[
  {
    "path": ".gitattributes",
    "content": "* text=auto\n\n#Explicitly set here just for sanity.\n*.cs text\n*.dfy text\n*.expect text\n*.bpl text\n*.atg text\n*.mdk text\n*.json text\n*.sty text\n*.md text\n*.tmp text\n\n#Needs to be crlf\n*.sln text eol=crlf\n*.csproj text eol=crlf\n*.vsixmanifest eol=crlf\n*.config eol=crlf\n*.bat eol=crlf\n*.transcript eol=crlf\n\n#Needs to be lr\nBinaries/dafny text eol=lf\nBinaries/dafny-server text eol=lf\n\n#Never convert these\n*.dll binary\n*.exe binary\n*.png binary\n*.jpg binary\n*.xcf binary\n*.snk binary\n"
  },
  {
    "path": ".gitignore",
    "content": "*.config\n*.manifest\n*.pkgdef\n*.suo\n*.userprefs\n*.vsix\n*.vsixmanifest\n*~\n*.vdfy\n\n.idea/\n\nBinaries/*\n\nPackage/\n\nSource/*/bin/\nSource/*/obj/\nSource/Armada/Parser.cs\nSource/Armada/Scanner.cs\nSource/Armada/Parser.cs.old\nSource/Armada/Scanner.cs.old\nSource/packages\n\nSource/DafnyExtension/DafnyPrelude.bpl\nSource/DafnyExtension/DafnyRuntime.cs\nSource/DafnyExtension/Z3-LICENSE.txt\nSource/DafnyExtension/z3.exe\n*.csproj.user\n\nTest/**/.sconsign.dblite\nTest/**/*.exe\nTest/**/*.dll\nTest/**/*.mdb\nTest/**/*.pdb\nTest/**/Output/\nTest/server/model.bvd\nTest/dafny0/Extern.cs\nTest/dafny0/ExternCopyFromTrait.cs\nTest/git-issues/github-issue-305-*.cs\nTest/desktop/*\nTest/node_modules/\nTest/package-lock.json\n\nDocs/OnlineTutorial/DocumentationTransducer.exe\nDocs/OnlineTutorial/DocumentationTransducer.pdb\nDocs/OnlineTutorial/DocumentationTransducer/obj\nDocs/OnlineTutorial/manuscripts/*.htm\nDocs/OnlineTutorial/manuscripts/*.*.dfy\nTest/comp/*.cs\nTest/comp/*.js\nTest/comp/*-go\n\n# Generated by Rider IDE\n*.sln.DotSettings.user\n*.sln.DotSettings\n\n# Generated by Visual Studio 2019\n*.csproj.user\nSource/.vs\nBinaries/CodeContracts/\n\nbin/\n.sconsign.dblite\n*.tmp\nMisc/"
  },
  {
    "path": "Armada/.gitignore",
    "content": "*.tmp\n*.vdfy\nbin/\ncache/\n.sconsign.dblite\n"
  },
  {
    "path": "Armada/ArmadaCommonDefinitions.dfy",
    "content": "include \"util/collections/seqs.i.dfy\"\ninclude \"util/option.s.dfy\"\ninclude \"spec/refinement.s.dfy\"\n\nmodule ArmadaCommonDefinitions {\n\n  import opened util_collections_seqs_i\n  import opened util_option_s\n  import opened GeneralRefinementModule\n\n  ////////////////////////////////\n  // Primitive types\n  ////////////////////////////////\n\n  newtype uint8 = n: int | 0 <= n < 256\n\n  newtype uint16 = n: int | 0 <= n < 65536\n\n  newtype uint32 = n: int | 0 <= n < 4294967296\n\n  newtype uint64 = n: int | 0 <= n < 18446744073709551616\n\n  newtype int8 = n: int | -128 <= n < 128\n\n  newtype int16 = n: int | -32768 <= n < 32768\n\n  newtype int32 = n: int | -2147483648 <= n < 2147483648\n\n  newtype int64 = n: int | -9223372036854775808 <= n < 9223372036854775808\n\n  function Armada_CastTo_uint8(n: int): (n': uint8)\n    ensures 0 <= n < 256 ==> n' as int == n\n  {\n    (n % 256) as uint8\n  }\n\n  function Armada_CastTo_uint16(n: int): (n': uint16)\n    ensures 0 <= n < 65536 ==> n' as int == n\n  {\n    (n % 65536) as uint16\n  }\n\n  function Armada_CastTo_uint32(n: int): (n': uint32)\n    ensures 0 <= n < 4294967296 ==> n' as int == n\n  {\n    (n % 4294967296) as uint32\n  }\n\n  function Armada_CastTo_uint64(n: int): (n': uint64)\n    ensures 0 <= n < 18446744073709551616 ==> n' as int == n\n  {\n    (n % 18446744073709551616) as uint64\n  }\n\n  function {:axiom} Armada_CastTo_int8(n: int): (n': int8)\n    ensures -128 <= n < 128 ==> n' as int == n\n\n  function {:axiom} Armada_CastTo_int16(n: int): (n': int16)\n    ensures -32768 <= n < 32768 ==> n' as int == n\n\n  function {:axiom} Armada_CastTo_int32(n: int): (n': int32)\n    ensures -2147483648 <= n < 2147483648 ==> n' as int == n\n\n  function {:axiom} Armada_CastTo_int64(n: int): (n': int64)\n    ensures -9223372036854775808 <= n < 9223372036854775808 ==> n' as int == n\n\n  datatype Armada_PrimitiveValue =\n      Armada_PrimitiveValueNone\n    | Armada_PrimitiveValue_uint8(n_uint8: uint8)\n    | Armada_PrimitiveValue_uint16(n_uint16: uint16)\n    | Armada_PrimitiveValue_uint32(n_uint32: uint32)\n    | Armada_PrimitiveValue_uint64(n_uint64: uint64)\n    | Armada_PrimitiveValue_int8(n_int8: int8)\n    | Armada_PrimitiveValue_int16(n_int16: int16)\n    | Armada_PrimitiveValue_int32(n_int32: int32)\n    | Armada_PrimitiveValue_int64(n_int64: int64)\n\n  datatype Armada_PrimitiveType = \n      Armada_PrimitiveType_uint8\n    | Armada_PrimitiveType_uint16\n    | Armada_PrimitiveType_uint32\n    | Armada_PrimitiveType_uint64\n    | Armada_PrimitiveType_int8\n    | Armada_PrimitiveType_int16\n    | Armada_PrimitiveType_int32\n    | Armada_PrimitiveType_int64\n\n  predicate Armada_PrimitiveValueMatchesType(v: Armada_PrimitiveValue, ty: Armada_PrimitiveType)\n  {\n    match ty\n    case Armada_PrimitiveType_uint8 =>\n      v.Armada_PrimitiveValue_uint8?\n    case Armada_PrimitiveType_uint16 =>\n      v.Armada_PrimitiveValue_uint16?\n    case Armada_PrimitiveType_uint32 =>\n      v.Armada_PrimitiveValue_uint32?\n    case Armada_PrimitiveType_uint64 =>\n      v.Armada_PrimitiveValue_uint64?\n    case Armada_PrimitiveType_int8 =>\n      v.Armada_PrimitiveValue_int8?\n    case Armada_PrimitiveType_int16 =>\n      v.Armada_PrimitiveValue_int16?\n    case Armada_PrimitiveType_int32 =>\n      v.Armada_PrimitiveValue_int32?\n    case Armada_PrimitiveType_int64 =>\n      v.Armada_PrimitiveValue_int64?\n  }\n\n  predicate Armada_PrimitiveValuesOfSameType(v: Armada_PrimitiveValue, v': Armada_PrimitiveValue)\n  {\n    match v\n      case Armada_PrimitiveValueNone => v'.Armada_PrimitiveValueNone?\n      case Armada_PrimitiveValue_uint8(_) => v'.Armada_PrimitiveValue_uint8?\n      case Armada_PrimitiveValue_uint16(_) => v'.Armada_PrimitiveValue_uint16?\n      case Armada_PrimitiveValue_uint32(_) => v'.Armada_PrimitiveValue_uint32?\n      case Armada_PrimitiveValue_uint64(_) => v'.Armada_PrimitiveValue_uint64?\n      case Armada_PrimitiveValue_int8(_) => v'.Armada_PrimitiveValue_int8?\n      case Armada_PrimitiveValue_int16(_) => v'.Armada_PrimitiveValue_int16?\n      case Armada_PrimitiveValue_int32(_) => v'.Armada_PrimitiveValue_int32?\n      case Armada_PrimitiveValue_int64(_) => v'.Armada_PrimitiveValue_int64?\n  }\n\n  ////////////////////////////////\n  // Bit vectors\n  ////////////////////////////////\n\n  function {:opaque} U32(b:bv32) : uint32 { b as uint32 }\n  function {:opaque} B32(u:uint32) : bv32 { u as bv32 }\n  function {:opaque} U64(b:bv64) : uint64 { b as uint64 }\n  function {:opaque} B64(u:uint64) : bv64 { u as bv64 }\n\n  // 32 bits\n  function {:opaque} bit_and32(b0:bv32, b1:bv32) : bv32 \n    { b0 & b1 }\n\n  function {:opaque} bit_or32(b0:bv32, b1:bv32) : bv32 \n    { b0 | b1 }\n\n  function {:opaque} bit_mod32(b0:bv32, b1:bv32) : bv32 \n    requires b1 != 0;\n    { b0 % b1 }\n\n  function {:opaque} bit_xor32(b0:bv32, b1:bv32) : bv32 \n    { b0 ^ b1 }\n\n  function {:opaque} bit_lshift32(b0:bv32, b1:bv32) : bv32 \n    requires b1 <= 32;\n    { b0 << b1 }\n\n  function {:opaque} bit_rshift32(b0:bv32, b1:bv32) : bv32 \n    requires b1 <= 32;\n    { b0 >> b1 }\n\n  function {:opaque} bit_and_uint32(u0:uint32, u1:uint32) : uint32 \n  {\n    U32(bit_and32(B32(u0), B32(u1)))\n  }\n\n  function {:opaque} bit_or_uint32(u0:uint32, u1:uint32) : uint32 \n  {\n    U32(bit_or32(B32(u0), B32(u1)))\n  }\n\n  function {:opaque} bit_mod_uint32(u0:uint32, u1:uint32) : uint32 \n    requires u1 != 0;\n  {\n    reveal B32();\n    U32(bit_mod32(B32(u0), B32(u1)))\n  }\n\n  function {:opaque} bit_xor_uint32(u0:uint32, u1:uint32) : uint32 \n  {\n    U32(bit_xor32(B32(u0), B32(u1)))\n  }\n\n  function {:opaque} bit_lshift_uint32(u0:uint32, u1:uint32) : uint32 \n    requires u1 <= 32;\n  {\n    bv32_inequality(u1);\n    U32(bit_lshift32(B32(u0), B32(u1)))\n  }\n\n  function {:opaque} bit_rshift_uint32(u0:uint32, u1:uint32) : uint32 \n    requires u1 <= 32;\n  {\n    bv32_inequality(u1);\n    U32(bit_rshift32(B32(u0), B32(u1)))\n  }\n\n  // 64 bits\n  function {:opaque} bit_and64(b0:bv64, b1:bv64) : bv64 \n    { b0 & b1 }\n\n  function {:opaque} bit_or64(b0:bv64, b1:bv64) : bv64 \n    { b0 | b1 }\n\n  function {:opaque} bit_mod64(b0:bv64, b1:bv64) : bv64 \n    requires b1 != 0;\n    { b0 % b1 }\n\n  function {:opaque} bit_xor64(b0:bv64, b1:bv64) : bv64 \n    { b0 ^ b1 }\n\n  function {:opaque} bit_lshift64(b0:bv64, b1:bv64) : bv64 \n    requires b1 <= 64;\n    { b0 << b1 }\n\n  function {:opaque} bit_rshift64(b0:bv64, b1:bv64) : bv64 \n    requires b1 <= 64;\n    { b0 >> b1 }\n\n  function {:opaque} bit_and_uint64(u0:uint64, u1:uint64) : uint64 \n  {\n    U64(bit_and64(B64(u0), B64(u1)))\n  }\n\n  function {:opaque} bit_or_uint64(u0:uint64, u1:uint64) : uint64 \n  {\n    U64(bit_or64(B64(u0), B64(u1)))\n  }\n\n  function {:opaque} bit_mod_uint64(u0:uint64, u1:uint64) : uint64 \n    requires u1 != 0;\n  {\n    reveal B64();\n    U64(bit_mod64(B64(u0), B64(u1)))\n  }\n\n  function {:opaque} bit_xor_uint64(u0:uint64, u1:uint64) : uint64 \n  {\n    U64(bit_xor64(B64(u0), B64(u1)))\n  }\n\n  function {:opaque} bit_lshift_uint64(u0:uint64, u1:uint64) : uint64 \n    requires u1 <= 64;\n  {\n    bv64_inequality(u1);\n    U64(bit_lshift64(B64(u0), B64(u1)))\n  }\n\n  function {:opaque} bit_rshift_uint64(u0:uint64, u1:uint64) : uint64 \n    requires u1 <= 64;\n  {\n    bv64_inequality(u1);\n    U64(bit_rshift64(B64(u0), B64(u1)))\n  }\n\n  lemma {:axiom} bv_core_properties()\n    ensures forall u:uint32 :: U32(B32(u)) == u;\n    ensures forall b:bv32 :: B32(U32(b)) == b;\n    ensures forall x:uint32, m:uint32 :: \n                   m != 0 && B32(m) != 0 ==> (x % m) == U32(bit_mod32(B32(x), B32(m)));\n    ensures forall u:uint64 :: U64(B64(u)) == u;\n    ensures forall b:bv64 :: B64(U64(b)) == b;\n    ensures forall x:uint64, m:uint64 :: \n                   m != 0 && B64(m) != 0 ==> (x % m) == U64(bit_mod64(B64(x), B64(m)));\n  \n  // 32 bits\n  lemma B32_injective(u0:uint32, u1:uint32)\n    ensures u0 == u1 <==> B32(u0) == B32(u1);\n  {\n    bv_core_properties();\n    assert u0 == u1 ==> B32(u0) == B32(u1);\n    var b0 := B32(u0);\n    var b1 := B32(u1);\n    assert b0 == b1 ==> U32(b0) == U32(b1);\n  }\n  \n  lemma U32_injective(b0:bv32, b1:bv32)\n    ensures b0 == b1 <==> U32(b0) == U32(b1);\n  {\n    bv_core_properties();\n    assert b0 == b1 ==> U32(b0) == U32(b1);\n    var u0 := U32(b0);\n    var u1 := U32(b1);\n    assert u0 == u1 ==> B32(u0) == B32(u1);\n  }\n\n  lemma bv32_injectivity()\n    ensures forall u0:uint32, u1:uint32 :: u0 == u1 <==> B32(u0) == B32(u1)\n    ensures forall b0, b1 :: b0 == b1 <==> U32(b0) == U32(b1)\n  {\n    reveal B32(); // Without this, Dafny can't seem to translate the forall statement to the forall expression\n    reveal U32(); // Without this, Dafny can't seem to translate the forall statement to the forall expression\n    forall u0:uint32, u1:uint32 ensures u0 == u1 <==> B32(u0) == B32(u1) { B32_injective(u0, u1); }\n    forall b0, b1 ensures b0 == b1 <==> U32(b0) == U32(b1) { U32_injective(b0, b1); }\n  }\n\n  lemma bv32_inequality(u:uint32)\n    requires u <= 32;\n    ensures  B32(u) <= 32;\n  {\n    reveal B32();\n    reveal U32();\n    bv_core_properties();\n    bv32_injectivity();\n  }\n\n  // 64 bits\n  lemma B64_injective(u0:uint64, u1:uint64)\n    ensures u0 == u1 <==> B64(u0) == B64(u1);\n  {\n    bv_core_properties();\n    assert u0 == u1 ==> B64(u0) == B64(u1);\n    var b0 := B64(u0);\n    var b1 := B64(u1);\n    assert b0 == b1 ==> U64(b0) == U64(b1);\n  }\n  \n  lemma U64_injective(b0:bv64, b1:bv64)\n    ensures b0 == b1 <==> U64(b0) == U64(b1);\n  {\n    bv_core_properties();\n    assert b0 == b1 ==> U64(b0) == U64(b1);\n    var u0 := U64(b0);\n    var u1 := U64(b1);\n    assert u0 == u1 ==> B64(u0) == B64(u1);\n  }\n\n  lemma bv64_injectivity()\n    ensures forall u0:uint64, u1:uint64 :: u0 == u1 <==> B64(u0) == B64(u1)\n    ensures forall b0, b1 :: b0 == b1 <==> U64(b0) == U64(b1)\n  {\n    reveal B64(); // Without this, Dafny can't seem to translate the forall statement to the forall expression\n    reveal U64(); // Without this, Dafny can't seem to translate the forall statement to the forall expression\n    forall u0:uint64, u1:uint64 ensures u0 == u1 <==> B64(u0) == B64(u1) { B64_injective(u0, u1); }\n    forall b0, b1 ensures b0 == b1 <==> U64(b0) == U64(b1) { U64_injective(b0, b1); }\n  }\n\n  lemma bv64_inequality(u:uint64)\n    requires u <= 64;\n    ensures  B64(u) <= 64;\n  {\n    reveal B64();\n    reveal U64();\n    bv_core_properties();\n    bv64_injectivity();\n  }\n\n\n  // Example uses\n  lemma bv_test(b:bv64)\n    //ensures bit_and64(b, 0) == 0;\n    //ensures bit_and64(b, 0xFFFFFFFFFFFFFFFF) == b\n    ensures bit_xor64(b, 0) == b;\n  {\n    //reveal bit_and64();\n    var all_ones:bv64 := 0xFFFFFFFFFFFFFFFF; \n    //assert bit_and64(b, all_ones) == b;\n    reveal_bit_xor64();\n  }\n  \n  lemma bv64_properties()\n    ensures forall u0:uint64 :: bit_and_uint64(u0, 0) == 0\n  {\n    reveal bit_and_uint64();  // Without this, Dafny can't seem to translate the forall statement to the forall expression\n    forall u0 ensures bit_and_uint64(u0, 0) == 0 { bv64_properties_specific(u0, 0); }\n  }\n\n  lemma bv64_properties_specific(u0:uint64, u1:uint64)\n    ensures bit_and_uint64(u0, 0) == 0\n    ensures bit_and_uint64(u0, u1) == bit_and_uint64(u1, u0)\n    ensures bit_xor_uint64(u0, u0) == 0 \n    ensures bit_xor_uint64(u0, u1) == bit_xor_uint64(u1, u0)\n  {\n    bv_core_properties(); reveal U64(); reveal B64();\n\n    var all_ones:uint64 := 0xFFFFFFFFFFFFFFFF; \n    assert B64(0) == 0; // Help Z3 with constant conversion\n    assert B64(all_ones) == 0xFFFFFFFFFFFFFFFF; // Help Z3 with constant conversion\n\n    // AND\n    assert bit_and_uint64(u0, 0)  == 0 by { reveal bit_and_uint64(); reveal bit_and64(); }\n    assert bit_and_uint64(u0, all_ones)  == u0 by { reveal bit_and_uint64(); reveal bit_and64(); }\n    assert bit_and_uint64(u0, u1) == bit_and_uint64(u1, u0) by { reveal bit_and_uint64(); reveal bit_and64(); }\n\n    // OR\n    assert bit_or_uint64(u0, 0)  == u0 by { reveal bit_or_uint64(); reveal bit_or64(); }\n    assert bit_or_uint64(u0, all_ones)  == all_ones by { reveal bit_or_uint64(); reveal bit_or64(); }\n    assert bit_or_uint64(u0, u1) == bit_or_uint64(u1, u0) by { reveal bit_or_uint64(); reveal bit_or64(); }\n\n    // XOR\n    assert bit_xor_uint64(u0, u0) == 0 by { reveal bit_xor_uint64(); reveal bit_xor64(); }\n    assert bit_xor_uint64(u0, u1) == bit_xor_uint64(u1, u0) by { reveal bit_xor_uint64(); reveal bit_xor64(); }\n    assert bit_xor_uint64(u0, 0)  == u0 by { reveal bit_xor_uint64(); reveal bit_xor64(); }\n  }\n    \n\n//  method bitwise_and(x:uint64, y:uint64) returns (z:uint64)\n//    ensures z == bit_and_uint64(x, y)\n\n  ////////////////////////////////\n  // Thread handle\n  ////////////////////////////////\n\n  type Armada_ThreadHandle = uint64\n\n  ////////////////////////////////\n  // Termination\n  ////////////////////////////////\n\n  datatype Armada_StopReason = Armada_NotStopped\n                             | Armada_StopReasonTerminated\n                             | Armada_StopReasonAssertionFailure\n                             | Armada_StopReasonUndefinedBehavior\n\n  ////////////////////////////////\n  // Multisteps\n  ////////////////////////////////\n\n  datatype Armada_SpecFunctions<!State, !OneStep, !PC> =\n    Armada_SpecFunctions(\n      init:State->bool,\n      step_valid:(State, OneStep, Armada_ThreadHandle)->bool,\n      step_next:(State, OneStep, Armada_ThreadHandle)->State,\n      is_step_tau:OneStep->bool,\n      state_ok:State->bool,\n      get_thread_pc:(State, Armada_ThreadHandle)->Option<PC>,\n      is_pc_nonyielding:PC->bool\n      )\n\n  predicate Armada_ThreadYielding<State, OneStep, PC>(\n    asf:Armada_SpecFunctions<State, OneStep, PC>,\n    s:State,\n    tid:Armada_ThreadHandle\n    )\n  {\n    // Either the process has crashed, the thread isn't running, or the thread is at a yield point\n    var pc := asf.get_thread_pc(s, tid);\n    !asf.state_ok(s) || pc.None? || !asf.is_pc_nonyielding(pc.v)\n  }\n\n  predicate Armada_StepsStartNonyielding<State, OneStep, PC>(\n    asf:Armada_SpecFunctions<State, OneStep, PC>,\n    s:State,\n    s':State,\n    steps:seq<OneStep>,\n    tid:Armada_ThreadHandle\n    )\n  {\n    |steps| > 0 ==>\n      && !Armada_ThreadYielding(asf, s, tid)\n      && !asf.is_step_tau(steps[0])\n      && Armada_StepsStartNonyielding(asf, asf.step_next(s, steps[0], tid), s', steps[1..], tid)\n  }\n\n  predicate Armada_NextMultipleSteps<State, OneStep, PC>(\n    asf:Armada_SpecFunctions<State, OneStep, PC>,\n    s:State,\n    s':State,\n    steps:seq<OneStep>,\n    tid:Armada_ThreadHandle\n    )\n  {\n    if |steps| == 0 then\n      s' == s\n    else\n      && asf.step_valid(s, steps[0], tid)\n      && Armada_NextMultipleSteps(asf, asf.step_next(s, steps[0], tid), s', steps[1..], tid)\n  }\n\n  predicate Armada_NextMultistep<State, OneStep, PC>(\n    asf:Armada_SpecFunctions<State, OneStep, PC>,\n    s:State,\n    s':State,\n    steps:seq<OneStep>,\n    tid:Armada_ThreadHandle,\n    tau:bool\n    )\n  {\n    && Armada_NextMultipleSteps(asf, s, s', steps, tid)\n    && (|steps| > 0 ==>\n       if tau then\n         && |steps| == 1\n         && asf.is_step_tau(steps[0])\n       else\n         && Armada_ThreadYielding(asf, s, tid)\n         && Armada_ThreadYielding(asf, s', tid)\n         && !asf.is_step_tau(steps[0])\n         && Armada_StepsStartNonyielding(asf, asf.step_next(s, steps[0], tid), s', steps[1..], tid)\n       )\n  }\n\n  function Armada_SpecFunctionsToSpec<State(!new), OneStep(!new), PC>(\n    asf:Armada_SpecFunctions<State, OneStep, PC>\n    ) : Spec<State>\n  {\n    Spec(iset s | asf.init(s),\n         iset s, s', steps, tid, tau | Armada_NextMultistep(asf, s, s', steps, tid, tau) :: StatePair(s, s'))\n  }\n\n  ////////////////////////////////\n  // Heap types\n  ////////////////////////////////\n\n  datatype Armada_ObjectType = Armada_ObjectTypePrimitive(pty: Armada_PrimitiveType)\n                             | Armada_ObjectTypeStruct(fieldTypes: seq<Armada_ObjectType>)\n                             | Armada_ObjectTypeArray(subtype: Armada_ObjectType, sz: int)\n\n  ////////////////////////////////\n  // Pointers and heaps\n  ////////////////////////////////\n\n  type Armada_Pointer = uint64\n\n  function Armada_TriggerPointer(p:Armada_Pointer) : Armada_Pointer { p }\n\n  datatype Armada_RootType = Armada_RootTypeStaticHeap | Armada_RootTypeDynamicHeap | Armada_RootTypeStack\n\n  datatype Armada_ChildType = Armada_ChildTypeRoot(rt: Armada_RootType) | Armada_ChildTypeIndex(i: int)\n\n  datatype Armada_Node = Armada_Node(parent: Armada_Pointer, child_type: Armada_ChildType,\n                                     children: seq<Armada_Pointer>, ty: Armada_ObjectType)\n\n  type Armada_HeapValues = map<Armada_Pointer, Armada_PrimitiveValue>\n\n  datatype Armada_Heap = Armada_Heap(tree: map<Armada_Pointer, Armada_Node>, valid: set<Armada_Pointer>, freed: set<Armada_Pointer>,\n                                     values: Armada_HeapValues)\n    \n  predicate Armada_TreeForestProperties(tree: map<Armada_Pointer, Armada_Node>)\n  {\n    && (forall p {:trigger Armada_TriggerPointer(p)} ::\n           Armada_TriggerPointer(p) in tree ==> tree[p].parent in tree)\n    && (forall p {:trigger Armada_TriggerPointer(p)} ::\n           Armada_TriggerPointer(p) in tree ==> (tree[p].child_type.Armada_ChildTypeRoot? <==> tree[p].parent == p))\n    && (forall p, i {:trigger Armada_TriggerPointer(p), tree[p].children[i]} ::\n           Armada_TriggerPointer(p) in tree && 0 <= i < |tree[p].children|\n           ==> var q := tree[p].children[i]; q in tree && tree[q].parent == p && tree[q].child_type == Armada_ChildTypeIndex(i))\n    && (forall q {:trigger Armada_TriggerPointer(q)} ::\n           Armada_TriggerPointer(q) in tree && !tree[q].child_type.Armada_ChildTypeRoot?\n           ==> var p, f := tree[q].parent, tree[q].child_type;\n               p in tree && 0 <= f.i < |tree[p].children| && tree[p].children[f.i] == q)\n  }\n\n  predicate Armada_TreeStructProperties(tree: map<Armada_Pointer, Armada_Node>)\n  {\n    && (forall p {:trigger Armada_TriggerPointer(p)} ::\n         Armada_TriggerPointer(p) in tree && tree[p].ty.Armada_ObjectTypeStruct? ==> |tree[p].children| == |tree[p].ty.fieldTypes|)\n    && (forall p, i {:trigger Armada_TriggerPointer(p), tree[p].children[i]} ::\n         Armada_TriggerPointer(p) in tree && tree[p].ty.Armada_ObjectTypeStruct? && 0 <= i < |tree[p].children| ==>\n         var q := tree[p].children[i];\n         q in tree && tree[q].ty == tree[p].ty.fieldTypes[i])\n  }\n\n  predicate Armada_TreeArrayProperties(tree: map<Armada_Pointer, Armada_Node>)\n  {\n    && (forall p {:trigger Armada_TriggerPointer(p)} ::\n           Armada_TriggerPointer(p) in tree && tree[p].ty.Armada_ObjectTypeArray? ==> tree[p].ty.sz >= 0)\n    && (forall p {:trigger Armada_TriggerPointer(p)} ::\n           Armada_TriggerPointer(p) in tree && tree[p].ty.Armada_ObjectTypeArray? ==> |tree[p].children| == tree[p].ty.sz)\n    && (forall p, q {:trigger Armada_TriggerPointer(p), Armada_TriggerPointer(q), tree[p].ty.Armada_ObjectTypeArray?} ::\n           && Armada_TriggerPointer(p) in tree && Armada_TriggerPointer(q) in tree\n           && tree[p].ty.Armada_ObjectTypeArray? && tree[q].parent == p && q != p\n           ==> tree[q].ty == tree[p].ty.subtype)\n  }\n\n  predicate Armada_TreePrimitiveProperties(tree: map<Armada_Pointer, Armada_Node>)\n  {\n    forall p {:trigger Armada_TriggerPointer(p)} ::\n      Armada_TriggerPointer(p) in tree && tree[p].ty.Armada_ObjectTypePrimitive? ==> |tree[p].children| == 0\n  }\n\n  predicate Armada_TreeProperties(tree: map<Armada_Pointer, Armada_Node>)\n  {\n    && Armada_TreeForestProperties(tree)\n    && Armada_TreeStructProperties(tree)\n    && Armada_TreeArrayProperties(tree)\n    && Armada_TreePrimitiveProperties(tree)\n  }\n\n  predicate Armada_HeapInvariant(h: Armada_Heap)\n  {\n    && (forall p :: p in h.valid ==> p !in h.freed)\n    && 0 in h.freed\n    && !(0 in h.valid)\n    && Armada_TreeProperties(h.tree)\n    && (forall p {:trigger Armada_TriggerPointer(p)} {:trigger Armada_TriggerPointer(h.tree[p].parent)} :: \n        Armada_TriggerPointer(p) in h.tree ==>\n          (p in h.valid <==> Armada_TriggerPointer(h.tree[p].parent) in h.valid))\n    && forall p {:trigger Armada_TriggerPointer(p)} :: \n        Armada_TriggerPointer(p) in h.tree &&\n        h.tree[p].ty.Armada_ObjectTypePrimitive? ==>\n          p in h.values &&\n          Armada_PrimitiveValueMatchesType(h.values[p], h.tree[p].ty.pty)\n  }\n\n  predicate Armada_HeapMetadataUnchanged(h: Armada_Heap, h': Armada_Heap)\n  {\n    && h'.tree == h.tree\n    && h'.valid == h.valid\n    && h'.freed == h.freed\n  }\n\n  predicate Armada_ComparablePointer(p: Armada_Pointer, h: Armada_Heap)\n  {\n    p !in h.freed || p == 0\n  }\n\n  /////////////////////////////////////////////\n  // Pointer subtree structural correctness\n  /////////////////////////////////////////////\n\n  predicate Armada_PointerSubtreeHasObjectType(tree: map<Armada_Pointer, Armada_Node>, p: Armada_Pointer, ty: Armada_ObjectType)\n    decreases ty\n  {\n    && p in tree\n    && tree[p].ty == ty\n    && match tree[p].ty\n        case Armada_ObjectTypePrimitive(pty) =>\n          |tree[p].children| == 0\n        case Armada_ObjectTypeStruct(fieldTypes) =>\n          && |tree[p].children| == |fieldTypes|\n          && (forall i {:trigger tree[p].children[i]} :: 0 <= i < |fieldTypes| ==>\n               Armada_PointerSubtreeHasObjectType(tree, tree[p].children[i], fieldTypes[i]))\n        case Armada_ObjectTypeArray(subtype, sz) =>\n          && |tree[p].children| == sz\n          && (forall i {:trigger tree[p].children[i]} :: 0 <= i < sz ==>\n               Armada_PointerSubtreeHasObjectType(tree, tree[p].children[i], subtype))\n  }\n\n  predicate Armada_PointerSubtreeCorrect(tree: map<Armada_Pointer, Armada_Node>, p: Armada_Pointer)\n  {\n    p in tree && Armada_PointerSubtreeHasObjectType(tree, p, tree[p].ty)\n  }\n\n  ////////////////////////////////////\n  // Descendants in heap tree\n  ////////////////////////////////////\n\n  function Armada_DescendantsOfPointerToObjectType(\n    tree: map<Armada_Pointer, Armada_Node>,\n    p: Armada_Pointer,\n    ty: Armada_ObjectType\n    ) : set<Armada_Pointer>\n    decreases ty\n  {\n    match ty\n      case Armada_ObjectTypePrimitive(_) =>\n        {Armada_TriggerPointer(p)}\n      case Armada_ObjectTypeStruct(fieldTypes) =>\n        {Armada_TriggerPointer(p)}\n        + (set q, i, ty {:trigger q in Armada_DescendantsOfPointerToObjectType(tree, tree[p].children[i], ty)}\n            | && p in tree\n              && 0 <= i < |tree[p].children| && i < |fieldTypes|\n              && ty == fieldTypes[i]\n              && q in Armada_DescendantsOfPointerToObjectType(tree, tree[p].children[i], ty)\n            :: Armada_TriggerPointer(q))\n      case Armada_ObjectTypeArray(subtype, _) =>\n        {Armada_TriggerPointer(p)}\n        + (set q, i {:trigger q in Armada_DescendantsOfPointerToObjectType(tree, tree[p].children[i], subtype)}\n            | && p in tree\n              && 0 <= i < |tree[p].children|\n              && q in Armada_DescendantsOfPointerToObjectType(tree, tree[p].children[i], subtype)\n            :: Armada_TriggerPointer(q))\n  }\n\n  function Armada_DescendantsOfPointer(tree: map<Armada_Pointer, Armada_Node>, p: Armada_Pointer) : set<Armada_Pointer>\n    requires p in tree\n  {\n    Armada_DescendantsOfPointerToObjectType(tree, p, tree[p].ty)\n  }\n\n  ////////////////////////////////////\n  // Pointer validity\n  ////////////////////////////////////\n\n  function Armada_ValidPointerToObjectType(h: Armada_Heap, p: Armada_Pointer, ty: Armada_ObjectType) : (b: bool)\n    ensures  b ==> Armada_PointerSubtreeHasObjectType(h.tree, p, ty)\n    decreases ty\n  {\n    && Armada_TriggerPointer(p) in h.tree\n    && p in h.valid\n    && h.tree[p].ty == ty\n    && match h.tree[p].ty\n        case Armada_ObjectTypePrimitive(pty) =>\n          && |h.tree[p].children| == 0\n          && p in h.values\n          && Armada_PrimitiveValueMatchesType(h.values[p], pty)\n        case Armada_ObjectTypeStruct(fieldTypes) =>\n          && |h.tree[p].children| == |fieldTypes|\n          && (forall i {:trigger h.tree[p].children[i]} :: 0 <= i < |fieldTypes| ==>\n               Armada_ValidPointerToObjectType(h, h.tree[p].children[i], fieldTypes[i]))\n        case Armada_ObjectTypeArray(subtype, sz) =>\n          && |h.tree[p].children| == sz\n          && (forall i {:trigger h.tree[p].children[i]} :: 0 <= i < sz ==>\n               Armada_ValidPointerToObjectType(h, h.tree[p].children[i], subtype))\n  }\n\n  function Armada_ValidPointer(h: Armada_Heap, p: Armada_Pointer) : (b: bool)\n    ensures  b ==> Armada_PointerSubtreeCorrect(h.tree, p)\n  {\n    p in h.tree && Armada_ValidPointerToObjectType(h, p, h.tree[p].ty)\n  }\n\n  ////////////////////////////////////\n  // Updating heap via pointers\n  ////////////////////////////////////\n\n  function Armada_UpdateHeapValuesWithPrimitiveValue(\n    values: map<Armada_Pointer, Armada_PrimitiveValue>,\n    p: Armada_Pointer,\n    new_value: Armada_PrimitiveValue\n    ) : (\n    new_values: map<Armada_Pointer, Armada_PrimitiveValue>\n    )\n  {\n    map q | q in values :: if q == p then new_value else values[q]\n  }\n\n  predicate Armada_ArbitrarilyResolveConflictingUpdatesTrigger(p: Armada_Pointer)\n  {\n    true\n  }\n\n  function {:opaque} Armada_ArbitrarilyResolveConflictingUpdates(update_set: set<(Armada_Pointer, Armada_PrimitiveValue)>)\n    : (update_map : map<Armada_Pointer, Armada_PrimitiveValue>)\n    ensures forall p :: p in update_map ==> (p, update_map[p]) in update_set\n    ensures forall p, v :: (p, v) in update_set ==> p in update_map\n  {\n    map p {:trigger Armada_ArbitrarilyResolveConflictingUpdatesTrigger(p)}\n          | Armada_ArbitrarilyResolveConflictingUpdatesTrigger(p) && (exists v :: (p, v) in update_set)\n          :: (var v :| (p, v) in update_set; v)\n  }\n\n  function Armada_UpdateHeapValuesSimultaneously(\n    values: Armada_HeapValues,\n    updates: set<(Armada_Pointer, Armada_PrimitiveValue)>\n    ) : (\n    values': Armada_HeapValues\n    )\n  {\n    var update_map := Armada_ArbitrarilyResolveConflictingUpdates(updates);\n    map p | p in values :: if p in update_map then update_map[p] else values[p]\n  }\n   \n  ////////////////////////////////\n  // Configuration\n  ////////////////////////////////\n\n  datatype Armada_Config = Armada_Config(tid_init: Armada_ThreadHandle, new_ptrs: set<Armada_Pointer>)\n\n  ////////////////////////////////\n  // Placeholder types\n  ////////////////////////////////\n\n  type ArmadaPlaceholder_ExtendedFrame\n  datatype ArmadaPlaceholder_StoreBufferEntry = ArmadaPlaceholder_StoreBufferEntry(value: Armada_PrimitiveValue)\n  datatype ArmadaPlaceholder_Thread =\n    ArmadaPlaceholder_Thread(stack: seq<ArmadaPlaceholder_ExtendedFrame>, storeBuffer: seq<ArmadaPlaceholder_StoreBufferEntry>)\n  datatype ArmadaPlaceholder_TotalState =\n    ArmadaPlaceholder_TotalState(stop_reason: Armada_StopReason, threads: map<Armada_ThreadHandle, ArmadaPlaceholder_Thread>,\n                                 joinable_tids: set<Armada_ThreadHandle>)\n\n}\n"
  },
  {
    "path": "Armada/spec/refinement.s.dfy",
    "content": "include \"../util/collections/seqs.s.dfy\"\n\nmodule GeneralRefinementModule {\n\n    import opened util_collections_seqs_s\n\n    datatype StatePair<State> = StatePair(s:State, s':State)\n\n    datatype Spec<!State> = Spec(init:iset<State>, next:iset<StatePair<State>>)\n\n    predicate BehaviorSatisfiesSpec<State>(b:seq<State>, sm:Spec<State>)\n    {\n        && |b| > 0\n        && b[0] in sm.init\n        && (forall i {:trigger StatePair(b[i], b[i+1]) in sm.next} :: 0 <= i < |b|-1 ==> StatePair(b[i], b[i+1]) in sm.next)\n    }\n\n    datatype RefinementRange = RefinementRange(first:int, last:int)\n    type RefinementMap = seq<RefinementRange>\n    datatype RefinementPair<L, H> = RefinementPair(low:L, high:H)\n    type RefinementRelation<!L(==), !H(==)> = iset<RefinementPair<L, H>>\n\n    predicate IsValidRefinementMap(low_level_behavior_size:int, high_level_behavior_size:int, lh_map:RefinementMap)\n    {\n        && |lh_map| == low_level_behavior_size\n        && low_level_behavior_size > 0\n        && (forall pair :: pair in lh_map ==> 0 <= pair.first <= pair.last < high_level_behavior_size)\n        && lh_map[0].first == 0\n        && last(lh_map).last == high_level_behavior_size - 1\n        && (forall i :: 0 <= i < |lh_map| - 1 ==> lh_map[i+1].first == lh_map[i].last || lh_map[i+1].first == lh_map[i].last + 1)\n    }\n\n    predicate BehaviorRefinesBehaviorUsingRefinementMap<L, H>(\n        lb:seq<L>,\n        hb:seq<H>,\n        relation:RefinementRelation<L, H>,\n        lh_map:RefinementMap\n        )\n    {\n        && IsValidRefinementMap(|lb|, |hb|, lh_map)\n        && (forall i, j {:trigger RefinementPair(lb[i], hb[j]) in relation} ::\n                    0 <= i < |lb| && lh_map[i].first <= j <= lh_map[i].last ==> RefinementPair(lb[i], hb[j]) in relation)\n    }\n\n    predicate BehaviorRefinesBehavior<L, H>(\n        lb:seq<L>,\n        hb:seq<H>,\n        relation:RefinementRelation<L, H>\n        )\n    {\n        exists lh_map :: BehaviorRefinesBehaviorUsingRefinementMap(lb, hb, relation, lh_map)\n    }\n\n    predicate BehaviorRefinesSpec<L, H(!new)>(\n        lb:seq<L>,\n        spec:Spec<H>,\n        relation:RefinementRelation<L, H>\n        )\n    {\n        exists hb :: BehaviorRefinesBehavior(lb, hb, relation) && BehaviorSatisfiesSpec(hb, spec)\n    }\n\n    predicate SpecRefinesSpec<L(!new), H(!new)>(\n        l_spec:Spec<L>,\n        h_spec:Spec<H>,\n        relation:RefinementRelation<L, H>\n        )\n    {\n        forall lb :: BehaviorSatisfiesSpec(lb, l_spec) ==> BehaviorRefinesSpec(lb, h_spec, relation)\n    }\n\n}\n"
  },
  {
    "path": "Armada/strategies/chl/AtomicConcurrentHoareLogic.i.dfy",
    "content": "include \"../../util/option.s.dfy\"\ninclude \"../../util/collections/seqs.s.dfy\"\ninclude \"../../util/collections/seqs.i.dfy\"\ninclude \"../refinement/GeneralRefinementLemmas.i.dfy\"\ninclude \"../refinement/RefinementConvolution.i.dfy\"\ninclude \"../refinement/AnnotatedBehavior.i.dfy\"\ninclude \"../invariants.i.dfy\"\ninclude \"../generic/GenericArmadaLemmas.i.dfy\"\ninclude \"../generic/LiftAtomicToAtomic.i.dfy\"\ninclude \"ConcurrentHoareLogicSpec.i.dfy\"\ninclude \"AtomicConcurrentHoareLogicLemmas.i.dfy\"\n\nmodule AtomicConcurrentHoareLogicModule {\n\n  import opened util_option_s\n  import opened util_collections_seqs_s\n  import opened util_collections_seqs_i\n  import opened GeneralRefinementModule\n  import opened GeneralRefinementLemmasModule\n  import opened RefinementConvolutionModule\n  import opened AnnotatedBehaviorModule\n  import opened InvariantsModule\n  import opened ArmadaCommonDefinitions\n  import opened GenericArmadaSpecModule\n  import opened GenericArmadaLemmasModule\n  import opened GenericArmadaAtomicModule\n  import opened LiftAtomicToAtomicModule\n  import opened ConcurrentHoareLogicSpecModule\n  import opened AtomicConcurrentHoareLogicSpecModule\n  import opened AtomicConcurrentHoareLogicLemmasModule\n\n  lemma lemma_LiftAtomicToAtomicUsingCHLRequest<LState(!new), LPath(!new), LPC(!new), LProc(!new), HState(!new), HPath(!new), HPC(!new)>(\n    ar:AtomicConcurrentHoareLogicRequest<LState, LPath, LPC, LProc, HState, HPath, HPC>\n    )\n    requires IsValidAtomicConcurrentHoareLogicRequest(ar)\n    ensures  SpecRefinesSpec(AtomicSpec(ar.l), AtomicSpec(ar.h), ar.relation)\n  {\n    var inv := ExtractInv(ar);\n    var relation := ExtractLiftingRelation(ar);\n    lemma_EstablishInitRequirements(ar, inv, relation);\n    lemma_EstablishAtomicPathsLiftable(ar, inv, relation);\n    lemma_LiftAtomicToAtomicGivenAtomicPathsLiftable(ar.l, ar.h, inv, relation, ar.relation);\n  }\n\n}\n"
  },
  {
    "path": "Armada/strategies/chl/AtomicConcurrentHoareLogicLemmas.i.dfy",
    "content": "include \"../../util/option.s.dfy\"\ninclude \"../../util/collections/seqs.s.dfy\"\ninclude \"../../util/collections/seqs.i.dfy\"\ninclude \"../refinement/GeneralRefinementLemmas.i.dfy\"\ninclude \"../refinement/RefinementConvolution.i.dfy\"\ninclude \"../refinement/AnnotatedBehavior.i.dfy\"\ninclude \"../invariants.i.dfy\"\ninclude \"../generic/GenericArmadaLemmas.i.dfy\"\ninclude \"../generic/LiftAtomicToAtomic.i.dfy\"\ninclude \"ConcurrentHoareLogic.i.dfy\"\ninclude \"AtomicConcurrentHoareLogicSpec.i.dfy\"\n\nmodule AtomicConcurrentHoareLogicLemmasModule {\n\n  import opened util_option_s\n  import opened util_collections_seqs_s\n  import opened util_collections_seqs_i\n  import opened GeneralRefinementModule\n  import opened GeneralRefinementLemmasModule\n  import opened RefinementConvolutionModule\n  import opened AnnotatedBehaviorModule\n  import opened InvariantsModule\n  import opened ArmadaCommonDefinitions\n  import opened GenericArmadaSpecModule\n  import opened GenericArmadaLemmasModule\n  import opened GenericArmadaAtomicModule\n  import opened LiftAtomicToAtomicModule\n  import opened ConcurrentHoareLogicSpecModule\n  import opened ConcurrentHoareLogicLemmasModule\n  import opened ConcurrentHoareLogicModule\n  import opened AtomicConcurrentHoareLogicSpecModule\n\n  function ExtractInv<LState(!new), LPath(!new), LPC(!new), LProc(!new), HState(!new), HPath(!new), HPC(!new)>(\n    ar:AtomicConcurrentHoareLogicRequest<LState, LPath, LPC, LProc, HState, HPath, HPC>\n    ) : LState->bool\n  {\n    s => s in AnnotatedReachables(ar.cr.spec)\n  }\n\n  function ExtractLiftingRelation<LState, LPath, LPC, LProc, HState, HPath, HPC>(\n    ar:AtomicConcurrentHoareLogicRequest<LState, LPath, LPC, LProc, HState, HPath, HPC>\n    ) : (LState, HState)->bool\n  {\n    (ls, hs) => hs == ar.lstate_to_hstate(ls)\n  }\n\n  lemma lemma_EstablishInitRequirements<LState(!new), LPath(!new), LPC(!new), LProc(!new), HState(!new), HPath(!new), HPC(!new)>(\n    ar:AtomicConcurrentHoareLogicRequest<LState, LPath, LPC, LProc, HState, HPath, HPC>,\n    inv:LState->bool,\n    relation:(LState, HState)->bool\n    )\n    requires IsValidAtomicConcurrentHoareLogicRequest(ar)\n    requires inv == ExtractInv(ar)\n    requires relation == ExtractLiftingRelation(ar)\n    ensures  AtomicInitImpliesInv(ar.l, inv)\n    ensures  forall ls :: ar.l.init(ls) ==> exists hs :: ar.h.init(hs) && relation(ls, hs)\n  {\n    forall ls | ar.l.init(ls)\n      ensures inv(ls)\n      ensures exists hs :: ar.h.init(hs) && relation(ls, hs)\n    {\n      lemma_InitStateInAnnotatedReachables(ls, ar.cr.spec);\n      var hs := ar.lstate_to_hstate(ls);\n      assert ar.h.init(hs) && relation(ls, hs);\n    }\n  }\n\n  lemma lemma_EstablishAtomicPathsLiftable<LState(!new), LPath(!new), LPC(!new), LProc(!new), HState(!new), HPath(!new), HPC(!new)>(\n    ar:AtomicConcurrentHoareLogicRequest<LState, LPath, LPC, LProc, HState, HPath, HPC>,\n    inv:LState->bool,\n    relation:(LState, HState)->bool\n    )\n    requires IsValidAtomicConcurrentHoareLogicRequest(ar)\n    requires inv == ExtractInv(ar)\n    requires relation == ExtractLiftingRelation(ar)\n    ensures  forall ls, lpath, tid, hs ::\n               inv(ls) && relation(ls, hs) && ar.l.path_valid(ls, lpath, tid)\n             ==> exists hpath :: LiftAtomicPathSuccessful(ar.l, ar.h, inv, relation, ls, lpath, tid, hs, hpath)\n  {\n    forall ls, lpath, tid, hs | inv(ls) && relation(ls, hs) && ar.l.path_valid(ls, lpath, tid)\n      ensures exists hpath :: LiftAtomicPathSuccessful(ar.l, ar.h, inv, relation, ls, lpath, tid, hs, hpath)\n    {\n      assert ls in AnnotatedReachables(ar.cr.spec);\n      var lb :| AnnotatedBehaviorSatisfiesSpec(lb, ar.cr.spec) && last(lb.states) == ls;\n\n      var ls' := ar.l.path_next(ls, lpath, tid);\n\n      var lpath_and_tid := PathAndTid(lpath, tid);\n      lemma_ExtendStateNextSeqRight(lb.states, lb.trace, ar.cr.spec.next, ls', lpath_and_tid);\n      var lb' := AnnotatedBehavior(lb.states + [ls'], lb.trace + [lpath_and_tid]);\n\n      var pos := |lb.trace|;\n      assert AnnotatedBehaviorSatisfiesSpec(lb', ar.cr.spec);\n      assert lb'.states[pos] == ls;\n      assert lb'.states[pos + 1] == ls';\n      assert lb'.trace[pos] == lpath_and_tid;\n\n      lemma_InvariantPredicateHoldsAtStep(lb', pos, ar.cr.spec, ar.cr.established_inv);\n\n      var hpath := ar.lpath_to_hpath(lpath);\n      assert CorrectCHLStepEffect(ar.cr, ls, ls', lpath_and_tid);\n      assert ar.cr.state_ok(ls);\n      lemma_CHLGlobalInvariantHoldsWhenActorPresent(ar.cr, lb', pos, tid);\n      if !ar.l.path_type(lpath).AtomicPathType_Tau? {\n        lemma_CHLLocalInvariantHoldsWhenActorAboutToStep(ar.cr, lb', pos, tid);\n      }\n      assert LPathImpliesHPathConditions(ar, ls, lpath, tid);\n      assert LiftAtomicPathSuccessful(ar.l, ar.h, inv, relation, ls, lpath, tid, hs, hpath);\n    }\n  }\n\n}\n"
  },
  {
    "path": "Armada/strategies/chl/AtomicConcurrentHoareLogicSpec.i.dfy",
    "content": "include \"../refinement/AnnotatedBehavior.i.dfy\"\ninclude \"../invariants.i.dfy\"\ninclude \"../generic/GenericArmadaAtomic.i.dfy\"\ninclude \"ConcurrentHoareLogicSpec.i.dfy\"\n\nmodule AtomicConcurrentHoareLogicSpecModule {\n\n  import opened util_option_s\n  import opened GeneralRefinementModule\n  import opened AnnotatedBehaviorModule\n  import opened InvariantsModule\n  import opened ArmadaCommonDefinitions\n  import opened GenericArmadaSpecModule\n  import opened GenericArmadaAtomicModule\n  import opened ConcurrentHoareLogicSpecModule\n\n  datatype PathAndTid<Path> = PathAndTid(path: Path, tid: Armada_ThreadHandle)\n\n  datatype AtomicConcurrentHoareLogicRequest<!LState, !LPath(==), !LPC, !LProc, !HState, !HPath, !HPC> =\n    AtomicConcurrentHoareLogicRequest(\n      cr:ConcurrentHoareLogicRequest<LState, Armada_ThreadHandle, PathAndTid<LPath>, LPC, LProc>,\n      l:AtomicSpecFunctions<LState, LPath, LPC>,\n      h:AtomicSpecFunctions<HState, HPath, HPC>,\n      relation:RefinementRelation<LState, HState>,\n      lstate_to_hstate:LState->HState,\n      lpath_to_hpath:LPath->HPath,\n      lpc_to_hpc:LPC->HPC\n      )\n\n  predicate LInitImpliesHInit<LState(!new), LPath, LPC, LProc, HState, HPath, HPC>(\n    ar:AtomicConcurrentHoareLogicRequest<LState, LPath, LPC, LProc, HState, HPath, HPC>\n    )\n  {\n    forall ls :: ar.l.init(ls) ==> ar.h.init(ar.lstate_to_hstate(ls))\n  }\n\n  predicate LStateToHStateMapsPCsCorrectly<LState(!new), LPath, LPC, LProc, HState, HPath, HPC>(\n    ar:AtomicConcurrentHoareLogicRequest<LState, LPath, LPC, LProc, HState, HPath, HPC>\n    )\n  {\n    forall ls, tid :: var hs := ar.lstate_to_hstate(ls);\n                var lpc := ar.l.get_thread_pc(ls, tid);\n                var hpc := ar.h.get_thread_pc(hs, tid);\n                hpc == if lpc.Some? then Some(ar.lpc_to_hpc(lpc.v)) else None()\n  }\n\n  predicate LHPathPropertiesMatch<LState(!new), LPath(!new), LPC, LProc, HState, HPath, HPC>(\n    ar:AtomicConcurrentHoareLogicRequest<LState, LPath, LPC, LProc, HState, HPath, HPC>\n    )\n  {\n    forall lpath :: var hpath := ar.lpath_to_hpath(lpath);\n              ar.l.path_type(lpath) == ar.h.path_type(hpath)\n  }\n\n  predicate LPathImpliesHPathConditions<LState(!new), LPath(!new), LPC, LProc, HState, HPath, HPC>(\n    ar: AtomicConcurrentHoareLogicRequest<LState, LPath, LPC, LProc, HState, HPath, HPC>,\n    ls: LState,\n    lpath: LPath,\n    tid: Armada_ThreadHandle\n    )\n  {\n    && ar.l.path_valid(ls, lpath, tid)\n    && ar.cr.established_inv(ls)\n    && (!ar.l.path_type(lpath).AtomicPathType_Tau? ==> ar.cr.local_inv(ls, tid))\n    && ar.cr.global_inv(ls)\n  }\n\n  predicate LPathImpliesHPath<LState(!new), LPath(!new), LPC, LProc, HState, HPath, HPC>(\n    ar:AtomicConcurrentHoareLogicRequest<LState, LPath, LPC, LProc, HState, HPath, HPC>\n    )\n  {\n    forall ls, lpath, tid {:trigger LPathImpliesHPathConditions(ar, ls, lpath, tid)} :: LPathImpliesHPathConditions(ar, ls, lpath, tid) ==>\n      var ls' := ar.l.path_next(ls, lpath, tid);\n      var hs := ar.lstate_to_hstate(ls);\n      var hpath := ar.lpath_to_hpath(lpath);\n      var hs' := ar.lstate_to_hstate(ls');\n      && ar.h.path_valid(hs, hpath, tid)\n      && hs' == ar.h.path_next(hs, hpath, tid)\n  }\n\n  predicate StateConversionPreservesOK<LState(!new), LPath, LPC, LProc, HState, HPath, HPC>(\n    ar:AtomicConcurrentHoareLogicRequest<LState, LPath, LPC, LProc, HState, HPath, HPC>\n    )\n  {\n    forall ls :: ar.h.state_ok(ar.lstate_to_hstate(ls)) == ar.l.state_ok(ls)\n  }\n\n  predicate StateConversionSatisfiesRelation<LState(!new), LPath, LPC, LProc, HState, HPath, HPC>(\n    ar:AtomicConcurrentHoareLogicRequest<LState, LPath, LPC, LProc, HState, HPath, HPC>\n    )\n  {\n    forall ls :: RefinementPair(ls, ar.lstate_to_hstate(ls)) in ar.relation\n  }\n\n  predicate EmbeddedRequestCorresponds<LState(!new), LPath(!new), LPC, LProc, HState, HPath, HPC>(\n    ar:AtomicConcurrentHoareLogicRequest<LState, LPath, LPC, LProc, HState, HPath, HPC>\n    )\n  {\n    && (forall s :: ar.l.init(s) <==> s in ar.cr.spec.init)\n    && (forall s :: ar.l.state_ok(s) <==> ar.cr.state_ok(s))\n    && (forall s, s', path, tid :: ActionTuple(s, s', PathAndTid(path, tid)) in ar.cr.spec.next <==>\n                            ar.l.path_valid(s, path, tid) && s' == ar.l.path_next(s, path, tid))\n    && (forall path, tid :: ar.cr.step_to_actor(PathAndTid(path, tid)) ==\n                     if ar.l.path_type(path).AtomicPathType_Tau? then None else Some(tid))\n    && (forall s, tid :: ar.cr.get_actor_pc_stack(s, tid).Some? <==> ar.l.get_thread_pc(s, tid).Some?)\n  }\n\n  predicate IsValidAtomicConcurrentHoareLogicRequest<LState(!new), LPath(!new), LPC(!new), LProc(!new), HState(!new), HPath(!new), HPC(!new)>(\n    ar:AtomicConcurrentHoareLogicRequest<LState, LPath, LPC, LProc, HState, HPath, HPC>\n    )\n  {\n    && IsValidConcurrentHoareLogicRequest(ar.cr)\n    && LPathImpliesHPath(ar)\n    && EmbeddedRequestCorresponds(ar)\n    && AtomicInitImpliesOK(ar.l)\n    && AtomicPathRequiresOK(ar.l)\n    && AtomicSteppingThreadHasPC(ar.l)\n    && AtomicTauLeavesPCUnchanged(ar.l)\n    && AtomicThreadCantAffectOtherThreadPCExceptViaFork(ar.l)\n    && LInitImpliesHInit(ar)\n    && LStateToHStateMapsPCsCorrectly(ar)\n    && LHPathPropertiesMatch(ar)\n    && StateConversionPreservesOK(ar)\n    && StateConversionSatisfiesRelation(ar)\n  }\n\n}\n"
  },
  {
    "path": "Armada/strategies/chl/ConcurrentHoareLogic.i.dfy",
    "content": "include \"ConcurrentHoareLogicLemmas.i.dfy\"\n\nmodule ConcurrentHoareLogicModule {\n\n  import opened AnnotatedBehaviorModule\n  import opened InvariantsModule\n  import opened util_collections_seqs_s\n  import opened util_option_s\n  import opened ConcurrentHoareLogicSpecModule\n  import opened ConcurrentHoareLogicLemmasModule\n\n  lemma lemma_CHLGlobalInvariantHoldsWhenActorPresent<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr: ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    b: AnnotatedBehavior<State, Step>,\n    pos: int,\n    actor: Actor\n    )\n    requires IsValidConcurrentHoareLogicRequest(cr)\n    requires AnnotatedBehaviorSatisfiesSpec(b, cr.spec)\n    requires 0 <= pos < |b.states|\n    requires cr.get_actor_pc_stack(b.states[pos], actor).Some?\n    requires cr.state_ok(b.states[pos])\n    ensures  cr.global_inv(b.states[pos])\n  {\n    var pc := cr.get_actor_pc_stack(b.states[pos], actor).v.pc;\n    var proc := cr.pc_to_proc(pc);\n    var overlay := lemma_GetStraightlineBehaviorForCurrentProc(cr, b, pos, actor, proc);\n    lemma_StraightlineBehaviorSatisfiesGlobalInvariant(cr, overlay.sb, actor, proc, |overlay.sb.states| - 1);\n  }\n\n  lemma lemma_CHLLocalInvariantHoldsWhenActorAboutToStep<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr: ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    b: AnnotatedBehavior<State, Step>,\n    pos: int,\n    actor: Actor\n    )\n    requires IsValidConcurrentHoareLogicRequest(cr)\n    requires AnnotatedBehaviorSatisfiesSpec(b, cr.spec)\n    requires 0 <= pos < |b.trace|\n    requires cr.step_to_actor(b.trace[pos]).Some?\n    ensures  cr.local_inv(b.states[pos], cr.step_to_actor(b.trace[pos]).v)\n  {\n    var s := b.states[pos];\n    var s' := b.states[pos + 1];\n    var step := b.trace[pos];\n    assert ActionTuple(s, s', step) in cr.spec.next;\n\n    var actor := cr.step_to_actor(step).v;\n    var effect := cr.step_to_effect(step);\n    var PCStack(pc, stack) := cr.get_actor_pc_stack(s, actor).v;\n    var proc := cr.pc_to_proc(pc);\n    var overlay := lemma_GetStraightlineBehaviorForCurrentProc(cr, b, pos, actor, proc);\n    assert AnnotatedBehaviorSatisfiesSpec(overlay.sb, GetStraightlineSpec(cr, actor, proc));\n    assert StraightlineBehaviorsSatisfyLocalInvariantConditions(cr, overlay.sb, step, s');\n  }\n\n}\n"
  },
  {
    "path": "Armada/strategies/chl/ConcurrentHoareLogicLemmas.i.dfy",
    "content": "include \"ConcurrentHoareLogicSpec.i.dfy\"\n\nmodule ConcurrentHoareLogicLemmasModule {\n\n  import opened util_collections_maps_s\n  import opened util_collections_seqs_s\n  import opened util_option_s\n  import opened AnnotatedBehaviorModule\n  import opened InvariantsModule\n  import opened ConcurrentHoareLogicSpecModule\n\n  ///////////////////////////////////////////\n  // Sequence monotonicity\n  ///////////////////////////////////////////\n\n  predicate {:opaque} SequenceMonotonic(s:seq<int>)\n  {\n    forall i, j :: 0 <= i <= j < |s| ==> s[i] <= s[j]\n  }\n\n  lemma lemma_TakeSequenceMonotonic(s:seq<int>, n:int)\n    requires SequenceMonotonic(s)\n    requires 0 <= n < |s|\n    ensures  SequenceMonotonic(s[..n])\n  {\n    reveal SequenceMonotonic();\n  }\n\n  lemma lemma_ExtendSequenceMonotonic(s:seq<int>, n:int)\n    requires SequenceMonotonic(s)\n    requires |s| > 0 ==> n >= last(s)\n    ensures  SequenceMonotonic(s + [n])\n  {\n    reveal SequenceMonotonic();\n  }\n\n  lemma lemma_UseSequenceMonotonic(s:seq<int>, i:int, j:int)\n    requires SequenceMonotonic(s)\n    requires 0 <= i <= j < |s|\n    ensures  s[i] <= s[j]\n  {\n    reveal SequenceMonotonic();\n  }\n\n  lemma lemma_EstablishSequenceMonotonic(s:seq<int>)\n    requires forall i, j :: 0 <= i <= j < |s| ==> s[i] <= s[j]\n    ensures  SequenceMonotonic(s)\n  {\n    reveal SequenceMonotonic();\n  }\n\n  lemma lemma_ReplaceLastSequenceMonotonic(s:seq<int>, n:int)\n    requires SequenceMonotonic(s)\n    requires |s| > 0\n    requires n >= last(s)\n    ensures  SequenceMonotonic(all_but_last(s) + [n])\n  {\n    reveal SequenceMonotonic();\n  }\n\n  ///////////////////////////////////////////\n  // Overlay validity\n  ///////////////////////////////////////////\n\n  datatype HowStarted = HowStartedInit | HowStartedCall | HowStartedFork\n\n  datatype StraightlineOverlay<State, Step, PC, Proc> = StraightlineOverlay(\n    sb:AnnotatedBehavior<StraightlineState<State, PC>, StraightlineStep<Step, PC, Proc>>,\n    how_started:HowStarted,\n    positions:seq<int>\n    )\n\n  predicate IsCallStep<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    actor:Actor,\n    step:Step\n    )\n  {\n    var step_actor := cr.step_to_actor(step);\n    var effect := cr.step_to_effect(step);\n    && step_actor.Some?\n    && step_actor.v == actor\n    && (effect.CHLStepEffectCall? || effect.CHLStepEffectReturnThenCall?)\n  }\n\n  predicate IsForkStep<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    actor:Actor,\n    s:State\n    )\n  {\n    cr.get_actor_pc_stack(s, actor).None?\n  }\n\n  predicate StraightlineOverlayValid<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    overlay:StraightlineOverlay<State, Step, PC, Proc>,\n    b:AnnotatedBehavior<State, Step>,\n    actor:Actor,\n    proc:Proc\n    )\n  {\n    && AnnotatedBehaviorSatisfiesSpec(overlay.sb, GetStraightlineSpec(cr, actor, proc))\n    && |overlay.positions| == |overlay.sb.states|\n    && |overlay.positions| > 0\n    && SequenceMonotonic(overlay.positions)\n    && (forall i :: 0 <= i < |overlay.positions| ==>\n         && 0 <= overlay.positions[i] < |b.states|\n         && b.states[overlay.positions[i]] == overlay.sb.states[i].state)\n    && (var pos := overlay.positions[0];\n       match overlay.how_started\n         case HowStartedInit => pos == 0\n         case HowStartedCall => 0 < pos <= |b.trace| && IsCallStep(cr, actor, b.trace[pos-1])\n         case HowStartedFork => 0 < pos <= |b.trace| && IsForkStep(cr, actor, b.states[pos-1]))\n  }\n\n  predicate StraightlineOverlayLeadsToPos<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    overlay:StraightlineOverlay<State, Step, PC, Proc>,\n    b:AnnotatedBehavior<State, Step>,\n    actor:Actor,\n    proc:Proc,\n    pos:int\n    )\n  {\n    && StraightlineOverlayValid(cr, overlay, b, actor, proc)\n    && last(overlay.positions) == pos\n  }\n\n  ///////////////////////////////////////////\n  // Lemmas about straightline behaviors\n  ///////////////////////////////////////////\n\n  predicate ActorInProc<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    s:State,\n    actor:Actor,\n    proc:Proc\n    )\n  {\n    && cr.get_actor_pc_stack(s, actor).Some?\n    && var pc := cr.get_actor_pc_stack(s, actor).v.pc;\n      cr.pc_to_proc(pc) == proc\n  }\n\n  lemma lemma_StraightlineBehaviorSatisfiesGlobalInvariant<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    sb:AnnotatedBehavior<StraightlineState<State, PC>, StraightlineStep<Step, PC, Proc>>,\n    actor:Actor,\n    proc:Proc,\n    pos:int\n    )\n    requires IsValidConcurrentHoareLogicRequest(cr)\n    requires AnnotatedBehaviorSatisfiesSpec(sb, GetStraightlineSpec(cr, actor, proc))\n    requires 0 <= pos < |sb.states|\n    ensures  cr.global_inv(sb.states[pos].state)\n    ensures  cr.state_ok(sb.states[pos].state)\n  {\n    if pos == 0 {\n      return;\n    }\n\n    var sspec := GetStraightlineSpec(cr, actor, proc);\n    var prev := pos-1;\n    var ss := sb.states[prev];\n    var ss' := sb.states[prev+1];\n    var sstep := sb.trace[prev];\n    assert ActionTuple(ss, ss', sstep) in sspec.next;\n    assert StraightlineSpecNext(cr, ss, ss', sstep, actor, proc);\n    assert StraightlineSpecNextCommon(cr, ss, ss', sstep, actor);\n    assert cr.global_inv(ss'.state);\n  }\n\n  lemma lemma_StraightlineBehaviorNeverChangesStack<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    sb:AnnotatedBehavior<StraightlineState<State, PC>, StraightlineStep<Step, PC, Proc>>,\n    actor:Actor,\n    proc:Proc,\n    pos:int\n    )\n    requires IsValidConcurrentHoareLogicRequest(cr)\n    requires AnnotatedBehaviorSatisfiesSpec(sb, GetStraightlineSpec(cr, actor, proc))\n    requires 0 <= pos < |sb.states|\n    ensures  var ss0 := sb.states[0];\n             var ss' := sb.states[pos];\n             var s0 := ss0.state;\n             var StraightlineState(s', aux') := ss';\n             && cr.get_actor_pc_stack(s0, actor).Some?\n             && cr.get_actor_pc_stack(s', actor).Some?\n             && var PCStack(pc0, stack0) := cr.get_actor_pc_stack(s0, actor).v;\n               var PCStack(pc', stack') := cr.get_actor_pc_stack(s', actor).v;\n               if aux'.phase.StraightlinePhaseCalled? || aux'.phase.StraightlinePhaseEnsured? then\n                 && |stack'| > 0\n                 && stack'[0] == proc\n                 && stack'[1..] == stack0\n               else\n                 && cr.pc_to_proc(pc') == proc\n                 && stack' == stack0\n    decreases pos\n  {\n    if pos == 0 {\n      return;\n    }\n\n    var prev := pos-1;\n    var ss := sb.states[prev];\n    var ss' := sb.states[prev+1];\n    var sstep := sb.trace[prev];\n\n    var sspec := GetStraightlineSpec(cr, actor, proc);\n    assert ActionTuple(ss, ss', sstep) in sspec.next;\n\n    lemma_StraightlineBehaviorNeverChangesStack(cr, sb, actor, proc, pos-1);\n    assert StraightlineSpecNext(cr, ss, ss', sstep, actor, proc);\n  }\n\n  lemma lemma_VisitedLoopsOnlyContainsLoopHeads<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    sb:AnnotatedBehavior<StraightlineState<State, PC>, StraightlineStep<Step, PC, Proc>>,\n    actor:Actor,\n    proc:Proc,\n    pc:PC,\n    pos:int\n    )\n    requires IsValidConcurrentHoareLogicRequest(cr)\n    requires AnnotatedBehaviorSatisfiesSpec(sb, GetStraightlineSpec(cr, actor, proc))\n    requires 0 <= pos < |sb.states|\n    ensures  pc in sb.states[pos].aux.visited_loops ==> cr.is_loop_head(pc)\n  {\n    if pos == 0 {\n      return;\n    }\n\n    var prev := pos-1;\n    var ss := sb.states[prev];\n    var ss' := sb.states[prev+1];\n    var step := sb.trace[prev];\n\n    var sspec := GetStraightlineSpec(cr, actor, proc);\n    assert ActionTuple(ss, ss', step) in sspec.next;\n    lemma_VisitedLoopsOnlyContainsLoopHeads(cr, sb, actor, proc, pc, prev);\n  }\n\n  lemma lemma_PCVisitedIfInLoopedPhase<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    sb:AnnotatedBehavior<StraightlineState<State, PC>, StraightlineStep<Step, PC, Proc>>,\n    actor:Actor,\n    proc:Proc,\n    pos:int\n    )\n    requires IsValidConcurrentHoareLogicRequest(cr)\n    requires AnnotatedBehaviorSatisfiesSpec(sb, GetStraightlineSpec(cr, actor, proc))\n    requires 0 <= pos < |sb.states|\n    ensures  cr.get_actor_pc_stack(sb.states[pos].state, actor).Some?\n    ensures  var StraightlineState(s, aux) := sb.states[pos];\n             var pc := cr.get_actor_pc_stack(s, actor).v.pc;\n             var phase := aux.phase;\n             && (cr.is_loop_head(pc) && phase.StraightlinePhaseLooped? ==> pc in aux.visited_loops)\n             && (pc in aux.visited_loops ==> cr.is_loop_head(pc))\n  {\n    if pos == 0 {\n      return;\n    }\n\n    var prev := pos-1;\n    lemma_PCVisitedIfInLoopedPhase(cr, sb, actor, proc, prev);\n\n    var sspec := GetStraightlineSpec(cr, actor, proc);\n    assert ActionTuple(sb.states[prev], sb.states[prev+1], sb.trace[prev]) in sspec.next;\n    var pc := cr.get_actor_pc_stack(sb.states[pos].state, actor).v.pc;\n    lemma_VisitedLoopsOnlyContainsLoopHeads(cr, sb, actor, proc, pc, pos);\n  }\n\n  ///////////////////////////////////////////\n  // Lemmas about overlays\n  ///////////////////////////////////////////\n\n  lemma lemma_FindWhenLoopBegan<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    b:AnnotatedBehavior<State, Step>,\n    actor:Actor,\n    proc:Proc,\n    overlay:StraightlineOverlay<State, Step, PC, Proc>,\n    pc:PC,\n    pos:int\n    ) returns (\n    earlier_pos:int\n    )\n    requires IsValidConcurrentHoareLogicRequest(cr)\n    requires StraightlineOverlayValid(cr, overlay, b, actor, proc)\n    requires 0 <= pos < |overlay.sb.states|\n    requires pc in overlay.sb.states[pos].aux.visited_loops\n    requires cr.get_actor_pc_stack(overlay.sb.states[pos].state, actor).Some?\n    ensures  0 <= earlier_pos < pos\n    ensures  cr.is_loop_head(pc)\n    ensures  cr.get_actor_pc_stack(overlay.sb.states[earlier_pos].state, actor).Some?\n    ensures  cr.get_actor_pc_stack(overlay.sb.states[earlier_pos].state, actor).v.pc == pc\n    ensures  overlay.sb.states[earlier_pos].aux.phase.StraightlinePhaseYielded?\n    ensures  pc !in overlay.sb.states[earlier_pos].aux.visited_loops\n    ensures  pc in overlay.sb.states[earlier_pos+1].aux.visited_loops\n    ensures  overlay.sb.states[earlier_pos+1].aux.visited_loops[pc] == overlay.sb.states[pos].aux.visited_loops[pc]\n               == overlay.sb.states[earlier_pos].state\n    ensures  overlay.sb.trace[earlier_pos] == StraightlineStepLoopModifies(pc)\n  {\n    if pos == 0 {\n      assert false;\n      return;\n    }\n\n    lemma_VisitedLoopsOnlyContainsLoopHeads(cr, overlay.sb, actor, proc, pc, pos);\n    var sspec := GetStraightlineSpec(cr, actor, proc);\n    var prev := pos-1;\n    assert ActionTuple(overlay.sb.states[prev], overlay.sb.states[prev+1], overlay.sb.trace[prev]) in sspec.next;\n    lemma_PCVisitedIfInLoopedPhase(cr, overlay.sb, actor, proc, prev);\n\n    if pc !in overlay.sb.states[prev].aux.visited_loops {\n      earlier_pos := prev;\n      return;\n    }\n\n    earlier_pos := lemma_FindWhenLoopBegan(cr, b, actor, proc, overlay, pc, pos-1);\n  }\n\n  lemma lemma_ExtendYieldingOverlayOneStep<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    b:AnnotatedBehavior<State, Step>,\n    actor:Actor,\n    proc:Proc,\n    pos:int,\n    overlay_prev:StraightlineOverlay<State, Step, PC, Proc>\n    ) returns (\n    overlay:StraightlineOverlay<State, Step, PC, Proc>\n    )\n    requires IsValidConcurrentHoareLogicRequest(cr)\n    requires AnnotatedBehaviorSatisfiesSpec(b, cr.spec)\n    requires StraightlineOverlayLeadsToPos(cr, overlay_prev, b, actor, proc, pos-1)\n    requires last(overlay_prev.sb.states).aux.phase.StraightlinePhaseYielded?\n    requires 0 < pos < |b.states|\n    requires cr.state_ok(b.states[pos])\n    requires cr.yield_pred(b.states[pos-1], b.states[pos], actor)\n    requires cr.global_inv(b.states[pos])\n    requires cr.get_actor_pc_stack(b.states[pos], actor) == cr.get_actor_pc_stack(b.states[pos-1], actor)\n    ensures  StraightlineOverlayLeadsToPos(cr, overlay, b, actor, proc, pos)\n    ensures  last(overlay.sb.states).aux.phase.StraightlinePhaseYielded?\n  {\n    var s' := b.states[pos];\n    var sspec := GetStraightlineSpec(cr, actor, proc);\n    var opos := |overlay_prev.sb.trace| - 1;\n    var ss := overlay_prev.sb.states[opos];\n    var ss' := overlay_prev.sb.states[opos+1];\n    var sstep := overlay_prev.sb.trace[opos];\n    assert ActionTuple(ss, ss', sstep) in sspec.next;\n    assert StraightlineSpecNextYield(cr, ss, ss', sstep, actor, proc);\n\n    var new_aux' := StraightlineUpdateAux(cr, ss, actor, sstep, s');\n    var new_ss' := StraightlineState(s', new_aux');\n    var sstates := all_but_last(overlay_prev.sb.states) + [new_ss'];\n    lemma_InvariantPredicateHoldsAtStep(b, overlay_prev.positions[opos], cr.spec, cr.established_inv);\n    lemma_StraightlineBehaviorSatisfiesGlobalInvariant(cr, overlay_prev.sb, actor, proc, opos);\n    lemma_InvariantPredicateHoldsAtStep(b, pos, cr.spec, cr.established_inv);\n    assert StraightlineSpecNextYield(cr, ss, new_ss', sstep, actor, proc);\n    assert StraightlineSpecNext(cr, ss, new_ss', sstep, actor, proc);\n\n    lemma_ReplaceStateOnlyStateNextSeqRight(overlay_prev.sb.states, overlay_prev.sb.trace, sspec.next, new_ss');\n    lemma_ReplaceLastSequenceMonotonic(overlay_prev.positions, pos);\n    overlay := overlay_prev.(sb := overlay_prev.sb.(states := sstates), positions := all_but_last(overlay_prev.positions) + [pos]);\n  }\n\n  lemma lemma_ExtendOverlayWithYielding<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    b:AnnotatedBehavior<State, Step>,\n    actor:Actor,\n    proc:Proc,\n    pos:int,\n    overlay_prev:StraightlineOverlay<State, Step, PC, Proc>\n    ) returns (\n    overlay:StraightlineOverlay<State, Step, PC, Proc>\n    )\n    requires IsValidConcurrentHoareLogicRequest(cr)\n    requires AnnotatedBehaviorSatisfiesSpec(b, cr.spec)\n    requires StraightlineOverlayValid(cr, overlay_prev, b, actor, proc)\n    requires last(overlay_prev.positions) == pos\n    requires last(overlay_prev.sb.states).aux.phase.StraightlinePhaseNormal?\n    ensures  StraightlineOverlayLeadsToPos(cr, overlay, b, actor, proc, pos)\n    ensures  last(overlay.sb.states).aux.phase.StraightlinePhaseYielded?\n  {\n    var ss := last(overlay_prev.sb.states);\n    var StraightlineState(s, aux) := ss;\n    var phase := aux.phase;\n    var overlay_pos := |overlay_prev.sb.trace|;\n    lemma_StraightlineBehaviorNeverChangesStack(cr, overlay_prev.sb, actor, proc, overlay_pos);\n    var pc := cr.get_actor_pc_stack(s, actor).v.pc;\n\n    var sspec := GetStraightlineSpec(cr, actor, proc);\n    var AnnotatedBehavior(sstates, strace) := overlay_prev.sb;\n    var positions := overlay_prev.positions;\n\n    lemma_StraightlineBehaviorSatisfiesGlobalInvariant(cr, overlay_prev.sb, actor, proc, overlay_pos);\n    lemma_InvariantPredicateHoldsAtStep(b, last(overlay_prev.positions), cr.spec, cr.established_inv);\n\n    var sstep := StraightlineStepYield();\n    var aux2 := StraightlineUpdateAux(cr, last(sstates), actor, sstep, s);\n    var sstate' := StraightlineState(s, aux2);\n    assert StraightlineSpecNextYield(cr, last(sstates), sstate', sstep, actor, proc);\n    assert StraightlineSpecNext(cr, last(sstates), sstate', sstep, actor, proc);\n    lemma_ExtendStateNextSeqRight(sstates, strace, sspec.next, sstate', sstep);\n    sstates := sstates + [sstate'];\n    strace := strace + [sstep];\n    lemma_ExtendSequenceMonotonic(positions, pos);\n    positions := positions + [pos];\n\n    overlay := overlay_prev.(sb := AnnotatedBehavior(sstates, strace), positions := positions);\n  }\n\n  lemma lemma_ExtendOverlayWithLooping<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    b:AnnotatedBehavior<State, Step>,\n    actor:Actor,\n    proc:Proc,\n    pos:int,\n    overlay_prev:StraightlineOverlay<State, Step, PC, Proc>\n    ) returns (\n    overlay:StraightlineOverlay<State, Step, PC, Proc>\n    )\n    requires IsValidConcurrentHoareLogicRequest(cr)\n    requires AnnotatedBehaviorSatisfiesSpec(b, cr.spec)\n    requires StraightlineOverlayValid(cr, overlay_prev, b, actor, proc)\n    requires last(overlay_prev.positions) == pos\n    requires last(overlay_prev.sb.states).aux.phase.StraightlinePhaseYielded?\n    requires cr.get_actor_pc_stack(last(overlay_prev.sb.states).state, actor).Some?\n    requires var s := last(overlay_prev.sb.states).state;\n             var pc := cr.get_actor_pc_stack(s, actor).v.pc;\n             cr.is_loop_head(pc)\n    ensures  StraightlineOverlayLeadsToPos(cr, overlay, b, actor, proc, pos)\n    ensures  last(overlay.sb.states).aux.phase.StraightlinePhaseLooped?\n  {\n    var ss := last(overlay_prev.sb.states);\n    var StraightlineState(s, aux) := ss;\n    var phase := aux.phase;\n    var overlay_pos := |overlay_prev.sb.trace|;\n    lemma_StraightlineBehaviorNeverChangesStack(cr, overlay_prev.sb, actor, proc, overlay_pos);\n    var pc := cr.get_actor_pc_stack(s, actor).v.pc;\n\n    var sspec := GetStraightlineSpec(cr, actor, proc);\n    lemma_StraightlineBehaviorSatisfiesGlobalInvariant(cr, overlay_prev.sb, actor, proc, overlay_pos);\n\n    if pc in aux.visited_loops {\n      lemma_VisitedLoopsOnlyContainsLoopHeads(cr, overlay_prev.sb, actor, proc, pc, overlay_pos);\n      assert StraightlineBehaviorsSatisfyLoopModifiesClausesOnJumpBackConditions(cr, overlay_prev.sb, actor, proc);\n      var earlier_pos := lemma_FindWhenLoopBegan(cr, b, actor, proc, overlay_prev, pc, overlay_pos);\n      var ss_earlier := overlay_prev.sb.states[earlier_pos];\n      var sstep := overlay_prev.sb.trace[earlier_pos];\n      var aux_new := StraightlineUpdateAux(cr, ss_earlier, actor, sstep, s);\n      var ss_new := StraightlineState(s, aux_new);\n\n      var states := overlay_prev.sb.states[..earlier_pos + 1] + [ss_new];\n      var trace := overlay_prev.sb.trace[..earlier_pos] + [sstep];\n      var positions := overlay_prev.positions[..earlier_pos + 1] + [pos];\n      lemma_TakeSequenceMonotonic(overlay_prev.positions, earlier_pos + 1);\n      lemma_UseSequenceMonotonic(overlay_prev.positions, earlier_pos, |overlay_prev.positions|-1);\n      lemma_ExtendSequenceMonotonic(overlay_prev.positions[..earlier_pos + 1], pos);\n\n      lemma_TakeStateNextSeq(overlay_prev.sb.states, overlay_prev.sb.trace, sspec.next, earlier_pos);\n\n      lemma_InvariantPredicateHoldsAtStep(b, pos, cr.spec, cr.established_inv);\n      lemma_StraightlineBehaviorNeverChangesStack(cr, overlay_prev.sb, actor, proc, 0);\n      lemma_StraightlineBehaviorNeverChangesStack(cr, overlay_prev.sb, actor, proc, earlier_pos);\n      lemma_StraightlineBehaviorNeverChangesStack(cr, overlay_prev.sb, actor, proc, |overlay_prev.sb.states|-1);\n\n      assert StraightlineSpecNextLoopModifies(cr, ss_earlier, ss_new, sstep, actor, proc, pc);\n      assert StraightlineSpecNext(cr, ss_earlier, ss_new, sstep, actor, proc);\n      lemma_ExtendStateNextSeqRight(overlay_prev.sb.states[..earlier_pos + 1], overlay_prev.sb.trace[..earlier_pos], sspec.next,\n                                    ss_new, sstep);\n      var sb := AnnotatedBehavior(states, trace);\n      assert AnnotatedBehaviorSatisfiesSpec(sb, sspec);\n\n      overlay := StraightlineOverlay(sb, overlay_prev.how_started, positions);\n    }\n    else {\n      var AnnotatedBehavior(sstates, strace) := overlay_prev.sb;\n      var positions := overlay_prev.positions;\n      var sstep0 := StraightlineStepLoopModifies(pc);\n      var aux1 := StraightlineUpdateAux(cr, last(sstates), actor, sstep0, s);\n      var sstate1 := StraightlineState(s, aux1);\n\n      lemma_InvariantPredicateHoldsAtStep(b, last(overlay_prev.positions), cr.spec, cr.established_inv);\n\n      assert StraightlineBehaviorsSatisfyLoopModifiesClausesOnEntryConditions(cr, overlay_prev.sb, actor, proc);\n      assert StraightlineSpecNextLoopModifies(cr, last(sstates), sstate1, sstep0, actor, proc, pc);\n      assert StraightlineSpecNext(cr, last(sstates), sstate1, sstep0, actor, proc);\n      lemma_ExtendStateNextSeqRight(sstates, strace, sspec.next, sstate1, sstep0);\n      sstates := sstates + [sstate1];\n      strace := strace + [sstep0];\n      lemma_ExtendSequenceMonotonic(positions, pos);\n      positions := positions + [pos];\n\n      overlay := overlay_prev.(sb := AnnotatedBehavior(sstates, strace), positions := positions);\n    }\n  }\n\n  ///////////////////////////////////////////////\n  // Cases of obtaining straightline behaviors\n  ///////////////////////////////////////////////\n\n  lemma lemma_GetStraightlineBehaviorCaseInit<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    b:AnnotatedBehavior<State, Step>,\n    actor:Actor,\n    proc:Proc\n    ) returns (\n    overlay:StraightlineOverlay<State, Step, PC, Proc>\n    )\n    requires IsValidConcurrentHoareLogicRequest(cr)\n    requires AnnotatedBehaviorSatisfiesSpec(b, cr.spec)\n    requires cr.get_actor_pc_stack(b.states[0], actor).Some?\n    requires ActorInProc(cr, b.states[0], actor, proc)\n    ensures  StraightlineOverlayLeadsToPos(cr, overlay, b, actor, proc, 0)\n    ensures  last(overlay.sb.states).aux.phase.StraightlinePhaseYielded?\n  {\n    var positions := [0];\n    lemma_EstablishSequenceMonotonic(positions);\n    var s := b.states[0];\n\n    assert ActorsBeginAtEntryPointsWithEmptyStacksConditions(cr, s, actor);\n    assert RequiresClausesSatisfiedInitiallyConditions(cr, s, actor);\n\n    var ss := StraightlineState(s, StraightlineInitAux());\n    var sb := AnnotatedBehavior([ss], []);\n    lemma_InvariantPredicateHoldsAtStart(s, cr.spec, cr.established_inv);\n\n    assert StraightlineSpecInit(cr, sb.states[0], actor, proc);\n\n    var overlay_prev := StraightlineOverlay(sb, HowStartedInit, [0]);\n    overlay := lemma_ExtendOverlayWithYielding(cr, b, actor, proc, 0, overlay_prev);\n  }\n\n  lemma lemma_GetStraightlineBehaviorCaseNormal<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    b:AnnotatedBehavior<State, Step>,\n    pos:int,\n    actor:Actor,\n    proc:Proc\n    ) returns (\n    overlay:StraightlineOverlay<State, Step, PC, Proc>\n    )\n    requires IsValidConcurrentHoareLogicRequest(cr)\n    requires AnnotatedBehaviorSatisfiesSpec(b, cr.spec)\n    requires 0 < pos < |b.states|\n    requires cr.state_ok(b.states[pos])\n    requires ActorInProc(cr, b.states[pos], actor, proc)\n    requires cr.step_to_actor(b.trace[pos-1]).Some?\n    requires cr.step_to_actor(b.trace[pos-1]).v == actor\n    requires cr.step_to_effect(b.trace[pos-1]).CHLStepEffectNormal?\n    ensures  StraightlineOverlayLeadsToPos(cr, overlay, b, actor, proc, pos)\n    ensures  last(overlay.sb.states).aux.phase.StraightlinePhaseYielded?\n    decreases pos, 1\n  {\n    var prev := pos-1;\n    var s := b.states[prev];\n    var s' := b.states[prev+1];\n    var step := b.trace[prev];\n    assert ActionTuple(s, s', step) in cr.spec.next;\n\n    var pc := cr.get_actor_pc_stack(s, actor).v.pc;\n    var pc' := cr.get_actor_pc_stack(s', actor).v.pc;\n    assert cr.pc_to_proc(pc') == cr.pc_to_proc(pc);\n\n    var overlay_prev := lemma_GetStraightlineBehaviorForCurrentProc(cr, b, pos-1, actor, proc);\n    assert StraightlineBehaviorsSatisfyLocalInvariantConditions(cr, overlay_prev.sb, step, s');\n    assert StraightlineBehaviorsSatisfyGlobalInvariantConditions(cr, overlay_prev.sb, step, s');\n    if cr.is_loop_head(pc) {\n      overlay_prev := lemma_ExtendOverlayWithLooping(cr, b, actor, proc, pos-1, overlay_prev);\n    }\n\n    var sspec := GetStraightlineSpec(cr, actor, proc);\n    var sstates := overlay_prev.sb.states;\n    var strace := overlay_prev.sb.trace;\n    var ss := last(sstates);\n    var sstep := StraightlineStepNormal(step);\n    var aux := ss.aux;\n    var aux' := StraightlineUpdateAux(cr, ss, actor, sstep, s');\n    var ss' := StraightlineState(s', aux');\n    var overlay_pos := |overlay_prev.sb.states| - 1;\n\n    lemma_StraightlineBehaviorSatisfiesGlobalInvariant(cr, overlay_prev.sb, actor, proc, overlay_pos);\n    lemma_PCVisitedIfInLoopedPhase(cr, overlay_prev.sb, actor, proc, overlay_pos);\n    lemma_InvariantPredicateHoldsAtStep(b, pos, cr.spec, cr.established_inv);\n    assert StraightlineSpecNextNormal(cr, last(sstates), ss', sstep, actor, proc, step);\n    lemma_ExtendStateNextSeqRight(sstates, strace, sspec.next, ss', sstep);\n    var sb_next := AnnotatedBehavior(sstates + [ss'], strace + [sstep]);\n    var positions := overlay_prev.positions + [pos];\n    lemma_ExtendSequenceMonotonic(overlay_prev.positions, pos);\n    var overlay_next := StraightlineOverlay(sb_next, overlay_prev.how_started, positions);\n    \n    overlay := lemma_ExtendOverlayWithYielding(cr, b, actor, proc, pos, overlay_next);\n  }\n\n  lemma lemma_GetStraightlineBehaviorCaseFork<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    b:AnnotatedBehavior<State, Step>,\n    pos:int,\n    actor:Actor,\n    proc:Proc\n    ) returns (\n    overlay:StraightlineOverlay<State, Step, PC, Proc>\n    )\n    requires IsValidConcurrentHoareLogicRequest(cr)\n    requires AnnotatedBehaviorSatisfiesSpec(b, cr.spec)\n    requires 0 < pos < |b.states|\n    requires cr.state_ok(b.states[pos])\n    requires cr.get_actor_pc_stack(b.states[pos-1], actor).None?\n    requires cr.get_actor_pc_stack(b.states[pos], actor).Some?\n    requires ActorInProc(cr, b.states[pos], actor, proc)\n    requires cr.get_actor_pc_stack(b.states[pos], actor).Some?\n    requires cr.step_to_actor(b.trace[pos-1]).Some?\n    requires cr.step_to_actor(b.trace[pos-1]).v != actor\n    ensures  StraightlineOverlayLeadsToPos(cr, overlay, b, actor, proc, pos)\n    ensures  last(overlay.sb.states).aux.phase.StraightlinePhaseYielded?\n    decreases pos, 0\n  {\n    var prev := pos-1;\n    var s := b.states[prev];\n    var s' := b.states[prev+1];\n    var step := b.trace[prev];\n    var effect := cr.step_to_effect(step);\n    assert ActionTuple(s, s', step) in cr.spec.next;\n\n    var pc' := cr.get_actor_pc_stack(s', actor).v.pc;\n    var forker_actor := cr.step_to_actor(step).v;\n    var PCStack(forker_pc, forker_stack) := cr.get_actor_pc_stack(s, forker_actor).v;\n\n    assert ForkedActorsStartAtEntryPointsWithEmptyStacksConditions(cr, s, s', step, actor);\n    assert !effect.CHLStepEffectExit?;\n    var forker_proc, forker_overlay;\n    if effect.CHLStepEffectReturn? || effect.CHLStepEffectReturnThenCall? {\n      var overlay_alt := lemma_GetStraightlineBehaviorForCurrentProc(cr, b, prev, forker_actor, cr.pc_to_proc(forker_pc));\n      assert StraightlineBehaviorsSatisfyLocalInvariantConditions(cr, overlay_alt.sb, step, s');\n      forker_proc := forker_stack[0];\n      forker_overlay := lemma_GetStraightlineBehaviorForCallerProc(cr, b, prev, forker_actor, forker_proc);\n    }\n    else {\n      forker_proc := cr.step_to_proc(step);\n      forker_overlay := lemma_GetStraightlineBehaviorForCurrentProc(cr, b, prev, forker_actor, forker_proc);\n      assert StraightlineBehaviorsSatisfyLocalInvariantConditions(cr, forker_overlay.sb, step, s');\n    }\n\n    assert StraightlineBehaviorsSatisfyPreconditionsForForksConditions(cr, forker_overlay.sb, step, s', actor);\n    assert StraightlineBehaviorsSatisfyGlobalInvariantConditions(cr, forker_overlay.sb, step, s');\n    assert cr.global_inv(s');\n\n    var myb := forker_overlay.sb;\n    assert AnnotatedBehaviorSatisfiesSpec(myb, GetStraightlineSpec(cr, forker_actor, forker_proc));\n    assert ActionTuple(s, s', step) in cr.spec.next;\n    assert cr.step_to_actor(step).v == forker_actor;\n    assert cr.get_actor_pc_stack(s, forker_actor).Some?;\n    assert cr.get_actor_pc_stack(s, actor).None?;\n    assert cr.get_actor_pc_stack(s', actor).Some?;\n    assert pc' == cr.get_actor_pc_stack(s', actor).v.pc;\n    assert proc == cr.pc_to_proc(pc');\n    assert cr.requires_clauses(proc, s', actor);\n\n    var ss := StraightlineState(s', StraightlineInitAux());\n    var overlay_prev := StraightlineOverlay(AnnotatedBehavior([ss], []), HowStartedFork, [pos]);\n    lemma_EstablishSequenceMonotonic(overlay_prev.positions);\n    lemma_InvariantPredicateHoldsAtStep(b, pos, cr.spec, cr.established_inv);\n\n    assert IsForkStep(cr, actor, s);\n    assert StraightlineSpecInit(cr, ss, actor, proc);\n    assert StraightlineOverlayValid(cr, overlay_prev, b, actor, proc);\n\n    overlay := lemma_ExtendOverlayWithYielding(cr, b, actor, proc, pos, overlay_prev);\n  }\n\n  lemma lemma_GetStraightlineBehaviorCaseOtherActor<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    b:AnnotatedBehavior<State, Step>,\n    pos:int,\n    actor:Actor,\n    proc:Proc\n    ) returns (\n    overlay:StraightlineOverlay<State, Step, PC, Proc>\n    )\n    requires IsValidConcurrentHoareLogicRequest(cr)\n    requires AnnotatedBehaviorSatisfiesSpec(b, cr.spec)\n    requires 0 < pos < |b.states|\n    requires cr.state_ok(b.states[pos])\n    requires cr.get_actor_pc_stack(b.states[pos], actor).Some?\n    requires ActorInProc(cr, b.states[pos], actor, proc)\n    requires cr.step_to_actor(b.trace[pos-1]).Some?\n    requires cr.step_to_actor(b.trace[pos-1]).v != actor\n    ensures  StraightlineOverlayLeadsToPos(cr, overlay, b, actor, proc, pos)\n    ensures  last(overlay.sb.states).aux.phase.StraightlinePhaseYielded?\n    decreases pos, 1\n  {\n    var prev := pos-1;\n    var s := b.states[prev];\n    var s' := b.states[prev+1];\n    var step := b.trace[prev];\n    assert ActionTuple(s, s', step) in cr.spec.next;\n\n    if cr.get_actor_pc_stack(s, actor).None? {\n      overlay := lemma_GetStraightlineBehaviorCaseFork(cr, b, pos, actor, proc);\n      return;\n    }\n\n    var other_actor := cr.step_to_actor(step).v;\n    var PCStack(other_pc, other_stack) := cr.get_actor_pc_stack(s, other_actor).v;\n    var effect := cr.step_to_effect(step);\n\n    var other_proc, overlay_other;\n    if effect.CHLStepEffectReturn? || effect.CHLStepEffectReturnThenCall? {\n      var overlay_alt := lemma_GetStraightlineBehaviorForCurrentProc(cr, b, pos - 1, other_actor, cr.pc_to_proc(other_pc));\n      assert StraightlineBehaviorsSatisfyLocalInvariantConditions(cr, overlay_alt.sb, step, s');\n      other_proc := other_stack[0];\n      overlay_other := lemma_GetStraightlineBehaviorForCallerProc(cr, b, pos - 1, other_actor, other_proc);\n    }\n    else {\n      other_proc := cr.step_to_proc(step);\n      overlay_other := lemma_GetStraightlineBehaviorForCurrentProc(cr, b, pos - 1, other_actor, other_proc);\n      assert StraightlineBehaviorsSatisfyLocalInvariantConditions(cr, overlay_other.sb, step, s');\n    }\n\n    assert StraightlineBehaviorsSatisfyGlobalInvariantConditions(cr, overlay_other.sb, step, s');\n    assert StraightlineBehaviorsSatisfyYieldPredicateConditions(cr, overlay_other.sb, step, s', actor);\n    assert StepsDontChangeOtherActorsExceptViaForkConditions(cr, s, s', step, actor);\n    var overlay_prev := lemma_GetStraightlineBehaviorForCurrentProc(cr, b, pos - 1, actor, proc);\n\n    overlay := lemma_ExtendYieldingOverlayOneStep(cr, b, actor, proc, pos, overlay_prev);\n  }\n\n  lemma lemma_GetStraightlineBehaviorCaseActorless<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    b:AnnotatedBehavior<State, Step>,\n    pos:int,\n    actor:Actor,\n    proc:Proc\n    ) returns (\n    overlay:StraightlineOverlay<State, Step, PC, Proc>\n    )\n    requires IsValidConcurrentHoareLogicRequest(cr)\n    requires AnnotatedBehaviorSatisfiesSpec(b, cr.spec)\n    requires 0 < pos < |b.states|\n    requires cr.state_ok(b.states[pos])\n    requires cr.get_actor_pc_stack(b.states[pos], actor).Some?\n    requires ActorInProc(cr, b.states[pos], actor, proc)\n    requires cr.step_to_actor(b.trace[pos-1]).None?\n    ensures  StraightlineOverlayLeadsToPos(cr, overlay, b, actor, proc, pos)\n    ensures  last(overlay.sb.states).aux.phase.StraightlinePhaseYielded?\n    decreases pos, 1\n  {\n    var prev := pos-1;\n    var s := b.states[prev];\n    var s' := b.states[prev+1];\n    var step := b.trace[prev];\n    assert ActionTuple(s, s', step) in cr.spec.next;\n\n    lemma_InvariantPredicateHoldsAtStep(b, prev, cr.spec, cr.established_inv);\n    assert ActorlessStepsDontChangeActorsConditions(cr, s, s', step, actor);\n    var overlay_prev := lemma_GetStraightlineBehaviorForCurrentProc(cr, b, pos-1, actor, proc);\n\n    lemma_InvariantPredicateHoldsAtStep(b, pos, cr.spec, cr.established_inv);\n    lemma_StraightlineBehaviorSatisfiesGlobalInvariant(cr, overlay_prev.sb, actor, proc, |overlay_prev.sb.states|-1);\n    assert ActorlessStepsMaintainYieldPredicateAndGlobalInvariantConditions(cr, s, s', step, actor);\n\n    overlay := lemma_ExtendYieldingOverlayOneStep(cr, b, actor, proc, pos, overlay_prev);\n  }\n\n  lemma lemma_GetStraightlineBehaviorCaseCall<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    b:AnnotatedBehavior<State, Step>,\n    pos:int,\n    actor:Actor,\n    proc:Proc\n    ) returns (\n    overlay:StraightlineOverlay<State, Step, PC, Proc>\n    )\n    requires IsValidConcurrentHoareLogicRequest(cr)\n    requires AnnotatedBehaviorSatisfiesSpec(b, cr.spec)\n    requires 0 < pos < |b.states|\n    requires cr.state_ok(b.states[pos])\n    requires ActorInProc(cr, b.states[pos], actor, proc)\n    requires cr.step_to_actor(b.trace[pos-1]).Some?\n    requires cr.step_to_actor(b.trace[pos-1]).v == actor\n    requires var effect := cr.step_to_effect(b.trace[pos-1]); effect.CHLStepEffectCall? || effect.CHLStepEffectReturnThenCall?\n    ensures  StraightlineOverlayLeadsToPos(cr, overlay, b, actor, proc, pos)\n    ensures  last(overlay.sb.states).aux.phase.StraightlinePhaseYielded?\n    decreases pos, 1\n  {\n    var prev := pos-1;\n    var s := b.states[prev];\n    var s' := b.states[prev+1];\n    var step := b.trace[prev];\n    assert ActionTuple(s, s', step) in cr.spec.next;\n    var effect := cr.step_to_effect(step);\n    var pc' := cr.get_actor_pc_stack(s', actor).v.pc;\n\n    var caller_pc := cr.get_actor_pc_stack(s, actor).v.pc;\n    var caller_proc := cr.step_to_proc(step);\n    var caller_overlay;\n    if effect.CHLStepEffectCall? {\n      caller_overlay := lemma_GetStraightlineBehaviorForCurrentProc(cr, b, pos-1, actor, caller_proc);\n      assert StraightlineBehaviorsSatisfyLocalInvariantConditions(cr, caller_overlay.sb, step, s');\n    }\n    else {\n      var overlay_alt := lemma_GetStraightlineBehaviorForCurrentProc(cr, b, pos-1, actor, cr.pc_to_proc(caller_pc));\n      assert StraightlineBehaviorsSatisfyLocalInvariantConditions(cr, overlay_alt.sb, step, s');\n      caller_overlay := lemma_GetStraightlineBehaviorForCallerProc(cr, b, pos-1, actor, caller_proc);\n    }\n\n    assert StraightlineBehaviorsSatisfyPreconditionsForCallsConditions(cr, caller_overlay.sb, step, s');\n    assert StraightlineBehaviorsSatisfyGlobalInvariantConditions(cr, caller_overlay.sb, step, s');\n    assert cr.requires_clauses(proc, s', actor);\n    assert cr.global_inv(s');\n\n    var positions := [pos];\n    lemma_EstablishSequenceMonotonic(positions);\n\n    var ss := StraightlineState(s', StraightlineInitAux());\n    var sb := AnnotatedBehavior([ss], []);\n    lemma_InvariantPredicateHoldsAtStep(b, pos, cr.spec, cr.established_inv);\n\n    var overlay_prev := StraightlineOverlay(sb, HowStartedCall, positions);\n    assert StraightlineSpecInit(cr, ss, actor, proc);\n    overlay := lemma_ExtendOverlayWithYielding(cr, b, actor, proc, pos, overlay_prev);\n  }\n\n  lemma lemma_GetStraightlineBehaviorCaseReturn<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    b:AnnotatedBehavior<State, Step>,\n    pos:int,\n    actor:Actor,\n    proc:Proc\n    ) returns (\n    overlay:StraightlineOverlay<State, Step, PC, Proc>\n    )\n    requires IsValidConcurrentHoareLogicRequest(cr)\n    requires AnnotatedBehaviorSatisfiesSpec(b, cr.spec)\n    requires 0 < pos < |b.states|\n    requires cr.state_ok(b.states[pos])\n    requires ActorInProc(cr, b.states[pos], actor, proc)\n    requires cr.step_to_actor(b.trace[pos-1]).Some?\n    requires cr.step_to_actor(b.trace[pos-1]).v == actor\n    requires cr.step_to_effect(b.trace[pos-1]).CHLStepEffectReturn?\n    ensures  StraightlineOverlayLeadsToPos(cr, overlay, b, actor, proc, pos)\n    ensures  last(overlay.sb.states).aux.phase.StraightlinePhaseYielded?\n    decreases pos, 1\n  {\n    var prev := pos-1;\n    var s := b.states[prev];\n    var s' := b.states[prev+1];\n    var step := b.trace[prev];\n    assert ActionTuple(s, s', step) in cr.spec.next;\n    assert s' == b.states[pos];\n\n    var PCStack(pc, stack) := cr.get_actor_pc_stack(s, actor).v;\n    var PCStack(pc', stack') := cr.get_actor_pc_stack(s', actor).v;\n\n    var caller_proc := cr.pc_to_proc(pc);\n    var caller_overlay := lemma_GetStraightlineBehaviorForCurrentProc(cr, b, pos-1, actor, caller_proc);\n    assert StraightlineBehaviorsSatisfyLocalInvariantConditions(cr, caller_overlay.sb, step, s');\n\n    var overlay_prev := lemma_GetStraightlineBehaviorForCallerProc(cr, b, pos-1, actor, proc);\n\n    var sspec := GetStraightlineSpec(cr, actor, proc);\n    var sstates := overlay_prev.sb.states;\n    var strace := overlay_prev.sb.trace;\n    var ss := last(sstates);\n    var aux := ss.aux;\n    var sstep := StraightlineStepReturn(step);\n    var aux' := StraightlineUpdateAux(cr, ss, actor, sstep, s');\n    var ss' := StraightlineState(s', aux');\n    var overlay_pos := |overlay_prev.sb.states| - 1;\n\n    lemma_StraightlineBehaviorSatisfiesGlobalInvariant(cr, overlay_prev.sb, actor, proc, overlay_pos);\n    lemma_PCVisitedIfInLoopedPhase(cr, overlay_prev.sb, actor, proc, overlay_pos);\n    assert StraightlineBehaviorsSatisfyGlobalInvariantConditions(cr, overlay_prev.sb, step, s');\n    lemma_InvariantPredicateHoldsAtStep(b, pos, cr.spec, cr.established_inv);\n    assert StraightlineSpecNextReturn(cr, last(sstates), ss', sstep, actor, proc, step);\n    lemma_ExtendStateNextSeqRight(sstates, strace, sspec.next, ss', sstep);\n    var sb_next := AnnotatedBehavior(sstates + [ss'], strace + [sstep]);\n    var positions := overlay_prev.positions + [pos];\n    lemma_ExtendSequenceMonotonic(overlay_prev.positions, pos);\n    var overlay_next := StraightlineOverlay(sb_next, overlay_prev.how_started, positions);\n    \n    overlay := lemma_ExtendOverlayWithYielding(cr, b, actor, proc, pos, overlay_next);\n  }\n\n  ///////////////////////////////////////////\n  // Obtaining straightline behaviors\n  ///////////////////////////////////////////\n\n  lemma lemma_GetStraightlineBehaviorForCallerProc<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    b:AnnotatedBehavior<State, Step>,\n    pos:int,\n    actor:Actor,\n    proc:Proc\n    ) returns (\n    overlay:StraightlineOverlay<State, Step, PC, Proc>\n    )\n    requires IsValidConcurrentHoareLogicRequest(cr)\n    requires AnnotatedBehaviorSatisfiesSpec(b, cr.spec)\n    requires 0 <= pos < |b.states|\n    requires cr.state_ok(b.states[pos])\n    requires cr.get_actor_pc_stack(b.states[pos], actor).Some?\n    requires var PCStack(pc, stack) := cr.get_actor_pc_stack(b.states[pos], actor).v;\n             |stack| > 0 && stack[0] == proc && cr.is_return_site(pc)\n    ensures  StraightlineOverlayLeadsToPos(cr, overlay, b, actor, proc, pos)\n    ensures  last(overlay.sb.states).aux.phase.StraightlinePhaseEnsured?\n    decreases pos, 3\n  {\n    var s := b.states[pos];\n    var PCStack(pc, stack) := cr.get_actor_pc_stack(s, actor).v;\n    var callee := cr.pc_to_proc(pc);\n    var overlay_alt := lemma_GetStraightlineBehaviorForCurrentProc(cr, b, pos, actor, callee);\n    lemma_StraightlineBehaviorNeverChangesStack(cr, overlay_alt.sb, actor, callee, 0);\n    lemma_StraightlineBehaviorNeverChangesStack(cr, overlay_alt.sb, actor, callee, |overlay_alt.sb.states|-1);\n\n    var call_pos := overlay_alt.positions[0] - 1;\n\n    if overlay_alt.how_started.HowStartedInit? {\n      assert ActorsBeginAtEntryPointsWithEmptyStacksConditions(cr, b.states[overlay_alt.positions[0]], actor);\n      assert false;\n    }\n\n    var call_s := b.states[call_pos];\n    var call_s' := b.states[call_pos+1];\n    var call_step := b.trace[call_pos];\n    assert ActionTuple(call_s, call_s', call_step) in cr.spec.next;\n    \n    if overlay_alt.how_started.HowStartedFork? {\n      assert ForkedActorsStartAtEntryPointsWithEmptyStacksConditions(cr, call_s, call_s', call_step, actor);\n      assert false;\n    }\n\n    assert overlay_alt.how_started.HowStartedCall?;\n    assert IsCallStep(cr, actor, call_step);\n\n    assert proc == cr.step_to_proc(call_step);\n    var call_effect := cr.step_to_effect(call_step);\n    assert call_effect.CHLStepEffectCall? || call_effect.CHLStepEffectReturnThenCall?;\n    var simple_call := call_effect.CHLStepEffectCall?;\n\n    assert cr.requires_clauses(callee, call_s', actor);\n\n    assert StraightlineBehaviorsSatisfyPostconditionsConditions(cr, overlay_alt.sb, actor, callee);\n    assert cr.ensures_clauses(callee, overlay_alt.sb.states[0].state, last(overlay_alt.sb.states).state, actor);\n    assert cr.ensures_clauses(callee, call_s', s, actor);\n\n    lemma_UseSequenceMonotonic(overlay_alt.positions, 0, |overlay_alt.positions|-1);\n    lemma_StraightlineBehaviorNeverChangesStack(cr, overlay_alt.sb, actor, callee, |overlay_alt.sb.states| - 1);\n    var overlay_prev;\n    if simple_call {\n      overlay_prev := lemma_GetStraightlineBehaviorForCurrentProc(cr, b, call_pos, actor, proc);\n      assert StraightlineBehaviorsSatisfyLocalInvariantConditions(cr, overlay_prev.sb, call_step, call_s');\n      assert StraightlineBehaviorsSatisfyGlobalInvariantConditions(cr, overlay_prev.sb, call_step, call_s');\n      if cr.is_loop_head(cr.get_actor_pc_stack(call_s, actor).v.pc) {\n        overlay_prev := lemma_ExtendOverlayWithLooping(cr, b, actor, proc, call_pos, overlay_prev);\n      }\n    }\n    else {\n      var caller_pc := cr.get_actor_pc_stack(call_s, actor).v.pc;\n      var caller_proc := cr.pc_to_proc(caller_pc);\n      var caller_overlay := lemma_GetStraightlineBehaviorForCurrentProc(cr, b, call_pos, actor, caller_proc);\n      assert StraightlineBehaviorsSatisfyLocalInvariantConditions(cr, caller_overlay.sb, call_step, call_s');\n      overlay_prev := lemma_GetStraightlineBehaviorForCallerProc(cr, b, call_pos, actor, proc);\n      assert StraightlineBehaviorsSatisfyGlobalInvariantConditions(cr, overlay_prev.sb, call_step, call_s');\n    }\n\n    var sspec := GetStraightlineSpec(cr, actor, proc);\n    var sstates := overlay_prev.sb.states;\n    var strace := overlay_prev.sb.trace;\n    var positions := overlay_prev.positions;\n\n    var sstep0;\n    if simple_call {\n      sstep0 := StraightlineStepCall(call_step);\n    }\n    else {\n      sstep0 := StraightlineStepReturnThenCall(call_step);\n    }\n    var aux0 := StraightlineUpdateAux(cr, last(sstates), actor, sstep0, call_s');\n    var sstate0 := StraightlineState(call_s', aux0);\n\n    var sstep1 := StraightlineStepEnsures(callee);\n    var aux1 := StraightlineUpdateAux(cr, sstate0, actor, sstep1, s);\n    var sstate1 := StraightlineState(s, aux1);\n\n    var overlay_pos := |overlay_prev.sb.states| - 1;\n    lemma_ExtendSequenceMonotonic(positions, call_pos + 1);\n    lemma_PCVisitedIfInLoopedPhase(cr, overlay_prev.sb, actor, proc, overlay_pos);\n    if simple_call {\n      assert StraightlineSpecNextCall(cr, last(sstates), sstate0, sstep0, actor, proc, call_step);\n    }\n    else {\n      assert StraightlineSpecNextReturnThenCall(cr, last(sstates), sstate0, sstep0, actor, proc, call_step);\n    }\n    assert StraightlineSpecNext(cr, last(sstates), sstate0, sstep0, actor, proc);\n    lemma_ExtendStateNextSeqRight(sstates, strace, sspec.next, sstate0, sstep0);\n\n    lemma_ExtendSequenceMonotonic(positions + [call_pos + 1], pos);\n    lemma_StraightlineBehaviorSatisfiesGlobalInvariant(cr, overlay_alt.sb, actor, callee, |overlay_alt.sb.states| - 1);\n    lemma_InvariantPredicateHoldsAtStep(b, pos, cr.spec, cr.established_inv);\n    assert StraightlineSpecNextEnsures(cr, sstate0, sstate1, sstep1, actor, proc, callee);\n    assert StraightlineSpecNext(cr, sstate0, sstate1, sstep1, actor, proc);\n    lemma_ExtendStateNextSeqRight(sstates + [sstate0], strace + [sstep0], sspec.next, sstate1, sstep1);\n\n    var sb := AnnotatedBehavior(sstates + [sstate0] + [sstate1], strace + [sstep0] + [sstep1]);\n    overlay := StraightlineOverlay(sb, overlay_prev.how_started, positions + [call_pos + 1] + [pos]);\n  }\n\n  lemma lemma_GetStraightlineBehaviorForCurrentProc<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    b:AnnotatedBehavior<State, Step>,\n    pos:int,\n    actor:Actor,\n    proc:Proc\n    ) returns (\n    overlay:StraightlineOverlay<State, Step, PC, Proc>\n    )\n    requires IsValidConcurrentHoareLogicRequest(cr)\n    requires AnnotatedBehaviorSatisfiesSpec(b, cr.spec)\n    requires 0 <= pos < |b.states|\n    requires cr.get_actor_pc_stack(b.states[pos], actor).Some?\n    requires cr.state_ok(b.states[pos])\n    requires ActorInProc(cr, b.states[pos], actor, proc)\n    ensures  StraightlineOverlayLeadsToPos(cr, overlay, b, actor, proc, pos)\n    ensures  last(overlay.sb.states).aux.phase.StraightlinePhaseYielded?\n    decreases pos, 2\n  {\n    if pos == 0 {\n      overlay := lemma_GetStraightlineBehaviorCaseInit(cr, b, actor, proc);\n      return;\n    }\n\n    var prev := pos-1;\n    var step := b.trace[prev];\n    \n    if cr.step_to_actor(step).Some? && cr.step_to_actor(step).v != actor {\n      overlay := lemma_GetStraightlineBehaviorCaseOtherActor(cr, b, pos, actor, proc);\n      return;\n    }\n\n    assert ActionTuple(b.states[prev], b.states[prev+1], b.trace[prev]) in cr.spec.next;\n\n    var effect := cr.step_to_effect(step);\n    match effect {\n      case CHLStepEffectNormal =>            overlay := lemma_GetStraightlineBehaviorCaseNormal(cr, b, pos, actor, proc);\n      case CHLStepEffectCall(_) =>           overlay := lemma_GetStraightlineBehaviorCaseCall(cr, b, pos, actor, proc);\n      case CHLStepEffectReturnThenCall(_) => overlay := lemma_GetStraightlineBehaviorCaseCall(cr, b, pos, actor, proc);\n      case CHLStepEffectReturn =>            overlay := lemma_GetStraightlineBehaviorCaseReturn(cr, b, pos, actor, proc);\n      case CHLStepEffectActorless =>         overlay := lemma_GetStraightlineBehaviorCaseActorless(cr, b, pos, actor, proc);\n      case CHLStepEffectExit =>              assert false;\n    }\n  }\n\n}\n"
  },
  {
    "path": "Armada/strategies/chl/ConcurrentHoareLogicSpec.i.dfy",
    "content": "include \"../refinement/AnnotatedBehavior.i.dfy\"\ninclude \"../invariants.i.dfy\"\ninclude \"../../util/collections/maps.s.dfy\"\ninclude \"../../util/collections/seqs.s.dfy\"\ninclude \"../../util/option.s.dfy\"\n\nmodule ConcurrentHoareLogicSpecModule {\n\n  // Yields are dealt with as follows.\n  // * On a call, the callee has to deal with a yield happening after the requires clause is satisfied.\n  // * On reaching a loop head for the first time, the loop modifies clause must hold before the yield.\n  // * On reaching a loop a subsequent time, the loop modifies clause must hold between s1 and s2, where s1 is the\n  //   state on reaching the loop head before a yield, and s2 is the state on returning to the loop head before yielding.\n  // * After executing a loop-modifies clause, a yield can happen.\n  // * On a return, the callee/returner must deal with a yield happening after reaching the return site.  That is,\n  //   it must ensure the postcondition even after a yield.\n  // * After executing an ensures clause, one does not have to worry about a yield happening.\n\n  // The result of calling cr.step_to_proc on a step indicates which procedure that step is part of.\n  // * A step that calls from method X into method Y is considered part of method X.\n  // * A step that returns from method Y to method X is considered part of method X.  That's not a typo:  it's considered\n  //   part of the caller, not the callee.\n  // * A step that returns from method Y to method X and then calls method Z is likewise considered part of method X.\n\n  import opened util_collections_maps_s\n  import opened util_collections_seqs_s\n  import opened util_option_s\n  import opened AnnotatedBehaviorModule\n  import opened InvariantsModule\n\n  /////////////////////////////////////////////////////\n  // Type definitions\n  /////////////////////////////////////////////////////\n\n  datatype StraightlineStep<Step, PC, Proc> = StraightlineStepNormal(step:Step)\n                                            | StraightlineStepLoopModifies(pc:PC)\n                                            | StraightlineStepYield\n                                            | StraightlineStepCall(step:Step)\n                                            | StraightlineStepEnsures(callee:Proc)\n                                            | StraightlineStepReturn(step:Step)\n                                            | StraightlineStepReturnThenCall(step:Step)\n\n  datatype StraightlinePhase = StraightlinePhaseNormal\n                             | StraightlinePhaseLooped\n                             | StraightlinePhaseYielded\n                             | StraightlinePhaseCalled\n                             | StraightlinePhaseEnsured\n\n  datatype StraightlineAux<State, PC> = StraightlineAux(phase:StraightlinePhase, visited_loops:map<PC, State>)\n\n  datatype StraightlineState<State, PC> = StraightlineState(state:State, aux:StraightlineAux<State, PC>)\n\n  datatype PCStack<PC, Proc> = PCStack(pc:PC, stack:seq<Proc>)\n\n  datatype CHLStepEffect<Proc> = CHLStepEffectNormal\n                               | CHLStepEffectCall(callee:Proc)\n                               | CHLStepEffectReturn\n                               | CHLStepEffectExit\n                               | CHLStepEffectReturnThenCall(callee:Proc)\n                               | CHLStepEffectActorless\n                               | CHLStepEffectStop\n\n  datatype ConcurrentHoareLogicRequest<!State(==), !Actor(==), !Step(==), !PC(==), !Proc(==)> = ConcurrentHoareLogicRequest(\n    spec:AnnotatedBehaviorSpec<State, Step>,\n    step_to_actor:Step->Option<Actor>,\n    step_to_proc:Step->Proc,\n    get_actor_pc_stack:(State, Actor)->Option<PCStack<PC, Proc>>,\n    state_ok:State->bool,\n    pc_to_proc:PC->Proc,\n    is_entry_point:PC->bool,\n    is_loop_head:PC->bool,\n    is_return_site:PC->bool,\n    step_to_effect:Step->CHLStepEffect<Proc>,\n    established_inv:State->bool,\n    global_inv:State->bool,\n    local_inv:(State, Actor)->bool,\n    yield_pred:(State, State, Actor)->bool,\n    requires_clauses:(Proc, State, Actor)->bool,\n    ensures_clauses:(Proc, State, State, Actor)->bool,\n    loop_modifies_clauses:(PC, State, State, Actor)->bool\n    )\n\n  /////////////////////////////////////////////////////\n  // Straightline behavior specification\n  /////////////////////////////////////////////////////\n\n  function StraightlineInitAux<State, PC>() : StraightlineAux<State, PC>\n  {\n    StraightlineAux(StraightlinePhaseNormal, map [])\n  }\n\n  predicate StraightlineSpecInit<State, Actor, Step, PC, Proc>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    ss:StraightlineState<State, PC>,\n    actor:Actor,\n    proc:Proc\n    )\n  {\n    // A straightline behavior begins with the actor at the beginning of a procedure\n    var s := ss.state;\n    && cr.get_actor_pc_stack(s, actor).Some?\n    && var pc := cr.get_actor_pc_stack(s, actor).v.pc;\n    && cr.pc_to_proc(pc) == proc\n    && cr.is_entry_point(pc)\n    && cr.established_inv(s)\n    && cr.global_inv(s)\n    && cr.state_ok(s)\n    && cr.requires_clauses(proc, s, actor)\n    && ss.aux == StraightlineInitAux()\n  }\n\n  function StraightlineUpdateAux<State, Actor, Step, PC, Proc>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    ss:StraightlineState<State, PC>,\n    actor:Actor,\n    sstep:StraightlineStep<Step, PC, Proc>,\n    s':State\n    ) : StraightlineAux<State, PC>\n  {\n    var phase' :=\n      match sstep\n        case StraightlineStepNormal(_) =>          StraightlinePhaseNormal\n        case StraightlineStepLoopModifies(_) =>    StraightlinePhaseLooped\n        case StraightlineStepYield() =>            StraightlinePhaseYielded\n        case StraightlineStepCall(_) =>            StraightlinePhaseCalled\n        case StraightlineStepEnsures(_) =>         StraightlinePhaseEnsured\n        case StraightlineStepReturn(_) =>          StraightlinePhaseNormal\n        case StraightlineStepReturnThenCall(_) =>  StraightlinePhaseCalled\n      ;\n    var StraightlineState(s, aux) := ss;\n    var visited_loops' := if sstep.StraightlineStepLoopModifies? && cr.get_actor_pc_stack(s, actor).Some? then\n                            aux.visited_loops[cr.get_actor_pc_stack(s, actor).v.pc := s]\n                          else\n                            aux.visited_loops;\n    StraightlineAux(phase', visited_loops')\n  }\n\n  predicate StraightlineSpecNextCommon<State, Actor, Step, PC, Proc>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    ss:StraightlineState<State, PC>,\n    ss':StraightlineState<State, PC>,\n    sstep:StraightlineStep<Step, PC, Proc>,\n    actor:Actor\n    )\n  {\n    var StraightlineState(s, aux) := ss;\n    var StraightlineState(s', aux') := ss';\n\n    // The actor must be present both before and after the step.\n\n    && cr.get_actor_pc_stack(s, actor).Some?\n    && cr.get_actor_pc_stack(s', actor).Some?\n\n    // The type of step the state machine can take is dictated by the current phase.  (The phase depends on the previous\n    // step, so this restriction restricts consecutive pairs of steps.)\n\n    && var pc := cr.get_actor_pc_stack(s, actor).v.pc;\n    && (match aux.phase\n         case StraightlinePhaseNormal => sstep.StraightlineStepYield?\n         case StraightlinePhaseLooped => sstep.StraightlineStepNormal? || sstep.StraightlineStepCall?\n         case StraightlinePhaseYielded => if cr.is_loop_head(pc) then sstep.StraightlineStepLoopModifies?\n                                          else sstep.StraightlineStepNormal? || sstep.StraightlineStepCall?\n         case StraightlinePhaseCalled => sstep.StraightlineStepEnsures?\n         case StraightlinePhaseEnsured => sstep.StraightlineStepReturn? || sstep.StraightlineStepReturnThenCall?)\n\n    // The established and global invariants are always preserved, and the state is always OK.\n\n    && cr.established_inv(s')\n    && cr.global_inv(s')\n    && cr.state_ok(s')\n\n    // The auxiliary information is a deterministic function of the current state and the straightline step taken.\n    \n    && aux' == StraightlineUpdateAux(cr, ss, actor, sstep, s')\n\n    // If the state machine has reached an already-visited loop head and yielded, it can't execute further.\n\n    && !(pc in aux.visited_loops && aux.phase.StraightlinePhaseYielded?)\n\n    // The state machine can never return, except to return from a call that it made to another method.\n\n    && (sstep.StraightlineStepReturn? || sstep.StraightlineStepReturnThenCall? ==> ss.aux.phase.StraightlinePhaseEnsured?)\n  }\n\n  predicate StraightlineSpecNextStep<State, Actor, Step, PC, Proc>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    ss:StraightlineState<State, PC>,\n    ss':StraightlineState<State, PC>,\n    sstep:StraightlineStep<Step, PC, Proc>,\n    actor:Actor,\n    proc:Proc,\n    step:Step\n    )\n  {\n    && StraightlineSpecNextCommon(cr, ss, ss', sstep, actor)\n    && cr.step_to_actor(step).Some?\n    && cr.step_to_actor(step).v == actor\n    && cr.step_to_proc(step) == proc\n    && ActionTuple(ss.state, ss'.state, step) in cr.spec.next\n    && cr.local_inv(ss.state, actor)\n  }\n\n  predicate StraightlineSpecNextNormal<State, Actor, Step, PC, Proc>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    ss:StraightlineState<State, PC>,\n    ss':StraightlineState<State, PC>,\n    sstep:StraightlineStep<Step, PC, Proc>,\n    actor:Actor,\n    proc:Proc,\n    step:Step\n    )\n    requires sstep.StraightlineStepNormal?\n  {\n    && StraightlineSpecNextStep(cr, ss, ss', sstep, actor, proc, step)\n    && cr.step_to_effect(step).CHLStepEffectNormal?\n  }\n\n  predicate StraightlineSpecNextCall<State, Actor, Step, PC, Proc>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    ss:StraightlineState<State, PC>,\n    ss':StraightlineState<State, PC>,\n    sstep:StraightlineStep<Step, PC, Proc>,\n    actor:Actor,\n    proc:Proc,\n    step:Step\n    )\n    requires sstep.StraightlineStepCall?\n  {\n    && StraightlineSpecNextStep(cr, ss, ss', sstep, actor, proc, step)\n    && cr.step_to_effect(step).CHLStepEffectCall?\n    && var s' := ss'.state;\n      var callee := cr.step_to_effect(step).callee;\n    && callee == cr.pc_to_proc(cr.get_actor_pc_stack(s', actor).v.pc)\n    && cr.requires_clauses(callee, s', actor)\n  }\n\n  predicate StraightlineSpecNextReturn<State, Actor, Step, PC, Proc>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    ss:StraightlineState<State, PC>,\n    ss':StraightlineState<State, PC>,\n    sstep:StraightlineStep<Step, PC, Proc>,\n    actor:Actor,\n    proc:Proc,\n    step:Step\n    )\n    requires sstep.StraightlineStepReturn?\n  {\n    && StraightlineSpecNextStep(cr, ss, ss', sstep, actor, proc, step)\n    && cr.step_to_effect(step).CHLStepEffectReturn?\n  }\n\n  predicate StraightlineSpecNextReturnThenCall<State, Actor, Step, PC, Proc>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    ss:StraightlineState<State, PC>,\n    ss':StraightlineState<State, PC>,\n    sstep:StraightlineStep<Step, PC, Proc>,\n    actor:Actor,\n    proc:Proc,\n    step:Step\n    )\n    requires sstep.StraightlineStepReturnThenCall?\n  {\n    && StraightlineSpecNextStep(cr, ss, ss', sstep, actor, proc, step)\n    && cr.step_to_effect(step).CHLStepEffectReturnThenCall?\n    && var s' := ss'.state;\n      var callee := cr.step_to_effect(step).callee;\n    && callee == cr.pc_to_proc(cr.get_actor_pc_stack(s', actor).v.pc)\n    && cr.requires_clauses(callee, s', actor)\n  }\n\n  predicate StraightlineSpecNextYield<State, Actor, Step, PC, Proc>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    ss:StraightlineState<State, PC>,\n    ss':StraightlineState<State, PC>,\n    sstep:StraightlineStep<Step, PC, Proc>,\n    actor:Actor,\n    proc:Proc\n    )\n    requires sstep.StraightlineStepYield?\n  {\n    && StraightlineSpecNextCommon(cr, ss, ss', sstep, actor)\n    && var s := ss.state;\n       var s' := ss'.state;\n    && cr.get_actor_pc_stack(s', actor) == cr.get_actor_pc_stack(s, actor)\n    && cr.yield_pred(s, s', actor)\n  }\n\n  predicate StraightlineSpecNextLoopModifies<State, Actor, Step, PC, Proc>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    ss:StraightlineState<State, PC>,\n    ss':StraightlineState<State, PC>,\n    sstep:StraightlineStep<Step, PC, Proc>,\n    actor:Actor,\n    proc:Proc,\n    pc:PC\n    )\n    requires sstep.StraightlineStepLoopModifies?\n  {\n    && StraightlineSpecNextCommon(cr, ss, ss', sstep, actor)\n    && var s := ss.state;\n      var s' := ss'.state;\n    && pc == cr.get_actor_pc_stack(s, actor).v.pc\n    && cr.is_loop_head(pc)\n    && cr.get_actor_pc_stack(s', actor) == cr.get_actor_pc_stack(s, actor)\n    && cr.loop_modifies_clauses(pc, s, s', actor)\n  }\n\n  predicate StraightlineSpecNextEnsures<State, Actor, Step, PC, Proc>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    ss:StraightlineState<State, PC>,\n    ss':StraightlineState<State, PC>,\n    sstep:StraightlineStep<Step, PC, Proc>,\n    actor:Actor,\n    proc:Proc,\n    callee:Proc\n    )\n    requires sstep.StraightlineStepEnsures?\n  {\n    && StraightlineSpecNextCommon(cr, ss, ss', sstep, actor)\n    && var s := ss.state;\n       var s' := ss'.state;\n       var PCStack(pc, stack) := cr.get_actor_pc_stack(s, actor).v;\n       var PCStack(pc', stack') := cr.get_actor_pc_stack(s', actor).v;\n    && callee == cr.pc_to_proc(pc)\n    && callee == cr.pc_to_proc(pc')\n    && cr.is_return_site(pc')\n    && stack' == stack\n    && cr.ensures_clauses(callee, s, s', actor)\n  }\n\n  predicate StraightlineSpecNext<State, Actor, Step, PC, Proc>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    ss:StraightlineState<State, PC>,\n    ss':StraightlineState<State, PC>,\n    sstep:StraightlineStep<Step, PC, Proc>,\n    actor:Actor,\n    proc:Proc\n    )\n  {\n    match sstep\n      case StraightlineStepNormal(step) =>\n        StraightlineSpecNextNormal(cr, ss, ss', sstep, actor, proc, step)\n\n      case StraightlineStepLoopModifies(pc) =>\n        StraightlineSpecNextLoopModifies(cr, ss, ss', sstep, actor, proc, pc)\n\n      case StraightlineStepYield() =>\n        StraightlineSpecNextYield(cr, ss, ss', sstep, actor, proc)\n\n      case StraightlineStepCall(step) =>\n        StraightlineSpecNextCall(cr, ss, ss', sstep, actor, proc, step)\n\n      case StraightlineStepEnsures(callee) =>\n        StraightlineSpecNextEnsures(cr, ss, ss', sstep, actor, proc, callee)\n\n      case StraightlineStepReturn(step) =>\n        StraightlineSpecNextReturn(cr, ss, ss', sstep, actor, proc, step)\n\n      case StraightlineStepReturnThenCall(step) =>\n        StraightlineSpecNextReturnThenCall(cr, ss, ss', sstep, actor, proc, step)\n  }\n\n  function GetStraightlineSpec<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    actor:Actor,\n    proc:Proc\n    ) :\n    AnnotatedBehaviorSpec<StraightlineState<State, PC>, StraightlineStep<Step, PC, Proc>>\n  {\n    AnnotatedBehaviorSpec(iset s | StraightlineSpecInit(cr, s, actor, proc),\n                          iset s, s', step | StraightlineSpecNext(cr, s, s', step, actor, proc) :: ActionTuple(s, s', step))\n  }\n\n  /////////////////////////////////////////////////////\n  // Simple parameter validity\n  /////////////////////////////////////////////////////\n\n  predicate LoopHeadsArentReturnSites<PC(!new)>(\n    is_loop_head:PC->bool,\n    is_return_site:PC->bool\n    )\n  {\n    forall pc :: !(is_loop_head(pc) && is_return_site(pc))\n  }\n\n  predicate YieldPredicateReflexive<State(!new), Actor(!new), Step, PC, Proc>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>\n    )\n  {\n    forall s, actor {:trigger cr.yield_pred(s, s, actor)} ::\n      cr.state_ok(s) && cr.get_actor_pc_stack(s, actor).Some? ==> cr.yield_pred(s, s, actor)\n  }\n\n  predicate YieldPredicateTransitive<State(!new), Actor(!new), Step, PC, Proc>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>\n    )\n  {\n    forall s1, s2, s3, actor {:trigger cr.yield_pred(s1, s2, actor), cr.yield_pred(s2, s3, actor)} ::\n       && cr.established_inv(s1)\n       && cr.global_inv(s1)\n       && cr.established_inv(s2)\n       && cr.global_inv(s2)\n       && cr.yield_pred(s1, s2, actor)\n       && cr.yield_pred(s2, s3, actor)\n       ==> cr.yield_pred(s1, s3, actor)\n  }\n\n  /////////////////////////////////////////////////////\n  // State initialization\n  /////////////////////////////////////////////////////\n\n  predicate ActorsBeginAtEntryPointsWithEmptyStacksConditions<State(!new), Actor(!new), Step(!new), PC, Proc>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    s:State,\n    actor:Actor\n    )\n  {\n    && s in cr.spec.init\n    && cr.get_actor_pc_stack(s, actor).Some?\n  }\n\n  predicate ActorsBeginAtEntryPointsWithEmptyStacks<State(!new), Actor(!new), Step(!new), PC, Proc>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>\n    )\n  {\n    // At initialization, each thread is at a procedure entry point with an empty stack\n    forall s, actor {:trigger ActorsBeginAtEntryPointsWithEmptyStacksConditions(cr, s, actor)} ::\n      ActorsBeginAtEntryPointsWithEmptyStacksConditions(cr, s, actor)\n      ==> var PCStack(pc, stack) := cr.get_actor_pc_stack(s, actor).v;\n          && cr.is_entry_point(pc)\n          && |stack| == 0\n  }\n\n  predicate GlobalInvariantSatisfiedInitially<State(!new), Actor(!new), Step, PC, Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>\n    )\n  {\n    forall s :: s in cr.spec.init ==> cr.global_inv(s) && cr.state_ok(s)\n  }\n\n  predicate RequiresClausesSatisfiedInitiallyConditions<State(!new), Actor(!new), Step, PC, Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    s:State,\n    actor:Actor\n    )\n  {\n    && s in cr.spec.init\n    && cr.get_actor_pc_stack(s, actor).Some?\n  }\n\n  predicate RequiresClausesSatisfiedInitially<State(!new), Actor(!new), Step, PC, Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>\n    )\n  {\n    forall s, actor {:trigger RequiresClausesSatisfiedInitiallyConditions(cr, s, actor)} ::\n      RequiresClausesSatisfiedInitiallyConditions(cr, s, actor)\n      ==> var pc := cr.get_actor_pc_stack(s, actor).v.pc;\n          var proc := cr.pc_to_proc(pc);\n          cr.requires_clauses(proc, s, actor)\n  }\n\n  /////////////////////////////////////////////////////\n  // Actorless steps\n  /////////////////////////////////////////////////////\n\n  predicate ActorlessStepsDontChangeActorsConditions<State(!new), Actor(!new), Step(!new), PC, Proc>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    s:State,\n    s':State,\n    step:Step,\n    actor:Actor\n    )\n  {\n    && cr.established_inv(s)\n    && ActionTuple(s, s', step) in cr.spec.next\n    && cr.step_to_actor(step).None?\n  }\n\n  predicate ActorlessStepsDontChangeActors<State(!new), Actor(!new), Step(!new), PC, Proc>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>\n    )\n  {\n    forall s, s', step, actor {:trigger ActorlessStepsDontChangeActorsConditions(cr, s, s', step, actor)} ::\n      ActorlessStepsDontChangeActorsConditions(cr, s, s', step, actor)\n      ==> cr.get_actor_pc_stack(s', actor) == cr.get_actor_pc_stack(s, actor)\n  }\n\n  predicate ActorlessStepsMaintainYieldPredicateAndGlobalInvariantConditions<State(!new), Actor(!new), Step(!new), PC, Proc>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    s:State,\n    s':State,\n    step:Step,\n    actor:Actor\n    )\n  {\n    && cr.established_inv(s)\n    && cr.global_inv(s)\n    && cr.established_inv(s')\n    && ActionTuple(s, s', step) in cr.spec.next\n    && cr.step_to_actor(step).None?\n    && cr.get_actor_pc_stack(s, actor).Some?\n  }\n\n  predicate ActorlessStepsMaintainYieldPredicateAndGlobalInvariant<State(!new), Actor(!new), Step(!new), PC, Proc>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>\n    )\n  {\n    forall s, s', step, actor {:trigger ActorlessStepsMaintainYieldPredicateAndGlobalInvariantConditions(cr, s, s', step, actor)} ::\n      ActorlessStepsMaintainYieldPredicateAndGlobalInvariantConditions(cr, s, s', step, actor)\n      ==> cr.yield_pred(s, s', actor) && cr.global_inv(s') && cr.state_ok(s')\n  }\n\n  /////////////////////////////////////////////////////\n  // Step effects\n  /////////////////////////////////////////////////////\n\n  predicate CorrectCHLStepEffectNormal<State(!new), Actor, Step(!new), PC, Proc>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    s:State,\n    s':State,\n    step:Step\n    )\n  {\n    && cr.state_ok(s)\n    && cr.state_ok(s')\n    && cr.step_to_actor(step).Some?\n    && var actor := cr.step_to_actor(step).v;\n    && cr.get_actor_pc_stack(s, actor).Some?\n    && cr.get_actor_pc_stack(s', actor).Some?\n    && var PCStack(pc, stack) := cr.get_actor_pc_stack(s, actor).v;\n      var PCStack(pc', stack') := cr.get_actor_pc_stack(s', actor).v;\n    && !cr.is_return_site(pc)\n    && cr.pc_to_proc(pc') == cr.pc_to_proc(pc) == cr.step_to_proc(step)\n    && stack' == stack\n  }\n\n  predicate CorrectCHLStepEffectCall<State(!new), Actor, Step(!new), PC, Proc>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    s:State,\n    s':State,\n    step:Step,\n    callee:Proc\n    )\n  {\n    && cr.state_ok(s)\n    && cr.state_ok(s')\n    && cr.step_to_actor(step).Some?\n    && var actor := cr.step_to_actor(step).v;\n    && cr.get_actor_pc_stack(s, actor).Some?\n    && cr.get_actor_pc_stack(s', actor).Some?\n    && var PCStack(pc, stack) := cr.get_actor_pc_stack(s, actor).v;\n      var PCStack(pc', stack') := cr.get_actor_pc_stack(s', actor).v;\n    && !cr.is_return_site(pc)\n    && cr.is_entry_point(pc')\n    && cr.pc_to_proc(pc') == callee\n    && |stack'| > 0\n    && stack'[0] == cr.pc_to_proc(pc) == cr.step_to_proc(step)\n    && stack'[1..] == stack\n  }\n\n  predicate CorrectCHLStepEffectReturn<State(!new), Actor, Step(!new), PC, Proc>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    s:State,\n    s':State,\n    step:Step\n    )\n  {\n    && cr.state_ok(s)\n    && cr.state_ok(s')\n    && cr.step_to_actor(step).Some?\n    && var actor := cr.step_to_actor(step).v;\n    && cr.get_actor_pc_stack(s, actor).Some?\n    && cr.get_actor_pc_stack(s', actor).Some?\n    && var PCStack(pc, stack) := cr.get_actor_pc_stack(s, actor).v;\n      var PCStack(pc', stack') := cr.get_actor_pc_stack(s', actor).v;\n    && cr.is_return_site(pc)\n    && |stack| > 0\n    && cr.pc_to_proc(pc') == stack[0] == cr.step_to_proc(step)\n    && stack' == stack[1..]\n  }\n\n  predicate CorrectCHLStepEffectExit<State(!new), Actor, Step(!new), PC, Proc>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    s:State,\n    s':State,\n    step:Step\n    )\n  {\n    && cr.state_ok(s)\n    && cr.state_ok(s')\n    && cr.step_to_actor(step).Some?\n    && var actor := cr.step_to_actor(step).v;\n    && cr.get_actor_pc_stack(s, actor).Some?\n    && cr.get_actor_pc_stack(s', actor).None?\n    && var PCStack(pc, stack) := cr.get_actor_pc_stack(s, actor).v;\n    && cr.is_return_site(pc)\n    && cr.pc_to_proc(pc) == cr.step_to_proc(step)\n    && |stack| == 0\n  }\n\n  predicate CorrectCHLStepEffectReturnThenCall<State(!new), Actor, Step(!new), PC, Proc>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    s:State,\n    s':State,\n    step:Step,\n    callee:Proc\n    )\n  {\n    // Step that returns to a caller, then does another call\n    && cr.state_ok(s)\n    && cr.state_ok(s')\n    && cr.step_to_actor(step).Some?\n    && var actor := cr.step_to_actor(step).v;\n    && cr.get_actor_pc_stack(s, actor).Some?\n    && cr.get_actor_pc_stack(s', actor).Some?\n    && var PCStack(pc, stack) := cr.get_actor_pc_stack(s, actor).v;\n      var PCStack(pc', stack') := cr.get_actor_pc_stack(s', actor).v;\n    && cr.is_return_site(pc)\n    && |stack| > 0\n    && stack[0] == cr.step_to_proc(step)\n    && cr.pc_to_proc(pc') == callee\n    && cr.is_entry_point(pc')\n    && stack' == stack\n  }\n\n  predicate CorrectCHLStepEffectActorless<State(!new), Actor, Step(!new), PC, Proc>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    s:State,\n    s':State,\n    step:Step\n    )\n  {\n    && cr.state_ok(s)\n    && cr.state_ok(s')\n    && cr.step_to_actor(step).None?\n  }\n\n  predicate CorrectCHLStepEffectStop<State(!new), Actor, Step(!new), PC, Proc>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    s:State,\n    s':State,\n    step:Step\n    )\n  {\n    && cr.state_ok(s)\n    && !cr.state_ok(s')\n    && (cr.step_to_actor(step).Some? ==> cr.get_actor_pc_stack(s, cr.step_to_actor(step).v).Some?)\n  }\n\n  predicate CorrectCHLStepEffect<State(!new), Actor, Step(!new), PC, Proc>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    s:State,\n    s':State,\n    step:Step\n    )\n  {\n    match cr.step_to_effect(step)\n      case CHLStepEffectNormal => CorrectCHLStepEffectNormal(cr, s, s', step)\n      case CHLStepEffectCall(callee) => CorrectCHLStepEffectCall(cr, s, s', step, callee)\n      case CHLStepEffectReturn => CorrectCHLStepEffectReturn(cr, s, s', step)\n      case CHLStepEffectExit => CorrectCHLStepEffectExit(cr, s, s', step)\n      case CHLStepEffectReturnThenCall(callee) => CorrectCHLStepEffectReturnThenCall(cr, s, s', step, callee)\n      case CHLStepEffectActorless => CorrectCHLStepEffectActorless(cr, s, s', step)\n      case CHLStepEffectStop => CorrectCHLStepEffectStop(cr, s, s', step)\n  }\n\n  predicate CHLStepEffectsCorrect<State(!new), Actor, Step(!new), PC, Proc>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>\n    )\n  {\n    forall s, s', step :: ActionTuple(s, s', step) in cr.spec.next ==> CorrectCHLStepEffect(cr, s, s', step)\n  }\n\n  /////////////////////////////////////////////////////\n  // Other control flow\n  /////////////////////////////////////////////////////\n\n  predicate ForkedActorsStartAtEntryPointsWithEmptyStacksConditions<State(!new), Actor(!new), Step(!new), PC, Proc>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    s:State,\n    s':State,\n    step:Step,\n    forked_actor:Actor\n    )\n  {\n    && ActionTuple(s, s', step) in cr.spec.next\n    && cr.get_actor_pc_stack(s, forked_actor).None?\n    && cr.get_actor_pc_stack(s', forked_actor).Some?\n  }\n\n  predicate ForkedActorsStartAtEntryPointsWithEmptyStacks<State(!new), Actor(!new), Step(!new), PC, Proc>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>\n    )\n  {\n    // When a thread starts (i.e., is forked), the forking step isn't actorless or an exit and the forked thread\n    // is at a procedure entry point with an empty stack\n    forall s, s', step, forked_actor {:trigger ForkedActorsStartAtEntryPointsWithEmptyStacksConditions(cr, s, s', step, forked_actor)} ::\n      ForkedActorsStartAtEntryPointsWithEmptyStacksConditions(cr, s, s', step, forked_actor)\n      ==> && cr.step_to_actor(step).Some?\n          && !cr.step_to_effect(step).CHLStepEffectExit?\n          && var PCStack(pc', stack') := cr.get_actor_pc_stack(s', forked_actor).v;\n          && cr.is_entry_point(pc')\n          && |stack'| == 0\n  }\n\n  predicate StepsDontChangeOtherActorsExceptViaForkConditions<State(!new), Actor(!new), Step(!new), PC, Proc>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    s:State,\n    s':State,\n    step:Step,\n    other_actor:Actor\n    )\n  {\n    && ActionTuple(s, s', step) in cr.spec.next\n    && cr.step_to_actor(step) != Some(other_actor)\n    && cr.get_actor_pc_stack(s, other_actor).Some?\n  }\n\n  predicate StepsDontChangeOtherActorsExceptViaFork<State(!new), Actor(!new), Step(!new), PC, Proc>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>\n    )\n  {\n    // One actor taking a step leaves each other actor's PC and stack unchanged\n    // (unless that other actor didn't have a PC before, i.e., this actor was forking that actor)\n    forall s, s', step, other_actor {:trigger StepsDontChangeOtherActorsExceptViaForkConditions(cr, s, s', step, other_actor)} ::\n      StepsDontChangeOtherActorsExceptViaForkConditions(cr, s, s', step, other_actor)\n      ==> cr.get_actor_pc_stack(s', other_actor) == cr.get_actor_pc_stack(s, other_actor)\n  }\n\n  /////////////////////////////////////////////////////\n  // Requirements for straightline behaviors\n  /////////////////////////////////////////////////////\n\n  predicate StraightlineBehaviorsSatisfyGlobalInvariantConditions<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    sb:AnnotatedBehavior<StraightlineState<State, PC>, StraightlineStep<Step, PC, Proc>>,\n    step:Step,\n    s':State\n    )\n  {\n    && cr.step_to_actor(step).Some?\n    && var actor := cr.step_to_actor(step).v;\n      var proc := cr.step_to_proc(step);\n      var effect := cr.step_to_effect(step);\n    && AnnotatedBehaviorSatisfiesSpec(sb, GetStraightlineSpec(cr, actor, proc))\n    && var ss := last(sb.states);\n      var s := ss.state;\n      var phase := ss.aux.phase;\n    && cr.local_inv(s, actor)\n    && ActionTuple(s, s', step) in cr.spec.next\n    && !effect.CHLStepEffectStop?\n    && (if effect.CHLStepEffectReturn? || effect.CHLStepEffectReturnThenCall? then\n         phase.StraightlinePhaseEnsured?\n       else\n         phase.StraightlinePhaseYielded?)\n  }\n\n  predicate StraightlineBehaviorsSatisfyGlobalInvariant<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>\n    )\n  {\n    forall sb, step, s' {:trigger StraightlineBehaviorsSatisfyGlobalInvariantConditions(cr, sb, step, s')} ::\n      StraightlineBehaviorsSatisfyGlobalInvariantConditions(cr, sb, step, s')\n      ==> cr.global_inv(s')\n  }\n\n  predicate StraightlineBehaviorsSatisfyLocalInvariantConditions<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    sb:AnnotatedBehavior<StraightlineState<State, PC>, StraightlineStep<Step, PC, Proc>>,\n    step:Step,\n    s':State\n    )\n  {\n    && cr.step_to_actor(step).Some?\n    && |sb.states| > 0\n    && var ss := last(sb.states);\n      var s := ss.state;\n      var phase := ss.aux.phase;\n      var actor := cr.step_to_actor(step).v;\n    && cr.get_actor_pc_stack(s, actor).Some?\n    && var pc := cr.get_actor_pc_stack(s, actor).v.pc;\n      var proc := cr.pc_to_proc(pc);\n    && AnnotatedBehaviorSatisfiesSpec(sb, GetStraightlineSpec(cr, actor, proc))\n    && ActionTuple(s, s', step) in cr.spec.next\n    && phase.StraightlinePhaseYielded?\n  }\n\n  predicate StraightlineBehaviorsSatisfyLocalInvariant<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>\n    )\n  {\n    forall sb, step, s' {:trigger StraightlineBehaviorsSatisfyLocalInvariantConditions(cr, sb, step, s')} ::\n      StraightlineBehaviorsSatisfyLocalInvariantConditions(cr, sb, step, s')\n      ==> cr.local_inv(last(sb.states).state, cr.step_to_actor(step).v)\n  }\n\n  predicate StraightlineBehaviorsSatisfyPreconditionsForCallsConditions<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    sb:AnnotatedBehavior<StraightlineState<State, PC>, StraightlineStep<Step, PC, Proc>>,\n    step:Step,\n    s':State\n    )\n  {\n    && cr.step_to_actor(step).Some?\n    && var actor := cr.step_to_actor(step).v;\n      var proc := cr.step_to_proc(step);\n      var effect := cr.step_to_effect(step);\n    && AnnotatedBehaviorSatisfiesSpec(sb, GetStraightlineSpec(cr, actor, proc))\n    && var ss := last(sb.states);\n      var s := ss.state;\n      var phase := ss.aux.phase;\n    && cr.local_inv(s, actor)\n    && ActionTuple(s, s', step) in cr.spec.next\n    && (|| (effect.CHLStepEffectCall? && phase.StraightlinePhaseYielded?)\n       || (effect.CHLStepEffectReturnThenCall? && phase.StraightlinePhaseEnsured?))\n    && cr.get_actor_pc_stack(s', actor).Some?\n  }\n\n  predicate StraightlineBehaviorsSatisfyPreconditionsForCalls<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>\n    )\n  {\n    forall sb, step, s' {:trigger StraightlineBehaviorsSatisfyPreconditionsForCallsConditions(cr, sb, step, s')} ::\n      StraightlineBehaviorsSatisfyPreconditionsForCallsConditions(cr, sb, step, s')\n      ==> var actor := cr.step_to_actor(step).v;\n          var callee := cr.step_to_effect(step).callee;\n          cr.requires_clauses(callee, s', actor)\n  }\n\n  predicate StraightlineBehaviorsSatisfyPreconditionsForForksConditions<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    sb:AnnotatedBehavior<StraightlineState<State, PC>, StraightlineStep<Step, PC, Proc>>,\n    step:Step,\n    s':State,\n    forked_actor:Actor\n    )\n  {\n    && cr.step_to_actor(step).Some?\n    && var actor := cr.step_to_actor(step).v;\n      var proc := cr.step_to_proc(step);\n      var effect := cr.step_to_effect(step);\n    && AnnotatedBehaviorSatisfiesSpec(sb, GetStraightlineSpec(cr, actor, proc))\n    && var ss := last(sb.states);\n      var s := ss.state;\n      var phase := ss.aux.phase;\n    && cr.local_inv(s, actor)\n    && ActionTuple(s, s', step) in cr.spec.next\n    && !effect.CHLStepEffectStop?\n    && (if effect.CHLStepEffectReturn? || effect.CHLStepEffectReturnThenCall? then\n         phase.StraightlinePhaseEnsured?\n       else \n         phase.StraightlinePhaseYielded?)\n    && actor != forked_actor\n    && cr.get_actor_pc_stack(s, forked_actor).None?\n    && cr.get_actor_pc_stack(s', forked_actor).Some?\n  }\n\n  predicate StraightlineBehaviorsSatisfyPreconditionsForForks<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>\n    )\n  {\n    forall sb, step, s', forked_actor {:trigger StraightlineBehaviorsSatisfyPreconditionsForForksConditions(cr, sb, step, s', forked_actor)} ::\n      StraightlineBehaviorsSatisfyPreconditionsForForksConditions(cr, sb, step, s', forked_actor)\n      ==> var forked_pc := cr.get_actor_pc_stack(s', forked_actor).v.pc;\n          var forked_proc := cr.pc_to_proc(forked_pc);\n          cr.requires_clauses(forked_proc, s', forked_actor)\n  }\n\n  predicate StraightlineBehaviorsSatisfyPostconditionsConditions<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    sb:AnnotatedBehavior<StraightlineState<State, PC>, StraightlineStep<Step, PC, Proc>>,\n    actor:Actor,\n    proc:Proc\n    )\n  {\n    && AnnotatedBehaviorSatisfiesSpec(sb, GetStraightlineSpec(cr, actor, proc))\n    && var ss := last(sb.states);\n      var s := ss.state;\n      var phase := ss.aux.phase;\n    && cr.get_actor_pc_stack(s, actor).Some?\n    && var pc := cr.get_actor_pc_stack(s, actor).v.pc;\n    && cr.is_return_site(pc)\n    && phase.StraightlinePhaseYielded?\n  }\n\n  predicate StraightlineBehaviorsSatisfyPostconditions<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>\n    )\n  {\n    forall sb, actor, proc {:trigger StraightlineBehaviorsSatisfyPostconditionsConditions(cr, sb, actor, proc)} ::\n      StraightlineBehaviorsSatisfyPostconditionsConditions(cr, sb, actor, proc)\n      ==> cr.ensures_clauses(proc, sb.states[0].state, last(sb.states).state, actor)\n  }\n\n  predicate StraightlineBehaviorsSatisfyLoopModifiesClausesOnEntryConditions<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    sb:AnnotatedBehavior<StraightlineState<State, PC>, StraightlineStep<Step, PC, Proc>>,\n    actor:Actor,\n    proc:Proc\n    )\n  {\n    && AnnotatedBehaviorSatisfiesSpec(sb, GetStraightlineSpec(cr, actor, proc))\n    && var ss := last(sb.states);\n      var StraightlineState(s, aux) := ss;\n      var phase := aux.phase;\n    && cr.get_actor_pc_stack(s, actor).Some?\n    && var pc := cr.get_actor_pc_stack(s, actor).v.pc;\n    && cr.is_loop_head(pc)\n    && pc !in aux.visited_loops\n    && phase.StraightlinePhaseYielded?\n  }\n\n  predicate StraightlineBehaviorsSatisfyLoopModifiesClausesOnEntry<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>\n    )\n  {\n    forall sb, actor, proc {:trigger StraightlineBehaviorsSatisfyLoopModifiesClausesOnEntryConditions(cr, sb, actor, proc)} ::\n      StraightlineBehaviorsSatisfyLoopModifiesClausesOnEntryConditions(cr, sb, actor, proc)\n      ==> var s := last(sb.states).state;\n          var pc := cr.get_actor_pc_stack(s, actor).v.pc;\n          cr.loop_modifies_clauses(pc, s, s, actor)\n  }\n\n  predicate StraightlineBehaviorsSatisfyLoopModifiesClausesOnJumpBackConditions<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    sb:AnnotatedBehavior<StraightlineState<State, PC>, StraightlineStep<Step, PC, Proc>>,\n    actor:Actor,\n    proc:Proc\n    )\n  {\n    && AnnotatedBehaviorSatisfiesSpec(sb, GetStraightlineSpec(cr, actor, proc))\n    && var ss := last(sb.states);\n      var s := ss.state;\n      var phase := ss.aux.phase;\n    && cr.get_actor_pc_stack(s, actor).Some?\n    && var pc := cr.get_actor_pc_stack(s, actor).v.pc;\n    && cr.is_loop_head(pc)\n    && pc in ss.aux.visited_loops\n    && phase.StraightlinePhaseYielded?\n  }\n\n  predicate StraightlineBehaviorsSatisfyLoopModifiesClausesOnJumpBack<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>\n    )\n  {\n    forall sb, actor, proc {:trigger StraightlineBehaviorsSatisfyLoopModifiesClausesOnJumpBackConditions(cr, sb, actor, proc)} ::\n      StraightlineBehaviorsSatisfyLoopModifiesClausesOnJumpBackConditions(cr, sb, actor, proc)\n      ==> var StraightlineState(s, aux) := last(sb.states);\n          var pc := cr.get_actor_pc_stack(s, actor).v.pc;\n          cr.loop_modifies_clauses(pc, aux.visited_loops[pc], s, actor)\n  }\n\n  predicate StraightlineBehaviorsSatisfyYieldPredicateConditions<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>,\n    sb:AnnotatedBehavior<StraightlineState<State, PC>, StraightlineStep<Step, PC, Proc>>,\n    step:Step,\n    s':State,\n    other_actor:Actor\n    )\n  {\n    && cr.step_to_actor(step).Some?\n    && var actor := cr.step_to_actor(step).v;\n      var proc := cr.step_to_proc(step);\n      var effect := cr.step_to_effect(step);\n    && AnnotatedBehaviorSatisfiesSpec(sb, GetStraightlineSpec(cr, actor, proc))\n    && var ss := last(sb.states);\n      var s := ss.state;\n      var phase := ss.aux.phase;\n    && cr.local_inv(s, actor)\n    && ActionTuple(s, s', step) in cr.spec.next\n    && !effect.CHLStepEffectStop?\n    && (if effect.CHLStepEffectReturn? || effect.CHLStepEffectReturnThenCall? then\n         phase.StraightlinePhaseEnsured?\n       else \n         phase.StraightlinePhaseYielded?)\n    && actor != other_actor\n    && cr.get_actor_pc_stack(s, other_actor).Some?\n  }\n\n  predicate StraightlineBehaviorsSatisfyYieldPredicate<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>\n    )\n  {\n    forall sb, step, s', other_actor {:trigger StraightlineBehaviorsSatisfyYieldPredicateConditions(cr, sb, step, s', other_actor)} ::\n      StraightlineBehaviorsSatisfyYieldPredicateConditions(cr, sb, step, s', other_actor)\n      ==> cr.yield_pred(last(sb.states).state, s', other_actor)\n  }\n\n  /////////////////////////////////////////////////////\n  // Request validity\n  /////////////////////////////////////////////////////\n\n  predicate IsValidConcurrentHoareLogicRequest<State(!new), Actor(!new), Step(!new), PC(!new), Proc(!new)>(\n    cr:ConcurrentHoareLogicRequest<State, Actor, Step, PC, Proc>\n    )\n  {\n    // Simple parameter validity\n    && IsInvariantPredicateOfSpec(cr.established_inv, cr.spec)\n    && LoopHeadsArentReturnSites(cr.is_loop_head, cr.is_return_site)\n    && YieldPredicateReflexive(cr)\n    && YieldPredicateTransitive(cr)\n\n    // Initialization\n    && ActorsBeginAtEntryPointsWithEmptyStacks(cr)\n    && GlobalInvariantSatisfiedInitially(cr)\n    && RequiresClausesSatisfiedInitially(cr)\n\n    // Actorless steps\n    && ActorlessStepsDontChangeActors(cr)\n    && ActorlessStepsMaintainYieldPredicateAndGlobalInvariant(cr)\n\n    // Control flow\n    && CHLStepEffectsCorrect(cr)\n    && ForkedActorsStartAtEntryPointsWithEmptyStacks(cr)\n    && StepsDontChangeOtherActorsExceptViaFork(cr)\n\n    // Straightline behaviors\n    && StraightlineBehaviorsSatisfyGlobalInvariant(cr)\n    && StraightlineBehaviorsSatisfyLocalInvariant(cr)\n    && StraightlineBehaviorsSatisfyPreconditionsForCalls(cr)\n    && StraightlineBehaviorsSatisfyPreconditionsForForks(cr)\n    && StraightlineBehaviorsSatisfyPostconditions(cr)\n    && StraightlineBehaviorsSatisfyLoopModifiesClausesOnEntry(cr)\n    && StraightlineBehaviorsSatisfyLoopModifiesClausesOnJumpBack(cr)\n    && StraightlineBehaviorsSatisfyYieldPredicate(cr)\n  }\n\n}\n"
  },
  {
    "path": "Armada/strategies/combining/ArmadaCombining.i.dfy",
    "content": "/////////////////////////////////////////////////////////////////////////////////////////////////////\n//\n// This file contains a lemma for performing refinement via combining on an Armada behavior.  Such a\n// combining takes a behavior satisfying a low-level spec, which has a certain atomic step\n// represented as a multistep consisting of two or more mini-steps, and returns a behavior\n// satisfying a higher-level specification that has that atomic step consist of a single mini-step.\n// It does so by lifting multi-step multisteps in the lower-level specification to single-step\n// multisteps in the higher-level specification.\n//\n// To use this lemma, first create a request r of type ArmadaCombiningRequest (defined in\n// ArmadaCombiningSpec.i.dfy).  Then, prove that it's a valid request, i.e., that\n// ValidArmadaCombiningRequest(r).\n//\n/////////////////////////////////////////////////////////////////////////////////////////////////////\n\ninclude \"ArmadaCombiningSpec.i.dfy\"\ninclude \"ArmadaCombiningLemmas.i.dfy\"\n\nmodule ArmadaCombiningModule {\n\n  import opened util_collections_seqs_s\n  import opened util_collections_seqs_i\n  import opened GeneralRefinementModule\n  import opened AnnotatedBehaviorModule\n  import opened ArmadaCombiningSpecModule\n  import opened ArmadaCombiningLemmasModule\n  import opened GenericArmadaLemmasModule\n  import opened ArmadaCommonDefinitions\n  import opened GenericArmadaSpecModule\n\n  lemma lemma_PerformArmadaCombining<LState, LOneStep, LPC, HState, HOneStep, HPC>(\n    acr:ArmadaCombiningRequest<LState, LOneStep, LPC, HState, HOneStep, HPC>,\n    lb:AnnotatedBehavior<LState, Armada_Multistep<LOneStep>>\n    ) returns (\n    hb:AnnotatedBehavior<HState, Armada_Multistep<HOneStep>>\n    )\n    requires ValidArmadaCombiningRequest(acr)\n    requires AnnotatedBehaviorSatisfiesSpec(lb, SpecFunctionsToSpec(acr.l))\n    ensures  BehaviorRefinesBehavior(lb.states, hb.states, acr.relation)\n    ensures  AnnotatedBehaviorSatisfiesSpec(hb, SpecFunctionsToSpec(acr.h))\n  {\n    var hstates := MapSeqToSeq(lb.states, acr.lstate_to_hstate);\n    var htrace := [];\n    var pos := 0;\n\n    while pos < |lb.trace|\n      invariant 0 <= pos <= |lb.trace|\n      invariant |htrace| == pos\n      invariant AnnotatedBehaviorSatisfiesSpec(AnnotatedBehavior(hstates[..pos+1], htrace), SpecFunctionsToSpec(acr.h))\n      invariant acr.inv(lb.states[pos])\n    {\n      lemma_MultistepNextMaintainsInv(acr.l, acr.inv, lb.states[pos], lb.states[pos+1], lb.trace[pos]);\n      lemma_AllThreadsYieldingAtPos(acr.l, lb, pos);\n      lemma_AllThreadsYieldingAtPos(acr.l, lb, pos+1);\n      var hstep := lemma_LiftMultistep(acr, lb.states[pos], lb.states[pos+1], lb.trace[pos], hstates[pos], hstates[pos+1]);\n      htrace := htrace + [hstep];\n      pos := pos + 1;\n    }\n\n    hb := AnnotatedBehavior(hstates, htrace);\n    var lh_map := ConvertMapToSeq(|lb.states|, map i | 0 <= i < |lb.states| :: RefinementRange(i, i));\n    assert BehaviorRefinesBehaviorUsingRefinementMap(lb.states, hstates, acr.relation, lh_map);\n  }\n\n}\n"
  },
  {
    "path": "Armada/strategies/combining/ArmadaCombiningLemmas.i.dfy",
    "content": "/////////////////////////////////////////////////////////////////////////////////////////////////////\n//\n// This file contains lemmas useful in effecting a refinement via combining on an Armada behavior.\n// They support lemma_PerformArmadaCombining (in ArmadaCombining.i.dfy).\n//\n/////////////////////////////////////////////////////////////////////////////////////////////////////\n\ninclude \"ArmadaCombiningSpec.i.dfy\"\ninclude \"../../util/collections/seqs.i.dfy\"\ninclude \"../generic/GenericArmadaLemmas.i.dfy\"\n\nmodule ArmadaCombiningLemmasModule {\n\n  import opened util_collections_seqs_s\n  import opened util_collections_seqs_i\n  import opened util_option_s\n  import opened GeneralRefinementModule\n  import opened GeneralRefinementLemmasModule\n  import opened RefinementConvolutionModule\n  import opened AnnotatedBehaviorModule\n  import opened InvariantsModule\n  import opened ArmadaCombiningSpecModule\n  import opened GenericArmadaSpecModule\n  import opened GenericArmadaLemmasModule\n  import opened ArmadaCommonDefinitions\n\n  lemma lemma_LiftMultistepCaseNoSteps<LState, LOneStep, LPC, HState, HOneStep, HPC>(\n    acr:ArmadaCombiningRequest<LState, LOneStep, LPC, HState, HOneStep, HPC>,\n    ls:LState,\n    ls':LState,\n    lstep:Armada_Multistep<LOneStep>,\n    hs:HState,\n    hs':HState\n    ) returns (\n    hstep:Armada_Multistep<HOneStep>\n    )\n    requires ValidArmadaCombiningRequest(acr)\n    requires acr.inv(ls)\n    requires ActionTuple(ls, ls', lstep) in SpecFunctionsToSpec(acr.l).next\n    requires forall tid :: Armada_ThreadYielding(acr.l, ls, tid)\n    requires forall tid :: Armada_ThreadYielding(acr.l, ls', tid)\n    requires |lstep.steps| == 0\n    requires hs == acr.lstate_to_hstate(ls)\n    requires hs' == acr.lstate_to_hstate(ls')\n    ensures  ActionTuple(hs, hs', hstep) in SpecFunctionsToSpec(acr.h).next\n  {\n    hstep := Armada_Multistep([], lstep.tid, lstep.tau);\n  }\n\n  lemma lemma_LiftMultistepCaseTau<LState, LOneStep, LPC, HState, HOneStep, HPC>(\n    acr:ArmadaCombiningRequest<LState, LOneStep, LPC, HState, HOneStep, HPC>,\n    ls:LState,\n    ls':LState,\n    lstep:Armada_Multistep<LOneStep>,\n    hs:HState,\n    hs':HState\n    ) returns (\n    hstep:Armada_Multistep<HOneStep>\n    )\n    requires ValidArmadaCombiningRequest(acr)\n    requires acr.inv(ls)\n    requires ActionTuple(ls, ls', lstep) in SpecFunctionsToSpec(acr.l).next\n    requires forall tid :: Armada_ThreadYielding(acr.l, ls, tid)\n    requires forall tid :: Armada_ThreadYielding(acr.l, ls', tid)\n    requires lstep.tau\n    requires |lstep.steps| == 1\n    requires hs == acr.lstate_to_hstate(ls)\n    requires hs' == acr.lstate_to_hstate(ls')\n    ensures  ActionTuple(hs, hs', hstep) in SpecFunctionsToSpec(acr.h).next\n  {\n    var lonestep := lstep.steps[0];\n    assert acr.l.step_valid(ls, lonestep);\n    assert acr.l.state_ok(ls);\n    var tid := acr.l.step_to_thread(lonestep);\n    assert Armada_NextMultipleSteps(acr.l, acr.l.step_next(ls, lonestep), ls', lstep.steps[1..]);\n    assert lstep.steps[1..] == [];\n    assert ls' == acr.l.step_next(ls, lonestep);\n    assert Armada_ThreadYielding(acr.l, ls, tid);\n    assert !IsInnerStep(acr, ls, ls', lonestep);\n    var honestep := acr.lonestep_to_honestep(lonestep);\n    assert NonInnerStepsLiftableConditions(acr, ls, lonestep);\n    assert acr.h.step_valid(hs, honestep) && hs' == acr.h.step_next(hs, honestep);\n    hstep := Armada_Multistep([honestep], acr.h.step_to_thread(honestep), acr.h.is_step_tau(honestep));\n    assert Armada_NextMultistep(acr.h, hs, hs', hstep.steps, hstep.tid, hstep.tau);\n  }\n\n  lemma lemma_LiftMultistepCaseCombinable<LState, LOneStep, LPC, HState, HOneStep, HPC>(\n    acr:ArmadaCombiningRequest<LState, LOneStep, LPC, HState, HOneStep, HPC>,\n    ls:LState,\n    ls':LState,\n    lstep:Armada_Multistep<LOneStep>,\n    hs:HState,\n    hs':HState\n    ) returns (\n    hstep:Armada_Multistep<HOneStep>\n    )\n    requires ValidArmadaCombiningRequest(acr)\n    requires acr.inv(ls)\n    requires ActionTuple(ls, ls', lstep) in SpecFunctionsToSpec(acr.l).next\n    requires forall tid :: Armada_ThreadYielding(acr.l, ls, tid)\n    requires forall tid :: Armada_ThreadYielding(acr.l, ls', tid)\n    requires !lstep.tau\n    requires |lstep.steps| > 0\n    requires IsInnerOptionalPC(acr, acr.l.get_thread_pc(acr.l.step_next(ls, lstep.steps[0]), lstep.tid))\n    requires hs == acr.lstate_to_hstate(ls)\n    requires hs' == acr.lstate_to_hstate(ls')\n    ensures  ActionTuple(hs, hs', hstep) in SpecFunctionsToSpec(acr.h).next\n  {\n    assert CanCombineInnerStepsConditions(acr, ls, ls', lstep.steps, lstep.tid);\n    var honestep :| InnerStepsCombined(acr, ls, ls', honestep);\n    assert !acr.h.is_step_tau(honestep) && acr.h.step_valid(hs, honestep) && hs' == acr.h.step_next(hs, honestep);\n    hstep := Armada_Multistep([honestep], acr.h.step_to_thread(honestep), false);\n    assert Armada_ThreadYielding(acr.l, ls, hstep.tid);\n    assert Armada_ThreadYielding(acr.l, ls', hstep.tid);\n    assert Armada_NextMultistep(acr.h, hs, hs', hstep.steps, hstep.tid, hstep.tau);\n    assert ActionTuple(hs, hs', hstep) in SpecFunctionsToSpec(acr.h).next;\n  }\n\n  lemma lemma_LiftMultistepCaseAllNonInnerSteps\n    <LState, LOneStep, LPC, HState, HOneStep, HPC>(\n    acr:ArmadaCombiningRequest<LState, LOneStep, LPC, HState, HOneStep, HPC>,\n    ls:LState,\n    ls':LState,\n    lstep:Armada_Multistep<LOneStep>,\n    hs:HState,\n    hs':HState,\n    lstates:seq<LState>\n    ) returns (\n    hstep:Armada_Multistep<HOneStep>\n    )\n    requires ValidArmadaCombiningRequest(acr)\n    requires acr.inv(ls)\n    requires ActionTuple(ls, ls', lstep) in SpecFunctionsToSpec(acr.l).next\n    requires forall tid :: Armada_ThreadYielding(acr.l, ls, tid)\n    requires forall tid :: Armada_ThreadYielding(acr.l, ls', tid)\n    requires lstates == Armada_GetStateSequence(acr.l, ls, lstep.steps);\n    requires !lstep.tau\n    requires |lstep.steps| > 0\n    requires forall i :: 0 <= i < |lstep.steps| ==> !IsInnerStep(acr, lstates[i], lstates[i+1], lstep.steps[i])\n    requires hs == acr.lstate_to_hstate(ls)\n    requires hs' == acr.lstate_to_hstate(ls')\n    ensures  ActionTuple(hs, hs', hstep) in SpecFunctionsToSpec(acr.h).next\n  {\n    var tid := lstep.tid;\n    var lsteps := lstep.steps;\n    var hsteps := MapSeqToSeq(lsteps, acr.lonestep_to_honestep);\n    hstep := Armada_Multistep(hsteps, tid, lstep.tau);\n    var hstates := Armada_GetStateSequence(acr.h, hs, hsteps);\n\n    var pos := 0;\n    while pos < |hsteps|\n      invariant 0 <= pos <= |hsteps|\n      invariant forall i :: 0 <= i <= pos ==> hstates[i] == acr.lstate_to_hstate(lstates[i])\n      invariant forall i :: 0 <= i < pos ==> acr.h.step_to_thread(hsteps[i]) == acr.l.step_to_thread(lsteps[i])\n      invariant forall i :: 0 <= i < pos ==> acr.h.is_step_tau(hsteps[i]) == acr.l.is_step_tau(lsteps[i])\n      invariant forall i :: 0 <= i < pos ==> acr.h.step_valid(hstates[i], hsteps[i])\n      invariant forall i :: 0 <= i < pos ==> hstates[i+1] == acr.h.step_next(hstates[i], hsteps[i])\n      invariant forall i :: 0 < i < pos ==> var pc := acr.h.get_thread_pc(hstates[i], tid); pc.Some? && acr.h.is_pc_nonyielding(pc.v)\n    {\n      lemma_InvariantHoldsAtIntermediateState(acr.l, acr.inv, ls, ls', lsteps, lstates, pos);\n      lemma_ArmadaNextMultipleStepsImpliesValidStep(acr.l, ls, ls', lsteps, lstates, pos);\n      assert !IsInnerStep(acr, lstates[pos], lstates[pos+1], lsteps[pos]);\n      assert NonInnerStepsLiftableConditions(acr, lstates[pos], lsteps[pos]);\n      lemma_ArmadaGetStateSequenceOnePos(acr.h, hs, hsteps, pos);\n      assert hstates[pos+1] == acr.h.step_next(hstates[pos], hsteps[pos]);\n      assert hstates[pos+1] == acr.lstate_to_hstate(lstates[pos+1]);\n      pos := pos + 1;\n    }\n\n    lemma_ArmadaNextMultipleStepsLastElement(acr.l, ls, ls', lsteps, lstates);\n    lemma_IfAllStepsValidThenArmadaNextMultipleSteps(acr.h, hstates, hsteps);\n    assert Armada_NextMultistep(acr.h, hs, hs', hsteps, tid, lstep.tau);\n  }\n\n  lemma lemma_LiftMultistepCaseNonInnerPC<LState, LOneStep, LPC, HState, HOneStep, HPC>(\n    acr:ArmadaCombiningRequest<LState, LOneStep, LPC, HState, HOneStep, HPC>,\n    ls:LState,\n    ls':LState,\n    lstep:Armada_Multistep<LOneStep>,\n    hs:HState,\n    hs':HState\n    ) returns (\n    hstep:Armada_Multistep<HOneStep>\n    )\n    requires ValidArmadaCombiningRequest(acr)\n    requires acr.inv(ls)\n    requires ActionTuple(ls, ls', lstep) in SpecFunctionsToSpec(acr.l).next\n    requires forall tid :: Armada_ThreadYielding(acr.l, ls, tid)\n    requires forall tid :: Armada_ThreadYielding(acr.l, ls', tid)\n    requires !lstep.tau\n    requires |lstep.steps| > 0\n    requires !IsInnerOptionalPC(acr, acr.l.get_thread_pc(acr.l.step_next(ls, lstep.steps[0]), lstep.tid))\n    requires hs == acr.lstate_to_hstate(ls)\n    requires hs' == acr.lstate_to_hstate(ls')\n    ensures  ActionTuple(hs, hs', hstep) in SpecFunctionsToSpec(acr.h).next\n  {\n    var tid := lstep.tid;\n    var lsteps := lstep.steps;\n    var lstates := Armada_GetStateSequence(acr.l, ls, lstep.steps);\n\n    var pos := 1;\n    while pos < |lsteps|\n      invariant 1 <= pos <= |lsteps|\n      invariant forall i :: 0 <= i <= pos ==> !IsInnerOptionalPC(acr, acr.l.get_thread_pc(lstates[i], tid))\n    {\n      var pc := acr.l.get_thread_pc(lstates[pos], tid);\n      var pc' := acr.l.get_thread_pc(lstates[pos+1], tid);\n      lemma_ArmadaNextMultipleStepsImpliesValidStep(acr.l, ls, ls', lsteps, lstates, pos);\n      assert !acr.l.is_step_tau(lsteps[pos]);\n      assert acr.l.step_valid(lstates[pos], lsteps[pos]);\n      assert lstates[pos+1] == acr.l.step_next(lstates[pos], lsteps[pos]);\n      if pc'.Some? && acr.is_inner_pc(pc'.v) {\n        assert InnerPCPrecededByInnerOrYieldingPCConditions(acr, lstates[pos], lsteps[pos]);\n        assert pc.Some? && (acr.is_inner_pc(pc.v) || !acr.l.is_pc_nonyielding(pc.v));\n        assert !IsInnerOptionalPC(acr, pc);\n        assert !acr.l.is_pc_nonyielding(pc.v);\n        assert false;\n      }\n      assert !IsInnerOptionalPC(acr, pc');\n      pos := pos + 1;\n    }\n\n    assert forall i :: 0 <= i <= |lsteps| ==> !IsInnerOptionalPC(acr, acr.l.get_thread_pc(lstates[i], tid));\n\n    hstep := lemma_LiftMultistepCaseAllNonInnerSteps(acr, ls, ls', lstep, hs, hs', lstates);\n  }\n\n  lemma lemma_LiftMultistep<LState, LOneStep, LPC, HState, HOneStep, HPC>(\n    acr:ArmadaCombiningRequest<LState, LOneStep, LPC, HState, HOneStep, HPC>,\n    ls:LState,\n    ls':LState,\n    lstep:Armada_Multistep<LOneStep>,\n    hs:HState,\n    hs':HState\n    ) returns (\n    hstep:Armada_Multistep<HOneStep>\n    )\n    requires ValidArmadaCombiningRequest(acr)\n    requires acr.inv(ls)\n    requires ActionTuple(ls, ls', lstep) in SpecFunctionsToSpec(acr.l).next\n    requires forall tid :: Armada_ThreadYielding(acr.l, ls, tid)\n    requires forall tid :: Armada_ThreadYielding(acr.l, ls', tid)\n    requires hs == acr.lstate_to_hstate(ls)\n    requires hs' == acr.lstate_to_hstate(ls')\n    ensures  ActionTuple(hs, hs', hstep) in SpecFunctionsToSpec(acr.h).next\n  {\n    var lstates := Armada_GetStateSequence(acr.l, ls, lstep.steps);\n    if |lstep.steps| == 0 {\n      hstep := lemma_LiftMultistepCaseNoSteps(acr, ls, ls', lstep, hs, hs');\n    }\n    else if lstep.tau {\n      hstep := lemma_LiftMultistepCaseTau(acr, ls, ls', lstep, hs, hs');\n    }\n    else if IsInnerOptionalPC(acr, acr.l.get_thread_pc(acr.l.step_next(ls, lstep.steps[0]), lstep.tid)) {\n      hstep := lemma_LiftMultistepCaseCombinable(acr, ls, ls', lstep, hs, hs');\n    }\n    else {\n      hstep := lemma_LiftMultistepCaseNonInnerPC(acr, ls, ls', lstep, hs, hs');\n    }\n  }\n\n}\n"
  },
  {
    "path": "Armada/strategies/combining/ArmadaCombiningSpec.i.dfy",
    "content": "/////////////////////////////////////////////////////////////////////////////////////////////////////\n//\n// This file is the specification for a request to perform combining on an Armada behavior.  Such a\n// combining takes a behavior satisfying a low-level spec, which has a certain atomic step\n// represented as a multistep consisting of two or more mini-steps, and returns a behavior\n// satisfying a higher-level specification that has that atomic step consist of a single mini-step.\n// It does so by lifting multi-step multisteps in the lower-level specification to single-step\n// multisteps in the higher-level specification.\n//\n// To use this specification, first create a request r of type ArmadaCombiningRequest.  Then, prove\n// that it's a valid request, i.e., that ValidArmadaCombiningRequest(r).  Finally, call\n// lemma_PerformArmadaCombining (in ArmadaCombining.i.dfy).\n//\n// The request describes the Armada state machine in an abstract way.  It models the Armada\n// multisteps as instances of ArrStepSequence, which include a sequence of steps of type LOneStep.\n// It models the steps as being either tau steps or non-tau steps.\n//\n/////////////////////////////////////////////////////////////////////////////////////////////////////\n\ninclude \"../../util/option.s.dfy\"\ninclude \"../../util/collections/seqs.s.dfy\"\ninclude \"../refinement/GeneralRefinementLemmas.i.dfy\"\ninclude \"../refinement/RefinementConvolution.i.dfy\"\ninclude \"../refinement/AnnotatedBehavior.i.dfy\"\ninclude \"../invariants.i.dfy\"\ninclude \"../generic/GenericArmadaSpec.i.dfy\"\n\nmodule ArmadaCombiningSpecModule {\n\n  import opened util_option_s\n  import opened util_collections_seqs_s\n  import opened GeneralRefinementModule\n  import opened GeneralRefinementLemmasModule\n  import opened RefinementConvolutionModule\n  import opened AnnotatedBehaviorModule\n  import opened InvariantsModule\n  import opened GenericArmadaSpecModule\n  import opened ArmadaCommonDefinitions\n\n  datatype ArmadaCombiningRequest<!LState, !LOneStep, !LPC, !HState, !HOneStep, !HPC> =\n    ArmadaCombiningRequest(\n      l:Armada_SpecFunctions<LState, LOneStep, LPC>,\n      h:Armada_SpecFunctions<HState, HOneStep, HPC>,\n      relation:RefinementRelation<LState, HState>,\n      inv:LState->bool,\n      lstate_to_hstate:LState->HState,\n      lonestep_to_honestep:LOneStep->HOneStep,\n      lpc_to_hpc:LPC->HPC,\n      is_inner_pc:LPC->bool\n      )\n\n  predicate IsInnerOptionalPC\n    <LState(!new), LOneStep(!new), LPC, HState, HOneStep, HPC>(\n    acr:ArmadaCombiningRequest<LState, LOneStep, LPC, HState, HOneStep, HPC>,\n    pc:Option<LPC>\n    )\n  {\n    pc.Some? && acr.is_inner_pc(pc.v)\n  }\n\n  predicate IsInnerStep\n    <LState(!new), LOneStep(!new), LPC, HState, HOneStep, HPC>(\n    acr:ArmadaCombiningRequest<LState, LOneStep, LPC, HState, HOneStep, HPC>,\n    s:LState,\n    s':LState,\n    step:LOneStep\n    )\n  {\n    var tid := acr.l.step_to_thread(step);\n    || IsInnerOptionalPC(acr, acr.l.get_thread_pc(s, tid))\n    || IsInnerOptionalPC(acr, acr.l.get_thread_pc(s', tid))\n  }\n\n  predicate LInitImpliesHInit<LState(!new), LOneStep, LPC, HState, HOneStep, HPC>(\n    acr:ArmadaCombiningRequest<LState, LOneStep, LPC, HState, HOneStep, HPC>\n    )\n  {\n    forall ls :: acr.l.init(ls) ==> acr.h.init(acr.lstate_to_hstate(ls))\n  }\n\n  predicate LStateToHStateMapsPCsCorrectly\n    <LState(!new), LOneStep, LPC, HState, HOneStep, HPC>(\n    acr:ArmadaCombiningRequest<LState, LOneStep, LPC, HState, HOneStep, HPC>\n    )\n  {\n    forall ls, tid :: var hs := acr.lstate_to_hstate(ls);\n                var lpc := acr.l.get_thread_pc(ls, tid);\n                var hpc := acr.h.get_thread_pc(hs, tid);\n                hpc == if lpc.Some? then Some(acr.lpc_to_hpc(lpc.v)) else None()\n  }\n\n  predicate LHYieldingCorrespondence<LState, LOneStep, LPC(!new), HState, HOneStep, HPC>(\n    acr:ArmadaCombiningRequest<LState, LOneStep, LPC, HState, HOneStep, HPC>\n    )\n  {\n    forall lpc :: var hpc := acr.lpc_to_hpc(lpc);\n            acr.is_inner_pc(lpc) || (acr.h.is_pc_nonyielding(hpc) <==> acr.l.is_pc_nonyielding(lpc))\n  }\n\n  predicate StateConversionPreservesOK<LState(!new), LOneStep, LPC, HState, HOneStep, HPC>(\n    acr:ArmadaCombiningRequest<LState, LOneStep, LPC, HState, HOneStep, HPC>\n    )\n  {\n    forall ls :: acr.h.state_ok(acr.lstate_to_hstate(ls)) == acr.l.state_ok(ls)\n  }\n\n  predicate StateConversionSatisfiesRelation\n    <LState(!new), LOneStep, LPC, HState, HOneStep, HPC>(\n    acr:ArmadaCombiningRequest<LState, LOneStep, LPC, HState, HOneStep, HPC>\n    )\n  {\n    forall ls :: RefinementPair(ls, acr.lstate_to_hstate(ls)) in acr.relation\n  }\n\n  predicate InnerPCsDontYield<LState, LOneStep, LPC(!new), HState, HOneStep, HPC>(\n    acr:ArmadaCombiningRequest<LState, LOneStep, LPC, HState, HOneStep, HPC>\n    )\n  {\n    forall pc :: acr.is_inner_pc(pc) ==> acr.l.is_pc_nonyielding(pc)\n  }\n\n  predicate InnerPCPrecededByInnerOrYieldingPCConditions\n    <LState(!new), LOneStep(!new), LPC, HState, HOneStep, HPC>(\n    acr:ArmadaCombiningRequest<LState, LOneStep, LPC, HState, HOneStep, HPC>,\n    ls:LState,\n    lstep:LOneStep\n    )\n  {\n    var ls' := acr.l.step_next(ls, lstep);\n    var tid := acr.l.step_to_thread(lstep);\n    var pc' := acr.l.get_thread_pc(ls', tid);\n    && !acr.l.is_step_tau(lstep)\n    && acr.l.step_valid(ls, lstep)\n    && pc'.Some?\n    && acr.is_inner_pc(pc'.v)\n  }\n\n  predicate InnerPCPrecededByInnerOrYieldingPC\n    <LState(!new), LOneStep(!new), LPC, HState, HOneStep, HPC>(\n    acr:ArmadaCombiningRequest<LState, LOneStep, LPC, HState, HOneStep, HPC>\n    )\n  {\n    forall ls, lstep {:trigger InnerPCPrecededByInnerOrYieldingPCConditions(acr, ls, lstep)} ::\n      InnerPCPrecededByInnerOrYieldingPCConditions(acr, ls, lstep)\n      ==> var tid := acr.l.step_to_thread(lstep);\n          var pc := acr.l.get_thread_pc(ls, tid);\n          pc.Some? && (acr.is_inner_pc(pc.v) || !acr.l.is_pc_nonyielding(pc.v))\n  }\n\n  predicate InnerPCSucceededByInnerOrYieldingPCConditions\n    <LState(!new), LOneStep(!new), LPC, HState, HOneStep, HPC>(\n    acr:ArmadaCombiningRequest<LState, LOneStep, LPC, HState, HOneStep, HPC>,\n    ls:LState,\n    lstep:LOneStep\n    )\n  {\n    var tid := acr.l.step_to_thread(lstep);\n    var pc := acr.l.get_thread_pc(ls, tid);\n    && !acr.l.is_step_tau(lstep)\n    && acr.l.step_valid(ls, lstep)\n    && pc.Some?\n    && acr.is_inner_pc(pc.v)\n  }\n\n  predicate InnerPCSucceededByInnerOrYieldingPC\n    <LState(!new), LOneStep(!new), LPC, HState, HOneStep, HPC>(\n    acr:ArmadaCombiningRequest<LState, LOneStep, LPC, HState, HOneStep, HPC>\n    )\n  {\n    forall ls, lstep {:trigger InnerPCSucceededByInnerOrYieldingPCConditions(acr, ls, lstep)} ::\n      InnerPCSucceededByInnerOrYieldingPCConditions(acr, ls, lstep)\n      ==> var tid := acr.l.step_to_thread(lstep);\n          var ls' := acr.l.step_next(ls, lstep);\n          var pc' := acr.l.get_thread_pc(ls', tid);\n          pc'.Some? && (acr.is_inner_pc(pc'.v) || !acr.l.is_pc_nonyielding(pc'.v))\n  }\n\n  predicate NonInnerStepsLiftableConditions\n    <LState(!new), LOneStep(!new), LPC, HState, HOneStep, HPC>(\n    acr:ArmadaCombiningRequest<LState, LOneStep, LPC, HState, HOneStep, HPC>,\n    ls:LState,\n    lstep:LOneStep\n    )\n  {\n    var ls' := acr.l.step_next(ls, lstep);\n    && acr.inv(ls)\n    && acr.l.step_valid(ls, lstep)\n    && !IsInnerStep(acr, ls, ls', lstep)\n  }\n\n  predicate NonInnerStepsLiftable<LState(!new), LOneStep(!new), LPC, HState, HOneStep, HPC>(\n    acr:ArmadaCombiningRequest<LState, LOneStep, LPC, HState, HOneStep, HPC>\n    )\n  {\n    forall ls, lstep {:trigger NonInnerStepsLiftableConditions(acr, ls, lstep)} ::\n      NonInnerStepsLiftableConditions(acr, ls, lstep)\n      ==> var ls' := acr.l.step_next(ls, lstep);\n          var hs := acr.lstate_to_hstate(ls);\n          var hstep := acr.lonestep_to_honestep(lstep);\n          var hs' := acr.lstate_to_hstate(ls');\n          && acr.l.step_to_thread(lstep) == acr.h.step_to_thread(hstep)\n          && acr.l.is_step_tau(lstep) == acr.h.is_step_tau(hstep)\n          && acr.h.step_valid(hs, hstep)\n          && hs' == acr.h.step_next(hs, hstep)\n  }\n\n  predicate CanCombineInnerStepsConditions\n    <LState(!new), LOneStep(!new), LPC, HState, HOneStep(!new), HPC>(\n    acr:ArmadaCombiningRequest<LState, LOneStep, LPC, HState, HOneStep, HPC>,\n    ls:LState,\n    ls':LState,\n    lsteps:seq<LOneStep>,\n    tid:Armada_ThreadHandle\n    )\n  {\n     && acr.inv(ls)\n     && Armada_NextMultistep(acr.l, ls, ls', lsteps, tid, false)\n     && |lsteps| > 0\n     && IsInnerOptionalPC(acr, acr.l.get_thread_pc(acr.l.step_next(ls, lsteps[0]), tid))\n  }\n\n  predicate InnerStepsCombined\n    <LState, LOneStep, LPC, HState, HOneStep, HPC>(\n    acr:ArmadaCombiningRequest<LState, LOneStep, LPC, HState, HOneStep, HPC>,\n    ls:LState,\n    ls':LState,\n    hstep:HOneStep\n    )\n  {\n    var hs := acr.lstate_to_hstate(ls);\n    var hs' := acr.lstate_to_hstate(ls');\n    !acr.h.is_step_tau(hstep) && acr.h.step_valid(hs, hstep) && hs' == acr.h.step_next(hs, hstep)\n  }\n\n  predicate CanCombineInnerSteps\n    <LState(!new), LOneStep(!new), LPC, HState, HOneStep(!new), HPC>(\n    acr:ArmadaCombiningRequest<LState, LOneStep, LPC, HState, HOneStep, HPC>\n    )\n  {\n    forall ls, ls', lsteps, tid {:trigger CanCombineInnerStepsConditions(acr, ls, ls', lsteps, tid)} ::\n      CanCombineInnerStepsConditions(acr, ls, ls', lsteps, tid)\n      ==> exists hstep :: InnerStepsCombined(acr, ls, ls', hstep)\n  }\n\n  predicate ValidArmadaCombiningRequest<LState, LOneStep, LPC, HState, HOneStep, HPC>(\n    acr:ArmadaCombiningRequest<LState, LOneStep, LPC, HState, HOneStep, HPC>\n    )\n  {\n    && InitImpliesInv(acr.l, acr.inv)\n    && OneStepPreservesInv(acr.l, acr.inv)\n    && OneStepRequiresOK(acr.l)\n    && InitImpliesYielding(acr.l)\n    && InitImpliesOK(acr.l)\n    && SteppingThreadHasPC(acr.l)\n    && TauLeavesPCUnchanged(acr.l)\n    && ThreadCantAffectOtherThreadPCExceptViaFork(acr.l)\n    && LInitImpliesHInit(acr)\n    && LStateToHStateMapsPCsCorrectly(acr)\n    && LHYieldingCorrespondence(acr)\n    && StateConversionPreservesOK(acr)\n    && StateConversionSatisfiesRelation(acr)\n    && InnerPCsDontYield(acr)\n    && InnerPCPrecededByInnerOrYieldingPC(acr)\n    && InnerPCSucceededByInnerOrYieldingPC(acr)\n    && NonInnerStepsLiftable(acr)\n    && CanCombineInnerSteps(acr)\n  }\n\n}\n\n"
  },
  {
    "path": "Armada/strategies/generic/GenericArmadaAtomic.i.dfy",
    "content": "include \"GenericArmadaSpec.i.dfy\"\ninclude \"GenericArmadaLemmas.i.dfy\"\ninclude \"../invariants.i.dfy\"\ninclude \"../../util/collections/seqs.i.dfy\"\ninclude \"../../strategies/refinement/GeneralRefinementLemmas.i.dfy\"\n\nmodule GenericArmadaAtomicModule {\n\n  import opened util_collections_seqs_s\n  import opened util_collections_seqs_i\n  import opened util_option_s\n  import opened GenericArmadaSpecModule\n  import opened AnnotatedBehaviorModule\n  import opened ArmadaCommonDefinitions\n  import opened GeneralRefinementModule\n  import opened GeneralRefinementLemmasModule\n  import opened InvariantsModule\n  import opened GenericArmadaLemmasModule\n\n  //////////////////////////////////////////////\n  // DEFINITIONS\n  //////////////////////////////////////////////\n\n  datatype AtomicPathType = AtomicPathType_Tau\n                          | AtomicPathType_YY\n                          | AtomicPathType_YS\n                          | AtomicPathType_YR\n                          | AtomicPathType_RY\n                          | AtomicPathType_RS\n                          | AtomicPathType_RR\n\n  datatype AtomicTraceEntry<Path> =\n      AtomicTraceEntry_Stutter()\n    | AtomicTraceEntry_Tau(tau_tid: Armada_ThreadHandle, tau: Path)\n    | AtomicTraceEntry_Normal(normal_tid: Armada_ThreadHandle, path: Path)\n    | AtomicTraceEntry_Recurrent(recurrent_tid: Armada_ThreadHandle, yr: Path, rrs: seq<Path>, rx: Path)\n\n  datatype AtomicSpecFunctions<!State, !Path, !PC> =\n    AtomicSpecFunctions(\n      init: State->bool,\n      path_valid: (State, Path, Armada_ThreadHandle)->bool,\n      path_next: (State, Path, Armada_ThreadHandle)->State,\n      path_type: Path->AtomicPathType,\n      state_ok: State->bool,\n      get_thread_pc: (State, Armada_ThreadHandle)->Option<PC>,\n      is_pc_nonyielding: PC->bool\n      )\n\n  predicate AtomicValidPathSequence<State, Path, PC>(\n    asf: AtomicSpecFunctions<State, Path, PC>,\n    s: State,\n    paths: seq<Path>,\n    tid: Armada_ThreadHandle\n    )\n  {\n    |paths| > 0 ==>\n      && asf.path_type(paths[0]).AtomicPathType_RR?\n      && asf.path_valid(s, paths[0], tid)\n      && AtomicValidPathSequence(asf, asf.path_next(s, paths[0], tid), paths[1..], tid)\n  }\n\n  function AtomicGetStateAfterPaths<State, Path, PC>(\n    asf: AtomicSpecFunctions<State, Path, PC>,\n    s: State,\n    paths: seq<Path>,\n    tid: Armada_ThreadHandle\n    ) : State\n  {\n    if |paths| == 0 then s else AtomicGetStateAfterPaths(asf, asf.path_next(s, paths[0], tid), paths[1..], tid)\n  }\n\n  function AtomicGetStateSequence<State, Path, PC>(\n    asf: AtomicSpecFunctions<State, Path, PC>,\n    s: State,\n    paths: seq<Path>,\n    tid: Armada_ThreadHandle\n    ) : (states: seq<State>)\n    ensures |states| == |paths| + 1\n  {\n    if |paths| == 0 then [s] else [s] + AtomicGetStateSequence(asf, asf.path_next(s, paths[0], tid), paths[1..], tid)\n  }\n\n  function AtomicGetNextStateAlways<State, Path, PC>(\n    asf: AtomicSpecFunctions<State, Path, PC>,\n    s: State,\n    entry: AtomicTraceEntry<Path>\n    ) : State\n  {\n    match entry\n      case AtomicTraceEntry_Stutter() => s\n      case AtomicTraceEntry_Tau(tid, path) => asf.path_next(s, path, tid)\n      case AtomicTraceEntry_Normal(tid, path) => asf.path_next(s, path, tid)\n      case AtomicTraceEntry_Recurrent(tid, yr, rrs, rx) =>\n        var s1 := asf.path_next(s, yr, tid);\n        var s2 := AtomicGetStateAfterPaths(asf, s1, rrs, tid);\n        asf.path_next(s2, rx, tid)\n  }\n  \n  predicate AtomicValidRecursiveStep<State, Path, PC>(\n    asf: AtomicSpecFunctions<State, Path, PC>,\n    s: State,\n    tid: Armada_ThreadHandle,\n    yr: Path,\n    rrs: seq<Path>,\n    rx: Path\n    )\n  {\n    // The first path has the type YR\n    && asf.path_type(yr).AtomicPathType_YR?\n\n    // All the paths are valid\n    && var s1 := asf.path_next(s, yr, tid);\n      var s2 := AtomicGetStateAfterPaths(asf, s1, rrs, tid);\n      var s3 := asf.path_next(s2, rx, tid);\n    && asf.path_valid(s, yr, tid)\n    && AtomicValidPathSequence(asf, s1, rrs, tid)\n    && asf.path_valid(s2, rx, tid)\n\n    // The final state has ok-ness matching the path type\n    && (if asf.state_ok(s3) then asf.path_type(rx).AtomicPathType_RY? else asf.path_type(rx).AtomicPathType_RS?)\n  }\n\n  predicate AtomicValidStep<State, Path, PC>(\n    asf: AtomicSpecFunctions<State, Path, PC>,\n    s: State,\n    entry: AtomicTraceEntry<Path>\n    )\n  {\n    match entry\n      case AtomicTraceEntry_Stutter() =>\n        true\n\n      case AtomicTraceEntry_Tau(tid, path) =>\n        && asf.path_type(path).AtomicPathType_Tau?\n        && asf.path_valid(s, path, tid)\n\n      case AtomicTraceEntry_Normal(tid, path) =>\n        && asf.path_valid(s, path, tid)\n        && (if asf.state_ok(asf.path_next(s, path, tid)) then asf.path_type(path).AtomicPathType_YY? else asf.path_type(path).AtomicPathType_YS?)\n\n      case AtomicTraceEntry_Recurrent(tid, yr, rrs, rx) =>\n        AtomicValidRecursiveStep(asf, s, tid, yr, rrs, rx)\n  }\n\n  predicate AtomicNext<State, Path, PC>(\n    asf: AtomicSpecFunctions<State, Path, PC>,\n    s: State,\n    s': State,\n    entry: AtomicTraceEntry<Path>\n    )\n  {\n    && AtomicValidStep(asf, s, entry)\n    && s' == AtomicGetNextStateAlways(asf, s, entry)\n  }\n\n  function AtomicAnnotatedSpec<State(!new), Path(!new), PC>(asf: AtomicSpecFunctions<State, Path, PC>)\n    : AnnotatedBehaviorSpec<State, AtomicTraceEntry<Path>>\n  {\n    AnnotatedBehaviorSpec(iset s | asf.init(s) :: s,\n                          iset s, s', entry | AtomicNext(asf, s, s', entry) :: ActionTuple(s, s', entry))\n  }\n\n  function AtomicSpec<State(!new), Path(!new), PC>(asf: AtomicSpecFunctions<State, Path, PC>) : Spec<State>\n  {\n    Spec(iset s | asf.init(s) :: s,\n         iset s, s', entry: AtomicTraceEntry<Path> | AtomicNext(asf, s, s', entry) :: StatePair(s, s'))\n  }\n\n  function GenericAtomicLiftTraceEntry<LPath, HPath>(lentry: AtomicTraceEntry<LPath>, pathLift: LPath->HPath) : AtomicTraceEntry<HPath>\n  {\n    match lentry\n      case AtomicTraceEntry_Stutter() => AtomicTraceEntry_Stutter()\n      case AtomicTraceEntry_Tau(tid, path) => AtomicTraceEntry_Tau(tid, pathLift(path))\n      case AtomicTraceEntry_Normal(tid, path) => AtomicTraceEntry_Normal(tid, pathLift(path))\n      case AtomicTraceEntry_Recurrent(tid, yr, rrs, rx) =>\n        AtomicTraceEntry_Recurrent(tid, pathLift(yr), MapSeqToSeq(rrs, pathLift), pathLift(rx))\n  }\n\n  function GenericAtomicLiftPathSeqStateDependent<LState(!new), LPath(!new), LPC, HPath>(\n    asf: AtomicSpecFunctions<LState, LPath, LPC>,\n    ls: LState,\n    paths: seq<LPath>,\n    tid: Armada_ThreadHandle,\n    lift_fn: (LState, LPath)-->HPath\n    ) : seq<HPath>\n    requires AtomicValidPathSequence(asf, ls, paths, tid)\n    requires forall ls, lpath :: asf.path_valid(ls, lpath, tid) ==> lift_fn.requires(ls, lpath)\n    decreases |paths|\n  {\n    if |paths| == 0 then\n      []\n    else\n      var ls_next := asf.path_next(ls, paths[0], tid);\n      [lift_fn(ls, paths[0])] + GenericAtomicLiftPathSeqStateDependent(asf, ls_next, paths[1..], tid, lift_fn)\n  }\n\n  function GenericAtomicLiftTraceEntryStateDependent<LState(!new), LPath(!new), LPC, HPath>(\n    asf: AtomicSpecFunctions<LState, LPath, LPC>,\n    ls: LState,\n    lentry: AtomicTraceEntry<LPath>,\n    lift_fn: (LState, LPath)-->HPath\n    ) : AtomicTraceEntry<HPath>\n    requires AtomicValidStep(asf, ls, lentry)\n    requires forall ls, lpath, tid :: asf.path_valid(ls, lpath, tid) ==> lift_fn.requires(ls, lpath)\n  {\n    match lentry\n      case AtomicTraceEntry_Stutter() => AtomicTraceEntry_Stutter()\n      case AtomicTraceEntry_Tau(tid, path) => AtomicTraceEntry_Tau(tid, lift_fn(ls, path))\n      case AtomicTraceEntry_Normal(tid, path) => AtomicTraceEntry_Normal(tid, lift_fn(ls, path))\n      case AtomicTraceEntry_Recurrent(tid, yr, rrs, rx) =>\n        var ls1 := asf.path_next(ls, yr, tid);\n        var ls2 := AtomicGetStateAfterPaths(asf, ls1, rrs, tid);\n        var rrs' := GenericAtomicLiftPathSeqStateDependent(asf, ls1, rrs, tid, lift_fn);\n        AtomicTraceEntry_Recurrent(tid, lift_fn(ls, yr), rrs', lift_fn(ls2, rx))\n  }\n\n  predicate AtomicInitImpliesInv<State(!new), Path, PC>(\n    asf: AtomicSpecFunctions<State, Path, PC>,\n    inv: State->bool\n    )\n  {\n    forall s :: asf.init(s) ==> inv(s)\n  }\n\n  predicate AtomicInitImpliesYielding<State(!new), Path, PC>(\n    asf: AtomicSpecFunctions<State, Path, PC>\n    )\n  {\n    forall s, tid :: asf.init(s) && asf.get_thread_pc(s, tid).Some? ==> !asf.is_pc_nonyielding(asf.get_thread_pc(s, tid).v)\n  }\n\n  predicate AtomicInitImpliesOK<State(!new), Path, PC>(\n    asf: AtomicSpecFunctions<State, Path, PC>\n    )\n  {\n    forall s :: asf.init(s) ==> asf.state_ok(s)\n  }\n\n  predicate AtomicPathPreservesInv<State(!new), Path(!new), PC>(\n    asf: AtomicSpecFunctions<State, Path, PC>,\n    inv: State->bool\n    )\n  {\n    forall s, path, tid :: inv(s) && asf.path_valid(s, path, tid) ==> inv(asf.path_next(s, path, tid))\n  }\n\n  predicate AtomicPathRequiresOK<State(!new), Path(!new), PC>(\n    asf: AtomicSpecFunctions<State, Path, PC>\n    )\n  {\n    forall s, path, tid :: asf.path_valid(s, path, tid) ==> asf.state_ok(s)\n  }\n\n  predicate AtomicSteppingThreadHasPC<State(!new), Path(!new), PC>(\n    asf: AtomicSpecFunctions<State, Path, PC>\n    )\n  {\n    forall s, path, tid :: asf.path_valid(s, path, tid) ==> asf.get_thread_pc(s, tid).Some?\n  }\n\n  predicate AtomicTauLeavesPCUnchanged<State(!new), Path(!new), PC>(\n    asf: AtomicSpecFunctions<State, Path, PC>\n    )\n  {\n    forall s, path, tid :: asf.path_valid(s, path, tid) && asf.path_type(path).AtomicPathType_Tau? ==>\n      var s' := asf.path_next(s, path, tid);\n      asf.get_thread_pc(s', tid) == asf.get_thread_pc(s, tid)\n  }\n\n  predicate AtomicThreadYielding<State(!new), Path, PC>(\n    asf: AtomicSpecFunctions<State, Path, PC>,\n    s: State,\n    tid: Armada_ThreadHandle\n    )\n  {\n    var pc := asf.get_thread_pc(s, tid);\n    !asf.state_ok(s) || pc.None? || !asf.is_pc_nonyielding(pc.v)\n  }\n\n  predicate AtomicThreadCantAffectOtherThreadPCExceptViaFork<State(!new), Path(!new), PC>(\n    asf: AtomicSpecFunctions<State, Path, PC>\n    )\n  {\n    forall s, path, tid, other_tid :: asf.path_valid(s, path, tid) && tid != other_tid\n       ==> var s' := asf.path_next(s, path, tid);\n           var pc := asf.get_thread_pc(s, other_tid);\n           var pc' := asf.get_thread_pc(s', other_tid);\n           (pc' != pc ==> pc.None? && !asf.is_pc_nonyielding(pc'.v))\n  }\n\n  predicate AtomicPathTypeMatchesPCTypes<State(!new), Path(!new), PC>(\n    asf: AtomicSpecFunctions<State, Path, PC>,\n    s: State,\n    path: Path,\n    tid: Armada_ThreadHandle\n    )\n  {\n    var s' := asf.path_next(s, path, tid);\n    match asf.path_type(path)\n      case AtomicPathType_Tau => true\n      case AtomicPathType_YY => AtomicThreadYielding(asf, s, tid) && asf.state_ok(s') && AtomicThreadYielding(asf, s', tid)\n      case AtomicPathType_YS => AtomicThreadYielding(asf, s, tid) && !asf.state_ok(s')\n      case AtomicPathType_YR => AtomicThreadYielding(asf, s, tid) && !AtomicThreadYielding(asf, s', tid)\n      case AtomicPathType_RY => !AtomicThreadYielding(asf, s, tid) && asf.state_ok(s') && AtomicThreadYielding(asf, s', tid)\n      case AtomicPathType_RS => !AtomicThreadYielding(asf, s, tid) && !asf.state_ok(s')\n      case AtomicPathType_RR => !AtomicThreadYielding(asf, s, tid) && !AtomicThreadYielding(asf, s', tid)\n  }\n\n  predicate AtomicPathTypeAlwaysMatchesPCTypes<State(!new), Path(!new), PC>(\n    asf: AtomicSpecFunctions<State, Path, PC>\n    )\n  {\n    forall s, path, tid :: asf.path_valid(s, path, tid) ==> AtomicPathTypeMatchesPCTypes(asf, s, path, tid)\n  }\n\n  //////////////////////////////////////////////\n  // UTILITY LEMMAS\n  //////////////////////////////////////////////\n\n  lemma lemma_AtomicGetStateSequenceOnePos<State, Path, PC>(\n    asf: AtomicSpecFunctions<State, Path, PC>,\n    s: State,\n    paths: seq<Path>,\n    tid: Armada_ThreadHandle,\n    pos: int\n    )\n    requires 0 <= pos < |paths|\n    ensures  var states := AtomicGetStateSequence(asf, s, paths, tid); states[pos+1] == asf.path_next(states[pos], paths[pos], tid)\n  {\n    if |paths| > 0 && pos > 0 {\n      lemma_AtomicGetStateSequenceOnePos(asf, asf.path_next(s, paths[0], tid), paths[1..], tid, pos-1);\n    }\n  }\n\n  lemma lemma_AtomicValidPathSequenceImpliesValidPath<State, Path, PC>(\n    asf: AtomicSpecFunctions<State, Path, PC>,\n    s: State,\n    s': State,\n    paths: seq<Path>,\n    tid: Armada_ThreadHandle,\n    states: seq<State>,\n    i: int\n    )\n    requires AtomicValidPathSequence(asf, s, paths, tid)\n    requires 0 <= i < |paths|\n    requires states == AtomicGetStateSequence(asf, s, paths, tid)\n    ensures  asf.path_valid(states[i], paths[i], tid)\n    ensures  states[i+1] == asf.path_next(states[i], paths[i], tid)\n  {\n    if i > 0 {\n      var s_mid := asf.path_next(s, paths[0], tid);\n      lemma_AtomicValidPathSequenceImpliesValidPath(asf, s_mid, s', paths[1..], tid, states[1..], i-1);\n    }\n  }\n\n  lemma lemma_AtomicNextLastElement<State, Path, PC>(\n    asf: AtomicSpecFunctions<State, Path, PC>,\n    s: State,\n    s': State,\n    paths: seq<Path>,\n    tid: Armada_ThreadHandle,\n    states: seq<State>\n    )\n    requires s' == AtomicGetStateAfterPaths(asf, s, paths, tid)\n    requires states == AtomicGetStateSequence(asf, s, paths, tid)\n    ensures  last(states) == s'\n  {\n    if |paths| > 0 {\n      var s_mid := asf.path_next(s, paths[0], tid);\n      lemma_AtomicNextLastElement(asf, s_mid, s', paths[1..], tid, states[1..]);\n    }\n  }\n\n  lemma lemma_ExtendAtomicGetStateAfterPaths<State, Path, PC>(\n    asf: AtomicSpecFunctions<State, Path, PC>,\n    s: State,\n    s': State,\n    paths: seq<Path>,\n    tid: Armada_ThreadHandle,\n    path: Path\n    )\n    requires s' == AtomicGetStateAfterPaths(asf, s, paths, tid)\n    ensures  asf.path_next(s', path, tid) == AtomicGetStateAfterPaths(asf, s, paths + [path], tid)\n    decreases |paths|\n  {\n    if |paths| > 0 {\n      var s_next := asf.path_next(s, paths[0], tid);\n      lemma_ExtendAtomicGetStateAfterPaths(asf, s_next, s', paths[1..], tid, path);\n      assert paths + [path] == [paths[0]] + (paths[1..] + [path]);\n    }\n  }\n\n  lemma lemma_ExtendAtomicValidPathSequence<State, Path, PC>(\n    asf: AtomicSpecFunctions<State, Path, PC>,\n    s: State,\n    s': State,\n    paths: seq<Path>,\n    tid: Armada_ThreadHandle,\n    path: Path\n    )\n    requires AtomicValidPathSequence(asf, s, paths, tid)\n    requires s' == AtomicGetStateAfterPaths(asf, s, paths, tid)\n    requires asf.path_valid(s', path, tid)\n    requires asf.path_type(path).AtomicPathType_RR?\n    ensures  AtomicValidPathSequence(asf, s, paths + [path], tid)\n    decreases |paths|\n  {\n    if |paths| > 0 {\n      var s_next := asf.path_next(s, paths[0], tid);\n      lemma_ExtendAtomicValidPathSequence(asf, s_next, s', paths[1..], tid, path);\n      assert paths + [path] == [paths[0]] + (paths[1..] + [path]);\n    }\n  }\n\n  lemma lemma_AtomicBehaviorToAnnotatedBehavior<State(!new), Path(!new), PC(!new)>(\n    asf:AtomicSpecFunctions<State, Path, PC>,\n    b:seq<State>\n    ) returns (\n    ab:AnnotatedBehavior<State, AtomicTraceEntry<Path>>\n    )\n    requires BehaviorSatisfiesSpec(b, AtomicSpec(asf))\n    ensures  AnnotatedBehaviorSatisfiesSpec(ab, AtomicAnnotatedSpec(asf))\n    ensures  ab.states == b\n  {\n    var trace:seq<AtomicTraceEntry<Path>> := [];\n    var pos := 0;\n\n    while pos < |b| - 1\n      invariant 0 <= pos < |b|\n      invariant |trace| == pos\n      invariant AnnotatedBehaviorSatisfiesSpec(AnnotatedBehavior(b[..pos + 1], trace), AtomicAnnotatedSpec(asf))\n    {\n      assert StatePair(b[pos], b[pos + 1]) in AtomicSpec(asf).next;\n      var entry :| AtomicNext(asf, b[pos], b[pos + 1], entry);\n      lemma_ExtendStateNextSeqRight(b[..pos + 1], trace, AtomicAnnotatedSpec(asf).next, b[pos + 1], entry);\n      assert b[..pos + 1] + [b[pos + 1]] == b[..(pos + 1) + 1];\n      trace := trace + [entry];\n      pos := pos + 1;\n    }\n\n    assert b[..pos + 1] == b;\n    ab := AnnotatedBehavior(b, trace);\n  }\n\n  lemma lemma_AtomicAnnotatedBehaviorSatisfiesAtomicSpec<State(!new), Path(!new), PC(!new)>(\n    asf:AtomicSpecFunctions<State, Path, PC>,\n    ab:AnnotatedBehavior<State, AtomicTraceEntry<Path>>\n    )\n    requires AnnotatedBehaviorSatisfiesSpec(ab, AtomicAnnotatedSpec(asf))\n    ensures  BehaviorSatisfiesSpec(ab.states, AtomicSpec(asf))\n  {\n    var b := ab.states;\n    var spec := AtomicSpec(asf);\n    forall i {:trigger StatePair(b[i], b[i + 1]) in spec.next} | 0 <= i < |b| - 1\n      ensures StatePair(b[i], b[i + 1]) in spec.next\n    {\n      assert ActionTuple(ab.states[i], ab.states[i + 1], ab.trace[i]) in AtomicAnnotatedSpec(asf).next;\n    }\n  }\n\n}\n"
  },
  {
    "path": "Armada/strategies/generic/GenericArmadaLemmas.i.dfy",
    "content": "include \"GenericArmadaSpec.i.dfy\"\ninclude \"../refinement/GeneralRefinementLemmas.i.dfy\"\n\nmodule GenericArmadaLemmasModule {\n\n  import opened util_collections_seqs_s\n  import opened AnnotatedBehaviorModule\n  import opened ArmadaCommonDefinitions\n  import opened GeneralRefinementModule\n  import opened GeneralRefinementLemmasModule\n  import opened GenericArmadaSpecModule\n\n  lemma lemma_BehaviorToAnnotatedBehavior<State(!new), OneStep(!new), PC(!new)>(\n    asf:Armada_SpecFunctions<State, OneStep, PC>,\n    b:seq<State>\n    ) returns (\n    ab:AnnotatedBehavior<State, Armada_Multistep<OneStep>>\n    )\n    requires BehaviorSatisfiesSpec(b, Armada_SpecFunctionsToSpec(asf))\n    ensures  AnnotatedBehaviorSatisfiesSpec(ab, SpecFunctionsToAnnotatedSpec(asf))\n    ensures  ab.states == b\n  {\n    var spec := Armada_SpecFunctionsToSpec(asf);\n    var aspec := SpecFunctionsToAnnotatedSpec(asf);\n    var pos := 0;\n    var trace := [];\n    while pos < |b|-1\n      invariant pos == |trace|\n      invariant pos < |b|\n      invariant AnnotatedBehaviorSatisfiesSpec(AnnotatedBehavior(b[..pos+1], trace), aspec)\n    {\n      var s := b[pos];\n      var s' := b[pos+1];\n      assert StatePair(s, s') in spec.next;\n      var steps, tid, tau :| Armada_NextMultistep(asf, s, s', steps, tid, tau);\n      var multistep := Armada_Multistep(steps, tid, tau);\n      assert StatePair(b[pos], b[pos+1]) in spec.next;\n      lemma_ExtendStateNextSeqRight(b[..pos+1], trace, aspec.next, b[pos+1], multistep);\n      assert b[..(pos+1)+1] == b[..pos+1] + [b[pos+1]];\n      trace := trace + [multistep];\n      pos := pos + 1;\n    }\n    return AnnotatedBehavior(b, trace);\n  }\n\n  lemma lemma_IfAnnotatedBehaviorSatisfiesSpecThenBehaviorDoes<State(!new), OneStep(!new), PC(!new)>(\n    asf:Armada_SpecFunctions<State, OneStep, PC>,\n    ab:AnnotatedBehavior<State, Armada_Multistep<OneStep>>\n    )\n    requires AnnotatedBehaviorSatisfiesSpec(ab, SpecFunctionsToAnnotatedSpec(asf))\n    ensures  BehaviorSatisfiesSpec(ab.states, Armada_SpecFunctionsToSpec(asf))\n  {\n    var aspec := SpecFunctionsToAnnotatedSpec(asf);\n    var spec := Armada_SpecFunctionsToSpec(asf);\n    forall pos | 0 <= pos < |ab.states|-1\n      ensures StatePair(ab.states[pos], ab.states[pos+1]) in spec.next\n    {\n      assert ActionTuple(ab.states[pos], ab.states[pos+1], ab.trace[pos]) in aspec.next;\n    }\n  }\n\n  lemma lemma_ExtendArmadaNextMultipleSteps<State(!new), OneStep(!new), PC(!new)>(\n    asf: Armada_SpecFunctions<State, OneStep, PC>,\n    s: State,\n    s': State,\n    s'': State,\n    steps: seq<OneStep>,\n    step: OneStep,\n    tid: Armada_ThreadHandle\n    )\n    requires Armada_NextMultipleSteps(asf, s, s', steps, tid)\n    requires asf.step_valid(s', step, tid)\n    requires s'' == asf.step_next(s', step, tid)\n    ensures  Armada_NextMultipleSteps(asf, s, s'', steps + [step], tid)\n    decreases |steps|\n  {\n    if |steps| > 0 {\n      var s_next := asf.step_next(s, steps[0], tid);\n      lemma_ExtendArmadaNextMultipleSteps(asf, s_next, s', s'', steps[1..], step, tid);\n      var all_steps := steps + [step];\n      assert all_steps[0] == steps[0];\n      assert all_steps[1..] == steps[1..] + [step];\n      assert Armada_NextMultipleSteps(asf, s_next, s'', all_steps[1..], tid);\n    }\n  }\n\n  lemma lemma_ExtendArmadaStepsStartNonyielding<State(!new), OneStep(!new), PC(!new)>(\n    asf: Armada_SpecFunctions<State, OneStep, PC>,\n    s: State,\n    s': State,\n    s'': State,\n    steps: seq<OneStep>,\n    step: OneStep,\n    tid: Armada_ThreadHandle\n    )\n    requires Armada_StepsStartNonyielding(asf, s, s', steps, tid)\n    requires Armada_NextMultipleSteps(asf, s, s', steps, tid)\n    requires !Armada_ThreadYielding(asf, s', tid)\n    requires !asf.is_step_tau(step)\n    requires asf.step_valid(s', step, tid)\n    requires s'' == asf.step_next(s', step, tid)\n    ensures  Armada_StepsStartNonyielding(asf, s, s'', steps + [step], tid)\n    ensures  Armada_NextMultipleSteps(asf, s, s'', steps + [step], tid)\n    decreases |steps|\n  {\n    if |steps| > 0 {\n      var s_next := asf.step_next(s, steps[0], tid);\n      lemma_ExtendArmadaStepsStartNonyielding(asf, s_next, s', s'', steps[1..], step, tid);\n      var all_steps := steps + [step];\n      assert all_steps[0] == steps[0];\n      assert all_steps[1..] == steps[1..] + [step];\n      assert Armada_StepsStartNonyielding(asf, s_next, s'', all_steps[1..], tid);\n      assert Armada_StepsStartNonyielding(asf, s, s'', steps + [step], tid);\n      assert Armada_NextMultipleSteps(asf, s, s'', steps + [step], tid);\n    }\n    else {\n      assert Armada_StepsStartNonyielding(asf, s, s'', steps + [step], tid);\n      assert Armada_NextMultipleSteps(asf, s, s'', steps + [step], tid);\n    }\n  }\n\n  lemma lemma_CombineArmadaNextMultipleSteps<State(!new), OneStep(!new), PC(!new)>(\n    asf: Armada_SpecFunctions<State, OneStep, PC>,\n    s: State,\n    s': State,\n    s'': State,\n    steps1: seq<OneStep>,\n    steps2: seq<OneStep>,\n    tid: Armada_ThreadHandle\n    )\n    requires Armada_NextMultipleSteps(asf, s, s', steps1, tid)\n    requires Armada_NextMultipleSteps(asf, s', s'', steps2, tid)\n    ensures  Armada_NextMultipleSteps(asf, s, s'', steps1 + steps2, tid)\n    decreases |steps2|\n  {\n    if |steps2| == 0 {\n      assert s'' == s';\n      assert steps1 + steps2 == steps1;\n      return;\n    }\n\n    var s_next := asf.step_next(s', steps2[0], tid);\n    lemma_ExtendArmadaNextMultipleSteps(asf, s, s', s_next, steps1, steps2[0], tid);\n    lemma_CombineArmadaNextMultipleSteps(asf, s, s_next, s'', steps1 + [steps2[0]], steps2[1..], tid);\n\n    calc {\n      steps1 + steps2;\n      steps1 + ([steps2[0]] + steps2[1..]);\n      (steps1 + [steps2[0]]) + steps2[1..];\n    }\n  }\n\n  lemma lemma_CombineArmadaStepsStartNonyielding<State(!new), OneStep(!new), PC(!new)>(\n    asf: Armada_SpecFunctions<State, OneStep, PC>,\n    s: State,\n    s': State,\n    s'': State,\n    steps1: seq<OneStep>,\n    steps2: seq<OneStep>,\n    tid: Armada_ThreadHandle\n    )\n    requires Armada_StepsStartNonyielding(asf, s, s', steps1, tid)\n    requires Armada_NextMultipleSteps(asf, s, s', steps1, tid)\n    requires Armada_StepsStartNonyielding(asf, s', s'', steps2, tid)\n    requires Armada_NextMultipleSteps(asf, s', s'', steps2, tid)\n    ensures  Armada_StepsStartNonyielding(asf, s, s'', steps1 + steps2, tid)\n    ensures  Armada_NextMultipleSteps(asf, s, s'', steps1 + steps2, tid)\n    decreases |steps2|\n  {\n    if |steps2| == 0 {\n      assert s'' == s';\n      assert steps1 + steps2 == steps1;\n      return;\n    }\n\n    var s_next := asf.step_next(s', steps2[0], tid);\n    lemma_ExtendArmadaStepsStartNonyielding(asf, s, s', s_next, steps1, steps2[0], tid);\n    lemma_CombineArmadaStepsStartNonyielding(asf, s, s_next, s'', steps1 + [steps2[0]], steps2[1..], tid);\n\n    calc {\n      steps1 + steps2;\n      steps1 + ([steps2[0]] + steps2[1..]);\n      (steps1 + [steps2[0]]) + steps2[1..];\n    }\n  }\n\n}\n"
  },
  {
    "path": "Armada/strategies/generic/GenericArmadaPlus.i.dfy",
    "content": "include \"GenericArmadaSpec.i.dfy\"\ninclude \"GenericArmadaLemmas.i.dfy\"\ninclude \"../refinement/GeneralRefinementLemmas.i.dfy\"\n\nmodule GenericArmadaPlusModule\n{\n  import opened util_collections_seqs_s\n  import opened AnnotatedBehaviorModule\n  import opened ArmadaCommonDefinitions\n  import opened GeneralRefinementModule\n  import opened GeneralRefinementLemmasModule\n  import opened GenericArmadaLemmasModule\n\n  predicate InitsMatch<LState(!new), HState(!new), OneStep(!new), PC>(\n    lasf: Armada_SpecFunctions<LState, OneStep, PC>,\n    hasf: Armada_SpecFunctions<HState, OneStep, PC>,\n    convert: HState->LState\n    )\n  {\n    forall ls :: lasf.init(ls) ==> exists hs :: hasf.init(hs) && ls == convert(hs)\n  }\n\n  predicate NextsMatch<LState(!new), HState(!new), OneStep(!new), PC>(\n    lasf: Armada_SpecFunctions<LState, OneStep, PC>,\n    hasf: Armada_SpecFunctions<HState, OneStep, PC>,\n    convert: HState->LState\n    )\n  {\n    forall ls, hs, step, tid :: lasf.step_valid(ls, step, tid) && ls == convert(hs)\n      ==> hasf.step_valid(hs, step, tid) && lasf.step_next(ls, step, tid) == convert(hasf.step_next(hs, step, tid))\n  }\n\n  predicate TausMatch<LState(!new), HState(!new), OneStep(!new), PC>(\n    lasf: Armada_SpecFunctions<LState, OneStep, PC>,\n    hasf: Armada_SpecFunctions<HState, OneStep, PC>,\n    convert: HState->LState\n    )\n  {\n    forall step :: lasf.is_step_tau(step) <==> hasf.is_step_tau(step)\n  }\n\n  predicate ThreadPCsMatch<LState(!new), HState(!new), OneStep(!new), PC>(\n    lasf: Armada_SpecFunctions<LState, OneStep, PC>,\n    hasf: Armada_SpecFunctions<HState, OneStep, PC>,\n    convert: HState->LState\n    )\n  {\n    forall ls, hs, tid :: ls == convert(hs) ==> lasf.get_thread_pc(ls, tid) == hasf.get_thread_pc(hs, tid)\n  }\n\n  predicate NonyieldingPCsMatch<LState(!new), HState(!new), OneStep(!new), PC(!new)>(\n    lasf: Armada_SpecFunctions<LState, OneStep, PC>,\n    hasf: Armada_SpecFunctions<HState, OneStep, PC>,\n    convert: HState->LState\n    )\n  {\n    forall pc :: lasf.is_pc_nonyielding(pc) <==> hasf.is_pc_nonyielding(pc)\n  }\n\n  predicate StateOKsMatch<LState(!new), HState(!new), OneStep(!new), PC>(\n    lasf: Armada_SpecFunctions<LState, OneStep, PC>,\n    hasf: Armada_SpecFunctions<HState, OneStep, PC>,\n    convert: HState->LState\n    )\n  {\n    forall ls, hs :: ls == convert(hs) ==> lasf.state_ok(ls) == hasf.state_ok(hs)\n  }\n\n  predicate RequirementsForSpecRefinesPlusSpec<LState(!new), HState(!new), OneStep(!new), PC(!new)>(\n    lasf: Armada_SpecFunctions<LState, OneStep, PC>,\n    hasf: Armada_SpecFunctions<HState, OneStep, PC>,\n    convert: HState->LState\n    )\n  {\n    && InitsMatch(lasf, hasf, convert)\n    && NextsMatch(lasf, hasf, convert)\n    && TausMatch(lasf, hasf, convert)\n    && ThreadPCsMatch(lasf, hasf, convert)\n    && NonyieldingPCsMatch(lasf, hasf, convert)\n    && StateOKsMatch(lasf, hasf, convert)\n  }\n\n  lemma lemma_LiftStepsStartNonyielding<LState(!new), HState(!new), OneStep(!new), PC>(\n    lasf: Armada_SpecFunctions<LState, OneStep, PC>,\n    hasf: Armada_SpecFunctions<HState, OneStep, PC>,\n    convert: HState->LState,\n    ls: LState,\n    ls': LState,\n    hs: HState,\n    steps: seq<OneStep>,\n    tid: Armada_ThreadHandle\n    ) returns (\n    hs': HState\n    )\n    requires RequirementsForSpecRefinesPlusSpec(lasf, hasf, convert)\n    requires Armada_NextMultipleSteps(lasf, ls, ls', steps, tid)\n    requires Armada_StepsStartNonyielding(lasf, ls, ls', steps, tid)\n    requires ls == convert(hs)\n    ensures  Armada_NextMultipleSteps(hasf, hs, hs', steps, tid)\n    ensures  Armada_StepsStartNonyielding(hasf, hs, hs', steps, tid)\n    ensures  ls' == convert(hs')\n  {\n    if |steps| == 0 {\n      hs' := hs;\n      return;\n    }\n\n    var step := steps[0];\n    var ls_next := lasf.step_next(ls, step, tid);\n    var hs_next := hasf.step_next(hs, step, tid);\n    hs' := lemma_LiftStepsStartNonyielding(lasf, hasf, convert, ls_next, ls', hs_next, steps[1..], tid);\n  }\n\n  lemma lemma_LiftMultistep<LState(!new), HState(!new), OneStep(!new), PC>(\n    lasf: Armada_SpecFunctions<LState, OneStep, PC>,\n    hasf: Armada_SpecFunctions<HState, OneStep, PC>,\n    convert: HState->LState,\n    ls: LState,\n    ls': LState,\n    hs: HState,\n    steps: seq<OneStep>,\n    tid: Armada_ThreadHandle,\n    tau: bool\n    ) returns (\n    hs': HState\n    )\n    requires RequirementsForSpecRefinesPlusSpec(lasf, hasf, convert)\n    requires Armada_NextMultistep(lasf, ls, ls', steps, tid, tau)\n    requires ls == convert(hs)\n    ensures  Armada_NextMultistep(hasf, hs, hs', steps, tid, tau)\n    ensures  ls' == convert(hs')\n  {\n    if |steps| == 0 {\n      hs' := hs;\n      return;\n    }\n\n    var step := steps[0];\n    var ls_next := lasf.step_next(ls, step, tid);\n    var hs_next := hasf.step_next(hs, step, tid);\n\n    if tau {\n      hs' := hs_next;\n      assert Armada_NextMultipleSteps(lasf, ls_next, ls', steps[1..], tid);\n    }\n    else {\n      hs' := lemma_LiftStepsStartNonyielding(lasf, hasf, convert, ls_next, ls', hs_next, steps[1..], tid);\n    }\n  }\n\n  lemma lemma_LiftBehavior<LState(!new), HState(!new), OneStep(!new), PC>(\n    lasf: Armada_SpecFunctions<LState, OneStep, PC>,\n    hasf: Armada_SpecFunctions<HState, OneStep, PC>,\n    convert: HState->LState,\n    refinement_relation: RefinementRelation<LState, HState>,\n    lb: seq<LState>\n    ) returns (\n    hb: seq<HState>\n    )\n    requires RequirementsForSpecRefinesPlusSpec(lasf, hasf, convert)\n    requires BehaviorSatisfiesSpec(lb, Armada_SpecFunctionsToSpec(lasf))\n    requires refinement_relation == iset ls, hs | ls == convert(hs) :: RefinementPair(ls, hs)\n    ensures  BehaviorRefinesBehavior(lb, hb, refinement_relation)\n    ensures  BehaviorSatisfiesSpec(hb, Armada_SpecFunctionsToSpec(hasf))\n  {\n    assert lasf.init(lb[0]);\n    var hs0 :| hasf.init(hs0) && lb[0] == convert(hs0);\n    hb := [hs0];\n    var pos := 0;\n    var lspec := Armada_SpecFunctionsToSpec(lasf);\n    var hspec := Armada_SpecFunctionsToSpec(hasf);\n\n    assert BehaviorRefinesBehaviorUsingRefinementMap(lb[..pos+1], hb, refinement_relation, [RefinementRange(0, 0)]);\n    assert BehaviorRefinesBehavior(lb[..pos+1], hb, refinement_relation);\n\n    while pos + 1 < |lb|\n      invariant |hb| == pos + 1\n      invariant pos < |lb|\n      invariant BehaviorRefinesBehavior(lb[..pos+1], hb, refinement_relation)\n      invariant BehaviorSatisfiesSpec(hb, hspec)\n    {\n      var ls := lb[pos];\n      var ls' := lb[pos+1];\n      var hs := hb[pos];\n      assert RefinementPair(ls, hs) in refinement_relation;\n      assert StatePair(ls, ls') in lspec.next;\n      var steps, tid, tau :| Armada_NextMultistep(lasf, ls, ls', steps, tid, tau);\n      var hs' := lemma_LiftMultistep(lasf, hasf, convert, ls, ls', hs, steps, tid, tau);\n      assert Armada_NextMultistep(hasf, hs, hs', steps, tid, tau);\n      assert StatePair(hs, hs') in hspec.next;\n      lemma_ExtendBehaviorRefinesBehaviorRightOne_LH(lb[..pos+1], hb, refinement_relation, ls', hs');\n      lemma_ExtendBehaviorSatisfiesSpecRightOne(hb, hspec, hs');\n      assert lb[..(pos+1)+1] == lb[..pos+1] + [ls'];\n      pos := pos + 1;\n      hb := hb + [hs'];\n    }\n\n    assert lb[..pos+1] == lb;\n  }\n\n  lemma lemma_SpecRefinesPlusSpec<LState(!new), HState(!new), OneStep(!new), PC>(\n    lasf: Armada_SpecFunctions<LState, OneStep, PC>,\n    hasf: Armada_SpecFunctions<HState, OneStep, PC>,\n    convert: HState->LState\n    ) returns (\n    refinement_relation: RefinementRelation<LState, HState>\n    )\n    requires RequirementsForSpecRefinesPlusSpec(lasf, hasf, convert)\n    ensures  SpecRefinesSpec(Armada_SpecFunctionsToSpec(lasf), Armada_SpecFunctionsToSpec(hasf), refinement_relation)\n    ensures  refinement_relation == iset ls, hs | ls == convert(hs) :: RefinementPair(ls, hs)\n  {\n    refinement_relation := iset ls, hs | ls == convert(hs) :: RefinementPair(ls, hs);\n    var hspec := Armada_SpecFunctionsToSpec(hasf);\n    forall lb | BehaviorSatisfiesSpec(lb, Armada_SpecFunctionsToSpec(lasf))\n      ensures exists hb :: BehaviorRefinesBehavior(lb, hb, refinement_relation) && BehaviorSatisfiesSpec(hb, hspec)\n    {\n      var hb := lemma_LiftBehavior(lasf, hasf, convert, refinement_relation, lb);\n      assert BehaviorRefinesBehavior(lb, hb, refinement_relation) && BehaviorSatisfiesSpec(hb, hspec);\n    }\n  }\n}\n"
  },
  {
    "path": "Armada/strategies/generic/GenericArmadaSpec.i.dfy",
    "content": "include \"../../util/option.s.dfy\"\ninclude \"../refinement/AnnotatedBehavior.i.dfy\"\ninclude \"../../ArmadaCommonDefinitions.dfy\"\n\nmodule GenericArmadaSpecModule {\n\n  import opened util_option_s\n  import opened AnnotatedBehaviorModule\n  import opened ArmadaCommonDefinitions\n\n  /////////////////////////////////////////////\n  // Constructing an AnnotatedBehaviorSpec\n  /////////////////////////////////////////////\n\n  datatype Armada_Multistep<OneStep> = Armada_Multistep(steps:seq<OneStep>, tid:Armada_ThreadHandle, tau:bool)\n\n  function SpecFunctionsToAnnotatedSpec<State(!new), OneStep(!new), PC>(\n    asf: Armada_SpecFunctions<State, OneStep, PC>\n    ) : AnnotatedBehaviorSpec<State, Armada_Multistep<OneStep>>\n  {\n    AnnotatedBehaviorSpec(\n      iset s | asf.init(s) :: s,\n      iset s, s', entry:Armada_Multistep<OneStep>\n        | Armada_NextMultistep(asf, s, s', entry.steps, entry.tid, entry.tau)\n        :: ActionTuple(s, s', entry)\n    )\n  }\n\n  predicate Armada_Next<State(!new), OneStep(!new), PC>(\n    asf: Armada_SpecFunctions<State, OneStep, PC>,\n    s: State,\n    s': State,\n    multistep: Armada_Multistep<OneStep>\n    )\n  {\n    Armada_NextMultistep(asf, s, s', multistep.steps, multistep.tid, multistep.tau)\n  }\n\n  /////////////////////////////////////////////\n  // Predicates about an Armada spec\n  /////////////////////////////////////////////\n\n  predicate InitImpliesInv<State(!new), OneStep, PC>(\n    asf:Armada_SpecFunctions<State, OneStep, PC>,\n    inv:State->bool\n    )\n  {\n    forall s :: asf.init(s) ==> inv(s)\n  }\n\n  predicate InitImpliesYielding<State(!new), OneStep, PC>(\n    asf:Armada_SpecFunctions<State, OneStep, PC>\n    )\n  {\n    forall s, tid :: asf.init(s) && asf.get_thread_pc(s, tid).Some? ==> !asf.is_pc_nonyielding(asf.get_thread_pc(s, tid).v)\n  }\n\n  predicate InitImpliesOK<State(!new), OneStep, PC>(\n    asf:Armada_SpecFunctions<State, OneStep, PC>\n    )\n  {\n    forall s :: asf.init(s) ==> asf.state_ok(s)\n  }\n\n  predicate OneStepPreservesInv<State(!new), OneStep(!new), PC>(\n    asf:Armada_SpecFunctions<State, OneStep, PC>,\n    inv:State->bool\n    )\n  {\n    forall s, step, tid :: inv(s) && asf.step_valid(s, step, tid) ==> inv(asf.step_next(s, step, tid))\n  }\n\n  predicate OneStepRequiresOK<State(!new), OneStep(!new), PC>(\n    asf:Armada_SpecFunctions<State, OneStep, PC>\n    )\n  {\n    forall s, step, tid :: asf.step_valid(s, step, tid) ==> asf.state_ok(s)\n  }\n\n  predicate SteppingThreadHasPC<State(!new), OneStep(!new), PC>(\n    asf:Armada_SpecFunctions<State, OneStep, PC>\n    )\n  {\n    forall s, step, tid :: asf.step_valid(s, step, tid) ==> asf.get_thread_pc(s, tid).Some?\n  }\n\n  predicate TauLeavesPCUnchanged<State(!new), OneStep(!new), PC>(\n    asf:Armada_SpecFunctions<State, OneStep, PC>\n    )\n  {\n    forall s, step, tid :: asf.step_valid(s, step, tid) && asf.is_step_tau(step) ==>\n      var s' := asf.step_next(s, step, tid);\n      asf.get_thread_pc(s', tid) == asf.get_thread_pc(s, tid)\n  }\n\n  predicate ThreadCantAffectOtherThreadPCExceptViaFork<State(!new), OneStep(!new), PC>(\n    asf:Armada_SpecFunctions<State, OneStep, PC>\n    )\n  {\n    forall s, step, tid, other_tid :: asf.step_valid(s, step, tid) && tid != other_tid\n       ==> var s' := asf.step_next(s, step, tid);\n           var pc := asf.get_thread_pc(s, other_tid);\n           var pc' := asf.get_thread_pc(s', other_tid);\n           (pc' != pc ==> pc.None? && !asf.is_pc_nonyielding(pc'.v))\n  }\n\n  ////////////////////////////////////////////////////////////////////////\n  // Extracting a sequence of states from a sequence of steps\n  ////////////////////////////////////////////////////////////////////////\n\n  function Armada_GetStateSequence<State, OneStep, PC>(\n    asf: Armada_SpecFunctions<State, OneStep, PC>,\n    s: State,\n    steps: seq<OneStep>,\n    tid: Armada_ThreadHandle\n    ) : (states: seq<State>)\n    ensures |states| == |steps| + 1\n    ensures states[0] == s\n    decreases |steps|\n  {\n    if |steps| == 0 then\n      [s]\n    else\n      [s] + Armada_GetStateSequence(asf, asf.step_next(s, steps[0], tid), steps[1..], tid)\n  }\n\n}\n"
  },
  {
    "path": "Armada/strategies/generic/LiftAtomicToAtomic.i.dfy",
    "content": "include \"GenericArmadaAtomic.i.dfy\"\n\nmodule LiftAtomicToAtomicModule\n{\n  import opened util_collections_seqs_s\n  import opened util_collections_seqs_i\n  import opened util_option_s\n  import opened GenericArmadaSpecModule\n  import opened AnnotatedBehaviorModule\n  import opened ArmadaCommonDefinitions\n  import opened GeneralRefinementModule\n  import opened GeneralRefinementLemmasModule\n  import opened InvariantsModule\n  import opened GenericArmadaLemmasModule\n  import opened GenericArmadaAtomicModule\n\n  //////////////////////////////////////////////\n  // LIFTING BETWEEN TWO ATOMIC SPECS\n  //////////////////////////////////////////////\n\n  predicate LiftAtomicPathSuccessful<LState, LPath, LPC, HState, HPath, HPC>(\n    lasf: AtomicSpecFunctions<LState, LPath, LPC>,\n    hasf: AtomicSpecFunctions<HState, HPath, HPC>,\n    inv: LState->bool,\n    relation: (LState, HState)->bool,\n    ls: LState,\n    lpath: LPath,\n    tid: Armada_ThreadHandle,\n    hs: HState,\n    hpath: HPath\n    )\n  {\n    var ls' := lasf.path_next(ls, lpath, tid);\n    var hs' := hasf.path_next(hs, hpath, tid);\n    && inv(ls')\n    && hasf.path_valid(hs, hpath, tid)\n    && relation(ls', hs')\n    && hasf.path_type(hpath) == lasf.path_type(lpath)\n    && lasf.state_ok(ls') == hasf.state_ok(hs')\n  }\n\n  predicate LiftAtomicTraceEntrySuccessful<LState, LPath, LPC, HState, HPath, HPC>(\n    lasf: AtomicSpecFunctions<LState, LPath, LPC>,\n    hasf: AtomicSpecFunctions<HState, HPath, HPC>,\n    inv: LState->bool,\n    relation: (LState, HState)->bool,\n    ls: LState,\n    lentry: AtomicTraceEntry<LPath>,\n    hs: HState,\n    hentry: AtomicTraceEntry<HPath>\n    )\n  {\n    var ls' := AtomicGetNextStateAlways(lasf, ls, lentry);\n    && inv(ls')\n    && AtomicValidStep(hasf, hs, hentry)\n    && relation(ls', AtomicGetNextStateAlways(hasf, hs, hentry))\n  }\n\n  predicate AtomicPathSkippable<LState, LPath, LPC, HState>(\n    lasf: AtomicSpecFunctions<LState, LPath, LPC>,\n    inv: LState->bool,\n    relation: (LState, HState)->bool,\n    ls: LState,\n    lpath: LPath,\n    tid: Armada_ThreadHandle,\n    hs: HState\n    )\n  {\n    var ls' := lasf.path_next(ls, lpath, tid);\n    var ty := lasf.path_type(lpath);\n    && inv(ls')\n    && relation(ls', hs)\n    && lasf.state_ok(ls')\n    && (ty.AtomicPathType_Tau? || ty.AtomicPathType_YY? || ty.AtomicPathType_YS? || ty.AtomicPathType_RR?)\n  }\n\n  predicate ProgressMade(value: (int, int), value': (int, int))\n  {\n    var (x, y) := value;\n    var (x', y') := value';\n    && 0 <= x\n    && 0 <= x'\n    && 0 <= y\n    && 0 <= y'\n    && (x' < x || (x' == x && y' < y))\n  }\n\n  predicate AtomicPathIntroduced<LState, LPath, LPC, HState, HPath, HPC>(\n    lasf: AtomicSpecFunctions<LState, LPath, LPC>,\n    hasf: AtomicSpecFunctions<HState, HPath, HPC>,\n    relation: (LState, HState)->bool,\n    progress_measure: (HState, LPath, Armada_ThreadHandle)->(int, int),\n    ls: LState,\n    lpath: LPath,\n    tid: Armada_ThreadHandle,\n    hs: HState,\n    hpath: HPath\n    )\n  {\n    var lty := lasf.path_type(lpath);\n    var hty := hasf.path_type(hpath);\n    var hs' := hasf.path_next(hs, hpath, tid);\n    && hasf.path_valid(hs, hpath, tid)\n    && relation(ls, hs')\n    && hasf.state_ok(hs')\n    && ProgressMade(progress_measure(hs, lpath, tid), progress_measure(hs', lpath, tid))\n    && match lty\n        case AtomicPathType_Tau => hty.AtomicPathType_Tau?\n        case AtomicPathType_YY => hty.AtomicPathType_YY? || hty.AtomicPathType_Tau?\n        case AtomicPathType_YS => hty.AtomicPathType_YY? || hty.AtomicPathType_Tau?\n        case AtomicPathType_YR => hty.AtomicPathType_YY? || hty.AtomicPathType_Tau?\n        case AtomicPathType_RY => hty.AtomicPathType_RR?\n        case AtomicPathType_RS => hty.AtomicPathType_RR?\n        case AtomicPathType_RR => hty.AtomicPathType_RR?\n  }\n\n  function GetTraceEntryProgressMeasure<LPath, HState>(\n    progress_measure: (HState, LPath, Armada_ThreadHandle)->(int, int),\n    hs: HState,\n    entry: AtomicTraceEntry<LPath>\n    ) : (int, int)\n  {\n    match entry\n      case AtomicTraceEntry_Stutter() => (0, 0)\n      case AtomicTraceEntry_Tau(tid, path) => progress_measure(hs, path, tid)\n      case AtomicTraceEntry_Normal(tid, path) => progress_measure(hs, path, tid)\n      case AtomicTraceEntry_Recurrent(tid, yr, _, _) => progress_measure(hs, yr, tid)\n  }\n\n  predicate IntroduceAtomicTraceEntrySuccessful<LState, LPath, HState, HPath, HPC>(\n    hasf: AtomicSpecFunctions<HState, HPath, HPC>,\n    inv: LState->bool,\n    relation: (LState, HState)->bool,\n    progress_measure: (HState, LPath, Armada_ThreadHandle)->(int, int),\n    ls: LState,\n    lentry: AtomicTraceEntry<LPath>,\n    hs: HState,\n    hentry: AtomicTraceEntry<HPath>\n    )\n  {\n    var hs' := AtomicGetNextStateAlways(hasf, hs, hentry);\n    && AtomicValidStep(hasf, hs, hentry)\n    && relation(ls, hs')\n    && ProgressMade(GetTraceEntryProgressMeasure(progress_measure, hs, lentry),\n                   GetTraceEntryProgressMeasure(progress_measure, hs', lentry))\n  }\n\n  lemma lemma_LiftPathSequenceGivenAtomicPathsLiftable<LState, LPath, LPC, HState, HPath, HPC>(\n    lasf: AtomicSpecFunctions<LState, LPath, LPC>,\n    hasf: AtomicSpecFunctions<HState, HPath, HPC>,\n    inv: LState->bool,\n    relation: (LState, HState)->bool,\n    progress_measure: (HState, LPath, Armada_ThreadHandle)->(int, int),\n    ls: LState,\n    tid: Armada_ThreadHandle,\n    lpaths: seq<LPath>,\n    hs: HState\n    ) returns (\n    hpaths: seq<HPath>\n    )\n    requires forall ls0, lpath0, hs0 ::\n               && inv(ls0)\n               && relation(ls0, hs0)\n               && lasf.path_valid(ls0, lpath0, tid)\n               && !AtomicPathSkippable(lasf, inv, relation, ls0, lpath0, tid, hs0)\n               ==> exists hpath :: AtomicPathIntroduced(lasf, hasf, relation, progress_measure, ls0, lpath0, tid, hs0, hpath)\n                             || LiftAtomicPathSuccessful(lasf, hasf, inv, relation, ls0, lpath0, tid, hs0, hpath)\n    requires inv(ls)\n    requires relation(ls, hs)\n    requires AtomicValidPathSequence(lasf, ls, lpaths, tid)\n    ensures  inv(AtomicGetStateAfterPaths(lasf, ls, lpaths, tid))\n    ensures  AtomicValidPathSequence(hasf, hs, hpaths, tid)\n    ensures  relation(AtomicGetStateAfterPaths(lasf, ls, lpaths, tid), AtomicGetStateAfterPaths(hasf, hs, hpaths, tid))\n    decreases |lpaths|,\n              if |lpaths| > 0 then progress_measure(hs, lpaths[0], tid).0 else 0,\n              if |lpaths| > 0 then progress_measure(hs, lpaths[0], tid).1 else 0\n  {\n    if |lpaths| == 0 {\n      hpaths := [];\n      return;\n    }\n\n    var ls_next := lasf.path_next(ls, lpaths[0], tid);\n\n    if AtomicPathSkippable(lasf, inv, relation, ls, lpaths[0], tid, hs) {\n      hpaths := lemma_LiftPathSequenceGivenAtomicPathsLiftable(lasf, hasf, inv, relation, progress_measure, ls_next, tid, lpaths[1..], hs);\n      return;\n    }\n\n    var hpath0 :| AtomicPathIntroduced(lasf, hasf, relation, progress_measure, ls, lpaths[0], tid, hs, hpath0)\n                  || LiftAtomicPathSuccessful(lasf, hasf, inv, relation, ls, lpaths[0], tid, hs, hpath0);\n\n    var lty := lasf.path_type(lpaths[0]);\n    var hty := hasf.path_type(hpath0);\n\n    var hs_next := hasf.path_next(hs, hpath0, tid);\n\n    if AtomicPathIntroduced(lasf, hasf, relation, progress_measure, ls, lpaths[0], tid, hs, hpath0) {\n      var hpaths_next :=\n        lemma_LiftPathSequenceGivenAtomicPathsLiftable(lasf, hasf, inv, relation, progress_measure, ls, tid, lpaths, hs_next);\n      hpaths := [hpath0] + hpaths_next;\n      assert hpaths[0] == hpath0;\n      assert hpaths[1..] == hpaths_next;\n      return;\n    }\n\n    var hpaths_next := lemma_LiftPathSequenceGivenAtomicPathsLiftable(lasf, hasf, inv, relation, progress_measure, ls_next,\n                                                                      tid, lpaths[1..], hs_next);\n    hpaths := [hpath0] + hpaths_next;\n    assert hpaths[0] == hpath0;\n    assert hpaths[1..] == hpaths_next;\n  }\n\n  lemma lemma_LiftRecurrentAtomicTraceEntryGivenAtomicPathsLiftable<LState, LPath, LPC, HState, HPath, HPC>(\n    lasf: AtomicSpecFunctions<LState, LPath, LPC>,\n    hasf: AtomicSpecFunctions<HState, HPath, HPC>,\n    inv: LState->bool,\n    relation: (LState, HState)->bool,\n    progress_measure: (HState, LPath, Armada_ThreadHandle)->(int, int),\n    ls: LState,\n    tid: Armada_ThreadHandle,\n    lyr: LPath,\n    lrrs: seq<LPath>,\n    lrx: LPath,\n    hs: HState,\n    hyr: HPath\n    ) returns (\n    hrrs: seq<HPath>,\n    hrx: HPath\n    )\n    requires forall ls0, lpath0, hs0 ::\n               && inv(ls0)\n               && relation(ls0, hs0)\n               && lasf.path_valid(ls0, lpath0, tid)\n               && !AtomicPathSkippable(lasf, inv, relation, ls0, lpath0, tid, hs0)\n               ==> exists hpath :: AtomicPathIntroduced(lasf, hasf, relation, progress_measure, ls0, lpath0, tid, hs0, hpath)\n                             || LiftAtomicPathSuccessful(lasf, hasf, inv, relation, ls0, lpath0, tid, hs0, hpath)\n    requires inv(ls)\n    requires relation(ls, hs)\n    requires AtomicValidRecursiveStep(lasf, ls, tid, lyr, lrrs, lrx)\n    requires LiftAtomicPathSuccessful(lasf, hasf, inv, relation, ls, lyr, tid, hs, hyr)\n    ensures  AtomicValidRecursiveStep(hasf, hs, tid, hyr, hrrs, hrx)\n    ensures  var ls1 := lasf.path_next(ls, lyr, tid);\n             var ls2 := AtomicGetStateAfterPaths(lasf, ls1, lrrs, tid);\n             var ls3 := lasf.path_next(ls2, lrx, tid);\n             var hs1 := hasf.path_next(hs, hyr, tid);\n             var hs2 := AtomicGetStateAfterPaths(hasf, hs1, hrrs, tid);\n             var hs3 := hasf.path_next(hs2, hrx, tid);\n             inv(ls3) && relation(ls3, hs3)\n  {\n    var ls1 := lasf.path_next(ls, lyr, tid);\n    var ls2 := AtomicGetStateAfterPaths(lasf, ls1, lrrs, tid);\n    var ls3 := lasf.path_next(ls2, lrx, tid);\n    var hs1 := hasf.path_next(hs, hyr, tid);\n    hrrs := lemma_LiftPathSequenceGivenAtomicPathsLiftable(lasf, hasf, inv, relation, progress_measure, ls1, tid, lrrs, hs1);\n    var hs2 := AtomicGetStateAfterPaths(hasf, hs1, hrrs, tid);\n\n    hrx :| AtomicPathIntroduced(lasf, hasf, relation, progress_measure, ls2, lrx, tid, hs2, hrx)\n           || LiftAtomicPathSuccessful(lasf, hasf, inv, relation, ls2, lrx, tid, hs2, hrx);\n\n    while AtomicPathIntroduced(lasf, hasf, relation, progress_measure, ls2, lrx, tid, hs2, hrx)\n      invariant AtomicPathIntroduced(lasf, hasf, relation, progress_measure, ls2, lrx, tid, hs2, hrx)\n                || LiftAtomicPathSuccessful(lasf, hasf, inv, relation, ls2, lrx, tid, hs2, hrx);\n      invariant AtomicValidPathSequence(hasf, hs1, hrrs, tid)\n      invariant hs2 == AtomicGetStateAfterPaths(hasf, hs1, hrrs, tid)\n      invariant relation(ls2, hs2)\n      decreases progress_measure(hs2, lrx, tid).0, progress_measure(hs2, lrx, tid).1\n    {\n      assert AtomicPathIntroduced(lasf, hasf, relation, progress_measure, ls2, lrx, tid, hs2, hrx);\n      if lasf.path_type(lrx).AtomicPathType_RY? {\n        assert hasf.path_type(hrx).AtomicPathType_RR?;\n      }\n      else {\n        assert lasf.path_type(lrx).AtomicPathType_RS?;\n        assert hasf.path_type(hrx).AtomicPathType_RR?;\n      }\n      lemma_ExtendAtomicGetStateAfterPaths(hasf, hs1, hs2, hrrs, tid, hrx);\n      lemma_ExtendAtomicValidPathSequence(hasf, hs1, hs2, hrrs, tid, hrx);\n      hrrs := hrrs + [hrx];\n      hs2 := hasf.path_next(hs2, hrx, tid);\n      hrx :| AtomicPathIntroduced(lasf, hasf, relation, progress_measure, ls2, lrx, tid, hs2, hrx)\n             || LiftAtomicPathSuccessful(lasf, hasf, inv, relation, ls2, lrx, tid, hs2, hrx);\n    }\n\n    var hs3 := hasf.path_next(hs2, hrx, tid);\n  }\n\n  lemma lemma_LiftAtomicTraceEntryGivenAtomicPathsLiftable<LState, LPath, LPC, HState, HPath, HPC>(\n    lasf: AtomicSpecFunctions<LState, LPath, LPC>,\n    hasf: AtomicSpecFunctions<HState, HPath, HPC>,\n    inv: LState->bool,\n    relation: (LState, HState)->bool,\n    progress_measure: (HState, LPath, Armada_ThreadHandle)->(int, int),\n    ls: LState,\n    lentry: AtomicTraceEntry<LPath>,\n    hs: HState\n    ) returns (\n    hentry: AtomicTraceEntry<HPath>\n    )\n    requires forall ls0, lpath0, hs0, tid ::\n               && inv(ls0)\n               && relation(ls0, hs0)\n               && lasf.path_valid(ls0, lpath0, tid)\n               && !AtomicPathSkippable(lasf, inv, relation, ls0, lpath0, tid, hs0)\n               ==> exists hpath :: AtomicPathIntroduced(lasf, hasf, relation, progress_measure, ls0, lpath0, tid, hs0, hpath)\n                             || LiftAtomicPathSuccessful(lasf, hasf, inv, relation, ls0, lpath0, tid, hs0, hpath)\n    requires inv(ls)\n    requires relation(ls, hs)\n    requires AtomicValidStep(lasf, ls, lentry)\n    ensures  AtomicValidStep(hasf, hs, hentry)\n    ensures  || IntroduceAtomicTraceEntrySuccessful(hasf, inv, relation, progress_measure, ls, lentry, hs, hentry)\n             || LiftAtomicTraceEntrySuccessful(lasf, hasf, inv, relation, ls, lentry, hs, hentry)\n  {\n    match lentry\n    {\n      case AtomicTraceEntry_Stutter() =>\n        hentry := AtomicTraceEntry_Stutter();\n\n      case AtomicTraceEntry_Tau(tid, lpath) =>\n        if AtomicPathSkippable(lasf, inv, relation, ls, lpath, tid, hs) {\n          hentry := AtomicTraceEntry_Stutter();\n        }\n        else {\n          var hpath :| AtomicPathIntroduced(lasf, hasf, relation, progress_measure, ls, lpath, tid, hs, hpath)\n                       || LiftAtomicPathSuccessful(lasf, hasf, inv, relation, ls, lpath, tid, hs, hpath);\n          hentry := AtomicTraceEntry_Tau(tid, hpath);\n        }\n\n      case AtomicTraceEntry_Normal(tid, lpath) =>\n        if AtomicPathSkippable(lasf, inv, relation, ls, lpath, tid, hs) {\n          hentry := AtomicTraceEntry_Stutter();\n        }\n        else {\n          var hpath :| AtomicPathIntroduced(lasf, hasf, relation, progress_measure, ls, lpath, tid, hs, hpath)\n                       || LiftAtomicPathSuccessful(lasf, hasf, inv, relation, ls, lpath, tid, hs, hpath);\n          if AtomicPathIntroduced(lasf, hasf, relation, progress_measure, ls, lpath, tid, hs, hpath) {\n            if hasf.path_type(hpath).AtomicPathType_Tau? {\n              hentry := AtomicTraceEntry_Tau(tid, hpath);\n            }\n            else {\n              hentry := AtomicTraceEntry_Normal(tid, hpath);\n            }\n          }\n          else {\n            hentry := AtomicTraceEntry_Normal(tid, hpath);\n          }\n        }\n\n      case AtomicTraceEntry_Recurrent(tid, lyr, lrrs, lrx) =>\n        var hpath :| AtomicPathIntroduced(lasf, hasf, relation, progress_measure, ls, lyr, tid, hs, hpath)\n                     || LiftAtomicPathSuccessful(lasf, hasf, inv, relation, ls, lyr, tid, hs, hpath);\n        if AtomicPathIntroduced(lasf, hasf, relation, progress_measure, ls, lyr, tid, hs, hpath) {\n          if hasf.path_type(hpath).AtomicPathType_Tau? {\n            hentry := AtomicTraceEntry_Tau(tid, hpath);\n          }\n          else {\n            hentry := AtomicTraceEntry_Normal(tid, hpath);\n          }\n        }\n        else {\n          var hrrs, hrx :=\n            lemma_LiftRecurrentAtomicTraceEntryGivenAtomicPathsLiftable(lasf, hasf, inv, relation, progress_measure,\n                                                                        ls, tid, lyr, lrrs, lrx, hs, hpath);\n          hentry := AtomicTraceEntry_Recurrent(tid, hpath, hrrs, hrx);\n        }\n    }\n  }\n\n  lemma lemma_LiftAtomicBehaviorGivenAtomicPathsLiftableGeneral<LState(!new), LPath(!new), LPC(!new), HState(!new), HPath(!new), HPC(!new)>(\n    lb: AnnotatedBehavior<LState, AtomicTraceEntry<LPath>>,\n    lasf: AtomicSpecFunctions<LState, LPath, LPC>,\n    hasf: AtomicSpecFunctions<HState, HPath, HPC>,\n    inv: LState->bool,\n    relation: (LState, HState)->bool,\n    progress_measure: (HState, LPath, Armada_ThreadHandle)->(int, int),\n    refinement_relation: RefinementRelation<LState, HState>\n    ) returns (\n    hb: AnnotatedBehavior<HState, AtomicTraceEntry<HPath>>\n    )\n    requires forall ls, lpath, hs, tid ::\n               && inv(ls)\n               && relation(ls, hs)\n               && lasf.path_valid(ls, lpath, tid)\n               && !AtomicPathSkippable(lasf, inv, relation, ls, lpath, tid, hs)\n               ==> exists hpath :: AtomicPathIntroduced(lasf, hasf, relation, progress_measure, ls, lpath, tid, hs, hpath)\n                             || LiftAtomicPathSuccessful(lasf, hasf, inv, relation, ls, lpath, tid, hs, hpath)\n    requires AtomicInitImpliesInv(lasf, inv)\n    requires forall ls :: lasf.init(ls) ==> exists hs :: hasf.init(hs) && relation(ls, hs)\n    requires forall ls, hs :: inv(ls) && relation(ls, hs) ==> RefinementPair(ls, hs) in refinement_relation\n    requires AnnotatedBehaviorSatisfiesSpec(lb, AtomicAnnotatedSpec(lasf))\n    ensures  AnnotatedBehaviorSatisfiesSpec(hb, AtomicAnnotatedSpec(hasf))\n    ensures  BehaviorRefinesBehavior(lb.states, hb.states, refinement_relation)\n  {\n    var hs0 :| hasf.init(hs0) && relation(lb.states[0], hs0);\n    hb := AnnotatedBehavior([hs0], []);\n    var pos := 0;\n    var lh_map := [RefinementRange(0, 0)];\n\n    assert BehaviorRefinesBehaviorUsingRefinementMap(lb.states[..pos+1], hb.states, refinement_relation, lh_map);\n\n    while pos < |lb.trace|\n      invariant 0 <= pos <= |lb.trace|\n      invariant |hb.states| > 0\n      invariant BehaviorRefinesBehavior(lb.states[..pos+1], hb.states, refinement_relation)\n      invariant AnnotatedBehaviorSatisfiesSpec(hb, AtomicAnnotatedSpec(hasf))\n      invariant relation(lb.states[pos], last(hb.states))\n      invariant inv(lb.states[pos])\n      decreases |lb.states| - pos,\n                if pos < |lb.trace| then GetTraceEntryProgressMeasure(progress_measure, last(hb.states), lb.trace[pos]).0 else 0,\n                if pos < |lb.trace| then GetTraceEntryProgressMeasure(progress_measure, last(hb.states), lb.trace[pos]).1 else 0\n    {\n      var ls := lb.states[pos];\n      var ls' := lb.states[pos+1];\n      var lentry := lb.trace[pos];\n      var hs := last(hb.states);\n      assert ActionTuple(ls, ls', lentry) in AtomicAnnotatedSpec(lasf).next;\n      var hentry := lemma_LiftAtomicTraceEntryGivenAtomicPathsLiftable(lasf, hasf, inv, relation, progress_measure, ls, lentry, hs);\n      var hs' := AtomicGetNextStateAlways(hasf, hs, hentry);\n      if LiftAtomicTraceEntrySuccessful(lasf, hasf, inv, relation, ls, lentry, hs, hentry) {\n        lemma_ExtendBehaviorRefinesBehaviorRightOne_LH(lb.states[..pos+1], hb.states, refinement_relation, ls', hs');\n        assert lb.states[..pos+1] + [ls'] == lb.states[..pos+1+1];\n        pos := pos + 1;\n      }\n      else {\n        lemma_ExtendBehaviorRefinesBehaviorRightOne_LStutter(lb.states[..pos+1], hb.states, refinement_relation, hs');\n      }\n      hb := AnnotatedBehavior(hb.states + [hs'], hb.trace + [hentry]);\n    }\n\n    assert lb.states[..pos+1] == lb.states;\n    assert BehaviorRefinesBehavior(lb.states, hb.states, refinement_relation);\n  }\n\n  lemma lemma_AtomicBehaviorToAnnotatedBehavior<State(!new), Path(!new), PC(!new)>(\n    asf: AtomicSpecFunctions<State, Path, PC>,\n    b: seq<State>\n    ) returns (\n    ab: AnnotatedBehavior<State, AtomicTraceEntry<Path>>\n    )\n    requires BehaviorSatisfiesSpec(b, AtomicSpec(asf))\n    ensures  AnnotatedBehaviorSatisfiesSpec(ab, AtomicAnnotatedSpec(asf))\n    ensures  ab.states == b\n  {\n    var pos := 0;\n    var trace := [];\n    while pos < |b| - 1\n      invariant 0 <= pos <= |b| - 1\n      invariant |trace| == pos\n      invariant AnnotatedBehaviorSatisfiesSpec(AnnotatedBehavior(b[..pos + 1], trace), AtomicAnnotatedSpec(asf))\n    {\n      assert StatePair(b[pos], b[pos+1]) in AtomicSpec(asf).next;\n      var entry :| AtomicNext(asf, b[pos], b[pos + 1], entry);\n      lemma_ExtendStateNextSeqRight(b[..pos + 1], trace, AtomicAnnotatedSpec(asf).next, b[pos + 1], entry);\n      assert b[..pos + 1] + [b[pos + 1]] == b[..(pos + 1) + 1];\n      trace := trace + [entry];\n      pos := pos + 1;\n    }\n    assert b[..pos + 1] == b;\n    ab := AnnotatedBehavior(b, trace);\n  }\n\n  lemma lemma_AtomicAnnotatedBehaviorSatisfiesAtomicSpec<State(!new), Path(!new), PC(!new)>(\n    asf: AtomicSpecFunctions<State, Path, PC>,\n    ab: AnnotatedBehavior<State, AtomicTraceEntry<Path>>\n    )\n    requires AnnotatedBehaviorSatisfiesSpec(ab, AtomicAnnotatedSpec(asf))\n    ensures  BehaviorSatisfiesSpec(ab.states, AtomicSpec(asf))\n  {\n    forall pos | 0 <= pos < |ab.trace|\n      ensures StatePair(ab.states[pos], ab.states[pos + 1]) in AtomicSpec(asf).next\n    {\n      assert ActionTuple(ab.states[pos], ab.states[pos + 1], ab.trace[pos]) in AtomicAnnotatedSpec(asf).next;\n    }\n  }\n\n  lemma lemma_LiftAtomicToAtomicGivenAtomicPathsLiftableGeneral<LState(!new), LPath(!new), LPC(!new), HState(!new), HPath(!new), HPC(!new)>(\n    lasf: AtomicSpecFunctions<LState, LPath, LPC>,\n    hasf: AtomicSpecFunctions<HState, HPath, HPC>,\n    inv: LState->bool,\n    relation: (LState, HState)->bool,\n    progress_measure: (HState, LPath, Armada_ThreadHandle)->(int, int),\n    refinement_relation: RefinementRelation<LState, HState>\n    )\n    requires forall ls, lpath, hs, tid ::\n               && inv(ls)\n               && relation(ls, hs)\n               && lasf.path_valid(ls, lpath, tid)\n               && !AtomicPathSkippable(lasf, inv, relation, ls, lpath, tid, hs)\n               ==> exists hpath :: AtomicPathIntroduced(lasf, hasf, relation, progress_measure, ls, lpath, tid, hs, hpath)\n                             || LiftAtomicPathSuccessful(lasf, hasf, inv, relation, ls, lpath, tid, hs, hpath)\n    requires AtomicInitImpliesInv(lasf, inv)\n    requires forall ls :: lasf.init(ls) ==> exists hs :: hasf.init(hs) && relation(ls, hs)\n    requires forall ls, hs :: inv(ls) && relation(ls, hs) ==> RefinementPair(ls, hs) in refinement_relation\n    ensures  SpecRefinesSpec(AtomicSpec(lasf), AtomicSpec(hasf), refinement_relation)\n  {\n    forall lb | BehaviorSatisfiesSpec(lb, AtomicSpec(lasf))\n      ensures exists hb :: BehaviorRefinesBehavior(lb, hb, refinement_relation) && BehaviorSatisfiesSpec(hb, AtomicSpec(hasf))\n    {\n      var alb := lemma_AtomicBehaviorToAnnotatedBehavior(lasf, lb);\n      var ahb := lemma_LiftAtomicBehaviorGivenAtomicPathsLiftableGeneral(alb, lasf, hasf, inv, relation, progress_measure,\n                                                                         refinement_relation);\n      lemma_AtomicAnnotatedBehaviorSatisfiesAtomicSpec(hasf, ahb);\n      var hb := ahb.states;\n      assert BehaviorRefinesBehavior(lb, hb, refinement_relation) && BehaviorSatisfiesSpec(hb, AtomicSpec(hasf));\n    }\n  }\n\n  lemma lemma_LiftAtomicToAtomicGivenAtomicPathsLiftable<LState(!new), LPath(!new), LPC(!new), HState(!new), HPath(!new), HPC(!new)>(\n    lasf: AtomicSpecFunctions<LState, LPath, LPC>,\n    hasf: AtomicSpecFunctions<HState, HPath, HPC>,\n    inv: LState->bool,\n    relation: (LState, HState)->bool,\n    refinement_relation: RefinementRelation<LState, HState>\n    )\n    requires forall ls, lpath, hs, tid ::\n               && inv(ls)\n               && relation(ls, hs)\n               && lasf.path_valid(ls, lpath, tid)\n               ==> exists hpath :: LiftAtomicPathSuccessful(lasf, hasf, inv, relation, ls, lpath, tid, hs, hpath)\n    requires AtomicInitImpliesInv(lasf, inv)\n    requires forall ls, hs :: relation(ls, hs) ==> lasf.state_ok(ls) == hasf.state_ok(hs)\n    requires forall ls :: lasf.init(ls) ==> exists hs :: hasf.init(hs) && relation(ls, hs)\n    requires forall ls, hs :: inv(ls) && relation(ls, hs) ==> RefinementPair(ls, hs) in refinement_relation\n    ensures  SpecRefinesSpec(AtomicSpec(lasf), AtomicSpec(hasf), refinement_relation)\n  {\n    var progress_measure:(HState, LPath, Armada_ThreadHandle)->(int, int) := (hs: HState, ls: LPath, tid: Armada_ThreadHandle) => (0, 0);\n    lemma_LiftAtomicToAtomicGivenAtomicPathsLiftableGeneral(lasf, hasf, inv, relation, progress_measure, refinement_relation);\n  }\n\n  lemma lemma_LiftAtomicToAtomicGivenAtomicPathsSkippablyLiftable<LState(!new), LPath(!new), LPC(!new), HState(!new), HPath(!new), HPC(!new)>(\n    lasf: AtomicSpecFunctions<LState, LPath, LPC>,\n    hasf: AtomicSpecFunctions<HState, HPath, HPC>,\n    inv: LState->bool,\n    relation: (LState, HState)->bool,\n    refinement_relation: RefinementRelation<LState, HState>\n    )\n    requires forall ls, lpath, hs, tid ::\n               && inv(ls)\n               && relation(ls, hs)\n               && lasf.path_valid(ls, lpath, tid)\n               && !AtomicPathSkippable(lasf, inv, relation, ls, lpath, tid, hs)\n               ==> exists hpath :: LiftAtomicPathSuccessful(lasf, hasf, inv, relation, ls, lpath, tid, hs, hpath)\n    requires AtomicInitImpliesInv(lasf, inv)\n    requires forall ls :: lasf.init(ls) ==> exists hs :: hasf.init(hs) && relation(ls, hs)\n    requires forall ls, hs :: inv(ls) && relation(ls, hs) ==> RefinementPair(ls, hs) in refinement_relation\n    ensures  SpecRefinesSpec(AtomicSpec(lasf), AtomicSpec(hasf), refinement_relation)\n  {\n    var progress_measure:(HState, LPath, Armada_ThreadHandle)->(int, int) := (hs: HState, ls: LPath, tid: Armada_ThreadHandle) => (0, 0);\n    lemma_LiftAtomicToAtomicGivenAtomicPathsLiftableGeneral(lasf, hasf, inv, relation, progress_measure, refinement_relation);\n  }\n\n  lemma lemma_LiftAtomicToAtomicGivenAtomicPathsIntroduciblyLiftable<LState(!new), LPath(!new), LPC(!new), HState(!new), HPath(!new), HPC(!new)>(\n    lasf: AtomicSpecFunctions<LState, LPath, LPC>,\n    hasf: AtomicSpecFunctions<HState, HPath, HPC>,\n    inv: LState->bool,\n    relation: (LState, HState)->bool,\n    progress_measure: (HState, LPath, Armada_ThreadHandle)->(int, int),\n    refinement_relation: RefinementRelation<LState, HState>\n    )\n    requires forall ls, lpath, hs, tid ::\n               && inv(ls)\n               && relation(ls, hs)\n               && lasf.path_valid(ls, lpath, tid)\n               ==> exists hpath :: AtomicPathIntroduced(lasf, hasf, relation, progress_measure, ls, lpath, tid, hs, hpath)\n                             || LiftAtomicPathSuccessful(lasf, hasf, inv, relation, ls, lpath, tid, hs, hpath)\n    requires AtomicInitImpliesInv(lasf, inv)\n    requires forall ls :: lasf.init(ls) ==> exists hs :: hasf.init(hs) && relation(ls, hs)\n    requires forall ls, hs :: inv(ls) && relation(ls, hs) ==> RefinementPair(ls, hs) in refinement_relation\n    ensures  SpecRefinesSpec(AtomicSpec(lasf), AtomicSpec(hasf), refinement_relation)\n  {\n    lemma_LiftAtomicToAtomicGivenAtomicPathsLiftableGeneral(lasf, hasf, inv, relation, progress_measure, refinement_relation);\n  }\n\n}\n"
  },
  {
    "path": "Armada/strategies/generic/LiftFromAtomic.i.dfy",
    "content": "include \"GenericArmadaAtomic.i.dfy\"\n\nmodule LiftFromAtomicModule\n{\n  import opened util_collections_seqs_s\n  import opened util_collections_seqs_i\n  import opened util_option_s\n  import opened GenericArmadaSpecModule\n  import opened AnnotatedBehaviorModule\n  import opened ArmadaCommonDefinitions\n  import opened GeneralRefinementModule\n  import opened GeneralRefinementLemmasModule\n  import opened InvariantsModule\n  import opened GenericArmadaLemmasModule\n  import opened GenericArmadaAtomicModule\n\n  //////////////////////////////////////////////\n  // LIFTING FROM ATOMIC\n  //////////////////////////////////////////////\n\n  predicate AtomicLiftPathFromAtomicPossible<State, Path, PC>(\n    asf: AtomicSpecFunctions<State, Path, PC>,\n    s: State,\n    s': State,\n    path: Path,\n    tid: Armada_ThreadHandle\n    )\n  {\n    && asf.path_valid(s, path, tid)\n    && s' == asf.path_next(s, path, tid)\n  }\n\n  predicate AtomicStepsLiftPathFromAtomic<State, OneStep, PC>(\n    asf: Armada_SpecFunctions<State, OneStep, PC>,\n    s: State,\n    s': State,\n    steps: seq<OneStep>,\n    tid: Armada_ThreadHandle,\n    startsYielding: bool,\n    mustEndYielding: bool,\n    ok: bool\n    )\n  {\n    && |steps| > 0\n    && !asf.is_step_tau(steps[0])\n    && (startsYielding == Armada_ThreadYielding(asf, s, tid))\n    && (mustEndYielding ==> Armada_ThreadYielding(asf, s', tid))\n    && Armada_StepsStartNonyielding(asf, asf.step_next(s, steps[0], tid), s', steps[1..], tid)\n    && asf.state_ok(s') == ok\n  }\n\n  predicate AtomicLiftPathFromAtomicSuccessful<State, OneStep, Path, PC>(\n    lasf: AtomicSpecFunctions<State, Path, PC>,\n    hasf: Armada_SpecFunctions<State, OneStep, PC>,\n    s: State,\n    s': State,\n    path: Path,\n    tid: Armada_ThreadHandle,\n    steps: seq<OneStep>\n    )\n  {\n    && Armada_NextMultipleSteps(hasf, s, s', steps, tid)\n    && match lasf.path_type(path)\n        case AtomicPathType_Tau => |steps| == 1 && hasf.is_step_tau(steps[0])\n        case AtomicPathType_YY  => AtomicStepsLiftPathFromAtomic(hasf, s, s', steps, tid, true, true, true)\n        case AtomicPathType_YS  => AtomicStepsLiftPathFromAtomic(hasf, s, s', steps, tid, true, true, false)\n        case AtomicPathType_YR  => AtomicStepsLiftPathFromAtomic(hasf, s, s', steps, tid, true, false, true)\n        case AtomicPathType_RY  => AtomicStepsLiftPathFromAtomic(hasf, s, s', steps, tid, false, true, true)\n        case AtomicPathType_RS  => AtomicStepsLiftPathFromAtomic(hasf, s, s', steps, tid, false, true, false)\n        case AtomicPathType_RR  => AtomicStepsLiftPathFromAtomic(hasf, s, s', steps, tid, false, false, true)\n  }\n  lemma lemma_LiftRecurrentEntryFromAtomic<State(!new), OneStep(!new), Path(!new), PC(!new)>(\n    lasf: AtomicSpecFunctions<State, Path, PC>,\n    hasf: Armada_SpecFunctions<State, OneStep, PC>,\n    s: State,\n    s': State,\n    tid: Armada_ThreadHandle,\n    yr: Path,\n    rrs: seq<Path>,\n    rx: Path\n    ) returns (\n    hsteps: seq<OneStep>\n    )\n    requires forall s :: lasf.state_ok(s) <==> hasf.state_ok(s)\n    requires AtomicValidRecursiveStep(lasf, s, tid, yr, rrs, rx)\n    requires s' == lasf.path_next(AtomicGetStateAfterPaths(lasf, lasf.path_next(s, yr, tid), rrs, tid), rx, tid)\n    requires forall ls, ls', path :: AtomicLiftPathFromAtomicPossible(lasf, ls, ls', path, tid) ==>\n               exists hsteps' :: AtomicLiftPathFromAtomicSuccessful(lasf, hasf, ls, ls', path, tid, hsteps')\n    ensures  Armada_NextMultistep(hasf, s, s', hsteps, tid, false)\n  {\n    var ls1 := lasf.path_next(s, yr, tid);\n    assert AtomicLiftPathFromAtomicPossible(lasf, s, ls1, yr, tid);\n    var hsteps_yr :| AtomicLiftPathFromAtomicSuccessful(lasf, hasf, s, ls1, yr, tid, hsteps_yr);\n\n    var hstep0 := hsteps_yr[0];\n    var hsteps_current := hsteps_yr[1..];\n    var s_next := hasf.step_next(s, hstep0, tid);\n\n    var current_state := ls1;\n    var rrs_remaining := rrs;\n    var ls2 := AtomicGetStateAfterPaths(lasf, ls1, rrs, tid);\n\n    while |rrs_remaining| > 0\n      invariant AtomicValidPathSequence(lasf, current_state, rrs_remaining, tid)\n      invariant ls2 == AtomicGetStateAfterPaths(lasf, current_state, rrs_remaining, tid)\n      invariant Armada_StepsStartNonyielding(hasf, s_next, current_state, hsteps_current, tid)\n      invariant Armada_NextMultipleSteps(hasf, s_next, current_state, hsteps_current, tid)\n    {\n      var next_state := lasf.path_next(current_state, rrs_remaining[0], tid);\n      assert AtomicLiftPathFromAtomicPossible(lasf, current_state, next_state, rrs_remaining[0], tid);\n      var hsteps_next :| AtomicLiftPathFromAtomicSuccessful(lasf, hasf, current_state, next_state, rrs_remaining[0], tid, hsteps_next);\n\n      lemma_CombineArmadaStepsStartNonyielding(hasf, s_next, current_state, next_state, hsteps_current, hsteps_next, tid);\n      assert Armada_StepsStartNonyielding(hasf, s_next, next_state, hsteps_current + hsteps_next, tid);\n\n      hsteps_current := hsteps_current + hsteps_next;\n      rrs_remaining := rrs_remaining[1..];\n      current_state := next_state;\n    }\n\n    assert current_state == ls2;\n\n    assert AtomicLiftPathFromAtomicPossible(lasf, ls2, s', rx, tid);\n    var hsteps_next :| AtomicLiftPathFromAtomicSuccessful(lasf, hasf, ls2, s', rx, tid, hsteps_next);\n\n    lemma_CombineArmadaStepsStartNonyielding(hasf, s_next, ls2, s', hsteps_current, hsteps_next, tid);\n\n    assert Armada_StepsStartNonyielding(hasf, s_next, s', hsteps_current + hsteps_next, tid);\n    assert Armada_NextMultipleSteps(hasf, s_next, s', hsteps_current + hsteps_next, tid);\n\n    hsteps := [hstep0] + (hsteps_current + hsteps_next);\n    assert hsteps[0] == hstep0;\n    assert hsteps[1..] == hsteps_current + hsteps_next;\n    assert Armada_NextMultistep(hasf, s, s', hsteps, tid, false);\n  }\n\n  lemma lemma_LiftEntryFromAtomic<State(!new), OneStep(!new), Path(!new), PC(!new)>(\n    lasf: AtomicSpecFunctions<State, Path, PC>,\n    hasf: Armada_SpecFunctions<State, OneStep, PC>,\n    s: State,\n    s': State,\n    lentry: AtomicTraceEntry<Path>\n    ) returns (\n    hsteps: seq<OneStep>,\n    tid: Armada_ThreadHandle,\n    tau: bool\n    )\n    requires forall s :: lasf.state_ok(s) <==> hasf.state_ok(s)\n    requires AtomicNext(lasf, s, s', lentry)\n    requires forall ls, ls', path, tid :: AtomicLiftPathFromAtomicPossible(lasf, ls, ls', path, tid) ==>\n               exists hsteps' :: AtomicLiftPathFromAtomicSuccessful(lasf, hasf, ls, ls', path, tid, hsteps')\n    ensures  Armada_NextMultistep(hasf, s, s', hsteps, tid, tau)\n  {\n    match lentry\n    {\n      case AtomicTraceEntry_Stutter =>\n        hsteps := [];\n        // No need to set tid, since the tid used for a stutter can be arbitrary.\n        tau := false;\n\n      case AtomicTraceEntry_Tau(tau_tid, path) =>\n        tid := tau_tid;\n        assert AtomicLiftPathFromAtomicPossible(lasf, s, s', path, tid);\n        hsteps :| AtomicLiftPathFromAtomicSuccessful(lasf, hasf, s, s', path, tid, hsteps);\n        tau := true;\n\n      case AtomicTraceEntry_Normal(normal_tid, path) =>\n        tid := normal_tid;\n        assert AtomicLiftPathFromAtomicPossible(lasf, s, s', path, tid);\n        hsteps :| AtomicLiftPathFromAtomicSuccessful(lasf, hasf, s, s', path, tid, hsteps);\n        tau := false;\n\n      case AtomicTraceEntry_Recurrent(entry_tid, yr, rrs, rx) =>\n        tid := entry_tid;\n        hsteps := lemma_LiftRecurrentEntryFromAtomic(lasf, hasf, s, s', tid, yr, rrs, rx);\n        tau := false;\n    }\n  }\n\n  lemma lemma_LiftBehaviorFromAtomic<State(!new), OneStep(!new), Path(!new), PC(!new)>(\n    lasf: AtomicSpecFunctions<State, Path, PC>,\n    hasf: Armada_SpecFunctions<State, OneStep, PC>,\n    b: seq<State>\n    )\n    requires BehaviorSatisfiesSpec(b, AtomicSpec(lasf))\n    requires forall s :: lasf.init(s) ==> hasf.init(s)\n    requires forall s :: lasf.state_ok(s) <==> hasf.state_ok(s)\n    requires forall ls, ls', path, tid :: AtomicLiftPathFromAtomicPossible(lasf, ls, ls', path, tid) ==>\n               exists hsteps :: AtomicLiftPathFromAtomicSuccessful(lasf, hasf, ls, ls', path, tid, hsteps)\n    ensures  BehaviorSatisfiesSpec(b, Armada_SpecFunctionsToSpec(hasf))\n  {\n    var lspec := AtomicSpec(lasf);\n    var hspec := Armada_SpecFunctionsToSpec(hasf);\n\n    forall i {:trigger StatePair(b[i], b[i + 1]) in hspec.next} | 0 <= i < |b| - 1\n      ensures StatePair(b[i], b[i + 1]) in hspec.next\n    {\n      assert StatePair(b[i], b[i + 1]) in lspec.next;\n      var lentry :| AtomicNext(lasf, b[i], b[i + 1], lentry);\n      var hsteps, tid, tau := lemma_LiftEntryFromAtomic(lasf, hasf, b[i], b[i + 1], lentry);\n      assert StatePair(b[i], b[i + 1]) in hspec.next;\n    }\n  }\n\n  lemma lemma_AtomicSpecRefinesSpec<State(!new), OneStep(!new), Path(!new), PC(!new)>(\n    lasf: AtomicSpecFunctions<State, Path, PC>,\n    hasf: Armada_SpecFunctions<State, OneStep, PC>\n    ) returns (\n    refinement_relation: RefinementRelation<State, State>\n    )\n    requires forall s :: lasf.init(s) ==> hasf.init(s)\n    requires forall s :: lasf.state_ok(s) <==> hasf.state_ok(s)\n    requires forall ls, ls', path, tid :: AtomicLiftPathFromAtomicPossible(lasf, ls, ls', path, tid) ==>\n               exists hsteps :: AtomicLiftPathFromAtomicSuccessful(lasf, hasf, ls, ls', path, tid, hsteps)\n    ensures  SpecRefinesSpec(AtomicSpec(lasf), Armada_SpecFunctionsToSpec(hasf), refinement_relation)\n    ensures  refinement_relation == iset s | true :: RefinementPair(s, s)\n  {\n    refinement_relation := iset s | true :: RefinementPair(s, s);\n    forall lb | BehaviorSatisfiesSpec(lb, AtomicSpec(lasf))\n      ensures BehaviorRefinesSpec(lb, Armada_SpecFunctionsToSpec(hasf), refinement_relation)\n    {\n      lemma_LiftBehaviorFromAtomic(lasf, hasf, lb);\n      lemma_IfRefinementRelationReflexiveThenBehaviorRefinesItself(lb, refinement_relation);\n      assert BehaviorRefinesBehavior(lb, lb, refinement_relation) && BehaviorSatisfiesSpec(lb, Armada_SpecFunctionsToSpec(hasf));\n    }\n  }\n\n}\n"
  },
  {
    "path": "Armada/strategies/generic/LiftToAtomic.i.dfy",
    "content": "include \"GenericArmadaAtomic.i.dfy\"\n\nmodule LiftToAtomicModule\n{\n  import opened util_collections_seqs_s\n  import opened util_collections_seqs_i\n  import opened util_option_s\n  import opened GenericArmadaSpecModule\n  import opened AnnotatedBehaviorModule\n  import opened ArmadaCommonDefinitions\n  import opened GeneralRefinementModule\n  import opened GeneralRefinementLemmasModule\n  import opened InvariantsModule\n  import opened GenericArmadaLemmasModule\n  import opened GenericArmadaAtomicModule\n\n  //////////////////////////////////////////////\n  // LIFTING TO ATOMIC\n  //////////////////////////////////////////////\n\n  predicate ThreadYieldingOrRecurrent<State, OneStep, PC>(\n    asf: Armada_SpecFunctions<State, OneStep, PC>,\n    is_recurrent_pc: PC->bool,\n    s: State,\n    tid: Armada_ThreadHandle\n    )\n  {\n    Armada_ThreadYielding(asf, s, tid) || is_recurrent_pc(asf.get_thread_pc(s, tid).v)\n  }\n\n  predicate LInitImpliesHInit<State(!new), OneStep, Path, PC>(\n    lasf: Armada_SpecFunctions<State, OneStep, PC>,\n    hasf: AtomicSpecFunctions<State, Path, PC>\n    )\n  {\n    forall s :: lasf.init(s) ==> hasf.init(s)\n  }\n\n  predicate StateOKsMatch<State(!new), OneStep, Path, PC>(\n    lasf: Armada_SpecFunctions<State, OneStep, PC>,\n    hasf: AtomicSpecFunctions<State, Path, PC>\n    )\n  {\n    forall s :: lasf.state_ok(s) == hasf.state_ok(s)\n  }\n\n  predicate NonyieldingPCsMatch<State, OneStep, Path, PC(!new)>(\n    lasf: Armada_SpecFunctions<State, OneStep, PC>,\n    hasf: AtomicSpecFunctions<State, Path, PC>\n    )\n  {\n    forall pc :: lasf.is_pc_nonyielding(pc) <==> hasf.is_pc_nonyielding(pc)\n  }\n\n  predicate ThreadPCsMatch<State(!new), OneStep, Path, PC>(\n    lasf: Armada_SpecFunctions<State, OneStep, PC>,\n    hasf: AtomicSpecFunctions<State, Path, PC>\n    )\n  {\n    forall s, tid :: lasf.get_thread_pc(s, tid) == hasf.get_thread_pc(s, tid)\n  }\n\n  predicate TausLiftableConditions<State(!new), OneStep(!new), PC>(\n    lasf: Armada_SpecFunctions<State, OneStep, PC>,\n    s: State,\n    s': State,\n    step: OneStep,\n    tid: Armada_ThreadHandle\n    )\n  {\n    && lasf.step_valid(s, step, tid)\n    && s' == lasf.step_next(s, step, tid)\n    && lasf.is_step_tau(step)\n  }\n\n  predicate TausLiftable<State(!new), OneStep(!new), Path(!new), PC>(\n    lasf: Armada_SpecFunctions<State, OneStep, PC>,\n    hasf: AtomicSpecFunctions<State, Path, PC>\n    )\n  {\n    forall s, s', lstep, tid {:trigger TausLiftableConditions(lasf, s, s', lstep, tid)} ::\n      TausLiftableConditions(lasf, s, s', lstep, tid)\n      ==> exists hpath ::\n            && hasf.path_valid(s, hpath, tid)\n            && hasf.path_type(hpath).AtomicPathType_Tau? \n            && s' == hasf.path_next(s, hpath, tid)\n  }\n\n  predicate SequencesCompressibleConditions<State, OneStep, PC>(\n    asf: Armada_SpecFunctions<State, OneStep, PC>,\n    is_recurrent_pc: PC->bool,\n    s: State,\n    s': State,\n    steps: seq<OneStep>,\n    tid: Armada_ThreadHandle\n    )\n  {\n    && |steps| > 0\n    && !asf.is_step_tau(steps[0])\n    && asf.step_valid(s, steps[0], tid)\n    && ThreadYieldingOrRecurrent(asf, is_recurrent_pc, s, tid)\n    && ThreadYieldingOrRecurrent(asf, is_recurrent_pc, s', tid)\n    && StepsStartNonyieldingNonrecurrent(asf, is_recurrent_pc, asf.step_next(s, steps[0], tid), s', steps[1..], tid)\n  }\n\n  predicate SequencesCompressibleConclusions<State(!new), Path(!new), PC>(\n    asf: AtomicSpecFunctions<State, Path, PC>,\n    s: State,\n    s': State,\n    tid: Armada_ThreadHandle,\n    path: Path\n    )\n  {\n    && asf.path_valid(s, path, tid)\n    && s' == asf.path_next(s, path, tid)\n    && !asf.path_type(path).AtomicPathType_Tau?\n    && AtomicPathTypeMatchesPCTypes(asf, s, path, tid)\n  }\n\n  predicate SequencesCompressible<State(!new), OneStep(!new), Path(!new), PC>(\n    lasf: Armada_SpecFunctions<State, OneStep, PC>,\n    hasf: AtomicSpecFunctions<State, Path, PC>,\n    is_recurrent_pc: PC->bool\n    )\n  {\n    forall s, s', lsteps, tid {:trigger SequencesCompressibleConditions(lasf, is_recurrent_pc, s, s', lsteps, tid)} ::\n      SequencesCompressibleConditions(lasf, is_recurrent_pc, s, s', lsteps, tid)\n      ==> exists hpath :: SequencesCompressibleConclusions(hasf, s, s', tid, hpath)\n  }\n\n  predicate RequirementsForLiftingToAtomic<State(!new), OneStep(!new), Path(!new), PC(!new)>(\n    lasf: Armada_SpecFunctions<State, OneStep, PC>,\n    hasf: AtomicSpecFunctions<State, Path, PC>,\n    is_recurrent_pc: PC->bool\n    )\n  {\n    && LInitImpliesHInit(lasf, hasf)\n    && StateOKsMatch(lasf, hasf)\n    && NonyieldingPCsMatch(lasf, hasf)\n    && ThreadPCsMatch(lasf, hasf)\n    && TausLiftable(lasf, hasf)\n    && SequencesCompressible(lasf, hasf, is_recurrent_pc)\n  }\n\n  predicate StepsEndNonyieldingNonrecurrent<State, OneStep, PC>(\n    asf: Armada_SpecFunctions<State, OneStep, PC>,\n    is_recurrent_pc: PC->bool,\n    s: State,\n    s': State,\n    steps: seq<OneStep>,\n    tid: Armada_ThreadHandle\n    )\n  {\n    if |steps| == 0 then\n      s' == s\n    else\n      var s_next := asf.step_next(s, steps[0], tid);\n      && !Armada_ThreadYielding(asf, s_next, tid)\n      && !is_recurrent_pc(asf.get_thread_pc(s_next, tid).v)\n      && !asf.is_step_tau(steps[0])\n      && StepsEndNonyieldingNonrecurrent(asf, is_recurrent_pc, s_next, s', steps[1..], tid)\n  }\n\n  predicate StepsStartNonyieldingNonrecurrent<State, OneStep, PC>(\n    asf: Armada_SpecFunctions<State, OneStep, PC>,\n    is_recurrent_pc: PC->bool,\n    s: State,\n    s': State,\n    steps: seq<OneStep>,\n    tid: Armada_ThreadHandle\n    )\n  {\n    if |steps| == 0 then\n      s' == s\n    else\n      var s_next := asf.step_next(s, steps[0], tid);\n      && asf.step_valid(s, steps[0], tid)\n      && !Armada_ThreadYielding(asf, s, tid)\n      && !is_recurrent_pc(asf.get_thread_pc(s, tid).v)\n      && !asf.is_step_tau(steps[0])\n      && StepsStartNonyieldingNonrecurrent(asf, is_recurrent_pc, s_next, s', steps[1..], tid)\n  }\n\n  lemma lemma_ExtendStepsEndNonyieldingNonrecurrent<State, OneStep, PC>(\n    asf: Armada_SpecFunctions<State, OneStep, PC>,\n    is_recurrent_pc: PC->bool,\n    s: State,\n    s': State,\n    s'': State,\n    steps: seq<OneStep>,\n    step: OneStep,\n    tid: Armada_ThreadHandle\n    )\n    requires Armada_NextMultipleSteps(asf, s, s', steps, tid)\n    requires StepsEndNonyieldingNonrecurrent(asf, is_recurrent_pc, s, s', steps, tid)\n    requires !asf.is_step_tau(step)\n    requires asf.step_valid(s', step, tid)\n    requires s'' == asf.step_next(s', step, tid)\n    requires !Armada_ThreadYielding(asf, s'', tid)\n    requires !is_recurrent_pc(asf.get_thread_pc(s'', tid).v)\n    ensures  Armada_NextMultipleSteps(asf, s, s'', steps + [step], tid)\n    ensures  StepsEndNonyieldingNonrecurrent(asf, is_recurrent_pc, s, s'', steps + [step], tid);\n  {\n    if |steps| > 0 {\n      var s_next := asf.step_next(s, steps[0], tid);\n      lemma_ExtendStepsEndNonyieldingNonrecurrent(asf, is_recurrent_pc, s_next, s', s'', steps[1..], step, tid);\n      var all_steps := steps + [step];\n      assert all_steps[0] == steps[0];\n      assert all_steps[1..] == steps[1..] + [step];\n      assert StepsEndNonyieldingNonrecurrent(asf, is_recurrent_pc, s_next, s'', all_steps[1..], tid);\n      assert StepsEndNonyieldingNonrecurrent(asf, is_recurrent_pc, s, s'', all_steps, tid);\n    }\n  }\n\n  lemma lemma_IfStepsEndNonyieldingNonrecurrentThenShiftedTheyStartNonyielding<State, OneStep, PC>(\n    asf: Armada_SpecFunctions<State, OneStep, PC>,\n    is_recurrent_pc: PC->bool,\n    s: State,\n    s': State,\n    s'': State,\n    steps: seq<OneStep>,\n    step: OneStep,\n    tid: Armada_ThreadHandle\n    )\n    requires Armada_NextMultipleSteps(asf, s, s', steps, tid)\n    requires StepsEndNonyieldingNonrecurrent(asf, is_recurrent_pc, s, s', steps, tid)\n    requires !asf.is_step_tau(step)\n    requires asf.step_valid(s', step, tid)\n    requires s'' == asf.step_next(s', step, tid)\n    ensures  var new_steps := steps + [step];\n             StepsStartNonyieldingNonrecurrent(asf, is_recurrent_pc, asf.step_next(s, new_steps[0], tid), s'', new_steps[1..], tid)\n  {\n    if |steps| == 0 {\n      return;\n    }\n\n    var s_next := asf.step_next(s, steps[0], tid);\n    lemma_IfStepsEndNonyieldingNonrecurrentThenShiftedTheyStartNonyielding(asf, is_recurrent_pc, s_next, s', s'', steps[1..], step, tid);\n    var new_steps := steps + [step];\n    assert new_steps[0] == steps[0];\n    assert new_steps[1..] == steps[1..] + [step];\n  }\n\n  lemma lemma_ExtendAtomicValidPathSequence<State, Path, PC>(\n    asf: AtomicSpecFunctions<State, Path, PC>,\n    s: State,\n    s': State,\n    s'': State,\n    rrs: seq<Path>,\n    rr: Path,\n    tid: Armada_ThreadHandle\n    )\n    requires AtomicValidPathSequence(asf, s, rrs, tid)\n    requires s' == AtomicGetStateAfterPaths(asf, s, rrs, tid)\n    requires asf.path_valid(s', rr, tid)\n    requires s'' == asf.path_next(s', rr, tid)\n    requires asf.path_type(rr).AtomicPathType_RR?\n    ensures  AtomicValidPathSequence(asf, s, rrs + [rr], tid)\n    ensures  s'' == AtomicGetStateAfterPaths(asf, s, rrs + [rr], tid)\n  {\n    if |rrs| > 0 {\n      var s_next := asf.path_next(s, rrs[0], tid);\n      lemma_ExtendAtomicValidPathSequence(asf, s_next, s', s'', rrs[1..], rr, tid);\n      assert (rrs + [rr])[0] == rrs[0];\n      assert (rrs + [rr])[1..] == rrs[1..] + [rr];\n    }\n  }\n\n  lemma lemma_LiftMultistepToAtomicGivenYRRRs<State(!new), OneStep(!new), Path(!new), PC(!new)>(\n    lasf: Armada_SpecFunctions<State, OneStep, PC>,\n    hasf: AtomicSpecFunctions<State, Path, PC>,\n    is_recurrent_pc: PC->bool,\n    s: State,\n    s': State,\n    steps: seq<OneStep>,\n    tid: Armada_ThreadHandle,\n    pos_after_rrs: int,\n    pos_mid: int,\n    yr: Path,\n    rrs: seq<Path>,\n    state_after_yr: State,\n    state_after_rrs: State,\n    s_mid: State\n    ) returns (\n    entry: AtomicTraceEntry<Path>\n    )\n    requires RequirementsForLiftingToAtomic(lasf, hasf, is_recurrent_pc)\n    requires 0 <= pos_after_rrs <= pos_mid < |steps|\n    requires hasf.path_type(yr).AtomicPathType_YR?\n    requires state_after_yr == hasf.path_next(s, yr, tid)\n    requires state_after_rrs == AtomicGetStateAfterPaths(hasf, state_after_yr, rrs, tid)\n    requires hasf.path_valid(s, yr, tid)\n    requires AtomicValidPathSequence(hasf, state_after_yr, rrs, tid)\n    requires Armada_NextMultipleSteps(lasf, state_after_rrs, s_mid, steps[pos_after_rrs..pos_mid], tid)\n    requires Armada_NextMultipleSteps(lasf, s_mid, s', steps[pos_mid..], tid)\n    requires StepsEndNonyieldingNonrecurrent(lasf, is_recurrent_pc, state_after_rrs, s_mid, steps[pos_after_rrs..pos_mid], tid)\n    requires Armada_NextMultipleSteps(lasf, state_after_rrs, s', steps[pos_after_rrs..], tid)\n    requires Armada_StepsStartNonyielding(lasf, s_mid, s', steps[pos_mid..], tid)\n    requires Armada_NextMultipleSteps(lasf, s_mid, s', steps[pos_mid..], tid)\n    requires Armada_StepsStartNonyielding(lasf, s_mid, s', steps[pos_mid..], tid)\n    requires !Armada_ThreadYielding(lasf, state_after_rrs, tid)\n    requires is_recurrent_pc(lasf.get_thread_pc(state_after_rrs, tid).v)\n    requires Armada_ThreadYielding(lasf, s', tid)\n    ensures  AtomicNext(hasf, s, s', entry)\n    decreases |steps| - pos_mid\n  {\n    var s_next := lasf.step_next(s_mid, steps[pos_mid], tid);\n    if pos_mid == |steps|-1 {\n      assert s_next == s';\n      lemma_IfStepsEndNonyieldingNonrecurrentThenShiftedTheyStartNonyielding(lasf, is_recurrent_pc, state_after_rrs, s_mid, s_next,\n                                                                             steps[pos_after_rrs..pos_mid], steps[pos_mid], tid);\n      assert steps[pos_after_rrs..pos_mid] + [steps[pos_mid]] == steps[pos_after_rrs..];\n      assert SequencesCompressibleConditions(lasf, is_recurrent_pc, state_after_rrs, s', steps[pos_after_rrs..], tid);\n      var rx :| SequencesCompressibleConclusions(hasf, state_after_rrs, s', tid, rx);\n      entry := AtomicTraceEntry_Recurrent(tid, yr, rrs, rx);\n      assert AtomicValidRecursiveStep(hasf, s, tid, yr, rrs, rx);\n      return;\n    }\n\n    assert !Armada_ThreadYielding(lasf, s_next, tid);\n    assert steps[pos_after_rrs..pos_mid+1] == steps[pos_after_rrs..pos_mid] + [steps[pos_mid]];\n    var pc := lasf.get_thread_pc(s_next, tid).v;\n    if !is_recurrent_pc(pc) {\n      lemma_ExtendStepsEndNonyieldingNonrecurrent(lasf, is_recurrent_pc, state_after_rrs, s_mid, s_next, steps[pos_after_rrs..pos_mid],\n                                                  steps[pos_mid], tid);\n      entry := lemma_LiftMultistepToAtomicGivenYRRRs(lasf, hasf, is_recurrent_pc, s, s', steps, tid, pos_after_rrs, pos_mid + 1, yr, rrs,\n                                                     state_after_yr, state_after_rrs, s_next);\n      return;\n    }\n\n    lemma_ExtendArmadaNextMultipleSteps(lasf, state_after_rrs, s_mid, s_next, steps[pos_after_rrs..pos_mid], steps[pos_mid], tid);\n    lemma_IfStepsEndNonyieldingNonrecurrentThenShiftedTheyStartNonyielding(lasf, is_recurrent_pc, state_after_rrs, s_mid, s_next,\n                                                                           steps[pos_after_rrs..pos_mid], steps[pos_mid], tid);\n    assert SequencesCompressibleConditions(lasf, is_recurrent_pc, state_after_rrs, s_next, steps[pos_after_rrs..pos_mid+1], tid);\n    var rr :| SequencesCompressibleConclusions(hasf, state_after_rrs, s_next, tid, rr);\n    lemma_ExtendAtomicValidPathSequence(hasf, state_after_yr, state_after_rrs, s_next, rrs, rr, tid);\n    entry := lemma_LiftMultistepToAtomicGivenYRRRs(lasf, hasf, is_recurrent_pc, s, s', steps, tid,\n                                                   pos_mid + 1, pos_mid + 1, yr, rrs + [rr], state_after_yr, s_next, s_next);\n  }\n\n  lemma lemma_LiftMultistepToAtomicGivenInitialSteps<State(!new), OneStep(!new), Path(!new), PC(!new)>(\n    lasf: Armada_SpecFunctions<State, OneStep, PC>,\n    hasf: AtomicSpecFunctions<State, Path, PC>,\n    is_recurrent_pc: PC->bool,\n    s: State,\n    s': State,\n    steps: seq<OneStep>,\n    tid: Armada_ThreadHandle,\n    pos: int,\n    s_mid: State\n    ) returns (\n    entry: AtomicTraceEntry<Path>\n    )\n    requires RequirementsForLiftingToAtomic(lasf, hasf, is_recurrent_pc)\n    requires 0 <= pos < |steps|\n    requires Armada_NextMultipleSteps(lasf, s, s_mid, steps[..pos], tid)\n    requires Armada_NextMultipleSteps(lasf, s_mid, s', steps[pos..], tid)\n    requires !lasf.is_step_tau(steps[pos])\n    requires lasf.step_valid(s_mid, steps[pos], tid)\n    requires StepsEndNonyieldingNonrecurrent(lasf, is_recurrent_pc, s, s_mid, steps[..pos], tid)\n    requires Armada_StepsStartNonyielding(lasf, lasf.step_next(s_mid, steps[pos], tid), s', steps[pos+1..], tid)\n    requires Armada_ThreadYielding(lasf, s, tid)\n    requires Armada_ThreadYielding(lasf, s', tid)\n    ensures  AtomicNext(hasf, s, s', entry)\n    decreases |steps| - pos\n  {\n    var s_next := lasf.step_next(s_mid, steps[pos], tid);\n    if pos == |steps|-1 {\n      assert s_next == s';\n      lemma_IfStepsEndNonyieldingNonrecurrentThenShiftedTheyStartNonyielding(lasf, is_recurrent_pc, s, s_mid, s_next, steps[..pos],\n                                                                             steps[pos], tid);\n      assert steps == steps[..pos] + [steps[pos]];\n      assert SequencesCompressibleConditions(lasf, is_recurrent_pc, s, s', steps, tid);\n      var hpath :| SequencesCompressibleConclusions(hasf, s, s', tid, hpath);\n      entry := AtomicTraceEntry_Normal(tid, hpath);\n      return;\n    }\n\n    assert !Armada_ThreadYielding(lasf, s_next, tid);\n    assert steps[..pos+1] == steps[..pos] + [steps[pos]];\n    var pc := lasf.get_thread_pc(s_next, tid).v;\n    if !is_recurrent_pc(pc) {\n      lemma_ExtendStepsEndNonyieldingNonrecurrent(lasf, is_recurrent_pc, s, s_mid, s_next, steps[..pos], steps[pos], tid);\n      entry := lemma_LiftMultistepToAtomicGivenInitialSteps(lasf, hasf, is_recurrent_pc, s, s', steps, tid, pos + 1, s_next);\n      return;\n    }\n\n    lemma_ExtendArmadaNextMultipleSteps(lasf, s, s_mid, s_next, steps[..pos], steps[pos], tid);\n    lemma_IfStepsEndNonyieldingNonrecurrentThenShiftedTheyStartNonyielding(lasf, is_recurrent_pc, s, s_mid, s_next, steps[..pos],\n                                                                           steps[pos], tid);\n    assert steps[..pos] + [steps[pos]] == steps[..pos+1];\n    assert SequencesCompressibleConditions(lasf, is_recurrent_pc, s, s_next, steps[..pos+1], tid);\n    var yr :| SequencesCompressibleConclusions(hasf, s, s_next, tid, yr);\n    entry := lemma_LiftMultistepToAtomicGivenYRRRs(lasf, hasf, is_recurrent_pc, s, s', steps, tid,\n                                                   pos + 1, pos + 1, yr, [], s_next, s_next, s_next);\n  }\n\n  lemma lemma_LiftMultistepToAtomicRegular<State(!new), OneStep(!new), Path(!new), PC(!new)>(\n    lasf: Armada_SpecFunctions<State, OneStep, PC>,\n    hasf: AtomicSpecFunctions<State, Path, PC>,\n    is_recurrent_pc: PC->bool,\n    s: State,\n    s': State,\n    steps: seq<OneStep>,\n    tid: Armada_ThreadHandle\n    ) returns (\n    entry: AtomicTraceEntry<Path>\n    )\n    requires RequirementsForLiftingToAtomic(lasf, hasf, is_recurrent_pc)\n    requires |steps| > 0\n    requires !lasf.is_step_tau(steps[0])\n    requires Armada_ThreadYielding(lasf, s, tid)\n    requires Armada_ThreadYielding(lasf, s', tid)\n    requires Armada_NextMultipleSteps(lasf, s, s', steps, tid)\n    requires Armada_StepsStartNonyielding(lasf, lasf.step_next(s, steps[0], tid), s', steps[1..], tid)\n    ensures  AtomicNext(hasf, s, s', entry)\n  {\n    entry := lemma_LiftMultistepToAtomicGivenInitialSteps(lasf, hasf, is_recurrent_pc, s, s', steps, tid, 0, s);\n  }\n\n  lemma lemma_LiftMultistepToAtomic<State(!new), OneStep(!new), Path(!new), PC(!new)>(\n    lasf: Armada_SpecFunctions<State, OneStep, PC>,\n    hasf: AtomicSpecFunctions<State, Path, PC>,\n    is_recurrent_pc: PC->bool,\n    s: State,\n    s': State,\n    steps: seq<OneStep>,\n    tid: Armada_ThreadHandle,\n    tau: bool\n    ) returns (\n    entry: AtomicTraceEntry<Path>\n    )\n    requires RequirementsForLiftingToAtomic(lasf, hasf, is_recurrent_pc)\n    requires Armada_NextMultistep(lasf, s, s', steps, tid, tau)\n    ensures  AtomicNext(hasf, s, s', entry)\n  {\n    if |steps| == 0 {\n      entry := AtomicTraceEntry_Stutter();\n    }\n    else if tau {\n      assert Armada_NextMultipleSteps(lasf, lasf.step_next(s, steps[0], tid), s', steps[1..], tid);\n      assert TausLiftableConditions(lasf, s, s', steps[0], tid);\n      var hpath :| && hasf.path_valid(s, hpath, tid)\n                   && hasf.path_type(hpath).AtomicPathType_Tau? \n                   && s' == hasf.path_next(s, hpath, tid);\n      entry := AtomicTraceEntry_Tau(tid, hpath);\n    }\n    else {\n      entry := lemma_LiftMultistepToAtomicRegular(lasf, hasf, is_recurrent_pc, s, s', steps, tid);\n    }\n  }\n\n  lemma lemma_LiftToAtomic<State(!new), OneStep(!new), Path(!new), PC(!new)>(\n    lasf: Armada_SpecFunctions<State, OneStep, PC>,\n    hasf: AtomicSpecFunctions<State, Path, PC>,\n    is_recurrent_pc: PC->bool,\n    b: seq<State>\n    )\n    requires RequirementsForLiftingToAtomic(lasf, hasf, is_recurrent_pc)\n    requires BehaviorSatisfiesSpec(b, Armada_SpecFunctionsToSpec(lasf))\n    ensures  BehaviorSatisfiesSpec(b, AtomicSpec(hasf))\n    decreases |b|\n  {\n    forall pos | 0 <= pos < |b|-1\n      ensures StatePair(b[pos], b[pos+1]) in AtomicSpec(hasf).next\n    {\n      var s := b[pos];\n      var s' := b[pos+1];\n      assert StatePair(s, s') in Armada_SpecFunctionsToSpec(lasf).next;\n      var steps, tid, tau :| Armada_NextMultistep(lasf, s, s', steps, tid, tau);\n      var entry := lemma_LiftMultistepToAtomic(lasf, hasf, is_recurrent_pc, s, s', steps, tid, tau);\n    }\n  }\n\n  lemma lemma_SpecRefinesAtomicSpec<State(!new), OneStep(!new), Path(!new), PC(!new)>(\n    lasf: Armada_SpecFunctions<State, OneStep, PC>,\n    hasf: AtomicSpecFunctions<State, Path, PC>,\n    is_recurrent_pc: PC->bool\n    ) returns (\n    refinement_relation: RefinementRelation<State, State>\n    )\n    requires RequirementsForLiftingToAtomic(lasf, hasf, is_recurrent_pc)\n    ensures  SpecRefinesSpec(Armada_SpecFunctionsToSpec(lasf), AtomicSpec(hasf), refinement_relation)\n    ensures  refinement_relation == iset s: State | true :: RefinementPair(s, s)\n  {\n    refinement_relation := iset s: State | true :: RefinementPair(s, s);\n\n    forall lb | BehaviorSatisfiesSpec(lb, Armada_SpecFunctionsToSpec(lasf))\n      ensures exists hb :: BehaviorRefinesBehavior(lb, hb, refinement_relation) && BehaviorSatisfiesSpec(hb, AtomicSpec(hasf))\n    {\n      lemma_LiftToAtomic(lasf, hasf, is_recurrent_pc, lb);\n      lemma_IfRefinementRelationReflexiveThenBehaviorRefinesItself(lb, refinement_relation);\n      assert BehaviorRefinesBehavior(lb, lb, refinement_relation);\n      assert BehaviorSatisfiesSpec(lb, AtomicSpec(hasf));\n    }\n  }\n}\n"
  },
  {
    "path": "Armada/strategies/invariants.i.dfy",
    "content": "include \"refinement/AnnotatedBehavior.i.dfy\"\ninclude \"../spec/refinement.s.dfy\"\n\nmodule InvariantsModule\n{\n    import opened util_collections_seqs_s\n    import opened AnnotatedBehaviorModule\n    import opened GeneralRefinementModule\n\n    datatype StateActorPair<State, Actor> = StateActorPair(s:State, actor:Actor)\n\n    ////////////////////////////////////////\n    // INVARIANTS OF SPECS\n    ////////////////////////////////////////\n\n    function {:opaque} Reachables<State(!new)>(spec:Spec<State>) : iset<State>\n    {\n        iset b | BehaviorSatisfiesSpec(b, spec) :: last(b)\n    }\n\n    lemma lemma_ReachablesPremiumProperties<State(!new)>(\n        spec:Spec<State>\n        )\n        ensures var rs := Reachables(spec);\n                && (forall s {:trigger s in spec.init} {:trigger s in rs} ::\n                        s in spec.init ==> s in rs)\n                && (forall s, s' {:trigger s in rs, StatePair(s, s') in spec.next} ::\n                        s in rs && StatePair(s, s') in spec.next ==> s' in rs)\n                && (forall s' {:trigger s' in rs, s' in spec.init} ::\n                        s' in rs && s' !in spec.init ==>\n                        exists s :: s in rs && StatePair(s, s') in spec.next)\n                && (forall b, s {:trigger BehaviorSatisfiesSpec(b, spec), s in b}{:trigger BehaviorSatisfiesSpec(b, spec),s in rs} ::\n                        BehaviorSatisfiesSpec(b, spec) && s in b ==> s in rs);\n    {\n        reveal Reachables();\n        var rs := Reachables(spec);\n\n        forall s | s in spec.init\n            ensures s in rs;\n        {\n            var b := [s];\n            assert BehaviorSatisfiesSpec(b, spec);\n        }\n\n        forall s, s' | s in rs && StatePair(s, s') in spec.next\n            ensures s' in rs;\n        {\n            var b :| BehaviorSatisfiesSpec(b, spec) && s == last(b);\n            var b' := b + [s'];\n            assert BehaviorSatisfiesSpec(b', spec);\n        }\n\n        forall s' | s' in rs && s' !in spec.init\n            ensures exists s :: s in rs && StatePair(s, s') in spec.next;\n        {\n            var b :| BehaviorSatisfiesSpec(b, spec) && s' == last(b);\n            assert |b| > 1;\n            var b' := all_but_last(b);\n            assert BehaviorSatisfiesSpec(b', spec);\n            var s := last(b');\n            var penult := |b|-2;\n            assert s == b[penult];\n            assert s' == b[penult+1];\n            assert s in rs && StatePair(s, s') in spec.next;\n        }\n\n        forall b, s | BehaviorSatisfiesSpec(b, spec) && s in b\n            ensures s in rs;\n        {\n            var i :| 0 <= i < |b| && s == b[i];\n            var b' := b[..i+1];\n            assert BehaviorSatisfiesSpec(b', spec);\n            assert s == last(b');\n        }\n    }\n\n    function ReachablesPremium<State(!new)>(spec:Spec<State>) : (rs:iset<State>)\n        ensures rs == Reachables(spec)\n        ensures (forall s {:trigger s in spec.init} {:trigger s in rs} ::\n                        s in spec.init ==> s in rs);\n        ensures (forall s, s' {:trigger s in rs, StatePair(s, s') in spec.next} ::\n                        s in rs && StatePair(s, s') in spec.next ==> s' in rs);\n        ensures (forall s' {:trigger s' in rs, s' in spec.init} ::\n                        s' in rs && s' !in spec.init ==>\n                        exists s :: s in rs && StatePair(s, s') in spec.next);\n        ensures (forall b, s {:trigger BehaviorSatisfiesSpec(b, spec), s in b}{:trigger BehaviorSatisfiesSpec(b, spec), s in rs} ::\n                        BehaviorSatisfiesSpec(b, spec) && s in b ==> s in rs);\n    {\n        lemma_ReachablesPremiumProperties(spec);\n        Reachables(spec)\n    }\n\n    predicate IsSpecInvariant<State(!new)>(\n        inv:iset<State>,\n        spec:Spec<State>\n        )\n    {\n        Reachables(spec) <= inv\n    }\n\n    predicate ConditionsForSpecInvariance<State(!new)>(\n        inv:iset<State>,\n        spec:Spec<State>\n        )\n    {\n        && (forall s :: s in spec.init ==> s in inv)\n        && (forall s, s' :: s in inv && StatePair(s, s') in spec.next ==> s' in inv)\n    }\n\n    predicate ConditionsForSpecInvarianceDeduction<State(!new)>(\n        inv_unknown:iset<State>,\n        inv_known:iset<State>,\n        spec:Spec<State>\n        )\n    {\n        && (forall s :: s in spec.init ==> s in inv_unknown)\n        && (forall s, s' :: && s in inv_known\n                      && s in inv_unknown\n                      && StatePair(s, s') in spec.next\n                      ==> s' in inv_unknown)\n    }\n\n    predicate ConditionsForSpecInvarianceDeductionBeforeAndAfter<State(!new)>(\n        inv_unknown:iset<State>,\n        inv_known:iset<State>,\n        spec:Spec<State>\n        )\n    {\n        && (forall s :: s in spec.init ==> s in inv_unknown)\n        && (forall s, s' :: && s in inv_known\n                      && s' in inv_known\n                      && s in inv_unknown\n                      && StatePair(s, s') in spec.next\n                      ==> s' in inv_unknown)\n    }\n\n    function ExtendSpecWithInvariant<State(!new)>(spec:Spec<State>, inv:iset<State>) : Spec<State>\n    {\n        Spec(spec.init, iset s, s' | StatePair(s, s') in spec.next && s in inv :: StatePair(s, s'))\n    }\n\n    lemma lemma_EstablishSpecInvariantPure<State(!new)>(\n        inv:iset<State>,\n        spec:Spec<State>\n        )\n        requires ConditionsForSpecInvariance(inv, spec)\n        ensures  IsSpecInvariant(inv, spec)\n    {\n        var rs := Reachables(spec);\n        reveal Reachables();\n\n        forall r | r in rs\n            ensures r in inv;\n        {\n            var b :| BehaviorSatisfiesSpec(b, spec) && last(b) == r;\n            assert b[0] in spec.init;\n            var i := 0;\n            while i < |b|-1\n                invariant 0 <= i < |b|;\n                invariant b[i] in inv;\n            {\n                assert b[i] in inv;\n                assert StatePair(b[i], b[i+1]) in spec.next;\n                assert b[i+1] in inv;\n                i := i + 1;\n            }\n            assert i == |b|-1;\n            assert b[i] == r;\n        }\n    }\n\n    lemma lemma_EstablishSpecInvariantUsingInvariant<State(!new)>(\n        inv_unknown:iset<State>,\n        inv_known:iset<State>,\n        spec:Spec<State>\n        )\n        requires IsSpecInvariant(inv_known, spec)\n        requires ConditionsForSpecInvarianceDeduction(inv_unknown, inv_known, spec)\n        ensures  IsSpecInvariant(inv_unknown, spec)\n    {\n        var rs := Reachables(spec);\n        reveal Reachables();\n\n        forall r | r in rs\n            ensures r in inv_unknown;\n        {\n            var b :| BehaviorSatisfiesSpec(b, spec) && last(b) == r;\n            var i := 0;\n            while i < |b|-1\n                invariant 0 <= i < |b|;\n                invariant b[i] in inv_unknown;\n            {\n                assert BehaviorSatisfiesSpec(b[..i+1], spec);\n                assert StatePair(b[i], b[i+1]) in spec.next;\n                i := i + 1;\n            }\n            assert i == |b|-1;\n            assert b[i] == r;\n        }\n    }\n\n    lemma lemma_EstablishSpecInvariantUsingInvariantBeforeAndAfter<State(!new)>(\n        inv_unknown:iset<State>,\n        inv_known:iset<State>,\n        spec:Spec<State>\n        )\n        requires IsSpecInvariant(inv_known, spec)\n        requires ConditionsForSpecInvarianceDeductionBeforeAndAfter(inv_unknown, inv_known, spec)\n        ensures  IsSpecInvariant(inv_unknown, spec)\n    {\n        var rs := Reachables(spec);\n        reveal Reachables();\n\n        forall r | r in rs\n            ensures r in inv_unknown;\n        {\n            var b :| BehaviorSatisfiesSpec(b, spec) && last(b) == r;\n            var i := 0;\n            while i < |b|-1\n                invariant 0 <= i < |b|;\n                invariant b[i] in inv_unknown;\n            {\n                assert BehaviorSatisfiesSpec(b[..i+1], spec);\n                assert BehaviorSatisfiesSpec(b[..i+1+1], spec);\n                assert StatePair(b[i], b[i+1]) in spec.next;\n                i := i + 1;\n            }\n            assert i == |b|-1;\n            assert b[i] == r;\n        }\n    }\n\n    lemma lemma_SpecInvariantHoldsAtStart<State(!new)>(\n        s:State,\n        spec:Spec<State>,\n        inv:iset<State>\n        )\n        requires s in spec.init\n        requires IsSpecInvariant(inv, spec)\n        ensures  s in inv\n    {\n        var rs := ReachablesPremium(spec);\n    }\n\n    lemma lemma_SpecInvariantHoldsAtStep<State(!new)>(\n        b:seq<State>,\n        t:int,\n        spec:Spec<State>,\n        inv:iset<State>\n        )\n        requires BehaviorSatisfiesSpec(b, spec)\n        requires 0 <= t < |b|\n        requires IsSpecInvariant(inv, spec)\n        ensures  b[t] in inv\n    {\n        reveal Reachables();\n        var b' := b[..t+1];\n        assert BehaviorSatisfiesSpec(b', spec);\n    }\n\n    lemma lemma_ReachablesSatisfyConditionsForSpecInvariance<State(!new)>(\n        spec:Spec<State>\n        )\n        ensures ConditionsForSpecInvariance(Reachables(spec), spec);\n    {\n        var rs := ReachablesPremium(spec);\n    }\n\n    lemma lemma_ExtendingSpecWithInvariantProducesEquivalentSpec<State(!new)>(\n        spec:Spec<State>,\n        inv:iset<State>,\n        b:seq<State>\n        )\n        requires IsSpecInvariant(inv, spec)\n        ensures  BehaviorSatisfiesSpec(b, spec) <==> BehaviorSatisfiesSpec(b, ExtendSpecWithInvariant(spec, inv))\n    {\n        var espec := ExtendSpecWithInvariant(spec, inv);\n\n        if BehaviorSatisfiesSpec(b, spec) {\n            lemma_ReachablesPremiumProperties(spec);\n            assert BehaviorSatisfiesSpec(b, espec);\n        }\n\n        if BehaviorSatisfiesSpec(b, espec) {\n            forall i | 0 <= i < |b|-1\n                ensures StatePair(b[i], b[i+1]) in espec.next\n            {\n            }\n            assert BehaviorSatisfiesSpec(b, spec);\n        }\n    }\n\n    ////////////////////////////////////////\n    // INVARIANTS OF ANNOTATED SPECS\n    ////////////////////////////////////////\n\n    function {:opaque} AnnotatedReachables<State(!new), Step(!new)>(spec:AnnotatedBehaviorSpec<State, Step>) : iset<State>\n    {\n        iset ab | AnnotatedBehaviorSatisfiesSpec(ab, spec) :: last(ab.states)\n    }\n\n    lemma lemma_AnnotatedReachablesPremiumProperties<State(!new), Step(!new)>(\n        spec:AnnotatedBehaviorSpec<State, Step>\n        )\n        ensures var rs := AnnotatedReachables(spec);\n                && (forall s {:trigger s in spec.init} {:trigger s in rs} ::\n                        s in spec.init ==> s in rs)\n                && (forall s, s', step {:trigger s in rs, ActionTuple(s, s', step) in spec.next} ::\n                        s in rs && ActionTuple(s, s', step) in spec.next ==> s' in rs)\n                && (forall s' {:trigger s' in rs, s' in spec.init} ::\n                        s' in rs && s' !in spec.init ==>\n                        exists s, step :: s in rs && ActionTuple(s, s', step) in spec.next)\n                && (forall ab, s {:trigger AnnotatedBehaviorSatisfiesSpec(ab, spec), s in ab.states}\n\t\t\t\t                 {:trigger AnnotatedBehaviorSatisfiesSpec(ab, spec), s in rs} ::\n                        AnnotatedBehaviorSatisfiesSpec(ab, spec) && s in ab.states ==> s in rs);\n    {\n        reveal AnnotatedReachables();\n        var rs := AnnotatedReachables(spec);\n\n        forall s | s in spec.init\n            ensures s in rs;\n        {\n            var ab := AnnotatedBehavior([s], []);\n            assert AnnotatedBehaviorSatisfiesSpec(ab, spec);\n        }\n\n        forall s, s', step | s in rs && ActionTuple(s, s', step) in spec.next\n            ensures s' in rs;\n        {\n            var ab :| AnnotatedBehaviorSatisfiesSpec(ab, spec) && s == last(ab.states);\n            var ab' := AnnotatedBehavior(ab.states + [s'], ab.trace + [step]);\n            assert AnnotatedBehaviorSatisfiesSpec(ab', spec);\n        }\n\n        forall s' | s' in rs && s' !in spec.init\n            ensures exists s, step :: s in rs && ActionTuple(s, s', step) in spec.next;\n        {\n            var ab :| AnnotatedBehaviorSatisfiesSpec(ab, spec) && s' == last(ab.states);\n            assert |ab.states| > 1;\n            var ab' := AnnotatedBehavior(all_but_last(ab.states), all_but_last(ab.trace));\n            assert AnnotatedBehaviorSatisfiesSpec(ab', spec);\n            var s := last(ab'.states);\n            var penult := |ab.states|-2;\n            var step := ab.trace[penult];\n            assert s == ab.states[penult];\n            assert s' == ab.states[penult+1];\n            assert s in rs && ActionTuple(s, s', step) in spec.next;\n        }\n\n        forall ab, s | AnnotatedBehaviorSatisfiesSpec(ab, spec) && s in ab.states\n            ensures s in rs;\n        {\n            var i :| 0 <= i < |ab.states| && s == ab.states[i];\n            var ab' := AnnotatedBehavior(ab.states[..i+1], ab.trace[..i]);\n            assert AnnotatedBehaviorSatisfiesSpec(ab', spec);\n            assert s == last(ab'.states);\n        }\n    }\n\n    function AnnotatedReachablesPremium<State(!new), Step(!new)>(\n        spec:AnnotatedBehaviorSpec<State, Step>\n        ) : (rs:iset<State>)\n        ensures rs == AnnotatedReachables(spec)\n        ensures forall s {:trigger s in spec.init} {:trigger s in rs} ::\n                        s in spec.init ==> s in rs;\n        ensures forall s, s', step {:trigger s in rs, ActionTuple(s, s', step) in spec.next} ::\n                        s in rs && ActionTuple(s, s', step) in spec.next ==> s' in rs;\n        ensures forall s' {:trigger s' in rs, s' in spec.init} ::\n                        s' in rs && !(s' in spec.init) ==>\n                        exists s, step :: s in rs && ActionTuple(s, s', step) in spec.next;\n        ensures forall ab, s {:trigger AnnotatedBehaviorSatisfiesSpec(ab, spec), s in ab.states}\n                             {:trigger AnnotatedBehaviorSatisfiesSpec(ab, spec), s in rs} ::\n                        AnnotatedBehaviorSatisfiesSpec(ab, spec) && s in ab.states ==> s in rs;\n    {\n        lemma_AnnotatedReachablesPremiumProperties(spec);\n        AnnotatedReachables(spec)\n    }\n\n    lemma lemma_InitStateInAnnotatedReachables<State(!new), Step(!new)>(\n        s:State,\n        spec:AnnotatedBehaviorSpec<State, Step>\n        )\n        requires s in spec.init\n        ensures  s in AnnotatedReachables(spec)\n    {\n        assert AnnotatedReachables(spec) == AnnotatedReachablesPremium(spec);\n    }\n\n    lemma lemma_NextMaintainsAnnotatedReachables<State(!new), Step(!new)>(\n        s:State,\n        s':State,\n        step:Step,\n        spec:AnnotatedBehaviorSpec<State, Step>\n        )\n        requires s in AnnotatedReachables(spec)\n        requires ActionTuple(s, s', step) in spec.next\n        ensures  s' in AnnotatedReachables(spec)\n    {\n        assert AnnotatedReachables(spec) == AnnotatedReachablesPremium(spec);\n    }\n\n    lemma lemma_StateNextSeqMaintainsAnnotatedReachables<State(!new), Step(!new)>(\n        states:seq<State>,\n        trace:seq<Step>,\n        spec:AnnotatedBehaviorSpec<State, Step>\n        )\n        requires StateNextSeq(states, trace, spec.next)\n        requires states[0] in AnnotatedReachables(spec)\n        ensures  forall s :: s in states ==> s in AnnotatedReachables(spec)\n    {\n        var pos := 0;\n        while pos < |states|-1\n            invariant 0 <= pos < |states|\n            invariant forall i :: 0 <= i <= pos ==> states[i] in AnnotatedReachables(spec)\n        {\n            assert states[pos] in AnnotatedReachables(spec);\n            lemma_NextMaintainsAnnotatedReachables(states[pos], states[pos+1], trace[pos], spec);\n            pos := pos + 1;\n        }\n    }\n\n    predicate IsInvariantOfSpec<State(!new), Step(!new)>(\n        inv:iset<State>,\n        spec:AnnotatedBehaviorSpec<State, Step>\n        )\n    {\n        AnnotatedReachables(spec) <= inv\n    }\n\n    predicate ConditionsForInvariance<State(!new), Step(!new)>(\n        inv:iset<State>,\n        spec:AnnotatedBehaviorSpec<State, Step>\n        )\n    {\n        && (forall s :: s in spec.init ==> s in inv)\n        && (forall s, s', step :: s in inv && ActionTuple(s, s', step) in spec.next ==> s' in inv)\n    }\n\n    predicate ConditionsForInvarianceDeduction<State(!new), Step(!new)>(\n        inv_unknown:iset<State>,\n        inv_known:iset<State>,\n        spec:AnnotatedBehaviorSpec<State, Step>\n        )\n    {\n        && (forall s :: s in spec.init ==> s in inv_unknown)\n        && (forall s, s', step :: && s in inv_known\n                                   && s in inv_unknown\n                                   && ActionTuple(s, s', step) in spec.next\n                                   ==> s' in inv_unknown)\n    }\n\n    predicate ConditionsForInvarianceDeductionBeforeAndAfter<State(!new), Step(!new)>(\n        inv_unknown:iset<State>,\n        inv_known:iset<State>,\n        spec:AnnotatedBehaviorSpec<State, Step>\n        )\n    {\n        && (forall s :: s in spec.init ==> s in inv_unknown)\n        && (forall s, s', step :: && s in inv_known\n                                   && s' in inv_known\n                                   && s in inv_unknown\n                                   && ActionTuple(s, s', step) in spec.next\n                                   ==> s' in inv_unknown)\n    }\n\n    function ExtendAnnotatedBehaviorSpecWithInvariant<State(!new), Step(!new)>(\n        spec:AnnotatedBehaviorSpec<State, Step>,\n        inv:iset<State>\n        ) : AnnotatedBehaviorSpec<State, Step>\n    {\n        AnnotatedBehaviorSpec(spec.init,\n                              iset s, s', step | ActionTuple(s, s', step) in spec.next && s in inv\n                                                      :: ActionTuple(s, s', step))\n    }\n\n    lemma lemma_EstablishInvariantPure<State(!new), Step(!new)>(\n        inv:iset<State>,\n        spec:AnnotatedBehaviorSpec<State, Step>\n        )\n        requires ConditionsForInvariance(inv, spec)\n        ensures  IsInvariantOfSpec(inv, spec)\n    {\n        var rs := AnnotatedReachables(spec);\n        reveal AnnotatedReachables();\n\n        forall r | r in rs\n            ensures r in inv;\n        {\n            var ab :| AnnotatedBehaviorSatisfiesSpec(ab, spec) && last(ab.states) == r;\n            assert ab.states[0] in spec.init;\n            var i := 0;\n            while i < |ab.states|-1\n                invariant 0 <= i < |ab.states|;\n                invariant ab.states[i] in inv;\n            {\n                assert ab.states[i] in inv;\n                assert ActionTuple(ab.states[i], ab.states[i+1], ab.trace[i]) in spec.next;\n                assert ab.states[i+1] in inv;\n                i := i + 1;\n            }\n            assert i == |ab.states|-1;\n            assert ab.states[i] == r;\n        }\n    }\n\n    lemma lemma_EstablishInvariantUsingInvariant<State(!new), Step(!new)>(\n        inv_unknown:iset<State>,\n        inv_known:iset<State>,\n        spec:AnnotatedBehaviorSpec<State, Step>\n        )\n        requires IsInvariantOfSpec(inv_known, spec)\n        requires ConditionsForInvarianceDeduction(inv_unknown, inv_known, spec)\n        ensures  IsInvariantOfSpec(inv_unknown, spec)\n    {\n        var rs := AnnotatedReachables(spec);\n        reveal AnnotatedReachables();\n\n        forall r | r in rs\n            ensures r in inv_unknown;\n        {\n            var ab :| AnnotatedBehaviorSatisfiesSpec(ab, spec) && last(ab.states) == r;\n            var i := 0;\n            while i < |ab.states|-1\n                invariant 0 <= i < |ab.states|;\n                invariant ab.states[i] in inv_unknown;\n            {\n                assert AnnotatedBehaviorSatisfiesSpec(AnnotatedBehavior(ab.states[..i+1], ab.trace[..i]), spec);\n                assert ActionTuple(ab.states[i], ab.states[i+1], ab.trace[i]) in spec.next;\n                i := i + 1;\n            }\n            assert i == |ab.states|-1;\n            assert ab.states[i] == r;\n        }\n    }\n\n    lemma lemma_EstablishInvariantUsingInvariantBeforeAndAfter<State(!new), Step(!new)>(\n        inv_unknown:iset<State>,\n        inv_known:iset<State>,\n        spec:AnnotatedBehaviorSpec<State, Step>\n        )\n        requires IsInvariantOfSpec(inv_known, spec)\n        requires ConditionsForInvarianceDeductionBeforeAndAfter(inv_unknown, inv_known, spec)\n        ensures  IsInvariantOfSpec(inv_unknown, spec)\n    {\n        var rs := AnnotatedReachables(spec);\n        reveal AnnotatedReachables();\n\n        forall r | r in rs\n            ensures r in inv_unknown;\n        {\n            var ab :| AnnotatedBehaviorSatisfiesSpec(ab, spec) && last(ab.states) == r;\n            var i := 0;\n            while i < |ab.states|-1\n                invariant 0 <= i < |ab.states|;\n                invariant ab.states[i] in inv_unknown;\n            {\n                assert AnnotatedBehaviorSatisfiesSpec(AnnotatedBehavior(ab.states[..i+1], ab.trace[..i]), spec);\n                assert AnnotatedBehaviorSatisfiesSpec(AnnotatedBehavior(ab.states[..i+1+1], ab.trace[..i+1]), spec);\n                assert ActionTuple(ab.states[i], ab.states[i+1], ab.trace[i]) in spec.next;\n                i := i + 1;\n            }\n            assert i == |ab.states|-1;\n            assert ab.states[i] == r;\n        }\n    }\n\n    lemma lemma_InvariantHoldsAtStart<State(!new), Step(!new)>(\n        s:State,\n        spec:AnnotatedBehaviorSpec<State, Step>,\n        inv:iset<State>\n        )\n        requires s in spec.init\n        requires IsInvariantOfSpec(inv, spec)\n        ensures  s in inv\n    {\n        var rs := AnnotatedReachablesPremium(spec);\n    }\n\n    lemma lemma_InvariantHoldsAtStep<State(!new), Step(!new)>(\n        ab:AnnotatedBehavior<State, Step>,\n        t:int,\n        spec:AnnotatedBehaviorSpec<State, Step>,\n        inv:iset<State>\n        )\n        requires AnnotatedBehaviorSatisfiesSpec(ab, spec)\n        requires 0 <= t < |ab.states|\n        requires IsInvariantOfSpec(inv, spec)\n        ensures  ab.states[t] in inv\n    {\n        reveal AnnotatedReachables();\n        var ab' := AnnotatedBehavior(ab.states[..t+1], ab.trace[..t]);\n        assert AnnotatedBehaviorSatisfiesSpec(ab', spec);\n    }\n\n    lemma lemma_AnnotatedReachablesSatisfyConditionsForInvariance<State(!new), Step(!new)>(\n        spec:AnnotatedBehaviorSpec<State, Step>\n        )\n        ensures ConditionsForInvariance(AnnotatedReachables(spec), spec);\n    {\n        var rs := AnnotatedReachablesPremium(spec);\n    }\n\n    lemma lemma_ConditionsForInvarianceTransferAcrossStateNextSeq<State(!new), Step(!new)>(\n        states:seq<State>,\n        trace:seq<Step>,\n        spec:AnnotatedBehaviorSpec<State, Step>,\n        inv:iset<State>\n        )\n        requires ConditionsForInvariance(inv, spec)\n        requires StateNextSeq(states, trace, spec.next)\n        requires states[0] in inv\n        ensures  forall s :: s in states ==> s in inv\n    {\n        var j := 1;\n        while j < |states|\n            invariant 0 <= j <= |states|;\n            invariant forall i :: 0 <= i < j ==> states[i] in inv;\n        {\n            var prev := j-1;\n            assert ActionTuple(states[prev], states[prev+1], trace[prev]) in spec.next;\n            j := j + 1;\n        }\n    }\n\n    lemma lemma_ConjunctionOfInvariantsIsInvariant<State(!new), Step(!new)>(\n        spec:AnnotatedBehaviorSpec<State, Step>,\n        invs:seq<State->bool>,\n        aggregate_inv:State->bool\n        )\n        requires forall inv :: inv in invs ==> IsInvariantPredicateOfSpec(inv, spec)\n        requires forall s :: (forall inv :: inv in invs ==> inv(s)) ==> aggregate_inv(s)\n        ensures  IsInvariantPredicateOfSpec(aggregate_inv, spec)\n    {\n    }\n\n    lemma lemma_ExtendingAnnotatedSpecWithInvariantProducesEquivalentSpec<State(!new), Step(!new)>(\n        spec:AnnotatedBehaviorSpec<State, Step>,\n        inv:iset<State>,\n        ab:AnnotatedBehavior<State, Step>\n        )\n        requires IsInvariantOfSpec(inv, spec)\n        ensures  AnnotatedBehaviorSatisfiesSpec(ab, spec) <==>\n                 AnnotatedBehaviorSatisfiesSpec(ab, ExtendAnnotatedBehaviorSpecWithInvariant(spec, inv))\n    {\n        var espec := ExtendAnnotatedBehaviorSpecWithInvariant(spec, inv);\n\n        if AnnotatedBehaviorSatisfiesSpec(ab, spec) {\n            lemma_AnnotatedReachablesPremiumProperties(spec);\n            assert AnnotatedBehaviorSatisfiesSpec(ab, espec);\n        }\n\n        if AnnotatedBehaviorSatisfiesSpec(ab, espec) {\n            forall i | 0 <= i < |ab.trace|\n                ensures ActionTuple(ab.states[i], ab.states[i+1], ab.trace[i]) in espec.next\n            {\n            }\n            assert AnnotatedBehaviorSatisfiesSpec(ab, spec);\n        }\n    }\n\n    predicate IsInvariantPredicateOfSpec<State(!new), Step(!new)>(\n        inv:State->bool,\n        spec:AnnotatedBehaviorSpec<State, Step>\n        )\n    {\n        forall s :: s in AnnotatedReachables(spec) ==> inv(s)\n    }\n\n    predicate ConditionsForInvariancePredicate<State(!new), Step(!new)>(\n        inv:State->bool,\n        spec:AnnotatedBehaviorSpec<State, Step>\n        )\n    {\n        && (forall s :: s in spec.init ==> inv(s))\n        && (forall s, s', step :: inv(s) && ActionTuple(s, s', step) in spec.next ==> inv(s'))\n    }\n\n    predicate ConditionsForInvariancePredicateDeduction<State(!new), Step(!new)>(\n        inv_unknown:State->bool,\n        inv_known:State->bool,\n        spec:AnnotatedBehaviorSpec<State, Step>\n        )\n    {\n        && (forall s :: s in spec.init ==> inv_unknown(s))\n        && (forall s, s', step :: && inv_known(s)\n                                   && inv_unknown(s)\n                                   && ActionTuple(s, s', step) in spec.next\n                                   ==> inv_unknown(s'))\n    }\n\n    predicate ConditionsForInvariancePredicateDeductionBeforeAndAfter<State(!new), Step(!new)>(\n        inv_unknown:State->bool,\n        inv_known:State->bool,\n        spec:AnnotatedBehaviorSpec<State, Step>\n        )\n    {\n        && (forall s :: s in spec.init ==> inv_unknown(s))\n        && (forall s, s', step :: && inv_known(s)\n                                   && inv_known(s')\n                                   && inv_unknown(s)\n                                   && ActionTuple(s, s', step) in spec.next\n                                   ==> inv_unknown(s'))\n    }\n\n    function ExtendAnnotatedBehaviorSpecWithInvariantPredicate<State(!new), Step(!new)>(\n        spec:AnnotatedBehaviorSpec<State, Step>,\n        inv:State->bool\n        ) : AnnotatedBehaviorSpec<State, Step>\n    {\n        AnnotatedBehaviorSpec(spec.init,\n                              iset s, s', step | ActionTuple(s, s', step) in spec.next && inv(s) :: ActionTuple(s, s', step))\n    }\n\n    lemma lemma_EstablishInvariantPredicatePure<State(!new), Step(!new)>(\n        inv:State->bool,\n        spec:AnnotatedBehaviorSpec<State, Step>\n        )\n        requires ConditionsForInvariancePredicate(inv, spec)\n        ensures  IsInvariantPredicateOfSpec(inv, spec)\n    {\n        var rs := AnnotatedReachables(spec);\n        reveal AnnotatedReachables();\n\n        forall r | r in rs\n            ensures inv(r);\n        {\n            var ab :| AnnotatedBehaviorSatisfiesSpec(ab, spec) && last(ab.states) == r;\n            assert ab.states[0] in spec.init;\n            var i := 0;\n            while i < |ab.states|-1\n                invariant 0 <= i < |ab.states|;\n                invariant inv(ab.states[i]);\n            {\n                assert inv(ab.states[i]);\n                assert ActionTuple(ab.states[i], ab.states[i+1], ab.trace[i]) in spec.next;\n                assert inv(ab.states[i+1]);\n                i := i + 1;\n            }\n            assert i == |ab.states|-1;\n            assert ab.states[i] == r;\n        }\n    }\n\n    lemma lemma_EstablishInvariantPredicateUsingInvariantPredicate<State(!new), Step(!new)>(\n        inv_unknown:State->bool,\n        inv_known:State->bool,\n        spec:AnnotatedBehaviorSpec<State, Step>\n        )\n        requires IsInvariantPredicateOfSpec(inv_known, spec)\n        requires ConditionsForInvariancePredicateDeduction(inv_unknown, inv_known, spec)\n        ensures  IsInvariantPredicateOfSpec(inv_unknown, spec)\n    {\n        var rs := AnnotatedReachables(spec);\n        reveal AnnotatedReachables();\n\n        forall r | r in rs\n            ensures inv_unknown(r);\n        {\n            var ab :| AnnotatedBehaviorSatisfiesSpec(ab, spec) && last(ab.states) == r;\n            var i := 0;\n            while i < |ab.states|-1\n                invariant 0 <= i < |ab.states|\n                invariant inv_unknown(ab.states[i])\n            {\n                lemma_InvariantPredicateHoldsAtStep(ab, i, spec, inv_known);\n                assert ActionTuple(ab.states[i], ab.states[i+1], ab.trace[i]) in spec.next;\n                assert inv_unknown(ab.states[i+1]);\n                i := i + 1;\n            }\n            assert i == |ab.states|-1;\n            assert ab.states[i] == r;\n        }\n    }\n\n    lemma lemma_EstablishInvariantPredicateUsingInvariantPredicateBeforeAndAfter<State(!new), Step(!new)>(\n        inv_unknown:State->bool,\n        inv_known:State->bool,\n        spec:AnnotatedBehaviorSpec<State, Step>\n        )\n        requires IsInvariantPredicateOfSpec(inv_known, spec)\n        requires ConditionsForInvariancePredicateDeductionBeforeAndAfter(inv_unknown, inv_known, spec)\n        ensures  IsInvariantPredicateOfSpec(inv_unknown, spec)\n    {\n        var rs := AnnotatedReachables(spec);\n        reveal AnnotatedReachables();\n\n        forall r | r in rs\n            ensures inv_unknown(r);\n        {\n            var ab :| AnnotatedBehaviorSatisfiesSpec(ab, spec) && last(ab.states) == r;\n            var i := 0;\n            while i < |ab.states|-1\n                invariant 0 <= i < |ab.states|\n                invariant inv_unknown(ab.states[i])\n            {\n                assert AnnotatedBehaviorSatisfiesSpec(AnnotatedBehavior(ab.states[..i+1], ab.trace[..i]), spec);\n                assert AnnotatedBehaviorSatisfiesSpec(AnnotatedBehavior(ab.states[..i+1+1], ab.trace[..i+1]), spec);\n                assert ActionTuple(ab.states[i], ab.states[i+1], ab.trace[i]) in spec.next;\n                i := i + 1;\n            }\n            assert i == |ab.states|-1;\n            assert ab.states[i] == r;\n        }\n    }\n\n    lemma lemma_InvariantPredicateHoldsAtStart<State(!new), Step(!new)>(\n        s:State,\n        spec:AnnotatedBehaviorSpec<State, Step>,\n        inv:State->bool\n        )\n        requires s in spec.init\n        requires IsInvariantPredicateOfSpec(inv, spec)\n        ensures  inv(s)\n    {\n        var rs := AnnotatedReachablesPremium(spec);\n    }\n\n    lemma lemma_InvariantPredicateHoldsAtStep<State(!new), Step(!new)>(\n        ab:AnnotatedBehavior<State, Step>,\n        t:int,\n        spec:AnnotatedBehaviorSpec<State, Step>,\n        inv:State->bool\n        )\n        requires AnnotatedBehaviorSatisfiesSpec(ab, spec)\n        requires 0 <= t < |ab.states|\n        requires IsInvariantPredicateOfSpec(inv, spec)\n        ensures  inv(ab.states[t])\n    {\n        reveal AnnotatedReachables();\n        var ab' := AnnotatedBehavior(ab.states[..t+1], ab.trace[..t]);\n        assert AnnotatedBehaviorSatisfiesSpec(ab', spec);\n    }\n\n    lemma lemma_ConditionsForInvariancePredicateTransferAcrossStateNextSeq<State(!new), Step(!new)>(\n        states:seq<State>,\n        trace:seq<Step>,\n        spec:AnnotatedBehaviorSpec<State, Step>,\n        inv:State->bool\n        )\n        requires ConditionsForInvariancePredicate(inv, spec)\n        requires StateNextSeq(states, trace, spec.next)\n        requires inv(states[0])\n        ensures  forall s :: s in states ==> inv(s)\n    {\n        var j := 1;\n        while j < |states|\n            invariant 0 <= j <= |states|;\n            invariant forall i :: 0 <= i < j ==> inv(states[i])\n        {\n            var prev := j-1;\n            assert ActionTuple(states[prev], states[prev+1], trace[prev]) in spec.next;\n            j := j + 1;\n        }\n    }\n\n    lemma lemma_ExtendingAnnotatedSpecWithInvariantPredicateProducesEquivalentSpec<State(!new), Step(!new)>(\n        spec:AnnotatedBehaviorSpec<State, Step>,\n        inv:State->bool,\n        ab:AnnotatedBehavior<State, Step>\n        )\n        requires IsInvariantPredicateOfSpec(inv, spec)\n        ensures  AnnotatedBehaviorSatisfiesSpec(ab, spec) <==>\n                 AnnotatedBehaviorSatisfiesSpec(ab, ExtendAnnotatedBehaviorSpecWithInvariantPredicate(spec, inv))\n    {\n        var espec := ExtendAnnotatedBehaviorSpecWithInvariantPredicate(spec, inv);\n\n        if AnnotatedBehaviorSatisfiesSpec(ab, spec) {\n            lemma_AnnotatedReachablesPremiumProperties(spec);\n            assert AnnotatedBehaviorSatisfiesSpec(ab, espec);\n        }\n\n        if AnnotatedBehaviorSatisfiesSpec(ab, espec) {\n            forall i | 0 <= i < |ab.trace|\n                ensures ActionTuple(ab.states[i], ab.states[i+1], ab.trace[i]) in espec.next\n            {\n            }\n            assert AnnotatedBehaviorSatisfiesSpec(ab, spec);\n        }\n    }\n\n    lemma lemma_StateInAnnotatedBehaviorInAnnotatedReachables<State(!new), Step(!new)>(\n        spec:AnnotatedBehaviorSpec<State, Step>,\n        ab:AnnotatedBehavior<State, Step>,\n        pos:int\n        )\n        requires AnnotatedBehaviorSatisfiesSpec(ab, spec)\n        requires 0 <= pos < |ab.states|\n        ensures  ab.states[pos] in AnnotatedReachables(spec)\n    {\n        assert AnnotatedReachables(spec) == AnnotatedReachablesPremium(spec);\n        lemma_StateNextSeqMaintainsAnnotatedReachables(ab.states, ab.trace, spec);\n        assert ab.states[pos] in ab.states;\n    }\n\n}\n"
  },
  {
    "path": "Armada/strategies/reduction/AtomicReduction.i.dfy",
    "content": "/////////////////////////////////////////////////////////////////////////////////////////////////////\n//\n// This file contains a lemma for performing refinement via a Cohen-Lamport reduction on an Armada\n// atomic behavior.  Such a reduction takes a behavior satisfying a low-level spec, which allows\n// threads to sometimes be in phase 1 or 2 between multisteps, and returns a behavior satisfying a\n// higher-level specification that only allows those phases in the middle of multisteps.  It does so\n// by lifting sequences of multisteps in the lower-level specification to single multisteps in the\n// higher-level specification.\n//\n// To use this lemma, first create a request r of type AtomicReductionRequest (defined in\n// AtomicReductionSpec.i.dfy).  Then, prove that it's a valid request, i.e., that\n// ValidAtomicReductionRequest(r).\n//\n// This lemma makes use of a lemma in another file (lemma_PerformRefinementViaReduction, in\n// RefinementViaReduction.i.dfy).  That lemma performs refinement via reduction for generic state\n// machines.\n//\n/////////////////////////////////////////////////////////////////////////////////////////////////////\n\ninclude \"AtomicReductionSpec.i.dfy\"\ninclude \"AtomicReductionLemmas.i.dfy\"\ninclude \"RefinementViaReduction.i.dfy\"\n\nmodule AtomicReductionModule {\n\n  import opened util_collections_seqs_s\n  import opened util_collections_seqs_i\n  import opened util_option_s\n  import opened GeneralRefinementModule\n  import opened GeneralRefinementLemmasModule\n  import opened RefinementConvolutionModule\n  import opened AnnotatedBehaviorModule\n  import opened InvariantsModule\n  import opened AtomicReductionSpecModule\n  import opened AtomicReductionLemmasModule\n  import opened RefinementViaReductionSpecModule\n  import opened RefinementViaReductionModule\n  import opened GenericArmadaSpecModule\n  import opened GenericArmadaAtomicModule\n  import opened ArmadaCommonDefinitions\n\n  lemma lemma_ReduceAtomicBehavior<LState(!new), LPath(!new), LPC(!new), HState(!new), HPath(!new), HPC(!new)>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    lb:AnnotatedBehavior<LState, AtomicTraceEntry<LPath>>\n    ) returns (\n    hb:AnnotatedBehavior<HState, AtomicTraceEntry<HPath>>\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires AnnotatedBehaviorSatisfiesSpec(lb, AtomicAnnotatedSpec(arr.l))\n    ensures  BehaviorRefinesBehavior(lb.states, hb.states, arr.relation)\n    ensures  AnnotatedBehaviorSatisfiesSpec(hb, AtomicAnnotatedSpec(arr.h))\n  {\n    var mb1 := lemma_IfBehaviorSatisfiesGenericSpecThenItSatisfiesRefinementViaReductionLSpec(arr, lb);\n\n    lemma_IfAtomicReductionRequestValidThenRefinementViaReductionRequestValid(arr);\n    var mb2 := lemma_PerformRefinementViaReduction(GetRefinementViaReductionRequest(arr), mb1);\n\n    var hstates := MapSeqToSeq(mb2.states, arr.lstate_to_hstate);\n    var htrace := MapSeqToSeq(mb2.trace, x => ConvertMultistepToAtomicTraceEntry(arr, x));\n    hb := AnnotatedBehavior(hstates, htrace);\n\n    var mh_map := ConvertMapToSeq(|hstates|, map i | 0 <= i < |hstates| :: RefinementRange(i, i));\n    var hspec := AtomicAnnotatedSpec(arr.h);\n    assert BehaviorRefinesBehaviorUsingRefinementMap(mb2.states, hb.states, arr.relation, mh_map);\n    forall i | 0 <= i < |htrace|\n      ensures ActionTuple(hstates[i], hstates[i+1], htrace[i]) in hspec.next\n    {\n      lemma_GenericNextReducedBehaviorSatisfiesInv(arr, mb2, i);\n      lemma_LHMaintainsNext(arr, mb2.states[i], mb2.states[i+1], mb2.trace[i], hstates[i], hstates[i+1], htrace[i]);\n    }\n    assert AnnotatedBehaviorSatisfiesSpec(hb, hspec);\n    lemma_RefinementConvolutionPure(lb.states, mb2.states, hb.states, arr.self_relation, arr.relation, arr.relation);\n  }\n\n  lemma lemma_PerformAtomicReduction<LState(!new), LPath(!new), LPC(!new), HState(!new), HPath(!new), HPC(!new)>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    )\n    requires ValidAtomicReductionRequest(arr)\n    ensures  SpecRefinesSpec(AtomicSpec(arr.l), AtomicSpec(arr.h), arr.relation)\n  {\n    var lspec := AtomicSpec(arr.l);\n    var hspec := AtomicSpec(arr.h);\n    forall lb | BehaviorSatisfiesSpec(lb, lspec)\n      ensures BehaviorRefinesSpec(lb, hspec, arr.relation)\n    {\n      var alb := lemma_AtomicBehaviorToAnnotatedBehavior(arr.l, lb);\n      var ahb := lemma_ReduceAtomicBehavior(arr, alb);\n      lemma_AtomicAnnotatedBehaviorSatisfiesAtomicSpec(arr.h, ahb);\n      assert BehaviorRefinesBehavior(lb, ahb.states, arr.relation) && BehaviorSatisfiesSpec(ahb.states, hspec);\n    }\n  }\n\n}\n"
  },
  {
    "path": "Armada/strategies/reduction/AtomicReductionLemmas.i.dfy",
    "content": "/////////////////////////////////////////////////////////////////////////////////////////////////////\n//\n// This file contains lemmas useful in effecting a refinement via reduction on an Armada atomic\n// behavior.  They support lemma_PerformAtomicReduction (in AtomicReduction.i.dfy).\n//\n// The general strategy is to show that the Armada atomic state machine, despite all its complexity\n// having to do with things like tau operations and recurrent trace entries, nevertheless satisfies\n// the conditions required by the more generic lemma_PerformRefinementViaReduction (in\n// RefinementViaReduction.i.dfy).  These conditions are satisfied by creating a\n// RefinementViaReductionRequest and proving that it satisfies ValidRefinementViaReductionRequest.\n//\n/////////////////////////////////////////////////////////////////////////////////////////////////////\n\ninclude \"AtomicReductionSpec.i.dfy\"\ninclude \"RefinementViaReductionSpec.i.dfy\"\ninclude \"../../util/collections/seqs.i.dfy\"\ninclude \"../generic/GenericArmadaLemmas.i.dfy\"\n\nmodule AtomicReductionLemmasModule {\n\n  import opened util_collections_seqs_s\n  import opened util_collections_seqs_i\n  import opened util_option_s\n  import opened GeneralRefinementModule\n  import opened GeneralRefinementLemmasModule\n  import opened RefinementConvolutionModule\n  import opened AnnotatedBehaviorModule\n  import opened InvariantsModule\n  import opened AtomicReductionSpecModule\n  import opened RefinementViaReductionSpecModule\n  import opened GenericArmadaSpecModule\n  import opened GenericArmadaLemmasModule\n  import opened GenericArmadaAtomicModule\n  import opened ArmadaCommonDefinitions\n\n  //////////////////////////////////////////////////////////\n  // FUNCTIONS FOR BUILDING CRASHING REDUCTION REQUEST\n  //////////////////////////////////////////////////////////\n\n  predicate IsNonyieldingOrInPhase<LState, LPath, LPC, HState, HPath, HPC>(\n    arr: AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    s: LState,\n    tid: Armada_ThreadHandle\n    )\n  {\n    var pc := arr.l.get_thread_pc(s, tid);\n    arr.l.state_ok(s) && pc.Some? && (arr.l.is_pc_nonyielding(pc.v) || arr.is_phase1(pc.v) || arr.is_phase2(pc.v))\n  }\n\n  predicate AtomicValidPathSequenceOfAnyType<State, Path, PC>(\n    asf: AtomicSpecFunctions<State, Path, PC>,\n    s: State,\n    paths: seq<Path>,\n    tid: Armada_ThreadHandle\n    )\n  {\n    |paths| > 0 ==>\n      && asf.path_valid(s, paths[0], tid)\n      && AtomicValidPathSequenceOfAnyType(asf, asf.path_next(s, paths[0], tid), paths[1..], tid)\n  }\n\n  predicate AtomicNextMultiplePaths<State, Path, PC>(\n    asf: AtomicSpecFunctions<State, Path, PC>,\n    s: State,\n    s': State,\n    paths: seq<Path>,\n    tid: Armada_ThreadHandle\n    )\n  {\n    && AtomicValidPathSequenceOfAnyType(asf, s, paths, tid)\n    && s' == AtomicGetStateAfterPaths(asf, s, paths, tid)\n  }\n    \n  function GetReducedAtomicSpecFunctions<LState, LPath, LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    ) : AtomicSpecFunctions<LState, LPath, LPC>\n  {\n    AtomicSpecFunctions(\n      arr.l.init,\n      arr.l.path_valid,\n      arr.l.path_next,\n      lpath => arr.h.path_type(arr.lpath_to_hpath(lpath)),\n      arr.l.state_ok,\n      arr.l.get_thread_pc,\n      lpc => arr.h.is_pc_nonyielding(arr.lpc_to_hpc(lpc))\n      )\n  }\n\n  predicate GenericNextReduced<LState, LPath, LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    s:LState,\n    s':LState,\n    paths:seq<LPath>,\n    tid:Armada_ThreadHandle,\n    tau:bool\n    )\n  {\n    && AtomicNextMultiplePaths(arr.l, s, s', paths, tid)\n    && (forall path :: path in paths ==> arr.l.path_type(path).AtomicPathType_Tau? == tau)\n    && if tau then |paths| <= 1 else |paths| > 0 ==> (\n        && !IsNonyieldingOrInPhase(arr, s, tid)\n        && !IsNonyieldingOrInPhase(arr, s', tid)\n        && (var states := AtomicGetStateSequence(arr.l, s, paths, tid);\n           forall i :: 0 < i < |paths| ==> IsNonyieldingOrInPhase(arr, states[i], tid))\n      )\n  }\n\n  predicate AtomicNextMultistep<State(!new), Path(!new), PC(!new)>(\n    asf:AtomicSpecFunctions<State, Path, PC>,\n    s:State,\n    s':State,\n    paths:seq<Path>,\n    tid:Armada_ThreadHandle,\n    tau:bool\n    )\n  {\n    && AtomicNextMultiplePaths(asf, s, s', paths, tid)\n    && (forall path :: path in paths ==> asf.path_type(path).AtomicPathType_Tau? == tau)\n    && if tau then |paths| <= 1 else |paths| > 0 ==> (\n        && AtomicThreadYielding(asf, s, tid)\n        && AtomicThreadYielding(asf, s', tid)\n        && (var states := AtomicGetStateSequence(asf, s, paths, tid);\n           forall i :: 0 < i < |paths| ==> !AtomicThreadYielding(asf, states[i], tid))\n      )\n  }\n\n  predicate RefinementViaReductionLSpecNext<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    s:LState,\n    s':LState,\n    multistep:Armada_Multistep<LPath>\n    )\n  {\n    AtomicNextMultistep(arr.l, s, s', multistep.steps, multistep.tid, multistep.tau)\n  }\n\n  function GetRefinementViaReductionLSpec<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    ) : AnnotatedBehaviorSpec<LState, Armada_Multistep<LPath>>\n  {\n    AnnotatedBehaviorSpec(\n      iset s | arr.l.init(s),\n      iset s, s', multistep | RefinementViaReductionLSpecNext(arr, s, s', multistep) :: ActionTuple(s, s', multistep))\n  }\n\n  predicate RefinementViaReductionHSpecNext<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    s:LState,\n    s':LState,\n    multistep:Armada_Multistep<LPath>\n    )\n  {\n    GenericNextReduced(arr, s, s', multistep.steps, multistep.tid, multistep.tau)\n  }\n\n  function GetRefinementViaReductionHSpec<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    ) : AnnotatedBehaviorSpec<LState, Armada_Multistep<LPath>>\n  {\n    AnnotatedBehaviorSpec(\n      iset s | arr.l.init(s),\n      iset s, s', multistep | RefinementViaReductionHSpecNext(arr, s, s', multistep) :: ActionTuple(s, s', multistep))\n  }\n\n  function RefinementViaReductionIdmap<LState, LPath(!new), LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    multistep:Armada_Multistep<LPath>\n    ) : Option<Armada_ThreadHandle>\n  {\n    if multistep.tau then None else Some(multistep.tid)\n  }\n\n  function GetRefinementViaReductionIdmap<LState, LPath(!new), LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    ) : Armada_Multistep<LPath>->Option<Armada_ThreadHandle>\n  {\n    multistep => RefinementViaReductionIdmap(arr, multistep)\n  }\n\n  predicate RefinementViaReductionPhase1<LState(!new), LPath, LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    s:LState,\n    tid:Option<Armada_ThreadHandle>\n    )\n  {\n    && tid.Some?\n    && var pc := arr.l.get_thread_pc(s, tid.v);\n      pc.Some? && arr.is_phase1(pc.v)\n  }\n\n  function GetRefinementViaReductionPhase1<LState(!new), LPath, LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    ) : (LState, Option<Armada_ThreadHandle>)->bool\n  {\n    (s:LState, tid:Option<Armada_ThreadHandle>) => RefinementViaReductionPhase1(arr, s, tid)\n  }\n\n  predicate RefinementViaReductionPhase2<LState(!new), LPath, LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    s:LState,\n    tid:Option<Armada_ThreadHandle>\n    )\n  {\n    && tid.Some?\n    && var pc := arr.l.get_thread_pc(s, tid.v);\n      pc.Some? && arr.is_phase2(pc.v)\n  }\n\n  function GetRefinementViaReductionPhase2<LState(!new), LPath, LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    ) : (LState, Option<Armada_ThreadHandle>)->bool\n  {\n    (s:LState, tid:Option<Armada_ThreadHandle>) => RefinementViaReductionPhase2(arr, s, tid)\n  }\n\n  function GetRefinementViaReductionCrashedPred<LState(!new), LPath, LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    ) : LState->bool\n  {\n    (s:LState) => !arr.l.state_ok(s)\n  }\n\n  function GetRefinementViaReductionRequest<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    ) : RefinementViaReductionRequest<LState, Option<Armada_ThreadHandle>, Armada_Multistep<LPath>, Armada_Multistep<LPath>>\n  {\n    RefinementViaReductionRequest(GetRefinementViaReductionLSpec(arr), GetRefinementViaReductionHSpec(arr), arr.self_relation,\n                                  GetRefinementViaReductionIdmap(arr), GetRefinementViaReductionPhase1(arr),\n                                  GetRefinementViaReductionPhase2(arr), GetRefinementViaReductionCrashedPred(arr))\n  }\n\n  //////////////////////////////\n  // UTILITY PREDICATES\n  //////////////////////////////\n\n  predicate IsPhase1<LState, LPath, LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    s:LState,\n    tid:Armada_ThreadHandle\n    )\n  {\n    var pc := arr.l.get_thread_pc(s, tid);\n    pc.Some? && arr.is_phase1(pc.v)\n  }\n\n  predicate IsPhase2<LState, LPath, LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    s:LState,\n    tid:Armada_ThreadHandle\n    )\n  {\n    var pc := arr.l.get_thread_pc(s, tid);\n    pc.Some? && arr.is_phase2(pc.v)\n  }\n\n  predicate IsNonyielding<LState, LPath, LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    s:LState,\n    tid:Armada_ThreadHandle\n    )\n  {\n    var pc := arr.l.get_thread_pc(s, tid);\n    pc.Some? && arr.l.is_pc_nonyielding(pc.v)\n  }\n\n  predicate PCTypesMatch<LState, LPath, LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    s:LState,\n    s':LState,\n    tid:Armada_ThreadHandle\n    )\n  {\n    && IsPhase1(arr, s', tid) == IsPhase1(arr, s, tid)\n    && IsPhase2(arr, s', tid) == IsPhase2(arr, s, tid)\n    && IsNonyielding(arr, s', tid) == IsNonyielding(arr, s, tid)\n  }\n\n  predicate OKAndPCTypesMatch<LState, LPath, LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    s:LState,\n    s':LState,\n    tid:Armada_ThreadHandle\n    )\n  {\n    && arr.l.state_ok(s') == arr.l.state_ok(s)\n    && PCTypesMatch(arr, s, s', tid)\n  }\n\n  //////////////////////////////\n  // UTILITY LEMMAS\n  //////////////////////////////\n\n  lemma lemma_SpecificSequenceCaseA<T>(s1:seq<T>, s2:seq<T>, x:T, i:int)\n    requires |s2| > 0\n    requires 0 <= i - |s1 + [x]| + 1 < |s2[1..]|\n    ensures  s2[1..][i - |s1 + [x]| + 1] == s2[i - |s1| + 1]\n  {\n  }\n\n  lemma lemma_SpecificSequenceCaseB<T>(s1:seq<T>, x:T, i:int)\n    requires |s1| > 0\n    requires i == |s1| - 1\n    ensures  (s1 + [x])[i] == last(s1)\n  {\n  }\n\n  lemma lemma_SpecificSequenceCaseC<T>(s1:seq<T>, s2:seq<T>, s3:seq<T>, i:int)\n    requires |s1| > 0\n    requires |s3| > 0\n    requires |s1| <= i + 1 < |s1| + |s2|\n    ensures  s2[(i-|all_but_last(s1)|+1)-|[last(s3)]|] == s2[i-|s1|+1]\n  {\n  }\n\n  lemma lemma_ConcatenationCommutesWithAllButLast<T>(s1:seq<T>, s2:seq<T>)\n    requires |s2| > 0\n    ensures  s1 + all_but_last(s2) == all_but_last(s1 + s2)\n  {\n  }\n\n  lemma lemma_AtomicValidPathSequenceOfAnyTypeImpliesValidPath<State, Path, PC>(\n    asf: AtomicSpecFunctions<State, Path, PC>,\n    s: State,\n    s': State,\n    paths: seq<Path>,\n    tid: Armada_ThreadHandle,\n    states: seq<State>,\n    i: int\n    )\n    requires AtomicValidPathSequenceOfAnyType(asf, s, paths, tid)\n    requires 0 <= i < |paths|\n    requires states == AtomicGetStateSequence(asf, s, paths, tid)\n    ensures  asf.path_valid(states[i], paths[i], tid)\n    ensures  states[i+1] == asf.path_next(states[i], paths[i], tid)\n  {\n    if i > 0 {\n      var s_mid := asf.path_next(s, paths[0], tid);\n      lemma_AtomicValidPathSequenceOfAnyTypeImpliesValidPath(asf, s_mid, s', paths[1..], tid, states[1..], i-1);\n    }\n  }\n\n  lemma lemma_ExtendingStateSequenceWorks<State, Path, PC>(\n    asf:AtomicSpecFunctions<State, Path, PC>,\n    s:State,\n    s':State,\n    paths:seq<Path>,\n    states:seq<State>,\n    tid:Armada_ThreadHandle,\n    next_path:Path,\n    next_state:State\n    )\n    requires AtomicNextMultiplePaths(asf, s, s', paths, tid)\n    requires states == AtomicGetStateSequence(asf, s, paths, tid)\n    requires asf.path_valid(s', next_path, tid)\n    requires next_state == asf.path_next(s', next_path, tid)\n    ensures  AtomicNextMultiplePaths(asf, s, next_state, paths + [next_path], tid)\n    ensures  states + [next_state] == AtomicGetStateSequence(asf, s, paths + [next_path], tid)\n    decreases |paths|\n  {\n    if |paths| > 0 {\n      var s_mid := asf.path_next(s, paths[0], tid);\n      lemma_ExtendingStateSequenceWorks(asf, s_mid, s', paths[1..], states[1..], tid, next_path, next_state);\n      assert paths + [next_path] == [paths[0]] + (paths[1..] + [next_path]);\n      assert states + [next_state] == [states[0]] + (states[1..] + [next_state]);\n    }\n  }\n\n  lemma lemma_AllButLastPreservesAtomicNextMultiplePaths<LState, LPath, LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    s:LState,\n    s':LState,\n    paths:seq<LPath>,\n    states:seq<LState>,\n    tid:Armada_ThreadHandle\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires AtomicNextMultiplePaths(arr.l, s, s', paths, tid)\n    requires states == AtomicGetStateSequence(arr.l, s, paths, tid)\n    requires |paths| > 0\n    ensures  all_but_last(states) == AtomicGetStateSequence(arr.l, s, all_but_last(paths), tid)\n    ensures  AtomicNextMultiplePaths(arr.l, s, states[|states|-2], all_but_last(paths), tid)\n  {\n    if |paths| > 1 {\n      var s_mid := arr.l.path_next(s, paths[0], tid);\n      lemma_AllButLastPreservesAtomicNextMultiplePaths(arr, s_mid, s', paths[1..], states[1..], tid);\n      assert all_but_last(states[1..]) == AtomicGetStateSequence(arr.l, s_mid, all_but_last(paths[1..]), tid);\n      assert AtomicNextMultiplePaths(arr.l, s_mid, states[1..][|states[1..]|-2], all_but_last(paths[1..]), tid);\n      assert states[1..][|states[1..]|-2] == states[|states|-2];\n\n      var abl := [paths[0]] + all_but_last(paths[1..]);\n      lemma_ConcatenationCommutesWithAllButLast([paths[0]], paths[1..]);\n      lemma_SequenceIsCarPlusCdr(paths);\n      assert abl == all_but_last(paths);\n\n      calc {\n        all_but_last(states);\n        [states[0]] + all_but_last(states[1..]);\n        [states[0]] + AtomicGetStateSequence(arr.l, s_mid, all_but_last(paths[1..]), tid);\n        AtomicGetStateSequence(arr.l, s, [paths[0]] + all_but_last(paths[1..]), tid);\n        AtomicGetStateSequence(arr.l, s, all_but_last(paths), tid);\n      }\n    }\n  }\n\n  lemma lemma_IfMultistepEndsInPhase1ThenEachPathDoes<LState, LPath, LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    s:LState,\n    s':LState,\n    multistep:Armada_Multistep<LPath>,\n    states:seq<LState>\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires !multistep.tau\n    requires AtomicNextMultistep(arr.l, s, s', multistep.steps, multistep.tid, multistep.tau)\n    requires states == AtomicGetStateSequence(arr.l, s, multistep.steps, multistep.tid)\n    requires IsPhase1(arr, s', multistep.tid)\n    ensures  forall s :: s in states ==> arr.l.get_thread_pc(s, multistep.tid).Some?\n    ensures  forall i :: 0 < i < |states| ==> arr.is_phase1(arr.l.get_thread_pc(states[i], multistep.tid).v)\n  {\n    var pos := |states|-1;\n    lemma_AtomicNextLastElement(arr.l, s, s', multistep.steps, multistep.tid, states);\n    while pos > 0\n      invariant 0 <= pos < |states|\n      invariant arr.l.get_thread_pc(states[pos], multistep.tid).Some?\n      invariant pos > 0 ==> arr.is_phase1(arr.l.get_thread_pc(states[pos], multistep.tid).v)\n      invariant forall i :: pos <= i < |states| ==> arr.l.get_thread_pc(states[i], multistep.tid).Some?\n      invariant forall i :: pos < i < |states| ==> arr.is_phase1(arr.l.get_thread_pc(states[i], multistep.tid).v)\n      decreases pos\n    {\n      var prev_pos := pos-1;\n      lemma_AtomicValidPathSequenceOfAnyTypeImpliesValidPath(arr.l, s, s', multistep.steps, multistep.tid, states, prev_pos);\n      var pc := arr.l.get_thread_pc(states[prev_pos], multistep.tid);\n      var pc' := arr.l.get_thread_pc(states[prev_pos+1], multistep.tid);\n      assert pc'.Some? && arr.is_phase1(pc'.v);\n      assert arr.l.path_valid(states[prev_pos], multistep.steps[prev_pos], multistep.tid);\n      assert arr.l.state_ok(states[prev_pos]);\n      assert states[prev_pos+1] == arr.l.path_next(states[prev_pos], multistep.steps[prev_pos], multistep.tid);\n      assert pc.Some?;\n      if prev_pos > 0 {\n        assert arr.is_phase1(pc.v);\n        assert IsPhase1(arr, states[prev_pos], multistep.tid);\n      }\n      pos := prev_pos;\n    }\n  }\n\n  lemma lemma_IfMultistepStartsInPhase2ThenEachPathDoes<LState, LPath, LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    s:LState,\n    s':LState,\n    multistep:Armada_Multistep<LPath>,\n    states:seq<LState>\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires !multistep.tau\n    requires AtomicNextMultistep(arr.l, s, s', multistep.steps, multistep.tid, multistep.tau)\n    requires states == AtomicGetStateSequence(arr.l, s, multistep.steps, multistep.tid)\n    requires IsPhase2(arr, s, multistep.tid)\n    ensures  forall i :: 0 <= i < |states|-1 ==> IsPhase2(arr, states[i], multistep.tid)\n  {\n    if |states| == 1 {\n      return;\n    }\n\n    var pos := 0;\n    lemma_AtomicNextLastElement(arr.l, s, s', multistep.steps, multistep.tid, states);\n    while pos < |states|-2\n      invariant 0 <= pos <= |states|-2\n      invariant arr.l.get_thread_pc(states[pos], multistep.tid).Some?\n      invariant arr.is_phase2(arr.l.get_thread_pc(states[pos], multistep.tid).v)\n      invariant forall i :: 0 <= i <= pos ==> arr.l.get_thread_pc(states[i], multistep.tid).Some?\n      invariant forall i :: 0 <= i <= pos ==> arr.is_phase2(arr.l.get_thread_pc(states[i], multistep.tid).v)\n      decreases |states|-pos\n    {\n      lemma_AtomicValidPathSequenceOfAnyTypeImpliesValidPath(arr.l, s, s', multistep.steps, multistep.tid, states, pos);\n      var pc := arr.l.get_thread_pc(states[pos], multistep.tid);\n      var pc' := arr.l.get_thread_pc(states[pos+1], multistep.tid);\n      assert pc.Some? && arr.is_phase2(pc.v);\n      assert arr.l.path_valid(states[pos], multistep.steps[pos], multistep.tid);\n      assert states[pos+1] == arr.l.path_next(states[pos], multistep.steps[pos], multistep.tid);\n      var next_pos := pos+1;\n      assert 0 < next_pos < |multistep.steps|;\n      assert arr.l.get_thread_pc(states[next_pos], multistep.tid).Some?\n               && arr.l.is_pc_nonyielding(arr.l.get_thread_pc(states[next_pos], multistep.tid).v);\n      assert pc'.Some?;\n      assert arr.is_phase2(pc'.v);\n      pos := pos + 1;\n    }\n  }\n\n  lemma lemma_TakingAtomicMultistepKeepsThreadYielding<State(!new), Path(!new), PC(!new)>(\n    asf:AtomicSpecFunctions<State, Path, PC>,\n    s:State,\n    s':State,\n    multistep:Armada_Multistep<Path>,\n    tid:Armada_ThreadHandle\n    )\n    requires AtomicTauLeavesPCUnchanged(asf)\n    requires AtomicThreadCantAffectOtherThreadPCExceptViaFork(asf)\n    requires AtomicPathRequiresOK(asf)\n    requires AtomicNextMultistep(asf, s, s', multistep.steps, multistep.tid, multistep.tau)\n    requires asf.state_ok(s) ==> AtomicThreadYielding(asf, s, tid)\n    ensures  asf.state_ok(s') ==> AtomicThreadYielding(asf, s', tid)\n  {\n    var pc' := asf.get_thread_pc(s', tid);\n    var states := AtomicGetStateSequence(asf, s, multistep.steps, multistep.tid);\n    lemma_AtomicNextLastElement(asf, s, s', multistep.steps, multistep.tid, states);\n\n    if multistep.tau {\n      return;\n    }\n\n    if multistep.tid == tid {\n      return;\n    }\n\n    var pos := 0;\n    while pos < |multistep.steps|\n      invariant 0 <= pos <= |multistep.steps|\n      invariant asf.state_ok(states[pos]) ==> AtomicThreadYielding(asf, states[pos], tid)\n      decreases |multistep.steps|-pos\n    {\n      lemma_AtomicValidPathSequenceOfAnyTypeImpliesValidPath(asf, s, s', multistep.steps, multistep.tid, states, pos);\n      pos := pos + 1;\n    }\n  }\n\n  lemma lemma_StateAmongAnnotatedReachablesHasThreadYielding<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    s:LState,\n    tid:Armada_ThreadHandle\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires s in AnnotatedReachables(GetRefinementViaReductionLSpec(arr))\n    ensures  arr.l.state_ok(s) ==> AtomicThreadYielding(arr.l, s, tid)\n  {\n    var rspec := GetRefinementViaReductionLSpec(arr);\n\n    reveal_AnnotatedReachables();\n    var ab :| AnnotatedBehaviorSatisfiesSpec(ab, rspec) && last(ab.states) == s;\n    var pos := 0;\n    while pos < |ab.states|-1\n      invariant 0 <= pos < |ab.states|\n      invariant arr.l.state_ok(ab.states[pos]) ==> AtomicThreadYielding(arr.l, ab.states[pos], tid)\n      decreases |ab.states|-pos\n    {\n      var subpos := 0;\n      var s := ab.states[pos];\n      var s' := ab.states[pos+1];\n      var path := ab.trace[pos];\n      assert ActionTuple(ab.states[pos], ab.states[pos+1], ab.trace[pos]) in rspec.next;\n      lemma_TakingAtomicMultistepKeepsThreadYielding(arr.l, ab.states[pos], ab.states[pos+1], ab.trace[pos], tid);\n      pos := pos + 1;\n    }\n  }\n\n  lemma lemma_AtomicNextMultiplePathsTransitive<LState, LPath, LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    s1:LState,\n    s2:LState,\n    s3:LState,\n    paths1:seq<LPath>,\n    paths2:seq<LPath>,\n    tid:Armada_ThreadHandle\n    )\n    requires AtomicNextMultiplePaths(arr.l, s1, s2, paths1, tid)\n    requires AtomicNextMultiplePaths(arr.l, s2, s3, paths2, tid)\n    ensures  AtomicNextMultiplePaths(arr.l, s1, s3, paths1 + paths2, tid)\n  {\n    if |paths1| > 0 {\n      var s_mid := arr.l.path_next(s1, paths1[0], tid);\n      lemma_AtomicNextMultiplePathsTransitive(arr, s_mid, s2, s3, paths1[1..], paths2, tid);\n      assert AtomicNextMultiplePaths(arr.l, s_mid, s3, paths1[1..] + paths2, tid);\n      var paths3 := paths1 + paths2;\n      assert paths3[0] == paths1[0];\n      assert paths3[1..] == paths1[1..] + paths2;\n    }\n    else {\n      assert s1 == s2;\n      assert paths1 + paths2 == paths2;\n    }\n  }\n\n  lemma lemma_ExecutingPathDoesntChangeOtherActorPCType<LState, LPath, LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    s:LState,\n    s':LState,\n    path:LPath,\n    tid:Armada_ThreadHandle,\n    other_tid:Armada_ThreadHandle\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires arr.l.path_valid(s, path, tid)\n    requires s' == arr.l.path_next(s, path, tid)\n    requires tid != other_tid || arr.l.path_type(path).AtomicPathType_Tau?\n    ensures  PCTypesMatch(arr, s, s', other_tid)\n  {\n  }\n\n  lemma lemma_ExecutingPathSequenceDoesntChangeOtherActorPCType<LState, LPath, LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    s:LState,\n    s':LState,\n    paths:seq<LPath>,\n    tau:bool,\n    tid:Armada_ThreadHandle,\n    other_tid:Armada_ThreadHandle\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires AtomicNextMultiplePaths(arr.l, s, s', paths, tid)\n    requires forall path :: path in paths ==> arr.l.path_type(path).AtomicPathType_Tau? == tau\n    requires tau || tid != other_tid\n    ensures  PCTypesMatch(arr, s, s', other_tid)\n    decreases |paths|\n  {\n    if |paths| > 0 {\n      var s_mid := arr.l.path_next(s, paths[0], tid);\n      lemma_ExecutingPathDoesntChangeOtherActorPCType(arr, s, s_mid, paths[0], tid, other_tid);\n      lemma_ExecutingPathSequenceDoesntChangeOtherActorPCType(arr, s_mid, s', paths[1..], tau, tid, other_tid);\n    }\n  }\n\n  lemma lemma_ExecutingPathDoesntRemoveOtherActorPC<LState, LPath, LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    s:LState,\n    s':LState,\n    path:LPath,\n    tid:Armada_ThreadHandle,\n    other_tid:Armada_ThreadHandle\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires arr.l.path_valid(s, path, tid)\n    requires s' == arr.l.path_next(s, path, tid)\n    requires tid != other_tid || arr.l.path_type(path).AtomicPathType_Tau?\n    ensures  arr.l.get_thread_pc(s, other_tid).Some? ==> arr.l.get_thread_pc(s', other_tid).Some?\n  {\n  }\n\n  lemma lemma_ExecutingPathSequenceDoesntRemoveOtherActorPC<LState, LPath, LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    s:LState,\n    s':LState,\n    paths:seq<LPath>,\n    tau:bool,\n    tid:Armada_ThreadHandle,\n    other_tid:Armada_ThreadHandle\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires AtomicNextMultiplePaths(arr.l, s, s', paths, tid)\n    requires forall path :: path in paths ==> arr.l.path_type(path).AtomicPathType_Tau? == tau\n    requires tau || tid != other_tid\n    ensures  arr.l.get_thread_pc(s, other_tid).Some? ==> arr.l.get_thread_pc(s', other_tid).Some?\n    decreases |paths|\n  {\n    if |paths| > 0 {\n      var s_mid := arr.l.path_next(s, paths[0], tid);\n      lemma_ExecutingPathDoesntRemoveOtherActorPC(arr, s, s_mid, paths[0], tid, other_tid);\n      lemma_ExecutingPathSequenceDoesntRemoveOtherActorPC(arr, s_mid, s', paths[1..], tau, tid, other_tid);\n    }\n  }\n\n  lemma lemma_StateAmongAnnotatedReachablesSatisfiesInv<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    s:LState\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires s in AnnotatedReachables(GetRefinementViaReductionLSpec(arr))\n    ensures  arr.inv(s)\n  {\n    var rspec := GetRefinementViaReductionLSpec(arr);\n    reveal_AnnotatedReachables();\n    var ab :| AnnotatedBehaviorSatisfiesSpec(ab, rspec) && last(ab.states) == s;\n    var pos := 0;\n    while pos < |ab.states|-1\n      invariant 0 <= pos < |ab.states|\n      invariant arr.inv(ab.states[pos])\n      decreases |ab.states|-pos\n    {\n      var subpos := 0;\n      var s := ab.states[pos];\n      var s' := ab.states[pos+1];\n      var multistep := ab.trace[pos];\n      assert ActionTuple(ab.states[pos], ab.states[pos+1], ab.trace[pos]) in rspec.next;\n      assert AtomicNextMultistep(arr.l, s, s', multistep.steps, multistep.tid, multistep.tau);\n      var states := AtomicGetStateSequence(arr.l, s, multistep.steps, multistep.tid);\n      while subpos < |multistep.steps|\n        invariant 0 <= subpos <= |multistep.steps|\n        invariant arr.inv(states[subpos])\n        decreases |multistep.steps|-subpos\n      {\n        lemma_AtomicValidPathSequenceOfAnyTypeImpliesValidPath(arr.l, s, s', multistep.steps, multistep.tid, states, subpos);\n        subpos := subpos + 1;\n      }\n      lemma_AtomicNextLastElement(arr.l, s, s', multistep.steps, multistep.tid, states);\n      pos := pos+1;\n    }\n  }\n\n  lemma lemma_AtomicInvariantHoldsAtIntermediateState<State, Path, PC>(\n    asf:AtomicSpecFunctions<State, Path, PC>,\n    inv:State->bool,\n    s:State,\n    s':State,\n    paths:seq<Path>,\n    tid:Armada_ThreadHandle,\n    states:seq<State>,\n    pos:int\n    )\n    requires AtomicPathPreservesInv(asf, inv)\n    requires AtomicNextMultiplePaths(asf, s, s', paths, tid)\n    requires states == AtomicGetStateSequence(asf, s, paths, tid)\n    requires 0 <= pos < |states|\n    requires inv(states[0])\n    ensures  inv(states[pos])\n    decreases pos\n  {\n    if pos > 0 {\n      var s_mid := asf.path_next(s, paths[0], tid);\n      lemma_AtomicInvariantHoldsAtIntermediateState(asf, inv, s_mid, s', paths[1..], tid, states[1..], pos-1);\n    }\n  }\n\n  //////////////////////////////\n  // LEMMA-SPECIFIC PREDICATES\n  //////////////////////////////\n\n  predicate PerformRightMoveTrigger(i:int)\n  {\n    true\n  }\n\n  predicate PerformRightMoveThroughPredicate<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    other_tid:Armada_ThreadHandle,\n    other_states_before:seq<LState>,\n    other_states_after:seq<LState>,\n    other_states':seq<LState>\n    )\n    requires |other_states_before| > 0\n    requires |other_states_after| > 0\n    requires |other_states'| == |other_states_before| + |other_states_after| - 1\n  {\n    && (forall i {:trigger PerformRightMoveTrigger(i)} ::\n             PerformRightMoveTrigger(i) && 0 <= i < |other_states_before| ==>\n             OKAndPCTypesMatch(arr, other_states'[i], other_states_before[i], other_tid))\n    && (forall i {:trigger PerformRightMoveTrigger(i)} ::\n             PerformRightMoveTrigger(i) && |other_states_before|-1 <= i < |other_states'| ==>\n             OKAndPCTypesMatch(arr, other_states'[i], other_states_after[i-|other_states_before|+1], other_tid))\n  }\n\n  predicate PerformRightMoveRemainingPredicate<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    mover_tid:Armada_ThreadHandle,\n    mover_states_before:seq<LState>,\n    mover_states_after:seq<LState>,\n    mover_states':seq<LState>\n    )\n    requires |mover_states_before| > 0\n    requires |mover_states_after| > 0\n    requires |mover_states'| == |mover_states_before| + |mover_states_after| - 1\n  {\n    && (forall i {:trigger PerformRightMoveTrigger(i)} ::\n          PerformRightMoveTrigger(i) && 0 <= i < |mover_states_before| ==>\n          OKAndPCTypesMatch(arr, mover_states'[i], mover_states_before[i], mover_tid))\n    && (forall i {:trigger PerformRightMoveTrigger(i)} ::\n          PerformRightMoveTrigger(i) && |mover_states_before|-1 <= i < |mover_states'| ==>\n          OKAndPCTypesMatch(arr, mover_states'[i], mover_states_after[i-|mover_states_before|+1], mover_tid))\n  }\n\n  //////////////////////////////////////////\n  // LEMMAS SUPPORTING PERFORM-RIGHT-MOVE\n  //////////////////////////////////////////\n\n  lemma lemma_PerformRightMoveSingle<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    mover_tid:Armada_ThreadHandle,\n    other_tid:Armada_ThreadHandle,\n    other_tau:bool,\n    s1:LState,\n    s2:LState,\n    s3:LState,\n    mover_path:LPath,\n    other_path:LPath\n    ) returns (\n    s2':LState\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires other_tau || other_tid != mover_tid\n\n    requires arr.inv(s1)\n    requires arr.l.state_ok(s3)\n\n    requires arr.l.path_type(other_path).AtomicPathType_Tau? == other_tau\n    requires !arr.l.path_type(mover_path).AtomicPathType_Tau?\n\n    requires arr.l.path_valid(s1, mover_path, mover_tid)\n    requires s2 == arr.l.path_next(s1, mover_path, mover_tid)\n    requires arr.l.path_valid(s2, other_path, other_tid)\n    requires s3 == arr.l.path_next(s2, other_path, other_tid)\n\n    requires arr.l.get_thread_pc(s1, mover_tid).Some?\n    requires arr.l.get_thread_pc(s2, mover_tid).Some?\n    requires arr.is_phase1(arr.l.get_thread_pc(s2, mover_tid).v)\n\n    ensures  arr.l.path_valid(s1, other_path, other_tid)\n    ensures  s2' == arr.l.path_next(s1, other_path, other_tid)\n    ensures  arr.l.path_valid(s2', mover_path, mover_tid)\n    ensures  s3 == arr.l.path_next(s2', mover_path, mover_tid)\n    ensures  OKAndPCTypesMatch(arr, s2', s1, mover_tid)\n  {\n    assert AtomicReductionSpecModule.RightMoversCommuteConditions(arr, s1, mover_path, other_path, mover_tid, other_tid);\n    s2' := arr.l.path_next(s1, other_path, other_tid);\n  }\n\n  lemma lemma_PerformRightMoveThroughHelper<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    mover_tid:Armada_ThreadHandle,\n    other_tid:Armada_ThreadHandle,\n    other_tau:bool,\n    mover_path:LPath,\n    other_paths_before:seq<LPath>,\n    other_states_before:seq<LState>,\n    other_paths_after:seq<LPath>,\n    other_states_after:seq<LState>,\n    s2':LState,\n    other_states':seq<LState>\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires other_tau || other_tid != mover_tid\n\n    requires |other_states_before| > 0\n    requires arr.inv(other_states_before[0])\n\n    requires other_states_before == AtomicGetStateSequence(arr.l, other_states_before[0], other_paths_before, other_tid)\n    requires forall path :: path in other_paths_before ==> arr.l.path_type(path).AtomicPathType_Tau? == other_tau\n    requires AtomicNextMultiplePaths(arr.l, other_states_before[0], last(other_states_before), other_paths_before, other_tid)\n\n    requires |other_states_after| > 0\n    requires arr.l.state_ok(last(other_states_after))\n    requires other_states_after == AtomicGetStateSequence(arr.l, other_states_after[0], other_paths_after, other_tid)\n    requires forall path :: path in other_paths_after ==> arr.l.path_type(path).AtomicPathType_Tau? == other_tau\n    requires AtomicNextMultiplePaths(arr.l, other_states_after[0], last(other_states_after), other_paths_after, other_tid)\n\n    requires arr.l.path_valid(last(other_states_before), mover_path, mover_tid)\n    requires other_states_after[0] == arr.l.path_next(last(other_states_before), mover_path, mover_tid)\n    requires !arr.l.path_type(mover_path).AtomicPathType_Tau?\n    requires arr.l.get_thread_pc(other_states_before[0], mover_tid).Some?\n    requires arr.l.get_thread_pc(other_states_after[0], mover_tid).Some?\n    requires arr.is_phase1(arr.l.get_thread_pc(other_states_after[0], mover_tid).v)\n\n    requires |other_paths_after| > 0\n    requires |other_states_after| > 1\n\n    requires arr.l.path_valid(last(other_states_before), other_paths_after[0], other_tid)\n    requires s2' == arr.l.path_next(last(other_states_before), other_paths_after[0], other_tid)\n    requires arr.l.path_valid(s2', mover_path, mover_tid)\n    requires other_states_after[1] == arr.l.path_next(s2', mover_path, mover_tid)\n    requires OKAndPCTypesMatch(arr, s2', last(other_states_before), mover_tid)\n\n    requires |other_states'| == |(other_states_before + [s2'])| + |other_states_after[1..]| - 1\n    requires other_states'[0] == (other_states_before + [s2'])[0]\n    requires other_states' == AtomicGetStateSequence(arr.l, other_states'[0],\n                                                     (other_paths_before + [other_paths_after[0]]) + other_paths_after[1..], other_tid)\n    requires AtomicNextMultiplePaths(arr.l, other_states'[0], last(other_states'),\n                                       (other_paths_before + [other_paths_after[0]]) + other_paths_after[1..], other_tid)\n    requires !other_tau ==> PerformRightMoveThroughPredicate(arr, other_tid, other_states_before + [s2'], other_states_after[1..],\n                                                             other_states')\n    requires OKAndPCTypesMatch(arr, last(other_states'), last((other_states_before + [s2'])), mover_tid)\n    requires arr.l.path_valid(last(other_states'), mover_path, mover_tid)\n    requires last(other_states_after[1..]) == arr.l.path_next(last(other_states'), mover_path, mover_tid)\n\n    ensures  |other_states'| == |other_states_before| + |other_states_after| - 1\n    ensures  other_states'[0] == other_states_before[0]\n    ensures  other_states' == AtomicGetStateSequence(arr.l, other_states'[0], other_paths_before + other_paths_after, other_tid)\n    ensures  AtomicNextMultiplePaths(arr.l, other_states'[0], last(other_states'), other_paths_before + other_paths_after, other_tid)\n    ensures  !other_tau ==> PerformRightMoveThroughPredicate(arr, other_tid, other_states_before, other_states_after, other_states')\n    ensures  OKAndPCTypesMatch(arr, last(other_states'), last(other_states_before), mover_tid)\n    ensures  arr.l.path_valid(last(other_states'), mover_path, mover_tid)\n    ensures  last(other_states_after) == arr.l.path_next(last(other_states'), mover_path, mover_tid)\n  {\n    calc {\n      other_paths_before + other_paths_after;\n        { lemma_SequenceIsCarPlusCdr(other_paths_after); }\n      other_paths_before + ([other_paths_after[0]] + other_paths_after[1..]);\n        { lemma_SequenceConcatenationAssociative(other_paths_before, [other_paths_after[0]], other_paths_after[1..]); }\n      (other_paths_before + [other_paths_after[0]]) + other_paths_after[1..];\n    }\n\n    if !other_tau {\n      forall i | |other_states_before|-1 <= i < |other_states'|\n        ensures OKAndPCTypesMatch(arr, other_states'[i], other_states_after[i-|other_states_before|+1], other_tid)\n      {\n        if i >= |other_states_before + [s2']|-1 {\n          assert PerformRightMoveTrigger(i);\n          assert OKAndPCTypesMatch(arr, other_states'[i], other_states_after[1..][i-|other_states_before + [s2']|+1], other_tid);\n          calc {\n            arr.l.get_thread_pc(other_states_after[1..][i-|other_states_before + [s2']|+1], other_tid);\n              { lemma_SpecificSequenceCaseA(other_states_before, other_states_after, s2', i); }\n            arr.l.get_thread_pc(other_states_after[i-|other_states_before|+1], other_tid);\n          }\n          assert OKAndPCTypesMatch(arr, other_states'[i], other_states_after[i-|other_states_before|+1], other_tid);\n        }\n        else {\n          assert i == |other_states_before|-1;\n          assert i < |other_states_before + [s2']|-1;\n          assert PerformRightMoveTrigger(i);\n          assert OKAndPCTypesMatch(arr, other_states'[i], (other_states_before + [s2'])[i], other_tid);\n          calc {\n            arr.l.get_thread_pc((other_states_before + [s2'])[i], other_tid);\n              { lemma_SpecificSequenceCaseB(other_states_before, s2', i); }\n            arr.l.get_thread_pc(last(other_states_before), other_tid);\n          }\n          lemma_ExecutingPathDoesntChangeOtherActorPCType(arr, last(other_states_before), other_states_after[0], mover_path,\n                                                          mover_tid, other_tid);\n          calc {\n            arr.l.get_thread_pc(other_states_after[0], other_tid);\n              { assert i - |other_states_before| + 1 == 0; }\n            arr.l.get_thread_pc(other_states_after[i-|other_states_before|+1], other_tid);\n          }\n          assert OKAndPCTypesMatch(arr, other_states'[i], other_states_after[i-|other_states_before|+1], other_tid);\n        }\n      }\n    }\n  }\n\n  lemma lemma_PerformRightMoveThrough<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    mover_tid:Armada_ThreadHandle,\n    other_tid:Armada_ThreadHandle,\n    other_tau:bool,\n    mover_path:LPath,\n    other_paths_before:seq<LPath>,\n    other_states_before:seq<LState>,\n    other_paths_after:seq<LPath>,\n    other_states_after:seq<LState>\n    ) returns (\n    other_states':seq<LState>\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires other_tau || other_tid != mover_tid\n\n    requires |other_states_before| > 0\n    requires arr.inv(other_states_before[0])\n\n    requires other_states_before == AtomicGetStateSequence(arr.l, other_states_before[0], other_paths_before, other_tid)\n    requires forall path :: path in other_paths_before ==> arr.l.path_type(path).AtomicPathType_Tau? == other_tau\n    requires AtomicNextMultiplePaths(arr.l, other_states_before[0], last(other_states_before), other_paths_before, other_tid)\n\n    requires |other_states_after| > 0\n    requires arr.l.state_ok(last(other_states_after))\n    requires other_states_after == AtomicGetStateSequence(arr.l, other_states_after[0], other_paths_after, other_tid)\n    requires forall path :: path in other_paths_after ==> arr.l.path_type(path).AtomicPathType_Tau? == other_tau\n    requires AtomicNextMultiplePaths(arr.l, other_states_after[0], last(other_states_after), other_paths_after, other_tid)\n\n    requires arr.l.path_valid(last(other_states_before), mover_path, mover_tid)\n    requires other_states_after[0] == arr.l.path_next(last(other_states_before), mover_path, mover_tid)\n    requires !arr.l.path_type(mover_path).AtomicPathType_Tau?\n    requires arr.l.get_thread_pc(other_states_before[0], mover_tid).Some?\n    requires arr.l.get_thread_pc(other_states_after[0], mover_tid).Some?\n    requires arr.is_phase1(arr.l.get_thread_pc(other_states_after[0], mover_tid).v)\n\n    ensures  |other_states'| == |other_states_before| + |other_states_after| - 1\n    ensures  other_states'[0] == other_states_before[0]\n    ensures  other_states' == AtomicGetStateSequence(arr.l, other_states'[0], other_paths_before + other_paths_after, other_tid)\n    ensures  AtomicNextMultiplePaths(arr.l, other_states'[0], last(other_states'), other_paths_before + other_paths_after, other_tid)\n    ensures  !other_tau ==> PerformRightMoveThroughPredicate(arr, other_tid, other_states_before, other_states_after, other_states')\n\n    ensures  OKAndPCTypesMatch(arr, last(other_states'), last(other_states_before), mover_tid)\n    ensures  arr.l.path_valid(last(other_states'), mover_path, mover_tid)\n    ensures  last(other_states_after) == arr.l.path_next(last(other_states'), mover_path, mover_tid)\n    decreases |other_paths_after|\n  {\n    lemma_ExecutingPathSequenceDoesntChangeOtherActorPCType(arr, other_states_before[0], last(other_states_before),\n                                                            other_paths_before, other_tau, other_tid, mover_tid);\n    if |other_paths_after| == 0 {\n      other_states' := other_states_before;\n      assert other_paths_before + other_paths_after == other_paths_before;\n      if !other_tau {\n        forall i | |other_states_before|-1 <= i < |other_states'|\n          ensures OKAndPCTypesMatch(arr, other_states'[i], other_states_after[i-|other_states_before|+1], other_tid)\n        {\n          assert i == |other_states_before|-1;\n          assert other_states'[i] == last(other_states_before);\n          assert other_states_after[i-|other_states_before|+1] == other_states_after[0];\n          lemma_ExecutingPathDoesntChangeOtherActorPCType(arr, last(other_states_before), other_states_after[0], mover_path, mover_tid,\n                                                          other_tid);\n        }\n      }\n    }\n    else {\n      lemma_AtomicInvariantHoldsAtIntermediateState(arr.l, arr.inv, other_states_before[0], last(other_states_before), other_paths_before,\n                                                    other_tid, other_states_before, |other_states_before|-1);\n      forall ensures arr.l.state_ok(other_states_after[1]) {\n        if |other_paths_after| == 1 {\n          assert other_states_after[1] == last(other_states_after);\n        }\n        else {\n          lemma_AtomicValidPathSequenceOfAnyTypeImpliesValidPath(arr.l, other_states_after[0], last(other_states_after), other_paths_after,\n                                                                 other_tid, other_states_after, 1);\n        }\n      }\n      var s2' := lemma_PerformRightMoveSingle(arr, mover_tid, other_tid, other_tau, last(other_states_before), other_states_after[0],\n                                              other_states_after[1], mover_path, other_paths_after[0]);\n      lemma_ExtendingStateSequenceWorks(arr.l, other_states_before[0], last(other_states_before), other_paths_before,\n                                        other_states_before, other_tid, other_paths_after[0], s2');\n      other_states' := lemma_PerformRightMoveThrough(arr, mover_tid, other_tid, other_tau, mover_path,\n                                                     other_paths_before + [other_paths_after[0]],\n                                                     other_states_before + [s2'],\n                                                     other_paths_after[1..], other_states_after[1..]);\n      lemma_PerformRightMoveThroughHelper(arr, mover_tid, other_tid, other_tau, mover_path, other_paths_before,\n                                          other_states_before, other_paths_after, other_states_after, s2', other_states');\n    }\n  }\n\n  lemma lemma_PerformRightMoveOne<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    mover_tid:Armada_ThreadHandle,\n    other_tid:Armada_ThreadHandle,\n    other_tau:bool,\n    mover_path:LPath,\n    initial_state:LState,\n    other_paths:seq<LPath>,\n    other_states:seq<LState>\n    ) returns (\n    other_states':seq<LState>\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires other_tau || other_tid != mover_tid\n\n    requires arr.inv(initial_state)\n\n    requires |other_states| > 0\n    requires arr.l.state_ok(last(other_states))\n    requires IsPhase1(arr, other_states[0], mover_tid)\n    requires arr.l.path_valid(initial_state, mover_path, mover_tid)\n    requires other_states[0] == arr.l.path_next(initial_state, mover_path, mover_tid)\n    requires !arr.l.path_type(mover_path).AtomicPathType_Tau?\n\n    requires other_states == AtomicGetStateSequence(arr.l, other_states[0], other_paths, other_tid)\n    requires forall path :: path in other_paths ==> arr.l.path_type(path).AtomicPathType_Tau? == other_tau\n    requires AtomicNextMultiplePaths(arr.l, other_states[0], last(other_states), other_paths, other_tid)\n\n    ensures  |other_states'| == |other_states|\n    ensures  other_states'[0] == initial_state\n    ensures  other_states' == AtomicGetStateSequence(arr.l, other_states'[0], other_paths, other_tid)\n    ensures  AtomicNextMultiplePaths(arr.l, other_states'[0], last(other_states'), other_paths, other_tid)\n    ensures  !other_tau ==> forall i :: 0 <= i < |other_states| ==> OKAndPCTypesMatch(arr, other_states'[i], other_states[i], other_tid)\n\n    ensures  OKAndPCTypesMatch(arr, last(other_states'), initial_state, mover_tid)\n    ensures  arr.l.path_valid(last(other_states'), mover_path, mover_tid)\n    ensures  last(other_states) == arr.l.path_next(last(other_states'), mover_path, mover_tid)\n  {\n    other_states' := lemma_PerformRightMoveThrough(arr, mover_tid, other_tid, other_tau, mover_path, [], [initial_state],\n                                                   other_paths, other_states);\n    assert [] + other_paths == other_paths;\n\n    if !other_tau {\n      forall i | 0 <= i < |other_states|\n        ensures OKAndPCTypesMatch(arr, other_states'[i], other_states[i], other_tid)\n      {\n        assert PerformRightMoveTrigger(i);\n      }\n    }\n  }\n\n  lemma lemma_PerformRightMoveRemainingHelper1<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    mover_tid:Armada_ThreadHandle,\n    other_tid:Armada_ThreadHandle,\n    other_tau:bool,\n    mover_paths_before:seq<LPath>,\n    mover_states_before:seq<LState>,\n    mover_paths_after:seq<LPath>,\n    mover_states_after:seq<LState>,\n    other_paths:seq<LPath>,\n    other_states:seq<LState>,\n    other_states_mid:seq<LState>,\n    mover_states':seq<LState>,\n    other_states':seq<LState>\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires other_tau || other_tid != mover_tid\n\n    requires |mover_states_before| > 0\n    requires arr.inv(mover_states_before[0])\n    requires arr.l.get_thread_pc(mover_states_before[0], mover_tid).Some?\n\n    requires mover_states_before == AtomicGetStateSequence(arr.l, mover_states_before[0], mover_paths_before, mover_tid)\n    requires forall s :: s in mover_states_before ==> arr.l.get_thread_pc(s, mover_tid).Some?\n    requires forall i :: 0 < i < |mover_states_before| ==> arr.is_phase1(arr.l.get_thread_pc(mover_states_before[i], mover_tid).v)\n    requires AtomicNextMultiplePaths(arr.l, mover_states_before[0], last(mover_states_before), mover_paths_before, mover_tid)\n    requires forall path :: path in mover_paths_before ==> !arr.l.path_type(path).AtomicPathType_Tau?\n\n    requires |mover_states_after| > 0\n    requires mover_states_after == AtomicGetStateSequence(arr.l, mover_states_after[0], mover_paths_after, mover_tid)\n    requires forall s :: s in mover_states_after ==> arr.l.get_thread_pc(s, mover_tid).Some?\n    requires forall i :: 0 < i < |mover_states_after| ==> arr.is_phase1(arr.l.get_thread_pc(mover_states_after[i], mover_tid).v)\n    requires |mover_paths_before| > 0 ==> arr.is_phase1(arr.l.get_thread_pc(mover_states_after[0], mover_tid).v)\n    requires AtomicNextMultiplePaths(arr.l, mover_states_after[0], last(mover_states_after), mover_paths_after, mover_tid)\n    requires forall path :: path in mover_paths_after ==> !arr.l.path_type(path).AtomicPathType_Tau?\n\n    requires |other_states| > 0\n    requires other_states[0] == last(mover_states_before)\n    requires last(other_states) == mover_states_after[0]\n    requires other_states == AtomicGetStateSequence(arr.l, other_states[0], other_paths, other_tid)\n    requires AtomicNextMultiplePaths(arr.l, other_states[0], last(other_states), other_paths, other_tid)\n    requires forall path :: path in other_paths ==> arr.l.path_type(path).AtomicPathType_Tau? == other_tau\n\n    requires |mover_paths_before| > 0\n    requires |other_states_mid| == |other_states|\n    requires other_states_mid[0] == mover_states_before[|mover_paths_before|-1]\n    requires other_states_mid == AtomicGetStateSequence(arr.l, other_states_mid[0], other_paths, other_tid)\n    requires AtomicNextMultiplePaths(arr.l, other_states_mid[0], last(other_states_mid), other_paths, other_tid)\n    requires !other_tau ==> forall i :: 0 <= i < |other_states| ==> OKAndPCTypesMatch(arr, other_states_mid[i], other_states[i], other_tid)\n  \n    requires |other_states'| == |other_states_mid|\n    requires other_states'[0] == all_but_last(mover_states_before)[0]\n    requires other_states' == AtomicGetStateSequence(arr.l, other_states'[0], other_paths, other_tid)\n    requires AtomicNextMultiplePaths(arr.l, other_states'[0], last(other_states'), other_paths, other_tid)\n    requires !other_tau ==> forall i :: 0 <= i < |other_states_mid| ==> OKAndPCTypesMatch(arr, other_states'[i], other_states_mid[i], other_tid)\n    requires |mover_states'| == |all_but_last(mover_states_before)| + |([last(other_states_mid)] + mover_states_after)| - 1\n    requires mover_states'[0] == last(other_states')\n    requires last(mover_states') == last(([last(other_states_mid)] + mover_states_after))\n    requires mover_states' == AtomicGetStateSequence(arr.l, mover_states'[0],\n                                                     all_but_last(mover_paths_before) + ([last(mover_paths_before)] + mover_paths_after),\n                                                     mover_tid)\n    requires AtomicNextMultiplePaths(arr.l, mover_states'[0], last(mover_states'),\n                                      all_but_last(mover_paths_before) + ([last(mover_paths_before)] + mover_paths_after), mover_tid)\n\n    ensures  |other_states'| == |other_states|\n    ensures  other_states'[0] == mover_states_before[0]\n    ensures  other_states' == AtomicGetStateSequence(arr.l, other_states'[0], other_paths, other_tid)\n    ensures  AtomicNextMultiplePaths(arr.l, other_states'[0], last(other_states'), other_paths, other_tid)\n    ensures  !other_tau ==> forall i :: 0 <= i < |other_states| ==> OKAndPCTypesMatch(arr, other_states'[i], other_states[i], other_tid)\n    ensures  |mover_states'| == |mover_states_before| + |mover_states_after| - 1\n    ensures  mover_states'[0] == last(other_states')\n    ensures  last(mover_states') == last(mover_states_after)\n    ensures  mover_states' == AtomicGetStateSequence(arr.l, mover_states'[0], mover_paths_before + mover_paths_after, mover_tid)\n    ensures  AtomicNextMultiplePaths(arr.l, mover_states'[0], last(mover_states'), mover_paths_before + mover_paths_after, mover_tid)\n  {\n    calc {\n      all_but_last(mover_paths_before) + ([last(mover_paths_before)] + mover_paths_after);\n        { lemma_SequenceConcatenationAssociative(all_but_last(mover_paths_before), [last(mover_paths_before)], mover_paths_after); }\n      (all_but_last(mover_paths_before) + [last(mover_paths_before)]) + mover_paths_after;\n        { lemma_AllButLastPlusLastIsSeq(mover_paths_before); }\n      mover_paths_before + mover_paths_after;\n    }\n    lemma_LastOfConcatenationIsLastOfLatter([last(other_states_mid)], mover_states_after);\n  }\n\n  lemma lemma_PerformRightMoveRemainingHelper2<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    mover_tid:Armada_ThreadHandle,\n    other_tid:Armada_ThreadHandle,\n    other_tau:bool,\n    mover_paths_before:seq<LPath>,\n    mover_states_before:seq<LState>,\n    mover_paths_after:seq<LPath>,\n    mover_states_after:seq<LState>,\n    other_paths:seq<LPath>,\n    other_states:seq<LState>,\n    other_states_mid:seq<LState>,\n    mover_states':seq<LState>,\n    other_states':seq<LState>\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires other_tau || other_tid != mover_tid\n\n    requires |mover_states_before| > 0\n    requires arr.inv(mover_states_before[0])\n    requires arr.l.get_thread_pc(mover_states_before[0], mover_tid).Some?\n\n    requires mover_states_before == AtomicGetStateSequence(arr.l, mover_states_before[0], mover_paths_before, mover_tid)\n    requires forall s :: s in mover_states_before ==> arr.l.get_thread_pc(s, mover_tid).Some?\n    requires forall i :: 0 < i < |mover_states_before| ==> arr.is_phase1(arr.l.get_thread_pc(mover_states_before[i], mover_tid).v)\n    requires AtomicNextMultiplePaths(arr.l, mover_states_before[0], last(mover_states_before), mover_paths_before, mover_tid)\n    requires forall path :: path in mover_paths_before ==> !arr.l.path_type(path).AtomicPathType_Tau?\n\n    requires |mover_states_after| > 0\n    requires mover_states_after == AtomicGetStateSequence(arr.l, mover_states_after[0], mover_paths_after, mover_tid)\n    requires forall s :: s in mover_states_after ==> arr.l.get_thread_pc(s, mover_tid).Some?\n    requires forall i :: 0 < i < |mover_states_after| ==> arr.is_phase1(arr.l.get_thread_pc(mover_states_after[i], mover_tid).v)\n    requires |mover_paths_before| > 0 ==> arr.is_phase1(arr.l.get_thread_pc(mover_states_after[0], mover_tid).v)\n    requires AtomicNextMultiplePaths(arr.l, mover_states_after[0], last(mover_states_after), mover_paths_after, mover_tid)\n    requires forall path :: path in mover_paths_after ==> !arr.l.path_type(path).AtomicPathType_Tau?\n\n    requires |other_states| > 0\n    requires arr.l.state_ok(last(other_states))\n    requires other_states[0] == last(mover_states_before)\n    requires last(other_states) == mover_states_after[0]\n    requires other_states == AtomicGetStateSequence(arr.l, other_states[0], other_paths, other_tid)\n    requires AtomicNextMultiplePaths(arr.l, other_states[0], last(other_states), other_paths, other_tid)\n    requires forall path :: path in other_paths ==> arr.l.path_type(path).AtomicPathType_Tau? == other_tau\n\n    requires |mover_paths_before| > 0\n    requires |other_states_mid| == |other_states|\n    requires other_states_mid[0] == mover_states_before[|mover_paths_before|-1]\n    requires other_states_mid == AtomicGetStateSequence(arr.l, other_states_mid[0], other_paths, other_tid)\n    requires AtomicNextMultiplePaths(arr.l, other_states_mid[0], last(other_states_mid), other_paths, other_tid)\n    requires !other_tau ==> forall i :: 0 <= i < |other_states| ==> OKAndPCTypesMatch(arr, other_states_mid[i], other_states[i], other_tid)\n  \n    requires |other_states'| == |other_states_mid|\n    requires other_states'[0] == all_but_last(mover_states_before)[0]\n    requires other_states' == AtomicGetStateSequence(arr.l, other_states'[0], other_paths, other_tid)\n    requires AtomicNextMultiplePaths(arr.l, other_states'[0], last(other_states'), other_paths, other_tid)\n    requires !other_tau ==> forall i :: 0 <= i < |other_states_mid| ==> OKAndPCTypesMatch(arr, other_states'[i], other_states_mid[i], other_tid)\n    requires |mover_states'| == |all_but_last(mover_states_before)| + |([last(other_states_mid)] + mover_states_after)| - 1\n    requires mover_states'[0] == last(other_states')\n    requires last(mover_states') == last(([last(other_states_mid)] + mover_states_after))\n    requires mover_states' == AtomicGetStateSequence(arr.l, mover_states'[0],\n                                                     all_but_last(mover_paths_before) + ([last(mover_paths_before)] + mover_paths_after),\n                                                     mover_tid)\n    requires AtomicNextMultiplePaths(arr.l, mover_states'[0], last(mover_states'),\n                                     all_but_last(mover_paths_before) + ([last(mover_paths_before)] + mover_paths_after), mover_tid)\n    requires PerformRightMoveRemainingPredicate(arr, mover_tid, all_but_last(mover_states_before),\n                                                [last(other_states_mid)] + mover_states_after, mover_states')\n\n    ensures  PerformRightMoveRemainingPredicate(arr, mover_tid, mover_states_before, mover_states_after, mover_states')\n  {\n    forall i | 0 <= i < |mover_states_before|\n      ensures OKAndPCTypesMatch(arr, mover_states'[i], mover_states_before[i], mover_tid)\n    {\n      assert PerformRightMoveTrigger(i);\n      if i < |all_but_last(mover_states_before)| {\n        assert OKAndPCTypesMatch(arr, mover_states'[i], all_but_last(mover_states_before)[i], mover_tid);\n        calc {\n          arr.l.get_thread_pc(all_but_last(mover_states_before)[i], mover_tid);\n          arr.l.get_thread_pc(mover_states_before[i], mover_tid);\n        }\n      }\n      else {\n        assert i == |all_but_last(mover_states_before)|;\n        assert |all_but_last(mover_states_before)|-1 <= i < |mover_states'|;\n        assert OKAndPCTypesMatch(arr, mover_states'[i],\n                                 ([last(other_states_mid)] + mover_states_after)[i-|all_but_last(mover_states_before)|+1],\n                                 mover_tid);\n        calc {\n          arr.l.get_thread_pc(([last(other_states_mid)] + mover_states_after)[i-|all_but_last(mover_states_before)|+1], mover_tid);\n          arr.l.get_thread_pc(([last(other_states_mid)] + mover_states_after)[1], mover_tid);\n          arr.l.get_thread_pc(mover_states_after[0], mover_tid);\n        }\n        lemma_ExecutingPathSequenceDoesntChangeOtherActorPCType(arr, last(mover_states_before), mover_states_after[0],\n                                                                  other_paths, other_tau, other_tid, mover_tid);\n        assert last(mover_states_before) == mover_states_before[i];\n      }\n    }\n\n    forall i | |mover_states_before|-1 <= i < |mover_states'|\n      ensures OKAndPCTypesMatch(arr, mover_states'[i], mover_states_after[i-|mover_states_before|+1], mover_tid)\n    {\n      assert PerformRightMoveTrigger(i);\n      assert |all_but_last(mover_states_before)|-1 <= i < |mover_states'|;\n      assert OKAndPCTypesMatch(arr, mover_states'[i],\n                               ([last(other_states_mid)] + mover_states_after)[i-|all_but_last(mover_states_before)|+1],\n                               mover_tid);\n      calc {\n        arr.l.get_thread_pc(([last(other_states_mid)] + mover_states_after)[i-|all_but_last(mover_states_before)|+1], mover_tid);\n          { lemma_IndexIntoConcatenation([last(other_states_mid)], mover_states_after, i-|all_but_last(mover_states_before)|+1); }\n        arr.l.get_thread_pc(mover_states_after[(i-|all_but_last(mover_states_before)|+1)-|[last(other_states_mid)]|], mover_tid);\n          { lemma_SpecificSequenceCaseC(mover_states_before, mover_states_after, other_states_mid, i); }\n        arr.l.get_thread_pc(mover_states_after[i-|mover_states_before|+1], mover_tid);\n      }\n    }\n  }\n\n  lemma lemma_PerformRightMoveRemaining<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    mover_tid:Armada_ThreadHandle,\n    other_tid:Armada_ThreadHandle,\n    other_tau:bool,\n    mover_paths_before:seq<LPath>,\n    mover_states_before:seq<LState>,\n    mover_paths_after:seq<LPath>,\n    mover_states_after:seq<LState>,\n    other_paths:seq<LPath>,\n    other_states:seq<LState>\n    ) returns (\n    mover_states':seq<LState>,\n    other_states':seq<LState>\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires other_tau || other_tid != mover_tid\n\n    requires |mover_states_before| > 0\n    requires arr.inv(mover_states_before[0])\n    requires arr.l.get_thread_pc(mover_states_before[0], mover_tid).Some?\n\n    requires mover_states_before == AtomicGetStateSequence(arr.l, mover_states_before[0], mover_paths_before, mover_tid)\n    requires forall s :: s in mover_states_before ==> arr.l.get_thread_pc(s, mover_tid).Some?\n    requires forall i :: 0 < i < |mover_states_before| ==> arr.is_phase1(arr.l.get_thread_pc(mover_states_before[i], mover_tid).v)\n    requires AtomicNextMultiplePaths(arr.l, mover_states_before[0], last(mover_states_before), mover_paths_before, mover_tid)\n    requires forall path :: path in mover_paths_before ==> !arr.l.path_type(path).AtomicPathType_Tau?\n\n    requires |mover_states_after| > 0\n    requires mover_states_after == AtomicGetStateSequence(arr.l, mover_states_after[0], mover_paths_after, mover_tid)\n    requires forall s :: s in mover_states_after ==> arr.l.get_thread_pc(s, mover_tid).Some?\n    requires forall i :: 0 < i < |mover_states_after| ==> arr.is_phase1(arr.l.get_thread_pc(mover_states_after[i], mover_tid).v)\n    requires |mover_paths_before| > 0 ==> arr.is_phase1(arr.l.get_thread_pc(mover_states_after[0], mover_tid).v)\n    requires AtomicNextMultiplePaths(arr.l, mover_states_after[0], last(mover_states_after), mover_paths_after, mover_tid)\n    requires forall path :: path in mover_paths_after ==> !arr.l.path_type(path).AtomicPathType_Tau?\n\n    requires |other_states| > 0\n    requires arr.l.state_ok(last(other_states))\n    requires other_states[0] == last(mover_states_before)\n    requires last(other_states) == mover_states_after[0]\n    requires other_states == AtomicGetStateSequence(arr.l, other_states[0], other_paths, other_tid)\n    requires AtomicNextMultiplePaths(arr.l, other_states[0], last(other_states), other_paths, other_tid)\n    requires forall path :: path in other_paths ==> arr.l.path_type(path).AtomicPathType_Tau? == other_tau\n\n    ensures  |other_states'| == |other_states|\n    ensures  other_states'[0] == mover_states_before[0]\n    ensures  other_states' == AtomicGetStateSequence(arr.l, other_states'[0], other_paths, other_tid)\n    ensures  AtomicNextMultiplePaths(arr.l, other_states'[0], last(other_states'), other_paths, other_tid)\n    ensures  !other_tau ==> forall i :: 0 <= i < |other_states| ==> OKAndPCTypesMatch(arr, other_states'[i], other_states[i], other_tid)\n\n    ensures  |mover_states'| == |mover_states_before| + |mover_states_after| - 1\n    ensures  mover_states'[0] == last(other_states')\n    ensures  last(mover_states') == last(mover_states_after)\n    ensures  mover_states' == AtomicGetStateSequence(arr.l, mover_states'[0], mover_paths_before + mover_paths_after, mover_tid)\n    ensures  AtomicNextMultiplePaths(arr.l, mover_states'[0], last(mover_states'), mover_paths_before + mover_paths_after, mover_tid)\n    ensures  PerformRightMoveRemainingPredicate(arr, mover_tid, mover_states_before, mover_states_after, mover_states')\n\n    decreases |mover_paths_before|\n  {\n    lemma_ExecutingPathSequenceDoesntRemoveOtherActorPC(arr, other_states[0], last(other_states), other_paths, other_tau,\n                                                        other_tid, mover_tid);\n    lemma_ExecutingPathSequenceDoesntChangeOtherActorPCType(arr, other_states[0], last(other_states), other_paths, other_tau,\n                                                            other_tid, mover_tid);\n    if |mover_paths_before| == 0 {\n      mover_states' := mover_states_after;\n      other_states' := other_states;\n      assert mover_paths_before + mover_paths_after == mover_paths_after;\n      assert PerformRightMoveRemainingPredicate(arr, mover_tid, mover_states_before, mover_states_after, mover_states');\n    }\n    else {\n      lemma_AtomicInvariantHoldsAtIntermediateState(arr.l, arr.inv, mover_states_before[0], last(mover_states_before), mover_paths_before,\n                                                    mover_tid, mover_states_before, |mover_paths_before|-1);\n      assert arr.inv(mover_states_before[|mover_paths_before|-1]);\n      lemma_AtomicValidPathSequenceOfAnyTypeImpliesValidPath(arr.l, mover_states_before[0], last(mover_states_before), mover_paths_before,\n                                                             mover_tid, mover_states_before, |mover_paths_before|-1);\n      assert arr.l.path_valid(mover_states_before[|mover_paths_before|-1], mover_paths_before[|mover_paths_before|-1], mover_tid);\n      assert arr.l.path_valid(mover_states_before[|mover_paths_before|-1], last(mover_paths_before), mover_tid);\n\n      var other_states_mid :=\n        lemma_PerformRightMoveOne(arr, mover_tid, other_tid, other_tau, last(mover_paths_before),\n                                  mover_states_before[|mover_paths_before|-1], other_paths, other_states);\n\n      lemma_AllButLastPreservesAtomicNextMultiplePaths(arr, mover_states_before[0], last(mover_states_before), mover_paths_before,\n                                                       mover_states_before, mover_tid);\n      calc {\n        other_states_mid[0];\n        mover_states_before[|mover_paths_before|-1];\n        last(all_but_last(mover_states_before));\n      }\n\n      var mover_states_after' := [last(other_states_mid)] + mover_states_after;\n      var mover_paths_after' := [last(mover_paths_before)] + mover_paths_after;\n      assert mover_states_after'[0] == last(other_states_mid);\n      assert mover_states_after'[1..] == mover_states_after;\n      assert mover_paths_after'[0] == last(mover_paths_before);\n      assert mover_paths_after'[1..] == mover_paths_after;\n      assert AtomicNextMultiplePaths(arr.l, mover_states_after'[0], last(mover_states_after'), mover_paths_after', mover_tid);\n\n      mover_states', other_states' :=\n        lemma_PerformRightMoveRemaining(arr, mover_tid, other_tid, other_tau, all_but_last(mover_paths_before),\n                                        all_but_last(mover_states_before), [last(mover_paths_before)] + mover_paths_after,\n                                        [last(other_states_mid)] + mover_states_after, other_paths, other_states_mid);\n      assert PerformRightMoveRemainingPredicate(arr, mover_tid, all_but_last(mover_states_before),\n                                                [last(other_states_mid)] + mover_states_after, mover_states');\n      lemma_PerformRightMoveRemainingHelper1(arr, mover_tid, other_tid, other_tau, mover_paths_before, mover_states_before,\n                                             mover_paths_after, mover_states_after, other_paths, other_states, other_states_mid,\n                                             mover_states', other_states');\n      lemma_PerformRightMoveRemainingHelper2(arr, mover_tid, other_tid, other_tau, mover_paths_before, mover_states_before,\n                                             mover_paths_after, mover_states_after, other_paths, other_states, other_states_mid,\n                                             mover_states', other_states');\n      assert PerformRightMoveRemainingPredicate(arr, mover_tid, mover_states_before, mover_states_after, mover_states');\n    }\n  }\n\n  lemma lemma_PerformRightMoveAll<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    mover_tid:Armada_ThreadHandle,\n    other_tid:Armada_ThreadHandle,\n    other_tau:bool,\n    mover_paths:seq<LPath>,\n    mover_states:seq<LState>,\n    other_paths:seq<LPath>,\n    other_states:seq<LState>\n    ) returns (\n    mover_states':seq<LState>,\n    other_states':seq<LState>\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires other_tau || other_tid != mover_tid\n\n    requires |mover_states| > 0\n    requires arr.inv(mover_states[0])\n    requires arr.l.get_thread_pc(mover_states[0], mover_tid).Some?\n    requires mover_states == AtomicGetStateSequence(arr.l, mover_states[0], mover_paths, mover_tid)\n    requires forall s :: s in mover_states ==> arr.l.get_thread_pc(s, mover_tid).Some?\n    requires forall i :: 0 < i < |mover_states| ==> arr.is_phase1(arr.l.get_thread_pc(mover_states[i], mover_tid).v)\n    requires AtomicNextMultiplePaths(arr.l, mover_states[0], last(mover_states), mover_paths, mover_tid)\n    requires forall path :: path in mover_paths ==> !arr.l.path_type(path).AtomicPathType_Tau?\n\n    requires |other_states| > 0\n    requires arr.l.state_ok(last(other_states))\n    requires other_states[0] == last(mover_states)\n    requires other_states == AtomicGetStateSequence(arr.l, other_states[0], other_paths, other_tid)\n    requires AtomicNextMultiplePaths(arr.l, other_states[0], last(other_states), other_paths, other_tid)\n    requires forall path :: path in other_paths ==> arr.l.path_type(path).AtomicPathType_Tau? == other_tau\n\n    ensures  |other_states'| == |other_states|\n    ensures  other_states'[0] == mover_states[0]\n    ensures  other_states' == AtomicGetStateSequence(arr.l, other_states'[0], other_paths, other_tid)\n    ensures  AtomicNextMultiplePaths(arr.l, other_states'[0], last(other_states'), other_paths, other_tid)\n    ensures  !other_tau ==> forall i :: 0 <= i < |other_states| ==> OKAndPCTypesMatch(arr, other_states'[i], other_states[i], other_tid)\n\n    ensures  |mover_states'| == |mover_states|\n    ensures  mover_states'[0] == last(other_states')\n    ensures  last(mover_states') == last(other_states)\n    ensures  mover_states' == AtomicGetStateSequence(arr.l, mover_states'[0], mover_paths, mover_tid)\n    ensures  AtomicNextMultiplePaths(arr.l, mover_states'[0], last(mover_states'), mover_paths, mover_tid)\n    ensures  forall i :: 0 <= i < |mover_states| ==> OKAndPCTypesMatch(arr, mover_states'[i], mover_states[i], mover_tid)\n  {\n    lemma_ExecutingPathSequenceDoesntRemoveOtherActorPC(arr, other_states[0], last(other_states), other_paths, other_tau,\n                                                        other_tid, mover_tid);\n    lemma_ExecutingPathSequenceDoesntChangeOtherActorPCType(arr, other_states[0], last(other_states), other_paths, other_tau,\n                                                            other_tid, mover_tid);\n\n    mover_states', other_states' := lemma_PerformRightMoveRemaining(arr, mover_tid, other_tid, other_tau, mover_paths,\n                                                                    mover_states, [], [last(other_states)], other_paths, other_states);\n    assert mover_paths + [] == mover_paths;\n\n    if !other_tau {\n      forall i | 0 <= i < |other_states|\n        ensures OKAndPCTypesMatch(arr, other_states'[i], other_states[i], other_tid)\n      {\n        assert PerformRightMoveTrigger(i);\n      }\n    }\n\n    forall i | 0 <= i < |mover_states|\n      ensures OKAndPCTypesMatch(arr, mover_states'[i], mover_states[i], mover_tid)\n    {\n      assert PerformRightMoveTrigger(i);\n    }\n  }\n\n  lemma lemma_PerformRightMove<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    s1:LState,\n    s2:LState,\n    s3:LState,\n    multistep1:Armada_Multistep<LPath>,\n    multistep2:Armada_Multistep<LPath>\n    ) returns (\n    s2':LState\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires s1 in AnnotatedReachables(GetRefinementViaReductionLSpec(arr))\n    requires arr.l.state_ok(s3)\n    requires AtomicNextMultistep(arr.l, s1, s2, multistep1.steps, multistep1.tid, multistep1.tau)\n    requires AtomicNextMultistep(arr.l, s2, s3, multistep2.steps, multistep2.tid, multistep2.tau)\n    requires !multistep1.tau\n    requires multistep2.tau || multistep2.tid != multistep1.tid\n    requires IsPhase1(arr, s2, multistep1.tid)\n    ensures  AtomicNextMultistep(arr.l, s1, s2', multistep2.steps, multistep2.tid, multistep2.tau)\n    ensures  AtomicNextMultistep(arr.l, s2', s3, multistep1.steps, multistep1.tid, multistep1.tau)\n  {\n    lemma_StateAmongAnnotatedReachablesSatisfiesInv(arr, s1);\n    assert arr.inv(s1);\n    var mover_states := AtomicGetStateSequence(arr.l, s1, multistep1.steps, multistep1.tid);\n    lemma_IfMultistepEndsInPhase1ThenEachPathDoes(arr, s1, s2, multistep1, mover_states);\n    var other_states := AtomicGetStateSequence(arr.l, s2, multistep2.steps, multistep2.tid);\n    lemma_AtomicNextLastElement(arr.l, s1, s2, multistep1.steps, multistep1.tid, mover_states);\n    lemma_AtomicNextLastElement(arr.l, s2, s3, multistep2.steps, multistep2.tid, other_states);\n    var mover_states', other_states' :=\n      lemma_PerformRightMoveAll(arr, multistep1.tid, multistep2.tid, multistep2.tau, multistep1.steps, mover_states,\n                                multistep2.steps, other_states);\n    s2' := last(other_states');\n    lemma_AtomicNextLastElement(arr.l, s2', s3, multistep1.steps, multistep1.tid, mover_states');\n  }\n\n  //////////////////////////////////////////\n  // LEFT-MOVER ENABLEMENT LEMMAS\n  //////////////////////////////////////////\n\n  lemma lemma_GenerateLeftMoverSequenceOfSubpaths<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    s:LState,\n    tid:Armada_ThreadHandle\n    ) returns (\n    states:seq<LState>,\n    trace:seq<LPath>\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires arr.inv(s)\n    requires arr.l.state_ok(s)\n    requires IsPhase2(arr, s, tid)\n    requires AtomicThreadYielding(arr.l, s, tid)\n    ensures  states == AtomicGetStateSequence(arr.l, s, trace, tid)\n    ensures  AtomicNextMultiplePaths(arr.l, s, last(states), trace, tid)\n    ensures  states[0] == s\n    ensures  arr.l.state_ok(last(states)) ==> !IsPhase2(arr, last(states), tid) && AtomicThreadYielding(arr.l, last(states), tid)\n    ensures  forall i :: 0 <= i < |states|-1 ==> IsPhase2(arr, states[i], tid)\n    ensures  forall path :: path in trace ==> !arr.l.path_type(path).AtomicPathType_Tau?\n  {\n    states := [s];\n    trace := [];\n\n    while arr.l.state_ok(last(states)) && IsPhase2(arr, last(states), tid)\n      invariant states == AtomicGetStateSequence(arr.l, s, trace, tid)\n      invariant AtomicNextMultiplePaths(arr.l, s, last(states), trace, tid)\n      invariant states[0] == s\n      invariant arr.inv(last(states))\n      invariant arr.l.state_ok(last(states)) && !AtomicThreadYielding(arr.l, last(states), tid) ==> IsPhase2(arr, last(states), tid)\n      invariant forall i :: 0 <= i < |states|-1 ==> IsPhase2(arr, states[i], tid)\n      invariant forall path :: path in trace ==> !arr.l.path_type(path).AtomicPathType_Tau?\n      decreases arr.left_mover_generation_progress(last(states), tid)\n    {\n      var states_current := states;\n      forall i | 0 <= i < |states_current|\n        ensures IsPhase2(arr, states_current[i], tid)\n      {\n        if i < |states|-1 {\n          assert IsPhase2(arr, states[i], tid);\n        }\n        else {\n          assert states_current[i] == last(states);\n        }\n      }\n\n      var s_current := last(states);\n      var path := arr.generate_left_mover(s_current, tid);\n      assert AtomicReductionSpecModule.LeftMoversAlwaysEnabledConditions(arr, s_current, tid);\n      assert arr.l.path_valid(s_current, path, tid) && !arr.l.path_type(path).AtomicPathType_Tau?;\n      var s_next := arr.l.path_next(s_current, path, tid);\n      assert 0 <= arr.left_mover_generation_progress(s_next, tid) < arr.left_mover_generation_progress(s_current, tid);\n      lemma_ExtendingStateSequenceWorks(arr.l, s, s_current, trace, states, tid, path, s_next);\n      trace := trace + [path];\n      states := states + [s_next];\n\n      forall i | 0 <= i < |states|-1\n        ensures IsPhase2(arr, states[i], tid)\n      {\n        assert states[i] == states_current[i];\n      }\n    }\n  }\n\n  lemma lemma_GenerateLeftMoverSequence<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    s:LState,\n    tid:Armada_ThreadHandle\n    ) returns (\n    states:seq<LState>,\n    trace:seq<Armada_Multistep<LPath>>\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires arr.inv(s)\n    requires arr.l.state_ok(s)\n    requires IsPhase2(arr, s, tid)\n    requires AtomicThreadYielding(arr.l, s, tid)\n    ensures  StateNextSeq(states, trace, GetRefinementViaReductionLSpec(arr).next)\n    ensures  states[0] == s\n    ensures  arr.l.state_ok(last(states)) ==> !IsPhase2(arr, last(states), tid) && AtomicThreadYielding(arr.l, last(states), tid)\n    ensures  forall i :: 0 <= i < |states|-1 ==> IsPhase2(arr, states[i], tid)\n    ensures  forall multistep :: multistep in trace ==> !multistep.tau && multistep.tid == tid\n  {\n    var rspec := GetRefinementViaReductionLSpec(arr);\n    var single_states, single_trace := lemma_GenerateLeftMoverSequenceOfSubpaths(arr, s, tid);\n\n    states := [s];\n    trace := [];\n    var partial_paths := [];\n    var partial_states := [s];\n\n    var pos := 0;\n\n    assert !arr.l.state_ok(single_states[pos]) || AtomicThreadYielding(arr.l, single_states[pos], tid) ==> |partial_paths| == 0;\n    while pos < |single_trace|\n      invariant 0 <= pos <= |single_trace|\n      invariant |states| > 0\n      invariant states[0] == s\n      invariant StateNextSeq(states, trace, GetRefinementViaReductionLSpec(arr).next)\n      invariant if pos < |single_trace| then\n                  (forall state :: state in states ==> IsPhase2(arr, state, tid))\n                else\n                  (forall i :: 0 <= i < |states|-1 ==> IsPhase2(arr, states[i], tid))\n      invariant forall multistep :: multistep in trace ==> !multistep.tau && multistep.tid == tid\n      invariant !arr.l.state_ok(last(states)) || AtomicThreadYielding(arr.l, last(states), tid)\n      invariant !arr.l.state_ok(single_states[pos]) || AtomicThreadYielding(arr.l, single_states[pos], tid) ==> |partial_paths| == 0\n      invariant AtomicNextMultiplePaths(arr.l, last(states), single_states[pos], partial_paths, tid)\n      invariant partial_states == AtomicGetStateSequence(arr.l, last(states), partial_paths, tid)\n      invariant forall i :: 0 < i < |partial_states| ==> !AtomicThreadYielding(arr.l, partial_states[i], tid)\n      invariant forall path :: path in partial_paths ==> !arr.l.path_type(path).AtomicPathType_Tau?\n      decreases |single_trace| - pos\n    {\n      var s_current := single_states[pos];\n      var s_next := single_states[pos+1];\n      var next_path := single_trace[pos];\n\n      lemma_AtomicValidPathSequenceOfAnyTypeImpliesValidPath(arr.l, single_states[0], last(single_states), single_trace, tid,\n                                                             single_states, pos);\n      assert arr.l.path_valid(s_current, next_path, tid);\n      assert s_next == arr.l.path_next(s_current, next_path, tid);\n\n      lemma_ExtendingStateSequenceWorks(arr.l, last(states), s_current, partial_paths, partial_states, tid, next_path, s_next);\n\n      var upper := |partial_states|;\n      assert forall i :: 0 < i < upper ==> !AtomicThreadYielding(arr.l, partial_states[i], tid);\n      partial_paths := partial_paths + [next_path];\n      partial_states := partial_states + [s_next];\n      assert upper == |partial_paths|;\n      assert forall i :: 0 < i < |partial_paths| ==> !AtomicThreadYielding(arr.l, partial_states[i], tid);\n\n      if !arr.l.state_ok(s_next) || AtomicThreadYielding(arr.l, s_next, tid) {\n        var multistep := Armada_Multistep(partial_paths, tid, false);\n\n        assert AtomicNextMultistep(arr.l, last(states), s_next, multistep.steps, multistep.tid, multistep.tau);\n        assert ActionTuple(last(states), s_next, multistep) in rspec.next;\n\n        var states_next := states + [s_next];\n        var trace_next := trace + [multistep];\n\n        forall i | 0 <= i < |trace_next|\n          ensures ActionTuple(states_next[i], states_next[i+1], trace_next[i]) in rspec.next\n        {\n          if i < |trace| {\n            assert ActionTuple(states[i], states[i+1], trace[i]) in rspec.next;\n            assert states_next[i] == states[i];\n            assert states_next[i+1] == states[i+1];\n            assert trace_next[i] == trace[i];\n          }\n          else {\n            assert i == |trace| == |states|-1;\n            assert states_next[i] == states[i] == last(states);\n            assert states_next[i+1] == s_next;\n            assert trace_next[i] == multistep;\n          }\n        }\n\n        states := states_next;\n        trace := trace_next;\n        partial_paths := [];\n        partial_states := [s_next];\n           \n        assert StateNextSeq(states, trace, rspec.next);\n      }\n      pos := pos + 1;\n      assert AtomicNextMultiplePaths(arr.l, last(states), single_states[pos], partial_paths, tid);\n    }\n\n    assert |partial_paths| == 0;\n    assert pos == |single_trace|;\n    assert last(states) == single_states[pos] == last(single_states);\n  }\n\n  lemma lemma_LeftMoversAlwaysEnabled<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    )\n    requires ValidAtomicReductionRequest(arr)\n    ensures  RefinementViaReductionSpecModule.LeftMoversAlwaysEnabled(GetRefinementViaReductionRequest(arr))\n  {\n    var rr := GetRefinementViaReductionRequest(arr);\n    forall s, actor |\n      && s in AnnotatedReachables(rr.lspec)\n      && rr.phase2(s, actor)\n      && !rr.crashed(s)\n      ensures exists states, trace ::\n                 && StateNextSeq(states, trace, rr.lspec.next)\n                 && states[0] == s\n                 && (!arr.l.state_ok(last(states)) || !rr.phase2(last(states), actor))\n                 && (forall i :: 0 <= i < |states|-1 ==> rr.phase2(states[i], actor))\n                 && (forall path :: path in trace ==> rr.idmap(path) == actor)\n    {\n      lemma_StateAmongAnnotatedReachablesSatisfiesInv(arr, s);\n      assert actor.Some?;\n      lemma_StateAmongAnnotatedReachablesHasThreadYielding(arr, s, actor.v);\n      var states, trace := lemma_GenerateLeftMoverSequence(arr, s, actor.v);\n    }\n  }\n\n  ////////////////////////////////////////////\n  // LEMMAS ABOUT LIFTING ACTION SEQUENCES\n  ////////////////////////////////////////////\n\n  function CombineMultisteps<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    trace:seq<Armada_Multistep<LPath>>\n    ) : seq<LPath>\n  {\n    if |trace| == 0 then [] else trace[0].steps + CombineMultisteps(arr, trace[1..])\n  }\n\n  lemma lemma_CombineMultistepsEffectOnGetStateSequence<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    states:seq<LState>,\n    trace:seq<Armada_Multistep<LPath>>,\n    tid:Armada_ThreadHandle\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires |trace| > 0\n    requires |states| == |trace| + 1\n    requires forall i :: 0 <= i < |trace| ==> AtomicNextMultiplePaths(arr.l, states[i], states[i+1], trace[i].steps, tid)\n    ensures  AtomicGetStateSequence(arr.l, states[0], CombineMultisteps(arr, trace), tid) ==\n             AtomicGetStateSequence(arr.l, states[0], trace[0].steps, tid) +\n             AtomicGetStateSequence(arr.l, states[1], CombineMultisteps(arr, trace[1..]), tid)[1..]\n    decreases |trace[0].steps|\n  {\n    var pos := 0;\n    assert AtomicNextMultiplePaths(arr.l, states[pos], states[pos+1], trace[pos].steps, tid);\n    var multistep := trace[0];\n\n    if |multistep.steps| == 0 {\n      calc {\n        AtomicGetStateSequence(arr.l, states[0], trace[0].steps, tid) +\n          AtomicGetStateSequence(arr.l, states[1], CombineMultisteps(arr, trace[1..]), tid)[1..];\n         { assert trace[0].steps == [];\n           assert AtomicGetStateSequence(arr.l, states[0], trace[0].steps, tid) == [states[0]]; }\n        [states[0]] + AtomicGetStateSequence(arr.l, states[1], CombineMultisteps(arr, trace[1..]), tid)[1..];\n          { assert states[1] == states[0]; }\n        [states[0]] + AtomicGetStateSequence(arr.l, states[0], CombineMultisteps(arr, trace[1..]), tid)[1..];\n          { assert AtomicGetStateSequence(arr.l, states[0], CombineMultisteps(arr, trace[1..]), tid)[0] == states[0]; }\n        AtomicGetStateSequence(arr.l, states[0], CombineMultisteps(arr, trace[1..]), tid);\n          { assert CombineMultisteps(arr, trace) == CombineMultisteps(arr, trace[1..]); }\n        AtomicGetStateSequence(arr.l, states[0], CombineMultisteps(arr, trace), tid);\n      }\n    }\n    else {\n      var s_mid := arr.l.path_next(states[0], multistep.steps[0], tid);\n      var new_trace0 := multistep.(steps := multistep.steps[1..]);\n      var states' := states[0 := s_mid];\n      var trace' := trace[0 := new_trace0];\n\n      forall i {:trigger ActionTuple(states'[i], states'[i+1], trace'[i]) in GetRefinementViaReductionLSpec(arr).next} | 0 <= i < |trace'|\n        ensures AtomicNextMultiplePaths(arr.l, states'[i], states'[i+1], trace'[i].steps, tid);\n      {\n        assert AtomicNextMultiplePaths(arr.l, states[i], states[i+1], trace[i].steps, tid);\n        if i == 0 {\n          assert states'[i] == s_mid;\n          assert states'[i+1] == states[1];\n          assert trace'[i] == new_trace0;\n        }\n        else {\n          assert states'[i] == states[i];\n          assert states'[i+1] == states[i+1];\n          assert trace'[i] == trace[i];\n        }\n      }\n\n      lemma_CombineMultistepsEffectOnGetStateSequence(arr, states', trace', tid);\n      assert AtomicGetStateSequence(arr.l, states'[0], CombineMultisteps(arr, trace'), tid) ==\n             AtomicGetStateSequence(arr.l, states'[0], trace'[0].steps, tid) +\n             AtomicGetStateSequence(arr.l, states'[1], CombineMultisteps(arr, trace'[1..]), tid)[1..];\n\n      calc {\n        CombineMultisteps(arr, trace');\n        trace'[0].steps + CombineMultisteps(arr, trace'[1..]);\n        new_trace0.steps + CombineMultisteps(arr, trace'[1..]);\n        multistep.steps[1..] + CombineMultisteps(arr, trace[1..]);\n          { lemma_DroppingHeadOfConcatenation(multistep.steps, CombineMultisteps(arr, trace[1..])); }\n        (multistep.steps + CombineMultisteps(arr, trace[1..]))[1..];\n        CombineMultisteps(arr, trace)[1..];\n      }\n\n      calc {\n        AtomicGetStateSequence(arr.l, states[0], CombineMultisteps(arr, trace), tid);\n        [states[0]] + AtomicGetStateSequence(arr.l, s_mid, CombineMultisteps(arr, trace)[1..], tid);\n        [states[0]] + AtomicGetStateSequence(arr.l, states'[0], CombineMultisteps(arr, trace)[1..], tid);\n          { assert CombineMultisteps(arr, trace') == CombineMultisteps(arr, trace)[1..]; }\n        [states[0]] + AtomicGetStateSequence(arr.l, states'[0], CombineMultisteps(arr, trace'), tid);\n          { assert AtomicGetStateSequence(arr.l, states'[0], CombineMultisteps(arr, trace'), tid) ==\n                   AtomicGetStateSequence(arr.l, states'[0], trace'[0].steps, tid) +\n                   AtomicGetStateSequence(arr.l, states'[1], CombineMultisteps(arr, trace'[1..]), tid)[1..]; }\n        [states[0]] + (AtomicGetStateSequence(arr.l, states'[0], trace'[0].steps, tid) +\n                       AtomicGetStateSequence(arr.l, states'[1], CombineMultisteps(arr, trace'[1..]), tid)[1..]);\n          { lemma_SequenceConcatenationAssociative(\n              [states[0]],\n              AtomicGetStateSequence(arr.l, states'[0], trace'[0].steps, tid),\n              AtomicGetStateSequence(arr.l, states'[1], CombineMultisteps(arr, trace'[1..]), tid)[1..]); }\n        [states[0]] + AtomicGetStateSequence(arr.l, states'[0], trace'[0].steps, tid) +\n             AtomicGetStateSequence(arr.l, states'[1], CombineMultisteps(arr, trace'[1..]), tid)[1..];\n        [states[0]] + AtomicGetStateSequence(arr.l, states'[0], trace'[0].steps, tid) +\n             AtomicGetStateSequence(arr.l, states[1], CombineMultisteps(arr, trace'[1..]), tid)[1..];\n        [states[0]] + AtomicGetStateSequence(arr.l, states'[0], trace'[0].steps, tid) +\n             AtomicGetStateSequence(arr.l, states[1], CombineMultisteps(arr, trace[1..]), tid)[1..];\n        AtomicGetStateSequence(arr.l, states[0], trace[0].steps, tid) +\n          AtomicGetStateSequence(arr.l, states[1], CombineMultisteps(arr, trace[1..]), tid)[1..];\n\n      }\n    }\n  }\n\n  lemma lemma_CombineMultistepsCreatesValidHPathHelper<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    s:LState,\n    s':LState,\n    multistep:Armada_Multistep<LPath>,\n    states:seq<LState>,\n    i:int\n    )\n    requires states == AtomicGetStateSequence(arr.l, s, multistep.steps, multistep.tid)\n    requires !multistep.tau\n    requires AtomicNextMultistep(arr.l, s, s', multistep.steps, multistep.tid, multistep.tau)\n    requires 0 < i < |states|\n    requires i == |states|-1 ==> arr.l.state_ok(s')\n    requires i == |states|-1 ==> IsPhase1(arr, s', multistep.tid) || IsPhase2(arr, s', multistep.tid)\n    ensures  IsNonyieldingOrInPhase(arr, states[i], multistep.tid)\n  {\n    var pc := arr.l.get_thread_pc(states[i], multistep.tid);\n    if i < |states|-1 {\n      assert pc.Some? && arr.l.is_pc_nonyielding(pc.v);\n    }\n    else {\n      assert i == |states|-1;\n      assert states[i] == last(states);\n      lemma_AtomicNextLastElement(arr.l, s, s', multistep.steps, multistep.tid, states);\n      assert last(states) == s';\n      assert IsPhase1(arr, states[i], multistep.tid) || IsPhase2(arr, states[i], multistep.tid);\n      assert pc.Some? && (arr.is_phase1(pc.v) || arr.is_phase2(pc.v));\n    }\n    assert IsNonyieldingOrInPhase(arr, states[i], multistep.tid);\n  }\n\n  lemma lemma_CombineMultistepsCreatesValidHPath<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    states:seq<LState>,\n    trace:seq<Armada_Multistep<LPath>>,\n    tid:Armada_ThreadHandle,\n    combined:seq<LPath>,\n    all_states:seq<LState>\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires StateNextSeq(states, trace, GetRefinementViaReductionLSpec(arr).next)\n    requires forall multistep :: multistep in trace ==> !multistep.tau && multistep.tid == tid\n    requires combined == CombineMultisteps(arr, trace)\n    requires forall i :: 0 < i < |trace| ==> arr.l.state_ok(states[i])\n    requires forall i :: 0 < i < |trace| ==> IsPhase1(arr, states[i], tid) || IsPhase2(arr, states[i], tid)\n    requires all_states == AtomicGetStateSequence(arr.l, states[0], combined, tid)\n    ensures  forall i :: 0 < i < |combined| ==> IsNonyieldingOrInPhase(arr, all_states[i], tid)\n  {\n    var rspec := GetRefinementViaReductionLSpec(arr);\n\n    if |trace| > 0 {\n      forall i | 0 <= i < |trace|\n        ensures AtomicNextMultiplePaths(arr.l, states[i], states[i+1], trace[i].steps, tid)\n      {\n        assert ActionTuple(states[i], states[i+1], trace[i]) in rspec.next;\n      }\n      \n      lemma_CombineMultistepsEffectOnGetStateSequence(arr, states, trace, tid);\n\n      var states' := states[1..];\n      var trace' := trace[1..];\n      var combined' := CombineMultisteps(arr, trace');\n      var all_states' := AtomicGetStateSequence(arr.l, states'[0], combined', tid);\n\n      forall i {:trigger ActionTuple(states'[i], states'[i+1], trace'[i]) in rspec.next} | 0 <= i < |trace'|\n        ensures ActionTuple(states'[i], states'[i+1], trace'[i]) in rspec.next\n      {\n        var next := i+1;\n        assert ActionTuple(states[next], states[next+1], trace[next]) in rspec.next;\n      }\n\n      lemma_CombineMultistepsCreatesValidHPath(arr, states[1..], trace[1..], tid, combined', all_states');\n\n      var multistep := trace[0];\n      assert multistep.tid == tid;\n      var first_states := AtomicGetStateSequence(arr.l, states[0], multistep.steps, tid);\n      assert all_states == first_states + all_states'[1..];\n      forall i | 0 < i < |combined|\n        ensures IsNonyieldingOrInPhase(arr, all_states[i], tid)\n      {\n        if i < |first_states| {\n          var zero := 0;\n          assert ActionTuple(states[zero], states[zero+1], trace[zero]) in rspec.next;\n          assert AtomicNextMultistep(arr.l, states[zero], states[zero+1], multistep.steps, multistep.tid, multistep.tau);\n          var one := zero+1;\n          lemma_AtomicNextLastElement(arr.l, states[zero], states[zero+1], multistep.steps, multistep.tid, first_states);\n          assert all_states[i] == first_states[i];\n          if i == |first_states|-1 {\n            assert |combined| > |combined'|;\n            assert |states| > 2;\n            assert 0 < one < |trace|;\n            assert arr.l.state_ok(states[one]);\n            assert IsPhase1(arr, states[one], tid) || IsPhase2(arr, states[one], tid);\n          }\n          lemma_CombineMultistepsCreatesValidHPathHelper(arr, states[zero], states[one], multistep, first_states, i);\n          assert IsNonyieldingOrInPhase(arr, all_states[i], tid);\n        }\n        else {\n          calc {\n            all_states[i];\n            (first_states + all_states'[1..])[i];\n              { lemma_IndexIntoConcatenation(first_states, all_states'[1..], i); }\n            all_states'[1..][i - |first_states|];\n              { lemma_IndexIntoDrop(all_states', 1, i - |first_states|); }\n            all_states'[1 + i - |first_states|];\n          }\n          var pos := 1 + i - |first_states|;\n          assert 0 < pos < |combined'|;\n          assert IsNonyieldingOrInPhase(arr, all_states'[pos], tid);\n          assert IsNonyieldingOrInPhase(arr, all_states[i], tid);\n        }\n      }\n    }\n  }\n\n  lemma lemma_CombineMultistepsPreservesStateNextSeq<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    states:seq<LState>,\n    trace:seq<Armada_Multistep<LPath>>,\n    tid:Armada_ThreadHandle,\n    combined:seq<LPath>\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires StateNextSeq(states, trace, GetRefinementViaReductionLSpec(arr).next)\n    requires forall multistep :: multistep in trace ==> !multistep.tau && multistep.tid == tid\n    requires combined == CombineMultisteps(arr, trace)\n    ensures  AtomicNextMultiplePaths(arr.l, states[0], last(states), combined, tid)\n    ensures  forall path :: path in combined ==> !arr.l.path_type(path).AtomicPathType_Tau?\n  {\n    var rspec := GetRefinementViaReductionLSpec(arr);\n\n    if |trace| > 0 {\n      var pos := 0;\n      assert ActionTuple(states[pos], states[pos+1], trace[pos]) in rspec.next;\n      var multistep := trace[0];\n      assert AtomicNextMultistep(arr.l, states[pos], states[pos+1], multistep.steps, multistep.tid, multistep.tau);\n\n      var states' := states[1..];\n      var trace' := trace[1..];\n\n      forall i {:trigger ActionTuple(states'[i], states'[i+1], trace'[i]) in rspec.next} | 0 <= i < |trace'|\n        ensures ActionTuple(states'[i], states'[i+1], trace'[i]) in rspec.next\n      {\n        var next := i+1;\n        assert ActionTuple(states[next], states[next+1], trace[next]) in rspec.next;\n        assert states'[i] == states[next];\n        assert states'[i+1] == states[next+1];\n        assert trace'[i] == trace[next];\n      }\n\n      var combined' := CombineMultisteps(arr, trace');\n      lemma_CombineMultistepsPreservesStateNextSeq(arr, states', trace', tid, combined');\n      lemma_AtomicNextMultiplePathsTransitive(arr, states[0], states[1], last(states), multistep.steps, combined', tid);\n    }\n  }\n\n  lemma lemma_LiftActionSequenceCaseMultiplePaths<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    rr:RefinementViaReductionRequest<LState, Option<Armada_ThreadHandle>, Armada_Multistep<LPath>, Armada_Multistep<LPath>>,\n    states:seq<LState>,\n    trace:seq<Armada_Multistep<LPath>>,\n    actor:Option<Armada_ThreadHandle>\n    ) returns (\n    hmultistep:Armada_Multistep<LPath>\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires rr == GetRefinementViaReductionRequest(arr)\n    requires StateNextSeq(states, trace, GetRefinementViaReductionLSpec(arr).next)\n    requires forall multistep :: multistep in trace ==> rr.idmap(multistep) == actor\n    requires !rr.phase1(states[0], actor)\n    requires !rr.phase2(states[0], actor)\n    requires var s := last(states); !rr.crashed(s) ==> !rr.phase1(s, actor) && !rr.phase2(s, actor)\n    requires forall i :: 0 < i < |trace| ==> !rr.crashed(states[i])\n    requires forall i :: 0 < i < |trace| ==> var s := states[i]; rr.phase1(s, actor) || rr.phase2(s, actor)\n    requires |trace| > 1\n    requires actor.Some?\n    ensures  ActionTuple(states[0], last(states), hmultistep) in rr.hspec.next\n  {\n    var rspec := GetRefinementViaReductionLSpec(arr);\n\n    var pos := 0;\n    assert ActionTuple(states[pos], states[pos+1], trace[pos]) in rspec.next;\n    assert rr.idmap(trace[pos]) == actor;\n    assert !IsNonyieldingOrInPhase(arr, states[0], actor.v);\n\n    pos := |trace|-1;\n    assert ActionTuple(states[pos], states[pos+1], trace[pos]) in rspec.next;\n    assert rr.idmap(trace[pos]) == actor;\n    assert !IsNonyieldingOrInPhase(arr, last(states), actor.v);\n\n    var paths := CombineMultisteps(arr, trace);\n    hmultistep := Armada_Multistep(paths, actor.v, false);\n    lemma_CombineMultistepsPreservesStateNextSeq(arr, states, trace, actor.v, paths);\n\n    var all_states := AtomicGetStateSequence(arr.l, states[0], paths, actor.v);\n    forall i | 1 <= i < |states|-1\n      ensures IsPhase1(arr, states[i], actor.v) || IsPhase2(arr, states[i], actor.v)\n    {\n      assert rr.phase1(states[i], actor) || rr.phase2(states[i], actor);\n    }\n\n    lemma_CombineMultistepsCreatesValidHPath(arr, states, trace, actor.v, paths, all_states);\n    assert GenericNextReduced(arr, states[0], last(states), paths, actor.v, false);\n  }\n\n  lemma lemma_LiftActionSequenceCasePath<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    rr:RefinementViaReductionRequest<LState, Option<Armada_ThreadHandle>, Armada_Multistep<LPath>, Armada_Multistep<LPath>>,\n    states:seq<LState>,\n    trace:seq<Armada_Multistep<LPath>>,\n    actor:Option<Armada_ThreadHandle>\n    ) returns (\n    hmultistep:Armada_Multistep<LPath>\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires rr == GetRefinementViaReductionRequest(arr)\n    requires StateNextSeq(states, trace, GetRefinementViaReductionLSpec(arr).next)\n    requires forall multistep :: multistep in trace ==> rr.idmap(multistep) == actor\n    requires !rr.phase1(states[0], actor)\n    requires !rr.phase2(states[0], actor)\n    requires var s := last(states); !rr.crashed(s) ==> !rr.phase1(s, actor) && !rr.phase2(s, actor)\n    requires forall i :: 1 <= i < |states|-1 ==> rr.phase1(states[i], actor) || rr.phase2(states[i], actor)\n    requires |trace| == 1\n    ensures  ActionTuple(states[0], last(states), hmultistep) in rr.hspec.next\n  {\n    var s := states[0];\n    var s' := last(states);\n    hmultistep := trace[0];\n    var pos := 0;\n    assert ActionTuple(states[pos], states[pos+1], trace[pos]) in GetRefinementViaReductionLSpec(arr).next;\n    assert AtomicNextMultistep(arr.l, states[0], states[0+1], hmultistep.steps, hmultistep.tid, hmultistep.tau);\n    assert rr.idmap(trace[0]) == actor;\n    assert !hmultistep.tau ==> actor == Some(hmultistep.tid);\n    assert GenericNextReduced(arr, s, s', hmultistep.steps, hmultistep.tid, hmultistep.tau);\n  }\n\n  lemma lemma_LiftActionSequenceCaseTau<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    rr:RefinementViaReductionRequest<LState, Option<Armada_ThreadHandle>, Armada_Multistep<LPath>, Armada_Multistep<LPath>>,\n    states:seq<LState>,\n    trace:seq<Armada_Multistep<LPath>>,\n    actor:Option<Armada_ThreadHandle>\n    ) returns (\n    hmultistep:Armada_Multistep<LPath>\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires rr == GetRefinementViaReductionRequest(arr)\n    requires StateNextSeq(states, trace, GetRefinementViaReductionLSpec(arr).next)\n    requires forall multistep :: multistep in trace ==> rr.idmap(multistep) == actor\n    requires !rr.phase1(states[0], actor)\n    requires !rr.phase2(states[0], actor)\n    requires var s := last(states); !rr.crashed(s) ==> !rr.phase1(s, actor) && !rr.phase2(s, actor)\n    requires forall i :: 1 <= i < |states|-1 ==> rr.phase1(states[i], actor) || rr.phase2(states[i], actor)\n    requires |trace| > 1\n    requires actor.None?\n    ensures  ActionTuple(states[0], last(states), hmultistep) in rr.hspec.next\n  {\n    var pos := 1;\n    assert 1 <= pos < |states|-1;\n    assert rr.phase1(states[pos], actor) || rr.phase2(states[pos], actor);\n    assert false;\n  }\n\n  lemma lemma_LiftActionSequence<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    rr:RefinementViaReductionRequest<LState, Option<Armada_ThreadHandle>, Armada_Multistep<LPath>, Armada_Multistep<LPath>>,\n    states:seq<LState>,\n    trace:seq<Armada_Multistep<LPath>>,\n    actor:Option<Armada_ThreadHandle>\n    ) returns (\n    hmultistep:Armada_Multistep<LPath>\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires rr == GetRefinementViaReductionRequest(arr)\n    requires StateNextSeq(states, trace, GetRefinementViaReductionLSpec(arr).next)\n    requires forall multistep :: multistep in trace ==> rr.idmap(multistep) == actor\n    requires |states| > 1\n    requires !rr.phase1(states[0], actor)\n    requires !rr.phase2(states[0], actor)\n    requires var s := last(states); !rr.crashed(s) ==> !rr.phase1(s, actor) && !rr.phase2(s, actor)\n    requires forall i :: 0 < i < |trace| ==> !rr.crashed(states[i])\n    requires forall i :: 0 < i < |trace| ==> rr.phase1(states[i], actor) || rr.phase2(states[i], actor)\n    ensures  ActionTuple(states[0], last(states), hmultistep) in rr.hspec.next\n  {\n    if |trace| == 1 {\n      hmultistep := lemma_LiftActionSequenceCasePath(arr, rr, states, trace, actor);\n    }\n    else if actor.None? {\n      hmultistep := lemma_LiftActionSequenceCaseTau(arr, rr, states, trace, actor);\n    }\n    else {\n      hmultistep := lemma_LiftActionSequenceCaseMultiplePaths(arr, rr, states, trace, actor);\n    }\n  }\n\n  lemma lemma_ActionSequencesLiftable<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    )\n    requires ValidAtomicReductionRequest(arr)\n    ensures  ActionSequencesLiftable(GetRefinementViaReductionRequest(arr))\n  {\n    var rr := GetRefinementViaReductionRequest(arr);\n    forall states, trace, actor\n      {:trigger RefinementViaReductionSpecModule.ActionSequencesLiftableConditions(rr, states, trace, actor)}\n      | RefinementViaReductionSpecModule.ActionSequencesLiftableConditions(rr, states, trace, actor)\n      ensures exists hmultistep :: ActionTuple(states[0], last(states), hmultistep) in rr.hspec.next\n    {\n      var hmultistep := lemma_LiftActionSequence(arr, rr, states, trace, actor);\n    }\n  }\n\n  //////////////////////////////////////////////////////////////////////////\n  // LEMMAS PROVING VALIDITY OF GENERATED CRASHING REDUCTION REQUEST\n  //////////////////////////////////////////////////////////////////////////\n\n  lemma lemma_IfAtomicReductionRequestValidThenCrashingCantGoDirectlyFromPhase2ToPhase1<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    )\n    requires ValidAtomicReductionRequest(arr)\n    ensures  CantGoDirectlyFromPhase2ToPhase1(GetRefinementViaReductionRequest(arr))\n  {\n    var rr := GetRefinementViaReductionRequest(arr);\n    forall s, s', multistep | ActionTuple(s, s', multistep) in rr.lspec.next && rr.phase2(s, rr.idmap(multistep))\n      ensures !rr.phase1(s', rr.idmap(multistep))\n    {\n      assert AtomicNextMultistep(arr.l, s, s', multistep.steps, multistep.tid, multistep.tau);\n      var tid := multistep.tid;\n      if |multistep.steps| > 0 {\n        var states := AtomicGetStateSequence(arr.l, s, multistep.steps, multistep.tid);\n        var pos := 0;\n        while pos < |multistep.steps|-1\n          invariant 0 <= pos < |multistep.steps|\n          invariant IsPhase2(arr, states[pos], tid)\n          decreases |multistep.steps| - pos\n        {\n          lemma_AtomicValidPathSequenceOfAnyTypeImpliesValidPath(arr.l, s, s', multistep.steps, multistep.tid, states, pos);\n          assert arr.l.path_valid(states[pos], multistep.steps[pos], multistep.tid);\n          assert states[pos+1] == arr.l.path_next(states[pos], multistep.steps[pos], multistep.tid);\n          var next_pos := pos+1;\n          var pc := arr.l.get_thread_pc(states[next_pos], tid).v;\n          assert arr.l.is_pc_nonyielding(pc);\n          pos := pos+1;\n        }\n        lemma_AtomicValidPathSequenceOfAnyTypeImpliesValidPath(arr.l, s, s', multistep.steps, multistep.tid, states, pos);\n        lemma_AtomicNextLastElement(arr.l, s, s', multistep.steps, multistep.tid, states);\n      }\n    }\n  }\n\n  lemma lemma_IfAtomicReductionRequestValidThenCrashingPhaseUnaffectedByOtherActorsHelper<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    )\n    requires ValidAtomicReductionRequest(arr)\n    ensures  var rr := GetRefinementViaReductionRequest(arr);\n             forall s, s', multistep, actor :: ActionTuple(s, s', multistep) in rr.lspec.next && rr.idmap(multistep) != actor\n                ==> && (rr.phase1(s, actor) <==> rr.phase1(s', actor))\n                    && (rr.phase2(s, actor) <==> rr.phase2(s', actor))\n  {\n    var rr := GetRefinementViaReductionRequest(arr);\n    forall s, s', multistep, actor | ActionTuple(s, s', multistep) in rr.lspec.next && rr.idmap(multistep) != actor\n      ensures rr.phase1(s, actor) <==> rr.phase1(s', actor)\n      ensures rr.phase2(s, actor) <==> rr.phase2(s', actor)\n    {\n      if actor.Some? {\n        assert AtomicNextMultistep(arr.l, s, s', multistep.steps, multistep.tid, multistep.tau);\n        var tid := actor.v;\n        var states := AtomicGetStateSequence(arr.l, s, multistep.steps, multistep.tid);\n        var pc := arr.l.get_thread_pc(s, tid);\n        var phase1 := pc.Some? && arr.is_phase1(pc.v);\n        var phase2 := pc.Some? && arr.is_phase2(pc.v);\n        var pos := 0;\n        while pos < |multistep.steps|\n          invariant 0 <= pos <= |multistep.steps|\n          invariant phase1 <==> IsPhase1(arr, states[pos], tid)\n          invariant phase2 <==> IsPhase2(arr, states[pos], tid)\n          decreases |multistep.steps| - pos\n        {\n          lemma_AtomicValidPathSequenceOfAnyTypeImpliesValidPath(arr.l, s, s', multistep.steps, multistep.tid, states, pos);\n          assert arr.l.path_valid(states[pos], multistep.steps[pos], multistep.tid);\n          assert states[pos+1] == arr.l.path_next(states[pos], multistep.steps[pos], multistep.tid);\n          var pc1 := arr.l.get_thread_pc(states[pos], tid);\n          var pc2 := arr.l.get_thread_pc(states[pos+1], tid);\n          assert pc1 != pc2 ==> pc1.None? && !arr.is_phase1(pc2.v) && !arr.is_phase2(pc2.v);\n          var next_pos := pos+1;\n          pos := pos+1;\n        }\n        lemma_AtomicNextLastElement(arr.l, s, s', multistep.steps, multistep.tid, states);\n      }\n    }\n  }\n\n  lemma lemma_IfAtomicReductionRequestValidThenCrashingPhaseUnaffectedByOtherActors<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    )\n    requires ValidAtomicReductionRequest(arr)\n    ensures  RefinementViaReductionSpecModule.PhaseUnaffectedByOtherActors(GetRefinementViaReductionRequest(arr))\n  {\n    lemma_IfAtomicReductionRequestValidThenCrashingPhaseUnaffectedByOtherActorsHelper(arr);\n    var rr := GetRefinementViaReductionRequest(arr);\n\n    forall s, s', multistep, actor | ActionTuple(s, s', multistep) in rr.lspec.next && rr.idmap(multistep) != actor\n      ensures rr.phase1(s, actor) <==> rr.phase1(s', actor)\n    {\n      assert && (rr.phase1(s, actor) <==> rr.phase1(s', actor))\n             && (rr.phase2(s, actor) <==> rr.phase2(s', actor));\n    }\n\n    forall s, s', multistep, actor | ActionTuple(s, s', multistep) in rr.lspec.next && rr.idmap(multistep) != actor\n      ensures rr.phase2(s, actor) <==> rr.phase2(s', actor)\n    {\n      assert && (rr.phase1(s, actor) <==> rr.phase1(s', actor))\n             && (rr.phase2(s, actor) <==> rr.phase2(s', actor));\n    }\n  }\n\n  lemma lemma_PostCrashStepsStutter<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    )\n    requires ValidAtomicReductionRequest(arr)\n    ensures  PostCrashStepsStutter(GetRefinementViaReductionRequest(arr))\n  {\n    var rr := GetRefinementViaReductionRequest(arr);\n    forall s, s', multistep | rr.crashed(s) && ActionTuple(s, s', multistep) in GetRefinementViaReductionLSpec(arr).next\n      ensures s' == s\n    {\n      assert AtomicNextMultiplePaths(arr.l, s, s', multistep.steps, multistep.tid);\n      if |multistep.steps| > 0 {\n        assert arr.l.path_valid(s, multistep.steps[0], multistep.tid);\n        assert !arr.l.state_ok(s);\n        assert !arr.l.path_valid(s, multistep.steps[0], multistep.tid);\n        assert false;\n      }\n      else {\n        assert s' == s;\n      }\n    }\n  }\n\n  lemma lemma_RightMoversPreserveStateRefinement<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    )\n    requires ValidAtomicReductionRequest(arr)\n    ensures  RefinementViaReductionSpecModule.RightMoversPreserveStateRefinement(GetRefinementViaReductionRequest(arr))\n  {\n    var rr := GetRefinementViaReductionRequest(arr);\n    forall s, s', multistep |\n      && ActionTuple(s, s', multistep) in rr.lspec.next\n      && rr.phase1(s', rr.idmap(multistep))\n      && arr.l.state_ok(s')\n      ensures RefinementPair(s', s) in rr.relation\n    {\n      assert !multistep.tau;\n      assert AtomicNextMultistep(arr.l, s, s', multistep.steps, multistep.tid, multistep.tau);\n      var tid := multistep.tid;\n      var states := AtomicGetStateSequence(arr.l, s, multistep.steps, multistep.tid);\n      lemma_AtomicNextLastElement(arr.l, s, s', multistep.steps, multistep.tid, states);\n      var pos := |multistep.steps|;\n      while pos > 0\n        invariant 0 <= pos <= |multistep.steps|\n        invariant pos > 0 ==> IsPhase1(arr, states[pos], tid)\n        invariant arr.l.state_ok(states[pos])\n        invariant RefinementPair(s', states[pos]) in rr.relation\n        decreases pos\n      {\n        var prev_pos := pos-1;\n        lemma_AtomicValidPathSequenceOfAnyTypeImpliesValidPath(arr.l, s, s', multistep.steps, multistep.tid, states, prev_pos);\n        assert arr.l.path_valid(states[prev_pos], multistep.steps[prev_pos], multistep.tid);\n        assert states[prev_pos+1] == arr.l.path_next(states[prev_pos], multistep.steps[prev_pos], multistep.tid);\n        assert RefinementPair(states[prev_pos+1], states[prev_pos]) in arr.self_relation;\n        assert RefinementPair(s', states[pos]) in arr.self_relation;\n        assert RefinementPair(s', states[prev_pos]) in arr.self_relation;\n        if prev_pos > 0 {\n          var pc := arr.l.get_thread_pc(states[prev_pos], tid);\n          assert pc.Some? && arr.l.is_pc_nonyielding(pc.v);\n          assert !arr.is_phase2(pc.v);\n          assert arr.is_phase1(pc.v);\n        }\n        pos := pos-1;\n      }\n    }\n  }\n\n  lemma lemma_LeftMoversPreserveStateRefinement<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    )\n    requires ValidAtomicReductionRequest(arr)\n    ensures  RefinementViaReductionSpecModule.LeftMoversPreserveStateRefinement(GetRefinementViaReductionRequest(arr))\n  {\n    var rr := GetRefinementViaReductionRequest(arr);\n    forall s, s', multistep |\n      && ActionTuple(s, s', multistep) in rr.lspec.next\n      && rr.phase2(s, rr.idmap(multistep))\n      ensures RefinementPair(s, s') in rr.relation\n    {\n      assert !multistep.tau;\n      assert AtomicNextMultistep(arr.l, s, s', multistep.steps, multistep.tid, multistep.tau);\n      var tid := multistep.tid;\n      var states := AtomicGetStateSequence(arr.l, s, multistep.steps, multistep.tid);\n      var pos := 0;\n      while pos < |multistep.steps|\n        invariant 0 <= pos <= |multistep.steps|\n        invariant pos < |multistep.steps| ==> IsPhase2(arr, states[pos], tid)\n        invariant RefinementPair(s, states[pos]) in rr.relation\n        decreases |multistep.steps| - pos\n      {\n        lemma_AtomicValidPathSequenceOfAnyTypeImpliesValidPath(arr.l, s, s', multistep.steps, multistep.tid, states, pos);\n        assert arr.l.path_valid(states[pos], multistep.steps[pos], multistep.tid);\n        assert states[pos+1] == arr.l.path_next(states[pos], multistep.steps[pos], multistep.tid);\n        assert RefinementPair(states[pos], states[pos+1]) in arr.self_relation;\n        pos := pos+1;\n      }\n      lemma_AtomicNextLastElement(arr.l, s, s', multistep.steps, multistep.tid, states);\n    }\n  }\n\n  lemma lemma_MoveLeftMoverLeftOneAsSinglePath<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    mover_tid:Armada_ThreadHandle,\n    other_tid:Armada_ThreadHandle,\n    other_tau:bool,\n    initial_state:LState,\n    state_after_other_path:LState,\n    state_after_both_paths:LState,\n    mover_path:LPath,\n    other_path:LPath\n    ) returns (\n    state_after_mover_path:LState\n    )\n    requires ValidAtomicReductionRequest(arr)\n\n    requires arr.inv(initial_state)\n    requires arr.l.path_valid(initial_state, other_path, other_tid)\n    requires state_after_other_path == arr.l.path_next(initial_state, other_path, other_tid)\n    requires arr.l.path_type(other_path).AtomicPathType_Tau? == other_tau\n\n    requires arr.l.path_valid(state_after_other_path, mover_path, mover_tid)\n    requires state_after_both_paths == arr.l.path_next(state_after_other_path, mover_path, mover_tid)\n    requires !arr.l.path_type(mover_path).AtomicPathType_Tau?\n\n    requires other_tau || other_tid != mover_tid\n    requires arr.l.state_ok(state_after_both_paths)\n\n    requires IsPhase2(arr, state_after_other_path, mover_tid)\n\n    ensures  arr.l.path_valid(initial_state, mover_path, mover_tid)\n    ensures  state_after_mover_path == arr.l.path_next(initial_state, mover_path, mover_tid)\n    ensures  arr.l.path_valid(state_after_mover_path, other_path, other_tid)\n    ensures  state_after_both_paths == arr.l.path_next(state_after_mover_path, other_path, other_tid)\n    ensures  OKAndPCTypesMatch(arr, state_after_mover_path, state_after_both_paths, mover_tid)\n    ensures  !other_tau ==> OKAndPCTypesMatch(arr, state_after_other_path, state_after_both_paths, other_tid)\n  {\n    state_after_mover_path := arr.l.path_next(initial_state, mover_path, mover_tid);\n    assert AtomicReductionSpecModule.LeftMoversCommuteConditions(arr, initial_state, other_path, mover_path, mover_tid, other_tid);\n\n    if !other_tau {\n      lemma_ExecutingPathDoesntChangeOtherActorPCType(arr, state_after_other_path, state_after_both_paths, mover_path, mover_tid, other_tid);\n    }\n    lemma_ExecutingPathDoesntChangeOtherActorPCType(arr, state_after_mover_path, state_after_both_paths, other_path, other_tid, mover_tid);\n  }\n\n  lemma {:timeLimitMultiplier 2} lemma_MoveLeftMoverLeftAsSinglePaths<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    mover_tid:Armada_ThreadHandle,\n    other_tid:Armada_ThreadHandle,\n    other_tau:bool,\n    post_mover_state:LState,\n    mover_path:LPath,\n    other_states:seq<LState>,\n    other_paths:seq<LPath>\n    ) returns (\n    other_states':seq<LState>\n    )\n    requires ValidAtomicReductionRequest(arr)\n\n    requires |other_states| > 0\n    requires arr.inv(other_states[0])\n    requires AtomicNextMultiplePaths(arr.l, other_states[0], last(other_states), other_paths, other_tid)\n    requires other_states == AtomicGetStateSequence(arr.l, other_states[0], other_paths, other_tid)\n    requires forall path :: path in other_paths ==> arr.l.path_type(path).AtomicPathType_Tau? == other_tau\n\n    requires arr.l.path_valid(last(other_states), mover_path, mover_tid)\n    requires post_mover_state == arr.l.path_next(last(other_states), mover_path, mover_tid)\n    requires !arr.l.path_type(mover_path).AtomicPathType_Tau?\n\n    requires other_tau || other_tid != mover_tid\n    requires arr.l.state_ok(post_mover_state)\n\n    requires IsPhase2(arr, last(other_states), mover_tid)\n\n    ensures  |other_states'| == |other_states|\n    ensures  last(other_states') == post_mover_state\n    ensures  arr.l.path_valid(other_states[0], mover_path, mover_tid)\n    ensures  other_states'[0] == arr.l.path_next(other_states[0], mover_path, mover_tid)\n    ensures  AtomicNextMultiplePaths(arr.l, other_states'[0], last(other_states'), other_paths, other_tid)\n    ensures  other_states' == AtomicGetStateSequence(arr.l, other_states'[0], other_paths, other_tid)\n    ensures  OKAndPCTypesMatch(arr, other_states[0], last(other_states), mover_tid)\n    ensures  OKAndPCTypesMatch(arr, other_states'[0], post_mover_state, mover_tid)\n    ensures  !other_tau ==> forall i :: 0 <= i < |other_states| ==> OKAndPCTypesMatch(arr, other_states'[i], other_states[i], other_tid)\n    decreases |other_states|\n  {\n    if |other_paths| == 0 {\n      other_states' := [post_mover_state];\n      return;\n    }\n\n    var pos := |other_states|-2;\n    lemma_AtomicInvariantHoldsAtIntermediateState(arr.l, arr.inv, other_states[0], last(other_states), other_paths, other_tid,\n                                                  other_states, pos);\n    lemma_AtomicValidPathSequenceOfAnyTypeImpliesValidPath(arr.l, other_states[0], last(other_states), other_paths, other_tid,\n                                                           other_states, pos);\n    var state_after_mover_path :=\n      lemma_MoveLeftMoverLeftOneAsSinglePath(\n        arr,  mover_tid, other_tid, other_tau, other_states[pos], other_states[pos+1], post_mover_state, mover_path, other_paths[pos]);\n\n    lemma_AllButLastPreservesAtomicNextMultiplePaths(arr, other_states[0], last(other_states), other_paths, other_states, other_tid);\n    assert last(all_but_last(other_states)) == other_states[pos];\n    var other_states_next :=\n      lemma_MoveLeftMoverLeftAsSinglePaths(\n        arr, mover_tid, other_tid, other_tau, state_after_mover_path, mover_path,\n        all_but_last(other_states), all_but_last(other_paths));\n    other_states' := other_states_next + [post_mover_state];\n\n    lemma_ExtendingStateSequenceWorks(arr.l, other_states_next[0], last(other_states_next), all_but_last(other_paths), other_states_next,\n                                      other_tid, last(other_paths), post_mover_state);\n    lemma_AllButLastPlusLastIsSeq(other_paths);\n\n    if !other_tau {\n      forall i | 0 <= i < |other_states|\n        ensures OKAndPCTypesMatch(arr, other_states'[i], other_states[i], other_tid)\n      {\n        if i < |other_states_next| {\n          assert other_states'[i] == other_states_next[i];\n          assert OKAndPCTypesMatch(arr, other_states_next[i], other_states[i], other_tid);\n        }\n        else {\n          assert |other_states_next| == |all_but_last(other_states)| == |other_states|-1 == i;\n          assert other_states'[i] == post_mover_state;\n          assert other_states[i] == last(other_states);\n          lemma_ExecutingPathDoesntChangeOtherActorPCType(arr, last(other_states), post_mover_state, mover_path, mover_tid, other_tid);\n          assert OKAndPCTypesMatch(arr, post_mover_state, last(other_states), other_tid);\n        }\n      }\n    }\n  }\n\n  lemma lemma_MoveLeftMoversLeftAsSinglePaths<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    mover_tid:Armada_ThreadHandle,\n    other_tid:Armada_ThreadHandle,\n    other_tau:bool,\n    mover_states:seq<LState>,\n    mover_paths:seq<LPath>,\n    other_states:seq<LState>,\n    other_paths:seq<LPath>\n    ) returns (\n    mover_states':seq<LState>,\n    other_states':seq<LState>\n    )\n    requires ValidAtomicReductionRequest(arr)\n\n    requires |other_states| > 0\n    requires arr.inv(other_states[0])\n    requires AtomicNextMultiplePaths(arr.l, other_states[0], last(other_states), other_paths, other_tid)\n    requires other_states == AtomicGetStateSequence(arr.l, other_states[0], other_paths, other_tid)\n    requires forall path :: path in other_paths ==> arr.l.path_type(path).AtomicPathType_Tau? == other_tau\n\n    requires |mover_states| > 1\n    requires last(other_states) == mover_states[0]\n    requires AtomicNextMultiplePaths(arr.l, mover_states[0], last(mover_states), mover_paths, mover_tid)\n    requires mover_states == AtomicGetStateSequence(arr.l, mover_states[0], mover_paths, mover_tid)\n    requires forall path :: path in mover_paths ==> !arr.l.path_type(path).AtomicPathType_Tau?\n\n    requires forall i :: 0 <= i < |mover_states|-1 ==> IsPhase2(arr, mover_states[i], mover_tid)\n\n    requires other_tau || other_tid != mover_tid\n    requires arr.l.state_ok(last(mover_states))\n\n    ensures  |mover_states'| == |mover_states|\n    ensures  |other_states'| == |other_states|\n    ensures  mover_states'[0] == other_states[0]\n    ensures  last(mover_states') == other_states'[0]\n    ensures  last(other_states') == last(mover_states)\n    ensures  AtomicNextMultiplePaths(arr.l, mover_states'[0], last(mover_states'), mover_paths, mover_tid)\n    ensures  AtomicNextMultiplePaths(arr.l, other_states'[0], last(other_states'), other_paths, other_tid)\n    ensures  mover_states' == AtomicGetStateSequence(arr.l, mover_states'[0], mover_paths, mover_tid)\n    ensures  other_states' == AtomicGetStateSequence(arr.l, other_states'[0], other_paths, other_tid)\n    ensures  forall i :: 0 <= i < |mover_states| ==> OKAndPCTypesMatch(arr, mover_states'[i], mover_states[i], mover_tid)\n    ensures  !other_tau ==> forall i :: 0 <= i < |other_states| ==> OKAndPCTypesMatch(arr, other_states'[i], other_states[i], other_tid)\n    decreases |mover_states|\n  {\n    assert |mover_paths| > 0;\n    var pos := 0;\n    assert mover_states[pos+1] == arr.l.path_next(mover_states[pos], mover_paths[pos], mover_tid);\n    forall ensures arr.l.state_ok(mover_states[pos+1]) {\n      if |mover_paths| == 1 {\n        assert mover_states[pos+1] == last(mover_states);\n      }\n      else {\n        lemma_AtomicValidPathSequenceOfAnyTypeImpliesValidPath(arr.l, mover_states[0], last(mover_states), mover_paths, mover_tid,\n                                                               mover_states, pos+1);\n      }\n    }\n    var other_states_mid :=\n      lemma_MoveLeftMoverLeftAsSinglePaths(\n        arr, mover_tid, other_tid, other_tau, mover_states[pos+1], mover_paths[pos], other_states, other_paths);\n    if |mover_paths| == 1 {\n      mover_states' := [other_states[0], other_states_mid[0]];\n      other_states' := other_states_mid;\n    }\n    else {\n      var mover_states_next;\n      lemma_LastOfDropIsLast(mover_states, 1);\n      mover_states_next, other_states' :=\n        lemma_MoveLeftMoversLeftAsSinglePaths(\n          arr, mover_tid, other_tid, other_tau, mover_states[1..], mover_paths[1..], other_states_mid, other_paths);\n      mover_states' := [other_states[0]] + mover_states_next;\n      lemma_LastOfConcatenationIsLastOfLatter([other_states[0]], mover_states_next);\n      calc {\n        last(other_states');\n        last(mover_states[1..]);\n        last(mover_states);\n      }\n      forall i | 0 <= i < |mover_states|\n        ensures OKAndPCTypesMatch(arr, mover_states'[i], mover_states[i], mover_tid)\n      {\n        if i > 0 {\n          var j := i-1;\n          assert OKAndPCTypesMatch(arr, mover_states_next[j], mover_states[1..][j], mover_tid);\n          assert mover_states'[i] == mover_states_next[j];\n          assert mover_states[i] == mover_states[1..][j];\n        }\n        else {\n          assert mover_states'[i] == other_states[0];\n          assert mover_states[i] == mover_states[0];\n        }\n      }\n      if !other_tau {\n        forall i | 0 <= i < |other_states|\n          ensures OKAndPCTypesMatch(arr, other_states'[i], other_states[i], other_tid)\n        {\n          assert OKAndPCTypesMatch(arr, other_states'[i], other_states_mid[i], other_tid);\n          assert OKAndPCTypesMatch(arr, other_states'[i], other_states[i], other_tid);\n        }\n      }\n    }\n  }\n\n  lemma lemma_PerformLeftMoveAll<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    mover_tid:Armada_ThreadHandle,\n    other_tid:Armada_ThreadHandle,\n    other_tau:bool,\n    mover_paths:seq<LPath>,\n    mover_states:seq<LState>,\n    other_paths:seq<LPath>,\n    other_states:seq<LState>\n    ) returns (\n    mover_states':seq<LState>,\n    other_states':seq<LState>\n    )\n\n    requires ValidAtomicReductionRequest(arr)\n\n    requires |other_states| > 0\n    requires arr.inv(other_states[0])\n    requires AtomicNextMultiplePaths(arr.l, other_states[0], last(other_states), other_paths, other_tid)\n    requires other_states == AtomicGetStateSequence(arr.l, other_states[0], other_paths, other_tid)\n    requires forall path :: path in other_paths ==> arr.l.path_type(path).AtomicPathType_Tau? == other_tau\n\n    requires |mover_states| > 0\n    requires last(other_states) == mover_states[0]\n    requires AtomicNextMultiplePaths(arr.l, mover_states[0], last(mover_states), mover_paths, mover_tid)\n    requires mover_states == AtomicGetStateSequence(arr.l, mover_states[0], mover_paths, mover_tid)\n    requires forall path :: path in mover_paths ==> !arr.l.path_type(path).AtomicPathType_Tau?\n\n    requires forall i :: 0 <= i < |mover_states|-1 ==> IsPhase2(arr, mover_states[i], mover_tid)\n\n    requires other_tau || other_tid != mover_tid\n    requires arr.l.state_ok(last(mover_states))\n\n    ensures  |mover_states'| == |mover_states|\n    ensures  |other_states'| == |other_states|\n    ensures  mover_states'[0] == other_states[0]\n    ensures  last(mover_states') == other_states'[0]\n    ensures  last(other_states') == last(mover_states)\n    ensures  AtomicNextMultiplePaths(arr.l, mover_states'[0], last(mover_states'), mover_paths, mover_tid)\n    ensures  AtomicNextMultiplePaths(arr.l, other_states'[0], last(other_states'), other_paths, other_tid)\n    ensures  mover_states' == AtomicGetStateSequence(arr.l, mover_states'[0], mover_paths, mover_tid)\n    ensures  other_states' == AtomicGetStateSequence(arr.l, other_states'[0], other_paths, other_tid)\n    ensures  forall i :: 0 <= i < |mover_states| ==> OKAndPCTypesMatch(arr, mover_states'[i], mover_states[i], mover_tid)\n    ensures  !other_tau ==> forall i :: 0 <= i < |other_states| ==> OKAndPCTypesMatch(arr, other_states'[i], other_states[i], other_tid)\n  {\n    if |mover_states| == 1 {\n     lemma_ExecutingPathSequenceDoesntChangeOtherActorPCType(arr, other_states[0], last(other_states), other_paths, other_tau,\n                                                             other_tid, mover_tid);\n      mover_states' := [other_states[0]];\n      other_states' := other_states;\n    }\n    else\n    {\n      mover_states', other_states' := lemma_MoveLeftMoversLeftAsSinglePaths\n      (arr, mover_tid, other_tid, other_tau, mover_states, mover_paths, other_states, other_paths);\n    } \n  }\n\n  lemma lemma_PerformLeftMove<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    s1:LState,\n    s2:LState,\n    s3:LState,\n    multistep1:Armada_Multistep<LPath>,\n    multistep2:Armada_Multistep<LPath>\n    ) returns (\n    s2':LState\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires s1 in AnnotatedReachables(GetRefinementViaReductionLSpec(arr))\n    requires arr.l.state_ok(s3)\n    requires AtomicNextMultistep(arr.l, s1, s2, multistep1.steps, multistep1.tid, multistep1.tau)\n    requires AtomicNextMultistep(arr.l, s2, s3, multistep2.steps, multistep2.tid, multistep2.tau)\n    requires !multistep2.tau\n    requires multistep1.tau || multistep1.tid != multistep2.tid\n    requires IsPhase2(arr, s2, multistep2.tid)\n    ensures  AtomicNextMultistep(arr.l, s1, s2', multistep2.steps, multistep2.tid, multistep2.tau)\n    ensures  AtomicNextMultistep(arr.l, s2', s3, multistep1.steps, multistep1.tid, multistep1.tau)\n  {\n    lemma_StateAmongAnnotatedReachablesSatisfiesInv(arr, s1);\n    assert arr.inv(s1);\n    var mover_states := AtomicGetStateSequence(arr.l, s2, multistep2.steps, multistep2.tid);\n    lemma_IfMultistepStartsInPhase2ThenEachPathDoes(arr, s2, s3, multistep2, mover_states);\n    var other_states := AtomicGetStateSequence(arr.l, s1, multistep1.steps, multistep1.tid);\n    lemma_AtomicNextLastElement(arr.l, s1, s2, multistep1.steps, multistep1.tid, other_states);\n    lemma_AtomicNextLastElement(arr.l, s2, s3, multistep2.steps, multistep2.tid, mover_states);\n    var mover_states', other_states' :=\n      lemma_PerformLeftMoveAll(arr, multistep2.tid, multistep1.tid, multistep1.tau, multistep2.steps, mover_states,\n                               multistep1.steps, other_states);\n    s2' := last(mover_states');\n    lemma_AtomicNextLastElement(arr.l, s2', s3, multistep1.steps, multistep1.tid, other_states');\n  }\n\n  lemma lemma_RightMoversCommute<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    )\n    requires ValidAtomicReductionRequest(arr)\n    ensures  RefinementViaReductionSpecModule.RightMoversCommute(GetRefinementViaReductionRequest(arr))\n  {\n    var rr := GetRefinementViaReductionRequest(arr);\n    var idmap := rr.idmap;\n    var phase1 := rr.phase1;\n    var phase2 := rr.phase2;\n\n    forall initial_state, state_after_right_mover, state_after_both_paths, right_mover, other_multistep\n      {:trigger RefinementViaReductionSpecModule.RightMoversCommuteConditions(rr, initial_state, state_after_right_mover,\n                                                                              state_after_both_paths, right_mover, other_multistep)}\n      | RefinementViaReductionSpecModule.RightMoversCommuteConditions(rr, initial_state, state_after_right_mover, state_after_both_paths,\n                                                                      right_mover, other_multistep)\n      ensures exists new_middle_state, other_multistep', right_mover' ::\n                && ActionTuple(initial_state, new_middle_state, other_multistep') in rr.lspec.next\n                && ActionTuple(new_middle_state, state_after_both_paths, right_mover') in rr.lspec.next\n                && rr.idmap(other_multistep') == rr.idmap(other_multistep)\n                && rr.idmap(right_mover') == rr.idmap(right_mover)\n    {\n      var new_middle_state:LState;\n      new_middle_state := lemma_PerformRightMove(arr, initial_state, state_after_right_mover, state_after_both_paths,\n                                                 right_mover, other_multistep);\n      assert ActionTuple(initial_state, new_middle_state, other_multistep) in rr.lspec.next;\n      assert ActionTuple(new_middle_state, state_after_both_paths, right_mover) in rr.lspec.next;\n    }\n  }\n\n  lemma lemma_LeftMoversCommute<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    )\n    requires ValidAtomicReductionRequest(arr)\n    ensures  RefinementViaReductionSpecModule.LeftMoversCommute(GetRefinementViaReductionRequest(arr))\n  {\n    var rr := GetRefinementViaReductionRequest(arr);\n    var idmap := rr.idmap;\n    var phase1 := rr.phase1;\n    var phase2 := rr.phase2;\n\n    forall initial_state, state_after_other_multistep, state_after_both_paths, other_multistep, left_mover\n      {:trigger RefinementViaReductionSpecModule.LeftMoversCommuteConditions(rr, initial_state, state_after_other_multistep,\n                                                                             state_after_both_paths, other_multistep, left_mover)}\n      | RefinementViaReductionSpecModule.LeftMoversCommuteConditions(rr, initial_state, state_after_other_multistep, state_after_both_paths,\n                                                                     other_multistep, left_mover)\n      ensures exists new_middle_state, left_mover', other_multistep' ::\n                && ActionTuple(initial_state, new_middle_state, left_mover') in rr.lspec.next\n                && ActionTuple(new_middle_state, state_after_both_paths, other_multistep') in rr.lspec.next\n                && rr.idmap(left_mover') == rr.idmap(left_mover)\n                && rr.idmap(other_multistep') == rr.idmap(other_multistep)\n    {\n      var new_middle_state:LState;\n      new_middle_state := lemma_PerformLeftMove(arr, initial_state, state_after_other_multistep, state_after_both_paths,\n                                                other_multistep, left_mover);\n      assert ActionTuple(initial_state, new_middle_state, left_mover) in rr.lspec.next;\n      assert ActionTuple(new_middle_state, state_after_both_paths, other_multistep) in rr.lspec.next;\n    }\n  }\n\n  //////////////////////////////////////\n  // RIGHT MOVER CRASH PRESERVATION\n  //////////////////////////////////////\n\n  lemma lemma_DemonstrateRightMoverCrashPreservationOneRightMoverPathOtherPathSequence<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    rr:RefinementViaReductionRequest<LState, Option<Armada_ThreadHandle>, Armada_Multistep<LPath>, Armada_Multistep<LPath>>,\n    initial_state:LState,\n    state_after_right_mover:LState,\n    state_after_both_paths:LState,\n    right_mover:LPath,\n    right_mover_tid:Armada_ThreadHandle,\n    other_multistep_paths:seq<LPath>,\n    other_multistep_tid:Armada_ThreadHandle,\n    other_multistep_tau:bool,\n    other_multistep_states:seq<LState>\n    ) returns (\n    state_after_other_multistep':LState,\n    other_multistep_states':seq<LState>\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires rr == GetRefinementViaReductionRequest(arr)\n    requires arr.inv(initial_state)\n    requires arr.l.path_valid(initial_state, right_mover, right_mover_tid)\n    requires state_after_right_mover == arr.l.path_next(initial_state, right_mover, right_mover_tid)\n    requires !arr.l.path_type(right_mover).AtomicPathType_Tau?\n    requires AtomicNextMultiplePaths(arr.l, state_after_right_mover, state_after_both_paths, other_multistep_paths, other_multistep_tid)\n    requires forall path :: path in other_multistep_paths ==> arr.l.path_type(path).AtomicPathType_Tau? == other_multistep_tau\n    requires other_multistep_states == AtomicGetStateSequence(arr.l, state_after_right_mover, other_multistep_paths, other_multistep_tid)\n    requires !rr.crashed(initial_state)\n    requires !rr.crashed(state_after_right_mover)\n    requires rr.crashed(state_after_both_paths)\n    requires IsPhase1(arr, state_after_right_mover, right_mover_tid)\n    requires other_multistep_tau || other_multistep_tid != right_mover_tid\n    ensures  AtomicNextMultiplePaths(arr.l, initial_state, state_after_other_multistep', other_multistep_paths, other_multistep_tid)\n    ensures  other_multistep_states' == AtomicGetStateSequence(arr.l, initial_state, other_multistep_paths, other_multistep_tid)\n    ensures  |other_multistep_states'| == |other_multistep_states|\n    ensures  !other_multistep_tau ==>\n             forall i :: 0 <= i < |other_multistep_states|-1 ==>\n                   OKAndPCTypesMatch(arr, other_multistep_states'[i], other_multistep_states[i], other_multistep_tid)\n    ensures  rr.crashed(state_after_other_multistep')\n    ensures  RefinementPair(state_after_both_paths, state_after_other_multistep') in rr.relation\n  {\n    assert |other_multistep_paths| > 0;\n    assert arr.l.path_valid(state_after_right_mover, other_multistep_paths[0], other_multistep_tid);\n    assert other_multistep_states[1] == arr.l.path_next(state_after_right_mover, other_multistep_paths[0], other_multistep_tid);\n\n    if !other_multistep_tau {\n      lemma_ExecutingPathDoesntChangeOtherActorPCType(arr, initial_state, state_after_right_mover, right_mover,\n                                                      right_mover_tid, other_multistep_tid);\n    }\n\n    if |other_multistep_paths| == 1 {\n      other_multistep_states' := AtomicGetStateSequence(arr.l, initial_state, other_multistep_paths, other_multistep_tid);\n      state_after_other_multistep' := arr.l.path_next(initial_state, other_multistep_paths[0], other_multistep_tid);\n      lemma_AtomicNextLastElement(arr.l, state_after_right_mover, state_after_both_paths,\n                                  other_multistep_paths, other_multistep_tid, other_multistep_states);\n      assert AtomicReductionSpecModule.RightMoverCrashPreservationConditions(arr, initial_state, right_mover, other_multistep_paths[0],\n                                                                             right_mover_tid, other_multistep_tid);\n      return;\n    }\n\n    lemma_AtomicValidPathSequenceOfAnyTypeImpliesValidPath(arr.l, state_after_right_mover, state_after_both_paths,\n                                                           other_multistep_paths, other_multistep_tid, other_multistep_states, 1);\n    assert AtomicReductionSpecModule.RightMoversCommuteConditions(arr, initial_state, right_mover, other_multistep_paths[0],\n                                                                  right_mover_tid, other_multistep_tid);\n    assert arr.l.path_valid(initial_state, other_multistep_paths[0], other_multistep_tid);\n    var s2' := arr.l.path_next(initial_state, other_multistep_paths[0], other_multistep_tid);\n    assert arr.l.path_valid(s2', right_mover, right_mover_tid);\n    assert other_multistep_states[1] == arr.l.path_next(s2', right_mover, right_mover_tid);\n\n    var other_multistep_states_mid;\n    state_after_other_multistep', other_multistep_states_mid :=\n      lemma_DemonstrateRightMoverCrashPreservationOneRightMoverPathOtherPathSequence(\n        arr, rr, s2', other_multistep_states[1], state_after_both_paths, right_mover,\n        right_mover_tid, other_multistep_paths[1..], other_multistep_tid, other_multistep_tau,\n        other_multistep_states[1..]);\n\n    other_multistep_states' := [initial_state] + other_multistep_states_mid;\n  }\n\n  lemma lemma_DemonstrateRightMoverCrashPreservationOneRightMoverOtherArmada_Multistep<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    rr:RefinementViaReductionRequest<LState, Option<Armada_ThreadHandle>, Armada_Multistep<LPath>, Armada_Multistep<LPath>>,\n    initial_state:LState,\n    state_after_right_mover:LState,\n    state_after_both_paths:LState,\n    other_multistep:Armada_Multistep<LPath>,\n    right_mover:LPath,\n    right_mover_tid:Armada_ThreadHandle\n    ) returns (\n    state_after_other_multistep':LState\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires rr == GetRefinementViaReductionRequest(arr)\n    requires arr.inv(initial_state)\n    requires arr.l.path_valid(initial_state, right_mover, right_mover_tid)\n    requires state_after_right_mover == arr.l.path_next(initial_state, right_mover, right_mover_tid)\n    requires !arr.l.path_type(right_mover).AtomicPathType_Tau?\n    requires AtomicNextMultistep(arr.l, state_after_right_mover, state_after_both_paths, other_multistep.steps,\n                                 other_multistep.tid, other_multistep.tau)\n    requires !rr.crashed(initial_state)\n    requires !rr.crashed(state_after_right_mover)\n    requires rr.crashed(state_after_both_paths)\n    requires IsPhase1(arr, state_after_right_mover, right_mover_tid)\n    requires other_multistep.tau || other_multistep.tid != right_mover_tid\n    ensures  AtomicNextMultistep(arr.l, initial_state, state_after_other_multistep', other_multistep.steps, other_multistep.tid,\n                                 other_multistep.tau)\n    ensures  rr.crashed(state_after_other_multistep')\n    ensures  RefinementPair(state_after_both_paths, state_after_other_multistep') in rr.relation\n  {\n    var other_multistep_states := AtomicGetStateSequence(arr.l, state_after_right_mover, other_multistep.steps, other_multistep.tid);\n    var other_multistep_states';\n    state_after_other_multistep', other_multistep_states' :=\n      lemma_DemonstrateRightMoverCrashPreservationOneRightMoverPathOtherPathSequence(\n        arr, rr, initial_state, state_after_right_mover, state_after_both_paths,\n        right_mover, right_mover_tid, other_multistep.steps, other_multistep.tid, other_multistep.tau,\n        other_multistep_states);\n  }\n\n  lemma lemma_DemonstrateRightMoverCrashPreservationOneRightMoverOtherMultistep<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    rr:RefinementViaReductionRequest<LState, Option<Armada_ThreadHandle>, Armada_Multistep<LPath>, Armada_Multistep<LPath>>,\n    initial_state:LState,\n    state_after_right_mover:LState,\n    state_after_both_paths:LState,\n    other_multistep:Armada_Multistep<LPath>,\n    right_mover:LPath,\n    right_mover_tid:Armada_ThreadHandle\n    ) returns (\n    state_after_other_multistep':LState\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires rr == GetRefinementViaReductionRequest(arr)\n    requires arr.inv(initial_state)\n    requires arr.l.path_valid(initial_state, right_mover, right_mover_tid)\n    requires state_after_right_mover == arr.l.path_next(initial_state, right_mover, right_mover_tid)\n    requires !arr.l.path_type(right_mover).AtomicPathType_Tau?\n    requires ActionTuple(state_after_right_mover, state_after_both_paths, other_multistep) in rr.lspec.next\n    requires !rr.crashed(initial_state)\n    requires !rr.crashed(state_after_right_mover)\n    requires rr.crashed(state_after_both_paths)\n    requires IsPhase1(arr, state_after_right_mover, right_mover_tid)\n    requires rr.idmap(other_multistep) != Some(right_mover_tid)\n    ensures  ActionTuple(initial_state, state_after_other_multistep', other_multistep) in rr.lspec.next\n    ensures  rr.crashed(state_after_other_multistep')\n    ensures  RefinementPair(state_after_both_paths, state_after_other_multistep') in rr.relation\n  {\n    state_after_other_multistep' :=\n      lemma_DemonstrateRightMoverCrashPreservationOneRightMoverOtherArmada_Multistep(\n        arr, rr, initial_state, state_after_right_mover, state_after_both_paths,\n        other_multistep, right_mover, right_mover_tid);\n  }\n\n  lemma lemma_DemonstrateRightMoverCrashPreservationRightMoverPathSequenceOtherMultistep<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    rr:RefinementViaReductionRequest<LState, Option<Armada_ThreadHandle>, Armada_Multistep<LPath>, Armada_Multistep<LPath>>,\n    initial_state:LState,\n    state_after_right_mover:LState,\n    state_after_both_paths:LState,\n    other_multistep:Armada_Multistep<LPath>,\n    right_mover_paths:seq<LPath>,\n    right_mover_tid:Armada_ThreadHandle,\n    right_mover_states:seq<LState>\n    ) returns (\n    state_after_other_multistep':LState\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires rr == GetRefinementViaReductionRequest(arr)\n    requires arr.inv(initial_state)\n    requires AtomicNextMultiplePaths(arr.l, initial_state, state_after_right_mover, right_mover_paths, right_mover_tid)\n    requires forall path :: path in right_mover_paths ==> !arr.l.path_type(path).AtomicPathType_Tau?\n    requires ActionTuple(state_after_right_mover, state_after_both_paths, other_multistep) in rr.lspec.next\n    requires !rr.crashed(initial_state)\n    requires !rr.crashed(state_after_right_mover)\n    requires rr.crashed(state_after_both_paths)\n    requires IsPhase1(arr, state_after_right_mover, right_mover_tid)\n    requires right_mover_states == AtomicGetStateSequence(arr.l, initial_state, right_mover_paths, right_mover_tid)\n    requires forall i :: 0 < i < |right_mover_states| ==> IsPhase1(arr, right_mover_states[i], right_mover_tid)\n    requires rr.idmap(other_multistep) != Some(right_mover_tid)\n    ensures  ActionTuple(initial_state, state_after_other_multistep', other_multistep) in rr.lspec.next\n    ensures  rr.crashed(state_after_other_multistep')\n    ensures  RefinementPair(state_after_both_paths, state_after_other_multistep') in rr.relation\n    decreases |right_mover_paths|\n  {\n    if |right_mover_paths| == 0 {\n      state_after_other_multistep' := state_after_both_paths;\n      return;\n    }\n\n    var pos := |right_mover_states|-2;\n    var penultimate_state := right_mover_states[pos];\n    lemma_AtomicValidPathSequenceOfAnyTypeImpliesValidPath(arr.l, initial_state, state_after_right_mover, right_mover_paths,\n                                                           right_mover_tid, right_mover_states, pos);\n    lemma_AtomicNextLastElement(arr.l, initial_state, state_after_right_mover, right_mover_paths, right_mover_tid, right_mover_states);\n    lemma_AtomicInvariantHoldsAtIntermediateState(arr.l, arr.inv, initial_state, state_after_right_mover, right_mover_paths,\n                                                  right_mover_tid, right_mover_states, pos);\n    var state_after_other_multistep_mid :=\n      lemma_DemonstrateRightMoverCrashPreservationOneRightMoverOtherMultistep(\n        arr, rr, penultimate_state, state_after_right_mover, state_after_both_paths,\n        other_multistep, last(right_mover_paths), right_mover_tid);\n\n    if |right_mover_paths| == 1 {\n      state_after_other_multistep' := state_after_other_multistep_mid;\n      return;\n    }\n\n    lemma_AllButLastPreservesAtomicNextMultiplePaths(arr, initial_state, state_after_right_mover, right_mover_paths,\n                                                     right_mover_states, right_mover_tid);\n    assert 0 < pos < |right_mover_states|;\n    assert IsPhase1(arr, penultimate_state, right_mover_tid);\n    state_after_other_multistep' :=\n      lemma_DemonstrateRightMoverCrashPreservationRightMoverPathSequenceOtherMultistep(\n        arr, rr, initial_state, penultimate_state, state_after_other_multistep_mid,\n        other_multistep, all_but_last(right_mover_paths), right_mover_tid,\n        all_but_last(right_mover_states));\n  }\n\n  lemma lemma_DemonstrateRightMoverCrashPreservationRightMoverArmada_MultistepOtherMultistep<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    rr:RefinementViaReductionRequest<LState, Option<Armada_ThreadHandle>, Armada_Multistep<LPath>, Armada_Multistep<LPath>>,\n    initial_state:LState,\n    state_after_right_mover:LState,\n    state_after_both_paths:LState,\n    right_mover:Armada_Multistep<LPath>,\n    other_multistep:Armada_Multistep<LPath>\n    ) returns (\n    state_after_other_multistep':LState\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires rr == GetRefinementViaReductionRequest(arr)\n    requires arr.inv(initial_state)\n    requires AtomicNextMultistep(arr.l, initial_state, state_after_right_mover, right_mover.steps, right_mover.tid, right_mover.tau)\n    requires ActionTuple(state_after_right_mover, state_after_both_paths, other_multistep) in rr.lspec.next\n    requires !rr.crashed(initial_state)\n    requires !rr.crashed(state_after_right_mover)\n    requires rr.crashed(state_after_both_paths)\n    requires IsPhase1(arr, state_after_right_mover, right_mover.tid)\n    requires !right_mover.tau\n    requires rr.idmap(other_multistep) != Some(right_mover.tid)\n    ensures  ActionTuple(initial_state, state_after_other_multistep', other_multistep) in rr.lspec.next\n    ensures  rr.crashed(state_after_other_multistep')\n    ensures  RefinementPair(state_after_both_paths, state_after_other_multistep') in rr.relation\n  {\n    var right_mover_states := AtomicGetStateSequence(arr.l, initial_state, right_mover.steps, right_mover.tid);\n    lemma_IfMultistepEndsInPhase1ThenEachPathDoes(arr, initial_state, state_after_right_mover, right_mover, right_mover_states);\n    state_after_other_multistep' :=\n      lemma_DemonstrateRightMoverCrashPreservationRightMoverPathSequenceOtherMultistep(\n        arr, rr, initial_state, state_after_right_mover, state_after_both_paths,\n        other_multistep, right_mover.steps, right_mover.tid, right_mover_states);\n  }\n\n  lemma lemma_DemonstrateRightMoverCrashPreservation<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    rr:RefinementViaReductionRequest<LState, Option<Armada_ThreadHandle>, Armada_Multistep<LPath>, Armada_Multistep<LPath>>,\n    initial_state:LState,\n    state_after_right_mover:LState,\n    state_after_both_paths:LState,\n    right_mover:Armada_Multistep<LPath>,\n    other_multistep:Armada_Multistep<LPath>\n    ) returns (\n    other_multistep':Armada_Multistep<LPath>,\n    state_after_other_multistep':LState\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires rr == GetRefinementViaReductionRequest(arr)\n    requires initial_state in AnnotatedReachables(rr.lspec)\n    requires ActionTuple(initial_state, state_after_right_mover, right_mover) in rr.lspec.next\n    requires ActionTuple(state_after_right_mover, state_after_both_paths, other_multistep) in rr.lspec.next\n    requires !rr.crashed(initial_state)\n    requires !rr.crashed(state_after_right_mover)\n    requires rr.crashed(state_after_both_paths)\n    requires rr.phase1(state_after_right_mover, rr.idmap(right_mover))\n    requires rr.idmap(right_mover) != rr.idmap(other_multistep)\n    ensures  rr.idmap(other_multistep') == rr.idmap(other_multistep)\n    ensures  ActionTuple(initial_state, state_after_other_multistep', other_multistep') in rr.lspec.next\n    ensures  rr.crashed(state_after_other_multistep')\n    ensures  RefinementPair(state_after_both_paths, state_after_other_multistep') in rr.relation\n  {\n    lemma_StateAmongAnnotatedReachablesSatisfiesInv(arr, initial_state);\n    other_multistep' := other_multistep;\n    state_after_other_multistep' :=\n      lemma_DemonstrateRightMoverCrashPreservationRightMoverArmada_MultistepOtherMultistep(\n        arr, rr, initial_state, state_after_right_mover, state_after_both_paths,\n        right_mover, other_multistep);\n  }\n\n  lemma lemma_RightMoverCrashPreservation<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    )\n    requires ValidAtomicReductionRequest(arr)\n    ensures  RefinementViaReductionSpecModule.RightMoverCrashPreservation(GetRefinementViaReductionRequest(arr))\n  {\n    var rr := GetRefinementViaReductionRequest(arr);\n\n    forall initial_state, state_after_right_mover, state_after_both_paths, right_mover, other_multistep\n      {:trigger RefinementViaReductionSpecModule.RightMoverCrashPreservationConditions(rr, initial_state, state_after_right_mover,\n                                                                                       state_after_both_paths, right_mover,\n                                                                                       other_multistep)}\n      | RefinementViaReductionSpecModule.RightMoverCrashPreservationConditions(rr, initial_state, state_after_right_mover,\n                                                                               state_after_both_paths, right_mover, other_multistep)\n      && initial_state in AnnotatedReachables(rr.lspec)\n      && ActionTuple(initial_state, state_after_right_mover, right_mover) in rr.lspec.next\n      && ActionTuple(state_after_right_mover, state_after_both_paths, other_multistep) in rr.lspec.next\n      && !rr.crashed(initial_state)\n      && !rr.crashed(state_after_right_mover)\n      && rr.crashed(state_after_both_paths)\n      && rr.phase1(state_after_right_mover, rr.idmap(right_mover))\n      && rr.idmap(right_mover) != rr.idmap(other_multistep)\n      ensures exists other_multistep', state_after_other_multistep' ::\n                && rr.idmap(other_multistep') == rr.idmap(other_multistep)\n                && ActionTuple(initial_state, state_after_other_multistep', other_multistep') in rr.lspec.next\n                && rr.crashed(state_after_other_multistep')\n                && RefinementPair(state_after_both_paths, state_after_other_multistep') in rr.relation\n    {\n      var other_multistep', state_after_other_multistep' :=\n        lemma_DemonstrateRightMoverCrashPreservation(arr, rr, initial_state, state_after_right_mover, state_after_both_paths,\n                                                     right_mover, other_multistep);\n    }\n  }\n\n  //////////////////////////////////////\n  // LEFT MOVERS ENABLED BEFORE CRASH\n  //////////////////////////////////////\n\n  lemma lemma_CombineLeftMoverSubpathsIntoPathsOneIteration<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    rr:RefinementViaReductionRequest<LState, Option<Armada_ThreadHandle>, Armada_Multistep<LPath>, Armada_Multistep<LPath>>,\n    tid:Armada_ThreadHandle,\n    states:seq<LState>,\n    paths:seq<LPath>,\n    pos:int,\n    multistates:seq<LState>,\n    multipaths:seq<Armada_Multistep<LPath>>,\n    partial_paths:seq<LPath>,\n    partial_multistates:seq<LState>\n    ) returns (\n    pos':int,\n    multistates':seq<LState>,\n    multipaths':seq<Armada_Multistep<LPath>>,\n    partial_paths':seq<LPath>,\n    partial_multistates':seq<LState>\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires rr == GetRefinementViaReductionRequest(arr)\n    requires |states| > 0\n    requires AtomicNextMultiplePaths(arr.l, states[0], last(states), paths, tid)\n    requires states == AtomicGetStateSequence(arr.l, states[0], paths, tid)\n    requires arr.inv(states[0])\n    requires IsPhase2(arr, states[0], tid)\n    requires AtomicThreadYielding(arr.l, states[0], tid)\n    requires forall i :: 0 <= i < |states|-1 ==> IsPhase2(arr, states[i], tid)\n    requires !IsPhase2(arr, last(states), tid)\n    requires AtomicThreadYielding(arr.l, last(states), tid)\n    requires forall path :: path in paths ==> !arr.l.path_type(path).AtomicPathType_Tau?\n\n    requires 0 <= pos < |paths|\n    requires |multistates| > 0\n    requires multistates[0] == states[0]\n    requires StateNextSeq(multistates, multipaths, rr.lspec.next)\n    requires forall multipath :: multipath in multipaths ==> !multipath.tau && multipath.tid == tid\n    requires AtomicThreadYielding(arr.l, last(multistates), tid)\n    requires AtomicThreadYielding(arr.l, states[pos], tid) ==> |partial_paths| == 0\n    requires AtomicNextMultiplePaths(arr.l, last(multistates), states[pos], partial_paths, tid)\n    requires partial_multistates == AtomicGetStateSequence(arr.l, last(multistates), partial_paths, tid)\n    requires forall i :: 0 < i < |partial_multistates| ==> !AtomicThreadYielding(arr.l, partial_multistates[i], tid)\n    requires forall path :: path in partial_paths ==> !arr.l.path_type(path).AtomicPathType_Tau?\n    requires if pos < |paths| then (\n                 forall s :: s in multistates ==> IsPhase2(arr, s, tid)\n             ) else (\n                 forall i :: 0 <= i < |multistates|-1 ==> IsPhase2(arr, multistates[i], tid)\n             )\n\n    ensures  pos' == pos + 1\n    ensures  |multistates'| > 0\n    ensures  multistates'[0] == states[0]\n    ensures  StateNextSeq(multistates', multipaths', rr.lspec.next)\n    ensures  forall multipath :: multipath in multipaths' ==> !multipath.tau && multipath.tid == tid\n    ensures  AtomicThreadYielding(arr.l, last(multistates'), tid)\n    ensures  AtomicThreadYielding(arr.l, states[pos'], tid) ==> |partial_paths'| == 0\n    ensures  AtomicNextMultiplePaths(arr.l, last(multistates'), states[pos'], partial_paths', tid)\n    ensures  partial_multistates' == AtomicGetStateSequence(arr.l, last(multistates'), partial_paths', tid)\n    ensures  forall i :: 0 < i < |partial_multistates'| ==> !AtomicThreadYielding(arr.l, partial_multistates'[i], tid)\n    ensures  forall path :: path in partial_paths' ==> !arr.l.path_type(path).AtomicPathType_Tau?\n    ensures  if pos' < |paths| then (\n                 forall s :: s in multistates' ==> IsPhase2(arr, s, tid)\n             ) else (\n                 forall i :: 0 <= i < |multistates'|-1 ==> IsPhase2(arr, multistates'[i], tid)\n             )\n  {\n    var s_current := states[pos];\n    var s_next := states[pos+1];\n    var next_path := paths[pos];\n\n    lemma_AtomicValidPathSequenceOfAnyTypeImpliesValidPath(arr.l, states[0], last(states), paths, tid, states, pos);\n    assert arr.l.path_valid(s_current, next_path, tid);\n    assert s_next == arr.l.path_next(s_current, next_path, tid);\n    var pc' := arr.l.get_thread_pc(s_next, tid);\n\n    lemma_ExtendingStateSequenceWorks(arr.l, last(multistates), s_current, partial_paths, partial_multistates, tid, next_path, s_next);\n\n    var upper := |partial_multistates|;\n    assert forall i :: 0 < i < upper ==> !AtomicThreadYielding(arr.l, partial_multistates[i], tid);\n\n    partial_paths' := partial_paths + [next_path];\n    partial_multistates' := partial_multistates + [s_next];\n\n    assert upper == |partial_paths'|;\n    assert forall i :: 0 < i < |partial_paths'| ==> !AtomicThreadYielding(arr.l, partial_multistates'[i], tid);\n\n    if AtomicThreadYielding(arr.l, s_next, tid) {\n      var multipath := Armada_Multistep(partial_paths', tid, false);\n\n      assert AtomicNextMultistep(arr.l, last(multistates), s_next, multipath.steps, multipath.tid, multipath.tau);\n      assert ActionTuple(last(multistates), s_next, multipath) in rr.lspec.next;\n\n      multistates' := multistates + [s_next];\n      multipaths' := multipaths + [multipath];\n\n      forall i | 0 <= i < |multipaths'|\n        ensures ActionTuple(multistates'[i], multistates'[i+1], multipaths'[i]) in rr.lspec.next\n      {\n        if i < |multipaths| {\n          assert ActionTuple(multistates[i], multistates[i+1], multipaths[i]) in rr.lspec.next;\n          assert multistates'[i] == multistates[i];\n          assert multistates'[i+1] == multistates[i+1];\n          assert multipaths'[i] == multipaths[i];\n        }\n        else {\n          assert i == |multipaths| == |multistates|-1;\n          assert multistates'[i] == multistates[i] == last(multistates);\n          assert multistates'[i+1] == s_next;\n          assert multipaths'[i] == multipath;\n        }\n      }\n\n      assert StateNextSeq(multistates', multipaths', rr.lspec.next);\n\n      partial_paths' := [];\n      partial_multistates' := [s_next];\n    }\n    else {\n      multistates' := multistates;\n      multipaths' := multipaths;\n    }\n\n    pos' := pos + 1;\n    assert AtomicNextMultiplePaths(arr.l, last(multistates'), states[pos'], partial_paths', tid);\n  }\n\n  lemma lemma_CombineLeftMoverSubpathsIntoPaths<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    rr:RefinementViaReductionRequest<LState, Option<Armada_ThreadHandle>, Armada_Multistep<LPath>, Armada_Multistep<LPath>>,\n    tid:Armada_ThreadHandle,\n    states:seq<LState>,\n    paths:seq<LPath>\n    ) returns (\n    multistates:seq<LState>,\n    multipaths:seq<Armada_Multistep<LPath>>\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires rr == GetRefinementViaReductionRequest(arr)\n    requires |states| > 0\n    requires AtomicNextMultiplePaths(arr.l, states[0], last(states), paths, tid)\n    requires states == AtomicGetStateSequence(arr.l, states[0], paths, tid)\n    requires arr.inv(states[0])\n    requires AtomicThreadYielding(arr.l, states[0], tid)\n    requires IsPhase2(arr, states[0], tid)\n    requires forall i :: 0 <= i < |states|-1 ==> IsPhase2(arr, states[i], tid)\n    requires !IsPhase2(arr, last(states), tid)\n    requires AtomicThreadYielding(arr.l, last(states), tid)\n    requires forall path :: path in paths ==> !arr.l.path_type(path).AtomicPathType_Tau?\n    ensures  StateNextSeq(multistates, multipaths, rr.lspec.next)\n    ensures  |multistates| > 0\n    ensures  multistates[0] == states[0]\n    ensures  last(multistates) == last(states)\n    ensures  forall i :: 0 <= i < |multistates|-1 ==> IsPhase2(arr, multistates[i], tid)\n    ensures  forall multipath :: multipath in multipaths ==> !multipath.tau && multipath.tid == tid\n  {\n    multistates := [states[0]];\n    multipaths := [];\n    var partial_paths := [];\n    var partial_multistates := [states[0]];\n\n    var pos := 0;\n\n    assert AtomicThreadYielding(arr.l, states[pos], tid) ==> |partial_paths| == 0;\n    while pos < |paths|\n      invariant 0 <= pos <= |paths|\n      invariant |multistates| > 0\n      invariant multistates[0] == states[0]\n      invariant StateNextSeq(multistates, multipaths, rr.lspec.next)\n      invariant forall multipath :: multipath in multipaths ==> !multipath.tau && multipath.tid == tid\n      invariant AtomicThreadYielding(arr.l, last(multistates), tid)\n      invariant AtomicThreadYielding(arr.l, states[pos], tid) ==> |partial_paths| == 0\n      invariant AtomicNextMultiplePaths(arr.l, last(multistates), states[pos], partial_paths, tid)\n      invariant partial_multistates == AtomicGetStateSequence(arr.l, last(multistates), partial_paths, tid)\n      invariant forall i :: 0 < i < |partial_multistates| ==> !AtomicThreadYielding(arr.l, partial_multistates[i], tid)\n      invariant forall path :: path in partial_paths ==> !arr.l.path_type(path).AtomicPathType_Tau?\n      invariant if pos < |paths| then (\n                    forall s :: s in multistates ==> IsPhase2(arr, s, tid)\n                ) else (\n                    forall i :: 0 <= i < |multistates|-1 ==> IsPhase2(arr, multistates[i], tid)\n                )\n      decreases |paths| - pos\n    {\n      pos, multistates, multipaths, partial_paths, partial_multistates :=\n        lemma_CombineLeftMoverSubpathsIntoPathsOneIteration(\n          arr, rr, tid, states, paths, pos, multistates, multipaths, partial_paths, partial_multistates);\n    }\n  }\n\n  lemma lemma_DemonstrateLeftMoversEnabledBeforeCrashCrashPathSequencePart2<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    rr:RefinementViaReductionRequest<LState, Option<Armada_ThreadHandle>, Armada_Multistep<LPath>, Armada_Multistep<LPath>>,\n    initial_state:LState,\n    post_crash_state:LState,\n    crash_path_paths:seq<LPath>,\n    crash_path_tid:Armada_ThreadHandle,\n    crash_path_tau:bool,\n    crash_path_states:seq<LState>,\n    left_mover_tid:Armada_ThreadHandle,\n    left_mover_states_mid:seq<LState>,\n    left_mover_paths_mid:seq<LPath>,\n    post_crash_state':LState\n    ) returns (\n    left_mover_states:seq<LState>,\n    left_mover_paths:seq<Armada_Multistep<LPath>>,\n    crash_path_states':seq<LState>\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires rr == GetRefinementViaReductionRequest(arr)\n    requires arr.inv(initial_state)\n    requires AtomicNextMultiplePaths(arr.l, initial_state, post_crash_state, crash_path_paths, crash_path_tid)\n    requires forall path :: path in crash_path_paths ==> arr.l.path_type(path).AtomicPathType_Tau? == crash_path_tau\n    requires crash_path_states == AtomicGetStateSequence(arr.l, initial_state, crash_path_paths, crash_path_tid)\n    requires !rr.crashed(initial_state)\n    requires rr.crashed(post_crash_state)\n    requires crash_path_tau || crash_path_tid != left_mover_tid\n    requires IsPhase2(arr, initial_state, left_mover_tid)\n    requires AtomicThreadYielding(arr.l, initial_state, left_mover_tid)\n    requires |left_mover_states_mid| > 1\n    requires AtomicNextMultiplePaths(arr.l, crash_path_states[|crash_path_states|-2], last(left_mover_states_mid), left_mover_paths_mid,\n                                     left_mover_tid)\n    requires left_mover_states_mid == AtomicGetStateSequence(arr.l, crash_path_states[|crash_path_states|-2], left_mover_paths_mid,\n                                                             left_mover_tid)\n    requires arr.l.state_ok(last(left_mover_states_mid))\n    requires !IsPhase2(arr, last(left_mover_states_mid), left_mover_tid)\n    requires AtomicThreadYielding(arr.l, last(left_mover_states_mid), left_mover_tid)\n    requires forall i :: 0 <= i < |left_mover_states_mid|-1 ==> IsPhase2(arr, left_mover_states_mid[i], left_mover_tid)\n    requires forall path :: path in left_mover_paths_mid ==> !arr.l.path_type(path).AtomicPathType_Tau?\n    requires arr.l.path_valid(last(left_mover_states_mid), last(crash_path_paths), crash_path_tid)\n    requires post_crash_state' == arr.l.path_next(last(left_mover_states_mid), last(crash_path_paths), crash_path_tid);\n    requires rr.crashed(post_crash_state')\n    requires RefinementPair(post_crash_state, post_crash_state') in rr.relation\n\n    ensures  StateNextSeq(left_mover_states, left_mover_paths, rr.lspec.next)\n    ensures  left_mover_states[0] == initial_state\n    ensures  arr.l.state_ok(last(left_mover_states))\n    ensures  !IsPhase2(arr, last(left_mover_states), left_mover_tid)\n    ensures  forall i :: 0 <= i < |left_mover_states|-1 ==> IsPhase2(arr, left_mover_states[i], left_mover_tid)\n    ensures  forall path :: path in left_mover_paths ==> rr.idmap(path) == Some(left_mover_tid)\n    ensures  AtomicNextMultiplePaths(arr.l, last(left_mover_states), post_crash_state', crash_path_paths, crash_path_tid)\n    ensures  crash_path_states' == AtomicGetStateSequence(arr.l, last(left_mover_states), crash_path_paths, crash_path_tid)\n    ensures  |crash_path_states'| == |crash_path_states|\n    ensures  !crash_path_tau ==>\n               forall i :: 0 <= i < |crash_path_states|-1 ==> OKAndPCTypesMatch(arr, crash_path_states'[i], crash_path_states[i], crash_path_tid)\n  {\n    var pos := |crash_path_states|-2;\n    var penultimate_state := crash_path_states[pos];\n    lemma_AtomicValidPathSequenceOfAnyTypeImpliesValidPath(arr.l, initial_state, post_crash_state, crash_path_paths,\n                                                           crash_path_tid, crash_path_states, pos);\n    lemma_AtomicNextLastElement(arr.l, initial_state, post_crash_state, crash_path_paths, crash_path_tid, crash_path_states);\n    lemma_AtomicInvariantHoldsAtIntermediateState(arr.l, arr.inv, initial_state, post_crash_state, crash_path_paths,\n                                                  crash_path_tid, crash_path_states, pos);\n    lemma_AllButLastPreservesAtomicNextMultiplePaths(arr, initial_state, post_crash_state, crash_path_paths,\n                                                     crash_path_states, crash_path_tid);\n\n    var mover_states', other_states' :=\n      lemma_MoveLeftMoversLeftAsSinglePaths(\n        arr, left_mover_tid, crash_path_tid, crash_path_tau, left_mover_states_mid, left_mover_paths_mid,\n        all_but_last(crash_path_states), all_but_last(crash_path_paths));\n\n    left_mover_states, left_mover_paths :=\n      lemma_CombineLeftMoverSubpathsIntoPaths(arr, rr, left_mover_tid, mover_states', left_mover_paths_mid);\n\n    assert last(left_mover_states) == last(mover_states') == other_states'[0];\n    assert AtomicNextMultiplePaths(arr.l, other_states'[0], last(other_states'), all_but_last(crash_path_paths), crash_path_tid);\n    assert last(other_states') == last(left_mover_states_mid);\n\n    lemma_ExtendingStateSequenceWorks(arr.l, last(left_mover_states), last(left_mover_states_mid), all_but_last(crash_path_paths),\n                                      other_states', crash_path_tid, last(crash_path_paths), post_crash_state');\n    lemma_AllButLastPlusLastIsSeq(crash_path_paths);\n    assert AtomicNextMultiplePaths(arr.l, last(left_mover_states), post_crash_state', crash_path_paths, crash_path_tid);\n\n    crash_path_states' := other_states' + [post_crash_state'];\n    if !crash_path_tau {\n      forall i | 0 <= i < |crash_path_states|-1\n        ensures OKAndPCTypesMatch(arr, crash_path_states'[i], crash_path_states[i], crash_path_tid)\n      {\n        assert crash_path_states'[i] == other_states'[i];\n        assert all_but_last(crash_path_states)[i] == crash_path_states[i];\n      }\n    }\n  }\n\n  lemma lemma_DemonstrateLeftMoversEnabledBeforeCrashCrashPath<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    rr:RefinementViaReductionRequest<LState, Option<Armada_ThreadHandle>, Armada_Multistep<LPath>, Armada_Multistep<LPath>>,\n    initial_state:LState,\n    post_crash_state:LState,\n    crash_path:LPath,\n    crash_path_tid:Armada_ThreadHandle,\n    crash_path_tau:bool,\n    left_mover_tid:Armada_ThreadHandle\n    ) returns (\n    left_mover_states:seq<LState>,\n    left_mover_paths:seq<LPath>,\n    post_crash_state':LState\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires rr == GetRefinementViaReductionRequest(arr)\n    requires arr.inv(initial_state)\n    requires arr.l.path_valid(initial_state, crash_path, crash_path_tid)\n    requires post_crash_state == arr.l.path_next(initial_state, crash_path, crash_path_tid)\n    requires arr.l.path_type(crash_path).AtomicPathType_Tau? == crash_path_tau\n    requires !rr.crashed(initial_state)\n    requires rr.crashed(post_crash_state)\n    requires crash_path_tau || crash_path_tid != left_mover_tid\n    requires IsPhase2(arr, initial_state, left_mover_tid)\n    ensures  |left_mover_states| > 0\n    ensures  AtomicNextMultiplePaths(arr.l, initial_state, last(left_mover_states), left_mover_paths, left_mover_tid)\n    ensures  left_mover_states == AtomicGetStateSequence(arr.l, initial_state, left_mover_paths, left_mover_tid)\n    ensures  arr.l.state_ok(last(left_mover_states))\n    ensures  !IsPhase2(arr, last(left_mover_states), left_mover_tid)\n    ensures  AtomicThreadYielding(arr.l, last(left_mover_states), left_mover_tid)\n    ensures  forall i :: 0 <= i < |left_mover_states|-1 ==> IsPhase2(arr, left_mover_states[i], left_mover_tid)\n    ensures  |left_mover_paths| > 0\n    ensures  forall path :: path in left_mover_paths ==> !arr.l.path_type(path).AtomicPathType_Tau?\n    ensures  arr.l.path_valid(last(left_mover_states), crash_path, crash_path_tid)\n    ensures  post_crash_state' == arr.l.path_next(last(left_mover_states), crash_path, crash_path_tid)\n    ensures  !crash_path_tau ==> OKAndPCTypesMatch(arr, last(left_mover_states), initial_state, crash_path_tid)\n    ensures  rr.crashed(post_crash_state')\n    ensures  RefinementPair(post_crash_state, post_crash_state') in rr.relation\n    decreases arr.left_mover_generation_progress(initial_state, left_mover_tid)\n  {\n    assert AtomicReductionSpecModule.LeftMoversAlwaysEnabledConditions(arr, initial_state, left_mover_tid);\n    var left_mover_path := arr.generate_left_mover(initial_state, left_mover_tid);\n    var state_after_left_mover := arr.l.path_next(initial_state, left_mover_path, left_mover_tid);\n    assert && arr.l.path_valid(initial_state, left_mover_path, left_mover_tid)\n           && !arr.l.path_type(left_mover_path).AtomicPathType_Tau?\n           && 0 <= arr.left_mover_generation_progress(state_after_left_mover, left_mover_tid)\n               < arr.left_mover_generation_progress(initial_state, left_mover_tid);\n\n    assert AtomicReductionSpecModule.LeftMoverCrashPreservationConditions(arr, initial_state, left_mover_path, crash_path,\n                                                                          left_mover_tid, crash_path_tid);\n    var state_after_both_paths := arr.l.path_next(state_after_left_mover, crash_path, crash_path_tid);\n    assert && arr.l.path_valid(state_after_left_mover, crash_path, crash_path_tid)\n           && !arr.l.state_ok(state_after_both_paths)\n           && RefinementPair(post_crash_state, state_after_both_paths) in arr.self_relation;\n\n    if !IsPhase2(arr, state_after_left_mover, left_mover_tid) {\n      assert AtomicThreadYielding(arr.l, state_after_left_mover, left_mover_tid);\n      left_mover_states := [initial_state, state_after_left_mover];\n      left_mover_paths := [left_mover_path];\n      post_crash_state' := state_after_both_paths;\n    }\n    else {\n      var left_mover_states_next, left_mover_paths_next;\n      left_mover_states_next, left_mover_paths_next, post_crash_state' :=\n        lemma_DemonstrateLeftMoversEnabledBeforeCrashCrashPath(\n          arr, rr, state_after_left_mover, state_after_both_paths, crash_path, crash_path_tid, crash_path_tau, left_mover_tid);\n      left_mover_states := [initial_state] + left_mover_states_next;\n      left_mover_paths := [left_mover_path] + left_mover_paths_next;\n      lemma_LastOfConcatenationIsLastOfLatter([initial_state], left_mover_states_next);\n    }\n  }\n\n  lemma lemma_DemonstrateLeftMoversEnabledBeforeCrashCrashPathSequence\n    <LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    rr:RefinementViaReductionRequest<LState, Option<Armada_ThreadHandle>, Armada_Multistep<LPath>, Armada_Multistep<LPath>>,\n    initial_state:LState,\n    post_crash_state:LState,\n    crash_path_paths:seq<LPath>,\n    crash_path_tid:Armada_ThreadHandle,\n    crash_path_tau:bool,\n    crash_path_states:seq<LState>,\n    left_mover_tid:Armada_ThreadHandle\n    ) returns (\n    left_mover_states:seq<LState>,\n    left_mover_paths:seq<Armada_Multistep<LPath>>,\n    crash_path_states':seq<LState>,\n    post_crash_state':LState\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires rr == GetRefinementViaReductionRequest(arr)\n    requires arr.inv(initial_state)\n    requires AtomicNextMultiplePaths(arr.l, initial_state, post_crash_state, crash_path_paths, crash_path_tid)\n    requires forall path :: path in crash_path_paths ==> arr.l.path_type(path).AtomicPathType_Tau? == crash_path_tau\n    requires crash_path_states == AtomicGetStateSequence(arr.l, initial_state, crash_path_paths, crash_path_tid)\n    requires !rr.crashed(initial_state)\n    requires rr.crashed(post_crash_state)\n    requires crash_path_tau || crash_path_tid != left_mover_tid\n    requires IsPhase2(arr, initial_state, left_mover_tid)\n    requires AtomicThreadYielding(arr.l, initial_state, left_mover_tid)\n    ensures  StateNextSeq(left_mover_states, left_mover_paths, rr.lspec.next)\n    ensures  left_mover_states[0] == initial_state\n    ensures  arr.l.state_ok(last(left_mover_states))\n    ensures  !IsPhase2(arr, last(left_mover_states), left_mover_tid)\n    ensures  forall i :: 0 <= i < |left_mover_states|-1 ==> IsPhase2(arr, left_mover_states[i], left_mover_tid)\n    ensures  forall path :: path in left_mover_paths ==> rr.idmap(path) == Some(left_mover_tid)\n    ensures  AtomicNextMultiplePaths(arr.l, last(left_mover_states), post_crash_state', crash_path_paths, crash_path_tid)\n    ensures  crash_path_states' == AtomicGetStateSequence(arr.l, last(left_mover_states), crash_path_paths, crash_path_tid)\n    ensures  |crash_path_states'| == |crash_path_states|\n    ensures  !crash_path_tau ==>\n               forall i :: 0 <= i < |crash_path_states|-1 ==> OKAndPCTypesMatch(arr, crash_path_states'[i], crash_path_states[i], crash_path_tid)\n    ensures  rr.crashed(post_crash_state')\n    ensures  RefinementPair(post_crash_state, post_crash_state') in rr.relation\n  {\n    assert |crash_path_paths| > 0;\n\n    var pos := |crash_path_states|-2;\n    var penultimate_state := crash_path_states[pos];\n    lemma_AtomicValidPathSequenceOfAnyTypeImpliesValidPath(arr.l, initial_state, post_crash_state, crash_path_paths,\n                                                           crash_path_tid, crash_path_states, pos);\n    lemma_AtomicNextLastElement(arr.l, initial_state, post_crash_state, crash_path_paths, crash_path_tid, crash_path_states);\n    lemma_AtomicInvariantHoldsAtIntermediateState(arr.l, arr.inv, initial_state, post_crash_state, crash_path_paths,\n                                                  crash_path_tid, crash_path_states, pos);\n    lemma_AllButLastPreservesAtomicNextMultiplePaths(arr, initial_state, post_crash_state, crash_path_paths, crash_path_states,\n                                                     crash_path_tid);\n    lemma_ExecutingPathSequenceDoesntChangeOtherActorPCType(arr, initial_state, penultimate_state, all_but_last(crash_path_paths),\n                                                            crash_path_tau, crash_path_tid, left_mover_tid);\n\n    var left_mover_states_mid, left_mover_paths_mid;\n    left_mover_states_mid, left_mover_paths_mid, post_crash_state' :=\n      lemma_DemonstrateLeftMoversEnabledBeforeCrashCrashPath(\n        arr, rr, penultimate_state, post_crash_state, last(crash_path_paths), crash_path_tid, crash_path_tau, left_mover_tid);\n\n    left_mover_states, left_mover_paths, crash_path_states' :=\n      lemma_DemonstrateLeftMoversEnabledBeforeCrashCrashPathSequencePart2(\n        arr, rr, initial_state, post_crash_state, crash_path_paths, crash_path_tid, crash_path_tau, crash_path_states,\n        left_mover_tid, left_mover_states_mid, left_mover_paths_mid, post_crash_state');\n  }\n\n  lemma lemma_DemonstrateLeftMoversEnabledBeforeCrashCrashArmada_Multistep\n    <LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    rr:RefinementViaReductionRequest<LState, Option<Armada_ThreadHandle>, Armada_Multistep<LPath>, Armada_Multistep<LPath>>,\n    initial_state:LState,\n    post_crash_state:LState,\n    crash_multistep:Armada_Multistep<LPath>,\n    left_mover_tid:Armada_ThreadHandle\n    ) returns (\n    left_mover_states:seq<LState>,\n    left_mover_multisteps:seq<Armada_Multistep<LPath>>,\n    post_crash_state':LState\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires rr == GetRefinementViaReductionRequest(arr)\n    requires arr.inv(initial_state)\n    requires AtomicNextMultistep(arr.l, initial_state, post_crash_state, crash_multistep.steps, crash_multistep.tid, crash_multistep.tau)\n    requires !rr.crashed(initial_state)\n    requires rr.crashed(post_crash_state)\n    requires crash_multistep.tau || crash_multistep.tid != left_mover_tid\n    requires IsPhase2(arr, initial_state, left_mover_tid)\n    requires AtomicThreadYielding(arr.l, initial_state, left_mover_tid)\n    ensures  StateNextSeq(left_mover_states, left_mover_multisteps, rr.lspec.next)\n    ensures  left_mover_states[0] == initial_state\n    ensures  arr.l.state_ok(last(left_mover_states))\n    ensures  !IsPhase2(arr, last(left_mover_states), left_mover_tid)\n    ensures  forall i :: 0 <= i < |left_mover_states|-1 ==> IsPhase2(arr, left_mover_states[i], left_mover_tid)\n    ensures  forall path :: path in left_mover_multisteps ==> rr.idmap(path) == Some(left_mover_tid)\n    ensures  AtomicNextMultistep(arr.l, last(left_mover_states), post_crash_state', crash_multistep.steps, crash_multistep.tid,\n                                 crash_multistep.tau)\n    ensures  rr.crashed(post_crash_state')\n    ensures  RefinementPair(post_crash_state, post_crash_state') in rr.relation\n  {\n    var crash_multistep_states := AtomicGetStateSequence(arr.l, initial_state, crash_multistep.steps, crash_multistep.tid);\n    var crash_multistep_states';\n    left_mover_states, left_mover_multisteps, crash_multistep_states', post_crash_state' :=\n      lemma_DemonstrateLeftMoversEnabledBeforeCrashCrashPathSequence(\n        arr, rr, initial_state, post_crash_state, crash_multistep.steps, crash_multistep.tid, crash_multistep.tau, crash_multistep_states,\n        left_mover_tid);\n  } \n\n  lemma lemma_DemonstrateLeftMoversEnabledBeforeCrash<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    rr:RefinementViaReductionRequest<LState, Option<Armada_ThreadHandle>, Armada_Multistep<LPath>, Armada_Multistep<LPath>>,\n    initial_state:LState,\n    post_crash_state:LState,\n    crash_multistep:Armada_Multistep<LPath>,\n    left_mover_tid:Armada_ThreadHandle\n    ) returns (\n    left_mover_states:seq<LState>,\n    left_mover_multisteps:seq<Armada_Multistep<LPath>>,\n    post_crash_state':LState\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires rr == GetRefinementViaReductionRequest(arr)\n    requires initial_state in AnnotatedReachables(rr.lspec)\n    requires ActionTuple(initial_state, post_crash_state, crash_multistep) in rr.lspec.next\n    requires !rr.crashed(initial_state)\n    requires rr.crashed(post_crash_state)\n    requires rr.idmap(crash_multistep) != Some(left_mover_tid)\n    requires IsPhase2(arr, initial_state, left_mover_tid)\n    ensures  StateNextSeq(left_mover_states, left_mover_multisteps, rr.lspec.next)\n    ensures  left_mover_states[0] == initial_state\n    ensures  arr.l.state_ok(last(left_mover_states))\n    ensures  !IsPhase2(arr, last(left_mover_states), left_mover_tid)\n    ensures  forall i :: 0 <= i < |left_mover_states|-1 ==> IsPhase2(arr, left_mover_states[i], left_mover_tid)\n    ensures  forall path :: path in left_mover_multisteps ==> rr.idmap(path) == Some(left_mover_tid)\n    ensures  ActionTuple(last(left_mover_states), post_crash_state', crash_multistep) in rr.lspec.next\n    ensures  rr.crashed(post_crash_state')\n    ensures  RefinementPair(post_crash_state, post_crash_state') in rr.relation\n  {\n    lemma_StateAmongAnnotatedReachablesSatisfiesInv(arr, initial_state);\n    lemma_StateAmongAnnotatedReachablesHasThreadYielding(arr, initial_state, left_mover_tid);\n    left_mover_states, left_mover_multisteps, post_crash_state' :=\n      lemma_DemonstrateLeftMoversEnabledBeforeCrashCrashArmada_Multistep(\n        arr, rr, initial_state, post_crash_state, crash_multistep, left_mover_tid);\n    assert AtomicNextMultistep(arr.l, last(left_mover_states), post_crash_state', crash_multistep.steps, crash_multistep.tid,\n                               crash_multistep.tau);\n    assert ActionTuple(last(left_mover_states), post_crash_state', crash_multistep) in rr.lspec.next;\n  }\n\n  lemma lemma_LeftMoversEnabledBeforeCrash<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    )\n    requires ValidAtomicReductionRequest(arr)\n    ensures  LeftMoversEnabledBeforeCrash(GetRefinementViaReductionRequest(arr))\n  {\n    var rr := GetRefinementViaReductionRequest(arr);\n    forall initial_state, post_crash_state, crash_multistep, actor\n      {:trigger RefinementViaReductionSpecModule.LeftMoversEnabledBeforeCrashConditions(rr, initial_state, post_crash_state,\n                                                                                        crash_multistep, actor)}\n      | RefinementViaReductionSpecModule.LeftMoversEnabledBeforeCrashConditions(rr, initial_state, post_crash_state, crash_multistep, actor)\n      ensures exists states, trace, crash_multistep', post_crash_state' ::\n                 && StateNextSeq(states, trace, rr.lspec.next)\n                 && states[0] == initial_state\n                 && !rr.crashed(last(states))\n                 && !rr.phase2(last(states), actor)\n                 && (forall i :: 0 <= i < |states|-1 ==> rr.phase2(states[i], actor))\n                 && (forall path :: path in trace ==> rr.idmap(path) == actor)\n                 && ActionTuple(last(states), post_crash_state', crash_multistep') in rr.lspec.next\n                 && rr.idmap(crash_multistep') == rr.idmap(crash_multistep)\n                 && rr.crashed(post_crash_state')\n                 && RefinementPair(post_crash_state, post_crash_state') in rr.relation\n    {\n      var states, trace, post_crash_state' :=\n        lemma_DemonstrateLeftMoversEnabledBeforeCrash(arr, rr, initial_state, post_crash_state, crash_multistep, actor.v);\n    }\n  }\n\n  //////////////////////////////////////////\n  // LEFT MOVER SELF CRASH PRESERVATION\n  //////////////////////////////////////////\n\n  lemma lemma_DemonstrateLeftMoverSinglePathSelfCrashPreservationAcrossSinglePath\n    <LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    rr:RefinementViaReductionRequest<LState, Option<Armada_ThreadHandle>, Armada_Multistep<LPath>, Armada_Multistep<LPath>>,\n    initial_state:LState,\n    state_after_other_path:LState,\n    state_after_both_paths:LState,\n    other_path:LPath,\n    mover_path:LPath,\n    mover_tid:Armada_ThreadHandle,\n    other_tau:bool,\n    other_tid:Armada_ThreadHandle\n    ) returns (\n    state_after_left_mover:LState\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires rr == GetRefinementViaReductionRequest(arr)\n    requires arr.inv(initial_state)\n    requires arr.l.path_valid(initial_state, other_path, other_tid)\n    requires state_after_other_path == arr.l.path_next(initial_state, other_path, other_tid)\n    requires arr.l.path_type(other_path).AtomicPathType_Tau? == other_tau\n    requires arr.l.path_valid(state_after_other_path, mover_path, mover_tid)\n    requires state_after_both_paths == arr.l.path_next(state_after_other_path, mover_path, mover_tid)\n    requires !arr.l.path_type(mover_path).AtomicPathType_Tau?\n    requires !rr.crashed(initial_state)\n    requires !rr.crashed(state_after_other_path)\n    requires rr.crashed(state_after_both_paths)\n    requires IsPhase2(arr, state_after_other_path, mover_tid)\n    requires other_tau || other_tid != mover_tid\n    ensures  arr.l.path_valid(initial_state, mover_path, mover_tid)\n    ensures  state_after_left_mover == arr.l.path_next(initial_state, mover_path, mover_tid)\n    ensures  rr.crashed(state_after_left_mover)\n    ensures  RefinementPair(state_after_both_paths, state_after_left_mover) in rr.relation\n  {\n    assert AtomicReductionSpecModule.LeftMoverSelfCrashPreservationConditions(arr, initial_state, mover_path, other_path,\n                                                                              mover_tid, other_tid);\n    state_after_left_mover := arr.l.path_next(initial_state, mover_path, mover_tid);\n  }\n\n  lemma lemma_DemonstrateLeftMoverSinglePathSelfCrashPreservationAcrossPathSequence\n    <LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    rr:RefinementViaReductionRequest<LState, Option<Armada_ThreadHandle>, Armada_Multistep<LPath>, Armada_Multistep<LPath>>,\n    initial_state:LState,\n    state_after_other_path:LState,\n    state_after_both_paths:LState,\n    other_paths:seq<LPath>,\n    mover_path:LPath,\n    mover_tid:Armada_ThreadHandle,\n    other_tau:bool,\n    other_tid:Armada_ThreadHandle\n    ) returns (\n    state_after_left_mover:LState\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires rr == GetRefinementViaReductionRequest(arr)\n    requires arr.inv(initial_state)\n    requires AtomicNextMultiplePaths(arr.l, initial_state, state_after_other_path, other_paths, other_tid)\n    requires forall path :: path in other_paths ==> arr.l.path_type(path).AtomicPathType_Tau? == other_tau\n    requires arr.l.path_valid(state_after_other_path, mover_path, mover_tid)\n    requires state_after_both_paths == arr.l.path_next(state_after_other_path, mover_path, mover_tid)\n    requires !arr.l.path_type(mover_path).AtomicPathType_Tau?\n    requires !rr.crashed(initial_state)\n    requires !rr.crashed(state_after_other_path)\n    requires rr.crashed(state_after_both_paths)\n    requires IsPhase2(arr, state_after_other_path, mover_tid)\n    requires other_tau || other_tid != mover_tid\n    ensures  arr.l.path_valid(initial_state, mover_path, mover_tid)\n    ensures  state_after_left_mover == arr.l.path_next(initial_state, mover_path, mover_tid)\n    ensures  rr.crashed(state_after_left_mover)\n    ensures  RefinementPair(state_after_both_paths, state_after_left_mover) in rr.relation\n  {\n    if |other_paths| == 0 {\n      state_after_left_mover := state_after_both_paths;\n      return;\n    }\n\n    var other_states := AtomicGetStateSequence(arr.l, initial_state, other_paths, other_tid);\n    var pos := |other_states|-2;\n    lemma_AtomicValidPathSequenceOfAnyTypeImpliesValidPath(arr.l, initial_state, state_after_other_path, other_paths,\n                                                           other_tid, other_states, pos);\n    lemma_AtomicNextLastElement(arr.l, initial_state, state_after_other_path, other_paths, other_tid, other_states);\n    lemma_AllButLastPreservesAtomicNextMultiplePaths(arr, initial_state, state_after_other_path, other_paths, other_states, other_tid);\n    lemma_AtomicInvariantHoldsAtIntermediateState(arr.l, arr.inv, initial_state, state_after_other_path, other_paths, other_tid,\n                                                  other_states, pos);\n    var state_after_left_mover_mid :=\n      lemma_DemonstrateLeftMoverSinglePathSelfCrashPreservationAcrossSinglePath(\n        arr, rr, other_states[pos], other_states[pos+1], state_after_both_paths, last(other_paths), mover_path,\n        mover_tid, other_tau, other_tid);\n\n    state_after_left_mover :=\n      lemma_DemonstrateLeftMoverSinglePathSelfCrashPreservationAcrossPathSequence(\n        arr, rr, initial_state, other_states[pos], state_after_left_mover_mid, all_but_last(other_paths), mover_path,\n        mover_tid, other_tau, other_tid);\n  }\n\n  lemma lemma_DemonstrateLeftMoverSelfCrashPreservationPathSequence<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    rr:RefinementViaReductionRequest<LState, Option<Armada_ThreadHandle>, Armada_Multistep<LPath>, Armada_Multistep<LPath>>,\n    initial_state:LState,\n    state_after_other_path:LState,\n    state_after_both_paths:LState,\n    other_paths:seq<LPath>,\n    mover_paths:seq<LPath>,\n    mover_states:seq<LState>,\n    mover_tid:Armada_ThreadHandle,\n    other_tau:bool,\n    other_tid:Armada_ThreadHandle\n    ) returns (\n    state_after_left_mover:LState,\n    mover_states':seq<LState>\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires rr == GetRefinementViaReductionRequest(arr)\n    requires arr.inv(initial_state)\n    requires AtomicNextMultiplePaths(arr.l, initial_state, state_after_other_path, other_paths, other_tid)\n    requires forall path :: path in other_paths ==> arr.l.path_type(path).AtomicPathType_Tau? == other_tau\n    requires AtomicNextMultiplePaths(arr.l, state_after_other_path, state_after_both_paths, mover_paths, mover_tid)\n    requires mover_states == AtomicGetStateSequence(arr.l, state_after_other_path, mover_paths, mover_tid)\n    requires forall path :: path in mover_paths ==> !arr.l.path_type(path).AtomicPathType_Tau?\n    requires forall i :: 0 <= i < |mover_states|-1 ==> IsPhase2(arr, mover_states[i], mover_tid)\n    requires !rr.crashed(initial_state)\n    requires !rr.crashed(state_after_other_path)\n    requires rr.crashed(state_after_both_paths)\n    requires IsPhase2(arr, state_after_other_path, mover_tid)\n    requires other_tau || other_tid != mover_tid\n    ensures  AtomicNextMultiplePaths(arr.l, initial_state, state_after_left_mover, mover_paths, mover_tid)\n    ensures  mover_states' == AtomicGetStateSequence(arr.l, initial_state, mover_paths, mover_tid)\n    ensures  |mover_states'| == |mover_states|\n    ensures  forall i :: 0 <= i < |mover_states|-1 ==> OKAndPCTypesMatch(arr, mover_states[i], mover_states'[i], mover_tid)\n    ensures  rr.crashed(state_after_left_mover)\n    ensures  RefinementPair(state_after_both_paths, state_after_left_mover) in rr.relation\n  {\n    assert state_after_both_paths != state_after_other_path;\n    assert |mover_paths| > 0;\n\n    var pos := |mover_states|-2;\n    lemma_AtomicValidPathSequenceOfAnyTypeImpliesValidPath(arr.l, state_after_other_path, state_after_both_paths, mover_paths,\n                                                           mover_tid, mover_states, pos);\n    assert !rr.crashed(mover_states[pos]);\n\n    var other_states := AtomicGetStateSequence(arr.l, initial_state, other_paths, other_tid);\n    lemma_AtomicNextLastElement(arr.l, initial_state, state_after_other_path, other_paths, other_tid, other_states);\n    lemma_AtomicNextLastElement(arr.l, state_after_other_path, state_after_both_paths, mover_paths, mover_tid, mover_states);\n    lemma_AllButLastPreservesAtomicNextMultiplePaths(arr, state_after_other_path, state_after_both_paths, mover_paths, mover_states,\n                                                     mover_tid);\n\n    var mover_states_mid, other_states_mid;\n    if |mover_paths| == 1 {\n      mover_states_mid := [initial_state];\n      other_states_mid := other_states;\n      forall i | 0 <= i < |all_but_last(mover_states)|\n        ensures OKAndPCTypesMatch(arr, mover_states_mid[i], all_but_last(mover_states)[i], mover_tid)\n      {\n        assert mover_states_mid[i] == initial_state;\n        assert all_but_last(mover_states)[i] == state_after_other_path;\n        lemma_ExecutingPathSequenceDoesntChangeOtherActorPCType(arr, initial_state, state_after_other_path, other_paths, other_tau,\n                                                                other_tid, mover_tid);\n      }\n    }\n    else {\n      mover_states_mid, other_states_mid :=\n        lemma_MoveLeftMoversLeftAsSinglePaths(arr, mover_tid, other_tid, other_tau, all_but_last(mover_states),\n                                              all_but_last(mover_paths), other_states, other_paths);\n    }\n    assert forall i :: 0 <= i < |all_but_last(mover_states)| ==>\n                 OKAndPCTypesMatch(arr, mover_states_mid[i], all_but_last(mover_states)[i], mover_tid);\n\n    lemma_AtomicInvariantHoldsAtIntermediateState(arr.l, arr.inv, initial_state, last(mover_states_mid), all_but_last(mover_paths),\n                                                  mover_tid, mover_states_mid, |mover_states_mid|-1);\n    state_after_left_mover :=\n      lemma_DemonstrateLeftMoverSinglePathSelfCrashPreservationAcrossPathSequence(\n        arr, rr, last(mover_states_mid), last(other_states_mid), last(mover_states), other_paths, last(mover_paths),\n        mover_tid, other_tau, other_tid);\n    mover_states' := mover_states_mid + [state_after_left_mover];\n    lemma_ExtendingStateSequenceWorks(arr.l, initial_state, last(mover_states_mid), all_but_last(mover_paths), mover_states_mid,\n                                      mover_tid, last(mover_paths), state_after_left_mover);\n    lemma_AllButLastPlusLastIsSeq(mover_paths);\n\n    forall i | 0 <= i < |mover_states|-1\n      ensures OKAndPCTypesMatch(arr, mover_states[i], mover_states'[i], mover_tid)\n    {\n      assert mover_states'[i] == mover_states_mid[i];\n      assert 0 <= i < |all_but_last(mover_states)|;\n      assert OKAndPCTypesMatch(arr, mover_states_mid[i], all_but_last(mover_states)[i], mover_tid);\n      assert all_but_last(mover_states)[i] == mover_states[i];\n    }\n  }\n\n  lemma lemma_DemonstrateLeftMoverSelfCrashPreservationArmadaMultistep<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    rr:RefinementViaReductionRequest<LState, Option<Armada_ThreadHandle>, Armada_Multistep<LPath>, Armada_Multistep<LPath>>,\n    initial_state:LState,\n    state_after_other_multistep:LState,\n    state_after_both_paths:LState,\n    other_multistep:Armada_Multistep<LPath>,\n    mover_multistep:Armada_Multistep<LPath>,\n    mover_tid:Armada_ThreadHandle\n    ) returns (\n    state_after_left_mover:LState\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires rr == GetRefinementViaReductionRequest(arr)\n    requires arr.inv(initial_state)\n    requires AtomicNextMultistep(arr.l, initial_state, state_after_other_multistep, other_multistep.steps,\n                                 other_multistep.tid, other_multistep.tau)\n    requires AtomicNextMultistep(arr.l, state_after_other_multistep, state_after_both_paths, mover_multistep.steps,\n                                 mover_multistep.tid, mover_multistep.tau)\n    requires mover_multistep.tid == mover_tid\n    requires !mover_multistep.tau\n    requires !rr.crashed(initial_state)\n    requires !rr.crashed(state_after_other_multistep)\n    requires rr.crashed(state_after_both_paths)\n    requires IsPhase2(arr, state_after_other_multistep, mover_tid)\n    requires other_multistep.tau || other_multistep.tid != mover_tid\n    ensures  AtomicNextMultistep(arr.l, initial_state, state_after_left_mover, mover_multistep.steps, mover_multistep.tid,\n                                 mover_multistep.tau)\n    ensures  rr.crashed(state_after_left_mover)\n    ensures  RefinementPair(state_after_both_paths, state_after_left_mover) in rr.relation\n  {\n    var mover_states := AtomicGetStateSequence(arr.l, state_after_other_multistep, mover_multistep.steps, mover_multistep.tid);\n    lemma_IfMultistepStartsInPhase2ThenEachPathDoes(arr, state_after_other_multistep, state_after_both_paths, mover_multistep,\n                                                    mover_states);\n    var mover_states';\n    state_after_left_mover, mover_states' :=\n      lemma_DemonstrateLeftMoverSelfCrashPreservationPathSequence(\n        arr, rr, initial_state, state_after_other_multistep, state_after_both_paths, other_multistep.steps, mover_multistep.steps,\n        mover_states, mover_tid, other_multistep.tau, other_multistep.tid);\n  }\n\n  lemma lemma_DemonstrateLeftMoverSelfCrashPreservation<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    rr:RefinementViaReductionRequest<LState, Option<Armada_ThreadHandle>, Armada_Multistep<LPath>, Armada_Multistep<LPath>>,\n    initial_state:LState,\n    state_after_other_multistep:LState,\n    state_after_both_paths:LState,\n    other_multistep:Armada_Multistep<LPath>,\n    left_mover:Armada_Multistep<LPath>,\n    mover_tid:Armada_ThreadHandle\n    ) returns (\n    state_after_left_mover:LState\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires rr == GetRefinementViaReductionRequest(arr)\n    requires initial_state in AnnotatedReachables(rr.lspec)\n    requires ActionTuple(initial_state, state_after_other_multistep, other_multistep) in rr.lspec.next\n    requires ActionTuple(state_after_other_multistep, state_after_both_paths, left_mover) in rr.lspec.next\n    requires !rr.crashed(initial_state)\n    requires !rr.crashed(state_after_other_multistep)\n    requires rr.crashed(state_after_both_paths)\n    requires IsPhase2(arr, state_after_other_multistep, mover_tid)\n    requires rr.idmap(left_mover) == Some(mover_tid)\n    requires rr.idmap(other_multistep) != Some(mover_tid)\n    ensures  ActionTuple(initial_state, state_after_left_mover, left_mover) in rr.lspec.next\n    ensures  rr.crashed(state_after_left_mover)\n    ensures  RefinementPair(state_after_both_paths, state_after_left_mover) in rr.relation\n  {\n    lemma_StateAmongAnnotatedReachablesSatisfiesInv(arr, initial_state);\n    state_after_left_mover :=\n      lemma_DemonstrateLeftMoverSelfCrashPreservationArmadaMultistep(\n        arr, rr, initial_state, state_after_other_multistep, state_after_both_paths, other_multistep, left_mover, mover_tid);\n  }\n\n  lemma lemma_LeftMoverSelfCrashPreservation<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    )\n    requires ValidAtomicReductionRequest(arr)\n    ensures  RefinementViaReductionSpecModule.LeftMoverSelfCrashPreservation(GetRefinementViaReductionRequest(arr))\n  {\n    var rr := GetRefinementViaReductionRequest(arr);\n\n    forall initial_state, state_after_other_multistep, state_after_both_paths, other_multistep, left_mover\n      {:trigger RefinementViaReductionSpecModule.LeftMoverSelfCrashPreservationConditions(rr, initial_state, state_after_other_multistep,\n                                                                                          state_after_both_paths, other_multistep,\n                                                                                          left_mover)}\n      | RefinementViaReductionSpecModule.LeftMoverSelfCrashPreservationConditions(rr, initial_state, state_after_other_multistep,\n                                                                                  state_after_both_paths, other_multistep, left_mover)\n      && initial_state in AnnotatedReachables(rr.lspec)\n      && ActionTuple(initial_state, state_after_other_multistep, other_multistep) in rr.lspec.next\n      && ActionTuple(state_after_other_multistep, state_after_both_paths, left_mover) in rr.lspec.next\n      && !rr.crashed(initial_state)\n      && !rr.crashed(state_after_other_multistep)\n      && rr.crashed(state_after_both_paths)\n      && rr.phase2(state_after_other_multistep, rr.idmap(left_mover))\n      && rr.idmap(left_mover) != rr.idmap(other_multistep)\n      ensures exists left_mover', state_after_left_mover' ::\n                 && rr.idmap(left_mover') == rr.idmap(left_mover)\n                 && ActionTuple(initial_state, state_after_left_mover', left_mover') in rr.lspec.next\n                 && rr.crashed(state_after_left_mover')\n                 && RefinementPair(state_after_both_paths, state_after_left_mover') in rr.relation\n    {\n      var state_after_left_mover :=\n        lemma_DemonstrateLeftMoverSelfCrashPreservation(arr, rr, initial_state, state_after_other_multistep, state_after_both_paths,\n                                                        other_multistep, left_mover, rr.idmap(left_mover).v);\n    }\n  }\n\n  //////////////////////////////////////\n  // REDUCTION REQUEST VALID\n  //////////////////////////////////////\n\n  lemma lemma_IfAtomicReductionRequestValidThenRefinementViaReductionRequestValid\n    <LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    )\n    requires ValidAtomicReductionRequest(arr)\n    ensures  ValidRefinementViaReductionRequest(GetRefinementViaReductionRequest(arr))\n  {\n    var rr := GetRefinementViaReductionRequest(arr);\n    assert RefinementRelationReflexive(rr.relation);\n    assert RefinementRelationTransitive(rr.relation);\n    assert rr.hspec.init == rr.lspec.init;\n    assert forall s, actor :: s in rr.lspec.init ==> !rr.phase1(s, actor) && !rr.phase2(s, actor);\n    assert forall s, actor :: rr.phase1(s, actor) ==> !rr.phase2(s, actor);\n    lemma_IfAtomicReductionRequestValidThenCrashingCantGoDirectlyFromPhase2ToPhase1(arr);\n    lemma_IfAtomicReductionRequestValidThenCrashingPhaseUnaffectedByOtherActors(arr);\n    lemma_PostCrashStepsStutter(arr);\n    lemma_RightMoversPreserveStateRefinement(arr);\n    lemma_LeftMoversPreserveStateRefinement(arr);\n    lemma_RightMoversCommute(arr);\n    lemma_LeftMoversCommute(arr);\n    lemma_RightMoverCrashPreservation(arr);\n    lemma_LeftMoverSelfCrashPreservation(arr);\n    lemma_ActionSequencesLiftable(arr);\n    lemma_LeftMoversAlwaysEnabled(arr);\n    lemma_LeftMoversEnabledBeforeCrash(arr);\n  }\n\n  //////////////////////////////\n  // UTILITY FUNCTIONS\n  //////////////////////////////\n\n  function LMultistepToHMultistep<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    lmultipath:Armada_Multistep<LPath>\n    ) : Armada_Multistep<HPath>\n  {\n    Armada_Multistep(MapSeqToSeq(lmultipath.steps, arr.lpath_to_hpath), lmultipath.tid, lmultipath.tau)\n  }\n\n  //////////////////////////////\n  // UTILITY LEMMAS\n  //////////////////////////////\n\n  lemma lemma_ArmadaGetStateSequenceLastElement<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    s:LState,\n    s':LState,\n    paths:seq<LPath>,\n    states:seq<LState>,\n    tid:Armada_ThreadHandle\n    )\n    requires AtomicNextMultiplePaths(arr.l, s, s', paths, tid)\n    requires states == AtomicGetStateSequence(arr.l, s, paths, tid)\n    ensures  last(states) == s'\n  {\n    if |paths| > 0 {\n      var s_mid := arr.l.path_next(s, paths[0], tid);\n      lemma_ArmadaGetStateSequenceLastElement(arr, s_mid, s', paths[1..], states[1..], tid);\n    }\n  }\n\n  lemma lemma_AtomicValidPathSequenceImpliesOfAnyType<State, Path, PC>(\n    asf: AtomicSpecFunctions<State, Path, PC>,\n    s: State,\n    paths: seq<Path>,\n    tid: Armada_ThreadHandle\n    )\n    requires AtomicValidPathSequence(asf, s, paths, tid)\n    ensures  AtomicValidPathSequenceOfAnyType(asf, s, paths, tid)\n  {\n    if |paths| > 0 {\n      var s_next := asf.path_next(s, paths[0], tid);\n      lemma_AtomicValidPathSequenceImpliesOfAnyType(asf, s_next, paths[1..], tid);\n    }\n  }\n\n  lemma lemma_AtomicValidPathSequenceImpliesRR<State, Path, PC>(\n    asf: AtomicSpecFunctions<State, Path, PC>,\n    s: State,\n    paths: seq<Path>,\n    tid: Armada_ThreadHandle,\n    pos: int\n    )\n    requires AtomicValidPathSequence(asf, s, paths, tid)\n    requires 0 <= pos < |paths|\n    ensures  asf.path_type(paths[pos]).AtomicPathType_RR?\n  {\n    if pos > 0 {\n      var s_next := asf.path_next(s, paths[0], tid);\n      lemma_AtomicValidPathSequenceImpliesRR(asf, s_next, paths[1..], tid, pos-1);\n    }\n  }\n\n  /////////////////////////////////////////////\n  // SHIM BETWEEN ARMADA AND COHEN-LAMPORT\n  /////////////////////////////////////////////\n\n  function ConvertAtomicTraceEntryToMultistep<State, Path, PC>(\n    asf:AtomicSpecFunctions<State, Path, PC>,\n    entry:AtomicTraceEntry<Path>\n    ) : Armada_Multistep<Path>\n  {\n    match entry\n      case AtomicTraceEntry_Stutter => Armada_Multistep([], 0, false)\n      case AtomicTraceEntry_Tau(tid, path) => Armada_Multistep([path], tid, true)\n      case AtomicTraceEntry_Normal(tid, path) => Armada_Multistep([path], tid, false)\n      case AtomicTraceEntry_Recurrent(tid, yr, rrs, rx) => Armada_Multistep([yr] + rrs + [rx], tid, false)\n  }\n\n  function ConvertMultistepToAtomicTraceEntry<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    multistep:Armada_Multistep<LPath>\n    ) : AtomicTraceEntry<HPath>\n  {\n    if |multistep.steps| == 0 then\n      AtomicTraceEntry_Stutter()\n    else\n      var hpath0 := arr.lpath_to_hpath(multistep.steps[0]);\n      if multistep.tau then\n        AtomicTraceEntry_Tau(multistep.tid, hpath0)\n      else if |multistep.steps| == 1 then\n        AtomicTraceEntry_Normal(multistep.tid, hpath0)\n      else\n        AtomicTraceEntry_Recurrent(\n          multistep.tid,\n          hpath0,\n          MapSeqToSeq(multistep.steps[1..|multistep.steps|-1], arr.lpath_to_hpath),\n          arr.lpath_to_hpath(last(multistep.steps))\n        )\n  }\n\n  lemma lemma_ConvertAtomicTraceEntryToMultistepMaintainsNext<State(!new), Path(!new), PC(!new)>(\n    asf:AtomicSpecFunctions<State, Path, PC>,\n    s:State,\n    s':State,\n    lentry:AtomicTraceEntry<Path>\n    )\n    requires AtomicPathRequiresOK(asf)\n    requires AtomicPathTypeAlwaysMatchesPCTypes(asf)\n    requires AtomicNext(asf, s, s', lentry)\n    ensures  var hmultistep := ConvertAtomicTraceEntryToMultistep(asf, lentry);\n             AtomicNextMultistep(asf, s, s', hmultistep.steps, hmultistep.tid, hmultistep.tau)\n  {\n    var hmultistep := ConvertAtomicTraceEntryToMultistep(asf, lentry);\n    if !lentry.AtomicTraceEntry_Recurrent? {\n      // Everything but the recurrent case is trivial\n      return;\n    }\n\n    var tid, yr, rrs, rx := lentry.recurrent_tid, lentry.yr, lentry.rrs, lentry.rx;\n    var s1 := asf.path_next(s, yr, tid);\n    var s2 := AtomicGetStateAfterPaths(asf, s1, rrs, tid);\n    lemma_AtomicValidPathSequenceImpliesOfAnyType(asf, s1, rrs, tid);\n\n    var paths := [yr] + rrs + [rx];\n    var states_mid := AtomicGetStateSequence(asf, s1, rrs, tid);\n    var states := [s] + states_mid + [s'];\n\n    forall i | 0 <= i < |paths|\n      ensures asf.path_valid(states[i], paths[i], tid)\n      ensures states[i+1] == asf.path_next(states[i], paths[i], tid)\n      ensures !asf.path_type(paths[i]).AtomicPathType_Tau?\n      ensures i > 0 ==> var ty := asf.path_type(paths[i]); ty.AtomicPathType_RY? || ty.AtomicPathType_RS? || ty.AtomicPathType_RR?\n    {\n      if i == 0 {\n        assert states[i] == s;\n        assert states[i+1] == s1;\n        assert paths[i] == yr;\n      }\n      else if i < |paths|-1 {\n        lemma_AtomicValidPathSequenceOfAnyTypeImpliesValidPath(asf, s1, s2, rrs, tid, states_mid, i-1);\n        assert asf.path_valid(states_mid[i-1], rrs[i-1], tid);\n        assert states_mid[i-1+1] == asf.path_next(states_mid[i-1], rrs[i-1], tid);\n        assert states[i] == states_mid[i-1];\n        assert states[i+1] == states_mid[i-1+1];\n        lemma_AtomicValidPathSequenceImpliesRR(asf, s1, rrs, tid, i-1);\n      }\n      else {\n        lemma_AtomicNextLastElement(asf, s1, s2, rrs, tid, states_mid);\n        assert states[i] == s2;\n        assert states[i+1] == s';\n        assert paths[i] == rx;\n      }\n    }\n\n    forall i | 0 < i < |paths|\n      ensures !AtomicThreadYielding(asf, states[i], tid)\n    {\n      assert asf.path_valid(states[i], paths[i], tid);\n      assert states[i+1] == asf.path_next(states[i], paths[i], tid);\n      var ty := asf.path_type(paths[i]);\n      assert ty.AtomicPathType_RY? || ty.AtomicPathType_RS? || ty.AtomicPathType_RR?;\n      assert !AtomicThreadYielding(asf, states[i], tid);\n    }\n\n    var pos := 0;\n    while pos < |paths|\n      invariant 0 <= pos <= |paths|\n      invariant AtomicNextMultiplePaths(asf, s, states[pos], paths[..pos], tid)\n      invariant states[..pos+1] == AtomicGetStateSequence(asf, s, paths[..pos], tid)\n    {\n      lemma_ExtendingStateSequenceWorks(asf, s, states[pos], paths[..pos], states[..pos+1], tid, paths[pos], states[pos+1]);\n      assert paths[..pos+1] == paths[..pos] + [paths[pos]];\n      assert states[..pos+1+1] == states[..pos+1] + [states[pos+1]];\n      pos := pos + 1;\n    }\n\n    assert s' == states[pos];\n    assert paths[..pos] == paths;\n    assert AtomicNextMultiplePaths(asf, s, s', paths, tid);\n  }\n\n  lemma lemma_IfBehaviorSatisfiesGenericSpecThenItSatisfiesRefinementViaReductionLSpec<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    lb:AnnotatedBehavior<LState, AtomicTraceEntry<LPath>>\n    ) returns (\n    hb:AnnotatedBehavior<LState, Armada_Multistep<LPath>>\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires AnnotatedBehaviorSatisfiesSpec(lb, AtomicAnnotatedSpec(arr.l))\n    ensures  AnnotatedBehaviorSatisfiesSpec(hb, GetRefinementViaReductionLSpec(arr))\n    ensures  hb.states == lb.states\n  {\n    var htrace := MapSeqToSeq(lb.trace, entry => ConvertAtomicTraceEntryToMultistep(arr.l, entry));\n    hb := AnnotatedBehavior(lb.states, htrace);\n\n    var lspec := AtomicAnnotatedSpec(arr.l);\n    var hspec := GetRefinementViaReductionLSpec(arr);\n    forall i {:trigger ActionTuple(hb.states[i], hb.states[i+1], hb.trace[i]) in hspec.next} | 0 <= i < |hb.trace|\n      ensures ActionTuple(hb.states[i], hb.states[i+1], hb.trace[i]) in hspec.next\n    {\n      assert ActionTuple(lb.states[i], lb.states[i+1], lb.trace[i]) in AtomicAnnotatedSpec(arr.l).next;\n      lemma_ConvertAtomicTraceEntryToMultistepMaintainsNext(arr.l, lb.states[i], lb.states[i+1], lb.trace[i]);\n    }\n  }\n\n  lemma lemma_LHMaintainsNextRecurrent<LState(!new), LPath(!new), LPC(!new), HState(!new), HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    ls:LState,\n    ls':LState,\n    lmultistep:Armada_Multistep<LPath>,\n    hs:HState,\n    hs':HState,\n    hentry:AtomicTraceEntry<HPath>\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires arr.inv(ls)\n    requires GenericNextReduced(arr, ls, ls', lmultistep.steps, lmultistep.tid, lmultistep.tau)\n    requires !lmultistep.tau\n    requires |lmultistep.steps| > 1\n    requires hs == arr.lstate_to_hstate(ls)\n    requires hs' == arr.lstate_to_hstate(ls')\n    requires hentry == ConvertMultistepToAtomicTraceEntry(arr, lmultistep)\n    requires hentry.AtomicTraceEntry_Recurrent?\n    ensures  AtomicNext(arr.h, hs, hs', hentry)\n  {\n    var lpaths := lmultistep.steps;\n    var tid, lyr, lrrs := lmultistep.tid, lpaths[0], lpaths[1..|lpaths|-1];\n    var hyr, hrrs, hrx := hentry.yr, hentry.rrs, hentry.rx;\n\n    var lstates := AtomicGetStateSequence(arr.l, ls, lpaths, tid);\n    lemma_AtomicNextLastElement(arr.l, ls, ls', lpaths, tid, lstates);\n\n    var hstates := MapSeqToSeq(lstates, arr.lstate_to_hstate);\n\n    lemma_AtomicValidPathSequenceOfAnyTypeImpliesValidPath(arr.l, ls, ls', lpaths, tid, lstates, 0);\n    assert arr.h.path_valid(hs, hyr, tid);\n    assert hstates[1] == arr.h.path_next(hs, hyr, tid);\n\n    assert !IsNonyieldingOrInPhase(arr, ls, tid);\n    assert AtomicThreadYielding(arr.h, hs, tid);\n    assert IsNonyieldingOrInPhase(arr, lstates[1], tid);\n    assert !AtomicThreadYielding(arr.h, hstates[1], tid);\n\n    var pos := 0;\n    while pos < |hrrs|\n      invariant 0 <= pos <= |hrrs|\n      invariant forall p :: p in hrrs[..pos] ==> arr.h.path_type(p).AtomicPathType_RR?\n      invariant AtomicValidPathSequence(arr.h, hstates[1], hrrs[..pos], tid)\n      invariant hstates[pos+1] == AtomicGetStateAfterPaths(arr.h, hstates[1], hrrs[..pos], tid)\n      invariant arr.inv(lstates[pos+1])\n    {\n      lemma_AtomicValidPathSequenceImpliesOfAnyType(arr.h, hstates[1], hrrs[..pos], tid);\n      lemma_AtomicValidPathSequenceOfAnyTypeImpliesValidPath(arr.l, ls, ls', lpaths, tid, lstates, pos+1);\n      assert hrrs[pos] == arr.lpath_to_hpath(lpaths[pos+1]);\n      assert hstates[pos+1] == arr.lstate_to_hstate(lstates[pos+1]);\n      assert arr.h.path_valid(hstates[pos+1], hrrs[pos], tid);\n      assert hstates[pos+1+1] == arr.h.path_next(hstates[pos+1], hrrs[pos], tid);\n      lemma_ExtendAtomicGetStateAfterPaths(arr.h, hstates[1], hstates[pos+1], hrrs[..pos], tid, hrrs[pos]);\n      assert hrrs[..pos+1] == hrrs[..pos] + [hrrs[pos]];\n      lemma_ExtendAtomicValidPathSequence(arr.h, hstates[1], hstates[pos+1], hrrs[..pos], tid, hrrs[pos]);\n      assert IsNonyieldingOrInPhase(arr, lstates[pos+1], tid);\n      assert !AtomicThreadYielding(arr.h, hstates[pos+1], tid);\n      assert IsNonyieldingOrInPhase(arr, lstates[pos+1+1], tid);\n      assert !AtomicThreadYielding(arr.h, hstates[pos+1+1], tid);\n      lemma_AtomicValidPathSequenceOfAnyTypeImpliesValidPath(arr.l, ls, ls', lpaths, tid, lstates, pos+1+1);\n      assert arr.h.path_type(hrrs[pos]).AtomicPathType_RR?;\n      assert forall p :: p in hrrs[..pos+1] ==> p in hrrs[..pos] || p == hrrs[pos];\n      pos := pos + 1;\n    }\n\n    assert hrrs[..pos] == hrrs;\n    lemma_AtomicValidPathSequenceOfAnyTypeImpliesValidPath(arr.l, ls, ls', lpaths, tid, lstates, pos+1);\n    assert AtomicValidRecursiveStep(arr.h, hs, tid, hyr, hrrs, hrx);\n  }\n\n  lemma lemma_LHMaintainsNext<LState(!new), LPath(!new), LPC(!new), HState(!new), HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    ls:LState,\n    ls':LState,\n    lmultistep:Armada_Multistep<LPath>,\n    hs:HState,\n    hs':HState,\n    hentry:AtomicTraceEntry<HPath>\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires arr.inv(ls)\n    requires ActionTuple(ls, ls', lmultistep) in GetRefinementViaReductionHSpec(arr).next;\n    requires hs == arr.lstate_to_hstate(ls)\n    requires hs' == arr.lstate_to_hstate(ls')\n    requires hentry == ConvertMultistepToAtomicTraceEntry(arr, lmultistep)\n    ensures  ActionTuple(hs, hs', hentry) in AtomicAnnotatedSpec(arr.h).next\n  {\n    assert GenericNextReduced(arr, ls, ls', lmultistep.steps, lmultistep.tid, lmultistep.tau);\n    if |lmultistep.steps| == 0 {\n      return;\n    }\n\n    var lstates := AtomicGetStateSequence(arr.l, ls, lmultistep.steps, lmultistep.tid);\n    lemma_AtomicNextLastElement(arr.l, ls, ls', lmultistep.steps, lmultistep.tid, lstates);\n\n    if lmultistep.tau {\n      return;\n    }\n\n    if |lmultistep.steps| == 1 {\n      return;\n    }\n\n    lemma_LHMaintainsNextRecurrent(arr, ls, ls', lmultistep, hs, hs', hentry);\n  }\n\n  lemma lemma_AtomicInvariantHoldsAtIntermediateStateAtomicNextMultiplePaths<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    s:LState,\n    s':LState,\n    paths:seq<LPath>,\n    tid:Armada_ThreadHandle,\n    states:seq<LState>,\n    pos:int\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires AtomicNextMultiplePaths(arr.l, s, s', paths, tid)\n    requires states == AtomicGetStateSequence(arr.l, s, paths, tid)\n    requires 0 <= pos < |states|\n    requires arr.inv(states[0])\n    ensures  arr.inv(states[pos])\n    decreases pos\n  {\n    if pos > 0 {\n      var s_mid := arr.l.path_next(s, paths[0], tid);\n      lemma_AtomicInvariantHoldsAtIntermediateStateAtomicNextMultiplePaths(arr, s_mid, s', paths[1..], tid, states[1..], pos-1);\n    }\n  }\n\n  lemma lemma_GenericNextReducedBehaviorSatisfiesInv<LState(!new), LPath(!new), LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    b:AnnotatedBehavior<LState, Armada_Multistep<LPath>>,\n    i:int\n    )\n    requires ValidAtomicReductionRequest(arr)\n    requires AnnotatedBehaviorSatisfiesSpec(b, GetRefinementViaReductionHSpec(arr))\n    requires 0 <= i < |b.states|\n    ensures  arr.inv(b.states[i])\n  {\n    if i == 0 {\n      return;\n    }\n\n    lemma_GenericNextReducedBehaviorSatisfiesInv(arr, b, i-1);\n\n    var spec := GetRefinementViaReductionHSpec(arr);\n    var prev := i-1;\n    var s := b.states[prev];\n    var s' := b.states[prev+1];\n    var multistep := b.trace[prev];\n    var paths := multistep.steps;\n    var tid := multistep.tid;\n    var states := AtomicGetStateSequence(arr.l, s, paths, tid);\n\n    assert s' == b.states[i];\n    assert 0 <= prev < |b.trace|;\n    assert ActionTuple(b.states[prev], b.states[prev+1], b.trace[prev]) in spec.next;\n    assert GenericNextReduced(arr, s, s', paths, multistep.tid, multistep.tau);\n    assert AtomicNextMultiplePaths(arr.l, s, s', paths, tid);\n    lemma_AtomicInvariantHoldsAtIntermediateStateAtomicNextMultiplePaths(arr, s, s', paths, tid, states, |states|-1);\n    assert arr.inv(states[|states|-1]);\n    assert arr.inv(last(states));\n    lemma_ArmadaGetStateSequenceLastElement(arr, s, s', paths, states, tid);\n    assert last(states) == s';\n    assert arr.inv(s');\n  }\n\n}\n"
  },
  {
    "path": "Armada/strategies/reduction/AtomicReductionSpec.i.dfy",
    "content": "/////////////////////////////////////////////////////////////////////////////////////////////////////\n//\n// This file is the specification for a request to perform refinement via a Cohen-Lamport reduction\n// on an Armada atomic behavior.  Such a reduction takes a behavior satisfying a low-level spec, which\n// allows threads to sometimes be in phase 1 or 2 between trace entries, and returns a behavior\n// satisfying a higher-level specification that only allows those phases in the middle of\n// trace entries.  It does so by lifting sequences of trace entries in the lower-level specification to\n// single trace entries in the higher-level specification.\n//\n// To use this specification, first create a request r of type AtomicReductionRequest.  Then, prove\n// that it's a valid request, i.e., that ValidAtomicReductionRequest(r).  Finally, call\n// lemma_PerformArmadaReduction (in AtomicReduction.i.dfy).\n//\n/////////////////////////////////////////////////////////////////////////////////////////////////////\n\ninclude \"../../util/option.s.dfy\"\ninclude \"../../util/collections/seqs.s.dfy\"\ninclude \"../refinement/GeneralRefinementLemmas.i.dfy\"\ninclude \"../refinement/RefinementConvolution.i.dfy\"\ninclude \"../refinement/AnnotatedBehavior.i.dfy\"\ninclude \"../invariants.i.dfy\"\ninclude \"../generic/GenericArmadaSpec.i.dfy\"\ninclude \"../generic/GenericArmadaAtomic.i.dfy\"\n\nmodule AtomicReductionSpecModule {\n\n  import opened util_option_s\n  import opened util_collections_seqs_s\n  import opened GeneralRefinementModule\n  import opened GeneralRefinementLemmasModule\n  import opened RefinementConvolutionModule\n  import opened AnnotatedBehaviorModule\n  import opened InvariantsModule\n  import opened GenericArmadaSpecModule\n  import opened GenericArmadaAtomicModule\n  import opened ArmadaCommonDefinitions\n\n  datatype AtomicReductionRequest<!LState, !LPath, !LPC, !HState, !HPath, !HPC> =\n    AtomicReductionRequest(\n      l:AtomicSpecFunctions<LState, LPath, LPC>,\n      h:AtomicSpecFunctions<HState, HPath, HPC>,\n      relation:RefinementRelation<LState, HState>,\n      inv:LState->bool,\n      self_relation:RefinementRelation<LState, LState>,\n      lstate_to_hstate:LState->HState,\n      lpath_to_hpath:LPath->HPath,\n      lpc_to_hpc:LPC->HPC,\n      is_phase1:LPC->bool,\n      is_phase2:LPC->bool,\n      generate_left_mover:(LState, Armada_ThreadHandle)->LPath,\n      left_mover_generation_progress:(LState,Armada_ThreadHandle)->int\n      )\n\n  predicate LInitImpliesHInit<LState(!new), LPath, LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    )\n  {\n    forall ls :: arr.l.init(ls) ==> arr.h.init(arr.lstate_to_hstate(ls))\n  }\n\n  predicate LStateToHStateMapsPCsCorrectly<LState(!new), LPath, LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    )\n  {\n    forall ls, tid :: var hs := arr.lstate_to_hstate(ls);\n                var lpc := arr.l.get_thread_pc(ls, tid);\n                var hpc := arr.h.get_thread_pc(hs, tid);\n                hpc == if lpc.Some? then Some(arr.lpc_to_hpc(lpc.v)) else None()\n  }\n\n  predicate LHYieldingCorrespondence<LState, LPath, LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    )\n  {\n    forall lpc :: var hpc := arr.lpc_to_hpc(lpc);\n            arr.h.is_pc_nonyielding(hpc) <==> (arr.l.is_pc_nonyielding(lpc) || arr.is_phase1(lpc) || arr.is_phase2(lpc))\n  }\n\n  predicate LHPathTypesMatchYR(lty:AtomicPathType, hty:AtomicPathType)\n  {\n    match lty\n      case AtomicPathType_Tau => hty.AtomicPathType_Tau?\n      case AtomicPathType_YY  =>\n        hty.AtomicPathType_YY? || hty.AtomicPathType_YR? || hty.AtomicPathType_RY? || hty.AtomicPathType_RR?\n      case AtomicPathType_YS  => hty.AtomicPathType_YS? || hty.AtomicPathType_RS?\n      case AtomicPathType_YR  => hty.AtomicPathType_YR? || hty.AtomicPathType_RR?\n      case AtomicPathType_RY  => hty.AtomicPathType_RY? || hty.AtomicPathType_RR?\n      case AtomicPathType_RS  => hty.AtomicPathType_RS?\n      case AtomicPathType_RR  => hty.AtomicPathType_RR?\n  }\n\n  predicate LHPathPropertiesMatch<LState(!new), LPath(!new), LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    )\n  {\n    forall lpath :: var hpath := arr.lpath_to_hpath(lpath);\n              LHPathTypesMatchYR(arr.l.path_type(lpath), arr.h.path_type(hpath))\n  }\n\n  predicate LPathImpliesHPath<LState(!new), LPath(!new), LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    )\n  {\n    forall ls, lpath, tid ::\n      arr.inv(ls) && arr.l.path_valid(ls, lpath, tid) ==>\n      var ls' := arr.l.path_next(ls, lpath, tid);\n      var hs := arr.lstate_to_hstate(ls);\n      var hpath := arr.lpath_to_hpath(lpath);\n      var hs' := arr.lstate_to_hstate(ls');\n      && arr.h.path_valid(hs, hpath, tid)\n      && hs' == arr.h.path_next(hs, hpath, tid)\n  }\n\n  predicate StateConversionPreservesOK<LState(!new), LPath, LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    )\n  {\n    forall ls :: arr.h.state_ok(arr.lstate_to_hstate(ls)) == arr.l.state_ok(ls)\n  }\n\n  predicate StateConversionSatisfiesRelation<LState(!new), LPath, LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    )\n  {\n    forall ls :: RefinementPair(ls, arr.lstate_to_hstate(ls)) in arr.relation\n  }\n\n  predicate ThreadsDontStartInAnyPhase<LState(!new), LPath, LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    )\n  {\n    forall s, tid :: arr.l.init(s) && arr.l.get_thread_pc(s, tid).Some?\n        ==> var pc := arr.l.get_thread_pc(s, tid).v;\n            !arr.is_phase1(pc) && !arr.is_phase2(pc)\n  }\n\n  predicate PhasesDontOverlap<LState, LPath, LPC(!new), HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    )\n  {\n    forall pc :: arr.is_phase1(pc) ==> !arr.is_phase2(pc)\n  }\n\n  predicate ThreadCantAffectOtherThreadPhaseExceptViaFork\n    <LState(!new), LPath(!new), LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    )\n  {\n    forall s, path, mover_tid, other_tid :: arr.l.path_valid(s, path, mover_tid) && mover_tid != other_tid\n       ==> var s' := arr.l.path_next(s, path, mover_tid);\n           var pc := arr.l.get_thread_pc(s, other_tid);\n           var pc' := arr.l.get_thread_pc(s', other_tid);\n           (pc' != pc ==> pc.None? && !arr.is_phase1(pc'.v) && !arr.is_phase2(pc'.v) && !arr.l.is_pc_nonyielding(pc'.v))\n  }\n\n  predicate PhasesPrecededByYielding<LState(!new), LPath(!new), LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    )\n  {\n    forall s, path, tid ::\n      var s' := arr.l.path_next(s, path, tid);\n      var pc := arr.l.get_thread_pc(s, tid);\n      var pc' := arr.l.get_thread_pc(s', tid);\n      && arr.l.path_valid(s, path, tid)\n      && pc'.Some?\n      && (arr.is_phase1(pc'.v) || arr.is_phase2(pc'.v))\n      && pc.Some?\n      && (!arr.is_phase1(pc.v) && !arr.is_phase2(pc.v))\n      ==> !arr.l.is_pc_nonyielding(pc.v)\n  }\n\n  predicate PhasesSucceededByYielding<LState(!new), LPath(!new), LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    )\n  {\n    forall s, path, tid ::\n      var s' := arr.l.path_next(s, path, tid);\n      var pc := arr.l.get_thread_pc(s, tid);\n      var pc' := arr.l.get_thread_pc(s', tid);\n      && arr.l.path_valid(s, path, tid)\n      && pc.Some?\n      && (arr.is_phase1(pc.v) || arr.is_phase2(pc.v))\n      && pc'.Some?\n      && (!arr.is_phase1(pc'.v) && !arr.is_phase2(pc'.v))\n      ==> !arr.l.is_pc_nonyielding(pc'.v)\n  }\n\n  predicate Phase2NotFollowedByPhase1<LState(!new), LPath(!new), LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    )\n  {\n    forall s, path, tid ::\n      var s' := arr.l.path_next(s, path, tid);\n      var pc := arr.l.get_thread_pc(s, tid);\n      var pc' := arr.l.get_thread_pc(s', tid);\n      && arr.l.path_valid(s, path, tid)\n      && pc.Some?\n      && arr.is_phase2(pc.v)\n      && pc'.Some?\n      && !arr.is_phase2(pc'.v)\n      ==> !arr.is_phase1(pc'.v)\n  }\n\n  predicate RightMoversPreserveStateRefinement\n    <LState(!new), LPath(!new), LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    )\n  {\n    forall s, path, tid :: arr.l.path_valid(s, path, tid) && !arr.l.path_type(path).AtomicPathType_Tau?\n       ==> var s' := arr.l.path_next(s, path, tid);\n           var pc' := arr.l.get_thread_pc(s', tid);\n           (pc'.Some? && arr.is_phase1(pc'.v) && arr.l.state_ok(s') ==> RefinementPair(s', s) in arr.self_relation)\n  }\n\n  predicate LeftMoversPreserveStateRefinement\n    <LState(!new), LPath(!new), LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    )\n  {\n    forall s, path, tid :: arr.l.path_valid(s, path, tid) && !arr.l.path_type(path).AtomicPathType_Tau?\n       ==> var s' := arr.l.path_next(s, path, tid);\n           var pc := arr.l.get_thread_pc(s, tid);\n           (pc.Some? && arr.is_phase2(pc.v) ==> RefinementPair(s, s') in arr.self_relation)\n  }\n\n  predicate RightMoversCommuteConditions<LState(!new), LPath(!new), LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    initial_state:LState,\n    right_mover:LPath,\n    other_path:LPath,\n    mover_tid:Armada_ThreadHandle,\n    other_tid:Armada_ThreadHandle\n    )\n  {\n    var other_tau := arr.l.path_type(other_path).AtomicPathType_Tau?;\n    var state_after_right_mover := arr.l.path_next(initial_state, right_mover, mover_tid);\n    var state_after_both_paths := arr.l.path_next(state_after_right_mover, other_path, other_tid);\n    var pc := arr.l.get_thread_pc(state_after_right_mover, mover_tid);\n    && arr.inv(initial_state)\n    && !arr.l.path_type(right_mover).AtomicPathType_Tau?\n    && arr.l.path_valid(initial_state, right_mover, mover_tid)\n    && pc.Some?\n    && arr.is_phase1(pc.v)\n    && arr.l.path_valid(state_after_right_mover, other_path, other_tid)\n    && arr.l.state_ok(state_after_both_paths)\n    && (other_tau || other_tid != mover_tid)\n  }\n\n  predicate RightMoversCommute<LState(!new), LPath(!new), LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    )\n  {\n      forall initial_state, right_mover, other_path, mover_tid, other_tid\n        {:trigger RightMoversCommuteConditions(arr, initial_state, right_mover, other_path, mover_tid, other_tid)}\n        :: RightMoversCommuteConditions(arr, initial_state, right_mover, other_path, mover_tid, other_tid)\n        ==> var state_after_right_mover := arr.l.path_next(initial_state, right_mover, mover_tid);\n            var state_after_both_paths := arr.l.path_next(state_after_right_mover, other_path, other_tid);\n            var new_middle_state := arr.l.path_next(initial_state, other_path, other_tid);\n            && arr.l.path_valid(initial_state, other_path, other_tid)\n            && arr.l.path_valid(new_middle_state, right_mover, mover_tid)\n            && state_after_both_paths == arr.l.path_next(new_middle_state, right_mover, mover_tid)\n  }\n\n  predicate LeftMoversCommuteConditions<LState(!new), LPath(!new), LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    initial_state:LState,\n    other_path:LPath,\n    left_mover:LPath,\n    mover_tid:Armada_ThreadHandle,\n    other_tid:Armada_ThreadHandle\n    )\n  {\n    var state_after_other_path := arr.l.path_next(initial_state, other_path, other_tid);\n    var state_after_both_paths := arr.l.path_next(state_after_other_path, left_mover, mover_tid);\n    var pc := arr.l.get_thread_pc(state_after_other_path, mover_tid);\n    && arr.inv(initial_state)\n    && arr.l.path_valid(initial_state, other_path, other_tid)\n    && pc.Some?\n    && arr.is_phase2(pc.v)\n    && !arr.l.path_type(left_mover).AtomicPathType_Tau?\n    && arr.l.path_valid(state_after_other_path, left_mover, mover_tid)\n    && (arr.l.path_type(other_path).AtomicPathType_Tau? || other_tid != mover_tid)\n    && arr.l.state_ok(state_after_both_paths)\n  }\n\n  predicate LeftMoversCommute<LState(!new), LPath(!new), LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    )\n  {\n    forall initial_state, other_path, left_mover, mover_tid, other_tid\n      {:trigger LeftMoversCommuteConditions(arr, initial_state, other_path, left_mover, mover_tid, other_tid)}\n      :: LeftMoversCommuteConditions(arr, initial_state, other_path, left_mover, mover_tid, other_tid)\n        ==> var state_after_other_path := arr.l.path_next(initial_state, other_path, other_tid);\n            var state_after_both_paths := arr.l.path_next(state_after_other_path, left_mover, mover_tid);\n            var new_middle_state := arr.l.path_next(initial_state, left_mover, mover_tid);\n            && arr.l.path_valid(initial_state, left_mover, mover_tid)\n            && arr.l.path_valid(new_middle_state, other_path, other_tid)\n            && state_after_both_paths == arr.l.path_next(new_middle_state, other_path, other_tid)\n  }\n\n  predicate LeftMoversAlwaysEnabledConditions\n    <LState(!new), LPath, LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    s:LState,\n    tid:Armada_ThreadHandle\n    )\n  {\n    && arr.inv(s)\n    && arr.l.state_ok(s)\n    && arr.l.get_thread_pc(s, tid).Some?\n    && arr.is_phase2(arr.l.get_thread_pc(s, tid).v)\n  }\n\n  predicate LeftMoversAlwaysEnabled<LState(!new), LPath, LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    )\n  {\n    forall s, tid\n      {:trigger LeftMoversAlwaysEnabledConditions(arr, s, tid)}\n      :: LeftMoversAlwaysEnabledConditions(arr, s, tid)\n      ==> var path := arr.generate_left_mover(s, tid);\n          && arr.l.path_valid(s, path, tid)\n          && !arr.l.path_type(path).AtomicPathType_Tau?\n          && var s' := arr.l.path_next(s, path, tid);\n            0 <= arr.left_mover_generation_progress(s', tid) < arr.left_mover_generation_progress(s, tid)\n  }\n\n  predicate RightMoverCrashPreservationConditions\n    <LState(!new), LPath(!new), LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    initial_state:LState,\n    right_mover:LPath,\n    other_path:LPath,\n    mover_tid:Armada_ThreadHandle,\n    other_tid:Armada_ThreadHandle\n    )\n  {\n    var state_after_right_mover := arr.l.path_next(initial_state, right_mover, mover_tid);\n    var state_after_both_paths := arr.l.path_next(state_after_right_mover, other_path, other_tid);\n    var pc := arr.l.get_thread_pc(state_after_right_mover, mover_tid);\n    var other_tau := arr.l.path_type(other_path).AtomicPathType_Tau?;\n    && arr.inv(initial_state)\n    && arr.l.path_valid(initial_state, right_mover, mover_tid)\n    && arr.l.path_valid(state_after_right_mover, other_path, other_tid)\n    && !arr.l.state_ok(state_after_both_paths)\n    && !arr.l.path_type(right_mover).AtomicPathType_Tau?\n    && pc.Some?\n    && arr.is_phase1(pc.v)\n    && (other_tau || other_tid != mover_tid)\n  }\n    \n  predicate RightMoverCrashPreservation<LState(!new), LPath(!new), LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    )\n  {\n    forall initial_state, right_mover, other_path, mover_tid, other_tid\n      {:trigger RightMoverCrashPreservationConditions(arr, initial_state, right_mover, other_path, mover_tid, other_tid)}\n      :: RightMoverCrashPreservationConditions(arr, initial_state, right_mover, other_path, mover_tid, other_tid)\n      ==> var state_after_right_mover := arr.l.path_next(initial_state, right_mover, mover_tid);\n          var state_after_both_paths := arr.l.path_next(state_after_right_mover, other_path, other_tid);\n          var state_after_other_path := arr.l.path_next(initial_state, other_path, other_tid);\n          && arr.l.path_valid(initial_state, other_path, other_tid)\n          && !arr.l.state_ok(state_after_other_path)\n          && RefinementPair(state_after_both_paths, state_after_other_path) in arr.self_relation\n  }\n\n  predicate LeftMoverCrashPreservationConditions\n    <LState(!new), LPath(!new), LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    initial_state:LState,\n    left_mover:LPath,\n    other_path:LPath,\n    mover_tid:Armada_ThreadHandle,\n    other_tid:Armada_ThreadHandle\n    )\n  {\n    var state_after_other_path := arr.l.path_next(initial_state, other_path, other_tid);\n    var pc := arr.l.get_thread_pc(initial_state, mover_tid);\n    var other_tau := arr.l.path_type(other_path).AtomicPathType_Tau?;\n    && arr.inv(initial_state)\n    && !arr.l.path_type(left_mover).AtomicPathType_Tau?\n    && arr.l.path_valid(initial_state, left_mover, mover_tid)\n    && arr.l.path_valid(initial_state, other_path, other_tid)\n    && arr.l.state_ok(initial_state)\n    && !arr.l.state_ok(state_after_other_path)\n    && pc.Some?\n    && arr.is_phase2(pc.v)\n    && (other_tau || other_tid != mover_tid)\n  }\n  \n  predicate LeftMoverCrashPreservation<LState(!new), LPath(!new), LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    )\n  {\n    forall initial_state, left_mover, other_path, mover_tid, other_tid\n      {:trigger LeftMoverCrashPreservationConditions(arr, initial_state, left_mover, other_path, mover_tid, other_tid)}\n      :: LeftMoverCrashPreservationConditions(arr, initial_state, left_mover, other_path, mover_tid, other_tid)\n      ==> var state_after_other_path := arr.l.path_next(initial_state, other_path, other_tid);\n          var state_after_left_mover := arr.l.path_next(initial_state, left_mover, mover_tid);\n          var state_after_both_paths := arr.l.path_next(state_after_left_mover, other_path, other_tid);\n          && arr.l.path_valid(state_after_left_mover, other_path, other_tid)\n          && !arr.l.state_ok(state_after_both_paths)\n          && RefinementPair(state_after_other_path, state_after_both_paths) in arr.self_relation\n  }\n\n  predicate LeftMoverSelfCrashPreservationConditions\n    <LState(!new), LPath(!new), LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>,\n    initial_state:LState,\n    left_mover:LPath,\n    other_path:LPath,\n    mover_tid:Armada_ThreadHandle,\n    other_tid:Armada_ThreadHandle\n    )\n  {\n    var state_after_other_path := arr.l.path_next(initial_state, other_path, other_tid);\n    var state_after_both_paths := arr.l.path_next(state_after_other_path, left_mover, mover_tid);\n    var pc := arr.l.get_thread_pc(state_after_other_path, mover_tid);\n    var other_tau := arr.l.path_type(other_path).AtomicPathType_Tau?;\n    && arr.inv(initial_state)\n    && !arr.l.path_type(left_mover).AtomicPathType_Tau?\n    && arr.l.path_valid(initial_state, other_path, other_tid)\n    && arr.l.path_valid(state_after_other_path, left_mover, mover_tid)\n    && arr.l.state_ok(initial_state)\n    && !arr.l.state_ok(state_after_both_paths)\n    && pc.Some?\n    && arr.is_phase2(pc.v)\n    && (other_tau || other_tid != mover_tid)\n  }\n    \n  predicate LeftMoverSelfCrashPreservation<LState(!new), LPath(!new), LPC, HState, HPath, HPC>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    )\n  {\n    forall initial_state, left_mover, other_path, mover_tid, other_tid\n      {:trigger LeftMoverSelfCrashPreservationConditions(arr, initial_state, left_mover, other_path, mover_tid, other_tid)}\n      :: LeftMoverSelfCrashPreservationConditions(arr, initial_state, left_mover, other_path, mover_tid, other_tid)\n      ==> var state_after_other_path := arr.l.path_next(initial_state, other_path, other_tid);\n          var state_after_both_paths := arr.l.path_next(state_after_other_path, left_mover, mover_tid);\n          var state_after_left_mover := arr.l.path_next(initial_state, left_mover, mover_tid);\n          && arr.l.path_valid(initial_state, left_mover, mover_tid)\n          && !arr.l.state_ok(state_after_left_mover)\n          && RefinementPair(state_after_both_paths, state_after_left_mover) in arr.self_relation\n  }\n\n  predicate ValidAtomicReductionRequest<LState(!new), LPath(!new), LPC(!new), HState(!new), HPath(!new), HPC(!new)>(\n    arr:AtomicReductionRequest<LState, LPath, LPC, HState, HPath, HPC>\n    )\n  {\n    && RefinementRelationReflexive(arr.self_relation)\n    && RefinementRelationTransitive(arr.self_relation)\n    && RefinementRelationsConvolve(arr.self_relation, arr.relation, arr.relation)\n    && LInitImpliesHInit(arr)\n    && AtomicInitImpliesInv(arr.l, arr.inv)\n    && AtomicPathPreservesInv(arr.l, arr.inv)\n    && AtomicPathRequiresOK(arr.l)\n    && AtomicInitImpliesYielding(arr.l)\n    && AtomicInitImpliesOK(arr.l)\n    && AtomicPathTypeAlwaysMatchesPCTypes(arr.l)\n    && AtomicPathTypeAlwaysMatchesPCTypes(arr.h)\n    && LStateToHStateMapsPCsCorrectly(arr)\n    && LHYieldingCorrespondence(arr)\n    && LHPathPropertiesMatch(arr)\n    && LPathImpliesHPath(arr)\n    && StateConversionPreservesOK(arr)\n    && StateConversionSatisfiesRelation(arr)\n    && ThreadsDontStartInAnyPhase(arr)\n    && PhasesDontOverlap(arr)\n    && PhasesPrecededByYielding(arr)\n    && PhasesSucceededByYielding(arr)\n    && Phase2NotFollowedByPhase1(arr)\n    && AtomicSteppingThreadHasPC(arr.l)\n    && AtomicTauLeavesPCUnchanged(arr.l)\n    && ThreadCantAffectOtherThreadPhaseExceptViaFork(arr)\n    && RightMoversPreserveStateRefinement(arr)\n    && LeftMoversPreserveStateRefinement(arr)\n    && RightMoversCommute(arr)\n    && LeftMoversCommute(arr)\n    && RightMoverCrashPreservation(arr)\n    && LeftMoverCrashPreservation(arr)\n    && LeftMoverSelfCrashPreservation(arr)\n    && LeftMoversAlwaysEnabled(arr)\n  }\n\n}\n"
  },
  {
    "path": "Armada/strategies/reduction/CohenLamportReduction.i.dfy",
    "content": "/////////////////////////////////////////////////////////////////////////////////////////////////////\n//\n// This file contains the lemma for performing a Cohen-Lamport reduction on a behavior.  Such a\n// reduction takes a behavior where some states are in phase 1 or 2, and returns a behavior in which\n// no state (except possibly the last, crashing state) is in phase 1 or 2.  That resulting behavior\n// satisfies the same specification, but is a refinement of the original behavior.\n//\n// To use this lemma, lemma_PerformCohenLamportReduction, you need to first create a request r of\n// type CohenLamportReductionRequest (defined in CohenLamportReductionSpec.i.dfy), then prove that\n// it's a valid request, i.e., that ValidCohenLamportReductionRequest(r).\n//\n// The lemma allows behaviors that crash as their final step.  But, it demans that action sequences\n// be reducible if they crash in the middle, i.e., even if the actor performing those action\n// sequences executes a step that crashes while in phase 1 or 2.\n//\n/////////////////////////////////////////////////////////////////////////////////////////////////////\n\ninclude \"CohenLamportReductionSpec.i.dfy\"\ninclude \"CohenLamportReductionLemmas.i.dfy\"\n\nmodule CohenLamportReductionModule {\n\n  import opened AnnotatedBehaviorModule\n  import opened GeneralRefinementModule\n  import opened RefinementConvolutionModule\n  import opened CohenLamportReductionSpecModule\n  import opened CohenLamportReductionLemmasModule\n\n  lemma lemma_PerformCohenLamportReduction<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    lb:AnnotatedBehavior<State, Step>\n    ) returns (\n    hb:AnnotatedBehavior<State, Step>\n    )\n    requires ValidCohenLamportReductionRequest(clrr)\n    requires AnnotatedBehaviorSatisfiesSpec(lb, clrr.spec)\n    ensures  BehaviorRefinesBehavior(lb.states, hb.states, clrr.relation)\n    ensures  AnnotatedBehaviorSatisfiesSpec(hb, clrr.spec)\n    ensures  forall i, actor :: 0 <= i < |hb.states| ==> var s := hb.states[i]; !clrr.crashed(s) ==> !clrr.phase1(s, actor) && !clrr.phase2(s, actor)\n  {\n    var mb := lemma_RemoveAllNonmovers(clrr, lb);\n    hb := lemma_RemoveAllRightMovers(clrr, mb);\n    lemma_RefinementConvolutionTransitive(lb.states, mb.states, hb.states, clrr.relation);\n  }\n\n}\n"
  },
  {
    "path": "Armada/strategies/reduction/CohenLamportReductionLemmas.i.dfy",
    "content": "/////////////////////////////////////////////////////////////////////////////////////////////////////\n//\n// This file contains lemmas useful in effecting a Cohen-Lamport reduction on a behavior.  They\n// support lemma_PerformCohenLamportReduction (in CohenLamportReduction.i.dfy).\n//\n/////////////////////////////////////////////////////////////////////////////////////////////////////\n\ninclude \"CohenLamportReductionSpec.i.dfy\"\ninclude \"../../util/collections/seqs.i.dfy\"\n\nmodule CohenLamportReductionLemmasModule {\n\n  import opened util_collections_seqs_s\n  import opened GeneralRefinementModule\n  import opened GeneralRefinementLemmasModule\n  import opened RefinementConvolutionModule\n  import opened AnnotatedBehaviorModule\n  import opened InvariantsModule\n  import opened CohenLamportReductionSpecModule\n  import opened util_collections_seqs_i\n\n  lemma lemma_InstantiateLeftMoversBeforeCrash<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    initial_state:State,\n    post_crash_state:State,\n    crash_step:Step,\n    actor:Actor\n    ) returns (\n    states:seq<State>,\n    trace:seq<Step>\n    )\n    requires ValidCohenLamportReductionRequest(clrr)\n    requires LeftMoversEnabledBeforeCrashConditions(clrr, initial_state, post_crash_state, crash_step, actor)\n    ensures  StateNextSeq(states, trace, clrr.spec.next)\n    ensures  |states| > 2\n    ensures  states[0] == initial_state\n    ensures  !clrr.crashed(states[|states|-2])\n    ensures  !clrr.phase2(states[|states|-2], actor)\n    ensures  forall i :: 0 <= i < |states|-2 ==> clrr.phase2(states[i], actor)\n    ensures  forall i :: 0 <= i < |trace|-1 ==> clrr.idmap(trace[i]) == actor\n    ensures  clrr.idmap(last(trace)) != actor\n    ensures  clrr.crashed(last(states))\n    ensures  BehaviorRefinesBehavior([initial_state, post_crash_state], states, clrr.relation)\n  {\n    var mover_states, mover_trace, crash_step', post_crash_state' :|\n      && StateNextSeq(mover_states, mover_trace, clrr.spec.next)\n      && mover_states[0] == initial_state\n      && !clrr.crashed(last(mover_states))\n      && !clrr.phase2(last(mover_states), actor)\n      && (forall i :: 0 <= i < |mover_states|-1 ==> clrr.phase2(mover_states[i], actor))\n      && (forall step :: step in mover_trace ==> clrr.idmap(step) == actor)\n      && ActionTuple(last(mover_states), post_crash_state', crash_step') in clrr.spec.next\n      && clrr.idmap(crash_step') == clrr.idmap(crash_step)\n      && clrr.crashed(post_crash_state')\n      && RefinementPair(post_crash_state, post_crash_state') in clrr.relation;\n\n    var pos := 0;\n    while pos < |mover_trace|\n      invariant 0 <= pos <= |mover_trace|\n      invariant forall i :: 0 <= i <= pos ==> RefinementPair(initial_state, mover_states[i]) in clrr.relation\n    {\n      assert RefinementPair(initial_state, mover_states[pos]) in clrr.relation;\n      assert ActionTuple(mover_states[pos], mover_states[pos+1], mover_trace[pos]) in clrr.spec.next;\n      assert RefinementPair(mover_states[pos], mover_states[pos+1]) in clrr.relation;\n      assert RefinementPair(initial_state, mover_states[pos+1]) in clrr.relation;\n      pos := pos + 1;\n    }\n\n    states := mover_states + [post_crash_state'];\n    trace := mover_trace + [crash_step'];\n    var lm_map := [RefinementRange(0, |mover_states|-1), RefinementRange(|mover_states|, |mover_states|)];\n    assert BehaviorRefinesBehaviorUsingRefinementMap([initial_state, post_crash_state], states, clrr.relation, lm_map);\n  }\n\n  lemma lemma_CreateLeftMoversBeforeCrash<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    lstates:seq<State>,\n    ltrace:seq<Step>,\n    step_actor:Actor\n    ) returns (\n    hstates:seq<State>,\n    htrace:seq<Step>\n    )\n    requires ValidCohenLamportReductionRequest(clrr)\n    requires StateNextSeq(lstates, ltrace, clrr.spec.next)\n    requires lstates[0] in AnnotatedReachables(clrr.spec)\n    requires !clrr.phase1(lstates[0], step_actor)\n    requires !clrr.crashed(lstates[0])\n    requires forall i :: 0 <= i < |ltrace| ==> clrr.idmap(ltrace[i]) != step_actor\n    requires clrr.phase2(last(lstates), step_actor)\n    requires clrr.crashed(last(lstates))\n    ensures  StateNextSeq(hstates, htrace, clrr.spec.next)\n    ensures  BehaviorRefinesBehavior(lstates, hstates, clrr.relation)\n    ensures  |hstates| > |lstates|\n    ensures  forall i :: 0 <= i < |ltrace| ==> hstates[i] == lstates[i]\n    ensures  forall i :: 0 <= i < |ltrace|-1 ==> htrace[i] == ltrace[i]\n    ensures  forall i :: |ltrace|-1 <= i < |htrace|-1 ==> clrr.idmap(htrace[i]) == step_actor\n    ensures  forall i :: |ltrace|-1 <= i < |htrace|-1 ==> clrr.phase2(hstates[i], step_actor)\n    ensures  clrr.idmap(last(htrace)) != step_actor\n    ensures  !clrr.phase2(hstates[|htrace|-1], step_actor)\n    ensures  !clrr.crashed(hstates[|hstates|-2])\n    ensures  clrr.crashed(last(hstates))\n  {\n    var penult := |ltrace|-1;\n    assert ActionTuple(lstates[penult], lstates[penult+1], ltrace[penult]) in clrr.spec.next;\n\n    lemma_StateNextSeqMaintainsAnnotatedReachables(lstates, ltrace, clrr.spec);\n    assert lstates[penult] in lstates;\n    assert LeftMoversEnabledBeforeCrashConditions(clrr, lstates[penult], lstates[penult+1], ltrace[penult], step_actor);\n    var end_states', end_trace' :=\n      lemma_InstantiateLeftMoversBeforeCrash(clrr, lstates[penult], lstates[penult+1], ltrace[penult], step_actor);\n    assert clrr.idmap(last(end_trace')) != step_actor;\n\n    assert lstates[penult..] == [lstates[penult], lstates[penult+1]];\n    lemma_ExtendBehaviorRefinesBehaviorLeft(lstates[penult..], end_states', clrr.relation, lstates[..penult]);\n    hstates := lstates[..penult] + end_states';\n    htrace := ltrace[..penult] + end_trace';\n    lemma_LastOfConcatenationIsLastOfLatter(ltrace[..penult], end_trace');\n    assert last(htrace) == last(end_trace');\n    lemma_TakePlusDropIsSeq(lstates, penult);\n    assert BehaviorRefinesBehavior(lstates, hstates, clrr.relation);\n\n    assert |lstates[..penult]| == penult;\n    assert |ltrace[..penult]| == penult;\n\n    forall i {:trigger ActionTuple(hstates[i], hstates[i+1], htrace[i]) in clrr.spec.next} | 0 <= i < |htrace|\n      ensures ActionTuple(hstates[i], hstates[i+1], htrace[i]) in clrr.spec.next\n    {\n      lemma_IndexIntoConcatenation(lstates[..penult], end_states', i);\n      lemma_IndexIntoConcatenation(lstates[..penult], end_states', i+1);\n      lemma_IndexIntoConcatenation(ltrace[..penult], end_trace', i);\n\n      if i < penult-1 {\n        assert hstates[i] == lstates[i];\n        assert hstates[i+1] == lstates[i+1];\n        assert htrace[i] == ltrace[i];\n        assert ActionTuple(lstates[i], lstates[i+1], ltrace[i]) in clrr.spec.next;\n      }\n      else if i == penult - 1 {\n        assert hstates[i] == lstates[i];\n        assert hstates[i+1] == end_states'[0] == lstates[penult] == lstates[i+1];\n        assert htrace[i] == ltrace[i];\n        assert ActionTuple(lstates[i], lstates[i+1], ltrace[i]) in clrr.spec.next;\n      }\n      else {\n        var iadj := i - penult;\n        assert hstates[i] == end_states'[iadj];\n        calc {\n          hstates[i+1];\n          end_states'[i+1-penult];\n            { assert i+1-penult == iadj+1; }\n          end_states'[iadj+1];\n        }\n        assert htrace[i] == end_trace'[iadj];\n        assert ActionTuple(end_states'[iadj], end_states'[iadj+1], end_trace'[iadj]) in clrr.spec.next;\n      }\n    }\n    assert StateNextSeq(hstates, htrace, clrr.spec.next);\n\n    forall i | 0 <= i < |ltrace|\n      ensures hstates[i] == lstates[i]\n    {\n      lemma_IndexIntoConcatenation(lstates[..penult], end_states', i);\n\n      if i < penult {\n        assert hstates[i] == lstates[..penult][i] == lstates[i];\n      }\n      else {\n        assert i == penult;\n        assert hstates[i] == end_states'[0] == lstates[penult] == lstates[i];\n      }\n    }\n\n    forall i | 0 <= i < |ltrace|-1\n      ensures htrace[i] == ltrace[i]\n    {\n      lemma_IndexIntoConcatenation(lstates[..penult], end_states', i);\n\n      assert htrace[i] == ltrace[..penult][i] == ltrace[i];\n    }\n  }\n\n  lemma lemma_BringLeftMoversToStartByCreatingLeftMoversBeforeCrash<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    lstates:seq<State>,\n    ltrace:seq<Step>,\n    step_actor:Actor\n    ) returns (\n    hstates:seq<State>,\n    htrace:seq<Step>,\n    end_pos:int\n    )\n    requires ValidCohenLamportReductionRequest(clrr)\n    requires StateNextSeq(lstates, ltrace, clrr.spec.next)\n    requires lstates[0] in AnnotatedReachables(clrr.spec)\n    requires !clrr.phase1(lstates[0], step_actor)\n    requires !clrr.crashed(lstates[0])\n    requires forall i :: 0 <= i < |ltrace| ==> clrr.idmap(ltrace[i]) != step_actor\n    requires clrr.phase2(last(lstates), step_actor)\n    requires clrr.crashed(last(lstates))\n    ensures  BehaviorRefinesBehavior(lstates, hstates, clrr.relation)\n    ensures  StateNextSeq(hstates, htrace, clrr.spec.next)\n    ensures  hstates[0] == lstates[0]\n    ensures  |hstates| <= |lstates| + end_pos\n    ensures  0 <= end_pos < |hstates|\n    ensures  var s := hstates[end_pos]; !clrr.crashed(s) ==> !clrr.phase1(s, step_actor) && !clrr.phase2(s, step_actor)\n    ensures  forall i :: 0 <= i < end_pos ==> clrr.idmap(htrace[i]) == step_actor\n    ensures  forall i :: 0 <= i < end_pos ==> clrr.phase2(hstates[i], step_actor)\n  {\n    var mstates, mtrace := lemma_CreateLeftMoversBeforeCrash(clrr, lstates, ltrace, step_actor);\n\n    var hstates_trunc, htrace_trunc;\n    hstates_trunc, htrace_trunc, end_pos :=\n      lemma_BringLeftMoversToStartAfterCreatingLeftMovers(clrr, all_but_last(mstates), all_but_last(mtrace), step_actor, |ltrace|-1);\n    assert !clrr.crashed(last(all_but_last(mstates)));\n    assert last(hstates_trunc) == last(all_but_last(mstates));\n\n    lemma_ExtendBehaviorRefinesBehaviorRightOne(all_but_last(mstates), hstates_trunc, clrr.relation, last(mstates));\n    assert BehaviorRefinesBehavior(all_but_last(mstates) + [last(mstates)], hstates_trunc + [last(mstates)], clrr.relation);\n    hstates := hstates_trunc + [last(mstates)];\n    htrace := htrace_trunc + [last(mtrace)];\n    lemma_AllButLastPlusLastIsSeq(mstates);\n    assert BehaviorRefinesBehavior(mstates, hstates, clrr.relation);\n\n    forall i {:trigger ActionTuple(hstates[i], hstates[i+1], htrace[i]) in clrr.spec.next} | 0 <= i < |htrace|\n      ensures ActionTuple(hstates[i], hstates[i+1], htrace[i]) in clrr.spec.next\n    {\n      if i < |htrace|-1 {\n        assert hstates[i] == hstates_trunc[i];\n        assert hstates[i+1] == hstates_trunc[i+1];\n        assert htrace[i] == htrace_trunc[i];\n        assert ActionTuple(hstates_trunc[i], hstates_trunc[i+1], htrace_trunc[i]) in clrr.spec.next;\n      }\n      else {\n        var j := |mstates|-2;\n        assert hstates[i] == last(hstates_trunc) == last(all_but_last(mstates)) == mstates[j];\n        assert hstates[i+1] == last(mstates) == mstates[j+1];\n        assert htrace[i] == last(mtrace) == mtrace[j];\n        assert ActionTuple(mstates[j], mstates[j+1], mtrace[j]) in clrr.spec.next;\n      }\n    }\n\n    assert StateNextSeq(hstates, htrace, clrr.spec.next);\n    lemma_RefinementConvolutionTransitive(lstates, mstates, hstates, clrr.relation);\n  }\n\n  lemma lemma_BringLeftMoversToStartAfterCreatingLeftMovers<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    lstates:seq<State>,\n    ltrace:seq<Step>,\n    step_actor:Actor,\n    left_mover_pos:int\n    ) returns (\n    hstates:seq<State>,\n    htrace:seq<Step>,\n    end_pos:int\n    )\n    requires ValidCohenLamportReductionRequest(clrr)\n    requires StateNextSeq(lstates, ltrace, clrr.spec.next)\n    requires lstates[0] in AnnotatedReachables(clrr.spec)\n    requires 0 <= left_mover_pos < |ltrace|\n    requires forall i :: 0 <= i < left_mover_pos ==> clrr.idmap(ltrace[i]) != step_actor\n    requires forall i :: left_mover_pos <= i < |ltrace| ==> clrr.idmap(ltrace[i]) == step_actor\n    requires forall i :: left_mover_pos <= i < |ltrace| ==> clrr.phase2(lstates[i], step_actor)\n    requires clrr.crashed(last(lstates)) || !clrr.phase2(last(lstates), step_actor)\n    ensures  BehaviorRefinesBehavior(lstates, hstates, clrr.relation)\n    ensures  StateNextSeq(hstates, htrace, clrr.spec.next)\n    ensures  hstates[0] == lstates[0]\n    ensures  |hstates| <= |lstates|\n    ensures  end_pos == |ltrace| - left_mover_pos\n    ensures  0 <= end_pos < |hstates|\n    ensures  var s := hstates[end_pos]; !clrr.crashed(s) ==> !clrr.phase1(s, step_actor) && !clrr.phase2(s, step_actor)\n    ensures  forall i :: 0 <= i < end_pos ==> clrr.idmap(htrace[i]) == step_actor\n    ensures  forall i :: 0 <= i < end_pos ==> clrr.phase2(hstates[i], step_actor)\n    ensures  !clrr.crashed(last(lstates)) ==> last(hstates) == last(lstates)\n    decreases |lstates|\n  {\n    end_pos := |ltrace| - left_mover_pos;\n\n    var mstates, mtrace := lemma_BringLeftMoverToStart(clrr, lstates, ltrace, step_actor, left_mover_pos);\n\n    if left_mover_pos == |ltrace|-1 {\n      hstates := mstates;\n      htrace := mtrace;\n      return;\n    }\n\n    var pos_plus := left_mover_pos+1;\n    assert ActionTuple(lstates[pos_plus], lstates[pos_plus+1], ltrace[pos_plus]) in clrr.spec.next;\n\n    lemma_ReduceStateNextSeqLeft(mstates, mtrace, clrr.spec.next);\n    lemma_StateNextSeqMaintainsAnnotatedReachables(mstates, mtrace, clrr.spec);\n    assert mstates[1..][0] in mstates;\n    var hstates_trunc, htrace_trunc, end_pos_trunc :=\n      lemma_BringLeftMoversToStartAfterCreatingLeftMovers(clrr, mstates[1..], mtrace[1..], step_actor, left_mover_pos);\n\n    hstates := [mstates[0]] + hstates_trunc;\n    htrace := [mtrace[0]] + htrace_trunc;\n    lemma_ExtendStateNextSeqLeft(hstates_trunc, htrace_trunc, clrr.spec.next, mstates[0], mtrace[0]);\n    lemma_ExtendBehaviorRefinesBehaviorLeftOne(mstates[1..], hstates_trunc, clrr.relation, mstates[0]);\n    lemma_SequenceIsCarPlusCdr(mstates);\n    lemma_RefinementConvolutionTransitive(lstates, mstates, hstates, clrr.relation);\n  }\n\n  lemma lemma_BringLeftMoversToStartByCreatingLeftMoversAtEnd<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    lstates:seq<State>,\n    ltrace:seq<Step>,\n    step_actor:Actor\n    ) returns (\n    hstates:seq<State>,\n    htrace:seq<Step>,\n    end_pos:int\n    )\n    requires ValidCohenLamportReductionRequest(clrr)\n    requires StateNextSeq(lstates, ltrace, clrr.spec.next)\n    requires lstates[0] in AnnotatedReachables(clrr.spec)\n    requires forall i :: 0 <= i < |ltrace| ==> clrr.idmap(ltrace[i]) != step_actor\n    requires clrr.phase2(last(lstates), step_actor)\n    requires !clrr.crashed(last(lstates))\n    ensures  BehaviorRefinesBehavior(lstates, hstates, clrr.relation)\n    ensures  StateNextSeq(hstates, htrace, clrr.spec.next)\n    ensures  hstates[0] == lstates[0]\n    ensures  |hstates| <= |lstates| + end_pos\n    ensures  0 <= end_pos < |hstates|\n    ensures  var s := hstates[end_pos]; !clrr.crashed(s) ==> !clrr.phase1(s, step_actor) && !clrr.phase2(s, step_actor)\n    ensures  forall i :: 0 <= i < end_pos ==> clrr.idmap(htrace[i]) == step_actor\n    ensures  forall i :: 0 <= i < end_pos ==> clrr.phase2(hstates[i], step_actor)\n  {\n    lemma_StateNextSeqMaintainsAnnotatedReachables(lstates, ltrace, clrr.spec);\n    assert last(lstates) in lstates;\n    assert LeftMoversAlwaysEnabledConditions(clrr, last(lstates), step_actor);\n\n    var end_states', end_trace' :|\n          && StateNextSeq(end_states', end_trace', clrr.spec.next)\n          && end_states'[0] == last(lstates)\n          && (clrr.crashed(last(end_states')) || !clrr.phase2(last(end_states'), step_actor))\n          && (forall i :: 0 <= i < |end_states'|-1 ==> clrr.phase2(end_states'[i], step_actor))\n          && (forall step :: step in end_trace' ==> clrr.idmap(step) == step_actor);\n\n    var pos := 0;\n    while pos < |end_trace'|\n      invariant 0 <= pos <= |end_trace'|\n      invariant forall i :: 0 <= i <= pos ==> RefinementPair(last(lstates), end_states'[i]) in clrr.relation\n    {\n      assert RefinementPair(last(lstates), end_states'[pos]) in clrr.relation;\n      assert ActionTuple(end_states'[pos], end_states'[pos+1], end_trace'[pos]) in clrr.spec.next;\n      assert RefinementPair(end_states'[pos], end_states'[pos+1]) in clrr.relation;\n      assert RefinementPair(last(lstates), end_states'[pos+1]) in clrr.relation;\n      pos := pos + 1;\n    }\n\n    var end_states := [last(lstates)];\n    var lm_map := [RefinementRange(0, |end_trace'|)];\n    assert BehaviorRefinesBehaviorUsingRefinementMap(end_states, end_states', clrr.relation, lm_map);\n    assert BehaviorRefinesBehavior(end_states, end_states', clrr.relation);\n    lemma_ExtendBehaviorRefinesBehaviorLeft(end_states, end_states', clrr.relation, all_but_last(lstates));\n\n    var mstates := all_but_last(lstates) + end_states';\n    var mtrace := ltrace + end_trace';\n    lemma_AllButLastPlusLastIsSeq(lstates);\n    assert BehaviorRefinesBehavior(lstates, mstates, clrr.relation);\n\n    forall i {:trigger ActionTuple(mstates[i], mstates[i+1], mtrace[i]) in clrr.spec.next} | 0 <= i < |mtrace|\n      ensures ActionTuple(mstates[i], mstates[i+1], mtrace[i]) in clrr.spec.next\n    {\n      if i < |ltrace| {\n        assert mstates[i] == lstates[i];\n        assert mstates[i+1] == lstates[i+1];\n        assert mtrace[i] == ltrace[i];\n        assert ActionTuple(lstates[i], lstates[i+1], ltrace[i]) in clrr.spec.next;\n      }\n      else {\n        var iminus := i - |ltrace|;\n        assert mstates[i] == end_states'[iminus];\n        assert mstates[i+1] == end_states'[iminus+1];\n        assert mtrace[i] == end_trace'[iminus];\n        assert ActionTuple(end_states'[iminus], end_states'[iminus+1], end_trace'[iminus]) in clrr.spec.next;\n      }\n    }\n    assert StateNextSeq(mstates, mtrace, clrr.spec.next);\n\n    hstates, htrace, end_pos :=\n      lemma_BringLeftMoversToStartAfterCreatingLeftMovers(clrr, mstates, mtrace, step_actor, |ltrace|);\n    lemma_RefinementConvolutionTransitive(lstates, mstates, hstates, clrr.relation);\n  }\n\n  lemma lemma_BringLeftMoversToStartByCreatingLeftMovers<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    lstates:seq<State>,\n    ltrace:seq<Step>,\n    step_actor:Actor\n    ) returns (\n    hstates:seq<State>,\n    htrace:seq<Step>,\n    end_pos:int\n    )\n    requires ValidCohenLamportReductionRequest(clrr)\n    requires StateNextSeq(lstates, ltrace, clrr.spec.next)\n    requires lstates[0] in AnnotatedReachables(clrr.spec)\n    requires !clrr.phase1(lstates[0], step_actor)\n    requires !clrr.crashed(lstates[0])\n    requires clrr.phase2(lstates[0], step_actor)\n    requires forall i :: 0 <= i < |ltrace| ==> clrr.idmap(ltrace[i]) != step_actor\n    requires clrr.phase2(last(lstates), step_actor)\n    ensures  BehaviorRefinesBehavior(lstates, hstates, clrr.relation)\n    ensures  StateNextSeq(hstates, htrace, clrr.spec.next)\n    ensures  hstates[0] == lstates[0]\n    ensures  |hstates| <= |lstates| + end_pos\n    ensures  0 <= end_pos < |hstates|\n    ensures  var s := hstates[end_pos]; !clrr.crashed(s) ==> !clrr.phase1(s, step_actor) && !clrr.phase2(s, step_actor)\n    ensures  forall i :: 0 <= i < end_pos ==> clrr.idmap(htrace[i]) == step_actor\n    ensures  forall i :: 0 <= i < end_pos ==> clrr.phase2(hstates[i], step_actor)\n  {\n    if clrr.crashed(last(lstates)) {\n      hstates, htrace, end_pos :=\n        lemma_BringLeftMoversToStartByCreatingLeftMoversBeforeCrash(clrr, lstates, ltrace, step_actor);\n    }\n    else {\n      hstates, htrace, end_pos :=\n        lemma_BringLeftMoversToStartByCreatingLeftMoversAtEnd(clrr, lstates, ltrace, step_actor);\n    }\n  }\n\n  lemma lemma_BringLeftMoverLeftOneCaseCrashing<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    lstates:seq<State>,\n    ltrace:seq<Step>,\n    step_actor:Actor\n    ) returns (\n    hstates:seq<State>,\n    htrace:seq<Step>\n    )\n    requires ValidCohenLamportReductionRequest(clrr)\n    requires StateNextSeq(lstates, ltrace, clrr.spec.next)\n    requires lstates[0] in AnnotatedReachables(clrr.spec)\n    requires |ltrace| == 2\n    requires clrr.idmap(ltrace[0]) != step_actor\n    requires clrr.idmap(ltrace[1]) == step_actor\n    requires clrr.phase2(lstates[1], step_actor)\n    requires clrr.crashed(lstates[2])\n    ensures  BehaviorRefinesBehavior(lstates, hstates, clrr.relation)\n    ensures  StateNextSeq(hstates, htrace, clrr.spec.next)\n    ensures  hstates[0] == lstates[0]\n    ensures  |hstates| <= |lstates|\n    ensures  |htrace| == 1\n    ensures  clrr.crashed(hstates[1])\n    ensures  clrr.idmap(htrace[0]) == step_actor\n    ensures  clrr.phase2(hstates[0], step_actor)\n  {\n    var zero := 0;\n    assert ActionTuple(lstates[zero], lstates[zero+1], ltrace[zero]) in clrr.spec.next;\n    var one := 1;\n    assert ActionTuple(lstates[one], lstates[one+1], ltrace[one]) in clrr.spec.next;\n    assert LeftMoverSelfCrashPreservationConditions(clrr, lstates[0], lstates[1], lstates[2], ltrace[0], ltrace[1]);\n    var left_mover', state_after_left_mover' :|\n          && clrr.idmap(left_mover') == clrr.idmap(ltrace[1])\n          && ActionTuple(lstates[0], state_after_left_mover', left_mover') in clrr.spec.next\n          && clrr.crashed(state_after_left_mover')\n          && RefinementPair(lstates[2], state_after_left_mover') in clrr.relation;\n\n    hstates := [lstates[0], state_after_left_mover'];\n    htrace := [left_mover'];\n\n    var lh_map := [RefinementRange(0, 0), RefinementRange(1, 1), RefinementRange(1, 1)];\n    forall i, j {:trigger RefinementPair(lstates[i], hstates[j]) in clrr.relation}\n      | 0 <= i < |lstates| && lh_map[i].first <= j <= lh_map[i].last\n      ensures RefinementPair(lstates[i], hstates[j]) in clrr.relation\n    {\n      if i == 0 && j == 0 {\n        assert lstates[i] == lstates[0];\n        assert hstates[j] == lstates[0];\n        assert RefinementPair(lstates[0], lstates[0]) in clrr.relation;\n      }\n      else if i == 1 && j == 1 {\n        assert lstates[i] == lstates[1];\n        assert hstates[j] == state_after_left_mover';\n        assert ActionTuple(lstates[1], lstates[2], ltrace[1]) in clrr.spec.next;\n        assert RefinementPair(lstates[1], lstates[2]) in clrr.relation;\n        assert RefinementPair(lstates[2], state_after_left_mover') in clrr.relation;\n        assert RefinementPair(lstates[1], state_after_left_mover') in clrr.relation;\n      }\n      else {\n        assert i == 2 && j == 1;\n        assert lstates[i] == lstates[2];\n        assert hstates[j] == state_after_left_mover';\n        assert RefinementPair(lstates[2], state_after_left_mover') in clrr.relation;\n      }\n    }\n    assert BehaviorRefinesBehaviorUsingRefinementMap(lstates, hstates, clrr.relation, lh_map);\n    assert BehaviorRefinesBehavior(lstates, hstates, clrr.relation);\n  }\n\n  lemma lemma_BringLeftMoverLeftOneCaseNotCrashing<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    lstates:seq<State>,\n    ltrace:seq<Step>,\n    step_actor:Actor\n    ) returns (\n    hstates:seq<State>,\n    htrace:seq<Step>\n    )\n    requires ValidCohenLamportReductionRequest(clrr)\n    requires StateNextSeq(lstates, ltrace, clrr.spec.next)\n    requires lstates[0] in AnnotatedReachables(clrr.spec)\n    requires |ltrace| >= 2\n    requires clrr.idmap(ltrace[0]) != step_actor\n    requires clrr.idmap(ltrace[1]) == step_actor\n    requires clrr.phase2(lstates[1], step_actor)\n    requires !clrr.crashed(lstates[2])\n    ensures  BehaviorRefinesBehavior(lstates, hstates, clrr.relation)\n    ensures  StateNextSeq(hstates, htrace, clrr.spec.next)\n    ensures  hstates[0] == lstates[0]\n    ensures  |hstates| == |lstates|\n    ensures  !clrr.crashed(hstates[1])\n    ensures  !clrr.crashed(hstates[2])\n    ensures  hstates[2..] == lstates[2..]\n    ensures  htrace[2..] == ltrace[2..]\n    ensures  clrr.idmap(htrace[0]) == step_actor\n    ensures  clrr.idmap(htrace[1]) != step_actor\n    ensures  clrr.phase2(hstates[0], step_actor)\n    ensures  clrr.phase2(hstates[1], step_actor) <==> clrr.phase2(lstates[2], step_actor)\n  {\n    var zero := 0;\n    assert ActionTuple(lstates[zero], lstates[zero+1], ltrace[zero]) in clrr.spec.next;\n    var one := 1;\n    assert ActionTuple(lstates[one], lstates[one+1], ltrace[one]) in clrr.spec.next;\n    assert LeftMoversCommuteConditions(clrr, lstates[0], lstates[1], lstates[2], ltrace[0], ltrace[1]);\n    var new_middle_state, left_mover', other_step' :|\n          && ActionTuple(lstates[0], new_middle_state, left_mover') in clrr.spec.next\n          && ActionTuple(new_middle_state, lstates[2], other_step') in clrr.spec.next\n          && clrr.idmap(left_mover') == clrr.idmap(ltrace[1])\n          && clrr.idmap(other_step') == clrr.idmap(ltrace[0]);\n\n    var hstates_init := [lstates[0], new_middle_state, lstates[2]];\n    var htrace_init := [left_mover', other_step'];\n    assert StateNextSeq(hstates_init, htrace_init, clrr.spec.next);\n\n    hstates := hstates_init + lstates[3..];\n    htrace := htrace_init + ltrace[2..];\n    assert StateNextSeq(hstates, htrace, clrr.spec.next);\n\n    var lh_map := [RefinementRange(0, 1), RefinementRange(2, 2), RefinementRange(2, 2)];\n    var lstates_init := lstates[..3];\n    forall i, j {:trigger RefinementPair(lstates_init[i], hstates_init[j]) in clrr.relation}\n      | 0 <= i < |lstates_init| && lh_map[i].first <= j <= lh_map[i].last\n      ensures RefinementPair(lstates_init[i], hstates_init[j]) in clrr.relation\n    {\n      if i == 0 && j == 0 {\n        assert lstates_init[i] == lstates[0];\n        assert hstates_init[j] == lstates[0];\n        assert RefinementPair(lstates[0], lstates[0]) in clrr.relation;\n      }\n      else if i == 0 && j == 1 {\n        assert lstates_init[i] == lstates[0];\n        assert hstates_init[j] == new_middle_state;\n        assert ActionTuple(lstates[0], new_middle_state, left_mover') in clrr.spec.next;\n        assert RefinementPair(lstates[0], new_middle_state) in clrr.relation;\n      }\n      else if i == 1 && j == 2 {\n        assert lstates_init[i] == lstates[1];\n        assert hstates_init[j] == lstates[2];\n        assert ActionTuple(lstates[1], lstates[2], ltrace[1]) in clrr.spec.next;\n        assert RefinementPair(lstates[1], lstates[2]) in clrr.relation;\n      }\n      else {\n        assert i == 2 && j == 2;\n        assert lstates_init[i] == lstates[2];\n        assert hstates_init[j] == lstates[2];\n        assert RefinementPair(lstates[2], lstates[2]) in clrr.relation;\n      }\n    }\n    assert BehaviorRefinesBehaviorUsingRefinementMap(lstates_init, hstates_init, clrr.relation, lh_map);\n    assert BehaviorRefinesBehavior(lstates_init, hstates_init, clrr.relation);\n    lemma_ExtendBehaviorRefinesBehaviorRight(lstates_init, hstates_init, clrr.relation, lstates[3..]);\n    lemma_TakePlusDropIsSeq(lstates, 3);\n  }\n\n  lemma lemma_BringLeftMoverLeftOne<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    lstates:seq<State>,\n    ltrace:seq<Step>,\n    step_actor:Actor\n    ) returns (\n    hstates:seq<State>,\n    htrace:seq<Step>\n    )\n    requires ValidCohenLamportReductionRequest(clrr)\n    requires StateNextSeq(lstates, ltrace, clrr.spec.next)\n    requires lstates[0] in AnnotatedReachables(clrr.spec)\n    requires |ltrace| >= 2\n    requires clrr.idmap(ltrace[0]) != step_actor\n    requires clrr.idmap(ltrace[1]) == step_actor\n    requires clrr.phase2(lstates[1], step_actor)\n    ensures  BehaviorRefinesBehavior(lstates, hstates, clrr.relation)\n    ensures  StateNextSeq(hstates, htrace, clrr.spec.next)\n    ensures  hstates[0] == lstates[0]\n    ensures  |hstates| <= |lstates|\n    ensures  |htrace| > 0\n    ensures  !clrr.phase1(hstates[1], step_actor)\n    ensures  if clrr.crashed(lstates[2]) then\n               && |hstates| == 2\n               && clrr.crashed(hstates[1])\n             else\n               && |hstates| == |lstates|\n               && hstates[2..] == lstates[2..]\n               && htrace[2..] == ltrace[2..]\n               && !clrr.crashed(hstates[1])\n               && (clrr.phase2(hstates[1], step_actor) <==> clrr.phase2(lstates[2], step_actor))\n               && clrr.idmap(htrace[1]) != step_actor\n    ensures  clrr.idmap(htrace[0]) == step_actor\n    ensures  clrr.phase2(hstates[0], step_actor)\n  {\n    if clrr.crashed(lstates[2]) {\n      if 2 < |ltrace| {\n        var two := 2;\n        assert ActionTuple(lstates[two], lstates[two+1], ltrace[two]) in clrr.spec.next;\n        assert false;\n      }\n      hstates, htrace := lemma_BringLeftMoverLeftOneCaseCrashing(clrr, lstates, ltrace, step_actor);\n    }\n    else {\n      hstates, htrace := lemma_BringLeftMoverLeftOneCaseNotCrashing(clrr, lstates, ltrace, step_actor);\n    }\n  }\n   \n  lemma lemma_BringLeftMoverToStart<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    lstates:seq<State>,\n    ltrace:seq<Step>,\n    step_actor:Actor,\n    left_mover_pos:int\n    ) returns (\n    hstates:seq<State>,\n    htrace:seq<Step>\n    )\n    requires ValidCohenLamportReductionRequest(clrr)\n    requires StateNextSeq(lstates, ltrace, clrr.spec.next)\n    requires lstates[0] in AnnotatedReachables(clrr.spec)\n    requires 0 <= left_mover_pos < |ltrace|\n    requires forall i :: 0 <= i < left_mover_pos ==> clrr.idmap(ltrace[i]) != step_actor\n    requires clrr.idmap(ltrace[left_mover_pos]) == step_actor\n    requires clrr.phase2(lstates[left_mover_pos], step_actor)\n    ensures  BehaviorRefinesBehavior(lstates, hstates, clrr.relation)\n    ensures  StateNextSeq(hstates, htrace, clrr.spec.next)\n    ensures  hstates[0] == lstates[0]\n    ensures  |hstates| <= |lstates|\n    ensures  |htrace| > 0\n    ensures  clrr.idmap(htrace[0]) == step_actor\n    ensures  !clrr.phase1(hstates[1], step_actor)\n    ensures  clrr.phase2(hstates[0], step_actor)\n    ensures  if clrr.crashed(lstates[left_mover_pos+1]) then\n               && |hstates| == 2\n               && clrr.crashed(hstates[1])\n             else\n               && |hstates| == |lstates|\n               && !clrr.crashed(hstates[1])\n               && hstates[left_mover_pos+1..] == lstates[left_mover_pos+1..]\n               && htrace[left_mover_pos+1..] == ltrace[left_mover_pos+1..]\n               && (clrr.phase2(hstates[1], step_actor) <==> clrr.phase2(lstates[left_mover_pos+1], step_actor))\n               && (forall i :: 1 <= i <= left_mover_pos ==> clrr.idmap(htrace[i]) != step_actor)\n    decreases left_mover_pos\n  {\n    if clrr.crashed(lstates[left_mover_pos+1]) && |ltrace| > left_mover_pos+1 {\n      var pos_plus := left_mover_pos + 1;\n      assert ActionTuple(lstates[pos_plus], lstates[pos_plus+1], ltrace[pos_plus]) in clrr.spec.next;\n      assert false;\n    }\n\n    if left_mover_pos == 0 {\n      hstates := lstates;\n      htrace := ltrace;\n      lemma_IfRefinementRelationReflexiveThenBehaviorRefinesItself(lstates, clrr.relation);\n      return;\n    }\n\n    var prev := left_mover_pos-1;\n    lemma_DropStateNextSeq(lstates, ltrace, clrr.spec.next, prev);\n    lemma_StateNextSeqMaintainsAnnotatedReachables(lstates, ltrace, clrr.spec);\n    assert lstates[prev..][0] in lstates;\n    var mstates_trunc, mtrace_trunc := lemma_BringLeftMoverLeftOne(clrr, lstates[prev..], ltrace[prev..], step_actor);\n\n    if !clrr.crashed(lstates[left_mover_pos+1]) {\n      assert !clrr.crashed(lstates[prev..][2]);\n      assert |mstates_trunc| == |lstates[prev..]| == |lstates| - prev;\n      assert mtrace_trunc[2..] == ltrace[prev..][2..] == ltrace[left_mover_pos+1..];\n    }\n\n    var mstates := lstates[..prev] + mstates_trunc;\n    var mtrace := ltrace[..prev] + mtrace_trunc;\n    lemma_ExtendBehaviorRefinesBehaviorLeft(lstates[prev..], mstates_trunc, clrr.relation, lstates[..prev]);\n    lemma_TakePlusDropIsSeq(lstates, prev);\n    lemma_TakePlusDropIsSeq(ltrace, prev);\n    assert BehaviorRefinesBehavior(lstates, mstates, clrr.relation);\n\n    forall i {:trigger ActionTuple(mstates[i], mstates[i+1], mtrace[i]) in clrr.spec.next} | 0 <= i < |mtrace|\n      ensures ActionTuple(mstates[i], mstates[i+1], mtrace[i]) in clrr.spec.next\n    {\n      if i < prev-1 {\n        assert mstates[i] == lstates[i];\n        assert mstates[i+1] == lstates[i+1];\n        assert mtrace[i] == ltrace[i];\n        assert ActionTuple(lstates[i], lstates[i+1], ltrace[i]) in clrr.spec.next;\n      }\n      else if i == prev-1 {\n        assert mstates[i] == lstates[i];\n        assert mstates[i+1] == mstates_trunc[0] == lstates[prev..][0] == lstates[prev] == lstates[i+1];\n        assert mtrace[i] == ltrace[i];\n        assert ActionTuple(lstates[i], lstates[i+1], ltrace[i]) in clrr.spec.next;\n      }\n      else {\n        var iminus := i-prev;\n        assert mstates[i] == mstates_trunc[iminus];\n        assert mstates[i+1] == mstates_trunc[iminus+1];\n        assert mtrace[i] == mtrace_trunc[iminus];\n        assert ActionTuple(mstates_trunc[iminus], mstates_trunc[iminus+1], mtrace_trunc[iminus]) in clrr.spec.next;\n      }\n    }\n    assert StateNextSeq(mstates, mtrace, clrr.spec.next);\n\n    hstates, htrace := lemma_BringLeftMoverToStart(clrr, mstates, mtrace, step_actor, left_mover_pos-1);\n    calc {\n      mstates[left_mover_pos-1+1];\n      (lstates[..prev] + mstates_trunc)[left_mover_pos];\n      mstates_trunc[left_mover_pos - prev];\n    }\n    lemma_RefinementConvolutionTransitive(lstates, mstates, hstates, clrr.relation);\n  }\n\n  lemma lemma_FindFirstLeftMover<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    states:seq<State>,\n    trace:seq<Step>,\n    step_actor:Actor\n    ) returns (\n    pos:int\n    )\n    requires ValidCohenLamportReductionRequest(clrr)\n    requires StateNextSeq(states, trace, clrr.spec.next)\n    requires states[0] in AnnotatedReachables(clrr.spec)\n    requires clrr.phase2(states[0], step_actor)\n\n    ensures  0 <= pos <= |trace|\n    ensures  forall i :: 0 <= i < pos ==> clrr.idmap(trace[i]) != step_actor\n    ensures  clrr.phase2(states[pos], step_actor)\n    ensures  pos < |trace| ==> clrr.idmap(trace[pos]) == step_actor\n  {\n    pos := 0;\n    while pos < |trace| && clrr.idmap(trace[pos]) != step_actor\n      invariant 0 <= pos <= |trace|\n      invariant forall i :: 0 <= i < pos ==> clrr.idmap(trace[i]) != step_actor\n      invariant clrr.phase2(states[pos], step_actor)\n    {\n      assert ActionTuple(states[pos], states[pos+1], trace[pos]) in clrr.spec.next;\n      pos := pos + 1;\n    }\n  }\n\n  lemma lemma_BringLeftMoversToStart<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    lstates:seq<State>,\n    ltrace:seq<Step>,\n    step_actor:Actor\n    ) returns (\n    hstates:seq<State>,\n    htrace:seq<Step>,\n    end_pos:int\n    )\n    requires ValidCohenLamportReductionRequest(clrr)\n    requires StateNextSeq(lstates, ltrace, clrr.spec.next)\n    requires lstates[0] in AnnotatedReachables(clrr.spec)\n    requires clrr.crashed(lstates[0]) || !clrr.phase1(lstates[0], step_actor)\n    ensures  BehaviorRefinesBehavior(lstates, hstates, clrr.relation)\n    ensures  StateNextSeq(hstates, htrace, clrr.spec.next)\n    ensures  hstates[0] == lstates[0]\n    ensures  |hstates| <= |lstates| + end_pos\n    ensures  0 <= end_pos < |hstates|\n    ensures  var s := hstates[end_pos]; !clrr.crashed(s) ==> !clrr.phase1(s, step_actor) && !clrr.phase2(s, step_actor)\n    ensures  forall i :: 0 <= i < end_pos ==> clrr.idmap(htrace[i]) == step_actor\n    ensures  forall i :: 0 <= i < end_pos ==> clrr.phase2(hstates[i], step_actor)\n    decreases |lstates|\n  {\n    if clrr.crashed(lstates[0]) || !clrr.phase2(lstates[0], step_actor) {\n      hstates := lstates;\n      htrace := ltrace;\n      end_pos := 0;\n      lemma_IfRefinementRelationReflexiveThenBehaviorRefinesItself(lstates, clrr.relation);\n      return;\n    }\n\n    var left_mover_pos := lemma_FindFirstLeftMover(clrr, lstates, ltrace, step_actor);\n    if left_mover_pos == |ltrace| {\n      hstates, htrace, end_pos := lemma_BringLeftMoversToStartByCreatingLeftMovers(clrr, lstates, ltrace, step_actor);\n      return;\n    }\n\n    var mstates, mtrace := lemma_BringLeftMoverToStart(clrr, lstates, ltrace, step_actor, left_mover_pos);\n\n    var zero := 0;\n    assert ActionTuple(mstates[zero], mstates[zero+1], mtrace[zero]) in clrr.spec.next;\n    lemma_NextMaintainsAnnotatedReachables(mstates[zero], mstates[zero+1], mtrace[zero], clrr.spec);\n    lemma_ReduceStateNextSeqLeft(mstates, mtrace, clrr.spec.next);\n    var m2states, m2trace, m2end_pos := lemma_BringLeftMoversToStart(clrr, mstates[1..], mtrace[1..], step_actor);\n\n    hstates := [mstates[0]] + m2states;\n    htrace := [mtrace[0]] + m2trace;\n    lemma_ExtendStateNextSeqLeft(m2states, m2trace, clrr.spec.next, mstates[0], mtrace[0]);\n    lemma_ExtendBehaviorRefinesBehaviorLeftOne(mstates[1..], m2states, clrr.relation, mstates[0]);\n    lemma_SequenceIsCarPlusCdr(mstates);\n    lemma_RefinementConvolutionTransitive(lstates, mstates, hstates, clrr.relation);\n    end_pos := m2end_pos + 1;\n  }\n\n  lemma lemma_EarlierStateInBehaviorAlsoNotCrashed<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    lb:AnnotatedBehavior<State, Step>,\n    pos2:int,\n    pos1:int\n    )\n    requires ValidCohenLamportReductionRequest(clrr)\n    requires AnnotatedBehaviorSatisfiesSpec(lb, clrr.spec)\n    requires 0 <= pos1 <= pos2 < |lb.states|\n    requires !clrr.crashed(lb.states[pos2])\n    ensures  !clrr.crashed(lb.states[pos1])\n  {\n    if pos1 < pos2 {\n      var pos := pos2-1;\n      assert ActionTuple(lb.states[pos], lb.states[pos+1], lb.trace[pos]) in clrr.spec.next;\n      lemma_EarlierStateInBehaviorAlsoNotCrashed(clrr, lb, pos, pos1);\n    }\n  }\n\n  lemma lemma_EstablishBehaviorRefinesBehaviorAfterMovingRightMoverRight<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    lb:AnnotatedBehavior<State, Step>,\n    step_actor:Actor,\n    right_mover_pos:int,\n    new_middle_state:State,\n    other_step':Step,\n    right_mover':Step,\n    hb:AnnotatedBehavior<State, Step>\n    )\n    requires ValidCohenLamportReductionRequest(clrr)\n    requires AnnotatedBehaviorSatisfiesSpec(lb, clrr.spec)\n    requires forall i :: 0 <= i < |lb.trace| ==> !IsNonmoverPos(clrr, lb.states, lb.trace, i)\n    requires !clrr.crashed(last(lb.states))\n    requires 0 <= right_mover_pos < |lb.trace|-1\n    requires clrr.idmap(lb.trace[right_mover_pos]) == step_actor\n    requires forall i :: right_mover_pos < i < |lb.trace| ==> clrr.idmap(lb.trace[i]) != step_actor\n    requires clrr.phase1(lb.states[right_mover_pos+1], step_actor)\n    requires ActionTuple(lb.states[right_mover_pos], new_middle_state, other_step') in clrr.spec.next\n    requires ActionTuple(new_middle_state, lb.states[right_mover_pos+2], right_mover') in clrr.spec.next\n    requires clrr.idmap(other_step') == clrr.idmap(lb.trace[right_mover_pos+1])\n    requires clrr.idmap(right_mover') == clrr.idmap(lb.trace[right_mover_pos])\n    requires hb.states == lb.states[..right_mover_pos+1] + [new_middle_state] + lb.states[right_mover_pos+2..]\n    requires hb.trace == lb.trace[..right_mover_pos] + [other_step', right_mover'] + lb.trace[right_mover_pos+2..]\n\n    ensures  BehaviorRefinesBehavior(lb.states, hb.states, clrr.relation)\n    ensures  last(hb.states) == last(lb.states)\n    ensures  |hb.states| == |lb.states|\n    ensures  |hb.trace| == |lb.trace|\n    ensures  clrr.idmap(hb.trace[right_mover_pos+1]) == step_actor\n  {\n    var lb2 := lb.states[right_mover_pos..right_mover_pos+3];\n    var hb2 := [lb.states[right_mover_pos], new_middle_state, lb.states[right_mover_pos+2]];\n\n    var right_mover_pos_plus := right_mover_pos+1;\n\n    forall ensures RefinementPair(lb2[2], hb2[1]) in clrr.relation\n    {\n      assert ActionTuple(new_middle_state, lb.states[right_mover_pos+2], right_mover') in clrr.spec.next;\n      assert clrr.idmap(right_mover') == step_actor;\n      assert ActionTuple(lb.states[right_mover_pos_plus], lb.states[right_mover_pos_plus+1], lb.trace[right_mover_pos_plus])\n               in clrr.spec.next;\n      assert clrr.idmap(lb.trace[right_mover_pos_plus]) != step_actor;\n      assert clrr.phase1(lb.states[right_mover_pos_plus+1], step_actor);\n      lemma_EarlierStateInBehaviorAlsoNotCrashed(clrr, lb, |lb.states|-1, right_mover_pos+2);\n      assert !clrr.crashed(lb.states[right_mover_pos+2]);\n      assert RefinementPair(lb.states[right_mover_pos+2], new_middle_state) in clrr.relation;\n    }\n\n    forall ensures RefinementPair(lb2[1], hb2[0]) in clrr.relation\n    {\n      assert ActionTuple(lb.states[right_mover_pos], lb.states[right_mover_pos+1], lb.trace[right_mover_pos]) in clrr.spec.next;\n      assert clrr.idmap(lb.trace[right_mover_pos]) == step_actor;\n      lemma_EarlierStateInBehaviorAlsoNotCrashed(clrr, lb, |lb.states|-1, right_mover_pos+1);\n      assert !clrr.crashed(lb.states[right_mover_pos+1]);\n      assert RefinementPair(lb.states[right_mover_pos+1], lb.states[right_mover_pos]) in clrr.relation;\n    }\n\n    forall ensures RefinementPair(lb2[0], hb2[0]) in clrr.relation\n    {\n      assert hb2[0] == lb2[0];\n    }\n\n    forall ensures RefinementPair(lb2[2], hb2[2]) in clrr.relation\n    {\n      assert hb2[2] == lb2[2];\n    }\n\n    var lh_map := [RefinementRange(0, 0), RefinementRange(0, 0), RefinementRange(1, 2)];\n    assert BehaviorRefinesBehaviorUsingRefinementMap(lb2, hb2, clrr.relation, lh_map);\n\n    lemma_ExtendBehaviorRefinesBehaviorLeft(lb2, hb2, clrr.relation, lb.states[..right_mover_pos]);\n    lemma_ExtendBehaviorRefinesBehaviorRight(lb.states[..right_mover_pos] + lb2, lb.states[..right_mover_pos] + hb2, clrr.relation,\n                                             lb.states[right_mover_pos+3..]);\n    assert BehaviorRefinesBehavior(lb.states[..right_mover_pos] + lb2 + lb.states[right_mover_pos+3..],\n                                   lb.states[..right_mover_pos] + hb2 + lb.states[right_mover_pos+3..], clrr.relation);\n    lemma_SeqEqualsThreeWayConcatentation(lb.states, right_mover_pos, right_mover_pos+3);\n\n    assert hb.states == lb.states[..right_mover_pos] + hb2 + lb.states[right_mover_pos+3..];\n  }\n\n  lemma lemma_EstablishBehaviorSatisfiesSpecAfterMovingRightMoverRight<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    lb:AnnotatedBehavior<State, Step>,\n    step_actor:Actor,\n    right_mover_pos:int,\n    new_middle_state:State,\n    other_step':Step,\n    right_mover':Step,\n    hb:AnnotatedBehavior<State, Step>\n    )\n    requires ValidCohenLamportReductionRequest(clrr)\n    requires AnnotatedBehaviorSatisfiesSpec(lb, clrr.spec)\n    requires forall i :: 0 <= i < |lb.trace| ==> !IsNonmoverPos(clrr, lb.states, lb.trace, i)\n    requires !clrr.crashed(last(lb.states))\n    requires 0 <= right_mover_pos < |lb.trace|-1\n    requires clrr.idmap(lb.trace[right_mover_pos]) == step_actor\n    requires forall i :: right_mover_pos < i < |lb.trace| ==> clrr.idmap(lb.trace[i]) != step_actor\n    requires clrr.phase1(lb.states[right_mover_pos+1], step_actor)\n    requires ActionTuple(lb.states[right_mover_pos], new_middle_state, other_step') in clrr.spec.next\n    requires ActionTuple(new_middle_state, lb.states[right_mover_pos+2], right_mover') in clrr.spec.next\n    requires clrr.idmap(other_step') == clrr.idmap(lb.trace[right_mover_pos+1])\n    requires clrr.idmap(right_mover') == clrr.idmap(lb.trace[right_mover_pos])\n    requires hb.states == lb.states[..right_mover_pos+1] + [new_middle_state] + lb.states[right_mover_pos+2..]\n    requires hb.trace == lb.trace[..right_mover_pos] + [other_step', right_mover'] + lb.trace[right_mover_pos+2..]\n\n    ensures  AnnotatedBehaviorSatisfiesSpec(hb, clrr.spec)\n  {\n    forall i {:trigger ActionTuple(hb.states[i], hb.states[i+1], hb.trace[i]) in clrr.spec.next}\n      | 0 <= i < |hb.trace|\n      ensures ActionTuple(hb.states[i], hb.states[i+1], hb.trace[i]) in clrr.spec.next\n    {\n      if i == right_mover_pos {\n        assert hb.states[i] == lb.states[right_mover_pos];\n        assert hb.states[i+1] == new_middle_state;\n        assert hb.trace[i] == other_step';\n        assert ActionTuple(lb.states[right_mover_pos], new_middle_state, other_step') in clrr.spec.next;\n      }\n      else if i == right_mover_pos + 1 {\n        assert hb.states[i] == new_middle_state;\n        assert hb.states[i+1] == lb.states[right_mover_pos+2];\n        assert hb.trace[i] == right_mover';\n        assert ActionTuple(new_middle_state, lb.states[right_mover_pos+2], right_mover') in clrr.spec.next;\n      }\n      else {\n        assert hb.states[i] == lb.states[i];\n        assert hb.states[i+1] == lb.states[i+1];\n        assert hb.trace[i] == lb.trace[i];\n        assert ActionTuple(lb.states[i], lb.states[i+1], lb.trace[i]) in clrr.spec.next;\n      }\n    }\n  }\n\n  lemma lemma_EstablishStillNoNonmoversAfterMovingRightMoverRight<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    lb:AnnotatedBehavior<State, Step>,\n    step_actor:Actor,\n    right_mover_pos:int,\n    new_middle_state:State,\n    other_step':Step,\n    right_mover':Step,\n    hb:AnnotatedBehavior<State, Step>\n    )\n    requires ValidCohenLamportReductionRequest(clrr)\n    requires AnnotatedBehaviorSatisfiesSpec(lb, clrr.spec)\n    requires forall i :: 0 <= i < |lb.trace| ==> !IsNonmoverPos(clrr, lb.states, lb.trace, i)\n    requires !clrr.crashed(last(lb.states))\n    requires 0 <= right_mover_pos < |lb.trace|-1\n    requires clrr.idmap(lb.trace[right_mover_pos]) == step_actor\n    requires forall i :: right_mover_pos < i < |lb.trace| ==> clrr.idmap(lb.trace[i]) != step_actor\n    requires clrr.phase1(lb.states[right_mover_pos+1], step_actor)\n    requires ActionTuple(lb.states[right_mover_pos], new_middle_state, other_step') in clrr.spec.next\n    requires ActionTuple(new_middle_state, lb.states[right_mover_pos+2], right_mover') in clrr.spec.next\n    requires clrr.idmap(other_step') == clrr.idmap(lb.trace[right_mover_pos+1])\n    requires clrr.idmap(right_mover') == clrr.idmap(lb.trace[right_mover_pos])\n    requires hb.states == lb.states[..right_mover_pos+1] + [new_middle_state] + lb.states[right_mover_pos+2..]\n    requires hb.trace == lb.trace[..right_mover_pos] + [other_step', right_mover'] + lb.trace[right_mover_pos+2..]\n\n    ensures  forall i :: 0 <= i < |hb.trace| ==> !IsNonmoverPos(clrr, hb.states, hb.trace, i)\n  {\n    var right_mover_pos_plus := right_mover_pos + 1;\n\n    lemma_EarlierStateInBehaviorAlsoNotCrashed(clrr, lb, |lb.states|-1, right_mover_pos+2);\n\n    forall i | 0 <= i < |hb.trace|\n      ensures !IsNonmoverPos(clrr, hb.states, hb.trace, i)\n    {\n      if i == right_mover_pos {\n        assert hb.states[i] == lb.states[right_mover_pos];\n        assert hb.states[i+1] == new_middle_state;\n        assert !IsNonmoverPos(clrr, lb.states, lb.trace, right_mover_pos_plus);\n        assert ActionTuple(lb.states[right_mover_pos], lb.states[right_mover_pos+1], lb.trace[right_mover_pos]) in clrr.spec.next;\n        assert ActionTuple(new_middle_state, lb.states[right_mover_pos_plus+1], right_mover') in clrr.spec.next;\n        assert !IsNonmoverStep(clrr, lb.states[right_mover_pos], new_middle_state, clrr.idmap(hb.trace[i]));\n      }\n      else if i == right_mover_pos + 1 {\n        assert hb.states[i] == new_middle_state;\n        assert hb.states[i+1] == lb.states[right_mover_pos+2];\n      }\n      else {\n        assert !IsNonmoverPos(clrr, lb.states, lb.trace, i);\n      }\n    }\n  }\n\n  lemma lemma_MoveRightMoverRight<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    lb:AnnotatedBehavior<State, Step>,\n    step_actor:Actor,\n    right_mover_pos:int\n    ) returns (\n    hb:AnnotatedBehavior<State, Step>\n    )\n    requires ValidCohenLamportReductionRequest(clrr)\n    requires AnnotatedBehaviorSatisfiesSpec(lb, clrr.spec)\n    requires forall i :: 0 <= i < |lb.trace| ==> !IsNonmoverPos(clrr, lb.states, lb.trace, i)\n    requires !clrr.crashed(last(lb.states))\n    requires 0 <= right_mover_pos < |lb.trace|-1\n    requires clrr.idmap(lb.trace[right_mover_pos]) == step_actor\n    requires forall i :: right_mover_pos < i < |lb.trace| ==> clrr.idmap(lb.trace[i]) != step_actor\n    requires clrr.phase1(lb.states[right_mover_pos+1], step_actor)\n\n    ensures  BehaviorRefinesBehavior(lb.states, hb.states, clrr.relation)\n    ensures  AnnotatedBehaviorSatisfiesSpec(hb, clrr.spec)\n    ensures  last(hb.states) == last(lb.states)\n    ensures  |hb.states| == |lb.states|\n    ensures  forall i :: 0 <= i < |hb.trace| ==> !IsNonmoverPos(clrr, hb.states, hb.trace, i)\n    ensures  clrr.idmap(hb.trace[right_mover_pos+1]) == step_actor\n    ensures  clrr.phase1(hb.states[right_mover_pos+2], step_actor)\n    ensures  forall i :: right_mover_pos + 1 < i < |hb.trace| ==> clrr.idmap(hb.trace[i]) != step_actor\n  {\n    assert ActionTuple(lb.states[right_mover_pos], lb.states[right_mover_pos+1], lb.trace[right_mover_pos]) in clrr.spec.next;\n    var right_mover_pos_plus := right_mover_pos + 1;\n    assert ActionTuple(lb.states[right_mover_pos_plus], lb.states[right_mover_pos_plus+1], lb.trace[right_mover_pos_plus]) in clrr.spec.next;\n    lemma_StateInAnnotatedBehaviorInAnnotatedReachables(clrr.spec, lb, right_mover_pos);\n    lemma_EarlierStateInBehaviorAlsoNotCrashed(clrr, lb, |lb.states|-1, right_mover_pos_plus+1);\n    assert RightMoversCommuteConditions(clrr, lb.states[right_mover_pos], lb.states[right_mover_pos+1],\n                                        lb.states[right_mover_pos_plus+1], lb.trace[right_mover_pos],\n                                        lb.trace[right_mover_pos+1]);\n    var new_middle_state, other_step', right_mover' :|\n      && ActionTuple(lb.states[right_mover_pos], new_middle_state, other_step') in clrr.spec.next\n      && ActionTuple(new_middle_state, lb.states[right_mover_pos_plus+1], right_mover') in clrr.spec.next\n      && clrr.idmap(other_step') == clrr.idmap(lb.trace[right_mover_pos+1])\n      && clrr.idmap(right_mover') == clrr.idmap(lb.trace[right_mover_pos]);\n\n    var hstates := lb.states[..right_mover_pos+1] + [new_middle_state] + lb.states[right_mover_pos+2..];\n    var htrace := lb.trace[..right_mover_pos] + [other_step', right_mover'] + lb.trace[right_mover_pos+2..];\n    hb := AnnotatedBehavior(hstates, htrace);\n\n    lemma_EstablishBehaviorRefinesBehaviorAfterMovingRightMoverRight(\n      clrr, lb, step_actor, right_mover_pos, new_middle_state, other_step', right_mover', hb);\n    lemma_EstablishBehaviorSatisfiesSpecAfterMovingRightMoverRight(\n      clrr, lb, step_actor, right_mover_pos, new_middle_state, other_step', right_mover', hb);\n    lemma_EstablishStillNoNonmoversAfterMovingRightMoverRight(\n      clrr, lb, step_actor, right_mover_pos, new_middle_state, other_step', right_mover', hb);\n  }\n\n  lemma lemma_MoveRightMoverToEnd<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    lb:AnnotatedBehavior<State, Step>,\n    step_actor:Actor,\n    right_mover_pos:int\n    ) returns (\n    hb:AnnotatedBehavior<State, Step>\n    )\n    requires ValidCohenLamportReductionRequest(clrr)\n    requires AnnotatedBehaviorSatisfiesSpec(lb, clrr.spec)\n    requires forall i :: 0 <= i < |lb.trace| ==> !IsNonmoverPos(clrr, lb.states, lb.trace, i)\n    requires !clrr.crashed(last(lb.states))\n    requires 0 <= right_mover_pos < |lb.trace|\n    requires clrr.idmap(lb.trace[right_mover_pos]) == step_actor\n    requires forall i :: right_mover_pos < i < |lb.trace| ==> clrr.idmap(lb.trace[i]) != step_actor\n    requires clrr.phase1(lb.states[right_mover_pos+1], step_actor)\n\n    ensures  BehaviorRefinesBehavior(lb.states, hb.states, clrr.relation)\n    ensures  AnnotatedBehaviorSatisfiesSpec(hb, clrr.spec)\n    ensures  last(hb.states) == last(lb.states)\n    ensures  |hb.states| == |lb.states|\n    ensures  forall i :: 0 <= i < |hb.trace| ==> !IsNonmoverPos(clrr, hb.states, hb.trace, i)\n    ensures  clrr.idmap(last(hb.trace)) == step_actor\n\n    decreases |lb.trace| - right_mover_pos\n  {\n    if right_mover_pos == |lb.trace|-1 {\n      hb := lb;\n      lemma_IfRefinementRelationReflexiveThenBehaviorRefinesItself(lb.states, clrr.relation);\n      return;\n    }\n\n    var mb := lemma_MoveRightMoverRight(clrr, lb, step_actor, right_mover_pos);\n    hb := lemma_MoveRightMoverToEnd(clrr, mb, step_actor, right_mover_pos+1);\n    lemma_RefinementConvolutionTransitive(lb.states, mb.states, hb.states, clrr.relation);\n  }\n\n  lemma lemma_BringRightMoversToEnd<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    lb:AnnotatedBehavior<State, Step>,\n    step_actor:Actor\n    ) returns (\n    hb:AnnotatedBehavior<State, Step>,\n    start_pos:int\n    )\n    requires ValidCohenLamportReductionRequest(clrr)\n    requires AnnotatedBehaviorSatisfiesSpec(lb, clrr.spec)\n    requires forall i :: 0 <= i < |lb.trace| ==> !IsNonmoverPos(clrr, lb.states, lb.trace, i)\n    requires !clrr.crashed(last(lb.states))\n    requires !clrr.phase2(last(lb.states), step_actor)\n    ensures  BehaviorRefinesBehavior(lb.states, hb.states, clrr.relation)\n    ensures  AnnotatedBehaviorSatisfiesSpec(hb, clrr.spec)\n    ensures  last(hb.states) == last(lb.states)\n    ensures  |hb.states| == |lb.states|\n    ensures  forall i :: 0 <= i < |hb.trace| ==> !IsNonmoverPos(clrr, hb.states, hb.trace, i)\n    ensures  0 <= start_pos < |hb.states|\n    ensures  !clrr.crashed(hb.states[start_pos])\n    ensures  !clrr.phase1(hb.states[start_pos], step_actor)\n    ensures  !clrr.phase2(hb.states[start_pos], step_actor)\n    ensures  forall i :: start_pos <= i < |hb.trace| ==> clrr.idmap(hb.trace[i]) == step_actor\n    ensures  forall i :: start_pos < i < |hb.states| ==> clrr.phase1(hb.states[i], step_actor)\n    decreases |lb.states|\n  {\n    if !clrr.phase1(last(lb.states), step_actor) {\n      start_pos := |lb.states| - 1;\n      hb := lb;\n      lemma_IfRefinementRelationReflexiveThenBehaviorRefinesItself(lb.states, clrr.relation);\n      return;\n    }\n\n    var right_mover_pos := lemma_FindLastRightMover(clrr, lb, step_actor);\n    var mb := lemma_MoveRightMoverToEnd(clrr, lb, step_actor, right_mover_pos);\n\n    assert BehaviorRefinesBehavior(lb.states, mb.states, clrr.relation);\n\n    var mb_trunc := AnnotatedBehavior(all_but_last(mb.states), all_but_last(mb.trace));\n    lemma_ReduceStateNextSeqRight(mb.states, mb.trace, clrr.spec.next);\n\n    forall i | 0 <= i < |mb_trunc.states|-1\n      ensures !IsNonmoverPos(clrr, mb_trunc.states, mb_trunc.trace, i)\n    {\n      assert !IsNonmoverPos(clrr, mb.states, mb.trace, i);\n    }\n\n    forall ensures !clrr.crashed(last(mb_trunc.states))\n    {\n      var penult := |mb.states|-2;\n      assert ActionTuple(mb.states[penult], mb.states[penult+1], mb.trace[penult]) in clrr.spec.next;\n    }\n\n    var mb2;\n    mb2, start_pos := lemma_BringRightMoversToEnd(clrr, mb_trunc, step_actor);\n    assert BehaviorRefinesBehavior(mb_trunc.states, mb2.states, clrr.relation);\n\n    hb := AnnotatedBehavior(mb2.states + [last(mb.states)], mb2.trace + [last(mb.trace)]);\n    lemma_ExtendBehaviorRefinesBehaviorRightOne(mb_trunc.states, mb2.states, clrr.relation, last(mb.states));\n    lemma_AllButLastPlusLastIsSeq(mb.states);\n\n    lemma_RefinementConvolutionTransitive(lb.states, mb.states, hb.states, clrr.relation);\n    lemma_ExtendStateNextSeqRight(mb2.states, mb2.trace, clrr.spec.next, last(mb.states), last(mb.trace));\n\n    forall i | 0 <= i < |hb.trace|\n      ensures !IsNonmoverPos(clrr, hb.states, hb.trace, i);\n    {\n      if i < |mb2.states|-1 {\n        assert !IsNonmoverPos(clrr, mb2.states, mb2.trace, i);\n      }\n      else {\n        assert i == |mb2.states|-1 == |mb.states|-2;\n        assert hb.states[i] == last(mb2.states) == last(mb_trunc.states) == mb.states[|mb.states|-2];\n        assert hb.states[i+1] == last(mb.states);\n        assert !IsNonmoverPos(clrr, mb.states, mb.trace, i);\n      }\n    }\n  }\n\n  lemma lemma_FindLastRightMover<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    b:AnnotatedBehavior<State, Step>,\n    step_actor:Actor\n    ) returns (\n    pos:int\n    )\n    requires ValidCohenLamportReductionRequest(clrr)\n    requires AnnotatedBehaviorSatisfiesSpec(b, clrr.spec)\n    requires !clrr.crashed(last(b.states))\n    requires clrr.phase1(last(b.states), step_actor)\n    requires !clrr.phase2(last(b.states), step_actor)\n    ensures  0 <= pos < |b.trace|\n    ensures  clrr.idmap(b.trace[pos]) == step_actor\n    ensures  forall i :: pos < i < |b.trace| ==> clrr.idmap(b.trace[i]) != step_actor\n    ensures  clrr.phase1(b.states[pos+1], step_actor)\n  {\n    pos := |b.trace|;\n    while pos > 0 && clrr.idmap(b.trace[pos-1]) != step_actor\n      invariant 0 <= pos <= |b.trace|\n      invariant clrr.phase1(b.states[pos], step_actor)\n      invariant forall i :: pos <= i < |b.trace| ==> clrr.idmap(b.trace[i]) != step_actor\n      invariant forall i :: pos <= i < |b.states| ==> clrr.phase1(b.states[i], step_actor)\n      decreases pos\n    {\n      var prev := pos-1;\n      assert ActionTuple(b.states[prev], b.states[prev+1], b.trace[prev]) in clrr.spec.next;\n      pos := pos - 1;\n    }\n\n    assert pos != 0;\n    pos := pos - 1;\n  }\n\n  lemma lemma_StateNextSeqCausesPhaseMatch<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    states:seq<State>,\n    trace:seq<Step>,\n    step_actor:Actor,\n    other_actor:Actor\n    )\n    requires ValidCohenLamportReductionRequest(clrr)\n    requires StateNextSeq(states, trace, clrr.spec.next)\n    requires forall step :: step in trace ==> clrr.idmap(step) == step_actor\n    requires step_actor != other_actor\n    ensures  clrr.phase1(states[0], other_actor) <==> clrr.phase1(last(states), other_actor)\n    ensures  clrr.phase2(states[0], other_actor) <==> clrr.phase2(last(states), other_actor)\n  {\n    if |trace| > 0 {\n      var zero := 0;\n      assert ActionTuple(states[zero], states[zero+1], trace[zero]) in clrr.spec.next;\n      lemma_ReduceStateNextSeqLeft(states, trace, clrr.spec.next);\n      lemma_StateNextSeqCausesPhaseMatch(clrr, states[1..], trace[1..], step_actor, other_actor);\n    }\n  }\n\n  lemma lemma_ShowBehaviorRefinementAfterLifting<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    lb:AnnotatedBehavior<State, Step>,\n    start_pos:int,\n    nonmover_pos:int,\n    end_pos:int,\n    step_actor:Actor,\n    hstep:Step,\n    hb:AnnotatedBehavior<State, Step>\n    )\n    requires ValidCohenLamportReductionRequest(clrr)\n    requires AnnotatedBehaviorSatisfiesSpec(lb, clrr.spec)\n    requires 0 <= start_pos <= nonmover_pos < end_pos < |lb.states|\n    requires forall i :: start_pos <= i < end_pos ==> clrr.idmap(lb.trace[i]) == step_actor\n    requires forall i :: start_pos < i <= nonmover_pos ==> clrr.phase1(lb.states[i], step_actor)\n    requires forall i :: nonmover_pos < i < end_pos ==> clrr.phase2(lb.states[i], step_actor)\n    requires ActionTuple(lb.states[start_pos], lb.states[end_pos], hstep) in clrr.spec.next\n    requires hb.states == lb.states[..start_pos+1] + lb.states[end_pos..]\n    requires hb.trace == lb.trace[..start_pos] + [hstep] + lb.trace[end_pos..]\n    ensures  BehaviorRefinesBehavior(lb.states, hb.states, clrr.relation)\n  {\n    var pos := start_pos;\n    while pos < nonmover_pos\n      invariant start_pos <= pos <= nonmover_pos\n      invariant forall i :: start_pos <= i <= pos ==> RefinementPair(lb.states[i], lb.states[start_pos]) in clrr.relation\n    {\n      assert RefinementPair(lb.states[pos], lb.states[start_pos]) in clrr.relation;\n      assert ActionTuple(lb.states[pos], lb.states[pos+1], lb.trace[pos]) in clrr.spec.next;\n      assert clrr.phase1(lb.states[pos+1], step_actor);\n      var pos_plus := pos+1;\n      assert ActionTuple(lb.states[pos_plus], lb.states[pos_plus+1], lb.trace[pos_plus]) in clrr.spec.next;\n      assert !clrr.crashed(lb.states[pos+1]);\n      assert RefinementPair(lb.states[pos+1], lb.states[pos]) in clrr.relation;\n      assert RefinementPair(lb.states[pos+1], lb.states[start_pos]) in clrr.relation;\n      pos := pos + 1;\n    }\n\n    pos := end_pos;\n    while pos > nonmover_pos + 1\n      invariant nonmover_pos < pos <= end_pos\n      invariant forall i :: pos <= i <= end_pos ==> RefinementPair(lb.states[i], lb.states[end_pos]) in clrr.relation\n    {\n      assert RefinementPair(lb.states[pos], lb.states[end_pos]) in clrr.relation;\n      var prev := pos-1;\n      assert ActionTuple(lb.states[prev], lb.states[prev+1], lb.trace[prev]) in clrr.spec.next;\n      assert clrr.phase2(lb.states[prev], step_actor);\n      assert RefinementPair(lb.states[prev], lb.states[prev+1]) in clrr.relation;\n      assert RefinementPair(lb.states[prev], lb.states[end_pos]) in clrr.relation;\n      pos := prev;\n    }\n\n    var lb2 := lb.states[start_pos..end_pos+1];\n    var hb2 := hb.states[start_pos..start_pos+2];\n    assert hb2[0] == lb.states[start_pos];\n    assert hb2[1] == lb.states[end_pos];\n    var lh_map1 := RepeatingValue(RefinementRange(0, 0), nonmover_pos - start_pos + 1); \n    var lh_map2 := RepeatingValue(RefinementRange(1, 1), end_pos - nonmover_pos);\n    var lh_map := lh_map1 + lh_map2;\n\n    lemma_IndexIntoConcatenation(lh_map1, lh_map2, end_pos-start_pos);\n    forall i | 0 <= i < |lh_map| - 1\n      ensures lh_map[i+1].first == lh_map[i].last || lh_map[i+1].first == lh_map[i].last + 1\n    {\n      lemma_IndexIntoConcatenation(lh_map1, lh_map2, i);\n      lemma_IndexIntoConcatenation(lh_map1, lh_map2, i+1);\n    }\n\n    assert BehaviorRefinesBehaviorUsingRefinementMap(lb2, hb2, clrr.relation, lh_map);\n\n    lemma_ExtendBehaviorRefinesBehaviorLeft(lb2, hb2, clrr.relation, lb.states[..start_pos]);\n    assert hb.states[..start_pos] == lb.states[..start_pos];\n    lemma_ExtendBehaviorRefinesBehaviorRight(lb.states[..start_pos] + lb2, hb.states[..start_pos] + hb2, clrr.relation,\n                                             lb.states[end_pos+1..]);\n    assert hb.states[start_pos+2..] == lb.states[end_pos+1..];\n    lemma_SeqEqualsThreeWayConcatentation(lb.states, start_pos, end_pos+1);\n    lemma_SeqEqualsThreeWayConcatentation(hb.states, start_pos, start_pos+2);\n  }\n\n  lemma lemma_ShowBehaviorSatisfiesSpecAfterLifting<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    lb:AnnotatedBehavior<State, Step>,\n    start_pos:int,\n    nonmover_pos:int,\n    end_pos:int,\n    step_actor:Actor,\n    hstep:Step,\n    hb:AnnotatedBehavior<State, Step>\n    )\n    requires ValidCohenLamportReductionRequest(clrr)\n    requires AnnotatedBehaviorSatisfiesSpec(lb, clrr.spec)\n    requires 0 <= start_pos <= nonmover_pos < end_pos < |lb.states|\n    requires forall i :: start_pos <= i < end_pos ==> clrr.idmap(lb.trace[i]) == step_actor\n    requires forall i :: start_pos < i <= nonmover_pos ==> clrr.phase1(lb.states[i], step_actor)\n    requires forall i :: nonmover_pos < i < end_pos ==> clrr.phase2(lb.states[i], step_actor)\n    requires ActionTuple(lb.states[start_pos], lb.states[end_pos], hstep) in clrr.spec.next\n    requires hb.states == lb.states[..start_pos+1] + lb.states[end_pos..]\n    requires hb.trace == lb.trace[..start_pos] + [hstep] + lb.trace[end_pos..]\n    ensures  AnnotatedBehaviorSatisfiesSpec(hb, clrr.spec)\n  {\n    assert hb.states[0] == lb.states[0];\n\n    forall i | 0 <= i < |hb.trace|\n      ensures ActionTuple(hb.states[i], hb.states[i+1], hb.trace[i]) in clrr.spec.next\n    {\n      if i < start_pos {\n        assert hb.states[i] == lb.states[i];\n        assert hb.states[i+1] == lb.states[i+1];\n        assert hb.trace[i] == lb.trace[i];\n        assert ActionTuple(lb.states[i], lb.states[i+1], lb.trace[i]) in clrr.spec.next;\n      }\n      else if i == start_pos {\n        assert hb.states[i] == lb.states[start_pos];\n        assert hb.states[i+1] == lb.states[end_pos];\n        assert hb.trace[i] == hstep;\n        assert ActionTuple(lb.states[start_pos], lb.states[end_pos], hstep) in clrr.spec.next;\n      }\n      else {\n        var iadj := i + (end_pos - start_pos - 1);\n        assert hb.states[i] == lb.states[iadj];\n        assert hb.states[i+1] == lb.states[iadj+1];\n        assert hb.trace[i] == lb.trace[iadj];\n        assert ActionTuple(lb.states[iadj], lb.states[iadj+1], lb.trace[iadj]) in clrr.spec.next;\n      }\n    }\n  }\n\n  lemma lemma_LiftActionSequence<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    states:seq<State>,\n    trace:seq<Step>,\n    actor:Actor\n    ) returns (\n    hstep:Step\n    )\n    requires ActionSequencesLiftable(clrr)\n    requires ActionSequencesLiftableConditions(clrr, states, trace, actor)\n    ensures  ActionTuple(states[0], last(states), hstep) in clrr.spec.next\n    ensures  clrr.idmap(hstep) == actor\n  {\n    hstep :| ActionTuple(states[0], last(states), hstep) in clrr.spec.next && clrr.idmap(hstep) == actor;\n  }\n\n  lemma lemma_RemoveNonmoverAtPos<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    lb:AnnotatedBehavior<State, Step>,\n    nonmover_pos:int,\n    step_actor:Actor\n    ) returns (\n    hb:AnnotatedBehavior<State, Step>,\n    pos_past_nonmovers:int\n    )\n    requires ValidCohenLamportReductionRequest(clrr)\n    requires AnnotatedBehaviorSatisfiesSpec(lb, clrr.spec)\n    requires 0 <= nonmover_pos < |lb.trace|\n    requires forall i :: 0 <= i < nonmover_pos ==> !IsNonmoverPos(clrr, lb.states, lb.trace, i)\n    requires clrr.idmap(lb.trace[nonmover_pos]) == step_actor\n    requires IsNonmoverPos(clrr, lb.states, lb.trace, nonmover_pos)\n    ensures  BehaviorRefinesBehavior(lb.states, hb.states, clrr.relation)\n    ensures  AnnotatedBehaviorSatisfiesSpec(hb, clrr.spec)\n    ensures  |hb.states| - pos_past_nonmovers < |lb.states| - nonmover_pos\n    ensures  0 <= pos_past_nonmovers < |hb.states|\n    ensures  forall i :: 0 <= i < pos_past_nonmovers ==> !IsNonmoverPos(clrr, hb.states, hb.trace, i)\n  {\n    var mb, start_pos, end_pos := lemma_BringMoversCloseToNonmoverAtPos(clrr, lb, nonmover_pos, step_actor);\n\n    var states := mb.states[start_pos..end_pos+1];\n    var trace := mb.trace[start_pos..end_pos];\n\n    forall i | 0 <= i < |trace|\n      ensures ActionTuple(states[i], states[i+1], trace[i]) in clrr.spec.next\n      ensures !clrr.crashed(states[i])\n    {\n      var pos := start_pos+i;\n      assert ActionTuple(mb.states[pos], mb.states[pos+1], mb.trace[pos]) in clrr.spec.next;\n    }\n    \n    assert ActionSequencesLiftableConditions(clrr, states, trace, step_actor);\n    var hstep := lemma_LiftActionSequence(clrr, states, trace, step_actor);\n\n    var hstates := mb.states[..start_pos+1] + mb.states[end_pos..];\n    var htrace := mb.trace[..start_pos] + [hstep] + mb.trace[end_pos..];\n    hb := AnnotatedBehavior(hstates, htrace);\n    pos_past_nonmovers := start_pos + 1;\n\n    lemma_ShowBehaviorRefinementAfterLifting(clrr, mb, start_pos, nonmover_pos, end_pos, step_actor, hstep, hb);\n    lemma_ShowBehaviorSatisfiesSpecAfterLifting(clrr, mb, start_pos, nonmover_pos, end_pos, step_actor, hstep, hb);\n    lemma_RefinementConvolutionTransitive(lb.states, mb.states, hb.states, clrr.relation);\n\n    forall i | 0 <= i < pos_past_nonmovers\n      ensures !IsNonmoverPos(clrr, hb.states, hb.trace, i)\n    {\n      if i < start_pos {\n        assert hb.states[i] == mb.states[i];\n        assert hb.states[i+1] == mb.states[i+1];\n        assert !IsNonmoverPos(clrr, mb.states, mb.trace, i);\n      }\n      else {\n        assert hb.states[i] == mb.states[start_pos] == states[0];\n        assert hb.states[i+1] == mb.states[end_pos] == last(states);\n        assert ActionTuple(states[0], last(states), hstep) in clrr.spec.next;\n        assert !IsNonmoverStep(clrr, states[0], last(states), step_actor);\n      }\n    }\n  }\n\n  lemma lemma_BringMoversCloseToNonmoverAtPos<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    lb:AnnotatedBehavior<State, Step>,\n    nonmover_pos:int,\n    step_actor:Actor\n    ) returns (\n    hb:AnnotatedBehavior<State, Step>,\n    start_pos:int,\n    end_pos:int\n    )\n    requires ValidCohenLamportReductionRequest(clrr)\n    requires AnnotatedBehaviorSatisfiesSpec(lb, clrr.spec)\n    requires 0 <= nonmover_pos < |lb.trace|\n    requires forall i :: 0 <= i < nonmover_pos ==> !IsNonmoverPos(clrr, lb.states, lb.trace, i)\n    requires clrr.idmap(lb.trace[nonmover_pos]) == step_actor\n    requires IsNonmoverPos(clrr, lb.states, lb.trace, nonmover_pos)\n\n    ensures  BehaviorRefinesBehavior(lb.states, hb.states, clrr.relation)\n    ensures  AnnotatedBehaviorSatisfiesSpec(hb, clrr.spec)\n    ensures  |hb.states| < |lb.states| + (end_pos - nonmover_pos)\n    ensures  0 <= start_pos <= nonmover_pos < end_pos < |hb.states|\n    ensures  forall i :: 0 <= i < nonmover_pos ==> !IsNonmoverPos(clrr, hb.states, hb.trace, i)\n    ensures  !clrr.crashed(hb.states[start_pos])\n    ensures  !clrr.phase1(hb.states[start_pos], step_actor)\n    ensures  !clrr.phase2(hb.states[start_pos], step_actor)\n    ensures  hb.states[nonmover_pos] == lb.states[nonmover_pos]\n    ensures  hb.states[nonmover_pos+1] == lb.states[nonmover_pos+1]\n    ensures  var s := hb.states[end_pos]; !clrr.crashed(s) ==> !clrr.phase1(s, step_actor) && !clrr.phase2(s, step_actor)\n    ensures  forall i :: start_pos <= i < end_pos ==> clrr.idmap(hb.trace[i]) == step_actor\n    ensures  forall i :: start_pos < i <= nonmover_pos ==> clrr.phase1(hb.states[i], step_actor)\n    ensures  forall i :: nonmover_pos < i < end_pos ==> clrr.phase2(hb.states[i], step_actor)\n  {\n    lemma_TakeStateNextSeq(lb.states, lb.trace, clrr.spec.next, nonmover_pos);\n    var pre_nonmover_behavior := AnnotatedBehavior(lb.states[..nonmover_pos+1], lb.trace[..nonmover_pos]);\n\n    forall i | 0 <= i < |pre_nonmover_behavior.states|-1\n      ensures !IsNonmoverPos(clrr, pre_nonmover_behavior.states, pre_nonmover_behavior.trace, i)\n    {\n      assert pre_nonmover_behavior.states[i] == lb.states[i];\n      assert pre_nonmover_behavior.states[i+1] == lb.states[i+1];\n      assert pre_nonmover_behavior.trace[i] == lb.trace[i];\n      assert !IsNonmoverPos(clrr, lb.states, lb.trace, i);\n    }\n    assert ActionTuple(lb.states[nonmover_pos], lb.states[nonmover_pos+1], lb.trace[nonmover_pos]) in clrr.spec.next;\n\n    var pre_nonmover_behavior';\n    pre_nonmover_behavior', start_pos := lemma_BringRightMoversToEnd(clrr, pre_nonmover_behavior, step_actor);\n\n    lemma_DropStateNextSeq(lb.states, lb.trace, clrr.spec.next, nonmover_pos+1);\n    lemma_StateInAnnotatedBehaviorInAnnotatedReachables(clrr.spec, lb, nonmover_pos+1);\n    var post_nonmover_states', post_nonmover_trace', end_pos_relative :=\n      lemma_BringLeftMoversToStart(clrr, lb.states[nonmover_pos+1..], lb.trace[nonmover_pos+1..], step_actor);\n\n    var hstates' := pre_nonmover_behavior'.states + post_nonmover_states';\n    var htrace' := pre_nonmover_behavior'.trace + [lb.trace[nonmover_pos]] + post_nonmover_trace';\n    end_pos := nonmover_pos + 1 + end_pos_relative;\n    hb := AnnotatedBehavior(hstates', htrace');\n\n    lemma_ConcatenatingBehaviorsPreservesRefinement(lb.states[..nonmover_pos+1], lb.states[nonmover_pos+1..],\n                                                    pre_nonmover_behavior'.states, post_nonmover_states', clrr.relation);\n    lemma_TakePlusDropIsSeq(lb.states, nonmover_pos+1);\n\n    forall i | 0 <= i < |htrace'|\n      ensures ActionTuple(hstates'[i], hstates'[i+1], htrace'[i]) in clrr.spec.next\n    {\n      if i < |pre_nonmover_behavior'.trace| {\n        assert hstates'[i] == pre_nonmover_behavior'.states[i];\n        assert hstates'[i+1] == pre_nonmover_behavior'.states[i+1];\n        assert htrace'[i] == pre_nonmover_behavior'.trace[i];\n        assert ActionTuple(pre_nonmover_behavior'.states[i], pre_nonmover_behavior'.states[i+1], pre_nonmover_behavior'.trace[i])\n               in clrr.spec.next;\n      }\n      else if i == |pre_nonmover_behavior'.trace| {\n        assert hstates'[i] == last(pre_nonmover_behavior'.states) == lb.states[nonmover_pos];\n        assert hstates'[i+1] == post_nonmover_states'[0] == lb.states[nonmover_pos+1];\n        assert htrace'[i] == lb.trace[nonmover_pos];\n        assert ActionTuple(lb.states[nonmover_pos], lb.states[nonmover_pos+1], lb.trace[nonmover_pos]) in clrr.spec.next;\n      }\n      else {\n        var j := i - |pre_nonmover_behavior'.states|;\n        assert hstates'[i] == post_nonmover_states'[j];\n        assert hstates'[i+1] == post_nonmover_states'[j+1];\n        assert htrace'[i] == post_nonmover_trace'[j];\n        assert ActionTuple(post_nonmover_states'[j], post_nonmover_states'[j+1], post_nonmover_trace'[j]) in clrr.spec.next;\n      }\n    }\n\n    forall i | 0 <= i < nonmover_pos\n      ensures !IsNonmoverPos(clrr, hb.states, hb.trace, i);\n    {\n      assert hb.states[i] == pre_nonmover_behavior'.states[i];\n      assert hb.states[i+1] == pre_nonmover_behavior'.states[i+1];\n      assert hb.trace[i] == pre_nonmover_behavior'.trace[i];\n      assert !IsNonmoverPos(clrr, pre_nonmover_behavior'.states, pre_nonmover_behavior'.trace, i);\n    }\n  }\n\n  lemma lemma_RemoveAnyNonmoverAtPos<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    lb:AnnotatedBehavior<State, Step>,\n    nonmover_pos:int\n    ) returns (\n    hb:AnnotatedBehavior<State, Step>,\n    pos_past_nonmovers:int\n    )\n    requires ValidCohenLamportReductionRequest(clrr)\n    requires AnnotatedBehaviorSatisfiesSpec(lb, clrr.spec)\n    requires 0 <= nonmover_pos < |lb.trace|\n    requires forall i :: 0 <= i < nonmover_pos ==> !IsNonmoverPos(clrr, lb.states, lb.trace, i)\n    ensures  BehaviorRefinesBehavior(lb.states, hb.states, clrr.relation)\n    ensures  AnnotatedBehaviorSatisfiesSpec(hb, clrr.spec)\n    ensures  |hb.states| - pos_past_nonmovers < |lb.states| - nonmover_pos\n    ensures  0 <= pos_past_nonmovers < |hb.states|\n    ensures  forall i :: 0 <= i < pos_past_nonmovers ==> !IsNonmoverPos(clrr, hb.states, hb.trace, i)\n  {\n    assert ActionTuple(lb.states[nonmover_pos], lb.states[nonmover_pos+1], lb.trace[nonmover_pos]) in clrr.spec.next;\n    var step_actor := clrr.idmap(lb.trace[nonmover_pos]);\n\n    if !IsNonmoverPos(clrr, lb.states, lb.trace, nonmover_pos) {\n      hb := lb;\n      lemma_IfRefinementRelationReflexiveThenBehaviorRefinesItself(lb.states, clrr.relation);\n      pos_past_nonmovers := nonmover_pos + 1;\n      return;\n    }\n\n    hb, pos_past_nonmovers := lemma_RemoveNonmoverAtPos(clrr, lb, nonmover_pos, step_actor);\n  }\n\n  lemma lemma_RemoveAllNonmoversFromPos<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    lb:AnnotatedBehavior<State, Step>,\n    nonmover_pos:int\n    ) returns (\n    hb:AnnotatedBehavior<State, Step>\n    )\n    requires ValidCohenLamportReductionRequest(clrr)\n    requires AnnotatedBehaviorSatisfiesSpec(lb, clrr.spec)\n    requires 0 <= nonmover_pos < |lb.states|\n    requires forall i :: 0 <= i < nonmover_pos ==> !IsNonmoverPos(clrr, lb.states, lb.trace, i)\n    ensures  BehaviorRefinesBehavior(lb.states, hb.states, clrr.relation)\n    ensures  AnnotatedBehaviorSatisfiesSpec(hb, clrr.spec)\n    ensures  forall i :: 0 <= i < |hb.trace| ==> !IsNonmoverPos(clrr, hb.states, hb.trace, i)\n    decreases |lb.states| - nonmover_pos\n  {\n    if nonmover_pos == |lb.trace| {\n      hb := lb;\n      lemma_IfRefinementRelationReflexiveThenBehaviorRefinesItself(lb.states, clrr.relation);\n    }\n    else {\n      var mb, pos_past_nonmovers := lemma_RemoveAnyNonmoverAtPos(clrr, lb, nonmover_pos);\n      hb := lemma_RemoveAllNonmoversFromPos(clrr, mb, pos_past_nonmovers);\n      lemma_RefinementConvolutionTransitive(lb.states, mb.states, hb.states, clrr.relation);\n    }\n  }\n\n  predicate IsNonmoverStep<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    s:State,\n    s':State,\n    actor:Actor\n    )\n  {\n    || (!clrr.phase1(s, actor) && !clrr.phase2(s, actor) && clrr.phase2(s', actor) && !clrr.crashed(s'))\n    || (clrr.phase1(s, actor) && !clrr.phase1(s', actor))\n    || (clrr.phase1(s, actor) && clrr.crashed(s'))\n  }\n\n  predicate IsNonmoverPos<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    states:seq<State>,\n    trace:seq<Step>,\n    pos:int\n    )\n    requires 0 <= pos < |trace| < |states|\n  {\n    IsNonmoverStep(clrr, states[pos], states[pos+1], clrr.idmap(trace[pos]))\n  }\n\n  lemma lemma_RemoveAllNonmovers<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    lb:AnnotatedBehavior<State, Step>\n    ) returns (\n    hb:AnnotatedBehavior<State, Step>\n    )\n    requires ValidCohenLamportReductionRequest(clrr)\n    requires AnnotatedBehaviorSatisfiesSpec(lb, clrr.spec)\n    ensures  BehaviorRefinesBehavior(lb.states, hb.states, clrr.relation)\n    ensures  AnnotatedBehaviorSatisfiesSpec(hb, clrr.spec)\n    ensures  forall i :: 0 <= i < |hb.trace| ==> !IsNonmoverPos(clrr, hb.states, hb.trace, i)\n  {\n    hb := lemma_RemoveAllNonmoversFromPos(clrr, lb, 0);\n  }\n\n  lemma lemma_RemoveRightMoverFromPosCaseBeforeCrash<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    lstates:seq<State>,\n    ltrace:seq<Step>,\n    step_actor:Actor,\n    right_mover_pos:int\n    ) returns (\n    hstates:seq<State>,\n    htrace:seq<Step>\n    )\n    requires ValidCohenLamportReductionRequest(clrr)\n    requires StateNextSeq(lstates, ltrace, clrr.spec.next)\n    requires lstates[0] in AnnotatedReachables(clrr.spec)\n    requires 0 <= right_mover_pos < |ltrace|-1\n    requires !clrr.crashed(lstates[right_mover_pos+1])\n    requires clrr.phase1(lstates[right_mover_pos+1], step_actor)\n    requires clrr.idmap(ltrace[right_mover_pos]) == step_actor\n    requires clrr.crashed(lstates[right_mover_pos+2])\n    requires forall i :: 0 <= i < |ltrace| ==> !IsNonmoverPos(clrr, lstates, ltrace, i)\n    requires forall i :: 0 <= i < right_mover_pos ==>\n               var actor := clrr.idmap(ltrace[i]);\n               var s := lstates[i+1];\n               !clrr.crashed(s) ==> !clrr.phase1(s, actor) && !clrr.phase2(s, actor)\n    requires forall i :: right_mover_pos < i < |ltrace| ==>\n               var actor := clrr.idmap(ltrace[i]);\n               var s := lstates[i+1];\n               !clrr.crashed(s) ==> !clrr.phase1(s, actor) && !clrr.phase2(s, actor)\n    ensures  BehaviorRefinesBehavior(lstates, hstates, clrr.relation)\n    ensures  StateNextSeq(hstates, htrace, clrr.spec.next)\n    ensures  hstates[0] == lstates[0]\n    ensures  |htrace| <= |ltrace|\n    ensures  forall i :: 0 <= i < |htrace| ==> !IsNonmoverPos(clrr, hstates, htrace, i)\n    ensures  forall i :: 0 <= i < |htrace| ==>\n               var actor := clrr.idmap(htrace[i]);\n               var s := hstates[i+1];\n               !clrr.crashed(s) ==> !clrr.phase1(s, actor) && !clrr.phase2(s, actor)\n  {\n    assert ActionTuple(lstates[right_mover_pos], lstates[right_mover_pos+1], ltrace[right_mover_pos]) in clrr.spec.next;\n    var pos_plus := right_mover_pos + 1;\n    assert ActionTuple(lstates[pos_plus], lstates[pos_plus+1], ltrace[pos_plus]) in clrr.spec.next;\n    if |ltrace| != right_mover_pos + 2 {\n      var pos_plus_2 := right_mover_pos + 2;\n      assert ActionTuple(lstates[pos_plus_2], lstates[pos_plus_2+1], ltrace[pos_plus_2]) in clrr.spec.next;\n      assert false;\n    }\n    lemma_StateNextSeqMaintainsAnnotatedReachables(lstates, ltrace, clrr.spec);\n    assert lstates[right_mover_pos] in lstates;\n    assert !IsNonmoverPos(clrr, lstates, ltrace, right_mover_pos+1);\n    assert RightMoverCrashPreservationConditions(clrr, lstates[right_mover_pos], lstates[right_mover_pos+1], lstates[right_mover_pos+2],\n                                                 ltrace[right_mover_pos], ltrace[right_mover_pos+1]);\n    var other_step', state_after_other_step' :|\n          && clrr.idmap(other_step') == clrr.idmap(ltrace[right_mover_pos+1])\n          && ActionTuple(lstates[right_mover_pos], state_after_other_step', other_step') in clrr.spec.next\n          && clrr.crashed(state_after_other_step')\n          && RefinementPair(lstates[right_mover_pos+2], state_after_other_step') in clrr.relation;\n\n    hstates := lstates[..right_mover_pos+1] + [state_after_other_step'];\n    htrace := ltrace[..right_mover_pos] + [other_step'];\n    assert StateNextSeq(hstates, htrace, clrr.spec.next);\n\n    var lh_map := ConvertMapToSeq(\n                    |lstates|,\n                    map i | 0 <= i < |lstates| ::\n                      if i <= right_mover_pos then RefinementRange(i, i)\n                      else if i == right_mover_pos+1 then RefinementRange(right_mover_pos, right_mover_pos)\n                      else RefinementRange(right_mover_pos+1, right_mover_pos+1));\n\n    forall i, j {:trigger RefinementPair(lstates[i], hstates[j]) in clrr.relation}\n      | 0 <= i < |lstates| && lh_map[i].first <= j <= lh_map[i].last\n      ensures RefinementPair(lstates[i], hstates[j]) in clrr.relation\n    {\n      if i <= right_mover_pos {\n        assert j == i;\n        assert hstates[j] == lstates[i];\n        assert RefinementPair(lstates[i], lstates[i]) in clrr.relation;\n      }\n      else if i == right_mover_pos+1 {\n        assert j == right_mover_pos;\n        assert hstates[j] == lstates[right_mover_pos];\n        assert ActionTuple(lstates[right_mover_pos], lstates[right_mover_pos+1], ltrace[right_mover_pos]) in clrr.spec.next;\n        assert !clrr.crashed(lstates[right_mover_pos+1]);\n        assert clrr.idmap(ltrace[right_mover_pos]) == step_actor;\n        assert clrr.phase1(lstates[right_mover_pos+1], step_actor);\n        assert RefinementPair(lstates[right_mover_pos+1], lstates[right_mover_pos]) in clrr.relation;\n      }\n      else {\n        assert i == right_mover_pos+2;\n        assert j == right_mover_pos+1;\n        assert hstates[j] == state_after_other_step';\n        assert RefinementPair(lstates[right_mover_pos+2], state_after_other_step') in clrr.relation;\n      }\n    }\n    assert BehaviorRefinesBehaviorUsingRefinementMap(lstates, hstates, clrr.relation, lh_map);\n\n    forall i | 0 <= i < |htrace|\n      ensures !IsNonmoverPos(clrr, hstates, htrace, i)\n    {\n      if i < right_mover_pos {\n        assert !IsNonmoverPos(clrr, lstates, ltrace, i);\n      }\n      else {\n        assert hstates[i] == lstates[right_mover_pos];\n        assert hstates[i+1] == state_after_other_step';\n        assert htrace[i] == other_step';\n      }\n    }\n  }\n\n  lemma lemma_RemoveRightMoverFromPosCaseAtEnd<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    lstates:seq<State>,\n    ltrace:seq<Step>,\n    step_actor:Actor,\n    right_mover_pos:int\n    ) returns (\n    hstates:seq<State>,\n    htrace:seq<Step>\n    )\n    requires ValidCohenLamportReductionRequest(clrr)\n    requires StateNextSeq(lstates, ltrace, clrr.spec.next)\n    requires lstates[0] in AnnotatedReachables(clrr.spec)\n    requires |ltrace| > 0\n    requires right_mover_pos == |ltrace|-1;\n    requires !clrr.crashed(lstates[right_mover_pos+1])\n    requires clrr.phase1(lstates[right_mover_pos+1], step_actor)\n    requires clrr.idmap(ltrace[right_mover_pos]) == step_actor\n    requires forall i :: 0 <= i < |ltrace| ==> !IsNonmoverPos(clrr, lstates, ltrace, i)\n    requires forall i :: 0 <= i < right_mover_pos ==>\n               var actor := clrr.idmap(ltrace[i]);\n               var s := lstates[i+1];\n               !clrr.crashed(s) ==> !clrr.phase1(s, actor) && !clrr.phase2(s, actor)\n    requires forall i :: right_mover_pos < i < |ltrace| ==>\n               var actor := clrr.idmap(ltrace[i]);\n               var s := lstates[i+1];\n               !clrr.crashed(s) ==> !clrr.phase1(s, actor) && !clrr.phase2(s, actor)\n    ensures  BehaviorRefinesBehavior(lstates, hstates, clrr.relation)\n    ensures  StateNextSeq(hstates, htrace, clrr.spec.next)\n    ensures  hstates[0] == lstates[0]\n    ensures  |htrace| <= |ltrace|\n    ensures  forall i :: 0 <= i < |htrace| ==> !IsNonmoverPos(clrr, hstates, htrace, i)\n    ensures  forall i :: 0 <= i < |htrace| ==>\n               var actor := clrr.idmap(htrace[i]);\n               var s := hstates[i+1];\n               !clrr.crashed(s) ==> !clrr.phase1(s, actor) && !clrr.phase2(s, actor)\n  {\n    hstates := all_but_last(lstates);\n    htrace := all_but_last(ltrace);\n    lemma_ReduceStateNextSeqRight(lstates, ltrace, clrr.spec.next);\n\n    var lh_map := ConvertMapToSeq(|lstates|, map i | 0 <= i < |lstates| :: if i < |ltrace| then RefinementRange(i, i)\n                                                                                         else RefinementRange(|hstates|-1, |hstates|-1));\n    forall i, j {:trigger RefinementPair(lstates[i], hstates[j]) in clrr.relation}\n      | 0 <= i < |lstates| && lh_map[i].first <= j <= lh_map[i].last\n      ensures RefinementPair(lstates[i], hstates[j]) in clrr.relation\n    {\n      if i < |ltrace| {\n        assert j == i;\n        assert hstates[j] == lstates[i];\n        assert RefinementPair(lstates[i], lstates[i]) in clrr.relation;\n      }\n      else {\n        var ult := |ltrace|-1;\n        assert lstates[i] == lstates[ult+1];\n        assert j == |hstates|-1 == |ltrace|-1 == ult;\n        assert hstates[j] == lstates[ult];\n        assert ActionTuple(lstates[ult], lstates[ult+1], ltrace[ult]) in clrr.spec.next;\n        assert clrr.idmap(ltrace[ult]) == step_actor;\n        assert clrr.phase1(lstates[ult+1], step_actor);\n        assert RefinementPair(lstates[ult+1], lstates[ult]) in clrr.relation;\n      }\n    }\n\n    assert BehaviorRefinesBehaviorUsingRefinementMap(lstates, hstates, clrr.relation, lh_map);\n\n    forall i | 0 <= i < |htrace|\n      ensures !IsNonmoverPos(clrr, hstates, htrace, i)\n    {\n      assert !IsNonmoverPos(clrr, lstates, ltrace, i);\n    }\n  }\n\n  lemma lemma_EstablishBehaviorRefinesBehaviorAfterMovingRightMoverForRemoval<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    lstates:seq<State>,\n    ltrace:seq<Step>,\n    step_actor:Actor,\n    right_mover_pos:int,\n    new_middle_state:State,\n    other_step':Step,\n    right_mover':Step,\n    hstates:seq<State>,\n    htrace:seq<Step>\n    )\n    requires ValidCohenLamportReductionRequest(clrr)\n    requires StateNextSeq(lstates, ltrace, clrr.spec.next)\n    requires lstates[0] in AnnotatedReachables(clrr.spec)\n    requires 0 <= right_mover_pos < |ltrace|-1\n    requires !clrr.crashed(lstates[right_mover_pos+2])\n    requires clrr.phase1(lstates[right_mover_pos+1], step_actor)\n    requires clrr.idmap(ltrace[right_mover_pos]) == step_actor\n    requires clrr.idmap(ltrace[right_mover_pos+1]) != step_actor\n    requires ActionTuple(lstates[right_mover_pos], new_middle_state, other_step') in clrr.spec.next\n    requires ActionTuple(new_middle_state, lstates[right_mover_pos+2], right_mover') in clrr.spec.next\n    requires clrr.idmap(other_step') == clrr.idmap(ltrace[right_mover_pos+1])\n    requires clrr.idmap(right_mover') == clrr.idmap(ltrace[right_mover_pos])\n    requires hstates == lstates[..right_mover_pos+1] + [new_middle_state] + lstates[right_mover_pos+2..]\n    requires htrace == ltrace[..right_mover_pos] + [other_step', right_mover'] + ltrace[right_mover_pos+2..]\n    ensures  BehaviorRefinesBehavior(lstates, hstates, clrr.relation)\n    ensures  last(hstates) == last(lstates)\n    ensures  |hstates| == |lstates|\n    ensures  |htrace| == |ltrace|\n    ensures  clrr.idmap(htrace[right_mover_pos+1]) == step_actor\n  {\n    var lb2 := lstates[right_mover_pos..right_mover_pos+3];\n    var hb2 := [lstates[right_mover_pos], new_middle_state, lstates[right_mover_pos+2]];\n\n    var right_mover_pos_plus := right_mover_pos+1;\n    assert ActionTuple(lstates[right_mover_pos_plus], lstates[right_mover_pos_plus+1], ltrace[right_mover_pos_plus]) in clrr.spec.next;\n    assert !clrr.crashed(lstates[right_mover_pos_plus]);\n\n    forall ensures RefinementPair(lb2[2], hb2[1]) in clrr.relation\n    {\n      assert ActionTuple(new_middle_state, lstates[right_mover_pos+2], right_mover') in clrr.spec.next;\n      assert clrr.idmap(right_mover') == step_actor;\n      assert ActionTuple(lstates[right_mover_pos_plus], lstates[right_mover_pos_plus+1], ltrace[right_mover_pos_plus])\n               in clrr.spec.next;\n      assert clrr.idmap(ltrace[right_mover_pos_plus]) != step_actor;\n      assert clrr.phase1(lstates[right_mover_pos_plus+1], step_actor);\n      assert !clrr.crashed(lstates[right_mover_pos+2]);\n      assert RefinementPair(lstates[right_mover_pos+2], new_middle_state) in clrr.relation;\n    }\n\n    forall ensures RefinementPair(lb2[1], hb2[0]) in clrr.relation\n    {\n      assert ActionTuple(lstates[right_mover_pos], lstates[right_mover_pos+1], ltrace[right_mover_pos]) in clrr.spec.next;\n      assert clrr.idmap(ltrace[right_mover_pos]) == step_actor;\n      assert !clrr.crashed(lstates[right_mover_pos+1]);\n      assert RefinementPair(lstates[right_mover_pos+1], lstates[right_mover_pos]) in clrr.relation;\n    }\n\n    forall ensures RefinementPair(lb2[0], hb2[0]) in clrr.relation\n    {\n      assert hb2[0] == lb2[0];\n    }\n\n    forall ensures RefinementPair(lb2[2], hb2[2]) in clrr.relation\n    {\n      assert hb2[2] == lb2[2];\n    }\n\n    var lh_map := [RefinementRange(0, 0), RefinementRange(0, 0), RefinementRange(1, 2)];\n    assert BehaviorRefinesBehaviorUsingRefinementMap(lb2, hb2, clrr.relation, lh_map);\n\n    lemma_ExtendBehaviorRefinesBehaviorLeft(lb2, hb2, clrr.relation, lstates[..right_mover_pos]);\n    lemma_ExtendBehaviorRefinesBehaviorRight(lstates[..right_mover_pos] + lb2, lstates[..right_mover_pos] + hb2, clrr.relation,\n                                             lstates[right_mover_pos+3..]);\n    assert BehaviorRefinesBehavior(lstates[..right_mover_pos] + lb2 + lstates[right_mover_pos+3..],\n                                   lstates[..right_mover_pos] + hb2 + lstates[right_mover_pos+3..], clrr.relation);\n    lemma_SeqEqualsThreeWayConcatentation(lstates, right_mover_pos, right_mover_pos+3);\n\n    assert hstates == lstates[..right_mover_pos] + hb2 + lstates[right_mover_pos+3..];\n  }\n\n  lemma lemma_EstablishBehaviorSatisfiesSpecAfterMovingRightMoverForRemoval<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    lstates:seq<State>,\n    ltrace:seq<Step>,\n    step_actor:Actor,\n    right_mover_pos:int,\n    new_middle_state:State,\n    other_step':Step,\n    right_mover':Step,\n    hstates:seq<State>,\n    htrace:seq<Step>\n    )\n    requires ValidCohenLamportReductionRequest(clrr)\n    requires StateNextSeq(lstates, ltrace, clrr.spec.next)\n    requires lstates[0] in AnnotatedReachables(clrr.spec)\n    requires 0 <= right_mover_pos < |ltrace|-1\n    requires !clrr.crashed(lstates[right_mover_pos+2])\n    requires clrr.phase1(lstates[right_mover_pos+1], step_actor)\n    requires clrr.idmap(ltrace[right_mover_pos]) == step_actor\n    requires ActionTuple(lstates[right_mover_pos], new_middle_state, other_step') in clrr.spec.next\n    requires ActionTuple(new_middle_state, lstates[right_mover_pos+2], right_mover') in clrr.spec.next\n    requires clrr.idmap(other_step') == clrr.idmap(ltrace[right_mover_pos+1])\n    requires clrr.idmap(right_mover') == clrr.idmap(ltrace[right_mover_pos])\n    requires hstates == lstates[..right_mover_pos+1] + [new_middle_state] + lstates[right_mover_pos+2..]\n    requires htrace == ltrace[..right_mover_pos] + [other_step', right_mover'] + ltrace[right_mover_pos+2..]\n    ensures  StateNextSeq(hstates, htrace, clrr.spec.next)\n    ensures  hstates[0] == lstates[0]\n  {\n    forall i {:trigger ActionTuple(hstates[i], hstates[i+1], htrace[i]) in clrr.spec.next}\n      | 0 <= i < |htrace|\n      ensures ActionTuple(hstates[i], hstates[i+1], htrace[i]) in clrr.spec.next\n    {\n      if i == right_mover_pos {\n        assert hstates[i] == lstates[right_mover_pos];\n        assert hstates[i+1] == new_middle_state;\n        assert htrace[i] == other_step';\n        assert ActionTuple(lstates[right_mover_pos], new_middle_state, other_step') in clrr.spec.next;\n      }\n      else if i == right_mover_pos + 1 {\n        assert hstates[i] == new_middle_state;\n        assert hstates[i+1] == lstates[right_mover_pos+2];\n        assert htrace[i] == right_mover';\n        assert ActionTuple(new_middle_state, lstates[right_mover_pos+2], right_mover') in clrr.spec.next;\n      }\n      else {\n        assert hstates[i] == lstates[i];\n        assert hstates[i+1] == lstates[i+1];\n        assert htrace[i] == ltrace[i];\n        assert ActionTuple(lstates[i], lstates[i+1], ltrace[i]) in clrr.spec.next;\n      }\n    }\n  }\n\n  lemma lemma_EstablishStillNoNonmoversAfterMovingRightMoverForRemoval<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    lstates:seq<State>,\n    ltrace:seq<Step>,\n    step_actor:Actor,\n    right_mover_pos:int,\n    new_middle_state:State,\n    other_step':Step,\n    right_mover':Step,\n    hstates:seq<State>,\n    htrace:seq<Step>\n    )\n    requires ValidCohenLamportReductionRequest(clrr)\n    requires StateNextSeq(lstates, ltrace, clrr.spec.next)\n    requires lstates[0] in AnnotatedReachables(clrr.spec)\n    requires 0 <= right_mover_pos < |ltrace|-1\n    requires !clrr.crashed(lstates[right_mover_pos+2])\n    requires clrr.phase1(lstates[right_mover_pos+1], step_actor)\n    requires clrr.idmap(ltrace[right_mover_pos]) == step_actor\n    requires clrr.idmap(ltrace[right_mover_pos+1]) != step_actor\n    requires forall i :: 0 <= i < |ltrace| ==> !IsNonmoverPos(clrr, lstates, ltrace, i)\n    requires forall i :: 0 <= i < right_mover_pos ==>\n               var actor := clrr.idmap(ltrace[i]);\n               var s := lstates[i+1];\n               !clrr.crashed(s) ==> !clrr.phase1(s, actor) && !clrr.phase2(s, actor)\n    requires forall i :: right_mover_pos < i < |ltrace| ==>\n               var actor := clrr.idmap(ltrace[i]);\n               var s := lstates[i+1];\n               !clrr.crashed(s) ==> !clrr.phase1(s, actor) && !clrr.phase2(s, actor)\n    requires ActionTuple(lstates[right_mover_pos], new_middle_state, other_step') in clrr.spec.next\n    requires ActionTuple(new_middle_state, lstates[right_mover_pos+2], right_mover') in clrr.spec.next\n    requires clrr.idmap(other_step') == clrr.idmap(ltrace[right_mover_pos+1])\n    requires clrr.idmap(right_mover') == clrr.idmap(ltrace[right_mover_pos])\n    requires hstates == lstates[..right_mover_pos+1] + [new_middle_state] + lstates[right_mover_pos+2..]\n    requires htrace == ltrace[..right_mover_pos] + [other_step', right_mover'] + ltrace[right_mover_pos+2..]\n    ensures  forall i :: 0 <= i < |htrace| ==> !IsNonmoverPos(clrr, hstates, htrace, i)\n    ensures  forall i :: 0 <= i <= right_mover_pos ==>\n               var actor := clrr.idmap(htrace[i]);\n               var s := hstates[i+1];\n               !clrr.crashed(s) ==> !clrr.phase1(s, actor) && !clrr.phase2(s, actor)\n    ensures  forall i :: right_mover_pos+1 < i < |htrace| ==>\n               var actor := clrr.idmap(htrace[i]);\n               var s := hstates[i+1];\n               !clrr.crashed(s) ==> !clrr.phase1(s, actor) && !clrr.phase2(s, actor)\n  {\n    var right_mover_pos_plus := right_mover_pos + 1;\n\n    forall i | 0 <= i < |htrace|\n      ensures !IsNonmoverPos(clrr, hstates, htrace, i)\n    {\n      if i == right_mover_pos {\n        assert hstates[i] == lstates[right_mover_pos];\n        assert hstates[i+1] == new_middle_state;\n        assert !IsNonmoverPos(clrr, lstates, ltrace, right_mover_pos_plus);\n        assert ActionTuple(lstates[right_mover_pos], lstates[right_mover_pos+1], ltrace[right_mover_pos]) in clrr.spec.next;\n        assert ActionTuple(new_middle_state, lstates[right_mover_pos_plus+1], right_mover') in clrr.spec.next;\n        assert !IsNonmoverStep(clrr, lstates[right_mover_pos], new_middle_state, clrr.idmap(htrace[i]));\n      }\n      else if i == right_mover_pos + 1 {\n        assert hstates[i] == new_middle_state;\n        assert hstates[i+1] == lstates[right_mover_pos+2];\n      }\n      else {\n        assert !IsNonmoverPos(clrr, lstates, ltrace, i);\n      }\n    }\n\n    forall i | 0 <= i <= right_mover_pos\n      ensures var actor := clrr.idmap(htrace[i]);\n              var s := hstates[i+1];\n              !clrr.crashed(s) ==> !clrr.phase1(s, actor) && !clrr.phase2(s, actor)\n    {\n      if i < right_mover_pos {\n        assert htrace[i] == ltrace[i];\n        assert hstates[i+1] == lstates[i+1];\n        assert var actor := clrr.idmap(ltrace[i]);\n               var s := lstates[i+1];\n               !clrr.crashed(s) ==> !clrr.phase1(s, actor) && !clrr.phase2(s, actor);\n      }\n      else {\n        assert i == right_mover_pos;\n        assert htrace[i] == other_step';\n        var other_actor := clrr.idmap(other_step');\n        assert other_actor == clrr.idmap(ltrace[right_mover_pos+1]);\n        assert hstates[i+1] == new_middle_state;\n        assert ActionTuple(new_middle_state, lstates[right_mover_pos+2], right_mover') in clrr.spec.next;\n        assert clrr.idmap(right_mover') != other_actor;\n        assert clrr.phase1(new_middle_state, other_actor) <==> clrr.phase1(lstates[right_mover_pos+2], other_actor);\n        assert clrr.phase2(new_middle_state, other_actor) <==> clrr.phase2(lstates[right_mover_pos+2], other_actor);\n        assert var actor := clrr.idmap(ltrace[right_mover_pos_plus]);\n               var s := lstates[right_mover_pos_plus+1];\n               !clrr.crashed(s) ==> !clrr.phase1(s, actor) && !clrr.phase2(s, actor);\n      }\n    }\n  }\n\n  lemma lemma_MoveRightMoverRightForRemoval<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    lstates:seq<State>,\n    ltrace:seq<Step>,\n    step_actor:Actor,\n    right_mover_pos:int\n    ) returns (\n    hstates:seq<State>,\n    htrace:seq<Step>\n    )\n    requires ValidCohenLamportReductionRequest(clrr)\n    requires StateNextSeq(lstates, ltrace, clrr.spec.next)\n    requires lstates[0] in AnnotatedReachables(clrr.spec)\n    requires 0 <= right_mover_pos < |ltrace|-1\n    requires !clrr.crashed(lstates[right_mover_pos+2])\n    requires clrr.phase1(lstates[right_mover_pos+1], step_actor)\n    requires clrr.idmap(ltrace[right_mover_pos]) == step_actor\n    requires forall i :: 0 <= i < |ltrace| ==> !IsNonmoverPos(clrr, lstates, ltrace, i)\n    requires forall i :: 0 <= i < right_mover_pos ==>\n               var actor := clrr.idmap(ltrace[i]);\n               var s := lstates[i+1];\n               !clrr.crashed(s) ==> !clrr.phase1(s, actor) && !clrr.phase2(s, actor)\n    requires forall i :: right_mover_pos < i < |ltrace| ==>\n               var actor := clrr.idmap(ltrace[i]);\n               var s := lstates[i+1];\n               !clrr.crashed(s) ==> !clrr.phase1(s, actor) && !clrr.phase2(s, actor)\n    ensures  BehaviorRefinesBehavior(lstates, hstates, clrr.relation)\n    ensures  StateNextSeq(hstates, htrace, clrr.spec.next)\n    ensures  hstates[0] == lstates[0]\n    ensures  |htrace| == |ltrace|\n    ensures  forall i :: 0 <= i < |htrace| ==> !IsNonmoverPos(clrr, hstates, htrace, i)\n    ensures  forall i :: 0 <= i <= right_mover_pos ==>\n               var actor := clrr.idmap(htrace[i]);\n               var s := hstates[i+1];\n               !clrr.crashed(s) ==> !clrr.phase1(s, actor) && !clrr.phase2(s, actor)\n    ensures  forall i :: right_mover_pos+1 < i < |htrace| ==>\n               var actor := clrr.idmap(htrace[i]);\n               var s := hstates[i+1];\n               !clrr.crashed(s) ==> !clrr.phase1(s, actor) && !clrr.phase2(s, actor)\n    ensures  clrr.idmap(htrace[right_mover_pos+1]) == step_actor\n    ensures  clrr.phase1(hstates[right_mover_pos+2], step_actor)\n    ensures  !clrr.crashed(hstates[right_mover_pos+2])\n  {\n    assert ActionTuple(lstates[right_mover_pos], lstates[right_mover_pos+1], ltrace[right_mover_pos]) in clrr.spec.next;\n    var right_mover_pos_plus := right_mover_pos + 1;\n    assert ActionTuple(lstates[right_mover_pos_plus], lstates[right_mover_pos_plus+1], ltrace[right_mover_pos_plus]) in clrr.spec.next;\n    lemma_StateNextSeqMaintainsAnnotatedReachables(lstates, ltrace, clrr.spec);\n    assert !IsNonmoverPos(clrr, lstates, ltrace, right_mover_pos+1);\n    assert RightMoversCommuteConditions(clrr, lstates[right_mover_pos], lstates[right_mover_pos+1],\n                                        lstates[right_mover_pos_plus+1], ltrace[right_mover_pos],\n                                        ltrace[right_mover_pos+1]);\n    var new_middle_state, other_step', right_mover' :|\n      && ActionTuple(lstates[right_mover_pos], new_middle_state, other_step') in clrr.spec.next\n      && ActionTuple(new_middle_state, lstates[right_mover_pos_plus+1], right_mover') in clrr.spec.next\n      && clrr.idmap(other_step') == clrr.idmap(ltrace[right_mover_pos+1])\n      && clrr.idmap(right_mover') == clrr.idmap(ltrace[right_mover_pos]);\n\n    hstates := lstates[..right_mover_pos+1] + [new_middle_state] + lstates[right_mover_pos+2..];\n    htrace := ltrace[..right_mover_pos] + [other_step', right_mover'] + ltrace[right_mover_pos+2..];\n    lemma_EstablishBehaviorRefinesBehaviorAfterMovingRightMoverForRemoval(\n      clrr, lstates, ltrace, step_actor, right_mover_pos, new_middle_state, other_step', right_mover', hstates, htrace);\n    lemma_EstablishBehaviorSatisfiesSpecAfterMovingRightMoverForRemoval(\n      clrr, lstates, ltrace, step_actor, right_mover_pos, new_middle_state, other_step', right_mover', hstates, htrace);\n    lemma_EstablishStillNoNonmoversAfterMovingRightMoverForRemoval(\n      clrr, lstates, ltrace, step_actor, right_mover_pos, new_middle_state, other_step', right_mover', hstates, htrace);\n  }\n\n  lemma lemma_RemoveRightMoverFromPos<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    lstates:seq<State>,\n    ltrace:seq<Step>,\n    step_actor:Actor,\n    right_mover_pos:int\n    ) returns (\n    hstates:seq<State>,\n    htrace:seq<Step>\n    )\n    requires ValidCohenLamportReductionRequest(clrr)\n    requires StateNextSeq(lstates, ltrace, clrr.spec.next)\n    requires lstates[0] in AnnotatedReachables(clrr.spec)\n    requires 0 <= right_mover_pos < |ltrace|\n    requires !clrr.crashed(lstates[right_mover_pos+1])\n    requires clrr.phase1(lstates[right_mover_pos+1], step_actor)\n    requires clrr.idmap(ltrace[right_mover_pos]) == step_actor\n    requires forall i :: 0 <= i < |ltrace| ==> !IsNonmoverPos(clrr, lstates, ltrace, i)\n    requires forall i :: 0 <= i < right_mover_pos ==>\n               var actor := clrr.idmap(ltrace[i]);\n               var s := lstates[i+1];\n               !clrr.crashed(s) ==> !clrr.phase1(s, actor) && !clrr.phase2(s, actor)\n    requires forall i :: right_mover_pos < i < |ltrace| ==>\n               var actor := clrr.idmap(ltrace[i]);\n               var s := lstates[i+1];\n               !clrr.crashed(s) ==> !clrr.phase1(s, actor) && !clrr.phase2(s, actor)\n    ensures  BehaviorRefinesBehavior(lstates, hstates, clrr.relation)\n    ensures  StateNextSeq(hstates, htrace, clrr.spec.next)\n    ensures  hstates[0] == lstates[0]\n    ensures  |htrace| <= |ltrace|\n    ensures  forall i :: 0 <= i < |htrace| ==> !IsNonmoverPos(clrr, hstates, htrace, i)\n    ensures  forall i :: 0 <= i < |htrace| ==>\n               var actor := clrr.idmap(htrace[i]);\n               var s := hstates[i+1];\n               !clrr.crashed(s) ==> !clrr.phase1(s, actor) && !clrr.phase2(s, actor)\n    decreases |lstates| - right_mover_pos\n  {\n    if right_mover_pos == |ltrace|-1 {\n      hstates, htrace := lemma_RemoveRightMoverFromPosCaseAtEnd(clrr, lstates, ltrace, step_actor, right_mover_pos);\n      return;\n    }\n\n    if clrr.crashed(lstates[right_mover_pos+2]) {\n      hstates, htrace := lemma_RemoveRightMoverFromPosCaseBeforeCrash(clrr, lstates, ltrace, step_actor, right_mover_pos);\n      return;\n    }\n\n    var mstates, mtrace := lemma_MoveRightMoverRightForRemoval(clrr, lstates, ltrace, step_actor, right_mover_pos);\n    hstates, htrace := lemma_RemoveRightMoverFromPos(clrr, mstates, mtrace, step_actor, right_mover_pos+1);\n    lemma_RefinementConvolutionTransitive(lstates, mstates, hstates, clrr.relation);\n  }\n\n  lemma lemma_NoNonmoversMeansNoPhase2<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    b:AnnotatedBehavior<State, Step>,\n    pos:int,\n    step_actor:Actor\n    )\n    requires ValidCohenLamportReductionRequest(clrr)\n    requires AnnotatedBehaviorSatisfiesSpec(b, clrr.spec)\n    requires forall i :: 0 <= i < |b.trace| ==> !IsNonmoverPos(clrr, b.states, b.trace, i)\n    requires 0 <= pos < |b.states|\n    ensures  !clrr.crashed(b.states[pos]) ==> !clrr.phase2(b.states[pos], step_actor)\n    decreases pos\n  {\n    if pos > 0 {\n      var prev := pos - 1;\n      assert ActionTuple(b.states[prev], b.states[prev+1], b.trace[prev]) in clrr.spec.next;\n      lemma_NoNonmoversMeansNoPhase2(clrr, b, prev, step_actor);\n      assert !IsNonmoverPos(clrr, b.states, b.trace, prev);\n    }\n  }\n\n  lemma lemma_RemoveAllRightMoversAtOrBeforePos<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    lb:AnnotatedBehavior<State, Step>,\n    right_mover_pos:int\n    ) returns (\n    hb:AnnotatedBehavior<State, Step>\n    )\n    requires ValidCohenLamportReductionRequest(clrr)\n    requires AnnotatedBehaviorSatisfiesSpec(lb, clrr.spec)\n    requires forall i :: 0 <= i < |lb.trace| ==> !IsNonmoverPos(clrr, lb.states, lb.trace, i)\n    requires 0 <= right_mover_pos < |lb.trace|\n    requires forall i :: right_mover_pos < i < |lb.trace| ==>\n               var actor := clrr.idmap(lb.trace[i]);\n               var s := lb.states[i+1];\n               !clrr.crashed(s) ==> !clrr.phase1(s, actor) && !clrr.phase2(s, actor)\n    ensures  BehaviorRefinesBehavior(lb.states, hb.states, clrr.relation)\n    ensures  AnnotatedBehaviorSatisfiesSpec(hb, clrr.spec)\n    ensures  forall i :: 0 <= i < |hb.trace| ==> !IsNonmoverPos(clrr, hb.states, hb.trace, i)\n    ensures  forall i :: 0 <= i < |hb.trace| ==>\n               var actor := clrr.idmap(hb.trace[i]);\n               var s := hb.states[i+1];\n               !clrr.crashed(s) ==> !clrr.phase1(s, actor) && !clrr.phase2(s, actor)\n    decreases right_mover_pos;\n  {\n    var step_actor := clrr.idmap(lb.trace[right_mover_pos]);\n    var s := lb.states[right_mover_pos];\n    var s' := lb.states[right_mover_pos+1];\n\n    lemma_NoNonmoversMeansNoPhase2(clrr, lb, right_mover_pos+1, step_actor);\n\n    if clrr.crashed(s') || !clrr.phase1(s', step_actor) {\n      if right_mover_pos == 0 {\n        hb := lb;\n        lemma_IfRefinementRelationReflexiveThenBehaviorRefinesItself(lb.states, clrr.relation);\n      }\n      else {\n        hb := lemma_RemoveAllRightMoversAtOrBeforePos(clrr, lb, right_mover_pos-1);\n      }\n      return;\n    }\n\n    var lstates_trunc := lb.states[right_mover_pos..];\n    var ltrace_trunc := lb.trace[right_mover_pos..];\n    forall i | 0 <= i < |ltrace_trunc|\n      ensures !IsNonmoverPos(clrr, lstates_trunc, ltrace_trunc, i)\n    {\n      lemma_IndexIntoDrop(lb.states, right_mover_pos, i);\n      lemma_IndexIntoDrop(lb.states, right_mover_pos, i+1);\n      assert lstates_trunc[i] == lb.states[right_mover_pos+i];\n      assert lstates_trunc[i+1] == lb.states[right_mover_pos+i+1];\n      assert !IsNonmoverPos(clrr, lb.states, lb.trace, right_mover_pos+i);\n    }\n\n    lemma_StateInAnnotatedBehaviorInAnnotatedReachables(clrr.spec, lb, right_mover_pos);\n    var mstates_trunc, mtrace_trunc := lemma_RemoveRightMoverFromPos(clrr, lstates_trunc, ltrace_trunc, step_actor, 0);\n\n    lemma_ExtendBehaviorRefinesBehaviorLeft(lb.states[right_mover_pos..], mstates_trunc, clrr.relation, lb.states[..right_mover_pos]);\n    lemma_TakePlusDropIsSeq(lb.states, right_mover_pos);\n\n    var mb := AnnotatedBehavior(lb.states[..right_mover_pos] + mstates_trunc, lb.trace[..right_mover_pos] + mtrace_trunc);\n    assert BehaviorRefinesBehavior(lb.states, mb.states, clrr.relation);\n    assert StateNextSeq(mb.states, mb.trace, clrr.spec.next);\n\n    forall i | 0 <= i < |mb.trace|\n      ensures !IsNonmoverPos(clrr, mb.states, mb.trace, i)\n    {\n      if i < right_mover_pos-1 {\n        assert mb.states[i] == lb.states[i];\n        assert mb.states[i+1] == lb.states[i+1];\n        assert mb.trace[i] == lb.trace[i];\n        assert !IsNonmoverPos(clrr, lb.states, lb.trace, i);\n      }\n      else if i == right_mover_pos-1 {\n        assert mb.states[i] == lb.states[i];\n        assert mb.states[i+1] == mstates_trunc[0] == lstates_trunc[0] == lb.states[right_mover_pos] == lb.states[i+1];\n        assert mb.trace[i] == lb.trace[i];\n        assert !IsNonmoverPos(clrr, lb.states, lb.trace, i);\n      }\n      else {\n        var iadj := i - right_mover_pos;\n        assert mb.states[i] == mstates_trunc[iadj];\n        assert mb.states[i+1] == mstates_trunc[iadj+1];\n        assert mb.trace[i] == mtrace_trunc[iadj];\n        assert !IsNonmoverPos(clrr, mstates_trunc, mtrace_trunc, iadj);\n      }\n    }\n\n    if right_mover_pos == 0 {\n      hb := mb;\n    }\n    else {\n      hb := lemma_RemoveAllRightMoversAtOrBeforePos(clrr, mb, right_mover_pos-1);\n      lemma_RefinementConvolutionTransitive(lb.states, mb.states, hb.states, clrr.relation);\n    }\n  }\n\n  lemma lemma_RemoveAllRightMovers<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    lb:AnnotatedBehavior<State, Step>\n    ) returns (\n    hb:AnnotatedBehavior<State, Step>\n    )\n    requires ValidCohenLamportReductionRequest(clrr)\n    requires AnnotatedBehaviorSatisfiesSpec(lb, clrr.spec)\n    requires forall i :: 0 <= i < |lb.trace| ==> !IsNonmoverPos(clrr, lb.states, lb.trace, i)\n    ensures  BehaviorRefinesBehavior(lb.states, hb.states, clrr.relation)\n    ensures  AnnotatedBehaviorSatisfiesSpec(hb, clrr.spec)\n    ensures  forall i, actor :: 0 <= i < |hb.states| ==> var s := hb.states[i]; !clrr.crashed(s) ==> !clrr.phase1(s, actor) && !clrr.phase2(s, actor)\n  {\n    if |lb.trace| == 0 {\n      hb := lb;\n      lemma_IfRefinementRelationReflexiveThenBehaviorRefinesItself(lb.states, clrr.relation);\n    }\n    else {\n      hb := lemma_RemoveAllRightMoversAtOrBeforePos(clrr, lb, |lb.trace|-1);\n    }\n\n    forall j, actor | 0 <= j < |hb.states|\n      ensures var s := hb.states[j]; !clrr.crashed(s) ==> !clrr.phase1(s, actor) && !clrr.phase2(s, actor)\n    {\n      var pos := 0;\n      while pos < |hb.trace|\n        invariant 0 <= pos <= |hb.trace|\n        invariant forall i :: 0 <= i <= pos ==> var s := hb.states[i]; !clrr.crashed(s) ==> !clrr.phase1(s, actor) && !clrr.phase2(s, actor)\n      {\n        var s := hb.states[pos];\n        var s' := hb.states[pos+1];\n        if clrr.idmap(hb.trace[pos]) == actor {\n          assert !clrr.crashed(s') ==> !clrr.phase1(s', actor) && !clrr.phase2(s', actor);\n        }\n        else {\n          assert ActionTuple(hb.states[pos], hb.states[pos+1], hb.trace[pos]) in clrr.spec.next;\n          assert !clrr.crashed(s) ==> !clrr.phase1(s, actor) && !clrr.phase2(s, actor);\n          assert clrr.phase1(s, actor) <==> clrr.phase1(s', actor);\n          assert clrr.phase2(s, actor) <==> clrr.phase2(s', actor);\n        }\n        pos := pos + 1;\n      }\n    }\n  }\n\n}\n"
  },
  {
    "path": "Armada/strategies/reduction/CohenLamportReductionSpec.i.dfy",
    "content": "/////////////////////////////////////////////////////////////////////////////////////////////////////\n//\n// This file is the specification for a request to perform a Cohen-Lamport reduction on a behavior.\n// Such a reduction takes a behavior where some states are in phase 1 or 2, and returns a behavior\n// in which no state (except possibly the last, crashing state) is in phase 1 or 2.  That resulting\n// behavior satisfies the same specification, but is a refinement of the original behavior.\n//\n// To use this specification, first create a request r of type CohenLamportReductionRequest.  Then,\n// prove that it's a valid request, i.e., that ValidCohenLamportReductionRequest(r).  Finally, call\n// lemma_PerformCohenLamportReduction (in CohenLamportReduction.i.dfy).\n//\n// The request specification allows behaviors that crash as their final step.  But, the request\n// specification also demands that action sequences be reducible if they crash in the middle, i.e.,\n// even if the actor performing those action sequences executes a step that crashes while in phase 1\n// or 2.\n//\n/////////////////////////////////////////////////////////////////////////////////////////////////////\n\ninclude \"../../util/collections/seqs.s.dfy\"\ninclude \"../../spec/refinement.s.dfy\"\ninclude \"../refinement/GeneralRefinementLemmas.i.dfy\"\ninclude \"../refinement/RefinementConvolution.i.dfy\"\ninclude \"../refinement/AnnotatedBehavior.i.dfy\"\ninclude \"../invariants.i.dfy\"\n\nmodule CohenLamportReductionSpecModule {\n\n  import opened util_collections_seqs_s\n  import opened GeneralRefinementModule\n  import opened GeneralRefinementLemmasModule\n  import opened RefinementConvolutionModule\n  import opened AnnotatedBehaviorModule\n  import opened InvariantsModule\n\n  datatype CohenLamportReductionRequest<!State(==), !Actor(==), !Step> = CohenLamportReductionRequest(\n    spec:AnnotatedBehaviorSpec<State, Step>,\n    relation:RefinementRelation<State, State>,\n    idmap:Step->Actor,\n    phase1:(State, Actor)->bool,\n    phase2:(State, Actor)->bool,\n    crashed:State->bool\n    )\n\n  predicate PhaseUnaffectedByOtherActors<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>\n    )\n  {\n    && (forall s, s', step, actor :: ActionTuple(s, s', step) in clrr.spec.next && clrr.idmap(step) != actor ==>\n                              (clrr.phase1(s, actor) <==> clrr.phase1(s', actor)))\n    && (forall s, s', step, actor :: ActionTuple(s, s', step) in clrr.spec.next && clrr.idmap(step) != actor ==>\n                              (clrr.phase2(s, actor) <==> clrr.phase2(s', actor)))\n  }\n\n  predicate CantGoDirectlyFromPhase2ToPhase1<State(!new), Actor, Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>\n    )\n  {\n    forall s, s', step :: ActionTuple(s, s', step) in clrr.spec.next && clrr.phase2(s, clrr.idmap(step)) ==> !clrr.phase1(s', clrr.idmap(step))\n  }\n\n  predicate RightMoversPreserveStateRefinement<State(!new), Actor, Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>\n    )\n  {\n    forall s, s', step ::\n      && ActionTuple(s, s', step) in clrr.spec.next\n      && clrr.phase1(s', clrr.idmap(step))\n      && !clrr.crashed(s')\n      ==> RefinementPair(s', s) in clrr.relation\n  }\n\n  predicate LeftMoversPreserveStateRefinement<State(!new), Actor, Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>\n    )\n  {\n    forall s, s', step ::\n      && ActionTuple(s, s', step) in clrr.spec.next\n      && clrr.phase2(s, clrr.idmap(step))\n      ==> RefinementPair(s, s') in clrr.relation\n  }\n\n  predicate NoStepsAfterCrash<State(!new), Actor(!new), Step(!new)(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>\n    )\n  {\n    forall s, s', step :: ActionTuple(s, s', step) in clrr.spec.next ==> !clrr.crashed(s)\n  }\n\n  predicate RightMoversCommuteConditions<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    initial_state:State,\n    state_after_right_mover:State,\n    state_after_both_steps:State,\n    right_mover:Step,\n    other_step:Step\n    )\n  {\n    && initial_state in AnnotatedReachables(clrr.spec)\n    && ActionTuple(initial_state, state_after_right_mover, right_mover) in clrr.spec.next\n    && ActionTuple(state_after_right_mover, state_after_both_steps, other_step) in clrr.spec.next\n    && clrr.idmap(right_mover) != clrr.idmap(other_step)\n    && clrr.phase1(state_after_right_mover, clrr.idmap(right_mover))\n    && !clrr.crashed(state_after_both_steps)\n  }\n\n  predicate RightMoversCommute<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>\n    )\n  {\n    forall initial_state, state_after_right_mover, state_after_both_steps, right_mover, other_step\n      {:trigger RightMoversCommuteConditions(clrr, initial_state, state_after_right_mover, state_after_both_steps, right_mover, other_step)}\n      :: RightMoversCommuteConditions(clrr, initial_state, state_after_right_mover, state_after_both_steps, right_mover, other_step)\n      ==> exists new_middle_state, other_step', right_mover' ::\n            && ActionTuple(initial_state, new_middle_state, other_step') in clrr.spec.next\n            && ActionTuple(new_middle_state, state_after_both_steps, right_mover') in clrr.spec.next\n            && clrr.idmap(other_step') == clrr.idmap(other_step)\n            && clrr.idmap(right_mover') == clrr.idmap(right_mover)\n  }\n\n  predicate LeftMoversCommuteConditions<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    initial_state:State,\n    state_after_other_step:State,\n    state_after_both_steps:State,\n    other_step:Step,\n    left_mover:Step\n    )\n  {\n    && initial_state in AnnotatedReachables(clrr.spec)\n    && ActionTuple(initial_state, state_after_other_step, other_step) in clrr.spec.next\n    && ActionTuple(state_after_other_step, state_after_both_steps, left_mover) in clrr.spec.next\n    && clrr.idmap(other_step) != clrr.idmap(left_mover)\n    && clrr.phase2(state_after_other_step, clrr.idmap(left_mover))\n    && !clrr.crashed(state_after_both_steps)\n  }\n\n  predicate LeftMoversCommute<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>\n    )\n  {\n    forall initial_state, state_after_other_step, state_after_both_steps, other_step, left_mover\n      {:trigger LeftMoversCommuteConditions(clrr, initial_state, state_after_other_step, state_after_both_steps, other_step, left_mover)}\n      :: LeftMoversCommuteConditions(clrr, initial_state, state_after_other_step, state_after_both_steps, other_step, left_mover)\n      ==> exists new_middle_state, left_mover', other_step' ::\n            && ActionTuple(initial_state, new_middle_state, left_mover') in clrr.spec.next\n            && ActionTuple(new_middle_state, state_after_both_steps, other_step') in clrr.spec.next\n            && clrr.idmap(left_mover') == clrr.idmap(left_mover)\n            && clrr.idmap(other_step') == clrr.idmap(other_step)\n  }\n\n  predicate LeftMoversAlwaysEnabledConditions<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    s:State,\n    actor:Actor\n    )\n  {\n    && s in AnnotatedReachables(clrr.spec)\n    && clrr.phase2(s, actor)\n    && !clrr.crashed(s)\n  }\n\n  predicate LeftMoversAlwaysEnabled<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>\n    )\n  {\n    forall s, actor\n      {:trigger LeftMoversAlwaysEnabledConditions(clrr, s, actor)}\n      :: LeftMoversAlwaysEnabledConditions(clrr, s, actor)\n      ==> exists states, trace ::\n             && StateNextSeq(states, trace, clrr.spec.next)\n             && states[0] == s\n             && (clrr.crashed(last(states)) || !clrr.phase2(last(states), actor))\n             && (forall i :: 0 <= i < |states|-1 ==> clrr.phase2(states[i], actor))\n             && (forall step :: step in trace ==> clrr.idmap(step) == actor)\n  }\n\n  predicate LeftMoversEnabledBeforeCrashConditions<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    initial_state:State,\n    post_crash_state:State,\n    crash_step:Step,\n    actor:Actor\n    )\n  {\n    && initial_state in AnnotatedReachables(clrr.spec)\n    && ActionTuple(initial_state, post_crash_state, crash_step) in clrr.spec.next\n    && !clrr.crashed(initial_state)\n    && clrr.crashed(post_crash_state)\n    && clrr.idmap(crash_step) != actor\n    && clrr.phase2(initial_state, actor)\n  }\n\n  predicate LeftMoversEnabledBeforeCrash<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>\n    )\n  {\n    forall initial_state, post_crash_state, crash_step, actor\n      {:trigger LeftMoversEnabledBeforeCrashConditions(clrr, initial_state, post_crash_state, crash_step, actor)}\n      :: LeftMoversEnabledBeforeCrashConditions(clrr, initial_state, post_crash_state, crash_step, actor)\n      ==> exists states, trace, crash_step', post_crash_state' ::\n             && StateNextSeq(states, trace, clrr.spec.next)\n             && states[0] == initial_state\n             && !clrr.crashed(last(states))\n             && !clrr.phase2(last(states), actor)\n             && (forall i :: 0 <= i < |states|-1 ==> clrr.phase2(states[i], actor))\n             && (forall step :: step in trace ==> clrr.idmap(step) == actor)\n             && ActionTuple(last(states), post_crash_state', crash_step') in clrr.spec.next\n             && clrr.idmap(crash_step') == clrr.idmap(crash_step)\n             && clrr.crashed(post_crash_state')\n             && RefinementPair(post_crash_state, post_crash_state') in clrr.relation\n  }\n\n  predicate RightMoverCrashPreservationConditions<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    initial_state:State,\n    state_after_right_mover:State,\n    state_after_both_steps:State,\n    right_mover:Step,\n    other_step:Step\n    )\n  {\n    && initial_state in AnnotatedReachables(clrr.spec)\n    && ActionTuple(initial_state, state_after_right_mover, right_mover) in clrr.spec.next\n    && ActionTuple(state_after_right_mover, state_after_both_steps, other_step) in clrr.spec.next\n    && !clrr.crashed(initial_state)\n    && !clrr.crashed(state_after_right_mover)\n    && clrr.crashed(state_after_both_steps)\n    && clrr.phase1(state_after_right_mover, clrr.idmap(right_mover))\n    && clrr.idmap(right_mover) != clrr.idmap(other_step)\n  }\n\n  predicate RightMoverCrashPreservation<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>\n    )\n  {\n    forall initial_state, state_after_right_mover, state_after_both_steps, right_mover, other_step\n      {:trigger RightMoverCrashPreservationConditions(clrr, initial_state, state_after_right_mover, state_after_both_steps, right_mover,\n                                                      other_step)}\n      :: RightMoverCrashPreservationConditions(clrr, initial_state, state_after_right_mover, state_after_both_steps, right_mover, other_step)\n      ==> exists other_step', state_after_other_step' ::\n            && clrr.idmap(other_step') == clrr.idmap(other_step)\n            && ActionTuple(initial_state, state_after_other_step', other_step') in clrr.spec.next\n            && clrr.crashed(state_after_other_step')\n            && RefinementPair(state_after_both_steps, state_after_other_step') in clrr.relation\n  }\n\n  predicate LeftMoverSelfCrashPreservationConditions<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    initial_state:State,\n    state_after_other_step:State,\n    state_after_both_steps:State,\n    other_step:Step,\n    left_mover:Step\n    )\n  {\n    && initial_state in AnnotatedReachables(clrr.spec)\n    && ActionTuple(initial_state, state_after_other_step, other_step) in clrr.spec.next\n    && ActionTuple(state_after_other_step, state_after_both_steps, left_mover) in clrr.spec.next\n    && !clrr.crashed(initial_state)\n    && !clrr.crashed(state_after_other_step)\n    && clrr.crashed(state_after_both_steps)\n    && clrr.phase2(state_after_other_step, clrr.idmap(left_mover))\n    && clrr.idmap(left_mover) != clrr.idmap(other_step)\n  }\n\n  predicate LeftMoverSelfCrashPreservation<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>\n    )\n  {\n    forall initial_state, state_after_other_step, state_after_both_steps, other_step, left_mover\n      {:trigger LeftMoverSelfCrashPreservationConditions(clrr, initial_state, state_after_other_step, state_after_both_steps, other_step,\n                                                         left_mover)}\n      :: LeftMoverSelfCrashPreservationConditions(clrr, initial_state, state_after_other_step, state_after_both_steps, other_step, left_mover)\n      ==> exists left_mover', state_after_left_mover' ::\n            && clrr.idmap(left_mover') == clrr.idmap(left_mover)\n            && ActionTuple(initial_state, state_after_left_mover', left_mover') in clrr.spec.next\n            && clrr.crashed(state_after_left_mover')\n            && RefinementPair(state_after_both_steps, state_after_left_mover') in clrr.relation\n  }\n\n  predicate ActionSequencesLiftableConditions<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>,\n    states:seq<State>,\n    trace:seq<Step>,\n    actor:Actor\n    )\n  {\n    && StateNextSeq(states, trace, clrr.spec.next)\n    && (forall step :: step in trace ==> clrr.idmap(step) == actor)\n    && |states| > 1\n    && !clrr.phase1(states[0], actor)\n    && !clrr.phase2(states[0], actor)\n    && (var s := last(states); !clrr.crashed(s) ==> !clrr.phase1(s, actor) && !clrr.phase2(s, actor))\n    && (forall i :: 0 <= i < |trace| ==> !clrr.crashed(states[i]))\n    && (forall i :: 0 < i < |trace| ==> var s := states[i]; clrr.phase1(s, actor) || clrr.phase2(s, actor))\n  }\n\n  predicate ActionSequencesLiftable<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>\n    )\n  {\n    forall states, trace, actor\n      {:trigger ActionSequencesLiftableConditions(clrr, states, trace, actor)}\n      :: ActionSequencesLiftableConditions(clrr, states, trace, actor)\n      ==> exists hstep :: ActionTuple(states[0], last(states), hstep) in clrr.spec.next && clrr.idmap(hstep) == actor\n  }\n\n  predicate ValidCohenLamportReductionRequest<State(!new), Actor(!new), Step(!new)>(\n    clrr:CohenLamportReductionRequest<State, Actor, Step>\n    )\n  {\n    && RefinementRelationReflexive(clrr.relation)\n    && RefinementRelationTransitive(clrr.relation)\n    && (forall s, actor :: s in clrr.spec.init ==> !clrr.phase1(s, actor) && !clrr.phase2(s, actor))\n    && (forall s, actor :: clrr.phase1(s, actor) ==> !clrr.phase2(s, actor))\n    && CantGoDirectlyFromPhase2ToPhase1(clrr)\n    && PhaseUnaffectedByOtherActors(clrr)\n    && RightMoversPreserveStateRefinement(clrr)\n    && LeftMoversPreserveStateRefinement(clrr)\n    && NoStepsAfterCrash(clrr)\n    && RightMoversCommute(clrr)\n    && LeftMoversCommute(clrr)\n    && LeftMoversAlwaysEnabled(clrr)\n    && LeftMoversEnabledBeforeCrash(clrr)\n    && RightMoverCrashPreservation(clrr)\n    && LeftMoverSelfCrashPreservation(clrr)\n    && ActionSequencesLiftable(clrr)\n  }\n}\n"
  },
  {
    "path": "Armada/strategies/reduction/RefinementViaReduction.i.dfy",
    "content": "/////////////////////////////////////////////////////////////////////////////////////////////////////\n//\n// This file contains a lemma for performing refinement via a Cohen-Lamport reduction on a\n// behavior. Such a reduction takes a behavior where some states are in phase 1 or 2, and returns a\n// behavior satisfying a higher-level specification that lacks those phases.  It does so by lifting\n// sequences of steps in the lower-level specification to atomic steps in the higher-level\n// specification.\n//\n// To use this specification, first create a request r of type RefinementViaReductionRequest.  Then,\n// prove that it's a valid request, i.e., that ValidRefinementViaReductionRequest(r).  Finally, call\n// lemma_PerformRefinementViaReduction (in RefinementViaReduction.i.dfy).\n//\n// The request specification allows behaviors that crash as their final step.  But, the request\n// specification also demands that action sequences be reducible if they crash in the middle, i.e.,\n// even if the actor performing those action sequences executes a step that crashes while in phase 1\n// or 2.\n//\n// This lemma makes use of a lemma (lemma_PerformCohenLamportReduction) for performing Cohen-Lamport\n// reduction on a behavior without changing its specification.\n//\n/////////////////////////////////////////////////////////////////////////////////////////////////////\n\ninclude \"RefinementViaReductionLemmas.i.dfy\"\ninclude \"CohenLamportReduction.i.dfy\"\n\nmodule RefinementViaReductionModule {\n\n  import opened AnnotatedBehaviorModule\n  import opened RefinementViaReductionSpecModule\n  import opened RefinementViaReductionLemmasModule\n  import opened GeneralRefinementModule\n  import opened RefinementConvolutionModule\n  import opened CohenLamportReductionModule\n\n  lemma lemma_PerformRefinementViaReduction<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    lb:AnnotatedBehavior<State, LStep>\n    ) returns (\n    hb:AnnotatedBehavior<State, HStep>\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires AnnotatedBehaviorSatisfiesSpec(lb, rr.lspec)\n    ensures  BehaviorRefinesBehavior(lb.states, hb.states, rr.relation)\n    ensures  AnnotatedBehaviorSatisfiesSpec(hb, rr.hspec)\n  {\n    var cb := lemma_LiftBehaviorToCrossLevel(rr, lb);\n    var clrr := GetCohenLamportReductionRequest(rr);\n    lemma_IsValidCohenLamportReductionRequest(rr);\n    var mb := lemma_PerformCohenLamportReduction(clrr, cb);\n    lemma_RefinementConvolutionPure(lb.states, cb.states, mb.states, GetIdentityRelation<State>(), clrr.relation, rr.relation);\n    hb := lemma_LiftBehaviorToHighLayer(rr, mb);\n  }\n}\n"
  },
  {
    "path": "Armada/strategies/reduction/RefinementViaReductionLemmas.i.dfy",
    "content": "/////////////////////////////////////////////////////////////////////////////////////////////////////\n//\n// This file contains lemmas useful in effecting a refinement via reduction on a behavior.  They\n// support lemma_PerformRefinementViaReduction (in RefinementViaReduction.i.dfy).\n//\n// The general strategy is as follows.  We create a cross-level specification that bridges the gap\n// between the low-level spec and the high-level spec.  We then:\n// (1) Lift the given low-level behavior to produce a cross-level behavior.\n// (2) Use the Cohen-Lamport reduction library to reduce that to another cross-level behavior.\n// (3) Lift the resulting cross-level behavior to produce a high-level behavior.\n//\n// The cross-level specification has two types of steps: Low and Reducible.  A Low step consists of\n// a single low-level step, while a Reducible step consists of a reducible sequence of low-level\n// steps.\n//\n// It's easy to lift a low-level behavior to produce a cross-level behavior, since it just involves\n// converting every step into a Low step.\n//\n// The cross-level specification satisfies the conditions required by the Cohen-Lamport reduction\n// library, since it provides the ability to lift any reducible sequence of steps to another step in\n// the same specification (by turning them into a Reducible step).\n//\n// Finally, once the Cohen-Lamport reduction library has finished with the cross-level behavior,\n// it's easy to lift it to the high-level spec.  After all, all the non-liftable steps (the ones\n// that start or end in phase 1 or 2) have been eliminated.\n//\n/////////////////////////////////////////////////////////////////////////////////////////////////////\n\ninclude \"RefinementViaReductionSpec.i.dfy\"\ninclude \"CohenLamportReductionSpec.i.dfy\"\ninclude \"../../util/collections/seqs.i.dfy\"\n\nmodule RefinementViaReductionLemmasModule {\n\n  import opened util_collections_seqs_s\n  import opened GeneralRefinementModule\n  import opened GeneralRefinementLemmasModule\n  import opened RefinementConvolutionModule\n  import opened AnnotatedBehaviorModule\n  import opened InvariantsModule\n  import opened RefinementViaReductionSpecModule\n  import opened CohenLamportReductionSpecModule\n  import opened util_collections_seqs_i\n\n  ///////////////////////////////////////////\n  // CrossLevel spec\n  ///////////////////////////////////////////\n\n  datatype PhaseType = PhaseType1 | PhaseType2 | PhaseTypeNeither\n  datatype MoverType = MoverTypeRight | MoverTypeLeft | MoverTypeNonmover | MoverTypeExternal | MoverTypeImpossible\n\n  datatype CrossLevelStep<State, Actor, LStep> =\n    | Low(actor:Actor, step:LStep)\n    | Reducible(actor:Actor, states:seq<State>, trace:seq<LStep>)\n\n  predicate ValidReducibleCrossLevelStep<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    states:seq<State>,\n    trace:seq<LStep>,\n    actor:Actor\n    )\n  {\n    && StateNextSeq(states, trace, rr.lspec.next)\n    && (forall step :: step in trace ==> rr.idmap(step) == actor)\n    && |states| > 1\n    && !rr.phase1(states[0], actor)\n    && !rr.phase2(states[0], actor)\n    && (var s := last(states); !rr.crashed(s) ==> !rr.phase1(s, actor) && !rr.phase2(s, actor))\n    && (forall i :: 0 <= i < |trace| ==> !rr.crashed(states[i]))\n    && (forall i :: 0 < i < |trace| ==> rr.phase1(states[i], actor) || rr.phase2(states[i], actor))\n  }\n\n  predicate CrossLevelNext<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    s:State,\n    s':State,\n    cstep:CrossLevelStep<State, Actor, LStep>\n    )\n  {\n    match cstep\n      case Low(actor, step) =>\n        !rr.crashed(s) && ActionTuple(s, s', step) in rr.lspec.next && actor == rr.idmap(step)\n      case Reducible(actor, states, trace) =>\n        ValidReducibleCrossLevelStep(rr, states, trace, actor) && states[0] == s && last(states) == s'\n  }\n\n  function GetCrossLevelSpec<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>\n    ) : AnnotatedBehaviorSpec<State, CrossLevelStep<State, Actor, LStep>>\n  {\n    AnnotatedBehaviorSpec(rr.lspec.init,\n                          iset s, s', step | CrossLevelNext(rr, s, s', step) :: ActionTuple(s, s', step))\n  }\n\n  function GetIdentityRelation<State(!new)>() : RefinementRelation<State, State>\n  {\n    iset s | true :: RefinementPair(s, s)\n  }\n\n  lemma lemma_StateInCrossLevelBehaviorReachableInBaseSpec<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    b:AnnotatedBehavior<State, CrossLevelStep<State, Actor, LStep>>,\n    pos:int\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires AnnotatedBehaviorSatisfiesSpec(b, GetCrossLevelSpec(rr))\n    requires 0 <= pos < |b.states|\n    ensures  b.states[pos] in AnnotatedReachables(rr.lspec)\n    decreases pos\n  {\n    var cspec := GetCrossLevelSpec(rr);\n\n    if pos == 0 {\n      assert b.states[pos] in cspec.init;\n      assert b.states[pos] in rr.lspec.init;\n      assert AnnotatedReachables(rr.lspec) == AnnotatedReachablesPremium(rr.lspec);\n      return;\n    }\n\n    var prev := pos-1;\n    lemma_StateInCrossLevelBehaviorReachableInBaseSpec(rr, b, prev);\n    assert ActionTuple(b.states[prev], b.states[prev+1], b.trace[prev]) in cspec.next;\n    if b.trace[prev].Low? {\n      lemma_NextMaintainsAnnotatedReachables(b.states[prev], b.states[prev+1], b.trace[prev].step, rr.lspec);\n    }\n    else {\n      lemma_StateNextSeqMaintainsAnnotatedReachables(b.trace[prev].states, b.trace[prev].trace, rr.lspec);\n      assert last(b.trace[prev].states) == b.states[prev+1];\n      assert b.states[prev+1] in b.trace[prev].states;\n    }\n  }\n\n  lemma lemma_AnnotatedReachablesOfCrossLevelSpec<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    ensures  AnnotatedReachables(GetCrossLevelSpec(rr)) == AnnotatedReachables(rr.lspec)\n  {\n    var cspec := GetCrossLevelSpec(rr);\n    reveal AnnotatedReachables();\n\n    forall s | s in AnnotatedReachables(rr.lspec)\n      ensures s in AnnotatedReachables(cspec)\n    {\n      var ab :| AnnotatedBehaviorSatisfiesSpec(ab, rr.lspec) && last(ab.states) == s;\n      var cb := lemma_LiftBehaviorToCrossLevel(rr, ab);\n      assert AnnotatedBehaviorSatisfiesSpec(cb, cspec);\n      var relation := GetIdentityRelation<State>();\n      var ac_map :| BehaviorRefinesBehaviorUsingRefinementMap(ab.states, cb.states, relation, ac_map);\n      assert last(ac_map).last == |cb.states|-1;\n      assert RefinementPair(last(ab.states), last(cb.states)) in relation;\n    }\n\n    forall s | s in AnnotatedReachables(cspec)\n      ensures s in AnnotatedReachables(rr.lspec)\n    {\n      var cb :| AnnotatedBehaviorSatisfiesSpec(cb, cspec) && last(cb.states) == s;\n      lemma_StateInCrossLevelBehaviorReachableInBaseSpec(rr, cb, |cb.states|-1);\n    }\n  }\n\n  function LiftStepToCrossLevel<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    s:State,\n    s':State,\n    step:LStep\n    ) : CrossLevelStep<State, Actor, LStep>\n  {\n    Low(rr.idmap(step), step)\n  }\n\n  lemma lemma_LiftStateNextSeqToCrossLevel<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    clrr:CohenLamportReductionRequest<State, Actor, CrossLevelStep<State, Actor, LStep>>,\n    states:seq<State>,\n    ltrace:seq<LStep>\n    ) returns (\n    htrace:seq<CrossLevelStep<State, Actor, LStep>>\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires clrr == GetCohenLamportReductionRequest(rr)\n    requires StateNextSeq(states, ltrace, rr.lspec.next)\n    requires !rr.crashed(last(states))\n    ensures  StateNextSeq(states, htrace, clrr.spec.next)\n    ensures  forall state :: state in states ==> !rr.crashed(state)\n    ensures  forall i :: 0 <= i < |htrace| ==> htrace[i] == Low(rr.idmap(ltrace[i]), ltrace[i])\n  {\n    forall i | 0 <= i < |states|\n      ensures !rr.crashed(states[i])\n    {\n      if rr.crashed(states[i]) {\n        lemma_AllStatesFollowingCrashedStateSame(rr, states, ltrace, i);\n        assert states[i] == last(states);\n        assert false;\n      }\n    }\n\n    htrace := MapSeqToSeq(ltrace, x => Low(rr.idmap(x), x));\n\n    forall i {:trigger ActionTuple(states[i], states[i+1], htrace[i]) in clrr.spec.next} | 0 <= i < |htrace|\n      ensures ActionTuple(states[i], states[i+1], htrace[i]) in clrr.spec.next\n    {\n      assert ActionTuple(states[i], states[i+1], ltrace[i]) in rr.lspec.next;\n      assert htrace[i].Low?;\n      assert !rr.crashed(states[i]);\n      assert htrace[i].actor == rr.idmap(htrace[i].step);\n      assert CrossLevelNext(rr, states[i], states[i+1], htrace[i]);\n    }\n  }\n\n  lemma lemma_FindFirstCrashingState<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    states:seq<State>,\n    trace:seq<LStep>\n    ) returns (\n    pos:int\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires StateNextSeq(states, trace, rr.lspec.next)\n    ensures  0 <= pos <= |states|\n    ensures  forall i :: 0 <= i < pos ==> !rr.crashed(states[i])\n    ensures  pos < |states| ==> rr.crashed(states[pos])\n    ensures  pos < |states| ==> forall i :: pos < i < |states| ==> states[i] == states[pos]\n  {\n    pos := 0;\n\n    while pos < |trace| && !rr.crashed(states[pos])\n      invariant 0 <= pos <= |trace|\n      invariant forall i :: 0 <= i < pos ==> !rr.crashed(states[i])\n    {\n      assert ActionTuple(states[pos], states[pos+1], trace[pos]) in rr.lspec.next;\n      pos := pos + 1;\n    }\n\n    if pos == |trace| {\n      if !rr.crashed(states[pos]) {\n        pos := pos + 1;\n      }\n      return;\n    }\n\n    var j := pos;\n    while j < |trace|\n      invariant pos <= j <= |trace|\n      invariant forall i :: pos <= i <= j ==> states[i] == states[pos]\n    {\n      assert ActionTuple(states[j], states[j+1], trace[j]) in rr.lspec.next;\n      j := j + 1;\n    }\n  }\n\n  lemma lemma_LiftBehaviorToCrossLevel<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    lb:AnnotatedBehavior<State, LStep>\n    ) returns (\n    hb:AnnotatedBehavior<State, CrossLevelStep<State, Actor, LStep>>\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires AnnotatedBehaviorSatisfiesSpec(lb, rr.lspec)\n    ensures  BehaviorRefinesBehavior(lb.states, hb.states, GetIdentityRelation<State>())\n    ensures  AnnotatedBehaviorSatisfiesSpec(hb, GetCrossLevelSpec(rr))\n  {\n    var pos := lemma_FindFirstCrashingState(rr, lb.states, lb.trace);\n    var relation := GetIdentityRelation<State>();\n\n    if pos == |lb.states| {\n      var htrace := ConvertMapToSeq(|lb.trace|,\n                                    map i | 0 <= i < |lb.trace| :: LiftStepToCrossLevel(rr, lb.states[i], lb.states[i+1], lb.trace[i]));\n      hb := AnnotatedBehavior(lb.states, htrace);\n      var lh_map := ConvertMapToSeq(|lb.states|, map i | 0 <= i < |lb.states| :: RefinementRange(i, i));\n      assert BehaviorRefinesBehaviorUsingRefinementMap(lb.states, hb.states, relation, lh_map);\n    }\n    else {\n      var htrace := ConvertMapToSeq(pos, map i | 0 <= i < pos :: LiftStepToCrossLevel(rr, lb.states[i], lb.states[i+1], lb.trace[i]));\n      hb := AnnotatedBehavior(lb.states[..pos+1], htrace);\n      var lh_map := ConvertMapToSeq(|lb.states|,\n                                    map i | 0 <= i < |lb.states| :: if i <= pos then RefinementRange(i, i) else RefinementRange(pos, pos));\n      assert BehaviorRefinesBehaviorUsingRefinementMap(lb.states, hb.states, relation, lh_map);\n    }\n  }\n\n  lemma lemma_LiftBehaviorToHighLayer<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    cb:AnnotatedBehavior<State, CrossLevelStep<State, Actor, LStep>>\n    ) returns (\n    hb:AnnotatedBehavior<State, HStep>\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires AnnotatedBehaviorSatisfiesSpec(cb, GetCrossLevelSpec(rr))\n    requires forall i, actor :: 0 <= i < |cb.states| ==> var s := cb.states[i]; !rr.crashed(s) ==> !rr.phase1(s, actor) && !rr.phase2(s, actor)\n    ensures  hb.states == cb.states\n    ensures  AnnotatedBehaviorSatisfiesSpec(hb, rr.hspec)\n  {\n    var cspec := GetCrossLevelSpec(rr);\n    var htrace := [];\n    var n := 0;\n\n    assert |cb.states| == |cb.trace| + 1;\n\n    while n < |cb.trace|\n      invariant 0 <= n <= |cb.trace|\n      invariant |htrace| == n\n      invariant forall i :: 0 <= i < n ==> ActionTuple(cb.states[i], cb.states[i+1], htrace[i]) in rr.hspec.next\n    {\n      assert ActionTuple(cb.states[n], cb.states[n+1], cb.trace[n]) in cspec.next;\n      var cstep := cb.trace[n];\n      var states:seq<State>, trace:seq<LStep>, actor:Actor;\n\n      if cstep.Low? {\n        states := [cb.states[n], cb.states[n+1]];\n        trace := [cstep.step];\n        actor := rr.idmap(cstep.step);\n      }\n      else {\n        states := cstep.states;\n        trace := cstep.trace;\n        actor := cstep.actor;\n      }\n\n      assert RefinementViaReductionSpecModule.ActionSequencesLiftableConditions(rr, states, trace, actor);\n      var hstep :| ActionTuple(states[0], last(states), hstep) in rr.hspec.next;\n      htrace := htrace + [hstep];\n      n := n + 1;\n    }\n\n    hb := AnnotatedBehavior(cb.states, htrace);\n  }\n\n  lemma lemma_StateInCSpecBehaviorAmongAnnotatedReachables<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    b:AnnotatedBehavior<State, CrossLevelStep<State, Actor, LStep>>,\n    pos:int\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires AnnotatedBehaviorSatisfiesSpec(b, GetCrossLevelSpec(rr))\n    requires 0 <= pos < |b.states|\n    ensures  b.states[pos] in AnnotatedReachables(GetCrossLevelSpec(rr))\n    ensures  b.states[pos] in AnnotatedReachables(rr.lspec)\n  {\n    var cspec := GetCrossLevelSpec(rr);\n    var ar := AnnotatedReachablesPremium(cspec);\n\n    lemma_AnnotatedReachablesOfCrossLevelSpec(rr);\n\n    if pos > 0 {\n      var prev_pos := pos - 1;\n      assert ActionTuple(b.states[prev_pos], b.states[prev_pos+1], b.trace[prev_pos]) in cspec.next;\n      lemma_StateInCSpecBehaviorAmongAnnotatedReachables(rr, b, prev_pos);\n      assert b.states[prev_pos] in AnnotatedReachables(cspec);\n      assert b.states[prev_pos+1] in AnnotatedReachables(cspec);\n    }\n  }\n\n  ///////////////////////////////////////////\n  // GENERAL CRASH LEMMAS\n  ///////////////////////////////////////////\n\n  lemma lemma_StateNextSeqPreservesCrash<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    states:seq<State>,\n    trace:seq<LStep>\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires StateNextSeq(states, trace, rr.lspec.next)\n    requires rr.crashed(states[0])\n    ensures  last(states) == states[0]\n  {\n    if |states| > 1 {\n      var zero := 0;\n      assert ActionTuple(states[zero], states[zero+1], trace[zero]) in rr.lspec.next;\n      assert rr.crashed(states[zero+1]);\n      assert states[zero+1] == states[zero];\n\n      var states' := states[1..];\n      var trace' := trace[1..];\n\n      forall i {:trigger ActionTuple(states'[i], states'[i+1], trace'[i]) in rr.lspec.next} | 0 <= i < |trace'|\n        ensures ActionTuple(states'[i], states'[i+1], trace'[i]) in rr.lspec.next\n      {\n        var iplus := i+1;\n        assert states'[i] == states[iplus];\n        assert states'[i+1] == states[iplus+1];\n        assert trace'[i] == trace[iplus];\n        assert ActionTuple(states[iplus], states[iplus+1], trace[iplus]) in rr.lspec.next;\n      }\n      \n      lemma_StateNextSeqPreservesCrash(rr, states', trace');\n    }\n  }\n\n  lemma lemma_CSpecNextPreservesCrash<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    s:State,\n    s':State,\n    step:CrossLevelStep<State, Actor, LStep>\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires ActionTuple(s, s', step) in GetCrossLevelSpec(rr).next\n    requires rr.crashed(s)\n    ensures  s' == s\n  {\n    if step.Reducible? {\n      lemma_StateNextSeqPreservesCrash(rr, step.states, step.trace);\n    }\n  }\n\n  lemma lemma_AllStatesFollowingCrashedStateSame<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    states:seq<State>,\n    trace:seq<LStep>,\n    pos:int\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires StateNextSeq(states, trace, rr.lspec.next)\n    requires 0 <= pos < |states|\n    requires rr.crashed(states[pos])\n    ensures  forall i :: pos <= i < |states| ==> states[i] == states[pos]\n    decreases |states|-pos\n  {\n    if pos < |states|-1 {\n      assert ActionTuple(states[pos], states[pos+1], trace[pos]) in rr.lspec.next;\n      assert rr.crashed(states[pos+1]);\n      assert states[pos+1] == states[pos];\n      lemma_AllStatesFollowingCrashedStateSame(rr, states, trace, pos+1);\n    }\n  }\n\n  lemma lemma_AllCSpecStatesFollowingCrashedStateSame<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    states:seq<State>,\n    trace:seq<CrossLevelStep<State, Actor, LStep>>,\n    pos:int\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires StateNextSeq(states, trace, GetCrossLevelSpec(rr).next)\n    requires 0 <= pos < |states|\n    requires rr.crashed(states[pos])\n    ensures  forall i :: pos <= i < |states| ==> states[i] == states[pos]\n    decreases |states|-pos\n  {\n    var cspec := GetCrossLevelSpec(rr);\n    if pos < |states|-1 {\n      lemma_CSpecNextPreservesCrash(rr, states[pos], states[pos+1], trace[pos]);\n      assert rr.crashed(states[pos+1]);\n      lemma_AllCSpecStatesFollowingCrashedStateSame(rr, states, trace, pos+1);\n    }\n  }\n\n  lemma lemma_CSpecNextPreservesNoncrashBackward<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    s:State,\n    s':State,\n    step:CrossLevelStep<State, Actor, LStep>\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires ActionTuple(s, s', step) in GetCrossLevelSpec(rr).next\n    requires !rr.crashed(s')\n    ensures  !rr.crashed(s)\n  {\n    if rr.crashed(s) {\n      lemma_CSpecNextPreservesCrash(rr, s, s', step);\n      assert false;\n    }\n  }\n\n  lemma lemma_IfStateNextSeqDoesntCrashNoStateDoes<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    states:seq<State>,\n    trace:seq<LStep>,\n    pos:int\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires StateNextSeq(states, trace, rr.lspec.next)\n    requires !rr.crashed(last(states))\n    requires 0 <= pos < |states|\n    ensures  !rr.crashed(states[pos])\n  {\n    if pos < |states|-1 {\n      var penult := |states|-2;\n      assert ActionTuple(states[penult], states[penult+1], trace[penult]) in rr.lspec.next;\n      assert !rr.crashed(states[penult]);\n      lemma_LastOfAllButLast(states);\n      lemma_IfStateNextSeqDoesntCrashNoStateDoes(rr, all_but_last(states), all_but_last(trace), pos);\n    }\n  }\n\n  ///////////////////////////////////////////\n  // CohenLamportReductionRequest\n  ///////////////////////////////////////////\n\n  function GetCohenLamportReductionIdmap<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>\n    ) : CrossLevelStep<State, Actor, LStep>->Actor\n  {\n    (s:CrossLevelStep<State, Actor, LStep>) => s.actor\n  }\n\n  function GetCohenLamportReductionRequest<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>\n    ) : CohenLamportReductionRequest<State, Actor, CrossLevelStep<State, Actor, LStep>>\n  {\n    CohenLamportReductionRequest(GetCrossLevelSpec(rr), rr.relation, GetCohenLamportReductionIdmap(rr), rr.phase1,\n                                 rr.phase2, rr.crashed)\n  }\n\n  /////////////////////////////////////////////////////////////////\n  // Proof that CohenLamportReductionRequest is valid\n  /////////////////////////////////////////////////////////////////\n\n  /////////////////////////\n  // UTILITY LEMMAS\n  /////////////////////////\n\n  predicate PhasesMatch<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    s1:State,\n    s2:State,\n    actor:Actor\n    )\n  {\n    && (rr.crashed(s1) <==> rr.crashed(s2))\n    && (rr.phase1(s1, actor) <==> rr.phase1(s2, actor))\n    && (rr.phase2(s1, actor) <==> rr.phase2(s2, actor))\n  }\n\n  lemma lemma_ReducibleStepStartsAndEndsOutOfPhase<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    s:State,\n    s':State,\n    step:CrossLevelStep<State, Actor, LStep>\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires CrossLevelNext(rr, s, s', step)\n    requires step.Reducible?\n    ensures  !rr.phase1(s, step.actor)\n    ensures  !rr.phase2(s, step.actor)\n    ensures  !rr.crashed(s') ==> !rr.phase1(s', step.actor) && !rr.phase2(s', step.actor)\n  {\n  }\n\n  lemma lemma_StateNextSeqByOtherActorCausesPhasesMatch<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    clrr:CohenLamportReductionRequest<State, Actor, CrossLevelStep<State, Actor, LStep>>,\n    states:seq<State>,\n    trace:seq<LStep>,\n    pos:int,\n    step_actor:Actor,\n    other_actor:Actor\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires StateNextSeq(states, trace, rr.lspec.next)\n    requires forall step :: step in trace ==> rr.idmap(step) == step_actor\n    requires step_actor != other_actor\n    requires 0 <= pos < |states|\n    requires !rr.crashed(states[pos])\n    ensures  PhasesMatch(rr, states[0], states[pos], other_actor)\n  {\n    if pos > 0 {\n      var prev := pos-1;\n      assert ActionTuple(states[prev], states[prev+1], trace[prev]) in rr.lspec.next;\n      assert rr.idmap(trace[prev]) == step_actor;\n      assert PhasesMatch(rr, states[prev], states[prev+1], other_actor);\n      lemma_StateNextSeqByOtherActorCausesPhasesMatch(rr, clrr, states, trace, pos-1, step_actor, other_actor);\n    }\n  }\n\n  /////////////////////////////////////\n  // PhaseUnaffectedByOtherActors\n  /////////////////////////////////////\n\n  lemma lemma_DemonstratePhaseUnaffectedByOtherActors<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    clrr:CohenLamportReductionRequest<State, Actor, CrossLevelStep<State, Actor, LStep>>,\n    s:State,\n    s':State,\n    step:CrossLevelStep<State, Actor, LStep>,\n    actor:Actor\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires clrr == GetCohenLamportReductionRequest(rr)\n    requires ActionTuple(s, s', step) in clrr.spec.next\n    requires clrr.idmap(step) != actor\n    ensures  clrr.phase1(s, actor) <==> clrr.phase1(s', actor)\n    ensures  clrr.phase2(s, actor) <==> clrr.phase2(s', actor)\n  {\n    if step.Low? {\n      return;\n    }\n\n    var pos := 0;\n    while pos < |step.trace|\n      invariant 0 <= pos <= |step.trace|\n      invariant clrr.phase1(s, actor) <==> clrr.phase1(step.states[pos], actor)\n      invariant clrr.phase2(s, actor) <==> clrr.phase2(step.states[pos], actor)\n    {\n      assert ActionTuple(step.states[pos], step.states[pos+1], step.trace[pos]) in rr.lspec.next;\n      pos := pos + 1;\n    }\n  }\n\n  lemma lemma_PhaseUnaffectedByOtherActors<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    clrr:CohenLamportReductionRequest<State, Actor, CrossLevelStep<State, Actor, LStep>>\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires clrr == GetCohenLamportReductionRequest(rr)\n    ensures  CohenLamportReductionSpecModule.PhaseUnaffectedByOtherActors(clrr)\n  {\n    forall s, s', step, actor | ActionTuple(s, s', step) in clrr.spec.next && clrr.idmap(step) != actor\n      ensures clrr.phase1(s, actor) <==> clrr.phase1(s', actor)\n    {\n      lemma_DemonstratePhaseUnaffectedByOtherActors(rr, clrr, s, s', step, actor);\n    }\n\n    forall s, s', step, actor | ActionTuple(s, s', step) in clrr.spec.next && clrr.idmap(step) != actor\n      ensures clrr.phase2(s, actor) <==> clrr.phase2(s', actor)\n    {\n      lemma_DemonstratePhaseUnaffectedByOtherActors(rr, clrr, s, s', step, actor);\n    }\n  }\n\n  /////////////////////////////////////\n  // ActionSequencesLiftable\n  /////////////////////////////////////\n\n  lemma lemma_DemonstrateActionSequencesLiftable<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    clrr:CohenLamportReductionRequest<State, Actor, CrossLevelStep<State, Actor, LStep>>,\n    states:seq<State>,\n    trace:seq<CrossLevelStep<State, Actor, LStep>>,\n    actor:Actor\n    ) returns (\n    hstep:CrossLevelStep<State, Actor, LStep>\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires clrr == GetCohenLamportReductionRequest(rr)\n    requires StateNextSeq(states, trace, clrr.spec.next)\n    requires forall step :: step in trace ==> clrr.idmap(step) == actor\n    requires |states| > 1\n    requires !clrr.crashed(states[0])\n    requires !clrr.phase1(states[0], actor)\n    requires !clrr.phase2(states[0], actor)\n    requires var s := last(states); !clrr.crashed(s) ==> !clrr.phase1(s, actor) && !clrr.phase2(s, actor)\n    requires forall i :: 0 < i < |trace| ==> clrr.phase1(states[i], actor) || clrr.phase2(states[i], actor)\n    ensures  ActionTuple(states[0], last(states), hstep) in clrr.spec.next\n    ensures  clrr.idmap(hstep) == actor\n  {\n    var zero := 0;\n    assert ActionTuple(states[zero], states[zero+1], trace[zero]) in clrr.spec.next;\n\n    if |trace| == 1 {\n      hstep := trace[0];\n      return;\n    }\n\n    if rr.crashed(states[1]) {\n      lemma_AllCSpecStatesFollowingCrashedStateSame(rr, states, trace, 1);\n      assert states[1] == last(states);\n      hstep := trace[0];\n      return;\n    }\n\n    forall i | 0 <= i < |trace|\n      ensures  trace[i].Low?\n      ensures  rr.idmap(trace[i].step) == actor\n      ensures  ActionTuple(states[i], states[i+1], trace[i].step) in rr.lspec.next\n      ensures  !rr.crashed(states[i])\n    {\n      assert ActionTuple(states[i], states[i+1], trace[i]) in clrr.spec.next;\n      assert clrr.idmap(trace[i]) == actor;\n      assert trace[i].actor == actor;\n      assert !rr.crashed(states[i]);\n      if trace[i].Reducible? {\n        assert CrossLevelNext(rr, states[i], states[i+1], trace[i]);\n        assert && ValidReducibleCrossLevelStep(rr, trace[i].states, trace[i].trace, trace[i].actor)\n               && trace[i].states[0] == states[i]\n               && last(trace[i].states) == states[i+1];\n        if i == 0 {\n          var iplus := i+1;\n          assert 0 < iplus < |trace|;\n          var s' := states[iplus];\n          assert clrr.phase1(s', actor) || clrr.phase2(s', actor);\n          assert var s := last(trace[i].states); !rr.crashed(s) ==> !rr.phase1(s, actor) && !rr.phase2(s, actor);\n          assert last(trace[i].states) == states[iplus] == states[1];\n          assert !rr.crashed(states[1]);\n          assert false;\n        }\n        else {\n          assert 0 < i < |trace|;\n          var s := states[i];\n          assert clrr.phase1(s, actor) || clrr.phase2(s, actor);\n          assert var s := trace[i].states[0]; !rr.crashed(s) && !rr.phase1(s, actor) && !rr.phase2(s, actor);\n          assert false;\n        }\n      }  \n      assert trace[i].Low?;\n    }\n\n    var random_step:LStep :| true;\n    var htrace := MapSeqToSeq(trace, (s:CrossLevelStep<State, Actor, LStep>) => if s.Low? then s.step else random_step);\n    hstep := Reducible(actor, states, htrace);\n\n    forall step | step in htrace\n      ensures rr.idmap(step) == actor\n    {\n      var s :| s in trace && step == s.step;\n      assert clrr.idmap(s) == actor;\n      assert rr.idmap(step) == actor;\n    }\n    \n    assert ValidReducibleCrossLevelStep(rr, states, htrace, actor);\n  }\n\n  lemma lemma_ActionSequencesLiftable<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    clrr:CohenLamportReductionRequest<State, Actor, CrossLevelStep<State, Actor, LStep>>\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires clrr == GetCohenLamportReductionRequest(rr)\n    ensures  CohenLamportReductionSpecModule.ActionSequencesLiftable(clrr)\n  {\n    forall states, trace, actor\n      {:trigger CohenLamportReductionSpecModule.ActionSequencesLiftableConditions(clrr, states, trace, actor)}\n      | CohenLamportReductionSpecModule.ActionSequencesLiftableConditions(clrr, states, trace, actor)\n      ensures exists hstep :: ActionTuple(states[0], last(states), hstep) in clrr.spec.next && clrr.idmap(hstep) == actor\n    {\n      var hstep := lemma_DemonstrateActionSequencesLiftable(rr, clrr, states, trace, actor);\n    }\n  }\n\n  /////////////////////////////////////\n  // RightMoversCommute\n  /////////////////////////////////////\n\n  lemma lemma_DemonstrateRightMoverCommutesCaseOneStep<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    clrr:CohenLamportReductionRequest<State, Actor, CrossLevelStep<State, Actor, LStep>>,\n    initial_state:State,\n    state_after_right_mover:State,\n    state_after_both_steps:State,\n    right_mover:LStep,\n    other_step:LStep\n    ) returns (\n    new_middle_state:State,\n    other_step':LStep,\n    right_mover':LStep\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires clrr == GetCohenLamportReductionRequest(rr)\n    requires initial_state in AnnotatedReachables(rr.lspec)\n    requires ActionTuple(initial_state, state_after_right_mover, right_mover) in rr.lspec.next\n    requires ActionTuple(state_after_right_mover, state_after_both_steps, other_step) in rr.lspec.next\n    requires rr.idmap(right_mover) != rr.idmap(other_step)\n    requires rr.phase1(state_after_right_mover, rr.idmap(right_mover))\n    requires !rr.crashed(state_after_both_steps)\n\n    ensures  ActionTuple(initial_state, new_middle_state, other_step') in rr.lspec.next\n    ensures  ActionTuple(new_middle_state, state_after_both_steps, right_mover') in rr.lspec.next\n    ensures  rr.idmap(other_step') == rr.idmap(other_step)\n    ensures  rr.idmap(right_mover') == rr.idmap(right_mover)\n    ensures  PhasesMatch(rr, initial_state, state_after_right_mover, rr.idmap(other_step))\n    ensures  PhasesMatch(rr, new_middle_state, state_after_both_steps, rr.idmap(other_step))\n    ensures  PhasesMatch(rr, initial_state, new_middle_state, rr.idmap(right_mover))\n    ensures  PhasesMatch(rr, state_after_right_mover, state_after_both_steps, rr.idmap(right_mover))\n  {\n    assert RefinementViaReductionSpecModule.RightMoversCommuteConditions(rr, initial_state, state_after_right_mover, state_after_both_steps,\n                                                                         right_mover, other_step);\n    new_middle_state, other_step', right_mover' :|\n      && ActionTuple(initial_state, new_middle_state, other_step') in rr.lspec.next\n      && ActionTuple(new_middle_state, state_after_both_steps, right_mover') in rr.lspec.next\n      && rr.idmap(other_step') == rr.idmap(other_step)\n      && rr.idmap(right_mover') == rr.idmap(right_mover);\n  }\n\n  lemma lemma_DemonstrateRightMoverCommutesCaseMultipleSteps<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    clrr:CohenLamportReductionRequest<State, Actor, CrossLevelStep<State, Actor, LStep>>,\n    initial_state:State,\n    state_after_right_mover:State,\n    state_after_both_steps:State,\n    right_mover:LStep,\n    other_states:seq<State>,\n    other_steps:seq<LStep>,\n    other_actor:Actor\n    ) returns (\n    new_middle_state:State,\n    other_states':seq<State>,\n    other_steps':seq<LStep>,\n    right_mover':LStep\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires clrr == GetCohenLamportReductionRequest(rr)\n    requires initial_state in AnnotatedReachables(rr.lspec)\n    requires ActionTuple(initial_state, state_after_right_mover, right_mover) in rr.lspec.next\n    requires StateNextSeq(other_states, other_steps, rr.lspec.next)\n    requires forall step :: step in other_steps ==> rr.idmap(step) == other_actor\n    requires other_states[0] == state_after_right_mover\n    requires last(other_states) == state_after_both_steps\n    requires rr.idmap(right_mover) != other_actor\n    requires rr.phase1(state_after_right_mover, rr.idmap(right_mover))\n    requires !rr.crashed(state_after_both_steps)\n\n    ensures  StateNextSeq(other_states', other_steps', rr.lspec.next)\n    ensures  other_states'[0] == initial_state\n    ensures  last(other_states') == new_middle_state\n    ensures  forall step :: step in other_steps' ==> rr.idmap(step) == other_actor\n    ensures  ActionTuple(new_middle_state, state_after_both_steps, right_mover') in rr.lspec.next\n    ensures  rr.idmap(right_mover') == rr.idmap(right_mover)\n    ensures  PhasesMatch(rr, initial_state, new_middle_state, rr.idmap(right_mover))\n    ensures  PhasesMatch(rr, state_after_right_mover, state_after_both_steps, rr.idmap(right_mover))\n    ensures  |other_states'| == |other_states|\n    ensures  forall i :: 0 <= i < |other_states| ==> PhasesMatch(rr, other_states[i], other_states'[i], other_actor)\n  {\n    if |other_steps| == 0 {\n      new_middle_state := initial_state;\n      other_states' := [initial_state];\n      other_steps' := [];\n      right_mover' := right_mover;\n      return;\n    }\n\n    var zero := 0;\n    assert ActionTuple(other_states[zero], other_states[zero+1], other_steps[zero]) in rr.lspec.next;\n    lemma_IfStateNextSeqDoesntCrashNoStateDoes(rr, other_states, other_steps, zero+1);\n    var new_middle_state_mid, other_step_mid, right_mover_mid :=\n      lemma_DemonstrateRightMoverCommutesCaseOneStep(\n        rr, clrr, initial_state, state_after_right_mover, other_states[zero+1], right_mover, other_steps[zero]);\n\n    lemma_NextMaintainsAnnotatedReachables(initial_state, new_middle_state_mid, other_step_mid, rr.lspec);\n\n    lemma_ReduceStateNextSeqLeft(other_states, other_steps, rr.lspec.next);\n    var other_states_next, other_steps_next;\n    lemma_LastOfDropIsLast(other_states, 1);\n\n    forall step | step in other_steps[1..]\n      ensures rr.idmap(step) == other_actor\n    {\n      assert step in other_steps;\n    }\n\n    new_middle_state, other_states_next, other_steps_next, right_mover' :=\n      lemma_DemonstrateRightMoverCommutesCaseMultipleSteps(\n        rr, clrr, new_middle_state_mid, other_states[zero+1], state_after_both_steps, right_mover_mid,\n        other_states[1..], other_steps[1..], other_actor);\n\n    other_states' := [initial_state] + other_states_next;\n    other_steps' := [other_step_mid] + other_steps_next;\n    lemma_ExtendStateNextSeqLeft(other_states_next, other_steps_next, rr.lspec.next, initial_state, other_step_mid);\n    lemma_LastOfConcatenationIsLastOfLatter([initial_state], other_states_next);\n\n    forall i | 0 <= i < |other_states|\n      ensures PhasesMatch(rr, other_states[i], other_states'[i], other_actor)\n    {\n      if i == 0 {\n        assert other_states[i] == state_after_right_mover;\n        assert other_states'[i] == initial_state;\n        assert PhasesMatch(rr, other_states[i], other_states'[i], other_actor);\n      }\n      else {\n        var iminus := i-1;\n        lemma_IndexIntoConcatenation([initial_state], other_states_next, i);\n        assert other_states'[i] == other_states_next[i-1];\n        calc {\n          other_states[i];\n            { assert i == 1+(i-1); }\n          other_states[1+(i-1)];\n            { lemma_IndexIntoDrop(other_states, 1, i-1); }\n          other_states[1..][i-1];\n        }\n        assert PhasesMatch(rr, other_states_next[iminus], other_states[1..][iminus], other_actor);\n      }\n    }\n\n    forall step | step in other_steps'\n      ensures rr.idmap(step) == other_actor\n    {\n      if step in other_steps_next {\n        assert rr.idmap(step) == other_actor;\n      }\n      else {\n        assert step == other_step_mid;\n      }\n    }\n  }\n\n  lemma lemma_DemonstrateRightMoverCommutesCaseLow<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    clrr:CohenLamportReductionRequest<State, Actor, CrossLevelStep<State, Actor, LStep>>,\n    initial_state:State,\n    state_after_right_mover:State,\n    state_after_both_steps:State,\n    right_mover:CrossLevelStep<State, Actor, LStep>,\n    other_step:CrossLevelStep<State, Actor, LStep>\n    ) returns (\n    new_middle_state:State,\n    other_step':CrossLevelStep<State, Actor, LStep>,\n    right_mover':CrossLevelStep<State, Actor, LStep>\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires clrr == GetCohenLamportReductionRequest(rr)\n    requires initial_state in AnnotatedReachables(rr.lspec)\n    requires ActionTuple(initial_state, state_after_right_mover, right_mover) in clrr.spec.next\n    requires ActionTuple(state_after_right_mover, state_after_both_steps, other_step) in clrr.spec.next\n    requires clrr.idmap(right_mover) != clrr.idmap(other_step)\n    requires clrr.phase1(state_after_right_mover, clrr.idmap(right_mover))\n    requires !clrr.crashed(state_after_both_steps)\n    requires right_mover.Low?\n    requires other_step.Low?\n\n    ensures  ActionTuple(initial_state, new_middle_state, other_step') in clrr.spec.next\n    ensures  ActionTuple(new_middle_state, state_after_both_steps, right_mover') in clrr.spec.next\n    ensures  clrr.idmap(other_step') == clrr.idmap(other_step)\n    ensures  clrr.idmap(right_mover') == clrr.idmap(right_mover)\n  {\n    var other_step_single, right_mover_single;\n    new_middle_state, other_step_single, right_mover_single :=\n      lemma_DemonstrateRightMoverCommutesCaseOneStep(\n        rr, clrr, initial_state, state_after_right_mover, state_after_both_steps, right_mover.step, other_step.step);\n    other_step' := Low(rr.idmap(other_step_single), other_step_single);\n    right_mover' := Low(rr.idmap(right_mover_single), right_mover_single);\n  }\n\n  lemma lemma_DemonstrateRightMoverCommutesCaseReducible<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    clrr:CohenLamportReductionRequest<State, Actor, CrossLevelStep<State, Actor, LStep>>,\n    initial_state:State,\n    state_after_right_mover:State,\n    state_after_both_steps:State,\n    right_mover:CrossLevelStep<State, Actor, LStep>,\n    other_step:CrossLevelStep<State, Actor, LStep>\n    ) returns (\n    new_middle_state:State,\n    other_step':CrossLevelStep<State, Actor, LStep>,\n    right_mover':CrossLevelStep<State, Actor, LStep>\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires clrr == GetCohenLamportReductionRequest(rr)\n    requires initial_state in AnnotatedReachables(rr.lspec)\n    requires ActionTuple(initial_state, state_after_right_mover, right_mover) in clrr.spec.next\n    requires ActionTuple(state_after_right_mover, state_after_both_steps, other_step) in clrr.spec.next\n    requires clrr.idmap(right_mover) != clrr.idmap(other_step)\n    requires clrr.phase1(state_after_right_mover, clrr.idmap(right_mover))\n    requires !clrr.crashed(state_after_both_steps)\n    requires right_mover.Low?\n    requires other_step.Reducible?\n\n    ensures  ActionTuple(initial_state, new_middle_state, other_step') in clrr.spec.next\n    ensures  ActionTuple(new_middle_state, state_after_both_steps, right_mover') in clrr.spec.next\n    ensures  clrr.idmap(other_step') == clrr.idmap(other_step)\n    ensures  clrr.idmap(right_mover') == clrr.idmap(right_mover)\n  {\n    var other_states', other_steps', right_mover_single;\n    new_middle_state, other_states', other_steps', right_mover_single :=\n      lemma_DemonstrateRightMoverCommutesCaseMultipleSteps(\n        rr, clrr, initial_state, state_after_right_mover, state_after_both_steps, right_mover.step, other_step.states, other_step.trace,\n        other_step.actor);\n    other_step' := Reducible(other_step.actor, other_states', other_steps');\n    right_mover' := Low(rr.idmap(right_mover_single), right_mover_single);\n    assert ValidReducibleCrossLevelStep(rr, other_states', other_steps', other_step.actor);\n    assert CrossLevelNext(rr, initial_state, new_middle_state, other_step');\n    assert CrossLevelNext(rr, new_middle_state, state_after_both_steps, right_mover');\n  }\n\n  lemma lemma_DemonstrateRightMoverCommutes<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    clrr:CohenLamportReductionRequest<State, Actor, CrossLevelStep<State, Actor, LStep>>,\n    initial_state:State,\n    state_after_right_mover:State,\n    state_after_both_steps:State,\n    right_mover:CrossLevelStep<State, Actor, LStep>,\n    other_step:CrossLevelStep<State, Actor, LStep>\n    ) returns (\n    new_middle_state:State,\n    other_step':CrossLevelStep<State, Actor, LStep>,\n    right_mover':CrossLevelStep<State, Actor, LStep>\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires clrr == GetCohenLamportReductionRequest(rr)\n    requires initial_state in AnnotatedReachables(clrr.spec)\n    requires ActionTuple(initial_state, state_after_right_mover, right_mover) in clrr.spec.next\n    requires ActionTuple(state_after_right_mover, state_after_both_steps, other_step) in clrr.spec.next\n    requires clrr.idmap(right_mover) != clrr.idmap(other_step)\n    requires clrr.phase1(state_after_right_mover, clrr.idmap(right_mover))\n    requires !clrr.crashed(state_after_both_steps)\n\n    ensures  ActionTuple(initial_state, new_middle_state, other_step') in clrr.spec.next\n    ensures  ActionTuple(new_middle_state, state_after_both_steps, right_mover') in clrr.spec.next\n    ensures  clrr.idmap(other_step') == clrr.idmap(other_step)\n    ensures  clrr.idmap(right_mover') == clrr.idmap(right_mover)\n  {\n    lemma_AnnotatedReachablesOfCrossLevelSpec(rr);\n    assert initial_state in AnnotatedReachables(rr.lspec);\n    if right_mover.Reducible? {\n      lemma_ReducibleStepStartsAndEndsOutOfPhase(rr, initial_state, state_after_right_mover, right_mover);\n      assert false;\n    }\n    \n    if other_step.Low? {\n      new_middle_state, other_step', right_mover' := lemma_DemonstrateRightMoverCommutesCaseLow(\n        rr, clrr, initial_state, state_after_right_mover, state_after_both_steps, right_mover, other_step);\n    }\n    else {\n      new_middle_state, other_step', right_mover' := lemma_DemonstrateRightMoverCommutesCaseReducible(\n        rr, clrr, initial_state, state_after_right_mover, state_after_both_steps, right_mover, other_step);\n    }\n  }\n\n  lemma lemma_RightMoversCommute<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    clrr:CohenLamportReductionRequest<State, Actor, CrossLevelStep<State, Actor, LStep>>\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires clrr == GetCohenLamportReductionRequest(rr)\n    ensures  CohenLamportReductionSpecModule.RightMoversCommute(clrr)\n  {\n    forall initial_state, state_after_right_mover, state_after_both_steps, right_mover, other_step\n      {:trigger CohenLamportReductionSpecModule.RightMoversCommuteConditions(clrr, initial_state, state_after_right_mover,\n                                                                             state_after_both_steps, right_mover, other_step)}\n      | CohenLamportReductionSpecModule.RightMoversCommuteConditions(clrr, initial_state, state_after_right_mover,\n                                                                     state_after_both_steps, right_mover, other_step)\n      && initial_state in AnnotatedReachables(clrr.spec)\n      && ActionTuple(initial_state, state_after_right_mover, right_mover) in clrr.spec.next\n      && ActionTuple(state_after_right_mover, state_after_both_steps, other_step) in clrr.spec.next\n      && clrr.idmap(right_mover) != clrr.idmap(other_step)\n      && clrr.phase1(state_after_right_mover, clrr.idmap(right_mover))\n      && !clrr.crashed(state_after_both_steps)\n      ensures exists new_middle_state, other_step', right_mover' ::\n                && ActionTuple(initial_state, new_middle_state, other_step') in clrr.spec.next\n                && ActionTuple(new_middle_state, state_after_both_steps, right_mover') in clrr.spec.next\n                && clrr.idmap(other_step') == clrr.idmap(other_step)\n                && clrr.idmap(right_mover') == clrr.idmap(right_mover)\n    {\n      var new_middle_state, other_step', right_mover' :=\n        lemma_DemonstrateRightMoverCommutes(\n          rr, clrr, initial_state, state_after_right_mover, state_after_both_steps, right_mover, other_step);\n    }\n  }\n\n  /////////////////////////////////////\n  // LeftMoversCommute\n  /////////////////////////////////////\n\n  lemma lemma_DemonstrateLeftMoverCommutesCaseOneStep<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    clrr:CohenLamportReductionRequest<State, Actor, CrossLevelStep<State, Actor, LStep>>,\n    initial_state:State,\n    state_after_other_step:State,\n    state_after_both_steps:State,\n    other_step:LStep,\n    left_mover:LStep\n    ) returns (\n    new_middle_state:State,\n    left_mover':LStep,\n    other_step':LStep\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires clrr == GetCohenLamportReductionRequest(rr)\n    requires initial_state in AnnotatedReachables(rr.lspec)\n    requires ActionTuple(initial_state, state_after_other_step, other_step) in rr.lspec.next\n    requires ActionTuple(state_after_other_step, state_after_both_steps, left_mover) in rr.lspec.next\n    requires rr.idmap(other_step) != rr.idmap(left_mover)\n    requires rr.phase2(state_after_other_step, rr.idmap(left_mover))\n    requires !rr.crashed(state_after_both_steps)\n\n    ensures  ActionTuple(initial_state, new_middle_state, left_mover') in rr.lspec.next\n    ensures  ActionTuple(new_middle_state, state_after_both_steps, other_step') in rr.lspec.next\n    ensures  rr.idmap(left_mover') == rr.idmap(left_mover)\n    ensures  rr.idmap(other_step') == rr.idmap(other_step)\n    ensures  PhasesMatch(rr, initial_state, state_after_other_step, rr.idmap(left_mover))\n    ensures  PhasesMatch(rr, new_middle_state, state_after_both_steps, rr.idmap(left_mover))\n    ensures  PhasesMatch(rr, initial_state, new_middle_state, rr.idmap(other_step))\n    ensures  PhasesMatch(rr, state_after_other_step, state_after_both_steps, rr.idmap(other_step))\n  {\n    assert RefinementViaReductionSpecModule.LeftMoversCommuteConditions(rr, initial_state, state_after_other_step, state_after_both_steps,\n                                                                        other_step, left_mover);\n    new_middle_state, left_mover', other_step' :|\n      && ActionTuple(initial_state, new_middle_state, left_mover') in rr.lspec.next\n      && ActionTuple(new_middle_state, state_after_both_steps, other_step') in rr.lspec.next\n      && rr.idmap(left_mover') == rr.idmap(left_mover)\n      && rr.idmap(other_step') == rr.idmap(other_step);\n  }\n\n  lemma lemma_DemonstrateLeftMoverCommutesCaseMultipleSteps<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    clrr:CohenLamportReductionRequest<State, Actor, CrossLevelStep<State, Actor, LStep>>,\n    initial_state:State,\n    state_after_other_step:State,\n    state_after_both_steps:State,\n    other_states:seq<State>,\n    other_steps:seq<LStep>,\n    other_actor:Actor,\n    left_mover:LStep\n    ) returns (\n    new_middle_state:State,\n    left_mover':LStep,\n    other_states':seq<State>,\n    other_steps':seq<LStep>\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires clrr == GetCohenLamportReductionRequest(rr)\n    requires initial_state in AnnotatedReachables(rr.lspec)\n    requires StateNextSeq(other_states, other_steps, rr.lspec.next)\n    requires forall step :: step in other_steps ==> rr.idmap(step) == other_actor\n    requires other_states[0] == initial_state\n    requires last(other_states) == state_after_other_step\n    requires ActionTuple(state_after_other_step, state_after_both_steps, left_mover) in rr.lspec.next\n    requires rr.idmap(left_mover) != other_actor\n    requires rr.phase2(state_after_other_step, rr.idmap(left_mover))\n    requires !rr.crashed(state_after_both_steps)\n\n    ensures  ActionTuple(initial_state, new_middle_state, left_mover') in rr.lspec.next\n    ensures  StateNextSeq(other_states', other_steps', rr.lspec.next)\n    ensures  other_states'[0] == new_middle_state\n    ensures  last(other_states') == state_after_both_steps\n    ensures  forall step :: step in other_steps' ==> rr.idmap(step) == other_actor\n    ensures  rr.idmap(left_mover') == rr.idmap(left_mover)\n    ensures  PhasesMatch(rr, initial_state, state_after_other_step, rr.idmap(left_mover))\n    ensures  PhasesMatch(rr, new_middle_state, state_after_both_steps, rr.idmap(left_mover))\n    ensures  |other_states'| == |other_states|\n    ensures  forall i :: 0 <= i < |other_states| ==> PhasesMatch(rr, other_states[i], other_states'[i], other_actor)\n\n    decreases |other_states|\n  {\n    if |other_steps| == 0 {\n      new_middle_state := state_after_both_steps;\n      left_mover' := left_mover;\n      other_states' := [state_after_both_steps];\n      other_steps' := [];\n      return;\n    }\n\n    var penult := |other_states|-2;\n    assert ActionTuple(other_states[penult], other_states[penult+1], other_steps[penult]) in rr.lspec.next;\n    lemma_StateNextSeqMaintainsAnnotatedReachables(other_states, other_steps, rr.lspec);\n    assert other_states[penult] in other_states;\n    assert other_states[penult] in AnnotatedReachables(rr.lspec);\n\n    calc {\n      other_states[penult+1];\n        { assert penult+1 == |other_states|-1; }\n      last(other_states);\n      state_after_other_step;\n    }\n\n    var new_middle_state_mid, left_mover_mid, other_step_mid :=\n      lemma_DemonstrateLeftMoverCommutesCaseOneStep(\n        rr, clrr, other_states[penult], other_states[penult+1], state_after_both_steps, other_steps[penult], left_mover);\n\n    lemma_ReduceStateNextSeqRight(other_states, other_steps, rr.lspec.next);\n    forall step | step in all_but_last(other_steps)\n      ensures rr.idmap(step) == other_actor\n    {\n      assert step in other_steps;\n    }\n    lemma_LastOfAllButLast(other_states);\n\n    var other_states_next, other_steps_next;\n    new_middle_state, left_mover', other_states_next, other_steps_next :=\n      lemma_DemonstrateLeftMoverCommutesCaseMultipleSteps(\n        rr, clrr, initial_state, other_states[penult], new_middle_state_mid, all_but_last(other_states), all_but_last(other_steps),\n        other_actor, left_mover_mid);\n    other_states' := other_states_next + [state_after_both_steps];\n    other_steps' := other_steps_next + [other_step_mid];\n\n    lemma_ExtendStateNextSeqRight(other_states_next, other_steps_next, rr.lspec.next, state_after_both_steps, other_step_mid);\n    lemma_IndexIntoConcatenation(other_states_next, [state_after_both_steps], |other_states'|-1);\n\n    forall step | step in other_steps'\n      ensures rr.idmap(step) == other_actor\n    {\n      if step in other_steps_next {\n        assert rr.idmap(step) == other_actor;\n      }\n      else {\n        assert step == other_step_mid;\n      }\n    }\n\n    forall i | 0 <= i < |other_states|\n      ensures PhasesMatch(rr, other_states[i], other_states'[i], other_actor)\n    {\n      if i < |other_states_next| {\n        assert other_states[i] == all_but_last(other_states)[i];\n        assert other_states'[i] == other_states_next[i];\n        assert PhasesMatch(rr, all_but_last(other_states)[i], other_states_next[i], other_actor);\n      }\n      else {\n        assert |other_states_next| == |all_but_last(other_states)| == |other_states|-1;\n        assert i == |other_states|-1;\n        assert other_states[i] == last(other_states) == state_after_other_step;\n        assert other_states'[i] == state_after_both_steps;\n        assert PhasesMatch(rr, state_after_other_step, state_after_both_steps, other_actor);\n      }\n    }\n  }\n\n  lemma lemma_DemonstrateLeftMoverCommutesCaseLow<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    clrr:CohenLamportReductionRequest<State, Actor, CrossLevelStep<State, Actor, LStep>>,\n    initial_state:State,\n    state_after_other_step:State,\n    state_after_both_steps:State,\n    other_step:CrossLevelStep<State, Actor, LStep>,\n    left_mover:CrossLevelStep<State, Actor, LStep>\n    ) returns (\n    new_middle_state:State,\n    left_mover':CrossLevelStep<State, Actor, LStep>,\n    other_step':CrossLevelStep<State, Actor, LStep>\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires clrr == GetCohenLamportReductionRequest(rr)\n    requires initial_state in AnnotatedReachables(rr.lspec)\n    requires ActionTuple(initial_state, state_after_other_step, other_step) in clrr.spec.next\n    requires ActionTuple(state_after_other_step, state_after_both_steps, left_mover) in clrr.spec.next\n    requires clrr.idmap(other_step) != clrr.idmap(left_mover)\n    requires clrr.phase2(state_after_other_step, clrr.idmap(left_mover))\n    requires !clrr.crashed(state_after_both_steps)\n    requires other_step.Low?\n    requires left_mover.Low?\n\n    ensures  ActionTuple(initial_state, new_middle_state, left_mover') in clrr.spec.next\n    ensures  ActionTuple(new_middle_state, state_after_both_steps, other_step') in clrr.spec.next\n    ensures  clrr.idmap(left_mover') == clrr.idmap(left_mover)\n    ensures  clrr.idmap(other_step') == clrr.idmap(other_step)\n  {\n    var left_mover_single, other_step_single;\n    new_middle_state, left_mover_single, other_step_single :=\n      lemma_DemonstrateLeftMoverCommutesCaseOneStep(\n        rr, clrr, initial_state, state_after_other_step, state_after_both_steps, other_step.step, left_mover.step);\n    left_mover' := Low(rr.idmap(left_mover_single), left_mover_single);\n    other_step' := Low(rr.idmap(other_step_single), other_step_single);\n  }\n\n  lemma lemma_DemonstrateLeftMoverCommutesCaseReducible<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    clrr:CohenLamportReductionRequest<State, Actor, CrossLevelStep<State, Actor, LStep>>,\n    initial_state:State,\n    state_after_other_step:State,\n    state_after_both_steps:State,\n    other_step:CrossLevelStep<State, Actor, LStep>,\n    left_mover:CrossLevelStep<State, Actor, LStep>\n    ) returns (\n    new_middle_state:State,\n    left_mover':CrossLevelStep<State, Actor, LStep>,\n    other_step':CrossLevelStep<State, Actor, LStep>\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires clrr == GetCohenLamportReductionRequest(rr)\n    requires initial_state in AnnotatedReachables(rr.lspec)\n    requires ActionTuple(initial_state, state_after_other_step, other_step) in clrr.spec.next\n    requires ActionTuple(state_after_other_step, state_after_both_steps, left_mover) in clrr.spec.next\n    requires clrr.idmap(other_step) != clrr.idmap(left_mover)\n    requires clrr.phase2(state_after_other_step, clrr.idmap(left_mover))\n    requires !clrr.crashed(state_after_both_steps)\n    requires other_step.Reducible?\n    requires left_mover.Low?\n\n    ensures  ActionTuple(initial_state, new_middle_state, left_mover') in clrr.spec.next\n    ensures  ActionTuple(new_middle_state, state_after_both_steps, other_step') in clrr.spec.next\n    ensures  clrr.idmap(left_mover') == clrr.idmap(left_mover)\n    ensures  clrr.idmap(other_step') == clrr.idmap(other_step)\n  {\n    var left_mover_single, other_states', other_steps';\n    new_middle_state, left_mover_single, other_states', other_steps' :=\n      lemma_DemonstrateLeftMoverCommutesCaseMultipleSteps(\n        rr, clrr, initial_state, state_after_other_step, state_after_both_steps, other_step.states, other_step.trace,\n        other_step.actor, left_mover.step);\n    left_mover' := Low(rr.idmap(left_mover_single), left_mover_single);\n    other_step' := Reducible(other_step.actor, other_states', other_steps');\n    assert ValidReducibleCrossLevelStep(rr, other_states', other_steps', other_step.actor);\n    assert CrossLevelNext(rr, new_middle_state, state_after_both_steps, other_step');\n    assert CrossLevelNext(rr, initial_state, new_middle_state, left_mover');\n  }\n\n  lemma lemma_DemonstrateLeftMoverCommutes<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    clrr:CohenLamportReductionRequest<State, Actor, CrossLevelStep<State, Actor, LStep>>,\n    initial_state:State,\n    state_after_other_step:State,\n    state_after_both_steps:State,\n    other_step:CrossLevelStep<State, Actor, LStep>,\n    left_mover:CrossLevelStep<State, Actor, LStep>\n    ) returns (\n    new_middle_state:State,\n    left_mover':CrossLevelStep<State, Actor, LStep>,\n    other_step':CrossLevelStep<State, Actor, LStep>\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires clrr == GetCohenLamportReductionRequest(rr)\n    requires initial_state in AnnotatedReachables(clrr.spec)\n    requires ActionTuple(initial_state, state_after_other_step, other_step) in clrr.spec.next\n    requires ActionTuple(state_after_other_step, state_after_both_steps, left_mover) in clrr.spec.next\n    requires clrr.idmap(other_step) != clrr.idmap(left_mover)\n    requires clrr.phase2(state_after_other_step, clrr.idmap(left_mover))\n    requires !clrr.crashed(state_after_both_steps)\n\n    ensures  ActionTuple(initial_state, new_middle_state, left_mover') in clrr.spec.next\n    ensures  ActionTuple(new_middle_state, state_after_both_steps, other_step') in clrr.spec.next\n    ensures  clrr.idmap(left_mover') == clrr.idmap(left_mover)\n    ensures  clrr.idmap(other_step') == clrr.idmap(other_step)\n  {\n    lemma_AnnotatedReachablesOfCrossLevelSpec(rr);\n    assert initial_state in AnnotatedReachables(rr.lspec);\n    if left_mover.Reducible? {\n      lemma_ReducibleStepStartsAndEndsOutOfPhase(rr, state_after_other_step, state_after_both_steps, left_mover);\n      assert false;\n    }\n\n    if other_step.Low? {\n      new_middle_state, left_mover', other_step' :=\n        lemma_DemonstrateLeftMoverCommutesCaseLow(\n          rr, clrr, initial_state, state_after_other_step, state_after_both_steps, other_step, left_mover);\n    }\n    else {\n      new_middle_state, left_mover', other_step' :=\n        lemma_DemonstrateLeftMoverCommutesCaseReducible(\n          rr, clrr, initial_state, state_after_other_step, state_after_both_steps, other_step, left_mover);\n    }\n  }\n\n  lemma lemma_LeftMoversCommute<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    clrr:CohenLamportReductionRequest<State, Actor, CrossLevelStep<State, Actor, LStep>>\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires clrr == GetCohenLamportReductionRequest(rr)\n    ensures  CohenLamportReductionSpecModule.LeftMoversCommute(clrr)\n  {\n    forall initial_state, state_after_other_step, state_after_both_steps, other_step, left_mover\n      {:trigger CohenLamportReductionSpecModule.LeftMoversCommuteConditions(clrr, initial_state, state_after_other_step,\n                                                                            state_after_both_steps, other_step, left_mover)}\n      | CohenLamportReductionSpecModule.LeftMoversCommuteConditions(clrr, initial_state, state_after_other_step,\n                                                                    state_after_both_steps, other_step, left_mover)\n      && initial_state in AnnotatedReachables(clrr.spec)\n      && ActionTuple(initial_state, state_after_other_step, other_step) in clrr.spec.next\n      && ActionTuple(state_after_other_step, state_after_both_steps, left_mover) in clrr.spec.next\n      && clrr.idmap(other_step) != clrr.idmap(left_mover)\n      && clrr.phase2(state_after_other_step, clrr.idmap(left_mover))\n      && !clrr.crashed(state_after_both_steps)\n      ensures exists new_middle_state, left_mover', other_step' ::\n                && ActionTuple(initial_state, new_middle_state, left_mover') in clrr.spec.next\n                && ActionTuple(new_middle_state, state_after_both_steps, other_step') in clrr.spec.next\n                && clrr.idmap(left_mover') == clrr.idmap(left_mover)\n                && clrr.idmap(other_step') == clrr.idmap(other_step)\n    {\n      var new_middle_state, left_mover', other_step' :=\n        lemma_DemonstrateLeftMoverCommutes(\n          rr, clrr, initial_state, state_after_other_step, state_after_both_steps, other_step, left_mover);\n    }\n  }\n\n  ////////////////////////////////////////\n  // LeftMoversAlwaysEnabled\n  ////////////////////////////////////////\n\n  lemma lemma_DemonstrateLeftMoversAlwaysEnabled<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    clrr:CohenLamportReductionRequest<State, Actor, CrossLevelStep<State, Actor, LStep>>,\n    s:State,\n    actor:Actor\n    ) returns (\n    states:seq<State>,\n    trace:seq<CrossLevelStep<State, Actor, LStep>>\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires clrr == GetCohenLamportReductionRequest(rr)\n    requires s in AnnotatedReachables(clrr.spec)\n    requires clrr.phase2(s, actor)\n    requires !clrr.crashed(s)\n    ensures  StateNextSeq(states, trace, clrr.spec.next)\n    ensures  states[0] == s\n    ensures  clrr.crashed(last(states)) || !clrr.phase2(last(states), actor)\n    ensures  forall i :: 0 <= i < |states|-1 ==> clrr.phase2(states[i], actor)\n    ensures  forall step :: step in trace ==> clrr.idmap(step) == actor\n  {\n    lemma_AnnotatedReachablesOfCrossLevelSpec(rr);\n    assert RefinementViaReductionSpecModule.LeftMoversAlwaysEnabledConditions(rr, s, actor);\n    var states_mid, trace_mid :|\n      && StateNextSeq(states_mid, trace_mid, rr.lspec.next)\n      && states_mid[0] == s\n      && (rr.crashed(last(states_mid)) || !rr.phase2(last(states_mid), actor))\n      && (forall i :: 0 <= i < |states_mid|-1 ==> rr.phase2(states_mid[i], actor))\n      && (forall step :: step in trace_mid ==> rr.idmap(step) == actor);\n\n    var pos := lemma_FindFirstCrashingState(rr, states_mid, trace_mid);\n    if pos < |states_mid| {\n      states := states_mid[..pos+1];\n      trace := MapSeqToSeq(trace_mid[..pos], x => Low(rr.idmap(x), x));\n      assert last(states) == states_mid[pos] == last(states_mid);\n    }\n    else {\n      states := states_mid;\n      trace := MapSeqToSeq(trace_mid, x => Low(rr.idmap(x), x));\n    }\n\n    assert forall i :: 0 <= i < |trace| ==> trace[i] == Low(rr.idmap(trace_mid[i]), trace_mid[i]);\n    assert forall i :: 0 <= i < |trace| ==> !rr.crashed(states[i]);\n    assert last(states) == last(states_mid);\n\n    forall i {:trigger ActionTuple(states[i], states[i+1], trace[i]) in clrr.spec.next} | 0 <= i < |trace|\n      ensures ActionTuple(states[i], states[i+1], trace[i]) in clrr.spec.next\n    {\n      assert ActionTuple(states[i], states[i+1], trace_mid[i]) in rr.lspec.next;\n      assert trace[i].Low?;\n      assert !rr.crashed(states[i]);\n      assert trace[i].actor == rr.idmap(trace[i].step);\n      assert CrossLevelNext(rr, states[i], states[i+1], trace[i]);\n    }\n  }\n\n  lemma lemma_LeftMoversAlwaysEnabled<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    clrr:CohenLamportReductionRequest<State, Actor, CrossLevelStep<State, Actor, LStep>>\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires clrr == GetCohenLamportReductionRequest(rr)\n    ensures  CohenLamportReductionSpecModule.LeftMoversAlwaysEnabled(clrr)\n  {\n    forall s, actor\n      {:trigger CohenLamportReductionSpecModule.LeftMoversAlwaysEnabledConditions(clrr, s, actor)}\n      | CohenLamportReductionSpecModule.LeftMoversAlwaysEnabledConditions(clrr, s, actor)\n      ensures exists states, trace ::\n                && StateNextSeq(states, trace, clrr.spec.next)\n                && states[0] == s\n                && (clrr.crashed(last(states)) || !clrr.phase2(last(states), actor))\n                && (forall i :: 0 <= i < |states|-1 ==> clrr.phase2(states[i], actor))\n                && (forall step :: step in trace ==> clrr.idmap(step) == actor)\n    {\n      var states, trace := lemma_DemonstrateLeftMoversAlwaysEnabled(rr, clrr, s, actor);\n    }\n  }\n\n  ////////////////////////////////////////\n  // LeftMoversEnabledBeforeCrash\n  ////////////////////////////////////////\n\n  lemma lemma_MoveMultipleLeftMoversAcrossMultipleSteps<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    clrr:CohenLamportReductionRequest<State, Actor, CrossLevelStep<State, Actor, LStep>>,\n    initial_state:State,\n    state_after_other_step:State,\n    state_after_both_steps:State,\n    other_states:seq<State>,\n    other_steps:seq<LStep>,\n    other_actor:Actor,\n    left_mover_states:seq<State>,\n    left_mover_steps:seq<LStep>,\n    left_mover_actor:Actor\n    ) returns (\n    new_middle_state:State,\n    left_mover_states':seq<State>,\n    left_mover_steps':seq<LStep>,\n    other_states':seq<State>,\n    other_steps':seq<LStep>\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires clrr == GetCohenLamportReductionRequest(rr)\n    requires initial_state in AnnotatedReachables(rr.lspec)\n    requires StateNextSeq(other_states, other_steps, rr.lspec.next)\n    requires forall step :: step in other_steps ==> rr.idmap(step) == other_actor\n    requires other_states[0] == initial_state\n    requires last(other_states) == state_after_other_step\n    requires StateNextSeq(left_mover_states, left_mover_steps, rr.lspec.next)\n    requires left_mover_states[0] == state_after_other_step\n    requires last(left_mover_states) == state_after_both_steps\n    requires forall step :: step in left_mover_steps ==> rr.idmap(step) == left_mover_actor\n    requires forall i :: 0 <= i < |left_mover_states|-1 ==> rr.phase2(left_mover_states[i], left_mover_actor)\n    requires left_mover_actor != other_actor\n    requires !rr.crashed(state_after_both_steps)\n\n    ensures  StateNextSeq(left_mover_states', left_mover_steps', rr.lspec.next)\n    ensures  left_mover_states'[0] == initial_state\n    ensures  last(left_mover_states') == new_middle_state\n    ensures  forall step :: step in left_mover_steps' ==> rr.idmap(step) == left_mover_actor\n    ensures  |left_mover_states'| == |left_mover_states|\n    ensures  forall i :: 0 <= i < |left_mover_states| ==> PhasesMatch(rr, left_mover_states[i], left_mover_states'[i], left_mover_actor)\n    ensures  StateNextSeq(other_states', other_steps', rr.lspec.next)\n    ensures  other_states'[0] == new_middle_state\n    ensures  last(other_states') == state_after_both_steps\n    ensures  forall step :: step in other_steps' ==> rr.idmap(step) == other_actor\n    ensures  |other_states'| == |other_states|\n    ensures  forall i :: 0 <= i < |other_states| ==> PhasesMatch(rr, other_states[i], other_states'[i], other_actor)\n\n    decreases |left_mover_states|\n  {\n    if |left_mover_steps| == 0 {\n      lemma_StateNextSeqByOtherActorCausesPhasesMatch(rr, clrr, other_states, other_steps, |other_steps|, other_actor, left_mover_actor);\n      new_middle_state := initial_state;\n      left_mover_states' := [initial_state];\n      left_mover_steps' := [];\n      other_states' := other_states;\n      other_steps' := other_steps;\n      return;\n    }\n\n    var zero := 0;\n    assert ActionTuple(left_mover_states[zero], left_mover_states[zero+1], left_mover_steps[zero]) in rr.lspec.next;\n    lemma_IfStateNextSeqDoesntCrashNoStateDoes(rr, left_mover_states, left_mover_steps, zero+1);\n    var new_middle_state_mid, left_mover_mid, other_states_mid, other_steps_mid :=\n      lemma_DemonstrateLeftMoverCommutesCaseMultipleSteps(\n        rr, clrr, initial_state, state_after_other_step, left_mover_states[zero+1], other_states, other_steps, other_actor,\n        left_mover_steps[zero]);\n\n    lemma_ReduceStateNextSeqLeft(left_mover_states, left_mover_steps, rr.lspec.next);\n    lemma_NextMaintainsAnnotatedReachables(initial_state, new_middle_state_mid, left_mover_mid, rr.lspec);\n    var left_mover_states_next, left_mover_steps_next;\n    new_middle_state, left_mover_states_next, left_mover_steps_next, other_states', other_steps' :=\n      lemma_MoveMultipleLeftMoversAcrossMultipleSteps(\n        rr, clrr, new_middle_state_mid, left_mover_states[zero+1], last(left_mover_states), other_states_mid, other_steps_mid,\n        other_actor, left_mover_states[1..], left_mover_steps[1..], left_mover_actor);\n\n    left_mover_states' := [initial_state] + left_mover_states_next;\n    left_mover_steps' := [left_mover_mid] + left_mover_steps_next;\n    lemma_ExtendStateNextSeqLeft(left_mover_states_next, left_mover_steps_next, rr.lspec.next, initial_state, left_mover_mid);\n\n    forall i | 0 <= i < |left_mover_states|\n      ensures PhasesMatch(rr, left_mover_states[i], left_mover_states'[i], left_mover_actor)\n    {\n      if i > 0 {\n        var iminus := i-1;\n        assert 0 <= iminus < |left_mover_states[1..]|;\n        lemma_IndexIntoConcatenation([initial_state], left_mover_states_next, i);\n        assert left_mover_states'[i] == left_mover_states_next[iminus];\n        calc {\n          left_mover_states[i];\n            { assert i == 1+iminus; }\n          left_mover_states[1+iminus];\n            { lemma_IndexIntoDrop(left_mover_states, 1, iminus); }\n           left_mover_states[1..][iminus];\n        }\n        assert PhasesMatch(rr, left_mover_states[1..][iminus], left_mover_states_next[iminus], left_mover_actor);\n      }\n      else {\n        assert left_mover_states'[i] == initial_state;\n        lemma_StateNextSeqByOtherActorCausesPhasesMatch(rr, clrr, other_states, other_steps, |other_steps|, other_actor, left_mover_actor);\n      }\n    }\n  }\n\n  lemma lemma_DemonstrateLeftMoversEnabledBeforeCrashCaseOneStep<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    clrr:CohenLamportReductionRequest<State, Actor, CrossLevelStep<State, Actor, LStep>>,\n    initial_state:State,\n    post_crash_state:State,\n    crash_step:LStep,\n    left_mover_actor:Actor\n    ) returns (\n    left_mover_states:seq<State>,\n    left_mover_steps:seq<LStep>,\n    crash_step':LStep,\n    post_crash_state':State\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires clrr == GetCohenLamportReductionRequest(rr)\n    requires initial_state in AnnotatedReachables(rr.lspec)\n    requires ActionTuple(initial_state, post_crash_state, crash_step) in rr.lspec.next\n    requires !clrr.crashed(initial_state)\n    requires rr.crashed(post_crash_state)\n    requires rr.idmap(crash_step) != left_mover_actor\n    requires rr.phase2(initial_state, left_mover_actor)\n\n    ensures  StateNextSeq(left_mover_states, left_mover_steps, rr.lspec.next)\n    ensures  left_mover_states[0] == initial_state\n    ensures  !rr.crashed(last(left_mover_states))\n    ensures  !rr.phase2(last(left_mover_states), left_mover_actor)\n    ensures  forall i :: 0 <= i < |left_mover_states|-1 ==> rr.phase2(left_mover_states[i], left_mover_actor)\n    ensures  forall step :: step in left_mover_steps ==> rr.idmap(step) == left_mover_actor\n    ensures  ActionTuple(last(left_mover_states), post_crash_state', crash_step') in rr.lspec.next\n    ensures  rr.idmap(crash_step') == rr.idmap(crash_step)\n    ensures  rr.crashed(post_crash_state')\n    ensures  RefinementPair(post_crash_state, post_crash_state') in rr.relation\n  {\n    assert RefinementViaReductionSpecModule.LeftMoversEnabledBeforeCrashConditions(rr, initial_state, post_crash_state, crash_step,\n                                                                                   left_mover_actor);\n    left_mover_states, left_mover_steps, crash_step', post_crash_state' :|\n           && StateNextSeq(left_mover_states, left_mover_steps, rr.lspec.next)\n           && left_mover_states[0] == initial_state\n           && !rr.crashed(last(left_mover_states))\n           && !rr.phase2(last(left_mover_states), left_mover_actor)\n           && (forall i :: 0 <= i < |left_mover_states|-1 ==> rr.phase2(left_mover_states[i], left_mover_actor))\n           && (forall step :: step in left_mover_steps ==> rr.idmap(step) == left_mover_actor)\n           && ActionTuple(last(left_mover_states), post_crash_state', crash_step') in rr.lspec.next\n           && rr.idmap(crash_step') == rr.idmap(crash_step)\n           && rr.crashed(post_crash_state')\n           && RefinementPair(post_crash_state, post_crash_state') in rr.relation;\n  }\n\n  lemma lemma_DemonstrateLeftMoversEnabledBeforeCrashCaseLow<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    clrr:CohenLamportReductionRequest<State, Actor, CrossLevelStep<State, Actor, LStep>>,\n    initial_state:State,\n    post_crash_state:State,\n    crash_step:CrossLevelStep<State, Actor, LStep>,\n    left_mover_actor:Actor\n    ) returns (\n    left_mover_states:seq<State>,\n    left_mover_steps:seq<CrossLevelStep<State, Actor, LStep>>,\n    crash_step':CrossLevelStep<State, Actor, LStep>,\n    post_crash_state':State\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires clrr == GetCohenLamportReductionRequest(rr)\n    requires initial_state in AnnotatedReachables(rr.lspec)\n    requires ActionTuple(initial_state, post_crash_state, crash_step) in clrr.spec.next\n    requires !clrr.crashed(initial_state)\n    requires clrr.crashed(post_crash_state)\n    requires clrr.idmap(crash_step) != left_mover_actor\n    requires clrr.phase2(initial_state, left_mover_actor)\n    requires crash_step.Low?\n\n    ensures  StateNextSeq(left_mover_states, left_mover_steps, clrr.spec.next)\n    ensures  left_mover_states[0] == initial_state\n    ensures  !clrr.crashed(last(left_mover_states))\n    ensures  !clrr.phase2(last(left_mover_states), left_mover_actor)\n    ensures  forall i :: 0 <= i < |left_mover_states|-1 ==> clrr.phase2(left_mover_states[i], left_mover_actor)\n    ensures  forall step :: step in left_mover_steps ==> clrr.idmap(step) == left_mover_actor\n    ensures  ActionTuple(last(left_mover_states), post_crash_state', crash_step') in clrr.spec.next\n    ensures  clrr.idmap(crash_step') == clrr.idmap(crash_step)\n    ensures  clrr.crashed(post_crash_state')\n    ensures  RefinementPair(post_crash_state, post_crash_state') in clrr.relation\n  {\n    var ltrace, crash_step_single;\n    left_mover_states, ltrace, crash_step_single, post_crash_state' :=\n      lemma_DemonstrateLeftMoversEnabledBeforeCrashCaseOneStep(\n        rr, clrr, initial_state, post_crash_state, crash_step.step, left_mover_actor);\n    crash_step' := Low(rr.idmap(crash_step_single), crash_step_single);\n    left_mover_steps := lemma_LiftStateNextSeqToCrossLevel(rr, clrr, left_mover_states, ltrace);\n  }\n\n  lemma lemma_DemonstrateLeftMoversEnabledBeforeCrashCaseMultipleSteps<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    clrr:CohenLamportReductionRequest<State, Actor, CrossLevelStep<State, Actor, LStep>>,\n    initial_state:State,\n    post_crash_state:State,\n    crash_states:seq<State>,\n    crash_steps:seq<LStep>,\n    crash_actor:Actor,\n    left_mover_actor:Actor\n    ) returns (\n    left_mover_states:seq<State>,\n    left_mover_steps:seq<LStep>,\n    crash_states':seq<State>,\n    crash_steps':seq<LStep>,\n    post_crash_state':State\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires clrr == GetCohenLamportReductionRequest(rr)\n    requires initial_state in AnnotatedReachables(rr.lspec)\n    requires StateNextSeq(crash_states, crash_steps, rr.lspec.next)\n    requires crash_states[0] == initial_state\n    requires last(crash_states) == post_crash_state\n    requires forall step :: step in crash_steps ==> rr.idmap(step) == crash_actor\n    requires !clrr.crashed(initial_state)\n    requires clrr.crashed(post_crash_state)\n    requires crash_actor != left_mover_actor\n    requires rr.phase2(initial_state, left_mover_actor)\n\n    ensures  StateNextSeq(left_mover_states, left_mover_steps, rr.lspec.next)\n    ensures  left_mover_states[0] == initial_state\n    ensures  !rr.crashed(last(left_mover_states))\n    ensures  !rr.phase2(last(left_mover_states), left_mover_actor)\n    ensures  forall i :: 0 <= i < |left_mover_states|-1 ==> rr.phase2(left_mover_states[i], left_mover_actor)\n    ensures  forall step :: step in left_mover_steps ==> rr.idmap(step) == left_mover_actor\n    ensures  StateNextSeq(crash_states', crash_steps', rr.lspec.next)\n    ensures  crash_states'[0] == last(left_mover_states)\n    ensures  last(crash_states') == post_crash_state'\n    ensures  forall step :: step in crash_steps' ==> rr.idmap(step) == crash_actor\n    ensures  clrr.crashed(post_crash_state')\n    ensures  RefinementPair(post_crash_state, post_crash_state') in clrr.relation\n    ensures  |crash_states'| <= |crash_states|\n    ensures  forall i :: 0 <= i < |crash_states'|-1 ==> PhasesMatch(rr, crash_states[i], crash_states'[i], crash_actor)\n  {\n    var pos := lemma_FindFirstCrashingState(rr, crash_states, crash_steps);\n    assert 0 < pos < |crash_states|;\n    var prev := pos-1;\n    assert post_crash_state == last(crash_states) == crash_states[pos];\n\n    assert ActionTuple(crash_states[prev], crash_states[prev+1], crash_steps[prev]) in rr.lspec.next;\n    lemma_StateNextSeqMaintainsAnnotatedReachables(crash_states, crash_steps, rr.lspec);\n    assert crash_states[prev] in crash_states;\n    assert crash_states[prev] in AnnotatedReachables(rr.lspec);\n    lemma_StateNextSeqByOtherActorCausesPhasesMatch(rr, clrr, crash_states, crash_steps, prev, crash_actor, left_mover_actor);\n\n    var left_mover_states_mid, left_mover_steps_mid, crash_step_mid;\n    left_mover_states_mid, left_mover_steps_mid, crash_step_mid, post_crash_state' :=\n      lemma_DemonstrateLeftMoversEnabledBeforeCrashCaseOneStep(\n        rr, clrr, crash_states[prev], crash_states[prev+1], crash_steps[prev], left_mover_actor);\n\n    lemma_TakeStateNextSeq(crash_states, crash_steps, rr.lspec.next, prev);\n    var new_middle_state, other_states, other_steps;\n    new_middle_state, left_mover_states, left_mover_steps, other_states, other_steps :=\n      lemma_MoveMultipleLeftMoversAcrossMultipleSteps(\n        rr, clrr, initial_state, crash_states[prev], last(left_mover_states_mid), crash_states[..prev+1], crash_steps[..prev],\n        crash_actor, left_mover_states_mid, left_mover_steps_mid, left_mover_actor);\n\n    crash_states' := other_states + [post_crash_state'];\n    crash_steps' := other_steps + [crash_step_mid];\n    lemma_ExtendStateNextSeqRight(other_states, other_steps, rr.lspec.next, post_crash_state', crash_step_mid);\n\n    forall i | 0 <= i < |left_mover_states|-1\n      ensures rr.phase2(left_mover_states[i], left_mover_actor)\n    {\n      assert PhasesMatch(rr, left_mover_states_mid[i], left_mover_states[i], left_mover_actor);\n    }\n\n    forall i | 0 <= i < |crash_states'|-1\n      ensures PhasesMatch(rr, crash_states[i], crash_states'[i], crash_actor)\n    {\n      assert crash_states[i] == crash_states[..prev+1][i];\n      assert crash_states'[i] == other_states[i];\n      assert PhasesMatch(rr, crash_states[..prev+1][i], other_states[i], crash_actor);\n    }\n  }\n\n  lemma lemma_DemonstrateLeftMoversEnabledBeforeCrashCaseReducible<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    clrr:CohenLamportReductionRequest<State, Actor, CrossLevelStep<State, Actor, LStep>>,\n    initial_state:State,\n    post_crash_state:State,\n    crash_step:CrossLevelStep<State, Actor, LStep>,\n    left_mover_actor:Actor\n    ) returns (\n    left_mover_states:seq<State>,\n    left_mover_steps:seq<CrossLevelStep<State, Actor, LStep>>,\n    crash_step':CrossLevelStep<State, Actor, LStep>,\n    post_crash_state':State\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires clrr == GetCohenLamportReductionRequest(rr)\n    requires initial_state in AnnotatedReachables(rr.lspec)\n    requires ActionTuple(initial_state, post_crash_state, crash_step) in clrr.spec.next\n    requires !clrr.crashed(initial_state)\n    requires clrr.crashed(post_crash_state)\n    requires clrr.idmap(crash_step) != left_mover_actor\n    requires clrr.phase2(initial_state, left_mover_actor)\n    requires crash_step.Reducible?\n\n    ensures  StateNextSeq(left_mover_states, left_mover_steps, clrr.spec.next)\n    ensures  left_mover_states[0] == initial_state\n    ensures  !clrr.crashed(last(left_mover_states))\n    ensures  !clrr.phase2(last(left_mover_states), left_mover_actor)\n    ensures  forall i :: 0 <= i < |left_mover_states|-1 ==> clrr.phase2(left_mover_states[i], left_mover_actor)\n    ensures  forall step :: step in left_mover_steps ==> clrr.idmap(step) == left_mover_actor\n    ensures  ActionTuple(last(left_mover_states), post_crash_state', crash_step') in clrr.spec.next\n    ensures  clrr.idmap(crash_step') == clrr.idmap(crash_step)\n    ensures  clrr.crashed(post_crash_state')\n    ensures  RefinementPair(post_crash_state, post_crash_state') in clrr.relation\n  {\n    var ltrace, crash_states', crash_steps';\n    left_mover_states, ltrace, crash_states', crash_steps', post_crash_state' :=\n      lemma_DemonstrateLeftMoversEnabledBeforeCrashCaseMultipleSteps(\n        rr, clrr, initial_state, post_crash_state, crash_step.states, crash_step.trace, crash_step.actor, left_mover_actor);\n    crash_step' := Reducible(crash_step.actor, crash_states', crash_steps');\n    left_mover_steps := lemma_LiftStateNextSeqToCrossLevel(rr, clrr, left_mover_states, ltrace);\n    assert ValidReducibleCrossLevelStep(rr, crash_states', crash_steps', crash_step.actor);\n    assert CrossLevelNext(rr, last(left_mover_states), post_crash_state', crash_step');\n  }\n\n  lemma lemma_DemonstrateLeftMoversEnabledBeforeCrash<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    clrr:CohenLamportReductionRequest<State, Actor, CrossLevelStep<State, Actor, LStep>>,\n    initial_state:State,\n    post_crash_state:State,\n    crash_step:CrossLevelStep<State, Actor, LStep>,\n    left_mover_actor:Actor\n    ) returns (\n    left_mover_states:seq<State>,\n    left_mover_steps:seq<CrossLevelStep<State, Actor, LStep>>,\n    crash_step':CrossLevelStep<State, Actor, LStep>,\n    post_crash_state':State\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires clrr == GetCohenLamportReductionRequest(rr)\n    requires initial_state in AnnotatedReachables(clrr.spec)\n    requires ActionTuple(initial_state, post_crash_state, crash_step) in clrr.spec.next\n    requires !clrr.crashed(initial_state)\n    requires clrr.crashed(post_crash_state)\n    requires clrr.idmap(crash_step) != left_mover_actor\n    requires clrr.phase2(initial_state, left_mover_actor)\n\n    ensures  StateNextSeq(left_mover_states, left_mover_steps, clrr.spec.next)\n    ensures  left_mover_states[0] == initial_state\n    ensures  !clrr.crashed(last(left_mover_states))\n    ensures  !clrr.phase2(last(left_mover_states), left_mover_actor)\n    ensures  forall i :: 0 <= i < |left_mover_states|-1 ==> clrr.phase2(left_mover_states[i], left_mover_actor)\n    ensures  forall step :: step in left_mover_steps ==> clrr.idmap(step) == left_mover_actor\n    ensures  ActionTuple(last(left_mover_states), post_crash_state', crash_step') in clrr.spec.next\n    ensures  clrr.idmap(crash_step') == clrr.idmap(crash_step)\n    ensures  clrr.crashed(post_crash_state')\n    ensures  RefinementPair(post_crash_state, post_crash_state') in clrr.relation\n  {\n    lemma_AnnotatedReachablesOfCrossLevelSpec(rr);\n    if crash_step.Low? {\n      left_mover_states, left_mover_steps, crash_step', post_crash_state' :=\n        lemma_DemonstrateLeftMoversEnabledBeforeCrashCaseLow(rr, clrr, initial_state, post_crash_state, crash_step, left_mover_actor);\n    }\n    else {\n      left_mover_states, left_mover_steps, crash_step', post_crash_state' :=\n        lemma_DemonstrateLeftMoversEnabledBeforeCrashCaseReducible(rr, clrr, initial_state, post_crash_state, crash_step, left_mover_actor);\n    }\n  }\n\n  lemma lemma_LeftMoversEnabledBeforeCrash<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    clrr:CohenLamportReductionRequest<State, Actor, CrossLevelStep<State, Actor, LStep>>\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires clrr == GetCohenLamportReductionRequest(rr)\n    ensures  CohenLamportReductionSpecModule.LeftMoversEnabledBeforeCrash(clrr)\n  {\n    forall initial_state, post_crash_state, crash_step, actor\n      {:trigger CohenLamportReductionSpecModule.LeftMoversEnabledBeforeCrashConditions(clrr, initial_state, post_crash_state,\n                                                                                       crash_step, actor)}\n      | CohenLamportReductionSpecModule.LeftMoversEnabledBeforeCrashConditions(clrr, initial_state, post_crash_state, crash_step, actor)\n      ensures exists states, trace, crash_step', post_crash_state' ::\n                && StateNextSeq(states, trace, clrr.spec.next)\n                && states[0] == initial_state\n                && !clrr.crashed(last(states))\n                && !clrr.phase2(last(states), actor)\n                && (forall i :: 0 <= i < |states|-1 ==> clrr.phase2(states[i], actor))\n                && (forall step :: step in trace ==> clrr.idmap(step) == actor)\n                && ActionTuple(last(states), post_crash_state', crash_step') in clrr.spec.next\n                && clrr.idmap(crash_step') == clrr.idmap(crash_step)\n                && clrr.crashed(post_crash_state')\n                && RefinementPair(post_crash_state, post_crash_state') in clrr.relation\n    {\n      var states, trace, crash_step', post_crash_state' :=\n        lemma_DemonstrateLeftMoversEnabledBeforeCrash(rr, clrr, initial_state, post_crash_state, crash_step, actor);\n    }\n  }\n\n  ////////////////////////////////////////\n  // RightMoverCrashPreservation\n  ////////////////////////////////////////\n\n  lemma lemma_DemonstrateRightMoverCrashPreservationCaseOneStep<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    clrr:CohenLamportReductionRequest<State, Actor, CrossLevelStep<State, Actor, LStep>>,\n    initial_state:State,\n    state_after_right_mover:State,\n    state_after_both_steps:State,\n    right_mover:LStep,\n    other_step:LStep\n    ) returns (\n    other_step':LStep,\n    state_after_other_step':State\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires clrr == GetCohenLamportReductionRequest(rr)\n    requires initial_state in AnnotatedReachables(rr.lspec)\n    requires ActionTuple(initial_state, state_after_right_mover, right_mover) in rr.lspec.next\n    requires ActionTuple(state_after_right_mover, state_after_both_steps, other_step) in rr.lspec.next\n    requires !rr.crashed(initial_state)\n    requires !rr.crashed(state_after_right_mover)\n    requires rr.crashed(state_after_both_steps)\n    requires rr.phase1(state_after_right_mover, rr.idmap(right_mover))\n    requires rr.idmap(right_mover) != rr.idmap(other_step)\n\n    ensures  rr.idmap(other_step') == rr.idmap(other_step)\n    ensures  ActionTuple(initial_state, state_after_other_step', other_step') in rr.lspec.next\n    ensures  rr.crashed(state_after_other_step')\n    ensures  RefinementPair(state_after_both_steps, state_after_other_step') in rr.relation\n  {\n    assert RefinementViaReductionSpecModule.RightMoverCrashPreservationConditions(rr, initial_state, state_after_right_mover,\n                                                                                  state_after_both_steps, right_mover, other_step);\n    other_step', state_after_other_step' :|\n      && rr.idmap(other_step') == rr.idmap(other_step)\n      && ActionTuple(initial_state, state_after_other_step', other_step') in rr.lspec.next\n      && rr.crashed(state_after_other_step')\n      && RefinementPair(state_after_both_steps, state_after_other_step') in rr.relation;\n  }\n\n  lemma lemma_DemonstrateRightMoverCrashPreservationCaseMultipleSteps<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    clrr:CohenLamportReductionRequest<State, Actor, CrossLevelStep<State, Actor, LStep>>,\n    initial_state:State,\n    state_after_right_mover:State,\n    state_after_both_steps:State,\n    right_mover:LStep,\n    other_states:seq<State>,\n    other_steps:seq<LStep>,\n    other_actor:Actor\n    ) returns (\n    other_states':seq<State>,\n    other_steps':seq<LStep>,\n    state_after_other_step':State\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires clrr == GetCohenLamportReductionRequest(rr)\n    requires initial_state in AnnotatedReachables(rr.lspec)\n    requires ActionTuple(initial_state, state_after_right_mover, right_mover) in rr.lspec.next\n    requires StateNextSeq(other_states, other_steps, rr.lspec.next)\n    requires other_states[0] == state_after_right_mover\n    requires last(other_states) == state_after_both_steps\n    requires forall step :: step in other_steps ==> rr.idmap(step) == other_actor\n    requires !rr.crashed(initial_state)\n    requires !rr.crashed(state_after_right_mover)\n    requires rr.crashed(state_after_both_steps)\n    requires rr.phase1(state_after_right_mover, rr.idmap(right_mover))\n    requires rr.idmap(right_mover) != other_actor\n\n    ensures  StateNextSeq(other_states', other_steps', rr.lspec.next)\n    ensures  other_states'[0] == initial_state\n    ensures  last(other_states') == state_after_other_step'\n    ensures  forall step :: step in other_steps' ==> rr.idmap(step) == other_actor\n    ensures  rr.crashed(state_after_other_step')\n    ensures  RefinementPair(state_after_both_steps, state_after_other_step') in rr.relation\n    ensures  |other_states'| <= |other_states|\n    ensures  forall i :: 0 <= i < |other_states'|-1 ==> PhasesMatch(rr, other_states[i], other_states'[i], other_actor)\n  {\n    var pos := lemma_FindFirstCrashingState(rr, other_states, other_steps);\n    assert 0 < pos < |other_states|;\n    var prev := pos-1;\n    assert state_after_both_steps == last(other_states) == other_states[pos];\n\n    assert ActionTuple(other_states[prev], other_states[prev+1], other_steps[prev]) in rr.lspec.next;\n\n    lemma_TakeStateNextSeq(other_states, other_steps, rr.lspec.next, prev);\n    var new_middle_state, other_states_next, other_steps_next, right_mover' :=\n      lemma_DemonstrateRightMoverCommutesCaseMultipleSteps(\n        rr, clrr, initial_state, state_after_right_mover, other_states[prev], right_mover,\n        other_states[..prev+1], other_steps[..prev], other_actor);\n\n    lemma_StateNextSeqMaintainsAnnotatedReachables(other_states_next, other_steps_next, rr.lspec);\n    assert new_middle_state == last(other_states_next);\n    assert new_middle_state in other_states_next;\n    assert new_middle_state in AnnotatedReachables(rr.lspec);\n    assert RefinementViaReductionSpecModule.RightMoverCrashPreservationConditions(rr, new_middle_state, other_states[prev],\n                                                                                  other_states[prev+1], right_mover', other_steps[prev]);\n\n    var other_step';\n    other_step', state_after_other_step' :|\n      && rr.idmap(other_step') == rr.idmap(other_steps[prev])\n      && ActionTuple(new_middle_state, state_after_other_step', other_step') in rr.lspec.next\n      && rr.crashed(state_after_other_step')\n      && RefinementPair(other_states[prev+1], state_after_other_step') in rr.relation;\n\n    other_states' := other_states_next + [state_after_other_step'];\n    other_steps' := other_steps_next + [other_step'];\n    lemma_ExtendStateNextSeqRight(other_states_next, other_steps_next, rr.lspec.next, state_after_other_step', other_step');\n  }\n\n  lemma lemma_DemonstrateRightMoverCrashPreservationCaseLow<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    clrr:CohenLamportReductionRequest<State, Actor, CrossLevelStep<State, Actor, LStep>>,\n    initial_state:State,\n    state_after_right_mover:State,\n    state_after_both_steps:State,\n    right_mover:CrossLevelStep<State, Actor, LStep>,\n    other_step:CrossLevelStep<State, Actor, LStep>\n    ) returns (\n    other_step':CrossLevelStep<State, Actor, LStep>,\n    state_after_other_step':State\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires clrr == GetCohenLamportReductionRequest(rr)\n    requires initial_state in AnnotatedReachables(rr.lspec)\n    requires ActionTuple(initial_state, state_after_right_mover, right_mover) in clrr.spec.next\n    requires ActionTuple(state_after_right_mover, state_after_both_steps, other_step) in clrr.spec.next\n    requires !clrr.crashed(initial_state)\n    requires !clrr.crashed(state_after_right_mover)\n    requires clrr.crashed(state_after_both_steps)\n    requires clrr.phase1(state_after_right_mover, clrr.idmap(right_mover))\n    requires clrr.idmap(right_mover) != clrr.idmap(other_step)\n    requires right_mover.Low?\n    requires other_step.Low?\n\n    ensures  clrr.idmap(other_step') == clrr.idmap(other_step)\n    ensures  ActionTuple(initial_state, state_after_other_step', other_step') in clrr.spec.next\n    ensures  clrr.crashed(state_after_other_step')\n    ensures  RefinementPair(state_after_both_steps, state_after_other_step') in clrr.relation\n  {\n    var other_step_single;\n    other_step_single, state_after_other_step' :=\n      lemma_DemonstrateRightMoverCrashPreservationCaseOneStep(\n        rr, clrr, initial_state, state_after_right_mover, state_after_both_steps, right_mover.step, other_step.step);\n    other_step' := Low(rr.idmap(other_step_single), other_step_single);\n  }\n\n  lemma lemma_DemonstrateRightMoverCrashPreservationCaseReducible<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    clrr:CohenLamportReductionRequest<State, Actor, CrossLevelStep<State, Actor, LStep>>,\n    initial_state:State,\n    state_after_right_mover:State,\n    state_after_both_steps:State,\n    right_mover:CrossLevelStep<State, Actor, LStep>,\n    other_step:CrossLevelStep<State, Actor, LStep>\n    ) returns (\n    other_step':CrossLevelStep<State, Actor, LStep>,\n    state_after_other_step':State\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires clrr == GetCohenLamportReductionRequest(rr)\n    requires initial_state in AnnotatedReachables(rr.lspec)\n    requires ActionTuple(initial_state, state_after_right_mover, right_mover) in clrr.spec.next\n    requires ActionTuple(state_after_right_mover, state_after_both_steps, other_step) in clrr.spec.next\n    requires !clrr.crashed(initial_state)\n    requires !clrr.crashed(state_after_right_mover)\n    requires clrr.crashed(state_after_both_steps)\n    requires clrr.phase1(state_after_right_mover, clrr.idmap(right_mover))\n    requires clrr.idmap(right_mover) != clrr.idmap(other_step)\n    requires right_mover.Low?\n    requires other_step.Reducible?\n\n    ensures  clrr.idmap(other_step') == clrr.idmap(other_step)\n    ensures  ActionTuple(initial_state, state_after_other_step', other_step') in clrr.spec.next\n    ensures  clrr.crashed(state_after_other_step')\n    ensures  RefinementPair(state_after_both_steps, state_after_other_step') in clrr.relation\n  {\n    var other_states', other_steps';\n    other_states', other_steps', state_after_other_step' :=\n      lemma_DemonstrateRightMoverCrashPreservationCaseMultipleSteps(\n        rr, clrr, initial_state, state_after_right_mover, state_after_both_steps, right_mover.step,\n        other_step.states, other_step.trace, other_step.actor);\n    other_step' := Reducible(other_step.actor, other_states', other_steps');\n    assert ValidReducibleCrossLevelStep(rr, other_states', other_steps', other_step.actor);\n    assert CrossLevelNext(rr, initial_state, state_after_other_step', other_step');\n  }\n\n  lemma lemma_DemonstrateRightMoverCrashPreservation<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    clrr:CohenLamportReductionRequest<State, Actor, CrossLevelStep<State, Actor, LStep>>,\n    initial_state:State,\n    state_after_right_mover:State,\n    state_after_both_steps:State,\n    right_mover:CrossLevelStep<State, Actor, LStep>,\n    other_step:CrossLevelStep<State, Actor, LStep>\n    ) returns (\n    other_step':CrossLevelStep<State, Actor, LStep>,\n    state_after_other_step':State\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires clrr == GetCohenLamportReductionRequest(rr)\n    requires initial_state in AnnotatedReachables(clrr.spec)\n    requires ActionTuple(initial_state, state_after_right_mover, right_mover) in clrr.spec.next\n    requires ActionTuple(state_after_right_mover, state_after_both_steps, other_step) in clrr.spec.next\n    requires !clrr.crashed(initial_state)\n    requires !clrr.crashed(state_after_right_mover)\n    requires clrr.crashed(state_after_both_steps)\n    requires clrr.phase1(state_after_right_mover, clrr.idmap(right_mover))\n    requires clrr.idmap(right_mover) != clrr.idmap(other_step)\n\n    ensures  clrr.idmap(other_step') == clrr.idmap(other_step)\n    ensures  ActionTuple(initial_state, state_after_other_step', other_step') in clrr.spec.next\n    ensures  clrr.crashed(state_after_other_step')\n    ensures  RefinementPair(state_after_both_steps, state_after_other_step') in clrr.relation\n  {\n    lemma_AnnotatedReachablesOfCrossLevelSpec(rr);\n    assert initial_state in AnnotatedReachables(rr.lspec);\n    if right_mover.Reducible? {\n      lemma_ReducibleStepStartsAndEndsOutOfPhase(rr, initial_state, state_after_right_mover, right_mover);\n      assert false;\n    }\n\n    if other_step.Low? {\n      other_step', state_after_other_step' :=\n        lemma_DemonstrateRightMoverCrashPreservationCaseLow(\n          rr, clrr, initial_state, state_after_right_mover, state_after_both_steps, right_mover, other_step);\n    }\n    else {\n      other_step', state_after_other_step' :=\n        lemma_DemonstrateRightMoverCrashPreservationCaseReducible(\n          rr, clrr, initial_state, state_after_right_mover, state_after_both_steps, right_mover, other_step);\n    }\n  }\n\n  lemma lemma_RightMoverCrashPreservation<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    clrr:CohenLamportReductionRequest<State, Actor, CrossLevelStep<State, Actor, LStep>>\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires clrr == GetCohenLamportReductionRequest(rr)\n    ensures  CohenLamportReductionSpecModule.RightMoverCrashPreservation(clrr)\n  {\n    forall initial_state, state_after_right_mover, state_after_both_steps, right_mover, other_step\n      {:trigger CohenLamportReductionSpecModule.RightMoverCrashPreservationConditions(clrr, initial_state, state_after_right_mover,\n                                                                                      state_after_both_steps, right_mover, other_step)}\n      | CohenLamportReductionSpecModule.RightMoverCrashPreservationConditions(clrr, initial_state, state_after_right_mover,\n                                                                              state_after_both_steps, right_mover, other_step)\n      ensures exists other_step', state_after_other_step' ::\n                && clrr.idmap(other_step') == clrr.idmap(other_step)\n                && ActionTuple(initial_state, state_after_other_step', other_step') in clrr.spec.next\n                && clrr.crashed(state_after_other_step')\n                && RefinementPair(state_after_both_steps, state_after_other_step') in clrr.relation\n    {\n      var other_step', state_after_other_step' :=\n        lemma_DemonstrateRightMoverCrashPreservation(\n          rr, clrr, initial_state, state_after_right_mover, state_after_both_steps, right_mover, other_step);\n    }\n  }\n\n  ////////////////////////////////////////\n  // LeftMoverSelfCrashPreservation\n  ////////////////////////////////////////\n\n  lemma lemma_DemonstrateLeftMoverSelfCrashPreservationCaseOneStep<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    clrr:CohenLamportReductionRequest<State, Actor, CrossLevelStep<State, Actor, LStep>>,\n    initial_state:State,\n    state_after_other_step:State,\n    state_after_both_steps:State,\n    other_step:LStep,\n    left_mover:LStep\n    ) returns (\n    left_mover':LStep,\n    state_after_left_mover':State\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires clrr == GetCohenLamportReductionRequest(rr)\n    requires initial_state in AnnotatedReachables(rr.lspec)\n    requires ActionTuple(initial_state, state_after_other_step, other_step) in rr.lspec.next\n    requires ActionTuple(state_after_other_step, state_after_both_steps, left_mover) in rr.lspec.next\n    requires !rr.crashed(initial_state)\n    requires !rr.crashed(state_after_other_step)\n    requires rr.crashed(state_after_both_steps)\n    requires rr.phase2(state_after_other_step, rr.idmap(left_mover))\n    requires rr.idmap(left_mover) != rr.idmap(other_step)\n\n    ensures  rr.idmap(left_mover') == rr.idmap(left_mover)\n    ensures  ActionTuple(initial_state, state_after_left_mover', left_mover') in rr.lspec.next\n    ensures  rr.crashed(state_after_left_mover')\n    ensures  RefinementPair(state_after_both_steps, state_after_left_mover') in rr.relation\n  {\n    assert RefinementViaReductionSpecModule.LeftMoverSelfCrashPreservationConditions(rr, initial_state, state_after_other_step,\n                                                                                     state_after_both_steps, other_step, left_mover);\n    left_mover', state_after_left_mover' :|\n      && rr.idmap(left_mover') == rr.idmap(left_mover)\n      && ActionTuple(initial_state, state_after_left_mover', left_mover') in rr.lspec.next\n      && rr.crashed(state_after_left_mover')\n      && RefinementPair(state_after_both_steps, state_after_left_mover') in rr.relation;\n  }\n\n  lemma lemma_DemonstrateLeftMoverSelfCrashPreservationCaseLow<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    clrr:CohenLamportReductionRequest<State, Actor, CrossLevelStep<State, Actor, LStep>>,\n    initial_state:State,\n    state_after_other_step:State,\n    state_after_both_steps:State,\n    other_step:CrossLevelStep<State, Actor, LStep>,\n    left_mover:CrossLevelStep<State, Actor, LStep>\n    ) returns (\n    left_mover':CrossLevelStep<State, Actor, LStep>,\n    state_after_left_mover':State\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires clrr == GetCohenLamportReductionRequest(rr)\n    requires initial_state in AnnotatedReachables(rr.lspec)\n    requires ActionTuple(initial_state, state_after_other_step, other_step) in clrr.spec.next\n    requires ActionTuple(state_after_other_step, state_after_both_steps, left_mover) in clrr.spec.next\n    requires !clrr.crashed(initial_state)\n    requires !clrr.crashed(state_after_other_step)\n    requires clrr.crashed(state_after_both_steps)\n    requires clrr.phase2(state_after_other_step, clrr.idmap(left_mover))\n    requires clrr.idmap(left_mover) != clrr.idmap(other_step)\n    requires other_step.Low?\n    requires left_mover.Low?\n\n    ensures  clrr.idmap(left_mover') == clrr.idmap(left_mover)\n    ensures  ActionTuple(initial_state, state_after_left_mover', left_mover') in clrr.spec.next\n    ensures  clrr.crashed(state_after_left_mover')\n    ensures  RefinementPair(state_after_both_steps, state_after_left_mover') in rr.relation\n  {\n    var left_mover_single;\n    left_mover_single, state_after_left_mover' :=\n      lemma_DemonstrateLeftMoverSelfCrashPreservationCaseOneStep(\n        rr, clrr, initial_state, state_after_other_step, state_after_both_steps, other_step.step, left_mover.step);\n    left_mover' := Low(rr.idmap(left_mover_single), left_mover_single);\n  }\n\n  lemma lemma_DemonstrateLeftMoverSelfCrashPreservationCaseMultipleSteps<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    clrr:CohenLamportReductionRequest<State, Actor, CrossLevelStep<State, Actor, LStep>>,\n    initial_state:State,\n    state_after_other_step:State,\n    state_after_both_steps:State,\n    other_states:seq<State>,\n    other_steps:seq<LStep>,\n    other_actor:Actor,\n    left_mover:LStep\n    ) returns (\n    left_mover':LStep,\n    state_after_left_mover':State\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires clrr == GetCohenLamportReductionRequest(rr)\n    requires initial_state in AnnotatedReachables(rr.lspec)\n    requires |other_states| > 1\n    requires StateNextSeq(other_states, other_steps, rr.lspec.next)\n    requires other_states[0] == initial_state\n    requires last(other_states) == state_after_other_step\n    requires forall step :: step in other_steps ==> rr.idmap(step) == other_actor\n    requires ActionTuple(state_after_other_step, state_after_both_steps, left_mover) in rr.lspec.next\n    requires !rr.crashed(initial_state)\n    requires !rr.crashed(state_after_other_step)\n    requires rr.crashed(state_after_both_steps)\n    requires rr.phase2(state_after_other_step, rr.idmap(left_mover))\n    requires rr.idmap(left_mover) != other_actor\n\n    ensures  rr.idmap(left_mover') == rr.idmap(left_mover)\n    ensures  ActionTuple(initial_state, state_after_left_mover', left_mover') in rr.lspec.next\n    ensures  rr.crashed(state_after_left_mover')\n    ensures  RefinementPair(state_after_both_steps, state_after_left_mover') in rr.relation\n\n    decreases |other_states|\n  {\n    var penult := |other_states|-2;\n    assert ActionTuple(other_states[penult], other_states[penult+1], other_steps[penult]) in rr.lspec.next;\n    lemma_StateNextSeqMaintainsAnnotatedReachables(other_states, other_steps, rr.lspec);\n    assert RefinementViaReductionSpecModule.LeftMoverSelfCrashPreservationConditions(rr, other_states[penult], other_states[penult+1],\n                                                                                     state_after_both_steps, other_steps[penult],\n                                                                                     left_mover);\n    var left_mover_mid, state_after_left_mover_mid :|\n      && rr.idmap(left_mover_mid) == rr.idmap(left_mover)\n      && ActionTuple(other_states[penult], state_after_left_mover_mid, left_mover_mid) in rr.lspec.next\n      && rr.crashed(state_after_left_mover_mid)\n      && RefinementPair(state_after_both_steps, state_after_left_mover_mid) in rr.relation;\n\n    if penult == 0 {\n      left_mover' := left_mover_mid;\n      state_after_left_mover' := state_after_left_mover_mid;\n    }\n    else {\n      lemma_ReduceStateNextSeqRight(other_states, other_steps, rr.lspec.next);\n      left_mover', state_after_left_mover' :=\n        lemma_DemonstrateLeftMoverSelfCrashPreservationCaseMultipleSteps(\n          rr, clrr, initial_state, other_states[penult], state_after_left_mover_mid, all_but_last(other_states),\n          all_but_last(other_steps), other_actor, left_mover_mid);\n    }\n  }\n\n  lemma lemma_DemonstrateLeftMoverSelfCrashPreservationCaseReducible<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    clrr:CohenLamportReductionRequest<State, Actor, CrossLevelStep<State, Actor, LStep>>,\n    initial_state:State,\n    state_after_other_step:State,\n    state_after_both_steps:State,\n    other_step:CrossLevelStep<State, Actor, LStep>,\n    left_mover:CrossLevelStep<State, Actor, LStep>\n    ) returns (\n    left_mover':CrossLevelStep<State, Actor, LStep>,\n    state_after_left_mover':State\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires clrr == GetCohenLamportReductionRequest(rr)\n    requires initial_state in AnnotatedReachables(rr.lspec)\n    requires ActionTuple(initial_state, state_after_other_step, other_step) in clrr.spec.next\n    requires ActionTuple(state_after_other_step, state_after_both_steps, left_mover) in clrr.spec.next\n    requires !clrr.crashed(initial_state)\n    requires !clrr.crashed(state_after_other_step)\n    requires clrr.crashed(state_after_both_steps)\n    requires clrr.phase2(state_after_other_step, clrr.idmap(left_mover))\n    requires clrr.idmap(left_mover) != clrr.idmap(other_step)\n    requires other_step.Reducible?\n    requires left_mover.Low?\n\n    ensures  clrr.idmap(left_mover') == clrr.idmap(left_mover)\n    ensures  ActionTuple(initial_state, state_after_left_mover', left_mover') in clrr.spec.next\n    ensures  clrr.crashed(state_after_left_mover')\n    ensures  RefinementPair(state_after_both_steps, state_after_left_mover') in rr.relation\n\n  {\n    var left_mover_single;\n    left_mover_single, state_after_left_mover' :=\n      lemma_DemonstrateLeftMoverSelfCrashPreservationCaseMultipleSteps(\n        rr, clrr, initial_state, state_after_other_step, state_after_both_steps, other_step.states, other_step.trace,\n        other_step.actor, left_mover.step);\n    left_mover' := Low(rr.idmap(left_mover_single), left_mover_single);\n  }\n\n  lemma lemma_DemonstrateLeftMoverSelfCrashPreservation<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    clrr:CohenLamportReductionRequest<State, Actor, CrossLevelStep<State, Actor, LStep>>,\n    initial_state:State,\n    state_after_other_step:State,\n    state_after_both_steps:State,\n    other_step:CrossLevelStep<State, Actor, LStep>,\n    left_mover:CrossLevelStep<State, Actor, LStep>\n    ) returns (\n    left_mover':CrossLevelStep<State, Actor, LStep>,\n    state_after_left_mover':State\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires clrr == GetCohenLamportReductionRequest(rr)\n    requires initial_state in AnnotatedReachables(clrr.spec)\n    requires ActionTuple(initial_state, state_after_other_step, other_step) in clrr.spec.next\n    requires ActionTuple(state_after_other_step, state_after_both_steps, left_mover) in clrr.spec.next\n    requires !clrr.crashed(initial_state)\n    requires !clrr.crashed(state_after_other_step)\n    requires clrr.crashed(state_after_both_steps)\n    requires clrr.phase2(state_after_other_step, clrr.idmap(left_mover))\n    requires clrr.idmap(left_mover) != clrr.idmap(other_step)\n\n    ensures  clrr.idmap(left_mover') == clrr.idmap(left_mover)\n    ensures  ActionTuple(initial_state, state_after_left_mover', left_mover') in clrr.spec.next\n    ensures  clrr.crashed(state_after_left_mover')\n    ensures  RefinementPair(state_after_both_steps, state_after_left_mover') in rr.relation\n  {\n    lemma_AnnotatedReachablesOfCrossLevelSpec(rr);\n    assert initial_state in AnnotatedReachables(rr.lspec);\n    if left_mover.Reducible? {\n      lemma_ReducibleStepStartsAndEndsOutOfPhase(rr, state_after_other_step, state_after_both_steps, left_mover);\n      assert false;\n    }\n\n    if other_step.Low? {\n      left_mover', state_after_left_mover' :=\n        lemma_DemonstrateLeftMoverSelfCrashPreservationCaseLow(\n          rr, clrr, initial_state, state_after_other_step, state_after_both_steps, other_step, left_mover);\n    }\n    else {\n      left_mover', state_after_left_mover' :=\n        lemma_DemonstrateLeftMoverSelfCrashPreservationCaseReducible(\n          rr, clrr, initial_state, state_after_other_step, state_after_both_steps, other_step, left_mover);\n    }\n  }\n\n  lemma lemma_LeftMoverSelfCrashPreservation<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    clrr:CohenLamportReductionRequest<State, Actor, CrossLevelStep<State, Actor, LStep>>\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    requires clrr == GetCohenLamportReductionRequest(rr)\n    ensures  CohenLamportReductionSpecModule.LeftMoverSelfCrashPreservation(clrr)\n  {\n    forall initial_state, state_after_other_step, state_after_both_steps, other_step, left_mover\n      {:trigger CohenLamportReductionSpecModule.LeftMoverSelfCrashPreservationConditions(clrr, initial_state, state_after_other_step,\n                                                                                         state_after_both_steps, other_step, left_mover)}\n      | CohenLamportReductionSpecModule.LeftMoverSelfCrashPreservationConditions(clrr, initial_state, state_after_other_step,\n                                                                                 state_after_both_steps, other_step, left_mover)\n      ensures exists left_mover', state_after_left_mover' ::\n                && clrr.idmap(left_mover') == clrr.idmap(left_mover)\n                && ActionTuple(initial_state, state_after_left_mover', left_mover') in clrr.spec.next\n                && clrr.crashed(state_after_left_mover')\n                && RefinementPair(state_after_both_steps, state_after_left_mover') in clrr.relation\n    {\n      var left_mover', state_after_left_mover' :=\n        lemma_DemonstrateLeftMoverSelfCrashPreservation(\n          rr, clrr, initial_state, state_after_other_step, state_after_both_steps, other_step, left_mover);\n    }\n  }\n\n  ///////////////////////////////////////////////////////////////////////////\n  // Final demonstration that CohenLamportReductionRequest is valid\n  ///////////////////////////////////////////////////////////////////////////\n\n  lemma lemma_IsValidCohenLamportReductionRequest<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>\n    )\n    requires ValidRefinementViaReductionRequest(rr)\n    ensures  ValidCohenLamportReductionRequest(GetCohenLamportReductionRequest(rr))\n  {\n    var clrr := GetCohenLamportReductionRequest(rr);\n    lemma_AnnotatedReachablesOfCrossLevelSpec(rr);\n    lemma_PhaseUnaffectedByOtherActors(rr, clrr);\n    lemma_RightMoversCommute(rr, clrr);\n    lemma_LeftMoversCommute(rr, clrr);\n    lemma_LeftMoversAlwaysEnabled(rr, clrr);\n    lemma_LeftMoversEnabledBeforeCrash(rr, clrr);\n    lemma_RightMoverCrashPreservation(rr, clrr);\n    lemma_LeftMoverSelfCrashPreservation(rr, clrr);\n    lemma_ActionSequencesLiftable(rr, clrr);\n  }\n\n}\n"
  },
  {
    "path": "Armada/strategies/reduction/RefinementViaReductionSpec.i.dfy",
    "content": "/////////////////////////////////////////////////////////////////////////////////////////////////////\n//\n// This file is the specification for a request to perform refinement via a Cohen-Lamport reduction\n// on a behavior. Such a reduction takes a behavior where some states are in phase 1 or 2, and\n// returns a behavior satisfying a higher-level specification that lacks those phases.  It does\n// so by lifting sequences of steps in the lower-level specification to atomic steps in the\n// higher-level specification.\n//\n// To use this specification, first create a request r of type RefinementViaReductionRequest.  Then,\n// prove that it's a valid request, i.e., that ValidRefinementViaReductionRequest(r).  Finally, call\n// lemma_PerformRefinementViaReduction (in RefinementViaReduction.i.dfy).\n//\n// The request specification allows behaviors that crash as their final step.  But, the request\n// specification also demands that action sequences be reducible if they crash in the middle, i.e.,\n// even if the actor performing those action sequences executes a step that crashes while in phase 1\n// or 2.\n//\n/////////////////////////////////////////////////////////////////////////////////////////////////////\n\ninclude \"../../util/collections/seqs.s.dfy\"\ninclude \"../../spec/refinement.s.dfy\"\ninclude \"../refinement/GeneralRefinementLemmas.i.dfy\"\ninclude \"../refinement/RefinementConvolution.i.dfy\"\ninclude \"../refinement/AnnotatedBehavior.i.dfy\"\ninclude \"../invariants.i.dfy\"\n\nmodule RefinementViaReductionSpecModule {\n\n  import opened util_collections_seqs_s\n  import opened GeneralRefinementModule\n  import opened GeneralRefinementLemmasModule\n  import opened RefinementConvolutionModule\n  import opened AnnotatedBehaviorModule\n  import opened InvariantsModule\n\n  datatype RefinementViaReductionRequest<!State(==), !Actor(==), !LStep, !HStep> = RefinementViaReductionRequest(\n    lspec:AnnotatedBehaviorSpec<State, LStep>,\n    hspec:AnnotatedBehaviorSpec<State, HStep>,\n    relation:RefinementRelation<State, State>,\n    idmap:LStep->Actor,\n    phase1:(State, Actor)->bool,\n    phase2:(State, Actor)->bool,\n    crashed:State->bool\n    )\n\n  predicate PhaseUnaffectedByOtherActors<State(!new), Actor(!new), LStep(!new), HStep>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>\n    )\n  {\n    && (forall s, s', step, actor :: ActionTuple(s, s', step) in rr.lspec.next && rr.idmap(step) != actor ==>\n                              (rr.phase1(s, actor) <==> rr.phase1(s', actor)))\n    && (forall s, s', step, actor :: ActionTuple(s, s', step) in rr.lspec.next && rr.idmap(step) != actor ==>\n                              (rr.phase2(s, actor) <==> rr.phase2(s', actor)))\n  }\n\n  predicate CantGoDirectlyFromPhase2ToPhase1<State(!new), Actor, LStep(!new), HStep>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>\n    )\n  {\n    forall s, s', step :: ActionTuple(s, s', step) in rr.lspec.next && rr.phase2(s, rr.idmap(step)) ==> !rr.phase1(s', rr.idmap(step))\n  }\n\n  predicate RightMoversPreserveStateRefinement<State(!new), Actor, LStep(!new), HStep>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>\n    )\n  {\n    forall s, s', step ::\n      && ActionTuple(s, s', step) in rr.lspec.next\n      && rr.phase1(s', rr.idmap(step))\n      && !rr.crashed(s')\n      ==> RefinementPair(s', s) in rr.relation\n  }\n\n  predicate LeftMoversPreserveStateRefinement<State(!new), Actor, LStep(!new), HStep>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>\n    )\n  {\n    forall s, s', step ::\n      && ActionTuple(s, s', step) in rr.lspec.next\n      && rr.phase2(s, rr.idmap(step))\n      ==> RefinementPair(s, s') in rr.relation\n  }\n\n  predicate PostCrashStepsStutter<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>\n    )\n  {\n    forall s, s', step :: rr.crashed(s) && ActionTuple(s, s', step) in rr.lspec.next ==> s' == s\n  }\n\n  predicate RightMoversCommuteConditions<State(!new), Actor(!new), LStep(!new), HStep>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    initial_state:State,\n    state_after_right_mover:State,\n    state_after_both_steps:State,\n    right_mover:LStep,\n    other_step:LStep\n    )\n  {\n    && initial_state in AnnotatedReachables(rr.lspec)\n    && ActionTuple(initial_state, state_after_right_mover, right_mover) in rr.lspec.next\n    && ActionTuple(state_after_right_mover, state_after_both_steps, other_step) in rr.lspec.next\n    && rr.idmap(right_mover) != rr.idmap(other_step)\n    && rr.phase1(state_after_right_mover, rr.idmap(right_mover))\n    && !rr.crashed(state_after_both_steps)\n  }\n\n  predicate RightMoversCommute<State(!new), Actor(!new), LStep(!new), HStep>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>\n    )\n  {\n    forall initial_state, state_after_right_mover, state_after_both_steps, right_mover, other_step\n      {:trigger RightMoversCommuteConditions(rr, initial_state, state_after_right_mover, state_after_both_steps, right_mover, other_step)}\n      :: RightMoversCommuteConditions(rr, initial_state, state_after_right_mover, state_after_both_steps, right_mover, other_step)\n      ==> exists new_middle_state, other_step', right_mover' ::\n            && ActionTuple(initial_state, new_middle_state, other_step') in rr.lspec.next\n            && ActionTuple(new_middle_state, state_after_both_steps, right_mover') in rr.lspec.next\n            && rr.idmap(other_step') == rr.idmap(other_step)\n            && rr.idmap(right_mover') == rr.idmap(right_mover)\n  }\n\n  predicate LeftMoversCommuteConditions<State(!new), Actor(!new), LStep(!new), HStep>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    initial_state:State,\n    state_after_other_step:State,\n    state_after_both_steps:State,\n    other_step:LStep,\n    left_mover:LStep\n    )\n  {\n    && initial_state in AnnotatedReachables(rr.lspec)\n    && ActionTuple(initial_state, state_after_other_step, other_step) in rr.lspec.next\n    && ActionTuple(state_after_other_step, state_after_both_steps, left_mover) in rr.lspec.next\n    && rr.idmap(other_step) != rr.idmap(left_mover)\n    && rr.phase2(state_after_other_step, rr.idmap(left_mover))\n    && !rr.crashed(state_after_both_steps)\n  }\n\n  predicate LeftMoversCommute<State(!new), Actor(!new), LStep(!new), HStep>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>\n    )\n  {\n    forall initial_state, state_after_other_step, state_after_both_steps, other_step, left_mover\n      {:trigger LeftMoversCommuteConditions(rr, initial_state, state_after_other_step, state_after_both_steps, other_step, left_mover)}\n      :: LeftMoversCommuteConditions(rr, initial_state, state_after_other_step, state_after_both_steps, other_step, left_mover)\n      ==> exists new_middle_state, left_mover', other_step' ::\n            && ActionTuple(initial_state, new_middle_state, left_mover') in rr.lspec.next\n            && ActionTuple(new_middle_state, state_after_both_steps, other_step') in rr.lspec.next\n            && rr.idmap(left_mover') == rr.idmap(left_mover)\n            && rr.idmap(other_step') == rr.idmap(other_step)\n  }\n\n  predicate LeftMoversAlwaysEnabledConditions<State(!new), Actor(!new), LStep(!new), HStep>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    s:State,\n    actor:Actor\n    )\n  {\n    && s in AnnotatedReachables(rr.lspec)\n    && rr.phase2(s, actor)\n    && !rr.crashed(s)\n  }\n\n  predicate LeftMoversAlwaysEnabled<State(!new), Actor(!new), LStep(!new), HStep>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>\n    )\n  {\n    forall s, actor\n      {:trigger LeftMoversAlwaysEnabledConditions(rr, s, actor)}\n      :: LeftMoversAlwaysEnabledConditions(rr, s, actor)\n      ==> exists states, trace ::\n             && StateNextSeq(states, trace, rr.lspec.next)\n             && states[0] == s\n             && (rr.crashed(last(states)) || !rr.phase2(last(states), actor))\n             && (forall i :: 0 <= i < |states|-1 ==> rr.phase2(states[i], actor))\n             && (forall step :: step in trace ==> rr.idmap(step) == actor)\n  }\n\n  predicate LeftMoversEnabledBeforeCrashConditions<State(!new), Actor(!new), LStep(!new), HStep>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    initial_state:State,\n    post_crash_state:State,\n    crash_step:LStep,\n    actor:Actor\n    )\n  {\n    && initial_state in AnnotatedReachables(rr.lspec)\n    && ActionTuple(initial_state, post_crash_state, crash_step) in rr.lspec.next\n    && !rr.crashed(initial_state)\n    && rr.crashed(post_crash_state)\n    && rr.idmap(crash_step) != actor\n    && rr.phase2(initial_state, actor)\n  }\n\n  predicate LeftMoversEnabledBeforeCrash<State(!new), Actor(!new), LStep(!new), HStep>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>\n    )\n  {\n    forall initial_state, post_crash_state, crash_step, actor\n      {:trigger LeftMoversEnabledBeforeCrashConditions(rr, initial_state, post_crash_state, crash_step, actor)}\n      :: LeftMoversEnabledBeforeCrashConditions(rr, initial_state, post_crash_state, crash_step, actor)\n      ==> exists states, trace, crash_step', post_crash_state' ::\n             && StateNextSeq(states, trace, rr.lspec.next)\n             && states[0] == initial_state\n             && !rr.crashed(last(states))\n             && !rr.phase2(last(states), actor)\n             && (forall i :: 0 <= i < |states|-1 ==> rr.phase2(states[i], actor))\n             && (forall step :: step in trace ==> rr.idmap(step) == actor)\n             && ActionTuple(last(states), post_crash_state', crash_step') in rr.lspec.next\n             && rr.idmap(crash_step') == rr.idmap(crash_step)\n             && rr.crashed(post_crash_state')\n             && RefinementPair(post_crash_state, post_crash_state') in rr.relation\n  }\n\n  predicate RightMoverCrashPreservationConditions<State(!new), Actor(!new), LStep(!new), HStep>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    initial_state:State,\n    state_after_right_mover:State,\n    state_after_both_steps:State,\n    right_mover:LStep,\n    other_step:LStep\n    )\n  {\n    && initial_state in AnnotatedReachables(rr.lspec)\n    && ActionTuple(initial_state, state_after_right_mover, right_mover) in rr.lspec.next\n    && ActionTuple(state_after_right_mover, state_after_both_steps, other_step) in rr.lspec.next\n    && !rr.crashed(initial_state)\n    && !rr.crashed(state_after_right_mover)\n    && rr.crashed(state_after_both_steps)\n    && rr.phase1(state_after_right_mover, rr.idmap(right_mover))\n    && rr.idmap(right_mover) != rr.idmap(other_step)\n  }\n\n  predicate RightMoverCrashPreservation<State(!new), Actor(!new), LStep(!new), HStep>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>\n    )\n  {\n    forall initial_state, state_after_right_mover, state_after_both_steps, right_mover, other_step\n      {:trigger RightMoverCrashPreservationConditions(rr, initial_state, state_after_right_mover, state_after_both_steps, right_mover,\n                                                      other_step)}\n      :: RightMoverCrashPreservationConditions(rr, initial_state, state_after_right_mover, state_after_both_steps, right_mover, other_step) \n      ==> exists other_step', state_after_other_step' ::\n            && rr.idmap(other_step') == rr.idmap(other_step)\n            && ActionTuple(initial_state, state_after_other_step', other_step') in rr.lspec.next\n            && rr.crashed(state_after_other_step')\n            && RefinementPair(state_after_both_steps, state_after_other_step') in rr.relation\n  }\n\n  predicate LeftMoverSelfCrashPreservationConditions<State(!new), Actor(!new), LStep(!new), HStep>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    initial_state:State,\n    state_after_other_step:State,\n    state_after_both_steps:State,\n    other_step:LStep,\n    left_mover:LStep\n    )\n  {\n    && initial_state in AnnotatedReachables(rr.lspec)\n    && ActionTuple(initial_state, state_after_other_step, other_step) in rr.lspec.next\n    && ActionTuple(state_after_other_step, state_after_both_steps, left_mover) in rr.lspec.next\n    && !rr.crashed(initial_state)\n    && !rr.crashed(state_after_other_step)\n    && rr.crashed(state_after_both_steps)\n    && rr.phase2(state_after_other_step, rr.idmap(left_mover))\n    && rr.idmap(left_mover) != rr.idmap(other_step)\n  }\n\n  predicate LeftMoverSelfCrashPreservation<State(!new), Actor(!new), LStep(!new), HStep>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>\n    )\n  {\n    forall initial_state, state_after_other_step, state_after_both_steps, other_step, left_mover\n      {:trigger LeftMoverSelfCrashPreservationConditions(rr, initial_state, state_after_other_step, state_after_both_steps, other_step,\n                left_mover)}\n      :: LeftMoverSelfCrashPreservationConditions(rr, initial_state, state_after_other_step, state_after_both_steps, other_step, left_mover)\n      ==> exists left_mover', state_after_left_mover' ::\n            && rr.idmap(left_mover') == rr.idmap(left_mover)\n            && ActionTuple(initial_state, state_after_left_mover', left_mover') in rr.lspec.next\n            && rr.crashed(state_after_left_mover')\n            && RefinementPair(state_after_both_steps, state_after_left_mover') in rr.relation\n  }\n\n  predicate ActionSequencesLiftableConditions<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>,\n    states:seq<State>,\n    trace:seq<LStep>,\n    actor:Actor\n    )\n  {\n    && StateNextSeq(states, trace, rr.lspec.next)\n    && (forall step :: step in trace ==> rr.idmap(step) == actor)\n    && |states| > 1\n    && !rr.phase1(states[0], actor)\n    && !rr.phase2(states[0], actor)\n    && (var s := last(states); !rr.crashed(s) ==> !rr.phase1(s, actor) && !rr.phase2(s, actor))\n    && (forall i :: 0 <= i < |trace| ==> !rr.crashed(states[i]))\n    && (forall i :: 0 < i < |trace| ==> var s := states[i]; rr.phase1(s, actor) || rr.phase2(s, actor))\n  }\n\n  predicate ActionSequencesLiftable<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>\n    )\n  {\n    forall states, trace, actor\n      {:trigger ActionSequencesLiftableConditions(rr, states, trace, actor)}\n      :: ActionSequencesLiftableConditions(rr, states, trace, actor)\n      ==> exists hstep :: ActionTuple(states[0], last(states), hstep) in rr.hspec.next\n  }\n\n  predicate ValidRefinementViaReductionRequest<State(!new), Actor(!new), LStep(!new), HStep(!new)>(\n    rr:RefinementViaReductionRequest<State, Actor, LStep, HStep>\n    )\n  {\n    && RefinementRelationReflexive(rr.relation)\n    && RefinementRelationTransitive(rr.relation)\n    && rr.hspec.init == rr.lspec.init\n    && (forall s, actor :: s in rr.lspec.init ==> !rr.phase1(s, actor) && !rr.phase2(s, actor))\n    && (forall s, actor :: rr.phase1(s, actor) ==> !rr.phase2(s, actor))\n    && CantGoDirectlyFromPhase2ToPhase1(rr)\n    && PhaseUnaffectedByOtherActors(rr)\n    && RightMoversPreserveStateRefinement(rr)\n    && LeftMoversPreserveStateRefinement(rr)\n    && PostCrashStepsStutter(rr)\n    && RightMoversCommute(rr)\n    && LeftMoversCommute(rr)\n    && LeftMoversAlwaysEnabled(rr)\n    && LeftMoversEnabledBeforeCrash(rr)\n    && RightMoverCrashPreservation(rr)\n    && LeftMoverSelfCrashPreservation(rr)\n    && ActionSequencesLiftable(rr)\n  }\n}\n"
  },
  {
    "path": "Armada/strategies/refinement/AnnotatedBehavior.i.dfy",
    "content": "include \"../../spec/refinement.s.dfy\"\ninclude \"../../util/collections/seqs.i.dfy\"\n\nmodule AnnotatedBehaviorModule {\n\n    import opened GeneralRefinementModule\n    import opened util_collections_seqs_s\n    import opened util_collections_seqs_i\n\n    datatype ActionTuple<State, Step> = ActionTuple(s:State, s':State, step:Step)\n\n    datatype AnnotatedBehavior<State, Step> = AnnotatedBehavior(\n        states:seq<State>,\n        trace:seq<Step>\n        )\n\n    datatype AnnotatedBehaviorSpec<!State(==), !Step(==)> = AnnotatedBehaviorSpec(\n        init:iset<State>,\n        next:iset<ActionTuple<State, Step>>\n        )\n\n    predicate StateNextSeq<State, Step>(\n        states:seq<State>,\n        trace:seq<Step>,\n        next:iset<ActionTuple<State, Step>>\n        )\n    {\n        && |states| == |trace| + 1\n        && (forall i {:trigger ActionTuple(states[i], states[i+1], trace[i]) in next} :: 0 <= i < |trace| ==> ActionTuple(states[i], states[i+1], trace[i]) in next)\n    }\n\n    predicate AnnotatedBehaviorSatisfiesSpec<State, Step>(\n        b:AnnotatedBehavior<State, Step>,\n        spec:AnnotatedBehaviorSpec<State, Step>\n        )\n    {\n        && StateNextSeq(b.states, b.trace, spec.next)\n        && b.states[0] in spec.init\n    }\n\n    function AnnotatedBehaviorSpecToSpec<State(!new), Step(!new)>(spec:AnnotatedBehaviorSpec<State, Step>) : Spec<State>\n    {\n        Spec(spec.init,\n             iset s, s', step | ActionTuple(s, s', step) in spec.next :: StatePair(s, s'))\n    }\n\n    predicate AnnotatedBehaviorSpecRefinesSpec<State(!new), Step(!new)>(\n        aspec:AnnotatedBehaviorSpec<State, Step>,\n        spec:Spec<State>\n        )\n    {\n        && aspec.init <= spec.init\n        && (forall s, s', step :: ActionTuple(s, s', step) in aspec.next ==> StatePair(s, s') in spec.next)\n    }\n\n    predicate SpecRefinesAnnotatedBehaviorSpec<State(!new), Step(!new)>(\n        spec:Spec<State>,\n        aspec:AnnotatedBehaviorSpec<State, Step>\n        )\n    {\n        && spec.init <= aspec.init\n        && (forall s, s' :: StatePair(s, s') in spec.next ==> exists step:Step :: ActionTuple(s, s', step) in aspec.next)\n    }\n\n    lemma lemma_AnnotatedBehaviorSpecEquivalentToConvertedSelf<State, Step>(spec:AnnotatedBehaviorSpec<State, Step>)\n        ensures AnnotatedBehaviorSpecRefinesSpec(spec, AnnotatedBehaviorSpecToSpec(spec));\n        ensures SpecRefinesAnnotatedBehaviorSpec(AnnotatedBehaviorSpecToSpec(spec), spec);\n    {\n    }\n\n    lemma lemma_BehaviorInAnnotatedBehaviorSatisfiesSpec<State, Step>(\n        ab:AnnotatedBehavior<State, Step>,\n        aspec:AnnotatedBehaviorSpec<State, Step>,\n        spec:Spec<State>\n        )\n        requires AnnotatedBehaviorSatisfiesSpec(ab, aspec);\n        requires AnnotatedBehaviorSpecRefinesSpec(aspec, spec);\n        ensures  BehaviorSatisfiesSpec(ab.states, spec);\n    {\n        forall i | 0 <= i < |ab.trace|\n            ensures ActionTuple(ab.states[i], ab.states[i+1], ab.trace[i]) in aspec.next\n        {\n        }\n    }\n\n    lemma lemma_BehaviorInAnnotatedBehaviorSatisfiesConvertedSpec<State(!new), Step(!new)>(\n        b:AnnotatedBehavior<State, Step>,\n        spec:AnnotatedBehaviorSpec<State, Step>\n        )\n        requires AnnotatedBehaviorSatisfiesSpec(b, spec);\n        ensures  BehaviorSatisfiesSpec(b.states, AnnotatedBehaviorSpecToSpec(spec));\n    {\n        lemma_AnnotatedBehaviorSpecEquivalentToConvertedSelf(spec);\n        lemma_BehaviorInAnnotatedBehaviorSatisfiesSpec(b, spec, AnnotatedBehaviorSpecToSpec(spec));\n    }\n\n    lemma lemma_CreateAnnotatedBehaviorFromBehavior<State, Step>(\n        b:seq<State>,\n        spec:Spec<State>,\n        aspec:AnnotatedBehaviorSpec<State, Step>\n        ) returns (\n        ab:AnnotatedBehavior<State, Step>\n        )\n        requires SpecRefinesAnnotatedBehaviorSpec(spec, aspec);\n        requires BehaviorSatisfiesSpec(b, spec);\n        ensures  ab.states == b;\n        ensures  AnnotatedBehaviorSatisfiesSpec(ab, aspec);\n    {\n        if |b| == 1 {\n            ab := AnnotatedBehavior(b, []);\n        }\n        else {\n            var ab_prefix := lemma_CreateAnnotatedBehaviorFromBehavior(all_but_last(b), spec, aspec);\n            var penult := |b|-2;\n            assert StatePair(b[penult], b[penult+1]) in spec.next;\n            var step :| ActionTuple(b[|b|-2], b[|b|-2+1], step) in aspec.next;\n            ab := AnnotatedBehavior(b, ab_prefix.trace + [step]);\n        }\n    }\n\n    lemma lemma_ExtendStateNextSeqRight<State, Step>(\n        states:seq<State>,\n        trace:seq<Step>,\n        next:iset<ActionTuple<State, Step>>,\n        new_state:State,\n        new_step:Step\n        )\n        requires StateNextSeq(states, trace, next)\n        requires ActionTuple(last(states), new_state, new_step) in next\n        ensures  StateNextSeq(states + [new_state], trace + [new_step], next)\n    {\n    }\n\n    lemma lemma_ExtendStateNextSeqLeft<State, Step>(\n        states:seq<State>,\n        trace:seq<Step>,\n        next:iset<ActionTuple<State, Step>>,\n        new_state:State,\n        new_step:Step\n        )\n        requires StateNextSeq(states, trace, next)\n        requires ActionTuple(new_state, states[0], new_step) in next\n        ensures  StateNextSeq([new_state] + states, [new_step] + trace, next)\n    {\n        var states' := [new_state] + states;\n        var trace' := [new_step] + trace;\n        forall i {:trigger ActionTuple(states'[i], states'[i+1], trace'[i]) in next} | 0 <= i < |trace'|\n            ensures ActionTuple(states'[i], states'[i+1], trace'[i]) in next\n        {\n            if i == 0 {\n                assert states'[i] == new_state;\n                assert states'[i+1] == states[0];\n                assert trace'[i] == new_step;\n            }\n            else {\n                var iminus := i-1;\n                assert states'[i] == states[iminus];\n                assert states'[i+1] == states[iminus+1];\n                assert trace'[i] == trace[iminus];\n                assert ActionTuple(states[iminus], states[iminus+1], trace[iminus]) in next;\n            }\n        }\n    }\n\n    lemma lemma_ReduceStateNextSeqRight<State, Step>(\n        states:seq<State>,\n        trace:seq<Step>,\n        next:iset<ActionTuple<State, Step>>\n        )\n        requires StateNextSeq(states, trace, next)\n        requires |trace| > 0\n        ensures  StateNextSeq(all_but_last(states), all_but_last(trace), next)\n    {\n    }\n\n    lemma lemma_ReduceStateNextSeqLeft<State, Step>(\n        states:seq<State>,\n        trace:seq<Step>,\n        next:iset<ActionTuple<State, Step>>\n        )\n        requires StateNextSeq(states, trace, next)\n        requires |trace| > 0\n        ensures  StateNextSeq(states[1..], trace[1..], next)\n    {\n        var states' := states[1..];\n        var trace' := trace[1..];\n        forall i {:trigger ActionTuple(states'[i], states'[i+1], trace'[i]) in next} | 0 <= i < |trace'|\n            ensures ActionTuple(states'[i], states'[i+1], trace'[i]) in next\n        {\n            var iplus := i+1;\n            assert states'[i] == states[iplus];\n            assert states'[i+1] == states[iplus+1];\n            assert trace'[i] == trace[iplus];\n            assert ActionTuple(states[iplus], states[iplus+1], trace[iplus]) in next;\n        }\n    }\n\n    lemma lemma_ReplaceStateOnlyStateNextSeqRight<State, Step>(\n        states:seq<State>,\n        trace:seq<Step>,\n        next:iset<ActionTuple<State, Step>>,\n        new_state:State\n        )\n        requires StateNextSeq(states, trace, next)\n        requires |states| > 1\n        requires ActionTuple(states[|states|-2], new_state, last(trace)) in next\n        ensures  StateNextSeq(all_but_last(states) + [new_state], trace, next)\n    {\n    }\n\n    lemma lemma_ReplaceStateNextSeqRight<State, Step>(\n        states:seq<State>,\n        trace:seq<Step>,\n        next:iset<ActionTuple<State, Step>>,\n        new_state:State,\n        new_step:Step\n        )\n        requires StateNextSeq(states, trace, next)\n        requires |states| > 1\n        requires ActionTuple(states[|states|-2], new_state, new_step) in next\n        ensures  StateNextSeq(all_but_last(states) + [new_state], all_but_last(trace) + [new_step], next)\n    {\n    }\n\n    lemma lemma_TakeStateNextSeq<State, Step>(\n        states:seq<State>,\n        trace:seq<Step>,\n        next:iset<ActionTuple<State, Step>>,\n        pos:int\n        )\n        requires StateNextSeq(states, trace, next)\n        requires |trace| > 0\n        requires 0 <= pos <= |trace|\n        ensures  StateNextSeq(states[..pos+1], trace[..pos], next)\n    {\n    }\n\n    lemma lemma_DropStateNextSeq<State, Step>(\n        states:seq<State>,\n        trace:seq<Step>,\n        next:iset<ActionTuple<State, Step>>,\n        pos:int\n        )\n        requires StateNextSeq(states, trace, next)\n        requires |trace| > 0\n        requires 0 <= pos <= |trace|\n        ensures  StateNextSeq(states[pos..], trace[pos..], next)\n    {\n        var states' := states[pos..];\n        var trace' := trace[pos..];\n        forall i {:trigger ActionTuple(states'[i], states'[i+1], trace'[i]) in next} | 0 <= i < |trace'|\n            ensures ActionTuple(states'[i], states'[i+1], trace'[i]) in next\n        {\n            var iplus := i+pos;\n            lemma_IndexIntoDrop(states, pos, i);\n            lemma_IndexIntoDrop(states, pos, i+1);\n            lemma_IndexIntoDrop(trace, pos, i);\n            assert states'[i] == states[iplus];\n            assert states'[i+1] == states[iplus+1];\n            assert trace'[i] == trace[iplus];\n            assert ActionTuple(states[iplus], states[iplus+1], trace[iplus]) in next;\n        }\n    }\n\n}\n"
  },
  {
    "path": "Armada/strategies/refinement/GeneralRefinementLemmas.i.dfy",
    "content": "include \"../../spec/refinement.s.dfy\"\ninclude \"../../util/collections/seqs.i.dfy\"\n\nmodule GeneralRefinementLemmasModule {\n\n  import opened util_collections_seqs_i\n  import opened util_collections_seqs_s\n  import opened GeneralRefinementModule\n\n  predicate RefinementRelationReflexive<T(!new)>(relation:RefinementRelation<T, T>)\n  {\n    forall x :: RefinementPair(x, x) in relation\n  }\n\n  lemma lemma_IfRefinementRelationReflexiveThenBehaviorRefinesItself<T>(b:seq<T>, relation:RefinementRelation<T, T>)\n    requires |b| > 0\n    requires RefinementRelationReflexive(relation)\n    ensures  BehaviorRefinesBehavior(b, b, relation)\n  {\n    var lh_map := ConvertMapToSeq(|b|, map i | 0 <= i < |b| :: RefinementRange(i, i));\n    assert BehaviorRefinesBehaviorUsingRefinementMap(b, b, relation, lh_map);\n  }\n\n  lemma lemma_LaterFirstBeyondEarlierLastInRefinementMap(\n    low_level_behavior_size:int,\n    high_level_behavior_size:int,\n    lh_map:RefinementMap,\n    i:int,\n    j:int\n    )\n    requires IsValidRefinementMap(low_level_behavior_size, high_level_behavior_size, lh_map)\n    requires 0 <= i <= j < low_level_behavior_size\n    ensures  i < j ==> lh_map[i].last <= lh_map[j].first\n    decreases j - i\n  {\n    if j == i || j == i + 1 {\n      return;\n    }\n    \n    lemma_LaterFirstBeyondEarlierLastInRefinementMap(low_level_behavior_size, high_level_behavior_size, lh_map, i+1, j);\n  }\n\n  lemma lemma_GetPrefixOfBehaviorsAndRefinementMap<L, H>(\n    lb:seq<L>,\n    hb:seq<H>,\n    lh_map:RefinementMap,\n    lh_relation:RefinementRelation<L, H>,\n    new_low_behavior_size:int\n    ) returns (\n    lb':seq<L>,\n    hb':seq<H>,\n    lh_map':RefinementMap\n    )\n    requires BehaviorRefinesBehaviorUsingRefinementMap(lb, hb, lh_relation, lh_map)\n    requires 0 < new_low_behavior_size <= |lb|\n    ensures  |lb'| == new_low_behavior_size\n    ensures  lb' == lb[..new_low_behavior_size]\n    ensures  lh_map' == lh_map[..new_low_behavior_size]\n    ensures  new_low_behavior_size > 0 ==> 0 <= lh_map[new_low_behavior_size-1].last < |hb|\n    ensures  if new_low_behavior_size > 0 then hb' == hb[ .. lh_map[new_low_behavior_size-1].last + 1] else hb' == []\n    ensures  BehaviorRefinesBehaviorUsingRefinementMap(lb', hb', lh_relation, lh_map')\n  {\n    if new_low_behavior_size == |lb| {\n      lb' := lb;\n      hb' := hb;\n      lh_map' := lh_map;\n      return;\n    }\n    \n    var j := new_low_behavior_size - 1;\n    assert lh_map[j].last == lh_map[j+1].first || lh_map[j].last == lh_map[j+1].first - 1;\n    \n    lb' := lb[..new_low_behavior_size];\n    lh_map' := lh_map[..new_low_behavior_size];\n    hb' := hb[.. last(lh_map').last+1];\n    \n    forall pair | pair in lh_map'\n      ensures 0 <= pair.first <= pair.last < |hb'|;\n    {\n      var i :| 0 <= i < |lh_map'| && pair == lh_map'[i];\n      lemma_LaterFirstBeyondEarlierLastInRefinementMap(|lb|, |hb|, lh_map, i, j);\n    }\n    \n    assert BehaviorRefinesBehaviorUsingRefinementMap(lb', hb', lh_relation, lh_map');\n  }\n  \n  lemma lemma_RefinementMapIsReversible(\n    low_level_behavior_size:int,\n    high_level_behavior_size:int,\n    lh_map:RefinementMap,\n    hpos:int\n    ) returns (\n    lpos:int\n    )\n    requires IsValidRefinementMap(low_level_behavior_size, high_level_behavior_size, lh_map)\n    requires 0 <= hpos < high_level_behavior_size\n    ensures  0 <= lpos < low_level_behavior_size\n    ensures  lh_map[lpos].first <= hpos <= lh_map[lpos].last\n  {\n    if last(lh_map).first <= hpos <= last(lh_map).last {\n      lpos := |lh_map| - 1;\n      return;\n    }\n    \n    var j := |lh_map| - 2;\n    assert lh_map[j+1].first == lh_map[j].last || lh_map[j+1].first == lh_map[j].last + 1;\n    \n    var new_low_level_behavior_size := low_level_behavior_size - 1;\n    var lh_map' := lh_map[..new_low_level_behavior_size];\n    var new_high_level_behavior_size := last(lh_map').last + 1;\n    \n    forall pair | pair in lh_map'\n      ensures 0 <= pair.first <= pair.last < new_high_level_behavior_size;\n    {\n      var i :| 0 <= i < |lh_map'| && pair == lh_map'[i];\n      lemma_LaterFirstBeyondEarlierLastInRefinementMap(low_level_behavior_size, high_level_behavior_size, lh_map, i, j);\n    }\n    \n    assert IsValidRefinementMap(new_low_level_behavior_size, new_high_level_behavior_size, lh_map');\n    lpos := lemma_RefinementMapIsReversible(new_low_level_behavior_size, new_high_level_behavior_size, lh_map', hpos);\n  }\n  \n  lemma lemma_ConcatenatingBehaviorsPreservesRefinement<L, H>(\n    lb1:seq<L>,\n    lb2:seq<L>,\n    hb1:seq<H>,\n    hb2:seq<H>,\n    relation:RefinementRelation<L, H>\n    )\n    requires BehaviorRefinesBehavior(lb1, hb1, relation)\n    requires BehaviorRefinesBehavior(lb2, hb2, relation)\n    ensures  BehaviorRefinesBehavior(lb1 + lb2, hb1 + hb2, relation)\n  {\n    var lh_map1 :| BehaviorRefinesBehaviorUsingRefinementMap(lb1, hb1, relation, lh_map1);\n    var lh_map2 :| BehaviorRefinesBehaviorUsingRefinementMap(lb2, hb2, relation, lh_map2);\n    var lh_map2_adjusted := MapSeqToSeq(lh_map2, (x:RefinementRange) => RefinementRange(x.first + |hb1|, x.last + |hb1|));\n    var lh_map := lh_map1 + lh_map2_adjusted;\n    var lb := lb1 + lb2;\n    var hb := hb1 + hb2;\n    assert BehaviorRefinesBehaviorUsingRefinementMap(lb, hb, relation, lh_map);\n  }\n\n  lemma lemma_ExtendBehaviorRefinesBehaviorRightOne<T>(lb:seq<T>, hb:seq<T>, relation:RefinementRelation<T, T>, s:T)\n    requires BehaviorRefinesBehavior(lb, hb, relation)\n    requires RefinementRelationReflexive(relation)\n    ensures  BehaviorRefinesBehavior(lb + [s], hb + [s], relation)\n  {\n    var lh_map :| BehaviorRefinesBehaviorUsingRefinementMap(lb, hb, relation, lh_map);\n\n    var lb' := lb + [s];\n    var hb' := hb + [s];\n    var lh_map' := lh_map + [RefinementRange(|hb|, |hb|)];\n    assert BehaviorRefinesBehaviorUsingRefinementMap(lb', hb', relation, lh_map');\n  }\n\n  lemma lemma_ExtendBehaviorRefinesBehaviorRightOne_LH<T, U>(lb:seq<T>, hb:seq<U>, relation:RefinementRelation<T, U>, ls:T, hs:U)\n    requires BehaviorRefinesBehavior(lb, hb, relation)\n    requires RefinementPair(ls, hs) in relation\n    ensures  BehaviorRefinesBehavior(lb + [ls], hb + [hs], relation)\n  {\n    var lh_map :| BehaviorRefinesBehaviorUsingRefinementMap(lb, hb, relation, lh_map);\n\n    var lb' := lb + [ls];\n    var hb' := hb + [hs];\n    var lh_map' := lh_map + [RefinementRange(|hb|, |hb|)];\n    assert BehaviorRefinesBehaviorUsingRefinementMap(lb', hb', relation, lh_map');\n  }\n\n  lemma lemma_ExtendBehaviorRefinesBehaviorRightOne_LStutter<T, U>(lb:seq<T>, hb:seq<U>, relation:RefinementRelation<T, U>, hs:U)\n    requires BehaviorRefinesBehavior(lb, hb, relation)\n    requires RefinementPair(last(lb), hs) in relation\n    ensures  BehaviorRefinesBehavior(lb, hb + [hs], relation)\n  {\n    var lh_map :| BehaviorRefinesBehaviorUsingRefinementMap(lb, hb, relation, lh_map);\n    var last_range := last(lh_map);\n    var last_range' := last_range.(last := |hb|);\n\n    var hb' := hb + [hs];\n    var lh_map' := lh_map[|lh_map|-1 := last_range'];\n    assert BehaviorRefinesBehaviorUsingRefinementMap(lb, hb', relation, lh_map');\n  }\n\n  lemma lemma_ExtendBehaviorRefinesBehaviorRightOne_HStutter<T, U>(lb:seq<T>, hb:seq<U>, relation:RefinementRelation<T, U>, ls:T)\n    requires BehaviorRefinesBehavior(lb, hb, relation)\n    requires RefinementPair(ls, last(hb)) in relation\n    ensures  BehaviorRefinesBehavior(lb + [ls], hb, relation)\n  {\n    var lh_map :| BehaviorRefinesBehaviorUsingRefinementMap(lb, hb, relation, lh_map);\n\n    var lb' := lb + [ls];\n    var lh_map' := lh_map + [RefinementRange(|hb|-1, |hb|-1)];\n    assert BehaviorRefinesBehaviorUsingRefinementMap(lb', hb, relation, lh_map');\n  }\n\n  lemma lemma_ExtendBehaviorRefinesBehaviorLeftOne<T>(lb:seq<T>, hb:seq<T>, relation:RefinementRelation<T, T>, s:T)\n    requires BehaviorRefinesBehavior(lb, hb, relation)\n    requires RefinementRelationReflexive(relation)\n    ensures  BehaviorRefinesBehavior([s] + lb, [s] + hb, relation)\n  {\n    var lh_map :| BehaviorRefinesBehaviorUsingRefinementMap(lb, hb, relation, lh_map);\n\n    var lb' := [s] + lb;\n    var hb' := [s] + hb;\n    var lh_map' := [RefinementRange(0, 0)] + MapSeqToSeq(lh_map, (x:RefinementRange) => RefinementRange(x.first+1, x.last+1));\n    assert BehaviorRefinesBehaviorUsingRefinementMap(lb', hb', relation, lh_map');\n  }\n\n  lemma lemma_ExtendBehaviorRefinesBehaviorLeftOne_LH<T, U>(lb:seq<T>, hb:seq<U>, relation:RefinementRelation<T, U>, ls:T, hs:U)\n    requires BehaviorRefinesBehavior(lb, hb, relation)\n    requires RefinementPair(ls, hs) in relation\n    ensures  BehaviorRefinesBehavior([ls] + lb, [hs] + hb, relation)\n  {\n    var lh_map :| BehaviorRefinesBehaviorUsingRefinementMap(lb, hb, relation, lh_map);\n\n    var lb' := [ls] + lb;\n    var hb' := [hs] + hb;\n    var lh_map' := [RefinementRange(0, 0)] + MapSeqToSeq(lh_map, (x:RefinementRange) => RefinementRange(x.first+1, x.last+1));\n    assert BehaviorRefinesBehaviorUsingRefinementMap(lb', hb', relation, lh_map');\n  }\n\n  lemma lemma_ExtendBehaviorRefinesBehaviorRight<T>(lb:seq<T>, hb:seq<T>, relation:RefinementRelation<T, T>, eb:seq<T>)\n    requires BehaviorRefinesBehavior(lb, hb, relation)\n    requires RefinementRelationReflexive(relation);\n    ensures  BehaviorRefinesBehavior(lb + eb, hb + eb, relation)\n    decreases |eb|\n  {\n    if |eb| == 0 {\n      assert lb + eb == lb;\n      assert hb + eb == hb;\n    }\n    else {\n      lemma_ExtendBehaviorRefinesBehaviorRightOne(lb, hb, relation, eb[0]);\n      lemma_ExtendBehaviorRefinesBehaviorRight(lb + [eb[0]], hb + [eb[0]], relation, eb[1..]);\n\n      lemma_SequenceIsCarPlusCdr(eb);\n      lemma_SequenceConcatenationAssociative(lb, [eb[0]], eb[1..]);\n      lemma_SequenceConcatenationAssociative(hb, [eb[0]], eb[1..]);\n    }\n  }\n\n  lemma lemma_ExtendBehaviorRefinesBehaviorLeft<T>(lb:seq<T>, hb:seq<T>, relation:RefinementRelation<T, T>, eb:seq<T>)\n    requires BehaviorRefinesBehavior(lb, hb, relation)\n    requires RefinementRelationReflexive(relation);\n    ensures  BehaviorRefinesBehavior(eb + lb, eb + hb, relation)\n    decreases |eb|\n  {\n    if |eb| == 0 {\n      assert eb + lb == lb;\n      assert eb + hb == hb;\n    }\n    else {\n      lemma_ExtendBehaviorRefinesBehaviorLeftOne(lb, hb, relation, last(eb));\n      lemma_ExtendBehaviorRefinesBehaviorLeft([last(eb)] + lb, [last(eb)] + hb, relation, all_but_last(eb));\n\n      lemma_AllButLastPlusLastIsSeq(eb);\n      lemma_SequenceConcatenationAssociative(all_but_last(eb), [last(eb)], lb);\n      lemma_SequenceConcatenationAssociative(all_but_last(eb), [last(eb)], hb);\n    }\n  }\n\n  lemma lemma_ExtendBehaviorSatisfiesSpecRightOne<State>(b:seq<State>, spec:Spec<State>, s':State)\n    requires BehaviorSatisfiesSpec(b, spec)\n    requires StatePair(last(b), s') in spec.next\n    ensures  BehaviorSatisfiesSpec(b + [s'], spec)\n  {\n  }\n    \n\n}\n"
  },
  {
    "path": "Armada/strategies/refinement/RefinementConvolution.i.dfy",
    "content": "include \"GeneralRefinementLemmas.i.dfy\"\n\nmodule RefinementConvolutionModule {\n\n  import opened GeneralRefinementLemmasModule\n  import opened GeneralRefinementModule\n  import opened util_collections_seqs_s\n\n  predicate RefinementRelationsConvolve<L(!new), M(!new), H(!new)>(\n    lm_relation:RefinementRelation<L, M>,\n    mh_relation:RefinementRelation<M, H>,\n    lh_relation:RefinementRelation<L, H>\n    )\n  {\n    forall l, m, h :: RefinementPair(l, m) in lm_relation && RefinementPair(m, h) in mh_relation ==> RefinementPair(l, h) in lh_relation\n  }\n\n  predicate RefinementRelationsQuadruplyConvolve<S1(!new), S2(!new), S3(!new), S4(!new), S5(!new)>(\n    r12: RefinementRelation<S1, S2>,\n    r23: RefinementRelation<S2, S3>,\n    r34: RefinementRelation<S3, S4>,\n    r45: RefinementRelation<S4, S5>,\n    r15: RefinementRelation<S1, S5>\n    )\n  {\n    forall s1, s2, s3, s4, s5 ::\n      && RefinementPair(s1, s2) in r12\n      && RefinementPair(s2, s3) in r23\n      && RefinementPair(s3, s4) in r34\n      && RefinementPair(s4, s5) in r45\n      ==> RefinementPair(s1, s5) in r15\n  }\n\n  predicate RefinementRelationTransitive<T(!new)>(relation:RefinementRelation<T, T>)\n  {\n    RefinementRelationsConvolve(relation, relation, relation)\n  }\n\n  predicate BehaviorRefinesWhatOtherBehaviorRefines<LState(!new), MState(!new), HState(!new)>(\n    lb:seq<LState>,\n    mb:seq<MState>,\n    lh_relation:RefinementRelation<LState, HState>,\n    mh_relation:RefinementRelation<MState, HState>\n    )\n  {\n    forall hb :: BehaviorRefinesBehavior(mb, hb, mh_relation) ==> BehaviorRefinesBehavior(lb, hb, lh_relation)\n  }\n\n  lemma lemma_RefinementConvolution<L(!new), M(!new), H(!new)>(\n    lb:seq<L>,\n    mb:seq<M>,\n    hb:seq<H>,\n    lm_relation:RefinementRelation<L, M>,\n    mh_relation:RefinementRelation<M, H>,\n    lh_relation:RefinementRelation<L, H>,\n    lm_map:RefinementMap,\n    mh_map:RefinementMap\n    ) returns (\n    lh_map:RefinementMap\n    )\n    requires BehaviorRefinesBehaviorUsingRefinementMap(lb, mb, lm_relation, lm_map);\n    requires BehaviorRefinesBehaviorUsingRefinementMap(mb, hb, mh_relation, mh_map);\n    requires RefinementRelationsConvolve(lm_relation, mh_relation, lh_relation);\n    ensures  BehaviorRefinesBehaviorUsingRefinementMap(lb, hb, lh_relation, lh_map);\n  {\n    if |lb| == 0 {\n      lh_map := [];\n      return;\n    }\n\n    if |lb| == 1 {\n      lh_map := [ RefinementRange(0, |hb|-1) ];\n      assert IsValidRefinementMap(|lb|, |hb|, lh_map);\n      forall i, j {:trigger RefinementPair(lb[i], hb[j]) in lh_relation} |\n        0 <= i < |lb| && lh_map[i].first <= j <= lh_map[i].last && 0 <= j < |hb|\n        ensures RefinementPair(lb[i], hb[j]) in lh_relation;\n      {\n        var k := lemma_RefinementMapIsReversible(|mb|, |hb|, mh_map, j);\n        assert lm_map[i].first <= k <= lm_map[i].last;\n        assert RefinementPair(lb[i], mb[k]) in lm_relation;\n        assert RefinementPair(mb[k], hb[j]) in mh_relation;\n      }\n      return;\n    }\n\n    var lb', mb', lm_map' := lemma_GetPrefixOfBehaviorsAndRefinementMap(lb, mb, lm_map, lm_relation, |lb|-1);\n    var mb'', hb', mh_map' := lemma_GetPrefixOfBehaviorsAndRefinementMap(mb, hb, mh_map, mh_relation, |mb'|);\n    assert mb'' == mb';\n\n    var lh_map' := lemma_RefinementConvolution(lb', mb', hb', lm_relation, mh_relation, lh_relation, lm_map', mh_map');\n\n    var second_from_last := |lm_map|-2;\n    assert    lm_map[second_from_last].last == lm_map[second_from_last+1].first\n           || lm_map[second_from_last].last + 1 == lm_map[second_from_last+1].first;\n\n    var new_first;\n    var witness_to_correspondence;\n\n    if lm_map[second_from_last].last == lm_map[second_from_last+1].first {\n      new_first := last(lh_map').last;\n      witness_to_correspondence := lm_map[second_from_last].last;\n    }\n    else {\n      assert lm_map[second_from_last].last + 1 == lm_map[second_from_last+1].first;\n      var k := lm_map[second_from_last].last;\n      assert mh_map[k].last == mh_map[k+1].first || mh_map[k].last + 1 == mh_map[k+1].first;\n      \n      if mh_map[k].last == mh_map[k+1].first {\n        new_first := last(lh_map').last;\n        witness_to_correspondence := k+1;\n      }\n      else {\n        assert mh_map[k].last + 1 == mh_map[k+1].first;\n        new_first := last(lh_map').last + 1;\n        witness_to_correspondence := lm_map[second_from_last+1].first;\n      }\n    }\n    \n    assert new_first == last(lh_map').last || new_first == last(lh_map').last + 1;\n    assert lm_map[second_from_last+1].first <= witness_to_correspondence <= lm_map[second_from_last+1].last;\n    assert mh_map[witness_to_correspondence].first <= new_first <= mh_map[witness_to_correspondence].last;\n    \n    lh_map := lh_map' + [ RefinementRange(new_first, |hb|-1) ];\n    \n    forall i | 0 <= i < |lh_map|-1\n      ensures lh_map[i+1].first == lh_map[i].last || lh_map[i+1].first == lh_map[i].last + 1\n    {\n      if i < |lh_map|-2 {\n        assert lh_map[i] == lh_map'[i];\n        assert lh_map[i+1] == lh_map'[i+1];\n        assert lh_map'[i+1].first == lh_map'[i].last || lh_map'[i+1].first == lh_map'[i].last + 1;\n      }\n      else {\n        assert lh_map[i] == lh_map'[i];\n        assert lh_map[i+1].first == new_first;\n        assert lh_map[i+1].last == |hb|-1;\n        assert lh_map[i+1].first == lh_map[i].last || lh_map[i+1].first == lh_map[i].last + 1;\n      }\n    }\n      \n    assert IsValidRefinementMap(|lb|, |hb|, lh_map);\n\n    forall i, j {:trigger RefinementPair(lb[i], hb[j]) in lh_relation} |\n      0 <= i < |lb| && lh_map[i].first <= j <= lh_map[i].last\n      ensures RefinementPair(lb[i], hb[j]) in lh_relation;\n    {\n      if i < |lb'| {\n        assert lh_map'[i] == lh_map[i];\n        assert lh_map'[i].first <= j <= lh_map'[i].last;\n        assert RefinementPair(lb'[i], hb'[j]) in lh_relation;\n      }\n      else {\n        assert lm_map[i] == lm_map[second_from_last+1];\n        assert lm_map[i].first <= witness_to_correspondence <= lm_map[i].last;\n        var mid := lemma_RefinementMapIsReversible(|mb|, |hb|, mh_map, j);\n        assert mh_map[mid].first <= j <= mh_map[mid].last;\n        \n        if mid < witness_to_correspondence {\n          lemma_LaterFirstBeyondEarlierLastInRefinementMap(|mb|, |hb|, mh_map, mid, witness_to_correspondence);\n          assert new_first <= j <= mh_map[mid].last <= mh_map[witness_to_correspondence].first <= new_first;\n          assert j == new_first;\n          assert RefinementPair(lb[i], mb[witness_to_correspondence]) in lm_relation;\n          assert RefinementPair(mb[witness_to_correspondence], hb[j]) in mh_relation;\n        }\n        else {\n          assert RefinementPair(lb[i], mb[mid]) in lm_relation;\n          assert RefinementPair(mb[mid], hb[j]) in mh_relation;\n        }\n      }\n    }\n\n    assert BehaviorRefinesBehaviorUsingRefinementMap(lb, hb, lh_relation, lh_map);\n  }\n\n  lemma lemma_RefinementConvolutionPure<L(!new), M(!new), H(!new)>(\n    lb:seq<L>,\n    mb:seq<M>,\n    hb:seq<H>,\n    lm_relation:RefinementRelation<L, M>,\n    mh_relation:RefinementRelation<M, H>,\n    lh_relation:RefinementRelation<L, H>\n    )\n    requires BehaviorRefinesBehavior(lb, mb, lm_relation);\n    requires BehaviorRefinesBehavior(mb, hb, mh_relation);\n    requires RefinementRelationsConvolve(lm_relation, mh_relation, lh_relation);\n    ensures  BehaviorRefinesBehavior(lb, hb, lh_relation);\n  {\n    var lm_map :| BehaviorRefinesBehaviorUsingRefinementMap(lb, mb, lm_relation, lm_map);\n    var mh_map :| BehaviorRefinesBehaviorUsingRefinementMap(mb, hb, mh_relation, mh_map);\n    var lh_map := lemma_RefinementConvolution(lb, mb, hb, lm_relation, mh_relation, lh_relation, lm_map, mh_map);\n  }\n  \n  lemma lemma_RefinementConvolutionTransitive<T(!new)>(\n    lb:seq<T>,\n    mb:seq<T>,\n    hb:seq<T>,\n    relation:RefinementRelation<T, T>\n    )\n    requires BehaviorRefinesBehavior(lb, mb, relation);\n    requires BehaviorRefinesBehavior(mb, hb, relation);\n    requires RefinementRelationTransitive(relation);\n    ensures  BehaviorRefinesBehavior(lb, hb, relation);\n  {\n    lemma_RefinementConvolutionPure(lb, mb, hb, relation, relation, relation);\n  }\n\n  lemma lemma_EstablishBehaviorRefinesWhatOtherBehaviorRefines<LState(!new), MState(!new), HState(!new)>(\n    lb:seq<LState>,\n    mb:seq<MState>,\n    lm_relation:RefinementRelation<LState, MState>,\n    mh_relation:RefinementRelation<MState, HState>,\n    lh_relation:RefinementRelation<LState, HState>\n    )\n    requires BehaviorRefinesBehavior(lb, mb, lm_relation);\n    requires RefinementRelationsConvolve(lm_relation, mh_relation, lh_relation);\n    ensures  BehaviorRefinesWhatOtherBehaviorRefines(lb, mb, lh_relation, mh_relation);\n  {\n    forall hb | BehaviorRefinesBehavior(mb, hb, mh_relation)\n      ensures BehaviorRefinesBehavior(lb, hb, lh_relation);\n    {\n      lemma_RefinementConvolutionPure(lb, mb, hb, lm_relation, mh_relation, lh_relation);\n    }\n  }\n\n  lemma lemma_SpecRefinesSpecConvolution<S1(!new), S2(!new), S3(!new)>(\n    spec1: Spec<S1>,\n    spec2: Spec<S2>,\n    spec3: Spec<S3>,\n    r12: RefinementRelation<S1, S2>,\n    r23: RefinementRelation<S2, S3>,\n    r13: RefinementRelation<S1, S3>\n    )\n    requires SpecRefinesSpec(spec1, spec2, r12)\n    requires SpecRefinesSpec(spec2, spec3, r23)\n    requires RefinementRelationsConvolve(r12, r23, r13)\n    ensures  SpecRefinesSpec(spec1, spec3, r13)\n  {\n    forall b1 | BehaviorSatisfiesSpec(b1, spec1)\n      ensures BehaviorRefinesSpec(b1, spec3, r13)\n    {\n      assert BehaviorRefinesSpec(b1, spec2, r12);\n      var b2 :| BehaviorRefinesBehavior(b1, b2, r12) && BehaviorSatisfiesSpec(b2, spec2);\n      assert BehaviorRefinesSpec(b2, spec3, r23);\n      var b3 :| BehaviorRefinesBehavior(b2, b3, r23) && BehaviorSatisfiesSpec(b3, spec3);\n      lemma_RefinementConvolutionPure(b1, b2, b3, r12, r23, r13);\n    }\n  }\n    \n  lemma lemma_SpecRefinesSpecQuadrupleConvolution<S1(!new), S2(!new), S3(!new), S4(!new), S5(!new)>(\n    spec1: Spec<S1>,\n    spec2: Spec<S2>,\n    spec3: Spec<S3>,\n    spec4: Spec<S4>,\n    spec5: Spec<S5>,\n    r12: RefinementRelation<S1, S2>,\n    r23: RefinementRelation<S2, S3>,\n    r34: RefinementRelation<S3, S4>,\n    r45: RefinementRelation<S4, S5>,\n    r15: RefinementRelation<S1, S5>\n    )\n    requires SpecRefinesSpec(spec1, spec2, r12)\n    requires SpecRefinesSpec(spec2, spec3, r23)\n    requires SpecRefinesSpec(spec3, spec4, r34)\n    requires SpecRefinesSpec(spec4, spec5, r45)\n    requires RefinementRelationsQuadruplyConvolve(r12, r23, r34, r45, r15)\n    ensures  SpecRefinesSpec(spec1, spec5, r15)\n  {\n    var r13 := iset s1, s2, s3 | RefinementPair(s1, s2) in r12 && RefinementPair(s2, s3) in r23 :: RefinementPair(s1, s3);\n    var r14 := iset s1, s3, s4 | RefinementPair(s1, s3) in r13 && RefinementPair(s3, s4) in r34 :: RefinementPair(s1, s4);\n\n    forall b1 | BehaviorSatisfiesSpec(b1, spec1)\n      ensures BehaviorRefinesSpec(b1, spec5, r15)\n    {\n      assert BehaviorRefinesSpec(b1, spec2, r12);\n      var b2 :| BehaviorRefinesBehavior(b1, b2, r12) && BehaviorSatisfiesSpec(b2, spec2);\n      var b3 :| BehaviorRefinesBehavior(b2, b3, r23) && BehaviorSatisfiesSpec(b3, spec3);\n      lemma_RefinementConvolutionPure(b1, b2, b3, r12, r23, r13);\n      var b4 :| BehaviorRefinesBehavior(b3, b4, r34) && BehaviorSatisfiesSpec(b4, spec4);\n      lemma_RefinementConvolutionPure(b1, b3, b4, r13, r34, r14);\n      var b5 :| BehaviorRefinesBehavior(b4, b5, r45) && BehaviorSatisfiesSpec(b5, spec5);\n      lemma_RefinementConvolutionPure(b1, b4, b5, r14, r45, r15);\n      assert BehaviorRefinesBehavior(b1, b5, r15);\n    }\n  }\n}\n"
  },
  {
    "path": "Armada/strategies/starweakening/StarWeakening.i.dfy",
    "content": "include \"StarWeakeningSpec.i.dfy\"\ninclude \"../../util/collections/seqs.i.dfy\"\ninclude \"../../spec/refinement.s.dfy\"\n\nmodule StarWeakeningModule {\n\n    import opened StarWeakeningSpecModule\n    import opened AnnotatedBehaviorModule\n    import opened InvariantsModule\n    import opened GeneralRefinementModule\n    import opened util_collections_seqs_i\n    import opened util_collections_seqs_s\n    \n    lemma lemma_LRefinesH<LState, HState, LStep, HStep> (\n      lb:AnnotatedBehavior<LState, LStep>,\n      hb:AnnotatedBehavior<HState, HStep>,\n      wr:StarWeakeningRequest<LState, HState, LStep, HStep>,\n      lh_map:RefinementMap)\n      \n      requires ValidStarWeakeningRequest(wr)\n      requires AnnotatedBehaviorSatisfiesSpec(lb, wr.lspec)\n      requires hb.states == MapSeqToSeq(lb.states, wr.converter);\n      requires |lh_map| == |lb.states|\n      requires forall i :: 0 <= i < |lh_map| ==> lh_map[i] == RefinementRange(i, i)\n      ensures  BehaviorRefinesBehaviorUsingRefinementMap(lb.states, hb.states, wr.relation, lh_map)\n    {\n      assert hb.states == MapSeqToSeq(lb.states, wr.converter);\n      lemma_InvariantHoldsAtStep(lb, 0, wr.lspec, wr.inv);\n      var i := 0;\n      while i < |lb.states|\n        invariant 0 <= i <= |lb.states|\n        invariant forall j :: 0 <= j < i ==>  RefinementPair(lb.states[j], hb.states[j]) in wr.relation;\n      {\n        lemma_InvariantHoldsAtStep(lb, i, wr.lspec, wr.inv);\n        assert RefinementPair(lb.states[i], hb.states[i]) in wr.relation;\n        i := i + 1;\n      }\n    }\n\n    lemma lemma_PerformStarWeakening<LState, HState, LStep, HStep>(\n        wr:StarWeakeningRequest<LState, HState, LStep, HStep>,\n        lb:AnnotatedBehavior<LState, LStep>\n    )\n    returns (\n        hb:AnnotatedBehavior<HState, HStep>\n    )\n      requires ValidStarWeakeningRequest(wr)\n      requires AnnotatedBehaviorSatisfiesSpec(lb, wr.lspec)\n      ensures  hb.states == MapSeqToSeq(lb.states, wr.converter)\n      ensures  AnnotatedBehaviorSatisfiesSpec(hb, wr.hspec)\n      ensures  BehaviorRefinesBehavior(lb.states, hb.states, wr.relation)\n    {\n      var hstates := [wr.converter(lb.states[0])];\n      var htrace := [];\n      var lh_map := [RefinementRange(0, 0)];\n      var pos := 0;\n\n      lemma_InvariantHoldsAtStep(lb, 0, wr.lspec, wr.inv);\n\n      while pos < |lb.states| - 1\n        invariant 0 <= pos < |lb.states|\n            invariant |htrace| == |hstates|-1\n            invariant hstates[0] in wr.hspec.init\n            invariant forall i :: 0 <= i < |htrace| ==> ActionTuple(hstates[i], hstates[i+1], htrace[i]) in wr.hspec.next\n            invariant last(hstates) == wr.converter(lb.states[pos])\n            invariant hstates == MapSeqToSeq(lb.states[..pos + 1], wr.converter)\n            invariant forall i :: 0 <= i < |lh_map| ==> lh_map[i] == RefinementRange(i, i)\n            invariant |lh_map| == pos + 1\n      {\n        lemma_InvariantHoldsAtStep(lb, pos, wr.lspec, wr.inv);\n        lemma_InvariantHoldsAtStep(lb, pos+1, wr.lspec, wr.inv);\n        var ls := lb.states[pos];\n        var ls' := lb.states[pos+1];\n        var lstep := lb.trace[pos];\n        assert ActionTuple(ls, ls', lstep) in wr.lspec.next;\n        assert ls in wr.inv;\n\n        var hstep := wr.step_refiner(ls, lstep);\n        htrace := htrace + [hstep];\n        hstates := hstates + [wr.converter(ls')];\n        assert hstates == MapSeqToSeq(lb.states[..pos + 2], wr.converter);\n          \n        lh_map := lh_map + [RefinementRange(|hstates|-1, |hstates|-1)];\n        pos := pos + 1;\n      }\n\n      hb := AnnotatedBehavior(hstates, htrace);\n      lemma_LRefinesH(lb, hb, wr, lh_map);\n    }\n\n}\n\n"
  },
  {
    "path": "Armada/strategies/starweakening/StarWeakeningSpec.i.dfy",
    "content": "include \"../refinement/AnnotatedBehavior.i.dfy\"\ninclude \"../../spec/refinement.s.dfy\"\ninclude \"../invariants.i.dfy\"\n\nmodule StarWeakeningSpecModule {\n\n    import opened AnnotatedBehaviorModule\n    import opened InvariantsModule\n    import opened GeneralRefinementModule\n\n    \n    datatype StarWeakeningRequest<!LState(==), HState(==), !LStep(==), HStep(==)> =\n        StarWeakeningRequest(\n            lspec:AnnotatedBehaviorSpec<LState, LStep>,\n            hspec:AnnotatedBehaviorSpec<HState, HStep>,\n            relation:RefinementRelation<LState, HState>,\n            inv:iset<LState>,\n            converter:(LState)->HState,\n            step_refiner:(LState, LStep) --> HStep\n            )\n    \n    predicate ConvertingSatisfiesRelation<LState(!new), HState, LStep, HStep>(wr:StarWeakeningRequest<LState, HState, LStep, HStep>)\n    {\n        forall ls :: ls in wr.inv ==> RefinementPair(ls, wr.converter(ls)) in wr.relation\n    }\n\n    predicate AllActionsLiftableStarWeakened<LState(!new), HState(!new), LStep(!new), HStep(!new)>(wr:StarWeakeningRequest<LState, HState, LStep, HStep>)\n    {\n     \n        forall s, s', lstep ::\n            && ActionTuple(s, s', lstep) in wr.lspec.next\n            && s in wr.inv\n            ==>  wr.step_refiner.requires(s, lstep) && ActionTuple(wr.converter(s), wr.converter(s'), wr.step_refiner(s, lstep)) in wr.hspec.next\n    }\n\n    predicate InitStatesEquivalent<LState(!new), HState(!new), LStep(!new), HStep(!new)>(wr:StarWeakeningRequest<LState, HState, LStep, HStep>)\n    {\n      forall initial_ls | initial_ls in wr.lspec.init ::\n        wr.converter(initial_ls) in wr.hspec.init\n    }\n\n    predicate ValidStarWeakeningRequest<LState, HState, LStep, HStep>(wr:StarWeakeningRequest<LState, HState, LStep, HStep>)\n    {\n      && InitStatesEquivalent(wr)\n      && IsInvariantOfSpec(wr.inv, wr.lspec)\n      && AllActionsLiftableStarWeakened(wr)\n      && ConvertingSatisfiesRelation(wr)\n    }\n\n}\n"
  },
  {
    "path": "Armada/strategies/tsoelimination/TSOElimination.i.dfy",
    "content": "include \"TSOEliminationLemmas.i.dfy\"\n\nmodule TSOEliminationModule {\n\n    import opened AnnotatedBehaviorModule\n    import opened GeneralRefinementModule\n    import opened InvariantsModule\n    import opened util_collections_seqs_s\n    import opened TSOEliminationSpecModule\n    import opened TSOEliminationLemmasModule\n\n    lemma lemma_PerformTSOElimination<LState, HState, ThreadID, LStep, HStep>(\n        ter:TSOEliminationRequest<LState, HState, ThreadID, LStep, HStep>,\n        lb:AnnotatedBehavior<LState, LStep>\n        ) returns (\n        hb:AnnotatedBehavior<HState, HStep>\n        )\n        requires ValidTSOEliminationRequest(ter)\n        requires AnnotatedBehaviorSatisfiesSpec(lb, ter.lspec)\n        ensures  BehaviorRefinesBehavior(lb.states, hb.states, ter.relation)\n        ensures  AnnotatedBehaviorSatisfiesSpec(hb, ter.hspec)\n    {\n        var hstates := [ter.initial_state_refiner(lb.states[0])];\n        var htrace := [];\n        var lh_map := [RefinementRange(0, 0)];\n        var pos := 0;\n\n        lemma_InvariantPredicateHoldsAtStep(lb, 0, ter.lspec, ter.inv);\n\n        while pos < |lb.states| - 1\n            invariant 0 <= pos < |lb.states|\n            invariant |htrace| == |hstates|-1\n            invariant hstates[0] in ter.hspec.init\n            invariant forall i :: 0 <= i < |htrace| ==> ActionTuple(hstates[i], hstates[i+1], htrace[i]) in ter.hspec.next\n            invariant ter.intermediate_relation(lb.states[pos], last(hstates))\n            invariant BehaviorRefinesBehaviorUsingRefinementMap(lb.states[..pos+1], hstates, ter.relation, lh_map)\n        {\n            hstates, htrace, lh_map := lemma_PerformOneStepOfTSOElimination(ter, lb, pos, hstates, htrace, lh_map);\n            pos := pos + 1;\n        }\n\n        hb := AnnotatedBehavior(hstates, htrace);\n        assert lb.states[..pos+1] == lb.states;\n        assert BehaviorRefinesBehaviorUsingRefinementMap(lb.states, hb.states, ter.relation, lh_map);\n    }\n\n}\n"
  },
  {
    "path": "Armada/strategies/tsoelimination/TSOEliminationLemmas.i.dfy",
    "content": "include \"TSOEliminationSpec.i.dfy\"\ninclude \"../refinement/RefinementConvolution.i.dfy\"\ninclude \"../../util/collections/seqs.i.dfy\"\n\nmodule TSOEliminationLemmasModule {\n\n    import opened TSOEliminationSpecModule\n    import opened util_collections_seqs_s\n    import opened util_collections_seqs_i\n    import opened AnnotatedBehaviorModule\n    import opened InvariantsModule\n    import opened GeneralRefinementModule\n    import opened RefinementConvolutionModule\n\n    lemma lemma_IntermediateRelationImpliesRefinementRelation<LState, HState, ThreadID, LStep, HStep>(\n        ter:TSOEliminationRequest<LState, HState, ThreadID, LStep, HStep>,\n        ls:LState,\n        hs:HState\n        )\n        requires ValidTSOEliminationRequest(ter)\n        requires ter.inv(ls)\n        requires ter.intermediate_relation(ls, hs)\n        ensures  RefinementPair(ls, hs) in ter.relation\n    {\n    }\n\n    lemma lemma_PerformOneStepOfTSOElimination<LState, HState, ThreadID, LStep, HStep>(\n        ter:TSOEliminationRequest<LState, HState, ThreadID, LStep, HStep>,\n        lb:AnnotatedBehavior<LState, LStep>,\n        pos:int,\n        hstates:seq<HState>,\n        htrace:seq<HStep>,\n        lh_map:RefinementMap\n        ) returns (\n        hstates':seq<HState>,\n        htrace':seq<HStep>,\n        lh_map':RefinementMap\n        )\n        requires ValidTSOEliminationRequest(ter)\n        requires AnnotatedBehaviorSatisfiesSpec(lb, ter.lspec)\n        requires 0 <= pos < |lb.states| - 1\n        requires |htrace| == |hstates|-1\n        requires hstates[0] in ter.hspec.init\n        requires forall i :: 0 <= i < |htrace| ==> ActionTuple(hstates[i], hstates[i+1], htrace[i]) in ter.hspec.next\n        requires ter.intermediate_relation(lb.states[pos], last(hstates))\n        requires BehaviorRefinesBehaviorUsingRefinementMap(lb.states[..pos+1], hstates, ter.relation, lh_map)\n        ensures  |htrace'| == |hstates'|-1\n        ensures  hstates'[0] == hstates[0]\n        ensures  forall i :: 0 <= i < |htrace'| ==> ActionTuple(hstates'[i], hstates'[i+1], htrace'[i]) in ter.hspec.next\n        ensures  ter.intermediate_relation(lb.states[pos+1], last(hstates'))\n        ensures  BehaviorRefinesBehaviorUsingRefinementMap(lb.states[..pos+2], hstates', ter.relation, lh_map')\n    {\n        var ls := lb.states[pos];\n        var ls' := lb.states[pos+1];\n        var lstep := lb.trace[pos];\n        var hs := last(hstates);\n        assert ActionTuple(ls, ls', lstep) in ter.lspec.next;\n\n        lemma_InvariantPredicateHoldsAtStep(lb, pos, ter.lspec, ter.inv);\n        assert ter.inv(ls);\n\n        assert ter.intermediate_relation(ls, hs);\n\n        var hstep := ter.step_refiner(ls, hs, lstep);\n        var hs' := ter.next_state(hs, hstep);\n        \n        assert ActionTuple(hs, hs', hstep) in ter.hspec.next;\n        assert ter.intermediate_relation(ls', hs');\n\n        hstates' := hstates + [hs'];\n        htrace' := htrace + [hstep];\n        lh_map' := lh_map + [RefinementRange(|hstates|, |hstates|)];\n\n        lemma_InvariantPredicateHoldsAtStep(lb, pos+1, ter.lspec, ter.inv);\n        lemma_IntermediateRelationImpliesRefinementRelation(ter, ls', hs');\n\n        var lstates := lb.states[..pos+2];\n        forall i, j {:trigger RefinementPair(lstates[i], hstates'[j]) in ter.relation}\n            | 0 <= i < |lstates| && lh_map'[i].first <= j <= lh_map'[i].last\n            ensures RefinementPair(lstates[i], hstates'[j]) in ter.relation\n        {\n        }\n\n        forall i | 0 <= i < |lh_map'|-1\n            ensures lh_map'[i+1].first == lh_map'[i].last || lh_map'[i+1].first == lh_map'[i].last + 1\n        {\n            if i < |lh_map|-1 {\n                assert lh_map'[i] == lh_map[i];\n                assert lh_map'[i+1] == lh_map[i+1];\n            }\n            else {\n                assert lh_map'[i] == last(lh_map);\n                assert last(lh_map).last == |hstates|-1;\n                assert lh_map'[i+1].first == |hstates|;\n                assert lh_map'[i+1].first == lh_map'[i].last + 1;\n            }\n        }\n\n        forall i | 0 <= i < |htrace'|\n            ensures ActionTuple(hstates'[i], hstates'[i+1], htrace'[i]) in ter.hspec.next\n        {\n            if i < |htrace| {\n                assert hstates'[i] == hstates[i];\n                assert hstates'[i+1] == hstates[i+1];\n                assert htrace'[i] == htrace[i];\n            }\n            else {\n                assert i == |htrace| == |hstates|-1;\n                assert hstates[i] == last(hstates);\n                assert hstates'[i] == hstates[i] == last(hstates) == hs;\n                assert hstates'[i+1] == hs';\n                assert htrace'[i] == hstep;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Armada/strategies/tsoelimination/TSOEliminationSpec.i.dfy",
    "content": "include \"../refinement/AnnotatedBehavior.i.dfy\"\ninclude \"../invariants.i.dfy\"\ninclude \"../../util/option.s.dfy\"\ninclude \"../../spec/refinement.s.dfy\"\n\nmodule TSOEliminationSpecModule {\n\n    import opened AnnotatedBehaviorModule\n    import opened InvariantsModule\n    import opened GeneralRefinementModule\n    import opened util_option_s\n\n    datatype TSOEliminationRequest<!LState(==), !HState(==), !ThreadID(==), !LStep(==), !HStep(==)> =\n        TSOEliminationRequest(\n            lspec:AnnotatedBehaviorSpec<LState, LStep>,\n            hspec:AnnotatedBehaviorSpec<HState, HStep>,\n            relation:RefinementRelation<LState, HState>,\n            inv:LState->bool,\n            initial_state_refiner:LState->HState,\n            step_refiner:(LState,HState,LStep)->HStep,\n            next_state:(HState,HStep)->HState, // computes next state given current state and next step\n            intermediate_relation:(LState, HState)->bool\n            )\n\n    predicate InitialConditionsHold<LState(!new), HState, ThreadID(!new), LStep, HStep>(\n        ter:TSOEliminationRequest<LState, HState, ThreadID, LStep, HStep>\n        )\n    {\n        forall ls :: ls in ter.lspec.init ==> var hs := ter.initial_state_refiner(ls);\n                                       && hs in ter.hspec.init\n                                       && ter.intermediate_relation(ls, hs)\n    }\n\n    predicate IntermediateRelationImpliesRelation<LState(!new), HState(!new), ThreadID, LStep, HStep>(\n        ter:TSOEliminationRequest<LState, HState, ThreadID, LStep, HStep>\n        )\n    {\n        forall ls, hs :: ter.intermediate_relation(ls, hs) ==> RefinementPair(ls, hs) in ter.relation\n    }\n\n    predicate StepMaintainsRelation<LState(!new), HState(!new), ThreadID(!new), LStep(!new), HStep(!new)>(\n        ter:TSOEliminationRequest<LState, HState, ThreadID, LStep, HStep>\n        )\n    {\n        forall ls, ls', lstep, hs ::\n            && ter.inv(ls)\n            && ter.intermediate_relation(ls, hs)\n            && ActionTuple(ls, ls', lstep) in ter.lspec.next\n            ==> var hstep := ter.step_refiner(ls, hs, lstep);\n                var hs' := ter.next_state(hs, hstep);\n                && ActionTuple(hs, hs', hstep) in ter.hspec.next\n                && ter.intermediate_relation(ls', hs')\n    }\n    \n    predicate ValidTSOEliminationRequest<LState(!new), HState(!new), ThreadID(!new), LStep(!new), HStep(!new)>(\n        ter:TSOEliminationRequest<LState, HState, ThreadID, LStep, HStep>\n        )\n    {\n        && IsInvariantPredicateOfSpec(ter.inv, ter.lspec)\n        && InitialConditionsHold(ter)\n        && IntermediateRelationImpliesRelation(ter)\n        && StepMaintainsRelation(ter)\n    }\n    \n}\n"
  },
  {
    "path": "Armada/strategies/varhiding/VarHiding.i.dfy",
    "content": "include \"VarHidingSpec.i.dfy\"\ninclude \"../refinement/RefinementConvolution.i.dfy\"\ninclude \"../../util/collections/seqs.i.dfy\"\n\nmodule VarHidingModule {\n\n    import opened VarHidingSpecModule\n    import opened util_collections_maps_s\n    import opened util_collections_seqs_s\n    import opened util_collections_seqs_i\n    import opened AnnotatedBehaviorModule\n    import opened InvariantsModule\n    import opened GeneralRefinementModule\n    import opened RefinementConvolutionModule\n\n    lemma lemma_PerformVarHiding<LState, HState, LStep, HStep>(\n        vr:VarHidingRequest<LState, HState, LStep, HStep>,\n        lb:AnnotatedBehavior<LState, LStep>\n        ) returns (\n        hb:AnnotatedBehavior<HState, HStep>\n        )\n        requires ValidVarHidingRequest(vr)\n        requires AnnotatedBehaviorSatisfiesSpec(lb, vr.lspec)\n        ensures  BehaviorRefinesBehavior(lb.states, hb.states, vr.relation)\n        ensures  AnnotatedBehaviorSatisfiesSpec(hb, vr.hspec)\n    {\n        var hstates := [vr.hider(lb.states[0])];\n        var htrace := [];\n        var lh_map := [RefinementRange(0, 0)];\n        var pos := 0;\n\n        lemma_InvariantPredicateHoldsAtStep(lb, 0, vr.lspec, vr.inv);\n\n        while pos < |lb.states| - 1\n            invariant 0 <= pos < |lb.states|\n            invariant |htrace| == |hstates|-1\n            invariant hstates[0] in vr.hspec.init\n            invariant forall i :: 0 <= i < |htrace| ==> ActionTuple(hstates[i], hstates[i+1], htrace[i]) in vr.hspec.next\n            invariant last(hstates) == vr.hider(lb.states[pos])\n            invariant BehaviorRefinesBehaviorUsingRefinementMap(lb.states[..pos+1], hstates, vr.relation, lh_map)\n        {\n            lemma_InvariantPredicateHoldsAtStep(lb, pos, vr.lspec, vr.inv);\n            lemma_InvariantPredicateHoldsAtStep(lb, pos+1, vr.lspec, vr.inv);\n            var s := lb.states[pos];\n            var s' := lb.states[pos+1];\n            var lstep := lb.trace[pos];\n            assert ActionTuple(s, s', lstep) in vr.lspec.next;\n            assert vr.inv(s);\n            if (vr.hider(s) != vr.hider(s')) {\n                var hstep := vr.step_refiner(s, lstep);\n                htrace := htrace + [hstep];\n                hstates := hstates + [vr.hider(s')];\n            }\n            lh_map := lh_map + [RefinementRange(|hstates|-1, |hstates|-1)];\n            pos := pos + 1;\n\n            var lstates := lb.states[..pos+1];\n            forall i, j {:trigger RefinementPair(lstates[i], hstates[j]) in vr.relation}\n                | 0 <= i < |lstates| && lh_map[i].first <= j <= lh_map[i].last\n                ensures RefinementPair(lstates[i], hstates[j]) in vr.relation\n            {\n            }\n        }\n\n        hb := AnnotatedBehavior(hstates, htrace);\n        assert lb.states[..pos+1] == lb.states;\n        assert BehaviorRefinesBehaviorUsingRefinementMap(lb.states, hb.states, vr.relation, lh_map);\n    }\n\n}\n"
  },
  {
    "path": "Armada/strategies/varhiding/VarHidingSpec.i.dfy",
    "content": "include \"../refinement/AnnotatedBehavior.i.dfy\"\ninclude \"../invariants.i.dfy\"\ninclude \"../../spec/refinement.s.dfy\"\ninclude \"../../util/collections/maps.s.dfy\"\n\nmodule VarHidingSpecModule {\n\n    import opened util_collections_maps_s\n    import opened AnnotatedBehaviorModule\n    import opened InvariantsModule\n    import opened GeneralRefinementModule\n\n    datatype VarHidingRequest<!LState(==), HState(==), !LStep(==), HStep(==)> =\n        VarHidingRequest(\n            lspec:AnnotatedBehaviorSpec<LState, LStep>,\n            hspec:AnnotatedBehaviorSpec<HState, HStep>,\n            relation:RefinementRelation<LState, HState>,\n            inv:LState->bool,\n            hider:LState->HState,\n            step_refiner:(LState,LStep)->HStep\n            )\n\n    predicate AllActionsLiftableWithoutVariable<LState(!new), HState(!new), LStep(!new), HStep(!new)>(\n        vr:VarHidingRequest<LState, HState, LStep, HStep>)\n    {\n        forall s, s', lstep ::\n            && ActionTuple(s, s', lstep) in vr.lspec.next\n            && vr.inv(s)\n            && vr.hider(s) != vr.hider(s')\n            ==> ActionTuple(vr.hider(s), vr.hider(s'), vr.step_refiner(s, lstep)) in vr.hspec.next\n    }\n\n    predicate HidingSatisfiesRelation<LState(!new), HState, LStep, HStep>(vr:VarHidingRequest<LState, HState, LStep, HStep>)\n    {\n        forall s :: vr.inv(s) ==> RefinementPair(s, vr.hider(s)) in vr.relation\n    }\n\n    predicate HidingPreservesInit<LState, HState, LStep, HStep>(vr:VarHidingRequest<LState, HState, LStep, HStep>)\n    {\n        forall s :: s in vr.lspec.init ==> vr.hider(s) in vr.hspec.init\n    }\n\n    predicate ValidVarHidingRequest<LState, HState, LStep, HStep>(vr:VarHidingRequest<LState, HState, LStep, HStep>)\n    {\n        && IsInvariantPredicateOfSpec(vr.inv, vr.lspec)\n        && AllActionsLiftableWithoutVariable(vr)\n        && HidingSatisfiesRelation(vr)\n        && HidingPreservesInit(vr)\n    }\n\n}\n"
  },
  {
    "path": "Armada/strategies/varintro/VarIntro.i.dfy",
    "content": "include \"VarIntroSpec.i.dfy\"\ninclude \"../refinement/RefinementConvolution.i.dfy\"\ninclude \"../../util/collections/seqs.s.dfy\"\ninclude \"../../util/collections/seqs.i.dfy\"\n\nmodule VarIntroModule {\n\n    import opened VarIntroSpecModule\n    import opened util_collections_maps_s\n    import opened util_collections_seqs_s\n    import opened util_collections_seqs_i\n    import opened AnnotatedBehaviorModule\n    import opened InvariantsModule\n    import opened GeneralRefinementModule\n    import opened RefinementConvolutionModule\n\n    lemma lemma_PerformVarIntroOneStepCaseAtNewInstruction<LState, HState, LStep, HStep>(\n        vr:VarIntroRequest<LState, HState, LStep, HStep>,\n        lb:AnnotatedBehavior<LState, LStep>,\n        hb:AnnotatedBehavior<HState, HStep>,\n        lh_map:RefinementMap,\n        pos:int\n        )\n        returns (\n        hb':AnnotatedBehavior<HState, HStep>,\n        lh_map':RefinementMap\n        )\n        requires ValidVarIntroRequest(vr)\n        requires AnnotatedBehaviorSatisfiesSpec(lb, vr.lspec)\n        requires 1 <= pos < |lb.states|\n        requires |hb.states| > 0\n        requires vr.at_new_instruction(last(hb.states))\n        requires BehaviorRefinesBehaviorUsingRefinementMap(lb.states[..pos], hb.states, vr.relation, lh_map)\n        requires AnnotatedBehaviorSatisfiesSpec(hb, vr.hspec)\n        requires lb.states[pos-1] == vr.hider(last(hb.states))\n        requires vr.inv(last(hb.states))\n        ensures  |hb'.states| > 0\n        ensures  BehaviorRefinesBehaviorUsingRefinementMap(lb.states[..pos+1], hb'.states, vr.relation, lh_map')\n        ensures  AnnotatedBehaviorSatisfiesSpec(hb', vr.hspec)\n        ensures  lb.states[pos] == vr.hider(last(hb'.states))\n        ensures  vr.inv(last(hb'.states))\n        decreases vr.progress_measure(last(hb.states)), 0\n    {\n        var hs := last(hb.states);\n        var hstep := vr.next_step(hs);\n        var hs_mid := vr.next_state(hs, hstep);\n        assert vr.inv(hs_mid);\n        assert vr.hider(hs) == vr.hider(hs_mid);\n        assert ActionTuple(hs, hs_mid, hstep) in vr.hspec.next;\n        assert 0 <= vr.progress_measure(hs_mid) < vr.progress_measure(hs);\n\n        var htrace_mid := hb.trace + [hstep];\n        var hstates_mid := hb.states + [hs_mid];\n        var hb_mid := AnnotatedBehavior(hstates_mid, htrace_mid);\n        var lh_map_mid := lh_map[|lh_map|-1 := last(lh_map).(last := |hb.states|)];\n        hb', lh_map' := lemma_PerformVarIntroOneStep(vr, lb, hb_mid, lh_map_mid, pos);\n    }\n\n    lemma lemma_PerformVarIntroOneStepCaseNotAtNewInstruction<LState, HState, LStep, HStep>(\n        vr:VarIntroRequest<LState, HState, LStep, HStep>,\n        lb:AnnotatedBehavior<LState, LStep>,\n        hb:AnnotatedBehavior<HState, HStep>,\n        lh_map:RefinementMap,\n        pos:int\n        )\n        returns (\n        hb':AnnotatedBehavior<HState, HStep>,\n        lh_map':RefinementMap\n        )\n        requires ValidVarIntroRequest(vr)\n        requires AnnotatedBehaviorSatisfiesSpec(lb, vr.lspec)\n        requires 1 <= pos < |lb.states|\n        requires |hb.states| > 0\n        requires !vr.at_new_instruction(last(hb.states))\n        requires BehaviorRefinesBehaviorUsingRefinementMap(lb.states[..pos], hb.states, vr.relation, lh_map)\n        requires AnnotatedBehaviorSatisfiesSpec(hb, vr.hspec)\n        requires lb.states[pos-1] == vr.hider(last(hb.states))\n        requires vr.inv(last(hb.states))\n        ensures  |hb'.states| > 0\n        ensures  BehaviorRefinesBehaviorUsingRefinementMap(lb.states[..pos+1], hb'.states, vr.relation, lh_map')\n        ensures  AnnotatedBehaviorSatisfiesSpec(hb', vr.hspec)\n        ensures  lb.states[pos] == vr.hider(last(hb'.states))\n        ensures  vr.inv(last(hb'.states))\n        decreases vr.progress_measure(last(hb.states))\n    {\n        var prev := pos-1;\n        var ls := lb.states[prev];\n        var ls' := lb.states[prev+1];\n        var lstep := lb.trace[prev];\n        assert ActionTuple(ls, ls', lstep) in vr.lspec.next;\n        var hs := last(hb.states);\n        var hstep := vr.step_mapper(lstep);\n        var hs' := vr.next_state(hs, hstep);\n        assert vr.inv(hs');\n        assert ls' == vr.hider(hs');\n        assert ActionTuple(hs, hs', hstep) in vr.hspec.next;\n        var htrace' := hb.trace + [hstep];\n        var hstates' := hb.states + [hs'];\n        lh_map' := lh_map + [RefinementRange(|hb.states|, |hb.states|)];\n        hb' := AnnotatedBehavior(hstates', htrace');\n\n        var lstates' := lb.states[..pos+1];\n        forall i, j {:trigger RefinementPair(lstates'[i], hstates'[j]) in vr.relation}\n            | 0 <= i < |lstates'| && lh_map'[i].first <= j <= lh_map'[i].last\n            ensures RefinementPair(lstates'[i], hstates'[j]) in vr.relation\n        {\n        }\n    }\n\n    lemma lemma_PerformVarIntroOneStep<LState, HState, LStep, HStep>(\n        vr:VarIntroRequest<LState, HState, LStep, HStep>,\n        lb:AnnotatedBehavior<LState, LStep>,\n        hb:AnnotatedBehavior<HState, HStep>,\n        lh_map:RefinementMap,\n        pos:int\n        )\n        returns (\n        hb':AnnotatedBehavior<HState, HStep>,\n        lh_map':RefinementMap\n        )\n        requires ValidVarIntroRequest(vr)\n        requires AnnotatedBehaviorSatisfiesSpec(lb, vr.lspec)\n        requires 1 <= pos < |lb.states|\n        requires |hb.states| > 0\n        requires BehaviorRefinesBehaviorUsingRefinementMap(lb.states[..pos], hb.states, vr.relation, lh_map)\n        requires AnnotatedBehaviorSatisfiesSpec(hb, vr.hspec)\n        requires lb.states[pos-1] == vr.hider(last(hb.states))\n        requires vr.inv(last(hb.states))\n        ensures  |hb'.states| > 0\n        ensures  BehaviorRefinesBehaviorUsingRefinementMap(lb.states[..pos+1], hb'.states, vr.relation, lh_map')\n        ensures  AnnotatedBehaviorSatisfiesSpec(hb', vr.hspec)\n        ensures  lb.states[pos] == vr.hider(last(hb'.states))\n        ensures  vr.inv(last(hb'.states))\n        decreases vr.progress_measure(last(hb.states)), 1\n    {\n        var ls := lb.states[pos-1];\n        var ls' := lb.states[pos-1+1];\n        var hs := last(hb.states);\n\n        if vr.at_new_instruction(hs) {\n            hb', lh_map' := lemma_PerformVarIntroOneStepCaseAtNewInstruction(vr, lb, hb, lh_map, pos);\n        }\n        else {\n            hb', lh_map' := lemma_PerformVarIntroOneStepCaseNotAtNewInstruction(vr, lb, hb, lh_map, pos);\n        }\n    }\n\n    lemma lemma_PerformVarIntro<LState, HState, LStep, HStep>(\n        vr:VarIntroRequest<LState, HState, LStep, HStep>,\n        lb:AnnotatedBehavior<LState, LStep>\n        ) returns (\n        hb:AnnotatedBehavior<HState, HStep>\n        )\n        requires ValidVarIntroRequest(vr)\n        requires AnnotatedBehaviorSatisfiesSpec(lb, vr.lspec)\n        ensures  BehaviorRefinesBehavior(lb.states, hb.states, vr.relation)\n        ensures  AnnotatedBehaviorSatisfiesSpec(hb, vr.hspec)\n    {\n        var ls := lb.states[0];\n        assert ls in vr.lspec.init;\n        var hs := vr.revealer(ls);\n        assert vr.hider(hs) == ls && vr.inv(hs) && hs in vr.hspec.init;\n        var hstates := [hs];\n        var htrace := [];\n        hb := AnnotatedBehavior(hstates, htrace);\n        var pos := 1;\n        var lh_map := [RefinementRange(0, 0)];\n\n        while pos < |lb.states|\n            invariant 1 <= pos <= |lb.states|\n            invariant |hb.states| > 0\n            invariant BehaviorRefinesBehaviorUsingRefinementMap(lb.states[..pos], hb.states, vr.relation, lh_map)\n            invariant AnnotatedBehaviorSatisfiesSpec(hb, vr.hspec)\n            invariant lb.states[pos-1] == vr.hider(last(hb.states))\n            invariant vr.inv(last(hb.states))\n        {\n            hb, lh_map := lemma_PerformVarIntroOneStep(vr, lb, hb, lh_map, pos);\n            pos := pos + 1;\n        }\n\n        assert BehaviorRefinesBehaviorUsingRefinementMap(lb.states, hb.states, vr.relation, lh_map);\n    }\n\n}\n"
  },
  {
    "path": "Armada/strategies/varintro/VarIntroSpec.i.dfy",
    "content": "include \"../refinement/AnnotatedBehavior.i.dfy\"\ninclude \"../invariants.i.dfy\"\ninclude \"../../spec/refinement.s.dfy\"\ninclude \"../../util/collections/maps.s.dfy\"\n\nmodule VarIntroSpecModule {\n\n    import opened util_collections_maps_s\n    import opened AnnotatedBehaviorModule\n    import opened InvariantsModule\n    import opened GeneralRefinementModule\n\n    datatype VarIntroRequest<!LState(==), !HState(==), !LStep(==), !HStep(==)> =\n        VarIntroRequest(\n            lspec:AnnotatedBehaviorSpec<LState, LStep>,\n            hspec:AnnotatedBehaviorSpec<HState, HStep>,\n            relation:RefinementRelation<LState, HState>,\n            inv:HState->bool,                  // invariant of the high-level state\n            hider:HState->LState,              // hides values of introduced variables\n            revealer:LState->HState,           // only matters for initial state, introduces values for introduced variables\n            step_mapper:LStep->HStep,          // maps a low-level step to a high-level one\n            next_state:(HState,HStep)->HState, // computes next state given current state and next step\n            at_new_instruction:HState->bool,   // whether the PC is just before a new instruction (an assignment to an introduced variable)\n            next_step:HState->HStep,           // only matters when at_new_instruction, returns the step for that new instruction\n            progress_measure:HState->int       // only matters when at_new_instruction, must decrease by executing the new instruction\n            )\n\n    predicate WhenAtNewInstructionNextStepMakesProgress<LState(!new), HState(!new), LStep(!new), HStep(!new)>(\n        vr:VarIntroRequest<LState, HState, LStep, HStep>)\n    {\n        forall hs :: vr.inv(hs) && vr.at_new_instruction(hs)\n                ==> var hstep := vr.next_step(hs);\n                    var hs' := vr.next_state(hs, hstep);\n                    && vr.inv(hs')\n                    && vr.hider(hs) == vr.hider(hs')\n                    && ActionTuple(hs, hs', hstep) in vr.hspec.next\n                    && 0 <= vr.progress_measure(hs') < vr.progress_measure(hs)\n    }\n\n    predicate WhenNotAtNewInstructionActionIsLiftable<LState(!new), HState(!new), LStep(!new), HStep(!new)>(\n        vr:VarIntroRequest<LState, HState, LStep, HStep>)\n    {\n        forall ls, ls', hs, lstep ::\n            && ActionTuple(ls, ls', lstep) in vr.lspec.next\n            && vr.inv(hs)\n            && ls == vr.hider(hs)\n            && !vr.at_new_instruction(hs)\n            ==> var hstep := vr.step_mapper(lstep);\n                var hs' := vr.next_state(hs, hstep);\n                && vr.inv(hs')\n                && ls' == vr.hider(hs')\n                && ActionTuple(hs, hs', hstep) in vr.hspec.next\n    }\n\n    predicate IntroSatisfiesRelation<LState, HState(!new), LStep, HStep>(vr:VarIntroRequest<LState, HState, LStep, HStep>)\n    {\n        forall s :: vr.inv(s) ==> RefinementPair(vr.hider(s), s) in vr.relation\n    }\n\n    predicate IntroPreservesInit<LState, HState, LStep, HStep>(vr:VarIntroRequest<LState, HState, LStep, HStep>)\n    {\n        forall ls :: ls in vr.lspec.init ==> var hs := vr.revealer(ls); vr.hider(hs) == ls && vr.inv(hs) && hs in vr.hspec.init\n    }\n\n    predicate ValidVarIntroRequest<LState, HState, LStep, HStep>(vr:VarIntroRequest<LState, HState, LStep, HStep>)\n    {\n        && WhenAtNewInstructionNextStepMakesProgress(vr)\n        && WhenNotAtNewInstructionActionIsLiftable(vr)\n        && IntroSatisfiesRelation(vr)\n        && IntroPreservesInit(vr)\n    }\n\n}\n"
  },
  {
    "path": "Armada/strategies/weakening/Weakening.i.dfy",
    "content": "include \"WeakeningSpec.i.dfy\"\ninclude \"../../util/collections/seqs.i.dfy\"\ninclude \"../../spec/refinement.s.dfy\"\n\nmodule WeakeningModule {\n\n    import opened WeakeningSpecModule\n    import opened AnnotatedBehaviorModule\n    import opened InvariantsModule\n    import opened GeneralRefinementModule\n    import opened util_collections_seqs_i\n    import opened util_collections_seqs_s\n    \n    lemma lemma_LRefinesH<LState, HState, LStep, HStep> (\n      lb:AnnotatedBehavior<LState, LStep>,\n      hb:AnnotatedBehavior<HState, HStep>,\n      wr:WeakeningRequest<LState, HState, LStep, HStep>,\n      lh_map:RefinementMap)\n      \n      requires ValidWeakeningRequest(wr)\n      requires AnnotatedBehaviorSatisfiesSpec(lb, wr.lspec)\n      requires hb.states == MapSeqToSeq(lb.states, wr.converter);\n      requires |lh_map| == |lb.states|\n      requires forall i :: 0 <= i < |lh_map| ==> lh_map[i] == RefinementRange(i, i)\n      ensures  BehaviorRefinesBehaviorUsingRefinementMap(lb.states, hb.states, wr.relation, lh_map)\n    {\n      assert hb.states == MapSeqToSeq(lb.states, wr.converter);\n      lemma_InvariantHoldsAtStep(lb, 0, wr.lspec, wr.inv);\n      var i := 0;\n      while i < |lb.states|\n        invariant 0 <= i <= |lb.states|\n        invariant forall j :: 0 <= j < i ==>  RefinementPair(lb.states[j], hb.states[j]) in wr.relation;\n      {\n        lemma_InvariantHoldsAtStep(lb, i, wr.lspec, wr.inv);\n        assert RefinementPair(lb.states[i], hb.states[i]) in wr.relation;\n        i := i + 1;\n      }\n    }\n\n    lemma lemma_PerformWeakening<LState, HState, LStep, HStep>(\n        wr:WeakeningRequest<LState, HState, LStep, HStep>,\n        lb:AnnotatedBehavior<LState, LStep>\n    )\n    returns (\n        hb:AnnotatedBehavior<HState, HStep>\n    )\n      requires ValidWeakeningRequest(wr)\n      requires AnnotatedBehaviorSatisfiesSpec(lb, wr.lspec)\n      ensures  hb.states == MapSeqToSeq(lb.states, wr.converter)\n      ensures  AnnotatedBehaviorSatisfiesSpec(hb, wr.hspec)\n      ensures  BehaviorRefinesBehavior(lb.states, hb.states, wr.relation)\n    {\n      var hstates := [wr.converter(lb.states[0])];\n      var htrace := [];\n      var lh_map := [RefinementRange(0, 0)];\n      var pos := 0;\n\n      lemma_InvariantHoldsAtStep(lb, 0, wr.lspec, wr.inv);\n\n      while pos < |lb.states| - 1\n        invariant 0 <= pos < |lb.states|\n            invariant |htrace| == |hstates|-1\n            invariant hstates[0] in wr.hspec.init\n            invariant forall i :: 0 <= i < |htrace| ==> ActionTuple(hstates[i], hstates[i+1], htrace[i]) in wr.hspec.next\n            invariant last(hstates) == wr.converter(lb.states[pos])\n            invariant hstates == MapSeqToSeq(lb.states[..pos + 1], wr.converter)\n            invariant forall i :: 0 <= i < |lh_map| ==> lh_map[i] == RefinementRange(i, i)\n            invariant |lh_map| == pos + 1\n      {\n        lemma_InvariantHoldsAtStep(lb, pos, wr.lspec, wr.inv);\n        lemma_InvariantHoldsAtStep(lb, pos+1, wr.lspec, wr.inv);\n        var ls := lb.states[pos];\n        var ls' := lb.states[pos+1];\n        var lstep := lb.trace[pos];\n        assert ActionTuple(ls, ls', lstep) in wr.lspec.next;\n        assert ls in wr.inv;\n\n        var hstep := wr.step_refiner(lstep);\n        htrace := htrace + [hstep];\n        hstates := hstates + [wr.converter(ls')];\n        assert hstates == MapSeqToSeq(lb.states[..pos + 2], wr.converter);\n          \n        lh_map := lh_map + [RefinementRange(|hstates|-1, |hstates|-1)];\n        pos := pos + 1;\n      }\n\n      hb := AnnotatedBehavior(hstates, htrace);\n      lemma_LRefinesH(lb, hb, wr, lh_map);\n    }\n\n}\n\n"
  },
  {
    "path": "Armada/strategies/weakening/WeakeningSpec.i.dfy",
    "content": "include \"../refinement/AnnotatedBehavior.i.dfy\"\ninclude \"../../spec/refinement.s.dfy\"\ninclude \"../invariants.i.dfy\"\n\nmodule WeakeningSpecModule {\n\n    import opened AnnotatedBehaviorModule\n    import opened InvariantsModule\n    import opened GeneralRefinementModule\n\n\n    datatype WeakeningRequest<!LState(==), HState(==), !LStep(==), HStep(==)> =\n        WeakeningRequest(\n            lspec:AnnotatedBehaviorSpec<LState, LStep>,\n            hspec:AnnotatedBehaviorSpec<HState, HStep>,\n            relation:RefinementRelation<LState, HState>,\n            inv:iset<LState>,\n            converter:(LState)->HState,\n            step_refiner:(LStep)->HStep\n            )\n\n\n    predicate ConvertingSatisfiesRelation<LState(!new), HState, LStep, HStep>(wr:WeakeningRequest<LState, HState, LStep, HStep>)\n    {\n        forall ls :: ls in wr.inv ==> RefinementPair(ls, wr.converter(ls)) in wr.relation\n    }\n\n    predicate AllActionsLiftableWeakened<LState(!new), HState(!new), LStep(!new), HStep(!new)>(wr:WeakeningRequest<LState, HState, LStep, HStep>)\n    {\n        forall s, s', lstep ::\n            && ActionTuple(s, s', lstep) in wr.lspec.next\n            && s in wr.inv\n            ==> ActionTuple(wr.converter(s), wr.converter(s'), wr.step_refiner(lstep)) in wr.hspec.next\n    }\n\n    predicate InitStatesEquivalent<LState(!new), HState(!new), LStep(!new), HStep(!new)>(wr:WeakeningRequest<LState, HState, LStep, HStep>)\n    {\n      forall initial_ls | initial_ls in wr.lspec.init ::\n        wr.converter(initial_ls) in wr.hspec.init\n    }\n\n    predicate ValidWeakeningRequest<LState, HState, LStep, HStep>(wr:WeakeningRequest<LState, HState, LStep, HStep>)\n    {\n      && InitStatesEquivalent(wr)\n      && IsInvariantOfSpec(wr.inv, wr.lspec)\n      && AllActionsLiftableWeakened(wr)\n      && ConvertingSatisfiesRelation(wr)\n    }\n\n}\n"
  },
  {
    "path": "Armada/util/collections/MapSum.i.dfy",
    "content": "include \"maps.s.dfy\"\ninclude \"sets.i.dfy\"\n\nmodule util_collections_MapSum_i {\n\n  import opened util_collections_maps_s\n  import opened util_collections_sets_i\n\n  lemma MapNonEmptyDomainNonEmpty<K, V>(m: map<K, V>)\n    requires |m| > 0\n    ensures |mapdomain(m)| > 0\n  {\n    var k :| k in m;\n    assert k in mapdomain(m);\n  }\n\n  function chooseone<T>(m: set<T>): T\n    requires |m| > 0\n  {\n    var k :| k in m;\n    k\n  }\n\n  function MapSum<K, V>(m: map<K, V>, f:V->int): int\n  {\n    if |m| == 0 then\n      0\n    else\n      MapNonEmptyDomainNonEmpty(m);\n      var k := chooseone(mapdomain(m));\n      var m0 := mapremove(m, k);\n      f(m[k]) + MapSum(m0, f)\n  }\n\n  lemma lemma_MapSumNonNegativeIfAllElementsNonNegative<K, V>(m: map<K, V>, f:V->int)\n    requires forall k :: k in m ==> f(m[k]) >= 0\n    ensures  MapSum(m, f) >= 0\n  {\n  }\n\n  lemma lemma_MapSumLessIfOneElementLessAndRestSame<K, V>(m1:map<K, V>, m2:map<K, V>, k: K, f:V->int)\n    requires forall k :: k in m1 <==> k in m2\n    requires k in m1\n    requires forall k0 :: k0 != k && k0 in m1 ==> m1[k0] == m2[k0]\n    requires f(m1[k]) < f(m2[k])\n    ensures  MapSum(m1, f) < MapSum(m2, f)\n  {\n    assert (mapdomain(m1) == mapdomain(m2));\n    if |m1| == 0 {\n    }\n    else {\n      MapNonEmptyDomainNonEmpty(m1);\n      MapNonEmptyDomainNonEmpty(m2);\n      var k0 := chooseone(mapdomain(m1));\n      if k0 == k {\n        assert mapremove(m1, k0) == mapremove(m2, k0);\n      }\n      else {\n        lemma_MapSumLessIfOneElementLessAndRestSame(mapremove(m1, k0), mapremove(m2, k0), k, f);\n      }\n    }\n  }\n\n\n  lemma lemma_MapSumLessOrEqualIfOneElementLessOrEqualAndRestSame<K, V>(m1:map<K, V>, m2:map<K, V>, k: K, f:V->int)\n    requires forall k :: k in m1 <==> k in m2\n    requires k in m1\n    requires forall k0 :: k0 != k && k0 in m1 ==> m1[k0] == m2[k0]\n    requires f(m1[k]) <= f(m2[k])\n    ensures  MapSum(m1, f) <= MapSum(m2, f)\n  {\n    assert (mapdomain(m1) == mapdomain(m2));\n    if |m1| == 0 {\n    }\n    else {\n      MapNonEmptyDomainNonEmpty(m1);\n      MapNonEmptyDomainNonEmpty(m2);\n      var k0 := chooseone(mapdomain(m1));\n      if k0 == k {\n        assert mapremove(m1, k0) == mapremove(m2, k0);\n      }\n      else {\n        lemma_MapSumLessOrEqualIfOneElementLessOrEqualAndRestSame(mapremove(m1, k0), mapremove(m2, k0), k, f);\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "Armada/util/collections/SeqSum.i.dfy",
    "content": "module util_collections_SeqSum_i {\n\n    function SeqSum(s:seq<int>) : int\n    {\n        if |s| == 0 then\n            0\n        else\n            s[0] + SeqSum(s[1..])\n    }\n\n    lemma lemma_SeqSumNonNegativeIfAllElementsNonNegative(s:seq<int>)\n        requires forall i :: 0 <= i < |s| ==> s[i] >= 0\n        ensures  SeqSum(s) >= 0\n    {\n    }\n\n    lemma lemma_SeqSumLessIfOneElementLessAndRestSame(s1:seq<int>, s2:seq<int>, pos:int)\n        requires |s1| == |s2|\n        requires 0 <= pos < |s1|\n        requires forall i :: 0 <= i < |s1| && i != pos ==> s1[i] == s2[i]\n        requires s1[pos] < s2[pos]\n        ensures  SeqSum(s1) < SeqSum(s2)\n    {\n        if |s1| == 0 {\n        }\n        else if pos == 0 {\n            assert s1[1..] == s2[1..];\n        }\n        else {\n            lemma_SeqSumLessIfOneElementLessAndRestSame(s1[1..], s2[1..], pos-1);\n        }\n    }\n    \n}\n\n    \n"
  },
  {
    "path": "Armada/util/collections/maps.i.dfy",
    "content": "include \"sets.i.dfy\"\n\nmodule util_collections_maps_i\n{\n    import opened util_collections_sets_i\n\n    function AddSetToMap<K,V>(m: map<K,V>, ks: set<K>, v: V) : (m': map<K,V>)\n      // requires forall k :: k in ks ==> !(k in m)\n      ensures forall k :: k in m ==> k in m' && m'[k] == m[k]\n      ensures forall k :: k in ks && k !in m ==> k in m' && m'[k] == v\n    {\n      map k | k in ks + m.Keys :: if k in m then m[k] else v\n    }\n\n    function MapMapToMap_internal<K, V1, V2>(m: map<K, V1>, f: V1->V2) : (m': map<K, V2>)\n        ensures m'.Keys == m.Keys\n        ensures forall k :: k in m' ==> m'[k] == f(m[k])\n    {\n        map k | k in m :: f(m[k])\n    }\n\n    lemma lemma_MapMapToMapMaintainsSize<K, V1, V2>(m: map<K, V1>, f:V1->V2)\n        ensures |MapMapToMap_internal(m, f)| == |m|\n    {\n        var m' := MapMapToMap_internal(m, f);\n        var keys := set k | k in m;\n        var keys' := set k | k in m';\n        assert keys' == keys;\n        calc {\n            |m'|;\n            |keys'|;\n            |keys|;\n            |m|;\n        }\n    }\n\n    function MapMapToMap<K, V1, V2>(m:map<K, V1>, f:V1->V2) : (m':map<K, V2>)\n        ensures m'.Keys == m.Keys\n        ensures forall k :: k in m' ==> m'[k] == f(m[k])\n        ensures |m'| == |m|\n    {\n        lemma_MapMapToMapMaintainsSize(m, f);\n        MapMapToMap_internal(m, f)\n    }\n\n    function Map2MapToMap_internal<K1(!new), V1, K2(!new), V2>(m:map<K1, V1>, fk:K1->K2, fk_inv:K2->K1, fv:V1->V2) : (m':map<K2, V2>)\n        requires Inverses(fk, fk_inv)\n    {\n        var keys' := MapSetToSet(m.Keys, fk);\n        map k | k in keys' :: fv(m[fk_inv(k)])\n    }\n\n    lemma lemma_SetExtensionality<T>(s1:set<T>, s2:set<T>)\n        requires forall x :: x in s1 <==> x in s2\n        ensures  s1 == s2\n    {\n    }\n\n    lemma lemma_Map2MapToMap<K1(!new), V1, K2(!new), V2>(m:map<K1, V1>, fk:K1->K2, fk_inv:K2->K1, fv:V1->V2, m':map<K2, V2>)\n        requires Inverses(fk, fk_inv)\n        requires m' == Map2MapToMap_internal(m, fk, fk_inv, fv)\n        ensures  m'.Keys == MapSetToSet(m.Keys, fk)\n        ensures  forall k :: k in m' ==> m'[k] == fv(m[fk_inv(k)])\n    {\n        var keys' := MapSetToSet(m.Keys, fk);\n\n        forall k | k in m'\n            ensures k in keys'\n            ensures m'[k] == fv(m[fk_inv(k)])\n        {\n        }\n\n        lemma_SetExtensionality(m'.Keys, keys');\n    }\n\n    function Map2MapToMap<K1(!new), V1, K2(!new), V2>(m:map<K1, V1>, fk:K1->K2, fk_inv:K2->K1, fv:V1->V2) : (m':map<K2, V2>)\n        requires Inverses(fk, fk_inv)\n        ensures  m'.Keys == MapSetToSet(m.Keys, fk)\n        ensures  forall k :: k in m' ==> m'[k] == fv(m[fk_inv(k)])\n    {\n        var m' := Map2MapToMap_internal(m, fk, fk_inv, fv);\n        lemma_Map2MapToMap(m, fk, fk_inv, fv, m');\n        m'\n    }\n\n    predicate MapHasUniqueKey<T, U>(m:map<T, U>, k:T)\n    {\n        && k in m\n        && (forall k' :: k' in m ==> k' == k)\n    }\n\n    lemma EmptyMapPredicateInvalid<S, T>(m:map<S, T>, P:T->bool)\n      requires |set x | x in m && P(m[x])| == 0\n      ensures forall x :: x in m ==> ! P(m[x])\n    {\n      forall x | x in m\n        ensures ! P(m[x])\n      {\n        if P(m[x]) {\n          assert x in (set x | x in m && P(m[x]));\n          lemma_EmptySetCantHaveMember(x, set x | x in m && P(m[x]));\n        }\n      }\n    }\n\n    lemma lemma_IfMapKeysMatchThenCardinalitiesMatch<K, V1, V2>(m1:map<K, V1>, m2:map<K, V2>)\n      requires forall k :: k in m1 <==> k in m2\n      ensures  |m1| == |m2|\n    {\n      var keys1 := set k | k in m1;\n      var keys2 := set k | k in m2;\n      assert m1.Keys == keys1;\n      assert m2.Keys == keys2;\n      assert keys1 == keys2;\n      calc {\n        |m1|;\n        |m1.Keys|;\n        |keys1|;\n        |keys2|;\n        |m2.Keys|;\n        |m2|;\n      }\n    }\n}\n"
  },
  {
    "path": "Armada/util/collections/maps.s.dfy",
    "content": "module util_collections_maps_s\n{\n    function mapdomain<KT,VT>(m:map<KT,VT>) : set<KT>\n    {\n        set k | k in m :: k\n    }\n    \n    function mapremove<KT,VT>(m:map<KT,VT>, k:KT) : map<KT,VT>\n    {\n        map ki | ki in m && ki != k :: m[ki]\n    }\n\n    predicate maptotal<KT(!new),VT>(m:map<KT,VT>)\n    {\n        forall k {:trigger m[k]}{:trigger k in m} :: k in m\n    }\n    \n    predicate imaptotal<KT(!new),VT>(m:imap<KT,VT>)\n    {\n        forall k {:trigger m[k]}{:trigger k in m} :: k in m\n    }\n} \n"
  },
  {
    "path": "Armada/util/collections/seqs.i.dfy",
    "content": "include \"../option.s.dfy\"\ninclude \"seqs.s.dfy\"\n\nmodule util_collections_seqs_i\n{\n  import opened util_option_s\n  import opened util_collections_seqs_s\n\n  function {:opaque} ConvertMapToSeq<T>(n:int, m:map<int, T>) : seq<T>\n    requires n >= 0;\n    requires forall i {:trigger i in m} :: 0 <= i < n ==> i in m;\n    ensures  |ConvertMapToSeq(n, m)| == n;\n    ensures  var s := ConvertMapToSeq(n, m);\n             forall i {:trigger s[i]} :: 0 <= i < n ==> s[i] == m[i];\n  {\n    if n == 0 then []\n    else ConvertMapToSeq(n-1, m) + [m[n-1]]\n  }\n\n  function {:opaque} MapSeqToSeq<T, U>(s:seq<T>, f:T->U) : (s':seq<U>)\n    ensures |s'| == |s|\n    ensures forall i {:trigger s'[i]} {:trigger f(s[i])} :: 0 <= i < |s| ==> s'[i] == f(s[i])\n  {\n    if |s| == 0 then\n      []\n    else\n      [f(s[0])] + MapSeqToSeq(s[1..], f)\n  }\n\n  lemma lemma_MapSeqToSeqDrop<T, U>(s:seq<T>, f:T->U, n:int)\n    requires 0 <= n <= |s|\n    ensures MapSeqToSeq(s, f)[n..] == MapSeqToSeq(s[n..], f)\n  {\n  }\n\n  lemma lemma_MapSeqToSeqTake<T, U>(s:seq<T>, f:T->U, n:int)\n    requires 0 <= n <= |s|\n    ensures MapSeqToSeq(s, f)[..n] == MapSeqToSeq(s[..n], f)\n  {\n  }\n\n  function FilterSeqToSeq<T>(s:seq<T>, f:T->bool) : (s':seq<T>)\n    ensures forall x :: x in s' ==> f(x)\n  {\n    if |s| == 0 then\n      []\n    else if f(s[0]) then\n      [s[0]] + FilterSeqToSeq(s[1..], f)\n    else\n      FilterSeqToSeq(s[1..], f)\n  }\n\n  lemma FilterSeqToSeqDecreasesLength<T>(s:seq<T>, f:T->bool)\n    ensures |FilterSeqToSeq(s, f)| <= |s|\n  {\n  }\n\n  function FilterMapSeqToSeq<T, U>(s:seq<T>, f:T->Option<U>) : (s':seq<U>)\n  {\n    if |s| == 0 then\n      []\n    else if f(s[0]).Some? then\n      [f(s[0]).v] + FilterMapSeqToSeq(s[1..], f)\n    else\n      FilterMapSeqToSeq(s[1..], f)\n  }\n\n  lemma lemma_FilterMapSeqsToSeq<T, U>(s1:seq<T>, s2:seq<T>, f:T->Option<U>)\n    ensures FilterMapSeqToSeq(s1, f) + FilterMapSeqToSeq(s2, f) == FilterMapSeqToSeq(s1 + s2, f)\n  {\n    if |s1| == 0 {\n      assert s2 == s1 + s2;\n    }\n    else {\n      assert s1 + s2 == [s1[0]] + (s1[1..] + s2);\n    }\n  }\n\n  lemma FilterMapSeqToSeq_FilterEmpty<T, U>(s: seq<T>, f: T->Option<U>)\n    requires forall e :: e in s ==> f(e).None?\n    ensures FilterMapSeqToSeq(s, f) == []\n  {\n    if |s| == 0 {\n\n    }\n    else {\n      if (f(s[0]).Some?) {\n\n      }\n      else {\n        FilterMapSeqToSeq_FilterEmpty(s[1..], f);\n      }\n    }\n  }\n\n  function RepeatingValue<T>(x:T, n:int) : (s:seq<T>)\n    requires n >= 0\n    ensures  |s| == n\n    ensures  forall e :: e in s ==> e == x\n    ensures  forall i :: 0 <= i < |s| ==> s[i] == x\n  {\n    if n == 0 then [] else [x] + RepeatingValue(x, n-1)\n  }\n\n  //////////////////////////////\n  // UTILITY LEMMAS\n  //////////////////////////////\n\n  lemma lemma_SequenceIsCarPlusCdr<T>(s:seq<T>)\n    requires |s| > 0\n    ensures  s == [s[0]] + s[1..];\n  {\n  }\n\n  lemma lemma_SequenceConcatenationAssociative<T>(s1:seq<T>, s2:seq<T>, s3:seq<T>)\n    ensures s1 + (s2 + s3) == (s1 + s2) + s3;\n  {\n  }\n\n  lemma lemma_DroppingHeadOfConcatenation<T>(s1:seq<T>, s2:seq<T>)\n    requires |s1| > 0\n    ensures  s1[1..] + s2 == (s1 + s2)[1..]\n  {\n  }\n\n  lemma lemma_IndexIntoDrop<T>(s:seq<T>, i:int, j:int)\n    requires 0 <= i\n    requires 0 <= j\n    requires i + j < |s|\n    ensures  s[i..][j] == s[i+j]\n  {\n  }\n\n  lemma lemma_IndexIntoConcatenation<T>(s1:seq<T>, s2:seq<T>, i:int)\n    requires 0 <= i < |s1| + |s2|\n    ensures  (s1 + s2)[i] == if i < |s1| then s1[i] else s2[i-|s1|]\n  {\n  }\n\n  lemma lemma_LastOfConcatenationIsLastOfLatter<T>(s1:seq<T>, s2:seq<T>)\n    requires |s2| > 0\n    ensures  last(s1 + s2) == last(s2)\n  {\n  }\n\n  lemma lemma_AllButLastPlusLastIsSeq<T>(s:seq<T>)\n    requires |s| > 0\n    ensures  all_but_last(s) + [last(s)] == s\n  {\n  }\n\n  lemma lemma_LastOfDropIsLast<T>(s:seq<T>, i:int)\n    requires 0 <= i < |s|\n    ensures  last(s[i..]) == last(s)\n  {\n  }\n\n  lemma lemma_LastOfAllButLast<T>(s:seq<T>)\n    requires |s| > 1\n    ensures  last(all_but_last(s)) == s[|s|-2]\n  {\n  }\n\n  lemma lemma_TakePlusDropIsSeq<T>(s:seq<T>, i:int)\n    requires 0 <= i <= |s|\n    ensures  s == s[..i] + s[i..]\n  {\n  }\n\n  lemma lemma_SeqEqualsThreeWayConcatentation<T>(s:seq<T>, i:int, j:int)\n    requires 0 <= i <= j <= |s|\n    ensures  s == s[..i] + s[i..j] + s[j..]\n  {\n  }\n\n  lemma lemma_DropMapSeqToSeq<T, U>(s:seq<T>, f:T->U, i:int)\n    requires |s| >= i >= 0\n    ensures  MapSeqToSeq(s[i..], f) == MapSeqToSeq(s, f)[i..]\n    decreases i\n  {\n    var s1 := MapSeqToSeq(s[i..], f);\n    var s2 := MapSeqToSeq(s, f)[i..];\n    assert |s1| == |s2|;\n    forall j | 0 <= j < |s1|\n      ensures s1[j] == s2[j]\n    {\n      calc {\n        s1[j];\n        f(s[i..][j]);\n          { lemma_IndexIntoDrop(s, i, j); }\n        f(s[i+j]);\n        MapSeqToSeq(s, f)[i+j];\n          { lemma_IndexIntoDrop(MapSeqToSeq(s, f), i, j); }\n        MapSeqToSeq(s, f)[i..][j];\n        s2[j];\n      }\n    }\n  }\n\n}\n"
  },
  {
    "path": "Armada/util/collections/seqs.s.dfy",
    "content": "module util_collections_seqs_s\n{\n    function last<T>(s:seq<T>) : T\n        requires |s| > 0;\n    {\n        s[|s|-1]\n    }\n    \n    function all_but_last<T>(s:seq<T>) : seq<T>\n        requires |s| > 0;\n    {\n        s[..|s|-1]\n    }\n} \n"
  },
  {
    "path": "Armada/util/collections/sets.i.dfy",
    "content": "module util_collections_sets_i {\n\nlemma ThingsIKnowAboutSubset<T>(x:set<T>, y:set<T>)\n    requires x<y;\n    ensures |x|<|y|;\n{\n    if (x!={}) {\n        var e :| e in x;\n        ThingsIKnowAboutSubset(x-{e}, y-{e});\n    }\n}\n\nlemma SubsetCardinality<T>(x:set<T>, y:set<T>)\n    ensures x<y ==> |x|<|y|;\n    ensures x<=y ==> |x|<=|y|;\n{\n    if (x<y) {\n        ThingsIKnowAboutSubset(x, y);\n    }\n    if (x==y) { // OBSERVE the other case\n    }\n}\n\nlemma ItIsASingletonSet<T>(foo:set<T>, x:T)\n    requires foo=={x};\n    ensures |foo|==1;\n{\n}\n\nlemma ThingsIKnowAboutASingletonSet<T>(foo:set<T>, x:T, y:T)\n    requires |foo|==1;\n    requires x in foo;\n    requires y in foo;\n    ensures x==y;\n{\n    if (x!=y) {\n        assert {x} < foo;\n        ThingsIKnowAboutSubset({x}, foo);\n        assert |{x}| < |foo|;\n        assert |foo|>1;\n        assert false;\n    }\n}\n\npredicate Injective<X(!new), Y>(f:X->Y)\n{\n  forall x1, x2 :: f(x1) == f(x2) ==> x1 == x2\n}\n\npredicate InjectiveOver<X, Y>(xs:set<X>, ys:set<Y>, f:X->Y)\n{\n  forall x1, x2 :: x1 in xs && x2 in xs && f(x1) in ys && f(x2) in ys && f(x1) == f(x2) ==> x1 == x2\n}\n\npredicate InjectiveOverSeq<X, Y>(xs:seq<X>, ys:set<Y>, f:X->Y)\n{\n  forall x1, x2 :: x1 in xs && x2 in xs && f(x1) in ys && f(x2) in ys && f(x1) == f(x2) ==> x1 == x2\n}\n\npredicate Inverses<X(!new), Y(!new)>(f1:X->Y, f2:Y->X)\n{\n    && forall x :: f2(f1(x)) == x\n    && forall y :: f1(f2(y)) == y\n}\n\nlemma lemma_MapSetCardinality<X, Y>(xs:set<X>, ys:set<Y>, f:X->Y)\n  requires Injective(f);\n  requires forall x :: x in xs <==> f(x) in ys;\n  requires forall y :: y in ys ==> exists x :: x in xs && y == f(x);\n  ensures  |xs| == |ys|;\n{\n  if (xs != {})\n  {\n    var x :| x in xs;\n    var xs' := xs - {x};\n    var ys' := ys - {f(x)};\n    lemma_MapSetCardinality(xs', ys', f);\n  }\n}\n\nlemma lemma_MapSetCardinalityOver<X, Y>(xs:set<X>, ys:set<Y>, f:X->Y)\n  requires InjectiveOver(xs, ys, f);\n  requires forall x :: x in xs ==> f(x) in ys;\n  requires forall y :: y in ys ==> exists x :: x in xs && y == f(x);\n  ensures  |xs| == |ys|;\n{\n  if (xs != {})\n  {\n    var x :| x in xs;\n    var xs' := xs - {x};\n    var ys' := ys - {f(x)};\n    lemma_MapSetCardinalityOver(xs', ys', f);\n  }\n}\n\nlemma lemma_MapSubsetCardinalityOver<X, Y>(xs:set<X>, ys:set<Y>, f:X->Y)\n  requires InjectiveOver(xs, ys, f);\n  requires forall x :: x in xs ==> f(x) in ys;\n  ensures  |xs| <= |ys|;\n{\n  if (xs != {})\n  {\n    var x :| x in xs;\n    var xs' := xs - {x};\n    var ys' := ys - {f(x)};\n    lemma_MapSubsetCardinalityOver(xs', ys', f);\n  }\n}\n\nlemma lemma_MapSubseqCardinalityOver<X, Y>(xs:seq<X>, ys:set<Y>, f:X->Y)\n  requires forall i, j :: 0 <= i < |xs| && 0 <= j < |xs| && i != j ==> xs[i] != xs[j];\n  requires InjectiveOverSeq(xs, ys, f);\n  requires forall x :: x in xs ==> f(x) in ys;\n  ensures  |xs| <= |ys|;\n{\n  if (xs != [])\n  {\n    var x := xs[0];\n    var xs' := xs[1..];\n    var ys' := ys - {f(x)};\n    forall x' | x' in xs'\n        ensures f(x') in ys';\n    {\n        assert x' in xs;\n        assert f(x') in ys;\n        if f(x') == f(x)\n        {\n            assert x in xs && x' in xs && f(x) in ys && f(x') in ys && f(x') == f(x);\n            assert x' == x;\n        }\n    }\n    forall x1, x2 | x1 in xs' && x2 in xs' && f(x1) in ys' && f(x2) in ys' && f(x1) == f(x2)\n        ensures x1 == x2;\n    {\n        assert x1 in xs && x2 in xs && f(x1) in ys && f(x2) in ys';\n    }\n    lemma_MapSubseqCardinalityOver(xs', ys', f);\n  }\n}\n\nfunction MapSetToSet<X(!new), Y>(xs:set<X>, f:X->Y) : (ys:set<Y>)\n  requires Injective(f);\n  ensures  forall x :: x in xs <==> f(x) in ys;\n  ensures  |xs| == |ys|;\n{\n  var ys := set x | x in xs :: f(x); \n  lemma_MapSetCardinality(xs, ys, f);\n  ys\n}\n\nfunction MapSetToSetBijective<X(!new), Y(!new)>(xs:set<X>, f:X->Y, f_inv:Y->X):(ys:set<Y>)\n  requires Inverses(f, f_inv)\n  ensures  forall x :: x in xs <==> f(x) in ys\n  ensures  forall y :: y in ys <==> f_inv(y) in xs\n  ensures  |xs| == |ys|\n{\n  var ys := set x | x in xs :: f(x); \n  lemma_MapSetCardinality(xs, ys, f);\n  ys\n}\n\nfunction MapSetToSetOver<X, Y>(xs:set<X>, f:X->Y):set<Y>\n  requires InjectiveOver(xs, set x | x in xs :: f(x), f);\n  ensures  forall x :: x in xs ==> f(x) in MapSetToSetOver(xs, f);\n  ensures  |xs| == |MapSetToSetOver(xs, f)|;\n{\n  var ys := set x | x in xs :: f(x); \n  lemma_MapSetCardinalityOver(xs, ys, f);\n  ys\n}\n\nfunction MapSeqToSet<X(!new), Y>(xs:seq<X>, f:X->Y):set<Y>\n  requires Injective(f);\n  ensures  forall x :: x in xs <==> f(x) in MapSeqToSet(xs, f);\n{\n  set x | x in xs :: f(x)\n}\n\nlemma lemma_SubsetCardinality<X>(xs:set<X>, ys:set<X>, f:X->bool)\n  requires forall x :: x in ys ==> x in xs && f(x);\n  ensures  |ys| <= |xs|;\n{\n  if (ys != {})\n  {\n    var y :| y in ys;\n    var xs' := xs - {y};\n    var ys' := ys - {y};\n    lemma_SubsetCardinality(xs', ys', f);\n  }\n}\n\nfunction/*TODO:{:opaque}*/ MakeSubset<X(!new)>(xs:set<X>, f:X->bool):set<X>\n  ensures  forall x :: x in MakeSubset(xs, f) <==> x in xs && f(x);\n  ensures  |MakeSubset(xs, f)| <= |xs|;\n{\n  var ys := set x | x in xs && f(x);\n  lemma_SubsetCardinality(xs, ys, f);\n  ys\n}\n\n/* examples:\nfunction{:opaque} setAdd1(xs:set<int>):set<int>\n  ensures forall x :: x in xs <==> x + 1 in setAdd1(xs);\n  ensures |xs| == |setAdd1(xs)|;\n{\n  MapSetToSet(xs, x => x + 1)\n}\n\nfunction{:opaque} setPos(xs:set<int>):set<int>\n  ensures forall x :: x in setPos(xs) <==> x in xs && x > 0;\n{\n  MakeSubset(xs, x => x > 0)\n}\n*/\n\nlemma lemma_UnionCardinality<X>(xs:set<X>, ys:set<X>, us:set<X>)\n    requires us==xs+ys;\n    ensures |us| >= |xs|;\n    decreases ys;\n{\n    if (ys=={}) {\n    } else {\n        var y :| y in ys;\n        if (y in xs) {\n            var xr := xs - {y};\n            var yr := ys - {y};\n            var ur := us - {y};\n            lemma_UnionCardinality(xr, yr, ur);\n        } else {\n            var ur := us - {y};\n            var yr := ys - {y};\n            lemma_UnionCardinality(xs, yr, ur);\n        }\n    }\n}\n\nfunction SetOfNumbersInRightExclusiveRange(a:int, b:int):set<int>\n    requires a <= b;\n    ensures forall opn :: a <= opn < b ==> opn in SetOfNumbersInRightExclusiveRange(a, b);\n    ensures forall opn :: opn in SetOfNumbersInRightExclusiveRange(a, b) ==> a <= opn < b;\n    ensures |SetOfNumbersInRightExclusiveRange(a, b)| == b-a;\n    decreases b-a;\n{\n    if a == b then {} else {a} + SetOfNumbersInRightExclusiveRange(a+1, b)\n}\n\nlemma lemma_CardinalityOfBoundedSet(s:set<int>, a:int, b:int)\n    requires forall opn :: opn in s ==> a <= opn < b;\n    requires a <= b;\n    ensures  |s| <= b-a;\n{\n    var range := SetOfNumbersInRightExclusiveRange(a, b);\n    forall i | i in s\n        ensures i in range;\n    {\n    }\n    assert s <= range;\n    SubsetCardinality(s, range);\n}\n\nfunction intsetmax(s:set<int>):int\n    requires |s| > 0;\n    ensures  var m := intsetmax(s);\n             m in s && forall i :: i in s ==> m >= i;\n{\n    var x :| x in s;\n    if |s| == 1 then\n        assert |s - {x}| == 0;\n        x\n    else\n        var sy := s - {x};\n        var y := intsetmax(sy);\n        assert forall i :: i in s ==> i in sy || i == x;\n        if x > y then x else y\n}\n\nlemma lemma_EmptySetCantHaveMember<T>(x:T, s:set<T>)\n    requires x in s\n    requires |s| == 0 || s == {}\n    ensures  false\n{\n}\n\n} \n"
  },
  {
    "path": "Armada/util/functions.i.dfy",
    "content": "module util_functions_i {\n\n  predicate RelationSatisfiableAt<T, U(!new)>(relation:(T,U)->bool, x:T)\n  {\n    exists y:U :: relation(x, y)\n  }\n\n  predicate RelationAlwaysSatisfiable<T(!new), U(!new)>(relation:(T,U)->bool)\n  {\n    forall x:T :: RelationSatisfiableAt(relation, x)\n  }\n\n  predicate FunctionSatisfiesRelation<T(!new), U(!new)>(f:T->U, relation:(T,U)->bool)\n  {\n    forall t:T :: relation(t, f(t))\n  }\n\n  function FunctionSatisfyingRelation<T(!new), U(!new)>(relation:(T,U)->bool) : (T->U)\n    requires RelationAlwaysSatisfiable(relation)\n  {\n    (x:T) => var y :| assert RelationSatisfiableAt(relation, x); relation(x, y); y\n  }\n\n  /* Example use:\n  predicate MyRelation(x:int, y:int)\n\n  lemma SatisfyMyRelation(x:int) returns (y:int)\n    ensures MyRelation(x, y)\n\n  lemma ConstructFunctionSatisfyingMyRelation() returns (f:int->int)\n    ensures FunctionSatisfiesRelation(f, MyRelation)\n  {\n    forall x:int\n      ensures RelationSatisfiableAt(MyRelation, x)\n    {\n      var y := SatisfyMyRelation(x);\n    }\n    f := FunctionSatisfyingRelation(MyRelation);\n  }\n  */\n  \n}\n"
  },
  {
    "path": "Armada/util/math/.gitignore",
    "content": "*.bpl\n*.log\n"
  },
  {
    "path": "Armada/util/math/div.i.dfy",
    "content": "include \"power.i.dfy\"\ninclude \"mul.i.dfy\"\ninclude \"div_def.i.dfy\"\ninclude \"div_boogie.i.dfy\"\ninclude \"div_nonlinear.i.dfy\"\ninclude \"div_auto.i.dfy\"\ninclude \"mod_auto.i.dfy\"\ninclude \"mul_auto.i.dfy\"\ninclude \"powers.i.dfy\"\ninclude \"mul_nonlinear.i.dfy\"\n\nmodule Math__div_i {\nimport opened Math__power_i\nimport opened Math__mul_i\nimport opened Math__div_def_i\nimport opened Math__div_boogie_i\nimport opened Math__div_nonlinear_i\nimport opened Math__div_auto_i\nimport opened Math__mod_auto_i\nimport opened Math__mul_auto_i\nimport opened Math__power_s\nimport opened Math__mul_nonlinear_i\n\n//-////////////////////////////////////////////////////////////////////////////\n//-\n//- Core div lemmas, with named arguments.\n//-\n//-////////////////////////////////////////////////////////////////////////////\n\nlemma lemma_div_by_one_is_identity(x:int) {}\n\nlemma lemma_div_basics(x:int)\n    ensures x != 0 ==> 0 / x == 0;\n    ensures x / 1 == x;\n    ensures x!=0 ==> x / x == 1;\n{\n    if (x != 0) {\n        lemma_div_by_self(x);\n        lemma_div_of_0(x);\n    }\n}\n\n\nlemma lemma_small_div_converse()\n    ensures forall x, d {:trigger x/d} :: 0<=x && 0<d && x/d==0 ==> x < d;\n{\n    forall x, d | 0<=x && 0<d && x/d==0 ensures x < d;\n    {\n        lemma_div_auto_induction(d, x, imap u :: 0<=u && 0<d && u/d==0 ==> u < d);\n    }\n}\n\n\nlemma lemma_div_is_ordered_by_denominator(x:int, y:int, z:int)\n    requires x >= 0;\n    requires 1 <= y <= z;\n    ensures x / y >= x / z;\n    decreases x;\n{\n    lemma_div_is_div_recursive_forall();\n    assert forall u:int, d:int {:trigger u / d}{:trigger my_div_recursive(u, d)} :: d > 0 ==> my_div_recursive(u, d) == u / d;\n\n    if (x < z)\n    {\n        lemma_div_is_ordered(0, x, y);\n    }\n    else\n    {\n        lemma_div_is_ordered(x-z, x-y, y);\n        lemma_div_is_ordered_by_denominator(x-z, y, z);\n    }\n}\n\nlemma lemma_div_is_strictly_ordered_by_denominator(x:int, d:int)\n    requires 0 < x;\n    requires 1 < d;\n    ensures x/d < x;\n    decreases x;\n{\n    lemma_div_auto_induction(d, x, imap u :: 0 < u ==> u / d < u);\n}\n\nlemma lemma_dividing_sums(a:int, b:int, d:int, R:int)\n    requires 0<d;\n    requires R == a%d + b%d - (a+b)%d;\n    ensures d*((a+b)/d) - R == d*(a/d) + d*(b/d);\n{\n    calc ==> {\n        a%d + b%d == R + (a+b)%d;\n        (a+b)-(a+b)%d - R == a-(a%d) + b - (b%d);\n            {\n                lemma_fundamental_div_mod(a+b,d);\n                lemma_fundamental_div_mod(a,d);\n                lemma_fundamental_div_mod(b,d);\n            }\n        d*((a+b)/d) - R == d*(a/d) + d*(b/d);\n    }\n}\n\n\n//-static lemma lemma_negative_divisor(x:int, d:int)\n//-    requires d < 0;\n//-    ensures x / (-1*d) == -1*(x / d); \n//-{\n//-    var q := x / (-1*d);\n//-    var r := x % (-1*d);\n//-    \n//-    calc {\n//-        x;\n//-            { lemma_fundamental_div_mod(x, -1*d); }\n//-        q * (-1*d) + r;\n//-            { lemma_mul_is_associative(q, -1, d); }\n//-        (q*-1)*d + r;\n//-            { lemma_mul_is_commutative(q, -1); }\n//-        (-q) * d + r;\n//-    }\n//-    lemma_mod_range(x, -1*d);\n//-    lemma_fundamental_div_mod_converse(x, d, -q, r);\n//-    assert x / d == -q;\n//-    assert -1*(x/d) == q;\n//-}\n\n\nlemma lemma_div_pos_is_pos(x:int, divisor:int)\n    requires 0 <= x;\n    requires 0 < divisor;\n    ensures x / divisor >= 0;\n{\n    lemma_div_auto_induction(divisor, x, imap u :: 0 <= u ==> u / divisor >= 0);\n}\n//-////////////////////////////////////////////////////////////////////////////\n//-\n//- Forall lemmas: these restate the core lemmas with foralls,\n//- so callers needn't name the specific expressions to manipulate.\n//-\n//- These are all boilerplate transformations of args/requires/ensures\n//- into forall args :: requires ==> ensures, with a correpsonding\n//- mechanically generated forall proof that invokes the core lemma.\n// So don't bother reading them.\n//-\n//-////////////////////////////////////////////////////////////////////////////\n\nlemma lemma_div_basics_forall()\n    ensures forall x {:trigger 0 / x} :: x != 0 ==> 0 / x == 0;\n    ensures forall x {:trigger x / 1} :: x / 1 == x;\n    ensures forall x, y {:trigger x/y} :: x >= 0 && y > 0 ==> x/y >= 0;\n    ensures forall x, y {:trigger x/y} :: x >= 0 && y > 0 ==> x/y <= x;\n{\n    forall (x:int)\n        ensures x != 0 ==> 0 / x == 0;\n        ensures x / 1 == x;\n    {\n        lemma_div_basics(x);\n    }\n    forall x:int, y:int | x >= 0 && y > 0\n        ensures x / y >= 0;\n        ensures x / y <= x;\n    {\n        lemma_div_pos_is_pos(x, y);\n        lemma_div_is_ordered_by_denominator(x, 1, y);\n    }\n}\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// I'm not sure how useful this is. I wrote it to try to bring\n// negative numerators to the positive side for trying to prove\n// the negative half of lemma_fundamental_div_mod. That turned out\n// to be the wrong idea, so maybe these are just useless.\n\nlemma lemma_div_neg_neg(x:int, d:int)\n    requires d > 0;\n    ensures x/d == -((-x+d-1)/d);\n{\n    lemma_div_auto(d);\n}\n\n\n//-\n//-////////////////////////////////////////////////////////////////////////////\n\n\n/*******************************\n *  Useful lemmas about mod    *\n *******************************/\n\n////////////////////////////////////////////////\n//  No longer needed.  Here for legacy reasons\n////////////////////////////////////////////////\n\nlemma lemma_mod_2(x:int) {}\nlemma lemma_mod2_plus(x:int) {}\nlemma lemma_mod2_plus2(x:int) {}\nlemma lemma_mod32(x:int) {}\nlemma lemma_mod_remainder_neg_specific(x:int, m:int) {}\nlemma lemma_mod_remainder_neg() {}\nlemma lemma_mod_remainder_pos_specific(x:int, m:int) {}\nlemma lemma_mod_remainder_pos() {}\nlemma lemma_mod_remainder_specific(x:int, m:int) {}\nlemma lemma_mod_remainder() {}\n\n////////////////////////////////////////////////\n// Actual useful lemmas\n////////////////////////////////////////////////\n\nlemma lemma_mod_basics()\n    ensures forall m:int {:trigger m % m} :: m > 0 ==> m % m == 0;\n    ensures forall x:int, m:int {:trigger (x%m) % m} :: m > 0 ==> (x%m) % m == x%m;\n{\n    forall m:int | m > 0\n        ensures m % m == 0;\n    {\n        lemma_mod_auto(m);\n    }\n    forall x:int, m:int | m > 0\n        ensures (x % m) % m == x % m;\n    {\n        lemma_mod_auto(m);\n    }\n}\n\nlemma lemma_mod_properties()\n    ensures forall m:int {:trigger m % m} :: m > 0 ==> m % m == 0;\n    ensures forall x:int, m:int {:trigger (x%m) % m} :: m > 0 ==> (x%m) % m == x%m;\n    ensures forall x:int, m:int {:trigger x%m} :: m > 0 ==> 0 <= x%m < m;\n{\n    lemma_mod_basics();\n\n    forall x:int, m:int | m > 0\n        ensures m > 0 ==> 0 <= x%m < m;\n    {\n        lemma_mod_auto(m);\n    }\n}\n\nlemma lemma_mod_decreases(x:nat, d:nat)\n    requires 0<d;\n    ensures x%d <= x;\n{\n    lemma_mod_auto(d);\n}\n\nlemma lemma_mod_add_multiples_vanish(b:int, m:int)\n    requires 0 < m;\n    ensures (m + b) % m == b % m;\n{\n    lemma_mod_auto(m);\n}\n\nlemma lemma_mod_sub_multiples_vanish(b:int, m:int)\n    requires 0 < m;\n    ensures (-m + b) % m == b % m;\n{\n    lemma_mod_auto(m);\n}\n\nlemma lemma_mod_multiples_vanish(a:int, b:int, m:int)\n    decreases if a>0 then a else -a;\n    requires 0 < m;\n    ensures (m*a + b) % m == b % m;\n{\n    lemma_mod_auto(m);\n    lemma_mul_auto_induction(a, imap u :: (m*u + b) % m == b % m);\n}\n\nlemma lemma_add_mod_noop(x:int, y:int, m:int)\n    requires 0 < m;\n    ensures ((x % m) + (y % m)) % m == (x+y) % m;\n{\n    lemma_mod_auto(m);\n}\n\nlemma lemma_add_mod_noop_right(x:int, y:int, m:int)\n    requires 0 < m;\n    ensures (x + (y % m)) % m == (x+y) % m;\n{\n    lemma_mod_auto(m);\n}\n\nlemma lemma_mod_equivalence(x:int, y:int, m:int)\n    requires 0 < m;\n    ensures x % m == y % m <==> (x - y) % m == 0;\n{\n    lemma_mod_auto(m);\n}\n\nlemma lemma_sub_mod_noop(x:int, y:int, m:int)\n    requires 0 < m;\n    ensures ((x % m) - (y % m)) % m == (x-y) % m;\n{\n    lemma_mod_auto(m);\n}\n\nlemma lemma_sub_mod_noop_right(x:int, y:int, m:int)\n    requires 0 < m;\n    ensures (x - (y % m)) % m == (x-y) % m;\n{\n    lemma_mod_auto(m);\n}\n\nlemma lemma_mod_adds(a:int, b:int, d:int)\n    requires 0<d;\n    ensures a%d + b%d == (a+b)%d + d*((a%d + b%d)/d);\n    ensures (a%d + b%d) < d ==> a%d + b%d == (a+b)%d;\n{\n    lemma_mul_auto();\n    lemma_div_auto(d);\n}\n\nlemma {:timeLimitMultiplier 2} lemma_mod_neg_neg(x:int, d:int)\n    requires d > 0;\n    ensures x%d == (x*(1-d))%d;\n{\n    forall ensures (x - x * d) % d == x % d;\n    {\n        lemma_mod_auto(d);\n        var f := imap i :: (x - i * d) % d == x % d;\n        assert  MulAuto() ==> f[0]\n                        && (forall i {:trigger TMulAutoLe(0, i)} :: TMulAutoLe(0, i) && f[i] ==> f[i + 1])\n                        && (forall i {:trigger TMulAutoLe(i, 0)} :: TMulAutoLe(i, 0) && f[i] ==> f[i - 1]);\n        lemma_mul_auto_induction(x, imap i :: (x - i * d) % d == x % d);\n    }\n    lemma_mul_auto();\n}\n\nlemma lemma_fundamental_div_mod_converse(x:int, d:int, q:int, r:int)\n    requires d != 0;\n    requires 0 <= r < d;\n    requires x == q * d + r;\n    ensures q == x/d;\n    ensures r == x%d;\n{\n    lemma_div_auto(d);\n    lemma_mul_auto_induction(q, imap u :: u == (u * d + r) / d);\n    lemma_mul_auto_induction(q, imap u :: r == (u * d + r) % d);\n\n// REVIEW: this is a plausible alternative, but it times out:\n//    lemma_mul_auto();\n//    lemma_div_auto_induction(d, x, imap x :: x == q * d + r ==> q == x/d && r == x%d);\n}\n\nlemma lemma_mod_pos_bound(x:int, m:int)\n    decreases x;\n    requires 0 <= x;\n    requires 0 < m;\n    ensures  0 <= x%m < m;\n{\n    lemma_mod_auto(m);\n}\n\n\nlemma lemma_mul_mod_noop_left(x:int, y:int, m:int)\n    requires 0 < m;\n    ensures (x % m)*y % m == x*y % m;\n{\n    lemma_mod_auto(m);\n    lemma_mul_auto_induction(y, imap u :: (x % m)*u % m == x*u % m);\n}\n\nlemma lemma_mul_mod_noop_right(x:int, y:int, m:int)\n    requires 0 < m;\n    ensures x*(y % m) % m == (x*y) % m;\n{\n    lemma_mod_auto(m);\n    lemma_mul_auto_induction(x, imap u :: u*(y % m) % m == (u*y) % m);\n}\n\nlemma lemma_mul_mod_noop_general(x:int, y:int, m:int)\n    requires 0 < m;\n    ensures ((x % m) * y      ) % m == (x * y) % m;\n    ensures ( x      * (y % m)) % m == (x * y) % m;\n    ensures ((x % m) * (y % m)) % m == (x * y) % m;\n{\n    lemma_mod_properties();\n    lemma_mul_mod_noop_left(x, y, m);\n    lemma_mul_mod_noop_right(x, y, m);\n    lemma_mul_mod_noop_right(x % m, y, m);\n}\n\n\nlemma lemma_mul_mod_noop(x:int, y:int, m:int)\n    requires 0 < m;\n    ensures (x % m) * (y % m) % m == (x*y) % m;\n{\n    lemma_mul_mod_noop_general(x, y, m);\n}\n\nlemma lemma_power_mod_noop(b:int, e:nat, m:int)\n    decreases e;\n    requires 0 < m;\n    ensures power(b % m, e) % m == power(b, e) % m;\n{\n    reveal_power();\n    lemma_mod_properties();\n    if (e > 0)\n    {\n        calc {\n            power(b % m, e) % m;\n            ((b % m) * power(b % m, e - 1)) % m;\n            { lemma_mul_mod_noop_general(b, power(b % m, e - 1), m); }\n            ((b % m) * (power(b % m, e - 1) % m) % m) % m;\n            { lemma_power_mod_noop(b, e - 1, m); }\n            ((b % m) * (power(b, e - 1) % m) % m) % m;\n            { lemma_mul_mod_noop_general(b, power(b, e - 1), m); }\n            (b * (power(b, e - 1)) % m) % m;\n            (b * (power(b, e - 1))) % m;\n            power(b, e) % m;\n        }\n    }\n}\n\nlemma lemma_mod_subtraction(x:nat, s:nat, d:nat)\n    requires 0<d;\n    requires 0<=s<=x%d;\n    ensures x%d - s%d == (x-s)%d;\n{\n    lemma_mod_auto(d);\n}\n\nlemma lemma_mod_ordering(x:nat, k:nat, d:nat)\n    requires 1<d;\n    requires 0<k;\n    ensures 0<d*k;\n    ensures x%d <= x%(d*k);\n{\n    lemma_mul_strictly_increases(d,k);\n    calc {\n        x%d + d*(x/d);\n            { lemma_fundamental_div_mod(x,d); }\n        x;\n            { lemma_fundamental_div_mod(x,d*k); }\n        x%(d*k) + (d*k)*(x/(d*k));\n            { lemma_mul_is_associative_forall(); }\n        x%(d*k) + d*(k*(x/(d*k)));\n    }\n    calc {\n        x%d;\n            { lemma_mod_properties(); }\n        (x%d) % d;\n            { lemma_mod_multiples_vanish(x/d - k*(x/(d*k)), x%d, d); }\n        (x%d + d*(x/d - k*(x/(d*k)))) % d;\n            { lemma_mul_is_distributive_sub_forall(); }\n        (x%d + d*(x/d) - d*(k*(x/(d*k)))) % d;\n        (x%(d*k)) % d;\n        <= {\n            lemma_mod_properties();\n            lemma_mod_decreases(x%(d*k), d); }\n        x%(d*k);\n    }\n}\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// more probably-dead code\n\nlemma lemma_mod_multiples_basic(x:int, m:int)\n    requires m > 0;\n    ensures  (x * m) % m == 0;\n{\n    lemma_mod_auto(m);\n    lemma_mul_auto_induction(x, imap u :: (u * m) % m == 0);\n}\n\n//-\n//-////////////////////////////////////////////////////////////////////////////\n\n\n/************************************************************\n *  Lemmas that depend on properties of both div and mod    *\n ************************************************************/\n\n//-/////////////////////////////////////////////////////\n//- Proof that div is recursive div\n//-/////////////////////////////////////////////////////\nlemma lemma_div_plus_one(x:int, d:int)\n    requires d > 0;\n    //-requires x >= 0;\n    ensures 1 + x / d == (d + x) / d;\n{\n    lemma_div_auto(d);\n}\n\nlemma lemma_div_minus_one(x:int, d:int)\n    requires d > 0;\n    ensures -1 + x / d == (-d + x) / d;\n{\n    lemma_div_auto(d);\n}\n\nlemma lemma_mod_mod(x:int, a:int, b:int)\n    requires 0<a;\n    requires 0<b;\n    ensures 0<a*b;\n    ensures (x%(a*b))%a == x%a;\n{\n    lemma_mul_strictly_positive_forall();\n    calc {\n        x;\n            { lemma_fundamental_div_mod(x, a*b); }\n        (a*b)*(x/(a*b)) + x % (a*b);\n            { lemma_mul_is_associative_forall(); }\n        a*(b*(x/(a*b))) + x % (a*b);\n            { lemma_fundamental_div_mod(x%(a*b), a); }\n        a*(b*(x/(a*b))) + a*(x%(a*b)/a) + (x%(a*b))%a;\n            { lemma_mul_is_distributive_forall(); }\n        a*(b*(x/(a*b)) + x%(a*b)/a) + (x%(a*b))%a;\n    }\n    lemma_mod_properties();\n    lemma_mul_is_commutative_forall();\n    lemma_fundamental_div_mod_converse(x, a, b*(x/(a*b)) + x%(a*b)/a, (x%(a*b))%a);\n}\n\nlemma lemma_div_is_div_recursive(x:int, d:int)\n    requires d > 0;\n    ensures my_div_recursive(x, d) == x / d;\n{\n    lemma_div_auto_induction(d, x, imap u :: my_div_recursive(u, d) == u / d);\n\n// Omitted rather than prove lemma_negative_divisor\n//\n//-    if d > 0 {\n//-       lemma_div_is_div_pos(x, d); \n//-    } else {\n//-        calc {\n//-            my_div_recursive(x, d);\n//-            -1 * my_div_pos(x, -1*d);\n//-                { lemma_div_is_div_pos(x, -1*d); }\n//-            -1 * (x / (-1*d));\n//-                { lemma_negative_divisor(x, d); }\n//-            x / d;\n//-       }\n//-    }\n}\n\nlemma lemma_div_is_div_recursive_forall()\n    ensures forall x:int, d:int :: d > 0 ==> my_div_recursive(x, d) == x / d;\n{\n    forall x:int, d:int | d > 0\n        ensures my_div_recursive(x, d) == x / d;\n    {\n        lemma_div_is_div_recursive(x, d);\n    }\n}\n\n//-/////////////////////////////////////////////////////\n\n//-/////////////////////////////////////////////////////\n//- Proof that mod is recursive mod\n//-/////////////////////////////////////////////////////\n\nlemma lemma_mod_is_mod_recursive(x:int, m:int)\n    requires m > 0;\n    ensures my_mod_recursive(x, m) == x % m;\n    decreases if x < 0 then -x + m else x;\n{\n\n    if x < 0 { \n        calc { \n            my_mod_recursive(x, m);\n            my_mod_recursive(x + m, m);\n                { lemma_mod_is_mod_recursive(x + m, m); }\n            (x + m) % m;\n                { lemma_add_mod_noop(x, m, m); } \n            ((x % m) + (m % m)) % m;\n                { lemma_mod_basics(); }\n            (x % m) % m;\n                { lemma_mod_basics(); }\n            x % m;\n        }\n    } else if x < m { \n        lemma_small_mod(x, m);\n    } else {\n        calc { \n            my_mod_recursive(x, m);\n            my_mod_recursive(x - m, m);\n                { lemma_mod_is_mod_recursive(x - m, m); }\n            (x - m) % m;\n                { lemma_sub_mod_noop(x, m, m); } \n            ((x % m) - (m % m)) % m;\n                { lemma_mod_basics(); }\n            (x % m) % m;\n                { lemma_mod_basics(); }\n            x % m;\n        }\n    }\n}\n\nlemma lemma_mod_is_mod_recursive_forall()\n    ensures forall x:int, d:int :: d > 0 ==> my_mod_recursive(x, d) == x % d;\n{\n    forall x:int, d:int | d > 0\n        ensures my_mod_recursive(x, d) == x % d;\n    {\n        lemma_mod_is_mod_recursive(x, d);\n    }\n}\n\n//-/////////////////////////////////////////////////////\n\n\nlemma lemma_basic_div(d:int)\n    requires d > 0;\n    ensures forall x {:trigger x / d} :: 0 <= x < d ==> x / d == 0;\n{\n    lemma_div_auto(d);\n}\n\nlemma lemma_div_is_ordered(x:int, y:int, z:int)\n    requires x <= y;\n    requires z > 0;\n    ensures x / z <= y / z;\n{\n    lemma_div_auto_induction(z, x - y, imap xy :: xy <= 0 ==> (xy + y) / z <= y / z);\n}\n\nlemma lemma_div_decreases(x:int, d:int)\n    requires 0<x;\n    requires 1<d;\n    ensures x/d < x;\n{\n    lemma_div_auto_induction(d, x, imap u :: 0<u ==> u/d < u);\n}\n\nlemma lemma_div_nonincreasing(x:int, d:int)\n    requires 0<=x;\n    requires 0<d;\n    ensures x/d <= x;\n{\n    lemma_div_auto_induction(d, x, imap u :: 0<=u ==> u/d <= u);\n}\n\nlemma lemma_breakdown(a:int, b:int, c:int)\n    requires 0<=a;\n    requires 0<b;\n    requires 0<c;\n    ensures 0<b*c;\n    ensures a%(b*c) == b * ((a/b)%c) + a%b;\n{\n    lemma_mul_strictly_positive_forall();\n    lemma_div_pos_is_pos(a,b);\n    assert 0<=a/b;\n\n//-    lemma_mod_properties();\n//-    assert a%b < b;\n//-    assert 1<c;\n//-    calc {\n//-        b;\n//-        <    { lemma_mul_strictly_increases(c,b); }\n//-        c*b;\n//-            { lemma_mul_is_commutative_forall(); }\n//-        b*c;\n//-    }\n//-    lemma_mod_properties();\n//-    assert (a%b)%(b*c) < b;\n\n    calc {\n        (b*(a/b)) % (b*c) + (a%b) % (b*c);\n        <=    { lemma_part_bound1(a, b, c); }\n        b*(c-1) + (a%b) % (b*c);\n        <    { lemma_part_bound2(a, b, c); }\n        b*(c-1) + b;\n            { lemma_mul_basics_forall(); }\n        b*(c-1) + mul(b,1);\n            { lemma_mul_is_distributive_forall(); }\n        b*(c-1+1);\n        b*c;\n    }\n\n    calc {\n        a % (b*c);\n            { lemma_fundamental_div_mod(a,b); }\n        (b*(a/b)+a%b) % (b*c);\n            {\n                lemma_mod_properties();\n                assert 0<=a%b;\n                lemma_mul_nonnegative(b,a/b);\n                assert (b*(a/b)) % (b*c) + (a%b) % (b*c) < b*c;\n                lemma_mod_adds(b*(a/b), a%b, b*c);\n            }\n        (b*(a/b)) % (b*c) + (a%b) % (b*c);\n            {\n                lemma_mod_properties();\n                lemma_mul_increases(c,b);\n                lemma_mul_is_commutative_forall();\n                assert a%b<b<=b*c;\n                lemma_small_mod(a%b,b*c);\n                assert (a%b) % (b*c) == a%b;\n            }\n        (b*(a/b)) % (b*c) + a%b;\n            { lemma_truncate_middle(a/b,b,c); }\n        b * ((a/b)%c) + a%b;\n    }\n}\n\nlemma lemma_remainder_upper(x:int, divisor:int)\n    requires 0 <= x;\n    requires 0 < divisor;\n    ensures   x - divisor < x / divisor * divisor;\n{\n    lemma_mul_auto();\n    lemma_div_auto_induction(divisor, x, imap u :: 0 <= u ==> u - divisor < u / divisor * divisor);\n}\n\nlemma lemma_remainder_lower(x:int, divisor:int)\n    requires 0 <= x;\n    requires 0 < divisor;\n    ensures  x >= x / divisor * divisor;\n{\n    lemma_mul_auto();\n    lemma_div_auto_induction(divisor, x, imap u :: 0 <= u ==> u >= u / divisor * divisor);\n}\n\nlemma lemma_remainder(x:int, divisor:int)\n    requires 0 <= x;\n    requires 0 < divisor;\n    ensures  0 <= x - x / divisor * divisor < divisor;\n{\n    lemma_mul_auto();\n    lemma_div_auto_induction(divisor, x, imap u :: 0 <= u - u / divisor * divisor < divisor);\n}\n\n\nlemma lemma_div_denominator(x:int,c:nat,d:nat)\n    requires 0 <= x;\n    requires 0<c;\n    requires 0<d;\n    ensures c * d != 0;\n    ensures (x/c)/d == x / (c*d);\n{\n    lemma_mul_strictly_positive_forall();\n    //-assert 0 < c*d;\n    var R := x % (c*d);\n    lemma_mod_properties();\n    //-assert 0<=R;\n\n    lemma_div_pos_is_pos(R,c);\n    //-assert 0 <= R/c;\n    if (R/c >= d) {\n        lemma_fundamental_div_mod(R, c);\n//-        assert R >= c*(R/c);\n        lemma_mul_inequality(d, R/c, c);\n        lemma_mul_is_commutative_forall();\n//-        assert c*(R/c) >= c*d;\n//-        assert R >= c*d;\n        assert false;\n    }\n    assert R/c < d;\n\n    lemma_mul_basics_forall();\n    lemma_fundamental_div_mod_converse(R/c, d, 0, R/c);\n    assert (R/c) % d == R/c;\n\n    lemma_fundamental_div_mod(R, c);\n    assert c*(R/c) + R%c == R;\n\n    assert c*((R/c) % d) + R%c == R;\n\n    var k := x/(c*d);\n    lemma_fundamental_div_mod(x, c*d);\n    assert x == (c*d)*(x/(c*d)) + x % (c*d);\n    assert R == x - (c*d)*(x/(c*d));\n    assert R == x - (c*d)*k;\n\n    calc {\n        c*((x/c)%d) + x%c;\n            { lemma_mod_multiples_vanish(-k, x/c, d); lemma_mul_is_commutative_forall(); }\n        c*((x/c+(-k)*d) % d) + x%c;\n            { lemma_hoist_over_denominator(x, (-k)*d, c); }\n        c*(((x+(((-k)*d)*c))/c) % d) + x%c;\n            { lemma_mul_is_associative(-k,d,c); }\n        c*(((x+((-k)*(d*c)))/c) % d) + x%c;\n            { lemma_mul_unary_negation(k,d*c); }\n        c*(((x+(-(k*(d*c))))/c) % d) + x%c;\n            { lemma_mul_is_associative(k,d,c); }\n        c*(((x+(-(k*d*c)))/c) % d) + x%c;\n        c*(((x-k*d*c)/c) % d) + x%c;\n            {\n                lemma_mul_is_associative_forall();\n                lemma_mul_is_commutative_forall();\n            }\n        c*((R/c) % d) + x%c;\n        c*(R/c) + x%c;\n            { lemma_fundamental_div_mod(R,c);\n                assert R == c*(R/c) + R % c;\n                lemma_mod_mod(x,c,d);\n                assert R%c == x%c;\n            }\n        R;\n            { lemma_mod_is_mod_recursive_forall(); }\n        R%(c*d);\n        (x-(c*d)*k) % (c*d);\n            { lemma_mul_unary_negation(c*d,k); }\n        (x+(c*d)*(-k)) % (c*d);\n            { lemma_mod_multiples_vanish(-k, x, c*d); }\n        x % (c*d);\n    }\n    calc ==> {\n        c*(x/c) + x%c - R == c*(x/c) - c*((x/c)%d);\n            { lemma_fundamental_div_mod(x,c); }\n        x - R == c*(x/c) - c*((x/c)%d);\n    }\n    calc ==> {\n        true;\n            { lemma_fundamental_div_mod(x/c,d); }\n        d*((x/c)/d) == x/c - ((x/c)%d);\n        c*(d*((x/c)/d)) == c*(x/c - ((x/c)%d));\n            { lemma_mul_is_associative_forall(); }\n        (c*d)*((x/c)/d) == c*(x/c - ((x/c)%d));\n            { lemma_mul_is_distributive_forall(); }\n        (c*d)*((x/c)/d) == c*(x/c) - c*((x/c)%d);\n        (c*d)*((x/c)/d) == x - R;\n            { lemma_fundamental_div_mod(x, c*d); }\n        (c*d)*((x/c)/d) == (c*d)*(x/(c*d)) + x%(c*d) - R;\n        (c*d)*((x/c)/d) == (c*d)*(x/(c*d));\n            { lemma_mul_one_to_one(c*d, (x/c)/d, x/(c*d)); }\n        (x/c)/d == x/(c*d);\n    }\n}\n\nlemma lemma_mul_hoist_inequality(x:int, y:int, z:int)\n    requires 0 <= x;\n    requires 0 < z;\n    ensures x*(y/z) <= (x*y)/z;\n{\n    calc {\n        (x*y)/z;\n            { lemma_fundamental_div_mod(y, z); }\n        (x*(z*(y/z)+y%z))/z;\n            { lemma_mul_is_distributive_forall(); }\n        (x*(z*(y/z))+x*(y%z))/z;\n        >=  {\n            lemma_mod_properties();\n            lemma_mul_nonnegative(x, y%z);\n            lemma_div_is_ordered(x*(z*(y/z)), x*(z*(y/z))+x*(y%z), z); }\n        (x*(z*(y/z)))/z;\n            { lemma_mul_is_associative_forall();\n              lemma_mul_is_commutative_forall(); }\n        (z*(x*(y/z)))/z;\n            { lemma_div_multiples_vanish(x*(y/z), z); }\n        x*(y/z);\n    }\n}\n\nlemma lemma_indistinguishable_quotients(a:int, b:int, d:int)\n    requires 0<d;\n    requires 0 <= a - a%d <= b < a + d - a%d;\n    ensures a/d == b/d;\n{\n    lemma_div_auto_induction(d, a - b, imap ab :: var u := ab + b; 0 <= u - u%d <= b < u + d - u%d ==> u/d == b/d);\n}\n\nlemma lemma_truncate_middle(x:int, b:int, c:int)\n    requires 0<=x;\n    requires 0<b;\n    requires 0<c;\n    ensures 0<b*c;\n    ensures (b*x)%(b*c) == b*(x%c);\n{\n    lemma_mul_strictly_positive_forall();\n    lemma_mul_nonnegative_forall();\n    calc {\n        b*x;\n            { lemma_fundamental_div_mod(b*x,b*c); }\n        (b*c)*((b*x)/(b*c)) + (b*x)%(b*c);\n            { lemma_div_denominator(b*x,b,c); }\n        (b*c)*(((b*x)/b)/c) + (b*x)%(b*c);\n            { lemma_mul_is_commutative_forall(); lemma_div_by_multiple(x,b); }\n        (b*c)*(x/c) + (b*x)%(b*c);\n    }\n    calc ==> {\n        true;\n            { lemma_fundamental_div_mod(x,c); }\n        x == c*(x/c) + x%c;\n        b*x == b*(c*(x/c) + x%c);\n            { lemma_mul_is_distributive_forall(); }\n        b*x == b*(c*(x/c)) + b*(x%c);\n            { lemma_mul_is_associative_forall(); }\n        b*x == (b*c)*(x/c) + b*(x%c);\n    }\n}\n\nlemma lemma_div_multiples_vanish_quotient(x:int, a:int, d:int)\n    requires 0<x;\n    requires 0<=a;\n    requires 0<d;\n    ensures 0 < x*d;\n    ensures a/d == (x*a)/(x*d);\n{\n    lemma_mul_strictly_positive(x,d);\n    calc {\n        (x*a)/(x*d);\n            {\n                lemma_mul_nonnegative(x,a);\n                lemma_div_denominator(x*a, x, d); }\n        ((x*a)/x) / d;\n            { lemma_div_multiples_vanish(a, x); }\n        a / d;\n    }\n}\n\nlemma lemma_round_down(a:int, r:int, d:int)\n    requires 0<d;\n    requires a%d == 0;\n    requires 0<=r<d;\n    ensures a==d*((a+r)/d);\n{\n    lemma_mul_auto();\n    lemma_div_auto_induction(d, a, imap u :: u%d == 0 ==> u==d*((u+r)/d));\n}\n\n\nlemma lemma_div_multiples_vanish_fancy(x:int, b:int, d:int)\n    requires 0<d;\n    requires 0<=b<d;\n    ensures (d*x + b)/d == x;\n{\n    lemma_div_auto(d);\n    lemma_mul_auto_induction(x, imap u :: (d*u + b)/d == u);\n}\n\nlemma lemma_div_multiples_vanish(x:int, d:int)\n    requires 0<d;\n    ensures (d*x)/d == x;\n{\n    lemma_div_multiples_vanish_fancy(x, 0, d);\n}\n\n// Oh, this is a synonym for lemma_div_multiples_vanish\nlemma lemma_div_by_multiple(b:int, d:int)\n    requires 0 <= b;\n    requires 0 < d;\n    ensures  (b*d) / d == b;\n{   \n    lemma_div_multiples_vanish(b,d);\n}\n\n\nlemma lemma_div_by_multiple_is_strongly_ordered(x:int, y:int, m:int, z:int)\n    requires x < y;\n    requires y == m * z;\n    requires z > 0;\n    ensures     x / z < y / z;\n{\n    lemma_mod_multiples_basic(m, z);\n    lemma_div_auto_induction(z, y - x, imap yx :: var u := yx + x; x < u && u % z == 0 ==> x / z < u / z);\n}\n\nlemma lemma_multiply_divide_le(a:int, b:int, c:int)\n    requires 0 < b;\n    requires a <= b * c;\n    ensures  a / b <= c;\n{\n    lemma_mod_multiples_basic(c, b);\n    lemma_div_auto_induction(b, b * c - a, imap i :: 0 <= i && (i + a) % b == 0 ==> a / b <= (i + a) / b);\n    lemma_div_multiples_vanish(c, b);\n}\n\nlemma lemma_multiply_divide_lt(a:int, b:int, c:int)\n    requires 0 < b;\n    requires a < b * c;\n    ensures  a / b < c;\n{\n    lemma_mod_multiples_basic(c, b);\n    lemma_div_auto_induction(b, b * c - a, imap i :: 0 < i && (i + a) % b == 0 ==> a / b < (i + a) / b);\n    lemma_div_multiples_vanish(c, b);\n}\n\nlemma lemma_hoist_over_denominator(x:int, j:int, d:nat)\n    requires 0<d;\n    ensures x/d + j == (x+j*d) / d;\n{\n    lemma_div_auto(d);\n    lemma_mul_auto_induction(j, imap u :: x/d + u == (x+u*d) / d);\n}\n\nlemma lemma_part_bound1(a:int, b:int, c:int)\n    requires 0<=a;\n    requires 0<b;\n    requires 0<c;\n    ensures 0<b*c;\n    ensures (b*(a/b) % (b*c)) <= b*(c-1);\n{\n    lemma_mul_strictly_positive_forall();\n    calc {\n        b*(a/b) % (b*c);\n            { lemma_fundamental_div_mod(b*(a/b),b*c); }\n        b*(a/b) - (b*c)*((b*(a/b))/(b*c));\n            { lemma_mul_is_associative_forall(); }\n        b*(a/b) - b*(c*((b*(a/b))/(b*c)));\n            { lemma_mul_is_distributive_forall(); }\n        b*((a/b) - (c*((b*(a/b))/(b*c))));\n    }\n\n    calc ==> {\n        true;\n            { lemma_mod_properties(); }\n        b*(a/b) % (b*c) < b*c;\n        b*((a/b) - (c*((b*(a/b))/(b*c)))) < b*c;\n            { lemma_mul_is_commutative_forall(); lemma_mul_strict_inequality_converse_forall(); }\n        ((a/b) - (c*((b*(a/b))/(b*c)))) < c;\n        ((a/b) - (c*((b*(a/b))/(b*c)))) <= c-1;\n            { lemma_mul_is_commutative_forall(); lemma_mul_inequality_forall(); }\n        b*((a/b) - (c*((b*(a/b))/(b*c)))) <= b*(c-1);\n        b*(a/b) % (b*c) <= b*(c-1);\n    }\n}\n\nlemma lemma_part_bound2(a:int, b:int, c:int)\n    requires 0<=a;\n    requires 0<b;\n    requires 0<c;\n    ensures 0<b*c;\n    ensures (a%b)%(b*c) < b;\n{\n    lemma_mul_strictly_positive_forall();\n    lemma_mod_properties();\n    assert a%b < b;\n    lemma_mul_increases_forall();\n    lemma_mul_is_commutative_forall();\n    assert b <= b * c;\n    assert 0 <= a%b < b * c;\n    lemma_mod_properties();\n    lemma_small_mod(a%b,b*c);\n    assert (a%b)%(b*c) == a%b;\n}\n\nlemma lemma_mod_breakdown(a:int, b:int, c:int)\n    requires 0<=a;\n    requires 0<b;\n    requires 0<c;\n    ensures 0<b*c;\n    ensures a%(b*c) == b * ((a/b)%c) + a%b;\n{\n    lemma_mul_strictly_positive_forall();\n    lemma_div_pos_is_pos(a,b);\n    assert 0<=a/b;\n\n    calc {\n        (b*(a/b)) % (b*c) + (a%b) % (b*c);\n        <=    { lemma_part_bound1(a, b, c); }\n        b*(c-1) + (a%b) % (b*c);\n        <    { lemma_part_bound2(a, b, c); }\n        b*(c-1) + b;\n            { lemma_mul_basics_forall(); }\n        b*(c-1) + mul(b,1);\n            { lemma_mul_is_distributive_forall(); }\n        b*(c-1+1);\n        b*c;\n    }\n\n    calc {\n        a % (b*c);\n            { lemma_fundamental_div_mod(a,b); }\n        (b*(a/b)+a%b) % (b*c);\n            {\n                lemma_mod_properties();\n                assert 0<=a%b;\n                lemma_mul_nonnegative(b,a/b);\n                assert (b*(a/b)) % (b*c) + (a%b) % (b*c) < b*c;\n                lemma_mod_adds(b*(a/b), a%b, b*c);\n            }\n        (b*(a/b)) % (b*c) + (a%b) % (b*c);\n            {\n                lemma_mod_properties();\n                lemma_mul_increases(c,b);\n                lemma_mul_is_commutative_forall();\n                assert a%b<b<=b*c;\n                lemma_small_mod(a%b,b*c);\n                assert (a%b) % (b*c) == a%b;\n            }\n        (b*(a/b)) % (b*c) + a%b;\n            { lemma_truncate_middle(a/b,b,c); }\n        b * ((a/b)%c) + a%b;\n    }\n}\n\n\nlemma lemma_div_denominator_forall()\n    ensures forall c:nat,d:nat {:trigger c * d} :: 0 < c && 0 < d ==> c * d != 0;\n    ensures forall x:int,c:nat,d:nat {:trigger (x/c)/d} :: 0 <= x && 0 < c && 0 < d\n        ==> (x/c)/d == x/(c*d);\n{\n    lemma_mul_nonzero_forall();\n    forall (x:int,c:nat,d:nat | 0 <= x && 0 < c && 0 < d)\n        ensures c * d != 0;\n        ensures (x/c)/d == x/(c*d);\n    {\n        lemma_div_denominator(x,c,d);\n    }\n}\n\n} \n"
  },
  {
    "path": "Armada/util/math/div_auto.i.dfy",
    "content": "include \"mod_auto.i.dfy\"\ninclude \"div_auto_proofs.i.dfy\"\ninclude \"mod_auto_proofs.i.dfy\"\n\nmodule Math__div_auto_i {\nimport opened Math__mod_auto_i\nimport opened Math__div_auto_proofs_i\nimport opened Math__mod_auto_proofs_i\n\npredicate DivAuto(n:int)\n    requires n > 0; // TODO: allow n < 0\n{\n    ModAuto(n)\n && (n / n == -((-n) / n) == 1)\n && (forall x:int {:trigger x / n} :: 0 <= x < n <==> x / n == 0)\n && (forall x:int, y:int {:trigger (x + y) / n} ::\n                (var z := (x % n) + (y % n);\n                    (  (0 <= z < n     && (x + y) / n == x / n + y / n)\n                    || (n <= z < n + n && (x + y) / n == x / n + y / n + 1))))\n && (forall x:int, y:int {:trigger (x - y) / n} ::\n                (var z := (x % n) - (y % n);\n                    (   (0 <= z < n && (x - y) / n == x / n - y / n)\n                    || (-n <= z < 0 && (x - y) / n == x / n - y / n - 1))))\n}\n\nlemma lemma_div_auto(n:int)\n    requires n > 0;\n    ensures  DivAuto(n);\n{\n    lemma_mod_auto(n);\n    lemma_div_auto_basics(n);\n    assert (0 + n) / n == 1;\n    assert (0 - n) / n == -1;\n    forall x:int, y:int {:trigger (x + y) / n}\n        ensures  (var z := (x % n) + (y % n);\n                     (   (0 <= z < n && (x + y) / n == x / n + y / n)\n                      || (n <= z < 2 * n && (x + y) / n == x / n + y / n + 1)));\n    {\n        var f := imap xy:(int, int) ::\n                 (var z := (xy.0 % n) + (xy.1 % n);\n                     (   (0 <= z < n && (xy.0 + xy.1) / n == xy.0 / n + xy.1 / n)\n                      || (n <= z < 2 * n && (xy.0 + xy.1) / n == xy.0 / n + xy.1 / n + 1)));\n        forall i, j\n            ensures j >= 0 && f[(i, j)] ==> f[(i, j + n)];\n            ensures i < n  && f[(i, j)] ==> f[(i - n, j)];\n            ensures j < n  && f[(i, j)] ==> f[(i, j - n)];\n            ensures i >= 0 && f[(i, j)] ==> f[(i + n, j)];\n        {\n            assert ((i + n) + j) / n == ((i + j) + n) / n;\n            assert (i + (j + n)) / n == ((i + j) + n) / n;\n            assert ((i - n) + j) / n == ((i + j) - n) / n;\n            assert (i + (j - n)) / n == ((i + j) - n) / n;\n        }\n        forall i, j\n            ensures 0 <= i < n && 0 <= j < n ==> f[(i, j)];\n        {\n            assert ((i + n) + j) / n == ((i + j) + n) / n;\n            assert (i + (j + n)) / n == ((i + j) + n) / n;\n            assert ((i - n) + j) / n == ((i + j) - n) / n;\n            assert (i + (j - n)) / n == ((i + j) - n) / n;\n        }\n        lemma_mod_induction_forall2(n, f);\n        assert f[(x, y)];\n    }\n    forall x:int, y:int {:trigger (x - y) / n}\n        ensures  (var z := (x % n) - (y % n);\n                     (   (0 <= z < n && (x - y) / n == x / n - y / n)\n                     || (-n <= z < 0 && (x - y) / n == x / n - y / n - 1)));\n    {\n        var f := imap xy:(int, int) ::\n                 (var z := (xy.0 % n) - (xy.1 % n);\n                     (   (0 <= z < n && (xy.0 - xy.1) / n == xy.0 / n - xy.1 / n)\n                     || (-n <= z < 0 && (xy.0 - xy.1) / n == xy.0 / n - xy.1 / n - 1)));\n        forall i, j\n            ensures j >= 0 && f[(i, j)] ==> f[(i, j + n)];\n            ensures i < n  && f[(i, j)] ==> f[(i - n, j)];\n            ensures j < n  && f[(i, j)] ==> f[(i, j - n)];\n            ensures i >= 0 && f[(i, j)] ==> f[(i + n, j)];\n        {\n            assert ((i + n) - j) / n == ((i - j) + n) / n;\n            assert (i - (j - n)) / n == ((i - j) + n) / n;\n            assert ((i - n) - j) / n == ((i - j) - n) / n;\n            assert (i - (j + n)) / n == ((i - j) - n) / n;\n        }\n        forall i, j\n            ensures 0 <= i < n && 0 <= j < n ==> f[(i, j)];\n        {\n            assert ((i + n) - j) / n == ((i - j) + n) / n;\n            assert (i - (j - n)) / n == ((i - j) + n) / n;\n            assert ((i - n) - j) / n == ((i - j) - n) / n;\n            assert (i - (j + n)) / n == ((i - j) - n) / n;\n        }\n        lemma_mod_induction_forall2(n, f);\n        assert f[(x, y)];\n    }\n}\n\npredicate TDivAutoLe(x:int, y:int) { x <= y }\n\nlemma lemma_div_auto_induction(n:int, x:int, f:imap<int,bool>)\n    requires n > 0;\n    requires forall i :: i in f;\n    requires DivAuto(n) ==> (forall i {:trigger TDivAutoLe(0, i)} :: TDivAutoLe(0, i) && i < n ==> f[i])\n                         && (forall i {:trigger TDivAutoLe(0, i)} :: TDivAutoLe(0, i) && f[i] ==> f[i + n])\n                         && (forall i {:trigger TDivAutoLe(i + 1, n)} :: TDivAutoLe(i + 1, n) && f[i] ==> f[i - n]);\n    ensures  DivAuto(n);\n    ensures  f[x];\n{\n    lemma_div_auto(n);\n    assert forall i :: TDivAutoLe(0, i) && i < n ==> f[i];\n    assert forall i {:trigger f[i], f[i + n]} :: TDivAutoLe(0, i) && f[i] ==> f[i + n];\n    assert forall i {:trigger f[i], f[i - n]} :: TDivAutoLe(i + 1, n) && f[i] ==> f[i - n];\n    lemma_mod_induction_forall(n, f);\n    assert f[x];\n}\n\nlemma lemma_div_auto_induction_forall(n:int, f:imap<int,bool>)\n    requires n > 0;\n    requires forall i :: i in f;\n    requires DivAuto(n) ==> (forall i {:trigger TDivAutoLe(0, i)} :: TDivAutoLe(0, i) && i < n ==> f[i])\n                         && (forall i {:trigger TDivAutoLe(0, i)} :: TDivAutoLe(0, i) && f[i] ==> f[i + n])\n                         && (forall i {:trigger TDivAutoLe(i + 1, n)} :: TDivAutoLe(i + 1, n) && f[i] ==> f[i - n]);\n    ensures  DivAuto(n);\n    ensures  forall i {:trigger f[i]} :: f[i];\n{\n    lemma_div_auto(n);\n    assert forall i :: TDivAutoLe(0, i) && i < n ==> f[i];\n    assert forall i {:trigger f[i], f[i + n]} :: TDivAutoLe(0, i) && f[i] ==> f[i + n];\n    assert forall i {:trigger f[i], f[i - n]} :: TDivAutoLe(i + 1, n) && f[i] ==> f[i - n];\n    lemma_mod_induction_forall(n, f);\n}\n\n} \n"
  },
  {
    "path": "Armada/util/math/div_auto_proofs.i.dfy",
    "content": "include \"mod_auto.i.dfy\"\ninclude \"mod_auto_proofs.i.dfy\"\n  \nmodule Math__div_auto_proofs_i {\nimport opened Math__mod_auto_i\nimport opened Math__mod_auto_proofs_i\n\nlemma lemma_div_auto_basics(n:int)\n    requires n > 0;\n    ensures  (n / n == -((-n) / n) == 1)\n    ensures  (forall x:int {:trigger x / n} :: 0 <= x < n <==> x / n == 0)\n    ensures  forall x:int {:trigger (x + n) / n} :: (x + n) / n == x / n + 1;\n    ensures  forall x:int {:trigger (x - n) / n} :: (x - n) / n == x / n - 1;\n{\n    lemma_mod_auto(n);\n    lemma_mod_auto_basics(n);\n    lemma_small_div();\n    lemma_div_by_self(n);\n    forall x:int | x / n == 0 ensures 0 <= x < n;\n    {\n        lemma_fundamental_div_mod(x, n);\n    }\n}\n\n\n} \n"
  },
  {
    "path": "Armada/util/math/div_boogie.i.dfy",
    "content": "include \"div_def.i.dfy\"\ninclude \"mul.i.dfy\"\n\nmodule Math__div_boogie_i {\nimport opened Math__div_def_i\nimport opened Math__mul_i\n\nlemma lemma_div_is_div_boogie(x:int, d:int)\n    requires d != 0;\n//-    ensures INTERNAL_div(x, d) == INTERNAL_div_boogie(x, d);\n{\n}\n\nlemma lemma_mod_is_mod_boogie(x:int, d:int)\n    requires d > 0;\n    //-ensures INTERNAL_mod(x, d) == INTERNAL_mod_boogie(x, d);\n{\n}\n\n//-static lemma lemma_div_is_div_boogie_at_least_for_2(x:int)\n//-    ensures INTERNAL_div(x, 2) == INTERNAL_div_boogie(x,2);\n//-{\n//-}\n//-\n//-static lemma lemma_div_is_div_boogie_for_4_which_is_also_a_number(x:int)\n//-    ensures INTERNAL_div(x, 4) == INTERNAL_div_boogie(x,4);\n//-{\n//-}\n//-\n//-static lemma lemma_div_is_div_boogie_for_8_which_is_also_a_number(x:int)\n//-    ensures INTERNAL_div(x, 8) == INTERNAL_div_boogie(x,8);\n//-{\n//-}\n//-\n//-static lemma lemma_div_is_div_boogie_for_16_which_is_also_a_number(x:int)\n//-    ensures INTERNAL_div(x, 16) == INTERNAL_div_boogie(x,16);\n//-{\n//-}\n//-\n// Copy-pasta from lemma_div_is_div_boogie_at_least_for_2\n//-static lemma lemma_div_is_div_boogie_for_256_which_is_also_a_number(x:int)\n//-    ensures INTERNAL_div(x, 256) == INTERNAL_div_boogie(x,256);\n//-{\n//-}\n//-\n//-static lemma lemma_div_is_div_boogie_for_65536_which_is_also_a_number(x:int)\n//-    ensures INTERNAL_div(x, 65536) == INTERNAL_div_boogie(x,65536);\n//-{\n//-}\n//-\n//-static lemma lemma_div_is_div_boogie_for_16777216_which_is_also_a_number(x:int)\n//-    ensures INTERNAL_div(x, 16777216) == INTERNAL_div_boogie(x,16777216);\n//-{\n//-}\n//-\n//-static lemma lemma_mod_is_mod_boogie_for_2_which_is_also_a_number(x:int)\n//-    ensures INTERNAL_mod(x, 2) == INTERNAL_mod_boogie(x,2);\n//-{\n//-}\n//-\n//-static lemma lemma_mod_is_mod_boogie_for_4_which_is_also_a_number(x:int)\n//-    ensures INTERNAL_mod(x, 4) == INTERNAL_mod_boogie(x,4);\n//-{\n//-}\n//-\n//-static lemma lemma_mod_is_mod_boogie_for_16_which_is_also_a_number(x:int)\n//-    ensures INTERNAL_mod(x, 16) == INTERNAL_mod_boogie(x,16);\n//-{\n//-}\n//-\n//-static lemma lemma_mod_is_mod_boogie_for_256_which_is_also_a_number(x:int)\n//-    ensures INTERNAL_mod(x, 256) == INTERNAL_mod_boogie(x,256);\n//-{\n//-}\n//-\n//-static lemma lemma_mod_is_mod_boogie_for_65536_which_is_also_a_number(x:int)\n//-    ensures INTERNAL_mod(x, 65536) == INTERNAL_mod_boogie(x,65536);\n//-{\n//-}\n\n} \n"
  },
  {
    "path": "Armada/util/math/div_def.i.dfy",
    "content": "//- Specs/implements mathematical div and mod, not the C version.\n//- This may produce \"surprising\" results for negative values\n//- For example, -3 div 5 is -1 and -3 mod 5 is 2.\n//- Note this is consistent: -3 * -1 + 2 == 5\n\nmodule Math__div_def_i {\n/*\nfunction mod(x:int, m:int) : int\n    requires m > 0;\n    decreases if x < 0 then (m - x) else x;\n{\n    if x < 0 then\n        mod(m + x, m)\n    else if x < m then\n        x\n    else\n        mod(x - m, m)\n}\n*/\n\nfunction div(x:int, d:int) : int\n    requires d != 0;\n{\n    x/d\n}\n\nfunction mod(x:int, d:int) : int\n    requires d != 0;\n{\n    x%d\n}\n\nfunction div_recursive(x:int, d:int) : int\n    requires d != 0;\n{ INTERNAL_div_recursive(x,d) }\n\nfunction mod_recursive(x:int, d:int) : int\n    requires d > 0;\n{ INTERNAL_mod_recursive(x,d) }\n\nfunction mod_boogie(x:int, y:int) : int\n    requires y != 0;\n{ x % y } //- INTERNAL_mod_boogie(x,y) }\n\nfunction div_boogie(x:int, y:int) : int\n    requires y != 0;\n{ x / y } //-{ INTERNAL_div_boogie(x,y) }\n\nfunction my_div_recursive(x:int, d:int) : int\n    requires d != 0;\n{\n    if d > 0 then\n        my_div_pos(x, d)\n    else\n        -1 * my_div_pos(x, -1*d)\n}\n\nfunction my_div_pos(x:int, d:int) : int\n    requires d >  0;\n    decreases if x < 0 then (d - x) else x;\n{\n    if x < 0 then\n        -1 + my_div_pos(x+d, d)\n    else if x < d then\n        0\n    else\n        1 + my_div_pos(x-d, d)\n}\n\nfunction my_mod_recursive(x:int, m:int) : int\n    requires m > 0;\n    decreases if x < 0 then (m - x) else x;\n{\n    if x < 0 then\n        my_mod_recursive(m + x, m)\n    else if x < m then\n        x\n    else\n        my_mod_recursive(x - m, m)\n}\n\n\n//- Kept for legacy reasons:\n//-static function INTERNAL_mod_boogie(x:int, m:int) : int   { x % y }\nfunction INTERNAL_mod_recursive(x:int, m:int) : int  \n    requires m > 0;\n{ my_mod_recursive(x, m) }\n\n//-static function INTERNAL_div_boogie(x:int, m:int) : int   { x / m }\nfunction INTERNAL_div_recursive(x:int, d:int) : int \n    requires d != 0;\n{ my_div_recursive(x, d) }\n\n\n/*\nghost method mod_test()\n{\n    assert -3 % 5 == 2;\n    assert 10 % -5 == 0;\n    assert 1 % -5 == 1;\n    assert -3 / 5 == -1;\n}\n*/\n\n} \n"
  },
  {
    "path": "Armada/util/math/div_nonlinear.i.dfy",
    "content": "//- <NuBuild AddDafnyFlag /z3opt:smt.arith.nl=true/>\n//- WARNING: In general, you shouldn't need to call these directly.  Try\n//- to use the ones in div.i.dfy instead.  They're more full-featured anyway.\n\nmodule Math__div_nonlinear_i {\n\n// WARNING: Think three times before adding anything to this file!\n// Nonlinear verification is highly unstable, so even if it appears to work,\n// it may cause problems down the road.  Thus, we want to keep this file as\n// small and simple as possible.  Instead of adding code here, try proving\n// it in div.i.dfy using the connection to the recursive definition\n\nlemma lemma_div_of_0(d:int)\n    requires d != 0;\n    ensures 0/d == 0;\n{ }\n\nlemma lemma_div_by_self(d:int)\n    requires d != 0;\n    ensures d/d == 1;\n{ }\n\nlemma lemma_small_div()\n    ensures forall x, d {:trigger x / d} :: 0 <= x < d && d > 0 ==> x / d == 0;\n{ }\n\nlemma lemma_mod_of_zero_is_zero(m:int)\n    requires 0 < m;\n    ensures 0 % m == 0;\n{ }\n\nlemma lemma_fundamental_div_mod(x:int, d:int)\n    requires d != 0;\n    ensures x == d * (x/d) + (x%d);\n{ }\n\nlemma lemma_0_mod_anything()\n    ensures forall m:int {:trigger 0 % m} :: m > 0 ==> 0 % m == 0;\n{ }\n\nlemma lemma_mod_yourself(m:int)\n    ensures m > 0 ==> m % m == 0;\n{ }\n\nlemma lemma_small_mod(x:nat, m:nat)\n    requires x<m;\n    requires 0<m;\n    ensures x % m == x;\n{ }\n\nlemma lemma_mod_range(x:int, m:int)\n    requires m > 0;\n    ensures 0 <= x % m < m;\n{ }\n\nlemma lemma_real_div_gt(x:real, y:real)\n    requires x > y;\n    requires x >= 0.0;\n    requires y > 0.0;\n    ensures  x / y > 1 as real;\n{ }\n\n} \n"
  },
  {
    "path": "Armada/util/math/mod_auto.i.dfy",
    "content": "include \"mod_auto_proofs.i.dfy\"\n\nmodule Math__mod_auto_i {\nimport opened Math__mod_auto_proofs_i\n\n\npredicate eq_mod(x:int, y:int, n:int)\n    requires n > 0;\n{\n    (x - y) % n == 0 // same as x % n == y % n, but easier to do induction on x - y than x and y separately\n}\n\npredicate ModAuto(n:int)\n    requires n > 0;\n{\n    (n % n == (-n) % n == 0)\n && (forall x:int {:trigger (x % n) % n} :: (x % n) % n == x % n)\n && (forall x:int {:trigger x % n} :: 0 <= x < n <==> x % n == x)\n && (forall x:int, y:int {:trigger (x + y) % n} ::\n                (var z := (x % n) + (y % n);\n                    (  (0 <= z < n     && (x + y) % n == z)\n                    || (n <= z < n + n && (x + y) % n == z - n))))\n && (forall x:int, y:int {:trigger (x - y) % n} ::\n                (var z := (x % n) - (y % n);\n                    (   (0 <= z < n && (x - y) % n == z)\n                    || (-n <= z < 0 && (x - y) % n == z + n))))\n}\n\nlemma lemma_QuotientAndRemainderUnique(x:int, q:int, r:int, n:int)\n    requires n > 0\n    requires 0 <= r < n\n    requires x == q * n + r\n    ensures  q == x / n\n    ensures  r == x % n\n    decreases if q > 0 then q else -q\n{\n    lemma_mod_auto_basics(n);\n    if q > 0 {\n        assert q * n + r == (q - 1) * n + r + n;\n        lemma_QuotientAndRemainderUnique(x - n, q - 1, r, n);\n    }\n    else if q < 0 {\n        assert q * n + r == (q + 1) * n + r - n;\n        lemma_QuotientAndRemainderUnique(x + n, q + 1, r, n);\n    }\n}\n\nlemma lemma_mod_auto(n:int)\n    requires n > 0;\n    ensures  ModAuto(n);\n{\n    lemma_mod_auto_basics(n);\n\n    forall x:int, y:int {:trigger (x + y) % n}\n        ensures var z := (x % n) + (y % n);\n                  (0 <= z < n && (x + y) % n == z)\n                || (n <= z < 2 * n && (x + y) % n == z - n)\n    {\n        var xq, xr := x / n, x % n;\n        assert x == xq * n + xr;\n        var yq, yr := y / n, y % n;\n        assert y == yq * n + yr;\n        if xr + yr < n {\n            lemma_QuotientAndRemainderUnique(x + y, xq + yq, xr + yr, n);\n        }\n        else {\n            lemma_QuotientAndRemainderUnique(x + y, xq + yq + 1, xr + yr - n, n);\n        }\n    }\n\n    forall x:int, y:int {:trigger (x - y) % n}\n        ensures var z := (x % n) - (y % n);\n                  (0 <= z < n && (x - y) % n == z)\n                || (-n <= z < 0 && (x - y) % n == z + n)\n    {\n        var xq, xr := x / n, x % n;\n        assert x == xq * n + xr;\n        var yq, yr := y / n, y % n;\n        assert y == yq * n + yr;\n        if xr - yr >= 0 {\n            lemma_QuotientAndRemainderUnique(x - y, xq - yq, xr - yr, n);\n        }\n        else {\n            lemma_QuotientAndRemainderUnique(x - y, xq - yq - 1, xr - yr + n, n);\n        }\n    }\n}\n\npredicate TModAutoLe(x:int, y:int) { x <= y }\n\nlemma lemma_mod_auto_induction(n:int, x:int, f:imap<int,bool>)\n    requires n > 0;\n    requires forall i :: i in f;\n    requires ModAuto(n) ==> (forall i {:trigger TModAutoLe(0, i)} :: TModAutoLe(0, i) && i < n ==> f[i])\n                         && (forall i {:trigger TModAutoLe(0, i)} :: TModAutoLe(0, i) && f[i] ==> f[i + n])\n                         && (forall i {:trigger TModAutoLe(i + 1, n)} :: TModAutoLe(i + 1, n) && f[i] ==> f[i - n]);\n    ensures  ModAuto(n);\n    ensures  f[x];\n{\n    lemma_mod_auto(n);\n    assert forall i :: TModAutoLe(0, i) && i < n ==> f[i];\n    assert forall i {:trigger f[i], f[i + n]} :: TModAutoLe(0, i) && f[i] ==> f[i + n];\n    assert forall i {:trigger f[i], f[i - n]} :: TModAutoLe(i + 1, n) && f[i] ==> f[i - n];\n    lemma_mod_induction_forall(n, f);\n    assert f[x];\n}\n\nlemma lemma_mod_auto_induction_forall(n:int, f:imap<int,bool>)\n    requires n > 0;\n    requires forall i :: i in f;\n    requires ModAuto(n) ==> (forall i {:trigger TModAutoLe(0, i)} :: TModAutoLe(0, i) && i < n ==> f[i])\n                         && (forall i {:trigger TModAutoLe(0, i)} :: TModAutoLe(0, i) && f[i] ==> f[i + n])\n                         && (forall i {:trigger TModAutoLe(i + 1, n)} :: TModAutoLe(i + 1, n) && f[i] ==> f[i - n]);\n    ensures  ModAuto(n);\n    ensures  forall i {:trigger f[i]} :: f[i];\n{\n    lemma_mod_auto(n);\n    assert forall i :: TModAutoLe(0, i) && i < n ==> f[i];\n    assert forall i {:trigger f[i], f[i + n]} :: TModAutoLe(0, i) && f[i] ==> f[i + n];\n    assert forall i {:trigger f[i], f[i - n]} :: TModAutoLe(i + 1, n) && f[i] ==> f[i - n];\n    lemma_mod_induction_forall(n, f);\n}\n\n/* TODO: if we need these at all, they should have better triggers to protect call sites\nlemma lemma_mod_auto_induction2(x:int, y:int, n:int, f:imap<(int,int),bool>)\n    requires n > 0;\n    requires forall i, j :: (i, j) in f;\n    requires ModAuto(n) ==> (forall i, j {:trigger f[(i, j)]} :: 0 <= i < n && 0 <= j < n ==> f[(i, j)]);\n    requires ModAuto(n) ==> (forall i, j {:trigger f[(i, j)]} :: i >= 0 && f[(i, j)] ==> f[(i + n, j)]);\n    requires ModAuto(n) ==> (forall i, j {:trigger f[(i, j)]} :: j >= 0 && f[(i, j)] ==> f[(i, j + n)]);\n    requires ModAuto(n) ==> (forall i, j {:trigger f[(i, j)]} :: i < n  && f[(i, j)] ==> f[(i - n, j)]);\n    requires ModAuto(n) ==> (forall i, j {:trigger f[(i, j)]} :: j < n  && f[(i, j)] ==> f[(i, j - n)]);\n    ensures  ModAuto(n);\n    ensures  f[(x, y)];\n{\n    lemma_mod_auto(n);\n    lemma_mod_induction_forall2(n, f);\n    assert f[(x, y)];\n}\n\nlemma lemma_mod_auto_induction_forall2(n:int, f:imap<(int,int),bool>)\n    requires n > 0;\n    requires forall i, j :: (i, j) in f;\n    requires ModAuto(n) ==> (forall i, j {:trigger f[(i, j)]} :: 0 <= i < n && 0 <= j < n ==> f[(i, j)]);\n    requires ModAuto(n) ==> (forall i, j {:trigger f[(i, j)]} :: i >= 0 && f[(i, j)] ==> f[(i + n, j)]);\n    requires ModAuto(n) ==> (forall i, j {:trigger f[(i, j)]} :: j >= 0 && f[(i, j)] ==> f[(i, j + n)]);\n    requires ModAuto(n) ==> (forall i, j {:trigger f[(i, j)]} :: i < n  && f[(i, j)] ==> f[(i - n, j)]);\n    requires ModAuto(n) ==> (forall i, j {:trigger f[(i, j)]} :: j < n  && f[(i, j)] ==> f[(i, j - n)]);\n    ensures  ModAuto(n);\n    ensures  forall i, j {:trigger f[(i, j)]} :: f[(i, j)];\n{\n    lemma_mod_auto(n);\n    lemma_mod_induction_forall2(n, f);\n}\n*/\n\n} \n"
  },
  {
    "path": "Armada/util/math/mod_auto_proofs.i.dfy",
    "content": "include \"mul_auto.i.dfy\"\ninclude \"mul.i.dfy\"\ninclude \"div_nonlinear.i.dfy\"\n\nmodule Math__mod_auto_proofs_i {\nimport opened Math__mul_auto_i\nimport opened Math__mul_i\nimport opened Math__div_nonlinear_i\n\nlemma lemma_mod_induction_helper(n:int, f:imap<int,bool>, x:int)\n    requires n > 0;\n    requires forall i :: i in f;\n    requires forall i :: 0 <= i < n ==> f[i];\n    requires forall i {:trigger f[i], f[i + n]} :: i >= 0 && f[i] ==> f[i + n];\n    requires forall i {:trigger f[i], f[i - n]} :: i < n  && f[i] ==> f[i - n];\n    ensures  f[x];\n    decreases if x >= n then x else -x;\n{\n    if (x >= n)\n    {\n        lemma_mod_induction_helper(n, f, x - n);\n        assert f[(x - n) + n];\n    }\n    else if (x < 0)\n    {\n        lemma_mod_induction_helper(n, f, x + n);\n        assert f[(x + n) - n];\n    }\n}\n\nlemma lemma_mod_induction_forall(n:int, f:imap<int,bool>)\n    requires n > 0;\n    requires forall i :: i in f;\n    requires forall i :: 0 <= i < n ==> f[i];\n    requires forall i {:trigger f[i], f[i + n]} :: i >= 0 && f[i] ==> f[i + n];\n    requires forall i {:trigger f[i], f[i - n]} :: i < n  && f[i] ==> f[i - n];\n    ensures  forall i :: f[i];\n{\n    forall i ensures f[i] { lemma_mod_induction_helper(n, f, i); }\n}\n\nlemma lemma_mod_induction_forall2(n:int, f:imap<(int,int),bool>)\n    requires n > 0;\n    requires forall i, j :: (i, j) in f;\n    requires forall i, j :: 0 <= i < n && 0 <= j < n ==> f[(i, j)];\n    requires forall i, j {:trigger f[(i, j)], f[(i + n, j)]} :: i >= 0 && f[(i, j)] ==> f[(i + n, j)];\n    requires forall i, j {:trigger f[(i, j)], f[(i, j + n)]} :: j >= 0 && f[(i, j)] ==> f[(i, j + n)];\n    requires forall i, j {:trigger f[(i, j)], f[(i - n, j)]} :: i < n  && f[(i, j)] ==> f[(i - n, j)];\n    requires forall i, j {:trigger f[(i, j)], f[(i, j - n)]} :: j < n  && f[(i, j)] ==> f[(i, j - n)];\n    ensures  forall i, j :: f[(i, j)];\n{\n    forall x, y ensures f[(x, y)];\n    {\n        forall i | 0 <= i < n ensures f[(i, y)];\n        {\n            var fj := imap j :: f[(i, j)];\n            lemma_mod_induction_forall(n, fj);\n            assert fj[y];\n        }\n        var fi := imap i :: f[(i, y)];\n        lemma_mod_induction_forall(n, fi);\n        assert fi[x];\n    }\n}\n\nlemma lemma_mod_auto_basics(n:int)\n    requires n > 0;\n    ensures  forall x:int {:trigger (x + n) % n} :: (x + n) % n == x % n;\n    ensures  forall x:int {:trigger (x - n) % n} :: (x - n) % n == x % n;\n    ensures  forall x:int {:trigger (x + n) / n} :: (x + n) / n == x / n + 1;\n    ensures  forall x:int {:trigger (x - n) / n} :: (x - n) / n == x / n - 1;\n    ensures  forall x:int {:trigger x % n} :: 0 <= x < n <==> x % n == x;\n{\n    forall x:int\n        ensures 0 <= x < n <==> x % n == x;\n    {\n        if (0 <= x < n) { lemma_small_mod(x, n); }\n        lemma_mod_range(x, n);\n    }\n    forall x:int\n        ensures (x + n) % n == x % n;\n        ensures (x - n) % n == x % n;\n        ensures (x + n) / n == x / n + 1;\n        ensures (x - n) / n == x / n - 1;\n    {\n        lemma_fundamental_div_mod(x, n);\n        lemma_fundamental_div_mod(x + n, n);\n        lemma_fundamental_div_mod(x - n, n);\n        lemma_mod_range(x, n);\n        lemma_mod_range(x + n, n);\n        lemma_mod_range(x - n, n);\n        var zp := (x + n) / n - x / n - 1;\n        var zm := (x - n) / n - x / n + 1;\n        forall ensures 0 == n * zp + ((x + n) % n) - (x % n) { lemma_mul_auto(); }\n        forall ensures 0 == n * zm + ((x - n) % n) - (x % n) { lemma_mul_auto(); }\n        if (zp > 0) { lemma_mul_inequality(1, zp, n); }\n        if (zp < 0) { lemma_mul_inequality(zp, -1, n); }\n        if (zm > 0) { lemma_mul_inequality(1, zm, n); }\n        if (zm < 0) { lemma_mul_inequality(zm, -1, n); }\n    }\n}\n\n\n} \n"
  },
  {
    "path": "Armada/util/math/mul.i.dfy",
    "content": "include \"mul_nonlinear.i.dfy\"\ninclude \"mul_auto.i.dfy\"\n\nmodule Math__mul_i {\nimport opened Math__mul_nonlinear_i\nimport opened Math__mul_auto_i\n\n// TODO_MODULE: module Math__mul_i {\n// TODO_MODULE: import opened Math__mul_nonlinear_i\n\nfunction mul(x:int, y:int) : int { x*y }\n\n//-////////////////////////////////////////////////////////////\n//- Recursive definitions that can be handy for proving \n//- properties we can't or don't want to rely on nonlinear for\n//-////////////////////////////////////////////////////////////\n\nfunction mul_recursive(x:int, y:int) : int\n{\n if x >= 0 then mul_pos(x, y)\n else -1*mul_pos(-1*x, y)\n}\n\nfunction{:opaque} mul_pos(x:int, y:int) : int\n requires x >= 0;\n{\n if x == 0 then 0\n else y + mul_pos(x - 1, y)\n}\n\nlemma lemma_mul_is_mul_recursive(x:int, y:int)\n    ensures x * y == mul_recursive(x, y);\n{\n    if (x >= 0) { lemma_mul_is_mul_pos(x, y); }\n    if (x <= 0) { lemma_mul_is_mul_pos(-x, y); }\n    lemma_mul_auto();\n}\n\nlemma lemma_mul_is_mul_pos(x:int, y:int)\n    requires x >= 0;\n    ensures x * y == mul_pos(x, y);\n{\n    reveal_mul_pos();\n    lemma_mul_auto_induction(x, imap u :: u >= 0 ==> u * y == mul_pos(u, y));\n}\n\n//-////////////////////////////////////////////////////////////////////////////\n//-\n//- Core lemmas, with named arguments.\n//-\n//-////////////////////////////////////////////////////////////////////////////\n\nlemma lemma_mul_basics(x:int)\n    ensures 0*x == 0;\n    ensures x*0 == 0;\n    ensures 1*x == x;\n    ensures x*1 == x;\n{\n}\n\nlemma lemma_mul_is_commutative(x:int, y:int)\n    ensures x*y == y*x;\n{\n}\n\nlemma lemma_mul_ordering_general()\n    ensures forall x:int, y:int {:trigger x*y} :: (0 < x && 0 < y && 0 <= x*y) ==> x <= x*y && y <= x*y;\n{\n    forall x:int, y:int | 0 < x && 0 < y && 0 <= x*y\n        ensures x <= x*y && y <= x*y;\n    {\n        lemma_mul_ordering(x, y);\n    }\n}\n\nlemma lemma_mul_is_mul_boogie(x:int, y:int)\n{\n}\n\nlemma lemma_mul_inequality(x:int, y:int, z:int)\n    requires x <= y;\n    requires z >= 0;\n    ensures  x*z <= y*z;\n{\n    lemma_mul_auto_induction(z, imap u :: u >= 0 ==> x * u <= y * u);\n}\n\nlemma lemma_mul_upper_bound(x:int, x_bound:int, y:int, y_bound:int)\n    requires x <= x_bound;\n    requires y <= y_bound;\n    requires 0<=x;\n    requires 0<=y;\n    ensures x*y <= x_bound * y_bound;\n{\n    lemma_mul_inequality(x, x_bound, y);\n    lemma_mul_inequality(y, y_bound, x_bound);\n}\n\n//- This lemma is less precise than the non-strict version, since\n//- it uses two < facts to achieve only one < result. Thus, use it with\n//- caution -- it may be throwing away precision you'll require later.\nlemma lemma_mul_strict_upper_bound(x:int, x_bound:int, y:int, y_bound:int)\n    requires x < x_bound;\n    requires y < y_bound;\n    requires 0<=x;\n    requires 0<=y;\n    ensures x*y < x_bound * y_bound;\n{\n    lemma_mul_auto_induction(x, imap u :: 0 <= u ==> u * y <= u * y_bound);\n    lemma_mul_auto_induction(y_bound, imap u :: 1 <= u ==> x * u < x_bound * u);\n}\n\nlemma lemma_mul_left_inequality(x:int, y:int, z:int)\n    requires x > 0;\n    ensures y <= z ==> x*y <= x*z;\n    ensures y < z ==> x*y < x*z;\n{\n    lemma_mul_auto_induction(x, imap u :: u > 0 ==> y <= z ==> u*y <= u*z);\n    lemma_mul_auto_induction(x, imap u :: u > 0 ==> y < z ==> u*y < u*z);\n}\n\nlemma lemma_mul_strict_inequality_converse(x:int, y:int, z:int)\n    requires x*z < y*z;\n    requires z >= 0;\n    ensures  x < y;\n{\n    lemma_mul_auto_induction(z, imap u :: x * u < y * u && u >= 0 ==> x < y);\n}\n\nlemma lemma_mul_inequality_converse(x:int, y:int, z:int)\n    requires x*z <= y*z;\n    requires z > 0;\n    ensures  x <= y;\n{\n    lemma_mul_auto_induction(z, imap u :: x * u <= y * u && u > 0 ==> x <= y);\n}\n\nlemma lemma_mul_equality_converse(x:int, y:int, z:int)\n    requires x*z == y*z;\n    requires 0<z;\n    ensures x==y;\n{\n    lemma_mul_auto_induction(z, imap u :: x > y && 0 < u ==> x * u > y * u);\n    lemma_mul_auto_induction(z, imap u :: x < y && 0 < u ==> x * u < y * u);\n}\n\nlemma lemma_mul_is_distributive_add_other_way(x:int, y:int, z:int)\n    ensures (y + z)*x == y*x + z*x;\n{\n    lemma_mul_auto();\n}\n\nlemma lemma_mul_is_distributive_sub(x:int, y:int, z:int)\n    ensures x*(y - z) == x*y - x*z;\n{\n    lemma_mul_auto();\n}\n\nlemma lemma_mul_is_distributive(x:int, y:int, z:int)\n    ensures x*(y + z) == x*y + x*z;\n    ensures x*(y - z) == x*y - x*z;\n    ensures (y + z)*x == y*x + z*x;\n    ensures (y - z)*x == y*x - z*x;\n    ensures x*(y + z) == (y + z)*x;\n    ensures x*(y - z) == (y - z)*x;\n    ensures x*y == y*x;\n    ensures x*z == z*x;\n{\n    lemma_mul_auto();\n}\n\nlemma lemma_mul_strictly_increases(x:int, y:int)\n    requires 1 < x;\n    requires 0 < y;\n    ensures y < x*y;\n{\n    lemma_mul_auto_induction(x, imap u :: 1 < u ==> y < u * y);\n}\n\nlemma lemma_mul_increases(x:int, y:int)\n    requires 0<x;\n    requires 0<y;\n    ensures y <= x*y;\n{\n    lemma_mul_auto_induction(x, imap u :: 0 < u ==> y <= u * y);\n}\n\nlemma lemma_mul_nonnegative(x:int, y:int)\n    requires 0 <= x;\n    requires 0 <= y;\n    ensures  0 <= x*y;\n{\n    lemma_mul_auto_induction(x, imap u :: 0 <= u ==> 0 <= u * y);\n}\n\nlemma lemma_mul_unary_negation(x:int, y:int)\n    ensures (-x)*y == -(x*y) == x*(-y);\n{\n    lemma_mul_auto_induction(x, imap u :: (-u)*y == -(u*y) == u*(-y));\n}\n\n// TODO: delete lemma_mul_one_to_one_pos; use lemma_mul_one_to_one instead\nlemma lemma_mul_one_to_one_pos(m:int, x:int, y:int)\n    requires 0<m;\n    requires m*x == m*y;\n    ensures x == y;\n{\n    lemma_mul_auto_induction(m, imap u :: x > y && 0 < u ==> x * u > y * u);\n    lemma_mul_auto_induction(m, imap u :: x < y && 0 < u ==> x * u < y * u);\n}\n\nlemma lemma_mul_one_to_one(m:int, x:int, y:int)\n    requires m!=0;\n    requires m*x == m*y;\n    ensures x == y;\n{\n    lemma_mul_auto_induction(m, imap u :: x > y && 0 < u ==> x * u > y * u);\n    lemma_mul_auto_induction(m, imap u :: x > y && 0 > u ==> x * u < y * u);\n    lemma_mul_auto_induction(m, imap u :: x < y && 0 < u ==> x * u < y * u);\n    lemma_mul_auto_induction(m, imap u :: x < y && 0 > u ==> x * u > y * u);\n}\n\n//-////////////////////////////////////////////////////////////////////////////\n//-\n//- Forall lemmas: these restate the core lemmas with foralls,\n//- so callers needn't name the specific expressions to manipulate.\n//-\n//- These are all boilerplate transformations of args/requires/ensures\n//- into forall args :: requires ==> ensures, with a correpsonding\n//- mechanically generated forall proof that invokes the core lemma.\n// So don't bother reading them.\n//-\n//-////////////////////////////////////////////////////////////////////////////\n\nlemma lemma_mul_is_mul_recursive_forall()\n    ensures forall x:int, y:int :: x * y == mul_recursive(x, y);\n{\n    forall x:int, y:int\n        ensures x * y == mul_recursive(x, y);\n    {\n        lemma_mul_is_mul_recursive(x, y);\n    }\n}\n\nlemma lemma_mul_basics_forall()\n    ensures forall x:int {:trigger 0*x} :: 0*x == 0;\n    ensures forall x:int {:trigger x*0} :: x*0 == 0;\n    ensures forall x:int {:trigger 1*x} :: 1*x == x;\n    ensures forall x:int {:trigger x*1} :: x*1 == x;\n{\n}\n\nlemma lemma_mul_is_commutative_forall()\n    ensures forall x:int, y:int {:trigger x*y} :: x*y == y*x;\n{\n}\n\nlemma lemma_mul_ordering_forall()\n    ensures forall x:int, y:int {:trigger x*y} ::\n        0 < x && 0 < y && 0 <= x*y\n        ==> x <= x*y && y <= x*y;\n{\n    forall x:int, y:int | 0 < x && 0 < y && 0 <= x*y\n        ensures x <= x*y && y <= x*y;\n    {\n        lemma_mul_ordering(x,y);\n    }\n}\n\nlemma lemma_mul_strict_inequality_forall()\n    ensures  forall x:int, y:int, z:int {:trigger x*z, y*z} ::\n        x < y && z>0 ==> x*z < y*z;\n{\n    forall (x:int, y:int, z:int | x < y && z>0)\n        ensures x*z < y*z;\n    {\n        lemma_mul_strict_inequality(x, y, z);\n    }\n}\n\nlemma lemma_mul_inequality_forall()\n    ensures  forall x:int, y:int, z:int {:trigger x*z, y*z} ::\n        x <= y && z>=0 ==> x*z <= y*z;\n{\n    forall (x:int, y:int, z:int | x <= y && z>=0)\n        ensures x*z <= y*z;\n    {\n        lemma_mul_inequality(x, y, z);\n    }\n}\n\nlemma lemma_mul_strict_inequality_converse_forall()\n    ensures  forall x:int, y:int, z:int {:trigger x*z, y*z} ::\n        x*z < y*z && z>=0 ==> x < y;\n{\n    forall (x:int, y:int, z:int | x*z < y*z && z>=0)\n        ensures x < y;\n    {\n        lemma_mul_strict_inequality_converse(x,y,z);\n    }\n}\n\nlemma lemma_mul_inequality_converse_forall()\n    ensures  forall x:int, y:int, z:int {:trigger x*z, y*z} ::\n        x*z <= y*z && z>0 ==> x <= y;\n{\n    forall (x:int, y:int, z:int | x*z <= y*z && z>0)\n        ensures x <= y;\n    {\n        lemma_mul_inequality_converse(x,y,z);\n    }\n}\n\nlemma lemma_mul_is_distributive_add_forall()\n    ensures forall x:int, y:int, z:int {:trigger x*(y + z)} :: x*(y + z) == x*y + x*z;\n{\n    forall (x:int, y:int, z:int)\n        ensures x*(y + z) == x*y + x*z;\n    {\n        lemma_mul_is_distributive_add(x,y,z);\n    }\n}\n\nlemma lemma_mul_is_distributive_sub_forall()\n    ensures forall x:int, y:int, z:int {:trigger x*(y - z)} :: x*(y - z) == x*y - x*z;\n{\n    forall (x:int, y:int, z:int)\n        ensures x*(y - z) == x*y - x*z;\n    {\n        lemma_mul_is_distributive_sub(x,y,z);\n    }\n}\n\nlemma lemma_mul_is_distributive_forall()\n    ensures forall x:int, y:int, z:int {:trigger x*(y + z)} :: x*(y + z) == x*y + x*z;\n    ensures forall x:int, y:int, z:int {:trigger x*(y - z)} :: x*(y - z) == x*y - x*z;\n    ensures forall x:int, y:int, z:int {:trigger (y + z)*x} :: (y + z)*x == y*x + z*x;\n    ensures forall x:int, y:int, z:int {:trigger (y - z)*x} :: (y - z)*x == y*x - z*x;\n{\n    lemma_mul_is_distributive_add_forall();\n    lemma_mul_is_distributive_sub_forall();\n    lemma_mul_is_commutative_forall();\n}\n\nlemma lemma_mul_is_associative_forall()\n    ensures forall x:int, y:int, z:int {:trigger x * (y * z)}{:trigger (x * y) * z} :: x * (y * z) == (x * y) * z;\n{\n    forall (x:int, y:int, z:int)\n        ensures x * (y * z) == (x * y) * z;\n    {\n        lemma_mul_is_associative(x,y,z);\n    }\n}\n\nlemma lemma_mul_nonzero_forall()\n    ensures forall x:int, y:int {:trigger x*y} :: x*y != 0 <==> x != 0 && y != 0;\n{\n    forall (x:int, y:int)\n        ensures x*y != 0 <==> x != 0 && y != 0;\n    {\n        lemma_mul_nonzero(x,y);\n    }\n}\n\nlemma lemma_mul_nonnegative_forall()\n    ensures forall x:int, y:int {:trigger x*y} :: 0 <= x && 0 <= y ==> 0 <= x*y;\n{\n    forall (x:int, y:int | 0 <= x && 0 <= y)\n        ensures 0 <= x*y;\n    {\n        lemma_mul_nonnegative(x,y);\n    }\n}\n\nlemma lemma_mul_unary_negation_forall()\n    ensures forall x:int, y:int {:trigger (-x)*y}{:trigger x*(-y)} :: (-x)*y == -(x*y) == x*(-y);\n{\n    forall (x:int, y:int) \n        ensures (-x)*y == -(x*y) == x*(-y);\n    {\n        lemma_mul_unary_negation(x,y);\n    }\n}\n\nlemma lemma_mul_strictly_increases_forall()\n    ensures forall x:int, y:int {:trigger x*y} :: (1 < x && 0 < y) ==> (y < x*y);\n{\n    forall (x:int, y:int | 1 < x && 0 < y)\n        ensures y < x*y;\n    {\n        lemma_mul_strictly_increases(x,y);\n    }\n}\n\nlemma lemma_mul_increases_forall()\n    ensures forall x:int, y:int {:trigger x*y} :: (0 < x && 0 < y) ==> (y <= x*y);\n{\n    forall (x:int, y:int | 0 < x && 0 < y)\n        ensures y <= x*y;\n    {\n        lemma_mul_increases(x,y);\n    }\n}\n\nlemma lemma_mul_strictly_positive_forall()\n    ensures forall x:int, y:int {:trigger x*y} :: (0 < x && 0 < y) ==> (0 < x*y);\n{\n    forall (x:int, y:int | 0 < x && 0 < y)\n        ensures 0 < x*y;\n    {\n        lemma_mul_strictly_positive(x,y);\n    }\n}\n\nlemma lemma_mul_one_to_one_forall()\n    ensures forall m:int, x:int, y:int {:trigger m*x, m*y} :: (m!=0 && m*x == m*y) ==> x==y;\n{\n    forall (m:int, x:int, y:int | m!=0 && m*x == m*y)\n        ensures x==y;\n    {\n        lemma_mul_one_to_one(m, x, y);\n    }\n}\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// The big properties bundle. This can be a little dangerous, because\n// it may produce a trigger storm. Whether it does seems to depend on\n// how complex the expressions being mul'ed are. If that happens,\n// fall back on specifying an individiual _forall lemma or use\n// lemma_mul_auto/lemma_mul_auto_induction.\n//\n//////////////////////////////////////////////////////////////////////////////\n\nlemma lemma_mul_properties()\n    ensures forall x:int, y:int {:trigger x*y} :: x*y == y*x;\n//    ensures forall x:int {:trigger x*0}{:trigger 0*x} :: x*0 == 0*x == 0;\n//    ensures forall x:int {:trigger x*1}{:trigger 1*x} :: x*1 == 1*x == x;\n    ensures forall x:int, y:int, z:int {:trigger x*z, y*z} :: x < y && z > 0 ==> x*z < y*z;\n    ensures forall x:int, y:int, z:int {:trigger x*z, y*z} :: x <= y && z >= 0 ==> x*z <= y*z;\n    ensures forall x:int, y:int, z:int {:trigger x*(y + z)} :: x*(y + z) == x*y + x*z;\n    ensures forall x:int, y:int, z:int {:trigger x*(y - z)} :: x*(y - z) == x*y - x*z;\n    ensures forall x:int, y:int, z:int {:trigger (y + z)*x} :: (y + z)*x == y*x + z*x;\n    ensures forall x:int, y:int, z:int {:trigger (y - z)*x} :: (y - z)*x == y*x - z*x;\n    ensures forall x:int, y:int, z:int {:trigger x*(y*z)}{:trigger (x*y)*z} :: x*(y*z) == (x*y)*z;\n    ensures forall x:int, y:int {:trigger x*y} :: x*y != 0 <==> x != 0 && y != 0;\n    ensures forall x:int, y:int {:trigger x*y} :: 0 <= x && 0 <= y ==> 0 <= x*y;\n//    ensures forall x:int, y:int {:trigger x*y} :: 0 < x && 0 < y && 0 <= x*y ==> x <= x*y && y <= x*y;\n//    ensures forall x:int, y:int {:trigger x*y} :: (1 < x && 0 < y) ==> (y < x*y);\n//    ensures forall x:int, y:int {:trigger x*y} :: (0 < x && 0 < y) ==> (y <= x*y);\n//    ensures forall x:int, y:int {:trigger x*y} :: (0 < x && 0 < y) ==> (0 < x*y);\n{\n    lemma_mul_strict_inequality_forall();\n    lemma_mul_inequality_forall();\n    lemma_mul_is_distributive_forall();\n    lemma_mul_is_associative_forall();\n    lemma_mul_ordering_forall();\n    lemma_mul_nonzero_forall();\n    lemma_mul_nonnegative_forall();\n    lemma_mul_strictly_increases_forall();\n    lemma_mul_increases_forall();\n}\n\nlemma lemma_mul_cancels_negatives(a:int, b:int)\n    ensures a*b == (-a)*(-b);\n{\n    lemma_mul_auto_induction(a, imap u :: u*b == (-u)*(-b));\n}\n\n//- Kept for legacy reasons:\nfunction INTERNAL_mul_recursive(x:int, y:int) : int { mul_recursive(x, y) }\n\n// TODO_MODULE: } import opened Math__mul_i_ = Math__mul_i\n\n} \n"
  },
  {
    "path": "Armada/util/math/mul_auto.i.dfy",
    "content": "include \"mul_auto_proofs.i.dfy\"\n\nmodule Math__mul_auto_i {\nimport opened Math__mul_auto_proofs_i\n\npredicate MulAuto()\n{\n    (forall x:int, y:int {:trigger x * y} :: x * y == y * x)\n && (forall x:int, y:int, z:int {:trigger (x + y) * z} :: (x + y) * z == x * z + y * z)\n && (forall x:int, y:int, z:int {:trigger (x - y) * z} :: (x - y) * z == x * z - y * z)\n}\n\nlemma lemma_mul_auto()\n    ensures  MulAuto();\n{\n    lemma_mul_auto_commutes();\n    lemma_mul_auto_distributes();\n}\n\npredicate TMulAutoLe(x:int, y:int) { x <= y }\n\nlemma lemma_mul_auto_induction(x:int, f:imap<int,bool>)\n    requires forall i :: i in f;\n    requires MulAuto() ==> f[0]\n                        && (forall i {:trigger TMulAutoLe(0, i)} :: TMulAutoLe(0, i) && f[i] ==> f[i + 1])\n                        && (forall i {:trigger TMulAutoLe(i, 0)} :: TMulAutoLe(i, 0) && f[i] ==> f[i - 1]);\n    ensures  MulAuto();\n    ensures  f[x];\n{\n    lemma_mul_auto_commutes();\n    lemma_mul_auto_distributes();\n    assert forall i {:trigger f[i]} :: TMulAutoLe(0, i) && f[i] ==> f[i + 1];\n    assert forall i {:trigger f[i]} :: TMulAutoLe(i, 0) && f[i] ==> f[i - 1];\n    lemma_mul_induction_forall(f);\n    assert f[x];\n}\n\nlemma lemma_mul_auto_induction_forall(f:imap<int,bool>)\n    requires forall i :: i in f;\n    requires MulAuto() ==> f[0]\n                        && (forall i {:trigger TMulAutoLe(0, i)} :: TMulAutoLe(0, i) && f[i] ==> f[i + 1])\n                        && (forall i {:trigger TMulAutoLe(i, 0)} :: TMulAutoLe(i, 0) && f[i] ==> f[i - 1]);\n    ensures  MulAuto();\n    ensures  forall i {:trigger f[i]} :: f[i];\n{\n    lemma_mul_auto_commutes();\n    lemma_mul_auto_distributes();\n    assert forall i {:trigger f[i]} :: TMulAutoLe(0, i) && f[i] ==> f[i + 1];\n    assert forall i {:trigger f[i]} :: TMulAutoLe(i, 0) && f[i] ==> f[i - 1];\n    lemma_mul_induction_forall(f);\n}\n\n} \n"
  },
  {
    "path": "Armada/util/math/mul_auto_proofs.i.dfy",
    "content": "include \"mul_nonlinear.i.dfy\"\n\nmodule Math__mul_auto_proofs_i {\nimport opened Math__mul_nonlinear_i\n\nlemma lemma_mul_induction_helper(f:imap<int,bool>, x:int)\n    requires forall i :: i in f;\n    requires f[0];\n    requires forall i {:trigger f[i], f[i + 1]} :: i >= 0 && f[i] ==> f[i + 1];\n    requires forall i {:trigger f[i], f[i - 1]} :: i <= 0 && f[i] ==> f[i - 1];\n    ensures  f[x];\n    decreases if x >= 0 then x else -x;\n{\n    if (x > 0)\n    {\n        lemma_mul_induction_helper(f, x - 1);\n        assert f[(x - 1) + 1];\n    }\n    else if (x < 0)\n    {\n        lemma_mul_induction_helper(f, x + 1);\n        assert f[(x + 1) - 1];\n    }\n}\n\nlemma lemma_mul_induction_forall(f:imap<int,bool>)\n    requires forall i :: i in f;\n    requires f[0];\n    requires forall i {:trigger f[i], f[i + 1]} :: i >= 0 && f[i] ==> f[i + 1];\n    requires forall i {:trigger f[i], f[i - 1]} :: i <= 0 && f[i] ==> f[i - 1];\n    ensures  forall i :: f[i];\n{\n    forall i ensures f[i] { lemma_mul_induction_helper(f, i); }\n}\n\nlemma lemma_mul_auto_commutes()\n    ensures  forall x:int, y:int {:trigger x * y} :: x * y == y * x;\n{\n    forall x:int, y:int ensures x * y == y * x;\n    {\n        lemma_mul_induction_forall(imap i :: x * i == i * x);\n    }\n}\n\nlemma lemma_mul_auto_succ()\n    ensures  forall x:int, y:int {:trigger (x + 1) * y} :: (x + 1) * y == x * y + y;\n    ensures  forall x:int, y:int {:trigger (x - 1) * y} :: (x - 1) * y == x * y - y;\n{\n    lemma_mul_auto_commutes();\n    forall x:int, y:int\n        ensures  (x + 1) * y == x * y + y;\n        ensures  (x - 1) * y == x * y - y;\n    {\n        lemma_mul_is_distributive_add(y, x, 1);\n        lemma_mul_is_distributive_add(y, x, -1);\n    }\n}\n\nlemma lemma_mul_auto_distributes()\n    ensures  forall x:int, y:int, z:int {:trigger (x + y) * z} :: (x + y) * z == x * z + y * z;\n    ensures  forall x:int, y:int, z:int {:trigger (x - y) * z} :: (x - y) * z == x * z - y * z;\n{\n    lemma_mul_auto_succ();\n    forall x:int, y:int, z:int\n        ensures (x + y) * z == x * z + y * z;\n        ensures (x - y) * z == x * z - y * z;\n    {\n        var f1 := imap i :: (x + i) * z == x * z + i * z;\n        var f2 := imap i :: (x - i) * z == x * z - i * z;\n        assert forall i {:trigger (x + (i + 1)) * z} :: (x + (i + 1)) * z == ((x + i) + 1) * z == (x + i) * z + z;\n        assert forall i {:trigger (x + (i - 1)) * z} :: (x + (i - 1)) * z == ((x + i) - 1) * z == (x + i) * z - z;\n        assert forall i {:trigger (x - (i + 1)) * z} :: (x - (i + 1)) * z == ((x - i) - 1) * z == (x - i) * z - z;\n        assert forall i {:trigger (x - (i - 1)) * z} :: (x - (i - 1)) * z == ((x - i) + 1) * z == (x - i) * z + z;\n        lemma_mul_induction_forall(f1);\n        lemma_mul_induction_forall(f2);\n        assert f1[y];\n        assert f2[y];\n    }\n}\n\n} \n"
  },
  {
    "path": "Armada/util/math/mul_nonlinear.i.dfy",
    "content": "//- <NuBuild AddDafnyFlag /z3opt:smt.arith.nl=true/>\n//- WARNING: In general, you shouldn't need to call these directly.  Try\n//- to use the ones in mul.i.dfy instead.  They're more full-featured anyway.\n\nmodule Math__mul_nonlinear_i {\n\n// TODO_MODULE: module Math__mul_nonlinear_i {\n\n// WARNING: Think three times before adding anything to this file!\n// Nonlinear verification is highly unstable, so even if it appears to work,\n// it may cause problems down the road.  Thus, we want to keep this file as\n// small and simple as possible.  Instead of adding code here, try proving\n// it in div.i.dfy using the connection to the recursive definition\n\nlemma lemma_mul_strictly_positive(x:int, y:int)\n    ensures (0 < x && 0 < y) ==> (0 < x*y);\n{}\n\nlemma lemma_mul_nonzero(x:int, y:int)\n    ensures x*y != 0 <==> x != 0 && y != 0;\n{}\n\nlemma lemma_mul_is_associative(x:int, y:int, z:int)\n    ensures x * (y * z) == (x * y) * z;\n{}\n\nlemma lemma_mul_is_distributive_add(x:int, y:int, z:int)\n    ensures x*(y + z) == x*y + x*z;\n{}\n\nlemma lemma_mul_ordering(x:int, y:int)\n    requires 0 < x;\n    requires 0 < y;\n    requires 0 <= x*y;\n    ensures x <= x*y && y <= x*y;\n{ }\n\nlemma lemma_mul_strict_inequality(x:int, y:int, z:int)\n    requires x < y;\n    requires z > 0;\n    ensures  x*z < y*z;\n{}\n\n// TODO_MODULE: } import opened Math__mul_nonlinear_i_ = Math__mul_nonlinear_i\n\n} \n"
  },
  {
    "path": "Armada/util/math/power.i.dfy",
    "content": "include \"powers.i.dfy\"\ninclude \"mul.i.dfy\"\ninclude \"mul_auto.i.dfy\"\n\nmodule Math__power_i {\nimport opened Math__power_s\nimport opened Math__mul_i\nimport opened Math__mul_auto_i\n\n//-lemma lemma_mul_passes_harmlessly_through_mod(\n//-    ensures mul(x,y) % m == mul(x\n\nlemma lemma_power_0(b:int)\n    ensures power(b,0) == 1;\n{\n    reveal_power();\n}\n\nlemma lemma_power_1(b:int)\n    ensures power(b,1) == b;\n{\n    calc {\n        power(b,1);\n            { reveal_power(); }\n        b*power(b,0);\n            { lemma_power_0(b); }\n        b*1;\n            { lemma_mul_basics_forall(); }\n        b;\n    }\n}\n\nlemma lemma_0_power(e:nat)\n    requires e > 0;\n    ensures power(0,e) == 0;\n{\n    reveal_power();\n    lemma_mul_basics_forall();\n    if (e != 1)\n    {\n        lemma_0_power(e - 1);\n    }\n}\n\nlemma lemma_1_power(e:nat)\n    ensures power(1,e) == 1;\n{\n    reveal_power();\n    lemma_mul_basics_forall();\n    if (e != 0)\n    {\n        lemma_1_power(e - 1);\n    }\n}\n\nlemma lemma_power_adds(b:int, e1:nat, e2:nat)\n    decreases e1;\n    ensures power(b,e1)*power(b,e2) == power(b,e1+e2);\n{\n    if (e1==0)\n    {\n        calc {\n            power(b,e1)*power(b,e2);\n                { lemma_power_0(b); }\n            1*power(b,e2);\n                { lemma_mul_basics_forall(); }\n            power(b,0+e2);\n        }\n    }\n    else\n    {\n        calc {\n            power(b,e1)*power(b,e2);\n                { reveal_power(); }\n            (b*power(b,e1-1))*power(b,e2);\n                { lemma_mul_is_associative_forall(); }\n            b*(power(b,e1-1)*power(b,e2));\n                { lemma_power_adds(b, e1-1, e2); }\n            b*power(b,e1-1+e2);\n                { reveal_power(); }\n            power(b,e1+e2);\n        }\n    }\n}\n\nlemma lemma_power_multiplies(a:int,b:nat,c:nat)\n    decreases c;\n    ensures 0<=b*c;\n    ensures power(a,b*c) == power(power(a,b),c);\n{\n    lemma_mul_nonnegative(b,c);\n    if (0==c)\n    {\n        lemma_mul_basics_forall();\n        calc {\n            power(a,b*c);\n                { lemma_power_0(a); }\n            1;\n                { lemma_power_0(power(a,b)); }\n            power(power(a,b),c);\n        }\n    }\n    else\n    {\n        calc {\n            b*c - b;\n                { lemma_mul_basics_forall(); }\n            b*c - mul(b,1);\n                { lemma_mul_is_distributive_forall(); }\n            b*(c-1);\n        }\n        lemma_mul_nonnegative(b,c-1);\n        assert 0 <= b*c-b;\n\n        calc {\n            power(a,b*c);\n            power(a,b+b*c-b);\n                { lemma_power_adds(a,b,b*c-b); }\n            power(a,b)*power(a,b*c-b);\n            power(a,b)*power(a,b*(c-1));\n                { lemma_power_multiplies(a,b,c-1); }\n            power(a,b)*power(power(a,b),c-1);\n                { reveal_power(); }\n            power(power(a,b),c);\n        }\n    }\n}\n\nlemma lemma_power_distributes(a:int, b:int, e:nat)\n    decreases e;\n    ensures power(a*b, e) == power(a, e) * power(b, e);\n{\n    reveal_power();\n    lemma_mul_basics_forall();\n    if (e > 0)\n    {\n        calc {\n            power(a*b, e);\n            (a*b) * power(a*b, e - 1);\n            { lemma_power_distributes(a, b, e - 1); }\n            (a*b) * (power(a, e - 1) * power(b, e - 1));\n            { lemma_mul_is_associative_forall(); lemma_mul_is_commutative_forall(); }\n            (a*power(a, e - 1)) * (b*power(b, e - 1));\n            power(a,e) * power(b,e);\n        }\n        lemma_mul_is_distributive_forall();\n    }\n}\n\nlemma lemma_power_auto()\n    ensures  forall x:int {:trigger power(x, 0)} :: power(x, 0) == 1;\n    ensures  forall x:int {:trigger power(x, 1)} :: power(x, 1) == x;\n    ensures  forall x:int, y:int {:trigger power(x, y)} :: y == 0 ==> power(x, y) == 1; // REVIEW: because of Dafny's LitInt special treatment, these are not the same as the two ensures above\n    ensures  forall x:int, y:int {:trigger power(x, y)} :: y == 1 ==> power(x, y) == x; // ...\n    ensures  forall x:int, y:int {:trigger x * y} :: 0 < x && 0 < y ==> x <= x * y;\n    ensures  forall x:int, y:int {:trigger x * y} :: 0 < x && 1 < y ==> x < x * y;\n    ensures  forall x:int, y:nat, z:nat {:trigger power(x, y + z)} :: power(x, y + z) == power(x, y) * power(x, z);\n    ensures  forall x:int, y:nat, z:nat {:trigger power(x, y - z)} :: y >= z ==> power(x, y - z) * power(x, z) == power(x, y);\n    ensures  forall x:int, y:int, z:nat {:trigger power(x * y, z)} :: power(x * y, z) == power(x, z) * power(y, z);\n{\n    forall x:int\n        ensures power(x, 0) == 1;\n        ensures power(x, 1) == x;\n    {\n        lemma_power_0(x);\n        lemma_power_1(x);\n    }\n    forall x:int, y:int, z:nat\n        ensures power(x * y, z) == power(x, z) * power(y, z);\n    {\n        lemma_power_distributes(x, y, z);\n    }\n    forall x:int, y:nat, z:nat\n        ensures power(x, y + z) == power(x, y) * power(x, z);\n    {\n        lemma_power_adds(x, y, z);\n    }\n    lemma_mul_auto();\n    lemma_mul_increases_forall();\n    lemma_mul_strictly_increases_forall();\n}\n\nlemma lemma_power_positive(b:int, e:nat)\n    requires 0<b;\n    ensures 0<power(b,e);\n{\n    lemma_power_auto();\n    lemma_mul_auto_induction(e, imap u :: 0 <= u ==> 0 < power(b, u));\n}\n\nlemma lemma_power_increases(b:nat,e1:nat,e2:nat)\n    requires 0<b;\n    requires e1 <= e2;\n    ensures power(b,e1) <= power(b,e2);\n{\n    lemma_power_auto();\n    lemma_mul_auto_induction(e2 - e1, imap e :: 0 <= e ==> power(b, e1) <= power(b, e1 + e));\n}\n\nlemma lemma_power_strictly_increases(b:nat,e1:nat,e2:nat)\n    requires 1<b;\n    requires e1 < e2;\n    ensures power(b,e1) < power(b,e2);\n{\n    lemma_power_auto();\n    lemma_mul_auto_induction(e2 - e1, imap e :: 0 < e ==> power(b, e1) < power(b, e1 + e));\n}\n\nlemma lemma_square_is_power_2(x:nat)\n    ensures power(x,2) == x*x;\n{\n    reveal_power();\n}\n\n} \n"
  },
  {
    "path": "Armada/util/math/powers.i.dfy",
    "content": "\nmodule Math__power_s {\n\n// TODO_MODULE: module Math__power_s {\nfunction {:opaque} power(b:int, e:nat) : int\n    decreases e;\n{\n    if (e==0) then\n        1\n    else\n        b*power(b,e-1)\n}\n\n// TODO_MODULE: } import opened Math__power_s_ = Math__power_s\n\n} \n"
  },
  {
    "path": "Armada/util/option.s.dfy",
    "content": "module util_option_s {\n\n    datatype Option<T> = Some(v:T) | None()\n\n}\n\n"
  },
  {
    "path": "Armada/util/types.s.dfy",
    "content": "module util_types_s {\n\n    newtype byte = x:int | 0 <= x < 0x100\n    newtype uint = x:int | 0 <= x < 0x1_0000_0000\n\n}\n"
  },
  {
    "path": "BUILD.md",
    "content": "Building on Linux\n===\nThese instructions are adapted from the [Dafny Wiki](https://github.com/dafny-lang/dafny/wiki/INSTALL). They assume that `BASE-DIRECTORY` is the base directory in which you want to build Armada.\n\n1. Install .NET 5.0 following the instructions [here](https://docs.microsoft.com/en-us/dotnet/core/install/).\n\n2. Create the base directory with\n```\n       mkdir BASE-DIRECTORY\n```\n\n3. Download Dafny v3.0.0 with\n```\n       cd BASE-DIRECTORY\n       wget https://github.com/dafny-lang/dafny/releases/download/v3.0.0/dafny-3.0.0-x64-debian-8.11.zip\n       unzip dafny-3.0.0-x64-debian-8.11.zip\n```\n\n4. Download and build Armada with:\n```\n       cd BASE-DIRECTORY\n       git clone https://github.com/microsoft/armada\n       dotnet build armada/Source/Armada.sln\n```\n\n   You should then find an executable named `Armada.dll` in the directory `armada/Binaries/`.\n\n5. To run the tests, you'll also need to install [scons](https://scons.org).\n\nBuilding on Windows/Mac OS\n===\nBuilding on other platforms is similar to building on Linux. You will need to download the correct Dafny binaries for your platform in step 3. On the Windows platform, the produced binary is `Armada.exe` instead of `Armada.dll`.\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Microsoft Open Source Code of Conduct\n\nThis project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).\n\nResources:\n\n- [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)\n- [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)\n- Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns\n"
  },
  {
    "path": "LICENSE",
    "content": "    Armada\r\n\r\n    Copyright (c) Microsoft Corporation;\r\n                  Jacob R. Lorch, Microsoft Corporation;\r\n                  Yixuan Chen, University of Michigan and Yale University;\r\n                  Seyed Armin Vakil Ghahani, University of Michigan;\r\n                  Yuchen Jiang, University of Michigan;\r\n                  Manos Kapritsos, University of Michigan;\r\n                  Haojun Ma, University of Michigan;\r\n                  Bryan Parno, Carnegie Mellon University;\r\n                  Upamanyu Sharma, University of Michigan;\r\n                  James R. Wilcox, Microsoft Corporation and University of Washington;\r\n                  Yanlong Yao, University of Michigan;\r\n                  Xueyuan Zhao, Carnegie Mellon University\r\n\r\n    MIT License\r\n\r\n    Permission is hereby granted, free of charge, to any person obtaining a copy\r\n    of this software and associated documentation files (the \"Software\"), to deal\r\n    in the Software without restriction, including without limitation the rights\r\n    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n    copies of the Software, and to permit persons to whom the Software is\r\n    furnished to do so, subject to the following conditions:\r\n\r\n    The above copyright notice and this permission notice shall be included in all\r\n    copies or substantial portions of the Software.\r\n\r\n    THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n    SOFTWARE\r\n"
  },
  {
    "path": "NOTICE.txt",
    "content": "This project uses third party material from the projects listed\nbelow. The original copyright notice and the license under which\nMicrosoft received such third party material are set forth below.\nMicrosoft reserves all other rights not expressly granted, whether by\nimplication, estoppel or otherwise.\n\n----------------------------------------------------------------------\n\nDafny\n\nCopyright (c) Microsoft Corporation\n\nAll rights reserved.\n\nMIT License\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"\"Software\"\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n----------------------------------------------------------------------\n\nCompiler Generator Coco/R,\nCopyright (c) 1990, 2005 Hanspeter Moessenboeck, University of Linz\nextended by M. Loeberbauer & A. Woess, Univ. of Linz\nwith improvements by Pat Terry, Rhodes University\n\nThis program is free software; you can redistribute it and/or modify it\nunder the terms of the GNU General Public License as published by the\nFree Software Foundation; either version 2, or (at your option) any\nlater version.\n\nThis program is distributed in the hope that it will be useful, but\nWITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\nor FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\nfor more details.\n\nYou should have received a copy of the GNU General Public License along\nwith this program; if not, write to the Free Software Foundation, Inc.,\n59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n\nAs an exception, it is allowed to write an extension of Coco/R that is\nused as a plugin in non-free software.\n\nIf not otherwise stated, any source code generated by Coco/R (other than\nCoco/R itself) does not fall under the GNU General Public License.\n\n----------------------------------------------------------------------\n\nliblfds\n\nYou are free to use this library in any way. Go forth and create wealth!\n\nIf for legal reasons a custom licence is required, the license of your choice\nwill be granted, and license is hereby granted up front for a range of popular\nlicenses : the MIT license, the BSD license, the Apache license, the GPL and\nLPGL (all versions thereof) and the Creative Commons licenses (all of\nthem). Additionally, everything is also placed in the public domain.\n"
  },
  {
    "path": "README.md",
    "content": "# Overview\n\nSafely writing high-performance concurrent programs is notoriously difficult. To aid developers, we\nintroduce Armada, a language and tool designed to formally verify such programs with relatively\nlittle effort. Via a C-like language that compiles to the C subset ClightTSO and a small-step,\nstate-machine-based semantics, Armada gives developers the flexibility to choose arbitrary memory\nlayout and synchronization primitives so they are never constrained in their pursuit of\nperformance. To reduce developer effort, Armada leverages SMT-powered automation and a library of\npowerful reasoning techniques, including rely-guarantee, TSO elimination, reduction, and alias\nanalysis. All these techniques are proven sound, and Armada can be soundly extended with additional\nstrategies over time. Using Armada, we verify four concurrent case studies and show that we can\nachieve performance equivalent to that of unverified code.\n\nYou can read more about Armada in our PLDI '20 paper, which ACM will publish on June 17, 2020:\n\nJacob R. Lorch, Yixuan Chen, Manos Kapritsos, Bryan Parno, Shaz Qadeer, Upamanyu Sharma, James\nR. Wilcox, and Xueyuan Zhao. 2020. Armada: Low-Effort Verification of High-Performance Concurrent\nPrograms. In Proceedings of the 41st ACM SIGPLAN International Conference on Programming Language\nDesign and Implementation (PLDI '20), June 15-20, 2020, London, UK. ACM, New York, NY, USA, 14\npages. https://doi.org/10.1145/3385412.3385971\n\n\n# Getting started\n\nTo build Armada, please follow the detailed instructions documented in [BUILD.md](BUILD.md).\n\nTo use Armada, you'll need the following tools:\n\n  * .NET 5.0 (runtime for both Armada and Dafny)\n  * pip (needed for installing scons)\n  * scons (installable by running `pip install scons`)\n  * Dafny v3.2.0 (available at https://github.com/dafny-lang/dafny)\n\n\n# Generating and testing proofs\n\nTo use the Armada tool to generate proofs for all the included test Armada files (`Test/*/*.arm`),\nrun, from the Armada top-level directory, `scons -j <n> -f SConstruct1` where `<n>` is the number of\nthreads you want scons to use.\n\nTo verify all the generated proofs, run, from the same directory, `scons -j <n> -f SConstruct2\n--DAFNYPATH=<dafny-path>` where `<dafny-path>` is the directory containing the `Dafny.exe`/`Dafny.dll`\nbinary you installed.\n\nIf this second scons finishes without printing an error message, this means that everything worked.\nIf it reports an error, this is likely due to running on a machine without enough memory, so try\nagain with fewer threads.\n\n\n# Compilation, performance evaluation, and graph generation\n\nTo build the queue benchmarks, run them, and generate the performance graphs, run `python3\nrun_benchmarks.py` in the `Test/qbss_benchmark/` directory. This will produce a file\n`qbss_performance_graph.pdf` with the performance graph.\n\n\n# Contributing\n\nThis project welcomes contributions and suggestions.  Most contributions require you to agree to a\nContributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us\nthe rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.\n\nWhen you submit a pull request, a CLA bot will automatically determine whether you need to provide\na CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions\nprovided by the bot. You will only need to do this once across all repos using our CLA.\n\nThis project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).\nFor more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or\ncontact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.\n"
  },
  {
    "path": "SConstruct1",
    "content": "# -*- python -*-\nimport re\nimport sys\nimport os, os.path\nimport subprocess\nimport traceback\nimport pdb\nimport SCons.Util\nimport atexit\nimport platform\n\nImport(\"*\")\n\nenv = Environment()\nif sys.platform != 'win32' and sys.platform != 'cygwin':\n  env['DOTNET'] = 'dotnet'\n\n# Retrieve tool-specific command overrides passed in by the user\n# We don't really need --DAFNYPATH, but it's OK if the user\n# specifies it.\nAddOption('--DAFNYPATH',\n  dest='dafny_path',\n  type='string',\n  default=None,\n  action='store',\n  help='Specify the path to Dafny tool binaries (not needed)')\n\npipeline_dll = os.path.abspath('Binaries/ArmadaPipeline.dll')\nif sys.platform == \"win32\" or sys.platform == \"cygwin\":\n  armada_exe = os.path.abspath('Binaries/Armada.exe')\nelse:\n  armada_exe = os.path.abspath('Binaries/Armada.dll')\n\n####################################################################\n#\n#   Define Armada transformation Builders\n#\n####################################################################\n\ndef generate_armada_actions(source, target, env, for_signature):\n#  print(\"Target \", [File(t).path for t in target], \" has dependencies \", [File(s).path for s in source])\n  source_path = File(source[0]).path\n  source_dir = os.path.dirname(source_path)\n  source_name = os.path.basename(source_path)\n  num_slashes = source_path.count(\"/\")\n  if num_slashes > 0:\n    armada_path = \"../\" * (num_slashes-1) + \"..\"\n  else:\n    armada_path = \".\"\n  return \"cd %s; $DOTNET %s /armadaPath:%s %s\" % (source_dir, armada_exe, armada_path, source_name)\n\ndef add_armada(env):\n  armada = Builder(generator=generate_armada_actions)\n  env.Append(BUILDERS = {'Armada' : armada})\n\n####################################################################\n#\n#   Put it all together\n#\n####################################################################\n\nadd_armada(env)\n\n####################################################################\n#\n#   Create dependencies\n#\n####################################################################\n\ndef run_directory(dir_name, entries):\n  for (armada_name, dafny_files, proof_dirs) in entries:\n    source = \"Test/%s/%s.arm\" % (dir_name, armada_name)\n    targets = [\"Test/%s/%s.dfy\" % (dir_name, dafny_file) for dafny_file in dafny_files]\n    cmd = env.Armada(targets, [source, armada_exe, pipeline_dll])\n    for proof_dir in proof_dirs:\n      subdir = \"Test/%s/%s\" % (dir_name, proof_dir)\n      if os.path.isdir(subdir):\n        for filename in os.listdir(subdir):\n          if os.path.splitext(filename)[1] == '.dfy':\n            Clean(cmd, \"%s/%s\" % (subdir, filename))\n        Clean(cmd, subdir)\n\n\nrun_directory(\"assume-intro\", [\n    (\"test\", [\"SharedStructs\", \"A\", \"B\", \"AB\"], [\"AB\"]),\n    (\"test2\", [\"SharedStructs2\", \"C\", \"D\", \"CD\"], [\"CD\"]),\n    (\"test3\", [\"SharedStructs3\", \"E\", \"F\", \"EF\"], [\"EF\"]),\n])\n\nrun_directory(\"barrier\", [\n    (\"barrier\", [\"SharedStructs\", \"Impl\", \"L1\", \"L2\", \"ImplRefinesL1\", \"L1RefinesL2\"], [\"ImplRefinesL1\", \"L1RefinesL2\"]),\n])\n\nrun_directory(\"tsoelim\", [\n    (\"test\", [\"SharedStructs\", \"A\", \"B\", \"AB\"], [\"AB\"]),\n    (\"test2\", [\"SharedStructs2\", \"C\", \"D\", \"CD\"], [\"CD\"]),\n    (\"test3\", [\"SharedStructs3\", \"E\", \"F\", \"EF\"], [\"EF\"]),\n    (\"test4\", [\"SharedStructs4\", \"G\", \"H\", \"GH\"], [\"GH\"]),\n])\n\nrun_directory(\"reduction\", [\n    (\"test\", [\"SharedStructs\", \"A\", \"B\", \"AB\"], [\"AB\"]),\n    (\"test2\", [\"SharedStructs2\", \"C\", \"D\", \"CD\"], [\"CD\"]),\n])\n\nrun_directory(\"combining\", [\n    (\"test\", [\"SharedStructs\", \"A\", \"B\", \"AB\"], [\"AB\"]),\n])\n\nrun_directory(\"starweakening\", [\n    (\"test\", [\"SharedStructs\", \"A\", \"B\", \"AB\"], [\"AB\"]),\n    (\"test2\", [\"SharedStructs2\", \"C\", \"D\", \"CD\"], [\"CD\"]),\n    (\"test3\", [\"SharedStructs3\", \"E\", \"F\", \"EF\"], [\"EF\"]),\n    (\"test4\", [\"SharedStructs4\", \"G\", \"H\", \"GH\"], [\"GH\"]),\n])\n\nrun_directory(\"varhiding\", [\n    (\"test\", [\"SharedStructs\", \"A\", \"B\", \"AB\"], [\"AB\"]),\n    (\"test2\", [\"SharedStructs2\", \"C\", \"D\", \"CD\"], [\"CD\"]),\n    (\"test3\", [\"SharedStructs3\", \"E\", \"F\", \"EF\"], [\"EF\"]),\n    (\"test4\", [\"SharedStructs4\", \"G\", \"H\", \"GH\"], [\"GH\"]),\n    (\"test5\", [\"SharedStructs5\", \"I\", \"J\", \"IJ\"], [\"IJ\"]),\n])\n\nrun_directory(\"varintro\", [\n    (\"test\", [\"SharedStructs\", \"A\", \"B\", \"AB\"], [\"AB\"]),\n    (\"test2\", [\"SharedStructs2\", \"C\", \"D\", \"CD\"], [\"CD\"]),\n    (\"test3\", [\"SharedStructs3\", \"E\", \"F\", \"EF\"], [\"EF\"]),\n    (\"test4\", [\"SharedStructs4\", \"G\", \"H\", \"GH\"], [\"GH\"]),\n])\n\nrun_directory(\"weakening\", [\n    (\"test\", [\"SharedStructs\", \"A\", \"B\", \"AB\"], [\"AB\"]),\n    (\"test2\", [\"SharedStructs2\", \"C\", \"D\", \"CD\"], [\"CD\"]),\n    (\"test3\", [\"SharedStructs3\", \"E\", \"F\", \"EF\"], [\"EF\"]),\n])\n\nrun_directory(\"counter\", [\n    (\"SharedStructs\", [\"SharedStructs\"], []),\n    (\"A\", [\"A\"], []),\n    (\"B\", [\"B\"], []),\n    (\"C\", [\"C\"], []),\n    (\"D\", [\"D\"], []),\n    (\"E\", [\"E\"], []),\n    (\"F\", [\"F\"], []),\n    (\"G\", [\"G\"], []),\n    (\"I\", [\"I\"], []),\n    (\"J\", [\"J\"], []),\n    (\"AB\", [\"AB\"], [\"AB\"]),\n    (\"BC\", [\"BC\"], [\"BC\"]),\n    (\"CD\", [\"CD\"], [\"CD\"]),\n    (\"DE\", [\"DE\"], [\"DE\"]),\n    (\"EF\", [\"EF\"], [\"EF\"]),\n    (\"FG\", [\"FG\"], [\"FG\"]),\n    (\"GI\", [\"GI\"], [\"GI\"]),\n    (\"IJ\", [\"IJ\"], [\"IJ\"]),\n])\n\nrun_directory(\"bitvector\", [\n    (\"test\", [\"SharedStructs\", \"A\", \"B\", \"AB\"], [\"AB\"]),\n])\n\nrun_directory(\"regions\", [\n    (\"test\", [\"SharedStructs\", \"A\", \"B\", \"AB\"], [\"AB\"]),\n    (\"test2\", [\"SharedStructs2\", \"C\", \"D\", \"CD\"], [\"CD\"]),\n    (\"test3\", [\"SharedStructs3\", \"E\", \"F\", \"EF\"], [\"EF\"]),\n    (\"test4\", [\"SharedStructs4\", \"G\", \"H\", \"GH\"], [\"GH\"]),\n    (\"pointers\", [\"SharedStructsPointers\", \"level0\", \"level1\", \"level01proof\"], [\"level01proof\"]),\n])\n\nrun_directory(\"armada-parser\", [\n    (\"test\", [\"SharedStructs\", \"A\"], []),\n    (\"test2\", [\"SharedStructs2\", \"B\"], []),\n    (\"test3\", [\"SharedStructs3\", \"C\"], []),\n    (\"test4\", [\"SharedStructs4\", \"D\"], []),\n    (\"test5\", [\"SharedStructs5\", \"E\"], []),\n    (\"test6\", [\"SharedStructs6\", \"F\"], []),\n    (\"test7\", [\"SharedStructs7\", \"G\"], [])\n])\n\nrun_directory(\"mcslock\", [\n    (\"lock-array\", [\"MCSLock\", \"pseudo_impl\", \"L1\", \"L2\", \"L3\", \"L4\", \"L5\", \"L6\", \"pseudo_impl_L1\", \"L1_L2\", \"L2_L3\", \"L3_L4\", \"L4_L5\", \"L5_L6\"],\n     [\"pseudo_impl_L1\", \"L1_L2\", \"L2_L3\", \"L3_L4\", \"L4_L5\", \"L5_L6\"])\n])\n\nrun_directory(\"qbss\", [\n    (\"queue\", [\n        \"QueueBSSNoTSO\",\n        \"QueueBSSNoTSO_AbstractQueueIntroduced\",\n        \"QueueBSSNoTSO_AbstractQueueIntroduced_CombinedEnqueue\",\n        \"QueueBSSNoTSO_WithAbstractQueue\",\n        \"QueueBSSNoTSO_AbstractLogs\",\n        \"QueueBSSNoTSO_AbstractLogsStarweakened\",\n        \"QueueBSSNoTSO_HiddenEnqLocals\",\n        \"QueueBSSNoTSO_HiddenEnqDeqLocals\",\n        \"QueueBSSNoTSO_HiddenImpl\",\n    ],\n    [\n        \"NoTSOIntroduceAbstractQueue\",\n        \"CombineEnqueueAtomicAbstractQueue\",\n        \"CombineDequeueAtomicAbstractQueue\",\n        \"NoTSOUseAbstractQueueForLog\",\n        \"NoTSOStarWeaken\",\n        \"HideEnqueueLocals\",\n        \"HideDequeueLocals\",\n        \"HideGlobal\",\n    ])\n])\n"
  },
  {
    "path": "SConstruct2",
    "content": "# -*- python -*-\nimport re\nimport sys\nimport os, os.path\nimport subprocess\nimport traceback\nimport pdb\nimport random\nimport SCons.Util\nimport atexit\nimport platform\n\nImport(\"*\")\n\nenv = Environment()\nif sys.platform != 'win32' and sys.platform != 'cygwin':\n  env['MONO'] = 'dotnet'\n\n# Retrieve tool-specific command overrides passed in by the user\nAddOption('--DAFNYPATH',\n  dest='dafny_path',\n  type='string',\n  default=None,\n  action='store',\n  help='Specify the path to Dafny tool binaries')\n\nAddOption('--ONLYFILENAMES',\n  dest='onlyfilenames',\n  action='store_true',\n  default=False,\n  help='Only print out the file paths of dafny files that would be verified')\nonlyfilenames = GetOption('onlyfilenames')\n\nAddOption('--TIMELIMIT',\n  dest='time_limit',\n  type='int',\n  default=120,\n  action='store',\n  help='Specify the time limit to use for each verification')\n\ndafny_path = GetOption('dafny_path')\nif dafny_path is None:\n  sys.stderr.write(\"ERROR:  Missing --DAFNYPATH on command line\\n\")\n  exit(-1)\n\nif sys.platform == \"win32\" or sys.platform == \"cygwin\":\n  dafny_exe = os.path.join(dafny_path, 'Dafny.exe')\n  if not os.path.exists(dafny_exe):\n    print(\"ERROR:  Could not find Dafny executable in \" + dafny_path)\n    exit(-1)\n  dafny_invocation = [dafny_exe]\nelse:\n  dafny_exe = os.path.join(dafny_path, 'Dafny.dll')\n  if not os.path.exists(dafny_exe):\n    dafny_exe = os.path.join(dafny_path, 'dafny.dll')\n  if not os.path.exists(dafny_exe):\n    print(\"ERROR:  Could not find Dafny executable in \" + dafny_path)\n    exit(-1)\n  dafny_invocation = [\"dotnet\", dafny_exe]\n\n# Useful Dafny command lines\ndafny_basic_args = ['/compile:0', '/timeLimit:' + str(GetOption('time_limit')), '/trace']\ndafny_default_args = dafny_basic_args + ['/arith:5', '/noCheating:1']\ndafny_args_nlarith = dafny_basic_args + ['/arith:2', '/noCheating:1']\ndafny_spec_args = dafny_basic_args\n\n####################################################################\n#\n#   General routines\n#\n####################################################################\n\ndef recursive_glob(env, pattern, strings=False):\n  matches = []\n  split = os.path.split(pattern) # [0] is the directory, [1] is the actual pattern\n  platform_directory =  split[0] #os.path.normpath(split[0])\n  for d in os.listdir(platform_directory):\n    if os.path.isdir(os.path.join(platform_directory, d)):\n      newpattern = os.path.join(split[0], d, split[1])\n      matches.append(recursive_glob(env, newpattern, strings))\n\n  files = env.Glob(pattern, strings=strings)\n  matches.append(files)\n  return Flatten(matches)\n\n####################################################################\n#\n#   Make table of special cases requiring non-default arguments\n#\n####################################################################\n\nsource_to_args = [\n  ('.*test\\/weakening\\/ArithmeticFacts\\.dfy', dafny_args_nlarith),\n  ('.*Armada\\/util\\/math\\/[^\\.]+nonlinear\\.i\\.dfy', dafny_args_nlarith),\n  ('.*Armada\\/util\\/math\\/[^\\.]+auto[^\\.]*\\.i\\.dfy', dafny_args_nlarith),\n  ('.*Armada\\/util\\/math\\/mul\\.i\\.dfy', dafny_args_nlarith),\n  ('.*\\.dfy', dafny_default_args),\n]\n\n####################################################################\n#\n#   Dafny-specific utilities\n#\n####################################################################\n\ndafny_include_re = re.compile(r'include\\s+\"(\\S+)\"', re.M)\nsingle_line_comments_re = re.compile(r'//.*\\n')\nmultiline_comments_re = re.compile(r'/\\*(([^/\\*])|(\\*[^/])|(/[^\\*]))*\\*/')\n\ndef remove_dafny_comments(contents):\n  # Strip out multi-line comments, using a loop to deal with nested comments\n  while True:\n    (contents, substitutions_made) = re.subn(multiline_comments_re, ' ', contents)\n    if substitutions_made == 0:\n      break\n\n  # Strip out single-line comments\n  contents = re.sub(single_line_comments_re, '\\n', contents)\n  return contents\n\n# helper to look up Dafny command-line arguments matching a srcpath, from the\n# source_to_args[] dictionary, dealing with POSIX and Windows pathnames, and\n# falling back on a default if no specific override is present.\ndef get_dafny_command_line_args(srcpath):\n  srcpath = os.path.normpath(srcpath)  # normalize the path, which, on Windows, switches to \\\\ separators\n  srcpath = srcpath.replace('\\\\', '/') # switch to posix path separators\n  for entry in source_to_args:\n    pattern, args = entry\n    if re.search(pattern, srcpath, flags=re.IGNORECASE):\n      return args\n\n  return dafny_default_args\n\ndependencies_by_file = dict()\nalready_verified_files = set()\nalready_printed_files = set()\n\n# Scan a .dfy file to discover its transitive dependencies, and store a\n# list of them in dependencies_by_file[fullpath].\ndef recursively_scan_for_dependencies(fullpath):\n  if fullpath in dependencies_by_file:\n    return\n  contents = File(fullpath).get_text_contents()\n  dirname = os.path.dirname(fullpath)\n  filename = os.path.basename(fullpath)\n  contents = remove_dafny_comments(contents)\n  includes = dafny_include_re.findall(contents)\n  extra_files = [os.path.abspath(os.path.join(dirname, i)) for i in includes]\n  transitive_dependencies = set(extra_files)\n  for srcpath in extra_files:\n    recursively_scan_for_dependencies(srcpath)\n    transitive_dependencies.update(dependencies_by_file[srcpath])\n  all_dependencies = sorted(list(transitive_dependencies))\n  dependencies_by_file[fullpath] = all_dependencies\n\n\n# Scan a .dfy file to discover its dependencies, and add .vdfy targets for each.\ndef scan_for_more_targets(target, source, env):\n  node = source[0]\n  fullpath = str(node)\n  recursively_scan_for_dependencies(fullpath)\n  dependencies = dependencies_by_file[fullpath]\n  for srcpath in dependencies:\n    if srcpath not in already_verified_files:\n      f = os.path.splitext(srcpath)[0] + '.vdfy'\n      env.DafnyVerify(f, [srcpath, dafny_exe])\n      already_verified_files.add(srcpath)\n  return target, source + dependencies\n\n####################################################################\n#\n#   Dafny routines\n#\n####################################################################\n\ndef check_dafny(lines):\n  for line in lines:\n    if re.search(\"[Oo]ut of resource\", line):\n      sys.stderr.write(\"Dafny reported an out-of-resource error\\n\")\n      raise Exception()\n    if re.search(\"proof obligations\\]\\s+errors\", line):\n      sys.stderr.write(\"Dafny reported errors not in summary\\n\")\n      raise Exception()\n\ndef check_and_print_tail(filename):\n  with open(filename, 'r') as fh:\n    lines = fh.readlines()\n    check_dafny(lines)\n    sys.stdout.write(lines[-1])\n    sys.stdout.write('Full check of Dafny output succeeded\\n')\n\nCheckAndPrintTail = SCons.Action.ActionFactory(check_and_print_tail, lambda x: \"Checking \" + x)\n\ndef generate_dafny_verifier_actions(source, target, env, for_signature):\n  abs_source = File(source[0]).abspath\n  abs_target = File(target[0]).abspath\n  source_name = str(source[0])\n  temp_target_file = re.sub(r'\\.dfy$', '.tmp', source_name)\n  args = get_dafny_command_line_args(abs_source)\n  return [\n      dafny_invocation + args + [source_name, \">\", temp_target_file],\n      CheckAndPrintTail(temp_target_file),\n      Move(abs_target, temp_target_file)\n  ]\n\n\n# Add env.DafnyVerify(), to generate Dafny verifier actions\ndef add_dafny_verifier_builder(env):\n  dafny_verifier = Builder(generator = generate_dafny_verifier_actions,\n                           suffix = '.vdfy',\n                           src_suffix = '.dfy',\n                           chdir=0,\n                           emitter = scan_for_more_targets,\n                           )\n  env.Append(BUILDERS = {'DafnyVerify' : dafny_verifier})\n\n# Verify a set of Dafny files by creating verification targets for each,\n# which in turn causes a dependency scan to verify all of their dependencies.\ndef verify_dafny_files(env, files):\n  for f in files:\n    target = os.path.splitext(f)[0] + '.vdfy'\n    env.DafnyVerify(target, [f, dafny_exe])\n\n# Verify *.dfy files in a list of directories.  This enumerates\n# all files in those trees, and creates verification targets for each,\n# which in turn causes a dependency scan to verify all of their dependencies.\ndef verify_files_in(env, directories):\n  for d in directories:\n    files = recursive_glob(env, d+'/*.dfy', strings=True)\n    verify_dafny_files(env, files)\n\n####################################################################\n#\n#   Extract verification failure information\n#\n####################################################################\n\n# extract a string filename out of a build failure\ndef bf_to_filename(bf):\n    import SCons.Errors\n    if bf is None: # unknown targets product None in list\n        return '(unknown tgt)'\n    elif isinstance(bf, SCons.Errors.StopError):\n        return str(bf)\n    elif bf.node:\n        return str(bf.node)\n    elif bf.filename:\n        return bf.filename\n    return '(unknown failure)'\n\ndef report_verification_failures():\n    from SCons.Script import GetBuildFailures\n    bf = GetBuildFailures()\n    if bf:\n        # bf is normally a list of build failures; if an element is None,\n        # it's because of a target that scons doesn't know anything about.\n        for x in bf:\n          if x is not None:\n            filename = bf_to_filename(x)\n            if filename.endswith('.vdfy'):\n              file_to_print = os.path.splitext(filename)[0] + '.tmp'\n              if os.path.isfile(file_to_print):\n                sys.stdout.write('\\n##### Verification error.  Printing contents of ' + file_to_print + ' #####\\n\\n')\n                with open (file_to_print, 'r') as myfile:\n                  sys.stdout.write(myfile.read())\n              else:\n                print(\"ERROR:  Verification error, but cannot print output since file %s doesn't exist\" % (file_to_print))\n            else:\n              print(\"Build failure for %s\" % (filename))\n\n\ndef display_build_status():\n    report_verification_failures()\n\n####################################################################\n#\n#   Put it all together\n#\n####################################################################\n\nadd_dafny_verifier_builder(env)\nenv.AddMethod(verify_files_in, \"VerifyFilesIn\")\nenv.AddMethod(verify_dafny_files, \"VerifyDafnyFiles\")\natexit.register(display_build_status)\n\n####################################################################\n#\n#   Create dependencies\n#\n####################################################################\n\ndef run_directory(dir_name, dafny_files):\n  for dafny_file in dafny_files:\n    source = \"Test/%s/%s.dfy\" % (dir_name, dafny_file)\n    target = \"Test/%s/%s.vdfy\" % (dir_name, dafny_file)\n    env.DafnyVerify(target, [source, dafny_exe])\n\nrun_directory(\"assume-intro\", [\"AB\", \"CD\", \"EF\"])\nrun_directory(\"barrier\", [\"ImplRefinesL1\", \"L1RefinesL2\"])\nrun_directory(\"tsoelim\", [\"AB\", \"CD\", \"EF\", \"GH\"])\nrun_directory(\"reduction\", [\"AB\", \"CD\"])\nrun_directory(\"combining\", [\"AB\"])\nrun_directory(\"varhiding\", [\"AB\", \"CD\", \"EF\", \"GH\", \"IJ\"])\nrun_directory(\"varintro\", [\"AB\", \"CD\", \"EF\", \"GH\"])\nrun_directory(\"weakening\", [\"AB\", \"CD\", \"EF\"])\nrun_directory(\"counter\", [\"AB\", \"BC\", \"CD\", \"DE\", \"EF\", \"FG\", \"GI\", \"IJ\"])\nrun_directory(\"bitvector\", [\"AB\"])\nrun_directory(\"regions\", [\"AB\", \"CD\", \"EF\", \"GH\", \"level01proof\"])\nrun_directory(\"starweakening\", [\"AB\", \"CD\", \"EF\", \"GH\"])\nrun_directory(\"armada-parser\", [\"A\", \"B\", \"C\", \"D\", \"E\", \"F\"])\nrun_directory(\"mcslock\", [\"pseudo_impl_L1\", \"L1_L2\", \"L2_L3\", \"L3_L4\", \"L4_L5\", \"L5_L6\"])\nrun_directory(\"qbss\", [\"NoTSOIntroduceAbstractQueue\",\n                       \"CombineEnqueueAtomicAbstractQueue\",\n                       \"CombineDequeueAtomicAbstractQueue\",\n                       \"NoTSOUseAbstractQueueForLog\",\n                       \"NoTSOStarWeaken\",\n                       \"HideEnqueueLocals\",\n                       \"HideDequeueLocals\",\n                       \"HideGlobal\",\n                      ])\n"
  },
  {
    "path": "SECURITY.md",
    "content": "<!-- BEGIN MICROSOFT SECURITY.MD V0.0.3 BLOCK -->\n\n## Security\n\nMicrosoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).\n\nIf you believe you have found a security vulnerability in any Microsoft-owned repository that meets Microsoft's [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)) of a security vulnerability, please report it to us as described below.\n\n## Reporting Security Issues\n\n**Please do not report security vulnerabilities through public GitHub issues.**\n\nInstead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report).\n\nIf you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com).  If possible, encrypt your message with our PGP key; please download it from the the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc).\n\nYou should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc).\n\nPlease include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:\n\n  * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)\n  * Full paths of source file(s) related to the manifestation of the issue\n  * The location of the affected source code (tag/branch/commit or direct URL)\n  * Any special configuration required to reproduce the issue\n  * Step-by-step instructions to reproduce the issue\n  * Proof-of-concept or exploit code (if possible)\n  * Impact of the issue, including how an attacker might exploit the issue\n\nThis information will help us triage your report more quickly.\n\nIf you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs.\n\n## Preferred Languages\n\nWe prefer all communications to be in English.\n\n## Policy\n\nMicrosoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd).\n\n<!-- END MICROSOFT SECURITY.MD BLOCK -->\n"
  },
  {
    "path": "Source/Armada/AbstractProofGenerator.cs",
    "content": "using System;\nusing System.Numerics;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text;\nusing System.Text.RegularExpressions;\nusing Token = Microsoft.Boogie.Token;\n\nnamespace Microsoft.Armada\n{\n  public class AuxiliaryInfo\n  {\n    public readonly string FieldName;\n    public readonly string TypeName;\n    public readonly string InitName;\n    public readonly string NextName;\n\n    public AuxiliaryInfo(string i_FieldName, string i_TypeName, string i_InitName, string i_NextName)\n    {\n      FieldName = i_FieldName;\n      TypeName = i_TypeName;\n      InitName = i_InitName;\n      NextName = i_NextName;\n    }\n  }\n\n  public abstract class InvariantInfo\n  {\n    protected string key;\n    protected string name;\n    protected List<string> dependencies;\n    protected string initLemmaName;\n    protected string nextLemmaName;\n    protected string nextStepBody;\n    protected bool opaque;\n\n    public InvariantInfo(string i_key, string i_name, List<string> i_dependencies, string i_nextStepBody, bool i_opaque)\n    {\n      key = i_key;\n      name = i_name;\n      dependencies = i_dependencies;\n      initLemmaName = null;\n      nextLemmaName = null;\n      nextStepBody = i_nextStepBody;\n      opaque = i_opaque;\n    }\n\n    public virtual string Key { get { return key; } }\n    public virtual string Name { get { return name; } }\n    public virtual List<string> Dependencies { get { return dependencies; } }\n    public virtual string InitLemmaName { get { return initLemmaName; } }\n    public virtual string NextLemmaName { get { return nextLemmaName; } }\n\n    private string FindMatchingDependency(string dependency, IEnumerable<InvariantInfo> allInvariants)\n    {\n      foreach (var inv in allInvariants) {\n        if (inv.Key == dependency || inv.Key == $\"UserInv_{dependency}\") {\n          return inv.Name;\n        }\n      }\n      return dependency;\n    }\n\n    private string GetRevelations(IEnumerable<InvariantInfo> allInvariants)\n    {\n      string revelations = opaque ? $\"reveal {Name}();\\n\" : \"\";\n      foreach (var dependency in Dependencies) {\n        foreach (var inv in allInvariants) {\n          if (inv.Key == dependency || inv.Key == $\"UserInv_{dependency}\") {\n            if (inv.opaque) {\n              revelations += $\"reveal {inv.Name}();\\n\";\n              break;\n            }\n          }\n        }\n      }\n      return revelations;\n    }\n\n    public virtual void GenerateInitLemma(ProofGenerationParams pgp)\n    {\n      initLemmaName = $\"lemma_InvariantPredicateImpliedByInit_{Key}\";\n      var revelation = opaque ? $\"reveal {Name}();\" : \"\";\n      string str = $@\"\n        lemma {initLemmaName}(s:LPlusState)\n          requires LPlus_Init(s)\n          ensures  {Name}(s)\n        {{\n          {revelation}\n        }}\n      \";\n      pgp.AddLemma(str, \"invariants\");\n    }\n\n    public virtual string GenerateSpecificNextLemma(ProofGenerationParams pgp, AtomicPath atomicPath,\n                                                    IEnumerable<InvariantInfo> allInvariants, AtomicSpec atomicSpec,\n                                                    bool onlyNonstoppingPaths)\n    {\n      string nameSuffix = atomicPath.Name;\n      string specificPathLemmaName = $\"lemma_InvariantPredicateMaintainedByPath_{Key}_{nameSuffix}\";\n      var pr = new PathPrinter(atomicSpec);\n      string str = $@\"\n        lemma {specificPathLemmaName}(s: LPlusState, s': LPlusState, path: {atomicSpec.Prefix}_Path, tid: Armada_ThreadHandle)\n          requires {Name}(s)\n      \";\n      str += String.Concat(Dependencies.Select(dependency => $\"  requires {FindMatchingDependency(dependency, allInvariants)}(s);\\n\"));\n      if (onlyNonstoppingPaths) {\n        str += $@\"\n          requires s'.s.stop_reason.Armada_NotStopped?\n        \";\n      }\n      str += $@\"\n          requires path.{atomicSpec.Prefix}_Path_{nameSuffix}?\n          requires {atomicSpec.Prefix}_ValidPath(s, path, tid)\n          requires s' == {atomicSpec.Prefix}_GetStateAfterPath(s, path, tid)\n          ensures  {Name}(s')\n        {{\n          { pr.GetOpenValidPathInvocation(atomicPath) }\n          { GetRevelations(allInvariants) }\n          ProofCustomizationGoesHere();\n          { nextStepBody }\n          assert {Name}(s');\n        }}\n      \";\n      pgp.AddLemma(str, \"invariants\");\n\n      return specificPathLemmaName;\n    }\n\n    public virtual void GenerateAtomicNextLemma(ProofGenerationParams pgp, IEnumerable<InvariantInfo> allInvariants,\n                                                AtomicSpec atomicSpec, bool onlyNonstoppingPaths)\n    {\n      string finalCases = \"\";\n      foreach (var atomicPath in atomicSpec.AtomicPaths) {\n        string specificPathLemma = GenerateSpecificNextLemma(pgp, atomicPath, allInvariants, atomicSpec, onlyNonstoppingPaths);\n        finalCases += $\"    case {atomicSpec.Prefix}_Path_{atomicPath.Name}(_) => {specificPathLemma}(s, s', path, tid);\\n\";\n      }\n\n      nextLemmaName = $\"lemma_InvariantPredicateMaintainedByPath_{Key}\";\n      string str = $@\"\n        lemma {nextLemmaName}(s: LPlusState, s': LPlusState, path: {atomicSpec.Prefix}_Path, tid: Armada_ThreadHandle)\n          requires {Name}(s)\n      \";\n      foreach (var dependency in Dependencies)\n      {\n        str += $\"  requires {FindMatchingDependency(dependency, allInvariants)}(s);\\n\";\n      }\n      if (onlyNonstoppingPaths) {\n        str += @\"\n          requires s'.s.stop_reason.Armada_NotStopped?\n        \";\n      }\n      str += $@\"\n          requires {atomicSpec.Prefix}_ValidPath(s, path, tid)\n          requires s' == {atomicSpec.Prefix}_GetStateAfterPath(s, path, tid)\n          ensures  {Name}(s')\n        {{\n          { GetRevelations(allInvariants) }\n          match path {{\n            { finalCases }\n          }}\n        }}\n      \";\n      pgp.AddLemma(str, \"invariants\");\n    }\n\n    public virtual void GenerateProofs(ProofGenerationParams pgp, IEnumerable<InvariantInfo> allInvariants, AtomicSpec atomicSpec,\n                                       bool onlyNonstoppingPaths)\n    {\n      GenerateInitLemma(pgp);\n      GenerateAtomicNextLemma(pgp, allInvariants, atomicSpec, onlyNonstoppingPaths);\n    }\n  }\n\n  public class UserInvariantInfo : InvariantInfo\n  {\n    public UserInvariantInfo(string i_key, string i_name, List<string> i_dependencies, bool i_opaque)\n      : base(i_key, i_name, i_dependencies, \"\", i_opaque)\n    {\n    }\n  }\n\n  public class InternalInvariantInfo : InvariantInfo\n  {\n    public InternalInvariantInfo(string i_key, string i_name, List<string> i_dependencies, string nextStepBody=\"\")\n      : base(i_key, i_name, i_dependencies, nextStepBody, false /* opaque: no */)\n    {\n    }\n  }\n\n  public abstract class AbstractProofGenerator\n  {\n    protected ProofGenerationParams pgp;\n    protected bool stateDependentConvertStep;\n    protected Dictionary<ArmadaPC, ArmadaPC> pcMap;\n    protected Dictionary<NextRoutine, NextRoutine> nextRoutineMap;\n    protected List<ImportFileArmadaProofDecl> importedFiles;\n    protected List<ImportModuleArmadaProofDecl> importedModules;\n    protected List<InvariantInfo> invariants;\n    protected List<AuxiliaryInfo> auxiliaries;\n    protected AtomicSpec lAtomic, hAtomic;\n    protected Dictionary<AtomicPath, AtomicPath> pathMap;\n\n    // To prevent duplicate lemmas when there are duplicate calls\n    private bool calledGenerateAppendStoreBufferOtherWay = false;\n\n    public AbstractProofGenerator(ProofGenerationParams i_pgp, bool i_stateDependentConvertStep = false)\n    {\n      pgp = i_pgp;\n      stateDependentConvertStep = i_stateDependentConvertStep;\n      nextRoutineMap = null;\n      importedFiles = new List<ImportFileArmadaProofDecl>();\n      importedModules = new List<ImportModuleArmadaProofDecl>();\n      invariants = new List<InvariantInfo>();\n      auxiliaries = new List<AuxiliaryInfo>();\n      lAtomic = null;\n      hAtomic = null;\n      pathMap = null;\n\n      var revelationsFile = pgp.proofFiles.CreateAuxiliaryProofFile(\"revelations\", false);\n      pgp.proofFiles.MainProof.IncludeAndImportGeneratedFile(\"revelations\");\n\n      var specFile = pgp.proofFiles.CreateAuxiliaryProofFile(\"specs\", false);\n      specFile.AddIncludeImport(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/option.s.dfy\", \"util_option_s\");\n      specFile.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/strategies/generic/GenericArmadaLemmas.i.dfy\");\n      specFile.AddImport(\"GenericArmadaSpecModule\");\n      specFile.AddImport(\"GenericArmadaLemmasModule\");\n      specFile.IncludeAndImportGeneratedFile(\"revelations\");\n      pgp.proofFiles.MainProof.IncludeAndImportGeneratedFile(\"specs\");\n\n      var plusFile = pgp.proofFiles.CreateAuxiliaryProofFile(\"PlusLemmas\");\n      plusFile.IncludeAndImportGeneratedFile(\"specs\");\n      plusFile.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/strategies/generic/GenericArmadaPlus.i.dfy\");\n      plusFile.AddImport(\"GenericArmadaPlusModule\");\n      pgp.proofFiles.MainProof.IncludeAndImportGeneratedFile(\"PlusLemmas\");\n\n      var effectFile = pgp.proofFiles.CreateAuxiliaryProofFile(\"pceffect\");\n      effectFile.IncludeAndImportGeneratedFile(\"specs\");\n      effectFile.IncludeAndImportGeneratedFile(\"revelations\");\n      pgp.proofFiles.MainProof.IncludeAndImportGeneratedFile(\"pceffect\");\n\n      var latomicFile = pgp.proofFiles.CreateAuxiliaryProofFile(\"latomic\");\n      latomicFile.IncludeAndImportGeneratedFile(\"specs\");\n      latomicFile.IncludeAndImportGeneratedFile(\"revelations\");\n      pgp.proofFiles.MainProof.IncludeAndImportGeneratedFile(\"latomic\");\n\n      var hatomicFile = pgp.proofFiles.CreateAuxiliaryProofFile(\"hatomic\");\n      hatomicFile.IncludeAndImportGeneratedFile(\"specs\");\n      hatomicFile.IncludeAndImportGeneratedFile(\"revelations\");\n      pgp.proofFiles.MainProof.IncludeAndImportGeneratedFile(\"hatomic\");\n\n      var convertFile = pgp.proofFiles.CreateAuxiliaryProofFile(\"convert\");\n      convertFile.IncludeAndImportGeneratedFile(\"specs\");\n      convertFile.IncludeAndImportGeneratedFile(\"pceffect\");\n      convertFile.IncludeAndImportGeneratedFile(\"latomic\");\n      convertFile.IncludeAndImportGeneratedFile(\"hatomic\");\n      convertFile.AddIncludeImport(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/seqs.i.dfy\", \"util_collections_seqs_i\");\n      convertFile.AddIncludeImport(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/maps.i.dfy\", \"util_collections_maps_i\");\n      pgp.proofFiles.MainProof.IncludeAndImportGeneratedFile(\"convert\");\n\n      var defsFile = pgp.proofFiles.CreateAuxiliaryProofFile(\"defs\");\n      defsFile.IncludeAndImportGeneratedFile(\"specs\");\n      defsFile.IncludeAndImportGeneratedFile(\"convert\");\n      defsFile.IncludeAndImportGeneratedFile(\"latomic\");\n      defsFile.IncludeAndImportGeneratedFile(\"hatomic\");\n      defsFile.AddIncludeImport(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/option.s.dfy\", \"util_option_s\");\n      defsFile.AddIncludeImport(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/maps.i.dfy\", \"util_collections_maps_i\");\n      defsFile.AddIncludeImport(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/seqs.i.dfy\", \"util_collections_seqs_i\");\n      defsFile.AddImport(\"util_collections_seqs_s\");\n      pgp.proofFiles.MainProof.IncludeAndImportGeneratedFile(\"defs\");\n\n      var utilityFile = pgp.proofFiles.CreateAuxiliaryProofFile(\"utility\");\n      utilityFile.IncludeAndImportGeneratedFile(\"specs\");\n      utilityFile.IncludeAndImportGeneratedFile(\"convert\");\n      utilityFile.IncludeAndImportGeneratedFile(\"defs\");\n      utilityFile.IncludeAndImportGeneratedFile(\"latomic\");\n      utilityFile.IncludeAndImportGeneratedFile(\"hatomic\");\n      utilityFile.AddIncludeImport(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/seqs.s.dfy\",\n                                   \"util_collections_seqs_s\");\n      utilityFile.AddIncludeImport(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/seqs.i.dfy\",\n                                   \"util_collections_seqs_i\");\n      pgp.proofFiles.MainProof.IncludeAndImportGeneratedFile(\"utility\");\n\n      var invFile = pgp.proofFiles.CreateAuxiliaryProofFile(\"invariants\");\n      invFile.IncludeAndImportGeneratedFile(\"specs\");\n      invFile.IncludeAndImportGeneratedFile(\"convert\");\n      invFile.IncludeAndImportGeneratedFile(\"revelations\");\n      invFile.IncludeAndImportGeneratedFile(\"utility\");\n      invFile.IncludeAndImportGeneratedFile(\"defs\");\n      invFile.IncludeAndImportGeneratedFile(\"latomic\");\n      invFile.IncludeAndImportGeneratedFile(\"hatomic\");\n      invFile.AddIncludeImport(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/strategies/invariants.i.dfy\", \"InvariantsModule\");\n      invFile.AddIncludeImport(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/strategies/generic/GenericArmadaSpec.i.dfy\",\n                               \"GenericArmadaSpecModule\");\n      pgp.proofFiles.MainProof.IncludeAndImportGeneratedFile(\"invariants\");\n\n      var liftFile = pgp.proofFiles.CreateAuxiliaryProofFile(\"lift\");\n      liftFile.IncludeAndImportGeneratedFile(\"specs\");\n      liftFile.IncludeAndImportGeneratedFile(\"convert\");\n      liftFile.IncludeAndImportGeneratedFile(\"defs\");\n      liftFile.IncludeAndImportGeneratedFile(\"invariants\");\n      liftFile.IncludeAndImportGeneratedFile(\"utility\");\n      liftFile.IncludeAndImportGeneratedFile(\"latomic\");\n      liftFile.IncludeAndImportGeneratedFile(\"hatomic\");\n      liftFile.IncludeAndImportGeneratedFile(\"revelations\");\n      liftFile.AddIncludeImport(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/strategies/generic/LiftAtomicToAtomic.i.dfy\",\n                                \"LiftAtomicToAtomicModule\");\n      liftFile.AddIncludeImport(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/strategies/generic/GenericArmadaAtomic.i.dfy\",\n                                \"GenericArmadaAtomicModule\");\n      liftFile.AddIncludeImport(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/seqs.s.dfy\",\n                                \"util_collections_seqs_s\");\n      pgp.proofFiles.MainProof.IncludeAndImportGeneratedFile(\"lift\");\n\n      var str = @\"\n        predicate InductiveInvBasic(s: LPlusState)\n        {\n          0 !in s.s.threads\n        }\n      \";\n      pgp.AddPredicate(str, \"defs\");\n      AddInvariant(new InternalInvariantInfo(\"InductiveInvBasic\", \"InductiveInvBasic\", new List<string>()));\n\n      var atomicModulePath = ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/strategies/generic/GenericArmadaAtomic.i.dfy\";\n      convertFile.AddIncludeImport(atomicModulePath, \"GenericArmadaAtomicModule\");\n      invFile.AddIncludeImport(atomicModulePath, \"GenericArmadaAtomicModule\");\n      pgp.proofFiles.MainProof.AddIncludeImport(atomicModulePath, \"GenericArmadaAtomicModule\");\n    }\n\n    public abstract void GenerateProof();\n\n    ////////////////////////////////////////////////////////////////////////\n    /// Checking that the layers are similar enough to generate a proof\n    ////////////////////////////////////////////////////////////////////////\n\n    protected virtual bool CheckEquivalence()\n    {\n      return CheckStructsEquivalence() && CheckGlobalsEquivalence() && CheckMethodsEquivalence();\n    }\n\n    protected virtual bool CheckStructsEquivalence()\n    {\n      if (pgp.symbolsLow.StructsModuleName != pgp.symbolsHigh.StructsModuleName) {\n        AH.PrintError(pgp.prog, $\"Levels {pgp.mLow.Name} and {pgp.mHigh.Name} don't use the same structs module\");\n        return false;\n      }\n\n      return true;\n    }\n\n    protected bool CheckGlobalVariableEquivalence(string name, ArmadaVariable v_l, ArmadaVariable v_h)\n    {\n        if (v_l is AddressableArmadaVariable && !(v_h is AddressableArmadaVariable)) {\n          AH.PrintError(pgp.prog, $\"Global variable {name} is addressable in level {pgp.mLow.Name} but not in level {pgp.mHigh.Name}\");\n          return false;\n        }\n        if (!(v_l is AddressableArmadaVariable) && (v_h is AddressableArmadaVariable)) {\n          AH.PrintError(pgp.prog, $\"Global variable {name} is addressable in level {pgp.mHigh.Name} but not in level {pgp.mLow.Name}\");\n          return false;\n        }\n        if (v_l.NoTSO() && !v_h.NoTSO()) {\n          AH.PrintError(pgp.prog, $\"Global variable {name} is ghost in level {pgp.mLow.Name} but not in level {pgp.mHigh.Name}\");\n          return false;\n        }\n        if (!v_l.NoTSO() && v_h.NoTSO()) {\n          AH.PrintError(pgp.prog, $\"Global variable {name} is ghost in level {pgp.mHigh.Name} but not in level {pgp.mLow.Name}\");\n          return false;\n        }\n\n        if (!AH.TypesMatch(v_l.ty, v_h.ty)) {\n          AH.PrintError(pgp.prog, $\"Global variable {name} has type {v_l.ty} in level {pgp.mLow.Name} but type {v_h.ty} in level {pgp.mHigh.Name}\");\n          return false;\n        }\n\n        if (v_l is GlobalUnaddressableArmadaVariable && v_h is GlobalUnaddressableArmadaVariable &&\n            ((GlobalUnaddressableArmadaVariable)v_l).initialValue == null && ((GlobalUnaddressableArmadaVariable)v_h).initialValue != null) {\n          AH.PrintError(pgp.prog, $\"Global variable {name} has an initial value in level {pgp.mHigh.Name} but no initial value in level {pgp.mLow.Name}\");\n          return false;\n        }\n\n        return true;\n    }\n\n    protected virtual bool CheckGlobalsEquivalence()\n    {\n      return CheckGlobalsEquivalenceAbstract();\n    }\n\n    protected bool CheckGlobalsEquivalenceAbstract()\n    {\n      var globalVarsLow = pgp.symbolsLow.Globals.VariableNames.ToArray();\n      var globalVarsHigh = pgp.symbolsHigh.Globals.VariableNames.ToArray();\n\n      if (globalVarsLow.Length != globalVarsHigh.Length) {\n        AH.PrintError(pgp.prog, $\"There are {globalVarsLow.Length} global variables in level {pgp.mLow.Name} but {globalVarsHigh.Length} in level {pgp.mHigh.Name}\");\n        return false;\n      }\n\n      for (int i = 0; i < globalVarsLow.Length; ++i) {\n        if (globalVarsLow[i] != globalVarsHigh[i]) {\n          AH.PrintError(pgp.prog, $\"Global variable number {i+1} in level {pgp.mLow.Name} is {globalVarsLow[i]}, which doesn't match global variable number {i+1} in level {pgp.mHigh.Name} which is {globalVarsHigh[i]}\");\n          return false;\n        }\n        var name = globalVarsLow[i];\n        if (!CheckGlobalVariableEquivalence(name, pgp.symbolsLow.Globals.Lookup(name), pgp.symbolsHigh.Globals.Lookup(name))) {\n          return false;\n        }\n      }\n\n      return true;\n    }\n\n    protected virtual bool CheckVariableNameListEquivalence(IEnumerable<string> varNames_l, IEnumerable<string> varNames_h,\n                                                            ArmadaSingleMethodSymbolTable s_l, ArmadaSingleMethodSymbolTable s_h,\n                                                            string methodName, string descriptor)\n    {\n      var vars_l = varNames_l.ToArray();\n      var vars_h = varNames_h.ToArray();\n      if (vars_l.Length != vars_h.Length) {\n        AH.PrintError(pgp.prog, $\"Method {methodName} has {vars_l.Length} {descriptor} variables in level {pgp.mLow.Name} but {vars_h.Length} of them in level {pgp.mHigh.Name}\");\n        return false;\n      }\n\n      for (int i = 0; i < vars_l.Length; ++i) {\n        var name_l = vars_l[i];\n        var name_h = vars_h[i];\n        if (name_l != name_h) {\n          AH.PrintError(pgp.prog, $\"In method {methodName}, {descriptor} variable number {i+1} is named {name_l} in level {pgp.mLow.Name} but named {name_h} in level {pgp.mHigh.Name}\");\n          return false;\n        }\n        var v_l = s_l.LookupVariable(name_l);\n        var v_h = s_h.LookupVariable(name_h);\n        if (!AH.TypesMatch(v_l.ty, v_h.ty)) {\n          AH.PrintError(pgp.prog, $\"In method {methodName}, the {descriptor} variable named {name_l} has type {v_l.ty} in level {pgp.mLow.Name} but type {v_h.ty} in level {pgp.mHigh.Name}\");\n          return false;\n        }\n      }\n\n      return true;\n    }\n\n    protected virtual bool CheckMethodsEquivalence()\n    {\n      foreach (var methodName in pgp.symbolsLow.MethodNames) {\n        if (!pgp.symbolsHigh.DoesMethodNameExist(methodName)) {\n          AH.PrintError(pgp.prog, $\"Method {methodName} is in level {pgp.mLow.Name} but not in level {pgp.mHigh.Name}\");\n          return false;\n        }\n      }\n\n      foreach (var methodName in pgp.symbolsHigh.MethodNames) {\n        if (!pgp.symbolsLow.DoesMethodNameExist(methodName)) {\n          AH.PrintError(pgp.prog, $\"Method {methodName} is in level {pgp.mHigh.Name} but not in level {pgp.mLow.Name}\");\n          return false;\n        }\n      }\n\n      foreach (var methodName in pgp.symbolsLow.MethodNames) {\n        var s_l = pgp.symbolsLow.GetMethodSymbolTable(methodName);\n        var s_h = pgp.symbolsHigh.GetMethodSymbolTable(methodName);\n\n        if (s_l.IsExternal && !s_h.IsExternal) {\n            AH.PrintError(pgp.prog, $\"Method {methodName} is external in level {pgp.mLow.Name} but not external in level {pgp.mHigh.Name}\");\n            return false;\n        }\n        if (!s_l.IsExternal && s_h.IsExternal) {\n            AH.PrintError(pgp.prog, $\"Method {methodName} is external in level {pgp.mHigh.Name} but not external in level {pgp.mLow.Name}\");\n            return false;\n        }\n\n        if (!CheckVariableNameListEquivalence(s_l.InputVariableNames, s_h.InputVariableNames, s_l, s_h, methodName, \"input\")) {\n          return false;\n        }\n        if (!CheckVariableNameListEquivalence(s_l.OutputVariableNames, s_h.OutputVariableNames, s_l, s_h, methodName, \"output\")) {\n          return false;\n        }\n        if (!CheckVariableNameListEquivalence(s_l.AllVariableNamesInOrder, s_h.AllVariableNamesInOrder, s_l, s_h, methodName, \"\")) {\n          return false;\n        }\n      }\n\n      return true;\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    /// Generate PC-effect elements\n    ////////////////////////////////////////////////////////////////////////\n\n    protected void GeneratePCEffectLemmas()\n    {\n      GeneratePCEffectLemmas(\"L\", pgp.symbolsLow);\n      GeneratePCEffectLemmas(\"H\", pgp.symbolsHigh);\n    }\n\n    protected void GeneratePCEffectLemmas(string m, ArmadaSymbolTable symbols)\n    {\n      string str;\n\n      var pr = new ModuleStepPrinter(m);\n      foreach (var nextRoutine in symbols.NextRoutines)\n      {\n        str = $@\"\n          lemma lemma_PCEffectOfStep_{m}_{nextRoutine.NameSuffix}(\n            s: {m}.Armada_TotalState,\n            step: {m}.Armada_Step,\n            tid: Armada_ThreadHandle\n            )\n            requires {m}.Armada_ValidStep(s, step, tid)\n            requires step.Armada_Step_{nextRoutine.NameSuffix}?\n        \";\n\n        if (nextRoutine.Tau) {\n          str += $@\"\n            ensures  var s' := {m}.Armada_GetNextState(s, step, tid);\n                     s'.stop_reason.Armada_NotStopped? && tid in s'.threads && s'.threads[tid].pc == s.threads[tid].pc\";\n        }\n        else {\n          str += $\"ensures  s.threads[tid].pc.{nextRoutine.startPC}?\\n\";\n          if (nextRoutine.Stopping) {\n            str += $\"ensures var s' := {m}.Armada_GetNextState(s, step, tid); !s'.stop_reason.Armada_NotStopped?\\n\";\n          }\n          else if (nextRoutine.endPC == null) {\n            str += $\"ensures var s' := {m}.Armada_GetNextState(s, step, tid); s'.stop_reason.Armada_NotStopped? && tid !in s'.threads\\n\";\n          }\n          else {\n            str += $@\"\n            ensures  var s' := {m}.Armada_GetNextState(s, step, tid);\n                     s'.stop_reason.Armada_NotStopped? && tid in s'.threads && s'.threads[tid].pc.{nextRoutine.endPC}?\n            \";\n          }\n        }\n\n        str += $@\"\n          {{\n            { pr.GetOpenValidStepInvocation(nextRoutine) }\n          }}\n        \";\n\n        pgp.AddLemma(str, \"pceffect\");\n      }\n\n      var pcToNextRoutines = new Dictionary<ArmadaPC, List<NextRoutine>>();\n\n      foreach (var nextRoutine in symbols.NextRoutines.Where(r => !r.Tau))\n      {\n        if (pcToNextRoutines.ContainsKey(nextRoutine.startPC)) {\n          pcToNextRoutines[nextRoutine.startPC].Add(nextRoutine);\n        }\n        else {\n          pcToNextRoutines[nextRoutine.startPC] = new List<NextRoutine>{ nextRoutine };\n        }\n      }\n\n      var pcs = new List<ArmadaPC>();\n      symbols.AllMethods.AppendAllPCs(pcs);\n      foreach (var pc in pcs)\n      {\n        str = $@\"\n          lemma lemma_PossibleStepsFromPC_{m}_{pc}(s: {m}.Armada_TotalState, step: {m}.Armada_Step, tid: Armada_ThreadHandle)\n            requires {m}.Armada_ValidStep(s, step, tid)\n            requires tid in s.threads\n            requires s.threads[tid].pc.{pc}?\n            ensures  step.Armada_Step_Tau?\";\n        var nextRoutines = pcToNextRoutines.ContainsKey(pc) ? pcToNextRoutines[pc] : new List<NextRoutine>();\n        str += String.Concat(nextRoutines.Select(r => $\" || step.Armada_Step_{r.NameSuffix}?\"));\n        str += @\"\n          {\n            match step {\n        \";\n        foreach (var nextRoutine in symbols.NextRoutines) {\n          str += $\"{pr.CaseEntry(nextRoutine)} =>\\n\";\n          if (!nextRoutine.Tau && !nextRoutine.startPC.Equals(pc)) {\n            str += $\"lemma_PCEffectOfStep_{m}_{nextRoutine.NameSuffix}(s, step, tid);\\n\";\n          }\n        }\n        str += \"} }\";\n        pgp.AddLemma(str, \"pceffect\");\n      }\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    /// PC map\n    ////////////////////////////////////////////////////////////////////////\n\n    protected void MakeTrivialPCMap()\n    {\n      pcMap = new Dictionary<ArmadaPC, ArmadaPC>();\n      var pcs = new List<ArmadaPC>();\n      pgp.symbolsLow.AllMethods.AppendAllPCs(pcs);\n      foreach (var pc in pcs)\n      {\n        pcMap[pc] = pc.CloneWithNewSymbolTable(pgp.symbolsHigh);\n      }\n    }\n\n    protected virtual void ExtendPCMapWithExternalAndStructsMethods()\n    {\n      foreach (var methodName in pgp.symbolsLow.MethodNames) {\n        var st = pgp.symbolsLow.GetMethodSymbolTable(methodName);\n        if (st.IsExternal || st.IsFromStructsModule) {\n          List<ArmadaPC> allPCs = new List<ArmadaPC>();\n          pgp.symbolsLow.AllMethods.LookupMethod(methodName).AppendAllPCs(allPCs);\n          foreach (var pc in allPCs) {\n            pcMap[pc] = pc.CloneWithNewSymbolTable(pgp.symbolsHigh);\n          }\n        }\n      }\n    }\n\n    protected ArmadaPC LiftPC(ArmadaPC pc)\n    {\n      if (pc == null) {\n        return null;\n      }\n      return pcMap[pc];\n    }\n\n    protected virtual String TranslateFormalNameUsingPcMap(NextFormal formal, ArmadaPC lpc, Dictionary<ArmadaPC, ArmadaPC> pcMap)\n    {\n      var lpcName = lpc.ToString();\n      if (formal.GloballyUniqueVarName.Contains(lpcName)) {\n        return formal.GloballyUniqueVarName.Replace(lpcName, pcMap[lpc].ToString());\n      }\n      else {\n        return formal.GloballyUniqueVarName;\n      }\n    }\n\n    protected virtual void GenerateNextRoutineMap(bool warnOnMissingRoutines = true)\n    {\n      nextRoutineMap = new Dictionary<NextRoutine, NextRoutine>();\n      var hmap = new Dictionary<Tuple<ArmadaPC, ArmadaPC, bool, bool>, NextRoutine>();\n      foreach (var nextRoutine in pgp.symbolsHigh.NextRoutines) {\n        var t = new Tuple<ArmadaPC, ArmadaPC, bool, bool>(nextRoutine.startPC, nextRoutine.endPC, nextRoutine.UndefinedBehavior,\n                                                          nextRoutine.BranchOutcome);\n        if (hmap.ContainsKey(t)) {\n          AH.PrintError(pgp.prog,\n                        $\"More than one next routine from PC {nextRoutine.startPC} to {nextRoutine.endPC} in level {pgp.mHigh.Name}\");\n          hmap.Remove(t);\n        }\n        else {\n          hmap[t] = nextRoutine;\n        }\n      }\n\n      foreach (var nextRoutine in pgp.symbolsLow.NextRoutines) {\n        var startPC = LiftPC(nextRoutine.startPC);\n        var endPC = LiftPC(nextRoutine.endPC);\n        var t = new Tuple<ArmadaPC, ArmadaPC, bool, bool>(startPC, endPC, nextRoutine.UndefinedBehavior, nextRoutine.BranchOutcome);\n        if (hmap.ContainsKey(t)) {\n          nextRoutineMap[nextRoutine] = hmap[t];\n        }\n        else if (warnOnMissingRoutines) {\n          AH.PrintWarning(pgp.prog, $\"No next routine found in high level from {startPC} to {endPC}\");\n        }\n      }\n    }\n\n    protected virtual NextRoutine LiftNextRoutine(NextRoutine lNextRoutine)\n    {\n      NextRoutine hNextRoutine;\n      nextRoutineMap.TryGetValue(lNextRoutine, out hNextRoutine);\n      return hNextRoutine;\n    }\n\n    protected virtual AtomicPath LiftAtomicPath(AtomicPath lPath)\n    {\n      AtomicPath hPath = null;\n      pathMap.TryGetValue(lPath, out hPath);\n      return hPath;\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    /// Includes and imports\n    ////////////////////////////////////////////////////////////////////////\n\n    private void AddInductiveInvariant(InductiveInvariantArmadaProofDecl d)\n    {\n      string invKey = d.InvariantName;\n      string invName, str;\n      var userInvariants = pgp.symbolsLow.GlobalInvariants;\n      var attrs = d.CanBeRevealed() ? \"{:opaque}\" : \"\";\n      if (d.Code != null) {\n        invName = $\"UserInv_{invKey}\";\n        str = $@\"\n          predicate {attrs} {invName}(s:LPlusState)\n          {{\n            var threads := s.s.threads;\n            var globals := s.s.mem.globals;\n            var ghosts := s.s.ghosts;\n            var tid_init := s.config.tid_init;\n            { d.Code }\n          }}\n        \";\n        pgp.AddPredicate(str, \"defs\");\n        if (d.CanBeRevealed()) {\n          pgp.AddOpaqueUserDef(invName);\n        }\n      }\n      else if (userInvariants.ContainsKey(invKey)) {\n        var inv = userInvariants[invKey];\n        invName = $\"UserInv_{invKey}\";\n        str = $@\"\n          predicate {attrs} {invName}(splus:LPlusState)\n          {{\n            L.{inv.TranslatedName}(splus.s)\n          }}\n        \";\n        pgp.AddPredicate(str, \"defs\");\n        if (d.CanBeRevealed()) {\n          pgp.AddOpaqueUserDef(invName);\n        }\n      }\n      else {\n        AH.PrintError(pgp.prog, d.tok, $\"No invariant named {invKey} found among the invariants\");\n        return;\n      }\n      var dependencies = new List<string>(d.Dependencies);\n      invariants.Add(new UserInvariantInfo(invKey, invName, dependencies, d.CanBeRevealed()));\n    }\n\n    private void ParseImports()\n    {\n      foreach (var topDecl in pgp.MainProof.Module.TopLevelDecls) {\n        if (topDecl is ImportFileArmadaProofDecl) {\n          var ifd = (ImportFileArmadaProofDecl)topDecl;\n          importedFiles.Add(ifd);\n        }\n        else if (topDecl is ImportModuleArmadaProofDecl) {\n          var imd = (ImportModuleArmadaProofDecl)topDecl;\n          importedModules.Add(imd);\n        }\n        else if (topDecl is InductiveInvariantArmadaProofDecl) {\n          var iid = (InductiveInvariantArmadaProofDecl)topDecl;\n          AddInductiveInvariant(iid);\n        }\n        else if (topDecl is ExtraMaterialArmadaProofDecl) {\n          var emapd = (ExtraMaterialArmadaProofDecl)topDecl;\n          pgp.AddExtraMaterial(emapd.Loc, emapd.Contents);\n        }\n        else if (topDecl is UseRegionsArmadaProofDecl) {\n          GenerateRegionInvariant();\n        }\n        else if (topDecl is UseAddressInvariantArmadaProofDecl) {\n          GenerateAddressableInvariant();\n        }\n        else if (topDecl is AuxiliaryArmadaProofDecl) {\n          var iad = (AuxiliaryArmadaProofDecl)topDecl;\n          if (iad.TypeDefinitionCode.Length > 0) {\n            var d = AH.ParseTopLevelDecl(pgp.prog, iad.TypeName, iad.TypeDefinitionCode);\n            if (d is DatatypeDecl) {\n              pgp.AddTopLevelDecl((DatatypeDecl)d, \"specs\");\n            }\n            else if (d is TypeSynonymDecl) {\n              pgp.AddTopLevelDecl((TypeSynonymDecl)d, \"specs\");\n            }\n            else {\n              AH.PrintError(pgp.prog, d.tok, \"Type definition code is neither a datatype declaration nor a type declaration\");\n              continue;\n            }\n          }\n          string str;\n          string auxInitName = $\"AuxInit_{iad.FieldName}\";\n          str = $@\"\n            function {auxInitName}(s:LState, config:Armada_Config) : {iad.TypeName}\n            {{\n              {iad.InitCode}\n            }}\n          \";\n          pgp.AddFunction(str, \"specs\");\n\n          string auxNextName = $\"AuxNext_{iad.FieldName}\";\n          str = $@\"\n            function {auxNextName}(s: LPlusState, s': LState, step: L.Armada_Step, tid: Armada_ThreadHandle) : {iad.TypeName}\n            {{\n              {iad.NextCode}\n            }}\n          \";\n          pgp.AddFunction(str, \"specs\");\n\n          var auxiliaryInfo = new AuxiliaryInfo(iad.FieldName, iad.TypeName, auxInitName, auxNextName);\n          auxiliaries.Add(auxiliaryInfo);\n        }\n      }\n    }\n\n    protected virtual void AddIncludesAndImports()\n    {\n      ParseImports();\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    /// Revelations\n    ////////////////////////////////////////////////////////////////////////\n\n    protected void GenerateRevelationLemmas()\n    {\n      GenerateRevelationLemmas(\"L\", pgp.symbolsLow);\n      GenerateRevelationLemmas(\"H\", pgp.symbolsHigh);\n    }\n\n    protected void GenerateRevelationLemmas(string moduleName, ArmadaSymbolTable symbols)\n    {\n      string str;\n\n      var pr = new ModuleStepPrinter(moduleName);\n\n      foreach (var nextRoutine in symbols.NextRoutines)\n      {\n        str = $@\"\n          lemma lemma_OpenStep_{moduleName}_{nextRoutine.NameSuffix}(\n            s: {moduleName}.Armada_TotalState,\n            step: {moduleName}.Armada_Step,\n            tid: Armada_ThreadHandle\n            )\n            requires step.Armada_Step_{nextRoutine.NameSuffix}?\n            ensures  {moduleName}.Armada_ValidStep(s, step, tid) <==>\n                       tid in s.threads && s.stop_reason.Armada_NotStopped? && {pr.ValidStepInvocation(nextRoutine)}\n            ensures  {moduleName}.Armada_ValidStep(s, step, tid) ==>\n                       {moduleName}.Armada_GetNextState(s, step, tid) == {pr.GetNextStateInvocation(nextRoutine)}\n          {{\n            reveal {moduleName}.Armada_ValidStepCases();\n            reveal {moduleName}.Armada_GetNextState();\n          }}\n        \";\n        pgp.AddLemma(str, \"revelations\");\n      }\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    /// Atomic specs\n    ////////////////////////////////////////////////////////////////////////\n\n    protected void GenerateAtomicSpecs(bool avoidFinalUnmappedStoppingStep = true,\n                                       HashSet<ArmadaPC> lExtraRecurrentPCs = null,\n                                       HashSet<ArmadaPC> hExtraRecurrentPCs = null)\n    {\n      GeneratePCEffectLemmas();\n\n      lAtomic = new AtomicSpec(pgp, pgp.symbolsLow, \"latomic\", \"LAtomic\", true, \"L\", \"LPlusState\",\n                               \"LPlus_GetSpecFunctions()\", \"GetLPlusSpec()\",\n                               \"LPlus_ValidStep\", \"LPlus_GetNextState\");\n      lAtomic.MakeSpec(lExtraRecurrentPCs);\n\n      GenerateLiftToAtomicLemma();\n\n      hAtomic = new AtomicSpec(pgp, pgp.symbolsHigh, \"hatomic\", \"HAtomic\", false, \"H\", \"HState\",\n                               \"H.Armada_GetSpecFunctions()\", \"GetHSpec()\", \"H.Armada_ValidStep\",\n                               \"H.Armada_GetNextState\");\n      hAtomic.MakeSpec(hExtraRecurrentPCs);\n\n      GenerateLiftFromAtomicLemma();\n\n      if (nextRoutineMap == null) {\n        pathMap = lAtomic.CreatePathMap(hAtomic);\n      }\n      else {\n        pathMap = lAtomic.CreatePathMap(hAtomic, nextRoutineMap, avoidFinalUnmappedStoppingStep);\n      }\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    /// LiftToAtomic\n    ////////////////////////////////////////////////////////////////////////\n\n    public void GenerateLiftToAtomicSimpleRequirementsLemma()\n    {\n      string str = @\"\n        lemma lemma_LiftToAtomicSimpleRequirements()\n          ensures var lasf := LPlus_GetSpecFunctions();\n                  var hasf := LAtomic_GetSpecFunctions();\n                  && LInitImpliesHInit(lasf, hasf)\n                  && StateOKsMatch(lasf, hasf)\n                  && NonyieldingPCsMatch(lasf, hasf)\n                  && ThreadPCsMatch(lasf, hasf)\n        {\n        }\n      \";\n      pgp.AddLemma(str, \"LiftToAtomic\");\n    }\n\n    public void GenerateTausLiftableLemma()\n    {\n      var stepPr = new LPlusStepPrinter();\n      stepPr.Step = \"lstep\";\n\n      var pathPr = new PathPrinter(lAtomic);\n      pathPr.State = \"s\";\n      pathPr.States = \"hstates\";\n      pathPr.Steps = \"hsteps\";\n      pathPr.Path = \"hpath\";\n\n      string str = $@\"\n        lemma lemma_TausLiftable()\n          ensures var lasf := LPlus_GetSpecFunctions();\n                  var hasf := LAtomic_GetSpecFunctions();\n                  TausLiftable(lasf, hasf)\n        {{\n          reveal_LAtomic_ValidPath();\n          reveal_LAtomic_GetStateAfterPath();\n          var lasf := LPlus_GetSpecFunctions();\n          var hasf := LAtomic_GetSpecFunctions();\n          forall s, s', lstep, tid {{:trigger TausLiftableConditions(lasf, s, s', lstep, tid)}}\n            | TausLiftableConditions(lasf, s, s', lstep, tid)\n            ensures exists hpath :: && hasf.path_valid(s, hpath, tid)\n                              && hasf.path_type(hpath).AtomicPathType_Tau? \n                              && s' == hasf.path_next(s, hpath, tid)\n          {{\n            { stepPr.GetOpenValidStepInvocation(pgp.symbolsLow.TauNextRoutine) }\n            var hpath := LAtomic_Path_Tau(LAtomic_PathSteps_Tau(lstep));\n            { pathPr.GetOpenPathInvocation(lAtomic.TauPath) }\n            ProofCustomizationGoesHere();\n            assert && hasf.path_valid(s, hpath, tid)\n                   && hasf.path_type(hpath).AtomicPathType_Tau? \n                   && s' == hasf.path_next(s, hpath, tid);\n          }}\n        }}\n      \";\n      pgp.AddLemma(str, \"LiftToAtomic\");\n    }\n\n    public string GenerateCompressStepSequenceBodyForPathPrefix(AtomicPathPrefix pathPrefix)\n    {\n      var pos = pathPrefix.NumNextRoutines - 1;\n      var nextRoutine = pathPrefix.LastNextRoutine;\n      string str = \"\";\n      var stepsRemaining = (pos == 0) ? \"steps\" : $\"steps[{pos}..]\";\n      str += $@\"\n          if steps[{pos}].Armada_Step_{nextRoutine.NameSuffix}? {{\n            var s{pos + 1} := asf.step_next(s{pos}, steps[{pos}], tid);\n            assert steps[{pos+1}..] == {stepsRemaining}[1..];\n            assert StepsStartNonyieldingNonrecurrent(asf, LAtomic_IsRecurrentPC, s{pos + 1}, s', steps[{pos + 1}..], tid);\n            assert |steps[{pos + 1}..]| == 0 <==> ThreadYieldingOrRecurrent(asf, LAtomic_IsRecurrentPC, s{pos + 1}, tid);\n            lemma_PCEffectOfStep_L_{nextRoutine.NameSuffix}(s{pos}.s, steps[{pos}], tid);\n      \";\n      if (pathPrefix.EndType is PCAtomicType.Nonyielding) {\n        str += $@\"\n            assert !ThreadYieldingOrRecurrent(asf, LAtomic_IsRecurrentPC, s{pos + 1}, tid);\n            assert steps[{pos+1}] == steps[{pos + 1}..][0];\n            lemma_PossibleStepsFromPC_L_{nextRoutine.endPC}(s{pos + 1}.s, steps[{pos + 1}], tid);\n        \";\n        foreach (var descendant in pathPrefix.Extensions)\n        {\n          str += GenerateCompressStepSequenceBodyForPathPrefix(descendant);\n        }\n        str += @\"\n             assert false;\n           }\n        \";\n      }\n      else {\n        var path = pathPrefix.PathVal;\n        var pr = new PathPrinter(lAtomic);\n        str += $@\"\n            assert ThreadYieldingOrRecurrent(asf, LAtomic_IsRecurrentPC, s{pos + 1}, tid);\n            assert s' == s{pos + 1};\n            path := LAtomic_Path_{path.Name}(LAtomic_PathSteps_{path.Name}(\n        \";\n        str += String.Join(\", \", Enumerable.Range(0, pos + 1).Select(i => $\"steps[{i}]\"));\n        str += $@\"));\n            { pr.GetOpenPathInvocation(path) }\n            return;\n          }}\n        \";\n      }\n      return str;\n    }\n\n    public void GenerateCompressStepSequenceIntoPathStartingAt(ArmadaPC startPC)\n    {\n      string str;\n\n      str = $@\"\n        lemma lemma_CompressStepSequenceIntoPathStartingAt_{startPC}(\n          asf: Armada_SpecFunctions<LPlusState, L.Armada_Step, L.Armada_PC>,\n          s: LPlusState,\n          s': LPlusState,\n          steps: seq<L.Armada_Step>,\n          tid: Armada_ThreadHandle\n          ) returns (\n          path: LAtomic_Path\n          )\n          requires asf == LPlus_GetSpecFunctions()\n          requires |steps| > 0\n          requires !steps[0].Armada_Step_Tau?\n          requires LPlus_ValidStep(s, steps[0], tid)\n          requires ThreadYieldingOrRecurrent(asf, LAtomic_IsRecurrentPC, s, tid)\n          requires ThreadYieldingOrRecurrent(asf, LAtomic_IsRecurrentPC, s', tid)\n          requires StepsStartNonyieldingNonrecurrent(asf, LAtomic_IsRecurrentPC, asf.step_next(s, steps[0], tid), s', steps[1..], tid)\n          requires s.s.threads[tid].pc.{startPC}?\n          ensures  LAtomic_ValidPath(s, path, tid)\n          ensures  s' == LAtomic_GetStateAfterPath(s, path, tid)\n          ensures  !LAtomic_GetPathType(path).AtomicPathType_Tau?\n          ensures  AtomicPathTypeMatchesPCTypes(LAtomic_GetSpecFunctions(), s, path, tid)\n        {{\n          var s0 := s;\n          lemma_PossibleStepsFromPC_L_{startPC}(s.s, steps[0], tid);\n      \";\n      foreach (var pathPrefix in lAtomic.RootPathPrefixesByPC(startPC))\n      {\n        str += GenerateCompressStepSequenceBodyForPathPrefix(pathPrefix);\n      }\n      str += @\"\n          assert false;\n        }}\n      \";\n      pgp.AddLemma(str, \"LiftToAtomic\");\n    }\n\n    public void GenerateCompressStepSequenceLemmas()\n    {\n      string str;\n\n      str = @\"\n        lemma lemma_CompressStepSequenceIntoPath(\n          asf: Armada_SpecFunctions<LPlusState, L.Armada_Step, L.Armada_PC>,\n          s: LPlusState,\n          s': LPlusState,\n          steps: seq<L.Armada_Step>,\n          tid: Armada_ThreadHandle\n          ) returns (\n          path: LAtomic_Path\n          )\n          requires asf == LPlus_GetSpecFunctions()\n          requires |steps| > 0\n          requires !steps[0].Armada_Step_Tau?\n          requires LPlus_ValidStep(s, steps[0], tid)\n          requires ThreadYieldingOrRecurrent(asf, LAtomic_IsRecurrentPC, s, tid)\n          requires ThreadYieldingOrRecurrent(asf, LAtomic_IsRecurrentPC, s', tid)\n          requires StepsStartNonyieldingNonrecurrent(asf, LAtomic_IsRecurrentPC, asf.step_next(s, steps[0], tid), s', steps[1..], tid)\n          ensures  LAtomic_ValidPath(s, path, tid)\n          ensures  s' == LAtomic_GetStateAfterPath(s, path, tid)\n          ensures  !LAtomic_GetPathType(path).AtomicPathType_Tau?\n          ensures  AtomicPathTypeMatchesPCTypes(LAtomic_GetSpecFunctions(), s, path, tid)\n        {\n          var pc := s.s.threads[tid].pc;\n          assert L.Armada_IsNonyieldingPC(pc) ==> LAtomic_IsRecurrentPC(pc);\n          match pc {\n      \";\n      foreach (var pc in lAtomic.AllPCs)\n      {\n        str += $\"    case {pc} =>\\n\";\n        if (pgp.symbolsLow.IsNonyieldingPC(pc) && !lAtomic.RecurrentPCs.Contains(pc)) {\n          str += \"     assert false;\\n\";\n        }\n        else {\n          GenerateCompressStepSequenceIntoPathStartingAt(pc);\n          str += $\"    path := lemma_CompressStepSequenceIntoPathStartingAt_{pc}(asf, s, s', steps, tid);\\n\";\n        }\n      }\n      str += \"}\\n}\\n\";\n      pgp.AddLemma(str, \"LiftToAtomic\");\n    }\n\n    public void GenerateSequencesCompressibleLemma()\n    {\n      string str = @\"\n        lemma lemma_SequencesCompressible()\n          ensures SequencesCompressible(LPlus_GetSpecFunctions(), LAtomic_GetSpecFunctions(), LAtomic_IsRecurrentPC)\n        {\n          var lasf := LPlus_GetSpecFunctions();\n          var hasf := LAtomic_GetSpecFunctions();\n          forall s, s', lsteps, tid {:trigger SequencesCompressibleConditions(lasf, LAtomic_IsRecurrentPC, s, s', lsteps, tid)}\n            | SequencesCompressibleConditions(lasf, LAtomic_IsRecurrentPC, s, s', lsteps, tid)\n            ensures exists hpath :: SequencesCompressibleConclusions(hasf, s, s', tid, hpath)\n          {\n            var hpath := lemma_CompressStepSequenceIntoPath(lasf, s, s', lsteps, tid);\n            assert SequencesCompressibleConclusions(hasf, s, s', tid, hpath);\n          }\n        }\n      \";\n      pgp.AddLemma(str, \"LiftToAtomic\");\n    }\n\n    public void GenerateLiftToAtomicLemma()\n    {\n      var liftFile = pgp.proofFiles.CreateAuxiliaryProofFile(\"LiftToAtomic\");\n      liftFile.IncludeAndImportGeneratedFile(\"specs\");\n      liftFile.IncludeAndImportGeneratedFile(\"defs\");\n      liftFile.IncludeAndImportGeneratedFile(\"pceffect\");\n      liftFile.IncludeAndImportGeneratedFile(\"revelations\");\n      liftFile.IncludeAndImportGeneratedFile(\"latomic\");\n      liftFile.AddIncludeImport(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/seqs.s.dfy\", \"util_collections_seqs_s\");\n      liftFile.AddIncludeImport(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/strategies/generic/LiftToAtomic.i.dfy\",\n                                \"LiftToAtomicModule\");\n      liftFile.AddImport(\"GenericArmadaAtomicModule\");\n      pgp.proofFiles.MainProof.IncludeAndImportGeneratedFile(\"LiftToAtomic\");\n\n      GenerateLiftToAtomicSimpleRequirementsLemma();\n      GenerateTausLiftableLemma();\n      GenerateCompressStepSequenceLemmas();\n      GenerateSequencesCompressibleLemma();\n\n      string str = $@\"\n        lemma lemma_LiftToAtomic() returns (refinement_relation:RefinementRelation<LPlusState, LPlusState>)\n          ensures SpecRefinesSpec(Armada_SpecFunctionsToSpec(LPlus_GetSpecFunctions()), AtomicSpec(LAtomic_GetSpecFunctions()),\n                                  refinement_relation)\n          ensures refinement_relation == iset s: LPlusState | true :: RefinementPair(s, s)\n        {{\n          lemma_LiftToAtomicSimpleRequirements();\n          lemma_TausLiftable();\n          lemma_SequencesCompressible();\n          refinement_relation := lemma_SpecRefinesAtomicSpec(LPlus_GetSpecFunctions(), LAtomic_GetSpecFunctions(), LAtomic_IsRecurrentPC);\n        }}\n      \";\n      pgp.AddLemma(str, \"LiftToAtomic\");\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    /// LiftFromAtomic\n    ////////////////////////////////////////////////////////////////////////\n\n    private void GenerateLiftTauPathFromAtomicLemma(AtomicPath atomicPath)\n    {\n      var pr = new PathPrinter(hAtomic);\n      var str = $@\"\n        lemma lemma_HAtomic_LiftFromAtomic_Tau(\n          lasf: AtomicSpecFunctions<H.Armada_TotalState, HAtomic_Path, H.Armada_PC>,\n          hasf: Armada_SpecFunctions<H.Armada_TotalState, H.Armada_Step, H.Armada_PC>,\n          s: H.Armada_TotalState,\n          s': H.Armada_TotalState,\n          path: HAtomic_Path,\n          tid: Armada_ThreadHandle\n          ) returns (\n          hsteps: seq<H.Armada_Step>\n          )\n          requires lasf == HAtomic_GetSpecFunctions()\n          requires hasf == H.Armada_GetSpecFunctions()\n          requires lasf.path_type(path).AtomicPathType_Tau?\n          requires AtomicLiftPathFromAtomicPossible(lasf, s, s', path, tid)\n          ensures  AtomicLiftPathFromAtomicSuccessful(lasf, hasf, s, s', path, tid, hsteps)\n        {{\n          { pr.GetOpenPathInvocation(hAtomic.TauPath) }\n          ProofCustomizationGoesHere();\n          hsteps := [steps.step0];\n          lemma_PCEffectOfStep_H_Tau(s, steps.step0, tid);\n        }}\n      \";\n      pgp.AddLemma(str, \"LiftFromAtomic\");\n    }\n\n    private void GenerateSpecificLiftPathFromAtomicLemma(AtomicPath atomicPath)\n    {\n      if (atomicPath.Tau) {\n        GenerateLiftTauPathFromAtomicLemma(atomicPath);\n        return;\n      }\n\n      var n = atomicPath.NumNextRoutines;\n      var pr = new PathPrinter(hAtomic);\n\n      var str = $@\"\n        lemma lemma_HAtomic_LiftFromAtomic_{atomicPath.Name}(\n          lasf: AtomicSpecFunctions<H.Armada_TotalState, HAtomic_Path, H.Armada_PC>,\n          hasf: Armada_SpecFunctions<H.Armada_TotalState, H.Armada_Step, H.Armada_PC>,\n          s: H.Armada_TotalState,\n          s': H.Armada_TotalState,\n          path: HAtomic_Path,\n          tid: Armada_ThreadHandle\n          ) returns (\n          hsteps: seq<H.Armada_Step>\n          )\n          requires lasf == HAtomic_GetSpecFunctions()\n          requires hasf == H.Armada_GetSpecFunctions()\n          requires path.HAtomic_Path_{atomicPath.Name}?\n          requires AtomicLiftPathFromAtomicPossible(lasf, s, s', path, tid)\n          ensures  AtomicLiftPathFromAtomicSuccessful(lasf, hasf, s, s', path, tid, hsteps)\n        {{\n          { pr.GetOpenValidPathInvocation(atomicPath) }\n      \";\n      str += \"hsteps := [\";\n      str += String.Join(\", \", Enumerable.Range(0, n).Select(i => $\"steps.step{i}\"));\n      str += \"];\\n\";\n      str += String.Concat(Enumerable.Range(0, n).Select(\n        i => $@\"\n          lemma_PCEffectOfStep_H_{atomicPath.NextRoutines[i].NameSuffix}(states.s{i}, steps.step{i}, tid);\n        \"\n      ));\n      str += String.Concat(Enumerable.Range(0, n).Select(\n        i => $@\"                                                                                                            \n          assert Armada_NextMultipleSteps(hasf, states.s{n - i}, s', hsteps[{n-i}..], tid);\n          assert hsteps[{n-i-1}..][1..] == hsteps[{n-i}..];\n        \"\n      ));\n      str += String.Concat(Enumerable.Range(1, n - 1).Select(\n        i => $@\"                                                                                                            \n          assert Armada_StepsStartNonyielding(hasf, states.s{n - i}, s', hsteps[{n-i}..], tid);\n        \"\n      ));\n      if (atomicPath.EndType == PCAtomicType.Yielding) {\n        str += $@\"\n          assert Armada_ThreadYielding(hasf, s', tid);\n        \";\n      }\n      str += $@\"\n          assert hsteps == hsteps[0..];\n          assert {atomicPath.OptionalNotForOK}hasf.state_ok(states.s{n});\n          assert Armada_NextMultipleSteps(hasf, s, s', hsteps, tid);\n        }}\n      \";\n      pgp.AddLemma(str, \"LiftFromAtomic\");\n    }\n\n    private void GenerateLiftPathFromAtomicLemma()\n    {\n      foreach (var atomicPath in hAtomic.AtomicPaths)\n      {\n        GenerateSpecificLiftPathFromAtomicLemma(atomicPath);\n      }\n\n      var str = $@\"\n        lemma lemma_LiftPathFromAtomic(\n          lasf: AtomicSpecFunctions<H.Armada_TotalState, HAtomic_Path, H.Armada_PC>,\n          hasf: Armada_SpecFunctions<H.Armada_TotalState, H.Armada_Step, H.Armada_PC>,\n          s: H.Armada_TotalState,\n          s': H.Armada_TotalState,\n          path: HAtomic_Path,\n          tid: Armada_ThreadHandle\n          ) returns (\n          hsteps: seq<H.Armada_Step>\n          )\n          requires lasf == HAtomic_GetSpecFunctions()\n          requires hasf == H.Armada_GetSpecFunctions()\n          requires AtomicLiftPathFromAtomicPossible(lasf, s, s', path, tid)\n          ensures  AtomicLiftPathFromAtomicSuccessful(lasf, hasf, s, s', path, tid, hsteps)\n       {{\n         match path {{\n      \";\n      str += String.Concat(hAtomic.AtomicPaths.Select(p => $@\"\n          case HAtomic_Path_{p.Name}(_) =>\n            hsteps := lemma_HAtomic_LiftFromAtomic_{p.Name}(lasf, hasf, s, s', path, tid);\n            return;\n      \"));\n      str += \"}\\n }\\n\";\n      pgp.AddLemma(str, \"LiftFromAtomic\");\n    }\n\n    public void GenerateLiftFromAtomicLemma()\n    {\n      var liftFile = pgp.proofFiles.CreateAuxiliaryProofFile(\"LiftFromAtomic\");\n      liftFile.IncludeAndImportGeneratedFile(\"specs\");\n      liftFile.IncludeAndImportGeneratedFile(\"defs\");\n      liftFile.IncludeAndImportGeneratedFile(\"pceffect\");\n      liftFile.IncludeAndImportGeneratedFile(\"revelations\");\n      liftFile.IncludeAndImportGeneratedFile(\"hatomic\");\n      liftFile.AddIncludeImport(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/seqs.s.dfy\", \"util_collections_seqs_s\");\n      liftFile.AddIncludeImport(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/strategies/generic/LiftFromAtomic.i.dfy\",\n                                \"LiftFromAtomicModule\");\n      liftFile.AddImport(\"GenericArmadaAtomicModule\");\n      pgp.proofFiles.MainProof.IncludeAndImportGeneratedFile(\"LiftFromAtomic\");\n\n      GenerateLiftPathFromAtomicLemma();\n\n      string str = $@\"\n        lemma lemma_LiftFromAtomic() returns (refinement_relation: RefinementRelation<H.Armada_TotalState, H.Armada_TotalState>)\n          ensures SpecRefinesSpec(AtomicSpec(HAtomic_GetSpecFunctions()), Armada_SpecFunctionsToSpec(H.Armada_GetSpecFunctions()),\n                                  refinement_relation)\n          ensures refinement_relation == iset s: H.Armada_TotalState | true :: RefinementPair(s, s)\n        {{\n          var lasf := HAtomic_GetSpecFunctions();\n          var hasf := H.Armada_GetSpecFunctions();\n          forall ls, ls', path, tid | AtomicLiftPathFromAtomicPossible(lasf, ls, ls', path, tid)\n            ensures exists hsteps :: AtomicLiftPathFromAtomicSuccessful(lasf, hasf, ls, ls', path, tid, hsteps)\n          {{\n            var hsteps := lemma_LiftPathFromAtomic(lasf, hasf, ls, ls', path, tid);\n          }}\n          refinement_relation := lemma_AtomicSpecRefinesSpec(lasf, hasf);\n        }}\n      \";\n      pgp.AddLemma(str, \"LiftFromAtomic\");\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    /// Utility functions\n    ////////////////////////////////////////////////////////////////////////\n\n    protected string GetConversionFunctionForTypeName_LH(string s)\n    {\n      var m = Regex.Match(s, @\"^Armada_(PC|Globals|StoreBufferLocation|StoreBufferEntry|Stack|StoreBuffer|Thread|Threads|TotalState|Config)$\");\n      if (m.Success) {\n        return $\"Abstract{m.Groups[1]}_LH\";\n      }\n\n      return null;\n    }\n\n    protected string GetConversionFunctionForTypeName_HL(string s)\n    {\n      var m = Regex.Match(s, @\"^Armada_(PC|Globals|StoreBufferLocation|StoreBufferEntry|Stack|StoreBuffer|Thread|Threads|TotalState|Config)$\");\n      if (m.Success) {\n        return $\"Abstract{m.Groups[1]}_HL\";\n      }\n\n      return null;\n    }\n\n    protected Type AddModuleNameToArmadaType(Type ty, string moduleName)\n    {\n      if (ty is UserDefinedType) {\n        var udt = (UserDefinedType)ty;\n        string conversionFn = GetConversionFunctionForTypeName_LH(udt.Name);\n        if (conversionFn != null) {\n          return new UserDefinedType(udt.tok, $\"{moduleName}.{udt.Name}\", udt.TypeArgs);\n        }\n      }\n      else if (ty is SeqType) {\n        var sty = (SeqType)ty;\n        return new SeqType(AddModuleNameToArmadaType(sty.Arg, moduleName));\n      }\n      else if (ty is SetType) {\n        var sty = (SetType)ty;\n        return new SetType(sty.Finite, AddModuleNameToArmadaType(sty.Arg, moduleName));\n      }\n\n      return ty;\n    }\n\n    protected string GetCalleeNameForCallStmt(Statement stmt)\n    {\n      var us = (UpdateStmt)stmt;\n      var rhs = us.Rhss[0];\n      var ex = (ExprRhs)rhs;\n      var suffix = (ApplySuffix)ex.Expr;\n      var suffixName = (NameSegment)suffix.Lhs;\n      return suffixName.Name;\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    /// State abstraction functions\n    ////////////////////////////////////////////////////////////////////////\n\n    protected virtual void GenerateConvertPC_LH()\n    {\n      var caseBodies = String.Concat(pcMap.Select(mapping => $\"case {mapping.Key.ToString()} => H.{mapping.Value}\\n\"));\n      var fn = $@\"\n        function ConvertPC_LH(pc: L.Armada_PC) : H.Armada_PC\n        {{\n          match pc\n            {caseBodies}\n        }}\n      \";\n      pgp.AddFunction(fn, \"convert\");\n    }\n\n    protected virtual void GenerateConvertStackVars_LH(string methodName)\n    {\n      var smst = pgp.symbolsLow.GetMethodSymbolTable(methodName);\n      var ps = smst.AllVariablesInOrder.Select(v => $\"vs.{v.FieldName}\");\n      var fn = $@\"\n        function ConvertStackVars_LH_{methodName}(vs: L.Armada_StackVars_{methodName}) : H.Armada_StackVars_{methodName}\n        {{\n          H.Armada_StackVars_{methodName}({AH.CombineStringsWithCommas(ps)})\n        }}\n      \";\n      pgp.AddFunction(fn, \"convert\");\n    }\n\n    protected virtual void GenerateConvertStackFrame_LH()\n    {\n      var methodNames = pgp.symbolsLow.MethodNames;\n      foreach (var methodName in methodNames) {\n        GenerateConvertStackVars_LH(methodName);\n      }\n      var caseBodies = String.Concat(methodNames.Select(methodName =>\n        $@\"case Armada_StackFrame_{methodName}(vs) => H.Armada_StackFrame_{methodName}(ConvertStackVars_LH_{methodName}(vs))\"\n      ));\n      var fn = $@\"\n        function ConvertStackFrame_LH(frame: L.Armada_StackFrame) : H.Armada_StackFrame\n        {{\n          match frame\n            {caseBodies}\n        }}\n      \";\n      pgp.AddFunction(fn, \"convert\");\n    }\n\n    protected virtual void GenerateConvertGlobals_LH()\n    {\n      var ps = new List<string>();\n      foreach (var varName in pgp.symbolsLow.Globals.VariableNames) {\n        var v = pgp.symbolsLow.Globals.Lookup(varName);\n        if (v is GlobalUnaddressableArmadaVariable) {\n          ps.Add($\"globals.{v.FieldName}\");\n        }\n      }\n      var fn = $@\"\n        function ConvertGlobals_LH(globals: L.Armada_Globals) : H.Armada_Globals\n        {{\n          H.Armada_Globals({AH.CombineStringsWithCommas(ps)})\n        }}\n      \";\n      pgp.AddFunction(fn, \"convert\");\n    }\n\n    protected virtual void GenerateConvertGhosts_LH()\n    {\n      var ps = new List<string>();\n      foreach (var varName in pgp.symbolsLow.Globals.VariableNames) {\n        var v = pgp.symbolsLow.Globals.Lookup(varName);\n        if (v is GlobalGhostArmadaVariable) {\n          ps.Add($\"ghosts.{v.FieldName}\");\n        }\n      }\n      var fn = $@\"\n        function ConvertGhosts_LH(ghosts: L.Armada_Ghosts) : H.Armada_Ghosts\n        {{\n          H.Armada_Ghosts({AH.CombineStringsWithCommas(ps)})\n        }}\n      \";\n      pgp.AddFunction(fn, \"convert\");\n    }\n\n    protected virtual void GenerateConvertAddrs_LH()\n    {\n      var ps = new List<string>();\n      foreach (var varName in pgp.symbolsLow.Globals.VariableNames) {\n        var v = pgp.symbolsLow.Globals.Lookup(varName);\n        if (v is GlobalAddressableArmadaVariable) {\n          ps.Add($\"addrs.{v.FieldName}\");\n        }\n      }\n      var fn = $@\"\n        function ConvertAddrs_LH(addrs: L.Armada_Addrs) : H.Armada_Addrs\n        {{\n          H.Armada_Addrs({AH.CombineStringsWithCommas(ps)})\n        }}\n      \";\n      pgp.AddFunction(fn, \"convert\");\n    }\n\n    protected virtual void GenerateConvertGlobalStaticVar_LH()\n    {\n      var caseBodies = \"case Armada_GlobalStaticVarNone => H.Armada_GlobalStaticVarNone\\n\";\n      foreach (var varName in pgp.symbolsLow.Globals.VariableNames) {\n        var gv = pgp.symbolsLow.Globals.Lookup(varName);\n        if (gv is GlobalUnaddressableArmadaVariable) {\n          caseBodies += $\"case Armada_GlobalStaticVar_{varName} => H.Armada_GlobalStaticVar_{varName}\\n\";\n        }\n      }\n      var fn = $@\"\n        function ConvertGlobalStaticVar_LH(v: L.Armada_GlobalStaticVar) : H.Armada_GlobalStaticVar\n        {{\n          match v\n            {caseBodies}\n        }}\n      \";\n      pgp.AddFunction(fn, \"convert\");\n    }\n\n    protected virtual void GenerateConvertSharedMemory_LH()\n    {\n      string str = @\"\n        function ConvertSharedMemory_LH(mem: L.Armada_SharedMemory) : H.Armada_SharedMemory\n        {\n          H.Armada_SharedMemory(mem.heap, ConvertGlobals_LH(mem.globals))\n        }\n      \";\n      pgp.AddFunction(str, \"convert\");\n    }\n\n    protected virtual void GenerateConvertStoreBufferLocation_LH()\n    {\n      string str = @\"\n        function ConvertStoreBufferLocation_LH(loc:L.Armada_StoreBufferLocation) : H.Armada_StoreBufferLocation\n        {\n          match loc\n            case Armada_StoreBufferLocation_Unaddressable(v, fields) =>\n              H.Armada_StoreBufferLocation_Unaddressable(ConvertGlobalStaticVar_LH(v), fields)\n            case Armada_StoreBufferLocation_Addressable(p) =>\n              H.Armada_StoreBufferLocation_Addressable(p)\n        }\n      \";\n      pgp.AddFunction(str, \"convert\");\n    }\n\n    protected virtual void GenerateConvertStoreBufferEntry_LH()\n    {\n      string str = @\"\n        function ConvertStoreBufferEntry_LH(entry:L.Armada_StoreBufferEntry) : H.Armada_StoreBufferEntry\n        {\n          H.Armada_StoreBufferEntry(ConvertStoreBufferLocation_LH(entry.loc), entry.value, ConvertPC_LH(entry.pc))\n        }\n      \";\n      pgp.AddFunction(str, \"convert\");\n    }\n\n    protected virtual void GenerateConvertStoreBuffer_LH()\n    {\n      string str = @\"\n        function ConvertStoreBuffer_LH(entries:seq<L.Armada_StoreBufferEntry>) : seq<H.Armada_StoreBufferEntry>\n        {\n          MapSeqToSeq(entries, ConvertStoreBufferEntry_LH)\n        }\n      \";\n      pgp.AddFunction(str, \"convert\");\n    }\n\n    protected virtual void GenerateConvertExtendedFrame_LH()\n    {\n      string str = @\"\n        function ConvertExtendedFrame_LH(eframe:L.Armada_ExtendedFrame) : H.Armada_ExtendedFrame\n        {\n          H.Armada_ExtendedFrame(ConvertPC_LH(eframe.return_pc), ConvertStackFrame_LH(eframe.frame), eframe.new_ptrs)\n        }\n      \";\n      pgp.AddFunction(str, \"convert\");\n    }\n\n    protected virtual void GenerateConvertStack_LH()\n    {\n      string str = @\"\n        function ConvertStack_LH(stack:seq<L.Armada_ExtendedFrame>) : seq<H.Armada_ExtendedFrame>\n        {\n          MapSeqToSeq(stack, ConvertExtendedFrame_LH)\n        }\n      \";\n      pgp.AddFunction(str, \"convert\");\n    }\n\n    protected virtual void GenerateConvertThread_LH()\n    {\n      string str = @\"\n        function ConvertThread_LH(t:L.Armada_Thread) : H.Armada_Thread\n        {\n          H.Armada_Thread(ConvertPC_LH(t.pc), ConvertStackFrame_LH(t.top), t.new_ptrs, ConvertStack_LH(t.stack),\n                          ConvertStoreBuffer_LH(t.storeBuffer))\n        }\n      \";\n      pgp.AddFunction(str, \"convert\");\n    }\n\n    protected virtual void GenerateConvertThreads_LH()\n    {\n      string str = @\"\n        function ConvertThreads_LH(threads:map<Armada_ThreadHandle, L.Armada_Thread>) : map<Armada_ThreadHandle, H.Armada_Thread>\n        {\n          MapMapToMap(threads, ConvertThread_LH)\n        }\n      \";\n      pgp.AddFunction(str, \"convert\");\n    }\n\n    protected virtual void GenerateConvertTotalState_LH()\n    {\n      string str = @\"\n        function ConvertTotalState_LH(s:L.Armada_TotalState) : H.Armada_TotalState\n        {\n          H.Armada_TotalState(s.stop_reason, ConvertThreads_LH(s.threads), ConvertSharedMemory_LH(s.mem), ConvertGhosts_LH(s.ghosts),\n                              ConvertAddrs_LH(s.addrs), s.joinable_tids)\n        }\n      \";\n      pgp.AddFunction(str, \"convert\");\n\n      str = @\"\n        function ConvertTotalState_LPlusH(s:LPlusState) : HState\n        {\n          ConvertTotalState_LH(s.s)\n        }\n      \";\n      pgp.AddFunction(str, \"convert\");\n    }\n\n    protected virtual void GenerateConvertConfig_LH()\n    {\n      string str = @\"\n        function ConvertConfig_LH(config:Armada_Config) : Armada_Config\n        {\n          config\n        }\n      \";\n      pgp.AddFunction(str, \"convert\");\n    }\n\n    protected virtual void GenerateStateAbstractionFunctions_LH()\n    {\n      GenerateConvertPC_LH();\n      GenerateConvertStackFrame_LH();\n      GenerateConvertGlobals_LH();\n      GenerateConvertGhosts_LH();\n      GenerateConvertAddrs_LH();\n      GenerateConvertGlobalStaticVar_LH();\n      GenerateConvertSharedMemory_LH();\n      GenerateConvertStoreBufferLocation_LH();\n      GenerateConvertStoreBufferEntry_LH();\n      GenerateConvertStoreBuffer_LH();\n      GenerateConvertExtendedFrame_LH();\n      GenerateConvertStack_LH();\n      GenerateConvertThread_LH();\n      GenerateConvertThreads_LH();\n      GenerateConvertTotalState_LH();\n      GenerateConvertConfig_LH();\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    /// Step abstraction functions\n    ////////////////////////////////////////////////////////////////////////\n\n    protected virtual string GetStepCaseForSuppressedNextRoutine_LH(NextRoutine nextRoutine)\n    {\n      string nextRoutineName = nextRoutine.NameSuffix;\n\n      // This is the case where the next routine doesn't have a corresponding next routine in the high layer,\n      // e.g., because it's an assignment to a hidden variable.  In this case, just arbitrarily map it to\n      // something we know to exist, namely H.Armada_Step_Tau.\n\n      var bvs = nextRoutine.HasFormals ? \"_\" : \"\";\n      return $\"case Armada_Step_{nextRoutine.NameSuffix}({bvs}) => H.Armada_Step_Tau\\n\";\n    }\n\n    protected virtual string GetStepCaseForNormalNextRoutine_LH(NextRoutine nextRoutine)\n    {\n      string nextRoutineName = nextRoutine.NameSuffix;\n      var hNextRoutine = LiftNextRoutine(nextRoutine);\n      string hname = (hNextRoutine != null) ? hNextRoutine.NameSuffix : \"Tau\";\n\n      var bvs = nextRoutine.HasFormals ? \"params\" : \"\";\n\n      string caseBody;\n      if (hNextRoutine == null) {\n        caseBody = \"H.Armada_Step_Tau\";\n      }\n      else if (hNextRoutine.HasFormals) {\n        var ps = nextRoutine.Formals.Select(f => $\"params.{f.LocalVarName}\");\n        caseBody = $\"H.Armada_Step_{hname}(H.Armada_StepParams_{hname}({AH.CombineStringsWithCommas(ps)}))\";\n      }\n      else {\n        caseBody = $\"H.Armada_Step_{hname}\";\n      }\n\n      return $\"case Armada_Step_{nextRoutineName}({bvs}) => {caseBody}\\n\";\n    }\n\n    protected virtual string GetStepCaseForNextRoutine_LH(NextRoutine nextRoutine)\n    {\n      return GetStepCaseForNormalNextRoutine_LH(nextRoutine);\n    }\n\n    protected virtual void GenerateConvertStep_LH()\n    {\n      var caseBodies = String.Concat(pgp.symbolsLow.NextRoutines.Select(nextRoutine => GetStepCaseForNextRoutine_LH(nextRoutine)));\n      var fn = $@\"\n        function ConvertStep_LH(step: L.Armada_Step) : H.Armada_Step\n        {{\n          match step\n            {caseBodies}\n        }}\n      \";\n      pgp.AddFunction(fn, \"convert\");\n    }\n\n    protected virtual void GenerateConvertAtomicPathStateDependent_LH()\n    {\n      string str = @\"\n        function ConvertAtomicPath_LH(ls: LPlusState, lpath: LAtomic_Path, tid: Armada_ThreadHandle) : HAtomic_Path\n          requires LAtomic_ValidPath(ls, lpath, tid)\n        {\n          reveal LAtomic_ValidPath();\n          reveal LAtomic_GetStateAfterPath();\n          match lpath\n      \";\n\n      var pr = new PathPrinter(lAtomic);\n\n      foreach (var lpath in lAtomic.AtomicPaths)\n      {\n        if (pathMap.ContainsKey(lpath)) {\n          var hpath = pathMap[lpath];\n          str += $@\"\n            case LAtomic_Path_{lpath.Name}(steps) =>\n              var states := LAtomic_GetPathStates_{lpath.Name}(ls, tid, steps);\n          \";\n          str += $\"HAtomic_Path_{hpath.Name}(HAtomic_PathSteps_{hpath.Name}(\";\n          str += String.Join(\", \", Enumerable.Range(0, lpath.NextRoutines.Count)\n                                             .Where(i => nextRoutineMap.ContainsKey(lpath.NextRoutines[i]))\n                                             .Select(i => $\"ConvertStep_LH(states.s{i}, steps.step{i}, tid)\"));\n          str += \"))\\n\";\n        }\n        else {\n          str += $\"case LAtomic_Path_{lpath.Name}(_) => HAtomic_Path_Tau(HAtomic_PathSteps_Tau(H.Armada_Step_Tau()))\\n\";\n        }\n      }\n      str += \"}\";\n      pgp.AddFunction(str, \"convert\");\n    }\n\n    protected virtual void GenerateConvertAtomicPath_LH()\n    {\n      if (stateDependentConvertStep) {\n        GenerateConvertAtomicPathStateDependent_LH();\n        return;\n      }\n\n      string str = @\"\n        function ConvertAtomicPath_LH(lpath: LAtomic_Path) : HAtomic_Path\n        {\n          match lpath\n      \";\n      foreach (var lpath in lAtomic.AtomicPaths)\n      {\n        if (pathMap.ContainsKey(lpath) && pathMap[lpath] != null) {\n          var hpath = pathMap[lpath];\n          str += $\"case LAtomic_Path_{lpath.Name}(steps) => HAtomic_Path_{hpath.Name}(HAtomic_PathSteps_{hpath.Name}(\";\n          str += String.Join(\", \", Enumerable.Range(0, lpath.NextRoutines.Count)\n                                             .Where(i => nextRoutineMap.ContainsKey(lpath.NextRoutines[i]))\n                                             .Select(i => $\"ConvertStep_LH(steps.step{i})\"));\n          str += \"))\\n\";\n        }\n        else {\n          str += $\"case LAtomic_Path_{lpath.Name}(_) => HAtomic_Path_Tau(HAtomic_PathSteps_Tau(H.Armada_Step_Tau()))\\n\";\n        }\n      }\n      str += \"}\";\n      pgp.AddFunction(str, \"convert\");\n    }\n\n    protected virtual void GenerateConvertAtomicTraceEntry_LH()\n    {\n      string str;\n      if (stateDependentConvertStep) {\n        str = @\"\n          function ConvertAtomicTraceEntry_LH(ls: LPlusState, lentry: AtomicTraceEntry<LAtomic_Path>): AtomicTraceEntry<HAtomic_Path>\n            requires AtomicValidStep(LAtomic_GetSpecFunctions(), ls, lentry)\n          {\n            GenericAtomicLiftTraceEntryStateDependent(LAtomic_GetSpecFunctions(), ls, lentry, ConvertAtomicPath_LH)\n          }\n        \";\n        pgp.AddFunction(str, \"convert\");\n      }\n      else {\n        str = @\"\n          function ConvertAtomicTraceEntry_LH(lentry:AtomicTraceEntry<LAtomic_Path>) : AtomicTraceEntry<HAtomic_Path>\n          {\n            GenericAtomicLiftTraceEntry(lentry, ConvertAtomicPath_LH)\n          }\n        \";\n        pgp.AddFunction(str, \"convert\");\n      }\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    /// State refinement functions\n    ////////////////////////////////////////////////////////////////////////\n\n    protected virtual void GenerateConvertPC_HL(Dictionary<ArmadaPC, ArmadaPC> reversePCMap)\n    {\n      var caseBodies = String.Concat(reversePCMap.Select(mapping => $\"case {mapping.Key} => L.{mapping.Value}\\n\"));\n      var fn = $@\"\n        function ConvertPC_HL(pc: H.Armada_PC) : L.Armada_PC\n        {{\n          match pc\n            {caseBodies}\n        }}\n      \";\n      pgp.AddFunction(fn, \"convert\");\n    }\n\n    protected virtual void GenerateConvertStackVars_HL(string methodName)\n    {\n      var smst = pgp.symbolsHigh.GetMethodSymbolTable(methodName);\n      var ps = smst.AllVariablesInOrder.Select(v => $\"vs.{v.FieldName}\");\n      var fn = $@\"\n        function ConvertStackVars_HL_{methodName}(vs: H.Armada_StackVars_{methodName}) : L.Armada_StackVars_{methodName}\n        {{\n          L.Armada_StackVars_{methodName}({AH.CombineStringsWithCommas(ps)})\n        }}\n      \";\n      pgp.AddFunction(fn, \"convert\");\n    }\n\n    protected virtual void GenerateConvertStackFrame_HL()\n    {\n      var caseBodies = \"\";\n      foreach (var methodName in pgp.symbolsHigh.MethodNames) {\n        GenerateConvertStackVars_HL(methodName);\n        caseBodies += $\"case Armada_StackFrame_{methodName}(vs) => L.Armada_StackFrame_{methodName}(ConvertStackVars_HL_{methodName}(vs))\\n\";\n      }\n\n      var fn = $@\"\n        function ConvertStackFrame_HL(frame: H.Armada_StackFrame) : L.Armada_StackFrame\n        {{\n          match frame\n            {caseBodies}\n        }}\n      \";\n      pgp.AddFunction(fn, \"convert\");\n    }\n\n    protected virtual void GenerateConvertGlobals_HL()\n    {\n      var g = pgp.symbolsHigh.Globals;\n      var ps = pgp.symbolsHigh.Globals.VariableNames.Select(varName => $\"globals.{g.Lookup(varName).FieldName}\");\n      var fn = $@\"\n        function ConvertGlobals_HL(globals: H.Armada_Globals) : L.Armada_Globals\n        {{\n          L.Armada_Globals({AH.CombineStringsWithCommas(ps)})\n        }}\n      \";\n      pgp.AddFunction(fn, \"convert\");\n    }\n\n    protected virtual void GenerateConvertGhosts_HL()\n    {\n      var ps = new List<string>();\n      foreach (var varName in pgp.symbolsHigh.Globals.VariableNames) {\n        var v = pgp.symbolsHigh.Globals.Lookup(varName);\n        if (v is GlobalGhostArmadaVariable) {\n          ps.Add($\"ghosts.{v.FieldName}\");\n        }\n      }\n      var fn = $@\"\n        function ConvertGhosts_HL(ghosts: H.Armada_Ghosts) : L.Armada_Ghosts\n        {{\n          L.Armada_Ghosts({AH.CombineStringsWithCommas(ps)})\n        }}\n      \";\n      pgp.AddFunction(fn, \"convert\");\n    }\n\n    protected virtual void GenerateConvertAddrs_HL()\n    {\n      var ps = new List<string>();\n      foreach (var varName in pgp.symbolsHigh.Globals.VariableNames) {\n        var v = pgp.symbolsHigh.Globals.Lookup(varName);\n        if (v is GlobalAddressableArmadaVariable) {\n          ps.Add($\"addrs.{v.FieldName}\");\n        }\n      }\n      var fn = $@\"\n        function ConvertAddrs_HL(addrs: H.Armada_Addrs) : L.Armada_Addrs\n        {{\n          L.Armada_Addrs({AH.CombineStringsWithCommas(ps)})\n        }}\n      \";\n      pgp.AddFunction(fn, \"convert\");\n    }\n\n    protected virtual void GenerateConvertGlobalStaticVar_HL()\n    {\n      var caseBodies = $\"case Armada_GlobalStaticVarNone => L.Armada_GlobalStaticVarNone\\n\";\n      foreach (var varName in pgp.symbolsHigh.Globals.VariableNames) {\n        var gv = pgp.symbolsHigh.Globals.Lookup(varName);\n        if (gv is UnaddressableArmadaVariable && !gv.NoTSO()) {\n          caseBodies += $\"case Armada_GlobalStaticVar_{varName} => L.Armada_GlobalStaticVar_{varName}\\n\";\n        }\n      }\n      var fn = $@\"\n        function ConvertGlobalStaticVar_HL(v: H.Armada_GlobalStaticVar) : L.Armada_GlobalStaticVar\n        {{\n          match v\n            {caseBodies}\n        }}\n      \";\n      pgp.AddFunction(fn, \"convert\");\n    }\n\n    protected virtual void GenerateConvertSharedMemory_HL()\n    {\n      string str = @\"\n        function ConvertSharedMemory_HL(mem: H.Armada_SharedMemory) : L.Armada_SharedMemory\n        {\n          L.Armada_SharedMemory(mem.heap, ConvertGlobals_HL(mem.globals))\n        }\n      \";\n      pgp.AddFunction(str, \"convert\");\n    }\n\n    protected virtual void GenerateConvertStoreBufferLocation_HL()\n    {\n      string str = @\"\n        function ConvertStoreBufferLocation_HL(loc:H.Armada_StoreBufferLocation) : L.Armada_StoreBufferLocation\n        {\n          match loc\n            case Armada_StoreBufferLocation_Unaddressable(v, fields) =>\n              L.Armada_StoreBufferLocation_Unaddressable(ConvertGlobalStaticVar_HL(v), fields)\n            case Armada_StoreBufferLocation_Addressable(p) =>\n              L.Armada_StoreBufferLocation_Addressable(p)\n        }\n      \";\n      pgp.AddFunction(str, \"convert\");\n    }\n\n    protected virtual void GenerateConvertStoreBufferEntry_HL()\n    {\n      string str = @\"\n        function ConvertStoreBufferEntry_HL(entry:H.Armada_StoreBufferEntry) : L.Armada_StoreBufferEntry\n        {\n          L.Armada_StoreBufferEntry(ConvertStoreBufferLocation_HL(entry.loc), entry.value, ConvertPC_HL(entry.pc))\n        }\n      \";\n      pgp.AddFunction(str, \"convert\");\n    }\n\n    protected virtual void GenerateConvertStoreBuffer_HL()\n    {\n      string str = @\"\n        function ConvertStoreBuffer_HL(entries:seq<H.Armada_StoreBufferEntry>) : seq<L.Armada_StoreBufferEntry>\n        {\n          MapSeqToSeq(entries, ConvertStoreBufferEntry_HL)\n        }\n      \";\n      pgp.AddFunction(str, \"convert\");\n    }\n\n    protected virtual void GenerateConvertExtendedFrame_HL()\n    {\n      string str = @\"\n        function ConvertExtendedFrame_HL(eframe:H.Armada_ExtendedFrame) : L.Armada_ExtendedFrame\n        {\n          L.Armada_ExtendedFrame(ConvertPC_HL(eframe.return_pc), ConvertStackFrame_HL(eframe.frame), eframe.new_ptrs)\n        }\n      \";\n      pgp.AddFunction(str, \"convert\");\n    }\n\n    protected virtual void GenerateConvertStack_HL()\n    {\n      string str = @\"\n        function ConvertStack_HL(stack:seq<H.Armada_ExtendedFrame>) : seq<L.Armada_ExtendedFrame>\n        {\n          MapSeqToSeq(stack, ConvertExtendedFrame_HL)\n        }\n      \";\n      pgp.AddFunction(str, \"convert\");\n    }\n\n    protected virtual void GenerateConvertThread_HL()\n    {\n      string str = @\"\n        function ConvertThread_HL(t:H.Armada_Thread) : L.Armada_Thread\n        {\n          L.Armada_Thread(ConvertPC_HL(t.pc), ConvertStackFrame_HL(t.top), t.new_ptrs, ConvertStack_HL(t.stack),\n                          ConvertStoreBuffer_HL(t.storeBuffer))\n        }\n      \";\n      pgp.AddFunction(str, \"convert\");\n    }\n\n    protected virtual void GenerateConvertThreads_HL()\n    {\n      string str = @\"\n        function ConvertThreads_HL(threads:map<Armada_ThreadHandle, H.Armada_Thread>) : map<Armada_ThreadHandle, L.Armada_Thread>\n        {\n          MapMapToMap(threads, ConvertThread_HL)\n        }\n      \";\n      pgp.AddFunction(str, \"convert\");\n    }\n\n    protected virtual void GenerateConvertTotalState_HL()\n    {\n      string str = @\"\n        function ConvertTotalState_HL(s:H.Armada_TotalState) : L.Armada_TotalState\n        {\n          L.Armada_TotalState(s.stop_reason, ConvertThreads_HL(s.threads), ConvertSharedMemory_HL(s.mem), ConvertGhosts_HL(s.ghosts),\n                              ConvertAddrs_HL(s.addrs), s.joinable_tids)\n        }\n      \";\n      pgp.AddFunction(str, \"convert\");\n    }\n\n    protected virtual void GenerateConvertConfig_HL()\n    {\n      string str = @\"\n        function ConvertConfig_HL(config:Armada_Config) : Armada_Config\n        {\n          config\n        }\n      \";\n      pgp.AddFunction(str, \"convert\");\n    }\n\n    protected virtual void GenerateStateAbstractionFunctions_HL(Dictionary<ArmadaPC, ArmadaPC> reversePCMap)\n    {\n      GenerateConvertPC_HL(reversePCMap);\n      GenerateConvertStackFrame_HL();\n      GenerateConvertGlobals_HL();\n      GenerateConvertGhosts_HL();\n      GenerateConvertAddrs_HL();\n      GenerateConvertGlobalStaticVar_HL();\n      GenerateConvertSharedMemory_HL();\n      GenerateConvertStoreBufferLocation_HL();\n      GenerateConvertStoreBufferEntry_HL();\n      GenerateConvertStoreBuffer_HL();\n      GenerateConvertExtendedFrame_HL();\n      GenerateConvertStack_HL();\n      GenerateConvertThread_HL();\n      GenerateConvertThreads_HL();\n      GenerateConvertTotalState_HL();\n      GenerateConvertConfig_HL();\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    /// Proof header\n    ////////////////////////////////////////////////////////////////////////\n\n    public void AddCommonHeaderElements(ProofFile proof)\n    {\n      proof.AddInclude(pgp.mLow.Name + \".dfy\");\n      proof.AddInclude(pgp.mHigh.Name + \".dfy\");\n      proof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/strategies/refinement/AnnotatedBehavior.i.dfy\");\n      if (pgp.symbolsLow.StructsModuleName != null) {\n        proof.AddInclude($\"{pgp.symbolsLow.StructsModuleName}.dfy\");\n      }\n\n      if (proof.IncludeImportedFiles) {\n        foreach (var importedFile in importedFiles) {\n          proof.AddInclude(importedFile);\n        }\n      }\n\n      proof.AddImport(pgp.mLow.Name, \"L\");\n      proof.AddImport(pgp.mHigh.Name, \"H\");\n      proof.AddImport(\"AnnotatedBehaviorModule\");\n      if (pgp.symbolsLow.StructsModuleName != null) {\n        proof.AddImport(pgp.symbolsLow.StructsModuleName);\n      }\n\n      if (proof.IncludeImportedFiles) {\n        foreach (var importedModule in importedModules) {\n          proof.AddImport(importedModule);\n        }\n      }\n    }\n\n    protected void GenerateProofHeader()\n    {\n      GenerateSpecsFile();\n      GenerateRevelationLemmas();\n      pgp.proofFiles.AssociateProofGenerator(this);\n    }\n\n    protected void GenerateSpecsFile()\n    {\n      pgp.AddImport(\"util_collections_seqs_s\", null, \"specs\");\n\n      pgp.AddTypeSynonym(\"type LState = L.Armada_TotalState\", \"specs\");\n      pgp.AddTypeSynonym(\"type HState = H.Armada_TotalState\", \"specs\");\n      pgp.AddTypeSynonym(\"type LSpec = AnnotatedBehaviorSpec<LState, Armada_Multistep<L.Armada_Step>>\", \"specs\");\n      pgp.AddTypeSynonym(\"type HSpec = AnnotatedBehaviorSpec<HState, Armada_Multistep<H.Armada_Step>>\", \"specs\");\n      pgp.AddTypeSynonym(\"type LPlusSpec = AnnotatedBehaviorSpec<LPlusState, Armada_Multistep<L.Armada_Step>>\", \"specs\");\n\n      string str;\n\n      str = @\"\n        function GetLSpec() : LSpec\n        {\n          SpecFunctionsToAnnotatedSpec(L.Armada_GetSpecFunctions())\n        }\n      \";\n      pgp.AddFunction(str, \"specs\");\n\n      str = @\"\n        function GetHSpec() : HSpec\n        {\n          SpecFunctionsToAnnotatedSpec(H.Armada_GetSpecFunctions())\n        }\n      \";\n      pgp.AddFunction(str, \"specs\");\n\n      str = @\"\n        function GetLPlusSpec() : LPlusSpec\n        {\n          SpecFunctionsToAnnotatedSpec(LPlus_GetSpecFunctions())\n        }\n      \";\n      pgp.AddFunction(str, \"specs\");\n\n      str = $@\"\n        predicate LHStateRefinement(ls:LState, hs:HState)\n        {{\n          {pgp.symbolsLow.RefinementConstraint}\n        }}\n      \";\n      pgp.AddPredicate(str, \"specs\");\n\n      str = @\"\n        function GetLHRefinementRelation() : RefinementRelation<LState, HState>\n        {\n          iset p:RefinementPair<LState, HState> | LHStateRefinement(p.low, p.high)\n        }\n      \";\n      pgp.AddFunction(str, \"specs\");\n\n      var auxiliaryParams = String.Concat(auxiliaries.Select(aux => $\", {aux.FieldName}: {aux.TypeName}\"));\n      pgp.AddDatatype($\"datatype LPlusState = LPlusState(s: LState, config: Armada_Config{auxiliaryParams})\", \"specs\");\n\n      str = @\"\n        predicate LPlusHStateRefinement(lplus:LPlusState, hs:HState)\n        {\n          LHStateRefinement(lplus.s, hs)\n        }\n      \";\n      pgp.AddPredicate(str, \"specs\");\n\n      str = @\"\n        function GetLPlusHRefinementRelation() : RefinementRelation<LPlusState, HState>\n        {\n          iset p:RefinementPair<LPlusState, HState> | LPlusHStateRefinement(p.low, p.high)\n        }\n      \";\n      pgp.AddFunction(str, \"specs\");\n\n      str = @\"\n        predicate LPlus_Init(splus:LPlusState)\n        {\n          && L.Armada_InitConfig(splus.s, splus.config)\n      \";\n      foreach (var aux in auxiliaries) {\n        str += $\"  && splus.{aux.FieldName} == {aux.InitName}(splus.s, splus.config)\\n\";\n      }\n      str += \"}\\n\";\n      pgp.AddPredicate(str, \"specs\");\n\n      str = @\"\n        predicate LPlus_ValidStep(s: LPlusState, step:L.Armada_Step, tid: Armada_ThreadHandle)\n        {\n          L.Armada_ValidStep(s.s, step, tid)\n        }\n      \";\n      pgp.AddPredicate(str, \"specs\");\n\n      str = @\"\n        function MakeLPlusInitialState(s:LState) : (splus:LPlusState)\n          requires s in L.Armada_Spec().init\n          ensures  splus.s == s\n          ensures  LPlus_Init(splus)\n        {\n          var config :| L.Armada_InitConfig(s, config);\n      \";\n      foreach (var aux in auxiliaries) {\n        str += $\"    var field_{aux.FieldName} := {aux.InitName}(s, config);\\n\";\n      }\n      str += \"    LPlusState(s, config\";\n      foreach (var aux in auxiliaries) {\n        str += $\", field_{aux.FieldName}\";\n      }\n      str += \")\\n\";\n      str += \"}\\n\";\n      pgp.AddFunction(str, \"specs\");\n\n      str = @\"\n        function LPlus_GetNextState(splus: LPlusState, step: L.Armada_Step, tid: Armada_ThreadHandle) : (splus': LPlusState)\n        {\n          var s' := L.Armada_GetNextState(splus.s, step, tid);\n      \";\n      foreach (var aux in auxiliaries) {\n        str += $\"  var field_{aux.FieldName} := {aux.NextName}(splus, s', step, tid);\\n\";\n      }\n      str += \"LPlusState(s', splus.config\";\n      foreach (var aux in auxiliaries) {\n        str += $\", field_{aux.FieldName}\";\n      }\n      str += \")\\n\";\n      str += \"}\\n\";\n      pgp.AddFunction(str, \"specs\");\n\n      str = @\"\n        function LPlus_GetSpecFunctions() : Armada_SpecFunctions<LPlusState, L.Armada_Step, L.Armada_PC>\n        {\n          Armada_SpecFunctions(LPlus_Init, LPlus_ValidStep, LPlus_GetNextState,\n                              (step: L.Armada_Step) => step.Armada_Step_Tau?,\n                              (s: LPlusState) => s.s.stop_reason.Armada_NotStopped?,\n                              (s: LPlusState, tid: Armada_ThreadHandle) =>\n                                if tid in s.s.threads then Some(s.s.threads[tid].pc) else None,\n                              L.Armada_IsNonyieldingPC)\n        }\n      \";\n      pgp.AddFunction(str, \"specs\");\n\n      str = @\"\n        function ConvertTotalState_LPlusL(lps: LPlusState) : LState\n        {\n          lps.s\n        }\n      \";\n      pgp.AddFunction(str, \"PlusLemmas\");\n\n      str = @\"\n        lemma lemma_EstablishRequirementsForLSpecRefinesLPlusSpec()\n          ensures RequirementsForSpecRefinesPlusSpec(L.Armada_GetSpecFunctions(), LPlus_GetSpecFunctions(), ConvertTotalState_LPlusL)\n        {\n          var lasf := L.Armada_GetSpecFunctions();\n          var hasf := LPlus_GetSpecFunctions();\n          var convert := ConvertTotalState_LPlusL;\n          forall ls | lasf.init(ls)\n            ensures exists hs :: hasf.init(hs) && ls == convert(hs)\n          {\n            var hs := MakeLPlusInitialState(ls);\n            assert hasf.init(hs) && ls == convert(hs);\n          }\n        }\n      \";\n      pgp.AddLemma(str, \"PlusLemmas\");\n\n      str = @\"\n        lemma lemma_LSpecRefinesLPlusSpec() returns (refinement_relation:RefinementRelation<LState, LPlusState>)\n          ensures SpecRefinesSpec(Armada_SpecFunctionsToSpec(L.Armada_GetSpecFunctions()),\n                                  Armada_SpecFunctionsToSpec(LPlus_GetSpecFunctions()),\n                                  refinement_relation)\n          ensures  refinement_relation == iset ls: LState, lps: LPlusState | ls == lps.s :: RefinementPair(ls, lps)\n        {\n          lemma_EstablishRequirementsForLSpecRefinesLPlusSpec();\n          refinement_relation :=\n            lemma_SpecRefinesPlusSpec(L.Armada_GetSpecFunctions(), LPlus_GetSpecFunctions(), ConvertTotalState_LPlusL);\n        }\n      \";\n      pgp.AddLemma(str, \"PlusLemmas\");\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    /// Lemmas about region invariant\n    ////////////////////////////////////////////////////////////////////////\n\n    protected virtual List<string> GenerateAddressableInvariant_Global()\n    {\n      pgp.AuxiliaryProof(\"specs\").AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/maps.i.dfy\");\n      pgp.AuxiliaryProof(\"specs\").AddImport(\"util_collections_maps_i\");\n\n      var abstractAddresses = new List<string>();\n      var preds = new List<string>();\n      foreach (var globalVarName in pgp.symbolsLow.Globals.VariableNames) {\n        var globalVar = pgp.symbolsLow.Globals.Lookup(globalVarName);\n        if (globalVar is GlobalAddressableArmadaVariable) {\n          string globalAddress = $\"s.s.addrs.{globalVarName}\";\n          preds.Add(AH.GetInvocationOfValidPointer(\"s.s.mem.heap\", $\"s.s.addrs.{globalVarName}\", globalVar.ty));\n          var descendants = AH.GetInvocationOfDescendants(\"s.s.mem.heap\", $\"s.s.addrs.{globalVarName}\", globalVar.ty);\n          preds.Add($@\"\n            forall p {{:trigger Armada_TriggerPointer(p)}} :: Armada_TriggerPointer(p) in {descendants} ==>\n              p in s.addr_map && s.addr_map[p] == GlobalAbstractAddress_{globalVarName}\n          \");\n          abstractAddresses.Add($\"GlobalAbstractAddress_{globalVarName}\");\n        }\n      }\n\n      var str = $@\"\n        predicate AddressableInvariant_Globals(s: LPlusState)\n        {{\n          {AH.CombineStringsWithAnd(preds)}\n        }}\n      \";\n      pgp.AddPredicate(str, \"defs\");\n      return abstractAddresses;\n    }\n\n    protected virtual List<string> GenerateAddressableInvariant_StackFrame(string methodName)\n    {\n      var methodSymbols = pgp.symbolsLow.GetMethodSymbolTable(methodName);\n      var abstractAddresses = new List<string>();\n      var preds = new List<string>();\n      foreach (var localVar in methodSymbols.AllVariablesInOrder.Where(v => v is MethodStackFrameAddressableLocalArmadaVariable)) {\n        string varStackFrameFieldName = methodSymbols.GetVariableStackFrameFieldName(localVar.name);\n        preds.Add(AH.GetInvocationOfValidPointer(\"heap\", $\"frame_vars.{varStackFrameFieldName}\", localVar.ty));\n        var descendants = AH.GetInvocationOfDescendants(\"heap\", $\"frame_vars.{varStackFrameFieldName}\", localVar.ty);\n        preds.Add($@\"\n          forall p {{:trigger Armada_TriggerPointer(p)}} :: Armada_TriggerPointer(p) in ({descendants}) ==>\n            p in addr_map &&\n            addr_map[p] == LocalAbstractAddress_{AH.ExpandUnderscores(methodName)}_{AH.ExpandUnderscores(varStackFrameFieldName)}(tid, h)\n        \");\n        abstractAddresses.Add($\"LocalAbstractAddress_{AH.ExpandUnderscores(methodName)}_{AH.ExpandUnderscores(varStackFrameFieldName)}(tid:Armada_ThreadHandle, h:int)\");\n      }\n\n      var str = $@\"\n        predicate AddressableInvariant_StackFrame_{methodName}(addr_map:map<Armada_Pointer, AbstractAddress>, frame: L.Armada_StackFrame,\n                                                               tid: Armada_ThreadHandle, h: int, heap: Armada_Heap)\n          requires frame.Armada_StackFrame_{methodName}?\n        {{\n          var frame_vars := frame.{methodName};\n          {AH.CombineStringsWithAnd(preds)}\n        }}\n      \";\n      pgp.AddPredicate(str, \"defs\");\n      return abstractAddresses;\n    }\n\n    protected virtual void GenerateAddressableMapInit()\n    {\n      var methodSymbols = pgp.symbolsLow.GetMethodSymbolTable(\"main\");\n      MapBuilder mapBuilder = new MapBuilder(\"m\");\n\n      foreach (var localVar in methodSymbols.AllVariablesInOrder.Where(v => v is MethodStackFrameAddressableLocalArmadaVariable)) {\n        string varStackFrameFieldName = methodSymbols.GetVariableStackFrameFieldName(localVar.name);\n        var localAddress = $\"s.threads[config.tid_init].top.main.{varStackFrameFieldName}\";\n        var descendants = AH.GetInvocationOfDescendants(\"s.mem.heap\", localAddress, localVar.ty);\n        mapBuilder.Add(descendants, $\"LocalAbstractAddress_main_{AH.ExpandUnderscores(varStackFrameFieldName)}(config.tid_init, 0)\");\n      }\n      foreach (var globalVarName in pgp.symbolsLow.Globals.VariableNames) {\n        var globalVar = pgp.symbolsLow.Globals.Lookup(globalVarName);\n        if (globalVar is GlobalAddressableArmadaVariable) {\n          string globalAddress = $\"s.addrs.{globalVarName}\";\n          var descendants = AH.GetInvocationOfDescendants(\"s.mem.heap\", globalAddress, globalVar.ty);\n          mapBuilder.Add(descendants, $\"GlobalAbstractAddress_{globalVarName}\");\n        }\n      }\n\n      string str = $@\"\n        function AddrMapInit(s: LState, config: Armada_Config): map<Armada_Pointer, AbstractAddress>\n          requires L.Armada_InitConfig(s, config)\n        {{\n          {mapBuilder.Extract()}\n        }}\n      \";\n      pgp.AddFunction(str, \"specs\");\n    }\n\n    protected virtual string GenerateAddressableMapNextCase_Call(NextRoutine nextRoutine)\n    {\n      var armadaCallStmt = (ArmadaCallStatement)nextRoutine.armadaStatement;\n      var methodName = armadaCallStmt.CalleeName;\n      var methodSymbols = pgp.symbolsLow.GetMethodSymbolTable(methodName);\n      MapBuilder mapBuilder = new MapBuilder(\"m\", \"splus.addr_map\");\n      foreach (var localVar in methodSymbols.AllVariablesInOrder.Where(v => v is MethodStackFrameAddressableLocalArmadaVariable)) {\n        string varStackFrameFieldName = methodSymbols.GetVariableStackFrameFieldName(localVar.name);\n        var localAddress = $\"new_frame.{varStackFrameFieldName}\";\n        var descendants = AH.GetInvocationOfDescendants(\"s'.mem.heap\", localAddress, localVar.ty);\n        mapBuilder.Add(descendants, $\"LocalAbstractAddress_{AH.ExpandUnderscores(methodName)}_{AH.ExpandUnderscores(varStackFrameFieldName)}(tid, |s'.threads[tid].stack|)\");\n      }\n      var pr = new ModuleStepPrinter(\"L\");\n      pr.State = \"splus.s\";\n      string str = $@\"\n        { pr.GetOpenStepInvocation(nextRoutine) }\n        if s'.stop_reason.Armada_NotStopped? then\n          var new_frame := s'.threads[tid].top.{methodName}; {mapBuilder.Extract()}\n        else\n          splus.addr_map\n      \";\n      return str;\n    }\n\n    protected virtual string GenerateAddressableMapNextCase_CreateThread(NextRoutine nextRoutine)\n    {\n      var armadaCreateThreadStmt = (ArmadaCreateThreadStatement)nextRoutine.armadaStatement;\n      var stmt = (UpdateStmt)armadaCreateThreadStmt.Stmt;\n      var rhs = (CreateThreadRhs)stmt.Rhss[0];\n      var methodName = rhs.MethodName.val;\n      var methodSymbols = pgp.symbolsLow.GetMethodSymbolTable(methodName);\n      MapBuilder mapBuilder = new MapBuilder(\"m\", \"splus.addr_map\");\n      foreach (var localVar in methodSymbols.AllVariablesInOrder.Where(v => v is MethodStackFrameAddressableLocalArmadaVariable)) {\n        string varStackFrameFieldName = methodSymbols.GetVariableStackFrameFieldName(localVar.name);\n        var localAddress = $\"new_frame.{varStackFrameFieldName}\";\n        var descendants = AH.GetInvocationOfDescendants(\"s'.mem.heap\", localAddress, localVar.ty);\n        mapBuilder.Add(descendants,\n          $\"LocalAbstractAddress_{AH.ExpandUnderscores(methodName)}_{AH.ExpandUnderscores(varStackFrameFieldName)}(newtid, 0)\");\n      }\n      var pr = new ModuleStepPrinter(\"L\");\n      pr.State = \"splus.s\";\n      string str = $@\"\n        { pr.GetOpenStepInvocation(nextRoutine) }\n        if s'.stop_reason.Armada_NotStopped? then\n          var newtid := params.newtid; var new_frame := s'.threads[newtid].top.{methodName}; {mapBuilder.Extract()}\n        else\n          splus.addr_map\n      \";\n      return str;\n    }\n\n    protected virtual string GenerateAddressableMapNextCase(NextRoutine nextRoutine)\n    {\n      string caseBody = \"\";\n      if (nextRoutine.Stopping) {\n        caseBody = \"splus.addr_map\";\n      }\n      else if (nextRoutine.nextType == NextType.Call) {\n        caseBody = GenerateAddressableMapNextCase_Call(nextRoutine);\n      }\n      else if (nextRoutine.nextType == NextType.CreateThread) {\n        caseBody = GenerateAddressableMapNextCase_CreateThread(nextRoutine);\n      }\n      else {\n        caseBody = \"splus.addr_map\";\n      }\n\n      var pr = new ModuleStepPrinter(\"L\");\n      return $\"{pr.CaseEntry(nextRoutine)} => {caseBody}\";\n    }\n\n    protected virtual void GenerateAddressableMapNext()\n    {\n      var caseStrings = new List<string>();\n\n      foreach (var nextRoutine in pgp.symbolsLow.NextRoutines) {\n        caseStrings.Add(GenerateAddressableMapNextCase(nextRoutine));\n      }\n\n      string str = $@\"\n        function AddrMapNext(splus: LPlusState, s': LState, step: L.Armada_Step, tid: Armada_ThreadHandle)\n          : map<Armada_Pointer, AbstractAddress>\n          requires s' == L.Armada_GetNextState(splus.s, step, tid)\n        {{\n          if L.Armada_ValidStep(splus.s, step, tid) then\n            match step\n            {{\n              {string.Join(\"\\n\", caseStrings)}\n            }}\n          else\n            splus.addr_map\n        }}\n      \";\n      pgp.AddFunction(str, \"specs\");\n    }\n\n    protected virtual void GenerateAddressableMapAux(List<string> abstractAddresses)\n    {\n      string datatypeDecl = \"datatype AbstractAddress = \" + string.Join(\" | \", abstractAddresses);\n      if (abstractAddresses.Count == 0) {\n        datatypeDecl = \"datatype AbstractAddress = AbstractAddress_None\";\n      }\n      pgp.AddDatatype(datatypeDecl, \"specs\");\n\n      GenerateAddressableMapNext();\n      GenerateAddressableMapInit();\n\n      var auxiliaryInfo = new AuxiliaryInfo(\"addr_map\", \"map<Armada_Pointer, AbstractAddress>\", \"AddrMapInit\", \"AddrMapNext\");\n      auxiliaries.Add(auxiliaryInfo);\n    }\n\n    protected virtual void GenerateAddressableInvariant()\n    {\n      GenerateValidStackFramePredicate();\n      string body = $@\"\";\n      List<string> abstractAddresses = new List<string>();\n      abstractAddresses = GenerateAddressableInvariant_Global();\n      foreach (var methodName in pgp.symbolsLow.MethodNames) {\n        abstractAddresses.AddRange(GenerateAddressableInvariant_StackFrame(methodName));\n        body += $@\"\n          && (forall tid :: tid in s.s.threads && s.s.threads[tid].top.Armada_StackFrame_{methodName}?\n            ==>\n            var frame := s.s.threads[tid].top; var heap := s.s.mem.heap;\n            AddressableInvariant_StackFrame_{methodName}(s.addr_map, frame, tid, |s.s.threads[tid].stack|, heap)\n          )\n\n          && (forall tid, h ::\n              tid in s.s.threads && 0 <= h < |s.s.threads[tid].stack| && s.s.threads[tid].stack[h].frame.Armada_StackFrame_{methodName}?\n              ==>\n              var frame := s.s.threads[tid].stack[h].frame; var heap := s.s.mem.heap;\n              AddressableInvariant_StackFrame_{methodName}(s.addr_map, frame, tid, |s.s.threads[tid].stack| - 1 - h, heap)\n          )\n        \";\n      }\n      GenerateAddressableMapAux(abstractAddresses);\n\n      string predicateDecl = $@\"\n        predicate AddressableInvariant(s: LPlusState)\n        {{\n          {body}\n          && AllValidStackFrames(s)\n          && AddressableInvariant_Globals(s)\n          && (forall p :: p in s.addr_map ==> (p in s.s.mem.heap.valid || p in s.s.mem.heap.freed) )\n        }}\n      \";\n      pgp.AddDefaultClassDecl((Predicate)AH.ParseTopLevelDecl(pgp.prog, \"AddressableInvariant\", predicateDecl), \"defs\");\n\n      AddInvariant(new InternalInvariantInfo(\"AddressableInvariant\", \"AddressableInvariant\", new List<string>()));\n    }\n\n    protected virtual void GenerateValidStackMethod(string methodName) {\n      var methodSymbols = pgp.symbolsLow.GetMethodSymbolTable(methodName);\n      var preds = new List<string>();\n      var p_in_new_ptrs = new List<string>();\n      foreach (var localVar in methodSymbols.AllVariablesInOrder.Where(v => v is MethodStackFrameAddressableLocalArmadaVariable)) {\n        string varStackFrameFieldName = methodSymbols.GetVariableStackFrameFieldName(localVar.name);\n        preds.Add(AH.GetInvocationOfValidPointer(\"heap\", $\"frame_vars.{varStackFrameFieldName}\", localVar.ty));\n        preds.Add($@\"\n          heap.tree[frame_vars.{varStackFrameFieldName}].child_type.Armada_ChildTypeRoot?\n          && heap.tree[frame_vars.{varStackFrameFieldName}].child_type.rt.Armada_RootTypeStack?\");\n        var descendants = AH.GetInvocationOfDescendants(\"heap\", $\"frame_vars.{varStackFrameFieldName}\", localVar.ty);\n        p_in_new_ptrs.Add($\"p in ({descendants})\");\n      }\n\n      if (p_in_new_ptrs.Count > 0) {\n        preds.Add($@\"\n          forall p {{:trigger Armada_TriggerPointer(p)}} ::\n            (Armada_TriggerPointer(p) in new_ptrs) <==> ({AH.CombineStringsWithOr(p_in_new_ptrs)})\n        \");\n      } else {\n        preds.Add(\"|new_ptrs| == 0\");\n      }\n       \n      string predicateDecl = $@\"\n        predicate ValidStackFrame_{methodName}(frame: L.Armada_StackFrame, heap: Armada_Heap, new_ptrs: set<Armada_Pointer>) \n        requires frame.Armada_StackFrame_{methodName}?\n        {{\n          var frame_vars := frame.{methodName};\n          {AH.CombineStringsWithAnd(preds)}\n        }}\n      \";\n      pgp.AddPredicate(predicateDecl, \"defs\");\n    }\n\n    protected virtual void GenerateValidStackFramePredicate()\n    {\n      List<string> caseBodies = new List<string>();\n      foreach (var methodName in pgp.symbolsLow.MethodNames)\n      {\n        GenerateValidStackMethod(methodName);\n\n        caseBodies.Add($@\"\n          forall tid :: tid in s.s.threads && s.s.threads[tid].top.Armada_StackFrame_{methodName}? ==>\n            var t := s.s.threads[tid];\n            ValidStackFrame_{methodName}(t.top, s.s.mem.heap, t.new_ptrs)\n        \");\n        caseBodies.Add($@\"\n          forall tid, h ::\n            tid in s.s.threads && 0 <= h < |s.s.threads[tid].stack|\n            && s.s.threads[tid].stack[h].frame.Armada_StackFrame_{methodName}? ==>\n            ValidStackFrame_{methodName}(s.s.threads[tid].stack[h].frame, s.s.mem.heap, s.s.threads[tid].stack[h].new_ptrs)\n        \");\n      }\n\n      string str = $@\"\n        predicate AllValidStackFrames(s: LPlusState)\n        {{\n          {AH.CombineStringsWithAnd(caseBodies)}\n        }}\n      \";\n      pgp.AddPredicate(str, \"defs\");\n    }\n\n    public class RegionInfo\n    {\n      public Dictionary<string, string> globalPtrVarRegionMap;\n      public Dictionary<string, string> globalAddrVarRegionMap;\n      public Dictionary<string, Dictionary<string, string>> methodToPtrVarRegionTable;\n      public Dictionary<string, Dictionary<string, string>> methodToAddrVarRegionTable;\n      public List<string> regionIds;\n\n      public RegionInfo()\n      {\n        globalPtrVarRegionMap = new Dictionary<string, string>();\n        globalAddrVarRegionMap = new Dictionary<string, string>();\n        methodToPtrVarRegionTable = new Dictionary<string, Dictionary<string, string>>();\n        methodToAddrVarRegionTable = new Dictionary<string, Dictionary<string, string>>();\n        regionIds = new List<string>();\n      }\n\n      public string GetGlobalRegionId(string varName)\n      {\n        string regionId = null;\n        if (varName.Length > 0 && varName[0] == '&') {\n          globalAddrVarRegionMap.TryGetValue(varName.Substring(1), out regionId);\n        }\n        else {\n          globalPtrVarRegionMap.TryGetValue(varName, out regionId);\n        }\n        return regionId;\n      }\n\n      public string GetLocalRegionId(string methodName, string varName)\n      {\n        string regionId = null;\n        Dictionary<string, string> methodAddrVarRegionTable = null;\n        if (methodToAddrVarRegionTable.TryGetValue(methodName, out methodAddrVarRegionTable)) {\n          if (varName.Length > 0 && varName[0] == '&') {\n            methodToAddrVarRegionTable[methodName].TryGetValue(varName.Substring(1), out regionId);\n          }\n          else {\n            methodToPtrVarRegionTable[methodName].TryGetValue(varName, out regionId);\n          }\n        }\n        return regionId;\n      }\n\n      public string GetRegionId(string methodName, string varName)\n      {\n        string regionId = GetLocalRegionId(methodName, varName);\n        if (regionId == null) {\n          regionId = GetGlobalRegionId(varName);\n        }\n        return regionId;\n      }\n    }\n\n    // Initial region of &globalVariable is represented as `r_&globalVariableName`\n    // Initial region of globalPointer is represented as `r_globalPointer`\n    // Initial region of methodName's &localVariable is represented as `r_methodName.&localVariable`\n    // Initial region of methodName's localPointer is represented as `r_methodName.localVariable`\n    // Initial region of methodName's Malloc/Calloc statement at PC=p is represented `alloc_r_methodName[p]`\n\n    private RegionInfo GenerateInitialRegionInfo()\n    {\n      RegionInfo r = new RegionInfo();\n\n      foreach (var globalVarName in pgp.symbolsLow.Globals.VariableNames) {\n        var globalVar = pgp.symbolsLow.Globals.Lookup(globalVarName);\n        // Global addressable variables\n        if (globalVar is GlobalAddressableArmadaVariable) {\n          r.globalAddrVarRegionMap[globalVarName] = $\"rga_{globalVarName}\";\n          r.regionIds.Add($\"rga_{globalVarName}\");\n        }\n        if (globalVar.ty is PointerType) {\n          r.globalPtrVarRegionMap[globalVarName] = $\"rgp_{globalVarName}\";\n          r.regionIds.Add($\"rgp_{globalVarName}\");\n        }\n      }\n\n      foreach (var methodName in pgp.symbolsLow.MethodNames) {\n        var methodSymbols = pgp.symbolsLow.GetMethodSymbolTable(methodName);\n        Dictionary<string, string> ptrRegionTable = new Dictionary<string, string>();\n        Dictionary<string, string> addrRegionTable = new Dictionary<string, string>();\n        foreach (var localVar in methodSymbols.AllVariables) {\n          var localVarName = localVar.name;\n          if (localVar is MethodStackFrameAddressableLocalArmadaVariable) {\n            addrRegionTable[localVarName] = $\"rap_{AH.ExpandUnderscores(methodName)}_{AH.ExpandUnderscores(localVarName)}\";\n            r.regionIds.Add($\"rap_{AH.ExpandUnderscores(methodName)}_{AH.ExpandUnderscores(localVarName)}\");\n          }\n          if (localVar.ty is PointerType) {\n            ptrRegionTable[localVarName] = $\"rlp_{AH.ExpandUnderscores(methodName)}_{AH.ExpandUnderscores(localVarName)}\";\n            r.regionIds.Add($\"rlp_{AH.ExpandUnderscores(methodName)}_{AH.ExpandUnderscores(localVarName)}\");\n          }\n          r.methodToAddrVarRegionTable[methodName] = addrRegionTable;\n          r.methodToPtrVarRegionTable[methodName] = ptrRegionTable;\n        }\n      }\n      // Console.WriteLine(string.Join(\" \", r.regionIds));\n      return r;\n    }\n\n    protected virtual List<string> GetPossibleResultantVariables(Expression expr)\n    {\n      var vars = new List<string>();\n      if (expr is NameSegment) // return `variable`\n      {\n        var e = (NameSegment)expr;\n        vars.Add(e.Name);\n      }\n      if (expr is UnaryOpExpr)\n      {\n        var e = (UnaryOpExpr)expr;\n        if (e.Op == UnaryOpExpr.Opcode.AddressOf)\n        {\n          vars.Add(Printer.ExprToString(e)); // Want to return `&variable`\n        }\n      }\n      return vars;\n    }\n\n    protected virtual RegionInfo GenerateVariableRegionMap()\n    {\n      RegionInfo r = GenerateInitialRegionInfo();\n      Dictionary<string, int> regionIdToIndex = new Dictionary<string, int>();\n      List<string> indexToRegionId = new List<string>();\n      int numRegions = 0;\n      foreach (var regionId in r.regionIds)\n      {\n        regionIdToIndex[regionId] = numRegions;\n        indexToRegionId.Add(regionId);\n        numRegions += 1;\n      }\n      DisjointSet d = new DisjointSet(numRegions);\n\n      // TODO: Merge for al initializations of pointer variables\n\n      // Merge for all statements that force regions to be merged\n      foreach (var nextRoutine in pgp.symbolsLow.NextRoutines) {\n        if (nextRoutine.Stopping) {\n          continue;\n        }\n        if (nextRoutine.nextType == NextType.Update) {\n          var updateStmt = (UpdateStmt)nextRoutine.stmt;\n          var lhss = updateStmt.Lhss;\n          var rhss = updateStmt.Rhss;\n          var methodName = nextRoutine.method.Name;\n          for (int i = 0; i < lhss.Count; ++i) {\n            var lhs = lhss[i];\n            var rhs_Rhs = rhss[i];\n            \n            var lhsVarName = Printer.ExprToString(lhs);\n\n            var eRhs = (ExprRhs)rhs_Rhs;\n            var rhs = eRhs.Expr;\n            List<string> rhsVarNames = GetPossibleResultantVariables(rhs);\n            var r1 = r.GetRegionId(methodName, lhsVarName);\n            if (r1 != null) {\n              foreach (var rhsVarName in rhsVarNames) {\n                // Console.WriteLine($\"Merging {lhsVarName} with {rhsVarName}\");\n                var r2 = r.GetRegionId(methodName, rhsVarName);\n                // Console.WriteLine($\"Merging region {r1} with {r2}\");\n                if (r2 != null) {\n                  d.Join(regionIdToIndex[r1], regionIdToIndex[r2]);\n                } else { // For whatever reason, we don't know the region of the RHS, so we can't reason about the LHS either.\n                  //Console.WriteLine($\"Region can't be specified for {lhsVarName} because of {Printer.ExprToString(rhs)}\");\n                }\n              }\n            } else {\n              //Console.WriteLine(lhsVarName);\n            }\n          }\n        }\n        else if (nextRoutine.nextType == NextType.Call) {\n          var methodName = nextRoutine.method.Name;\n          var armadaCallStmt = (ArmadaCallStatement)nextRoutine.armadaStatement;\n          var stmt = (UpdateStmt)armadaCallStmt.Stmt;\n          var ex = (ExprRhs)stmt.Rhss[0];\n          var suffix = (ApplySuffix)ex.Expr;\n          var args = suffix.Args;\n          var calledMethodName = armadaCallStmt.CalleeName;\n          var methodSymbols = pgp.symbolsLow.GetMethodSymbolTable(calledMethodName);\n          var methodInputVars = methodSymbols.InputVariableNames.ToList();\n          for (int i = 0; i < methodInputVars.Count; i++) {\n            var inputVar = methodSymbols.LookupVariable(methodInputVars[i]);\n            if (inputVar.ty is PointerType) {\n              var lhsVarName = methodInputVars[i];\n              var arg = args[i];\n              List<string> rhsVarNames = GetPossibleResultantVariables(arg);\n\n              foreach (var rhsVarName in rhsVarNames) {\n                // Console.WriteLine($\"Merging {lhsVarName} with {rhsVarName}\");\n                var r1 = r.GetRegionId(calledMethodName, lhsVarName);\n                var r2 = r.GetRegionId(methodName, rhsVarName);\n                //Console.WriteLine($\"Method varName: {methodName} {rhsVarName}\");\n                //Console.WriteLine($\"Merging region {r1} with {r2}\");\n                if (r2 != null) {\n                  d.Join(regionIdToIndex[r1], regionIdToIndex[r2]);\n                } else { // For whatever reason, we don't know the region of the RHS, so we can't reason about the LHS either.\n                  //Console.WriteLine($\"Region can't be specified for {lhsVarName} because of {rhsVarName}\");\n                }\n              }\n            }\n          }\n        }\n        else if (nextRoutine.nextType == NextType.CreateThread) {\n          var methodName = nextRoutine.method.Name;\n          var armadaCallStmt = (ArmadaCreateThreadStatement)nextRoutine.armadaStatement;\n          var stmt = (UpdateStmt)armadaCallStmt.Stmt;\n          var rhs = (CreateThreadRhs)stmt.Rhss[0];\n          var calledMethodName = rhs.MethodName.val;\n          var args = rhs.Args;\n          var methodSymbols = pgp.symbolsLow.GetMethodSymbolTable(calledMethodName);\n          var methodInputVars = methodSymbols.InputVariableNames.ToList();\n          for (int i = 0; i < methodInputVars.Count; i++) {\n            var inputVar = methodSymbols.LookupVariable(methodInputVars[i]);\n            if (inputVar.ty is PointerType) {\n              var lhsVarName = methodInputVars[i];\n              var arg = args[i];\n              List<string> rhsVarNames = GetPossibleResultantVariables(arg);\n\n              foreach (var rhsVarName in rhsVarNames) {\n                // Console.WriteLine($\"Merging {lhsVarName} with {rhsVarName}\");\n                var r1 = r.GetRegionId(calledMethodName, lhsVarName);\n                var r2 = r.GetRegionId(methodName, rhsVarName);\n                // Console.WriteLine($\"Merging region {r1} with {r2}\");\n                d.Join(regionIdToIndex[r1], regionIdToIndex[r2]);\n              }\n            }\n          }\n        }\n      }\n\n      foreach (var k in r.globalAddrVarRegionMap.Keys.ToList())\n      {\n        r.globalAddrVarRegionMap[k] = indexToRegionId[d.Find(regionIdToIndex[r.globalAddrVarRegionMap[k]])];\n      }\n      foreach (var k in r.globalPtrVarRegionMap.Keys.ToList())\n      {\n        r.globalPtrVarRegionMap[k] = indexToRegionId[d.Find(regionIdToIndex[r.globalPtrVarRegionMap[k]])];\n      }\n      foreach (var k1 in r.methodToAddrVarRegionTable.Keys.ToList())\n      {\n        foreach (var k2 in r.methodToAddrVarRegionTable[k1].Keys.ToList())\n        {\n          r.methodToAddrVarRegionTable[k1][k2] = indexToRegionId[d.Find(regionIdToIndex[r.methodToAddrVarRegionTable[k1][k2]])];\n        }\n      }\n      foreach (var k1 in r.methodToPtrVarRegionTable.Keys.ToList())\n      {\n        foreach (var k2 in r.methodToPtrVarRegionTable[k1].Keys.ToList())\n        {\n          r.methodToPtrVarRegionTable[k1][k2] = indexToRegionId[d.Find(regionIdToIndex[r.methodToPtrVarRegionTable[k1][k2]])];\n        }\n      }\n\n      HashSet<string> possibleRegionIds = new HashSet<string>();\n      foreach(var pair in regionIdToIndex)\n      {\n         possibleRegionIds.Add(indexToRegionId[d.Find(pair.Value)]);\n      }\n      string str = \"datatype RegionId = \" + String.Join(\" | \", possibleRegionIds);\n      pgp.AddDatatype(str, \"specs\");\n      return r;\n    }\n\n    protected virtual string GenerateRegionMapNextCase_CreateThread(NextRoutine nextRoutine, RegionInfo regionInfo)\n    {\n      var armadaCreateThreadStmt = (ArmadaCreateThreadStatement)nextRoutine.armadaStatement;\n      var stmt = (UpdateStmt)armadaCreateThreadStmt.Stmt;\n      var rhs = (CreateThreadRhs)stmt.Rhss[0];\n      var methodName = rhs.MethodName.val;\n      var methodSymbols = pgp.symbolsLow.GetMethodSymbolTable(methodName);\n      List<string> mapUpdates = new List<string>();\n      foreach (var localVar in methodSymbols.AllVariablesInOrder.Where(v => v is MethodStackFrameAddressableLocalArmadaVariable)) {\n        string regionIdStr = regionInfo.GetRegionId(methodName, \"&\" + localVar.name);\n        mapUpdates.Add($\"[params.newframe_{localVar.name} := {regionIdStr}]\");\n      }\n      string mapUpdateBody = string.Join(\"\", mapUpdates);\n      var pr = new LPlusStepPrinter();\n      string str = $@\"\n        { pr.GetOpenStepInvocation(nextRoutine) }\n        s.region_map{mapUpdateBody}\n      \";\n      return str;\n    }\n\n    protected virtual string GenerateRegionMapNextCase_Call(NextRoutine nextRoutine, RegionInfo regionInfo)\n    {\n      var armadaCallStmt = (ArmadaCallStatement)nextRoutine.armadaStatement;\n      var methodName = armadaCallStmt.CalleeName;\n      var methodSymbols = pgp.symbolsLow.GetMethodSymbolTable(methodName);\n      List<string> mapUpdates = new List<string>();\n      foreach (var localVar in methodSymbols.AllVariablesInOrder.Where(v => v is MethodStackFrameAddressableLocalArmadaVariable)) {\n        string regionIdStr = regionInfo.GetRegionId(methodName, \"&\" + localVar.name);\n        mapUpdates.Add($\"[params.newframe_{localVar.name} := {regionIdStr}]\");\n      }\n      string mapUpdateBody = string.Join(\"\", mapUpdates);\n      var pr = new LPlusStepPrinter();\n      string str = $@\"\n        { pr.GetOpenStepInvocation(nextRoutine) }\n        s.region_map{mapUpdateBody}\n      \";\n      return str;\n    }\n    \n    protected virtual string GenerateRegionMapNextCase(NextRoutine nextRoutine, RegionInfo regionInfo)\n    {\n      string str = \"\"; // $\"case Armada_Step_{nextRoutine.NameSuffix} => \";\n      if (nextRoutine.Stopping) {\n        str = \"s.region_map\";\n      }\n      else if (nextRoutine.nextType == NextType.MallocSuccess) {\n        var updateStmt = (UpdateStmt)nextRoutine.armadaStatement.Stmt;\n        // Get the variable from the LHS and use that to determine the case \n        string methodName = nextRoutine.method.Name;\n        string varName = Printer.ExprToString(updateStmt.Lhss[0]);\n        var regionId = regionInfo.GetRegionId(methodName, varName);\n        var pr = new LPlusStepPrinter();\n        str = $@\"\n          { pr.GetOpenStepInvocation(nextRoutine) }\n          s.region_map[params.new_ptr := {regionId}]\n        \";\n      }\n      else if (nextRoutine.nextType == NextType.Call) {\n        str = GenerateRegionMapNextCase_Call(nextRoutine, regionInfo);\n      }\n      else if (nextRoutine.nextType == NextType.CreateThread) {\n        str = GenerateRegionMapNextCase_CreateThread(nextRoutine, regionInfo);\n      }\n      else {\n        str = \"s.region_map\";\n      }\n\n      var bvs = nextRoutine.HasFormals ? $\"params: L.Armada_StepParams_{nextRoutine.NameSuffix}\" : \"\";\n      return $\"case Armada_Step_{nextRoutine.NameSuffix}({bvs}) => {str}\\n\";\n    }\n\n    protected virtual void GenerateRegionMapNext(RegionInfo regionInfo)\n    {\n      var caseBodies =\n        String.Concat(pgp.symbolsLow.NextRoutines.Select(nextRoutine => GenerateRegionMapNextCase(nextRoutine, regionInfo)));\n      var fn = $@\"\n        function RegionMapNext(s: LPlusState, ls': LState, step: L.Armada_Step, tid: Armada_ThreadHandle)\n          : map<Armada_Pointer, RegionId>\n        {{\n          match step\n            {caseBodies}\n        }}\n      \";\n      pgp.AddFunction(fn, \"specs\");\n    }\n\n    protected virtual void GenerateRegionMap(IEnumerable<string> regionIds)\n    {\n      var auxiliaryInfo = new AuxiliaryInfo(\"region_map\", \"map<Armada_Pointer, RegionId>\", \"RegionMapInit\", \"RegionMapNext\");\n      auxiliaries.Add(auxiliaryInfo);\n    }\n\n    protected virtual void GenerateRegionInvariant()\n    {\n      GenerateHeapInvariant();\n      RegionInfo regionInfo = GenerateVariableRegionMap();\n      GenerateAddressableInvariant();\n      // OtherWay lemmas are needed for addressable pointer variables\n      GenerateAppendStoreBufferOtherWay();\n      var regionIds = new HashSet<string>();\n\n      var preds = new List<string>();\n      List<string> regionMapInitUpdates = new List<string>();\n\n      foreach (var globalVarName in pgp.symbolsLow.Globals.VariableNames) {\n        var globalVar = pgp.symbolsLow.Globals.Lookup(globalVarName);\n        // Global addressable variables\n        if (globalVar is GlobalAddressableArmadaVariable) {\n          string regionNameStr = regionInfo.GetGlobalRegionId(\"&\" + globalVarName);\n\n          preds.Add($\"addrs.{globalVarName} in region_map\");\n\n          preds.Add($\"region_map[addrs.{globalVarName}] == {regionNameStr}\");\n\n          regionMapInitUpdates.Add($\"s.addrs.{globalVarName} := {regionNameStr}\");\n        }\n\n        // Deal with global pointer variables\n        if (globalVar.ty is PointerType) {\n          string regionNameStr = regionInfo.GetGlobalRegionId(globalVarName);\n\n          // Global addressable pointer variable\n          if (globalVar is GlobalAddressableArmadaVariable) {\n\n            // Need to ensure that the address stored in this pointer variable is in the correct region\n            var pointerValue = AH.GetInvocationOfDereferencePointer(\"mem.heap\", $\"addrs.{globalVarName}\", globalVar.ty);\n            var validPointer = AH.GetInvocationOfValidPointer(\"mem.heap\", $\"addrs.{globalVarName}\", globalVar.ty);\n            preds.Add(validPointer);\n            preds.Add($\"({pointerValue}) == 0 || (({pointerValue}) in region_map && region_map[{pointerValue}] == {regionNameStr})\");\n          }\n          // Global non-addressable pointer variable\n          else \n          {\n            preds.Add($\"mem.globals.{globalVarName} == 0 || (mem.globals.{globalVarName} in region_map && region_map[mem.globals.{globalVarName}] == {regionNameStr})\");\n          }\n        }\n      }\n      // Deal with addresses of addressable stack variables\n      foreach (var methodName in pgp.symbolsLow.MethodNames) {\n        var methodSymbols = pgp.symbolsLow.GetMethodSymbolTable(methodName);\n        foreach (var localVar in methodSymbols.AllVariables) {\n          var localVarName = localVar.name;\n          if (localVar is MethodStackFrameAddressableLocalArmadaVariable) {\n            string varStackFrameFieldName = methodSymbols.GetVariableStackFrameFieldName(localVar.name);\n            string regionIdStr = regionInfo.GetLocalRegionId(methodName, \"&\" + localVarName);\n\n            if (methodName == \"main\") {\n              regionMapInitUpdates.Add($\"s.threads[config.tid_init].top.{methodName}.{varStackFrameFieldName} := {regionIdStr}\");\n            }\n\n            preds.Add($@\"\n              forall tid, extended_frame ::\n                tid in threads\n                && extended_frame in threads[tid].stack\n                && extended_frame.frame.Armada_StackFrame_{methodName}?\n                  ==> var stack_frame := extended_frame.frame.{methodName};\n                  (stack_frame.{varStackFrameFieldName} in region_map && region_map[stack_frame.{varStackFrameFieldName}] == {regionIdStr})\n            \");\n\n            preds.Add($@\"\n              forall tid ::\n                tid in threads\n                && threads[tid].top.Armada_StackFrame_{methodName}?\n                  ==> var stack_frame := threads[tid].top.{methodName};\n                  (stack_frame.{varStackFrameFieldName} in region_map && region_map[stack_frame.{varStackFrameFieldName}] == {regionIdStr})\n            \");\n          }\n          if (localVar.ty is PointerType) { // If the variable is a pointer type\n            string regionIdStr = regionInfo.GetLocalRegionId(methodName, localVarName);\n            string varStackFrameFieldName = methodSymbols.GetVariableStackFrameFieldName(localVar.name);\n\n            var validPointerStr = AH.GetInvocationOfValidPointer(\"mem.heap\", $\"frame_vars.{varStackFrameFieldName}\", localVar.ty);\n            var pointerValueStr = AH.GetInvocationOfDereferencePointer(\"mem.heap\", $\"frame_vars.{varStackFrameFieldName}\", localVar.ty);\n\n            // Local addressable pointer\n            if (localVar is MethodStackFrameAddressableLocalArmadaVariable) {\n              preds.Add($@\"\n                forall tid :: tid in threads && threads[tid].top.Armada_StackFrame_{methodName}?\n                ==> var frame_vars := threads[tid].top.{methodName};\n                    {validPointerStr}\n                    && ({pointerValueStr} == 0 ||\n                        ({pointerValueStr} in region_map \n                         && region_map[{pointerValueStr}] == {regionIdStr}\n                         )\n                        )\n              \");\n\n              preds.Add($@\"\n                forall tid, extended_frame ::\n                  tid in threads\n                  && extended_frame in threads[tid].stack\n                  && extended_frame.frame.Armada_StackFrame_{methodName}?\n                    ==> var frame_vars := extended_frame.frame.{methodName};\n                    {validPointerStr}\n                    && ({pointerValueStr} == 0 ||\n                        ({pointerValueStr} in region_map \n                         && region_map[{pointerValueStr}] == {regionIdStr}\n                         )\n                      )\n              \");\n            }\n            // Local non-addressable pointer\n            else {\n              preds.Add($@\"\n                forall tid, extended_frame ::\n                  tid in threads\n                  && extended_frame in threads[tid].stack\n                  && extended_frame.frame.Armada_StackFrame_{methodName}?\n                    ==> var stack_frame_vars := extended_frame.frame.{methodName};\n                    stack_frame_vars.{varStackFrameFieldName} == 0 || (stack_frame_vars.{varStackFrameFieldName} in region_map && region_map[stack_frame_vars.{varStackFrameFieldName}] == {regionIdStr})\n              \");\n\n              preds.Add($@\"\n                forall tid ::\n                  tid in threads\n                  && threads[tid].top.Armada_StackFrame_{methodName}?\n                    ==> var stack_frame_vars := threads[tid].top.{methodName};\n                    stack_frame_vars.{varStackFrameFieldName} == 0 || (stack_frame_vars.{varStackFrameFieldName} in region_map && region_map[stack_frame_vars.{varStackFrameFieldName}] == {regionIdStr})\n              \");\n            }\n          }\n        }\n      }\n\n      var str = $@\"\n        function RegionMapInit(s: LState, config: Armada_Config) : map<Armada_Pointer, RegionId>\n           requires L.Armada_InitConfig(s, config)\n        {{\n          map[{AH.CombineStringsWithCommas(regionMapInitUpdates)}]\n        }}\n      \";\n      pgp.AddFunction(str, \"specs\");\n\n      GenerateRegionMapNext(regionInfo);\n\n      str = $@\"\n        predicate RegionInvariant_mem(threads: map<Armada_ThreadHandle, L.Armada_Thread>, addrs: L.Armada_Addrs,\n                                      mem: L.Armada_SharedMemory, region_map: map<Armada_Pointer, RegionId>)\n        {{\n          {AH.CombineStringsWithAnd(preds)}\n        }}\n      \";\n      pgp.AddPredicate(str, \"defs\");\n\n      str = @\"\n        predicate RegionMapOnlyContainsValidOrFreedPointers(s: LPlusState)\n        {\n          forall k :: k in s.region_map ==> k in s.s.mem.heap.valid || k in s.s.mem.heap.freed\n        }\n      \";\n      pgp.AddPredicate(str, \"defs\");\n\n      str = $@\"\n        predicate RegionInvariant(s: LPlusState)\n        {{\n            RegionMapOnlyContainsValidOrFreedPointers(s)\n            && RegionInvariant_mem(s.s.threads, s.s.addrs, s.s.mem, s.region_map)\n            && (forall tid, storeBufferEntry, threads, addrs, mem, region_map ::\n                 tid in s.s.threads && storeBufferEntry in s.s.threads[tid].storeBuffer\n                 && (forall p :: p in s.region_map ==> p in region_map && region_map[p] == s.region_map[p]) \n                 && RegionInvariant_mem(threads, addrs, mem, region_map) ==>\n                 RegionInvariant_mem(threads, addrs, L.Armada_ApplyStoreBufferEntry(mem, storeBufferEntry), region_map))\n        }}\n      \";\n      pgp.AddPredicate(str, \"defs\");\n\n      GenerateRegionMap(regionIds);\n      AddInvariant(new InternalInvariantInfo(\"RegionInvariant\", \"RegionInvariant\", new List<string>(){\"AddressableInvariant\"}, \"lemma_RegionInvariantOnGlobalViewAlwaysImpliesRegionInvariantOnLocalView();\"));\n      GenerateRegionInvariantHoldsOnLocalViewLemmas();\n    }\n\n    protected virtual void GenerateRegionInvariantHoldsOnLocalViewLemmas()\n    {\n      string str = @\"\n        lemma lemma_RegionInvariantOnGlobalViewImpliesRegionInvariantOnLocalView(s_threads: map<Armada_ThreadHandle, L.Armada_Thread>, s_addrs: L.Armada_Addrs, s_mem: L.Armada_SharedMemory, s_region_map: map<Armada_Pointer, RegionId>, storeBuffer:seq<L.Armada_StoreBufferEntry>)\n          requires RegionInvariant_mem(s_threads, s_addrs, s_mem, s_region_map)\n          \n          requires forall storeBufferEntry, threads, addrs, mem, region_map :: \n              storeBufferEntry in storeBuffer &&\n              (forall p :: p in s_region_map ==> p in region_map && region_map[p] == s_region_map[p]) &&\n              RegionInvariant_mem(threads, addrs, mem, region_map) ==>\n              RegionInvariant_mem(threads, addrs, L.Armada_ApplyStoreBufferEntry(mem, storeBufferEntry), region_map)\n              \n          ensures RegionInvariant_mem(s_threads, s_addrs, L.Armada_ApplyStoreBuffer(s_mem, storeBuffer), s_region_map)\n          decreases |storeBuffer|\n        {\n          if |storeBuffer| > 0 {\n            var s_mem' := L.Armada_ApplyStoreBufferEntry(s_mem, storeBuffer[0]);\n            lemma_RegionInvariantOnGlobalViewImpliesRegionInvariantOnLocalView(s_threads, s_addrs, s_mem', s_region_map, storeBuffer[1..]);\n          }\n        }\n      \";\n      pgp.AddLemma(str, \"invariants\");\n\n      str = @\"\n        lemma lemma_RegionInvariantOnGlobalViewAlwaysImpliesRegionInvariantOnLocalView()\n          ensures forall s :: RegionInvariant(s) ==> (forall tid :: tid in s.s.threads ==>\n          RegionInvariant_mem(s.s.threads, s.s.addrs, L.Armada_GetThreadLocalView(s.s, tid), s.region_map))\n        {\n          forall s | RegionInvariant(s)\n            ensures (forall tid :: tid in s.s.threads ==> RegionInvariant_mem(s.s.threads, s.s.addrs, L.Armada_GetThreadLocalView(s.s, tid), s.region_map))\n          {\n            forall tid | tid in s.s.threads\n              ensures RegionInvariant_mem(s.s.threads, s.s.addrs, L.Armada_GetThreadLocalView(s.s, tid), s.region_map)\n            {\n              lemma_RegionInvariantOnGlobalViewImpliesRegionInvariantOnLocalView(s.s.threads, s.s.addrs, s.s.mem, s.region_map, s.s.threads[tid].storeBuffer);\n            }\n          }\n        }\n      \";\n      pgp.AddLemma(str, \"invariants\");\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    /// Lemmas about heap invariant preservation\n    ////////////////////////////////////////////////////////////////////////\n\n    protected virtual void GenerateHeapInvariant() {\n      string str = @\"\n        predicate HeapInvariant(s:LPlusState)\n        {\n          Armada_HeapInvariant(s.s.mem.heap)\n        }\n      \";\n      pgp.AddDefaultClassDecl((Predicate)AH.ParseTopLevelDecl(pgp.prog, \"HeapInvariant\", str), \"specs\");\n      AddInvariant(new InternalInvariantInfo(\"HeapInvariant\", \"HeapInvariant\", new List<string>() {\"AddressableInvariant\"} ));\n    }\n\n    protected virtual void GenerateLemmasHelpfulForProvingInitPreservation_LH()\n    {\n      string str;\n\n      str = $@\"\n        lemma lemma_ConvertTotalStatePreservesAddressableStaticVariablesAreValid(ls:LState, hs:HState, new_ptrs:set<Armada_Pointer>)\n          requires hs == ConvertTotalState_LH(ls)\n          requires L.Armada_AddressableStaticVariablesAreValid(ls, new_ptrs)\n          ensures  H.Armada_AddressableStaticVariablesAreValid(hs, new_ptrs)\n        {{\n          var lheap := ls.mem.heap.(valid := ls.mem.heap.valid - new_ptrs);\n          var hheap := hs.mem.heap.(valid := hs.mem.heap.valid - new_ptrs);\n        }}\n      \";\n      pgp.AddLemma(str);\n\n      str = @\"\n        lemma lemma_ConvertTotalStatePreservesAddressableStaticVariablesAreRoots(ls:LState, hs:HState)\n          requires hs == ConvertTotalState_LH(ls)\n          requires L.Armada_AddressableStaticVariablesAreDistinctRoots(ls)\n          ensures  H.Armada_AddressableStaticVariablesAreDistinctRoots(hs)\n        {\n        }\n      \";\n      pgp.AddLemma(str);\n\n      str = @\"\n        lemma lemma_ConvertTotalStatePreservesInit(ls: LState, hs: HState, lconfig: Armada_Config, hconfig: Armada_Config)\n          requires L.Armada_InitConfig(ls, lconfig)\n          requires hs == ConvertTotalState_LH(ls)\n          requires hconfig == ConvertConfig_LH(lconfig)\n          ensures  H.Armada_InitConfig(hs, hconfig)\n        {\n          lemma_ConvertTotalStatePreservesAddressableStaticVariablesAreValid(ls, hs, lconfig.new_ptrs);\n          lemma_ConvertTotalStatePreservesAddressableStaticVariablesAreRoots(ls, hs);\n        }\n      \";\n      pgp.AddLemma(str);\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    /// Lemmas about commutativity\n    ////////////////////////////////////////////////////////////////////////\n\n    protected virtual void GenerateLocalViewCommutativityLemmas()\n    {\n      string str;\n\n      str = @\"\n        lemma lemma_ApplyStoreBufferEntryUnaddressableCommutesWithConvert(\n          lglobals:L.Armada_Globals, lv:L.Armada_GlobalStaticVar, fields:seq<int>, value:Armada_PrimitiveValue,\n          hv:H.Armada_GlobalStaticVar, hglobals1:H.Armada_Globals, hglobals2:H.Armada_Globals)\n          requires hv == ConvertGlobalStaticVar_LH(lv)\n          requires hglobals1 == ConvertGlobals_LH(L.Armada_ApplyTauUnaddressable(lglobals, lv, fields, value))\n          requires hglobals2 == H.Armada_ApplyTauUnaddressable(ConvertGlobals_LH(lglobals), hv, fields, value)\n          ensures  hglobals1 == hglobals2\n        {\n        }\n      \";\n      pgp.AddLemma(str, \"utility\");\n\n      str = @\"\n        lemma lemma_ApplyStoreBufferEntryCommutesWithConvert(lmem:L.Armada_SharedMemory, lentry:L.Armada_StoreBufferEntry,\n                                                             hentry:H.Armada_StoreBufferEntry, hmem1:H.Armada_SharedMemory,\n                                                             hmem2:H.Armada_SharedMemory)\n          requires hentry == ConvertStoreBufferEntry_LH(lentry)\n          requires hmem1 == ConvertSharedMemory_LH(L.Armada_ApplyStoreBufferEntry(lmem, lentry))\n          requires hmem2 == H.Armada_ApplyStoreBufferEntry(ConvertSharedMemory_LH(lmem), hentry)\n          ensures  hmem1 == hmem2\n        {\n          match lentry.loc\n            case Armada_StoreBufferLocation_Unaddressable(lv, lfields) =>\n            {\n              var hv := ConvertGlobalStaticVar_LH(lv);\n              lemma_ApplyStoreBufferEntryUnaddressableCommutesWithConvert(lmem.globals, lv, lfields, lentry.value, hv, hmem1.globals,\n                                                                          hmem2.globals);\n            }\n            case Armada_StoreBufferLocation_Addressable(p) =>\n            {\n            }\n        }\n      \";\n      pgp.AddLemma(str, \"utility\");\n\n      str = @\"\n        lemma lemma_ApplyStoreBufferCommutesWithConvert(lmem:L.Armada_SharedMemory, lbuf:seq<L.Armada_StoreBufferEntry>,\n                                                        hbuf:seq<H.Armada_StoreBufferEntry>, hmem1:H.Armada_SharedMemory,\n                                                        hmem2:H.Armada_SharedMemory)\n          requires hbuf == ConvertStoreBuffer_LH(lbuf)\n          requires hmem1 == ConvertSharedMemory_LH(L.Armada_ApplyStoreBuffer(lmem, lbuf))\n          requires hmem2 == H.Armada_ApplyStoreBuffer(ConvertSharedMemory_LH(lmem), hbuf)\n          ensures  hmem1 == hmem2\n          decreases |lbuf| + |hbuf|\n        {\n          if |lbuf| == 0 {\n              return;\n          }\n\n          var lmem' := L.Armada_ApplyStoreBufferEntry(lmem, lbuf[0]);\n\n          var hmem1' := ConvertSharedMemory_LH(L.Armada_ApplyStoreBufferEntry(lmem, lbuf[0]));\n          var hmem2' := H.Armada_ApplyStoreBufferEntry(ConvertSharedMemory_LH(lmem), hbuf[0]);\n          lemma_ApplyStoreBufferEntryCommutesWithConvert(lmem, lbuf[0], hbuf[0], hmem1', hmem2');\n          lemma_ApplyStoreBufferCommutesWithConvert(lmem', lbuf[1..], hbuf[1..], hmem1, hmem2);\n        }\n      \";\n      pgp.AddLemma(str, \"utility\");\n\n      str = @\"\n        lemma lemma_GetThreadLocalViewCommutesWithConvert(ls:LState, hs:HState, tid:Armada_ThreadHandle)\n          requires hs == ConvertTotalState_LH(ls)\n          requires tid in ls.threads;\n          ensures  ConvertSharedMemory_LH(L.Armada_GetThreadLocalView(ls, tid)) == H.Armada_GetThreadLocalView(hs, tid)\n        {\n          assert tid in hs.threads;\n          lemma_ApplyStoreBufferCommutesWithConvert(ls.mem, ls.threads[tid].storeBuffer,\n                                                    hs.threads[tid].storeBuffer,\n                                                    ConvertSharedMemory_LH(L.Armada_GetThreadLocalView(ls, tid)),\n                                                    H.Armada_GetThreadLocalView(hs, tid));\n        }\n      \";\n      pgp.AddLemma(str, \"utility\");\n\n      str = @\"\n        lemma lemma_GetThreadLocalViewAlwaysCommutesWithConvert()\n          ensures forall ls:L.Armada_TotalState, tid:Armada_ThreadHandle\n                    {:trigger L.Armada_GetThreadLocalView(ls, tid)}\n                    :: tid in ls.threads ==>\n                    ConvertSharedMemory_LH(L.Armada_GetThreadLocalView(ls, tid)) == H.Armada_GetThreadLocalView(ConvertTotalState_LH(ls), tid)\n        {\n          forall ls:L.Armada_TotalState, tid:Armada_ThreadHandle {:trigger L.Armada_GetThreadLocalView(ls, tid)}\n            | tid in ls.threads\n            ensures ConvertSharedMemory_LH(L.Armada_GetThreadLocalView(ls, tid)) ==\n                    H.Armada_GetThreadLocalView(ConvertTotalState_LH(ls), tid)\n          {\n              var hs := ConvertTotalState_LH(ls);\n              lemma_GetThreadLocalViewCommutesWithConvert(ls, hs, tid);\n          }\n        }\n      \";\n      pgp.AddLemma(str, \"utility\");\n\n      str = @\"\n        lemma lemma_StoreBufferAppendConversion(buf: seq<L.Armada_StoreBufferEntry>, entry: L.Armada_StoreBufferEntry)\n          ensures  ConvertStoreBuffer_LH(buf + [entry]) == ConvertStoreBuffer_LH(buf) + [ConvertStoreBufferEntry_LH(entry)]\n        {\n          assert [entry][1..] == [];\n\n          if |buf| == 0 {\n            assert buf + [entry] == [entry];\n            assert ConvertStoreBuffer_LH(buf + [entry]) == ConvertStoreBuffer_LH([entry]);\n            assert ConvertStoreBuffer_LH(buf) == [];\n\n            calc {\n                ConvertStoreBuffer_LH([entry]);\n                [ConvertStoreBufferEntry_LH(entry)] + ConvertStoreBuffer_LH([entry][1..]);\n                [ConvertStoreBufferEntry_LH(entry)] + ConvertStoreBuffer_LH([]);\n                [ConvertStoreBufferEntry_LH(entry)] + [];\n                [ConvertStoreBufferEntry_LH(entry)];\n            }\n          }\n          else {\n            calc {\n              ConvertStoreBuffer_LH(buf + [entry]);\n              {\n                assert buf == [buf[0]] + buf[1..];\n              }\n              ConvertStoreBuffer_LH([buf[0]] + buf[1..] + [entry]);\n              {\n                assert [buf[0]] + buf[1..] + [entry] == [buf[0]] + (buf[1..] + [entry]);\n              }\n              ConvertStoreBuffer_LH([buf[0]] + (buf[1..] + [entry]));\n            }\n            calc {\n              ConvertStoreBuffer_LH(buf + [entry]);\n              ConvertStoreBuffer_LH([buf[0]] + (buf[1..] + [entry]));\n              [ConvertStoreBufferEntry_LH(buf[0])] + ConvertStoreBuffer_LH(buf[1..] + [entry]);\n            }\n            lemma_StoreBufferAppendConversion(buf[1..], entry);\n            calc {\n              ConvertStoreBuffer_LH(buf + [entry]);\n              [ConvertStoreBufferEntry_LH(buf[0])] + (ConvertStoreBuffer_LH(buf[1..]) + [ConvertStoreBufferEntry_LH(entry)]);\n              [ConvertStoreBufferEntry_LH(buf[0])] + ConvertStoreBuffer_LH(buf[1..]) + [ConvertStoreBufferEntry_LH(entry)];\n              ConvertStoreBuffer_LH(buf) + [ConvertStoreBufferEntry_LH(entry)];\n            }\n          }\n        }\n      \";\n      pgp.AddLemma(str, \"utility\");\n\n      str = @\"\n        lemma lemma_StoreBufferAppendAlwaysCommutesWithConvert()\n          ensures forall lbuf: seq<L.Armada_StoreBufferEntry>, lentry: L.Armada_StoreBufferEntry {:trigger L.Armada_StoreBufferAppend(lbuf, lentry)} :: H.Armada_StoreBufferAppend(ConvertStoreBuffer_LH(lbuf), ConvertStoreBufferEntry_LH(lentry)) == ConvertStoreBuffer_LH(L.Armada_StoreBufferAppend(lbuf, lentry))\n        {\n          forall lbuf: seq<L.Armada_StoreBufferEntry>, lentry: L.Armada_StoreBufferEntry {:trigger L.Armada_StoreBufferAppend(lbuf, lentry)}\n            ensures H.Armada_StoreBufferAppend(ConvertStoreBuffer_LH(lbuf), ConvertStoreBufferEntry_LH(lentry)) == ConvertStoreBuffer_LH(L.Armada_StoreBufferAppend(lbuf, lentry))\n          {\n            lemma_StoreBufferAppendConversion(lbuf, lentry);\n          }\n        }\n      \";\n      pgp.AddLemma(str, \"utility\");\n\n      str = @\"\n        lemma lemma_ConvertStoreBufferCommutesOverBeheadment(buf:seq<L.Armada_StoreBufferEntry>)\n          requires |buf| > 0\n          ensures  ConvertStoreBuffer_LH(buf[1..]) == ConvertStoreBuffer_LH(buf)[1..]\n        {\n          var hbuf1 := ConvertStoreBuffer_LH(buf[1..]);\n          var hbuf2 := ConvertStoreBuffer_LH(buf)[1..];\n          assert |hbuf1| == |hbuf2| == |buf| - 1;\n\n          forall i | 0 <= i < |buf| - 1\n            ensures hbuf1[i] == hbuf2[i]\n          {\n          }\n\n          assert hbuf1 == hbuf2;\n        }\n      \";\n      pgp.AddLemma(str, \"utility\");\n    }\n\n    protected virtual void GenerateAppendStoreBufferOtherWay()\n    {\n      if (calledGenerateAppendStoreBufferOtherWay)\n      {\n        return;\n      }\n      calledGenerateAppendStoreBufferOtherWay= true;\n      string str;\n\n      str = @\"\n        function ApplyStoreBufferOtherWay_L(mem: L.Armada_SharedMemory, storeBuffer: seq<L.Armada_StoreBufferEntry>): (mem': L.Armada_SharedMemory)\n          decreases |storeBuffer|\n        {\n          if |storeBuffer| == 0 then\n            mem\n          else\n            L.Armada_ApplyStoreBufferEntry(ApplyStoreBufferOtherWay_L(mem, all_but_last(storeBuffer)), last(storeBuffer))\n        }\n      \";\n      pgp.AddFunction(str, \"utility\");\n\n      str = @\"\n        function ApplyStoreBufferOtherWay_H(mem: H.Armada_SharedMemory, storeBuffer: seq<H.Armada_StoreBufferEntry>): (mem': H.Armada_SharedMemory)\n          decreases |storeBuffer|\n        {\n          if |storeBuffer| == 0 then\n            mem\n          else\n            H.Armada_ApplyStoreBufferEntry(ApplyStoreBufferOtherWay_H(mem, all_but_last(storeBuffer)), last(storeBuffer))\n        }\n      \";\n      pgp.AddFunction(str, \"utility\");\n\n      str = @\"\n        lemma lemma_ApplyStoreBufferOtherWayEquivalent_L(mem: L.Armada_SharedMemory, storeBuffer: seq<L.Armada_StoreBufferEntry>)\n          ensures L.Armada_ApplyStoreBuffer(mem, storeBuffer) == ApplyStoreBufferOtherWay_L(mem, storeBuffer)\n          decreases |storeBuffer|\n        {\n          if |storeBuffer| == 0 || |storeBuffer| == 1 {\n              return;\n          }\n\n          var mem' := L.Armada_ApplyStoreBufferEntry(mem, storeBuffer[0]);\n          calc {\n              L.Armada_ApplyStoreBuffer(mem, storeBuffer);\n              L.Armada_ApplyStoreBuffer(mem', storeBuffer[1..]);\n              { lemma_ApplyStoreBufferOtherWayEquivalent_L(mem', storeBuffer[1..]); }\n              ApplyStoreBufferOtherWay_L(mem', storeBuffer[1..]);\n              L.Armada_ApplyStoreBufferEntry(ApplyStoreBufferOtherWay_L(mem', all_but_last(storeBuffer[1..])), last(storeBuffer[1..]));\n              { assert last(storeBuffer[1..]) == last(storeBuffer); }\n              L.Armada_ApplyStoreBufferEntry(ApplyStoreBufferOtherWay_L(mem', all_but_last(storeBuffer[1..])), last(storeBuffer));\n              { lemma_ApplyStoreBufferOtherWayEquivalent_L(mem', all_but_last(storeBuffer[1..])); }\n              L.Armada_ApplyStoreBufferEntry(L.Armada_ApplyStoreBuffer(mem', all_but_last(storeBuffer[1..])), last(storeBuffer));\n              L.Armada_ApplyStoreBufferEntry(L.Armada_ApplyStoreBuffer(mem, [storeBuffer[0]] + all_but_last(storeBuffer[1..])), last(storeBuffer));\n              { assert [storeBuffer[0]] + all_but_last(storeBuffer[1..]) == all_but_last(storeBuffer); }\n              L.Armada_ApplyStoreBufferEntry(L.Armada_ApplyStoreBuffer(mem, all_but_last(storeBuffer)), last(storeBuffer));\n              { lemma_ApplyStoreBufferOtherWayEquivalent_L(mem, all_but_last(storeBuffer)); }\n              L.Armada_ApplyStoreBufferEntry(ApplyStoreBufferOtherWay_L(mem, all_but_last(storeBuffer)), last(storeBuffer));\n              ApplyStoreBufferOtherWay_L(mem, storeBuffer);\n          }\n        }\n      \";\n      pgp.AddLemma(str, \"utility\");\n\n      str = @\"\n        lemma lemma_ApplyStoreBufferOtherWayEquivalent_H(mem: H.Armada_SharedMemory, storeBuffer: seq<H.Armada_StoreBufferEntry>)\n          ensures H.Armada_ApplyStoreBuffer(mem, storeBuffer) == ApplyStoreBufferOtherWay_H(mem, storeBuffer)\n          decreases |storeBuffer|\n        {\n          if |storeBuffer| == 0 || |storeBuffer| == 1 {\n              return;\n          }\n\n          var mem' := H.Armada_ApplyStoreBufferEntry(mem, storeBuffer[0]);\n          calc {\n              H.Armada_ApplyStoreBuffer(mem, storeBuffer);\n              H.Armada_ApplyStoreBuffer(mem', storeBuffer[1..]);\n              { lemma_ApplyStoreBufferOtherWayEquivalent_H(mem', storeBuffer[1..]); }\n              ApplyStoreBufferOtherWay_H(mem', storeBuffer[1..]);\n              H.Armada_ApplyStoreBufferEntry(ApplyStoreBufferOtherWay_H(mem', all_but_last(storeBuffer[1..])), last(storeBuffer[1..]));\n              { assert last(storeBuffer[1..]) == last(storeBuffer); }\n              H.Armada_ApplyStoreBufferEntry(ApplyStoreBufferOtherWay_H(mem', all_but_last(storeBuffer[1..])), last(storeBuffer));\n              { lemma_ApplyStoreBufferOtherWayEquivalent_H(mem', all_but_last(storeBuffer[1..])); }\n              H.Armada_ApplyStoreBufferEntry(H.Armada_ApplyStoreBuffer(mem', all_but_last(storeBuffer[1..])), last(storeBuffer));\n              H.Armada_ApplyStoreBufferEntry(H.Armada_ApplyStoreBuffer(mem, [storeBuffer[0]] + all_but_last(storeBuffer[1..])), last(storeBuffer));\n              { assert [storeBuffer[0]] + all_but_last(storeBuffer[1..]) == all_but_last(storeBuffer); }\n              H.Armada_ApplyStoreBufferEntry(H.Armada_ApplyStoreBuffer(mem, all_but_last(storeBuffer)), last(storeBuffer));\n              { lemma_ApplyStoreBufferOtherWayEquivalent_H(mem, all_but_last(storeBuffer)); }\n              H.Armada_ApplyStoreBufferEntry(ApplyStoreBufferOtherWay_H(mem, all_but_last(storeBuffer)), last(storeBuffer));\n              ApplyStoreBufferOtherWay_H(mem, storeBuffer);\n          }\n        }\n      \";\n      pgp.AddLemma(str, \"utility\");\n\n      str = @\"\n        lemma lemma_ApplyStoreBufferOtherWayAlwaysEquivalent()\n          ensures forall mem, storeBuffer :: L.Armada_ApplyStoreBuffer(mem, storeBuffer) == ApplyStoreBufferOtherWay_L(mem, storeBuffer)\n          ensures forall mem, storeBuffer :: H.Armada_ApplyStoreBuffer(mem, storeBuffer) == ApplyStoreBufferOtherWay_H(mem, storeBuffer)\n        {\n          forall mem, storeBuffer\n            ensures L.Armada_ApplyStoreBuffer(mem, storeBuffer) == ApplyStoreBufferOtherWay_L(mem, storeBuffer)\n          {\n            lemma_ApplyStoreBufferOtherWayEquivalent_L(mem, storeBuffer);\n          }\n\n          forall mem, storeBuffer\n            ensures H.Armada_ApplyStoreBuffer(mem, storeBuffer) == ApplyStoreBufferOtherWay_H(mem, storeBuffer)\n          {\n            lemma_ApplyStoreBufferOtherWayEquivalent_H(mem, storeBuffer);\n          }\n        }\n      \";\n      pgp.AddLemma(str, \"utility\");\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    /// Store buffers\n    ////////////////////////////////////////////////////////////////////////\n\n    protected void GenerateGenericStoreBufferLemmas_L()\n    {\n      string str;\n\n      str = @\"\n        lemma lemma_ApplyStoreBufferCommutesWithAppend_L(\n          mem: L.Armada_SharedMemory,\n          buf:seq<L.Armada_StoreBufferEntry>,\n          entry:L.Armada_StoreBufferEntry\n          )\n          ensures L.Armada_ApplyStoreBuffer(mem, L.Armada_StoreBufferAppend(buf, entry)) ==\n                  L.Armada_ApplyStoreBufferEntry(L.Armada_ApplyStoreBuffer(mem, buf), entry)\n          decreases |buf|\n        {\n          if |buf| > 0 {\n            var mem' := L.Armada_ApplyStoreBufferEntry(mem, buf[0]);\n            var buf' := L.Armada_StoreBufferAppend(buf, entry);\n            assert buf'[0] == buf[0];\n            assert buf'[1..] == buf[1..] + [entry];\n            calc {\n              L.Armada_ApplyStoreBuffer(mem, L.Armada_StoreBufferAppend(buf, entry));\n              L.Armada_ApplyStoreBuffer(mem, buf');\n              L.Armada_ApplyStoreBuffer(L.Armada_ApplyStoreBufferEntry(mem, buf'[0]), buf'[1..]);\n              L.Armada_ApplyStoreBuffer(mem', buf'[1..]);\n              { lemma_ApplyStoreBufferCommutesWithAppend_L(mem', buf[1..], entry); }\n              L.Armada_ApplyStoreBufferEntry(L.Armada_ApplyStoreBuffer(mem', buf[1..]), entry);\n              L.Armada_ApplyStoreBufferEntry(L.Armada_ApplyStoreBuffer(mem, buf), entry);\n            }\n          }\n        }\n      \";\n      pgp.AddLemma(str, \"utility\");\n\n      str = @\"\n        lemma lemma_ApplyStoreBufferCommutesWithAppendAlways_L()\n          ensures forall mem: L.Armada_SharedMemory, buf:seq<L.Armada_StoreBufferEntry>, entry:L.Armada_StoreBufferEntry ::\n                    L.Armada_ApplyStoreBuffer(mem, L.Armada_StoreBufferAppend(buf, entry)) ==\n                    L.Armada_ApplyStoreBufferEntry(L.Armada_ApplyStoreBuffer(mem, buf), entry)\n        {\n          forall mem: L.Armada_SharedMemory, buf:seq<L.Armada_StoreBufferEntry>, entry:L.Armada_StoreBufferEntry\n            ensures L.Armada_ApplyStoreBuffer(mem, L.Armada_StoreBufferAppend(buf, entry)) ==\n                    L.Armada_ApplyStoreBufferEntry(L.Armada_ApplyStoreBuffer(mem, buf), entry)\n          {\n            lemma_ApplyStoreBufferCommutesWithAppend_L(mem, buf, entry);\n          }\n        }\n      \";\n      pgp.AddLemma(str, \"utility\");\n\n      str = @\"\n        predicate SharedMemoryHasPredecessor_L(mem':L.Armada_SharedMemory, entry:L.Armada_StoreBufferEntry)\n        {\n          exists mem :: mem' == L.Armada_ApplyStoreBufferEntry(mem, entry)\n        }\n      \";\n      pgp.AddPredicate(str, \"utility\");\n\n      str = @\"\n        lemma lemma_StoreBufferAppendHasEffectOfAppendedEntryAlways_L()\n          ensures forall mem:L.Armada_SharedMemory, buf:seq<L.Armada_StoreBufferEntry>, entry:L.Armada_StoreBufferEntry\n                    {:trigger L.Armada_ApplyStoreBuffer(mem, L.Armada_StoreBufferAppend(buf, entry))} ::\n                    SharedMemoryHasPredecessor_L(L.Armada_ApplyStoreBuffer(mem, L.Armada_StoreBufferAppend(buf, entry)), entry)\n        {\n          forall mem:L.Armada_SharedMemory, buf:seq<L.Armada_StoreBufferEntry>, entry:L.Armada_StoreBufferEntry\n                    {:trigger L.Armada_ApplyStoreBuffer(mem, L.Armada_StoreBufferAppend(buf, entry))}\n            ensures SharedMemoryHasPredecessor_L(L.Armada_ApplyStoreBuffer(mem, L.Armada_StoreBufferAppend(buf, entry)), entry)\n          {\n            lemma_ApplyStoreBufferCommutesWithAppend_L(mem, buf, entry);\n            var mem_prev := L.Armada_ApplyStoreBuffer(mem, buf);\n            assert L.Armada_ApplyStoreBuffer(mem, L.Armada_StoreBufferAppend(buf, entry)) ==\n                   L.Armada_ApplyStoreBufferEntry(mem_prev, entry);\n          }\n        }\n      \";\n      pgp.AddLemma(str, \"utility\");\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    /// Invariants\n    ////////////////////////////////////////////////////////////////////////\n\n    protected void AddInvariant(InvariantInfo inv)\n    {\n      invariants.Add(inv);\n    }\n\n    private void GenerateInductiveInv(ProofGenerationParams pgp, bool onlyNonstoppingPaths)\n    {\n      var invNames = invariants.Select(x => x.Name).ToList();\n\n      var conjuncts = new List<string>();\n      if (onlyNonstoppingPaths) {\n        conjuncts.Add(\"s.s.stop_reason.Armada_NotStopped?\");\n      }\n      conjuncts.AddRange(invariants.Select(inv => $\"{inv.Name}(s)\"));\n      \n      string str = $@\"\n        predicate InductiveInv(s:LPlusState)\n        {{\n          { AH.CombineStringsWithAnd(conjuncts) }\n        }}\n      \";\n      pgp.AddPredicate(str, \"defs\");\n    }\n\n    private void GenerateInitImpliesInductiveInvLemma(ProofGenerationParams pgp)\n    {\n      string str = @\"\n        lemma lemma_InitImpliesInductiveInv(s:LPlusState)\n          requires LPlus_Init(s)\n          ensures  InductiveInv(s)\n        {\n      \";\n      str += String.Concat(invariants.Select(inv => $\"{inv.InitLemmaName}(s);\\n\"));\n      str += \"  }\\n\";\n      pgp.AddLemma(str, \"invariants\");\n    }\n\n    private void GenerateAtomicPathMaintainsInductiveInvLemma(ProofGenerationParams pgp)\n    {\n      string str = @\"\n        lemma lemma_AtomicPathMaintainsInductiveInv(s: LPlusState, s': LPlusState, path: LAtomic_Path, tid: Armada_ThreadHandle)\n          requires InductiveInv(s)\n          requires LAtomic_ValidPath(s, path, tid)\n          requires s' == LAtomic_GetStateAfterPath(s, path, tid)\n          ensures  InductiveInv(s')\n        {\n      \";\n      str += String.Concat(invariants.Select(inv => $\"{inv.NextLemmaName}(s, s', path, tid);\\n\"));\n      str += \"}\\n\";\n      pgp.AddLemma(str, \"invariants\");\n    }\n\n    public void GenerateInvariantProof(ProofGenerationParams pgp, bool onlyNonstoppingPaths = false)\n    {\n      if (lAtomic == null) {\n        AH.PrintError(pgp.prog, \"Internal error:  Must call GenerateProofHeader before calling GenerateInvariantProof\");\n      }\n\n      foreach (var inv in invariants) {\n        inv.GenerateProofs(pgp, invariants, lAtomic, onlyNonstoppingPaths);\n      }\n\n      GenerateInductiveInv(pgp, onlyNonstoppingPaths);\n      GenerateInitImpliesInductiveInvLemma(pgp);\n      GenerateAtomicPathMaintainsInductiveInvLemma(pgp);\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    /// Lemmas about path lifting\n    ////////////////////////////////////////////////////////////////////////\n\n    protected virtual void GenerateLiftAtomicPathLemmaForNormalPath(AtomicPath atomicPath,\n                                                                    string typeComparison = \"HAtomic_GetPathType(hpath) == ty\",\n                                                                    string extraSignatureLines = \"\",\n                                                                    string extraProof = \"\")\n    {\n      string convertParams = stateDependentConvertStep ? \"ls, lpath, tid\" : \"lpath\";\n      var hAtomicPath = pathMap[atomicPath];\n      var lpr = new PrefixedVarsPathPrinter(lAtomic);\n      var hpr = new PrefixedVarsPathPrinter(hAtomic);\n      var prioritizationAttrs = Prioritizer.GetPrioritizationAttributesForLiftAtomicPath(atomicPath, hAtomicPath);\n      var str = $@\"\n        lemma {prioritizationAttrs} lemma_LiftAtomicPath_{atomicPath.Name}(ls: LPlusState, lpath: LAtomic_Path, tid: Armada_ThreadHandle)\n          requires InductiveInv(ls)\n          requires LAtomic_ValidPath(ls, lpath, tid)\n          requires lpath.LAtomic_Path_{atomicPath.Name}?\n          { extraSignatureLines }\n          ensures  var ls' := LAtomic_GetStateAfterPath(ls, lpath, tid);\n                   var hs := ConvertTotalState_LPlusH(ls);\n                   var hpath := ConvertAtomicPath_LH({convertParams});\n                   var hs' := HAtomic_GetStateAfterPath(hs, hpath, tid);\n                   var ty := LAtomic_GetPathType(lpath);\n                   && {typeComparison}\n                   && HAtomic_ValidPath(hs, hpath, tid)\n                   && hs' == ConvertTotalState_LPlusH(ls')\n                   && {atomicPath.OptionalNotForOK}ls'.s.stop_reason.Armada_NotStopped?\n                   && {atomicPath.OptionalNotForOK}hs'.stop_reason.Armada_NotStopped?\n        {{\n          { lpr.GetOpenValidPathInvocation(atomicPath) }\n          var locv: H.Armada_SharedMemory := H.Armada_GetThreadLocalView(ConvertTotalState_LPlusH(ls), tid);\n          var ls' := LAtomic_GetStateAfterPath(ls, lpath, tid);\n          var hs := ConvertTotalState_LPlusH(ls);\n          var hpath := ConvertAtomicPath_LH({convertParams});\n          var hs' := ConvertTotalState_LPlusH(ls');\n\n          { hpr.GetOpenPathInvocation(hAtomicPath) }\n\n          lemma_GetThreadLocalViewAlwaysCommutesWithConvert();\n          lemma_StoreBufferAppendAlwaysCommutesWithConvert();\n          { extraProof }\n          ProofCustomizationGoesHere();\n      \";\n      if (atomicPath.Stopping) {\n        str += \"assert !hs'.stop_reason.Armada_NotStopped?;\\n\";\n      }\n      else {\n        str += @\"\n          assert ls'.s.stop_reason.Armada_NotStopped?;\n          var alt_hs' := HAtomic_GetStateAfterPath(hs, hpath, tid);\n          assert hs'.stop_reason == alt_hs'.stop_reason;\n        \";\n        if (atomicPath.LastNextRoutine.nextType == NextType.TerminateThread) {\n          str += @\"\n            assert tid !in hs'.threads;\n            assert tid !in alt_hs'.threads;\n          \";\n        }\n        else {\n          str += \"assert hs'.threads[tid] == alt_hs'.threads[tid];\\n\";\n        }\n        foreach (var tup in atomicPath.NextRoutinesWithIndices) {\n          var nextRoutine = tup.Item1;\n          if (nextRoutine.nextType == NextType.CreateThread) {\n            var i = tup.Item2;\n            str += $@\"\n              assert  hs'.threads[lsteps.step{i}.params_{nextRoutine.NameSuffix}.newtid] ==\n                      alt_hs'.threads[lsteps.step{i}.params_{nextRoutine.NameSuffix}.newtid];\n            \";\n          }\n        }\n        str += @\"\n          forall other_tid\n            ensures other_tid !in hs'.threads ==> other_tid !in alt_hs'.threads\n            ensures other_tid in hs'.threads ==> other_tid in alt_hs'.threads && hs'.threads[other_tid] == alt_hs'.threads[other_tid]\n          {\n          }\n          assert hs'.threads == alt_hs'.threads;\n          assert hs'.mem == alt_hs'.mem;\n          assert hs' == alt_hs';\n        \";\n      }\n//      str += hpr.GetAssertValidPathInvocation(hAtomicPath);\n      str += \"}\\n\";\n      pgp.AddLemma(str, \"lift\");\n    }\n\n    protected virtual void GenerateLiftAtomicPathLemmaForTauPath(AtomicPath atomicPath,\n                                                                 string typeComparison = \"HAtomic_GetPathType(hpath) == ty\",\n                                                                 string extraSignatureLines = \"\")\n    {\n      string convertParams = stateDependentConvertStep ? \"ls, lpath, tid\" : \"lpath\";\n      var hAtomicPath = pathMap[atomicPath];\n      var lpr = new PrefixedVarsPathPrinter(lAtomic);\n      var hpr = new PrefixedVarsPathPrinter(hAtomic);\n      var str = $@\"\n        lemma lemma_LiftAtomicPath_Tau(ls: LPlusState, lpath: LAtomic_Path, tid: Armada_ThreadHandle)\n          requires InductiveInv(ls)\n          requires LAtomic_ValidPath(ls, lpath, tid)\n          requires lpath.LAtomic_Path_{atomicPath.Name}?\n          { extraSignatureLines }\n          ensures  var ls' := LAtomic_GetStateAfterPath(ls, lpath, tid);\n                   var hs := ConvertTotalState_LPlusH(ls);\n                   var hpath := ConvertAtomicPath_LH({convertParams});\n                   var hs' := HAtomic_GetStateAfterPath(hs, hpath, tid);\n                   var ty := LAtomic_GetPathType(lpath);\n                   && {typeComparison}\n                   && HAtomic_ValidPath(hs, hpath, tid)\n                   && hs' == ConvertTotalState_LPlusH(ls')\n                   && ls'.s.stop_reason.Armada_NotStopped? == hs'.stop_reason.Armada_NotStopped?\n        {{\n          { lpr.GetOpenValidPathInvocation(atomicPath) }\n          var ls' := LAtomic_GetStateAfterPath(ls, lpath, tid);\n          var hs := ConvertTotalState_LPlusH(ls);\n          var hpath := ConvertAtomicPath_LH({convertParams});\n          var hs' := ConvertTotalState_LPlusH(ls');\n\n          var lentry := ls.s.threads[tid].storeBuffer[0];\n          var hentry := hs.threads[tid].storeBuffer[0];\n          var lmem := ls.s.mem;\n          var hmem1 := ConvertSharedMemory_LH(L.Armada_ApplyStoreBufferEntry(lmem, lentry));\n          var hmem2 := H.Armada_ApplyStoreBufferEntry(ConvertSharedMemory_LH(lmem), hentry);\n\n          lemma_ApplyStoreBufferEntryCommutesWithConvert(lmem, lentry, hentry, hmem1, hmem2);\n\n          { hpr.GetOpenPathInvocation(hAtomicPath) }\n\n          var alt_hs' := HAtomic_GetStateAfterPath(hs, hpath, tid);\n          ProofCustomizationGoesHere();\n\n          assert hs'.threads[tid] == alt_hs'.threads[tid];\n          assert hs'.threads == alt_hs'.threads;\n          assert hs' == alt_hs';\n\n          /* { hpr.GetAssertValidPathInvocation(hAtomicPath) } */\n        }}\n      \";\n      pgp.AddLemma(str, \"lift\");\n    }\n\n    protected virtual void GenerateLiftAtomicPathLemmaForUnmappedPath(AtomicPath atomicPath, string extraSignatureLines)\n    {\n      var lpr = new PrefixedVarsPathPrinter(lAtomic);\n      var str = $@\"\n        lemma lemma_LiftAtomicPath_{atomicPath.Name}(ls: LPlusState, lpath: LAtomic_Path, tid: Armada_ThreadHandle)\n          requires InductiveInv(ls)\n          requires LAtomic_ValidPath(ls, lpath, tid)\n          requires lpath.LAtomic_Path_{atomicPath.Name}?\n          { extraSignatureLines }\n          ensures  false\n        {{\n          { lpr.GetOpenValidPathInvocation(atomicPath) }\n          var ls' := LAtomic_GetStateAfterPath(ls, lpath, tid);\n\n          lemma_GetThreadLocalViewAlwaysCommutesWithConvert();\n          lemma_StoreBufferAppendAlwaysCommutesWithConvert();\n          ProofCustomizationGoesHere();\n        }}\n      \";\n      pgp.AddLemma(str, \"lift\");\n    }\n\n    protected virtual void GenerateLiftAtomicPathLemmas(string typeComparison = \"HAtomic_GetPathType(hpath) == ty\",\n                                                        string extraSignatureLines = \"\", string extraProof = \"\")\n    {\n      var finalCases = \"\";\n\n      foreach (var atomicPath in lAtomic.AtomicPaths) {\n        if (atomicPath.Tau) {\n          GenerateLiftAtomicPathLemmaForTauPath(atomicPath, typeComparison, extraSignatureLines);\n        }\n        else if (pathMap.ContainsKey(atomicPath) && pathMap[atomicPath] != null) {\n          GenerateLiftAtomicPathLemmaForNormalPath(atomicPath, typeComparison, extraSignatureLines, extraProof);\n        }\n        else {\n          GenerateLiftAtomicPathLemmaForUnmappedPath(atomicPath, extraSignatureLines);\n        }\n        finalCases += $\"case LAtomic_Path_{atomicPath.Name}(_) => lemma_LiftAtomicPath_{atomicPath.Name}(ls, lpath, tid);\\n\";\n      }\n\n      string convertParams = stateDependentConvertStep ? \"ls, lpath, tid\" : \"lpath\";\n      string str = $@\"\n        lemma lemma_LiftAtomicPath(ls: LPlusState, lpath: LAtomic_Path, tid: Armada_ThreadHandle)\n          requires InductiveInv(ls)\n          requires LAtomic_ValidPath(ls, lpath, tid)\n          { extraSignatureLines }\n          ensures  var ls' := LAtomic_GetStateAfterPath(ls, lpath, tid);\n                   var hs := ConvertTotalState_LPlusH(ls);\n                   var hpath := ConvertAtomicPath_LH({convertParams});\n                   var hs' := HAtomic_GetStateAfterPath(hs, hpath, tid);\n                   var ty := LAtomic_GetPathType(lpath);\n                   && {typeComparison}\n                   && HAtomic_ValidPath(hs, hpath, tid)\n                   && hs' == ConvertTotalState_LPlusH(ls')\n                   && ls'.s.stop_reason.Armada_NotStopped? == hs'.stop_reason.Armada_NotStopped?\n        {{\n          match lpath {{\n            {finalCases}\n          }}\n        }}\n      \";\n      pgp.AddLemma(str, \"lift\");\n    }\n\n    protected virtual void GenerateLiftingRelation()\n    {\n      string str = @\"\n        predicate LiftingRelation(ls:LPlusState, hs:HState)\n        {\n          hs == ConvertTotalState_LPlusH(ls)\n        }\n      \";\n      pgp.AddPredicate(str, \"defs\");\n    }\n\n    protected virtual void GenerateEstablishAtomicPathLiftableLemma()\n    {\n      var convertParams = stateDependentConvertStep ? \"ls, lpath, tid\" : \"lpath\";\n      string str = $@\"\n        lemma lemma_EstablishAtomicPathLiftable(\n          lasf:AtomicSpecFunctions<LPlusState, LAtomic_Path, L.Armada_PC>,\n          hasf:AtomicSpecFunctions<HState, HAtomic_Path, H.Armada_PC>,\n          ls: LPlusState,\n          lpath: LAtomic_Path,\n          tid: Armada_ThreadHandle,\n          hs: HState\n          ) returns (\n          hpath: HAtomic_Path\n          )\n          requires lasf == LAtomic_GetSpecFunctions()\n          requires hasf == HAtomic_GetSpecFunctions()\n          requires InductiveInv(ls)\n          requires LiftingRelation(ls, hs)\n          requires LAtomic_ValidPath(ls, lpath, tid)\n          ensures  LiftAtomicPathSuccessful(lasf, hasf, InductiveInv, LiftingRelation, ls, lpath, tid, hs, hpath)\n        {{\n          var ls' := LAtomic_GetStateAfterPath(ls, lpath, tid);\n          lemma_AtomicPathMaintainsInductiveInv(ls, ls', lpath, tid);\n          assert InductiveInv(ls');\n          lemma_LiftAtomicPath(ls, lpath, tid);\n          hpath := ConvertAtomicPath_LH({convertParams});\n          assert LiftAtomicPathSuccessful(lasf, hasf, InductiveInv, LiftingRelation, ls, lpath, tid, hs, hpath);\n        }}\n      \";\n      pgp.AddLemma(str);\n    }\n\n    protected virtual void GenerateEstablishAtomicPathsLiftableLemma(bool skippable, bool introducible)\n    {\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/strategies/generic/LiftAtomicToAtomic.i.dfy\");\n      pgp.MainProof.AddImport(\"LiftAtomicToAtomicModule\");\n\n      string str = @\"\n        lemma lemma_EstablishAtomicPathsLiftable(\n          lasf:AtomicSpecFunctions<LPlusState, LAtomic_Path, L.Armada_PC>,\n          hasf:AtomicSpecFunctions<HState, HAtomic_Path, H.Armada_PC>,\n          inv:LPlusState->bool,\n          relation:(LPlusState, HState)->bool\n      \";\n      if (introducible) {\n        str += \", progress_measure:(HState, LAtomic_Path, Armada_ThreadHandle)->(int, int)\";\n      }\n      str += @\"\n          )\n          requires lasf == LAtomic_GetSpecFunctions()\n          requires hasf == HAtomic_GetSpecFunctions()\n          requires inv == InductiveInv\n          requires relation == LiftingRelation\n      \";\n      if (introducible) {\n        str += @\"\n          requires progress_measure == ProgressMeasure\n        \";\n      }\n      str += @\"\n          ensures forall ls, lpath, hs, tid ::\n                    inv(ls) && relation(ls, hs) && lasf.path_valid(ls, lpath, tid)\n      \";\n      if (skippable) {\n        str += \" && !AtomicPathSkippable(lasf, inv, relation, ls, lpath, tid, hs)\";\n      }\n      str += @\"\n                    ==> exists hpath :: LiftAtomicPathSuccessful(lasf, hasf, inv, relation, ls, lpath, tid, hs, hpath)\n      \";\n      if (introducible) {\n        str += @\"\n                                        || AtomicPathIntroduced(lasf, hasf, relation, progress_measure, ls, lpath, tid, hs, hpath)\n        \";\n      }\n      str += @\"\n        {\n          forall ls, lpath, hs, tid\n            | inv(ls) && relation(ls, hs) && lasf.path_valid(ls, lpath, tid)\n      \";\n      if (skippable) {\n        str += \" && !AtomicPathSkippable(lasf, inv, relation, ls, lpath, tid, hs)\";\n      }\n      str += @\"\n            ensures exists hpath :: LiftAtomicPathSuccessful(lasf, hasf, inv, relation, ls, lpath, tid, hs, hpath)\n      \";\n      if (introducible) {\n        str += @\"\n                                    || AtomicPathIntroduced(lasf, hasf, relation, progress_measure, ls, lpath, tid, hs, hpath)\n        \";\n      }\n      str += @\"\n          {\n            var hpath := lemma_EstablishAtomicPathLiftable(lasf, hasf, ls, lpath, tid, hs);\n          }\n        }\n      \";\n      pgp.AddLemma(str);\n    }\n\n    protected virtual void GenerateEstablishInitRequirementsLemma()\n    {\n      string str = @\"\n        lemma lemma_EstablishInitRequirements(\n          lasf:AtomicSpecFunctions<LPlusState, LAtomic_Path, L.Armada_PC>,\n          hasf:AtomicSpecFunctions<HState, HAtomic_Path, H.Armada_PC>,\n          inv:LPlusState->bool,\n          relation:(LPlusState, HState)->bool\n          )\n          requires lasf == LAtomic_GetSpecFunctions()\n          requires hasf == HAtomic_GetSpecFunctions()\n          requires inv == InductiveInv\n          requires relation == LiftingRelation\n          ensures  AtomicInitImpliesInv(lasf, inv)\n          ensures  forall ls :: lasf.init(ls) ==> exists hs :: hasf.init(hs) && relation(ls, hs)\n        {\n          forall ls | lasf.init(ls)\n            ensures inv(ls)\n            ensures exists hs :: hasf.init(hs) && relation(ls, hs)\n          {\n            lemma_InitImpliesInductiveInv(ls);\n            var hs := ConvertTotalState_LPlusH(ls);\n            var hconfig := ConvertConfig_LH(ls.config);\n            assert H.Armada_InitConfig(hs, hconfig);\n            assert hasf.init(hs) && relation(ls, hs);\n          }\n        }\n      \";\n      pgp.AddLemma(str);\n    }\n\n    protected virtual void GenerateEstablishStateOKRequirementLemma()\n    {\n      string str = @\"\n        lemma lemma_EstablishStateOKRequirement(\n          lasf:AtomicSpecFunctions<LPlusState, LAtomic_Path, L.Armada_PC>,\n          hasf:AtomicSpecFunctions<HState, HAtomic_Path, H.Armada_PC>,\n          relation:(LPlusState, HState)->bool\n          )\n          requires lasf == LAtomic_GetSpecFunctions()\n          requires hasf == HAtomic_GetSpecFunctions()\n          requires relation == LiftingRelation\n          ensures  forall ls, hs :: relation(ls, hs) ==> lasf.state_ok(ls) == hasf.state_ok(hs)\n        {\n        }\n      \";\n      pgp.AddLemma(str);\n    }\n\n    protected virtual void GenerateEstablishRelationRequirementLemma()\n    {\n      string str = @\"\n        lemma lemma_EstablishRelationRequirement(\n          lasf:AtomicSpecFunctions<LPlusState, LAtomic_Path, L.Armada_PC>,\n          hasf:AtomicSpecFunctions<HState, HAtomic_Path, H.Armada_PC>,\n          inv:LPlusState->bool,\n          relation:(LPlusState, HState)->bool,\n          refinement_relation:RefinementRelation<LPlusState, HState>\n          )\n          requires lasf == LAtomic_GetSpecFunctions()\n          requires hasf == HAtomic_GetSpecFunctions()\n          requires inv == InductiveInv\n          requires relation == LiftingRelation\n          requires refinement_relation == GetLPlusHRefinementRelation()\n          ensures  forall ls, hs :: inv(ls) && relation(ls, hs) ==> RefinementPair(ls, hs) in refinement_relation\n        {\n          forall ls, hs | inv(ls) && relation(ls, hs)\n            ensures RefinementPair(ls, hs) in refinement_relation\n          {\n          }\n        }\n      \";\n      pgp.AddLemma(str);\n    }\n\n    protected virtual void GenerateLiftLAtomicToHAtomicLemma(bool skippable, bool introducible)\n    {\n      string str = @\"\n        lemma lemma_LiftLAtomicToHAtomic() returns (refinement_relation:RefinementRelation<LPlusState, H.Armada_TotalState>)\n          ensures SpecRefinesSpec(AtomicSpec(LAtomic_GetSpecFunctions()), AtomicSpec(HAtomic_GetSpecFunctions()), refinement_relation)\n          ensures refinement_relation == GetLPlusHRefinementRelation()\n        {\n          var lasf := LAtomic_GetSpecFunctions();\n          var hasf := HAtomic_GetSpecFunctions();\n          var inv := InductiveInv;\n          var relation := LiftingRelation;\n          refinement_relation := GetLPlusHRefinementRelation();\n      \";\n      if (introducible) {\n        str += @\"\n          var progress_measure := ProgressMeasure;\n          lemma_EstablishAtomicPathsLiftable(lasf, hasf, inv, relation, progress_measure);\n        \";\n      }\n      else {\n        str += @\"\n          lemma_EstablishAtomicPathsLiftable(lasf, hasf, inv, relation);\n        \";\n      }\n      str += @\"\n          lemma_EstablishInitRequirements(lasf, hasf, inv, relation);\n          lemma_EstablishStateOKRequirement(lasf, hasf, relation);\n          lemma_EstablishRelationRequirement(lasf, hasf, inv, relation, refinement_relation);\n      \";\n      if (skippable) {\n        if (introducible) {\n          str += @\"\n          lemma_LiftAtomicToAtomicGivenAtomicPathsLiftableGeneral(lasf, hasf, inv, relation, progress_measure, refinement_relation);\n          \";\n        }\n        else {\n          str += @\"\n          lemma_LiftAtomicToAtomicGivenAtomicPathsSkippablyLiftable(lasf, hasf, inv, relation, refinement_relation);\n          \";\n        }\n      }\n      else if (introducible) {\n        str += @\"\n          lemma_LiftAtomicToAtomicGivenAtomicPathsIntroduciblyLiftable(lasf, hasf, inv, relation, progress_measure, refinement_relation);\n        \";\n      }\n      else {\n        str += @\"\n          lemma_LiftAtomicToAtomicGivenAtomicPathsLiftable(lasf, hasf, inv, relation, refinement_relation);\n        \";\n      }\n      str += \"}\\n\";\n      pgp.AddLemma(str);\n    }\n\n    protected void GenerateGenericAtomicPropertyLemmas()\n    {\n      string str;\n\n      str = $@\"\n        lemma lemma_LAtomic_AtomicInitImpliesOK()\n          ensures AtomicInitImpliesOK(LAtomic_GetSpecFunctions())\n        {{\n        }}\n      \";\n      pgp.AddLemma(str);\n\n      str = $@\"\n        lemma lemma_LAtomic_AtomicInitImpliesInv()\n          ensures AtomicInitImpliesInv(LAtomic_GetSpecFunctions(), InductiveInv)\n        {{\n          forall s | LAtomic_GetSpecFunctions().init(s)\n            ensures InductiveInv(s)\n          {{\n            lemma_InitImpliesInductiveInv(s);\n          }}\n        }}\n      \";\n      pgp.AddLemma(str);\n\n      str = $@\"\n        lemma lemma_LAtomic_AtomicPathPreservesInv()\n          ensures AtomicPathPreservesInv(LAtomic_GetSpecFunctions(), InductiveInv)\n        {{\n          var asf := LAtomic_GetSpecFunctions();\n          forall s, path, tid | InductiveInv(s) && asf.path_valid(s, path, tid)\n            ensures InductiveInv(asf.path_next(s, path, tid))\n          {{\n            var s' := asf.path_next(s, path, tid);\n            lemma_AtomicPathMaintainsInductiveInv(s, s', path, tid);\n          }}\n        }}\n      \";\n      pgp.AddLemma(str);\n    }\n\n    protected virtual void GenerateFinalProof()\n    {\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/strategies/refinement/RefinementConvolution.i.dfy\");\n      pgp.MainProof.AddImport(\"RefinementConvolutionModule\");\n\n      string str = @\"\n        lemma lemma_ProveRefinement()\n          ensures SpecRefinesSpec(L.Armada_Spec(), H.Armada_Spec(), GetLHRefinementRelation())\n        {\n          var rr1 := lemma_LSpecRefinesLPlusSpec();\n          var rr2 := lemma_LiftToAtomic();\n          var rr3 := lemma_LiftLAtomicToHAtomic();\n          var rr4 := lemma_LiftFromAtomic();\n          lemma_SpecRefinesSpecQuadrupleConvolution(\n            L.Armada_Spec(),\n            Armada_SpecFunctionsToSpec(LPlus_GetSpecFunctions()),\n            AtomicSpec(LAtomic_GetSpecFunctions()),\n            AtomicSpec(HAtomic_GetSpecFunctions()),\n            H.Armada_Spec(),\n            rr1,\n            rr2,\n            rr3,\n            rr4,\n            GetLHRefinementRelation()\n            );\n        }\n      \";\n      pgp.AddLemma(str);\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    /// PC functions\n    ////////////////////////////////////////////////////////////////////////\n\n    protected virtual void GeneratePCFunctions(bool low)\n    {\n      var c = low ? \"L\" : \"H\";\n      var symbols = low ? pgp.symbolsLow : pgp.symbolsHigh;\n\n      var methodNames = symbols.AllMethods.AllMethodNames;\n\n      string str;\n\n      str = $\"datatype {c}MethodName = \" + String.Join(\" | \", methodNames.Select(x => $\"{c}MethodName_{x}\"));\n      pgp.AddDatatype(str, \"specs\");\n\n      str = $@\"\n        function MethodToInstructionCount_{c}(m:{c}MethodName) : (v:int)\n          ensures v >= 0\n        {{\n          match m\n      \";\n      foreach (var methodName in methodNames)\n      {\n        var methodInfo = symbols.AllMethods.LookupMethod(methodName);\n        str += $\"    case {c}MethodName_{methodName} => {methodInfo.NumPCs}\\n\";\n      }\n      str += \"  }\\n\";\n      pgp.AddFunction(str, \"specs\");\n\n      var pcs = new List<ArmadaPC>();\n      symbols.AllMethods.AppendAllPCs(pcs);\n      var maxInstructionCount = pcs.Select(pc => pc.instructionCount).Max();\n\n      str = $@\"\n        function PCToMethod_{c}(pc:{c}.Armada_PC) : {c}MethodName\n        {{\n          match pc\n      \";\n      foreach (var pc in pcs)\n      {\n        str += $\"    case {pc} => {c}MethodName_{pc.methodName}\\n\";\n      }\n      str += \"  }\\n\";\n      pgp.AddFunction(str, \"specs\");\n\n      str = $@\"\n        function MaxPCInstructionCount_{c}() : int\n        {{\n          { maxInstructionCount }\n        }}\n      \";\n      pgp.AddFunction(str, \"specs\");\n\n      str = $@\"\n        function PCToInstructionCount_{c}(pc:{c}.Armada_PC) : (v:int)\n          ensures 0 <= v <= MaxPCInstructionCount_{c}()\n        {{\n          match pc\n      \";\n      foreach (var pc in pcs)\n      {\n        str += $\"    case {pc} => {pc.instructionCount}\\n\";\n      }\n      str += \"  }\\n\";\n      pgp.AddFunction(str, \"specs\");\n\n      str = $@\"\n        lemma lemma_PCInstructionCountLessThanMethodInstructionCount_{c}(pc:{c}.Armada_PC)\n          ensures 0 <= PCToInstructionCount_{c}(pc) < MethodToInstructionCount_{c}(PCToMethod_{c}(pc))\n        {{\n        }}\n      \";\n      pgp.AddLemma(str, \"specs\");\n\n      str = $@\"\n        predicate StackMatchesMethod_{c}(frame:{c}.Armada_StackFrame, m:{c}MethodName)\n        {{\n          match m\n      \";\n      foreach (var methodName in methodNames) {\n        str += $\"    case {c}MethodName_{methodName} => frame.Armada_StackFrame_{methodName}?\\n\";\n      }\n      str += \"  }\\n\";\n      pgp.AddPredicate(str, \"specs\");\n    }\n\n    protected virtual void GeneratePCFunctions_L()\n    {\n      GeneratePCFunctions(true);\n    }\n\n    protected virtual void GeneratePCFunctions_H()\n    {\n      GeneratePCFunctions(false);\n    }\n\n    protected void AddStackMatchesMethodInvariant()\n    {\n      string str;\n\n      str = @\"\n        predicate StackMatchesMethodInv(s:LPlusState)\n        {\n          forall tid :: tid in s.s.threads ==>\n            var pc := s.s.threads[tid].pc;\n            StackMatchesMethod_L(s.s.threads[tid].top, PCToMethod_L(pc))\n        }\n      \";\n      pgp.AddPredicate(str, \"defs\");\n\n      var inv = new InternalInvariantInfo(\"StackMatchesMethodInv\", \"StackMatchesMethodInv\", new List<string>());\n      invariants.Add(inv);\n    }\n  }\n  \n}\n"
  },
  {
    "path": "Source/Armada/Armada.atg",
    "content": "/*-----------------------------------------------------------------------------\n//\n// Copyright (C) Microsoft Corporation.  All Rights Reserved.\n//\n//-----------------------------------------------------------------------------*/\n/*---------------------------------------------------------------------------\n// Armada\n// Rustan Leino, first created 25 January 2008\n//--------------------------------------------------------------------------*/\nusing System.Collections.Generic;\nusing System.Numerics;\nusing Microsoft.Boogie;\nusing System.IO;\nusing System.Text;\nCOMPILER Armada\n/*--------------------------------------------------------------------------*/\nreadonly Expression/*!*/ dummyExpr;\nreadonly AssignmentRhs/*!*/ dummyRhs;\nreadonly FrameExpression/*!*/ dummyFrameExpr;\nreadonly Statement/*!*/ dummyStmt;\nreadonly Statement/*!*/ dummyIfStmt;\nreadonly Include theInclude;\nreadonly ModuleDecl theModule;\nreadonly BuiltIns theBuiltIns;\nreadonly bool theVerifyThisFile;\nint anonymousIds = 0;\n\n/// <summary>\n/// Holds the modifiers given for a declaration\n///\n/// Not all modifiers are applicable to all kinds of declarations.\n/// Errors are given when a modify does not apply.\n/// We also record the tokens for the specified modifiers so that\n/// they can be used in error messages.\n/// </summary>\nstruct DeclModifierData {\n  public bool IsAbstract;\n  public IToken AbstractToken;\n  public bool IsGhost;\n  public IToken GhostToken;\n  public bool IsStatic;\n  public IToken StaticToken;\n  public bool IsProtected;\n  public IToken ProtectedToken;\n  public bool IsNoAddr;\n  public IToken NoAddrToken;\n\n}\n\n// Check that token has not been set, then set it.\npublic void CheckAndSetToken(ref IToken token)\n{\n    if (token != null) {\n      SemErr(t, \"Duplicate declaration modifier: \" + t.val);\n    }\n    token = t;\n}\n\n/// <summary>\n// A flags type used to tell what declaration modifiers are allowed for a declaration.\n/// </summary>\n[Flags]\nenum AllowedDeclModifiers {\n  None = 0,\n  Abstract = 1,\n  Ghost = 2,\n\n  // Means ghost not allowed because already implicitly ghost.\n  AlreadyGhost = 4,\n  Static = 8,\n  Protected = 16,\n  NoAddr = 32\n};\n\n/// <summary>\n/// Check the declaration modifiers against those that are allowed.\n///\n/// The 'allowed' parameter specifies which declaratio modifiers are allowed.\n/// The 'declCaption' parameter should be a string describing the kind of declaration.\n/// It is used in error messages.\n/// Any declaration modifiers that are present but not allowed are cleared.\n///</summary>\nvoid CheckDeclModifiers(DeclModifierData dmod, string declCaption, AllowedDeclModifiers allowed)\n{\n  if (dmod.IsAbstract && ((allowed & AllowedDeclModifiers.Abstract) == 0)) {\n    SemErr(dmod.AbstractToken, declCaption + \" cannot be declared 'abstract'.\");\n    dmod.IsAbstract = false;\n  }\n  if (dmod.IsGhost) {\n    if ((allowed & AllowedDeclModifiers.AlreadyGhost) != 0) {\n      SemErr(dmod.GhostToken, declCaption + \" cannot be declared ghost (they are 'ghost' by default).\");\n      dmod.IsGhost = false;\n    } else if ((allowed & AllowedDeclModifiers.Ghost) == 0) {\n      SemErr(dmod.GhostToken, declCaption + \" cannot be declared 'ghost'.\");\n      dmod.IsGhost = false;\n    }\n  }\n  if (dmod.IsStatic && ((allowed & AllowedDeclModifiers.Static) == 0)) {\n    SemErr(dmod.StaticToken, declCaption + \" cannot be declared 'static'.\");\n    dmod.IsStatic = false;\n  }\n  if (dmod.IsProtected && ((allowed & AllowedDeclModifiers.Protected) == 0)) {\n    SemErr(dmod.ProtectedToken, declCaption + \" cannot be declared 'protected'.\");\n    dmod.IsProtected = false;\n  }\n  if (dmod.IsNoAddr && ((allowed & AllowedDeclModifiers.NoAddr) == 0)) {\n    SemErr(dmod.NoAddrToken, declCaption + \" cannot be declared 'noaddr'.\");\n    dmod.IsNoAddr = false;\n  }\n}\n\n///<summary>\n/// Parses top-level things (modules, classes, datatypes, class members) from \"filename\"\n/// and appends them in appropriate form to \"module\".\n/// Returns the number of parsing errors encountered.\n/// Note: first initialize the Scanner.\n///</summary>\npublic static int Parse (string/*!*/ filename, Include include, ModuleDecl module, BuiltIns builtIns, Errors/*!*/ errors, bool verifyThisFile=true) /* throws System.IO.IOException */ {\n  Contract.Requires(filename != null);\n  Contract.Requires(module != null);\n  string s;\n  if (filename == \"stdin.dfy\") {\n    s = Microsoft.Boogie.ParserHelper.Fill(System.Console.In, new List<string>());\n    return Parse(s, filename, filename, include, module, builtIns, errors, verifyThisFile);\n  } else {\n    using (System.IO.StreamReader reader = new System.IO.StreamReader(filename)) {\n      s = Microsoft.Boogie.ParserHelper.Fill(reader, new List<string>());\n      return Parse(s, filename, ArmadaOptions.Clo.UseBaseNameForFileName ? Path.GetFileName(filename) : filename, include, module, builtIns, errors, verifyThisFile);\n    }\n  }\n}\n///<summary>\n/// Parses top-level things (modules, classes, datatypes, class members)\n/// and appends them in appropriate form to \"module\".\n/// Returns the number of parsing errors encountered.\n/// Note: first initialize the Scanner.\n///</summary>\npublic static int Parse (string/*!*/ s, string/*!*/ fullFilename, string/*!*/ filename, ModuleDecl module, BuiltIns builtIns, ErrorReporter reporter, bool verifyThisFile=true) {\n  Contract.Requires(s != null);\n  Contract.Requires(filename != null);\n  Contract.Requires(module != null);\n  Errors errors = new Errors(reporter);\n  return Parse(s, fullFilename, filename, null, module, builtIns, errors, verifyThisFile);\n}\n\npublic static Parser SetupParser(string/*!*/ s, string/*!*/ fullFilename, string/*!*/ filename, Include include, ModuleDecl module,\n                                 BuiltIns builtIns, Errors/*!*/ errors, bool verifyThisFile=true) {\n  Contract.Requires(s != null);\n  Contract.Requires(filename != null);\n  Contract.Requires(module != null);\n  Contract.Requires(errors != null);\n  byte[]/*!*/ buffer = cce.NonNull( UTF8Encoding.Default.GetBytes(s));\n  MemoryStream ms = new MemoryStream(buffer,false);\n  Scanner scanner = new Scanner(ms, errors, fullFilename, filename);\n  return new Parser(scanner, errors, include, module, builtIns, verifyThisFile);\n}\n\npublic static Expression ParseExpression(string/*!*/ s, string/*!*/ fullFilename, string/*!*/ filename, Include include, ModuleDecl module,\n                                         BuiltIns builtIns, Errors/*!*/ errors, bool verifyThisFile=true) {\n  Parser parser = SetupParser(s, fullFilename, filename, include, module, builtIns, errors, verifyThisFile);\n  parser.la = new Token();\n  parser.la.val = \"\";\n  parser.Get();\n  Expression e;\n  parser.Expression(out e, true, true, true);\n  return e;\n}\n\n\n// This has to return Declaration because it might return a TopLevelDecl or a MemberDecl\npublic static Declaration ParseTopLevelDecl(string/*!*/ s, string/*!*/ fullFilename, string/*!*/ filename, Include include, ModuleDecl module,\n                                             BuiltIns builtIns, Errors/*!*/ errors, bool verifyThisFile=true) {\n  Parser parser = SetupParser(s, fullFilename, filename, include, module, builtIns, errors, verifyThisFile);\n  parser.la = new Token();\n  parser.la.val = \"\";\n  parser.Get();\n  var defaultClassMembers = new List<MemberDecl>();\n  var moduleDef = new ModuleDefinition(Token.NoToken, \"DummyModule\", new List<IToken>(), false, false, false, Token.NoToken, null, null, false);\n  parser.TopDecl(moduleDef, defaultClassMembers, true, false);\n\n  if (moduleDef.TopLevelDecls.Count == 1) {\n      return moduleDef.TopLevelDecls[0];\n  } else if (defaultClassMembers.Count == 1) {\n      return defaultClassMembers[0];\n  } else {\n      errors.SemErr(Token.NoToken, \"ParseTopLevelDecl got wrong number of declarations\");\n      return null;\n  }\n}\n\n\n///<summary>\n/// Parses top-level things (modules, classes, datatypes, class members)\n/// and appends them in appropriate form to \"module\".\n/// Returns the number of parsing errors encountered.\n/// Note: first initialize the Scanner with the given Errors sink.\n///</summary>\npublic static int Parse (string/*!*/ s, string/*!*/ fullFilename, string/*!*/ filename, Include include, ModuleDecl module,\n                         BuiltIns builtIns, Errors/*!*/ errors, bool verifyThisFile=true) {\n  Parser parser = SetupParser(s, fullFilename, filename, include, module, builtIns, errors, verifyThisFile);\n  parser.Parse();\n  return parser.errors.ErrorCount;\n}\n\npublic Parser(Scanner/*!*/ scanner, Errors/*!*/ errors, Include include, ModuleDecl module, BuiltIns builtIns, bool verifyThisFile=true)\n  : this(scanner, errors)  // the real work\n{\n  // initialize readonly fields\n  dummyExpr = new LiteralExpr(Token.NoToken);\n  dummyRhs = new ExprRhs(dummyExpr, null);\n  dummyFrameExpr = new FrameExpression(dummyExpr.tok, dummyExpr, null);\n  dummyStmt = new ReturnStmt(Token.NoToken, Token.NoToken, null);\n  var dummyBlockStmt = new BlockStmt(Token.NoToken, Token.NoToken, new List<Statement>());\n  dummyIfStmt = new IfStmt(Token.NoToken, Token.NoToken, false, null, dummyBlockStmt, null);\n  theInclude = include; // the \"include\" that includes this file\n  theModule = module;\n  theBuiltIns = builtIns;\n  theVerifyThisFile = verifyThisFile;\n}\n\nbool IsLabel(bool allowLabel) {\n  if (!allowLabel) {\n    return false;\n  }\n  scanner.ResetPeek();\n  IToken x = scanner.Peek();\n  return (la.kind == _ident || la.kind == _digits) && x.kind == _colon;\n}\n\nbool IsAlternative() {\n  IToken x = scanner.Peek();\n  return (la.kind == _lbrace && x.kind == _case)\n      || la.kind == _case;\n}\n\nbool FollowedByColon() {\n  IToken x = la;\n  while (x.kind == _ident || x.kind == _openparen)\n     x = scanner.Peek();\n  return x.kind == _colon;\n}\n\nbool IsStaticArrayBracket() {\n  return la.kind == _lbracket;\n}\n\nbool StarFollowedByCommaSemiOrOpenBrace() {\n  if (la.kind != _star) {\n    return false;\n  }\n  Token x = scanner.Peek();\n  return (x.kind == _comma || x.kind == _semi || x.kind == _lbrace);\n}\n\nbool IsGets() {\n  return la.kind == _gets;\n}\n\n// an existential guard starts with an identifier and is then followed by\n// * a colon (if the first identifier is given an explicit type),\n// * a comma (if there's a list of bound variables and the first one is not given an explicit type),\n// * a start-attribute (if there's one bound variable and it is not given an explicit type and there are attributes), or\n// * a bored smiley (if there's one bound variable and it is not given an explicit type).\nbool IsExistentialGuard() {\n  scanner.ResetPeek();\n  if (la.kind == _ident) {\n    Token x = scanner.Peek();\n    if (x.kind == _colon || x.kind == _comma || x.kind == _boredSmiley || x.kind == _lbracecolon) {\n      return true;\n    }\n  }\n  return false;\n}\n\nbool IsLoopSpec() {\n  return la.kind == _invariant || la.kind == _decreases || la.kind == _modifies;\n}\n\nbool IsWitness() {\n  scanner.ResetPeek();\n  if (la.kind == _witness) {\n    return true;\n  } else if (la.kind == _ghost) {\n    Token x = scanner.Peek();\n    return x.kind == _witness;\n  }\n  return false;\n}\n\nbool IsFunctionDecl() {\n  scanner.ResetPeek();\n  switch (la.kind) {\n    case _function:\n    case _predicate:\n    case _copredicate:\n      return true;\n    case _inductive:\n      return scanner.Peek().kind != _lemma;\n    case _twostate:\n      var x = scanner.Peek();\n      return x.kind == _function || x.kind == _predicate;\n    default:\n      return false;\n  }\n}\n\nbool IsParenStar() {\n  scanner.ResetPeek();\n  Token x = scanner.Peek();\n  return la.kind == _openparen && x.kind == _star;\n}\n\nbool IsEquivOp() {\n  return la.val == \"<==>\" || la.val == \"\\u21d4\";\n}\nbool IsImpliesOp() {\n  return la.val == \"==>\" || la.val == \"\\u21d2\";\n}\nbool IsExpliesOp() {\n  return la.val == \"<==\" || la.val == \"\\u21d0\";\n}\nbool IsAndOp() {\n  return la.val == \"&&\" || la.val == \"\\u2227\";\n}\nbool IsOrOp() {\n  return la.val == \"||\" || la.val == \"\\u2228\";\n}\nbool IsBitwiseAndOp() {\n  return la.val == \"&\";\n}\nbool IsBitwiseOrOp() {\n  return la.val == \"|\";\n}\nbool IsBitwiseXorOp() {\n  return la.val == \"^\";\n}\nbool IsBitwiseOp() {\n  return IsBitwiseAndOp() || IsBitwiseOrOp() || IsBitwiseXorOp();\n}\nbool IsAs() {\n  return la.kind == _as;\n}\nbool IsRelOp() {\n  return la.val == \"==\"\n      || la.val == \"<\"\n      || la.val == \">\"\n      || la.val == \"<=\"\n      || la.val == \">=\"\n      || la.val == \"!=\"\n      || la.val == \"in\"\n      || la.kind == _notIn\n      || la.val ==\"!\"\n      || la.val == \"\\u2260\"\n      || la.val == \"\\u2264\"\n      || la.val == \"\\u2265\";\n}\nbool IsShiftOp() {\n  if (la.kind == _openAngleBracket) {\n  } else if (la.kind == _closeAngleBracket) {\n  } else {\n    return false;\n  }\n  scanner.ResetPeek();\n  var x = scanner.Peek();\n  if (x.kind != la.kind) {\n    return false;\n  }\n  return x.pos == la.pos + 1;  // return true only if the tokens are adjacent to each other\n}\nbool IsAddOp() {\n  return la.val == \"+\" || la.val == \"-\";\n}\nbool IsMulOp() {\n  return la.kind == _star || la.val == \"/\" || la.val == \"%\";\n}\nbool IsQSep() {\n  return la.kind == _doublecolon || la.kind == _bullet;\n}\n\nbool IsNonFinalColon() {\n  return la.kind == _colon && scanner.Peek().kind != _rbracket;\n}\nbool IsMapDisplay() {\n  scanner.ResetPeek();\n  return la.kind == _map && scanner.Peek().kind == _lbracket;\n}\nbool IsIMapDisplay() {\n  scanner.ResetPeek();\n  return la.kind == _imap && scanner.Peek().kind == _lbracket;\n}\nbool IsISetDisplay() {\n  scanner.ResetPeek();\n  return la.kind == _iset && scanner.Peek().kind == _lbrace;\n}\n\nbool IsSuffix() {\n  return la.kind == _dot || la.kind == _lbracket || la.kind == _openparen;\n}\n\nstring UnwildIdent(string x, bool allowWildcardId) {\n  if (x.StartsWith(\"_\")) {\n    if (allowWildcardId && x.Length == 1) {\n      return \"_v\" + anonymousIds++;\n    } else {\n      SemErr(\"cannot declare identifier beginning with underscore\");\n    }\n  }\n  return x;\n}\n\nbool IsLambda(bool allowLambda)\n{\n  if (!allowLambda) {\n    return false;\n  }\n  scanner.ResetPeek();\n  Token x;\n  // peek at what might be a signature of a lambda expression\n  if (la.kind == _ident) {\n    // cool, that's the entire candidate signature\n  } else if (la.kind != _openparen) {\n    return false;  // this is not a lambda expression\n  } else {\n    int identCount = 0;\n    x = scanner.Peek();\n    while (x.kind != _closeparen) {\n      if (identCount != 0) {\n        if (x.kind != _comma) {\n          return false;  // not the signature of a lambda\n        }\n        x = scanner.Peek();\n      }\n      if (x.kind != _ident) {\n        return false;  // not a lambda expression\n      }\n      identCount++;\n      x = scanner.Peek();\n      if (x.kind == _colon) {\n        // a colon belongs only in a lamdba signature, so this must be a lambda (or something ill-formed)\n        return true;\n      }\n    }\n  }\n  // What we have seen so far could have been a lambda signature or could have been some\n  // other expression (in particular, an identifier, a parenthesized identifier, or a\n  // tuple all of whose subexpressions are identifiers).\n  // It is a lambda expression if what follows is something that must be a lambda.\n  x = scanner.Peek();\n  return x.kind == _darrow || x.kind == _reads || x.kind == _requires;\n}\n\nbool IsIdentParen() {\n  scanner.ResetPeek();\n  Token x = scanner.Peek();\n  return la.kind == _ident && x.kind == _openparen;\n}\n\n/* Used to disambiguate the LHS of a VarDeclStmt. If it looks like the start of a CasePattern,\n * we consider it to be a LetStmt. But if we are looking at a simple identifier, then we\n * consider it to be a VarDeclStmt.\n */\nbool IsLetStmt() {\n  return IsIdentParen() || la.kind == _openparen;\n}\n\nbool IsIdentColonOrBar() {\n  Token x = scanner.Peek();\n  return la.kind == _ident && (x.kind == _colon || x.kind == _verticalbar);\n}\n\nbool SemiFollowsCall(bool allowSemi, Expression e) {\n  return allowSemi && la.kind == _semi && (e is ApplySuffix || (e is RevealExpr && (((RevealExpr)e).Expr is ApplySuffix)));\n}\n\nbool IsNotEndOfCase() {\n  return la.kind != _EOF && la.kind != _rbrace && la.kind != _case;\n}\n\n/* The following is the largest lookahead there is. It needs to check if what follows\n * can be nothing but \"<\" Type { \",\" Type } \">\".\n */\nbool IsGenericInstantiation(bool inExpressionContext) {\n  scanner.ResetPeek();\n  if (!inExpressionContext) {\n    return la.kind == _openAngleBracket;\n  }\n  IToken pt = la;\n  if (!IsTypeList(ref pt)) {\n    return false;\n  }\n  /* There are ambiguities in the parsing.  For example:\n   *     F( a < b , c > (d) )\n   * can either be a unary function F whose argument is a function \"a\" with type arguments \"<b,c>\" and\n   * parameter \"d\", or can be a binary function F with the two boolean arguments \"a < b\" and \"c > (d)\".\n   * To make the situation a little better, we (somewhat heuristically) look at the character that\n   * follows the \">\".  Note that if we, contrary to a user's intentions, pick \"a<b,c>\" out as a function\n   * with a type instantiation, the user can disambiguate it by making sure the \">\" sits inside some\n   * parentheses, like:\n   *     F( a < b , (c > (d)) )\n   */\n  switch (pt.kind) {\n    case _dot:  // here, we're sure it must have been a type instantiation we saw, because an expression cannot begin with dot\n    case _openparen:  // it was probably a type instantiation of a function/method\n    case _lbracket:  // it is possible that it was a type instantiation\n    case _lbrace:  // it was probably a type instantiation of a function/method\n    // In the following cases, we're sure we must have read a type instantiation that just ended an expression\n    case _closeparen:\n    case _rbracket:\n    case _rbrace:\n    case _comma:\n    case _semi:\n    case _then:\n    case _else:\n    case _case:\n    case _eq:\n    case _neq:\n    case _neqAlt:\n    case _as:\n    case _by:\n    case _in:\n    case _openAngleBracket:\n    case _closeAngleBracket:\n    case _EOF:\n    // (specification clauses that can follow an expression)\n    case _decreases:\n    case _modifies:\n    case _reads:\n    case _requires:\n    case _ensures:\n    case _invariant:\n    case _witness:\n    // (top-level declarations that can follow an expression)\n    case _function:\n    case _predicate:\n    case _inductive:\n    case _twostate:\n    case _lemma:\n    case _copredicate:\n    case _ghost:\n    case _static:\n    case _protected:\n    case _import:\n    case _export:\n    case _class:\n    case _trait:\n    case _datatype:\n    case _codatatype:\n    case _var:\n    case _const:\n    case _newtype:\n    case _type:\n    case _iterator:\n    case _method:\n    case _colemma:\n    case _constructor:\n      return true;\n    default:\n      return false;\n  }\n}\n/* Returns true if the next thing is of the form:\n *     \"<\" Type { \",\" Type } \">\"\n */\nbool IsTypeList(ref IToken pt) {\n  if (pt.kind != _openAngleBracket) {\n    return false;\n  }\n  pt = scanner.Peek();\n  return IsTypeSequence(ref pt, _closeAngleBracket);\n}\n/* Returns true if the next thing is of the form:\n *     Type { \",\" Type }\n * followed by an endBracketKind.\n */\nbool IsTypeSequence(ref IToken pt, int endBracketKind) {\n  while (true) {\n    if (!IsType(ref pt)) {\n      return false;\n    }\n    if (pt.kind == endBracketKind) {\n      // end of type list\n      pt = scanner.Peek();\n      return true;\n    } else if (pt.kind == _comma) {\n      // type list continues\n      pt = scanner.Peek();\n    } else {\n      // not a type list\n      return false;\n    }\n  }\n}\nbool IsType(ref IToken pt) {\n  switch (pt.kind) {\n    case _bool:\n    case _char:\n    case _nat:\n    case _int:\n    case _real:\n    case _ORDINAL:\n    case _string:\n    case _object_q:\n    case _object:\n      pt = scanner.Peek();\n      return true;\n    case _arrayToken:\n    case _arrayToken_q:\n    case _bvToken:\n    case _set:\n    case _iset:\n    case _multiset:\n    case _seq:\n    case _map:\n    case _imap:\n      pt = scanner.Peek();\n      return pt.kind != _openAngleBracket || IsTypeList(ref pt);\n    case _ident:\n      while (true) {\n        // invariant: next token is an ident\n        pt = scanner.Peek();\n        if (pt.kind == _openAngleBracket && !IsTypeList(ref pt)) {\n          return false;\n        }\n        if (pt.kind != _dot) {\n          // end of the type\n          return true;\n        }\n        pt = scanner.Peek();  // get the _dot\n        if (pt.kind != _ident) {\n          return false;\n        }\n      }\n    case _openparen:\n      pt = scanner.Peek();\n      if (pt.kind == _closeparen) {\n        // end of type list\n        pt = scanner.Peek();\n        return true;\n      }\n      return IsTypeSequence(ref pt, _closeparen);\n    default:\n      return false;\n  }\n}\n\n\nvoid ConvertKeywordTokenToIdent() {\n  var oldKind = la.kind;\n  la.kind = _ident;\n\n  // call CheckLiteral with la\n  var origT = t;\n  t = la;\n  scanner.CheckLiteral();\n  t = origT;\n\n  if (la.kind != _ident) {\n    // it has been changed by CheckLiteral, which means it was a keyword\n    la.kind = _ident;  // convert it to an ident\n  } else {\n    // la was something other than a keyword\n    la.kind = oldKind;\n  }\n}\n\nint StringToInt(string s, int defaultValue, string errString) {\n  Contract.Requires(s != null);\n  Contract.Requires(errString != null);\n  try {\n    if (s != \"\") {\n      defaultValue = int.Parse(s);\n    }\n  } catch (System.OverflowException) {\n    SemErr(string.Format(\"sorry, {0} ({1}) are not supported\", errString, s));\n  }\n  return defaultValue;\n}\n\n/*--------------------------------------------------------------------------*/\nCHARACTERS\n  letter = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\".\n  digit = \"0123456789\".\n  posDigit = \"123456789\".\n  hexdigit = \"0123456789ABCDEFabcdef\".\n  special = \"'_?\".\n  glyph = \"`~!@#$%^&*()-_=+[{]}|;:',<.>/?\\\\\".\n  cr        = '\\r'.\n  lf        = '\\n'.\n  tab       = '\\t'.\n  space = ' '.\n  nondigit = letter + special.\n  idchar = nondigit + digit.\n  nonidchar = ANY - idchar.\n  /* exclude the characters in 'array' and '\\'' */\n  nondigitMinusABTick = nondigit - 'a' - 'b' - '\\''.\n  nondigitMinusQuery = nondigit - '?'.\n  idcharMinusA = idchar - 'a'.\n  idcharMinusR = idchar - 'r'.\n  idcharMinusY = idchar - 'y'.\n  idcharMinusV = idchar - 'v'.\n  idcharMinusPosDigitMinusQuery = idchar - posDigit - '?'.\n  idcharMinusTick = idchar - '\\''.\n  /* string literals */\n  charChar = ANY - '\\'' - '\\\\' - cr - lf.\n  stringChar = ANY - '\"' - '\\\\' - cr - lf.\n  verbatimStringChar = ANY - '\"'.\n\n/*------------------------------------------------------------------------*/\nTOKENS\n  ident =  nondigitMinusABTick {idchar}       /* if char 0 is not an 'a' or '\\'', then anything else is fine */\n        |  'a' [ idcharMinusR {idchar} ]      /* if char 0 is an 'a', then either there is no char 1 or char 1 is not an 'r' */\n        |  'a' 'r' [ idcharMinusR {idchar} ]  /* etc. */\n        |  'a' 'r' 'r' [ idcharMinusA {idchar} ]\n        |  'a' 'r' 'r' 'a' [ idcharMinusY {idchar} ]\n        |  'a' 'r' 'r' 'a' 'y' idcharMinusPosDigitMinusQuery {idchar}\n        |  'a' 'r' 'r' 'a' 'y' '?' idchar {idchar}\n        |  'a' 'r' 'r' 'a' 'y' posDigit {digit} nondigitMinusQuery {idchar}\n        |  'a' 'r' 'r' 'a' 'y' posDigit {digit} '?' idchar {idchar}\n        |  'b' [ idcharMinusV {idchar} ]\n        |  'b' 'v' [ nondigit {idchar} ]\n        |  'b' 'v' '0' idchar {idchar}\n        |  'b' 'v' posDigit {idchar} nondigit {idchar}\n        |  \"'\" [ idchar ]                        /* if char 0 is a '\\'' and length is 1 or 2, then it is an identifier */\n        |  \"'\" idchar idcharMinusTick            /* if char 0 is '\\'' and length is 3, then it is an identifier provided char 2 is not '\\'' */\n        |  \"'\" idchar idchar idchar { idchar }   /* if char 0 is '\\'' and length exceeds 3, then it is an identifier */\n        .\n  digits = digit {['_'] digit}.\n  hexdigits = \"0x\" hexdigit {['_'] hexdigit}.\n  decimaldigits = digit {['_'] digit} '.' digit {['_'] digit}.\n  arrayToken = \"array\" [posDigit {digit}].\n  arrayToken_q = \"array\" [posDigit {digit}] '?'.\n  bvToken = \"bv\" ( '0' | posDigit {digit} ).\n  bool = \"bool\".\n  char = \"char\".\n  int = \"int\".\n  nat = \"nat\".\n  real = \"real\".\n  ORDINAL = \"ORDINAL\".\n  object = \"object\".\n  object_q = \"object?\".\n  string = \"string\".\n  set = \"set\".\n  iset = \"iset\".\n  multiset = \"multiset\".\n  seq = \"seq\".\n  map = \"map\".\n  imap = \"imap\".\n  charToken =\n      \"'\"\n      ( charChar\n        | \"\\\\\\'\" | \"\\\\\\\"\" | \"\\\\\\\\\" | \"\\\\0\" | \"\\\\n\" | \"\\\\r\" | \"\\\\t\"\n        | \"\\\\u\" hexdigit hexdigit hexdigit hexdigit\n      )\n      \"'\".\n  stringToken =\n      '\"'\n      { stringChar\n        | \"\\\\\\'\" | \"\\\\\\\"\" | \"\\\\\\\\\" | \"\\\\0\" | \"\\\\n\" | \"\\\\r\" | \"\\\\t\"\n        | \"\\\\u\" hexdigit hexdigit hexdigit hexdigit\n      }\n      '\"'\n    | '@' '\"' { verbatimStringChar | \"\\\"\\\"\" } '\"'.\n  colon = ':'.\n  comma = ','.\n  verticalbar = '|'.\n  doublecolon = \"::\".\n  gets = \":=\".\n  boredSmiley = \":|\".\n  bullet = '\\u2022'.\n  dot = '.'.\n  backtick = \"`\".\n  semi = ';'.\n  darrow = \"=>\".\n  assume = \"assume\".\n  calc = \"calc\".\n  case = \"case\".\n  then = \"then\".\n  else = \"else\".\n  as = \"as\".\n  by = \"by\".\n  in = \"in\".\n  decreases = \"decreases\".\n  invariant = \"invariant\".\n  function = \"function\".\n  predicate = \"predicate\".\n  inductive = \"inductive\".\n  twostate = \"twostate\".\n  copredicate = \"copredicate\".\n  lemma = \"lemma\".\n  static = \"static\".\n  protected = \"protected\".\n  import = \"import\".\n  export = \"export\".\n  class = \"class\".\n  trait = \"trait\".\n  datatype = \"datatype\".\n  codatatype = \"codatatype\".\n  var = \"var\".\n  const = \"const\".\n  newtype = \"newtype\".\n  type = \"type\".\n  iterator = \"iterator\".\n  method = \"method\".\n  colemma = \"colemma\".\n  constructor = \"constructor\".\n  modifies = \"modifies\".\n  reads = \"reads\".\n  requires = \"requires\".\n  ensures = \"ensures\".\n  ghost = \"ghost\".\n  witness = \"witness\".\n  lbracecolon = \"{:\".\n  lbrace = '{'.\n  rbrace = '}'.\n  lbracket = '['.\n  rbracket = ']'.\n  openparen = '('.\n  closeparen = ')'.\n  openAngleBracket = '<'.\n  closeAngleBracket = '>'.\n  eq = \"==\".\n  neq = \"!=\".\n  neqAlt = '\\u2260'.\n  star = '*'.\n  notIn = \"!in\" CONTEXT (nonidchar).\n  ellipsis = \"...\".\n  reveal = \"reveal\".\n  module = \"module\".\n  commit = \"commit\".\nCOMMENTS FROM \"/*\" TO \"*/\" NESTED\nCOMMENTS FROM \"//\" TO lf\nIGNORE cr + lf + tab\n/*------------------------------------------------------------------------*/\nPRODUCTIONS\nArmada\n= (. List<MemberDecl/*!*/> membersDefaultClass = new List<MemberDecl/*!*/>();\n     // to support multiple files, create a default module only if theModule is null\n     DefaultModuleDecl defaultModule = (DefaultModuleDecl)((LiteralModuleDecl)theModule).ModuleDef;\n     // theModule should be a DefaultModuleDecl (actually, the singular DefaultModuleDecl)\n     Contract.Assert(defaultModule != null);\n  .)\n  { \"include\" stringToken               (. {\n                                             string parsedFile = scanner.FullFilename;\n                                             bool isVerbatimString;\n                                             string s = t.val;\n                                             string includedFile = Util.RemoveParsedStringQuotes(s, out isVerbatimString);\n                                             includedFile = Util.RemoveEscaping(includedFile, isVerbatimString);\n                                             string fullPath = includedFile;\n                                             if (!Path.IsPathRooted(includedFile)) {\n                                               string basePath = Path.GetDirectoryName(parsedFile);\n                                               includedFile = Path.Combine(basePath, includedFile);\n                                               fullPath = Path.GetFullPath(includedFile);\n                                             }\n                                             defaultModule.Includes.Add(new Include(t, parsedFile, includedFile, fullPath, s));\n                                           }\n                                        .)\n  }\n  { TopDecl<defaultModule, membersDefaultClass, /* isTopLevel */ true, /* isAbstract */ false> }\n  (. // find the default class in the default module, then append membersDefaultClass to its member list\n     DefaultClassDecl defaultClass = null;\n     foreach (TopLevelDecl topleveldecl in defaultModule.TopLevelDecls) {\n       defaultClass = topleveldecl as DefaultClassDecl;\n       if (defaultClass != null) {\n         defaultClass.Members.AddRange(membersDefaultClass);\n         break;\n       }\n     }\n     if (defaultClass == null) { // create the default class here, because it wasn't found\n       defaultClass = new DefaultClassDecl(defaultModule, membersDefaultClass);\n       defaultModule.TopLevelDecls.Add(defaultClass);\n     } .)\n  EOF\n  .\n\nDeclModifier<ref DeclModifierData dmod>\n= ( \"abstract\"                             (. dmod.IsAbstract = true;  CheckAndSetToken(ref dmod.AbstractToken); .)\n  | \"ghost\"                                (. dmod.IsGhost = true;  CheckAndSetToken(ref dmod.GhostToken); .)\n  | \"static\"                               (. dmod.IsStatic = true; CheckAndSetToken(ref dmod.StaticToken); .)\n  | \"protected\"                            (. dmod.IsProtected = true; CheckAndSetToken(ref dmod.ProtectedToken); .)\n  | \"noaddr\"                               (. dmod.IsNoAddr = true; CheckAndSetToken(ref dmod.NoAddrToken); .)\n  )\n  .\n\nTopDecl<. ModuleDefinition module, List<MemberDecl/*!*/> membersDefaultClass, bool isTopLevel, bool isAbstract .>\n= (. DeclModifierData dmod = new DeclModifierData(); ModuleDecl submodule;\n     ClassDecl/*!*/ c; DatatypeDecl/*!*/ dt; TopLevelDecl td; IteratorDecl iter;\n     TraitDecl/*!*/ trait;\n     ArmadaProofDecl proofDecl;\n     RefinementConstraintDecl refinementConstraintDecl;\n  .)\n  { DeclModifier<ref dmod> }\n  ( SubModuleDecl<dmod, module, out submodule> (. var litmod = submodule as LiteralModuleDecl;\n                                                  if (litmod != null && litmod.ModuleDef.PrefixIds.Count != 0) {\n                                                    var tup = new Tuple<List<IToken>, LiteralModuleDecl>(litmod.ModuleDef.PrefixIds, litmod);\n                                                    module.PrefixNamedModules.Add(tup);\n                                                  } else {\n                                                    module.TopLevelDecls.Add(submodule);\n                                                  } .)\n  | ClassDecl<dmod, module, out c>             (. module.TopLevelDecls.Add(c); .)\n  | DatatypeDecl<dmod, module, out dt>         (. module.TopLevelDecls.Add(dt); .)\n  | NewtypeDecl<dmod, module, out td>          (. module.TopLevelDecls.Add(td); .)\n  | OtherTypeDecl<dmod, module, out td>        (. module.TopLevelDecls.Add(td); .)\n  | IteratorDecl<dmod, module, out iter>       (. module.TopLevelDecls.Add(iter); .)\n  | TraitDecl<dmod, module, out trait>         (. module.TopLevelDecls.Add(trait); .)\n  /* NOTE (Luke): upstream Dafny now forbids mutable member declaration as direct\n                  children field of a module, which is what we want in Dafny.\n                  I enabled it here, but don't know if it will cause other problems. */\n  | ClassMemberDecl<dmod, membersDefaultClass, false, false, !ArmadaOptions.O.AllowGlobals,\n                    !isTopLevel && ArmadaOptions.O.IronDafny && isAbstract>\n  | RefinementConstraintDecl<dmod, module, out refinementConstraintDecl>   (. module.TopLevelDecls.Add(refinementConstraintDecl); .)\n  | ArmadaProofDecl<dmod, module, out proofDecl> (. module.TopLevelDecls.Add(proofDecl); .)\n  ) .\n\nSubModuleDecl<DeclModifierData dmod, ModuleDefinition parent, out ModuleDecl submodule>\n= (. Attributes attrs = null;  IToken/*!*/ id; var prefixIds = new List<IToken>();\n     List<MemberDecl/*!*/> namedModuleDefaultClassMembers = new List<MemberDecl>();;\n     List<IToken> idPath, idExports;\n     IToken idRefined = null;\n     ModuleDefinition module;\n     submodule = null; // appease compiler\n     bool isAbstract = dmod.IsAbstract;\n     bool isProtected = dmod.IsProtected;\n     bool opened = false;\n     ArmadaModuleType moduleType = ArmadaModuleType.NotArmada;\n     IToken abstracts = null;\n     List<IToken> reduces = null;\n     IToken structsModuleName = null;\n     CheckDeclModifiers(dmod, \"Modules\", AllowedDeclModifiers.Abstract | AllowedDeclModifiers.Protected);\n  .)\n    ((  \"module\"\n      | \"layer\"                       (. moduleType = ArmadaModuleType.ArmadaLevel; .)\n      | \"level\"                       (. moduleType = ArmadaModuleType.ArmadaLevel; .)\n      | \"structs\"                     (. moduleType = ArmadaModuleType.ArmadaStructs;\n                                         theBuiltIns.CreateArrowTypeDecl(0);  /* We always need arrow types 0-3 for the Armada heap */\n                                         theBuiltIns.CreateArrowTypeDecl(1);\n                                         theBuiltIns.CreateArrowTypeDecl(2);\n                                         theBuiltIns.CreateArrowTypeDecl(3);\n                                      .)\n      | \"proof\"                       (. moduleType = ArmadaModuleType.ArmadaProof; .)\n     )\n    { Attribute<ref attrs> }\n    NoUSIdent<out id>\n    { (. prefixIds.Add(id); .)\n      \".\" NoUSIdent<out id>\n    }\n        [\"using\" NoUSIdent<out structsModuleName>\n        ]\n\n      [ \"refines\" ModuleName<out idRefined> ]\n            (. module = new ModuleDefinition(id, id.val, new List<IToken>(), isAbstract, isProtected, false, idRefined, parent, attrs, false, moduleType, structsModuleName, abstracts, reduces); module.IsToBeVerified = theVerifyThisFile;\n               AliasModuleDecl aliasDecl;\n               if (moduleType == ArmadaModuleType.ArmadaStructs || moduleType == ArmadaModuleType.ArmadaLevel) {\n                 /* Add \"import opened ArmadaCommonDefinitions\" */\n                 Token commonModule = new Token();\n                 commonModule.val = \"ArmadaCommonDefinitions\";\n                 aliasDecl = new AliasModuleDecl(new List<IToken>{commonModule}, commonModule, module, true, new List<IToken>());\n                 module.TopLevelDecls.Add(aliasDecl);\n               }\n               if (structsModuleName != null) {\n                 /* Add \"import opened <structsModuleName>\" */\n                 aliasDecl = new AliasModuleDecl(new List<IToken>{structsModuleName}, structsModuleName, module, true, new List<IToken>());\n                 module.TopLevelDecls.Add(aliasDecl);\n               }\n            .)\n       \"{\"                                 (. module.BodyStartTok = t; .)\n      { TopDecl<module, namedModuleDefaultClassMembers, /* isTopLevel */ false, isAbstract>}\n    \"}\"                                 (. module.BodyEndTok = t;\n                                           module.TopLevelDecls.Add(new DefaultClassDecl(module, namedModuleDefaultClassMembers));\n                                           submodule = new LiteralModuleDecl(module, parent); .)\n  |\n    \"import\" [\"opened\" (.opened = true;.)]\n    ModuleName<out id>\n    ( (. idPath = new List<IToken>(); idExports = new List<IToken>(); .)\n      [ QualifiedModuleExportSuffix<idPath, idExports> ]\n      (. if (idPath.Count > 0)\n           SemErr(idPath[0], \"Qualified imports must be given a name.\");\n        idPath.Insert(0, id);\n        submodule = new AliasModuleDecl(idPath, id, parent, opened, idExports);\n      .)\n    | \"=\" QualifiedModuleExport<out idPath, out idExports>\n      (. submodule = new AliasModuleDecl(idPath, id, parent, opened, idExports); .)\n    | \":\" QualifiedModuleExport<out idPath, out idExports>\n        (. submodule = new ModuleFacadeDecl(idPath, id, parent, opened, idExports); .)\n\n    )\n\n\n    [ SYNC \";\"\n        // This semi-colon used to be required, but it seems silly to have it.\n        // To stage the transition toward not having it at all, let's make it optional for now.  Then,\n        // in the next big version of Dafny, don't allow the semi-colon at all.\n        (. errors.Deprecated(t, \"the semi-colon that used to terminate a sub-module declaration has been deprecated; in the new syntax, just leave off the semi-colon\"); .)\n    ]\n  | (.\n      IToken exportId;\n      List<ExportSignature> exports = new List<ExportSignature>();;\n      List<string> extends = new List<string>();\n      bool provideAll = false;\n      bool revealAll = false;\n      bool isDefault = false;\n      ExportSignature exsig;\n    .)\n    \"export\" (. exportId = t; .)\n    [ ExportIdent<out exportId> ]\n    {\n      \"provides\"\n      (\n        ( ModuleExportSignature<true, out exsig>        (. exports.Add(exsig); .)\n          {\",\" ModuleExportSignature<true, out exsig>   (. exports.Add(exsig); .) }\n        )\n      | \"*\" (. provideAll = true; .)\n      )\n    | \"reveals\"\n      (\n        ( ModuleExportSignature<false, out exsig>       (. exports.Add(exsig); .)\n          {\",\" ModuleExportSignature<false, out exsig>  (. exports.Add(exsig); .) }\n        )\n      | \"*\" (. revealAll = true; .)\n      )\n    | \"extends\"\n      ExportIdent<out id>       (. extends.Add(id.val); .)\n      {\",\" ExportIdent<out id>  (. extends.Add(id.val); .) }\n    }\n    (. if (exportId.val == \"export\" || exportId.val == parent.Name) {\n         isDefault = true;\n       }\n       submodule = new ModuleExportDecl(exportId, parent, exports, extends, provideAll, revealAll, isDefault);\n    .)\n  )\n.\n\nModuleExportSignature<bool opaque, out ExportSignature exsig>\n= (. IToken prefix; IToken suffix = null; .)\n  TypeNameOrCtorSuffix<out prefix> [ \".\" TypeNameOrCtorSuffix<out suffix> ]\n  (. if (suffix != null) {\n       exsig = new ExportSignature(prefix, prefix.val, suffix, suffix.val, opaque);\n     } else {\n       exsig = new ExportSignature(prefix, prefix.val, opaque);\n     }\n  .)\n  .\n\n\n/* The only modules in any given scope are siblings, so we no longer need qualified lookups */\nModuleName<out IToken id>\n= Ident<out id>\n  .\n\n/* This production is for referring to module exports for imports (both normal and facades) */\nQualifiedModuleExportSuffix<.List<IToken> ids, List<IToken> exports.>\n= (. IToken id; .)\n  (\n    \".\" ModuleName<out id>   (. ids.Add(id); .)\n    { \".\" ModuleName<out id> (. ids.Add(id); .) }\n  | \"`\"\n    ( ExportIdent<out id>       (. exports.Add(id); .)\n    | \"{\" ExportIdent<out id>   (. exports.Add(id); .)\n      { \",\" ExportIdent<out id> (. exports.Add(id); .) }\n      \"}\"\n    )\n  )\n  .\n\nQualifiedModuleExport<.out List<IToken> ids, out List<IToken> exports.>\n= (. IToken id; ids = new List<IToken>();\n     List<IToken> sids = new List<IToken>(); exports = new List<IToken>();\n  .)\n  ModuleName<out id> (. ids.Add(id); .)\n  [ QualifiedModuleExportSuffix<sids, exports> ]\n  (. ids.AddRange(sids); .)\n  .\n\nClassDecl<DeclModifierData dmodClass, ModuleDefinition/*!*/ module, out ClassDecl/*!*/ c>\n= (. Contract.Requires(module != null);\n     Contract.Ensures(Contract.ValueAtReturn(out c) != null);\n     IToken/*!*/ id;\n   Type trait = null;\n     List<Type>/*!*/ traits = new List<Type>();\n   Attributes attrs = null;\n     List<TypeParameter/*!*/> typeArgs = new List<TypeParameter/*!*/>();\n     List<MemberDecl/*!*/> members = new List<MemberDecl/*!*/>();\n     IToken bodyStart;\n     CheckDeclModifiers(dmodClass, \"Classes\", AllowedDeclModifiers.None);\n     DeclModifierData dmod;\n  .)\n  SYNC\n  \"struct\"\n  { Attribute<ref attrs> }\n  NoUSIdent<out id>\n  [ GenericParameters<typeArgs, true> ]\n  [\"extends\"\n  Type<out trait>    (. traits.Add(trait); .)\n  {\",\" Type<out trait>  (. traits.Add(trait); .) }\n  ]\n  \"{\"                                            (. bodyStart = t;  .)\n  { (. dmod = new DeclModifierData(); .)\n    { DeclModifier<ref dmod> }\n    ClassMemberDecl<dmod, members, true, false, false, false>\n  }\n  \"}\"\n  (. c = new ClassDecl(id, id.val, module, typeArgs, members, attrs, traits);\n     c.BodyStartTok = bodyStart;\n     c.BodyEndTok = t;\n  .)\n  .\n\nTraitDecl<DeclModifierData dmodIn, ModuleDefinition/*!*/ module, out TraitDecl/*!*/ trait>\n  = (. Contract.Requires(module != null);\n     Contract.Ensures(Contract.ValueAtReturn(out trait) != null);\n     CheckDeclModifiers(dmodIn, \"Traits\", AllowedDeclModifiers.None);\n     IToken/*!*/ id;\n     Attributes attrs = null;\n     List<TypeParameter/*!*/> typeArgs = new List<TypeParameter/*!*/>(); //traits should not support type parameters at the moment\n     List<MemberDecl/*!*/> members = new List<MemberDecl/*!*/>();\n     IToken bodyStart;\n     DeclModifierData dmod;\n    .)\n  SYNC\n  \"trait\"\n  { Attribute<ref attrs> }\n  NoUSIdent<out id>\n  [ GenericParameters<typeArgs, true> ]\n    \"{\"                                            (. bodyStart = t; .)\n      {                                            (. dmod  = new DeclModifierData(); .)\n        { DeclModifier<ref dmod> }\n        ClassMemberDecl<dmod, members, true, false, false, false>\n      }\n    \"}\"\n  (. trait = new TraitDecl(id, id.val, module, typeArgs, members, attrs);\n     trait.BodyStartTok = bodyStart;\n     trait.BodyEndTok = t;\n    .)\n  .\n\nGlobalInvariantDecl<DeclModifierData dModIn, out GlobalInvariantDecl globalInvariant>\n= (. Contract.Ensures(Contract.ValueAtReturn(out globalInvariant) != null);\n     CheckDeclModifiers(dModIn, \"Global invariants\", AllowedDeclModifiers.None);\n     IToken id;\n     Expression body;\n     IToken bodyStart;\n     IToken bodyEnd;\n  .)\n  SYNC\n  \"invariant\"\n  NoUSIdent<out id>\n  FunctionBody<out body, out bodyStart, out bodyEnd>\n (. globalInvariant = new GlobalInvariantDecl(id, id.val, null, body); .)\n  .\n\nYieldPredicateDecl<DeclModifierData dModIn, out YieldPredicateDecl yieldPredicate>\n= (. Contract.Ensures(Contract.ValueAtReturn(out yieldPredicate) != null);\n     CheckDeclModifiers(dModIn, \"Yield predicates\", AllowedDeclModifiers.None);\n     IToken id;\n     Expression body;\n     IToken bodyStart;\n     IToken bodyEnd;\n  .)\n  SYNC\n  \"yield_predicate\"\n  NoUSIdent<out id>\n  FunctionBody<out body, out bodyStart, out bodyEnd>\n (. yieldPredicate = new YieldPredicateDecl(id, id.val, null, body); .)\n  .\n\nUniversalStepConstraintDecl<DeclModifierData dModIn, out UniversalStepConstraintDecl stepConstraint>\n= (. Contract.Ensures(Contract.ValueAtReturn(out stepConstraint) != null);\n     CheckDeclModifiers(dModIn, \"Yield predicates\", AllowedDeclModifiers.None);\n     IToken id;\n     Expression body;\n     IToken bodyStart;\n     IToken bodyEnd;\n     string code;\n     bool isVerbatimString;\n     stepConstraint = null;\n  .)\n  SYNC\n  \"universal_step_constraint\"\n  NoUSIdent<out id>\n  ( FunctionBody<out body, out bodyStart, out bodyEnd> (. stepConstraint = new UniversalStepConstraintDecl(id, id.val, null, body); .)\n    | stringToken (. code = Util.RemoveParsedStringQuotes(t.val, out isVerbatimString);\n                     stepConstraint = new UniversalStepConstraintDecl(id, id.val, null, code); .)\n  )\n  .\n\nArmadaProofDecl<DeclModifierData dModIn, ModuleDefinition module, out ArmadaProofDecl proofDecl>\n= (. Contract.Requires(module != null);\n     Contract.Ensures(Contract.ValueAtReturn(out proofDecl) != null);\n     CheckDeclModifiers(dModIn, \"Strategies\", AllowedDeclModifiers.None);\n     Attributes attrs = null;\n     if (module.ModuleType != ArmadaModuleType.ArmadaProof) {\n       SemErr(\"Strategies only supported in Armada refinement proofs\");\n     }\n     IToken x;\n     IToken id, id2, id3;\n     List<IToken> ids, ids2;\n     List<Tuple<string, string>> ranges, ranges2;\n     List<string> usedItems;\n     string includedFile, usedFile;\n     string code, code2, code3;\n     proofDecl = null;\n  .)\n  ( \"refinement\" (. x = t; .)\n    NoUSIdent<out id>\n    NoUSIdent<out id2>\n    (. proofDecl = new RefinementParametersDecl(x, module, id, id2); .)\n  | \"include_file\"                (. x = t; .)\n    stringToken                   (. bool isVerbatimString;\n                                     includedFile = Util.RemoveParsedStringQuotes(t.val, out isVerbatimString);\n                                     includedFile = Util.RemoveEscaping(includedFile, isVerbatimString);\n                                     usedItems = new List<string>(); .)\n    [ \"which_includes\"\n      stringToken                 (. usedFile = Util.RemoveParsedStringQuotes(t.val, out isVerbatimString);\n                                     usedFile = Util.RemoveEscaping(usedFile, isVerbatimString);\n                                     usedItems.Add(usedFile); .)\n      {\",\" stringToken            (. usedFile = Util.RemoveParsedStringQuotes(t.val, out isVerbatimString);\n                                     usedFile = Util.RemoveEscaping(usedFile, isVerbatimString);\n                                     usedItems.Add(usedFile); .)\n      }\n    ]                             (. proofDecl = new ImportFileArmadaProofDecl(x, module, includedFile, usedItems); .)\n  | \"import_module\"               (. x = t; .)\n    NoUSIdent<out id>             (. usedItems = new List<string>(); .)\n    [ \"which_imports\"\n      NoUSIdent<out id2>          (. usedItems.Add(id2.val); .)\n      {\",\" NoUSIdent<out id2>     (. usedItems.Add(id2.val); .)\n      }\n    ]                             (. proofDecl = new ImportModuleArmadaProofDecl(x, module, id.val, usedItems); .)\n  | \"extra\"                       (. x = t; .)\n    NoUSIdent<out id>\n    stringToken                   (. proofDecl = new ExtraMaterialArmadaProofDecl(x, module, id.val, t.val); .)\n  | \"inductive_invariant\"         (. x = t; code = null; ids = new List<IToken>(); .)\n    { Attribute<ref attrs> }\n    NoUSIdent<out id>\n    [ stringToken                 (. code = t.val; .)\n    ]\n    [ \"depends_on\"\n      NoUSIdent<out id2>          (. ids.Add(id2); .)\n      { \",\" NoUSIdent<out id2>    (. ids.Add(id2); .)\n      }\n    ]\n                                  (. proofDecl = new InductiveInvariantArmadaProofDecl(x, module, id, code, ids, attrs); .)\n  | \"use_regions\"                 (. proofDecl = new UseRegionsArmadaProofDecl(t, module); .)\n  | \"use_address_invariant\"       (. proofDecl = new UseAddressInvariantArmadaProofDecl(t, module); .)\n  | \"chl_invariant\"  (. x = t; code = null; .)\n    { Attribute<ref attrs> }\n    NoUSIdent<out id>\n    [ stringToken    (. code = t.val; .)\n    ]\n                     (. proofDecl = new CHLInvariantArmadaProofDecl(x, module, id, code, attrs); .)\n  | \"chl_local_invariant\"  (. x = t; code = null; .)\n    { Attribute<ref attrs> }\n    NoUSIdent<out id>\n    NoUSIdent<out id2>\n    [ stringToken          (. code = t.val; .)\n    ]\n                     (. proofDecl = new CHLLocalInvariantArmadaProofDecl(x, module, id, id2, code, attrs); .)\n  | \"chl_yield_pred\" (. x = t; code = null; .)\n    { Attribute<ref attrs> }\n    NoUSIdent<out id>\n    [ stringToken    (. code = t.val; .)\n    ]                (. proofDecl = new CHLYieldPredicateArmadaProofDecl(x, module, id, code, attrs); .)\n  | \"chl_precondition\"  (. x = t; code = null; .)\n    { Attribute<ref attrs> }\n    NoUSIdent<out id>\n    NoUSIdent<out id2>\n    [ stringToken    (. code = t.val; .)\n    ]\n                     (. proofDecl = new CHLPreconditionArmadaProofDecl(x, module, id, id2, code, attrs); .)\n  | \"chl_postcondition\"  (. x = t; code = null; .)\n    { Attribute<ref attrs> }\n    NoUSIdent<out id>\n    NoUSIdent<out id2>\n    [ stringToken    (. code = t.val; .)\n    ]\n                     (. proofDecl = new CHLPostconditionArmadaProofDecl(x, module, id, id2, code, attrs); .)\n  | \"chl_loop_modifies\"  (. x = t; code = null; .)\n    { Attribute<ref attrs> }\n    NoUSIdent<out id>\n    NoUSIdent<out id2>\n    [ stringToken    (. code = t.val; .)\n    ]\n                     (. proofDecl = new CHLLoopModifiesClauseArmadaProofDecl(x, module, id, id2, code, attrs); .)\n  | \"auxiliary\" (. x = t; .)\n    NoUSIdent<out id>\n    stringToken        (. code = t.val; .)\n    stringToken        (. code2 = t.val; .)\n    stringToken        (. code3 = t.val; .)\n    stringToken        (. proofDecl = new AuxiliaryArmadaProofDecl(x, module, id.val, code, code2, code3, t.val); .)\n  | \"weakening\" (. x = t; ids = new List<IToken>(); .)\n    [ LabelIdent<out id>       (. ids.Add(id); .)\n      { \",\" LabelIdent<out id> (. ids.Add(id); .) }\n    ] (. proofDecl = new WeakeningStrategyDecl(x, module, ids); .)\n  | \"starweakening\" (. x = t; ids = new List<IToken>(); ids2 = new List<IToken>(); .)\n    [ \"statements\" LabelIdent<out id>       (. ids.Add(id); .)\n      { \",\" LabelIdent<out id> (. ids.Add(id); .) }\n    ]\n    [ \"variables\" LabelIdent<out id>       (. ids2.Add(id); .)\n      { \",\" LabelIdent<out id> (. ids2.Add(id); .) }\n    ] (. proofDecl = new StarWeakeningStrategyDecl(x, module, ids, ids2); .)\n  | \"var_hiding\" (. x = t; ids = new List<IToken>(); .)\n    NoUSIdent<out id>          (. ids.Add(id); .)\n    { \",\" NoUSIdent<out id>    (. ids.Add(id); .) }\n    (. proofDecl = new GlobalVariableHidingStrategyDecl(x, module, ids); .)\n  | \"stack_var_hiding\" (. x = t; ids = new List<IToken>(); .)\n    NoUSIdent<out id>\n    NoUSIdent<out id2>          (. ids.Add(id2); .)\n    { \",\" NoUSIdent<out id2>     (. ids.Add(id2); .) }\n    (. proofDecl = new StackVariableHidingStrategyDecl(x, module, id, ids); .)\n  | \"var_intro\" (. x = t; ids = new List<IToken>(); .)\n    NoUSIdent<out id>          (. ids.Add(id); .)\n    { \",\" NoUSIdent<out id>    (. ids.Add(id); .) }\n    (. proofDecl = new GlobalVariableIntroStrategyDecl(x, module, ids); .)\n  | \"stack_var_intro\" (. x = t; code = null; .)\n    NoUSIdent<out id>\n    NoUSIdent<out id2>\n    [ stringToken (. code = t.val; .)\n    ]\n    (. proofDecl = new StackVariableIntroStrategyDecl(x, module, id, id2, code); .)\n  | \"reduction\"                        (. x = t;\n                                          ranges = new List<Tuple<string, string>>();\n                                          ranges2 = new List<Tuple<string, string>>(); .)\n    [ \"phase1\"\n      NoUSIdent<out id>                (. id2 = id; .)\n      [ \"-\" NoUSIdent<out id2> ]       (. ranges.Add(new Tuple<string, string>(id.val, id2.val)); .)\n      { \",\" NoUSIdent<out id>          (. id2 = id; .)\n        [ \"-\" NoUSIdent<out id2> ]     (. ranges.Add(new Tuple<string, string>(id.val, id2.val)); .)\n      }\n    ]\n    [ \"phase2\"\n      NoUSIdent<out id>                (. id2 = id; .)\n      [ \"-\" NoUSIdent<out id2> ]       (. ranges2.Add(new Tuple<string, string>(id.val, id2.val)); .)\n      { \",\" NoUSIdent<out id>          (. id2 = id; .)\n        [ \"-\" NoUSIdent<out id2> ]     (. ranges2.Add(new Tuple<string, string>(id.val, id2.val)); .)\n      }\n    ]\n    (. proofDecl = new ReductionStrategyDecl(x, module, ranges, ranges2); .)\n  | \"combining\" (. x = t; .)\n    NoUSIdent<out id>\n    NoUSIdent<out id2>\n    NoUSIdent<out id3>\n    (. proofDecl = new CombiningStrategyDecl(x, module, id, id2, id3); .)\n  | \"field_hiding\" (. x = t; .)\n    NoUSIdent<out id> NoUSIdent<out id2> (. proofDecl = new FieldHidingStrategyDecl(x, module, id, id2); .)\n  | \"field_intro\" (. x = t; .)\n    NoUSIdent<out id> NoUSIdent<out id2> (. proofDecl = new FieldIntroStrategyDecl(x, module, id, id2); .)\n  | \"assume_intro\" (. x = t; ids = new List<IToken>(); .)\n    [ LabelIdent<out id>       (. ids.Add(id); .)\n      { \",\" LabelIdent<out id> (. ids.Add(id); .) }\n    ] (. proofDecl = new AssumeIntroStrategyDecl(x, module, ids); .)\n  | \"chl\" (. proofDecl = new ConcurrentHoareLogicStrategyDecl(t, module); .)\n  | \"critsec\" (. x = t; .)\n    NoUSIdent<out id> (. proofDecl = new CriticalSectionStrategyDecl(x, module, id); .)\n  | \"tso_elim\"          (. x = t; .)\n    PeriodSeparatedIdentifierList<out ids>\n    stringToken         (. proofDecl = new TSOEliminationStrategyDecl(x, module, ids, t.val); .)\n  )\n.\n\nRefinementConstraintDecl<DeclModifierData dModIn, ModuleDefinition module, out RefinementConstraintDecl refinementConstraintDecl>\n= (. Contract.Requires(module != null);\n     Contract.Ensures(Contract.ValueAtReturn(out refinementConstraintDecl) != null);\n     IToken x;\n  .)\n  ( \"refinement_constraint\" (. x = t; .)\n    stringToken             (. refinementConstraintDecl = new RefinementConstraintDecl(x, module, t.val); .)\n  )\n.\n\nPeriodSeparatedIdentifierList<.out List<IToken> ids.>\n= (. IToken id;\n     ids = new List<IToken>(); .)\n  NoUSIdent<out id> (. ids.Add(id); .)\n  { \".\" NoUSIdent<out id> (. ids.Add(id); .)\n  }\n  .\n\nClassMemberDecl<. DeclModifierData dmod, List<MemberDecl> mm, bool allowConstructors, bool isValueType, bool moduleLevelDecl, bool isWithinAbstractModule.>\n= (. Contract.Requires(cce.NonNullElements(mm));\n     Method/*!*/ m;\n     Function/*!*/ f;\n     GlobalInvariantDecl globalInvariant;\n     YieldPredicateDecl yieldPredicate;\n     UniversalStepConstraintDecl stepConstraint;\n  .)\n  ( (. if (moduleLevelDecl) {\n         SemErr(la, \"fields are not allowed to be declared at the module level; instead, wrap the field in a 'class' declaration\");\n         dmod.IsStatic = false;\n       }\n    .)\n    FieldDecl<dmod, isValueType, mm>\n  | ConstantFieldDecl<dmod, mm, moduleLevelDecl>\n  | IF(IsFunctionDecl())\n    (. if (moduleLevelDecl && dmod.StaticToken != null) {\n         errors.Warning(dmod.StaticToken, \"module-level functions are always non-instance, so the 'static' keyword is not allowed here\");\n         dmod.IsStatic = false;\n       }\n    .)\n    FunctionDecl<dmod, isWithinAbstractModule, out f>                   (. mm.Add(f); .)\n  | (. if (moduleLevelDecl && dmod.StaticToken != null) {\n         errors.Warning(dmod.StaticToken, \"module-level methods are always non-instance, so the 'static' keyword is not allowed here\");\n         dmod.IsStatic = false;\n       }\n    .)\n    MethodDecl<dmod, allowConstructors, isWithinAbstractModule, out m>  (. mm.Add(m); .)\n  | GlobalInvariantDecl<dmod, out globalInvariant> (. mm.Add(globalInvariant); .)\n  | YieldPredicateDecl<dmod, out yieldPredicate> (. mm.Add(yieldPredicate); .)\n  | UniversalStepConstraintDecl<dmod, out stepConstraint> (. mm.Add(stepConstraint); .)\n\n  )\n  .\nDatatypeDecl<DeclModifierData dmod, ModuleDefinition/*!*/ module, out DatatypeDecl/*!*/ dt>\n= (. Contract.Requires(module != null);\n     Contract.Ensures(Contract.ValueAtReturn(out dt)!=null);\n     IToken/*!*/ id;\n     Attributes attrs = null;\n     List<TypeParameter/*!*/> typeArgs = new List<TypeParameter/*!*/>();\n     List<DatatypeCtor/*!*/> ctors = new List<DatatypeCtor/*!*/>();\n     IToken bodyStart = Token.NoToken;  // dummy assignment\n     bool co = false;\n     CheckDeclModifiers(dmod, \"Datatypes or codatatypes\", AllowedDeclModifiers.None);\n     var members = new List<MemberDecl>();\n  .)\n  SYNC\n  ( \"datatype\"\n  | \"codatatype\"     (. co = true; .)\n  )\n  { Attribute<ref attrs> }\n  NoUSIdent<out id>\n  [ GenericParameters<typeArgs, true> ]\n  \"=\"                                      (. bodyStart = t; .)\n  [ \"|\" ] DatatypeMemberDecl<ctors>\n  { \"|\" DatatypeMemberDecl<ctors> }\n  [ TypeMembers<module, members> ]\n  (. if (co) {\n       dt = new CoDatatypeDecl(id, id.val, module, typeArgs, ctors, members, attrs);\n     } else {\n       dt = new IndDatatypeDecl(id, id.val, module, typeArgs, ctors, members, attrs);\n     }\n     dt.BodyStartTok = bodyStart;\n     dt.BodyEndTok = t;\n  .)\n  .\nDatatypeMemberDecl<.List<DatatypeCtor/*!*/>/*!*/ ctors.>\n= (. Contract.Requires(cce.NonNullElements(ctors));\n     Attributes attrs = null;\n     IToken/*!*/ id;\n     List<Formal/*!*/> formals = new List<Formal/*!*/>();\n  .)\n  { Attribute<ref attrs> }\n  NoUSIdent<out id>\n  [ FormalsOptionalIds<formals> ]\n  (. ctors.Add(new DatatypeCtor(id, id.val, formals, attrs)); .)\n  .\nTypeMembers<. ModuleDefinition/*!*/ module, List<MemberDecl> members .>\n= (. DeclModifierData dmod;\n  .)\n  \"{\"\n  { (. dmod = new DeclModifierData(); .)\n    { DeclModifier<ref dmod> }\n    ClassMemberDecl<dmod, members, false, true, false, module.IsAbstract>\n  }\n  \"}\"\n  .\nFieldDecl<.DeclModifierData dmod, bool isValueType, List<MemberDecl> mm.>\n= (. Contract.Requires(cce.NonNullElements(mm));\n     Attributes attrs = null;\n     IToken/*!*/ id;  Type/*!*/ ty;\n     Expression initialValue = null;\n     CheckDeclModifiers(dmod, \"Fields\", AllowedDeclModifiers.Ghost | AllowedDeclModifiers.NoAddr | AllowedDeclModifiers.Static);\n     if (isValueType) {\n       // we're about to produce an error; put fields into a throw-away list, so we don't return them\n       mm = new List<MemberDecl>();\n     }\n  .)\n  SYNC\n  \"var\"                                             (. if (isValueType) {\n                                                         SemErr(t, \"mutable fields are now allowed in value types\");\n                                                       }\n                                                    .)\n  { Attribute<ref attrs> }\n  FIdentType<out id, out ty>\n    [ \":=\" Expression<out initialValue, false, false> ]\n    (. mm.Add(new Field(id, id.val, dmod.IsGhost, ty, attrs, dmod.IsNoAddr, dmod.IsStatic, initialValue)); .)\n  { \",\" FIdentType<out id, out ty>\n    [ \":=\" Expression<out initialValue, false, false> ]\n    (. mm.Add(new Field(id, id.val, dmod.IsGhost, ty, attrs, dmod.IsNoAddr, dmod.IsStatic, initialValue)); .)\n  }\n  OldSemi\n  .\nConstantFieldDecl<.DeclModifierData dmod, List<MemberDecl/*!*/>/*!*/ mm, bool moduleLevelDecl.>\n= (. Contract.Requires(cce.NonNullElements(mm));\n     Attributes attrs = null;\n     IToken/*!*/ id;  Type/*!*/ ty;\n     Expression e = null;\n     if (moduleLevelDecl && dmod.StaticToken != null) {\n       errors.Warning(dmod.StaticToken, \"module-level const declarations are always non-instance, so the 'static' keyword is not allowed here\");\n       dmod.IsStatic = false;\n     }\n     CheckDeclModifiers(dmod, \"Fields\", AllowedDeclModifiers.Ghost | AllowedDeclModifiers.Static | AllowedDeclModifiers.NoAddr);\n  .)\n  SYNC\n  \"const\"\n  { Attribute<ref attrs> }\n  CIdentType<out id, out ty>                 (. if (ty == null) { ty = new InferredTypeProxy(); } .)\n  [ \":=\" Expression<out e, false, true> ]\n                                             (. if (e == null && ty is InferredTypeProxy) {\n                                                  SemErr(id, \"a const declaration must have a type or a RHS value\");\n                                                }\n                                                mm.Add(new ConstantField(id, id.val, e, dmod.IsStatic, dmod.IsGhost, ty, attrs));\n                                             .)\n  OldSemi\n  .\nNewtypeDecl<DeclModifierData dmod, ModuleDefinition module, out TopLevelDecl td>\n= (. IToken id, bvId;\n     Attributes attrs = null;\n     td = null;\n     Type baseType = null;\n     Expression constraint;\n     Expression witness = null;\n     bool witnessIsGhost = false;\n     CheckDeclModifiers(dmod, \"Newtypes\", AllowedDeclModifiers.None);\n     var members = new List<MemberDecl>();\n  .)\n  \"newtype\"\n  { Attribute<ref attrs> }\n  NoUSIdent<out id>\n  \"=\"\n  ( IF(IsIdentColonOrBar())\n    NoUSIdent<out bvId>\n    [ \":\" Type<out baseType> ]       (. if (baseType == null) { baseType = new InferredTypeProxy(); } .)\n    \"|\"\n    Expression<out constraint, false, true>\n    [ IF(IsWitness())\n      [ \"ghost\"                      (. witnessIsGhost = true; .)\n      ]\n      \"witness\" Expression<out witness, false, true>\n    ]\n    [ TypeMembers<module, members> ]\n    (. var witnessKind = witness == null ? SubsetTypeDecl.WKind.None :\n       witnessIsGhost ? SubsetTypeDecl.WKind.Ghost : SubsetTypeDecl.WKind.Compiled;\n       td = new NewtypeDecl(id, id.val, module, new BoundVar(bvId, bvId.val, baseType), constraint, witnessKind, witness, members, attrs); .)\n  | Type<out baseType>\n    [ TypeMembers<module, members> ]\n    (. td = new NewtypeDecl(id, id.val, module, baseType, members, attrs); .)\n  )\n  .\nOtherTypeDecl<DeclModifierData dmod, ModuleDefinition module, out TopLevelDecl td>\n= (. IToken id, bvId;\n     Attributes attrs = null;\n     var characteristics = new TypeParameter.TypeParameterCharacteristics(false);\n     var typeArgs = new List<TypeParameter>();\n     td = null;\n     Type ty = null;\n     Expression constraint;\n     Expression witness = null;\n     bool witnessIsGhost = false;\n     var kind = \"Opaque type\";\n  .)\n  \"type\"\n  { Attribute<ref attrs> }\n  NoUSIdent<out id>\n  { TypeParameterCharacteristics<ref characteristics> }\n  [ GenericParameters<typeArgs, true> ]\n  [ \"=\"\n    ( IF(IsIdentColonOrBar())\n      NoUSIdent<out bvId>\n      [ \":\" Type<out ty> ]   (. if (ty == null) { ty = new InferredTypeProxy(); } .)\n      \"|\"\n      Expression<out constraint, false, true>\n      [ IF(IsWitness())\n        [ \"ghost\"            (. witnessIsGhost = true; .)\n        ]\n        \"witness\" Expression<out witness, false, true>\n      ]\n                             (. var witnessKind = witness == null ? SubsetTypeDecl.WKind.None :\n                                  witnessIsGhost ? SubsetTypeDecl.WKind.Ghost : SubsetTypeDecl.WKind.Compiled;\n                                td = new SubsetTypeDecl(id, id.val, characteristics, typeArgs, module, new BoundVar(bvId, bvId.val, ty), constraint, witnessKind, witness, attrs);\n                                kind = \"Subset type\";\n                             .)\n    |\n      Type<out ty>           (. td = new TypeSynonymDecl(id, id.val, characteristics, typeArgs, module, ty, attrs);\n                                kind = \"Type synonym\";\n                             .)\n    )\n  ]\n                             (. if (td == null) {\n                                  if (module is DefaultModuleDecl) {\n                                    // opaque type declarations at the very outermost program scope get an automatic (!new)\n                                    characteristics.DisallowReferenceTypes = true;\n                                  }\n                                  td = new OpaqueTypeDecl(id, id.val, module, characteristics, typeArgs, attrs);\n                                }\n                             .)\n  (. CheckDeclModifiers(dmod, kind, AllowedDeclModifiers.None); .)\n  [ SYNC \";\"\n      // This semi-colon used to be required, but it seems silly to have it.\n      // To stage the transition toward not having it at all, let's make it optional for now.  Then,\n      // in the next big version of Dafny, don't allow the semi-colon at all.\n      (. errors.Deprecated(t, \"the semi-colon that used to terminate an opaque-type declaration has been deprecated; in the new syntax, just leave off the semi-colon\"); .)\n  ]\n  .\nGIdentType<bool allowGhostKeyword, bool allowNewKeyword, out IToken/*!*/ id, out Type/*!*/ ty, out bool isGhost, out bool isOld>\n/* isGhost always returns as false if allowGhostKeyword is false */\n= (. Contract.Ensures(Contract.ValueAtReturn(out id)!=null);\n     Contract.Ensures(Contract.ValueAtReturn(out ty)!=null);\n     isGhost = false; isOld = allowNewKeyword; .)\n  { \"ghost\"                    (. if (allowGhostKeyword) { isGhost = true; } else { SemErr(t, \"formal cannot be declared 'ghost' in this context\"); } .)\n  | \"new\"                      (. if (allowNewKeyword) { isOld = false; } else { SemErr(t, \"formal cannot be declared 'new' in this context\"); } .)\n  }\n  IdentType<out id, out ty, true>\n  .\nFIdentType<out IToken/*!*/ id, out Type/*!*/ ty>\n= (.Contract.Ensures(Contract.ValueAtReturn(out id) != null); Contract.Ensures(Contract.ValueAtReturn(out ty) != null);\n    id = Token.NoToken;\n  .)\n  ( WildIdent<out id, false>\n  | digits         (. id = t; .)\n  )\n  \":\"\n  Type<out ty>\n  .\nCIdentType<out IToken/*!*/ id, out Type ty>\n= (.Contract.Ensures(Contract.ValueAtReturn(out id) != null);\n    id = Token.NoToken;\n    ty = null;\n  .)\n  ( WildIdent<out id, false>\n  | digits         (. id = t; .)\n  )\n  [ \":\"\n    Type<out ty>\n  ]\n  .\nIdentType<out IToken/*!*/ id, out Type/*!*/ ty, bool allowWildcardId>\n= (.Contract.Ensures(Contract.ValueAtReturn(out id) != null); Contract.Ensures(Contract.ValueAtReturn(out ty) != null);.)\n  WildIdent<out id, allowWildcardId>\n  \":\"\n  Type<out ty>\n  .\nLocalIdentTypeOptional<out LocalVariable var, bool isGhost, bool isNoAddr>\n= (. IToken id;  Type ty;  Type optType = null;\n  .)\n  WildIdent<out id, true>\n  [ \":\" Type<out ty>             (. optType = ty; .)\n  ]\n  (. var = new LocalVariable(id, id, id.val, optType == null ? new InferredTypeProxy() : optType, isGhost, isNoAddr); .)\n  .\nIdentTypeOptional<out BoundVar var>\n= (. Contract.Ensures(Contract.ValueAtReturn(out var) != null);\n     IToken id;  Type ty;  Type optType = null;\n  .)\n  WildIdent<out id, true>\n  [ \":\" Type<out ty>             (. optType = ty; .)\n  ]\n  (. var = new BoundVar(id, id.val, optType == null ? new InferredTypeProxy() : optType); .)\n  .\nTypeIdentOptional<out IToken/*!*/ id, out string/*!*/ identName, out Type/*!*/ ty, out bool isGhost>\n= (.Contract.Ensures(Contract.ValueAtReturn(out id)!=null);\n     Contract.Ensures(Contract.ValueAtReturn(out ty)!=null);\n     Contract.Ensures(Contract.ValueAtReturn(out identName)!=null);\n     string name = null; id = Token.NoToken; ty = new BoolType()/*dummy*/; isGhost = false; .)\n  [ \"ghost\"                            (. isGhost = true; .)\n  ]\n  ( TypeAndToken<out id, out ty, false>\n    [ \":\"\n      (. /* try to convert ty to an identifier */\n         UserDefinedType udt = ty as UserDefinedType;\n         if (udt != null && udt.TypeArgs.Count == 0) {\n           name = udt.Name;\n         } else {\n           SemErr(id, \"invalid formal-parameter name in datatype constructor\");\n         }\n      .)\n      Type<out ty>\n    ]\n  | digits         (. id = t; name = id.val;.)\n    \":\"\n    Type<out ty>\n  )\n  (. if (name != null) {\n       identName = name;\n     } else {\n       identName = \"#\" + anonymousIds++;\n     }\n  .)\n  .\n/*------------------------------------------------------------------------*/\nIteratorDecl<DeclModifierData dmod, ModuleDefinition module, out IteratorDecl/*!*/ iter>\n= (. Contract.Ensures(Contract.ValueAtReturn(out iter) != null);\n     IToken/*!*/ id;\n     Attributes attrs = null;\n     List<TypeParameter/*!*/>/*!*/ typeArgs = new List<TypeParameter/*!*/>();\n     List<Formal/*!*/> ins = new List<Formal/*!*/>();\n     List<Formal/*!*/> outs = new List<Formal/*!*/>();\n     List<FrameExpression/*!*/> reads = new List<FrameExpression/*!*/>();\n     List<FrameExpression/*!*/> mod = new List<FrameExpression/*!*/>();\n     List<Expression/*!*/> decreases = new List<Expression>();\n     List<MaybeFreeExpression/*!*/> req = new List<MaybeFreeExpression/*!*/>();\n     List<MaybeFreeExpression/*!*/> ens = new List<MaybeFreeExpression/*!*/>();\n     List<MaybeFreeExpression/*!*/> yieldReq = new List<MaybeFreeExpression/*!*/>();\n     List<MaybeFreeExpression/*!*/> yieldEns = new List<MaybeFreeExpression/*!*/>();\n     List<Expression/*!*/> dec = new List<Expression/*!*/>();\n     Attributes readsAttrs = null;\n     Attributes modAttrs = null;\n     Attributes decrAttrs = null;\n     BlockStmt body = null;\n     IToken signatureEllipsis = null;\n     IToken bodyStart = Token.NoToken;\n     IToken bodyEnd = Token.NoToken;\n     CheckDeclModifiers(dmod, \"Iterators\", AllowedDeclModifiers.None);\n  .)\n  SYNC\n  \"iterator\"\n  { Attribute<ref attrs> }\n  NoUSIdent<out id>\n  (\n    [ GenericParameters<typeArgs, true> ]\n    Formals<true, true, false, ins>\n    [ ( \"yields\"\n      | \"returns\"           (. SemErr(t, \"iterators don't have a 'returns' clause; did you mean 'yields'?\"); .)\n      )\n      Formals<false, true, false, outs>\n    ]\n  | \"...\"                                       (. signatureEllipsis = t; .)\n  )\n  { IteratorSpec<reads, mod, decreases, req, ens, yieldReq, yieldEns, ref readsAttrs, ref modAttrs, ref decrAttrs> }\n  [ BlockStmt<out body, out bodyStart, out bodyEnd>\n  ]\n  (. iter = new IteratorDecl(id, id.val, module, typeArgs, ins, outs,\n                             new Specification<FrameExpression>(reads, readsAttrs),\n                             new Specification<FrameExpression>(mod, modAttrs),\n                             new Specification<Expression>(decreases, decrAttrs),\n                             req, ens, yieldReq, yieldEns,\n                             body, attrs, signatureEllipsis);\n     iter.BodyStartTok = bodyStart;\n     iter.BodyEndTok = bodyEnd;\n .)\n  .\n/*------------------------------------------------------------------------*/\nGenericParameters<.List<TypeParameter/*!*/>/*!*/ typeArgs, bool allowVariance.>\n= (. Contract.Requires(cce.NonNullElements(typeArgs));\n     IToken/*!*/ id;\n     TypeParameter.TypeParameterCharacteristics characteristics;\n     TypeParameter.TPVarianceSyntax variance = TypeParameter.TPVarianceSyntax.NonVariant_Strict;  // assignment is to please compiler\n     characteristics = new TypeParameter.TypeParameterCharacteristics(false);\n  .)\n  // There's a subtle issue here.  The next things in the input could be a '<' followed by an '=' (and then an identifier).\n  // This is legal (provided \"allowVariance\" is \"true\").  However, unless there's whitespace between the '<' and '=', the\n  // scanner will read these two characters as a \"<=\" token.\n  \"<\"\n  [ Variance<out variance>  (. if (!allowVariance) { SemErr(t, \"type-parameter variance is not allowed to be specified in this context\"); } .)\n  ]\n  NoUSIdent<out id>\n  { TypeParameterCharacteristics<ref characteristics> }\n  (. typeArgs.Add(new TypeParameter(id, id.val, variance, characteristics)); .)\n  { \",\"\n    (. variance = TypeParameter.TPVarianceSyntax.NonVariant_Strict;\n       characteristics = new TypeParameter.TypeParameterCharacteristics(false);\n    .)\n    [ Variance<out variance>  (. if (!allowVariance) { SemErr(t, \"type-parameter variance is not allowed to be specified in this context\"); } .)\n    ]\n    NoUSIdent<out id>\n    { TypeParameterCharacteristics<ref characteristics> }\n    (. typeArgs.Add(new TypeParameter(id, id.val, variance, characteristics)); .)\n  }\n  \">\"\n  .\nVariance<out TypeParameter.TPVarianceSyntax variance>\n= (. variance = TypeParameter.TPVarianceSyntax.NonVariant_Strict;  // never used; here just to please the C# compiler\n  .)\n  ( \"*\"  (. variance = TypeParameter.TPVarianceSyntax.Covariant_Permissive; .)\n  | \"+\"  (. variance = TypeParameter.TPVarianceSyntax.Covariant_Strict; .)\n  | \"!\"  (. variance = TypeParameter.TPVarianceSyntax.NonVariant_Permissive; .)\n  | \"-\"  (. variance = TypeParameter.TPVarianceSyntax.Contravariance; .)\n  )\n  .\nTypeParameterCharacteristics<ref TypeParameter.TypeParameterCharacteristics characteristics>\n= \"(\"\n  TPCharOption<ref characteristics>\n  { \",\"\n    TPCharOption<ref characteristics>\n  }\n  \")\"\n  .\nTPCharOption<ref TypeParameter.TypeParameterCharacteristics characteristics>\n= ( \"==\"       (. characteristics.EqualitySupport = TypeParameter.EqualitySupportValue.Required; .)\n  | digits     (. if (t.val == \"0\") {\n                    characteristics.MustSupportZeroInitialization = true;\n                  } else {\n                    SemErr(t, \"unexpected TPCharOption\");\n                  }\n               .)\n  | \"!\" \"new\"  (. characteristics.DisallowReferenceTypes = true; .)\n  )\n  .\n/*------------------------------------------------------------------------*/\nMethodDecl<DeclModifierData dmod, bool allowConstructor, bool isWithinAbstractModule, out Method/*!*/ m>\n= (. Contract.Ensures(Contract.ValueAtReturn(out m) !=null);\n     IToken/*!*/ id = Token.NoToken;\n     bool hasName = false;  IToken keywordToken;\n     Attributes attrs = null;\n     List<TypeParameter/*!*/>/*!*/ typeArgs = new List<TypeParameter/*!*/>();\n     List<Formal/*!*/> ins = new List<Formal/*!*/>();\n     List<Formal/*!*/> outs = new List<Formal/*!*/>();\n     List<MaybeFreeExpression/*!*/> req = new List<MaybeFreeExpression/*!*/>();\n     List<FrameExpression/*!*/> mod = new List<FrameExpression/*!*/>();\n     List<MaybeFreeExpression/*!*/> ens = new List<MaybeFreeExpression/*!*/>();\n     List<Expression/*!*/> dec = new List<Expression/*!*/>();\n     List<Expression/*!*/> reads = new List<Expression/*!*/>();\n     List<Expression/*!*/> awaits = new List<Expression/*!*/>();\n     List<Expression/*!*/> undefinedUnless = new List<Expression/*!*/>();\n     Attributes decAttrs = null;\n     Attributes modAttrs = null;\n     BlockStmt body = null;\n     bool isPlainOlMethod = false;\n     bool isLemma = false;\n     bool isTwoStateLemma = false;\n     bool isConstructor = false;\n     bool isDestructor = false;\n     bool isIndLemma = false;\n     bool isCoLemma = false;\n     IToken signatureEllipsis = null;\n     IToken bodyStart = Token.NoToken;\n     IToken bodyEnd = Token.NoToken;\n     AllowedDeclModifiers allowed = AllowedDeclModifiers.None;\n     string caption = \"\";\n     FixpointPredicate.KType kType = FixpointPredicate.KType.Unspecified;\n  .)\n  SYNC\n  ( \"method\"                        (. isPlainOlMethod = true; caption = \"Methods\";\n                                       allowed = AllowedDeclModifiers.Ghost | AllowedDeclModifiers.Static; .)\n  | \"lemma\"                         (. isLemma = true; caption = \"Lemmas\";\n                                       allowed = AllowedDeclModifiers.AlreadyGhost | AllowedDeclModifiers.Static\n                                         | AllowedDeclModifiers.Protected; .)\n  | \"colemma\"                       (. isCoLemma = true; caption = \"Colemmas\";\n                                       allowed = AllowedDeclModifiers.AlreadyGhost | AllowedDeclModifiers.Static\n                                         | AllowedDeclModifiers.Protected; .)\n  | \"comethod\"                      (. isCoLemma = true; caption = \"Comethods\";\n                                       allowed = AllowedDeclModifiers.AlreadyGhost | AllowedDeclModifiers.Static\n                                         | AllowedDeclModifiers.Protected;\n                                       errors.Deprecated(t, \"the 'comethod' keyword has been deprecated; it has been renamed to 'colemma'\");\n                                    .)\n  | \"inductive\" \"lemma\"             (. isIndLemma = true;  caption = \"Inductive lemmas\";\n                                       allowed = AllowedDeclModifiers.AlreadyGhost | AllowedDeclModifiers.Static;.)\n  | \"twostate\" \"lemma\"              (. isTwoStateLemma = true; caption = \"Two-state lemmas\";\n                                       allowed = AllowedDeclModifiers.AlreadyGhost | AllowedDeclModifiers.Static\n                                         | AllowedDeclModifiers.Protected; .)\n  | \"constructor\"                   (. if (allowConstructor) {\n                                         isConstructor = true;\n                                       } else {\n                                         SemErr(t, \"constructors are allowed only in classes\");\n                                       }\n                                       caption = \"Constructors\";\n                                       allowed = AllowedDeclModifiers.None;\n                                    .)\n  | \"destructor\"                    (. if (allowConstructor) {\n                                         isDestructor = true;\n                                       } else {\n                                         SemErr(t, \"destructors are allowed only in classes\");\n                                       }\n                                       caption = \"Destructors\";\n                                       allowed = AllowedDeclModifiers.None;\n                                    .)\n  )                                 (. keywordToken = t;\n                                       CheckDeclModifiers(dmod, caption, allowed); .)\n  { Attribute<ref attrs> }\n  [ FuMe_Ident<out id>               (. hasName = true; .)\n  ]\n  (. if (!hasName) {\n       id = keywordToken;\n       if (!isConstructor && !isDestructor) {\n         SemErr(la, \"a method must be given a name (expecting identifier)\");\n       }\n     }\n  .)\n  (\n    [ GenericParameters<typeArgs, false> ]\n    [ KType<ref kType>              (. if (!(isCoLemma || isIndLemma)) { SemErr(t, \"type of _k can only be specified for inductive lemmas and co-lemmas\"); } .)\n    ]\n    (. var isCompilable = (isPlainOlMethod && !dmod.IsGhost) || isConstructor || isDestructor; .)\n    Formals<true, isCompilable, isTwoStateLemma, ins> (. if (isDestructor && ins.Count > 0) { SemErr(t, \"destructors cannot have in-parameters\"); } .)\n    [ \"returns\"                                 (. if (isConstructor) { SemErr(t, \"constructors cannot have out-parameters\"); }\n                                                   if (isDestructor) { SemErr(t, \"destructors cannot have out-parameters\"); } .)\n      Formals<false, isCompilable, false, outs>\n    ]\n  | \"...\"                                       (. signatureEllipsis = t; .)\n  )\n  { MethodSpec<req, mod, ens, dec, reads, awaits, undefinedUnless, ref decAttrs, ref modAttrs, caption, isConstructor || isDestructor> }\n  [ IF(isConstructor)\n    (. DividedBlockStmt dividedBody; .)\n    DividedBlockStmt<out dividedBody, out bodyStart, out bodyEnd>\n    (. body = dividedBody; .)\n  | BlockStmt<out body, out bodyStart, out bodyEnd>\n  ]\n  (.\n     if (!isWithinAbstractModule && ArmadaOptions.O.DisallowSoundnessCheating && body == null && ens.Count > 0 && !Attributes.Contains(attrs, \"axiom\") && !Attributes.Contains(attrs, \"imported\") && !Attributes.Contains(attrs, \"decl\") && theVerifyThisFile) {\n        SemErr(t, \"a method with an ensures clause must have a body, unless given the :axiom attribute\");\n     }\n\n     IToken tok = id;\n     if (isConstructor) {\n       m = new Constructor(tok, hasName ? id.val : \"_ctor\", typeArgs, ins,\n                           req, new Specification<FrameExpression>(mod, modAttrs), ens, new Specification<Expression>(dec, decAttrs), (DividedBlockStmt)body, attrs, signatureEllipsis);\n     } else if (isDestructor) {\n       m = new Destructor(tok, hasName ? id.val : \"_dtor\", typeArgs, ins,\n                          req, new Specification<FrameExpression>(mod, modAttrs), ens, new Specification<Expression>(dec, decAttrs), body, attrs, signatureEllipsis);\n     } else if (isIndLemma) {\n       m = new InductiveLemma(tok, id.val, dmod.IsStatic, kType, typeArgs, ins, outs,\n                              req, new Specification<FrameExpression>(mod, modAttrs), ens, new Specification<Expression>(dec, decAttrs), body, attrs, signatureEllipsis);\n     } else if (isCoLemma) {\n       m = new CoLemma(tok, id.val, dmod.IsStatic, kType, typeArgs, ins, outs,\n                       req, new Specification<FrameExpression>(mod, modAttrs), ens, new Specification<Expression>(dec, decAttrs), body, attrs, signatureEllipsis);\n     } else if (isLemma) {\n       m = new Lemma(tok, id.val, dmod.IsStatic, typeArgs, ins, outs,\n                     req, new Specification<FrameExpression>(mod, modAttrs), ens, new Specification<Expression>(dec, decAttrs), body, attrs, signatureEllipsis);\n     } else if (isTwoStateLemma) {\n       m = new TwoStateLemma(tok, id.val, dmod.IsStatic, typeArgs, ins, outs,\n                             req, new Specification<FrameExpression>(mod, modAttrs),\n                             ens, new Specification<Expression>(dec, decAttrs), body, attrs, signatureEllipsis);\n    } else {\n       m = new Method(tok, id.val, dmod.IsStatic, dmod.IsGhost, typeArgs, ins, outs,\n                      req, new Specification<FrameExpression>(mod, modAttrs), ens, new Specification<Expression>(dec, decAttrs), new Specification<Expression>(reads, null), awaits, undefinedUnless, body, attrs, signatureEllipsis);\n     }\n     m.BodyStartTok = bodyStart;\n     m.BodyEndTok = bodyEnd;\n .)\n  .\nKType<ref FixpointPredicate.KType kType>\n= \"[\"\n  ( \"nat\"       (. kType = FixpointPredicate.KType.Nat; .)\n  | \"ORDINAL\"   (. kType = FixpointPredicate.KType.ORDINAL; .)\n  )\n  \"]\"\n  .\nMethodSpec<.List<MaybeFreeExpression> req, List<FrameExpression> mod, List<MaybeFreeExpression> ens,\n            List<Expression> decreases, List<Expression> reads, List<Expression> awaits, List<Expression> undefinedUnless,\n            ref Attributes decAttrs, ref Attributes modAttrs, string caption, bool performThisDeprecatedCheck.>\n= (. Contract.Requires(cce.NonNullElements(req));\n     Contract.Requires(cce.NonNullElements(mod));\n     Contract.Requires(cce.NonNullElements(ens));\n     Contract.Requires(cce.NonNullElements(decreases));\n     Expression e;  FrameExpression fe;  bool isFree = false; Attributes ensAttrs = null; Attributes reqAttrs = null;\n     IToken lbl = null;\n  .)\n  SYNC\n  ( \"modifies\" { Attribute<ref modAttrs> }\n               FrameExpression<out fe, false, false>         (. Util.AddFrameExpression(mod, fe, performThisDeprecatedCheck, errors); .)\n               { \",\" FrameExpression<out fe, false, false>   (. Util.AddFrameExpression(mod, fe, performThisDeprecatedCheck, errors); .)\n               }\n               OldSemi\n  | [ \"free\"                                                 (. isFree = true;\n                                                                errors.Deprecated(t, \"the 'free' keyword is soon to be deprecated\");\n                                                             .)\n    ]\n    ( \"requires\"\n      { Attribute<ref reqAttrs> }\n      [ IF(IsLabel(true))\n        LabelIdent<out lbl> \":\"\n      ]\n      Expression<out e, false, false> OldSemi                (. req.Add(new MaybeFreeExpression(e, isFree, lbl == null ? null : new AssertLabel(lbl, lbl.val), reqAttrs)); .)\n    | \"ensures\"\n      { Attribute<ref ensAttrs> }\n      Expression<out e, false, false> OldSemi                (. ens.Add(new MaybeFreeExpression(e, isFree, ensAttrs)); .)\n    )\n  | \"decreases\" { Attribute<ref decAttrs> } DecreasesList<decreases, true, false> OldSemi\n  | \"reads\"    Expression<out e, false, false>               (. reads.Add(e); .)\n               { \",\" Expression<out e, false, false>         (. reads.Add(e); .)\n               }\n               OldSemi\n  | \"awaits\"   Expression<out e, false, false>               (. awaits.Add(e); .)\n               { \",\" Expression<out e, false, false>         (. awaits.Add(e); .)\n               }\n               OldSemi\n  | \"undefined_unless\"\n               Expression<out e, false, false>               (. undefinedUnless.Add(e); .)\n               { \",\" Expression<out e, false, false>         (. undefinedUnless.Add(e); .)\n               }\n               OldSemi\n  )\n  .\nIteratorSpec<.List<FrameExpression/*!*/>/*!*/ reads, List<FrameExpression/*!*/>/*!*/ mod, List<Expression/*!*/> decreases,\n              List<MaybeFreeExpression/*!*/>/*!*/ req, List<MaybeFreeExpression/*!*/>/*!*/ ens,\n              List<MaybeFreeExpression/*!*/>/*!*/ yieldReq, List<MaybeFreeExpression/*!*/>/*!*/ yieldEns,\n              ref Attributes readsAttrs, ref Attributes modAttrs, ref Attributes decrAttrs.>\n= (. Expression/*!*/ e; FrameExpression/*!*/ fe; bool isFree = false; bool isYield = false; Attributes ensAttrs = null;\n     IToken lbl = null;\n  .)\n  SYNC\n  ( \"reads\"    { Attribute<ref readsAttrs> }\n               FrameExpression<out fe, false, false>       (. reads.Add(fe); .)\n               { \",\" FrameExpression<out fe, false, false> (. reads.Add(fe); .)\n               }\n               OldSemi\n  | \"modifies\" { Attribute<ref modAttrs> }\n               FrameExpression<out fe, false, false>       (. mod.Add(fe); .)\n               { \",\" FrameExpression<out fe, false, false> (. mod.Add(fe); .)\n               }\n               OldSemi\n  | [ \"free\"                                                 (. isFree = true;\n                                                                errors.Deprecated(t, \"the 'free' keyword is soon to be deprecated\");\n                                                             .)\n    ]\n    [ \"yield\"                                                (. isYield = true; .)\n    ]\n    ( \"requires\"\n      [ IF(IsLabel(!isYield))\n        LabelIdent<out lbl> \":\"\n      ]\n      Expression<out e, false, false> OldSemi                (. AssertLabel al = lbl == null ? null : new AssertLabel(lbl, lbl.val);\n                                                                if (isYield) {\n                                                                  yieldReq.Add(new MaybeFreeExpression(e, isFree, al, null));\n                                                                } else {\n                                                                  req.Add(new MaybeFreeExpression(e, isFree, al, null));\n                                                                }\n                                                             .)\n    | \"ensures\" { Attribute<ref ensAttrs> }\n      Expression<out e, false, false> OldSemi                (. if (isYield) {\n                                                                  yieldEns.Add(new MaybeFreeExpression(e, isFree, ensAttrs));\n                                                                } else {\n                                                                  ens.Add(new MaybeFreeExpression(e, isFree, ensAttrs));\n                                                                }\n                                                             .)\n    )\n  | \"decreases\" { Attribute<ref decrAttrs> } DecreasesList<decreases, false, false> OldSemi\n  )\n  .\nFormals<.bool incoming, bool allowGhostKeyword, bool allowNewKeyword, List<Formal> formals.>\n= (. Contract.Requires(cce.NonNullElements(formals));\n     IToken id;\n     Type ty;\n     bool isGhost;\n     bool isOld;\n  .)\n  \"(\"\n  [\n    GIdentType<allowGhostKeyword, allowNewKeyword, out id, out ty, out isGhost, out isOld>\n                 (. formals.Add(new Formal(id, id.val, ty, incoming, isGhost, isOld)); .)\n    { \",\" GIdentType<allowGhostKeyword, allowNewKeyword, out id, out ty, out isGhost, out isOld>\n                 (. formals.Add(new Formal(id, id.val, ty, incoming, isGhost, isOld)); .)\n    }\n  ]\n  \")\"\n  .\nFormalsOptionalIds<.List<Formal/*!*/>/*!*/ formals.>\n= (. Contract.Requires(cce.NonNullElements(formals)); IToken/*!*/ id;  Type/*!*/ ty;  string/*!*/ name;  bool isGhost; .)\n  \"(\"\n  [\n    TypeIdentOptional<out id, out name, out ty, out isGhost>        (. formals.Add(new Formal(id, name, ty, true, isGhost)); .)\n    { \",\" TypeIdentOptional<out id, out name, out ty, out isGhost>  (. formals.Add(new Formal(id, name, ty, true, isGhost)); .)\n    }\n  ]\n  \")\"\n  .\n/*------------------------------------------------------------------------*/\nType<out Type ty>\n= (. Contract.Ensures(Contract.ValueAtReturn(out ty) != null); IToken/*!*/ tok; .)\n  TypeAndToken<out tok, out ty, false>\n  .\n\nTypeAndToken<out IToken tok, out Type ty, bool inExpressionContext>\n= (. Contract.Ensures(Contract.ValueAtReturn(out tok)!=null); Contract.Ensures(Contract.ValueAtReturn(out ty) != null);\n     tok = Token.NoToken;  ty = new BoolType();  /*keep compiler happy*/\n     List<Type> gt; List<Type> tupleArgTypes = null;\n     BigInteger n;\n  .)\n  ( \"bool\"                          (. tok = t; .)\n  | \"char\"                          (. tok = t;  ty = new CharType(); .)\n  | \"int\"                           (. tok = t;  ty = new IntType(); .)\n  | \"nat\"                           (. tok = t;  ty = new UserDefinedType(tok, tok.val, null); .)\n  | \"real\"                          (. tok = t;  ty = new RealType(); .)\n  | \"ORDINAL\"                       (. tok = t;  ty = new BigOrdinalType(); .)\n  | bvToken                         (. tok = t;\n                                       int w = StringToInt(tok.val.Substring(2), 0, \"bitvectors that wide\");\n                                       ty = new BitvectorType(w);\n                                    .)\n  | \"set\"                           (. tok = t;.)\n    OptGenericInstantiation<out gt, inExpressionContext>\n                                    (. if (gt != null && gt.Count > 1) {\n                                         SemErr(\"set type expects only one type argument\");\n                                       }\n                                       ty = new SetType(true, gt != null ?gt[0] : null);\n                                    .)\n  | \"iset\"                          (. tok = t; .)\n    OptGenericInstantiation<out gt, inExpressionContext>\n                                    (. if (gt != null && gt.Count > 1) {\n                                         SemErr(\"set type expects only one type argument\");\n                                       }\n                                       ty = new SetType(false, gt != null ? gt[0] : null);\n                                    .)\n  | \"multiset\"                      (. tok = t; .)\n    OptGenericInstantiation<out gt, inExpressionContext>\n                                    (. if (gt != null && gt.Count > 1) {\n                                         SemErr(\"multiset type expects only one type argument\");\n                                       }\n                                       ty = new MultiSetType(gt != null ? gt[0] : null);\n                                    .)\n  | \"seq\"                           (. tok = t; .)\n    OptGenericInstantiation<out gt, inExpressionContext>\n                                    (. if (gt != null && gt.Count > 1) {\n                                         SemErr(\"seq type expects only one type argument\");\n                                       }\n                                       ty = new SeqType(gt != null ? gt[0] : null);\n                                    .)\n  | \"ptr\"                           (. tok = t; .)\n    OptGenericInstantiation<out gt, inExpressionContext>\n                                    (. if (gt != null && gt.Count > 1) {\n                                         SemErr(\"seq type expects only one type argument\");\n                                       }\n                                       ty = new PointerType(gt != null ? gt[0] : null);\n                                    .)\n  | \"string\"                        (. tok = t;  ty = new UserDefinedType(tok, tok.val, null); .)\n  | \"object\"                        (. tok = t;  ty = new UserDefinedType(tok, tok.val, null); .)\n  | \"object?\"                       (. tok = t;  ty = new UserDefinedType(tok, tok.val, null); .)\n  | \"map\"                           (. tok = t; .)\n    OptGenericInstantiation<out gt, inExpressionContext>\n                                    (. if (gt == null) {\n                                         ty = new MapType(true, null, null);\n                                       } else if (gt.Count != 2) {\n                                         SemErr(\"map type expects two type arguments\");\n                                         ty = new MapType(true, gt[0], gt.Count == 1 ? new InferredTypeProxy() : gt[1]);\n                                       } else {\n                                         ty = new MapType(true, gt[0], gt[1]);\n                                       }\n                                    .)\n  | \"imap\"                          (. tok = t; .)\n    OptGenericInstantiation<out gt, inExpressionContext>\n                                    (. if (gt == null) {\n                                         ty = new MapType(false, null, null);\n                                       } else if (gt.Count != 2) {\n                                         SemErr(\"imap type expects two type arguments\");\n                                         ty = new MapType(false, gt[0], gt.Count == 1 ? new InferredTypeProxy() : gt[1]);\n                                       } else {\n                                         ty = new MapType(false, gt[0], gt[1]);\n                                       }\n                                    .)\n  | arrayToken                      (. tok = t; .)\n    OptGenericInstantiation<out gt, inExpressionContext>\n                                    (. var dimString = tok.val.Substring(5);\n                                       int dims = StringToInt(dimString, 1, \"arrays of that many dimensions\");\n                                       ty = theBuiltIns.ArrayType(tok, dims, gt, true);\n                                    .)\n  | arrayToken_q                    (. tok = t; .)\n    OptGenericInstantiation<out gt, inExpressionContext>\n                                    (. var dimString = tok.val.Substring(5);\n                                       dimString = dimString.Substring(0, dimString.Length - 1);\n                                       int dims = StringToInt(dimString, 1, \"arrays of that many dimensions\");\n                                       ty = theBuiltIns.ArrayType(tok, dims, gt, true, true);\n                                    .)\n  | \"(\"                             (. tok = t; tupleArgTypes = new List<Type>(); .)\n    [ Type<out ty>                  (. tupleArgTypes.Add(ty); .)\n      { \",\" Type<out ty>            (. tupleArgTypes.Add(ty); .)\n      }\n    ]\n    \")\"                             (. if (tupleArgTypes.Count == 1) {\n                                         // just return the type 'ty'\n                                       } else {\n                                         var dims = tupleArgTypes.Count;\n                                         var tmp = theBuiltIns.TupleType(tok, dims, true);  // make sure the tuple type exists\n                                         ty = new UserDefinedType(tok, BuiltIns.TupleTypeName(dims), dims == 0 ? null : tupleArgTypes);\n                                       }\n                                    .)\n  | (. Expression e; .)\n    NameSegmentForTypeName<out e, inExpressionContext>  (. tok = t; .)\n    { \".\" TypeNameOrCtorSuffix<out tok>       (. List<Type> typeArgs; .)\n      OptGenericInstantiation<out typeArgs, inExpressionContext>\n      (. e = new ExprDotName(tok, e, tok.val, typeArgs); .)\n    }\n    (. ty = new UserDefinedType(e.tok, e); .)\n  )\n  [ IF(IsStaticArrayBracket()) \"[\" Nat<out n> \"]\"    (. ty = new SizedArrayType(ty, new LiteralExpr(Token.NoToken, n)); .) ]\n  [ (. int arrowKind = 0; /* 0: any, 1: partial, 2: total */\n       Type t2;\n    .)\n    ( \"~>\"           (. tok = t; arrowKind = 0; .)\n    | \"-->\"          (. tok = t; arrowKind = 1; .)\n    | \"->\"           (. tok = t; arrowKind = 2; .)\n    )\n    Type<out t2>\n    (. if (tupleArgTypes != null) {\n         gt = tupleArgTypes;\n        } else {\n         gt = new List<Type>{ ty };\n       }\n       var arity = gt.Count;\n       theBuiltIns.CreateArrowTypeDecl(arity);\n       if (arrowKind == 0) {\n         ty = new ArrowType(tok, gt, t2);\n       } else {\n         gt.Add(t2);\n         if (arrowKind == 1) {\n           ty = new UserDefinedType(tok, ArrowType.PartialArrowTypeName(arity), gt);\n         } else {\n           ty = new UserDefinedType(tok, ArrowType.TotalArrowTypeName(arity), gt);\n         }\n       }\n    .)\n  ]\n  .\nOptGenericInstantiation<.out List<Type> gt, bool inExpressionContext.>  /* NOTE: Coco complains about \"OptGenericInstantiation deletable\". That's okay. */\n= (. gt = null; .)\n  [ IF(IsGenericInstantiation(inExpressionContext))  /* be greedy -- if it looks like a type instantiation, take it */\n    (. gt = new List<Type>(); .)\n    GenericInstantiation<gt>\n  ]\n  .\nGenericInstantiation<.List<Type> gt.>\n= (. Contract.Requires(cce.NonNullElements(gt)); Type/*!*/ ty; .)\n  \"<\"\n    Type<out ty>                     (. gt.Add(ty); .)\n    { \",\" Type<out ty>               (. gt.Add(ty); .)\n    }\n  \">\"\n  .\n/*------------------------------------------------------------------------*/\nFunctionDecl<DeclModifierData dmod, bool isWithinAbstractModule, out Function/*!*/ f>\n= (. Contract.Ensures(Contract.ValueAtReturn(out f)!=null);\n     Attributes attrs = null;\n     IToken/*!*/ id = Token.NoToken;  // to please compiler\n     List<TypeParameter/*!*/> typeArgs = new List<TypeParameter/*!*/>();\n     List<Formal/*!*/> formals = new List<Formal/*!*/>();\n     List<Formal/*!*/> outs = new List<Formal/*!*/>();\n     Formal/*!*/ result = null;\n     Type/*!*/ returnType = new BoolType();\n     List<MaybeFreeExpression/*!*/> reqs = new List<MaybeFreeExpression/*!*/>();\n     List<MaybeFreeExpression/*!*/> ens = new List<MaybeFreeExpression/*!*/>();\n     List<FrameExpression/*!*/> reads = new List<FrameExpression/*!*/>();\n     List<Expression/*!*/> decreases;\n     List<FrameExpression/*!*/> mod;\n     Expression body = null;\n     bool isPredicate = false; bool isIndPredicate = false; bool isCoPredicate = false;\n     bool isFunctionMethod = false;\n     IToken bodyStart = Token.NoToken;\n     IToken bodyEnd = Token.NoToken;\n     IToken signatureEllipsis = null;\n     bool missingOpenParen;\n     bool isTwoState = false;\n     FixpointPredicate.KType kType = FixpointPredicate.KType.Unspecified;\n  .)\n  /* ----- function ----- */\n  [ \"twostate\"               (. isTwoState = true; .)\n  ]\n  ( \"function\"\n    [ \"method\"                 (. if (isTwoState) { SemErr(t, \"twostate functions are supported only as a ghosts, not as function methods\"); }\n                                  else { isFunctionMethod = true; }\n                               .)\n    ]\n    (. AllowedDeclModifiers allowed = AllowedDeclModifiers.AlreadyGhost | AllowedDeclModifiers.Static;\n       if (!isTwoState) { allowed |= AllowedDeclModifiers.Protected; }\n       string caption = \"Functions\";\n       if (isFunctionMethod) {\n         caption = \"Function methods\";\n       }\n       CheckDeclModifiers(dmod, caption, allowed);\n    .)\n    { Attribute<ref attrs> }\n    FuMe_Ident<out id>\n    (\n      [ GenericParameters<typeArgs, false> ]\n      Formals<true, isFunctionMethod, isTwoState, formals>\n      \":\"\n      (  IF(FollowedByColon())\n         \"(\"\n           (.\n              IToken resultId;\n              Type ty;\n              bool isGhost;\n              bool isOld;\n           .)\n           GIdentType<false, false, out resultId, out ty, out isGhost, out isOld>\n           (. Contract.Assert(!isGhost && !isOld);\n              result = new Formal(resultId, resultId.val, ty, false, false, false);\n           .)\n         \")\"\n         | Type<out returnType>\n      )\n    | \"...\"                    (. signatureEllipsis = t; .)\n    )\n\n  /* ----- predicate ----- */\n  | \"predicate\"                (. isPredicate = true; .)\n    [ \"method\"                 (. if (isTwoState) { SemErr(t, \"twostate predicates are supported only as a ghosts, not as predicate methods\"); }\n                                  else { isFunctionMethod = true; }\n                               .)\n    ]\n    (. AllowedDeclModifiers allowed = AllowedDeclModifiers.AlreadyGhost | AllowedDeclModifiers.Static;\n       if (!isTwoState) { allowed |= AllowedDeclModifiers.Protected; }\n       string caption = \"Predicates\";\n       if (isFunctionMethod) {\n         caption = \"Predicate methods\";\n       }\n       CheckDeclModifiers(dmod, caption, allowed);\n    .)\n    { Attribute<ref attrs> }\n    NoUSIdent<out id>\n    (\n      [ GenericParameters<typeArgs, false> ]                 (. missingOpenParen = true; .)\n      [ Formals<true, isFunctionMethod, isTwoState, formals> (. missingOpenParen = false; .)\n      ]                                                 (. if (missingOpenParen) { errors.Warning(t, \"with the new support of higher-order functions in Dafny, parentheses-less predicates are no longer supported; in the new syntax, parentheses are required for the declaration and uses of predicates, even if the predicate takes no additional arguments\"); } .)\n      [ \":\"                    (. SemErr(t, \"predicates do not have an explicitly declared return type; it is always bool\"); .)\n      ]\n    | \"...\"                    (. signatureEllipsis = t; .)\n    )\n\n  /* ----- inductive predicate ----- */\n  | (. Contract.Assert(!isTwoState);  // the IsFunctionDecl check checks that \"twostate\" is not followed by \"inductive\"\n    .)\n    \"inductive\" \"predicate\"    (. isIndPredicate = true; .)\n    (. CheckDeclModifiers(dmod, \"Inductive predicates\",\n         AllowedDeclModifiers.AlreadyGhost | AllowedDeclModifiers.Static | AllowedDeclModifiers.Protected);\n    .)\n    { Attribute<ref attrs> }\n    FuMe_Ident<out id>\n    (\n      [ GenericParameters<typeArgs, false> ]\n      [ KType<ref kType> ]\n      Formals<true, isFunctionMethod, false, formals>\n      [ \":\"                    (. SemErr(t, \"inductive predicates do not have an explicitly declared return type; it is always bool\"); .)\n      ]\n    | \"...\"                    (. signatureEllipsis = t; .)\n    )\n\n  /* ----- copredicate ----- */\n  | (. Contract.Assert(!isTwoState);  // the IsFunctionDecl check checks that \"twostate\" is not followed by \"copredicate\"\n    .)\n    \"copredicate\"              (. isCoPredicate = true; .)\n    (. CheckDeclModifiers(dmod, \"Copredicates\",\n         AllowedDeclModifiers.AlreadyGhost | AllowedDeclModifiers.Static | AllowedDeclModifiers.Protected);\n    .)\n    { Attribute<ref attrs> }\n    NoUSIdent<out id>\n    (\n      [ GenericParameters<typeArgs, false> ]\n      [ KType<ref kType> ]\n      Formals<true, isFunctionMethod, false, formals>\n      [ \":\"                    (. SemErr(t, \"copredicates do not have an explicitly declared return type; it is always bool\"); .)\n      ]\n    | \"...\"                    (. signatureEllipsis = t; .)\n    )\n\n  )\n\n  (. decreases = isIndPredicate || isCoPredicate ? null : new List<Expression/*!*/>(); .)\n  (. mod = null; .)\n  { FunctionSpec<reqs, reads, ens, decreases, mod> }\n  [ FunctionBody<out body, out bodyStart, out bodyEnd>\n  ]\n  (. if (!isWithinAbstractModule && ArmadaOptions.O.DisallowSoundnessCheating && body == null && ens.Count > 0 &&\n         !Attributes.Contains(attrs, \"axiom\") && !Attributes.Contains(attrs, \"imported\")) {\n        SemErr(t, \"a function with an ensures clause must have a body, unless given the :axiom attribute\");\n     }\n     IToken tok = id;\n     if (isTwoState && isPredicate) {\n        f = new TwoStatePredicate(tok, id.val, dmod.IsStatic, typeArgs, formals,\n                                  reqs, reads, ens, new Specification<Expression>(decreases, null), body, attrs, signatureEllipsis);\n     } else if (isTwoState) {\n        f = new TwoStateFunction(tok, id.val, dmod.IsStatic, typeArgs, formals, result, returnType,\n                                 reqs, reads, ens, new Specification<Expression>(decreases, null), body, attrs, signatureEllipsis);\n     } else if (isPredicate) {\n        f = new Predicate(tok, id.val, dmod.IsStatic, dmod.IsProtected, !isFunctionMethod, typeArgs, formals,\n                          reqs, reads, ens, new Specification<Expression>(decreases, null), body, Predicate.BodyOriginKind.OriginalOrInherited, attrs, signatureEllipsis);\n     } else if (isIndPredicate) {\n        f = new InductivePredicate(tok, id.val, dmod.IsStatic, dmod.IsProtected, kType, typeArgs, formals,\n                                   reqs, reads, ens, body, attrs, signatureEllipsis);\n     } else if (isCoPredicate) {\n        f = new CoPredicate(tok, id.val, dmod.IsStatic, dmod.IsProtected, kType, typeArgs, formals,\n                            reqs, reads, ens, body, attrs, signatureEllipsis);\n     } else {\n        f = new Function(tok, id.val, dmod.IsStatic, dmod.IsProtected, !isFunctionMethod, typeArgs, formals, result, returnType,\n                         reqs, reads, ens, new Specification<Expression>(decreases, null), body, attrs, signatureEllipsis);\n     }\n     f.BodyStartTok = bodyStart;\n     f.BodyEndTok = bodyEnd;\n     theBuiltIns.CreateArrowTypeDecl(formals.Count);\n     if (isIndPredicate || isCoPredicate) {\n       // also create an arrow type for the corresponding prefix predicate\n       theBuiltIns.CreateArrowTypeDecl(formals.Count + 1);\n     }\n  .)\n  .\nFunctionSpec<.List<MaybeFreeExpression/*!*/>/*!*/ reqs, List<FrameExpression/*!*/>/*!*/ reads, List<MaybeFreeExpression/*!*/>/*!*/ ens, List<Expression/*!*/> decreases, List<FrameExpression/*!*/> mod.>\n= (. Contract.Requires(cce.NonNullElements(reqs));\n     Contract.Requires(cce.NonNullElements(reads));\n     Contract.Requires(decreases == null || cce.NonNullElements(decreases));\n     Expression/*!*/ e;  FrameExpression/*!*/ fe;\n/* NOTE (Luke): I'm not certain about this one...\n\t\t Attributes ensAttrs = null; Attributes reqAttrs = null; .)\n  SYNC\n  ( \"requires\"\n\t  { IF(IsAttribute()) Attribute<ref reqAttrs> }\n\t\t  Expression<out e, false, false> OldSemi                (. reqs.Add(new MaybeFreeExpression(e, false, reqAttrs)); .)\n      */\n     Attributes ensAttrs = null; Attributes reqAttrs = null; .)\n  SYNC\n  ( \"requires\"\n    { Attribute<ref reqAttrs> }\n    Expression<out e, false, false> OldSemi                (. reqs.Add(new MaybeFreeExpression(e, false, reqAttrs)); .)\n  | \"reads\"\n    PossiblyWildFrameExpression<out fe, false>          (. reads.Add(fe); .)\n    { \",\" PossiblyWildFrameExpression<out fe, false>    (. reads.Add(fe); .)\n    }\n    OldSemi\n  | \"ensures\"\n      { Attribute<ref ensAttrs> }\n      Expression<out e, false, false> OldSemi                (. ens.Add(new MaybeFreeExpression(e, false, ensAttrs)); .)\n  | \"decreases\"                               (. if (decreases == null) {\n                                                   SemErr(t, \"'decreases' clauses are meaningless for copredicates, so they are not allowed\");\n                                                   decreases = new List<Expression/*!*/>();\n                                                 }\n                                              .)\n    DecreasesList<decreases, false, false> OldSemi\n  )\n  .\n\nPossiblyWildExpression<out Expression e, bool allowLambda>\n= (. Contract.Ensures(Contract.ValueAtReturn(out e)!=null);\n     e = dummyExpr; .)\n  /* A decreases clause on a loop asks that no termination check be performed.\n   * Use of this feature is sound only with respect to partial correctness.\n   */\n  ( IF(StarFollowedByCommaSemiOrOpenBrace())\n    \"*\"                        (. e = new WildcardExpr(t); .)\n  | Expression<out e, false, allowLambda>\n  )\n  .\nPossiblyWildFrameExpression<out FrameExpression fe, bool allowSemi>\n= (. Contract.Ensures(Contract.ValueAtReturn(out fe) != null); fe = dummyFrameExpr; .)\n  /* A reads clause can list a wildcard, which allows the enclosing function to\n   * read anything.  In many cases, and in particular in all cases where\n   * the function is defined recursively, this makes it next to impossible to make\n   * any use of the function.  Nevertheless, as an experimental feature, the\n   * language allows it (and it is sound).\n   */\n  ( IF(StarFollowedByCommaSemiOrOpenBrace())\n    \"*\"                        (. fe = new FrameExpression(t, new WildcardExpr(t), null); .)\n  | FrameExpression<out fe, allowSemi, false>\n  )\n  .\nFrameExpression<out FrameExpression fe, bool allowSemi, bool allowLambda>\n= (. Contract.Ensures(Contract.ValueAtReturn(out fe) != null);\n     Expression/*!*/ e;\n     IToken/*!*/ id;\n     string fieldName = null;  IToken feTok = null;\n     fe = dummyFrameExpr;\n  .)\n  ( Expression<out e, allowSemi, allowLambda>   (. feTok = e.tok; .)\n    [ \"`\" Ident<out id>        (. fieldName = id.val;  feTok = id; .)\n    ]                          (. fe = new FrameExpression(feTok, e, fieldName); .)\n  |\n    \"`\" Ident<out id>          (. fieldName = id.val; .)\n                               (. fe = new FrameExpression(id, new ImplicitThisExpr(id), fieldName); .)\n  )\n  .\nFunctionBody<out Expression/*!*/ e, out IToken bodyStart, out IToken bodyEnd>\n= (. Contract.Ensures(Contract.ValueAtReturn(out e) != null); e = dummyExpr; .)\n  \"{\"                         (. bodyStart = t; .)\n  Expression<out e, true, true>\n  \"}\"                         (. bodyEnd = t; .)\n  .\n/*------------------------------------------------------------------------*/\nBlockStmt<out BlockStmt/*!*/ block, out IToken bodyStart, out IToken bodyEnd>\n= (. Contract.Ensures(Contract.ValueAtReturn(out block) != null);\n     List<Statement/*!*/> body = new List<Statement/*!*/>();\n  .)\n  \"{\"                                  (. bodyStart = t; .)\n  { Stmt<body>\n  }\n  \"}\"                                  (. bodyEnd = t;\n                                          block = new BlockStmt(bodyStart, bodyEnd, body); .)\n  .\nDividedBlockStmt<out DividedBlockStmt body, out IToken bodyStart, out IToken bodyEnd>\n= (. Contract.Ensures(Contract.ValueAtReturn(out body) != null);\n     List<Statement> bodyInit = new List<Statement>();\n     IToken separatorTok = null;\n     List<Statement> bodyProper = new List<Statement>();\n  .)\n  \"{\"                                  (. bodyStart = t; .)\n  { Stmt<bodyInit> }\n  [ \"new\"                              (. separatorTok = t; .)\n    \";\"\n    { Stmt<bodyProper> }\n  ]\n  \"}\"                                  (. bodyEnd = t; .)\n  (. body = new DividedBlockStmt(bodyStart, bodyEnd, bodyInit, separatorTok, bodyProper); .)\n  .\n\nExplicitYieldBlockStmt<out Statement s>\n= (. IToken bodyStart;\n     IToken bodyEnd;\n     List<Statement/*!*/> body = new List<Statement>(); .)\n  (\"explicit_yield\" | \"atomic\") \"{\"            (. bodyStart = t; .)\n  { Stmt<body> }\n  \"}\"                             (. bodyEnd = t; s = new ExplicitYieldBlockStmt(bodyStart, bodyEnd, body);  .)\n  .\n\nStmt<.List<Statement/*!*/>/*!*/ ss.>\n= (. Statement/*!*/ s;\n  .)\n  OneStmt<out s>                                (. ss.Add(s); .)\n  .\nOneStmt<out Statement/*!*/ s>\n= (. Contract.Ensures(Contract.ValueAtReturn(out s) != null); IToken/*!*/ x;  IToken/*!*/ id;  string label = null;\n     s = dummyStmt;  /* to please the compiler */\n     BlockStmt bs;\n     IToken bodyStart, bodyEnd;\n     int breakCount;\n  .)\n  SYNC\n  ( BlockStmt<out bs, out bodyStart, out bodyEnd>  (. s = bs; .)\n  | AssertStmt<out s, false>\n  | AssumeStmt<out s>\n  | PrintStmt<out s>\n  | RevealStmt<out s>\n  | SomehowStmt<out s>\n  | FenceStmt<out s>\n  | GotoStmt<out s>\n  | CompareAndSwapStmt<out s>\n  | AtomicExchangeStmt<out s>\n  | DeallocStmt<out s>\n  | CreateThreadStmt<out s>\n  | UpdateStmt<out s>\n  | VarDeclStatement<out s>\n  | IfStmt<out s>\n  | WhileStmt<out s>\n  | MatchStmt<out s>\n  | ForallStmt<out s>\n  | CalcStmt<out s>\n  | ModifyStmt<out s>\n  | \"label\"\n    LabelIdent<out id> \":\"\n    OneStmt<out s>                     (. s.Labels = new LList<Label>(new Label(id, id.val), s.Labels); .)\n  | \"break\"                            (. x = t; breakCount = 1; label = null; .)\n    ( LabelIdent<out id>               (. label = id.val; .)\n    | { \"break\"                        (. breakCount++; .)\n      }\n    )\n    SYNC\n    \";\"                                (. s = label != null ? new BreakStmt(x, t, label) : new BreakStmt(x, t, breakCount); .)\n  | \"continue\"                         (. x = t; .)\n    SYNC\n    \";\"                                (. s = new ContinueStmt(x, t); .)\n  | ReturnStmt<out s>\n  | SkeletonStmt<out s>\n  | JoinStmt<out s>\n  | ExplicitYieldBlockStmt<out s>\n  )\n  .\n\nSkeletonStmt<out Statement s>\n= (. List<IToken> names = null;\n     List<Expression> exprs = null;\n     IToken tok, dotdotdot, whereTok;\n     Expression e; .)\n  \"...\"                                (. dotdotdot = t; .)\n  [\"where\"                             (. names = new List<IToken>(); exprs = new List<Expression>(); whereTok = t;.)\n     Ident<out tok>                    (. names.Add(tok); .)\n     {\",\" Ident<out tok>               (. names.Add(tok); .)\n     }\n     \":=\"\n     Expression<out e, false, true>          (. exprs.Add(e); .)\n     {\",\" Expression<out e, false, true>     (. exprs.Add(e); .)\n     }\n                                       (. if (exprs.Count != names.Count) {\n                                            SemErr(whereTok, exprs.Count < names.Count ? \"not enough expressions\" : \"too many expressions\");\n                                            names = null; exprs = null;\n                                          }\n                                       .)\n  ]\n  \";\"\n  (. s = new SkeletonStatement(dotdotdot, t, names, exprs); .)\n  .\nReturnStmt<out Statement/*!*/ s>\n= (.\n   IToken returnTok = null;\n   List<AssignmentRhs> rhss = null;\n   AssignmentRhs r;\n   bool isYield = false;\n   .)\n  ( \"return\"                         (. returnTok = t; .)\n  | \"yield\"                          (. returnTok = t; isYield = true; .)\n  )\n  [ Rhs<out r>                       (. rhss = new List<AssignmentRhs>(); rhss.Add(r); .)\n    { \",\" Rhs<out r>                 (. rhss.Add(r); .)\n    }\n  ]\n  \";\"                                (. if (isYield) {\n                                          s = new YieldStmt(returnTok, t, rhss);\n                                        } else {\n                                          s = new ReturnStmt(returnTok, t, rhss);\n                                        }\n                                     .)\n  .\nJoinStmt<out Statement/*!*/ s>\n= (. IToken beginTok; Expression e; .)\n  \"join\"                                  (. beginTok = t; .)\n  Expression<out e, false, false, false>  (. s = new JoinStmt(beginTok, t, e); .)\n  \";\"\n.\n\nUpdateStmt<out Statement/*!*/ s>\n= (. List<Expression> lhss = new List<Expression>();\n     List<AssignmentRhs> rhss = new List<AssignmentRhs>();\n     Expression e;\n     AssignmentRhs r;\n     IToken x = Token.NoToken;\n     IToken endTok = Token.NoToken;\n     Attributes attrs = null;\n     IToken suchThatAssume = null;\n     Expression suchThat = null;\n     bool bypassStoreBuffers = false;\n     Expression exceptionExpr = null;\n  .)\n( Lhs<out e>                       (. x = e.tok; .)\n  ( { Attribute<ref attrs> }\n    \";\"                            (. endTok = t; rhss.Add(new ExprRhs(e, attrs)); .)\n  |                                (. lhss.Add(e); .)\n    { \",\" Lhs<out e>               (. lhss.Add(e); .)\n    }\n    ( (  \":=\"                      (. x = t; .)\n       | \"::=\"                     (. x = t; bypassStoreBuffers = true; .)\n      )\n      Rhs<out r>                   (. rhss.Add(r); .)\n      { \",\" Rhs<out r>             (. rhss.Add(r); .)\n      }\n    | \":|\"                         (. x = t; .)\n      [ IF(la.kind == _assume)     /* an Expression can also begin with an \"assume\", so this says to resolve it to pick up any \"assume\" here */\n        \"assume\"                   (. suchThatAssume = t; .)\n      ]\n      Expression<out suchThat, false, true>\n    | \":-\"                         (. x = t; .)\n      Expression<out exceptionExpr, false, false>\n    )\n    \";\"                            (. endTok = t; .)\n  | \":\"                            (. SemErr(t, \"invalid statement (did you forget the 'label' keyword?)\"); .)\n  )\n| \":-\"                             (. x = t; .)\n   Expression<out exceptionExpr, false, false>\n   \";\"                             (. endTok = t; .)\n)\n  (. if (suchThat != null) {\n       s = new AssignSuchThatStmt(x, endTok, lhss, suchThat, suchThatAssume, null);\n     } else if (exceptionExpr != null) {\n       if (lhss.Count > 1) {\n         SemErr(x, \"':-' assignments can only have one LHS\");\n         lhss = new List<Expression>() { lhss[0] };\n       }\n       s = new AssignOrReturnStmt(x, endTok, lhss, exceptionExpr);\n     } else {\n       if (lhss.Count == 0 && rhss.Count == 0) {\n         s = new BlockStmt(x, endTok, new List<Statement>()); // error, give empty statement\n       } else {\n         s = new UpdateStmt(x, endTok, lhss, rhss, false, bypassStoreBuffers);\n       }\n     }\n  .)\n  .\nRhs<out AssignmentRhs r>\n= (. Contract.Ensures(Contract.ValueAtReturn<AssignmentRhs>(out r) != null);\n     IToken/*!*/ x, newToken;  Expression/*!*/ e, e2, e3;\n     IToken id;\n     Type ty = new InferredTypeProxy();\n     List<Expression> ee = null;\n     List<Expression> args = null;\n     Expression arrayElementInit = null;\n     List<Expression> display = null;\n     r = dummyRhs;  // to please compiler\n     Attributes attrs = null;\n  .)\n  ( \"new\"                              (. newToken = t; .)\n    ( NewArray<out ee, out arrayElementInit, out display>  // \"ty\" is set to InferredTypeProxy above\n    | TypeAndToken<out x, out ty, false>\n      [ NewArray<out ee, out arrayElementInit, out display>\n      |                                (. x = null; args = new List<Expression/*!*/>(); .)\n        \"(\"\n          [ Expressions<args> ]\n        \")\"\n      ]\n    )\n    (. if (ee != null) {\n         if (display != null) {\n           r = new TypeRhs(newToken, ty, ee[0], display);\n         } else {\n           r = new TypeRhs(newToken, ty, ee, arrayElementInit);\n         }\n       } else if (args != null) {\n         r = new TypeRhs(newToken, ty, args, false);\n       } else {\n         r = new TypeRhs(newToken, ty);\n       }\n    .)\n  | IF(StarFollowedByCommaSemiOrOpenBrace())\n    \"*\"                                (. r = new HavocRhs(t); .)\n  | Expression<out e, false, true>     (. r = new ExprRhs(e); .)\n  | \"create_thread\"                                 (. x = t; args = new List<Expression>(); .)\n    NoUSIdent<out id> \"(\" [ Expressions<args> ] \")\" (. r = new CreateThreadRhs(x, id, args); .)\n  | \"malloc\" (. x = t; id = null; .)\n    \"(\" Type<out ty> \")\" (. r = new MallocRhs(x, ty); .)\n  | \"calloc\" (. x = t; .)\n    \"(\" Type<out ty> \",\" Expression<out e, false, false> \")\" (. r = new CallocRhs(x, ty, e); .)\n  | \"compare_and_swap\"                    (. x = t; .)\n    \"(\" Expression<out e, false, false>\n    \",\" Expression<out e2, false, false>\n    \",\" Expression<out e3, false, false>\n    \")\"                                   (. r = new CompareAndSwapRhs(x, e, e2, e3); .)\n  | \"atomic_exchange\"                     (. x = t; .)\n    \"(\" Expression<out e, false, false>\n    \",\" Expression<out e2, false, false>\n    \")\"                                   (. r = new AtomicExchangeRhs(x, e, e2); .)\n  )\n  { Attribute<ref attrs> }             (. r.Attributes = attrs; .)\n  .\nNewArray<. out List<Expression> ee, out Expression arrayElementInit, out List<Expression> display .>\n= (. ee = new List<Expression>();\n     arrayElementInit = null;\n     display = null;\n     IToken x;\n  .)\n  \"[\"                                (. x = t; .)\n  ( \"]\"                              /* no size is given; this is allowed as long as an initialization display is given */\n    \"[\"                              (. display = new List<Expression>(); .)\n    [ Expressions<display> ]\n    \"]\"                              (. // we fill in the size\n                                        ee.Add(new LiteralExpr(x, display.Count));\n                                     .)\n  | Expressions<ee>\n    \"]\"                              (. // make sure an array class with this dimensionality exists\n                                        var tmp = theBuiltIns.ArrayType(ee.Count, new IntType(), true);\n                                     .)\n    [ \"(\" Expression<out arrayElementInit, true, true>\n      \")\"\n    | \"[\"                            (. if (ee.Count > 1) {\n                                          SemErr(t, \"An initializing element display is allowed only for 1-dimensional arrays\");\n                                        }\n                                        display = new List<Expression>();\n                                     .)\n      [ Expressions<display> ]\n      \"]\"\n    ]\n  )\n  (. if (ee.Count == 0) {\n       // an error occurred while parsing, but we still want to make sure to return a nonempty \"ee\"\n       ee.Add(new LiteralExpr(x, 0));\n     }\n  .)\n  .\nVarDeclStatement<.out Statement/*!*/ s.>\n= (. IToken x = null, assignTok = null;  bool isGhost = false; bool isNoAddr = false;\n     LocalVariable d;\n     AssignmentRhs r;\n     List<LocalVariable> lhss = new List<LocalVariable>();\n     List<AssignmentRhs> rhss = new List<AssignmentRhs>();\n     IToken suchThatAssume = null;\n     Expression suchThat = null;\n     Expression exceptionExpr = null;\n     Attributes attrs = null;\n     bool bypassStoreBuffers = false;\n     IToken endTok;\n     s = dummyStmt;\n  .)\n  [ \"ghost\"                                 (. isGhost = true;  x = t; .)\n  ]\n  [ \"noaddr\"                                (. isNoAddr = true; if (x == null) { x = t; } .)\n  ]\n  \"var\"                                     (. if (x == null) { x = t; } .)\n  ( IF(!IsLetStmt())\n    { Attribute<ref attrs> }\n    LocalIdentTypeOptional<out d, isGhost, isNoAddr>    (. lhss.Add(d); d.Attributes = attrs; attrs = null; .)\n    { \",\"\n      { Attribute<ref attrs> }\n      LocalIdentTypeOptional<out d, isGhost, isNoAddr>  (. lhss.Add(d); d.Attributes = attrs; attrs = null; .)\n    }\n    [ (\":=\"                           (. assignTok = t; .)\n       | \"::=\"                        (. assignTok = t; bypassStoreBuffers = true; .)\n      )\n      Rhs<out r>                     (. rhss.Add(r); .)\n      { \",\" Rhs<out r>               (. rhss.Add(r); .)\n      }\n    | { Attribute<ref attrs> }\n      \":|\"                           (. assignTok = t; .)\n      [ IF(la.kind == _assume)       /* an Expression can also begin with an \"assume\", so this says to resolve it to pick up any \"assume\" here */\n        \"assume\"                     (. suchThatAssume = t; .)\n      ]\n      Expression<out suchThat, false, true>\n    | \":-\"                           (. assignTok = t; .)\n      Expression<out exceptionExpr, false, false>\n    ]\n    SYNC \";\"                         (. endTok = t; .)\n    (. ConcreteUpdateStatement update;\n       var lhsExprs = new List<Expression>();\n       foreach (var lhs in lhss) {\n         lhsExprs.Add(new IdentifierExpr(lhs.Tok, lhs.Name));\n       }\n       if (suchThat != null) {\n         update = new AssignSuchThatStmt(assignTok, endTok, lhsExprs, suchThat, suchThatAssume, attrs);\n       } else if (exceptionExpr != null) {\n           Contract.Assert(lhss.Count >= 1);\n           if (lhss.Count != 1) {\n             SemErr(assignTok, \"':-' assignments can only have one LHS\");\n             lhsExprs = new List<Expression>() { lhsExprs[0] };\n           }\n           update = new AssignOrReturnStmt(assignTok, endTok, lhsExprs, exceptionExpr);\n       } else if (rhss.Count == 0) {\n         update = null;\n       } else {\n         var ies = new List<Expression>();\n         foreach (var lhs in lhss) {\n           ies.Add(new AutoGhostIdentifierExpr(lhs.Tok, lhs.Name));\n         }\n         update = new UpdateStmt(assignTok, endTok, ies, rhss);\n       }\n       s = new VarDeclStmt(x, endTok, lhss, update, bypassStoreBuffers);\n    .)\n  | (. CasePattern<LocalVariable> pat;\n       Expression e = dummyExpr;\n       IToken id = t;\n    .)\n    CasePatternLocal<out pat, isGhost>\n    ( \":=\"\n    | { Attribute<ref attrs> }\n      \":|\"                          (.  SemErr(pat.tok, \"LHS of assign-such-that expression must be variables, not general patterns\"); .)\n    )\n    Expression<out e, false, true>\n\n    \";\"\n    (. s = new LetStmt(e.tok, e.tok, pat, e); .)\n  )\n  .\nIfStmt<out Statement/*!*/ ifStmt>\n= (. Contract.Ensures(Contract.ValueAtReturn(out ifStmt) != null); IToken/*!*/ x;\n     Expression guard = null;  IToken guardEllipsis = null;  bool isExistentialGuard = false;\n     BlockStmt/*!*/ thn;\n     BlockStmt/*!*/ bs;\n     Statement/*!*/ s;\n     Statement els = null;\n     IToken bodyStart, bodyEnd, endTok;\n     List<GuardedAlternative> alternatives;\n     ifStmt = dummyIfStmt;  // to please the compiler\n     bool usesOptionalBraces;\n  .)\n  \"if\"                       (. x = t; .)\n  (\n    IF(IsAlternative())\n    AlternativeBlock<true, out alternatives, out usesOptionalBraces, out endTok>\n    (. ifStmt = new AlternativeStmt(x, endTok, alternatives, usesOptionalBraces); .)\n  |\n    ( IF(IsExistentialGuard())\n      ExistentialGuard<out guard, true>  (. isExistentialGuard = true; .)\n    | Guard<out guard>\n    | \"...\"                              (. guardEllipsis = t; .)\n    )\n    BlockStmt<out thn, out bodyStart, out bodyEnd>    (. endTok = thn.EndTok; .)\n    [ \"else\"\n      ( IfStmt<out s>                                 (. els = s; endTok = s.EndTok; .)\n      | BlockStmt<out bs, out bodyStart, out bodyEnd> (. els = bs; endTok = bs.EndTok; .)\n      )\n    ]\n    (. if (guardEllipsis != null) {\n         ifStmt = new SkeletonStatement(new IfStmt(x, endTok, isExistentialGuard, guard, thn, els), guardEllipsis, null);\n       } else {\n         ifStmt = new IfStmt(x, endTok, isExistentialGuard, guard, thn, els);\n       }\n    .)\n  )\n  .\nAlternativeBlock<.bool allowExistentialGuards, out List<GuardedAlternative> alternatives, out bool usesOptionalBraces, out IToken endTok.>\n= (. alternatives = new List<GuardedAlternative>();\n     endTok = null;\n     usesOptionalBraces = false;\n     GuardedAlternative alt;\n  .)\n  ( \"{\"    (. usesOptionalBraces = true; .)\n    {\n      AlternativeBlockCase<allowExistentialGuards, out alt>  (. alternatives.Add(alt); .)\n    }\n    \"}\"\n  | /* Note, an alternative-less while is not parsed here; it is a body-less while (not an alternative while).\n       Also, an alternative-less if is not allowed.\n       These decisions save a Coco warning.\n    */\n    AlternativeBlockCase<allowExistentialGuards, out alt>  (. alternatives.Add(alt); .)\n    { IF(la.kind == _case)\n      AlternativeBlockCase<allowExistentialGuards, out alt>  (. alternatives.Add(alt); .)\n    }\n  )\n  (. endTok = t; .)\n  .\nAlternativeBlockCase<.bool allowExistentialGuards, out GuardedAlternative alt.>\n= (. IToken x;\n     Expression e; bool isExistentialGuard;\n     List<Statement> body;\n  .)\n  \"case\"                             (. x = t; isExistentialGuard = false; e = dummyExpr; .)\n  ( IF(allowExistentialGuards && IsExistentialGuard())\n    ExistentialGuard<out e, false >  (. isExistentialGuard = true; .)  // NB: don't allow lambda here\n  | Expression<out e, true, false> // NB: don't allow lambda here\n  )\n  \"=>\"\n  (. body = new List<Statement>(); .)\n  SYNC  /* this SYNC and the one inside the loop below are used to avoid problems with the IsNotEndOfCase test. The SYNC will\n          * skip until the next symbol that can legally occur here, which is either the beginning of a Stmt or whatever is allowed\n          * to follow the CaseStatement.\n          */\n  { IF(IsNotEndOfCase()) /* This is a little sketchy. It would be nicer to be able to write IF(la is start-symbol of Stmt), but Coco doesn't allow that */\n    Stmt<body>\n    SYNC  /* see comment about SYNC above */\n  }\n  (. alt = new GuardedAlternative(x, isExistentialGuard, e, body); .)\n  .\nWhileStmt<out Statement stmt>\n= (. Contract.Ensures(Contract.ValueAtReturn(out stmt) != null); IToken x;\n     Expression guard = null;  IToken guardEllipsis = null;\n\n     List<MaybeFreeExpression> invariants = new List<MaybeFreeExpression>();\n     List<Expression> ens = new List<Expression>();\n     List<Expression> decreases = new List<Expression>();\n     Attributes decAttrs = null;\n     Attributes modAttrs = null;\n     List<FrameExpression> mod = null;\n\n     BlockStmt body = null;  IToken bodyEllipsis = null;\n     IToken bodyStart = null, bodyEnd = null, endTok = Token.NoToken;\n     List<GuardedAlternative> alternatives;\n     stmt = dummyStmt;  // to please the compiler\n     bool isDirtyLoop = true;\n     bool usesOptionalBraces;\n  .)\n  \"while\"                    (. x = t; .)\n  (\n    IF(IsLoopSpec() || IsAlternative())\n    { LoopSpec<invariants, ens, decreases, ref mod, ref decAttrs, ref modAttrs> }\n    AlternativeBlock<false, out alternatives, out usesOptionalBraces, out endTok>\n    (. stmt = new AlternativeLoopStmt(x, endTok, invariants, new Specification<Expression>(decreases, decAttrs), new Specification<FrameExpression>(mod, modAttrs), alternatives, usesOptionalBraces); .)\n  |\n    ( Guard<out guard>           (. Contract.Assume(guard == null || cce.Owner.None(guard)); .)\n    | \"...\"                      (. guardEllipsis = t; .)\n    )\n    { LoopSpec<invariants, ens, decreases, ref mod, ref decAttrs, ref modAttrs> }\n    ( IF(la.kind == _lbrace)      /* if there's an open brace, claim it as the beginning of the loop body (as opposed to a BlockStmt following the loop) */\n      BlockStmt<out body, out bodyStart, out bodyEnd>  (. endTok = body.EndTok; isDirtyLoop = false; .)\n    | IF(la.kind == _ellipsis)    /* if there's an ellipsis, claim it as standing for the loop body (as opposed to a \"...;\" statement following the loop) */\n      \"...\"                      (. bodyEllipsis = t; endTok = t; isDirtyLoop = false; .)\n    | /* go body-less */\n    )\n    (.\n      if (guardEllipsis != null || bodyEllipsis != null) {\n        if (mod != null) {\n          SemErr(mod[0].E.tok, \"'modifies' clauses are not allowed on refining loops\");\n        }\n        if (body == null && !isDirtyLoop) {\n          body = new BlockStmt(x, endTok, new List<Statement>());\n        }\n        stmt = new WhileStmt(x, endTok, guard, invariants, ens, new Specification<Expression>(decreases, decAttrs), new Specification<FrameExpression>(null, null), body);\n        stmt = new SkeletonStatement(stmt, guardEllipsis, bodyEllipsis);\n      } else {\n        // The following statement protects against crashes in case of parsing errors\n        if (body == null && !isDirtyLoop) {\n          body = new BlockStmt(x, endTok, new List<Statement>());\n        }\n        stmt = new WhileStmt(x, endTok, guard, invariants, ens, new Specification<Expression>(decreases, decAttrs), new Specification<FrameExpression>(mod, modAttrs), body);\n      }\n    .)\n  )\n  .\nLoopSpec<.List<MaybeFreeExpression> invariants, List<Expression> ens, List<Expression> decreases, ref List<FrameExpression> mod, ref Attributes decAttrs, ref Attributes modAttrs.>\n= (. Expression e; FrameExpression fe;\n     bool isFree = false; Attributes attrs = null;\n  .)\n  ( SYNC\n    [ \"free\"                                      (. isFree = true; errors.Deprecated(t, \"the 'free' keyword is soon to be deprecated\"); .)\n    ]\n    \"invariant\"\n    { Attribute<ref attrs> }\n    Expression<out e, false, true>                (. invariants.Add(new MaybeFreeExpression(e, isFree, attrs)); .)\n    OldSemi\n  | SYNC \"ensures\"\n    Expression<out e, false, true>                (. ens.Add(e); .)\n    OldSemi\n  | SYNC \"decreases\"\n    { Attribute<ref decAttrs> }\n    DecreasesList<decreases, true, true>\n    OldSemi\n  | SYNC \"modifies\"                               (. mod = mod ?? new List<FrameExpression>(); .)\n    { Attribute<ref modAttrs> }\n    FrameExpression<out fe, false, true>          (. mod.Add(fe); .)\n    { \",\" FrameExpression<out fe, false, true>    (. mod.Add(fe); .)\n    }\n    OldSemi\n  )\n  .\nDecreasesList<.List<Expression> decreases, bool allowWildcard, bool allowLambda.>\n= (. Expression e; .)\n  PossiblyWildExpression<out e, allowLambda> (. if (!allowWildcard && e is WildcardExpr) {\n                                                  SemErr(e.tok, \"'decreases *' is allowed only on loops and tail-recursive methods\");\n                                                } else {\n                                                  decreases.Add(e);\n                                                }\n                                             .)\n  { \",\" PossiblyWildExpression<out e, allowLambda>\n                                             (. if (!allowWildcard && e is WildcardExpr) {\n                                                  SemErr(e.tok, \"'decreases *' is allowed only on loops and tail-recursive methods\");\n                                                } else {\n                                                  decreases.Add(e);\n                                                }\n                                             .)\n  }\n  .\nGuard<out Expression e>   /* null represents demonic-choice */\n= (. Expression/*!*/ ee;  e = null; .)\n  ( IF(StarFollowedByCommaSemiOrOpenBrace())\n    \"*\"                             (. e = null; .)\n  | IF(IsParenStar())  \"(\" \"*\" \")\"  (. e = null; .)\n  | Expression<out ee, true, true>        (. e = ee; .)\n  )\n  .\nExistentialGuard<out Expression e, bool allowLambda>\n= (. var bvars = new List<BoundVar>();\n     BoundVar bv;  IToken x;\n     Attributes attrs = null;\n     Expression body;\n  .)\n  IdentTypeOptional<out bv>                    (. bvars.Add(bv); x = bv.tok; .)\n  { \",\"\n    IdentTypeOptional<out bv>                  (. bvars.Add(bv); .)\n  }\n  { Attribute<ref attrs> }\n  \":|\"\n  Expression<out body, true, allowLambda>\n  (. e = new ExistsExpr(x, bvars, null, body, attrs); .)\n  .\nMatchStmt<out Statement/*!*/ s>\n= (. Contract.Ensures(Contract.ValueAtReturn(out s) != null);\n     IToken x;  Expression/*!*/ e;  MatchCaseStmt/*!*/ c;\n     List<MatchCaseStmt/*!*/> cases = new List<MatchCaseStmt/*!*/>();\n     bool usesOptionalBraces = false;\n  .)\n  \"match\"                     (. x = t; .)\n  Expression<out e, true, true>\n  ( IF(la.kind == _lbrace)  /* always favor brace-enclosed match body to a case-less match */\n    \"{\" (. usesOptionalBraces = true; .)\n        { CaseStatement<out c> (. cases.Add(c); .) }\n    \"}\"\n  |     { IF(la.kind == _case)  /* let each \"case\" bind to the closest preceding \"match\" */\n          CaseStatement<out c> (. cases.Add(c); .)\n        }\n  )\n  (. s = new MatchStmt(x, t, e, cases, usesOptionalBraces); .)\n  .\nCaseStatement<out MatchCaseStmt/*!*/ c>\n= (. Contract.Ensures(Contract.ValueAtReturn(out c) != null);\n     IToken/*!*/ x, id;\n     var arguments = new List<CasePattern<BoundVar>>();\n     CasePattern<BoundVar>/*!*/ pat;\n     var body = new List<Statement/*!*/>();\n     string/*!*/ name = \"\";\n  .)\n  \"case\"                      (. x = t; .)\n  ( Ident<out id>             (. name = id.val; .)\n    [ \"(\"\n       [ CasePattern<out pat>        (. arguments.Add(pat); .)\n         { \",\" CasePattern<out pat>  (. arguments.Add(pat); .)\n         }\n       ]\n    \")\" ]\n  | \"(\"\n      CasePattern<out pat>        (. arguments.Add(pat); .)\n      { \",\" CasePattern<out pat>  (. arguments.Add(pat); .)\n      }\n    \")\"\n  )\n  \"=>\"\n    SYNC  /* this SYNC and the one inside the loop below are used to avoid problems with the IsNotEndOfCase test. The SYNC will\n           * skip until the next symbol that can legally occur here, which is either the beginning of a Stmt or whatever is allowed\n           * to follow the CaseStatement.\n           */\n    { IF(IsNotEndOfCase()) /* This is a little sketchy. It would be nicer to be able to write IF(la is start-symbol of Stmt), but Coco doesn't allow that */\n      Stmt<body>\n      SYNC  /* see comment about SYNC above */\n    }\n  (. c = new MatchCaseStmt(x, name, arguments, body); .)\n  .\n/*------------------------------------------------------------------------*/\nAssertStmt<out Statement/*!*/ s, bool inExprContext>\n= (. Contract.Ensures(Contract.ValueAtReturn(out s) != null); IToken/*!*/ x;\n     Expression e = dummyExpr; Attributes attrs = null;\n     IToken dotdotdot = null;\n     BlockStmt proof = null;\n     IToken proofStart, proofEnd;\n     IToken lbl = null;\n  .)\n  \"assert\"                                     (. x = t; .)\n  { Attribute<ref attrs> }\n  ( [ IF(IsLabel(!inExprContext))\n      LabelIdent<out lbl> \":\"\n    ]\n    Expression<out e, false, true>\n    ( \"by\"\n      BlockStmt<out proof, out proofStart, out proofEnd>\n    | \";\"\n    )\n  | \"...\"                                      (. dotdotdot = t; .)\n    \";\"\n  )\n  (. if (dotdotdot != null) {\n       s = new SkeletonStatement(new AssertStmt(x, t, new LiteralExpr(x, true), null, null, attrs), dotdotdot, null);\n     } else {\n       s = new AssertStmt(x, t, e, proof, lbl == null ? null : new AssertLabel(lbl, lbl.val), attrs);\n     }\n  .)\n  .\nAssumeStmt<out Statement/*!*/ s>\n= (. Contract.Ensures(Contract.ValueAtReturn(out s) != null); IToken/*!*/ x;\n     Expression e = dummyExpr; Attributes attrs = null;\n     IToken dotdotdot = null;\n  .)\n  (\"assume\" | \"wait_until\")                    (. x = t; .)\n  { Attribute<ref attrs> }\n  ( Expression<out e, false, true>\n  | \"...\"                                      (. dotdotdot = t; .)\n  )\n  \";\"\n  (. if (dotdotdot != null) {\n       s = new SkeletonStatement(new AssumeStmt(x, t, new LiteralExpr(x, true), attrs), dotdotdot, null);\n     } else {\n       s = new AssumeStmt(x, t, e, attrs);\n     }\n  .)\n  .\nPrintStmt<out Statement s>\n= (. Contract.Ensures(Contract.ValueAtReturn(out s) != null);\n     IToken x;  Expression e;\n     var args = new List<Expression>();\n  .)\n  \"print\"                                      (. x = t; .)\n  Expression<out e, false, true>               (. args.Add(e); .)\n  { \",\" Expression<out e, false, true>         (. args.Add(e); .)\n  }\n  \";\"                                          (. s = new PrintStmt(x, t, args); .)\n  .\n\nRevealStmt<out Statement s>\n= (. Contract.Ensures(Contract.ValueAtReturn(out s) != null);\n     IToken x; Expression e; var es = new List<Expression>();\n  .)\n  \"reveal\"                                      (. x = t; .)\n  Expression<out e, false, true>                (. es.Add(e); .)\n  { \",\" Expression<out e, false, true>          (. es.Add(e); .)\n  }\n  \";\"                                           (. s = new RevealStmt(x, t, es); .)\n  .\n\nSomehowStmt<out Statement/*!*/ s>\n= (. Contract.Ensures(Contract.ValueAtReturn(out s) != null); IToken/*!*/ x;\n     List<Expression/*!*/> undefinedUnless = new List<Expression/*!*/>();\n     List<Expression/*!*/> mod = new List<Expression/*!*/>();\n     List<Expression/*!*/> ens = new List<Expression/*!*/>();\n     Attributes modAttrs = null;\n     Expression e = null;\n  .)\n  \"somehow\" (. x = t; .)\n  {\n      ( \"undefined_unless\"\n                   Expression<out e, false, false>           (. undefinedUnless.Add(e); .)\n                   { \",\" Expression<out e, false, false>     (. undefinedUnless.Add(e); .)\n                   }\n      | \"modifies\" { Attribute<ref modAttrs> }\n                   Expression<out e, false, false>           (. mod.Add(e); .)\n                   { \",\" Expression<out e, false, false>     (. mod.Add(e); .)\n                   }\n      | \"ensures\"  Expression<out e, false, false>           (. ens.Add(e); .)\n      )\n  }\n  \";\" (. s = new SomehowStmt(x, t, undefinedUnless, new Specification<Expression>(mod, modAttrs), ens); .)\n  .\n\nFenceStmt<out Statement/*!*/ s>\n= (. Contract.Ensures(Contract.ValueAtReturn(out s) != null); IToken/*!*/ x;\n  .)\n  \"fence\" (. x = t; .)\n  \";\" (. s = new FenceStmt(x, t); .)\n  .\n\nGotoStmt<out Statement/*!*/ s>\n= (. Contract.Ensures(Contract.ValueAtReturn(out s) != null); IToken/*!*/ x, id;\n  .)\n  \"goto\" (. x = t; .)\n  LabelIdent<out id>\n  \";\" (. s = new GotoStmt(x, t, id.val); .)\n  .\n\nCompareAndSwapStmt<out Statement/*!*/ s>\n= (. Contract.Ensures(Contract.ValueAtReturn(out s) != null);\n     IToken/*!*/ x;\n     Expression e, e2, e3;\n  .)\n  \"compare_and_swap\"                      (. x = t; .)\n  \"(\" Expression<out e, false, false>\n  \",\" Expression<out e2, false, false>\n  \",\" Expression<out e3, false, false>\n  \")\" \";\" (. s = new UpdateStmt(x, t, new List<Expression>(), new List<AssignmentRhs> { new CompareAndSwapRhs(x, e, e2, e3) }); .)\n  .\n\nAtomicExchangeStmt<out Statement/*!*/ s>\n= (. Contract.Ensures(Contract.ValueAtReturn(out s) != null);\n     IToken/*!*/ x;\n     Expression e, e2;\n  .)\n  \"atomic_exchange\"                      (. x = t; .)\n  \"(\" Expression<out e, false, false>\n  \",\" Expression<out e2, false, false>\n  \")\" \";\" (. s = new UpdateStmt(x, t, new List<Expression>(), new List<AssignmentRhs> { new AtomicExchangeRhs(x, e, e2) }); .)\n  .\n\nDeallocStmt<out Statement/*!*/ s>\n= (. Contract.Ensures(Contract.ValueAtReturn(out s) != null);\n     IToken/*!*/ x;\n     Expression e;\n  .)\n\n  \"dealloc\" (. x = t; .)\n  Expression<out e, false, false>\n  \";\" (. s = new DeallocStmt(x, t, e); .)\n  .\n\nCreateThreadStmt<out Statement/*!*/ s>\n= (. Contract.Ensures(Contract.ValueAtReturn(out s) != null);\n     IToken/*!*/ x;\n     IToken/*!*/ id;\n     List<Expression/*!*/> args = new List<Expression/*!*/>();\n  .)\n  \"create_thread\" (. x = t; .)\n  NoUSIdent<out id> \"(\" [ Expressions<args> ] \")\"\n  \";\" (. s = new UpdateStmt(x, t, new List<Expression>(), new List<AssignmentRhs> { new CreateThreadRhs(x, id, args) }); .)\n  .\n\n\nForallStmt<out Statement/*!*/ s>\n= (. Contract.Ensures(Contract.ValueAtReturn(out s) != null);\n     IToken/*!*/ x = Token.NoToken;\n     List<BoundVar> bvars = null;\n     Attributes attrs = null;\n     Expression range = null;\n     var ens = new List<MaybeFreeExpression/*!*/>();\n     bool isFree;\n     Expression/*!*/ e;\n     BlockStmt block = null;\n     IToken bodyStart, bodyEnd;\n     IToken tok = Token.NoToken;\n  .)\n  ( \"forall\"                                  (. x = t; tok = x; .)\n  | \"parallel\"                                (. x = t;\n                                                 errors.Deprecated(t, \"the 'parallel' keyword has been deprecated; the comprehension statement now uses the keyword 'forall' (and the parentheses around the bound variables are now optional)\");\n                                              .)\n  )\n\n  ( IF(la.kind == _openparen)  /* disambiguation needed, because of the possibility of a body-less forall statement */\n    \"(\" [ QuantifierDomain<out bvars, out attrs, out range> ] \")\"\n  |     [ IF(la.kind == _ident)  /* disambiguation needed, because of the possibility of a body-less forall statement */\n          QuantifierDomain<out bvars, out attrs, out range>\n        ]\n  )\n  (. if (bvars == null) { bvars = new List<BoundVar>(); }\n     if (range == null) { range = new LiteralExpr(x, true); }\n  .)\n\n  {                                         (. isFree = false; .)\n    [ \"free\"                                (. isFree = true;\n                                               errors.Deprecated(t, \"the 'free' keyword is soon to be deprecated\");\n                                            .)\n    ]\n    \"ensures\" Expression<out e, false, true>  (. ens.Add(new MaybeFreeExpression(e, isFree)); .)\n    OldSemi                                   (. tok = t; .)\n  }\n  [ IF(la.kind == _lbrace)  /* if the input continues like a block statement, take it to be the body of the forall statement; a body-less forall statement must continue in some other way */\n    BlockStmt<out block, out bodyStart, out bodyEnd>\n  ]\n  (. if (ArmadaOptions.O.DisallowSoundnessCheating && block == null && 0 < ens.Count) {\n        SemErr(t, \"a forall statement with an ensures clause must have a body\");\n     }\n\n     if (block != null) {\n        tok = block.EndTok;\n     }\n     s = new ForallStmt(x, tok, bvars, attrs, range, ens, block);\n  .)\n  .\n\nModifyStmt<out Statement s>\n= (. IToken tok;  IToken endTok = Token.NoToken;\n     Attributes attrs = null;\n     FrameExpression fe;  var mod = new List<FrameExpression>();\n     BlockStmt body = null;  IToken bodyStart;\n     IToken ellipsisToken = null;\n  .)\n  \"modify\"           (. tok = t; .)\n  { Attribute<ref attrs> }\n  /* Note, there is an ambiguity here, because a curly brace may look like a FrameExpression and\n   * may also look like a BlockStmt.  We're happy to parse the former, because if the user intended\n   * the latter, then an explicit FrameExpression of {} could be given.\n   */\n  ( FrameExpression<out fe, false, true>       (. mod.Add(fe); .)\n    { \",\" FrameExpression<out fe, false, true> (. mod.Add(fe); .)\n    }\n  | \"...\"                               (. ellipsisToken = t; .)\n  )\n  ( BlockStmt<out body, out bodyStart, out endTok>\n  | SYNC \";\"         (. endTok = t; .)\n  )\n  (. s = new ModifyStmt(tok, endTok, mod, attrs, body);\n     if (ellipsisToken != null) {\n       s = new SkeletonStatement(s, ellipsisToken, null);\n     }\n  .)\n  .\n\nCalcStmt<out Statement s>\n= (. Contract.Ensures(Contract.ValueAtReturn(out s) != null);\n     IToken x;\n     Attributes attrs = null;\n     CalcStmt.CalcOp op, userSuppliedOp = null, resOp = Microsoft.Armada.CalcStmt.DefaultOp;\n     var lines = new List<Expression>();\n     var hints = new List<BlockStmt>();\n     CalcStmt.CalcOp stepOp;\n     var stepOps = new List<CalcStmt.CalcOp>();\n     Expression e;\n     IToken opTok;\n     IToken danglingOperator = null;\n  .)\n  \"calc\"                                                  (. x = t; .)\n  { Attribute<ref attrs> }\n  [ CalcOp<out opTok, out userSuppliedOp>                 (. if (userSuppliedOp.ResultOp(userSuppliedOp) == null) { // guard against non-transitive calcOp (like !=)\n                                                               SemErr(opTok, \"the main operator of a calculation must be transitive\");\n                                                             } else {\n                                                               resOp = userSuppliedOp;\n                                                             }\n                                                          .)\n  ]\n  \"{\"\n  { Expression<out e, false, true>                        (. lines.Add(e); stepOp = null; danglingOperator = null; .)\n    \";\"\n    [ CalcOp<out opTok, out op>                           (. var maybeOp = resOp.ResultOp(op);\n                                                             if (maybeOp == null) {\n                                                               SemErr(opTok, \"this operator cannot continue this calculation\");\n                                                             } else {\n                                                               stepOp = op;\n                                                               resOp = maybeOp;\n                                                               danglingOperator = opTok;\n                                                             }\n                                                          .)\n    ]                                                     (. stepOps.Add(stepOp); .)\n\n    /* now for the hint, which we build up as a possibly empty sequence of statements placed into one BlockStmt */\n    (. var subhints = new List<Statement>();\n       IToken hintStart = la;  IToken hintEnd = hintStart;\n       IToken t0, t1;\n       BlockStmt subBlock; Statement subCalc;\n    .)\n    { IF(la.kind == _lbrace || la.kind == _calc)  /* Grab as a hint if possible, not a next line in the calculation whose expression begins with an open brace\n                                                   * or StmtExpr containing a calc.  A user has to rewrite such a line to be enclosed in parentheses.\n                                                   */\n      ( BlockStmt<out subBlock, out t0, out t1>   (. hintEnd = subBlock.EndTok; subhints.Add(subBlock); .)\n      | CalcStmt<out subCalc>                     (. hintEnd = subCalc.EndTok; subhints.Add(subCalc); .)\n      )\n    }\n    (. var h = new BlockStmt(hintStart, hintEnd, subhints); // if the hint is empty, hintStart is the first token of the next line, but it doesn't matter because the block statement is just used as a container\n       hints.Add(h);\n       if (h.Body.Count != 0) { danglingOperator = null; }\n    .)\n  }\n  \"}\"\n  (.\n    if (danglingOperator != null) {\n      SemErr(danglingOperator, \"a calculation cannot end with an operator\");\n    }\n    if (lines.Count > 0) {\n      // Repeat the last line to create a dummy line for the dangling hint\n      lines.Add(lines[lines.Count - 1]);\n    }\n    s = new CalcStmt(x, t, userSuppliedOp, lines, hints, stepOps, attrs);\n  .)\n  .\nCalcOp<out IToken x, out CalcStmt.CalcOp/*!*/ op>\n= (. var binOp = BinaryExpr.Opcode.Eq; // Returns Eq if parsing fails because it is compatible with any other operator\n     Expression k = null;\n     x = null;\n  .)\n  ( \"==\"           (. x = t;  binOp = BinaryExpr.Opcode.Eq; .)\n    [ \"#\" \"[\" Expression<out k, true, true> \"]\" ]\n  | \"<\"            (. x = t;  binOp = BinaryExpr.Opcode.Lt; .)\n  | \">\"            (. x = t;  binOp = BinaryExpr.Opcode.Gt; .)\n  | \"<=\"           (. x = t;  binOp = BinaryExpr.Opcode.Le; .)\n  | \">=\"           (. x = t;  binOp = BinaryExpr.Opcode.Ge; .)\n  | \"!=\"           (. x = t;  binOp = BinaryExpr.Opcode.Neq; .)\n  | '\\u2260'       (. x = t;  binOp = BinaryExpr.Opcode.Neq; .)\n  | '\\u2264'       (. x = t;  binOp = BinaryExpr.Opcode.Le; .)\n  | '\\u2265'       (. x = t;  binOp = BinaryExpr.Opcode.Ge; .)\n  | EquivOp        (. x = t;  binOp = BinaryExpr.Opcode.Iff; .)\n  | ImpliesOp      (. x = t;  binOp = BinaryExpr.Opcode.Imp; .)\n  | ExpliesOp      (. x = t;  binOp = BinaryExpr.Opcode.Exp; .)\n  )\n  (.\n    if (k == null) {\n      op = new Microsoft.Armada.CalcStmt.BinaryCalcOp(binOp);\n    } else {\n      op = new Microsoft.Armada.CalcStmt.TernaryCalcOp(k);\n    }\n  .)\n  .\n\n/*------------------------------------------------------------------------*/\n/* Note. In order to avoid LL(1) warnings for expressions that \"parse as far as possible\", it is\n * necessary to use Coco/R's IF construct.  That means there are two ways to check for some of\n * these operators, both in Is...() methods (defined above) and as grammar non-terminals (defined\n * here).  These pairs of definitions must be changed together.\n */\nEquivOp = \"<==>\" | '\\u21d4'.\nImpliesOp = \"==>\" | '\\u21d2'.\nExpliesOp = \"<==\" | '\\u21d0'.\nAndOp = \"&&\" | '\\u2227'.\nOrOp = \"||\" | '\\u2228'.\n\nNegOp = \"!\" | '\\u00ac'.\nForall = \"forall\" | '\\u2200'.\nExists = \"exists\" | '\\u2203'.\nQSep = \"::\" | '\\u2022'.\n\n/* The \"allowSemi\" argument says whether or not the expression\n * to be parsed is allowed to have the form S;E where S is a call to a lemma.\n * \"allowSemi\" should be passed in as \"false\" whenever the expression to\n * be parsed sits in a context that itself is terminated by a semi-colon.\n *\n * The \"allowLambda\" says whether or not the expression to be parsed is\n * allowed to be a lambda expression.  More precisely, an identifier or\n * parenthesized-enclosed comma-delimited list of identifiers is allowed to\n * continue as a lambda expression (that is, continue with a \"reads\", \"requires\",\n * or \"=>\") only if \"allowLambda\" is true.  This affects function/method/iterator\n * specifications, if/while statements with guarded alternatives, and expressions\n * in the specification of a lambda expression itself.\n *\n * The \"allowBitwiseOps\" says whether or not to include or bypass bitwise operators\n * at the top level of this expression. It is passed in as \"false\" only inside\n * cardinality brackets, that is, \"|expr|\".\n */\nExpression<out Expression e, bool allowSemi, bool allowLambda, bool allowBitwiseOps = true>\n= (. Expression e0; IToken endTok; .)\n  EquivExpression<out e, allowSemi, allowLambda, allowBitwiseOps>\n  [ IF(SemiFollowsCall(allowSemi, e))\n    /* here we parse the \";E\" that is part of a \"LemmaCall;E\" expression (other \"S;E\" expressions are parsed elsewhere) */\n    \";\"                       (. endTok = t; .)\n    Expression<out e0, allowSemi, allowLambda>\n    (. e = new StmtExpr(e.tok,\n             new UpdateStmt(e.tok, endTok, new List<Expression>(), new List<AssignmentRhs>() { new ExprRhs(e, null) }),\n             e0);\n    .)\n  ]\n  .\n/*------------------------------------------------------------------------*/\nEquivExpression<out Expression e0, bool allowSemi, bool allowLambda, bool allowBitwiseOps>\n= (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x;  Expression/*!*/ e1; .)\n  ImpliesExpliesExpression<out e0, allowSemi, allowLambda, allowBitwiseOps>\n  { IF(IsEquivOp())  /* read an EquivExpression as far as possible */\n    EquivOp                                                   (. x = t; .)\n    ImpliesExpliesExpression<out e1, allowSemi, allowLambda, allowBitwiseOps>  (. e0 = new BinaryExpr(x, BinaryExpr.Opcode.Iff, e0, e1); .)\n  }\n  .\n/*------------------------------------------------------------------------*/\nImpliesExpliesExpression<out Expression e0, bool allowSemi, bool allowLambda, bool allowBitwiseOps>\n= (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x;  Expression/*!*/ e1; .)\n  LogicalExpression<out e0, allowSemi, allowLambda, allowBitwiseOps>\n  [ IF(IsImpliesOp() || IsExpliesOp())  /* read an ImpliesExpliesExpression as far as possible */\n    /* Note, the asymmetry in the parsing of implies and explies expressions stems from the fact that\n     * implies is right associative whereas reverse implication is left associative\n     */\n    ( ImpliesOp                                               (. x = t; .)\n      ImpliesExpression<out e1, allowSemi, allowLambda, allowBitwiseOps>       (. e0 = new BinaryExpr(x, BinaryExpr.Opcode.Imp, e0, e1); .)\n    | ExpliesOp                                               (. x = t; .)\n      LogicalExpression<out e1, allowSemi, allowLambda, allowBitwiseOps>       (. // The order of operands is reversed so that it can be turned into implication during resolution\n                                                                 e0 = new BinaryExpr(x, BinaryExpr.Opcode.Exp, e1, e0); .)\n      { IF(IsExpliesOp())  /* read a reverse implication as far as possible */\n        ExpliesOp                                             (. x = t; .)\n        LogicalExpression<out e1, allowSemi, allowLambda, allowBitwiseOps>     (. //The order of operands is reversed so that it can be turned into implication during resolution\n                                                                 e0 = new BinaryExpr(x, BinaryExpr.Opcode.Exp, e1, e0);\n                                                              .)\n      }\n    )\n  ]\n  .\nImpliesExpression<out Expression e0, bool allowSemi, bool allowLambda, bool allowBitwiseOps>\n= (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x;  Expression/*!*/ e1; .)\n  LogicalExpression<out e0, allowSemi, allowLambda, allowBitwiseOps>\n  [ IF(IsImpliesOp())  /* read an ImpliesExpression as far as possible */\n    ImpliesOp                                               (. x = t; .)\n    ImpliesExpression<out e1, allowSemi, allowLambda, allowBitwiseOps>       (. e0 = new BinaryExpr(x, BinaryExpr.Opcode.Imp, e0, e1); .)\n  ]\n  .\n/*------------------------------------------------------------------------*/\nLogicalExpression<out Expression e0, bool allowSemi, bool allowLambda, bool allowBitwiseOps>\n= (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x;  Expression/*!*/ e1;\n     Expression first;\n     e0 = dummyExpr; /* mute the warning */\n  .)\n  ( AndOp                                                       (. x = t; .)\n    RelationalExpression<out e0, allowSemi, allowLambda, allowBitwiseOps>        (. first = e0; .)\n    { IF(IsAndOp())  /* read a conjunction as far as possible */\n      AndOp                                                     (. x = t; .)\n      RelationalExpression<out e1, allowSemi, allowLambda, allowBitwiseOps>      (. e0 = new BinaryExpr(x, BinaryExpr.Opcode.And, e0, e1); .)\n    }\n    (. if (e0 == first) {\n         // There was only one conjunct. To make sure that the type checker still checks it to\n         // be a boolean, we conjoin \"true\" to its left.\n         e0 = new BinaryExpr(x, BinaryExpr.Opcode.And, new LiteralExpr(x, true), e0);\n       }\n    .)\n  | OrOp                                                        (. x = t; .)\n    RelationalExpression<out e0, allowSemi, allowLambda, allowBitwiseOps>        (. first = e0; .)\n    { IF(IsOrOp())  /* read a disjunction as far as possible */\n      OrOp                                                      (. x = t; .)\n      RelationalExpression<out e1, allowSemi, allowLambda, allowBitwiseOps>      (. e0 = new BinaryExpr(x, BinaryExpr.Opcode.Or, e0, e1); .)\n    }\n    (. if (e0 == first) {\n         // There was only one disjunct. To make sure that the type checker still checks it to\n         // be a boolean, we disjoin [sic] \"false\" to its left.\n         e0 = new BinaryExpr(x, BinaryExpr.Opcode.Or, new LiteralExpr(x, false), e0);\n       }\n    .)\n  | RelationalExpression<out e0, allowSemi, allowLambda, allowBitwiseOps>\n    [ IF(IsAndOp() || IsOrOp())  /* read a LogicalExpression as far as possible */\n      ( AndOp                                                   (. x = t; .)\n        RelationalExpression<out e1, allowSemi, allowLambda, allowBitwiseOps>    (. e0 = new BinaryExpr(x, BinaryExpr.Opcode.And, e0, e1); .)\n        { IF(IsAndOp())  /* read a conjunction as far as possible */\n          AndOp                                                 (. x = t; .)\n          RelationalExpression<out e1, allowSemi, allowLambda, allowBitwiseOps>  (. e0 = new BinaryExpr(x, BinaryExpr.Opcode.And, e0, e1); .)\n        }\n      | OrOp                                                    (. x = t; .)\n        RelationalExpression<out e1, allowSemi, allowLambda, allowBitwiseOps>    (. e0 = new BinaryExpr(x, BinaryExpr.Opcode.Or, e0, e1); .)\n        { IF(IsOrOp())  /* read a disjunction as far as possible */\n          OrOp                                                  (. x = t; .)\n          RelationalExpression<out e1, allowSemi, allowLambda, allowBitwiseOps>  (. e0 = new BinaryExpr(x, BinaryExpr.Opcode.Or, e0, e1); .)\n        }\n      )\n    ]\n  )\n  .\n/*------------------------------------------------------------------------*/\nRelationalExpression<out Expression e, bool allowSemi, bool allowLambda, bool allowBitwiseOps>\n= (. Contract.Ensures(Contract.ValueAtReturn(out e) != null);\n     IToken x = null;  Expression e0, e1 = null;  BinaryExpr.Opcode op;\n     List<Expression> chain = null;\n     List<BinaryExpr.Opcode> ops = null;\n     List<IToken> opLocs = null;\n     List<Expression/*?*/> prefixLimits = null;\n     Expression k;\n     int kind = 0;  // 0 (\"uncommitted\") indicates chain of ==, possibly with one !=\n                    // 1 (\"ascending\")   indicates chain of ==, <, <=, possibly with one !=\n                    // 2 (\"descending\")  indicates chain of ==, >, >=, possibly with one !=\n                    // 3 (\"illegal\")     indicates illegal chain\n                    // 4 (\"disjoint\")    indicates chain of disjoint set operators\n     bool hasSeenNeq = false;\n  .)\n  ShiftTerm<out e0, allowSemi, allowLambda, allowBitwiseOps>\n                                   (. e = e0; .)\n  [ IF(IsRelOp())  /* read a RelationalExpression as far as possible */\n    RelOp<out x, out op, out k>\n    ShiftTerm<out e1, allowSemi, allowLambda, allowBitwiseOps>\n                                   (. if (k == null) {\n                                        e = new BinaryExpr(x, op, e0, e1);\n                                      } else {\n                                        Contract.Assert(op == BinaryExpr.Opcode.Eq || op == BinaryExpr.Opcode.Neq);\n                                        e = new TernaryExpr(x, op == BinaryExpr.Opcode.Eq ? TernaryExpr.Opcode.PrefixEqOp : TernaryExpr.Opcode.PrefixNeqOp, k, e0, e1);\n                                      }\n                                   .)\n    { IF(IsRelOp())  /* read a RelationalExpression as far as possible */\n                                   (. if (chain == null) {\n                                        chain = new List<Expression>();\n                                        ops = new List<BinaryExpr.Opcode>();\n                                        opLocs = new List<IToken>();\n                                        prefixLimits = new List<Expression>();\n                                        chain.Add(e0); ops.Add(op); opLocs.Add(x); prefixLimits.Add(k); chain.Add(e1);\n                                        switch (op) {\n                                          case BinaryExpr.Opcode.Eq:\n                                            kind = 0;  break;\n                                          case BinaryExpr.Opcode.Neq:\n                                            kind = 0;  hasSeenNeq = true;  break;\n                                          case BinaryExpr.Opcode.Lt:\n                                          case BinaryExpr.Opcode.Le:\n                                            kind = 1;  break;\n                                          case BinaryExpr.Opcode.Gt:\n                                          case BinaryExpr.Opcode.Ge:\n                                            kind = 2;  break;\n                                          case BinaryExpr.Opcode.Disjoint:\n                                            kind = 4;  break;\n                                          default:\n                                            kind = 3;  break;\n                                        }\n                                      }\n                                   .)\n      RelOp<out x, out op, out k>  (. switch (op) {\n                                        case BinaryExpr.Opcode.Eq:\n                                          if (kind != 0 && kind != 1 && kind != 2) { SemErr(x, \"chaining not allowed from the previous operator\"); kind = 3; }\n                                          break;\n                                        case BinaryExpr.Opcode.Neq:\n                                          if (hasSeenNeq) { SemErr(x, \"a chain cannot have more than one != operator\"); kind = 3; }\n                                          else if (kind != 0 && kind != 1 && kind != 2) { SemErr(x, \"this operator cannot continue this chain\"); kind = 3; }\n                                          hasSeenNeq = true;  break;\n                                        case BinaryExpr.Opcode.Lt:\n                                        case BinaryExpr.Opcode.Le:\n                                          if (kind == 0) { kind = 1; }\n                                          else if (kind != 1) { SemErr(x, \"this operator chain cannot continue with an ascending operator\"); kind = 3; }\n                                          break;\n                                        case BinaryExpr.Opcode.Gt:\n                                        case BinaryExpr.Opcode.Ge:\n                                          if (kind == 0) { kind = 2; }\n                                          else if (kind != 2) { SemErr(x, \"this operator chain cannot continue with a descending operator\"); kind = 3; }\n                                          break;\n                                        case BinaryExpr.Opcode.Disjoint:\n                                          if (kind != 4) { SemErr(x, \"can only chain disjoint (!!) with itself.\"); kind = 3; }\n                                          break;\n                                        default:\n                                          SemErr(x, \"this operator cannot be part of a chain\");\n                                          kind = 3;  break;\n                                      }\n                                   .)\n      ShiftTerm<out e1, allowSemi, allowLambda, allowBitwiseOps>\n                                   (. ops.Add(op); opLocs.Add(x); prefixLimits.Add(k); chain.Add(e1);\n                                   .)\n    }\n  ]\n  (. if (chain != null && kind != 3) {\n       e = new ChainingExpression(opLocs[0], chain, ops, opLocs, prefixLimits);\n     }\n  .)\n  .\nRelOp<out IToken/*!*/ x, out BinaryExpr.Opcode op, out Expression k>\n= (. Contract.Ensures(Contract.ValueAtReturn(out x) != null);\n     x = Token.NoToken;  op = BinaryExpr.Opcode.Add/*(dummy)*/;\n     IToken y;\n     k = null;\n  .)\n  ( \"==\"           (. x = t;  op = BinaryExpr.Opcode.Eq; .)\n    [ \"#\" \"[\" Expression<out k, true, true> \"]\" ]\n  | \"<\"            (. x = t;  op = BinaryExpr.Opcode.Lt; .)\n  | \">\"            (. x = t;  op = BinaryExpr.Opcode.Gt; .)\n  | \"<=\"           (. x = t;  op = BinaryExpr.Opcode.Le; .)\n  | \">=\"           (. x = t;  op = BinaryExpr.Opcode.Ge; .)\n  | \"!=\"           (. x = t;  op = BinaryExpr.Opcode.Neq; .)\n    [ \"#\" \"[\" Expression<out k, true, true> \"]\" ]\n  | \"in\"           (. x = t;  op = BinaryExpr.Opcode.In; .)\n  | notIn          (. x = t;  op = BinaryExpr.Opcode.NotIn; .)\n  | /* The next operator is \"!!\", but we have to scan it as two \"!\", since the scanner is greedy\n       so if \"!!\" is a valid token, we won't be able to scan it as two \"!\" when needed: */\n    \"!\"            (. x = t;  y = Token.NoToken; .)\n    [ IF(la.val == \"!\")\n      \"!\"          (. y = t; .)\n    ]              (. if (y == Token.NoToken) {\n                        SemErr(x, \"invalid RelOp\");\n                      } else if (y.pos != x.pos + 1) {\n                        SemErr(x, \"invalid RelOp (perhaps you intended \\\"!!\\\" with no intervening whitespace?)\");\n                      } else {\n                        x.val = \"!!\";\n                        op = BinaryExpr.Opcode.Disjoint;\n                      }\n                   .)\n  | '\\u2260'       (. x = t;  op = BinaryExpr.Opcode.Neq; .)\n  | '\\u2264'       (. x = t;  op = BinaryExpr.Opcode.Le; .)\n  | '\\u2265'       (. x = t;  op = BinaryExpr.Opcode.Ge; .)\n  )\n  .\n/*------------------------------------------------------------------------*/\nShiftTerm<out Expression e0, bool allowSemi, bool allowLambda, bool allowBitwiseOps>\n= (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null);\n     IToken x = Token.NoToken;  Expression e1;  BinaryExpr.Opcode op = BinaryExpr.Opcode.LeftShift/*(dummy)*/;\n  .)\n  Term<out e0, allowSemi, allowLambda, allowBitwiseOps>\n  { IF(IsShiftOp())  /* read a Term as far as possible */\n    ( \"<\"            (. x = t;  op = BinaryExpr.Opcode.LeftShift; .)\n      \"<\"            (. x.val = \"<<\";  Contract.Assert(t.pos == x.pos + 1); .)\n    | \">\"            (. x = t;  op = BinaryExpr.Opcode.RightShift; .)\n      \">\"            (. x.val = \"<<\";  Contract.Assert(t.pos == x.pos + 1); .)\n    )\n    Term<out e1, allowSemi, allowLambda, allowBitwiseOps> (. e0 = new BinaryExpr(x, op, e0, e1); .)\n  }\n  .\n/*------------------------------------------------------------------------*/\nTerm<out Expression e0, bool allowSemi, bool allowLambda, bool allowBitwiseOps>\n= (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x;  Expression/*!*/ e1;  BinaryExpr.Opcode op; .)\n  Factor<out e0, allowSemi, allowLambda, allowBitwiseOps>\n  { IF(IsAddOp())  /* read a Term as far as possible */\n    AddOp<out x, out op>\n    Factor<out e1, allowSemi, allowLambda, allowBitwiseOps> (. e0 = new BinaryExpr(x, op, e0, e1); .)\n  }\n  .\nAddOp<out IToken x, out BinaryExpr.Opcode op>\n= (. Contract.Ensures(Contract.ValueAtReturn(out x) != null); x = Token.NoToken;  op=BinaryExpr.Opcode.Add/*(dummy)*/; .)\n  ( \"+\"            (. x = t;  op = BinaryExpr.Opcode.Add; .)\n  | \"-\"            (. x = t;  op = BinaryExpr.Opcode.Sub; .)\n  )\n  .\n/*------------------------------------------------------------------------*/\nFactor<out Expression e0, bool allowSemi, bool allowLambda, bool allowBitwiseOps>\n= (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x;  Expression/*!*/ e1;  BinaryExpr.Opcode op; .)\n  BitvectorFactor<out e0, allowSemi, allowLambda, allowBitwiseOps>\n  { IF(IsMulOp())  /* read a Factor as far as possible */\n    MulOp<out x, out op>\n    BitvectorFactor<out e1, allowSemi, allowLambda, allowBitwiseOps> (. e0 = new BinaryExpr(x, op, e0, e1); .)\n  }\n  .\nMulOp<out IToken x, out BinaryExpr.Opcode op>\n= (. Contract.Ensures(Contract.ValueAtReturn(out x) != null); x = Token.NoToken;  op = BinaryExpr.Opcode.Add/*(dummy)*/; .)\n  ( \"*\"            (. x = t;  op = BinaryExpr.Opcode.Mul; .)\n  | \"/\"            (. x = t;  op = BinaryExpr.Opcode.Div; .)\n  | \"%\"            (. x = t;  op = BinaryExpr.Opcode.Mod; .)\n  )\n  .\n/*------------------------------------------------------------------------*/\nBitvectorFactor<out Expression e0, bool allowSemi, bool allowLambda, bool allowBitwiseOps>\n= (. Contract.Ensures(Contract.ValueAtReturn(out e0) != null); IToken/*!*/ x;  Expression/*!*/ e1;  BinaryExpr.Opcode op; .)\n  AsExpression<out e0, allowSemi, allowLambda, allowBitwiseOps>\n  [ IF(allowBitwiseOps && IsBitwiseOp())  /* read a BitvectorFactor as far as possible, but not in the context inside a |.| size expression */\n    ( (. op = BinaryExpr.Opcode.BitwiseAnd; .)\n      \"&\"                                                             (. x = t; .)\n      AsExpression<out e1, allowSemi, allowLambda, allowBitwiseOps>   (. e0 = new BinaryExpr(x, op, e0, e1); .)\n      { IF(IsBitwiseAndOp())\n        \"&\"                                                           (. x = t; .)\n        AsExpression<out e1, allowSemi, allowLambda, allowBitwiseOps> (. e0 = new BinaryExpr(x, op, e0, e1); .)\n      }\n    | (. op = BinaryExpr.Opcode.BitwiseOr; .)\n      \"|\"                                                             (. x = t; .)\n      AsExpression<out e1, allowSemi, allowLambda, allowBitwiseOps>   (. e0 = new BinaryExpr(x, op, e0, e1); .)\n      { IF(IsBitwiseOrOp())\n        \"|\"                                                           (. x = t; .)\n        AsExpression<out e1, allowSemi, allowLambda, allowBitwiseOps> (. e0 = new BinaryExpr(x, op, e0, e1); .)\n      }\n    | (. op = BinaryExpr.Opcode.BitwiseXor; .)\n      \"^\"                                                             (. x = t; .)\n      AsExpression<out e1, allowSemi, allowLambda, allowBitwiseOps>   (. e0 = new BinaryExpr(x, op, e0, e1); .)\n      { IF(IsBitwiseXorOp())\n        \"^\"                                                           (. x = t; .)\n        AsExpression<out e1, allowSemi, allowLambda, allowBitwiseOps> (. e0 = new BinaryExpr(x, op, e0, e1); .)\n      }\n    )\n  ]\n  .\n/*------------------------------------------------------------------------*/\nAsExpression<out Expression e, bool allowSemi, bool allowLambda, bool allowBitwiseOps>\n= (. IToken tok; IToken x; Type toType; .)\n  UnaryExpression<out e, allowSemi, allowLambda, allowBitwiseOps>\n  { IF(IsAs())\n    \"as\"                                     (. tok = t; .)\n     TypeAndToken<out x, out toType, true>   (. e = new ConversionExpr(tok, e, toType); .)\n  }\n  .\nUnaryExpression<out Expression e, bool allowSemi, bool allowLambda, bool allowBitwiseOps>\n= (. Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x;  e = dummyExpr; .)\n  ( \"-\"                                             (. x = t; .)\n    UnaryExpression<out e, allowSemi, allowLambda, allowBitwiseOps>  (. e = new NegationExpression(x, e); .)\n  | NegOp                                           (. x = t; .)\n    UnaryExpression<out e, allowSemi, allowLambda, allowBitwiseOps>  (. e = new UnaryOpExpr(x, UnaryOpExpr.Opcode.Not, e); .)\n  | \"&\"                                             (. x = t; .)\n    UnaryExpression<out e, allowSemi, allowLambda, allowBitwiseOps>  (. e = new UnaryOpExpr(x, UnaryOpExpr.Opcode.AddressOf, e); .)\n  | \"*\"                                             (. x = t; .)\n    UnaryExpression<out e, allowSemi, allowLambda, allowBitwiseOps>  (. e = new UnaryOpExpr(x, UnaryOpExpr.Opcode.Dereference, e); .)\n  | IF(IsMapDisplay())  /* this alternative must be checked before going into EndlessExpression, where there is another \"map\" */\n    \"map\"                                           (. x = t; .)\n    MapDisplayExpr<x, true, out e>\n    { IF(IsSuffix()) Suffix<ref e> }\n  | IF(IsIMapDisplay())  /* this alternative must be checked before going into EndlessExpression, where there is another \"imap\" */\n    \"imap\"                                          (. x = t; .)\n    MapDisplayExpr<x, false, out e>\n    { IF(IsSuffix()) Suffix<ref e> }\n  | IF(IsISetDisplay())  /* this alternative must be checked before going into EndlessExpression, where there is another \"iset\" */\n    \"iset\"                                          (. x = t; .)\n    ISetDisplayExpr<x, false, out e>\n    { IF(IsSuffix()) Suffix<ref e> }\n  | IF(IsLambda(allowLambda))\n    LambdaExpression<out e, allowSemi, allowBitwiseOps>  /* this is an endless expression */\n  | EndlessExpression<out e, allowSemi, allowLambda, allowBitwiseOps>\n  | NameSegment<out e>\n    { IF(IsSuffix()) Suffix<ref e> }\n  | DisplayExpr<out e>\n    { IF(IsSuffix()) Suffix<ref e> }\n  | MultiSetExpr<out e>\n    { IF(IsSuffix()) Suffix<ref e> }\n  | SeqConstructionExpr<out e>\n    { IF(IsSuffix()) Suffix<ref e> }\n  | ConstAtomExpression<out e, allowSemi, allowLambda>\n    { IF(IsSuffix()) Suffix<ref e> }\n  )\n  .\nLhs<out Expression e>\n= (. e = dummyExpr;  // the assignment is to please the compiler, the dummy value to satisfy contracts in the event of a parse error\n     IToken x; Expression ee;\n  .)\n  ( NameSegment<out e>\n    { Suffix<ref e> }\n  | \"*\" (. x = t; .)\n    Expression<out ee, false, false> (. e = new UnaryOpExpr(x, UnaryOpExpr.Opcode.Dereference, ee); .)\n  | ConstAtomExpression<out e, false, false>\n    Suffix<ref e>\n    { Suffix<ref e> }\n  )\n  .\n\n/* A ConstAtomExpression is never an l-value, and does not start with an identifier. */\nConstAtomExpression<out Expression e, bool allowSemi, bool allowLambda>\n= (. Contract.Ensures(Contract.ValueAtReturn(out e) != null);\n     IToken/*!*/ x;  BigInteger n;   BaseTypes.BigDec d; Expression e2;\n     e = dummyExpr; e2 = null; Type toType = null;\n  .)\n  ( \"false\"                                    (. e = new LiteralExpr(t, false); .)\n  | \"true\"                                     (. e = new LiteralExpr(t, true); .)\n  | \"null\"                                     (. e = new LiteralExpr(t); .)\n  | Nat<out n>                                 (. e = new LiteralExpr(t, n); .)\n  | Dec<out d>                                 (. e = new LiteralExpr(t, d); .)\n  | charToken                                  (. e = new CharLiteralExpr(t, t.val.Substring(1, t.val.Length - 2)); .)\n  | stringToken                                (. bool isVerbatimString;\n                                                  string s = Util.RemoveParsedStringQuotes(t.val, out isVerbatimString);\n                                                  e = new StringLiteralExpr(t, s, isVerbatimString);\n                                               .)\n  | \"this\"                                     (. e = new ThisExpr(t); .)\n  | \"$me\"                                      (. e = new MeExpr(t); .)\n  | \"$sb_empty\"                                (. e = new StoreBufferEmptyExpr(t); .)\n  | \"$state\"                                   (. e = new TotalStateExpr(t); .)\n  | \"fresh\"                                    (. x = t; .)\n    \"(\" Expression<out e, true, true> \")\"      (. e = new UnaryOpExpr(x, UnaryOpExpr.Opcode.Fresh, e); .)\n  | \"allocated\"                                (. x = t; .)\n    \"(\" Expression<out e, true, true> \")\"      (. e = new UnaryOpExpr(x, UnaryOpExpr.Opcode.Allocated, e); .)\n  | \"allocated_array\"                          (. x = t; .)\n    \"(\" Expression<out e, true, true> \")\"      (. e = new UnaryOpExpr(x, UnaryOpExpr.Opcode.AllocatedArray, e); .)\n  | \"if_undefined\"                             (. x = t; .)\n    \"(\" Expression<out e, true, true> \",\"\n        Expression<out e2, true, true> \")\"     (. e = new IfUndefinedExpr(x, e, e2); .)\n  | \"global_view\"                              (. x = t; .)\n    \"(\" Expression<out e, true, true> \")\"      (. e = new UnaryOpExpr(x, UnaryOpExpr.Opcode.GlobalView, e); .)\n  | \"unchanged\"                                (. x = t; FrameExpression fe; var mod = new List<FrameExpression>(); IToken oldAt = null; .)\n    [ \"@\" LabelIdent<out oldAt> ]\n    \"(\"\n      FrameExpression<out fe, false, false>         (. mod.Add(fe); .)\n      { \",\" FrameExpression<out fe, false, false>   (. mod.Add(fe); .)\n      }\n    \")\"                                        (. e = new UnchangedExpr(x, mod, oldAt?.val); .)\n  | \"old\"                                      (. x = t; IToken oldAt = null; .)\n    [ \"@\" LabelIdent<out oldAt> ]\n    \"(\" Expression<out e, true, true> \")\"      (. e = new OldExpr(x, e, oldAt?.val); .)\n  | \"|\"                                        (. x = t; .)\n      Expression<out e, true, true, false>     (. e = new UnaryOpExpr(x, UnaryOpExpr.Opcode.Cardinality, e); .)\n    \"|\"\n  | ( \"int\"                                    (. x = t; toType = new IntType(); .)\n    | \"real\"                                   (. x = t; toType = new RealType(); .)\n    )                                          (. errors.Deprecated(t, string.Format(\"the syntax \\\"{0}(expr)\\\" for type conversions has been deprecated; the new syntax is \\\"expr as {0}\\\"\", x.val)); .)\n    \"(\" Expression<out e, true, true> \")\"      (. e = new ConversionExpr(x, e, toType); .)\n  | ParensExpression<out e, allowSemi, allowLambda>\n  )\n  .\n\nLambdaArrow = \"=>\".\n\nLambdaExpression<out Expression e, bool allowSemi, bool allowBitwiseOps>\n= (. IToken x = Token.NoToken;\n     IToken id;  BoundVar bv;\n     var bvs = new List<BoundVar>();\n     FrameExpression fe;  Expression ee;\n     var reads = new List<FrameExpression>();\n     Expression req = null;\n     Expression body = null;\n  .)\n  ( WildIdent<out id, true>                  (. x = t; bvs.Add(new BoundVar(id, id.val, new InferredTypeProxy())); .)\n  | \"(\"                                      (. x = t; .)\n      [\n        IdentTypeOptional<out bv>            (. bvs.Add(bv); .)\n        { \",\" IdentTypeOptional<out bv>      (. bvs.Add(bv); .)\n        }\n      ]\n    \")\"\n  )\n  { \"reads\"\n    PossiblyWildFrameExpression<out fe, true>         (. reads.Add(fe); .)\n    { \",\"\n      PossiblyWildFrameExpression<out fe, true>       (. reads.Add(fe); .)\n    }\n  | \"requires\" Expression<out ee, true, false>        (. req = req == null ? ee : new BinaryExpr(req.tok, BinaryExpr.Opcode.And, req, ee); .)\n  }\n  LambdaArrow\n  Expression<out body, allowSemi, true, allowBitwiseOps>\n  (. e = new LambdaExpr(x, bvs, req, reads, body);\n     theBuiltIns.CreateArrowTypeDecl(bvs.Count);\n  .)\n  .\nParensExpression<out Expression e, bool allowSemi, bool allowLambda>\n= (. IToken x;\n     var args = new List<Expression>();\n  .)\n  \"(\"                                        (. x = t; .)\n  [ Expressions<args> ]\n  \")\"\n  (. if (args.Count == 1) {\n       e = new ParensExpression(x, args[0]);\n     } else {\n       // make sure the corresponding tuple type exists\n       var tmp = theBuiltIns.TupleType(x, args.Count, true);\n       e = new DatatypeValue(x, BuiltIns.TupleTypeName(args.Count), BuiltIns.TupleTypeCtorNamePrefix + args.Count, args);\n     }\n  .)\n  .\nISetDisplayExpr<IToken/*!*/ setToken, bool finite, out Expression e>\n= (. Contract.Ensures(Contract.ValueAtReturn(out e) != null);\n     List<Expression> elements = new List<Expression/*!*/>();;\n     e = dummyExpr;\n  .)\n  \"{\"\n      [ Expressions<elements> ]                (. e = new SetDisplayExpr(setToken, finite, elements);.)\n  \"}\"\n  .\nDisplayExpr<out Expression e>\n= (. Contract.Ensures(Contract.ValueAtReturn(out e) != null);\n     IToken x;  List<Expression> elements;\n     e = dummyExpr;\n  .)\n  ( \"{\"                                        (. x = t;  elements = new List<Expression/*!*/>(); .)\n      [ Expressions<elements> ]                (. e = new SetDisplayExpr(x, true, elements);.)\n    \"}\"\n  | \"[\"                                        (. x = t;  elements = new List<Expression/*!*/>(); .)\n      [ Expressions<elements> ]                (. e = new SeqDisplayExpr(x, elements); .)\n    \"]\"\n  )\n  .\nMultiSetExpr<out Expression e>\n= (. Contract.Ensures(Contract.ValueAtReturn(out e) != null);\n     IToken/*!*/ x = null;  List<Expression/*!*/>/*!*/ elements;\n     e = dummyExpr;\n  .)\n  \"multiset\"                                   (. x = t; .)\n  ( \"{\"                                        (. elements = new List<Expression/*!*/>(); .)\n      [ Expressions<elements> ]                (. e = new MultiSetDisplayExpr(x, elements);.)\n    \"}\"\n  | \"(\"                                        (. x = t;  elements = new List<Expression/*!*/>(); .)\n      Expression<out e, true, true>            (. e = new MultiSetFormingExpr(x, e); .)\n    \")\"\n  )\n  .\nSeqConstructionExpr<out Expression e>\n= (. Contract.Ensures(Contract.ValueAtReturn(out e) != null);\n     IToken x = null;\n     Expression n, f;\n     e = dummyExpr;\n  .)\n  \"seq\"                          (. x = t; .)\n  \"(\"\n  Expression<out n, true, true>\n  \",\"\n  Expression<out f, true, true>\n  \")\"                            (. e = new SeqConstructionExpr(x, n, f); .)\n  .\nMapDisplayExpr<IToken/*!*/ mapToken, bool finite, out Expression e>\n= (. Contract.Ensures(Contract.ValueAtReturn(out e) != null);\n     List<ExpressionPair/*!*/>/*!*/ elements= new List<ExpressionPair/*!*/>() ;\n     e = dummyExpr;\n  .)\n  \"[\"\n    [ MapLiteralExpressions<out elements> ]  (. e = new MapDisplayExpr(mapToken, finite, elements);.)\n  \"]\"\n  .\nMapLiteralExpressions<.out List<ExpressionPair> elements.>\n= (. Expression/*!*/ d, r;\n     elements = new List<ExpressionPair/*!*/>(); .)\n  Expression<out d, true, true> \":=\" Expression<out r, true, true>       (. elements.Add(new ExpressionPair(d,r)); .)\n  { \",\" Expression<out d, true, true> \":=\" Expression<out r, true, true> (. elements.Add(new ExpressionPair(d,r)); .)\n  }\n  .\nMapComprehensionExpr<IToken mapToken, bool finite, out Expression e, bool allowSemi, bool allowLambda, bool allowBitwiseOps>\n= (. Contract.Ensures(Contract.ValueAtReturn(out e) != null);\n     BoundVar bv;\n     List<BoundVar> bvars = new List<BoundVar>();\n     Expression range = null;\n     Expression bodyLeft = null;\n     Expression bodyRight;\n     Attributes attrs = null;\n  .)\n  IdentTypeOptional<out bv>                    (. bvars.Add(bv); .)\n  { \",\"\n    IdentTypeOptional<out bv>                  (. bvars.Add(bv); .)\n  }\n  { Attribute<ref attrs> }\n  [ \"|\" Expression<out range, true, true, true> ]\n  QSep\n  Expression<out bodyRight, allowSemi, allowLambda, allowBitwiseOps>\n  [ IF(IsGets())  /* greedily parse \":=\" */    (. bodyLeft = bodyRight; .)\n    \":=\" Expression<out bodyRight, allowSemi, allowLambda, allowBitwiseOps>\n  ]\n  (. if (bodyLeft == null && bvars.Count != 1) {\n       SemErr(t, \"a map comprehension with more than one bound variable must have a term expression of the form 'Expr := Expr'\");\n       e = dummyExpr;\n     } else {\n       e = new MapComprehension(mapToken, finite, bvars, range ?? new LiteralExpr(mapToken, true), bodyLeft, bodyRight, attrs);\n     }\n  .)\n  .\nEndlessExpression<out Expression e, bool allowSemi, bool allowLambda, bool allowBitwiseOps>\n= (. IToken/*!*/ x;\n     Expression e0, e1;\n     Statement s;\n     bool isExistentialGuard = false;\n     e = dummyExpr;\n  .)\n  ( \"if\"                            (. x = t; .)\n    ( IF(IsExistentialGuard())\n      ExistentialGuard<out e, true>  (. isExistentialGuard = true; .)\n    | Expression<out e, true, true>\n    )\n    \"then\" Expression<out e0, true, true, true>\n    \"else\" Expression<out e1, allowSemi, allowLambda, allowBitwiseOps>\n                                                         (.  if (isExistentialGuard) {\n                                                               var exists = (ExistsExpr) e;\n                                                               var LHSs = new List<CasePattern<BoundVar>>();\n                                                               foreach (var v in exists.BoundVars) {\n                                                                 LHSs.Add(new CasePattern<BoundVar>(e.tok, v));\n                                                               }\n                                                               e0 = new LetExpr(e.tok, LHSs, new List<Expression>() { exists.Term }, e0, false);\n                                                             }\n                                                             e = new ITEExpr(x, isExistentialGuard, e, e0, e1);\n                                                         .)\n  | MatchExpression<out e, allowSemi, allowLambda, allowBitwiseOps>\n  | QuantifierGuts<out e, allowSemi, allowLambda>  /* types are such that we can allow bitwise operations in the quantifier body */\n  | \"set\"                           (. x = t; .)\n    SetComprehensionExpr<x, true, out e, allowSemi, allowLambda, allowBitwiseOps>\n  | \"iset\"                          (. x = t; .)\n    SetComprehensionExpr<x, false, out e, allowSemi, allowLambda, true>\n  | StmtInExpr<out s>\n    Expression<out e, allowSemi, allowLambda, allowBitwiseOps>    (. e = new StmtExpr(s.Tok, s, e); .)\n  | LetExpr<out e, allowSemi, allowLambda, allowBitwiseOps>\n  | \"map\"                           (. x = t; .)\n    MapComprehensionExpr<x, true, out e, allowSemi, allowLambda, allowBitwiseOps>\n  | \"imap\"                          (. x = t; .)\n    MapComprehensionExpr<x, false, out e, allowSemi, allowLambda, true>\n  | \"reveal\"\n    Expression<out e, false, false, allowBitwiseOps> (. e = new RevealExpr(e.tok, e); .)\n  | NamedExpr<out e, allowSemi, allowLambda, allowBitwiseOps>\n  )\n  .\n\nStmtInExpr<out Statement s>\n= (. s = dummyStmt; .)\n  ( AssertStmt<out s, true>\n  | AssumeStmt<out s>\n  | CalcStmt<out s>\n  )\n  .\n\nLetExpr<out Expression e, bool allowSemi, bool allowLambda, bool allowBitwiseOps>\n= (. e = dummyExpr; .)\n  ( LetExprWithLHS<out e, allowSemi, allowLambda, allowBitwiseOps>\n  | LetExprWithoutLHS<out e, allowSemi, allowLambda, allowBitwiseOps>\n  ).\n\nLetExprWithLHS<out Expression e, bool allowSemi, bool allowLambda, bool allowBitwiseOps>\n= (. IToken x = null;\n     bool isGhost = false;\n     var letLHSs = new List<CasePattern<BoundVar>>();\n     var letRHSs = new List<Expression>();\n     CasePattern<BoundVar> pat;\n     bool exact = true;\n     bool isLetOrFail = false;\n     Attributes attrs = null;\n     e = dummyExpr;\n  .)\n    [ \"ghost\"                       (. isGhost = true;  x = t; .)\n    ]\n    \"var\"                           (. if (!isGhost) { x = t; } .)\n    CasePattern<out pat>            (. if (isGhost) { pat.Vars.Iter(bv => bv.IsGhost = true); }\n                                       letLHSs.Add(pat);\n                                    .)\n    { \",\" CasePattern<out pat>      (. if (isGhost) { pat.Vars.Iter(bv => bv.IsGhost = true); }\n                                       letLHSs.Add(pat);\n                                    .)\n    }\n    ( \":=\"\n    | { Attribute<ref attrs> }\n      \":|\"                          (. exact = false;\n                                       foreach (var lhs in letLHSs) {\n                                         if (lhs.Arguments != null) {\n                                           SemErr(lhs.tok, \"LHS of let-such-that expression must be variables, not general patterns\");\n                                         }\n                                       }\n                                    .)\n    | \":-\"                          (. isLetOrFail = true; .)\n    )\n    Expression<out e, false, true>        (. letRHSs.Add(e); .)\n    { \",\" Expression<out e, false, true>  (. letRHSs.Add(e); .)\n    }\n    \";\"\n    Expression<out e, allowSemi, allowLambda, allowBitwiseOps>\n  (.\n    if (isLetOrFail) {\n      CasePattern<BoundVar> lhs = null;\n      Contract.Assert(letLHSs.Count > 0);\n      if (letLHSs.Count == 1) {\n        lhs = letLHSs[0];\n      } else {\n        SemErr(\"':-' can have at most one left-hand side\");\n      }\n      Expression rhs = null;\n      Contract.Assert(letRHSs.Count > 0);\n      if (letRHSs.Count == 1) {\n        rhs = letRHSs[0];\n      } else {\n        SemErr(\"':-' must have exactly one right-hand side\");\n      }\n      e = new LetOrFailExpr(x, lhs, rhs, e);\n    } else {\n      e = new LetExpr(x, letLHSs, letRHSs, e, exact, attrs);\n    }\n  .)\n  .\n\nLetExprWithoutLHS<out Expression e, bool allowSemi, bool allowLambda, bool allowBitwiseOps>\n= (. IToken x;\n     Expression rhs;\n     Expression body;\n  .)\n  \":-\"                                    (. x = t; .)\n  Expression<out rhs, false, true>\n  \";\"\n  Expression<out body, allowSemi, allowLambda, allowBitwiseOps>\n  (. e = new LetOrFailExpr(x, null, rhs, body); .)\n  .\n\nNamedExpr<out Expression e, bool allowSemi, bool allowLambda, bool allowBitwiseOps>\n= (. IToken/*!*/ x, d;\n     e = dummyExpr;\n     Expression expr;\n  .)\n    \"label\"                          (. x = t; .)\n    NoUSIdent<out d>\n    \":\"\n    Expression<out e, allowSemi, allowLambda, allowBitwiseOps>\n                                     (. expr = e;\n                                        e = new NamedExpr(x, d.val, expr); .)\n  .\n\nMatchExpression<out Expression e, bool allowSemi, bool allowLambda, bool allowBitwiseOps>\n= (. Contract.Ensures(Contract.ValueAtReturn(out e) != null); IToken/*!*/ x;  MatchCaseExpr/*!*/ c;\n     List<MatchCaseExpr/*!*/> cases = new List<MatchCaseExpr/*!*/>();\n     bool usesOptionalBraces = false;\n  .)\n  \"match\"                     (. x = t; .)\n  Expression<out e, allowSemi, allowLambda, allowBitwiseOps>\n  ( IF(la.kind == _lbrace)  /* always favor brace-enclosed match body to a case-less match */\n    \"{\" (. usesOptionalBraces = true; .)\n        { CaseExpression<out c, true, true, allowBitwiseOps> (. cases.Add(c); .) }\n    \"}\"\n  |     { IF(la.kind == _case)  /* let each \"case\" bind to the closest preceding \"match\" */\n          CaseExpression<out c, allowSemi, allowLambda, allowBitwiseOps> (. cases.Add(c); .)\n        }\n  )\n  (. e = new MatchExpr(x, e, cases, usesOptionalBraces); .)\n  .\nCaseExpression<out MatchCaseExpr c, bool allowSemi, bool allowLambda, bool allowBitwiseOps>\n= (. Contract.Ensures(Contract.ValueAtReturn(out c) != null); IToken/*!*/ x, id;\n     var arguments = new List<CasePattern<BoundVar>>();\n     CasePattern<BoundVar>/*!*/ pat;\n     Expression/*!*/ body;\n     string/*!*/ name = \"\";\n  .)\n  \"case\"                      (. x = t; .)\n  ( Ident<out id>             (. name = id.val; .)\n    [ \"(\"\n       [ CasePattern<out pat>        (. arguments.Add(pat); .)\n         { \",\" CasePattern<out pat>  (. arguments.Add(pat); .)\n         }\n       ]\n    \")\" ]\n  | \"(\"\n      CasePattern<out pat>        (. arguments.Add(pat); .)\n      { \",\" CasePattern<out pat>  (. arguments.Add(pat); .)\n      }\n    \")\"\n  )\n  \"=>\"\n  Expression<out body, allowSemi, allowLambda, allowBitwiseOps>    (. c = new MatchCaseExpr(x, name, arguments, body); .)\n  .\nCasePattern<.out CasePattern<BoundVar> pat.>\n= (. IToken id;  List<CasePattern<BoundVar>> arguments;\n     BoundVar bv;\n     pat = null;\n  .)\n  ( IF(IsIdentParen())\n    Ident<out id>\n    \"(\"                                (. arguments = new List<CasePattern<BoundVar>>(); .)\n      [ CasePattern<out pat>           (. arguments.Add(pat); .)\n        { \",\" CasePattern<out pat>     (. arguments.Add(pat); .)\n        }\n      ]\n    \")\"                                (. pat = new CasePattern<BoundVar>(id, id.val, arguments); .)\n  | \"(\"                                (. id = t;\n                                          arguments = new List<CasePattern<BoundVar>>();\n                                       .)\n      [ CasePattern<out pat>           (. arguments.Add(pat); .)\n        { \",\" CasePattern<out pat>     (. arguments.Add(pat); .)\n        }\n      ]\n    \")\"                                (. // Parse parenthesis without an identifier as a built in tuple type.\n                                          theBuiltIns.TupleType(id, arguments.Count, true); // make sure the tuple type exists\n                                          string ctor = BuiltIns.TupleTypeCtorNamePrefix + arguments.Count;  //use the TupleTypeCtors\n                                          pat = new CasePattern<BoundVar>(id, ctor, arguments);\n                                       .)\n  | IdentTypeOptional<out bv>          (. // This could be a BoundVar of a parameter-less constructor and we may not know until resolution.\n                                          // Nevertheless, we do put the \"bv\" into the CasePattern here (even though it will get thrown out\n                                          // later if resolution finds the CasePattern to denote a parameter-less constructor), because this\n                                          // (in particular, bv.IsGhost) is the place where a LetExpr records whether or not the \"ghost\"\n                                          // keyword was used in the declaration.\n                                          pat = new CasePattern<BoundVar>(bv.tok, bv);\n                                       .)\n  )\n  (. // In case of parsing errors, make sure 'pat' still returns as non-null\n     if (pat == null) {\n       pat = new CasePattern<BoundVar>(t, \"_ParseError\", new List<CasePattern<BoundVar>>());\n     }\n  .)\n  .\n/* CasePatternLocal is identical to CasePattern, except that it uses LocalVariable instead of BoundVar. Coco does\n * not have a way to make the patterns take a bounded type parameter.\n */\nCasePatternLocal<.out CasePattern<LocalVariable> pat, bool isGhost.>\n= (. IToken id;  List<CasePattern<LocalVariable>> arguments;\n     LocalVariable local;\n     pat = null;\n  .)\n  ( IF(IsIdentParen())\n    Ident<out id>\n    \"(\"                                          (. arguments = new List<CasePattern<LocalVariable>>(); .)\n      [ CasePatternLocal<out pat, isGhost>       (. arguments.Add(pat); .)\n        { \",\" CasePatternLocal<out pat, isGhost> (. arguments.Add(pat); .)\n        }\n      ]\n    \")\"                                          (. pat = new CasePattern<LocalVariable>(id, id.val, arguments); .)\n  | \"(\"                                          (. id = t;\n                                                    arguments = new List<CasePattern<LocalVariable>>();\n                                                 .)\n      [ CasePatternLocal<out pat, isGhost>       (. arguments.Add(pat); .)\n        { \",\" CasePatternLocal<out pat, isGhost> (. arguments.Add(pat); .)\n        }\n      ]\n    \")\"                                (. // Parse parenthesis without an identifier as a built in tuple type.\n                                          theBuiltIns.TupleType(id, arguments.Count, true); // make sure the tuple type exists\n                                          string ctor = BuiltIns.TupleTypeCtorNamePrefix + arguments.Count;  //use the TupleTypeCtors\n                                          pat = new CasePattern<LocalVariable>(id, ctor, arguments);\n                                       .)\n  | LocalIdentTypeOptional<out local, isGhost, true>\n                                       (. // This could be a LocalVariable of a parameter-less constructor and we may not know until resolution.\n                                          // Nevertheless, we do put the local\" into the CasePattern here (even though it will get thrown out\n                                          // later if resolution finds the CasePattern to denote a parameter-less constructor), because this\n                                          // (in particular, local.IsGhost) is the place where a LetExpr records whether or not the \"ghost\"\n                                          // keyword was used in the declaration.\n                                          pat = new CasePattern<LocalVariable>(local.Tok, local);\n                                       .)\n  )\n  (. // In case of parsing errors, make sure 'pat' still returns as non-null\n     if (pat == null) {\n       pat = new CasePattern<LocalVariable>(t, \"_ParseError\", new List<CasePattern<LocalVariable>>());\n     }\n  .)\n  .\n/*------------------------------------------------------------------------*/\nNameSegment<out Expression e>\n= (. IToken id;\n     IToken openParen = null;  List<Type> typeArgs = null;  List<Expression> args = null;\n  .)\n  Ident<out id>\n  ( IF(IsGenericInstantiation(true))\n    (. typeArgs = new List<Type>(); .)\n    GenericInstantiation<typeArgs>\n  | HashCall<id, out openParen, out typeArgs, out args>\n  | /* empty */\n  )\n  /* Note, since HashCall updates id.val, we make sure not to use id.val until after the possibility of calling HashCall. */\n  (. e = new NameSegment(id, id.val, typeArgs);\n     if (openParen != null) {\n       e = new ApplySuffix(openParen, e, args);\n     }\n  .)\n  .\n/* NameSegmentForTypeName is like the production NameSegment, except that it does not allow HashCall */\nNameSegmentForTypeName<out Expression e, bool inExpressionContext>\n= (. IToken id;  List<Type> typeArgs; .)\n  Ident<out id>\n  OptGenericInstantiation<out typeArgs, inExpressionContext>\n  (. e = new NameSegment(id, id.val, typeArgs);\n  .)\n  .\n/* The HashCall production extends a given identifier with a hash sign followed by\n * a list of argument expressions.  That is, if what was just parsed was an identifier id,\n * then the HashCall production will continue parsing into id#[arg](args).\n * One could imagine parsing just the id# as an expression, but Dafny doesn't do that\n * since the first argument to a prefix predicate/method is textually set apart; instead\n * if a programmer wants to curry the arguments, one has to resort to using a lambda\n * expression, just like for other function applications.\n * Note: This grammar production mutates the id.val field to append the hash sign.\n */\nHashCall<.IToken id, out IToken openParen, out List<Type> typeArgs, out List<Expression> args.>\n= (. Expression k; args = new List<Expression>(); typeArgs = null; .)\n  \"#\"                                      (. id.val = id.val + \"#\"; .)\n  [                                        (. typeArgs = new List<Type>(); .)\n    GenericInstantiation<typeArgs>\n  ]\n  \"[\" Expression<out k, true, true> \"]\"    (. args.Add(k); .)\n  \"(\"                                      (. openParen = t; .)\n    [ Expressions<args> ]\n  \")\"\n  .\nSuffix<ref Expression e>\n= (. Contract.Requires(e != null); Contract.Ensures(e!=null);\n     IToken id, x;\n     Expression e0 = null;  Expression e1 = null;  Expression ee;  bool anyDots = false;\n     List<Expression> multipleLengths = null; bool takeRest = false; // takeRest is relevant only if multipleLengths is non-null\n     List<Expression> multipleIndices = null;\n     List<Tuple<IToken, string, Expression>> updates;\n     Expression v;\n  .)\n  ( \".\"\n    ( \"(\"                                             (. x = t; updates = new List<Tuple<IToken, string, Expression>>(); .)\n        MemberBindingUpdate<out id, out v>            (. updates.Add(Tuple.Create(id, id.val, v)); .)\n        { \",\" MemberBindingUpdate<out id, out v>      (. updates.Add(Tuple.Create(id, id.val, v)); .)\n        }\n      \")\"\n      (. e = new DatatypeUpdateExpr(x, e, updates); .)\n    | DotSuffix<out id, out x>                 (. if (x != null) {\n                                                    // process id as a Suffix in its own right\n                                                    e = new ExprDotName(id, e, id.val, null);\n                                                    id = x;  // move to the next Suffix\n                                                  }\n                                                  IToken openParen = null;  List<Type> typeArgs = null;  List<Expression> args = null;\n                                               .)\n\n\n      ( IF(IsGenericInstantiation(true))\n        (. typeArgs = new List<Type>(); .)\n        GenericInstantiation<typeArgs>\n      | HashCall<id, out openParen, out typeArgs, out args>\n      | /* empty */\n      )\n      (. e = new ExprDotName(id, e, id.val, typeArgs);\n         if (openParen != null) {\n           e = new ApplySuffix(openParen, e, args);\n         }\n      .)\n    )\n  | \"[\"                                        (. x = t; .)\n      ( Expression<out ee, true, true>         (. e0 = ee; .)\n        ( \"..\"                                 (. anyDots = true; .)\n          [ Expression<out ee, true, true>     (. e1 = ee; .)\n          ]\n        | \":=\"\n          Expression<out ee, true, true>       (. e1 = ee; .)\n        | \":\"                                  (. multipleLengths = new List<Expression>();\n                                                  multipleLengths.Add(e0);  // account for the Expression read before the colon\n                                                  takeRest = true;\n                                               .)\n          [ Expression<out ee, true, true>     (. multipleLengths.Add(ee); takeRest = false; .)\n            { IF(IsNonFinalColon())\n              \":\"\n              Expression<out ee, true, true>   (. multipleLengths.Add(ee); .)\n            }\n            [ \":\"                              (. takeRest = true; .)\n            ]\n          ]\n        | { \",\" Expression<out ee, true, true> (. if (multipleIndices == null) {\n                                                    multipleIndices = new List<Expression>();\n                                                    multipleIndices.Add(e0);\n                                                  }\n                                                  multipleIndices.Add(ee);\n                                               .)\n          }\n        )\n      | \"..\"                                   (. anyDots = true; .)\n        [ Expression<out ee, true, true>       (. e1 = ee; .)\n        ]\n      )\n      (. if (multipleIndices != null) {\n           e = new MultiSelectExpr(x, e, multipleIndices);\n           // make sure an array class with this dimensionality exists\n           var tmp = theBuiltIns.ArrayType(multipleIndices.Count, new IntType(), true);\n         } else {\n           if (!anyDots && e0 == null) {\n             /* a parsing error occurred */\n             e0 = dummyExpr;\n           }\n           Contract.Assert(anyDots || e0 != null);\n           if (anyDots) {\n             //Contract.Assert(e0 != null || e1 != null);\n             e = new SeqSelectExpr(x, false, e, e0, e1);\n           } else if (multipleLengths != null) {\n             Expression prev = null;\n             List<Expression> seqs = new List<Expression>();\n              foreach (var len in multipleLengths) {\n                var end = prev == null ? len : new BinaryExpr(x, BinaryExpr.Opcode.Add, prev, len);\n                seqs.Add(new SeqSelectExpr(x, false, e, prev, end));\n                prev = end;\n              }\n             if (takeRest) {\n               seqs.Add(new SeqSelectExpr(x, false, e, prev, null));\n             }\n             e = new SeqDisplayExpr(x, seqs);\n           } else if (e1 == null) {\n             Contract.Assert(e0 != null);\n             e = new SeqSelectExpr(x, true, e, e0, null);\n           } else {\n             Contract.Assert(e0 != null);\n             e = new SeqUpdateExpr(x, e, e0, e1);\n           }\n         }\n      .)\n    \"]\"\n  | \"(\"                                    (. IToken openParen = t; var args = new List<Expression>(); .)\n    [ Expressions<args> ]\n    \")\"                                    (. e = new ApplySuffix(openParen, e, args); .)\n  )\n  .\n\n/*------------------------------------------------------------------------*/\nQuantifierGuts<out Expression q, bool allowSemi, bool allowLambda>\n= (. Contract.Ensures(Contract.ValueAtReturn(out q) != null); IToken/*!*/ x = Token.NoToken;\n     bool univ = false;\n     List<BoundVar/*!*/> bvars;\n     Attributes attrs;\n     Expression range;\n     Expression/*!*/ body;\n  .)\n  ( Forall                                     (. x = t;  univ = true; .)\n  | Exists                                     (. x = t; .)\n  )\n  QuantifierDomain<out bvars, out attrs, out range>\n  QSep\n  Expression<out body, allowSemi, allowLambda>\n  (. if (univ) {\n       q = new ForallExpr(x, bvars, range, body, attrs);\n     } else {\n       q = new ExistsExpr(x, bvars, range, body, attrs);\n     }\n  .)\n  .\n\nQuantifierDomain<.out List<BoundVar> bvars, out Attributes attrs, out Expression range.>\n= (.\n     bvars = new List<BoundVar>();\n     BoundVar/*!*/ bv;\n     attrs = null;\n     range = null;\n  .)\n  IdentTypeOptional<out bv>                    (. bvars.Add(bv); .)\n  { \",\"\n    IdentTypeOptional<out bv>                  (. bvars.Add(bv); .)\n  }\n  { Attribute<ref attrs> }\n  [ IF(la.kind == _verticalbar)   /* Coco complains about this ambiguity, thinking that a \"|\" can follow a body-less forall statement; I don't see how that's possible, but this IF is good and suppresses the reported ambiguity */\n    \"|\"\n    Expression<out range, true, true>\n  ]\n  .\n\nSetComprehensionExpr<IToken setToken, bool finite, out Expression q, bool allowSemi, bool allowLambda, bool allowBitwiseOps>\n= (. Contract.Ensures(Contract.ValueAtReturn(out q) != null);\n     BoundVar bv;\n     List<BoundVar/*!*/> bvars = new List<BoundVar>();\n     Expression range;\n     Expression body = null;\n     Attributes attrs = null;\n  .)\n  IdentTypeOptional<out bv>                    (. bvars.Add(bv); .)\n  { \",\"\n    IdentTypeOptional<out bv>                  (. bvars.Add(bv); .)\n  }\n  { Attribute<ref attrs> }\n  \"|\" Expression<out range, allowSemi, allowLambda, allowBitwiseOps>\n  [ IF(IsQSep())  /* let any given body bind to the closest enclosing set comprehension */\n    QSep\n    Expression<out body, allowSemi, allowLambda, allowBitwiseOps>\n  ]\n  (. if (body == null && bvars.Count != 1) {\n       SemErr(t, \"a set comprehension with more than one bound variable must have a term expression\");\n       q = dummyExpr;\n     } else {\n       q = new SetComprehension(setToken, finite, bvars, range, body, attrs);\n     }\n  .)\n  .\nExpressions<.List<Expression> args.>\n= (. Expression e; .)\n  Expression<out e, true, true>                      (. args.Add(e); .)\n  { \",\" Expression<out e, true, true>                (. args.Add(e); .)\n  }\n  .\n/*------------------------------------------------------------------------*/\nAttribute<ref Attributes attrs>\n= (. IToken openBrace, closeBrace;\n     IToken x = null;\n     var args = new List<Expression>();\n  .)\n  \"{:\"                         (. openBrace = t; .)\n  (. ConvertKeywordTokenToIdent(); .)\n  NoUSIdent<out x>\n  [ Expressions<args> ]\n  \"}\"                         (. closeBrace = t; .)\n  (. attrs = new UserSuppliedAttributes(x, openBrace, closeBrace, args, attrs); .)\n  .\n/*------------------------------------------------------------------------*/\nIdent<out IToken/*!*/ x>\n= (. Contract.Ensures(Contract.ValueAtReturn(out x) != null); .)\n  ident            (. x = t; .)\n  .\n// Identifier or sequence of digits\n// Parse one of the following, which are supposed to follow a \".\":\n//        ident\n//        digits\n//        digits . digits\n// In the first two cases, x returns as the token for the ident/digits and y returns as null.\n// In the third case, x and y return as the tokens for the first and second digits.\n// This parser production solves a problem where the scanner might parse a real number instead\n// of stopping at the decimal point.\nDotSuffix<out IToken x, out IToken y>\n= (. Contract.Ensures(Contract.ValueAtReturn(out x) != null);\n     x = Token.NoToken;\n     y = null;\n  .)\n  ( ident          (. x = t; .)\n  | digits         (. x = t; .)\n  | decimaldigits  (. x = t;\n                      int exponent = x.val.IndexOf('e');\n                      if (0 <= exponent) {\n                        // this is not a legal field/destructor name\n                        SemErr(x, \"invalid DotSuffix\");\n                      } else {\n                        int dot = x.val.IndexOf('.');\n                        if (0 <= dot) {\n                          y = new Token();\n                          y.pos = x.pos + dot + 1;\n                          y.val = x.val.Substring(dot + 1);\n                          x.val = x.val.Substring(0, dot);\n                          y.col = x.col + dot + 1;\n                          y.line = x.line;\n                          y.filename = x.filename;\n                          y.kind = x.kind;\n                        }\n                      }\n                   .)\n  | \"requires\"     (. x = t; .)\n  | \"reads\"        (. x = t; .)\n  )\n  .\nMemberBindingUpdate<out IToken id, out Expression e>\n= (. id = Token.NoToken; e = dummyExpr; .)\n  ( ident          (. id = t; .)\n  | digits         (. id = t; .)\n  )\n  \":=\"\n  Expression<out e, true, true>\n  .\n\nLabelIdent<out IToken id>\n= (. id = Token.NoToken; .)\n  ( NoUSIdent<out id>\n  | digits         (. id = t; .)\n  )\n  .\nFuMe_Ident<out IToken id>\n= (. id = Token.NoToken; .)\n  ( NoUSIdent<out id>\n  | digits         (. id = t; .)\n  )\n  .\nExportIdent<out IToken id>\n=\n  FuMe_Ident<out id>\n  .\nTypeNameOrCtorSuffix<out IToken id>\n= (. id = Token.NoToken; .)\n  ( ident          (. id = t; .)\n  | digits         (. id = t; .)\n  )\n  .\n\n// Identifier, disallowing leading underscores\nNoUSIdent<out IToken/*!*/ x>\n= (. Contract.Ensures(Contract.ValueAtReturn(out x) != null); .)\n  ident            (. x = t;\n                      if (x.val.StartsWith(\"_\")) {\n                        SemErr(\"cannot declare identifier beginning with underscore\");\n                      }\n                   .)\n  .\n\n// Identifier, disallowing leading underscores, except possibly the \"wildcard\" identifier \"_\"\nWildIdent<out IToken x, bool allowWildcardId>\n= (. Contract.Ensures(Contract.ValueAtReturn(out x) != null); .)\n  ident            (. x = t;\n                      t.val = UnwildIdent(t.val, allowWildcardId);\n                   .)\n  .\n\nOldSemi  /* NOTE: Coco complains about \"OldSemi deletable\". That's okay. */\n= /* In the future, it may be that semi-colons will be neither needed nor allowed in certain places where,\n   * in the past, they were required.  As a period of transition between the two, such semi-colons are optional.\n   */\n  [ SYNC \";\"    (. errors.DeprecatedStyle(t, \"deprecated style: a semi-colon is not needed here\"); .)\n  ].\n\nNat<out BigInteger n>\n= (. n = BigInteger.Zero;\n     string S;\n  .)\n  ( digits\n    (. S = Util.RemoveUnderscores(t.val);\n       try {\n         n = BigIntegerParser.Parse(S);\n       } catch (System.FormatException) {\n         SemErr(\"incorrectly formatted number\");\n         n = BigInteger.Zero;\n       }\n    .)\n  | hexdigits\n    (. S = Util.RemoveUnderscores(t.val.Substring(2));\n       try {\n         // note: leading 0 required when parsing positive hex numbers\n         n = BigIntegerParser.Parse(\"0\" + S, System.Globalization.NumberStyles.HexNumber);\n       } catch (System.FormatException) {\n         SemErr(\"incorrectly formatted number\");\n         n = BigInteger.Zero;\n       }\n    .)\n  )\n  .\nDec<out BaseTypes.BigDec d>\n= (. d = BaseTypes.BigDec.ZERO; .)\n  (decimaldigits\n    (. var S = Util.RemoveUnderscores(t.val);\n       try {\n         d = BaseTypes.BigDec.FromString(S);\n       } catch (System.FormatException) {\n         SemErr(\"incorrectly formatted number\");\n         d = BaseTypes.BigDec.ZERO;\n       }\n    .)\n  )\n  .\nEND Armada.\n"
  },
  {
    "path": "Source/Armada/ArmadaAst.cs",
    "content": "#define TI_DEBUG_PRINT\n//-----------------------------------------------------------------------------\n//\n// Copyright (C) Microsoft Corporation.  All Rights Reserved.\n//\n//-----------------------------------------------------------------------------\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics.Contracts;\nusing System.Numerics;\nusing System.Linq;\nusing Microsoft.Boogie;\nusing System.Diagnostics;\n\nnamespace Microsoft.Armada {\n  public class Program {\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(FullName != null);\n      Contract.Invariant(DefaultModule != null);\n    }\n\n    public readonly string FullName;\n    public Dictionary<ModuleDefinition,ModuleSignature> ModuleSigs; // filled in during resolution.\n                                                     // Resolution essentially flattens the module hierarchy, for\n                                                     // purposes of translation and compilation.\n\n    public List<ModuleDefinition> CompileModules; // filled in during resolution.\n                                                  // Contains the definitions to be used for compilation.\n\n    public readonly ModuleDecl DefaultModule;\n    public readonly ModuleDefinition DefaultModuleDef;\n    public readonly BuiltIns BuiltIns;\n    public readonly ErrorReporter reporter;\n\n    public Program(string name, [Captured] ModuleDecl module, [Captured] BuiltIns builtIns, ErrorReporter reporter) {\n      Contract.Requires(name != null);\n      Contract.Requires(module != null);\n      Contract.Requires(module is LiteralModuleDecl);\n      Contract.Requires(reporter != null);\n      FullName = name;\n      DefaultModule = module;\n      DefaultModuleDef = (DefaultModuleDecl)((LiteralModuleDecl)module).ModuleDef;\n      BuiltIns = builtIns;\n      this.reporter = reporter;\n      ModuleSigs = new Dictionary<ModuleDefinition,ModuleSignature>();\n      CompileModules = new List<ModuleDefinition>();\n    }\n\n    //Set appropriate visibilty before presenting module\n    public IEnumerable<ModuleDefinition> Modules() {\n\n      foreach (var msig in ModuleSigs) {\n        Type.PushScope(msig.Value.VisibilityScope);\n        yield return msig.Key;\n        Type.PopScope(msig.Value.VisibilityScope);\n      }\n\n    }\n\n    public IEnumerable<ModuleDefinition> RawModules() {\n      return ModuleSigs.Keys;\n    }\n\n    public string Name\n    {\n      get\n      {\n        try\n        {\n          return System.IO.Path.GetFileName(FullName);\n        }\n        catch (ArgumentException)\n        {\n          return FullName;\n        }\n      }\n    }\n  }\n\n\n  public class Include : IComparable\n  {\n    public readonly IToken tok;\n    public readonly string includerFilename;\n    public readonly string includedFilename;\n    public readonly string includedFullPath;\n    public readonly string rawFilename;\n    public bool ErrorReported;\n\n    public Include(IToken tok, string includer, string theFilename, string fullPath, string rawFilename) {\n      this.tok = tok;\n      this.includerFilename = includer;\n      this.includedFilename = theFilename;\n      this.includedFullPath = fullPath;\n      this.ErrorReported = false;\n      this.rawFilename = rawFilename;\n    }\n\n    public int CompareTo(object obj) {\n      var i = obj as Include;\n      if (i != null) {\n        return this.includedFullPath.CompareTo(i.includedFullPath);\n      } else {\n        throw new NotImplementedException();\n      }\n    }\n  }\n\n  public class BuiltIns\n  {\n    public readonly ModuleDefinition SystemModule = new ModuleDefinition(Token.NoToken, \"_System\", new List<IToken>(), false, false, false, null, null, null, true);\n    readonly Dictionary<int, ClassDecl> arrayTypeDecls = new Dictionary<int, ClassDecl>();\n    public readonly Dictionary<int, ArrowTypeDecl> ArrowTypeDecls = new Dictionary<int, ArrowTypeDecl>();\n    public readonly Dictionary<int, SubsetTypeDecl> PartialArrowTypeDecls = new Dictionary<int, SubsetTypeDecl>();  // same keys as arrowTypeDecl\n    public readonly Dictionary<int, SubsetTypeDecl> TotalArrowTypeDecls = new Dictionary<int, SubsetTypeDecl>();  // same keys as arrowTypeDecl\n    readonly Dictionary<int, TupleTypeDecl> tupleTypeDecls = new Dictionary<int, TupleTypeDecl>();\n    public readonly ISet<int> Bitwidths = new HashSet<int>();\n    public SpecialField ORDINAL_Offset;  // filled in by the resolver, used by the translator\n\n    public readonly SubsetTypeDecl NatDecl;\n    public UserDefinedType Nat() { return new UserDefinedType(Token.NoToken, \"nat\", NatDecl, new List<Type>()); }\n    public readonly TraitDecl ObjectDecl;\n    public UserDefinedType ObjectQ() {\n      Contract.Assume(ObjectDecl != null);\n      return new UserDefinedType(Token.NoToken, \"object?\", null) { ResolvedClass = ObjectDecl };\n    }\n\n    public BuiltIns() {\n      SystemModule.Height = -1;  // the system module doesn't get a height assigned later, so we set it here to something below everything else\n      // create type synonym 'string'\n      var str = new TypeSynonymDecl(Token.NoToken, \"string\", new TypeParameter.TypeParameterCharacteristics(TypeParameter.EqualitySupportValue.InferredRequired, false, false), new List<TypeParameter>(), SystemModule, new SeqType(new CharType()), null);\n      SystemModule.TopLevelDecls.Add(str);\n      // create subset type 'nat'\n      var bvNat = new BoundVar(Token.NoToken, \"x\", Type.Int);\n      var natConstraint = Expression.CreateAtMost(Expression.CreateIntLiteral(Token.NoToken, 0), Expression.CreateIdentExpr(bvNat));\n      var ax = AxiomAttribute();\n      NatDecl = new SubsetTypeDecl(Token.NoToken, \"nat\", new TypeParameter.TypeParameterCharacteristics(TypeParameter.EqualitySupportValue.InferredRequired, false, false), new List<TypeParameter>(), SystemModule, bvNat, natConstraint, SubsetTypeDecl.WKind.None, null, ax);\n      SystemModule.TopLevelDecls.Add(NatDecl);\n      // create trait 'object'\n      ObjectDecl = new TraitDecl(Token.NoToken, \"object\", SystemModule, new List<TypeParameter>(), new List<MemberDecl>(), DontCompile());\n      SystemModule.TopLevelDecls.Add(ObjectDecl);\n      // add one-dimensional arrays, since they may arise during type checking\n      // Arrays of other dimensions may be added during parsing as the parser detects the need for these\n      UserDefinedType tmp = ArrayType(1, Type.Int, true);\n      // Arrow types of other dimensions may be added during parsing as the parser detects the need for these.  For the 0-arity\n      // arrow type, the resolver adds a Valid() predicate for iterators, whose corresponding arrow type is conveniently created here.\n      CreateArrowTypeDecl(0);\n      // Note, in addition to these types, the _System module contains tuple types.  These tuple types are added to SystemModule\n      // by the parser as the parser detects the need for these.\n    }\n\n    private Attributes DontCompile() {\n      var flse = Expression.CreateBoolLiteral(Token.NoToken, false);\n      return new Attributes(\"compile\", new List<Expression>() { flse }, null);\n    }\n\n    public static Attributes AxiomAttribute() {\n      return new Attributes(\"axiom\", new List<Expression>(), null);\n    }\n\n    public UserDefinedType ArrayType(int dims, Type arg, bool allowCreationOfNewClass) {\n      Contract.Requires(1 <= dims);\n      Contract.Requires(arg != null);\n      return ArrayType(Token.NoToken, dims, new List<Type>() { arg }, allowCreationOfNewClass);\n    }\n    public UserDefinedType ArrayType(IToken tok, int dims, List<Type> optTypeArgs, bool allowCreationOfNewClass, bool useClassNameType = false) {\n      Contract.Requires(tok != null);\n      Contract.Requires(1 <= dims);\n      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\n      Contract.Ensures(Contract.Result<UserDefinedType>() != null);\n\n      var arrayName = ArrayClassName(dims);\n      if (useClassNameType) {\n        arrayName = arrayName + \"?\";\n      }\n      if (allowCreationOfNewClass && !arrayTypeDecls.ContainsKey(dims)) {\n        ArrayClassDecl arrayClass = new ArrayClassDecl(dims, SystemModule, DontCompile());\n        for (int d = 0; d < dims; d++) {\n          string name = dims == 1 ? \"Length\" : \"Length\" + d;\n          Field len = new SpecialField(Token.NoToken, name, SpecialField.ID.ArrayLength, dims == 1 ? null : (object)d, false, false, false, Type.Int, null);\n          len.EnclosingClass = arrayClass;  // resolve here\n          arrayClass.Members.Add(len);\n        }\n        arrayTypeDecls.Add(dims, arrayClass);\n        SystemModule.TopLevelDecls.Add(arrayClass);\n      }\n      UserDefinedType udt = new UserDefinedType(tok, arrayName, optTypeArgs);\n      return udt;\n    }\n\n    public static string ArrayClassName(int dims) {\n      Contract.Requires(1 <= dims);\n      if (dims == 1) {\n        return \"array\";\n      } else {\n        return \"array\" + dims;\n      }\n    }\n\n    /// <summary>\n    /// Idempotently add an arrow type with arity 'arity' to the system module, and along\n    /// with this arrow type, the two built-in subset types based on the arrow type.\n    /// </summary>\n    public void CreateArrowTypeDecl(int arity) {\n      Contract.Requires(0 <= arity);\n      if (!ArrowTypeDecls.ContainsKey(arity)) {\n        IToken tok = Token.NoToken;\n        var tps = Util.Map(Enumerable.Range(0, arity + 1), x => x < arity ?\n          new TypeParameter(tok, \"T\" + x, TypeParameter.TPVarianceSyntax.Contravariance) :\n          new TypeParameter(tok, \"R\", TypeParameter.TPVarianceSyntax.Covariant_Strict));\n        var tys = tps.ConvertAll(tp => (Type)(new UserDefinedType(tp)));\n        var args = Util.Map(Enumerable.Range(0, arity), i => new Formal(tok, \"x\" + i, tys[i], true, false));\n        var argExprs = args.ConvertAll(a =>\n              (Expression)new IdentifierExpr(tok, a.Name) { Var = a, Type = a.Type });\n        var readsIS = new FunctionCallExpr(tok, \"reads\", new ImplicitThisExpr(tok), tok, argExprs) {\n          Type = new SetType(true, ObjectQ()),\n        };\n        var readsFrame = new List<FrameExpression> { new FrameExpression(tok, readsIS, null) };\n        var req = new Function(tok, \"requires\", false, false, true,\n          new List<TypeParameter>(), args, null, Type.Bool,\n          new List<MaybeFreeExpression>(), readsFrame, new List<MaybeFreeExpression>(),\n          new Specification<Expression>(new List<Expression>(), null),\n          null, null, null);\n        var reads = new Function(tok, \"reads\", false, false, true,\n          new List<TypeParameter>(), args, null, new SetType(true, ObjectQ()),\n          new List<MaybeFreeExpression>(), readsFrame, new List<MaybeFreeExpression>(),\n          new Specification<Expression>(new List<Expression>(), null),\n          null, null, null);\n        readsIS.Function = reads;  // just so we can really claim the member declarations are resolved\n        readsIS.TypeArgumentSubstitutions = Util.Dict(tps, tys);  // ditto\n        var arrowDecl = new ArrowTypeDecl(tps, req, reads, SystemModule, DontCompile());\n        ArrowTypeDecls.Add(arity, arrowDecl);\n        SystemModule.TopLevelDecls.Add(arrowDecl);\n\n        // declaration of read-effect-free arrow-type, aka heap-independent arrow-type, aka partial-function arrow-type\n        tps = Util.Map(Enumerable.Range(0, arity + 1), x => x < arity ?\n          new TypeParameter(tok, \"T\" + x, TypeParameter.TPVarianceSyntax.Contravariance) :\n          new TypeParameter(tok, \"R\", TypeParameter.TPVarianceSyntax.Covariant_Strict));\n        tys = tps.ConvertAll(tp => (Type)(new UserDefinedType(tp)));\n        var id = new BoundVar(tok, \"f\", new ArrowType(tok, arrowDecl, tys));\n        var partialArrow = new SubsetTypeDecl(tok, ArrowType.PartialArrowTypeName(arity),\n          new TypeParameter.TypeParameterCharacteristics(false), tps, SystemModule,\n          id, ArrowSubtypeConstraint(tok, id, reads, tps, false), SubsetTypeDecl.WKind.Special, null, DontCompile());\n        PartialArrowTypeDecls.Add(arity, partialArrow);\n        SystemModule.TopLevelDecls.Add(partialArrow);\n\n        // declaration of total arrow-type\n\n        tps = Util.Map(Enumerable.Range(0, arity + 1), x => x < arity ?\n          new TypeParameter(tok, \"T\" + x, TypeParameter.TPVarianceSyntax.Contravariance) :\n          new TypeParameter(tok, \"R\", TypeParameter.TPVarianceSyntax.Covariant_Strict));\n        tys = tps.ConvertAll(tp => (Type)(new UserDefinedType(tp)));\n        id = new BoundVar(tok, \"f\", new UserDefinedType(tok, partialArrow.Name, partialArrow, tys));\n        var totalArrow = new SubsetTypeDecl(tok, ArrowType.TotalArrowTypeName(arity),\n          new TypeParameter.TypeParameterCharacteristics(false), tps, SystemModule,\n          id, ArrowSubtypeConstraint(tok, id, req, tps, true), SubsetTypeDecl.WKind.Special, null, DontCompile());\n        TotalArrowTypeDecls.Add(arity, totalArrow);\n        SystemModule.TopLevelDecls.Add(totalArrow);\n      }\n    }\n\n    /// <summary>\n    /// Returns an expression that is the constraint of:\n    /// the built-in partial-arrow type (if \"!total\", in which case \"member\" is expected to denote the \"reads\" member), or\n    /// the built-in total-arrow type (if \"total\", in which case \"member\" is expected to denote the \"requires\" member).\n    /// The given \"id\" is expected to be already resolved.\n    /// </summary>\n    private Expression ArrowSubtypeConstraint(IToken tok, BoundVar id, Function member, List<TypeParameter> tps, bool total) {\n      Contract.Requires(tok != null);\n      Contract.Requires(id != null);\n      Contract.Requires(member != null);\n      Contract.Requires(tps != null && 1 <= tps.Count);\n      var f = new IdentifierExpr(tok, id);\n      // forall x0,x1,x2 :: f.reads(x0,x1,x2) == {}\n      // OR\n      // forall x0,x1,x2 :: f.requires(x0,x1,x2)\n      var bvs = new List<BoundVar>();\n      var args = new List<Expression>();\n      var bounds = new List<ComprehensionExpr.BoundedPool>();\n      for (int i = 0; i < tps.Count - 1; i++) {\n        var bv = new BoundVar(tok, \"x\" + i, new UserDefinedType(tps[i]));\n        bvs.Add(bv);\n        args.Add(new IdentifierExpr(tok, bv));\n        bounds.Add(new ComprehensionExpr.SpecialAllocIndependenceAllocatedBoundedPool());\n      }\n      var fn = new MemberSelectExpr(tok, f, member.Name) {\n        Member = member,\n        TypeApplication = f.Type.TypeArgs,\n        Type = member.Type\n      };\n      Expression body = new ApplyExpr(tok, fn, args);\n      body.Type = member.ResultType;  // resolve here\n      if (!total) {\n        Expression emptySet = new SetDisplayExpr(tok, true, new List<Expression>());\n        emptySet.Type = member.ResultType;  // resolve here\n        body = Expression.CreateEq(body, emptySet, member.ResultType);\n      }\n      if (tps.Count > 1) {\n        body = new ForallExpr(tok, bvs, null, body, null) { Type = Type.Bool, Bounds = bounds };\n      }\n      return body;\n    }\n\n    public TupleTypeDecl TupleType(IToken tok, int dims, bool allowCreationOfNewType) {\n      Contract.Requires(tok != null);\n      Contract.Requires(0 <= dims);\n      Contract.Ensures(Contract.Result<TupleTypeDecl>() != null);\n\n      TupleTypeDecl tt;\n      if (!tupleTypeDecls.TryGetValue(dims, out tt)) {\n        Contract.Assume(allowCreationOfNewType);  // the parser should ensure that all needed tuple types exist by the time of resolution\n        if (dims == 2) {\n          // tuple#2 is already defined in DafnyRuntime.cs\n          tt = new TupleTypeDecl(dims, SystemModule, DontCompile());\n        } else {\n          tt = new TupleTypeDecl(dims, SystemModule, null);\n        }\n        tupleTypeDecls.Add(dims, tt);\n        SystemModule.TopLevelDecls.Add(tt);\n      }\n      return tt;\n    }\n\n    public static string TupleTypeName(int dims) {\n      Contract.Requires(0 <= dims);\n      return \"_tuple#\" + dims;\n    }\n    public static bool IsTupleTypeName(string s) {\n      Contract.Requires(s != null);\n      return s.StartsWith(\"_tuple#\");\n    }\n    public const string TupleTypeCtorNamePrefix = \"_#Make\";  // the printer wants this name prefix to be uniquely recognizable\n  }\n\n  /// <summary>\n  /// A class implementing this interface is one that can carry attributes.\n  /// </summary>\n  public interface IAttributeBearingDeclaration\n  {\n  }\n\n  public class Attributes {\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(Name != null);\n      Contract.Invariant(cce.NonNullElements(Args));\n    }\n\n    public string Name;\n    /*Frozen*/\n    public readonly List<Expression> Args;\n    public readonly Attributes Prev;\n\n    public Attributes(string name, [Captured] List<Expression> args, Attributes prev) {\n      Contract.Requires(name != null);\n      Contract.Requires(cce.NonNullElements(args));\n      Name = name;\n      Args = args;\n      Prev = prev;\n    }\n\n    public static IEnumerable<Expression> SubExpressions(Attributes attrs) {\n      return attrs.AsEnumerable().SelectMany(aa => aa.Args);\n    }\n\n    public static bool Contains(Attributes attrs, string nm) {\n      Contract.Requires(nm != null);\n      return attrs.AsEnumerable().Any(aa => aa.Name == nm);\n    }\n\n    /// <summary>\n    /// Returns true if \"nm\" is a specified attribute.  If it is, then:\n    /// - if the attribute is {:nm true}, then value==true\n    /// - if the attribute is {:nm false}, then value==false\n    /// - if the attribute is anything else, then value returns as whatever it was passed in as.\n    /// </summary>\n    [Pure]\n    public static bool ContainsBool(Attributes attrs, string nm, ref bool value) {\n      Contract.Requires(nm != null);\n      foreach (var attr in attrs.AsEnumerable()) {\n        if (attr.Name == nm) {\n          if (attr.Args.Count == 1) {\n            var arg = attr.Args[0] as LiteralExpr;\n            if (arg != null && arg.Value is bool) {\n              value = (bool)arg.Value;\n            }\n          }\n          return true;\n        }\n      }\n      return false;\n    }\n\n    /// <summary>\n    /// Checks whether a Boolean attribute has been set on the declaration itself,\n    /// the enclosing class, or any enclosing module.  Settings closer to the declaration\n    /// override those further away.\n    /// </summary>\n    public static bool ContainsBoolAtAnyLevel(MemberDecl decl, string attribName) {\n      bool setting = true;\n      if (Attributes.ContainsBool(decl.Attributes, attribName, ref setting)) {\n        return setting;\n      }\n\n      if (Attributes.ContainsBool(decl.EnclosingClass.Attributes, attribName, ref setting)) {\n        return setting;\n      }\n\n      // Check the entire stack of modules\n      var mod = decl.EnclosingClass.Module;\n      while (mod != null) {\n        if (Attributes.ContainsBool(mod.Attributes, attribName, ref setting)) {\n          return setting;\n        }\n        mod = mod.Module;\n      }\n\n      return false;\n    }\n\n    /// <summary>\n    /// Returns list of expressions if \"nm\" is a specified attribute:\n    /// - if the attribute is {:nm e1,...,en}, then returns (e1,...,en)\n    /// Otherwise, returns null.\n    /// </summary>\n    public static List<Expression> FindExpressions(Attributes attrs, string nm) {\n      Contract.Requires(nm != null);\n      foreach (var attr in attrs.AsEnumerable()) {\n        if (attr.Name == nm) {\n          return attr.Args;\n        }\n      }\n      return null;\n    }\n\n\n    /// <summary>\n    /// Same as FindExpressions, but returns all matches\n    /// </summary>\n    public static List<List<Expression>> FindAllExpressions(Attributes attrs, string nm) {\n      Contract.Requires(nm != null);\n      List<List<Expression>> ret = null;\n      for (; attrs != null; attrs = attrs.Prev) {\n        if (attrs.Name == nm) {\n          ret = ret ?? new List<List<Expression>>();   // Avoid allocating the list in the common case where we don't find nm\n          ret.Add(attrs.Args);\n        }\n      }\n      return ret;\n    }\n\n    /// <summary>\n    /// Returns true if \"nm\" is a specified attribute whose arguments match the \"allowed\" parameter.\n    /// - if \"nm\" is not found in attrs, return false and leave value unmodified.  Otherwise,\n    /// - if \"allowed\" contains Empty and the Args contains zero elements, return true and leave value unmodified.  Otherwise,\n    /// - if \"allowed\" contains Bool and Args contains one bool literal, return true and set value to the bool literal.  Otherwise,\n    /// - if \"allowed\" contains Int and Args contains one BigInteger literal, return true and set value to the BigInteger literal.  Otherwise,\n    /// - if \"allowed\" contains String and Args contains one string literal, return true and set value to the string literal.  Otherwise,\n    /// - if \"allowed\" contains Expression and Args contains one element, return true and set value to the one element (of type Expression).  Otherwise,\n    /// - return false, leave value unmodified, and call reporter with an error string.\n    /// </summary>\n    public enum MatchingValueOption { Empty, Bool, Int, String, Expression }\n    public static bool ContainsMatchingValue(Attributes attrs, string nm, ref object value, IEnumerable<MatchingValueOption> allowed, Action<string> reporter) {\n      Contract.Requires(nm != null);\n      Contract.Requires(allowed != null);\n      Contract.Requires(reporter != null);\n      List<Expression> args = FindExpressions(attrs, nm);\n      if (args == null) {\n        return false;\n      } else if (args.Count == 0) {\n        if (allowed.Contains(MatchingValueOption.Empty)) {\n          return true;\n        } else {\n          reporter(\"Attribute \" + nm + \" requires one argument\");\n          return false;\n        }\n      } else if (args.Count == 1) {\n        Expression arg = args[0];\n        StringLiteralExpr stringLiteral = arg as StringLiteralExpr;\n        LiteralExpr literal = arg as LiteralExpr;\n        if (literal != null && literal.Value is bool && allowed.Contains(MatchingValueOption.Bool)) {\n          value = literal.Value;\n          return true;\n        } else if (literal != null && literal.Value is BigInteger && allowed.Contains(MatchingValueOption.Int)) {\n          value = literal.Value;\n          return true;\n        } else if (stringLiteral != null && stringLiteral.Value is string && allowed.Contains(MatchingValueOption.String)) {\n          value = stringLiteral.Value;\n          return true;\n        } else if (allowed.Contains(MatchingValueOption.Expression)) {\n          value = arg;\n          return true;\n        } else {\n          reporter(\"Attribute \" + nm + \" expects an argument in one of the following categories: \" + String.Join(\", \", allowed));\n          return false;\n        }\n      } else {\n        reporter(\"Attribute \" + nm + \" cannot have more than one argument\");\n        return false;\n      }\n    }\n  }\n\n  public static class AttributesExtensions {\n    /// <summary>\n    /// By making this an extension method, it can also be invoked for a null receiver.\n    /// </summary>\n    public static IEnumerable<Attributes> AsEnumerable(this Attributes attr) {\n      while (attr != null) {\n        yield return attr;\n        attr = attr.Prev;\n      }\n    }\n  }\n\n  public class UserSuppliedAttributes : Attributes\n  {\n    public readonly IToken tok;  // may be null, if the attribute was constructed internally\n    public readonly IToken OpenBrace;\n    public readonly IToken CloseBrace;\n    public bool Recognized;  // set to true to indicate an attribute that is processed by some part of Dafny; this allows it to be colored in the IDE\n    public UserSuppliedAttributes(IToken tok, IToken openBrace, IToken closeBrace, List<Expression> args, Attributes prev)\n      : base(tok.val, args, prev) {\n      Contract.Requires(tok != null);\n      Contract.Requires(openBrace != null);\n      Contract.Requires(closeBrace != null);\n      Contract.Requires(args != null);\n      this.tok = tok;\n      OpenBrace = openBrace;\n      CloseBrace = closeBrace;\n    }\n  }\n\n\n  public class VisibilityScope {\n    private static uint maxScopeID = 0;\n\n    private SortedSet<uint> scopeTokens = new SortedSet<uint>();\n\n    // Only for debugging\n    private SortedSet<string> scopeIds = new SortedSet<string>();\n\n    private bool overlaps(SortedSet<uint> set1, SortedSet<uint> set2) {\n      if (set1.Count < set2.Count) {\n        return set2.Overlaps(set1);\n      } else {\n        return set1.Overlaps(set2);\n      }\n    }\n\n    private Dictionary<VisibilityScope, Tuple<int, bool>> cached = new Dictionary<VisibilityScope, Tuple<int, bool>>();\n\n    //By convention, the \"null\" scope sees all\n    public bool VisibleInScope(VisibilityScope other) {\n      if (other != null) {\n        Tuple<int, bool> result;\n        if (cached.TryGetValue(other, out result)) {\n          if (result.Item1 == other.scopeTokens.Count()) {\n            return result.Item2;\n          } else {\n            if (result.Item2) {\n              return true;\n            }\n          }\n        }\n        var isoverlap = overlaps(other.scopeTokens, this.scopeTokens);\n        cached[other] = new Tuple<int, bool>(other.scopeTokens.Count(), isoverlap);\n        return isoverlap;\n\n      }\n      return true;\n    }\n\n    [Pure]\n    public bool IsEmpty() {\n      return scopeTokens.Count == 0;\n    }\n\n\n    //However augmenting with a null scope does nothing\n    public void Augment(VisibilityScope other) {\n      if (other != null) {\n        scopeTokens.UnionWith(other.scopeTokens);\n        scopeIds.UnionWith(other.scopeIds);\n        cached.Clear();\n      }\n    }\n\n    public VisibilityScope(bool newScope, string name) {\n      scopeTokens.Add(maxScopeID);\n      scopeIds.Add(name);\n      if (maxScopeID == uint.MaxValue) {\n        Contract.Assert(false);\n      }\n      maxScopeID++;\n    }\n\n    public VisibilityScope() {\n    }\n\n  }\n\n\n  // ------------------------------------------------------------------------------------------------------\n\n  public abstract class Type {\n    public static readonly BoolType Bool = new BoolType();\n    public static readonly CharType Char = new CharType();\n    public static readonly IntType Int = new IntType();\n    public static readonly RealType Real = new RealType();\n    public static Type Nat() { return new UserDefinedType(Token.NoToken, \"nat\", null); }  // note, this returns an unresolved type\n    public static Type String() { return new UserDefinedType(Token.NoToken, \"string\", null); }  // note, this returns an unresolved type\n    public static readonly BigOrdinalType BigOrdinal = new BigOrdinalType();\n\n    [ThreadStatic]\n    private static List<VisibilityScope> scopes = new List<VisibilityScope>();\n\n    [ThreadStatic]\n    private static bool scopesEnabled = false;\n\n    public static void PushScope(VisibilityScope scope) {\n      scopes.Add(scope);\n    }\n\n    public static void ResetScopes() {\n      scopes = new List<VisibilityScope>();\n      scopesEnabled = false;\n    }\n\n\n    public static void PopScope() {\n      Contract.Assert(scopes.Count > 0);\n      scopes.RemoveAt(scopes.Count - 1);\n    }\n\n    public static void PopScope(VisibilityScope expected) {\n      Contract.Assert(scopes.Count > 0);\n      Contract.Assert(scopes[scopes.Count - 1] == expected);\n      PopScope();\n    }\n\n    public static VisibilityScope GetScope() {\n      if (scopes.Count > 0 && scopesEnabled) {\n        return scopes[scopes.Count - 1];\n      }\n      return null;\n    }\n\n    public static void EnableScopes() {\n      Contract.Assert(!scopesEnabled);\n      scopesEnabled = true;\n    }\n\n    public static void DisableScopes() {\n      Contract.Assert(scopesEnabled);\n      scopesEnabled = false;\n    }\n\n\n    public static string TypeArgsToString(ModuleDefinition/*?*/ context, List<Type> typeArgs, bool parseAble = false) {\n      Contract.Requires(typeArgs == null ||\n        (typeArgs.All(ty => ty != null && ty.TypeName(context, parseAble) != null) &&\n         (typeArgs.All(ty => ty.TypeName(context, parseAble).StartsWith(\"_\")) ||\n          typeArgs.All(ty => !ty.TypeName(context, parseAble).StartsWith(\"_\")))));\n\n      if (typeArgs != null && typeArgs.Count > 0 &&\n          (!parseAble || !typeArgs[0].TypeName(context, parseAble).StartsWith(\"_\"))){\n        return string.Format(\"<{0}>\",Util.Comma(\", \", typeArgs, ty => ty.TypeName(context, parseAble)));\n      }\n      return \"\";\n    }\n\n    public static string TypeArgsToString(List<Type> typeArgs, bool parseAble = false) {\n      return TypeArgsToString(null, typeArgs, parseAble);\n    }\n\n    public string TypeArgsToString(ModuleDefinition/*?*/ context, bool parseAble = false) {\n      return Type.TypeArgsToString(context, this.TypeArgs, parseAble);\n    }\n\n    // Type arguments to the type\n    public List<Type> TypeArgs = new List<Type>();\n\n    [Pure]\n    public abstract string TypeName(ModuleDefinition/*?*/ context, bool parseAble = false);\n    [Pure]\n    public override string ToString() {\n      return TypeName(null, false);\n    }\n\n    /// <summary>\n    /// Return the most constrained version of \"this\", getting to the bottom of proxies.\n    /// </summary>\n    public Type Normalize() {\n      Contract.Ensures(Contract.Result<Type>() != null);\n      Type type = this;\n      while (true) {\n        var pt = type as TypeProxy;\n        if (pt != null && pt.T != null) {\n          type = pt.T;\n        } else {\n          return type;\n        }\n      }\n    }\n\n    /// <summary>\n    /// Return the type that \"this\" stands for, getting to the bottom of proxies and following type synonyms.\n    /// </summary>\n    [Pure]\n    public Type NormalizeExpand(bool keepConstraints = false) {\n      Contract.Ensures(Contract.Result<Type>() != null);\n      Contract.Ensures(!(Contract.Result<Type>() is TypeProxy) || ((TypeProxy)Contract.Result<Type>()).T == null);  // return a proxy only if .T == null\n      Type type = this;\n      while (true) {\n\n        var pt = type as TypeProxy;\n        if (pt != null && pt.T != null) {\n          type = pt.T;\n          continue;\n        }\n\n        var scope = Type.GetScope();\n        var rtd = type.AsRevealableType;\n        if (rtd != null) {\n          var udt = (UserDefinedType)type;\n\n          if (!rtd.AsTopLevelDecl.IsVisibleInScope(scope)) {\n            Contract.Assert(false);\n          }\n\n          if (rtd.IsRevealedInScope(scope)) {\n            if (rtd is TypeSynonymDecl && (!(rtd is SubsetTypeDecl) || !keepConstraints)) {\n              type = ((TypeSynonymDecl)rtd).RhsWithArgumentIgnoringScope(udt.TypeArgs);\n              continue;\n            } else {\n              return type;\n            }\n          } else { // type is hidden, no more normalization is possible\n            return rtd.SelfSynonym(type.TypeArgs);\n          }\n        }\n\n        //A hidden type may become visible in another scope\n        var isyn = type.AsInternalTypeSynonym;\n        if (isyn != null) {\n          Contract.Assert(isyn.IsVisibleInScope(scope));\n          if (isyn.IsRevealedInScope(scope)) {\n            var udt = (UserDefinedType)type;\n            type = isyn.RhsWithArgument(udt.TypeArgs);\n            continue;\n          } else {\n            return type;\n          }\n        }\n\n        return type;\n      }\n    }\n\n    /// <summary>\n    /// Return the type that \"this\" stands for, getting to the bottom of proxies and following type synonyms, but does\n    /// not follow subset types.\n    /// </summary>\n    [Pure]\n    public Type NormalizeExpandKeepConstraints() {\n      return NormalizeExpand(true);\n    }\n\n    /// <summary>\n    /// Returns whether or not \"this\" and \"that\" denote the same type, module proxies and type synonyms and subset types.\n    /// </summary>\n    [Pure]\n    public abstract bool Equals(Type that);\n\n    public bool IsBoolType { get { return NormalizeExpand() is BoolType; } }\n    public bool IsCharType { get { return NormalizeExpand() is CharType; } }\n    public bool IsIntegerType { get { return NormalizeExpand() is IntType; } }\n    public bool IsRealType { get { return NormalizeExpand() is RealType; } }\n    public bool IsBigOrdinalType { get { return NormalizeExpand() is BigOrdinalType; } }\n    public bool IsBitVectorType { get { return AsBitVectorType != null; } }\n    public BitvectorType AsBitVectorType { get { return NormalizeExpand() as BitvectorType; } }\n    public bool IsNumericBased() {\n      var t = NormalizeExpand();\n      return t.IsIntegerType || t.IsRealType || t.AsNewtype != null;\n    }\n    public enum NumericPersuation { Int, Real }\n    [Pure]\n    public bool IsNumericBased(NumericPersuation p) {\n      Type t = this;\n      while (true) {\n        t = t.NormalizeExpand();\n        if (t.IsIntegerType) {\n          return p == NumericPersuation.Int;\n        } else if (t.IsRealType) {\n          return p == NumericPersuation.Real;\n        }\n        var d = t.AsNewtype;\n        if (d == null) {\n          return false;\n        }\n        t = d.BaseType;\n      }\n    }\n\n    public bool HasFinitePossibleValues {\n      get {\n        if (IsBoolType || IsCharType || IsRefType) {\n          return true;\n        }\n        var st = AsSetType;\n        if (st != null && st.Arg.HasFinitePossibleValues) {\n          return true;\n        }\n        var mt = AsMapType;\n        if (mt != null && mt.Domain.HasFinitePossibleValues) {\n          return true;\n        }\n        var dt = AsDatatype;\n        if (dt != null && dt.HasFinitePossibleValues) {\n          return true;\n        }\n        return false;\n      }\n    }\n\n    public bool IsAllocFree {\n      get {\n        if (IsRefType) {\n          return false;\n        } else if (IsTypeParameter) {\n          return AsTypeParameter.Characteristics.DisallowReferenceTypes;\n        } else {\n          return TypeArgs.All(ta => ta.IsAllocFree);\n        }\n      }\n    }\n\n    public CollectionType AsCollectionType { get { return NormalizeExpand() as CollectionType; } }\n    public SetType AsSetType { get { return NormalizeExpand() as SetType; } }\n    public MultiSetType AsMultiSetType { get { return NormalizeExpand() as MultiSetType; } }\n    public SeqType AsSeqType { get { return NormalizeExpand() as SeqType; } }\n    public MapType AsMapType { get { return NormalizeExpand() as MapType; } }\n\n    public bool IsRefType {\n      get {\n        var udt = NormalizeExpand() as UserDefinedType;\n        return udt != null && udt.ResolvedParam == null && udt.ResolvedClass is ClassDecl\n          && !(udt.ResolvedClass is ArrowTypeDecl);\n      }\n    }\n    public bool IsTopLevelTypeWithMembers {\n      get {\n        return AsTopLevelTypeWithMembers != null;\n      }\n    }\n    public TopLevelDeclWithMembers/*?*/ AsTopLevelTypeWithMembers {\n      get {\n        var udt = NormalizeExpand() as UserDefinedType;\n        return udt != null && udt.ResolvedParam == null ? udt.ResolvedClass as TopLevelDeclWithMembers : null;\n      }\n    }\n    /// <summary>\n    /// Returns \"true\" if the type represents the \"object?\".\n    /// </summary>\n    public bool IsObjectQ {\n      get {\n        var udt = NormalizeExpandKeepConstraints() as UserDefinedType;\n        return udt != null && udt.ResolvedClass is ClassDecl && ((ClassDecl)udt.ResolvedClass).Name == \"object\";\n      }\n    }\n    /// <summary>\n    /// Returns \"true\" if the type is a non-null type or any subset type thereof.\n    /// </summary>\n    public bool IsNonNullRefType {\n      get {\n        return AsNonNullRefType != null;\n      }\n    }\n    /// <summary>\n    /// If the type is a non-null type or any subset type thereof, return the UserDefinedType whose\n    /// .ResolvedClass value is a NonNullTypeDecl.\n    /// Otherwise, return \"null\".\n    /// </summary>\n    public UserDefinedType AsNonNullRefType {\n      get {\n        var t = this;\n        while (true) {\n          var udt = t.NormalizeExpandKeepConstraints() as UserDefinedType;\n          if (udt == null) {\n            return null;\n          }\n          if (udt.ResolvedClass is NonNullTypeDecl) {\n            return udt;\n          }\n          var sst = udt.ResolvedClass as SubsetTypeDecl;\n          if (sst != null) {\n            t = sst.RhsWithArgument(udt.TypeArgs);  // continue the search up the chain of subset types\n          } else {\n            return null;\n          }\n        }\n      }\n    }\n    public bool IsTraitType {\n      get {\n        var udt = NormalizeExpand() as UserDefinedType;\n        return udt != null && udt.ResolvedParam == null && udt.ResolvedClass is TraitDecl;\n      }\n    }\n    public bool IsArrayType {\n      get {\n        return AsArrayType != null;\n      }\n    }\n    public ArrayClassDecl/*?*/ AsArrayType {\n      get {\n        var t = NormalizeExpand();\n        var udt = UserDefinedType.DenotesClass(t);\n        return udt == null ? null : udt.ResolvedClass as ArrayClassDecl;\n      }\n    }\n    /// <summary>\n    /// Returns \"true\" if the type is one of the 3 built-in arrow types.\n    /// </summary>\n    public bool IsBuiltinArrowType {\n      get {\n        var t = Normalize();  // but don't expand synonyms or strip off constraints\n        if (t is ArrowType) {\n          return true;\n        }\n        var udt = t as UserDefinedType;\n        return udt != null && (ArrowType.IsPartialArrowTypeName(udt.Name) || ArrowType.IsTotalArrowTypeName(udt.Name));\n      }\n    }\n    /// <summary>\n    /// Returns \"true\" if the type is a partial arrow or any subset type thereof.\n    /// </summary>\n    public bool IsArrowTypeWithoutReadEffects {\n      get {\n        var t = this;\n        while (true) {\n          var udt = t.NormalizeExpandKeepConstraints() as UserDefinedType;\n          if (udt == null) {\n            return false;\n          } else if (ArrowType.IsPartialArrowTypeName(udt.Name)) {\n            return true;\n          }\n          var sst = udt.ResolvedClass as SubsetTypeDecl;\n          if (sst != null) {\n            t = sst.RhsWithArgument(udt.TypeArgs);  // continue the search up the chain of subset types\n          } else {\n            return false;\n          }\n        }\n      }\n    }\n    /// <summary>\n    /// Returns \"true\" if the type is a total arrow or any subset type thereof.\n    /// </summary>\n    public bool IsArrowTypeWithoutPreconditions {\n      get {\n        var t = this;\n        while (true) {\n          var udt = t.NormalizeExpandKeepConstraints() as UserDefinedType;\n          if (udt == null) {\n            return false;\n          } else if (ArrowType.IsTotalArrowTypeName(udt.Name)) {\n            return true;\n          }\n          var sst = udt.ResolvedClass as SubsetTypeDecl;\n          if (sst != null) {\n            t = sst.RhsWithArgument(udt.TypeArgs);  // continue the search up the chain of subset types\n          } else {\n            return false;\n          }\n        }\n      }\n    }\n    public bool IsArrowType {\n      get { return AsArrowType != null; }\n    }\n    public ArrowType AsArrowType {\n      get {\n        var t = NormalizeExpand();\n        return t as ArrowType;\n      }\n    }\n    public bool IsMapType {\n      get {\n        var t = NormalizeExpand() as MapType;\n        return t != null && t.Finite;\n      }\n    }\n\n    public bool IsIMapType {\n      get {\n        var t = NormalizeExpand() as MapType;\n        return t != null && !t.Finite;\n      }\n    }\n    public bool IsISetType {\n      get {\n        var t = NormalizeExpand() as SetType;\n        return t != null && !t.Finite;\n      }\n    }\n    public NewtypeDecl AsNewtype {\n      get {\n        var udt = NormalizeExpand() as UserDefinedType;\n        return udt == null ? null : udt.ResolvedClass as NewtypeDecl;\n      }\n    }\n    public TypeSynonymDecl AsTypeSynonym {\n      get {\n        var udt = this as UserDefinedType;  // note, it is important to use 'this' here, not 'this.NormalizeExpand()'\n        if (udt == null) {\n          return null;\n        } else {\n          return udt.ResolvedClass as TypeSynonymDecl;\n        }\n      }\n    }\n    public InternalTypeSynonymDecl AsInternalTypeSynonym {\n      get {\n        var udt = this as UserDefinedType;  // note, it is important to use 'this' here, not 'this.NormalizeExpand()'\n        if (udt == null) {\n          return null;\n        } else {\n          return udt.ResolvedClass as InternalTypeSynonymDecl;\n        }\n      }\n    }\n    public RedirectingTypeDecl AsRedirectingType {\n      get {\n        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, or with care thereafter.\n        if (udt == null) {\n          return null;\n        } else {\n          return (RedirectingTypeDecl)(udt.ResolvedClass as TypeSynonymDecl) ?? udt.ResolvedClass as NewtypeDecl;\n        }\n      }\n    }\n    public RevealableTypeDecl AsRevealableType {\n      get {\n        var udt = this as UserDefinedType;\n        if (udt == null) {\n          return null;\n        } else {\n          return (udt.ResolvedClass as RevealableTypeDecl);\n        }\n      }\n    }\n    public bool IsRevealableType {\n      get { return AsRevealableType != null; }\n    }\n    public bool IsDatatype {\n      get {\n        return AsDatatype != null;\n      }\n    }\n    public DatatypeDecl AsDatatype {\n      get {\n        var udt = NormalizeExpand() as UserDefinedType;\n        if (udt == null) {\n          return null;\n        } else {\n          return udt.ResolvedClass as DatatypeDecl;\n        }\n      }\n    }\n    public bool IsIndDatatype {\n      get {\n        return AsIndDatatype != null;\n      }\n    }\n    public IndDatatypeDecl AsIndDatatype {\n      get {\n        var udt = NormalizeExpand() as UserDefinedType;\n        if (udt == null) {\n          return null;\n        } else {\n          return udt.ResolvedClass as IndDatatypeDecl;\n        }\n      }\n    }\n    public bool IsCoDatatype {\n      get {\n        return AsCoDatatype != null;\n      }\n    }\n    public CoDatatypeDecl AsCoDatatype {\n      get {\n        var udt = NormalizeExpand() as UserDefinedType;\n        if (udt == null) {\n          return null;\n        } else {\n          return udt.ResolvedClass as CoDatatypeDecl;\n        }\n      }\n    }\n    public bool InvolvesCoDatatype {\n      get {\n        return IsCoDatatype;  // TODO: should really check structure of the type recursively\n      }\n    }\n    public bool IsTypeParameter {\n      get {\n        return AsTypeParameter != null;\n      }\n    }\n    public bool IsInternalTypeSynonym {\n      get { return AsInternalTypeSynonym != null; }\n    }\n    public TypeParameter AsTypeParameter {\n      get {\n        var ct = NormalizeExpandKeepConstraints() as UserDefinedType;\n        return ct == null ? null : ct.ResolvedParam;\n      }\n    }\n    public bool IsOpaqueType {\n      get {\n        var udt = this.Normalize() as UserDefinedType;  // note, it is important to use 'this.Normalize()' here, not 'this.NormalizeExpand()'\n        return udt != null && udt.ResolvedClass is OpaqueTypeDecl;\n      }\n    }\n    public virtual bool SupportsEquality {\n      get {\n        return true;\n      }\n    }\n    public virtual bool MayInvolveReferences {\n      get {\n        return false;\n      }\n    }\n\n    /// <summary>\n    /// Returns true if it is known how to meaningfully compare the type's inhabitants.\n    /// </summary>\n    public bool IsOrdered {\n      get {\n        var ct = NormalizeExpand();\n        return !ct.IsTypeParameter && !ct.IsInternalTypeSynonym && !ct.IsCoDatatype && !ct.IsArrowType && !ct.IsIMapType && !ct.IsISetType;\n      }\n    }\n\n    /// <summary>\n    /// Returns \"true\" iff \"sub\" is a subtype of \"super\".\n    /// Expects that neither \"super\" nor \"sub\" is an unresolved proxy.\n    /// </summary>\n    public static bool IsSupertype(Type super, Type sub) {\n      Contract.Requires(super != null);\n      Contract.Requires(sub != null);\n      if (!IsHeadSupertypeOf(super, sub)) {\n        return false;\n      }\n      super = super.NormalizeExpand();\n      sub = sub.NormalizeExpand();\n      var polarities = GetPolarities(super);\n      Contract.Assert(super.IsTraitType ? polarities.Count == 0 : polarities.Count == super.TypeArgs.Count && polarities.Count == sub.TypeArgs.Count);\n      if (super.IsTraitType) {\n        return true;\n      }\n      var allGood = true;\n      for (int i = 0; allGood && i < polarities.Count; i++) {\n        switch (polarities[i]) {\n          case TypeParameter.TPVariance.Co:\n            allGood = IsSupertype(super.TypeArgs[i], sub.TypeArgs[i]);\n            break;\n          case TypeParameter.TPVariance.Contra:\n            allGood = IsSupertype(sub.TypeArgs[i], super.TypeArgs[i]);\n            break;\n          case TypeParameter.TPVariance.Non:\n          default:  // \"default\" shouldn't ever happen\n            allGood = Equal_Improved(super.TypeArgs[i], sub.TypeArgs[i]);\n            break;\n        }\n      }\n      return allGood;\n    }\n\n    /// <summary>\n    /// Expects that \"type\" has already been normalized.\n    /// </summary>\n    public static List<TypeParameter.TPVariance> GetPolarities(Type type) {\n      Contract.Requires(type != null);\n      if (type is BasicType || type is ArtificialType) {\n        // there are no type parameters\n        return new List<TypeParameter.TPVariance>();\n      } else if (type is MapType) {\n        return new List<TypeParameter.TPVariance> { TypeParameter.TPVariance.Co, TypeParameter.TPVariance.Co };\n      } else if (type is CollectionType) {\n        return new List<TypeParameter.TPVariance> { TypeParameter.TPVariance.Co };\n      } else {\n        var udf = (UserDefinedType)type;\n        if (udf.TypeArgs.Count == 0) {\n          return new List<TypeParameter.TPVariance>();\n        }\n        // look up the declaration of the formal type parameters\n        var cl = udf.ResolvedClass;\n        return cl.TypeArgs.ConvertAll(tp => tp.Variance);\n      }\n    }\n\n    public static bool FromSameHead_Subtype(Type t, Type u, BuiltIns builtIns, out Type a, out Type b) {\n      Contract.Requires(t != null);\n      Contract.Requires(u != null);\n      Contract.Requires(builtIns != null);\n      if (FromSameHead(t, u, out a, out b)) {\n        return true;\n      }\n      t = t.NormalizeExpand();\n      u = u.NormalizeExpand();\n      if (t.IsRefType && u.IsRefType) {\n        if (t.IsObjectQ) {\n          a = b = t;\n          return true;\n        } else if (u.IsObjectQ) {\n          a = b = u;\n          return true;\n        }\n        var tt = ((UserDefinedType)t).ResolvedClass as ClassDecl;\n        var uu = ((UserDefinedType)u).ResolvedClass as ClassDecl;\n        if (uu.DerivesFrom(tt)) {\n          a = b = t;\n          return true;\n        } else if (tt.DerivesFrom(uu)) {\n          a = b = u;\n          return true;\n        }\n      }\n      return false;\n    }\n\n    public static bool FromSameHead(Type t, Type u, out Type a, out Type b) {\n      a = t;\n      b = u;\n      var towerA = GetTowerOfSubsetTypes(a);\n      var towerB = GetTowerOfSubsetTypes(b);\n      for (var n = Math.Min(towerA.Count, towerB.Count); 0 <= --n;) {\n        a = towerA[n];\n        b = towerB[n];\n        if (SameHead(a, b)) {\n          return true;\n        }\n      }\n      return false;\n    }\n\n    /// <summary>\n    /// Returns true if t and u have the same head type.\n    /// It is assumed that t and u have been normalized and expanded by the caller, according\n    /// to its purposes.\n    /// </summary>\n    public static bool SameHead(Type t, Type u) {\n      Contract.Requires(t != null);\n      Contract.Requires(u != null);\n      if (t is TypeProxy) {\n        return t == u;\n      } else if (t.TypeArgs.Count == 0) {\n        return Equal_Improved(t, u);\n      } else if (t is SetType) {\n        return u is SetType && t.IsISetType == u.IsISetType;\n      } else if (t is SeqType) {\n        return u is SeqType;\n      } else if (t is MultiSetType) {\n        return u is MultiSetType;\n      } else if (t is MapType) {\n        return u is MapType && t.IsIMapType == u.IsIMapType;\n      } else if (t is PointerType) {\n        return u is PointerType;\n      } else if (t is SizedArrayType) {\n        return u is SizedArrayType;\n      } else {\n        Contract.Assert(t is UserDefinedType);\n        var udtT = (UserDefinedType)t;\n        var udtU = u as UserDefinedType;\n        return udtU != null && udtT.ResolvedClass == udtU.ResolvedClass;\n      }\n    }\n\n    /// <summary>\n    /// Returns \"true\" iff the head symbols of \"sub\" can be a subtype of the head symbol of \"super\".\n    /// Expects that neither \"super\" nor \"sub\" is an unresolved proxy type (but their type arguments are\n    /// allowed to be, since this method does not inspect the type arguments).\n    /// </summary>\n    public static bool IsHeadSupertypeOf(Type super, Type sub) {\n      Contract.Requires(super != null);\n      Contract.Requires(sub != null);\n      super = super.NormalizeExpandKeepConstraints();  // expand type synonyms\n      var origSub = sub;\n      sub = sub.NormalizeExpand();  // expand type synonyms AND constraints\n      if (super is TypeProxy) {\n        return super == sub;\n      } else if (super is BoolType) {\n        return sub is BoolType;\n      } else if (super is CharType) {\n        return sub is CharType;\n      } else if (super is IntType) {\n        return sub is IntType;\n      } else if (super is RealType) {\n        return sub is RealType;\n      } else if (super is BitvectorType) {\n        var bitvectorSuper = (BitvectorType)super;\n        var bitvectorSub = sub as BitvectorType;\n        return bitvectorSub != null && bitvectorSuper.Width == bitvectorSub.Width;\n      } else if (super is IntVarietiesSupertype) {\n        while (sub.AsNewtype != null) {\n          sub = sub.AsNewtype.BaseType.NormalizeExpand();\n        }\n        return sub.IsIntegerType || sub is BitvectorType || sub is BigOrdinalType;\n      } else if (super is RealVarietiesSupertype) {\n        while (sub.AsNewtype != null) {\n          sub = sub.AsNewtype.BaseType.NormalizeExpand();\n        }\n        return sub is RealType;\n      } else if (super is BigOrdinalType) {\n        return sub is BigOrdinalType;\n      } else if (super is SetType) {\n        return sub is SetType && (super.IsISetType || !sub.IsISetType);\n      } else if (super is SeqType) {\n        return sub is SeqType;\n      } else if (super is PointerType) {\n        return sub is PointerType;\n      } else if (super is SizedArrayType) {\n        return sub is SizedArrayType;\n      } else if (super is MultiSetType) {\n        return sub is MultiSetType;\n      } else if (super is MapType) {\n        return sub is MapType && (super.IsIMapType || !sub.IsIMapType);\n      } else if (super is ArrowType) {\n        var asuper = (ArrowType)super;\n        var asub = sub as ArrowType;\n        return asub != null && asuper.Arity == asub.Arity;\n      } else if (super.IsObjectQ) {\n        var clSub = sub as UserDefinedType;\n        return sub.IsObjectQ || (clSub != null && clSub.ResolvedClass is ClassDecl);\n      } else if (super is UserDefinedType) {\n        var udtSuper = (UserDefinedType)super;\n        if (udtSuper.ResolvedParam != null) {\n          return udtSuper.ResolvedParam == sub.AsTypeParameter;\n        } else {\n          Contract.Assert(udtSuper.ResolvedClass != null);\n          sub = origSub;  // get back to the starting point\n          while (true) {\n            sub = sub.NormalizeExpandKeepConstraints();  // skip past proxies and type synonyms\n            var udtSub = sub as UserDefinedType;\n            if (udtSub == null) {\n              return false;\n            } else if (udtSuper.ResolvedClass == udtSub.ResolvedClass) {\n              return true;\n            } else if (udtSub.ResolvedClass is SubsetTypeDecl) {\n              sub = ((SubsetTypeDecl)udtSub.ResolvedClass).RhsWithArgument(udtSub.TypeArgs);\n              if (udtSub.ResolvedClass is NonNullTypeDecl && udtSuper.ResolvedClass is NonNullTypeDecl) {\n                // move \"super\" up the base-type chain, as was done with \"sub\", because non-nullness is essentially a co-variant type constructor\n                var possiblyNullSuper = ((SubsetTypeDecl)udtSuper.ResolvedClass).RhsWithArgument(udtSuper.TypeArgs);\n                udtSuper = (UserDefinedType)possiblyNullSuper;  // applying .RhsWithArgument to a NonNullTypeDecl should always yield a UserDefinedType\n                if (udtSuper.IsObjectQ) {\n                  return true;\n                }\n              }\n            } else if (udtSub.ResolvedClass is ClassDecl) {\n              var cl = (ClassDecl)udtSub.ResolvedClass;\n              return cl.DerivesFrom(udtSuper.ResolvedClass);\n            } else {\n              return false;\n            }\n          }\n        }\n      } else {\n        Contract.Assert(false);  // unexpected kind of type\n        return true;  // to please the compiler\n      }\n    }\n\n    /// <summary>\n    /// Returns \"true\" iff \"a\" and \"b\" denote the same type, expanding type synonyms (but treating types with\n    /// constraints as being separate types).\n    /// Expects that neither \"a\" nor \"b\" is or contains an unresolved proxy type.\n    /// </summary>\n    public static bool Equal_Improved(Type a, Type b) {\n      Contract.Requires(a != null);\n      Contract.Requires(b != null);\n      a = a.NormalizeExpandKeepConstraints();  // expand type synonyms\n      b = b.NormalizeExpandKeepConstraints();  // expand type synonyms\n      if (a is BoolType) {\n        return b is BoolType;\n      } else if (a is CharType) {\n        return b is CharType;\n      } else if (a is IntType) {\n        return b is IntType;\n      } else if (a is RealType) {\n        return b is RealType;\n      } else if (a is BitvectorType) {\n        var bitvectorSuper = (BitvectorType)a;\n        var bitvectorSub = b as BitvectorType;\n        return bitvectorSub != null && bitvectorSuper.Width == bitvectorSub.Width;\n      } else if (a is BigOrdinalType) {\n        return b is BigOrdinalType;\n      } else if (a is SetType) {\n        return b is SetType && Equal_Improved(a.TypeArgs[0], b.TypeArgs[0]) && (a.IsISetType == b.IsISetType);\n      } else if (a is SeqType) {\n        return b is SeqType && Equal_Improved(a.TypeArgs[0], b.TypeArgs[0]);\n      } else if (a is MultiSetType) {\n        return b is MultiSetType && Equal_Improved(a.TypeArgs[0], b.TypeArgs[0]);\n      } else if (a is MapType) {\n        return b is MapType && Equal_Improved(a.TypeArgs[0], b.TypeArgs[0]) && Equal_Improved(a.TypeArgs[1], b.TypeArgs[1]) && (a.IsIMapType == b.IsIMapType);\n      } else if (a is ArrowType) {\n        var asuper = (ArrowType)a;\n        var asub = b as ArrowType;\n        return asub != null && asuper.Arity == asub.Arity;\n      } else if (a is UserDefinedType) {\n        var udtA = (UserDefinedType)a;\n        if (udtA.ResolvedClass != null) {\n          while (true) {\n            var udtB = b as UserDefinedType;\n            if (udtB == null) {\n              return false;\n            } else if (udtA.ResolvedClass != udtB.ResolvedClass) {\n              return false;\n            } else {\n              Contract.Assert(udtA.TypeArgs.Count == udtB.TypeArgs.Count);\n              for (int i = 0; i < udtA.TypeArgs.Count; i++) {\n                if (!Equal_Improved(udtA.TypeArgs[i], udtB.TypeArgs[i])) {\n                  return false;\n                }\n              }\n              return true;\n            }\n          }\n        } else {\n          Contract.Assert(udtA.ResolvedParam != null);\n          Contract.Assert(udtA.TypeArgs.Count == 0);\n          return udtA.ResolvedParam == b.AsTypeParameter;\n        }\n      } else if (a is Resolver_IdentifierExpr.ResolverType_Module) {\n        return b is Resolver_IdentifierExpr.ResolverType_Module;\n      } else if (a is Resolver_IdentifierExpr.ResolverType_Type) {\n        return b is Resolver_IdentifierExpr.ResolverType_Type;\n      } else {\n        Contract.Assert(false);  // unexpected kind of type\n        return true;  // to please the compiler\n      }\n    }\n\n    public static Type HeadWithProxyArgs(Type t) {\n      Contract.Requires(t != null);\n      Contract.Requires(!(t is TypeProxy));\n      if (t.TypeArgs.Count == 0) {\n        return t;\n      } else if (t is SetType) {\n        var s = (SetType)t;\n        return new SetType(s.Finite, new InferredTypeProxy());\n      } else if (t is MultiSetType) {\n        return new MultiSetType(new InferredTypeProxy());\n      } else if (t is SeqType) {\n        return new SeqType(new InferredTypeProxy());\n      } else if (t is MapType) {\n        var s = (MapType)t;\n        return new MapType(s.Finite, new InferredTypeProxy(), new InferredTypeProxy());\n      } else if (t is ArrowType) {\n        var s = (ArrowType)t;\n        var args = s.TypeArgs.ConvertAll(_ => (Type)new InferredTypeProxy());\n        return new ArrowType(s.tok, (ArrowTypeDecl)s.ResolvedClass, args);\n      } else if (t is PointerType) {\n        return new PointerType(new InferredTypeProxy());\n      } else if (t is SizedArrayType) {\n        var s = (SizedArrayType)t;\n        return new SizedArrayType(new InferredTypeProxy(), s.Size);\n      } else {\n        var s = (UserDefinedType)t;\n        var args = s.TypeArgs.ConvertAll(_ => (Type)new InferredTypeProxy());\n        return new UserDefinedType(s.tok, s.Name, s.ResolvedClass, args);\n      }\n    }\n\n    /// <summary>\n    /// Returns a stack of base types leading to \"type\".  More precisely, of the tower returned,\n    ///     tower[0] == type.NormalizeExpand()\n    ///     tower.Last == type.NormalizeExpandKeepConstraints()\n    /// In between, for consecutive indices i and i+1:\n    ///     tower[i] is the base type (that is, .Rhs) of the subset type tower[i+1]\n    /// The tower thus has the property that:\n    ///     tower[0] is not a UserDefinedType with .ResolvedClass being a SubsetTypeDecl,\n    ///     but all other tower[i] (for i > 0) are.\n    /// </summary>\n    public static List<Type> GetTowerOfSubsetTypes(Type type) {\n      Contract.Requires(type != null);\n      type = type.NormalizeExpandKeepConstraints();\n      List<Type> tower;\n      var udt = type as UserDefinedType;\n      if (udt != null && udt.ResolvedClass is SubsetTypeDecl) {\n        var sst = (SubsetTypeDecl)udt.ResolvedClass;\n        var parent = sst.RhsWithArgument(udt.TypeArgs);\n        tower = GetTowerOfSubsetTypes(parent);\n      } else {\n        tower = new List<Type>();\n      }\n      tower.Add(type);\n      return tower;\n    }\n\n    /// <summary>\n    /// For each i, computes some combination of a[i] and b[i], according to direction[i].\n    /// For a negative direction (Contra), computes Meet(a[i], b[i]), provided this meet exists.\n    /// For a zero direction (Inv), uses a[i], provided a[i] and b[i] are equal.\n    /// For a positive direction (Co), computes Join(a[i], b[i]), provided this join exists.\n    /// Returns null if any operation fails.\n    /// </summary>\n    public static List<Type> ComputeExtrema(List<TypeParameter.TPVariance> directions, List<Type> a, List<Type> b, BuiltIns builtIns) {\n      Contract.Requires(directions != null);\n      Contract.Requires(a != null);\n      Contract.Requires(b != null);\n      Contract.Requires(directions.Count == a.Count);\n      Contract.Requires(directions.Count == b.Count);\n      Contract.Requires(builtIns != null);\n      var n = directions.Count;\n      var r = new List<Type>(n);\n      for (int i = 0; i < n; i++) {\n        if (a[i].Normalize() is TypeProxy) {\n          r.Add(b[i]);\n        } else if (b[i].Normalize() is TypeProxy) {\n          r.Add(a[i]);\n        } else if (directions[i] == TypeParameter.TPVariance.Non) {\n          if (a[i].Equals(b[i])) {\n            r.Add(a[i]);\n          } else {\n            return null;\n          }\n        } else {\n          var t = directions[i] == TypeParameter.TPVariance.Contra ? Meet(a[i], b[i], builtIns) : Join(a[i], b[i], builtIns);\n          if (t == null) {\n            return null;\n          }\n          r.Add(t);\n        }\n      }\n      return r;\n    }\n\n    /// <summary>\n    /// Does a best-effort to compute the meet of \"a\" and \"b\", returning \"null\" if not successful.\n    /// </summary>\n    public static Type Meet(Type a, Type b, BuiltIns builtIns) {\n      Contract.Requires(a != null);\n      Contract.Requires(b != null);\n      Contract.Requires(builtIns != null);\n      var j = MeetX(a, b, builtIns);\n      if (ArmadaOptions.O.TypeInferenceDebug) {\n        Console.WriteLine(\"DEBUG: Meet( {0}, {1} ) = {2}\", a, b, j);\n      }\n      return j;\n    }\n    public static Type MeetX(Type a, Type b, BuiltIns builtIns) {\n      Contract.Requires(a != null);\n      Contract.Requires(b != null);\n      Contract.Requires(builtIns != null);\n\n      // Before we do anything else, make a note of whether or not both \"a\" and \"b\" are non-null types.\n      var abNonNullTypes = a.IsNonNullRefType && b.IsNonNullRefType;\n\n      var towerA = GetTowerOfSubsetTypes(a);\n      var towerB = GetTowerOfSubsetTypes(b);\n      for (var n = Math.Min(towerA.Count, towerB.Count); 1 <= --n; ) {\n        a = towerA[n];\n        b = towerB[n];\n        var udtA = (UserDefinedType)a;\n        var udtB = (UserDefinedType)b;\n        if (udtA.ResolvedClass == udtB.ResolvedClass) {\n          // We have two subset types with equal heads\n          if (a.Equals(b)) {  // optimization for a special case, which applies for example when there are no arguments or when the types happen to be the same\n            return a;\n          }\n          Contract.Assert(a.TypeArgs.Count == b.TypeArgs.Count);\n          var directions = udtA.ResolvedClass.TypeArgs.ConvertAll(tp => TypeParameter.Negate(tp.Variance));\n          var typeArgs = ComputeExtrema(directions, a.TypeArgs, b.TypeArgs, builtIns);\n          if (typeArgs == null) {\n            return null;\n          }\n          return new UserDefinedType(udtA.tok, udtA.Name, udtA.ResolvedClass, typeArgs);\n        }\n      }\n      // We exhausted all possibilities of subset types being equal, so use the base-most types.\n      a = towerA[0];\n      b = towerB[0];\n\n      if (a is IntVarietiesSupertype) {\n        return b is IntVarietiesSupertype || b.IsNumericBased(NumericPersuation.Int) || b.IsBigOrdinalType || b.IsBitVectorType ? b : null;\n      } else if (b is IntVarietiesSupertype) {\n        return a.IsNumericBased(NumericPersuation.Int) || a.IsBigOrdinalType || a.IsBitVectorType ? a : null;\n      } else if (a.IsBoolType || a.IsCharType || a.IsBitVectorType || a.IsBigOrdinalType || a.IsTypeParameter || a.IsInternalTypeSynonym || a is TypeProxy) {\n        return a.Equals(b) ? a : null;\n      } else if (a is RealVarietiesSupertype) {\n        return b is RealVarietiesSupertype || b.IsNumericBased(NumericPersuation.Real) ? b : null;\n      } else if (b is RealVarietiesSupertype) {\n        return a.IsNumericBased(NumericPersuation.Real) ? a : null;\n      } else if (a.IsNumericBased()) {\n        // Note, for meet, we choose not to step down to IntVarietiesSupertype or RealVarietiesSupertype\n        return a.Equals(b) ? a : null;\n      } else if (a is SetType) {\n        var aa = (SetType)a;\n        var bb = b as SetType;\n        if (bb == null || aa.Finite != bb.Finite) {\n          return null;\n        }\n        // sets are co-variant in their argument type\n        var typeArg = Meet(a.TypeArgs[0], b.TypeArgs[0], builtIns);\n        return typeArg == null ? null : new SetType(aa.Finite, typeArg);\n      } else if (a is MultiSetType) {\n        var aa = (MultiSetType)a;\n        var bb = b as MultiSetType;\n        if (bb == null) {\n          return null;\n        }\n        // multisets are co-variant in their argument type\n        var typeArg = Meet(a.TypeArgs[0], b.TypeArgs[0], builtIns);\n        return typeArg == null ? null : new MultiSetType(typeArg);\n      } else if (a is SeqType) {\n        var aa = (SeqType)a;\n        var bb = b as SeqType;\n        if (bb == null) {\n          return null;\n        }\n        // sequences are co-variant in their argument type\n        var typeArg = Meet(a.TypeArgs[0], b.TypeArgs[0], builtIns);\n        return typeArg == null ? null : new SeqType(typeArg);\n      } else if (a is MapType) {\n        var aa = (MapType)a;\n        var bb = b as MapType;\n        if (bb == null || aa.Finite != bb.Finite) {\n          return null;\n        }\n        // maps are co-variant in both argument types\n        var typeArgDomain = Meet(a.TypeArgs[0], b.TypeArgs[0], builtIns);\n        var typeArgRange = Meet(a.TypeArgs[1], b.TypeArgs[1], builtIns);\n        return typeArgDomain == null || typeArgRange == null ? null : new MapType(aa.Finite, typeArgDomain, typeArgRange);\n      } else if (a.IsDatatype) {\n        var aa = a.AsDatatype;\n        if (aa != b.AsDatatype) {\n          return null;\n        }\n        if (a.Equals(b)) {  // optimization for a special case, which applies for example when there are no arguments or when the types happen to be the same\n          return a;\n        }\n        Contract.Assert(a.TypeArgs.Count == b.TypeArgs.Count);\n        var directions = aa.TypeArgs.ConvertAll(tp => TypeParameter.Negate(tp.Variance));\n        var typeArgs = ComputeExtrema(directions, a.TypeArgs, b.TypeArgs, builtIns);\n        if (typeArgs == null) {\n          return null;\n        }\n        var udt = (UserDefinedType)a;\n        return new UserDefinedType(udt.tok, udt.Name, aa, typeArgs);\n      } else if (a.AsArrowType != null) {\n        var aa = a.AsArrowType;\n        var bb = b.AsArrowType;\n        if (bb == null || aa.Arity != bb.Arity) {\n          return null;\n        }\n        int arity = aa.Arity;\n        Contract.Assert(a.TypeArgs.Count == arity + 1);\n        Contract.Assert(b.TypeArgs.Count == arity + 1);\n        Contract.Assert(((ArrowType)a).ResolvedClass == ((ArrowType)b).ResolvedClass);\n        var directions = new List<TypeParameter.TPVariance>();\n        for (int i = 0; i < arity; i++) {\n          directions.Add(TypeParameter.Negate(TypeParameter.TPVariance.Contra));  // arrow types are contra-variant in the argument types, so compute joins of these\n        }\n        directions.Add(TypeParameter.Negate(TypeParameter.TPVariance.Co));  // arrow types are co-variant in the result type, so compute the meet of these\n        var typeArgs = ComputeExtrema(directions, a.TypeArgs, b.TypeArgs, builtIns);\n        if (typeArgs == null) {\n          return null;\n        }\n        var arr = (ArrowType)aa;\n        return new ArrowType(arr.tok, (ArrowTypeDecl)arr.ResolvedClass, typeArgs);\n      } else if (b.IsObjectQ) {\n        var udtB = (UserDefinedType)b;\n        return !a.IsRefType ? null : abNonNullTypes ? UserDefinedType.CreateNonNullType(udtB) : udtB;\n      } else if (a.IsObjectQ) {\n        var udtA = (UserDefinedType)a;\n        return !b.IsRefType ? null : abNonNullTypes ? UserDefinedType.CreateNonNullType(udtA) : udtA;\n      } else {\n        // \"a\" is a class, trait, or opaque type\n        var aa = ((UserDefinedType)a).ResolvedClass;\n        Contract.Assert(aa != null);\n        if (!(b is UserDefinedType)) {\n          return null;\n        }\n        var bb = ((UserDefinedType)b).ResolvedClass;\n        if (a.Equals(b)) {  // optimization for a special case, which applies for example when there are no arguments or when the types happen to be the same\n          return a;\n        } else if (aa == bb) {\n          Contract.Assert(a.TypeArgs.Count == b.TypeArgs.Count);\n          var directions = aa.TypeArgs.ConvertAll(tp => TypeParameter.Negate(tp.Variance));\n          var typeArgs = ComputeExtrema(directions, a.TypeArgs, b.TypeArgs, builtIns);\n          if (typeArgs == null) {\n            return null;\n          }\n          var udt = (UserDefinedType)a;\n          var xx = new UserDefinedType(udt.tok, udt.Name, aa, typeArgs);\n          return abNonNullTypes ? UserDefinedType.CreateNonNullType(xx) : xx;\n        } else if (aa is ClassDecl && bb is ClassDecl) {\n          var A = (ClassDecl)aa;\n          var B = (ClassDecl)bb;\n          // Here are the assumptions about the type system that the rest of this code depends on:\n          Contract.Assert(!(A is TraitDecl) || (A.TypeArgs.Count == 0 && ((TraitDecl)A).TraitsTyp.Count == 0));\n          Contract.Assert(!(B is TraitDecl) || (B.TypeArgs.Count == 0 && ((TraitDecl)B).TraitsTyp.Count == 0));\n          if (A.DerivesFrom(B)) {\n            var udtB = (UserDefinedType)b;\n            return abNonNullTypes ? UserDefinedType.CreateNonNullType(udtB) : udtB;\n          } else if (B.DerivesFrom(A)) {\n            var udtA = (UserDefinedType)a;\n            return abNonNullTypes ? UserDefinedType.CreateNonNullType(udtA) : udtA;\n          } else if (A is TraitDecl || B is TraitDecl) {\n            return abNonNullTypes ? UserDefinedType.CreateNonNullType(builtIns.ObjectQ()) : builtIns.ObjectQ();\n          }\n          // A and B are classes. They always have object as a common supertype, but they may also both be extending some other\n          // trait.  If such a trait is unique, pick it. (Unfortunately, this makes the meet operation not associative.)\n          var commonTraits = new List<Type>();\n          foreach (var at in A.TraitsTyp) {\n            if (B.TraitsTyp.Exists(bt => at.Equals(bt))) {\n              commonTraits.Add(at);\n            }\n          }\n          if (commonTraits.Count == 1) {\n            var udtTrait = (UserDefinedType)commonTraits[0];  // in a successfully resolved program, we expect all .TraitsTyp to be a UserDefinedType\n            Contract.Assert(udtTrait.ResolvedClass is NonNullTypeDecl);  // in fact, we expect it to be the non-null version of the trait type\n            return abNonNullTypes ? udtTrait : udtTrait.NormalizeExpand();\n          } else {\n            // the unfortunate part is when commonTraits.Count > 1 here :(\n            return abNonNullTypes ? UserDefinedType.CreateNonNullType(builtIns.ObjectQ()) : builtIns.ObjectQ();\n          }\n        } else {\n          return null;\n        }\n      }\n    }\n\n    /// <summary>\n    /// Does a best-effort to compute the join of \"a\" and \"b\", returning \"null\" if not successful.\n    /// </summary>\n    public static Type Join(Type a, Type b, BuiltIns builtIns) {\n      Contract.Requires(a != null);\n      Contract.Requires(b != null);\n      Contract.Requires(builtIns != null);\n      a = a.NormalizeExpandKeepConstraints();\n      b = b.NormalizeExpandKeepConstraints();\n\n      var joinNeedsNonNullConstraint = false;\n      Type j;\n      if (a is UserDefinedType && ((UserDefinedType)a).ResolvedClass is NonNullTypeDecl) {\n        joinNeedsNonNullConstraint = true;\n        var nnt = (NonNullTypeDecl)((UserDefinedType)a).ResolvedClass;\n        j = JoinX(nnt.RhsWithArgument(a.TypeArgs), b, builtIns);\n      } else if (b is UserDefinedType && ((UserDefinedType)b).ResolvedClass is NonNullTypeDecl) {\n        joinNeedsNonNullConstraint = true;\n        var nnt = (NonNullTypeDecl)((UserDefinedType)b).ResolvedClass;\n        j = JoinX(a, nnt.RhsWithArgument(b.TypeArgs), builtIns);\n      } else {\n        j = JoinX(a, b, builtIns);\n      }\n      if (j != null && joinNeedsNonNullConstraint && !j.IsNonNullRefType) {\n        // try to make j into a non-null type; if that's not possible, then there is no join\n        var udt = j as UserDefinedType;\n        if (udt != null && udt.ResolvedClass is ClassDecl) {\n          // add the non-null constraint back in\n          j = UserDefinedType.CreateNonNullType(udt);\n        } else {\n          // the original a and b have no join\n          j = null;\n        }\n      }\n      if (ArmadaOptions.O.TypeInferenceDebug) {\n        Console.WriteLine(\"DEBUG: Join( {0}, {1} ) = {2}\", a, b, j);\n      }\n      return j;\n    }\n    public static Type JoinX(Type a, Type b, BuiltIns builtIns) {\n      Contract.Requires(a != null);\n      Contract.Requires(b != null);\n      Contract.Requires(builtIns != null);\n\n      var towerA = GetTowerOfSubsetTypes(a);\n      var towerB = GetTowerOfSubsetTypes(b);\n      if (towerB.Count < towerA.Count) {\n      // make A be the shorter tower\n        var tmp0 = a; a = b; b = tmp0;\n        var tmp1 = towerA; towerA = towerB; towerB = tmp1;\n      }\n      var n = towerA.Count;\n      Contract.Assert(1 <= n);  // guaranteed by GetTowerOfSubsetTypes\n      if (towerA.Count < towerB.Count) {\n        // B is strictly taller. The join exists only if towerA[n-1] is a supertype of towerB[n-1], and\n        // then the join is \"b\".\n        return Type.IsSupertype(towerA[n - 1], towerB[n - 1]) ? b : null;\n      }\n      Contract.Assert(towerA.Count == towerB.Count);\n      a = towerA[n - 1];\n      b = towerB[n - 1];\n      if (2 <= n) {\n        var udtA = (UserDefinedType)a;\n        var udtB = (UserDefinedType)b;\n        if (udtA.ResolvedClass == udtB.ResolvedClass) {\n          // We have two subset types with equal heads\n          if (a.Equals(b)) {  // optimization for a special case, which applies for example when there are no arguments or when the types happen to be the same\n            return a;\n          }\n          Contract.Assert(a.TypeArgs.Count == b.TypeArgs.Count);\n          var directions = udtA.ResolvedClass.TypeArgs.ConvertAll(tp => tp.Variance);\n          var typeArgs = ComputeExtrema(directions, a.TypeArgs, b.TypeArgs, builtIns);\n          if (typeArgs == null) {\n            return null;\n          }\n          return new UserDefinedType(udtA.tok, udtA.Name, udtA.ResolvedClass, typeArgs);\n        } else {\n          // The two subset types do not have the same head, so there is no join\n          return null;\n        }\n      }\n      Contract.Assert(towerA.Count == 1 && towerB.Count == 1);\n\n      if (a is IntVarietiesSupertype) {\n        return b is IntVarietiesSupertype || b.IsNumericBased(NumericPersuation.Int) || b.IsBigOrdinalType || b.IsBitVectorType ? b : null;\n      } else if (b is IntVarietiesSupertype) {\n        return a.IsNumericBased(NumericPersuation.Int) || a.IsBigOrdinalType || a.IsBitVectorType ? a : null;\n      } else if (a.IsBoolType || a.IsCharType || a.IsBigOrdinalType || a.IsTypeParameter || a.IsInternalTypeSynonym || a is TypeProxy) {\n        return a.Equals(b) ? a : null;\n      } else if (a is RealVarietiesSupertype) {\n        return b is RealVarietiesSupertype || b.IsNumericBased(NumericPersuation.Real) ? b : null;\n      } else if (b is RealVarietiesSupertype) {\n        return a.IsNumericBased(NumericPersuation.Real) ? a : null;\n      } else if (a.IsNumericBased()) {\n        return a.Equals(b) ? a : null;\n      } else if (a is SetType) {\n        var aa = (SetType)a;\n        var bb = b as SetType;\n        if (bb == null || aa.Finite != bb.Finite) {\n          return null;\n        }\n        // sets are co-variant in their argument type\n        var typeArg = Join(a.TypeArgs[0], b.TypeArgs[0], builtIns);\n        return typeArg == null ? null : new SetType(aa.Finite, typeArg);\n      } else if (a is MultiSetType) {\n        var aa = (MultiSetType)a;\n        var bb = b as MultiSetType;\n        if (bb == null) {\n          return null;\n        }\n        // multisets are co-variant in their argument type\n        var typeArg = Join(a.TypeArgs[0], b.TypeArgs[0], builtIns);\n        return typeArg == null ? null : new MultiSetType(typeArg);\n      } else if (a is SeqType) {\n        var aa = (SeqType)a;\n        var bb = b as SeqType;\n        if (bb == null) {\n          return null;\n        }\n        // sequences are co-variant in their argument type\n        var typeArg = Join(a.TypeArgs[0], b.TypeArgs[0], builtIns);\n        return typeArg == null ? null : new SeqType(typeArg);\n      } else if (a is MapType) {\n        var aa = (MapType)a;\n        var bb = b as MapType;\n        if (bb == null || aa.Finite != bb.Finite) {\n          return null;\n        }\n        // maps are co-variant in both argument types\n        var typeArgDomain = Join(a.TypeArgs[0], b.TypeArgs[0], builtIns);\n        var typeArgRange = Join(a.TypeArgs[1], b.TypeArgs[1], builtIns);\n        return typeArgDomain == null || typeArgRange == null ? null : new MapType(aa.Finite, typeArgDomain, typeArgRange);\n      } else if (a.IsDatatype) {\n        var aa = a.AsDatatype;\n        if (aa != b.AsDatatype) {\n          return null;\n        }\n        if (a.Equals(b)) {  // optimization for a special case, which applies for example when there are no arguments or when the types happen to be the same\n          return a;\n        }\n        Contract.Assert(a.TypeArgs.Count == b.TypeArgs.Count);\n        var directions = aa.TypeArgs.ConvertAll(tp => tp.Variance);\n        var typeArgs = ComputeExtrema(directions, a.TypeArgs, b.TypeArgs, builtIns);\n        if (typeArgs == null) {\n          return null;\n        }\n        var udt = (UserDefinedType)a;\n        return new UserDefinedType(udt.tok, udt.Name, aa, typeArgs);\n      } else if (a.AsArrowType != null) {\n        var aa = a.AsArrowType;\n        var bb = b.AsArrowType;\n        if (bb == null || aa.Arity != bb.Arity) {\n          return null;\n        }\n        int arity = aa.Arity;\n        Contract.Assert(a.TypeArgs.Count == arity + 1);\n        Contract.Assert(b.TypeArgs.Count == arity + 1);\n        Contract.Assert(((ArrowType)a).ResolvedClass == ((ArrowType)b).ResolvedClass);\n        var directions = new List<TypeParameter.TPVariance>();\n        for (int i = 0; i < arity; i++) {\n          directions.Add(TypeParameter.TPVariance.Contra);  // arrow types are contra-variant in the argument types, so compute meets of these\n        }\n        directions.Add(TypeParameter.TPVariance.Co);  // arrow types are co-variant in the result type, so compute the join of these\n        var typeArgs = ComputeExtrema(directions, a.TypeArgs, b.TypeArgs, builtIns);\n        if (typeArgs == null) {\n          return null;\n        }\n        var arr = (ArrowType)aa;\n        return new ArrowType(arr.tok, (ArrowTypeDecl)arr.ResolvedClass, typeArgs);\n      } else if (b.IsObjectQ) {\n        return a.IsRefType ? a : null;\n      } else if (a.IsObjectQ) {\n        return b.IsRefType ? b : null;\n      } else {\n        // \"a\" is a class, trait, or opaque type\n        var aa = ((UserDefinedType)a).ResolvedClass;\n        Contract.Assert(aa != null);\n        if (!(b is UserDefinedType)) {\n          return null;\n        }\n        var bb = ((UserDefinedType)b).ResolvedClass;\n        if (a.Equals(b)) {  // optimization for a special case, which applies for example when there are no arguments or when the types happen to be the same\n          return a;\n        } else if (aa == bb) {\n          Contract.Assert(a.TypeArgs.Count == b.TypeArgs.Count);\n          var directions = aa.TypeArgs.ConvertAll(tp => tp.Variance);\n          var typeArgs = ComputeExtrema(directions, a.TypeArgs, b.TypeArgs, builtIns);\n          if (typeArgs == null) {\n            return null;\n          }\n          var udt = (UserDefinedType)a;\n          return new UserDefinedType(udt.tok, udt.Name, aa, typeArgs);\n        } else if (aa is ClassDecl && bb is ClassDecl) {\n          var A = (ClassDecl)aa;\n          var B = (ClassDecl)bb;\n          if (A.DerivesFrom(B)) {\n            Contract.Assert(B is TraitDecl && b.TypeArgs.Count == 0);\n            return a;\n          } else if (B.DerivesFrom(A)) {\n            Contract.Assert(A is TraitDecl && a.TypeArgs.Count == 0);\n            return b;\n          } else {\n            return null;\n          }\n        } else {\n          return null;\n        }\n      }\n    }\n\n    public void ForeachTypeComponent(Action<Type> action) {\n      action(this);\n      TypeArgs.ForEach(x => x.ForeachTypeComponent(action));\n    }\n\n    public bool ContainsProxy(TypeProxy proxy) {\n      Contract.Requires(proxy != null && proxy.T == null);\n      if (this == proxy) {\n        return true;\n      } else {\n        return TypeArgs.Exists(t => t.ContainsProxy(proxy));\n      }\n    }\n  }\n\n  /// <summary>\n  /// An ArtificialType is only used during type checking. It should never be assigned as the type of any expression.\n  /// </summary>\n  public abstract class ArtificialType : Type\n  {\n  }\n  /// <summary>\n  /// The type \"IntVarietiesSupertype\" is used to denote a decimal-less number type, namely an int-based type\n  /// or a bitvector type.\n  /// </summary>\n  public class IntVarietiesSupertype : ArtificialType\n  {\n    [Pure]\n    public override string TypeName(ModuleDefinition context, bool parseAble) {\n      return \"int\";\n    }\n    public override bool Equals(Type that) {\n      return that is IntVarietiesSupertype;\n    }\n  }\n  public class RealVarietiesSupertype : ArtificialType\n  {\n    [Pure]\n    public override string TypeName(ModuleDefinition context, bool parseAble) {\n      return \"real\";\n    }\n    public override bool Equals(Type that) {\n      return that is RealVarietiesSupertype;\n    }\n  }\n\n  /// <summary>\n  /// A NonProxy type is a fully constrained type.  It may contain members.\n  /// </summary>\n  public abstract class NonProxyType : Type\n  {\n  }\n\n  public abstract class BasicType : NonProxyType\n  {\n  }\n\n  public class BoolType : BasicType {\n    [Pure]\n    public override string TypeName(ModuleDefinition context, bool parseAble) {\n      return \"bool\";\n    }\n    public override bool Equals(Type that) {\n      return that.IsBoolType;\n    }\n  }\n\n  public class CharType : BasicType\n  {\n    [Pure]\n    public override string TypeName(ModuleDefinition context, bool parseAble) {\n      return \"char\";\n    }\n    public override bool Equals(Type that) {\n      return that.IsCharType;\n    }\n  }\n\n  public class IntType : BasicType\n  {\n    [Pure]\n    public override string TypeName(ModuleDefinition context, bool parseAble) {\n      return \"int\";\n    }\n    public override bool Equals(Type that) {\n      return that.IsIntegerType;\n    }\n  }\n\n  public class RealType : BasicType {\n    [Pure]\n    public override string TypeName(ModuleDefinition context, bool parseAble) {\n      return \"real\";\n    }\n    public override bool Equals(Type that) {\n      return that.IsRealType;\n    }\n  }\n\n  public class BigOrdinalType : BasicType\n  {\n    [Pure]\n    public override string TypeName(ModuleDefinition context, bool parseAble) {\n      return \"ORDINAL\";\n    }\n    public override bool Equals(Type that) {\n      return that.IsBigOrdinalType;\n    }\n  }\n\n  public class BitvectorType : BasicType\n  {\n    public readonly int Width;\n    public readonly NativeType NativeType;\n    public BitvectorType(int width)\n      : base() {\n      Contract.Requires(0 <= width);\n      Width = width;\n      foreach (var nativeType in Resolver.NativeTypes) {\n        if ((nativeType.CompilationTargets & ArmadaOptions.O.CompileTarget) != 0 && width <= nativeType.Bitwidth) {\n          NativeType = nativeType;\n          break;\n        }\n      }\n    }\n\n    [Pure]\n    public override string TypeName(ModuleDefinition context, bool parseAble) {\n      return \"bv\" + Width;\n    }\n    public override bool Equals(Type that) {\n      var bv = that.NormalizeExpand() as BitvectorType;\n      return bv != null && bv.Width == Width;\n    }\n  }\n\n  public class SelfType : NonProxyType\n  {\n    public TypeParameter TypeArg;\n    public Type ResolvedType;\n    public SelfType() : base() {\n      TypeArg = new TypeParameter(Token.NoToken, \"selfType\", TypeParameter.TPVarianceSyntax.NonVariant_Strict);\n    }\n\n    [Pure]\n    public override string TypeName(ModuleDefinition context, bool parseAble) {\n      return \"selftype\";\n    }\n    public override bool Equals(Type that) {\n      return that.NormalizeExpand() is SelfType;\n    }\n  }\n\n  public class ArrowType : UserDefinedType\n  {\n    public List<Type> Args {\n      get { return TypeArgs.GetRange(0, Arity); }\n    }\n\n    public Type Result {\n      get { return TypeArgs[Arity]; }\n    }\n\n    public int Arity {\n      get { return TypeArgs.Count - 1; }\n    }\n\n    /// <summary>\n    /// Constructs a(n unresolved) arrow type.\n    /// </summary>\n    public ArrowType(IToken tok, List<Type> args, Type result)\n      :  base(tok, ArrowTypeName(args.Count), Util.Snoc(args, result)) {\n      Contract.Requires(tok != null);\n      Contract.Requires(args != null);\n      Contract.Requires(result != null);\n    }\n    /// <summary>\n    /// Constructs and returns a resolved arrow type.\n    /// </summary>\n    public ArrowType(IToken tok, ArrowTypeDecl atd, List<Type> typeArgsAndResult)\n      : base(tok, ArrowTypeName(atd.Arity), atd, typeArgsAndResult) {\n      Contract.Requires(tok != null);\n      Contract.Requires(atd != null);\n      Contract.Requires(typeArgsAndResult != null);\n      Contract.Requires(typeArgsAndResult.Count == atd.Arity + 1);\n    }\n    /// <summary>\n    /// Constructs and returns a resolved arrow type.\n    /// </summary>\n    public ArrowType(IToken tok, ArrowTypeDecl atd, List<Type> typeArgs, Type result)\n      : this(tok, atd, Util.Snoc(typeArgs, result)) {\n      Contract.Requires(tok != null);\n      Contract.Requires(atd != null);\n      Contract.Requires(typeArgs!= null);\n      Contract.Requires(typeArgs.Count == atd.Arity);\n      Contract.Requires(result != null);\n    }\n\n    public const string Arrow_FullCompileName = \"Func\";  // this is the same for all arities\n\n    public static string ArrowTypeName(int arity) {\n      return \"_#Func\" + arity;\n    }\n\n    [Pure]\n    public static bool IsArrowTypeName(string s) {\n      return s.StartsWith(\"_#Func\");\n    }\n\n    public static string PartialArrowTypeName(int arity) {\n      return \"_#PartialFunc\" + arity;\n    }\n\n    [Pure]\n    public static bool IsPartialArrowTypeName(string s) {\n      return s.StartsWith(\"_#PartialFunc\");\n    }\n\n    public static string TotalArrowTypeName(int arity) {\n      return \"_#TotalFunc\" + arity;\n    }\n\n    [Pure]\n    public static bool IsTotalArrowTypeName(string s) {\n      return s.StartsWith(\"_#TotalFunc\");\n    }\n\n    public const string ANY_ARROW = \"~>\";\n    public const string PARTIAL_ARROW = \"-->\";\n    public const string TOTAL_ARROW = \"->\";\n\n    public override string TypeName(ModuleDefinition context, bool parseAble) {\n      return PrettyArrowTypeName(ANY_ARROW, Args, Result, context, parseAble);\n    }\n\n    /// <summary>\n    /// Pretty prints an arrow type.  If \"result\" is null, then all arguments, including the result type are expected in \"typeArgs\".\n    /// If \"result\" is non-null, then only the in-arguments are in \"typeArgs\".\n    /// </summary>\n    public static string PrettyArrowTypeName(string arrow, List<Type> typeArgs, Type result, ModuleDefinition context, bool parseAble) {\n      Contract.Requires(arrow != null);\n      Contract.Requires(typeArgs != null);\n      Contract.Requires(result != null || 1 <= typeArgs.Count);\n\n      int arity = result == null ? typeArgs.Count - 1 : typeArgs.Count;\n      var domainNeedsParens = false;\n      if (arity != 1) {\n        // 0 or 2-or-more arguments:  need parentheses\n        domainNeedsParens = true;\n      } else if (typeArgs[0].IsBuiltinArrowType) {\n        // arrows are right associative, so we need parentheses around the domain type\n        domainNeedsParens = true;\n      } else {\n        // if the domain type consists of a single tuple type, then an extra set of parentheses is needed\n        // Note, we do NOT call .AsDatatype or .AsIndDatatype here, because those calls will do a NormalizeExpand().  Instead, we do the check manually.\n        var udt = typeArgs[0].Normalize() as UserDefinedType;  // note, we do Normalize(), not NormalizeExpand(), since the TypeName will use any synonym\n        if (udt != null && udt.ResolvedClass is TupleTypeDecl) {\n          domainNeedsParens = true;\n        }\n      }\n      string s = \"\";\n      if (domainNeedsParens) { s += \"(\"; }\n      s += Util.Comma(\", \", typeArgs.Take(arity), arg => arg.TypeName(context, parseAble));\n      if (domainNeedsParens) { s += \")\"; }\n      s += \" \" + arrow + \" \";\n      s += (result ?? typeArgs.Last()).TypeName(context, parseAble);\n      return s;\n    }\n\n    public override bool SupportsEquality {\n      get {\n        return false;\n      }\n    }\n  }\n\n  public abstract class CollectionType : NonProxyType\n  {\n    public abstract string CollectionTypeName { get; }\n    public override string TypeName(ModuleDefinition context, bool parseAble) {\n      Contract.Ensures(Contract.Result<string>() != null);\n      var targs = HasTypeArg() ? this.TypeArgsToString(context, parseAble) : \"\";\n      return CollectionTypeName + targs;\n    }\n    public Type Arg {\n      get {\n        Contract.Ensures(Contract.Result<Type>() != null);  // this is true only after \"arg\" has really been set (i.e., it follows from the precondition)\n        Contract.Assume(arg != null);  // This is really a precondition.  Don't call Arg until \"arg\" has been set.\n        return arg;\n      }\n    }  // denotes the Domain type for a Map\n    private Type arg;\n    // The following methods, HasTypeArg and SetTypeArg/SetTypeArgs, are to be called during resolution to make sure that \"arg\" becomes set.\n    public bool HasTypeArg() {\n      return arg != null;\n    }\n    public void SetTypeArg(Type arg) {\n      Contract.Requires(arg != null);\n      Contract.Requires(1 <= this.TypeArgs.Count);  // this is actually an invariant of all collection types\n      Contract.Assume(this.arg == null);  // Can only set it once.  This is really a precondition.\n      this.arg = arg;\n      this.TypeArgs[0] = arg;\n    }\n    public virtual void SetTypeArgs(Type arg, Type other) {\n      Contract.Requires(arg != null);\n      Contract.Requires(other != null);\n      Contract.Requires(this.TypeArgs.Count == 2);\n      Contract.Assume(this.arg == null);  // Can only set it once.  This is really a precondition.\n      this.arg = arg;\n      this.TypeArgs[0] = arg;\n      this.TypeArgs[1] = other;\n    }\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      // Contract.Invariant(Contract.ForAll(TypeArgs, tp => tp != null));\n      // After resolution, the following is invariant:  Contract.Invariant(Arg != null);\n      // However, it may not be true until then.\n    }\n    /// <summary>\n    /// This constructor is a collection types with 1 type argument\n    /// </summary>\n    protected CollectionType(Type arg) {\n      this.arg = arg;\n      this.TypeArgs = new List<Type> { arg };\n    }\n    /// <summary>\n    /// This constructor is a collection types with 2 type arguments\n    /// </summary>\n    protected CollectionType(Type arg, Type other) {\n      this.arg = arg;\n      this.TypeArgs = new List<Type> { arg, other };\n    }\n\n    public override bool MayInvolveReferences {\n      get {\n        return Arg.MayInvolveReferences;\n      }\n    }\n  }\n\n  public class SetType : CollectionType {\n    private bool finite;\n\n    public bool Finite {\n      get { return finite; }\n      set { finite = value; }\n    }\n\n    public SetType(bool finite, Type arg) : base(arg) {\n      this.finite = finite;\n    }\n    public override string CollectionTypeName { get { return finite ? \"set\" : \"iset\"; } }\n    [Pure]\n    public override bool Equals(Type that) {\n      var t = that.NormalizeExpand() as SetType;\n      return t != null && Finite == t.Finite && Arg.Equals(t.Arg);\n    }\n    public override bool SupportsEquality {\n      get {\n        // Sets always support equality, because there is a check that the set element type always does.\n        return true;\n      }\n    }\n  }\n\n  public class MultiSetType : CollectionType\n  {\n    public MultiSetType(Type arg) : base(arg) {\n    }\n    public override string CollectionTypeName { get { return \"multiset\"; } }\n    public override bool Equals(Type that) {\n      var t = that.NormalizeExpand() as MultiSetType;\n      return t != null && Arg.Equals(t.Arg);\n    }\n    public override bool SupportsEquality {\n      get {\n        // Multisets always support equality, because there is a check that the set element type always does.\n        return true;\n      }\n    }\n  }\n\n  public class SeqType : CollectionType {\n    public SeqType(Type arg) : base(arg) {\n    }\n    public override string CollectionTypeName { get { return \"seq\"; } }\n    public override bool Equals(Type that) {\n      var t = that.NormalizeExpand() as SeqType;\n      return t != null && Arg.Equals(t.Arg);\n    }\n    public override bool SupportsEquality {\n      get {\n        // The sequence type supports equality if its element type does\n        return Arg.SupportsEquality;\n      }\n    }\n  }\n  public class MapType : CollectionType\n  {\n    public bool Finite {\n      get { return finite; }\n      set { finite = value; }\n    }\n    private bool finite;\n    public Type Range {\n      get { return range; }\n    }\n    private Type range;\n    public override void SetTypeArgs(Type domain, Type range) {\n      base.SetTypeArgs(domain, range);\n      Contract.Assume(this.range == null);  // Can only set once.  This is really a precondition.\n      this.range = range;\n    }\n    public MapType(bool finite, Type domain, Type range) : base(domain, range) {\n      Contract.Requires((domain == null && range == null) || (domain != null && range != null));\n      this.finite = finite;\n      this.range = range;\n    }\n    public Type Domain {\n      get { return Arg; }\n    }\n    public override string CollectionTypeName { get { return finite ? \"map\" : \"imap\"; } }\n    [Pure]\n    public override string TypeName(ModuleDefinition context, bool parseAble) {\n      Contract.Ensures(Contract.Result<string>() != null);\n      var targs = HasTypeArg() ? this.TypeArgsToString(context, parseAble) : \"\";\n      return CollectionTypeName + targs;\n    }\n    public override bool Equals(Type that) {\n      var t = that.NormalizeExpand() as MapType;\n      return t != null && Finite == t.Finite && Arg.Equals(t.Arg) && Range.Equals(t.Range);\n    }\n    public override bool SupportsEquality {\n      get {\n        // A map type supports equality if both its Keys type and Values type does.  It is checked\n        // that the Keys type always supports equality, so we only need to check the Values type here.\n        return range.SupportsEquality;\n      }\n    }\n    public override bool MayInvolveReferences {\n      get {\n        return Domain.MayInvolveReferences || Range.MayInvolveReferences;\n      }\n    }\n  }\n\n  public class SizedArrayType : CollectionType {\n    public Type Range {\n      get { return range; }\n    }\n    private Type range;\n\n    public Expression Size {\n      get { return sz; }\n    }\n    private Expression sz;\n\n    public SizedArrayType(Type i_range, Expression i_sz) : base(i_range) {\n      range = i_range;\n      sz = i_sz;\n    }\n\n    public override string CollectionTypeName {\n      get\n      {\n        return (sz is LiteralExpr) ? $\"array (size {((LiteralExpr)sz).Value})\" : \"sized array\";\n      }\n    }\n\n    [Pure]\n    public override string TypeName(ModuleDefinition context, bool parseAble) {\n      Contract.Ensures(Contract.Result<string>() != null);\n      if (sz is LiteralExpr le) {\n        return $\"{Range.TypeName(context, parseAble)}[{le.Value}]\";\n      }\n      else {\n        return $\"{Range.TypeName(context, parseAble)}[]\";\n      }\n    }\n\n    private bool SizeEquals(SizedArrayType that) {\n      if (that == null) {\n        return false;\n      }\n      if (Size is LiteralExpr && that.Size is LiteralExpr) {\n        var s1 = (LiteralExpr)Size;\n        var s2 = (LiteralExpr)that.Size;\n        return s1.Value.Equals(s2.Value);\n      }\n      return Size.Equals(that.Size);\n    }\n\n    public override bool Equals(Type that) {\n      var t = that.NormalizeExpand() as SizedArrayType;\n      return t != null && SizeEquals(t) && Range.Equals(t.Range);\n    }\n    public override bool SupportsEquality {\n      get {\n        // A static array type supports equality if its range type does.\n        return range.SupportsEquality;\n      }\n    }\n    public override bool MayInvolveReferences {\n      get {\n        return Range.MayInvolveReferences;\n      }\n    }\n  }\n\n  public class PointerType : CollectionType\n  {\n    public PointerType(Type arg) : base(arg) {\n    }\n    public override string TypeName(ModuleDefinition context, bool parseAble) {\n      return $\"ptr<{Arg.TypeName(context, parseAble)}>\";\n    }\n    public override string CollectionTypeName { get { return \"ptr\"; } }\n    public override bool Equals(Type that) {\n      var t = that.NormalizeExpand() as PointerType;\n      return t != null && Arg.Equals(t.Arg);\n    }\n    public override bool SupportsEquality {\n      get {\n        return true;\n      }\n    }\n  }\n\n  public class UserDefinedType : NonProxyType\n  {\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(tok != null);\n      Contract.Invariant(Name != null);\n      Contract.Invariant(cce.NonNullElements(TypeArgs));\n      Contract.Invariant(NamePath is NameSegment || NamePath is ExprDotName);\n      Contract.Invariant(!ArrowType.IsArrowTypeName(Name) || this is ArrowType);\n    }\n\n    public readonly Expression NamePath;  // either NameSegment or ExprDotName (with the inner expression satisfying this same constraint)\n    public readonly IToken tok;  // token of the Name\n    public readonly string Name;\n    [Rep]\n\n    public string FullName {\n      get {\n        if (ResolvedClass != null && !ResolvedClass.Module.IsDefaultModule) {\n          return ResolvedClass.Module.Name + \".\" + Name;\n        } else {\n          return Name;\n        }\n      }\n    }\n\n    string compileName;\n    public string CompileName {\n      get {\n        if (compileName == null) {\n          compileName = NonglobalVariable.CompilerizeName(Name);\n        }\n        return compileName;\n      }\n    }\n    public virtual string FullCompileName {\n      get {\n        if (ResolvedClass == null) {\n          return CompileName;\n        } else if (ResolvedClass.Module.IsDefaultModule) {\n          return ResolvedClass.CompileName;\n        } else {\n          return ResolvedClass.Module.CompileName + \".@\" + ResolvedClass.CompileName;\n        }\n      }\n    }\n    public string FullCompanionCompileName {\n      get {\n        Contract.Requires(ResolvedClass is TraitDecl);\n        var m = ResolvedClass.Module;\n        var s = m.IsDefaultModule ? \"\" : m.CompileName + \".\";\n        return s + \"_Companion_\" + ResolvedClass.CompileName;\n      }\n    }\n\n    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\n    public TypeParameter ResolvedParam;  // filled in by resolution, if Name denotes an enclosing type parameter and TypeArgs is the empty list\n\n    public UserDefinedType(IToken tok, string name, List<Type> optTypeArgs)\n      : this(tok, new NameSegment(tok, name, optTypeArgs))\n    {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Contract.Requires(optTypeArgs == null || optTypeArgs.Count > 0);  // this is what it means to be syntactically optional\n    }\n\n    public UserDefinedType(IToken tok, Expression namePath) {\n      Contract.Requires(tok != null);\n      Contract.Requires(namePath is NameSegment || namePath is ExprDotName);\n      this.tok = tok;\n      if (namePath is NameSegment) {\n        var n = (NameSegment)namePath;\n        this.Name = n.Name;\n        this.TypeArgs = n.OptTypeArguments;\n      } else {\n        var n = (ExprDotName)namePath;\n        this.Name = n.SuffixName;\n        this.TypeArgs = n.OptTypeArguments;\n      }\n      if (this.TypeArgs == null) {\n        this.TypeArgs = new List<Type>();  // TODO: is this really the thing to do?\n      }\n      this.NamePath = namePath;\n    }\n\n    /// <summary>\n    /// Constructs a Type (in particular, a UserDefinedType) from a TopLevelDecl denoting a type declaration.  If\n    /// the given declaration takes type parameters, these are filled as references to the formal type parameters\n    /// themselves.  (Usually, this method is called when the type parameters in the result don't matter, other\n    /// than that they need to be filled in, so as to make a properly resolved UserDefinedType.)\n    /// If \"typeArgs\" is non-null, then its type parameters are used in constructing the returned type.\n    /// If \"typeArgs\" is null, then the formal type parameters of \"cd\" are used.\n    /// </summary>\n    public static UserDefinedType FromTopLevelDecl(IToken tok, TopLevelDecl cd, List<TypeParameter> typeArgs = null) {\n      Contract.Requires(tok != null);\n      Contract.Requires(cd != null);\n      Contract.Assert((cd is ArrowTypeDecl) == ArrowType.IsArrowTypeName(cd.Name));\n      var args = (typeArgs ?? cd.TypeArgs).ConvertAll(tp => (Type)new UserDefinedType(tp));\n      if (cd is ArrowTypeDecl) {\n        return new ArrowType(tok, (ArrowTypeDecl)cd, args);\n      } else if (cd is ClassDecl && !(cd is DefaultClassDecl)) {\n        return new UserDefinedType(tok, cd.Name + \"?\", cd, args);\n      } else {\n        return new UserDefinedType(tok, cd.Name, cd, args);\n      }\n    }\n\n    /// <summary>\n    /// This constructor constructs a resolved class/datatype/iterator/subset-type/newtype type\n    /// </summary>\n    public UserDefinedType(IToken tok, string name, TopLevelDecl cd, [Captured] List<Type> typeArgs) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Contract.Requires(cd != null);\n      Contract.Requires(cce.NonNullElements(typeArgs));\n      Contract.Requires(cd.TypeArgs.Count == typeArgs.Count);\n      // The following is almost a precondition. In a few places, the source program names a class, not a type,\n      // and in then name==cd.Name for a ClassDecl.\n      //Contract.Requires(!(cd is ClassDecl) || cd is DefaultClassDecl || cd is ArrowTypeDecl || name == cd.Name + \"?\");\n      Contract.Requires(!(cd is ArrowTypeDecl) || name == cd.Name);\n      Contract.Requires(!(cd is DefaultClassDecl) || name == cd.Name);\n      this.tok = tok;\n      this.Name = name;\n      this.ResolvedClass = cd;\n      this.TypeArgs = typeArgs;\n      var ns = new NameSegment(tok, name, typeArgs.Count == 0 ? null : typeArgs);\n      var r = new Resolver_IdentifierExpr(tok, cd, typeArgs);\n      ns.ResolvedExpression = r;\n      ns.Type = r.Type;\n      this.NamePath = ns;\n    }\n\n    public static UserDefinedType CreateNonNullType(UserDefinedType udtNullableType) {\n      Contract.Requires(udtNullableType != null);\n      Contract.Requires(udtNullableType.ResolvedClass is ClassDecl);\n      var cl = (ClassDecl)udtNullableType.ResolvedClass;\n      return new UserDefinedType(udtNullableType.tok, cl.NonNullTypeDecl.Name, cl.NonNullTypeDecl, udtNullableType.TypeArgs);\n    }\n\n    /// <summary>\n    /// This constructor constructs a resolved type parameter\n    /// </summary>\n    public UserDefinedType(TypeParameter tp)\n      : this(tp.tok, tp) {\n      Contract.Requires(tp != null);\n    }\n\n    /// <summary>\n    /// This constructor constructs a resolved type parameter (but shouldn't be called if \"tp\" denotes\n    /// the .TheType of an opaque type -- use the (OpaqueType_AsParameter, OpaqueTypeDecl, List(Type))\n    /// constructor for that).\n    /// </summary>\n    public UserDefinedType(IToken tok, TypeParameter tp) {\n      Contract.Requires(tok != null);\n      Contract.Requires(tp != null);\n      Contract.Requires(!(tp is OpaqueType_AsParameter));\n      this.tok = tok;\n      this.Name = tp.Name;\n      this.TypeArgs = new List<Type>();\n      this.ResolvedParam = tp;\n      var ns = new NameSegment(tok, tp.Name, null);\n      var r = new Resolver_IdentifierExpr(tok, tp);\n      ns.ResolvedExpression = r;\n      ns.Type = r.Type;\n      this.NamePath = ns;\n    }\n\n    /// <summary>\n    /// Constructs a resolved type for an opaque type.\n    /// </summary>\n    public UserDefinedType(OpaqueType_AsParameter tp, OpaqueTypeDecl decl, List<Type> typeArgs) {\n      Contract.Requires(tp != null);\n      Contract.Requires(decl != null && decl.TheType == tp);\n      Contract.Requires(typeArgs != null);\n      this.tok = tp.tok;\n      this.Name = tp.Name;\n      this.ResolvedParam = tp;\n      this.ResolvedClass = decl;\n      this.TypeArgs = typeArgs;\n      var ns = new NameSegment(tok, tp.Name, null);\n      var r = new Resolver_IdentifierExpr(tok, tp);\n      ns.ResolvedExpression = r;\n      ns.Type = r.Type;\n      this.NamePath = ns;\n    }\n\n    public override bool Equals(Type that) {\n      var i = NormalizeExpand();\n      if (i is UserDefinedType) {\n        var ii = (UserDefinedType)i;\n        var t = that.NormalizeExpand() as UserDefinedType;\n        if (t == null || ii.ResolvedParam != t.ResolvedParam || ii.ResolvedClass != t.ResolvedClass || ii.TypeArgs.Count != t.TypeArgs.Count) {\n          return false;\n        } else {\n          for (int j = 0; j < ii.TypeArgs.Count; j++) {\n            if (!ii.TypeArgs[j].Equals(t.TypeArgs[j])) {\n              return false;\n            }\n          }\n          return true;\n        }\n      } else {\n        return i.Equals(that);\n      }\n    }\n\n    /// <summary>\n    /// If type denotes a resolved class type, then return that class type.\n    /// Otherwise, return null.\n    /// </summary>\n    public static UserDefinedType DenotesClass(Type type) {\n      Contract.Requires(type != null);\n      Contract.Ensures(Contract.Result<UserDefinedType>() == null || Contract.Result<UserDefinedType>().ResolvedClass is ClassDecl);\n      type = type.NormalizeExpand();\n      UserDefinedType ct = type as UserDefinedType;\n      if (ct != null && ct.ResolvedClass is ClassDecl) {\n        return ct;\n      } else {\n        return null;\n      }\n    }\n\n    public static Type ArrayElementType(Type type) {\n      Contract.Requires(type.IsArrayType);\n\n      Contract.Requires(type != null);\n      Contract.Ensures(Contract.Result<Type>() != null);\n\n      UserDefinedType udt = DenotesClass(type);\n      Contract.Assert(udt != null);\n      Contract.Assert(udt.TypeArgs.Count == 1);  // holds true of all array types\n      return udt.TypeArgs[0];\n    }\n\n    [Pure]\n    public override string TypeName(ModuleDefinition context, bool parseAble) {\n      Contract.Ensures(Contract.Result<string>() != null);\n      if (BuiltIns.IsTupleTypeName(Name)) {\n        return \"(\" + Util.Comma(\", \", TypeArgs, ty => ty.TypeName(context, parseAble)) + \")\";\n      } else if (ArrowType.IsPartialArrowTypeName(Name)) {\n        return ArrowType.PrettyArrowTypeName(ArrowType.PARTIAL_ARROW, TypeArgs, null, context, parseAble);\n      } else if (ArrowType.IsTotalArrowTypeName(Name)) {\n        return ArrowType.PrettyArrowTypeName(ArrowType.TOTAL_ARROW, TypeArgs, null, context, parseAble);\n      } else {\n#if TEST_TYPE_SYNONYM_TRANSPARENCY\n        if (Name == \"type#synonym#transparency#test\" && ResolvedClass is TypeSynonymDecl) {\n          return ((TypeSynonymDecl)ResolvedClass).Rhs.TypeName(context);\n        }\n#endif\n        var s = Printer.ExprToString(NamePath);\n        if (ResolvedClass != null) {\n          var optionalTypeArgs = NamePath is NameSegment ? ((NameSegment)NamePath).OptTypeArguments : ((ExprDotName)NamePath).OptTypeArguments;\n          if (optionalTypeArgs == null && TypeArgs != null && TypeArgs.Count != 0) {\n            s += this.TypeArgsToString(context, parseAble);\n          }\n        }\n        return s;\n      }\n    }\n\n    public override bool SupportsEquality {\n      get {\n        if (ResolvedClass is ClassDecl || ResolvedClass is NewtypeDecl) {\n          return ResolvedClass.IsRevealedInScope(Type.GetScope());\n        } else if (ResolvedClass is CoDatatypeDecl) {\n          return false;\n        } else if (ResolvedClass is IndDatatypeDecl) {\n          var dt = (IndDatatypeDecl)ResolvedClass;\n          Contract.Assume(dt.EqualitySupport != IndDatatypeDecl.ES.NotYetComputed);\n          if (!dt.IsRevealedInScope(Type.GetScope())) {\n            return false;\n          }\n          if (dt.EqualitySupport == IndDatatypeDecl.ES.Never) {\n            return false;\n          }\n          Contract.Assert(dt.TypeArgs.Count == TypeArgs.Count);\n          var i = 0;\n          foreach (var tp in dt.TypeArgs) {\n            if (tp.NecessaryForEqualitySupportOfSurroundingInductiveDatatype && !TypeArgs[i].SupportsEquality) {\n              return false;\n            }\n            i++;\n          }\n          return true;\n        } else if (ResolvedClass is TypeSynonymDeclBase) {\n          var t = (TypeSynonymDeclBase)ResolvedClass;\n          if (t.MustSupportEquality) {\n            return true;\n          } else if (t.IsRevealedInScope(Type.GetScope())) {\n            return t.RhsWithArgument(TypeArgs).SupportsEquality;\n          } else {\n            return false;\n          }\n        } else if (ResolvedParam != null) {\n          return ResolvedParam.MustSupportEquality;\n        }\n        Contract.Assume(false);  // the SupportsEquality getter requires the Type to have been successfully resolved\n        return true;\n      }\n    }\n\n    public override bool MayInvolveReferences {\n      get {\n        if (ResolvedClass is ClassDecl) {\n          return true;\n        } else if (ResolvedClass is NewtypeDecl) {\n          return false;\n        } else if (ResolvedClass is DatatypeDecl) {\n          var dt = (DatatypeDecl)ResolvedClass;\n          if (!dt.IsRevealedInScope(Type.GetScope())) {\n            return true;\n          }\n          Contract.Assert(dt.TypeArgs.Count == TypeArgs.Count);\n          return TypeArgs.TrueForAll(ta => ta.MayInvolveReferences);\n        } else if (ResolvedClass is TypeSynonymDeclBase) {\n          var t = (TypeSynonymDeclBase)ResolvedClass;\n          // (Note, if type parameters/opaque types could have a may-involve-references characteristic, then it would be consulted here)\n          if (t.IsRevealedInScope(Type.GetScope())) {\n            return t.RhsWithArgument(TypeArgs).MayInvolveReferences;\n          } else {\n            return true;\n          }\n        } else if (ResolvedParam != null) {\n          // (Note, if type parameters/opaque types could have a may-involve-references characteristic, then it would be consulted here)\n          return true;\n        }\n        Contract.Assume(false);  // the MayInvolveReferences getter requires the Type to have been successfully resolved\n        return true;\n      }\n    }\n  }\n\n  public abstract class TypeProxy : Type {\n    public Type T;  // filled in during resolution\n    public readonly List<Resolver.TypeConstraint> SupertypeConstraints = new List<Resolver.TypeConstraint>();\n    public readonly List<Resolver.TypeConstraint> SubtypeConstraints = new List<Resolver.TypeConstraint>();\n    public IEnumerable<Type> Supertypes {\n      get {\n        foreach (var c in SupertypeConstraints) {\n          if (c.KeepConstraints) {\n            yield return c.Super.NormalizeExpandKeepConstraints();\n          } else {\n            yield return c.Super.NormalizeExpand();\n          }\n        }\n      }\n    }\n    public IEnumerable<Type> SupertypesKeepConstraints {\n      get {\n        foreach (var c in SupertypeConstraints) {\n          yield return c.Super.NormalizeExpandKeepConstraints();\n        }\n      }\n    }\n    public void AddSupertype(Resolver.TypeConstraint c) {\n      Contract.Requires(c != null);\n      Contract.Requires(c.Sub == this);\n      SupertypeConstraints.Add(c);\n    }\n    public IEnumerable<Type> Subtypes {\n      get {\n        foreach (var c in SubtypeConstraints) {\n          if (c.KeepConstraints) {\n            yield return c.Sub.NormalizeExpandKeepConstraints();\n          } else {\n            yield return c.Sub.NormalizeExpand();\n          }\n        }\n      }\n    }\n\n    public IEnumerable<Type> SubtypesKeepConstraints {\n      get {\n        foreach (var c in SubtypeConstraints) {\n          yield return c.Sub.NormalizeExpandKeepConstraints();\n        }\n      }\n    }\n\n    public IEnumerable<Type> SubtypesKeepConstraints_WithAssignable(List<Resolver.XConstraint> allXConstraints) {\n      Contract.Requires(allXConstraints != null);\n      foreach (var c in SubtypeConstraints) {\n        yield return c.Sub.NormalizeExpandKeepConstraints();\n      }\n      foreach (var xc in allXConstraints) {\n        if (xc.ConstraintName == \"Assignable\") {\n          if (xc.Types[0].Normalize() == this) {\n            yield return xc.Types[1].NormalizeExpandKeepConstraints();\n          }\n        }\n      }\n    }\n\n    public void AddSubtype(Resolver.TypeConstraint c) {\n      Contract.Requires(c != null);\n      Contract.Requires(c.Super == this);\n      SubtypeConstraints.Add(c);\n    }\n\n    public enum Family { Unknown, Bool, Char, IntLike, RealLike, Ordinal, BitVector, ValueType, Ref, Opaque }\n    public Family family = Family.Unknown;\n    public static Family GetFamily(Type t) {\n      Contract.Ensures(Contract.Result<Family>() != Family.Unknown || t is TypeProxy || t is Resolver_IdentifierExpr.ResolverType);  // return Unknown ==> t is TypeProxy || t is ResolverType\n      if (t.IsBoolType) {\n        return Family.Bool;\n      } else if (t.IsCharType) {\n        return Family.Char;\n      } else if (t.IsNumericBased(NumericPersuation.Int) || t is IntVarietiesSupertype) {\n        return Family.IntLike;\n      } else if (t.IsNumericBased(NumericPersuation.Real) || t is RealVarietiesSupertype) {\n        return Family.RealLike;\n      } else if (t.IsBigOrdinalType) {\n        return Family.Ordinal;\n      } else if (t.IsBitVectorType) {\n        return Family.BitVector;\n      } else if (t.AsCollectionType != null || t.AsArrowType != null || t.IsDatatype) {\n        return Family.ValueType;\n      } else if (t.IsRefType) {\n        return Family.Ref;\n      } else if (t.IsTypeParameter || t.IsOpaqueType || t.IsInternalTypeSynonym) {\n        return Family.Opaque;\n      } else if (t is TypeProxy) {\n        return ((TypeProxy)t).family;\n      } else {\n        return Family.Unknown;\n      }\n    }\n\n    internal TypeProxy() {\n    }\n\n#if TI_DEBUG_PRINT\n    static int _id = 0;\n    int id = _id++;\n#endif\n    [Pure]\n    public override string TypeName(ModuleDefinition context, bool parseAble) {\n      Contract.Ensures(Contract.Result<string>() != null);\n#if TI_DEBUG_PRINT\n      if (ArmadaOptions.O.TypeInferenceDebug) {\n        return T == null ? \"?\" + id : T.TypeName(context);\n      }\n#endif\n      return T == null ? \"?\" : T.TypeName(context, parseAble);\n    }\n    public override bool SupportsEquality {\n      get {\n        if (T != null) {\n          return T.SupportsEquality;\n        } else {\n          return base.SupportsEquality;\n        }\n      }\n    }\n    public override bool MayInvolveReferences {\n      get {\n        if (T != null) {\n          return T.MayInvolveReferences;\n        } else {\n          return true;\n        }\n      }\n    }\n    public override bool Equals(Type that) {\n      var i = NormalizeExpand();\n      if (i is TypeProxy) {\n        var u = that.NormalizeExpand() as TypeProxy;\n        return u != null && object.ReferenceEquals(i, u);\n      } else {\n        return i.Equals(that);\n      }\n    }\n\n    [Pure]\n    internal static bool IsSupertypeOfLiteral(Type t) {\n      Contract.Requires(t != null);\n      return t is ArtificialType;\n    }\n    internal Type InClusterOfArtificial(List<Resolver.XConstraint> allXConstraints) {\n      Contract.Requires(allXConstraints != null);\n      return InClusterOfArtificial_aux(new HashSet<TypeProxy>(), allXConstraints);\n    }\n    private Type InClusterOfArtificial_aux(ISet<TypeProxy> visitedProxies, List<Resolver.XConstraint> allXConstraints) {\n      Contract.Requires(visitedProxies != null);\n      Contract.Requires(allXConstraints != null);\n      if (visitedProxies.Contains(this)) {\n        return null;\n      }\n      visitedProxies.Add(this);\n      foreach (var c in SupertypeConstraints) {\n        var sup = c.Super.Normalize();\n        if (sup is IntVarietiesSupertype) {\n          return Type.Int;\n        } else if (sup is RealVarietiesSupertype) {\n          return Type.Real;\n        } else if (sup is TypeProxy) {\n          var a = ((TypeProxy)sup).InClusterOfArtificial_aux(visitedProxies, allXConstraints);\n          if (a != null) {\n            return a;\n          }\n        }\n      }\n      foreach (var su in SubtypesKeepConstraints_WithAssignable(allXConstraints)) {\n        var pr = su as TypeProxy;\n        if (pr != null) {\n          var a = pr.InClusterOfArtificial_aux(visitedProxies, allXConstraints);\n          if (a != null) {\n            return a;\n          }\n        }\n      }\n      return null;\n    }\n  }\n\n  /// <summary>\n  /// This proxy stands for any type.\n  /// </summary>\n  public class InferredTypeProxy : TypeProxy {\n    public bool KeepConstraints;\n    public InferredTypeProxy() : base() {\n      KeepConstraints = false; // whether the typeProxy should be inferred to base type or as subset type\n    }\n  }\n\n  /// <summary>\n  /// This proxy stands for any type, but it originates from an instantiated type parameter.\n  /// </summary>\n  public class ParamTypeProxy : TypeProxy {\n    public TypeParameter orig;\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(orig != null);\n    }\n\n    public ParamTypeProxy(TypeParameter orig) {\n      Contract.Requires(orig != null);\n      this.orig = orig;\n    }\n  }\n\n  // ------------------------------------------------------------------------------------------------------\n\n  /// <summary>\n  /// This interface is used by the Dafny IDE.\n  /// </summary>\n  public interface INamedRegion\n  {\n    IToken BodyStartTok { get; }\n    IToken BodyEndTok { get; }\n    string Name { get; }\n  }\n\n  public abstract class Declaration : INamedRegion, IAttributeBearingDeclaration\n  {\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(tok != null);\n      Contract.Invariant(Name != null);\n    }\n\n    public static string IdProtect(string name) {\n      switch (ArmadaOptions.O.CompileTarget) {\n        case ArmadaOptions.CompilationTarget.Clight:\n          return ClightTsoCompiler.PublicIdProtect(name);\n        default:\n          Contract.Assert(false);  // unexpected compile target\n          return name;\n      }\n    }\n\n    public IToken tok;\n    public IToken BodyStartTok = Token.NoToken;\n    public IToken BodyEndTok = Token.NoToken;\n    public readonly string Name;\n    IToken INamedRegion.BodyStartTok { get { return BodyStartTok; } }\n    IToken INamedRegion.BodyEndTok { get { return BodyEndTok; } }\n    string INamedRegion.Name { get { return Name; } }\n    string compileName;\n\n    private VisibilityScope opaqueScope = new VisibilityScope();\n    private VisibilityScope revealScope = new VisibilityScope();\n\n    private bool scopeIsInherited = false;\n\n    public virtual bool CanBeExported() {\n      return true;\n    }\n\n    public virtual bool CanBeRevealed() {\n      return false;\n    }\n\n    public bool ScopeIsInherited { get { return scopeIsInherited; } }\n\n    public void AddVisibilityScope(VisibilityScope scope, bool IsOpaque) {\n      Contract.Requires(!ScopeIsInherited); //pragmatically we should only augment the visibility of the parent\n\n      if (IsOpaque) {\n        opaqueScope.Augment(scope);\n      } else {\n        revealScope.Augment(scope);\n      }\n    }\n\n\n    public void InheritVisibility(Declaration d, bool onlyRevealed = true) {\n      Contract.Assert(opaqueScope.IsEmpty());\n      Contract.Assert(revealScope.IsEmpty());\n      scopeIsInherited = false;\n\n      revealScope = d.revealScope;\n\n      if (!onlyRevealed) {\n        opaqueScope = d.opaqueScope;\n      }\n      scopeIsInherited = true;\n\n    }\n\n    public bool IsRevealedInScope(VisibilityScope scope) {\n      return revealScope.VisibleInScope(scope);\n    }\n\n    public bool IsVisibleInScope(VisibilityScope scope) {\n      return IsRevealedInScope(scope) || opaqueScope.VisibleInScope(scope);\n    }\n\n    public virtual string CompileName {\n      get {\n        if (compileName == null) {\n          string qual;\n          IsExtern(out qual, out compileName);\n          if (compileName == null) {\n            // this is the usual name\n            compileName = NonglobalVariable.CompilerizeName(Name);\n          }\n        }\n        return compileName;\n      }\n    }\n    public bool IsExtern(out string/*?*/ qualification, out string/*?*/ name) {\n      // ensures result==false ==> qualification == null && name == null\n      Contract.Ensures(Contract.Result<bool>() || (Contract.ValueAtReturn(out qualification) == null && Contract.ValueAtReturn(out name) == null));\n      // ensures result==true ==> qualification != null ==> name != null\n      Contract.Ensures(!Contract.Result<bool>() || Contract.ValueAtReturn(out qualification) == null || Contract.ValueAtReturn(out name) != null);\n\n      qualification = null;\n      name = null;\n      if (!ArmadaOptions.O.DisallowExterns) {\n        var externArgs = Attributes.FindExpressions(this.Attributes, \"extern\");\n        if (externArgs != null) {\n          if (externArgs.Count == 0) {\n            return true;\n          } else if (externArgs.Count == 1 && externArgs[0] is StringLiteralExpr) {\n            name = externArgs[0].AsStringLiteral();\n            return true;\n          } else if (externArgs.Count == 2 && externArgs[0] is StringLiteralExpr && externArgs[1] is StringLiteralExpr) {\n            qualification = externArgs[0].AsStringLiteral();\n            name = externArgs[1].AsStringLiteral();\n            return true;\n          }\n        }\n      }\n      return false;\n    }\n    public Attributes Attributes;  // readonly, except during class merging in the refinement transformations and when changed by Compiler.MarkCapitalizationConflict\n\n    public Declaration(IToken tok, string name, Attributes attributes) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      this.tok = tok;\n      this.Name = name;\n      this.Attributes = attributes;\n    }\n\n    [Pure]\n    public override string ToString() {\n      Contract.Ensures(Contract.Result<string>() != null);\n      return Name;\n    }\n\n    internal FreshIdGenerator IdGenerator = new FreshIdGenerator();\n  }\n\n  public class OpaqueType_AsParameter : TypeParameter {\n    public readonly List<TypeParameter> TypeArgs;\n    public OpaqueType_AsParameter(IToken tok, string name, TypeParameterCharacteristics characteristics, List<TypeParameter> typeArgs)\n      : base(tok, name, TypeParameter.TPVarianceSyntax.NonVariant_Strict, characteristics) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Contract.Requires(typeArgs != null);\n      TypeArgs = typeArgs;\n    }\n  }\n\n  public class TypeParameter : Declaration {\n    public interface ParentType {\n      string FullName {\n        get;\n      }\n    }\n    [Peer]\n    ParentType parent;\n    public ParentType Parent {\n      get {\n        return parent;\n      }\n      [param: Captured]\n      set {\n        Contract.Requires(Parent == null);  // set it only once\n        Contract.Requires(value != null);\n        parent = value;\n      }\n    }\n\n    /// <summary>\n    /// NonVariant_Strict     (default) - non-variant, no uses left of an arrow\n    /// NonVariant_Permissive    !      - non-variant\n    /// Covariant_Strict         +      - co-variant, no uses left of an arrow\n    /// Covariant_Permissive     *      - co-variant\n    /// Contravarianct           -       - contra-variant\n    /// </summary>\n    public enum TPVarianceSyntax { NonVariant_Strict, NonVariant_Permissive, Covariant_Strict, Covariant_Permissive, Contravariance }\n    public enum TPVariance { Co, Non, Contra }\n    public static TPVariance Negate(TPVariance v) {\n      switch (v) {\n        case TPVariance.Co:\n          return TPVariance.Contra;\n        case TPVariance.Contra:\n          return TPVariance.Co;\n        default:\n          return v;\n      }\n    }\n    public TPVarianceSyntax VarianceSyntax;\n    public TPVariance Variance {\n      get {\n        switch (VarianceSyntax) {\n          case TPVarianceSyntax.Covariant_Strict:\n          case TPVarianceSyntax.Covariant_Permissive:\n            return TPVariance.Co;\n          case TPVarianceSyntax.NonVariant_Strict:\n          case TPVarianceSyntax.NonVariant_Permissive:\n            return TPVariance.Non;\n          case TPVarianceSyntax.Contravariance:\n            return TPVariance.Contra;\n          default:\n            Contract.Assert(false);  // unexpected VarianceSyntax\n            throw new cce.UnreachableException();\n        }\n      }\n    }\n    public bool StrictVariance {\n      get {\n        switch (VarianceSyntax) {\n          case TPVarianceSyntax.Covariant_Strict:\n          case TPVarianceSyntax.NonVariant_Strict:\n            return true;\n          case TPVarianceSyntax.Covariant_Permissive:\n          case TPVarianceSyntax.NonVariant_Permissive:\n          case TPVarianceSyntax.Contravariance:\n            return false;\n          default:\n            Contract.Assert(false);  // unexpected VarianceSyntax\n            throw new cce.UnreachableException();\n        }\n      }\n    }\n\n    public enum EqualitySupportValue { Required, InferredRequired, Unspecified }\n    public struct TypeParameterCharacteristics\n    {\n      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)\n      public bool MustSupportZeroInitialization;\n      public bool DisallowReferenceTypes;\n      public TypeParameterCharacteristics(bool dummy) {\n        EqualitySupport = EqualitySupportValue.Unspecified;\n        MustSupportZeroInitialization = false;\n        DisallowReferenceTypes = false;\n      }\n      public TypeParameterCharacteristics(EqualitySupportValue eqSupport, bool mustSupportZeroInitialization, bool disallowReferenceTypes) {\n        EqualitySupport = eqSupport;\n        MustSupportZeroInitialization = mustSupportZeroInitialization;\n        DisallowReferenceTypes = disallowReferenceTypes;\n      }\n    }\n    public TypeParameterCharacteristics Characteristics;\n    public bool MustSupportEquality {\n      get { return Characteristics.EqualitySupport != EqualitySupportValue.Unspecified; }\n    }\n\n    public bool NecessaryForEqualitySupportOfSurroundingInductiveDatatype = false;  // computed during resolution; relevant only when Parent denotes an IndDatatypeDecl\n\n    public bool IsAbstractTypeDeclaration { // true if this type parameter represents t in type t;\n      get { return parent == null; }\n    }\n    public bool IsToplevelScope { // true if this type parameter is on a toplevel (ie. class C<T>), and false if it is on a member (ie. method m<T>(...))\n      get { return parent is TopLevelDecl; }\n    }\n    public int PositionalIndex; // which type parameter this is (ie. in C<S, T, U>, S is 0, T is 1 and U is 2).\n\n    public TypeParameter(IToken tok, string name, TPVarianceSyntax varianceS, TypeParameterCharacteristics characteristics)\n      : base(tok, name, null) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Characteristics = characteristics;\n      VarianceSyntax = varianceS;\n    }\n\n    public TypeParameter(IToken tok, string name, TPVarianceSyntax varianceS)\n      : this(tok, name, varianceS, new TypeParameterCharacteristics(false)) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n    }\n\n    public TypeParameter(IToken tok, string name, int positionalIndex, ParentType parent)\n       : this(tok, name, TPVarianceSyntax.NonVariant_Strict)\n    {\n      PositionalIndex = positionalIndex;\n      Parent = parent;\n    }\n\n    public string FullName() {\n      // when debugging, print it all:\n      return /* Parent.FullName + \".\" + */ Name;\n    }\n\n    public static TypeParameterCharacteristics GetExplicitCharacteristics(TopLevelDecl d) {\n      Contract.Requires(d != null);\n      TypeParameterCharacteristics characteristics = new TypeParameterCharacteristics(false);\n      if (d is OpaqueTypeDecl) {\n        var dd = (OpaqueTypeDecl)d;\n        characteristics = dd.Characteristics;\n      } else if (d is TypeSynonymDecl) {\n        var dd = (TypeSynonymDecl)d;\n        characteristics = dd.Characteristics;\n      }\n      if (characteristics.EqualitySupport == EqualitySupportValue.InferredRequired) {\n        return new TypeParameterCharacteristics(EqualitySupportValue.Unspecified, characteristics.MustSupportZeroInitialization, characteristics.DisallowReferenceTypes);\n      } else {\n        return characteristics;\n      }\n    }\n  }\n\n  // Represents a submodule declaration at module level scope\n  abstract public class ModuleDecl : TopLevelDecl\n  {\n    public override string WhatKind { get { return \"module\"; } }\n    public ModuleSignature Signature; // filled in by resolution, in topological order.\n    public virtual ModuleSignature AccessibleSignature(bool ignoreExports) {\n      Contract.Requires(Signature != null);\n      return Signature;\n    }\n    public virtual ModuleSignature AccessibleSignature() {\n      Contract.Requires(Signature != null);\n      return Signature;\n    }\n    public int Height;\n\n    public readonly bool Opened;\n\n    public ModuleDecl(IToken tok, string name, ModuleDefinition parent, bool opened)\n      : base(tok, name, parent, new List<TypeParameter>(), null) {\n        Height = -1;\n      Signature = null;\n      Opened = opened;\n    }\n    public abstract object Dereference();\n\n    public int? ResolvedHash { get; set; }\n  }\n  // Represents module X { ... }\n  public class LiteralModuleDecl : ModuleDecl\n  {\n    public readonly ModuleDefinition ModuleDef;\n    public ModuleSignature DefaultExport;  // the default export set of the module. fill in by the resolver.\n\n    private ModuleSignature emptySignature;\n    public override ModuleSignature AccessibleSignature(bool ignoreExports) {\n      if (ignoreExports) {\n        return Signature;\n      }\n      return this.AccessibleSignature();\n    }\n    public override ModuleSignature AccessibleSignature() {\n      if (DefaultExport == null) {\n        if (emptySignature == null) {\n          emptySignature = new ModuleSignature();\n        }\n        return emptySignature;\n      }\n      return DefaultExport;\n    }\n\n    public LiteralModuleDecl(ModuleDefinition module, ModuleDefinition parent)\n      : base(module.tok, module.Name, parent, false) {\n      ModuleDef = module;\n    }\n    public override object Dereference() { return ModuleDef; }\n  }\n  // Represents \"module name = path;\", where name is an identifier and path is a possibly qualified name.\n  public class AliasModuleDecl : ModuleDecl\n  {\n    public readonly List<IToken> Path; // generated by the parser, this is looked up\n    public readonly List<IToken> Exports; // list of exports sets\n    public ModuleDecl Root; // the moduleDecl that Path[0] refers to.\n\n    public AliasModuleDecl(List<IToken> path, IToken name, ModuleDefinition parent, bool opened, List<IToken> exports)\n      : base(name, name.val, parent, opened) {\n       Contract.Requires(path != null && path.Count > 0);\n       Contract.Requires(exports != null);\n       Contract.Requires(exports.Count == 0 || path.Count == 1);\n       Path = path;\n       Exports = exports;\n    }\n    public override object Dereference() { return Signature.ModuleDef; }\n  }\n\n  // Represents \"module name as path [ = compilePath];\", where name is a identifier and path is a possibly qualified name.\n  public class ModuleFacadeDecl : ModuleDecl\n  {\n    public ModuleDecl Root;\n    public readonly List<IToken> Path;\n    public readonly List<IToken> Exports; // list of exports sets\n    public ModuleDecl CompileRoot;\n    public ModuleSignature OriginalSignature;\n\n    public ModuleFacadeDecl(List<IToken> path, IToken name, ModuleDefinition parent, bool opened, List<IToken> exports)\n      : base(name, name.val, parent, opened) {\n      Contract.Requires(path != null && path.Count > 0);\n      Contract.Requires(exports != null);\n      Contract.Requires(exports.Count == 0 || path.Count == 1);\n\n      Path = path;\n      Exports = exports;\n      Root = null;\n    }\n    public override object Dereference() { return this; }\n  }\n\n  // Represents the exports of a module.\n  public class ModuleExportDecl : ModuleDecl\n  {\n    public readonly bool IsDefault;\n    public List<ExportSignature> Exports; // list of TopLevelDecl that are included in the export\n    public List<string> Extends; // list of exports that are extended\n    public readonly List<ModuleExportDecl> ExtendDecls = new List<ModuleExportDecl>(); // fill in by the resolver\n    public readonly HashSet<Tuple<Declaration, bool>> ExportDecls = new HashSet<Tuple<Declaration, bool>>(); // fill in by the resolver\n    public bool RevealAll; // only kept for initial rewriting, then discarded\n    public bool ProvideAll;\n\n    public readonly VisibilityScope ThisScope;\n    public ModuleExportDecl(IToken tok, ModuleDefinition parent,\n      List<ExportSignature> exports, List<string> extends, bool provideAll, bool revealAll, bool isDefault)\n      : base(tok, isDefault ? parent.Name : tok.val, parent, false) {\n      Contract.Requires(exports != null);\n      IsDefault = isDefault;\n      Exports = exports;\n      Extends = extends;\n      ProvideAll = provideAll;\n      RevealAll = revealAll;\n      ThisScope = new VisibilityScope(true, this.FullCompileName);\n    }\n\n    public void SetupDefaultSignature() {\n      Contract.Requires(this.Signature == null);\n      var sig = new ModuleSignature();\n      sig.ModuleDef = this.Module;\n      sig.IsAbstract = this.Module.IsAbstract;\n      sig.VisibilityScope = new VisibilityScope();\n      sig.VisibilityScope.Augment(ThisScope);\n      this.Signature = sig;\n    }\n\n    public override object Dereference() { return this; }\n    public override bool CanBeExported() {\n      return false;\n    }\n\n  }\n\n  public class ExportSignature\n  {\n    public readonly IToken Tok;\n    public readonly IToken ClassIdTok;\n    public readonly bool Opaque;\n    public readonly string ClassId;\n    public readonly string Id;\n\n    public Declaration Decl;  // filled in by the resolver\n\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(Tok != null);\n      Contract.Invariant(Id != null);\n      Contract.Invariant((ClassId != null) == (ClassIdTok != null));\n    }\n\n    public ExportSignature(IToken prefixTok, string prefix, IToken idTok, string id, bool opaque) {\n      Contract.Requires(prefixTok != null);\n      Contract.Requires(prefix != null);\n      Contract.Requires(idTok != null);\n      Contract.Requires(id != null);\n      Tok = idTok;\n      ClassIdTok = prefixTok;\n      ClassId = prefix;\n      Id = id;\n      Opaque = opaque;\n    }\n\n    public ExportSignature(IToken idTok, string id, bool opaque) {\n      Contract.Requires(idTok != null);\n      Contract.Requires(id != null);\n      Tok = idTok;\n      Id = id;\n      Opaque = opaque;\n    }\n\n    public override string ToString() {\n      if (ClassId != null) {\n        return ClassId + \".\" + Id;\n      }\n      return Id;\n    }\n  }\n\n  public enum ArmadaModuleType { NotArmada, ArmadaStructs, ArmadaLevel, ArmadaProof }\n\n  public class ModuleSignature {\n    public  VisibilityScope VisibilityScope = null;\n    public readonly Dictionary<string, TopLevelDecl> TopLevels = new Dictionary<string, TopLevelDecl>();\n    public readonly Dictionary<string, ModuleExportDecl> ExportSets = new Dictionary<string, ModuleExportDecl>();\n    public readonly Dictionary<string, Tuple<DatatypeCtor, bool>> Ctors = new Dictionary<string, Tuple<DatatypeCtor, bool>>();\n    public readonly Dictionary<string, MemberDecl> StaticMembers = new Dictionary<string, MemberDecl>();\n    public ModuleDefinition ModuleDef = null; // Note: this is null if this signature does not correspond to a specific definition (i.e.\n                                              // it is abstract). Otherwise, it points to that definition.\n    public ModuleSignature CompileSignature = null; // This is the version of the signature that should be used at compile time.\n    public ModuleSignature Refines = null;\n    public bool IsAbstract = false;\n    public ArmadaModuleType ModuleType = ArmadaModuleType.NotArmada;\n    public ModuleSignature() {}\n    public int? ResolvedHash { get; set; }\n\n    // Qualified accesses follow module imports\n    public bool FindImport(string name, out ModuleSignature pp) {\n      TopLevelDecl top;\n      if (TopLevels.TryGetValue(name, out top) && top is ModuleDecl) {\n          pp = ((ModuleDecl)top).AccessibleSignature();\n        return true;\n      } else {\n        pp = null;\n        return false;\n      }\n    }\n  }\n\n  public class ModuleDefinition : INamedRegion, IAttributeBearingDeclaration\n  {\n    public readonly IToken tok;\n    public IToken BodyStartTok = Token.NoToken;\n    public IToken BodyEndTok = Token.NoToken;\n    public readonly string Name;\n    public string FullName {\n      get {\n        if (Module == null || Module.IsDefaultModule) {\n          return Name;\n        } else {\n          return Module.FullName + \".\" + Name;\n        }\n      }\n    }\n    public readonly List<IToken> PrefixIds;\n    IToken INamedRegion.BodyStartTok { get { return BodyStartTok; } }\n    IToken INamedRegion.BodyEndTok { get { return BodyEndTok; } }\n    string INamedRegion.Name { get { return Name; } }\n    public ModuleDefinition Module;  // readonly, except can be changed by resolver for prefix-named modules when the real parent is discovered\n    public readonly Attributes Attributes;\n    public readonly IToken RefinementBaseName;  // null if no refinement base\n    public ModuleDecl RefinementBaseRoot; // filled in early during resolution, corresponds to RefinementBaseName[0]\n    public bool SuccessfullyResolved;  // set to true upon successful resolution; modules that import an unsuccessfully resolved module are not themselves resolved\n\n    public List<Include> Includes;\n\n    public readonly List<TopLevelDecl> TopLevelDecls = new List<TopLevelDecl>();  // filled in by the parser; readonly after that, except for the addition of prefix-named modules, which happens in the resolver\n    public readonly List<Tuple<List<IToken>, LiteralModuleDecl>> PrefixNamedModules = new List<Tuple<List<IToken>, LiteralModuleDecl>>();  // filled in by the parser; emptied by the resolver\n    public readonly Graph<ICallable> CallGraph = new Graph<ICallable>();  // filled in during resolution\n    public int Height;  // height in the topological sorting of modules; filled in during resolution\n    public readonly bool IsAbstract;\n    public readonly bool IsProtected;\n    public readonly bool IsFacade; // True iff this module represents a module facade (that is, an abstract interface)\n    private readonly bool IsBuiltinName; // true if this is something like _System that shouldn't have it's name mangled.\n    public bool IsToBeVerified = true;\n    public ArmadaModuleType ModuleType;\n    public IToken StructsModuleName;\n    public readonly IToken Abstracts;\n    public ModuleDecl AbstractsDecl; // filled in early during resolution, corresponds to Abstracts\n    public readonly List<string> Reduces;\n\n    public ModuleDefinition ArmadaTranslation;  // null unless this is a level or refinement proof; filled out by StateMachineTranslator or RefinementProofGenerator\n    public List<string> ArmadaIncludes; // null unless this is a level or refinement proof; filled out by StateMachineTranslator or RefinementProofGenerator\n    public ArmadaStructs ArmadaStructs; // null unless this is a structs module; filled out by StateMachineTranslator\n    public ArmadaSymbolTable ArmadaSymbols; // null unless this is a level; filled out by StateMachineTranslator\n\n    private ModuleSignature refinementBaseSig; // module signature of the refinementBase.\n    public ModuleSignature RefinementBaseSig {\n      get {\n        return refinementBaseSig;\n      }\n\n      set {\n        // the refinementBase member may only be changed once.\n        if (null != refinementBaseSig) {\n          throw new InvalidOperationException(string.Format(\"This module ({0}) already has a refinement base ({1}).\", Name, refinementBase.Name));\n        }\n        refinementBaseSig = value;\n      }\n    }\n\n    private ModuleDefinition refinementBase; // filled in during resolution via RefinementBase property (null if no refinement base yet or at all).\n\n    public ModuleDefinition RefinementBase {\n        get {\n           return refinementBase;\n        }\n\n        set {\n          // the refinementBase member may only be changed once.\n          if (null != refinementBase) {\n              throw new InvalidOperationException(string.Format(\"This module ({0}) already has a refinement base ({1}).\", Name, refinementBase.Name));\n          }\n          refinementBase = value;\n        }\n    }\n\n    public int? ResolvedHash { get; set; }\n\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(cce.NonNullElements(TopLevelDecls));\n      Contract.Invariant(CallGraph != null);\n    }\n\n    public ModuleDefinition(IToken tok, string name, List<IToken> prefixIds, bool isAbstract, bool isProtected, bool isFacade, IToken refinementBase, ModuleDefinition parent, Attributes attributes, bool isBuiltinName, ArmadaModuleType moduleType = ArmadaModuleType.NotArmada, IToken structsModuleName = null, IToken abstracts = null, List<IToken> reduces = null, Parser parser = null)\n    {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      this.tok = tok;\n      this.Name = name;\n      this.PrefixIds = prefixIds;\n      this.Attributes = attributes;\n      this.Module = parent;\n      RefinementBaseName = refinementBase;\n      IsAbstract = isAbstract;\n      IsProtected = isProtected;\n      IsFacade = isFacade;\n      RefinementBaseRoot = null;\n      this.refinementBase = null;\n      Includes = new List<Include>();\n      IsBuiltinName = isBuiltinName;\n      ModuleType = moduleType;\n      StructsModuleName = structsModuleName;\n      ArmadaTranslation = null;\n      ArmadaIncludes = null;\n      ArmadaStructs = null;\n      ArmadaSymbols = null;\n    }\n\n    VisibilityScope visibilityScope;\n\n    public VisibilityScope VisibilityScope {\n      get {\n        if (visibilityScope == null) {\n          visibilityScope = new VisibilityScope(true, this.CompileName);\n        }\n        return visibilityScope;\n      }\n    }\n\n    public virtual bool IsDefaultModule {\n      get {\n        return false;\n      }\n    }\n    string compileName;\n    public string CompileName {\n      get {\n        if (compileName == null) {\n          var externArgs = ArmadaOptions.O.DisallowExterns ? null : Attributes.FindExpressions(this.Attributes, \"extern\");\n          if (externArgs != null && 1 <= externArgs.Count && externArgs[0] is StringLiteralExpr) {\n            compileName = (string)((StringLiteralExpr)externArgs[0]).Value;\n          } else if (IsBuiltinName || externArgs != null) {\n            compileName = Name;\n          } else {\n            compileName = \"_\" + Height.ToString() + \"_\" + NonglobalVariable.CompilerizeName(Name);\n          }\n        }\n        return compileName;\n      }\n    }\n\n    public string RefinementCompileName {\n      get {\n        return this.CompileName;\n      }\n    }\n\n    /// <summary>\n    /// Determines if \"a\" and \"b\" are in the same strongly connected component of the call graph, that is,\n    /// if \"a\" and \"b\" are mutually recursive.\n    /// Assumes that CallGraph has already been filled in for the modules containing \"a\" and \"b\".\n    /// </summary>\n    public static bool InSameSCC(ICallable a, ICallable b) {\n      Contract.Requires(a != null);\n      Contract.Requires(b != null);\n      if (a is SpecialFunction || b is SpecialFunction) { return false; }\n      var module = a.EnclosingModule;\n      return module == b.EnclosingModule && module.CallGraph.GetSCCRepresentative(a) == module.CallGraph.GetSCCRepresentative(b);\n    }\n\n    /// <summary>\n    /// Return the representative elements of the SCCs that contain contain any member declaration in a\n    /// class in \"declarations\".\n    /// Note, the representative element may in some cases be a Method, not necessarily a Function.\n    /// </summary>\n    public static IEnumerable<ICallable> AllFunctionSCCs(List<TopLevelDecl> declarations) {\n      var set = new HashSet<ICallable>();\n      foreach (var d in declarations) {\n        var cl = d as ClassDecl;\n        if (cl != null) {\n          var module = cl.Module;\n          foreach (var member in cl.Members) {\n            var fn = member as Function;\n            if (fn != null) {\n              var repr = module.CallGraph.GetSCCRepresentative(fn);\n              set.Add(repr);\n            }\n          }\n        }\n      }\n      return set;\n    }\n\n    public static IEnumerable<Function> AllFunctions(List<TopLevelDecl> declarations) {\n      foreach (var d in declarations) {\n        var cl = d as ClassDecl;\n        if (cl != null) {\n          foreach (var member in cl.Members) {\n            var fn = member as Function;\n            if (fn != null) {\n              yield return fn;\n            }\n          }\n        }\n      }\n    }\n\n    public static IEnumerable<Field> AllFields(List<TopLevelDecl> declarations) {\n      foreach (var d in declarations) {\n        var cl = d as ClassDecl;\n        if (cl != null) {\n          foreach (var member in cl.Members) {\n            var fn = member as Field;\n            if (fn != null) {\n              yield return fn;\n            }\n          }\n        }\n      }\n    }\n\n    public static IEnumerable<ClassDecl> AllClasses(List<TopLevelDecl> declarations) {\n      foreach (var d in declarations) {\n        var cl = d as ClassDecl;\n        if (cl != null) {\n          yield return cl;\n        }\n      }\n    }\n\n    /// <summary>\n    /// Yields all functions and methods that are members of some class in the given list of\n    /// declarations.\n    /// Note, an iterator declaration is a class, in this sense.\n    /// Note, if the given list are the top-level declarations of a module, the yield will include\n    /// colemmas but not their associated prefix lemmas (which are tucked into the colemma's\n    /// .PrefixLemma field).\n    /// </summary>\n    public static IEnumerable<ICallable> AllCallables(List<TopLevelDecl> declarations) {\n      foreach (var d in declarations) {\n        var cl = d as ClassDecl;\n        if (cl != null) {\n          foreach (var member in cl.Members) {\n            var clbl = member as ICallable;\n            if (clbl != null && !(member is Field)) {\n              yield return clbl;\n            }\n          }\n        }\n      }\n    }\n\n    /// <summary>\n    /// Yields all functions and methods that are members of some non-iterator class in the given\n    /// list of declarations, as well as any IteratorDecl's in that list.\n    /// </summary>\n    public static IEnumerable<ICallable> AllItersAndCallables(List<TopLevelDecl> declarations) {\n      foreach (var d in declarations) {\n        if (d is IteratorDecl) {\n          var iter = (IteratorDecl)d;\n          yield return iter;\n        } else if (d is ClassDecl) {\n          var cl = (ClassDecl)d;\n          foreach (var member in cl.Members) {\n            var clbl = member as ICallable;\n            if (clbl != null) {\n              yield return clbl;\n            }\n          }\n        }\n      }\n    }\n\n    public static IEnumerable<IteratorDecl> AllIteratorDecls(List<TopLevelDecl> declarations) {\n      foreach (var d in declarations) {\n        var iter = d as IteratorDecl;\n        if (iter != null) {\n          yield return iter;\n        }\n      }\n    }\n\n    /// <summary>\n    /// Emits the declarations in \"declarations\", but for each such declaration that is a class with\n    /// a corresponding non-null type, also emits that non-null type *after* the class declaration.\n    /// </summary>\n    public static IEnumerable<TopLevelDecl> AllDeclarationsAndNonNullTypeDecls(List<TopLevelDecl> declarations) {\n      foreach (var d in declarations) {\n        yield return d;\n        var cl = d as ClassDecl;\n        if (cl != null && cl.NonNullTypeDecl != null) {\n          yield return cl.NonNullTypeDecl;\n        }\n      }\n    }\n\n    public static IEnumerable<FixpointLemma> AllFixpointLemmas(List<TopLevelDecl> declarations) {\n      foreach (var d in declarations) {\n        var cl = d as ClassDecl;\n        if (cl != null) {\n          foreach (var member in cl.Members) {\n            var m = member as FixpointLemma;\n            if (m != null) {\n              yield return m;\n            }\n          }\n        }\n      }\n    }\n\n    public bool IsEssentiallyEmptyModuleBody() {\n      foreach (var d in TopLevelDecls) {\n        if (d is ModuleDecl) {\n          // modules don't count\n          continue;\n        } else if (d is ClassDecl) {\n          var cl = (ClassDecl)d;\n          if (cl.Members.Count == 0) {\n            // the class is empty, so it doesn't count\n            continue;\n          }\n        }\n        return false;\n      }\n      return true;\n    }\n  }\n\n  public class DefaultModuleDecl : ModuleDefinition {\n    public DefaultModuleDecl()\n      : base(Token.NoToken, \"_module\", new List<IToken>(), false, false, false, null, null, null, true) {\n    }\n    public override bool IsDefaultModule {\n      get {\n        return true;\n      }\n    }\n  }\n\n  public abstract class TopLevelDecl : Declaration, TypeParameter.ParentType {\n    public abstract string WhatKind { get; }\n    public readonly ModuleDefinition Module;\n    public readonly List<TypeParameter> TypeArgs;\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(cce.NonNullElements(TypeArgs));\n    }\n\n    public TopLevelDecl(IToken tok, string name, ModuleDefinition module, List<TypeParameter> typeArgs, Attributes attributes)\n      : base(tok, name, attributes) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Contract.Requires(cce.NonNullElements(typeArgs));\n      Module = module;\n      TypeArgs = typeArgs;\n    }\n\n    public string FullName {\n      get {\n        return Module.FullName + \".\" + Name;\n      }\n    }\n    public string FullSanitizedName {\n      get {\n        return Module.CompileName + \".\" + CompileName;\n      }\n    }\n\n    public string FullSanitizedRefinementName {\n      get {\n        return Module.RefinementCompileName + \".\" + CompileName;\n      }\n    }\n\n    public string FullNameInContext(ModuleDefinition context) {\n      if (Module == context) {\n        return Name;\n      } else {\n        return Module.Name + \".\" + Name;\n      }\n    }\n    public string FullCompileName {\n      get {\n        var externArgs = Attributes.FindExpressions(this.Attributes, \"extern\");\n        if (!ArmadaOptions.O.DisallowExterns && externArgs != null) {\n          if (externArgs.Count == 2 && externArgs[0] is StringLiteralExpr && externArgs[1] is StringLiteralExpr) {\n            return externArgs[0].AsStringLiteral() + \".\" + externArgs[1].AsStringLiteral();\n          }\n        }\n        return Declaration.IdProtect(Module.CompileName) + \".\" + Declaration.IdProtect(CompileName);\n      }\n    }\n\n    public TopLevelDecl ViewAsClass {\n      get {\n        if (this is NonNullTypeDecl) {\n          return ((NonNullTypeDecl)this).Class;\n        } else {\n          return this;\n        }\n      }\n    }\n  }\n\n  public abstract class TopLevelDeclWithMembers : TopLevelDecl {\n    public readonly List<MemberDecl> Members;\n    public TopLevelDeclWithMembers(IToken tok, string name, ModuleDefinition module, List<TypeParameter> typeArgs, List<MemberDecl> members, Attributes attributes)\n      : base(tok, name, module, typeArgs, attributes) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Contract.Requires(cce.NonNullElements(typeArgs));\n      Contract.Requires(cce.NonNullElements(members));\n      Members = members;\n    }\n  }\n\n  public class TraitDecl : ClassDecl {\n    public override string WhatKind { get { return \"trait\"; } }\n    public bool IsParent { set; get; }\n    public TraitDecl(IToken tok, string name, ModuleDefinition module,\n      List<TypeParameter> typeArgs, [Captured] List<MemberDecl> members, Attributes attributes)\n      : base(tok, name, module, typeArgs, members, attributes, null) { }\n  }\n\n  public class ClassDecl : TopLevelDeclWithMembers {\n    public override string WhatKind { get { return \"class\"; } }\n    public override bool CanBeRevealed() { return true; }\n    public readonly List<MemberDecl> InheritedMembers = new List<MemberDecl>();  // these are instance fields and instance members defined with bodies in traits\n    public readonly List<Type> TraitsTyp;  // these are the types that are parsed after the keyword 'extends'\n    public readonly List<TraitDecl> TraitsObj = new List<TraitDecl>();  // populated during resolution\n    public bool HasConstructor;  // filled in (early) during resolution; true iff there exists a member that is a Constructor\n    public readonly NonNullTypeDecl NonNullTypeDecl;\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(cce.NonNullElements(Members));\n      Contract.Invariant(TraitsTyp != null);\n      Contract.Invariant(TraitsObj != null);\n    }\n\n    public ClassDecl(IToken tok, string name, ModuleDefinition module,\n      List<TypeParameter> typeArgs, [Captured] List<MemberDecl> members, Attributes attributes, List<Type> traits)\n      : base(tok, name, module, typeArgs, members, attributes) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Contract.Requires(module != null);\n      Contract.Requires(cce.NonNullElements(typeArgs));\n      Contract.Requires(cce.NonNullElements(members));\n      TraitsTyp = traits ?? new List<Type>();\n      if (!IsDefaultClass && !(this is ArrowTypeDecl)) {\n        NonNullTypeDecl = new NonNullTypeDecl(this);\n      }\n    }\n    public virtual bool IsDefaultClass {\n      get {\n        return false;\n      }\n    }\n\n    internal bool DerivesFrom(TopLevelDecl b) {\n      Contract.Requires(b != null);\n      return this == b || this.TraitsObj.Exists(tr => tr.DerivesFrom(b));\n    }\n  }\n\n  public class DefaultClassDecl : ClassDecl {\n    public DefaultClassDecl(ModuleDefinition module, [Captured] List<MemberDecl> members)\n      : base(Token.NoToken, \"_default\", module, new List<TypeParameter>(), members, null, null) {\n      Contract.Requires(module != null);\n      Contract.Requires(cce.NonNullElements(members));\n    }\n    public override bool IsDefaultClass {\n      get {\n        return true;\n      }\n    }\n  }\n\n  public class ArrayClassDecl : ClassDecl {\n    public override string WhatKind { get { return \"array type\"; } }\n    public readonly int Dims;\n    public ArrayClassDecl(int dims, ModuleDefinition module, Attributes attrs)\n    : base(Token.NoToken, BuiltIns.ArrayClassName(dims), module,\n      new List<TypeParameter>(new TypeParameter[]{ new TypeParameter(Token.NoToken, \"arg\", TypeParameter.TPVarianceSyntax.NonVariant_Strict) }),\n      new List<MemberDecl>(), attrs, null)\n    {\n      Contract.Requires(1 <= dims);\n      Contract.Requires(module != null);\n\n      Dims = dims;\n    }\n  }\n\n  public class ArrowTypeDecl : ClassDecl\n  {\n    public override string WhatKind { get { return \"function type\"; } }\n    public readonly int Arity;\n    public readonly Function Requires;\n    public readonly Function Reads;\n\n    public ArrowTypeDecl(List<TypeParameter> tps, Function req, Function reads, ModuleDefinition module, Attributes attributes)\n      : base(Token.NoToken, ArrowType.ArrowTypeName(tps.Count - 1), module, tps,\n             new List<MemberDecl> { req, reads }, attributes, null) {\n      Contract.Requires(tps != null && 1 <= tps.Count);\n      Contract.Requires(req != null);\n      Contract.Requires(reads != null);\n      Contract.Requires(module != null);\n      Arity = tps.Count - 1;\n      Requires = req;\n      Reads = reads;\n      Requires.EnclosingClass = this;\n      Reads.EnclosingClass = this;\n    }\n  }\n\n  public abstract class DatatypeDecl : TopLevelDeclWithMembers, RevealableTypeDecl, ICallable\n  {\n    public override bool CanBeRevealed() { return true; }\n    public readonly List<DatatypeCtor> Ctors;\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(cce.NonNullElements(Ctors));\n      Contract.Invariant(1 <= Ctors.Count);\n    }\n\n    public DatatypeDecl(IToken tok, string name, ModuleDefinition module, List<TypeParameter> typeArgs,\n      [Captured] List<DatatypeCtor> ctors, List<MemberDecl> members, Attributes attributes)\n      : base(tok, name, module, typeArgs, members, attributes) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Contract.Requires(module != null);\n      Contract.Requires(cce.NonNullElements(typeArgs));\n      Contract.Requires(cce.NonNullElements(ctors));\n      Contract.Requires(cce.NonNullElements(members));\n      Contract.Requires(1 <= ctors.Count);\n      Ctors = ctors;\n      this.NewSelfSynonym();\n    }\n    public bool HasFinitePossibleValues {\n      get {\n        return (TypeArgs.Count == 0 && Ctors.TrueForAll(ctr => ctr.Formals.Count == 0));\n      }\n    }\n\n    public bool IsRecordType {\n      get { return this is IndDatatypeDecl && Ctors.Count == 1; }\n    }\n\n    TopLevelDecl RevealableTypeDecl.AsTopLevelDecl { get { return this; } }\n\n    bool ICodeContext.IsGhost { get { return true; } }\n    List<TypeParameter> ICodeContext.TypeArgs { get { return TypeArgs; } }\n    List<Formal> ICodeContext.Ins { get { return new List<Formal>(); } }\n    ModuleDefinition ICodeContext.EnclosingModule { get { return Module; } }\n    bool ICodeContext.MustReverify { get { return false; } }\n    bool ICodeContext.AllowsNontermination { get { return false; } }\n    IToken ICallable.Tok { get { return tok; } }\n    string ICallable.NameRelativeToModule { get { return Name; } }\n    Specification<Expression> ICallable.Decreases {\n      get {\n        // The resolver checks that a NewtypeDecl sits in its own SSC in the call graph.  Therefore,\n        // the question of what its Decreases clause is should never arise.\n        throw new cce.UnreachableException();\n      }\n    }\n    bool ICallable.InferredDecreases {\n      get { throw new cce.UnreachableException(); }  // see comment above about ICallable.Decreases\n      set { throw new cce.UnreachableException(); }  // see comment above about ICallable.Decreases\n    }\n  }\n\n  public class IndDatatypeDecl : DatatypeDecl, RevealableTypeDecl\n  {\n    public override string WhatKind { get { return \"datatype\"; } }\n    public DatatypeCtor DefaultCtor;  // set during resolution\n    public bool[] TypeParametersUsedInConstructionByDefaultCtor;  // set during resolution; has same length as the number of type arguments\n\n    public enum ES { NotYetComputed, Never, ConsultTypeArguments }\n    public ES EqualitySupport = ES.NotYetComputed;\n\n    public IndDatatypeDecl(IToken tok, string name, ModuleDefinition module, List<TypeParameter> typeArgs,\n      [Captured] List<DatatypeCtor> ctors, List<MemberDecl> members, Attributes attributes)\n      : base(tok, name, module, typeArgs, ctors, members, attributes) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Contract.Requires(module != null);\n      Contract.Requires(cce.NonNullElements(typeArgs));\n      Contract.Requires(cce.NonNullElements(ctors));\n      Contract.Requires(cce.NonNullElements(members));\n      Contract.Requires(1 <= ctors.Count);\n    }\n  }\n\n  public class TupleTypeDecl : IndDatatypeDecl\n  {\n    public readonly int Dims;\n    /// <summary>\n    /// Construct a resolved built-in tuple type with \"dim\" arguments.  \"systemModule\" is expected to be the _System module.\n    /// </summary>\n    public TupleTypeDecl(int dims, ModuleDefinition systemModule, Attributes attributes)\n      : this(systemModule, CreateCovariantTypeParameters(dims), attributes) {\n      Contract.Requires(0 <= dims);\n      Contract.Requires(systemModule != null);\n    }\n\n    private TupleTypeDecl(ModuleDefinition systemModule, List<TypeParameter> typeArgs, Attributes attributes)\n      : base(Token.NoToken, BuiltIns.TupleTypeName(typeArgs.Count), systemModule, typeArgs, CreateConstructors(typeArgs), new List<MemberDecl>(), attributes) {\n      Contract.Requires(systemModule != null);\n      Contract.Requires(typeArgs != null);\n      Dims = typeArgs.Count;\n      foreach (var ctor in Ctors) {\n        ctor.EnclosingDatatype = this;  // resolve here\n        DefaultCtor = ctor;\n        TypeParametersUsedInConstructionByDefaultCtor = new bool[typeArgs.Count];\n        for (int i = 0; i < typeArgs.Count; i++) {\n          TypeParametersUsedInConstructionByDefaultCtor[i] = true;\n        }\n      }\n      this.EqualitySupport = ES.ConsultTypeArguments;\n    }\n    private static List<TypeParameter> CreateCovariantTypeParameters(int dims) {\n      Contract.Requires(0 <= dims);\n      var ts = new List<TypeParameter>();\n      for (int i = 0; i < dims; i++) {\n        var tp = new TypeParameter(Token.NoToken, \"T\" + i, TypeParameter.TPVarianceSyntax.Covariant_Strict);\n        tp.NecessaryForEqualitySupportOfSurroundingInductiveDatatype = true;\n        ts.Add(tp);\n      }\n      return ts;\n    }\n    private static List<DatatypeCtor> CreateConstructors(List<TypeParameter> typeArgs) {\n      Contract.Requires(typeArgs != null);\n      var formals = new List<Formal>();\n      for (int i = 0; i < typeArgs.Count; i++) {\n        var tp = typeArgs[i];\n        var f = new Formal(Token.NoToken, i.ToString(), new UserDefinedType(Token.NoToken, tp), true, false);\n        formals.Add(f);\n      }\n      var ctor = new DatatypeCtor(Token.NoToken, BuiltIns.TupleTypeCtorNamePrefix + typeArgs.Count, formals, null);\n      return new List<DatatypeCtor>() { ctor };\n    }\n\n    public override string CompileName {\n      get {\n        return \"Tuple\" + Dims;\n      }\n    }\n  }\n\n  public class CoDatatypeDecl : DatatypeDecl\n  {\n    public override string WhatKind { get { return \"codatatype\"; } }\n    public CoDatatypeDecl SscRepr;  // filled in during resolution\n\n    public CoDatatypeDecl(IToken tok, string name, ModuleDefinition module, List<TypeParameter> typeArgs,\n      [Captured] List<DatatypeCtor> ctors, List<MemberDecl> members, Attributes attributes)\n      : base(tok, name, module, typeArgs, ctors, members, attributes) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Contract.Requires(module != null);\n      Contract.Requires(cce.NonNullElements(typeArgs));\n      Contract.Requires(cce.NonNullElements(ctors));\n      Contract.Requires(cce.NonNullElements(members));\n      Contract.Requires(1 <= ctors.Count);\n    }\n  }\n\n  /// <summary>\n  /// The \"ValuetypeDecl\" class models the built-in value types (like bool, int, set, and seq.\n  /// Its primary function is to hold the formal type parameters and built-in members of these types.\n  /// </summary>\n  public class ValuetypeDecl : TopLevelDecl\n  {\n    public override string WhatKind { get { return Name; } }\n    public readonly Dictionary<string, MemberDecl> Members = new Dictionary<string, MemberDecl>();\n    readonly Func<Type, bool> typeTester;\n    readonly Func<List<Type>, Type>/*?*/ typeCreator;\n\n    public ValuetypeDecl(string name, ModuleDefinition module, int typeParameterCount, Func<Type, bool> typeTester, Func<List<Type>, Type>/*?*/ typeCreator)\n      : base(Token.NoToken, name, module, new List<TypeParameter>(), null) {\n      Contract.Requires(name != null);\n      Contract.Requires(module != null);\n      Contract.Requires(0 <= typeParameterCount);\n      Contract.Requires(typeTester != null);\n      // fill in the type parameters\n      for (int i = 0; i < typeParameterCount; i++) {\n        TypeArgs.Add(new TypeParameter(Token.NoToken, ((char)('T' + i)).ToString(), i, this));\n      }\n      this.typeTester = typeTester;\n      this.typeCreator = typeCreator;\n    }\n\n    public bool IsThisType(Type t) {\n      Contract.Assert(t != null);\n      return typeTester(t);\n    }\n\n    public Type CreateType(List<Type> typeArgs) {\n      Contract.Requires(typeArgs != null);\n      Contract.Requires(typeArgs.Count == TypeArgs.Count);\n      Contract.Assume(typeCreator != null);  // can only call CreateType for a ValuetypeDecl with a type creator (this is up to the caller to ensure)\n      return typeCreator(typeArgs);\n    }\n  }\n\n  public class DatatypeCtor : Declaration, TypeParameter.ParentType\n  {\n    public readonly List<Formal> Formals;\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(cce.NonNullElements(Formals));\n      Contract.Invariant(Destructors != null);\n      Contract.Invariant(\n        Destructors.Count == 0 || // this is until resolution\n        Destructors.Count == Formals.Count);  // after resolution\n    }\n\n    // TODO: One could imagine having a precondition on datatype constructors\n    public DatatypeDecl EnclosingDatatype;  // filled in during resolution\n    public SpecialField QueryField;  // filled in during resolution\n    public List<DatatypeDestructor> Destructors = new List<DatatypeDestructor>();  // contents filled in during resolution; includes both implicit (not mentionable in source) and explicit destructors\n\n    public DatatypeCtor(IToken tok, string name, [Captured] List<Formal> formals, Attributes attributes)\n      : base(tok, name, attributes) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Contract.Requires(cce.NonNullElements(formals));\n      this.Formals = formals;\n    }\n\n    public string FullName {\n      get {\n        Contract.Ensures(Contract.Result<string>() != null);\n        Contract.Assume(EnclosingDatatype != null);\n\n        return \"#\" + EnclosingDatatype.FullName + \".\" + Name;\n      }\n    }\n  }\n\n  /// <summary>\n  /// An ICodeContext is an ICallable or a NoContext.\n  /// </summary>\n  public interface ICodeContext\n  {\n    bool IsGhost { get; }\n    List<TypeParameter> TypeArgs { get; }\n    List<Formal> Ins { get; }\n    ModuleDefinition EnclosingModule { get; }  // to be called only after signature-resolution is complete\n    bool MustReverify { get; }\n    string FullSanitizedName { get; }\n    bool AllowsNontermination { get; }\n  }\n  /// <summary>\n  /// An ICallable is a Function, Method, IteratorDecl, or (less fitting for the name ICallable) RedirectingTypeDecl or DatatypeDecl.\n  /// </summary>\n  public interface ICallable : ICodeContext\n  {\n    IToken Tok { get; }\n    string WhatKind { get; }\n    string NameRelativeToModule { get; }\n    Specification<Expression> Decreases { get; }\n    /// <summary>\n    /// The InferredDecreases property says whether or not a process was attempted to provide a default decreases\n    /// clause.  If such a process was attempted, even if the resulting decreases clause turned out to be empty,\n    /// the property will get the value \"true\".  This is so that a useful error message can be provided.\n    /// </summary>\n    bool InferredDecreases { get; set; }\n  }\n\n  public class DontUseICallable : ICallable\n  {\n    public string WhatKind { get { throw new cce.UnreachableException(); } }\n    public bool IsGhost { get { throw new cce.UnreachableException(); } }\n    public List<TypeParameter> TypeArgs { get { throw new cce.UnreachableException(); } }\n    public List<Formal> Ins { get { throw new cce.UnreachableException(); } }\n    public ModuleDefinition EnclosingModule { get { throw new cce.UnreachableException(); } }\n    public bool MustReverify { get { throw new cce.UnreachableException(); } }\n    public string FullSanitizedName { get { throw new cce.UnreachableException(); } }\n    public bool AllowsNontermination { get { throw new cce.UnreachableException(); } }\n    public IToken Tok { get { throw new cce.UnreachableException(); } }\n    public string NameRelativeToModule { get { throw new cce.UnreachableException(); } }\n    public Specification<Expression> Decreases { get { throw new cce.UnreachableException(); } }\n    public bool InferredDecreases {\n      get { throw new cce.UnreachableException(); }\n      set { throw new cce.UnreachableException(); }\n    }\n  }\n  /// <summary>\n  /// An IMethodCodeContext is a Method or IteratorDecl.\n  /// </summary>\n  public interface IMethodCodeContext : ICallable\n  {\n    List<Formal> Outs { get; }\n    Specification<FrameExpression> Modifies { get; }\n  }\n\n  /// <summary>\n  /// Applies when we are not inside an ICallable.  In particular, a NoContext is used to resolve the attributes of declarations with no other context.\n  /// </summary>\n  public class NoContext : ICodeContext\n  {\n    public readonly ModuleDefinition Module;\n    public NoContext(ModuleDefinition module)\n    {\n      this.Module = module;\n    }\n    bool ICodeContext.IsGhost { get { return true; } }\n    List<TypeParameter> ICodeContext.TypeArgs { get { return new List<TypeParameter>(); } }\n    List<Formal> ICodeContext.Ins { get { return new List<Formal>(); } }\n    Specification<Expression> Decreases { get { return new Specification<Expression>(null, null); } }\n    ModuleDefinition ICodeContext.EnclosingModule { get { return Module; } }\n    bool ICodeContext.MustReverify { get { Contract.Assume(false, \"should not be called on NoContext\"); throw new cce.UnreachableException(); } }\n    public string FullSanitizedName { get { Contract.Assume(false, \"should not be called on NoContext\"); throw new cce.UnreachableException(); } }\n    public bool AllowsNontermination { get { Contract.Assume(false, \"should not be called on NoContext\"); throw new cce.UnreachableException(); } }\n  }\n\n  public class IteratorDecl : ClassDecl, IMethodCodeContext\n  {\n    public override string WhatKind { get { return \"iterator\"; } }\n    public readonly List<Formal> Ins;\n    public readonly List<Formal> Outs;\n    public readonly Specification<FrameExpression> Reads;\n    public readonly Specification<FrameExpression> Modifies;\n    public readonly Specification<Expression> Decreases;\n    public readonly List<MaybeFreeExpression> Requires;\n    public readonly List<MaybeFreeExpression> Ensures;\n    public readonly List<MaybeFreeExpression> YieldRequires;\n    public readonly List<MaybeFreeExpression> YieldEnsures;\n    public readonly BlockStmt Body;\n    public bool SignatureIsOmitted { get { return SignatureEllipsis != null; } }\n    public readonly IToken SignatureEllipsis;\n    public readonly List<Field> OutsFields;\n    public readonly List<Field> OutsHistoryFields;  // these are the 'xs' variables\n    public readonly List<Field> DecreasesFields;  // filled in during resolution\n    public SpecialField Member_Modifies;  // filled in during resolution\n    public SpecialField Member_Reads;  // filled in during resolution\n    public SpecialField Member_New;  // filled in during resolution\n    public Constructor Member_Init;  // created during registration phase of resolution; its specification is filled in during resolution\n    public Predicate Member_Valid;  // created during registration phase of resolution; its specification is filled in during resolution\n    public Method Member_MoveNext;  // created during registration phase of resolution; its specification is filled in during resolution\n    public readonly LocalVariable YieldCountVariable;\n\n    public IteratorDecl(IToken tok, string name, ModuleDefinition module, List<TypeParameter> typeArgs,\n                        List<Formal> ins, List<Formal> outs,\n                        Specification<FrameExpression> reads, Specification<FrameExpression> mod, Specification<Expression> decreases,\n                        List<MaybeFreeExpression> requires,\n                        List<MaybeFreeExpression> ensures,\n                        List<MaybeFreeExpression> yieldRequires,\n                        List<MaybeFreeExpression> yieldEnsures,\n                        BlockStmt body, Attributes attributes, IToken signatureEllipsis)\n      : base(tok, name, module, MutateIntoRequiringZeroInitBit(typeArgs), new List<MemberDecl>(), attributes, null)\n    {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Contract.Requires(module != null);\n      Contract.Requires(typeArgs != null);\n      Contract.Requires(ins != null);\n      Contract.Requires(outs != null);\n      Contract.Requires(reads != null);\n      Contract.Requires(mod != null);\n      Contract.Requires(decreases != null);\n      Contract.Requires(requires != null);\n      Contract.Requires(ensures != null);\n      Contract.Requires(yieldRequires != null);\n      Contract.Requires(yieldEnsures != null);\n      Ins = ins;\n      Outs = outs;\n      Reads = reads;\n      Modifies = mod;\n      Decreases = decreases;\n      Requires = requires;\n      Ensures = ensures;\n      YieldRequires = yieldRequires;\n      YieldEnsures = yieldEnsures;\n      Body = body;\n      SignatureEllipsis = signatureEllipsis;\n\n      OutsFields = new List<Field>();\n      OutsHistoryFields = new List<Field>();\n      DecreasesFields = new List<Field>();\n\n      YieldCountVariable = new LocalVariable(tok, tok, \"_yieldCount\", new EverIncreasingType(), true, false);\n      YieldCountVariable.type = YieldCountVariable.OptionalType;  // resolve YieldCountVariable here\n    }\n\n    private static List<TypeParameter> MutateIntoRequiringZeroInitBit(List<TypeParameter> typeArgs) {\n      Contract.Requires(typeArgs != null);\n      Contract.Ensures(Contract.Result<List<TypeParameter>>() == typeArgs);\n      // Note! This is not the only place where IteratorDecl type parameters come through.  Some may\n      // be created by \"FillInTypeArguments\".\n      foreach (var tp in typeArgs) {\n        tp.Characteristics.MustSupportZeroInitialization = true;\n      }\n      return typeArgs;\n    }\n\n    /// <summary>\n    /// Returns the non-null expressions of this declaration proper (that is, do not include the expressions of substatements).\n    /// Does not include the generated class members.\n    /// </summary>\n    public virtual IEnumerable<Expression> SubExpressions {\n      get {\n        foreach (var e in Attributes.SubExpressions(Attributes)) {\n          yield return e;\n        }\n        foreach (var e in Attributes.SubExpressions(Reads.Attributes)) {\n          yield return e;\n        }\n        foreach (var e in Reads.Expressions) {\n          yield return e.E;\n        }\n        foreach (var e in Attributes.SubExpressions(Modifies.Attributes)) {\n          yield return e;\n        }\n        foreach (var e in Modifies.Expressions) {\n          yield return e.E;\n        }\n        foreach (var e in Attributes.SubExpressions(Decreases.Attributes)) {\n          yield return e;\n        }\n        foreach (var e in Decreases.Expressions) {\n          yield return e;\n        }\n        foreach (var e in Requires) {\n          yield return e.E;\n        }\n        foreach (var e in Ensures) {\n          yield return e.E;\n        }\n        foreach (var e in YieldRequires) {\n          yield return e.E;\n        }\n        foreach (var e in YieldEnsures) {\n          yield return e.E;\n        }\n      }\n    }\n\n    /// <summary>\n    /// This Dafny type exists only for the purpose of giving the yield-count variable a type, so\n    /// that the type can be recognized during translation of Dafny into Boogie.  It represents\n    /// an integer component in a \"decreases\" clause whose order is (\\lambda x,y :: x GREATER y),\n    /// not the usual (\\lambda x,y :: x LESS y AND 0 ATMOST y).\n    /// </summary>\n    public class EverIncreasingType : BasicType\n    {\n      [Pure]\n      public override string TypeName(ModuleDefinition context, bool parseAble) {\n        Contract.Assert(parseAble == false);\n\n        return \"_increasingInt\";\n      }\n      public override bool Equals(Type that) {\n        return that.NormalizeExpand() is EverIncreasingType;\n      }\n    }\n\n    bool ICodeContext.IsGhost { get { return false; } }\n    List<TypeParameter> ICodeContext.TypeArgs { get { return this.TypeArgs; } }\n    List<Formal> ICodeContext.Ins { get { return this.Ins; } }\n    List<Formal> IMethodCodeContext.Outs { get { return this.Outs; } }\n    Specification<FrameExpression> IMethodCodeContext.Modifies { get { return this.Modifies; } }\n    IToken ICallable.Tok { get { return this.tok; } }\n    string ICallable.NameRelativeToModule { get { return this.Name; } }\n    Specification<Expression> ICallable.Decreases { get { return this.Decreases; } }\n    bool _inferredDecr;\n    bool ICallable.InferredDecreases {\n      set { _inferredDecr = value; }\n      get { return _inferredDecr; }\n    }\n\n    ModuleDefinition ICodeContext.EnclosingModule { get { return this.Module; } }\n    bool ICodeContext.MustReverify { get { return false; } }\n    public bool AllowsNontermination {\n      get {\n        return Contract.Exists(Decreases.Expressions, e => e is WildcardExpr);\n      }\n    }\n  }\n\n  public abstract class MemberDecl : Declaration {\n    public abstract string WhatKind { get; }\n    public readonly bool HasStaticKeyword;\n    public virtual bool IsStatic {\n      get {\n        return HasStaticKeyword || (EnclosingClass is ClassDecl && ((ClassDecl)EnclosingClass).IsDefaultClass);\n      }\n    }\n    protected readonly bool isGhost;\n    public bool IsGhost { get { return isGhost; } }\n    public bool IsInstanceIndependentConstant {\n      get {\n        var cf = this as ConstantField;\n        return cf != null && cf.Rhs != null;\n      }\n    }\n\n    public TopLevelDecl EnclosingClass;  // filled in during resolution\n    public MemberDecl RefinementBase;  // filled in during the pre-resolution refinement transformation; null if the member is new here\n    public MemberDecl(IToken tok, string name, bool hasStaticKeyword, bool isGhost, Attributes attributes)\n      : base(tok, name, attributes) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      HasStaticKeyword = hasStaticKeyword;\n      this.isGhost = isGhost;\n    }\n    /// <summary>\n    /// Returns className+\".\"+memberName.  Available only after resolution.\n    /// </summary>\n    public virtual string FullName {\n      get {\n        Contract.Requires(EnclosingClass != null);\n        Contract.Ensures(Contract.Result<string>() != null);\n\n        return EnclosingClass.FullName + \".\" + Name;\n      }\n    }\n    public virtual string FullSanitizedName {\n      get {\n        Contract.Requires(EnclosingClass != null);\n        Contract.Ensures(Contract.Result<string>() != null);\n\n        if (Name == \"requires\") {\n          return Translator.Requires(((ArrowTypeDecl)EnclosingClass).Arity);\n        } else if (Name == \"reads\") {\n          return Translator.Reads(((ArrowTypeDecl)EnclosingClass).Arity);\n        } else {\n          return EnclosingClass.FullSanitizedName + \".\" + CompileName;\n        }\n      }\n    }\n    public virtual string FullSanitizedRefinementName {\n      get {\n        Contract.Requires(EnclosingClass != null);\n        Contract.Ensures(Contract.Result<string>() != null);\n\n        if (Name == \"requires\") {\n          return Translator.Requires(((ArrowTypeDecl)EnclosingClass).Arity);\n        } else if (Name == \"reads\") {\n          return Translator.Reads(((ArrowTypeDecl)EnclosingClass).Arity);\n        } else {\n          return EnclosingClass.FullSanitizedRefinementName + \".\" + CompileName;\n        }\n      }\n    }\n    public virtual string FullNameInContext(ModuleDefinition context) {\n      Contract.Requires(EnclosingClass != null);\n      Contract.Ensures(Contract.Result<string>() != null);\n\n      return EnclosingClass.FullNameInContext(context) + \".\" + Name;\n    }\n    public override string CompileName {\n      get {\n        var nm = base.CompileName;\n        if (this.Name == EnclosingClass.Name) {\n          nm = \"_\" + nm;\n        }\n        return nm;\n      }\n    }\n    public virtual string FullCompileName {\n      get {\n        Contract.Requires(EnclosingClass != null);\n        Contract.Ensures(Contract.Result<string>() != null);\n\n        return EnclosingClass.FullCompileName + \".\" + Declaration.IdProtect(CompileName);\n      }\n    }\n    public virtual IEnumerable<Expression> SubExpressions {\n      get {\n        yield break;\n      }\n    }\n  }\n\n  public class Field : MemberDecl, ICodeContext {\n    public override string WhatKind { get { return \"field\"; } }\n    public readonly bool IsMutable;  // says whether or not the field can ever change values\n    public readonly bool IsUserMutable;  // says whether or not code is allowed to assign to the field (IsUserMutable implies IsMutable)\n    public readonly Type Type;\n    public readonly bool IsNoAddr;\n    public readonly Expression InitialValue;\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(Type != null);\n      Contract.Invariant(!IsUserMutable || IsMutable);  // IsUserMutable ==> IsMutable\n    }\n\n    public Field(IToken tok, string name, bool isGhost, Type type, Attributes attributes, bool isNoAddr = false, bool isStatic = false, Expression initialValue = null)\n      : this(tok, name, isStatic, isGhost, true, true, type, attributes, isNoAddr) {\n      InitialValue = initialValue;\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Contract.Requires(type != null);\n    }\n\n    public Field(IToken tok, string name, bool hasStaticKeyword, bool isGhost, bool isMutable, bool isUserMutable, Type type, Attributes attributes, bool isNoAddr = false, Expression initialValue = null)\n      : base(tok, name, hasStaticKeyword, isGhost, attributes) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Contract.Requires(type != null);\n      Contract.Requires(!isUserMutable || isMutable);\n      IsMutable = isMutable;\n      IsUserMutable = isUserMutable;\n      Type = type;\n      IsNoAddr = isNoAddr;\n      InitialValue = initialValue;\n    }\n\n    //\n    public new bool IsGhost { get { return this.isGhost; } }\n    public List<TypeParameter> TypeArgs { get { return new List<TypeParameter>(); } }\n    public List<Formal> Ins { get { return new List<Formal>(); } }\n    public ModuleDefinition EnclosingModule { get { return this.EnclosingClass.Module; } }\n    public bool MustReverify { get { return false; } }\n    public bool AllowsNontermination { get { throw new cce.UnreachableException(); } }\n    public IToken Tok { get { return tok; } }\n    public string NameRelativeToModule {\n      get {\n        if (EnclosingClass is DefaultClassDecl) {\n          return Name;\n        } else {\n          return EnclosingClass.Name + \".\" + Name;\n        }\n      }\n    }\n    public Specification<Expression> Decreases { get { throw new cce.UnreachableException(); } }\n    public bool InferredDecreases\n    {\n      get { throw new cce.UnreachableException(); }\n      set { throw new cce.UnreachableException(); }\n    }\n  }\n\n  public class SpecialFunction : Function, ICodeContext, ICallable\n  {\n    readonly ModuleDefinition Module;\n    public SpecialFunction(IToken tok, string name, ModuleDefinition module, bool hasStaticKeyword, bool isProtected, bool isGhost,\n                    List<TypeParameter> typeArgs, List<Formal> formals, Type resultType,\n                    List<MaybeFreeExpression> req, List<FrameExpression> reads, List<MaybeFreeExpression> ens, Specification<Expression> decreases,\n                    Expression body, Attributes attributes, IToken signatureEllipsis)\n      : base(tok, name, hasStaticKeyword, isProtected, isGhost, typeArgs, formals, null, resultType, req, reads, ens, decreases, body, attributes, signatureEllipsis)\n    {\n      Module = module;\n    }\n    ModuleDefinition ICodeContext.EnclosingModule { get { return this.Module; } }\n    string ICallable.NameRelativeToModule { get { return Name; } }\n  }\n\n    public class SpecialField : Field\n  {\n    public enum ID {\n      UseIdParam,  // IdParam is a string\n      ArrayLength,  // IdParam is null for .Length; IdParam is an int \"x\" for GetLength(x)\n      ArrayLengthInt,  // same as ArrayLength, but produces int instead of BigInteger\n      Floor,\n      IsLimit,\n      IsSucc,\n      Offset,\n      IsNat,\n      Keys,\n      Values,\n      Items,\n      Reads,\n      Modifies,\n      New,\n    }\n    public readonly ID SpecialId;\n    public readonly object IdParam;\n    public SpecialField(IToken tok, string name, ID specialId, object idParam, bool isGhost, bool isMutable, bool isUserMutable, Type type, Attributes attributes)\n      : this(tok, name, specialId, idParam, false, isGhost, isMutable, isUserMutable, type, attributes) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Contract.Requires(!isUserMutable || isMutable);\n      Contract.Requires(type != null);\n    }\n\n    public SpecialField(IToken tok, string name, ID specialId, object idParam, bool hasStaticKeyword, bool isGhost, bool isMutable, bool isUserMutable, Type type, Attributes attributes)\n      : base(tok, name, hasStaticKeyword, isGhost, isMutable, isUserMutable, type, attributes) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Contract.Requires(!isUserMutable || isMutable);\n      Contract.Requires(type != null);\n\n      SpecialId = specialId;\n      IdParam = idParam;\n    }\n\n    public override string FullName {\n      get {\n        Contract.Ensures(Contract.Result<string>() != null);\n        return EnclosingClass != null ? EnclosingClass.FullName + \".\" + Name : Name;\n      }\n    }\n\n    public override string FullSanitizedName {\n      get {\n        Contract.Ensures(Contract.Result<string>() != null);\n        return EnclosingClass != null ? EnclosingClass.FullSanitizedName + \".\" + CompileName : CompileName;\n      }\n    }\n\n    public override string FullSanitizedRefinementName {\n      get{\n        Contract.Ensures(Contract.Result<string>() != null);\n        return EnclosingClass != null ? EnclosingClass.FullSanitizedRefinementName + \".\" + CompileName : CompileName;\n      }\n    }\n\n    public override string FullNameInContext(ModuleDefinition context) {\n      Contract.Ensures(Contract.Result<string>() != null);\n      return EnclosingClass != null ? EnclosingClass.FullNameInContext(context) + \".\" + Name : Name;\n    }\n\n    public override string CompileName {\n      get {\n        Contract.Ensures(Contract.Result<string>() != null);\n        return EnclosingClass != null ? base.CompileName : Name;\n      }\n    }\n\n    public override string FullCompileName {\n      get {\n        Contract.Ensures(Contract.Result<string>() != null);\n        var cn = Declaration.IdProtect(CompileName);\n        return EnclosingClass != null ? EnclosingClass.FullCompileName + \".\" + cn : cn;\n      }\n    }\n  }\n\n  public class DatatypeDestructor : SpecialField\n  {\n    public readonly List<DatatypeCtor> EnclosingCtors = new List<DatatypeCtor>();  // is always a nonempty list\n    public readonly List<Formal> CorrespondingFormals = new List<Formal>();  // is always a nonempty list\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(EnclosingCtors != null);\n      Contract.Invariant(CorrespondingFormals != null);\n      Contract.Invariant(EnclosingCtors.Count > 0);\n      Contract.Invariant(EnclosingCtors.Count == CorrespondingFormals.Count);\n    }\n\n    public DatatypeDestructor(IToken tok, DatatypeCtor enclosingCtor, Formal correspondingFormal, string name, string compiledName, bool isGhost, Type type, Attributes attributes)\n      : base(tok, name, SpecialField.ID.UseIdParam, compiledName, isGhost, false, false, type, attributes)\n    {\n      Contract.Requires(tok != null);\n      Contract.Requires(enclosingCtor != null);\n      Contract.Requires(correspondingFormal != null);\n      Contract.Requires(name != null);\n      Contract.Requires(type != null);\n      EnclosingCtors.Add(enclosingCtor);  // more enclosing constructors may be added later during resolution\n      CorrespondingFormals.Add(correspondingFormal);  // more corresponding formals may be added later during resolution\n    }\n\n    /// <summary>\n    /// To be called only by the resolver. Called to share this datatype destructor between multiple constructors\n    /// of the same datatype.\n    /// </summary>\n    internal void AddAnotherEnclosingCtor(DatatypeCtor ctor, Formal formal) {\n      Contract.Requires(ctor != null);\n      Contract.Requires(formal != null);\n      EnclosingCtors.Add(ctor);  // more enclosing constructors may be added later during resolution\n      CorrespondingFormals.Add(formal);  // more corresponding formals may be added later during resolution\n    }\n\n    internal string EnclosingCtorNames(string grammaticalConjunction) {\n      Contract.Requires(grammaticalConjunction != null);\n      return PrintableCtorNameList(EnclosingCtors, grammaticalConjunction);\n    }\n\n    static internal string PrintableCtorNameList(List<DatatypeCtor> ctors, string grammaticalConjunction) {\n      Contract.Requires(ctors != null);\n      Contract.Requires(grammaticalConjunction != null);\n      var n = ctors.Count;\n      if (n == 1) {\n        return string.Format(\"'{0}'\", ctors[0].Name);\n      } else if (n == 2) {\n        return string.Format(\"'{0}' {1} '{2}'\", ctors[0].Name, grammaticalConjunction, ctors[1].Name);\n      } else {\n        var s = \"\";\n        for (int i = 0; i < n - 1; i++) {\n          s += string.Format(\"'{0}', \", ctors[i].Name);\n        }\n        return s + string.Format(\"{0} '{1}'\", grammaticalConjunction, ctors[n - 1].Name);\n      }\n    }\n  }\n\n  public class ConstantField : SpecialField, ICallable\n  {\n    public override string WhatKind { get { return \"const field\"; } }\n    public readonly Expression Rhs;\n    public ConstantField(IToken tok, string name, Expression/*?*/ rhs, bool hasStaticKeyword, bool isGhost, Type type, Attributes attributes)\n      : base(tok, name, SpecialField.ID.UseIdParam, NonglobalVariable.CompilerizeName(name), hasStaticKeyword, isGhost, false, false, type, attributes)\n    {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Contract.Requires(type != null);\n      this.Rhs = rhs;\n    }\n\n    public override bool CanBeRevealed() {\n      return true;\n    }\n\n    //\n    public new bool IsGhost { get { return this.isGhost; } }\n  }\n\n  public class OpaqueTypeDecl : TopLevelDecl, TypeParameter.ParentType, RevealableTypeDecl\n  {\n    public override string WhatKind { get { return \"opaque type\"; } }\n    public override bool CanBeRevealed() { return true; }\n    public readonly TypeParameter TheType;\n    public TypeParameter.TypeParameterCharacteristics Characteristics {\n      get { return TheType.Characteristics; }\n    }\n    public bool MustSupportEquality {\n      get { return TheType.MustSupportEquality; }\n    }\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(TheType != null && Name == TheType.Name);\n    }\n\n    public OpaqueTypeDecl(IToken tok, string name, ModuleDefinition module, TypeParameter.TypeParameterCharacteristics characteristics, List<TypeParameter> typeArgs, Attributes attributes)\n      : base(tok, name, module, typeArgs, attributes) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Contract.Requires(module != null);\n      Contract.Requires(typeArgs != null);\n      TheType = new OpaqueType_AsParameter(tok, name, characteristics, TypeArgs);\n      this.NewSelfSynonym();\n    }\n\n    public TopLevelDecl AsTopLevelDecl {\n      get { return this; }\n    }\n\n    public bool SupportsEquality {\n      get { return this.MustSupportEquality; }\n    }\n  }\n\n  public interface RedirectingTypeDecl : ICallable\n  {\n    string Name { get; }\n\n    IToken tok { get; }\n    Attributes Attributes { get; }\n    ModuleDefinition Module { get; }\n    BoundVar/*?*/ Var { get; }\n    Expression/*?*/ Constraint { get; }\n    SubsetTypeDecl.WKind WitnessKind { get; }\n    Expression/*?*/ Witness { get; }  // non-null iff WitnessKind is Compiled or Ghost\n    FreshIdGenerator IdGenerator { get; }\n  }\n\n  public class NativeType\n  {\n    public readonly string Name;\n    public readonly BigInteger LowerBound;\n    public readonly BigInteger UpperBound;\n    public readonly int Bitwidth;  // for unasigned types, this shows the number of bits in the type; else is 0\n    public enum Selection { Byte, SByte, UShort, Short, UInt, Int, Number, ULong, Long }\n    public readonly Selection Sel;\n    public readonly ArmadaOptions.CompilationTarget CompilationTargets;\n    public NativeType(string Name, BigInteger LowerBound, BigInteger UpperBound, int bitwidth, Selection sel, ArmadaOptions.CompilationTarget compilationTargets) {\n      Contract.Requires(Name != null);\n      Contract.Requires(0 <= bitwidth && (bitwidth == 0 || LowerBound == 0));\n      this.Name = Name;\n      this.LowerBound = LowerBound;\n      this.UpperBound = UpperBound;\n      this.Bitwidth = bitwidth;\n      this.Sel = sel;\n      this.CompilationTargets = compilationTargets;\n    }\n  }\n\n  public static class RevealableTypeDeclHelper {\n    private static Dictionary<TopLevelDecl, InternalTypeSynonymDecl> tsdMap = new Dictionary<TopLevelDecl, InternalTypeSynonymDecl>();\n\n    public static void NewSelfSynonym(this RevealableTypeDecl rtd) {\n      var d = rtd.AsTopLevelDecl;\n      Contract.Assert(!tsdMap.ContainsKey(d));\n\n      var thisType = UserDefinedType.FromTopLevelDecl(d.tok, d);\n      if (d is OpaqueTypeDecl) {\n        thisType.ResolvedParam = ((OpaqueTypeDecl)d).TheType;\n      }\n\n      var tsd = new InternalTypeSynonymDecl(d.tok, d.Name, TypeParameter.GetExplicitCharacteristics(d), d.TypeArgs, d.Module, thisType, d.Attributes);\n      tsd.InheritVisibility(d, false);\n\n      tsdMap.Add(d, tsd);\n    }\n\n    public static UserDefinedType SelfSynonym(this RevealableTypeDecl rtd, List<Type> args) {\n      Contract.Requires(args != null);\n      var d = rtd.AsTopLevelDecl;\n      Contract.Assert(tsdMap.ContainsKey(d));\n      var typeSynonym = tsdMap[d];\n      Contract.Assert(typeSynonym.TypeArgs.Count == args.Count);\n      return new UserDefinedType(typeSynonym.tok, typeSynonym.Name, typeSynonym, args);\n    }\n\n    public static InternalTypeSynonymDecl SelfSynonymDecl(this RevealableTypeDecl rtd) {\n      var d = rtd.AsTopLevelDecl;\n      Contract.Assert(tsdMap.ContainsKey(d));\n      return tsdMap[d];\n    }\n\n    public static TopLevelDecl AccessibleDecl(this RevealableTypeDecl rtd, VisibilityScope scope) {\n      var d = rtd.AsTopLevelDecl;\n      if (d.IsRevealedInScope(scope)) {\n        return d;\n      } else {\n        return rtd.SelfSynonymDecl();\n      }\n    }\n\n    //Internal implementations are called before extensions, so this is safe\n    public static bool IsRevealedInScope(this RevealableTypeDecl rtd, VisibilityScope scope) {\n      var d = rtd.AsTopLevelDecl;\n      return d.IsRevealedInScope(scope);\n    }\n  }\n\n  public interface RevealableTypeDecl {\n    TopLevelDecl AsTopLevelDecl {get; }\n  }\n\n  public class NewtypeDecl : TopLevelDeclWithMembers, RevealableTypeDecl, RedirectingTypeDecl\n  {\n    public override string WhatKind { get { return \"newtype\"; } }\n    public override bool CanBeRevealed() { return true; }\n    public readonly Type BaseType;\n    public readonly BoundVar Var;  // can be null (if non-null, then object.ReferenceEquals(Var.Type, BaseType))\n    public readonly Expression Constraint;  // is null iff Var is\n    public readonly SubsetTypeDecl.WKind WitnessKind = SubsetTypeDecl.WKind.None;\n    public readonly Expression/*?*/ Witness;  // non-null iff WitnessKind is Compiled or Ghost\n    public NativeType NativeType; // non-null for fixed-size representations (otherwise, use BigIntegers for integers)\n    public NewtypeDecl(IToken tok, string name, ModuleDefinition module, Type baseType, List<MemberDecl> members, Attributes attributes)\n      : base(tok, name, module, new List<TypeParameter>(), members, attributes) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Contract.Requires(module != null);\n      Contract.Requires(baseType != null);\n      Contract.Requires(members != null);\n      BaseType = baseType;\n    }\n    public NewtypeDecl(IToken tok, string name, ModuleDefinition module, BoundVar bv, Expression constraint, SubsetTypeDecl.WKind witnessKind, Expression witness, List<MemberDecl> members, Attributes attributes)\n      : base(tok, name, module, new List<TypeParameter>(), members, attributes) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Contract.Requires(module != null);\n      Contract.Requires(bv != null && bv.Type != null);\n      Contract.Requires((witnessKind == SubsetTypeDecl.WKind.Compiled || witnessKind == SubsetTypeDecl.WKind.Ghost) == (witness != null));\n      Contract.Requires(members != null);\n      BaseType = bv.Type;\n      Var = bv;\n      Constraint = constraint;\n      Witness = witness;\n      WitnessKind = witnessKind;\n      this.NewSelfSynonym();\n    }\n\n    TopLevelDecl RevealableTypeDecl.AsTopLevelDecl { get { return this; } }\n    public TypeParameter.EqualitySupportValue EqualitySupport {\n      get {\n        if (this.BaseType.SupportsEquality) {\n          return TypeParameter.EqualitySupportValue.Required;\n        } else {\n          return TypeParameter.EqualitySupportValue.Unspecified;\n        }\n      }\n    }\n\n    string RedirectingTypeDecl.Name { get { return Name; } }\n    IToken RedirectingTypeDecl.tok { get { return tok; } }\n    Attributes RedirectingTypeDecl.Attributes { get { return Attributes; } }\n    ModuleDefinition RedirectingTypeDecl.Module { get { return Module; } }\n    BoundVar RedirectingTypeDecl.Var { get { return Var; } }\n    Expression RedirectingTypeDecl.Constraint { get { return Constraint; } }\n    SubsetTypeDecl.WKind RedirectingTypeDecl.WitnessKind { get { return WitnessKind; } }\n    Expression RedirectingTypeDecl.Witness { get { return Witness; } }\n    FreshIdGenerator RedirectingTypeDecl.IdGenerator { get { return IdGenerator; } }\n\n    bool ICodeContext.IsGhost { get { return true; } }\n    List<TypeParameter> ICodeContext.TypeArgs { get { return new List<TypeParameter>(); } }\n    List<Formal> ICodeContext.Ins { get { return new List<Formal>(); } }\n    ModuleDefinition ICodeContext.EnclosingModule { get { return Module; } }\n    bool ICodeContext.MustReverify { get { return false; } }\n    bool ICodeContext.AllowsNontermination { get { return false; } }\n    IToken ICallable.Tok { get { return tok; } }\n    string ICallable.NameRelativeToModule { get { return Name; } }\n    Specification<Expression> ICallable.Decreases {\n      get {\n        // The resolver checks that a NewtypeDecl sits in its own SSC in the call graph.  Therefore,\n        // the question of what its Decreases clause is should never arise.\n        throw new cce.UnreachableException();\n      }\n    }\n    bool ICallable.InferredDecreases {\n      get { throw new cce.UnreachableException(); }  // see comment above about ICallable.Decreases\n      set { throw new cce.UnreachableException(); }  // see comment above about ICallable.Decreases\n    }\n  }\n\n\n  public abstract class TypeSynonymDeclBase : TopLevelDecl, RedirectingTypeDecl\n  {\n    public override string WhatKind { get { return \"type synonym\"; } }\n    public TypeParameter.TypeParameterCharacteristics Characteristics;  // the resolver may change the .EqualitySupport component of this value from Unspecified to InferredRequired (for some signatures that may immediately imply that equality support is required)\n    public bool MustSupportEquality {\n      get { return Characteristics.EqualitySupport != TypeParameter.EqualitySupportValue.Unspecified; }\n    }\n    public readonly Type Rhs;\n    public TypeSynonymDeclBase(IToken tok, string name, TypeParameter.TypeParameterCharacteristics characteristics, List<TypeParameter> typeArgs, ModuleDefinition module, Type rhs, Attributes attributes)\n      : base(tok, name, module, typeArgs, attributes) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Contract.Requires(typeArgs != null);\n      Contract.Requires(module != null);\n      Contract.Requires(rhs != null);\n      Characteristics = characteristics;\n      Rhs = rhs;\n    }\n    /// <summary>\n    /// Return .Rhs instantiated with \"typeArgs\", but only look at the part of .Rhs that is in scope.\n    /// </summary>\n    public Type RhsWithArgument(List<Type> typeArgs) {\n      Contract.Requires(typeArgs != null);\n      Contract.Requires(typeArgs.Count == TypeArgs.Count);\n      var scope = Type.GetScope();\n      var rtd = Rhs.AsRevealableType;\n      if (rtd != null) {\n        Contract.Assume(rtd.AsTopLevelDecl.IsVisibleInScope(scope));\n        if (!rtd.IsRevealedInScope(scope)) {\n          // type is actually hidden in this scope\n          return rtd.SelfSynonym(typeArgs);\n        }\n      }\n      return RhsWithArgumentIgnoringScope(typeArgs);\n    }\n    /// <summary>\n    /// Returns the declared .Rhs but with formal type arguments replaced by the given actuals.\n    /// </summary>\n    public Type RhsWithArgumentIgnoringScope(List<Type> typeArgs) {\n      Contract.Requires(typeArgs != null);\n      Contract.Requires(typeArgs.Count == TypeArgs.Count);\n      // Instantiate with the actual type arguments\n      if (typeArgs.Count == 0) {\n        // this optimization seems worthwhile\n        return Rhs;\n      } else {\n        var subst = Resolver.TypeSubstitutionMap(TypeArgs, typeArgs);\n        return Resolver.SubstType(Rhs, subst);\n      }\n    }\n\n    string RedirectingTypeDecl.Name { get { return Name; } }\n    IToken RedirectingTypeDecl.tok { get { return tok; } }\n    Attributes RedirectingTypeDecl.Attributes { get { return Attributes; } }\n    ModuleDefinition RedirectingTypeDecl.Module { get { return Module; } }\n    BoundVar RedirectingTypeDecl.Var { get { return null; } }\n    Expression RedirectingTypeDecl.Constraint { get { return null; } }\n    SubsetTypeDecl.WKind RedirectingTypeDecl.WitnessKind { get { return SubsetTypeDecl.WKind.None; } }\n    Expression RedirectingTypeDecl.Witness { get { return null; } }\n    FreshIdGenerator RedirectingTypeDecl.IdGenerator { get { return IdGenerator; } }\n\n    bool ICodeContext.IsGhost { get { return false; } }\n    List<TypeParameter> ICodeContext.TypeArgs { get { return TypeArgs; } }\n    List<Formal> ICodeContext.Ins { get { return new List<Formal>(); } }\n    ModuleDefinition ICodeContext.EnclosingModule { get { return Module; } }\n    bool ICodeContext.MustReverify {get { return false; } }\n    bool ICodeContext.AllowsNontermination { get { return false; } }\n    IToken ICallable.Tok { get { return tok; } }\n    string ICallable.NameRelativeToModule { get { return Name; } }\n    Specification<Expression> ICallable.Decreases {\n      get {\n        // The resolver checks that a NewtypeDecl sits in its own SSC in the call graph.  Therefore,\n        // the question of what its Decreases clause is should never arise.\n        throw new cce.UnreachableException();\n      }\n    }\n    bool ICallable.InferredDecreases {\n      get { throw new cce.UnreachableException(); }  // see comment above about ICallable.Decreases\n      set { throw new cce.UnreachableException(); }  // see comment above about ICallable.Decreases\n    }\n    public override bool CanBeRevealed() {\n      return true;\n    }\n  }\n\n  public class TypeSynonymDecl : TypeSynonymDeclBase, RedirectingTypeDecl, RevealableTypeDecl {\n    public TypeSynonymDecl(IToken tok, string name, TypeParameter.TypeParameterCharacteristics characteristics, List<TypeParameter> typeArgs, ModuleDefinition module, Type rhs, Attributes attributes)\n      : base(tok, name, characteristics, typeArgs, module, rhs, attributes) {\n        this.NewSelfSynonym();\n    }\n    TopLevelDecl RevealableTypeDecl.AsTopLevelDecl { get { return this; } }\n  }\n\n  public class InternalTypeSynonymDecl : TypeSynonymDeclBase, RedirectingTypeDecl {\n    public InternalTypeSynonymDecl(IToken tok, string name, TypeParameter.TypeParameterCharacteristics characteristics, List<TypeParameter> typeArgs, ModuleDefinition module, Type rhs, Attributes attributes)\n      : base(tok, name, characteristics, typeArgs, module, rhs, attributes) {\n    }\n  }\n\n\n\n  public class SubsetTypeDecl : TypeSynonymDecl, RedirectingTypeDecl\n  {\n    public override string WhatKind { get { return \"subset type\"; } }\n    public readonly BoundVar Var;\n    public readonly Expression Constraint;\n    public enum WKind { None, Compiled, Ghost, Special }\n    public readonly SubsetTypeDecl.WKind WitnessKind;\n    public readonly Expression/*?*/ Witness;  // non-null iff WitnessKind is Compiled or Ghost\n    public SubsetTypeDecl(IToken tok, string name, TypeParameter.TypeParameterCharacteristics characteristics, List<TypeParameter> typeArgs, ModuleDefinition module,\n      BoundVar id, Expression constraint, WKind witnessKind, Expression witness,\n      Attributes attributes)\n      : base(tok, name, characteristics, typeArgs, module, id.Type, attributes) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Contract.Requires(typeArgs != null);\n      Contract.Requires(module != null);\n      Contract.Requires(id != null && id.Type != null);\n      Contract.Requires(constraint != null);\n      Contract.Requires((witnessKind == WKind.Compiled || witnessKind == WKind.Ghost) == (witness != null));\n      Var = id;\n      Constraint = constraint;\n      Witness = witness;\n      WitnessKind = witnessKind;\n    }\n    BoundVar RedirectingTypeDecl.Var { get { return Var; } }\n    Expression RedirectingTypeDecl.Constraint { get { return Constraint; } }\n    WKind RedirectingTypeDecl.WitnessKind { get { return WitnessKind; } }\n    Expression RedirectingTypeDecl.Witness { get { return Witness; } }\n  }\n\n  public class NonNullTypeDecl : SubsetTypeDecl\n  {\n    public readonly ClassDecl Class;\n    /// <summary>\n    /// The public constructor is NonNullTypeDecl(ClassDecl cl). The rest is pretty bizarre: There are stages of \"this\"-constructor calls\n    /// in order to build values that depend on previously computed parameters.\n    /// </summary>\n    public NonNullTypeDecl(ClassDecl cl)\n      : this(cl, cl.TypeArgs.ConvertAll(tp => new TypeParameter(tp.tok, tp.Name, tp.VarianceSyntax, tp.Characteristics)))\n {\n      Contract.Requires(cl != null);\n    }\n\n    private NonNullTypeDecl(ClassDecl cl, List<TypeParameter> tps)\n      : this(cl, tps,\n      new BoundVar(cl.tok, \"c\", new UserDefinedType(cl.tok, cl.Name + \"?\", tps.Count == 0 ? null : tps.ConvertAll(tp => (Type)new UserDefinedType(tp)))))\n    {\n      Contract.Requires(cl != null);\n      Contract.Requires(tps != null);\n    }\n\n    private NonNullTypeDecl(ClassDecl cl, List<TypeParameter> tps, BoundVar id)\n      : base(cl.tok, cl.Name, new TypeParameter.TypeParameterCharacteristics(), tps, cl.Module, id,\n      new BinaryExpr(cl.tok, BinaryExpr.Opcode.Neq, new IdentifierExpr(cl.tok, id), new LiteralExpr(cl.tok)),\n      SubsetTypeDecl.WKind.Special, null, BuiltIns.AxiomAttribute())\n    {\n      Contract.Requires(cl != null);\n      Contract.Requires(tps != null);\n      Contract.Requires(id != null);\n      Class = cl;\n    }\n  }\n\n  [ContractClass(typeof(IVariableContracts))]\n  public interface IVariable {\n    string Name {\n      get;\n    }\n    string DisplayName {  // what the user thinks he wrote\n      get;\n    }\n    string UniqueName {\n      get;\n    }\n    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\n      get;\n    }\n    string AssignUniqueName(FreshIdGenerator generator);\n    string CompileName {\n      get;\n    }\n    Type Type {\n      get;\n    }\n    Type OptionalType {\n      get;\n    }\n    bool IsMutable {\n      get;\n    }\n    bool IsGhost {\n      get;\n    }\n    IToken Tok {\n      get;\n    }\n  }\n  [ContractClassFor(typeof(IVariable))]\n  public abstract class IVariableContracts : IVariable {\n    public string Name {\n      get {\n        Contract.Ensures(Contract.Result<string>() != null);\n        throw new NotImplementedException();  // this getter implementation is here only so that the Ensures contract can be given here\n      }\n    }\n    public string DisplayName {\n      get {\n        Contract.Ensures(Contract.Result<string>() != null);\n        throw new NotImplementedException();  // this getter implementation is here only so that the Ensures contract can be given here\n      }\n    }\n    public string UniqueName {\n      get {\n        Contract.Ensures(Contract.Result<string>() != null);\n        throw new NotImplementedException();  // this getter implementation is here only so that the Ensures contract can be given here\n      }\n    }\n    public bool HasBeenAssignedUniqueName {\n      get {\n        throw new NotImplementedException();  // this getter implementation is here only so that the Ensures contract can be given here\n      }\n    }\n    public string CompileName {\n      get {\n        Contract.Ensures(Contract.Result<string>() != null);\n        throw new NotImplementedException();  // this getter implementation is here only so that the Ensures contract can be given here\n      }\n    }\n    public Type Type {\n      get {\n        Contract.Ensures(Contract.Result<Type>() != null);\n        throw new NotImplementedException();  // this getter implementation is here only so that the Ensures contract can be given here\n      }\n    }\n    public Type OptionalType {\n      get {\n        Contract.Ensures(Contract.Result<Type>() != null);\n        throw new NotImplementedException();  // this getter implementation is here only so that the Ensures contract can be given here\n      }\n    }\n    public bool IsMutable {\n      get {\n        throw new NotImplementedException();\n      }\n    }\n    public bool IsGhost {\n      get {\n        throw new NotImplementedException();\n      }\n    }\n    public IToken Tok {\n      get {\n        Contract.Ensures(Contract.Result<IToken>() != null);\n        throw new NotImplementedException();\n      }\n    }\n    public string AssignUniqueName(FreshIdGenerator generator)\n    {\n      Contract.Ensures(Contract.Result<string>() != null);\n      throw new NotImplementedException();\n    }\n  }\n\n  public abstract class NonglobalVariable : IVariable {\n    public readonly IToken tok;\n    readonly string name;\n\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(tok != null);\n      Contract.Invariant(name != null);\n      Contract.Invariant(type != null);\n    }\n\n    public string Name {\n      get {\n        Contract.Ensures(Contract.Result<string>() != null);\n        return name;\n      }\n    }\n    public string DisplayName {\n      get { return LocalVariable.DisplayNameHelper(this); }\n    }\n    private string uniqueName;\n    public string UniqueName {\n      get {\n        return uniqueName;\n      }\n    }\n    public bool HasBeenAssignedUniqueName {\n      get {\n        return uniqueName != null;\n      }\n    }\n    public string AssignUniqueName(FreshIdGenerator generator)\n    {\n      if (uniqueName == null)\n      {\n        uniqueName = generator.FreshId(Name + \"#\");\n        compileName = string.Format(\"_{0}_{1}\", Compiler.FreshId(), CompilerizeName(name));\n      }\n      return UniqueName;\n    }\n    static char[] specialChars = new char[] { '\\'', '_', '?', '\\\\', '#' };\n    public static string CompilerizeName(string nm) {\n      if ('0' <= nm[0] && nm[0] <= '9') {\n        // the identifier is one that consists of just digits\n        return \"_\" + nm;\n      }\n      string name = null;\n      int i = 0;\n      while (true) {\n        int j = nm.IndexOfAny(specialChars, i);\n        if (j == -1) {\n          if (i == 0) {\n            return nm;  // this is the common case\n          } else {\n            return name + nm.Substring(i);\n          }\n        } else {\n          string nxt = nm.Substring(i, j - i);\n          name = name == null ? nxt : name + nxt;\n          switch (nm[j]) {\n            case '\\'': name += \"_k\"; break;\n            case '_': name += \"__\"; break;\n            case '?': name += \"_q\"; break;\n            case '\\\\': name += \"_b\"; break;\n            case '#': name += \"_h\"; break;\n            default:\n              Contract.Assume(false);  // unexpected character\n              break;\n          }\n          i = j + 1;\n          if (i == nm.Length) {\n            return name;\n          }\n        }\n      }\n    }\n    protected string compileName;\n    public virtual string CompileName {\n      get {\n        if (compileName == null)\n        {\n          compileName = string.Format(\"_{0}_{1}\", Compiler.FreshId(), CompilerizeName(name));\n        }\n        return compileName;\n      }\n    }\n    Type type;\n    public Type SyntacticType { get { return type; } }  // returns the non-normalized type\n    public Type Type {\n      get {\n        Contract.Ensures(Contract.Result<Type>() != null);\n        return type.Normalize();\n      }\n    }\n    Type IVariable.OptionalType {\n      get { return Type; }  // same as Type for NonglobalVariable\n    }\n    public abstract bool IsMutable {\n      get;\n    }\n    bool isGhost;  // readonly after resolution\n    public bool IsGhost {\n      get {\n        return isGhost;\n      }\n      set {\n        isGhost = value;\n      }\n    }\n    public IToken Tok {\n      get {\n        return tok;\n      }\n    }\n\n    public NonglobalVariable(IToken tok, string name, Type type, bool isGhost) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Contract.Requires(type != null);\n      this.tok = tok;\n      this.name = name;\n      this.type = type;\n      this.isGhost = isGhost;\n    }\n  }\n\n  public class Formal : NonglobalVariable {\n    public readonly bool InParam;  // true to in-parameter, false for out-parameter\n    public override bool IsMutable {\n      get {\n        return !InParam;\n      }\n    }\n    public readonly bool IsOld;\n\n    public Formal(IToken tok, string name, Type type, bool inParam, bool isGhost, bool isOld = false)\n      : base(tok, name, type, isGhost) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Contract.Requires(type != null);\n      InParam = inParam;\n      IsOld = isOld;\n    }\n\n    public bool HasName {\n      get {\n        return !Name.StartsWith(\"#\");\n      }\n    }\n    public override string CompileName {\n      get {\n        if (compileName == null) {\n          compileName = CompilerizeName(Name);\n        }\n        return compileName;\n      }\n    }\n  }\n\n  /// <summary>\n  /// An ImplicitFormal is a parameter that is declared implicitly, in particular the \"_k\" depth parameter\n  /// of each colemma (for use in the comethod body only, not the specification).\n  /// </summary>\n  public class ImplicitFormal : Formal\n  {\n    public ImplicitFormal(IToken tok, string name, Type type, bool inParam, bool isGhost)\n      : base(tok, name, type, inParam, isGhost) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Contract.Requires(type != null);\n    }\n  }\n\n  [DebuggerDisplay(\"Bound<{name}>\")]\n  public class BoundVar : NonglobalVariable {\n    public override bool IsMutable {\n      get {\n        return false;\n      }\n    }\n\n    public BoundVar(IToken tok, string name, Type type)\n      : base(tok, name, type, false) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Contract.Requires(type != null);\n    }\n  }\n\n  public class Function : MemberDecl, TypeParameter.ParentType, ICallable {\n    public override string WhatKind { get { return \"function\"; } }\n    public override bool CanBeRevealed() { return true; }\n    public readonly bool IsProtected;\n    public bool IsRecursive;  // filled in during resolution\n    public bool IsFueled;  // filled in during resolution if anyone tries to adjust this function's fuel\n    public readonly List<TypeParameter> TypeArgs;\n    public readonly List<Formal> Formals;\n    public readonly Formal Result;\n    public readonly Type ResultType;\n    public readonly List<MaybeFreeExpression> Req;\n    public readonly List<FrameExpression> Reads;\n    public readonly List<MaybeFreeExpression> Ens;\n    public readonly Specification<Expression> Decreases;\n    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\n    public bool SignatureIsOmitted { get { return SignatureEllipsis != null; } }  // is \"false\" for all Function objects that survive into resolution\n    public readonly IToken SignatureEllipsis;\n    public bool IsBuiltin;\n    public Function OverriddenFunction;\n    public bool containsQuantifier;\n    public bool ContainsQuantifier {\n      set { containsQuantifier = value; }\n      get { return containsQuantifier;  }\n    }\n\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        foreach (var e in Req) {\n          yield return e.E;\n        }\n        foreach (var e in Reads) {\n          yield return e.E;\n        }\n        foreach (var e in Ens) {\n          yield return e.E;\n        }\n        foreach (var e in Decreases.Expressions) {\n          yield return e;\n        }\n        if (Body != null) {\n          yield return Body;\n        }\n      }\n    }\n\n    public Type Type {\n      get {\n        // Note, the following returned type can contain type parameters from the function and its enclosing class\n        return new ArrowType(tok, Formals.ConvertAll(f => f.Type), ResultType);\n      }\n    }\n\n    public bool AllowsNontermination {\n      get {\n        return Contract.Exists(Decreases.Expressions, e => e is WildcardExpr);\n      }\n    }\n\n    /// <summary>\n    /// 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).\n    /// It records all function calls made by the Function, including calls made in the body as well as in the specification.\n    /// The field is filled in during resolution (and used toward the end of resolution, to attach a helpful \"decreases\" prefix to functions in clusters\n    /// with co-recursive calls.\n    /// </summary>\n    public readonly List<FunctionCallExpr> AllCalls = new List<FunctionCallExpr>();\n    public enum CoCallClusterInvolvement {\n      None,  // the SCC containing the function does not involve any co-recursive calls\n      IsMutuallyRecursiveTarget,  // the SCC contains co-recursive calls, and this function is the target of some non-self recursive call\n      CoRecursiveTargetAllTheWay,  // the SCC contains co-recursive calls, and this function is the target only of self-recursive calls and co-recursive calls\n    }\n    public CoCallClusterInvolvement CoClusterTarget = CoCallClusterInvolvement.None;\n\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(cce.NonNullElements(TypeArgs));\n      Contract.Invariant(cce.NonNullElements(Formals));\n      Contract.Invariant(ResultType != null);\n      Contract.Invariant(cce.NonNullElements(Req));\n      Contract.Invariant(cce.NonNullElements(Reads));\n      Contract.Invariant(cce.NonNullElements(Ens));\n      Contract.Invariant(Decreases != null);\n    }\n\n    /// <summary>\n    /// Note, functions are \"ghost\" by default; a non-ghost function is called a \"function method\".\n    /// </summary>\n    public Function(IToken tok, string name, bool hasStaticKeyword, bool isProtected, bool isGhost,\n                    List<TypeParameter> typeArgs, List<Formal> formals, Formal result, Type resultType,\n                    List<MaybeFreeExpression> req, List<FrameExpression> reads, List<MaybeFreeExpression> ens, Specification<Expression> decreases,\n                    Expression body, Attributes attributes, IToken signatureEllipsis)\n      : base(tok, name, hasStaticKeyword, isGhost, attributes) {\n\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Contract.Requires(cce.NonNullElements(typeArgs));\n      Contract.Requires(cce.NonNullElements(formals));\n      Contract.Requires(resultType != null);\n      Contract.Requires(cce.NonNullElements(req));\n      Contract.Requires(cce.NonNullElements(reads));\n      Contract.Requires(cce.NonNullElements(ens));\n      Contract.Requires(decreases != null);\n      this.IsProtected = isProtected;\n      this.IsFueled = false;  // Defaults to false.  Only set to true if someone mentions this function in a fuel annotation\n      this.TypeArgs = typeArgs;\n      this.Formals = formals;\n      this.Result = result;\n      this.ResultType = result != null ? result.Type : resultType;\n      this.Req = req;\n      this.Reads = reads;\n      this.Ens = ens;\n      this.Decreases = decreases;\n      this.Body = body;\n      this.SignatureEllipsis = signatureEllipsis;\n\n      if (attributes != null) {\n        List<Expression> args = Attributes.FindExpressions(attributes, \"fuel\");\n        if (args != null) {\n          if (args.Count == 1) {\n            LiteralExpr literal = args[0] as LiteralExpr;\n            if (literal != null && literal.Value is BigInteger) {\n              this.IsFueled = true;\n            }\n          } else if (args.Count == 2) {\n            LiteralExpr literalLow = args[0] as LiteralExpr;\n            LiteralExpr literalHigh = args[1] as LiteralExpr;\n\n            if (literalLow != null && literalLow.Value is BigInteger && literalHigh != null && literalHigh.Value is BigInteger) {\n              this.IsFueled = true;\n            }\n          }\n        }\n      }\n    }\n\n\n    bool ICodeContext.IsGhost { get { return this.IsGhost; } }\n    List<TypeParameter> ICodeContext.TypeArgs { get { return this.TypeArgs; } }\n    List<Formal> ICodeContext.Ins { get { return this.Formals; } }\n    IToken ICallable.Tok { get { return this.tok; } }\n    string ICallable.NameRelativeToModule {\n      get {\n        if (EnclosingClass is DefaultClassDecl) {\n          return Name;\n        } else {\n          return EnclosingClass.Name + \".\" + Name;\n        }\n      }\n    }\n    Specification<Expression> ICallable.Decreases { get { return this.Decreases; } }\n    bool _inferredDecr;\n    bool ICallable.InferredDecreases {\n      set { _inferredDecr = value; }\n      get { return _inferredDecr; }\n    }\n    ModuleDefinition ICodeContext.EnclosingModule { get { return this.EnclosingClass.Module; } }\n    bool ICodeContext.MustReverify { get { return false; } }\n\n    [Pure]\n    public bool IsFuelAware() { return IsRecursive || IsFueled; }\n    public virtual bool ReadsHeap { get { return Reads.Count != 0; } }\n  }\n\n  public class Predicate : Function\n  {\n    public override string WhatKind { get { return \"predicate\"; } }\n    public enum BodyOriginKind\n    {\n      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)\n      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\n      Extension  // this predicate extends the definition of a predicate with a body in a module being refined\n    }\n    public readonly BodyOriginKind BodyOrigin;\n    public Predicate(IToken tok, string name, bool hasStaticKeyword, bool isProtected, bool isGhost,\n                     List<TypeParameter> typeArgs, List<Formal> formals,\n                     List<MaybeFreeExpression> req, List<FrameExpression> reads, List<MaybeFreeExpression> ens, Specification<Expression> decreases,\n                     Expression body, BodyOriginKind bodyOrigin, Attributes attributes, IToken signatureEllipsis)\n      : base(tok, name, hasStaticKeyword, isProtected, isGhost, typeArgs, formals, null, Type.Bool, req, reads, ens, decreases, body, attributes, signatureEllipsis) {\n      Contract.Requires(bodyOrigin == Predicate.BodyOriginKind.OriginalOrInherited || body != null);\n      BodyOrigin = bodyOrigin;\n    }\n  }\n\n  public class ActionPredicate : Predicate\n  {\n    public readonly Specification<FrameExpression> Mod;\n    public readonly List<Formal> Outs;\n    public ActionPredicate(IToken tok, string name,\n                  List<TypeParameter> typeArgs, List<Formal> formals, List<Formal> outs,\n                  List<MaybeFreeExpression> req, List<FrameExpression> reads, Specification<FrameExpression> mod, List<MaybeFreeExpression> ens, Specification<Expression> decreases,\n                  Expression body, Attributes attributes, IToken signatureEllipsis)\n    : base(tok, name, false, false, false, typeArgs, formals, req, reads, ens, decreases, body, BodyOriginKind.OriginalOrInherited, attributes, signatureEllipsis)\n    {\n      this.Mod = mod;\n      this.Outs = outs;\n    }\n  }\n\n  public class GlobalInvariantDecl : MemberDecl\n  {\n    public override string WhatKind { get { return \"global invariant\"; } }\n    public override bool CanBeRevealed() { return false; }\n    public readonly Expression Body;\n\n    public GlobalInvariantDecl(IToken tok, string name, Attributes attributes, Expression body) :\n      base(tok, name, false, false, attributes) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Body = body;\n    }\n  }\n\n  public class YieldPredicateDecl : MemberDecl\n  {\n    public override string WhatKind { get { return \"yield predicate\"; } }\n    public override bool CanBeRevealed() { return false; }\n    public readonly Expression Body;\n\n    public YieldPredicateDecl(IToken tok, string name, Attributes attributes, Expression body) :\n        base(tok, name, false, false, attributes) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Body = body;\n    }\n  }\n\n  public class UniversalStepConstraintDecl : MemberDecl\n  {\n    public override string WhatKind { get { return \"universal step constraint\"; } }\n    public override bool CanBeRevealed() { return false; }\n    public readonly Expression Body;\n    public readonly string Code;\n\n    public UniversalStepConstraintDecl(IToken tok, string name, Attributes attributes, Expression body) :\n        base(tok, name, false, false, attributes) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Body = body;\n      Code = null;\n    }\n\n    public UniversalStepConstraintDecl(IToken tok, string name, Attributes attributes, string code) :\n        base(tok, name, false, false, attributes) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Body = null;\n      Code = code;\n    }\n  }\n\n  public class RefinementConstraintDecl : TopLevelDecl\n  {\n    public override string WhatKind { get { return \"Armada refinement constraint\"; } }\n    public override bool CanBeRevealed() { return false; }\n    public RefinementConstraintDecl(IToken tok, ModuleDefinition module, string body) :\n      base(tok, \"\", module, new List<TypeParameter>(), null)\n    {\n      Body = Util.RemoveParsedStringQuotesSimple(body);\n    }\n\n    public readonly string Body;\n  }\n\n  public abstract class ArmadaProofDecl : TopLevelDecl\n  {\n    public override string WhatKind { get { return \"Armada proof element\"; } }\n    public override bool CanBeRevealed() { return Attributes.Contains(Attributes, \"opaque\"); }\n    public ArmadaProofDecl(IToken tok, ModuleDefinition module, Attributes attrs) :\n      base(tok, \"\", module, new List<TypeParameter>(), attrs)\n    {\n    }\n  }\n\n  public class RefinementParametersDecl : ArmadaProofDecl\n  {\n    public override string WhatKind { get { return \"refinement\"; } }\n\n    public RefinementParametersDecl(IToken tok, ModuleDefinition module, IToken lowLevel, IToken highLevel)\n      : base(tok, module, null)\n    {\n      LowLevel = lowLevel;\n      HighLevel = highLevel;\n    }\n\n    public readonly IToken LowLevel;\n    public readonly IToken HighLevel;\n  }\n\n  public class ImportFileArmadaProofDecl : ArmadaProofDecl\n  {\n    public override string WhatKind { get { return \"import file\"; } }\n\n    public ImportFileArmadaProofDecl(IToken tok, ModuleDefinition module, string includePath, List<string> usedFiles)\n      : base(tok, module, null)\n    {\n      IncludePath = includePath;\n      UsedFiles = usedFiles;\n    }\n\n    public readonly string IncludePath;\n    public readonly List<string> UsedFiles;\n  }\n\n  public class ImportModuleArmadaProofDecl : ArmadaProofDecl\n  {\n    public override string WhatKind { get { return \"import module\"; } }\n\n    public ImportModuleArmadaProofDecl(IToken tok, ModuleDefinition module, string includeModule, List<string> usedModules)\n      : base(tok, module, null)\n    {\n      IncludeModule = includeModule;\n      UsedModules = usedModules;\n    }\n\n    public readonly string IncludeModule;\n    public readonly List<string> UsedModules;\n  }\n\n  public class ExtraMaterialArmadaProofDecl : ArmadaProofDecl\n  {\n    public override string WhatKind { get { return \"extra material\"; } }\n\n    public ExtraMaterialArmadaProofDecl(IToken tok, ModuleDefinition module, string loc, string contents)\n      : base(tok, module, null)\n    {\n      Loc = loc;\n      Contents = Util.RemoveParsedStringQuotesSimple(contents);\n    }\n\n    public readonly string Loc;\n    public readonly string Contents;\n  }\n\n  public class InductiveInvariantArmadaProofDecl : ArmadaProofDecl\n  {\n    public override string WhatKind { get { return \"inductive invariant\"; } }\n\n    public InductiveInvariantArmadaProofDecl(IToken tok, ModuleDefinition module, IToken name, string code, List<IToken> dependencies,\n                                             Attributes attrs)\n      : base(tok, module, attrs)\n    {\n      InvariantName = name.val;\n      Code = Util.RemoveParsedStringQuotesSimple(code);\n      Dependencies = dependencies.Select(x => x.val).ToList();\n    }\n\n    public readonly string InvariantName;\n    public readonly string Code;\n    public readonly List<string> Dependencies;\n  }\n\n  public class UseRegionsArmadaProofDecl : ArmadaProofDecl\n  {\n    public override string WhatKind { get { return \"use regions\"; } }\n\n    public UseRegionsArmadaProofDecl(IToken tok, ModuleDefinition module)\n      : base(tok, module, null)\n    {\n    }\n  }\n\n  public class UseAddressInvariantArmadaProofDecl : ArmadaProofDecl\n  {\n    public override string WhatKind { get { return \"use address invariant\"; } }\n\n    public UseAddressInvariantArmadaProofDecl(IToken tok, ModuleDefinition module)\n      : base(tok, module, null)\n    {\n    }\n  }\n\n  public class CHLInvariantArmadaProofDecl : ArmadaProofDecl\n  {\n    public override string WhatKind { get { return \"Concurrent Hoare logic invariant\"; } }\n\n    public CHLInvariantArmadaProofDecl(IToken tok, ModuleDefinition module, IToken invariantName, string code, Attributes attrs)\n      : base(tok, module, attrs)\n    {\n      InvariantName = invariantName.val;\n      Code = Util.RemoveParsedStringQuotesSimple(code);\n    }\n\n    public readonly string InvariantName;\n    public readonly string Code;\n  }\n\n  public class CHLLocalInvariantArmadaProofDecl : ArmadaProofDecl\n  {\n    public override string WhatKind { get { return \"Concurrent Hoare logic local invariant clause\"; } }\n\n    public CHLLocalInvariantArmadaProofDecl(IToken tok, ModuleDefinition module, IToken pcName, IToken clauseName, string code,\n                                            Attributes attrs)\n      : base(tok, module, attrs)\n    {\n      PCName = pcName.val;\n      ClauseName = clauseName.val;\n      Code = Util.RemoveParsedStringQuotesSimple(code);\n    }\n\n    public readonly string PCName;\n    public readonly string ClauseName;\n    public readonly string Code;\n  }\n\n  public class CHLYieldPredicateArmadaProofDecl : ArmadaProofDecl\n  {\n\n    public override string WhatKind { get { return \"Concurrent Hoare logic yield predicate\"; } }\n\n    public CHLYieldPredicateArmadaProofDecl(IToken tok, ModuleDefinition module, IToken yieldPredicateName, string code, Attributes attrs) :\n      base(tok, module, attrs)\n    {\n      YieldPredicateName = yieldPredicateName.val;\n      Code = Util.RemoveParsedStringQuotesSimple(code);\n    }\n\n    public readonly string YieldPredicateName;\n    public readonly string Code;\n  }\n\n  public class CHLPreconditionArmadaProofDecl : ArmadaProofDecl\n  {\n    public override string WhatKind { get { return \"Concurrent Hoare logic precondition\"; } }\n\n    public CHLPreconditionArmadaProofDecl(IToken tok, ModuleDefinition module, IToken methodName, IToken preconditionName, string code,\n                                          Attributes attrs)\n      : base(tok, module, attrs)\n    {\n      MethodName = methodName.val;\n      PreconditionName = preconditionName.val;\n      Code = Util.RemoveParsedStringQuotesSimple(code);\n    }\n\n    public readonly string MethodName;\n    public readonly string PreconditionName;\n    public readonly string Code;\n  }\n\n  public class CHLPostconditionArmadaProofDecl : ArmadaProofDecl\n  {\n    public override string WhatKind { get { return \"Concurrent Hoare logic postcondition\"; } }\n\n    public CHLPostconditionArmadaProofDecl(IToken tok, ModuleDefinition module, IToken methodName, IToken postconditionName, string code,\n                                           Attributes attrs)\n      : base(tok, module, attrs)\n    {\n      MethodName = methodName.val;\n      PostconditionName = postconditionName.val;\n      Code = Util.RemoveParsedStringQuotesSimple(code);\n    }\n\n    public readonly string MethodName;\n    public readonly string PostconditionName;\n    public readonly string Code;\n  }\n\n  public class CHLLoopModifiesClauseArmadaProofDecl : ArmadaProofDecl\n  {\n    public override string WhatKind { get { return \"Concurrent Hoare logic loop modifies clause\"; } }\n\n    public CHLLoopModifiesClauseArmadaProofDecl(IToken tok, ModuleDefinition module, IToken pcName, IToken clauseName, string code,\n                                                Attributes attrs)\n      : base(tok, module, attrs)\n    {\n      PCName = pcName.val;\n      ClauseName = clauseName.val;\n      Code = Util.RemoveParsedStringQuotesSimple(code);\n    }\n\n    public readonly string PCName;\n    public readonly string ClauseName;\n    public readonly string Code;\n  }\n\n  public class AuxiliaryArmadaProofDecl : ArmadaProofDecl\n  {\n    public override string WhatKind { get { return \"auxiliary state\"; } }\n\n    public AuxiliaryArmadaProofDecl(IToken tok, ModuleDefinition module, string fieldName, string typeName,\n                                    string typeDefinitionCode, string initCode, string nextCode)\n      : base(tok, module, null)\n    {\n      FieldName = fieldName;\n      TypeName = Util.RemoveParsedStringQuotesSimple(typeName);\n      TypeDefinitionCode = Util.RemoveParsedStringQuotesSimple(typeDefinitionCode);\n      InitCode = Util.RemoveParsedStringQuotesSimple(initCode);\n      NextCode = Util.RemoveParsedStringQuotesSimple(nextCode);\n    }\n\n    public readonly string FieldName;\n    public readonly string TypeName;\n    public readonly string TypeDefinitionCode;\n    public readonly string InitCode;\n    public readonly string NextCode;\n  }\n\n  public abstract class StrategyDecl : ArmadaProofDecl\n  {\n    public override string WhatKind { get { return \"strategy\"; } }\n    public override bool CanBeRevealed() { return false; }\n    public StrategyDecl(IToken tok, ModuleDefinition module) : base(tok, module, null)\n    {\n    }\n  }\n\n  public class WeakeningStrategyDecl : StrategyDecl\n  {\n    public override string WhatKind { get { return \"weakening strategy\"; } }\n\n    public WeakeningStrategyDecl(IToken tok, ModuleDefinition module, List<IToken> labels) :\n      base(tok, module)\n    {\n      Labels = labels;\n    }\n\n    public readonly List<IToken> Labels;\n  }\n\n  public class StarWeakeningStrategyDecl : StrategyDecl\n  {\n    public override string WhatKind { get { return \"star weakening strategy\"; } }\n\n    public StarWeakeningStrategyDecl(IToken tok, ModuleDefinition module, List<IToken> labels, List<IToken> globalVars) :\n      base(tok, module)\n    {\n      Labels = labels;\n      GlobalVars = globalVars.Select(x => x.val).ToList();\n    }\n\n    public readonly List<IToken> Labels;\n    public readonly List<string> GlobalVars;\n  }\n\n  public class GlobalVariableHidingStrategyDecl : StrategyDecl\n  {\n    public override string WhatKind { get { return \"global variable hiding strategy\"; } }\n\n    public GlobalVariableHidingStrategyDecl(IToken tok, ModuleDefinition module, List<IToken> variables) :\n      base(tok, module)\n    {\n      Variables = variables.Select(v => v.val).ToList();\n    }\n\n    public readonly List<string> Variables;\n  }\n\n  public class StackVariableHidingStrategyDecl : StrategyDecl\n  {\n    public override string WhatKind { get { return \"stack variable hiding strategy\"; } }\n\n    public StackVariableHidingStrategyDecl(IToken tok, ModuleDefinition module, IToken methodName, List<IToken> variables) :\n      base(tok, module)\n    {\n      MethodName = methodName.val;\n      Variables = variables.Select(v => v.val).ToList();\n    }\n\n    public readonly string MethodName;\n    public readonly List<string> Variables;\n  }\n\n  public class GlobalVariableIntroStrategyDecl : StrategyDecl\n  {\n    public override string WhatKind { get { return \"global variable introduction strategy\"; } }\n\n    public GlobalVariableIntroStrategyDecl(IToken tok, ModuleDefinition module, List<IToken> variables) :\n      base(tok, module)\n    {\n      Variables = variables;\n    }\n\n    public readonly List<IToken> Variables;\n  }\n\n  public class StackVariableIntroStrategyDecl : StrategyDecl\n  {\n    public override string WhatKind { get { return \"stack variable introduction strategy\"; } }\n\n    public StackVariableIntroStrategyDecl(IToken tok, ModuleDefinition module, IToken methodName, IToken variableName,\n                                          string initializationExpression) :\n      base(tok, module)\n    {\n      MethodName = methodName.val;\n      VariableName = variableName.val;\n      if (initializationExpression == null) {\n        InitializationExpression = \"0\";\n      }\n      else {\n        InitializationExpression = Util.RemoveParsedStringQuotesSimple(initializationExpression);\n      }\n    }\n\n    public readonly string MethodName;\n    public readonly string VariableName;\n    public readonly string InitializationExpression;\n  }\n\n  public class ReductionStrategyDecl : StrategyDecl\n  {\n    public override string WhatKind { get { return \"reduction strategy\"; } }\n\n    public ReductionStrategyDecl(IToken tok, ModuleDefinition module, List<Tuple<string, string>> phase1_label_ranges,\n                                 List<Tuple<string, string>> phase2_label_ranges) :\n      base(tok, module)\n    {\n      Phase1LabelRanges = phase1_label_ranges;\n      Phase2LabelRanges = phase2_label_ranges;\n    }\n\n    public readonly List<Tuple<string, string>> Phase1LabelRanges;\n    public readonly List<Tuple<string, string>> Phase2LabelRanges;\n  }\n\n  public class CombiningStrategyDecl : StrategyDecl\n  {\n    public override string WhatKind { get { return \"combining strategy\"; } }\n\n    public CombiningStrategyDecl(IToken tok, ModuleDefinition module, IToken start_label, IToken end_label, IToken single_label) :\n      base(tok, module)\n    {\n      StartLabel = start_label;\n      EndLabel = end_label;\n      SingleLabel = single_label;\n    }\n\n    public readonly IToken StartLabel;\n    public readonly IToken EndLabel;\n    public readonly IToken SingleLabel;\n  }\n\n  public class FieldHidingStrategyDecl : StrategyDecl\n  {\n    public override string WhatKind { get { return \"field hiding strategy\"; } }\n\n    public FieldHidingStrategyDecl(IToken tok, ModuleDefinition module, IToken className, IToken fieldName) :\n      base(tok, module)\n    {\n      ClassName = className;\n      FieldName = fieldName;\n    }\n\n    public readonly IToken ClassName;\n    public readonly IToken FieldName;\n  }\n\n  public class FieldIntroStrategyDecl : StrategyDecl\n  {\n    public override string WhatKind { get { return \"field introduction strategy\"; } }\n\n    public FieldIntroStrategyDecl(IToken tok, ModuleDefinition module, IToken className, IToken fieldName) :\n      base(tok, module)\n    {\n      ClassName = className;\n      FieldName = fieldName;\n    }\n\n    public readonly IToken ClassName;\n    public readonly IToken FieldName;\n  }\n\n  public class AssumeIntroStrategyDecl : StrategyDecl\n  {\n    public override string WhatKind { get { return \"assume introduction strategy\"; } }\n\n    public AssumeIntroStrategyDecl(IToken tok, ModuleDefinition module, List<IToken> labels) :\n      base(tok, module)\n    {\n      Labels = labels;\n    }\n\n    public readonly List<IToken> Labels;\n  }\n\n  public class ConcurrentHoareLogicStrategyDecl : StrategyDecl\n  {\n    public override string WhatKind { get { return \"concurrent Hoare logic strategy\"; } }\n\n    public ConcurrentHoareLogicStrategyDecl(IToken tok, ModuleDefinition module) :\n      base(tok, module)\n    {\n    }\n  }\n\n  public class CriticalSectionStrategyDecl : StrategyDecl\n  {\n    public override string WhatKind { get { return \"critical section strategy\"; } }\n\n    public CriticalSectionStrategyDecl(IToken tok, ModuleDefinition module, IToken critSecPredicate) :\n      base(tok, module)\n    {\n      CritSecPredicate = critSecPredicate;\n    }\n\n    public readonly IToken CritSecPredicate;\n  }\n\n  public class TSOEliminationStrategyDecl : StrategyDecl\n  {\n    public override string WhatKind { get { return \"TSO elimination strategy\"; } }\n\n    public TSOEliminationStrategyDecl(IToken tok, ModuleDefinition module, List<IToken> fields, string ownershipPredicate) :\n      base(tok, module)\n    {\n      Fields = fields.Select(x => x.val).ToList();\n      OwnershipPredicate = Util.RemoveParsedStringQuotesSimple(ownershipPredicate);\n    }\n\n    public readonly List<string> Fields;\n    public readonly string OwnershipPredicate;\n  }\n\n  /// <summary>\n  /// An PrefixPredicate is the inductive unrolling P# implicitly declared for every fixpoint-predicate P.\n  /// </summary>\n  public class PrefixPredicate : Function\n  {\n    public override string WhatKind { get { return \"prefix predicate\"; } }\n    public readonly Formal K;\n    public readonly FixpointPredicate FixpointPred;\n    public PrefixPredicate(IToken tok, string name, bool hasStaticKeyword, bool isProtected,\n                     List<TypeParameter> typeArgs, Formal k, List<Formal> formals,\n                     List<MaybeFreeExpression> req, List<FrameExpression> reads, List<MaybeFreeExpression> ens, Specification<Expression> decreases,\n                     Expression body, Attributes attributes, FixpointPredicate fixpointPred)\n      : base(tok, name, hasStaticKeyword, isProtected, true, typeArgs, formals, null, Type.Bool, req, reads, ens, decreases, body, attributes, null) {\n      Contract.Requires(k != null);\n      Contract.Requires(fixpointPred != null);\n      Contract.Requires(formals != null && 1 <= formals.Count && formals[0] == k);\n      K = k;\n      FixpointPred = fixpointPred;\n    }\n  }\n\n  public abstract class FixpointPredicate : Function\n  {\n    public enum KType { Unspecified, Nat, ORDINAL }\n    public readonly KType TypeOfK;\n    public bool KNat {\n      get {\n        return TypeOfK == KType.Nat;\n      }\n    }\n    public readonly List<FunctionCallExpr> Uses = new List<FunctionCallExpr>();  // filled in during resolution, used by verifier\n    public PrefixPredicate PrefixPredicate;  // filled in during resolution (name registration)\n\n    public FixpointPredicate(IToken tok, string name, bool hasStaticKeyword, bool isProtected, KType typeOfK,\n                             List<TypeParameter> typeArgs, List<Formal> formals,\n                             List<MaybeFreeExpression> req, List<FrameExpression> reads, List<MaybeFreeExpression> ens,\n                             Expression body, Attributes attributes, IToken signatureEllipsis)\n      : base(tok, name, hasStaticKeyword, isProtected, true, typeArgs, formals, null, Type.Bool,\n             req, reads, ens, new Specification<Expression>(new List<Expression>(), null), body, attributes, signatureEllipsis) {\n      TypeOfK = typeOfK;\n    }\n\n    /// <summary>\n    /// For the given call P(s), return P#[depth](s).  The resulting expression shares some of the subexpressions\n    /// with 'fexp' (that is, what is returned is not necessarily a clone).\n    /// </summary>\n    public FunctionCallExpr CreatePrefixPredicateCall(FunctionCallExpr fexp, Expression depth) {\n      Contract.Requires(fexp != null);\n      Contract.Requires(fexp.Function == this);\n      Contract.Requires(depth != null);\n      Contract.Ensures(Contract.Result<FunctionCallExpr>() != null);\n\n      var args = new List<Expression>() { depth };\n      args.AddRange(fexp.Args);\n      var prefixPredCall = new FunctionCallExpr(fexp.tok, this.PrefixPredicate.Name, fexp.Receiver, fexp.OpenParen, args);\n      prefixPredCall.Function = this.PrefixPredicate;  // resolve here\n\n      prefixPredCall.TypeArgumentSubstitutions = new Dictionary<TypeParameter, Type>();\n      var old_to_new = new Dictionary<TypeParameter, TypeParameter>();\n      for (int i = 0; i < this.TypeArgs.Count; i++) {\n        old_to_new[this.TypeArgs[i]] = this.PrefixPredicate.TypeArgs[i];\n      }\n      foreach (var p in fexp.TypeArgumentSubstitutions) {\n        TypeParameter tp;\n        if (old_to_new.TryGetValue(p.Key, out tp)) {\n          // p.Key denotes a type parameter of the predicate\n          prefixPredCall.TypeArgumentSubstitutions[tp] = p.Value;\n        } else {\n          // p.Key denotes a type parameter of the enclosing class; it is the same for the prefix predicate\n          prefixPredCall.TypeArgumentSubstitutions[p.Key] = p.Value;\n        }\n      }  // resolved here.\n\n      prefixPredCall.Type = fexp.Type;  // resolve here\n      prefixPredCall.CoCall = fexp.CoCall;  // resolve here\n      return prefixPredCall;\n    }\n  }\n\n  public class InductivePredicate : FixpointPredicate\n  {\n    public override string WhatKind { get { return \"inductive predicate\"; } }\n    public InductivePredicate(IToken tok, string name, bool hasStaticKeyword, bool isProtected, KType typeOfK,\n                              List<TypeParameter> typeArgs, List<Formal> formals,\n                              List<MaybeFreeExpression> req, List<FrameExpression> reads, List<MaybeFreeExpression> ens,\n                              Expression body, Attributes attributes, IToken signatureEllipsis)\n      : base(tok, name, hasStaticKeyword, isProtected, typeOfK, typeArgs, formals,\n             req, reads, ens, body, attributes, signatureEllipsis) {\n    }\n  }\n\n  public class CoPredicate : FixpointPredicate\n  {\n    public override string WhatKind { get { return \"copredicate\"; } }\n    public CoPredicate(IToken tok, string name, bool hasStaticKeyword, bool isProtected, KType typeOfK,\n                       List<TypeParameter> typeArgs, List<Formal> formals,\n                       List<MaybeFreeExpression> req, List<FrameExpression> reads, List<MaybeFreeExpression> ens,\n                       Expression body, Attributes attributes, IToken signatureEllipsis)\n      : base(tok, name, hasStaticKeyword, isProtected, typeOfK, typeArgs, formals,\n             req, reads, ens, body, attributes, signatureEllipsis) {\n    }\n  }\n\n  public class TwoStateFunction : Function\n  {\n    public override string WhatKind { get { return \"twostate function\"; } }\n    public TwoStateFunction(IToken tok, string name, bool hasStaticKeyword,\n                     List<TypeParameter> typeArgs, List<Formal> formals, Formal result, Type resultType,\n                     List<MaybeFreeExpression> req, List<FrameExpression> reads, List<MaybeFreeExpression> ens, Specification<Expression> decreases,\n                     Expression body, Attributes attributes, IToken signatureEllipsis)\n      : base(tok, name, hasStaticKeyword, false, true, typeArgs, formals, result, resultType, req, reads, ens, decreases, body, attributes, signatureEllipsis) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Contract.Requires(typeArgs != null);\n      Contract.Requires(formals != null);\n      Contract.Requires(resultType != null);\n      Contract.Requires(req != null);\n      Contract.Requires(reads != null);\n      Contract.Requires(ens != null);\n      Contract.Requires(decreases != null);\n    }\n    public override bool ReadsHeap { get { return true; } }\n  }\n\n  public class TwoStatePredicate : TwoStateFunction\n  {\n    public override string WhatKind { get { return \"twostate predicate\"; } }\n    public TwoStatePredicate(IToken tok, string name, bool hasStaticKeyword,\n                     List<TypeParameter> typeArgs, List<Formal> formals,\n                     List<MaybeFreeExpression> req, List<FrameExpression> reads, List<MaybeFreeExpression> ens, Specification<Expression> decreases,\n                     Expression body, Attributes attributes, IToken signatureEllipsis)\n      : base(tok, name, hasStaticKeyword, typeArgs, formals, null, Type.Bool, req, reads, ens, decreases, body, attributes, signatureEllipsis) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Contract.Requires(typeArgs != null);\n      Contract.Requires(formals != null);\n      Contract.Requires(req != null);\n      Contract.Requires(reads != null);\n      Contract.Requires(ens != null);\n      Contract.Requires(decreases != null);\n    }\n  }\n\n  public class Method : MemberDecl, TypeParameter.ParentType, IMethodCodeContext\n  {\n    public override string WhatKind { get { return \"method\"; } }\n    public bool SignatureIsOmitted { get { return SignatureEllipsis != null; } }\n    public readonly IToken SignatureEllipsis;\n    public bool MustReverify;\n    public readonly List<TypeParameter> TypeArgs;\n    public readonly List<Formal> Ins;\n    public readonly List<Formal> Outs;\n    public readonly List<MaybeFreeExpression> Req;\n    public readonly Specification<FrameExpression> Mod;\n    public readonly List<MaybeFreeExpression> Ens;\n    public readonly Specification<Expression> Decreases;\n    public readonly Specification<Expression> Reads;\n    public readonly List<Expression> Awaits;\n    public readonly List<Expression> UndefinedUnless;\n    private BlockStmt methodBody;  // Body is readonly after construction, except for any kind of rewrite that may take place around the time of resolution (note that \"methodBody\" is a \"DividedBlockStmt\" for any \"Method\" that is a \"Constructor\")\n    public bool IsRecursive;  // filled in during resolution\n    public bool IsTailRecursive;  // filled in during resolution\n    public readonly ISet<IVariable> AssignedAssumptionVariables = new HashSet<IVariable>();\n    public Method OverriddenMethod;\n    private static BlockStmt emptyBody = new BlockStmt(Token.NoToken, Token.NoToken, new List<Statement>());\n    public NextRoutineConstructor externStartNextRoutineConstructor;\n    public NextRoutineConstructor externContinueNextRoutineConstructor;\n    public NextRoutineConstructor externEndNextRoutineConstructor;\n    public NextRoutineConstructor terminateNextRoutineConstructor;\n\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        foreach (var e in Req) {\n          yield return e.E;\n        }\n        foreach (var e in Mod.Expressions) {\n          yield return e.E;\n        }\n        foreach (var e in Ens) {\n          yield return e.E;\n        }\n        foreach (var e in Decreases.Expressions) {\n          yield return e;\n        }\n        foreach (var e in Reads.Expressions) {\n          yield return e;\n        }\n      }\n    }\n\n\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(cce.NonNullElements(TypeArgs));\n      Contract.Invariant(cce.NonNullElements(Ins));\n      Contract.Invariant(cce.NonNullElements(Outs));\n      Contract.Invariant(cce.NonNullElements(Req));\n      Contract.Invariant(Mod != null);\n      Contract.Invariant(cce.NonNullElements(Ens));\n      Contract.Invariant(Decreases != null);\n    }\n\n    public Method(IToken tok, string name,\n                  bool hasStaticKeyword, bool isGhost,\n                  [Captured] List<TypeParameter> typeArgs,\n                  [Captured] List<Formal> ins, [Captured] List<Formal> outs,\n                  [Captured] List<MaybeFreeExpression> req, [Captured] Specification<FrameExpression> mod,\n                  [Captured] List<MaybeFreeExpression> ens,\n                  [Captured] Specification<Expression> decreases,\n                  Specification<Expression> reads,\n                  List<Expression> awaits,\n                  List<Expression> undefinedUnless,\n                  [Captured] BlockStmt body,\n                  Attributes attributes, IToken signatureEllipsis)\n      : base(tok, name, hasStaticKeyword, isGhost, attributes) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Contract.Requires(cce.NonNullElements(typeArgs));\n      Contract.Requires(cce.NonNullElements(ins));\n      Contract.Requires(cce.NonNullElements(outs));\n      Contract.Requires(cce.NonNullElements(req));\n      Contract.Requires(mod != null);\n      Contract.Requires(cce.NonNullElements(ens));\n      Contract.Requires(decreases != null);\n      this.TypeArgs = typeArgs;\n      this.Ins = ins;\n      this.Outs = outs;\n      this.Req = req;\n      this.Mod = mod;\n      this.Ens = ens;\n      this.Decreases = decreases;\n      this.Reads = reads;\n      this.Awaits = awaits;\n      this.UndefinedUnless = undefinedUnless;\n      this.methodBody = body;\n      this.SignatureEllipsis = signatureEllipsis;\n      MustReverify = false;\n    }\n\n    bool ICodeContext.IsGhost { get { return this.IsGhost; } }\n    List<TypeParameter> ICodeContext.TypeArgs { get { return this.TypeArgs; } }\n    List<Formal> ICodeContext.Ins { get { return this.Ins; } }\n    List<Formal> IMethodCodeContext.Outs { get { return this.Outs; } }\n    Specification<FrameExpression> IMethodCodeContext.Modifies { get { return Mod; } }\n    IToken ICallable.Tok { get { return this.tok; } }\n    string ICallable.NameRelativeToModule {\n      get {\n        if (EnclosingClass is DefaultClassDecl) {\n          return Name;\n        } else {\n          return EnclosingClass.Name + \".\" + Name;\n        }\n      }\n    }\n    Specification<Expression> ICallable.Decreases { get { return this.Decreases; } }\n    bool _inferredDecr;\n    bool ICallable.InferredDecreases {\n      set { _inferredDecr = value; }\n      get { return _inferredDecr; }\n    }\n\n    ModuleDefinition ICodeContext.EnclosingModule {\n      get {\n        Contract.Assert(this.EnclosingClass != null);  // this getter is supposed to be called only after signature-resolution is complete\n        return this.EnclosingClass.Module;\n      }\n    }\n    bool ICodeContext.MustReverify { get { return this.MustReverify; } }\n    public bool AllowsNontermination {\n      get {\n        return Contract.Exists(Decreases.Expressions, e => e is WildcardExpr);\n      }\n    }\n\n    public override string CompileName {\n      get {\n        var nm = base.CompileName;\n        if (IsStatic && nm == \"Main\" && !Microsoft.Armada.Compiler.IsMain(this)) {\n          // for a static method that is named \"Main\" but is not a legal \"Main\" method,\n          // change its name.\n          nm = EnclosingClass.Name + \"_\" + nm;\n        }\n        return nm;\n      }\n    }\n\n    public BlockStmt Body {\n      get {\n        // Lemma from included files do not need to be resolved and translated\n        // so we return emptyBody. This is to speed up resolvor and translator.\n        if (methodBody != null && (this is Lemma || this is TwoStateLemma) && this.tok is IncludeToken && !ArmadaOptions.O.VerifyAllModules) {\n          return Method.emptyBody;\n        } else {\n          return methodBody;\n        }\n      }\n      set {\n        methodBody = value;\n      }\n    }\n\n    public BlockStmt BodyForRefinement {\n      // For refinement, we still need to merge in the body\n      // a lemma that is in the refinement base that is defined\n      // in a include file.\n      get {\n        return methodBody;\n      }\n    }\n  }\n\n  public class Lemma : Method\n  {\n    public override string WhatKind { get { return \"lemma\"; } }\n    public Lemma(IToken tok, string name,\n                 bool hasStaticKeyword,\n                 [Captured] List<TypeParameter> typeArgs,\n                 [Captured] List<Formal> ins, [Captured] List<Formal> outs,\n                 [Captured] List<MaybeFreeExpression> req, [Captured] Specification<FrameExpression> mod,\n                 [Captured] List<MaybeFreeExpression> ens,\n                 [Captured] Specification<Expression> decreases,\n                 [Captured] BlockStmt body,\n                 Attributes attributes, IToken signatureEllipsis)\n      : base(tok, name, hasStaticKeyword, true, typeArgs, ins, outs, req, mod, ens, decreases, new Specification<Expression>(new List<Expression>(), null), new List<Expression>(), new List<Expression>(), body, attributes, signatureEllipsis) {\n    }\n  }\n\n  public class TwoStateLemma : Method\n  {\n    public override string WhatKind { get { return \"twostate lemma\"; } }\n    public TwoStateLemma(IToken tok, string name,\n                 bool hasStaticKeyword,\n                 [Captured] List<TypeParameter> typeArgs,\n                 [Captured] List<Formal> ins, [Captured] List<Formal> outs,\n                 [Captured] List<MaybeFreeExpression> req,\n                 [Captured] Specification<FrameExpression> mod,\n                 [Captured] List<MaybeFreeExpression> ens,\n                 [Captured] Specification<Expression> decreases,\n                 [Captured] BlockStmt body,\n                 Attributes attributes, IToken signatureEllipsis)\n      : base(tok, name, hasStaticKeyword, true, typeArgs, ins, outs, req, mod, ens, decreases, new Specification<Expression>(new List<Expression>(), null), new List<Expression>(), new List<Expression>(), body, attributes, signatureEllipsis) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Contract.Requires(typeArgs != null);\n      Contract.Requires(ins != null);\n      Contract.Requires(outs != null);\n      Contract.Requires(req != null);\n      Contract.Requires(mod != null);\n      Contract.Requires(ens != null);\n      Contract.Requires(decreases != null);\n    }\n  }\n\n  public class Constructor : Method\n  {\n    public override string WhatKind { get { return \"constructor\"; } }\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(Body == null || Body is DividedBlockStmt);\n    }\n    public List<Statement> BodyInit {  // first part of Body's statements\n      get {\n        if (Body == null) {\n          return null;\n        } else {\n          return ((DividedBlockStmt)Body).BodyInit;\n        }\n      }\n    }\n    public List<Statement> BodyProper {  // second part of Body's statements\n      get {\n        if (Body == null) {\n          return null;\n        } else {\n          return ((DividedBlockStmt)Body).BodyProper;\n        }\n      }\n    }\n    public Constructor(IToken tok, string name,\n                  List<TypeParameter> typeArgs,\n                  List<Formal> ins,\n                  List<MaybeFreeExpression> req, [Captured] Specification<FrameExpression> mod,\n                  List<MaybeFreeExpression> ens,\n                  Specification<Expression> decreases,\n                  DividedBlockStmt body,\n                  Attributes attributes, IToken signatureEllipsis)\n      : base(tok, name, false, false, typeArgs, ins, new List<Formal>(), req, mod, ens, decreases, new Specification<Expression>(new List<Expression>(), null), new List<Expression>(), new List<Expression>(), body, attributes, signatureEllipsis) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Contract.Requires(cce.NonNullElements(typeArgs));\n      Contract.Requires(cce.NonNullElements(ins));\n      Contract.Requires(cce.NonNullElements(req));\n      Contract.Requires(mod != null);\n      Contract.Requires(cce.NonNullElements(ens));\n      Contract.Requires(decreases != null);\n    }\n\n    public bool HasName {\n      get {\n        return Name != \"_ctor\";\n      }\n    }\n  }\n\n  public class Destructor : Method\n  {\n    public override string WhatKind { get { return \"destructor\"; } }\n\n    public Destructor(IToken tok, string name,\n                  List<TypeParameter> typeArgs,\n                  List<Formal> ins,\n                  List<MaybeFreeExpression> req, [Captured] Specification<FrameExpression> mod,\n                  List<MaybeFreeExpression> ens,\n                  Specification<Expression> decreases,\n                  BlockStmt body,\n                  Attributes attributes, IToken signatureEllipsis)\n      : base(tok, name, false, false, typeArgs, ins, new List<Formal>(), req, mod, ens, decreases, new Specification<Expression>(new List<Expression>(), null), new List<Expression>(), new List<Expression>(), body, attributes, signatureEllipsis) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Contract.Requires(cce.NonNullElements(typeArgs));\n      Contract.Requires(cce.NonNullElements(ins));\n      Contract.Requires(cce.NonNullElements(req));\n      Contract.Requires(mod != null);\n      Contract.Requires(cce.NonNullElements(ens));\n      Contract.Requires(decreases != null);\n    }\n\n    public bool HasName {\n      get {\n        return Name != \"_dtor\";\n      }\n    }\n  }\n\n  /// <summary>\n  /// A PrefixLemma is the inductive unrolling M# implicitly declared for every colemma M.\n  /// </summary>\n  public class PrefixLemma : Method\n  {\n    public override string WhatKind { get { return \"prefix lemma\"; } }\n    public readonly Formal K;\n    public readonly FixpointLemma FixpointLemma;\n    public PrefixLemma(IToken tok, string name, bool hasStaticKeyword,\n                       List<TypeParameter> typeArgs, Formal k, List<Formal> ins, List<Formal> outs,\n                       List<MaybeFreeExpression> req, Specification<FrameExpression> mod, List<MaybeFreeExpression> ens, Specification<Expression> decreases,\n                       BlockStmt body, Attributes attributes, FixpointLemma fixpointLemma)\n      : base(tok, name, hasStaticKeyword, true, typeArgs, ins, outs, req, mod, ens, decreases, new Specification<Expression>(new List<Expression>(), null), new List<Expression>(), new List<Expression>(), body, attributes, null) {\n      Contract.Requires(k != null);\n      Contract.Requires(ins != null && 1 <= ins.Count && ins[0] == k);\n      Contract.Requires(fixpointLemma != null);\n      K = k;\n      FixpointLemma = fixpointLemma;\n    }\n  }\n\n  public abstract class FixpointLemma : Method\n  {\n    public readonly FixpointPredicate.KType TypeOfK;\n    public bool KNat {\n      get {\n        return TypeOfK == FixpointPredicate.KType.Nat;\n      }\n    }\n    public PrefixLemma PrefixLemma;  // filled in during resolution (name registration)\n\n    public FixpointLemma(IToken tok, string name,\n                         bool hasStaticKeyword, FixpointPredicate.KType typeOfK,\n                         List<TypeParameter> typeArgs,\n                         List<Formal> ins, [Captured] List<Formal> outs,\n                         List<MaybeFreeExpression> req, [Captured] Specification<FrameExpression> mod,\n                         List<MaybeFreeExpression> ens,\n                         Specification<Expression> decreases,\n                         BlockStmt body,\n                         Attributes attributes, IToken signatureEllipsis)\n      : base(tok, name, hasStaticKeyword, true, typeArgs, ins, outs, req, mod, ens, decreases, new Specification<Expression>(new List<Expression>(), null), new List<Expression>(), new List<Expression>(), body, attributes, signatureEllipsis) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Contract.Requires(cce.NonNullElements(typeArgs));\n      Contract.Requires(cce.NonNullElements(ins));\n      Contract.Requires(cce.NonNullElements(outs));\n      Contract.Requires(cce.NonNullElements(req));\n      Contract.Requires(mod != null);\n      Contract.Requires(cce.NonNullElements(ens));\n      Contract.Requires(decreases != null);\n      TypeOfK = typeOfK;\n    }\n  }\n\n  public class InductiveLemma : FixpointLemma\n  {\n    public override string WhatKind { get { return \"inductive lemma\"; } }\n\n    public InductiveLemma(IToken tok, string name,\n                          bool hasStaticKeyword, FixpointPredicate.KType typeOfK,\n                          List<TypeParameter> typeArgs,\n                          List<Formal> ins, [Captured] List<Formal> outs,\n                          List<MaybeFreeExpression> req, [Captured] Specification<FrameExpression> mod,\n                          List<MaybeFreeExpression> ens,\n                          Specification<Expression> decreases,\n                          BlockStmt body,\n                          Attributes attributes, IToken signatureEllipsis)\n      : base(tok, name, hasStaticKeyword, typeOfK, typeArgs, ins, outs, req, mod, ens, decreases, body, attributes, signatureEllipsis) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Contract.Requires(cce.NonNullElements(typeArgs));\n      Contract.Requires(cce.NonNullElements(ins));\n      Contract.Requires(cce.NonNullElements(outs));\n      Contract.Requires(cce.NonNullElements(req));\n      Contract.Requires(mod != null);\n      Contract.Requires(cce.NonNullElements(ens));\n      Contract.Requires(decreases != null);\n    }\n  }\n\n  public class CoLemma : FixpointLemma\n  {\n    public override string WhatKind { get { return \"colemma\"; } }\n\n    public CoLemma(IToken tok, string name,\n                   bool hasStaticKeyword, FixpointPredicate.KType typeOfK,\n                   List<TypeParameter> typeArgs,\n                   List<Formal> ins, [Captured] List<Formal> outs,\n                   List<MaybeFreeExpression> req, [Captured] Specification<FrameExpression> mod,\n                   List<MaybeFreeExpression> ens,\n                   Specification<Expression> decreases,\n                   BlockStmt body,\n                   Attributes attributes, IToken signatureEllipsis)\n      : base(tok, name, hasStaticKeyword, typeOfK, typeArgs, ins, outs, req, mod, ens, decreases, body, attributes, signatureEllipsis) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Contract.Requires(cce.NonNullElements(typeArgs));\n      Contract.Requires(cce.NonNullElements(ins));\n      Contract.Requires(cce.NonNullElements(outs));\n      Contract.Requires(cce.NonNullElements(req));\n      Contract.Requires(mod != null);\n      Contract.Requires(cce.NonNullElements(ens));\n      Contract.Requires(decreases != null);\n    }\n  }\n\n  // ------------------------------------------------------------------------------------------------------\n\n  public abstract class Statement : IAttributeBearingDeclaration\n  {\n    public readonly IToken Tok;\n    public readonly IToken EndTok;  // typically a terminating semi-colon or end-curly-brace\n    public LList<Label> Labels;  // mutable during resolution\n\n    private Attributes attributes;\n    public Attributes Attributes {\n      get {\n        return attributes;\n      }\n      set {\n        attributes = value;\n      }\n    }\n\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(Tok != null);\n      Contract.Invariant(EndTok != null);\n    }\n\n    public bool IsGhost;  // filled in by resolution\n    public ArmadaStatement Parsed;\n\n    public Statement(IToken tok, IToken endTok, Attributes attrs) {\n      Contract.Requires(tok != null);\n      Contract.Requires(endTok != null);\n      this.Tok = tok;\n      this.EndTok = endTok;\n      this.attributes = attrs;\n      this.Parsed = null;\n    }\n\n    public Statement(IToken tok, IToken endTok)\n      : this(tok, endTok, null) {\n      Contract.Requires(tok != null);\n      Contract.Requires(endTok != null);\n    }\n\n    /// <summary>\n    /// Returns the non-null substatements of the Statements.\n    /// </summary>\n    public virtual IEnumerable<Statement> SubStatements {\n      get { yield break; }\n    }\n\n    /// <summary>\n    /// Returns the non-null expressions of this statement proper (that is, do not include the expressions of substatements).\n    /// </summary>\n    public virtual IEnumerable<Expression> SubExpressions {\n      get {\n        foreach (var e in Attributes.SubExpressions(Attributes)) {\n          yield return e;\n        }\n      }\n    }\n  }\n\n  public class LList<T>\n  {\n    public readonly T Data;\n    public readonly LList<T> Next;\n    const LList<T> Empty = null;\n\n    public LList(T d, LList<T> next) {\n      Data = d;\n      Next = next;\n    }\n\n    public static LList<T> Append(LList<T> a, LList<T> b) {\n      if (a == null) return b;\n      return new LList<T>(a.Data, Append(a.Next, b));\n      // pretend this is ML\n    }\n    public static int Count(LList<T> n) {\n      int count = 0;\n      while (n != null) {\n        count++;\n        n = n.Next;\n      }\n      return count;\n    }\n  }\n\n  public class Label\n  {\n    public readonly IToken Tok;\n    public readonly string Name;\n    string uniqueId = null;\n    public string AssignUniqueId(FreshIdGenerator idGen)\n    {\n      if (uniqueId == null)\n      {\n        uniqueId = idGen.FreshNumericId(\"label\");\n      }\n      return uniqueId;\n    }\n    public Label(IToken tok, string/*?*/ label) {\n      Contract.Requires(tok != null);\n      Tok = tok;\n      Name = label;\n    }\n  }\n\n  public class AssertLabel : Label\n  {\n    public Boogie.Expr E;  // filled in during translation\n    public AssertLabel(IToken tok, string label)\n      : base(tok, label) {\n      Contract.Requires(tok != null);\n      Contract.Requires(label != null);\n    }\n  }\n\n  public abstract class PredicateStmt : Statement\n  {\n    public readonly Expression Expr;\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(Expr != null);\n    }\n\n    public PredicateStmt(IToken tok, IToken endTok, Expression expr, Attributes attrs)\n      : base(tok, endTok, attrs) {\n      Contract.Requires(tok != null);\n      Contract.Requires(endTok != null);\n      Contract.Requires(expr != null);\n      this.Expr = expr;\n    }\n\n    public PredicateStmt(IToken tok, IToken endTok, Expression expr)\n      : this(tok, endTok, expr, null) {\n      Contract.Requires(tok != null);\n      Contract.Requires(endTok != null);\n      Contract.Requires(expr != null);\n      this.Expr = expr;\n    }\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        foreach (var e in base.SubExpressions) { yield return e; }\n        yield return Expr;\n      }\n    }\n  }\n\n  public class AssertStmt : PredicateStmt {\n    public readonly BlockStmt Proof;\n    public readonly AssertLabel Label;\n    public AssertStmt(IToken tok, IToken endTok, Expression expr, BlockStmt/*?*/ proof, AssertLabel/*?*/ label, Attributes attrs)\n      : base(tok, endTok, expr, attrs) {\n      Contract.Requires(tok != null);\n      Contract.Requires(endTok != null);\n      Contract.Requires(expr != null);\n      Proof = proof;\n      Label = label;\n    }\n    public override IEnumerable<Statement> SubStatements {\n      get {\n        if (Proof != null) {\n          yield return Proof;\n        }\n      }\n    }\n    public void AddCustomizedErrorMessage(IToken tok, string s) {\n      var args = new List<Expression>() { new StringLiteralExpr(tok, s, true) };\n      IToken openBrace = tok;\n      IToken closeBrace = new Token(tok.line, tok.col + 7 + s.Length + 1); // where 7 = length(\":error \")\n      this.Attributes = new UserSuppliedAttributes(tok, openBrace, closeBrace, args, this.Attributes);\n    }\n  }\n\n  public class AssumeStmt : PredicateStmt {\n    public AssumeStmt(IToken tok, IToken endTok, Expression expr, Attributes attrs)\n      : base(tok, endTok, expr, attrs) {\n      Contract.Requires(tok != null);\n      Contract.Requires(endTok != null);\n      Contract.Requires(expr != null);\n    }\n  }\n\n  public class PrintStmt : Statement {\n    public readonly List<Expression> Args;\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(cce.NonNullElements(Args));\n    }\n\n    public PrintStmt(IToken tok, IToken endTok, List<Expression> args)\n      : base(tok, endTok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(endTok != null);\n      Contract.Requires(cce.NonNullElements(args));\n\n      Args = args;\n    }\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        foreach (var e in base.SubExpressions) { yield return e; }\n        foreach (var arg in Args) {\n          yield return arg;\n        }\n      }\n    }\n  }\n\n  public class RevealStmt : Statement\n  {\n    public readonly List<Expression> Exprs;\n    public readonly List<AssertLabel> LabeledAsserts = new List<AssertLabel>();  // contents filled in during resolution to indicate that \"Expr\" denotes a labeled assertion\n    public readonly List<Statement> ResolvedStatements = new List<Statement>(); // contents filled in during resolution\n\n    public override IEnumerable<Statement> SubStatements {\n      get { return ResolvedStatements; }\n    }\n\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(Exprs != null);\n      Contract.Invariant(LabeledAsserts.Count <= Exprs.Count);\n    }\n\n    public RevealStmt(IToken tok, IToken endTok, List<Expression> exprs)\n      : base(tok, endTok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(endTok != null);\n      Contract.Requires(exprs != null);\n      this.Exprs = exprs;\n    }\n\n    public static string SingleName(Expression e) {\n      Contract.Requires(e != null);\n      if (e is NameSegment || e is LiteralExpr) {\n        return e.tok.val;\n      } else {\n        return null;\n      }\n    }\n  }\n\n  public class SomehowStmt : Statement\n  {\n    public readonly List<Expression> UndefinedUnless;\n    public readonly Specification<Expression> Mod;\n    public readonly List<Expression> Ens;\n\n    public SomehowStmt(IToken tok, IToken endTok, List<Expression> undefinedUnless, Specification<Expression> mod,\n                       List<Expression> ens) : base(tok, endTok)\n    {\n      Contract.Requires(tok != null);\n      Contract.Requires(endTok != null);\n      Contract.Requires(undefinedUnless != null);\n      Contract.Requires(mod != null);\n      Contract.Requires(ens != null);\n\n      this.UndefinedUnless = undefinedUnless;\n      this.Mod = mod;\n      this.Ens = ens;\n    }\n  }\n\n  public class FenceStmt : Statement\n  {\n    public FenceStmt(IToken tok, IToken endTok) : base(tok, endTok)\n    {\n      Contract.Requires(tok != null);\n      Contract.Requires(endTok != null);\n    }\n  }\n\n  public class GotoStmt : Statement\n  {\n    public readonly string Target;\n    public Label TargetLabel;\n\n    public GotoStmt(IToken tok, IToken endTok, string target) : base(tok, endTok)\n    {\n      Contract.Requires(tok != null);\n      Contract.Requires(endTok != null);\n      Contract.Requires(target != null);\n      Target = target;\n    }\n  }\n\n  public class DeallocStmt : Statement\n  {\n    public readonly Expression Addr;\n\n    public DeallocStmt(IToken tok, IToken endTok, Expression addr) : base(tok, endTok)\n    {\n      Contract.Requires(tok != null);\n      Contract.Requires(endTok != null);\n      Contract.Requires(addr != null);\n\n      this.Addr = addr;\n    }\n  }\n\n  public class BreakStmt : Statement {\n    public readonly string TargetLabel;\n    public readonly int BreakCount;\n    public Statement TargetStmt;  // filled in during resolution\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(TargetLabel != null || 1 <= BreakCount);\n    }\n\n    public BreakStmt(IToken tok, IToken endTok, string targetLabel)\n      : base(tok, endTok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(endTok != null);\n      Contract.Requires(targetLabel != null);\n      this.TargetLabel = targetLabel;\n    }\n    public BreakStmt(IToken tok, IToken endTok, int breakCount)\n      : base(tok, endTok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(endTok != null);\n      Contract.Requires(1 <= breakCount);\n      this.BreakCount = breakCount;\n    }\n  }\n\n  public class ContinueStmt : Statement {\n    public ContinueStmt(IToken tok, IToken endTok)\n      : base(tok, endTok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(endTok != null);\n    }\n  }\n\n  public abstract class ProduceStmt : Statement\n  {\n    public List<AssignmentRhs> rhss;\n    public UpdateStmt hiddenUpdate;\n    public ProduceStmt(IToken tok, IToken endTok, List<AssignmentRhs> rhss)\n      : base(tok, endTok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(endTok != null);\n      this.rhss = rhss;\n      hiddenUpdate = null;\n    }\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        foreach (var e in base.SubExpressions) { yield return e; }\n        if (rhss != null) {\n          foreach (var rhs in rhss) {\n            foreach (var ee in rhs.SubExpressions) {\n              yield return ee;\n            }\n          }\n        }\n      }\n    }\n    public override IEnumerable<Statement> SubStatements {\n      get {\n        if (rhss != null) {\n          foreach (var rhs in rhss) {\n            foreach (var s in rhs.SubStatements) {\n              yield return s;\n            }\n          }\n        }\n      }\n    }\n  }\n\n  public class ReturnStmt : ProduceStmt\n  {\n    public bool ReverifyPost;  // set during pre-resolution refinement transformation\n    public ReturnStmt(IToken tok, IToken endTok, List<AssignmentRhs> rhss)\n      : base(tok, endTok, rhss) {\n      Contract.Requires(tok != null);\n      Contract.Requires(endTok != null);\n    }\n  }\n\n  public class YieldStmt : ProduceStmt\n  {\n    public YieldStmt(IToken tok, IToken endTok, List<AssignmentRhs> rhss)\n      : base(tok, endTok, rhss) {\n      Contract.Requires(tok != null);\n      Contract.Requires(endTok != null);\n    }\n  }\n\n  public abstract class AssignmentRhs\n  {\n    public readonly IToken Tok;\n\n    private Attributes attributes;\n    public Attributes Attributes\n    {\n      get\n      {\n        return attributes;\n      }\n      set\n      {\n        attributes = value;\n      }\n    }\n\n    public bool HasAttributes()\n    {\n      return Attributes != null;\n    }\n\n    internal AssignmentRhs(IToken tok, Attributes attrs = null) {\n      Tok = tok;\n      Attributes = attrs;\n    }\n    public abstract bool CanAffectPreviouslyKnownExpressions { get; }\n    /// <summary>\n    /// Returns the non-null subexpressions of the AssignmentRhs.\n    /// </summary>\n    public virtual IEnumerable<Expression> SubExpressions {\n      get {\n        foreach (var e in Attributes.SubExpressions(Attributes)) {\n          yield return e;\n        }\n      }\n    }\n    /// <summary>\n    /// Returns the non-null sub-statements of the AssignmentRhs.\n    /// </summary>\n    public virtual IEnumerable<Statement> SubStatements{\n      get { yield break; }\n    }\n  }\n\n  public class ExprRhs : AssignmentRhs\n  {\n    public readonly Expression Expr;\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(Expr != null);\n    }\n\n    public ExprRhs(Expression expr, Attributes attrs = null)  // TODO: these 'attrs' apparently aren't handled correctly in the Cloner, and perhaps not in various visitors either (for example, CheckIsCompilable should not go into attributes)\n      : base(expr.tok, attrs)\n    {\n      Contract.Requires(expr != null);\n      Expr = expr;\n    }\n    public override bool CanAffectPreviouslyKnownExpressions { get { return false; } }\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        yield return Expr;\n      }\n    }\n  }\n\n  /// <summary>\n  /// A TypeRhs represents one of five things, each having to do with allocating something in the heap:\n  ///  * new T[EE]\n  ///    This allocates an array of objects of type T (where EE is a list of expression)\n  ///  * new T[EE] (elementInit)\n  ///    This is like the previous, but uses \"elementInit\" to initialize the elements of the new array.\n  ///  * new T[E] [EE]\n  ///    This is like the first one, but uses the elements displayed in the list EE as the initial\n  ///    elements of the array.  Only a 1-dimensional array may be used in this case.  The size denoted\n  ///    by E must equal the length of EE.\n  ///  * new C\n  ///    This allocates an object of type C\n  ///  * new C.Init(EE)\n  ///    This allocates an object of type C and then invokes the method/constructor Init on it\n  /// There are three ways to construct a TypeRhs syntactically:\n  ///  * TypeRhs(T, EE, initExpr)\n  ///      -- represents \"new T[EE]\" (with \"elementInit\" being \"null\") and \"new T[EE] (elementInit)\"\n  ///  * TypeRhs(T, E, EE)\n  ///      -- represents \"new T[E] [EE]\"\n  ///  * TypeRhs(C)\n  ///      -- represents new C\n  ///  * TypeRhs(Path, EE)\n  ///    Here, Path may either be of the form C.Init\n  ///      -- represents new C.Init(EE)\n  ///    or all of Path denotes a type\n  ///      -- represents new C._ctor(EE), where _ctor is the anonymous constructor for class C\n  /// </summary>\n  public class TypeRhs : AssignmentRhs\n  {\n    /// <summary>\n    /// If ArrayDimensions != null, then the TypeRhs represents \"new EType[ArrayDimensions]\",\n    ///     ElementInit is non-null to represent \"new EType[ArrayDimensions] (elementInit)\",\n    ///     InitDisplay is non-null to represent \"new EType[ArrayDimensions] [InitDisplay]\",\n    ///     and Arguments, Path, and InitCall are all null.\n    /// If ArrayDimentions == null && Arguments == null, then the TypeRhs represents \"new EType\"\n    ///     and ElementInit, Path, and InitCall are all null.\n    /// If Arguments != null, then the TypeRhs represents \"new Path(Arguments)\"\n    ///     and EType and InitCall is filled in by resolution, and ArrayDimensions == null and ElementInit == null.\n    /// If OptionalNameComponent == null and Arguments != null, then the TypeRHS has not been resolved yet;\n    ///   resolution will either produce an error or will chop off the last part of \"EType\" and move it to\n    ///   OptionalNameComponent, after which the case above applies.\n    /// </summary>\n    public Type EType;  // in the case of Arguments != null, EType is filled in during resolution\n    public readonly List<Expression> ArrayDimensions;\n    public readonly Expression ElementInit;\n    public readonly List<Expression> InitDisplay;\n    public readonly List<Expression> Arguments;\n    public Type Path;\n    public CallStmt InitCall;  // may be null (and is definitely null for arrays), may be filled in during resolution\n    public Type Type;  // filled in during resolution\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(EType != null || Arguments != null);\n      Contract.Invariant(ElementInit == null || InitDisplay == null);\n      Contract.Invariant(InitDisplay == null || ArrayDimensions.Count == 1);\n      Contract.Invariant(ArrayDimensions == null || (Arguments == null && Path == null && InitCall == null && 1 <= ArrayDimensions.Count));\n      Contract.Invariant(Arguments == null || (Path != null && ArrayDimensions == null && ElementInit == null && InitDisplay == null));\n      Contract.Invariant(!(ArrayDimensions == null && Arguments == null) || (Path == null && InitCall == null && ElementInit == null && InitDisplay == null));\n    }\n\n    public TypeRhs(IToken tok, Type type, List<Expression> arrayDimensions, Expression elementInit)\n      : base(tok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(type != null);\n      Contract.Requires(arrayDimensions != null && 1 <= arrayDimensions.Count);\n      EType = type;\n      ArrayDimensions = arrayDimensions;\n      ElementInit = elementInit;\n    }\n    public TypeRhs(IToken tok, Type type, Expression dim, List<Expression> initDisplay)\n      : base(tok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(type != null);\n      Contract.Requires(dim != null);\n      Contract.Requires(initDisplay != null);\n      EType = type;\n      ArrayDimensions = new List<Expression> { dim };\n      InitDisplay = initDisplay;\n    }\n    public TypeRhs(IToken tok, Type type)\n      : base(tok)\n    {\n      Contract.Requires(tok != null);\n      Contract.Requires(type != null);\n      EType = type;\n    }\n    public TypeRhs(IToken tok, Type path, List<Expression> arguments, bool disambiguatingDummy)\n      : base(tok)\n    {\n      Contract.Requires(tok != null);\n      Contract.Requires(path != null);\n      Contract.Requires(arguments != null);\n      Path = path;\n      Arguments = arguments;\n    }\n    public override bool CanAffectPreviouslyKnownExpressions {\n      get {\n        if (InitCall != null) {\n          foreach (var mod in InitCall.Method.Mod.Expressions) {\n            if (!(mod.E is ThisExpr)) {\n              return true;\n            }\n          }\n        }\n        return false;\n      }\n    }\n\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        if (ArrayDimensions != null) {\n          foreach (var e in ArrayDimensions) {\n            yield return e;\n          }\n          if (ElementInit != null) {\n            yield return ElementInit;\n          }\n          if (InitDisplay != null) {\n            foreach (var e in InitDisplay) {\n              yield return e;\n            }\n          }\n        }\n      }\n    }\n    public override IEnumerable<Statement> SubStatements {\n      get {\n        if (InitCall != null) {\n          yield return InitCall;\n        }\n      }\n    }\n  }\n\n  public class HavocRhs : AssignmentRhs {\n    public HavocRhs(IToken tok)\n      : base(tok)\n    {\n    }\n    public override bool CanAffectPreviouslyKnownExpressions { get { return false; } }\n  }\n\n  public class CreateThreadRhs : AssignmentRhs {\n    public CreateThreadRhs(IToken tok, IToken methodName, List<Expression> args)\n      : base(tok)\n    {\n       MethodName = methodName;\n       Args = args;\n    }\n\n    public readonly IToken MethodName;\n    public readonly List<Expression> Args;\n\n    public override bool CanAffectPreviouslyKnownExpressions { get { return false; } }\n\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        foreach (var arg in Args) {\n          yield return arg;\n        }\n      }\n    }\n  }\n\n  public class MallocRhs : AssignmentRhs {\n    public MallocRhs(IToken tok, Type allocatedType)\n      : base(tok)\n    {\n      AllocatedType = allocatedType;\n    }\n\n    public readonly Type AllocatedType;\n\n    public override bool CanAffectPreviouslyKnownExpressions { get { return false; } }\n  }\n\n  public class CallocRhs : AssignmentRhs {\n    public CallocRhs(IToken tok, Type allocatedType, Expression count)\n      : base(tok)\n    {\n      AllocatedType = allocatedType;\n      Count = count;\n    }\n\n    public readonly Type AllocatedType;\n    public readonly Expression Count;\n\n    public override bool CanAffectPreviouslyKnownExpressions { get { return false; } }\n  }\n\n  public class CompareAndSwapRhs : AssignmentRhs {\n    public CompareAndSwapRhs(IToken tok, Expression target, Expression oldval, Expression newval)\n      : base(tok)\n    {\n      Target = target;\n      OldVal = oldval;\n      NewVal = newval;\n    }\n\n    public readonly Expression Target;\n    public readonly Expression OldVal;\n    public readonly Expression NewVal;\n\n    public override bool CanAffectPreviouslyKnownExpressions { get { return false; } }\n\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        yield return Target;\n        yield return OldVal;\n        yield return NewVal;\n      }\n    }\n  }\n\n  public class AtomicExchangeRhs : AssignmentRhs {\n    public AtomicExchangeRhs(IToken tok, Expression target, Expression newval)\n      : base(tok)\n    {\n      Target = target;\n      NewVal = newval;\n    }\n\n    public readonly Expression Target;\n    public readonly Expression NewVal;\n\n    public override bool CanAffectPreviouslyKnownExpressions { get { return false; } }\n\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        yield return Target;\n        yield return NewVal;\n      }\n    }\n  }\n\n  public class VarDeclStmt : Statement\n  {\n    public readonly List<LocalVariable> Locals;\n    public readonly ConcreteUpdateStatement Update;\n    public readonly bool BypassStoreBuffers;\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(cce.NonNullElements(Locals));\n      Contract.Invariant(Locals.Count != 0);\n    }\n\n    public VarDeclStmt(IToken tok, IToken endTok, List<LocalVariable> locals, ConcreteUpdateStatement update, bool bypassStoreBuffers)\n      : base(tok, endTok)\n    {\n      Contract.Requires(tok != null);\n      Contract.Requires(endTok != null);\n      Contract.Requires(locals != null);\n      Contract.Requires(locals.Count != 0);\n\n      Locals = locals;\n      Update = update;\n      BypassStoreBuffers = bypassStoreBuffers;\n    }\n\n    public override IEnumerable<Statement> SubStatements {\n      get { if (Update != null) { yield return Update; } }\n    }\n\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        foreach (var e in base.SubExpressions) { yield return e; }\n        foreach (var v in Locals) {\n          foreach (var e in Attributes.SubExpressions(v.Attributes)) {\n            yield return e;\n          }\n        }\n      }\n    }\n  }\n\n  public class LetStmt : Statement\n  {\n    public readonly CasePattern<LocalVariable> LHS;\n    public readonly Expression RHS;\n\n    public LetStmt(IToken tok, IToken endTok, CasePattern<LocalVariable> lhs, Expression rhs)\n      : base(tok, endTok) {\n      LHS = lhs;\n      RHS = rhs;\n    }\n\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        foreach (var e in Attributes.SubExpressions(Attributes)) {\n          yield return e;\n        }\n        yield return RHS;\n      }\n    }\n\n    public IEnumerable<LocalVariable> LocalVars {\n      get {\n        foreach (var bv in LHS.Vars) {\n          yield return bv;\n        }\n      }\n    }\n  }\n\n  /// <summary>\n  /// Common superclass of UpdateStmt, AssignSuchThatStmt and AssignOrReturnStmt\n  /// </summary>\n  public abstract class ConcreteUpdateStatement : Statement\n  {\n    public readonly List<Expression> Lhss;\n    public ConcreteUpdateStatement(IToken tok, IToken endTok, List<Expression> lhss, Attributes attrs = null)\n      : base(tok, endTok, attrs) {\n      Contract.Requires(tok != null);\n      Contract.Requires(endTok != null);\n      Contract.Requires(cce.NonNullElements(lhss));\n      Lhss = lhss;\n    }\n  }\n\n  public class AssignSuchThatStmt : ConcreteUpdateStatement\n  {\n    public readonly Expression Expr;\n    public readonly IToken AssumeToken;\n\n    public List<ComprehensionExpr.BoundedPool> Bounds;  // initialized and filled in by resolver; null for a ghost statement\n    // invariant Bounds == null || Bounds.Count == BoundVars.Count;\n    public List<IVariable> MissingBounds;  // filled in during resolution; remains \"null\" if bounds can be found\n    // invariant Bounds == null || MissingBounds == null;\n    public class WiggleWaggleBound : ComprehensionExpr.BoundedPool\n    {\n      public override PoolVirtues Virtues => PoolVirtues.Enumerable | PoolVirtues.IndependentOfAlloc | PoolVirtues.IndependentOfAlloc_or_ExplicitAlloc;\n      public override int Preference() => 1;\n    }\n\n    /// <summary>\n    /// \"assumeToken\" is allowed to be \"null\", in which case the verifier will check that a RHS value exists.\n    /// If \"assumeToken\" is non-null, then it should denote the \"assume\" keyword used in the statement.\n    /// </summary>\n    public AssignSuchThatStmt(IToken tok, IToken endTok, List<Expression> lhss, Expression expr, IToken assumeToken, Attributes attrs)\n      : base(tok, endTok, lhss, attrs) {\n      Contract.Requires(tok != null);\n      Contract.Requires(endTok != null);\n      Contract.Requires(cce.NonNullElements(lhss));\n      Contract.Requires(lhss.Count != 0);\n      Contract.Requires(expr != null);\n      Expr = expr;\n      if (assumeToken != null) {\n        AssumeToken = assumeToken;\n      }\n    }\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        foreach (var e in base.SubExpressions) { yield return e; }\n        yield return Expr;\n        foreach (var lhs in Lhss) {\n          yield return lhs;\n        }\n      }\n    }\n  }\n\n  public class UpdateStmt : ConcreteUpdateStatement\n  {\n    public readonly List<AssignmentRhs> Rhss;\n    public readonly bool CanMutateKnownState;\n    public readonly bool BypassStoreBuffers;\n\n    public readonly List<Statement> ResolvedStatements = new List<Statement>();  // contents filled in during resolution\n    public override IEnumerable<Statement> SubStatements {\n      get { return ResolvedStatements; }\n    }\n\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(cce.NonNullElements(Lhss));\n      Contract.Invariant(cce.NonNullElements(Rhss));\n    }\n\n    public UpdateStmt(IToken tok, IToken endTok, List<Expression> lhss, List<AssignmentRhs> rhss, bool mutate=false, bool bypassStoreBuffers=false)\n      : base(tok, endTok, lhss)\n    {\n      Contract.Requires(tok != null);\n      Contract.Requires(endTok != null);\n      Contract.Requires(cce.NonNullElements(lhss));\n      Contract.Requires(cce.NonNullElements(rhss));\n      Contract.Requires(lhss.Count != 0 || rhss.Count == 1);\n      Rhss = rhss;\n      CanMutateKnownState = mutate;\n      BypassStoreBuffers = bypassStoreBuffers;\n    }\n  }\n\n  public class AssignOrReturnStmt : ConcreteUpdateStatement\n  {\n    public readonly Expression Rhs; // this is the unresolved RHS, and thus can also be a method call\n    public readonly List<Statement> ResolvedStatements = new List<Statement>();  // contents filled in during resolution\n    public override IEnumerable<Statement> SubStatements {\n      get { return ResolvedStatements; }\n    }\n\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(Lhss != null);\n      Contract.Invariant(\n          Lhss.Count == 0 ||                   // \":- MethodOrExpresion;\" which returns void success or an error\n          Lhss.Count == 1 && Lhss[0] != null   // \"y :- MethodOrExpression;\"\n      );\n      Contract.Invariant(Rhs != null);\n    }\n\n    public AssignOrReturnStmt(IToken tok, IToken endTok, List<Expression> lhss, Expression rhs)\n      : base(tok, endTok, lhss)\n    {\n      Contract.Requires(tok != null);\n      Contract.Requires(endTok != null);\n      Contract.Requires(lhss != null);\n      Contract.Requires(lhss.Count <= 1);\n      Contract.Requires(rhs != null);\n      Rhs = rhs;\n    }\n  }\n\n  public class AssignStmt : Statement {\n    public readonly Expression Lhs;\n    public readonly AssignmentRhs Rhs;\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(Lhs != null);\n      Contract.Invariant(Rhs != null);\n    }\n\n    public AssignStmt(IToken tok, IToken endTok, Expression lhs, AssignmentRhs rhs)\n      : base(tok, endTok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(endTok != null);\n      Contract.Requires(lhs != null);\n      Contract.Requires(rhs != null);\n      this.Lhs = lhs;\n      this.Rhs = rhs;\n    }\n\n    public override IEnumerable<Statement> SubStatements {\n      get {\n        foreach (var s in Rhs.SubStatements) {\n          yield return s;\n        }\n      }\n    }\n\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        foreach (var e in base.SubExpressions) { yield return e; }\n        yield return Lhs;\n        foreach (var ee in Rhs.SubExpressions) {\n          yield return ee;\n        }\n      }\n    }\n\n    /// <summary>\n    /// This method assumes \"lhs\" has been successfully resolved.\n    /// </summary>\n    public static bool LhsIsToGhost(Expression lhs) {\n      Contract.Requires(lhs != null);\n      return LhsIsToGhost_Which(lhs) == NonGhostKind.IsGhost;\n    }\n    public enum NonGhostKind { IsGhost, Variable, Field, ArrayElement }\n    public static string NonGhostKind_To_String(NonGhostKind gk) {\n      Contract.Requires(gk != NonGhostKind.IsGhost);\n      switch (gk) {\n        case NonGhostKind.Variable: return \"non-ghost variable\";\n        case NonGhostKind.Field: return \"non-ghost field\";\n        case NonGhostKind.ArrayElement: return \"array element\";\n        default:\n          Contract.Assume(false);  // unexpected NonGhostKind\n          throw new cce.UnreachableException();  // please compiler\n      }\n    }\n    /// <summary>\n    /// This method assumes \"lhs\" has been successfully resolved.\n    /// </summary>\n    public static NonGhostKind LhsIsToGhost_Which(Expression lhs) {\n      Contract.Requires(lhs != null);\n      lhs = lhs.Resolved;\n      if (lhs is IdentifierExpr) {\n        var x = (IdentifierExpr)lhs;\n        if (!x.Var.IsGhost) {\n          return NonGhostKind.Variable;\n        }\n      } else if (lhs is MemberSelectExpr) {\n        var x = (MemberSelectExpr)lhs;\n        if (!x.Member.IsGhost) {\n          return NonGhostKind.Field;\n        }\n      } else {\n        // LHS denotes an array element, which is always non-ghost\n        return NonGhostKind.ArrayElement;\n      }\n      return NonGhostKind.IsGhost;\n    }\n  }\n\n  public class LocalVariable : IVariable, IAttributeBearingDeclaration {\n    public readonly IToken Tok;\n    public readonly IToken EndTok;  // typically a terminating semi-colon or end-curly-brace\n    readonly string name;\n    public Attributes Attributes;\n    public bool IsGhost;\n    public readonly bool IsNoAddr;\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(name != null);\n      Contract.Invariant(OptionalType != null);\n    }\n\n    public LocalVariable(IToken tok, IToken endTok, string name, Type type, bool isGhost, bool isNoAddr) {\n      Contract.Requires(tok != null);\n      Contract.Requires(endTok != null);\n      Contract.Requires(name != null);\n      Contract.Requires(type != null);  // can be a proxy, though\n\n      this.Tok = tok;\n      this.EndTok = endTok;\n      this.name = name;\n      this.OptionalType = type;\n      if (type is InferredTypeProxy) {\n        ((InferredTypeProxy)type).KeepConstraints = true;\n      }\n      this.IsGhost = isGhost;\n      this.IsNoAddr = isNoAddr;\n    }\n\n    public string Name {\n      get {\n        Contract.Ensures(Contract.Result<string>() != null);\n        return name;\n      }\n    }\n    public static bool HasWildcardName(IVariable v) {\n      Contract.Requires(v != null);\n      return v.Name.StartsWith(\"_v\");\n    }\n    public static string DisplayNameHelper(IVariable v) {\n      Contract.Requires(v != null);\n      return HasWildcardName(v) ? \"_\" : v.Name;\n    }\n    public string DisplayName {\n      get { return DisplayNameHelper(this); }\n    }\n    private string uniqueName;\n    public string UniqueName {\n      get {\n        return uniqueName;\n      }\n    }\n    public bool HasBeenAssignedUniqueName {\n      get {\n        return uniqueName != null;\n      }\n    }\n    public string AssignUniqueName(FreshIdGenerator generator)\n    {\n      if (uniqueName == null)\n      {\n        uniqueName = generator.FreshId(Name + \"#\");\n        compileName = string.Format(\"_{0}_{1}\", Compiler.FreshId(), NonglobalVariable.CompilerizeName(name));\n      }\n      return UniqueName;\n    }\n    string compileName;\n    public string CompileName {\n      get {\n        if (compileName == null)\n        {\n          compileName = string.Format(\"_{0}_{1}\", Compiler.FreshId(), NonglobalVariable.CompilerizeName(name));\n        }\n        return compileName;\n      }\n    }\n    public readonly Type OptionalType;  // this is the type mentioned in the declaration, if any\n    Type IVariable.OptionalType { get { return this.OptionalType; } }\n    internal Type type;  // this is the declared or inferred type of the variable; it is non-null after resolution (even if resolution fails)\n    public Type Type {\n      get {\n        Contract.Ensures(Contract.Result<Type>() != null);\n\n        Contract.Assume(type != null);  /* we assume object has been resolved */\n        return type.Normalize();\n      }\n    }\n    public bool IsMutable {\n      get {\n        return true;\n      }\n    }\n    bool IVariable.IsGhost {\n      get {\n        return this.IsGhost;\n      }\n    }\n    /// <summary>\n    /// This method retrospectively makes the LocalVariable a ghost.  It is to be used only during resolution.\n    /// </summary>\n    public void MakeGhost() {\n      this.IsGhost = true;\n    }\n    IToken IVariable.Tok {\n      get {\n        return Tok;\n      }\n    }\n  }\n\n  /// <summary>\n  /// A CallStmt is always resolved.  It is typically produced as a resolved counterpart of the syntactic AST note ApplySuffix.\n  /// </summary>\n  public class CallStmt : Statement {\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(MethodSelect.Member is Method);\n      Contract.Invariant(cce.NonNullElements(Lhs));\n      Contract.Invariant(cce.NonNullElements(Args));\n    }\n\n    public readonly List<Expression> Lhs;\n    public readonly MemberSelectExpr MethodSelect;\n    public readonly List<Expression> Args;\n\n    public Expression Receiver { get { return MethodSelect.Obj; } }\n    public Method Method { get { return (Method)MethodSelect.Member; } }\n\n    public CallStmt(IToken tok, IToken endTok, List<Expression> lhs, MemberSelectExpr memSel, List<Expression> args)\n      : base(tok, endTok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(endTok != null);\n      Contract.Requires(cce.NonNullElements(lhs));\n      Contract.Requires(memSel != null);\n      Contract.Requires(memSel.Member is Method);\n      Contract.Requires(cce.NonNullElements(args));\n\n      this.Lhs = lhs;\n      this.MethodSelect = memSel;\n      this.Args = args;\n    }\n\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        foreach (var e in base.SubExpressions) { yield return e; }\n        foreach (var ee in Lhs) {\n          yield return ee;\n        }\n        yield return MethodSelect;\n        foreach (var ee in Args) {\n          yield return ee;\n        }\n      }\n    }\n  }\n\n  public class CommitStmt : Statement {\n    public readonly Statement Body;\n    public CommitStmt(IToken tok, IToken endTok, [Captured] Statement body)\n      : base(tok, endTok)\n    {\n      this.Body = body;\n    }\n\n    public override IEnumerable<Statement> SubStatements {\n      get { yield return Body; }\n    }\n  }\n\n  public class JoinStmt : Statement {\n    public readonly Expression WhichThread;\n    public JoinStmt(IToken tok, IToken endTok, Expression whichThread)\n      : base(tok, endTok)\n    {\n      this.WhichThread = whichThread;\n    }\n\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        foreach (var ee in WhichThread.SubExpressions) {\n          yield return ee;\n        }\n      }\n    }\n  }\n\n  public class BlockStmt : Statement {\n    public readonly List<Statement> Body;\n    public BlockStmt(IToken tok, IToken endTok, [Captured] List<Statement> body)\n      : base(tok, endTok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(endTok != null);\n      Contract.Requires(cce.NonNullElements(body));\n      this.Body = body;\n    }\n\n    public override IEnumerable<Statement> SubStatements {\n      get { return Body; }\n    }\n\n    public virtual void AppendStmt(Statement s) {\n      Contract.Requires(s != null);\n      Body.Add(s);\n    }\n  }\n\n  public class DividedBlockStmt : BlockStmt\n  {\n    public readonly List<Statement> BodyInit;  // first part of Body's statements\n    public readonly IToken SeparatorTok;  // token that separates the two parts, if any\n    public readonly List<Statement> BodyProper;  // second part of Body's statements\n    public DividedBlockStmt(IToken tok, IToken endTok, List<Statement> bodyInit, IToken/*?*/ separatorTok, List<Statement> bodyProper)\n      : base(tok, endTok, Util.Concat(bodyInit, bodyProper)) {\n      Contract.Requires(tok != null);\n      Contract.Requires(endTok != null);\n      Contract.Requires(cce.NonNullElements(bodyInit));\n      Contract.Requires(cce.NonNullElements(bodyProper));\n      this.BodyInit = bodyInit;\n      this.SeparatorTok = separatorTok;\n      this.BodyProper = bodyProper;\n    }\n    public override void AppendStmt(Statement s) {\n      BodyProper.Add(s);\n      base.AppendStmt(s);\n    }\n  }\n\n  public class ExplicitYieldBlockStmt : BlockStmt {\n    public ExplicitYieldBlockStmt(IToken tok, IToken endTok, [Captured] List<Statement> body)\n      : base(tok, endTok, body) {\n    }\n  }\n\n  public class IfStmt : Statement {\n    public readonly bool IsBindingGuard;\n    public readonly Expression Guard;\n    public readonly BlockStmt Thn;\n    public readonly Statement Els;\n\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(!IsBindingGuard || (Guard is ExistsExpr && ((ExistsExpr)Guard).Range == null));\n      Contract.Invariant(Thn != null);\n      Contract.Invariant(Els == null || Els is BlockStmt || Els is IfStmt || Els is SkeletonStatement);\n    }\n    public IfStmt(IToken tok, IToken endTok, bool isBindingGuard, Expression guard, BlockStmt thn, Statement els)\n      : base(tok, endTok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(endTok != null);\n      Contract.Requires(!isBindingGuard || (guard is ExistsExpr && ((ExistsExpr)guard).Range == null));\n      Contract.Requires(thn != null);\n      Contract.Requires(els == null || els is BlockStmt || els is IfStmt || els is SkeletonStatement);\n      this.IsBindingGuard = isBindingGuard;\n      this.Guard = guard;\n      this.Thn = thn;\n      this.Els = els;\n    }\n    public override IEnumerable<Statement> SubStatements {\n      get {\n        yield return Thn;\n        if (Els != null) {\n          yield return Els;\n        }\n      }\n    }\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        foreach (var e in base.SubExpressions) { yield return e; }\n        if (Guard != null) {\n          yield return Guard;\n        }\n      }\n    }\n  }\n\n  public class GuardedAlternative\n  {\n    public readonly IToken Tok;\n    public readonly bool IsBindingGuard;\n    public readonly Expression Guard;\n    public readonly List<Statement> Body;\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(Tok != null);\n      Contract.Invariant(Guard != null);\n      Contract.Invariant(!IsBindingGuard || (Guard is ExistsExpr && ((ExistsExpr)Guard).Range == null));\n      Contract.Invariant(Body != null);\n    }\n    public GuardedAlternative(IToken tok, bool isBindingGuard, Expression guard, List<Statement> body)\n    {\n      Contract.Requires(tok != null);\n      Contract.Requires(guard != null);\n      Contract.Requires(!isBindingGuard || (guard is ExistsExpr && ((ExistsExpr)guard).Range == null));\n      Contract.Requires(body != null);\n      this.Tok = tok;\n      this.IsBindingGuard = isBindingGuard;\n      this.Guard = guard;\n      this.Body = body;\n    }\n  }\n\n  public class AlternativeStmt : Statement\n  {\n    public readonly bool UsesOptionalBraces;\n    public readonly List<GuardedAlternative> Alternatives;\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(Alternatives != null);\n    }\n    public AlternativeStmt(IToken tok, IToken endTok, List<GuardedAlternative> alternatives, bool usesOptionalBraces)\n      : base(tok, endTok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(endTok != null);\n      Contract.Requires(alternatives != null);\n      this.Alternatives = alternatives;\n      this.UsesOptionalBraces = usesOptionalBraces;\n    }\n    public override IEnumerable<Statement> SubStatements {\n      get {\n        foreach (var alt in Alternatives) {\n          foreach (var s in alt.Body) {\n            yield return s;\n          }\n        }\n      }\n    }\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        foreach (var e in base.SubExpressions) { yield return e; }\n        foreach (var alt in Alternatives) {\n          yield return alt.Guard;\n        }\n      }\n    }\n  }\n\n  public abstract class LoopStmt : Statement\n  {\n    public readonly List<MaybeFreeExpression> Invariants;\n    public readonly Specification<Expression> Decreases;\n    public bool InferredDecreases;  // filled in by resolution\n    public readonly Specification<FrameExpression> Mod;\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(cce.NonNullElements(Invariants));\n      Contract.Invariant(Decreases != null);\n      Contract.Invariant(Mod != null);\n    }\n    public LoopStmt(IToken tok, IToken endTok, List<MaybeFreeExpression> invariants, Specification<Expression> decreases, Specification<FrameExpression> mod)\n    : base(tok, endTok)\n    {\n      Contract.Requires(tok != null);\n      Contract.Requires(endTok != null);\n      Contract.Requires(cce.NonNullElements(invariants));\n      Contract.Requires(decreases != null);\n      Contract.Requires(mod != null);\n\n      this.Invariants = invariants;\n      this.Decreases = decreases;\n      this.Mod = mod;\n      if (ArmadaOptions.O.Dafnycc) {\n        Decreases = new Specification<Expression>(\n          new List<Expression>() { new WildcardExpr(tok) }, null);\n      }\n    }\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        foreach (var e in base.SubExpressions) { yield return e; }\n        foreach (var mfe in Invariants) {\n          foreach (var e in Attributes.SubExpressions(mfe.Attributes)) { yield return e; }\n          yield return mfe.E;\n        }\n        foreach (var e in Attributes.SubExpressions(Decreases.Attributes)) { yield return e; }\n        if (Decreases.Expressions != null) {\n          foreach (var e in Decreases.Expressions) {\n            yield return e;\n          }\n        }\n        foreach (var e in Attributes.SubExpressions(Mod.Attributes)) { yield return e; }\n        if (Mod.Expressions != null) {\n          foreach (var fe in Mod.Expressions) {\n            yield return fe.E;\n          }\n        }\n      }\n    }\n  }\n\n  public class WhileStmt : LoopStmt\n  {\n    public readonly Expression Guard;\n    public readonly BlockStmt Body;\n    public readonly List<Expression> Ens;\n\n    public WhileStmt(IToken tok, IToken endTok, Expression guard, List<MaybeFreeExpression> invariants,\n                     List<Expression> ens, Specification<Expression> decreases, Specification<FrameExpression> mod,\n                     BlockStmt body)\n      : base(tok, endTok, invariants, decreases, mod) {\n      Contract.Requires(tok != null);\n      Contract.Requires(endTok != null);\n      this.Guard = guard;\n      this.Body = body;\n      this.Ens = ens;\n    }\n\n    public override IEnumerable<Statement> SubStatements {\n      get {\n        if (Body != null) {\n          yield return Body;\n        }\n      }\n    }\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        foreach (var e in base.SubExpressions) { yield return e; }\n        foreach (var e in Ens) { yield return e; }\n        if (Guard != null) {\n          yield return Guard;\n        }\n      }\n    }\n  }\n\n  /// <summary>\n  /// This class is really just a WhileStmt, except that it serves the purpose of remembering if the object was created as the result of a refinement\n  /// merge.\n  /// </summary>\n  public class RefinedWhileStmt : WhileStmt\n  {\n    public RefinedWhileStmt(IToken tok, IToken endTok, Expression guard,\n                            List<MaybeFreeExpression> invariants, Specification<Expression> decreases, Specification<FrameExpression> mod,\n                            BlockStmt body)\n      : base(tok, endTok, guard, invariants, new List<Expression>(), decreases, mod, body) {\n      Contract.Requires(tok != null);\n      Contract.Requires(endTok != null);\n      Contract.Requires(body != null);\n    }\n  }\n\n  public class AlternativeLoopStmt : LoopStmt\n  {\n    public readonly bool UsesOptionalBraces;\n    public readonly List<GuardedAlternative> Alternatives;\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(Alternatives != null);\n    }\n    public AlternativeLoopStmt(IToken tok, IToken endTok,\n                               List<MaybeFreeExpression> invariants, Specification<Expression> decreases, Specification<FrameExpression> mod,\n                               List<GuardedAlternative> alternatives, bool usesOptionalBraces)\n      : base(tok, endTok, invariants, decreases, mod) {\n      Contract.Requires(tok != null);\n      Contract.Requires(endTok != null);\n      Contract.Requires(alternatives != null);\n      this.Alternatives = alternatives;\n      this.UsesOptionalBraces = usesOptionalBraces;\n    }\n    public override IEnumerable<Statement> SubStatements {\n      get {\n        foreach (var alt in Alternatives) {\n          foreach (var s in alt.Body) {\n            yield return s;\n          }\n        }\n      }\n    }\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        foreach (var e in base.SubExpressions) { yield return e; }\n        foreach (var alt in Alternatives) {\n          yield return alt.Guard;\n        }\n      }\n    }\n  }\n\n  public class ForallStmt : Statement\n  {\n    public readonly List<BoundVar> BoundVars;  // note, can be the empty list, in which case Range denotes \"true\"\n    public Expression Range;  // mostly readonly, except that it may in some cases be updated during resolution to conjoin the precondition of the call in the body\n    public readonly List<MaybeFreeExpression> Ens;\n    public readonly Statement Body;\n    public List<Expression> ForallExpressions;   // fill in by rewriter.\n    public bool CanConvert = true; //  can convert to ForallExpressions\n\n    public List<ComprehensionExpr.BoundedPool> Bounds;  // initialized and filled in by resolver\n    // invariant: if successfully resolved, Bounds.Count == BoundVars.Count;\n\n    /// <summary>\n    /// Assign means there are no ensures clauses and the body consists of one update statement,\n    ///   either to an object field or to an array.\n    /// Call means there are no ensures clauses and the body consists of a single call to a (presumably\n    ///   ghost, but non-ghost is also allowed) method with no out-parameters and an empty modifies\n    ///   clause.\n    /// Proof means there is at least one ensures clause, and the body consists of any (presumably ghost,\n    ///   but non-ghost is also allowed) code without side effects on variables (including fields and array\n    ///   elements) declared outside the body itself.\n    /// Notes:\n    /// * More kinds may be allowed in the future.\n    /// * One could also allow Call to call non-ghost methods without side effects.  However, that\n    ///   would seem pointless in the program, so they are disallowed (to avoid any confusion that\n    ///   such use of the forall statement might actually have a point).\n    /// * One could allow Proof even without ensures clauses that \"export\" what was learned.\n    ///   However, that might give the false impression that the body is nevertheless exported.\n    /// </summary>\n    public enum BodyKind { Assign, Call, Proof }\n    public BodyKind Kind;  // filled in during resolution\n\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(BoundVars != null);\n      Contract.Invariant(Range != null);\n      Contract.Invariant(BoundVars.Count != 0 || LiteralExpr.IsTrue(Range));\n      Contract.Invariant(Ens != null);\n    }\n\n    public ForallStmt(IToken tok, IToken endTok, List<BoundVar> boundVars, Attributes attrs, Expression range, List<MaybeFreeExpression> ens, Statement body)\n      : base(tok, endTok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(endTok != null);\n      Contract.Requires(cce.NonNullElements(boundVars));\n      Contract.Requires(range != null);\n      Contract.Requires(boundVars.Count != 0 || LiteralExpr.IsTrue(range));\n      Contract.Requires(cce.NonNullElements(ens));\n      this.BoundVars = boundVars;\n      this.Attributes = attrs;\n      this.Range = range;\n      this.Ens = ens;\n      this.Body = body;\n    }\n\n    public Statement S0 {\n      get {\n        // dig into Body to find a single statement\n        Statement s = this.Body;\n        while (true) {\n          var block = s as BlockStmt;\n          if (block != null && block.Body.Count == 1) {\n            s = block.Body[0];\n            // dig further into s\n          } else if (s is UpdateStmt) {\n            var update = (UpdateStmt)s;\n            if (update.ResolvedStatements.Count == 1) {\n              s = update.ResolvedStatements[0];\n              // dig further into s\n            } else {\n              return s;\n            }\n          } else {\n            return s;\n          }\n        }\n      }\n    }\n\n    public override IEnumerable<Statement> SubStatements {\n      get {\n        if (Body != null) {\n          yield return Body;\n        }\n      }\n    }\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        foreach (var e in base.SubExpressions) { yield return e; }\n        yield return Range;\n        foreach (var ee in Ens) {\n          foreach (var e in Attributes.SubExpressions(ee.Attributes)) { yield return e; }\n          yield return ee.E;\n        }\n      }\n    }\n\n    public List<BoundVar> UncompilableBoundVars() {\n      Contract.Ensures(Contract.Result<List<BoundVar>>() != null);\n      var v = ComprehensionExpr.BoundedPool.PoolVirtues.Finite | ComprehensionExpr.BoundedPool.PoolVirtues.Enumerable;\n      return ComprehensionExpr.BoundedPool.MissingBounds(BoundVars, Bounds, v);\n    }\n  }\n\n  public class ModifyStmt : Statement\n  {\n    public readonly Specification<FrameExpression> Mod;\n    public readonly BlockStmt Body;\n\n    public ModifyStmt(IToken tok, IToken endTok, List<FrameExpression> mod, Attributes attrs, BlockStmt body)\n      : base(tok, endTok)\n    {\n      Contract.Requires(tok != null);\n      Contract.Requires(endTok != null);\n      Contract.Requires(mod != null);\n      Mod = new Specification<FrameExpression>(mod, attrs);\n      Body = body;\n    }\n\n    public override IEnumerable<Statement> SubStatements {\n      get {\n        if (Body != null) {\n          yield return Body;\n        }\n      }\n    }\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        foreach (var e in base.SubExpressions) { yield return e; }\n        foreach (var e in Attributes.SubExpressions(Mod.Attributes)) { yield return e; }\n        foreach (var fe in Mod.Expressions) {\n          yield return fe.E;\n        }\n      }\n    }\n  }\n\n  public class CalcStmt : Statement\n  {\n    public abstract class CalcOp {\n      /// <summary>\n      /// Resulting operator \"x op z\" if \"x this y\" and \"y other z\".\n      /// Returns null if this and other are incompatible.\n      /// </summary>\n      [Pure]\n      public abstract CalcOp ResultOp(CalcOp other);\n\n      /// <summary>\n      /// Returns an expression \"line0 this line1\".\n      /// </summary>\n      [Pure]\n      public abstract Expression StepExpr(Expression line0, Expression line1);\n    }\n\n    public class BinaryCalcOp : CalcOp {\n      public readonly BinaryExpr.Opcode Op;\n\n      [ContractInvariantMethod]\n      void ObjectInvariant()\n      {\n        Contract.Invariant(ValidOp(Op));\n      }\n\n      /// <summary>\n      /// Is op a valid calculation operator?\n      /// </summary>\n      [Pure]\n      public static bool ValidOp(BinaryExpr.Opcode op) {\n        return\n             op == BinaryExpr.Opcode.Eq || op == BinaryExpr.Opcode.Neq\n          || op == BinaryExpr.Opcode.Lt || op == BinaryExpr.Opcode.Le\n          || op == BinaryExpr.Opcode.Gt || op == BinaryExpr.Opcode.Ge\n          || LogicOp(op);\n      }\n\n      /// <summary>\n      /// Is op a valid operator only for Boolean lines?\n      /// </summary>\n      [Pure]\n      public static bool LogicOp(BinaryExpr.Opcode op) {\n        return op == BinaryExpr.Opcode.Iff || op == BinaryExpr.Opcode.Imp || op == BinaryExpr.Opcode.Exp;\n      }\n\n      public BinaryCalcOp(BinaryExpr.Opcode op) {\n        Contract.Requires(ValidOp(op));\n        Op = op;\n      }\n\n      /// <summary>\n      /// Does this subsume other (this . other == other . this == this)?\n      /// </summary>\n      private bool Subsumes(BinaryCalcOp other) {\n        Contract.Requires(other != null);\n        var op1 = Op;\n        var op2 = other.Op;\n        if (op1 == BinaryExpr.Opcode.Neq || op2 == BinaryExpr.Opcode.Neq)\n          return op2 == BinaryExpr.Opcode.Eq;\n        if (op1 == op2)\n          return true;\n        if (LogicOp(op1) || LogicOp(op2))\n          return op2 == BinaryExpr.Opcode.Eq ||\n            (op1 == BinaryExpr.Opcode.Imp && op2 == BinaryExpr.Opcode.Iff) ||\n            (op1 == BinaryExpr.Opcode.Exp && op2 == BinaryExpr.Opcode.Iff) ||\n            (op1 == BinaryExpr.Opcode.Eq && op2 == BinaryExpr.Opcode.Iff);\n        return op2 == BinaryExpr.Opcode.Eq ||\n          (op1 == BinaryExpr.Opcode.Lt && op2 == BinaryExpr.Opcode.Le) ||\n          (op1 == BinaryExpr.Opcode.Gt && op2 == BinaryExpr.Opcode.Ge);\n      }\n\n      public override CalcOp ResultOp(CalcOp other) {\n        if (other is BinaryCalcOp) {\n          var o = (BinaryCalcOp) other;\n          if (this.Subsumes(o)) {\n            return this;\n          } else if (o.Subsumes(this)) {\n            return other;\n          }\n          return null;\n        } else if (other is TernaryCalcOp) {\n          return other.ResultOp(this);\n        } else {\n          Contract.Assert(false);\n          throw new cce.UnreachableException();\n        }\n      }\n\n      public override Expression StepExpr(Expression line0, Expression line1)\n      {\n        if (Op == BinaryExpr.Opcode.Exp) {\n          // The order of operands is reversed so that it can be turned into implication during resolution\n          return new BinaryExpr(line0.tok, Op, line1, line0);\n        } else {\n          return new BinaryExpr(line0.tok, Op, line0, line1);\n        }\n      }\n\n      public override string ToString()\n      {\n        return BinaryExpr.OpcodeString(Op);\n      }\n\n    }\n\n    public class TernaryCalcOp : CalcOp {\n      public readonly Expression Index; // the only allowed ternary operator is ==#, so we only store the index\n\n      [ContractInvariantMethod]\n      void ObjectInvariant()\n      {\n        Contract.Invariant(Index != null);\n      }\n\n      public TernaryCalcOp(Expression idx) {\n        Contract.Requires(idx != null);\n        Index = idx;\n      }\n\n      public override CalcOp ResultOp(CalcOp other) {\n        if (other is BinaryCalcOp) {\n          if (((BinaryCalcOp) other).Op == BinaryExpr.Opcode.Eq) {\n            return this;\n          }\n          return null;\n        } else if (other is TernaryCalcOp) {\n          var a = Index;\n          var b = ((TernaryCalcOp) other).Index;\n          var minIndex = new ITEExpr(a.tok, false, new BinaryExpr(a.tok, BinaryExpr.Opcode.Le, a, b), a, b);\n          return new TernaryCalcOp(minIndex); // ToDo: if we could compare expressions for syntactic equalty, we could use this here to optimize\n        } else {\n          Contract.Assert(false);\n          throw new cce.UnreachableException();\n        }\n      }\n\n      public override Expression StepExpr(Expression line0, Expression line1)\n      {\n        return new TernaryExpr(line0.tok, TernaryExpr.Opcode.PrefixEqOp, Index, line0, line1);\n      }\n\n      public override string ToString()\n      {\n        return \"==#\";\n      }\n\n    }\n\n    public readonly List<Expression> Lines;    // Last line is dummy, in order to form a proper step with the dangling hint\n    public readonly List<BlockStmt> Hints;     // Hints[i] comes after line i; block statement is used as a container for multiple sub-hints\n    public readonly CalcOp UserSuppliedOp;     // may be null, if omitted by the user\n    public CalcOp Op;                          // main operator of the calculation (either UserSuppliedOp or (after resolution) an inferred CalcOp)\n    public readonly List<CalcOp/*?*/> StepOps; // StepOps[i] comes after line i\n    public readonly List<Expression> Steps;    // expressions li op l<i + 1>, filled in during resolution (last step is dummy)\n    public Expression Result;                  // expression l0 ResultOp ln, filled in during resolution\n\n    public static readonly CalcOp DefaultOp = new BinaryCalcOp(BinaryExpr.Opcode.Eq);\n\n    [ContractInvariantMethod]\n    void ObjectInvariant()\n    {\n      Contract.Invariant(Lines != null);\n      Contract.Invariant(cce.NonNullElements(Lines));\n      Contract.Invariant(Hints != null);\n      Contract.Invariant(cce.NonNullElements(Hints));\n      Contract.Invariant(StepOps != null);\n      Contract.Invariant(Steps != null);\n      Contract.Invariant(cce.NonNullElements(Steps));\n      Contract.Invariant(Hints.Count == Math.Max(Lines.Count - 1, 0));\n      Contract.Invariant(StepOps.Count == Hints.Count);\n    }\n\n    public CalcStmt(IToken tok, IToken endTok, CalcOp userSuppliedOp, List<Expression> lines, List<BlockStmt> hints, List<CalcOp/*?*/> stepOps, Attributes attrs)\n      : base(tok, endTok)\n    {\n      Contract.Requires(tok != null);\n      Contract.Requires(endTok != null);\n      Contract.Requires(lines != null);\n      Contract.Requires(hints != null);\n      Contract.Requires(stepOps != null);\n      Contract.Requires(cce.NonNullElements(lines));\n      Contract.Requires(cce.NonNullElements(hints));\n      Contract.Requires(hints.Count == Math.Max(lines.Count - 1, 0));\n      Contract.Requires(stepOps.Count == hints.Count);\n      this.UserSuppliedOp = userSuppliedOp;\n      this.Lines = lines;\n      this.Hints = hints;\n      this.StepOps = stepOps;\n      this.Steps = new List<Expression>();\n      this.Result = null;\n      this.Attributes = attrs;\n    }\n\n    public override IEnumerable<Statement> SubStatements\n    {\n      get {\n        foreach (var h in Hints) {\n          yield return h;\n        }\n      }\n    }\n    public override IEnumerable<Expression> SubExpressions\n    {\n      get {\n        foreach (var e in base.SubExpressions) { yield return e; }\n        foreach (var e in Attributes.SubExpressions(Attributes)) { yield return e; }\n\n        for (int i = 0; i < Lines.Count - 1; i++) {  // note, we skip the duplicated line at the end\n          yield return Lines[i];\n        }\n        foreach (var calcop in AllCalcOps) {\n          var o3 = calcop as TernaryCalcOp;\n          if (o3 != null) {\n            yield return o3.Index;\n          }\n        }\n      }\n    }\n\n    IEnumerable<CalcOp> AllCalcOps {\n      get {\n        if (UserSuppliedOp != null) {\n          yield return UserSuppliedOp;\n        }\n        foreach (var stepop in StepOps) {\n          if (stepop != null) {\n            yield return stepop;\n          }\n        }\n      }\n    }\n\n    /// <summary>\n    /// Left-hand side of a step expression.\n    /// Note that Lhs(op.StepExpr(line0, line1)) != line0 when op is <==.\n    /// </summary>\n    public static Expression Lhs(Expression step)\n    {\n      Contract.Requires(step is BinaryExpr || step is TernaryExpr);\n      if (step is BinaryExpr) {\n        return ((BinaryExpr) step).E0;\n      } else {\n        return ((TernaryExpr) step).E1;\n      }\n    }\n\n    /// <summary>\n    /// Right-hand side of a step expression.\n    /// Note that Rhs(op.StepExpr(line0, line1)) != line1 when op is REVERSE-IMPLICATION.\n    /// </summary>\n    public static Expression Rhs(Expression step)\n    {\n      Contract.Requires(step is BinaryExpr || step is TernaryExpr);\n      if (step is BinaryExpr) {\n        return ((BinaryExpr) step).E1;\n      } else {\n        return ((TernaryExpr) step).E2;\n      }\n    }\n  }\n\n  public class MatchStmt : Statement\n  {\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(Source != null);\n      Contract.Invariant(cce.NonNullElements(Cases));\n      Contract.Invariant(cce.NonNullElements(MissingCases));\n    }\n\n    private Expression source;\n    private List<MatchCaseStmt> cases;\n    public readonly List<DatatypeCtor> MissingCases = new List<DatatypeCtor>();  // filled in during resolution\n    public readonly bool UsesOptionalBraces;\n    public MatchStmt OrigUnresolved;  // the resolver makes this clone of the MatchStmt before it starts desugaring it\n\n    public MatchStmt(IToken tok, IToken endTok, Expression source, [Captured] List<MatchCaseStmt> cases, bool usesOptionalBraces)\n      : base(tok, endTok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(endTok != null);\n      Contract.Requires(source != null);\n      Contract.Requires(cce.NonNullElements(cases));\n      this.source = source;\n      this.cases = cases;\n      this.UsesOptionalBraces = usesOptionalBraces;\n    }\n\n    public Expression Source {\n      get { return source; }\n    }\n\n    public List<MatchCaseStmt> Cases {\n      get { return cases; }\n    }\n\n    // should only be used in desugar in resolve to change the cases of the matchexpr\n    public void UpdateSource(Expression source) {\n      this.source = source;\n    }\n\n    public void UpdateCases(List<MatchCaseStmt> cases) {\n      this.cases = cases;\n    }\n\n    public override IEnumerable<Statement> SubStatements {\n      get {\n        foreach (var kase in cases) {\n          foreach (var s in kase.Body) {\n            yield return s;\n          }\n        }\n      }\n    }\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        foreach (var e in base.SubExpressions) { yield return e; }\n        yield return Source;\n      }\n    }\n  }\n\n  public class MatchCaseStmt : MatchCase\n  {\n    private List<Statement> body;\n\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(cce.NonNullElements(Body));\n    }\n\n    public MatchCaseStmt(IToken tok, string id, [Captured] List<BoundVar> arguments, [Captured] List<Statement> body)\n      : base(tok, id, arguments)\n    {\n      Contract.Requires(tok != null);\n      Contract.Requires(id != null);\n      Contract.Requires(cce.NonNullElements(arguments));\n      Contract.Requires(cce.NonNullElements(body));\n      this.body = body;\n    }\n\n    public MatchCaseStmt(IToken tok, string id, [Captured] List<CasePattern<BoundVar>> cps, [Captured] List<Statement> body)\n      : base(tok, id, cps) {\n      Contract.Requires(tok != null);\n      Contract.Requires(id != null);\n      Contract.Requires(cce.NonNullElements(cps));\n      Contract.Requires(cce.NonNullElements(body));\n      this.body = body;\n    }\n\n    public List<Statement> Body {\n      get { return body; }\n    }\n\n    // should only be called by resolve to reset the body of the MatchCaseExpr\n    public void UpdateBody(List<Statement> body) {\n      this.body = body;\n    }\n  }\n\n  /// <summary>\n  /// The class represents several possible scenarios:\n  /// * ...;\n  ///   S == null\n  /// * assert ...\n  ///   ConditionOmitted == true\n  /// * assume ...\n  ///   ConditionOmitted == true\n  /// * if ... { Stmt }\n  ///   if ... { Stmt } else ElseStmt\n  ///   ConditionOmitted == true\n  /// * while ... invariant J;\n  ///   ConditionOmitted == true && BodyOmitted == true\n  /// * while ... invariant J; { Stmt }\n  ///   ConditionOmitted == true && BodyOmitted == false\n  /// * modify ...;\n  ///   ConditionOmitted == true && BodyOmitted == false\n  /// * modify ... { Stmt }\n  ///   ConditionOmitted == true && BodyOmitted == false\n  /// </summary>\n  public class SkeletonStatement : Statement\n  {\n    public readonly Statement S;\n    public bool ConditionOmitted { get { return ConditionEllipsis != null; } }\n    public readonly IToken ConditionEllipsis;\n    public bool BodyOmitted { get { return BodyEllipsis != null; } }\n    public readonly IToken BodyEllipsis;\n    public readonly List<IToken> NameReplacements;\n    public readonly List<Expression> ExprReplacements;\n    public SkeletonStatement(IToken tok, IToken endTok)\n      : base(tok, endTok)\n    {\n      Contract.Requires(tok != null);\n      Contract.Requires(endTok != null);\n      S = null;\n    }\n    public SkeletonStatement(Statement s, IToken conditionEllipsis, IToken bodyEllipsis)\n      : base(s.Tok, s.EndTok)\n    {\n      Contract.Requires(s != null);\n      S = s;\n      ConditionEllipsis = conditionEllipsis;\n      BodyEllipsis = bodyEllipsis;\n    }\n    public SkeletonStatement(IToken tok, IToken endTok, List<IToken> nameReplacements, List<Expression> exprReplacements)\n      : base(tok, endTok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(endTok != null);\n      NameReplacements = nameReplacements;\n      ExprReplacements = exprReplacements;\n\n    }\n    public override IEnumerable<Statement> SubStatements {\n      get {\n        // The SkeletonStatement is really a modification of its inner statement S.  Therefore,\n        // we don't consider S to be a substatement.  Instead, the substatements of S are the\n        // substatements of the SkeletonStatement.  In the case the SkeletonStatement modifies\n        // S by omitting its body (which is true only for loops), there are no substatements.\n        if (!BodyOmitted) {\n          foreach (var s in S.SubStatements) {\n            yield return s;\n          }\n        }\n      }\n    }\n  }\n\n  // ------------------------------------------------------------------------------------------------------\n\n  public abstract class TokenWrapper : IToken\n  {\n    protected readonly IToken WrappedToken;\n    protected TokenWrapper(IToken wrappedToken) {\n      Contract.Requires(wrappedToken != null);\n      WrappedToken = wrappedToken;\n    }\n\n    public int col {\n      get { return WrappedToken.col; }\n      set { throw new NotSupportedException(); }\n    }\n    public virtual string filename {\n      get { return WrappedToken.filename; }\n      set { throw new NotSupportedException(); }\n    }\n    public bool IsValid {\n      get { return WrappedToken.IsValid; }\n    }\n    public int kind {\n      get { return WrappedToken.kind; }\n      set { throw new NotSupportedException(); }\n    }\n    public int line {\n      get { return WrappedToken.line; }\n      set { throw new NotSupportedException(); }\n    }\n    public int pos {\n      get { return WrappedToken.pos; }\n      set { throw new NotSupportedException(); }\n    }\n    public virtual string val {\n      get { return WrappedToken.val; }\n      set { throw new NotSupportedException(); }\n    }\n  }\n\n  public class NestedToken : TokenWrapper\n  {\n    public NestedToken(IToken outer, IToken inner)\n      : base(outer)\n    {\n      Contract.Requires(outer != null);\n      Contract.Requires(inner != null);\n      Inner = inner;\n    }\n    public IToken Outer { get { return WrappedToken; } }\n    public readonly IToken Inner;\n  }\n\n  /// <summary>\n  /// An IncludeToken is a wrapper that indicates that the function/method was\n  /// declared in a file that was included. Any proof obligations from such an\n  /// included file are to be ignored.\n  /// </summary>\n  public class IncludeToken : TokenWrapper\n  {\n    public Include Include;\n    public IncludeToken(Include include, IToken wrappedToken)\n      : base(wrappedToken) {\n      Contract.Requires(wrappedToken != null);\n      this.Include = include;\n    }\n\n    public override string val {\n      get { return WrappedToken.val; }\n      set { WrappedToken.val = value; }\n    }\n  }\n\n  // ------------------------------------------------------------------------------------------------------\n  [DebuggerDisplay(\"{Printer.ExprToString(this)}\")]\n  public abstract class Expression\n  {\n    public readonly IToken tok;\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(tok != null);\n    }\n\n    [Pure]\n    public bool WasResolved()\n    {\n      return Type != null;\n    }\n\n    public Expression Resolved {\n      get {\n        Contract.Requires(WasResolved());  // should be called only on resolved expressions; this approximates that precondition\n        Expression r = this;\n        while (true) {\n          Contract.Assert(r.WasResolved());  // this.WasResolved() implies anything it reaches is also resolved\n          var rr = r as ConcreteSyntaxExpression;\n          if (rr == null) {\n            return r;\n          }\n          r = rr.ResolvedExpression;\n          if (r == null) {\n            // for a NegationExpression, we're willing to return its non-ResolveExpression form (since it is filled in\n            // during a resolution phase after type checking and we may be called here during type checking)\n            return rr is NegationExpression ? rr : null;\n          }\n        }\n      }\n    }\n\n\n    protected Type type;\n    public Type Type {  // filled in during resolution\n      get {\n        Contract.Ensures(type != null || Contract.Result<Type>() == null);  // useful in conjunction with postcondition of constructor\n        return type == null ? null : type.Normalize();\n      }\n      set {\n        Contract.Requires(!WasResolved());  // set it only once\n        Contract.Requires(value != null);\n\n        //modifies type;\n        type = value.Normalize();\n      }\n    }\n    /// <summary>\n    /// This method can be used when .Type has been found to be erroneous and its current value\n    /// would be unexpected by the rest of the resolver. This method then sets .Type to a neutral\n    /// value.\n    /// </summary>\n    public void ResetTypeAssignment() {\n      Contract.Requires(WasResolved());\n      type = new InferredTypeProxy();\n    }\n#if TEST_TYPE_SYNONYM_TRANSPARENCY\n    public void DebugTest_ChangeType(Type ty) {\n      Contract.Requires(WasResolved());  // we're here to set it again\n      Contract.Requires(ty != null);\n      type = ty;\n    }\n#endif\n\n    public Expression(IToken tok) {\n      Contract.Requires(tok != null);\n      Contract.Ensures(type == null);  // we would have liked to have written Type==null, but that's not admissible or provable\n\n      this.tok = tok;\n    }\n\n    /// <summary>\n    /// Returns the non-null subexpressions of the Expression.  To be called after the expression has been resolved; this\n    /// means, for example, that any concrete syntax that resolves to some other expression will return the subexpressions\n    /// of the resolved expression.\n    /// </summary>\n    public virtual IEnumerable<Expression> SubExpressions {\n      get { yield break; }\n    }\n\n    public virtual bool IsImplicit {\n      get { return false; }\n    }\n\n    public static IEnumerable<Expression> Conjuncts(Expression expr) {\n      Contract.Requires(expr != null);\n      Contract.Requires(expr.Type.IsBoolType);\n      Contract.Ensures(cce.NonNullElements(Contract.Result<IEnumerable<Expression>>()));\n\n      expr = StripParens(expr);\n\n      var bin = expr as BinaryExpr;\n      if (bin != null && bin.ResolvedOp == BinaryExpr.ResolvedOpcode.And) {\n        foreach (Expression e in Conjuncts(bin.E0)) {\n          yield return e;\n        }\n        foreach (Expression e in Conjuncts(bin.E1)) {\n          yield return e;\n        }\n        yield break;\n      }\n      yield return expr;\n    }\n\n    /// <summary>\n    /// Create a resolved expression of the form \"e0 + e1\"\n    /// </summary>\n    public static Expression CreateAdd(Expression e0, Expression e1) {\n      Contract.Requires(e0 != null);\n      Contract.Requires(e1 != null);\n      Contract.Requires(\n        (e0.Type.IsNumericBased(Type.NumericPersuation.Int) && e1.Type.IsNumericBased(Type.NumericPersuation.Int)) ||\n        (e0.Type.IsNumericBased(Type.NumericPersuation.Real) && e1.Type.IsNumericBased(Type.NumericPersuation.Real)));\n      Contract.Ensures(Contract.Result<Expression>() != null);\n      var s = new BinaryExpr(e0.tok, BinaryExpr.Opcode.Add, e0, e1);\n      s.ResolvedOp = BinaryExpr.ResolvedOpcode.Add;  // resolve here\n      s.Type = e0.Type.NormalizeExpand();  // resolve here\n      return s;\n    }\n\n    /// <summary>\n    /// Create a resolved expression of the form \"e0 * e1\"\n    /// </summary>\n    public static Expression CreateMul(Expression e0, Expression e1) {\n      Contract.Requires(e0 != null);\n      Contract.Requires(e1 != null);\n      Contract.Requires(\n        (e0.Type.IsNumericBased(Type.NumericPersuation.Int) && e1.Type.IsNumericBased(Type.NumericPersuation.Int)) ||\n        (e0.Type.IsNumericBased(Type.NumericPersuation.Real) && e1.Type.IsNumericBased(Type.NumericPersuation.Real)));\n      Contract.Ensures(Contract.Result<Expression>() != null);\n      var s = new BinaryExpr(e0.tok, BinaryExpr.Opcode.Mul, e0, e1);\n      s.ResolvedOp = BinaryExpr.ResolvedOpcode.Mul;  // resolve here\n      s.Type = e0.Type.NormalizeExpand();  // resolve here\n      return s;\n    }\n\n    /// <summary>\n    /// Create a resolved expression of the form \"CVT(e0) - CVT(e1)\", where \"CVT\" is either \"int\" (if\n    /// e0.Type is an integer-based numeric type) or \"real\" (if e0.Type is a real-based numeric type).\n    /// </summary>\n    public static Expression CreateSubtract_TypeConvert(Expression e0, Expression e1) {\n      Contract.Requires(e0 != null);\n      Contract.Requires(e1 != null);\n      Contract.Requires(\n        (e0.Type.IsNumericBased(Type.NumericPersuation.Int) && e1.Type.IsNumericBased(Type.NumericPersuation.Int)) ||\n        (e0.Type.IsNumericBased(Type.NumericPersuation.Real) && e1.Type.IsNumericBased(Type.NumericPersuation.Real)));\n      Contract.Ensures(Contract.Result<Expression>() != null);\n\n      Type toType = e0.Type.IsNumericBased(Type.NumericPersuation.Int) ? (Type)Type.Int : Type.Real;\n      e0 = CastIfNeeded(e0, toType);\n      e1 = CastIfNeeded(e1, toType);\n      return CreateSubtract(e0, e1);\n    }\n\n    private static Expression CastIfNeeded(Expression expr, Type toType) {\n      if (!expr.Type.Equals(toType)) {\n        var cast = new ConversionExpr(expr.tok, expr, toType);\n        cast.Type = toType;\n        return cast;\n      } else {\n        return expr;\n      }\n    }\n\n    /// <summary>\n    /// Create a resolved expression of the form \"e0 - e1\"\n    /// </summary>\n    public static Expression CreateSubtract(Expression e0, Expression e1) {\n      Contract.Requires(e0 != null);\n      Contract.Requires(e0.Type != null);\n      Contract.Requires(e1 != null);\n      Contract.Requires(e1.Type != null);\n      Contract.Requires(\n        (e0.Type.IsNumericBased(Type.NumericPersuation.Int) && e1.Type.IsNumericBased(Type.NumericPersuation.Int)) ||\n        (e0.Type.IsNumericBased(Type.NumericPersuation.Real) && e1.Type.IsNumericBased(Type.NumericPersuation.Real)) ||\n        (e0.Type.IsBigOrdinalType && e1.Type.IsBigOrdinalType));\n      Contract.Ensures(Contract.Result<Expression>() != null);\n      var s = new BinaryExpr(e0.tok, BinaryExpr.Opcode.Sub, e0, e1);\n      s.ResolvedOp = BinaryExpr.ResolvedOpcode.Sub;  // resolve here\n      s.Type = e0.Type.NormalizeExpand();  // resolve here\n      return s;\n    }\n\n    /// <summary>\n    /// Create a resolved expression of the form \"e + n\"\n    /// </summary>\n    public static Expression CreateIncrement(Expression e, int n) {\n      Contract.Requires(e != null);\n      Contract.Requires(e.Type != null);\n      Contract.Requires(e.Type.IsNumericBased(Type.NumericPersuation.Int));\n      Contract.Requires(0 <= n);\n      Contract.Ensures(Contract.Result<Expression>() != null);\n      if (n == 0) {\n        return e;\n      }\n      var nn = CreateIntLiteral(e.tok, n);\n      return CreateAdd(e, nn);\n    }\n\n    /// <summary>\n    /// Create a resolved expression of the form \"e - n\"\n    /// </summary>\n    public static Expression CreateDecrement(Expression e, int n) {\n      Contract.Requires(e != null);\n      Contract.Requires(e.Type.IsNumericBased(Type.NumericPersuation.Int));\n      Contract.Requires(0 <= n);\n      Contract.Ensures(Contract.Result<Expression>() != null);\n      if (n == 0) {\n        return e;\n      }\n      var nn = CreateIntLiteral(e.tok, n);\n      return CreateSubtract(e, nn);\n    }\n\n    /// <summary>\n    /// Create a resolved expression of the form \"n\"\n    /// </summary>\n    public static Expression CreateIntLiteral(IToken tok, int n) {\n      Contract.Requires(tok != null);\n      Contract.Requires(n != int.MinValue);\n      if (0 <= n) {\n        var nn = new LiteralExpr(tok, n);\n        nn.Type = Type.Int;\n        return nn;\n      } else {\n        return CreateDecrement(CreateIntLiteral(tok, 0), -n);\n      }\n    }\n\n    /// <summary>\n    /// Create a resolved expression of the form \"x\"\n    /// </summary>\n    public static Expression CreateRealLiteral(IToken tok, BaseTypes.BigDec x) {\n      Contract.Requires(tok != null);\n      var nn = new LiteralExpr(tok, x);\n      nn.Type = Type.Real;\n      return nn;\n    }\n\n    /// <summary>\n    /// Create a resolved expression of the form \"n\", for either type \"int\" or type \"ORDINAL\".\n    /// </summary>\n    public static Expression CreateNatLiteral(IToken tok, int n, Type ty) {\n      Contract.Requires(tok != null);\n      Contract.Requires(0 <= n);\n      Contract.Requires(ty.IsNumericBased(Type.NumericPersuation.Int) || ty is BigOrdinalType);\n      var nn = new LiteralExpr(tok, n);\n      nn.Type = ty;\n      return nn;\n    }\n\n    /// <summary>\n    /// Create a resolved expression for a bool b\n    /// </summary>\n    public static Expression CreateBoolLiteral(IToken tok, bool b) {\n      Contract.Requires(tok != null);\n      var lit = new LiteralExpr(tok, b);\n      lit.Type = Type.Bool;  // resolve here\n      return lit;\n    }\n\n    /// <summary>\n    /// Returns \"expr\", but with all outer layers of parentheses removed.\n    /// This method can be called before resolution.\n    /// </summary>\n    public static Expression StripParens(Expression expr) {\n      while (true) {\n        var e = expr as ParensExpression;\n        if (e == null) {\n          return expr;\n        }\n        expr = e.E;\n      }\n    }\n\n    public static ThisExpr AsThis(Expression expr) {\n      Contract.Requires(expr != null);\n      return StripParens(expr) as ThisExpr;\n    }\n\n    /// <summary>\n    /// If \"expr\" denotes a boolean literal \"b\", then return \"true\" and set \"value\" to \"b\".\n    /// Otherwise, return \"false\" (and the value of \"value\" should not be used by the caller).\n    /// This method can be called before resolution.\n    /// </summary>\n    public static bool IsBoolLiteral(Expression expr, out bool value) {\n      Contract.Requires(expr != null);\n      var e = StripParens(expr) as LiteralExpr;\n      if (e != null && e.Value is bool) {\n        value = (bool)e.Value;\n        return true;\n      } else {\n        value = false;  // to please compiler\n        return false;\n      }\n    }\n\n    /// <summary>\n    /// Returns \"true\" if \"expr\" denotes the empty set (for \"iset\", \"set\", or \"multiset\").\n    /// This method can be called before resolution.\n    /// </summary>\n    public static bool IsEmptySetOrMultiset(Expression expr) {\n      Contract.Requires(expr != null);\n      expr = StripParens(expr);\n      return (expr is SetDisplayExpr && ((SetDisplayExpr)expr).Elements.Count == 0) ||\n        (expr is MultiSetDisplayExpr && ((MultiSetDisplayExpr)expr).Elements.Count == 0);\n    }\n\n    public static Expression CreateNot(IToken tok, Expression e) {\n      Contract.Requires(tok != null);\n      Contract.Requires(e.Type.IsBoolType);\n      var un = new UnaryOpExpr(tok, UnaryOpExpr.Opcode.Not, e);\n      un.Type = Type.Bool;  // resolve here\n      return un;\n    }\n\n    /// <summary>\n    /// Create a resolved expression of the form \"e0 LESS e1\"\n    /// </summary>\n    public static Expression CreateLess(Expression e0, Expression e1) {\n      Contract.Requires(e0 != null);\n      Contract.Requires(e1 != null);\n      Contract.Requires(\n        (e0.Type.IsNumericBased(Type.NumericPersuation.Int) && e1.Type.IsNumericBased(Type.NumericPersuation.Int)) ||\n        (e0.Type.IsBigOrdinalType && e1.Type.IsBigOrdinalType));\n      Contract.Ensures(Contract.Result<Expression>() != null);\n      var s = new BinaryExpr(e0.tok, BinaryExpr.Opcode.Lt, e0, e1);\n      s.ResolvedOp = BinaryExpr.ResolvedOpcode.Lt;  // resolve here\n      s.Type = Type.Bool;  // resolve here\n      return s;\n    }\n\n    /// <summary>\n    /// Create a resolved expression of the form \"e0 ATMOST e1\"\n    /// </summary>\n    public static Expression CreateAtMost(Expression e0, Expression e1) {\n      Contract.Requires(e0 != null);\n      Contract.Requires(e1 != null);\n      Contract.Requires(\n        (e0.Type.IsNumericBased(Type.NumericPersuation.Int) && e1.Type.IsNumericBased(Type.NumericPersuation.Int)) ||\n        (e0.Type.IsNumericBased(Type.NumericPersuation.Real) && e1.Type.IsNumericBased(Type.NumericPersuation.Real)));\n      Contract.Ensures(Contract.Result<Expression>() != null);\n      var s = new BinaryExpr(e0.tok, BinaryExpr.Opcode.Le, e0, e1);\n      s.ResolvedOp = BinaryExpr.ResolvedOpcode.Le;  // resolve here\n      s.Type = Type.Bool;  // resolve here\n      return s;\n    }\n\n    public static Expression CreateEq(Expression e0, Expression e1, Type ty) {\n      Contract.Requires(e0 != null);\n      Contract.Requires(e1 != null);\n      Contract.Requires(ty != null);\n      var eq = new BinaryExpr(e0.tok, BinaryExpr.Opcode.Eq, e0, e1);\n      if (ty is SetType) {\n        eq.ResolvedOp = BinaryExpr.ResolvedOpcode.SetEq;\n      } else if (ty is SeqType) {\n        eq.ResolvedOp = BinaryExpr.ResolvedOpcode.SeqEq;\n      } else if (ty is MultiSetType) {\n        eq.ResolvedOp = BinaryExpr.ResolvedOpcode.MultiSetEq;\n      } else if (ty is MapType) {\n        eq.ResolvedOp = BinaryExpr.ResolvedOpcode.MapEq;\n      } else {\n        eq.ResolvedOp = BinaryExpr.ResolvedOpcode.EqCommon;\n      }\n      eq.type = Type.Bool;\n      return eq;\n    }\n\n    /// <summary>\n    /// Create a resolved expression of the form \"e0 && e1\"\n    /// </summary>\n    public static Expression CreateAnd(Expression a, Expression b) {\n      Contract.Requires(a != null);\n      Contract.Requires(b != null);\n      Contract.Requires(a.Type.IsBoolType && b.Type.IsBoolType);\n      Contract.Ensures(Contract.Result<Expression>() != null);\n      if (LiteralExpr.IsTrue(a)) {\n        return b;\n      } else if (LiteralExpr.IsTrue(b)) {\n        return a;\n      } else {\n        var and = new BinaryExpr(a.tok, BinaryExpr.Opcode.And, a, b);\n        and.ResolvedOp = BinaryExpr.ResolvedOpcode.And;  // resolve here\n        and.Type = Type.Bool;  // resolve here\n        return and;\n      }\n    }\n\n    /// <summary>\n    /// Create a resolved expression of the form \"e0 ==> e1\"\n    /// </summary>\n    public static Expression CreateImplies(Expression a, Expression b) {\n      Contract.Requires(a != null);\n      Contract.Requires(b != null);\n      Contract.Requires(a.Type.IsBoolType && b.Type.IsBoolType);\n      Contract.Ensures(Contract.Result<Expression>() != null);\n      if (LiteralExpr.IsTrue(a) || LiteralExpr.IsTrue(b)) {\n        return b;\n      } else {\n        var imp = new BinaryExpr(a.tok, BinaryExpr.Opcode.Imp, a, b);\n        imp.ResolvedOp = BinaryExpr.ResolvedOpcode.Imp;  // resolve here\n        imp.Type = Type.Bool;  // resolve here\n        return imp;\n      }\n    }\n\n    /// <summary>\n    /// Create a resolved expression of the form \"if test then e0 else e1\"\n    /// </summary>\n    public static Expression CreateITE(Expression test, Expression e0, Expression e1) {\n      Contract.Requires(test != null);\n      Contract.Requires(e0 != null);\n      Contract.Requires(e1 != null);\n      Contract.Requires(test.Type.IsBoolType && e0.Type.Equals(e1.Type));\n      Contract.Ensures(Contract.Result<Expression>() != null);\n      var ite = new ITEExpr(test.tok, false, test, e0, e1);\n      ite.Type = e0.type;  // resolve here\n      return ite;\n    }\n\n    /// <summary>\n    /// Create a resolved case expression for a match expression\n    /// </summary>\n    public static MatchCaseExpr CreateMatchCase(MatchCaseExpr old_case, Expression new_body) {\n      Contract.Requires(old_case != null);\n      Contract.Requires(new_body != null);\n      Contract.Ensures(Contract.Result<MatchCaseExpr>() != null);\n\n      ResolvedCloner cloner = new ResolvedCloner();\n      var newVars = old_case.Arguments.ConvertAll(cloner.CloneBoundVar);\n      new_body = VarSubstituter(old_case.Arguments.ConvertAll<NonglobalVariable>(x=>(NonglobalVariable)x), newVars, new_body);\n\n      var new_case = new MatchCaseExpr(old_case.tok, old_case.Id, newVars, new_body);\n\n      new_case.Ctor = old_case.Ctor; // resolve here\n      return new_case;\n    }\n\n    /// <summary>\n    /// Create a match expression with a resolved type\n    /// </summary>\n    public static Expression CreateMatch(IToken tok, Expression src, List<MatchCaseExpr> cases, Type type) {\n      MatchExpr e = new MatchExpr(tok, src, cases, false);\n      e.Type = type;  // resolve here\n\n      return e;\n    }\n\n    /// <summary>\n    /// Create a let expression with a resolved type and fresh variables\n    /// </summary>\n    public static Expression CreateLet(IToken tok, List<CasePattern<BoundVar>> LHSs, List<Expression> RHSs, Expression body, bool exact) {\n      Contract.Requires(tok  != null);\n      Contract.Requires(LHSs != null && RHSs != null);\n      Contract.Requires(LHSs.Count == RHSs.Count);\n      Contract.Requires(body != null);\n\n      ResolvedCloner cloner = new ResolvedCloner();\n      var newLHSs = LHSs.ConvertAll(cloner.CloneCasePattern);\n\n      var oldVars = new List<BoundVar>();\n      LHSs.Iter(p => oldVars.AddRange(p.Vars));\n      var newVars = new List<BoundVar>();\n      newLHSs.Iter(p => newVars.AddRange(p.Vars));\n      body = VarSubstituter(oldVars.ConvertAll<NonglobalVariable>(x => (NonglobalVariable)x), newVars, body);\n\n      var let = new LetExpr(tok, newLHSs, RHSs, body, exact);\n      let.Type = body.Type;  // resolve here\n      return let;\n    }\n\n    /// <summary>\n    /// Create a quantifier expression with a resolved type and fresh variables\n    /// Optionally replace the old body with the supplied argument\n    /// </summary>\n    public static Expression CreateQuantifier(QuantifierExpr expr, bool forall,  Expression body = null) {\n      //(IToken tok, List<BoundVar> vars, Expression range, Expression body, Attributes attribs, Qu) {\n      Contract.Requires(expr != null);\n\n      ResolvedCloner cloner = new ResolvedCloner();\n      var newVars = expr.BoundVars.ConvertAll(cloner.CloneBoundVar);\n\n      if (body == null) {\n        body = expr.Term;\n      }\n\n      body = VarSubstituter(expr.BoundVars.ConvertAll<NonglobalVariable>(x=>(NonglobalVariable)x), newVars, body);\n\n      QuantifierExpr q;\n      if (forall) {\n        q = new ForallExpr(expr.tok, new List<TypeParameter>(), newVars, expr.Range, body, expr.Attributes);\n      } else {\n        q = new ExistsExpr(expr.tok, new List<TypeParameter>(), newVars, expr.Range, body, expr.Attributes);\n      }\n      q.Type = Type.Bool;\n\n      return q;\n    }\n\n    /// <summary>\n    /// Create a resolved IdentifierExpr (whose token is that of the variable)\n    /// </summary>\n    public static Expression CreateIdentExpr(IVariable v) {\n      Contract.Requires(v != null);\n      var e = new IdentifierExpr(v.Tok, v.Name);\n      e.Var = v;  // resolve here\n      e.type = v.Type;  // resolve here\n      return e;\n    }\n\n    public static Expression VarSubstituter(List<NonglobalVariable> oldVars, List<BoundVar> newVars, Expression e, Dictionary<TypeParameter, Type> typeMap=null) {\n      Contract.Requires(oldVars != null && newVars != null);\n      Contract.Requires(oldVars.Count == newVars.Count);\n\n      Dictionary<IVariable, Expression/*!*/> substMap = new Dictionary<IVariable, Expression>();\n      if (typeMap == null) {\n        typeMap = new Dictionary<TypeParameter, Type>();\n      }\n\n      for (int i = 0; i < oldVars.Count; i++) {\n        var id = new IdentifierExpr(newVars[i].tok, newVars[i].Name);\n        id.Var = newVars[i];    // Resolve here manually\n        id.Type = newVars[i].Type;  // Resolve here manually\n        substMap.Add(oldVars[i], id);\n      }\n\n      Translator.Substituter sub = new Translator.Substituter(null, substMap, typeMap);\n      return sub.Substitute(e);\n    }\n\n    /// <summary>\n    /// Returns the string literal underlying an actual string literal (not as a sequence display of characters)\n    /// </summary>\n    /// <returns></returns>\n    public string AsStringLiteral() {\n      var le = this as StringLiteralExpr;\n      return le == null ? null : le.Value as string;\n    }\n  }\n\n  /// <summary>\n  /// Instances of this class are introduced during resolution to indicate that a static method or function has\n  /// been invoked without specifying a receiver (that is, by just giving the name of the enclosing class).\n  /// </summary>\n  public class StaticReceiverExpr : LiteralExpr\n  {\n    public readonly Type UnresolvedType;\n    private bool Implicit;\n\n    public StaticReceiverExpr(IToken tok, Type t, bool isImplicit)\n      : base(tok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(t != null);\n      UnresolvedType = t;\n      Implicit = isImplicit;\n    }\n\n    /// <summary>\n    /// Constructs a resolved LiteralExpr representing the fictitious static-receiver literal whose type is\n    /// \"cl\" parameterized by the type arguments of \"cl\" itself.\n    /// </summary>\n    public StaticReceiverExpr(IToken tok, TopLevelDeclWithMembers cl, bool isImplicit)\n      : base(tok)\n    {\n      Contract.Requires(tok != null);\n      Contract.Requires(cl != null);\n      var typeArgs = cl.TypeArgs.ConvertAll(tp => (Type)new UserDefinedType(tp));\n      Type = new UserDefinedType(tok, cl is ClassDecl klass && klass.IsDefaultClass ? cl.Name : cl.Name + \"?\", cl, typeArgs);\n      UnresolvedType = Type;\n      Implicit = isImplicit;\n    }\n\n    /// <summary>\n    /// Constructs a resolved LiteralExpr representing the fictitious literal whose type is\n    /// \"cl\" parameterized according to the type arguments to \"t\".  It is assumed that \"t\" denotes\n    /// a class or trait that (possibly reflexively or transitively) extends \"cl\".\n    /// Examples:\n    /// * If \"t\" denotes \"C(G)\" and \"cl\" denotes \"C\", then the type of the StaticReceiverExpr\n    ///   will be \"C(G)\".\n    /// * Suppose \"C\" is a class that extends a trait \"T\"; then, if \"t\" denotes \"C\" and \"cl\" denotes\n    ///   \"T\", then the type of the StaticReceiverExpr will be \"T\".\n    /// * In the future, Dafny will support type parameters for traits and for classes that implement\n    ///   traits.  Then, suppose \"C(X)\" is a class that extends \"T(f(X))\", and that \"T(Y)\" is\n    ///   a trait that in turn extends trait \"W(g(Y))\".  If \"t\" denotes type \"C(G)\" and \"cl\" denotes \"W\",\n    ///   then type of the StaticReceiverExpr will be \"T(g(f(G)))\".\n    /// </summary>\n    public StaticReceiverExpr(IToken tok, UserDefinedType t, TopLevelDeclWithMembers cl, bool isImplicit)\n      : base(tok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(t.ResolvedClass != null);\n      Contract.Requires(cl != null);\n      if (t.ResolvedClass != cl) {\n        if (t.ResolvedClass is ClassDecl) {\n          var orig = (ClassDecl)t.ResolvedClass;\n          Contract.Assert(orig.TraitsObj.Contains(cl));  // Dafny currently supports only one level of inheritance from traits\n          Contract.Assert(orig.TypeArgs.Count == 0);  // Dafny currently only allows type-parameter-less classes to extend traits\n          Contract.Assert(cl.TypeArgs.Count == 0);  // Dafny currently does not support type parameters for traits\n        }\n        t = new UserDefinedType(tok, cl.Name, cl, new List<Type>());\n      }\n      Type = t;\n      UnresolvedType = Type;\n      Implicit = isImplicit;\n    }\n\n    public override bool IsImplicit {\n      get { return Implicit; }\n    }\n  }\n\n  public class LiteralExpr : Expression {\n    /// <summary>\n    /// One of the following:\n    ///   * 'null' for the 'null' literal (a special case of which is the subclass StaticReceiverExpr)\n    ///   * a bool for a bool literal\n    ///   * a BigInteger for int literal\n    ///   * a BaseTypes.BigDec for a (rational) real literal\n    ///   * a string for a char literal\n    ///     This case always uses the subclass CharLiteralExpr.\n    ///     Note, a string is stored to keep any escape sequence, since this simplifies printing of the character\n    ///     literal, both when pretty printed as a Dafny expression and when being compiled into C# code.  The\n    ///     parser checks the validity of any escape sequence and the verifier deals with turning such into a\n    ///     single character value.\n    ///   * a string for a string literal\n    ///     This case always uses the subclass StringLiteralExpr.\n    ///     Note, the string is stored with all escapes as characters.  For example, the input string \"hello\\n\" is\n    ///     stored in a LiteralExpr has being 7 characters long, whereas the Dafny (and C#) length of this string is 6.\n    ///     This simplifies printing of the string, both when pretty printed as a Dafny expression and when being\n    ///     compiled into C# code.  The parser checks the validity of the escape sequences and the verifier deals\n    ///     with turning them into single characters.\n    /// </summary>\n    public readonly object Value;\n\n    [Pure]\n    public static bool IsTrue(Expression e) {\n      Contract.Requires(e != null);\n      if (e is LiteralExpr) {\n        LiteralExpr le = (LiteralExpr)e;\n        return le.Value is bool && (bool)le.Value;\n      } else {\n        return false;\n      }\n    }\n\n    public LiteralExpr(IToken tok)\n      : base(tok) {  // represents the Dafny literal \"null\"\n      Contract.Requires(tok != null);\n      this.Value = null;\n    }\n\n    public LiteralExpr(IToken tok, BigInteger n)\n      : base(tok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(0 <= n.Sign);\n      this.Value = n;\n    }\n\n    public LiteralExpr(IToken tok, BaseTypes.BigDec n)\n      : base(tok) {\n      Contract.Requires(0 <= n.Mantissa.Sign);\n      Contract.Requires(tok != null);\n      this.Value = n;\n    }\n\n    public LiteralExpr(IToken tok, int n)\n      :base(tok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(0 <= n);\n      this.Value = new BigInteger(n);\n    }\n\n    public LiteralExpr(IToken tok, bool b)\n      : base(tok) {\n      Contract.Requires(tok != null);\n      this.Value = b;\n    }\n\n    /// <summary>\n    /// This constructor is to be used only with the StringLiteralExpr and CharLiteralExpr subclasses, for\n    /// two reasons:  both of these literals store a string in .Value, and string literals also carry an\n    /// additional field.\n    /// </summary>\n    protected LiteralExpr(IToken tok, string s)\n      : base(tok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(s != null);\n      this.Value = s;\n    }\n  }\n\n  public class CharLiteralExpr : LiteralExpr\n  {\n    public CharLiteralExpr(IToken tok, string s)\n      : base(tok, s) {\n      Contract.Requires(s != null);\n    }\n  }\n\n  public class StringLiteralExpr : LiteralExpr\n  {\n    public readonly bool IsVerbatim;\n    public StringLiteralExpr(IToken tok, string s, bool isVerbatim)\n      : base(tok, s) {\n      Contract.Requires(s != null);\n      IsVerbatim = isVerbatim;\n    }\n  }\n\n  public class DatatypeValue : Expression {\n    public readonly string DatatypeName;\n    public readonly string MemberName;\n    public readonly List<Expression> Arguments;\n    public DatatypeCtor Ctor;  // filled in by resolution\n    public List<Type> InferredTypeArgs = new List<Type>();  // filled in by resolution\n    public bool IsCoCall;  // filled in by resolution\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(DatatypeName != null);\n      Contract.Invariant(MemberName != null);\n      Contract.Invariant(cce.NonNullElements(Arguments));\n      Contract.Invariant(cce.NonNullElements(InferredTypeArgs));\n      Contract.Invariant(Ctor == null || InferredTypeArgs.Count == Ctor.EnclosingDatatype.TypeArgs.Count);\n    }\n\n    public DatatypeValue(IToken tok, string datatypeName, string memberName, [Captured] List<Expression> arguments)\n      : base(tok) {\n      Contract.Requires(cce.NonNullElements(arguments));\n      Contract.Requires(tok != null);\n      Contract.Requires(datatypeName != null);\n      Contract.Requires(memberName != null);\n      this.DatatypeName = datatypeName;\n      this.MemberName = memberName;\n      this.Arguments = arguments;\n    }\n\n    public override IEnumerable<Expression> SubExpressions {\n      get { return Arguments; }\n    }\n  }\n\n  public class ThisExpr : Expression {\n    public ThisExpr(IToken tok)\n      : base(tok) {\n      Contract.Requires(tok != null);\n    }\n  }\n\n  public class MeExpr : Expression {\n    public MeExpr(IToken tok) : base(tok) {\n      Contract.Requires(tok != null);\n    }\n  }\n\n  public class StoreBufferEmptyExpr : Expression {\n    public StoreBufferEmptyExpr(IToken tok) : base(tok) {\n      Contract.Requires(tok != null);\n    }\n  }\n\n  public class TotalStateExpr : Expression {\n    public TotalStateExpr(IToken tok) : base(tok) {\n      Contract.Requires(tok != null);\n    }\n  }\n\n  public class IfUndefinedExpr : Expression  {\n    public Expression PotentiallyUnsafe, SafeSubstitution;\n\n    public IfUndefinedExpr(IToken tok, Expression potentiallyUnsafe, Expression safeSubstitution) : base(tok) {\n      Contract.Requires(tok != null);\n      PotentiallyUnsafe = potentiallyUnsafe;\n      SafeSubstitution = safeSubstitution;\n    }\n  }\n\n  public class ExpressionPair {\n    public Expression A, B;\n    public ExpressionPair(Expression a, Expression b) {\n      Contract.Requires(a != null);\n      Contract.Requires(b != null);\n      A = a;\n      B = b;\n    }\n  }\n\n  public class ImplicitThisExpr : ThisExpr {\n    public ImplicitThisExpr(IToken tok)\n      : base(tok) {\n      Contract.Requires(tok != null);\n    }\n\n    public override bool IsImplicit {\n      get { return true; }\n    }\n  }\n\n  /// <summary>\n  /// An ImplicitThisExpr_ConstructorCall is used in the .InitCall of a TypeRhs,\n  /// which has a need for a \"throw-away receiver\".  Using a different type\n  /// gives a way to distinguish this receiver from other receivers, which\n  /// plays a role in checking the restrictions on divided block statements.\n  /// </summary>\n  public class ImplicitThisExpr_ConstructorCall : ImplicitThisExpr\n  {\n    public ImplicitThisExpr_ConstructorCall(IToken tok)\n      : base(tok) {\n      Contract.Requires(tok != null);\n    }\n  }\n\n  public class IdentifierExpr : Expression\n  {\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(Name != null);\n    }\n\n    public readonly string Name;\n    public IVariable Var;  // filled in by resolution\n\n    public IdentifierExpr(IToken tok, string name)\n      : base(tok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Name = name;\n    }\n    /// <summary>\n    /// Constructs a resolved IdentifierExpr.\n    /// </summary>\n    public IdentifierExpr(IToken tok, IVariable v)\n      : base(tok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(v != null);\n      Name = v.Name;\n      Var = v;\n      Type = v.Type;\n    }\n  }\n\n  /// <summary>\n  /// If an \"AutoGhostIdentifierExpr\" is used as the out-parameter of a ghost method or\n  /// a method with a ghost parameter, resolution will change the .Var's .IsGhost to true\n  /// automatically.  This class is intended to be used only as a communicate between the\n  /// parser and parts of the resolver.\n  /// </summary>\n  public class AutoGhostIdentifierExpr : IdentifierExpr\n  {\n    public AutoGhostIdentifierExpr(IToken tok, string name)\n      : base(tok, name) { }\n  }\n\n  /// <summary>\n  /// This class is used only inside the resolver itself. It stops responding in the AST in uncompleted name segments.\n  /// </summary>\n  class Resolver_IdentifierExpr : Expression\n  {\n    // The Resolver_IdentifierExpr either uses Decl and TypeArgs:\n    public readonly TopLevelDecl Decl;\n    public readonly List<Type> TypeArgs;\n    // ... or it uses TypeParamDecl:\n    public readonly TypeParameter TypeParamDecl;\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant((Decl != null) != (TypeParamDecl != null));  // The Decl / TypeParamDecl fields are exclusive\n      Contract.Invariant((Decl != null) == (TypeArgs != null));  // The Decl / TypeArgs fields are used together\n      Contract.Invariant(TypeArgs == null || TypeArgs.Count == Decl.TypeArgs.Count);\n      Contract.Invariant(Type == null || (Type is ResolverType_Module && TypeParamDecl == null) || Type is ResolverType_Type);\n    }\n\n    public abstract class ResolverType : Type\n    {\n    }\n    public class ResolverType_Module : ResolverType\n    {\n      [Pure]\n      public override string TypeName(ModuleDefinition context, bool parseAble) {\n        Contract.Assert(parseAble == false);\n        return \"#module\";\n      }\n      public override bool Equals(Type that) {\n        return that.NormalizeExpand() is ResolverType_Module;\n      }\n    }\n    public class ResolverType_Type : ResolverType {\n      [Pure]\n      public override string TypeName(ModuleDefinition context, bool parseAble) {\n        Contract.Assert(parseAble == false);\n        return \"#type\";\n      }\n      public override bool Equals(Type that) {\n        return that.NormalizeExpand() is ResolverType_Type;\n      }\n    }\n\n    public Resolver_IdentifierExpr(IToken tok, TopLevelDecl decl, List<Type> typeArgs)\n      : base(tok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(decl != null);\n      Contract.Requires(typeArgs != null && typeArgs.Count == decl.TypeArgs.Count);\n      Decl = decl;\n      TypeArgs = typeArgs;\n      Type = decl is ModuleDecl ? (Type)new ResolverType_Module() : new ResolverType_Type();\n    }\n    public Resolver_IdentifierExpr(IToken tok, TypeParameter tp)\n      : base(tok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(tp != null);\n      TypeParamDecl = tp;\n      Type = new ResolverType_Type();\n    }\n  }\n\n  public abstract class DisplayExpression : Expression {\n    public readonly List<Expression> Elements;\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(cce.NonNullElements(Elements));\n    }\n\n    public DisplayExpression(IToken tok, List<Expression> elements)\n      : base(tok) {\n      Contract.Requires(cce.NonNullElements(elements));\n      Elements = elements;\n    }\n\n    public override IEnumerable<Expression> SubExpressions {\n      get { return Elements; }\n    }\n  }\n\n  public class SetDisplayExpr : DisplayExpression {\n    public bool Finite;\n    public SetDisplayExpr(IToken tok, bool finite, List<Expression> elements)\n      : base(tok, elements) {\n      Contract.Requires(tok != null);\n      Contract.Requires(cce.NonNullElements(elements));\n      Finite = finite;\n    }\n  }\n\n  public class MultiSetDisplayExpr : DisplayExpression {\n    public MultiSetDisplayExpr(IToken tok, List<Expression> elements) : base(tok, elements) {\n      Contract.Requires(tok != null);\n      Contract.Requires(cce.NonNullElements(elements));\n    }\n  }\n\n  public class MapDisplayExpr : Expression {\n    public bool Finite;\n    public List<ExpressionPair> Elements;\n    public MapDisplayExpr(IToken tok, bool finite, List<ExpressionPair> elements)\n      : base(tok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(cce.NonNullElements(elements));\n      Finite = finite;\n      Elements = elements;\n    }\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        foreach (var ep in Elements) {\n          yield return ep.A;\n          yield return ep.B;\n        }\n      }\n    }\n  }\n  public class SeqDisplayExpr : DisplayExpression {\n    public SeqDisplayExpr(IToken tok, List<Expression> elements)\n      : base(tok, elements) {\n      Contract.Requires(cce.NonNullElements(elements));\n      Contract.Requires(tok != null);\n    }\n  }\n\n  public class MemberSelectExpr : Expression {\n    public readonly Expression Obj;\n    public readonly string MemberName;\n    public MemberDecl Member;          // filled in by resolution, will be a Field or Function\n    public List<Type> TypeApplication; // If Member is a Function or Method, then TypeApplication is the list of type arguments used with the enclosing class and the function/method itself; if it is a Field, then TypeApplication is the list of type arguments used with the enclosing class\n\n    public Dictionary<TypeParameter, Type> TypeArgumentSubstitutions() {\n      Contract.Requires(WasResolved());\n      Contract.Ensures(Contract.Result<Dictionary<TypeParameter, Type>>() != null);\n      Contract.Ensures(Contract.Result<Dictionary<TypeParameter, Type>>().Count == TypeApplication.Count);\n\n      var icallable = Member as ICallable;\n      Contract.Assert(Member.EnclosingClass.TypeArgs.Count + (icallable == null ? 0 : icallable.TypeArgs.Count) == TypeApplication.Count);  // a consequence of proper resolution\n      var subst = new Dictionary<TypeParameter, Type>();\n      var i = 0;\n      foreach (var tp in Member.EnclosingClass.TypeArgs) {\n        subst.Add(tp, TypeApplication[i]);\n        i++;\n      }\n      if (icallable != null) {\n        foreach (var tp in icallable.TypeArgs) {\n          subst.Add(tp, TypeApplication[i]);\n          i++;\n        }\n      }\n      return subst;\n    }\n\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(Obj != null);\n      Contract.Invariant(MemberName != null);\n      Contract.Invariant((Member != null) == (TypeApplication != null));  // TypeApplication is set whenever Member is set\n    }\n\n    public MemberSelectExpr(IToken tok, Expression obj, string memberName)\n      : base(tok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(obj != null);\n      Contract.Requires(memberName != null);\n      this.Obj = obj;\n      this.MemberName = memberName;\n    }\n\n    /// <summary>\n    /// Returns a resolved MemberSelectExpr for a field.\n    /// </summary>\n    public MemberSelectExpr(IToken tok, Expression obj, Field field)\n      : this(tok, obj, field.Name)\n    {\n      Contract.Requires(tok != null);\n      Contract.Requires(obj != null);\n      Contract.Requires(field != null);\n      Contract.Requires(obj.Type != null);  // \"obj\" is required to be resolved\n      this.Member = field;  // resolve here\n      if (field.EnclosingClass is TraitDecl) {\n        // It could be that the type of \"obj\" is a class that implements the trait.  If so,\n        // it would be necessary to map the class type instantiation to a type instantiation\n        // of the trait.  However, at present in Dafny, traits take no type arguments, so\n        // our job is easy.\n        Contract.Assert(field.EnclosingClass.TypeArgs.Count == 0);\n        this.TypeApplication = new List<Type>();\n      } else {\n        var receiverType = obj.Type.NormalizeExpand();\n        this.TypeApplication = receiverType.TypeArgs;  // resolve here\n      }\n      Contract.Assert(field.EnclosingClass == null || this.TypeApplication.Count == field.EnclosingClass.TypeArgs.Count);\n      var subst = new Dictionary<TypeParameter, Type>();\n      for (int i = 0; i < this.TypeApplication.Count; i++) {\n        subst.Add(field.EnclosingClass.TypeArgs[i], this.TypeApplication[i]);\n      }\n      this.Type = Resolver.SubstType(field.Type, subst);  // resolve here\n    }\n\n    public void MemberSelectCase(Action<Field> fieldK, Action<Function> functionK) {\n      MemberSelectCase<bool>(\n        f => {\n          fieldK(f);\n          return true;\n        },\n        f => {\n          functionK(f);\n          return true;\n        });\n    }\n\n    public A MemberSelectCase<A>(Func<Field,A> fieldK, Func<Function,A> functionK) {\n      var field = Member as Field;\n      var function = Member as Function;\n      if (field != null) {\n        return fieldK(field);\n      } else {\n        Contract.Assert(function != null);\n        return functionK(function);\n      }\n    }\n\n    public override IEnumerable<Expression> SubExpressions {\n      get { yield return Obj; }\n    }\n  }\n\n  public class SeqSelectExpr : Expression {\n    public readonly bool SelectOne;  // false means select a range\n    public readonly Expression Seq;\n    public readonly Expression E0;\n    public readonly Expression E1;\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(Seq != null);\n      Contract.Invariant(!SelectOne || E1 == null);\n    }\n\n    public SeqSelectExpr(IToken tok, bool selectOne, Expression seq, Expression e0, Expression e1)\n      : base(tok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(seq != null);\n      Contract.Requires(!selectOne || e1 == null);\n\n      SelectOne = selectOne;\n      Seq = seq;\n      E0 = e0;\n      E1 = e1;\n    }\n\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        yield return Seq;\n        if (E0 != null) yield return E0;\n        if (E1 != null) yield return E1;\n      }\n    }\n  }\n\n  public class MultiSelectExpr : Expression {\n    public readonly Expression Array;\n    public readonly List<Expression> Indices;\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(Array != null);\n      Contract.Invariant(cce.NonNullElements(Indices));\n      Contract.Invariant(1 <= Indices.Count);\n    }\n\n    public MultiSelectExpr(IToken tok, Expression array, List<Expression> indices)\n      : base(tok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(array != null);\n      Contract.Requires(cce.NonNullElements(indices) && 1 <= indices.Count);\n\n      Array = array;\n      Indices = indices;\n    }\n\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        yield return Array;\n        foreach (var e in Indices) {\n          yield return e;\n        }\n      }\n    }\n  }\n\n  /// <summary>\n  /// Represents an expression of the form A[B := C], where, syntactically, A, B, and C are expressions.\n  /// Successfully resolved, the expression stands for one of the following:\n  /// * if A is a sequence, then B is an integer-based index into the sequence and C's type is the sequence element type\n  /// * if A is a map(T,U), then B is a key of type T and C is a value of type U\n  /// * if A is a multiset, then B's type is the multiset element type and C is an integer-based numeric\n  /// * if A is a datatype, then B is the name of a destructor of A's type and C's type is the type of that destructor -- in\n  ///   this case, the resolver will set the ResolvedUpdateExpr to an expression that constructs an appropriate datatype value\n  /// </summary>\n  public class SeqUpdateExpr : Expression {\n    public readonly Expression Seq;\n    public readonly Expression Index;\n    public readonly Expression Value;\n    public Expression ResolvedUpdateExpr;       // filled in during resolution, if the SeqUpdateExpr corresponds to a datatype update\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(Seq != null);\n      Contract.Invariant(Index != null);\n      Contract.Invariant(Value != null);\n    }\n\n    public SeqUpdateExpr(IToken tok, Expression seq, Expression index, Expression val)\n      : base(tok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(seq != null);\n      Contract.Requires(index != null);\n      Contract.Requires(val != null);\n      Seq = seq;\n      Index = index;\n      Value = val;\n    }\n\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        if (ResolvedUpdateExpr == null)\n        {\n          yield return Seq;\n          yield return Index;\n          yield return Value;\n        }\n        else\n        {\n          foreach (var e in ResolvedUpdateExpr.SubExpressions)\n          {\n            yield return e;\n          }\n        }\n      }\n    }\n  }\n\n  public class ApplyExpr : Expression {\n    // The idea is that this apply expression does not need a type argument substitution,\n    // since lambda functions and anonymous functions are never polymorphic.\n    // Make a FunctionCallExpr otherwise, to call a resolvable anonymous function.\n    public readonly Expression Function;\n    public readonly List<Expression> Args;\n\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        yield return Function;\n        foreach (var e in Args) {\n          yield return e;\n        }\n      }\n    }\n\n    public ApplyExpr(IToken tok, Expression fn, List<Expression> args)\n      : base(tok)\n    {\n      Function = fn;\n      Args = args;\n    }\n  }\n\n  public class RevealExpr : Expression\n  {\n    public readonly Expression Expr;\n    public Expression ResolvedExpression;\n\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        if (ResolvedExpression != null) {\n          yield return ResolvedExpression;\n        }\n      }\n    }\n\n    public RevealExpr(IToken tok, Expression expr)\n      : base(tok)\n    {\n      this.Expr = expr;\n    }\n  }\n\n  public class FunctionCallExpr : Expression {\n    public readonly string Name;\n    public readonly Expression Receiver;\n    public readonly IToken OpenParen;  // can be null if Args.Count == 0\n    public readonly List<Expression> Args;\n    public Dictionary<TypeParameter, Type> TypeArgumentSubstitutions;  // created, initialized, and used by resolution (and also used by translation)\n    public enum CoCallResolution {\n      No,\n      Yes,\n      NoBecauseFunctionHasSideEffects,\n      NoBecauseFunctionHasPostcondition,\n      NoBecauseRecursiveCallsAreNotAllowedInThisContext,\n      NoBecauseIsNotGuarded,\n      NoBecauseRecursiveCallsInDestructiveContext\n    }\n    public CoCallResolution CoCall = CoCallResolution.No;  // indicates whether or not the call is a co-recursive call; filled in by resolution\n    public string CoCallHint = null;  // possible additional hint that can be used in verifier error message, filled in by resolver\n\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(Name != null);\n      Contract.Invariant(Receiver != null);\n      Contract.Invariant(cce.NonNullElements(Args));\n      Contract.Invariant(\n        Function == null || TypeArgumentSubstitutions == null ||\n        Contract.ForAll(\n          Function.TypeArgs,\n            a => TypeArgumentSubstitutions.ContainsKey(a)) &&\n        Contract.ForAll(\n          TypeArgumentSubstitutions.Keys,\n            a => Function.TypeArgs.Contains(a) || Function.EnclosingClass.TypeArgs.Contains(a)));\n    }\n\n    public Function Function;  // filled in by resolution\n\n    [Captured]\n    public FunctionCallExpr(IToken tok, string fn, Expression receiver, IToken openParen, [Captured] List<Expression> args)\n      : base(tok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(fn != null);\n      Contract.Requires(receiver != null);\n      Contract.Requires(cce.NonNullElements(args));\n      Contract.Requires(openParen != null || args.Count == 0);\n      Contract.Ensures(type == null);\n      Contract.Ensures(cce.Owner.Same(this, receiver));\n\n      this.Name = fn;\n      cce.Owner.AssignSame(this, receiver);\n      this.Receiver = receiver;\n      this.OpenParen = openParen;\n      this.Args = args;\n    }\n\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        yield return Receiver;\n        foreach (var e in Args) {\n          yield return e;\n        }\n      }\n    }\n  }\n\n  public class SeqConstructionExpr : Expression\n  {\n    public Expression N;\n    public Expression Initializer;\n    public SeqConstructionExpr(IToken tok, Expression length, Expression initializer)\n      : base(tok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(length != null);\n      Contract.Requires(initializer != null);\n      N = length;\n      Initializer = initializer;\n    }\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        yield return N;\n        yield return Initializer;\n      }\n    }\n  }\n\n  public class MultiSetFormingExpr : Expression\n  {\n    [Peer]\n    public readonly Expression E;\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(E != null);\n    }\n\n    [Captured]\n    public MultiSetFormingExpr(IToken tok, Expression expr)\n      : base(tok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(expr != null);\n      cce.Owner.AssignSame(this, expr);\n      E = expr;\n    }\n\n    public override IEnumerable<Expression> SubExpressions {\n      get { yield return E; }\n    }\n  }\n\n  public class OldExpr : Expression\n  {\n    [Peer]\n    public readonly Expression E;\n    public readonly string/*?*/ At;\n    public Label AtLabel;  // filled in during resolution; after that, At==null iff AtLabel==null\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(E != null);\n    }\n\n    [Captured]\n    public OldExpr(IToken tok, Expression expr, string at = null)\n      : base(tok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(expr != null);\n      cce.Owner.AssignSame(this, expr);\n      E = expr;\n      At = at;\n    }\n\n    public override IEnumerable<Expression> SubExpressions {\n      get { yield return E; }\n    }\n  }\n\n  public class UnchangedExpr : Expression\n  {\n    public readonly List<FrameExpression> Frame;\n    public readonly string/*?*/ At;\n    public Label AtLabel;  // filled in during resolution; after that, At==null iff AtLabel==null\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(Frame != null);\n    }\n\n    public UnchangedExpr(IToken tok, List<FrameExpression> frame, string/*?*/ at)\n      : base(tok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(frame != null);\n      this.Frame = frame;\n      this.At = at;\n    }\n\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        foreach (var fe in Frame) {\n          yield return fe.E;\n        }\n      }\n    }\n  }\n\n  public abstract class UnaryExpr : Expression\n  {\n    public readonly Expression E;\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(E != null);\n    }\n\n    public UnaryExpr(IToken tok, Expression e)\n      : base(tok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(e != null);\n      this.E = e;\n    }\n\n    public override IEnumerable<Expression> SubExpressions {\n      get { yield return E; }\n    }\n  }\n\n  public class UnaryOpExpr : UnaryExpr\n  {\n    public enum Opcode {\n      Not,  // boolean negation or bitwise negation\n      Cardinality,\n      Fresh,\n      Allocated,\n      Lit,  // there is no syntax for this operator, but it is sometimes introduced during translation\n      AddressOf,\n      Dereference,\n      AllocatedArray,\n      GlobalView\n    }\n    public readonly Opcode Op;\n\n    public UnaryOpExpr(IToken tok, Opcode op, Expression e)\n      : base(tok, e) {\n      Contract.Requires(tok != null);\n      Contract.Requires(e != null);\n      this.Op = op;\n    }\n  }\n\n  public class ConversionExpr : UnaryExpr\n  {\n    public readonly Type ToType;\n    public ConversionExpr(IToken tok, Expression expr, Type toType)\n      : base(tok, expr) {\n      Contract.Requires(tok != null);\n      Contract.Requires(expr != null);\n      Contract.Requires(toType != null);\n      ToType = toType;\n    }\n  }\n\n  public class BinaryExpr : Expression\n  {\n    public enum Opcode {\n      Iff,\n      Imp,\n      Exp, // turned into Imp during resolution\n      And,\n      Or,\n      Eq,\n      Neq,\n      Lt,\n      Le,\n      Ge,\n      Gt,\n      Disjoint,\n      In,\n      NotIn,\n      LeftShift,\n      RightShift,\n      Add,\n      Sub,\n      Mul,\n      Div,\n      Mod,\n      BitwiseAnd,\n      BitwiseOr,\n      BitwiseXor\n    }\n    public readonly Opcode Op;\n    public enum ResolvedOpcode {\n      YetUndetermined,  // the value before resolution has determined the value; .ResolvedOp should never be read in this state\n\n      // logical operators\n      Iff,\n      Imp,\n      And,\n      Or,\n      // non-collection types\n      EqCommon,\n      NeqCommon,\n      // integers, reals, bitvectors\n      Lt,\n      LessThanLimit,  // a synonym for Lt for ORDINAL, used only during translation\n      Le,\n      Ge,\n      Gt,\n      Add,\n      Sub,\n      Mul,\n      Div,\n      Mod,\n      // bitvectors\n      LeftShift,\n      RightShift,\n      BitwiseAnd,\n      BitwiseOr,\n      BitwiseXor,\n      // char\n      LtChar,\n      LeChar,\n      GeChar,\n      GtChar,\n      // sets\n      SetEq,\n      SetNeq,\n      ProperSubset,\n      Subset,\n      Superset,\n      ProperSuperset,\n      Disjoint,\n      InSet,\n      NotInSet,\n      Union,\n      Intersection,\n      SetDifference,\n      // multi-sets\n      MultiSetEq,\n      MultiSetNeq,\n      MultiSubset,\n      MultiSuperset,\n      ProperMultiSubset,\n      ProperMultiSuperset,\n      MultiSetDisjoint,\n      InMultiSet,\n      NotInMultiSet,\n      MultiSetUnion,\n      MultiSetIntersection,\n      MultiSetDifference,\n      // Sequences\n      SeqEq,\n      SeqNeq,\n      ProperPrefix,\n      Prefix,\n      Concat,\n      InSeq,\n      NotInSeq,\n      // Maps\n      MapEq,\n      MapNeq,\n      InMap,\n      NotInMap,\n      MapDisjoint,\n      MapUnion,\n      // datatypes\n      RankLt,\n      RankGt\n    }\n    private ResolvedOpcode _theResolvedOp = ResolvedOpcode.YetUndetermined;\n    public ResolvedOpcode ResolvedOp {\n      set {\n        Contract.Assume(_theResolvedOp == ResolvedOpcode.YetUndetermined || _theResolvedOp == value);  // there's never a reason for resolution to change its mind, is there?\n        _theResolvedOp = value;\n      }\n      get {\n        Contract.Assume(_theResolvedOp != ResolvedOpcode.YetUndetermined);  // shouldn't read it until it has been properly initialized\n        return _theResolvedOp;\n      }\n    }\n    public ResolvedOpcode ResolvedOp_PossiblyStillUndetermined {  // offer a way to return _theResolveOp -- for experts only!\n      get { return _theResolvedOp; }\n    }\n    public static bool IsEqualityOp(ResolvedOpcode op) {\n      switch (op) {\n        case ResolvedOpcode.EqCommon:\n        case ResolvedOpcode.SetEq:\n        case ResolvedOpcode.SeqEq:\n        case ResolvedOpcode.MultiSetEq:\n        case ResolvedOpcode.MapEq:\n          return true;\n        default:\n          return false;\n      }\n    }\n\n    public static Opcode ResolvedOp2SyntacticOp(ResolvedOpcode rop) {\n      switch (rop) {\n        case ResolvedOpcode.Iff: return Opcode.Iff;\n        case ResolvedOpcode.Imp: return Opcode.Imp;\n        case ResolvedOpcode.And: return Opcode.And;\n        case ResolvedOpcode.Or: return Opcode.Or;\n\n        case ResolvedOpcode.EqCommon:\n        case ResolvedOpcode.SetEq:\n        case ResolvedOpcode.MultiSetEq:\n        case ResolvedOpcode.SeqEq:\n        case ResolvedOpcode.MapEq:\n          return Opcode.Eq;\n\n        case ResolvedOpcode.NeqCommon:\n        case ResolvedOpcode.SetNeq:\n        case ResolvedOpcode.MultiSetNeq:\n        case ResolvedOpcode.SeqNeq:\n        case ResolvedOpcode.MapNeq:\n          return Opcode.Neq;\n\n        case ResolvedOpcode.Lt:\n        case ResolvedOpcode.LtChar:\n        case ResolvedOpcode.ProperSubset:\n        case ResolvedOpcode.ProperMultiSuperset:\n        case ResolvedOpcode.ProperPrefix:\n        case ResolvedOpcode.RankLt:\n          return Opcode.Lt;\n\n        case ResolvedOpcode.Le:\n        case ResolvedOpcode.LeChar:\n        case ResolvedOpcode.Subset:\n        case ResolvedOpcode.MultiSubset:\n        case ResolvedOpcode.Prefix:\n          return Opcode.Le;\n\n        case ResolvedOpcode.Ge:\n        case ResolvedOpcode.GeChar:\n        case ResolvedOpcode.Superset:\n        case ResolvedOpcode.MultiSuperset:\n          return Opcode.Ge;\n\n        case ResolvedOpcode.Gt:\n        case ResolvedOpcode.GtChar:\n        case ResolvedOpcode.ProperSuperset:\n        case ResolvedOpcode.ProperMultiSubset:\n        case ResolvedOpcode.RankGt:\n          return Opcode.Gt;\n\n        case ResolvedOpcode.LeftShift:\n          return Opcode.LeftShift;\n\n        case ResolvedOpcode.RightShift:\n          return Opcode.RightShift;\n\n        case ResolvedOpcode.Add:\n        case ResolvedOpcode.Union:\n        case ResolvedOpcode.MultiSetUnion:\n        case ResolvedOpcode.MapUnion:\n        case ResolvedOpcode.Concat:\n          return Opcode.Add;\n\n        case ResolvedOpcode.Sub:\n        case ResolvedOpcode.SetDifference:\n        case ResolvedOpcode.MultiSetDifference:\n          return Opcode.Sub;\n\n        case ResolvedOpcode.Mul:\n        case ResolvedOpcode.Intersection:\n        case ResolvedOpcode.MultiSetIntersection:\n          return Opcode.Mul;\n\n        case ResolvedOpcode.Div: return Opcode.Div;\n        case ResolvedOpcode.Mod: return Opcode.Mod;\n\n        case ResolvedOpcode.BitwiseAnd: return Opcode.BitwiseAnd;\n        case ResolvedOpcode.BitwiseOr: return Opcode.BitwiseOr;\n        case ResolvedOpcode.BitwiseXor: return Opcode.BitwiseXor;\n\n        case ResolvedOpcode.Disjoint:\n        case ResolvedOpcode.MultiSetDisjoint:\n        case ResolvedOpcode.MapDisjoint:\n          return Opcode.Disjoint;\n\n        case ResolvedOpcode.InSet:\n        case ResolvedOpcode.InMultiSet:\n        case ResolvedOpcode.InSeq:\n        case ResolvedOpcode.InMap:\n          return Opcode.In;\n\n        case ResolvedOpcode.NotInSet:\n        case ResolvedOpcode.NotInMultiSet:\n        case ResolvedOpcode.NotInSeq:\n        case ResolvedOpcode.NotInMap:\n          return Opcode.NotIn;\n\n        case ResolvedOpcode.LessThanLimit:  // not expected here (but if it were, the same case as Lt could perhaps be used)\n        default:\n          Contract.Assert(false);  // unexpected ResolvedOpcode\n          return Opcode.Add;  // please compiler\n      }\n    }\n\n    public static string OpcodeString(Opcode op) {\n      Contract.Ensures(Contract.Result<string>() != null);\n\n      switch (op) {\n        case Opcode.Iff:\n          return \"<==>\";\n        case Opcode.Imp:\n          return \"==>\";\n        case Opcode.Exp:\n          return \"<==\";\n        case Opcode.And:\n          return \"&&\";\n        case Opcode.Or:\n          return \"||\";\n        case Opcode.Eq:\n          return \"==\";\n        case Opcode.Lt:\n          return \"<\";\n        case Opcode.Gt:\n          return \">\";\n        case Opcode.Le:\n          return \"<=\";\n        case Opcode.Ge:\n          return \">=\";\n        case Opcode.Neq:\n          return \"!=\";\n        case Opcode.Disjoint:\n          return \"!!\";\n        case Opcode.In:\n          return \"in\";\n        case Opcode.NotIn:\n          return \"!in\";\n        case Opcode.LeftShift:\n          return \"<<\";\n        case Opcode.RightShift:\n          return \">>\";\n        case Opcode.Add:\n          return \"+\";\n        case Opcode.Sub:\n          return \"-\";\n        case Opcode.Mul:\n          return \"*\";\n        case Opcode.Div:\n          return \"/\";\n        case Opcode.Mod:\n          return \"%\";\n        case Opcode.BitwiseAnd:\n          return \"&\";\n        case Opcode.BitwiseOr:\n          return \"|\";\n        case Opcode.BitwiseXor:\n          return \"^\";\n        default:\n          Contract.Assert(false);\n          throw new cce.UnreachableException();  // unexpected operator\n      }\n    }\n    public readonly Expression E0;\n    public readonly Expression E1;\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(E0 != null);\n      Contract.Invariant(E1 != null);\n    }\n\n\n    public BinaryExpr(IToken tok, Opcode op, Expression e0, Expression e1)\n      : base(tok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(e0 != null);\n      Contract.Requires(e1 != null);\n      this.Op = op;\n      this.E0 = e0;\n      this.E1 = e1;\n    }\n\n    /// <summary>\n    /// Returns a resolved binary expression\n    /// </summary>\n    public BinaryExpr(Boogie.IToken tok, BinaryExpr.ResolvedOpcode rop, Expression e0, Expression e1)\n    : this(tok, BinaryExpr.ResolvedOp2SyntacticOp(rop), e0, e1) {\n      ResolvedOp = rop;\n      Type = Type.Bool;\n    }\n\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        yield return E0;\n        yield return E1;\n      }\n    }\n  }\n\n  public class TernaryExpr : Expression\n  {\n    public readonly Opcode Op;\n    public readonly Expression E0;\n    public readonly Expression E1;\n    public readonly Expression E2;\n    public enum Opcode { /*SOON: IfOp,*/ PrefixEqOp, PrefixNeqOp }\n    public static readonly bool PrefixEqUsesNat = false;  // \"k\" is either a \"nat\" or an \"ORDINAL\"\n    public TernaryExpr(IToken tok, Opcode op, Expression e0, Expression e1, Expression e2)\n      : base(tok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(e0 != null);\n      Contract.Requires(e1 != null);\n      Contract.Requires(e2 != null);\n      Op = op;\n      E0 = e0;\n      E1 = e1;\n      E2 = e2;\n    }\n\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        yield return E0;\n        yield return E1;\n        yield return E2;\n      }\n    }\n  }\n\n  public class LetExpr : Expression, IAttributeBearingDeclaration\n  {\n    public readonly List<CasePattern<BoundVar>> LHSs;\n    public readonly List<Expression> RHSs;\n    public readonly Expression Body;\n    public readonly bool Exact;  // Exact==true means a regular let expression; Exact==false means an assign-such-that expression\n    public readonly Attributes Attributes;\n    public List<ComprehensionExpr.BoundedPool> Constraint_Bounds;  // initialized and filled in by resolver; null for Exact=true and for when expression is in a ghost context\n    // invariant Constraint_Bounds == null || Constraint_Bounds.Count == BoundVars.Count;\n    private Expression translationDesugaring;  // filled in during translation, lazily; to be accessed only via Translation.LetDesugaring; always null when Exact==true\n    private Translator lastTranslatorUsed; // avoid clashing desugaring between translators\n\n    public void setTranslationDesugaring(Translator trans, Expression expr){\n      lastTranslatorUsed = trans;\n      translationDesugaring = expr;\n    }\n\n    public Expression getTranslationDesugaring(Translator trans) {\n      if (lastTranslatorUsed == trans) {\n        return translationDesugaring;\n      } else {\n        return null;\n      }\n    }\n\n    public LetExpr(IToken tok, List<CasePattern<BoundVar>> lhss, List<Expression> rhss, Expression body, bool exact, Attributes attrs = null)\n      : base(tok) {\n      LHSs = lhss;\n      RHSs = rhss;\n      Body = body;\n      Exact = exact;\n      Attributes = attrs;\n    }\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        foreach (var e in Attributes.SubExpressions(Attributes)) {\n          yield return e;\n        }\n        foreach (var rhs in RHSs) {\n          yield return rhs;\n        }\n        yield return Body;\n      }\n    }\n    public IEnumerable<BoundVar> BoundVars {\n      get {\n        foreach (var lhs in LHSs) {\n          foreach (var bv in lhs.Vars) {\n            yield return bv;\n          }\n        }\n      }\n    }\n  }\n\n  public class LetOrFailExpr : ConcreteSyntaxExpression\n  {\n    public readonly CasePattern<BoundVar>/*?*/ Lhs; // null means void-error handling: \":- E; F\", non-null means \"var pat :- E; F\"\n    public readonly Expression Rhs;\n    public readonly Expression Body;\n\n    public LetOrFailExpr(IToken tok, CasePattern<BoundVar>/*?*/ lhs, Expression rhs, Expression body): base(tok) {\n      Lhs = lhs;\n      Rhs = rhs;\n      Body = body;\n    }\n  }\n\n  // Represents expr Name: Body\n  //         or expr Name: (assert Body == Contract; Body)\n  public class NamedExpr : Expression\n  {\n    public readonly string Name;\n    public readonly Expression Body;\n    public readonly Expression Contract;\n    public readonly IToken ReplacerToken;\n\n    public NamedExpr(IToken tok, string p, Expression body)\n      : base(tok) {\n      Name = p;\n      Body = body;\n    }\n    public NamedExpr(IToken tok, string p, Expression body, Expression contract, IToken token)\n      : base(tok) {\n      Name = p;\n      Body = body;\n      Contract = contract;\n      ReplacerToken = token;\n    }\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        yield return Body;\n        if (Contract != null) yield return Contract;\n      }\n    }\n  }\n\n  /// <summary>\n  /// A ComprehensionExpr has the form:\n  ///   BINDER x Attributes | Range(x) :: Term(x)\n  /// When BINDER is \"forall\" or \"exists\", the range may be \"null\" (which stands for the logical value \"true\").\n  /// For other BINDERs (currently, \"set\"), the range is non-null.\n  /// where \"Attributes\" is optional, and \"| Range(x)\" is optional and defaults to \"true\".\n  /// Currently, BINDER is one of the logical quantifiers \"exists\" or \"forall\".\n  /// </summary>\n  public abstract class ComprehensionExpr : Expression, IAttributeBearingDeclaration\n  {\n    public readonly List<BoundVar> BoundVars;\n    public readonly Expression Range;\n    private Expression term;\n    public Expression Term { get { return term; } }\n\n    public void UpdateTerm(Expression newTerm) {\n      term = newTerm;\n    }\n\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(BoundVars != null);\n      Contract.Invariant(Term != null);\n    }\n\n    public Attributes Attributes;\n\n    public abstract class BoundedPool {\n      [Flags]\n      public enum PoolVirtues { None = 0, Finite = 1, Enumerable = 2, IndependentOfAlloc = 4, IndependentOfAlloc_or_ExplicitAlloc = 8 }\n      public abstract PoolVirtues Virtues { get; }\n      /// <summary>\n      /// A higher preference is better.\n      /// A preference below 2 is a last-resort bounded pool. Bounds discovery will not consider\n      /// such a pool to be final until there are no other choices.\n      ///\n      /// For easy reference, here is the BoundedPool hierarchy and their preference levels:\n      ///\n      /// 0: AllocFreeBoundedPool\n      /// 0: ExplicitAllocatedBoundedPool\n      /// 0: SpecialAllocIndependenceAllocatedBoundedPool\n      ///\n      /// 1: WiggleWaggleBound\n      ///\n      /// 2: SuperSetBoundedPool\n      /// 2: DatatypeInclusionBoundedPool\n      ///\n      /// 3: SubSetBoundedPool\n      ///\n      /// 4: IntBoundedPool with one bound\n      /// 5: IntBoundedPool with both bounds\n      /// 5: CharBoundedPool\n      ///\n      /// 8: DatatypeBoundedPool\n      ///\n      /// 10: CollectionBoundedPool\n      ///     - SetBoundedPool\n      ///     - MapBoundedPool\n      ///     - SeqBoundedPool\n      ///\n      /// 14: BoolBoundedPool\n      ///\n      /// 15: ExactBoundedPool\n      /// </summary>\n      public abstract int Preference(); // higher is better\n\n      public static BoundedPool GetBest(List<BoundedPool> bounds, PoolVirtues requiredVirtues) {\n        Contract.Requires(bounds != null);\n        bounds = CombineIntegerBounds(bounds);\n        BoundedPool best = null;\n        foreach (var bound in bounds) {\n          if ((bound.Virtues & requiredVirtues) == requiredVirtues) {\n            if (best == null || bound.Preference() > best.Preference()) {\n              best = bound;\n            }\n          }\n        }\n        return best;\n      }\n      public static List<VT> MissingBounds<VT>(List<VT> vars, List<BoundedPool> bounds, PoolVirtues requiredVirtues = PoolVirtues.None) where VT : IVariable {\n        Contract.Requires(vars != null);\n        Contract.Requires(bounds != null);\n        Contract.Requires(vars.Count == bounds.Count);\n        Contract.Ensures(Contract.Result<List<VT>>() != null);\n        var missing = new List<VT>();\n        for (var i = 0; i < vars.Count; i++) {\n          if (bounds[i] == null || (bounds[i].Virtues & requiredVirtues) != requiredVirtues) {\n            missing.Add(vars[i]);\n          }\n        }\n        return missing;\n      }\n      public static List<bool> HasBounds(List<BoundedPool> bounds, PoolVirtues requiredVirtues = PoolVirtues.None) {\n        Contract.Requires(bounds != null);\n        Contract.Ensures(Contract.Result<List<bool>>() != null);\n        Contract.Ensures(Contract.Result<List<bool>>().Count == bounds.Count);\n        return bounds.ConvertAll(bound => bound != null && (bound.Virtues & requiredVirtues) == requiredVirtues);\n      }\n      static List<BoundedPool> CombineIntegerBounds(List<BoundedPool> bounds) {\n        var lowerBounds = new List<IntBoundedPool>();\n        var upperBounds = new List<IntBoundedPool>();\n        var others = new List<BoundedPool>();\n        foreach (var b in bounds) {\n          var ib = b as IntBoundedPool;\n          if (ib != null && ib.UpperBound == null) {\n            lowerBounds.Add(ib);\n          } else if (ib != null && ib.LowerBound == null) {\n            upperBounds.Add(ib);\n          } else {\n            others.Add(b);\n          }\n        }\n        // pair up the bounds\n        var n = Math.Min(lowerBounds.Count, upperBounds.Count);\n        for (var i = 0; i < n; i++) {\n          others.Add(new IntBoundedPool(lowerBounds[i].LowerBound, upperBounds[i].UpperBound));\n        }\n        for (var i = n; i < lowerBounds.Count; i++) {\n          others.Add(lowerBounds[i]);\n        }\n        for (var i = n; i < upperBounds.Count; i++) {\n          others.Add(upperBounds[i]);\n        }\n        return others;\n      }\n    }\n    public class ExactBoundedPool : BoundedPool\n    {\n      public readonly Expression E;\n      public ExactBoundedPool(Expression e) {\n        Contract.Requires(e != null);\n        E = e;\n      }\n      public override PoolVirtues Virtues => PoolVirtues.Finite | PoolVirtues.Enumerable | PoolVirtues.IndependentOfAlloc | PoolVirtues.IndependentOfAlloc_or_ExplicitAlloc;\n      public override int Preference() => 15;  // the best of all bounds\n    }\n    public class BoolBoundedPool : BoundedPool\n    {\n      public override PoolVirtues Virtues => PoolVirtues.Finite | PoolVirtues.Enumerable | PoolVirtues.IndependentOfAlloc | PoolVirtues.IndependentOfAlloc_or_ExplicitAlloc;\n      public override int Preference() => 14;\n    }\n    public class CharBoundedPool : BoundedPool\n    {\n      public override PoolVirtues Virtues => PoolVirtues.Finite | PoolVirtues.Enumerable | PoolVirtues.IndependentOfAlloc | PoolVirtues.IndependentOfAlloc_or_ExplicitAlloc;\n      public override int Preference() => 5;\n    }\n    public class AllocFreeBoundedPool : BoundedPool\n    {\n      public Type Type;\n      public AllocFreeBoundedPool(Type t) {\n        Type = t;\n      }\n      public override PoolVirtues Virtues {\n        get {\n          if (Type.IsRefType) {\n            return PoolVirtues.Finite | PoolVirtues.IndependentOfAlloc | PoolVirtues.IndependentOfAlloc_or_ExplicitAlloc;\n          } else {\n            return PoolVirtues.IndependentOfAlloc | PoolVirtues.IndependentOfAlloc_or_ExplicitAlloc;\n          }\n        }\n      }\n      public override int Preference() => 0;\n    }\n    public class ExplicitAllocatedBoundedPool : BoundedPool\n    {\n      public ExplicitAllocatedBoundedPool() {\n      }\n      public override PoolVirtues Virtues => PoolVirtues.Finite | PoolVirtues.IndependentOfAlloc_or_ExplicitAlloc;\n      public override int Preference() => 0;\n    }\n    public class SpecialAllocIndependenceAllocatedBoundedPool : BoundedPool\n    {\n      public SpecialAllocIndependenceAllocatedBoundedPool() {\n      }\n      public override PoolVirtues Virtues => PoolVirtues.IndependentOfAlloc_or_ExplicitAlloc;\n      public override int Preference() => 0;\n    }\n    public class IntBoundedPool : BoundedPool\n    {\n      public readonly Expression LowerBound;\n      public readonly Expression UpperBound;\n      public IntBoundedPool(Expression lowerBound, Expression upperBound) {\n        Contract.Requires(lowerBound != null || upperBound != null);\n        LowerBound = lowerBound;\n        UpperBound = upperBound;\n      }\n      public override PoolVirtues Virtues {\n        get {\n          if (LowerBound != null && UpperBound != null) {\n            return PoolVirtues.Finite | PoolVirtues.Enumerable | PoolVirtues.IndependentOfAlloc | PoolVirtues.IndependentOfAlloc_or_ExplicitAlloc;\n          } else {\n            return PoolVirtues.Enumerable | PoolVirtues.IndependentOfAlloc | PoolVirtues.IndependentOfAlloc_or_ExplicitAlloc;\n          }\n        }\n      }\n      public override int Preference() => LowerBound != null && UpperBound != null ? 5 : 4;\n    }\n    public abstract class CollectionBoundedPool : BoundedPool\n    {\n      public readonly bool ExactTypes;\n      public readonly bool IsFiniteCollection;\n      public CollectionBoundedPool(bool exactTypes, bool isFiniteCollection) {\n        ExactTypes = exactTypes;\n        IsFiniteCollection = isFiniteCollection;\n      }\n      public override PoolVirtues Virtues {\n        get {\n          var v = PoolVirtues.IndependentOfAlloc;\n          if (IsFiniteCollection) {\n            v |= PoolVirtues.Finite;\n            if (ExactTypes) {\n              v |= PoolVirtues.Enumerable | PoolVirtues.IndependentOfAlloc_or_ExplicitAlloc;\n            }\n          }\n          return v;\n        }\n      }\n      public override int Preference() => 10;\n    }\n    public class SetBoundedPool : CollectionBoundedPool\n    {\n      public readonly Expression Set;\n      public SetBoundedPool(Expression set, bool exactTypes, bool isFiniteCollection) : base(exactTypes, isFiniteCollection) { Set = set; }\n    }\n    public class SubSetBoundedPool : BoundedPool\n    {\n      public readonly Expression UpperBound;\n      public readonly bool IsFiniteCollection;\n      public SubSetBoundedPool(Expression set, bool isFiniteCollection) {\n        UpperBound = set;\n        IsFiniteCollection = isFiniteCollection;\n      }\n      public override PoolVirtues Virtues {\n        get {\n          if (IsFiniteCollection) {\n            return PoolVirtues.Finite | PoolVirtues.Enumerable | PoolVirtues.IndependentOfAlloc | PoolVirtues.IndependentOfAlloc_or_ExplicitAlloc;\n          } else {\n            // it's still enumerable, because at run time, all sets are finite after all\n            return PoolVirtues.Enumerable | PoolVirtues.IndependentOfAlloc | PoolVirtues.IndependentOfAlloc_or_ExplicitAlloc;\n          }\n        }\n      }\n      public override int Preference() => 3;\n    }\n    public class SuperSetBoundedPool : BoundedPool\n    {\n      public readonly Expression LowerBound;\n      public SuperSetBoundedPool(Expression set) { LowerBound = set; }\n      public override int Preference() => 2;\n      public override PoolVirtues Virtues {\n        get {\n          if (LowerBound.Type.IsAllocFree) {\n            return PoolVirtues.IndependentOfAlloc | PoolVirtues.IndependentOfAlloc_or_ExplicitAlloc;\n          } else {\n            return PoolVirtues.None;\n          }\n        }\n      }\n    }\n    public class MultiSetBoundedPool : CollectionBoundedPool\n    {\n      public readonly Expression MultiSet;\n      public MultiSetBoundedPool(Expression multiset, bool exactTypes) : base(exactTypes, true) { MultiSet = multiset; }\n    }\n    public class MapBoundedPool : CollectionBoundedPool\n    {\n      public readonly Expression Map;\n      public MapBoundedPool(Expression map, bool exactTypes, bool isFiniteCollection) : base(exactTypes, isFiniteCollection) { Map = map; }\n    }\n    public class SeqBoundedPool : CollectionBoundedPool\n    {\n      public readonly Expression Seq;\n      public SeqBoundedPool(Expression seq, bool exactTypes) : base(exactTypes, true) { Seq = seq; }\n    }\n    public class DatatypeBoundedPool : BoundedPool\n    {\n      public readonly DatatypeDecl Decl;\n      public DatatypeBoundedPool(DatatypeDecl d) { Decl = d; }\n      public override PoolVirtues Virtues => PoolVirtues.Finite | PoolVirtues.Enumerable | PoolVirtues.IndependentOfAlloc | PoolVirtues.IndependentOfAlloc_or_ExplicitAlloc;\n      public override int Preference() => 8;\n    }\n    public class DatatypeInclusionBoundedPool : BoundedPool\n    {\n      public readonly bool IsIndDatatype;\n      public DatatypeInclusionBoundedPool(bool isIndDatatype) : base() { IsIndDatatype = isIndDatatype; }\n      public override PoolVirtues Virtues => (IsIndDatatype ? PoolVirtues.Finite : PoolVirtues.None) | PoolVirtues.IndependentOfAlloc | PoolVirtues.IndependentOfAlloc_or_ExplicitAlloc;\n      public override int Preference() => 2;\n    }\n\n    public List<BoundedPool> Bounds;  // initialized and filled in by resolver\n    // invariant Bounds == null || Bounds.Count == BoundVars.Count;\n\n    public List<BoundVar> UncompilableBoundVars() {\n      Contract.Ensures(Contract.Result<List<BoundVar>>() != null);\n      var v = BoundedPool.PoolVirtues.Finite | BoundedPool.PoolVirtues.Enumerable;\n      return ComprehensionExpr.BoundedPool.MissingBounds(BoundVars, Bounds, v);\n    }\n\n    public ComprehensionExpr(IToken tok, List<BoundVar> bvars, Expression range, Expression term, Attributes attrs)\n      : base(tok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(cce.NonNullElements(bvars));\n      Contract.Requires(term != null);\n\n      this.BoundVars = bvars;\n      this.Range = range;\n      this.UpdateTerm(term);\n      this.Attributes = attrs;\n    }\n\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        foreach (var e in Attributes.SubExpressions(Attributes)) {\n          yield return e;\n        }\n        if (Range != null) { yield return Range; }\n        yield return Term;\n      }\n    }\n  }\n\n  public abstract class QuantifierExpr : ComprehensionExpr, TypeParameter.ParentType {\n    private readonly int UniqueId;\n    public List<TypeParameter> TypeArgs;\n    private static int currentQuantId = -1;\n\n    protected virtual BinaryExpr.ResolvedOpcode SplitResolvedOp { get { return BinaryExpr.ResolvedOpcode.Or; } }\n\n    private Expression SplitQuantifierToExpression() {\n      Contract.Requires(SplitQuantifier != null && SplitQuantifier.Any());\n      Expression accumulator = SplitQuantifier[0];\n      for (int tid = 1; tid < SplitQuantifier.Count; tid++) {\n        accumulator = new BinaryExpr(Term.tok, SplitResolvedOp, accumulator, SplitQuantifier[tid]);\n      }\n      return accumulator;\n    }\n\n    private List<Expression> _SplitQuantifier;\n    public List<Expression> SplitQuantifier {\n      get {\n        return _SplitQuantifier;\n      }\n      set {\n        Contract.Assert(!value.Contains(this)); // don't let it put into its own split quantifiers.\n        _SplitQuantifier = value;\n        SplitQuantifierExpression = SplitQuantifierToExpression();\n      }\n    }\n\n    internal Expression SplitQuantifierExpression { get; private set; }\n\n    static int FreshQuantId() {\n      return System.Threading.Interlocked.Increment(ref currentQuantId);\n    }\n\n    public string FullName {\n      get {\n        return \"q$\" + UniqueId;\n      }\n    }\n\n    public String Refresh(string prefix, FreshIdGenerator idGen) {\n      return idGen.FreshId(prefix);\n    }\n\n    public TypeParameter Refresh(TypeParameter p, FreshIdGenerator idGen) {\n      var cp = new TypeParameter(p.tok, idGen.FreshId(p.Name + \"#\"), p.VarianceSyntax, p.Characteristics);\n      cp.Parent = this;\n      return cp;\n    }\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      var _scratch = true;\n      Contract.Invariant(Attributes.ContainsBool(Attributes, \"typeQuantifier\", ref _scratch) || TypeArgs.Count == 0);\n    }\n    public QuantifierExpr(IToken tok, List<TypeParameter> tvars, List<BoundVar> bvars, Expression range, Expression term, Attributes attrs)\n      : base(tok, bvars, range, term, attrs) {\n      Contract.Requires(tok != null);\n      Contract.Requires(cce.NonNullElements(bvars));\n      Contract.Requires(term != null);\n      this.TypeArgs = tvars;\n      this.UniqueId = FreshQuantId();\n    }\n\n    public virtual Expression LogicalBody(bool bypassSplitQuantifier = false) {\n      // Don't call this on a quantifier with a Split clause: it's not a real quantifier. The only exception is the Compiler.\n      Contract.Requires(bypassSplitQuantifier || SplitQuantifier == null);\n      throw new cce.UnreachableException(); // This body is just here for the \"Requires\" clause\n    }\n\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        if (SplitQuantifier == null) {\n          foreach (var e in base.SubExpressions) {\n            yield return e;\n          }\n        } else {\n          foreach (var e in Attributes.SubExpressions(Attributes)) {\n            yield return e;\n          }\n          foreach (var e in SplitQuantifier) {\n            yield return e;\n          }\n        }\n      }\n    }\n  }\n\n  public class ForallExpr : QuantifierExpr {\n    protected override BinaryExpr.ResolvedOpcode SplitResolvedOp { get { return BinaryExpr.ResolvedOpcode.And; } }\n\n    public ForallExpr(IToken tok, List<BoundVar> bvars, Expression range, Expression term, Attributes attrs)\n      : this(tok, new List<TypeParameter>(), bvars, range, term, attrs) {\n      Contract.Requires(cce.NonNullElements(bvars));\n      Contract.Requires(tok != null);\n      Contract.Requires(term != null);\n    }\n    public ForallExpr(IToken tok, List<TypeParameter> tvars, List<BoundVar> bvars, Expression range, Expression term, Attributes attrs)\n      : base(tok, tvars, bvars, range, term, attrs) {\n      Contract.Requires(cce.NonNullElements(bvars));\n      Contract.Requires(tok != null);\n      Contract.Requires(term != null);\n    }\n    public override Expression LogicalBody(bool bypassSplitQuantifier = false) {\n      if (Range == null) {\n        return Term;\n      }\n      var body = new BinaryExpr(Term.tok, BinaryExpr.Opcode.Imp, Range, Term);\n      body.ResolvedOp = BinaryExpr.ResolvedOpcode.Imp;\n      body.Type = Term.Type;\n      return body;\n    }\n  }\n\n  public class ExistsExpr : QuantifierExpr {\n    protected override BinaryExpr.ResolvedOpcode SplitResolvedOp { get { return BinaryExpr.ResolvedOpcode.Or; } }\n\n    public ExistsExpr(IToken tok, List<BoundVar> bvars, Expression range, Expression term, Attributes attrs)\n      : this(tok, new List<TypeParameter>(), bvars, range, term, attrs) {\n      Contract.Requires(cce.NonNullElements(bvars));\n      Contract.Requires(tok != null);\n      Contract.Requires(term != null);\n    }\n    public ExistsExpr(IToken tok, List<TypeParameter> tvars, List<BoundVar> bvars, Expression range, Expression term, Attributes attrs)\n      : base(tok, tvars, bvars, range, term, attrs) {\n      Contract.Requires(cce.NonNullElements(bvars));\n      Contract.Requires(tok != null);\n      Contract.Requires(term != null);\n    }\n    public override Expression LogicalBody(bool bypassSplitQuantifier = false) {\n      if (Range == null) {\n        return Term;\n      }\n      var body = new BinaryExpr(Term.tok, BinaryExpr.Opcode.And, Range, Term);\n      body.ResolvedOp = BinaryExpr.ResolvedOpcode.And;\n      body.Type = Term.Type;\n      return body;\n    }\n  }\n\n  public class SetComprehension : ComprehensionExpr\n  {\n    public readonly bool Finite;\n    public readonly bool TermIsImplicit;  // records the given syntactic form\n    public bool TermIsSimple {\n      get {\n        var term = Term as IdentifierExpr;\n        var r = term != null && BoundVars.Count == 1 && BoundVars[0].Name == term.Name;\n        Contract.Assert(!TermIsImplicit || r);  // TermIsImplicit ==> r\n        Contract.Assert(!r || term.Var == null || term.Var == BoundVars[0]);  // if the term is simple and it has been resolved, then it should have resolved to BoundVars[0]\n        return r;\n      }\n    }\n\n    public SetComprehension(IToken tok, bool finite, List<BoundVar> bvars, Expression range, Expression/*?*/ term, Attributes attrs)\n      : base(tok, bvars, range, term ?? new IdentifierExpr(tok, bvars[0].Name), attrs) {\n      Contract.Requires(tok != null);\n      Contract.Requires(cce.NonNullElements(bvars));\n      Contract.Requires(1 <= bvars.Count);\n      Contract.Requires(range != null);\n      Contract.Requires(term != null || bvars.Count == 1);\n\n      TermIsImplicit = term == null;\n      Finite = finite;\n    }\n  }\n  public class MapComprehension : ComprehensionExpr\n  {\n    public readonly bool Finite;\n    public readonly Expression TermLeft;\n\n    public List<Boogie.Function> ProjectionFunctions;  // filled in during translation (and only for general map comprehensions where \"TermLeft != null\")\n\n    public MapComprehension(IToken tok, bool finite, List<BoundVar> bvars, Expression range, Expression/*?*/ termLeft, Expression termRight, Attributes attrs)\n      : base(tok, bvars, range, termRight, attrs) {\n      Contract.Requires(tok != null);\n      Contract.Requires(cce.NonNullElements(bvars));\n      Contract.Requires(1 <= bvars.Count);\n      Contract.Requires(range != null);\n      Contract.Requires(termRight != null);\n      Contract.Requires(termLeft != null || bvars.Count == 1);\n\n      Finite = finite;\n      TermLeft = termLeft;\n    }\n\n    /// <summary>\n    /// IsGeneralMapComprehension returns true for general map comprehensions.\n    /// In other words, it returns false if either no TermLeft was given or if\n    /// the given TermLeft is the sole bound variable.\n    /// This property getter requires that the expression has been successfully\n    /// resolved.\n    /// </summary>\n    public bool IsGeneralMapComprehension {\n      get {\n        Contract.Requires(WasResolved());\n        if (TermLeft == null) {\n          return false;\n        } else if (BoundVars.Count != 1) {\n          return true;\n        }\n        var lhs = StripParens(TermLeft).Resolved;\n        if (lhs is IdentifierExpr ide && ide.Var == BoundVars[0]) {\n          // TermLeft is the sole bound variable, so this is the same as\n          // if TermLeft wasn't given at all\n          return false;\n        }\n        return true;\n      }\n    }\n\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        foreach (var e in Attributes.SubExpressions(Attributes)) {\n          yield return e;\n        }\n        if (Range != null) { yield return Range; }\n        if (TermLeft != null) { yield return TermLeft; }\n        yield return Term;\n      }\n    }\n  }\n\n  public class LambdaExpr : ComprehensionExpr\n  {\n    public readonly List<FrameExpression> Reads;\n\n    public LambdaExpr(IToken tok, List<BoundVar> bvars, Expression requires, List<FrameExpression> reads, Expression body)\n      : base(tok, bvars, requires, body, null)\n    {\n      Contract.Requires(reads != null);\n      Reads = reads;\n    }\n\n    // Synonym\n    public Expression Body {\n      get {\n        return Term;\n      }\n    }\n\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        yield return Term;\n        if (Range != null) {\n          yield return Range;\n        }\n        foreach (var read in Reads) {\n          yield return read.E;\n        }\n      }\n    }\n\n  }\n\n\n  public class WildcardExpr : Expression\n  {  // a WildcardExpr can occur only in reads clauses and a loop's decreases clauses (with different meanings)\n    public WildcardExpr(IToken tok)\n      : base(tok) {\n      Contract.Requires(tok != null);\n    }\n  }\n\n  /// <summary>\n  /// A StmtExpr has the form S;E where S is a statement (from a restricted set) and E is an expression.\n  /// The expression S;E evaluates to whatever E evaluates to, but its well-formedness comes down to\n  /// executing S (which itself must be well-formed) and then checking the well-formedness of E.\n  /// </summary>\n  public class StmtExpr : Expression\n  {\n    public readonly Statement S;\n    public readonly Expression E;\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(S != null);\n      Contract.Invariant(E != null);\n    }\n\n    public StmtExpr(IToken tok, Statement stmt, Expression expr)\n      : base(tok)\n    {\n      Contract.Requires(tok != null);\n      Contract.Requires(stmt != null);\n      Contract.Requires(expr != null);\n      S = stmt;\n      E = expr;\n    }\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        // Note:  A StmtExpr is unusual in that it contains a statement.  For now, callers\n        // of SubExpressions need to be aware of this and handle it specially.\n        yield return E;\n      }\n    }\n\n    /// <summary>\n    /// Returns a conclusion that S gives rise to, that is, something that is known after\n    /// S is executed.\n    /// This method should be called only after successful resolution of the expression.\n    /// </summary>\n    public Expression GetSConclusion() {\n      // this is one place where we actually investigate what kind of statement .S is\n      if (S is PredicateStmt) {\n        var s = (PredicateStmt)S;\n        return s.Expr;\n      } else if (S is CalcStmt) {\n        var s = (CalcStmt)S;\n        return s.Result;\n      } else if (S is UpdateStmt) {\n        return new LiteralExpr(tok, true);  // one could use the postcondition of the method, suitably instantiated, but \"true\" is conservative and much simpler :)\n      } else {\n        Contract.Assert(false); throw new cce.UnreachableException();  // unexpected statement\n      }\n    }\n  }\n\n  public class ITEExpr : Expression\n  {\n    public readonly bool IsBindingGuard;\n    public readonly Expression Test;\n    public readonly Expression Thn;\n    public readonly Expression Els;\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(Test != null);\n      Contract.Invariant(Thn != null);\n      Contract.Invariant(Els != null);\n    }\n\n    public ITEExpr(IToken tok, bool isBindingGuard, Expression test, Expression thn, Expression els)\n      : base(tok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(test != null);\n      Contract.Requires(thn != null);\n      Contract.Requires(els != null);\n      this.IsBindingGuard = isBindingGuard;\n      this.Test = test;\n      this.Thn = thn;\n      this.Els = els;\n    }\n\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        yield return Test;\n        yield return Thn;\n        yield return Els;\n      }\n    }\n  }\n\n  public class MatchExpr : Expression {  // a MatchExpr is an \"extended expression\" and is only allowed in certain places\n    private Expression source;\n    private List<MatchCaseExpr> cases;\n    public readonly List<DatatypeCtor> MissingCases = new List<DatatypeCtor>();  // filled in during resolution\n    public readonly bool UsesOptionalBraces;\n    public MatchExpr OrigUnresolved;  // the resolver makes this clone of the MatchExpr before it starts desugaring it\n\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(Source != null);\n      Contract.Invariant(cce.NonNullElements(Cases));\n      Contract.Invariant(cce.NonNullElements(MissingCases));\n    }\n\n    public MatchExpr(IToken tok, Expression source, [Captured] List<MatchCaseExpr> cases, bool usesOptionalBraces)\n      : base(tok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(source != null);\n      Contract.Requires(cce.NonNullElements(cases));\n      this.source = source;\n      this.cases = cases;\n      this.UsesOptionalBraces = usesOptionalBraces;\n    }\n\n    public Expression Source {\n      get { return source; }\n    }\n\n    public List<MatchCaseExpr> Cases {\n      get { return cases; }\n    }\n\n    // should only be used in desugar in resolve to change the source and cases of the matchexpr\n    public void UpdateSource(Expression source) {\n      this.source = source;\n    }\n\n    public void UpdateCases(List<MatchCaseExpr> cases) {\n      this.cases = cases;\n    }\n\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        yield return Source;\n        foreach (var mc in cases) {\n          yield return mc.Body;\n        }\n      }\n    }\n  }\n\n  /// <summary>\n  /// A CasePattern is either a BoundVar or a datatype constructor with optional arguments.\n  /// Lexically, the CasePattern starts with an identifier.  If it continues with an open paren (as\n  /// indicated by Arguments being non-null), then the CasePattern is a datatype constructor.  If\n  /// it continues with a colon (which is indicated by Var.Type not being a proxy type), then it is\n  /// a BoundVar.  But if it ends with just the identifier, then resolution is required to figure out\n  /// which it is; in this case, Var is non-null, because this is the only place where Var.IsGhost\n  /// is recorded by the parser.\n  /// </summary>\n  public class CasePattern<VT> where VT : IVariable\n  {\n    public readonly IToken tok;\n    public readonly string Id;\n    // After successful resolution, exactly one of the following two fields is non-null.\n    public DatatypeCtor Ctor;  // finalized by resolution (null if the pattern is a bound variable)\n    public VT Var;  // finalized by resolution (null if the pattern is a constructor)  Invariant:  Var != null ==> Arguments == null\n    public readonly List<CasePattern<VT>> Arguments;\n\n    public Expression Expr;  // an r-value version of the CasePattern; filled in by resolution\n\n    public CasePattern(IToken tok, string id, [Captured] List<CasePattern<VT>> arguments) {\n      Contract.Requires(tok != null);\n      Contract.Requires(id != null);\n      this.tok = tok;\n      Id = id;\n      Arguments = arguments;\n    }\n\n    public CasePattern(IToken tok, VT bv) {\n      Contract.Requires(tok != null);\n      Contract.Requires(bv != null);\n      this.tok = tok;\n      Id = bv.Name;\n      Var = bv;\n    }\n\n    /// <summary>\n    /// Sets the Expr field.  Assumes the CasePattern and its arguments to have been successfully resolved, except for assigning\n    /// to Expr.\n    /// </summary>\n    public void AssembleExpr(List<Type> dtvTypeArgs) {\n      Contract.Requires(Var != null || dtvTypeArgs != null);\n      if (Var != null) {\n        Contract.Assert(this.Id == this.Var.Name);\n        this.Expr = new IdentifierExpr(this.tok, this.Var);\n      } else {\n        var dtValue = new DatatypeValue(this.tok, this.Ctor.EnclosingDatatype.Name, this.Id, this.Arguments == null ? new List<Expression>() : this.Arguments.ConvertAll(arg => arg.Expr));\n        dtValue.Ctor = this.Ctor;  // resolve here\n        dtValue.InferredTypeArgs.AddRange(dtvTypeArgs);  // resolve here\n        dtValue.Type = new UserDefinedType(this.tok, this.Ctor.EnclosingDatatype.Name, this.Ctor.EnclosingDatatype, dtvTypeArgs);\n        this.Expr = dtValue;\n      }\n    }\n\n    public IEnumerable<VT> Vars {\n      get {\n        if (Var != null) {\n          yield return Var;\n        } else {\n          if (Arguments != null) {\n            foreach (var arg in Arguments) {\n              foreach (var bv in arg.Vars) {\n                yield return bv;\n              }\n            }\n          }\n        }\n      }\n    }\n  }\n\n  public abstract class MatchCase\n  {\n    public readonly IToken tok;\n    public readonly string Id;\n    public DatatypeCtor Ctor;  // filled in by resolution\n    public List<BoundVar> Arguments; // created by the resolver.\n    public List<CasePattern<BoundVar>> CasePatterns; // generated from parsers. It should be converted to List<BoundVar> during resolver. Invariant:  CasePatterns != null ==> Arguments == null\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(tok != null);\n      Contract.Invariant(Id != null);\n      Contract.Invariant(cce.NonNullElements(Arguments) || cce.NonNullElements(CasePatterns));\n    }\n\n    public MatchCase(IToken tok, string id, [Captured] List<BoundVar> arguments) {\n      Contract.Requires(tok != null);\n      Contract.Requires(id != null);\n      Contract.Requires(cce.NonNullElements(arguments));\n      this.tok = tok;\n      this.Id = id;\n      this.Arguments = arguments;\n    }\n\n    public MatchCase(IToken tok, string id, [Captured] List<CasePattern<BoundVar>> cps) {\n      Contract.Requires(tok != null);\n      Contract.Requires(id != null);\n      Contract.Requires(cce.NonNullElements(cps));\n      this.tok = tok;\n      this.Id = id;\n      this.CasePatterns = cps;\n    }\n  }\n\n  public class MatchCaseExpr : MatchCase\n  {\n    private Expression body;\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(body != null);\n    }\n\n    public MatchCaseExpr(IToken tok, string id, [Captured] List<BoundVar> arguments, Expression body)\n      : base(tok, id, arguments) {\n      Contract.Requires(tok != null);\n      Contract.Requires(id != null);\n      Contract.Requires(cce.NonNullElements(arguments));\n      Contract.Requires(body != null);\n      this.body = body;\n    }\n\n    public MatchCaseExpr(IToken tok, string id, [Captured] List<CasePattern<BoundVar>> cps, Expression body)\n      : base(tok, id, cps)\n    {\n      Contract.Requires(tok != null);\n      Contract.Requires(id != null);\n      Contract.Requires(cce.NonNullElements(cps));\n      Contract.Requires(body != null);\n      this.body = body;\n    }\n\n    public Expression Body {\n      get { return body; }\n    }\n\n    // should only be called by resolve to reset the body of the MatchCaseExpr\n    public void UpdateBody(Expression body) {\n      this.body = body;\n    }\n  }\n\n  public class BoxingCastExpr : Expression {  // a BoxingCastExpr is used only as a temporary placeholding during translation\n    public readonly Expression E;\n    public readonly Type FromType;\n    public readonly Type ToType;\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(E != null);\n      Contract.Invariant(FromType != null);\n      Contract.Invariant(ToType != null);\n    }\n\n    public BoxingCastExpr(Expression e, Type fromType, Type toType)\n      : base(e.tok) {\n      Contract.Requires(e != null);\n      Contract.Requires(fromType != null);\n      Contract.Requires(toType != null);\n\n      E = e;\n      FromType = fromType;\n      ToType = toType;\n    }\n\n    public override IEnumerable<Expression> SubExpressions {\n      get { yield return E; }\n    }\n  }\n\n  public class UnboxingCastExpr : Expression {  // an UnboxingCastExpr is used only as a temporary placeholding during translation\n    public readonly Expression E;\n    public readonly Type FromType;\n    public readonly Type ToType;\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(E != null);\n      Contract.Invariant(FromType != null);\n      Contract.Invariant(ToType != null);\n    }\n\n    public UnboxingCastExpr(Expression e, Type fromType, Type toType)\n      : base(e.tok) {\n      Contract.Requires(e != null);\n      Contract.Requires(fromType != null);\n      Contract.Requires(toType != null);\n\n      E = e;\n      FromType = fromType;\n      ToType = toType;\n    }\n\n    public override IEnumerable<Expression> SubExpressions {\n      get { yield return E; }\n    }\n  }\n\n\n  public class MaybeFreeExpression {\n    public readonly Expression E;\n    public readonly bool IsFree;\n    public readonly AssertLabel/*?*/ Label;\n\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(E != null);\n    }\n\n    private Attributes attributes;\n    public Attributes Attributes {\n      get {\n        return attributes;\n      }\n      set {\n        attributes = value;\n      }\n    }\n\n    public bool HasAttributes() {\n      return Attributes != null;\n    }\n\n    public MaybeFreeExpression(Expression e)\n      : this(e, false, null)\n    {\n      Contract.Requires(e != null);\n    }\n\n    public MaybeFreeExpression(Expression e, bool isFree)\n      : this(e, isFree, null)\n    {\n      Contract.Requires(e != null);\n    }\n\n    public MaybeFreeExpression(Expression e, bool isFree, Attributes attrs) {\n      Contract.Requires(e != null);\n      E = e;\n      IsFree = isFree;\n      Attributes = attrs;\n    }\n\n    public MaybeFreeExpression(Expression e, bool isFree, AssertLabel/*?*/ label, Attributes attrs) {\n      Contract.Requires(e != null);\n      E = e;\n      IsFree = isFree;\n      Label = label;\n      Attributes = attrs;\n    }\n\n    public void AddCustomizedErrorMessage(IToken tok, string s) {\n      var args = new List<Expression>() { new StringLiteralExpr(tok, s, true) };\n      IToken openBrace = tok;\n      IToken closeBrace = new Token(tok.line, tok.col + 7 + s.Length + 1); // where 7 = length(\":error \")\n      this.Attributes = new UserSuppliedAttributes(tok, openBrace, closeBrace, args, this.Attributes);\n    }\n  }\n\n\n  public class FrameExpression {\n    public readonly IToken tok;\n    public readonly Expression E;  // may be a WildcardExpr\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(E != null);\n      Contract.Invariant(!(E is WildcardExpr) || FieldName == null && Field == null);\n    }\n\n    public readonly string FieldName;\n    public Field Field;  // filled in during resolution (but is null if FieldName is)\n\n    /// <summary>\n    /// If a \"fieldName\" is given, then \"tok\" denotes its source location.  Otherwise, \"tok\"\n    /// denotes the source location of \"e\".\n    /// </summary>\n    public FrameExpression(IToken tok, Expression e, string fieldName) {\n      Contract.Requires(tok != null);\n      Contract.Requires(e != null);\n      Contract.Requires(!(e is WildcardExpr) || fieldName == null);\n      this.tok = tok;\n      E = e;\n      FieldName = fieldName;\n    }\n  }\n\n  /// <summary>\n  /// This class represents a piece of concrete syntax in the parse tree.  During resolution,\n  /// it gets \"replaced\" by the expression in \"ResolvedExpression\".\n  /// </summary>\n  public abstract class ConcreteSyntaxExpression : Expression\n  {\n    public Expression ResolvedExpression;  // filled in during resolution; after resolution, manipulation of \"this\" should proceed as with manipulating \"this.ResolvedExpression\"\n    public ConcreteSyntaxExpression(IToken tok)\n      : base(tok) {\n    }\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        if (ResolvedExpression != null) {\n          yield return ResolvedExpression;\n        }\n      }\n    }\n  }\n\n  public class ParensExpression : ConcreteSyntaxExpression\n  {\n    public readonly Expression E;\n    public ParensExpression(IToken tok, Expression e)\n      : base(tok) {\n      E = e;\n    }\n  }\n\n  public class TypeExpr : ParensExpression\n  {\n    public readonly Type T;\n    public TypeExpr(IToken tok, Expression e, Type t)\n      : base(tok, e)\n    {\n      Contract.Requires(t != null);\n      T = t;\n    }\n\n    public static Expression MaybeTypeExpr(Expression e, Type t) {\n      if (t == null) {\n        return e;\n      } else {\n        return new TypeExpr(e.tok, e, t);\n      }\n    }\n  }\n\n  public class DatatypeUpdateExpr : ConcreteSyntaxExpression\n  {\n    public readonly Expression Root;\n    public readonly List<Tuple<IToken, string, Expression>> Updates;\n    public List<DatatypeCtor> LegalSourceConstructors;  // filled in by resolution\n    public DatatypeUpdateExpr(IToken tok, Expression root, List<Tuple<IToken, string, Expression>> updates)\n      : base(tok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(root != null);\n      Contract.Requires(updates != null);\n      Contract.Requires(updates.Count != 0);\n      Root = root;\n      Updates = updates;\n    }\n\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        if (ResolvedExpression == null) {\n          yield return Root;\n          foreach (var update in Updates) {\n            yield return update.Item3;\n          }\n        } else {\n          foreach (var e in ResolvedExpression.SubExpressions) {\n            yield return e;\n          }\n        }\n      }\n    }\n  }\n\n\n  /// <summary>\n  /// An AutoGeneratedExpression is simply a wrapper around an expression.  This expression tells the generation of hover text (in the Dafny IDE)\n  /// that the expression was no supplied directly in the program text and should therefore be ignored.  In other places, an AutoGeneratedExpression\n  /// is just a parenthesized expression, which means that it works just the like expression .E that it contains.\n  /// (Ironically, AutoGeneratedExpression, which is like the antithesis of concrete syntax, inherits from ConcreteSyntaxExpression, which perhaps\n  /// should rather have been called SemanticsNeutralExpressionWrapper.)\n  /// </summary>\n  public class AutoGeneratedExpression : ParensExpression\n  {\n    public AutoGeneratedExpression(IToken tok, Expression e)\n      : base(tok, e) {\n      Contract.Requires(tok != null);\n      Contract.Requires(e != null);\n    }\n\n    /// <summary>\n    /// This maker method takes a resolved expression \"e\" and wraps a resolved AutoGeneratedExpression\n    /// around it.\n    /// </summary>\n    public static AutoGeneratedExpression Create(Expression e) {\n      Contract.Requires(e != null);\n      var a = new AutoGeneratedExpression(e.tok, e);\n      a.type = e.Type;\n      a.ResolvedExpression = e;\n      return a;\n    }\n  }\n\n  /// <summary>\n  /// A NegationExpression e represents the value -e and is syntactic shorthand\n  /// for 0-e (for integers) or 0.0-e (for reals).\n  /// </summary>\n  public class NegationExpression : ConcreteSyntaxExpression\n  {\n    public readonly Expression E;\n    public NegationExpression(IToken tok, Expression e)\n      : base(tok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(e != null);\n      E = e;\n    }\n    public override IEnumerable<Expression> SubExpressions {\n      get {\n        if (ResolvedExpression == null) {\n          // the expression hasn't yet been turned into a resolved expression, so use .E as the subexpression\n          yield return E;\n        } else {\n          foreach (var ee in base.SubExpressions) {\n            yield return ee;\n          }\n        }\n      }\n    }\n  }\n\n  public class ChainingExpression : ConcreteSyntaxExpression\n  {\n    public readonly List<Expression> Operands;\n    public readonly List<BinaryExpr.Opcode> Operators;\n    public readonly List<IToken> OperatorLocs;\n    public readonly List<Expression/*?*/> PrefixLimits;\n    public readonly Expression E;\n    public ChainingExpression(IToken tok, List<Expression> operands, List<BinaryExpr.Opcode> operators, List<IToken> operatorLocs, List<Expression/*?*/> prefixLimits)\n      : base(tok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(operands != null);\n      Contract.Requires(operators != null);\n      Contract.Requires(operatorLocs != null);\n      Contract.Requires(prefixLimits != null);\n      Contract.Requires(1 <= operators.Count);\n      Contract.Requires(operands.Count == operators.Count + 1);\n      Contract.Requires(operatorLocs.Count == operators.Count);\n      Contract.Requires(prefixLimits.Count == operators.Count);\n      // Additional preconditions apply, see Contract.Assume's below\n\n      Operands = operands;\n      Operators = operators;\n      OperatorLocs = operatorLocs;\n      PrefixLimits = prefixLimits;\n      Expression desugaring;\n      // Compute the desugaring\n      if (operators[0] == BinaryExpr.Opcode.Disjoint) {\n        Expression acc = operands[0];  // invariant:  \"acc\" is the union of all operands[j] where j <= i\n        desugaring = new BinaryExpr(operatorLocs[0], operators[0], operands[0], operands[1]);\n        for (int i = 0; i < operators.Count; i++) {\n          Contract.Assume(operators[i] == BinaryExpr.Opcode.Disjoint);\n          var opTok = operatorLocs[i];\n          var e = new BinaryExpr(opTok, BinaryExpr.Opcode.Disjoint, acc, operands[i + 1]);\n          desugaring = new BinaryExpr(opTok, BinaryExpr.Opcode.And, desugaring, e);\n          acc = new BinaryExpr(opTok, BinaryExpr.Opcode.Add, acc, operands[i + 1]);\n        }\n      } else {\n        desugaring = null;\n        for (int i = 0; i < operators.Count; i++) {\n          var opTok = operatorLocs[i];\n          var op = operators[i];\n          Contract.Assume(op != BinaryExpr.Opcode.Disjoint);\n          var k = prefixLimits[i];\n          Contract.Assume(k == null || op == BinaryExpr.Opcode.Eq || op == BinaryExpr.Opcode.Neq);\n          var e0 = operands[i];\n          var e1 = operands[i + 1];\n          Expression e;\n          if (k == null) {\n            e = new BinaryExpr(opTok, op, e0, e1);\n          } else {\n            e = new TernaryExpr(opTok, op == BinaryExpr.Opcode.Eq ? TernaryExpr.Opcode.PrefixEqOp : TernaryExpr.Opcode.PrefixNeqOp, k, e0, e1);\n          }\n          desugaring = desugaring == null ? e : new BinaryExpr(opTok, BinaryExpr.Opcode.And, desugaring, e);\n        }\n      }\n      E = desugaring;\n    }\n  }\n\n  /// <summary>\n  /// The parsing and resolution/type checking of expressions of the forms\n  ///   0. ident &lt; Types &gt;\n  ///   1. Expr . ident &lt; Types &gt;\n  ///   2. Expr ( Exprs )\n  ///   3. Expr [ Exprs ]\n  ///   4. Expr [ Expr .. Expr ]\n  /// is done as follows.  These forms are parsed into the following AST classes:\n  ///   0. NameSegment\n  ///   1. ExprDotName\n  ///   2. ApplySuffix\n  ///   3. SeqSelectExpr or MultiSelectExpr\n  ///   4. SeqSelectExpr\n  ///\n  /// The first three of these inherit from ConcreteSyntaxExpression.  The resolver will resolve\n  /// these into:\n  ///   0. IdentifierExpr or MemberSelectExpr (with .Lhs set to ImplicitThisExpr or StaticReceiverExpr)\n  ///   1. IdentifierExpr or MemberSelectExpr\n  ///   2. FuncionCallExpr or ApplyExpr\n  ///\n  /// The IdentifierExpr's that forms 0 and 1 can turn into sometimes denote the name of a module or\n  /// type.  The .Type field of the corresponding resolved expressions are then the special Type subclasses\n  /// ResolutionType_Module and ResolutionType_Type, respectively.  These will not be seen by the\n  /// verifier or compiler, since, in a well-formed program, the verifier and compiler will use the\n  /// .ResolvedExpr field of whatever form-1 expression contains these.\n  ///\n  /// Notes:\n  ///   * IdentifierExpr and FunctionCallExpr are resolved-only expressions (that is, they don't contain\n  ///     all the syntactic components that were used to parse them).\n  ///   * Rather than the current SeqSelectExpr/MultiSelectExpr split of forms 3 and 4, it would\n  ///     seem more natural to refactor these into 3: IndexSuffixExpr and 4: RangeSuffixExpr.\n  /// </summary>\n  abstract public class SuffixExpr : ConcreteSyntaxExpression {\n    public readonly Expression Lhs;\n    public SuffixExpr(IToken tok, Expression lhs)\n      : base(tok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(lhs != null);\n      Lhs = lhs;\n    }\n  }\n\n  public class NameSegment : ConcreteSyntaxExpression\n  {\n    public readonly string Name;\n    public readonly List<Type> OptTypeArguments;\n    public NameSegment(IToken tok, string name, List<Type> optTypeArguments)\n      : base(tok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Contract.Requires(optTypeArguments == null || optTypeArguments.Count > 0);\n      Name = name;\n      OptTypeArguments = optTypeArguments;\n    }\n  }\n\n  /// <summary>\n  /// An ExprDotName desugars into either an IdentifierExpr (if the Lhs is a static name) or a MemberSelectExpr (if the Lhs is a computed expression).\n  /// </summary>\n  public class ExprDotName : SuffixExpr\n  {\n    public readonly string SuffixName;\n    public readonly List<Type> OptTypeArguments;\n\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(SuffixName != null);\n    }\n\n    public ExprDotName(IToken tok, Expression obj, string suffixName, List<Type> optTypeArguments)\n      : base(tok, obj) {\n      Contract.Requires(tok != null);\n      Contract.Requires(obj != null);\n      Contract.Requires(suffixName != null);\n      this.SuffixName = suffixName;\n      OptTypeArguments = optTypeArguments;\n    }\n  }\n\n  /// <summary>\n  /// An ApplySuffix desugars into either an ApplyExpr or a FunctionCallExpr\n  /// </summary>\n  public class ApplySuffix : SuffixExpr\n  {\n    public readonly List<Expression> Args;\n\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(Args != null);\n    }\n\n    public ApplySuffix(IToken tok, Expression lhs, List<Expression> args)\n      : base(tok, lhs) {\n      Contract.Requires(tok != null);\n      Contract.Requires(lhs != null);\n      Contract.Requires(cce.NonNullElements(args));\n      Args = args;\n    }\n  }\n\n  public class Specification<T> where T : class\n  {\n    public readonly List<T> Expressions;\n\n    [ContractInvariantMethod]\n    private void ObjectInvariant()\n    {\n      Contract.Invariant(Expressions == null || cce.NonNullElements<T>(Expressions));\n    }\n\n\n    public Specification(List<T> exprs, Attributes attrs)\n    {\n      Contract.Requires(exprs == null || cce.NonNullElements<T>(exprs));\n      Expressions = exprs;\n      Attributes = attrs;\n    }\n\n    private Attributes attributes;\n    public Attributes Attributes\n    {\n      get\n      {\n        return attributes;\n      }\n      set\n      {\n        attributes = value;\n      }\n    }\n\n    public bool HasAttributes()\n    {\n      return Attributes != null;\n    }\n  }\n\n  public class BottomUpVisitor\n  {\n    public void Visit(IEnumerable<Expression> exprs) {\n      exprs.Iter(Visit);\n    }\n    public void Visit(IEnumerable<Statement> stmts) {\n      stmts.Iter(Visit);\n    }\n    public void Visit(MaybeFreeExpression expr) {\n      Visit(expr.E);\n    }\n    public void Visit(FrameExpression expr) {\n      Visit(expr.E);\n    }\n    public void Visit(IEnumerable<MaybeFreeExpression> exprs) {\n      exprs.Iter(Visit);\n    }\n    public void Visit(IEnumerable<FrameExpression> exprs) {\n      exprs.Iter(Visit);\n    }\n    public void Visit(ICallable decl) {\n      if (decl is Function) {\n        Visit((Function)decl);\n      } else if (decl is Method) {\n        Visit((Method)decl);\n      }\n      //TODO More?\n    }\n    public void Visit(Method method) {\n      Visit(method.Ens);\n      Visit(method.Req);\n      Visit(method.Mod.Expressions);\n      Visit(method.Decreases.Expressions);\n      if (method.Body != null) { Visit(method.Body); }\n      //TODO More?\n    }\n    public void Visit(Function function) {\n      Visit(function.Ens);\n      Visit(function.Req);\n      Visit(function.Reads);\n      Visit(function.Decreases.Expressions);\n      if (function.Body != null) { Visit(function.Body); }\n      //TODO More?\n    }\n    public void Visit(Expression expr) {\n      Contract.Requires(expr != null);\n      // recursively visit all subexpressions and all substatements\n      expr.SubExpressions.Iter(Visit);\n      if (expr is StmtExpr) {\n        // a StmtExpr also has a sub-statement\n        var e = (StmtExpr)expr;\n        Visit(e.S);\n      }\n      VisitOneExpr(expr);\n    }\n    public void Visit(Statement stmt) {\n      Contract.Requires(stmt != null);\n      // recursively visit all subexpressions and all substatements\n      stmt.SubExpressions.Iter(Visit);\n      stmt.SubStatements.Iter(Visit);\n      VisitOneStmt(stmt);\n    }\n    protected virtual void VisitOneExpr(Expression expr) {\n      Contract.Requires(expr != null);\n      // by default, do nothing\n    }\n    protected virtual void VisitOneStmt(Statement stmt) {\n      Contract.Requires(stmt != null);\n      // by default, do nothing\n    }\n  }\n  public class TopDownVisitor<State>\n  {\n    public void Visit(Expression expr, State st) {\n      Contract.Requires(expr != null);\n      if (VisitOneExpr(expr, ref st)) {\n        // recursively visit all subexpressions and all substatements\n        expr.SubExpressions.Iter(e => Visit(e, st));\n        if (expr is StmtExpr) {\n          // a StmtExpr also has a sub-statement\n          var e = (StmtExpr)expr;\n          Visit(e.S, st);\n        }\n      }\n    }\n    public void Visit(Statement stmt, State st) {\n      Contract.Requires(stmt != null);\n      if (VisitOneStmt(stmt, ref st)) {\n        // recursively visit all subexpressions and all substatements\n        stmt.SubExpressions.Iter(e => Visit(e, st));\n        stmt.SubStatements.Iter(s => Visit(s, st));\n      }\n    }\n    public void Visit(IEnumerable<Expression> exprs, State st) {\n      exprs.Iter(e => Visit(e, st));\n    }\n    public void Visit(IEnumerable<Statement> stmts, State st) {\n      stmts.Iter(e => Visit(e, st));\n    }\n    public void Visit(MaybeFreeExpression expr, State st) {\n      Visit(expr.E, st);\n    }\n    public void Visit(FrameExpression expr, State st) {\n      Visit(expr.E, st);\n    }\n    public void Visit(IEnumerable<MaybeFreeExpression> exprs, State st) {\n      exprs.Iter(e => Visit(e, st));\n    }\n    public void Visit(IEnumerable<FrameExpression> exprs, State st) {\n      exprs.Iter(e => Visit(e, st));\n    }\n    public void Visit(ICallable decl, State st) {\n      if (decl is Function) {\n        Visit((Function)decl, st);\n      } else if (decl is Method) {\n        Visit((Method)decl, st);\n      }\n      //TODO More?\n    }\n    public void Visit(Method method, State st) {\n      Visit(method.Ens, st);\n      Visit(method.Req, st);\n      Visit(method.Mod.Expressions, st);\n      Visit(method.Decreases.Expressions, st);\n      if (method.Body != null) { Visit(method.Body, st); }\n      //TODO More?\n    }\n    public void Visit(Function function, State st) {\n      Visit(function.Ens, st);\n      Visit(function.Req, st);\n      Visit(function.Reads, st);\n      Visit(function.Decreases.Expressions, st);\n      if (function.Body != null) { Visit(function.Body, st); }\n      //TODO More?\n    }\n    /// <summary>\n    /// Visit one expression proper.  This method is invoked before it is invoked on the\n    /// sub-parts (sub-expressions and sub-statements).  A return value of \"true\" says to\n    /// continue invoking the method on sub-parts, whereas \"false\" says not to do so.\n    /// The on-return value of \"st\" is the value that is passed to sub-parts.\n    /// </summary>\n    protected virtual bool VisitOneExpr(Expression expr, ref State st) {\n      Contract.Requires(expr != null);\n      return true;  // by default, visit the sub-parts with the same \"st\"\n    }\n    /// <summary>\n    /// Visit one statement proper.  For the rest of the description of what this method\n    /// does, see VisitOneExpr.\n    /// </summary>\n    protected virtual bool VisitOneStmt(Statement stmt, ref State st) {\n      Contract.Requires(stmt != null);\n      return true;  // by default, visit the sub-parts with the same \"st\"\n    }\n  }\n}\n"
  },
  {
    "path": "Source/Armada/ArmadaExpr.cs",
    "content": "using System;\nusing System.Numerics;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text;\nusing static Microsoft.Armada.Predicate;\nusing IToken = Microsoft.Boogie.IToken;\nusing Token = Microsoft.Boogie.Token;\n\nnamespace Microsoft.Armada {\n\n  public abstract class ArmadaLValue\n  {\n    protected readonly IToken tok;\n    protected readonly Type type;\n\n    public ArmadaLValue(IToken i_tok, Type i_type)\n    {\n      tok = i_tok;\n      type = i_type;\n    }\n\n    public virtual Type Type { get { return type; } }\n\n    public virtual bool IsHeap() { return false; }\n    public virtual bool NoTSO() { return false; }\n\n    public abstract UndefinedBehaviorAvoidanceConstraint GetUndefinedBehaviorAvoidanceConstraint();\n    public abstract string GetAddress();\n\n    public virtual string GetValueInLValueState(ResolutionContext context)\n    {\n      context.Fail(\"Internal error:  GetValueInLValueState not supported\");\n      return null;\n    }\n\n    public abstract string GetStoreBufferLocation();\n\n    public string GetStoreBufferEntry(string val_new, ArmadaPC pc)\n    {\n      var loc = GetStoreBufferLocation();\n      if (loc == null) {\n        return null;\n      }\n      return $\"Armada_StoreBufferEntry({loc}, {AH.GetPrimitiveValueConstructorName(type)}({val_new}), {pc.ToString()})\";\n    }\n\n    public abstract string UpdateTotalStateLocationDirectly(ResolutionContext context, IConstraintCollector constraintCollector,\n                                                            string val_new);\n\n    public string UpdateTotalStateBypassingStoreBuffer(ResolutionContext context, IConstraintCollector constraintCollector,\n                                                       string val_new)\n    {\n      var s_current = UpdateTotalStateLocationDirectly(context, constraintCollector, val_new);\n      return s_current;\n    }\n\n    public string UpdateTotalStateWithStoreBufferEntry(ResolutionContext context, IConstraintCollector constraintCollector,\n                                                       string val_new, ArmadaPC pc)\n    {\n      if (NoTSO()) {\n        return UpdateTotalStateLocationDirectly(context, constraintCollector, val_new);\n      }\n\n      if (!AH.IsPrimitiveType(type)) {\n        context.Fail(tok, \"Can't do TSO write to non-primitive type; try using ::= instead of :=\");\n        return null;\n      }\n\n      var entry = GetStoreBufferEntry(val_new, pc);\n      if (entry == null) {\n        context.Fail(tok, \"Can't do a TSO write to that location; try using ::= instead of :=\");\n        return null;\n      }\n\n      return $\"Armada_AppendToThreadStoreBuffer({context.GetLValueState()}, {context.tid}, {entry})\";\n    }\n\n    public abstract ArmadaLValue ApplyExprDotName(IToken i_tok, ResolutionContext context, string fieldName, Type ty);\n    public abstract ArmadaLValue ApplySeqSelect(IToken i_tok, ResolutionContext context, ArmadaRValue idx1, Type indexType, Type exprType);\n  }\n\n  public class AddressableArmadaLValue : ArmadaLValue\n  {\n    protected ArmadaRValue address;\n\n    public AddressableArmadaLValue(IToken i_tok, Type i_type, ArmadaRValue i_address)\n      : base(i_tok, i_type)\n    {\n      address = i_address;\n    }\n\n    public override bool IsHeap() { return true; }\n    public override bool NoTSO() { return false; }\n\n    public override UndefinedBehaviorAvoidanceConstraint GetUndefinedBehaviorAvoidanceConstraint() { return address.UndefinedBehaviorAvoidance; }\n    public override string GetAddress() { return address.Val; }\n\n    public override string GetStoreBufferLocation()\n    {\n      if (!AH.IsPrimitiveType(type)) {\n        return null;\n      }\n\n      return $\"Armada_StoreBufferLocation_Addressable({address.Val})\";\n    }\n\n    public override string UpdateTotalStateLocationDirectly(ResolutionContext context, IConstraintCollector constraintCollector,\n                                                            string val_new)\n    {\n      var s = context.GetLValueState();\n      var h = $\"({s}).mem.heap\";\n      var valid = AH.GetInvocationOfValidPointer(h, address.Val, type);\n      if (valid == null) {\n        constraintCollector.Fail(tok, $\"Type {type} is currently not supported in the heap\");\n      }\n      else {\n        constraintCollector.AddUndefinedBehaviorAvoidanceConstraint(valid);\n      }\n\n      var h_new = AH.GetInvocationOfUpdatePointer(h, address.Val, val_new, type);\n      if (h_new == null) {\n        constraintCollector.Fail(tok, $\"Type {type} is currently not supported in the heap\");\n      }\n\n      return $\"{s}.(mem := {s}.mem.(heap := {h_new}))\";\n    }\n\n    public override ArmadaLValue ApplyExprDotName(IToken i_tok, ResolutionContext context, string fieldName, Type targetType)\n    {\n      if (!(type is UserDefinedType)) {\n        context.Fail(i_tok, $\"Attempt to take a field ({fieldName}) of non-struct type {type}\");\n        return null;\n      }\n      UserDefinedType ut = (UserDefinedType)type;\n      if (!context.symbols.DoesStructExist(ut.Name)) {\n        context.Fail(i_tok, $\"Attempt to take a field ({fieldName}) of non struct type {ut.Name}\");\n        return null;\n      }\n      Type fieldType = context.symbols.GetStructFieldType(ut.Name, fieldName);\n      if (fieldType == null) {\n        context.Fail(i_tok, $\"Attempt to take non-existent field ({fieldName}) in struct type {ut.Name}\");\n        return null;\n      }\n      if (!AH.TypesMatch(fieldType, targetType)) {\n        context.Fail(i_tok, $\"Field {fieldName} of type {fieldType} used as type {targetType}\");\n        return null;\n      }\n\n      var crashAvoidance = address.UndefinedBehaviorAvoidance;\n\n      var s = context.GetLValueState();\n      var h = $\"({s}).mem.heap\";\n      int fieldPos = context.symbols.GetStructFieldPos(ut.Name, fieldName);\n      crashAvoidance.Add($\"{address.Val} in {h}.tree\");\n      crashAvoidance.Add($\"0 <= {fieldPos} < |{h}.tree[{address.Val}].children|\");\n\n      var child = $\"{h}.tree[{address.Val}].children[{fieldPos}]\";\n      return new AddressableArmadaLValue(i_tok, fieldType, new ArmadaRValue(crashAvoidance, child));\n    }\n\n    public override ArmadaLValue ApplySeqSelect(IToken i_tok, ResolutionContext context, ArmadaRValue idx1, Type indexType, Type exprType)\n    {\n      if (!(type is SizedArrayType)) {\n        context.Fail(i_tok, \"Attempt to obtain element of non-array type\");\n        return null;\n      }\n      SizedArrayType st = (SizedArrayType)type;\n      if (!AH.TypesMatch(st.Range, exprType)) {\n        context.Fail(i_tok, $\"Element of type {st.Range} used as type {exprType}\");\n        return null;\n      }\n\n      var crashAvoidance = address.UndefinedBehaviorAvoidance + idx1.UndefinedBehaviorAvoidance;\n\n      var s = context.GetLValueState();\n      var h = $\"({s}).mem.heap\";\n      var idx1_as_int = AH.ConvertToIntIfNotInt(idx1.Val, indexType);\n      crashAvoidance.Add($\"{address.Val} in {h}.tree\");\n      crashAvoidance.Add($\"0 <= {idx1_as_int} < |{h}.tree[{address.Val}].children|\");\n\n      var child = $\"{h}.tree[{address.Val}].children[{idx1_as_int}]\";\n      return new AddressableArmadaLValue(i_tok, st.Range, new ArmadaRValue(crashAvoidance, child));\n    }\n  }\n\n  public abstract class UnaddressableArmadaLValue : ArmadaLValue\n  {\n    protected UndefinedBehaviorAvoidanceConstraint crashAvoidance;\n\n    public UnaddressableArmadaLValue(IToken i_tok, Type i_type, UndefinedBehaviorAvoidanceConstraint i_crashAvoidance) : base(i_tok, i_type)\n    {\n      crashAvoidance = i_crashAvoidance;\n    }\n\n    public override UndefinedBehaviorAvoidanceConstraint GetUndefinedBehaviorAvoidanceConstraint()\n    {\n      return crashAvoidance;\n    }\n\n    public override string GetAddress() { return null; }\n\n    public abstract string GetStoreBufferLocationInfo(ref List<string> fields);\n\n    public override string GetStoreBufferLocation()\n    {\n      if (!AH.IsPrimitiveType(type)) {\n        return null;\n      }\n\n      var fields = new List<string>();\n      var v = GetStoreBufferLocationInfo(ref fields);\n      if (v == null) {\n        return null;\n      }\n\n      var fields_seq = String.Join(\", \", fields);\n      return $\"Armada_StoreBufferLocation_Unaddressable({v}, [{fields_seq}])\";\n    }\n\n    public override ArmadaLValue ApplyExprDotName(IToken i_tok, ResolutionContext context, string fieldName, Type ty)\n    {\n      if (!(type is UserDefinedType)) {\n        context.Fail(i_tok, $\"Attempt to take a field ({fieldName}) of non-struct, non-datatype type {type}\");\n        return null;\n      }\n\n      UserDefinedType ut = (UserDefinedType)type;\n      int fieldPos = 0;\n      if (context.symbols.DoesStructExist(ut.Name)) {\n        Type fieldType = context.symbols.GetStructFieldType(ut.Name, fieldName);\n        if (fieldType == null) {\n          context.Fail(i_tok, $\"Attempt to take non-existent field ({fieldName}) in struct type {ut.Name}\");\n          return null;\n        }\n        if (!AH.TypesMatch(fieldType, ty)) {\n          context.Fail(i_tok, $\"Field {fieldName} of type {fieldType} used as type {ty}\");\n          return null;\n        }\n        fieldPos = context.symbols.GetStructFieldPos(ut.Name, fieldName);\n      }\n\n      return new UnaddressableFieldArmadaLValue(i_tok, ty, this, crashAvoidance, fieldName, fieldPos, false);\n    }\n\n    public override ArmadaLValue ApplySeqSelect(IToken i_tok, ResolutionContext context, ArmadaRValue idx1, Type indexType, Type exprType)\n    {\n      var me = GetValueInLValueState(context);\n      var sz = $\"|{me}|\";\n\n      var newUndefinedBehaviorAvoidance = GetUndefinedBehaviorAvoidanceConstraint() + idx1.UndefinedBehaviorAvoidance;\n\n      var idx1val = AH.ConvertToIntIfNotInt(idx1.Val, indexType);\n\n      if (type is SizedArrayType) {\n        SizedArrayType st = (SizedArrayType)type;\n        if (!AH.TypesMatch(st.Range, exprType)) {\n          context.Fail(i_tok, $\"Element of type {st.Range} used as type {exprType}\");\n          return null;\n        }\n\n        newUndefinedBehaviorAvoidance.Add($\"0 <= {idx1val} < {sz}\");\n      }\n      else if (type is SeqType) {\n        newUndefinedBehaviorAvoidance.Add($\"0 <= {idx1val} < {sz}\");\n      }\n      else if (type is MapType) {\n        // There's no need to consider it undefined behavior if idx1.Val isn't in this map, since we're just\n        // using it as an lvalue.  It's fine to update an element of a map that isn't yet in its domain.\n        // So we don't need to do:\n        //   newUndefinedBehaviorAvoidance.Add($\"({idx1.Val}) in ({me})\");\n        return new UnaddressableIndexArmadaLValue(i_tok, exprType, this, newUndefinedBehaviorAvoidance, idx1.Val);\n      }\n      else {\n        context.Fail(i_tok, $\"Attempt to index into something that isn't an array, seq, or map\");\n        return null;\n      }\n\n      return new UnaddressableIndexArmadaLValue(i_tok, exprType, this, newUndefinedBehaviorAvoidance, idx1val);\n    }\n  }\n\n  public class TopStackVarsArmadaLValue : UnaddressableArmadaLValue\n  {\n    private string methodName;\n\n    public TopStackVarsArmadaLValue(UndefinedBehaviorAvoidanceConstraint i_crashAvoidance, string i_methodName)\n      : base(Token.NoToken, AH.ReferToType($\"Armada_StackVars_{i_methodName}\"), i_crashAvoidance)\n    {\n      methodName = i_methodName;\n    }\n\n    public override bool NoTSO() { return true; }\n\n    public override string GetValueInLValueState(ResolutionContext context)\n    {\n      return $\"({context.GetLValueTopStackFrame()}).{methodName}\";\n    }\n\n    public override string GetStoreBufferLocationInfo(ref List<string> fields)\n    {\n      return null;\n    }\n\n    public override string UpdateTotalStateLocationDirectly(ResolutionContext context, IConstraintCollector constraintCollector,\n                                                            string val_new)\n    {\n      return $\"Armada_UpdateTSFrame({context.GetLValueState()}, {context.tid}, Armada_StackFrame_{methodName}({val_new}))\";\n    }\n  }\n\n  public class GlobalsArmadaLValue : UnaddressableArmadaLValue\n  {\n    public GlobalsArmadaLValue() : base(Token.NoToken, AH.ReferToType(\"Armada_Globals\"), new UndefinedBehaviorAvoidanceConstraint()) { }\n\n    public override bool NoTSO() { return false; }\n\n    public override string GetValueInLValueState(ResolutionContext context)\n    {\n      return $\"({context.GetLValueState()}).mem.globals\";\n    }\n\n    public override string GetStoreBufferLocationInfo(ref List<string> fields)\n    {\n      return null;\n    }\n\n    public override string UpdateTotalStateLocationDirectly(ResolutionContext context, IConstraintCollector constraintCollector,\n                                                            string val_new)\n    {\n      var s = context.GetLValueState();\n      return $\"({s}).(mem := ({s}).mem.(globals := {val_new}))\";\n    }\n  }\n\n  public class GhostsArmadaLValue : UnaddressableArmadaLValue\n  {\n    public GhostsArmadaLValue() : base(Token.NoToken, AH.ReferToType(\"Armada_Ghosts\"), new UndefinedBehaviorAvoidanceConstraint()) { }\n\n    public override bool NoTSO() { return true; }\n\n    public override string GetValueInLValueState(ResolutionContext context)\n    {\n      return $\"({context.GetLValueState()}).ghosts\";\n    }\n\n    public override string GetStoreBufferLocationInfo(ref List<string> fields)\n    {\n      return null;\n    }\n\n    public override string UpdateTotalStateLocationDirectly(ResolutionContext context, IConstraintCollector constraintCollector,\n                                                            string val_new)\n    {\n      return $\"({context.GetLValueState()}).(ghosts := {val_new})\";\n    }\n  }\n\n  public class UnaddressableFieldArmadaLValue : UnaddressableArmadaLValue\n  {\n    private readonly UnaddressableArmadaLValue parent;\n    private readonly string fieldName;\n    private readonly int fieldPos;\n    public readonly bool noTSO;\n\n    public UnaddressableFieldArmadaLValue(IToken i_tok, Type i_type, UnaddressableArmadaLValue i_parent,\n                                          UndefinedBehaviorAvoidanceConstraint i_crashAvoidance, string i_fieldName,\n                                          int i_fieldPos, bool i_noTSO)\n      : base(i_tok, i_type, i_crashAvoidance)\n    {\n      parent = i_parent;\n      fieldName = i_fieldName;\n      fieldPos = i_fieldPos;\n      noTSO = i_noTSO;\n    }\n\n    public UnaddressableArmadaLValue GetParent() { return parent; }\n    public string GetFieldName() { return fieldName; }\n    public int GetFieldPos() { return fieldPos; }\n\n    public override bool NoTSO() { return noTSO || parent.NoTSO(); }\n\n    public override string GetValueInLValueState(ResolutionContext context)\n    {\n      return $\"({parent.GetValueInLValueState(context)}).{fieldName}\";\n    }\n\n    public override string GetStoreBufferLocationInfo(ref List<string> fields) {\n      if (parent.NoTSO()) {\n        return null;\n      }\n      if (parent is GlobalsArmadaLValue) {\n        return $\"Armada_GlobalStaticVar_{fieldName}\";\n      }\n      else if (!(parent.Type is UserDefinedType)) {\n        return null;\n      }\n      else {\n        var ut = (UserDefinedType)parent.Type;\n        var ret = parent.GetStoreBufferLocationInfo(ref fields);\n        if (ret == null) {\n          return null;\n        }\n        fields.Add($\"{fieldPos}\");\n        return ret;\n      }\n    }\n\n    public override string UpdateTotalStateLocationDirectly(ResolutionContext context, IConstraintCollector constraintCollector,\n                                                            string val_new)\n    {\n      string parent_val_old = parent.GetValueInLValueState(context);\n      string parent_val_new = $\"({parent_val_old}).({fieldName} := {val_new})\";\n      return parent.UpdateTotalStateLocationDirectly(context, constraintCollector, parent_val_new);\n    }\n  }\n\n  public class UnaddressableIndexArmadaLValue : UnaddressableArmadaLValue\n  {\n    private UnaddressableArmadaLValue parent;\n    private string index;\n\n    public UnaddressableIndexArmadaLValue(IToken i_tok, Type i_type, UnaddressableArmadaLValue i_parent,\n                                          UndefinedBehaviorAvoidanceConstraint i_crashAvoidance, string i_index)\n      : base(i_tok, i_type, i_crashAvoidance)\n    {\n      parent = i_parent;\n      index = i_index;\n    }\n\n    public UnaddressableArmadaLValue GetParent() { return parent; }\n    public string GetIndex() { return index; }\n\n    public override bool NoTSO() { return parent.NoTSO(); }\n\n    public override string GetValueInLValueState(ResolutionContext context)\n    {\n      return $\"({parent.GetValueInLValueState(context)})[{index}]\";\n    }\n\n    public override string GetStoreBufferLocationInfo(ref List<string> fields) {\n      if (parent.NoTSO()) {\n        return null;\n      }\n\n      var ret = parent.GetStoreBufferLocationInfo(ref fields);\n      if (ret == null) {\n        return null;\n      }\n\n      fields.Add(index);\n      return ret;\n    }\n\n    public override string UpdateTotalStateLocationDirectly(ResolutionContext context, IConstraintCollector constraintCollector,\n                                                            string val_new)\n    {\n      string parent_val_old = parent.GetValueInLValueState(context);\n      string parent_val_new = $\"({parent_val_old})[{index} := {val_new}]\";\n      return parent.UpdateTotalStateLocationDirectly(context, constraintCollector, parent_val_new);\n    }\n  }\n}\n"
  },
  {
    "path": "Source/Armada/ArmadaHelper.cs",
    "content": "using System;\nusing System.Numerics;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text;\nusing System.Text.RegularExpressions;\nusing static Microsoft.Armada.Predicate;\nusing IToken = Microsoft.Boogie.IToken;\nusing Token = Microsoft.Boogie.Token;\n\nnamespace Microsoft.Armada {\n\n  class AH {\n\n    public static void PrintError(Program prog, IToken tok, string s) {\n      prog.reporter.Error(MessageSource.Rewriter, tok, s);\n      throw new Exception(s);\n    }\n\n    public static void PrintError(Program prog, string s) {\n      PrintError(prog, Token.NoToken, s);\n    }\n\n    public static void PrintWarning(Program prog, IToken tok, string s) {\n      prog.reporter.Warning(MessageSource.Rewriter, tok, s);\n    }\n\n    public static void PrintWarning(Program prog, string s) {\n      PrintWarning(prog, Token.NoToken, s);\n    }\n\n    public static Declaration ParseTopLevelDecl(Program prog, string filename, string s) {\n      var e = new Errors(new ErrorReporterWrapper(prog.reporter, s));\n      return Parser.ParseTopLevelDecl(s, filename, filename, null, prog.DefaultModule, prog.BuiltIns, e);\n    }\n\n    public static Expression ParseExpression(Program prog, string filename, string s) {\n      var e = new Errors(new ErrorReporterWrapper(prog.reporter, s));\n      return Parser.ParseExpression(s, filename, filename, null, prog.DefaultModule, prog.BuiltIns, e);\n    }\n\n    public static string AddModuleToIdentifier(string moduleName, string typeName)\n    {\n      return moduleName != null ? moduleName + \".\" + typeName : typeName;\n    }\n\n    public static IToken MakeToken(string s) {\n      var t = new Token();\n      t.val = s;\n      return t;\n    }\n\n    public static Expression SetExprType(Expression e, Type t) {\n      if (t != null) {\n        e.Type = t;\n      }\n      return e;\n    }\n\n    public static Expression MakeNameSegment(string name, Type type) {\n      return SetExprType(new NameSegment(Token.NoToken, name, null), type);\n    }\n\n    public static AliasModuleDecl MakeAliasModuleDecl(string s, ModuleDefinition def, bool opened) {\n      var t = MakeToken(s);\n      return new AliasModuleDecl(new List<IToken>{t}, t, def, opened, new List<IToken>());\n    }\n\n    public static AliasModuleDecl MakeAliasModuleDecl(string alias, string target, ModuleDefinition def, bool opened) {\n      var t1 = MakeToken(target);\n      var t2 = MakeToken(alias);\n      return new AliasModuleDecl(new List<IToken>{t1}, t2, def, opened, new List<IToken>());\n    }\n\n    public static Type ReferToType(string name, string moduleName = null) {\n      return new UserDefinedType(Token.NoToken, AddModuleToIdentifier(moduleName, name), null);\n    }\n\n    public static string GetConcreteThreadHandleTypeName() {\n      return \"uint64\";\n    }\n\n    public static string GetConcretePointerTypeName() {\n      return \"uint64\";\n    }\n\n    public static Type ConcretizeType(Type t) {\n      t = t.NormalizeExpand(true);\n      if (t is PointerType) {\n        return ReferToType(GetConcretePointerTypeName());\n      }\n      if (t is UserDefinedType) {\n        var udt = (UserDefinedType)t;\n        if (udt.Name == \"Armada_ThreadHandle\") {\n          return ReferToType(GetConcreteThreadHandleTypeName());\n        }\n        if (udt.Name == \"Armada_Pointer\") {\n          return ReferToType(GetConcretePointerTypeName());\n        }\n      }\n      return t;\n    }\n\n    public static bool TypesMatch(Type t1, Type t2)\n    {\n      if (t1 is PointerType) {\n        if (!(t2 is PointerType)) {\n          return false;\n        }\n        var pt1 = (PointerType)t1;\n        var pt2 = (PointerType)t2;\n        return TypesMatch(pt1.Arg, pt2.Arg);\n      }\n\n      if (t1 is UserDefinedType && t2 is UserDefinedType) {\n        var ut1 = (UserDefinedType)t1;\n        var ut2 = (UserDefinedType)t2;\n        if (ut1.Name == ut2.Name) {\n          return true;\n        }\n      }\n\n      if (t1 is SizedArrayType) {\n        if (!(t2 is SizedArrayType)) {\n          return false;\n        }\n        var st1 = (SizedArrayType)t1;\n        var st2 = (SizedArrayType)t2;\n        var sz1 = st1.Size;\n        var sz2 = st2.Size;\n        if (sz1 is LiteralExpr && sz2 is LiteralExpr) {\n          var le1 = (LiteralExpr)sz1;\n          var le2 = (LiteralExpr)sz2;\n          if (!le1.Value.Equals(le2.Value)) {\n            return false;\n          }\n        }\n        else {\n          if (!sz1.Equals(sz2)) {\n            return false;\n          }\n        }\n        return TypesMatch(st1.Range, st2.Range);\n      }\n\n      return t1.Equals(t2);\n    }\n\n    public static string GetObjectType(Type t)\n    {\n      t = ConcretizeType(t);\n      if (t is PointerType) {\n        return $\"Armada_ObjectTypePrimitive(Armada_PrimitiveType_{GetConcretePointerTypeName()})\";\n      }\n      else if (t is SizedArrayType at) {\n        var subtypeConstructor = GetObjectType(at.Range);\n        return $\"Armada_ObjectTypeArray({subtypeConstructor}, {Printer.ExprToString(at.Size)})\";\n      }\n      else if (IsPrimitiveType(t)) {\n        return $\"Armada_ObjectTypePrimitive(Armada_PrimitiveType_{t})\";\n      }\n      else if (t is UserDefinedType ut) {\n        return $\"Armada_StructType_{ut.Name}()\";\n      }\n      else {\n        return null;\n      }\n    }\n\n    public static string GetInvocationOfValidPointer(string h, string p, Type t)\n    {\n      return $\"Armada_ValidPointerToObjectType({h}, {p}, {GetObjectType(t)})\";\n    }\n\n    public static string GetInvocationOfValidPointerToDynamicArray(string h, string p, Type t, string sz)\n    {\n      return $\"Armada_ValidPointerToObjectType({h}, {p}, Armada_ObjectTypeArray({GetObjectType(t)}, {sz}))\";\n    }\n\n    public static string GetInvocationOfDescendants(string h, string p, Type t)\n    {\n      return $\"Armada_DescendantsOfPointerToObjectType(({h}).tree, {p}, {GetObjectType(t)})\";\n    }\n\n    public static string GetInvocationOfDescendantsOfDynamicArray(string h, string p, Type subtype, string sz)\n    {\n      return $\"Armada_DescendantsOfPointerToObjectType(({h}).tree, {p}, Armada_ObjectTypeArray({GetObjectType(subtype)}, {sz}))\";\n    }\n\n    public static string GetInvocationOfDereferencePointer(string h, string p, Type t)\n    {\n      if (t is SizedArrayType at) {\n        var subinvocation = GetInvocationOfDereferencePointer(h, $\"{h}.tree[{p}].children[i]\", at.Range);\n        return $\"var sz := {h}.tree[{p}].ty.sz; seq(sz, i requires 0 <= i < sz => ({subinvocation}))\";\n      }\n      else {\n        t = ConcretizeType(t);\n        if (IsPrimitiveType(t)) {\n          return $\"{h}.values[{p}].n_{t}\";\n        }\n        else if (t is UserDefinedType ut) {\n          return $\"Armada_DereferenceStructPointer_{ut.Name}({h}, {p})\";\n        }\n        else {\n          return null;\n        }\n      }\n    }\n\n    public static string GetInvocationOfUpdateValuesViaPointer(string h, string p, string value, Type valueType)\n    {\n      if (valueType is SizedArrayType at) {\n        var invocation = GetInvocationOfUpdateValuesViaPointer(h, $\"{h}.tree[{p}].children[i_]\", $\"({value})[i_]\", at.Range);\n        return $@\"\n          set tup_: (Armada_Pointer, Armada_PrimitiveValue), i_: int\n            | 0 <= i_ < |{h}.tree[{p}].children| && i_ < |{value}| && tup_ in ({invocation}) :: tup_\n        \";\n      }\n      else {\n        var t = ConcretizeType(valueType);\n        if (IsPrimitiveType(t)) {\n          return $\"{{ ({p}, Armada_PrimitiveValue_{t}({value})) }}\";\n        }\n        else if (t is UserDefinedType ut) {\n          return $\"Armada_UpdateHeapValuesWithStruct_{ut.Name}({h}, {p}, {value})\";\n        }\n        else {\n          return null;\n        }\n      }\n    }\n\n    public static string GetInvocationOfUpdatePointer(string h, string p, string value, Type valueType)\n    {\n      if (IsPrimitiveType(valueType)) {\n        var t = ConcretizeType(valueType);\n        return $\"{h}.(values := Armada_UpdateHeapValuesWithPrimitiveValue({h}.values, {p}, Armada_PrimitiveValue_{t}({value})))\";\n      }\n      else {\n        var subinvocation = GetInvocationOfUpdateValuesViaPointer(h, p, value, valueType);\n        return $\"{h}.(values := Armada_UpdateHeapValuesSimultaneously({h}.values, {subinvocation}))\";\n      }\n    }\n\n    public static List<string> GetPrimitiveTypeNames()\n    {\n      return new List<string>{ \"uint8\", \"uint16\", \"uint32\", \"uint64\", \"int8\", \"int16\", \"int32\", \"int64\" };\n    }\n\n    public static bool IsLimitedSizeIntType(Type type)\n    {\n      type = ConcretizeType(type);\n      if (!(type is UserDefinedType)) {\n        return false;\n      }\n      var ut = (UserDefinedType)type;\n      return GetPrimitiveTypeNames().Contains(ut.Name);\n    }\n\n    public static bool IsPrimitiveType(Type type)\n    {\n      type = ConcretizeType(type);\n      if (!(type is UserDefinedType)) {\n        return false;\n      }\n      var ut = (UserDefinedType)type;\n      return GetPrimitiveTypeNames().Contains(ut.Name);\n    }\n\n    public static bool IsValidHeapType(Type type, ArmadaStructs structs)\n    {\n      if (type is PointerType pt) {\n        return IsValidHeapType(pt.Arg, structs);\n      }\n      else if (IsPrimitiveType(type)) {\n        return true;\n      }\n      else if (type is UserDefinedType ut) {\n        return structs.DoesStructExist(ut.Name); // Datatypes aren't allowed on the heap, only structs\n      }\n      else if (type is SizedArrayType at) {\n        return IsValidHeapType(at.Range, structs);\n      }\n      else {\n        return false;\n      }\n    }\n\n    public static bool IsValidType(Type type, ArmadaStructs structs)\n    {\n      if (type is PointerType pt) {\n        return IsValidHeapType(pt.Arg, structs); // Pointer types are only valid if they point to heap types\n      }\n      else if (IsPrimitiveType(type)) {\n        return true;\n      }\n      else if (type is UserDefinedType ut) {\n        return true;\n      }\n      else if (type is SizedArrayType at) {\n        return IsValidType(at.Range, structs);\n      }\n      else if (type is SeqType seqt) {\n        return IsValidType(seqt.Arg, structs);\n      }\n      else if (type is SetType sett) {\n        return IsValidType(sett.Arg, structs);\n      }\n      else if (type is MultiSetType mst) {\n        return IsValidType(mst.Arg, structs);\n      }\n      else if (type is MapType mt) {\n        return IsValidType(mt.Domain, structs) && IsValidType(mt.Range, structs);\n      }\n      else if (type is ArrowType arrowt) {\n        return arrowt.Args.All(subtype => IsValidType(subtype, structs)) && IsValidType(arrowt.Result, structs);\n      }\n      else if (type == null) {\n        return false;\n      }\n      else {\n        return true;\n      }\n    }\n\n    public static string GetPrimitiveValueField(Type type)\n    {\n      type = ConcretizeType(type);\n      if (!(type is UserDefinedType)) {\n        Debug.Assert(false);\n        return null;\n      }\n      var ut = (UserDefinedType)type;\n      var primitiveTypeNames = GetPrimitiveTypeNames();\n      foreach (var primitiveTypeName in primitiveTypeNames) {\n        if (ut.Name == primitiveTypeName) {\n          return \"n_\" + primitiveTypeName;\n        }\n      }\n      Debug.Assert(false);\n      return null;\n    }\n\n    public static string GetPrimitiveValueConstructorName(Type type)\n    {\n      type = ConcretizeType(type);\n      if (!(type is UserDefinedType)) {\n        Debug.Assert(false);\n        return null;\n      }\n      var ut = (UserDefinedType)type;\n      var primitiveTypeNames = GetPrimitiveTypeNames();\n      foreach (var primitiveTypeName in primitiveTypeNames) {\n        if (ut.Name == primitiveTypeName) {\n          return \"Armada_PrimitiveValue_\" + primitiveTypeName;\n        }\n      }\n      Debug.Assert(false);\n      return null;\n    }\n\n    public static string GetPrimitiveTypeName(Type type)\n    {\n      type = ConcretizeType(type);\n      if (!(type is UserDefinedType)) {\n        Debug.Assert(false);\n        return null;\n      }\n      var ut = (UserDefinedType)type;\n      var primitiveTypeNames = GetPrimitiveTypeNames();\n      foreach (var primitiveTypeName in primitiveTypeNames) {\n        if (ut.Name == primitiveTypeName) {\n          return \"Armada_PrimitiveType_\" + primitiveTypeName;\n        }\n      }\n      Debug.Assert(false);\n      return null;\n    }\n\n    public static int GetNumArrayDimensions(Type outerType, out Type innerType)\n    {\n      if (outerType is SizedArrayType at) {\n        return GetNumArrayDimensions(at.Range, out innerType) + 1;\n      }\n      innerType = ConcretizeType(outerType);\n      return 0;\n    }\n\n    public static string CombineStringsWithOr(IEnumerable<string> es)\n    {\n      var body = String.Join(\" || \", es.Select(e => $\"({e})\"));\n      return body.Length == 0 ? \"false\" : body;\n    }\n\n    public static string CombineStringsWithAnd(IEnumerable<string> es)\n    {\n      var body = String.Join(\" && \", es.Select(e => $\"({e})\"));\n      return body.Length == 0 ? \"true\" : body;\n    }\n\n    public static string CombineStringsWithCommas(IEnumerable<string> strs)\n    {\n      return String.Join(\", \", strs);\n    }\n\n    public static string CombineStringsWithSetAddition(IEnumerable<string> es)\n    {\n      var body = String.Join(\" + \", es.Select(e => $\"({e})\"));\n      return body.Length == 0 ? \"{}\" : body;\n    }\n\n    public static string ExpandUnderscores(string s)\n    {\n      return s.Replace(\"_\", \"__\");\n    }\n\n    public static bool IsJustNames(Expression e)\n    {\n      if (e is NameSegment) {\n        return true;\n      }\n      else if (e is ExprDotName subexpr) {\n        return IsJustNames(subexpr.Lhs);\n      }\n      else {\n        return false;\n      }\n    }\n\n    public static bool GetDereferenceType(Type t, out Type subtype, out string err) {\n      subtype = null;\n      err = null;\n      if (!(t is PointerType)) {\n        err = \"Attempt to dereference non-pointer type\";\n        return false;\n      }\n      PointerType pt = (PointerType)t;\n      subtype = pt.Arg;\n      return true;\n    }\n\n    public static string EnsureIntegerFit(string e, Type sourceType, Type targetType)\n    {\n      sourceType = ConcretizeType(sourceType);\n      targetType = ConcretizeType(targetType);\n\n      if (!(targetType is UserDefinedType)) {\n        return e;\n      }\n\n      var ut = (UserDefinedType)targetType;\n      var primitiveTypeNames = GetPrimitiveTypeNames();\n      foreach (var primitiveTypeName in primitiveTypeNames) {\n        if (ut.Name == primitiveTypeName) {\n          if (IsLimitedSizeIntType(sourceType)) {\n            e = $\"({e}) as int\";\n          }\n          return $\"Armada_CastTo_{primitiveTypeName}({e})\";\n        }\n      }\n\n      return e;\n    }\n\n    public static string ConvertToIntIfNotInt(string e, Type ty)\n    {\n      if (e == null || ty is IntType) {\n        return e;\n      }\n      return $\"({e}) as int\";\n    }\n\n    public static string ConvertToIntIfLimitedSizeInt(string e, Type ty)\n    {\n      if (IsLimitedSizeIntType(ty)) {\n        return $\"({e}) as int\";\n      }\n      else {\n        return e;\n      }\n    }\n\n    public static string GetBitWidth(UserDefinedType uty) {\n      Match match = Regex.Match(uty.Name, @\"^u?int(\\d+)$\");\n      if (!match.Success) {\n        throw new Exception(\"Failed to find the bit-width of: \" + uty);\n      }\n      return \"\" + match.Groups[1];\n    }\n\n    public static string GetLValueRootVariable(Expression expr)\n    {\n      if (expr == null) {\n        return null;\n      }\n\n      if (expr is ParensExpression pe) {\n        return GetLValueRootVariable(pe.E);\n      }\n\n      if (expr is NameSegment ns) {\n        return ns.Name;\n      }\n\n      if (expr is ExprDotName edn) {\n        return GetLValueRootVariable(edn.Lhs);\n      }\n\n      if (expr is SeqSelectExpr sse) {\n        return GetLValueRootVariable(sse.Seq);\n      }\n\n      if (expr is UnaryOpExpr uoe) {\n        return GetLValueRootVariable(uoe.E);\n      }\n\n      return null;\n    }\n\n    public static string TokenToString(IToken tok)\n    {\n      return $\"line {tok.line}, col {tok.col}\";\n    }\n  }\n}\n"
  },
  {
    "path": "Source/Armada/ArmadaMain.cs",
    "content": "//-----------------------------------------------------------------------------\n//\n// Copyright (C) Microsoft Corporation.  All Rights Reserved.\n//\n//-----------------------------------------------------------------------------\nusing System;\nusing System.IO;\nusing System.Collections.Generic;\nusing System.Diagnostics.Contracts;\nusing Bpl = Microsoft.Boogie;\nusing System.Reflection;\n\nnamespace Microsoft.Armada {\n\n  public class IllegalDafnyFile : Exception { }\n\n  public class DafnyFile {\n    public string FilePath { get; private set; }\n    public string BaseName { get; private set; }\n    public bool isPrecompiled { get; private set; }\n    public string SourceFileName { get; private set; }\n\n    public static List<string> fileNames(IList<DafnyFile> dafnyFiles) {\n      var sourceFiles = new List<string>();\n      foreach (DafnyFile f in dafnyFiles) {\n        sourceFiles.Add(f.FilePath);\n      }\n      return sourceFiles;\n    }\n\n    public DafnyFile(string filePath) {\n      FilePath = filePath;\n      BaseName = Path.GetFileName(filePath);\n\n      var extension = Path.GetExtension(filePath);\n      if (extension != null) { extension = extension.ToLower(); }\n\n      if (extension == \".dfy\" || extension == \".dfyi\" || extension == \".cdfy\" || extension == \".arm\") {\n        isPrecompiled = false;\n        SourceFileName = filePath;\n      } else if (extension == \".dll\") {\n        isPrecompiled = true;\n        Assembly.ReflectionOnlyLoad(\"DafnyRuntime\");\n        var asm = Assembly.ReflectionOnlyLoadFrom(filePath);\n        string sourceText = null;\n        foreach (var adata in asm.GetCustomAttributesData()) {\n          if (adata.Constructor.DeclaringType.Name == \"DafnySourceAttribute\") {\n            foreach (var args in adata.ConstructorArguments) {\n              if (args.ArgumentType == System.Type.GetType(\"System.String\")) {\n                sourceText = (string)args.Value;\n              }\n            }\n          }\n        }\n\n        if (sourceText == null) { throw new IllegalDafnyFile(); }\n        SourceFileName = Path.GetTempFileName();\n        File.WriteAllText(SourceFileName, sourceText);\n\n      } else {\n        throw new IllegalDafnyFile();\n      }\n\n\n    }\n  }\n\n  public class Main {\n\n      public static void MaybePrintProgram(Program program, string filename, bool afterResolver)\n      {\n          if (filename != null) {\n              TextWriter tw;\n              if (filename == \"-\") {\n                  tw = System.Console.Out;\n              } else {\n                  tw = new System.IO.StreamWriter(filename);\n              }\n              Printer pr = new Printer(tw, ArmadaOptions.O.PrintMode);\n              pr.PrintProgram(program, afterResolver);\n          }\n      }\n\n    public static void PrintLevels(Program program) {\n      foreach (TopLevelDecl d in program.DefaultModuleDef.TopLevelDecls) {\n        if (d is LiteralModuleDecl) {\n          var def = ((LiteralModuleDecl)d).ModuleDef;\n          var pathName = ArmadaOptions.O.ArmadaOutputDir + \"/\" + def.Name + \".dfy\";\n          if (def.ModuleType == ArmadaModuleType.ArmadaLevel && def.IsToBeVerified) {\n            Console.Out.WriteLine(\"Printing level to {0}\", pathName);\n          }\n          else if (def.ModuleType == ArmadaModuleType.ArmadaStructs && def.IsToBeVerified) {\n            Console.Out.WriteLine(\"Printing structs to {0}\", pathName);\n          }\n          else {\n            continue;\n          }\n          var tw = new System.IO.StreamWriter(pathName);\n          var pr = new Printer(tw, ArmadaOptions.O.PrintMode);\n          var fileBeingPrinted = Path.GetFullPath(program.FullName);\n          VisibilityScope scope = null;\n          var ld = (LiteralModuleDecl) d;\n          if (ld.Signature != null)\n          {\n            scope = ld.Signature.VisibilityScope;\n          }\n          foreach (var includePath in def.ArmadaIncludes) {\n            pr.PrintInclude(includePath);\n          }\n          pr.PrintModuleDefinition(def.ArmadaTranslation, scope, 0, new List<Bpl.IToken>(), fileBeingPrinted);\n          tw.Flush();\n        }\n      }\n    }\n\n    /// <summary>\n    /// Returns null on success, or an error string otherwise.\n    /// </summary>\n    public static string ParseCheck(IList<DafnyFile/*!*/>/*!*/ files, string/*!*/ programName, ErrorReporter reporter, out Program program)\n      //modifies Bpl.CommandLineOptions.Clo.XmlSink.*;\n    {\n      string err = Parse(files, programName, reporter, out program);\n      if (err != null) {\n        return err;\n      }\n\n      return Resolve(program, reporter);\n    }\n\n    public static string Parse(IList<DafnyFile> files, string programName, ErrorReporter reporter, out Program program)\n    {\n      Contract.Requires(programName != null);\n      Contract.Requires(files != null);\n      program = null;\n      ModuleDecl module = new LiteralModuleDecl(new DefaultModuleDecl(), null);\n      BuiltIns builtIns = new BuiltIns();\n      foreach (DafnyFile dafnyFile in files){\n        Contract.Assert(dafnyFile != null);\n        if (Bpl.CommandLineOptions.Clo.XmlSink != null && Bpl.CommandLineOptions.Clo.XmlSink.IsOpen) {\n          Bpl.CommandLineOptions.Clo.XmlSink.WriteFileFragment(dafnyFile.FilePath);\n        }\n        if (Bpl.CommandLineOptions.Clo.Trace)\n        {\n          Console.WriteLine(\"Parsing \" + dafnyFile.FilePath);\n        }\n\n        string err = ParseFile(dafnyFile, null, module, builtIns, new Errors(reporter));\n        if (err != null) {\n          return err;\n        }\n      }\n\n      if (!(ArmadaOptions.O.DisallowIncludes || ArmadaOptions.O.PrintIncludesMode == ArmadaOptions.IncludesModes.Immediate)) {\n        string errString = ParseIncludes(module, builtIns, DafnyFile.fileNames(files), new Errors(reporter));\n        if (errString != null) {\n          return errString;\n        }\n      }\n\n      if (ArmadaOptions.O.PrintIncludesMode == ArmadaOptions.IncludesModes.Immediate) {\n        DependencyMap dmap = new DependencyMap();\n        dmap.AddIncludes(((LiteralModuleDecl)module).ModuleDef.Includes);\n        dmap.PrintMap();\n      }\n\n      program = new Program(programName, module, builtIns, reporter);\n\n      MaybePrintProgram(program, ArmadaOptions.O.DafnyPrintFile, false);\n\n      return null; // success\n    }\n\n    public static string Resolve(Program program, ErrorReporter reporter)\n    {\n      if (Bpl.CommandLineOptions.Clo.NoResolve || Bpl.CommandLineOptions.Clo.NoTypecheck) { return null; }\n\n      Microsoft.Armada.Resolver r = new Microsoft.Armada.Resolver(program);\n      r.ResolveProgram(program);\n      MaybePrintProgram(program, ArmadaOptions.O.DafnyPrintResolvedFile, true);\n      PrintLevels(program);\n\n      if (reporter.Count(ErrorLevel.Error) != 0) {\n        return string.Format(\"{0} resolution/type errors detected in {1}\", reporter.Count(ErrorLevel.Error), program.Name);\n      }\n\n      return null;  // success\n    }\n\n    // Lower-case file names before comparing them, since Windows uses case-insensitive file names\n    private class IncludeComparer : IComparer<Include> {\n      public int Compare(Include x, Include y) {\n        return x.includedFullPath.ToLower().CompareTo(y.includedFullPath.ToLower());\n      }\n    }\n\n    public static string ParseIncludes(ModuleDecl module, BuiltIns builtIns, IList<string> excludeFiles, Errors errs) {\n      SortedSet<Include> includes = new SortedSet<Include>(new IncludeComparer());\n      DependencyMap dmap = new DependencyMap();\n      foreach (string fileName in excludeFiles) {\n        includes.Add(new Include(null, null, fileName, Path.GetFullPath(fileName), null));\n      }\n      dmap.AddIncludes(includes);\n      bool newlyIncluded;\n      do {\n        newlyIncluded = false;\n\n        List<Include> newFilesToInclude = new List<Include>();\n        dmap.AddIncludes(((LiteralModuleDecl)module).ModuleDef.Includes);\n        foreach (Include include in ((LiteralModuleDecl)module).ModuleDef.Includes) {\n          bool isNew = includes.Add(include);\n          if (isNew) {\n            newlyIncluded = true;\n            newFilesToInclude.Add(include);\n          }\n        }\n\n        foreach (Include include in newFilesToInclude) {\n          DafnyFile file;\n          try {file = new DafnyFile(include.includedFilename);}\n          catch (IllegalDafnyFile){\n            return (String.Format(\"Include of file \\\"{0}\\\" failed.\", include.includedFilename));\n          }\n          string ret = ParseFile(file, include, module, builtIns, errs, false);\n          if (ret != null) {\n            return ret;\n          }\n        }\n      } while (newlyIncluded);\n\n\n      if (ArmadaOptions.O.PrintIncludesMode != ArmadaOptions.IncludesModes.None) {\n        dmap.PrintMap();\n      }\n\n      return null; // Success\n    }\n\n    private static string ParseFile(DafnyFile dafnyFile, Include include, ModuleDecl module, BuiltIns builtIns, Errors errs, bool verifyThisFile = true) {\n      var fn = ArmadaOptions.Clo.UseBaseNameForFileName ? Path.GetFileName(dafnyFile.FilePath) : dafnyFile.FilePath;\n      try {\n        int errorCount = Microsoft.Armada.Parser.Parse(dafnyFile.SourceFileName, include, module, builtIns, errs, verifyThisFile);\n        if (errorCount != 0) {\n          return string.Format(\"{0} parse errors detected in {1}\", errorCount, fn);\n        }\n      } catch (IOException e) {\n        Bpl.IToken tok = include == null ? Bpl.Token.NoToken : include.tok;\n        errs.SemErr(tok, \"Unable to open included file\");\n        return string.Format(\"Error opening file \\\"{0}\\\": {1}\", fn, e.Message);\n      }\n      return null; // Success\n    }\n\n  }\n}\n"
  },
  {
    "path": "Source/Armada/ArmadaOptions.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Diagnostics.Contracts;\nusing Bpl = Microsoft.Boogie;\n\nnamespace Microsoft.Armada\n{\n  public class ArmadaOptions : Bpl.CommandLineOptions\n  {\n    private ErrorReporter errorReporter;\n\n    public ArmadaOptions(ErrorReporter errorReporter = null)\n      : base(\"Dafny\", \"Dafny program verifier\") {\n        this.errorReporter = errorReporter;\n    }\n\n    public override string VersionNumber {\n      get {\n        return System.Diagnostics.FileVersionInfo.GetVersionInfo(System.Reflection.Assembly.GetExecutingAssembly().Location).FileVersion\n#if ENABLE_IRONDAFNY\n          + \"[IronDafny]\"\n#endif\n          ;\n      }\n    }\n    public override string Version {\n      get {\n        return ToolName + VersionSuffix;\n      }\n    }\n    public override string VersionSuffix {\n      get {\n        return \" \" + VersionNumber;\n      }\n    }\n\n    private static ArmadaOptions clo;\n    public static ArmadaOptions O {\n      get { return clo; }\n    }\n\n    public static void Install(ArmadaOptions options) {\n      Contract.Requires(options != null);\n      clo = options;\n      Bpl.CommandLineOptions.Install(options);\n    }\n\n    public bool UnicodeOutput = false;\n    public bool DisallowSoundnessCheating = false;\n    public bool Dafnycc = false;\n    public int Induction = 3;\n    public int InductionHeuristic = 6;\n    public bool TypeInferenceDebug = false;\n    public string DafnyPrelude = null;\n    public string DafnyPrintFile = null;\n    public enum PrintModes { Everything, DllEmbed, NoIncludes, NoGhost, Armada };\n    public PrintModes PrintMode = PrintModes.Armada;\n    public bool DafnyVerify = false;\n    public string DafnyPrintResolvedFile = null;\n    public List<string> DafnyPrintExportedViews = new List<string>();\n    public bool Compile = false;\n    [Flags]\n    public enum CompilationTarget { Clight = 1 }\n    public CompilationTarget CompileTarget = CompilationTarget.Clight;\n    public bool CompileVerbose = true;\n    public string DafnyPrintCompiledFile = null;\n    public bool ForceCompile = false;\n    public bool RunAfterCompile = false;\n    public int SpillTargetCode = 0;  // [0..4]\n    public bool DisallowIncludes = false;\n    public bool DisallowExterns = false;\n    public bool DisableNLarith = false;\n    public int ArithMode = 1;  // [0..10]\n    public string AutoReqPrintFile = null;\n    public bool ignoreAutoReq = false;\n    public bool AllowGlobals = true;\n    public bool CountVerificationErrors = true;\n    public bool Optimize = false;\n    public bool AutoTriggers = true;\n    public bool RewriteFocalPredicates = true;\n    public bool PrintTooltips = false;\n    public bool PrintStats = false;\n    public bool PrintFunctionCallGraph = false;\n    public bool WarnShadowing = false;\n    public int DefiniteAssignmentLevel = 1;  // [0..4]\n    public bool ForbidNondeterminism {\n      get { return DefiniteAssignmentLevel == 3; }\n    }\n    public int DeprecationNoise = 1;\n    public bool VerifyAllModules = false;\n    public bool SeparateModuleOutput = false;\n    public enum IncludesModes { None, Immediate, Transitive }\n    public IncludesModes PrintIncludesMode = IncludesModes.None;\n    public int OptimizeResolution = 2;\n    public bool UseRuntimeLib = false;\n    public bool DisableScopes = false;\n    public int Allocated = 3;\n    public string ArmadaCommonDefsPath = \".\";\n    public string ArmadaOutputDir = \".\";\n    public bool IronDafny =\n#if ENABLE_IRONDAFNY\n      true\n#else\n      false\n#endif\n    ;\n\n    protected override bool ParseOption(string name, Bpl.CommandLineOptionEngine.CommandLineParseState ps) {\n      var args = ps.args;  // convenient synonym\n\n      switch (name) {\n        case \"armadaPath\":\n          if (ps.ConfirmArgumentCount(1)) {\n            ArmadaCommonDefsPath = args[ps.i];\n          }\n          return true;\n\n        case \"armadaOutputDir\":\n          if (ps.ConfirmArgumentCount(1)) {\n            ArmadaOutputDir = args[ps.i];\n          }\n          return true;\n\n        case \"dprelude\":\n          if (ps.ConfirmArgumentCount(1)) {\n            DafnyPrelude = args[ps.i];\n          }\n          return true;\n\n        case \"dprint\":\n          if (ps.ConfirmArgumentCount(1)) {\n            DafnyPrintFile = args[ps.i];\n          }\n          return true;\n\n        case \"printMode\":\n          if (ps.ConfirmArgumentCount(1)) {\n            if (args[ps.i].Equals(\"Everything\")) {\n              PrintMode = PrintModes.Everything;\n            }\n            else if (args[ps.i].Equals(\"NoIncludes\"))\n            {\n                PrintMode = PrintModes.NoIncludes;\n            }\n            else if (args[ps.i].Equals(\"NoGhost\"))\n            {\n                PrintMode = PrintModes.NoGhost;\n            }\n            else if (args[ps.i].Equals(\"DllEmbed\"))\n            {\n                PrintMode = PrintModes.DllEmbed;\n            }\n            else\n            {\n                throw new Exception(\"Invalid value for printMode\");\n            }\n          }\n          return true;\n\n        case \"rprint\":\n          if (ps.ConfirmArgumentCount(1)) {\n            DafnyPrintResolvedFile = args[ps.i];\n          }\n          return true;\n        case \"view\":\n          if (ps.ConfirmArgumentCount(1)) {\n            DafnyPrintExportedViews = args[ps.i].Split(',').ToList();\n          }\n          return true;\n\n        case \"compile\": {\n            int compile = 0;\n            if (ps.GetNumericArgument(ref compile, 5)) {\n              // convert option to two booleans\n              Compile = compile != 0;\n              ForceCompile = compile == 2 || compile == 4;\n              RunAfterCompile = compile == 3 || compile == 4;\n            }\n            return true;\n          }\n\n        case \"compileTarget\":\n          if (ps.ConfirmArgumentCount(1)) {\n            if (args[ps.i].Equals(\"clight\")) {\n              CompileTarget = CompilationTarget.Clight;\n            } else {\n              throw new Exception(\"Invalid value for compileTarget\");\n            }\n          }\n          return true;\n\n        case \"compileVerbose\": {\n            int verbosity = 0;\n            if (ps.GetNumericArgument(ref verbosity, 2)) {\n              CompileVerbose = verbosity == 1;\n            }\n            return true;\n          }\n\n        case \"dafnyVerify\":\n            {\n                int verify = 0;\n                if (ps.GetNumericArgument(ref verify, 2)) {\n                    DafnyVerify = verify != 0; // convert to boolean\n                }\n                return true;\n            }\n\n        case \"spillTargetCode\": {\n            int spill = 0;\n            if (ps.GetNumericArgument(ref spill, 4)) {\n              SpillTargetCode = spill;\n            }\n            return true;\n          }\n        case \"out\": {\n            if (ps.ConfirmArgumentCount(1)) {\n              DafnyPrintCompiledFile = args[ps.i];\n            }\n            return true;\n          }\n\n        case \"dafnycc\":\n          Dafnycc = true;\n          Induction = 0;\n          Compile = false;\n          UseAbstractInterpretation = false; // /noinfer\n          return true;\n\n        case \"noCheating\": {\n            int cheat = 0; // 0 is default, allows cheating\n            if (ps.GetNumericArgument(ref cheat, 2)) {\n              DisallowSoundnessCheating = cheat == 1;\n            }\n            return true;\n          }\n\n        case \"titrace\":\n          TypeInferenceDebug = true;\n          return true;\n\n        case \"induction\":\n          ps.GetNumericArgument(ref Induction, 4);\n          return true;\n\n        case \"inductionHeuristic\":\n          ps.GetNumericArgument(ref InductionHeuristic, 7);\n          return true;\n\n        case \"noIncludes\":\n          DisallowIncludes = true;\n          return true;\n\n        case \"noExterns\":\n          DisallowExterns = true;\n          return true;\n\n        case \"noNLarith\":\n          DisableNLarith = true;\n          return true;\n\n        case \"arith\": {\n            int a = 0;\n            if (ps.GetNumericArgument(ref a, 11)) {\n              ArithMode = a;\n            }\n            return true;\n          }\n\n        case \"autoReqPrint\":\n          if (ps.ConfirmArgumentCount(1)) {\n              AutoReqPrintFile = args[ps.i];\n          }\n          return true;\n\n        case \"noAutoReq\":\n          ignoreAutoReq = true;\n          return true;\n\n        case \"allowGlobals\":\n          AllowGlobals = true;\n          return true;\n\n        case \"stats\":\n          PrintStats = true;\n          return true;\n\n        case \"funcCallGraph\":\n          PrintFunctionCallGraph = true;\n          return true;\n\n        case \"warnShadowing\":\n          WarnShadowing = true;\n          return true;\n\n        case \"verifyAllModules\":\n          VerifyAllModules = true;\n          return true;\n\n        case \"separateModuleOutput\":\n          SeparateModuleOutput = true;\n          return true;\n\n        case \"deprecation\": {\n          int d = 1;\n          if (ps.GetNumericArgument(ref d, 3)) {\n            DeprecationNoise = d;\n          }\n          return true;\n        }\n\n        case \"countVerificationErrors\": {\n          int countErrors = 1; // defaults to reporting verification errors\n          if (ps.GetNumericArgument(ref countErrors, 2)) {\n            CountVerificationErrors = countErrors == 1;\n          }\n          return true;\n        }\n\n        case \"printTooltips\":\n          PrintTooltips = true;\n          return true;\n\n        case \"autoTriggers\": {\n            int autoTriggers = 0;\n            if (ps.GetNumericArgument(ref autoTriggers, 2)) {\n              AutoTriggers = autoTriggers == 1;\n            }\n            return true;\n          }\n\n        case \"rewriteFocalPredicates\": {\n            int rewriteFocalPredicates = 0;\n            if (ps.GetNumericArgument(ref rewriteFocalPredicates, 2)) {\n              RewriteFocalPredicates = rewriteFocalPredicates == 1;\n            }\n            return true;\n          }\n\n        case \"optimize\": {\n            Optimize = true;\n            return true;\n        }\n\n        case \"allocated\": {\n            ps.GetNumericArgument(ref Allocated, 5);\n            return true;\n        }\n\n        case \"noIronDafny\": {\n            IronDafny = false;\n            return true;\n        }\n\n        case \"ironDafny\": {\n            IronDafny = true;\n            return true;\n        }\n\n        case \"optimizeResolution\": {\n            int d = 2;\n            if (ps.GetNumericArgument(ref d, 3)) {\n              OptimizeResolution = d;\n            }\n            return true;\n          }\n\n        case \"definiteAssignment\": {\n            int da = 0;\n            if (ps.GetNumericArgument(ref da, 4)) {\n              DefiniteAssignmentLevel = da;\n            }\n            return true;\n          }\n\n        case \"useRuntimeLib\": {\n            UseRuntimeLib = true;\n            return true;\n          }\n\n        case \"disableScopes\": {\n            DisableScopes = true;\n            return true;\n          }\n\n        case \"printIncludes\":\n          if (ps.ConfirmArgumentCount(1)) {\n            if (args[ps.i].Equals(\"None\")) {\n              PrintIncludesMode = IncludesModes.None;\n            } else if (args[ps.i].Equals(\"Immediate\")) {\n              PrintIncludesMode = IncludesModes.Immediate;\n            } else if (args[ps.i].Equals(\"Transitive\")) {\n              PrintIncludesMode = IncludesModes.Transitive;\n            } else {\n              throw new Exception(\"Invalid value for includesMode\");\n            }\n\n            if (PrintIncludesMode == IncludesModes.Immediate || PrintIncludesMode == IncludesModes.Transitive) {\n              Compile = false;\n              DafnyVerify = false;\n            }\n          }\n          return true;\n\n        default:\n          break;\n      }\n      // not a Dafny-specific option, so defer to superclass\n      return base.ParseOption(name, ps);\n    }\n\n    public override void ApplyDefaultOptions() {\n      base.ApplyDefaultOptions();\n\n      // expand macros in filenames, now that LogPrefix is fully determined\n      ExpandFilename(ref DafnyPrelude, LogPrefix, FileTimestamp);\n      ExpandFilename(ref DafnyPrintFile, LogPrefix, FileTimestamp);\n    }\n\n    public override string AttributeHelp =>\n@\"Dafny: The following attributes are supported by this implementation.\n\n    {:extern}\n    {:extern <s1:string>}\n    {:extern <s1:string>, <s2:string>}\n      NOTE: :extern is target-language dependent.\n      The extern modifier is used\n        * to alter the CompileName of entities such as modules, classes, methods, etc.,\n        * to alter the ReferenceName of the entities,\n        * to decide whether to emit target code or not, and\n        * to decide whether a declaration is allowed not to have a body.\n      The CompileName is the name for the entity when translating to one of the target languages.\n      The ReferenceName is the name used to refer to the entity in the target language.\n      A common use case of :extern is to avoid name clashes with existing library functions.\n\n      :extern takes 0, 1, or 2 (possibly empty) string arguments:\n        - 0: Dafny will use the Dafny name as the CompileName and not affect the ReferenceName\n        - 1: Dafny will use s1 as the CompileName, and replaces the last portion of the ReferenceName by s1.\n        - 2: Dafny will use s2 as the CompileName.\n             Dafny will use a combination of s1 and s2 such as for example s1.s2 as the ReferenceName\n             It may also be the case that one of the arguments is simply ignored.\n      Dafny does not perform sanity checks on the arguments---it is the user's responsibility not to generate\n      malformed target code.\n\n    {:axiom}\n      TODO\n\n    {:handle}\n      TODO\n\n\t{:dllimport}\n      TODO\n\n\t{:compile}\n      TODO\n\n\t{:main}\n      TODO\n\n\t{:axiom}\n      TODO\n\n\t{:abstemious}\n      TODO\n\n\t{:nativeType}\n      TODO\n\n\t{:tailrecursion}\n      TODO\n\n\t{:termination}\n      TODO\n\n\t{:warnShadowing}\n      TODO\n\n\t{:verify}\n      TODO\n\n\t{:autocontracts}\n      TODO\n\n\t{:opaque}\n      TODO\n\n\t{:autoReq}\n      TODO\n\n\t{:timeLimitMultiplier}\n      TODO\n\n\t{:no_inline}\n      TODO\n\n\t{:nowarn}\n      TODO\n\n\t{:autotriggers}\n      TODO\n\n\t{:trigger}\n      TODO\n\";\n\n    public override string Help =>\n      base.Help +\n@\"\n\n\n  ---- Dafny options ---------------------------------------------------------\n\n  Multiple .dfy files supplied on the command line are concatenated into one\n  Dafny program.\n\n  /dprelude:<file>\n                choose Dafny prelude file\n  /dprint:<file>\n                print Dafny program after parsing it\n                (use - as <file> to print to console)\n  /printMode:<Everything|DllEmbed|NoIncludes|NoGhost>\n                Everything is the default.\n                DllEmbed prints the source that will be included in a compiled dll.\n                NoIncludes disables printing of {:verify false} methods incorporated via the\n                include mechanism, as well as datatypes and fields included from other files.\n                NoGhost disables printing of functions, ghost methods, and proof statements in\n                implementation methods.  It also disables anything NoIncludes disables.\n  /rprint:<file>\n                print Dafny program after resolving it\n                (use - as <file> to print to console)\n  /titrace      print type-inference debug info\n  /view:<view1, view2>\n                print the filtered views of a module after it is resolved (/rprint).\n                if print before the module is resolved (/dprint), then everthing in the module is printed\n                if no view is specified, then everything in the module is printed.\n\n  /dafnyVerify:<n>\n                0 (default) - stop after typechecking\n                1 - continue on to translation, verification, and compilation\n  /compile:<n>  0 (default) - do not compile Dafny program\n                1 - upon successful verification of the Dafny\n                    program, compile Dafny program to .NET assembly\n                    Program.exe (if the program has a Main method) or\n                    Program.dll (othewise), where Program.dfy is the name\n                    of the last .dfy file on the command line\n                2 - always attempt to compile Dafny program to C# program\n                    out.cs, regardless of verification outcome\n                3 - if there is a Main method and there are no verification\n                    errors, compiles program in memory (i.e., does not write\n                    an output file) and runs it\n                4 - like (3), but attempts to compile and run regardless of\n                    verification outcome\n  /compileTarget:<lang>\n                cs (default) - Compilation to .NET via C#\n                go - Compilation to Go\n                js - Compilation to JavaScript\n                java - Compilation to Java\n                clight - Compilation to Clight\n  /compileVerbose:<n>\n                0 - don't print status of compilation to the console\n                1 (default) - print information such as files being written by\n                    the compiler to the console\n  /spillTargetCode:<n>\n                0 (default) - don't write the compiled Dafny program (but\n                    still compile it, if /compile indicates to do so)\n                1 - write the compiled Dafny program as a .cs file, if it\n                    is being compiled\n                2 - write the compiled Dafny program as a .cs file, provided\n                    it passes the verifier, regardless of /compile setting\n                3 - write the compiled Dafny program as a .cs file, regardless\n                    of verification outcome and /compile setting\n                NOTE: If there are .cs or .dll files on the command line, then\n                the compiled Dafny program will also be written. More precisely,\n                such files on the command line implies /spillTargetCode:1 (or\n                higher, if manually specified).\n  /out:<file>\n                filename and location for the generated .cs, .dll or .exe files\n  /dafnycc      Disable features not supported by DafnyCC\n  /noCheating:<n>\n                0 (default) - allow assume statements and free invariants\n                1 - treat all assumptions as asserts, and drop free.\n  /induction:<n>\n                0 - never do induction, not even when attributes request it\n                1 - only apply induction when attributes request it\n                2 - apply induction as requested (by attributes) and also\n                    for heuristically chosen quantifiers\n                3 (default) - apply induction as requested, and for\n                    heuristically chosen quantifiers and lemmas\n  /inductionHeuristic:<n>\n                0 - least discriminating induction heuristic (that is, lean\n                    toward applying induction more often)\n                1,2,3,4,5 - levels in between, ordered as follows as far as\n                    how discriminating they are:  0 < 1 < 2 < (3,4) < 5 < 6\n                6 (default) - most discriminating\n  /noIncludes   Ignore include directives\n  /noExterns    Ignore extern and dllimport attributes\n  /noNLarith    Reduce Z3's knowledge of non-linear arithmetic (*,/,%).\n                Results in more manual work, but also produces more predictable behavior.\n                (This switch will perhaps be replaced by /arith in the future.\n                For now, it takes precedence of /arith.)\n  /arith:<n>    (Experimental switch. Its options may change.)\n                0 - Use Boogie/Z3 built-ins for all arithmetic operations.\n                1 (default) - Like 0, but introduce symbolic synonyms for *,/,%, and\n                    allow these operators to be used in triggers.\n                2 - Like 1, but introduce symbolic synonyms also for +,-.\n                3 - Turn off non-linear arithmetic in the SMT solver. Still,\n                    use Boogie/Z3 built-in symbols for all arithmetic operations.\n                4 - Like 3, but introduce symbolic synonyms for *,/,%, and allow these\n                    operators to be used in triggers.\n                5 - Like 4, but introduce symbolic synonyms also for +,-.\n                6 - Like 5, and introduce axioms that distribute + over *.\n                7 - like 6, and introduce facts that associate literals arguments of *.\n                8 - Like 7, and introduce axiom for the connection between *,/,%.\n                9 - Like 8, and introduce axioms for sign of multiplication\n                10 - Like 9, and introduce axioms for commutativity and\n                    associativity of *\n  /autoReqPrint:<file>\n                Print out requirements that were automatically generated by autoReq.\n  /noAutoReq    Ignore autoReq attributes\n  /allowGlobals Allow the implicit class '_default' to contain fields, instance functions,\n                and instance methods.  These class members are declared at the module scope,\n                outside of explicit classes.  This command-line option is provided to simplify\n                a transition from the behavior in the language prior to version 1.9.3, from\n                which point onward all functions and methods declared at the module scope are\n                implicitly static and fields declarations are not allowed at the module scope.\n  /countVerificationErrors:<n>\n                0 - If preprocessing succeeds, set exit code to 0 regardless of the number\n                    of verification errors.\n                1 (default) - If preprocessing succeeds, set exit code to the number of\n                              verification errors.\n  /autoTriggers:<n>\n                0 - Do not generate {:trigger} annotations for user-level quantifiers.\n                1 (default) - Add a {:trigger} to each user-level quantifier. Existing\n                              annotations are preserved.\n  /rewriteFocalPredicates:<n>\n                0 - Don't rewrite predicates in the body of prefix lemmas.\n                1 (default) - In the body of prefix lemmas, rewrite any use of a focal predicate\n                              P to P#[_k-1].\n  /optimize     Produce optimized C# code, meaning:\n                  - selects optimized C# prelude by passing\n                    /define:DAFNY_USE_SYSTEM_COLLECTIONS_IMMUTABLE to csc.exe (requires\n                    System.Collections.Immutable.dll in the source directory to successfully\n                    compile).\n                  - passes /optimize flag to csc.exe.\n  /optimizeResolution:<n>\n                0 - Resolve and translate all methods\n                1 - Translate methods only in the call graph of current verification target\n                2 (default) - As in 1, but only resolve method bodies in non-included Dafny sources\n  /stats        Print interesting statistics about the Dafny files supplied.\n  /funcCallGraph Print out the function call graph.  Format is: func,mod=callee*\n  /warnShadowing  Emits a warning if the name of a declared variable caused another variable\n                to be shadowed\n  /definiteAssignment:<n>\n                0 - ignores definite-assignment rules; this mode is for testing only--it is\n                    not sound to be used with compilation\n                1 (default) - enforces definite-assignment rules\n                2 - enforces definite-assignment for all non-ghost non-yield-parameter\n                    variables and fields, regardless of their types\n                3 - like 2, but also performs checks in the compiler that no nondeterministic\n                    statements are used; thus, a program that passes at this level 3 is one\n                    that the language guarantees that values seen during execution will be\n                    the same in every run of the program\n  /deprecation:<n>\n                0 - don't give any warnings about deprecated features\n                1 (default) - show warnings about deprecated features\n                2 - also point out where there's new simpler syntax\n  /verifyAllModules\n                Verify modules that come from an include directive\n  /separateModuleOutput\n                Output verification results for each module separately, rather than\n                aggregating them after they are all finished.\n  /useRuntimeLib\n                Refer to pre-built DafnyRuntime.dll in compiled assembly rather\n                than including DafnyRuntime.cs verbatim.\n  /allocated:<n>\n                Specify defaults for where Dafny should assert and assume\n                allocated(x) for various parameters x, local variables x,\n                bound variables x, etc.  Lower <n> may require more manual\n                allocated(x) annotations and thus may be more difficult to use.\n                Warning: this option should be chosen consistently across\n                an entire project; it would be unsound to use different\n                defaults for different files or modules within a project.\n                And even so, modes /allocated:0 and /allocated:1 let functions\n                depend on the allocation state, which is not sound in general.\n                0 - Nowhere (never assume/assert allocated(x) by default).\n                1 - Assume allocated(x) only for non-ghost variables and fields\n                    (these assumptions are free, since non-ghost variables\n                    always contain allocated values at run-time).  This option\n                    may speed up verification relative to /allocated:2.\n                2 - Assert/assume allocated(x) on all variables,\n                    even bound variables in quantifiers.  This option is\n                    the easiest to use for heapful code.\n                3 - (default) Frugal use of heap parameters.\n                4 - mode 3 but with alloc antecedents when ranges don't imply\n                    allocatedness.\n  /ironDafny    Enable experimental features needed to support Ironclad/Ironfleet. Use of\n                these features may cause your code to become incompatible with future\n                releases of Dafny.\n  /noIronDafny  Disable Ironclad/Ironfleet features, if enabled by default.\n  /printTooltips\n                Dump additional positional information (displayed as mouse-over tooltips by\n                the VS plugin) to stdout as 'Info' messages.\n  /printIncludes:<None|Immediate|Transitive>\n                None is the default.\n                Immediate prints files included by files listed on the command line\n                Transitive recurses on the files printed by Immediate\n                Immediate and Transitive will exit after printing.\n  /disableScopes\n                Treat all export sets as 'export reveal *'. i.e. don't hide function bodies\n                or type definitions during translation.\n  /armadaPath:<dir>\n                Use <dir> as the path to the directory containing the Armada library\n                directory.  (Don't include the suffix 'Armada' in <dir>.)\n  /armadaOutputDir:<dir>\n                Write Armada output files into directory <dir> instead of into the current\n                directory.\n\";\n  }\n}\n"
  },
  {
    "path": "Source/Armada/ArmadaParser.cs",
    "content": "using System;\nusing System.Numerics;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text;\nusing System.Text.RegularExpressions;\nusing IToken = Microsoft.Boogie.IToken;\nusing Token = Microsoft.Boogie.Token;\n\nnamespace Microsoft.Armada\n{\n  public class ParseInfo\n  {\n    public Program prog;\n    public ArmadaSymbolTable symbols;\n    public MethodInfo methodInfo;\n    public ArmadaWhileStatement innermostEnclosingWhile;\n\n    public ParseInfo(Program i_prog, ArmadaSymbolTable i_symbols, MethodInfo i_methodInfo)\n    {\n      prog = i_prog;\n      symbols = i_symbols;\n      methodInfo = i_methodInfo;\n      innermostEnclosingWhile = null;\n    }\n\n    public ParseInfo Clone()\n    {\n      var other = new ParseInfo(prog, symbols, methodInfo);\n      other.innermostEnclosingWhile = this.innermostEnclosingWhile;\n      return other;\n    }\n  }\n\n  public abstract class ArmadaStatement\n  {\n    protected ParseInfo parse;\n    protected ArmadaPC startPC;\n    protected ArmadaPC endPC;\n\n    public virtual Statement Stmt { get { return null; } }\n    public ArmadaPC StartPC { get { return startPC; } }\n    public ArmadaPC EndPC { get { return endPC; } }\n\n    public ArmadaStatement(ParseInfo i_parse)\n    {\n      parse = i_parse;\n      startPC = null;\n      endPC = null;\n    }\n\n    public static ArmadaStatement ParseStatementInternal(ParseInfo parse, Statement stmt)\n    {\n      if (stmt == null)\n      {\n        return null;\n      }\n      else if (stmt is BlockStmt)\n      {\n        var s = (BlockStmt)stmt;\n        return new ArmadaBlockStatement(parse, s);\n      }\n      else if (stmt is UpdateStmt)\n      {\n        var s = (UpdateStmt)stmt;\n\n        if (s.Rhss.Count == 1) {\n          var rhs = s.Rhss[0];\n          if (rhs is ExprRhs) {\n            var ex = (ExprRhs)rhs;\n            if (ex.Expr is ApplySuffix) {\n              var suffix = (ApplySuffix)ex.Expr;\n              if (suffix.Lhs is NameSegment) {\n                var suffixName = (NameSegment)suffix.Lhs;\n                if (parse.symbols.DoesMethodNameExist(suffixName.Name)) {\n                  return new ArmadaCallStatement(parse, s, suffixName.Name);\n                }\n              }\n            }\n          }\n          else if (rhs is CreateThreadRhs) {\n            return new ArmadaCreateThreadStatement(parse, s);\n          }\n          else if (rhs is MallocRhs) {\n            return new ArmadaMallocStatement(parse, s);\n          }\n          else if (rhs is CallocRhs) {\n            return new ArmadaCallocStatement(parse, s);\n          }\n          else if (rhs is CompareAndSwapRhs) {\n            return new ArmadaCompareAndSwapStatement(parse, s);\n          }\n          else if (rhs is AtomicExchangeRhs) {\n            return new ArmadaAtomicExchangeStatement(parse, s);\n          }\n        }\n\n        return new ArmadaUpdateStatement(parse, s);\n      }\n      else if (stmt is IfStmt)\n      {\n        var s = (IfStmt)stmt;\n        return new ArmadaIfStatement(parse, s);\n      }\n      else if (stmt is WhileStmt)\n      {\n        var s = (WhileStmt)stmt;\n        parse = parse.Clone();\n        return new ArmadaWhileStatement(parse, s);\n      }\n      else if (stmt is VarDeclStmt)\n      {\n        var s = (VarDeclStmt)stmt;\n        return new ArmadaVarDeclStatement(parse, s);\n      }\n      else if (stmt is ReturnStmt)\n      {\n        var s = (ReturnStmt)stmt;\n        return new ArmadaReturnStatement(parse, s);\n      }\n      else if (stmt is AssertStmt)\n      {\n        var s = (AssertStmt)stmt;\n        return new ArmadaAssertStatement(parse, s);\n      }\n      else if (stmt is AssumeStmt)\n      {\n        var s = (AssumeStmt)stmt;\n        return new ArmadaAssumeStatement(parse, s);\n      }\n      else if (stmt is SomehowStmt)\n      {\n        var s = (SomehowStmt)stmt;\n        return new ArmadaSomehowStatement(parse, s);\n      }\n      else if (stmt is FenceStmt)\n      {\n        var s = (FenceStmt)stmt;\n        return new ArmadaFenceStatement(parse, s);\n      }\n      else if (stmt is GotoStmt)\n      {\n        var s = (GotoStmt)stmt;\n        return new ArmadaGotoStatement(parse, s);\n      }\n      else if (stmt is DeallocStmt)\n      {\n        var s = (DeallocStmt)stmt;\n        return new ArmadaDeallocStatement(parse, s);\n      }\n      else if (stmt is JoinStmt)\n      {\n        var s = (JoinStmt)stmt;\n        return new ArmadaJoinStatement(parse, s);\n      }\n      else if (stmt is BreakStmt)\n      {\n        var s = (BreakStmt)stmt;\n        if (s.TargetLabel != null) {\n          AH.PrintError(parse.prog, stmt.Tok, \"Armada doesn't support breaks with statement labels\");\n        }\n        if (s.BreakCount != 1) {\n          AH.PrintError(parse.prog, stmt.Tok, \"Armada doesn't support breaks with counts other than 1\");\n        }\n        if (parse.innermostEnclosingWhile == null) {\n          AH.PrintError(parse.prog, stmt.Tok, \"Can't have a break that isn't inside of a while loop\");\n        }\n        return new ArmadaBreakStatement(parse, s);\n      }\n      else if (stmt is ContinueStmt)\n      {\n        var s = (ContinueStmt)stmt;\n        if (parse.innermostEnclosingWhile == null) {\n          AH.PrintError(parse.prog, stmt.Tok, \"Can't have a continue that isn't inside of a while loop\");\n        }\n        return new ArmadaContinueStatement(parse, s);\n      }\n      else if (stmt is YieldStmt)\n      {\n        var s = (YieldStmt)stmt;\n        return new ArmadaYieldStatement(parse, s);\n      }\n      else\n      {\n        AH.PrintWarning(parse.prog, stmt.Tok, \"Armada doesn't yet support this statement type\");\n        return null;\n      }\n    }\n\n    public static ArmadaStatement ParseStatement(ParseInfo parse, Statement stmt)\n    {\n      if (stmt == null) {\n        return null;\n      }\n      stmt.Parsed = ParseStatementInternal(parse, stmt);\n      return stmt.Parsed;\n    }\n\n    public virtual IEnumerator<ArmadaStatement> GetEnumerator()\n    {\n      yield return this;\n    }\n\n    public virtual ArmadaPC AssignPCs(ArmadaPC i_startPC)\n    {\n      startPC = i_startPC;\n      endPC = parse.methodInfo.GenerateOnePC();\n      return endPC;\n    }\n\n    public string UpdatePC(string s, string tid, ArmadaPC newPC)\n    {\n      return $\"Armada_UpdatePC({s}, {tid}, {newPC})\";\n    }\n\n    public virtual void AssociateLabelsWithPCs()\n    {\n      Statement stmt = Stmt;\n      if (stmt != null) {\n        for (var lbl = stmt.Labels; lbl != null; lbl = lbl.Next) {\n          if (lbl.Data != null && lbl.Data.Name != null) {\n            parse.symbols.AssociateLabelWithPC(lbl.Data.Name, startPC);\n          }\n        }\n      }\n    }\n\n    public virtual void GenerateEnablingConstraints()\n    {\n    }\n\n    public virtual void GenerateNextRoutines()\n    {\n    }\n\n    public virtual void ComputeNonyieldAndYieldPCs(bool inExplicitYieldBlock, HashSet<ArmadaPC> potentiallyNonyieldingPCs,\n                                                   HashSet<ArmadaPC> yieldPCs)\n    {\n      if (inExplicitYieldBlock) {\n        potentiallyNonyieldingPCs.Add(startPC);\n      }\n    }\n\n    public static void ComputeNonyieldingPCs(ArmadaStatement stmt, HashSet<ArmadaPC> nonyieldingPCs)\n    {\n      var potentiallyNonyieldingPCs = new HashSet<ArmadaPC>();\n      var yieldPCs = new HashSet<ArmadaPC>();\n\n      stmt.ComputeNonyieldAndYieldPCs(false, potentiallyNonyieldingPCs, yieldPCs);\n\n      foreach (var pc in potentiallyNonyieldingPCs) {\n        if (!yieldPCs.Contains(pc)) {\n          nonyieldingPCs.Add(pc);\n        }\n      }\n    }\n\n    protected void GetStackFrameForCallOrCreateThread(NextRoutineConstructor next, ResolutionContext resolutionContext,\n                                                      string calleeName, IEnumerable<Expression> args, ref string s_current,\n                                                      out string new_frame, out string new_ptrs)\n    {\n      // First, allocate new pointers to represent the addressable stack variables:\n      //\n      // s_current := s.(mem := s.mem.(heap := s.mem.heap.(valid := s.mem.heap.valid + new_ptrs)))\n\n      new_ptrs = next.AddFormal(new NextFormal($\"new_ptrs_{startPC}\", \"new_ptrs\", \"set<Armada_Pointer>\"));\n\n      var mem = $\"({s_current}).mem\";\n      var h = $\"{mem}.heap\";\n      s_current = $\"({s_current}).(mem := {mem}.(heap := {h}.(valid := {h}.valid + new_ptrs)))\";\n      s_current = next.AddVariableDeclaration(\"s\", s_current);\n\n      // The new_ptrs don't overlap the previous valid pointers\n\n      next.AddDefinedBehaviorConjunct($\"new_ptrs !! {h}.valid\");\n\n      // Nothing that was freed has become valid\n\n      next.AddDefinedBehaviorConjunct($\"new_ptrs !! {h}.freed\");\n\n      var h_current = $\"{s_current}.mem.heap\";\n\n      // Next, compute the parameters to the new-frame\n      // constructor. For each input field, get its value from the\n      // arguments; for each non-input field, model its initial\n      // value as non-deterministic.\n\n      List<string> new_frame_elements = new List<string>();\n      var smst = parse.symbols.GetMethodSymbolTable(calleeName);\n      List<string> p_in_new_ptrs = new List<string>();\n      List<string> addressesOfAddressables = new List<string>();\n      var argumentEnumerator = args.GetEnumerator();\n      foreach (var v in smst.AllVariablesInOrder)\n      {\n        if (v.varType is ArmadaVarType.Input) {\n          if (!argumentEnumerator.MoveNext()) {\n            next.Fail(\"Not enough input arguments provided to method\");\n          }\n          else {\n            var arg = argumentEnumerator.Current;\n            var argVal = resolutionContext.ResolveAsRValue(arg);\n            next.AddUndefinedBehaviorAvoidanceConstraint(argVal.UndefinedBehaviorAvoidance);\n            new_frame_elements.Add(argVal.Val);\n          }\n          continue;\n        }\n\n        var varName = v.name;\n        var ty = parse.symbols.FlattenType(v.ty);\n        if (v is AddressableArmadaVariable) {\n          // For addressable variables, we have to not only add a pointer to the new-frame constructor, we also\n          // have to make sure the pointed-to values are allocated\n\n          var new_ptr = next.AddFormal(new NextFormal($\"newframe_{startPC}_{varName}\", $\"newframe_{varName}\", \"Armada_Pointer\"));\n          new_frame_elements.Add(new_ptr);\n\n          // new_ptr is among new_ptrs\n\n          next.AddDefinedBehaviorConjunct($\"{new_ptr} in new_ptrs\");\n\n          // new_ptr is in s.mem.heap.tree\n\n          var tree = $\"{h}.tree\";\n          next.AddDefinedBehaviorConjunct($\"{new_ptr} in {tree}\");\n\n          // new_ptr is a stack-based root in s.mem.heap, i.e.,\n          //    && s.mem.heap.tree[new_ptr].child_type.Armada_ChildTypeRoot?\n          //    && s.mem.heap.tree[new_ptr].child_type.rt.Armada_RootTypeStack?\n\n          next.AddDefinedBehaviorConjunct($\"{tree}[{new_ptr}].child_type.Armada_ChildTypeRoot?\");\n          next.AddDefinedBehaviorConjunct($\"{tree}[{new_ptr}].child_type.rt.Armada_RootTypeStack?\");\n\n          /*\n          if (v.ty is SizedArrayType) {\n          }\n          else {\n            p_in_new_ptrs += $\"p in {AH.GetNameOfAllocator(v.ty)}(s2.mem.heap, newframe_{varName})\";\n          }\n          */\n          var descendants = AH.GetInvocationOfDescendants(h_current, new_ptr, v.ty);\n          p_in_new_ptrs.Add($\"p in ({descendants})\");\n          addressesOfAddressables.Add(new_ptr);\n          // new_ptr is a valid pointer in s_current.mem.heap\n\n          var pointer_valid = AH.GetInvocationOfValidPointer(h_current, new_ptr, v.ty);\n          next.AddDefinedBehaviorConjunct(pointer_valid);\n        }\n        else {\n          var elt = next.AddFormal(new NextFormal($\"newframe_{startPC}_{varName}\", $\"newframe_{varName}\", ty, parse.symbols));\n          new_frame_elements.Add(elt);\n        }\n      }\n\n      if (p_in_new_ptrs.Count > 0) {\n        next.AddDefinedBehaviorConjunct($\"forall p :: p in new_ptrs <==> ({AH.CombineStringsWithOr(p_in_new_ptrs)})\");\n      }\n      else {\n        next.AddDefinedBehaviorConjunct(\"|new_ptrs| == 0\");\n      }\n\n      for (int i = 0; i < addressesOfAddressables.Count; i++) {\n        for (int j = i + 1; j < addressesOfAddressables.Count; j++) {\n          next.AddDefinedBehaviorConjunct($\"({addressesOfAddressables[i]}) != ({addressesOfAddressables[j]})\");\n        }\n      }\n\n      // new_ptrs == Armada_Allocator_type1(local1) + ...\n      // Equivalently, forall x :: x in new_ptrs <==> x in Armada_Allocator_type1(local1)\n\n      // Finally, create the frame.\n      // var new_vars := Armada_StackVars_{calleeName}(input..., output..., normal..., reads...);\n      // var new_frame := Armada_StackFrame_{calleeName}(new_vars);\n\n      var new_frame_elements_list = String.Join(\", \", new_frame_elements);\n      new_frame = $\"Armada_StackFrame_{calleeName}(Armada_StackVars_{calleeName}({new_frame_elements_list}))\";\n      new_frame = next.AddVariableDeclaration(\"new_frame\", new_frame);\n    }\n\n    protected void PerformStackFrameInitializations(NextRoutineConstructor next, string calleeName,\n                                                    string tid, ref string s_current, ArmadaPC pc)\n    {\n      var smst = parse.symbols.GetMethodSymbolTable(calleeName);\n      foreach (var v in smst.AllVariablesInOrder.Where(v => v.InitialValue != null))\n      {\n        var resolutionContext = new ResolutionContext(s_current, s_current, tid, calleeName, parse.symbols, next);\n        var ty = parse.symbols.FlattenType(v.ty);\n        var lhs = v.GetLValue(v.InitialValue.tok, resolutionContext);\n        var rhsRVal = resolutionContext.ResolveAsRValue(v.InitialValue);\n        next.AddUndefinedBehaviorAvoidanceConstraint(rhsRVal.UndefinedBehaviorAvoidance);\n        var rhs = rhsRVal.Val;\n\n        bool bypassStoreBuffers = (v is MethodStackFrameAddressableLocalArmadaVariable) &&\n                                  ((MethodStackFrameAddressableLocalArmadaVariable)v).TSOBypassingInitialization;\n\n        // var s_current := lhs.update_state(s_current, rhs);\n        s_current = bypassStoreBuffers ? lhs.UpdateTotalStateBypassingStoreBuffer(resolutionContext, next, rhs)\n                                       : lhs.UpdateTotalStateWithStoreBufferEntry(resolutionContext, next, rhs, pc);\n        s_current = next.AddVariableDeclaration(\"s\", s_current);\n      }\n    }\n\n    public virtual bool RoughlyMatches(ArmadaStatement other)\n    {\n      return false;\n    }\n\n    public virtual IEnumerable<ArmadaStatement> GetStatementsInBody()\n    {\n      yield return this;\n    }\n  }\n\n  public class ArmadaBlockStatement : ArmadaStatement\n  {\n    private BlockStmt stmt;\n    private List<ArmadaStatement> statements;\n\n    public ArmadaBlockStatement(ParseInfo i_parse, BlockStmt i_stmt) : base(i_parse)\n    {\n      stmt = i_stmt;\n      statements = stmt.Body.Select(x => ParseStatement(parse, x)).ToList();\n    }\n\n    public override Statement Stmt { get { return stmt; } }\n\n    public override IEnumerable<ArmadaStatement> GetStatementsInBody()\n    {\n      foreach (var statement in statements) {\n        foreach (var substatement in statement.GetStatementsInBody()) {\n          yield return substatement;\n        }\n      }\n    }\n\n    public override IEnumerator<ArmadaStatement> GetEnumerator()\n    {\n      yield return this;\n      foreach (var statement in statements) {\n        foreach (var substatement in statement) {\n          yield return substatement;\n        }\n      }\n    }\n\n    public override ArmadaPC AssignPCs(ArmadaPC i_startPC)\n    {\n      startPC = i_startPC;\n      var currentPC = startPC;\n      foreach (var statement in statements)\n      {\n        currentPC = statement.AssignPCs(currentPC);\n      }\n      endPC = currentPC;\n      return endPC;\n    }\n\n    public override void ComputeNonyieldAndYieldPCs(bool inExplicitYieldBlock, HashSet<ArmadaPC> potentiallyNonyieldingPCs,\n                                                    HashSet<ArmadaPC> yieldPCs)\n    {\n      if (stmt is ExplicitYieldBlockStmt && !inExplicitYieldBlock) {\n        yieldPCs.Add(startPC);\n        yieldPCs.Add(endPC);\n        inExplicitYieldBlock = true;\n      }\n\n      foreach (var statement in statements) {\n        statement.ComputeNonyieldAndYieldPCs(inExplicitYieldBlock, potentiallyNonyieldingPCs, yieldPCs);\n      }\n    }\n\n    public override void GenerateNextRoutines()\n    {\n      foreach (var statement in statements) {\n        statement.GenerateNextRoutines();\n      }\n    }\n\n    public override bool RoughlyMatches(ArmadaStatement other)\n    {\n      return other is ArmadaBlockStatement;\n    }\n  }\n\n  public class ArmadaIfStatement : ArmadaStatement\n  {\n    private IfStmt stmt;\n    private ArmadaStatement thenClause;\n    private ArmadaStatement elseClause;\n\n    public ArmadaIfStatement(ParseInfo i_parse, IfStmt i_stmt) : base(i_parse)\n    {\n      stmt = i_stmt;\n      thenClause = ParseStatement(parse, stmt.Thn);\n      elseClause = ParseStatement(parse, stmt.Els);\n    }\n\n    public override Statement Stmt { get { return stmt; } }\n\n    public ArmadaStatement ThenClause { get { return thenClause; } }\n    public ArmadaStatement ElseClause { get { return elseClause; } }\n\n    public override IEnumerator<ArmadaStatement> GetEnumerator()\n    {\n      yield return this;\n      foreach (var statement in thenClause) {\n        yield return statement;\n      }\n      if (elseClause != null) {\n        foreach (var statement in elseClause) {\n          yield return statement;\n        }\n      }\n    }\n\n    public override ArmadaPC AssignPCs(ArmadaPC i_startPC)\n    {\n      startPC = i_startPC;\n      var thenPC = parse.methodInfo.GenerateOnePC();\n      var thenEndPC = thenClause.AssignPCs(thenPC);\n      Debug.Assert(thenEndPC == thenClause.EndPC);\n\n      if (elseClause == null) {\n        endPC = thenEndPC;\n      }\n      else {\n        var elsePC = parse.methodInfo.GenerateOnePC();\n        endPC = elseClause.AssignPCs(elsePC);\n      }\n      return endPC;\n    }\n\n    public override void ComputeNonyieldAndYieldPCs(bool inExplicitYieldBlock, HashSet<ArmadaPC> potentiallyNonyieldingPCs,\n                                                    HashSet<ArmadaPC> yieldPCs)\n    {\n      if (inExplicitYieldBlock) {\n        potentiallyNonyieldingPCs.Add(startPC);\n        if (elseClause != null) {\n          potentiallyNonyieldingPCs.Add(thenClause.EndPC);\n        }\n      }\n\n      foreach (var statement in thenClause) {\n        statement.ComputeNonyieldAndYieldPCs(inExplicitYieldBlock, potentiallyNonyieldingPCs, yieldPCs);\n      }\n\n      if (elseClause != null) {\n        foreach (var statement in elseClause) {\n          statement.ComputeNonyieldAndYieldPCs(inExplicitYieldBlock, potentiallyNonyieldingPCs, yieldPCs);\n        }\n      }\n    }\n\n    public override void AssociateLabelsWithPCs()\n    {\n      base.AssociateLabelsWithPCs();\n      if (elseClause != null) {\n        parse.symbols.AssociateLabelWithPC($\"JumpPastElse_{thenClause.EndPC.Name}\", thenClause.EndPC);\n      }\n    }\n\n    public override void GenerateNextRoutines()\n    {\n      //\n      // First, we generate the next routine for evaluating the guard at\n      // startPC and going to either thenClause.StartPC or (elseClause.StartPC or thenClause.EndPC),\n      // or failing because the guard evaluation crashes.\n      //\n\n      var elsePC = stmt.Els != null ? elseClause.StartPC : thenClause.EndPC;\n      var nextThen = new NextRoutineConstructor(parse.prog, parse.symbols, NextType.IfTrue, parse.methodInfo,\n                                                this, stmt, startPC, thenClause.StartPC);\n      var nextElse = new NextRoutineConstructor(parse.prog, parse.symbols, NextType.IfFalse, parse.methodInfo,\n                                                this, stmt, startPC, elsePC);\n\n      var contextThen = new NormalResolutionContext(nextThen, parse.symbols);\n      var contextElse = new NormalResolutionContext(nextElse, parse.symbols);\n\n      if (stmt.Guard != null) { // A null guard means a non-deterministic choice, i.e., *\n        var guardRValue = contextThen.ResolveAsRValue(stmt.Guard);\n        nextThen.AddUndefinedBehaviorAvoidanceConstraint(guardRValue.UndefinedBehaviorAvoidance);\n        nextThen.AddDefinedBehaviorConjunct(guardRValue.Val);\n\n        guardRValue = contextElse.ResolveAsRValue(stmt.Guard);\n        // There's need for an \"undefined behavior\" branch of the false case, since it matches the true case.\n        nextElse.AddUBAvoidanceConstraintAsDefinedBehaviorConjunct(guardRValue.UndefinedBehaviorAvoidance);\n        nextElse.AddDefinedBehaviorConjunct($\"!({guardRValue.Val})\");\n      }\n\n      // s' == Armada_UpdatePC(s, tid, {then/else PC})\n\n      var s_then = UpdatePC(nextThen.s, nextThen.tid, thenClause.StartPC);\n      nextThen.SetNextState(s_then);\n\n      var s_else = UpdatePC(nextElse.s, nextElse.tid, elsePC);\n      nextElse.SetNextState(s_else);\n\n      parse.symbols.AddNextRoutineConstructor(nextThen);\n      parse.symbols.AddNextRoutineConstructor(nextElse);\n\n      //\n      // Second, we generate the next routines for the then clause.\n      //\n\n      thenClause.GenerateNextRoutines();\n\n      if (elseClause != null) {\n\n        //\n        // Third, if there's an else clause, we generate the next\n        // routine for jumping from thenClause.EndPC directly and\n        // unconditionally to endPC.\n        //\n\n        var next = new NextRoutineConstructor(parse.prog, parse.symbols, NextType.JumpPastElse, parse.methodInfo,\n                                              this, stmt, thenClause.EndPC, endPC);\n        var s_prime = UpdatePC(next.s, next.tid, endPC);\n        next.SetNextState(s_prime);\n        parse.symbols.AddNextRoutineConstructor(next);\n\n        //\n        // Fourth, if there's an else clause, we generate the next routines for that clause\n        //\n\n        elseClause.GenerateNextRoutines();\n      }\n    }\n\n    public override bool RoughlyMatches(ArmadaStatement other)\n    {\n      return other is ArmadaIfStatement;\n    }\n  }\n\n  public class ArmadaWhileStatement : ArmadaStatement\n  {\n    private WhileStmt stmt;\n    private ArmadaStatement body;\n\n    public ArmadaWhileStatement(ParseInfo i_parse, WhileStmt i_stmt) : base(i_parse)\n    {\n      stmt = i_stmt;\n      parse = parse.Clone();\n      parse.innermostEnclosingWhile = this;\n      body = ParseStatement(parse, stmt.Body);\n    }\n\n    public override Statement Stmt { get { return stmt; } }\n\n    public ArmadaStatement Body { get { return body; } }\n\n    public override IEnumerator<ArmadaStatement> GetEnumerator()\n    {\n      yield return this;\n      foreach (var statement in body) {\n        yield return statement;\n      }\n    }\n\n    public override ArmadaPC AssignPCs(ArmadaPC i_startPC)\n    {\n      startPC = i_startPC;\n      var loopHeadPC = parse.methodInfo.GenerateOnePC();\n      var loopEndPC = body.AssignPCs(loopHeadPC);\n      endPC = parse.methodInfo.GenerateOnePC();\n      return endPC;\n    }\n\n    public override void ComputeNonyieldAndYieldPCs(bool inExplicitYieldBlock, HashSet<ArmadaPC> potentiallyNonyieldingPCs,\n                                                    HashSet<ArmadaPC> yieldPCs)\n    {\n      if (inExplicitYieldBlock) {\n        potentiallyNonyieldingPCs.Add(startPC);\n        potentiallyNonyieldingPCs.Add(body.EndPC);\n      }\n      foreach (var statement in body) {\n        statement.ComputeNonyieldAndYieldPCs(inExplicitYieldBlock, potentiallyNonyieldingPCs, yieldPCs);\n      }\n    }\n\n    public override void AssociateLabelsWithPCs()\n    {\n      base.AssociateLabelsWithPCs();\n      parse.symbols.AssociateLabelWithPC($\"JumpBack_{body.EndPC.Name}\", body.EndPC);\n    }\n\n    public override void GenerateEnablingConstraints()\n    {\n      foreach (var inv in stmt.Invariants)\n      {\n        parse.methodInfo.AddEnablingConstraint(parse.prog, startPC, inv.E);\n      }\n    }\n\n    public override void GenerateNextRoutines()\n    {\n      // First, make a next routine for conditionally jumping from the statement beginning to either the loop head or the statement end.\n\n      var nextTrue = new NextRoutineConstructor(parse.prog, parse.symbols, NextType.WhileTrue, parse.methodInfo,\n                                                this, stmt, startPC, body.StartPC);\n      var nextFalse = new NextRoutineConstructor(parse.prog, parse.symbols, NextType.WhileFalse, parse.methodInfo,\n                                                 this, stmt, startPC, endPC);\n\n      var contextTrue = new NormalResolutionContext(nextTrue, parse.symbols);\n      var contextFalse = new NormalResolutionContext(nextFalse, parse.symbols);\n\n      if (stmt.Guard != null) { // A null guard means a non-deterministic choice, i.e., *\n        var guardRValue = contextTrue.ResolveAsRValue(stmt.Guard);\n        nextTrue.AddUndefinedBehaviorAvoidanceConstraint(guardRValue.UndefinedBehaviorAvoidance);\n        nextTrue.AddDefinedBehaviorConjunct(guardRValue.Val);\n\n        guardRValue = contextFalse.ResolveAsRValue(stmt.Guard);\n        // There's need for an \"undefined behavior\" branch of the false case, since it matches the true case.\n        nextFalse.AddUBAvoidanceConstraintAsDefinedBehaviorConjunct(guardRValue.UndefinedBehaviorAvoidance);\n        nextFalse.AddDefinedBehaviorConjunct($\"!({guardRValue.Val})\");\n      }\n\n      // s' == Armada_UpdatePC(s, tid, {head/end PC})\n\n      var s_true = UpdatePC(nextTrue.s, nextTrue.tid, body.StartPC);\n      nextTrue.SetNextState(s_true);\n      var s_false = UpdatePC(nextFalse.s, nextFalse.tid, endPC);\n      nextFalse.SetNextState(s_false);\n\n      parse.symbols.AddNextRoutineConstructor(nextTrue);\n      parse.symbols.AddNextRoutineConstructor(nextFalse);\n\n      // Second, make next routines for the body\n\n      body.GenerateNextRoutines();\n\n      // Third, make a next routine for unconditionally jumping from the loop end to the statement beginning.\n\n      var next = new NextRoutineConstructor(parse.prog, parse.symbols, NextType.WhileEnd, parse.methodInfo,\n                                            this, stmt, body.EndPC, startPC);\n      var s_with_new_PC = UpdatePC(next.s, next.tid, startPC);\n      next.SetNextState(s_with_new_PC);\n      parse.symbols.AddNextRoutineConstructor(next);\n    }\n\n    public override bool RoughlyMatches(ArmadaStatement other)\n    {\n      return other is ArmadaWhileStatement;\n    }\n  }\n\n  public class ArmadaCallStatement : ArmadaStatement\n  {\n    private UpdateStmt stmt;\n    private string calleeName;\n\n    public ArmadaCallStatement(ParseInfo i_parse, UpdateStmt i_stmt, string i_calleeName) : base(i_parse)\n    {\n      stmt = i_stmt;\n      calleeName = i_calleeName;\n    }\n\n    public override Statement Stmt { get { return stmt; } }\n\n    public string CalleeName { get {return calleeName; } }\n\n    private void GenerateCallNextRoutine()\n    {\n      //\n      // The first next routine for a call statement is the one for the call itself.\n      //\n\n      var next = new NextRoutineConstructor(parse.prog, parse.symbols, NextType.Call, parse.methodInfo,\n                                            this, stmt, startPC, new ArmadaPC(parse.symbols, calleeName, 0));\n      var resolutionContext = new NormalResolutionContext(next, parse.symbols);\n      var ex = (ExprRhs)stmt.Rhss[0];\n      var suffix = (ApplySuffix)ex.Expr;\n\n      int numArgsExpected = parse.symbols.GetNumInputVariables(calleeName);\n      if (numArgsExpected != suffix.Args.Count) {\n        next.Fail(stmt.Tok, $\"Incorrect number of arguments to {calleeName} ({suffix.Args.Count} instead of {numArgsExpected})\");\n        return;\n      }\n      int numReturnValuesExpected = parse.symbols.GetNumOutputVariables(calleeName);\n      if (numReturnValuesExpected != stmt.Lhss.Count) {\n        next.Fail(stmt.Tok,\n                  $\"Incorrect number of return values assigned from {calleeName} ({stmt.Lhss.Count} instead of {numReturnValuesExpected}\");\n        return;\n      }\n\n      // Set up the new stack frame\n\n      string s_current = next.s, new_frame, new_ptrs;\n      GetStackFrameForCallOrCreateThread(next, resolutionContext, calleeName, suffix.Args, ref s_current, out new_frame, out new_ptrs);\n\n      var newPC = new ArmadaPC(parse.symbols, calleeName, 0);\n      var t = $\"({next.t})\";\n      s_current = next.AddVariableDeclaration(\"s\", $@\"\n        ({s_current}).(threads := ({next.s}).threads[{next.tid} := Armada_Thread({newPC}, {new_frame}, {new_ptrs},\n          [Armada_ExtendedFrame({endPC}, {t}.top, {t}.new_ptrs)] + {t}.stack, {t}.storeBuffer)])\n      \");\n\n      PerformStackFrameInitializations(next, calleeName, next.tid, ref s_current, startPC);\n\n      next.SetNextState(s_current);\n\n      parse.symbols.AddNextRoutineConstructor(next);\n    }\n\n    private void GenerateReturnNextRoutines()\n    {\n      //\n      // The second type of next routine for a call statement is the one for the return from the call,\n      // including assignment of returned values.\n      //\n\n      var method = parse.methodInfo.method;\n      var calleeMethodInfo = parse.symbols.AllMethods.LookupMethod(calleeName);\n\n      var returnPC = calleeMethodInfo.ReturnPC;\n      var next = new NextRoutineConstructor(parse.prog, parse.symbols, NextType.Return, calleeMethodInfo,\n                                            this, stmt, returnPC, endPC);\n\n      var t = $\"({next.t})\";\n      var s = $\"({next.s})\";\n\n      next.AddConjunct($\"|{t}.stack| > 0\");\n      next.AddConjunct($\"{t}.stack[0].return_pc == {endPC}\");\n      next.AddConjunct($\"{t}.stack[0].frame.Armada_StackFrame_{method.Name}?\");\n\n      // First, we update the state by popping the thread's top stack frame.\n\n      var s_current = $@\"\n        {s}.(threads := {s}.threads[{next.tid} := Armada_Thread({endPC}, {t}.stack[0].frame, {t}.stack[0].new_ptrs,\n                                                                {t}.stack[1..], {t}.storeBuffer)])\n      \";\n      s_current = next.AddVariableDeclaration(\"s\", s_current);\n\n      // Now, we need to free the new_ptrs.\n\n      s = s_current;\n      s_current = $@\"\n        {s}.(mem := {s}.mem.(heap := {s}.mem.heap.(valid := {s}.mem.heap.valid - {t}.new_ptrs, freed := {s}.mem.heap.freed + {t}.new_ptrs)))\n      \";\n      s_current = next.AddVariableDeclaration(\"s\", s_current);\n\n      // We need a context to compute the values of returned values, a callee_context.\n\n      var callee_context = new NormalResolutionContext(next, parse.symbols);\n\n      // When computing caller contexts (for use in computing lvalues to use for storing return values), we'll need to\n      // know the state of various objects as they appear right after popping the stack frame.  So, compute those now.\n\n      var state_after_pop = s_current;\n      var ghosts_after_pop = $\"{s_current}.ghosts\";\n      var top_after_pop = $\"{s_current}.threads[{next.tid}].top\";\n\n      int numReturnValuesExpected = parse.symbols.GetNumOutputVariables(calleeName);\n      for (int i = 0; i < numReturnValuesExpected; ++i) {\n        // We need a context for the caller to use when computing lvalues to use for storing return\n        // values into local variables.  The hard part of this is computing the local view of the\n        // state.  A shortcut to this is to observe that the local view of the state doesn't change\n        // due to a pop, so we can just use next.locv.\n\n        var caller_context = new CustomResolutionContext(s_current, state_after_pop, next.locv, top_after_pop,\n                                                         ghosts_after_pop, next.tid, method.Name, parse.symbols, next);\n\n        var av = parse.symbols.GetOutputVariableByIndex(calleeName, i);\n        var rhs = av.GetRValue(Token.NoToken, callee_context);\n        next.AddUndefinedBehaviorAvoidanceConstraint(rhs.UndefinedBehaviorAvoidance);\n        var lhs = stmt.Lhss.ElementAt(i);\n        var newLhs = caller_context.ResolveAsLValue(lhs);\n        if (!(newLhs is ArmadaLValue)) {\n          next.Fail(lhs.tok, \"Left-hand side is not a valid lvalue\");\n          return;\n        }\n        next.AddUndefinedBehaviorAvoidanceConstraint(newLhs.GetUndefinedBehaviorAvoidanceConstraint());\n\n        s_current = stmt.BypassStoreBuffers ?\n          newLhs.UpdateTotalStateBypassingStoreBuffer(caller_context, next, rhs.Val) :\n          newLhs.UpdateTotalStateWithStoreBufferEntry(caller_context, next, rhs.Val, returnPC);\n        s_current = next.AddVariableDeclaration(\"s\", s_current);\n      }\n\n      next.SetNextState(s_current);\n      parse.symbols.AddNextRoutineConstructor(next);\n    }\n\n    public override void GenerateNextRoutines()\n    {\n      GenerateCallNextRoutine();\n      GenerateReturnNextRoutines();\n    }\n\n    public override bool RoughlyMatches(ArmadaStatement other)\n    {\n      if (other is ArmadaCallStatement acs) {\n        return calleeName == acs.CalleeName;\n      }\n      else {\n        return false;\n      }\n    }\n  }\n\n  public class ArmadaCreateThreadStatement : ArmadaStatement\n  {\n    private UpdateStmt stmt;\n\n    public ArmadaCreateThreadStatement(ParseInfo i_parse, UpdateStmt i_stmt) : base(i_parse)\n    {\n      stmt = i_stmt;\n    }\n\n    public override Statement Stmt { get { return stmt; } }\n\n    public override void GenerateNextRoutines()\n    {\n      if (stmt.Lhss.Count > 1) {\n        AH.PrintError(parse.prog, stmt.Tok,\n                      $\"Number of left-hand sides for create_thread must be 0 or 1, since the only thing returned is a thread handle\");\n        return;\n      }\n\n      var rhs = (CreateThreadRhs)stmt.Rhss[0];\n      var calleeName = rhs.MethodName.val;\n\n      if (!parse.symbols.DoesMethodNameExist(calleeName)) {\n        AH.PrintError(parse.prog, stmt.Tok, $\"Call to create_thread on non-existent method {calleeName}\");\n        return;\n      }\n\n      if (calleeName.Equals(\"main\")) {\n        AH.PrintError(parse.prog, stmt.Tok, $\"It's illegal to create a thread using main as the routine\");\n        return;\n      }\n\n      parse.symbols.UseMethodAsThreadRoutine(calleeName);\n\n      int numInputs = parse.symbols.GetNumInputVariables(calleeName);\n      if (numInputs != rhs.Args.Count) {\n        AH.PrintError(parse.prog, stmt.Tok,\n                      $\"Call to create_thread has {rhs.Args.Count} input variables but {calleeName} takes {numInputs} input parameters\");\n        return;\n      }\n\n      var next = new NextRoutineConstructor(parse.prog, parse.symbols, NextType.CreateThread, parse.methodInfo,\n                                            this, stmt, startPC, endPC);\n      var resolutionContext = new NormalResolutionContext(next, parse.symbols);\n\n      var new_tid = next.AddFormal(new NextFormal($\"newtid_{startPC}\", \"newtid\", \"Armada_ThreadHandle\"));\n      var s = $\"({next.s})\";\n\n      next.AddConjunct($\"{new_tid} !in {s}.threads\");\n      next.AddConjunct($\"{new_tid} !in {s}.joinable_tids\");\n      next.AddConjunct($\"{new_tid} != 0\");\n\n      // Set up the new stack frame\n\n      string s_current = next.s, new_frame, new_ptrs;\n      GetStackFrameForCallOrCreateThread(next, resolutionContext, calleeName, rhs.Args, ref s_current, out new_frame, out new_ptrs);\n\n      var calleePC = new ArmadaPC(parse.symbols, calleeName, 0);\n      s_current = $@\"\n        ({s_current}).(threads := s.threads[{new_tid} := Armada_Thread({calleePC}, {new_frame}, {new_ptrs}, [], [])])\n      \";\n      s_current = next.AddVariableDeclaration(\"s\", s_current);\n\n      PerformStackFrameInitializations(next, calleeName, new_tid, ref s_current, startPC);\n\n      // s_current := Armada_UpdatePC(s_current, next.tid, endPC);\n\n      s_current = UpdatePC(s_current, next.tid, endPC);\n      s_current = next.AddVariableDeclaration(\"s\", s_current);\n\n      // If there's a return value, set it to new_tid\n\n      if (stmt.Lhss.Count > 0) {\n        var current_context = new NormalResolutionContext(s_current, next, parse.symbols);\n        var lhs = stmt.Lhss[0];\n        var newLhs = current_context.ResolveAsLValue(lhs);\n        if (!(newLhs is ArmadaLValue)) {\n          next.Fail(lhs.tok, \"Where to store the returned thread handle from create_thread is not a valid lvalue\");\n          return;\n        }\n        next.AddUndefinedBehaviorAvoidanceConstraint(newLhs.GetUndefinedBehaviorAvoidanceConstraint());\n\n        // var s_current := lhs.update_state(s_current, new_tid);\n        s_current = stmt.BypassStoreBuffers ? newLhs.UpdateTotalStateBypassingStoreBuffer(current_context, next, new_tid)\n                                            : newLhs.UpdateTotalStateWithStoreBufferEntry(current_context, next, new_tid, startPC);\n        s_current = next.AddVariableDeclaration(\"s\", s_current);\n      }\n\n      next.SetNextState(s_current);\n\n      // We're done creating the next routine, so add it to the list\n\n      parse.symbols.AddNextRoutineConstructor(next);\n    }\n\n    public override bool RoughlyMatches(ArmadaStatement other)\n    {\n      if (other is ArmadaCreateThreadStatement) {\n        return ((CreateThreadRhs)stmt.Rhss[0]).MethodName.val == ((CreateThreadRhs)((UpdateStmt)other.Stmt).Rhss[0]).MethodName.val;\n      }\n      else {\n        return false;\n      }\n    }\n  }\n\n  public class ArmadaMallocStatement : ArmadaStatement\n  {\n    private UpdateStmt stmt;\n\n    public ArmadaMallocStatement(ParseInfo i_parse, UpdateStmt i_stmt) : base(i_parse)\n    {\n      stmt = i_stmt;\n    }\n\n    public override Statement Stmt { get { return stmt; } }\n\n    public override void GenerateNextRoutines()\n    {\n      if (stmt.Lhss.Count != 1) {\n        AH.PrintError(parse.prog, stmt.Tok, $\"Number of left-hand sides for malloc must be 1\");\n        return;\n      }\n\n      var lhs = stmt.Lhss[0];\n      if (!(lhs.Type is PointerType)) {\n        AH.PrintError(parse.prog, stmt.Tok, $\"Result of malloc must be stored in a ptr\");\n        return;\n      }\n\n      var rhs = (MallocRhs)stmt.Rhss[0];\n      var lhsPointerType = (PointerType)lhs.Type;\n      if (!lhsPointerType.Arg.Equals(rhs.AllocatedType)) {\n        AH.PrintError(parse.prog, stmt.Tok, $\"Result of malloc must be stored in a ptr<{rhs.AllocatedType}>\");\n        return;\n      }\n\n      // First, create a next routine for the case where malloc succeeds.\n\n      var next = new NextRoutineConstructor(parse.prog, parse.symbols, NextType.MallocSuccess, parse.methodInfo,\n                                            this, stmt, startPC, endPC);\n\n      var s = $\"({next.s})\";\n      var h = $\"{s}.mem.heap\";\n      var tree = $\"{h}.tree\";\n\n      var new_ptr = next.AddFormal(new NextFormal($\"new_ptr_{startPC}\", \"new_ptr\", \"Armada_Pointer\"));\n      var new_ptrs = next.AddFormal(new NextFormal($\"new_ptrs_{startPC}\", \"new_ptrs\", \"set<Armada_Pointer>\"));\n\n      // new_ptr != 0\n      // new_ptr in new_ptrs\n      // new_ptrs == Armada_Allocator_{ty}(new_ptr)\n      // new_ptr is in s.mem.heap.tree\n      // new_ptr is a root in s.mem.heap, i.e., s.mem.heap.tree[new_ptr].child_type.Armada_ChildTypeRoot?\n      // new_ptr is a dynamic-heap root, i.e., s.mem.heap.tree[new_ptr].child_type.rt.Armada_RootTypeDynamicHeap?\n      // The new_ptrs don't overlap the previous valid pointers, i.e., new_ptrs !! s.mem.heap.valid\n      // Nothing that was freed has become valid, i.e., new_ptrs !! s.mem.heap.freed\n\n      next.AddDefinedBehaviorConjunct($\"{new_ptr} != 0\");\n      next.AddDefinedBehaviorConjunct($\"{new_ptr} in {new_ptrs}\");\n      next.AddDefinedBehaviorConjunct(AH.GetInvocationOfValidPointer(h, new_ptr, rhs.AllocatedType));\n      next.AddDefinedBehaviorConjunct($\"{new_ptr} in {tree}\");\n      next.AddDefinedBehaviorConjunct($\"{tree}[{new_ptr}].child_type.Armada_ChildTypeRoot?\");\n      next.AddDefinedBehaviorConjunct($\"{tree}[{new_ptr}].child_type.rt.Armada_RootTypeDynamicHeap?\");\n      next.AddDefinedBehaviorConjunct($\"{new_ptrs} !! {h}.valid\");\n      next.AddDefinedBehaviorConjunct($\"{new_ptrs} !! {h}.freed\");\n\n      // s_current := s.(mem := s.mem.(heap := s.mem.heap.(valid := s.mem.heap.valid + new_ptrs)))\n\n      var s_current = $\"{s}.(mem := {s}.mem.(heap := {s}.mem.heap.(valid := {s}.mem.heap.valid + {new_ptrs})))\";\n      s_current = next.AddVariableDeclaration(\"s\", s_current);\n\n      // new_ptr is a valid pointer in s_current.mem.heap\n\n      var h_current = $\"{s_current}.mem.heap\";\n      next.AddDefinedBehaviorConjunct(AH.GetInvocationOfValidPointer(h_current, new_ptr, rhs.AllocatedType));\n\n      var descendants = AH.GetInvocationOfDescendants(h_current, new_ptr, rhs.AllocatedType);\n      next.AddDefinedBehaviorConjunct($\"(forall p :: p in {new_ptrs} <==> p in {descendants})\");\n\n      // s_current := lhs.update_state(s_current, new_ptr);\n\n      var current_context = new NormalResolutionContext(s_current, next, parse.symbols);\n      var newLhs = current_context.ResolveAsLValue(lhs);\n      if (!(newLhs is ArmadaLValue)) {\n        next.Fail(lhs.tok, \"Left-hand side is not a valid lvalue\");\n        return;\n      }\n      next.AddUndefinedBehaviorAvoidanceConstraint(newLhs.GetUndefinedBehaviorAvoidanceConstraint());\n\n      s_current = stmt.BypassStoreBuffers ? newLhs.UpdateTotalStateBypassingStoreBuffer(current_context, next, new_ptr)\n                                          : newLhs.UpdateTotalStateWithStoreBufferEntry(current_context, next, new_ptr, startPC);\n      s_current = next.AddVariableDeclaration(\"s\", s_current);\n\n      // s_current := Armada_UpdatePC(s, tid, {end PC})\n\n      s_current = UpdatePC(s_current, next.tid, endPC);\n      s_current = next.AddVariableDeclaration(\"s\", s_current);\n\n      next.SetNextState(s_current);\n\n      // The next predicate is built, so add it to the list of next predicates.\n\n      parse.symbols.AddNextRoutineConstructor(next);\n\n      //////////////////////////////////////////////////////////////////////////////\n      // Now, create a next routine for the case where malloc fails.\n      //////////////////////////////////////////////////////////////////////////////\n\n      next = new NextRoutineConstructor(parse.prog, parse.symbols, NextType.MallocFailure, parse.methodInfo,\n                                        this, stmt, startPC, endPC);\n      current_context = new NormalResolutionContext(next.s, next, parse.symbols);\n\n      // s_current := lhs.update_state(s_current, new_ptr);\n\n      newLhs = current_context.ResolveAsLValue(lhs);\n      if (!(newLhs is ArmadaLValue)) {\n        next.Fail(lhs.tok, \"Left-hand side is not a valid lvalue\");\n        return;\n      }\n      next.AddUndefinedBehaviorAvoidanceConstraint(newLhs.GetUndefinedBehaviorAvoidanceConstraint());\n      s_current = stmt.BypassStoreBuffers ? newLhs.UpdateTotalStateBypassingStoreBuffer(current_context, next, \"0\")\n                                          : newLhs.UpdateTotalStateWithStoreBufferEntry(current_context, next, \"0\", startPC);\n      s_current = next.AddVariableDeclaration(\"s\", s_current);\n\n      // s_current := Armada_UpdatePC(s, tid, {end PC})\n\n      s_current = UpdatePC(s_current, next.tid, endPC);\n      s_current = next.AddVariableDeclaration(\"s\", s_current);\n\n      next.SetNextState(s_current);\n\n      // The next predicate is built, so add it to the list of next predicates.\n\n      parse.symbols.AddNextRoutineConstructor(next);\n    }\n\n    public override bool RoughlyMatches(ArmadaStatement other)\n    {\n      if (other is ArmadaMallocStatement ams) {\n        return AH.TypesMatch(((MallocRhs)stmt.Rhss[0]).AllocatedType, ((MallocRhs)((UpdateStmt)ams.Stmt).Rhss[0]).AllocatedType);\n      }\n      else {\n        return false;\n      }\n    }\n  }\n\n  public class ArmadaCallocStatement : ArmadaStatement\n  {\n    private UpdateStmt stmt;\n\n    public ArmadaCallocStatement(ParseInfo i_parse, UpdateStmt i_stmt) : base(i_parse)\n    {\n      stmt = i_stmt;\n    }\n\n    public override Statement Stmt { get { return stmt; } }\n\n    public override void GenerateNextRoutines()\n    {\n      if (stmt.Lhss.Count != 1) {\n        AH.PrintError(parse.prog, stmt.Tok, $\"Number of left-hand sides for calloc must be 1\");\n        return;\n      }\n\n      var lhs = stmt.Lhss[0];\n      if (!(lhs.Type is PointerType)) {\n        AH.PrintError(parse.prog, stmt.Tok, $\"Result of calloc must be stored in a ptr\");\n        return;\n      }\n\n      var rhs = (CallocRhs)stmt.Rhss[0];\n      var lhsPointerType = (PointerType)lhs.Type;\n      if (!lhsPointerType.Arg.Equals(rhs.AllocatedType)) {\n        AH.PrintError(parse.prog, stmt.Tok, $\"Result of calloc must be stored in a ptr<{rhs.AllocatedType}>\");\n        return;\n      }\n\n      // First, create a next routine for the case where calloc succeeds.\n\n      var next = new NextRoutineConstructor(parse.prog, parse.symbols, NextType.CallocSuccess, parse.methodInfo,\n                                            this, stmt, startPC, endPC);\n      var resolutionContext = new NormalResolutionContext(next, parse.symbols);\n\n      var countRValue = resolutionContext.ResolveAsRValue(rhs.Count);\n      next.AddUndefinedBehaviorAvoidanceConstraint(countRValue.UndefinedBehaviorAvoidance);\n      var count = $\"({countRValue.Val}) as int\";\n\n      var s = $\"({next.s})\";\n      var h = $\"{s}.mem.heap\";\n      var tree = $\"{h}.tree\";\n\n      var new_ptr = next.AddFormal(new NextFormal($\"new_ptr_{startPC}\", \"new_ptr\", \"Armada_Pointer\"));\n      var new_ptrs = next.AddFormal(new NextFormal($\"new_ptrs_{startPC}\", \"new_ptrs\", \"set<Armada_Pointer>\"));\n\n      // new_ptr != 0\n      // new_ptr in new_ptrs\n      // new_ptr is in s.mem.heap.tree\n      // new_ptr is a root in s.mem.heap, i.e., s.mem.heap.tree[new_ptr].child_type.Armada_ChildTypeRoot?\n      // new_ptr is a dynamic-heap root, i.e., s.mem.heap.tree[new_ptr].child_type.rt.Armada_RootTypeDynamicHeap?\n      // The new_ptrs don't overlap the previous valid pointers, i.e., new_ptrs !! s.mem.heap.valid\n      // Nothing that was freed has become valid, i.e., new_ptrs !! s.mem.heap.freed\n\n      next.AddDefinedBehaviorConjunct($\"{new_ptr} != 0\");\n      next.AddDefinedBehaviorConjunct($\"{new_ptr} in {new_ptrs}\");\n      next.AddDefinedBehaviorConjunct($\"{new_ptr} in {tree}\");\n      next.AddDefinedBehaviorConjunct($\"{tree}[{new_ptr}].child_type.Armada_ChildTypeRoot?\");\n      next.AddDefinedBehaviorConjunct($\"{tree}[{new_ptr}].child_type.rt.Armada_RootTypeDynamicHeap?\");\n      next.AddDefinedBehaviorConjunct($\"{new_ptrs} !! {h}.valid\");\n      next.AddDefinedBehaviorConjunct($\"{new_ptrs} !! {h}.freed\");\n\n      // We model it as undefined behavior if a non-positive number was passed as the count.\n      // The reason we don't allow allocation of a 0-size array is as follows.  What we return\n      // is a pointer to the 0th element, and there is no 0th element to return if we allocate\n      // an array of size 0.\n\n      next.AddUndefinedBehaviorAvoidanceConstraint($\"({count}) > 0\");\n\n      var s_current = $\"{s}.(mem := {s}.mem.(heap := {s}.mem.heap.(valid := {s}.mem.heap.valid + {new_ptrs})))\";\n      s_current = next.AddVariableDeclaration(\"s\", s_current);\n\n      // new_ptr is a valid pointer in s_current.mem.heap to a SizedArrayType.\n\n      var h_current = $\"{s_current}.mem.heap\";\n      next.AddDefinedBehaviorConjunct(AH.GetInvocationOfValidPointerToDynamicArray(h_current, new_ptr, rhs.AllocatedType, count));\n\n      var descendants = AH.GetInvocationOfDescendantsOfDynamicArray(h_current, new_ptr, rhs.AllocatedType, count);\n      next.AddDefinedBehaviorConjunct($\"(forall p :: p in new_ptrs <==> p in ({descendants}))\");\n\n      // There's a difference in Armada between a pointer to an array and the pointer to its 0th element.\n      // (The former is just a proof construct in the case of a calloc.)  So we need to get a pointer to\n      // the 0th element to store in the left-hand side.\n\n      var child = $\"{tree}[{new_ptr}].children[0]\";\n\n      // s_current := lhs.update_state(s_current, child);\n\n      var current_context = new NormalResolutionContext(s_current, next, parse.symbols);\n      var newLhs = current_context.ResolveAsLValue(lhs);\n      if (!(newLhs is ArmadaLValue)) {\n        next.Fail(lhs.tok, \"Left-hand side is not a valid lvalue\");\n        return;\n      }\n      next.AddUndefinedBehaviorAvoidanceConstraint(newLhs.GetUndefinedBehaviorAvoidanceConstraint());\n\n      s_current = stmt.BypassStoreBuffers ? newLhs.UpdateTotalStateBypassingStoreBuffer(current_context, next, child)\n                                          : newLhs.UpdateTotalStateWithStoreBufferEntry(current_context, next, child, startPC);\n      s_current = next.AddVariableDeclaration(\"s\", s_current);\n\n      // s_current := Armada_UpdatePC(s, tid, {end PC})\n\n      s_current = UpdatePC(s_current, next.tid, endPC);\n      s_current = next.AddVariableDeclaration(\"s\", s_current);\n\n      next.SetNextState(s_current);\n\n      // The next predicate is built, so add it to the list of next predicates.\n\n      parse.symbols.AddNextRoutineConstructor(next);\n\n      //////////////////////////////////////////////////////////////////////////////\n      // Now, create a next routine for the case where calloc fails.\n      //////////////////////////////////////////////////////////////////////////////\n\n      next = new NextRoutineConstructor(parse.prog, parse.symbols, NextType.CallocFailure, parse.methodInfo,\n                                        this, stmt, startPC, endPC);\n      current_context = new NormalResolutionContext(next.s, next, parse.symbols);\n\n      // s_current := lhs.update_state(s_current, new_ptr);\n\n      newLhs = current_context.ResolveAsLValue(lhs);\n      if (!(newLhs is ArmadaLValue)) {\n        next.Fail(lhs.tok, \"Left-hand side is not a valid lvalue\");\n        return;\n      }\n      next.AddUndefinedBehaviorAvoidanceConstraint(newLhs.GetUndefinedBehaviorAvoidanceConstraint());\n      s_current = stmt.BypassStoreBuffers ? newLhs.UpdateTotalStateBypassingStoreBuffer(current_context, next, \"0\")\n                                          : newLhs.UpdateTotalStateWithStoreBufferEntry(current_context, next, \"0\", startPC);\n      s_current = next.AddVariableDeclaration(\"s\", s_current);\n\n      // s_current := Armada_UpdatePC(s, tid, {end PC})\n\n      s_current = UpdatePC(s_current, next.tid, endPC);\n      s_current = next.AddVariableDeclaration(\"s\", s_current);\n\n      next.SetNextState(s_current);\n\n      // The next predicate is built, so add it to the list of next predicates.\n\n      parse.symbols.AddNextRoutineConstructor(next);\n    }\n\n    public override bool RoughlyMatches(ArmadaStatement other)\n    {\n      if (other is ArmadaCallocStatement ams) {\n        return AH.TypesMatch(((CallocRhs)stmt.Rhss[0]).AllocatedType, ((CallocRhs)((UpdateStmt)ams.Stmt).Rhss[0]).AllocatedType);\n      }\n      else {\n        return false;\n      }\n    }\n  }\n\n  public class ArmadaCompareAndSwapStatement : ArmadaStatement\n  {\n    private UpdateStmt stmt;\n\n    public ArmadaCompareAndSwapStatement(ParseInfo i_parse, UpdateStmt i_stmt) : base(i_parse)\n    {\n      stmt = i_stmt;\n    }\n\n    public override Statement Stmt { get { return stmt; } }\n\n    public override void GenerateNextRoutines()\n    {\n      if (stmt.Lhss.Count > 1) {\n        AH.PrintError(parse.prog, stmt.Tok, $\"Number of left-hand sides for compare-and-swap must be 1\");\n        return;\n      }\n\n      var rhs = (CompareAndSwapRhs)stmt.Rhss[0];\n      var target = rhs.Target;\n      var oldval = rhs.OldVal;\n      var newval = rhs.NewVal;\n\n      if (!AH.TypesMatch(target.Type, oldval.Type)) {\n        AH.PrintError(parse.prog, stmt.Tok, $\"The target has type {target.Type} but the comparison value is of type {oldval.Type}\");\n        return;\n      }\n      if (!AH.TypesMatch(target.Type, newval.Type)) {\n        AH.PrintError(parse.prog, stmt.Tok, $\"The target has type {target.Type} but the new value is of type {newval.Type}\");\n        return;\n      }\n\n      var next = new NextRoutineConstructor(parse.prog, parse.symbols, NextType.CompareAndSwap, parse.methodInfo,\n                                            this, stmt, startPC, endPC);\n\n      // Compare-and-swap is a locked routine, so it implies a fence.\n      // So, add the constraint |s.threads[tid].storeBuffer| == 0.\n\n      next.AddConjunct($\"|({next.t}).storeBuffer| == 0\");\n\n      // Add undefined-behavior constraints for evaluating the parameters to compare_and_swap.\n      // Use a TSO-bypassing context for all the rvalues since they use the global view of memory.\n      // (It is a LOCK'd instruction, after all, so the store buffer is empty.)\n\n      var resolutionContext = new NormalResolutionContext(next, parse.symbols);\n      var tsoBypassingContext = new TSOBypassingResolutionContext(next, parse.symbols);\n      var targetLValue = resolutionContext.ResolveAsLValue(target);\n      next.AddUndefinedBehaviorAvoidanceConstraint(targetLValue.GetUndefinedBehaviorAvoidanceConstraint());\n      var targetRValue = tsoBypassingContext.ResolveAsRValue(target);\n      next.AddUndefinedBehaviorAvoidanceConstraint(targetRValue.UndefinedBehaviorAvoidance);\n      var oldRValue = tsoBypassingContext.ResolveAsRValue(oldval);\n      next.AddUndefinedBehaviorAvoidanceConstraint(oldRValue.UndefinedBehaviorAvoidance);\n      var newRValue = tsoBypassingContext.ResolveAsRValue(newval);\n      next.AddUndefinedBehaviorAvoidanceConstraint(newRValue.UndefinedBehaviorAvoidance);\n\n      // s_current := if target == oldval then <update state setting target to newval> else next.s;\n\n      var targetMatchesOld = next.AddVariableDeclaration(\"m\", $\"({targetRValue.Val}) == ({oldRValue.Val})\");\n      var s_after_value_update = targetLValue.UpdateTotalStateBypassingStoreBuffer(resolutionContext, next, newRValue.Val);\n      var s_current = $\"if {targetMatchesOld} then {s_after_value_update} else {next.s}\";\n      s_current = next.AddVariableDeclaration(\"s\", s_current);\n\n      // If there's an LHS, then:\n      // s_current := oldval\n\n      if (stmt.Lhss.Count > 0) {\n        var lhs = stmt.Lhss[0];\n        if (!AH.TypesMatch(target.Type, lhs.Type)) {\n          AH.PrintError(parse.prog, stmt.Tok, $\"The target has type {target.Type} but the left hand side is of type {lhs.Type}\");\n          return;\n        }\n        ResolutionContext updated_context = new NormalResolutionContext(s_current, next, parse.symbols);\n        var lhsLValue = updated_context.ResolveAsLValue(lhs);\n        if (lhsLValue.IsHeap()) {\n          AH.PrintError(parse.prog, stmt.Tok, $\"The result of an atomic-exchange instruction may not be stored in a shared heap variable; it must be stored in a local variable.\");\n          return;\n        }\n        next.AddUndefinedBehaviorAvoidanceConstraint(lhsLValue.GetUndefinedBehaviorAvoidanceConstraint());\n        s_current = lhsLValue.UpdateTotalStateBypassingStoreBuffer(updated_context, next, targetRValue.Val);\n        s_current = next.AddVariableDeclaration(\"s\", s_current);\n      }\n\n      // s_current := Armada_UpdatePC(s_current, tid, {end PC})\n\n      s_current = UpdatePC(s_current, next.tid, endPC);\n      s_current = next.AddVariableDeclaration(\"s\", s_current);\n\n      next.SetNextState(s_current);\n\n      // The next predicate is built, so add it to the list of next predicates.\n\n      parse.symbols.AddNextRoutineConstructor(next);\n    }\n\n    public override bool RoughlyMatches(ArmadaStatement other)\n    {\n      return other is ArmadaCompareAndSwapStatement;\n    }\n  }\n\n  public class ArmadaAtomicExchangeStatement : ArmadaStatement\n  {\n    private UpdateStmt stmt;\n\n    public ArmadaAtomicExchangeStatement(ParseInfo i_parse, UpdateStmt i_stmt) : base(i_parse)\n    {\n      stmt = i_stmt;\n    }\n\n    public override Statement Stmt { get { return stmt; } }\n\n    public override void GenerateNextRoutines()\n    {\n      if (stmt.Lhss.Count > 1) {\n        AH.PrintError(parse.prog, stmt.Tok, $\"Number of left-hand sides for atomic-exchange must be 1\");\n        return;\n      }\n\n      var rhs = (AtomicExchangeRhs)stmt.Rhss[0];\n      var target = rhs.Target;\n      var newval = rhs.NewVal;\n\n      if (!AH.TypesMatch(target.Type, newval.Type)) {\n        AH.PrintError(parse.prog, stmt.Tok, $\"The target has type {target.Type} but the new value is of type {newval.Type}\");\n        return;\n      }\n\n      var next = new NextRoutineConstructor(parse.prog, parse.symbols, NextType.AtomicExchange, parse.methodInfo,\n                                            this, stmt, startPC, endPC);\n\n      // atomic exchange is a locked routine, so it implies a fence.\n      // So, add the constraint |s.threads[tid].storeBuffer| == 0.\n\n      next.AddConjunct($\"|({next.t}).storeBuffer| == 0\");\n\n      // Add undefined-behavior constraints for evaluating the parameters to atomic_exchange.\n      // Use a TSO-bypassing context for all the rvalues since they use the global view of memory.\n      // (It is a LOCK'd instruction, after all, so the store buffer is empty.)\n\n      var resolutionContext = new NormalResolutionContext(next, parse.symbols);\n      var tsoBypassingContext = new TSOBypassingResolutionContext(next, parse.symbols);\n      var targetLValue = resolutionContext.ResolveAsLValue(target);\n      next.AddUndefinedBehaviorAvoidanceConstraint(targetLValue.GetUndefinedBehaviorAvoidanceConstraint());\n      var targetRValue = tsoBypassingContext.ResolveAsRValue(target);\n      next.AddUndefinedBehaviorAvoidanceConstraint(targetRValue.UndefinedBehaviorAvoidance);\n      var newRValue = tsoBypassingContext.ResolveAsRValue(newval);\n      next.AddUndefinedBehaviorAvoidanceConstraint(newRValue.UndefinedBehaviorAvoidance);\n\n      // s_current := update state setting target to newval;\n\n      var s_current = targetLValue.UpdateTotalStateBypassingStoreBuffer(resolutionContext, next, newRValue.Val);\n      s_current = next.AddVariableDeclaration(\"s\", s_current);\n\n      // If there's an LHS, then:\n      // s_current := <update state setting lhs to old value of target>\n\n      if (stmt.Lhss.Count > 0) {\n        var lhs = stmt.Lhss[0];\n        if (!AH.TypesMatch(target.Type, lhs.Type)) {\n          AH.PrintError(parse.prog, stmt.Tok, $\"The target has type {target.Type} but the left hand side is of type {lhs.Type}\");\n          return;\n        }\n        ResolutionContext updated_context = new NormalResolutionContext(s_current, next, parse.symbols);\n        var lhsLValue = updated_context.ResolveAsLValue(lhs);\n        if (lhsLValue.IsHeap()) {\n          AH.PrintError(parse.prog, stmt.Tok,\n                        $\"The result of an atomic-exchange instruction may not be stored in a shared heap variable; it must be stored in a local variable.\");\n          return;\n        }\n        next.AddUndefinedBehaviorAvoidanceConstraint(lhsLValue.GetUndefinedBehaviorAvoidanceConstraint());\n        s_current = lhsLValue.UpdateTotalStateBypassingStoreBuffer(updated_context, next, targetRValue.Val);\n        s_current = next.AddVariableDeclaration(\"s\", s_current);\n      }\n\n      // s_current := Armada_UpdatePC(s_current, tid, {end PC})\n\n      s_current = UpdatePC(s_current, next.tid, endPC);\n      s_current = next.AddVariableDeclaration(\"s\", s_current);\n\n      next.SetNextState(s_current);\n\n      // The next predicate is built, so add it to the list of next predicates.\n\n      parse.symbols.AddNextRoutineConstructor(next);\n    }\n\n    public override bool RoughlyMatches(ArmadaStatement other)\n    {\n      return other is ArmadaAtomicExchangeStatement;\n    }\n  }\n\n  public class ArmadaUpdateStatement : ArmadaStatement\n  {\n    private UpdateStmt stmt;\n    private bool genuineTSO;\n\n    public ArmadaUpdateStatement(ParseInfo i_parse, UpdateStmt i_stmt) : base(i_parse)\n    {\n      stmt = i_stmt;\n      genuineTSO = ! i_stmt.BypassStoreBuffers;\n    }\n\n    public override Statement Stmt { get { return stmt; } }\n\n    public bool GenuineTSO { get { return genuineTSO; } }\n\n    public override void GenerateNextRoutines()\n    {\n      if (stmt.Lhss.Count != stmt.Rhss.Count) {\n        AH.PrintError(parse.prog, stmt.Tok, $\"Number of left-hand sides for assignment ({stmt.Lhss.Count}) statement doesn't match number of right-hand sides ({stmt.Rhss.Count}).\");\n        return;\n      }\n\n      var next = new NextRoutineConstructor(parse.prog, parse.symbols, NextType.Update, parse.methodInfo,\n                                            this, stmt, startPC, endPC);\n\n      var s_current = next.s;\n      for (int i = 0; i < stmt.Lhss.Count; ++i) {\n        var resolutionContext = new NormalResolutionContext(s_current, next, parse.symbols);\n\n        var lhs = stmt.Lhss.ElementAt(i);\n        var newLhs = resolutionContext.ResolveAsLValue(lhs);\n\n        if (newLhs.NoTSO()) {\n          genuineTSO = false;\n        }\n\n        if (newLhs == null) {\n          next.Fail(lhs.tok, \"Left-hand side is not a valid lvalue\");\n          return;\n        }\n        next.AddUndefinedBehaviorAvoidanceConstraint(newLhs.GetUndefinedBehaviorAvoidanceConstraint());\n\n        var rhs = stmt.Rhss.ElementAt(i);\n        string newRhs;\n        if (rhs is HavocRhs) {\n          newRhs = next.AddFormal(new NextFormal($\"nondet{i}_{startPC}\", $\"nondet{i}\", lhs.Type, parse.symbols));\n        }\n        else if (rhs is ExprRhs) {\n          var erhs = (ExprRhs)rhs;\n          var newRhsRValue = resolutionContext.ResolveAsRValue(erhs.Expr);\n          next.AddUndefinedBehaviorAvoidanceConstraint(newRhsRValue.UndefinedBehaviorAvoidance);\n          newRhs = newRhsRValue.Val;\n        }\n        else if (rhs is CreateThreadRhs) {\n          next.Fail(rhs.Tok, \"Create-thread can't be done in parallel with other assignments\");\n          return;\n        }\n        else if (rhs is MallocRhs || rhs is CallocRhs) {\n          next.Fail(rhs.Tok, \"Allocation can't be done in parallel with other assignments\");\n          return;\n        }\n        else if (rhs is CompareAndSwapRhs) {\n          next.Fail(rhs.Tok, \"Compare-and-swap can't be done in parallel with other assignments\");\n          return;\n        }\n        else if (rhs is AtomicExchangeRhs) {\n          next.Fail(rhs.Tok, \"atomic-exchange can't be done in parallel with other assignments\");\n          return;\n        }\n        else {\n          next.Fail(rhs.Tok, \"Right-hand side is not a valid rvalue\");\n          return;\n        }\n\n        // var s_current := lhs.update_state(s_current, rhs);\n        s_current = stmt.BypassStoreBuffers ? newLhs.UpdateTotalStateBypassingStoreBuffer(resolutionContext, next, newRhs)\n                                            : newLhs.UpdateTotalStateWithStoreBufferEntry(resolutionContext, next, newRhs, startPC);\n        s_current = next.AddVariableDeclaration(\"s\", s_current);\n      }\n\n      var nextState = UpdatePC(s_current, next.tid, endPC);\n      next.SetNextState(nextState);\n      parse.symbols.AddNextRoutineConstructor(next);\n    }\n\n    public override bool RoughlyMatches(ArmadaStatement other)\n    {\n      if (other is ArmadaUpdateStatement) {\n        var us = (UpdateStmt)other.Stmt;\n        if (stmt.Lhss.Count != us.Lhss.Count) {\n          return true; // Maybe it's a variable introduction or variable hiding\n        }\n        for (int i = 0; i < stmt.Rhss.Count; ++i) {\n          var rhs = stmt.Rhss.ElementAt(i);\n          var otherRhs = us.Rhss.ElementAt(i);\n          if (rhs is CreateThreadRhs && !(otherRhs is CreateThreadRhs)) {\n            return false;\n          }\n          if (otherRhs is CreateThreadRhs && !(rhs is CreateThreadRhs)) {\n            return false;\n          }\n          if (rhs is MallocRhs && !(otherRhs is MallocRhs)) {\n            return false;\n          }\n          if (otherRhs is MallocRhs && !(rhs is MallocRhs)) {\n            return false;\n          }\n          if (rhs is CallocRhs && !(otherRhs is CallocRhs)) {\n            return false;\n          }\n          if (otherRhs is CallocRhs && !(rhs is CallocRhs)) {\n            return false;\n          }\n          if (rhs is CompareAndSwapRhs && !(otherRhs is CompareAndSwapRhs)) {\n            return false;\n          }\n          if (otherRhs is CompareAndSwapRhs && !(rhs is CompareAndSwapRhs)) {\n            return false;\n          }\n          if (rhs is AtomicExchangeRhs && !(otherRhs is AtomicExchangeRhs)) {\n            return false;\n          }\n          if (otherRhs is AtomicExchangeRhs && !(rhs is AtomicExchangeRhs)) {\n            return false;\n          }\n        }\n        return true;\n      }\n      else {\n        return false;\n      }\n    }\n  }\n\n  public class ArmadaVarDeclStatement : ArmadaStatement\n  {\n    private VarDeclStmt stmt;\n\n    public ArmadaVarDeclStatement(ParseInfo i_parse, VarDeclStmt i_stmt) : base(i_parse)\n    {\n      stmt = i_stmt;\n    }\n\n    public override Statement Stmt { get { return stmt; } }\n\n    public override ArmadaPC AssignPCs(ArmadaPC i_startPC)\n    {\n      if (i_startPC.instructionCount > 0) {\n        if (stmt.Update != null) {\n          AH.PrintError(parse.prog, stmt.Tok, \"In Armada, all stack variables for a method are created and initialized atomically with the stack frame getting pushed onto the stack.  So, it's a bad idea to have a variable declaration with an initialization value, like this one, somewhere other than the beginning of the method.  After all, in this case the semantics will not be what seems intuitive from reading the code.\");\n        }\n        else {\n          AH.PrintWarning(parse.prog, stmt.Tok, \"Note that, in Armada, all stack variables for a method are created and initialized atomically with the stack frame getting pushed onto the stack.  So, it's generally a good idea to have all variable declarations at the beginnings of methods.  Otherwise, the semantics may not be what seems intuitive from reading the code.\");\n        }\n      }\n      return endPC = startPC = i_startPC;\n    }\n\n    public override void ComputeNonyieldAndYieldPCs(bool inExplicitYieldBlock, HashSet<ArmadaPC> potentiallyNonyieldingPCs,\n                                                    HashSet<ArmadaPC> yieldPCs)\n    {\n      if (stmt.Update != null && inExplicitYieldBlock) {\n        potentiallyNonyieldingPCs.Add(startPC);\n      }\n    }\n\n    public override bool RoughlyMatches(ArmadaStatement other)\n    {\n      return other is ArmadaVarDeclStatement;\n    }\n  }\n\n  public class ArmadaReturnStatement : ArmadaStatement\n  {\n    private ReturnStmt stmt;\n\n    public ArmadaReturnStatement(ParseInfo i_parse, ReturnStmt i_stmt) : base(i_parse)\n    {\n      stmt = i_stmt;\n    }\n\n    public override Statement Stmt { get { return stmt; } }\n\n    public override void GenerateNextRoutines()\n    {\n      if (stmt.rhss != null && stmt.rhss.Count > 0) {\n        AH.PrintError(parse.prog, stmt.Tok, \"Armada doesn't allow arguments in return statements. You should just assign to output variables and then use a return statement with no arguments.\");\n        return;\n      }\n      \n      // We model a return statement as a goto with the target being the method's end PC.\n\n      var targetPC = parse.methodInfo.ReturnPC;\n      var next = new NextRoutineConstructor(parse.prog, parse.symbols, NextType.Goto, parse.methodInfo,\n                                            this, stmt, startPC, targetPC);\n\n      // s' == Armada_UpdatePC(s, tid, targetPC)\n\n      var s_with_new_PC = UpdatePC(next.s, next.tid, targetPC);\n      next.SetNextState(s_with_new_PC);\n      parse.symbols.AddNextRoutineConstructor(next);\n    }\n\n    public override bool RoughlyMatches(ArmadaStatement other)\n    {\n      return other is ArmadaReturnStatement;\n    }\n  }\n\n  public class ArmadaAssertStatement : ArmadaStatement\n  {\n    private AssertStmt stmt;\n\n    public ArmadaAssertStatement(ParseInfo i_parse, AssertStmt i_stmt) : base(i_parse)\n    {\n      stmt = i_stmt;\n    }\n\n    public override Statement Stmt { get { return stmt; } }\n\n    public override void GenerateNextRoutines()\n    {\n      // First, create the NextRoutine for the case where the assertion succeeds.\n      \n      var next = new NextRoutineConstructor(parse.prog, parse.symbols, NextType.AssertTrue, parse.methodInfo,\n                                            this, stmt, startPC, endPC);\n      var resolutionContext = new NormalResolutionContext(next, parse.symbols);\n\n      // s' == Armada_UpdatePC(s, tid, endPC)\n\n      var rvalue = resolutionContext.ResolveAsRValue(stmt.Expr);\n      next.AddUndefinedBehaviorAvoidanceConstraint(rvalue.UndefinedBehaviorAvoidance);\n      next.AddDefinedBehaviorConjunct(rvalue.Val);\n\n      var s_prime = UpdatePC(next.s, next.tid, endPC);\n      next.SetNextState(s_prime);\n      parse.symbols.AddNextRoutineConstructor(next);\n\n      // Second, create the NextRoutine for the case where the assertion fails.\n\n      next = new NextRoutineConstructor(parse.prog, parse.symbols, NextType.AssertFalse, parse.methodInfo,\n                                        this, stmt, startPC, endPC);\n      resolutionContext = new NormalResolutionContext(next, parse.symbols);\n\n      rvalue = resolutionContext.ResolveAsRValue(stmt.Expr);\n      next.AddUBAvoidanceConstraintAsDefinedBehaviorConjunct(rvalue.UndefinedBehaviorAvoidance);\n      next.AddDefinedBehaviorConjunct($\"!({rvalue.Val})\");\n\n      // s' == s.(stop_reason := Armada_StopReasonAssertionFailure)\n\n      s_prime = $\"({next.s}).(stop_reason := Armada_StopReasonAssertionFailure)\";\n      next.SetNextState(s_prime);\n      parse.symbols.AddNextRoutineConstructor(next);\n    }\n\n    public override bool RoughlyMatches(ArmadaStatement other)\n    {\n      return other is ArmadaAssertStatement;\n    }\n  }\n\n  public class ArmadaAssumeStatement : ArmadaStatement\n  {\n    private AssumeStmt stmt;\n\n    public ArmadaAssumeStatement(ParseInfo i_parse, AssumeStmt i_stmt) : base(i_parse)\n    {\n      stmt = i_stmt;\n    }\n\n    public override Statement Stmt { get { return stmt; } }\n\n    public override ArmadaPC AssignPCs(ArmadaPC i_startPC)\n    {\n      return endPC = startPC = i_startPC;\n    }\n\n    public override void ComputeNonyieldAndYieldPCs(bool inExplicitYieldBlock, HashSet<ArmadaPC> potentiallyNonyieldingPCs,\n                                                    HashSet<ArmadaPC> yieldPCs)\n    {\n    }\n\n    public override void GenerateEnablingConstraints()\n    {\n      parse.methodInfo.AddEnablingConstraint(parse.prog, startPC, stmt.Expr);\n    }\n\n    public override bool RoughlyMatches(ArmadaStatement other)\n    {\n      return other is ArmadaAssumeStatement;\n    }\n  }\n\n  public class ArmadaSomehowStatement : ArmadaStatement\n  {\n    private SomehowStmt stmt;\n\n    public ArmadaSomehowStatement(ParseInfo i_parse, SomehowStmt i_stmt) : base(i_parse)\n    {\n      stmt = i_stmt;\n    }\n\n    public override Statement Stmt { get { return stmt; } }\n\n    public override void GenerateNextRoutines()\n    {\n      var next = new NextRoutineConstructor(parse.prog, parse.symbols, NextType.Somehow, parse.methodInfo,\n                                            this, stmt, startPC, endPC);\n      var method = parse.methodInfo.method;\n\n      var top = $\"({next.t}).top\";\n      var ghosts = $\"({next.s}).ghosts\";\n      var start_read_context = new CustomResolutionContext(next.s, next.s, next.locv, top,\n                                                           ghosts, next.tid, method.Name, parse.symbols, next);\n\n      // Add each undefined_unless clause as an undefined-behavior-avoidance constraint, to model that the\n      // instruction may have arbitrary behavior if those constraints aren't met at the outset.\n\n      foreach (var undefined_unless_clause in stmt.UndefinedUnless) {\n        var uuc = start_read_context.ResolveAsRValue(undefined_unless_clause);\n        next.AddUndefinedBehaviorAvoidanceConstraint(uuc.UndefinedBehaviorAvoidance);\n        next.AddUndefinedBehaviorAvoidanceConstraint(uuc.Val);\n      }\n\n      // Compute each s{i+1} by updating a single modifies element in s{i}.\n\n      var s_current = next.s;\n      for (int i = 0; i < stmt.Mod.Expressions.Count; ++i) {\n        var lhs = stmt.Mod.Expressions.ElementAt(i);\n\n        var nextFormal = new NextFormal($\"newval{i}_{startPC}\", $\"newval{i}\", lhs.Type, parse.symbols);\n        var newRhs = next.AddFormal(nextFormal);\n\n        //\n        // It's important that we model the external method as\n        // updating the state using store-buffer entries if the {:tso}\n        // annotation appears on the modifies clause.  If we model it\n        // as updating the state directly, then this doesn't permit\n        // any behavior in which the external method updates the store\n        // buffer and then, after it's returned, a tau causes the\n        // modification to be reflected in real state.\n        //\n\n        // s_current := lhs.update_state(s_current, newRhs);\n        var current_context = new NormalResolutionContext(s_current, next, parse.symbols);\n        var newLhs = current_context.ResolveAsLValue(lhs);\n        if (!(newLhs is ArmadaLValue)) {\n          next.Fail(lhs.tok, \"Modifies element is not a valid lvalue\");\n          return;\n        }\n        next.AddUndefinedBehaviorAvoidanceConstraint(newLhs.GetUndefinedBehaviorAvoidanceConstraint());\n\n        s_current = Attributes.Contains(stmt.Mod.Attributes, \"tso\") ?\n          newLhs.UpdateTotalStateWithStoreBufferEntry(current_context, next, newRhs, startPC) :\n          newLhs.UpdateTotalStateBypassingStoreBuffer(current_context, next, newRhs);\n        s_current = next.AddVariableDeclaration(\"s\", s_current);\n      }\n\n      // s_current := Armada_UpdatePC(s_current, tid, endPC);\n\n      s_current = UpdatePC(s_current, next.tid, endPC);\n      s_current = next.AddVariableDeclaration(\"s\", s_current);\n\n      // s' must be equal to the updated s we just computed\n\n      next.SetNextState(s_current);\n\n      // For each ensures clause, add another condition that the clause holds in s' (as viewed by the local thread).\n\n      if (stmt.Ens.Count > 0) {\n        var end_read_context = new EnsuresResolutionContext(next.s, s_current, next.tid, method.Name, parse.symbols, next, null);\n\n        foreach (var ens in stmt.Ens) {\n          var ens_resolved = end_read_context.ResolveAsRValue(ens);\n          next.AddUBAvoidanceConstraintAsDefinedBehaviorConjunct(ens_resolved.UndefinedBehaviorAvoidance);\n          next.AddDefinedBehaviorConjunct(ens_resolved.Val);\n        }\n      }\n\n      // We're done building the next routine, so add it to the list of nexts.\n\n      parse.symbols.AddNextRoutineConstructor(next);\n    }\n\n    public override bool RoughlyMatches(ArmadaStatement other)\n    {\n      return other is ArmadaSomehowStatement;\n    }\n  }\n\n  public class ArmadaFenceStatement : ArmadaStatement\n  {\n    private FenceStmt stmt;\n\n    public ArmadaFenceStatement(ParseInfo i_parse, FenceStmt i_stmt) : base(i_parse)\n    {\n      stmt = i_stmt;\n    }\n\n    public override Statement Stmt { get { return stmt; } }\n\n    public override void GenerateNextRoutines()\n    {\n      var next = new NextRoutineConstructor(parse.prog, parse.symbols, NextType.Fence, parse.methodInfo,\n                                            this, stmt, startPC, endPC);\n\n      // |s.threads[tid].storeBuffer| == 0\n\n      next.AddConjunct($\"|({next.t}).storeBuffer| == 0\");\n\n      // s' == Armada_UpdatePC(s, tid, endPC)\n\n      var s_with_new_PC = UpdatePC(next.s, next.tid, endPC);\n      next.SetNextState(s_with_new_PC);\n      parse.symbols.AddNextRoutineConstructor(next);\n    }\n\n    public override bool RoughlyMatches(ArmadaStatement other)\n    {\n      return other is ArmadaFenceStatement;\n    }\n  }\n\n  public class ArmadaGotoStatement : ArmadaStatement\n  {\n    private GotoStmt stmt;\n\n    public ArmadaGotoStatement(ParseInfo i_parse, GotoStmt i_stmt) : base(i_parse)\n    {\n      stmt = i_stmt;\n    }\n\n    public override Statement Stmt { get { return stmt; } }\n\n    public override void GenerateNextRoutines()\n    {\n      var targetPC = parse.symbols.GetPCForMethodAndLabel(parse.methodInfo.method.Name + \"_\" + stmt.Target);\n      if (targetPC == null) {\n        AH.PrintError(parse.prog, $\"ERROR:  No label found in method {parse.methodInfo.method.Name} with name {stmt.Target}\");\n      }\n      var next = new NextRoutineConstructor(parse.prog, parse.symbols, NextType.Goto, parse.methodInfo,\n                                            this, stmt, startPC, targetPC);\n\n      // s' == Armada_UpdatePC(s, tid, targetPC)\n\n      var s_with_new_PC = UpdatePC(next.s, next.tid, targetPC);\n      next.SetNextState(s_with_new_PC);\n      parse.symbols.AddNextRoutineConstructor(next);\n    }\n\n    public override bool RoughlyMatches(ArmadaStatement other)\n    {\n      return other is ArmadaGotoStatement;\n    }\n  }\n\n  public class ArmadaDeallocStatement : ArmadaStatement\n  {\n    private DeallocStmt stmt;\n\n    public ArmadaDeallocStatement(ParseInfo i_parse, DeallocStmt i_stmt) : base(i_parse)\n    {\n      stmt = i_stmt;\n    }\n\n    public override Statement Stmt { get { return stmt; } }\n\n    public override void GenerateNextRoutines()\n    {\n      var next = new NextRoutineConstructor(parse.prog, parse.symbols, NextType.Dealloc, parse.methodInfo,\n                                            this, stmt, startPC, endPC);\n      var resolutionContext = new NormalResolutionContext(next, parse.symbols);\n\n      if (stmt.Addr.Type == null)\n      {\n        next.Fail(stmt.Tok, \"Attempt to dealloc an address whose type isn't known\");\n        return;\n      }\n      Type subtype;\n      string err;\n      if (!AH.GetDereferenceType(stmt.Addr.Type, out subtype, out err))\n      {\n        next.Fail(stmt.Tok, err);\n        return;\n      }\n\n      var addrRValue = resolutionContext.ResolveAsRValue(stmt.Addr);\n      next.AddUndefinedBehaviorAvoidanceConstraint(addrRValue.UndefinedBehaviorAvoidance);\n\n      var addr = next.AddVariableDeclaration(\"addr\", addrRValue.Val);\n\n      var s = $\"({next.s})\";\n      var h = $\"{s}.mem.heap\";\n      var tree = $\"{h}.tree\";\n\n      // Experience undefined behavior if tree-forest properties don't hold\n      next.AddUndefinedBehaviorAvoidanceConstraint($\"Armada_TreeForestProperties({tree})\");\n\n      // Experience undefined behavior if addr isn't valid\n      next.AddUndefinedBehaviorAvoidanceConstraint(AH.GetInvocationOfValidPointer(h, addr, subtype));\n\n      //\n      // If 'addr' is a pointer to the 0th element of an array, then\n      // free its parent pointer instead, i.e., free the pointer to\n      // the array.  We can't require the Armada code to pass us that\n      // array pointer because there's no way to get that pointer in\n      // Armada.  After all, calloc returns a pointer to the 0th element\n      // and there's no way to go \"up\" to the pointer to the array.\n      //\n\n      // var addr_to_free := if tree[addr].child_type.Armada_ChildTypeIndex? && tree[addr].child_type.i == 0 then\n      //                         tree[addr].parent else addr\n      // Experience undefined behavior if we're using the parent and the parent isn't in the tree\n\n      var use_parent = next.AddVariableDeclaration(\n        \"use_parent\",\n        $\"{tree}[{addr}].child_type.Armada_ChildTypeIndex? && {tree}[{addr}].child_type.i == 0\"\n      );\n      var parent = $\"{tree}[{addr}].parent\";\n      next.AddUndefinedBehaviorAvoidanceConstraint($\"{use_parent} ==> {parent} in {tree}\");\n      var addr_to_free = next.AddVariableDeclaration(\"addr_to_free\", $\"if {use_parent} then {parent} else {addr}\");\n\n      // Experience undefined behavior if we're freeing something that isn't a root\n      next.AddUndefinedBehaviorAvoidanceConstraint($\"{tree}[{addr_to_free}].child_type.Armada_ChildTypeRoot?\");\n      next.AddUndefinedBehaviorAvoidanceConstraint($\"{tree}[{addr_to_free}].child_type.rt.Armada_RootTypeDynamicHeap?\");\n\n      // var descendants := set d | d in tree && Armada_PointerIsAncestorOfPointer(tree, addr_to_free, d) :: d;\n      var descendants = $\"Armada_DescendantsOfPointer({tree}, {addr_to_free})\";\n      descendants = next.AddVariableDeclaration(\"descendants\", descendants);\n\n      // Update valid and freed pointer sets\n\n      var s_current = $\"{s}.(mem := {s}.mem.(heap := {h}.(valid := {h}.valid - {descendants}, freed := {h}.freed + {descendants})))\";\n      s_current = next.AddVariableDeclaration(\"s\", s_current);\n\n      // s_current := Armada_UpdatePC(s, tid, {end PC})\n\n      s_current = UpdatePC(s_current, next.tid, endPC);\n      s_current = next.AddVariableDeclaration(\"s\", s_current);\n\n      next.SetNextState(s_current);\n\n      // The next predicate is built, so add it to the list of next predicates.\n\n      parse.symbols.AddNextRoutineConstructor(next);\n    }\n\n    public override bool RoughlyMatches(ArmadaStatement other)\n    {\n      return other is ArmadaDeallocStatement;\n    }\n  }\n\n  public class ArmadaJoinStatement : ArmadaStatement\n  {\n    private JoinStmt stmt;\n\n    public ArmadaJoinStatement(ParseInfo i_parse, JoinStmt i_stmt) : base(i_parse)\n    {\n      stmt = i_stmt;\n    }\n\n    public override Statement Stmt { get { return stmt; } }\n\n    public override void GenerateNextRoutines()\n    {\n      var next = new NextRoutineConstructor(parse.prog, parse.symbols, NextType.Join, parse.methodInfo,\n                                            this, stmt, startPC, endPC);\n      var resolutionContext = new NormalResolutionContext(next, parse.symbols);\n\n      var s = $\"({next.s})\";\n      var join_tid = resolutionContext.ResolveAsRValue(stmt.WhichThread);\n      var join_tid_undefined_behavior_avoidance = join_tid.UndefinedBehaviorAvoidance;\n      next.AddUndefinedBehaviorAvoidanceConstraint(join_tid_undefined_behavior_avoidance);\n\n      // It's undefined behavior to join a thread that isn't either running or joinable.\n      // For instance, once you join a thread you can't join it again.\n\n      next.AddUndefinedBehaviorAvoidanceConstraint($\"({join_tid.Val}) in {s}.threads || ({join_tid.Val}) in {s}.joinable_tids\");\n\n      // The step is enabled only when join_tid is in s.joinable_tids.\n\n      next.AddDefinedBehaviorConjunct($\"({join_tid.Val}) in {s}.joinable_tids\");\n\n      // Remove the joined thread from the set of joinable threads, to model the fact that a join\n      // releases the thread's resources and thus makes it illegal to join it again.\n      //\n      // s_current := s.(joinable_tids := joinable_tids - {join_tid});\n\n      var s_current = next.AddVariableDeclaration(\"s\", $\"{s}.(joinable_tids := {s}.joinable_tids - {{ {join_tid.Val} }})\");\n\n      // s' == Armada_UpdatePC(s_current, tid, endPC)\n\n      var s_with_new_PC = UpdatePC(s_current, next.tid, endPC);\n      next.SetNextState(s_with_new_PC);\n      parse.symbols.AddNextRoutineConstructor(next);\n    }\n\n    public override bool RoughlyMatches(ArmadaStatement other)\n    {\n      return other is ArmadaJoinStatement;\n    }\n  }\n\n  public class ArmadaBreakStatement : ArmadaStatement\n  {\n    private BreakStmt stmt;\n    private ArmadaWhileStatement innermostEnclosingWhile;\n\n    public ArmadaBreakStatement(ParseInfo i_parse, BreakStmt i_stmt) : base(i_parse)\n    {\n      stmt = i_stmt;\n      innermostEnclosingWhile = parse.innermostEnclosingWhile;\n    }\n\n    public override Statement Stmt { get { return stmt; } }\n\n    public override void GenerateNextRoutines()\n    {\n      var next = new NextRoutineConstructor(parse.prog, parse.symbols, NextType.WhileBreak, parse.methodInfo,\n                                            this, stmt, startPC, innermostEnclosingWhile.EndPC);\n      var s_with_new_PC = UpdatePC(next.s, next.tid, innermostEnclosingWhile.EndPC);\n      next.SetNextState(s_with_new_PC);\n      parse.symbols.AddNextRoutineConstructor(next);\n    }\n\n    public override bool RoughlyMatches(ArmadaStatement other)\n    {\n      return other is ArmadaBreakStatement;\n    }\n  }\n\n  public class ArmadaContinueStatement : ArmadaStatement\n  {\n    private ContinueStmt stmt;\n    private ArmadaWhileStatement innermostEnclosingWhile;\n\n    public ArmadaContinueStatement(ParseInfo i_parse, ContinueStmt i_stmt) : base(i_parse)\n    {\n      stmt = i_stmt;\n      innermostEnclosingWhile = parse.innermostEnclosingWhile;\n    }\n\n    public override Statement Stmt { get { return stmt; } }\n\n    public override void GenerateNextRoutines()\n    {\n      var next = new NextRoutineConstructor(parse.prog, parse.symbols, NextType.WhileContinue, parse.methodInfo,\n                                            this, stmt, startPC, innermostEnclosingWhile.StartPC);\n      var s_with_new_PC = UpdatePC(next.s, next.tid, innermostEnclosingWhile.StartPC);\n      next.SetNextState(s_with_new_PC);\n      parse.symbols.AddNextRoutineConstructor(next);\n    }\n\n    public override bool RoughlyMatches(ArmadaStatement other)\n    {\n      return other is ArmadaContinueStatement;\n    }\n  }\n\n  public class ArmadaYieldStatement : ArmadaStatement\n  {\n    private YieldStmt stmt;\n\n    public ArmadaYieldStatement(ParseInfo i_parse, YieldStmt i_stmt) : base(i_parse)\n    {\n      stmt = i_stmt;\n    }\n\n    public override Statement Stmt { get { return stmt; } }\n\n    public override ArmadaPC AssignPCs(ArmadaPC i_startPC)\n    {\n      endPC = startPC = i_startPC;\n      return endPC;\n    }\n\n    public override void ComputeNonyieldAndYieldPCs(bool inExplicitYieldBlock, HashSet<ArmadaPC> potentiallyNonyieldingPCs,\n                                                    HashSet<ArmadaPC> yieldPCs)\n    {\n      yieldPCs.Add(startPC);\n    }\n\n    public override bool RoughlyMatches(ArmadaStatement other)\n    {\n      return other is ArmadaYieldStatement;\n    }\n  }\n}\n"
  },
  {
    "path": "Source/Armada/ArmadaPipeline.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\r\n\r\n  <Target Name=\"RunCoco\" BeforeTargets=\"PreBuildEvent\" Outputs=\"$(ProjectDir)Parser.cs;$(ProjectDir)Scanner.cs\" Inputs=\"$(ProjectDir)Armada.atg\">\r\n    <Exec Command=\"dotnet tool restore\" />\r\n    <Exec Command=\"dotnet --info\" />\r\n    <Exec Command=\"dotnet tool run coco $(ProjectDir)Armada.atg -namespace Microsoft.Armada -frames $(ProjectDir)../../third_party/Coco/src\" />\r\n    <!-- Recompute files to build according to https://stackoverflow.com/a/44829863/93197 -->\r\n    <ItemGroup>\r\n      <Compile Include=\"**/*$(DefaultLanguageSourceExtension)\" Exclude=\"$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder);$(BaseIntermediateOutputPath)**;$(BaseOutputPath)**;@(Compile)\" />\r\n    </ItemGroup>\r\n  </Target>\r\n\r\n  <PropertyGroup>\r\n    <TargetFramework>net5.0</TargetFramework>\r\n  </PropertyGroup>\r\n\r\n</Project>\r\n"
  },
  {
    "path": "Source/Armada/ArmadaRValue.cs",
    "content": "using System;\nusing System.Numerics;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text;\nusing static Microsoft.Armada.Predicate;\nusing IToken = Microsoft.Boogie.IToken;\nusing Token = Microsoft.Boogie.Token;\n\nnamespace Microsoft.Armada {\n\n  public class UndefinedBehaviorAvoidanceConstraint\n  {\n    private List<string> constraints;\n\n    public UndefinedBehaviorAvoidanceConstraint()\n    {\n      constraints = new List<string>();\n    }\n\n    public UndefinedBehaviorAvoidanceConstraint(string e)\n    {\n      constraints = new List<string>();\n      if (e != null)\n      {\n        constraints.Add(e);\n      }\n    }\n\n    public UndefinedBehaviorAvoidanceConstraint(List<string> es)\n    {\n      constraints = new List<string>(es);\n    }\n\n    public UndefinedBehaviorAvoidanceConstraint(UndefinedBehaviorAvoidanceConstraint other)\n    {\n      constraints = new List<string>(other.AsList);\n    }\n\n    public string Expr\n    {\n      get\n      {\n        return AH.CombineStringsWithAnd(constraints);\n      }\n    }\n\n    public bool CanCauseUndefinedBehavior\n    {\n      get\n      {\n        return constraints.Any();\n      }\n    }\n\n    public void Add(string other)\n    {\n      if (other != null) {\n        constraints.Add(other);\n      }\n    }\n\n    public void Add(List<string> other)\n    {\n      foreach (var e in other) {\n        constraints.Add(e);\n      }\n    }\n\n    public void Add(UndefinedBehaviorAvoidanceConstraint other)\n    {\n      Add(other.AsList);\n    }\n\n    public List<string> AsList { get { return constraints; } }\n\n    public static UndefinedBehaviorAvoidanceConstraint operator+(UndefinedBehaviorAvoidanceConstraint c1, UndefinedBehaviorAvoidanceConstraint c2)\n    {\n      var ret = new UndefinedBehaviorAvoidanceConstraint(c1);\n      ret.Add(c2);\n      return ret;\n    }\n\n    public static UndefinedBehaviorAvoidanceConstraint operator+(UndefinedBehaviorAvoidanceConstraint c1, string c2)\n    {\n      var ret = new UndefinedBehaviorAvoidanceConstraint(c1);\n      ret.Add(c2);\n      return ret;\n    }\n  }\n\n  public class ArmadaRValue\n  {\n    private UndefinedBehaviorAvoidanceConstraint crashAvoidance;\n    private string val;\n\n    public ArmadaRValue(UndefinedBehaviorAvoidanceConstraint i_crashAvoidance, string i_val)\n    {\n      Debug.Assert(i_crashAvoidance != null);\n      crashAvoidance = i_crashAvoidance;\n      val = i_val;\n    }\n\n    public ArmadaRValue(string i_val)\n    {\n      crashAvoidance = new UndefinedBehaviorAvoidanceConstraint();\n      val = i_val;\n    }\n\n    public UndefinedBehaviorAvoidanceConstraint UndefinedBehaviorAvoidance { get { return crashAvoidance; } }\n    public string Val { get { return val; } }\n    public bool CanCauseUndefinedBehavior { get { return crashAvoidance.CanCauseUndefinedBehavior; } }\n  }\n\n  public class ArmadaRValueList\n  {\n    private UndefinedBehaviorAvoidanceConstraint crashAvoidance;\n    private List<string> vals;\n\n    public ArmadaRValueList()\n    {\n      crashAvoidance = new UndefinedBehaviorAvoidanceConstraint();\n      vals = new List<string>();\n    }\n\n    public void Add(ArmadaRValue rvalue)\n    {\n      if (rvalue != null)\n      {\n        crashAvoidance.Add(rvalue.UndefinedBehaviorAvoidance);\n        vals.Add(rvalue.Val);\n      }\n      else\n      {\n        vals.Add(null);\n      }\n    }\n\n    public UndefinedBehaviorAvoidanceConstraint UndefinedBehaviorAvoidance { get { return crashAvoidance; } }\n    public List<string> Vals { get { return vals; } }\n    public bool CanCauseUndefinedBehavior { get { return crashAvoidance.CanCauseUndefinedBehavior; } }\n  }\n\n}\n"
  },
  {
    "path": "Source/Armada/ArmadaStructs.cs",
    "content": "using System;\nusing System.Numerics;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text;\nusing static Microsoft.Armada.Predicate;\nusing IToken = Microsoft.Boogie.IToken;\nusing Token = Microsoft.Boogie.Token;\n\nnamespace Microsoft.Armada {\n\n  public class ArmadaStruct\n  {\n    private string name;\n    private Dictionary<string, Type> fieldTypes;\n    private List<string> fieldNames;\n\n    public ArmadaStruct(Program prog, ClassDecl c)\n    {\n      name = c.Name;\n      fieldTypes = new Dictionary<string, Type>();\n      fieldNames = new List<string>();\n\n      foreach (MemberDecl member in c.Members) {\n        if (member is Field) {\n          var f = (Field)member;\n          if (!f.IsStatic) {\n            fieldNames.Add(f.Name);\n            fieldTypes[f.Name] = f.Type;\n            if (f.InitialValue != null) {\n              AH.PrintError(prog, $\"Ignoring initializer {f.InitialValue} of field {f.Name} of struct {name}\");\n            }\n          }\n          else {\n            AH.PrintError(prog, $\"Ignoring static field {f.Name} in struct\");\n          }\n        }\n      }\n    }\n\n    public ArmadaStruct(string struct_name, Dictionary<string, Type> fields)\n    {\n      name = struct_name;\n      fieldTypes = fields;\n      fieldNames = fields.Keys.ToList();\n    }\n\n    public string Name { get { return name; } }\n    public IEnumerable<string> FieldNames { get { return fieldNames; } }\n    public Type GetFieldType(string fieldName) { return fieldTypes[fieldName]; }\n    public Type LookupFieldType(string fieldName) { return (fieldTypes.ContainsKey(fieldName)) ? fieldTypes[fieldName] : null; }\n    public int GetFieldPos(string fieldName) { return fieldNames.IndexOf(fieldName); }\n  }\n\n  public class ArmadaStructs\n  {\n    public readonly string StructsModuleName;\n    private Dictionary<string, ArmadaStruct> structs;\n    private ClassDecl defaultClass;\n    private string refinementConstraint;\n\n    public ArmadaStructs(string i_structsModuleName)\n    {\n      StructsModuleName = i_structsModuleName;\n      structs = new Dictionary<string, ArmadaStruct>();\n      defaultClass = null;\n      refinementConstraint = \"(ls.stop_reason.Armada_NotStopped? || ls.stop_reason == hs.stop_reason)\";\n    }\n\n    public void AddClass(Program prog, ClassDecl c)\n    {\n      if (!c.IsDefaultClass) {\n        structs[c.Name] = new ArmadaStruct(prog, c);\n      }\n    }\n\n    public void SetDefaultClass(ClassDecl c)\n    {\n      defaultClass = c;\n    }\n\n    public ClassDecl DefaultClass { get { return defaultClass;  } }\n\n    public IEnumerable<string> StructNames { get { return structs.Keys; } }\n    public bool DoesStructExist(string structName) { return structs.ContainsKey(structName); }\n    public ArmadaStruct GetStruct(string structName) { return structs[structName]; }\n    public ArmadaStruct LookupStruct(string structName) { return structs.ContainsKey(structName) ? structs[structName] : null; }\n\n    public Type GetStructFieldType(string structName, string fieldName)\n    {\n      return structs.ContainsKey(structName) ? structs[structName].GetFieldType(fieldName) : null;\n    }\n\n    public int GetStructFieldPos(string structName, string fieldName)\n    {\n      return structs.ContainsKey(structName) ? structs[structName].GetFieldPos(fieldName) : -1;\n    }\n\n    public Type FlattenType(Type t, string moduleName = null)\n    {\n      if (t is UserDefinedType) {\n        var ut = (UserDefinedType)t;\n        if (DoesStructExist(ut.Name)) {\n          return AH.ReferToType(\"Armada_Struct_\" + ut.Name, moduleName);\n        }\n      }\n      else if (t is SizedArrayType) {\n        var ssa = (SizedArrayType)t;\n        return new SeqType(FlattenType(ssa.Range, moduleName));\n      }\n      else if (t is PointerType) {\n        return AH.ReferToType(\"Armada_Pointer\");\n      }\n\n      return t;\n    }\n\n    public string RefinementConstraint { get { return refinementConstraint; } }\n\n    public void AddRefinementConstraint(string constraint)\n    {\n      refinementConstraint = $\"{refinementConstraint} && ({constraint})\";\n    }\n  }\n\n}\n"
  },
  {
    "path": "Source/Armada/AssumeIntro.cs",
    "content": "using System;\nusing System.Numerics;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text;\nusing System.Text.RegularExpressions;\n\nnamespace Microsoft.Armada\n{\n  ////////////////////////////////////////////////\n  // CHLPathEffect\n  ////////////////////////////////////////////////\n\n  abstract class CHLPathEffect\n  {\n    // A path's effective procedure can be obtained by calling ProcName.  Usually, that's the\n    // procedure where the path starts.  However, when the first thing that happens is a return,\n    // it's the procedure returned to.\n\n    // The start and end PCs are the actual PC values at the start and end of running the path.\n    // The effective start and end PCs, however, are always in the effective procedure of the path.\n    // They correspond to the PC at the top of the stack at the time.\n    // So, if the path starts out by returning, the effective start PC is the PC popped off the\n    // stack by the return.\n    // And, if the path ends by calling, the end PC is the PC pushed onto the stack by the call.\n\n    // The effective PCs are useful because they can be unambiguously used to name a sequence of\n    // paths in a straightline behavior.  The procedure name, effective end PC, and branch outcomes\n    // uniquely identify a straightline behavior.  They're also useful in constructing a sequence\n    // corresponding to a straightline behavior:  the effective end PC of one step is the effective\n    // start PC of the next.\n\n    public CHLPathEffect(ArmadaPC i_startPC, ArmadaPC i_endPC, ArmadaPC i_effectiveStartPC, ArmadaPC i_effectiveEndPC)\n    {\n      startPC = i_startPC;\n      endPC = i_endPC;\n      effectiveStartPC = i_effectiveStartPC;\n      effectiveEndPC = i_effectiveEndPC;\n    }\n\n    protected ArmadaPC startPC;\n    protected ArmadaPC endPC;\n    protected ArmadaPC effectiveStartPC;\n    protected ArmadaPC effectiveEndPC;\n\n    public ArmadaPC StartPC { get { return startPC; } }\n    public ArmadaPC EndPC { get { return endPC; } }\n    public ArmadaPC EffectiveStartPC { get { return effectiveStartPC; } }\n    public ArmadaPC EffectiveEndPC { get { return effectiveEndPC; } }\n\n    public virtual string ProcName { get; }\n    public virtual string Constructor { get; }\n    public virtual string Callee { get { return null; } }\n\n    public virtual bool CanFollow(StraightlineState state) { return false; }\n  }\n\n  class CHLPathEffectNormal : CHLPathEffect\n  {\n    public CHLPathEffectNormal(ArmadaPC i_startPC, ArmadaPC i_endPC) : base(i_startPC, i_endPC, i_startPC, i_endPC)\n    {\n    }\n\n    public override string ProcName { get { return startPC.methodName; } }\n    public override string Constructor { get { return \"CHLStepEffectNormal()\"; } }\n\n    public override bool CanFollow(StraightlineState state) { return state is StraightlineStateYielded; }\n  }\n\n  class CHLPathEffectReturn : CHLPathEffect\n  {\n    public CHLPathEffectReturn(ArmadaPC i_startPC, ArmadaPC i_endPC, ArmadaPC i_effectiveStartPC)\n      : base(i_startPC, i_endPC, i_effectiveStartPC, i_endPC)\n    {\n    }\n\n    public string Returner { get { return startPC.methodName; } }\n    public override string ProcName { get { return endPC.methodName; } }\n    public override string Constructor { get { return \"CHLStepEffectReturn()\"; } }\n\n    public override bool CanFollow(StraightlineState state) { return state is StraightlineStateEnsured; }\n  }\n\n  class CHLPathEffectCall : CHLPathEffect\n  {\n    public CHLPathEffectCall(ArmadaPC i_startPC, ArmadaPC i_endPC, ArmadaPC i_effectiveEndPC)\n      : base(i_startPC, i_endPC, i_startPC, i_effectiveEndPC)\n    {\n    }\n\n    public override string Callee { get { return endPC.methodName; } }\n    public override string ProcName { get { return startPC.methodName; } }\n    public override string Constructor { get { return $\"CHLStepEffectCall(LProcName_{endPC.methodName})\"; } }\n\n    public override bool CanFollow(StraightlineState state) { return state is StraightlineStateYielded; }\n  }\n\n  class CHLPathEffectReturnThenCall : CHLPathEffect\n  {\n    public CHLPathEffectReturnThenCall(ArmadaPC i_startPC, ArmadaPC i_endPC, ArmadaPC i_effectiveStartPC, ArmadaPC i_effectiveEndPC)\n      : base(i_startPC, i_endPC, i_effectiveStartPC, i_effectiveEndPC)\n    {\n    }\n\n    public string Returner { get { return startPC.methodName; } }\n    public override string Callee { get { return endPC.methodName; } }\n    public override string ProcName { get { return effectiveStartPC.methodName; } }\n    public override string Constructor { get { return $\"CHLStepEffectReturnThenCall(LProcName_{endPC.methodName})\"; } }\n\n    public override bool CanFollow(StraightlineState state) { return state is StraightlineStateEnsured; }\n  }\n\n  class CHLPathEffectActorless : CHLPathEffect\n  {\n    public CHLPathEffectActorless() : base(null, null, null, null)\n    {\n    }\n\n    public override string ProcName { get { return \"main\"; } }\n    public override string Constructor { get { return \"CHLStepEffectActorless()\"; } }\n  }\n\n  class CHLPathEffectExit : CHLPathEffect\n  {\n    public CHLPathEffectExit(ArmadaPC i_startPC) : base(i_startPC, null, i_startPC, null)\n    {\n    }\n\n    public override string ProcName { get { return startPC.methodName; } }\n    public override string Constructor { get { return \"CHLStepEffectExit()\"; } }\n\n    public override bool CanFollow(StraightlineState state) { return state is StraightlineStateYielded; }\n  }\n\n  class CHLPathEffectStop : CHLPathEffect\n  {\n    public CHLPathEffectStop(ArmadaPC i_startPC) : base(i_startPC, null, null, null)\n    {\n    }\n\n    public override string ProcName { get { return startPC.methodName; } }\n    public override string Constructor { get { return \"CHLStepEffectStop()\"; } }\n\n    public override bool CanFollow(StraightlineState state) { return false; }\n  }\n\n  ////////////////////////////////////////////////\n  // CHLPredicateInfo\n  ////////////////////////////////////////////////\n\n  class CHLPredicateInfo\n  {\n    public readonly string Key;\n    public readonly string Value;\n    public readonly bool Opaque;\n\n    public CHLPredicateInfo(string i_key, string i_value, bool i_opaque)\n    {\n      Key = i_key;\n      Value = i_value;\n      Opaque = i_opaque;\n    }\n  }\n\n  ////////////////////////////////////////////////\n  // AssumeIntroPathGenerator\n  ////////////////////////////////////////////////\n\n  public class AssumeIntroProofGenerator : AbstractProofGenerator\n  {\n    private AssumeIntroStrategyDecl strategy;\n    private List<ArmadaPC> lpcs;\n    private List<CHLPredicateInfo> globalInvariantInfos;\n    private List<CHLPredicateInfo> yieldPredicateInfos;\n    private Dictionary<string, List<string>> extraPreconditionsForMethod;\n    private Dictionary<string, List<string>> extraPostconditionsForMethod;\n    private Dictionary<ArmadaPC, List<string>> extraLoopModifiesClausesForPC;\n    private Dictionary<ArmadaPC, List<string>> extraLocalInvariantClausesForPC;\n    private HashSet<ArmadaPC> lExtraRecurrentPCs, hExtraRecurrentPCs;\n    private List<string> methodsWithPostconditions;\n    private HashSet<ArmadaPC> loopHeads;\n    private HashSet<ArmadaPC> pcsWithEnablingConditions;\n    private HashSet<ArmadaPC> pcsWithLocalInvariants;\n    private ProofFile pcstackFile;\n    private ProofFile sbdFile;\n    private ProofFile exhaustiveFile;\n    private Dictionary<string, ArmadaPC> returnPCForMethod;\n    private Dictionary<AtomicPath, CHLPathEffect> pathEffectMap;\n    private Dictionary<ArmadaPC, List<AtomicPath>> pathsStartingAtPC;\n    private List<StraightlineBehavior> straightlineBehaviorDescriptors;\n    private Dictionary<string, StraightlineBehavior> emptyStraightlineBehaviorForMethod;\n    private List<StraightlineBehavior> sbdsEndingNormal, sbdsEndingEnsured, sbdsEndingYielded;\n    private Dictionary<string, List<string>> preconditionsForMethod;\n\n    public AssumeIntroProofGenerator(ProofGenerationParams i_pgp, AssumeIntroStrategyDecl i_strategy)\n      : base(i_pgp)\n    {\n      strategy = i_strategy;\n      lpcs = new List<ArmadaPC>();\n      i_pgp.symbolsLow.AllMethods.AppendAllPCs(lpcs);\n      globalInvariantInfos = new List<CHLPredicateInfo>();\n      yieldPredicateInfos = new List<CHLPredicateInfo>();\n      extraPreconditionsForMethod = new Dictionary<string, List<string>>();\n      extraPostconditionsForMethod = new Dictionary<string, List<string>>();\n      extraLoopModifiesClausesForPC = new Dictionary<ArmadaPC, List<string>>();\n      extraLocalInvariantClausesForPC = new Dictionary<ArmadaPC, List<string>>();\n      methodsWithPostconditions = new List<string>();\n      loopHeads = new HashSet<ArmadaPC>();\n      pcsWithEnablingConditions = new HashSet<ArmadaPC>();\n      pcsWithLocalInvariants = new HashSet<ArmadaPC>();\n      returnPCForMethod = new Dictionary<string, ArmadaPC>();\n      pathEffectMap = new Dictionary<AtomicPath, CHLPathEffect>();\n      pathsStartingAtPC = new Dictionary<ArmadaPC, List<AtomicPath>>();\n      straightlineBehaviorDescriptors = new List<StraightlineBehavior>();\n      emptyStraightlineBehaviorForMethod = new Dictionary<string, StraightlineBehavior>();\n      sbdsEndingEnsured = new List<StraightlineBehavior>();\n      sbdsEndingYielded = new List<StraightlineBehavior>();\n      sbdsEndingNormal = new List<StraightlineBehavior>();\n      preconditionsForMethod = new Dictionary<string, List<string>>();\n    }\n\n    public override void GenerateProof()\n    {\n      if (!CheckEquivalence())\n      {\n        AH.PrintError(pgp.prog, \"Levels {pgp.mLow.Name} and {pgp.mHigh.Name} aren't sufficiently equivalent to perform refinement proof generation using the variable-hiding strategy\");\n        return;\n      }\n\n      if (!CheckForBackwardGotos())\n      {\n        return;\n      }\n\n      AddIncludesAndImports();\n      MakeTrivialPCMap();\n      CreateExtraRecurrentPCs();\n      CreateReturnPCForMethod();\n      GenerateNextRoutineMap();\n      DeterminePCsWithEnablingConditions();\n      GenerateProofGivenMap();\n    }\n\n    private void GenerateProofGivenMap()\n    {\n      GenerateProofHeader();\n      GenerateCustomCHLClauses();\n      ParseProgram();\n      GenerateAtomicSpecs(true, lExtraRecurrentPCs, hExtraRecurrentPCs);\n      CreatePathEffectMap();\n      CreateStoppingPathsStartingAtPC();\n      GeneratePathPCStackEffectLemmas();\n      CreateStraightlineBehaviors();\n      GenerateStraightlineBehaviorDescriptors();\n      GenerateStraightlineBehaviorDescriptorExhaustiveLemmas();\n      GenerateStraightlineBehaviorDescriptorContinuationLemmas();\n      GenerateStraightlineBehaviorDescriptorEnumerationLemmas();\n      GenerateStateAbstractionFunctions_LH();\n      GenerateConvertStep_LH();\n      GenerateConvertAtomicPath_LH();\n      GenerateConcurrentHoareLogicRequest();\n      GenerateLocalViewCommutativityLemmas();\n      GenerateGenericStoreBufferLemmas_L();\n      GenerateProofThatCHLRequestIsValid();\n      GenerateLemmasForAssumeIntroProof();\n      GenerateFinalProof();\n    }\n\n    private void CreateExtraRecurrentPCs()\n    {\n      lExtraRecurrentPCs = new HashSet<ArmadaPC>();\n      foreach (var pc in pgp.symbolsLow.EnumeratePotentialRecurrentPCs()) {\n        if (pgp.symbolsLow.IsNonyieldingPC(pc)) {\n          lExtraRecurrentPCs.Add(pc);\n        }\n      }\n\n      hExtraRecurrentPCs = new HashSet<ArmadaPC>();\n      foreach (var pc in pgp.symbolsHigh.EnumeratePotentialRecurrentPCs()) {\n        if (pgp.symbolsHigh.IsNonyieldingPC(pc)) {\n          hExtraRecurrentPCs.Add(pc);\n        }\n      }\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    /// Includes and imports\n    ////////////////////////////////////////////////////////////////////////\n\n    protected override void AddIncludesAndImports()\n    {\n      base.AddIncludesAndImports();\n\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/strategies/chl/AtomicConcurrentHoareLogic.i.dfy\");\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/option.s.dfy\");\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/seqs.s.dfy\");\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/seqs.i.dfy\");\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/sets.i.dfy\");\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/maps.i.dfy\");\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/strategies/generic/GenericArmadaLemmas.i.dfy\");\n\n      pgp.MainProof.AddImport(\"InvariantsModule\");\n      pgp.MainProof.AddImport(\"ConcurrentHoareLogicSpecModule\");\n      pgp.MainProof.AddImport(\"AtomicConcurrentHoareLogicSpecModule\");\n      pgp.MainProof.AddImport(\"AtomicConcurrentHoareLogicModule\");\n      pgp.MainProof.AddImport(\"util_option_s\");\n      pgp.MainProof.AddImport(\"util_collections_seqs_s\");\n      pgp.MainProof.AddImport(\"util_collections_seqs_i\");\n      pgp.MainProof.AddImport(\"util_collections_sets_i\");\n      pgp.MainProof.AddImport(\"util_collections_maps_i\");\n      pgp.MainProof.AddImport(\"GenericArmadaSpecModule\");\n      pgp.MainProof.AddImport(\"GenericArmadaLemmasModule\");\n\n      pgp.proofFiles.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/strategies/chl/AtomicConcurrentHoareLogicSpec.i.dfy\",\n                                \"defs\");\n      pgp.proofFiles.AddImport(\"ConcurrentHoareLogicSpecModule\", null, \"defs\");\n      pgp.proofFiles.AddImport(\"AtomicConcurrentHoareLogicSpecModule\", null, \"defs\");\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    /// PC Info\n    ////////////////////////////////////////////////////////////////////////\n\n    private void CreateReturnPCForMethod()\n    {\n      returnPCForMethod = pgp.symbolsLow.MethodNames.ToDictionary(\n        methodName => methodName,\n        methodName => pgp.symbolsLow.AllMethods.LookupMethod(methodName).ReturnPC\n      );\n    }\n\n    private CHLPathEffect GetCHLPathEffect(AtomicPath atomicPath)\n    {\n      if (atomicPath.Stopping) {\n        return new CHLPathEffectStop(atomicPath.StartPC);\n      }\n      if (atomicPath.Tau) {\n        return new CHLPathEffectActorless();\n      }\n\n      // Because all entry points and return sites of methods are considered yield or recurrent\n      // points, a path can only return (or exit) as its first routine and can only call as its last\n      // routine.  So, those are the only routines we need to look at to tell whether a path calls\n      // or returns.\n\n      var firstRoutine = atomicPath.NextRoutines[0];\n      var lastRoutine = atomicPath.LastNextRoutine;\n\n      if (firstRoutine.nextType == NextType.TerminateThread) {\n        return new CHLPathEffectExit(lastRoutine.startPC);\n      }\n      else if (firstRoutine.nextType == NextType.TerminateProcess) {\n        return new CHLPathEffectStop(lastRoutine.startPC);\n      }\n      else if (firstRoutine.nextType == NextType.Return) {\n        var effectiveStartPC = firstRoutine.endPC;\n        if (lastRoutine.nextType == NextType.Call) {\n          var effectiveEndPC = ((ArmadaCallStatement)lastRoutine.armadaStatement).EndPC;\n          return new CHLPathEffectReturnThenCall(atomicPath.StartPC, atomicPath.EndPC, effectiveStartPC, effectiveEndPC);\n        }\n        else {\n          return new CHLPathEffectReturn(atomicPath.StartPC, atomicPath.EndPC, effectiveStartPC);\n        }\n      }\n      else if (lastRoutine.nextType == NextType.Call) {\n        var effectiveEndPC = ((ArmadaCallStatement)lastRoutine.armadaStatement).EndPC;\n        return new CHLPathEffectCall(atomicPath.StartPC, atomicPath.EndPC, effectiveEndPC);\n      }\n\n      // There were no returns or calls, so this path just has a normal effect.\n\n      return new CHLPathEffectNormal(atomicPath.StartPC, atomicPath.EndPC);\n    }\n\n    private void CreatePathEffectMap()\n    {\n      foreach (var atomicPath in lAtomic.AtomicPaths)\n      {\n        var effect = GetCHLPathEffect(atomicPath);\n        pathEffectMap[atomicPath] = effect;\n      }\n    }\n\n    private void CreateStoppingPathsStartingAtPC()\n    {\n      foreach (var pc in lpcs)\n      {\n        pathsStartingAtPC[pc] = new List<AtomicPath>();\n      }\n      foreach (var atomicPath in lAtomic.AtomicPaths.Where(ap => !ap.Tau))\n      {\n        pathsStartingAtPC[atomicPath.StartPC].Add(atomicPath);\n      }\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    /// Static checks\n    ////////////////////////////////////////////////////////////////////////\n\n    private bool CheckForBackwardGotos()\n    {\n      var allMethodsInfo = pgp.symbolsLow.AllMethods;\n      foreach (var methodName in allMethodsInfo.AllMethodNames) {\n        var methodInfo = allMethodsInfo.LookupMethod(methodName);\n        if (methodInfo.method.Body != null) {\n          foreach (var stmt in methodInfo.ParsedBody) {\n            if (stmt is ArmadaGotoStatement) {\n              var startPC = stmt.StartPC;\n              var s = (GotoStmt)(stmt.Stmt);\n              var targetPC = pgp.symbolsLow.GetPCForMethodAndLabel(methodInfo.method.Name + \"_\" + s.Target);\n              if (targetPC == null || targetPC.instructionCount <= startPC.instructionCount) {\n                AH.PrintError(pgp.prog, s.Tok, $\"Only forward gotos are supported by assume-intro proofs\");\n                return false;\n              }\n            }\n          }\n        }\n      }\n\n      return true;\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    /// Concurrent Hoare logic request\n    ////////////////////////////////////////////////////////////////////////\n\n    private void GenerateConcurrentHoareLogicRequest()\n    {\n      string str;\n\n      str = \"datatype LProcName = \";\n      str += String.Join(\" | \", pgp.symbolsLow.MethodNames.Select(methodName => $\"LProcName_{methodName}\"));\n      pgp.AddDatatype(str, \"defs\");\n\n      str = $@\"\n        type CHLRequest = ConcurrentHoareLogicRequest<LPlusState, Armada_ThreadHandle, PathAndTid<LAtomic_Path>, L.Armada_PC, LProcName>\n      \";\n      pgp.AddTypeSynonym(str, \"defs\");\n\n      str = @\"\n        type AtomicCHLRequest = AtomicConcurrentHoareLogicRequest<LPlusState, LAtomic_Path, L.Armada_PC, LProcName,\n                                                                  H.Armada_TotalState, HAtomic_Path, H.Armada_PC>\n      \";\n      pgp.AddTypeSynonym(str, \"defs\");\n\n      str = \"type LAtomicStraightlineState = StraightlineState<LPlusState, L.Armada_PC>\";\n      pgp.AddTypeSynonym(str, \"defs\");\n\n      str = \"type LAtomicStraightlineStep = StraightlineStep<PathAndTid<LAtomic_Path>, L.Armada_PC, LProcName>\";\n      pgp.AddTypeSynonym(str, \"defs\");\n\n      str = \"type LAtomicStraightlineBehavior = AnnotatedBehavior<LAtomicStraightlineState, LAtomicStraightlineStep>\";\n      pgp.AddTypeSynonym(str, \"defs\");\n\n      str = \"type LAtomicStraightlineBehaviorSpec = AnnotatedBehaviorSpec<LAtomicStraightlineState, LAtomicStraightlineStep>\";\n      pgp.AddTypeSynonym(str, \"defs\");\n\n      str = @\"\n        function PCToProc(pc:L.Armada_PC) : LProcName\n        {\n          match pc\n      \";\n      foreach (var pc in lpcs)\n      {\n        str += $\"    case {pc} => LProcName_{pc.methodName}\";\n      }\n      str += \"}\";\n      pgp.AddFunction(str, \"defs\");\n\n      str = @\"\n        predicate StateOK(s:LPlusState)\n        {\n          s.s.stop_reason.Armada_NotStopped?\n        }\n      \";\n      pgp.AddPredicate(str, \"defs\");\n\n      str = @\"\n        function GetCHLSpec() : AnnotatedBehaviorSpec<LPlusState, PathAndTid<LAtomic_Path>>\n        {\n          var asf := LAtomic_GetSpecFunctions();\n          AnnotatedBehaviorSpec(iset s | asf.init(s),\n                                iset s, s', path, tid | asf.path_valid(s, path, tid) && s' == asf.path_next(s, path, tid)\n                                                      :: ActionTuple(s, s', PathAndTid(path, tid)))\n        }\n      \";\n      pgp.AddFunction(str, \"defs\");\n\n      str = @\"\n        function PathAndTidToTid(path_and_tid:PathAndTid<LAtomic_Path>) : Option<Armada_ThreadHandle>\n        {\n          if path_and_tid.path.LAtomic_Path_Tau? then None else Some(path_and_tid.tid)\n        }\n      \";\n      pgp.AddFunction(str, \"defs\");\n\n      str = @\"\n        function GetThreadPCStack(s:LPlusState, tid:Armada_ThreadHandle) : Option<PCStack<L.Armada_PC, LProcName>>\n        {\n          if tid in s.s.threads then\n            var t := s.s.threads[tid];\n            Some(PCStack(t.pc, MapSeqToSeq(t.stack, (e:L.Armada_ExtendedFrame) => PCToProc(e.return_pc))))\n          else\n            None\n        }\n      \";\n      pgp.AddFunction(str, \"defs\");\n\n      str = @\"\n        function PathToProc(path: LAtomic_Path) : LProcName\n        {\n          match path\n      \";\n      str += String.Concat(lAtomic.AtomicPaths.Select(path => $@\"\n            case LAtomic_Path_{path.Name}(_) => LProcName_{pathEffectMap[path].ProcName}\n      \"));\n      str += \"}\";\n      pgp.AddFunction(str, \"defs\");\n\n      str = @\"\n        function PathAndTidToProc(path_and_tid: PathAndTid<LAtomic_Path>) : LProcName\n        {\n          PathToProc(path_and_tid.path)\n        }\n      \";\n      pgp.AddFunction(str, \"defs\");\n\n      str = @\"\n        function PathToEffect(path: LAtomic_Path) : CHLStepEffect<LProcName>\n        {\n          match path\n      \";\n      str += String.Concat(lAtomic.AtomicPaths.Select(path => $@\"\n            case LAtomic_Path_{path.Name}(_) => {pathEffectMap[path].Constructor}\n      \"));\n      str += \"}\";\n      pgp.AddFunction(str, \"defs\");\n\n      str = @\"\n        function PathAndTidToEffect(path_and_tid: PathAndTid<LAtomic_Path>) : CHLStepEffect<LProcName>\n        {\n          PathToEffect(path_and_tid.path)\n        }\n      \";\n      pgp.AddFunction(str, \"defs\");\n\n      str = @\"\n        predicate IsEntryPoint(pc: L.Armada_PC)\n        {\n      \";\n      str += String.Join(\" || \", lpcs.Where(pc => pc.instructionCount == 0).Select(pc => $\"pc.{pc}?\"));\n      str += \"}\";\n      pgp.AddPredicate(str, \"defs\");\n\n      str = @\"\n        predicate IsLoopHead(pc: L.Armada_PC)\n        {\n      \";\n      str += AH.CombineStringsWithOr(loopHeads.Select(pc => $\"pc.{pc}?\"));\n      str += \"}\";\n      pgp.AddPredicate(str, \"defs\");\n\n      str = @\"\n        predicate IsReturnSite(pc: L.Armada_PC)\n        {\n      \";\n      str += String.Join(\" || \", returnPCForMethod.Select(e => $\"pc.{e.Value}?\"));\n      str += \"}\";\n      pgp.AddPredicate(str, \"defs\");\n\n      str = @\"\n        predicate ThreadAtReturnSite(s: LPlusState, tid: Armada_ThreadHandle, proc: LProcName)\n        {\n          && tid in s.s.threads\n          && var pc := s.s.threads[tid].pc;\n          && IsReturnSite(pc)\n          && PCToProc(pc) == proc\n        }\n      \";\n      pgp.AddPredicate(str, \"defs\");\n\n      GenerateGlobalInvariant();\n      GenerateLocalInv();\n      GenerateYieldPredicate();\n      GenerateRequiresClauses();\n      GenerateEnsuresClauses();\n\n      GenerateInvariantProof(pgp);\n\n      var mapLiteral = string.Join(\", \", loopHeads.Select(pc => $\"L.{pc} := LoopModifies_{pc}\"));\n      str = @\"\n        predicate LoopModifiesClauses(pc:L.Armada_PC, s:LPlusState, s':LPlusState, tid:Armada_ThreadHandle)\n        {\n          && s.config == s'.config\n          && match pc\n      \";\n      str += String.Concat(loopHeads.Select(pc => $\"case {pc} => LoopModifies_{pc}(s, s', tid)\\n\"));\n      str += @\"\n            case _ => false\n        }\n      \";\n      pgp.AddPredicate(str, \"defs\");\n\n      str = @\"\n        function GetConcurrentHoareLogicRequest() : CHLRequest\n        {\n          ConcurrentHoareLogicRequest(GetCHLSpec(), PathAndTidToTid, PathAndTidToProc, GetThreadPCStack,\n                                      StateOK, PCToProc, IsEntryPoint, IsLoopHead,\n                                      IsReturnSite, PathAndTidToEffect, InductiveInv, GlobalInv, LocalInv,\n                                      YieldPredicate, RequiresClauses, EnsuresClauses, LoopModifiesClauses)\n        }\n      \";\n      pgp.AddFunction(str, \"defs\");\n\n      str = @\"\n        function GetAtomicConcurrentHoareLogicRequest() : AtomicCHLRequest\n        {\n          AtomicConcurrentHoareLogicRequest(GetConcurrentHoareLogicRequest(), LAtomic_GetSpecFunctions(), HAtomic_GetSpecFunctions(),\n                                            GetLPlusHRefinementRelation(), ConvertTotalState_LPlusH, ConvertAtomicPath_LH, ConvertPC_LH)\n        }\n      \";\n      pgp.AddFunction(str, \"defs\");\n    }\n\n    private void ParseProgram()\n    {\n      foreach (var methodName in pgp.symbolsHigh.MethodNames)\n      {\n        var methodInfo = pgp.symbolsHigh.AllMethods.LookupMethod(methodName);\n        var method = methodInfo.method;\n        TurnRequirementsIntoLocalPredicates(pgp.symbolsLow, method);\n        CreatePostconditionsPredicate(method);\n        if (method.Body is null)\n        {\n          // PC 1 corresponds to the head of the loop that repeatedly checks for the postcondition\n          var pc = new ArmadaPC(pgp.symbolsLow, methodName, 1);\n          loopHeads.Add(pc);\n          ProcessWhileStatementInvariants(pc, new List<MaybeFreeExpression>(), new List<Expression>());\n        }\n        else\n        {\n          foreach (var stmt in methodInfo.ParsedBody) {\n            if (stmt is ArmadaWhileStatement) {\n              var s = (ArmadaWhileStatement)stmt;\n              var ws = (WhileStmt)s.Stmt;\n              var lowPC = s.StartPC.CloneWithNewSymbolTable(pgp.symbolsLow);\n              loopHeads.Add(lowPC);\n              ProcessWhileStatementInvariants(lowPC, ws.Invariants, ws.Ens);\n            }\n          }\n        }\n      }\n    }\n\n    private string CreateStackCorrectAtStartPredicate(Method method)\n    {\n      var stackInvName = $\"StackCorrectAtStart_{method.Name}\";\n\n      // predicate {stackInvName}(s:LPlusState, tid:Armada_ThreadHandle)\n      // {\n      //   && tid in s.s.threads\n      //   && s.s.threads[tid].top.Armada_StackFrame_{method.Name}?\n      //   && s.s.threads[tid].pc.{initialPC}?\n      //   && <for each initialized variable, that variable's initialization doesn't crash>\n      // }\n\n      var initialPC = new ArmadaPC(pgp.symbolsLow, method.Name, 0);\n      var preds = new List<string>{ \"tid in s.s.threads\", $\"s.s.threads[tid].top.Armada_StackFrame_{method.Name}?\",\n                                    $\"s.s.threads[tid].pc.{initialPC}?\" };\n\n      var smst = pgp.symbolsLow.GetMethodSymbolTable(method.Name);\n      foreach (var v in smst.AllVariablesInOrder.Where(v => v.InitialValue != null))\n      {\n        var failureReporter = new SimpleFailureReporter(pgp.prog);\n        var context = new RequiresResolutionContext(\"s.s\", \"tid\", method.Name, pgp.symbolsLow, failureReporter, \"L\");\n        var ty = pgp.symbolsLow.FlattenType(v.ty);\n        var lhsRVal = v.GetRValue(v.InitialValue.tok, context);\n        var rhsRVal = context.ResolveAsRValue(v.InitialValue);\n        if (rhsRVal.UndefinedBehaviorAvoidance.CanCauseUndefinedBehavior) {\n          preds.Add(rhsRVal.UndefinedBehaviorAvoidance.Expr);\n        }\n\n        preds.Add($\"({lhsRVal.Val}) == ({rhsRVal.Val})\");\n      }\n\n      var str = $@\"\n        predicate {stackInvName}(s: LPlusState, tid: Armada_ThreadHandle)\n        {{\n          {AH.CombineStringsWithAnd(preds)}\n        }}\n      \";\n      pgp.AddPredicate(str, \"defs\");\n      return stackInvName;\n    }\n\n    private void TurnRequirementsIntoLocalPredicates(ArmadaSymbolTable symbols, Method method)\n    {\n      var preconditionNames = new List<string>();\n      preconditionsForMethod[method.Name] = preconditionNames;\n\n      var stackInvName = CreateStackCorrectAtStartPredicate(method);\n      if (extraPreconditionsForMethod.ContainsKey(method.Name)) {\n        preconditionNames.AddRange(extraPreconditionsForMethod[method.Name]);\n      }\n\n      int reqCount = 0;\n      foreach (var req in method.Req)\n      {\n        // predicate Precondition_{reqCount}_{method.Name}(s: LPlusState, tid: Armada_ThreadHandle)\n        //   requires tid in s.s.threads && s.s.threads[tid].top.Armada_StackFrame_{method.Name}?\n        // {\n        //   <things that prevent requires clause expression from crashing> && <requires clause>\n        // }\n\n        reqCount++;\n        var reqName = $\"Precondition_{reqCount}_{method.Name}\";\n        var failureReporter = new SimpleFailureReporter(pgp.prog);\n        var context = new RequiresResolutionContext(\"s.s\", \"tid\", method.Name, pgp.symbolsLow, failureReporter, \"L\");\n        if (!failureReporter.Valid) {\n          reqCount--;\n          continue;\n        }\n        var rvalue = context.ResolveAsRValue(req.E);\n        var body = rvalue.CanCauseUndefinedBehavior ? $\"({rvalue.UndefinedBehaviorAvoidance.Expr}) && ({rvalue.Val})\" : rvalue.Val;\n\n        var fn = $@\"\n          predicate {reqName}(s: LPlusState, tid: Armada_ThreadHandle)\n            requires tid in s.s.threads && s.s.threads[tid].top.Armada_StackFrame_{method.Name}?\n          {{\n            {body}\n          }}\n        \";\n        pgp.AddPredicate(fn, \"defs\");\n        preconditionNames.Add(reqName);\n      }\n\n      string str = $@\"\n        predicate Preconditions_{method.Name}(s:LPlusState, tid:Armada_ThreadHandle)\n        {{\n          {stackInvName}(s, tid)\n      \";\n      str += String.Concat(preconditionNames.Select(name => $\" && {name}(s, tid)\"));\n      str += \"}\\n\";\n      pgp.AddPredicate(str, \"defs\");\n    }\n\n    private void CreatePostconditionsPredicate(Method method)\n    {\n      var clauses = new List<string> {\n        \"s.config == s'.config\",\n        \"tid in s.s.threads\",\n        $\"s.s.threads[tid].top.Armada_StackFrame_{method.Name}?\",\n        \"tid in s'.s.threads\",\n        $\"s'.s.threads[tid].top.Armada_StackFrame_{method.Name}?\",\n        \"s'.s.threads[tid].stack == s.s.threads[tid].stack\"     // Include a clause indicating that the stack hasn't changed\n      };\n\n      // For each ensures clause, add a clause\n\n      if (method.Ens != null) {\n        foreach (var ens in method.Ens)\n        {\n          var failureReporter = new SimpleFailureReporter(pgp.prog);\n          var context = new EnsuresResolutionContext(\"s.s\", \"s'.s\", \"tid\", method.Name, pgp.symbolsLow, failureReporter, \"L\");\n          if (!failureReporter.Valid) {\n            continue;\n          }\n          var rvalue = context.ResolveAsRValue(ens.E);\n          if (rvalue.CanCauseUndefinedBehavior)\n          {\n            clauses.Add(rvalue.UndefinedBehaviorAvoidance.Expr);\n          }\n          clauses.Add(rvalue.Val);\n        }\n      }\n\n      // For each extra CHL postcondition, add a clause\n\n      if (extraPostconditionsForMethod.ContainsKey(method.Name)) {\n        foreach (var postconditionName in extraPostconditionsForMethod[method.Name]) {\n          clauses.Add($\"{postconditionName}(s, s', tid)\");\n        }\n      }\n      foreach (var topDecl in pgp.MainProof.Module.TopLevelDecls) {\n        if (topDecl is CHLYieldPredicateArmadaProofDecl d) {\n          if (method.Name == \"main\") {\n            continue;\n          }\n          if (Attributes.FindExpressions(d.Attributes, \"excludeMethod\")?\n              .Any(expr => (expr as NameSegment).Name == method.Name) ?? false) {\n            continue;\n          }\n          if (Attributes.Contains(d.Attributes, \"excludeAll\")) {\n            continue;\n          }\n          var ypKey = d.YieldPredicateName;\n          if (d.Code != null || pgp.symbolsLow.YieldPredicates.ContainsKey(ypKey)) {\n            var pred = $\"UserYP_{ypKey}(s, s', tid)\";\n            clauses.Add(pred);\n          }\n          else {\n            AH.PrintError(pgp.prog, d.tok, $\"No yield predicate named {ypKey} found among the yield predicates\");\n            continue;\n          }\n        }\n      }\n\n      // Create a post-condition two-state function out of the collected clauses\n\n      var fn = $@\"\n        predicate Postconditions_{method.Name}(s: LPlusState, s': LPlusState, tid: Armada_ThreadHandle)\n        {{\n          {AH.CombineStringsWithAnd(clauses)}\n        }}\n      \";\n      pgp.AddPredicate(fn, \"defs\");\n    }\n\n    private void ProcessWhileStatementInvariants(ArmadaPC pc, List<MaybeFreeExpression> invariants, List<Expression> ens)\n    {\n      // predicate LoopModifies_{pc}(s:LPlusState, s':LPlusState, tid:Armada_ThreadHandle)\n      // {\n      //   && tid in s.s.threads\n      //   && tid in s'.s.threads\n      //   && s.s.threads[tid].top.Armada_StackFrame_{pc.methodName}?\n      //   && s'.s.threads[tid].top.Armada_StackFrame_{pc.methodName}?\n      //   && s'.s.threads[tid].pc.{pc}?\n      //   && s'.s.threads[tid].stack == s.s.threads[tid].stack\n      //   && <Input and ExternOld variables unchanged>\n      //   && <custom loop invariants>\n      // }\n\n      var preds = new List<string> {\n        \"tid in s.s.threads\",\n        \"tid in s'.s.threads\",\n        $\"s.s.threads[tid].top.Armada_StackFrame_{pc.methodName}?\",\n        $\"s'.s.threads[tid].top.Armada_StackFrame_{pc.methodName}?\",\n        $\"s'.s.threads[tid].pc.{pc}?\",\n        \"s'.s.threads[tid].stack == s.s.threads[tid].stack\"\n      };\n\n      var smst = pgp.symbolsLow.GetMethodSymbolTable(pc.methodName);\n      foreach (var v in smst.AllVariablesInOrder.Where(v => v.varType == ArmadaVarType.Input || v.varType == ArmadaVarType.ExternOld))\n      {\n        preds.Add($\"s.s.threads[tid].top.{pc.methodName}.{v.name} == s'.s.threads[tid].top.{pc.methodName}.{v.name}\");\n      }\n\n      var failureReporter = new SimpleFailureReporter(pgp.prog);\n      var ensContext = new EnsuresResolutionContext(\"s.s\", \"s'.s\", \"tid\", pc.methodName, pgp.symbolsLow, failureReporter, \"L\");\n      foreach (var clause in ens)\n      {\n        var rvalue = ensContext.ResolveAsRValue(clause);\n        var e = rvalue.CanCauseUndefinedBehavior ? $\"({rvalue.UndefinedBehaviorAvoidance.Expr}) && ({rvalue.Val})\" : rvalue.Val;\n        preds.Add(e);\n      }\n\n      if (extraLoopModifiesClausesForPC.ContainsKey(pc)) {\n        foreach (var clauseName in extraLoopModifiesClausesForPC[pc]) {\n          preds.Add($\"{clauseName}(s, s', tid)\");\n        }\n      }\n\n      foreach (var topDecl in pgp.MainProof.Module.TopLevelDecls) {\n        if (topDecl is CHLYieldPredicateArmadaProofDecl d) {\n          if (Attributes.FindExpressions(d.Attributes, \"excludeLoop\")?\n              .Any(expr => (expr as NameSegment).Name == pc.methodName + \"_\" + pc.Name) ?? false) {\n            continue;\n          }\n          if (Attributes.Contains(d.Attributes, \"excludeAll\")) {\n            continue;\n          }\n          var ypKey = d.YieldPredicateName;\n          if (d.Code != null || pgp.symbolsLow.YieldPredicates.ContainsKey(ypKey)) {\n            preds.Add($\"UserYP_{ypKey}(s, s', tid)\");\n          }\n          else {\n            AH.PrintError(pgp.prog, d.tok, $\"No yield predicate named {ypKey} found among the yield predicates\");\n            continue;\n          }\n        }\n      }\n\n      var fn = $@\"\n        predicate LoopModifies_{pc}(s: LPlusState, s': LPlusState, tid: Armada_ThreadHandle)\n        {{\n          {AH.CombineStringsWithAnd(preds)}\n        }}\n      \";\n      pgp.AddPredicate(fn, \"defs\");\n    }\n\n    private void DeterminePCsWithEnablingConditions()\n    {\n      foreach (var pc in lpcs)\n      {\n        var methodInfo = pgp.symbolsHigh.AllMethods.LookupMethod(pc.methodName);\n        var collector = methodInfo.GetEnablingConstraintCollector(pcMap[pc]);\n        if (collector != null && !collector.Empty)\n        {\n          pcsWithEnablingConditions.Add(pc);\n          pcsWithLocalInvariants.Add(pc);\n        }\n      }\n    }\n\n    private void GenerateLocalInv()\n    {\n      string str;\n\n      str = @\"\n        predicate PCHasLocalInvariant(pc:L.Armada_PC)\n        {\n      \";\n      str += AH.CombineStringsWithOr(pcsWithLocalInvariants.Select(pc => $\"pc.{pc}?\"));\n      str += \"}\";\n      pgp.AddPredicate(str, \"defs\");\n\n      if (pcsWithLocalInvariants.Any()) {\n        str = @\"\n          predicate LocalInv(s:LPlusState, tid:Armada_ThreadHandle)\n          {\n            tid in s.s.threads ==>\n              H.Armada_UniversalStepConstraint(ConvertTotalState_LPlusH(s), tid) &&\n              var t := s.s.threads[tid];\n              PCHasLocalInvariant(t.pc) && InductiveInv(s) ==>\n                match t.pc\n        \";\n        foreach (var pc in pcsWithLocalInvariants) {\n          str += $\"case {pc} => t.top.Armada_StackFrame_{pc.methodName}?\";\n          if (pcsWithEnablingConditions.Contains(pc)) {\n            str += $\" && H.Armada_EnablingConditions_{pcMap[pc]}(ConvertTotalState_LPlusH(s), tid)\";\n          }\n          if (extraLocalInvariantClausesForPC.ContainsKey(pc)) {\n            foreach (var fnName in extraLocalInvariantClausesForPC[pc]) {\n              str += $\" && {fnName}(s, tid)\";\n            }\n          }\n          str += \"\\n\";\n        }\n        str += \"}\\n\";\n        pgp.AddPredicate(str, \"defs\");\n      }\n      else {\n        str = @\"\n          predicate LocalInv(s:LPlusState, tid:Armada_ThreadHandle)\n          {\n            tid in s.s.threads ==> PCHasLocalInvariant(s.s.threads[tid].pc)\n          }\n        \";\n        pgp.AddPredicate(str, \"defs\");\n      }\n    }\n\n    private void GenerateGlobalInvariant()\n    {\n      string allInvClauses = \"\";\n      string str;\n\n      var userInvariants = pgp.symbolsLow.GlobalInvariants;\n\n      foreach (var topDecl in pgp.MainProof.Module.TopLevelDecls) {\n        if (topDecl is CHLInvariantArmadaProofDecl) {\n          var d = (CHLInvariantArmadaProofDecl)topDecl;\n          var invKey = d.InvariantName;\n          var invName = d.InvariantName;\n          var attrs = d.CanBeRevealed() ? \"{:opaque}\" : \"\";\n          if (d.Code != null) {\n            invName = $\"UserInv_{invKey}\";\n            str = $@\"\n              predicate {attrs} {invName}(s: LPlusState)\n              {{\n                var threads := s.s.threads;\n                var globals := s.s.mem.globals;\n                var ghosts := s.s.ghosts;\n                var tid_init := s.config.tid_init;\n                { d.Code }\n              }}\n            \";\n            pgp.AddPredicate(str, \"defs\");\n            if (d.CanBeRevealed()) {\n              pgp.AddOpaqueUserDef(invName);\n            }\n          }\n          else if (userInvariants.ContainsKey(invKey)) {\n            var inv = userInvariants[invKey];\n            invName = $\"UserInv_{invKey}\";\n            str = $@\"\n              predicate {attrs} {invName}(s: LPlusState)\n              {{\n                L.{inv.TranslatedName}(s.s)\n              }}\n              \";\n            pgp.AddPredicate(str, \"defs\");\n            if (d.CanBeRevealed()) {\n              pgp.AddOpaqueUserDef(invName);\n            }\n          }\n          else {\n            AH.PrintError(pgp.prog, d.tok, $\"No invariant named {invKey} found among the invariants\");\n            continue;\n          }\n          globalInvariantInfos.Add(new CHLPredicateInfo(invKey, invName, d.CanBeRevealed()));\n          allInvClauses += $\"  && {invName}(s)\\n\";\n        }\n      }\n\n      var body = (allInvClauses.Length == 0) ? \"true\" : $\"InductiveInv(s) ==> {allInvClauses}\";\n\n      str = $@\"\n        predicate GlobalInv(s: LPlusState)\n        {{\n          var threads := s.s.threads;\n          var globals := s.s.mem.globals;\n          var ghosts := s.s.ghosts;\n          var tid_init := s.config.tid_init;\n          {body}\n        }}\n      \";\n      pgp.AddPredicate(str, \"defs\");\n    }\n\n    private void GenerateCustomCHLClauses()\n    {\n      string str;\n      foreach (var topDecl in pgp.MainProof.Module.TopLevelDecls) {\n        if (topDecl is CHLLocalInvariantArmadaProofDecl) {\n          var d = (CHLLocalInvariantArmadaProofDecl)topDecl;\n          var pc = pgp.symbolsLow.GetPCForMethodAndLabel(d.PCName);\n          if (pc == null) {\n            AH.PrintError(pgp.prog, $\"Could not find PC corresponding to CHL local invariant clause with specified label {d.PCName}\");\n          }\n          var methodName = pc.methodName;\n          var fnName = $\"UserLocalInvariant_{methodName}_{pc.Name}_{d.ClauseName}\";\n          var attrs = d.CanBeRevealed() ? \"{:opaque}\" : \"\";\n          str = $@\"\n            predicate {attrs} {fnName}(s:LPlusState, tid:Armada_ThreadHandle)\n              requires tid in s.s.threads\n              requires s.s.threads[tid].top.Armada_StackFrame_{methodName}?\n              requires InductiveInv(s)\n            {{\n              var threads := s.s.threads;\n              var globals := s.s.mem.globals;\n              var ghosts := s.s.ghosts;\n              var tid_init := s.config.tid_init;\n              { d.Code }\n            }}\n          \";\n          pgp.AddPredicate(str, \"defs\");\n          if (d.CanBeRevealed()) {\n            pgp.AddOpaqueUserDef(fnName);\n          }\n          pcsWithLocalInvariants.Add(pc);\n          if (!extraLocalInvariantClausesForPC.ContainsKey(pc)) {\n            extraLocalInvariantClausesForPC[pc] = new List<string>{ fnName };\n          }\n          else {\n            extraLocalInvariantClausesForPC[pc].Add(fnName);\n          }\n        }\n        else if (topDecl is CHLPreconditionArmadaProofDecl) {\n          var d = (CHLPreconditionArmadaProofDecl)topDecl;\n          var methodName = d.MethodName;\n          var preconditionName = $\"UserPrecondition_{methodName}_{d.PreconditionName}\";\n          var attrs = d.CanBeRevealed() ? \"{:opaque}\" : \"\";\n          str = $@\"\n            predicate {attrs} {preconditionName}(s:LPlusState, tid:Armada_ThreadHandle)\n              requires tid in s.s.threads\n              requires s.s.threads[tid].top.Armada_StackFrame_{methodName}?\n            {{\n              var threads := s.s.threads;\n              var globals := s.s.mem.globals;\n              var ghosts := s.s.ghosts;\n              var tid_init := s.config.tid_init;\n              { d.Code }\n            }}\n          \";\n          pgp.AddPredicate(str, \"defs\");\n          if (d.CanBeRevealed()) {\n            pgp.AddOpaqueUserDef(preconditionName);\n          }\n          if (!extraPreconditionsForMethod.ContainsKey(methodName)) {\n            extraPreconditionsForMethod[methodName] = new List<string>{ preconditionName };\n          }\n          else {\n            extraPreconditionsForMethod[methodName].Add(preconditionName);\n          }\n        }\n        else if (topDecl is CHLPostconditionArmadaProofDecl) {\n          var d = (CHLPostconditionArmadaProofDecl)topDecl;\n          var methodName = d.MethodName;\n          var postconditionName = $\"UserPostcondition_{methodName}_{d.PostconditionName}\";\n          var attrs = d.CanBeRevealed() ? \"{:opaque}\" : \"\";\n          str = $@\"\n            predicate {attrs} {postconditionName}(s:LPlusState, s':LPlusState, tid:Armada_ThreadHandle)\n              requires tid in s.s.threads\n              requires s.s.threads[tid].top.Armada_StackFrame_{methodName}?\n              requires tid in s'.s.threads\n              requires s'.s.threads[tid].top.Armada_StackFrame_{methodName}?\n            {{\n              var threads := s.s.threads;\n              var globals := s.s.mem.globals;\n              var ghosts := s.s.ghosts;\n              var tid_init := s.config.tid_init;\n              var threads' := s'.s.threads;\n              var globals' := s'.s.mem.globals;\n              var ghosts' := s'.s.ghosts;\n              { d.Code }\n            }}\n          \";\n          pgp.AddPredicate(str, \"defs\");\n          if (d.CanBeRevealed()) {\n            pgp.AddOpaqueUserDef(postconditionName);\n          }\n          if (!extraPostconditionsForMethod.ContainsKey(methodName)) {\n            extraPostconditionsForMethod[methodName] = new List<string>{ postconditionName };\n          }\n          else {\n            extraPostconditionsForMethod[methodName].Add(postconditionName);\n          }\n        }\n        else if (topDecl is CHLLoopModifiesClauseArmadaProofDecl) {\n          var d = (CHLLoopModifiesClauseArmadaProofDecl)topDecl;\n          var pc = pgp.symbolsLow.GetPCForMethodAndLabel(d.PCName);\n          if (pc == null) {\n            AH.PrintError(pgp.prog, $\"Could not find PC corresponding to CHL loop modifies clause with specified label {d.PCName}\");\n          }\n          var methodName = pc.methodName;\n          var fnName = $\"UserLoopModifies_{methodName}_{pc.Name}_{d.ClauseName}\";\n          var attrs = d.CanBeRevealed() ? \"{:opaque}\" : \"\";\n          str = $@\"\n            predicate {attrs} {fnName}(s:LPlusState, s':LPlusState, tid:Armada_ThreadHandle)\n              requires tid in s.s.threads\n              requires s.s.threads[tid].top.Armada_StackFrame_{methodName}?\n              requires tid in s'.s.threads\n              requires s'.s.threads[tid].top.Armada_StackFrame_{methodName}?\n            {{\n              var threads := s.s.threads;\n              var globals := s.s.mem.globals;\n              var ghosts := s.s.ghosts;\n              var tid_init := s.config.tid_init;\n              var threads' := s'.s.threads;\n              var globals' := s'.s.mem.globals;\n              var ghosts' := s'.s.ghosts;\n              { d.Code }\n            }}\n          \";\n          pgp.AddPredicate(str, \"defs\");\n          if (d.CanBeRevealed()) {\n            pgp.AddOpaqueUserDef(fnName);\n          }\n          if (!extraLoopModifiesClausesForPC.ContainsKey(pc)) {\n            extraLoopModifiesClausesForPC[pc] = new List<string>{ fnName };\n          }\n          else {\n            extraLoopModifiesClausesForPC[pc].Add(fnName);\n          }\n        }\n      }\n    }\n\n    private void GenerateYieldPredicate()\n    {\n      string allYieldClauses = \"\";\n      string str;\n\n      var userYPs = pgp.symbolsLow.YieldPredicates;\n\n      foreach (var topDecl in pgp.MainProof.Module.TopLevelDecls) {\n        if (topDecl is CHLYieldPredicateArmadaProofDecl) {\n          var d = (CHLYieldPredicateArmadaProofDecl)topDecl;\n          var ypKey = d.YieldPredicateName;\n          var ypName = d.YieldPredicateName;\n          var attrs = d.CanBeRevealed() ? \"{:opaque}\" : \"\";\n          if (d.Code != null) {\n            ypName = $\"UserYP_{ypKey}\";\n            str = $@\"\n              predicate {attrs} {ypName}(s:LPlusState, s':LPlusState, tid:Armada_ThreadHandle)\n              {{\n                var threads := s.s.threads;\n                var globals := s.s.mem.globals;\n                var ghosts := s.s.ghosts;\n                var tid_init := s.config.tid_init;\n                var threads' := s'.s.threads;\n                var globals' := s'.s.mem.globals;\n                var ghosts' := s'.s.ghosts;\n                {d.Code}\n              }}\n            \";\n            pgp.AddPredicate(str, \"defs\");\n            if (d.CanBeRevealed()) {\n              pgp.AddOpaqueUserDef(ypName);\n            }\n          }\n          else if (userYPs.ContainsKey(ypKey)) {\n            ypName = $\"UserYP_{ypKey}\";\n            var yp = userYPs[ypKey];\n            str = $@\"\n              predicate {attrs} {ypName}(s:LPlusState, s':LPlusState, tid:Armada_ThreadHandle)\n              {{\n                tid in s.s.threads && tid in s'.s.threads ==> L.{yp.TranslatedName}(s.s, s'.s, tid)\n              }}\n            \";\n            pgp.AddPredicate(str, \"defs\");\n            if (d.CanBeRevealed()) {\n              pgp.AddOpaqueUserDef(ypName);\n            }\n          }\n          else {\n            AH.PrintError(pgp.prog, d.tok, $\"No yield predicate named {ypKey} found among the yield predicates\");\n            continue;\n          }\n          yieldPredicateInfos.Add(new CHLPredicateInfo(ypKey, ypName, d.CanBeRevealed()));\n          allYieldClauses += $\"  && {ypName}(s, s', tid)\\n\";\n        }\n      }\n\n      str = @\"\n        predicate YieldPredicateBasic(s:LPlusState, s':LPlusState, tid:Armada_ThreadHandle)\n        {\n          && tid in s.s.threads\n          && tid in s'.s.threads\n          && s'.s.threads[tid].pc == s.s.threads[tid].pc\n          && s'.s.threads[tid].top == s.s.threads[tid].top\n          && s'.s.threads[tid].stack == s.s.threads[tid].stack\n          && s'.config == s.config\n          && s'.s.stop_reason.Armada_NotStopped?\n        }\n      \";\n      pgp.AddPredicate(str, \"defs\");\n\n      str = $@\"\n        predicate YieldPredicate(s:LPlusState, s':LPlusState, tid:Armada_ThreadHandle)\n        {{\n          YieldPredicateBasic(s, s', tid)\n          {allYieldClauses}\n        }}\n      \";\n      pgp.AddPredicate(str, \"defs\");\n    }\n\n    private void GenerateRequiresClauses()\n    {\n      var str = @\"\n        predicate RequiresClauses(proc:LProcName, s:LPlusState, tid:Armada_ThreadHandle)\n        {\n          match proc\n      \";\n      foreach (var methodName in pgp.symbolsLow.MethodNames)\n      {\n        str += $\"    case LProcName_{methodName} => Preconditions_{methodName}(s, tid)\";\n      }\n      str += \"}\";\n      pgp.AddPredicate(str, \"defs\");\n    }\n\n    private void GenerateEnsuresClauses()\n    {\n      var str = @\"\n        predicate EnsuresClauses(proc:LProcName, s:LPlusState, s':LPlusState, tid:Armada_ThreadHandle)\n        {\n          match proc\n      \";\n      foreach (var methodName in pgp.symbolsLow.MethodNames)\n      {\n        str += $\"    case LProcName_{methodName} => Postconditions_{methodName}(s, s', tid)\";\n      }\n      str += \"}\";\n      pgp.AddPredicate(str, \"defs\");\n    }\n\n    private void GeneratePathPCStackEffectLemmas()\n    {\n      pcstackFile = pgp.proofFiles.CreateAuxiliaryProofFile(\"pcstack\");\n      pcstackFile.IncludeAndImportGeneratedFile(\"specs\");\n      pcstackFile.IncludeAndImportGeneratedFile(\"pceffect\");\n      pcstackFile.IncludeAndImportGeneratedFile(\"revelations\");\n      pcstackFile.IncludeAndImportGeneratedFile(\"latomic\");\n      pcstackFile.IncludeAndImportGeneratedFile(\"defs\");\n      pcstackFile.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/strategies/chl/AtomicConcurrentHoareLogicSpec.i.dfy\");\n      pcstackFile.AddImport(\"ConcurrentHoareLogicSpecModule\");\n      pcstackFile.AddImport(\"AtomicConcurrentHoareLogicSpecModule\");\n      pcstackFile.AddIncludeImport(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/option.s.dfy\", \"util_option_s\");\n      pcstackFile.AddIncludeImport(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/maps.i.dfy\", \"util_collections_maps_i\");\n      pcstackFile.AddIncludeImport(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/seqs.i.dfy\", \"util_collections_seqs_i\");\n      pcstackFile.AddImport(\"util_collections_seqs_s\");\n      pgp.proofFiles.MainProof.IncludeAndImportGeneratedFile(\"pcstack\");\n\n      string str;\n      var pr = new PathPrinter(lAtomic);\n      foreach (var atomicPath in lAtomic.AtomicPaths)\n      {\n        str = $@\"\n          lemma lemma_LAtomic_PathHasPCStackEffect_{atomicPath.Name}(\n            s: LPlusState,\n            s': LPlusState,\n            path: LAtomic_Path,\n            tid: Armada_ThreadHandle\n            )\n            requires LAtomic_NextPath(s, s', path, tid)\n            requires path.LAtomic_Path_{atomicPath.Name}?\n            ensures  tid in s.s.threads\n            ensures  s.s.stop_reason.Armada_NotStopped?\n            ensures  s'.config == s.config\n        \";\n\n        // What PC it starts at\n\n        if (!atomicPath.Tau) {\n          str += $\"ensures  s.s.threads[tid].pc.{atomicPath.StartPC}?\\n\";\n        }\n\n        // What constraints there are on the initial stack\n\n        var effect = pathEffectMap[atomicPath];\n        if (effect is CHLPathEffectReturn) {\n          var reffect = (CHLPathEffectReturn)effect;\n          str += $@\"\n            ensures |s.s.threads[tid].stack| > 0\n            ensures s.s.threads[tid].stack[0].return_pc.{reffect.EffectiveStartPC}?\n          \";\n        }\n        else if (effect is CHLPathEffectReturnThenCall) {\n          var rceffect = (CHLPathEffectReturnThenCall)effect;\n          str += $@\"\n            ensures |s.s.threads[tid].stack| > 0\n            ensures s.s.threads[tid].stack[0].return_pc.{rceffect.EffectiveStartPC}?\n          \";\n        }\n        else if (effect is CHLPathEffectExit) {\n          str += \"ensures |s.s.threads[tid].stack| == 0\\n\";\n        }\n\n        // Constraints on the subsequent PC and stack\n\n        if (atomicPath.Stopping) {\n          str += \"ensures !s'.s.stop_reason.Armada_NotStopped?\\n\";\n        }\n        else {\n          str += \"ensures s'.s.stop_reason.Armada_NotStopped?\\n\";\n\n          // Constraints on the subsequent PC\n\n          if (atomicPath.Tau) {\n            str += \"ensures tid in s'.s.threads\\n\";\n          }\n          else if (atomicPath.EndPC == null) {\n            str += $\"ensures tid !in s'.s.threads\\n\";\n          }\n          else {\n            str += $@\"\n              ensures tid in s'.s.threads\n              ensures s'.s.threads[tid].pc.{atomicPath.EndPC}?\n            \";\n          }\n\n          // Constraints on the subsequent stack\n\n          if (effect is CHLPathEffectNormal) {\n            str += \"ensures s'.s.threads[tid].stack == s.s.threads[tid].stack\\n\";\n          }\n          else if (effect is CHLPathEffectCall) {\n            var ceffect = (CHLPathEffectCall)effect;\n            str += $@\"\n              ensures |s'.s.threads[tid].stack| > 0\n              ensures s'.s.threads[tid].stack[0].return_pc.{ceffect.EffectiveEndPC}?\n              ensures s'.s.threads[tid].stack[1..] == s.s.threads[tid].stack\n            \";\n          }\n          else if (effect is CHLPathEffectReturn) {\n            str += $@\"\n              ensures s'.s.threads[tid].stack == s.s.threads[tid].stack[1..]\n            \";\n          }\n          else if (effect is CHLPathEffectReturnThenCall) {\n            var rceffect = (CHLPathEffectReturnThenCall)effect;\n            str += $@\"\n              ensures |s'.s.threads[tid].stack| > 0\n              ensures s'.s.threads[tid].stack[0].return_pc.{rceffect.EffectiveEndPC}?\n              ensures s'.s.threads[tid].stack[1..] == s.s.threads[tid].stack[1..]\n            \";\n          }\n          else if (effect is CHLPathEffectActorless) {\n            str += \"ensures s'.s.threads[tid].stack == s.s.threads[tid].stack\\n\";\n          }\n        }\n\n        str += $@\"\n          {{\n            { pr.GetOpenValidPathInvocation(atomicPath) }\n          }}\n        \";\n        pgp.AddLemma(str, \"pcstack\");\n      }\n\n      str = @\"\n        lemma lemma_PathImpliesThreadRunning(\n          s: LPlusState,\n          path: LAtomic_Path,\n          tid: Armada_ThreadHandle\n          )\n          ensures  var asf := LAtomic_GetSpecFunctions();\n                   asf.path_valid(s, path, tid) ==> asf.state_ok(s) && asf.get_thread_pc(s, tid).Some?\n        {\n          var asf := LAtomic_GetSpecFunctions();\n          if asf.path_valid(s, path, tid) {\n            var s' := asf.path_next(s, path, tid);\n            match path {\n      \";\n      str += String.Concat(lAtomic.AtomicPaths.Select(atomicPath => $@\"\n            case LAtomic_Path_{atomicPath.Name}(_) =>\n              lemma_LAtomic_PathHasPCStackEffect_{atomicPath.Name}(s, s', path, tid);\n      \"));\n      str += \"} } }\\n\";\n      pgp.AddLemma(str, \"pcstack\");\n\n      str = @\"\n        lemma lemma_PathLeavesConfigUnchanged(\n          s: LPlusState,\n          s': LPlusState,\n          path: LAtomic_Path,\n          tid: Armada_ThreadHandle\n          )\n          requires LAtomic_NextPath(s, s', path, tid)\n          ensures  s'.config == s.config\n        {\n          match path {\n      \";\n      str += String.Concat(lAtomic.AtomicPaths.Select(atomicPath => $@\"\n            case LAtomic_Path_{atomicPath.Name}(_) =>\n              lemma_LAtomic_PathHasPCStackEffect_{atomicPath.Name}(s, s', path, tid);\n      \"));\n      str += \"} }\\n\";\n      pgp.AddLemma(str, \"pcstack\");\n\n      str = @\"\n        lemma lemma_CHLStepEffectsCorrect()\n          ensures  CHLStepEffectsCorrect(GetConcurrentHoareLogicRequest())\n        {\n          var cr := GetConcurrentHoareLogicRequest();\n          forall s, s', step | ActionTuple(s, s', step) in cr.spec.next\n            ensures CorrectCHLStepEffect(cr, s, s', step)\n          {\n            var path: LAtomic_Path := step.path;\n            var tid := step.tid;\n\n            match path {\n      \";\n      str += String.Concat(lAtomic.AtomicPaths.Select(p => $@\"\n            case LAtomic_Path_{p.Name}(_) =>\n              lemma_LAtomic_PathHasPCStackEffect_{p.Name}(s, s', path, tid);\n      \"));\n      str += \"} } }\\n\";\n      pgp.AddLemma(str, \"pcstack\");\n\n      foreach (var pc in lpcs)\n      {\n        str = $@\"\n          predicate PathPossibilitiesStartingAtPC_{pc}(path: LAtomic_Path)\n          {{\n        \";\n        str += AH.CombineStringsWithOr(pathsStartingAtPC[pc].Select(p => $\"path.LAtomic_Path_{p.Name}?\"));\n        str += \"}\";\n        pgp.AddPredicate(str, \"pcstack\");\n\n        str = $@\"\n          lemma lemma_PathPossibilitiesStartingAtPC_{pc}(s: LPlusState, s': LPlusState, path: LAtomic_Path, tid: Armada_ThreadHandle)\n            requires LAtomic_NextPath(s, s', path, tid)\n            requires !path.LAtomic_Path_Tau?\n            requires tid in s.s.threads\n            requires s.s.threads[tid].pc.{pc}?\n            ensures  PathPossibilitiesStartingAtPC_{pc}(path)\n          {{\n            match path {{\n        \";\n        str += String.Concat(lAtomic.AtomicPaths.Where(p => !p.Tau).Select(p => $@\"\n            case LAtomic_Path_{p.Name}(_) =>\n              lemma_LAtomic_PathHasPCStackEffect_{p.Name}(s, s', path, tid);\n        \"));\n        str += \"} }\";\n        pgp.AddLemma(str, \"pcstack\");\n      }\n\n      foreach (var methodName in pgp.symbolsLow.MethodNames)\n      {\n        str = $@\"\n          predicate PathPossibilitiesReturningFrom_{methodName}(path: LAtomic_Path)\n          {{\n        \";\n        str += AH.CombineStringsWithOr(pathsStartingAtPC[returnPCForMethod[methodName]]\n                                       .Select(p => $\"path.LAtomic_Path_{p.Name}?\"));\n        str += \"}\";\n        pgp.AddPredicate(str, \"pcstack\");\n\n        str = $@\"\n          lemma lemma_PathPossibilitiesReturningFrom_{methodName}(\n            s: LPlusState,\n            s': LPlusState,\n            path: LAtomic_Path,\n            tid: Armada_ThreadHandle\n            )\n            requires LAtomic_NextPath(s, s', path, tid)\n            requires !path.LAtomic_Path_Tau?\n            requires tid in s.s.threads\n            requires IsReturnSite(s.s.threads[tid].pc)\n            requires PCToProc(s.s.threads[tid].pc).LProcName_{methodName}?\n            ensures  PathPossibilitiesReturningFrom_{methodName}(path)\n          {{\n            match path {{\n        \";\n        str += String.Concat(lAtomic.AtomicPaths.Where(p => !p.Tau).Select(p => $@\"\n            case LAtomic_Path_{p.Name}(_) =>\n              lemma_LAtomic_PathHasPCStackEffect_{p.Name}(s, s', path, tid);\n        \"));\n        str += \"} }\";\n        pgp.AddLemma(str, \"pcstack\");\n      }\n    }\n\n    private void GenerateProofThatCHLRequestIsValid()\n    {\n      GenerateGlobalInvLemmas();\n      GenerateYieldPredicateLemmas();\n      GenerateInitialInvariantLemmas();\n      GenerateStepsDontAffectOtherActorsLemmas();\n      GenerateForkedActorsStartAtEntryPointsWithEmptyStacks();\n      GenerateStraightlineBehaviorProofs();\n    }\n\n    private void GenerateStepsDontAffectOtherActorsLemmas()\n    {\n      var othersFile = pgp.proofFiles.CreateAuxiliaryProofFile(\"others\");\n      othersFile.IncludeAndImportGeneratedFile(\"specs\");\n      othersFile.IncludeAndImportGeneratedFile(\"defs\");\n      othersFile.IncludeAndImportGeneratedFile(\"revelations\");\n      othersFile.IncludeAndImportGeneratedFile(\"latomic\");\n      othersFile.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/strategies/chl/AtomicConcurrentHoareLogicSpec.i.dfy\");\n      othersFile.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/strategies/generic/GenericArmadaAtomic.i.dfy\");\n      othersFile.AddImport(\"ConcurrentHoareLogicSpecModule\");\n      othersFile.AddImport(\"AtomicConcurrentHoareLogicSpecModule\");\n      othersFile.AddIncludeImport(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/option.s.dfy\", \"util_option_s\");\n      othersFile.AddImport(\"util_collections_seqs_s\");\n      othersFile.AddImport(\"GenericArmadaAtomicModule\");\n      pgp.proofFiles.MainProof.IncludeAndImportGeneratedFile(\"others\");\n\n      string postcondition = @\"forall other_tid ::\n                               (other_tid != tid || asf.path_type(path).AtomicPathType_Tau?) && other_tid in s.s.threads ==>\n                               var s' := asf.path_next(s, path, tid);\n                               && other_tid in s'.s.threads\n                               && s'.s.threads[other_tid].pc == s.s.threads[other_tid].pc\n                               && s'.s.threads[other_tid].top == s.s.threads[other_tid].top\n                               && s'.s.threads[other_tid].stack == s.s.threads[other_tid].stack\";\n      lAtomic.GeneratePerAtomicPathLemma(\"others\",\n                                         \"AtomicPathCantAffectOtherThreadsExceptViaFork\",\n                                         atomicPath => true,\n                                         atomicPath => postcondition,\n                                         atomicPath => \"\",\n                                         false);\n      lAtomic.GenerateOverallAtomicPathLemma(\"others\",\n                                             \"AtomicPathCantAffectOtherThreadsExceptViaFork\",\n                                             \"AtomicPathCantAffectOtherThreadsExceptViaFork\",\n                                             postcondition,\n                                             ap => true);\n\n      string str = $@\"\n        lemma lemma_StepsDontChangeOtherActorsExceptViaFork()\n          ensures StepsDontChangeOtherActorsExceptViaFork(GetConcurrentHoareLogicRequest())\n        {{\n          var cr := GetConcurrentHoareLogicRequest();\n          forall s, s', step, other_actor | StepsDontChangeOtherActorsExceptViaForkConditions(cr, s, s', step, other_actor)\n            ensures cr.get_actor_pc_stack(s', other_actor) == cr.get_actor_pc_stack(s, other_actor)\n          {{\n            var asf := LAtomic_GetSpecFunctions();\n            lemma_LAtomic_AtomicPathCantAffectOtherThreadsExceptViaFork(asf, s, step.path, step.tid);\n          }}\n        }}\n      \";\n      pgp.AddLemma(str, \"others\");\n    }\n\n    private void GenerateForkedActorsStartAtEntryPointsWithEmptyStacks()\n    {\n      var forkedStacksFile = pgp.proofFiles.CreateAuxiliaryProofFile(\"ForkedStack\");\n      forkedStacksFile.IncludeAndImportGeneratedFile(\"specs\");\n      forkedStacksFile.IncludeAndImportGeneratedFile(\"defs\");\n      forkedStacksFile.IncludeAndImportGeneratedFile(\"revelations\");\n      forkedStacksFile.IncludeAndImportGeneratedFile(\"latomic\");\n      forkedStacksFile.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/strategies/chl/AtomicConcurrentHoareLogicSpec.i.dfy\");\n      forkedStacksFile.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/strategies/generic/GenericArmadaAtomic.i.dfy\");\n      forkedStacksFile.AddImport(\"ConcurrentHoareLogicSpecModule\");\n      forkedStacksFile.AddImport(\"AtomicConcurrentHoareLogicSpecModule\");\n      forkedStacksFile.AddIncludeImport(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/option.s.dfy\", \"util_option_s\");\n      forkedStacksFile.AddImport(\"util_collections_seqs_s\");\n      forkedStacksFile.AddImport(\"GenericArmadaAtomicModule\");\n      pgp.proofFiles.MainProof.IncludeAndImportGeneratedFile(\"ForkedStack\");\n\n      string str;\n\n      var postcondition = @\"forall forked_tid :: forked_tid !in s.s.threads && forked_tid in asf.path_next(s, path, tid).s.threads ==>\n                        var cr := GetConcurrentHoareLogicRequest();\n                        var s' := asf.path_next(s, path, tid);\n                        && cr.step_to_actor(PathAndTid(path, tid)).Some?\n                        && !cr.step_to_effect(PathAndTid(path, tid)).CHLStepEffectExit?\n                        && var PCStack(pc', stack') := cr.get_actor_pc_stack(s', forked_tid).v;\n                        && cr.is_entry_point(pc')\n                        && |stack'| == 0\";\n      lAtomic.GeneratePerAtomicPathLemma(\"ForkedStack\",\n                                         \"ForkedActorsStartAtEntryPointsWithEmptyStacks\",\n                                         atomicPath => true,\n                                         atomicPath => postcondition,\n                                         atomicPath => \"\",\n                                         false);\n      lAtomic.GenerateOverallAtomicPathLemma(\"ForkedStack\",\n                                             \"ForkedActorsStartAtEntryPointsWithEmptyStacks\",\n                                             \"ForkedActorsStartAtEntryPointsWithEmptyStacks\",\n                                             postcondition,\n                                             atomicPath => true);\n      str = $@\"\n        lemma lemma_ForkedActorsStartAtEntryPointsWithEmptyStacks()\n          ensures ForkedActorsStartAtEntryPointsWithEmptyStacks(GetConcurrentHoareLogicRequest())\n        {{\n          var cr := GetConcurrentHoareLogicRequest();\n          forall s, s', step, forked_actor | ForkedActorsStartAtEntryPointsWithEmptyStacksConditions(cr, s, s', step, forked_actor)\n            ensures cr.step_to_actor(step).Some?\n            ensures !cr.step_to_effect(step).CHLStepEffectExit?\n            ensures var PCStack(pc', stack') := cr.get_actor_pc_stack(s', forked_actor).v;\n                    && cr.is_entry_point(pc')\n                    && |stack'| == 0\n          {{\n            var asf := LAtomic_GetSpecFunctions();\n            lemma_LAtomic_ForkedActorsStartAtEntryPointsWithEmptyStacks(asf, s, step.path, step.tid);\n          }}\n        }}\n      \";\n      pgp.AddLemma(str, \"ForkedStack\");\n    }\n\n    private void GenerateGlobalInvLemmas()\n    {\n      string str;\n      string lemmaInvocations = \"\";\n\n      var pr = new PathPrinter(lAtomic);\n      foreach (var globalInvariantInfo in globalInvariantInfos)\n      {\n        str = $@\"\n          lemma lemma_ActorlessStepsMaintainSpecificGlobalInv_{globalInvariantInfo.Key}(\n            s: LPlusState,\n            s': LPlusState,\n            path: LAtomic_Path,\n            tid: Armada_ThreadHandle\n            )\n            requires path.LAtomic_Path_Tau?\n            requires InductiveInv(s)\n            requires GlobalInv(s)\n            requires LAtomic_NextPath(s, s', path, tid)\n            requires InductiveInv(s')\n            ensures  {globalInvariantInfo.Value}(s')\n          {{\n            { pr.GetOpenValidPathInvocation(lAtomic.TauPath) }\n            ProofCustomizationGoesHere();\n          }}\n        \";\n        pgp.AddLemma(str);\n        lemmaInvocations += $@\"\n          lemma_ActorlessStepsMaintainSpecificGlobalInv_{globalInvariantInfo.Key}(s, s', path, tid);\n        \";\n      }\n\n      str = $@\"\n        lemma lemma_ActorlessStepsMaintainGlobalInv(\n          s: LPlusState,\n          s': LPlusState,\n          path: LAtomic_Path,\n          tid: Armada_ThreadHandle\n          )\n          requires path.LAtomic_Path_Tau?\n          requires InductiveInv(s)\n          requires GlobalInv(s)\n          requires LAtomic_NextPath(s, s', path, tid)\n          ensures  GlobalInv(s')\n          ensures  s'.s.stop_reason.Armada_NotStopped?\n        {{\n          if InductiveInv(s') {{\n            { lemmaInvocations }\n          }}\n          lemma_LAtomic_PathHasPCStackEffect_Tau(s, s', path, tid);\n        }}\n      \";\n      pgp.AddLemma(str);\n    }\n\n    private void GenerateYieldPredicateLemmas()\n    {\n      string str;\n\n      var pr = new PathPrinter(lAtomic);\n\n      foreach (var yieldPredicateInfo in yieldPredicateInfos)\n      {\n        string yieldPredicateName = yieldPredicateInfo.Key;\n        string fullyQualifiedYPName = yieldPredicateInfo.Value;\n\n        str = $@\"\n          lemma lemma_YieldPredicateReflexive_{yieldPredicateName}(s:LPlusState, actor:Armada_ThreadHandle)\n            requires s.s.stop_reason.Armada_NotStopped?\n            requires actor in s.s.threads\n            ensures {fullyQualifiedYPName}(s, s, actor)\n          {{\n            ProofCustomizationGoesHere();\n          }}\n        \";\n        pgp.AddLemma(str);\n\n        str = $@\"\n          lemma lemma_YieldPredicateTransitive_{yieldPredicateName}(\n            s1: LPlusState,\n            s2: LPlusState,\n            s3: LPlusState,\n            actor: Armada_ThreadHandle\n            )\n            requires InductiveInv(s1)\n            requires GlobalInv(s1)\n            requires InductiveInv(s2)\n            requires GlobalInv(s2)\n            requires actor in s1.s.threads\n            requires actor in s2.s.threads\n            requires actor in s3.s.threads\n            requires YieldPredicate(s1, s2, actor)\n            requires YieldPredicate(s2, s3, actor)\n            ensures  {fullyQualifiedYPName}(s1, s3, actor)\n          {{\n            ProofCustomizationGoesHere();\n          }}\n        \";\n        pgp.AddLemma(str);\n\n        str = $@\"\n          lemma lemma_ActorlessStepsMaintainYieldPredicate_{yieldPredicateName}(\n            s: LPlusState,\n            s': LPlusState,\n            path: LAtomic_Path,\n            tid: Armada_ThreadHandle,\n            actor: Armada_ThreadHandle\n            )\n            requires path.LAtomic_Path_Tau?\n            requires InductiveInv(s)\n            requires GlobalInv(s)\n            requires LAtomic_NextPath(s, s', path, tid)\n            requires GlobalInv(s')\n            ensures  {fullyQualifiedYPName}(s, s', actor)\n          {{\n            { pr.GetOpenValidPathInvocation(lAtomic.TauPath) }\n            ProofCustomizationGoesHere();\n          }}\n        \";\n        pgp.AddLemma(str);\n      }\n\n      str = @\"\n        lemma lemma_YieldPredicateReflexive()\n          ensures YieldPredicateReflexive(GetConcurrentHoareLogicRequest())\n        {\n          var cr := GetConcurrentHoareLogicRequest();\n          forall s, actor {:trigger cr.yield_pred(s, s, actor)} | cr.state_ok(s) && cr.get_actor_pc_stack(s, actor).Some?\n            ensures cr.yield_pred(s, s, actor)\n          {\n      \";\n      foreach (var yieldPredicateInfo in yieldPredicateInfos)\n      {\n        str += $\"lemma_YieldPredicateReflexive_{yieldPredicateInfo.Key}(s, actor);\\n\";\n      }\n      str += @\"\n          }\n        }\n      \";\n      pgp.AddLemma(str);\n\n      str = @\"\n        lemma lemma_YieldPredicateTransitive()\n          ensures YieldPredicateTransitive(GetConcurrentHoareLogicRequest())\n        {\n          forall s1, s2, s3, actor |\n            && InductiveInv(s1)\n            && GlobalInv(s1)\n            && InductiveInv(s2)\n            && GlobalInv(s2)\n            && YieldPredicate(s1, s2, actor)\n            && YieldPredicate(s2, s3, actor)\n            ensures YieldPredicate(s1, s3, actor)\n          {\n            if actor in s1.s.threads && actor in s2.s.threads && actor in s3.s.threads {\n      \";\n      foreach (var yieldPredicateInfo in yieldPredicateInfos)\n      {\n        str += $\"        lemma_YieldPredicateTransitive_{yieldPredicateInfo.Key}(s1, s2, s3, actor);\";\n      }\n      str += @\"\n            }\n          }\n        }\n      \";\n      pgp.AddLemma(str);\n\n      str = $@\"\n        lemma lemma_ActorlessStepsMaintainYieldPredicateAndGlobalInvariant()\n          ensures ActorlessStepsMaintainYieldPredicateAndGlobalInvariant(GetConcurrentHoareLogicRequest())\n        {{\n          var cr := GetConcurrentHoareLogicRequest();\n          forall s, s', step, actor | ActorlessStepsMaintainYieldPredicateAndGlobalInvariantConditions(cr, s, s', step, actor)\n            ensures YieldPredicate(s, s', actor)\n            ensures GlobalInv(s')\n            ensures s'.s.stop_reason.Armada_NotStopped?\n          {{\n            var path: LAtomic_Path := step.path;\n            var tid := step.tid;\n\n            assert path.LAtomic_Path_Tau?;\n\n            { pr.GetOpenValidPathInvocation(lAtomic.TauPath) }\n            ProofCustomizationGoesHere();\n\n            assert InductiveInv(s);\n            assert GlobalInv(s);\n            assert LAtomic_NextPath(s, s', step.path, step.tid);\n            lemma_ActorlessStepsMaintainGlobalInv(s, s', step.path, step.tid);\n      \";\n      foreach (var yieldPredicateInfo in yieldPredicateInfos)\n      {\n        str += $@\"\n            lemma_ActorlessStepsMaintainYieldPredicate_{yieldPredicateInfo.Key}(s, s', step.path, step.tid, actor);\n        \";\n      }\n      str += @\"\n          }\n        }\n      \";\n      pgp.AddLemma(str);\n    }\n\n    private void GenerateInitialInvariantLemmas()\n    {\n      string str;\n      string body = \"\";\n\n      foreach (var globalInvariantInfo in globalInvariantInfos)\n      {\n        str = $@\"\n          lemma lemma_GlobalInvariantSatisfiedInitially_{globalInvariantInfo.Key}(s:LPlusState)\n            requires LPlus_Init(s)\n            ensures  {globalInvariantInfo.Value}(s)\n          {{\n            ProofCustomizationGoesHere();\n          }}\n        \";\n        pgp.AddLemma(str);\n\n        body += $\"lemma_GlobalInvariantSatisfiedInitially_{globalInvariantInfo.Key}(s);\\n\";\n      }\n\n      str = $@\"\n        lemma lemma_GlobalInvariantSatisfiedInInitialState(s:LPlusState)\n          requires LPlus_Init(s)\n          ensures  GlobalInv(s)\n        {{\n          {body}\n        }}\n      \";\n      pgp.AddLemma(str);\n\n      body = \"\";\n\n      str = @\"\n        lemma lemma_RequiresClausesSatisfiedInInitialState(s:LPlusState, tid:Armada_ThreadHandle)\n          requires LPlus_Init(s)\n          requires tid in s.s.threads\n          ensures  RequiresClauses(LProcName_main, s, tid)\n        {\n          assert Preconditions_main(s, tid);\n        }\n      \";\n      pgp.AddLemma(str);\n\n      str = @\"\n        lemma lemma_GlobalInvariantSatisfiedInitially()\n          ensures  GlobalInvariantSatisfiedInitially(GetConcurrentHoareLogicRequest())\n        {\n          var cr := GetConcurrentHoareLogicRequest();\n          forall s | s in cr.spec.init\n            ensures cr.global_inv(s)\n          {\n            lemma_GlobalInvariantSatisfiedInInitialState(s);\n          }\n       }\n      \";\n      pgp.AddLemma(str);\n\n      str = @\"\n        lemma lemma_RequiresClausesSatisfiedInitially()\n          ensures  RequiresClausesSatisfiedInitially(GetConcurrentHoareLogicRequest())\n        {\n          var cr := GetConcurrentHoareLogicRequest();\n          forall s, actor | RequiresClausesSatisfiedInitiallyConditions(cr, s, actor)\n            ensures cr.requires_clauses(cr.pc_to_proc(cr.get_actor_pc_stack(s, actor).v.pc), s, actor)\n          {\n            lemma_RequiresClausesSatisfiedInInitialState(s, actor);\n            assert cr.pc_to_proc(cr.get_actor_pc_stack(s, actor).v.pc) == LProcName_main;\n          }\n        }\n      \";\n      pgp.AddLemma(str);\n    }\n\n    private void GenerateIsValidConcurrentHoareLogicRequest()\n    {\n      string str;\n\n      var pr = new PathPrinter(lAtomic);\n\n      str = @\"\n        lemma lemma_IsInvariantPredicateOfSpec()\n          ensures IsInvariantPredicateOfSpec(InductiveInv, GetCHLSpec())\n        {\n          var inv := InductiveInv;\n          var spec := GetCHLSpec();\n\n          forall s | s in spec.init\n            ensures inv(s)\n          {\n            lemma_InitImpliesInductiveInv(s);\n          }\n\n          forall s, s', step | inv(s) && ActionTuple(s, s', step) in spec.next\n            ensures inv(s')\n          {\n            lemma_AtomicPathMaintainsInductiveInv(s, s', step.path, step.tid);\n          }\n\n          lemma_EstablishInvariantPredicatePure(inv, spec);\n        }\n      \";\n      pgp.AddLemma(str);\n\n      str = @\"\n        lemma lemma_LoopHeadsArentReturnSites()\n          ensures LoopHeadsArentReturnSites(IsLoopHead, IsReturnSite)\n        {\n        }\n      \";\n      pgp.AddLemma(str);\n\n      str = @\"\n        lemma lemma_ActorsBeginAtEntryPointsWithEmptyStacks()\n          ensures ActorsBeginAtEntryPointsWithEmptyStacks(GetConcurrentHoareLogicRequest())\n        {\n        }\n      \";\n      pgp.AddLemma(str);\n\n      str = $@\"\n        lemma lemma_ActorlessStepsDontChangeActors()\n          ensures ActorlessStepsDontChangeActors(GetConcurrentHoareLogicRequest())\n        {{\n          var cr := GetConcurrentHoareLogicRequest();\n          forall s, s', step, actor {{:trigger ActorlessStepsDontChangeActorsConditions(cr, s, s', step, actor)}}\n            | ActorlessStepsDontChangeActorsConditions(cr, s, s', step, actor)\n            ensures cr.get_actor_pc_stack(s', actor) == cr.get_actor_pc_stack(s, actor)\n          {{\n            var path: LAtomic_Path := step.path;\n            var tid := step.tid;\n\n            { pr.GetOpenValidPathInvocation(lAtomic.TauPath) }\n          }}\n        }}\n      \";\n      pgp.AddLemma(str);\n\n      str = @\"\n        lemma lemma_IsValidConcurrentHoareLogicRequest()\n          ensures  IsValidConcurrentHoareLogicRequest(GetConcurrentHoareLogicRequest())\n        {\n          lemma_IsInvariantPredicateOfSpec();\n          lemma_LoopHeadsArentReturnSites();\n          lemma_YieldPredicateReflexive();\n          lemma_YieldPredicateTransitive();\n          lemma_ActorsBeginAtEntryPointsWithEmptyStacks();\n          lemma_GlobalInvariantSatisfiedInitially();\n          lemma_RequiresClausesSatisfiedInitially();\n          lemma_ActorlessStepsDontChangeActors();\n          lemma_ActorlessStepsMaintainYieldPredicateAndGlobalInvariant();\n          lemma_CHLStepEffectsCorrect();\n          lemma_ForkedActorsStartAtEntryPointsWithEmptyStacks();\n          lemma_StepsDontChangeOtherActorsExceptViaFork();\n          lemma_StraightlineBehaviorsSatisfyGlobalInvariant();\n          lemma_StraightlineBehaviorsSatisfyLocalInvariant();\n          lemma_StraightlineBehaviorsSatisfyPreconditionsForCalls();\n          lemma_StraightlineBehaviorsSatisfyPreconditionsForForks();\n          lemma_StraightlineBehaviorsSatisfyPostconditions();\n          lemma_StraightlineBehaviorsSatisfyLoopModifiesClausesOnEntry();\n          lemma_StraightlineBehaviorsSatisfyLoopModifiesClausesOnJumpBack();\n          lemma_StraightlineBehaviorsSatisfyYieldPredicate();\n        }\n        \";\n      pgp.AddLemma(str);\n    }\n\n    private void AddAllSuffixesOfStraightlineBehavior(StraightlineBehavior behavior)\n    {\n      straightlineBehaviorDescriptors.Add(behavior);\n      if (behavior.LastState is StraightlineStateNormal) {\n        sbdsEndingNormal.Add(behavior);\n      }\n      if (behavior.LastState is StraightlineStateYielded) {\n        sbdsEndingYielded.Add(behavior);\n      }\n      if (behavior.LastState is StraightlineStateEnsured) {\n        sbdsEndingEnsured.Add(behavior);\n      }\n      foreach (var successorStep in behavior.LastState.GetSuccessorSteps(pathsStartingAtPC, loopHeads,\n                                                                         pathEffectMap, returnPCForMethod, pcsWithLocalInvariants)) {\n        var extension = new StraightlineBehavior(behavior, successorStep);\n        AddAllSuffixesOfStraightlineBehavior(extension);\n      }\n    }\n\n    private void CreateStraightlineBehaviors()\n    {\n      foreach (var methodName in pgp.symbolsLow.MethodNames)\n      {\n        var entryPoint = new ArmadaPC(pgp.symbolsLow, methodName, 0);\n        var behavior = new StraightlineBehavior(entryPoint);\n        emptyStraightlineBehaviorForMethod[methodName] = behavior;\n        AddAllSuffixesOfStraightlineBehavior(behavior);\n      }\n    }\n\n    private void GenerateStraightlineBehaviorDescriptors()\n    {\n      sbdFile = pgp.proofFiles.CreateAuxiliaryProofFile(\"sbd\");\n      sbdFile.IncludeAndImportGeneratedFile(\"specs\");\n      sbdFile.IncludeAndImportGeneratedFile(\"defs\");\n      sbdFile.IncludeAndImportGeneratedFile(\"revelations\");\n      sbdFile.IncludeAndImportGeneratedFile(\"latomic\");\n      sbdFile.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/strategies/chl/AtomicConcurrentHoareLogicSpec.i.dfy\");\n      sbdFile.AddImport(\"ConcurrentHoareLogicSpecModule\");\n      sbdFile.AddImport(\"AtomicConcurrentHoareLogicSpecModule\");\n      sbdFile.AddIncludeImport(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/option.s.dfy\", \"util_option_s\");\n      sbdFile.AddImport(\"util_collections_seqs_s\");\n      pgp.proofFiles.MainProof.IncludeAndImportGeneratedFile(\"sbd\");\n\n      string str;\n\n      str = \"datatype StraightlineBehaviorDescriptor = \";\n      str += String.Join(\" | \", straightlineBehaviorDescriptors.Select(sb => $\"SBD_{sb.Name}\"));\n      pgp.AddDatatype(str, \"sbd\");\n\n      var extractorSTrace = new ExtractorSTrace(\"strace\", \"proc\");\n      foreach (var sbd in straightlineBehaviorDescriptors)\n      {\n        str = $@\"\n          predicate StraightlineBehaviorSatisfiesDescriptor_{sbd.Name}(strace:seq<LAtomicStraightlineStep>, proc:LProcName)\n          {{\n        \";\n        str += String.Join(\" && \", sbd.GetSatisfiesDescriptorClauses(extractorSTrace));\n        str += \"}\";\n        pgp.AddPredicate(str, \"sbd\");\n\n        str = $@\"\n          predicate StraightlineBehaviorFullySatisfiesDescriptor_{sbd.Name}(strace:seq<LAtomicStraightlineStep>, proc:LProcName)\n          {{\n            && |strace| == {sbd.NumSteps}\n            && StraightlineBehaviorSatisfiesDescriptor_{sbd.Name}(strace, proc)\n          }}\n        \";\n        pgp.AddPredicate(str, \"sbd\");\n      }\n\n      str = @\"\n        predicate StraightlineBehaviorFullySatisfiesDescriptor(strace:seq<LAtomicStraightlineStep>, proc:LProcName,\n                                                               sbd:StraightlineBehaviorDescriptor)\n        {\n          match sbd\n      \";\n      str += String.Concat(straightlineBehaviorDescriptors.Select(sbd => $@\"\n        case SBD_{sbd.Name} => StraightlineBehaviorFullySatisfiesDescriptor_{sbd.Name}(strace, proc)\n      \"));\n      str += \"}\\n\";\n      pgp.AddPredicate(str, \"sbd\");\n    }\n\n    private void GenerateStraightlineBehaviorDescriptorExhaustiveLemmas()\n    {\n      exhaustiveFile = pgp.proofFiles.CreateAuxiliaryProofFile(\"exhaustive\");\n      exhaustiveFile.IncludeAndImportGeneratedFile(\"specs\");\n      exhaustiveFile.IncludeAndImportGeneratedFile(\"defs\");\n      exhaustiveFile.IncludeAndImportGeneratedFile(\"revelations\");\n      exhaustiveFile.IncludeAndImportGeneratedFile(\"latomic\");\n      exhaustiveFile.IncludeAndImportGeneratedFile(\"sbd\");\n      exhaustiveFile.IncludeAndImportGeneratedFile(\"pcstack\");\n      exhaustiveFile.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/strategies/chl/AtomicConcurrentHoareLogicSpec.i.dfy\");\n      exhaustiveFile.AddImport(\"ConcurrentHoareLogicSpecModule\");\n      exhaustiveFile.AddImport(\"AtomicConcurrentHoareLogicSpecModule\");\n      exhaustiveFile.AddIncludeImport(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/option.s.dfy\", \"util_option_s\");\n      exhaustiveFile.AddImport(\"util_collections_seqs_s\");\n      pgp.proofFiles.MainProof.IncludeAndImportGeneratedFile(\"exhaustive\");\n\n      string str;\n\n      str = @\"\n        function GetLAtomicStraightlineSpec(tid:Armada_ThreadHandle, proc:LProcName) : LAtomicStraightlineBehaviorSpec\n        {\n          GetStraightlineSpec(GetConcurrentHoareLogicRequest(), tid, proc)\n        }\n      \";\n      pgp.AddFunction(str, \"exhaustive\");\n\n      var extractorSB = new ExtractorSB(\"sb\", \"tid\", \"proc\");\n\n      foreach (var sbd in straightlineBehaviorDescriptors)\n      {\n        str = $@\"\n          lemma lemma_StraightlineBehaviorEndProperties_{sbd.Name}(\n            sb:LAtomicStraightlineBehavior,\n            tid:Armada_ThreadHandle,\n            proc:LProcName\n            )\n            requires AnnotatedBehaviorSatisfiesSpec(sb, GetLAtomicStraightlineSpec(tid, proc))\n            requires StraightlineBehaviorSatisfiesDescriptor_{sbd.Name}(sb.trace, proc)\n            ensures  proc.LProcName_{sbd.MethodName}?\n        \";\n        foreach (var c in sbd.LastState.GetEndProperties(extractorSB))\n        {\n          str += $\"ensures {c}\\n\";\n        }\n        str += \"{\\n\";\n        str += sbd.GetProofOfEndProperties(extractorSB);\n        str += \"}\\n\";\n        pgp.AddLemma(str, \"exhaustive\");\n      }\n\n      foreach (var sbd in straightlineBehaviorDescriptors)\n      {\n        str = $@\"\n          lemma lemma_GetFullDescriptorForStraightlineBehavior_{sbd.Name}(\n            sb:LAtomicStraightlineBehavior,\n            tid:Armada_ThreadHandle,\n            proc:LProcName\n            ) returns (\n            sbd:StraightlineBehaviorDescriptor\n            )\n            requires AnnotatedBehaviorSatisfiesSpec(sb, GetLAtomicStraightlineSpec(tid, proc))\n            requires StraightlineBehaviorSatisfiesDescriptor_{sbd.Name}(sb.trace, proc)\n            ensures  StraightlineBehaviorFullySatisfiesDescriptor(sb.trace, proc, sbd)\n          {{\n            if |sb.trace| == {sbd.NumSteps} {{\n              sbd := SBD_{sbd.Name};\n              return;\n            }}\n        \";\n        foreach (var successor in sbd.Successors) {\n          str += $@\"\n            if StraightlineBehaviorSatisfiesDescriptor_{successor.Name}(sb.trace, proc) {{\n              sbd := lemma_GetFullDescriptorForStraightlineBehavior_{successor.Name}(sb, tid, proc);\n              return;\n            }}\n          \";\n        }\n\n        str += $@\"\n          lemma_StraightlineBehaviorEndProperties_{sbd.Name}(sb, tid, proc);\n\n          var sspec := GetLAtomicStraightlineSpec(tid, proc);\n          assert ActionTuple(sb.states[{sbd.NumSteps}], sb.states[{sbd.NumSteps}+1], sb.trace[{sbd.NumSteps}]) in sspec.next;\n        \";\n        str += sbd.LastState.ProofOfLimitedNextSSteps(extractorSB);\n        str += \"}\";\n        pgp.AddLemma(str, \"exhaustive\");\n      }\n\n      str = $@\"\n        lemma lemma_GetFullDescriptorForStraightlineBehavior(\n          sb:LAtomicStraightlineBehavior,\n          tid:Armada_ThreadHandle,\n          proc:LProcName\n          ) returns (\n          sbd:StraightlineBehaviorDescriptor\n          )\n          requires AnnotatedBehaviorSatisfiesSpec(sb, GetLAtomicStraightlineSpec(tid, proc))\n          ensures  StraightlineBehaviorFullySatisfiesDescriptor(sb.trace, proc, sbd)\n        {{\n          match proc {{\n      \";\n      str += String.Concat(emptyStraightlineBehaviorForMethod.Select(item => $@\"\n            case LProcName_{item.Key} =>\n              sbd := lemma_GetFullDescriptorForStraightlineBehavior_{item.Value.Name}(sb, tid, proc);\n      \"));\n      str += \"} }\\n\";\n      pgp.AddLemma(str, \"exhaustive\");\n    }\n\n    private void GenerateStraightlineBehaviorDescriptorEndLemma(string phase, IEnumerable<StraightlineBehavior> sbds)\n    {\n      string str;\n\n      str = $@\"\n        predicate StraightlineBehaviorDescriptorEnds{phase}Possibilities(sbd:StraightlineBehaviorDescriptor)\n        {{\n      \";\n      str += AH.CombineStringsWithOr(sbds.Select(sbd => $\"sbd.SBD_{sbd.Name}?\"));\n      str += \"}\";\n      pgp.AddPredicate(str, \"continuation\");\n\n      str = $@\"\n        lemma lemma_GetFullDescriptorForStraightlineBehaviorEnding{phase}(\n          sb:LAtomicStraightlineBehavior,\n          tid:Armada_ThreadHandle,\n          proc:LProcName\n          ) returns (\n          sbd:StraightlineBehaviorDescriptor\n          )\n          requires AnnotatedBehaviorSatisfiesSpec(sb, GetLAtomicStraightlineSpec(tid, proc))\n          requires last(sb.states).aux.phase.StraightlinePhase{phase}?\n          ensures  StraightlineBehaviorFullySatisfiesDescriptor(sb.trace, proc, sbd)\n          ensures  StraightlineBehaviorDescriptorEnds{phase}Possibilities(sbd)\n        {{\n          sbd := lemma_GetFullDescriptorForStraightlineBehavior(sb, tid, proc);\n          match sbd {{\n      \";\n      str += String.Concat(straightlineBehaviorDescriptors.Select(sbd => $@\"\n            case SBD_{sbd.Name} =>\n              lemma_StraightlineBehaviorEndProperties_{sbd.Name}(sb, tid, proc);\n      \"));\n      str += \"} }\\n\";\n      pgp.AddLemma(str, \"continuation\");\n    }\n\n    private void GenerateStraightlineBehaviorDescriptorContinuationLemmas()\n    {\n      var continuationFile = pgp.proofFiles.CreateAuxiliaryProofFile(\"continuation\");\n      continuationFile.IncludeAndImportGeneratedFile(\"specs\");\n      continuationFile.IncludeAndImportGeneratedFile(\"defs\");\n      continuationFile.IncludeAndImportGeneratedFile(\"latomic\");\n      continuationFile.IncludeAndImportGeneratedFile(\"sbd\");\n      continuationFile.IncludeAndImportGeneratedFile(\"pcstack\");\n      continuationFile.IncludeAndImportGeneratedFile(\"exhaustive\");\n      continuationFile.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/strategies/chl/AtomicConcurrentHoareLogicSpec.i.dfy\");\n      continuationFile.AddImport(\"ConcurrentHoareLogicSpecModule\");\n      continuationFile.AddImport(\"AtomicConcurrentHoareLogicSpecModule\");\n      continuationFile.AddIncludeImport(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/option.s.dfy\", \"util_option_s\");\n      continuationFile.AddImport(\"util_collections_seqs_s\");\n      pgp.proofFiles.MainProof.IncludeAndImportGeneratedFile(\"continuation\");\n\n      GenerateStraightlineBehaviorDescriptorEndLemma(\"Ensured\", sbdsEndingEnsured);\n      GenerateStraightlineBehaviorDescriptorEndLemma(\"Yielded\", sbdsEndingYielded);\n\n      string str;\n\n      foreach (var sbd in sbdsEndingYielded.Concat(sbdsEndingEnsured))\n      {\n        str = $@\"\n          predicate StraightlineBehaviorNonstoppingContinuationPossibilities_{sbd.Name}(path:LAtomic_Path)\n          {{\n        \";\n        str += AH.CombineStringsWithOr(sbd.PotentialSuccessorPaths\n                                          .Where(tup => tup.Item2.CanFollow(sbd.LastState))\n                                          .Select(tup => $\"path.LAtomic_Path_{tup.Item1.Name}?\"));\n        str += \"}\";\n        pgp.AddPredicate(str, \"continuation\");\n\n        str = $@\"\n          lemma lemma_StraightlineBehaviorNonstoppingContinuationPossibilities_{sbd.Name}(\n            sb: LAtomicStraightlineBehavior,\n            tid: Armada_ThreadHandle,\n            proc: LProcName,\n            s': LPlusState,\n            path: LAtomic_Path\n            )\n            requires AnnotatedBehaviorSatisfiesSpec(sb, GetLAtomicStraightlineSpec(tid, proc))\n            requires StraightlineBehaviorFullySatisfiesDescriptor(sb.trace, proc, SBD_{sbd.Name})\n            requires LAtomic_NextPath(last(sb.states).state, s', path, tid)\n            requires !path.LAtomic_Path_Tau?\n            requires !PathToEffect(path).CHLStepEffectStop?\n            requires var effect := PathToEffect(path);\n         \";\n        if (sbd.LastState is StraightlineStateEnsured) {\n          str += $\"effect.CHLStepEffectReturn? || effect.CHLStepEffectReturnThenCall?\\n\";\n        }\n        else {\n          str += $\"!effect.CHLStepEffectReturn? && !effect.CHLStepEffectReturnThenCall?\\n\";\n        }\n        str += $@\"\n            ensures  StraightlineBehaviorNonstoppingContinuationPossibilities_{sbd.Name}(path)\n          {{\n            var ss := last(sb.states);\n            assert ss == sb.states[{sbd.NumSteps}];\n            var s := sb.states[{sbd.NumSteps}].state;\n            assert s == ss.state;\n            lemma_StraightlineBehaviorEndProperties_{sbd.Name}(sb, tid, proc);\n        \";\n        if (sbd.LastState is StraightlineStateEnsured) {\n          var callee = ((StraightlineStateEnsured) sbd.LastState).Callee;\n          str += $\"lemma_PathPossibilitiesReturningFrom_{callee}(s, s', path, tid);\\n\";\n        }\n        else {\n          str += $\"lemma_PathPossibilitiesStartingAtPC_{sbd.LastState.PC}(s, s', path, tid);\\n\";\n        }\n        str += String.Concat(sbd.PotentialSuccessorPaths.Where(tup => !tup.Item2.CanFollow(sbd.LastState)).Select(tup => $@\"\n              if path.LAtomic_Path_{tup.Item1.Name}? {{\n                lemma_LAtomic_PathHasPCStackEffect_{tup.Item1.Name}(s, s', path, tid);\n                assert false;\n              }}\n          \"));\n          str += \"}\\n\";\n        pgp.AddLemma(str, \"continuation\");\n      }\n    }\n\n    private void GenerateStraightlineBehaviorDescriptorEnumerationLemmas()\n    {\n      var enumerationFile = pgp.proofFiles.CreateAuxiliaryProofFile(\"enumeration\");\n      enumerationFile.IncludeAndImportGeneratedFile(\"specs\");\n      enumerationFile.IncludeAndImportGeneratedFile(\"defs\");\n      enumerationFile.IncludeAndImportGeneratedFile(\"latomic\");\n      enumerationFile.IncludeAndImportGeneratedFile(\"invariants\");\n      enumerationFile.IncludeAndImportGeneratedFile(\"sbd\");\n      enumerationFile.IncludeAndImportGeneratedFile(\"pcstack\");\n      enumerationFile.IncludeAndImportGeneratedFile(\"exhaustive\");\n      enumerationFile.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/strategies/chl/AtomicConcurrentHoareLogicSpec.i.dfy\");\n      enumerationFile.AddImport(\"ConcurrentHoareLogicSpecModule\");\n      enumerationFile.AddImport(\"AtomicConcurrentHoareLogicSpecModule\");\n      enumerationFile.AddIncludeImport(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/option.s.dfy\", \"util_option_s\");\n      enumerationFile.AddImport(\"util_collections_seqs_s\");\n\n      string str;\n\n      var extractorSB = new ExtractorSB(\"sb\", \"tid\", \"proc\");\n      foreach (var sbd in sbdsEndingYielded.Concat(sbdsEndingEnsured).Concat(sbdsEndingNormal)) {\n        str = $@\"\n          lemma lemma_EnumerateStraightlineBehaviorHelper_{sbd.Name}(\n            cr: CHLRequest,\n            sb: LAtomicStraightlineBehavior,\n            tid: Armada_ThreadHandle,\n            proc: LProcName\n            )\n            requires cr.spec == GetCHLSpec()\n            requires cr.step_to_actor == PathAndTidToTid\n            requires cr.step_to_proc == PathAndTidToProc\n            requires cr.get_actor_pc_stack == GetThreadPCStack\n            requires cr.state_ok == StateOK\n            requires cr.pc_to_proc == PCToProc\n            requires cr.is_entry_point == IsEntryPoint\n            requires cr.is_loop_head == IsLoopHead\n            requires cr.is_return_site == IsReturnSite\n            requires cr.step_to_effect == PathAndTidToEffect\n            requires proc.LProcName_{sbd.MethodName}?\n            requires AnnotatedBehaviorSatisfiesSpec(sb, GetStraightlineSpec(cr, tid, proc))\n            requires StraightlineBehaviorFullySatisfiesDescriptor(sb.trace, proc, SBD_{sbd.Name})\n        \";\n        foreach (var s in sbd.GetEnumerationClauses(extractorSB, false /* expanded */, true /* crRelative */)) {\n          str += $\"ensures {s}\\n\";\n        }\n        str += $@\"\n          {{\n            var sspec := GetStraightlineSpec(cr, tid, proc);\n        \";\n        str += String.Concat(Enumerable.Range(0, sbd.NumSteps).Select(i => $@\"\n            assert ActionTuple(sb.states[{i}], sb.states[{i}+1], sb.trace[{i}]) in sspec.next;\n        \"));\n        str += \"}\\n\";\n        pgp.AddLemma(str, \"enumeration\");\n\n        str = $@\"\n          lemma lemma_EnumerateStraightlineBehavior_{sbd.Name}(\n            sb:LAtomicStraightlineBehavior,\n            tid:Armada_ThreadHandle,\n            proc:LProcName\n            )\n            requires AnnotatedBehaviorSatisfiesSpec(sb, GetLAtomicStraightlineSpec(tid, proc))\n            requires StraightlineBehaviorFullySatisfiesDescriptor(sb.trace, proc, SBD_{sbd.Name})\n        \";\n        foreach (var s in sbd.GetEnumerationClauses(extractorSB)) {\n          str += $\"ensures {s}\\n\";\n        }\n        str += $@\"\n          {{\n            assert proc.LProcName_{sbd.MethodName}?;\n            lemma_EnumerateStraightlineBehaviorHelper_{sbd.Name}(GetConcurrentHoareLogicRequest(), sb, tid, proc);\n          }}\n        \";\n        str += \"}\\n\";\n        pgp.AddLemma(str, \"enumeration\");\n      }\n    }\n\n    private void GenerateStraightlineBehaviorsSatisfyGlobalInvariantProof()\n    {\n      string str;\n\n      var alwaysFile = pgp.proofFiles.CreateAuxiliaryProofFile(\"GlobalInvAlways\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"specs\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"invariants\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"defs\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"latomic\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"sbd\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"exhaustive\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"continuation\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"enumeration\");\n      alwaysFile.AddImport(\"AtomicConcurrentHoareLogicSpecModule\");\n      alwaysFile.AddImport(\"ConcurrentHoareLogicSpecModule\");\n      alwaysFile.AddImport(\"util_collections_seqs_s\");\n      pgp.proofFiles.MainProof.IncludeAndImportGeneratedFile(\"GlobalInvAlways\");\n\n      // If the global invariant is just \"true\", generate a very simple lemma:\n\n      if (!globalInvariantInfos.Any()) {\n        str = @\"\n          lemma lemma_StraightlineBehaviorsSatisfyGlobalInvariant()\n            ensures StraightlineBehaviorsSatisfyGlobalInvariant(GetConcurrentHoareLogicRequest())\n          {\n            var cr := GetConcurrentHoareLogicRequest();\n            forall sb, step, s' {:trigger StraightlineBehaviorsSatisfyGlobalInvariantConditions(cr, sb, step, s')}\n              | StraightlineBehaviorsSatisfyGlobalInvariantConditions(cr, sb, step, s')\n              ensures cr.global_inv(s')\n            {\n            }\n          }\n        \";\n        pgp.AddLemma(str, \"GlobalInvAlways\");\n\n        return;\n      }\n\n      // Otherwise, create two files for each global invariant, one to reason about all straightline behaviors\n      // and one to reason about specific straightline behaviors.\n\n      foreach (var item in globalInvariantInfos)\n      {\n        var invName = item.Key;\n\n        var invFile = pgp.proofFiles.CreateAuxiliaryProofFile($\"GlobalInv_{invName}\");\n        invFile.IncludeAndImportGeneratedFile(\"specs\");\n        invFile.IncludeAndImportGeneratedFile(\"defs\");\n        invFile.IncludeAndImportGeneratedFile(\"revelations\");\n        invFile.IncludeAndImportGeneratedFile(\"invariants\");\n        invFile.IncludeAndImportGeneratedFile(\"latomic\");\n        alwaysFile.IncludeAndImportGeneratedFile($\"GlobalInv_{invName}\");\n      }\n\n      var extractorEnumeration = new ExtractorEnumeration(lAtomic);\n      var extractorSB = new ExtractorSB(\"sb\", \"tid\", \"proc\");\n      foreach (var sbd in sbdsEndingYielded.Concat(sbdsEndingEnsured))\n      {\n        foreach (var atomicPath in sbd.PotentialSuccessorPaths.Where(tup => tup.Item2.CanFollow(sbd.LastState))\n                                                              .Select(tup => tup.Item1))\n        {\n          var beyondEnd = new StraightlineStepBeyondEnd(sbd.NumSteps, atomicPath, pcsWithLocalInvariants.Contains(sbd.LastState.PC));\n          var sbdPlus = new StraightlineBehavior(sbd, beyondEnd);\n          var pathExpander = new PathExpander(sbdPlus);\n          var extractorExpanded = new ExtractorExpanded(pathExpander);\n\n          var expandedParamDeclarations =\n            String.Join(\", \", new List<string>{ \"tid: Armada_ThreadHandle\" }\n                               .Concat(sbdPlus.GetStatesAndSteps(extractorExpanded, true)));\n          var expandedParamValues =\n            String.Join(\", \", new List<string>{ \"tid\" }\n                                .Concat(sbdPlus.GetStatesAndSteps(extractorEnumeration, false)));\n\n          var enumeratedParamDeclarations =\n            String.Join(\", \", new List<string> { \"tid: Armada_ThreadHandle\" }\n                               .Concat(sbdPlus.GetStatesAndPaths(extractorEnumeration, true)));\n          var enumeratedParamValues =\n            String.Join(\", \", new List<string>{ \"tid\" }\n                                .Concat(sbd.GetStatesAndPaths(extractorSB, false))\n                                .Concat(new List<string>{ \"path\", \"s'\" }));\n\n          foreach (var globalInvariantInfo in globalInvariantInfos)\n          {\n            var invName = globalInvariantInfo.Key;\n            var invPred = globalInvariantInfo.Value;\n            str = $@\"\n              lemma lemma_ExpandedStraightlineBehaviorSatisfiesGlobalInvariant_{invName}_{sbd.Name}_Then_{atomicPath.Name}(\n                {expandedParamDeclarations}\n              )\n            \";\n            str += String.Concat(sbdPlus.GetEnumerationClauses(extractorExpanded, true).Select(r => \"requires \" + r + \"\\n\"));\n            str += $@\"\n                requires InductiveInv({extractorExpanded.State(sbd.NumSteps + 1)})\n                ensures  {invPred}({extractorExpanded.State(sbd.NumSteps + 1)})\n              {{\n                ProofCustomizationGoesHere();\n              }}\n            \";\n            pgp.AddLemma(str, $\"GlobalInv_{invName}\");\n\n            str = $@\"\n              lemma lemma_EnumeratedStraightlineBehaviorSatisfiesGlobalInvariant_{invName}_{sbd.Name}_Then_{atomicPath.Name}(\n                {enumeratedParamDeclarations}\n              )\n            \";\n            str += String.Concat(sbdPlus.GetEnumerationClauses(extractorEnumeration, false).Select(r => \"requires \" + r + \"\\n\"));\n            str += $@\"\n                requires InductiveInv(s{sbd.NumSteps + 1})\n                ensures  {invPred}(s{sbd.NumSteps + 1})\n              {{\n                { String.Concat(sbd.GetOpenValidPathInvocations(extractorEnumeration)) }\n                { extractorEnumeration.GetOpenValidPathInvocation(atomicPath, sbd.NumSteps) }\n                lemma_ExpandedStraightlineBehaviorSatisfiesGlobalInvariant_{invName}_{sbd.Name}_Then_{atomicPath.Name}(\n                  {expandedParamValues}\n                );\n              }}\n            \";\n            pgp.AddLemma(str, $\"GlobalInv_{invName}\");\n          }\n\n          str = $@\"\n            lemma lemma_StraightlineBehaviorSatisfiesGlobalInvariant_{sbd.Name}_Then_{atomicPath.Name}(\n              sb: LAtomicStraightlineBehavior,\n              path: LAtomic_Path,\n              tid: Armada_ThreadHandle,\n              s': LPlusState\n              )\n              requires path.LAtomic_Path_{atomicPath.Name}?\n              requires AnnotatedBehaviorSatisfiesSpec(sb, GetLAtomicStraightlineSpec(tid, LProcName_{sbd.MethodName}))\n              requires LocalInv(last(sb.states).state, tid)\n              requires LAtomic_NextPath(last(sb.states).state, s', path, tid)\n              requires StraightlineBehaviorFullySatisfiesDescriptor(sb.trace, LProcName_{sbd.MethodName}, SBD_{sbd.Name})\n              ensures  GlobalInv(s')\n            {{\n              var proc := LProcName_{sbd.MethodName};\n              lemma_EnumerateStraightlineBehavior_{sbd.Name}(sb, tid, proc);\n              if InductiveInv(s') {{\n          \";\n          str += String.Concat(globalInvariantInfos.Select(info => info.Key).Select(invName => $@\"\n                lemma_EnumeratedStraightlineBehaviorSatisfiesGlobalInvariant_{invName}_{sbd.Name}_Then_{atomicPath.Name}(\n                  {enumeratedParamValues}\n                );\n          \"));\n          str += \"} }\";\n          pgp.AddLemma(str, \"GlobalInvAlways\");\n        }\n\n        var optionalNot = (sbd.LastState is StraightlineStateYielded) ? \"!\" : \"\";\n        str = $@\"\n          lemma lemma_StraightlineBehaviorSatisfiesGlobalInvariant_{sbd.Name}(\n            sb: LAtomicStraightlineBehavior,\n            path: LAtomic_Path,\n            tid: Armada_ThreadHandle,\n            s': LPlusState\n            )\n            requires !path.LAtomic_Path_Tau?\n            requires AnnotatedBehaviorSatisfiesSpec(sb, GetLAtomicStraightlineSpec(tid, LProcName_{sbd.MethodName}))\n            requires StraightlineBehaviorFullySatisfiesDescriptor(sb.trace, LProcName_{sbd.MethodName}, SBD_{sbd.Name})\n            requires LocalInv(last(sb.states).state, tid)\n            requires LAtomic_NextPath(last(sb.states).state, s', path, tid)\n            requires !PathToEffect(path).CHLStepEffectStop?\n            requires var effect := PathToEffect(path);\n                     {optionalNot}(effect.CHLStepEffectReturn? || effect.CHLStepEffectReturnThenCall?)\n            ensures  GlobalInv(s')\n          {{\n            lemma_StraightlineBehaviorNonstoppingContinuationPossibilities_{sbd.Name}(sb, tid, LProcName_{sbd.MethodName}, s', path);\n            match path {{\n        \";\n        foreach (var tup in sbd.PotentialSuccessorPaths)\n        {\n          var path = tup.Item1;\n          var effect = tup.Item2;\n          str += $\"case LAtomic_Path_{path.Name}(_) =>\\n\";\n          if (tup.Item2.CanFollow(sbd.LastState)) {\n            str += $\"lemma_StraightlineBehaviorSatisfiesGlobalInvariant_{sbd.Name}_Then_{path.Name}(sb, path, tid, s');\\n\";\n          }\n          else {\n            str += $\"assert PathToEffect(path) == {effect.Constructor};\\n assert false;\\n\";\n          }\n        }\n        str += \"} }\\n\";\n        pgp.AddLemma(str, \"GlobalInvAlways\");\n      }\n\n      str = @\"\n        lemma lemma_StraightlineBehaviorSatisfiesGlobalInvariant(\n          sb: LAtomicStraightlineBehavior,\n          path: LAtomic_Path,\n          tid: Armada_ThreadHandle,\n          s': LPlusState\n          )\n          requires !path.LAtomic_Path_Tau?\n          requires AnnotatedBehaviorSatisfiesSpec(sb, GetLAtomicStraightlineSpec(tid, PathToProc(path)))\n          requires LocalInv(last(sb.states).state, tid)\n          requires LAtomic_NextPath(last(sb.states).state, s', path, tid)\n          requires !PathToEffect(path).CHLStepEffectStop?\n          requires var phase := last(sb.states).aux.phase;\n                   var effect := PathToEffect(path);\n                   if effect.CHLStepEffectReturn? || effect.CHLStepEffectReturnThenCall? then\n                     phase.StraightlinePhaseEnsured?\n                   else\n                     phase.StraightlinePhaseYielded?\n          ensures  GlobalInv(s')\n        {\n          var proc := PathToProc(path);\n          var phase := last(sb.states).aux.phase;\n          if phase.StraightlinePhaseEnsured? {\n            var sbd := lemma_GetFullDescriptorForStraightlineBehaviorEndingEnsured(sb, tid, proc);\n            assert StraightlineBehaviorDescriptorEndsEnsuredPossibilities(sbd);\n            match sbd {\n      \";\n      str += String.Concat(sbdsEndingEnsured.Select(sbd => $@\"\n              case SBD_{sbd.Name} =>\n                lemma_StraightlineBehaviorSatisfiesGlobalInvariant_{sbd.Name}(sb, path, tid, s');\n      \"));\n      str += @\"\n            }\n          }\n          else {\n            var sbd := lemma_GetFullDescriptorForStraightlineBehaviorEndingYielded(sb, tid, proc);\n            assert StraightlineBehaviorDescriptorEndsYieldedPossibilities(sbd);\n            match sbd {\n      \";\n      str += String.Concat(sbdsEndingYielded.Select(sbd => $@\"\n              case SBD_{sbd.Name} =>\n                lemma_StraightlineBehaviorSatisfiesGlobalInvariant_{sbd.Name}(sb, path, tid, s');\n      \"));\n      str += @\"\n            }\n          }\n        }\n      \";\n      pgp.AddLemma(str, \"GlobalInvAlways\");\n\n      str = @\"\n        lemma lemma_StraightlineBehaviorsSatisfyGlobalInvariant()\n          ensures StraightlineBehaviorsSatisfyGlobalInvariant(GetConcurrentHoareLogicRequest())\n        {\n          var cr := GetConcurrentHoareLogicRequest();\n          forall sb, step, s' {:trigger StraightlineBehaviorsSatisfyGlobalInvariantConditions(cr, sb, step, s')}\n            | StraightlineBehaviorsSatisfyGlobalInvariantConditions(cr, sb, step, s')\n            ensures cr.global_inv(s')\n          {\n            lemma_StraightlineBehaviorSatisfiesGlobalInvariant(sb, step.path, step.tid, s');\n          }\n        }\n      \";\n      pgp.AddLemma(str, \"GlobalInvAlways\");\n    }\n\n    private void GenerateStraightlineBehaviorsSatisfyLocalInvariantProof()\n    {\n      string str;\n\n      var alwaysFile = pgp.proofFiles.CreateAuxiliaryProofFile(\"LocalInvAlways\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"specs\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"invariants\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"defs\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"latomic\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"sbd\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"pcstack\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"exhaustive\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"continuation\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"enumeration\");\n      alwaysFile.AddImport(\"AtomicConcurrentHoareLogicSpecModule\");\n      alwaysFile.AddImport(\"ConcurrentHoareLogicSpecModule\");\n      alwaysFile.AddImport(\"util_collections_seqs_s\");\n      pgp.proofFiles.MainProof.IncludeAndImportGeneratedFile(\"LocalInvAlways\");\n\n      var enumeratedFile = pgp.proofFiles.CreateAuxiliaryProofFile(\"LocalInv\");\n      enumeratedFile.IncludeAndImportGeneratedFile(\"specs\");\n      enumeratedFile.IncludeAndImportGeneratedFile(\"defs\");\n      enumeratedFile.IncludeAndImportGeneratedFile(\"revelations\");\n      enumeratedFile.IncludeAndImportGeneratedFile(\"invariants\");\n      enumeratedFile.IncludeAndImportGeneratedFile(\"latomic\");\n      enumeratedFile.IncludeAndImportGeneratedFile(\"convert\");\n      enumeratedFile.IncludeAndImportGeneratedFile(\"utility\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"LocalInv\");\n\n      var trivialUniversalStepConstraint = !pgp.symbolsHigh.UniversalStepConstraints.Any();\n\n      var extractorEnumeration = new ExtractorEnumeration(lAtomic);\n      var extractorSB = new ExtractorSB(\"sb\", \"tid\", \"proc\");\n\n      foreach (var sbd in sbdsEndingYielded)\n      {\n        // If there is no enabling condition for the PC at the end of this behavior, then\n        // it's trivial to prove that the enabling condition (true) holds.\n\n        if (trivialUniversalStepConstraint && !sbd.LastState.HasLocalInvariant(pcsWithLocalInvariants, returnPCForMethod)) {\n          str = $@\"\n            lemma lemma_StraightlineBehaviorSatisfiesLocalInvariant_{sbd.Name}(\n              sb: LAtomicStraightlineBehavior,\n              path: LAtomic_Path,\n              tid: Armada_ThreadHandle,\n              s': LPlusState,\n              proc: LProcName\n              )\n              requires AnnotatedBehaviorSatisfiesSpec(sb, GetLAtomicStraightlineSpec(tid, proc))\n              requires StraightlineBehaviorFullySatisfiesDescriptor(sb.trace, proc, SBD_{sbd.Name})\n              ensures  LocalInv(last(sb.states).state, tid)\n              {{\n                lemma_StraightlineBehaviorEndProperties_{sbd.Name}(sb, tid, proc);\n                assert !PCHasLocalInvariant(last(sb.states).state.s.threads[tid].pc);\n              }}\n          \";\n          pgp.AddLemma(str, \"LocalInvAlways\");\n          continue;\n        }\n\n        foreach (var atomicPath in sbd.PotentialSuccessorPaths.Select(tup => tup.Item1))\n        {\n          // We pass hasLocalInvariant = false to the constructor for StraightlineStepBeyondEnd because we don't\n          // get to assume that LocalInv holds just before that final step.\n\n          var sbdPlus = new StraightlineBehavior(sbd, new StraightlineStepBeyondEnd(sbd.NumSteps, atomicPath, false));\n          var pathExpander = new PathExpander(sbdPlus);\n          var extractorExpanded = new ExtractorExpanded(pathExpander);\n\n          var expandedParamDeclarations = String.Join(\", \", new List<string>{ \"tid: Armada_ThreadHandle\" }\n                                                  .Concat(sbdPlus.GetStatesAndSteps(extractorExpanded, true)));\n          var expandedParamValues = String.Join(\", \", new List<string>{ \"tid\" }\n                                                        .Concat(sbdPlus.GetStatesAndSteps(extractorEnumeration, false)));\n          var enumeratedParamDeclarations = String.Join(\", \", new List<string>{ \"tid:Armada_ThreadHandle\" }\n                                                                 .Concat(sbdPlus.GetStatesAndPaths(extractorEnumeration, true)));\n          var enumeratedParamValues = String.Join(\", \", new List<string>{ \"tid\" }.Concat(sbd.GetStatesAndPaths(extractorSB, false))\n                                                           .Concat(new List<string>{ \"path\", \"s'\" }));\n\n          str = $@\"\n            lemma lemma_ExpandedStraightlineBehaviorSatisfiesLocalInvariant_{sbd.Name}_Then_{atomicPath.Name}(\n              {expandedParamDeclarations}\n            )\n          \";\n          str += String.Concat(sbdPlus.GetEnumerationClauses(extractorExpanded, true).Select(r => \"requires \" + r + \"\\n\"));\n          str += $@\"\n              ensures  LocalInv({extractorExpanded.State(sbd.NumSteps)}, tid)\n            {{\n              lemma_StoreBufferAppendHasEffectOfAppendedEntryAlways_L();\n              lemma_GetThreadLocalViewAlwaysCommutesWithConvert();\n              ProofCustomizationGoesHere();\n            }}\n          \";\n          pgp.AddLemma(str, \"LocalInv\");\n\n          str = $@\"\n            lemma lemma_EnumeratedStraightlineBehaviorSatisfiesLocalInvariant_{sbd.Name}_Then_{atomicPath.Name}(\n              {enumeratedParamDeclarations}\n            )\n          \";\n          str += String.Concat(sbdPlus.GetEnumerationClauses(extractorEnumeration).Select(r => \"requires \" + r + \"\\n\"));\n          str += $@\"\n              ensures  LocalInv(s{sbd.NumSteps}, tid)\n            {{\n              { String.Concat(sbdPlus.GetOpenValidPathInvocations(extractorEnumeration)) }\n              lemma_ExpandedStraightlineBehaviorSatisfiesLocalInvariant_{sbd.Name}_Then_{atomicPath.Name}({expandedParamValues});\n            }}\n          \";\n          pgp.AddLemma(str, \"LocalInv\");\n\n          str = $@\"\n            lemma lemma_StraightlineBehaviorSatisfiesLocalInvariant_{sbd.Name}_Then_{atomicPath.Name}(\n              sb: LAtomicStraightlineBehavior,\n              path: LAtomic_Path,\n              tid: Armada_ThreadHandle,\n              s': LPlusState\n              )\n              requires path.LAtomic_Path_{atomicPath.Name}?\n              requires AnnotatedBehaviorSatisfiesSpec(sb, GetLAtomicStraightlineSpec(tid, LProcName_{sbd.MethodName}))\n              requires LAtomic_NextPath(last(sb.states).state, s', path, tid)\n              requires StraightlineBehaviorFullySatisfiesDescriptor(sb.trace, LProcName_{sbd.MethodName}, SBD_{sbd.Name})\n              ensures  LocalInv(last(sb.states).state, tid)\n            {{\n              var proc := LProcName_{sbd.MethodName};\n              lemma_EnumerateStraightlineBehavior_{sbd.Name}(sb, tid, proc);\n              lemma_EnumeratedStraightlineBehaviorSatisfiesLocalInvariant_{sbd.Name}_Then_{atomicPath.Name}({enumeratedParamValues});\n            }}\n          \";\n          pgp.AddLemma(str, \"LocalInvAlways\");\n        }\n\n        str = $@\"\n          lemma lemma_StraightlineBehaviorSatisfiesLocalInvariant_{sbd.Name}(\n            sb: LAtomicStraightlineBehavior,\n            path: LAtomic_Path,\n            tid: Armada_ThreadHandle,\n            s': LPlusState,\n            proc: LProcName\n            )\n            requires AnnotatedBehaviorSatisfiesSpec(sb, GetLAtomicStraightlineSpec(tid, proc))\n            requires tid in last(sb.states).state.s.threads\n            requires PCToProc(last(sb.states).state.s.threads[tid].pc) == proc\n            requires LAtomic_NextPath(last(sb.states).state, s', path, tid)\n            requires !path.LAtomic_Path_Tau?\n            requires StraightlineBehaviorFullySatisfiesDescriptor(sb.trace, proc, SBD_{sbd.Name})\n            ensures  LocalInv(last(sb.states).state, tid)\n          {{\n            lemma_StraightlineBehaviorEndProperties_{sbd.Name}(sb, tid, proc);\n            assert proc.LProcName_{sbd.MethodName}?;\n            lemma_PathPossibilitiesStartingAtPC_{sbd.LastState.PC}(last(sb.states).state, s', path, tid);\n            match path {{\n        \";\n        str += String.Concat(sbd.PotentialSuccessorPaths.Select(tup => tup.Item1).Select(path => $@\"\n              case LAtomic_Path_{path.Name}(_) =>\n                lemma_StraightlineBehaviorSatisfiesLocalInvariant_{sbd.Name}_Then_{path.Name}(sb, path, tid, s');\n        \"));\n        str += \"} }\\n\";\n        pgp.AddLemma(str, \"LocalInvAlways\");\n      }\n\n      str = @\"\n        lemma lemma_StraightlineBehaviorSatisfiesLocalInvariant(\n          sb: LAtomicStraightlineBehavior,\n          path: LAtomic_Path,\n          tid: Armada_ThreadHandle,\n          s': LPlusState,\n          proc: LProcName\n          )\n          requires AnnotatedBehaviorSatisfiesSpec(sb, GetLAtomicStraightlineSpec(tid, proc))\n          requires tid in last(sb.states).state.s.threads\n          requires PCToProc(last(sb.states).state.s.threads[tid].pc) == proc\n          requires last(sb.states).aux.phase.StraightlinePhaseYielded?\n          requires LAtomic_NextPath(last(sb.states).state, s', path, tid)\n          requires !path.LAtomic_Path_Tau?\n          ensures  LocalInv(last(sb.states).state, tid)\n        {\n          var phase := last(sb.states).aux.phase;\n          var sbd := lemma_GetFullDescriptorForStraightlineBehaviorEndingYielded(sb, tid, proc);\n          match sbd {\n      \";\n      str += String.Concat(sbdsEndingYielded.Select(sbd => $@\"\n            case SBD_{sbd.Name} =>\n              lemma_StraightlineBehaviorSatisfiesLocalInvariant_{sbd.Name}(sb, path, tid, s', proc);\n      \"));\n      str += @\"\n          }\n        }\n      \";\n      pgp.AddLemma(str, \"LocalInvAlways\");\n\n      str = @\"\n        lemma lemma_StraightlineBehaviorsSatisfyLocalInvariant()\n          ensures StraightlineBehaviorsSatisfyLocalInvariant(GetConcurrentHoareLogicRequest())\n        {\n          var cr := GetConcurrentHoareLogicRequest();\n          forall sb, step, s' {:trigger StraightlineBehaviorsSatisfyLocalInvariantConditions(cr, sb, step, s')}\n            | StraightlineBehaviorsSatisfyLocalInvariantConditions(cr, sb, step, s')\n            ensures cr.local_inv(last(sb.states).state, cr.step_to_actor(step).v)\n          {\n            var actor := cr.step_to_actor(step).v;\n            var pc := cr.get_actor_pc_stack(last(sb.states).state, actor).v.pc;\n            var proc := cr.pc_to_proc(pc);\n            lemma_StraightlineBehaviorSatisfiesLocalInvariant(sb, step.path, step.tid, s', proc);\n          }\n        }\n      \";\n      pgp.AddLemma(str, \"LocalInvAlways\");\n    }\n\n    private void GenerateStraightlineBehaviorsSatisfyPreconditionsForCallsProof()\n    {\n      string str;\n\n      var alwaysFile = pgp.proofFiles.CreateAuxiliaryProofFile(\"CallsAlways\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"specs\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"invariants\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"defs\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"latomic\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"sbd\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"pcstack\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"exhaustive\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"continuation\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"enumeration\");\n      alwaysFile.AddImport(\"AtomicConcurrentHoareLogicSpecModule\");\n      alwaysFile.AddImport(\"ConcurrentHoareLogicSpecModule\");\n      alwaysFile.AddImport(\"util_collections_seqs_s\");\n      pgp.proofFiles.MainProof.IncludeAndImportGeneratedFile(\"CallsAlways\");\n\n      var stackCorrectFile = pgp.proofFiles.CreateAuxiliaryProofFile(\"StackCorrect\");\n      stackCorrectFile.IncludeAndImportGeneratedFile(\"specs\");\n      stackCorrectFile.IncludeAndImportGeneratedFile(\"defs\");\n      stackCorrectFile.IncludeAndImportGeneratedFile(\"revelations\");\n      stackCorrectFile.IncludeAndImportGeneratedFile(\"latomic\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"StackCorrect\");\n\n      // For each call statement, demonstrate that it establishes the StackCorrectAtStart_{methodName} predicate.\n\n      foreach (var kv in pathEffectMap.Where(kv => kv.Value is CHLPathEffectCall || kv.Value is CHLPathEffectReturnThenCall))\n      {\n        var atomicPath = kv.Key;\n        var callee = kv.Value.Callee;\n        var pr = new PathPrinter(lAtomic);\n        str = $@\"\n          lemma lemma_AtomicPathEnsuresStackCorrectAtStart_{atomicPath.Name}(\n            s: LPlusState,\n            s': LPlusState,\n            path: LAtomic_Path,\n            tid: Armada_ThreadHandle\n            )\n            requires LAtomic_NextPath(s, s', path, tid)\n            requires path.LAtomic_Path_{atomicPath.Name}?\n            ensures  StackCorrectAtStart_{callee}(s', tid)\n          {{\n            { pr.GetOpenValidPathInvocation(atomicPath) }\n          }}\n        \";\n        pgp.AddLemma(str, \"StackCorrect\");\n      }\n\n      foreach (var preconditionName in preconditionsForMethod.Values.SelectMany(x => x))\n      {\n        var specificPreconditionFile = pgp.proofFiles.CreateAuxiliaryProofFile($\"Call_{preconditionName}\");\n        specificPreconditionFile.IncludeAndImportGeneratedFile(\"specs\");\n        specificPreconditionFile.IncludeAndImportGeneratedFile(\"defs\");\n        specificPreconditionFile.IncludeAndImportGeneratedFile(\"revelations\");\n        specificPreconditionFile.IncludeAndImportGeneratedFile(\"invariants\");\n        specificPreconditionFile.IncludeAndImportGeneratedFile(\"latomic\");\n        alwaysFile.IncludeAndImportGeneratedFile($\"Call_{preconditionName}\");\n      }\n\n      var extractorEnumeration = new ExtractorEnumeration(lAtomic);\n      var extractorSB = new ExtractorSB(\"sb\", \"tid\", \"proc\");\n      foreach (var sbd in sbdsEndingYielded.Concat(sbdsEndingEnsured)) {\n        foreach (var tup in sbd.PotentialSuccessorPaths\n                 .Where(tup => (sbd.LastState is StraightlineStateYielded && tup.Item2 is CHLPathEffectCall)\n                               || (sbd.LastState is StraightlineStateEnsured && tup.Item2 is CHLPathEffectReturnThenCall))) {\n          var atomicPath = tup.Item1;\n          var effect = tup.Item2;\n          var callee = effect.Callee;\n          var beyondEnd = new StraightlineStepBeyondEnd(sbd.NumSteps, atomicPath, pcsWithLocalInvariants.Contains(sbd.LastState.PC));\n          var sbdPlus = new StraightlineBehavior(sbd, beyondEnd);\n          var pathExpander = new PathExpander(sbdPlus);\n          var extractorExpanded = new ExtractorExpanded(pathExpander);\n\n          var expandedParamDeclarations = String.Join(\", \", new List<string>{ \"tid: Armada_ThreadHandle\" }\n                                                              .Concat(sbdPlus.GetStatesAndSteps(extractorExpanded, true)));\n          var expandedParamValues = String.Join(\", \", new List<string>{ \"tid\" }\n                                                        .Concat(sbdPlus.GetStatesAndSteps(extractorEnumeration, false)));\n          var enumeratedParamDeclarations =\n            String.Join(\", \", new List<string>{ \"tid:Armada_ThreadHandle\" }\n                               .Concat(sbdPlus.GetStatesAndPaths(extractorEnumeration, true)));\n          var enumeratedParamValues =\n            String.Join(\", \", new List<string>{ \"tid\" }\n                                .Concat(sbd.GetStatesAndPaths(extractorSB, false))\n                                .Concat(new List<string>{ \"path\", \"s'\" }));\n\n          foreach (var preconditionName in preconditionsForMethod[callee])\n          {\n            str = $@\"\n              lemma lemma_ExpandedStraightlineBehaviorSatisfiesPreconditionForCall_{preconditionName}_{sbd.Name}_Then_{atomicPath.Name}(\n                {expandedParamDeclarations}\n              )\n            \";\n            str += String.Concat(sbdPlus.GetEnumerationClauses(extractorExpanded, true).Select(r => \"requires \" + r + \"\\n\"));\n            str += $@\"\n                requires StackCorrectAtStart_{callee}({extractorExpanded.State(sbd.NumSteps + 1)}, tid)\n                ensures  {preconditionName}({extractorExpanded.State(sbd.NumSteps + 1)}, tid)\n              {{\n                ProofCustomizationGoesHere();\n              }}\n            \";\n            pgp.AddLemma(str, $\"Call_{preconditionName}\");\n\n            str = $@\"\n              lemma lemma_EnumeratedStraightlineBehaviorSatisfiesPreconditionForCall_{preconditionName}_{sbd.Name}_Then_{atomicPath.Name}(\n                {enumeratedParamDeclarations}\n              )\n            \";\n            str += String.Concat(sbdPlus.GetEnumerationClauses(extractorEnumeration).Select(r => \"requires \" + r + \"\\n\"));\n            str += $@\"\n                requires StackCorrectAtStart_{callee}(s{sbd.NumSteps + 1}, tid)\n                ensures  {preconditionName}(s{sbd.NumSteps + 1}, tid)\n              {{\n                { String.Concat(sbd.GetOpenValidPathInvocations(extractorEnumeration)) }\n                { extractorEnumeration.GetOpenValidPathInvocation(atomicPath, sbd.NumSteps) }\n                lemma_ExpandedStraightlineBehaviorSatisfiesPreconditionForCall_{preconditionName}_{sbd.Name}_Then_{atomicPath.Name}(\n                  {expandedParamValues}\n                );\n              }}\n            \";\n            pgp.AddLemma(str, $\"Call_{preconditionName}\");\n          }\n\n          str = $@\"\n            lemma lemma_StraightlineBehaviorSatisfiesPreconditionsForCall_{sbd.Name}_Then_{atomicPath.Name}(\n              sb: LAtomicStraightlineBehavior,\n              path: LAtomic_Path,\n              tid: Armada_ThreadHandle,\n              s': LPlusState\n              )\n              requires path.LAtomic_Path_{atomicPath.Name}?\n              requires AnnotatedBehaviorSatisfiesSpec(sb, GetLAtomicStraightlineSpec(tid, LProcName_{sbd.MethodName}))\n              requires LocalInv(last(sb.states).state, tid)\n              requires LAtomic_NextPath(last(sb.states).state, s', path, tid)\n              requires StraightlineBehaviorFullySatisfiesDescriptor(sb.trace, LProcName_{sbd.MethodName}, SBD_{sbd.Name})\n          \";\n          if (sbd.LastState is StraightlineStateYielded) {\n            str += \"requires PathToEffect(path).CHLStepEffectCall?\\n\";\n          }\n          else {\n            str += \"requires PathToEffect(path).CHLStepEffectReturnThenCall?\\n\";\n          }\n          str += $@\"\n              ensures  RequiresClauses(PathToEffect(path).callee, s', tid)\n            {{\n              var proc := LProcName_{sbd.MethodName};\n              assert PathToEffect(path).callee.LProcName_{callee}?;\n              lemma_AtomicPathEnsuresStackCorrectAtStart_{atomicPath.Name}(last(sb.states).state, s', path, tid);\n              lemma_EnumerateStraightlineBehavior_{sbd.Name}(sb, tid, proc);\n          \";\n          str += String.Concat(preconditionsForMethod[callee].Select(name => $@\"\n              lemma_EnumeratedStraightlineBehaviorSatisfiesPreconditionForCall_{name}_{sbd.Name}_Then_{atomicPath.Name}(\n                {enumeratedParamValues}\n              );\n          \"));\n          str += \"}\";\n          pgp.AddLemma(str, \"CallsAlways\");\n        }\n\n        str = $@\"\n          lemma lemma_StraightlineBehaviorSatisfiesPreconditionsForCall_{sbd.Name}(\n            sb: LAtomicStraightlineBehavior,\n            path: LAtomic_Path,\n            tid: Armada_ThreadHandle,\n            s': LPlusState\n            )\n            requires !path.LAtomic_Path_Tau?\n            requires AnnotatedBehaviorSatisfiesSpec(sb, GetLAtomicStraightlineSpec(tid, LProcName_{sbd.MethodName}))\n            requires LocalInv(last(sb.states).state, tid)\n            requires LAtomic_NextPath(last(sb.states).state, s', path, tid)\n            requires StraightlineBehaviorFullySatisfiesDescriptor(sb.trace, LProcName_{sbd.MethodName}, SBD_{sbd.Name})\n        \";\n        if (sbd.LastState is StraightlineStateYielded) {\n          str += \"requires PathToEffect(path).CHLStepEffectCall?\\n\";\n        }\n        else {\n          str += \"requires PathToEffect(path).CHLStepEffectReturnThenCall?\\n\";\n        }\n        str += $@\"\n            ensures  RequiresClauses(PathToEffect(path).callee, s', tid)\n          {{\n            lemma_StraightlineBehaviorNonstoppingContinuationPossibilities_{sbd.Name}(sb, tid, LProcName_{sbd.MethodName}, s', path);\n            match path {{\n        \";\n        foreach (var tup in sbd.PotentialSuccessorPaths)\n        {\n          var path = tup.Item1;\n          var effect = tup.Item2;\n          str += $@\"\n              case LAtomic_Path_{path.Name}(_) =>\n          \";\n          if ((sbd.LastState is StraightlineStateYielded && effect is CHLPathEffectCall) ||\n              (sbd.LastState is StraightlineStateEnsured && effect is CHLPathEffectReturnThenCall)) {\n            str += $\"lemma_StraightlineBehaviorSatisfiesPreconditionsForCall_{sbd.Name}_Then_{path.Name}(sb, path, tid, s');\\n\";\n          }\n          else {\n            str += $\"assert PathToEffect(path) == {effect.Constructor};\\n assert false;\\n\";\n          }\n        }\n        str += \"} }\\n\";\n        pgp.AddLemma(str, \"CallsAlways\");\n      }\n\n      str = @\"\n        lemma lemma_StraightlineBehaviorSatisfiesPreconditionsForCall(\n          sb: LAtomicStraightlineBehavior,\n          path: LAtomic_Path,\n          tid: Armada_ThreadHandle,\n          s': LPlusState\n          )\n          requires !path.LAtomic_Path_Tau?\n          requires AnnotatedBehaviorSatisfiesSpec(sb, GetLAtomicStraightlineSpec(tid, PathToProc(path)))\n          requires LocalInv(last(sb.states).state, tid)\n          requires LAtomic_NextPath(last(sb.states).state, s', path, tid)\n          requires var phase := last(sb.states).aux.phase;\n                   var effect := PathToEffect(path);\n                   || (effect.CHLStepEffectCall? && phase.StraightlinePhaseYielded?)\n                   || (effect.CHLStepEffectReturnThenCall? && phase.StraightlinePhaseEnsured?)\n          ensures  RequiresClauses(PathToEffect(path).callee, s', tid)\n        {\n          var proc := PathToProc(path);\n          var phase := last(sb.states).aux.phase;\n          var sbd;\n          if phase.StraightlinePhaseEnsured? {\n            sbd := lemma_GetFullDescriptorForStraightlineBehaviorEndingEnsured(sb, tid, proc);\n            match sbd {\n      \";\n      str += String.Concat(sbdsEndingEnsured.Select(sbd => $@\"\n              case SBD_{sbd.Name} =>\n                lemma_StraightlineBehaviorSatisfiesPreconditionsForCall_{sbd.Name}(sb, path, tid, s');\n      \"));\n      str += @\"\n            }\n          }\n          else {\n            sbd := lemma_GetFullDescriptorForStraightlineBehaviorEndingYielded(sb, tid, proc);\n            match sbd {\n      \";\n      str += String.Concat(sbdsEndingYielded.Select(sbd => $@\"\n              case SBD_{sbd.Name} =>\n                lemma_StraightlineBehaviorSatisfiesPreconditionsForCall_{sbd.Name}(sb, path, tid, s');\n      \"));\n      str += @\"\n            }\n          }\n        }\n      \";\n      pgp.AddLemma(str, \"CallsAlways\");\n\n      str = @\"\n        lemma lemma_StraightlineBehaviorsSatisfyPreconditionsForCalls()\n          ensures StraightlineBehaviorsSatisfyPreconditionsForCalls(GetConcurrentHoareLogicRequest())\n        {\n          var cr := GetConcurrentHoareLogicRequest();\n          forall sb, step, s' {:trigger StraightlineBehaviorsSatisfyPreconditionsForCallsConditions(cr, sb, step, s')}\n            | StraightlineBehaviorsSatisfyPreconditionsForCallsConditions(cr, sb, step, s')\n            ensures var actor := cr.step_to_actor(step).v;\n                    var callee := cr.step_to_effect(step).callee;\n                    cr.requires_clauses(callee, s', actor)\n          {\n            lemma_StraightlineBehaviorSatisfiesPreconditionsForCall(sb, step.path, step.tid, s');\n          }\n        }\n      \";\n      pgp.AddLemma(str, \"CallsAlways\");\n    }\n\n    private bool AtomicPathForks(AtomicPath path)\n    {\n      return path.NextRoutines.Where(r => r.nextType == NextType.CreateThread).Any();\n    }\n\n    private void GenerateStraightlineBehaviorsSatisfyPreconditionsForForksProof()\n    {\n      string str;\n\n      var alwaysFile = pgp.proofFiles.CreateAuxiliaryProofFile(\"ForksAlways\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"specs\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"invariants\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"defs\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"latomic\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"sbd\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"pcstack\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"exhaustive\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"continuation\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"enumeration\");\n      alwaysFile.AddImport(\"ConcurrentHoareLogicSpecModule\");\n      alwaysFile.AddImport(\"AtomicConcurrentHoareLogicSpecModule\");\n      alwaysFile.AddImport(\"util_collections_seqs_s\");\n      pgp.proofFiles.MainProof.IncludeAndImportGeneratedFile(\"ForksAlways\");\n\n      var forksFile = pgp.proofFiles.CreateAuxiliaryProofFile(\"Forks\");\n      forksFile.IncludeAndImportGeneratedFile(\"specs\");\n      forksFile.IncludeAndImportGeneratedFile(\"defs\");\n      forksFile.IncludeAndImportGeneratedFile(\"revelations\");\n      forksFile.IncludeAndImportGeneratedFile(\"latomic\");\n      forksFile.IncludeAndImportGeneratedFile(\"invariants\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"Forks\");\n\n      var nonforkersFile = pgp.proofFiles.CreateAuxiliaryProofFile(\"Nonforkers\");\n      nonforkersFile.IncludeAndImportGeneratedFile(\"specs\");\n      nonforkersFile.IncludeAndImportGeneratedFile(\"defs\");\n      nonforkersFile.IncludeAndImportGeneratedFile(\"revelations\");\n      nonforkersFile.IncludeAndImportGeneratedFile(\"latomic\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"Nonforkers\");\n\n      // For each non-stopping atomic path that can't fork, create a lemma saying it doesn't fork.\n\n      var pr = new PathPrinter(lAtomic);\n\n      foreach (var atomicPath in pathsStartingAtPC.Values.SelectMany(x => x).Where(path => !AtomicPathForks(path)))\n      {\n        str = $@\"\n          lemma lemma_AtomicPathDoesntFork_{atomicPath.Name}(\n            s: LPlusState,\n            s': LPlusState,\n            path: LAtomic_Path,\n            tid: Armada_ThreadHandle,\n            other_tid: Armada_ThreadHandle\n            )\n            requires LAtomic_NextPath(s, s', path, tid)\n            requires path.LAtomic_Path_{atomicPath.Name}?\n            requires other_tid != tid\n            requires other_tid !in s.s.threads\n            ensures  other_tid !in s'.s.threads\n          {{\n            { pr.GetOpenValidPathInvocation(atomicPath) }\n          }}\n        \";\n        pgp.AddLemma(str, \"Nonforkers\");\n      }\n\n      var extractorEnumeration = new ExtractorEnumeration(lAtomic);\n      var extractorSB = new ExtractorSB(\"sb\", \"tid\", \"proc\");\n      foreach (var sbd in sbdsEndingYielded.Concat(sbdsEndingEnsured))\n      {\n        var optionalNot = (sbd.LastState is StraightlineStateYielded) ? \"!\" : \"\";\n\n        foreach (var atomicPath in sbd.PotentialSuccessorPaths.Where(tup => tup.Item2.CanFollow(sbd.LastState))\n                                                              .Select(tup => tup.Item1))\n        {\n          if (AtomicPathForks(atomicPath)) {\n            var beyondEnd = new StraightlineStepBeyondEnd(sbd.NumSteps, atomicPath, pcsWithLocalInvariants.Contains(sbd.LastState.PC));\n            var sbdPlus = new StraightlineBehavior(sbd, beyondEnd);\n            var pathExpander = new PathExpander(sbdPlus);\n            var extractorExpanded = new ExtractorExpanded(pathExpander);\n\n            var expandedParamDeclarations =\n              String.Join(\", \", new List<string>{ \"tid: Armada_ThreadHandle\", \"forked_tid: Armada_ThreadHandle\", \"forked_proc: LProcName\" }\n                                 .Concat(sbdPlus.GetStatesAndSteps(extractorExpanded, true)));\n            var expandedParamValues =\n              String.Join(\", \", new List<string>{ \"tid\", \"forked_tid\", \"forked_proc\" }\n                                  .Concat(sbdPlus.GetStatesAndSteps(extractorEnumeration, false)));\n            var enumeratedParamDeclarations =\n              String.Join(\", \", new List<string> { \"tid: Armada_ThreadHandle\", \"forked_tid: Armada_ThreadHandle\", \"forked_proc: LProcName\" }\n                                 .Concat(sbdPlus.GetStatesAndPaths(extractorEnumeration, true)));\n            var enumeratedParamValues =\n              String.Join(\", \", new List<string>{ \"tid\", \"forked_tid\", \"forked_proc\" }\n                                  .Concat(sbd.GetStatesAndPaths(extractorSB, false))\n                                  .Concat(new List<string>{ \"path\", \"s'\" }));\n\n            str = $@\"\n              lemma lemma_ExpandedStraightlineBehaviorSatisfiesPreconditionsForForks_{sbd.Name}_Then_{atomicPath.Name}(\n                {expandedParamDeclarations}\n              )\n            \";\n            str += String.Concat(sbdPlus.GetEnumerationClauses(extractorExpanded, true).Select(r => \"requires \" + r + \"\\n\"));\n            str += $@\"\n                requires forked_tid != tid\n                requires forked_tid !in {extractorExpanded.State(sbd.NumSteps)}.s.threads\n                requires forked_tid in {extractorExpanded.State(sbd.NumSteps + 1)}.s.threads\n                requires forked_proc == PCToProc({extractorExpanded.State(sbd.NumSteps + 1)}.s.threads[forked_tid].pc)\n                ensures  RequiresClauses(forked_proc, {extractorExpanded.State(sbd.NumSteps + 1)}, forked_tid)\n                {{\n                  ProofCustomizationGoesHere();\n                }}\n            \";\n            pgp.AddLemma(str, \"Forks\");\n\n            str = $@\"\n              lemma lemma_EnumeratedStraightlineBehaviorSatisfiesPreconditionsForForks_{sbd.Name}_Then_{atomicPath.Name}(\n                {enumeratedParamDeclarations}\n              )\n            \";\n            str += String.Concat(sbdPlus.GetEnumerationClauses(extractorEnumeration, false).Select(r => \"requires \" + r + \"\\n\"));\n            str += $@\"\n                requires forked_tid != tid\n                requires forked_tid !in s{sbd.NumSteps}.s.threads\n                requires forked_tid in s{sbd.NumSteps + 1}.s.threads\n                requires forked_proc == PCToProc(s{sbd.NumSteps + 1}.s.threads[forked_tid].pc)\n                ensures  RequiresClauses(forked_proc, s{sbd.NumSteps + 1}, forked_tid)\n                {{\n                  { String.Concat(sbd.GetOpenValidPathInvocations(extractorEnumeration)) }\n                  { extractorEnumeration.GetOpenValidPathInvocation(atomicPath, sbd.NumSteps) }\n                  lemma_ExpandedStraightlineBehaviorSatisfiesPreconditionsForForks_{sbd.Name}_Then_{atomicPath.Name}(\n                    {expandedParamValues}\n                  );\n                }}\n            \";\n            pgp.AddLemma(str, \"Forks\");\n\n            str = $@\"\n              lemma lemma_StraightlineBehaviorSatisfiesPreconditionsForForks_{sbd.Name}_Then_{atomicPath.Name}(\n                sb: LAtomicStraightlineBehavior,\n                path: LAtomic_Path,\n                tid: Armada_ThreadHandle,\n                s': LPlusState,\n                forked_tid: Armada_ThreadHandle,\n                forked_proc: LProcName\n                )\n                requires path.LAtomic_Path_{atomicPath.Name}?\n                requires AnnotatedBehaviorSatisfiesSpec(sb, GetLAtomicStraightlineSpec(tid, LProcName_{sbd.MethodName}))\n                requires LocalInv(last(sb.states).state, tid)\n                requires LAtomic_NextPath(last(sb.states).state, s', path, tid)\n                requires forked_tid != tid\n                requires forked_tid !in last(sb.states).state.s.threads\n                requires forked_tid in s'.s.threads\n                requires forked_proc == PCToProc(s'.s.threads[forked_tid].pc)\n                requires StraightlineBehaviorFullySatisfiesDescriptor(sb.trace, LProcName_{sbd.MethodName}, SBD_{sbd.Name})\n                requires !PathToEffect(path).CHLStepEffectStop?\n                requires var effect := PathToEffect(path);\n                         {optionalNot}(effect.CHLStepEffectReturn? || effect.CHLStepEffectReturnThenCall?)\n                ensures  RequiresClauses(forked_proc, s', forked_tid)\n              {{\n                var proc := LProcName_{sbd.MethodName};\n                lemma_EnumerateStraightlineBehavior_{sbd.Name}(sb, tid, proc);\n                lemma_EnumeratedStraightlineBehaviorSatisfiesPreconditionsForForks_{sbd.Name}_Then_{atomicPath.Name}(\n                  {enumeratedParamValues}\n                );\n              }}\n            \";\n            pgp.AddLemma(str, \"ForksAlways\");\n          }\n        }\n\n        str = $@\"\n          lemma lemma_StraightlineBehaviorSatisfiesPreconditionsForForks_{sbd.Name}(\n            sb: LAtomicStraightlineBehavior,\n            path: LAtomic_Path,\n            tid: Armada_ThreadHandle,\n            s': LPlusState,\n            forked_tid: Armada_ThreadHandle,\n            forked_proc: LProcName\n            )\n            requires !path.LAtomic_Path_Tau?\n            requires AnnotatedBehaviorSatisfiesSpec(sb, GetLAtomicStraightlineSpec(tid, LProcName_{sbd.MethodName}))\n            requires LocalInv(last(sb.states).state, tid)\n            requires LAtomic_NextPath(last(sb.states).state, s', path, tid)\n            requires forked_tid != tid\n            requires forked_tid !in last(sb.states).state.s.threads\n            requires forked_tid in s'.s.threads\n            requires forked_proc == PCToProc(s'.s.threads[forked_tid].pc)\n            requires StraightlineBehaviorFullySatisfiesDescriptor(sb.trace, LProcName_{sbd.MethodName}, SBD_{sbd.Name})\n            requires !PathToEffect(path).CHLStepEffectStop?\n            requires var effect := PathToEffect(path);\n                     {optionalNot}(effect.CHLStepEffectReturn? || effect.CHLStepEffectReturnThenCall?)\n            ensures  RequiresClauses(forked_proc, s', forked_tid)\n          {{\n            lemma_StraightlineBehaviorNonstoppingContinuationPossibilities_{sbd.Name}(sb, tid, LProcName_{sbd.MethodName}, s', path);\n            match path {{\n        \";\n        foreach (var tup in sbd.PotentialSuccessorPaths)\n        {\n          var path = tup.Item1;\n          var effect = tup.Item2;\n          str += $\"case LAtomic_Path_{path.Name}(_) =>\\n\";\n          if (!effect.CanFollow(sbd.LastState)) {\n            str += $@\"\n                assert PathToEffect(path) == {effect.Constructor};\n                assert false;\n            \";\n          }\n          else if (AtomicPathForks(path)) {\n            str += $@\"\n                lemma_StraightlineBehaviorSatisfiesPreconditionsForForks_{sbd.Name}_Then_{path.Name}(sb, path, tid, s', forked_tid,\n                                                                                                     forked_proc);\n            \";\n          }\n          else {\n            str += $@\"\n                lemma_AtomicPathDoesntFork_{path.Name}(last(sb.states).state, s', path, tid, forked_tid);\n                assert false;\n            \";\n          }\n        }\n        str += \"} }\\n\";\n        pgp.AddLemma(str, \"ForksAlways\");\n      }\n\n      str = @\"\n        lemma lemma_StraightlineBehaviorSatisfiesPreconditionsForForks(\n          sb: LAtomicStraightlineBehavior,\n          path: LAtomic_Path,\n          tid: Armada_ThreadHandle,\n          s': LPlusState,\n          forked_tid: Armada_ThreadHandle,\n          forked_proc: LProcName\n          )\n          requires !path.LAtomic_Path_Tau?\n          requires AnnotatedBehaviorSatisfiesSpec(sb, GetLAtomicStraightlineSpec(tid, PathToProc(path)))\n          requires LocalInv(last(sb.states).state, tid)\n          requires LAtomic_NextPath(last(sb.states).state, s', path, tid)\n          requires forked_tid != tid\n          requires forked_tid !in last(sb.states).state.s.threads\n          requires forked_tid in s'.s.threads\n          requires forked_proc == PCToProc(s'.s.threads[forked_tid].pc)\n          requires !PathToEffect(path).CHLStepEffectStop?\n          requires var phase := last(sb.states).aux.phase;\n                   var effect := PathToEffect(path);\n                   if effect.CHLStepEffectReturn? || effect.CHLStepEffectReturnThenCall? then\n                     phase.StraightlinePhaseEnsured?\n                   else\n                     phase.StraightlinePhaseYielded?\n          ensures  RequiresClauses(forked_proc, s', forked_tid)\n        {\n          var proc := PathToProc(path);\n          var phase := last(sb.states).aux.phase;\n          var sbd;\n          if phase.StraightlinePhaseEnsured? {\n            sbd := lemma_GetFullDescriptorForStraightlineBehaviorEndingEnsured(sb, tid, proc);\n            match sbd {\n      \";\n      str += String.Concat(sbdsEndingEnsured.Select(sbd => $@\"\n              case SBD_{sbd.Name} =>\n                lemma_StraightlineBehaviorSatisfiesPreconditionsForForks_{sbd.Name}(sb, path, tid, s', forked_tid, forked_proc);\n      \"));\n      str += @\"\n            }\n          }\n          else {\n            sbd := lemma_GetFullDescriptorForStraightlineBehaviorEndingYielded(sb, tid, proc);\n            match sbd {\n      \";\n      str += String.Concat(sbdsEndingYielded.Select(sbd => $@\"\n              case SBD_{sbd.Name} =>\n                lemma_StraightlineBehaviorSatisfiesPreconditionsForForks_{sbd.Name}(sb, path, tid, s', forked_tid, forked_proc);\n      \"));\n      str += @\"\n            }\n          }\n        }\n      \";\n      pgp.AddLemma(str, \"ForksAlways\");\n\n      str = @\"\n        lemma lemma_StraightlineBehaviorsSatisfyPreconditionsForForks()\n          ensures StraightlineBehaviorsSatisfyPreconditionsForForks(GetConcurrentHoareLogicRequest())\n        {\n          var cr := GetConcurrentHoareLogicRequest();\n          forall sb, step, s', forked_actor\n            {:trigger StraightlineBehaviorsSatisfyPreconditionsForForksConditions(cr, sb, step, s', forked_actor)}\n            | StraightlineBehaviorsSatisfyPreconditionsForForksConditions(cr, sb, step, s', forked_actor)\n            ensures var forked_pc := cr.get_actor_pc_stack(s', forked_actor).v.pc;\n                    var forked_proc := cr.pc_to_proc(forked_pc);\n                    cr.requires_clauses(forked_proc, s', forked_actor)\n          {\n            var forked_pc := cr.get_actor_pc_stack(s', forked_actor).v.pc;\n            var forked_proc := cr.pc_to_proc(forked_pc);\n            lemma_StraightlineBehaviorSatisfiesPreconditionsForForks(sb, step.path, step.tid, s', forked_actor, forked_proc);\n          }\n        }\n      \";\n      pgp.AddLemma(str, \"ForksAlways\");\n    }\n\n    private bool EndsAtReturnPC(StraightlineBehavior sbd)\n    {\n      return returnPCForMethod[sbd.MethodName].Equals(sbd.LastState.PC);\n    }\n\n    private void GenerateStraightlineBehaviorsSatisfyPostconditionsProof()\n    {\n      string str;\n\n      var alwaysFile = pgp.proofFiles.CreateAuxiliaryProofFile(\"PostconditionsAlways\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"specs\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"invariants\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"defs\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"latomic\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"sbd\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"pcstack\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"exhaustive\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"continuation\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"enumeration\");\n      alwaysFile.AddImport(\"ConcurrentHoareLogicSpecModule\");\n      alwaysFile.AddImport(\"AtomicConcurrentHoareLogicSpecModule\");\n      alwaysFile.AddImport(\"util_collections_seqs_s\");\n      pgp.proofFiles.MainProof.IncludeAndImportGeneratedFile(\"PostconditionsAlways\");\n\n      var postconditionsFile = pgp.proofFiles.CreateAuxiliaryProofFile(\"Postconditions\");\n      postconditionsFile.IncludeAndImportGeneratedFile(\"specs\");\n      postconditionsFile.IncludeAndImportGeneratedFile(\"defs\");\n      postconditionsFile.IncludeAndImportGeneratedFile(\"revelations\");\n      postconditionsFile.IncludeAndImportGeneratedFile(\"invariants\");\n      postconditionsFile.IncludeAndImportGeneratedFile(\"latomic\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"Postconditions\");\n\n      var extractorEnumeration = new ExtractorEnumeration(lAtomic);\n      var extractorSB = new ExtractorSB(\"sb\", \"tid\", \"proc\");\n      foreach (var sbd in sbdsEndingYielded)\n      {\n        if (EndsAtReturnPC(sbd)) {\n          var pathExpander = new PathExpander(sbd);\n          var extractorExpanded = new ExtractorExpanded(pathExpander);\n          var expandedParamDeclarations =\n            String.Join(\", \", new List<string>{ \"tid: Armada_ThreadHandle\" }.Concat(sbd.GetStatesAndSteps(extractorExpanded, true)));\n          var expandedParamValues =\n            String.Join(\", \", new List<string>{ \"tid\" }.Concat(sbd.GetStatesAndSteps(extractorEnumeration, false)));\n          var enumeratedParamDeclarations =\n            String.Join(\", \", new List<string>{ \"tid:Armada_ThreadHandle\" }.Concat(sbd.GetStatesAndPaths(extractorEnumeration, true)));\n          var enumeratedParamValues = String.Join(\", \", new List<string>{ \"tid\" }.Concat(sbd.GetStatesAndPaths(extractorSB, false)));\n\n          str = $@\"\n            lemma lemma_ExpandedStraightlineBehaviorSatisfiesPostcondition_{sbd.Name}({expandedParamDeclarations})\n          \";\n          str += String.Concat(sbd.GetEnumerationClauses(extractorExpanded, true).Select(r => \"requires \" + r + \"\\n\"));\n          str += $@\"\n              ensures  Postconditions_{sbd.MethodName}({extractorExpanded.State(0)}, {extractorExpanded.State(sbd.NumSteps)}, tid)\n              {{\n                ProofCustomizationGoesHere();\n              }}\n          \";\n          pgp.AddLemma(str, \"Postconditions\");\n\n          str = $@\"\n            lemma lemma_EnumeratedStraightlineBehaviorSatisfiesPostcondition_{sbd.Name}({enumeratedParamDeclarations})\n          \";\n          str += String.Concat(sbd.GetEnumerationClauses(extractorEnumeration, false).Select(r => \"requires \" + r + \"\\n\"));\n          str += $@\"\n              ensures  Postconditions_{sbd.MethodName}(s0, s{sbd.NumSteps}, tid)\n              {{\n                { String.Concat(sbd.GetOpenValidPathInvocations(extractorEnumeration)) }\n                lemma_ExpandedStraightlineBehaviorSatisfiesPostcondition_{sbd.Name}({expandedParamValues});\n              }}\n          \";\n          pgp.AddLemma(str, \"Postconditions\");\n\n          str = $@\"\n            lemma lemma_StraightlineBehaviorSatisfiesPostcondition_{sbd.Name}(\n              sb: LAtomicStraightlineBehavior,\n              tid: Armada_ThreadHandle,\n              proc: LProcName\n              )\n              requires AnnotatedBehaviorSatisfiesSpec(sb, GetLAtomicStraightlineSpec(tid, proc))\n              requires StraightlineBehaviorFullySatisfiesDescriptor(sb.trace, proc, SBD_{sbd.Name})\n              ensures  EnsuresClauses(proc, sb.states[0].state, last(sb.states).state, tid)\n            {{\n              assert proc.LProcName_{sbd.MethodName}?;\n              lemma_EnumerateStraightlineBehavior_{sbd.Name}(sb, tid, proc);\n              lemma_EnumeratedStraightlineBehaviorSatisfiesPostcondition_{sbd.Name}({enumeratedParamValues});\n            }}\n          \";\n          pgp.AddLemma(str, \"PostconditionsAlways\");\n        }\n        else {\n          str = $@\"\n            lemma lemma_StraightlineBehaviorSatisfiesPostcondition_{sbd.Name}(\n              sb: LAtomicStraightlineBehavior,\n              tid: Armada_ThreadHandle,\n              proc: LProcName\n              )\n              requires AnnotatedBehaviorSatisfiesSpec(sb, GetLAtomicStraightlineSpec(tid, proc))\n              requires StraightlineBehaviorFullySatisfiesDescriptor(sb.trace, proc, SBD_{sbd.Name})\n              requires var s := last(sb.states).state; tid in s.s.threads && IsReturnSite(s.s.threads[tid].pc)\n              ensures  false\n            {{\n              var pc := last(sb.states).state.s.threads[tid].pc;\n              lemma_StraightlineBehaviorEndProperties_{sbd.Name}(sb, tid, proc);\n              assert !IsReturnSite(pc);\n            }}\n          \";\n          pgp.AddLemma(str, \"PostconditionsAlways\");\n        }\n      }\n\n      str = @\"\n        lemma lemma_StraightlineBehaviorSatisfiesPostcondition(\n          sb: LAtomicStraightlineBehavior,\n          tid: Armada_ThreadHandle,\n          proc: LProcName\n          )\n          requires AnnotatedBehaviorSatisfiesSpec(sb, GetLAtomicStraightlineSpec(tid, proc))\n          requires var phase := last(sb.states).aux.phase; phase.StraightlinePhaseYielded?\n          requires var s := last(sb.states).state; tid in s.s.threads && IsReturnSite(s.s.threads[tid].pc)\n          ensures  EnsuresClauses(proc, sb.states[0].state, last(sb.states).state, tid)\n        {\n          var sbd := lemma_GetFullDescriptorForStraightlineBehaviorEndingYielded(sb, tid, proc);\n          assert StraightlineBehaviorDescriptorEndsYieldedPossibilities(sbd);\n          match sbd {\n      \";\n      foreach (var sbd in straightlineBehaviorDescriptors) {\n        str += $\"case SBD_{sbd.Name} =>\\n\";\n        if (sbd.LastState is StraightlineStateYielded) {\n          str += $\"lemma_StraightlineBehaviorSatisfiesPostcondition_{sbd.Name}(sb, tid, proc);\\n\";\n        }\n        else {\n          str += $@\"\n            assert !StraightlineBehaviorDescriptorEndsYieldedPossibilities(sbd);\n            assert false;\n          \";\n        }\n      }\n      str += \"} }\\n\";\n      pgp.AddLemma(str, \"PostconditionsAlways\");\n\n      str = @\"\n        lemma lemma_StraightlineBehaviorsSatisfyPostconditions()\n          ensures StraightlineBehaviorsSatisfyPostconditions(GetConcurrentHoareLogicRequest())\n        {\n          var cr := GetConcurrentHoareLogicRequest();\n          forall sb, actor, proc {:trigger StraightlineBehaviorsSatisfyPostconditionsConditions(cr, sb, actor, proc)}\n            | StraightlineBehaviorsSatisfyPostconditionsConditions(cr, sb, actor, proc)\n            ensures cr.ensures_clauses(proc, sb.states[0].state, last(sb.states).state, actor)\n          {\n            lemma_StraightlineBehaviorSatisfiesPostcondition(sb, actor, proc);\n          }\n        }\n      \";\n      pgp.AddLemma(str, \"PostconditionsAlways\");\n    }\n\n    private bool EndsAtVisitedLoopHead(StraightlineBehavior sbd)\n    {\n      var pc = sbd.LastState.PC;\n      return loopHeads.Contains(pc) && sbd.LastState.IsLoopHeadVisited(pc);\n    }\n\n    private bool EndsAtUnvisitedLoopHead(StraightlineBehavior sbd)\n    {\n      var pc = sbd.LastState.PC;\n      return loopHeads.Contains(pc) && !sbd.LastState.IsLoopHeadVisited(pc);\n    }\n\n    private void GenerateStraightlineBehaviorsSatisfyLoopModifiesClausesOnEntryProof()\n    {\n      string str;\n\n      var alwaysFile = pgp.proofFiles.CreateAuxiliaryProofFile(\"LoopEntryAlways\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"specs\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"invariants\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"defs\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"latomic\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"sbd\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"pcstack\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"exhaustive\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"continuation\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"enumeration\");\n      alwaysFile.AddImport(\"ConcurrentHoareLogicSpecModule\");\n      alwaysFile.AddImport(\"AtomicConcurrentHoareLogicSpecModule\");\n      alwaysFile.AddImport(\"util_collections_seqs_s\");\n      pgp.proofFiles.MainProof.IncludeAndImportGeneratedFile(\"LoopEntryAlways\");\n\n      var loopEntryFile = pgp.proofFiles.CreateAuxiliaryProofFile(\"LoopEntry\");\n      loopEntryFile.IncludeAndImportGeneratedFile(\"specs\");\n      loopEntryFile.IncludeAndImportGeneratedFile(\"defs\");\n      loopEntryFile.IncludeAndImportGeneratedFile(\"revelations\");\n      loopEntryFile.IncludeAndImportGeneratedFile(\"invariants\");\n      loopEntryFile.IncludeAndImportGeneratedFile(\"latomic\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"LoopEntry\");\n\n      var extractorEnumeration = new ExtractorEnumeration(lAtomic);\n      var extractorSB = new ExtractorSB(\"sb\", \"tid\", \"proc\");\n      foreach (var sbd in sbdsEndingYielded)\n      {\n        if (EndsAtUnvisitedLoopHead(sbd)) {\n          var pathExpander = new PathExpander(sbd);\n          var extractorExpanded = new ExtractorExpanded(pathExpander);\n          var expandedParamDeclarations =\n            String.Join(\", \", new List<string>{ \"tid: Armada_ThreadHandle\" }.Concat(sbd.GetStatesAndSteps(extractorExpanded, true)));\n          var expandedParamValues =\n            String.Join(\", \", new List<string>{ \"tid\" }.Concat(sbd.GetStatesAndSteps(extractorEnumeration, false)));\n          var enumeratedParamDeclarations =\n            String.Join(\", \", new List<string>{ \"tid:Armada_ThreadHandle\" }.Concat(sbd.GetStatesAndPaths(extractorEnumeration, true)));\n          var enumeratedParamValues = String.Join(\", \", new List<string>{ \"tid\" }.Concat(sbd.GetStatesAndPaths(extractorSB, false)));\n\n          str = $@\"\n            lemma lemma_ExpandedStraightlineBehaviorSatisfiesLoopModifiesClausesOnEntry_{sbd.Name}({expandedParamDeclarations})\n          \";\n          str += String.Concat(sbd.GetEnumerationClauses(extractorExpanded, true).Select(r => \"requires \" + r + \"\\n\"));\n          str += $@\"\n              ensures  LoopModifies_{sbd.LastState.PC}({extractorExpanded.State(sbd.NumSteps)},\n                                                       {extractorExpanded.State(sbd.NumSteps)}, tid)\n            {{\n              ProofCustomizationGoesHere();\n            }}\n          \";\n          pgp.AddLemma(str, \"LoopEntry\");\n\n          str = $@\"\n            lemma lemma_EnumeratedStraightlineBehaviorSatisfiesLoopModifiesClausesOnEntry_{sbd.Name}({enumeratedParamDeclarations})\n          \";\n          str += String.Concat(sbd.GetEnumerationClauses(extractorEnumeration).Select(r => \"requires \" + r + \"\\n\"));\n          str += $@\"\n              ensures  LoopModifies_{sbd.LastState.PC}(s{sbd.NumSteps}, s{sbd.NumSteps}, tid)\n            {{\n              { String.Concat(sbd.GetOpenValidPathInvocations(extractorEnumeration)) }\n              lemma_ExpandedStraightlineBehaviorSatisfiesLoopModifiesClausesOnEntry_{sbd.Name}({expandedParamValues});\n            }}\n          \";\n          pgp.AddLemma(str, \"LoopEntry\");\n\n          str = $@\"\n            lemma lemma_StraightlineBehaviorSatisfiesLoopModifiesClausesOnEntry_{sbd.Name}(\n              sb: LAtomicStraightlineBehavior,\n              tid: Armada_ThreadHandle,\n              proc: LProcName\n              )\n              requires AnnotatedBehaviorSatisfiesSpec(sb, GetLAtomicStraightlineSpec(tid, proc))\n              requires StraightlineBehaviorFullySatisfiesDescriptor(sb.trace, proc, SBD_{sbd.Name})\n              requires tid in last(sb.states).state.s.threads\n              ensures  var s := last(sb.states).state; LoopModifiesClauses(s.s.threads[tid].pc, s, s, tid)\n            {{\n              var s := last(sb.states).state;\n              var pc := s.s.threads[tid].pc;\n              assert proc.LProcName_{sbd.MethodName}?;\n              lemma_EnumerateStraightlineBehavior_{sbd.Name}(sb, tid, proc);\n              lemma_EnumeratedStraightlineBehaviorSatisfiesLoopModifiesClausesOnEntry_{sbd.Name}({enumeratedParamValues});\n              assert LoopModifies_{sbd.LastState.PC}(s, s, tid);\n              forall ensures pc.{sbd.LastState.PC}? {{\n                lemma_StraightlineBehaviorEndProperties_{sbd.Name}(sb, tid, proc);\n              }}\n              assert LoopModifiesClauses(pc, s, s, tid);\n            }}\n          \";\n          pgp.AddLemma(str, \"LoopEntryAlways\");\n        }\n        else if (EndsAtVisitedLoopHead(sbd)) {\n          str = $@\"\n            lemma lemma_StraightlineBehaviorSatisfiesLoopModifiesClausesOnEntry_{sbd.Name}(\n              sb: LAtomicStraightlineBehavior,\n              tid: Armada_ThreadHandle,\n              proc: LProcName\n              )\n              requires AnnotatedBehaviorSatisfiesSpec(sb, GetLAtomicStraightlineSpec(tid, proc))\n              requires StraightlineBehaviorFullySatisfiesDescriptor(sb.trace, proc, SBD_{sbd.Name})\n              requires var StraightlineState(s, aux) := last(sb.states);\n                       tid in s.s.threads && s.s.threads[tid].pc !in aux.visited_loops\n              ensures  false\n            {{\n              var StraightlineState(s, aux) := last(sb.states);\n              var pc := s.s.threads[tid].pc;\n              lemma_StraightlineBehaviorEndProperties_{sbd.Name}(sb, tid, proc);\n              assert pc in aux.visited_loops;\n            }}\n          \";\n          pgp.AddLemma(str, \"LoopEntryAlways\");\n        }\n        else {\n          str = $@\"\n            lemma lemma_StraightlineBehaviorSatisfiesLoopModifiesClausesOnEntry_{sbd.Name}(\n              sb: LAtomicStraightlineBehavior,\n              tid: Armada_ThreadHandle,\n              proc: LProcName\n              )\n              requires AnnotatedBehaviorSatisfiesSpec(sb, GetLAtomicStraightlineSpec(tid, proc))\n              requires StraightlineBehaviorFullySatisfiesDescriptor(sb.trace, proc, SBD_{sbd.Name})\n              requires var s :=  last(sb.states).state;\n                       tid in s.s.threads && IsLoopHead(s.s.threads[tid].pc)\n              ensures  false\n            {{\n              var StraightlineState(s, aux) := last(sb.states);\n              var pc := s.s.threads[tid].pc;\n              lemma_StraightlineBehaviorEndProperties_{sbd.Name}(sb, tid, proc);\n              assert !IsLoopHead(pc);\n            }}\n          \";\n          pgp.AddLemma(str, \"LoopEntryAlways\");\n        }\n      }\n\n      str = @\"\n        lemma lemma_StraightlineBehaviorSatisfiesLoopModifiesClausesOnEntry(\n          sb: LAtomicStraightlineBehavior,\n          tid: Armada_ThreadHandle,\n          proc: LProcName\n          )\n          requires AnnotatedBehaviorSatisfiesSpec(sb, GetLAtomicStraightlineSpec(tid, proc))\n          requires var StraightlineState(s, aux) := last(sb.states);\n                   && aux.phase.StraightlinePhaseYielded?\n                   && tid in s.s.threads\n                   && IsLoopHead(s.s.threads[tid].pc)\n                   && s.s.threads[tid].pc !in aux.visited_loops\n          ensures  var s := last(sb.states).state; LoopModifiesClauses(s.s.threads[tid].pc, s, s, tid)\n        {\n          var sbd := lemma_GetFullDescriptorForStraightlineBehaviorEndingYielded(sb, tid, proc);\n          assert StraightlineBehaviorDescriptorEndsYieldedPossibilities(sbd);\n          var StraightlineState(s, aux) := last(sb.states);\n          var pc := s.s.threads[tid].pc;\n          match sbd {\n      \";\n      foreach (var sbd in straightlineBehaviorDescriptors) {\n        str += $\"case SBD_{sbd.Name} =>\\n\";\n        if (sbd.LastState is StraightlineStateYielded) {\n          str += $\"lemma_StraightlineBehaviorSatisfiesLoopModifiesClausesOnEntry_{sbd.Name}(sb, tid, proc);\\n\";\n        }\n        else {\n          str += $@\"\n            assert !StraightlineBehaviorDescriptorEndsYieldedPossibilities(sbd);\n            assert false;\n          \";\n        }\n      }\n      str += \"} }\\n\";\n      pgp.AddLemma(str, \"LoopEntryAlways\");\n\n      str = @\"\n        lemma lemma_StraightlineBehaviorsSatisfyLoopModifiesClausesOnEntry()\n          ensures StraightlineBehaviorsSatisfyLoopModifiesClausesOnEntry(GetConcurrentHoareLogicRequest())\n        {\n          var cr := GetConcurrentHoareLogicRequest();\n          forall sb, actor, proc {:trigger StraightlineBehaviorsSatisfyLoopModifiesClausesOnEntryConditions(cr, sb, actor, proc)}\n            | StraightlineBehaviorsSatisfyLoopModifiesClausesOnEntryConditions(cr, sb, actor, proc)\n            ensures var s := last(sb.states).state;\n                    var pc := cr.get_actor_pc_stack(s, actor).v.pc;\n                    cr.loop_modifies_clauses(pc, s, s, actor)\n          {\n            assert cr.get_actor_pc_stack(last(sb.states).state, actor).Some?;\n            lemma_StraightlineBehaviorSatisfiesLoopModifiesClausesOnEntry(sb, actor, proc);\n          }\n        }\n      \";\n      pgp.AddLemma(str, \"LoopEntryAlways\");\n    }\n\n    private bool RevisitsLoopHead(Tuple<AtomicPath, CHLPathEffect> tup, StraightlineBehavior sbd)\n    {\n      var atomicPath = tup.Item1;\n      var effect = tup.Item2;\n      return (   (sbd.LastState is StraightlineStateYielded && effect is CHLPathEffectNormal)\n              || (sbd.LastState is StraightlineStateEnsured && effect is CHLPathEffectReturn))\n             && atomicPath.EndPC != null\n             && sbd.LastState.IsLoopHeadVisited(atomicPath.EndPC);\n    }\n\n    private void GenerateStraightlineBehaviorsSatisfyLoopModifiesClausesOnJumpBackProof()\n    {\n      string str;\n\n      var alwaysFile = pgp.proofFiles.CreateAuxiliaryProofFile(\"LoopBackAlways\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"specs\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"invariants\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"defs\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"latomic\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"sbd\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"pcstack\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"exhaustive\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"continuation\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"enumeration\");\n      alwaysFile.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/strategies/chl/AtomicConcurrentHoareLogicSpec.i.dfy\");\n      alwaysFile.AddImport(\"ConcurrentHoareLogicSpecModule\");\n      alwaysFile.AddImport(\"AtomicConcurrentHoareLogicSpecModule\");\n      alwaysFile.AddIncludeImport(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/option.s.dfy\", \"util_option_s\");\n      alwaysFile.AddImport(\"util_collections_seqs_s\");\n      pgp.proofFiles.MainProof.IncludeAndImportGeneratedFile(\"LoopBackAlways\");\n\n      var loopJumpBackFile = pgp.proofFiles.CreateAuxiliaryProofFile(\"LoopBack\");\n      loopJumpBackFile.IncludeAndImportGeneratedFile(\"specs\");\n      loopJumpBackFile.IncludeAndImportGeneratedFile(\"defs\");\n      loopJumpBackFile.IncludeAndImportGeneratedFile(\"revelations\");\n      loopJumpBackFile.IncludeAndImportGeneratedFile(\"latomic\");\n      loopJumpBackFile.IncludeAndImportGeneratedFile(\"invariants\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"LoopBack\");\n\n      var extractorEnumeration = new ExtractorEnumeration(lAtomic);\n      var extractorSB = new ExtractorSB(\"sb\", \"tid\", \"proc\");\n      foreach (var sbd in sbdsEndingYielded)\n      {\n        if (EndsAtVisitedLoopHead(sbd)) {\n          var pos = sbd.LastState.VisitedLoopHeads[sbd.LastState.PC];\n          var pathExpander = new PathExpander(sbd);\n          var extractorExpanded = new ExtractorExpanded(pathExpander);\n          var expandedParamDeclarations =\n            String.Join(\", \", new List<string>{ \"tid: Armada_ThreadHandle\" }.Concat(sbd.GetStatesAndSteps(extractorExpanded, true)));\n          var expandedParamValues =\n            String.Join(\", \", new List<string>{ \"tid\" }.Concat(sbd.GetStatesAndSteps(extractorEnumeration, false)));\n          var enumeratedParamDeclarations =\n            String.Join(\", \", new List<string>{ \"tid:Armada_ThreadHandle\" }.Concat(sbd.GetStatesAndPaths(extractorEnumeration, true)));\n          var enumeratedParamValues = String.Join(\", \", new List<string>{ \"tid\" }.Concat(sbd.GetStatesAndPaths(extractorSB, false)));\n\n          str = $@\"\n            lemma lemma_ExpandedStraightlineBehaviorSatisfiesLoopModifiesClausesOnJumpBack_{sbd.Name}({expandedParamDeclarations})\n          \";\n          str += String.Concat(sbd.GetEnumerationClauses(extractorExpanded, true).Select(r => \"requires \" + r + \"\\n\"));\n          str += $@\"\n              ensures  LoopModifies_{sbd.LastState.PC}({extractorExpanded.State(pos)}, {extractorExpanded.State(sbd.NumSteps)}, tid)\n              ensures  {extractorExpanded.State(pos)}.config == {extractorExpanded.State(sbd.NumSteps)}.config\n            {{\n              ProofCustomizationGoesHere();\n            }}\n          \";\n          pgp.AddLemma(str, \"LoopBack\");\n\n          str = $@\"\n            lemma lemma_EnumeratedStraightlineBehaviorSatisfiesLoopModifiesClausesOnJumpBack_{sbd.Name}({enumeratedParamDeclarations})\n          \";\n          str += String.Concat(sbd.GetEnumerationClauses(extractorEnumeration).Select(r => \"requires \" + r + \"\\n\"));\n          str += $@\"\n              ensures  LoopModifies_{sbd.LastState.PC}(s{pos}, s{sbd.NumSteps}, tid)\n              ensures  s{pos}.config == s{sbd.NumSteps}.config\n            {{\n              { String.Concat(sbd.GetOpenValidPathInvocations(extractorEnumeration)) }\n              lemma_ExpandedStraightlineBehaviorSatisfiesLoopModifiesClausesOnJumpBack_{sbd.Name}({expandedParamValues});\n            }}\n          \";\n          pgp.AddLemma(str, \"LoopBack\");\n\n          str = $@\"\n            lemma lemma_StraightlineBehaviorSatisfiesLoopModifiesClausesOnJumpBack_{sbd.Name}(\n              sb: LAtomicStraightlineBehavior,\n              tid: Armada_ThreadHandle,\n              proc: LProcName\n              )\n              requires AnnotatedBehaviorSatisfiesSpec(sb, GetLAtomicStraightlineSpec(tid, proc))\n              requires StraightlineBehaviorFullySatisfiesDescriptor(sb.trace, proc, SBD_{sbd.Name})\n              requires var StraightlineState(s, aux) := last(sb.states);\n                       tid in s.s.threads && s.s.threads[tid].pc in aux.visited_loops\n              ensures  var StraightlineState(s, aux) := last(sb.states);\n                       var pc := s.s.threads[tid].pc;\n                       LoopModifiesClauses(pc, aux.visited_loops[pc], s, tid)\n            {{\n              var StraightlineState(s, aux) := last(sb.states);\n              var pc := s.s.threads[tid].pc;\n              assert proc.LProcName_{sbd.MethodName}?;\n              lemma_EnumerateStraightlineBehavior_{sbd.Name}(sb, tid, proc);\n              lemma_EnumeratedStraightlineBehaviorSatisfiesLoopModifiesClausesOnJumpBack_{sbd.Name}({enumeratedParamValues});\n              assert LoopModifies_{sbd.LastState.PC}(sb.states[{pos}].state, last(sb.states).state, tid);\n              assert sb.states[{pos}].state.config == last(sb.states).state.config;\n              forall\n                ensures pc.{sbd.LastState.PC}?\n                ensures aux.visited_loops[pc] == sb.states[{pos}].state\n              {{\n                lemma_StraightlineBehaviorEndProperties_{sbd.Name}(sb, tid, proc);\n              }}\n              assert LoopModifiesClauses(pc, aux.visited_loops[pc], s, tid);\n            }}\n          \";\n          pgp.AddLemma(str, \"LoopBackAlways\");\n        }\n        else if (EndsAtUnvisitedLoopHead(sbd)) {\n          str = $@\"\n            lemma lemma_StraightlineBehaviorSatisfiesLoopModifiesClausesOnJumpBack_{sbd.Name}(\n              sb: LAtomicStraightlineBehavior,\n              tid: Armada_ThreadHandle,\n              proc: LProcName\n              )\n              requires AnnotatedBehaviorSatisfiesSpec(sb, GetLAtomicStraightlineSpec(tid, proc))\n              requires StraightlineBehaviorFullySatisfiesDescriptor(sb.trace, proc, SBD_{sbd.Name})\n              requires var StraightlineState(s, aux) := last(sb.states);\n                       tid in s.s.threads && s.s.threads[tid].pc in aux.visited_loops\n              ensures  false\n            {{\n              var StraightlineState(s, aux) := last(sb.states);\n              var pc := s.s.threads[tid].pc;\n              lemma_StraightlineBehaviorEndProperties_{sbd.Name}(sb, tid, proc);\n              assert pc !in aux.visited_loops;\n            }}\n          \";\n          pgp.AddLemma(str, \"LoopBackAlways\");\n        }\n        else {\n          str = $@\"\n            lemma lemma_StraightlineBehaviorSatisfiesLoopModifiesClausesOnJumpBack_{sbd.Name}(\n              sb: LAtomicStraightlineBehavior,\n              tid: Armada_ThreadHandle,\n              proc: LProcName\n              )\n              requires AnnotatedBehaviorSatisfiesSpec(sb, GetLAtomicStraightlineSpec(tid, proc))\n              requires StraightlineBehaviorFullySatisfiesDescriptor(sb.trace, proc, SBD_{sbd.Name})\n              requires var s := last(sb.states).state;\n                       tid in s.s.threads && IsLoopHead(s.s.threads[tid].pc)\n              ensures  false\n            {{\n              var StraightlineState(s, aux) := last(sb.states);\n              var pc := s.s.threads[tid].pc;\n              lemma_StraightlineBehaviorEndProperties_{sbd.Name}(sb, tid, proc);\n              assert !IsLoopHead(pc);\n            }}\n          \";\n          pgp.AddLemma(str, \"LoopBackAlways\");\n        }\n      }\n\n      str = @\"\n        lemma lemma_StraightlineBehaviorSatisfiesLoopModifiesClausesOnJumpBack(\n          sb: LAtomicStraightlineBehavior,\n          tid: Armada_ThreadHandle,\n          proc: LProcName\n          )\n          requires AnnotatedBehaviorSatisfiesSpec(sb, GetLAtomicStraightlineSpec(tid, proc))\n          requires var StraightlineState(s, aux) := last(sb.states);\n                   && aux.phase.StraightlinePhaseYielded?\n                   && tid in s.s.threads\n                   && IsLoopHead(s.s.threads[tid].pc)\n                   && s.s.threads[tid].pc in aux.visited_loops\n          ensures  var StraightlineState(s, aux) := last(sb.states);\n                   var pc := s.s.threads[tid].pc;\n                   LoopModifiesClauses(pc, aux.visited_loops[pc], s, tid)\n        {\n          var sbd := lemma_GetFullDescriptorForStraightlineBehaviorEndingYielded(sb, tid, proc);\n          assert StraightlineBehaviorDescriptorEndsYieldedPossibilities(sbd);\n          var StraightlineState(s, aux) := last(sb.states);\n          var pc := s.s.threads[tid].pc;\n          match sbd {\n      \";\n      foreach (var sbd in straightlineBehaviorDescriptors) {\n        str += $\"case SBD_{sbd.Name} =>\\n\";\n        if (sbd.LastState is StraightlineStateYielded) {\n          str += $\"lemma_StraightlineBehaviorSatisfiesLoopModifiesClausesOnJumpBack_{sbd.Name}(sb, tid, proc);\\n\";\n        }\n        else {\n          str += $@\"\n            assert !StraightlineBehaviorDescriptorEndsYieldedPossibilities(sbd);\n            assert false;\n          \";\n        }\n      }\n      str += \"} }\\n\";\n      pgp.AddLemma(str, \"LoopBackAlways\");\n\n      str = @\"\n        lemma lemma_StraightlineBehaviorsSatisfyLoopModifiesClausesOnJumpBack()\n          ensures StraightlineBehaviorsSatisfyLoopModifiesClausesOnJumpBack(GetConcurrentHoareLogicRequest())\n        {\n          var cr := GetConcurrentHoareLogicRequest();\n          forall sb, actor, proc {:trigger StraightlineBehaviorsSatisfyLoopModifiesClausesOnJumpBackConditions(cr, sb, actor, proc)}\n            | StraightlineBehaviorsSatisfyLoopModifiesClausesOnJumpBackConditions(cr, sb, actor, proc)\n            ensures var StraightlineState(s, aux) := last(sb.states);\n                    var pc := cr.get_actor_pc_stack(s, actor).v.pc;\n                    cr.loop_modifies_clauses(pc, aux.visited_loops[pc], s, actor)\n          {\n            lemma_StraightlineBehaviorSatisfiesLoopModifiesClausesOnJumpBack(sb, actor, proc);\n          }\n        }\n      \";\n      pgp.AddLemma(str, \"LoopBackAlways\");\n    }\n\n    private void GenerateStraightlineBehaviorsSatisfyYieldPredicatesProof()\n    {\n      string str;\n\n      var alwaysFile = pgp.proofFiles.CreateAuxiliaryProofFile(\"YieldAlways\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"specs\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"invariants\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"defs\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"latomic\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"others\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"sbd\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"pcstack\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"exhaustive\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"continuation\");\n      alwaysFile.IncludeAndImportGeneratedFile(\"enumeration\");\n      alwaysFile.AddImport(\"ConcurrentHoareLogicSpecModule\");\n      alwaysFile.AddImport(\"AtomicConcurrentHoareLogicSpecModule\");\n      alwaysFile.AddImport(\"util_collections_seqs_s\");\n      pgp.proofFiles.MainProof.IncludeAndImportGeneratedFile(\"YieldAlways\");\n\n      // If the yield predicate is just \"true\", generate a very simple lemma:\n\n      if (!yieldPredicateInfos.Any()) {\n        str = @\"\n          lemma lemma_StraightlineBehaviorsSatisfyYieldPredicate()\n            ensures StraightlineBehaviorsSatisfyYieldPredicate(GetConcurrentHoareLogicRequest())\n          {\n            var cr := GetConcurrentHoareLogicRequest();\n            forall sb, step, s', other_actor {:trigger StraightlineBehaviorsSatisfyYieldPredicateConditions(cr, sb, step, s', other_actor)}\n              | StraightlineBehaviorsSatisfyYieldPredicateConditions(cr, sb, step, s', other_actor)\n              ensures cr.yield_pred(last(sb.states).state, s', other_actor)\n            {\n              var asf := LAtomic_GetSpecFunctions();\n              var s := last(sb.states).state;\n              var s' := asf.path_next(s, step.path, step.tid);\n              lemma_LAtomic_AtomicPathCantAffectOtherThreadsExceptViaFork(asf, s, step.path, step.tid);\n              lemma_PathLeavesConfigUnchanged(s, s', step.path, step.tid);\n              assert ActionTuple(s, s', PathAndTid(step.path, step.tid)) in cr.spec.next;\n              lemma_CHLStepEffectsCorrect();\n              assert YieldPredicateBasic(s, s', other_actor);\n            }\n          }\n        \";\n        pgp.AddLemma(str, \"YieldAlways\");\n\n        return;\n      }\n\n      // Otherwise, create a file for each yield predicate conjunct\n\n      foreach (var item in yieldPredicateInfos)\n      {\n        var predName = item.Key;\n        var specificPredFile = pgp.proofFiles.CreateAuxiliaryProofFile($\"Yield_{predName}\");\n        specificPredFile.IncludeAndImportGeneratedFile(\"specs\");\n        specificPredFile.IncludeAndImportGeneratedFile(\"defs\");\n        specificPredFile.IncludeAndImportGeneratedFile(\"revelations\");\n        specificPredFile.IncludeAndImportGeneratedFile(\"invariants\");\n        specificPredFile.IncludeAndImportGeneratedFile(\"latomic\");\n        alwaysFile.IncludeAndImportGeneratedFile($\"Yield_{predName}\");\n      }\n\n      var extractorEnumeration = new ExtractorEnumeration(lAtomic);\n      var extractorSB = new ExtractorSB(\"sb\", \"tid\", \"proc\");\n      foreach (var sbd in sbdsEndingYielded.Concat(sbdsEndingEnsured))\n      {\n        foreach (var atomicPath in sbd.PotentialSuccessorPaths.Where(tup => tup.Item2.CanFollow(sbd.LastState)).Select(tup => tup.Item1))\n        {\n          var beyondEnd = new StraightlineStepBeyondEnd(sbd.NumSteps, atomicPath, pcsWithLocalInvariants.Contains(sbd.LastState.PC));\n          var sbdPlus = new StraightlineBehavior(sbd, beyondEnd);\n          var pathExpander = new PathExpander(sbdPlus);\n          var extractorExpanded = new ExtractorExpanded(pathExpander);\n\n          var expandedParamDeclarations =\n            String.Join(\", \", new List<string>{ \"tid: Armada_ThreadHandle\", \"other_tid: Armada_ThreadHandle\" }\n                               .Concat(sbdPlus.GetStatesAndSteps(extractorExpanded, true)));\n          var expandedParamValues =\n            String.Join(\", \", new List<string>{ \"tid\", \"other_tid\" }\n                                .Concat(sbdPlus.GetStatesAndSteps(extractorEnumeration, false)));\n          var enumeratedParamDeclarations =\n            String.Join(\", \", new List<string> { \"tid: Armada_ThreadHandle\", \"other_tid: Armada_ThreadHandle\" }\n                               .Concat(sbdPlus.GetStatesAndPaths(extractorEnumeration, true)));\n          var enumeratedParamValues =\n            String.Join(\", \", new List<string>{ \"tid\", \"other_tid\" }\n                                .Concat(sbd.GetStatesAndPaths(extractorSB, false))\n                                .Concat(new List<string>{ \"path\", \"s'\" }));\n\n          foreach (var yieldPredicateInfo in yieldPredicateInfos)\n          {\n            var predName = yieldPredicateInfo.Key;\n            var predFun = yieldPredicateInfo.Value;\n\n            str = $@\"\n              lemma lemma_ExpandedStraightlineBehaviorSatisfiesYieldPredicate_{predName}_{sbd.Name}_Then_{atomicPath.Name}(\n                {expandedParamDeclarations}\n              )\n            \";\n            str += String.Concat(sbdPlus.GetEnumerationClauses(extractorExpanded, true).Select(r => \"requires \" + r + \"\\n\"));\n            str += $@\"\n                requires tid != other_tid\n                requires other_tid in {extractorExpanded.State(sbd.NumSteps)}.s.threads\n                ensures  {predFun}({extractorExpanded.State(sbd.NumSteps)}, {extractorExpanded.State(sbd.NumSteps + 1)}, other_tid)\n              {{\n                ProofCustomizationGoesHere();\n              }}\n            \";\n            pgp.AddLemma(str, $\"Yield_{predName}\");\n\n            str = $@\"\n              lemma lemma_EnumeratedStraightlineBehaviorSatisfiesYieldPredicate_{predName}_{sbd.Name}_Then_{atomicPath.Name}(\n                {enumeratedParamDeclarations}\n              )\n            \";\n            str += String.Concat(sbdPlus.GetEnumerationClauses(extractorEnumeration).Select(r => \"requires \" + r + \"\\n\"));\n            str += $@\"\n                requires tid != other_tid\n                requires other_tid in s{sbd.NumSteps}.s.threads\n                ensures  {predFun}(s{sbd.NumSteps}, s{sbd.NumSteps + 1}, other_tid)\n              {{\n                { String.Concat(sbd.GetOpenValidPathInvocations(extractorEnumeration)) }\n                { extractorEnumeration.GetOpenValidPathInvocation(atomicPath, sbd.NumSteps) }\n                lemma_ExpandedStraightlineBehaviorSatisfiesYieldPredicate_{predName}_{sbd.Name}_Then_{atomicPath.Name}(\n                  {expandedParamValues}\n                );\n              }}\n            \";\n            pgp.AddLemma(str, $\"Yield_{predName}\");\n          }\n\n          str = $@\"\n            lemma lemma_StraightlineBehaviorSatisfiesYieldPredicate_{sbd.Name}_Then_{atomicPath.Name}(\n              sb: LAtomicStraightlineBehavior,\n              path: LAtomic_Path,\n              tid: Armada_ThreadHandle,\n              s': LPlusState,\n              other_tid: Armada_ThreadHandle\n              )\n              requires path.LAtomic_Path_{atomicPath.Name}?\n              requires AnnotatedBehaviorSatisfiesSpec(sb, GetLAtomicStraightlineSpec(tid, LProcName_{sbd.MethodName}))\n              requires LocalInv(last(sb.states).state, tid)\n              requires LAtomic_NextPath(last(sb.states).state, s', path, tid)\n              requires StraightlineBehaviorFullySatisfiesDescriptor(sb.trace, LProcName_{sbd.MethodName}, SBD_{sbd.Name})\n              requires tid != other_tid\n              requires other_tid in last(sb.states).state.s.threads\n              ensures  YieldPredicate(last(sb.states).state, s', other_tid)\n            {{\n              var proc := LProcName_{sbd.MethodName};\n              var asf := LAtomic_GetSpecFunctions();\n              var s := last(sb.states).state;\n              lemma_LAtomic_AtomicPathCantAffectOtherThreadsExceptViaFork(asf, s, path, tid);\n              lemma_PathLeavesConfigUnchanged(s, s', path, tid);\n              lemma_LAtomic_PathHasPCStackEffect_{atomicPath.Name}(s, s', path, tid);\n              assert YieldPredicateBasic(s, s', other_tid);\n              lemma_EnumerateStraightlineBehavior_{sbd.Name}(sb, tid, proc);\n          \";\n          str += String.Concat(yieldPredicateInfos.Select(kv => kv.Key).Select(predName => $@\"\n              lemma_EnumeratedStraightlineBehaviorSatisfiesYieldPredicate_{predName}_{sbd.Name}_Then_{atomicPath.Name}({enumeratedParamValues});\n          \"));\n          str += \"}\";\n          pgp.AddLemma(str, \"YieldAlways\");\n        }\n\n        var optionalNot = (sbd.LastState is StraightlineStateYielded) ? \"!\" : \"\";\n        str = $@\"\n          lemma lemma_StraightlineBehaviorSatisfiesYieldPredicate_{sbd.Name}(\n            sb: LAtomicStraightlineBehavior,\n            path: LAtomic_Path,\n            tid: Armada_ThreadHandle,\n            s': LPlusState,\n            other_tid: Armada_ThreadHandle\n            )\n            requires !path.LAtomic_Path_Tau?\n            requires AnnotatedBehaviorSatisfiesSpec(sb, GetLAtomicStraightlineSpec(tid, LProcName_{sbd.MethodName}))\n            requires LocalInv(last(sb.states).state, tid)\n            requires LAtomic_NextPath(last(sb.states).state, s', path, tid)\n            requires StraightlineBehaviorFullySatisfiesDescriptor(sb.trace, LProcName_{sbd.MethodName}, SBD_{sbd.Name})\n            requires !PathToEffect(path).CHLStepEffectStop?\n            requires var effect := PathToEffect(path);\n                     {optionalNot}(effect.CHLStepEffectReturn? || effect.CHLStepEffectReturnThenCall?)\n            requires tid != other_tid\n            requires other_tid in last(sb.states).state.s.threads\n            ensures  YieldPredicate(last(sb.states).state, s', other_tid)\n          {{\n            lemma_StraightlineBehaviorNonstoppingContinuationPossibilities_{sbd.Name}(sb, tid, LProcName_{sbd.MethodName}, s', path);\n            match path {{\n        \";\n        foreach (var tup in sbd.PotentialSuccessorPaths)\n        {\n          var path = tup.Item1;\n          var effect = tup.Item2;\n          str += $\"case LAtomic_Path_{path.Name}(_) =>\\n\";\n          if (effect.CanFollow(sbd.LastState)) {\n            str += $\"lemma_StraightlineBehaviorSatisfiesYieldPredicate_{sbd.Name}_Then_{path.Name}(sb, path, tid, s', other_tid);\\n\";\n          }\n          else {\n            str += $@\"\n                assert PathToEffect(path) == {effect.Constructor};\n                assert false;\n            \";\n          }\n        }\n        str += \"} }\\n\";\n        pgp.AddLemma(str, \"YieldAlways\");\n      }\n\n      str = @\"\n        lemma lemma_StraightlineBehaviorSatisfiesYieldPredicate(\n          sb: LAtomicStraightlineBehavior,\n          path: LAtomic_Path,\n          tid: Armada_ThreadHandle,\n          s': LPlusState,\n          other_tid: Armada_ThreadHandle\n          )\n          requires !path.LAtomic_Path_Tau?\n          requires AnnotatedBehaviorSatisfiesSpec(sb, GetLAtomicStraightlineSpec(tid, PathToProc(path)))\n          requires LocalInv(last(sb.states).state, tid)\n          requires LAtomic_NextPath(last(sb.states).state, s', path, tid)\n          requires !PathToEffect(path).CHLStepEffectStop?\n          requires var phase := last(sb.states).aux.phase;\n                   var effect := PathToEffect(path);\n                   if effect.CHLStepEffectReturn? || effect.CHLStepEffectReturnThenCall? then\n                     phase.StraightlinePhaseEnsured?\n                   else\n                     phase.StraightlinePhaseYielded?\n          requires tid != other_tid\n          requires other_tid in last(sb.states).state.s.threads\n          ensures  YieldPredicate(last(sb.states).state, s', other_tid)\n        {\n          var proc := PathToProc(path);\n          var phase := last(sb.states).aux.phase;\n          var sbd;\n          if phase.StraightlinePhaseEnsured? {\n            sbd := lemma_GetFullDescriptorForStraightlineBehaviorEndingEnsured(sb, tid, proc);\n            match sbd {\n      \";\n      str += String.Concat(sbdsEndingEnsured.Select(sbd => $@\"\n              case SBD_{sbd.Name} =>\n                lemma_StraightlineBehaviorSatisfiesYieldPredicate_{sbd.Name}(sb, path, tid, s', other_tid);\n      \"));\n      str += @\"\n            }\n          }\n          else {\n            sbd := lemma_GetFullDescriptorForStraightlineBehaviorEndingYielded(sb, tid, proc);\n            match sbd {\n      \";\n      str += String.Concat(sbdsEndingYielded.Select(sbd => $@\"\n              case SBD_{sbd.Name} =>\n                lemma_StraightlineBehaviorSatisfiesYieldPredicate_{sbd.Name}(sb, path, tid, s', other_tid);\n      \"));\n      str += @\"\n            }\n          }\n        }\n      \";\n      pgp.AddLemma(str, \"YieldAlways\");\n\n      str = @\"\n        lemma lemma_StraightlineBehaviorsSatisfyYieldPredicate()\n          ensures StraightlineBehaviorsSatisfyYieldPredicate(GetConcurrentHoareLogicRequest())\n        {\n          var cr := GetConcurrentHoareLogicRequest();\n          forall sb, step, s', other_actor {:trigger StraightlineBehaviorsSatisfyYieldPredicateConditions(cr, sb, step, s', other_actor)}\n            | StraightlineBehaviorsSatisfyYieldPredicateConditions(cr, sb, step, s', other_actor)\n            ensures cr.yield_pred(last(sb.states).state, s', other_actor)\n          {\n            lemma_StraightlineBehaviorSatisfiesYieldPredicate(sb, step.path, step.tid, s', other_actor);\n          }\n        }\n      \";\n      pgp.AddLemma(str, \"YieldAlways\");\n    }\n\n    private void GenerateStraightlineBehaviorProofs()\n    {\n      GenerateStraightlineBehaviorsSatisfyGlobalInvariantProof();\n      GenerateStraightlineBehaviorsSatisfyLocalInvariantProof();\n      GenerateStraightlineBehaviorsSatisfyPreconditionsForCallsProof();\n      GenerateStraightlineBehaviorsSatisfyPreconditionsForForksProof();\n      GenerateStraightlineBehaviorsSatisfyPostconditionsProof();\n      GenerateStraightlineBehaviorsSatisfyLoopModifiesClausesOnEntryProof();\n      GenerateStraightlineBehaviorsSatisfyLoopModifiesClausesOnJumpBackProof();\n      GenerateStraightlineBehaviorsSatisfyYieldPredicatesProof();\n    }\n\n    private void GenerateLInitImpliesHInitLemma()\n    {\n      GenerateLemmasHelpfulForProvingInitPreservation_LH();\n\n      var str = @\"\n        lemma lemma_LInitImpliesHInit()\n          ensures LInitImpliesHInit(GetAtomicConcurrentHoareLogicRequest())\n        {\n          var ar := GetAtomicConcurrentHoareLogicRequest();\n          forall ls | ar.l.init(ls)\n            ensures ar.h.init(ar.lstate_to_hstate(ls))\n          {\n            var hs := ConvertTotalState_LPlusH(ls);\n            var hconfig := ConvertConfig_LH(ls.config);\n\n            lemma_ConvertTotalStatePreservesInit(ls.s, hs, ls.config, hconfig);\n            assert H.Armada_InitConfig(hs, hconfig);\n          }\n        }\n      \";\n      pgp.AddLemma(str);\n    }\n\n    private void GenerateLNextPlusLocalInvariantImpliesHNextLemmaForNormalPath(AtomicPath atomicPath)\n    {\n      var hAtomicPath = pathMap[atomicPath];\n      var lpr = new PrefixedVarsPathPrinter(lAtomic);\n      var hpr = new PrefixedVarsPathPrinter(hAtomic);\n\n      string str = $@\"\n        lemma lemma_LNextPlusLocalInvariantImpliesHNext_{atomicPath.Name}(\n          ls: LPlusState,\n          ls': LPlusState,\n          lpath: LAtomic_Path,\n          tid: Armada_ThreadHandle\n          )\n          requires LAtomic_NextPath(ls, ls', lpath, tid)\n          requires lpath.LAtomic_Path_{atomicPath.Name}?\n          requires InductiveInv(ls)\n          requires LocalInv(ls, tid)\n          requires GlobalInv(ls)\n          ensures  HAtomic_NextPath(ConvertTotalState_LPlusH(ls), ConvertTotalState_LPlusH(ls'), ConvertAtomicPath_LH(lpath), tid)\n        {{\n          { lpr.GetOpenValidPathInvocation(atomicPath) }\n\n          var hs := ConvertTotalState_LPlusH(ls);\n          var hs' := ConvertTotalState_LPlusH(ls');\n          var hpath := ConvertAtomicPath_LH(lpath);\n\n          { hpr.GetOpenPathInvocation(hAtomicPath) }\n\n          lemma_GetThreadLocalViewAlwaysCommutesWithConvert();\n          lemma_StoreBufferAppendAlwaysCommutesWithConvert();\n          ProofCustomizationGoesHere();\n      \";\n      for (var i = 0; i < atomicPath.NumNextRoutines; ++i) {\n        var nextRoutine = atomicPath.NextRoutines[i];\n        var pos = i+1;\n        str += $\"var hs{pos} := ConvertTotalState_LPlusH(lstates.s{pos});\\n\";\n        if (nextRoutine.Stopping) {\n          str += $@\"\n            assert !hs{pos}.stop_reason.Armada_NotStopped?;\n            assert !hstates.s{pos}.stop_reason.Armada_NotStopped?;\n          \";\n        }\n        else {\n          str += $@\"\n            assert hs{pos}.stop_reason.Armada_NotStopped?;\n            assert hstates.s{pos}.stop_reason.Armada_NotStopped?;\n          \";\n          if (nextRoutine.nextType == NextType.TerminateThread) {\n            str += $@\"\n              assert tid !in hs{pos}.threads;\n              assert tid !in hstates.s{pos}.threads;\n            \";\n          }\n          else {\n            str += $@\"\n              assert hs{pos}.threads[tid] == hstates.s{pos}.threads[tid];\n            \";\n          }\n\n          str += $@\"\n            assert hs{pos}.threads == hstates.s{pos}.threads;\n            assert hs{pos}.mem == hstates.s{pos}.mem;\n            assert hs{pos} == hstates.s{pos};\n          \";\n        }\n      }\n      str += $@\"\n        }}\n      \";\n      pgp.AddLemma(str, \"lift\");\n    }\n\n    private void GenerateLNextPlusLocalInvariantImpliesHNextLemmaForTauPath(AtomicPath atomicPath)\n    {\n      GenerateLiftAtomicPathLemmaForTauPath(atomicPath);\n\n      // This is just like lemma_LiftAtomicPath_Tau in AbstractProofGenerator, except it also gets\n      // to assume GlobalInv(ls) in the preconditions.  (It also has a slightly different calling\n      // convention:  it receives ls' as well.)\n\n      var lpr = new PrefixedVarsPathPrinter(lAtomic);\n      var hpr = new PrefixedVarsPathPrinter(hAtomic);\n      var hAtomicPath = pathMap[atomicPath];\n\n      string str = $@\"\n        lemma lemma_LNextPlusLocalInvariantImpliesHNext_Tau(\n          ls: LPlusState,\n          ls': LPlusState,\n          lpath: LAtomic_Path,\n          tid: Armada_ThreadHandle\n          )\n          requires LAtomic_NextPath(ls, ls', lpath, tid)\n          requires lpath.LAtomic_Path_Tau?\n          requires InductiveInv(ls)\n          requires GlobalInv(ls)\n          ensures  HAtomic_NextPath(ConvertTotalState_LPlusH(ls), ConvertTotalState_LPlusH(ls'), ConvertAtomicPath_LH(lpath), tid)\n        {{\n          { lpr.GetOpenValidPathInvocation(atomicPath) }\n\n          var hs := ConvertTotalState_LPlusH(ls);\n          var hpath := ConvertAtomicPath_LH(lpath);\n          var hs' := ConvertTotalState_LPlusH(ls');\n\n          { hpr.GetOpenPathInvocation(hAtomicPath) }\n\n          var lentry := ls.s.threads[tid].storeBuffer[0];\n          var hentry := hs.threads[tid].storeBuffer[0];\n          var lmem := ls.s.mem;\n          var hmem1 := ConvertSharedMemory_LH(L.Armada_ApplyStoreBufferEntry(lmem, lentry));\n          var hmem2 := H.Armada_ApplyStoreBufferEntry(ConvertSharedMemory_LH(lmem), hentry);\n          lemma_ApplyStoreBufferEntryCommutesWithConvert(lmem, lentry, hentry, hmem1, hmem2);\n\n          var alt_hs' := HAtomic_GetStateAfterPath(hs, hpath, tid);\n          ProofCustomizationGoesHere();\n          assert hs'.threads[tid] == alt_hs'.threads[tid];\n          assert hs'.threads == alt_hs'.threads;\n          assert hs' == alt_hs';\n\n          /* { hpr.GetAssertValidPathInvocation(hAtomicPath) } */\n        }}\n      \";\n      pgp.AddLemma(str, \"lift\");\n    }\n\n    private void GenerateLNextPlusLocalInvariantImpliesHNextLemma()\n    {\n      var finalCases = \"\";\n      foreach (var atomicPath in lAtomic.AtomicPaths) {\n        if (atomicPath.Tau) {\n          GenerateLNextPlusLocalInvariantImpliesHNextLemmaForTauPath(atomicPath);\n        }\n        else {\n          GenerateLNextPlusLocalInvariantImpliesHNextLemmaForNormalPath(atomicPath);\n        }\n\n        finalCases += $@\"\n          case LAtomic_Path_{atomicPath.Name}(_) =>\n            lemma_LNextPlusLocalInvariantImpliesHNext_{atomicPath.Name}(ls, ls', lpath, tid);\n        \";\n      }\n\n      string str = $@\"\n        lemma lemma_LNextPlusLocalInvariantImpliesHNext(\n          ls: LPlusState,\n          ls': LPlusState,\n          lpath: LAtomic_Path,\n          tid: Armada_ThreadHandle\n          )\n          requires LAtomic_NextPath(ls, ls', lpath, tid)\n          requires InductiveInv(ls)\n          requires !lpath.LAtomic_Path_Tau? ==> LocalInv(ls, tid)\n          requires GlobalInv(ls)\n          ensures  HAtomic_NextPath(ConvertTotalState_LPlusH(ls), ConvertTotalState_LPlusH(ls'), ConvertAtomicPath_LH(lpath), tid)\n        {{\n          match lpath {{\n            { finalCases }\n          }}\n        }}\n      \";\n      pgp.AddLemma(str, \"lift\");\n    }\n\n    private void GenerateIsValidAtomicConcurrentHoareLogicRequestLemmas()\n    {\n      string str;\n\n      GenerateIsValidConcurrentHoareLogicRequest();\n\n      str = @\"\n        lemma lemma_LPathImpliesHPath()\n          ensures LPathImpliesHPath(GetAtomicConcurrentHoareLogicRequest())\n        {\n          var ar := GetAtomicConcurrentHoareLogicRequest();\n          forall ls, lpath, tid | LPathImpliesHPathConditions(ar, ls, lpath, tid)\n            ensures var ls' := ar.l.path_next(ls, lpath, tid);\n                    var hs := ar.lstate_to_hstate(ls);\n                    var hpath := ar.lpath_to_hpath(lpath);\n                    var hs' := ar.lstate_to_hstate(ls');\n                    && ar.h.path_valid(hs, hpath, tid)\n                    && hs' == ar.h.path_next(hs, hpath, tid)\n          {\n            var ls' := ar.l.path_next(ls, lpath, tid);\n            lemma_LNextPlusLocalInvariantImpliesHNext(ls, ls', lpath, tid);\n          }\n        }\n      \";\n      pgp.AddLemma(str);\n\n      str = @\"\n        lemma lemma_EmbeddedRequestCorresponds()\n          ensures EmbeddedRequestCorresponds(GetAtomicConcurrentHoareLogicRequest())\n        {\n        }\n      \";\n      pgp.AddLemma(str);\n\n      str = $@\"\n        lemma lemma_AtomicInitImpliesOK()\n          ensures AtomicInitImpliesOK(LAtomic_GetSpecFunctions())\n        {{\n        }}\n      \";\n      pgp.AddLemma(str);\n\n      str = @\"\n        lemma lemma_AtomicPathRequiresOK()\n          ensures AtomicPathRequiresOK(LAtomic_GetSpecFunctions())\n        {\n          var asf := LAtomic_GetSpecFunctions();\n          forall s, path, tid | asf.path_valid(s, path, tid)\n            ensures asf.state_ok(s)\n          {\n            lemma_PathImpliesThreadRunning(s, path, tid);\n          }\n        }\n      \";\n      pgp.AddLemma(str);\n\n      str = @\"\n        lemma lemma_AtomicSteppingThreadHasPC()\n          ensures AtomicSteppingThreadHasPC(LAtomic_GetSpecFunctions())\n        {\n          var asf := LAtomic_GetSpecFunctions();\n          forall s, path, tid | asf.path_valid(s, path, tid)\n            ensures asf.get_thread_pc(s, tid).Some?\n          {\n            lemma_PathImpliesThreadRunning(s, path, tid);\n          }\n        }\n      \";\n      pgp.AddLemma(str);\n\n      lAtomic.GenerateAtomicTauLeavesPCUnchangedLemma();\n\n      str = @\"\n        lemma lemma_LStateToHStateMapsPCsCorrectly()\n          ensures LStateToHStateMapsPCsCorrectly(GetAtomicConcurrentHoareLogicRequest())\n        {\n        }\n      \";\n      pgp.AddLemma(str);\n\n      lAtomic.GenerateAtomicPathCantAffectOtherThreadPCsExceptViaForkLemma();\n\n      str = @\"\n        lemma lemma_LHPathPropertiesMatch()\n          ensures LHPathPropertiesMatch(GetAtomicConcurrentHoareLogicRequest())\n        {\n        }\n      \";\n      pgp.AddLemma(str);\n\n      str = @\"\n        lemma lemma_StateConversionPreservesOK()\n          ensures StateConversionPreservesOK(GetAtomicConcurrentHoareLogicRequest())\n        {\n        }\n      \";\n      pgp.AddLemma(str);\n\n      str = @\"\n        lemma lemma_StateConversionSatisfiesRelation()\n          ensures StateConversionSatisfiesRelation(GetAtomicConcurrentHoareLogicRequest())\n        {\n        }\n      \";\n      pgp.AddLemma(str);\n\n      str = @\"\n        lemma lemma_IsValidAtomicConcurrentHoareLogicRequest()\n          ensures IsValidAtomicConcurrentHoareLogicRequest(GetAtomicConcurrentHoareLogicRequest())\n        {\n          lemma_IsValidConcurrentHoareLogicRequest();\n          lemma_LPathImpliesHPath();\n          lemma_EmbeddedRequestCorresponds();\n          lemma_AtomicInitImpliesOK();\n          lemma_AtomicPathRequiresOK();\n          lemma_AtomicSteppingThreadHasPC();\n          lemma_LAtomic_AtomicTauLeavesPCUnchanged();\n          lemma_LAtomic_AtomicThreadCantAffectOtherThreadPCExceptViaFork();\n          lemma_LStateToHStateMapsPCsCorrectly();\n          lemma_LInitImpliesHInit();\n          lemma_LHPathPropertiesMatch();\n          lemma_StateConversionPreservesOK();\n          lemma_StateConversionSatisfiesRelation();\n        }\n      \";\n      pgp.AddLemma(str);\n    }\n\n    private void GenerateLemmasForAssumeIntroProof()\n    {\n      GenerateLInitImpliesHInitLemma();\n      GenerateLNextPlusLocalInvariantImpliesHNextLemma();\n      GenerateIsValidAtomicConcurrentHoareLogicRequestLemmas();\n\n      var str = @\"\n        lemma lemma_LiftLAtomicToHAtomic() returns (refinement_relation:RefinementRelation<LPlusState, H.Armada_TotalState>)\n          ensures SpecRefinesSpec(AtomicSpec(LAtomic_GetSpecFunctions()), AtomicSpec(HAtomic_GetSpecFunctions()), refinement_relation)\n          ensures refinement_relation == GetLPlusHRefinementRelation()\n        {\n          var ar := GetAtomicConcurrentHoareLogicRequest();\n          lemma_IsValidAtomicConcurrentHoareLogicRequest();\n          lemma_LiftAtomicToAtomicUsingCHLRequest(ar);\n          refinement_relation := GetLPlusHRefinementRelation();\n        }\n      \";\n      pgp.AddLemma(str);\n    }\n  }\n}\n"
  },
  {
    "path": "Source/Armada/AtomicSpec.cs",
    "content": "using System;\nusing System.Numerics;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text;\nusing System.Text.RegularExpressions;\nusing Token = Microsoft.Boogie.Token;\n\nnamespace Microsoft.Armada\n{\n  ///////////////////////////////////////////////////////////////////////\n  // PC TYPE\n  ///////////////////////////////////////////////////////////////////////\n\n  public enum PCAtomicType { Yielding, Recurrent, Nonyielding, Stopping };\n\n  public class PCAtomicTypePair : Tuple<PCAtomicType, PCAtomicType>\n  {\n    public PCAtomicTypePair(PCAtomicType i_Item1, PCAtomicType i_Item2) : base(i_Item1, i_Item2)\n    {\n    }\n\n    public override string ToString()\n    {\n      return Item1.ToString().Substring(0, 1) + Item2.ToString().Substring(0, 1);\n    }\n  }\n\n  ///////////////////////////////////////////////////////////////////////\n  // ATOMIC PATH PREFIX\n  ///////////////////////////////////////////////////////////////////////\n\n  public class AtomicPathPrefix\n  {\n    private AtomicSpec atomicSpec;\n    private List<NextRoutine> nextRoutines;\n    private bool tau;\n    private ArmadaPC startPC;\n    private ArmadaPC endPC;\n    private PCAtomicType startType;\n    private PCAtomicType endType;\n    private string name;\n    private List<AtomicPathPrefix> extensions;\n    private AtomicPath path;\n\n    public AtomicPathPrefix(AtomicSpec i_atomicSpec, List<NextRoutine> i_nextRoutines, bool i_tau, AtomicPathPrefix parent)\n    {\n      atomicSpec = i_atomicSpec;\n      nextRoutines = new List<NextRoutine>(i_nextRoutines);\n      tau = i_tau;\n      startPC = nextRoutines[0].startPC;\n      endPC = nextRoutines[nextRoutines.Count - 1].endPC;\n      startType = atomicSpec.GetPCAtomicType(startPC);\n      endType = nextRoutines[nextRoutines.Count - 1].Stopping ? PCAtomicType.Stopping : atomicSpec.GetPCAtomicType(endPC);\n      extensions = new List<AtomicPathPrefix>();\n      path = null;\n\n      if (parent != null) {\n        parent.AddExtension(this);\n      }\n\n      if (tau) {\n        name = \"Tau\";\n      }\n      else {\n        name = UndefinedBehavior ? \"UB_\" : \"\";\n        name += $\"From_{startPC.methodName}_{startPC.Name}\";\n\n        // It's possible for two atomic paths to have the same start\n        // and end PCs.  But, every path has to have a distinct name,\n        // so we sometimes have to name a path with more than just the\n        // start and end PCs.\n        //\n        // One way for two atomic paths with the same start and end\n        // PCs to differ is via returning to different PCs.  For\n        // instance, consider the following code:\n        //\n        //   method {:atomic} A {\n        //     S1;\n        //   label L:\n        //     S2;\n        //   }\n        //   \n        //   method B {\n        //     atomic {\n        //       A();\n        //       A();\n        //       A();\n        //     }\n        //   }\n        //\n        // Here, there are two ways to get from label L to label L:\n        // (1) by returning from B's first call to A and then making\n        // B's second call to A, and (2) by returning from B's second\n        // call to A and then making B's third call to A.  So, to make\n        // sure such paths have different names, we include in the\n        // name every returned-to PC in a step other than the last one\n        // in the path.\n        //\n        // Another way for two atomic paths with the same start and\n        // end PCs to differ is via branch outcomes.  For instance,\n        // consider the following code:\n        //\n        //   atomic {\n        //     if P {\n        //       S1;\n        //     }\n        //     S2;\n        //   }\n        //\n        // Here, there are two ways to get from the beginning to the\n        // end: via the true branch of the if (passing through\n        // statement S1) or via the false branch.  So we distinguish\n        // the names of such paths by the branch outcomes.\n\n        bool justBranched = false;\n        for (var i = 0; i < nextRoutines.Count; ++i)\n        {\n          var nextRoutine = nextRoutines[i];\n          if (i < nextRoutines.Count - 1 && nextRoutine.nextType == NextType.Return) {\n            var returnToPC = nextRoutine.endPC;\n            name += $\"_Via_{returnToPC.methodName}_{returnToPC.Name}\";\n            justBranched = false;\n          }\n\n          bool branchOutcome;\n          if (nextRoutine.TryGetBranchOutcome(out branchOutcome)) {\n            if (!justBranched) {\n              name += \"_\";\n            }\n            name += (branchOutcome ? \"T\" : \"F\");\n            justBranched = true;\n          }\n        }\n\n        if (endPC == null)\n        {\n          name += \"_to_exit\";\n        }\n        else\n        {\n          name += $\"_To_{endPC.methodName}_{endPC.Name}\";\n        }\n      }\n    }\n\n    public AtomicPathPrefix(AtomicSpec i_atomicSpec, ArmadaPC pc)\n    {\n      atomicSpec = i_atomicSpec;\n      nextRoutines = new List<NextRoutine>();\n      tau = false;\n      startPC = endPC = pc;\n      startType = endType = atomicSpec.GetPCAtomicType(pc);\n      extensions = new List<AtomicPathPrefix>();\n      path = null;\n    }\n\n    public bool Tau { get { return tau; } }\n    public ArmadaPC StartPC { get { return startPC; } }\n    public ArmadaPC EndPC { get { return endPC; } }\n    public PCAtomicType StartType { get { return startType; } }\n    public PCAtomicType EndType { get { return endType; } }\n    public List<NextRoutine> NextRoutines { get { return nextRoutines; } }\n    public NextRoutine LastNextRoutine { get { return nextRoutines[nextRoutines.Count - 1]; } }\n    public int NumNextRoutines { get { return nextRoutines.Count; } }\n    public string Name { get { return name; } }\n    public AtomicSpec Spec { get { return atomicSpec; } }\n\n    public void AddExtension(AtomicPathPrefix other) { extensions.Add(other); }\n    public List<AtomicPathPrefix> Extensions { get { return extensions; } }\n    public AtomicPath PathVal { get { return path; } set { path = value; } }\n\n    public bool UndefinedBehavior { get { return (nextRoutines.Count == 0) ? false : LastNextRoutine.UndefinedBehavior; } }\n    public bool Stopping { get { return (nextRoutines.Count == 0) ? false : LastNextRoutine.Stopping; } }\n\n    public List<ArmadaPC> GetPCs()\n    {\n      var pcs = new List<ArmadaPC>{ startPC };\n      pcs.AddRange(nextRoutines.Select(p => p.endPC));\n      return pcs;\n    }\n\n    public List<NextRoutine> MapNextRoutines(Dictionary<NextRoutine, NextRoutine> nextRoutineMap)\n    {\n      return nextRoutines.Where(n => nextRoutineMap.ContainsKey(n)).Select(n => nextRoutineMap[n]).ToList();\n    }\n\n    public List<ArmadaPC> GetMappedPCs(Dictionary<ArmadaPC, ArmadaPC> pcMap)\n    {\n      return GetPCs().Where(pc => pcMap.ContainsKey(pc)).Select(pc => pcMap[pc]).ToList();\n    }\n  }\n\n  ///////////////////////////////////////////////////////////////////////\n  // ATOMIC PATH\n  ///////////////////////////////////////////////////////////////////////\n\n  public class AtomicPath\n  {\n    private AtomicPathPrefix pathPrefix;\n    private bool stopping;\n    private string name;\n\n    public AtomicPath(AtomicPathPrefix i_pathPrefix)\n    {\n      pathPrefix = i_pathPrefix;\n      stopping = i_pathPrefix.Stopping;\n      name = pathPrefix.Name;\n    }\n\n    public bool Tau { get { return pathPrefix.Tau; } }\n    public string Name { get { return name;  } }\n    public ArmadaPC StartPC { get { return pathPrefix.StartPC; } }\n    public ArmadaPC EndPC { get { return pathPrefix.EndPC; } }\n    public PCAtomicType StartType { get { return pathPrefix.StartType; } }\n    public PCAtomicType EndType { get { return pathPrefix.EndType; } }\n    public bool Stopping { get { return stopping; } }\n\n    public string PathType {\n      get {\n        if (Tau) { return \"Tau\"; }\n        string s1 = StartType.ToString().Substring(0, 1);\n        string s2 = stopping ? \"S\" : EndType.ToString().Substring(0, 1);\n        return s1 + s2;\n      }\n    }\n    public List<NextRoutine> NextRoutines { get { return pathPrefix.NextRoutines; } }\n    public NextRoutine LastNextRoutine { get { return pathPrefix.LastNextRoutine; } }\n    public int NumNextRoutines { get { return pathPrefix.NumNextRoutines; } }\n\n    public IEnumerable<Tuple<NextRoutine, int>> NextRoutinesWithIndices\n    {\n      get\n      {\n        var i = 0;\n        while (i < pathPrefix.NumNextRoutines) {\n          yield return new Tuple<NextRoutine, int>(pathPrefix.NextRoutines[i], i);\n          ++i;\n        }\n      }\n    }\n\n    public IEnumerable<Tuple<NextRoutine, int>> NextRoutinesWithFormalsWithIndices\n    {\n      get\n      {\n        var i = 0;\n        while (i < pathPrefix.NumNextRoutines) {\n          var nextRoutine = pathPrefix.NextRoutines[i];\n          if (nextRoutine.HasFormals) {\n            yield return new Tuple<NextRoutine, int>(pathPrefix.NextRoutines[i], i);\n          }\n          ++i;\n        }\n      }\n    }\n\n    public string OptionalNotForOK { get { return stopping ? \"!\" : \"\"; } }\n\n    public List<ArmadaPC> GetPCs() { return pathPrefix.GetPCs(); }\n\n    public bool Mappable(Dictionary<NextRoutine, NextRoutine> nextRoutineMap, bool i_stopping, bool avoidFinalUnmappedStoppingStep)\n    {\n      if (Tau) {\n        return true;\n      }\n      if (stopping != i_stopping) {\n        return false;\n      }\n      if (!NextRoutines.Where(n => nextRoutineMap.ContainsKey(n)).Any()) {\n        return false;\n      }\n      if (avoidFinalUnmappedStoppingStep && stopping && !nextRoutineMap.ContainsKey(LastNextRoutine)) {\n        return false;\n      }\n      return true;\n    }\n\n    public List<NextRoutine> MapNextRoutines(Dictionary<NextRoutine, NextRoutine> nextRoutineMap)\n    {\n      return pathPrefix.MapNextRoutines(nextRoutineMap);\n    }\n\n    public List<ArmadaPC> GetMappedPCs(Dictionary<ArmadaPC, ArmadaPC> pcMap)\n    {\n      return pathPrefix.GetMappedPCs(pcMap);\n    }\n\n    public IEnumerable<bool> BranchOutcomes\n    {\n      get\n      {\n        foreach (var nextRoutine in NextRoutines)\n        {\n          bool outcome;\n          if (nextRoutine.TryGetBranchOutcome(out outcome))\n          {\n            yield return outcome;\n          }\n        }\n      }\n    }\n  }\n\n  ///////////////////////////////////////////////////////////////////////\n  // ATOMIC SPEC\n  ///////////////////////////////////////////////////////////////////////\n\n  public class AtomicSpec\n  {\n    private ProofGenerationParams pgp;\n    private ArmadaSymbolTable symbols;\n    private string auxName;\n    private string prefix;\n    private bool low;\n    private string moduleName;\n    private string typeState;\n    private string specFunctions;\n    private string spec;\n    private string validStep;\n    private string getNextState;\n    private List<ArmadaPC> allPCs;\n    private Dictionary<ArmadaPC, List<NextRoutine>> pcToNextRoutines;\n    private HashSet<ArmadaPC> nonyieldingPCs;\n    private HashSet<ArmadaPC> recurrentPCs;\n    private List<AtomicPath> atomicPaths;\n    private AtomicPath tauPath;\n    private Dictionary<ArmadaPC, List<AtomicPathPrefix>> rootPathPrefixesByPC;\n\n    public AtomicSpec(ProofGenerationParams i_pgp, ArmadaSymbolTable i_symbols, string i_auxName, string i_prefix, bool i_low,\n                      string i_moduleName, string i_typeState, string i_specFunctions, string i_spec,\n                      string i_validStep, string i_getNextState)\n    {\n      pgp = i_pgp;\n      symbols = i_symbols;\n      auxName = i_auxName;\n      prefix = i_prefix;\n      low = i_low;\n      moduleName = i_moduleName;\n      typeState = i_typeState;\n      specFunctions = i_specFunctions;\n      spec = i_spec;\n      validStep = i_validStep;\n      getNextState = i_getNextState;\n    }\n\n    public AtomicPath TauPath { get { return tauPath; } }\n    public string Prefix { get { return prefix; } }\n    public string TypeState { get { return typeState; } }\n    public List<AtomicPath> AtomicPaths { get { return atomicPaths; } }\n    public string ModuleName { get { return moduleName; } }\n    public IEnumerable<ArmadaPC> AllPCs { get { return allPCs; } }\n    public IEnumerable<AtomicPathPrefix> RootPathPrefixesByPC(ArmadaPC pc) { return rootPathPrefixesByPC[pc]; }\n    public HashSet<ArmadaPC> RecurrentPCs { get { return recurrentPCs; } }\n    public bool Low { get { return low; } }\n\n    public void MakeSpec(HashSet<ArmadaPC> extraRecurrentPCs = null)\n    {\n      AddIncludesAndImports();\n      DetermineNonyieldingPCs();\n      DeterminePCToNextRoutinesMap();\n      DetermineRecurrentPCs(extraRecurrentPCs);\n      DetermineAtomicPaths();\n      CreateAtomicSpec();\n    }\n\n    private void AddIncludesAndImports()\n    {\n      pgp.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/option.s.dfy\", auxName);\n      pgp.AddImport(\"util_option_s\", null, auxName);\n      pgp.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/seqs.s.dfy\", auxName);\n      pgp.AddImport(\"util_collections_seqs_s\", null, auxName);\n      pgp.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/strategies/generic/GenericArmadaLemmas.i.dfy\", auxName);\n      pgp.AddImport(\"GenericArmadaLemmasModule\", null, auxName);\n      pgp.AddImport(\"GenericArmadaSpecModule\", null, auxName);\n      pgp.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/strategies/generic/GenericArmadaAtomic.i.dfy\", auxName);\n      pgp.AddImport(\"GenericArmadaAtomicModule\", null, auxName);\n    }\n\n    public string GetConstructorString(AtomicPath atomicPath)\n    {\n      if (atomicPath.NextRoutines.Where(r => r.HasFormals).Any()) {\n        // TODO: this does not work with introduced statements with *\n        AH.PrintError(pgp.prog, \"Armada currently doesn't support introducing a non-deterministic statement.\");\n      }\n\n      var str = $\"{prefix}_Path_{atomicPath.Name}({prefix}_PathSteps_{atomicPath.Name}(\";\n      str += String.Join(\", \", atomicPath.NextRoutines.Select(r => $\"{moduleName}.Armada_Step_{r.NameSuffix}()\"));\n      str += \"))\";\n      return str;\n    }\n\n    ///////////////////////////////////////////////////////////////////////\n    // COLLECTING INFO\n    ///////////////////////////////////////////////////////////////////////\n\n    private void DetermineNonyieldingPCs()\n    {\n      var pcs = new List<ArmadaPC>();\n      symbols.AllMethods.AppendAllNonyieldingPCs(pcs);\n      nonyieldingPCs = new HashSet<ArmadaPC>(pcs);\n    }\n\n    private void DeterminePCToNextRoutinesMap()\n    {\n      pcToNextRoutines = new Dictionary<ArmadaPC, List<NextRoutine>>();\n      foreach (var nextRoutine in symbols.NextRoutines) {\n        var pc = nextRoutine.startPC;\n        if (pc == null) {\n          continue;\n        }\n        if (!pcToNextRoutines.ContainsKey(pc)) {\n          pcToNextRoutines[pc] = new List<NextRoutine>();\n        }\n        pcToNextRoutines[pc].Add(nextRoutine);\n      }\n    }\n\n    ///////////////////////////////////////////////////////////////////////\n    // FINDING RECURRENT PCS\n    ///////////////////////////////////////////////////////////////////////\n\n    /// <summary>\n    /// In CheckForFiniteNonyieldingPathBetween, we only care about\n    /// paths that reach end before visiting any other node twice\n    /// (since if it visits another node twice, it's potentially\n    /// infinite).  So, we keep track of nodes we've already visited\n    /// and don't visit them again.\n    /// </summary>\n\n    private bool CheckForFiniteNonyieldingPathBetween(ArmadaPC start, ArmadaPC end, HashSet<ArmadaPC> alreadyVisited)\n    {\n      if (start == null || end == null) {\n        return false;\n      }\n      if (!nonyieldingPCs.Contains(start)) {\n        return false;\n      }\n      List<NextRoutine> nextRoutines;\n      if (!pcToNextRoutines.TryGetValue(start, out nextRoutines)) {\n        return false;\n      }\n      foreach (var nextRoutine in nextRoutines) {\n        var nextPC = nextRoutine.endPC;\n        if (nextPC.Equals(end)) {\n          return true;\n        }\n        if (alreadyVisited.Contains(nextPC)) {\n          continue;\n        }\n        alreadyVisited.Add(nextPC);\n        if (CheckForFiniteNonyieldingPathBetween(nextPC, end, alreadyVisited)) {\n          return true;\n        }\n        alreadyVisited.Remove(nextPC);\n      }\n      return false;\n    }\n\n    private bool DoesNonyieldingPathBetweenPCsExist(ArmadaPC start, ArmadaPC end)\n    {\n      var alreadyVisited = new HashSet<ArmadaPC>();\n      return CheckForFiniteNonyieldingPathBetween(start, end, alreadyVisited);\n    }\n\n    private void DetermineRecurrentPCs(HashSet<ArmadaPC> extraRecurrentPCs)\n    {\n      if (extraRecurrentPCs != null) {\n        recurrentPCs = new HashSet<ArmadaPC>(extraRecurrentPCs);\n      }\n      else {\n        recurrentPCs = new HashSet<ArmadaPC>();\n      }\n\n      foreach (var pc in symbols.EnumeratePotentialRecurrentPCs())\n      {\n        if (!recurrentPCs.Contains(pc) && DoesNonyieldingPathBetweenPCsExist(pc, pc)) {\n          recurrentPCs.Add(pc);\n        }\n      }\n    }\n\n    ///////////////////////////////////////////////////////////////////////\n    // PC TYPES\n    ///////////////////////////////////////////////////////////////////////\n\n    public PCAtomicType GetPCAtomicType(ArmadaPC pc)\n    {\n      if (pc == null) {\n        return PCAtomicType.Yielding;\n      }\n      if (recurrentPCs.Contains(pc)) {\n        return PCAtomicType.Recurrent;\n      }\n      if (nonyieldingPCs.Contains(pc)) {\n        return PCAtomicType.Nonyielding;\n      }\n      else {\n        return PCAtomicType.Yielding;\n      }\n    }\n\n    ///////////////////////////////////////////////////////////////////////\n    // MAKING ATOMIC STEPS\n    ///////////////////////////////////////////////////////////////////////\n\n    private void DetermineAtomicPaths()\n    {\n      allPCs = new List<ArmadaPC>();\n      symbols.AllMethods.AppendAllPCs(allPCs);\n\n      var tauPathPrefix = new AtomicPathPrefix(this, new List<NextRoutine> { symbols.TauNextRoutine }, true, null);\n      tauPath = new AtomicPath(tauPathPrefix);\n      atomicPaths = new List<AtomicPath>{ tauPath };\n      rootPathPrefixesByPC = new Dictionary<ArmadaPC, List<AtomicPathPrefix>>();\n\n      foreach (var startPC in allPCs)\n      {\n        rootPathPrefixesByPC[startPC] = new List<AtomicPathPrefix>();\n        if (GetPCAtomicType(startPC) != PCAtomicType.Nonyielding) {\n          List<NextRoutine> nextRoutines;\n          if (pcToNextRoutines.TryGetValue(startPC, out nextRoutines)) {\n            foreach (var nextRoutine in nextRoutines)\n            {\n              var rootAtomicPathPrefix = new AtomicPathPrefix(this, new List<NextRoutine>{ nextRoutine }, false, null);\n              rootPathPrefixesByPC[startPC].Add(rootAtomicPathPrefix);\n              PopulateAtomicPathPrefix(rootAtomicPathPrefix);\n            }\n          }\n        }\n      }\n    }\n\n    private void PopulateAtomicPathPrefix(AtomicPathPrefix pathPrefix)\n    {\n      var currentPC = pathPrefix.EndPC;\n      if (pathPrefix.Stopping || currentPC == null || GetPCAtomicType(currentPC) != PCAtomicType.Nonyielding) {\n        pathPrefix.PathVal = new AtomicPath(pathPrefix);\n        atomicPaths.Add(pathPrefix.PathVal);\n        return;\n      }\n\n      List<NextRoutine> subsequentRoutines;\n      if (pcToNextRoutines.TryGetValue(currentPC, out subsequentRoutines)) {\n        foreach (var subsequentRoutine in subsequentRoutines)\n        {\n          var childNextRoutines = new List<NextRoutine>(pathPrefix.NextRoutines);\n          childNextRoutines.Add(subsequentRoutine);\n          var childPathPrefix = new AtomicPathPrefix(this, childNextRoutines, false, pathPrefix);\n          PopulateAtomicPathPrefix(childPathPrefix);\n        }\n      }\n    }\n\n    ///////////////////////////////////////////////////////////////////////\n    // EMITTING DAFNY CODE\n    ///////////////////////////////////////////////////////////////////////\n\n    private void CreateAtomicSpec()\n    {\n      CreateIsRecurrentPC();\n      CreatePathDatatype();\n      CreatePathTypeFunction();\n      CreatePathStatesDatatype();\n      foreach (var atomicPath in atomicPaths)\n      {\n        CreateFunctionsForAtomicPath(atomicPath);\n      }\n      CreateAtomicSpecFunctions();\n      CreateFunctionsForAllAtomicPaths();\n    }\n\n    ///////////////////////////////////////////////////////////////////////\n    // PATH DEFINITIONS AND FUNCTIONS\n    ///////////////////////////////////////////////////////////////////////\n\n    private void CreateIsRecurrentPC()\n    {\n      var body = String.Join(\" || \", recurrentPCs.Select(pc => $\"pc.{pc}?\"));\n      if (body.Length == 0) { body = \"false\"; }\n      string str = $@\"\n        predicate {prefix}_IsRecurrentPC(pc:{moduleName}.Armada_PC)\n        {{\n          {body}\n        }}\n      \";\n      pgp.AddPredicate(str, auxName);\n    }\n\n    private void CreatePathDatatype()\n    {\n      string str;\n\n      foreach (var atomicPath in atomicPaths)\n      {\n        str = $\"datatype {prefix}_PathSteps_{atomicPath.Name} = {prefix}_PathSteps_{atomicPath.Name}(\";\n        str += String.Join(\", \", Enumerable.Range(0, atomicPath.NumNextRoutines).Select(i => $\"step{i}: {moduleName}.Armada_Step\"));\n        str += \")\\n\";\n        pgp.AddDatatype(str, auxName);\n      }\n\n      str = $\"datatype {prefix}_Path = \";\n      str += String.Join(\" | \", atomicPaths.Select(\n        atomicPath => $\"{prefix}_Path_{atomicPath.Name}(steps_{atomicPath.Name}: {prefix}_PathSteps_{atomicPath.Name})\"\n      ));\n      pgp.AddDatatype(str, auxName);\n    }\n\n    private void CreatePathTypeFunction()\n    {\n      var caseBodies = String.Join(\"\\n\", atomicPaths.Select(\n        atomicPath => $\"case {prefix}_Path_{atomicPath.Name}(_) => AtomicPathType_{atomicPath.PathType}\"\n      ));\n      var str = $@\"\n        function {prefix}_GetPathType(path: {prefix}_Path) : AtomicPathType\n        {{\n          match path\n          {caseBodies}\n        }}\n      \";\n      pgp.AddFunction(str, auxName);\n    }\n\n    private void CreatePathStatesDatatype()\n    {\n      string str;\n\n      foreach (var atomicPath in atomicPaths)\n      {\n        str = $\"datatype {prefix}_PathStates_{atomicPath.Name} = {prefix}_PathStates_{atomicPath.Name}(\";\n        str += String.Join(\", \", Enumerable.Range(0, atomicPath.NumNextRoutines + 1).Select(i => $\"s{i}: {typeState}\"));\n        str += \")\";\n        pgp.AddDatatype(str, auxName);\n      }\n    }\n\n    private void CreateFunctionsForAtomicPath(AtomicPath atomicPath)\n    {\n      var nextRoutines = atomicPath.NextRoutines;\n      string str;\n\n      str = $@\"\n        function {prefix}_GetPathStates_{atomicPath.Name}(\n          s0: {typeState},\n          tid: Armada_ThreadHandle,\n          steps: {prefix}_PathSteps_{atomicPath.Name}\n          ) : {prefix}_PathStates_{atomicPath.Name}\n        {{\n      \";\n      str += String.Concat(\n        Enumerable.Range(0, nextRoutines.Count).Select(i => $\"    var s{i + 1} := {getNextState}(s{i}, steps.step{i}, tid);\\n\")\n      );\n      str += $\"    {prefix}_PathStates_{atomicPath.Name}(\";\n      str += String.Join(\", \", Enumerable.Range(0, nextRoutines.Count + 1).Select(i => $\"s{i}\"));\n      str += \") }\";\n      pgp.AddFunction(str, auxName);\n\n      str = $@\"\n        predicate {prefix}_ValidPath_{atomicPath.Name}(\n          s: {typeState},\n          tid: Armada_ThreadHandle,\n          steps: {prefix}_PathSteps_{atomicPath.Name}\n          )\n        {{\n          var states := {prefix}_GetPathStates_{atomicPath.Name}(s, tid, steps);\n      \";\n      str += String.Concat(Enumerable.Range(0, nextRoutines.Count).Select(i => $@\"\n          && steps.step{i}.Armada_Step_{nextRoutines[i].NameSuffix}?\n          && {validStep}(states.s{i}, steps.step{i}, tid)\n      \"));\n      str += \"}\";\n      pgp.AddPredicate(str, auxName);\n    }\n\n    private void CreateFunctionsForAllAtomicPaths()\n    {\n      var str = $@\"\n        predicate {{:opaque}} {prefix}_ValidPath(s: {typeState}, path: {prefix}_Path, tid: Armada_ThreadHandle)\n        {{\n          match path\n      \";\n      str += String.Concat(atomicPaths.Select(atomicPath =>\n          $\"case {prefix}_Path_{atomicPath.Name}(steps) => {prefix}_ValidPath_{atomicPath.Name}(s, tid, steps)\\n\"\n      ));\n      str += \"}\";\n      pgp.AddPredicate(str, auxName);\n\n      str = $@\"\n        function {{:opaque}} {prefix}_GetStateAfterPath(s: {typeState}, atomicPath: {prefix}_Path, tid: Armada_ThreadHandle) : {typeState}\n        {{\n          match atomicPath\n      \";\n      foreach (var atomicPath in atomicPaths) {\n        str += $@\"\n            case {prefix}_Path_{atomicPath.Name}(steps) =>\n              {prefix}_GetPathStates_{atomicPath.Name}(s, tid, steps).s{atomicPath.NumNextRoutines}\n        \";\n      }\n      str += \"}\\n\";\n      pgp.AddFunction(str, auxName);\n\n      str = $@\"\n        predicate {prefix}_NextPath(s: {typeState}, s': {typeState}, atomicPath: {prefix}_Path, tid: Armada_ThreadHandle)\n        {{\n          {prefix}_ValidPath(s, atomicPath, tid) && s' == {prefix}_GetStateAfterPath(s, atomicPath, tid)\n        }}\n      \";\n      pgp.AddPredicate(str, auxName);\n\n      foreach (var atomicPath in atomicPaths)\n      {\n        str = $@\"\n          lemma lemma_{prefix}_OpenPath_{atomicPath.Name}(\n            s: {typeState},\n            path: {prefix}_Path,\n            tid: Armada_ThreadHandle\n            ) returns (\n            steps: {prefix}_PathSteps_{atomicPath.Name},\n            states: {prefix}_PathStates_{atomicPath.Name}\n            )\n            requires path.{prefix}_Path_{atomicPath.Name}?\n            ensures  path == {prefix}_Path_{atomicPath.Name}(steps)\n            ensures  {prefix}_ValidPath(s, path, tid) == {prefix}_ValidPath_{atomicPath.Name}(s, tid, steps)\n            ensures  states == {prefix}_GetPathStates_{atomicPath.Name}(s, tid, steps)\n            ensures  {prefix}_GetStateAfterPath(s, path, tid) == states.s{atomicPath.NumNextRoutines}\n          {{\n            reveal {prefix}_ValidPath();\n            reveal {prefix}_GetStateAfterPath();\n            steps := path.steps_{atomicPath.Name};\n            states := {prefix}_GetPathStates_{atomicPath.Name}(s, tid, steps);\n          }}\n        \";\n        pgp.AddLemma(str, auxName);\n      }\n    }\n\n    ///////////////////////////////////////////////////////////////////////\n    // ATOMIC SPEC\n    ///////////////////////////////////////////////////////////////////////\n\n    private void CreateAtomicSpecFunctions()\n    {\n      var str = $@\"\n        function {prefix}_GetSpecFunctions() : AtomicSpecFunctions<{typeState}, {prefix}_Path, {moduleName}.Armada_PC>\n        {{\n          var lasf := {specFunctions};\n          AtomicSpecFunctions(lasf.init, {prefix}_ValidPath, {prefix}_GetStateAfterPath, {prefix}_GetPathType,\n                              lasf.state_ok, lasf.get_thread_pc, lasf.is_pc_nonyielding)\n        }}\n      \";\n      pgp.AddFunction(str, auxName);\n    }\n\n    ///////////////////////////////////////////////////////////////////////\n    // LEMMAS\n    ///////////////////////////////////////////////////////////////////////\n\n    public void GeneratePCEffectLemmas()\n    {\n      string str;\n      var pr = new PathPrinter(this);\n      foreach (var atomicPath in atomicPaths)\n      {\n        str = $@\"\n          lemma lemma_{prefix}_PathHasPCEffect_{atomicPath.Name}(\n            s: {typeState},\n            path: {prefix}_Path,\n            tid: Armada_ThreadHandle\n            )\n            requires path.{prefix}_Path_{atomicPath.Name}?\n            requires var asf := {prefix}_GetSpecFunctions(); asf.path_valid(s, path, tid)\n            ensures  var asf := {prefix}_GetSpecFunctions();\n                     var pc := asf.get_thread_pc(s, tid);\n                     var s' := asf.path_next(s, path, tid);\n                     var pc' := asf.get_thread_pc(s', tid);\n        \";\n        if (atomicPath.Tau) {\n          str += $\"asf.state_ok(s) && pc.Some? && asf.state_ok(s') && pc'.Some? && pc'.v == pc.v\";\n        }\n        else {\n          str += $\"asf.state_ok(s) && pc.Some? && pc.v.{atomicPath.StartPC}?\";\n          if (atomicPath.Stopping) {\n            str += \" && !asf.state_ok(s')\";\n          }\n          else if (atomicPath.EndPC == null) {\n            str += \" && asf.state_ok(s') && pc'.None?\";\n          }\n          else {\n            str += $\" && asf.state_ok(s') && pc'.Some? && pc'.v.{atomicPath.EndPC}?\";\n          }\n        }\n        str += \"{\\n\";\n        str += pr.GetOpenValidPathInvocation(atomicPath);\n        str += \"}\\n\";\n        pgp.AddLemma(str, auxName);\n      }\n\n      str = $@\"\n        lemma lemma_{prefix}_PathImpliesThreadRunning(\n          s: {typeState},\n          path: {prefix}_Path,\n          tid: Armada_ThreadHandle\n          )\n          ensures  var asf := {prefix}_GetSpecFunctions();\n                   asf.path_valid(s, path, tid) ==> asf.state_ok(s) && asf.get_thread_pc(s, tid).Some?\n        {{\n          var asf := {prefix}_GetSpecFunctions();\n          if asf.path_valid(s, path, tid) {{\n            match path {{\n      \";\n      foreach (var atomicPath in atomicPaths)\n      {\n        str += $@\"\n            case {prefix}_Path_{atomicPath.Name}(_) =>\n              lemma_{prefix}_PathHasPCEffect_{atomicPath.Name}(s, path, tid);\n        \";\n      }\n      str += \"} } }\\n\";\n      pgp.AddLemma(str, auxName);\n    }\n\n    ///////////////////////////////////////////////////////////////////////\n    // SEARCHING FOR AN ATOMIC PATH\n    ///////////////////////////////////////////////////////////////////////\n\n    public AtomicPathPrefix FindAtomicPathPrefixByNextRoutines(List<NextRoutine> nextRoutines)\n    {\n      if (nextRoutines.Count == 0) {\n        return null;\n      }\n\n      var firstRoutine = nextRoutines[0];\n      if (firstRoutine.nextType == NextType.Tau) {\n        return null;\n      }\n\n      AtomicPathPrefix pathPrefix = null;\n      foreach (var nextRoutine in nextRoutines)\n      {\n        var children = (pathPrefix == null ? rootPathPrefixesByPC[firstRoutine.startPC] : pathPrefix.Extensions);\n        pathPrefix = children.FirstOrDefault(p => p.LastNextRoutine == nextRoutine);\n        if (pathPrefix == null) {\n          return null;\n        }\n      }\n\n      return pathPrefix;\n    }\n\n    public AtomicPath FindAtomicPathByNextRoutines(List<NextRoutine> nextRoutines)\n    {\n      if (nextRoutines.Count == 0) {\n        return null;\n      }\n\n      var firstRoutine = nextRoutines[0];\n      if (firstRoutine.nextType == NextType.Tau) {\n        return tauPath;\n      }\n\n      var pathPrefix = FindAtomicPathPrefixByNextRoutines(nextRoutines);\n      return pathPrefix == null ? null : pathPrefix.PathVal;\n    }\n\n    public AtomicPath FindAtomicPathByPCs(List<ArmadaPC> pcs, bool stopping)\n    {\n      if (pcs.Count == 0) {\n        return null;\n      }\n\n      AtomicPathPrefix pathPrefix = null;\n\n      for (var i = 1; i < pcs.Count; ++i)\n      {\n        var pc = pcs[i];\n        var children = (i == 1) ? rootPathPrefixesByPC[pcs[0]] : pathPrefix.Extensions;\n        var findStopping = stopping && (i == pcs.Count - 1);\n        if (pc == null) {\n          pathPrefix = children.FirstOrDefault(p => p.LastNextRoutine.endPC == null && p.Stopping == findStopping);\n        }\n        else {\n          pathPrefix = children.FirstOrDefault(p => pc.Equals(p.LastNextRoutine.endPC) && p.Stopping == findStopping);\n        }\n        if (pathPrefix == null) {\n          return null;\n        }\n      }\n\n      return pathPrefix.PathVal;\n    }\n\n    ///////////////////////////////////////////////////////////////////////\n    // PATH MAPPING\n    ///////////////////////////////////////////////////////////////////////\n\n    public Dictionary<AtomicPath, AtomicPath> CreatePathMap(AtomicSpec hAtomic)\n    {\n      return atomicPaths.ToDictionary(\n               lPath => lPath,\n               lPath => lPath.Tau ? hAtomic.TauPath : hAtomic.FindAtomicPathByPCs(lPath.GetPCs(), lPath.Stopping));\n    }\n\n    public Dictionary<AtomicPath, AtomicPath> CreatePathMap(AtomicSpec hAtomic,\n                                                            Dictionary<NextRoutine, NextRoutine> nextRoutineMap,\n                                                            bool avoidFinalUnmappedStoppingStep = true)\n    {\n      return atomicPaths.Where(p => p.Mappable(nextRoutineMap, p.Stopping, avoidFinalUnmappedStoppingStep)).ToDictionary(\n               lPath => lPath,\n               lPath => lPath.Tau ? hAtomic.TauPath\n                                  : hAtomic.FindAtomicPathByNextRoutines(lPath.MapNextRoutines(nextRoutineMap)));\n    }\n\n    ///////////////////////////////////////////////////////////////////////\n    // BASIC LEMMAS\n    ///////////////////////////////////////////////////////////////////////\n\n    public delegate bool PathToBoolDelegate(AtomicPath ap);\n    public delegate string PathToStringDelegate(AtomicPath ap);\n\n    public void GeneratePerAtomicPathLemma(string fileName, string lemmaName, PathToBoolDelegate pathFilter,\n                                           PathToStringDelegate postconditionDelegate, PathToStringDelegate proofBodyDelegate,\n                                           bool customizable)\n    {\n      string str;\n\n      var customization = customizable ? \"ProofCustomizationGoesHere();\" : \"\";\n\n      var pr = new PathPrinter(this);\n      foreach (var atomicPath in atomicPaths.Where(ap => pathFilter(ap)))\n      {\n        str = $@\"\n          lemma lemma_{prefix}_{lemmaName}_{atomicPath.Name}(\n            asf: AtomicSpecFunctions<{typeState}, {prefix}_Path, {moduleName}.Armada_PC>,\n            s: {typeState},\n            path: {prefix}_Path,\n            tid: Armada_ThreadHandle\n            )\n            requires asf == {prefix}_GetSpecFunctions()\n            requires path.{prefix}_Path_{atomicPath.Name}?\n            requires asf.path_valid(s, path, tid)\n            ensures  {postconditionDelegate(atomicPath)}\n          {{\n            { pr.GetOpenValidPathInvocation(atomicPath) }\n            { proofBodyDelegate(atomicPath) }\n            { customization }\n          }}\n        \";\n        if (fileName == null) {\n          pgp.AddLemma(str);\n        }\n        else {\n          pgp.AddLemma(str, fileName);\n        }\n      }\n    }\n\n    public void GenerateOverallAtomicPathLemma(string fileName, string perPathLemmaName, string overallLemmaName,\n                                               string overallPostcondition, PathToBoolDelegate pathFilter)\n    {\n      string str = $@\"\n        lemma lemma_{prefix}_{overallLemmaName}(\n          asf: AtomicSpecFunctions<{typeState}, {prefix}_Path, {moduleName}.Armada_PC>,\n          s: {typeState},\n          path: {prefix}_Path,\n          tid: Armada_ThreadHandle\n          )\n            requires asf == {prefix}_GetSpecFunctions()\n            requires asf.path_valid(s, path, tid)\n            ensures  {overallPostcondition}\n          {{\n            match path {{\n      \";\n      str += String.Join(\"\\n\", atomicPaths.Select(atomicPath =>\n        $\"case {prefix}_Path_{atomicPath.Name}(_) => \" +\n        (pathFilter(atomicPath) ? $\"lemma_{prefix}_{perPathLemmaName}_{atomicPath.Name}(asf, s, path, tid);\"\n                                : \"assert {overallPostcondition};\")));\n      str += \"}\\n}\\n\";\n      if (fileName == null) {\n        pgp.AddLemma(str);\n      }\n      else {\n        pgp.AddLemma(str, fileName);\n      }\n    }\n\n    public void GenerateAtomicPathRequiresOKLemma()\n    {\n      string str = $@\"\n        lemma lemma_{prefix}_AtomicPathRequiresOK()\n          ensures AtomicPathRequiresOK({prefix}_GetSpecFunctions())\n        {{\n          var asf := {prefix}_GetSpecFunctions();\n          forall s, path, tid | asf.path_valid(s, path, tid)\n            ensures asf.state_ok(s)\n          {{\n            lemma_{prefix}_PathImpliesThreadRunning(s, path, tid);\n          }}\n        }}\n      \";\n      pgp.AddLemma(str, auxName);\n    }\n\n    public void GenerateAtomicSteppingThreadHasPCLemma()\n    {\n      string str = $@\"\n        lemma lemma_{prefix}_AtomicSteppingThreadHasPC()\n          ensures AtomicSteppingThreadHasPC({prefix}_GetSpecFunctions())\n        {{\n          var asf := {prefix}_GetSpecFunctions();\n          forall s, path, tid | asf.path_valid(s, path, tid)\n            ensures asf.get_thread_pc(s, tid).Some?\n          {{\n            lemma_{prefix}_PathImpliesThreadRunning(s, path, tid);\n          }}\n        }}\n      \";\n      pgp.AddLemma(str, auxName);\n    }\n\n    public void GenerateAtomicTauLeavesPCUnchangedLemma()\n    {\n      var pr = new PathPrinter(this);\n      string str = $@\"\n        lemma lemma_{prefix}_AtomicTauLeavesPCUnchanged()\n          ensures AtomicTauLeavesPCUnchanged({prefix}_GetSpecFunctions())\n        {{\n           var asf := {prefix}_GetSpecFunctions();\n           forall s, path, tid | asf.path_valid(s, path, tid) && asf.path_type(path).AtomicPathType_Tau?\n            ensures var s' := asf.path_next(s, path, tid);\n                    asf.get_thread_pc(s', tid) == asf.get_thread_pc(s, tid)\n           {{\n             { pr.GetOpenValidPathInvocation(TauPath) }\n           }}\n        }}\n      \";\n      pgp.AddLemma(str, auxName);\n    }\n\n    public void GenerateAtomicPathCantAffectOtherThreadPCsExceptViaForkLemma()\n    {\n      string postcondition = @\"forall other_tid :: other_tid != tid ==>\n                               var s' := asf.path_next(s, path, tid);\n                               var pc := asf.get_thread_pc(s, other_tid);\n                               var pc' := asf.get_thread_pc(s', other_tid);\n                               (pc' != pc ==> pc.None? && !asf.is_pc_nonyielding(pc'.v))\";\n      GeneratePerAtomicPathLemma(auxName, \"AtomicPathCantAffectOtherThreadPCsExceptViaFork\",\n                                 atomicPath => true,\n                                 atomicPath => postcondition,\n                                 atomicPath => \"\",\n                                 false);\n      GenerateOverallAtomicPathLemma(auxName,\n                                     \"AtomicPathCantAffectOtherThreadPCsExceptViaFork\",\n                                     \"AtomicPathCantAffectOtherThreadPCsExceptViaFork\",\n                                     postcondition,\n                                     ap => true);\n\n      string str = $@\"\n        lemma lemma_{prefix}_AtomicThreadCantAffectOtherThreadPCExceptViaFork()\n          ensures AtomicThreadCantAffectOtherThreadPCExceptViaFork({prefix}_GetSpecFunctions())\n        {{\n          var asf := {prefix}_GetSpecFunctions();\n          forall s, path, tid, other_tid | asf.path_valid(s, path, tid) && other_tid != tid\n            ensures var s' := asf.path_next(s, path, tid);\n                    var pc := asf.get_thread_pc(s, other_tid);\n                    var pc' := asf.get_thread_pc(s', other_tid);\n                    (pc' != pc ==> pc.None? && !asf.is_pc_nonyielding(pc'.v))\n          {{\n            lemma_{prefix}_AtomicPathCantAffectOtherThreadPCsExceptViaFork(asf, s, path, tid);\n          }}\n        }}\n      \";\n      pgp.AddLemma(str, auxName);\n    }\n\n    public void GenerateAtomicPathTypeAlwaysMatchesPCTypesLemma()\n    {\n      string str = $@\"\n        lemma lemma_{prefix}_AtomicPathTypeAlwaysMatchesPCTypes()\n          ensures AtomicPathTypeAlwaysMatchesPCTypes({prefix}_GetSpecFunctions())\n        {{\n          var asf := {prefix}_GetSpecFunctions();\n          forall s, path, tid | asf.path_valid(s, path, tid)\n            ensures AtomicPathTypeMatchesPCTypes(asf, s, path, tid)\n          {{\n            match path {{\n      \";\n      str += String.Join(\"\\n\", atomicPaths.Select(atomicPath => $@\"\n        case {prefix}_Path_{atomicPath.Name}(_) =>\n          lemma_{prefix}_PathHasPCEffect_{atomicPath.Name}(s, path, tid);\n      \"));\n      str += \"}\\n  }\\n  }\\n\";\n      pgp.AddLemma(str, auxName);\n    }\n  }\n}\n"
  },
  {
    "path": "Source/Armada/BigIntegerParser.cs",
    "content": "using System;\nusing System.Numerics;\nusing System.Globalization;\n\nnamespace Microsoft.Armada {\n    internal static class BigIntegerParser {\n        /// <summary>\n        ///   Mono does not support the BigInteger.TryParse method. In practice,\n        ///   we seldom actually need to parse huge integers, so it makes sense\n        ///   to support most real-life cases by simply trying to parse using\n        ///   Int64, and only falling back if needed.\n        /// </summary>\n        internal static BigInteger Parse(string str, NumberStyles style) {\n            UInt64 parsed;\n            if (UInt64.TryParse(str, style, NumberFormatInfo.CurrentInfo, out parsed)) {\n                return new BigInteger(parsed);\n            } else {\n                // Throws on Mono 3.2.8\n                return BigInteger.Parse(str, style);\n            }\n        }\n\n        internal static BigInteger Parse(string str) {\n            return BigIntegerParser.Parse(str, NumberStyles.Integer);\n        }\n    }\n}\n"
  },
  {
    "path": "Source/Armada/Cloner.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Numerics;\nusing System.Diagnostics.Contracts;\nusing IToken = Microsoft.Boogie.IToken;\n\nnamespace Microsoft.Armada\n{\n  class Cloner\n  {\n\n\n    public virtual ModuleDefinition CloneModuleDefinition(ModuleDefinition m, string name) {\n      ModuleDefinition nw;\n      if (m is DefaultModuleDecl) {\n        nw = new DefaultModuleDecl();\n      } else {\n        nw = new ModuleDefinition(Tok(m.tok), name, m.PrefixIds, m.IsAbstract, m.IsProtected, m.IsFacade, m.RefinementBaseName, m.Module, CloneAttributes(m.Attributes), true);\n      }\n      foreach (var d in m.TopLevelDecls) {\n        nw.TopLevelDecls.Add(CloneDeclaration(d, nw));\n      }\n      foreach (var tup in m.PrefixNamedModules) {\n        var newTup = new Tuple<List<IToken>, LiteralModuleDecl>(tup.Item1, (LiteralModuleDecl)CloneDeclaration(tup.Item2, nw));\n        nw.PrefixNamedModules.Add(newTup);\n      }\n      if (null != m.RefinementBase) {\n        nw.RefinementBase = GetRefinementBase(m);\n      }\n      nw.Height = m.Height;\n      return nw;\n    }\n\n\n    public virtual ModuleDefinition GetRefinementBase(ModuleDefinition m) {\n      Contract.Requires(m != null);\n      return m.RefinementBase;\n    }\n\n    public virtual TopLevelDecl CloneDeclaration(TopLevelDecl d, ModuleDefinition m) {\n      Contract.Requires(d != null);\n      Contract.Requires(m != null);\n\n      if (d is OpaqueTypeDecl) {\n        var dd = (OpaqueTypeDecl)d;\n        return new OpaqueTypeDecl(Tok(dd.tok), dd.Name, m, CloneTPChar(dd.TheType.Characteristics), dd.TypeArgs.ConvertAll(CloneTypeParam), CloneAttributes(dd.Attributes));\n      } else if (d is SubsetTypeDecl) {\n        Contract.Assume(!(d is NonNullTypeDecl));  // don't clone the non-null type declaration; close the class, which will create a new non-null type declaration\n        var dd = (SubsetTypeDecl)d;\n        var tps = dd.TypeArgs.ConvertAll(CloneTypeParam);\n        return new SubsetTypeDecl(Tok(dd.tok), dd.Name, CloneTPChar(dd.Characteristics), tps, m, CloneBoundVar(dd.Var), CloneExpr(dd.Constraint), dd.WitnessKind, CloneExpr(dd.Witness), CloneAttributes(dd.Attributes));\n      } else if (d is TypeSynonymDecl) {\n        var dd = (TypeSynonymDecl)d;\n        var tps = dd.TypeArgs.ConvertAll(CloneTypeParam);\n        return new TypeSynonymDecl(Tok(dd.tok), dd.Name, CloneTPChar(dd.Characteristics), tps, m, CloneType(dd.Rhs), CloneAttributes(dd.Attributes));\n      } else if (d is NewtypeDecl) {\n        var dd = (NewtypeDecl)d;\n          if (dd.Var == null) {\n            return new NewtypeDecl(Tok(dd.tok), dd.Name, m, CloneType(dd.BaseType), dd.Members.ConvertAll(CloneMember), CloneAttributes(dd.Attributes));\n          } else {\n            return new NewtypeDecl(Tok(dd.tok), dd.Name, m, CloneBoundVar(dd.Var), CloneExpr(dd.Constraint), dd.WitnessKind, CloneExpr(dd.Witness), dd.Members.ConvertAll(CloneMember), CloneAttributes(dd.Attributes));\n          }\n      } else if (d is TupleTypeDecl) {\n        var dd = (TupleTypeDecl)d;\n        return new TupleTypeDecl(dd.Dims, dd.Module, dd.Attributes);\n      } else if (d is IndDatatypeDecl) {\n        var dd = (IndDatatypeDecl)d;\n        var tps = dd.TypeArgs.ConvertAll(CloneTypeParam);\n        var ctors = dd.Ctors.ConvertAll(CloneCtor);\n        var dt = new IndDatatypeDecl(Tok(dd.tok), dd.Name, m, tps, ctors, dd.Members.ConvertAll(CloneMember), CloneAttributes(dd.Attributes));\n        return dt;\n      } else if (d is CoDatatypeDecl) {\n        var dd = (CoDatatypeDecl)d;\n        var tps = dd.TypeArgs.ConvertAll(CloneTypeParam);\n        var ctors = dd.Ctors.ConvertAll(CloneCtor);\n        var dt = new CoDatatypeDecl(Tok(dd.tok), dd.Name, m, tps, ctors, dd.Members.ConvertAll(CloneMember), CloneAttributes(dd.Attributes));\n        return dt;\n      } else if (d is IteratorDecl) {\n        var dd = (IteratorDecl)d;\n        var tps = dd.TypeArgs.ConvertAll(CloneTypeParam);\n        var ins = dd.Ins.ConvertAll(CloneFormal);\n        var outs = dd.Outs.ConvertAll(CloneFormal);\n        var reads = CloneSpecFrameExpr(dd.Reads);\n        var mod = CloneSpecFrameExpr(dd.Modifies);\n        var decr = CloneSpecExpr(dd.Decreases);\n        var req = dd.Requires.ConvertAll(CloneMayBeFreeExpr);\n        var yreq = dd.YieldRequires.ConvertAll(CloneMayBeFreeExpr);\n        var ens = dd.Ensures.ConvertAll(CloneMayBeFreeExpr);\n        var yens = dd.YieldEnsures.ConvertAll(CloneMayBeFreeExpr);\n        var body = CloneBlockStmt(dd.Body);\n        var iter = new IteratorDecl(Tok(dd.tok), dd.Name, dd.Module,\n          tps, ins, outs, reads, mod, decr,\n          req, ens, yreq, yens,\n          body, CloneAttributes(dd.Attributes), dd.SignatureEllipsis);\n        return iter;\n      } else if (d is TraitDecl) {\n        var dd = (TraitDecl)d;\n        var tps = dd.TypeArgs.ConvertAll(CloneTypeParam);\n        var mm = dd.Members.ConvertAll(CloneMember);\n        var cl = new TraitDecl(Tok(dd.tok), dd.Name, m, tps, mm, CloneAttributes(dd.Attributes));\n        return cl;\n      } else if (d is ClassDecl) {\n        var dd = (ClassDecl)d;\n        var tps = dd.TypeArgs.ConvertAll(CloneTypeParam);\n        var mm = dd.Members.ConvertAll(CloneMember);\n        if (d is DefaultClassDecl) {\n          return new DefaultClassDecl(m, mm);\n        } else {\n          return new ClassDecl(Tok(dd.tok), dd.Name, m, tps, mm, CloneAttributes(dd.Attributes), dd.TraitsTyp.ConvertAll(CloneType));\n        }\n      } else if (d is ModuleDecl) {\n        if (d is LiteralModuleDecl) {\n          return new LiteralModuleDecl(((LiteralModuleDecl)d).ModuleDef, m);\n        } else if (d is AliasModuleDecl) {\n          var a = (AliasModuleDecl)d;\n          return new AliasModuleDecl(a.Path, a.tok, m, a.Opened, a.Exports);\n        } else if (d is ModuleFacadeDecl) {\n          var a = (ModuleFacadeDecl)d;\n          return new ModuleFacadeDecl(a.Path, a.tok, m, a.Opened, a.Exports);\n        } else if (d is ModuleExportDecl) {\n          var a = (ModuleExportDecl)d;\n          return new ModuleExportDecl(a.tok, m, a.Exports, a.Extends, a.ProvideAll, a.RevealAll, a.IsDefault);\n        } else {\n          Contract.Assert(false);  // unexpected declaration\n          return null;  // to please compiler\n        }\n      } else {\n        Contract.Assert(false);  // unexpected declaration\n        return null;  // to please compiler\n      }\n    }\n\n    public TypeParameter.TypeParameterCharacteristics CloneTPChar(TypeParameter.TypeParameterCharacteristics characteristics) {\n      TypeParameter.EqualitySupportValue eqSupport;\n      if (characteristics.EqualitySupport == TypeParameter.EqualitySupportValue.InferredRequired) {\n        eqSupport = TypeParameter.EqualitySupportValue.Unspecified;\n      } else {\n        eqSupport = characteristics.EqualitySupport;\n      }\n      return new TypeParameter.TypeParameterCharacteristics(eqSupport, characteristics.MustSupportZeroInitialization, characteristics.DisallowReferenceTypes);\n    }\n\n    public DatatypeCtor CloneCtor(DatatypeCtor ct) {\n      return new DatatypeCtor(Tok(ct.tok), ct.Name, ct.Formals.ConvertAll(CloneFormal), CloneAttributes(ct.Attributes));\n    }\n\n    public TypeParameter CloneTypeParam(TypeParameter tp) {\n      return new TypeParameter(Tok(tp.tok), tp.Name, tp.VarianceSyntax, CloneTPChar(tp.Characteristics));\n    }\n\n    public virtual MemberDecl CloneMember(MemberDecl member) {\n      if (member is Field) {\n        var f = (Field)member;\n        return CloneField(f);\n      } else if (member is Function) {\n        var f = (Function)member;\n        return CloneFunction(f);\n      } else {\n        var m = (Method)member;\n        return CloneMethod(m);\n      }\n    }\n\n    public virtual Type CloneType(Type t) {\n      if (t is BasicType) {\n        return t;\n      } else if (t is SetType) {\n        var tt = (SetType)t;\n        return new SetType(tt.Finite, CloneType(tt.Arg));\n      } else if (t is SeqType) {\n        var tt = (SeqType)t;\n        return new SeqType(CloneType(tt.Arg));\n      } else if (t is MultiSetType) {\n        var tt = (MultiSetType)t;\n        return new MultiSetType(CloneType(tt.Arg));\n      } else if (t is MapType) {\n        var tt = (MapType)t;\n        return new MapType(tt.Finite, CloneType(tt.Domain), CloneType(tt.Range));\n      } else if (t is ArrowType) {\n        var tt = (ArrowType)t;\n        return new ArrowType(Tok(tt.tok), tt.Args.ConvertAll(CloneType), CloneType(tt.Result));\n      } else if (t is UserDefinedType) {\n        var tt = (UserDefinedType)t;\n#if TEST_TYPE_SYNONYM_TRANSPARENCY\n        if (tt.Name == \"type#synonym#transparency#test\") {\n          // time to drop the synonym wrapper\n          var syn = (TypeSynonymDecl)tt.ResolvedClass;\n          return CloneType(syn.Rhs);\n        }\n#endif\n        return new UserDefinedType(Tok(tt.tok), CloneExpr(tt.NamePath));\n      } else if (t is InferredTypeProxy) {\n        return new InferredTypeProxy();\n      } else if (t is ParamTypeProxy) {\n        return new ParamTypeProxy(CloneTypeParam(((ParamTypeProxy)t).orig));\n      } else {\n        Contract.Assert(false);  // unexpected type (e.g., no other type proxies are expected at this time)\n        return null;  // to please compiler\n      }\n    }\n\n    public Formal CloneFormal(Formal formal) {\n      Formal f = new Formal(Tok(formal.tok), formal.Name, CloneType(formal.Type), formal.InParam, formal.IsGhost, formal.IsOld);\n      //if (f.Type is UserDefinedType && formal.Type is UserDefinedType)\n      //    ((UserDefinedType)f.Type).ResolvedClass = ((UserDefinedType)(formal.Type)).ResolvedClass;\n      return f;\n    }\n\n    public virtual BoundVar CloneBoundVar(BoundVar bv) {\n      var bvNew = new BoundVar(Tok(bv.tok), bv.Name, CloneType(bv.SyntacticType));\n      bvNew.IsGhost = bv.IsGhost;\n      return bvNew;\n    }\n\n    public VT CloneIVariable<VT>(VT v) where VT: IVariable {\n      var iv = (IVariable)v;\n      if (iv is Formal) {\n        iv = CloneFormal((Formal)iv);\n      } else if (iv is BoundVar) {\n        iv = CloneBoundVar((BoundVar)iv);\n      } else if (iv is LocalVariable) {\n        var local = (LocalVariable)iv;\n        iv = new LocalVariable(Tok(local.Tok), Tok(local.EndTok), local.Name, CloneType(local.OptionalType), local.IsGhost, local.IsNoAddr);\n      } else {\n        Contract.Assume(false);  // unexpected IVariable\n        iv = null;  // please compiler\n      }\n      return (VT)iv;\n    }\n\n    public Specification<Expression> CloneSpecExpr(Specification<Expression> spec) {\n      var ee = spec.Expressions == null ? null : spec.Expressions.ConvertAll(CloneExpr);\n      return new Specification<Expression>(ee, CloneAttributes(spec.Attributes));\n    }\n\n    public Specification<FrameExpression> CloneSpecFrameExpr(Specification<FrameExpression> frame) {\n      var ee = frame.Expressions == null ? null : frame.Expressions.ConvertAll(CloneFrameExpr);\n      return new Specification<FrameExpression>(ee, CloneAttributes(frame.Attributes));\n    }\n\n    public FrameExpression CloneFrameExpr(FrameExpression frame) {\n      return new FrameExpression(Tok(frame.tok), CloneExpr(frame.E), frame.FieldName);\n    }\n    public Attributes CloneAttributes(Attributes attrs) {\n      if (attrs == null) {\n        return null;\n      } else if (attrs.Name.StartsWith(\"_\")) {\n        // skip this attribute, since it would have been produced during resolution\n        return CloneAttributes(attrs.Prev);\n      } else if (attrs is UserSuppliedAttributes) {\n        var usa = (UserSuppliedAttributes)attrs;\n        return new UserSuppliedAttributes(Tok(usa.tok), Tok(usa.OpenBrace), Tok(usa.CloseBrace), attrs.Args.ConvertAll(CloneExpr), CloneAttributes(attrs.Prev));\n      } else {\n        return new Attributes(attrs.Name, attrs.Args.ConvertAll(CloneExpr), CloneAttributes(attrs.Prev));\n      }\n    }\n\n    public MaybeFreeExpression CloneMayBeFreeExpr(MaybeFreeExpression expr) {\n      var mfe = new MaybeFreeExpression(CloneExpr(expr.E), expr.IsFree, expr.Label == null ? null : new AssertLabel(Tok(expr.Label.Tok), expr.Label.Name), CloneAttributes(expr.Attributes));\n      mfe.Attributes = CloneAttributes(expr.Attributes);\n      return mfe;\n    }\n\n    public virtual Expression CloneExpr(Expression expr) {\n      if (expr == null) {\n        return null;\n      } else if (expr is LiteralExpr) {\n        var e = (LiteralExpr)expr;\n        if (e is StaticReceiverExpr) {\n          var ee = (StaticReceiverExpr)e;\n          return new StaticReceiverExpr(Tok(e.tok), CloneType(ee.UnresolvedType), ee.IsImplicit);\n        } else if (e.Value == null) {\n          return new LiteralExpr(Tok(e.tok));\n        } else if (e.Value is bool) {\n          return new LiteralExpr(Tok(e.tok), (bool)e.Value);\n        } else if (e is CharLiteralExpr) {\n          return new CharLiteralExpr(Tok(e.tok), (string)e.Value);\n        } else if (e is StringLiteralExpr) {\n          var str = (StringLiteralExpr)e;\n          return new StringLiteralExpr(Tok(e.tok), (string)e.Value, str.IsVerbatim);\n        } else if (e.Value is BaseTypes.BigDec) {\n          return new LiteralExpr(Tok(e.tok), (BaseTypes.BigDec)e.Value);\n        } else {\n          return new LiteralExpr(Tok(e.tok), (BigInteger)e.Value);\n        }\n\n      } else if (expr is ThisExpr) {\n        if (expr is ImplicitThisExpr_ConstructorCall) {\n          return new ImplicitThisExpr_ConstructorCall(Tok(expr.tok));\n        } else if (expr is ImplicitThisExpr) {\n          return new ImplicitThisExpr(Tok(expr.tok));\n        } else {\n          return new ThisExpr(Tok(expr.tok));\n        }\n\n      } else if (expr is IdentifierExpr) {\n        var e = (IdentifierExpr)expr;\n        return new IdentifierExpr(Tok(e.tok), e.Name);\n\n      } else if (expr is DatatypeValue) {\n        var e = (DatatypeValue)expr;\n        return new DatatypeValue(Tok(e.tok), e.DatatypeName, e.MemberName, e.Arguments.ConvertAll(CloneExpr));\n\n      } else if (expr is DisplayExpression) {\n        DisplayExpression e = (DisplayExpression)expr;\n        if (expr is SetDisplayExpr) {\n          return new SetDisplayExpr(Tok(e.tok), ((SetDisplayExpr)expr).Finite, e.Elements.ConvertAll(CloneExpr));\n        } else if (expr is MultiSetDisplayExpr) {\n          return new MultiSetDisplayExpr(Tok(e.tok), e.Elements.ConvertAll(CloneExpr));\n        } else {\n          Contract.Assert(expr is SeqDisplayExpr);\n          return new SeqDisplayExpr(Tok(e.tok), e.Elements.ConvertAll(CloneExpr));\n        }\n\n      } else if (expr is MapDisplayExpr) {\n        MapDisplayExpr e = (MapDisplayExpr)expr;\n        List<ExpressionPair> pp = new List<ExpressionPair>();\n        foreach (ExpressionPair p in e.Elements) {\n          pp.Add(new ExpressionPair(CloneExpr(p.A), CloneExpr(p.B)));\n        }\n        return new MapDisplayExpr(Tok(expr.tok), e.Finite, pp);\n\n      } else if (expr is NameSegment) {\n        return CloneNameSegment(expr);\n      } else if (expr is ExprDotName) {\n        var e = (ExprDotName)expr;\n        return new ExprDotName(Tok(e.tok), CloneExpr(e.Lhs), e.SuffixName, e.OptTypeArguments == null ? null : e.OptTypeArguments.ConvertAll(CloneType));\n      } else if (expr is ApplySuffix) {\n        var e = (ApplySuffix) expr;\n        return CloneApplySuffix(e);\n      } else if (expr is RevealExpr) {\n        var e = (RevealExpr) expr;\n        return new RevealExpr(Tok(e.tok), CloneExpr(e.Expr));\n      } else if (expr is MemberSelectExpr) {\n        var e = (MemberSelectExpr)expr;\n        return new MemberSelectExpr(Tok(e.tok), CloneExpr(e.Obj), e.MemberName);\n\n      } else if (expr is SeqSelectExpr) {\n        var e = (SeqSelectExpr)expr;\n        return new SeqSelectExpr(Tok(e.tok), e.SelectOne, CloneExpr(e.Seq), CloneExpr(e.E0), CloneExpr(e.E1));\n\n      } else if (expr is MultiSelectExpr) {\n        var e = (MultiSelectExpr)expr;\n        return new MultiSelectExpr(Tok(e.tok), CloneExpr(e.Array), e.Indices.ConvertAll(CloneExpr));\n\n      } else if (expr is SeqUpdateExpr) {\n        var e = (SeqUpdateExpr)expr;\n        return new SeqUpdateExpr(Tok(e.tok), CloneExpr(e.Seq), CloneExpr(e.Index), CloneExpr(e.Value));\n\n      } else if (expr is DatatypeUpdateExpr) {\n        var e = (DatatypeUpdateExpr)expr;\n        return new DatatypeUpdateExpr(Tok(e.tok), CloneExpr(e.Root), e.Updates.ConvertAll(t => Tuple.Create(Tok(t.Item1), t.Item2, CloneExpr(t.Item3))));\n\n      } else if (expr is FunctionCallExpr) {\n        var e = (FunctionCallExpr)expr;\n        return new FunctionCallExpr(Tok(e.tok), e.Name, CloneExpr(e.Receiver), e.OpenParen == null ? null : Tok(e.OpenParen), e.Args.ConvertAll(CloneExpr));\n\n      } else if (expr is ApplyExpr) {\n        var e = (ApplyExpr)expr;\n        return new ApplyExpr(Tok(e.tok), CloneExpr(e.Function), e.Args.ConvertAll(CloneExpr));\n\n      } else if (expr is SeqConstructionExpr) {\n        var e = (SeqConstructionExpr)expr;\n        return new SeqConstructionExpr(Tok(e.tok), CloneExpr(e.N), CloneExpr(e.Initializer));\n\n      } else if (expr is MultiSetFormingExpr) {\n        var e = (MultiSetFormingExpr)expr;\n        return new MultiSetFormingExpr(Tok(e.tok), CloneExpr(e.E));\n\n      } else if (expr is OldExpr) {\n        var e = (OldExpr)expr;\n        return new OldExpr(Tok(e.tok), CloneExpr(e.E), e.At);\n\n      } else if (expr is UnchangedExpr) {\n        var e = (UnchangedExpr)expr;\n        return new UnchangedExpr(Tok(e.tok), e.Frame.ConvertAll(CloneFrameExpr), e.At);\n\n      } else if (expr is UnaryOpExpr) {\n        var e = (UnaryOpExpr)expr;\n        return new UnaryOpExpr(Tok(e.tok), e.Op, CloneExpr(e.E));\n\n      } else if (expr is ConversionExpr) {\n        var e = (ConversionExpr)expr;\n        return new ConversionExpr(Tok(e.tok), CloneExpr(e.E), CloneType(e.ToType));\n\n      } else if (expr is BinaryExpr) {\n        var e = (BinaryExpr)expr;\n        return new BinaryExpr(Tok(e.tok), e.Op, CloneExpr(e.E0), CloneExpr(e.E1));\n\n      } else if (expr is TernaryExpr) {\n        var e = (TernaryExpr)expr;\n        return new TernaryExpr(Tok(e.tok), e.Op, CloneExpr(e.E0), CloneExpr(e.E1), CloneExpr(e.E2));\n\n      } else if (expr is ChainingExpression) {\n        var e = (ChainingExpression)expr;\n        return new ChainingExpression(Tok(e.tok), e.Operands.ConvertAll(CloneExpr), e.Operators, e.OperatorLocs.ConvertAll(Tok), e.PrefixLimits.ConvertAll(CloneExpr));\n\n      } else if (expr is LetExpr) {\n        var e = (LetExpr)expr;\n        return new LetExpr(Tok(e.tok), e.LHSs.ConvertAll(CloneCasePattern), e.RHSs.ConvertAll(CloneExpr), CloneExpr(e.Body), e.Exact, e.Attributes);\n\n      } else if (expr is LetOrFailExpr) {\n        var e = (LetOrFailExpr)expr;\n        return new LetOrFailExpr(Tok(e.tok), e.Lhs == null ? null : CloneCasePattern(e.Lhs), CloneExpr(e.Rhs), CloneExpr(e.Body));\n\n      } else if (expr is NamedExpr) {\n        var e = (NamedExpr)expr;\n        return new NamedExpr(Tok(e.tok), e.Name, CloneExpr(e.Body));\n      } else if (expr is ComprehensionExpr) {\n        var e = (ComprehensionExpr)expr;\n        var tk = Tok(e.tok);\n        var bvs = e.BoundVars.ConvertAll(CloneBoundVar);\n        var range = CloneExpr(e.Range);\n        var term = CloneExpr(e.Term);\n        if (e is QuantifierExpr) {\n          var q = (QuantifierExpr)e;\n          var tvs = q.TypeArgs.ConvertAll(CloneTypeParam);\n          if (e is ForallExpr) {\n            return new ForallExpr(tk, tvs, bvs, range, term, CloneAttributes(e.Attributes));\n          } else if (e is ExistsExpr) {\n            return new ExistsExpr(tk, tvs, bvs, range, term, CloneAttributes(e.Attributes));\n          } else {\n            Contract.Assert(false); throw new cce.UnreachableException();  // unexpected quantifier expression\n          }\n        } else if (e is MapComprehension) {\n          var mc = (MapComprehension)e;\n          return new MapComprehension(tk, mc.Finite, bvs, range, mc.TermLeft == null ? null : CloneExpr(mc.TermLeft), term, CloneAttributes(e.Attributes));\n        } else if (e is LambdaExpr) {\n          var l = (LambdaExpr)e;\n          return new LambdaExpr(tk, bvs, range, l.Reads.ConvertAll(CloneFrameExpr), term);\n        } else {\n          Contract.Assert(e is SetComprehension);\n          var tt = (SetComprehension)e;\n          return new SetComprehension(tk, tt.Finite, bvs, range, tt.TermIsImplicit ? null : term, CloneAttributes(e.Attributes));\n        }\n\n      } else if (expr is WildcardExpr) {\n        return new WildcardExpr(Tok(expr.tok));\n\n      } else if (expr is StmtExpr) {\n        var e = (StmtExpr)expr;\n        return new StmtExpr(Tok(e.tok), CloneStmt(e.S), CloneExpr(e.E));\n\n      } else if (expr is ITEExpr) {\n        var e = (ITEExpr)expr;\n        return new ITEExpr(Tok(e.tok), e.IsBindingGuard, CloneExpr(e.Test), CloneExpr(e.Thn), CloneExpr(e.Els));\n\n      } else if (expr is AutoGeneratedExpression) {\n        var e = (AutoGeneratedExpression)expr;\n        var a = CloneExpr(e.E);\n        return new AutoGeneratedExpression(Tok(e.tok), a);\n\n      } else if (expr is ParensExpression) {\n        var e = (ParensExpression)expr;\n        return CloneExpr(e.E);  // skip the parentheses in the clone\n\n      } else if (expr is MatchExpr) {\n        var e = (MatchExpr)expr;\n        return new MatchExpr(Tok(e.tok), CloneExpr(e.Source), e.Cases.ConvertAll(CloneMatchCaseExpr), e.UsesOptionalBraces);\n\n      } else if (expr is NegationExpression) {\n        var e = (NegationExpression)expr;\n        return new NegationExpression(Tok(e.tok), CloneExpr(e.E));\n\n      } else {\n        Contract.Assert(false); throw new cce.UnreachableException();  // unexpected expression\n      }\n    }\n\n    public MatchCaseExpr CloneMatchCaseExpr(MatchCaseExpr c) {\n      Contract.Requires(c != null);\n      if (c.Arguments != null) {\n        Contract.Assert(c.CasePatterns == null);\n        return new MatchCaseExpr(Tok(c.tok), c.Id, c.Arguments.ConvertAll(CloneBoundVar), CloneExpr(c.Body));\n      } else {\n        Contract.Assert(c.Arguments == null);\n        Contract.Assert(c.CasePatterns != null);\n        return new MatchCaseExpr(Tok(c.tok), c.Id, c.CasePatterns.ConvertAll(CloneCasePattern), CloneExpr(c.Body));\n      }\n    }\n\n    public virtual Expression CloneApplySuffix(ApplySuffix e) {\n        return new ApplySuffix(Tok(e.tok), CloneExpr(e.Lhs), e.Args.ConvertAll(CloneExpr));\n    }\n\n    public virtual CasePattern<VT> CloneCasePattern<VT>(CasePattern<VT> pat) where VT: IVariable {\n      Contract.Requires(pat != null);\n      if (pat.Var != null) {\n        return new CasePattern<VT>(pat.tok, CloneIVariable(pat.Var));\n      } else if (pat.Arguments == null) {\n        return new CasePattern<VT>(pat.tok, pat.Id, null);\n      } else {\n        return new CasePattern<VT>(pat.tok, pat.Id, pat.Arguments.ConvertAll(CloneCasePattern));\n      }\n    }\n\n    public virtual NameSegment CloneNameSegment(Expression expr) {\n      var e = (NameSegment)expr;\n      return new NameSegment(Tok(e.tok), e.Name, e.OptTypeArguments == null ? null : e.OptTypeArguments.ConvertAll(CloneType));\n    }\n\n    public virtual AssignmentRhs CloneRHS(AssignmentRhs rhs) {\n      AssignmentRhs c;\n      if (rhs is ExprRhs) {\n        var r = (ExprRhs)rhs;\n        c = new ExprRhs(CloneExpr(r.Expr));\n      } else if (rhs is HavocRhs) {\n        c = new HavocRhs(Tok(rhs.Tok));\n      } else {\n        var r = (TypeRhs)rhs;\n        if (r.ArrayDimensions != null) {\n          if (r.InitDisplay != null) {\n            Contract.Assert(r.ArrayDimensions.Count == 1);\n            c = new TypeRhs(Tok(r.Tok), CloneType(r.EType), CloneExpr(r.ArrayDimensions[0]), r.InitDisplay.ConvertAll(CloneExpr));\n          } else {\n            c = new TypeRhs(Tok(r.Tok), CloneType(r.EType), r.ArrayDimensions.ConvertAll(CloneExpr), CloneExpr(r.ElementInit));\n          }\n        } else if (r.Arguments == null) {\n          c = new TypeRhs(Tok(r.Tok), CloneType(r.EType));\n        } else {\n          c = new TypeRhs(Tok(r.Tok), CloneType(r.Path), r.Arguments.ConvertAll(CloneExpr), false);\n        }\n      }\n      c.Attributes = CloneAttributes(rhs.Attributes);\n      return c;\n    }\n\n    public virtual BlockStmt CloneBlockStmt(BlockStmt stmt) {\n      Contract.Requires(!(stmt is DividedBlockStmt));  // for blocks that may be DividedBlockStmt's, call CloneDividedBlockStmt instead\n      if (stmt == null) {\n        return null;\n      } else {\n        return new BlockStmt(Tok(stmt.Tok), Tok(stmt.EndTok), stmt.Body.ConvertAll(CloneStmt));\n      }\n    }\n\n    public virtual DividedBlockStmt CloneDividedBlockStmt(DividedBlockStmt stmt) {\n      if (stmt == null) {\n        return null;\n      } else {\n        return new DividedBlockStmt(Tok(stmt.Tok), Tok(stmt.EndTok), stmt.BodyInit.ConvertAll(CloneStmt), stmt.SeparatorTok == null ? null : Tok(stmt.SeparatorTok), stmt.BodyProper.ConvertAll(CloneStmt));\n      }\n    }\n\n    public virtual Statement CloneStmt(Statement stmt) {\n      if (stmt == null) {\n        return null;\n      }\n\n      Statement r;\n      if (stmt is AssertStmt) {\n        var s = (AssertStmt)stmt;\n        r = new AssertStmt(Tok(s.Tok), Tok(s.EndTok), CloneExpr(s.Expr), CloneBlockStmt(s.Proof), s.Label == null ? null : new AssertLabel(Tok(s.Label.Tok), s.Label.Name), null);\n\n      } else if (stmt is AssumeStmt) {\n        var s = (AssumeStmt)stmt;\n        r = new AssumeStmt(Tok(s.Tok), Tok(s.EndTok), CloneExpr(s.Expr), null);\n\n      } else if (stmt is PrintStmt) {\n        var s = (PrintStmt)stmt;\n        r = new PrintStmt(Tok(s.Tok), Tok(s.EndTok), s.Args.ConvertAll(CloneExpr));\n\n      } else if (stmt is RevealStmt) {\n        var s = (RevealStmt)stmt;\n        r = new RevealStmt(Tok(s.Tok), Tok(s.EndTok), s.Exprs.ConvertAll(CloneExpr));\n\n      } else if (stmt is SomehowStmt) {\n        var s = (SomehowStmt)stmt;\n        r = new SomehowStmt(Tok(s.Tok), Tok(s.EndTok), s.UndefinedUnless.ConvertAll(CloneExpr), CloneSpecExpr(s.Mod), s.Ens.ConvertAll(CloneExpr));\n\n      } else if (stmt is FenceStmt) {\n        var s = (FenceStmt)stmt;\n        r = new FenceStmt(Tok(s.Tok), Tok(s.EndTok));\n\n      } else if (stmt is GotoStmt) {\n        var s = (GotoStmt)stmt;\n        r = new GotoStmt(Tok(s.Tok), Tok(s.EndTok), s.Target);\n\n      } else if (stmt is DeallocStmt) {\n        var s = (DeallocStmt)stmt;\n        r = new DeallocStmt(Tok(s.Tok), Tok(s.EndTok), CloneExpr(s.Addr));\n\n      } else if (stmt is JoinStmt) {\n        var s = (JoinStmt)stmt;\n        r = new JoinStmt(Tok(s.Tok), Tok(s.EndTok), CloneExpr(s.WhichThread));\n\n      } else if (stmt is BreakStmt) {\n        var s = (BreakStmt)stmt;\n        if (s.TargetLabel != null) {\n          r = new BreakStmt(Tok(s.Tok), Tok(s.EndTok), s.TargetLabel);\n        } else {\n          r = new BreakStmt(Tok(s.Tok), Tok(s.EndTok), s.BreakCount);\n        }\n\n      } else if (stmt is ContinueStmt) {\n        var s = (ContinueStmt)stmt;\n        r = new ContinueStmt(Tok(s.Tok), Tok(s.EndTok));\n\n      } else if (stmt is ReturnStmt) {\n        var s = (ReturnStmt)stmt;\n        r = new ReturnStmt(Tok(s.Tok), Tok(s.EndTok), s.rhss == null ? null : s.rhss.ConvertAll(CloneRHS));\n\n      } else if (stmt is YieldStmt) {\n        var s = (YieldStmt)stmt;\n        r = new YieldStmt(Tok(s.Tok), Tok(s.EndTok), s.rhss == null ? null : s.rhss.ConvertAll(CloneRHS));\n\n      } else if (stmt is AssignStmt) {\n        var s = (AssignStmt)stmt;\n        r = new AssignStmt(Tok(s.Tok), Tok(s.EndTok), CloneExpr(s.Lhs), CloneRHS(s.Rhs));\n\n      } else if (stmt is DividedBlockStmt) {\n        r = CloneDividedBlockStmt((DividedBlockStmt)stmt);\n\n      } else if (stmt is BlockStmt) {\n        r = CloneBlockStmt((BlockStmt)stmt);\n\n      } else if (stmt is IfStmt) {\n        var s = (IfStmt)stmt;\n        r = new IfStmt(Tok(s.Tok), Tok(s.EndTok), s.IsBindingGuard, CloneExpr(s.Guard), CloneBlockStmt(s.Thn), CloneStmt(s.Els));\n\n      } else if (stmt is AlternativeStmt) {\n        var s = (AlternativeStmt)stmt;\n        r = new AlternativeStmt(Tok(s.Tok), Tok(s.EndTok), s.Alternatives.ConvertAll(CloneGuardedAlternative), s.UsesOptionalBraces);\n\n      } else if (stmt is WhileStmt) {\n        var s = (WhileStmt)stmt;\n        r = new WhileStmt(Tok(s.Tok), Tok(s.EndTok), CloneExpr(s.Guard), s.Invariants.ConvertAll(CloneMayBeFreeExpr), s.Ens.ConvertAll(CloneExpr), CloneSpecExpr(s.Decreases), CloneSpecFrameExpr(s.Mod), CloneBlockStmt(s.Body));\n\n      } else if (stmt is AlternativeLoopStmt) {\n        var s = (AlternativeLoopStmt)stmt;\n        r = new AlternativeLoopStmt(Tok(s.Tok), Tok(s.EndTok), s.Invariants.ConvertAll(CloneMayBeFreeExpr), CloneSpecExpr(s.Decreases), CloneSpecFrameExpr(s.Mod), s.Alternatives.ConvertAll(CloneGuardedAlternative), s.UsesOptionalBraces);\n\n      } else if (stmt is ForallStmt) {\n        var s = (ForallStmt)stmt;\n        r = new ForallStmt(Tok(s.Tok), Tok(s.EndTok), s.BoundVars.ConvertAll(CloneBoundVar), null, CloneExpr(s.Range), s.Ens.ConvertAll(CloneMayBeFreeExpr), CloneStmt(s.Body));\n      } else if (stmt is CalcStmt) {\n        var s = (CalcStmt)stmt;\n        // calc statements have the unusual property that the last line is duplicated.  If that is the case (which\n        // we expect it to be here), we share the clone of that line as well.\n        var lineCount = s.Lines.Count;\n        var lines = new List<Expression>(lineCount);\n        for (int i = 0; i < lineCount; i++) {\n          lines.Add(i == lineCount - 1 && 2 <= lineCount && s.Lines[i] == s.Lines[i - 1] ? lines[i - 1] : CloneExpr(s.Lines[i]));\n        }\n        Contract.Assert(lines.Count == lineCount);\n        r = new CalcStmt(Tok(s.Tok), Tok(s.EndTok), CloneCalcOp(s.UserSuppliedOp), lines, s.Hints.ConvertAll(CloneBlockStmt), s.StepOps.ConvertAll(CloneCalcOp), CloneAttributes(s.Attributes));\n\n      } else if (stmt is MatchStmt) {\n        var s = (MatchStmt)stmt;\n        r = new MatchStmt(Tok(s.Tok), Tok(s.EndTok), CloneExpr(s.Source), s.Cases.ConvertAll(CloneMatchCaseStmt), s.UsesOptionalBraces);\n\n      } else if (stmt is AssignSuchThatStmt) {\n        var s = (AssignSuchThatStmt)stmt;\n        r = new AssignSuchThatStmt(Tok(s.Tok), Tok(s.EndTok), s.Lhss.ConvertAll(CloneExpr), CloneExpr(s.Expr), s.AssumeToken == null ? null : Tok(s.AssumeToken), null);\n\n      } else if (stmt is UpdateStmt) {\n        var s = (UpdateStmt)stmt;\n        r = new UpdateStmt(Tok(s.Tok), Tok(s.EndTok), s.Lhss.ConvertAll(CloneExpr), s.Rhss.ConvertAll(CloneRHS), s.CanMutateKnownState);\n\n      } else if (stmt is AssignOrReturnStmt) {\n        var s = (AssignOrReturnStmt)stmt;\n        r = new AssignOrReturnStmt(Tok(s.Tok), Tok(s.EndTok), s.Lhss.ConvertAll(CloneExpr), CloneExpr(s.Rhs));\n\n      } else if (stmt is VarDeclStmt) {\n        var s = (VarDeclStmt)stmt;\n        var lhss = s.Locals.ConvertAll(c => new LocalVariable(Tok(c.Tok), Tok(c.EndTok), c.Name, CloneType(c.OptionalType), c.IsGhost, c.IsNoAddr));\n        r = new VarDeclStmt(Tok(s.Tok), Tok(s.EndTok), lhss, (ConcreteUpdateStatement)CloneStmt(s.Update), s.BypassStoreBuffers);\n\n      } else if (stmt is LetStmt) {\n        var s = (LetStmt) stmt;\n        r = new LetStmt(Tok(s.Tok), Tok(s.EndTok), CloneCasePattern(s.LHS), CloneExpr(s.RHS));\n\n      } else if (stmt is ModifyStmt) {\n        var s = (ModifyStmt)stmt;\n        var mod = CloneSpecFrameExpr(s.Mod);\n        var body = s.Body == null ? null : CloneBlockStmt(s.Body);\n        r = new ModifyStmt(Tok(s.Tok), Tok(s.EndTok), mod.Expressions, mod.Attributes, body);\n\n      } else {\n        Contract.Assert(false); throw new cce.UnreachableException();  // unexpected statement\n      }\n\n      // add labels to the cloned statement\n      AddStmtLabels(r, stmt.Labels);\n      r.Attributes = CloneAttributes(stmt.Attributes);\n\n      return r;\n    }\n\n    public MatchCaseStmt CloneMatchCaseStmt(MatchCaseStmt c) {\n      Contract.Requires(c != null);\n      if (c.Arguments != null) {\n        Contract.Assert(c.CasePatterns == null);\n        return new MatchCaseStmt(Tok(c.tok), c.Id, c.Arguments.ConvertAll(CloneBoundVar), c.Body.ConvertAll(CloneStmt));\n      } else {\n        Contract.Assert(c.Arguments == null);\n        Contract.Assert(c.CasePatterns != null);\n        return new MatchCaseStmt(Tok(c.tok), c.Id, c.CasePatterns.ConvertAll(CloneCasePattern), c.Body.ConvertAll(CloneStmt));\n      }\n    }\n\n    public CalcStmt.CalcOp CloneCalcOp(CalcStmt.CalcOp op) {\n      if (op == null) {\n        return null;\n      } else if (op is CalcStmt.BinaryCalcOp) {\n        return new CalcStmt.BinaryCalcOp(((CalcStmt.BinaryCalcOp) op).Op);\n      } else if (op is CalcStmt.TernaryCalcOp) {\n        return new CalcStmt.TernaryCalcOp(CloneExpr(((CalcStmt.TernaryCalcOp) op).Index));\n      } else {\n        Contract.Assert(false);\n        throw new cce.UnreachableException();\n      }\n    }\n\n    public void AddStmtLabels(Statement s, LList<Label> node) {\n      if (node != null) {\n        AddStmtLabels(s, node.Next);\n        if (node.Data.Name == null) {\n          // this indicates an implicit-target break statement that has been resolved; don't add it\n        } else {\n          s.Labels = new LList<Label>(new Label(Tok(node.Data.Tok), node.Data.Name), s.Labels);\n        }\n      }\n    }\n\n    public GuardedAlternative CloneGuardedAlternative(GuardedAlternative alt) {\n      return new GuardedAlternative(Tok(alt.Tok), alt.IsBindingGuard, CloneExpr(alt.Guard), alt.Body.ConvertAll(CloneStmt));\n    }\n\n    public virtual Field CloneField(Field f) {\n      Contract.Requires(f != null);\n      if (f is ConstantField) {\n        var c = (ConstantField)f;\n        return new ConstantField(Tok(c.tok), c.Name, CloneExpr(c.Rhs), c.IsStatic, c.IsGhost, CloneType(c.Type), CloneAttributes(c.Attributes));\n      } else if (f is SpecialField) {\n        // We don't expect a SpecialField to ever be cloned. However, it can happen for malformed programs, for example if\n        // an iterator in a refined module is replaced by a class in the refining module.\n        var s = (SpecialField)f;\n        return new SpecialField(Tok(s.tok), s.Name, s.SpecialId, s.IdParam, s.IsGhost, s.IsMutable, s.IsUserMutable, CloneType(s.Type), CloneAttributes(s.Attributes));\n      } else {\n        return new Field(Tok(f.tok), f.Name, f.HasStaticKeyword, f.IsGhost, f.IsMutable, f.IsUserMutable, CloneType(f.Type), CloneAttributes(f.Attributes));\n      }\n    }\n\n    public virtual Function CloneFunction(Function f, string newName = null) {\n      var tps = f.TypeArgs.ConvertAll(CloneTypeParam);\n      var formals = f.Formals.ConvertAll(CloneFormal);\n      var req = f.Req.ConvertAll(CloneMayBeFreeExpr);\n      var reads = f.Reads.ConvertAll(CloneFrameExpr);\n      var decreases = CloneSpecExpr(f.Decreases);\n      var ens = f.Ens.ConvertAll(CloneMayBeFreeExpr);\n      Expression body;\n      body = CloneExpr(f.Body);\n\n      if (newName == null) {\n        newName = f.Name;\n      }\n\n      if (f is Predicate) {\n        return new Predicate(Tok(f.tok), newName, f.HasStaticKeyword, f.IsProtected, f.IsGhost, tps, formals,\n          req, reads, ens, decreases, body, Predicate.BodyOriginKind.OriginalOrInherited, CloneAttributes(f.Attributes), null);\n      } else if (f is InductivePredicate) {\n        return new InductivePredicate(Tok(f.tok), newName, f.HasStaticKeyword, f.IsProtected, ((InductivePredicate)f).TypeOfK, tps, formals,\n          req, reads, ens, body, CloneAttributes(f.Attributes), null);\n      } else if (f is CoPredicate) {\n        return new CoPredicate(Tok(f.tok), newName, f.HasStaticKeyword, f.IsProtected, ((CoPredicate)f).TypeOfK, tps, formals,\n          req, reads, ens, body, CloneAttributes(f.Attributes), null);\n      } else if (f is TwoStatePredicate) {\n        return new TwoStatePredicate(Tok(f.tok), newName, f.HasStaticKeyword, tps, formals,\n          req, reads, ens, decreases, body, CloneAttributes(f.Attributes), null);\n      } else if (f is TwoStateFunction) {\n        return new TwoStateFunction(Tok(f.tok), newName, f.HasStaticKeyword, tps, formals, f.Result == null ? null : CloneFormal(f.Result), CloneType(f.ResultType),\n          req, reads, ens, decreases, body, CloneAttributes(f.Attributes), null);\n      } else {\n        return new Function(Tok(f.tok), newName, f.HasStaticKeyword, f.IsProtected, f.IsGhost, tps, formals, f.Result == null ? null : CloneFormal(f.Result), CloneType(f.ResultType),\n          req, reads, ens, decreases, body, CloneAttributes(f.Attributes), null);\n      }\n    }\n\n    public virtual Method CloneMethod(Method m) {\n      Contract.Requires(m != null);\n\n      var tps = m.TypeArgs.ConvertAll(CloneTypeParam);\n      var ins = m.Ins.ConvertAll(CloneFormal);\n      var req = m.Req.ConvertAll(CloneMayBeFreeExpr);\n      var mod = CloneSpecFrameExpr(m.Mod);\n      var decreases = CloneSpecExpr(m.Decreases);\n      var reads = CloneSpecExpr(m.Reads);\n      var awaits = m.Awaits.ConvertAll(CloneExpr);\n      var undefinedUnless = m.UndefinedUnless.ConvertAll(CloneExpr);\n\n      var ens = m.Ens.ConvertAll(CloneMayBeFreeExpr);\n\n      BlockStmt body = CloneMethodBody(m);\n\n      if (m is Constructor) {\n        return new Constructor(Tok(m.tok), m.Name, tps, ins,\n          req, mod, ens, decreases, (DividedBlockStmt)body, CloneAttributes(m.Attributes), null);\n      } else if (m is InductiveLemma) {\n        return new InductiveLemma(Tok(m.tok), m.Name, m.HasStaticKeyword, ((InductiveLemma)m).TypeOfK, tps, ins, m.Outs.ConvertAll(CloneFormal),\n          req, mod, ens, decreases, body, CloneAttributes(m.Attributes), null);\n      } else if (m is CoLemma) {\n        return new CoLemma(Tok(m.tok), m.Name, m.HasStaticKeyword, ((CoLemma)m).TypeOfK, tps, ins, m.Outs.ConvertAll(CloneFormal),\n          req, mod, ens, decreases, body, CloneAttributes(m.Attributes), null);\n      } else if (m is Lemma) {\n        return new Lemma(Tok(m.tok), m.Name, m.HasStaticKeyword, tps, ins, m.Outs.ConvertAll(CloneFormal),\n          req, mod, ens, decreases, body, CloneAttributes(m.Attributes), null);\n      } else if (m is TwoStateLemma) {\n        var two = (TwoStateLemma)m;\n        return new TwoStateLemma(Tok(m.tok), m.Name, m.HasStaticKeyword, tps, ins, m.Outs.ConvertAll(CloneFormal),\n          req, mod, ens, decreases, body, CloneAttributes(m.Attributes), null);\n      } else {\n        return new Method(Tok(m.tok), m.Name, m.HasStaticKeyword, m.IsGhost, tps, ins, m.Outs.ConvertAll(CloneFormal),\n                          req, mod, ens, decreases, reads, awaits, undefinedUnless, body, CloneAttributes(m.Attributes), null);\n      }\n    }\n\n    public virtual BlockStmt CloneMethodBody(Method m) {\n      if (m.Body is DividedBlockStmt) {\n        return CloneDividedBlockStmt((DividedBlockStmt)m.Body);\n      } else {\n        return CloneBlockStmt(m.Body);\n      }\n    }\n\n    public virtual IToken Tok(IToken tok) {\n      return tok;\n    }\n  }\n\n\n  /// <summary>\n  /// This cloner copies the origin module signatures to their cloned declarations\n  /// </summary>\n  class DeepModuleSignatureCloner : Cloner {\n    public override TopLevelDecl CloneDeclaration(TopLevelDecl d, ModuleDefinition m) {\n      var dd = base.CloneDeclaration(d, m);\n      if (d is ModuleDecl) {\n        ((ModuleDecl)dd).Signature = ((ModuleDecl)d).Signature;\n        if (d is ModuleFacadeDecl) {\n          var sourcefacade = (ModuleFacadeDecl)d;\n\n          ((ModuleFacadeDecl)dd).OriginalSignature = sourcefacade.OriginalSignature;\n          if (sourcefacade.Root != null) {\n            ((ModuleFacadeDecl)dd).Root = (ModuleDecl)CloneDeclaration(sourcefacade.Root, m);\n          }\n        } else if (d is AliasModuleDecl) {\n          var sourcealias = (AliasModuleDecl)d;\n\n          if (sourcealias.Root != null) {\n            ((AliasModuleDecl)dd).Root = (ModuleDecl)CloneDeclaration(sourcealias.Root, m);\n          }\n        }\n      }\n      return dd;\n    }\n  }\n\n\n  class ScopeCloner : DeepModuleSignatureCloner {\n    private VisibilityScope scope = null;\n\n    private Dictionary<Declaration, Declaration> reverseMap = new Dictionary<Declaration, Declaration>();\n\n    private HashSet<AliasModuleDecl> extraProvides = new HashSet<AliasModuleDecl>();\n\n    private bool isInvisibleClone(Declaration d) {\n      Contract.Assert(reverseMap.ContainsKey(d));\n      return !reverseMap[d].IsVisibleInScope(scope);\n    }\n\n    public ScopeCloner(VisibilityScope scope) {\n      this.scope = scope;\n    }\n\n    private bool RevealedInScope(Declaration d) {\n      return d.IsRevealedInScope(scope);\n    }\n\n    private bool VisibleInScope(Declaration d) {\n      return d.IsVisibleInScope(scope);\n    }\n\n    public override ModuleDefinition CloneModuleDefinition(ModuleDefinition m, string name) {\n      var basem = base.CloneModuleDefinition(m, name);\n\n\n      //Merge signatures for imports which point to the same module\n      //This makes the consistency check understand that the same element\n      //may be referred to via different qualifications.\n      var sigmap = new Dictionary<ModuleDefinition, ModuleSignature>();\n      var declmap = new Dictionary<ModuleDefinition, List<AliasModuleDecl>>();\n      var vismap = new Dictionary<ModuleDefinition, VisibilityScope>();\n\n      foreach (var top in basem.TopLevelDecls) {\n        var import = reverseMap[top] as AliasModuleDecl;\n        if (import == null)\n          continue;\n\n        var def = import.Signature.ModuleDef;\n        if (!declmap.ContainsKey(def)) {\n          declmap.Add(def, new List<AliasModuleDecl>());\n          sigmap.Add(def, new ModuleSignature());\n          vismap.Add(def, new VisibilityScope());\n        }\n\n\n        sigmap[def] = Resolver.MergeSignature(sigmap[def], import.Signature);\n        sigmap[def].ModuleDef = def;\n        declmap[def].Add((AliasModuleDecl)top);\n        if (VisibleInScope(import)) {\n          vismap[def].Augment(import.Signature.VisibilityScope);\n        }\n\n      }\n\n      foreach (var decls in declmap) {\n        sigmap[decls.Key].VisibilityScope = vismap[decls.Key];\n        foreach (var decl in decls.Value) {\n          decl.Signature = sigmap[decls.Key];\n        }\n      }\n\n      basem.TopLevelDecls.RemoveAll(t => t is AliasModuleDecl ?\n        vismap[((AliasModuleDecl)t).Signature.ModuleDef].IsEmpty() : isInvisibleClone(t));\n\n      basem.TopLevelDecls.FindAll(t => t is ClassDecl).\n        ForEach(t => ((ClassDecl)t).Members.RemoveAll(isInvisibleClone));\n\n      return basem;\n    }\n\n    public override TopLevelDecl CloneDeclaration(TopLevelDecl d, ModuleDefinition m) {\n\n      var based = base.CloneDeclaration(d, m);\n\n      if (d is RevealableTypeDecl && !RevealedInScope(d)) {\n        var dd = (RevealableTypeDecl)d;\n        var tps = d.TypeArgs.ConvertAll(CloneTypeParam);\n        var characteristics = TypeParameter.GetExplicitCharacteristics(d);\n        based = new OpaqueTypeDecl(Tok(d.tok), d.Name, m, characteristics, tps, CloneAttributes(d.Attributes));\n      }\n\n      reverseMap.Add(based, d);\n\n      return based;\n\n    }\n\n    public override Field CloneField(Field f) {\n      var cf = f as ConstantField;\n      if (cf != null && cf.Rhs != null && !RevealedInScope(f)) {\n        // We erase the RHS value. While we do that, we must also make sure the declaration does have a type, so instead of\n        // cloning cf.Type, we assume \"f\" has been resolved and clone cf.Type.NormalizeExpandKeepConstraints().\n        return new ConstantField(Tok(cf.tok), cf.Name, null, cf.IsStatic, cf.IsGhost, CloneType(cf.Type.NormalizeExpandKeepConstraints()), CloneAttributes(cf.Attributes));\n      }\n      return base.CloneField(f);\n    }\n\n    public override Function CloneFunction(Function f, string newName = null) {\n      var basef = base.CloneFunction(f, newName);\n      if (!RevealedInScope(f)) {\n        basef.Body = null;\n      }\n      return basef;\n    }\n\n    public override Method CloneMethod(Method m) {\n      var basem = base.CloneMethod(m);\n      basem.Body = null; //exports never reveal method bodies\n      return basem;\n    }\n\n    public override MemberDecl CloneMember(MemberDecl member) {\n      var basem = base.CloneMember(member);\n      reverseMap.Add(basem, member);\n      return basem;\n    }\n\n  }\n\n  /// <summary>\n  /// This cloner is used during the creation of a module signature for a method facade.\n  /// It does not clone method bodies, and it copies module signatures.\n  /// </summary>\n  class ClonerButDropMethodBodies : DeepModuleSignatureCloner\n  {\n    public ClonerButDropMethodBodies()\n      : base() {\n    }\n\n    public override BlockStmt CloneBlockStmt(BlockStmt stmt) {\n      return null;\n    }\n  }\n\n  class AbstractSignatureCloner : ScopeCloner {\n\n    public AbstractSignatureCloner(VisibilityScope scope)\n      : base(scope) {\n    }\n\n    public override ModuleDefinition CloneModuleDefinition(ModuleDefinition m, string name) {\n      var basem = base.CloneModuleDefinition(m, name);\n      basem.TopLevelDecls.RemoveAll(t => t is ModuleExportDecl);\n      return basem;\n    }\n\n    public override BlockStmt CloneBlockStmt(BlockStmt stmt) {\n      return null;\n    }\n  }\n\n\n\n  /// <summary>\n  /// This cloner is used to clone a module into a _Compile module.  This is different from\n  /// the standard cloner in the following ways:\n  /// * \"match\" statements and \"match\" expressions obtain their original form, which may include\n  ///   nested patterns.  The resolver will turn these into nested \"match\" constructs with simple\n  ///   patterns.\n  /// * The various module-signature fields of modules are set to whatever they were in the original.\n  /// * To get the .RefinementBase, it redirects using the given mapping\n  /// </summary>\n  class CompilationCloner : DeepModuleSignatureCloner\n  {\n    Dictionary<ModuleDefinition, ModuleDefinition> compilationModuleClones;\n    public CompilationCloner(Dictionary<ModuleDefinition, ModuleDefinition> compilationModuleClones)\n      : base() {\n      this.compilationModuleClones = compilationModuleClones;\n    }\n\n\n\n    public override Expression CloneExpr(Expression expr) {\n      var me = expr as MatchExpr;\n      if (me != null && me.OrigUnresolved != null) {\n        return CloneExpr(me.OrigUnresolved);\n      }\n      return base.CloneExpr(expr);\n    }\n\n    public override Statement CloneStmt(Statement stmt) {\n      var s = stmt as MatchStmt;\n      if (s != null && s.OrigUnresolved != null) {\n        return CloneStmt(s.OrigUnresolved);\n      }\n      return base.CloneStmt(stmt);\n    }\n\n    public override ModuleDefinition GetRefinementBase(ModuleDefinition m) {\n      var rbase = m.RefinementBase;\n      ModuleDefinition r;\n      if (compilationModuleClones.TryGetValue(rbase, out r)) {\n        return r;\n      } else {\n        return rbase;\n      }\n    }\n\n    public ModuleSignature CloneModuleSignature(ModuleSignature org, ModuleSignature newSig) {\n      var sig = new ModuleSignature();\n      sig.ModuleDef = newSig.ModuleDef;\n      sig.IsAbstract = newSig.IsAbstract;\n      sig.VisibilityScope = new VisibilityScope();\n      sig.VisibilityScope.Augment(newSig.VisibilityScope);\n\n      foreach (var kv in org.TopLevels) {\n        TopLevelDecl d;\n        if (newSig.TopLevels.TryGetValue(kv.Key, out d)) {\n          sig.TopLevels.Add(kv.Key, d);\n        }\n      }\n\n      foreach (var kv in org.ExportSets) {\n        ModuleExportDecl d;\n        if (newSig.ExportSets.TryGetValue(kv.Key, out d)) {\n          sig.ExportSets.Add(kv.Key, d);\n        }\n      }\n\n      foreach (var kv in org.Ctors) {\n        Tuple<DatatypeCtor, bool> pair;\n        if (newSig.Ctors.TryGetValue(kv.Key, out pair)) {\n          sig.Ctors.Add(kv.Key, pair);\n        }\n      }\n\n      foreach (var kv in org.StaticMembers) {\n        MemberDecl md;\n        if (newSig.StaticMembers.TryGetValue(kv.Key, out md)) {\n          sig.StaticMembers.Add(kv.Key, md);\n        }\n      }\n      return sig;\n    }\n  }\n\n  /// <summary>\n  /// Subclass of Cloner that collects some common functionality between FixpointLemmaSpecificationSubstituter and\n  /// FixpointLemmaBodyCloner.\n  /// </summary>\n  abstract class FixpointCloner : Cloner\n  {\n    protected readonly Expression k;\n    protected readonly ErrorReporter reporter;\n    protected readonly string suffix;\n    protected FixpointCloner(Expression k, ErrorReporter reporter)\n    {\n      Contract.Requires(k != null);\n      Contract.Requires(reporter != null);\n      this.k = k;\n      this.reporter = reporter;\n      this.suffix = string.Format(\"#[{0}]\", Printer.ExprToString(k));\n    }\n    protected Expression CloneCallAndAddK(ApplySuffix e) {\n      Contract.Requires(e != null);\n      Contract.Requires(e.Resolved is FunctionCallExpr && ((FunctionCallExpr)e.Resolved).Function is FixpointPredicate);\n      Contract.Requires(e.Lhs is NameSegment || e.Lhs is ExprDotName);\n      Expression lhs;\n      string name;\n      var ns = e.Lhs as NameSegment;\n      if (ns != null) {\n        name = ns.Name;\n        lhs = new NameSegment(Tok(ns.tok), name + \"#\", ns.OptTypeArguments == null ? null : ns.OptTypeArguments.ConvertAll(CloneType));\n      } else {\n        var edn = (ExprDotName)e.Lhs;\n        name = edn.SuffixName;\n        lhs = new ExprDotName(Tok(edn.tok), CloneExpr(edn.Lhs), name + \"#\", edn.OptTypeArguments == null ? null : edn.OptTypeArguments.ConvertAll(CloneType));\n      }\n      var args = new List<Expression>();\n      args.Add(k);\n      foreach (var arg in e.Args) {\n        args.Add(CloneExpr(arg));\n      }\n      var apply = new ApplySuffix(Tok(e.tok), lhs, args);\n      reporter.Info(MessageSource.Cloner, e.tok, name + suffix);\n      return apply;\n    }\n    protected Expression CloneCallAndAddK(FunctionCallExpr e) {\n      Contract.Requires(e != null);\n      Contract.Requires(e.Function is FixpointPredicate);\n      var receiver = CloneExpr(e.Receiver);\n      var args = new List<Expression>();\n      args.Add(k);\n      foreach (var arg in e.Args) {\n        args.Add(CloneExpr(arg));\n      }\n      var fexp = new FunctionCallExpr(Tok(e.tok), e.Name + \"#\", receiver, e.OpenParen, args);\n      reporter.Info(MessageSource.Cloner, e.tok, e.Name + suffix);\n      return fexp;\n    }\n  }\n\n  /// <summary>\n  /// The FixpointLemmaSpecificationSubstituter clones the precondition (or postcondition) declared\n  /// on an inductive lemma (resp. colemma), but replaces the calls and equalities in \"coConclusions\"\n  /// with corresponding prefix versions.  The resulting expression is then appropriate to be a\n  /// precondition (resp. postcondition) of the inductive lemma's (resp. colemma's) corresponding prefix lemma.\n  /// It is assumed that the source expression has been resolved.  Note, the \"k\" given to the constructor\n  /// is not cloned with each use; it is simply used as is.\n  /// The resulting expression needs to be resolved by the caller.\n  /// </summary>\n  class FixpointLemmaSpecificationSubstituter : FixpointCloner\n  {\n    readonly bool isCoContext;\n    readonly ISet<Expression> friendlyCalls;\n    public FixpointLemmaSpecificationSubstituter(ISet<Expression> friendlyCalls, Expression k, ErrorReporter reporter, bool isCoContext)\n      : base(k, reporter)\n    {\n      Contract.Requires(friendlyCalls != null);\n      Contract.Requires(k != null);\n      Contract.Requires(reporter != null);\n      this.isCoContext = isCoContext;\n      this.friendlyCalls = friendlyCalls;\n    }\n    public override Expression CloneExpr(Expression expr) {\n      if (expr is NameSegment || expr is ExprDotName) {\n        // make sure to clone any user-supplied type-parameter instantiations\n        return base.CloneExpr(expr);\n      } else if (expr is ApplySuffix) {\n        var e = (ApplySuffix)expr;\n        var r = e.Resolved as FunctionCallExpr;\n        if (r != null && friendlyCalls.Contains(r)) {\n          return CloneCallAndAddK(e);\n        }\n      } else if (expr is SuffixExpr) {\n        // make sure to clone any user-supplied type-parameter instantiations\n        return base.CloneExpr(expr);\n      } else if (expr is ConcreteSyntaxExpression) {\n        var e = (ConcreteSyntaxExpression)expr;\n        // Note, the CoLemmaPostconditionSubstituter is an unusual cloner in that it operates on\n        // resolved expressions.  Hence, we bypass the syntactic parts here, except for the ones\n        // checked above.\n        return CloneExpr(e.Resolved);\n      } else if (expr is FunctionCallExpr) {\n        var e = (FunctionCallExpr)expr;\n        if (friendlyCalls.Contains(e)) {\n          return CloneCallAndAddK(e);\n        }\n      } else if (expr is BinaryExpr && isCoContext) {\n        var e = (BinaryExpr)expr;\n        if ((e.ResolvedOp == BinaryExpr.ResolvedOpcode.EqCommon || e.ResolvedOp == BinaryExpr.ResolvedOpcode.NeqCommon) && friendlyCalls.Contains(e)) {\n          var op = e.ResolvedOp == BinaryExpr.ResolvedOpcode.EqCommon ? TernaryExpr.Opcode.PrefixEqOp : TernaryExpr.Opcode.PrefixNeqOp;\n          var A = CloneExpr(e.E0);\n          var B = CloneExpr(e.E1);\n          var teq = new TernaryExpr(Tok(e.tok), op, k, A, B);\n          var opString = op == TernaryExpr.Opcode.PrefixEqOp ? \"==\" : \"!=\";\n          reporter.Info(MessageSource.Cloner, e.tok, opString + suffix);\n          return teq;\n        }\n      }\n      return base.CloneExpr(expr);\n    }\n    public override Type CloneType(Type t) {\n      if (t is UserDefinedType) {\n        var tt = (UserDefinedType)t;\n        // We want syntactic cloning of the Expression that is tt.NamePath, unlike the semantic (that is, post-resolved)\n        // cloning that CloneExpr is doing above.\n        return new UserDefinedType(Tok(tt.tok), CloneNamePathExpression(tt.NamePath));\n      } else {\n        return base.CloneType(t);\n      }\n    }\n    Expression CloneNamePathExpression(Expression expr) {\n      Contract.Requires(expr is NameSegment || expr is ExprDotName);\n      if (expr is NameSegment) {\n        var e = (NameSegment)expr;\n        return new NameSegment(Tok(e.tok), e.Name, e.OptTypeArguments == null ? null : e.OptTypeArguments.ConvertAll(CloneType));\n      } else {\n        var e = (ExprDotName)expr;\n        return new ExprDotName(Tok(e.tok), CloneNamePathExpression(e.Lhs), e.SuffixName, e.OptTypeArguments == null ? null : e.OptTypeArguments.ConvertAll(CloneType));\n      }\n    }\n  }\n\n  /// <summary>\n  /// The task of the FixpointLemmaBodyCloner is to fill in the implicit _k-1 arguments in recursive inductive/co-lemma calls\n  /// and in calls to the focal predicates.\n  /// The source statement and the given \"k\" are assumed to have been resolved.\n  /// </summary>\n  class FixpointLemmaBodyCloner : FixpointCloner\n  {\n    readonly FixpointLemma context;\n    readonly ISet<FixpointPredicate> focalPredicates;\n    public FixpointLemmaBodyCloner(FixpointLemma context, Expression k, ISet<FixpointPredicate> focalPredicates, ErrorReporter reporter)\n      : base(k, reporter)\n    {\n      Contract.Requires(context != null);\n      Contract.Requires(k != null);\n      Contract.Requires(reporter != null);\n      this.context = context;\n      this.focalPredicates = focalPredicates;\n    }\n    public override Expression CloneExpr(Expression expr) {\n      if (ArmadaOptions.O.RewriteFocalPredicates) {\n        if (expr is FunctionCallExpr) {\n          var e = (FunctionCallExpr)expr;\n#if DEBUG_PRINT\n          if (e.Function.Name.EndsWith(\"#\") && Contract.Exists(focalPredicates, p => e.Function.Name == p.Name + \"#\")) {\n            Console.WriteLine(\"{0}({1},{2}): DEBUG: Possible opportunity to rely on new rewrite: {3}\", e.tok.filename, e.tok.line, e.tok.col, Printer.ExprToString(e));\n          }\n#endif\n          // Note, we don't actually ever get here, because all calls will have been parsed as ApplySuffix.\n          // However, if something changes in the future (for example, some rewrite that changing an ApplySuffix\n          // to its resolved FunctionCallExpr), then we do want this code, so with the hope of preventing\n          // some error in the future, this case is included.  (Of course, it is currently completely untested!)\n          var f = e.Function as FixpointPredicate;\n          if (f != null && focalPredicates.Contains(f)) {\n#if DEBUG_PRINT\n            var r = CloneCallAndAddK(e);\n            Console.WriteLine(\"{0}({1},{2}): DEBUG: Rewrote extreme predicate into prefix predicate: {3}\", e.tok.filename, e.tok.line, e.tok.col, Printer.ExprToString(r));\n            return r;\n#else\n            return CloneCallAndAddK(e);\n#endif\n          }\n        } else if (expr is ApplySuffix) {\n          var apply = (ApplySuffix)expr;\n          if (!apply.WasResolved()) {\n            // Since we're assuming the enclosing statement to have been resolved, this ApplySuffix must\n            // be part of an ExprRhs that actually designates a method call.  Such an ApplySuffix does\n            // not get listed as being resolved, but its components (like its .Lhs) are resolved.\n            var mse = (MemberSelectExpr)apply.Lhs.Resolved;\n            Contract.Assume(mse.Member is Method);\n          } else {\n            var fce = apply.Resolved as FunctionCallExpr;\n            if (fce != null) {\n#if DEBUG_PRINT\n              if (fce.Function.Name.EndsWith(\"#\") && Contract.Exists(focalPredicates, p => fce.Function.Name == p.Name + \"#\")) {\n                Console.WriteLine(\"{0}({1},{2}): DEBUG: Possible opportunity to rely on new rewrite: {3}\", fce.tok.filename, fce.tok.line, fce.tok.col, Printer.ExprToString(fce));\n              }\n#endif\n              var f = fce.Function as FixpointPredicate;\n              if (f != null && focalPredicates.Contains(f)) {\n#if DEBUG_PRINT\n                var r = CloneCallAndAddK(fce);\n                Console.WriteLine(\"{0}({1},{2}): DEBUG: Rewrote extreme predicate into prefix predicate: {3}\", fce.tok.filename, fce.tok.line, fce.tok.col, Printer.ExprToString(r));\n                return r;\n#else\n                return CloneCallAndAddK(fce);\n#endif\n              }\n            }\n          }\n        }\n      }\n      return base.CloneExpr(expr);\n    }\n    public override AssignmentRhs CloneRHS(AssignmentRhs rhs) {\n      var r = rhs as ExprRhs;\n      if (r != null && r.Expr is ApplySuffix) {\n        var apply = (ApplySuffix)r.Expr;\n        var mse = apply.Lhs.Resolved as MemberSelectExpr;\n        if (mse != null && mse.Member is FixpointLemma && ModuleDefinition.InSameSCC(context, (FixpointLemma)mse.Member)) {\n          // we're looking at a recursive call to a fixpoint lemma\n          Contract.Assert(apply.Lhs is NameSegment || apply.Lhs is ExprDotName);  // this is the only way a call statement can have been parsed\n          // clone \"apply.Lhs\", changing the inductive/co lemma to the prefix lemma; then clone \"apply\", adding in the extra argument\n          Expression lhsClone;\n          if (apply.Lhs is NameSegment) {\n            var lhs = (NameSegment)apply.Lhs;\n            lhsClone = new NameSegment(Tok(lhs.tok), lhs.Name + \"#\", lhs.OptTypeArguments == null ? null : lhs.OptTypeArguments.ConvertAll(CloneType));\n          } else {\n            var lhs = (ExprDotName)apply.Lhs;\n            lhsClone = new ExprDotName(Tok(lhs.tok), CloneExpr(lhs.Lhs), lhs.SuffixName + \"#\", lhs.OptTypeArguments == null ? null : lhs.OptTypeArguments.ConvertAll(CloneType));\n          }\n          var args = new List<Expression>();\n          args.Add(k);\n          apply.Args.ForEach(arg => args.Add(CloneExpr(arg)));\n          var applyClone = new ApplySuffix(Tok(apply.tok), lhsClone, args);\n          var c = new ExprRhs(applyClone);\n          reporter.Info(MessageSource.Cloner, apply.Lhs.tok, mse.Member.Name + suffix);\n          return c;\n        }\n      }\n      return base.CloneRHS(rhs);\n    }\n  }\n\n\n  class ResolvedCloner : Cloner {\n\n    public override Type CloneType(Type t) {\n      Type new_t = base.CloneType(t);\n\n      if (t is UserDefinedType) {\n        var tt = (UserDefinedType)t;\n        var new_tt = (UserDefinedType)new_t;\n\n        new_tt.ResolvedClass = tt.ResolvedClass;\n        new_tt.ResolvedParam = tt.ResolvedParam;\n      }\n\n      return new_t;\n    }\n\n    public override CasePattern<VT> CloneCasePattern<VT>(CasePattern<VT> pat) {\n      if (pat.Var != null) {\n        var newPat = new CasePattern<VT>(pat.tok, CloneIVariable(pat.Var));\n        newPat.AssembleExpr(null);\n        return newPat;\n      } else {\n        var newArgs = pat.Arguments == null ? null : pat.Arguments.ConvertAll(CloneCasePattern);\n        var patE = (DatatypeValue)pat.Expr;\n        var newPat = new CasePattern<VT>(pat.tok, pat.Id, newArgs);\n        newPat.Ctor = pat.Ctor;\n        newPat.AssembleExpr(patE.InferredTypeArgs.ConvertAll(CloneType));\n        return newPat;\n      }\n    }\n\n    public override BoundVar CloneBoundVar(BoundVar bv) {\n      // The difference here from the overridden method is that we do CloneType(bv.Type) instead of CloneType(bv.SyntacticType)\n      var bvNew = new BoundVar(Tok(bv.tok), bv.Name, CloneType(bv.Type));\n      bvNew.IsGhost = bv.IsGhost;\n      return bvNew;\n    }\n  }\n\n}\n"
  },
  {
    "path": "Source/Armada/Combining.cs",
    "content": "using System;\nusing System.Numerics;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text;\nusing System.Text.RegularExpressions;\n\nnamespace Microsoft.Armada\n{\n  public class CombiningProofGenerator : AbstractProofGenerator\n  {\n    private CombiningStrategyDecl strategy;\n    private ArmadaPC startPC;\n    private ArmadaPC endPC;\n    private ArmadaPC singlePC;\n\n    public CombiningProofGenerator(ProofGenerationParams i_pgp, CombiningStrategyDecl i_strategy)\n      : base(i_pgp)\n    {\n      strategy = i_strategy;\n    }\n\n    public override void GenerateProof()\n    {\n      if (!CheckEquivalence()) {\n        AH.PrintError(pgp.prog, $\"Levels {pgp.mLow.Name} and {pgp.mHigh.Name} aren't sufficiently equivalent to perform refinement proof generation using the combining strategy\");\n        return;\n      }\n\n      if (!MakePCMap()) {\n        return;\n      }\n\n      AddIncludesAndImports();\n      GenerateProofGivenMap();\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    /// PC map\n    ////////////////////////////////////////////////////////////////////////\n\n    bool MakePCMap()\n    {\n      startPC = pgp.symbolsLow.GetPCForMethodAndLabel(strategy.StartLabel.val);\n      if (startPC == null) {\n        AH.PrintError(pgp.prog, $\"You specified a start label for combining of {strategy.StartLabel.val}, but that label doesn't exist in level {pgp.mLow.Name}.  Remember to prefix label names with the method name and an underscore, e.g., use main_lb1 if you have label lb1: in method main.\");\n        return false;\n      }\n\n      endPC = pgp.symbolsLow.GetPCForMethodAndLabel(strategy.EndLabel.val);\n      if (endPC == null) {\n        AH.PrintError(pgp.prog, $\"You specified an end label for combining of {strategy.EndLabel.val}, but that label doesn't exist in level {pgp.mLow.Name}.  Remember to prefix label names with the method name and an underscore, e.g., use main_lb1 if you have label lb1: in method main.\");\n        return false;\n      }\n\n      if (endPC.methodName != startPC.methodName) {\n        AH.PrintError(pgp.prog, $\"The start and end labels you provided for combining aren't from the same method in {pgp.mLow.Name}.  The start label {strategy.StartLabel.val} is in method {startPC.methodName} and the end label {strategy.EndLabel.val} is in method {endPC.methodName}.\");\n        return false;\n      }\n\n      if (endPC.instructionCount <= startPC.instructionCount) {\n        AH.PrintError(pgp.prog, $\"The end label you provided for combining ({strategy.EndLabel.val}) isn't after the start label you provided for combining ({strategy.StartLabel.val}).\");\n        return false;\n      }\n\n      singlePC = pgp.symbolsHigh.GetPCForMethodAndLabel(strategy.SingleLabel.val);\n      if (singlePC == null) {\n        AH.PrintError(pgp.prog, $\"You specified a single label for combining of {strategy.SingleLabel.val}, but that label doesn't exist in level {pgp.mHigh.Name}.  Remember to prefix label names with the method name and an underscore, e.g., use main_lb1 if you have label lb1: in method main.\");\n        return false;\n      }\n\n      if (singlePC.methodName != startPC.methodName) {\n        AH.PrintError(pgp.prog, $\"The start and end labels you provided for combining aren't from the same method as the single label you provided.  That is, {strategy.StartLabel.val} and {strategy.EndLabel.val} are both from method {startPC.methodName}, but the single label {strategy.SingleLabel.val} is from method {singlePC.methodName}.\");\n        return false;\n      }\n\n      if (singlePC.instructionCount != startPC.instructionCount) {\n        AH.PrintError(pgp.prog, $\"The start label you provided isn't at the same position in its method as the single label you provided.  That is, {strategy.StartLabel.val} is preceded by {startPC.instructionCount} instructions in {pgp.mLow.Name}, but {strategy.SingleLabel.val} is preceded by {singlePC.instructionCount} instructions in {pgp.mHigh.Name}.\");\n        return false;\n      }\n\n      pcMap = new Dictionary<ArmadaPC, ArmadaPC>();\n      var pcs = new List<ArmadaPC>();\n      pgp.symbolsLow.AllMethods.AppendAllPCs(pcs);\n      foreach (var pc in pcs)\n      {\n        if (pc.methodName != startPC.methodName) {\n          pcMap[pc] = pc.CloneWithNewSymbolTable(pgp.symbolsHigh);\n        }\n        else if (pc.instructionCount < startPC.instructionCount) {\n          pcMap[pc] = pc.CloneWithNewSymbolTable(pgp.symbolsHigh);\n        }\n        else if (pc.instructionCount == startPC.instructionCount) {\n          pcMap[pc] = singlePC;\n        }\n        else if (pc.instructionCount <= endPC.instructionCount) {\n          pcMap[pc] = new ArmadaPC(pgp.symbolsHigh, pc.methodName, singlePC.instructionCount + 1);\n        }\n        else {\n          pcMap[pc] = new ArmadaPC(pgp.symbolsHigh, pc.methodName, pc.instructionCount + startPC.instructionCount - endPC.instructionCount);\n        }\n      }\n\n      ExtendPCMapWithExternalAndStructsMethods();\n      GenerateNextRoutineMap(false);\n\n      return true;\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    /// Includes and imports\n    ////////////////////////////////////////////////////////////////////////\n\n    protected override void AddIncludesAndImports()\n    {\n      base.AddIncludesAndImports();\n\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/option.s.dfy\");\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/seqs.s.dfy\");\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/seqs.i.dfy\");\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/sets.i.dfy\");\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/maps.i.dfy\");\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/strategies/generic/GenericArmadaLemmas.i.dfy\");\n\n      pgp.MainProof.AddImport(\"InvariantsModule\");\n      pgp.MainProof.AddImport(\"GenericArmadaSpecModule\");\n      pgp.MainProof.AddImport(\"GenericArmadaLemmasModule\");\n      pgp.MainProof.AddImport(\"GeneralRefinementLemmasModule\");\n      pgp.MainProof.AddImport(\"util_option_s\");\n      pgp.MainProof.AddImport(\"util_collections_seqs_s\");\n      pgp.MainProof.AddImport(\"util_collections_seqs_i\");\n      pgp.MainProof.AddImport(\"util_collections_sets_i\");\n      pgp.MainProof.AddImport(\"util_collections_maps_i\");\n\n      pgp.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/strategies/generic/GenericArmadaLemmas.i.dfy\", \"invariants\");\n      pgp.AddImport(\"GenericArmadaLemmasModule\", null, \"invariants\");\n    }\n\n    private void GenerateProofGivenMap()\n    {\n      GenerateProofHeader();\n      GenerateAtomicSpecs(false);\n      GenerateStateAbstractionFunctions_LH();\n      GenerateConvertStep_LH();\n      GenerateConvertAtomicPath_LH();\n      GenerateGenericStoreBufferLemmas_L();\n\n      GeneratePCFunctions_L();\n      AddStackMatchesMethodInvariant();\n      GenerateInvariantProof(pgp);\n\n      GenerateLocalViewCommutativityLemmas();\n      GenerateLiftingRelation();\n      GenerateLiftAtomicPathLemmas();\n      GenerateEstablishInitRequirementsLemma();\n      GenerateEstablishStateOKRequirementLemma();\n      GenerateEstablishRelationRequirementLemma();\n      GenerateEstablishAtomicPathLiftableLemma();\n      GenerateEstablishAtomicPathsLiftableLemma(false, false);\n      GenerateLiftLAtomicToHAtomicLemma(false, false);\n      GenerateFinalProof();\n    }\n  }\n}\n"
  },
  {
    "path": "Source/Armada/Compiler-clight.cs",
    "content": "//-----------------------------------------------------------------------------\n//\n// Copyright (C) Amazon.  All Rights Reserved.\n//\n//-----------------------------------------------------------------------------\nusing System;\nusing System.CodeDom;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Numerics;\nusing System.IO;\nusing System.Diagnostics.Contracts;\nusing System.Collections.ObjectModel;\nusing System.Diagnostics;\nusing System.Reflection;\nusing System.Security.Principal;\nusing Bpl = Microsoft.Boogie;\n\nnamespace Microsoft.Armada {\n  public class ClightTsoCompiler : Compiler {\n    public ClightTsoCompiler(ErrorReporter reporter, ReadOnlyCollection<string> otherHeaders)\n    : base(reporter) {\n      this.headers = otherHeaders;\n      this.datatypeDecls = new List<DatatypeDecl>();\n      this.armadaMethodParams = new Dictionary<string, List<string>>();\n    }\n\n    private ReadOnlyCollection<string> headers;\n    private List<DatatypeDecl> datatypeDecls;\n\n    private Dictionary<string, List<string>> armadaMethodParams;\n\n    // Shadowing variables in Compiler.cs\n    //new string DafnySetClass = \"DafnySet\";\n    //new string DafnyMultiSetClass = \"DafnyMultiset\";\n    //new string DafnySeqClass = \"DafnySequence\";\n    //new string DafnyMapClass = \"DafnyMap\";\n\n    public override string TargetLanguage => \"ClightTSO\";\n\n    protected override void EmitHeader(Program program, TargetWriter wr) {\n      wr.WriteLine(\"// Dafny program {0} compiled into ClightTSO\", program.Name);\n      wr.WriteLine(\"#include \\\"DafnyRuntime.h\\\"\");\n      foreach (var header in this.headers) {\n        wr.WriteLine(\"#include \\\"{0}\\\"\", header);\n      }\n      // TODO: Include appropriate .h file here\n      //ReadRuntimeSystem(\"DafnyRuntime.h\", wr);\n    }\n\n    protected override void EmitFooter(Program program, TargetWriter wr) {\n      /*foreach (var dt in this.datatypeDecls) {\n        var wd = wr.NewBlock(String.Format(\"{0} {1}::{2}{3} get_default({1}::{2}{3}* ignored)\",\n          DeclareTemplate(dt.TypeArgs),\n          dt.Module.CompileName,\n          dt.CompileName,\n          TemplateMethod(dt.TypeArgs)));\n          wd.WriteLine(\"return {0}::{1}{2}();\", dt.Module.CompileName, dt.CompileName, TemplateMethod(dt.TypeArgs));\n      }*/\n    }\n\n    public override void EmitCallToMain(Method mainMethod, TargetWriter wr) {\n      var w = wr.NewBlock(\"int main()\");\n      w.WriteLine(\"_main();\");\n    }\n\n    protected override BlockTargetWriter CreateStaticMain(IClassWriter cw) {\n      var wr = (cw as ClightTsoCompiler.ClassWriter).MethodWriter;\n      return wr.NewBlock(\"int main()\");\n    }\n\n    protected override TargetWriter CreateModule(string moduleName, bool isDefault, bool isExtern, string/*?*/ libraryName, TargetWriter wr)\n    {\n\n      var s = string.Format(\"// namespace {0} \", IdProtect(moduleName));\n      wr.WriteLine(s);\n      return wr;\n    }\n\n\n\n    private string TypeParameters(List<TypeParameter> targs) {\n      Contract.Requires(cce.NonNullElements(targs));\n      Contract.Ensures(Contract.Result<string>() != null);\n\n      return Util.Comma(targs, tp => \"typename \" + IdName(tp));\n    }\n\n    private string DeclareTemplate(List<TypeParameter> typeArgs) {\n      var targs = \"\";\n      if (typeArgs.Count > 0) {\n        targs = String.Format(\"template <{0}>\", TypeParameters(typeArgs));\n      }\n      return targs;\n    }\n\n    private string DeclareTemplate(List<Type> typeArgs) {\n      var targs = \"\";\n      if (typeArgs.Count > 0) {\n        targs = String.Format(\"template <{0}>\", Util.Comma(typeArgs, t => \"typename \" + TypeName(t, null, null)));\n      }\n      return targs;\n    }\n\n    private string TemplateMethod(List<TypeParameter> typeArgs) {\n      var targs = \"\";\n      if (typeArgs.Count > 0) {\n        targs = String.Format(\"<{0}>\", Util.Comma(typeArgs, ta => ta.CompileName));\n      }\n      return targs;\n    }\n\n    private string TemplateMethod(List<Type> typeArgs) {\n      var targs = \"\";\n      if (typeArgs.Count > 0) {\n        targs = String.Format(\"<{0}>\", Util.Comma(typeArgs, ta => TypeName(ta, null, null)));\n      }\n      return targs;\n    }\n\n    protected override string GetHelperModuleName() => \"_dafny\";\n\n    protected Exception NotSupported(String msg) {\n      return new Exception(String.Format(\"{0} is not yet supported\", msg));\n    }\n\n    protected Exception NotSupported(String msg, Bpl.IToken tok) {\n      return new Exception(String.Format(\"{0} is not yet supported (at {1}:{2}:{3})\", msg, tok.filename, tok.line, tok.col));\n    }\n\n\n    protected override IClassWriter CreateClass(string name, bool isExtern, string/*?*/ fullPrintName, List<TypeParameter>/*?*/ typeParameters, List<Type>/*?*/ superClasses, Bpl.IToken tok, TargetWriter wr) {\n      if (isExtern || (superClasses != null && superClasses.Count > 0)) {\n        throw NotSupported(String.Format(\"extern and/or traits in class {0}\", name), tok);\n      }\n\n      if (typeParameters != null && typeParameters.Count > 0) {\n        wr.WriteLine(DeclareTemplate(typeParameters));\n      }\n\n      var w = wr.NewBlock(string.Format(\"struct {0}\", name), \";\");\n\n      //w.Write(\"// Constructor\\n\");\n      //w2.Write(string.Format(\"{0}(\", name));\n      //var fieldWriter = w.NewBlock(\")\");\n      var fieldWriter = w;\n      /*\n      if (fullPrintName != null) {\n        fieldWriter.WriteLine(\"this._tname = \\\"{0}\\\";\", fullPrintName);\n      }\n      */\n      var methodWriter = w;\n      return new ClassWriter(name, this, methodWriter, fieldWriter, wr);\n    }\n\n    protected override bool SupportsProperties { get => false; }\n\n    protected override IClassWriter CreateTrait(string name, bool isExtern, List<Type>/*?*/ superClasses, Bpl.IToken tok, TargetWriter wr) {\n      throw NotSupported(String.Format(\"traits in class {0}\", name), tok);\n      /*\n      var w = wr.NewBlock(string.Format(\"$module.{0} = class {0}\", IdProtect(name)), \";\");\n      var fieldWriter = w.NewBlock(\"constructor ()\");\n      var methodWriter = w;\n      return new ClassWriter(this, methodWriter, fieldWriter);\n      */\n    }\n\n    protected override BlockTargetWriter CreateIterator(IteratorDecl iter, TargetWriter wr) {\n      // An iterator is compiled as follows:\n      //   public class MyIteratorExample\n      //   {\n      //     public T q;  // in-parameter\n      //     public T x;  // yield-parameter\n      //     public int y;  // yield-parameter\n      //     IEnumerator<object> _iter;\n      //\n      //     public void _MyIteratorExample(T q) {\n      //       this.q = q;\n      //       _iter = TheIterator();\n      //     }\n      //\n      //     public void MoveNext(out bool more) {\n      //       more =_iter.MoveNext();\n      //     }\n      //\n      //     private IEnumerator<object> TheIterator() {\n      //       // the translation of the body of the iterator, with each \"yield\" turning into a \"yield return null;\"\n      //       yield break;\n      //     }\n      //   }\n      throw NotSupported(String.Format(\"iterator {0}\", iter));\n\n     /*  var cw = CreateClass(IdName(iter), iter.TypeArgs, wr) as ClightTsoCompiler.ClassWriter;\n      var w = cw.MethodWriter;\n      var instanceFieldsWriter = cw.FieldWriter;\n      // here come the fields\n      Constructor ct = null;\n      foreach (var member in iter.Members) {\n        var f = member as Field;\n        if (f != null && !f.IsGhost) {\n          DeclareField(IdName(f), false, false, f.Type, f.tok, DefaultValue(f.Type, instanceFieldsWriter, f.tok), instanceFieldsWriter);\n        } else if (member is Constructor) {\n          Contract.Assert(ct == null);  // we're expecting just one constructor\n          ct = (Constructor)member;\n        }\n      }\n      Contract.Assert(ct != null);  // we do expect a constructor\n      instanceFieldsWriter.WriteLine(\"this._iter = undefined;\");\n\n      // here's the initializer method\n      w.Write(\"{0}(\", IdName(ct));\n      string sep = \"\";\n      foreach (var p in ct.Ins) {\n        if (!p.IsGhost) {\n          // here we rely on the parameters and the corresponding fields having the same names\n          w.Write(\"{0}{1}\", sep, IdName(p));\n          sep = \", \";\n        }\n      }\n      using (var wBody = w.NewBlock(\")\")) {\n        foreach (var p in ct.Ins) {\n          if (!p.IsGhost) {\n            wBody.WriteLine(\"this.{0} = {0};\", IdName(p));\n          }\n        }\n        wBody.WriteLine(\"this.__iter = this.TheIterator();\");\n      }\n      // here are the enumerator methods\n      using (var wBody = w.NewBlock(\"MoveNext()\")) {\n        wBody.WriteLine(\"let r = this.__iter.next();\");\n        wBody.WriteLine(\"return !r.done;\");\n      }\n      var wIter = w.NewBlock(\"*TheIterator()\");\n      wIter.WriteLine(\"let _this = this;\");\n      return wIter; */\n    }\n\n    protected override IClassWriter DeclareDatatype(DatatypeDecl dt, TargetWriter wr) {\n\n      throw NotSupported(\"DeclareDatatype\");\n      // Given:\n      // datatype Example1 = Example1(u:uint32, b:bool)\n      // datatype Example2 = Ex2a(u:uint32) | Ex2b(b:bool)\n      //\n      // Produce:\n      // struct Example1 {\n      //   uint32 u;\n      //   bool b;\n      //   Example1(uint32 u, bool b) : u (u), b (b) {}\n      // };\n      // bool is_Example1(struct Example1 d) { return true; }\n      //\n      // struct Example2_2a {\n      //   uint32 u;\n      // };\n      //\n      // struct Example2_2b {\n      //   bool b;\n      // };\n      //\n      // struct Example2 {\n      //   enum {TAG_2a, TAG_2b} tag;\n      //   union {\n      //     struct Example2_2a v2a;\n      //     struct Example2_2b v2b;\n      //   };\n      //   static Example2 create_Ex2a(uint32 u) {\n      //      Example2 result;\n      //      result.tag = TAG_Ex2a;\n      //      result.v_Ex2a.u = u;\n      //      return result;\n      //    }\n      //    bool is_Example2_2a() { return tag == Example2::TAG_2a; }\n      //    bool is_Example2_2b() { return tag == Example2::TAG_2b; }\n      // };\n      // bool is_Example2_2a(struct Example2 d) { return d.tag == Example2::TAG_2a; }\n      // bool is_Example2_2b(struct Example2 d) { return d.tag == Example2::TAG_2b; }\n/*\n      if (dt is TupleTypeDecl) {\n        // Tuple types are declared once and for all in DafnyRuntime.h\n        return;\n      }\n\n      this.datatypeDecls.Add(dt);\n\n      string DtT = dt.CompileName;\n      string DtT_protected = IdProtect(DtT);\n\n      // Optimize a not-uncommon case\n      if (dt.Ctors.Count == 1) {\n        var ctor = dt.Ctors[0];\n        var ws = wr.NewBlock(String.Format(\"{0}\\nstruct {1}\", DeclareTemplate(dt.TypeArgs), DtT_protected), \";\");\n\n        // Declare the struct members\n        var i = 0;\n        var argNames = new List<string>();\n        foreach (Formal arg in ctor.Formals) {\n          if (!arg.IsGhost) {\n            ws.WriteLine(\"{0} {1};\", TypeName(arg.Type, wr, arg.tok), FormalName(arg, i));\n            argNames.Add(FormalName(arg, i));\n            i++;\n          }\n        }\n\n        if (argNames.Count > 0) {\n          // Create a constructor with arguments\n          ws.Write(\"{0}(\", DtT_protected);\n          WriteFormals(\"\", ctor.Formals, ws);\n          ws.Write(\")\");\n          if (argNames.Count > 0) {\n            // Add initializers\n            ws.Write(\" :\");\n            ws.Write(Util.Comma(argNames, nm => String.Format(\" {0} ({0})\", IdProtect(nm))));\n          }\n\n          ws.WriteLine(\" {}\");\n        }\n\n        // Create a constructor with no arguments\n        var wc = ws.NewNamedBlock(\"{0}()\", DtT_protected);\n        foreach (var arg in ctor.Formals) {\n          wc.WriteLine(\"{0} = {1};\", arg.CompileName, DefaultValue(arg.Type, wc, arg.tok));\n        }\n\n        // Overload the comparison operator\n        ws.WriteLine(\"friend bool operator==(const {0} &left, const {0} &right) {{ \", DtT_protected);\n        ws.Write(\"\\treturn true \");\n        foreach (var arg in argNames) {\n            ws.WriteLine(\"\\t\\t&& left.{0} == right.{0}\", arg);\n        }\n        ws.WriteLine(\";\\n}\");\n\n        // Overload the not-comparison operator\n        ws.WriteLine(\"friend bool operator!=(const {0} &left, const {0} &right) {{ return !(left == right); }} \", DtT_protected);\n\n        wr.WriteLine(\"{0}\\nbool is_{1}(const struct {2}{3} d) {{ return true; }}\", DeclareTemplate(dt.TypeArgs), ctor.CompileName, DtT_protected, TemplateMethod(dt.TypeArgs));\n      } else {\n\n        // Create one struct for each constructor\n        foreach (var ctor in dt.Ctors) {\n          string structName = string.Format(\"{0}_{1}\", DtT_protected, ctor.CompileName);\n          var wstruct = wr.NewBlock(String.Format(\"{0}\\nstruct {1}\", DeclareTemplate(dt.TypeArgs), structName), \";\");\n          // Declare the struct members\n          var i = 0;\n          var argNames = new List<string>();\n          foreach (Formal arg in ctor.Formals) {\n            if (!arg.IsGhost) {\n              wstruct.WriteLine(\"{0} {1};\", TypeName(arg.Type, wr, arg.tok), FormalName(arg, i));\n              argNames.Add(FormalName(arg, i));\n              i++;\n            }\n          }\n\n          // Overload the comparison operator\n          wstruct.WriteLine(\"friend bool operator==(const {0} &left, const {0} &right) {{ \", structName);\n          wstruct.Write(\"\\treturn true \");\n          foreach (var arg in argNames) {\n            wstruct.WriteLine(\"\\t\\t&& left.{0} == right.{0}\", arg);\n          }\n          wstruct.WriteLine(\";\\n}\");\n\n          // Overload the not-comparison operator\n          wstruct.WriteLine(\"friend bool operator!=(const {0} &left, const {0} &right) {{ return !(left == right); }} \", structName);\n        }\n\n        // Declare the overall tagged union\n        var ws = wr.NewBlock(String.Format(\"{0}\\nstruct {1}\", DeclareTemplate(dt.TypeArgs), DtT_protected), \";\");\n        ws.Write(\"enum {\");\n        ws.Write(Util.Comma(dt.Ctors, nm => String.Format(\" TAG_{0}\", nm.CompileName)));\n        ws.Write(\"} tag;\\n\");\n        var wu = ws.NewBlock(\"union \", \";\");\n        foreach (var ctor in dt.Ctors) {\n          wu.WriteLine(\"struct {2}_{0}{1} v_{0};\", ctor.CompileName, TemplateMethod(dt.TypeArgs), DtT_protected);\n        }\n\n        // Declare static \"constructors\" for each Dafny constructor\n        foreach (var ctor in dt.Ctors)\n        {\n          var argNames = new List<string>();\n          foreach (Formal arg in ctor.Formals)\n          {\n            if (!arg.IsGhost)\n            {\n              argNames.Add(arg.CompileName);\n            }\n          }\n\n          using (var wc = ws.NewNamedBlock(\"static {0} create_{1}({2})\",\n                                           DtT_protected, ctor.CompileName,\n                                           DeclareFormals(ctor.Formals))) {\n            wc.WriteLine(\"{0}{1} result;\", DtT_protected, TemplateMethod(dt.TypeArgs));\n            wc.WriteLine(\"result.tag = {0}::TAG_{1};\", DtT_protected, ctor.CompileName);\n            foreach (Formal arg in ctor.Formals)\n            {\n              wc.WriteLine(\"result.v_{0}.{1} = {1};\", ctor.CompileName, arg.CompileName);\n            }\n            wc.WriteLine(\"return result;\");\n          }\n        }\n\n        // Declare a default constructor\n        using (var wd = ws.NewNamedBlock(String.Format(\"{0}()\", DtT_protected))) {\n          var default_ctor = dt.Ctors[0];   // Arbitrarily choose the first one\n          wd.WriteLine(\"tag = {0}::TAG_{1};\", DtT_protected, default_ctor.CompileName);\n          foreach (Formal arg in default_ctor.Formals)\n          {\n            wd.WriteLine(\"v_{0}.{1} = {2};\", default_ctor.CompileName, arg.CompileName, DefaultValue(arg.Type, wd, arg.tok));\n          }\n        }\n\n        // Declare a default destructor\n        ws.WriteLine(\"~{0}() {{}}\", DtT_protected);\n\n        // Declare a default copy constructor (just in case any of our components are non-trivial, i.e., contain smart_ptr)\n        using (var wcc = ws.NewNamedBlock(String.Format(\"{0}(const {0} &other)\", DtT_protected))) {\n          wcc.WriteLine(\"tag = other.tag;\");\n          foreach (var ctor in dt.Ctors) {\n            wcc.WriteLine(\"if (tag == {0}::TAG_{1}) {{ v_{1} = other.v_{1}; }}\", DtT_protected, ctor.CompileName);\n          }\n        }\n\n        // Declare a default copy assignment operator (just in case any of our components are non-trivial, i.e., contain smart_ptr)\n        using (var wcc = ws.NewNamedBlock(String.Format(\"{0}& operator=(const {0} other)\", DtT_protected))) {\n          wcc.WriteLine(\"tag = other.tag;\");\n          foreach (var ctor in dt.Ctors) {\n            wcc.WriteLine(\"if (tag == {0}::TAG_{1}) {{ v_{1} = other.v_{1}; }}\", DtT_protected, ctor.CompileName);\n          }\n          wcc.WriteLine(\"return *this;\");\n        }\n\n        // Declare type queries, both as members and general-purpose functions\n        foreach (var ctor in dt.Ctors) {\n          ws.WriteLine(\"bool is_{0}() const {{ return tag == {1}{2}::TAG_{0}; }}\", ctor.CompileName, DtT_protected, TemplateMethod(dt.TypeArgs));\n          wr.WriteLine(\"{0}\\nbool is_{1}(const struct {2}{3} d) {{ return d.tag == {2}{3}::TAG_{1}; }}\", DeclareTemplate(dt.TypeArgs), ctor.CompileName, DtT_protected, TemplateMethod(dt.TypeArgs));\n        }\n\n        // Overload the comparison operator\n        ws.WriteLine(\"friend bool operator==(const {0} &left, const {0} &right) {{ \", DtT_protected);\n        ws.Write(\"\\treturn false\");\n        foreach (var ctor in dt.Ctors) {\n          ws.WriteLine(\"\\t\\t|| (left.is_{0}() && right.is_{0}() && left.v_{0} == right.v_{0})\", ctor.CompileName);\n        }\n        ws.WriteLine(\";\\n}\");\n\n        // Overload the not-comparison operator\n        ws.WriteLine(\"friend bool operator!=(const {0} &left, const {0} &right) {{ return !(left == right); }} \", DtT_protected);\n\n      }\n      */\n    }\n\n    protected override IClassWriter DeclareNewtype(NewtypeDecl nt, TargetWriter wr)\n    {\n      throw NotSupported(\"DeclareNewtype\");\n//      if (nt.NativeType != null) {\n//        if (nt.NativeType.Name != nt.Name) {\n//          string nt_name_def, literalSuffice_def;\n//          bool needsCastAfterArithmetic_def;\n//          GetNativeInfo(nt.NativeType.Sel, out nt_name_def, out literalSuffice_def, out needsCastAfterArithmetic_def);\n//          wr.WriteLine(\"typedef {0} {1};\", nt_name_def, nt.Name);\n//        }\n//        /*\n//        var wIntegerRangeBody = w.NewBlock(\"static *IntegerRange(lo, hi)\");\n//        var wLoopBody = wIntegerRangeBody.NewBlock(\"while (lo.isLessThan(hi))\");\n//        wLoopBody.WriteLine(\"yield lo.toNumber();\");\n//        EmitIncrementVar(\"lo\", wLoopBody);\n//        */\n//      } else {\n//        throw NotSupported(String.Format(\"non-native newtype {0}\", nt));\n//      }\n//      var className = \"class_\" + IdName(nt);\n//      var cw = CreateClass(className, null, wr) as ClightTsoCompiler.ClassWriter;\n//      var w = cw.MethodWriter;\n//      if (nt.WitnessKind == SubsetTypeDecl.WKind.Compiled) {\n//        var witness = new TargetWriter(w.IndentLevel, true);\n//        if (nt.NativeType == null) {\n//          TrExpr(nt.Witness, witness, false);\n//        } else {\n//          TrParenExpr(nt.Witness, witness, false);\n//          witness.Write(\".toNumber()\");\n//        }\n//\n//        DeclareField(className, nt.TypeArgs, \"Witness\", true, true, nt.BaseType, nt.tok, witness.ToString(), w, wr);\n//      }\n//\n//      string nt_name, literalSuffice;\n//      bool needsCastAfterArithmetic;\n//      GetNativeInfo(nt.NativeType.Sel, out nt_name, out literalSuffice, out needsCastAfterArithmetic);\n//      using (var wDefault = w.NewBlock(string.Format(\"static {0} get_Default()\", nt_name))) {\n//        var udt = new UserDefinedType(nt.tok, nt.Name, nt, new List<Type>());\n//        var d = TypeInitializationValue(udt, wr, nt.tok, false);\n//        wDefault.WriteLine(\"return {0};\", d);\n//      }\n//      // TODO(xueyuanz): make it compile, probably not correct.\n//      return cw;\n    }\n\n    protected override void DeclareSubsetType(SubsetTypeDecl sst, TargetWriter wr)\n    {\n      throw NotSupported(\"DeclareSubsetType\");\n      /*if (sst.Name == \"nat\") {\n        return;  // C++ does not support Nats\n      }\n\n      string templateDecl = \"\";\n      if (sst.Var.Type is SeqType s) {\n        templateDecl = DeclareTemplate(s.TypeArgs[0].TypeArgs);  // We want the type args (if any) for the seq-elt type, not the seq\n      } else {\n        templateDecl = DeclareTemplate(sst.Var.Type.TypeArgs);\n      }\n      wr.WriteLine(\"{2} using {1} = {0};\", TypeName(sst.Var.Type, wr, sst.tok), IdName(sst), templateDecl);\n\n      var className = \"class_\" + IdName(sst);\n      var cw = CreateClass(className, sst.TypeArgs, wr) as ClightTsoCompiler.ClassWriter;\n      var w = cw.MethodWriter;\n      if (sst.WitnessKind == SubsetTypeDecl.WKind.Compiled) {\n        var witness = new TargetWriter(w.IndentLevel, true);\n        TrExpr(sst.Witness, witness, false);\n        DeclareField(className, sst.TypeArgs, \"Witness\", true, true, sst.Rhs, sst.tok, witness.ToString(), w, wr);\n      }\n\n      using (var wDefault = w.NewBlock(String.Format(\"static {0}{1} get_Default()\", IdName(sst), TemplateMethod(sst.TypeArgs)))) {\n        var udt = new UserDefinedType(sst.tok, sst.Name, sst, sst.TypeArgs.ConvertAll(tp => (Type)new UserDefinedType(tp)));\n        var d = TypeInitializationValue(udt, wr, sst.tok, false);\n        wDefault.WriteLine(\"return {0};\", d);\n      }*/\n\n    }\n\n    protected override void GetNativeInfo(NativeType.Selection sel, out string name, out string literalSuffix, out bool needsCastAfterArithmetic) {\n      literalSuffix = \"\";\n      needsCastAfterArithmetic = false;\n      switch (sel) {\n        case NativeType.Selection.Byte:\n          name = \"uint8\";\n          break;\n        case NativeType.Selection.SByte:\n          name = \"int8\";\n          break;\n        case NativeType.Selection.UShort:\n          name = \"uint16\";\n          break;\n        case NativeType.Selection.Short:\n          name = \"int16\";\n          break;\n        case NativeType.Selection.UInt:\n          name = \"uint32\";\n          break;\n        case NativeType.Selection.Int:\n          name = \"int32\";\n          break;\n        case NativeType.Selection.ULong:\n          name = \"uint64\";\n          break;\n        case NativeType.Selection.Number:\n        case NativeType.Selection.Long:\n          name = \"int64\";\n          break;\n        default:\n          Contract.Assert(false);  // unexpected native type\n          throw new cce.UnreachableException();  // to please the compiler\n      }\n    }\n\n    protected class ClassWriter : IClassWriter {\n      public string ClassName;\n      public readonly ClightTsoCompiler Compiler;\n      public readonly BlockTargetWriter MethodWriter;\n      public readonly BlockTargetWriter FieldWriter;\n      public readonly TargetWriter Finisher;\n\n      public ClassWriter(string className, ClightTsoCompiler compiler, BlockTargetWriter methodWriter, BlockTargetWriter fieldWriter, TargetWriter finisher) {\n        Contract.Requires(compiler != null);\n        Contract.Requires(methodWriter != null);\n        Contract.Requires(fieldWriter != null);\n        this.ClassName = className;\n        this.Compiler = compiler;\n        this.MethodWriter = methodWriter;\n        this.FieldWriter = fieldWriter;\n        this.Finisher = finisher;\n      }\n\n      public BlockTargetWriter/*?*/ CreateMethod(Method m, bool createBody) {\n        return Compiler.CreateMethod(m, createBody, MethodWriter);\n      }\n      public BlockTargetWriter/*?*/ CreateFunction(string name, List<TypeParameter>/*?*/ typeArgs, List<Formal> formals, Type resultType, Bpl.IToken tok, bool isStatic, bool createBody, MemberDecl member) {\n        return Compiler.CreateFunction(name, typeArgs, formals, resultType, tok, isStatic, createBody, MethodWriter);\n      }\n      public BlockTargetWriter/*?*/ CreateGetter(string name, Type resultType, Bpl.IToken tok, bool isStatic, bool createBody, MemberDecl/*?*/ member) {\n        return Compiler.CreateGetter(name, resultType, tok, isStatic, createBody, MethodWriter);\n      }\n      public BlockTargetWriter/*?*/ CreateGetterSetter(string name, Type resultType, Bpl.IToken tok, bool isStatic, bool createBody, MemberDecl/*?*/ member, out TargetWriter setterWriter) {\n        return Compiler.CreateGetterSetter(name, resultType, tok, isStatic, createBody, out setterWriter, MethodWriter);\n      }\n      public void DeclareField(string name, List<TypeParameter> targs, bool isStatic, bool isConst, Type type, Bpl.IToken tok, string rhs) {\n        Compiler.DeclareField(ClassName, targs, name, isStatic, isConst, type, tok, rhs, FieldWriter, Finisher);\n      }\n      public TextWriter/*?*/ ErrorWriter() => MethodWriter;\n      public void Finish() { }\n    }\n\n    protected BlockTargetWriter/*?*/ CreateMethod(Method m, bool createBody, TargetWriter wr) {\n      string targetReturnTypeReplacement = null;\n      foreach (var p in m.Outs) {\n        if (!p.IsGhost) {\n          if (targetReturnTypeReplacement == null) {\n            targetReturnTypeReplacement = TypeName(p.Type, wr, p.tok);\n          } else if (targetReturnTypeReplacement != null) {\n            // there's more than one out-parameter, so bail\n            targetReturnTypeReplacement = null;\n            break;\n          }\n        }\n      }\n\n      if (!createBody) {\n        return null;\n      }\n\n      if (m.TypeArgs.Count != 0) {\n        wr.WriteLine(DeclareTemplate(m.TypeArgs));\n      }\n\n      wr.Write(\"{0}{1} {2}\",\n      m.IsStatic ? \"static \" : \"\",\n      targetReturnTypeReplacement ?? \"void\",\n      IdName(m));\n\n      wr.Write(\"(\");\n      int nIns = WriteFormals(\"\", m.Ins, wr);\n      if (targetReturnTypeReplacement == null) {\n        WriteFormals(nIns == 0 ? \"\" : \", \", m.Outs, wr);\n      }\n\n      var w = wr.NewBlock(\")\", null, BlockTargetWriter.BraceStyle.Newline, BlockTargetWriter.BraceStyle.Newline);\n\n      if (targetReturnTypeReplacement != null) {\n        var r = new TargetWriter(w.IndentLevel);\n        EmitReturn(m.Outs, r);\n        w.BodySuffix = r.ToString();\n      }\n      return w;\n    }\n\n    protected BlockTargetWriter/*?*/ CreateFunction(string name, List<TypeParameter>/*?*/ typeArgs, List<Formal> formals, Type resultType, Bpl.IToken tok, bool isStatic, bool createBody, TargetWriter wr) {\n      wr.Write(\"{0}{1} {2}\", isStatic ? \"static \" : \"\", TypeName(resultType, wr, tok), name);\n      if (typeArgs != null && typeArgs.Count != 0) {\n        throw NotSupported(String.Format(\"type parameters in function {0}\", name), tok);\n        //wr.Write(\"<{0}>\", TypeParameters(typeArgs));\n      }\n      wr.Write(\"(\");\n      WriteFormals(\"\", formals, wr);\n      if (!createBody) {\n        wr.WriteLine(\");\");\n        return null;\n      } else {\n        if (formals.Count > 1) {\n          var w = wr.NewBlock(\")\", null, BlockTargetWriter.BraceStyle.Newline, BlockTargetWriter.BraceStyle.Newline);\n          return w;\n        } else {\n          var w = wr.NewBlock(\")\");\n          return w;\n        }\n      }\n    }\n\n    new List<TypeParameter> UsedTypeParameters(DatatypeDecl dt) {\n      Contract.Requires(dt != null);\n\n      var idt = dt as IndDatatypeDecl;\n      if (idt == null) {\n        return dt.TypeArgs;\n      } else {\n        Contract.Assert(idt.TypeArgs.Count == idt.TypeParametersUsedInConstructionByDefaultCtor.Length);\n        var tps = new List<TypeParameter>();\n        for (int i = 0; i < idt.TypeArgs.Count; i++) {\n          if (idt.TypeParametersUsedInConstructionByDefaultCtor[i]) {\n            tps.Add(idt.TypeArgs[i]);\n          }\n        }\n        return tps;\n      }\n    }\n\n    List<Type> UsedTypeParameters(DatatypeDecl dt, List<Type> typeArgs) {\n      Contract.Requires(dt != null);\n      Contract.Requires(typeArgs != null);\n      Contract.Requires(dt.TypeArgs.Count == typeArgs.Count);\n\n      var idt = dt as IndDatatypeDecl;\n      if (idt == null) {\n        return typeArgs;\n      } else {\n        Contract.Assert(typeArgs.Count == idt.TypeParametersUsedInConstructionByDefaultCtor.Length);\n        var ts = new List<Type>();\n        for (int i = 0; i < typeArgs.Count; i++) {\n          if (idt.TypeParametersUsedInConstructionByDefaultCtor[i]) {\n            ts.Add(typeArgs[i]);\n          }\n        }\n        return ts;\n      }\n    }\n\n    int WriteRuntimeTypeDescriptorsFormals(List<TypeParameter> typeParams, bool useAllTypeArgs, TargetWriter wr, string prefix = \"\") {\n      Contract.Requires(typeParams != null);\n      Contract.Requires(wr != null);\n\n      if (typeParams.Count == 0) {\n        return 0;\n      } else {\n        throw NotSupported(\"WriteRuntimeTypeDescriptorsFormals\");\n      }\n/*\n      int c = 0;\n      foreach (var tp in typeParams) {\n        if (useAllTypeArgs || tp.Characteristics.MustSupportZeroInitialization) {\n          wr.Write(\"{0}{1}\", prefix, \"rtd$_\" + tp.CompileName);\n          prefix = \", \";\n          c++;\n        }\n      }\n      return c; */\n    }\n\n    protected override int EmitRuntimeTypeDescriptorsActuals(List<Type> typeArgs, List<TypeParameter> formals, Bpl.IToken tok, bool useAllTypeArgs, TargetWriter wr) {\n      var sep = \"\";\n      var c = 0;\n      for (int i = 0; i < typeArgs.Count; i++) {\n        var actual = typeArgs[i];\n        var formal = formals[i];\n        if (useAllTypeArgs || formal.Characteristics.MustSupportZeroInitialization) {\n          wr.Write(\"{0}{1}\", sep, RuntimeTypeDescriptor(actual, tok, wr));\n          sep = \", \";\n          c++;\n        }\n      }\n      return c;\n    }\n\n    string RuntimeTypeDescriptor(Type type, Bpl.IToken tok, TextWriter wr) {\n      Contract.Requires(type != null);\n      Contract.Requires(tok != null);\n      Contract.Requires(wr != null);\n      throw NotSupported(string.Format(\"RuntimeTypeDescriptor {0} not yet supported\", type), tok);\n/*\n      var xType = type.NormalizeExpandKeepConstraints();\n      if (xType is TypeProxy) {\n        // unresolved proxy; just treat as bool, since no particular type information is apparently needed for this type\n        return \"_dafny.Rtd_bool\";\n      }\n\n      if (xType is BoolType) {\n        return \"_dafny.Rtd_bool\";\n      } else if (xType is CharType) {\n        return \"_dafny.Rtd_char\";\n      } else if (xType is IntType) {\n        return \"_dafny.Rtd_int\";\n      } else if (xType is BigOrdinalType) {\n        return \"_dafny.BigOrdinal\";\n      } else if (xType is RealType) {\n        return \"_dafny.BigRational\";\n      } else if (xType is BitvectorType) {\n        var t = (BitvectorType)xType;\n        if (t.NativeType != null) {\n          return \"_dafny.Rtd_bv_Native\";\n        } else {\n          return \"_dafny.Rtd_bv_NonNative\";\n        }\n      } else if (xType is SetType) {\n        return \"_dafny.Set\";\n      } else if (xType is MultiSetType) {\n        return \"_dafny.MultiSet\";\n      } else if (xType is SeqType) {\n        return \"_dafny.Seq\";\n      } else if (xType is MapType) {\n        return \"_dafny.Map\";\n      } else if (xType.IsBuiltinArrowType) {\n        return \"_dafny.Rtd_ref\";  // null suffices as a default value, since the function will never be called\n      } else if (xType is UserDefinedType) {\n        var udt = (UserDefinedType)xType;\n        var tp = udt.ResolvedParam;\n        if (tp != null) {\n          return string.Format(\"{0}rtd$_{1}\", tp.Parent is ClassDecl ? \"this.\" : \"\", tp.CompileName);\n        }\n        var cl = udt.ResolvedClass;\n        Contract.Assert(cl != null);\n        bool isHandle = true;\n        if (Attributes.ContainsBool(cl.Attributes, \"handle\", ref isHandle) && isHandle) {\n          return \"_dafny.Rtd_ref\";\n        } else if (cl is ClassDecl) {\n          return \"_dafny.Rtd_ref\";\n        } else if (cl is DatatypeDecl) {\n          var dt = (DatatypeDecl)cl;\n          var w = new TargetWriter();\n          w.Write(\"{0}.Rtd(\", dt is TupleTypeDecl ? \"_dafny.Tuple\" : FullTypeName(udt));\n          EmitRuntimeTypeDescriptorsActuals(UsedTypeParameters(dt, udt.TypeArgs), cl.TypeArgs, udt.tok, true, w);\n          w.Write(\")\");\n          return w.ToString();\n        } else if (xType.IsNonNullRefType) {\n          // this initializer shouldn't ever be needed; the compiler is expected to generate an error\n          // sooner or later, , but it could be that the the compiler needs to\n          // lay down some bits to please the C#'s compiler's different definite-assignment rules.\n          return \"_dafny.Rtd_ref/\";\n        } else {\n          Contract.Assert(cl is NewtypeDecl || cl is SubsetTypeDecl);\n          return TypeName_UDT(FullTypeName(udt), udt.TypeArgs, wr, udt.tok);\n        }\n      } else {\n        Contract.Assert(false); throw new cce.UnreachableException();  // unexpected type\n      } */\n    }\n\n    protected BlockTargetWriter/*?*/ CreateGetter(string name, Type resultType, Bpl.IToken tok, bool isStatic, bool createBody, TargetWriter wr) {\n      // We don't use getters\n      return createBody ? new TargetWriter().NewBlock(\"\") : null;\n    }\n\n    protected BlockTargetWriter/*?*/ CreateGetterSetter(string name, Type resultType, Bpl.IToken tok, bool isStatic, bool createBody, out TargetWriter setterWriter, TargetWriter wr) {\n      // We don't use getter/setter pairs; we just embed the trait's fields.\n      if (createBody) {\n        var abyss = new TargetWriter();\n        setterWriter = abyss;\n        return abyss.NewBlock(\"\");\n      } else {\n        setterWriter = null;\n        return null;\n      }\n    }\n\n    protected override void EmitJumpToTailCallStart(TargetWriter wr) {\n      //wr.WriteLine(\"continue TAIL_CALL_START;\");\n    }\n\n    protected void Warn(string msg, Bpl.IToken tok) {\n      Console.Error.WriteLine(\"WARNING: {3} ({0}:{1}:{2})\", tok.filename, tok.line, tok.col, msg);\n    }\n\n    // Use class_name = true if you want the actual name of the class, not the type used when declaring variables/arguments/etc.\n    protected string TypeName(Type type, TextWriter wr, Bpl.IToken tok, MemberDecl/*?*/ member = null, bool class_name=false) {\n      Contract.Ensures(Contract.Result<string>() != null);\n      Contract.Assume(type != null);  // precondition; this ought to be declared as a Requires in the superclass\n\n      if (type is SizedArrayType)\n      {\n        return ((SizedArrayType) type).Arg.ToString();\n      } else if (type is PointerType)\n      {\n        var arg = ((PointerType) type).Arg;\n        var arg_name = (arg is SizedArrayType) ? TypeName(arg, wr, null) + \"*\" : TypeName(arg, wr, null) ;\n        return arg_name +  \"*\";\n      } else if (type is UserDefinedType)\n      {\n        var ty = ((UserDefinedType) type);\n        var primitiveTypes = new List<string>\n          {\"int\", \"uint8\", \"uint16\", \"uint32\", \"uint64\", \"int8\", \"int16\", \"int32\", \"int64\", \"bool\", \"_default\"};\n        if (primitiveTypes.Contains(ty.ToString()))\n        {\n          return ty.ToString();\n        }\n        else\n        {\n          return \"struct \" + (((UserDefinedType) type).ToString());\n        }\n      }\n      else\n      {\n        throw NotSupported(String.Format(\"Unknown Type: {0}\", type.ToString()));\n      }\n\n//      var xType = type.NormalizeExpand();\n//      Console.WriteLine(\"Handling TypeName {0}\",xType.ToString());\n//\n//      if (xType is TypeProxy) {\n//        // unresolved proxy; just treat as ref, since no particular type information is apparently needed for this type\n//        return \"object\";\n//      }\n//\n//      if (xType is BoolType) {\n//        return \"bool\";\n//      } else if (xType is CharType) {\n//        return \"char\";\n//      } else if (xType is IntType || xType is BigOrdinalType) {\n//        Warn(\"BigInteger used\", tok);\n//        return \"BigNumber\";\n//      } else if (xType is RealType) {\n//        Warn(\"BigRational used\", tok);\n//        return \"Dafny.BigRational\";\n//      } else if (xType is BitvectorType) {\n//        var t = (BitvectorType)xType;\n//        return t.NativeType != null ? GetNativeTypeName(t.NativeType) : \"BigNumber\";\n//      } else if (xType.AsNewtype != null) {\n//        NativeType nativeType = xType.AsNewtype.NativeType;\n//        if (nativeType != null) {\n//          return GetNativeTypeName(nativeType);\n//        }\n//        return TypeName(xType.AsNewtype.BaseType, wr, tok);\n//      } else if (xType.IsObjectQ) {\n//        return \"object\";\n//      } else if (xType.IsArrayType) {\n//        ArrayClassDecl at = xType.AsArrayType;\n//        Contract.Assert(at != null);  // follows from type.IsArrayType\n//        Type elType = UserDefinedType.ArrayElementType(xType);\n//        string typeNameSansBrackets, brackets;\n//        //TypeName_SplitArrayName(elType, wr, tok, out typeNameSansBrackets, out brackets);\n//        //return typeNameSansBrackets + TypeNameArrayBrackets(at.Dims) + brackets;\n//        if (at.Dims == 1) {\n//          return \"shared_ptr<vector<\" + TypeName(elType, wr, tok, null, false) + \">>\";\n//        } else {\n//          throw NotSupported(\"Multi-dimensional arrays\");\n//        }\n//      } else if (xType is UserDefinedType) {\n//        var udt = (UserDefinedType)xType;\n//        var s = FullTypeName(udt, member);\n//        var cl = udt.ResolvedClass;\n//        bool isHandle = true;\n//        if (cl != null && Attributes.ContainsBool(cl.Attributes, \"handle\", ref isHandle) && isHandle) {\n//          return \"ulong\";\n//        } else if (DafnyOptions.O.IronDafny &&\n//            !(xType is ArrowType) &&\n//            cl != null &&\n//            cl.Module != null &&\n//            !cl.Module.IsDefaultModule) {\n//          s = cl.FullCompileName;\n//        }\n//        if (class_name || xType.IsTypeParameter || xType.IsDatatype) {  // Don't add pointer decorations to class names or type parameters\n//          return IdProtect(s) + ActualTypeArgs(xType.TypeArgs);\n//        } else {\n//          return TypeName_UDT(s, udt.TypeArgs, wr, udt.tok);\n//        }\n//      } else if (xType is SetType) {\n//        Type argType = ((SetType)xType).Arg;\n//        if (ComplicatedTypeParameterForCompilation(argType)) {\n//          Error(tok, \"compilation of set<TRAIT> is not supported; consider introducing a ghost\", wr);\n//        }\n//        return DafnySetClass + \"<\" + TypeName(argType, wr, tok) + \">\";\n//      } else if (xType is SeqType) {\n//        Type argType = ((SeqType)xType).Arg;\n//        if (ComplicatedTypeParameterForCompilation(argType)) {\n//          Error(tok, \"compilation of seq<TRAIT> is not supported; consider introducing a ghost\", wr);\n//        }\n//        return DafnySeqClass + \"<\" + TypeName(argType, wr, tok) + \">\";\n//      } else if (xType is MultiSetType) {\n//        Type argType = ((MultiSetType)xType).Arg;\n//        if (ComplicatedTypeParameterForCompilation(argType)) {\n//          Error(tok, \"compilation of multiset<TRAIT> is not supported; consider introducing a ghost\", wr);\n//        }\n//        return DafnyMultiSetClass + \"<\" + TypeName(argType, wr, tok) + \">\";\n//      } else if (xType is MapType) {\n//        Type domType = ((MapType)xType).Domain;\n//        Type ranType = ((MapType)xType).Range;\n//        if (ComplicatedTypeParameterForCompilation(domType) || ComplicatedTypeParameterForCompilation(ranType)) {\n//          Error(tok, \"compilation of map<TRAIT, _> or map<_, TRAIT> is not supported; consider introducing a ghost\", wr);\n//        }\n//        return DafnyMapClass + \"<\" + TypeName(domType, wr, tok) + \",\" + TypeName(ranType, wr, tok) + \">\";\n//      } else if (xType is SizedArrayType) {\n//        //TODO(xueyuanz): Handle sized array type\n//        return \"TODO:SizedArrayType\";\n//      } else if (xType is PointerType) {\n//        return \"TODO:PointerType\";\n//      } else {\n//        Contract.Assert(false); throw new cce.UnreachableException();  // unexpected type\n//      }\n    }\n\n    protected override string TypeName(Type type, TextWriter wr, Bpl.IToken tok, MemberDecl/*?*/ member = null) {\n      Contract.Ensures(Contract.Result<string>() != null);\n      Contract.Assume(type != null);  // precondition; this ought to be declared as a Requires in the superclass\n      return TypeName(type, wr, tok, member, false);\n    }\n\n    protected string ClassName(Type type, TextWriter wr, Bpl.IToken tok, MemberDecl/*?*/ member = null) {\n      Contract.Ensures(Contract.Result<string>() != null);\n      Contract.Assume(type != null);  // precondition; this ought to be declared as a Requires in the superclass\n      return TypeName(type, wr, tok, member, true);\n    }\n\n    public override string TypeInitializationValue(Type type, TextWriter/*?*/ wr, Bpl.IToken/*?*/ tok, bool inAutoInitContext)\n    {\n      var xType = type.NormalizeExpandKeepConstraints();\n      Console.WriteLine(\"Handling Type {0}\",xType.ToString());\n\n      if (xType is BoolType) {\n        return \"false\";\n      } else if (xType is CharType) {\n        return \"'D'\";\n      } else if (xType is IntType || xType is BigOrdinalType) {\n        Warn(\"BigInteger used\", tok);\n        return \"new BigNumber(0)\";\n      } else if (xType is RealType) {\n        Warn(\"BigRational used\", tok);\n        return \"_dafny.BigRational.ZERO\";\n      } else if (xType is BitvectorType) {\n        var t = (BitvectorType)xType;\n        return t.NativeType != null ? \"0\" : \"new BigNumber(0)\";\n      } else if (xType is SetType) {\n        return \"_dafny.Set.Empty\";\n      } else if (xType is MultiSetType) {\n        return \"_dafny.MultiSet.Empty\";\n      } else if (xType is SeqType) {\n        return string.Format(\"DafnySequence<{0}>()\", TypeName(xType.AsSeqType.Arg, wr, tok, null, true));\n      } else if (xType is MapType) {\n        return \"_dafny.Map.Empty\";\n      } else if (xType is SizedArrayType) {\n        return \"{0}\";\n      } else if (xType is PointerType)\n      {\n        return \"NULL\";\n      }\n\n      var udt = (UserDefinedType)xType;\n      if (udt.ResolvedParam != null) {\n        if (udt.ResolvedClass != null && Attributes.Contains(udt.ResolvedClass.Attributes, \"extern\")) {\n          // Assume the external definition includes a default value\n          return String.Format(\"{1}::get_{0}_default()\", IdProtect(udt.Name), udt.ResolvedClass.Module.CompileName);\n        } else if (inAutoInitContext && !udt.ResolvedParam.Characteristics.MustSupportZeroInitialization) {\n          return String.Format(\"get_default<{0}>(NULL)\", IdProtect(udt.Name));\n        } else {\n          return null;\n          //return string.Format(\"{0}.Default\", RuntimeTypeDescriptor(udt, udt.tok, wr));\n        }\n      }\n      var cl = udt.ResolvedClass;\n      Contract.Assert(cl != null);\n      if (cl is NewtypeDecl) {\n        var td = (NewtypeDecl)cl;\n        if (td.Witness != null) {\n          return td.Module.CompileName + \"::class_\" + td.CompileName + \"::Witness\";\n          //return TypeName(udt, wr, udt.tok, null, true) + \"::Witness\";\n          //return TypeName(udt, wr, udt.tok, null, true) + \"()\";\n          //return \"Witness\";\n        } else if (td.NativeType != null) {\n          return \"0\";\n        } else {\n          return TypeInitializationValue(td.BaseType, wr, tok, inAutoInitContext);\n        }\n      } else if (cl is SubsetTypeDecl) {\n        var td = (SubsetTypeDecl)cl;\n        if (td.Witness != null) {\n          return td.Module.CompileName + \"::class_\" + td.CompileName + \"::Witness\";\n          //return TypeName(udt, wr, udt.tok, null, true) + \"::Witness\";\n          //return TypeName(udt, wr, udt.tok, null, true) + \"()\";\n          //return \"Witness\";\n        } else if (td.WitnessKind == SubsetTypeDecl.WKind.Special) {\n          // WKind.Special is only used with -->, ->, and non-null types:\n          Contract.Assert(ArrowType.IsPartialArrowTypeName(td.Name) || ArrowType.IsTotalArrowTypeName(td.Name) || td is NonNullTypeDecl);\n          if (ArrowType.IsPartialArrowTypeName(td.Name)) {\n            return null;\n          } else if (ArrowType.IsTotalArrowTypeName(td.Name)) {\n            var rangeDefaultValue = TypeInitializationValue(udt.TypeArgs.Last(), wr, tok, inAutoInitContext);\n            // return the lambda expression ((Ty0 x0, Ty1 x1, Ty2 x2) => rangeDefaultValue)\n            return string.Format(\"function () {{ return {0}; }}\", rangeDefaultValue);\n          } else if (((NonNullTypeDecl)td).Class is ArrayClassDecl) {\n            // non-null array type; we know how to initialize them\n            var arrayClass = (ArrayClassDecl)((NonNullTypeDecl)td).Class;\n            if (arrayClass.Dims == 1) {\n              return \"NULL\";\n            } else {\n              return string.Format(\"_dafny.newArray(nullptr, {0})\", Util.Comma(arrayClass.Dims, _ => \"0\"));\n            }\n          } else {\n            // non-null (non-array) type\n            // even though the type doesn't necessarily have a known initializer, it could be that the the compiler needs to\n            // lay down some bits to please the C#'s compiler's different definite-assignment rules.\n            return null;\n          }\n        } else {\n          return TypeInitializationValue(td.RhsWithArgument(udt.TypeArgs), wr, tok, inAutoInitContext);\n        }\n      } else if (cl is ClassDecl) {\n        bool isHandle = true;\n        if (Attributes.ContainsBool(cl.Attributes, \"handle\", ref isHandle) && isHandle) {\n          return \"0\";\n        } else {\n          return null;\n        }\n      } else if (cl is DatatypeDecl) {\n        var dt = (DatatypeDecl)cl;\n        var s = dt is TupleTypeDecl ? \"Tuple\" + (dt as TupleTypeDecl).Dims : FullTypeName(udt);\n        var w = new TargetWriter();\n        w.Write(\"{0}{1}()\", s, TemplateMethod(udt.TypeArgs));\n        /*\n        w.Write(\"{0}.Rtd(\", s);\n        EmitRuntimeTypeDescriptorsActuals(UsedTypeParameters(dt, udt.TypeArgs), dt.TypeArgs, udt.tok, true, w);\n        w.Write(\").Default\");\n        */\n        return w.ToString();\n      } else {\n        Contract.Assert(false); throw new cce.UnreachableException();  // unexpected type\n      }\n\n    }\n\n    private string ActualTypeArgs(List<Type> typeArgs) {\n      return typeArgs.Count > 0\n        ? String.Format(\" <{0}> \", Util.Comma(typeArgs, tp => TypeName(tp, null, null))) : \"\";\n    }\n\n    protected override string TypeName_UDT(string fullCompileName, List<Type> typeArgs, TextWriter wr, Bpl.IToken tok) {\n      Contract.Assume(fullCompileName != null);  // precondition; this ought to be declared as a Requires in the superclass\n      Contract.Assume(typeArgs != null);  // precondition; this ought to be declared as a Requires in the superclass\n      string s = IdProtect(fullCompileName);\n      return String.Format(\"std::shared_ptr<{0}{1}>\", s, ActualTypeArgs(typeArgs));\n    }\n\n    protected override string TypeName_Companion(Type type, TextWriter wr, Bpl.IToken tok, MemberDecl/*?*/ member) {\n      // There are no companion classes for Cpp\n      var t = TypeName(type, wr, tok, member, true);\n      return t;\n    }\n\n    // ----- Declarations -------------------------------------------------------------\n    protected override void DeclareExternType(OpaqueTypeDecl d, Expression compileTypeHint, TargetWriter wr) {\n      if (compileTypeHint.AsStringLiteral() == \"struct\") {\n        wr.WriteLine(\"// Extern declaration of {1}\\n{0} struct {1} {2};\", DeclareTemplate(d.TypeArgs), d.Name, TemplateMethod(d.TypeArgs));\n      } else {\n        Error(d.tok, \"Opaque type ('{0}') with unrecognized extern attribute {1} cannot be compiled.  Expected {{:extern compile_type_hint}} \", wr, d.FullName, compileTypeHint.AsStringLiteral());\n      }\n    }\n\n    protected void DeclareField(string className, List<TypeParameter> targs, string name, bool isStatic, bool isConst, Type type, Bpl.IToken tok, string rhs, TargetWriter wr, TargetWriter finisher) {\n\n      var t = TypeName(type, wr, tok);\n      var pref = \"\";\n      if (isStatic)\n      {\n        pref = \"static \";\n        //throw NotSupported(\"Static field\");\n      }\n      if (type is SizedArrayType)\n      {\n        var size = ((SizedArrayType) type).Size;\n        wr.WriteLine(\"{0}{1} {2}[{3}];\",pref, t, name,((LiteralExpr) size).Value.ToString() );\n      }\n      else\n      {\n        wr.WriteLine(\"{0}{1} {2};\", pref, t, name);\n      }\n    }\n\n    private  void CompileArmadaStruct(ArmadaStruct s,TargetWriter wr) {\n\n      var fieldWriter = wr.NewBlock(string.Format(\"struct {0};\\n\" +\n                                                  \"typedef struct {0} {0};\\n\" +\n                                                  \"struct {0}\", s.Name),\n        \";\");\n      var isParam = s.Name.StartsWith(\"_params_of_\");\n      foreach (string name in s.FieldNames)\n      {\n        var type = s.GetFieldType(name);\n        var t = TypeName(type, fieldWriter, null);\n\n        if (type is SizedArrayType)\n        {\n          fieldWriter.Write(DeclareSizedArray(name, (SizedArrayType) type, wr, null) + \";\");\n        }\n        else if (isParam) {\n          fieldWriter.WriteLine(\"{0} {1};\", t, name);\n        }\n        else\n        {\n          fieldWriter.WriteLine(\"volatile {0} {1};\", t, name);\n        }\n      }\n    }\n    public override void CompileArmadaStructs(ArmadaStructs structs, TargetWriter wr)\n    {\n      foreach (string name in structs.StructNames)\n      {\n        var s = structs.GetStruct(name);\n        CompileArmadaStruct(s, wr);\n      }\n    }\n\n    protected BlockTargetWriter/*?*/ CreateArmadaMethod(Method m, bool createBody, TargetWriter wr) {\n      var method_name = m.Name;\n      if (IsMain(m)) method_name = \"_main\";\n\n      string targetReturnTypeReplacement = null;\n      foreach (var p in m.Outs) {\n        if (!p.IsGhost) {\n          if (targetReturnTypeReplacement == null) {\n            targetReturnTypeReplacement = TypeName(p.Type, wr, p.tok);\n          } else if (targetReturnTypeReplacement != null) {\n            // there's more than one out-parameter, so bail\n            targetReturnTypeReplacement = null;\n            break;\n          }\n        }\n      }\n\n\n\n      if (m.TypeArgs.Count != 0) {\n        wr.WriteLine(DeclareTemplate(m.TypeArgs));\n      }\n\n      wr.Write(\"{0} {1}\",\n        targetReturnTypeReplacement ?? \"void\",\n        method_name);\n\n      wr.Write(\"(\");\n      int nIns = WriteFormals(\"\", m.Ins, wr);\n      if (targetReturnTypeReplacement == null) {\n        WriteFormals(nIns == 0 ? \"\" : \", \", m.Outs, wr);\n      }\n\n      if (!createBody) {\n        wr.WriteLine(\");\");\n        return null;\n      }\n\n      var w = wr.NewBlock(\")\", null, BlockTargetWriter.BraceStyle.Newline, BlockTargetWriter.BraceStyle.Newline);\n\n      if (targetReturnTypeReplacement != null) {\n        var r = new TargetWriter(w.IndentLevel);\n        EmitReturn(m.Outs, r);\n        w.BodySuffix = r.ToString();\n      }\n      return w;\n    }\n\n    protected void CreateParamStruct(Method m, TargetWriter wr)\n    {\n      var method_name = m.Name;\n      if (IsMain(m)) method_name = \"_main\";\n      var struct_name = \"_params_of_\" + method_name;\n      var fields = new Dictionary<string, Type>();\n      foreach (var formal in m.Ins)\n      {\n        var name = formal.Name;\n        var type = formal.Type;\n        fields.Add(name, type);\n      }\n\n      var param_struct = new ArmadaStruct(struct_name, fields);\n      CompileArmadaStruct(param_struct, wr);\n    }\n\n    protected void CreateThreadWrpper (Method m, bool createBody, TargetWriter wr)\n    {\n      var method_name = m.Name;\n      if (IsMain(m)) method_name = \"_main\";\n      var wrapper_name = \"_thread_of_\" + method_name;\n      var struct_name = \"_params_of_\" + method_name;\n\n      wr.Write(\"void* {0} (void* vargs)\", wrapper_name);\n      if (!createBody)\n      {\n        wr.WriteLine(\";\");\n        return;\n      }\n      var body_wr = wr.NewBlock(\"\",\"\");\n      body_wr.WriteLine(\"{0} args = *(({0} *) vargs);\",struct_name);\n      body_wr.Write(\"{0} (\", method_name);\n      var sep = \"\";\n      foreach (var formal in m.Ins)\n      {\n        var name = sep + \"args.\" + formal.Name;\n        sep = \",\";\n        body_wr.Write(name);\n      }\n      body_wr.WriteLine(\");\");\n      body_wr.WriteLine(\"return NULL;\");\n    }\n    protected void CompileArmadaMethod(Method m, TargetWriter wr)\n    {\n      var method_name = m.Name;\n      if (IsMain(m))\n        method_name = \"_main\";\n\n      if (m.IsExtern(out _, out _))\n      {\n        Console.WriteLine(\"Method {0} is extern\",method_name);\n        wr.WriteLine(\"// Skipped extern method {0}\", method_name);\n        CreateThreadWrpper(m, true, wr);\n        return;\n      }\n\n      wr.WriteLine(\"// Beginning of method {0}\", method_name);\n\n      // create the writer for the method\n      var w = CreateArmadaMethod(m, true, wr);\n      if (w != null) {\n        int nonGhostOutsCount = 0;\n        foreach (var p in m.Outs) {\n          if (!p.IsGhost) {\n            nonGhostOutsCount++;\n          }\n        }\n\n        var useReturnStyleOuts = UseReturnStyleOuts(m, nonGhostOutsCount);\n        foreach (var p in m.Outs) {\n          if (!p.IsGhost) {\n            DeclareLocalOutVar(IdName(p), p.Type, p.tok, DefaultValue(p.Type, w, p.tok, true), useReturnStyleOuts, w);\n          }\n        }\n\n        w = EmitMethodReturns(m, w);\n\n        if (m.Body == null) {\n          Error(m.tok, \"Method {0} has no body\", w, m.FullName);\n        } else {\n          Contract.Assert(enclosingMethod == null);\n          enclosingMethod = m;\n          // translate the body of method.\n          TrStmtList(m.Body.Body, w);\n          Contract.Assert(enclosingMethod == m);\n          enclosingMethod = null;\n        }\n\n        // create thread wrapper for the method.\n        CreateThreadWrpper(m, true, wr);\n\n        wr.WriteLine(\"// End of method {0}\\n\",method_name);\n      }\n\n      // allow the Main method to be an instance method\n      /*if (IsMain(m) && (!m.IsStatic || m.CompileName != \"Main\")) {\n        w = CreateStaticMain(cw);\n        if (!m.IsStatic) {\n          var c = m.EnclosingClass;\n          var typeArgs = c.TypeArgs.ConvertAll(tp => (Type)Type.Bool);\n          var ty = new UserDefinedType(m.tok, c.Name, c, typeArgs);\n          var wRhs = DeclareLocalVar(\"b\", ty, m.tok, w);\n          EmitNew(ty, m.tok, null, wRhs);\n          w.WriteLine(\"b.{0}();\", IdName(m));\n        } else {\n          w.WriteLine(\"{0}();\", IdName(m));\n        }\n      }*/\n\n    }\n\n    protected void DeclareArmadaGlobalVar(string name, Type/*?*/ type, Bpl.IToken/*?*/ tok, bool leaveRoomForRhs, string/*?*/ rhs, TargetWriter wr) {\n      if (type != null) {\n        if (type is SizedArrayType)\n          wr.Write(DeclareSizedArray(name, (SizedArrayType) type, wr, tok));\n        else\n          wr.Write(\"volatile {0} {1}\", TypeName(type, wr, tok), name);\n      } else {\n        throw NotSupported(\"auto type\");\n      }\n      if (leaveRoomForRhs) {\n        Contract.Assert(rhs == null);  // follows from precondition\n      } else if (rhs != null) {\n        wr.WriteLine(\" = {0};\", rhs);\n      } else {\n        wr.WriteLine(\";\");\n      }\n    }\n\n\n    public void CompileArmadaGlobalVariables(ArmadaGlobalVariableSymbolTable table, TargetWriter wr)\n    {\n      foreach (var name in table.VariableNames)\n      {\n        var variable = table.Lookup(name);\n        if (variable is GlobalGhostArmadaVariable)\n        {\n          continue;\n        }\n        var type = variable.ty;\n        if (variable.initialValue == null)\n        {\n          DeclareArmadaGlobalVar(name, type, null, false,  DefaultValue(type, wr, null), wr);\n        }\n        else\n        {\n          var wrhs = new TargetWriter();\n          variable.initialValue.Type = variable.ty;\n          // xueyuanz: May throw error when rhs is not constant, while this should not be allowed.\n          TrExpr(variable.initialValue, wrhs, false);\n          var rhs = wrhs.ToString();\n          DeclareArmadaGlobalVar(name, type, null, false,  rhs, wr);\n        }\n      }\n    }\n\n    public void UpdateArmadaMethodParams(AllMethodsInfo methods)\n    {\n      foreach (var methodName in methods.AllMethodNames)\n      {\n        var methodInfo = methods.LookupMethod(methodName);\n        var method = methodInfo.method;\n        var param_list = new List<string>();\n        foreach (var param in method.Ins)\n        {\n          param_list.Add(param.Name);\n        }\n        this.armadaMethodParams.Add(methodName, param_list);\n      }\n    }\n\n    void CreateParamStructs(AllMethodsInfo methods, TargetWriter wr)\n    {\n      foreach (var methodName in methods.AllMethodNames)\n      {\n        var methodInfo = methods.LookupMethod(methodName);\n        var method = methodInfo.method;\n        // create param struct for the method.\n        CreateParamStruct(method, wr);\n      }\n    }\n\n    void DeclareArmadaMethods(AllMethodsInfo methods, TargetWriter wr)\n    {\n      foreach (var methodName in methods.AllMethodNames)\n      {\n        var methodInfo = methods.LookupMethod(methodName);\n        var method = methodInfo.method;\n\n        // Skip the method decl if it is extern\n        if (!method.IsExtern(out _, out _))\n        {\n          CreateArmadaMethod(method, false, wr);\n        }\n        CreateThreadWrpper(method, false, wr);\n      }\n    }\n    void CompileArmadaMethods(AllMethodsInfo methods, TargetWriter wr)\n    {\n      foreach (var methodName in methods.AllMethodNames)\n      {\n        var methodInfo = methods.LookupMethod(methodName);\n        var method = methodInfo.method;\n        CompileArmadaMethod(method, wr);\n        if (IsMain(method))\n        {\n          EmitCallToMain(method, wr);\n        }\n      }\n    }\n\n    public override void CompileArmadaLayer(ModuleDefinition layer, TargetWriter wr)\n    {\n      var symbols = layer.ArmadaSymbols;\n      var globals = symbols.Globals;\n      var methods = symbols.AllMethods;\n      // Compile the global varibales\n      wr.WriteLine(\"// Global Variables\");\n      CompileArmadaGlobalVariables(globals, wr);\n\n      // Create the Param structs for each method\n      wr.WriteLine(\"// Param Stucts\");\n      CreateParamStructs(methods, wr);\n\n      // Update the info about method params for the use of create thread\n      UpdateArmadaMethodParams(methods);\n\n      // Declare all methods and their wrappers\n      wr.WriteLine(\"// Method Decls\");\n      DeclareArmadaMethods(methods, wr);\n\n      // Compile the methods together with their wrappers\n      wr.WriteLine(\"// Methods Defns\");\n      CompileArmadaMethods(methods, wr);\n\n\n\n    }\n\n    public override void CompileArmadaCreateThread(ArmadaCreateThreadStatement stmt, TargetWriter wr)\n    {\n      Contract.Assert(stmt.Stmt is UpdateStmt);\n      var s = (UpdateStmt) stmt.Stmt;\n      var bw = wr.NewBlock(\"//Begin Create Thread\\n\", \"\\n//End Create Thread\\n\" );\n      var lhs_name = \"_temp_thread_id\";\n\n      if (s.Lhss.Count == 0)\n      {\n        // create a temp tid if there is no LHS\n        bw.WriteLine(\"pthread_t {0};\",lhs_name);\n      }\n      else\n      {\n        // get the lhs name\n        Contract.Assert(s.Lhss.Count == 1);\n        var lhs_wr = new TargetWriter();\n        TrExpr(s.Lhss[0], lhs_wr, false);\n        lhs_name = lhs_wr.ToString();\n      }\n\n\n      Contract.Assert(s.Rhss.Count == 1);\n      Contract.Assert(s.Rhss[0] is CreateThreadRhs);\n\n      var rhs = (CreateThreadRhs) s.Rhss[0];\n      var method_name = rhs.MethodName.val;\n      Contract.Assert(this.armadaMethodParams.ContainsKey(method_name));\n      var param_names = this.armadaMethodParams[method_name];\n\n      // create and init param struct\n      bw.WriteLine(\"_params_of_{0}* args = malloc(sizeof(_params_of_{0}));\", method_name);\n      var index = 0;\n      foreach (var arg in rhs.Args)\n      {\n        var arg_wr = new TargetWriter();\n        TrExpr(arg, arg_wr, false);\n        var arg_val = arg_wr.ToString();\n        var arg_name = param_names[index];\n        bw.WriteLine(\"args->{0} = {1};\",arg_name,arg_val);\n        index += 1;\n      }\n      // call pthread_create\n      bw.WriteLine(\"pthread_create((pthread_t*) &({0}), NULL, _thread_of_{1}, (void *) args);\",lhs_name,method_name);\n    }\n\n    public override void CompileArmadaCompareAndSwap(ArmadaCompareAndSwapStatement stmt, TargetWriter wr)\n    {\n      var us = (UpdateStmt)stmt.Stmt;\n      var crhs = (CompareAndSwapRhs)us.Rhss[0];\n      if (us.Lhss.Count > 0) {\n        TrExpr(us.Lhss[0], wr, false);\n        wr.Write(\" = \");\n      }\n      wr.Write(\"__sync_val_compare_and_swap(&\");\n      TrParenExpr(crhs.Target, wr, false);\n      wr.Write(\", \");\n      TrExpr(crhs.OldVal, wr, false);\n      wr.Write(\", \");\n      TrExpr(crhs.NewVal, wr, false);\n      wr.WriteLine(\");\");\n    }\n\n    public override void CompileArmadaAtomicExchange(ArmadaAtomicExchangeStatement stmt, TargetWriter wr)\n    {\n      var us = (UpdateStmt)stmt.Stmt;\n      var crhs = (CompareAndSwapRhs)us.Rhss[0];\n      if (us.Lhss.Count > 0) {\n        TrExpr(us.Lhss[0], wr, false);\n        wr.Write(\" = \");\n      }\n      wr.Write(\"__armada_atomic_exchange(&\");\n      TrParenExpr(crhs.Target, wr, false);\n      wr.Write(\", \");\n      TrExpr(crhs.NewVal, wr, false);\n      wr.WriteLine(\");\");\n    }\n\n    private string DeclareFormalString(string prefix, string name, Type type, Bpl.IToken tok, bool isInParam) {\n      if (isInParam) {\n        return String.Format(\"{0}{2} {1}\", prefix, name, TypeName(type, null, tok));\n      } else {\n        return null;\n      }\n    }\n\n    protected override bool DeclareFormal(string prefix, string name, Type type, Bpl.IToken tok, bool isInParam, TextWriter wr) {\n      var formal_str = DeclareFormalString(prefix, name, type, tok, isInParam);\n      if (formal_str != null) {\n        wr.Write(formal_str);\n        return true;\n      } else {\n        return false;\n      }\n    }\n\n    private string DeclareFormals(List<Formal> formals) {\n      var i = 0;\n      var ret = \"\";\n      var sep = \"\";\n      foreach (Formal arg in formals) {\n        if (!arg.IsGhost) {\n          string name = FormalName(arg, i);\n          string decl = DeclareFormalString(sep, name, arg.Type, arg.tok, arg.InParam);\n          if (decl != null) {\n            ret += decl;\n            sep = \", \";\n          }\n          i++;\n        }\n      }\n      return ret;\n    }\n\n    private string DeclareSizedArray(string name, SizedArrayType type, TargetWriter wr, Bpl.IToken/*?*/ tok)\n    {\n      var size = type.Size;\n      return String.Format(\"{0} {1}[{2}]\", TypeName(type.Arg, wr, tok), name,((LiteralExpr) size).Value.ToString() );\n    }\n    protected override void DeclareLocalVar(string name, Type/*?*/ type, Bpl.IToken/*?*/ tok, bool leaveRoomForRhs, string/*?*/ rhs, TargetWriter wr) {\n      if (type != null) {\n        if (type is SizedArrayType)\n          wr.Write(DeclareSizedArray(name, (SizedArrayType) type, wr, tok));\n        else\n          wr.Write(\"{0} {1}\", TypeName(type, wr, tok), name);\n      } else {\n        throw NotSupported(\"auto type\");\n      }\n      if (leaveRoomForRhs) {\n        Contract.Assert(rhs == null);  // follows from precondition\n      } else if (rhs != null) {\n        wr.WriteLine(\" = {0};\", rhs);\n      } else {\n        wr.WriteLine(\";\");\n      }\n    }\n\n\n    protected override TargetWriter DeclareLocalVar(string name, Type/*?*/ type, Bpl.IToken/*?*/ tok, TargetWriter wr) {\n      if (type != null) {\n        wr.Write(\"{0} \", TypeName(type, wr, tok));\n      } else {\n        wr.Write(\"auto \");\n      }\n      wr.Write(\"{0} = \", name);\n      var w = wr.Fork();\n      wr.WriteLine(\";\");\n      return w;\n    }\n\n    protected override bool UseReturnStyleOuts(Method m, int nonGhostOutCount) => true;\n\n    protected override void DeclareOutCollector(string collectorVarName, TargetWriter wr) {\n      wr.Write(\"auto {0} = \", collectorVarName);\n    }\n    protected override void DeclareSpecificOutCollector(string collectorVarName, TargetWriter wr, int outCount, List<Type> types, Method m) {\n      for (int i = 0; i < types.Count; i++) {\n        Formal p = m.Outs[i];\n        if (!p.IsGhost) {\n          wr.Write($\"{TypeName(types[i], wr, p.tok)} {collectorVarName} = \");\n          return;\n        }\n      }\n    }\n\n    protected override void DeclareLocalOutVar(string name, Type type, Bpl.IToken tok, string rhs, bool useReturnStyleOuts, TargetWriter wr) {\n      DeclareLocalVar(name, type, tok, false, rhs, wr);\n    }\n\n    protected override void EmitOutParameterSplits(string outCollector, List<string> actualOutParamNames, TargetWriter wr) {\n      if (actualOutParamNames.Count == 1) {\n        EmitAssignment(actualOutParamNames[0], null, outCollector, null, wr);\n      } else {\n        for (var i = 0; i < actualOutParamNames.Count; i++) {\n          wr.WriteLine(\"{0} = {1}[{2}];\", actualOutParamNames[i], outCollector, i);\n        }\n      }\n    }\n\n    protected override void EmitActualTypeArgs(List<Type> typeArgs, Bpl.IToken tok, TextWriter wr) {\n      wr.Write(ActualTypeArgs(typeArgs));\n    }\n\n    protected override string GenerateLhsDecl(string target, Type/*?*/ type, TextWriter wr, Bpl.IToken tok) {\n      return \"auto \" + target;\n    }\n\n    protected override void EmitNull(Type type, TargetWriter wr) {\n      wr.Write(\"NULL\");\n    }\n\n    // ----- Statements -------------------------------------------------------------\n\n    protected override void EmitJoinStmt(TargetWriter wr, Expression thread_id)\n    {\n      var thread_id_wr = new TargetWriter();\n      TrExpr(thread_id, thread_id_wr, false);\n      var thread_id_val = thread_id_wr.ToString();\n      wr.WriteLine(\"pthread_join((pthread_t){0},NULL);\",thread_id_val);\n    }\n\n    protected override void EmitFenceStmt(TargetWriter wr)\n    {\n      wr.WriteLine(\"asm volatile (\\\"mfence\\\" ::: \\\"memory\\\");\");\n    }\n\n    protected override void EmitGotoStmt(TargetWriter wr, string target)\n    {\n      wr.WriteLine($\"goto after_{target};\");\n    }\n\n    protected override void EmitDeallocStmt(TargetWriter wr, Expression addr)\n    {\n      var addr_wr = new TargetWriter();\n      TrExpr(addr, addr_wr, false);\n      var addr_val = addr_wr.ToString();\n      wr.WriteLine(\"free({0});\",addr_val);\n    }\n\n    protected override void EmitPrintStmt(TargetWriter wr, Expression arg) {\n      //wr.Write(\"_dafny::Print(\");\n      //TrExpr(arg, wr, false);\n      //wr.WriteLine(\");\");\n      wr.Write(\"cout << (\");\n      TrExpr(arg, wr, false);\n      wr.WriteLine(\");\");\n    }\n\n    protected override void EmitReturn(List<Formal> outParams, TargetWriter wr) {\n      outParams = outParams.Where(f => !f.IsGhost).ToList();\n      if (!outParams.Any()) {\n        wr.WriteLine(\"return;\");\n      } else {\n        wr.WriteLine(\"return {0};\", Util.Comma(outParams, IdName));\n      }\n    }\n\n    protected override TargetWriter CreateLabeledCode(string label, TargetWriter wr) {\n      var w = wr.ForkSection();\n      wr.IndentLess();\n      wr.WriteLine(\"after_{0}: ;\", label);\n      return w;\n    }\n\n    protected override void EmitBreak(string/*?*/ label, TargetWriter wr) {\n      if (label == null) {\n        wr.WriteLine(\"break;\");\n      } else {\n        wr.WriteLine(\"goto after_{0};\", label);\n      }\n    }\n\n    protected override void EmitContinue( TargetWriter wr)\n    {\n      wr.WriteLine(\"continue;\");\n    }\n\n    protected override void EmitYield(TargetWriter wr) {\n      throw NotSupported(\"EmitYield\");\n      //wr.WriteLine(\"yield null;\");\n    }\n\n    protected override void EmitAbsurd(string/*?*/ message, TargetWriter wr) {\n      if (message == null) {\n        message = \"unexpected control point\";\n      }\n      wr.WriteLine(\"throw \\\"{0}\\\";\", message);\n    }\n\n    protected override BlockTargetWriter CreateForLoop(string indexVar, string bound, TargetWriter wr) {\n      return wr.NewNamedBlock(\"for (auto {0} = 0; {0} < {1}; {0}++)\", indexVar, bound);\n    }\n\n    protected override BlockTargetWriter CreateDoublingForLoop(string indexVar, int start, TargetWriter wr) {\n      return wr.NewNamedBlock(\"for (unsigned long long {0} = 1; ; {0} = {0} * 2)\", indexVar, start);\n    }\n\n    protected override void EmitIncrementVar(string varName, TargetWriter wr) {\n      wr.WriteLine(\"{0} += 1;\", varName);\n    }\n\n    protected override void EmitDecrementVar(string varName, TargetWriter wr) {\n      wr.WriteLine(\"{0} = {0} -= 1;\", varName);\n    }\n\n    protected override string GetQuantifierName(string bvType) {\n      return string.Format(\"_dafny.Quantifier\");\n    }\n\n    protected override BlockTargetWriter CreateForeachLoop(string boundVar, Type/*?*/ boundVarType, out TargetWriter collectionWriter, TargetWriter wr, string/*?*/ altBoundVarName = null, Type/*?*/ altVarType = null, Bpl.IToken/*?*/ tok = null) {\n      wr.Write(\"for ({0} {1} : \", boundVarType, boundVar);\n      collectionWriter = wr.Fork();\n      if (altBoundVarName == null) {\n        return wr.NewBlock(\")\");\n      } else if (altVarType == null) {\n        return wr.NewBlockWithPrefix(\")\", \"{0} = {1};\", altBoundVarName, boundVar);\n      } else {\n        return wr.NewBlockWithPrefix(\")\", \"auto {0} = {1};\", altBoundVarName, boundVar);\n      }\n    }\n\n    // ----- Expressions -------------------------------------------------------------\n\n    protected override void EmitNew(Type type, Bpl.IToken tok, CallStmt/*?*/ initCall, TargetWriter wr) {\n      var cl = (type.NormalizeExpand() as UserDefinedType)?.ResolvedClass;\n      if (cl != null && cl.Name == \"object\") {\n        wr.Write(\"_dafny.NewObject()\");\n      } else {\n        //string targs = type.TypeArgs.Count > 0\n        //  ? String.Format(\" <{0}> \", Util.Comma(type.TypeArgs, tp => TypeName(tp, wr, tok))) : \"\";\n        //wr.Write(\"std::make_shared<{0}{1}> (\", TypeName(type, wr, tok, null, true), targs);\n        wr.Write(\"std::make_shared<{0}> (\", TypeName(type, wr, tok, null, true));\n        EmitRuntimeTypeDescriptorsActuals(type.TypeArgs, cl.TypeArgs, tok, false, wr);\n        wr.Write(\")\");\n      }\n    }\n\n    protected override void EmitNewArray(Type elmtType, Bpl.IToken tok, List<Expression> dimensions, bool mustInitialize, TargetWriter wr) {\n      var initValue = mustInitialize ? DefaultValue(elmtType, wr, tok) : null;\n      // TODO: Handle initValue\n      if (dimensions.Count == 1) {\n        // handle the common case of 1-dimensional arrays separately\n        wr.Write(\"make_shared<vector<{0}>>(\", TypeName(elmtType, wr, tok));\n        TrExpr(dimensions[0], wr, false);\n        wr.Write(\")\");\n      } else {\n        throw NotSupported(\"Multi-dimensional arrays\", tok);\n        // the general case\n        /* wr.Write(\"_dafny.newArray({0}\", initValue ?? \"undefined\");\n        foreach (var dim in dimensions) {\n          wr.Write(\", \");\n          TrParenExpr(dim, wr, false);\n          wr.Write(\".toNumber()\");\n        }\n        wr.Write(\")\"); */\n      }\n    }\n\n    protected override void EmitLiteralExpr(TextWriter wr, LiteralExpr e) {\n      if (e is StaticReceiverExpr) {\n        wr.Write(TypeName(e.Type, wr, e.tok));\n      } else if (e.Value == null) {\n        wr.Write(\"NULL\");\n      } else if (e.Value is bool) {\n        wr.Write((bool)e.Value ? \"true\" : \"false\");\n      } else if (e is CharLiteralExpr) {\n        var v = (string)e.Value;\n        wr.Write(\"'{0}'\", v);\n      } else if (e is StringLiteralExpr) {\n        var str = (StringLiteralExpr)e;\n        // TODO: the string should be converted to a Dafny seq<char>\n        TrStringLiteral(str, wr);\n      } else if (AsNativeType(e.Type) is NativeType nt) {\n        wr.Write(\"({0}){1}\", GetNativeTypeName(nt), (BigInteger)e.Value);\n      } else if (e.Value is BigInteger i) {\n        EmitIntegerLiteral(i, wr);\n      } else if (e.Value is BaseTypes.BigDec) {\n        throw NotSupported(\"EmitLiteralExpr of BaseTypes.BigDec\");\n        /*\n        var n = (BaseTypes.BigDec)e.Value;\n        if (0 <= n.Exponent) {\n          wr.Write(\"new _dafny.BigRational(new BigNumber(\\\"{0}\", n.Mantissa);\n          for (int i = 0; i < n.Exponent; i++) {\n            wr.Write(\"0\");\n          }\n          wr.Write(\"\\\"))\");\n        } else {\n          wr.Write(\"new _dafny.BigRational(\");\n          EmitIntegerLiteral(n.Mantissa, wr);\n          wr.Write(\", new BigNumber(\\\"1\");\n          for (int i = n.Exponent; i < 0; i++) {\n            wr.Write(\"0\");\n          }\n          wr.Write(\"\\\"))\");\n        } */\n      } else {\n        Contract.Assert(false); throw new cce.UnreachableException();  // unexpected literal\n      }\n    }\n    void EmitIntegerLiteral(BigInteger i, TextWriter wr) {\n      Contract.Requires(wr != null);\n      wr.Write(i);\n      /*\n      if (i == 0) {\n        wr.Write(\"_dafny.Zero\");\n      } else if (long.MinValue <= i && i <= long.MaxValue) {\n        wr.Write(\"_dafny.IntOfInt64({0})\", i);\n      } else {\n        wr.Write(\"_dafny.IntOfString(\\\"{0}\\\")\", i);\n      }\n       */\n    }\n\n    protected override void EmitStringLiteral(string str, bool isVerbatim, TextWriter wr) {\n      var n = str.Length;\n      wr.Write(\"DafnySequence<char>(\");\n      if (!isVerbatim) {\n        wr.Write(\"\\\"{0}\\\"\", str);\n      } else {\n        wr.Write(\"\\\"\");\n        for (var i = 0; i < n; i++) {\n          if (str[i] == '\\\"' && i+1 < n && str[i+1] == '\\\"') {\n            wr.Write(\"\\\\\\\"\");\n            i++;\n          } else if (str[i] == '\\\\') {\n            wr.Write(\"\\\\\\\\\");\n          } else if (str[i] == '\\n') {\n            wr.Write(\"\\\\n\");\n          } else if (str[i] == '\\r') {\n            wr.Write(\"\\\\r\");\n          } else {\n            wr.Write(str[i]);\n          }\n        }\n        wr.Write(\"\\\"\");\n      }\n      wr.Write(\")\");\n    }\n\n    protected override TargetWriter EmitBitvectorTruncation(BitvectorType bvType, bool surroundByUnchecked, TargetWriter wr) {\n      throw NotSupported(\"EmitBitvectorTruncation\");\n      /*string nativeName = null, literalSuffix = null;\n      bool needsCastAfterArithmetic = false;\n      if (bvType.NativeType != null) {\n        GetNativeInfo(bvType.NativeType.Sel, out nativeName, out literalSuffix, out needsCastAfterArithmetic);\n      }\n\n      if (bvType.NativeType == null) {\n        wr.Write(\"(\");\n        var middle = wr.Fork();\n        wr.Write(\").mod(new BigNumber(2).exponentiatedBy({0}))\", bvType.Width);\n        return middle;\n      } else if (bvType.NativeType.Bitwidth != bvType.Width) {\n        // no truncation needed\n        return wr;\n      } else {\n        wr.Write(\"((\");\n        var middle = wr.Fork();\n        // print in hex, because that looks nice\n        wr.Write(\") & 0x{0:X}{1})\", (1UL << bvType.Width) - 1, literalSuffix);\n        return middle;\n      }*/\n    }\n\n    protected override void EmitRotate(Expression e0, Expression e1, bool isRotateLeft, TargetWriter wr, bool inLetExprBody, FCE_Arg_Translator tr) {\n      throw NotSupported(\"EmitRotate\");\n      /*string nativeName = null, literalSuffix = null;\n      bool needsCast = false;\n      var nativeType = AsNativeType(e0.Type);\n      if (nativeType != null) {\n        GetNativeInfo(nativeType.Sel, out nativeName, out literalSuffix, out needsCast);\n      }\n\n      var bv = e0.Type.AsBitVectorType;\n      if (bv.Width == 0) {\n        tr(e0, wr, inLetExprBody);\n      } else {\n        wr.Write(\"_dafny.{0}(\", isRotateLeft ? \"RotateLeft\" : \"RotateRight\");\n        tr(e0, wr, inLetExprBody);\n        wr.Write(\", (\");\n        tr(e1, wr, inLetExprBody);\n        wr.Write(\").toNumber(), {0})\", bv.Width);\n        if (needsCast) {\n          wr.Write(\".toNumber()\");\n        }\n      }*/\n    }\n\n    protected override void EmitEmptyTupleList(string tupleTypeArgs, TargetWriter wr) {\n      throw NotSupported(\"EmitEmptyTupleList\");\n      //wr.Write(\"[]\", tupleTypeArgs);\n    }\n\n    protected override TargetWriter EmitAddTupleToList(string ingredients, string tupleTypeArgs, TargetWriter wr) {\n      throw NotSupported(\"EmitAddTupleToList\");\n      /*wr.Write(\"{0}.push(_dafny.Tuple.of(\", ingredients, tupleTypeArgs);\n      var wrTuple = wr.Fork();\n      wr.WriteLine(\"));\");\n      return wrTuple;*/\n    }\n\n    protected override void EmitTupleSelect(string prefix, int i, TargetWriter wr) {\n      throw NotSupported(\"EmitTupleSelect\");\n      //wr.Write(\"{0}[{1}]\", prefix, i);\n    }\n\n    protected override string IdProtect(string name) {\n      return PublicIdProtect(name);\n    }\n    public static string PublicIdProtect(string name) {\n      Contract.Requires(name != null);\n      switch (name) {\n        // Taken from: https://www.w3schools.in/cplusplus-tutorial/keywords/\n        // Keywords\n        case \"asm\":\n        case \"auto\":\n        case \"bool\":\n        case \"break\":\n        case \"case\":\n        case \"catch\":\n        case \"char\":\n        case \"class\":\n        case \"const\":\n        case \"const_cast\":\n        case \"continue\":\n        case \"default\":\n        case \"delete\":\n        case \"do\":\n        case \"double\":\n        case \"dynamic_cast\":\n        case \"else\":\n        case \"enum\":\n        case \"explicit\":\n        case \"export\":\n        case \"extern\":\n        case \"false\":\n        case \"float\":\n        case \"for\":\n        case \"friend\":\n        case \"goto\":\n        case \"if\":\n        case \"inline\":\n        case \"int\":\n        case \"long\":\n        case \"mutable\":\n        case \"namespace\":\n        case \"new\":\n        case \"operator\":\n        case \"private\":\n        case \"protected\":\n        case \"public\":\n        case \"register\":\n        case \"reinterpret_cast\":\n        case \"return\":\n        case \"short\":\n        case \"signed\":\n        case \"sizeof\":\n        case \"static\":\n        case \"static_cast\":\n        case \"struct\":\n        case \"switch\":\n        case \"template\":\n        case \"this\":\n        case \"throw\":\n        case \"true\":\n        case \"try\":\n        case \"typedef\":\n        case \"typeid\":\n        case \"typename\":\n        case \"union\":\n        case \"unsigned\":\n        case \"using\":\n        case \"virtual\":\n        case \"void\":\n        case \"volatile\":\n        case \"wchar_t\":\n        case \"while\":\n\n        // Also reserved\n        case \"And\":\n        case \"and_eq\":\n        case \"bitand\":\n        case \"bitor\":\n        case \"compl\":\n        case \"not\":\n        case \"not_eq\":\n        case \"or\":\n        case \"or_eq\":\n        case \"xor\":\n        case \"xor_eq\":\n          return name + \"_\";\n        default:\n          return name;\n      }\n    }\n\n    protected override string FullTypeName(UserDefinedType udt, MemberDecl/*?*/ member = null) {\n      Contract.Assume(udt != null);  // precondition; this ought to be declared as a Requires in the superclass\n      if (udt is ArrowType) {\n        throw NotSupported(string.Format(\"UserDefinedTypeName {0}\", udt.Name));\n        //return ArrowType.Arrow_FullCompileName;\n      }\n      var cl = udt.ResolvedClass;\n      if (cl == null) {\n        return IdProtect(udt.CompileName);\n      } else if (cl is ClassDecl cdecl && cdecl.IsDefaultClass && Attributes.Contains(cl.Module.Attributes, \"extern\") &&\n                 member != null && Attributes.Contains(member.Attributes, \"extern\")) {\n        // omit the default class name (\"_default\") in extern modules, when the class is used to qualify an extern member\n        Contract.Assert(!cl.Module.IsDefaultModule); // default module is not marked \":extern\"\n        return IdProtect(cl.Module.CompileName);\n      } else if (Attributes.Contains(cl.Attributes, \"extern\")) {\n        return IdProtect(cl.Module.CompileName) + \"::\" + IdProtect(cl.Name);\n      } else if (cl is TupleTypeDecl) {\n        var tuple = cl as TupleTypeDecl;\n        return \"Tuple\" + tuple.Dims;\n      } else {\n        return IdProtect(cl.Module.CompileName) + \"::\" + IdProtect(cl.CompileName);\n      }\n    }\n\n    protected override void EmitThis(TargetWriter wr) {\n      wr.Write(\"this\");\n    }\n\n    protected override void EmitDatatypeValue(DatatypeValue dtv, string arguments, TargetWriter wr) {\n      EmitDatatypeValue(dtv, dtv.Ctor, dtv.IsCoCall, arguments, wr);\n    }\n\n    void EmitDatatypeValue(DatatypeValue dtv, DatatypeCtor ctor, bool isCoCall, string arguments, TargetWriter wr) {\n      var dt = dtv.Ctor.EnclosingDatatype;\n      var dtName = dt.CompileName;\n      var ctorName = ctor.CompileName;\n\n      if (dt is TupleTypeDecl) {\n        var tuple = dt as TupleTypeDecl;\n        var types = new List<Type>();\n        foreach (var arg in dtv.Arguments) {\n          types.Add(arg.Type);\n        }\n        wr.Write(\"Tuple{0}{1}({2})\", tuple.Dims, TemplateMethod(types), arguments);\n      } else if (!isCoCall) {\n        // Ordinary constructor (that is, one that does not guard any co-recursive calls)\n        // Generate:  Dt.create_Ctor(arguments)\n        if (dt.Ctors.Count == 1) {\n          wr.Write(\"{3}::{0}{1}({2})\",\n            dtName,\n            TemplateMethod(dt.TypeArgs),\n            arguments,\n            dt.Module.CompileName);\n        } else {\n          wr.Write(\"{4}::{0}{1}::create_{2}({3})\",\n            dtName, ActualTypeArgs(dtv.InferredTypeArgs), ctorName,\n            arguments, dt.Module.CompileName);\n        }\n\n      } else {\n        // Co-recursive call\n        // Generate:  Dt.lazy_Ctor(($dt) => Dt.create_Ctor($dt, args))\n        wr.Write(\"{0}.lazy_{1}(($dt) => \", dtName, ctorName);\n        wr.Write(\"{0}.create_{1}($dt{2}{3})\", dtName, ctorName, arguments.Length == 0 ? \"\" : \", \", arguments);\n        wr.Write(\")\");\n      }\n    }\n\n    protected override void GetSpecialFieldInfo(SpecialField.ID id, object idParam, out string compiledName, out string preString, out string postString) {\n      compiledName = \"\";\n      preString = \"\";\n      postString = \"\";\n      switch (id) {\n        case SpecialField.ID.UseIdParam:\n          compiledName = (string)idParam;\n          break;\n        case SpecialField.ID.ArrayLength:\n        case SpecialField.ID.ArrayLengthInt:\n          throw NotSupported(\"taking an array's length\");\n          //break;\n        case SpecialField.ID.Floor:\n          compiledName = \"int()\";\n          break;\n        case SpecialField.ID.IsLimit:\n          throw NotSupported(\"IsLimit\");\n        case SpecialField.ID.IsSucc:\n          throw NotSupported(\"IsSucc\");\n        case SpecialField.ID.Offset:\n          throw NotSupported(\"Offset\");\n        case SpecialField.ID.IsNat:\n          throw NotSupported(\"IsNat\");\n        case SpecialField.ID.Keys:\n          compiledName = \"dafnyKeySet()\";\n          break;\n        case SpecialField.ID.Values:\n          compiledName = \"dafnyValues()\";\n          break;\n        case SpecialField.ID.Items:\n          compiledName = \"Items()\";\n          break;\n        case SpecialField.ID.Reads:\n          compiledName = \"_reads\";\n          break;\n        case SpecialField.ID.Modifies:\n          compiledName = \"_modifies\";\n          break;\n        case SpecialField.ID.New:\n          compiledName = \"_new\";\n          break;\n        default:\n          Contract.Assert(false); // unexpected ID\n          break;\n      }\n    }\n\n    protected override TargetWriter EmitMemberSelect(MemberDecl member, bool isLValue, Type expectedType, TargetWriter wr) {\n      var wSource = wr.Fork();\n      if (isLValue && member is ConstantField) {\n        wr.Write(\".{0}\", member.Name);\n      } else if (member is DatatypeDestructor dtor && dtor.EnclosingClass is TupleTypeDecl)\n      {\n        throw NotSupported(\"datatype\");\n      } else if (member is SpecialField sf2 && sf2.SpecialId == SpecialField.ID.UseIdParam && sf2.IdParam is string fieldName && fieldName.StartsWith(\"is_\")) {\n        throw NotSupported(\"datatype special field\");\n      } else if (!isLValue && member is SpecialField sf) {\n        throw NotSupported(\"special field\");\n        /*\n        string compiledName, preStr, postStr;\n        GetSpecialFieldInfo(sf.SpecialId, sf.IdParam, out compiledName, out preStr, out postStr);\n        if (sf is ConstantField && !member.IsStatic && compiledName.Length != 0) {\n          wr.Write(\".{0}\", compiledName);\n        } else if (sf.SpecialId == SpecialField.ID.Keys || sf.SpecialId == SpecialField.ID.Values) {\n          wr.Write(\".{0}\", compiledName);\n        } else if (sf is DatatypeDestructor dtor2) {\n          if (dtor2.EnclosingCtors.Count > 1) {\n            NotSupported(String.Format(\"Using the same destructor {0} with multiple constructors is ambiguous\", member.Name), dtor2.tok);\n          }\n          if (!(dtor2.EnclosingClass is IndDatatypeDecl)) {\n            NotSupported(String.Format(\"Unexpected use of a destructor {0} that isn't for an inductive datatype.  Panic!\", member.Name), dtor2.tok);\n          }\n          var dt = dtor2.EnclosingClass as IndDatatypeDecl;\n          if (dt.Ctors.Count > 1) {\n            wr.Write(\".v_{0}.{1}\", dtor2.EnclosingCtors[0].CompileName, sf.CompileName);\n          } else {\n            wr.Write(\".{0}\", sf.CompileName);\n          }\n        } else if (compiledName.Length != 0) {\n          wr.Write(\"::{0}\", compiledName);\n        } else {\n          // this member selection is handled by some kind of enclosing function call, so nothing to do here\n        }*/\n      } else {\n        wr.Write(\".{0}\", member.Name);\n      }\n      return wSource;\n    }\n\n    protected override TargetWriter EmitArraySelect(List<string> indices, Type elmtType, TargetWriter wr) {\n      var w = wr.Fork();\n      foreach (var index in indices) {\n        wr.Write(\"[{0}]\", index);\n      }\n      return w;\n    }\n\n    protected override TargetWriter EmitArraySelect(List<Expression> indices, Type elmtType, bool inLetExprBody, TargetWriter wr) {\n      Contract.Assert(indices != null && 1 <= indices.Count);  // follows from precondition\n      var w = wr.Fork();\n      foreach (var index in indices) {\n        wr.Write(\"[\");\n        TrExpr(index, wr, inLetExprBody);\n        wr.Write(\"]\");\n      }\n      return w;\n    }\n\n    protected override string ArrayIndexToInt(string arrayIndex) {\n      //return string.Format(\"new BigNumber({0})\", arrayIndex);\n      return arrayIndex;\n    }\n\n    protected override void EmitExprAsInt(Expression expr, bool inLetExprBody, TargetWriter wr) {\n      TrParenExpr(expr, wr, inLetExprBody);\n      if (AsNativeType(expr.Type) == null) {\n        wr.Write(\".toNumber()\");\n      }\n    }\n\n    protected override void EmitIndexCollectionSelect(Expression source, Expression index, bool inLetExprBody, TargetWriter wr) {\n      TrParenExpr(source, wr, inLetExprBody);\n      if (source.Type.NormalizeExpand() is SeqType) {\n        // seq\n        wr.Write(\".select(\");\n        TrExpr(index, wr, inLetExprBody);\n        wr.Write(\")\");\n      } else {\n        // map or imap\n        wr.Write(\"[\");\n        TrExpr(index, wr, inLetExprBody);\n        wr.Write(\"]\");\n      }\n    }\n\n    protected override void EmitIndexCollectionUpdate(Expression source, Expression index, Expression value, bool inLetExprBody, TargetWriter wr, bool nativeIndex = false) {\n      TrParenExpr(source, wr, inLetExprBody);\n      wr.Write(\".update(\");\n      TrExpr(index, wr, inLetExprBody);\n      wr.Write(\", \");\n      TrExpr(value, wr, inLetExprBody);\n      wr.Write(\")\");\n    }\n\n    protected override void EmitSeqSelectRange(Expression source, Expression/*?*/ lo, Expression/*?*/ hi, bool fromArray, bool inLetExprBody, TargetWriter wr) {\n      if (fromArray) {\n        string typeName = \"\";\n        if (source.Type is UserDefinedType udt && udt.ResolvedClass != null &&\n            udt.ResolvedClass is TypeSynonymDecl tsd) {\n          // Hack to workaround type synonyms wrapped around the actual array type\n          // TODO: Come up with a more systematic way of resolving this!\n          typeName = TypeName(tsd.Rhs.TypeArgs[0], wr, source.tok, null, true);\n        } else {\n          typeName = TypeName(source.Type.TypeArgs[0], wr, source.tok, null, true);\n        }\n        wr.Write(\"DafnySequence<{0}>::SeqFromArray\", typeName);\n        //var arr = source.Type.AsArrayType;\n        // wr.Write(\"DafnySequence<{0}>::SeqFromArray\", TypeName(arr., wr, source.tok, null, true));\n        //wr.Write(\"DafnySequence<{0}>::SeqFromArray\", IdName(source.GetType().AsArrayType.TypeArgs[0]));\n      }\n      TrParenExpr(source, wr, inLetExprBody);\n\n      if (hi != null) {\n        TrParenExpr(\".take\", hi, wr, inLetExprBody);\n      }\n      if (lo != null) {\n        TrParenExpr(\".drop\", lo, wr, inLetExprBody);\n      }\n    }\n\n    protected override void EmitSeqConstructionExpr(SeqConstructionExpr expr, bool inLetExprBody, TargetWriter wr) {\n      wr.Write(\"DafnySequence<{0}>::Create(\", TypeName(expr.Type, wr, expr.tok, null, true));\n      TrExpr(expr.N, wr, inLetExprBody);\n      wr.Write(\", \");\n      TrExpr(expr.Initializer, wr, inLetExprBody);\n      wr.Write(\")\");\n    }\n\n    protected override void EmitMultiSetFormingExpr(MultiSetFormingExpr expr, bool inLetExprBody, TargetWriter wr) {\n      TrParenExpr(\"_dafny.MultiSet.FromArray\", expr.E, wr, inLetExprBody);\n    }\n\n    protected override void EmitApplyExpr(Type functionType, Bpl.IToken tok, Expression function, List<Expression> arguments, bool inLetExprBody, TargetWriter wr) {\n      TrParenExpr(function, wr, inLetExprBody);\n      TrExprList(arguments, wr, inLetExprBody);\n    }\n\n    protected override TargetWriter EmitBetaRedex(List<string> boundVars, List<Expression> arguments, string typeArgs, List<Type> boundTypes, Type resultType, Bpl.IToken tok, bool inLetExprBody, TargetWriter wr) {\n      wr.Write(\"(({0}) => \", Util.Comma(boundVars));\n      var w = wr.Fork();\n      wr.Write(\")\");\n      TrExprList(arguments, wr, inLetExprBody);\n      return w;\n    }\n\n    protected override void EmitConstructorCheck(string source, DatatypeCtor ctor, TargetWriter wr) {\n      wr.Write(\"is_{1}({0})\", source, ctor.CompileName);\n    }\n\n    protected override void EmitDestructor(string source, Formal dtor, int formalNonGhostIndex, DatatypeCtor ctor, List<Type> typeArgs, Type bvType, TargetWriter wr) {\n      if (ctor.EnclosingDatatype is TupleTypeDecl) {\n        wr.Write(\"({0})[{1}]\", source, formalNonGhostIndex);\n      } else {\n        var dtorName = FormalName(dtor, formalNonGhostIndex);\n        wr.Write(\"({0}){1}.v_{3}.{2}\", source, ctor.EnclosingDatatype is CoDatatypeDecl ? \"._D()\" : \"\", dtorName, ctor.CompileName);\n      }\n    }\n\n    protected override BlockTargetWriter CreateLambda(List<Type> inTypes, Bpl.IToken tok, List<string> inNames, Type resultType, TargetWriter wr, bool untyped = false) {\n      wr.Write(\"function (\");\n      Contract.Assert(inTypes.Count == inNames.Count);  // guaranteed by precondition\n      for (var i = 0; i < inNames.Count; i++) {\n        wr.Write(\"{0}{1}\", i == 0 ? \"\" : \", \", inNames[i]);\n      }\n      var w = wr.NewExprBlock(\")\");\n      return w;\n    }\n\n    protected override TargetWriter CreateIIFE_ExprBody(Expression source, bool inLetExprBody, Type sourceType, Bpl.IToken sourceTok, Type resultType, Bpl.IToken resultTok, string bvName, TargetWriter wr) {\n      throw NotSupported(\"CreateIIFE_ExprBody-A\", sourceTok);\n      /*var w = wr.NewExprBlock(\"function ({0})\", bvName);\n      w.Write(\"return \");\n      w.BodySuffix = \";\" + w.NewLine;\n      TrParenExpr(source, wr, inLetExprBody);\n      return w;*/\n    }\n\n    protected override TargetWriter CreateIIFE_ExprBody(string source, Type sourceType, Bpl.IToken sourceTok, Type resultType, Bpl.IToken resultTok, string bvName, TargetWriter wr) {\n      throw NotSupported(\"CreateIIFE_ExprBody-B\", sourceTok);\n      /*var w = wr.NewExprBlock(\"function ({0})\", bvName);\n      w.Write(\"return \");\n      w.BodySuffix = \";\" + w.NewLine;\n      wr.Write(\"({0})\", source);\n      return w;*/\n    }\n\n    protected override BlockTargetWriter CreateIIFE0(Type resultType, Bpl.IToken resultTok, TargetWriter wr) {\n      //throw NotSupported(\"CreateIIFE0\", resultTok);\n      var w = wr.NewBigExprBlock(\"[&] \", \" ()\");\n      return w;\n    }\n\n    protected override BlockTargetWriter CreateIIFE1(int source, Type resultType, Bpl.IToken resultTok, string bvName, TargetWriter wr) {\n      throw NotSupported(\"CreateIIFE1\", resultTok);\n      /*var w = wr.NewExprBlock(\"function ({0})\", bvName);\n      wr.Write(\"({0})\", source);\n      return w;*/\n    }\n\n    protected override void EmitUnaryExpr(ResolvedUnaryOp op, Expression expr, bool inLetExprBody, TargetWriter wr) {\n      switch (op) {\n        case ResolvedUnaryOp.BoolNot:\n          TrParenExpr(\"!\", expr, wr, inLetExprBody);\n          break;\n        case ResolvedUnaryOp.BitwiseNot:\n          if (AsNativeType(expr.Type) != null) {\n            wr.Write(\"~ \");\n            TrParenExpr(expr, wr, inLetExprBody);\n          } else {\n            TrParenExpr(expr, wr, inLetExprBody);\n            wr.Write(\".Not()\");\n          }\n          break;\n        case ResolvedUnaryOp.Cardinality:\n          TrParenExpr(expr, wr, inLetExprBody);\n          wr.Write(\".size()\");\n          break;\n        case ResolvedUnaryOp.Dereference:\n          TrParenExpr(\"*\" ,expr, wr, inLetExprBody);\n          break;\n        case ResolvedUnaryOp.AddressOf:\n          TrParenExpr(\"&\" ,expr, wr, inLetExprBody);\n          break;\n        default:\n          Contract.Assert(false); throw new cce.UnreachableException();  // unexpected unary expression\n      }\n    }\n\n    bool IsDirectlyComparable(Type t) {\n      Contract.Requires(t != null);\n      return t.IsBoolType || t.IsCharType || AsNativeType(t) != null;\n    }\n\n    protected override void CompileBinOp(BinaryExpr.ResolvedOpcode op,\n      Expression e0, Expression e1, Bpl.IToken tok, Type resultType,\n      out string opString,\n      out string preOpString,\n      out string postOpString,\n      out string callString,\n      out string staticCallString,\n      out bool reverseArguments,\n      out bool truncateResult,\n      out bool convertE1_to_int,\n      TextWriter errorWr) {\n\n      opString = null;\n      preOpString = \"\";\n      postOpString = \"\";\n      callString = null;\n      staticCallString = null;\n      reverseArguments = false;\n      truncateResult = false;\n      convertE1_to_int = false;\n\n      switch (op) {\n        case BinaryExpr.ResolvedOpcode.Iff:\n          opString = \"==\"; break;\n        case BinaryExpr.ResolvedOpcode.Imp:\n          preOpString = \"!\"; opString = \"||\"; break;\n        case BinaryExpr.ResolvedOpcode.Or:\n          opString = \"||\"; break;\n        case BinaryExpr.ResolvedOpcode.And:\n          opString = \"&&\"; break;\n        case BinaryExpr.ResolvedOpcode.BitwiseAnd:\n          if (AsNativeType(resultType) != null) {\n            opString = \"&\";\n          } else {\n            callString = \"And\";\n          }\n          break;\n        case BinaryExpr.ResolvedOpcode.BitwiseOr:\n          if (AsNativeType(resultType) != null) {\n            opString = \"|\";\n          } else {\n            callString = \"Or\";\n          }\n          break;\n        case BinaryExpr.ResolvedOpcode.BitwiseXor:\n          if (AsNativeType(resultType) != null) {\n            opString = \"^\";\n          } else {\n            callString = \"Xor\";\n          }\n          break;\n\n        case BinaryExpr.ResolvedOpcode.EqCommon: {\n            if (IsHandleComparison(tok, e0, e1, errorWr)) {\n              opString = \"==\";\n            } else if (IsDirectlyComparable(e0.Type)) {\n              opString = \"==\";\n            } else if (e0.Type.IsRefType) {\n              opString = \"==\";\n            } else {\n              //staticCallString = \"==\";\n              opString = \"==\";\n            }\n            break;\n          }\n        case BinaryExpr.ResolvedOpcode.NeqCommon: {\n            if (IsHandleComparison(tok, e0, e1, errorWr)) {\n              opString = \"!=\";\n              postOpString = \"/* handle */\";\n            } else if (IsDirectlyComparable(e0.Type)) {\n              opString = \"!=\";\n            } else if (e0.Type.IsRefType) {\n              opString = \"!=\";\n            } else {\n              opString = \"!=\";\n              //preOpString = \"!\";\n              //staticCallString = \"_dafny.AreEqual\";\n            }\n            break;\n          }\n\n        case BinaryExpr.ResolvedOpcode.Lt:\n        case BinaryExpr.ResolvedOpcode.LtChar:\n          opString = \"<\";\n          break;\n        case BinaryExpr.ResolvedOpcode.Le:\n        case BinaryExpr.ResolvedOpcode.LeChar:\n          opString = \"<=\";\n          break;\n        case BinaryExpr.ResolvedOpcode.Ge:\n        case BinaryExpr.ResolvedOpcode.GeChar:\n          opString = \">=\";\n          break;\n        case BinaryExpr.ResolvedOpcode.Gt:\n        case BinaryExpr.ResolvedOpcode.GtChar:\n          opString = \">\";\n          break;\n        case BinaryExpr.ResolvedOpcode.LeftShift:\n          if (resultType.IsBitVectorType) {\n            truncateResult = true;\n          }\n          if (AsNativeType(resultType) != null) {\n            opString = \"<<\";\n          } else {\n            if (AsNativeType(e1.Type) != null) {\n              callString = \"Lsh(_dafny.IntOfUint64(uint64\";\n              postOpString = \"))\";\n            } else {\n              callString = \"Lsh\";\n            }\n          }\n          break;\n        case BinaryExpr.ResolvedOpcode.RightShift:\n          if (AsNativeType(resultType) != null) {\n            opString = \">>\";\n            if (AsNativeType(e1.Type) == null) {\n              postOpString = \".Uint64()\";\n            }\n          } else {\n            if (AsNativeType(e1.Type) != null) {\n              callString = \"Rsh(_dafny.IntOfUint64(uint64\";\n              postOpString = \"))\";\n            } else {\n              callString = \"Rsh\";\n            }\n          }\n          break;\n        case BinaryExpr.ResolvedOpcode.Add:\n          if (resultType.IsBitVectorType) {\n            truncateResult = true;\n          }\n          if (resultType.IsCharType || AsNativeType(resultType) != null || resultType is PointerType) {\n            opString = \"+\";\n          } else {\n            callString = \"Plus\";\n          }\n          break;\n        case BinaryExpr.ResolvedOpcode.Sub:\n          if (resultType.IsBitVectorType) {\n            truncateResult = true;\n          }\n          if (resultType.IsCharType || AsNativeType(resultType) != null) {\n            opString = \"-\";\n          } else {\n            callString = \"Minus\";\n          }\n          break;\n        case BinaryExpr.ResolvedOpcode.Mul:\n          if (resultType.IsBitVectorType) {\n            truncateResult = true;\n          }\n          if (AsNativeType(resultType) != null) {\n            opString = \"*\";\n          } else {\n            callString = \"Times\";\n          }\n          break;\n        case BinaryExpr.ResolvedOpcode.Div:\n          if (AsNativeType(resultType) != null) {\n            var nt = AsNativeType(resultType);\n            if (nt.LowerBound < BigInteger.Zero) {\n              // Want Euclidean division for signed types\n              //staticCallString =  \"_dafny.Div\" + Capitalize(GetNativeTypeName(AsNativeType(resultType)));\n              //TODO(xueyuanz): using native division for all types\n              opString = \"/\";\n            } else {\n              // Native division is fine for unsigned\n              opString = \"/\";\n            }\n          } else {\n            callString = \"DivBy\";\n          }\n          break;\n        case BinaryExpr.ResolvedOpcode.Mod:\n          if (AsNativeType(resultType) != null) {\n            var nt = AsNativeType(resultType);\n            if (nt.LowerBound < BigInteger.Zero) {\n              // Want Euclidean division for signed types\n              //staticCallString = \"_dafny.Mod\" + Capitalize(GetNativeTypeName(AsNativeType(resultType)));\n              //TODO(xueyuanz): using native mod for all types\n              opString = \"%\";\n            } else {\n              // Native division is fine for unsigned\n              opString = \"%\";\n            }\n          } else {\n            callString = \"Modulo\";\n          }\n          break;\n        case BinaryExpr.ResolvedOpcode.SetEq:\n        case BinaryExpr.ResolvedOpcode.MultiSetEq:\n        case BinaryExpr.ResolvedOpcode.MapEq:\n        case BinaryExpr.ResolvedOpcode.SeqEq:\n          callString = \"equals\"; break;\n        case BinaryExpr.ResolvedOpcode.SetNeq:\n        case BinaryExpr.ResolvedOpcode.MultiSetNeq:\n        case BinaryExpr.ResolvedOpcode.MapNeq:\n        case BinaryExpr.ResolvedOpcode.SeqNeq:\n          preOpString = \"!\"; callString = \"equals\"; break;\n        case BinaryExpr.ResolvedOpcode.ProperSubset:\n        case BinaryExpr.ResolvedOpcode.ProperMultiSubset:\n          callString = \"IsProperSubsetOf\"; break;\n        case BinaryExpr.ResolvedOpcode.Subset:\n        case BinaryExpr.ResolvedOpcode.MultiSubset:\n          callString = \"IsSubsetOf\"; break;\n        case BinaryExpr.ResolvedOpcode.Superset:\n        case BinaryExpr.ResolvedOpcode.MultiSuperset:\n          callString = \"IsSupersetOf\"; break;\n        case BinaryExpr.ResolvedOpcode.ProperSuperset:\n        case BinaryExpr.ResolvedOpcode.ProperMultiSuperset:\n          callString = \"IsProperSupersetOf\"; break;\n        case BinaryExpr.ResolvedOpcode.Disjoint:\n        case BinaryExpr.ResolvedOpcode.MultiSetDisjoint:\n        case BinaryExpr.ResolvedOpcode.MapDisjoint:\n          callString = \"IsDisjointFrom\"; break;\n        case BinaryExpr.ResolvedOpcode.InSet:\n        case BinaryExpr.ResolvedOpcode.InMultiSet:\n        case BinaryExpr.ResolvedOpcode.InMap:\n          callString = \"contains\"; reverseArguments = true; break;\n        case BinaryExpr.ResolvedOpcode.NotInSet:\n        case BinaryExpr.ResolvedOpcode.NotInMultiSet:\n        case BinaryExpr.ResolvedOpcode.NotInMap:\n          preOpString = \"!\"; callString = \"contains\"; reverseArguments = true; break;\n        case BinaryExpr.ResolvedOpcode.Union:\n        case BinaryExpr.ResolvedOpcode.MultiSetUnion:\n          callString = \"Union\"; break;\n        case BinaryExpr.ResolvedOpcode.Intersection:\n        case BinaryExpr.ResolvedOpcode.MultiSetIntersection:\n          callString = \"Intersection\"; break;\n        case BinaryExpr.ResolvedOpcode.SetDifference:\n        case BinaryExpr.ResolvedOpcode.MultiSetDifference:\n          callString = \"Difference\"; break;\n\n        case BinaryExpr.ResolvedOpcode.ProperPrefix:\n          callString = \"IsProperPrefixOf\"; break;\n        case BinaryExpr.ResolvedOpcode.Prefix:\n          callString = \"IsPrefixOf\"; break;\n        case BinaryExpr.ResolvedOpcode.Concat:\n          callString = \"concatenate\"; break;\n        case BinaryExpr.ResolvedOpcode.InSeq:\n          callString = \"contains\"; reverseArguments = true; break;\n        case BinaryExpr.ResolvedOpcode.NotInSeq:\n          preOpString = \"!\"; callString = \"contains\"; reverseArguments = true; break;\n\n        default:\n          Contract.Assert(false); throw new cce.UnreachableException();  // unexpected binary expression\n      }\n    }\n\n    protected override void EmitIsZero(string varName, TargetWriter wr) {\n      wr.Write(\"{0}.Cmp(_dafny.Zero) == 0\", varName);\n    }\n\n    protected override void EmitConversionExpr(ConversionExpr e, bool inLetExprBody, TargetWriter wr) {\n      if (e.E.Type.IsNumericBased(Type.NumericPersuation.Int) || e.E.Type.IsBitVectorType || e.E.Type.IsCharType) {\n        if (e.ToType.IsNumericBased(Type.NumericPersuation.Real)) {\n          // (int or bv) -> real\n          Contract.Assert(AsNativeType(e.ToType) == null);\n          wr.Write(\"_dafny.RealOfFrac(\");\n          TargetWriter w;\n          if (AsNativeType(e.E.Type) is NativeType nt) {\n            wr.Write(\"_dafny.IntOf{0}(\", Capitalize(GetNativeTypeName(nt)));\n            w = wr.Fork();\n            wr.Write(\")\");\n          } else {\n            w = wr;\n          }\n          TrParenExpr(e.E, w, inLetExprBody);\n          wr.Write(\", _dafny.One)\");\n        } else if (e.ToType.IsCharType) {\n          wr.Write(\"_dafny.Char(\");\n          TrParenExpr(e.E, wr, inLetExprBody);\n          wr.Write(\".Int32())\");\n        } else {\n          // (int or bv or char) -> (int or bv or ORDINAL)\n          var fromNative = AsNativeType(e.E.Type);\n          var toNative = AsNativeType(e.ToType);\n          if (fromNative != null && toNative != null) {\n            // from a native, to a native -- simple!\n            wr.Write(GetNativeTypeName(toNative));\n            TrParenExpr(e.E, wr, inLetExprBody);\n          } else if (e.E.Type.IsCharType) {\n            Contract.Assert(fromNative == null);\n            if (toNative == null) {\n              // char -> big-integer (int or bv or ORDINAL)\n              wr.Write(\"_dafny.IntOfInt32(rune(\");\n              TrExpr(e.E, wr, inLetExprBody);\n              wr.Write(\"))\");\n            } else {\n              // char -> native\n              wr.Write(GetNativeTypeName(toNative));\n              TrParenExpr(e.E, wr, inLetExprBody);\n            }\n          } else if (fromNative == null && toNative == null) {\n            // big-integer (int or bv) -> big-integer (int or bv or ORDINAL), so identity will do\n            TrExpr(e.E, wr, inLetExprBody);\n          } else if (fromNative != null) {\n            Contract.Assert(toNative == null); // follows from other checks\n\n            // native (int or bv) -> big-integer (int or bv)\n            wr.Write(\"_dafny.IntOf{0}(\", Capitalize(GetNativeTypeName(fromNative)));\n            TrExpr(e.E, wr, inLetExprBody);\n            wr.Write(')');\n          } else {\n            // any (int or bv) -> native (int or bv)\n            // Consider some optimizations\n            var literal = PartiallyEvaluate(e.E);\n            UnaryOpExpr u = e.E.Resolved as UnaryOpExpr;\n            MemberSelectExpr m = e.E.Resolved as MemberSelectExpr;\n            if (literal != null) {\n              // Optimize constant to avoid intermediate BigInteger\n              wr.Write(\"{0}({1})\", GetNativeTypeName(toNative), literal);\n            } else if (u != null && u.Op == UnaryOpExpr.Opcode.Cardinality) {\n              // Optimize .Count to avoid intermediate BigInteger\n              wr.Write(\"{0}(\", GetNativeTypeName(toNative));\n              TrParenExpr(u.E, wr, inLetExprBody);\n              wr.Write(\".CardinalityInt())\");\n            } else if (m != null && m.MemberName == \"Length\" && m.Obj.Type.IsArrayType) {\n              // Optimize .Length to avoid intermediate BigInteger\n              wr.Write(\"{0}(\", GetNativeTypeName(toNative));\n              TrParenExpr(m.Obj, wr, inLetExprBody);\n              wr.Write(\".LenInt(0))\");\n            } else {\n              // no optimization applies; use the standard translation\n              TrParenExpr(e.E, wr, inLetExprBody);\n              wr.Write(\".{0}()\", Capitalize(GetNativeTypeName(toNative)));\n            }\n\n          }\n        }\n      } else if (e.E.Type.IsNumericBased(Type.NumericPersuation.Real)) {\n        Contract.Assert(AsNativeType(e.E.Type) == null);\n        if (e.ToType.IsNumericBased(Type.NumericPersuation.Real)) {\n          // real -> real\n          Contract.Assert(AsNativeType(e.ToType) == null);\n          TrExpr(e.E, wr, inLetExprBody);\n        } else {\n          // real -> (int or bv)\n          TrParenExpr(e.E, wr, inLetExprBody);\n          wr.Write(\".Int()\");\n          if (AsNativeType(e.ToType) is NativeType nt) {\n            wr.Write(\".{0}()\", Capitalize(GetNativeTypeName(nt)));\n          }\n        }\n      } else {\n        Contract.Assert(e.E.Type.IsBigOrdinalType);\n        Contract.Assert(e.ToType.IsNumericBased(Type.NumericPersuation.Int));\n        // identity will do\n        TrExpr(e.E, wr, inLetExprBody);\n      }\n    }\n\n    protected override void EmitCollectionDisplay(CollectionType ct, Bpl.IToken tok, List<Expression> elements, bool inLetExprBody, TargetWriter wr)\n    {\n      throw NotSupported(\"Collection\");\n      /*if (ct is SetType) {\n        wr.Write(\"DafnySet<{0}>::Create({{\", TypeName(ct.TypeArgs[0], wr, tok, null, false));\n        for (var i = 0; i < elements.Count; i++) {\n          TrExpr(elements[i], wr, inLetExprBody);\n          if (i < elements.Count - 1)  {\n            wr.Write(\",\");\n          }\n        }\n        wr.Write(\"})\");\n      } else if (ct is MultiSetType) {\n        throw NotSupported(\"EmitCollectionDisplay/multiset\", tok);\n        wr.Write(\"_dafny.MultiSet.fromElements\");\n        TrExprList(elements, wr, inLetExprBody);\n      } else {\n        Contract.Assert(ct is SeqType);  // follows from precondition\n        TargetWriter wrElements;\n        if (ct.Arg.IsCharType) {\n          throw NotSupported(\"EmitCollectionDisplay/string\", tok);\n          // We're really constructing a string.\n          // TODO: It may be that ct.Arg is a type parameter that may stand for char. We currently don't catch that case here.\n          wr.Write(\"[\");\n          wrElements = wr.Fork();\n          wr.Write(\"].join(\\\"\\\")\");\n        } else\n        {\n          wr.Write(\"DafnySequence<{0}>::Create({{\", TypeName(ct.TypeArgs[0], wr, tok, null, false));\n          for (var i = 0; i < elements.Count; i++) {\n            TrExpr(elements[i], wr, inLetExprBody);\n            if (i < elements.Count - 1)  {\n              wr.Write(\",\");\n            }\n          }\n          wr.Write(\"})\");\n        }\n\n\n\n        string sep = \"\";\n        foreach (var e in elements) {\n          wrElements.Write(sep);\n          TrExpr(e, wrElements, inLetExprBody);\n          sep = \", \";\n        }\n      }*/\n    }\n\n    protected override void EmitMapDisplay(MapType mt, Bpl.IToken tok, List<ExpressionPair> elements, bool inLetExprBody, TargetWriter wr) {\n      wr.Write(\"DafnyMap<{0},{1}>::Create({{\",\n               TypeName(mt.TypeArgs[0], wr, tok, null, false),\n               TypeName(mt.TypeArgs[1], wr, tok, null, false));\n      string sep = \"\";\n      foreach (ExpressionPair p in elements) {\n        wr.Write(sep);\n        wr.Write(\"{\");\n        TrExpr(p.A, wr, inLetExprBody);\n        wr.Write(\",\");\n        TrExpr(p.B, wr, inLetExprBody);\n        wr.Write(\"}\");\n        sep = \", \";\n      }\n      wr.Write(\"})\");\n    }\n\n    protected override void EmitCollectionBuilder_New(CollectionType ct, Bpl.IToken tok, TargetWriter wr) {\n\n      if (ct is SetType) {\n        wr.Write(\"DafnySet<{0}>()\", TypeName(ct.TypeArgs[0], wr, tok, null, false));\n      } else {\n        throw NotSupported(\"EmitCollectionBuilder_New/non_set\", tok);\n      }\n\n      /*\n      else if (ct is MultiSetType) {\n        wr.Write(\"new _dafny.MultiSet()\");\n      } else if (ct is MapType) {\n        wr.Write(\"new _dafny.Map()\");\n      } else {\n        Contract.Assume(false);  // unepxected collection type\n      }\n      */\n    }\n\n    protected override void EmitCollectionBuilder_Add(CollectionType ct, string collName, Expression elmt, bool inLetExprBody, TargetWriter wr) {\n      Contract.Assume(ct is SetType || ct is MultiSetType);  // follows from precondition\n      if (ct is MultiSetType) {\n        throw NotSupported(\"EmitCollectionBuilder_Add/MultiSetType\");\n      }\n      wr.Write(\"{0}.set.emplace(\", collName);\n      TrExpr(elmt, wr, inLetExprBody);\n      wr.WriteLine(\");\");\n    }\n\n    protected override TargetWriter EmitMapBuilder_Add(MapType mt, Bpl.IToken tok, string collName, Expression term, bool inLetExprBody, TargetWriter wr) {\n      throw NotSupported(\"EmitMapBuilder_Add\", tok);\n      /*wr.Write(\"{0}.push([\", collName);\n      var termLeftWriter = wr.Fork();\n      wr.Write(\",\");\n      TrExpr(term, wr, inLetExprBody);\n      wr.WriteLine(\"]);\");\n      return termLeftWriter;*/\n    }\n\n    protected override string GetCollectionBuilder_Build(CollectionType ct, Bpl.IToken tok, string collName, TargetWriter wr) {\n      // collections are built in place\n      return collName;\n    }\n\n    protected override void EmitSingleValueGenerator(Expression e, bool inLetExprBody, string type, TargetWriter wr) {\n      TrParenExpr(\"_dafny.SingleValue\", e, wr, inLetExprBody);\n    }\n\n    // ----- Target compilation and execution -------------------------------------------------------------\n\n    public override bool CompileTargetProgram(string dafnyProgramName, string targetProgramText, string/*?*/ callToMain, string/*?*/ targetFilename, ReadOnlyCollection<string> otherFileNames,\n      bool hasMain, bool runAfterCompile, TextWriter outputWriter, out object compilationResult) {\n      compilationResult = null;\n      throw NotSupported(\"Compilation of C++ files is not yet supported\");\n    }\n\n    public override bool RunTargetProgram(string dafnyProgramName, string targetProgramText, string/*?*/ callToMain, string targetFilename, ReadOnlyCollection<string> otherFileNames,\n      object compilationResult, TextWriter outputWriter) {\n        throw NotSupported(\"Running C++ programs is not yet supported\");\n    }\n  }\n\n\n}\n"
  },
  {
    "path": "Source/Armada/Compiler.cs",
    "content": "//-----------------------------------------------------------------------------\n//\n// Copyright (C) Microsoft Corporation.  All Rights Reserved.\n//\n//-----------------------------------------------------------------------------\nusing System;\nusing System.CodeDom;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Numerics;\nusing System.IO;\nusing System.Diagnostics.Contracts;\nusing Bpl = Microsoft.Boogie;\nusing System.Collections.ObjectModel;\nusing System.Diagnostics.SymbolStore;\nusing System.Net.Security;\nusing System.Text;\n\n\nnamespace Microsoft.Armada {\n  public abstract class Compiler {\n    public Compiler(ErrorReporter reporter) {\n      Reporter = reporter;\n    }\n\n    public abstract string TargetLanguage { get; }\n\n    Stack<TargetWriter> copyInstrWriters = new Stack<TargetWriter>(); // a buffer that stores copy instructions generated by letExpr that uses out param.\n    protected TopLevelDeclWithMembers thisContext;  // non-null when type members are being translated\n    protected Method enclosingMethod;  // non-null when a method body is being translated\n\n    FreshIdGenerator idGenerator = new FreshIdGenerator();\n\n    static FreshIdGenerator compileNameIdGenerator = new FreshIdGenerator();\n    public static string FreshId() {\n      return compileNameIdGenerator.FreshNumericId();\n    }\n    public static string FreshId(string prefix) {\n      return compileNameIdGenerator.FreshId(prefix);\n    }\n\n    Dictionary<Expression, int> uniqueAstNumbers = new Dictionary<Expression, int>();\n    int GetUniqueAstNumber(Expression expr) {\n      Contract.Requires(expr != null);\n      int n;\n      if (!uniqueAstNumbers.TryGetValue(expr, out n)) {\n        n = uniqueAstNumbers.Count;\n        uniqueAstNumbers.Add(expr, n);\n      }\n      return n;\n    }\n\n    public ErrorReporter Reporter;\n\n    protected void Error(Bpl.IToken tok, string msg, TextWriter/*?*/ wr, params object[] args) {\n      Contract.Requires(msg != null);\n      Contract.Requires(args != null);\n\n      Reporter.Error(MessageSource.Compiler, tok, msg, args);\n      if (wr is TargetWriter tw) {\n        tw.WriteError(\"/* {0} */\", string.Format(\"Compilation error: \" + msg, args));\n      } else if (wr != null) {\n        wr.WriteLine(\"/* {0} */\", string.Format(\"Compilation error: \" + msg, args));\n      }\n    }\n\n    protected string IntSelect = \",int\";\n    protected string LambdaExecute = \"\";\n\n    protected virtual void EmitHeader(Program program, TargetWriter wr) { }\n    protected virtual void EmitFooter(Program program, TargetWriter wr) { }\n    protected virtual void EmitBuiltInDecls(BuiltIns builtIns, TargetWriter wr) { }\n    /// <summary>\n    /// Emits a call to \"mainMethod\" as the program's entry point, if such an explicit call is\n    /// required in the target language.\n    /// </summary>\n    public virtual void EmitCallToMain(Method mainMethod, TargetWriter wr) { }\n    /// <summary>\n    /// Creates a static Main method. The caller will fill the body of this static Main with a\n    /// call to the instance Main method in the enclosing class.\n    /// </summary>\n    protected abstract BlockTargetWriter CreateStaticMain(IClassWriter wr);\n    protected abstract TargetWriter CreateModule(string moduleName, bool isDefault, bool isExtern, string/*?*/ libraryName, TargetWriter wr);\n    protected abstract string GetHelperModuleName();\n    protected interface IClassWriter {\n      BlockTargetWriter/*?*/ CreateMethod(Method m, bool createBody);\n      BlockTargetWriter/*?*/ CreateFunction(string name, List<TypeParameter>/*?*/ typeArgs, List<Formal> formals, Type resultType, Bpl.IToken tok, bool isStatic, bool createBody, MemberDecl member);\n      BlockTargetWriter/*?*/ CreateGetter(string name, Type resultType, Bpl.IToken tok, bool isStatic, bool createBody, MemberDecl/*?*/ member);  // returns null iff !createBody\n      BlockTargetWriter/*?*/ CreateGetterSetter(string name, Type resultType, Bpl.IToken tok, bool isStatic, bool createBody, MemberDecl/*?*/ member, out TargetWriter setterWriter);  // if createBody, then result and setterWriter are non-null, else both are null\n\n      void DeclareField(string name, List<TypeParameter> targs, bool isStatic, bool isConst, Type type, Bpl.IToken tok, string rhs);\n      //void DeclareField(string name, bool isStatic, bool isConst, Type type, Bpl.IToken tok, string rhs);\n      TextWriter/*?*/ ErrorWriter();\n      void Finish();\n    }\n    protected IClassWriter CreateClass(string name, List<TypeParameter>/*?*/ typeParameters, TargetWriter wr) {\n      return CreateClass(name, false, null, typeParameters, null, null, wr);\n    }\n    /// <summary>\n    /// \"tok\" can be \"null\" if \"superClasses\" is.\n    /// </summary>\n    protected abstract IClassWriter CreateClass(string name, bool isExtern, string/*?*/ fullPrintName, List<TypeParameter>/*?*/ typeParameters, List<Type>/*?*/ superClasses, Bpl.IToken tok, TargetWriter wr);\n    /// <summary>\n    /// \"tok\" can be \"null\" if \"superClasses\" is.\n    /// </summary>\n    protected abstract IClassWriter CreateTrait(string name, bool isExtern, List<Type>/*?*/ superClasses, Bpl.IToken tok, TargetWriter wr);\n    /// If this returns false, it is assumed that the implementation handles inherited fields on its own.\n    protected virtual bool NeedsWrappersForInheritedFields { get => true; }\n    protected virtual bool SupportsProperties { get => true; }\n    protected abstract BlockTargetWriter CreateIterator(IteratorDecl iter, TargetWriter wr);\n    /// <summary>\n    /// Returns an IClassWriter that can be used to write additional members. If \"dt\" is already written\n    /// in the DafnyRuntime.targetlanguage file, then returns \"null\".\n    /// </summary>\n    protected abstract IClassWriter/*?*/ DeclareDatatype(DatatypeDecl dt, TargetWriter wr);\n    /// <summary>\n    /// Returns an IClassWriter that can be used to write additional members.\n    /// </summary>\n    protected abstract IClassWriter DeclareNewtype(NewtypeDecl nt, TargetWriter wr);\n    protected abstract void DeclareSubsetType(SubsetTypeDecl sst, TargetWriter wr);\n    protected string GetNativeTypeName(NativeType nt) {\n      Contract.Requires(nt != null);\n      string nativeName = null, literalSuffix = null;\n      bool needsCastAfterArithmetic = false;\n      GetNativeInfo(nt.Sel, out nativeName, out literalSuffix, out needsCastAfterArithmetic);\n      return nativeName;\n    }\n    protected virtual void GetNativeInfo(NativeType.Selection sel, out string name, out string literalSuffix, out bool needsCastAfterArithmetic) {\n      switch (sel) {\n        case NativeType.Selection.Byte:\n          name = \"byte\"; literalSuffix = \"\"; needsCastAfterArithmetic = true;\n          break;\n        case NativeType.Selection.SByte:\n          name = \"sbyte\"; literalSuffix = \"\"; needsCastAfterArithmetic = true;\n          break;\n        case NativeType.Selection.UShort:\n          name = \"ushort\"; literalSuffix = \"\"; needsCastAfterArithmetic = true;\n          break;\n        case NativeType.Selection.Short:\n          name = \"short\"; literalSuffix = \"\"; needsCastAfterArithmetic = true;\n          break;\n        case NativeType.Selection.UInt:\n          name = \"uint\"; literalSuffix = \"U\"; needsCastAfterArithmetic = false;\n          break;\n        case NativeType.Selection.Int:\n          name = \"int\"; literalSuffix = \"\"; needsCastAfterArithmetic = false;\n          break;\n        case NativeType.Selection.Number:\n          name = \"number\"; literalSuffix = \"\"; needsCastAfterArithmetic = false;\n          break;\n        case NativeType.Selection.ULong:\n          name = \"ulong\"; literalSuffix = \"UL\"; needsCastAfterArithmetic = false;\n          break;\n        case NativeType.Selection.Long:\n          name = \"long\"; literalSuffix = \"L\"; needsCastAfterArithmetic = false;\n          break;\n        default:\n          Contract.Assert(false);  // unexpected native type\n          throw new cce.UnreachableException();  // to please the compiler\n      }\n    }\n\n    protected List<TypeParameter> UsedTypeParameters(DatatypeDecl dt) {\n      Contract.Requires(dt != null);\n\n      var idt = dt as IndDatatypeDecl;\n      if (idt == null) {\n        return dt.TypeArgs;\n      } else {\n        Contract.Assert(idt.TypeArgs.Count == idt.TypeParametersUsedInConstructionByDefaultCtor.Length);\n        var tps = new List<TypeParameter>();\n        for (int i = 0; i < idt.TypeArgs.Count; i++) {\n          if (idt.TypeParametersUsedInConstructionByDefaultCtor[i]) {\n            tps.Add(idt.TypeArgs[i]);\n          }\n        }\n        return tps;\n      }\n    }\n\n    protected void UsedTypeParameters(DatatypeDecl dt, List<Type> typeArgs, out List<TypeParameter> usedTypeFormals, out List<Type> usedTypeArgs) {\n      Contract.Requires(dt != null);\n      Contract.Requires(typeArgs != null);\n      Contract.Requires(dt.TypeArgs.Count == typeArgs.Count);\n      Contract.Ensures(Contract.ValueAtReturn<List<TypeParameter>>(out usedTypeFormals) != null);\n      Contract.Ensures(Contract.ValueAtReturn<List<TypeParameter>>(out usedTypeFormals) != null);\n      Contract.Ensures(Contract.ValueAtReturn<List<TypeParameter>>(out usedTypeFormals).Count == Contract.ValueAtReturn<List<TypeParameter>>(out usedTypeFormals).Count);\n\n      var idt = dt as IndDatatypeDecl;\n      if (idt == null) {\n        usedTypeFormals = dt.TypeArgs;\n        usedTypeArgs = typeArgs;\n      } else {\n        Contract.Assert(typeArgs.Count == idt.TypeParametersUsedInConstructionByDefaultCtor.Length);\n        usedTypeArgs = new List<Type>();\n        usedTypeFormals = new List<TypeParameter>();\n        for (int i = 0; i < typeArgs.Count; i++) {\n          if (idt.TypeParametersUsedInConstructionByDefaultCtor[i]) {\n            usedTypeFormals.Add(dt.TypeArgs[i]);\n            usedTypeArgs.Add(typeArgs[i]);\n          }\n        }\n      }\n    }\n\n    protected virtual int EmitRuntimeTypeDescriptorsActuals(List<Type> typeArgs, List<TypeParameter> formals, Bpl.IToken tok, bool useAllTypeArgs, TargetWriter wr) {\n      Contract.Requires(typeArgs != null);\n      Contract.Requires(formals != null);\n      Contract.Requires(typeArgs.Count == formals.Count);\n      Contract.Requires(tok != null);\n      Contract.Requires(wr != null);\n      return 0;\n    }\n    protected abstract void EmitJumpToTailCallStart(TargetWriter wr);\n    protected abstract string TypeName(Type type, TextWriter wr, Bpl.IToken tok, MemberDecl/*?*/ member = null);\n    public abstract string TypeInitializationValue(Type type, TextWriter/*?*/ wr, Bpl.IToken/*?*/ tok, bool inAutoInitContext);\n    protected abstract string TypeName_UDT(string fullCompileName, List<Type> typeArgs, TextWriter wr, Bpl.IToken tok);\n    protected abstract string/*?*/ TypeName_Companion(Type type, TextWriter wr, Bpl.IToken tok, MemberDecl/*?*/ member);\n    protected string TypeName_Companion(TopLevelDecl cls, TextWriter wr, Bpl.IToken tok) {\n      Contract.Requires(cls != null);\n      Contract.Requires(wr != null);\n      Contract.Requires(tok != null);\n      return TypeName_Companion(UserDefinedType.FromTopLevelDecl(tok, cls), wr, tok, null);\n    }\n    /// Return the \"native form\" of a type, to which EmitCoercionToNativeForm coerces it.\n    protected virtual Type NativeForm(Type type) {\n      return type;\n    }\n\n    protected abstract bool DeclareFormal(string prefix, string name, Type type, Bpl.IToken tok, bool isInParam, TextWriter wr);\n    /// <summary>\n    /// If \"leaveRoomForRhs\" is false and \"rhs\" is null, then generates:\n    ///     type name;\n    /// If \"leaveRoomForRhs\" is false and \"rhs\" is non-null, then generates:\n    ///     type name = rhs;\n    /// If \"leaveRoomForRhs\" is true, in which case \"rhs\" must be null, then generates:\n    ///     type name\n    /// which is intended to be followed up by a call to EmitAssignmentRhs.\n    /// In the above, if \"type\" is null, then it is replaced by \"var\" or \"let\".\n    /// \"tok\" is allowed to be null if \"type\" is.\n    /// </summary>\n    protected abstract void DeclareLocalVar(string name, Type/*?*/ type, Bpl.IToken /*?*/ tok, bool leaveRoomForRhs, string/*?*/ rhs, TargetWriter wr);\n\n    protected virtual void DeclareLocalVar(string name, Type /*?*/ type, Bpl.IToken /*?*/ tok, bool leaveRoomForRhs, string /*?*/ rhs, TargetWriter wr, Type t) {\n      DeclareLocalVar(name, type, tok, leaveRoomForRhs, rhs, wr);\n    }\n    /// <summary>\n    /// Generates:\n    ///     type name = rhs;\n    /// In the above, if \"type\" is null, then it is replaced by \"var\" or \"let\".\n    /// \"tok\" is allowed to be null if \"type\" is.\n    /// </summary>\n    protected virtual void DeclareLocalVar(string name, Type /*?*/ type, Bpl.IToken /*?*/ tok, Expression rhs, bool inLetExprBody, TargetWriter wr) {\n      var w = DeclareLocalVar(name, type, tok, wr);\n      TrExpr(rhs, w, inLetExprBody);\n    }\n\n    protected virtual void DeclareLocalVar(string name, Type /*?*/ type, Bpl.IToken /*?*/ tok, Expression rhs,\n      bool inLetExprBody, TargetWriter wr, Type t){\n      var w = DeclareLocalVar(name, type, tok, wr);\n      TrExpr(rhs, w, inLetExprBody);\n    }\n    /// <summary>\n    /// Generates\n    ///     type name = <<writer returned>>;\n    /// In the above, if \"type\" is null, then it is replaced by \"var\" or \"let\".\n    /// \"tok\" is allowed to be null if \"type\" is.\n    /// </summary>\n    protected abstract TargetWriter DeclareLocalVar(string name, Type/*?*/ type, Bpl.IToken/*?*/ tok, TargetWriter wr);\n    protected virtual void DeclareOutCollector(string collectorVarName, TargetWriter wr) { }  // called only for return-style calls\n    protected virtual void DeclareSpecificOutCollector(string collectorVarName, TargetWriter wr, int outCount, List<Type> types, Method m) {DeclareOutCollector(collectorVarName, wr); } // for languages that don't allow \"let\" or \"var\" expressions\n    protected virtual bool UseReturnStyleOuts(Method m, int nonGhostOutCount) => false;\n    protected virtual BlockTargetWriter EmitMethodReturns(Method m, BlockTargetWriter wr) { return wr; } // for languages that need explicit return statements not provided by Dafny\n    protected virtual bool SupportsMultipleReturns { get => false; }\n    protected virtual bool NeedsCastFromTypeParameter { get => false; }\n    protected virtual bool SupportsAmbiguousTypeDecl { get => true; }\n    protected virtual bool FieldsInTraits { get => true; } // True if language's \"trait\" equivalent allows for non-final field declarations, false otherwise\n    protected virtual void AddTupleToSet(int i) { }\n    public int TargetTupleSize = 0;\n    /// The punctuation that comes at the end of a statement.  Note that\n    /// statements are followed by newlines regardless.\n    protected virtual string StmtTerminator { get => \";\"; }\n    protected void EndStmt(TargetWriter wr) { wr.WriteLine(StmtTerminator); }\n    protected abstract void DeclareLocalOutVar(string name, Type type, Bpl.IToken tok, string rhs, bool useReturnStyleOuts, TargetWriter wr);\n    protected virtual void EmitActualOutArg(string actualOutParamName, TextWriter wr) { }  // actualOutParamName is always the name of a local variable; called only for non-return-style outs\n    protected virtual void EmitOutParameterSplits(string outCollector, List<string> actualOutParamNames, TargetWriter wr) { }  // called only for return-style calls\n    protected virtual void EmitCastOutParameterSplits(string outCollector, List<string> actualOutParamNames, TargetWriter wr, List<Type> actualOutParamTypes, Bpl.IToken tok) {\n      EmitOutParameterSplits(outCollector, actualOutParamNames, wr); }\n\n    protected abstract void EmitActualTypeArgs(List<Type> typeArgs, Bpl.IToken tok, TextWriter wr);\n    protected abstract string GenerateLhsDecl(string target, Type/*?*/ type, TextWriter wr, Bpl.IToken tok);\n\n    protected virtual TargetWriter DeclareLocalVar(string name, Type /*?*/ type, Bpl.IToken /*?*/ tok, TargetWriter wr, Type t){\n      return DeclareLocalVar(name, type, tok, wr);\n    }\n\n    protected virtual void EmitAssignment(out TargetWriter wLhs, Type /*?*/ lhsType, out TargetWriter wRhs, Type /*?*/ rhsType, TargetWriter wr, bool MemberSelectObjIsTrait) {\n      EmitAssignment(out wLhs, lhsType, out wRhs, rhsType, wr);\n    }\n\n    protected virtual void EmitAssignment(out TargetWriter wLhs, Type/*?*/ lhsType, out TargetWriter wRhs, Type/*?*/ rhsType, TargetWriter wr) {\n      wLhs = wr.Fork();\n      wr.Write(\" = \");\n      TargetWriter w;\n      if (rhsType != null) {\n        w = EmitCoercionIfNecessary(from:rhsType, to:lhsType, tok:Bpl.Token.NoToken, wr:wr);\n      } else {\n        w = wr;\n      }\n      wRhs = w.Fork();\n      EndStmt(wr);\n    }\n    protected void EmitAssignment(string lhs, Type/*?*/ lhsType, string rhs, Type/*?*/ rhsType, TargetWriter wr) {\n      EmitAssignment(out var wLhs, lhsType, out var wRhs, rhsType, wr);\n      wLhs.Write(lhs);\n      wRhs.Write(rhs);\n    }\n    protected void EmitAssignmentRhs(string rhs, TargetWriter wr) {\n      var w = EmitAssignmentRhs(wr);\n      w.Write(rhs);\n    }\n    protected void EmitAssignmentRhs(Expression rhs, bool inLetExprBody, TargetWriter wr) {\n      var w = EmitAssignmentRhs(wr);\n      TrExpr(rhs, w, inLetExprBody);\n    }\n    protected virtual TargetWriter EmitAssignmentRhs(TargetWriter wr) {\n      wr.Write(\" = \");\n      var w = wr.Fork();\n      EndStmt(wr);\n      return w;\n    }\n\n    protected virtual void EmitMultiAssignment(out List<TargetWriter> wLhss, List<Type> lhsTypes, out List<TargetWriter> wRhss, List<Type> rhsTypes, TargetWriter wr) {\n      Contract.Assert(lhsTypes.Count == rhsTypes.Count);\n      wLhss = new List<TargetWriter>();\n      wRhss = new List<TargetWriter>();\n      var rhsVars = new List<string>();\n      foreach (var lhsType in lhsTypes) {\n        string target = idGenerator.FreshId(\"_rhs\");\n        rhsVars.Add(target);\n        wr.Write(GenerateLhsDecl(target, lhsType, wr, null));\n        wr.Write(\" = \");\n        wRhss.Add(wr.Fork());\n        EndStmt(wr);\n      }\n\n      Contract.Assert(rhsVars.Count == lhsTypes.Count);\n      for (int i = 0; i < rhsVars.Count; i++) {\n        TargetWriter wLhs, wRhsVar;\n        EmitAssignment(out wLhs, lhsTypes[i], out wRhsVar, rhsTypes[i], wr);\n        wLhss.Add(wLhs);\n        wRhsVar.Write(rhsVars[i]);\n      }\n    }\n\n    protected virtual void EmitSetterParameter(TargetWriter wr) {\n      wr.Write(\"value\");\n    }\n    protected virtual void EmitGotoStmt(TargetWriter wr, string target) {}\n\n    protected virtual void EmitJoinStmt(TargetWriter wr, Expression thread_id) {}\n    protected virtual void EmitFenceStmt(TargetWriter wr) {}\n    protected virtual void EmitDeallocStmt(TargetWriter wr, Expression addr) {}\n    protected abstract void EmitPrintStmt(TargetWriter wr, Expression arg);\n    protected abstract void EmitReturn(List<Formal> outParams, TargetWriter wr);\n    protected virtual void EmitReturnExpr(Expression expr, bool inLetExprBody, TargetWriter wr) {  // emits \"return <expr>;\" for function bodies\n      var w = EmitReturnExpr(wr);\n      TrExpr(expr, w, inLetExprBody);\n    }\n    protected virtual void EmitReturnExpr(string returnExpr, TargetWriter wr) {  // emits \"return <returnExpr>;\" for function bodies\n      var w = EmitReturnExpr(wr);\n      w.Write(returnExpr);\n    }\n    protected virtual TargetWriter EmitReturnExpr(TargetWriter wr) {\n      // emits \"return <returnExpr>;\" for function bodies\n      wr.Write(\"return \");\n      var w = wr.Fork();\n      EndStmt(wr);\n      return w;\n    }\n    /// <summary>\n    /// Labels the code written to the TargetWriter returned, in such that way that any\n    /// emitted break to the label inside that code will abruptly end the execution of the code.\n    /// </summary>\n    protected abstract TargetWriter CreateLabeledCode(string label, TargetWriter wr);\n\n    protected virtual void EmitContinue(TargetWriter wr)\n    {}\n    protected abstract void EmitBreak(string/*?*/ label, TargetWriter wr);\n    protected abstract void EmitYield(TargetWriter wr);\n    protected abstract void EmitAbsurd(string/*?*/ message, TargetWriter wr);\n    protected virtual void EmitAbsurd(string message, TargetWriter wr, bool needIterLimit) {\n      EmitAbsurd(message, wr);\n    }\n\n    protected TargetWriter EmitIf(string guard, bool hasElse, TargetWriter wr) {\n      TargetWriter guardWriter;\n      var thn = EmitIf(out guardWriter, hasElse, wr);\n      guardWriter.Write(guard);\n      return thn;\n    }\n    protected virtual TargetWriter EmitIf(out TargetWriter guardWriter, bool hasElse, TargetWriter wr) {\n      wr.Write(\"if (\");\n      guardWriter = wr.Fork();\n      if (hasElse) {\n        var thn = wr.NewBlock(\")\", \" else\", BlockTargetWriter.BraceStyle.Space, BlockTargetWriter.BraceStyle.Space);\n        return thn;\n      } else {\n        var thn = wr.NewBlock(\")\");\n        return thn;\n      }\n    }\n    protected virtual TargetWriter EmitWhile(List<Statement> body, TargetWriter wr) {  // returns the guard writer\n      TargetWriter guardWriter;\n      var wBody = CreateWhileLoop(out guardWriter, wr);\n      TrStmtList(body, wBody);\n      return guardWriter;\n    }\n\n    protected virtual BlockTargetWriter CreateWhileLoop(out TargetWriter guardWriter, TargetWriter wr) {\n      wr.Write(\"while (\");\n      guardWriter = wr.Fork();\n      var wBody = wr.NewBlock(\")\");\n      return wBody;\n    }\n    protected abstract BlockTargetWriter CreateForLoop(string indexVar, string bound, TargetWriter wr);\n    protected abstract BlockTargetWriter CreateDoublingForLoop(string indexVar, int start, TargetWriter wr);\n    protected abstract void EmitIncrementVar(string varName, TargetWriter wr);  // increments a BigInteger by 1\n    protected abstract void EmitDecrementVar(string varName, TargetWriter wr);  // decrements a BigInteger by 1\n\n    protected abstract string GetQuantifierName(string bvType);\n\n    /// <summary>\n    /// \"tok\" can be null if \"altVarType\" is null, which in turn is allowed if \"altBoundVarName\" is null\n    /// </summary>\n    protected abstract BlockTargetWriter CreateForeachLoop(string boundVar, Type/*?*/ boundVarType, out TargetWriter collectionWriter, TargetWriter wr, string/*?*/ altBoundVarName = null, Type/*?*/ altVarType = null, Bpl.IToken/*?*/ tok = null);\n    /// <summary>\n    /// If \"initCall\" is non-null, then \"initCall.Method is Constructor\".\n    /// </summary>\n    protected abstract void EmitNew(Type type, Bpl.IToken tok, CallStmt/*?*/ initCall, TargetWriter wr);\n    protected abstract void EmitNewArray(Type elmtType, Bpl.IToken tok, List<Expression> dimensions, bool mustInitialize, TargetWriter wr);\n\n    protected abstract void EmitLiteralExpr(TextWriter wr, LiteralExpr e);\n    protected abstract void EmitStringLiteral(string str, bool isVerbatim, TextWriter wr);\n    protected abstract TargetWriter EmitBitvectorTruncation(BitvectorType bvType, bool surroundByUnchecked, TargetWriter wr);\n    protected delegate void FCE_Arg_Translator(Expression e, TargetWriter wr, bool inLetExpr=false);\n\n    protected abstract void EmitRotate(Expression e0, Expression e1, bool isRotateLeft, TargetWriter wr, bool inLetExprBody, FCE_Arg_Translator tr);\n    protected abstract void EmitEmptyTupleList(string tupleTypeArgs, TargetWriter wr);\n    protected abstract TargetWriter EmitAddTupleToList(string ingredients, string tupleTypeArgs, TargetWriter wr);\n    protected abstract void EmitTupleSelect(string prefix, int i, TargetWriter wr);\n    /// <summary>\n    /// If \"from\" and \"to\" are both given, and if a \"from\" needs an explicit coercion in order to become a \"to\", emit that coercion.  Needed in languages where either (a) we need to represent upcasts as explicit operations (like Go) or (b) there's static typing but no parametric polymorphism (like Go) so that lots of things need to be boxed and unboxed.\n    /// </summary>\n    protected virtual TargetWriter EmitCoercionIfNecessary(Type/*?*/ from, Type/*?*/ to, Bpl.IToken tok, TargetWriter wr) {\n      return wr;\n    }\n    protected virtual TargetWriter EmitCoercionToNativeForm(Type/*?*/ from, Bpl.IToken tok, TargetWriter wr) {\n      return wr;\n    }\n    protected virtual TargetWriter EmitCoercionFromNativeForm(Type/*?*/ to, Bpl.IToken tok, TargetWriter wr) {\n      return wr;\n    }\n    protected virtual TargetWriter EmitCoercionToNativeInt(TargetWriter wr) {\n      return wr;\n    }\n    /// <summary>\n    /// Emit a coercion of a value to any tuple, returning the writer for the value to coerce.  Needed in translating ForallStmt because some of the tuple components are native ints for which we have no Type object, but Go needs to coerce the value that comes out of the iterator.  Safe to leave this alone in subclasses that don't have the same problem.\n    /// </summary>\n    protected virtual TargetWriter EmitCoercionToArbitraryTuple(TargetWriter wr) {\n      return wr;\n    }\n    protected virtual string IdName(TopLevelDecl d) {\n      Contract.Requires(d != null);\n      return IdProtect(d.CompileName);\n    }\n    protected virtual string IdName(MemberDecl member) {\n      Contract.Requires(member != null);\n      return IdProtect(member.CompileName);\n    }\n    protected virtual string IdName(TypeParameter tp) {\n      Contract.Requires(tp != null);\n      return IdProtect(tp.CompileName);\n    }\n    protected virtual string IdName(IVariable v) {\n      Contract.Requires(v != null);\n      return IdProtect(v.CompileName);\n    }\n    protected virtual string IdMemberName(MemberSelectExpr mse) {\n      Contract.Requires(mse != null);\n      return IdProtect(mse.MemberName);\n    }\n    protected virtual string IdProtect(string name) {\n      Contract.Requires(name != null);\n      return name;\n    }\n    protected abstract string FullTypeName(UserDefinedType udt, MemberDecl/*?*/ member = null);\n    protected abstract void EmitThis(TargetWriter wr);\n    protected virtual void EmitNull(Type type, TargetWriter wr) {\n      wr.Write(\"null\");\n    }\n    protected virtual void EmitITE(Expression guard, Expression thn, Expression els, bool inLetExprBody, TargetWriter wr) {\n      Contract.Requires(guard != null);\n      Contract.Requires(thn != null);\n      Contract.Requires(thn.Type != null);\n      Contract.Requires(els != null);\n      Contract.Requires(wr != null);\n\n      wr.Write(\"(\");\n      TrExpr(guard, wr, inLetExprBody);\n      wr.Write(\") ? (\");\n      TrExpr(thn, wr, inLetExprBody);\n      wr.Write(\") : (\");\n      TrExpr(els, wr, inLetExprBody);\n      wr.Write(\")\");\n    }\n    protected abstract void EmitDatatypeValue(DatatypeValue dtv, string arguments, TargetWriter wr);\n    protected abstract void GetSpecialFieldInfo(SpecialField.ID id, object idParam, out string compiledName, out string preString, out string postString);\n    protected abstract TargetWriter EmitMemberSelect(MemberDecl member, bool isLValue, Type expectedType, TargetWriter wr);\n    protected virtual TargetWriter EmitMemberSelect(MemberDecl member, bool isLValue, Type expectedType, TargetWriter wr, bool MemberSelectObjIsTrait) {\n      return EmitMemberSelect(member, isLValue, expectedType, wr);\n    }\n    protected void EmitArraySelect(string index, Type elmtType, TargetWriter wr) {\n      EmitArraySelect(new List<string>() { index }, elmtType, wr);\n    }\n    protected abstract TargetWriter EmitArraySelect(List<string> indices, Type elmtType, TargetWriter wr);\n    protected abstract TargetWriter EmitArraySelect(List<Expression> indices, Type elmtType, bool inLetExprBody, TargetWriter wr);\n    protected virtual void EmitArraySelectAsLvalue(string array, List<string> indices, Type elmtType, TargetWriter wr) {\n      wr.Write(array);\n      EmitArraySelect(indices, elmtType, wr);\n    }\n    protected virtual TargetWriter EmitArrayUpdate(List<string> indices, string rhs, Type elmtType, TargetWriter wr) {\n      var w = EmitArraySelect(indices, elmtType, wr);\n      wr.Write(\" = {0}\", rhs);\n      return w;\n    }\n    protected TargetWriter EmitArrayUpdate(List<string> indices, Expression rhs, TargetWriter wr) {\n      var w = new TargetWriter(wr.IndentLevel, true);\n      TrExpr(rhs, w, false);\n      return EmitArrayUpdate(indices, w.ToString(), rhs.Type, wr);\n    }\n    protected virtual string ArrayIndexToInt(string arrayIndex) {\n      return arrayIndex;\n    }\n    protected abstract void EmitExprAsInt(Expression expr, bool inLetExprBody, TargetWriter wr);\n    protected abstract void EmitIndexCollectionSelect(Expression source, Expression index, bool inLetExprBody, TargetWriter wr);\n    protected abstract void EmitIndexCollectionUpdate(Expression source, Expression index, Expression value, bool inLetExprBody, TargetWriter wr, bool nativeIndex = false);\n    protected virtual void EmitIndexCollectionUpdate(out TargetWriter wSource, out TargetWriter wIndex, out TargetWriter wValue, TargetWriter wr, bool nativeIndex = false) {\n      wSource = wr.Fork();\n      wr.Write('[');\n      wIndex = wr.Fork();\n      wr.Write(\"] = \");\n      wValue = wr.Fork();\n    }\n    /// <summary>\n    /// If \"fromArray\" is false, then \"source\" is a sequence.\n    /// If \"fromArray\" is true, then \"source\" is an array.\n    /// </summary>\n    protected abstract void EmitSeqSelectRange(Expression source, Expression/*?*/ lo, Expression/*?*/ hi, bool fromArray, bool inLetExprBody, TargetWriter wr);\n    protected abstract void EmitSeqConstructionExpr(SeqConstructionExpr expr, bool inLetExprBody, TargetWriter wr);\n    protected abstract void EmitMultiSetFormingExpr(MultiSetFormingExpr expr, bool inLetExprBody, TargetWriter wr);\n    protected abstract void EmitApplyExpr(Type functionType, Bpl.IToken tok, Expression function, List<Expression> arguments, bool inLetExprBody, TargetWriter wr);\n    protected abstract TargetWriter EmitBetaRedex(List<string> boundVars, List<Expression> arguments, string typeArgs, List<Type> boundTypes, Type resultType, Bpl.IToken resultTok, bool inLetExprBody, TargetWriter wr);\n    protected virtual void EmitConstructorCheck(string source, DatatypeCtor ctor, TargetWriter wr) {\n      wr.Write(\"{0}.is_{1}()\", source, ctor.CompileName);\n    }\n    /// <summary>\n    /// EmitDestructor is somewhat similar to following \"source\" with a call to EmitMemberSelect.\n    /// However, EmitDestructor may also need to perform a cast on \"source\".\n    /// Furthermore, EmitDestructor also needs to work for anonymous destructors.\n    /// </summary>\n    protected abstract void EmitDestructor(string source, Formal dtor, int formalNonGhostIndex, DatatypeCtor ctor, List<Type> typeArgs, Type bvType, TargetWriter wr);\n    protected abstract BlockTargetWriter CreateLambda(List<Type> inTypes, Bpl.IToken tok, List<string> inNames, Type resultType, TargetWriter wr, bool untyped = false);\n    protected abstract TargetWriter CreateIIFE_ExprBody(Expression source, bool inLetExprBody, Type sourceType, Bpl.IToken sourceTok, Type resultType, Bpl.IToken resultTok, string bvName, TargetWriter wr);  // Immediately Invoked Function Expression\n    protected abstract TargetWriter CreateIIFE_ExprBody(string source, Type sourceType, Bpl.IToken sourceTok, Type resultType, Bpl.IToken resultTok, string bvName, TargetWriter wr);  // Immediately Invoked Function Expression\n    protected abstract BlockTargetWriter CreateIIFE0(Type resultType, Bpl.IToken resultTok, TargetWriter wr);  // Immediately Invoked Function Expression\n    protected abstract BlockTargetWriter CreateIIFE1(int source, Type resultType, Bpl.IToken resultTok, string bvName, TargetWriter wr);  // Immediately Invoked Function Expression\n    public enum ResolvedUnaryOp { BoolNot, BitwiseNot, Cardinality, Dereference, AddressOf }\n    protected abstract void EmitUnaryExpr(ResolvedUnaryOp op, Expression expr, bool inLetExprBody, TargetWriter wr);\n    protected abstract void CompileBinOp(BinaryExpr.ResolvedOpcode op,\n      Expression e0, Expression e1, Bpl.IToken tok, Type resultType,\n      out string opString,\n      out string preOpString,\n      out string postOpString,\n      out string callString,\n      out string staticCallString,\n      out bool reverseArguments,\n      out bool truncateResult,\n      out bool convertE1_to_int,\n      TextWriter errorWr);\n    protected abstract void EmitIsZero(string varName, TargetWriter wr);\n    protected abstract void EmitConversionExpr(ConversionExpr e, bool inLetExprBody, TargetWriter wr);\n    protected abstract void EmitCollectionDisplay(CollectionType ct, Bpl.IToken tok, List<Expression> elements, bool inLetExprBody, TargetWriter wr);  // used for sets, multisets, and sequences\n    protected abstract void EmitMapDisplay(MapType mt, Bpl.IToken tok, List<ExpressionPair> elements, bool inLetExprBody, TargetWriter wr);\n    protected abstract void EmitCollectionBuilder_New(CollectionType ct, Bpl.IToken tok, TargetWriter wr);\n    protected abstract void EmitCollectionBuilder_Add(CollectionType ct, string collName, Expression elmt, bool inLetExprBody, TargetWriter wr);\n    protected abstract TargetWriter EmitMapBuilder_Add(MapType mt, Bpl.IToken tok, string collName, Expression term, bool inLetExprBody, TargetWriter wr);\n    protected abstract string GetCollectionBuilder_Build(CollectionType ct, Bpl.IToken tok, string collName, TargetWriter wr);\n    protected virtual void EmitIntegerRange(Type type, out TargetWriter wLo, out TargetWriter wHi, TargetWriter wr) {\n      if (AsNativeType(type) != null) {\n        wr.Write(\"{0}.IntegerRange(\", IdProtect(type.AsNewtype.FullCompileName));\n      } else {\n        wr.Write(\"{0}.IntegerRange(\", GetHelperModuleName());\n      }\n      wLo = wr.Fork();\n      wr.Write(\", \");\n      wHi = wr.Fork();\n      wr.Write(')');\n    }\n    protected abstract void EmitSingleValueGenerator(Expression e, bool inLetExprBody, string type, TargetWriter wr);\n    protected virtual void FinishModule() { }\n\n    protected virtual void OrganizeModules(Program program, out List<ModuleDefinition> modules){\n      modules = program.CompileModules;\n    }\n\n    protected virtual void DeclareExternType(OpaqueTypeDecl d, Expression compileTypeHint, TargetWriter wr) { }\n\n    public virtual void CompileArmadaStructs(ArmadaStructs structs, TargetWriter wr)\n    { }\n    public virtual void CompileArmadaLayer(ModuleDefinition layer, TargetWriter wr)\n    { }\n    public virtual void CompileArmadaCreateThread(ArmadaCreateThreadStatement stmt, TargetWriter wr) {}\n    public virtual void CompileArmadaCompareAndSwap(ArmadaCompareAndSwapStatement stmt, TargetWriter wr) {}\n    public virtual void CompileArmadaAtomicExchange(ArmadaAtomicExchangeStatement stmt, TargetWriter wr) {}\n    public void Compile(Program program, TargetWriter wrx) {\n      Contract.Requires(program != null);\n\n      EmitHeader(program, wrx);\n      EmitBuiltInDecls(program.BuiltIns, wrx);\n      var temp = new List<ModuleDefinition>();\n      OrganizeModules(program, out temp);\n      program.CompileModules = temp;\n      Console.Write(\"Number of module sigs: {0}\\n\",program.ModuleSigs.Count);\n      Console.Write(\"Number of compile modules: {0}\\n\",program.CompileModules.Count);\n      foreach (ModuleDefinition m in program.CompileModules) {\n        // Skip the non-armada modules\n\n        if (!(m.ModuleType == ArmadaModuleType.ArmadaLevel || m.ModuleType == ArmadaModuleType.ArmadaStructs))\n        {\n          Console.Write(\"Skipping Non-Armada Module = {0}, type = {1}\\n\",\n            m.Name, m.ModuleType.ToString());\n          continue;\n        }\n\n        Console.Write(\"Handling Module = {0}, type = {1}, structs is null = {2}, symbols is null = {3}\\n\",\n          m.Name,m.ModuleType.ToString(),m.ArmadaStructs == null,m.ArmadaSymbols == null);\n\n        if (m.IsAbstract) {\n          // the purpose of an abstract module is to skip compilation\n          continue;\n        }\n        var moduleIsExtern = false;\n        string libraryName = null;\n        if (!ArmadaOptions.O.DisallowExterns) {\n          var args = Attributes.FindExpressions(m.Attributes, \"extern\");\n          if (args != null) {\n            if (args.Count == 2) {\n              libraryName = (string)(args[1] as StringLiteralExpr)?.Value;\n            }\n            moduleIsExtern = true;\n          }\n        }\n\n        var wr = CreateModule(m.CompileName, m.IsDefaultModule, moduleIsExtern, libraryName, wrx);\n\n        // Handle the AramdaStructs layer\n        if (m.ModuleType == ArmadaModuleType.ArmadaStructs)\n        {\n          CompileArmadaStructs(m.ArmadaStructs, wr);\n          continue;\n        }\n\n        // Handle the Aramda implemetation layer.\n        if (m.ModuleType == ArmadaModuleType.ArmadaLevel)\n        {\n          CompileArmadaLayer(m, wr);\n          continue;\n        }\n\n        /*\n        foreach (TopLevelDecl d in m.TopLevelDecls) {\n          bool compileIt = true;\n          if (Attributes.ContainsBool(d.Attributes, \"compile\", ref compileIt) && !compileIt) {\n            continue;\n          }\n          wr.WriteLine();\n          if (d is OpaqueTypeDecl) {\n\n            var at = (OpaqueTypeDecl)d;\n            bool externP = Attributes.Contains(at.Attributes, \"extern\");\n            if (externP) {\n              var exprs = Attributes.FindExpressions(at.Attributes, \"extern\");\n              if (exprs != null && exprs.Count >= 1) {\n                DeclareExternType(at, exprs[0], wr);\n              } else {\n                Error(d.tok, \"Opaque type ('{0}') with missing extern attribute cannot be compiled.  Expected {{:extern compile_type_hint}} \", wr, at.FullName);\n              }\n            } else {\n              Error(d.tok, \"Opaque type ('{0}') cannot be compiled\", wr, at.FullName);\n            }\n          } else if (d is TypeSynonymDecl) {\n            var sst = d as SubsetTypeDecl;\n            if (sst != null) {\n              DeclareSubsetType(sst, wr);\n            }\n          } else if (d is NewtypeDecl) {\n            var nt = (NewtypeDecl)d;\n            var w = DeclareNewtype(nt, wr);\n            CompileClassMembers(nt, w);\n          } else if (d is DatatypeDecl) {\n            var dt = (DatatypeDecl)d;\n            CheckForCapitalizationConflicts(dt.Ctors);\n            foreach (var ctor in dt.Ctors) {\n              CheckForCapitalizationConflicts(ctor.Destructors);\n            }\n            var w = DeclareDatatype(dt, wr);\n            if (w != null) {\n              CompileClassMembers(dt, w);\n            }\n          } else if (d is IteratorDecl) {\n            var iter = (IteratorDecl)d;\n            if (DafnyOptions.O.ForbidNondeterminism && iter.Outs.Count > 0) {\n              Error(iter.tok, \"since yield parameters are initialized arbitrarily, iterators are forbidden by /definiteAssignment:3 option\", wr);\n            }\n\n            var wIter = CreateIterator(iter, wr);\n            if (iter.Body == null) {\n              Error(iter.tok, \"Iterator {0} has no body\", wIter, iter.FullName);\n            } else {\n              TrStmtList(iter.Body.Body, wIter);\n            }\n\n          } else if (d is TraitDecl) {\n            // writing the trait\n            var trait = (TraitDecl)d;\n            var w = CreateTrait(trait.CompileName, trait.IsExtern(out _, out _), null, null, wr);\n            CompileClassMembers(trait, w);\n          } else if (d is ClassDecl) {\n\n            var cl = (ClassDecl)d;\n            var include = true;\n            if (cl.IsDefaultClass) {\n              Predicate<MemberDecl> compilationMaterial = x =>\n                !x.IsGhost && (DafnyOptions.O.DisallowExterns || !Attributes.Contains(x.Attributes, \"extern\"));\n              include = cl.Members.Exists(compilationMaterial) || cl.InheritedMembers.Exists(compilationMaterial);\n            }\n            var classIsExtern = false;\n            if (include) {\n              classIsExtern = !DafnyOptions.O.DisallowExterns && Attributes.Contains(cl.Attributes, \"extern\");\n              if (classIsExtern && cl.Members.TrueForAll(member => member.IsGhost || Attributes.Contains(member.Attributes, \"extern\"))) {\n                include = false;\n              }\n            }\n            if (include) {\n              var cw = CreateClass(IdName(cl), classIsExtern, cl.FullName, cl.TypeArgs, cl.TraitsTyp, cl.tok, wr);\n              CompileClassMembers(cl, cw);\n              cw.Finish();\n            } else {\n              // still check that given members satisfy compilation rules\n              var abyss = new NullClassWriter();\n              CompileClassMembers(cl, abyss);\n            }\n          } else if (d is ValuetypeDecl) {\n            // nop\n          } else if (d is ModuleDecl) {\n            // nop\n          } else { Contract.Assert(false); }\n\n        }\n        */\n        FinishModule();\n      }\n      EmitFooter(program, wrx);\n    }\n\n    protected class NullClassWriter : IClassWriter {\n      private readonly TargetWriter abyss = new TargetWriter();\n      private readonly BlockTargetWriter block;\n\n      public NullClassWriter() {\n        block = abyss.NewBlock(\"\");\n      }\n\n      public BlockTargetWriter/*?*/ CreateMethod(Method m, bool createBody) {\n        return createBody ? block : null;\n      }\n      public BlockTargetWriter/*?*/ CreateFunction(string name, List<TypeParameter>/*?*/ typeArgs, List<Formal> formals, Type resultType, Bpl.IToken tok, bool isStatic, bool createBody, MemberDecl member) {\n        return createBody ? block : null;\n      }\n      public BlockTargetWriter/*?*/ CreateGetter(string name, Type resultType, Bpl.IToken tok, bool isStatic, bool createBody, MemberDecl/*?*/ member) {\n        return createBody ? block : null;\n      }\n      public BlockTargetWriter/*?*/ CreateGetterSetter(string name, Type resultType, Bpl.IToken tok, bool isStatic, bool createBody, MemberDecl/*?*/ member, out TargetWriter setterWriter) {\n        if (createBody) {\n          setterWriter = block;\n          return block;\n        } else {\n          setterWriter = null;\n          return null;\n        }\n      }\n\n      public void DeclareField(string name, List<TypeParameter> targs, bool isStatic, bool isConst, Type type, Bpl.IToken tok, string rhs) {}\n\n      public TextWriter/*?*/ ErrorWriter() {\n        return null; // match the old behavior of Compile() where this is used\n      }\n\n      public void Finish() { }\n    }\n\n    protected void ReadRuntimeSystem(string filename, TextWriter wr) {\n      Contract.Requires(filename != null);\n      Contract.Requires(wr != null);\n\n      if (ArmadaOptions.O.UseRuntimeLib) {\n        return;\n      }\n      var assemblyLocation = System.Reflection.Assembly.GetExecutingAssembly().Location;\n      Contract.Assert(assemblyLocation != null);\n      var codebase = System.IO.Path.GetDirectoryName(assemblyLocation);\n      Contract.Assert(codebase != null);\n      string path = System.IO.Path.Combine(codebase, filename);\n      WriteFromFile(path, wr);\n    }\n\n    protected void WriteFromFile(string inputFilename, TextWriter outputWriter) {\n      using (var rd = new StreamReader(new FileStream(inputFilename, System.IO.FileMode.Open, System.IO.FileAccess.Read))) {\n        while (true) {\n          string s = rd.ReadLine();\n          if (s == null) {\n            return;\n          }\n          outputWriter.WriteLine(s);\n        }\n      }\n    }\n\n    // create a varName that is not a duplicate of formals' name\n    protected string GenVarName(string root, List<Formal> formals) {\n      bool finished = false;\n      while (!finished) {\n        finished = true;\n        int i = 0;\n        foreach (var arg in formals) {\n          if (!arg.IsGhost) {\n            // FormalName returns a protected name, so we compare a protected version of \"root\" to it\n            if (IdProtect(root).Equals(FormalName(arg, i))) {\n              root += root;\n              finished = false;\n            }\n            i++;\n          }\n        }\n      }\n      return root;\n    }\n\n    protected int WriteFormals(string sep, List<Formal> formals, TextWriter wr) {\n      Contract.Requires(sep != null);\n      int i = 0;\n      foreach (Formal arg in formals) {\n        if (!arg.IsGhost) {\n          string name = FormalName(arg, i);\n          if (DeclareFormal(sep, name, arg.Type, arg.tok, arg.InParam, wr)) {\n            sep = \", \";\n          }\n          i++;\n        }\n      }\n      return i;  // the number of formals written\n    }\n\n    protected string FormalName(Formal formal, int i) {\n      Contract.Requires(formal != null);\n      Contract.Ensures(Contract.Result<string>() != null);\n\n      return IdProtect(formal.HasName ? formal.CompileName : \"_a\" + i);\n    }\n\n    public bool HasMain(Program program, out Method mainMethod) {\n      mainMethod = null;\n      bool hasMain = false;\n      foreach (var module in program.CompileModules) {\n        if (module.IsAbstract) {\n          // the purpose of an abstract module is to skip compilation\n          continue;\n        }\n        foreach (var decl in module.TopLevelDecls) {\n          var c = decl as ClassDecl;\n          if (c != null) {\n            foreach (var member in c.Members) {\n              var m = member as Method;\n              if (m != null && IsMain(m)) {\n                if (mainMethod == null) {\n                  mainMethod = m;\n                  hasMain = true;\n                } else {\n                  // more than one main in the program\n                  Error(m.tok, \"More than one method is declared as \\\"main\\\". First declaration appeared at {0}.\", null, ErrorReporter.TokenToString(mainMethod.tok));\n                  hasMain = false;\n                }\n              }\n            }\n          }\n        }\n      }\n      if (!hasMain) {\n        // make sure \"mainMethod\" returns as null\n        mainMethod = null;\n      }\n      return hasMain;\n    }\n\n    public static bool IsMain(Method m) {\n      Contract.Requires(m.EnclosingClass is TopLevelDeclWithMembers);\n      // In order to be a legal Main() method, the following must be true:\n      //    The method is not a ghost method\n      //    The method takes no non-ghost parameters and no type parameters\n      //    The enclosing type does not take any type parameters\n      //    If the method is an instance (that is, non-static) method in a class, then the enclosing class must not declare any constructor\n      // In addition, either:\n      //    The method is called \"Main\"\n      //    The method has no requires clause\n      //    The method has no modifies clause\n      // or:\n      //    The method is annotated with {:main}\n      // Note, in the case where the method is annotated with {:main}, the method is allowed to have preconditions and modifies clauses.\n      // This lets the programmer add some explicit assumptions about the outside world, modeled, for example, via ghost parameters.\n      if (m.Name == \"main\")\n      {\n        return true;\n      }\n      return false;\n      /*\n      var cl = (TopLevelDeclWithMembers)m.EnclosingClass;\n      if (!m.IsGhost && m.TypeArgs.Count == 0 && cl.TypeArgs.Count == 0) {\n        if (m.Ins.TrueForAll(f => f.IsGhost) && m.Outs.TrueForAll(f => f.IsGhost)) {\n          if (m.IsStatic || (cl is ClassDecl klass && !(klass is TraitDecl) && !klass.HasConstructor)) {\n            if (m.Name == \"main\" && m.Req.Count == 0 && m.Mod.Expressions.Count == 0) {\n              return true;\n            } else if (Attributes.Contains(m.Attributes, \"main\")) {\n              return true;\n            }\n          }\n        }\n      }\n      return false;\n      */\n    }\n\n    void OrderedBySCC(List<MemberDecl> decls, TopLevelDeclWithMembers c) {\n      List<ConstantField> consts = new List<ConstantField>();\n      foreach (var decl in decls) {\n        if (decl is ConstantField) {\n          consts.Add((ConstantField)decl);\n        }\n      }\n      consts.Sort((a, b) => c.Module.CallGraph.GetSCCRepresentativeId(a) - c.Module.CallGraph.GetSCCRepresentativeId(b));\n      foreach (var con in consts) {\n        decls.Remove(con);\n      }\n      decls.AddRange(consts);\n    }\n\n    public static bool NeedsCustomReceiver(MemberDecl member) {\n      Contract.Requires(member != null);\n      return !member.IsStatic && member.EnclosingClass is NewtypeDecl;\n    }\n\n    void CompileClassMembers(TopLevelDeclWithMembers c, IClassWriter classWriter) {\n      Contract.Requires(c != null);\n      Contract.Requires(classWriter != null);\n      Contract.Requires(thisContext == null);\n      Contract.Ensures(thisContext == null);\n\n      thisContext = c;\n      var errorWr = classWriter.ErrorWriter();\n\n      if (c is ClassDecl) {\n        CheckHandleWellformed((ClassDecl)c, errorWr);\n      }\n\n      var inheritedMembers = c is ClassDecl ? ((ClassDecl)c).InheritedMembers : new List<MemberDecl>();\n\n      CheckForCapitalizationConflicts(c.Members, inheritedMembers);\n      OrderedBySCC(inheritedMembers, c);\n      OrderedBySCC(c.Members, c);\n\n      foreach (var member in inheritedMembers) {\n        Contract.Assert(!member.IsStatic);  // only instance members should ever be added to .InheritedMembers\n        if (member.IsGhost) {\n          // skip\n        } else if (member is ConstantField && SupportsProperties) {\n          if (NeedsWrappersForInheritedFields) {\n            var cf = (ConstantField)member;\n            if (cf.Rhs == null) {\n              Contract.Assert(!cf.IsStatic);  // as checked above, only instance members can be inherited\n              classWriter.DeclareField(\"_\" + cf.CompileName, c.TypeArgs,false, false, cf.Type, cf.tok, DefaultValue(cf.Type, errorWr, cf.tok, true));\n            }\n            var w = classWriter.CreateGetter(IdName(cf), cf.Type, cf.tok, false, true, member);\n            Contract.Assert(w != null);  // since the previous line asked for a body\n            if (cf.Rhs == null) {\n              var sw = EmitReturnExpr(w);\n              // get { return this._{0}; }\n              EmitThis(sw);\n              sw.Write(\"._{0}\", cf.CompileName);\n            } else {\n              CompileReturnBody(cf.Rhs, w);\n            }\n          }\n        } else if (member is Field) {\n          if (NeedsWrappersForInheritedFields) {\n            var f = (Field)member;\n            // every field is inherited\n            classWriter.DeclareField(\"_\" + f.CompileName, c.TypeArgs, false, false, f.Type, f.tok, DefaultValue(f.Type, errorWr, f.tok, true));\n            TargetWriter wSet;\n            var wGet = classWriter.CreateGetterSetter(IdName(f), f.Type, f.tok, false, true, member, out wSet);\n            {\n              var sw = EmitReturnExpr(wGet);\n              // get { return this._{0}; }\n              EmitThis(sw);\n              sw.Write(\"._{0}\", f.CompileName);\n            }\n            {\n              // set { this._{0} = value; }\n              EmitThis(wSet);\n              wSet.Write(\"._{0}\", f.CompileName);\n              var sw = EmitAssignmentRhs(wSet);\n              EmitSetterParameter(sw);\n            }\n          } else {\n            var f = (Field) member;\n            if (!FieldsInTraits && f is ConstantField cf && cf.Rhs != null) {\n              var w = new TargetWriter();\n              TrExpr(cf.Rhs, w, false);\n              var rhs = w.ToString();\n              classWriter.DeclareField(f.CompileName, c.TypeArgs, false, true, f.Type, f.tok, rhs);\n            } else {\n              classWriter.DeclareField(f.CompileName, c.TypeArgs, false, false, f.Type, f.tok, DefaultValue(f.Type, errorWr, f.tok, true));\n            }\n\n            if (!FieldsInTraits) { // Create getters and setters for \"traits\" in languages that don't allow for non-final field declarations.\n              TargetWriter wSet;\n              var wGet = classWriter.CreateGetterSetter(IdName(f), f.Type, f.tok, false, true, member, out wSet);\n              {\n                var sw = EmitReturnExpr(wGet);\n                // get { return this.{0}; }\n                EmitThis(sw);\n                sw.Write(\".{0}\", f.CompileName);\n              }\n              {\n                // set { this.{0} = value; }\n                EmitThis(wSet);\n                wSet.Write(\".{0}\", f.CompileName);\n                var sw = EmitAssignmentRhs(wSet);\n                EmitSetterParameter(sw);\n              }\n            }\n          }\n        } else if (member is Function) {\n          var f = (Function)member;\n          Contract.Assert(f.Body != null);\n          CompileFunction(f, classWriter);\n        } else if (member is Method) {\n          var method = (Method)member;\n          Contract.Assert(method.Body != null);\n          CompileMethod(method, classWriter);\n        } else {\n          Contract.Assert(false);  // unexpected member\n        }\n      }\n\n      List<TypeParameter> l = new List<TypeParameter>();\n      foreach (MemberDecl member in c.Members) {\n        if (member is Field) {\n          var f = (Field)member;\n          if (f.IsGhost) {\n            // emit nothing, but check for assumes\n            if (f is ConstantField cf && cf.Rhs != null) {\n              var v = new CheckHasNoAssumes_Visitor(this, errorWr);\n              v.Visit(cf.Rhs);\n            }\n          } else if (!ArmadaOptions.O.DisallowExterns && Attributes.Contains(f.Attributes, \"extern\")) {\n            // emit nothing\n          } else if (f is ConstantField) {\n            var cf = (ConstantField)f;\n            if (SupportsProperties || (c is NewtypeDecl && !cf.IsStatic)) {\n              BlockTargetWriter wBody;\n              if (c is NewtypeDecl && !cf.IsStatic) {\n                // an instance field in a newtype needs to be modeled as a static function that takes a parameter,\n                // because a newtype value is always represented as some existing type\n                wBody = classWriter.CreateFunction(IdName(cf), new List<TypeParameter>(), new List<Formal>(), cf.Type, cf.tok, true, true, cf);\n              } else if (cf.IsStatic) {\n                wBody = classWriter.CreateGetter(IdName(cf), cf.Type, cf.tok, true, true, cf);\n                Contract.Assert(wBody != null);  // since the previous line asked for a body\n              } else if (c is TraitDecl) {\n                wBody = classWriter.CreateGetter(IdName(cf), cf.Type, cf.tok, false, false, cf);\n                Contract.Assert(wBody == null);  // since the previous line said not to create a body\n              } else if (cf.Rhs == null) {\n                // create a backing field, since this constant field may be assigned in constructors\n                classWriter.DeclareField(\"_\" + f.CompileName, c.TypeArgs, false, false, f.Type, f.tok, DefaultValue(f.Type, errorWr, f.tok, true));\n                wBody = classWriter.CreateGetter(IdName(cf), cf.Type, cf.tok, false, true, cf);\n                Contract.Assert(wBody != null);  // since the previous line asked for a body\n              } else {\n                wBody = classWriter.CreateGetter(IdName(cf), cf.Type, cf.tok, false, true, cf);\n                Contract.Assert(wBody != null);  // since the previous line asked for a body\n              }\n              if (wBody != null) {\n                if (cf.Rhs != null) {\n                  CompileReturnBody(cf.Rhs, wBody);\n                } else if (!cf.IsStatic) {\n                  var sw = EmitReturnExpr(wBody);\n                  var wThis = EmitMemberSelect(cf, true, f.Type, sw);\n                  EmitThis(wThis);\n                } else {\n                  EmitReturnExpr(DefaultValue(cf.Type, wBody, cf.tok, true), wBody);\n                }\n              }\n            } else {\n              // If properties aren't supported, just use a field and hope\n              // everyone plays nicely ...\n              string rhs;\n              if (cf.Rhs != null) {\n                var w = new TargetWriter();\n                TrExpr(cf.Rhs, w, false);\n                rhs = w.ToString();\n              } else {\n                rhs = null;\n              }\n              if (!(c is TraitDecl && !FieldsInTraits) || cf.IsStatic) {\n                classWriter.DeclareField(IdName(f), c.TypeArgs, f.IsStatic, true, f.Type, f.tok, rhs);\n              } else { // Constant fields in traits (Java interface) should be get methods.\n                classWriter.CreateGetter(IdName(cf), cf.Type, cf.tok, false, false, cf);\n              }\n            }\n          } else if (c is TraitDecl && NeedsWrappersForInheritedFields) {\n            TargetWriter wSet;\n            var wGet = classWriter.CreateGetterSetter(IdName(f), f.Type, f.tok, f.IsStatic, false, member, out wSet);\n            Contract.Assert(wSet == null && wGet == null);  // since the previous line specified no body\n          } else if (c is TraitDecl && !FieldsInTraits && !f.IsStatic) {\n            TargetWriter wSet;\n            classWriter.CreateGetterSetter(IdName(f), f.Type, f.tok, false, false, member, out wSet);\n          } else if (c is ClassDecl && f.Type.IsTypeParameter) {\n            EmitTypeParams(classWriter, l, f, errorWr);\n          } else {\n            classWriter.DeclareField(IdName(f),c.TypeArgs,  f.IsStatic, false, f.Type, f.tok, DefaultValue(f.Type, errorWr, f.tok, true));\n          }\n        } else if (member is Function) {\n          var f = (Function)member;\n          if (f.Body == null && !(c is TraitDecl && !f.IsStatic) && !(!ArmadaOptions.O.DisallowExterns && Attributes.Contains(f.Attributes, \"dllimport\"))) {\n            // A (ghost or non-ghost) function must always have a body, except if it's an instance function in a trait.\n            if (Attributes.Contains(f.Attributes, \"axiom\") || (!ArmadaOptions.O.DisallowExterns && Attributes.Contains(f.Attributes, \"extern\"))) {\n              // suppress error message\n            } else {\n              Error(f.tok, \"Function {0} has no body\", errorWr, f.FullName);\n            }\n          } else if (f.IsGhost) {\n            // nothing to compile, but we do check for assumes\n            if (f.Body == null) {\n              Contract.Assert(c is TraitDecl && !f.IsStatic);\n            } else {\n              var v = new CheckHasNoAssumes_Visitor(this, errorWr);\n              v.Visit(f.Body);\n            }\n          } else if (c is TraitDecl && !f.IsStatic) {\n            var w = classWriter.CreateFunction(IdName(f), f.TypeArgs, f.Formals, f.ResultType, f.tok, false, false, f);\n            Contract.Assert(w == null);  // since we requested no body\n          } else {\n            CompileFunction(f, classWriter);\n          }\n        } else if (member is Method) {\n          var m = (Method)member;\n          if (m.Body == null && !(c is TraitDecl && !m.IsStatic) && !(!ArmadaOptions.O.DisallowExterns && Attributes.Contains(m.Attributes, \"dllimport\"))) {\n            // A (ghost or non-ghost) method must always have a body, except if it's an instance method in a trait.\n            if (Attributes.Contains(m.Attributes, \"axiom\") || (!ArmadaOptions.O.DisallowExterns && Attributes.Contains(m.Attributes, \"extern\"))) {\n              // suppress error message\n            } else {\n              Error(m.tok, \"Method {0} has no body\", errorWr, m.FullName);\n            }\n          } else if (m.IsGhost) {\n            // nothing to compile, but we do check for assumes\n            if (m.Body == null) {\n              Contract.Assert(c is TraitDecl && !m.IsStatic);\n            } else {\n              var v = new CheckHasNoAssumes_Visitor(this, errorWr);\n              v.Visit(m.Body);\n            }\n          } else if (c is TraitDecl && !m.IsStatic) {\n            var w = classWriter.CreateMethod(m, false);\n            Contract.Assert(w == null);  // since we requested no body\n          } else {\n            CompileMethod(m, classWriter);\n          }\n        } else {\n          Contract.Assert(false); throw new cce.UnreachableException();  // unexpected member\n        }\n      }\n      if (l.Count > 0){\n        CreateDefaultConstructor(c, classWriter, l);\n      }\n\n      thisContext = null;\n    }\n\n    protected virtual void CreateDefaultConstructor(TopLevelDeclWithMembers c, IClassWriter cw, List<TypeParameter> l) {\n      Contract.Requires(c != null);\n      Contract.Requires(cw != null);\n    }\n\n    protected virtual void EmitTypeParams(IClassWriter classWriter, List<TypeParameter> l, Field f, TextWriter errorWr) {\n      classWriter.DeclareField(IdName(f), l,  f.IsStatic, false, f.Type, f.tok,\n        DefaultValue(f.Type, errorWr, f.tok, true));\n\n    }\n\n    void CheckHandleWellformed(ClassDecl cl, TextWriter/*?*/ errorWr) {\n      Contract.Requires(cl != null);\n      var isHandle = true;\n      if (Attributes.ContainsBool(cl.Attributes, \"handle\", ref isHandle) && isHandle) {\n        foreach (var trait in cl.TraitsObj) {\n          isHandle = true;\n          if (Attributes.ContainsBool(trait.Attributes, \"handle\", ref isHandle) && isHandle) {\n            // all is good\n          } else {\n            Error(cl.tok, \"{0} '{1}' is marked as :handle, so all the traits it extends must be be marked as :handle as well: {2}\", errorWr, cl.WhatKind, cl.Name, trait.Name);\n          }\n        }\n        foreach (var member in cl.InheritedMembers.Concat(cl.Members)) {\n          if (!member.IsGhost && !member.IsStatic) {\n            Error(member.tok, \"{0} '{1}' is marked as :handle, so all its non-static members must be ghost: {2}\", errorWr, cl.WhatKind, cl.Name, member.Name);\n          }\n        }\n      }\n    }\n\n    /// <summary>\n    /// Check whether two declarations have the same name if capitalized.\n    /// </summary>\n    /// <param name=\"canChange\">The declarations to check.</param>\n    /// <param name=\"cantChange\">Additional declarations which may conflict, but which can't be given different names.  For example, these may be the inherited members of a class.</param>\n    /// <remarks>\n    /// If two elements of <paramref name=\"canChange\"/> have the same\n    /// capitalization, the lowercase one will get a\n    /// <c>{:_capitalizationConflict}</c> attribute.  If\n    /// <paramref name=\"cantChange\"/> is given and one of its elements conflicts\n    /// with one from <paramref name=\"canChange\"/>, the element from\n    /// <paramref name=\"canChange\"/> gets the attribute whether it is lowercase\n    /// or not.\n    /// </remarks>\n    /// <seealso cref=\"HasCapitalizationConflict\"/>\n    private void CheckForCapitalizationConflicts<T>(IEnumerable<T> canChange, IEnumerable<T> cantChange = null) where T : Declaration {\n      if (cantChange == null) {\n        cantChange = Enumerable.Empty<T>();\n      }\n      IDictionary<string, T> declsByCapName = new Dictionary<string, T>();\n      ISet<string> fixedNames = new HashSet<string>(from decl in cantChange select Capitalize(decl.CompileName));\n\n      foreach (var decl in canChange) {\n        var name = decl.CompileName;\n        var capName = Capitalize(name);\n        if (name == capName) {\n          if (fixedNames.Contains(name)) {\n            // Normally we mark the lowercase one, but in this case we can't change that one\n            MarkCapitalizationConflict(decl);\n          } else {\n            T other;\n            if (declsByCapName.TryGetValue(name, out other)) {\n              // Presume that the other is the lowercase one\n              MarkCapitalizationConflict(other);\n            } else {\n              declsByCapName.Add(name, decl);\n            }\n          }\n        } else {\n          if (declsByCapName.ContainsKey(capName)) {\n            MarkCapitalizationConflict(decl);\n          } else {\n            declsByCapName.Add(capName, decl);\n          }\n        }\n      }\n    }\n\n    protected string Capitalize(string str) {\n      if (!str.Any(c => c != '_')) {\n        return PrefixForForcedCapitalization + str;\n      }\n      var origStr = str;\n      while (str.StartsWith(\"_\")) {\n        str = str.Substring(1) + \"_\";\n      }\n      if (!char.IsLetter(str[0])) {\n        return PrefixForForcedCapitalization + origStr;\n      } else {\n        return char.ToUpper(str[0]) + str.Substring(1);\n      }\n    }\n\n    protected virtual string PrefixForForcedCapitalization { get => \"Cap_\"; }\n\n    private static void MarkCapitalizationConflict(Declaration decl) {\n      decl.Attributes = new Attributes(CapitalizationConflictAttribute, new List<Expression>(), decl.Attributes);\n    }\n\n    protected static bool HasCapitalizationConflict(Declaration decl) {\n      return Attributes.Contains(decl.Attributes, CapitalizationConflictAttribute);\n    }\n\n    private static string CapitalizationConflictAttribute = \"_capitalizationConflict\";\n\n    private void CompileFunction(Function f, IClassWriter cw) {\n      Contract.Requires(f != null);\n      Contract.Requires(cw != null);\n\n      var w = cw.CreateFunction(IdName(f), f.TypeArgs, f.Formals, f.ResultType, f.tok, f.IsStatic, true, f);\n      if (w != null) {\n        CompileReturnBody(f.Body, w);\n      }\n    }\n\n    protected void CompileMethod(Method m, IClassWriter cw) {\n      Contract.Requires(cw != null);\n      Contract.Requires(m != null);\n\n      var w = cw.CreateMethod(m, true);\n      if (w != null) {\n        int nonGhostOutsCount = 0;\n        foreach (var p in m.Outs) {\n          if (!p.IsGhost) {\n            nonGhostOutsCount++;\n          }\n        }\n\n        var useReturnStyleOuts = UseReturnStyleOuts(m, nonGhostOutsCount);\n        foreach (var p in m.Outs) {\n          if (!p.IsGhost) {\n            DeclareLocalOutVar(IdName(p), p.Type, p.tok, DefaultValue(p.Type, w, p.tok, true), useReturnStyleOuts, w);\n          }\n        }\n\n        w = EmitMethodReturns(m, w);\n\n        if (m.Body == null) {\n          Error(m.tok, \"Method {0} has no body\", w, m.FullName);\n        } else {\n          Contract.Assert(enclosingMethod == null);\n          enclosingMethod = m;\n          TrStmtList(m.Body.Body, w);\n          Contract.Assert(enclosingMethod == m);\n          enclosingMethod = null;\n        }\n      }\n\n      // allow the Main method to be an instance method\n      if (IsMain(m) && (!m.IsStatic || m.CompileName != \"Main\")) {\n        w = CreateStaticMain(cw);\n        if (!m.IsStatic) {\n          var c = m.EnclosingClass;\n          var typeArgs = c.TypeArgs.ConvertAll(tp => (Type)Type.Bool);\n          var ty = new UserDefinedType(m.tok, c.Name, c, typeArgs);\n          var wRhs = DeclareLocalVar(\"b\", ty, m.tok, w);\n          EmitNew(ty, m.tok, null, wRhs);\n          w.WriteLine(\"b.{0}();\", IdName(m));\n        } else {\n          w.WriteLine(\"{0}();\", IdName(m));\n        }\n      }\n    }\n\n    void TrCasePatternOpt<VT>(CasePattern<VT> pat, Expression rhs, TargetWriter wr, bool inLetExprBody) where VT: IVariable {\n      TrCasePatternOpt(pat, rhs, null, rhs.Type, rhs.tok, wr, inLetExprBody);\n    }\n\n    void TrCasePatternOpt<VT>(CasePattern<VT> pat, Expression rhs, string rhs_string, Type rhsType, Bpl.IToken rhsTok, TargetWriter wr, bool inLetExprBody) where VT: IVariable {\n      Contract.Requires(pat != null);\n      Contract.Requires(pat.Var != null || rhs != null || rhs_string != null);\n      Contract.Requires(rhs != null || rhs_string != null);\n      Contract.Requires(rhsType != null && rhsTok != null);\n\n      if (pat.Var != null) {\n        // The trivial Dafny \"pattern\" expression\n        //    var x := G\n        // is translated into C# as:\n        // var x := G;\n        var bv = pat.Var;\n        if (!bv.IsGhost) {\n          var w = DeclareLocalVar(IdProtect(bv.CompileName), bv.Type, rhsTok, wr);\n          if (rhs != null) {\n            w = EmitCoercionIfNecessary(from: rhs.Type, to: bv.Type, tok:rhsTok, wr:w);\n            TrExpr(rhs, w, inLetExprBody);\n          } else {\n            w.Write(rhs_string);\n          }\n        }\n      } else if (pat.Arguments != null) {\n        // The Dafny \"pattern\" expression\n        //    var Pattern(x,y) := G\n        // is translated into C# as:\n        // var tmp := G;\n        // var x := dtorX(tmp);\n        // var y := dtorY(tmp);\n        var ctor = pat.Ctor;\n        Contract.Assert(ctor != null);  // follows from successful resolution\n        Contract.Assert(pat.Arguments.Count == ctor.Formals.Count);  // follows from successful resolution\n\n        // Create the temporary variable to hold G\n        var tmp_name = idGenerator.FreshId(\"_let_tmp_rhs\");\n        if (rhs != null) {\n          DeclareLocalVar(tmp_name, rhs.Type, rhs.tok, rhs, inLetExprBody, wr);\n        } else {\n          DeclareLocalVar(tmp_name, rhsType, rhsTok, false, rhs_string, wr);\n        }\n\n        var k = 0;  // number of non-ghost formals processed\n        for (int i = 0; i < pat.Arguments.Count; i++) {\n          var arg = pat.Arguments[i];\n          var formal = ctor.Formals[i];\n          if (formal.IsGhost) {\n            // nothing to compile, but do a sanity check\n            Contract.Assert(Contract.ForAll(arg.Vars, bv => bv.IsGhost));\n          } else {\n            var sw = new TargetWriter(wr.IndentLevel, true);\n            EmitDestructor(tmp_name, formal, k, ctor, ((DatatypeValue)pat.Expr).InferredTypeArgs, arg.Expr.Type, sw);\n            TrCasePatternOpt(arg, null, sw.ToString(), pat.Expr.Type, pat.Expr.tok, wr, inLetExprBody);\n            k++;\n          }\n        }\n      }\n    }\n\n    void TrExprOpt(Expression expr, TargetWriter wr, bool inLetExprBody) {\n      Contract.Requires(expr != null);\n      if (expr is LetExpr) {\n        var e = (LetExpr)expr;\n        if (e.Exact) {\n          for (int i = 0; i < e.LHSs.Count; i++) {\n            var lhs = e.LHSs[i];\n            if (Contract.Exists(lhs.Vars, bv => !bv.IsGhost)) {\n              TrCasePatternOpt(lhs, e.RHSs[i], wr, inLetExprBody);\n            }\n          }\n          TrExprOpt(e.Body, wr, inLetExprBody);\n        } else {\n          // We haven't optimized the other cases, so fallback to normal compilation\n          EmitReturnExpr(e, inLetExprBody, wr);\n        }\n      } else if (expr is ITEExpr) {\n        var e = (ITEExpr)expr;\n        TargetWriter guardWriter;\n        var thn = EmitIf(out guardWriter, true, wr);\n        TrExpr(e.Test, guardWriter, inLetExprBody);\n        TrExprOpt(e.Thn, thn, inLetExprBody);\n        var els = wr.NewBlock(\"\");\n        TrExprOpt(e.Els, els, inLetExprBody);\n      } else if (expr is MatchExpr) {\n        var e = (MatchExpr)expr;\n        //   var _source = E;\n        //   if (source.is_Ctor0) {\n        //     FormalType f0 = ((Dt_Ctor0)source._D).a0;\n        //     ...\n        //     return Body0;\n        //   } else if (...) {\n        //     ...\n        //   } else if (true) {\n        //     ...\n        //   }\n        string source = idGenerator.FreshId(\"_source\");\n        DeclareLocalVar(source, e.Source.Type, e.Source.tok, e.Source, inLetExprBody, wr);\n\n        if (e.Cases.Count == 0) {\n          // the verifier would have proved we never get here; still, we need some code that will compile\n          EmitAbsurd(null, wr);\n        } else {\n          int i = 0;\n          var sourceType = (UserDefinedType)e.Source.Type.NormalizeExpand();\n          foreach (MatchCaseExpr mc in e.Cases) {\n            var w = MatchCasePrelude(source, sourceType, mc.Ctor, mc.Arguments, i, e.Cases.Count, wr);\n            TrExprOpt(mc.Body, w, inLetExprBody);\n            i++;\n          }\n        }\n      } else if (expr is StmtExpr) {\n        var e = (StmtExpr)expr;\n        TrExprOpt(e.E, wr, inLetExprBody);\n      } else {\n        // We haven't optimized any other cases, so fallback to normal compilation\n        EmitReturnExpr(expr, inLetExprBody, wr);\n      }\n    }\n\n    void CompileReturnBody(Expression body, TargetWriter wr) {\n      TrExprOpt(body.Resolved, wr, false);\n    }\n\n    // ----- Type ---------------------------------------------------------------------------------\n\n    protected readonly string DafnySetClass = \"Dafny.Set\";\n    protected readonly string DafnyMultiSetClass = \"Dafny.MultiSet\";\n    protected readonly string DafnySeqClass = \"Dafny.Sequence\";\n    protected readonly string DafnyMapClass = \"Dafny.Map\";\n\n    protected NativeType AsNativeType(Type typ) {\n      Contract.Requires(typ != null);\n      if (typ.AsNewtype != null) {\n        return typ.AsNewtype.NativeType;\n      } else if (typ.IsBitVectorType) {\n        return typ.AsBitVectorType.NativeType;\n      }\n      return null;\n    }\n\n    /// <summary>\n    /// Note, C# reverses the order of brackets in array type names.\n    /// </summary>\n    protected void TypeName_SplitArrayName(Type type, TextWriter wr, Bpl.IToken tok, out string typeNameSansBrackets, out string brackets) {\n      Contract.Requires(type != null);\n\n      var xType = type.NormalizeExpand();\n      if (xType.IsArrayType) {\n        ArrayClassDecl at = xType.AsArrayType;\n        Contract.Assert(at != null);  // follows from type.IsArrayType\n        Type elType = UserDefinedType.ArrayElementType(xType);\n        TypeName_SplitArrayName(elType, wr, tok, out typeNameSansBrackets, out brackets);\n        brackets = TypeNameArrayBrackets(at.Dims) + brackets;\n      } else {\n        typeNameSansBrackets = TypeName(type, wr, tok);\n        brackets = \"\";\n      }\n    }\n\n    protected virtual string TypeNameArrayBrackets(int dims){\n      Contract.Requires(0 <= dims);\n      var name = \"[\";\n      for (int i = 1; i < dims; i++) {\n        name += \",\";\n      }\n      return name + \"]\";\n    }\n\n    protected bool ComplicatedTypeParameterForCompilation(Type t) {\n      Contract.Requires(t != null);\n      return t.IsTraitType;\n    }\n\n    protected string/*!*/ TypeNames(List<Type/*!*/>/*!*/ types, TextWriter wr, Bpl.IToken tok) {\n      Contract.Requires(cce.NonNullElements(types));\n      Contract.Ensures(Contract.Result<string>() != null);\n      string res = \"\";\n      string c = \"\";\n      foreach (var t in types) {\n        res += c + TypeName(t, wr, tok);\n        c = \",\";\n      }\n      return res;\n    }\n\n    // TODO: move this method into CsharpCompiler\n    string/*!*/ TypeParameters(List<TypeParameter/*!*/>/*!*/ targs) {\n      Contract.Requires(cce.NonNullElements(targs));\n      Contract.Ensures(Contract.Result<string>() != null);\n\n      return Util.Comma(targs, IdName);\n    }\n\n    /// <summary>\n    /// Returns \"true\" if a value of type \"type\" can be initialized with the all-zero bit pattern.\n    /// </summary>\n    public static bool HasSimpleZeroInitializer(Type type) {\n      Contract.Requires(type != null);\n\n      bool hs, hz, ik;\n      string dv;\n      TypeInitialization(type, null, null, null, out hs, out hz, out ik, out dv);\n      return hs;\n    }\n\n    /// <summary>\n    /// Returns \"true\" if a value of type \"type\" can be initialized with the all-zero bit pattern or by calling the type's _DafnyDefaultValue method.\n    /// </summary>\n    public static bool HasZeroInitializer(Type type) {\n      Contract.Requires(type != null);\n\n      bool hs, hz, ik;\n      string dv;\n      TypeInitialization(type, null, null, null, out hs, out hz, out ik, out dv);\n      return hz;\n    }\n\n    /// <summary>\n    /// Returns \"true\" if \"type\" denotes a type for which a specific compiled value (non-ghost witness) is known.\n    /// </summary>\n    public static bool InitializerIsKnown(Type type) {\n      Contract.Requires(type != null);\n\n      bool hs, hz, ik;\n      string dv;\n      TypeInitialization(type, null, null, null, out hs, out hz, out ik, out dv);\n      return ik;\n    }\n\n    protected string DefaultValue(Type type, TextWriter wr, Bpl.IToken tok, bool inAutoInitContext = false) {\n      Contract.Requires(type != null);\n      Contract.Requires(wr != null);\n      Contract.Requires(tok != null);\n      Contract.Ensures(Contract.Result<string>() != null);\n\n      bool hs, hz, ik;\n      string dv;\n      TypeInitialization(type, this, wr, tok, out hs, out hz, out ik, out dv, inAutoInitContext);\n      return dv;\n    }\n\n    /// <summary>\n    /// This method returns three things about the given type. Since the three things are related,\n    /// it makes sense to compute them side by side.\n    ///   hasZeroInitializer - \"true\" if a value of type \"type\" can be initialized with the all-zero bit pattern or\n    ///                        by calling the type's _DafnyDefaultValue method.\n    ///   hasSimpleZeroInitializer - \"true\" if a value of type \"type\" can be initialized with the all-zero bit pattern.\n    ///   initializerIsKnown - \"true\" if \"type\" denotes a type for which a specific value (witness) is known.\n    ///   defaultValue - If \"compiler\" is non-null, \"defaultValue\" is the C# representation of one possible value of the\n    ///                  type (not necessarily the same value as the zero initializer, if any, may give).\n    ///                  If \"compiler\" is null, then \"defaultValue\" can return as anything.\n    ///   inAutoInitContext - If \"true\", the default value produced may have dummy values (outside the Dafny type) for\n    ///                       components those type requires user-specified initialization.\n    /// </summary>\n    static void TypeInitialization(Type type, Compiler/*?*/ compiler, TextWriter/*?*/ wr, Bpl.IToken/*?*/ tok,\n        out bool hasSimpleZeroInitializer, out bool hasZeroInitializer, out bool initializerIsKnown, out string defaultValue,\n        bool inAutoInitContext = false) {\n      Contract.Requires(type != null);\n      Contract.Requires(compiler == null || (wr != null && tok != null));\n      Contract.Ensures(!Contract.ValueAtReturn(out hasSimpleZeroInitializer) || Contract.ValueAtReturn(out hasZeroInitializer));  // hasSimpleZeroInitializer ==> hasZeroInitializer\n      Contract.Ensures(!Contract.ValueAtReturn(out hasZeroInitializer) || Contract.ValueAtReturn(out initializerIsKnown));  // hasZeroInitializer ==> initializerIsKnown\n      Contract.Ensures(compiler == null || Contract.ValueAtReturn(out defaultValue) != null);\n\n      var xType = type.NormalizeExpandKeepConstraints();\n      if (xType is TypeProxy) {\n        // unresolved proxy; just treat as bool, since no particular type information is apparently needed for this type\n        xType = new BoolType();\n      }\n\n      defaultValue = compiler?.TypeInitializationValue(xType, wr, tok, inAutoInitContext);\n      if (xType is BoolType) {\n        hasSimpleZeroInitializer = true;\n        hasZeroInitializer = true;\n        initializerIsKnown = true;\n        return;\n      } else if (xType is CharType) {\n        hasSimpleZeroInitializer = true;\n        hasZeroInitializer = true;\n        initializerIsKnown = true;\n        return;\n      } else if (xType is IntType || xType is BigOrdinalType) {\n        hasSimpleZeroInitializer = true;\n        hasZeroInitializer = true;\n        initializerIsKnown = true;\n        return;\n      } else if (xType is RealType) {\n        hasSimpleZeroInitializer = true;\n        hasZeroInitializer = true;\n        initializerIsKnown = true;\n        return;\n      } else if (xType is BitvectorType) {\n        var t = (BitvectorType)xType;\n        hasSimpleZeroInitializer = true;\n        hasZeroInitializer = true;\n        initializerIsKnown = true;\n        return;\n      } else if (xType is CollectionType) {\n        hasSimpleZeroInitializer = false;\n        hasZeroInitializer = true;\n        initializerIsKnown = true;\n        return;\n      }\n\n      var udt = (UserDefinedType)xType;\n      if (udt.ResolvedParam != null) {\n        hasSimpleZeroInitializer = false;\n        hasZeroInitializer = udt.ResolvedParam.Characteristics.MustSupportZeroInitialization;\n        initializerIsKnown = hasZeroInitializer;\n        // If the module is complete, we expect \"udt.ResolvedClass == null\" at this time. However, it could be that\n        // the compiler has already generated an error about this type not being compilable, in which case\n        // \"udt.ResolvedClass\" might be non-null here.\n        return;\n      }\n      var cl = udt.ResolvedClass;\n      Contract.Assert(cl != null);\n      if (cl is OpaqueTypeDecl) {\n        hasSimpleZeroInitializer = false;\n        hasZeroInitializer = ((OpaqueTypeDecl)cl).TheType.Characteristics.MustSupportZeroInitialization;\n        initializerIsKnown = hasZeroInitializer;\n        // The compiler should never need to know a \"defaultValue\" for an opaque type, but this routine may\n        // be asked from outside the compiler about one of the other output booleans.\n        Contract.Assume(compiler == null);\n        return;\n      } else if (cl is NewtypeDecl) {\n        var td = (NewtypeDecl)cl;\n        if (td.Witness != null) {\n          hasSimpleZeroInitializer = false;\n          hasZeroInitializer = false;\n          initializerIsKnown = td.WitnessKind != SubsetTypeDecl.WKind.Ghost;\n          return;\n        } else if (td.NativeType != null) {\n          bool ik;\n          string dv;\n          TypeInitialization(td.BaseType, null, null, null, out hasSimpleZeroInitializer, out hasZeroInitializer, out ik, out dv);\n          initializerIsKnown = true;\n          return;\n        } else {\n          Contract.Assert(td.WitnessKind != SubsetTypeDecl.WKind.Special);  // this value is never used with NewtypeDecl\n          string dv;\n          TypeInitialization(td.BaseType, compiler, wr, udt.tok, out hasSimpleZeroInitializer, out hasZeroInitializer, out initializerIsKnown, out dv);\n          Contract.Assert(compiler == null || string.Equals(dv, defaultValue));\n          return;\n        }\n      } else if (cl is SubsetTypeDecl) {\n        var td = (SubsetTypeDecl)cl;\n        if (td.Witness != null) {\n          hasSimpleZeroInitializer = false;\n          hasZeroInitializer = false;\n          initializerIsKnown = td.WitnessKind != SubsetTypeDecl.WKind.Ghost;\n          return;\n        } else if (td.WitnessKind == SubsetTypeDecl.WKind.Special) {\n          // WKind.Special is only used with -->, ->, and non-null types:\n          Contract.Assert(ArrowType.IsPartialArrowTypeName(td.Name) || ArrowType.IsTotalArrowTypeName(td.Name) || td is NonNullTypeDecl);\n          if (ArrowType.IsPartialArrowTypeName(td.Name)) {\n            // partial arrow\n            hasSimpleZeroInitializer = true;\n            hasZeroInitializer = true;\n            initializerIsKnown = true;\n            return;\n          } else if (ArrowType.IsTotalArrowTypeName(td.Name)) {\n            // total arrow\n            Contract.Assert(udt.TypeArgs.Count == td.TypeArgs.Count);\n            Contract.Assert(1 <= udt.TypeArgs.Count);  // the return type is one of the type arguments\n            hasSimpleZeroInitializer = false;\n            hasZeroInitializer = false;\n            bool hs, hz;\n            string dv;\n            TypeInitialization(udt.TypeArgs.Last(), compiler, wr, udt.tok, out hs, out hz, out initializerIsKnown, out dv);\n            return;\n          } else if (((NonNullTypeDecl)td).Class is ArrayClassDecl) {\n            // non-null array type; we know how to initialize them\n            hasSimpleZeroInitializer = false;\n            hasZeroInitializer = false;\n            initializerIsKnown = true;\n            Contract.Assert(udt.TypeArgs.Count == 1);\n          } else {\n            // non-null (non-array) type\n            hasSimpleZeroInitializer = false;\n            hasZeroInitializer = false;\n            initializerIsKnown = false;  // (this could be improved in some cases)\n            return;\n          }\n        } else {\n          string dv;\n          TypeInitialization(td.RhsWithArgument(udt.TypeArgs), compiler, wr, udt.tok, out hasSimpleZeroInitializer, out hasZeroInitializer, out initializerIsKnown, out dv);\n          Contract.Assert(compiler == null || string.Equals(dv, defaultValue));\n          return;\n        }\n      } else if (cl is TypeSynonymDeclBase) {\n        hasSimpleZeroInitializer = false;\n        hasZeroInitializer = ((TypeSynonymDeclBase)cl).Characteristics.MustSupportZeroInitialization;\n        initializerIsKnown = hasZeroInitializer;\n        // The compiler should never need to know a \"defaultValue\" for a(n internal) type synonym, but this routine may\n        // be asked from outside the compiler about one of the other output booleans.\n        Contract.Assume(compiler == null);\n        return;\n      } else if (cl is ClassDecl) {\n        hasSimpleZeroInitializer = true;\n        hasZeroInitializer = true;\n        initializerIsKnown = true;\n        return;\n      } else if (cl is DatatypeDecl) {\n        // --- hasZeroInitializer ---\n        hasSimpleZeroInitializer = false;  // TODO: improve this one in special cases where one of the datatype values can be represented by \"null\"\n        // --- initializerIsKnown ---\n        if (cl is CoDatatypeDecl) {\n          hasZeroInitializer = false;  // TODO: improve this one by laying down a _DafnyDefaultValue method when it's possible\n          // The constructors of a codatatype may use type arguments that are not \"smaller\" than \"type\",\n          // in which case recursing on the types of the constructor's formals may lead to an infinite loop\n          // here.  If this were important, the code here could be changed to detect such loop, which would\n          // let \"initializerIsKnown\" be computed more precisely.  For now, set it to \"true\" if the type\n          // has a zero initializer.\n          initializerIsKnown = hasZeroInitializer;\n        } else {\n          var defaultCtor = ((IndDatatypeDecl)cl).DefaultCtor;\n          var subst = Resolver.TypeSubstitutionMap(cl.TypeArgs, udt.TypeArgs);\n          hasZeroInitializer = defaultCtor.Formals.TrueForAll(formal => formal.IsGhost || HasZeroInitializer(Resolver.SubstType(formal.Type, subst)));\n          initializerIsKnown = defaultCtor.Formals.TrueForAll(formal => formal.IsGhost || InitializerIsKnown(Resolver.SubstType(formal.Type, subst)));\n        }\n        return;\n      } else {\n        Contract.Assert(false); throw new cce.UnreachableException();  // unexpected type\n      }\n    }\n\n    // ----- Stmt ---------------------------------------------------------------------------------\n\n    public class CheckHasNoAssumes_Visitor : BottomUpVisitor\n    {\n      readonly Compiler compiler;\n      TextWriter wr;\n      public CheckHasNoAssumes_Visitor(Compiler c, TextWriter wr) {\n        Contract.Requires(c != null);\n        compiler = c;\n        this.wr = wr;\n      }\n      protected override void VisitOneStmt(Statement stmt) {\n        if (stmt is AssumeStmt) {\n          compiler.Error(stmt.Tok, \"an assume statement cannot be compiled\", wr);\n        } else if (stmt is AssignSuchThatStmt) {\n          var s = (AssignSuchThatStmt)stmt;\n          if (s.AssumeToken != null) {\n            compiler.Error(stmt.Tok, \"an assume statement cannot be compiled\", wr);\n          }\n        } else if (stmt is ForallStmt) {\n          var s = (ForallStmt)stmt;\n          if (s.Body == null) {\n            compiler.Error(stmt.Tok, \"a forall statement without a body cannot be compiled\", wr);\n          }\n        } else if (stmt is WhileStmt) {\n          var s = (WhileStmt)stmt;\n          if (s.Body == null) {\n            compiler.Error(stmt.Tok, \"a while statement without a body cannot be compiled\", wr);\n          }\n        }\n      }\n    }\n\n    void TrStmt(Statement stmt, TargetWriter wr) {\n      Contract.Requires(stmt != null);\n      Contract.Requires(wr != null);\n      if (stmt.Parsed is ArmadaCreateThreadStatement)\n      {\n        CompileArmadaCreateThread((ArmadaCreateThreadStatement)stmt.Parsed, wr);\n        return;\n      }\n      if (stmt.Parsed is ArmadaCompareAndSwapStatement)\n      {\n        CompileArmadaCompareAndSwap((ArmadaCompareAndSwapStatement)stmt.Parsed, wr);\n        return;\n      }\n      if (stmt.Parsed is ArmadaAtomicExchangeStatement)\n      {\n        CompileArmadaAtomicExchange((ArmadaAtomicExchangeStatement)stmt.Parsed, wr);\n        return;\n      }\n\n      // TODO(xueyuan): Check out why while (*) {} stmts are marked as ghost.\n      // Currently we are compiling the ghost stmts anyway.\n      if (stmt.IsGhost) {\n        wr.WriteLine(\"// Marked as Ghost\");\n        //var v = new CheckHasNoAssumes_Visitor(this, wr);\n        //v.Visit(stmt);\n        //wr.WriteLine(\"{ }\");\n        //return;\n      }\n\n      if (stmt is ContinueStmt)\n      {\n        EmitContinue(wr);\n      } else if (stmt is BreakStmt) {\n        EmitBreak(null,wr);\n      } else if (stmt is JoinStmt)\n      {\n        var s = (JoinStmt) stmt;\n        EmitJoinStmt(wr, s.WhichThread);\n      } else if (stmt is FenceStmt)\n      {\n        var s = (FenceStmt) stmt;\n        EmitFenceStmt(wr);\n      } else if (stmt is GotoStmt)\n      {\n        var s = (GotoStmt) stmt;\n        EmitGotoStmt(wr, s.TargetLabel.AssignUniqueId(idGenerator));\n      } else if (stmt is DeallocStmt)\n      {\n        var s = (DeallocStmt) stmt;\n        EmitDeallocStmt(wr, s.Addr);\n      } else if (stmt is PrintStmt) {\n        var s = (PrintStmt)stmt;\n        foreach (var arg in s.Args) {\n          EmitPrintStmt(wr, arg);\n        }\n      } else if (stmt is BreakStmt) {\n        var s = (BreakStmt)stmt;\n        EmitBreak(s.TargetStmt.Labels.Data.AssignUniqueId(idGenerator), wr);\n      } else if (stmt is ProduceStmt) {\n        var s = (ProduceStmt)stmt;\n        if (s.hiddenUpdate != null) {\n          TrStmt(s.hiddenUpdate, wr);\n        }\n        if (s is YieldStmt) {\n          EmitYield(wr);\n        } else {\n          EmitReturn(this.enclosingMethod.Outs, wr);\n        }\n      } else if (stmt is UpdateStmt) {\n        var s = (UpdateStmt)stmt;\n        var resolved = s.ResolvedStatements;\n        if (resolved.Count == 1) {\n          TrStmt(resolved[0], wr);\n        } else {\n          // multi-assignment\n          Contract.Assert(s.Lhss.Count == resolved.Count);\n          Contract.Assert(s.Rhss.Count == resolved.Count);\n          var lhsTypes = new List<Type>();\n          var rhsTypes = new List<Type>();\n          var lhss = new List<Expression>();\n          var rhss = new List<AssignmentRhs>();\n          for (int i = 0; i < resolved.Count; i++) {\n            if (!resolved[i].IsGhost) {\n              var lhs = s.Lhss[i];\n              var rhs = s.Rhss[i];\n              if (rhs is HavocRhs) {\n                if (ArmadaOptions.O.ForbidNondeterminism) {\n                  Error(rhs.Tok, \"nondeterministic assignment forbidden by /definiteAssignment:3 option\", wr);\n                }\n              } else {\n                lhss.Add(lhs);\n                lhsTypes.Add(lhs.Type);\n                rhss.Add(rhs);\n                rhsTypes.Add(TypeOfRhs(rhs));\n              }\n            }\n          }\n\n          var wStmts = wr.ForkSection();\n          List<TargetWriter> wLhss, wRhss;\n          EmitMultiAssignment(out wLhss, lhsTypes, out wRhss, rhsTypes, wr);\n          for (int i = 0; i < wLhss.Count; i++) {\n            wLhss[i].Write(CreateLvalue(lhss[i], wStmts));\n            TrRhs(rhss[i], wRhss[i], wStmts);\n          }\n        }\n      } else if (stmt is AssignStmt) {\n        var s = (AssignStmt)stmt;\n        Contract.Assert(!(s.Lhs is SeqSelectExpr) || ((SeqSelectExpr)s.Lhs).SelectOne);  // multi-element array assignments are not allowed\n        if (s.Rhs is HavocRhs) {\n          if (ArmadaOptions.O.ForbidNondeterminism) {\n            Error(s.Rhs.Tok, \"nondeterministic assignment forbidden by /definiteAssignment:3 option\", wr);\n          }\n        } else {\n          var lvalue = CreateLvalue(s.Lhs, wr);\n          var wStmts = wr.ForkSection();\n          TargetWriter wLhs, wRhs;\n          var MemberSelectObjIsTrait = s.Lhs is MemberSelectExpr && ((MemberSelectExpr)s.Lhs).Obj.Type.IsTraitType && !(((MemberSelectExpr)s.Lhs).Obj is ThisExpr);\n          EmitAssignment(out wLhs, s.Lhs.Type, out wRhs, TypeOfRhs(s.Rhs), wr, MemberSelectObjIsTrait);\n          wLhs.Write(lvalue);\n          TrRhs(s.Rhs, wRhs, wStmts);\n        }\n\n      } else if (stmt is AssignSuchThatStmt) {\n        var s = (AssignSuchThatStmt)stmt;\n        if (ArmadaOptions.O.ForbidNondeterminism) {\n          Error(s.Tok, \"assign-such-that statement forbidden by /definiteAssignment:3 option\", wr);\n        }\n        if (s.AssumeToken != null) {\n          // Note, a non-ghost AssignSuchThatStmt may contain an assume\n          Error(s.AssumeToken, \"an assume statement cannot be compiled\", wr);\n        } else {\n          var lhss = s.Lhss.ConvertAll(lhs => ((IdentifierExpr)lhs.Resolved).Var);  // the resolver allows only IdentifierExpr left-hand sides\n          var missingBounds = ComprehensionExpr.BoundedPool.MissingBounds(lhss, s.Bounds, ComprehensionExpr.BoundedPool.PoolVirtues.Enumerable);\n          if (missingBounds.Count != 0) {\n            foreach (var bv in missingBounds) {\n              Error(s.Tok, \"this assign-such-that statement is too advanced for the current compiler; Dafny's heuristics cannot find any bound for variable '{0}'\", wr, bv.Name);\n            }\n          } else {\n            Contract.Assert(s.Bounds != null);\n            TrAssignSuchThat(lhss, s.Expr, s.Bounds, s.Tok.line, wr, false);\n          }\n        }\n\n      } else if (stmt is AssignOrReturnStmt) {\n        var s = (AssignOrReturnStmt)stmt;\n        // TODO there's potential here to use target-language specific features such as exceptions\n        // to make it more target-language idiomatic and improve performance\n        TrStmtList(s.ResolvedStatements, wr);\n\n      } else if (stmt is CallStmt) {\n        var s = (CallStmt)stmt;\n        TrCallStmt(s, null, wr);\n\n      } else if (stmt is BlockStmt) {\n        var w = wr.NewBlock(\"\", null, BlockTargetWriter.BraceStyle.Nothing, BlockTargetWriter.BraceStyle.Newline);\n        TrStmtList(((BlockStmt)stmt).Body, w);\n\n      } else if (stmt is IfStmt) {\n        IfStmt s = (IfStmt)stmt;\n        if (s.Guard == null) {\n          if (ArmadaOptions.O.ForbidNondeterminism) {\n            Error(s.Tok, \"nondeterministic if statement forbidden by /definiteAssignment:3 option\", wr);\n          }\n          // we can compile the branch of our choice\n          if (s.Els == null) {\n            // let's compile the \"else\" branch, since that involves no work\n            // (still, let's leave a marker in the source code to indicate that this is what we did)\n            wr.WriteLine(\"if (!false) { }\");\n          } else {\n            // let's compile the \"then\" branch\n            wr.Write(\"if (true) \");\n            TrStmt(s.Thn, wr);\n          }\n        } else {\n          if (s.IsBindingGuard && ArmadaOptions.O.ForbidNondeterminism) {\n            Error(s.Tok, \"binding if statement forbidden by /definiteAssignment:3 option\", wr);\n          }\n          TargetWriter guardWriter;\n          var thenWriter = EmitIf(out guardWriter, s.Els != null, wr);\n          TrExpr(s.IsBindingGuard ? Translator.AlphaRename((ExistsExpr)s.Guard, \"eg_d\") : s.Guard, guardWriter, false);\n\n          // We'd like to do \"TrStmt(s.Thn, indent)\", except we want the scope of any existential variables to come inside the block\n          if (s.IsBindingGuard) {\n            IntroduceAndAssignBoundVars((ExistsExpr)s.Guard, thenWriter);\n          }\n          TrStmtList(s.Thn.Body, thenWriter);\n\n          if (s.Els != null) {\n            TrStmt(s.Els, wr);\n          }\n        }\n\n      } else if (stmt is AlternativeStmt) {\n        var s = (AlternativeStmt)stmt;\n        if (ArmadaOptions.O.ForbidNondeterminism && 2 <= s.Alternatives.Count) {\n          Error(s.Tok, \"case-based if statement forbidden by /definiteAssignment:3 option\", wr);\n        }\n        foreach (var alternative in s.Alternatives) {\n          TargetWriter guardWriter;\n          var thn = EmitIf(out guardWriter, true, wr);\n          TrExpr(alternative.IsBindingGuard ? Translator.AlphaRename((ExistsExpr)alternative.Guard, \"eg_d\") : alternative.Guard, guardWriter, false);\n          if (alternative.IsBindingGuard) {\n            IntroduceAndAssignBoundVars((ExistsExpr)alternative.Guard, thn);\n          }\n          TrStmtList(alternative.Body, thn);\n        }\n        using (var wElse = wr.NewBlock(\"\", null, BlockTargetWriter.BraceStyle.Nothing)) {\n          EmitAbsurd(\"unreachable alternative\", wElse);\n        }\n\n      } else if (stmt is WhileStmt) {\n        WhileStmt s = (WhileStmt)stmt;\n        if (s.Body == null) {\n          return;\n        }\n        if (s.Guard == null) {\n          if (ArmadaOptions.O.ForbidNondeterminism) {\n            Error(s.Tok, \"nondeterministic loop forbidden by /definiteAssignment:3 option\", wr);\n          }\n          // this loop is allowed to stop iterating at any time; we choose to never iterate; but we still emit a loop structure\n          var guardWriter = EmitWhile(new List<Statement>(), wr);\n          guardWriter.Write(\"false\");\n        } else {\n          var guardWriter = EmitWhile(s.Body.Body, wr);\n          TrExpr(s.Guard, guardWriter, false);\n        }\n\n      } else if (stmt is AlternativeLoopStmt) {\n        var s = (AlternativeLoopStmt)stmt;\n        if (ArmadaOptions.O.ForbidNondeterminism) {\n          Error(s.Tok, \"case-based loop forbidden by /definiteAssignment:3 option\", wr);\n        }\n        if (s.Alternatives.Count != 0) {\n          TargetWriter whileGuardWriter;\n          var w = CreateWhileLoop(out whileGuardWriter, wr);\n          whileGuardWriter.Write(\"true\");\n          foreach (var alternative in s.Alternatives) {\n            TargetWriter guardWriter;\n            var thn = EmitIf(out guardWriter, true, w);\n            TrExpr(alternative.Guard, guardWriter, false);\n            TrStmtList(alternative.Body, thn);\n          }\n          using (var wElse = w.NewBlock(\"\")) {\n            EmitBreak(null, wElse);\n          }\n        }\n\n      } else if (stmt is ForallStmt) {\n        var s = (ForallStmt)stmt;\n        if (s.Kind != ForallStmt.BodyKind.Assign) {\n          // Call and Proof have no side effects, so they can simply be optimized away.\n          return;\n        } else if (s.BoundVars.Count == 0) {\n          // the bound variables just spell out a single point, so the forall statement is equivalent to one execution of the body\n          TrStmt(s.Body, wr);\n          return;\n        }\n        var s0 = (AssignStmt)s.S0;\n        if (s0.Rhs is HavocRhs) {\n          if (ArmadaOptions.O.ForbidNondeterminism) {\n            Error(s0.Rhs.Tok, \"nondeterministic assignment forbidden by /definiteAssignment:3 option\", wr);\n          }\n          // The forall statement says to havoc a bunch of things.  This can be efficiently compiled\n          // into doing nothing.\n          return;\n        }\n        var rhs = ((ExprRhs)s0.Rhs).Expr;\n\n        if (CanSequentializeForall(s.BoundVars, s.Bounds, s.Range, s0.Lhs, rhs)) {\n          // Just put the statement inside the loops\n          var wLoop = CompileGuardedLoops(s.BoundVars, s.Bounds, s.Range, wr);\n          TrStmt(s0, wLoop);\n        } else {\n          // Compile:\n          //   forall (w,x,y,z | Range(w,x,y,z)) {\n          //     LHS(w,x,y,z) := RHS(w,x,y,z);\n          //   }\n          // where w,x,y,z have types seq<W>,set<X>,int,bool and LHS has L-1 top-level subexpressions\n          // (that is, L denotes the number of top-level subexpressions of LHS plus 1),\n          // into:\n          //   var ingredients = new List< L-Tuple >();\n          //   foreach (W w in sq.UniqueElements) {\n          //     foreach (X x in st.Elements) {\n          //       for (BigInteger y = Lo; j < Hi; j++) {\n          //         for (bool z in Helper.AllBooleans) {\n          //           if (Range(w,x,y,z)) {\n          //             ingredients.Add(new L-Tuple( LHS0(w,x,y,z), LHS1(w,x,y,z), ..., RHS(w,x,y,z) ));\n          //           }\n          //         }\n          //       }\n          //     }\n          //   }\n          //   foreach (L-Tuple l in ingredients) {\n          //     LHS[ l0, l1, l2, ..., l(L-2) ] = l(L-1);\n          //   }\n          //\n          // Note, because the .NET Tuple class only supports up to 8 components, the compiler implementation\n          // here supports arrays only up to 6 dimensions.  This does not seem like a serious practical limitation.\n          // However, it may be more noticeable if the forall statement supported forall assignments in its\n          // body.  To support cases where tuples would need more than 8 components, .NET Tuple's would have to\n          // be nested.\n\n          // Temporary names\n          var c = idGenerator.FreshNumericId(\"_ingredients+_tup\");\n          string ingredients = \"_ingredients\" + c;\n          string tup = \"_tup\" + c;\n\n          // Compute L\n          int L;\n          string tupleTypeArgs;\n          List<Type> tupleTypeArgsList;\n          if (s0.Lhs is MemberSelectExpr) {\n            var lhs = (MemberSelectExpr) s0.Lhs;\n            L = 2;\n            tupleTypeArgs = TypeName(lhs.Obj.Type, wr, lhs.tok);\n            tupleTypeArgsList = new List<Type> { lhs.Obj.Type };\n          } else if (s0.Lhs is SeqSelectExpr) {\n            var lhs = (SeqSelectExpr) s0.Lhs;\n            L = 3;\n            // note, we might as well do the BigInteger-to-int cast for array indices here, before putting things into the Tuple rather than when they are extracted from the Tuple\n            tupleTypeArgs = TypeName(lhs.Seq.Type, wr, lhs.tok) + IntSelect;\n            tupleTypeArgsList = new List<Type> { lhs.Seq.Type, null };\n          } else {\n            var lhs = (MultiSelectExpr) s0.Lhs;\n            L = 2 + lhs.Indices.Count;\n            if (8 < L) {\n              Error(lhs.tok, \"compiler currently does not support assignments to more-than-6-dimensional arrays in forall statements\", wr);\n              return;\n            }\n            tupleTypeArgs = TypeName(lhs.Array.Type, wr, lhs.tok);\n            tupleTypeArgsList = new List<Type> { lhs.Array.Type };\n            for (int i = 0; i < lhs.Indices.Count; i++) {\n              // note, we might as well do the BigInteger-to-int cast for array indices here, before putting things into the Tuple rather than when they are extracted from the Tuple\n              tupleTypeArgs += IntSelect;\n              tupleTypeArgsList.Add(null);\n            }\n\n          }\n          tupleTypeArgs += \",\" + TypeName(rhs.Type, wr, rhs.tok);\n          tupleTypeArgsList.Add(rhs.Type);\n\n          // declare and construct \"ingredients\"\n          var wrOuter = EmitIngredients(wr, ingredients, L, tupleTypeArgs, s, s0, rhs);\n\n          //   foreach (L-Tuple l in ingredients) {\n          //     LHS[ l0, l1, l2, ..., l(L-2) ] = l(L-1);\n          //   }\n          TargetWriter collWriter;\n          TargetTupleSize = L;\n          wr = CreateForeachLoop(tup, null, out collWriter, wrOuter);\n          collWriter.Write(ingredients);\n          {\n            var wTup = new TargetWriter(wr.IndentLevel, true);\n            var wCoerceTup = EmitCoercionToArbitraryTuple(wTup);\n            wCoerceTup.Write(tup);\n            tup = wTup.ToString();\n          }\n          if (s0.Lhs is MemberSelectExpr) {\n            EmitMemberSelect(s0, tupleTypeArgsList,wr,tup);\n          } else if (s0.Lhs is SeqSelectExpr) {\n            EmitSeqSelect(s0, tupleTypeArgsList, wr, tup);\n          } else {\n            EmitMultiSelect(s0, tupleTypeArgsList, wr, tup, L);\n          }\n        }\n      } else if (stmt is MatchStmt) {\n        MatchStmt s = (MatchStmt)stmt;\n        // Type source = e;\n        // if (source.is_Ctor0) {\n        //   FormalType f0 = ((Dt_Ctor0)source._D).a0;\n        //   ...\n        //   Body0;\n        // } else if (...) {\n        //   ...\n        // } else if (true) {\n        //   ...\n        // }\n        if (s.Cases.Count != 0) {\n          string source = idGenerator.FreshId(\"_source\");\n          DeclareLocalVar(source, s.Source.Type, s.Source.tok, s.Source, false, wr);\n\n          int i = 0;\n          var sourceType = (UserDefinedType)s.Source.Type.NormalizeExpand();\n          foreach (MatchCaseStmt mc in s.Cases) {\n            var w = MatchCasePrelude(source, sourceType, cce.NonNull(mc.Ctor), mc.Arguments, i, s.Cases.Count, wr);\n            TrStmtList(mc.Body, w);\n            i++;\n          }\n        }\n\n      } else if (stmt is VarDeclStmt) {\n        var s = (VarDeclStmt)stmt;\n        var i = 0;\n        foreach (var local in s.Locals) {\n          bool hasRhs = s.Update is AssignSuchThatStmt;\n          if (!hasRhs && s.Update is UpdateStmt u) {\n            if (i < u.Rhss.Count && u.Rhss[i] is HavocRhs) {\n              // there's no specific initial value\n            } else {\n              hasRhs = true;\n            }\n          }\n          TrLocalVar(local, !hasRhs, wr);\n          i++;\n        }\n        if (s.Update != null) {\n          TrStmt(s.Update, wr);\n        }\n\n      } else if (stmt is LetStmt) {\n        var s = (LetStmt)stmt;\n        if (Contract.Exists(s.LHS.Vars, bv => !bv.IsGhost)) {\n          TrCasePatternOpt(s.LHS, s.RHS, wr, false);\n        }\n      } else if (stmt is ModifyStmt) {\n        var s = (ModifyStmt)stmt;\n        if (s.Body != null) {\n          TrStmt(s.Body, wr);\n        } else if (ArmadaOptions.O.ForbidNondeterminism) {\n          Error(s.Tok, \"modify statement without a body forbidden by /definiteAssignment:3 option\", wr);\n        }\n\n      } else {\n        Contract.Assert(false); throw new cce.UnreachableException();  // unexpected statement\n      }\n    }\n\n    protected virtual TargetWriter EmitIngredients(TargetWriter wr, string ingredients, int L, string tupleTypeArgs, ForallStmt s, AssignStmt s0, Expression rhs){\n\n      using (var wrVarInit = DeclareLocalVar(ingredients, null, null, wr)){\n        EmitEmptyTupleList(tupleTypeArgs, wrVarInit);\n      }\n\n      var wrOuter = wr;\n      wr = CompileGuardedLoops(s.BoundVars, s.Bounds, s.Range, wr);\n\n      using (var wrTuple = EmitAddTupleToList(ingredients, tupleTypeArgs, wr)){\n        if (s0.Lhs is MemberSelectExpr){\n          var lhs = (MemberSelectExpr) s0.Lhs;\n          TrExpr(lhs.Obj, wrTuple, false);\n        }\n        else if (s0.Lhs is SeqSelectExpr){\n          var lhs = (SeqSelectExpr) s0.Lhs;\n          TrExpr(lhs.Seq, wrTuple, false);\n          wrTuple.Write(\", \");\n          EmitExprAsInt(lhs.E0, false, wrTuple);\n        }\n        else{\n          var lhs = (MultiSelectExpr) s0.Lhs;\n          TrExpr(lhs.Array, wrTuple, false);\n          for (int i = 0; i < lhs.Indices.Count; i++){\n            wrTuple.Write(\", \");\n            EmitExprAsInt(lhs.Indices[i], false, wrTuple);\n          }\n        }\n\n        wrTuple.Write(\", \");\n        TrExpr(rhs, wrTuple, false);\n      }\n\n      return wrOuter;\n    }\n\n    protected virtual void EmitMemberSelect(AssignStmt s0, List<Type> tupleTypeArgsList, TargetWriter wr, string tup){\n      var lhs = (MemberSelectExpr) s0.Lhs;\n      var wCoerced = EmitCoercionIfNecessary(from: null, to: tupleTypeArgsList[0], tok: s0.Tok, wr: wr);\n      EmitTupleSelect(tup, 0, wCoerced);\n      wr.Write(\".{0} = \", IdMemberName(lhs));\n      wCoerced = EmitCoercionIfNecessary(from: null, to: tupleTypeArgsList[1], tok: s0.Tok, wr: wr);\n      EmitTupleSelect(tup, 1, wCoerced);\n      EndStmt(wr);\n    }\n\n    protected virtual void EmitSeqSelect(AssignStmt s0, List<Type> tupleTypeArgsList, TargetWriter wr, string tup){\n      var lhs = (SeqSelectExpr) s0.Lhs;\n      TargetWriter wColl, wIndex, wValue;\n      EmitIndexCollectionUpdate(out wColl, out wIndex, out wValue, wr, nativeIndex: true);\n      var wCoerce = EmitCoercionIfNecessary(from: null, to: lhs.Seq.Type, tok: s0.Tok, wr: wColl);\n      EmitTupleSelect(tup, 0, wCoerce);\n      var wCast = EmitCoercionToNativeInt(wIndex);\n      EmitTupleSelect(tup, 1, wCast);\n      EmitTupleSelect(tup, 2, wValue);\n      EndStmt(wr);\n    }\n\n    protected virtual void EmitMultiSelect(AssignStmt s0, List<Type> tupleTypeArgsList, TargetWriter wr, string tup, int L){\n      var lhs = (MultiSelectExpr) s0.Lhs;\n      var wArray = new TargetWriter(wr.IndentLevel, true);\n      var wCoerced = EmitCoercionIfNecessary(from: null, to: tupleTypeArgsList[0], tok: s0.Tok, wr: wArray);\n      EmitTupleSelect(tup, 0, wCoerced);\n      var array = wArray.ToString();\n      var indices = new List<string>();\n      for (int i = 0; i < lhs.Indices.Count; i++){\n        var wIndex = new TargetWriter();\n        EmitTupleSelect(tup, i + 1, wIndex);\n        indices.Add(wIndex.ToString());\n      }\n      EmitArraySelectAsLvalue(array, indices, tupleTypeArgsList[L - 1], wr);\n      wr.Write(\" = \");\n      EmitTupleSelect(tup, L - 1, wr);\n      EndStmt(wr);\n    }\n\n    protected TargetWriter CompileGuardedLoops(List<BoundVar> bvs, List<ComprehensionExpr.BoundedPool> bounds, Expression range, TargetWriter wr) {\n      var n = bvs.Count;\n      Contract.Assert(bounds.Count == n);\n      for (int i = 0; i < n; i++) {\n        var bound = bounds[i];\n        var bv = bvs[i];\n        TargetWriter collectionWriter;\n        wr = CreateForeachLoop(IdName(bv), bv.Type, out collectionWriter, wr);\n        CompileCollection(bound, bv, false, false, collectionWriter, bounds, bvs, i);\n      }\n\n      // if (range) {\n      //   ingredients.Add(new L-Tuple( LHS0(w,x,y,z), LHS1(w,x,y,z), ..., RHS(w,x,y,z) ));\n      // }\n      TargetWriter guardWriter;\n      wr = EmitIf(out guardWriter, false, wr);\n      foreach (var bv in bvs) {\n        var bvConstraints = Resolver.GetImpliedTypeConstraint(bv, bv.Type);\n        TrParenExpr(bvConstraints, guardWriter, false);\n        guardWriter.Write(\" && \");\n      }\n      TrParenExpr(range, guardWriter, false);\n\n      return wr;\n    }\n\n    void CompileCollection(ComprehensionExpr.BoundedPool bound, IVariable bv, bool inLetExprBody, bool includeDuplicates,\n        TargetWriter collectionWriter,\n        List<ComprehensionExpr.BoundedPool>/*?*/ bounds = null, List<BoundVar>/*?*/ boundVars = null, int boundIndex = 0) {\n      Contract.Requires(bound != null);\n      Contract.Requires(bounds == null || (boundVars != null && bounds.Count == boundVars.Count && 0 <= boundIndex && boundIndex < bounds.Count));\n      Contract.Requires(collectionWriter != null);\n      var propertySuffix = SupportsProperties ? \"\" : \"()\";\n\n      if (bound is ComprehensionExpr.BoolBoundedPool) {\n        collectionWriter.Write(\"{0}.AllBooleans()\", GetHelperModuleName());\n      } else if (bound is ComprehensionExpr.CharBoundedPool) {\n        collectionWriter.Write(\"{0}.AllChars()\", GetHelperModuleName());\n      } else if (bound is ComprehensionExpr.IntBoundedPool) {\n        var b = (ComprehensionExpr.IntBoundedPool)bound;\n        TargetWriter wLo, wHi;\n        EmitIntegerRange(bv.Type, out wLo, out wHi, collectionWriter);\n        if (b.LowerBound == null) {\n          EmitNull(bv.Type, wLo);\n        } else if (bounds != null) {\n          var low = SubstituteBound(b, bounds, boundVars, boundIndex, true);\n          TrExpr(low, wLo, inLetExprBody);\n        } else {\n          TrExpr(b.LowerBound, wLo, inLetExprBody);\n        }\n        if (b.UpperBound == null) {\n          EmitNull(bv.Type, wHi);\n        } else if (bounds != null) {\n          var high = SubstituteBound(b, bounds, boundVars, boundIndex, false);\n          TrExpr(high, wHi, inLetExprBody);\n        } else {\n          TrExpr(b.UpperBound, wHi, inLetExprBody);\n        }\n      } else if (bound is AssignSuchThatStmt.WiggleWaggleBound) {\n        collectionWriter.Write(\"{0}.AllIntegers()\", GetHelperModuleName());\n      } else if (bound is ComprehensionExpr.ExactBoundedPool) {\n        var b = (ComprehensionExpr.ExactBoundedPool)bound;\n        EmitSingleValueGenerator(b.E, inLetExprBody, TypeName(b.E.Type, collectionWriter, b.E.tok), collectionWriter);\n      } else if (bound is ComprehensionExpr.SetBoundedPool) {\n        var b = (ComprehensionExpr.SetBoundedPool)bound;\n        TrParenExpr(b.Set, collectionWriter, inLetExprBody);\n        collectionWriter.Write(\".Elements\" + propertySuffix);\n      } else if (bound is ComprehensionExpr.MultiSetBoundedPool) {\n        var b = (ComprehensionExpr.MultiSetBoundedPool)bound;\n        TrParenExpr(b.MultiSet, collectionWriter, inLetExprBody);\n        collectionWriter.Write((includeDuplicates ? \".Elements\" : \".UniqueElements\") + propertySuffix);\n      } else if (bound is ComprehensionExpr.SubSetBoundedPool) {\n        var b = (ComprehensionExpr.SubSetBoundedPool)bound;\n        TrParenExpr(b.UpperBound, collectionWriter, inLetExprBody);\n        collectionWriter.Write(\".AllSubsets\" + propertySuffix);\n      } else if (bound is ComprehensionExpr.MapBoundedPool) {\n        var b = (ComprehensionExpr.MapBoundedPool)bound;\n        TrParenExpr(b.Map, collectionWriter, inLetExprBody);\n        collectionWriter.Write(\".Keys{0}.Elements{0}\", propertySuffix);\n      } else if (bound is ComprehensionExpr.SeqBoundedPool) {\n        var b = (ComprehensionExpr.SeqBoundedPool)bound;\n        TrParenExpr(b.Seq, collectionWriter, inLetExprBody);\n        collectionWriter.Write((includeDuplicates ? \".Elements\" : \".UniqueElements\") + propertySuffix);\n      } else if (bound is ComprehensionExpr.DatatypeBoundedPool) {\n        var b = (ComprehensionExpr.DatatypeBoundedPool)bound;\n        collectionWriter.Write(\"{0}.AllSingletonConstructors{1}\", TypeName_Companion(bv.Type, collectionWriter, bv.Tok, null), propertySuffix);\n      } else {\n        Contract.Assert(false); throw new cce.UnreachableException();  // unexpected BoundedPool type\n      }\n    }\n\n    private Expression SubstituteBound(ComprehensionExpr.IntBoundedPool b, List<ComprehensionExpr.BoundedPool> bounds, List<BoundVar> boundVars, int index, bool lowBound) {\n      Contract.Requires(b != null);\n      Contract.Requires((lowBound ? b.LowerBound : b.UpperBound) != null);\n      Contract.Requires(bounds != null);\n      Contract.Requires(boundVars != null);\n      Contract.Requires(bounds.Count == boundVars.Count);\n      Contract.Requires(0 <= index && index < boundVars.Count);\n      // if the outer bound is dependent on the inner boundvar, we need to\n      // substitute the inner boundvar with its bound.\n      var bnd = lowBound ? b.LowerBound : b.UpperBound;\n      var sm = new Dictionary<IVariable, Expression>();\n      for (int i = index+1; i < boundVars.Count; i++) {\n        var bound = bounds[i];\n        if (bound is ComprehensionExpr.IntBoundedPool) {\n          var ib = (ComprehensionExpr.IntBoundedPool)bound;\n          var bv = boundVars[i];\n          sm[bv] = lowBound ? ib.LowerBound : ib.UpperBound;\n        }\n      }\n      var su = new Translator.Substituter(null, sm, new Dictionary<TypeParameter, Type>());\n      return su.Substitute(bnd);\n    }\n\n    private void IntroduceAndAssignBoundVars(ExistsExpr exists, TargetWriter wr) {\n      Contract.Requires(exists != null);\n      Contract.Assume(exists.Bounds != null);  // follows from successful resolution\n      Contract.Assert(exists.Range == null);  // follows from invariant of class IfStmt\n      foreach (var bv in exists.BoundVars) {\n        TrLocalVar(bv, false, wr);\n      }\n      var ivars = exists.BoundVars.ConvertAll(bv => (IVariable)bv);\n      TrAssignSuchThat(ivars, exists.Term, exists.Bounds, exists.tok.line, wr, false);\n    }\n\n    private bool CanSequentializeForall(List<BoundVar> bvs, List<ComprehensionExpr.BoundedPool> bounds, Expression range, Expression lhs, Expression rhs) {\n      // Given a statement\n      //\n      //   forall i, ... | R {\n      //     L := E;\n      //   }\n      //\n      // we sequentialize if all of these conditions hold:\n      //\n      //   1. There are no calls to functions which may have read effects in R,\n      //      L, or E\n      //   2. Each index value will be produced only once (note that this is\n      //      currently always true thanks to the use of UniqueElements())\n      //   3. If L has the form A[I] for some A and I, then one of the following\n      //      is true:\n      //      a. There are no array dereferences or array-to-sequence\n      //         conversions in R, A, I, or E\n      //      b. All of the following are true:\n      //         i.   There is only one bound variable; call it i\n      //         ii.  I is the variable i\n      //         iii. Each array dereference in R, A, or E has the form B[i] for\n      //              some B\n      //         iv.  There are no array-to-sequence conversions in R, A, or E\n      //   4. If L has the form A[I, J, ...] for some A, I, J, ... then there\n      //      are no multi-D array dereferences in R, A, E, or any of the\n      //      indices I, J, ...\n      //   5. If L has the form O.f for some field f, then one of the following\n      //      is true:\n      //      a. There are no accesses of f in R, O, or E\n      //      b. All of the following are true:\n      //         i.   There is only one bound variable; call it i\n      //         ii.  O is the variable i\n      //         iii. Each access of f in R or E has the form i.f\n      //\n      // TODO It may be possible to weaken rule 4 by adding an alternative\n      // similar to rules 3b and 5b.\n      Contract.Assert(bvs.Count == bounds.Count);\n\n      if (!noImpureFunctionCalls(lhs, rhs, range)) {\n        return false;\n      } else if (lhs is SeqSelectExpr sse) {\n        return\n          no1DArrayAccesses(sse.Seq, sse.E0, range, rhs) ||\n\n          bvs.Count == 1 &&\n          isVar(bvs[0], sse.E0) &&\n          indexIsAlwaysVar(bvs[0], range, sse.Seq, rhs); // also covers sequence conversions\n      } else if (lhs is MultiSelectExpr mse) {\n        return\n          noMultiDArrayAccesses(mse.Array, range, rhs) &&\n          noMultiDArrayAccesses(mse.Indices.ToArray());\n      } else {\n        // !@#$#@$% scope rules won't let me call this mse ...\n        var mse2 = (MemberSelectExpr) lhs;\n\n        return\n          noFieldAccesses(mse2.Member, mse2.Obj, range, rhs) ||\n\n          bvs.Count == 1 &&\n          isVar(bvs[0], mse2.Obj) &&\n          accessedObjectIsAlwaysVar(mse2.Member, bvs[0], range, rhs);\n      }\n\n      bool noImpureFunctionCalls(params Expression[] exprs) {\n        return exprs.All(e => Check<ApplyExpr>(e, ae => {\n          var ty = (UserDefinedType) ae.Function.Type.NormalizeExpandKeepConstraints();\n          return ArrowType.IsPartialArrowTypeName(ty.Name) || ArrowType.IsTotalArrowTypeName(ty.Name);\n        }));\n      }\n\n      bool no1DArrayAccesses(params Expression[] exprs) {\n        return exprs.All(e => Check<SeqSelectExpr>(e, sse => !sse.Seq.Type.IsArrayType)); // allow sequence accesses\n      }\n\n      bool noMultiDArrayAccesses(params Expression[] exprs) {\n        return exprs.All(e => Check<MultiSelectExpr>(e, _ => false));\n      }\n\n      bool noFieldAccesses(MemberDecl member, params Expression[] exprs) {\n        return exprs.All(e => Check<MemberSelectExpr>(e, mse => mse.Member != member));\n      }\n\n      bool isVar(BoundVar var, Expression expr) {\n        return expr.Resolved is IdentifierExpr ie && ie.Var == var;\n      }\n\n      bool indexIsAlwaysVar(BoundVar var, params Expression[] exprs) {\n        return exprs.All(e => Check<SeqSelectExpr>(e, sse2 => sse2.SelectOne && isVar(var, sse2.E0)));\n      }\n\n      bool accessedObjectIsAlwaysVar(MemberDecl member, BoundVar var, params Expression[] exprs) {\n        return exprs.All(e => Check<MemberSelectExpr>(e, mse => mse.Member != member || isVar(var, mse.Obj)));\n      }\n    }\n\n    /// <summary>\n    /// Check all of the given expression's subexpressions of a given type\n    /// using a predicate.  Returns true only if the predicate returns true for\n    /// all subexpressions of type <typeparamref name=\"E\"/>.\n    /// </summary>\n    private static bool Check<E>(Expression e, Predicate<E> pred) where E : Expression {\n      var checker = new Checker<E>(pred);\n      checker.Visit(e, null);\n      return checker.Passing;\n    }\n\n    private class Checker<E> : TopDownVisitor<object> where E : Expression {\n      private readonly Predicate<E> Pred;\n      public bool Passing = true;\n\n      public Checker(Predicate<E> pred) {\n        Pred = pred;\n      }\n\n      protected override bool VisitOneExpr(Expression expr, ref object st) {\n        if (expr is E e && !Pred(e)) {\n          Passing = false;\n          return false;\n        } else {\n          return true;\n        }\n      }\n    }\n\n    private void TrAssignSuchThat(List<IVariable> lhss, Expression constraint, List<ComprehensionExpr.BoundedPool> bounds, int debuginfoLine, TargetWriter wr, bool inLetExprBody) {\n      Contract.Requires(lhss != null);\n      Contract.Requires(constraint != null);\n      Contract.Requires(bounds != null);\n      // For \"i,j,k,l :| R(i,j,k,l);\", emit something like:\n      //\n      // for (BigInteger iterLimit = 5; ; iterLimit *= 2) {\n      //   var il$0 = iterLimit;\n      //   foreach (L l' in sq.Elements) { l = l';\n      //     if (il$0 == 0) { break; }  il$0--;\n      //     var il$1 = iterLimit;\n      //     foreach (K k' in st.Elements) { k = k';\n      //       if (il$1 == 0) { break; }  il$1--;\n      //       var il$2 = iterLimit;\n      //       j = Lo;\n      //       for (;; j++) {\n      //         if (il$2 == 0) { break; }  il$2--;\n      //         foreach (bool i' in Helper.AllBooleans) { i = i';\n      //           if (R(i,j,k,l)) {\n      //             goto ASSIGN_SUCH_THAT_<id>;\n      //           }\n      //         }\n      //       }\n      //     }\n      //   }\n      // }\n      // throw new Exception(\"assign-such-that search produced no value\"); // a verified program never gets here; however, we need this \"throw\" to please the C# compiler\n      // ASSIGN_SUCH_THAT_<id>: ;\n      //\n      // where the iterLimit loop can be omitted if lhss.Count == 1 or if all bounds are finite.  Further optimizations could be done, but\n      // are omitted for now.\n      //\n      var n = lhss.Count;\n      Contract.Assert(bounds.Count == n);\n      var c = idGenerator.FreshNumericId(\"_ASSIGN_SUCH_THAT_+_iterLimit_\");\n      var doneLabel = \"_ASSIGN_SUCH_THAT_\" + c;\n      var iterLimit = \"_iterLimit_\" + c;\n\n      bool needIterLimit = lhss.Count != 1 && bounds.Exists(bnd => (bnd.Virtues & ComprehensionExpr.BoundedPool.PoolVirtues.Finite) == 0);\n      wr = CreateLabeledCode(doneLabel, wr);\n      var wrOuter = wr;\n      if (needIterLimit) {\n        wr = CreateDoublingForLoop(iterLimit, 5, wr);\n      }\n\n      for (int i = 0; i < n; i++) {\n        var bound = bounds[i];\n        Contract.Assert((bound.Virtues & ComprehensionExpr.BoundedPool.PoolVirtues.Enumerable) != 0);  // if we have got this far, it must be an enumerable bound\n        var bv = lhss[i];\n        if (needIterLimit) {\n          DeclareLocalVar(string.Format(\"{0}_{1}\", iterLimit, i), null, null, false, iterLimit, wr, Type.Int);\n        }\n        var tmpVar = idGenerator.FreshId(\"_assign_such_that_\");\n        TargetWriter collectionWriter;\n        wr = CreateForeachLoop(tmpVar, bv.Type, out collectionWriter, wr, IdName(bv));\n        CompileCollection(bound, bv, inLetExprBody, true, collectionWriter);\n        if (needIterLimit) {\n          var varName = string.Format(\"{0}_{1}\", iterLimit, i);\n          TargetWriter isZeroWriter;\n          var thn = EmitIf(out isZeroWriter, false, wr);\n          EmitIsZero(varName, isZeroWriter);\n          EmitBreak(null, thn);\n          EmitDecrementVar(varName, wr);\n        }\n      }\n      TargetWriter guardWriter;\n      var wBody = EmitIf(out guardWriter, false, wr);\n      TrExpr(constraint, guardWriter, inLetExprBody);\n      EmitBreak(doneLabel, wBody);\n      // Java compiler throws unreachable error when absurd statement is written after unbounded for-loop, so we don't write it then.\n      EmitAbsurd(string.Format(\"assign-such-that search produced no value (line {0})\", debuginfoLine), wrOuter, needIterLimit);\n    }\n\n    string CreateLvalue(Expression lhs, TargetWriter wr) {\n      Contract.Requires(lhs != null);\n      Contract.Requires(wr != null);\n\n      lhs = lhs.Resolved;\n      if (lhs is IdentifierExpr) {\n        var ll = (IdentifierExpr)lhs;\n        return IdName(ll.Var);\n      } else if (lhs is MemberSelectExpr) {\n\n        var ll = (MemberSelectExpr)lhs;\n        Contract.Assert(!ll.Member.IsInstanceIndependentConstant);  // instance-independent const's don't have assignment statements\n        //var obj = StabilizeExpr(ll.Obj, \"_obj\", wr);\n\n        // generate Obj Name\n        var ow = new TargetWriter();\n        TrParenExpr(ll.Obj, ow, false);\n        var obj = ow.ToString();\n\n        // Omit the object when it is from default module.\n        if (obj == \"(_default)\")\n          return ll.MemberName;\n\n        // generate\n        var sw = new TargetWriter();\n        var MemberSelectObjIsTrait = ll.Obj.Type.IsTraitType && !(ll.Obj is ThisExpr);\n        var w = EmitMemberSelect(ll.Member, true, lhs.Type, sw, MemberSelectObjIsTrait);\n        // write the object name\n        w.Write(obj);\n\n        return sw.ToString();\n      } else if (lhs is UnaryOpExpr) {\n        var ll = (UnaryOpExpr) lhs;\n        Contract.Assert(ll.Op == UnaryOpExpr.Opcode.Dereference);\n        return \"*\" + (CreateLvalue(ll.E, wr));\n      } else if (lhs is SeqSelectExpr) {\n        var ll = (SeqSelectExpr)lhs;\n\n        var arr_wr = new TargetWriter();\n        TrExpr(ll.Seq, arr_wr, false);\n        var arr = arr_wr.ToString();\n\n        var index_wr = new TargetWriter();\n        TrExpr(ll.E0, index_wr, false);\n        var index = index_wr.ToString();\n\n        var sw = new TargetWriter();\n        EmitArraySelectAsLvalue(arr, new List<string>() { index }, ll.Type, sw);\n        return sw.ToString();\n      } else if (lhs is BinaryExpr) {\n        var ll = (BinaryExpr) lhs;\n        return \"(\" + CreateLvalue(ll.E0, wr) + BinaryExpr.OpcodeString(ll.Op) + CreateLvalue(ll.E1, wr) + \")\";\n      } else {\n        var ll = (MultiSelectExpr)lhs;\n        string arr = StabilizeExpr(ll.Array, \"_arr\", wr);\n        var indices = new List<string>();\n        int i = 0;\n        foreach (var idx in ll.Indices) {\n          indices.Add(StabilizeExpr(idx, \"_index\" + i + \"_\", wr));\n          i++;\n        }\n        var sw = new TargetWriter();\n        EmitArraySelectAsLvalue(arr, indices, ll.Type, sw);\n        return sw.ToString();\n      }\n    }\n\n    /// <summary>\n    /// If the given expression's value is stable, translate it and return the\n    /// string form.  Otherwise, output code to evaluate the expression, then\n    /// return a fresh variable bound to its value.\n    /// </summary>\n    /// <param name=\"e\">An expression to evaluate</param>\n    /// <param name=\"prefix\">The prefix to give the fresh variable, if\n    /// needed.</param>\n    /// <param name=\"wr\">A writer in a position to write statements\n    /// evaluating the expression</param>\n    /// <returns>A string giving the translated value as a stable\n    /// expression</returns>\n    /// <seealso cref=\"IsStableExpr\"/>\n    private string StabilizeExpr(Expression e, string prefix, TargetWriter wr) {\n      if (IsStableExpr(e)) {\n        var sw = new TargetWriter();\n        TrParenExpr(e, sw, false);\n        return sw.ToString();\n      } else {\n        var v = idGenerator.FreshId(prefix);\n        DeclareLocalVar(v, null, null, e, false, wr);\n        return v;\n      }\n    }\n\n    /// <summary>\n    /// Returns whether the given expression is <em>stable</em>, that is,\n    /// whether its value is fixed over the course of the evaluation of an\n    /// expression.  Note that anything that could be altered by a function call\n    /// (say, the value of a non-constant field) is unstable.\n    /// </summary>\n    private bool IsStableExpr(Expression e) {\n      if (e is IdentifierExpr || e is ThisExpr || e is LiteralExpr) {\n        return true;\n      } else if (e is MemberSelectExpr mse) {\n        if (!IsStableExpr(mse.Obj)) {\n          return false;\n        }\n        var member = mse.Member;\n        if (member is ConstantField) {\n          return true;\n        } else if (member is SpecialField sf) {\n          switch (sf.SpecialId) {\n            case SpecialField.ID.ArrayLength:\n            case SpecialField.ID.ArrayLengthInt:\n            case SpecialField.ID.Floor:\n            case SpecialField.ID.IsLimit:\n            case SpecialField.ID.IsSucc:\n            case SpecialField.ID.Offset:\n            case SpecialField.ID.IsNat:\n            case SpecialField.ID.Keys:\n            case SpecialField.ID.Values:\n            case SpecialField.ID.Items:\n              return true;\n            default:\n              return false;\n          }\n        } else {\n          return false;\n        }\n      } else if (e is ConcreteSyntaxExpression cse) {\n        return IsStableExpr(cse.ResolvedExpression);\n      } else {\n        return false;\n      }\n    }\n\n    /// <summary>\n    /// Translate the right-hand side of an assignment.\n    /// </summary>\n    /// <param name=\"rhs\">The RHS to translate</param>\n    /// <param name=\"wr\">The writer at the position for the translated RHS</param>\n    /// <param name=\"wStmts\">A writer at an earlier position where extra statements may be written</param>\n    void TrRhs(AssignmentRhs rhs, TargetWriter wr, TargetWriter wStmts) {\n      Contract.Requires(!(rhs is HavocRhs));\n      Contract.Requires(wr != null);\n\n      var tRhs = rhs as TypeRhs;\n\n      if (tRhs == null) {\n        if (rhs is MallocRhs) {\n          var mrhs = (MallocRhs) rhs;\n          var type_name = TypeName(mrhs.AllocatedType, wr, null);\n          var malloc = String.Format(\"({0}*) calloc((size_t)1, sizeof({0}))\",type_name);\n          wr.Write(malloc);\n        } else if (rhs is CallocRhs) {\n          var crhs = (CallocRhs) rhs;\n          var cw = new TargetWriter();\n          TrParenExpr(crhs.Count, cw, false);\n          var count = cw.ToString();\n          var type_name = TypeName(crhs.AllocatedType, wr, null);\n          var calloc = String.Format(\"({0}*) calloc((size_t){1}, sizeof({0}))\",type_name,count);\n          wr.Write(calloc);\n        } else {\n          var eRhs = (ExprRhs)rhs;  // it's not HavocRhs (by the precondition) or TypeRhs (by the \"if\" test), so it's gotta be ExprRhs\n          TrExpr(eRhs.Expr, wr, false);\n        }\n\n      } else {\n        var nw = idGenerator.FreshId(\"_nw\");\n        var wRhs = DeclareLocalVar(nw, null, null, wStmts, tRhs.Type);\n        TrTypeRhs(tRhs, wRhs);\n\n        // Proceed with initialization\n        if (tRhs.InitCall != null) {\n          string q, n;\n          if (tRhs.InitCall.Method is Constructor && tRhs.InitCall.Method.IsExtern(out q, out n)) {\n            // initialization was done at the time of allocation\n          } else {\n            TrCallStmt(tRhs.InitCall, nw, wStmts);\n          }\n        } else if (tRhs.ElementInit != null) {\n          // Compute the array-initializing function once and for all (as required by the language definition)\n          string f = idGenerator.FreshId(\"_arrayinit\");\n          DeclareLocalVar(f, null, null, tRhs.ElementInit, false, wStmts, tRhs.ElementInit.Type);\n          // Build a loop nest that will call the initializer for all indices\n          var indices = Translator.Map(Enumerable.Range(0, tRhs.ArrayDimensions.Count), ii => idGenerator.FreshId(\"_arrayinit_\" + ii));\n          var w = wStmts;\n          for (var d = 0; d < tRhs.ArrayDimensions.Count; d++) {\n            string len, p0, p1;\n            GetSpecialFieldInfo(SpecialField.ID.ArrayLengthInt, tRhs.ArrayDimensions.Count == 1 ? null : (object)d, out len, out p0, out p1);\n            var bound = string.Format(\"{0}.{1}\", nw, len);\n            w = CreateForLoop(indices[d], bound, w);\n          }\n          var eltRhs = string.Format(\"{0}{2}({1})\", f, Util.Comma(indices, ArrayIndexToInt), LambdaExecute);\n          var wArray = EmitArrayUpdate(indices, eltRhs, tRhs.ElementInit.Type, w);\n          wArray.Write(nw);\n          EndStmt(w);\n        } else if (tRhs.InitDisplay != null) {\n          var ii = 0;\n          foreach (var v in tRhs.InitDisplay) {\n            var wArray = EmitArrayUpdate(new List<string> { ii.ToString() }, v, wStmts);\n            wArray.Write(nw);\n            EndStmt(wStmts);\n            ii++;\n          }\n        }\n\n        // Assign to the final LHS\n        wr.Write(nw);\n      }\n    }\n\n    // to do: Make Type an abstract property of AssignmentRhs.  Unfortunately, this would first require convincing Microsoft that it makes sense for a base class to have a property that's only settable in some subclasses.  Until then, let it be known that Java's \"properties\" (i.e. getter/setter pairs) are more powerful >:-)\n    private static Type TypeOfRhs(AssignmentRhs rhs) {\n      if (rhs is TypeRhs tRhs) {\n        return tRhs.Type;\n      } else if (rhs is ExprRhs eRhs) {\n        return eRhs.Expr.Type;\n      } else {\n        return null;\n      }\n    }\n\n    protected virtual bool ReturnStyleHelper(string returnStyleOutCollector) {\n      return false;\n    }\n\n    void TrCallStmt(CallStmt s, string receiverReplacement, TargetWriter wr) {\n      Contract.Requires(s != null);\n      Contract.Assert(s.Method != null);  // follows from the fact that stmt has been successfully resolved\n      Console.WriteLine(s.Method.Name);\n\n      if (s.Method == enclosingMethod && enclosingMethod.IsTailRecursive) {\n        // compile call as tail-recursive\n\n        // assign the actual in-parameters to temporary variables\n        var inTmps = new List<string>();\n        if (receiverReplacement != null) {\n          // TODO:  What to do here?  When does this happen, what does it mean?\n        } else if (!s.Method.IsStatic) {\n\n          string inTmp = idGenerator.FreshId(\"_in\");\n          inTmps.Add(inTmp);\n          DeclareLocalVar(inTmp, null, null, s.Receiver, false, wr);\n        }\n        for (int i = 0; i < s.Method.Ins.Count; i++) {\n          Formal p = s.Method.Ins[i];\n          if (!p.IsGhost) {\n            string inTmp = idGenerator.FreshId(\"_in\");\n            inTmps.Add(inTmp);\n            DeclareLocalVar(inTmp, null, null, s.Args[i], false, wr, p.Type);\n          }\n        }\n        // Now, assign to the formals\n        int n = 0;\n        if (!s.Method.IsStatic) {\n          wr.Write(\"_this = {0}\", inTmps[n]);\n          EndStmt(wr);\n          n++;\n        }\n        foreach (var p in s.Method.Ins) {\n          if (!p.IsGhost) {\n            wr.Write(\"{0} = {1}\", p.CompileName, inTmps[n]);\n            EndStmt(wr);\n            n++;\n          }\n        }\n        Contract.Assert(n == inTmps.Count);\n        // finally, the jump back to the head of the method\n        EmitJumpToTailCallStart(wr);\n\n      } else {\n        // compile call as a regular call\n\n        var lvalues = new List<string/*?*/>();  // contains an entry for each non-ghost formal out-parameter, but the entry is null if the actual out-parameter is ghost\n        Contract.Assert(s.Lhs.Count == s.Method.Outs.Count);\n        // Clean-up all outs\n        // TODO(xueyuan): clean-up all outs to compile, not what this is for.\n        //s.Method.Outs.Clear();\n        for (int i = 0; i < s.Method.Outs.Count; i++) {\n          Formal p = s.Method.Outs[i];\n          if (!p.IsGhost) {\n            var lhs = s.Lhs[i].Resolved;\n            if (lhs is IdentifierExpr lhsIE && lhsIE.Var.IsGhost) {\n              lvalues.Add(null);\n            } else if (lhs is MemberSelectExpr lhsMSE && lhsMSE.Member.IsGhost) {\n              lvalues.Add(null);\n            } else {\n              lvalues.Add(CreateLvalue(s.Lhs[i], wr));\n            }\n          }\n        }\n        var outTmps = new List<string>();  // contains a name for each non-ghost formal out-parameter\n        var outTypes = new List<Type>();  // contains a type for each non-ghost formal out-parameter\n        for (int i = 0; i < s.Method.Outs.Count; i++) {\n          Formal p = s.Method.Outs[i];\n          if (!p.IsGhost) {\n            string target = idGenerator.FreshId(\"_out\");\n            outTmps.Add(target);\n            Type type;\n            if (!NeedsCastFromTypeParameter) {\n              type = s.Lhs[i].Type;\n            } else {\n              //\n              // The type of the parameter will differ from the LHS type in a\n              // situation like this:\n              //\n              //   method Gimmie<R(0)>() returns (r: R) { }\n              //\n              //   var a : int := Gimmie();\n              //\n              // The method Gimme will be compiled down to Go (or JavaScript)\n              // as a function which returns any value (some details omitted):\n              //\n              //   func Gimmie(ty _dafny.Type) interface{} {\n              //     return ty.Default()\n              //   }\n              //\n              // If we naively translate, we get a type error:\n              //\n              //   var lhs int = Gimmie(_dafny.IntType) // error!\n              //\n              // Fortunately, we have the information at hand to do better.  The\n              // LHS does have the actual final type (int in this case), and the\n              // out parameter on the method tells us the compiled type\n              // returned.  Therefore what we want to do is this:\n              //\n              //   var lhs dafny.Int\n              //   var _out interface{}\n              //\n              //   _out = Gimmie(dafny.IntType)\n              //\n              //   lhs = _out.(int) // type cast\n              //\n              // All we have to do now is declare the out variable with the type\n              // from the parameter; later we'll do the type cast.\n              //\n              // None of this is necessary if the language supports parametric\n              // functions to begin with (C#) or has dynamic typing so none of\n              // this comes up (JavaScript), so we only do this if\n              // NeedsCastFromTypeParameter is on.\n              type = p.Type;\n            }\n            if (s.Method.IsExtern(out _, out _)) {\n              type = NativeForm(type);\n            }\n            outTypes.Add(type);\n            DeclareLocalVar(target, type, s.Lhs[i].tok, false, null, wr);\n          }\n        }\n        Contract.Assert(lvalues.Count == outTmps.Count);\n\n        bool customReceiver = NeedsCustomReceiver(s.Method);\n        Contract.Assert(receiverReplacement == null || !customReceiver);  // What would be done in this case? It doesn't ever happen, right?\n\n        bool returnStyleOuts = UseReturnStyleOuts(s.Method, outTmps.Count);\n        var returnStyleOutCollector = outTmps.Count > 0 && returnStyleOuts && !SupportsMultipleReturns ? idGenerator.FreshId(\"_outcollector\") : null;\n        if (returnStyleOutCollector != null) {\n          DeclareSpecificOutCollector(returnStyleOutCollector, wr, outTmps.Count, outTypes, s.Method);\n        } else if (outTmps.Count > 0 && returnStyleOuts && SupportsMultipleReturns) {\n          wr.Write(\"{0} = \", Util.Comma(outTmps));\n        }\n        if (receiverReplacement != null) {\n          wr.Write(IdProtect(receiverReplacement));\n// ******************************************************************\n// TODO: Add an overrideable function for this\n// ******************************************************************\n          wr.Write(\".{0}\", IdName(s.Method));\n        } else if (customReceiver) {\n          wr.Write(TypeName_Companion(s.Receiver.Type, wr, s.Tok, s.Method));\n// ******************************************************************\n// TODO: Add an overrideable function for this\n// ******************************************************************\n          wr.Write(\".{0}\", IdName(s.Method));\n        } else if (!s.Method.IsStatic) {\n// ******************************************************************\n// TODO: Add an overrideable function for this\n// ******************************************************************\n          TrParenExpr(s.Receiver, wr, false);\n          wr.Write(\".{0}\", IdName(s.Method));\n        } else {\n          string qual, compileName;\n          if (s.Method.IsExtern(out qual, out compileName) && qual != null) {\n// ******************************************************************\n// TODO: Add an overrideable function for the double colon used here\n// ******************************************************************\n            wr.Write(\"{0}.{1}\", qual, compileName);\n          } else\n          {\n            // Since we only have a unified namespace, we directly use the Method.Name\n            var base_name = TypeName_Companion(s.Receiver.Type, wr, s.Tok, s.Method);\n            if (base_name == \"_default\")\n            {\n              wr.Write(s.Method.Name);\n            } else\n            {\n              wr.Write(\"{0}.{1}\",base_name,s.Method.Name);\n            }\n          }\n        }\n        List<Type> typeArgs;\n        var typeSubst = s.MethodSelect.TypeArgumentSubstitutions();\n        typeArgs = s.Method.TypeArgs.ConvertAll(ta => typeSubst[ta]);\n        EmitActualTypeArgs(typeArgs, s.Tok, wr);\n        wr.Write(\"(\");\n        var nRTDs = EmitRuntimeTypeDescriptorsActuals(typeArgs, s.Method.TypeArgs, s.Tok, ReturnStyleHelper(returnStyleOutCollector), wr);\n        string sep = nRTDs == 0 ? \"\" : \", \";\n        if (customReceiver) {\n          TrExpr(s.Receiver, wr, false);\n          sep = \", \";\n        }\n        for (int i = 0; i < s.Method.Ins.Count; i++) {\n          Formal p = s.Method.Ins[i];\n          if (!p.IsGhost) {\n            wr.Write(sep);\n            // Order of coercions is important here: EmitCoercionToNativeForm may coerce into a type we're unaware of, so it *has* to be second\n            var w = EmitCoercionIfNecessary(s.Args[i].Type, s.Method.Ins[i].Type, s.Tok, wr);\n            if (s.Method.IsExtern(out _, out _)) {\n              w = EmitCoercionToNativeForm(s.Method.Ins[i].Type, s.Tok, w);\n            }\n            TrExpr(s.Args[i], w, false);\n            sep = \", \";\n          }\n        }\n\n        if (returnStyleOutCollector == null && !SupportsMultipleReturns) {\n          foreach (var outTmp in outTmps) {\n            wr.Write(sep);\n            EmitActualOutArg(outTmp, wr);\n            sep = \", \";\n          }\n        }\n        wr.Write(')');\n        EndStmt(wr);\n        if (returnStyleOutCollector != null) {\n          EmitCastOutParameterSplits(returnStyleOutCollector, outTmps, wr, outTypes, s.Tok);\n        }\n\n        // assign to the actual LHSs\n        for (int j = 0, l = 0; j < s.Method.Outs.Count; j++) {\n          var p = s.Method.Outs[j];\n          if (!p.IsGhost) {\n            var lvalue = lvalues[l];\n            if (lvalue != null) {\n              // The type information here takes care both of implicit upcasts and\n              // implicit downcasts from type parameters (see above).\n              TargetWriter wLhs, wRhs;\n              EmitAssignment(out wLhs, s.Lhs[j].Type, out wRhs, p.Type, wr);\n              wLhs.Write(lvalue);\n              if (s.Method.IsExtern(out _, out _)) {\n                wRhs = EmitCoercionFromNativeForm(p.Type, s.Tok, wRhs);\n              }\n              wRhs.Write(outTmps[l]);\n              // Coercion from the out type to the LHS type is the responsibility\n              // of the EmitAssignment above\n            }\n            l++;\n          }\n        }\n      }\n    }\n\n    /// <summary>\n    /// Before calling TrAssignmentRhs(rhs), the caller must have spilled the let variables declared in \"tp\".\n    /// </summary>\n    void TrTypeRhs(TypeRhs tp, TargetWriter wr) {\n      Contract.Requires(tp != null);\n      Contract.Requires(wr != null);\n\n      if (tp.ArrayDimensions == null) {\n        var initCall = tp.InitCall != null && tp.InitCall.Method is Constructor ? tp.InitCall : null;\n        EmitNew(tp.EType, tp.Tok, initCall, wr);\n      } else if (tp.ElementInit != null || tp.InitDisplay != null) {\n        EmitNewArray(tp.EType, tp.Tok, tp.ArrayDimensions, false, wr);\n      } else {\n        // If an initializer is not known, the only way the verifier would have allowed this allocation\n        // is if the requested size is 0.\n        EmitNewArray(tp.EType, tp.Tok, tp.ArrayDimensions, InitializerIsKnown(tp.EType), wr);\n      }\n    }\n\n    protected void TrStmtList(List<Statement> stmts, TargetWriter writer){\n      Contract.Requires(cce.NonNullElements(stmts));\n      Contract.Requires(writer != null);\n      foreach (Statement ss in stmts) {\n        // label:        // if any\n        //   <prelude>   // filled via copyInstrWriters -- copies out-parameters used in letexpr to local variables\n        //   ss          // translation of ss has side effect of filling the top copyInstrWriters\n        var w = writer;\n        if (ss.Labels != null) {\n          w = CreateLabeledCode(ss.Labels.Data.AssignUniqueId(idGenerator), w);\n        }\n        var prelude = w.ForkSection();\n        copyInstrWriters.Push(prelude);\n        TrStmt(ss, w);\n        copyInstrWriters.Pop();\n      }\n    }\n\n    void TrLocalVar(IVariable v, bool alwaysInitialize, TargetWriter wr) {\n      Contract.Requires(v != null);\n      if (v.IsGhost) {\n        // only emit non-ghosts (we get here only for local variables introduced implicitly by call statements)\n        return;\n      }\n      DeclareLocalVar(IdName(v), v.Type, v.Tok, false, alwaysInitialize ? DefaultValue(v.Type, wr, v.Tok) : null, wr);\n    }\n\n    TargetWriter MatchCasePrelude(string source, UserDefinedType sourceType, DatatypeCtor ctor, List<BoundVar> arguments, int caseIndex, int caseCount, TargetWriter wr) {\n      Contract.Requires(source != null);\n      Contract.Requires(sourceType != null);\n      Contract.Requires(ctor != null);\n      Contract.Requires(cce.NonNullElements(arguments));\n      Contract.Requires(0 <= caseIndex && caseIndex < caseCount);\n      // if (source.is_Ctor0) {\n      //   FormalType f0 = ((Dt_Ctor0)source._D).a0;\n      //   ...\n      var lastCase = caseIndex == caseCount - 1;\n      TargetWriter w;\n      if (lastCase) {\n        // Need to avoid if (true) because some languages (Go, someday Java)\n        // pretend that an if (true) isn't a certainty, leading to a complaint\n        // about a missing return statement\n        w = wr.NewBlock(\"\", null, BlockTargetWriter.BraceStyle.Nothing);\n      } else {\n        TargetWriter guardWriter;\n        w = EmitIf(out guardWriter, !lastCase, wr);\n        EmitConstructorCheck(source, ctor, guardWriter);\n      }\n\n      int k = 0;  // number of processed non-ghost arguments\n      for (int m = 0; m < ctor.Formals.Count; m++) {\n        Formal arg = ctor.Formals[m];\n        if (!arg.IsGhost) {\n          BoundVar bv = arguments[m];\n          // FormalType f0 = ((Dt_Ctor0)source._D).a0;\n          var sw = DeclareLocalVar(IdName(bv), bv.Type, bv.Tok, w);\n          EmitDestructor(source, arg, k, ctor, sourceType.TypeArgs, bv.Type, sw);\n          k++;\n        }\n      }\n      return w;\n    }\n\n    // ----- Expression ---------------------------------------------------------------------------\n\n    /// <summary>\n    /// Before calling TrParenExpr(expr), the caller must have spilled the let variables declared in \"expr\".\n    /// </summary>\n    protected void TrParenExpr(string prefix, Expression expr, TargetWriter wr, bool inLetExprBody) {\n      Contract.Requires(prefix != null);\n      Contract.Requires(expr != null);\n      Contract.Requires(wr != null);\n      wr.Write(prefix);\n      TrParenExpr(expr, wr, inLetExprBody);\n    }\n\n    /// <summary>\n    /// Before calling TrParenExpr(expr), the caller must have spilled the let variables declared in \"expr\".\n    /// </summary>\n    protected void TrParenExpr(Expression expr, TargetWriter wr, bool inLetExprBody) {\n      Contract.Requires(expr != null);\n      Contract.Requires(wr != null);\n      wr.Write(\"(\");\n      TrExpr(expr, wr, inLetExprBody);\n      wr.Write(\")\");\n    }\n\n    protected virtual void TrBvExpr(Expression expr, TargetWriter wr, bool inLetExprBody){\n      Contract.Requires(expr != null);\n      Contract.Requires(wr != null);\n      TrParenExpr(expr, wr, inLetExprBody);\n    }\n\n    /// <summary>\n    /// Before calling TrExprList(exprs), the caller must have spilled the let variables declared in expressions in \"exprs\".\n    /// </summary>\n    protected void TrExprList(List<Expression> exprs, TargetWriter wr, bool inLetExprBody, Type/*?*/ type = null) {\n      Contract.Requires(cce.NonNullElements(exprs));\n      wr.Write(\"(\");\n      string sep = \"\";\n      foreach (Expression e in exprs) {\n        wr.Write(sep);\n        TargetWriter w;\n        if (type != null) {\n          w = wr.Fork();\n          w = EmitCoercionIfNecessary(e.Type, type, e.tok, w);\n        } else {\n          w = wr;\n        }\n        TrExpr(e, w, inLetExprBody);\n        sep = \", \";\n      }\n      wr.Write(\")\");\n    }\n\n    protected virtual void WriteCast(string s, TargetWriter wr) { }\n\n    /// <summary>\n    /// Before calling TrExpr(expr), the caller must have spilled the let variables declared in \"expr\".\n    /// </summary>\n    protected void TrExpr(Expression expr, TargetWriter wr, bool inLetExprBody) {\n      Contract.Requires(expr != null);\n      Contract.Requires(wr != null);\n\n      if (expr is LiteralExpr) {\n        LiteralExpr e = (LiteralExpr)expr;\n        EmitLiteralExpr(wr, e);\n\n      } else if (expr is ThisExpr) {\n        EmitThis(wr);\n\n      } else if (expr is IdentifierExpr) {\n        var e = (IdentifierExpr)expr;\n        if (e.Var is Formal && inLetExprBody && !((Formal)e.Var).InParam) {\n          // out param in letExpr body, need to copy it to a temp since\n          // letExpr body is translated to an anonymous function that doesn't\n          // allow out parameters\n          var name = string.Format(\"_pat_let_tv{0}\", GetUniqueAstNumber(e));\n          wr.Write(name);\n          DeclareLocalVar(name, null, null, false, IdName(e.Var), copyInstrWriters.Peek(), e.Type);\n        } else {\n          wr.Write(IdName(e.Var));\n        }\n      } else if (expr is SetDisplayExpr) {\n        var e = (SetDisplayExpr)expr;\n        EmitCollectionDisplay(e.Type.AsSetType, e.tok, e.Elements, inLetExprBody, wr);\n\n      } else if (expr is MultiSetDisplayExpr) {\n        var e = (MultiSetDisplayExpr)expr;\n        EmitCollectionDisplay(e.Type.AsMultiSetType, e.tok, e.Elements, inLetExprBody, wr);\n\n      } else if (expr is SeqDisplayExpr) {\n        var e = (SeqDisplayExpr)expr;\n        EmitCollectionDisplay(e.Type.AsSeqType, e.tok, e.Elements, inLetExprBody, wr);\n\n      } else if (expr is MapDisplayExpr) {\n        var e = (MapDisplayExpr)expr;\n        EmitMapDisplay(e.Type.AsMapType, e.tok, e.Elements, inLetExprBody, wr);\n\n      } else if (expr is MemberSelectExpr) {\n        MemberSelectExpr e = (MemberSelectExpr)expr;\n        var MemberSelectObjIsTrait = e.Obj.Type.IsTraitType;\n        SpecialField sf = e.Member as SpecialField;\n        if (sf != null) {\n          string compiledName, preStr, postStr;\n          GetSpecialFieldInfo(sf.SpecialId, sf.IdParam, out compiledName, out preStr, out postStr);\n          wr.Write(preStr);\n          var w = EmitMemberSelect(sf, false, expr.Type, wr, MemberSelectObjIsTrait);\n          if (NeedsCustomReceiver(e.Member)) {\n            w.Write(TypeName_Companion(e.Obj.Type, wr, e.tok, sf));\n            TrParenExpr(e.Obj, wr, inLetExprBody);\n          } else if (sf.IsStatic) {\n            w.Write(TypeName_Companion(e.Obj.Type, wr, e.tok, sf));\n          } else {\n            TrParenExpr(e.Obj, w, inLetExprBody);\n          }\n          wr.Write(postStr);\n        } else\n        {\n          var ow = new TargetWriter();\n          TrParenExpr(e.Obj, ow, inLetExprBody);\n          var obj = ow.ToString();\n\n          if (obj ==  \"(_default)\")\n            wr.Write(e.MemberName);\n          else\n          {\n            var w = EmitMemberSelect(e.Member, false, expr.Type, wr, MemberSelectObjIsTrait);\n            w.Write(obj);\n          }\n        }\n\n      } else if (expr is SeqSelectExpr) {\n        SeqSelectExpr e = (SeqSelectExpr)expr;\n        Contract.Assert(e.Seq.Type != null);\n        if (e.Seq.Type.IsArrayType) {\n          if (e.SelectOne) {\n            Contract.Assert(e.E0 != null && e.E1 == null);\n            var w = EmitArraySelect(new List<Expression>() { e.E0 }, e.Type, inLetExprBody, wr);\n            TrParenExpr(e.Seq, w, inLetExprBody);\n          } else {\n            EmitSeqSelectRange(e.Seq, e.E0, e.E1, true, inLetExprBody, wr);\n          }\n        } else if (e.SelectOne) {\n          Contract.Assert(e.E0 != null && e.E1 == null);\n          EmitIndexCollectionSelect(e.Seq, e.E0, inLetExprBody, wr);\n        } else {\n          EmitSeqSelectRange(e.Seq, e.E0, e.E1, false, inLetExprBody, wr);\n        }\n      } else if (expr is SeqConstructionExpr) {\n        var e = (SeqConstructionExpr)expr;\n        EmitSeqConstructionExpr(e, inLetExprBody, wr);\n      } else if (expr is MultiSetFormingExpr) {\n        var e = (MultiSetFormingExpr)expr;\n        EmitMultiSetFormingExpr(e, inLetExprBody, wr);\n      } else if (expr is MultiSelectExpr) {\n        MultiSelectExpr e = (MultiSelectExpr)expr;\n        WriteCast(TypeName(e.Type.NormalizeExpand(), wr, e.tok), wr);\n        var w = EmitArraySelect(e.Indices, e.Type, inLetExprBody, wr);\n        TrParenExpr(e.Array, w, inLetExprBody);\n\n      } else if (expr is SeqUpdateExpr) {\n        SeqUpdateExpr e = (SeqUpdateExpr)expr;\n        if (e.ResolvedUpdateExpr != null) {\n          TrExpr(e.ResolvedUpdateExpr, wr, inLetExprBody);\n        } else {\n          EmitIndexCollectionUpdate(e.Seq, e.Index, e.Value, inLetExprBody, wr);\n        }\n\n      } else if (expr is FunctionCallExpr) {\n        FunctionCallExpr e = (FunctionCallExpr)expr;\n        if (e.Function is SpecialFunction) {\n          CompileSpecialFunctionCallExpr(e, wr, inLetExprBody, TrExpr);\n        } else {\n          CompileFunctionCallExpr(e, wr, inLetExprBody, TrExpr);\n        }\n\n      } else if (expr is ApplyExpr) {\n        var e = expr as ApplyExpr;\n        EmitApplyExpr(e.Function.Type, e.tok, e.Function, e.Args, inLetExprBody, wr);\n\n      } else if (expr is DatatypeValue) {\n        var dtv = (DatatypeValue)expr;\n        Contract.Assert(dtv.Ctor != null);  // since dtv has been successfully resolved\n\n        var wrArgumentList = new TargetWriter();\n        string sep = \"\";\n        for (int i = 0; i < dtv.Arguments.Count; i++) {\n          var formal = dtv.Ctor.Formals[i];\n          if (!formal.IsGhost) {\n            wrArgumentList.Write(sep);\n            var w = EmitCoercionIfNecessary(from:dtv.Arguments[i].Type, to:dtv.Ctor.Formals[i].Type, tok:dtv.tok, wr:wrArgumentList);\n            TrExpr(dtv.Arguments[i], w, inLetExprBody);\n            sep = \", \";\n          }\n        }\n        EmitDatatypeValue(dtv, wrArgumentList.ToString(), wr);\n\n      } else if (expr is OldExpr) {\n        Contract.Assert(false); throw new cce.UnreachableException();  // 'old' is always a ghost\n\n      } else if (expr is UnaryOpExpr) {\n        var e = (UnaryOpExpr)expr;\n        switch (e.Op) {\n          case UnaryOpExpr.Opcode.Not:\n            if (e.Type.IsBitVectorType) {\n              var bvType = e.Type.AsBitVectorType;\n              var wrTruncOperand = EmitBitvectorTruncation(bvType, false, wr);\n              EmitUnaryExpr(ResolvedUnaryOp.BitwiseNot, e.E, inLetExprBody, wrTruncOperand);\n            } else {\n              EmitUnaryExpr(ResolvedUnaryOp.BoolNot, e.E, inLetExprBody, wr);\n            }\n            break;\n          case UnaryOpExpr.Opcode.Cardinality:\n            EmitUnaryExpr(ResolvedUnaryOp.Cardinality, e.E, inLetExprBody, wr);\n            break;\n          case UnaryOpExpr.Opcode.Dereference:\n            EmitUnaryExpr(ResolvedUnaryOp.Dereference, e.E, inLetExprBody, wr);\n            break;\n          case UnaryOpExpr.Opcode.AddressOf:\n            EmitUnaryExpr(ResolvedUnaryOp.AddressOf, e.E, inLetExprBody, wr);\n            break;\n          default:\n            Contract.Assert(false); throw new cce.UnreachableException();  // unexpected unary expression\n        }\n\n      } else if (expr is ConversionExpr) {\n        var e = (ConversionExpr)expr;\n        EmitConversionExpr(e, inLetExprBody, wr);\n\n      } else if (expr is BinaryExpr) {\n        var e = (BinaryExpr)expr;\n        string opString, preOpString, postOpString, callString, staticCallString;\n        bool reverseArguments, truncateResult, convertE1_to_int;\n        CompileBinOp(e.ResolvedOp, e.E0, e.E1, e.tok, expr.Type,\n          out opString,\n          out preOpString,\n          out postOpString,\n          out callString,\n          out staticCallString,\n          out reverseArguments,\n          out truncateResult,\n          out convertE1_to_int,\n          wr);\n\n        if (truncateResult && e.Type.IsBitVectorType) {\n          wr = EmitBitvectorTruncation(e.Type.AsBitVectorType, true, wr);\n        }\n        var e0 = reverseArguments ? e.E1 : e.E0;\n        var e1 = reverseArguments ? e.E0 : e.E1;\n        if (opString != null) {\n          var nativeType = AsNativeType(e.Type);\n          string nativeName = null, literalSuffix = null;\n          bool needsCast = false;\n          if (nativeType != null) {\n            GetNativeInfo(nativeType.Sel, out nativeName, out literalSuffix, out needsCast);\n          }\n          if (needsCast) {\n            wr.Write(\"(\" + nativeName + \")(\");\n          }\n          wr.Write(preOpString);\n          TrParenExpr(e0, wr, inLetExprBody);\n          wr.Write(\" {0} \", opString);\n          if (convertE1_to_int) {\n            EmitExprAsInt(e1, inLetExprBody, wr);\n          } else {\n            TrParenExpr(e1, wr, inLetExprBody);\n          }\n          if (needsCast) {\n            wr.Write(\")\");\n          }\n          wr.Write(postOpString);\n        } else if (callString != null) {\n          wr.Write(preOpString);\n          TrBvExpr(e0, wr, inLetExprBody);\n          wr.Write(\".{0}(\", callString);\n          if (convertE1_to_int) {\n            EmitExprAsInt(e1, inLetExprBody, wr);\n          } else {\n            TrBvExpr(e1, wr, inLetExprBody);\n          }\n          wr.Write(\")\");\n          wr.Write(postOpString);\n        } else if (staticCallString != null) {\n          wr.Write(preOpString);\n          wr.Write(\"{0}(\", staticCallString);\n          TrExpr(e0, wr, inLetExprBody);\n          wr.Write(\", \");\n          TrExpr(e1, wr, inLetExprBody);\n          wr.Write(\")\");\n          wr.Write(postOpString);\n        }\n\n      } else if (expr is TernaryExpr) {\n        Contract.Assume(false);  // currently, none of the ternary expressions is compilable\n\n      } else if (expr is LetExpr) {\n        var e = (LetExpr)expr;\n        if (e.Exact) {\n          // The Dafny \"let\" expression\n          //    var Pattern(x,y) := G; E\n          // is translated into C# as:\n          //    LamLet(G, tmp =>\n          //      LamLet(dtorX(tmp), x =>\n          //      LamLet(dtorY(tmp), y => E)))\n          Contract.Assert(e.LHSs.Count == e.RHSs.Count);  // checked by resolution\n          var w = wr;\n          for (int i = 0; i < e.LHSs.Count; i++) {\n            var lhs = e.LHSs[i];\n            if (Contract.Exists(lhs.Vars, bv => !bv.IsGhost)) {\n              var rhsName = string.Format(\"_pat_let{0}_{1}\", GetUniqueAstNumber(e), i);\n              w = CreateIIFE_ExprBody(e.RHSs[i], inLetExprBody, e.RHSs[i].Type, e.RHSs[i].tok, e.Body.Type, e.Body.tok, rhsName, w);\n              w = TrCasePattern(lhs, rhsName, e.Body.Type, w);\n            }\n          }\n          TrExpr(e.Body, w, true);\n        } else if (e.BoundVars.All(bv => bv.IsGhost)) {\n          // The Dafny \"let\" expression\n          //    ghost var x,y :| Constraint; E\n          // is compiled just like E is, because the resolver has already checked that x,y (or other ghost variables, for that matter) don't\n          // occur in E (moreover, the verifier has checked that values for x,y satisfying Constraint exist).\n          TrExpr(e.Body, wr, inLetExprBody);\n        } else {\n          // The Dafny \"let\" expression\n          //    var x,y :| Constraint; E\n          // is translated into C# as:\n          //    LamLet(0, dummy => {  // the only purpose of this construction here is to allow us to add some code inside an expression in C#\n          //        var x,y;\n          //        // Embark on computation that fills in x,y according to Constraint; the computation stops when the first\n          //        // such value is found, but since the verifier checks that x,y follows uniquely from Constraint, this is\n          //        // not a source of nondeterminancy.\n          //        return E;\n          //      })\n          Contract.Assert(e.RHSs.Count == 1);  // checked by resolution\n          var missingBounds = ComprehensionExpr.BoolBoundedPool.MissingBounds(e.BoundVars.ToList<BoundVar>(), e.Constraint_Bounds, ComprehensionExpr.BoundedPool.PoolVirtues.Enumerable);\n          if (missingBounds.Count != 0) {\n            foreach (var bv in missingBounds) {\n              Error(e.tok, \"this let-such-that expression is too advanced for the current compiler; Dafny's heuristics cannot find any bound for variable '{0}'\", wr, bv.Name);\n            }\n          } else {\n            var w = CreateIIFE1(0, e.Body.Type, e.Body.tok, \"_let_dummy_\" + GetUniqueAstNumber(e), wr);\n            foreach (var bv in e.BoundVars) {\n              DeclareLocalVar(IdName(bv), bv.Type, bv.tok, false, DefaultValue(bv.Type, wr, bv.tok), w);\n            }\n            TrAssignSuchThat(new List<IVariable>(e.BoundVars).ConvertAll(bv => (IVariable)bv), e.RHSs[0], e.Constraint_Bounds, e.tok.line, w, inLetExprBody);\n            EmitReturnExpr(e.Body, true, w);\n          }\n        }\n\n      } else if (expr is MatchExpr) {\n        var e = (MatchExpr)expr;\n        // ((System.Func<SourceType, TargetType>)((SourceType _source) => {\n        //   if (source.is_Ctor0) {\n        //     FormalType f0 = ((Dt_Ctor0)source._D).a0;\n        //     ...\n        //     return Body0;\n        //   } else if (...) {\n        //     ...\n        //   } else if (true) {\n        //     ...\n        //   }\n        // }))(src)\n\n        string source = idGenerator.FreshId(\"_source\");\n        var w = CreateLambda(new List<Type>() { e.Source.Type }, e.tok, new List<string>() { source }, e.Type, wr);\n\n        if (e.Cases.Count == 0) {\n          // the verifier would have proved we never get here; still, we need some code that will compile\n          EmitAbsurd(null, w);\n        } else {\n          int i = 0;\n          var sourceType = (UserDefinedType)e.Source.Type.NormalizeExpand();\n          foreach (MatchCaseExpr mc in e.Cases) {\n            var wCase = MatchCasePrelude(source, sourceType, mc.Ctor, mc.Arguments, i, e.Cases.Count, w);\n            EmitReturnExpr(mc.Body, inLetExprBody, wCase);\n            i++;\n          }\n        }\n        // We end with applying the source expression to the delegate we just built\n        wr.Write(LambdaExecute);\n        TrParenExpr(e.Source, wr, inLetExprBody);\n\n      } else if (expr is QuantifierExpr) {\n        var e = (QuantifierExpr)expr;\n\n        // Compilation does not check whether a quantifier was split.\n\n        Contract.Assert(e.Bounds != null);  // for non-ghost quantifiers, the resolver would have insisted on finding bounds\n        var n = e.BoundVars.Count;\n        Contract.Assert(e.Bounds.Count == n);\n        var wBody = wr;\n        for (int i = 0; i < n; i++) {\n          var bound = e.Bounds[i];\n          var bv = e.BoundVars[i];\n          // emit:  Dafny.Helpers.Quantifier(rangeOfValues, isForall, bv => body)\n          wBody.Write(\"{0}(\", GetQuantifierName(TypeName(bv.Type, wBody, bv.tok)));\n          CompileCollection(bound, bv, inLetExprBody, false, wBody, e.Bounds, e.BoundVars, i);\n          wBody.Write(\", {0}, \", expr is ForallExpr ? \"true\" : \"false\");\n          var native = AsNativeType(e.BoundVars[i].Type);\n          TargetWriter newWBody = CreateLambda(new List<Type>{ bv.Type }, e.tok, new List<string>{ IdName(bv) }, Type.Bool, wBody, untyped: true);\n          newWBody = EmitReturnExpr(newWBody);\n          wBody.Write(')');\n          wBody = newWBody;\n        }\n        TrExpr(e.LogicalBody(true), wBody, true);\n\n      } else if (expr is SetComprehension) {\n        var e = (SetComprehension)expr;\n        // For \"set i,j,k,l | R(i,j,k,l) :: Term(i,j,k,l)\" where the term has type \"G\", emit something like:\n        // ((System.Func<Set<G>>)(() => {\n        //   var _coll = new List<G>();\n        //   foreach (var tmp_l in sq.Elements) { L l = (L)tmp_l;\n        //     foreach (var tmp_k in st.Elements) { K k = (K)tmp_k;\n        //       for (BigInteger j = Lo; j < Hi; j++) {\n        //         for (bool i in Helper.AllBooleans) {\n        //           if (R(i,j,k,l)) {\n        //             _coll.Add(Term(i,j,k,l));\n        //           }\n        //         }\n        //       }\n        //     }\n        //   }\n        //   return Dafny.Set<G>.FromCollection(_coll);\n        // }))()\n        Contract.Assert(e.Bounds != null);  // the resolver would have insisted on finding bounds\n        var typeName = TypeName(e.Type.AsSetType.Arg, wr, e.tok);\n        var collection_name = idGenerator.FreshId(\"_coll\");\n        var bwr = CreateIIFE0(e.Type.AsSetType, e.tok, wr);\n        wr = bwr;\n        EmitSetComprehension(wr, expr, collection_name);\n        var n = e.BoundVars.Count;\n        Contract.Assert(e.Bounds.Count == n);\n        for (int i = 0; i < n; i++) {\n          var bound = e.Bounds[i];\n          var bv = e.BoundVars[i];\n          TargetWriter collectionWriter;\n          var tmpVar = idGenerator.FreshId(\"_compr_\");\n          wr = CreateForeachLoop(tmpVar, bv.Type, out collectionWriter, wr, IdName(bv), bv.Type, bv.tok);\n          CompileCollection(bound, bv, inLetExprBody, true, collectionWriter);\n        }\n        TargetWriter guardWriter;\n        var thn = EmitIf(out guardWriter, false, wr);\n        TrExpr(e.Range, guardWriter, inLetExprBody);\n        EmitCollectionBuilder_Add(e.Type.AsSetType, collection_name, e.Term, inLetExprBody, thn);\n        var s = GetCollectionBuilder_Build(e.Type.AsSetType, e.tok, collection_name, wr);\n        EmitReturnExpr(s, bwr);\n\n      } else if (expr is MapComprehension) {\n        var e = (MapComprehension)expr;\n        // For \"map i | R(i) :: Term(i)\" where the term has type \"V\" and i has type \"U\", emit something like:\n        // ((System.Func<Map<U, V>>)(() => {\n        //   var _coll = new List<Pair<U,V>>();\n        //   foreach (L l in sq.Elements) {\n        //     foreach (K k in st.Elements) {\n        //       for (BigInteger j = Lo; j < Hi; j++) {\n        //         for (bool i in Helper.AllBooleans) {\n        //           if (R(i,j,k,l)) {\n        //             _coll.Add(new Pair(i, Term(i));\n        //           }\n        //         }\n        //       }\n        //     }\n        //   }\n        //   return Dafny.Map<U, V>.FromCollection(_coll);\n        // }))()\n        Contract.Assert(e.Bounds != null);  // the resolver would have insisted on finding bounds\n        var domtypeName = TypeName(e.Type.AsMapType.Domain, wr, e.tok);\n        var rantypeName = TypeName(e.Type.AsMapType.Range, wr, e.tok);\n        var collection_name = idGenerator.FreshId(\"_coll\");\n        wr = CreateIIFE0(e.Type.AsMapType, e.tok, wr);\n        using (var wrVarInit = DeclareLocalVar(collection_name, null, null, wr, e.Type.AsMapType)){\n          EmitCollectionBuilder_New(e.Type.AsMapType, e.tok, wrVarInit);\n        }\n        var n = e.BoundVars.Count;\n        Contract.Assert(e.Bounds.Count == n && n == 1);\n        var bound = e.Bounds[0];\n        var bv = e.BoundVars[0];\n        Contract.Assume(e.BoundVars.Count == 1);  // TODO: implement the case where e.BoundVars.Count > 1\n        TargetWriter collectionWriter;\n        var w = CreateForeachLoop(IdName(bv), bv.Type, out collectionWriter, wr);\n        CompileCollection(bound, bv, inLetExprBody, true, collectionWriter);\n        TargetWriter guardWriter;\n        var thn = EmitIf(out guardWriter, false, w);\n        TrExpr(e.Range, guardWriter, inLetExprBody);\n        var termLeftWriter = EmitMapBuilder_Add(e.Type.AsMapType, e.tok, collection_name, e.Term, inLetExprBody, thn);\n        if (e.TermLeft == null) {\n          termLeftWriter.Write(IdName(bv));\n        } else {\n          TrExpr(e.TermLeft, termLeftWriter, inLetExprBody);\n        }\n\n        var s = GetCollectionBuilder_Build(e.Type.AsMapType, e.tok, collection_name, wr);\n        EmitReturnExpr(s, wr);\n\n      } else if (expr is LambdaExpr) {\n        LambdaExpr e = (LambdaExpr)expr;\n\n        List<BoundVar> bvars;\n        List<Expression> fexprs;\n        Translator.Substituter su;\n        CreateFreeVarSubstitution(expr, out bvars, out fexprs, out su);\n\n        var typeArgs = TypeName_UDT(ArrowType.Arrow_FullCompileName, Util.Snoc(bvars.ConvertAll(bv => bv.Type), expr.Type), wr, Bpl.Token.NoToken);\n        var boundVars = Util.Comma(bvars, IdName);\n        wr = EmitBetaRedex(bvars.ConvertAll(IdName), fexprs, typeArgs, bvars.ConvertAll(bv => bv.Type), expr.Type, expr.tok, inLetExprBody, wr);\n        wr = CreateLambda(e.BoundVars.ConvertAll(bv => bv.Type), Bpl.Token.NoToken, e.BoundVars.ConvertAll(IdName), e.Body.Type, wr);\n        wr = EmitReturnExpr(wr);\n        TrExpr(su.Substitute(e.Body), wr, inLetExprBody);\n\n      } else if (expr is StmtExpr) {\n        var e = (StmtExpr)expr;\n        TrExpr(e.E, wr, inLetExprBody);\n\n      } else if (expr is ITEExpr) {\n        var e = (ITEExpr)expr;\n        EmitITE(e.Test, e.Thn, e.Els, inLetExprBody, wr);\n\n      } else if (expr is ConcreteSyntaxExpression) {\n        var e = (ConcreteSyntaxExpression)expr;\n        TrExpr(e.ResolvedExpression, wr, inLetExprBody);\n\n      } else if (expr is NamedExpr) {\n        TrExpr(((NamedExpr)expr).Body, wr, inLetExprBody);\n      } else {\n        Contract.Assert(false); throw new cce.UnreachableException();  // unexpected expression\n      }\n    }\n\n    void CreateFreeVarSubstitution(Expression expr, out List<BoundVar> bvars, out List<Expression> fexprs, out Translator.Substituter su) {\n      Contract.Requires(expr != null);\n\n      var fvs = Translator.ComputeFreeVariables(expr);\n      var sm = new Dictionary<IVariable, Expression>();\n\n      bvars = new List<BoundVar>();\n      fexprs = new List<Expression>();\n      foreach (var fv in fvs) {\n        fexprs.Add(new IdentifierExpr(fv.Tok, fv.Name) {\n          Var = fv, // resolved here!\n          Type = fv.Type\n        });\n        var bv = new BoundVar(fv.Tok, fv.Name, fv.Type);\n        bvars.Add(bv);\n        sm[fv] = new IdentifierExpr(bv.Tok, bv.Name) {\n          Var = bv, // resolved here!\n          Type = bv.Type\n        };\n      }\n\n      su = new Translator.Substituter(null, sm, new Dictionary<TypeParameter, Type>());\n    }\n\n    protected virtual void EmitSetComprehension(TargetWriter wr, Expression expr, String collection_name){\n      var e = (SetComprehension) expr;\n        using (var wrVarInit = DeclareLocalVar(collection_name, null, null, wr)){\n          EmitCollectionBuilder_New(e.Type.AsSetType, e.tok, wrVarInit);\n        }\n    }\n\n    protected bool IsHandleComparison(Bpl.IToken tok, Expression e0, Expression e1, TextWriter errorWr) {\n      Contract.Requires(tok != null);\n      Contract.Requires(e0 != null);\n      Contract.Requires(e1 != null);\n      TopLevelDecl cl;\n      var isHandle0 = true;\n      cl = (e0.Type.NormalizeExpand() as UserDefinedType)?.ResolvedClass;\n      if (cl == null || !Attributes.ContainsBool(cl.Attributes, \"handle\", ref isHandle0)) {\n        isHandle0 = false;\n      }\n      var isHandle1 = true;\n      cl = (e1.Type.NormalizeExpand() as UserDefinedType)?.ResolvedClass;\n      if (cl == null || !Attributes.ContainsBool(cl.Attributes, \"handle\", ref isHandle1)) {\n        isHandle1 = false;\n      }\n      if (isHandle0 && isHandle1) {\n        return true;\n      } else if (isHandle0 || isHandle1) {\n        Error(tok, \"Comparison of a handle can only be with another handle\", errorWr);\n      }\n      return false;\n    }\n\n    protected void TrStringLiteral(StringLiteralExpr str, TextWriter wr) {\n      Contract.Requires(str != null);\n      Contract.Requires(wr != null);\n      EmitStringLiteral((string)str.Value, str.IsVerbatim, wr);\n    }\n\n    /// <summary>\n    /// Try to evaluate \"expr\" into one BigInteger.  On success, return it; otherwise, return \"null\".\n    /// </summary>\n    /// <param name=\"expr\"></param>\n    /// <returns></returns>\n    public static Nullable<BigInteger> PartiallyEvaluate(Expression expr) {\n      Contract.Requires(expr != null);\n      expr = expr.Resolved;\n      if (expr is LiteralExpr) {\n        var e = (LiteralExpr)expr;\n        if (e.Value is BigInteger) {\n          return (BigInteger)e.Value;\n        }\n      } else if (expr is BinaryExpr) {\n        var e = (BinaryExpr)expr;\n        switch (e.ResolvedOp) {\n          case BinaryExpr.ResolvedOpcode.Add:\n          case BinaryExpr.ResolvedOpcode.Sub:\n          case BinaryExpr.ResolvedOpcode.Mul:\n            // possibly the most important case is Sub, since that's how NegationExpression's end up\n            var arg0 = PartiallyEvaluate(e.E0);\n            var arg1 = arg0 == null ? null : PartiallyEvaluate(e.E1);\n            if (arg1 != null) {\n              switch (e.ResolvedOp) {\n                case BinaryExpr.ResolvedOpcode.Add:\n                  return arg0 + arg1;\n                case BinaryExpr.ResolvedOpcode.Sub:\n                  return arg0 - arg1;\n                case BinaryExpr.ResolvedOpcode.Mul:\n                  return arg0 * arg1;\n                default:\n                  Contract.Assert(false);\n                  break;  // please compiler\n              }\n            }\n            break;\n          default:\n            break;\n        }\n      }\n      return null;\n    }\n\n    TargetWriter TrCasePattern(CasePattern<BoundVar> pat, string rhsString, Type bodyType, TargetWriter wr) {\n      Contract.Requires(pat != null);\n      Contract.Requires(rhsString != null);\n      Contract.Requires(bodyType != null);\n      Contract.Requires(wr != null);\n\n      if (pat.Var != null) {\n        var bv = pat.Var;\n        if (!bv.IsGhost) {\n          wr = CreateIIFE_ExprBody(rhsString, bv.Type, bv.tok, bodyType, pat.tok, IdProtect(bv.CompileName), wr);\n        }\n      } else if (pat.Arguments != null) {\n        var ctor = pat.Ctor;\n        Contract.Assert(ctor != null);  // follows from successful resolution\n        Contract.Assert(pat.Arguments.Count == ctor.Formals.Count);  // follows from successful resolution\n        var k = 0;  // number of non-ghost formals processed\n        for (int i = 0; i < pat.Arguments.Count; i++) {\n          var arg = pat.Arguments[i];\n          var formal = ctor.Formals[i];\n          if (formal.IsGhost) {\n            // nothing to compile, but do a sanity check\n            Contract.Assert(!Contract.Exists(arg.Vars, bv => !bv.IsGhost));\n          } else {\n            var sw = new TargetWriter(wr.IndentLevel, true);\n            EmitDestructor(rhsString, formal, k, ctor, ((DatatypeValue)pat.Expr).InferredTypeArgs, arg.Expr.Type, sw);\n            wr = TrCasePattern(arg, sw.ToString(), bodyType, wr);\n            k++;\n          }\n        }\n      }\n      return wr;\n    }\n\n    void CompileSpecialFunctionCallExpr(FunctionCallExpr e, TargetWriter wr, bool inLetExprBody, FCE_Arg_Translator tr) {\n      string name = e.Function.Name;\n\n      if (name == \"RotateLeft\") {\n        EmitRotate(e.Receiver, e.Args[0], true, wr, inLetExprBody, tr);\n      } else if (name == \"RotateRight\") {\n        EmitRotate(e.Receiver, e.Args[0], false, wr, inLetExprBody, tr);\n      } else {\n        CompileFunctionCallExpr(e, wr, inLetExprBody, tr);\n      }\n    }\n\n    void CompileFunctionCallExpr(FunctionCallExpr e, TargetWriter wr, bool inLetExprBody, FCE_Arg_Translator tr) {\n      Contract.Requires(e != null && e.Function != null);\n      Contract.Requires(wr != null);\n      Contract.Requires(tr != null);\n      Function f = e.Function;\n\n      wr = EmitCoercionIfNecessary(f.ResultType, e.Type, e.tok, wr);\n\n      var customReceiver = NeedsCustomReceiver(f);\n      string qual = \"\";\n      string compileName = \"\";\n      if (f.IsExtern(out qual, out compileName) && qual != null)\n      {\n        // ******************************************************************\n        // TODO: Add an overrideable function for the double colon used here\n        // ******************************************************************\n        wr.Write(\"{0}::\", qual);\n      } else if (f.IsStatic || customReceiver) {\n        wr.Write(TypeName_Companion(e.Receiver.Type, wr, e.tok, f));\n        compileName = IdName(f);\n      } else {\n        wr.Write(\"(\");\n        tr(e.Receiver, wr, inLetExprBody);\n        wr.Write(\")\");\n        compileName = IdName(f);\n      }\n      wr.Write(compileName);\n      wr.Write(\".{0}\", IdName(f));\n      List<Type> typeArgs;\n      if (f.TypeArgs.Count != 0) {\n        typeArgs = f.TypeArgs.ConvertAll(ta => e.TypeArgumentSubstitutions[ta]);\n        EmitActualTypeArgs(typeArgs, f.tok, wr);\n      } else {\n        typeArgs = new List<Type>();\n      }\n      wr.Write(\"(\");\n      var nRTDs = EmitRuntimeTypeDescriptorsActuals(typeArgs, f.TypeArgs, e.tok, false, wr);\n      string sep = nRTDs == 0 ? \"\" : \", \";\n      if (customReceiver) {\n        TrExpr(e.Receiver, wr, inLetExprBody);\n        sep = \", \";\n      }\n      for (int i = 0; i < e.Args.Count; i++) {\n        if (!e.Function.Formals[i].IsGhost) {\n          wr.Write(sep);\n          var w = EmitCoercionIfNecessary(from:e.Args[i].Type, to:e.Function.Formals[i].Type, tok:e.tok, wr:wr);\n          tr(e.Args[i], w, inLetExprBody);\n          sep = \", \";\n        }\n      }\n      wr.Write(\")\");\n    }\n\n    public virtual bool SupportsInMemoryCompilation { get => true; }\n\n    /// <summary>\n    /// Compile the target program known as \"dafnyProgramName\".\n    /// \"targetProgramText\" contains the program text.\n    /// If \"targetFilename\" is non-null, it is the name of the target program text stored as a\n    /// file. \"targetFileName\" must be non-null if \"otherFileNames\" is nonempty.\n    /// \"otherFileNames\" is a list of other files to include in the compilation.\n    ///\n    /// \"hasMain\" says whether or not the program contains a \"Main()\" program.\n    ///\n    /// Upon successful compilation, \"runAfterCompile\" says whether or not to execute the program.\n    ///\n    /// Output any errors to \"outputWriter\".\n    /// Returns \"false\" if there were errors. Then, \"compilationResult\" should not be used.\n    /// Returns \"true\" on success. Then, \"compilationResult\" is a value that can be passed in to\n    /// the instance's \"RunTargetProgram\" method.\n    /// </summary>\n    public virtual bool CompileTargetProgram(string dafnyProgramName, string targetProgramText, string/*?*/ callToMain, string/*?*/ targetFilename, ReadOnlyCollection<string> otherFileNames,\n      bool hasMain, bool runAfterCompile, TextWriter outputWriter, out object compilationResult) {\n      Contract.Requires(dafnyProgramName != null);\n      Contract.Requires(targetProgramText != null);\n      Contract.Requires(otherFileNames != null);\n      Contract.Requires(otherFileNames.Count == 0 || targetFilename != null);\n      Contract.Requires(this.SupportsInMemoryCompilation || targetFilename != null);\n      Contract.Requires(!runAfterCompile || hasMain);\n      Contract.Requires(outputWriter != null);\n\n      compilationResult = null;\n      return true;\n    }\n\n    /// <summary>\n    /// Runs a target program after it has been successfully compiled.\n    /// dafnyProgram, targetProgramText, targetFilename, and otherFileNames are the same as the corresponding parameters to \"CompileTargetProgram\".\n    /// \"callToMain\" is an explicit call to Main, as required by the target compilation language.\n    /// \"compilationResult\" is a value returned by \"CompileTargetProgram\" for these parameters.\n    ///\n    /// Returns \"true\" on success, \"false\" on error. Any errors are output to \"outputWriter\".\n    /// </summary>\n    public virtual bool RunTargetProgram(string dafnyProgramName, string targetProgramText, string/*?*/ callToMain, string/*?*/ targetFilename, ReadOnlyCollection<string> otherFileNames,\n      object compilationResult, TextWriter outputWriter) {\n      Contract.Requires(dafnyProgramName != null);\n      Contract.Requires(targetProgramText != null);\n      Contract.Requires(otherFileNames != null);\n      Contract.Requires(otherFileNames.Count == 0 || targetFilename != null);\n      Contract.Requires(outputWriter != null);\n      return true;\n    }\n  }\n\n  public class TargetWriter : TextWriter {\n    public TargetWriter(int indent = 0, bool suppressInitialIndent = false) {\n      Contract.Requires(0 <= indent);\n      IndentLevel = indent;\n      IndentString = new string(' ', indent);\n      indentPending = !suppressInitialIndent;\n    }\n    public override Encoding Encoding {\n      get { return Encoding.Default; }\n    }\n\n    // ----- Indention ------------------------------\n\n    public readonly int IndentLevel;\n    public const int IndentAmount = 2;\n    const string IndentAmountString = \"  \";  // this should have the length IndentAmount\n    public readonly string IndentString;\n    public string UnIndentString => new string(' ', Math.Max(IndentLevel - IndentAmount, 0));\n    public void IndentLess() {\n      indentPending = false;\n      Write(UnIndentString);\n    }\n\n    // ----- Things ------------------------------\n\n    private readonly List<object> things = new List<object>();\n\n    private void AddThing(object thing) {\n      if (indentPending) {\n        indentPending = false;\n        things.Add(IndentString);\n      }\n      things.Add(thing);\n      if (thing is BlockTargetWriter btw && btw.EndsWithNewLine) {\n        indentPending = true;\n      } else {\n        indentPending = false;\n      }\n    }\n\n    public void Append(TargetWriter wr) {\n      Contract.Requires(wr != null);\n      AddThing(wr);\n    }\n\n    // ----- Writing ------------------------------\n\n    bool indentPending;\n\n    public override void Write(char[] buffer, int index, int count) {\n      if (indentPending && count == 1 && buffer[index] == '\\n') {\n        indentPending = false;\n      }\n      AddThing(new string(buffer, index, count));\n      indentPending = count > 0 && buffer[index + count - 1] == '\\n';\n    }\n    public override void Write(string value) {\n      if (indentPending && value == \"\\n\") {\n        indentPending = false;\n      }\n      AddThing(value);\n      indentPending = false;\n    }\n    public override void Write(char value) {\n      if (indentPending && value == '\\n') {\n        indentPending = false;\n      }\n      indentPending = false;\n      AddThing(new string(value, 1));\n      indentPending = false;\n    }\n\n    public void RepeatWrite(int times, string template, string separator) {\n      Contract.Requires(1 <= times);\n      Contract.Requires(template != null);\n      Contract.Requires(separator != null);\n      string sep = \"\";\n      for (int i = 0; i < times; i++) {\n        Write(sep);\n        Write(template, i);\n        sep = separator;\n      }\n    }\n\n    public void WriteError(string format, params string[] args) {\n      var oldIndentPending = indentPending;\n      WriteLine(format, args);\n      indentPending = oldIndentPending;\n    }\n\n    /// <summary>\n    /// Fork() is to be used when the new TargetWriter will not start with an indent\n    /// and will not end with a newline. (However, contrary to what the name of this parameter may\n    /// suggest, the new TargetWriter may choose to add its own newlines and indents in the middele.)\n    /// See also ForkSection().\n    /// </summary>\n    public TargetWriter Fork() {\n      var ans = new TargetWriter(IndentLevel, true);\n      AddThing(ans);\n      return ans;\n    }\n\n    /// <summary>\n    /// ForkSection() says that the new TargetWriter will form a block of complete lines,\n    /// each beginning with an indent and ending with a newline.\n    /// </summary>\n    public TargetWriter ForkSection(bool indentMore = false) {\n      indentPending = false;\n      var ans = new TargetWriter(IndentLevel + (indentMore ? IndentAmount : 0));\n      AddThing(ans);\n      indentPending = true;\n      return ans;\n    }\n\n    // ----- Nested blocks ------------------------------\n\n    public BlockTargetWriter NewBlock(string header, string/*?*/ footer = null,\n      BlockTargetWriter.BraceStyle open = BlockTargetWriter.BraceStyle.Space,\n      BlockTargetWriter.BraceStyle close = BlockTargetWriter.BraceStyle.Newline) {\n      Contract.Requires(header != null);\n      var btw = new BlockTargetWriter(IndentLevel + IndentAmount, header, footer);\n      btw.SetBraceStyle(open, close);\n      AddThing(btw);\n      return btw;\n    }\n    public BlockTargetWriter NewNamedBlock(string headerFormat, params object[] headerArgs) {\n      Contract.Requires(headerFormat != null);\n      return NewBigBlock(string.Format(headerFormat, headerArgs), null);\n    }\n    public BlockTargetWriter NewBigBlock(string header, string/*?*/ footer) {\n      Contract.Requires(header != null);\n      var btw = new BlockTargetWriter(IndentLevel + IndentAmount, header, footer);\n      btw.SetBraceStyle(BlockTargetWriter.BraceStyle.Space, BlockTargetWriter.BraceStyle.Newline);\n      AddThing(btw);\n      return btw;\n    }\n    public BlockTargetWriter NewExprBlock(string headerFormat, params object[] headerArgs) {\n      Contract.Requires(headerFormat != null);\n      return NewBigExprBlock(string.Format(headerFormat, headerArgs), null);\n    }\n    public BlockTargetWriter NewBigExprBlock(string header, string/*?*/ footer) {\n      Contract.Requires(header != null);\n      var btw = new BlockTargetWriter(IndentLevel + IndentAmount, header, footer);\n      btw.SetBraceStyle(BlockTargetWriter.BraceStyle.Space, BlockTargetWriter.BraceStyle.Nothing);\n      AddThing(btw);\n      return btw;\n    }\n    public BlockTargetWriter NewBlockWithPrefix(string headerFormat, string prefixFormat, params object[] headerArgs) {\n      Contract.Requires(headerFormat != null);\n      Contract.Requires(prefixFormat != null);\n      var btw = new BlockTargetWriter(IndentLevel + IndentAmount, string.Format(headerFormat, headerArgs), null);\n      btw.SetBraceStyle(BlockTargetWriter.BraceStyle.Space, BlockTargetWriter.BraceStyle.Newline);\n      btw.BodyPrefix = string.Format(prefixFormat, headerArgs);\n      AddThing(btw);\n      return btw;\n    }\n\n    public TargetWriter NewSection() {\n      var w = new TargetWriter(IndentLevel);\n      AddThing(w);\n      return w;\n    }\n\n    public FileTargetWriter NewFile(string filename) {\n      var w = new FileTargetWriter(filename);\n      AddThing(w);\n      return w;\n    }\n\n    // ----- Collection ------------------------------\n\n    public override string ToString() {\n      var sw = new StringWriter();\n      var q = new Queue<FileTargetWriter>();\n      Collect(sw, q);\n      while (q.Count != 0) {\n        var ftw = q.Dequeue();\n        sw.WriteLine(\"#file {0}\", ftw.Filename);\n        ftw.Collect(sw, q);\n      }\n      return sw.ToString();\n    }\n    public virtual void Collect(TextWriter wr, Queue<FileTargetWriter> files) {\n      Contract.Requires(wr != null);\n      Contract.Requires(files != null);\n\n      Contract.Assert(things != null);\n      CollectThings(wr, files);\n    }\n    protected void CollectThings(TextWriter wr, Queue<FileTargetWriter> files) {\n      Contract.Requires(wr != null);\n      Contract.Requires(files != null);\n\n      foreach (var o in things) {\n        if (o is string s) {\n          wr.Write(s);\n        } else if (o is FileTargetWriter ftw) {\n          files.Enqueue(ftw);\n        } else if (o is TargetWriter tw) {\n          tw.Collect(wr, files);\n        } else {\n          wr.Write(o.ToString());\n        }\n      }\n    }\n  }\n  public class BlockTargetWriter : TargetWriter {\n    string header;\n    public enum BraceStyle { Nothing, Space, Newline }\n    BraceStyle openBraceStyle = BraceStyle.Space;\n    BraceStyle closeBraceStyle = BraceStyle.Newline;  // must be set to its final value before the BlockTargetWriter is .Add'ed to an enclosing TargetWriter\n    public string BodyPrefix;  // just inside the open curly (before the newline)\n    public string BodySuffix;  // just before the close curly\n    public string Footer;  // just after the close curly\n    public BlockTargetWriter(int indentInsideBraces, string header, string/*?*/ footer)\n    : base(indentInsideBraces) {\n      Contract.Requires(IndentAmount <= indentInsideBraces);\n      Contract.Requires(header != null);\n      this.header = header;\n      this.Footer = footer;\n    }\n    public void SetBraceStyle(BraceStyle open, BraceStyle close) {\n      this.openBraceStyle = open;\n      this.closeBraceStyle = close;\n    }\n    public bool EndsWithNewLine {\n      get => closeBraceStyle == BraceStyle.Newline;\n    }\n    public void AppendHeader(string format, params object[] args) {\n      Contract.Requires(format != null);\n      header += args.Length == 0 ? format : string.Format(format, args);\n    }\n\n    public override void Collect(TextWriter wr, Queue<FileTargetWriter> files) {\n      wr.Write(header);\n      switch (openBraceStyle) {\n        case BraceStyle.Nothing:\n        default:\n          break;\n        case BraceStyle.Space:\n          wr.Write(\" \");\n          break;\n        case BraceStyle.Newline:\n          wr.WriteLine();\n          wr.Write(UnIndentString);\n          break;\n      }\n      wr.WriteLine(\"{{{0}\", BodyPrefix != null ? \" \" + BodyPrefix : \"\");\n      CollectThings(wr, files);\n      if (BodySuffix != null) {\n        wr.Write(BodySuffix);\n      }\n      wr.Write(UnIndentString);\n      wr.Write(\"}\");\n      if (Footer != null) {\n        wr.Write(Footer);\n      }\n      switch (closeBraceStyle) {\n        case BraceStyle.Nothing:\n        default:\n          break;\n        case BraceStyle.Space:\n          wr.Write(\" \");\n          break;\n        case BraceStyle.Newline:\n          wr.WriteLine();\n          break;\n      }\n    }\n  }\n\n  public class FileTargetWriter : TargetWriter {\n    public readonly string Filename;\n\n    public FileTargetWriter(string filename) {\n      Contract.Requires(filename != null);\n      Filename = filename;\n    }\n  }\n}\n"
  },
  {
    "path": "Source/Armada/ConstraintCollector.cs",
    "content": "using System;\nusing System.Numerics;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text;\nusing static Microsoft.Armada.Predicate;\nusing IToken = Microsoft.Boogie.IToken;\nusing Token = Microsoft.Boogie.Token;\n\nnamespace Microsoft.Armada {\n\n  public interface IFailureReporter {\n    bool Valid { get; }\n    void Fail(IToken tok, string reason);\n    void Fail(string reason);\n  }\n\n  public class SimpleFailureReporter : IFailureReporter {\n    private bool valid;\n    private Program prog;\n    \n    public bool Valid { get { return valid; } }\n\n    public SimpleFailureReporter(Program i_prog)\n    {\n      valid = true;\n      prog = i_prog;\n    }\n\n    public void Fail(IToken tok, string reason) {\n      valid = false;\n      if (reason != null) {\n        AH.PrintError(prog, tok, reason);\n      }\n    }\n\n    public void Fail(string reason) {\n      Fail(Token.NoToken, reason);\n    }\n  }\n\n  public interface IConstraintCollector : IFailureReporter {\n    string ReserveVariableName(string varName);\n    string AddVariableDeclaration(string varName, string value);\n    void AddUndefinedBehaviorAvoidanceConstraint(string constraint);\n    void AddUndefinedBehaviorAvoidanceConstraint(UndefinedBehaviorAvoidanceConstraint constraint);\n  }\n\n  public class EnablingConstraintCollector : IConstraintCollector\n  {\n    private Program prog;\n    private PredicateBuilder builder;\n    private bool valid;\n    private bool empty;\n\n    public readonly string s;\n    public readonly string tid;\n    public readonly string t;\n    public readonly string locv;\n    public readonly string top;\n    public readonly string ghosts;\n\n    public EnablingConstraintCollector(Program i_prog)\n    {\n      prog = i_prog;\n      builder = new PredicateBuilder(i_prog, true);\n      valid = true;\n      empty = true;\n\n      s = ReserveVariableName(\"s\");\n      tid = ReserveVariableName(\"tid\");\n      var threads = $\"{s}.threads\";\n      t = AddVariableDeclaration(\"t\", $\"{threads}[{tid}]\");\n      locv = AddVariableDeclaration(\"locv\", $\"Armada_GetThreadLocalView({s}, {tid})\");\n      top = $\"{t}.top\";\n      ghosts = $\"{s}.ghosts\";\n    }\n\n    public bool Valid { get { return valid; } }\n\n    public bool Empty { get { return empty; } }\n\n    public string ReserveVariableName(string varName)\n    {\n      return builder.ReserveVariableName(varName);\n    }\n\n    public string AddVariableDeclaration(string varName, string value)\n    {\n      return builder.AddVariableDeclaration(varName, value);\n    }\n\n    public void AddUndefinedBehaviorAvoidanceConstraint(string constraint)\n    {\n      empty = false;\n      builder.AddConjunct(constraint);\n    }\n\n    public void AddUndefinedBehaviorAvoidanceConstraint(UndefinedBehaviorAvoidanceConstraint constraint)\n    {\n      foreach (var e in constraint.AsList) {\n        AddUndefinedBehaviorAvoidanceConstraint(e);\n      }\n    }\n    \n    public void AddConjunct(string conjunct)\n    {\n      empty = false;\n      builder.AddConjunct(conjunct);\n    }\n\n    public void AddConjunct(UndefinedBehaviorAvoidanceConstraint constraint)\n    {\n      foreach (var e in constraint.AsList)\n      {\n        AddConjunct(e);\n      }\n    }\n\n    public void Fail(IToken tok, string reason) {\n      valid = false;\n      if (reason != null) {\n        AH.PrintError(prog, tok, reason);\n      }\n    }\n\n    public void Fail(string reason) {\n      Fail(Token.NoToken, reason);\n    }\n\n    public string Extract()\n    {\n      if (!valid) {\n        return null;\n      }\n\n      return builder.Extract();\n    }\n  }\n}\n"
  },
  {
    "path": "Source/Armada/DeclCollector.cs",
    "content": "using System;\nusing System.Numerics;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text;\nusing System.Text.RegularExpressions;\nusing static Microsoft.Armada.Predicate;\nusing Token = Microsoft.Boogie.Token;\n\nnamespace Microsoft.Armada\n{\n\n  public class DeclCollector\n  {\n    private Program prog;\n    private List<TopLevelDecl> newTopLevelDecls;\n    private List<MemberDecl> newDefaultClassDecls;\n\n    public DeclCollector(Program i_prog)\n    {\n      prog = i_prog;\n      newTopLevelDecls = new List<TopLevelDecl>();\n      newDefaultClassDecls = new List<MemberDecl>();\n    }\n\n    public List<TopLevelDecl> NewTopLevelDecls { get { return newTopLevelDecls; } }\n    public List<MemberDecl> NewDefaultClassDecls { get { return newDefaultClassDecls; } }\n\n    public void AddTopLevelDecl(TopLevelDecl d)\n    {\n      newTopLevelDecls.Add(d);\n    }\n\n    public void AddDefaultClassDecl(MemberDecl d)\n    {\n      newDefaultClassDecls.Add(d);\n    }\n\n    public void CopyMathematicalDefaultClassMembers(ClassDecl defaultClass)\n    {\n      foreach (var m in defaultClass.Members) {\n        if (m is Function || m is Lemma && ! m.Name.StartsWith(\"reveal_\")) { // fix for duplicate export of opaque functions\n          AddDefaultClassDecl(m);\n        }\n      }\n    }\n\n    public void CopyMathematicalTopLevelDecls(ModuleDefinition m)\n    {\n      foreach (var d in m.TopLevelDecls) {\n        if (d is DatatypeDecl || d is NewtypeDecl || d is TypeSynonymDecl || d is AliasModuleDecl) {\n          AddTopLevelDecl(d);\n        }\n      }\n    }\n\n    public void AddItem(string contents)\n    {\n      Match match = Regex.Match(contents, @\"^\\s*((lemma)|(function)|(predicate)|(datatype)|(type))\\s+\");\n      if (match.Success)\n      {\n        string name = match.Groups[1].Value;\n        if (name == \"lemma\") {\n          AddLemma(contents);\n        }\n        else if (name == \"function\") {\n          AddFunction(contents);\n        }\n        else if (name == \"predicate\") {\n          AddPredicate(contents);\n        }\n        else if (name == \"datatype\") {\n          AddDatatype(contents);\n        }\n        else if (name == \"type\") {\n          AddTypeSynonym(contents);\n        }\n        else {\n          AH.PrintError(prog, \"Can't add an item that doesn't start with lemma, function, predicate, datatype, or type\");\n        }\n      }\n      else\n      {\n        AH.PrintError(prog, \"Can't add an item that doesn't start with lemma, function, predicate, datatype, or type\");\n      }\n    }\n\n    public void AddLemma(string contents)\n    {\n      Match match = Regex.Match(contents, @\"^\\s*lemma\\s+({[^}]*}\\s*)*([^\\s<(]+)\");\n      if (match.Success)\n      {\n        string name = match.Groups[2].Value;\n        AddDefaultClassDecl((Lemma)AH.ParseTopLevelDecl(prog, name, contents));\n      }\n      else {\n        AH.PrintError(prog, $\"Could not find lemma name in {contents}\");\n      }\n    }\n\n    public void AddFunction(string contents)\n    {\n      Match match = Regex.Match(contents, @\"^\\s*function\\s+({[^}]*}\\s*)*([^\\s<(]+)\");\n      if (match.Success)\n      {\n        string name = match.Groups[2].Value;\n        AddDefaultClassDecl((Function)AH.ParseTopLevelDecl(prog, name, contents));\n      }\n      else {\n        AH.PrintError(prog, $\"Could not find function name in {contents}\");\n      }\n    }\n\n    public void AddPredicate(string contents)\n    {\n      Match match = Regex.Match(contents, @\"^\\s*predicate\\s+({[^}]*}\\s*)*([^\\s<(]+)\");\n      if (match.Success)\n      {\n        string name = match.Groups[2].Value;\n        AddDefaultClassDecl((Predicate)AH.ParseTopLevelDecl(prog, name, contents));\n      }\n      else {\n        AH.PrintError(prog, $\"Could not find predicate name in {contents}\");\n        return;\n      }\n    }\n\n    public void AddDatatype(string contents)\n    {\n      Match match = Regex.Match(contents, @\"^\\s*datatype\\s+([^\\s<(=]+)\");\n      if (match.Success)\n      {\n        string name = match.Groups[1].Value;\n        AddTopLevelDecl((DatatypeDecl)AH.ParseTopLevelDecl(prog, name, contents));\n      }\n      else\n      {\n        AH.PrintError(prog, $\"Could not find datatype name in {contents}\");\n      }\n    }\n\n    public void AddTypeSynonym(string contents)\n    {\n      Match match = Regex.Match(contents, @\"^\\s*type\\s+([^\\s<(=]+)\");\n      if (match.Success)\n      {\n        string name = match.Groups[1].Value;\n        AddTopLevelDecl((TypeSynonymDecl)AH.ParseTopLevelDecl(prog, name, contents));\n      }\n      else\n      {\n        AH.PrintError(prog, $\"Could not find type synonym name in {contents}\");\n      }\n    }\n\n  }\n\n}\n"
  },
  {
    "path": "Source/Armada/ExpressionBuilder.cs",
    "content": "using System;\nusing System.Numerics;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text;\nusing static Microsoft.Armada.Predicate;\nusing IToken = Microsoft.Boogie.IToken;\nusing Token = Microsoft.Boogie.Token;\n\nnamespace Microsoft.Armada {\n\n  public class ExpressionBuilder {\n    private Program prog;\n    private bool valid;\n    private List<string> variableNames;\n    private List<string> variableValues;\n    private Dictionary<string, int> variableUseCount;\n    private string body;\n\n    public ExpressionBuilder(Program i_prog)\n    {\n      prog = i_prog;\n      valid = true;\n      variableNames = new List<string>();\n      variableValues = new List<string>();\n      variableUseCount = new Dictionary<string, int>();\n      body = null;\n    }\n\n    public bool Valid { get { return valid; } }\n\n    public string ReserveVariableName(string varName)\n    {\n      if (variableUseCount.ContainsKey(varName)) {\n        AH.PrintError(prog, $\"Internal error:  Attempt to reserve variable name that's already in use ({varName}).\");\n        return null;\n      }\n      else {\n        variableUseCount[varName] = 1;\n        return varName;\n      }\n    }\n\n    public string AddVariableDeclaration(string varName, string value)\n    {\n      if (!valid) {\n        return null;\n      }\n\n      int count;\n      if (variableUseCount.TryGetValue(varName, out count)) {\n        variableUseCount[varName] = count + 1;\n        varName = $\"{varName}{count+1}\";\n      }\n      else {\n        variableUseCount[varName] = 1;\n      }\n\n      variableNames.Add(varName);\n      variableValues.Add(value);\n\n      return varName;\n    }\n\n    public void SetBody(string e)\n    {\n      body = e;\n    }\n\n    public string Extract()\n    {\n      if (body == null) {\n        Fail(\"Internal error:  Attempt to extract before body is set\");\n      }\n\n      if (!valid) {\n        return null;\n      }\n\n      return String.Concat(Enumerable.Range(0, variableNames.Count).Select(i => $\"var {variableNames[i]} := {variableValues[i]};\\n\"))\n             + body;\n    }\n\n    public void Fail(IToken tok, string reason) {\n      valid = false;\n      if (reason != null) {\n        AH.PrintError(prog, tok, reason);\n      }\n    }\n\n    public void Fail(string reason) {\n      Fail(Token.NoToken, reason);\n    }\n  }\n\n  public class MapBuilder {\n    private string mapName;\n    private List<string> variableLets;\n    private int count;\n\n    public MapBuilder(string i_mapName = \"m\", string initMap = \"map[]\") {\n      mapName = i_mapName;\n      count = 0;\n      variableLets = new List<string>();\n      variableLets.Add($\"var {mapName}0 := {initMap}\");\n    }\n\n    public void Add(string keySet, string value)\n    {\n      count++;\n      variableLets.Add($\"var {mapName}{count} := AddSetToMap({mapName}{count - 1}, ({keySet}), ({value}))\");\n    }\n\n    public string Extract()\n    {\n      return string.Join(\";\", variableLets) + $\"; m{count}\";\n    }\n  }\n}\n"
  },
  {
    "path": "Source/Armada/GlobalVarHiding.cs",
    "content": "using System;\nusing System.Numerics;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text;\nusing System.Text.RegularExpressions;\nusing static Microsoft.Armada.Predicate;\nusing IToken = Microsoft.Boogie.IToken;\nusing Token = Microsoft.Boogie.Token;\n\nnamespace Microsoft.Armada {\n\n  public class GlobalVarHidingProofGenerator : VarHidingProofGenerator\n  {\n    private GlobalVariableHidingStrategyDecl strategy;\n    private HashSet<string> hiddenVariables;\n\n    public GlobalVarHidingProofGenerator(ProofGenerationParams i_pgp, GlobalVariableHidingStrategyDecl i_strategy) : base(i_pgp, true)\n    {\n      strategy = i_strategy;\n      hiddenVariables = new HashSet<string>(strategy.Variables);\n      if (hiddenVariables.All(varName => pgp.symbolsLow.Globals.Lookup(varName).varType == ArmadaVarType.Ghost)) {\n        canHideTau = false;\n      }\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    /// Checking that the layers are similar enough to generate a proof\n    ////////////////////////////////////////////////////////////////////////\n\n    // We have to override the default implementation of CheckGlobalsEquivalence because we need to\n    // skip hidden variables.\n\n    protected override bool CheckGlobalsEquivalence()\n    {\n      var globalVarsLow = pgp.symbolsLow.Globals.VariableNames.Where(s => !hiddenVariables.Contains(s)).ToArray();\n      var globalVarsHigh = pgp.symbolsHigh.Globals.VariableNames.ToArray();\n\n      if (globalVarsLow.Length != globalVarsHigh.Length) {\n        AH.PrintError(pgp.prog, $\"There are {globalVarsLow.Length} global variables in level {pgp.mLow.Name} (not counting hidden ones) but {globalVarsHigh.Length} in level {pgp.mHigh.Name}\");\n        return false;\n      }\n\n      for (int i = 0; i < globalVarsLow.Length; ++i) {\n        if (globalVarsLow[i] != globalVarsHigh[i]) {\n          AH.PrintError(pgp.prog, $\"Global variable number {i+1} (not counting hidden ones) in level {pgp.mLow.Name} is {globalVarsLow[i]}, which doesn't match global variable number {i+1} in level {pgp.mHigh.Name} which is {globalVarsHigh[i]}\");\n          return false;\n        }\n        var name = globalVarsLow[i];\n        if (!CheckGlobalVariableEquivalence(name, pgp.symbolsLow.Globals.Lookup(name), pgp.symbolsHigh.Globals.Lookup(name))) {\n          return false;\n        }\n      }\n\n      return true;\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    // PC mapping\n    ////////////////////////////////////////////////////////////////////////\n\n    protected override bool IsVariableHidden(string methodName, string varName)\n    {\n      if (varName == null) {\n        return false;\n      }\n      if (!hiddenVariables.Contains(varName)) {\n        return false;\n      }\n\n      // If it has the same name as an introduced global varible, make sure\n      // it isn't shadowed by a local variable in this method.\n\n      var st = pgp.symbolsLow.GetMethodSymbolTable(methodName);\n      return st.LookupVariable(varName) == null;\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    /// Abstraction functions\n    ////////////////////////////////////////////////////////////////////////\n\n    protected override void GenerateConvertGlobals_LH()\n    {\n      var ps = new List<string>();\n      foreach (var varName in pgp.symbolsLow.Globals.VariableNames) {\n        if (hiddenVariables.Contains(varName)) {\n          continue;\n        }\n        var v = pgp.symbolsLow.Globals.Lookup(varName);\n        if (v is GlobalUnaddressableArmadaVariable) {\n          ps.Add($\"globals.{v.FieldName}\");\n        }\n      }\n      var fn = $@\"\n        function ConvertGlobals_LH(globals: L.Armada_Globals) : H.Armada_Globals\n        {{\n          H.Armada_Globals({AH.CombineStringsWithCommas(ps)})\n        }}\n      \";\n      pgp.AddFunction(fn, \"convert\");\n    }\n\n    protected override void GenerateConvertGlobalStaticVar_LH()\n    {\n      if (!canHideTau) {\n        base.GenerateConvertGlobalStaticVar_LH();\n        return;\n      }\n      \n      var es = new List<string>();\n      foreach (var varName in hiddenVariables) {\n        var gv = pgp.symbolsLow.Globals.Lookup(varName);\n        if (gv is GlobalUnaddressableArmadaVariable) {\n          es.Add($\"!v.Armada_GlobalStaticVar_{varName}?\");\n        }\n      }\n\n      var fn = $@\"\n        predicate CanConvertGlobalStaticVar_LH(v: L.Armada_GlobalStaticVar)\n        {{\n          {AH.CombineStringsWithAnd(es)}\n        }}\n      \";\n      pgp.AddPredicate(fn, \"convert\");\n\n      var caseBodies = \"case Armada_GlobalStaticVarNone => H.Armada_GlobalStaticVarNone\\n\";\n      foreach (var varName in pgp.symbolsLow.Globals.VariableNames) {\n        if (hiddenVariables.Contains(varName)) {\n          continue;\n        }\n        var gv = pgp.symbolsLow.Globals.Lookup(varName);\n        if (gv is GlobalUnaddressableArmadaVariable) {\n          caseBodies += $\"case Armada_GlobalStaticVar_{varName} => H.Armada_GlobalStaticVar_{varName}\\n\";\n        }\n      }\n      fn = $@\"\n        function ConvertGlobalStaticVar_LH(v: L.Armada_GlobalStaticVar) : H.Armada_GlobalStaticVar\n          requires CanConvertGlobalStaticVar_LH(v)\n        {{\n          match v\n            {caseBodies}\n        }}\n      \";\n      pgp.AddFunction(fn, \"convert\");\n    }\n\n    protected override void GenerateConvertGhosts_LH()\n    {\n      var ps = new List<string>();\n      foreach (var varName in pgp.symbolsLow.Globals.VariableNames) {\n        if (hiddenVariables.Contains(varName)) {\n          continue;\n        }\n        var v = pgp.symbolsLow.Globals.Lookup(varName);\n        if (v is GlobalGhostArmadaVariable) {\n          ps.Add($\"ghosts.{v.FieldName}\");\n        }\n      }\n      var fn = $@\"\n        function ConvertGhosts_LH(ghosts: L.Armada_Ghosts) : H.Armada_Ghosts\n        {{\n          H.Armada_Ghosts({AH.CombineStringsWithCommas(ps)})\n        }}\n      \";\n      pgp.AddFunction(fn, \"convert\");\n    }\n\n    protected override void GenerateConvertStoreBufferLocation_LH()\n    {\n      if (!canHideTau) {\n        base.GenerateConvertStoreBufferLocation_LH();\n        return;\n      }\n\n      string str;\n\n      str = @\"\n        predicate CanConvertStoreBufferLocation_LH(loc:L.Armada_StoreBufferLocation)\n        {\n          loc.Armada_StoreBufferLocation_Unaddressable? ==> CanConvertGlobalStaticVar_LH(loc.v)\n        }\n      \";\n      pgp.AddPredicate(str, \"convert\");\n\n      str = @\"\n        function ConvertStoreBufferLocation_LH(loc:L.Armada_StoreBufferLocation) : H.Armada_StoreBufferLocation\n          requires CanConvertStoreBufferLocation_LH(loc)\n        {\n          match loc\n            case Armada_StoreBufferLocation_Unaddressable(v, fields) =>\n              H.Armada_StoreBufferLocation_Unaddressable(ConvertGlobalStaticVar_LH(v), fields)\n            case Armada_StoreBufferLocation_Addressable(p) =>\n              H.Armada_StoreBufferLocation_Addressable(p)\n        }\n      \";\n      pgp.AddFunction(str, \"convert\");\n    }\n\n    protected override void GenerateConvertStoreBufferEntry_LH()\n    {\n      if (!canHideTau) {\n        base.GenerateConvertStoreBufferEntry_LH();\n        return;\n      }\n      \n      string str;\n\n      str = @\"\n        predicate CanConvertStoreBufferEntry_LH(entry:L.Armada_StoreBufferEntry)\n        {\n          CanConvertStoreBufferLocation_LH(entry.loc)\n        }\n      \";\n      pgp.AddPredicate(str, \"convert\");\n\n      str = @\"\n        function ConvertStoreBufferEntry_LH(entry:L.Armada_StoreBufferEntry) : H.Armada_StoreBufferEntry\n          requires CanConvertStoreBufferEntry_LH(entry)\n        {\n          H.Armada_StoreBufferEntry(ConvertStoreBufferLocation_LH(entry.loc), entry.value, ConvertPC_LH(entry.pc))\n        }\n      \";\n      pgp.AddFunction(str, \"convert\");\n    }\n\n    protected override void GenerateConvertStoreBuffer_LH()\n    {\n      if (!canHideTau) {\n        base.GenerateConvertStoreBuffer_LH();\n        return;\n      }\n\n      string str = @\"\n        function ConvertStoreBuffer_LH(entries:seq<L.Armada_StoreBufferEntry>) : seq<H.Armada_StoreBufferEntry>\n        {\n          FilterMapSeqToSeq(entries, e => if CanConvertStoreBufferEntry_LH(e) then Some(ConvertStoreBufferEntry_LH(e)) else None)\n        }\n      \";\n      pgp.AddFunction(str, \"convert\");\n    }\n\n    protected override void GenerateConvertAtomicPath_LH()\n    {\n      string str;\n\n      var skipped_strs = new List<string>();\n\n      if (canHideTau) {\n        str = @\"\n          predicate IsSkippedTauPath(s: LPlusState, path: LAtomic_Path, tid: Armada_ThreadHandle)\n          {\n            && path.LAtomic_Path_Tau?\n            && tid in s.s.threads\n            && |s.s.threads[tid].storeBuffer| > 0\n            && !CanConvertStoreBufferEntry_LH(s.s.threads[tid].storeBuffer[0])\n          }\n        \";\n        pgp.AddPredicate(str, \"convert\");\n\n        skipped_strs.Add(\"IsSkippedTauPath(s, path, tid)\");\n      }\n\n      string convert_str = @\"\n        function ConvertAtomicPath_LH(s: LPlusState, path: LAtomic_Path, tid: Armada_ThreadHandle) : HAtomic_Path\n          requires LAtomic_ValidPath(s, path, tid)\n          requires !IsSkippedPath(s, path, tid)\n        {\n          match path\n      \";\n\n      foreach (var lpath in lAtomic.AtomicPaths) {\n        if (pathMap.ContainsKey(lpath)) {\n          var hpath = pathMap[lpath];\n          var n = lpath.NextRoutines.Count;\n          convert_str += $\"case LAtomic_Path_{lpath.Name}(steps) => HAtomic_Path_{hpath.Name}(HAtomic_PathSteps_{hpath.Name}(\";\n          convert_str += String.Join(\", \", Enumerable.Range(0, n)\n                                                     .Where(i => nextRoutineMap.ContainsKey(lpath.NextRoutines[i]))\n                                                     .Select(i => $\"ConvertStep_LH(steps.step{i})\"));\n          convert_str += \"))\\n\";\n        }\n        else {\n          skipped_strs.Add($\"path.LAtomic_Path_{lpath.Name}?\");\n        }\n      }\n\n      convert_str += \"}\\n\";\n\n      pgp.AddPredicate($@\"\n        predicate IsSkippedPath(s: LPlusState, path: LAtomic_Path, tid: Armada_ThreadHandle)\n        {{\n          { AH.CombineStringsWithOr(skipped_strs) }\n        }}\n      \", \"convert\");\n\n      pgp.AddFunction(convert_str, \"convert\");\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    /// Store-buffer lemmas\n    ////////////////////////////////////////////////////////////////////////\n\n    protected override void GenerateLocalViewCommutativityLemmas()\n    {\n      if (!canHideTau) {\n        base.GenerateLocalViewCommutativityLemmas();\n        return;\n      }\n\n      string str;\n\n      string cases = \"\";\n      foreach (var varName in pgp.symbolsLow.Globals.VariableNames) {\n        if (hiddenVariables.Contains(varName)) {\n          continue;\n        }\n        var globalVar = pgp.symbolsLow.Globals.Lookup(varName);\n        if (globalVar is AddressableArmadaVariable || globalVar.NoTSO()) {\n          continue;\n        }\n        cases += $\"case Armada_GlobalStaticVar_{varName} => {{ }}\";\n      }\n      str = $@\"\n        lemma lemma_ApplyStoreBufferEntryUnaddressableCommutesWithConvert(\n          lglobals:L.Armada_Globals, lv:L.Armada_GlobalStaticVar, fields:seq<int>, value:Armada_PrimitiveValue,\n          hv:H.Armada_GlobalStaticVar, hglobals1:H.Armada_Globals, hglobals2:H.Armada_Globals)\n          requires CanConvertGlobalStaticVar_LH(lv)\n          requires hv == ConvertGlobalStaticVar_LH(lv)\n          requires hglobals1 == ConvertGlobals_LH(L.Armada_ApplyTauUnaddressable(lglobals, lv, fields, value))\n          requires hglobals2 == H.Armada_ApplyTauUnaddressable(ConvertGlobals_LH(lglobals), hv, fields, value)\n          ensures  hglobals1 == hglobals2\n        {{\n          match lv\n            case Armada_GlobalStaticVarNone =>\n            {{\n              var hglobals := ConvertGlobals_LH(lglobals);\n              assert hglobals1 == hglobals == hglobals2;\n            }}\n            { cases }\n        }}\n      \";\n      pgp.AddLemma(str, \"utility\");\n\n      str = @\"\n        lemma lemma_ApplyingUnconvertibleStoreBufferEntryDoesntChangeHState(lmem:L.Armada_SharedMemory, lentry:L.Armada_StoreBufferEntry)\n          requires !CanConvertStoreBufferEntry_LH(lentry)\n          ensures  ConvertSharedMemory_LH(L.Armada_ApplyStoreBufferEntry(lmem, lentry)) == ConvertSharedMemory_LH(lmem)\n        {\n        }\n      \";\n      pgp.AddLemma(str, \"utility\");\n\n      str = @\"\n        lemma lemma_ApplyStoreBufferEntryCommutesWithConvert(lmem:L.Armada_SharedMemory, lentry:L.Armada_StoreBufferEntry,\n                                                             hentry:H.Armada_StoreBufferEntry, hmem1:H.Armada_SharedMemory,\n                                                             hmem2:H.Armada_SharedMemory)\n          requires CanConvertStoreBufferEntry_LH(lentry)\n          requires hentry == ConvertStoreBufferEntry_LH(lentry)\n          requires hmem1 == ConvertSharedMemory_LH(L.Armada_ApplyStoreBufferEntry(lmem, lentry))\n          requires hmem2 == H.Armada_ApplyStoreBufferEntry(ConvertSharedMemory_LH(lmem), hentry)\n          ensures  hmem1 == hmem2\n        {\n          match lentry.loc\n            case Armada_StoreBufferLocation_Unaddressable(lv, lfields) =>\n            {\n              var hv := ConvertGlobalStaticVar_LH(lv);\n              lemma_ApplyStoreBufferEntryUnaddressableCommutesWithConvert(lmem.globals, lv, lfields, lentry.value, hv, hmem1.globals,\n                                                                          hmem2.globals);\n            }\n            case Armada_StoreBufferLocation_Addressable(p) =>\n            {\n            }\n        }\n      \";\n      pgp.AddLemma(str, \"utility\");\n\n      str = @\"\n        lemma lemma_ApplyStoreBufferCommutesWithConvert(lmem:L.Armada_SharedMemory, lbuf:seq<L.Armada_StoreBufferEntry>,\n                                                        hbuf:seq<H.Armada_StoreBufferEntry>, hmem1:H.Armada_SharedMemory,\n                                                        hmem2:H.Armada_SharedMemory)\n          requires hbuf == ConvertStoreBuffer_LH(lbuf)\n          requires hmem1 == ConvertSharedMemory_LH(L.Armada_ApplyStoreBuffer(lmem, lbuf))\n          requires hmem2 == H.Armada_ApplyStoreBuffer(ConvertSharedMemory_LH(lmem), hbuf)\n          ensures  hmem1 == hmem2\n          decreases |lbuf| + |hbuf|\n        {\n          if |lbuf| == 0 {\n              return;\n          }\n\n          var lmem' := L.Armada_ApplyStoreBufferEntry(lmem, lbuf[0]);\n\n          if CanConvertStoreBufferEntry_LH(lbuf[0]) {\n              var hmem1' := ConvertSharedMemory_LH(L.Armada_ApplyStoreBufferEntry(lmem, lbuf[0]));\n              var hmem2' := H.Armada_ApplyStoreBufferEntry(ConvertSharedMemory_LH(lmem), hbuf[0]);\n              lemma_ApplyStoreBufferEntryCommutesWithConvert(lmem, lbuf[0], hbuf[0], hmem1', hmem2');\n              lemma_ApplyStoreBufferCommutesWithConvert(lmem', lbuf[1..], hbuf[1..], hmem1, hmem2);\n          }\n          else {\n              lemma_ApplyingUnconvertibleStoreBufferEntryDoesntChangeHState(lmem, lbuf[0]);\n              assert ConvertSharedMemory_LH(lmem') == ConvertSharedMemory_LH(lmem);\n              assert hbuf == ConvertStoreBuffer_LH(lbuf[1..]);\n              lemma_ApplyStoreBufferCommutesWithConvert(lmem', lbuf[1..], hbuf, hmem1, hmem2);\n          }\n        }\n      \";\n      pgp.AddLemma(str, \"utility\");\n\n      str = @\"\n        lemma lemma_GetThreadLocalViewCommutesWithConvert(ls:LState, hs:HState, tid:Armada_ThreadHandle)\n          requires hs == ConvertTotalState_LH(ls)\n          requires tid in ls.threads;\n          ensures  ConvertSharedMemory_LH(L.Armada_GetThreadLocalView(ls, tid)) == H.Armada_GetThreadLocalView(hs, tid)\n        {\n          assert tid in hs.threads;\n          lemma_ApplyStoreBufferCommutesWithConvert(ls.mem, ls.threads[tid].storeBuffer,\n                                                    hs.threads[tid].storeBuffer,\n                                                    ConvertSharedMemory_LH(L.Armada_GetThreadLocalView(ls, tid)),\n                                                    H.Armada_GetThreadLocalView(hs, tid));\n        }\n      \";\n      pgp.AddLemma(str, \"utility\");\n\n      str = @\"\n        lemma lemma_GetThreadLocalViewAlwaysCommutesWithConvert()\n          ensures forall ls:L.Armada_TotalState, tid:Armada_ThreadHandle\n                    {:trigger L.Armada_GetThreadLocalView(ls, tid)}\n                    :: tid in ls.threads ==>\n                    ConvertSharedMemory_LH(L.Armada_GetThreadLocalView(ls, tid)) ==\n                    H.Armada_GetThreadLocalView(ConvertTotalState_LH(ls), tid)\n        {\n          forall ls:L.Armada_TotalState, tid:Armada_ThreadHandle {:trigger L.Armada_GetThreadLocalView(ls, tid)}\n            | tid in ls.threads\n            ensures ConvertSharedMemory_LH(L.Armada_GetThreadLocalView(ls, tid)) ==\n                    H.Armada_GetThreadLocalView(ConvertTotalState_LH(ls), tid)\n          {\n              var hs := ConvertTotalState_LH(ls);\n              lemma_GetThreadLocalViewCommutesWithConvert(ls, hs, tid);\n          }\n        }\n      \";\n      pgp.AddLemma(str, \"utility\");\n\n      str = @\"\n        lemma lemma_StoreBufferAppendConversion(buf: seq<L.Armada_StoreBufferEntry>, entry: L.Armada_StoreBufferEntry)\n          ensures  ConvertStoreBuffer_LH(buf + [entry]) ==\n                     if CanConvertStoreBufferEntry_LH(entry) then\n                       ConvertStoreBuffer_LH(buf) + [ConvertStoreBufferEntry_LH(entry)]\n                     else\n                       ConvertStoreBuffer_LH(buf)\n        {\n          assert [entry][1..] == [];\n\n          if |buf| == 0 {\n            assert buf + [entry] == [entry];\n            assert ConvertStoreBuffer_LH(buf + [entry]) == ConvertStoreBuffer_LH([entry]);\n            assert ConvertStoreBuffer_LH(buf) == [];\n\n            if CanConvertStoreBufferEntry_LH(entry) {\n              calc {\n                ConvertStoreBuffer_LH([entry]);\n                [ConvertStoreBufferEntry_LH(entry)] + ConvertStoreBuffer_LH([entry][1..]);\n                [ConvertStoreBufferEntry_LH(entry)] + ConvertStoreBuffer_LH([]);\n                [ConvertStoreBufferEntry_LH(entry)] + [];\n                [ConvertStoreBufferEntry_LH(entry)];\n              }\n            }\n            else {\n              calc {\n                ConvertStoreBuffer_LH([entry]);\n                ConvertStoreBuffer_LH([entry][1..]);\n                ConvertStoreBuffer_LH([]);\n                [];\n              }\n            }\n          }\n          else {\n            calc {\n              ConvertStoreBuffer_LH(buf + [entry]);\n              {\n                assert buf == [buf[0]] + buf[1..];\n              }\n              ConvertStoreBuffer_LH([buf[0]] + buf[1..] + [entry]);\n              {\n                assert [buf[0]] + buf[1..] + [entry] == [buf[0]] + (buf[1..] + [entry]);\n              }\n              ConvertStoreBuffer_LH([buf[0]] + (buf[1..] + [entry]));\n            }\n            if CanConvertStoreBufferEntry_LH(buf[0]) {\n              calc {\n                ConvertStoreBuffer_LH(buf + [entry]);\n                ConvertStoreBuffer_LH([buf[0]] + (buf[1..] + [entry]));\n                [ConvertStoreBufferEntry_LH(buf[0])] + ConvertStoreBuffer_LH(buf[1..] + [entry]);\n              }\n              lemma_StoreBufferAppendConversion(buf[1..], entry);\n              if CanConvertStoreBufferEntry_LH(entry) {\n                calc {\n                  ConvertStoreBuffer_LH(buf + [entry]);\n                  [ConvertStoreBufferEntry_LH(buf[0])] + (ConvertStoreBuffer_LH(buf[1..]) + [ConvertStoreBufferEntry_LH(entry)]);\n                  [ConvertStoreBufferEntry_LH(buf[0])] + ConvertStoreBuffer_LH(buf[1..]) + [ConvertStoreBufferEntry_LH(entry)];\n                  ConvertStoreBuffer_LH(buf) + [ConvertStoreBufferEntry_LH(entry)];\n                }\n              }\n              else {\n                calc {\n                  ConvertStoreBuffer_LH(buf + [entry]);\n                  [ConvertStoreBufferEntry_LH(buf[0])] + ConvertStoreBuffer_LH(buf[1..]);\n                  ConvertStoreBuffer_LH(buf);\n                }\n              }\n            }\n            else {\n              assert ConvertStoreBuffer_LH(buf) == ConvertStoreBuffer_LH(buf[1..]);\n              calc {\n                ConvertStoreBuffer_LH(buf + [entry]);\n                ConvertStoreBuffer_LH([buf[0]] + (buf[1..] + [entry]));\n                ConvertStoreBuffer_LH((buf[1..] + [entry]));\n              }\n              lemma_StoreBufferAppendConversion(buf[1..], entry);\n              if CanConvertStoreBufferEntry_LH(entry) {\n                calc {\n                  ConvertStoreBuffer_LH(buf + [entry]);\n                  ConvertStoreBuffer_LH(buf[1..]) + [ConvertStoreBufferEntry_LH(entry)];\n                  ConvertStoreBuffer_LH(buf) + [ConvertStoreBufferEntry_LH(entry)];\n                }\n              }\n              else {\n                calc {\n                  ConvertStoreBuffer_LH(buf + [entry]);\n                  ConvertStoreBuffer_LH(buf[1..]);\n                  ConvertStoreBuffer_LH(buf);\n                }\n              }\n            }\n          }\n        }\n      \";\n      pgp.AddLemma(str, \"utility\");\n\n      str = @\"\n        lemma lemma_StoreBufferAppendAlwaysCommutesWithConvert()\n          ensures forall lbuf: seq<L.Armada_StoreBufferEntry>, lentry: L.Armada_StoreBufferEntry\n                    {:trigger L.Armada_StoreBufferAppend(lbuf, lentry)} ::\n                    CanConvertStoreBufferEntry_LH(lentry) ==>\n                    H.Armada_StoreBufferAppend(ConvertStoreBuffer_LH(lbuf), ConvertStoreBufferEntry_LH(lentry)) ==\n                    ConvertStoreBuffer_LH(L.Armada_StoreBufferAppend(lbuf, lentry))\n        {\n          forall lbuf: seq<L.Armada_StoreBufferEntry>, lentry: L.Armada_StoreBufferEntry\n            {:trigger L.Armada_StoreBufferAppend(lbuf, lentry)}\n            | CanConvertStoreBufferEntry_LH(lentry)\n            ensures H.Armada_StoreBufferAppend(ConvertStoreBuffer_LH(lbuf), ConvertStoreBufferEntry_LH(lentry)) ==\n                    ConvertStoreBuffer_LH(L.Armada_StoreBufferAppend(lbuf, lentry))\n          {\n            lemma_StoreBufferAppendConversion(lbuf, lentry);\n          }\n        }\n      \";\n      pgp.AddLemma(str, \"utility\");\n\n      str = @\"\n        lemma lemma_ConvertStoreBufferCommutesOverBeheadment(buf:seq<L.Armada_StoreBufferEntry>)\n          requires |buf| > 0\n          requires CanConvertStoreBufferEntry_LH(buf[0])\n          ensures  ConvertStoreBuffer_LH(buf[1..]) == ConvertStoreBuffer_LH(buf)[1..]\n        {\n          var hbuf1 := ConvertStoreBuffer_LH(buf[1..]);\n          var hbuf2 := ConvertStoreBuffer_LH(buf)[1..];\n          assert |hbuf1| == |hbuf2|;\n\n          forall i | 0 <= i < |buf| - 1\n            ensures hbuf1[i] == hbuf2[i]\n          {\n          }\n\n          assert hbuf1 == hbuf2;\n        }\n      \";\n      pgp.AddLemma(str, \"utility\");\n\n      str = @\"\n        lemma lemma_AppendingHiddenStoreBufferEntryAlwaysDoesntAffectHighLevel(tid:Armada_ThreadHandle)\n          ensures forall s:L.Armada_TotalState, entry:L.Armada_StoreBufferEntry\n            {:trigger L.Armada_AppendToThreadStoreBuffer(s, tid, entry)} ::\n            tid in s.threads && !CanConvertStoreBufferEntry_LH(entry) ==>\n            ConvertTotalState_LH(L.Armada_AppendToThreadStoreBuffer(s, tid, entry)) == ConvertTotalState_LH(s)\n        {\n          forall s:L.Armada_TotalState, entry:L.Armada_StoreBufferEntry {:trigger L.Armada_AppendToThreadStoreBuffer(s, tid, entry)} |\n            tid in s.threads && !CanConvertStoreBufferEntry_LH(entry)\n            ensures ConvertTotalState_LH(L.Armada_AppendToThreadStoreBuffer(s, tid, entry)) == ConvertTotalState_LH(s)\n          {\n            var hs := ConvertTotalState_LH(s);\n            var hs' := ConvertTotalState_LH(L.Armada_AppendToThreadStoreBuffer(s, tid, entry));\n            lemma_StoreBufferAppendConversion(s.threads[tid].storeBuffer, entry);\n            assert hs.threads[tid].storeBuffer == hs'.threads[tid].storeBuffer;\n            assert hs.threads == hs'.threads;\n            assert hs == hs';\n          }\n        }\n      \";\n      pgp.AddLemma(str, \"utility\");\n    }\n  }\n}\n"
  },
  {
    "path": "Source/Armada/GlobalVarIntro.cs",
    "content": "using System.Collections.Generic;\nusing System.Linq;\nusing System;\n\nnamespace Microsoft.Armada\n{\n  public class GlobalVarIntroProofGenerator : VarIntroProofGenerator\n  {\n    private GlobalVariableIntroStrategyDecl strategy;\n    private HashSet<string> introducedVariables;\n\n    public GlobalVarIntroProofGenerator(ProofGenerationParams i_pgp, GlobalVariableIntroStrategyDecl i_strategy)\n      : base(i_pgp, true /* can introduce tau */)\n    {\n      strategy = i_strategy;\n      introducedVariables = new HashSet<string>();\n      foreach (var tok in strategy.Variables) {\n        introducedVariables.Add(tok.val);\n      }\n      if (introducedVariables.All(varName => pgp.symbolsHigh.Globals.Lookup(varName).varType == ArmadaVarType.Ghost)) {\n        canIntroduceTau = false;\n      }\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    // Equivalence checking\n    ////////////////////////////////////////////////////////////////////////\n\n    // We have to override the default implementation of CheckGlobalsEquivalence because we need to\n    // skip introduced variables.\n\n    protected override bool CheckGlobalsEquivalence()\n    {\n      var globalVarsLow = pgp.symbolsLow.Globals.VariableNames.ToArray();\n      var globalVarsHigh = pgp.symbolsHigh.Globals.VariableNames.Where(s => !introducedVariables.Contains(s)).ToArray();\n\n      if (globalVarsLow.Length != globalVarsHigh.Length) {\n        AH.PrintError(pgp.prog, $\"There are {globalVarsLow.Length} global variables in level {pgp.mLow.Name} (not counting hidden ones) but {globalVarsHigh.Length} in level {pgp.mHigh.Name}\");\n        return false;\n      }\n\n      for (int i = 0; i < globalVarsLow.Length; ++i) {\n        if (globalVarsLow[i] != globalVarsHigh[i]) {\n          AH.PrintError(pgp.prog, $\"Global variable number {i+1} (not counting hidden ones) in level {pgp.mLow.Name} is {globalVarsLow[i]}, which do<esn't match global variable number {i+1} in level {pgp.mHigh.Name} which is {globalVarsHigh[i]}\");\n          return false;\n        }\n        var name = globalVarsLow[i];\n        if (!CheckGlobalVariableEquivalence(name, pgp.symbolsLow.Globals.Lookup(name), pgp.symbolsHigh.Globals.Lookup(name))) {\n          return false;\n        }\n      }\n\n      return true;\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    // PC mapping\n    ////////////////////////////////////////////////////////////////////////\n\n    protected override bool IsIntroducedVariable(string methodName, string varName)\n    {\n      if (varName == null) {\n        return false;\n      }\n      if (!introducedVariables.Contains(varName)) {\n        return false;\n      }\n\n      // If it has the same name as an introduced global varible, make sure\n      // it isn't shadowed by a local variable in this method.\n\n      var st = pgp.symbolsHigh.GetMethodSymbolTable(methodName);\n      return st.LookupVariable(varName) == null;\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    // Abstraction\n    ////////////////////////////////////////////////////////////////////////\n\n    protected override void GenerateConvertGlobals_HL()\n    {\n      var ps = new List<string>();\n      foreach (var varName in pgp.symbolsHigh.Globals.VariableNames) {\n        if (introducedVariables.Contains(varName)) {\n          continue;\n        }\n        var v = pgp.symbolsHigh.Globals.Lookup(varName);\n        if (v is GlobalUnaddressableArmadaVariable) {\n          ps.Add($\"globals.{v.FieldName}\");\n        }\n      }\n      var fn = $@\"\n        function ConvertGlobals_HL(globals: H.Armada_Globals) : L.Armada_Globals\n        {{\n          L.Armada_Globals({AH.CombineStringsWithCommas(ps)})\n        }}\n      \";\n      pgp.AddFunction(fn, \"convert\");\n    }\n\n    protected override void GenerateConvertGlobalStaticVar_HL()\n    {\n      if (!canIntroduceTau) {\n        base.GenerateConvertGlobalStaticVar_HL();\n        return;\n      }\n\n      var es = new List<string>();\n      foreach (var varName in introducedVariables) {\n        var gv = pgp.symbolsHigh.Globals.Lookup(varName);\n        if (gv is GlobalUnaddressableArmadaVariable) {\n          es.Add($\"!v.Armada_GlobalStaticVar_{varName}?\");\n        }\n      }\n      var fn = $@\"\n        predicate CanConvertGlobalStaticVar_HL(v: H.Armada_GlobalStaticVar)\n        {{\n          {AH.CombineStringsWithAnd(es)}\n        }}\n      \";\n      pgp.AddPredicate(fn, \"convert\");\n\n      var caseBodies = \"case Armada_GlobalStaticVarNone => L.Armada_GlobalStaticVarNone\\n\";\n      foreach (var varName in pgp.symbolsHigh.Globals.VariableNames) {\n        if (introducedVariables.Contains(varName)) {\n          continue;\n        }\n        var gv = pgp.symbolsHigh.Globals.Lookup(varName);\n        if (gv is GlobalUnaddressableArmadaVariable) {\n          caseBodies += $\"case Armada_GlobalStaticVar_{varName} => L.Armada_GlobalStaticVar_{varName}\\n\";\n        }\n      }\n      fn = $@\"\n        function ConvertGlobalStaticVar_HL(v: H.Armada_GlobalStaticVar) : L.Armada_GlobalStaticVar\n          requires CanConvertGlobalStaticVar_HL(v)\n        {{\n          match v\n            {caseBodies}\n        }}\n      \";\n      pgp.AddFunction(fn, \"convert\");\n    }\n\n    protected override void GenerateConvertGhosts_HL()\n    {\n      var ps = new List<string>();\n      foreach (var varName in pgp.symbolsHigh.Globals.VariableNames) {\n        if (introducedVariables.Contains(varName)) {\n          continue;\n        }\n        var v = pgp.symbolsHigh.Globals.Lookup(varName);\n        if (v is GlobalGhostArmadaVariable) {\n          ps.Add($\"ghosts.{v.FieldName}\");\n        }\n      }\n      var fn = $@\"\n        function ConvertGhosts_HL(ghosts: H.Armada_Ghosts) : L.Armada_Ghosts\n        {{\n          L.Armada_Ghosts({AH.CombineStringsWithCommas(ps)})\n        }}\n      \";\n      pgp.AddFunction(fn, \"convert\");\n    }\n\n    protected override void GenerateConvertStoreBufferEntry_HL()\n    {\n      if (!canIntroduceTau) {\n        base.GenerateConvertStoreBufferEntry_HL();\n        return;\n      }\n      \n      string str;\n\n      str = @\"\n        predicate CanConvertStoreBufferEntry_HL(entry:H.Armada_StoreBufferEntry)\n        {\n          CanConvertStoreBufferLocation_HL(entry.loc)\n        }\n      \";\n      pgp.AddPredicate(str, \"convert\");\n\n      str = @\"\n        function ConvertStoreBufferEntry_HL(entry:H.Armada_StoreBufferEntry) : L.Armada_StoreBufferEntry\n          requires CanConvertStoreBufferEntry_HL(entry)\n        {\n          L.Armada_StoreBufferEntry(ConvertStoreBufferLocation_HL(entry.loc), entry.value, ConvertPC_HL(entry.pc))\n        }\n      \";\n      pgp.AddFunction(str, \"convert\");\n    }\n\n    protected override void GenerateConvertStoreBuffer_HL()\n    {\n      if (!canIntroduceTau) {\n        base.GenerateConvertStoreBuffer_HL();\n        return;\n      }\n\n      string str = @\"\n        function ConvertStoreBufferEntryTotal_HL(entry: H.Armada_StoreBufferEntry): Option<L.Armada_StoreBufferEntry> {\n          if CanConvertStoreBufferEntry_HL(entry) then\n            Some(ConvertStoreBufferEntry_HL(entry))\n          else\n            None\n        }\n      \";\n\n      pgp.AddFunction(str, \"convert\");\n\n      str = @\"\n        function ConvertStoreBuffer_HL(entries:seq<H.Armada_StoreBufferEntry>) : seq<L.Armada_StoreBufferEntry>\n        {\n          FilterMapSeqToSeq(entries, ConvertStoreBufferEntryTotal_HL)\n        }\n      \";\n      pgp.AddFunction(str, \"convert\");\n    }\n\n    protected override void GenerateConvertStoreBufferLocation_HL()\n    {\n      if (!canIntroduceTau) {\n        base.GenerateConvertStoreBufferLocation_HL();\n        return;\n      }\n\n      string str;\n\n      str = @\"\n        predicate CanConvertStoreBufferLocation_HL(loc:H.Armada_StoreBufferLocation)\n        {\n          loc.Armada_StoreBufferLocation_Unaddressable? ==> CanConvertGlobalStaticVar_HL(loc.v)\n        }\n      \";\n      pgp.AddPredicate(str, \"convert\");\n\n      str = @\"\n        function ConvertStoreBufferLocation_HL(loc:H.Armada_StoreBufferLocation) : L.Armada_StoreBufferLocation\n          requires CanConvertStoreBufferLocation_HL(loc)\n        {\n          match loc\n            case Armada_StoreBufferLocation_Unaddressable(v, fields) =>\n              L.Armada_StoreBufferLocation_Unaddressable(ConvertGlobalStaticVar_HL(v), fields)\n            case Armada_StoreBufferLocation_Addressable(p) =>\n              L.Armada_StoreBufferLocation_Addressable(p)\n        }\n      \";\n      pgp.AddFunction(str, \"convert\");\n    }\n\n    // TODO (Luke): more cases\n    protected string ResolveInit(Expression expr)\n    {\n      return Printer.ExprToString(expr);\n    }\n\n    protected override void GenerateConvertGlobals_LH()\n    {\n      var ps = new List<string>();\n      foreach (var varName in pgp.symbolsHigh.Globals.VariableNames) {\n        var v = pgp.symbolsLow.Globals.Lookup(varName);\n        if (v == null) {\n          v = pgp.symbolsHigh.Globals.Lookup(varName);\n          if (v is GlobalUnaddressableArmadaVariable global) {\n            var p = ResolveInit(global.initialValue);\n            if (p == null) {\n              AH.PrintError(pgp.prog, $\"Introduced global variable {varName} must be initialized\");\n            }\n            ps.Add(p);\n          }\n        }\n        else if (v is GlobalUnaddressableArmadaVariable) {\n          ps.Add($\"globals.{v.FieldName}\");\n        }\n      }\n      var fn = $@\"\n        function ConvertGlobals_LH(globals: L.Armada_Globals) : H.Armada_Globals\n        {{\n          H.Armada_Globals({AH.CombineStringsWithCommas(ps)})\n        }}\n      \";\n      pgp.AddFunction(fn, \"convert\");\n    }\n\n    protected override void GenerateConvertGhosts_LH()\n    {\n      var ps = new List<string>();\n      foreach (var varName in pgp.symbolsHigh.Globals.VariableNames) {\n        var v = pgp.symbolsLow.Globals.Lookup(varName);\n        if (v == null) {\n          v = pgp.symbolsHigh.Globals.Lookup(varName);\n          if (v is GlobalGhostArmadaVariable ghost) {\n            var p = ResolveInit(ghost.initialValue);\n            if (p == null) {\n              AH.PrintError(pgp.prog, $\"Introduced ghost variable {varName} must be initialized\");\n            }\n            ps.Add(p);\n          }\n        }\n        else if (v is GlobalGhostArmadaVariable) {\n          ps.Add($\"ghosts.{v.FieldName}\");\n        }\n      }\n      var fn = $@\"\n        function ConvertGhosts_LH(ghosts: L.Armada_Ghosts) : H.Armada_Ghosts\n        {{\n          H.Armada_Ghosts({AH.CombineStringsWithCommas(ps)})\n        }}\n      \";\n      pgp.AddFunction(fn, \"convert\");\n    }\n\n  }\n};\n"
  },
  {
    "path": "Source/Armada/NextRoutine.cs",
    "content": "using System;\nusing System.Numerics;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text;\nusing static Microsoft.Armada.Predicate;\nusing IToken = Microsoft.Boogie.IToken;\nusing Token = Microsoft.Boogie.Token;\n\nnamespace Microsoft.Armada {\n\n  public class NextFormal {\n    public readonly string GloballyUniqueVarName;\n    public readonly string LocalVarName;\n    public readonly string VarType;\n\n    public NextFormal(string globallyUniqueVarName, string localVarName, Type varType, ArmadaSymbolTable symbols)\n    {\n      GloballyUniqueVarName = globallyUniqueVarName;\n      LocalVarName = localVarName;\n      VarType = symbols.FlattenType(varType).ToString();\n    }\n\n    public NextFormal(string globallyUniqueVarName, string localVarName, string varTypeName)\n    {\n      GloballyUniqueVarName = globallyUniqueVarName;\n      LocalVarName = localVarName;\n      VarType = varTypeName;\n    }\n  }\n\n  public enum NextType { Update, Call, Return, CreateThread, MallocSuccess, MallocFailure, CallocSuccess, CallocFailure, Dealloc,\n                         IfTrue, IfFalse, JumpPastElse, WhileTrue, WhileFalse, WhileEnd, WhileBreak, WhileContinue,\n                         AssertTrue, AssertFalse, Somehow, Fence, Goto, CompareAndSwap, AtomicExchange, Join,\n                         ExternStart, ExternContinue, ExternEnd, TerminateThread, TerminateProcess, Tau }\n\n  public class NextRoutineConstructor : IConstraintCollector {\n    private Program prog;\n    private ArmadaSymbolTable symbols;\n    private PredicateBuilder validDefinedStepBuilder;\n    private PredicateBuilder validUndefinedStepBuilder;\n    private ExpressionBuilder getNextStateBuilder;\n    private ArmadaPC startPC;\n    private ArmadaPC endPC;\n    private List<NextFormal> formals;\n    private bool valid;\n    private bool hasUndefinedBehaviorAvoidanceConstraint;\n    private NextType nextType;\n    private MethodInfo methodInfo;\n    private ArmadaStatement armadaStatement;\n    private Statement stmt;\n    private NextRoutine definedBehaviorNextRoutine;\n    private NextRoutine undefinedBehaviorNextRoutine;\n\n    public string s;\n    public string entry;\n    public string tid;\n    public string t;\n    public string locv;\n    public Method method;\n\n    public NextRoutineConstructor(Program i_prog, ArmadaSymbolTable i_symbols, NextType i_nextType, MethodInfo i_methodInfo,\n                                  ArmadaStatement i_armadaStatement, Statement i_stmt, ArmadaPC i_startPC, ArmadaPC i_endPC)\n    {\n      prog = i_prog;\n      symbols = i_symbols;\n      nextType = i_nextType;\n      validDefinedStepBuilder = new PredicateBuilder(i_prog, true);\n      validUndefinedStepBuilder = new PredicateBuilder(i_prog, false);\n      getNextStateBuilder = new ExpressionBuilder(i_prog);\n      methodInfo = i_methodInfo;\n      method = methodInfo == null ? null : methodInfo.method;\n      armadaStatement = i_armadaStatement;\n      stmt = i_stmt;\n      startPC = i_startPC;\n      endPC = i_endPC;\n      formals = new List<NextFormal>();\n      valid = true;\n      hasUndefinedBehaviorAvoidanceConstraint = false;\n      definedBehaviorNextRoutine = null;\n      undefinedBehaviorNextRoutine = null;\n\n      s = ReserveVariableName(\"s\");\n      entry = ReserveVariableName(\"entry\");\n      tid = ReserveVariableName(\"tid\");\n      t = ReserveVariableName(\"t\");\n      locv = ReserveVariableName(\"locv\");\n\n      if (startPC != null) {\n        AddConjunct($\"{t}.pc.{startPC}?\");\n        AddConjunct($\"{t}.top.Armada_StackFrame_{startPC.methodName}?\");\n\n        if (methodInfo != null) {\n          var constraints = methodInfo.GetEnablingConstraintCollector(startPC);\n          if (constraints != null && !constraints.Empty) {\n            AddConjunct($\"Armada_EnablingConditions_{startPC}(s, tid)\");\n          }\n        }\n\n        AddConjunct(\"Armada_UniversalStepConstraint(s, tid)\");\n      }\n    }\n\n    public string AddFormal(NextFormal formal)\n    {\n      formals.Add(formal);\n      return formal.LocalVarName;\n    }\n    \n    public IEnumerable<NextFormal> Formals { get { return formals; } }\n    public NextRoutine DefinedBehaviorNextRoutine { get { return definedBehaviorNextRoutine; } }\n    public NextRoutine UndefinedBehaviorNextRoutine { get { return undefinedBehaviorNextRoutine; } }\n\n    private string MakeNameSuffix()\n    {\n      switch (nextType) {\n        case NextType.Tau:\n          return \"Tau\";\n        case NextType.Return:\n          return \"ReturnFrom_\" + startPC.methodName + \"_\" + startPC.Name + \"_To_\" + endPC.methodName + \"_\" + endPC.Name;\n        default:\n          return nextType.ToString(\"g\") + \"_\" + startPC.methodName + \"_\" + startPC.Name;\n      }\n    }\n\n    public bool Valid { get { return valid; } }\n\n    public string ReserveVariableName(string varName)\n    {\n      validDefinedStepBuilder.ReserveVariableName(varName);\n      validUndefinedStepBuilder.ReserveVariableName(varName);\n      return getNextStateBuilder.ReserveVariableName(varName);\n    }\n\n    public string AddVariableDeclaration(string varName, string value)\n    {\n      validDefinedStepBuilder.AddVariableDeclaration(varName, value);\n      validUndefinedStepBuilder.AddVariableDeclaration(varName, value);\n      return getNextStateBuilder.AddVariableDeclaration(varName, value);\n    }\n\n    public void AddUndefinedBehaviorAvoidanceConstraint(string constraint)\n    {\n      hasUndefinedBehaviorAvoidanceConstraint = true;\n      validDefinedStepBuilder.AddConjunct(constraint);\n      validUndefinedStepBuilder.AddDisjunct($\"!({constraint})\");\n    }\n\n    public void AddUndefinedBehaviorAvoidanceConstraint(UndefinedBehaviorAvoidanceConstraint constraint)\n    {\n      foreach (var e in constraint.AsList)\n      {\n        AddUndefinedBehaviorAvoidanceConstraint(e);\n      }\n    }\n\n    public void AddConjunct(string conjunct)\n    {\n      validDefinedStepBuilder.AddConjunct(conjunct);\n      validUndefinedStepBuilder.AddConjunct(conjunct);\n    }\n\n    public void AddUBAvoidanceConstraintAsConjunct(UndefinedBehaviorAvoidanceConstraint constraint)\n    {\n      foreach (var e in constraint.AsList) {\n        validDefinedStepBuilder.AddConjunct(e);\n        validUndefinedStepBuilder.AddConjunct(e);\n      }\n    }\n\n    public void AddDefinedBehaviorConjunct(string conjunct)\n    {\n      validDefinedStepBuilder.AddConjunct(conjunct);\n    }\n\n    public void AddUBAvoidanceConstraintAsDefinedBehaviorConjunct(UndefinedBehaviorAvoidanceConstraint constraint)\n    {\n      foreach (var e in constraint.AsList) {\n        validDefinedStepBuilder.AddConjunct(e);\n      }\n    }\n\n    public void SetNextState(string e)\n    {\n      getNextStateBuilder.SetBody(e);\n    }\n\n    public void Fail(IToken tok, string reason) {\n      valid = false;\n      if (reason != null) {\n        AH.PrintError(prog, tok, reason);\n      }\n    }\n\n    public void Fail(string reason) {\n      Fail(Token.NoToken, reason);\n    }\n\n    private void ExtractInternal(ArmadaSymbolTable symbols, DeclCollector declCollector, List<string> stepCtors, bool ub)\n    {\n      var nameSuffix = MakeNameSuffix();\n      if (ub) {\n        nameSuffix = \"UB_\" + nameSuffix;\n      }\n\n      if (formals.Any()) {\n        var paramsFormalsList = String.Join(\", \", formals.Select(f => $\"{f.LocalVarName}: {f.VarType}\"));\n        var paramsTypeDecl = $\"datatype Armada_StepParams_{nameSuffix} = Armada_StepParams_{nameSuffix}({paramsFormalsList})\";\n        declCollector.AddItem(paramsTypeDecl);\n      }\n\n      stepCtors.Add($\"Armada_Step_{nameSuffix}(\"\n                    + (formals.Any() ? $\"params_{nameSuffix}: Armada_StepParams_{nameSuffix}\" : \"\")\n                    + \")\");\n      \n      var extraParameterDecls = formals.Any() ? $\", params: Armada_StepParams_{nameSuffix}\" : \"\";\n      var extraParameterArgs = formals.Any() ? $\", params\" : \"\";\n      var paramDecls = String.Concat(formals.Select(f => $\"var {f.LocalVarName} := params.{f.LocalVarName};\\n\"));\n      var validState = ub ? validUndefinedStepBuilder.Extract() : validDefinedStepBuilder.Extract();\n      var nextState = ub ? $\"s.(stop_reason := Armada_StopReasonUndefinedBehavior)\" : $\"{paramDecls}{getNextStateBuilder.Extract()}\";\n\n      declCollector.AddItem($@\"\n        predicate Armada_ValidStep_{nameSuffix}(s: Armada_TotalState, tid: Armada_ThreadHandle{extraParameterDecls})\n          requires tid in s.threads\n        {{\n          var t := s.threads[tid];\n          var locv := Armada_GetThreadLocalView(s, tid);\n          {paramDecls}\n          {validState}\n        }}\n      \");\n\n      declCollector.AddItem($@\"\n        function Armada_GetNextState_{nameSuffix}(s: Armada_TotalState, tid: Armada_ThreadHandle{extraParameterDecls})\n          : Armada_TotalState\n          requires tid in s.threads\n          requires Armada_ValidStep_{nameSuffix}(s, tid{extraParameterArgs})\n        {{\n          var t := s.threads[tid];\n          var locv := Armada_GetThreadLocalView(s, tid);\n          {nextState}\n        }}\n      \");\n\n      var stopping = (nextType == NextType.TerminateProcess || nextType == NextType.AssertFalse || ub);\n      var nextRoutine = new NextRoutine(prog, symbols, nextType, methodInfo, armadaStatement, stmt, startPC, endPC,\n                                        formals, nameSuffix, ub, stopping);\n      symbols.AddNextRoutine(nextRoutine);\n      if (ub) {\n        undefinedBehaviorNextRoutine = nextRoutine;\n      }\n      else {\n        definedBehaviorNextRoutine = nextRoutine;\n      }\n    }\n\n    public void Extract(ArmadaSymbolTable symbols, DeclCollector declCollector, List<string> stepCtors)\n    {\n      if (!valid) {\n        return;\n      }\n\n      ExtractInternal(symbols, declCollector, stepCtors, false);\n      if (hasUndefinedBehaviorAvoidanceConstraint) {\n        ExtractInternal(symbols, declCollector, stepCtors, true);\n      }\n    }\n\n    public bool Nonyielding { get { return symbols.IsNonyieldingPC(endPC); } }\n  }\n\n  public class NextRoutine {\n    private Program prog;\n    private ArmadaSymbolTable symbols;\n\n    public NextType nextType;\n    public MethodInfo methodInfo;\n    public ArmadaStatement armadaStatement;\n    public Statement stmt;\n    public ArmadaPC startPC;\n    public ArmadaPC endPC;\n    private List<NextFormal> formals;\n    public string nameSuffix;\n\n    private bool undefinedBehavior;\n    private bool stopping;\n\n    public NextRoutine(Program i_prog, ArmadaSymbolTable i_symbols, NextType i_nextType, MethodInfo i_methodInfo,\n                       ArmadaStatement i_armadaStatement, Statement i_stmt, ArmadaPC i_startPC, ArmadaPC i_endPC,\n                       List<NextFormal> i_formals, string i_nameSuffix, bool i_undefinedBehavior, bool i_stopping)\n    {\n      prog = i_prog;\n      symbols = i_symbols;\n      nextType = i_nextType;\n      methodInfo = i_methodInfo;\n      armadaStatement = i_armadaStatement;\n      stmt = i_stmt;\n      startPC = i_startPC;\n      endPC = i_endPC;\n      formals = new List<NextFormal>(i_formals);\n      nameSuffix = i_nameSuffix;\n      undefinedBehavior = i_undefinedBehavior;\n      stopping = i_stopping;\n    }\n\n    public IEnumerable<NextFormal> Formals { get { return formals; } }\n    public bool HasFormals { get { return formals.Any(); } }\n    public string NameSuffix { get { return nameSuffix; } }\n    public bool Tau { get { return nextType == NextType.Tau; } }\n    public Method method { get { return methodInfo.method; } }\n\n    public bool Nonyielding { get { return symbols.IsNonyieldingPC(endPC); } }\n    public bool UndefinedBehavior { get { return undefinedBehavior; } }\n    public bool Stopping { get { return stopping; } }\n\n    public bool TryGetBranchOutcome(out bool outcome)\n    {\n      outcome = BranchOutcome;\n      return nextType == NextType.IfTrue ||\n             nextType == NextType.WhileTrue ||\n             nextType == NextType.AssertTrue ||\n             nextType == NextType.IfFalse ||\n             nextType == NextType.WhileFalse ||\n             nextType == NextType.AssertFalse ||\n             nextType == NextType.MallocSuccess ||\n             nextType == NextType.MallocFailure ||\n             nextType == NextType.CallocSuccess ||\n             nextType == NextType.CallocFailure;\n    }\n\n    public bool BranchOutcome\n    {\n      get {\n        return nextType != NextType.IfFalse &&\n               nextType != NextType.WhileFalse &&\n               nextType != NextType.AssertFalse &&\n               nextType != NextType.MallocFailure &&\n               nextType != NextType.CallocFailure;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "Source/Armada/PathPrinter.cs",
    "content": "using System;\nusing System.Numerics;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text;\nusing static Microsoft.Armada.Predicate;\nusing IToken = Microsoft.Boogie.IToken;\nusing Token = Microsoft.Boogie.Token;\n\nnamespace Microsoft.Armada\n{\n  public class PathPrinter\n  {\n    protected string state;\n    protected string nextState;\n    protected string tid;\n    protected string steps;\n    protected string states;\n    protected string step;\n    protected string path;\n    protected string paramsParam;\n    protected AtomicSpec atomicSpec;\n\n    public PathPrinter(AtomicSpec i_atomicSpec)\n    {\n      state = \"s\";\n      nextState = \"s'\";\n      tid = \"tid\";\n      steps = \"steps\";\n      states = \"states\";\n      step = \"step\";\n      path = \"path\";\n      paramsParam = \"params\";\n      atomicSpec = i_atomicSpec;\n    }\n\n    public virtual string State { get { return state; } set { state = value; } }\n    public virtual string NextState { get { return nextState; } set { nextState = value; } }\n    public virtual string Tid { get { return tid; } set { tid = value; } }\n    public virtual string Steps { get { return steps; } set { steps = value; } }\n    public virtual string States { get { return states; } set { states = value; } }\n    public virtual string Step { get { return step; } set { step = value; } }\n    public virtual string Path { get { return path; } set { path = value; } }\n    public virtual string ParamsParam { get { return paramsParam; } set { paramsParam = value; } }\n    public virtual string TotalStateType { get { return atomicSpec.TypeState; } }\n    public virtual string Prefix { get { return atomicSpec.Prefix; } }\n    public virtual string ModuleName { get { return atomicSpec.ModuleName; } }\n\n    public virtual string StepsType(AtomicPath path)\n    {\n      return $\"{Prefix}_PathSteps_{path.Name}\";\n    }\n\n    public virtual string CaseEntry(AtomicPath path)\n    {\n      return $\"case {Prefix}_Path_{path.Name}({ParamsParam})\";\n    }\n\n    public virtual string CaseEntryWithUnderscores(AtomicPath path)\n    {\n      return $\"case {Prefix}_Path_{path.Name}(_)\";\n    }\n\n    public virtual string PathFormals(AtomicPath path)\n    {\n      return $\"{State}:{TotalStateType}, {Tid}:Armada_ThreadHandle, {Steps}:{StepsType(path)}\";\n    }\n\n    public virtual string PathSteps(AtomicPath path)\n    {\n      return $\"{State}, {Tid}, {Steps}\";\n    }\n\n    public virtual string GetOpenValidPathInvocation(AtomicPath atomicPath)\n    {\n      string str = $@\"\n         var {Steps}, {States} := lemma_{Prefix}_OpenPath_{atomicPath.Name}({State}, {Path}, {Tid});\n      \";\n/*\n         assert {Path} == {Prefix}_Path_{atomicPath.Name}({Steps});\n         assert {Prefix}_ValidPath_{atomicPath.Name}({State}, {Tid}, {Steps});\n         assert {States} == {Prefix}_GetPathStates_{atomicPath.Name}({State}, {Tid}, {Steps});\n         assert {Prefix}_GetStateAfterPath({State}, {Path}, {Tid}) == {States}.s{atomicPath.NumNextRoutines};\n*/\n      foreach (var i in Enumerable.Range(0, atomicPath.NumNextRoutines))\n      {\n        var nextRoutine = atomicPath.NextRoutines[i];\n        var stepPrinter = new ModuleStepPrinter(ModuleName);\n        stepPrinter.State = atomicSpec.Low ? $\"{States}.s{i}.s\" :  $\"{States}.s{i}\";\n        stepPrinter.Step = $\"{Steps}.step{i}\";\n        stepPrinter.Tid = Tid;\n        str += stepPrinter.GetOpenValidStepInvocation(nextRoutine);\n      }\n      return str;\n    }\n\n    public virtual string GetOpenPathInvocation(AtomicPath atomicPath)\n    {\n      string str = $@\"\n         var {Steps}, {States} := lemma_{Prefix}_OpenPath_{atomicPath.Name}({State}, {Path}, {Tid});\n      \";\n/*\n         assert {Path} == {Prefix}_Path_{atomicPath.Name}({Steps});\n         assert {Prefix}_ValidPath({State}, {Path}, {Tid}) == {Prefix}_ValidPath_{atomicPath.Name}({State}, {Tid}, {Steps});\n         assert {States} == {Prefix}_GetPathStates_{atomicPath.Name}({State}, {Tid}, {Steps});\n         assert {Prefix}_GetStateAfterPath({State}, {Path}, {Tid}) == {States}.s{atomicPath.NumNextRoutines};\n*/\n      foreach (var i in Enumerable.Range(0, atomicPath.NumNextRoutines))\n      {\n        var nextRoutine = atomicPath.NextRoutines[i];\n        var stepPrinter = new ModuleStepPrinter(ModuleName);\n        stepPrinter.State = atomicSpec.Low ? $\"{States}.s{i}.s\" :  $\"{States}.s{i}\";\n        stepPrinter.Step = $\"{Steps}.step{i}\";\n        stepPrinter.Tid = Tid;\n        str += stepPrinter.GetOpenStepInvocation(nextRoutine);\n      }\n      return str;\n    }\n\n    public virtual string GetAssertValidPathInvocation(AtomicPath atomicPath)\n    {\n      string str = \"\";\n      foreach (var i in Enumerable.Range(0, atomicPath.NumNextRoutines))\n      {\n        var nextRoutine = atomicPath.NextRoutines[i];\n        var stepPrinter = new ModuleStepPrinter(ModuleName);\n        stepPrinter.State = atomicSpec.Low ? $\"{States}.s{i}.s\" :  $\"{States}.s{i}\";\n        stepPrinter.NextState = atomicSpec.Low ? $\"{States}.s{i + 1}.s\" :  $\"{States}.s{i + 1}\";\n        stepPrinter.Step = $\"{Steps}.step{i}\";\n        stepPrinter.Tid = Tid;\n        str += stepPrinter.GetAssertValidStepInvocation(nextRoutine);\n      }\n      str += $@\"\n        assert {Prefix}_ValidPath_{atomicPath.Name}({State}, {Tid}, {Steps});\n        assert {Prefix}_ValidPath({State}, {Path}, {Tid});\n        assert {NextState} == {Prefix}_GetStateAfterPath({State}, {Path}, {Tid});\n      \";\n      return str;\n    }\n  }\n\n  public class PrefixedVarsPathPrinter : PathPrinter\n  {\n    public PrefixedVarsPathPrinter(AtomicSpec i_atomicSpec) : base(i_atomicSpec)\n    {\n      var prefix = atomicSpec.Low ? \"l\" : \"h\";\n      State = prefix + State;\n      NextState = prefix + NextState;\n      States = prefix + States;\n      Steps = prefix + Steps;\n      Path = prefix + Path;\n    }\n  }\n\n  public class ReductionPathPrinter : PathPrinter\n  {\n    public ReductionPathPrinter(AtomicSpec i_atomicSpec, string i_uniq, string i_state, string i_nextState, string i_path, string i_tid)\n      : base(i_atomicSpec)\n    {\n      State = i_state;\n      NextState = i_nextState;\n      Path = i_path;\n      Steps = i_uniq + \"_steps\";\n      States = i_uniq + \"_states\";\n      Tid = i_tid;\n    }\n  }\n}\n"
  },
  {
    "path": "Source/Armada/PredicateBuilder.cs",
    "content": "using System;\nusing System.Numerics;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text;\nusing static Microsoft.Armada.Predicate;\nusing IToken = Microsoft.Boogie.IToken;\nusing Token = Microsoft.Boogie.Token;\nusing System.Security.Cryptography;\n\nnamespace Microsoft.Armada {\n\n  public abstract class PredicateBuilderNodeData\n  {\n    public PredicateBuilderNodeData() { }\n    public abstract string Extract();\n    public virtual PredicateBuilderNodeData Simplify() { return this; }\n  }\n\n  public class PredicateBuilderNodeDataFalse : PredicateBuilderNodeData\n  {\n    public PredicateBuilderNodeDataFalse()\n    {\n    }\n    \n    public override string Extract() { return \"false\"; }\n  }\n\n  public class PredicateBuilderNodeDataTrue : PredicateBuilderNodeData\n  {\n    public PredicateBuilderNodeDataTrue()\n    {\n    }\n    \n    public override string Extract() { return \"true\"; }\n  }\n\n  public class PredicateBuilderNodeDataExpression : PredicateBuilderNodeData\n  {\n    private string expr;\n    public PredicateBuilderNodeDataExpression(string i_expr)\n    {\n      expr = i_expr;\n    }\n\n    public override string Extract()\n    {\n      return expr;\n    }\n  }\n\n  public class PredicateBuilderNodeDataVariableDeclaration : PredicateBuilderNodeData\n  {\n    private string varName;\n    private string value;\n    private PredicateBuilderNode child;\n\n    public PredicateBuilderNodeDataVariableDeclaration(string i_varName, string i_value, PredicateBuilderNode i_child)\n    {\n      varName = i_varName;\n      value = i_value;\n      child = i_child;\n    }\n\n    public override string Extract()\n    {\n      return $\"var {varName} := {value}; {child.Extract()}\";\n    }\n\n    public override PredicateBuilderNodeData Simplify()\n    {\n      child.Simplify();\n      if (child.Data is PredicateBuilderNodeDataTrue || child.Data is PredicateBuilderNodeDataFalse) {\n        return child.Data;\n      }\n      return this;\n    }\n  }\n\n  public class PredicateBuilderNodeDataConjunction : PredicateBuilderNodeData\n  {\n    private List<PredicateBuilderNode> children;\n\n    public PredicateBuilderNodeDataConjunction(PredicateBuilderNode i_child1, PredicateBuilderNode i_child2)\n    {\n      children = new List<PredicateBuilderNode>{ i_child1, i_child2 };\n    }\n\n    public PredicateBuilderNodeDataConjunction(List<PredicateBuilderNode> i_children)\n    {\n      children = new List<PredicateBuilderNode>(i_children);\n    }\n\n    public override string Extract()\n    {\n      return AH.CombineStringsWithAnd(children.Select(child => child.Extract()));\n    }\n\n    public List<PredicateBuilderNode> Children { get { return children; } }\n\n    public override PredicateBuilderNodeData Simplify()\n    {\n      // First, simplify all children.\n\n      foreach (var child in children) {\n        child.Simplify();\n      }\n\n      // Next, inline any conjunctions, e.g., changing A && (B && C) && (D && E && F) into A && B && C && D && E && F.\n      // Also, remove any trues.  Also, if we encounter a false, just return false.\n\n      var newChildren = new List<PredicateBuilderNode>();\n      foreach (var child in children)\n      {\n        if (child.Data is PredicateBuilderNodeDataFalse cf) {\n          return cf;\n        }\n        else if (child.Data is PredicateBuilderNodeDataTrue) {\n          continue;\n        }\n        else if (child.Data is PredicateBuilderNodeDataConjunction cc) {\n          newChildren.AddRange(cc.Children);\n        }\n        else {\n          newChildren.Add(child);\n        }\n      }\n\n      // If we don't have any children, return true; otherwise, return a conjunction of\n      // those children.\n\n      if (newChildren.Count == 0) {\n        return new PredicateBuilderNodeDataTrue();\n      }\n      else {\n        return new PredicateBuilderNodeDataConjunction(newChildren);\n      }\n    }\n  }\n\n  public class PredicateBuilderNodeDataDisjunction : PredicateBuilderNodeData\n  {\n    private List<PredicateBuilderNode> children;\n\n    public PredicateBuilderNodeDataDisjunction(PredicateBuilderNode child1, PredicateBuilderNode child2)\n    {\n      children = new List<PredicateBuilderNode>{ child1, child2 };\n    }\n\n    public PredicateBuilderNodeDataDisjunction(List<PredicateBuilderNode> i_children)\n    {\n      children = new List<PredicateBuilderNode>(i_children);\n    }\n\n    public override string Extract()\n    {\n      return AH.CombineStringsWithOr(children.Select(child => child.Extract()));\n    }\n\n    public List<PredicateBuilderNode> Children { get { return children; } }\n\n    public override PredicateBuilderNodeData Simplify()\n    {\n      // First, simplify all children.\n\n      foreach (var child in children) {\n        child.Simplify();\n      }\n\n      // Next, inline any disjunctions, e.g., changing A || (B || C) || (D || E || F) into A || B || C || D || E || F.\n      // Also, remove any falses.  Also, if we encounter a true, just return true.\n\n      var newChildren = new List<PredicateBuilderNode>();\n      foreach (var child in children)\n      {\n        if (child.Data is PredicateBuilderNodeDataTrue ct) {\n          return ct;\n        }\n        else if (child.Data is PredicateBuilderNodeDataFalse) {\n          continue;\n        }\n        else if (child.Data is PredicateBuilderNodeDataDisjunction cd) {\n          newChildren.AddRange(cd.Children);\n        }\n        else {\n          newChildren.Add(child);\n        }\n      }\n\n      // If we don't have any children, return false; otherwise, return a disjunction of\n      // those children.\n\n      if (newChildren.Count == 0) {\n        return new PredicateBuilderNodeDataFalse();\n      }\n      else {\n        return new PredicateBuilderNodeDataDisjunction(newChildren);\n      }\n    }\n  }\n\n  public class PredicateBuilderNode\n  {\n    private PredicateBuilderNodeData data;\n\n    public PredicateBuilderNode(PredicateBuilderNodeData i_data)\n    {\n      data = i_data;\n    }\n\n    public PredicateBuilderNodeData Data\n    {\n      get { return data; }\n      set { data = value; }\n    }\n\n    public string Extract()\n    {\n      return data.Extract();\n    }\n\n    public void Simplify()\n    {\n      data = data.Simplify();\n    }\n\n    public PredicateBuilderNode AddVariableDeclaration(string varName, string value)\n    {\n      var newNode = new PredicateBuilderNode(data);\n      data = new PredicateBuilderNodeDataVariableDeclaration(varName, value, newNode);\n      return newNode;\n    }\n\n    public PredicateBuilderNode AddConjunct(string conjunct)\n    {\n      var newNode = new PredicateBuilderNode(data);\n      var conjunctNode = new PredicateBuilderNode(new PredicateBuilderNodeDataExpression(conjunct));\n      data = new PredicateBuilderNodeDataConjunction(conjunctNode, newNode);\n      return newNode;\n    }\n\n    public PredicateBuilderNode AddDisjunct(string disjunct)\n    {\n      var newNode = new PredicateBuilderNode(data);\n      var disjunctNode = new PredicateBuilderNode(new PredicateBuilderNodeDataExpression(disjunct));\n      data = new PredicateBuilderNodeDataDisjunction(disjunctNode, newNode);\n      return newNode;\n    }\n  }\n\n  public class PredicateBuilder {\n    private Program prog;\n    private bool valid;\n    private PredicateBuilderNode top;\n    private PredicateBuilderNode current;\n    private Dictionary<string, int> variableUseCount;\n\n    public PredicateBuilder(Program i_prog, bool defaultValue)\n    {\n      prog = i_prog;\n      valid = true;\n      if (defaultValue) {\n        top = new PredicateBuilderNode(new PredicateBuilderNodeDataTrue());\n      }\n      else {\n        top = new PredicateBuilderNode(new PredicateBuilderNodeDataFalse());\n      }\n      current = top;\n      variableUseCount = new Dictionary<string, int>();\n    }\n\n    public bool Valid { get { return valid; } }\n\n    public string ReserveVariableName(string varName)\n    {\n      if (variableUseCount.ContainsKey(varName)) {\n        Fail($\"Internal error:  Attempt to reserve variable name that's already in use ({varName}).\");\n        return null;\n      }\n      else {\n        variableUseCount[varName] = 1;\n        return varName;\n      }\n    }\n\n    public string AddVariableDeclaration(string varName, string value)\n    {\n      if (!valid) {\n        Debug.Assert(false);\n        return null;\n      }\n\n      int count;\n      if (variableUseCount.TryGetValue(varName, out count)) {\n        variableUseCount[varName] = count + 1;\n        varName = $\"{varName}{count+1}\";\n      }\n      else {\n        variableUseCount[varName] = 1;\n      }\n\n      current = current.AddVariableDeclaration(varName, value);\n\n      return varName;\n    }\n\n    public void AddConjunct(string conjunct)\n    {\n      current = current.AddConjunct(conjunct);\n    }\n\n    public void AddDisjunct(string disjunct)\n    {\n      current = current.AddDisjunct(disjunct);\n    }\n\n    public string Extract()\n    {\n      if (!valid) {\n        Debug.Assert(false);\n        return null;\n      }\n\n      top.Simplify();\n      return top.Extract();\n    }\n\n    public void Fail(IToken tok, string reason) {\n      valid = false;\n      if (reason != null) {\n        AH.PrintError(prog, tok, reason);\n      }\n    }\n\n    public void Fail(string reason) {\n      Fail(Token.NoToken, reason);\n    }\n  }\n\n}\n"
  },
  {
    "path": "Source/Armada/Printer.cs",
    "content": "//-----------------------------------------------------------------------------\n//\n// Copyright (C) Microsoft Corporation.  All Rights Reserved.\n//\n//-----------------------------------------------------------------------------\nusing System;\nusing System.IO;\nusing System.Collections.Generic;\nusing System.Diagnostics.Contracts;\nusing System.Numerics;\nusing System.Linq;\nusing Bpl = Microsoft.Boogie;\n\nnamespace Microsoft.Armada {\n  public class Printer {\n    TextWriter wr;\n    ArmadaOptions.PrintModes printMode;\n    bool afterResolver;\n    bool printingExportSet = false;\n\n    [ContractInvariantMethod]\n    void ObjectInvariant()\n    {\n      Contract.Invariant(wr!=null);\n    }\n\n    public Printer(TextWriter wr, ArmadaOptions.PrintModes printMode = ArmadaOptions.PrintModes.Everything) {\n      Contract.Requires(wr != null);\n      this.wr = wr;\n      this.printMode = printMode;\n    }\n\n    public static string ExprToString(Expression expr)\n    {\n      Contract.Requires(expr != null);\n      using (var wr = new System.IO.StringWriter()) {\n        var pr = new Printer(wr);\n        pr.PrintExpression(expr, false);\n        return wr.ToString();\n      }\n    }\n\n    public static string GuardToString(bool isBindingGuard, Expression expr) {\n      Contract.Requires(!isBindingGuard || (expr is ExistsExpr && ((ExistsExpr)expr).Range == null));\n      using (var wr = new System.IO.StringWriter()) {\n        var pr = new Printer(wr);\n        pr.PrintGuard(isBindingGuard, expr);\n        return wr.ToString();\n      }\n    }\n\n    public static string ExtendedExprToString(Expression expr) {\n      Contract.Requires(expr != null);\n      using (var wr = new System.IO.StringWriter()) {\n        var pr = new Printer(wr);\n        pr.PrintExtendedExpr(expr, 0, true, false, 0, false);\n        return wr.ToString();\n      }\n    }\n\n    public static string FrameExprListToString(List<FrameExpression> fexprs) {\n      Contract.Requires(fexprs != null);\n      using (var wr = new System.IO.StringWriter()) {\n        var pr = new Printer(wr);\n        pr.PrintFrameExpressionList(fexprs);\n        return wr.ToString();\n      }\n    }\n\n    public static string StatementToString(Statement stmt) {\n      Contract.Requires(stmt != null);\n      using (var wr = new System.IO.StringWriter()) {\n        var pr = new Printer(wr);\n        pr.PrintStatement(stmt, 0);\n        return ToStringWithoutNewline(wr);\n      }\n    }\n\n    public static string IteratorClassToString(IteratorDecl iter) {\n      Contract.Requires(iter != null);\n      using (var wr = new System.IO.StringWriter()) {\n        var pr = new Printer(wr);\n        pr.PrintIteratorClass(iter, 0, null);\n        return ToStringWithoutNewline(wr);\n      }\n    }\n\n    public static string IteratorSignatureToString(IteratorDecl iter) {\n      Contract.Requires(iter != null);\n      using (var wr = new System.IO.StringWriter()) {\n        var pr = new Printer(wr);\n        pr.PrintIteratorSignature(iter, 0);\n        return ToStringWithoutNewline(wr);\n      }\n    }\n\n    public static string FieldToString(Field field) {\n      Contract.Requires(field != null);\n      using (var wr = new System.IO.StringWriter()) {\n        var pr = new Printer(wr);\n        pr.PrintField(field, 0);\n        return ToStringWithoutNewline(wr);\n      }\n    }\n\n    public static string FunctionSignatureToString(Function f) {\n      Contract.Requires(f != null);\n      using (var wr = new System.IO.StringWriter()) {\n        var pr = new Printer(wr);\n        pr.PrintFunction(f, 0, true);\n        return ToStringWithoutNewline(wr);\n      }\n    }\n\n    public static string MethodSignatureToString(Method m) {\n      Contract.Requires(m != null);\n      using (var wr = new System.IO.StringWriter()) {\n        var pr = new Printer(wr);\n        pr.PrintMethod(m, 0, true);\n        return ToStringWithoutNewline(wr);\n      }\n    }\n\n    public static string ModuleDefinitionToString(ModuleDefinition m, ArmadaOptions.PrintModes printMode = ArmadaOptions.PrintModes.Everything) {\n      Contract.Requires(m != null);\n      using (var wr = new System.IO.StringWriter()) {\n        var pr = new Printer(wr, printMode);\n        pr.PrintModuleDefinition(m, m.VisibilityScope, 0, null, null);\n        return ToStringWithoutNewline(wr);\n      }\n    }\n\n\n    /// <summary>\n    /// Returns a string for all attributes on the list \"a\".  Each attribute is\n    /// followed by a space.\n    /// </summary>\n    public static string AttributesToString(Attributes a) {\n      if (a == null) {\n        return \"\";\n      } else {\n        return AttributesToString(a.Prev) + OneAttributeToString(a) + \" \";\n      }\n    }\n\n    public static string OneAttributeToString(Attributes a, string nameSubstitution = null) {\n      Contract.Requires(a != null);\n      using (var wr = new System.IO.StringWriter()) {\n        var pr = new Printer(wr);\n        pr.PrintOneAttribute(a, nameSubstitution);\n        return ToStringWithoutNewline(wr);\n      }\n    }\n\n    public static string ToStringWithoutNewline(System.IO.StringWriter wr) {\n      Contract.Requires(wr != null);\n      var sb = wr.GetStringBuilder();\n      var len = sb.Length;\n      while (len > 0 && (sb[len - 1] == '\\n' || sb[len - 1] == '\\r')) {\n        len--;\n      }\n      return sb.ToString(0, len);\n    }\n\n    public void PrintComment(String msg) {\n      wr.WriteLine(\"// \" + msg);\n    }\n\n    public void PrintProgram(Program prog, bool afterResolver) {\n      Contract.Requires(prog != null);\n      this.afterResolver = afterResolver;\n      if (Bpl.CommandLineOptions.Clo.ShowEnv != Bpl.CommandLineOptions.ShowEnvironment.Never) {\n        wr.WriteLine(\"// \" + Bpl.CommandLineOptions.Clo.Version);\n        wr.WriteLine(\"// \" + Bpl.CommandLineOptions.Clo.Environment);\n      }\n      if (printMode != ArmadaOptions.PrintModes.DllEmbed) {\n        wr.WriteLine(\"// {0}\", prog.Name);\n      }\n      if (ArmadaOptions.O.DafnyPrintResolvedFile != null && printMode == ArmadaOptions.PrintModes.Everything) {\n        wr.WriteLine();\n        wr.WriteLine(\"/*\");\n        PrintModuleDefinition(prog.BuiltIns.SystemModule, null, 0, null, Path.GetFullPath(ArmadaOptions.O.DafnyPrintResolvedFile));\n        wr.Write(\"// bitvector types in use:\");\n        foreach (var w in prog.BuiltIns.Bitwidths) {\n          wr.Write(\" bv{0}\", w);\n        }\n        wr.WriteLine();\n        wr.WriteLine(\"*/\");\n      }\n      wr.WriteLine();\n      PrintCallGraph(prog.DefaultModuleDef, 0);\n      var fileBeingPrinted = Path.GetFullPath(prog.FullName);\n      if (printMode == ArmadaOptions.PrintModes.Armada) {\n        foreach (var inc in prog.DefaultModuleDef.Includes) {\n          if (Path.GetFullPath(inc.includerFilename).Equals(fileBeingPrinted)) {\n            wr.WriteLine(\"include {0}\", inc.rawFilename);\n          }\n        }\n      }\n      PrintTopLevelDecls(prog.DefaultModuleDef.TopLevelDecls, 0, null, fileBeingPrinted);\n      wr.Flush();\n    }\n\n    public void PrintInclude(string file) {\n      wr.WriteLine(\"include \\\"{0}\\\"\", file);\n    }\n\n    public void PrintCallGraph(ModuleDefinition module, int indent) {\n      Contract.Requires(module != null);\n      Contract.Requires(0 <= indent);\n      if (ArmadaOptions.O.DafnyPrintResolvedFile != null && printMode == ArmadaOptions.PrintModes.Everything) {\n         // print call graph\n        Indent(indent); wr.WriteLine(\"/* CALL GRAPH for module {0}:\", module.Name);\n        var SCCs = module.CallGraph.TopologicallySortedComponents();\n        SCCs.Reverse();\n        foreach (var clbl in SCCs) {\n          Indent(indent); wr.WriteLine(\" * SCC at height {0}:\", module.CallGraph.GetSCCRepresentativeId(clbl));\n          var r = module.CallGraph.GetSCC(clbl);\n          foreach (var m in r) {\n            Indent(indent); wr.WriteLine(\" *   {0}\", m.NameRelativeToModule);\n          }\n        }\n        Indent(indent); wr.WriteLine(\" */\");\n      }\n    }\n\n    public void PrintTopLevelDecls(List<TopLevelDecl> decls, int indent, List<Bpl.IToken>/*?*/ prefixIds, string fileBeingPrinted) {\n      Contract.Requires(decls!= null);\n      int i = 0;\n      foreach (TopLevelDecl d in decls) {\n        Contract.Assert(d != null);\n        if (PrintModeSkipGeneralDecl(d, fileBeingPrinted)) { continue; }\n        if (d is OpaqueTypeDecl) {\n          var at = (OpaqueTypeDecl)d;\n          if (i++ != 0) { wr.WriteLine(); }\n          Indent(indent);\n          PrintClassMethodHelper(\"type\", at.Attributes, at.Name + TPCharacteristicsSuffix(at.TheType.Characteristics), d.TypeArgs);\n          wr.WriteLine();\n        } else if (d is NewtypeDecl) {\n          var dd = (NewtypeDecl)d;\n          if (i++ != 0) { wr.WriteLine(); }\n          Indent(indent);\n          PrintClassMethodHelper(\"newtype\", dd.Attributes, dd.Name, new List<TypeParameter>());\n          wr.Write(\" = \");\n          if (dd.Var == null) {\n            PrintType(dd.BaseType);\n            wr.WriteLine();\n          } else {\n            wr.Write(dd.Var.DisplayName);\n            if (ShowType(dd.Var.Type)) {\n              wr.Write(\": \");\n              PrintType(dd.BaseType);\n            }\n            wr.WriteLine();\n            Indent(indent + IndentAmount);\n            wr.Write(\"| \");\n            PrintExpression(dd.Constraint, true);\n            wr.WriteLine();\n            if (dd.WitnessKind != SubsetTypeDecl.WKind.None) {\n              Indent(indent + IndentAmount);\n              PrintWitnessClause(dd);\n              wr.WriteLine();\n            }\n          }\n          if (dd.Members.Count != 0) {\n            wr.WriteLine(\"{\");\n            PrintMembers(dd.Members, indent + IndentAmount, fileBeingPrinted);\n            Indent(indent);\n            wr.WriteLine(\"}\");\n          }\n        } else if (d is SubsetTypeDecl) {\n          var dd = (SubsetTypeDecl)d;\n          if (i++ != 0) { wr.WriteLine(); }\n          Indent(indent);\n          PrintClassMethodHelper(\"type\", dd.Attributes, dd.Name + TPCharacteristicsSuffix(dd.Characteristics), dd.TypeArgs);\n          wr.Write(\" = \");\n          wr.Write(dd.Var.DisplayName);\n          if (ShowType(dd.Var.Type)) {\n            wr.Write(\": \");\n            PrintType(dd.Rhs);\n          }\n          if (dd is NonNullTypeDecl) {\n            wr.Write(\" \");\n          } else {\n            wr.WriteLine();\n            Indent(indent + IndentAmount);\n          }\n          wr.Write(\"| \");\n          PrintExpression(dd.Constraint, true);\n          if (dd.WitnessKind != SubsetTypeDecl.WKind.None) {\n            if (dd is NonNullTypeDecl) {\n              wr.Write(\" \");\n            } else {\n              wr.WriteLine();\n              Indent(indent + IndentAmount);\n            }\n            PrintWitnessClause(dd);\n          }\n          wr.WriteLine();\n        } else if (d is TypeSynonymDecl) {\n          var dd = (TypeSynonymDecl)d;\n          if (i++ != 0) { wr.WriteLine(); }\n          Indent(indent);\n          PrintClassMethodHelper(\"type\", dd.Attributes, dd.Name + TPCharacteristicsSuffix(dd.Characteristics), dd.TypeArgs);\n          wr.Write(\" = \");\n          PrintType(dd.Rhs);\n          wr.WriteLine();\n        } else if (d is DatatypeDecl) {\n          var dd = (DatatypeDecl)d;\n          if (i++ != 0) { wr.WriteLine(); }\n          PrintDatatype(dd, indent, fileBeingPrinted);\n        } else if (d is IteratorDecl) {\n          var iter = (IteratorDecl)d;\n          if (i++ != 0) { wr.WriteLine(); }\n          PrintIteratorSignature(iter, indent);\n\n          if (iter.Body != null) {\n            Indent(indent);\n            PrintStatement(iter.Body, indent);\n            wr.WriteLine();\n          }\n\n          if (ArmadaOptions.O.DafnyPrintResolvedFile != null) {\n            // also print the members that were created as part of the interpretation of the iterator\n            Contract.Assert(iter.Members.Count != 0);  // filled in during resolution\n            Indent(indent); wr.WriteLine(\"/*---------- iterator members ----------\");\n            Indent(indent); PrintIteratorClass(iter, indent, fileBeingPrinted);\n            Indent(indent); wr.WriteLine(\"---------- iterator members ----------*/\");\n          }\n\n        } else if (d is ClassDecl) {\n          ClassDecl cl = (ClassDecl)d;\n          if (!cl.IsDefaultClass) {\n            if (i++ != 0) { wr.WriteLine(); }\n            PrintClass(cl, indent, fileBeingPrinted);\n          } else if (cl.Members.Count == 0) {\n            // print nothing\n          } else {\n            if (i++ != 0) { wr.WriteLine(); }\n            PrintMembers(cl.Members, indent, fileBeingPrinted);\n          }\n\n        } else if (d is ValuetypeDecl) {\n          var vtd = (ValuetypeDecl)d;\n          if (i++ != 0) { wr.WriteLine(); }\n          Indent(indent);\n          PrintClassMethodHelper(\"type\", vtd.Attributes, vtd.Name, vtd.TypeArgs);\n          if (vtd.Members.Count == 0) {\n            wr.WriteLine(\" { }\");\n          } else {\n            wr.WriteLine(\" {\");\n            PrintMembers(new List<MemberDecl>(vtd.Members.Values), indent + IndentAmount, fileBeingPrinted);\n            Indent(indent);\n            wr.WriteLine(\"}\");\n          }\n\n        } else if (d is ModuleDecl) {\n          wr.WriteLine();\n          Indent(indent);\n          if (d is LiteralModuleDecl) {\n            LiteralModuleDecl modDecl = ((LiteralModuleDecl)d);\n            VisibilityScope scope = null;\n            if (modDecl.Signature != null){\n              scope = modDecl.Signature.VisibilityScope;\n            }\n            PrintModuleDefinition(modDecl.ModuleDef, scope, indent, prefixIds, fileBeingPrinted);\n          } else if (d is AliasModuleDecl) {\n            var dd = (AliasModuleDecl)d;\n\n            wr.Write(\"import\"); if (dd.Opened) wr.Write(\" opened\");\n            if (dd.ResolvedHash.HasValue && this.printMode == ArmadaOptions.PrintModes.DllEmbed) {\n              wr.Write(\" /*\");\n              wr.Write(dd.ResolvedHash);\n              wr.Write(\"*/\");\n            }\n            wr.Write(\" {0} \", dd.Name);\n            wr.Write(\"= {0}\", Util.Comma(\".\", dd.Path, id => id.val));\n            if (dd.Exports.Count > 0) {\n              wr.Write(\"`{{{0}}}\", Util.Comma(\",\", dd.Exports, id => id.val));\n            }\n            wr.WriteLine();\n          } else if (d is ModuleFacadeDecl) {\n            var dd = (ModuleFacadeDecl)d;\n\n            wr.Write(\"import\"); if (dd.Opened) wr.Write(\" opened\");\n            if (dd.ResolvedHash.HasValue && this.printMode == ArmadaOptions.PrintModes.DllEmbed) {\n              wr.Write(\" /*\");\n              wr.Write(dd.ResolvedHash);\n              wr.Write(\"*/\");\n            }\n            wr.Write(\" {0} \", dd.Name);\n            wr.Write(\": {0}\", Util.Comma(\".\", dd.Path, id => id.val));\n            if (dd.Exports.Count > 0) {\n              wr.Write(\"`{{{0}}}\", Util.Comma(\",\", dd.Exports, id => id.val));\n            }\n            wr.WriteLine();\n\n          } else if (d is ModuleExportDecl) {\n            ModuleExportDecl e = (ModuleExportDecl)d;\n            if (!e.IsDefault) {\n              wr.Write(\"export {0}\", e.Name);\n            } else {\n              wr.Write(\"export \");\n            }\n            if (e.Extends.Count > 0) wr.Write(\" extends {0}\", Util.Comma(\", \", e.Extends, id => id));\n            wr.WriteLine();\n            PrintModuleExportDecl(e, indent + IndentAmount, fileBeingPrinted);\n            wr.WriteLine();\n          }\n        } else {\n          Contract.Assert(false);  // unexpected TopLevelDecl\n        }\n      }\n    }\n\n    private void PrintWitnessClause(RedirectingTypeDecl dd) {\n      Contract.Requires(dd != null);\n      Contract.Requires(dd.WitnessKind != SubsetTypeDecl.WKind.None);\n\n      switch (dd.WitnessKind) {\n        case SubsetTypeDecl.WKind.Ghost:\n          wr.Write(\"ghost \");\n          goto case SubsetTypeDecl.WKind.Compiled;\n        case SubsetTypeDecl.WKind.Compiled:\n          wr.Write(\"witness \");\n          PrintExpression(dd.Witness, true);\n          break;\n        case SubsetTypeDecl.WKind.Special:\n          wr.Write(\"/*special witness*/\");\n          break;\n        case SubsetTypeDecl.WKind.None:\n        default:\n          Contract.Assert(false);  // unexpected WKind\n          break;\n      }\n    }\n\n    void PrintModuleExportDecl(ModuleExportDecl m, int indent, string fileBeingPrinted) {\n      Contract.Requires(m != null);\n\n      var i = 0;\n      while (i < m.Exports.Count) {\n        var start = i;\n        var bodyKind = m.Exports[start].Opaque;\n        do {\n          i++;\n        } while (i < m.Exports.Count && m.Exports[i].Opaque == bodyKind);\n        // print [start..i)\n        Indent(indent);\n        wr.Write(\"{0} \", bodyKind ? \"provides\" : \"reveals\");\n        wr.WriteLine(Util.Comma(\", \", i - start, j => m.Exports[start + j].ToString()));\n\n        if (ArmadaOptions.O.DafnyPrintResolvedFile != null) {\n          Contract.Assert(!printingExportSet);\n          printingExportSet = true;\n          Indent(indent);\n          wr.WriteLine(\"/*----- exported view:\");\n          for (int j = start; j < i; j++) {\n            var id = m.Exports[j];\n            if (id.Decl is TopLevelDecl) {\n              PrintTopLevelDecls(new List<TopLevelDecl> { (TopLevelDecl)id.Decl }, indent + IndentAmount, null, fileBeingPrinted);\n            } else if (id.Decl is MemberDecl) {\n              PrintMembers(new List<MemberDecl> { (MemberDecl)id.Decl }, indent + IndentAmount, fileBeingPrinted);\n            }\n          }\n          Indent(indent);\n          wr.WriteLine(\"-----*/\");\n          Contract.Assert(printingExportSet);\n          printingExportSet = false;\n        }\n      }\n    }\n\n    public void PrintModuleDefinition(ModuleDefinition module, VisibilityScope scope, int indent, List<Bpl.IToken>/*?*/ prefixIds, string fileBeingPrinted) {\n      Contract.Requires(module != null);\n      Contract.Requires(0 <= indent);\n      Type.PushScope(scope);\n      if (module.IsAbstract) {\n        wr.Write(\"abstract \");\n      }\n      if (module.IsProtected) {\n        wr.Write(\"protected \");\n      }\n      wr.Write(\"module\");\n      PrintAttributes(module.Attributes);\n      wr.Write(\" \");\n      if (prefixIds != null) {\n        foreach (var p in prefixIds) {\n          wr.Write(\"{0}.\", p.val);\n        }\n      }\n      wr.Write(\"{0} \", module.Name);\n      if (module.RefinementBaseName != null) {\n        wr.Write(\"refines {0} \", module.RefinementBaseName.val);\n      }\n      if (module.TopLevelDecls.Count == 0) {\n        wr.WriteLine(\"{ }\");\n      } else {\n        wr.WriteLine(\"{\");\n        PrintCallGraph(module, indent + IndentAmount);\n        PrintTopLevelDeclsOrExportedView(module, indent, fileBeingPrinted);\n        Indent(indent);\n        wr.WriteLine(\"}\");\n      }\n      Type.PopScope(scope);\n    }\n\n    void PrintTopLevelDeclsOrExportedView(ModuleDefinition module, int indent, string fileBeingPrinted) {\n      var decls = module.TopLevelDecls;\n      // only filter based on view name after resolver.\n      if (afterResolver && ArmadaOptions.O.DafnyPrintExportedViews.Count != 0) {\n        decls = new List<TopLevelDecl>();\n        foreach (var nameOfView in ArmadaOptions.O.DafnyPrintExportedViews) {\n          foreach (var decl in module.TopLevelDecls) {\n            if (decl.FullName.Equals(nameOfView)) {\n              decls.Add(decl);\n            }\n          }\n        }\n      }\n      PrintTopLevelDecls(decls, indent + IndentAmount, null, fileBeingPrinted);\n      foreach (var tup in module.PrefixNamedModules) {\n        decls = new List<TopLevelDecl>() { tup.Item2 };\n        PrintTopLevelDecls(decls, indent + IndentAmount, tup.Item1, fileBeingPrinted);\n      }\n    }\n\n    void PrintIteratorSignature(IteratorDecl iter, int indent) {\n      Indent(indent);\n      PrintClassMethodHelper(\"iterator\", iter.Attributes, iter.Name, iter.TypeArgs);\n      if (iter.SignatureIsOmitted) {\n        wr.WriteLine(\" ...\");\n      } else {\n        PrintFormals(iter.Ins, iter);\n        if (iter.Outs.Count != 0) {\n          if (iter.Ins.Count + iter.Outs.Count <= 3) {\n            wr.Write(\" yields \");\n          } else {\n            wr.WriteLine();\n            Indent(indent + 2 * IndentAmount);\n            wr.Write(\"yields \");\n          }\n          PrintFormals(iter.Outs, iter);\n        }\n        wr.WriteLine();\n      }\n\n      int ind = indent + IndentAmount;\n      PrintSpec(\"requires\", iter.Requires, ind);\n      if (iter.Reads.Expressions != null) {\n        PrintFrameSpecLine(\"reads\", iter.Reads.Expressions, ind, iter.Reads.HasAttributes() ? iter.Reads.Attributes : null);\n      }\n      if (iter.Modifies.Expressions != null) {\n        PrintFrameSpecLine(\"modifies\", iter.Modifies.Expressions, ind, iter.Modifies.HasAttributes() ? iter.Modifies.Attributes : null);\n      }\n      PrintSpec(\"yield requires\", iter.YieldRequires, ind);\n      PrintSpec(\"yield ensures\", iter.YieldEnsures, ind);\n      PrintSpec(\"ensures\", iter.Ensures, ind);\n      PrintDecreasesSpec(iter.Decreases, ind);\n    }\n\n    private void PrintIteratorClass(IteratorDecl iter, int indent, string fileBeingPrinted) {\n      PrintClassMethodHelper(\"class\", null, iter.Name, iter.TypeArgs);\n      wr.WriteLine(\" {\");\n      PrintMembers(iter.Members, indent + IndentAmount, fileBeingPrinted);\n      Indent(indent); wr.WriteLine(\"}\");\n\n      Contract.Assert(iter.NonNullTypeDecl != null);\n      PrintTopLevelDecls(new List<TopLevelDecl> { iter.NonNullTypeDecl }, indent, null, fileBeingPrinted);\n    }\n\n    public void PrintClass(ClassDecl c, int indent, string fileBeingPrinted) {\n      Contract.Requires(c != null);\n\n      Indent(indent);\n      PrintClassMethodHelper((c is TraitDecl) ? \"trait\" : \"class\", c.Attributes, c.Name, c.TypeArgs);\n      string sep = \" extends \";\n      foreach (var trait in c.TraitsTyp) {\n        wr.Write(sep);\n        PrintType(trait);\n        sep = \", \";\n      }\n      if (c.Members.Count == 0) {\n        wr.WriteLine(\" { }\");\n      } else {\n        wr.WriteLine(\" {\");\n        PrintMembers(c.Members, indent + IndentAmount, fileBeingPrinted);\n        Indent(indent);\n        wr.WriteLine(\"}\");\n      }\n\n      if (ArmadaOptions.O.DafnyPrintResolvedFile != null && c.NonNullTypeDecl != null) {\n        if (!printingExportSet) {\n          Indent(indent); wr.WriteLine(\"/*-- non-null type\");\n        }\n        PrintTopLevelDecls(new List<TopLevelDecl> { c.NonNullTypeDecl }, indent, null, fileBeingPrinted);\n        if (!printingExportSet) {\n          Indent(indent); wr.WriteLine(\"*/\");\n        }\n      }\n    }\n\n    public void PrintMembers(List<MemberDecl> members, int indent, string fileBeingPrinted)\n    {\n      Contract.Requires(members != null);\n\n      int state = 0;  // 0 - no members yet; 1 - previous member was a field; 2 - previous member was non-field\n      foreach (MemberDecl m in members) {\n        if (PrintModeSkipGeneralMembers(m, fileBeingPrinted)) { continue; }\n        if (m is Method) {\n          if (state != 0) { wr.WriteLine(); }\n          PrintMethod((Method)m, indent, false);\n          var com = m as FixpointLemma;\n          if (com != null && com.PrefixLemma != null) {\n            Indent(indent); wr.WriteLine(\"/***\");\n            PrintMethod(com.PrefixLemma, indent, false);\n            Indent(indent); wr.WriteLine(\"***/\");\n          }\n          state = 2;\n        } else if (m is Field) {\n          if (state == 2) { wr.WriteLine(); }\n          PrintField((Field)m, indent);\n          state = 1;\n        } else if (m is Function) {\n          if (state != 0) { wr.WriteLine(); }\n          PrintFunction((Function)m, indent, false);\n          var fixp = m as FixpointPredicate;\n          if (fixp != null && fixp.PrefixPredicate != null) {\n            Indent(indent); wr.WriteLine(\"/*** (note, what is printed here does not show substitutions of calls to prefix predicates)\");\n            PrintFunction(fixp.PrefixPredicate, indent, false);\n            Indent(indent); wr.WriteLine(\"***/\");\n          }\n          state = 2;\n        } else {\n          Contract.Assert(false); throw new cce.UnreachableException();  // unexpected member\n        }\n      }\n    }\n\n    /// <summary>\n    /// Prints no space before \"kind\", but does print a space before \"attrs\" and \"name\".\n    /// </summary>\n    void PrintClassMethodHelper(string kind, Attributes attrs, string name, List<TypeParameter> typeArgs) {\n      Contract.Requires(kind != null);\n      Contract.Requires(name != null);\n      Contract.Requires(typeArgs != null);\n\n      wr.Write(kind);\n      PrintAttributes(attrs);\n\n      if (ArrowType.IsArrowTypeName(name)) {\n        PrintArrowType(ArrowType.ANY_ARROW, name, typeArgs);\n      } else if (ArrowType.IsPartialArrowTypeName(name)) {\n        PrintArrowType(ArrowType.PARTIAL_ARROW, name, typeArgs);\n      } else if (ArrowType.IsTotalArrowTypeName(name)) {\n        PrintArrowType(ArrowType.TOTAL_ARROW, name, typeArgs);\n      } else if (BuiltIns.IsTupleTypeName(name)) {\n        wr.Write(\" /*{0}*/ ({1})\", name, Util.Comma(\", \", typeArgs, TypeParamString));\n      } else {\n        wr.Write(\" {0}\", name);\n        PrintTypeParams(typeArgs);\n      }\n    }\n\n    private void PrintTypeParams(List<TypeParameter> typeArgs) {\n      Contract.Requires(typeArgs != null);\n      Contract.Requires(\n        typeArgs.All(tp => tp.Name.StartsWith(\"_\")) ||\n        typeArgs.All(tp => !tp.Name.StartsWith(\"_\")));\n\n      if (typeArgs.Count != 0 && !typeArgs[0].Name.StartsWith(\"_\")) {\n        wr.Write(\"<{0}>\", Util.Comma(\", \", typeArgs, TypeParamString));\n      }\n    }\n\n    public static string TypeParamString(TypeParameter tp) {\n      Contract.Requires(tp != null);\n      string variance;\n      switch (tp.VarianceSyntax) {\n        case TypeParameter.TPVarianceSyntax.Covariant_Permissive:\n          variance = \"*\";\n          break;\n        case TypeParameter.TPVarianceSyntax.Covariant_Strict:\n          variance = \"+\";\n          break;\n        case TypeParameter.TPVarianceSyntax.NonVariant_Permissive:\n          variance = \"!\";\n          break;\n        case TypeParameter.TPVarianceSyntax.NonVariant_Strict:\n          variance = \"\";\n          break;\n        case TypeParameter.TPVarianceSyntax.Contravariance:\n          variance = \"-\";\n          break;\n        default:\n          Contract.Assert(false);  // unexpected VarianceSyntax\n          throw new cce.UnreachableException();\n      }\n      return variance + tp.Name + TPCharacteristicsSuffix(tp.Characteristics);\n    }\n\n    private void PrintArrowType(string arrow, string internalName, List<TypeParameter> typeArgs) {\n      Contract.Requires(arrow != null);\n      Contract.Requires(internalName != null);\n      Contract.Requires(typeArgs != null);\n      Contract.Requires(1 <= typeArgs.Count);  // argument list ends with the result type\n      wr.Write(\" /*{0}*/ \", internalName);\n      int arity = typeArgs.Count - 1;\n      if (arity != 1) {\n        wr.Write(\"(\");\n      }\n      wr.Write(Util.Comma(\", \", arity, i => TypeParamString(typeArgs[i])));\n      if (arity != 1) {\n        wr.Write(\")\");\n      }\n      wr.Write(\" {0} {1}\", arrow, TypeParamString(typeArgs[arity]));\n    }\n\n    private void PrintTypeInstantiation(List<Type> typeArgs) {\n      Contract.Requires(typeArgs == null || typeArgs.Count != 0);\n      wr.Write(Type.TypeArgsToString(typeArgs));\n    }\n\n    public void PrintDatatype(DatatypeDecl dt, int indent, string fileBeingPrinted) {\n\n      Contract.Requires(dt != null);\n      Indent(indent);\n      PrintClassMethodHelper(dt is IndDatatypeDecl ? \"datatype\" : \"codatatype\", dt.Attributes, dt.Name, dt.TypeArgs);\n      wr.Write(\" =\");\n      string sep = \"\";\n      foreach (DatatypeCtor ctor in dt.Ctors) {\n        wr.Write(sep);\n        PrintClassMethodHelper(\"\", ctor.Attributes, ctor.Name, new List<TypeParameter>());\n        if (ctor.Formals.Count != 0) {\n          PrintFormals(ctor.Formals, null);\n        }\n        sep = \" |\";\n      }\n      if (dt.Members.Count == 0) {\n        wr.WriteLine();\n      } else {\n        wr.WriteLine(\" {\");\n        PrintMembers(dt.Members, indent + IndentAmount, fileBeingPrinted);\n        Indent(indent);\n        wr.WriteLine(\"}\");\n      }\n    }\n\n    /// <summary>\n    /// Prints a space before each attribute.\n    /// </summary>\n    public void PrintAttributes(Attributes a) {\n      if (a != null) {\n        PrintAttributes(a.Prev);\n        wr.Write(\" \");\n        PrintOneAttribute(a);\n      }\n    }\n    public void PrintOneAttribute(Attributes a, string nameSubstitution = null) {\n      Contract.Requires(a != null);\n      var name = nameSubstitution ?? a.Name;\n      var usAttribute = name.StartsWith(\"_\") || (ArmadaOptions.O.DisallowExterns && (name == \"extern\" || name == \"dllimport\"));\n      wr.Write(\"{1}{{:{0}\", name, usAttribute ? \"/*\" : \"\");\n      if (a.Args != null) {\n        PrintAttributeArgs(a.Args, false);\n      }\n      wr.Write(\"}}{0}\", usAttribute ? \"*/\" : \"\");\n\n    }\n\n    public void PrintAttributeArgs(List<Expression> args, bool isFollowedBySemicolon) {\n      Contract.Requires(args != null);\n      string prefix = \" \";\n      foreach (var arg in args) {\n        Contract.Assert(arg != null);\n        wr.Write(prefix);\n        prefix = \", \";\n        PrintExpression(arg, isFollowedBySemicolon);\n      }\n    }\n\n    public void PrintField(Field field, int indent) {\n      Contract.Requires(field != null);\n      Indent(indent);\n      if (field.HasStaticKeyword) {\n        wr.Write(\"static \");\n      }\n      if (field.IsGhost) {\n        wr.Write(\"ghost \");\n      }\n      if (field is ConstantField) {\n        wr.Write(\"const\");\n      } else {\n        wr.Write(\"var\");\n      }\n      PrintAttributes(field.Attributes);\n      wr.Write(\" {0}\", field.Name);\n      if (ShowType(field.Type)) {\n        wr.Write(\": \");\n        PrintType(field.Type);\n      }\n      if (field is ConstantField) {\n        var c = (ConstantField)field;\n        if (c.Rhs != null) {\n          wr.Write(\" := \");\n          PrintExpression(c.Rhs, true);\n        }\n      } else if (field.IsUserMutable) {\n        // nothing more to say\n      } else if (field.IsMutable) {\n        wr.Write(\"  // non-assignable\");\n      } else {\n        wr.Write(\"  // immutable\");\n      }\n      wr.WriteLine();\n    }\n\n    public void PrintFunction(Function f, int indent, bool printSignatureOnly) {\n      Contract.Requires(f != null);\n\n      if (PrintModeSkipFunctionOrMethod(f.IsGhost, f.Attributes, f.Name)) { return; }\n      var isPredicate = f is Predicate || f is PrefixPredicate;\n      Indent(indent);\n      string k = isPredicate ? \"predicate\" : f.WhatKind;\n      if (f.IsProtected) { k = \"protected \" + k; }\n      if (f.HasStaticKeyword) { k = \"static \" + k; }\n      if (!f.IsGhost) { k += \" method\"; }\n      PrintClassMethodHelper(k, f.Attributes, f.Name, f.TypeArgs);\n      if (f.SignatureIsOmitted) {\n        wr.WriteLine(\" ...\");\n      } else {\n        if (f is FixpointPredicate) {\n          PrintKTypeIndication(((FixpointPredicate)f).TypeOfK);\n        }\n        PrintFormals(f.Formals, f, f.Name);\n        if (!isPredicate && !(f is FixpointPredicate) && !(f is TwoStatePredicate)) {\n          wr.Write(\": \");\n          if (f.Result != null) {\n            wr.Write(\"(\");\n            PrintFormal(f.Result, false);\n            wr.Write(\")\");\n          } else {\n            PrintType(f.ResultType);\n          }\n        }\n        wr.WriteLine();\n      }\n\n      int ind = indent + IndentAmount;\n      PrintSpec(\"requires\", f.Req, ind);\n      PrintFrameSpecLine(\"reads\", f.Reads, ind, null);\n      PrintSpec(\"ensures\", f.Ens, ind);\n      PrintDecreasesSpec(f.Decreases, ind);\n      if (f.Body != null && !printSignatureOnly) {\n        Indent(indent);\n        wr.WriteLine(\"{\");\n        Indent(ind);\n        PrintExtendedExpr(f.Body, ind, true, false, 0, false);\n        Indent(indent);\n        wr.WriteLine(\"}\");\n      }\n    }\n\n    // ----------------------------- PrintMethod -----------------------------\n\n    const int IndentAmount = 2; // The amount of indent for each new scope\n    const string BunchaSpaces = \"                                \";\n    void Indent(int amount)\n    {\n      Contract.Requires(0 <= amount);\n\n      while (0 < amount) {\n        wr.Write(BunchaSpaces.Substring(0, amount));\n        amount -= BunchaSpaces.Length;\n      }\n    }\n\n    private bool PrintModeSkipFunctionOrMethod(bool IsGhost, Attributes attributes, string name)\n    {\n      if (printMode == ArmadaOptions.PrintModes.NoGhost && IsGhost)\n          { return true; }\n      if (printMode == ArmadaOptions.PrintModes.NoIncludes || printMode == ArmadaOptions.PrintModes.NoGhost)\n      {\n          bool verify = true;\n          if (Attributes.ContainsBool(attributes, \"verify\", ref verify) && !verify)\n          { return true; }\n          if (name.Contains(\"INTERNAL\") || name.StartsWith(\"reveal_\"))\n          { return true; }\n      }\n      return false;\n    }\n    private bool PrintModeSkipGeneralMembers(MemberDecl m, string fileBeingPrinted)\n    {\n      // never skip a class member in Armada mode\n      return printMode != ArmadaOptions.PrintModes.Armada && PrintModeSkipGeneral(m.tok, fileBeingPrinted);\n    }\n\n    private bool PrintModeSkipGeneralDecl(TopLevelDecl d, string fileBeingPrinted)\n    {\n      // only skip modules in Armada mode\n      return (printMode != ArmadaOptions.PrintModes.Armada || d is ModuleDecl) && PrintModeSkipGeneral(d.tok, fileBeingPrinted);\n    }\n\n    private bool PrintModeSkipGeneral(Bpl.IToken tok, string fileBeingPrinted)\n    {\n       return (printMode == ArmadaOptions.PrintModes.NoIncludes || printMode == ArmadaOptions.PrintModes.NoGhost || printMode == ArmadaOptions.PrintModes.Armada)\n               && (tok.filename != null && fileBeingPrinted != null && Path.GetFullPath(tok.filename) != fileBeingPrinted);\n    }\n\n    public void PrintMethod(Method method, int indent, bool printSignatureOnly) {\n      Contract.Requires(method != null);\n\n      if (PrintModeSkipFunctionOrMethod(method.IsGhost, method.Attributes, method.Name)) { return; }\n      Indent(indent);\n      string k = method is Constructor ? \"constructor\" :\n        method is InductiveLemma ? \"inductive lemma\" :\n        method is CoLemma ? \"colemma\" :\n        method is Lemma || method is PrefixLemma ? \"lemma\" :\n        method is TwoStateLemma ? \"twostate lemma\" :\n        \"method\";\n      if (method.HasStaticKeyword) { k = \"static \" + k; }\n      if (method.IsGhost && !(method is Lemma) && !(method is PrefixLemma) && !(method is TwoStateLemma) && !(method is FixpointLemma)) {\n        k = \"ghost \" + k;\n      }\n      string nm = method is Constructor && !((Constructor)method).HasName ? \"\" : method.Name;\n      PrintClassMethodHelper(k, method.Attributes, nm, method.TypeArgs);\n      if (method.SignatureIsOmitted) {\n        wr.WriteLine(\" ...\");\n      } else {\n        if (method is FixpointLemma) {\n          PrintKTypeIndication(((FixpointLemma)method).TypeOfK);\n        }\n        PrintFormals(method.Ins, method, method.Name);\n        if (method.Outs.Count != 0) {\n          if (method.Ins.Count + method.Outs.Count <= 3) {\n            wr.Write(\" returns \");\n          } else {\n            wr.WriteLine();\n            Indent(indent + 2 * IndentAmount);\n            wr.Write(\"returns \");\n          }\n          PrintFormals(method.Outs, method);\n        }\n        wr.WriteLine();\n      }\n\n      int ind = indent + IndentAmount;\n      PrintSpec(\"requires\", method.Req, ind);\n      if (method.Mod.Expressions != null) {\n        PrintFrameSpecLine(\"modifies\", method.Mod.Expressions, ind, method.Mod.HasAttributes() ? method.Mod.Attributes : null);\n      }\n      PrintSpec(\"ensures\", method.Ens, ind);\n      PrintDecreasesSpec(method.Decreases, ind);\n\n      if (method.Body != null && !printSignatureOnly) {\n        Indent(indent);\n        PrintStatement(method.Body, indent);\n        wr.WriteLine();\n      }\n    }\n\n    void PrintKTypeIndication(FixpointPredicate.KType kType) {\n      switch (kType) {\n        case FixpointPredicate.KType.Nat:\n          wr.Write(\"[nat]\");\n          break;\n        case FixpointPredicate.KType.ORDINAL:\n          wr.Write(\"[ORDINAL]\");\n          break;\n        case FixpointPredicate.KType.Unspecified:\n          break;\n        default:\n          Contract.Assume(false);  // unexpected KType value\n          break;\n      }\n    }\n\n    internal void PrintFormals(List<Formal> ff, ICallable/*?*/ context, string name = null) {\n      Contract.Requires(ff != null);\n      if (name != null && name.EndsWith(\"#\")) {\n        wr.Write(\"[\");\n        PrintFormal(ff[0], false);\n        wr.Write(\"]\");\n        ff = new List<Formal>(ff.Skip(1));\n      }\n      wr.Write(\"(\");\n      string sep = \"\";\n      foreach (Formal f in ff) {\n        Contract.Assert(f != null);\n        wr.Write(sep);\n        sep = \", \";\n        PrintFormal(f, (context is TwoStateLemma || context is TwoStateFunction) && f.InParam);\n      }\n      wr.Write(\")\");\n    }\n\n    void PrintFormal(Formal f, bool showNewKeyword) {\n      Contract.Requires(f != null);\n      if (showNewKeyword && !f.IsOld) {\n        wr.Write(\"new \");\n      }\n      if (f.IsGhost) {\n        wr.Write(\"ghost \");\n      }\n      if (f.HasName) {\n        wr.Write(\"{0}: \", f.DisplayName);\n      }\n      PrintType(f.Type);\n    }\n\n    internal void PrintSpec(string kind, List<Expression> ee, int indent) {\n      Contract.Requires(kind != null);\n      Contract.Requires(ee != null);\n      foreach (Expression e in ee) {\n        Contract.Assert(e != null);\n        Indent(indent);\n        wr.Write(\"{0} \", kind);\n        PrintExpression(e, true);\n        wr.WriteLine();\n      }\n    }\n\n    internal void PrintDecreasesSpec(Specification<Expression> decs, int indent, bool newLine = true) {\n      Contract.Requires(decs != null);\n      if (printMode == ArmadaOptions.PrintModes.NoGhost) { return; }\n      if (decs.Expressions != null && decs.Expressions.Count != 0) {\n        Indent(indent);\n        wr.Write(\"decreases\");\n        if (decs.HasAttributes())\n        {\n          PrintAttributes(decs.Attributes);\n        }\n        wr.Write(\" \");\n        PrintExpressionList(decs.Expressions, true);\n        if (newLine) {\n          wr.WriteLine();\n        } else {\n          wr.Write(\" \");\n        }\n      }\n    }\n\n    internal void PrintFrameSpecLine(string kind, List<FrameExpression/*!*/> ee, int indent, Attributes attrs, bool newLine = true) {\n      Contract.Requires(kind != null);\n      Contract.Requires(cce.NonNullElements(ee));\n      if (ee != null && ee.Count != 0) {\n        Indent(indent);\n        wr.Write(\"{0}\", kind);\n        if (attrs != null) {\n          PrintAttributes(attrs);\n        }\n        wr.Write(\" \");\n        PrintFrameExpressionList(ee);\n        if (newLine) {\n          wr.WriteLine();\n        } else {\n          wr.Write(\" \");\n        }\n      }\n    }\n\n    internal void PrintSpec(string kind, List<MaybeFreeExpression> ee, int indent, bool newLine = true) {\n      Contract.Requires(kind != null);\n      Contract.Requires(ee != null);\n      if (printMode == ArmadaOptions.PrintModes.NoGhost) { return; }\n      foreach (MaybeFreeExpression e in ee) {\n        Contract.Assert(e != null);\n        Indent(indent);\n        wr.Write(\"{0}{1}\", e.IsFree ? \"free \" : \"\", kind);\n\n        if (e.HasAttributes()) {\n          PrintAttributes(e.Attributes);\n        }\n\n        wr.Write(\" \");\n        if (e.Label != null) {\n          wr.Write(\"{0}: \", e.Label.Name);\n        }\n        PrintExpression(e.E, true);\n        if (newLine) {\n          wr.WriteLine();\n        } else {\n          wr.Write(\" \");\n        }\n      }\n    }\n\n    // ----------------------------- PrintType -----------------------------\n\n    public void PrintType(Type ty) {\n      Contract.Requires(ty != null);\n      wr.Write(ty.TypeName(null, true));\n    }\n\n    public void PrintType(string prefix, Type ty) {\n      Contract.Requires(prefix != null);\n      Contract.Requires(ty != null);\n      if (ArmadaOptions.O.DafnyPrintResolvedFile != null) {\n        ty = ty.Normalize();\n      }\n      string s = ty.TypeName(null, true);\n      if (!(ty is TypeProxy) && !s.StartsWith(\"_\")) {\n        wr.Write(\"{0}{1}\", prefix, s);\n      }\n    }\n\n    public static string TPCharacteristicsSuffix(TypeParameter.TypeParameterCharacteristics characteristics) {\n      string s = null;\n      if (characteristics.EqualitySupport == TypeParameter.EqualitySupportValue.Required ||\n        (characteristics.EqualitySupport == TypeParameter.EqualitySupportValue.InferredRequired && ArmadaOptions.O.DafnyPrintResolvedFile != null)) {\n        s = \"==\";\n      }\n      if (characteristics.MustSupportZeroInitialization) {\n        var prefix = s == null ? \"\" : s + \",\";\n        s = prefix + \"0\";\n      }\n      if (characteristics.DisallowReferenceTypes) {\n        var prefix = s == null ? \"\" : s + \",\";\n        s = prefix + \"!new\";\n      }\n      if (s == null) {\n        return \"\";\n      } else {\n        return \"(\" + s + \")\";\n      }\n    }\n\n    bool ShowType(Type t) {\n      Contract.Requires(t != null);\n      return !(t is TypeProxy) || ArmadaOptions.O.DafnyPrintResolvedFile != null;\n    }\n\n    // ----------------------------- PrintStatement -----------------------------\n\n    /// <summary>\n    /// Prints from the current position of the current line.\n    /// If the statement requires several lines, subsequent lines are indented at \"indent\".\n    /// No newline is printed after the statement.\n    /// </summary>\n    public void PrintStatement(Statement stmt, int indent) {\n      Contract.Requires(stmt != null);\n\n      if (stmt.IsGhost && printMode == ArmadaOptions.PrintModes.NoGhost) { return; }\n      for (LList<Label> label = stmt.Labels; label != null; label = label.Next) {\n        if (label.Data.Name != null) {\n          wr.WriteLine(\"label {0}:\", label.Data.Name);\n          Indent(indent);\n        }\n      }\n\n      if (stmt is PredicateStmt) {\n        if (printMode == ArmadaOptions.PrintModes.NoGhost) { return; }\n        Expression expr = ((PredicateStmt)stmt).Expr;\n        var assertStmt = stmt as AssertStmt;\n        wr.Write(assertStmt != null ? \"assert\" : \"assume\");\n        if (stmt.Attributes != null) {\n          PrintAttributes(stmt.Attributes);\n        }\n        wr.Write(\" \");\n        if (assertStmt != null && assertStmt.Label != null) {\n          wr.Write(\"{0}: \", assertStmt.Label.Name);\n        }\n        PrintExpression(expr, true);\n        if (assertStmt != null && assertStmt.Proof != null) {\n          wr.Write(\" by \");\n          PrintStatement(assertStmt.Proof, indent);\n        } else {\n          wr.Write(\";\");\n        }\n\n      } else if (stmt is PrintStmt) {\n        PrintStmt s = (PrintStmt)stmt;\n        wr.Write(\"print\");\n        PrintAttributeArgs(s.Args, true);\n        wr.Write(\";\");\n\n      } else if (stmt is RevealStmt) {\n        var s = (RevealStmt)stmt;\n        wr.Write(\"reveal \");\n        var sep = \"\";\n        foreach (var e in s.Exprs) {\n          wr.Write(sep);\n          sep = \", \";\n          if (RevealStmt.SingleName(e) != null) {\n            // this will do the printing correctly for labels (or label-lookalikes) like 00_023 (which by PrintExpression below would be printed as 23)\n            wr.Write(RevealStmt.SingleName(e));\n          } else {\n            PrintExpression(e, true);\n          }\n        }\n        wr.Write(\";\");\n\n      } else if (stmt is SomehowStmt) {\n        SomehowStmt s = (SomehowStmt)stmt;\n        wr.Write(\"somehow \");\n        foreach (var e in s.UndefinedUnless) {\n            wr.Write(\"undefined_unless \");\n            PrintExpression(e, true);\n        }\n        foreach (var e in s.Mod.Expressions) {\n            wr.Write(\"modifies \");\n            if (s.Mod.Attributes != null) {\n                PrintAttributes(s.Mod.Attributes);\n            }\n            PrintExpression(e, true);\n        }\n        foreach (var e in s.Ens) {\n            wr.Write(\"ensures \");\n            PrintExpression(e, true);\n        }\n        wr.Write(\";\");\n\n      } else if (stmt is BreakStmt) {\n        BreakStmt s = (BreakStmt)stmt;\n        if (s.TargetLabel != null) {\n          wr.Write(\"break {0};\", s.TargetLabel);\n        } else {\n          string sep = \"\";\n          for (int i = 0; i < s.BreakCount; i++) {\n            wr.Write(\"{0}break\", sep);\n            sep = \" \";\n          }\n          wr.Write(\";\");\n        }\n\n      } else if (stmt is ContinueStmt) {\n        wr.Write(\"continue;\");\n\n      } else if (stmt is ProduceStmt) {\n        var s = (ProduceStmt) stmt;\n        wr.Write(s is YieldStmt ? \"yield\" : \"return\");\n        if (s.rhss != null) {\n          var sep = \" \";\n          foreach (var rhs in s.rhss) {\n            wr.Write(sep);\n            PrintRhs(rhs);\n            sep = \", \";\n          }\n        }\n          wr.Write(\";\");\n\n      } else if (stmt is AssignStmt) {\n        AssignStmt s = (AssignStmt)stmt;\n        PrintExpression(s.Lhs, true);\n        wr.Write(\" := \");\n        PrintRhs(s.Rhs);\n        wr.Write(\";\");\n\n      } else if (stmt is DividedBlockStmt) {\n        var sbs = (DividedBlockStmt)stmt;\n        wr.WriteLine(\"{\");\n        int ind = indent + IndentAmount;\n        foreach (Statement s in sbs.BodyInit) {\n          Indent(ind);\n          PrintStatement(s, ind);\n          wr.WriteLine();\n        }\n        if (sbs.BodyProper.Count != 0 || sbs.SeparatorTok != null) {\n          Indent(indent + IndentAmount);\n          wr.WriteLine(\"new;\");\n          foreach (Statement s in sbs.BodyProper) {\n            Indent(ind);\n            PrintStatement(s, ind);\n            wr.WriteLine();\n          }\n        }\n        Indent(indent);\n        wr.Write(\"}\");\n\n      } else if (stmt is BlockStmt) {\n        wr.WriteLine(\"{\");\n        int ind = indent + IndentAmount;\n        foreach (Statement s in ((BlockStmt)stmt).Body) {\n          Indent(ind);\n          PrintStatement(s, ind);\n          wr.WriteLine();\n        }\n        Indent(indent);\n        wr.Write(\"}\");\n\n      } else if (stmt is IfStmt) {\n        IfStmt s = (IfStmt)stmt;\n        PrintIfStatement(indent, s, false);\n\n      } else if (stmt is AlternativeStmt) {\n        var s = (AlternativeStmt)stmt;\n        if (s.UsesOptionalBraces) {\n          wr.Write(\"if {\");\n        } else {\n          wr.Write(\"if\");\n        }\n        PrintAlternatives(indent + (s.UsesOptionalBraces ? IndentAmount : 0), s.Alternatives);\n        if (s.UsesOptionalBraces) {\n          wr.WriteLine();\n          Indent(indent);\n          wr.Write(\"}\");\n        }\n\n      } else if (stmt is WhileStmt) {\n        WhileStmt s = (WhileStmt)stmt;\n        PrintWhileStatement(indent, s, false, false);\n\n      } else if (stmt is AlternativeLoopStmt) {\n        var s = (AlternativeLoopStmt)stmt;\n        wr.Write(\"while\");\n        if (s.Invariants.Count != 0) {\n          wr.WriteLine();\n          PrintSpec(\"invariant\", s.Invariants, indent + IndentAmount, false);\n        }\n        if (s.Decreases.Expressions != null && s.Decreases.Expressions.Count != 0) {\n          wr.WriteLine();\n          PrintDecreasesSpec(s.Decreases, indent + IndentAmount, false);\n        }\n\n        if (s.UsesOptionalBraces) {\n          wr.WriteLine();\n          Indent(indent);\n          wr.Write(\"{\");\n        }\n        PrintAlternatives(indent + (s.UsesOptionalBraces ? IndentAmount : 0), s.Alternatives);\n        if (s.UsesOptionalBraces) {\n          wr.WriteLine();\n          Indent(indent);\n          wr.Write(\"}\");\n        }\n\n      } else if (stmt is ForallStmt) {\n        var s = (ForallStmt)stmt;\n        if (ArmadaOptions.O.DafnyPrintResolvedFile != null && s.ForallExpressions != null) {\n          foreach (var expr in s.ForallExpressions) {\n            PrintExpression(expr, false, new string(' ', indent + IndentAmount) + \"ensures \");\n          }\n          if (s.Body != null) {\n            wr.WriteLine();\n            Indent(indent);\n          }\n        } else {\n          wr.Write(\"forall\");\n          if (s.BoundVars.Count != 0) {\n            wr.Write(\" \");\n            PrintQuantifierDomain(s.BoundVars, s.Attributes, s.Range);\n          }\n          if (s.Ens.Count == 0) {\n            wr.Write(\" \");\n          } else {\n            wr.WriteLine();\n            PrintSpec(\"ensures\", s.Ens, indent + IndentAmount, s.Body != null);\n            Indent(indent);\n          }\n        }\n        if (s.Body != null) {\n          PrintStatement(s.Body, indent);\n        }\n\n      } else if (stmt is ModifyStmt) {\n        var s = (ModifyStmt)stmt;\n        PrintModifyStmt(indent, s, false);\n\n      } else if (stmt is CalcStmt) {\n        CalcStmt s = (CalcStmt)stmt;\n        if (printMode == ArmadaOptions.PrintModes.NoGhost) { return; }   // Calcs don't get a \"ghost\" attribute, but they are.\n        wr.Write(\"calc \");\n        if (s.UserSuppliedOp != null) {\n          PrintCalcOp(s.UserSuppliedOp);\n          wr.Write(\" \");\n        } else if (ArmadaOptions.O.DafnyPrintResolvedFile != null && s.Op != null) {\n          PrintCalcOp(s.Op);\n          wr.Write(\" \");\n        }\n        wr.WriteLine(\"{\");\n        int lineInd = indent + IndentAmount;\n        int lineCount = s.Lines.Count == 0 ? 0 : s.Lines.Count - 1;  // if nonempty, .Lines always contains a duplicated last line\n        // The number of op/hints is commonly one less than the number of lines, but\n        // it can also equal the number of lines for empty calc's and for calc's with\n        // a dangling hint.\n        int hintCount = s.Lines.Count != 0 && s.Hints.Last().Body.Count == 0 ? lineCount - 1 : lineCount;\n        for (var i = 0; i < lineCount; i++) {\n          var e = s.Lines[i];\n          var op = s.StepOps[i];\n          var h = s.Hints[i];\n          // print the line\n          Indent(lineInd);\n          PrintExpression(e, true, lineInd);\n          wr.WriteLine(\";\");\n          if (i == hintCount) {\n            break;\n          }\n          // print the operator, if any\n          if (op != null || (ArmadaOptions.O.DafnyPrintResolvedFile != null && s.Op != null)) {\n            Indent(indent);  // this lines up with the \"calc\"\n            PrintCalcOp(op ?? s.Op);\n            wr.WriteLine();\n          }\n          // print the hints\n          foreach (var st in h.Body) {\n            Indent(lineInd);\n            PrintStatement(st, lineInd);\n            wr.WriteLine();\n          }\n        }\n        Indent(indent);\n        wr.Write(\"}\");\n\n      } else if (stmt is MatchStmt) {\n        var s = (MatchStmt)stmt;\n        if (ArmadaOptions.O.DafnyPrintResolvedFile == null && s.OrigUnresolved != null) {\n          PrintStatement(s.OrigUnresolved, indent);\n        } else {\n          wr.Write(\"match \");\n          PrintExpression(s.Source, false);\n          if (s.UsesOptionalBraces) {\n            wr.Write(\" {\");\n          }\n          int caseInd = indent + (s.UsesOptionalBraces ? IndentAmount : 0);\n          foreach (MatchCaseStmt mc in s.Cases) {\n            wr.WriteLine();\n            Indent(caseInd);\n            wr.Write(\"case {0}\", mc.Id);\n            PrintMatchCaseArgument(mc);\n            wr.Write(\" =>\");\n            foreach (Statement bs in mc.Body) {\n              wr.WriteLine();\n              Indent(caseInd + IndentAmount);\n              PrintStatement(bs, caseInd + IndentAmount);\n            }\n          }\n          if (s.UsesOptionalBraces) {\n            wr.WriteLine();\n            Indent(indent);\n            wr.Write(\"}\");\n          }\n        }\n\n      } else if (stmt is ConcreteUpdateStatement) {\n        var s = (ConcreteUpdateStatement)stmt;\n        string sep = \"\";\n        foreach (var lhs in s.Lhss) {\n          wr.Write(sep);\n          PrintExpression(lhs, true);\n          sep = \", \";\n        }\n        if (s.Lhss.Count > 0) {\n          wr.Write(\" \");\n        }\n        PrintUpdateRHS(s, indent);\n        wr.Write(\";\");\n\n      } else if (stmt is CallStmt) {\n        // Most calls are printed from their concrete syntax given in the input. However, recursive calls to\n        // prefix lemmas end up as CallStmt's by the end of resolution and they may need to be printed here.\n        var s = (CallStmt)stmt;\n        PrintExpression(s.MethodSelect, false);\n        PrintActualArguments(s.Args, s.Method.Name);\n\n      } else if (stmt is VarDeclStmt) {\n        var s = (VarDeclStmt)stmt;\n        if (s.Locals.Exists(v => v.IsGhost) && printMode == ArmadaOptions.PrintModes.NoGhost) { return; }\n        if (s.Locals.Exists(v => v.IsGhost)) {\n          wr.Write(\"ghost \");\n        }\n        wr.Write(\"var\");\n        string sep = \"\";\n        foreach (var local in s.Locals) {\n          wr.Write(sep);\n          if (local.Attributes != null) {\n            PrintAttributes(local.Attributes);\n          }\n          wr.Write(\" {0}\", local.DisplayName);\n          PrintType(\": \", local.OptionalType);\n          sep = \",\";\n        }\n        if (s.Update != null) {\n          wr.Write(\" \");\n          PrintUpdateRHS(s.Update, indent);\n        }\n        wr.Write(\";\");\n\n      } else if (stmt is LetStmt) {\n        var s = (LetStmt)stmt;\n        wr.Write(\"var \");\n        PrintCasePattern(s.LHS);\n        wr.Write(\" := \");\n        PrintExpression(s.RHS, true);\n        wr.WriteLine(\";\");\n\n      } else if (stmt is SkeletonStatement) {\n        var s = (SkeletonStatement)stmt;\n        if (s.S == null) {\n          wr.Write(\"...;\");\n        } else if (s.S is AssertStmt) {\n          Contract.Assert(s.ConditionOmitted);\n          wr.Write(\"assert ...;\");\n        } else if (s.S is AssumeStmt) {\n          Contract.Assert(s.ConditionOmitted);\n          wr.Write(\"assume ...;\");\n        } else if (s.S is IfStmt) {\n          PrintIfStatement(indent, (IfStmt)s.S, s.ConditionOmitted);\n        } else if (s.S is WhileStmt) {\n          PrintWhileStatement(indent, (WhileStmt)s.S, s.ConditionOmitted, s.BodyOmitted);\n        } else if (s.S is ModifyStmt) {\n          PrintModifyStmt(indent, (ModifyStmt)s.S, true);\n        } else {\n          Contract.Assert(false); throw new cce.UnreachableException();  // unexpected skeleton statement\n        }\n\n      } else if (stmt is CommitStmt) {\n        var s = (CommitStmt)stmt;\n        wr.Write(\"commit \");\n        PrintStatement(s.Body, indent);\n\n      } else if (stmt is JoinStmt) {\n        var s = (JoinStmt)stmt;\n        wr.Write(\"join \");\n        PrintExpression(s.WhichThread, true);\n        wr.Write(\";\");\n\n      } else if (stmt is GotoStmt) {\n        var s = (GotoStmt)stmt;\n        wr.Write($\"goto {s.Target};\");\n\n      } else {\n        Contract.Assert(false); throw new cce.UnreachableException();  // unexpected statement\n      }\n    }\n\n    private void PrintModifyStmt(int indent, ModifyStmt s, bool omitFrame) {\n      Contract.Requires(0 <= indent);\n      Contract.Requires(s != null);\n      Contract.Requires(!omitFrame || s.Mod.Expressions.Count == 0);\n\n      wr.Write(\"modify\");\n      PrintAttributes(s.Mod.Attributes);\n      wr.Write(\" \");\n      if (omitFrame) {\n        wr.Write(\"...\");\n      } else {\n        PrintFrameExpressionList(s.Mod.Expressions);\n      }\n      if (s.Body != null) {\n        // There's a possible syntactic ambiguity, namely if the frame is empty (more precisely,\n        // if s.Mod.Expressions.Count is 0).  Since the statement was parsed at some point, this\n        // situation can occur only if the modify statement inherited its frame by refinement\n        // and we're printing the post-resolve AST.  In this special case, print an explicit\n        // empty set as the frame.\n        if (s.Mod.Expressions.Count == 0) {\n          wr.Write(\" {}\");\n        }\n        wr.Write(\" \");\n        PrintStatement(s.Body, indent);\n      } else {\n        wr.Write(\";\");\n      }\n    }\n\n    /// <summary>\n    /// Does not print LHS, nor the space one might want between LHS and RHS,\n    /// because if there's no LHS, we don't want to start with a space\n    /// </summary>\n    void PrintUpdateRHS(ConcreteUpdateStatement s, int indent) {\n      Contract.Requires(s != null);\n      if (s is UpdateStmt) {\n        var update = (UpdateStmt)s;\n        if (update.Lhss.Count != 0) {\n          wr.Write(\":= \");\n        }\n        var sep = \"\";\n        foreach (var rhs in update.Rhss) {\n          wr.Write(sep);\n          PrintRhs(rhs);\n          sep = \", \";\n        }\n      } else if (s is AssignSuchThatStmt) {\n        var update = (AssignSuchThatStmt)s;\n        wr.Write(\":| \");\n        if (update.AssumeToken != null) {\n          wr.Write(\"assume \");\n        }\n        PrintExpression(update.Expr, true);\n      } else if (s is AssignOrReturnStmt) {\n        var stmt = (AssignOrReturnStmt)s;\n        wr.Write(\":- \");\n        PrintExpression(stmt.Rhs, true);\n        if (ArmadaOptions.O.DafnyPrintResolvedFile != null) {\n          Contract.Assert(stmt.ResolvedStatements.Count > 0);  // filled in during resolution\n          wr.WriteLine();\n          Indent(indent); wr.WriteLine(\"/*---------- desugared ----------\");\n          foreach (Statement r in stmt.ResolvedStatements) {\n            Indent(indent);\n            PrintStatement(r, indent);\n            wr.WriteLine();\n          }\n          Indent(indent); wr.Write(\"---------- end desugared ----------*/\");\n        }\n\n      } else {\n        Contract.Assert(false);  // otherwise, unknown type\n      }\n    }\n\n    void PrintIfStatement(int indent, IfStmt s, bool omitGuard) {\n      if (omitGuard) {\n        wr.Write(\"if ... \");\n      } else {\n        wr.Write(\"if \");\n        PrintGuard(s.IsBindingGuard, s.Guard);\n        wr.Write(\" \");\n      }\n      PrintStatement(s.Thn, indent);\n      if (s.Els != null) {\n        wr.Write(\" else \");\n        PrintStatement(s.Els, indent);\n      }\n    }\n\n    void PrintWhileStatement(int indent, WhileStmt s, bool omitGuard, bool omitBody) {\n      Contract.Requires(0 <= indent);\n      if (omitGuard) {\n        wr.WriteLine(\"while ...\");\n      } else {\n        wr.Write(\"while \");\n        PrintGuard(false, s.Guard);\n        wr.WriteLine();\n      }\n\n      PrintSpec(\"invariant\", s.Invariants, indent + IndentAmount, s.Body != null || omitBody || (s.Decreases.Expressions != null && s.Decreases.Expressions.Count != 0) || (s.Mod.Expressions != null && s.Mod.Expressions.Count != 0));\n      PrintDecreasesSpec(s.Decreases, indent + IndentAmount, s.Body != null || omitBody || (s.Mod.Expressions != null && s.Mod.Expressions.Count != 0));\n      if (s.Mod.Expressions != null) {\n        PrintFrameSpecLine(\"modifies\", s.Mod.Expressions, indent + IndentAmount, s.Mod.HasAttributes() ? s.Mod.Attributes : null, s.Body != null || omitBody);\n      }\n      Indent(indent);\n      if (omitBody) {\n        wr.WriteLine(\"...;\");\n      } else if (s.Body != null) {\n        PrintStatement(s.Body, indent);\n      }\n    }\n\n    void PrintAlternatives(int indent, List<GuardedAlternative> alternatives) {\n      foreach (var alternative in alternatives) {\n        wr.WriteLine();\n        Indent(indent);\n        wr.Write(\"case \");\n        if (alternative.IsBindingGuard) {\n          var exists = (ExistsExpr)alternative.Guard;\n          PrintBindingGuard(exists);\n        } else {\n          PrintExpression(alternative.Guard, false);\n        }\n        wr.Write(\" =>\");\n        foreach (Statement s in alternative.Body) {\n          wr.WriteLine();\n          Indent(indent + IndentAmount);\n          PrintStatement(s, indent + IndentAmount);\n        }\n      }\n    }\n\n    void PrintRhs(AssignmentRhs rhs) {\n      Contract.Requires(rhs != null);\n      if (rhs is ExprRhs) {\n        PrintExpression(((ExprRhs)rhs).Expr, true);\n      } else if (rhs is HavocRhs) {\n        wr.Write(\"*\");\n      } else if (rhs is TypeRhs) {\n        TypeRhs t = (TypeRhs)rhs;\n        wr.Write(\"new \");\n        if (t.ArrayDimensions != null) {\n          if (ShowType(t.EType)) {\n            PrintType(t.EType);\n          }\n          var dim0 = t.ArrayDimensions[0] as LiteralExpr;\n          if (ArmadaOptions.O.DafnyPrintResolvedFile == null &&\n            t.InitDisplay != null &&\n            t.ArrayDimensions.Count == 1 && dim0.Value is BigInteger &&\n            (BigInteger)dim0.Value == new BigInteger(t.InitDisplay.Count)) {\n            // elide the size\n            wr.Write(\"[]\");\n          } else {\n            string s = \"[\";\n            foreach (Expression dim in t.ArrayDimensions) {\n              Contract.Assume(dim != null);\n              wr.Write(s);\n              PrintExpression(dim, false);\n              s = \", \";\n            }\n            wr.Write(\"]\");\n          }\n          if (t.ElementInit != null) {\n            wr.Write(\" (\");\n            PrintExpression(t.ElementInit, false);\n            wr.Write(\")\");\n          } else if (t.InitDisplay != null) {\n            wr.Write(\" [\");\n            PrintExpressionList(t.InitDisplay, false);\n            wr.Write(\"]\");\n          }\n        } else if (t.Arguments == null) {\n          PrintType(t.EType);\n        } else {\n          PrintType(t.Path);\n          wr.Write(\"(\");\n          PrintExpressionList(t.Arguments, false);\n          wr.Write(\")\");\n        }\n      } else if (rhs is CreateThreadRhs) {\n        var ctr = (CreateThreadRhs)rhs;\n        wr.Write($\"create_thread {ctr.MethodName}(\");\n        PrintExpressionList(ctr.Args, false);\n        wr.Write(\")\");\n      } else if (rhs is CompareAndSwapRhs) {\n        var csr = (CompareAndSwapRhs)rhs;\n        wr.Write(\"compare_and_swap (\");\n        PrintExpression(csr.Target, false);\n        wr.Write(\", \");\n        PrintExpression(csr.OldVal, false);\n        wr.Write(\", \");\n        PrintExpression(csr.NewVal, false);\n        wr.Write(\")\");\n      } else if (rhs is AtomicExchangeRhs) {\n        var aer = (AtomicExchangeRhs)rhs;\n        wr.Write(\"atomic_exchange (\");\n        PrintExpression(aer.Target, false);\n        wr.Write(\", \");\n        PrintExpression(aer.NewVal, false);\n        wr.Write(\")\");\n      } else if (rhs is MallocRhs) {\n        var mr = (MallocRhs)rhs;\n        wr.Write($\"malloc({mr.AllocatedType})\");\n      } else if (rhs is CallocRhs) {\n        var cr = (CallocRhs)rhs;\n        wr.Write($\"calloc({cr.AllocatedType}, \");\n        PrintExpression(cr.Count, false);\n        wr.Write(\")\");\n      } else {\n        Contract.Assert(false); throw new cce.UnreachableException();  // unexpected RHS\n      }\n\n      if (rhs.HasAttributes())\n      {\n        PrintAttributes(rhs.Attributes);\n      }\n    }\n\n    void PrintGuard(bool isBindingGuard, Expression guard) {\n      Contract.Requires(!isBindingGuard || (guard is ExistsExpr && ((ExistsExpr)guard).Range == null));\n      if (guard == null) {\n        wr.Write(\"*\");\n      } else if (isBindingGuard) {\n        var exists = (ExistsExpr)guard;\n        PrintBindingGuard(exists);\n      } else {\n        PrintExpression(guard, false);\n      }\n    }\n\n    void PrintBindingGuard(ExistsExpr guard) {\n      Contract.Requires(guard != null);\n      Contract.Requires(guard.Range == null);\n      PrintQuantifierDomain(guard.BoundVars, guard.Attributes, null);\n      wr.Write(\" :| \");\n      PrintExpression(guard.Term, false);\n    }\n\n    void PrintCalcOp(CalcStmt.CalcOp op) {\n      Contract.Requires(op != null);\n      wr.Write(op.ToString());\n      if (op is CalcStmt.TernaryCalcOp) {\n        wr.Write(\"[\");\n        PrintExpression(((CalcStmt.TernaryCalcOp) op).Index, false);\n        wr.Write(\"]\");\n      }\n    }\n\n    // ----------------------------- PrintExpression -----------------------------\n\n    /// <summary>\n    /// PrintExtendedExpr prints an expression, but formats top-level if-then-else and match expressions across several lines.\n    /// Its intended use is thus to print the body of a function.\n    /// </summary>\n    public void PrintExtendedExpr(Expression expr, int indent, bool isRightmost, bool endWithCloseParen, int contextBindingStrength, bool fragileContext) {\n      Contract.Requires(expr != null);\n      if (expr is ITEExpr) {\n        while (true) {\n          var ite = (ITEExpr)expr;\n          wr.Write(\"if \");\n          PrintExpression(ite.Test, false);\n          wr.WriteLine(\" then\");\n          Indent(indent + IndentAmount);\n          PrintExtendedExpr(ite.Thn, indent + IndentAmount, true, false, 0, false);\n          expr = ite.Els;\n          if (expr is ITEExpr) {\n            Indent(indent); wr.Write(\"else \");\n          } else {\n            Indent(indent); wr.WriteLine(\"else\");\n            Indent(indent + IndentAmount);\n            PrintExpression(expr, isRightmost, false);\n            wr.WriteLine(endWithCloseParen ? \")\" : \"\");\n            return;\n          }\n        }\n      } else if (expr is MatchExpr) {\n        var e = (MatchExpr)expr;\n        if (ArmadaOptions.O.DafnyPrintResolvedFile == null && e.OrigUnresolved != null) {\n          PrintExtendedExpr(e.OrigUnresolved, indent, isRightmost, endWithCloseParen, 0, false);\n        } else {\n          var parensNeeded = !isRightmost && !e.UsesOptionalBraces;\n          if (parensNeeded) { wr.Write(\"(\"); }\n          wr.Write(\"match \");\n          PrintExpression(e.Source, isRightmost && e.Cases.Count == 0, false);\n          if (e.UsesOptionalBraces) { wr.WriteLine(\" {\"); } else if (parensNeeded && e.Cases.Count == 0) { wr.WriteLine(\")\"); } else { wr.WriteLine(); }\n          int i = 0;\n          int ind = indent + (e.UsesOptionalBraces ? IndentAmount : 0);\n          foreach (var mc in e.Cases) {\n            bool isLastCase = i == e.Cases.Count - 1;\n            Indent(ind);\n            wr.Write(\"case {0}\", mc.Id);\n            PrintMatchCaseArgument(mc);\n            wr.WriteLine(\" =>\");\n            Indent(ind + IndentAmount);\n            PrintExtendedExpr(mc.Body, ind + IndentAmount, isLastCase, isLastCase && (parensNeeded || endWithCloseParen), 0, false);\n            i++;\n          }\n          if (e.UsesOptionalBraces) {\n            Indent(indent);\n            wr.WriteLine(\"}\");\n          }\n        }\n      } else if (expr is LetExpr) {\n        var e = (LetExpr)expr;\n        wr.Write(\"var \");\n        string sep = \"\";\n        foreach (var lhs in e.LHSs) {\n          wr.Write(sep);\n          PrintCasePattern(lhs);\n          sep = \", \";\n        }\n        if (e.Exact) {\n          wr.Write(\" := \");\n        } else {\n          wr.Write(\" :| \");\n        }\n        PrintExpressionList(e.RHSs, true);\n        wr.WriteLine(\";\");\n        Indent(indent);\n        PrintExtendedExpr(e.Body, indent, isRightmost, endWithCloseParen, 0, false);\n      } else if (expr is StmtExpr && isRightmost) {\n        var e = (StmtExpr)expr;\n        PrintStatement(e.S, indent);\n        wr.WriteLine();\n        Indent(indent);\n        PrintExtendedExpr(e.E, indent, isRightmost, endWithCloseParen, 0, false);\n      } else if (expr is ParensExpression) {\n        PrintExtendedExpr(((ParensExpression)expr).E, indent, isRightmost, endWithCloseParen, 0, false);\n      } else if (expr is BinaryExpr && (expr as BinaryExpr).Op == BinaryExpr.Opcode.And) {\n        var e = (BinaryExpr)expr;\n        if (e.E0 is BinaryExpr && (e.E0 as BinaryExpr).Op == BinaryExpr.Opcode.And) {\n          PrintExtendedExpr(e.E0, indent, false, false, 0x20, true);\n        } else {\n          wr.Write(\"&& \");\n          PrintExpr(e.E0, 0x20, true, false, false, indent + IndentAmount);\n          wr.WriteLine();\n          //PrintExtendedExpr(e.E0, indent + IndentAmount, false, false, 0x20, true);\n        }\n        Indent(indent);\n        wr.Write(\"&& \");\n        PrintExpr(e.E1, 0x20, true, isRightmost, false, indent + IndentAmount);\n        wr.WriteLine(endWithCloseParen ? \")\" : \"\");\n        //PrintExtendedExpr(e.E1, indent + IndentAmount, isRightmost, endWithCloseParen, 0x20, true);\n      }\n      else {\n        PrintExpr(expr, contextBindingStrength, fragileContext, isRightmost, false, indent);\n        wr.WriteLine(endWithCloseParen ? \")\" : \"\");\n      }\n    }\n\n    public void PrintMatchCaseArgument(MatchCase mc) {\n      if (mc.Arguments != null) {\n        if (mc.Arguments.Count != 0) {\n          string sep = \"(\";\n          foreach (BoundVar bv in mc.Arguments) {\n            wr.Write(\"{0}{1}\", sep, bv.DisplayName);\n            string typeName = bv.Type.TypeName(null, true);\n            if (bv.Type is NonProxyType && !typeName.StartsWith(\"_\")) {\n              wr.Write(\": {0}\", typeName);\n            }\n            sep = \", \";\n          }\n          wr.Write(\")\");\n        }\n      } else {\n        Contract.Assert(mc.CasePatterns != null);\n        if (mc.CasePatterns.Count != 0) {\n          string sep = \"(\";\n          foreach (var cp in mc.CasePatterns) {\n            wr.Write(sep);\n            PrintCasePattern(cp);\n            sep = \", \";\n          }\n          wr.Write(\")\");\n        }\n      }\n    }\n\n    public void PrintExpression(Expression expr, bool isFollowedBySemicolon) {\n      Contract.Requires(expr != null);\n      PrintExpr(expr, 0, false, true, isFollowedBySemicolon, -1);\n    }\n\n    public void PrintExpression(Expression expr, bool isRightmost, bool isFollowedBySemicolon) {\n      Contract.Requires(expr != null);\n      PrintExpr(expr, 0, false, isRightmost, isFollowedBySemicolon, -1);\n    }\n\n    /// <summary>\n    /// An indent of -1 means print the entire expression on one line.\n    /// </summary>\n    public void PrintExpression(Expression expr, bool isFollowedBySemicolon, int indent) {\n      Contract.Requires(expr != null);\n      PrintExpr(expr, 0, false, true, isFollowedBySemicolon, indent);\n    }\n\n    public void PrintExpression(Expression expr, bool isRightmost, bool isFollowedBySemicolon, int indent) {\n      Contract.Requires(expr != null);\n      PrintExpr(expr, 0, false, isRightmost, isFollowedBySemicolon, indent);\n    }\n\n    public void PrintExpression(Expression expr, bool isFollowedBySemicolon, string keyword) {\n      Contract.Requires(expr != null);\n      PrintExpr(expr, 0, false, true, isFollowedBySemicolon, -1, keyword);\n    }\n\n    private bool ParensNeeded(int opBindingStrength, int contextBindingStrength, bool fragileContext) {\n      return opBindingStrength < contextBindingStrength ||\n             (fragileContext && opBindingStrength == contextBindingStrength);\n    }\n\n    /// <summary>\n    /// An indent of -1 means print the entire expression on one line.\n    /// </summary>\n    void PrintExpr(Expression expr, int contextBindingStrength, bool fragileContext, bool isRightmost, bool isFollowedBySemicolon, int indent, string keyword = null, int resolv_count = 2 )\n    {\n      Contract.Requires(-1 <= indent);\n      Contract.Requires(expr != null);\n\n      /* When debugging:\n      if (resolv_count > 0 && expr.Resolved != null) {\n        PrintExpr(expr.Resolved, contextBindingStrength, fragileContext, isRightmost, isFollowedBySemicolon, indent, resolv_count - 1);\n        return;\n      }\n      */\n\n      if (expr is StaticReceiverExpr) {\n        StaticReceiverExpr e = (StaticReceiverExpr)expr;\n        wr.Write(e.Type);\n      } else if (expr is LiteralExpr) {\n        LiteralExpr e = (LiteralExpr)expr;\n        if (e.Value == null) {\n          wr.Write(\"null\");\n        } else if (e.Value is bool) {\n          wr.Write((bool)e.Value ? \"true\" : \"false\");\n        } else if (e is CharLiteralExpr) {\n          wr.Write(\"'{0}'\", (string)e.Value);\n        } else if (e is StringLiteralExpr) {\n          var str = (StringLiteralExpr)e;\n          wr.Write(\"{0}\\\"{1}\\\"\", str.IsVerbatim ? \"@\" : \"\", (string)e.Value);\n        } else if (e.Value is BaseTypes.BigDec) {\n          BaseTypes.BigDec dec = (BaseTypes.BigDec)e.Value;\n          wr.Write((dec.Mantissa >= 0) ? \"\" : \"-\");\n          string s = BigInteger.Abs(dec.Mantissa).ToString();\n          int digits = s.Length;\n          if (dec.Exponent >= 0) {\n            wr.Write(\"{0}{1}.0\", s, new string('0', dec.Exponent));\n          } else {\n            int exp = -dec.Exponent;\n            if (exp < digits) {\n              int intDigits = digits - exp;\n              int fracDigits = digits - intDigits;\n              wr.Write(\"{0}.{1}\", s.Substring(0, intDigits), s.Substring(intDigits, fracDigits));\n            } else {\n              int fracDigits = digits;\n              wr.Write(\"0.{0}{1}\", new string('0', exp - fracDigits), s.Substring(0, fracDigits));\n            }\n          }\n        } else {\n          wr.Write((BigInteger)e.Value);\n        }\n\n      } else if (expr is ThisExpr) {\n        wr.Write(\"this\");\n\n      } else if (expr is IdentifierExpr) {\n        wr.Write(((IdentifierExpr)expr).Name);\n\n      } else if (expr is DatatypeValue) {\n        var dtv = (DatatypeValue)expr;\n        bool printParens;\n        if (dtv.MemberName.StartsWith(BuiltIns.TupleTypeCtorNamePrefix)) {\n          // we're looking at a tuple, whose printed constructor name is essentially the empty string\n          printParens = true;\n        } else {\n          wr.Write(\"{0}.{1}\", dtv.DatatypeName, dtv.MemberName);\n          printParens = dtv.Arguments.Count != 0;\n        }\n        if (printParens) {\n          wr.Write(\"(\");\n          PrintExpressionList(dtv.Arguments, false);\n          wr.Write(\")\");\n        }\n\n      } else if (expr is DisplayExpression) {\n        DisplayExpression e = (DisplayExpression)expr;\n        if (e is MultiSetDisplayExpr) {\n          wr.Write(\"multiset\");\n        } else if (e is SetDisplayExpr && !((SetDisplayExpr)e).Finite) {\n          wr.Write(\"iset\");\n        }\n        wr.Write(e is SetDisplayExpr || e is MultiSetDisplayExpr ? \"{\" : \"[\");\n        PrintExpressionList(e.Elements, false);\n        wr.Write(e is SetDisplayExpr || e is MultiSetDisplayExpr ? \"}\" : \"]\");\n\n      } else if (expr is MapDisplayExpr) {\n        MapDisplayExpr e = (MapDisplayExpr)expr;\n        wr.Write(e.Finite ? \"map\" : \"imap\");\n        wr.Write(\"[\");\n        PrintExpressionPairList(e.Elements);\n        wr.Write(\"]\");\n\n      } else if (expr is NameSegment) {\n        var e = (NameSegment)expr;\n        wr.Write(e.Name);\n        PrintTypeInstantiation(e.OptTypeArguments);\n\n      } else if (expr is ExprDotName) {\n        var e = (ExprDotName)expr;\n        // determine if parens are needed\n        int opBindingStrength = 0x90;\n        bool parensNeeded = !e.Lhs.IsImplicit && // KRML: I think that this never holds\n          ParensNeeded(opBindingStrength, contextBindingStrength, fragileContext);\n\n        if (parensNeeded) { wr.Write(\"(\"); }\n        if (!e.Lhs.IsImplicit) {\n          PrintExpr(e.Lhs, opBindingStrength, false, false, !parensNeeded && isFollowedBySemicolon, -1, keyword);\n          wr.Write(\".\");\n        }\n        wr.Write(e.SuffixName);\n        PrintTypeInstantiation(e.OptTypeArguments);\n        if (parensNeeded) { wr.Write(\")\"); }\n\n      } else if (expr is ApplySuffix) {\n        var e = (ApplySuffix)expr;\n        // determine if parens are needed\n        int opBindingStrength = 0x90;\n        bool parensNeeded = !e.Lhs.IsImplicit &&  // KRML: I think that this never holds\n          ParensNeeded(opBindingStrength, contextBindingStrength, fragileContext);\n\n        if (parensNeeded) { wr.Write(\"(\"); }\n        if (ParensMayMatter(e.Lhs)) {\n          wr.Write(\"(\");\n          PrintExpression(e.Lhs, false);\n          wr.Write(\")\");\n        } else {\n          PrintExpr(e.Lhs, opBindingStrength, false, false, !parensNeeded && isFollowedBySemicolon, -1, keyword);\n        }\n        string name = e.Lhs is NameSegment ? ((NameSegment)e.Lhs).Name : e.Lhs is ExprDotName ? ((ExprDotName)e.Lhs).SuffixName : null;\n        PrintActualArguments(e.Args, name);\n        if (parensNeeded) { wr.Write(\")\"); }\n\n      } else if (expr is RevealExpr) {\n        var e = (RevealExpr)expr;\n        wr.Write(\"reveal \");\n        PrintExpression(e.Expr, true);\n\n      } else if (expr is MemberSelectExpr) {\n        MemberSelectExpr e = (MemberSelectExpr)expr;\n        // determine if parens are needed\n        int opBindingStrength = 0x90;\n        bool parensNeeded = !e.Obj.IsImplicit &&\n          ParensNeeded(opBindingStrength, contextBindingStrength, fragileContext);\n\n        if (parensNeeded) { wr.Write(\"(\"); }\n        if (!(e.Obj.IsImplicit)) {\n          PrintExpr(e.Obj, opBindingStrength, false, false, !parensNeeded && isFollowedBySemicolon, -1, keyword);\n          wr.Write(\".\");\n        }\n        wr.Write(e.MemberName);\n        if (parensNeeded) { wr.Write(\")\"); }\n\n      } else if (expr is SeqSelectExpr) {\n        SeqSelectExpr e = (SeqSelectExpr)expr;\n        // determine if parens are needed\n        int opBindingStrength = 0x90;\n        bool parensNeeded = ParensNeeded(opBindingStrength, contextBindingStrength, fragileContext);\n\n        if (parensNeeded) { wr.Write(\"(\"); }\n        PrintExpr(e.Seq, opBindingStrength, false, false, !parensNeeded && isFollowedBySemicolon, indent, keyword);\n        wr.Write(\"[\");\n        if (e.SelectOne) {\n          Contract.Assert(e.E0 != null);\n          PrintExpression(e.E0, false);\n        } else {\n          if (e.E0 != null) {\n            PrintExpression(e.E0, false);\n          }\n          wr.Write(e.E0 != null && e.E1 != null ? \" .. \" : \"..\");\n          if (e.E1 != null) {\n            PrintExpression(e.E1, false);\n          }\n        }\n        wr.Write(\"]\");\n        if (parensNeeded) { wr.Write(\")\"); }\n\n      } else if (expr is MultiSelectExpr) {\n        MultiSelectExpr e = (MultiSelectExpr)expr;\n        // determine if parens are needed\n        int opBindingStrength = 0x90;\n        bool parensNeeded = ParensNeeded(opBindingStrength, contextBindingStrength, fragileContext);\n\n        if (parensNeeded) { wr.Write(\"(\"); }\n        PrintExpr(e.Array, opBindingStrength, false, false, !parensNeeded && isFollowedBySemicolon, indent, keyword);\n        string prefix = \"[\";\n        foreach (Expression idx in e.Indices) {\n          Contract.Assert(idx != null);\n          wr.Write(prefix);\n          PrintExpression(idx, false);\n          prefix = \", \";\n        }\n        wr.Write(\"]\");\n        if (parensNeeded) { wr.Write(\")\"); }\n\n      } else if (expr is SeqUpdateExpr) {\n        SeqUpdateExpr e = (SeqUpdateExpr)expr;\n        if (e.ResolvedUpdateExpr != null) {\n          PrintExpr(e.ResolvedUpdateExpr, contextBindingStrength, fragileContext, isRightmost, isFollowedBySemicolon, indent, keyword);\n        } else {\n          // determine if parens are needed\n          int opBindingStrength = 0x90;\n          bool parensNeeded = ParensNeeded(opBindingStrength, contextBindingStrength, fragileContext);\n\n          if (parensNeeded) { wr.Write(\"(\"); }\n          PrintExpr(e.Seq, opBindingStrength, false, false, !parensNeeded && isFollowedBySemicolon, indent, keyword);\n          wr.Write(\"[\");\n          PrintExpression(e.Index, false);\n          wr.Write(\" := \");\n          PrintExpression(e.Value, false);\n          wr.Write(\"]\");\n          if (parensNeeded) { wr.Write(\")\"); }\n        }\n\n      } else if (expr is DatatypeUpdateExpr) {\n        var e = (DatatypeUpdateExpr)expr;\n        // determine if parens are needed\n        int opBindingStrength = 0x90;\n        bool parensNeeded = ParensNeeded(opBindingStrength, contextBindingStrength, fragileContext);\n\n        if (parensNeeded) { wr.Write(\"(\"); }\n        PrintExpr(e.Root, opBindingStrength, false, false, !parensNeeded && isFollowedBySemicolon, indent, keyword);\n        wr.Write(\".(\");\n        var sep = \"\";\n        foreach (var update in e.Updates) {\n          wr.Write(\"{0}{1} := \", sep, update.Item2);\n          PrintExpression(update.Item3, false);\n          sep = \", \";\n        }\n        wr.Write(\")\");\n        if (ArmadaOptions.O.DafnyPrintResolvedFile != null && ArmadaOptions.O.PrintMode == ArmadaOptions.PrintModes.Everything) {\n          if (e.ResolvedExpression != null) {\n            wr.Write(\"/*\");\n            PrintExpression(e.ResolvedExpression, false);\n            wr.Write(\"*/\");\n          }\n        }\n        if (parensNeeded) { wr.Write(\")\"); }\n\n      } else if (expr is ApplyExpr) {\n        var e = (ApplyExpr)expr;\n        // determine if parens are needed\n        int opBindingStrength = 0x90;\n        bool parensNeeded = ParensNeeded(opBindingStrength, contextBindingStrength, fragileContext);\n\n        if (parensNeeded) { wr.Write(\"(\"); }\n\n        PrintExpr(e.Function, opBindingStrength, false, false, !parensNeeded && isFollowedBySemicolon, -1, keyword);\n        wr.Write(\"(\");\n        PrintExpressionList(e.Args, false);\n        wr.Write(\")\");\n\n        if (parensNeeded) { wr.Write(\")\"); }\n\n      } else if (expr is FunctionCallExpr) {\n        var e = (FunctionCallExpr)expr;\n        // determine if parens are needed\n        int opBindingStrength = 0x90;\n        bool parensNeeded = !(e.Receiver.IsImplicit) &&\n          ParensNeeded(opBindingStrength, contextBindingStrength, fragileContext);\n\n        if (parensNeeded) { wr.Write(\"(\"); }\n        if (!e.Receiver.IsImplicit) {\n          PrintExpr(e.Receiver, opBindingStrength, false, false, !parensNeeded && isFollowedBySemicolon, -1, keyword);\n          wr.Write(\".\");\n        }\n        wr.Write(e.Name);\n        /* When debugging, this is nice to have:\n        if (e.TypeArgumentSubstitutions.Count > 0) {\n          wr.Write(\"[\");\n          wr.Write(Util.Comma(\",\", e.TypeArgumentSubstitutions, kv => kv.Key.FullName() + \"->\" + kv.Value));\n          wr.Write(\"]\");\n        }\n        */\n        if (e.OpenParen == null && e.Args.Count == 0) {\n        } else {\n          PrintActualArguments(e.Args, e.Name);\n        }\n        if (parensNeeded) { wr.Write(\")\"); }\n\n      } else if (expr is SeqConstructionExpr) {\n        var e = (SeqConstructionExpr)expr;\n        wr.Write(\"seq(\");\n        PrintExpression(e.N, false);\n        wr.Write(\", \");\n        PrintExpression(e.Initializer, false);\n        wr.Write(\")\");\n\n      } else if (expr is MultiSetFormingExpr) {\n        wr.Write(\"multiset(\");\n        PrintExpression(((MultiSetFormingExpr)expr).E, false);\n        wr.Write(\")\");\n\n      } else if (expr is OldExpr) {\n        var e = (OldExpr)expr;\n        wr.Write(\"old\");\n        if (e.At != null) {\n          wr.Write(\"@{0}\", e.At);\n        }\n        wr.Write(\"(\");\n        PrintExpression(e.E, false);\n        wr.Write(\")\");\n\n      } else if (expr is UnchangedExpr) {\n        var e = (UnchangedExpr)expr;\n        wr.Write(\"unchanged\");\n        if (e.At != null) {\n          wr.Write(\"@{0}\", e.At);\n        }\n        wr.Write(\"(\");\n        PrintFrameExpressionList(e.Frame);\n        wr.Write(\")\");\n\n      } else if (expr is UnaryOpExpr) {\n        var e = (UnaryOpExpr)expr;\n        if (e.Op == UnaryOpExpr.Opcode.Cardinality) {\n          wr.Write(\"|\");\n          PrintExpression(e.E, false);\n          wr.Write(\"|\");\n        } else if (e.Op == UnaryOpExpr.Opcode.Fresh) {\n          wr.Write(\"fresh(\");\n          PrintExpression(e.E, false);\n          wr.Write(\")\");\n        } else if (e.Op == UnaryOpExpr.Opcode.Allocated) {\n          wr.Write(\"allocated(\");\n          PrintExpression(e.E, false);\n          wr.Write(\")\");\n        } else if (e.Op == UnaryOpExpr.Opcode.Lit) {\n          wr.Write(\"Lit(\");\n          PrintExpression(e.E, false);\n          wr.Write(\")\");\n        } else {\n          // Prefix operator.\n          // determine if parens are needed\n          string op;\n          int opBindingStrength;\n          switch (e.Op) {\n            case UnaryOpExpr.Opcode.Not:\n              op = \"!\"; opBindingStrength = 0x80; break;\n            case UnaryOpExpr.Opcode.Dereference:\n              op = \"*\"; opBindingStrength = 0x80; break;\n            case UnaryOpExpr.Opcode.AddressOf:\n              op = \"&\"; opBindingStrength = 0x80; break;\n            default:\n              Contract.Assert(false); throw new cce.UnreachableException();  // unexpected unary opcode\n          }\n          bool parensNeeded = ParensNeeded(opBindingStrength, contextBindingStrength, fragileContext);\n\n          if (parensNeeded) { wr.Write(\"(\"); }\n          wr.Write(op);\n          PrintExpr(e.E, opBindingStrength, false, parensNeeded || isRightmost, !parensNeeded && isFollowedBySemicolon, -1, keyword);\n          if (parensNeeded) { wr.Write(\")\"); }\n        }\n\n      } else if (expr is ConversionExpr) {\n        var e = (ConversionExpr)expr;\n        int opBindingStrength = 0x70;\n        bool parensNeeded = ParensNeeded(opBindingStrength, contextBindingStrength, fragileContext);\n\n        if (parensNeeded) { wr.Write(\"(\"); }\n        PrintExpr(e.E, opBindingStrength, false, false, !parensNeeded && isFollowedBySemicolon, -1, keyword);\n        wr.Write(\" as \");\n        PrintType(e.ToType);\n        if (parensNeeded) { wr.Write(\")\"); }\n\n      } else if (expr is BinaryExpr) {\n        var e = (BinaryExpr)expr;\n        // determine if parens are needed\n        int opBindingStrength;\n        bool fragileLeftContext = false;  // false means \"allow same binding power on left without parens\"\n        bool fragileRightContext = false;  // false means \"allow same binding power on right without parens\"\n        switch (e.Op) {\n          case BinaryExpr.Opcode.LeftShift:\n          case BinaryExpr.Opcode.RightShift:\n            opBindingStrength = 0x48; fragileRightContext = true; break;\n          case BinaryExpr.Opcode.Add: {\n            opBindingStrength = 0x40;\n            var t1 = e.E1.Type;\n            fragileRightContext = t1 == null || !(t1.IsIntegerType || t1.IsRealType || t1.IsBigOrdinalType || t1.IsBitVectorType);\n            break;\n          }\n          case BinaryExpr.Opcode.Sub:\n            opBindingStrength = 0x40; fragileRightContext = true; break;\n          case BinaryExpr.Opcode.Mul: {\n            opBindingStrength = 0x50;\n            var t1 = e.E1.Type;\n            fragileRightContext = t1 == null || !(t1.IsIntegerType || t1.IsRealType || t1.IsBigOrdinalType || t1.IsBitVectorType);\n            break;\n          }\n          case BinaryExpr.Opcode.Div:\n          case BinaryExpr.Opcode.Mod:\n            opBindingStrength = 0x50; fragileRightContext = true; break;\n          case BinaryExpr.Opcode.BitwiseAnd:\n            opBindingStrength = 0x60; break;\n          case BinaryExpr.Opcode.BitwiseOr:\n            opBindingStrength = 0x61; break;\n          case BinaryExpr.Opcode.BitwiseXor:\n            opBindingStrength = 0x62; break;\n          case BinaryExpr.Opcode.Eq:\n          case BinaryExpr.Opcode.Neq:\n          case BinaryExpr.Opcode.Gt:\n          case BinaryExpr.Opcode.Ge:\n          case BinaryExpr.Opcode.Lt:\n          case BinaryExpr.Opcode.Le:\n          case BinaryExpr.Opcode.Disjoint:\n          case BinaryExpr.Opcode.In:\n          case BinaryExpr.Opcode.NotIn:\n            opBindingStrength = 0x30; fragileLeftContext = fragileRightContext = true; break;\n          case BinaryExpr.Opcode.And:\n            opBindingStrength = 0x20; break;\n          case BinaryExpr.Opcode.Or:\n            opBindingStrength = 0x21; break;\n          case BinaryExpr.Opcode.Imp:\n            opBindingStrength = 0x10; fragileLeftContext = true; break;\n          case BinaryExpr.Opcode.Exp:\n            opBindingStrength = 0x11; fragileRightContext = true; break;\n          case BinaryExpr.Opcode.Iff:\n            opBindingStrength = 0x08; break;\n          default:\n            Contract.Assert(false); throw new cce.UnreachableException();  // unexpected binary operator\n        }\n        int opBS = opBindingStrength & 0xF8;\n        int ctxtBS = contextBindingStrength & 0xF8;\n        bool parensNeeded = opBS < ctxtBS ||\n          (opBS == ctxtBS && (opBindingStrength != contextBindingStrength || fragileContext));\n\n        string op = BinaryExpr.OpcodeString(e.Op);\n        if (parensNeeded) { wr.Write(\"(\"); }\n        var sem = !parensNeeded && isFollowedBySemicolon;\n        if (0 <= indent && e.Op == BinaryExpr.Opcode.And) {\n          PrintExpr(e.E0, opBindingStrength, fragileLeftContext, false, sem, indent, keyword);\n          wr.WriteLine(\" {0}\", op);\n          Indent(indent);\n          PrintExpr(e.E1, opBindingStrength, fragileRightContext, parensNeeded || isRightmost, sem, indent, keyword);\n        } else if (0 <= indent && e.Op == BinaryExpr.Opcode.Imp) {\n          PrintExpr(e.E0, opBindingStrength, fragileLeftContext, false, sem, indent, keyword);\n          wr.WriteLine(\" {0}\", op);\n          int ind = indent + IndentAmount;\n          Indent(ind);\n          PrintExpr(e.E1, opBindingStrength, fragileRightContext, parensNeeded || isRightmost, sem, ind, keyword);\n        } else if (0 <= indent && e.Op == BinaryExpr.Opcode.Exp) {\n          PrintExpr(e.E1, opBindingStrength, fragileLeftContext, false, sem, indent, keyword);\n          wr.WriteLine(\" {0}\", op);\n          int ind = indent + IndentAmount;\n          Indent(ind);\n          PrintExpr(e.E0, opBindingStrength, fragileRightContext, parensNeeded || isRightmost, sem, ind, keyword);\n        } else if (e.Op == BinaryExpr.Opcode.Exp) {\n          PrintExpr(e.E1, opBindingStrength, fragileLeftContext, false, sem, -1, keyword);\n          wr.Write(\" {0} \", op);\n          PrintExpr(e.E0, opBindingStrength, fragileRightContext, parensNeeded || isRightmost, sem, -1, keyword);\n        } else {\n          PrintExpr(e.E0, opBindingStrength, fragileLeftContext, false, sem, -1, keyword);\n          wr.Write(\" {0} \", op);\n          PrintExpr(e.E1, opBindingStrength, fragileRightContext, parensNeeded || isRightmost, sem, -1, keyword);\n        }\n        if (parensNeeded) { wr.Write(\")\"); }\n\n      } else if (expr is TernaryExpr) {\n        var e = (TernaryExpr)expr;\n        switch (e.Op) {\n          case TernaryExpr.Opcode.PrefixEqOp:\n          case TernaryExpr.Opcode.PrefixNeqOp:\n            var opBindingStrength = 0x30;\n            var fragileLeftContext = true;\n            var fragileRightContext = true;\n\n            int opBS = opBindingStrength & 0xF8;\n            int ctxtBS = contextBindingStrength & 0xF8;\n            bool parensNeeded = opBS < ctxtBS ||\n              (opBS == ctxtBS && (opBindingStrength != contextBindingStrength || fragileContext));\n\n            if (parensNeeded) { wr.Write(\"(\"); }\n            var sem = !parensNeeded && isFollowedBySemicolon;\n            PrintExpr(e.E1, opBindingStrength, fragileLeftContext, false, sem, -1, keyword);\n            wr.Write(\" {0}#[\", e.Op == TernaryExpr.Opcode.PrefixEqOp ? \"==\" : \"!=\");\n            PrintExpression(e.E0, false);\n            wr.Write(\"] \");\n            PrintExpr(e.E2, opBindingStrength, fragileRightContext, parensNeeded || isRightmost, sem, -1, keyword);\n            if (parensNeeded) { wr.Write(\")\"); }\n            break;\n          default:\n            Contract.Assert(false);  // unexpected ternary operator\n            break;\n        }\n\n      } else if (expr is ChainingExpression) {\n        var e = (ChainingExpression)expr;\n        // determine if parens are needed\n        int opBindingStrength = 0x30;\n        int opBS = opBindingStrength & 0xF8;\n        int ctxtBS = contextBindingStrength & 0xF8;\n        bool parensNeeded = opBS < ctxtBS ||\n          (opBS == ctxtBS && (opBindingStrength != contextBindingStrength || fragileContext));\n\n        if (parensNeeded) { wr.Write(\"(\"); }\n        var sem = !parensNeeded && isFollowedBySemicolon;\n        PrintExpr(e.Operands[0], opBindingStrength, true, false, sem, -1, keyword);\n        for (int i = 0; i < e.Operators.Count; i++) {\n          string op = BinaryExpr.OpcodeString(e.Operators[i]);\n          if (e.PrefixLimits[i] == null) {\n            wr.Write(\" {0} \", op);\n          } else {\n            wr.Write(\" {0}#[\", op);\n            PrintExpression(e.PrefixLimits[i], false);\n            wr.Write(\"] \");\n          }\n          PrintExpr(e.Operands[i + 1], opBindingStrength, true, i == e.Operators.Count - 1 && (parensNeeded || isRightmost), sem, -1, keyword);\n        }\n        if (parensNeeded) { wr.Write(\")\"); }\n\n      } else if (expr is LetExpr) {\n        var e = (LetExpr)expr;\n        bool parensNeeded = !isRightmost;\n        if (parensNeeded) { wr.Write(\"(\"); }\n        if (e.LHSs.Exists(lhs => lhs != null && lhs.Var != null && lhs.Var.IsGhost)) { wr.Write(\"ghost \"); }\n        wr.Write(\"var \");\n        string sep = \"\";\n        foreach (var lhs in e.LHSs) {\n          wr.Write(sep);\n          PrintCasePattern(lhs);\n          sep = \", \";\n        }\n        if (e.Exact) {\n          wr.Write(\" := \");\n        } else {\n          wr.Write(\" :| \");\n        }\n        PrintExpressionList(e.RHSs, true);\n        wr.Write(\"; \");\n        PrintExpression(e.Body, !parensNeeded && isFollowedBySemicolon);\n        if (parensNeeded) { wr.Write(\")\"); }\n\n      } else if (expr is LetOrFailExpr) {\n        // TODO should we also print the desugared version?\n        // If so, should we insert newlines?\n        var e = (LetOrFailExpr)expr;\n        bool parensNeeded = !isRightmost;\n        if (parensNeeded) { wr.Write(\"(\"); }\n        if (e.Lhs != null) {\n          if (e.Lhs.Var != null && e.Lhs.Var.IsGhost) { wr.Write(\"ghost \"); }\n          wr.Write(\"var \");\n          PrintCasePattern(e.Lhs);\n          wr.Write(\" :- \");\n        }\n        PrintExpression(e.Rhs, true);\n        wr.Write(\"; \");\n        PrintExpression(e.Body, !parensNeeded && isFollowedBySemicolon);\n        if (parensNeeded) { wr.Write(\")\"); }\n\n      } else if (expr is QuantifierExpr) {\n        QuantifierExpr e = (QuantifierExpr)expr;\n\n        if (ArmadaOptions.O.DafnyPrintResolvedFile != null && e.SplitQuantifier != null) {\n          PrintExpr(e.SplitQuantifierExpression, contextBindingStrength, fragileContext, isRightmost, isFollowedBySemicolon, indent, keyword, resolv_count);\n          return;\n        }\n\n        bool parensNeeded = !isRightmost;\n        if (parensNeeded) { wr.Write(\"(\"); }\n        wr.Write(e is ForallExpr ? \"forall\" : \"exists\");\n        PrintTypeParams(e.TypeArgs); // new!\n        wr.Write(\" \");\n        PrintQuantifierDomain(e.BoundVars, e.Attributes, e.Range);\n        if (keyword == null) {\n          wr.Write(\" :: \");\n        } else {\n          wr.WriteLine();\n          wr.Write(keyword);\n        }\n        if (0 <= indent) {\n          int ind = indent + IndentAmount;\n          wr.WriteLine();\n          Indent(ind);\n          PrintExpression(e.Term, !parensNeeded && isFollowedBySemicolon, ind);\n        } else {\n          PrintExpression(e.Term, !parensNeeded && isFollowedBySemicolon);\n        }\n        if (parensNeeded) { wr.Write(\")\"); }\n\n      } else if (expr is NamedExpr) {\n        var e = (NamedExpr)expr;\n        wr.Write(\"expr {0}: \", e.Name);\n        PrintExpression(e.Body, isFollowedBySemicolon);\n\n      } else if (expr is SetComprehension) {\n        var e = (SetComprehension)expr;\n        bool parensNeeded = !isRightmost;\n        if (parensNeeded) { wr.Write(\"(\"); }\n        if (e.Finite) {\n          wr.Write(\"set \");\n        } else {\n          wr.Write(\"iset \");\n        }\n        string sep = \"\";\n        foreach (BoundVar bv in e.BoundVars) {\n          wr.Write(\"{0}{1}\", sep, bv.DisplayName);\n          sep = \", \";\n          PrintType(\": \", bv.Type);\n        }\n        PrintAttributes(e.Attributes);\n        wr.Write(\" | \");\n        PrintExpression(e.Range, !parensNeeded && isFollowedBySemicolon);\n        if (!e.TermIsImplicit) {\n          wr.Write(\" :: \");\n          PrintExpression(e.Term, !parensNeeded && isFollowedBySemicolon);\n        }\n        if (parensNeeded) { wr.Write(\")\"); }\n\n      } else if (expr is MapComprehension) {\n        var e = (MapComprehension)expr;\n        bool parensNeeded = !isRightmost;\n        if (parensNeeded) { wr.Write(\"(\"); }\n        wr.Write(e.Finite ? \"map \" : \"imap \");\n        string sep = \"\";\n        foreach (BoundVar bv in e.BoundVars) {\n          wr.Write(\"{0}{1}\", sep, bv.DisplayName);\n          sep = \", \";\n          PrintType(\": \", bv.Type);\n        }\n        PrintAttributes(e.Attributes);\n        wr.Write(\" | \");\n        PrintExpression(e.Range, false);\n        wr.Write(\" :: \");\n        if (e.TermLeft != null) {\n          PrintExpression(e.TermLeft, false);\n          wr.Write(\" := \");\n        }\n        PrintExpression(e.Term, !parensNeeded && isFollowedBySemicolon);\n        if (parensNeeded) { wr.Write(\")\"); }\n\n      } else if (expr is LambdaExpr) {\n        var e = (LambdaExpr)expr;\n        bool parensNeeded = !isRightmost;\n        if (parensNeeded) { wr.Write(\"(\"); }\n        var skipSignatureParens = e.BoundVars.Count == 1 && !ShowType(e.BoundVars[0].Type);\n        if (!skipSignatureParens) { wr.Write(\"(\"); }\n        wr.Write(Util.Comma(\", \", e.BoundVars, bv => bv.DisplayName + (ShowType(bv.Type) ? \": \" + bv.Type : \"\")));\n        if (!skipSignatureParens) { wr.Write(\")\"); }\n        if (e.Range != null) {\n          wr.Write(\" requires \");\n          PrintExpression(e.Range, false);\n        }\n        var readsPrefix = \" reads \";\n        foreach (var read in e.Reads) {\n          wr.Write(readsPrefix);\n          PrintExpression(read.E, false);\n          readsPrefix = \", \";\n        }\n        wr.Write(\" => \");\n        PrintExpression(e.Body, isFollowedBySemicolon);\n        if (parensNeeded) { wr.Write(\")\"); }\n\n      } else if (expr is WildcardExpr) {\n        wr.Write(\"*\");\n\n      } else if (expr is MeExpr) {\n        wr.Write(\"$me\");\n\n      } else if (expr is StoreBufferEmptyExpr) {\n        wr.Write(\"$sb_empty\");\n\n      } else if (expr is TotalStateExpr) {\n        wr.Write(\"$state\");\n\n      } else if (expr is StmtExpr) {\n        var e = (StmtExpr)expr;\n        bool parensNeeded;\n        if (e.S is AssertStmt || e.S is AssumeStmt || e.S is CalcStmt) {\n          parensNeeded = !isRightmost;\n        } else {\n          parensNeeded = !isRightmost || isFollowedBySemicolon;\n        }\n        if (parensNeeded) { wr.Write(\"(\"); }\n        int ind = indent < 0 ? IndentAmount : indent;  // if the expression was to be printed on one line, instead print the .S part at indentation IndentAmount (not pretty, but something)\n        PrintStatement(e.S, ind);\n        wr.Write(\" \");\n        PrintExpression(e.E, !parensNeeded && isFollowedBySemicolon);\n        if (parensNeeded) { wr.Write(\")\"); }\n\n      } else if (expr is ITEExpr) {\n        ITEExpr ite = (ITEExpr)expr;\n        bool parensNeeded = !isRightmost;\n        if (parensNeeded) { wr.Write(\"(\"); }\n        wr.Write(\"if \");\n        PrintExpression(ite.Test, false);\n        wr.Write(\" then \");\n        PrintExpression(ite.Thn, false);\n        wr.Write(\" else \");\n        PrintExpression(ite.Els, !parensNeeded && isFollowedBySemicolon);\n        if (parensNeeded) { wr.Write(\")\"); }\n\n      } else if (expr is ParensExpression) {\n        var e = (ParensExpression)expr;\n        // printing of parentheses is done optimally, not according to the parentheses in the given program\n        PrintExpr(e.E, contextBindingStrength, fragileContext, isRightmost, isFollowedBySemicolon, indent, keyword);\n\n      } else if (expr is NegationExpression) {\n        var e = (NegationExpression)expr;\n        string op = \"-\";\n        int opBindingStrength = 0x80;\n        bool parensNeeded = ParensNeeded(opBindingStrength, contextBindingStrength, fragileContext);\n\n        if (parensNeeded) { wr.Write(\"(\"); }\n        wr.Write(op);\n        PrintExpr(e.E, opBindingStrength, false, parensNeeded || isRightmost, !parensNeeded && isFollowedBySemicolon, -1, keyword);\n        if (parensNeeded) { wr.Write(\")\"); }\n\n      } else if (expr is MatchExpr) {\n        var e = (MatchExpr)expr;\n        if (ArmadaOptions.O.DafnyPrintResolvedFile == null && e.OrigUnresolved != null) {\n          PrintExpr(e.OrigUnresolved, contextBindingStrength, fragileContext, isRightmost, isFollowedBySemicolon, indent);\n        } else {\n          var parensNeeded = !isRightmost && !e.UsesOptionalBraces;\n          if (parensNeeded) { wr.Write(\"(\"); }\n          wr.Write(\"match \");\n          PrintExpression(e.Source, isRightmost && e.Cases.Count == 0, !parensNeeded && isFollowedBySemicolon);\n          if (e.UsesOptionalBraces) { wr.Write(\" {\"); }\n          int i = 0;\n          foreach (var mc in e.Cases) {\n            bool isLastCase = i == e.Cases.Count - 1;\n            wr.Write(\" case {0}\", mc.Id);\n            PrintMatchCaseArgument(mc);\n            wr.Write(\" => \");\n            PrintExpression(mc.Body, isRightmost && isLastCase, !parensNeeded && isFollowedBySemicolon);\n            i++;\n          }\n          if (e.UsesOptionalBraces) { wr.Write(\" }\"); } else if (parensNeeded) { wr.Write(\")\"); }\n        }\n\n      } else if (expr is BoxingCastExpr) {\n        // this is not expected for a parsed program, but we may be called for /trace purposes in the translator\n        var e = (BoxingCastExpr)expr;\n        PrintExpr(e.E, contextBindingStrength, fragileContext, isRightmost, isFollowedBySemicolon, indent, keyword);\n      } else if (expr is Translator.BoogieWrapper) {\n        wr.Write(\"[BoogieWrapper]\");  // this is somewhat unexpected, but we can get here if the /trace switch is used, so it seems best to cover this case here\n      } else if (expr is Translator.BoogieFunctionCall) {\n        wr.Write(\"[BoogieFunctionCall]\");  // this prevents debugger watch window crash\n      } else if (expr is Resolver_IdentifierExpr) {\n        wr.Write(\"[Resolver_IdentifierExpr]\");  // we can get here in the middle of a debugging session\n      } else {\n        Console.WriteLine(expr.GetType().Name);\n        Contract.Assert(false); throw new cce.UnreachableException();  // unexpected expression\n      }\n    }\n\n    bool ParensMayMatter(Expression expr) {\n      Contract.Requires(expr != null);\n      int parenPairs = 0;\n      for (; expr is ParensExpression; parenPairs++) {\n        expr = ((ParensExpression)expr).E;\n      }\n      // If the program were resolved, we could be more precise than the following (in particular, looking\n      // to see if expr denotes a MemberSelectExpr of a member that is a Function.\n      return parenPairs != 0 && (expr is NameSegment || expr is ExprDotName);\n    }\n\n    void PrintCasePattern<VT>(CasePattern<VT> pat) where VT: IVariable {\n      Contract.Requires(pat != null);\n      var v = pat.Var;\n      if (v != null) {\n        wr.Write(v.DisplayName);\n        if (v.OptionalType is NonProxyType || ArmadaOptions.O.DafnyPrintResolvedFile != null) {\n          PrintType(\": \", v.OptionalType);\n        }\n      } else {\n        if (pat.Id.StartsWith(BuiltIns.TupleTypeCtorNamePrefix)) {\n          Contract.Assert(pat.Arguments != null);\n        } else {\n          wr.Write(pat.Id);\n        }\n        if (pat.Arguments != null) {\n          wr.Write(\"(\");\n          var sep = \"\";\n          foreach (var arg in pat.Arguments) {\n            wr.Write(sep);\n            PrintCasePattern(arg);\n            sep = \", \";\n          }\n          wr.Write(\")\");\n        }\n      }\n    }\n\n    private void PrintQuantifierDomain(List<BoundVar> boundVars, Attributes attrs, Expression range) {\n      Contract.Requires(boundVars != null);\n      string sep = \"\";\n      foreach (BoundVar bv in boundVars) {\n        wr.Write(\"{0}{1}\", sep, bv.DisplayName);\n        PrintType(\": \", bv.Type);\n        sep = \", \";\n      }\n      PrintAttributes(attrs);\n      if (range != null) {\n        wr.Write(\" | \");\n        PrintExpression(range, false);\n      }\n    }\n\n    void PrintActualArguments(List<Expression> args, string name) {\n      Contract.Requires(args != null);\n      if (name != null && name.EndsWith(\"#\")) {\n        wr.Write(\"[\");\n        PrintExpression(args[0], false);\n        wr.Write(\"]\");\n        args = new List<Expression>(args.Skip(1));\n      }\n      wr.Write(\"(\");\n      PrintExpressionList(args, false);\n      wr.Write(\")\");\n    }\n\n    void PrintExpressionList(List<Expression> exprs, bool isFollowedBySemicolon) {\n      Contract.Requires(exprs != null);\n      string sep = \"\";\n      foreach (Expression e in exprs) {\n        Contract.Assert(e != null);\n        wr.Write(sep);\n        sep = \", \";\n        PrintExpression(e, isFollowedBySemicolon);\n      }\n    }\n    void PrintExpressionPairList(List<ExpressionPair> exprs) {\n      Contract.Requires(exprs != null);\n      string sep = \"\";\n      foreach (ExpressionPair p in exprs) {\n        Contract.Assert(p != null);\n        wr.Write(sep);\n        sep = \", \";\n        PrintExpression(p.A, false);\n        wr.Write(\" := \");\n        PrintExpression(p.B, false);\n      }\n    }\n\n    void PrintFrameExpressionList(List<FrameExpression/*!*/>/*!*/ fexprs) {\n      Contract.Requires(fexprs != null);\n      string sep = \"\";\n      foreach (FrameExpression fe in fexprs) {\n        Contract.Assert(fe != null);\n        wr.Write(sep);\n        sep = \", \";\n        if (fe.E is ImplicitThisExpr) {\n          Contract.Assert(fe.FieldName != null);\n        } else {\n          PrintExpression(fe.E, true);\n        }\n        if (fe.FieldName != null) {\n          wr.Write(\"`{0}\", fe.FieldName);\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "Source/Armada/Prioritization.cs",
    "content": "using System.Linq;\n\nnamespace Microsoft.Armada\n{\n  public class PrioritizationAttributes\n  {\n    public int likelihoodOfFailure;\n\n    public override string ToString()\n    {\n      return $\"{{:likelihood_of_failure {likelihoodOfFailure}}}\";\n    }\n  }\n\n  public class Prioritizer\n  {\n    public static PrioritizationAttributes GetPrioritizationAttributesForLiftAtomicPath(AtomicPath lowAtomicPath, AtomicPath highAtomicPath)\n    {\n\n        if (lowAtomicPath.NextRoutines.Select(nextRoutine => nextRoutine.armadaStatement == null ? null : Printer.StatementToString(nextRoutine.armadaStatement.Stmt)).SequenceEqual(\n          highAtomicPath.NextRoutines.Select(nextRoutine => nextRoutine.armadaStatement == null ? null : Printer.StatementToString(nextRoutine.armadaStatement.Stmt))))\n        {\n            return new PrioritizationAttributes { likelihoodOfFailure = 0 };\n        }\n\n      return new PrioritizationAttributes { likelihoodOfFailure = 3 };\n\n      /*\n      // TODO: this check assumes that corresponding nextRoutines with no associated armada statements are the same\n      if (lowAtomicPath.NextRoutines.Count == highAtomicPath.NextRoutines.Count)\n      {\n        bool stmtsEqual = false;\n        for (int i = 0; i < lowAtomicPath.NextRoutines.Count; i++) {\n          if (stmtsEqual) {\n            return new PrioritizationAttributes { likelihoodOfFailure = 0 };\n          }\n        }\n      }\n      return new PrioritizationAttributes { likelihoodOfFailure = 3 };\n      */\n    }\n  }\n\n}\n"
  },
  {
    "path": "Source/Armada/ProofFiles.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Text;\nusing System.Text.RegularExpressions;\nusing Token = Microsoft.Boogie.Token;\n\nnamespace Microsoft.Armada\n{\n  public class ProofFile\n  {\n    private string dirName;\n    private string auxName;\n    private ModuleDefinition module;\n    private List<MemberDecl> newDefaultClassDecls;\n    private bool includeImportedFiles;\n\n    public ProofFile(ModuleDefinition i_module, string i_dirName, bool i_includeImportedFiles = true)\n    {\n      dirName = i_dirName;\n      auxName = null;\n      module = i_module;\n      includeImportedFiles = i_includeImportedFiles;\n      Initialize();\n    }\n\n    public ProofFile(string i_dirName, string i_auxName, bool i_includeImportedFiles)\n    {\n      dirName = i_dirName;\n      auxName = i_auxName;\n      module = new ModuleDefinition(Token.NoToken, // tok\n                                    ModuleName, // name\n                                    new List<Microsoft.Boogie.IToken>(), // prefixIds\n                                    false, // isAbstract\n                                    false, // isProtected\n                                    false, // isFacade\n                                    Token.NoToken, // refinementBase\n                                    null, // parent\n                                    null, // attributes\n                                    false, // isBuiltinName\n                                    ArmadaModuleType.ArmadaProof, // moduleType\n                                    null, // structsModuleType\n                                    null, // abstracts\n                                    null, // reduces\n                                    null); // parser\n      includeImportedFiles = i_includeImportedFiles;\n      Initialize();\n    }\n\n    public string PathName\n    {\n      get { return (auxName == null) ? $\"{dirName}.dfy\" : $\"{dirName}/{auxName}.dfy\"; }\n    }\n\n    public string ModuleName\n    {\n      get { return $\"ArmadaModule_{auxName}\"; }\n    }\n\n    public string AuxName\n    {\n      get { return auxName; }\n    }\n\n    public bool IncludeImportedFiles\n    {\n      get { return includeImportedFiles; }\n    }\n\n    private void Initialize()\n    {\n      newDefaultClassDecls = new List<MemberDecl>();\n\n      module.ArmadaTranslation =\n        new ModuleDefinition(Token.NoToken, module.Name, new List<Microsoft.Boogie.IToken>(), false, false, false, null, module.Module, null, false);\n      module.ArmadaIncludes = new List<string>();\n\n      AddImport(\"ArmadaCommonDefinitions\");\n      AddImport(\"GeneralRefinementModule\");\n\n      AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/ArmadaCommonDefinitions.dfy\");\n      AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/spec/refinement.s.dfy\");\n    }\n\n    private void Flush()\n    {\n      var c = new DefaultClassDecl(module.ArmadaTranslation, newDefaultClassDecls);\n      AddTopLevelDecl(c);\n    }\n\n    public void Print(Program prog)\n    {\n      Flush();\n\n      var pathName = ArmadaOptions.O.ArmadaOutputDir + \"/\" + this.PathName;\n      Console.Out.WriteLine($\"Printing proof to {pathName}\");\n      var tw = new System.IO.StreamWriter(pathName);\n      var pr = new Printer(tw, ArmadaOptions.O.PrintMode);\n      var fileBeingPrinted = Path.GetFullPath(prog.FullName);\n      VisibilityScope scope = null;\n      foreach (var includePath in module.ArmadaIncludes) {\n        pr.PrintInclude(includePath);\n      }\n      pr.PrintModuleDefinition(module.ArmadaTranslation, scope, 0, new List<Microsoft.Boogie.IToken>(), fileBeingPrinted);\n      tw.Flush();\n    }\n\n    public ModuleDefinition Module { get { return module; } }\n\n    public void AddInclude (string s)\n    {\n      if (Path.IsPathRooted(s) || auxName == null)\n      {\n        module.ArmadaIncludes.Add(s);\n      }\n      else\n      {\n        module.ArmadaIncludes.Add(\"../\" + s);\n      }\n    }\n\n    public void AddInclude(ImportFileArmadaProofDecl ifd)\n    {\n      if (!ifd.UsedFiles.Contains(this.PathName)) {\n        AddInclude(ifd.IncludePath);\n      }\n    }\n\n    public void AddImport(string moduleName, string aliasName = null)\n    {\n      TopLevelDecl d;\n      if (aliasName == null) {\n        d = AH.MakeAliasModuleDecl(moduleName, module.ArmadaTranslation, true);\n      }\n      else {\n        d = AH.MakeAliasModuleDecl(aliasName, moduleName, module.ArmadaTranslation, false);\n      }\n      AddTopLevelDecl(d);\n    }\n\n    public void AddImport(ImportModuleArmadaProofDecl imd)\n    {\n      if (!imd.UsedModules.Contains(this.ModuleName)) {\n        AddImport(imd.IncludeModule);\n      }\n    }\n\n    public void AddIncludeImport(string includeFile, string moduleName, string aliasName = null)\n    {\n      AddInclude(includeFile);\n      AddImport(moduleName, aliasName);\n    }\n\n    public void IncludeAndImportGeneratedFile(string importedAuxName)\n    {\n      AddInclude($\"{dirName}/{importedAuxName}.dfy\");\n      AddImport($\"ArmadaModule_{importedAuxName}\");\n    }\n\n    public void AddTopLevelDecl(TopLevelDecl d)\n    {\n      module.ArmadaTranslation.TopLevelDecls.Add(d);\n    }\n\n    public void AddDefaultClassDecl(MemberDecl d)\n    {\n      newDefaultClassDecls.Add(d);\n    }\n\n  }\n  \n  public class ProofFileCollection\n  {\n    private Program prog;\n    private string name;\n    private ProofFile mainProof;\n    private Dictionary<string, ProofFile> auxiliaryProofs;\n    private AbstractProofGenerator pg;\n\n    public ProofFileCollection(Program i_prog, ModuleDefinition i_mainProof)\n    {\n      prog = i_prog;\n      name = i_mainProof.Name;\n      mainProof = new ProofFile(i_mainProof, name, true);\n      auxiliaryProofs = new Dictionary<string, ProofFile>();\n      pg = null;\n\n      var dirName = $\"{ArmadaOptions.O.ArmadaOutputDir}/{name}\";\n      if (!Directory.Exists(dirName))\n      {\n        Directory.CreateDirectory(dirName);\n      }\n    }\n\n    public void Print()\n    {\n      mainProof.Print(prog);\n      foreach (var proof in auxiliaryProofs.Values)\n      {\n        proof.Print(prog);\n      }\n    }\n\n    public void AssociateProofGenerator(AbstractProofGenerator i_pg)\n    {\n      pg = i_pg;\n\n      pg.AddCommonHeaderElements(mainProof);\n      foreach (var proof in auxiliaryProofs.Values)\n      {\n        pg.AddCommonHeaderElements(proof);\n      }\n    }\n\n    public ProofFile MainProof { get { return mainProof; } }\n\n    public ProofFile AuxiliaryProof(string auxName)\n    {\n      return auxiliaryProofs[auxName];\n    }\n\n    public ProofFile CreateAuxiliaryProofFile(string auxName, bool includeImportedFiles = true)\n    {\n      if (auxiliaryProofs.ContainsKey(auxName)) {\n        AH.PrintError(prog, Token.NoToken, $\"Attempt to create an auxiliary proof file with an already-existing name ({auxName})\");\n        return null;\n      }\n\n      var proof = new ProofFile(name, auxName, includeImportedFiles);\n      if (pg != null) {\n        pg.AddCommonHeaderElements(proof);\n      }\n      auxiliaryProofs[auxName] = proof;\n      return proof;\n    }\n\n    public ProofFile LookupFile(string auxName)\n    {\n      return (auxName == null) ? mainProof : auxiliaryProofs[auxName];\n    }\n\n    public void AddInclude(string path, string auxName = null)\n    {\n      LookupFile(auxName).AddInclude(path);\n    }\n    \n    public void IncludeAndImportGeneratedFile(string importedAuxName, string auxName = null)\n    {\n      LookupFile(auxName).IncludeAndImportGeneratedFile(importedAuxName);\n    }\n\n    public void AddImport(string moduleName, string aliasName = null, string auxName = null)\n    {\n      LookupFile(auxName).AddImport(moduleName, aliasName);\n    }\n\n    public void AddTopLevelDecl(TopLevelDecl d, string auxName = null)\n    {\n      LookupFile(auxName).AddTopLevelDecl(d);\n    }\n\n    public void AddDefaultClassDecl(MemberDecl d, string auxName = null)\n    {\n      LookupFile(auxName).AddDefaultClassDecl(d);\n    }\n  }\n}\n"
  },
  {
    "path": "Source/Armada/ProofGenerationParams.cs",
    "content": "using System;\nusing System.Numerics;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text;\nusing System.Text.RegularExpressions;\nusing Token = Microsoft.Boogie.Token;\n\nnamespace Microsoft.Armada\n{\n  public class ProofGenerationParams\n  {\n    public ProofGenerationParams(Program i_prog, ModuleDefinition i_mProof, LiteralModuleDecl i_mLow, LiteralModuleDecl i_mHigh)\n    {\n      prog = i_prog;\n      proofFiles = new ProofFileCollection(i_prog, i_mProof);\n      mLow = i_mLow;\n      mHigh = i_mHigh;\n      symbolsLow = mLow.ModuleDef.ArmadaSymbols;\n      symbolsHigh = mHigh.ModuleDef.ArmadaSymbols;\n      originalsLow = symbolsLow.DefaultClass;\n      originalsHigh = symbolsHigh.DefaultClass;\n      extraMaterial = new Dictionary<string, string>();\n      opaqueUserDefs = new List<string>();\n    }\n\n    public readonly Program prog;\n    public ProofFileCollection proofFiles;\n    public readonly LiteralModuleDecl mLow, mHigh;\n    public readonly ClassDecl originalsLow, originalsHigh;\n    public readonly ArmadaSymbolTable symbolsLow, symbolsHigh;\n    private Dictionary<string, string> extraMaterial;\n    private List<string> opaqueUserDefs;\n\n    public ProofFile MainProof { get { return proofFiles.MainProof; } }\n    public ProofFile AuxiliaryProof(string auxName) { return proofFiles.AuxiliaryProof(auxName); }\n\n    public void AddExtraMaterial(string name, string contents)\n    {\n      if (extraMaterial.ContainsKey(name)) {\n        extraMaterial[name] += \"\\n\" + contents;\n      }\n      else {\n        extraMaterial[name] = contents;\n      }\n    }\n\n    private string InsertExtraMaterial(string name, string contents, int minPos = 0)\n    {\n      // Remove any \"ProofCustomizationGoesHere();\" and replace it\n      // with the extra material.  The extra material is whatever is\n      // specified by the user or, if nothing is specified by them,\n      // revelations of all user-defined opaque definitions.\n\n      int insertionPos = contents.IndexOf(\"ProofCustomizationGoesHere();\", minPos);\n      if (insertionPos >= 0) {\n        string extra = extraMaterial.ContainsKey(name) ? extraMaterial[name] + \"\\n\"\n                                                       : String.Concat(opaqueUserDefs.Select(f => $\"reveal {f}();\\n\"));\n        return contents.Substring(0, insertionPos) + extra + contents.Substring(insertionPos + 29);\n      }\n\n      // If there is no \"ProofCustomizationGoesHere();\", but the user\n      // has provided extra material, put it after the first left\n      // brace + newline.  (Don't put it after a left brace not\n      // immediately followed by a newline because that might be\n      // followed by a colon indicating an attribute.)\n\n      if (extraMaterial.ContainsKey(name)) {\n        var bracePos = contents.IndexOf(\"{\\n\");\n        if (bracePos >= 0) {\n          return contents.Substring(0, bracePos + 2) + extraMaterial[name] + contents.Substring(bracePos + 2);\n        }\n      }\n\n      return contents;\n    }\n\n    public void AddOpaqueUserDef(string fnName)\n    {\n      opaqueUserDefs.Add(fnName);\n    }\n\n    public void AddDefaultClassDecl(MemberDecl d, string auxName = null)\n    {\n      proofFiles.AddDefaultClassDecl(d, auxName);\n    }\n\n    public void AddTopLevelDecl(TopLevelDecl d, string auxName = null)\n    {\n      proofFiles.AddTopLevelDecl(d, auxName);\n    }\n\n    public void AddLemma(string contents, string auxName = null)\n    {\n      Match match = Regex.Match(contents, @\"^\\s*lemma\\s+({[^}]*}\\s*)*([^\\s<(]+)\");\n      if (match.Success)\n      {\n        string name = match.Groups[2].Value;\n        int pos = match.Groups[2].Index;\n        string expandedContents = InsertExtraMaterial(name, contents, pos);\n        AddDefaultClassDecl((Lemma)AH.ParseTopLevelDecl(prog, name, expandedContents), auxName);\n      }\n      else {\n        AH.PrintError(prog, $\"Could not find lemma name in {contents}\");\n      }\n    }\n\n    public void AddFunction(string contents, string auxName = null)\n    {\n      Match match = Regex.Match(contents, @\"^\\s*function\\s+([^\\s<(]+)\");\n      if (match.Success)\n      {\n        string name = match.Groups[1].Value;\n        AddDefaultClassDecl((Function)AH.ParseTopLevelDecl(prog, name, contents), auxName);\n      }\n      else {\n        AH.PrintError(prog, $\"Could not find function name in {contents}\");\n      }\n    }\n\n    public void AddPredicate(string contents, string auxName = null)\n    {\n      Match match = Regex.Match(contents, @\"^\\s*predicate\\s+([^\\s<(]+)\");\n      if (match.Success)\n      {\n        string name = match.Groups[1].Value;\n        AddDefaultClassDecl((Predicate)AH.ParseTopLevelDecl(prog, name, contents), auxName);\n      }\n      else {\n        AH.PrintError(prog, $\"Could not find predicate name in {contents}\");\n        return;\n      }\n    }\n\n    public void AddDatatype(string contents, string auxName = null)\n    {\n      Match match = Regex.Match(contents, @\"^\\s*datatype\\s+([^\\s<(=]+)\");\n      if (match.Success)\n      {\n        string name = match.Groups[1].Value;\n        AddTopLevelDecl((DatatypeDecl)AH.ParseTopLevelDecl(prog, name, contents), auxName);\n      }\n      else\n      {\n        AH.PrintError(prog, $\"Could not find datatype name in {contents}\");\n      }\n    }\n\n    public void AddTypeSynonym(string contents, string auxName = null)\n    {\n      Match match = Regex.Match(contents, @\"^\\s*type\\s+([^\\s<(=]+)\");\n      if (match.Success)\n      {\n        string name = match.Groups[1].Value;\n        AddTopLevelDecl((TypeSynonymDecl)AH.ParseTopLevelDecl(prog, name, contents), auxName);\n      }\n      else\n      {\n        AH.PrintError(prog, $\"Could not find type synonym name in {contents}\");\n      }\n    }\n\n    public void AddInclude(string fileName, string auxName = null)\n    {\n      proofFiles.AddInclude(fileName, auxName);\n    }\n\n    public void AddImport(string moduleName, string aliasName = null, string auxName = null)\n    {\n      proofFiles.AddImport(moduleName, aliasName, auxName);\n    }\n  }\n}\n"
  },
  {
    "path": "Source/Armada/ProofGenerator.cs",
    "content": "using System;\nusing System.Numerics;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text;\nusing static Microsoft.Armada.Predicate;\nusing IToken = Microsoft.Boogie.IToken;\nusing Token = Microsoft.Boogie.Token;\n\nnamespace Microsoft.Armada {\n\n  public class RefinementProofGenerator\n  {\n    private Program prog;\n    private ModuleDefinition mProof;\n    private Resolver.ModuleBindings bindings;\n    private LiteralModuleDecl mLow, mHigh;\n    private ArmadaSymbolTable symbolsLow, symbolsHigh;\n    private StrategyDecl strategy;\n\n    public RefinementProofGenerator(Program i_prog, ModuleDefinition i_mProof, Resolver.ModuleBindings i_bindings)\n    {\n      prog = i_prog;\n      mProof = i_mProof;\n      bindings = i_bindings;\n      mLow = null;\n      mHigh = null;\n      strategy = null;\n    }\n\n    private bool LookupLevel(IToken levelDescriptor, string kind, out LiteralModuleDecl m)\n    {\n      ModuleDecl md = null;\n      m = null;\n\n      if (!bindings.TryLookup(levelDescriptor, out md)) {\n        AH.PrintError(prog, $\"Could not find {kind} level {levelDescriptor} referred to in proof module {mProof.Name}\");\n        return false;\n      }\n      if (!(md is LiteralModuleDecl)) {\n        AH.PrintError(prog, $\"Low-level {levelDescriptor} referred to in proof module {mProof.Name} isn't a code level\");\n        return false;\n      }\n      m = (LiteralModuleDecl)md;\n      return true;\n    }\n\n    private bool GetLevelsAndStrategy()\n    {\n      foreach (var d in mProof.TopLevelDecls) {\n        if (d is RefinementParametersDecl) {\n          var refinement = (RefinementParametersDecl)d;\n          if (mLow != null || mHigh != null) {\n            AH.PrintError(prog, $\"More than one 'refinement' declaration found in proof module {mProof.Name}\");\n            return false;\n          }\n          if (!LookupLevel(refinement.LowLevel, \"low-level\", out mLow)) {\n            return false;\n          }\n          if (!LookupLevel(refinement.HighLevel, \"high-level\", out mHigh)) {\n            return false;\n          }\n        }\n        else if (d is StrategyDecl) {\n          if (strategy != null) {\n            AH.PrintError(prog, $\"More than one strategy found in proof module {mProof.Name}\");\n            return false;\n          }\n          strategy = (StrategyDecl)d;\n        }\n      }\n\n      if (mLow == null || mHigh == null) {\n        AH.PrintError(prog, $\"No 'refinement' declaration found in proof module {mProof.Name}\");\n        return false;\n      }\n      if (strategy == null) {\n        AH.PrintError(prog, $\"No strategy given in proof module {mProof.Name}\");\n        return false;\n      }\n\n      symbolsLow = mLow.ModuleDef.ArmadaSymbols;\n      symbolsHigh = mHigh.ModuleDef.ArmadaSymbols;\n\n      return true;\n    }\n\n    public void GenerateProof()\n    {\n      if (!GetLevelsAndStrategy()) {\n        return;\n      }\n\n      ProofGenerationParams pgp = new ProofGenerationParams(prog, mProof, mLow, mHigh);\n      AbstractProofGenerator pg = null;\n      if (strategy is GlobalVariableHidingStrategyDecl gvhsd) {\n        pg = new GlobalVarHidingProofGenerator(pgp, gvhsd);\n      }\n      else if (strategy is StackVariableHidingStrategyDecl svhsd) {\n        pg = new StackVarHidingProofGenerator(pgp, svhsd);\n      }\n      else if (strategy is GlobalVariableIntroStrategyDecl gvisd) {\n        pg = new GlobalVarIntroProofGenerator(pgp, gvisd);\n      }\n      else if (strategy is StackVariableIntroStrategyDecl svisd) {\n        pg = new StackVarIntroProofGenerator(pgp, svisd);\n      }\n      else if (strategy is AssumeIntroStrategyDecl aisd) {\n        pg = new AssumeIntroProofGenerator(pgp, aisd);\n      }\n      else if (strategy is TSOEliminationStrategyDecl tesd) {\n        pg = new TSOEliminationProofGenerator(pgp, tesd);\n      }\n      else if (strategy is ReductionStrategyDecl rsd) {\n        pg = new ReductionProofGenerator(pgp, rsd);\n      }\n      else if (strategy is WeakeningStrategyDecl wsd) {\n        pg = new WeakeningProofGenerator(pgp, wsd);\n      }\n      else if (strategy is StarWeakeningStrategyDecl swsd) {\n        pg = new StarWeakeningProofGenerator(pgp, swsd);\n      }\n      else if (strategy is CombiningStrategyDecl csd) {\n        pg = new CombiningProofGenerator(pgp, csd);\n      }\n\n      if (pg != null) {\n        pg.GenerateProof();\n        pgp.proofFiles.Print();\n      }\n    }\n  }\n\n}\n"
  },
  {
    "path": "Source/Armada/Reduction.cs",
    "content": "using System;\nusing System.Numerics;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text;\nusing System.Text.RegularExpressions;\n\nnamespace Microsoft.Armada\n{\n  public class ReductionProofGenerator : AbstractProofGenerator\n  {\n    private ReductionStrategyDecl strategy;\n    private HashSet<ArmadaPC> phase1PCs;\n    private HashSet<ArmadaPC> phase2PCs;\n    private HashSet<ArmadaPC> extraRecurrentPCs;\n    private Dictionary<ArmadaPC, AtomicPath> phase2PCToPath;\n\n    public ReductionProofGenerator(ProofGenerationParams i_pgp, ReductionStrategyDecl i_strategy)\n      : base(i_pgp)\n    {\n      strategy = i_strategy;\n\n      phase1PCs = GetYieldingPCsForLabelRanges(strategy.Phase1LabelRanges);\n      phase2PCs = GetYieldingPCsForLabelRanges(strategy.Phase2LabelRanges);\n    }\n\n    public override void GenerateProof()\n    {\n      if (!CheckEquivalence()) {\n        AH.PrintError(pgp.prog, $\"Levels {pgp.mLow.Name} and {pgp.mHigh.Name} aren't sufficiently equivalent to perform refinement proof generation using the reduction strategy\");\n        return;\n      }\n\n      AddIncludesAndImports();\n      MakeTrivialPCMap();\n      GenerateExtraRecurrentPCs();\n      GenerateNextRoutineMap();\n      GenerateProofGivenMap();\n    }\n\n    private ArmadaPC GetPCForLabel(string labelName)\n    {\n      var pc = pgp.symbolsLow.GetPCForMethodAndLabel(labelName);\n      if (pc == null) {\n        AH.PrintError(pgp.prog, $\"Specified non-existent label {labelName} in reduction description.  Remember to prefix label names with the method name and an underscore, e.g., use main_lb1 if you have label lb1: in method main.\");\n      }\n      return pc;\n    }\n\n    private HashSet<ArmadaPC> GetYieldingPCsForLabelRanges(List<Tuple<string, string>> labelRanges)\n    {\n      HashSet<ArmadaPC> pcs = new HashSet<ArmadaPC>();\n\n      foreach (var labelRange in labelRanges)\n      {\n        var label1Name = labelRange.Item1;\n        var label2Name = labelRange.Item2;\n\n        var pc1 = GetPCForLabel(label1Name);\n        var pc2 = GetPCForLabel(label2Name);\n        if (pc1 == null || pc2 == null) {\n          continue;\n        }\n\n        if (pc1.methodName != pc2.methodName) {\n          AH.PrintError(pgp.prog, $\"You can't specify a range of labels where the start label is in a different method from the end label.  Label {label1Name} is in method {pc1.methodName} but label {label2Name} is in method {pc2.methodName}.\");\n          continue;\n        }\n\n        for (var i = pc1.instructionCount; i <= pc2.instructionCount; ++i) {\n          var pc = new ArmadaPC(pgp.symbolsLow, pc1.methodName, i);\n          if (!pgp.symbolsLow.IsNonyieldingPC(pc)) {\n            pcs.Add(pc);\n          }\n        }\n      }\n\n      return pcs;\n    }\n\n    private void GenerateExtraRecurrentPCs()\n    {\n      extraRecurrentPCs = new HashSet<ArmadaPC>(phase1PCs.Concat(phase2PCs).Select(pc => pcMap[pc]));\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    /// Includes and imports\n    ////////////////////////////////////////////////////////////////////////\n\n    protected override void AddIncludesAndImports()\n    {\n      base.AddIncludesAndImports();\n\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/strategies/reduction/AtomicReduction.i.dfy\");\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/option.s.dfy\");\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/seqs.s.dfy\");\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/seqs.i.dfy\");\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/sets.i.dfy\");\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/maps.i.dfy\");\n\n      pgp.MainProof.AddImport(\"InvariantsModule\");\n      pgp.MainProof.AddImport(\"GenericArmadaSpecModule\");\n      pgp.MainProof.AddImport(\"AtomicReductionSpecModule\");\n      pgp.MainProof.AddImport(\"AtomicReductionModule\");\n      pgp.MainProof.AddImport(\"GeneralRefinementLemmasModule\");\n      pgp.MainProof.AddImport(\"util_option_s\");\n      pgp.MainProof.AddImport(\"util_collections_seqs_s\");\n      pgp.MainProof.AddImport(\"util_collections_seqs_i\");\n      pgp.MainProof.AddImport(\"util_collections_sets_i\");\n      pgp.MainProof.AddImport(\"util_collections_maps_i\");\n\n      pgp.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/strategies/generic/GenericArmadaLemmas.i.dfy\", \"invariants\");\n      pgp.AddImport(\"GenericArmadaLemmasModule\", null, \"invariants\");\n\n      pgp.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/strategies/reduction/AtomicReductionSpec.i.dfy\", \"defs\");\n      pgp.AddImport(\"AtomicReductionSpecModule\", null, \"defs\");\n\n      pgp.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/strategies/reduction/AtomicReductionSpec.i.dfy\", \"lift\");\n      pgp.AddImport(\"AtomicReductionSpecModule\", null, \"lift\");\n    }\n\n    private void InitializeAuxiliaryProofFiles()\n    {\n      foreach (var atomicPath in lAtomic.AtomicPaths) {\n        var pathFileName = \"path_\" + atomicPath.Name;\n        var pathFile = pgp.proofFiles.CreateAuxiliaryProofFile(pathFileName);\n        pathFile.IncludeAndImportGeneratedFile(\"specs\");\n        pathFile.IncludeAndImportGeneratedFile(\"revelations\");\n        pathFile.IncludeAndImportGeneratedFile(\"invariants\");\n        pathFile.IncludeAndImportGeneratedFile(\"defs\");\n        pathFile.IncludeAndImportGeneratedFile(\"utility\");\n        pathFile.IncludeAndImportGeneratedFile(\"latomic\");\n        pathFile.AddIncludeImport(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/option.s.dfy\", \"util_option_s\");\n        pathFile.AddIncludeImport(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/maps.i.dfy\", \"util_collections_maps_i\");\n        pathFile.AddIncludeImport(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/seqs.i.dfy\", \"util_collections_seqs_i\");\n        pathFile.AddImport(\"util_collections_seqs_s\");\n        pgp.proofFiles.MainProof.IncludeAndImportGeneratedFile(pathFileName);\n      }\n    }\n\n    private void GenerateProofGivenMap()\n    {\n      GenerateProofHeader();\n      GenerateAtomicSpecs(true, null, extraRecurrentPCs);\n      InitializeAuxiliaryProofFiles();\n      GeneratePhasePredicates();\n      GenerateStateAbstractionFunctions_LH();\n      GenerateConvertStep_LH();\n      GenerateConvertAtomicPath_LH();\n      GenerateLocalViewCommutativityLemmas();\n\n      GeneratePCFunctions_L();\n      AddStackMatchesMethodInvariant();\n      GenerateInvariantProof(pgp);\n\n      GenerateReductionRequestComponents();\n      GenerateReductionRequest();\n      GenerateLInitImpliesHInitLemma();\n      GenerateLeftMoverCommutativityLemmas();\n      GenerateRightMoverCommutativityLemmas();\n      GenerateLiftAtomicPathLemmas(\"LHPathTypesMatchYR(ty, HAtomic_GetPathType(hpath))\");\n      GenerateLemmasSupportingValidRequest();\n      GenerateIsValidRequest();\n      GenerateLiftLAtomicToHAtomicLemma();\n      GenerateFinalProof();\n    }\n\n    private void GeneratePhasePredicates()\n    {\n      string str;\n\n      str = @\"\n        predicate IsPhase1PC(pc:L.Armada_PC)\n        {\n      \";\n      if (phase1PCs.Any())\n      {\n        foreach (var pc in phase1PCs)\n        {\n          str += $\"  || pc.{pc}?\\n\";\n        }\n      }\n      else\n      {\n        str += \"false\\n\";\n      }\n      str += \"}\";\n      pgp.AddPredicate(str, \"defs\");\n\n      str = @\"\n        predicate IsPhase2PC(pc:L.Armada_PC)\n        {\n      \";\n      if (phase2PCs.Any())\n      {\n        foreach (var pc in phase2PCs)\n        {\n          str += $\"  || pc.{pc}?\\n\";\n        }\n      }\n      else\n      {\n        str += \"false\\n\";\n      }\n      str += \"}\";\n      pgp.AddPredicate(str, \"defs\");\n    }\n\n    private void GenerateReductionRequestComponents()\n    {\n      string str;\n\n      phase2PCToPath = new Dictionary<ArmadaPC, AtomicPath>();\n      foreach (var atomicPath in lAtomic.AtomicPaths.Where(ap => !ap.Tau && !ap.Stopping && phase2PCs.Contains(ap.StartPC))) {\n        var pc = atomicPath.StartPC;\n        if (phase2PCToPath.ContainsKey(pc)) {\n          AH.PrintError(pgp.prog, $\"Multiple instructions occur at phase-2 PC {pc}.  I can't tell which of them to use for the proof that left movers are always enabled.\");\n        }\n        else {\n          phase2PCToPath[pc] = atomicPath;\n        }\n      }\n\n      str = $@\"\n        predicate LLStateRefinement(ls:LState, hs:LState)\n        {{\n          {pgp.symbolsLow.RefinementConstraint}\n        }}\n      \";\n      pgp.AddPredicate(str, \"defs\");\n\n      str = @\"\n        predicate LLPlusStateRefinement(ls:LPlusState, hs:LPlusState)\n        {\n          LLStateRefinement(ls.s, hs.s)\n        }\n      \";\n      pgp.AddPredicate(str, \"defs\");\n\n      str = @\"\n        function GetLLRefinementRelation() : RefinementRelation<LPlusState, LPlusState>\n        {\n          iset p:RefinementPair<LPlusState, LPlusState> | LLPlusStateRefinement(p.low, p.high)\n        }\n      \";\n      pgp.AddFunction(str, \"defs\");\n\n      str = @\"\n        function GenerateLeftMover(s:LPlusState, tid:Armada_ThreadHandle) : LAtomic_Path\n        {\n           if tid in s.s.threads then\n             var pc := s.s.threads[tid].pc;\n      \";\n      foreach (KeyValuePair<ArmadaPC, AtomicPath> entry in phase2PCToPath) {\n        str += $\"    if pc.{entry.Key}? then { lAtomic.GetConstructorString(entry.Value) } else\\n\";\n      }\n      str += $@\"\n             { lAtomic.GetConstructorString(lAtomic.TauPath) }\n           else\n             { lAtomic.GetConstructorString(lAtomic.TauPath) }\n        }}\n      \";\n      pgp.AddFunction(str, \"defs\");\n\n      str = @\"\n        function LeftMoverGenerationProgress(s:LPlusState, tid:Armada_ThreadHandle) : (progress:int)\n          ensures progress >= 0\n        {\n          if tid in s.s.threads then\n            var pc := s.s.threads[tid].pc;\n            lemma_PCInstructionCountLessThanMethodInstructionCount_L(pc);\n            MethodToInstructionCount_L(PCToMethod_L(pc)) - PCToInstructionCount_L(pc)\n          else\n            0\n        }\n      \";\n      pgp.AddFunction(str, \"defs\");\n    }\n\n    private void GenerateReductionRequest()\n    {\n      pgp.AddTypeSynonym(\"type ARRequest = AtomicReductionRequest<LPlusState, LAtomic_Path, L.Armada_PC, HState, HAtomic_Path, H.Armada_PC>\", \"defs\");\n\n      string str = @\"\n        function GetAtomicReductionRequest() : ARRequest\n        {\n          AtomicReductionRequest(LAtomic_GetSpecFunctions(), HAtomic_GetSpecFunctions(),\n                                 GetLPlusHRefinementRelation(), InductiveInv, GetLLRefinementRelation(),\n                                 ConvertTotalState_LPlusH, ConvertAtomicPath_LH, ConvertPC_LH, \n                                 IsPhase1PC, IsPhase2PC, GenerateLeftMover, LeftMoverGenerationProgress)\n        }\n      \";\n      pgp.AddFunction(str, \"defs\");\n    }\n\n    private void GenerateLInitImpliesHInitLemma()\n    {\n      GenerateLemmasHelpfulForProvingInitPreservation_LH();\n\n      string str;\n\n      str = @\"\n        lemma lemma_LInitImpliesHInit(arr:ARRequest)\n          requires arr == GetAtomicReductionRequest()\n          ensures  LInitImpliesHInit(arr)\n        {\n          forall ls | arr.l.init(ls)\n            ensures arr.h.init(arr.lstate_to_hstate(ls))\n          {\n            var hs := arr.lstate_to_hstate(ls);\n            var hconfig := ConvertConfig_LH(ls.config);\n\n            lemma_ConvertTotalStatePreservesInit(ls.s, hs, ls.config, hconfig);\n            assert H.Armada_InitConfig(hs, hconfig);\n          }\n        }\n      \";\n      pgp.AddLemma(str);\n    }\n\n    private void GenerateRightMoverCommutativityLemmaWithSpecificOther(AtomicPath rightMoverPath, AtomicPath otherPath)\n    {\n      string str;\n\n      var prRightMover = new ReductionPathPrinter(lAtomic, \"right_mover\", \"initial_state\", \"state_after_right_mover\",\n                                                  \"right_mover\", \"mover_tid\");\n      var prOther = new ReductionPathPrinter(lAtomic, \"other_path\", \"state_after_right_mover\", \"state_after_both_paths\",\n                                             \"other_path\", \"other_tid\");\n      var prOtherAlt = new ReductionPathPrinter(lAtomic, \"right_mover_alt\", \"initial_state\", \"state_after_other_path\",\n                                                \"other_path\", \"other_tid\");\n      var prRightMoverAlt = new ReductionPathPrinter(lAtomic, \"other_path_alt\", \"state_after_other_path\", \"state_after_both_paths'\",\n                                                     \"right_mover\", \"mover_tid\");\n\n      if (otherPath.Stopping) {\n        str = $@\"\n          lemma lemma_RightMoverPreservesCrashWithSpecificOther_{rightMoverPath.Name}_{otherPath.Name}(\n            initial_state: LPlusState,\n            state_after_right_mover: LPlusState,\n            state_after_both_paths: LPlusState,\n            right_mover: LAtomic_Path,\n            other_path: LAtomic_Path,\n            mover_tid: Armada_ThreadHandle,\n            other_tid: Armada_ThreadHandle,\n            state_after_other_path: LPlusState\n            )\n            requires InductiveInv(initial_state)\n            requires right_mover.LAtomic_Path_{rightMoverPath.Name}?\n            requires other_path.LAtomic_Path_{otherPath.Name}?\n            requires !right_mover.LAtomic_Path_Tau?\n            requires LAtomic_ValidPath(initial_state, right_mover, mover_tid)\n            requires state_after_right_mover == LAtomic_GetStateAfterPath(initial_state, right_mover, mover_tid)\n            requires LAtomic_ValidPath(state_after_right_mover, other_path, other_tid)\n            requires state_after_both_paths == LAtomic_GetStateAfterPath(state_after_right_mover, other_path, other_tid)\n            requires mover_tid in state_after_right_mover.s.threads\n            requires IsPhase1PC(state_after_right_mover.s.threads[mover_tid].pc)\n            requires other_path.LAtomic_Path_Tau? || other_tid != mover_tid\n            requires state_after_other_path == LAtomic_GetStateAfterPath(initial_state, other_path, other_tid)\n            requires !state_after_both_paths.s.stop_reason.Armada_NotStopped?\n            ensures  LAtomic_ValidPath(initial_state, other_path, other_tid)\n            ensures  !state_after_other_path.s.stop_reason.Armada_NotStopped?\n            ensures  LLPlusStateRefinement(state_after_both_paths, state_after_other_path)\n          {{\n            { prRightMover.GetOpenValidPathInvocation(rightMoverPath) }\n            { prOther.GetOpenValidPathInvocation(otherPath) }\n\n            { prOtherAlt.GetOpenPathInvocation(otherPath) }\n\n            /* { prOtherAlt.GetAssertValidPathInvocation(otherPath) } */\n\n            ProofCustomizationGoesHere();\n          }}\n        \";\n        pgp.AddLemma(str, \"path_\" + otherPath.Name);\n      }\n      else {\n        str = $@\"\n          lemma lemma_RightMoverCommutativityWithSpecificOther_{rightMoverPath.Name}_{otherPath.Name}(\n            initial_state:LPlusState,\n            state_after_right_mover:LPlusState,\n            state_after_both_paths:LPlusState,\n            right_mover:LAtomic_Path,\n            other_path:LAtomic_Path,\n            mover_tid:Armada_ThreadHandle,\n            other_tid:Armada_ThreadHandle,\n            state_after_other_path:LPlusState\n            )\n            requires InductiveInv(initial_state)\n            requires right_mover.LAtomic_Path_{rightMoverPath.Name}?\n            requires other_path.LAtomic_Path_{otherPath.Name}?\n            requires LAtomic_ValidPath(initial_state, right_mover, mover_tid)\n            requires state_after_right_mover == LAtomic_GetStateAfterPath(initial_state, right_mover, mover_tid)\n            requires LAtomic_ValidPath(state_after_right_mover, other_path, other_tid)\n            requires state_after_both_paths == LAtomic_GetStateAfterPath(state_after_right_mover, other_path, other_tid)\n            requires mover_tid in state_after_right_mover.s.threads\n            requires IsPhase1PC(state_after_right_mover.s.threads[mover_tid].pc)\n            requires other_path.LAtomic_Path_Tau? || other_tid != mover_tid\n            requires state_after_other_path == LAtomic_GetStateAfterPath(initial_state, other_path, other_tid)\n            requires state_after_both_paths.s.stop_reason.Armada_NotStopped?\n            ensures  LAtomic_ValidPath(initial_state, other_path, other_tid)\n            ensures  LAtomic_ValidPath(state_after_other_path, right_mover, mover_tid)\n            ensures  state_after_both_paths == LAtomic_GetStateAfterPath(state_after_other_path, right_mover, mover_tid)\n          {{\n            var state_after_both_paths' := LAtomic_GetStateAfterPath(state_after_other_path, right_mover, mover_tid);\n\n            { prRightMover.GetOpenValidPathInvocation(rightMoverPath) }\n            { prOther.GetOpenValidPathInvocation(otherPath) }\n\n            { prOtherAlt.GetOpenPathInvocation(otherPath) }\n            { prRightMoverAlt.GetOpenPathInvocation(rightMoverPath) }\n\n            /* { prOtherAlt.GetAssertValidPathInvocation(otherPath) } */\n            /* { prRightMoverAlt.GetAssertValidPathInvocation(rightMoverPath) } */\n\n            ProofCustomizationGoesHere();\n          }}\n        \";\n        pgp.AddLemma(str, \"path_\" + otherPath.Name);\n      }\n    }\n\n    private void GenerateSpecificRightMoverCommutativityLemma(AtomicPath rightMoverPath)\n    {\n      var finalCasesCommutativity = \"\";\n      var finalCasesCrashPreservation = \"\";\n\n      foreach (var otherPath in lAtomic.AtomicPaths) {\n        GenerateRightMoverCommutativityLemmaWithSpecificOther(rightMoverPath, otherPath);\n\n        var caseIntro = $\"case LAtomic_Path_{otherPath.Name}(_) =>\\n\";\n        finalCasesCommutativity += caseIntro;\n        finalCasesCrashPreservation += caseIntro;\n        \n        if (otherPath.Stopping) {\n          finalCasesCommutativity += $@\"\n            lemma_LAtomic_PathHasPCEffect_{otherPath.Name}(state_after_right_mover, other_path, other_tid);\n            assert !asf.state_ok(state_after_both_paths);\n            assert false;\";\n          finalCasesCrashPreservation += $@\"\n            lemma_RightMoverPreservesCrashWithSpecificOther_{rightMoverPath.Name}_{otherPath.Name}(\n              initial_state, state_after_right_mover, state_after_both_paths, right_mover, other_path,\n              mover_tid, other_tid, state_after_other_path);\";\n        }\n        else {\n          finalCasesCommutativity += $@\"\n            lemma_RightMoverCommutativityWithSpecificOther_{rightMoverPath.Name}_{otherPath.Name}(\n              initial_state, state_after_right_mover, state_after_both_paths, right_mover, other_path,\n              mover_tid, other_tid, state_after_other_path);\";\n          finalCasesCrashPreservation += $@\"\n            lemma_LAtomic_PathHasPCEffect_{otherPath.Name}(state_after_right_mover, other_path, other_tid);\n            lemma_LAtomic_PathHasPCEffect_{otherPath.Name}(state_after_right_mover, other_path, other_tid);\n            assert asf.state_ok(state_after_both_paths);\n            assert false;\";\n        }\n      }\n\n      string str;\n\n      str = $@\"\n        lemma lemma_RightMoverCommutativity_{rightMoverPath.Name}(\n          initial_state: LPlusState,\n          state_after_right_mover: LPlusState,\n          state_after_both_paths: LPlusState,\n          right_mover: LAtomic_Path,\n          other_path: LAtomic_Path,\n          mover_tid: Armada_ThreadHandle,\n          other_tid: Armada_ThreadHandle,\n          state_after_other_path: LPlusState\n          )\n          requires InductiveInv(initial_state)\n          requires right_mover.LAtomic_Path_{rightMoverPath.Name}?\n          requires LAtomic_ValidPath(initial_state, right_mover, mover_tid)\n          requires state_after_right_mover == LAtomic_GetStateAfterPath(initial_state, right_mover, mover_tid)\n          requires LAtomic_ValidPath(state_after_right_mover, other_path, other_tid)\n          requires state_after_both_paths == LAtomic_GetStateAfterPath(state_after_right_mover, other_path, other_tid)\n          requires mover_tid in state_after_right_mover.s.threads\n          requires IsPhase1PC(state_after_right_mover.s.threads[mover_tid].pc)\n          requires other_path.LAtomic_Path_Tau? || other_tid != mover_tid\n          requires state_after_other_path == LAtomic_GetStateAfterPath(initial_state, other_path, other_tid)\n          requires state_after_both_paths.s.stop_reason.Armada_NotStopped?\n          ensures  LAtomic_ValidPath(initial_state, other_path, other_tid)\n          ensures  LAtomic_ValidPath(state_after_other_path, right_mover, mover_tid)\n          ensures  state_after_both_paths == LAtomic_GetStateAfterPath(state_after_other_path, right_mover, mover_tid)\n        {{\n          var asf := LAtomic_GetSpecFunctions();\n          match other_path {{\n            {finalCasesCommutativity}\n          }}\n        }}\n      \";\n      pgp.AddLemma(str);\n\n      str = $@\"\n        lemma lemma_RightMoverPreservesCrash_{rightMoverPath.Name}(\n          initial_state: LPlusState,\n          state_after_right_mover: LPlusState,\n          state_after_both_paths: LPlusState,\n          right_mover: LAtomic_Path,\n          other_path: LAtomic_Path,\n          mover_tid: Armada_ThreadHandle,\n          other_tid: Armada_ThreadHandle,\n          state_after_other_path: LPlusState\n          )\n          requires InductiveInv(initial_state)\n          requires right_mover.LAtomic_Path_{rightMoverPath.Name}?\n          requires LAtomic_ValidPath(initial_state, right_mover, mover_tid)\n          requires state_after_right_mover == LAtomic_GetStateAfterPath(initial_state, right_mover, mover_tid)\n          requires LAtomic_ValidPath(state_after_right_mover, other_path, other_tid)\n          requires state_after_both_paths == LAtomic_GetStateAfterPath(state_after_right_mover, other_path, other_tid)\n          requires mover_tid in state_after_right_mover.s.threads\n          requires IsPhase1PC(state_after_right_mover.s.threads[mover_tid].pc)\n          requires other_path.LAtomic_Path_Tau? || other_tid != mover_tid\n          requires state_after_other_path == LAtomic_GetStateAfterPath(initial_state, other_path, other_tid)\n          requires !state_after_both_paths.s.stop_reason.Armada_NotStopped?\n          ensures  LAtomic_ValidPath(initial_state, other_path, other_tid)\n          ensures  !state_after_other_path.s.stop_reason.Armada_NotStopped?\n          ensures  LLPlusStateRefinement(state_after_both_paths, state_after_other_path)\n        {{\n          var asf := LAtomic_GetSpecFunctions();\n          match other_path {{\n            {finalCasesCrashPreservation}\n          }}\n        }}\n      \";\n      pgp.AddLemma(str);\n    }\n\n    private void GenerateRightMoverCommutativityLemmas()\n    {\n      string finalCasesCommutativity = \"\";\n      string finalCasesCrashPreservation = \"\";\n\n      foreach (var atomicPath in lAtomic.AtomicPaths) {\n\n        var caseIntro = $\"case LAtomic_Path_{atomicPath.Name}(_) =>\\n\";\n        finalCasesCommutativity += caseIntro;\n        finalCasesCrashPreservation += caseIntro;\n        \n        if (atomicPath.Tau) {\n          finalCasesCommutativity += $@\"\n            assert right_mover.LAtomic_Path_Tau?;\n            assert false;\";\n          finalCasesCrashPreservation += $@\"\n            assert right_mover.LAtomic_Path_Tau?;\n            assert false;\";\n        }\n        else if (atomicPath.Stopping) {\n          finalCasesCommutativity += $@\"\n              lemma_LAtomic_PathHasPCEffect_{atomicPath.Name}(initial_state, right_mover, mover_tid);\n              assert !asf.state_ok(state_after_right_mover);\n              assert false;\";\n          finalCasesCrashPreservation += $@\"\n              lemma_LAtomic_PathHasPCEffect_{atomicPath.Name}(initial_state, right_mover, mover_tid);\n              assert !asf.state_ok(state_after_right_mover);\n              assert false;\";\n        }\n        else if (phase1PCs.Contains(atomicPath.EndPC)) {\n          GenerateSpecificRightMoverCommutativityLemma(atomicPath);\n          finalCasesCommutativity += $@\"\n            lemma_RightMoverCommutativity_{atomicPath.Name}(\n              initial_state, state_after_right_mover, state_after_both_paths, right_mover, other_path,\n              mover_tid, other_tid, state_after_other_path);\";\n          finalCasesCrashPreservation += $@\"\n            lemma_RightMoverPreservesCrash_{atomicPath.Name}(\n              initial_state, state_after_right_mover, state_after_both_paths, right_mover, other_path,\n              mover_tid, other_tid, state_after_other_path);\";\n        }\n        else {\n          finalCasesCommutativity += $@\"\n            lemma_LAtomic_PathHasPCEffect_{atomicPath.Name}(initial_state, right_mover, mover_tid);\n            assert !IsPhase1PC(state_after_right_mover.s.threads[mover_tid].pc);\n            assert false;\";\n          finalCasesCrashPreservation += $@\"\n            lemma_LAtomic_PathHasPCEffect_{atomicPath.Name}(initial_state, right_mover, mover_tid);\n            assert !IsPhase1PC(state_after_right_mover.s.threads[mover_tid].pc);\n            assert false;\";\n        }\n      }\n\n      string str;\n\n      str = $@\"\n        lemma lemma_RightMoverCommutativity(\n          initial_state: LPlusState,\n          state_after_right_mover: LPlusState,\n          state_after_both_paths: LPlusState,\n          right_mover: LAtomic_Path,\n          other_path: LAtomic_Path,\n          mover_tid: Armada_ThreadHandle,\n          other_tid: Armada_ThreadHandle,\n          state_after_other_path: LPlusState\n          )\n          requires InductiveInv(initial_state)\n          requires !right_mover.LAtomic_Path_Tau?\n          requires LAtomic_ValidPath(initial_state, right_mover, mover_tid)\n          requires state_after_right_mover == LAtomic_GetStateAfterPath(initial_state, right_mover, mover_tid)\n          requires LAtomic_ValidPath(state_after_right_mover, other_path, other_tid)\n          requires state_after_both_paths == LAtomic_GetStateAfterPath(state_after_right_mover, other_path, other_tid)\n          requires mover_tid in state_after_right_mover.s.threads\n          requires IsPhase1PC(state_after_right_mover.s.threads[mover_tid].pc)\n          requires other_path.LAtomic_Path_Tau? || other_tid != mover_tid\n          requires state_after_other_path == LAtomic_GetStateAfterPath(initial_state, other_path, other_tid)\n          requires state_after_both_paths.s.stop_reason.Armada_NotStopped?\n          ensures  LAtomic_ValidPath(initial_state, other_path, other_tid)\n          ensures  LAtomic_ValidPath(state_after_other_path, right_mover, mover_tid)\n          ensures  state_after_both_paths == LAtomic_GetStateAfterPath(state_after_other_path, right_mover, mover_tid)\n        {{\n          var asf := LAtomic_GetSpecFunctions();\n          lemma_LAtomic_PathImpliesThreadRunning(state_after_right_mover, other_path, other_tid);\n          assert asf.state_ok(state_after_right_mover);\n          match right_mover {{\n            {finalCasesCommutativity}\n          }}\n        }}\n      \";\n      pgp.AddLemma(str);\n\n      str = $@\"\n        lemma lemma_RightMoverPreservesCrash(\n          initial_state: LPlusState,\n          state_after_right_mover: LPlusState,\n          state_after_both_paths: LPlusState,\n          right_mover: LAtomic_Path,\n          other_path: LAtomic_Path,\n          mover_tid: Armada_ThreadHandle,\n          other_tid: Armada_ThreadHandle,\n          state_after_other_path: LPlusState\n          )\n          requires InductiveInv(initial_state)\n          requires !right_mover.LAtomic_Path_Tau?\n          requires LAtomic_ValidPath(initial_state, right_mover, mover_tid)\n          requires state_after_right_mover == LAtomic_GetStateAfterPath(initial_state, right_mover, mover_tid)\n          requires LAtomic_ValidPath(state_after_right_mover, other_path, other_tid)\n          requires state_after_both_paths == LAtomic_GetStateAfterPath(state_after_right_mover, other_path, other_tid)\n          requires mover_tid in state_after_right_mover.s.threads\n          requires IsPhase1PC(state_after_right_mover.s.threads[mover_tid].pc)\n          requires other_path.LAtomic_Path_Tau? || other_tid != mover_tid\n          requires state_after_other_path == LAtomic_GetStateAfterPath(initial_state, other_path, other_tid)\n          requires !state_after_both_paths.s.stop_reason.Armada_NotStopped?\n          ensures  LAtomic_ValidPath(initial_state, other_path, other_tid)\n          ensures  !state_after_other_path.s.stop_reason.Armada_NotStopped?\n          ensures  LLPlusStateRefinement(state_after_both_paths, state_after_other_path)\n        {{\n          var asf := LAtomic_GetSpecFunctions();\n          lemma_LAtomic_PathImpliesThreadRunning(state_after_right_mover, other_path, other_tid);\n          match right_mover {{\n            {finalCasesCrashPreservation}\n          }}\n        }}\n      \";\n      pgp.AddLemma(str);\n    }\n\n    private void GenerateLeftMoverCommutativityLemmaWithSpecificOther(AtomicPath otherPath, AtomicPath leftMoverPath)\n    {\n      string str;\n\n      if (!otherPath.Stopping && !leftMoverPath.Stopping) {\n        var prOther = new ReductionPathPrinter(lAtomic, \"other_path\", \"initial_state\", \"state_after_othe_path\", \"other_path\", \"other_tid\");\n        var prLeftMover = new ReductionPathPrinter(lAtomic, \"left_mover\", \"state_after_other_path\", \"state_after_both_paths\",\n                                                   \"left_mover\", \"mover_tid\");\n        var prLeftMoverAlt = new ReductionPathPrinter(lAtomic, \"left_mover_alt\", \"initial_state\", \"state_after_left_mover\",\n                                                      \"left_mover\", \"mover_tid\");\n        var prOtherAlt = new ReductionPathPrinter(lAtomic, \"other_path_alt\", \"state_after_left_mover\", \"state_after_both_paths'\",\n                                                  \"other_path\", \"other_tid\");\n\n        str = $@\"\n          lemma lemma_LeftMoverCommutativityWithSpecificOther_{otherPath.Name}_{leftMoverPath.Name}(\n            initial_state: LPlusState,\n            state_after_other_path: LPlusState,\n            state_after_both_paths: LPlusState,\n            other_path: LAtomic_Path,\n            left_mover: LAtomic_Path,\n            mover_tid: Armada_ThreadHandle,\n            other_tid: Armada_ThreadHandle,\n            state_after_left_mover: LPlusState\n            )\n            requires InductiveInv(initial_state)\n            requires other_path.LAtomic_Path_{otherPath.Name}?\n            requires left_mover.LAtomic_Path_{leftMoverPath.Name}?\n            requires LAtomic_ValidPath(initial_state, other_path, other_tid)\n            requires state_after_other_path == LAtomic_GetStateAfterPath(initial_state, other_path, other_tid)\n            requires LAtomic_ValidPath(state_after_other_path, left_mover, mover_tid)\n            requires state_after_both_paths == LAtomic_GetStateAfterPath(state_after_other_path, left_mover, mover_tid)\n            requires mover_tid in state_after_other_path.s.threads\n            requires IsPhase2PC(state_after_other_path.s.threads[mover_tid].pc)\n            requires other_path.LAtomic_Path_Tau? || other_tid != mover_tid\n            requires state_after_both_paths.s.stop_reason.Armada_NotStopped?\n            requires state_after_left_mover == LAtomic_GetStateAfterPath(initial_state, left_mover, mover_tid)\n            ensures  LAtomic_ValidPath(initial_state, left_mover, mover_tid)\n            ensures  LAtomic_ValidPath(state_after_left_mover, other_path, other_tid)\n            ensures  state_after_both_paths == LAtomic_GetStateAfterPath(state_after_left_mover, other_path, other_tid)\n          {{\n            var state_after_both_paths' := LAtomic_GetStateAfterPath(state_after_left_mover, other_path, other_tid);\n\n            { prOther.GetOpenValidPathInvocation(otherPath) }\n            { prLeftMover.GetOpenValidPathInvocation(leftMoverPath) }\n\n            { prLeftMoverAlt.GetOpenPathInvocation(leftMoverPath) }\n            { prOtherAlt.GetOpenPathInvocation(otherPath) }\n\n            /* { prLeftMoverAlt.GetAssertValidPathInvocation(leftMoverPath) } */\n            /* { prOtherAlt.GetAssertValidPathInvocation(otherPath) } */\n\n            ProofCustomizationGoesHere();\n          }}\n        \";\n        pgp.AddLemma(str, \"path_\" + otherPath.Name);\n      }\n\n      if (otherPath.Stopping) {\n        var prOther = new ReductionPathPrinter(lAtomic, \"other_path\", \"initial_state\", \"state_after_other_path\", \"other_path\", \"other_tid\");\n        var prLeftMover = new ReductionPathPrinter(lAtomic, \"left_mover\", \"initial_state\", \"state_after_left_mover\",\n                                                   \"left_mover\", \"mover_tid\");\n        var prOtherAlt = new ReductionPathPrinter(lAtomic, \"other_path_alt\", \"state_after_left_mover\", \"state_after_both_paths\",\n                                                  \"other_path\", \"other_tid\");\n\n        str = $@\"\n          lemma lemma_LeftMoverPreservesCrashWithSpecificOther_{otherPath.Name}_{leftMoverPath.Name}(\n            initial_state: LPlusState,\n            state_after_other_path: LPlusState,\n            state_after_left_mover: LPlusState,\n            other_path: LAtomic_Path,\n            left_mover: LAtomic_Path,\n            mover_tid: Armada_ThreadHandle,\n            other_tid: Armada_ThreadHandle,\n            state_after_both_paths: LPlusState\n            )\n            requires InductiveInv(initial_state)\n            requires other_path.LAtomic_Path_{otherPath.Name}?\n            requires left_mover.LAtomic_Path_{leftMoverPath.Name}?\n            requires LAtomic_ValidPath(initial_state, other_path, other_tid)\n            requires state_after_other_path == LAtomic_GetStateAfterPath(initial_state, other_path, other_tid)\n            requires LAtomic_ValidPath(initial_state, left_mover, mover_tid)\n            requires state_after_left_mover == LAtomic_GetStateAfterPath(initial_state, left_mover, mover_tid)\n            requires mover_tid in initial_state.s.threads\n            requires IsPhase2PC(initial_state.s.threads[mover_tid].pc)\n            requires other_path.LAtomic_Path_Tau? || other_tid != mover_tid\n            requires !state_after_other_path.s.stop_reason.Armada_NotStopped?\n            requires state_after_both_paths == LAtomic_GetStateAfterPath(state_after_left_mover, other_path, other_tid)\n            ensures  LAtomic_ValidPath(state_after_left_mover, other_path, other_tid)\n            ensures  !state_after_both_paths.s.stop_reason.Armada_NotStopped?\n            ensures  LLPlusStateRefinement(state_after_other_path, state_after_both_paths)\n          {{\n            { prOther.GetOpenValidPathInvocation(otherPath) }\n            { prLeftMover.GetOpenValidPathInvocation(leftMoverPath) }\n\n            { prOtherAlt.GetOpenPathInvocation(otherPath) }\n\n            /* { prOtherAlt.GetAssertValidPathInvocation(otherPath) } */\n\n            ProofCustomizationGoesHere();\n          }}\n        \";\n        pgp.AddLemma(str, \"path_\" + otherPath.Name);\n      }\n\n      if (!otherPath.Stopping && leftMoverPath.Stopping) {\n        var prOther = new ReductionPathPrinter(lAtomic, \"other_path\", \"initial_state\", \"state_after_other_path\", \"other_path\", \"other_tid\");\n        var prLeftMover = new ReductionPathPrinter(lAtomic, \"left_mover\", \"state_after_other_path\", \"state_after_both_paths\",\n                                                   \"left_mover\", \"mover_tid\");\n        var prLeftMoverAlt = new ReductionPathPrinter(lAtomic, \"left_mover_alt\", \"initial_state\", \"state_after_left_mover\",\n                                                      \"left_mover\", \"mover_tid\");\n\n        str = $@\"\n          lemma lemma_LeftMoverPreservesSelfCrashWithSpecificOther_{otherPath.Name}_{leftMoverPath.Name}(\n            initial_state: LPlusState,\n            state_after_other_path: LPlusState,\n            state_after_both_paths: LPlusState,\n            other_path: LAtomic_Path,\n            left_mover: LAtomic_Path,\n            mover_tid: Armada_ThreadHandle,\n            other_tid: Armada_ThreadHandle,\n            state_after_left_mover: LPlusState\n            )\n            requires InductiveInv(initial_state)\n            requires other_path.LAtomic_Path_{otherPath.Name}?\n            requires left_mover.LAtomic_Path_{leftMoverPath.Name}?\n            requires LAtomic_ValidPath(initial_state, other_path, other_tid)\n            requires state_after_other_path == LAtomic_GetStateAfterPath(initial_state, other_path, other_tid)\n            requires LAtomic_ValidPath(state_after_other_path, left_mover, mover_tid)\n            requires state_after_both_paths == LAtomic_GetStateAfterPath(state_after_other_path, left_mover, mover_tid)\n            requires mover_tid in state_after_other_path.s.threads\n            requires IsPhase2PC(state_after_other_path.s.threads[mover_tid].pc)\n            requires other_path.LAtomic_Path_Tau? || other_tid != mover_tid\n            requires initial_state.s.stop_reason.Armada_NotStopped?\n            requires !state_after_both_paths.s.stop_reason.Armada_NotStopped?\n            requires state_after_left_mover == LAtomic_GetStateAfterPath(initial_state, left_mover, mover_tid)\n            ensures  LAtomic_ValidPath(initial_state, left_mover, mover_tid)\n            ensures  !state_after_left_mover.s.stop_reason.Armada_NotStopped?\n            ensures  LLPlusStateRefinement(state_after_both_paths, state_after_left_mover)\n          {{\n            { prOther.GetOpenValidPathInvocation(otherPath) }\n            { prLeftMover.GetOpenValidPathInvocation(leftMoverPath) }\n\n            { prLeftMoverAlt.GetOpenPathInvocation(leftMoverPath) }\n\n            /* { prLeftMoverAlt.GetAssertValidPathInvocation(leftMoverPath) } */\n\n            ProofCustomizationGoesHere();\n          }}\n        \";\n        pgp.AddLemma(str, \"path_\" + otherPath.Name);\n      }\n    }\n\n    private void GenerateSpecificLeftMoverCommutativityLemma(AtomicPath leftMoverPath)\n    {\n      var finalCasesCommutativity = \"\";\n      var finalCasesCrashPreservation = \"\";\n      var finalCasesSelfCrashPreservation = \"\";\n\n      foreach (var otherPath in lAtomic.AtomicPaths) {\n        GenerateLeftMoverCommutativityLemmaWithSpecificOther(otherPath, leftMoverPath);\n\n        var caseIntro = $\"case LAtomic_Path_{otherPath.Name}(_) =>\\n\";\n\n        if (!leftMoverPath.Stopping) {\n          finalCasesCommutativity += caseIntro;\n          if (otherPath.Stopping) {\n            finalCasesCommutativity += $@\"\n              lemma_LAtomic_PathHasPCEffect_{otherPath.Name}(initial_state, other_path, other_tid);\n              assert !asf.state_ok(state_after_other_path);\n              assert false;\";\n          }\n          else {\n            finalCasesCommutativity += $@\"\n              lemma_LeftMoverCommutativityWithSpecificOther_{otherPath.Name}_{leftMoverPath.Name}(\n                initial_state, state_after_other_path, state_after_both_paths, other_path, left_mover,\n                mover_tid, other_tid, state_after_left_mover);\";\n          }\n        }\n\n        finalCasesCrashPreservation += caseIntro;\n        if (otherPath.Stopping) {\n          finalCasesCrashPreservation += $@\"\n            lemma_LeftMoverPreservesCrashWithSpecificOther_{otherPath.Name}_{leftMoverPath.Name}(\n              initial_state, state_after_other_path, state_after_left_mover, other_path, left_mover,\n              mover_tid, other_tid, state_after_both_paths);\";\n        }\n        else {\n          finalCasesCrashPreservation += $@\"\n            lemma_LAtomic_PathHasPCEffect_{otherPath.Name}(initial_state, other_path, other_tid);\n            lemma_LAtomic_PathHasPCEffect_{otherPath.Name}(initial_state, other_path, other_tid);\n            assert asf.state_ok(state_after_other_path);\n            assert false;\";\n        }\n\n        if (leftMoverPath.Stopping) {\n          finalCasesSelfCrashPreservation += caseIntro;\n          if (otherPath.Stopping) {\n            finalCasesSelfCrashPreservation += $@\"\n              lemma_LAtomic_PathHasPCEffect_{otherPath.Name}(initial_state, other_path, other_tid);\n              assert !asf.state_ok(state_after_other_path);\n              assert false;\";\n          }\n          else {\n            finalCasesSelfCrashPreservation += $@\"\n              lemma_LeftMoverPreservesSelfCrashWithSpecificOther_{otherPath.Name}_{leftMoverPath.Name}(\n                initial_state, state_after_other_path, state_after_both_paths, other_path, left_mover,\n                mover_tid, other_tid, state_after_left_mover);\";\n          }\n        }\n      }\n\n      string str;\n\n      if (!leftMoverPath.Stopping) {\n        str = $@\"\n          lemma lemma_LeftMoverCommutativity_{leftMoverPath.Name}(\n            initial_state: LPlusState,\n            state_after_other_path: LPlusState,\n            state_after_both_paths: LPlusState,\n            other_path: LAtomic_Path,\n            left_mover: LAtomic_Path,\n            mover_tid: Armada_ThreadHandle,\n            other_tid: Armada_ThreadHandle,\n            state_after_left_mover: LPlusState\n            )\n            requires InductiveInv(initial_state)\n            requires LAtomic_ValidPath(initial_state, other_path, other_tid)\n            requires state_after_other_path == LAtomic_GetStateAfterPath(initial_state, other_path, other_tid)\n            requires left_mover.LAtomic_Path_{leftMoverPath.Name}?\n            requires LAtomic_ValidPath(state_after_other_path, left_mover, mover_tid)\n            requires state_after_both_paths == LAtomic_GetStateAfterPath(state_after_other_path, left_mover, mover_tid)\n            requires mover_tid in state_after_other_path.s.threads\n            requires IsPhase2PC(state_after_other_path.s.threads[mover_tid].pc)\n            requires other_path.LAtomic_Path_Tau? || other_tid != mover_tid\n            requires state_after_both_paths.s.stop_reason.Armada_NotStopped?\n            requires state_after_left_mover == LAtomic_GetStateAfterPath(initial_state, left_mover, mover_tid)\n            ensures  LAtomic_ValidPath(initial_state, left_mover, mover_tid)\n            ensures  LAtomic_ValidPath(state_after_left_mover, other_path, other_tid)\n            ensures  state_after_both_paths == LAtomic_GetStateAfterPath(state_after_left_mover, other_path, other_tid)\n          {{\n            var asf := LAtomic_GetSpecFunctions();\n            lemma_LAtomic_PathImpliesThreadRunning(state_after_other_path, left_mover, mover_tid);\n            match other_path {{\n              {finalCasesCommutativity}\n            }}\n          }}\n        \";\n        pgp.AddLemma(str);\n      }\n\n      str = $@\"\n        lemma lemma_LeftMoverPreservesCrash_{leftMoverPath.Name}(\n          initial_state: LPlusState,\n          state_after_other_path: LPlusState,\n          state_after_left_mover: LPlusState,\n          other_path: LAtomic_Path,\n          left_mover: LAtomic_Path,\n          mover_tid: Armada_ThreadHandle,\n          other_tid: Armada_ThreadHandle,\n          state_after_both_paths: LPlusState\n          )\n          requires InductiveInv(initial_state)\n          requires left_mover.LAtomic_Path_{leftMoverPath.Name}?\n          requires LAtomic_ValidPath(initial_state, other_path, other_tid)\n          requires state_after_other_path == LAtomic_GetStateAfterPath(initial_state, other_path, other_tid)\n          requires LAtomic_ValidPath(initial_state, left_mover, mover_tid)\n          requires state_after_left_mover == LAtomic_GetStateAfterPath(initial_state, left_mover, mover_tid)\n          requires mover_tid in initial_state.s.threads\n          requires IsPhase2PC(initial_state.s.threads[mover_tid].pc)\n          requires other_path.LAtomic_Path_Tau? || other_tid != mover_tid\n          requires !state_after_other_path.s.stop_reason.Armada_NotStopped?\n          requires state_after_both_paths == LAtomic_GetStateAfterPath(state_after_left_mover, other_path, other_tid)\n          ensures  LAtomic_ValidPath(state_after_left_mover, other_path, other_tid)\n          ensures  !state_after_both_paths.s.stop_reason.Armada_NotStopped?\n          ensures  LLPlusStateRefinement(state_after_other_path, state_after_both_paths)\n        {{\n          var asf := LAtomic_GetSpecFunctions();\n          match other_path {{\n            {finalCasesCrashPreservation}\n          }}\n        }}\n      \";\n      pgp.AddLemma(str);\n\n      if (leftMoverPath.Stopping) {\n        str = $@\"\n          lemma lemma_LeftMoverPreservesSelfCrash_{leftMoverPath.Name}(\n            initial_state: LPlusState,\n            state_after_other_path: LPlusState,\n            state_after_both_paths: LPlusState,\n            other_path: LAtomic_Path,\n            left_mover: LAtomic_Path,\n            mover_tid: Armada_ThreadHandle,\n            other_tid: Armada_ThreadHandle,\n            state_after_left_mover: LPlusState\n            )\n            requires InductiveInv(initial_state)\n            requires left_mover.LAtomic_Path_{leftMoverPath.Name}?\n            requires LAtomic_ValidPath(initial_state, other_path, other_tid)\n            requires state_after_other_path == LAtomic_GetStateAfterPath(initial_state, other_path, other_tid)\n            requires LAtomic_ValidPath(state_after_other_path, left_mover, mover_tid)\n            requires state_after_both_paths == LAtomic_GetStateAfterPath(state_after_other_path, left_mover, mover_tid)\n            requires mover_tid in state_after_other_path.s.threads\n            requires IsPhase2PC(state_after_other_path.s.threads[mover_tid].pc)\n            requires other_path.LAtomic_Path_Tau? || other_tid != mover_tid\n            requires initial_state.s.stop_reason.Armada_NotStopped?\n            requires !state_after_both_paths.s.stop_reason.Armada_NotStopped?\n            requires state_after_left_mover == LAtomic_GetStateAfterPath(initial_state, left_mover, mover_tid)\n            ensures  LAtomic_ValidPath(initial_state, left_mover, mover_tid)\n            ensures  !state_after_left_mover.s.stop_reason.Armada_NotStopped?\n            ensures  LLPlusStateRefinement(state_after_both_paths, state_after_left_mover)\n          {{\n            var asf := LAtomic_GetSpecFunctions();\n            lemma_LAtomic_PathImpliesThreadRunning(state_after_other_path, left_mover, mover_tid);\n            match other_path {{\n              {finalCasesSelfCrashPreservation}\n            }}\n          }}\n        \";\n        pgp.AddLemma(str);\n      }\n    }\n\n    private void GenerateLeftMoverCommutativityLemmas()\n    {\n      var finalCasesCommutativity = \"\";\n      var finalCasesCrashPreservation = \"\";\n      var finalCasesSelfCrashPreservation = \"\";\n\n      foreach (var atomicPath in lAtomic.AtomicPaths)\n      {\n        string caseIntro = $\"case LAtomic_Path_{atomicPath.Name}(_) =>\\n\";\n        finalCasesCommutativity += caseIntro;\n        finalCasesCrashPreservation += caseIntro;\n        finalCasesSelfCrashPreservation += caseIntro;\n\n        if (atomicPath.Tau)\n        {\n          finalCasesCommutativity += $@\"\n            assert left_mover.LAtomic_Path_Tau?;\n            assert false;\";\n          finalCasesCrashPreservation += $@\"\n            assert left_mover.LAtomic_Path_Tau?;\n            assert false;\";\n          finalCasesSelfCrashPreservation += $@\"\n            assert left_mover.LAtomic_Path_Tau?;\n            assert false;\";\n        }\n        else if (!phase2PCs.Contains(atomicPath.StartPC))\n        {\n          finalCasesCommutativity += $@\"\n            lemma_LAtomic_PathHasPCEffect_{atomicPath.Name}(state_after_other_path, left_mover, mover_tid);\n            assert !IsPhase2PC(state_after_other_path.s.threads[mover_tid].pc);\n            assert false;\";\n          finalCasesCrashPreservation += $@\"\n            lemma_LAtomic_PathHasPCEffect_{atomicPath.Name}(initial_state, left_mover, mover_tid);\n            assert !IsPhase2PC(initial_state.s.threads[mover_tid].pc);\n            assert false;\";\n          finalCasesSelfCrashPreservation += $@\"\n            lemma_LAtomic_PathHasPCEffect_{atomicPath.Name}(state_after_other_path, left_mover, mover_tid);\n            assert !IsPhase2PC(state_after_other_path.s.threads[mover_tid].pc);\n            assert false;\";\n        }\n        else {\n          GenerateSpecificLeftMoverCommutativityLemma(atomicPath);\n\n          if (atomicPath.Stopping) {\n            finalCasesCommutativity += $@\"\n              lemma_LAtomic_PathHasPCEffect_{atomicPath.Name}(state_after_other_path, left_mover, mover_tid);\n              assert !asf.state_ok(state_after_both_paths);\n              assert false;\";\n          }\n          else {\n            finalCasesCommutativity += $@\"\n              lemma_LeftMoverCommutativity_{atomicPath.Name}(\n                initial_state, state_after_other_path, state_after_both_paths, other_path, left_mover,\n                mover_tid, other_tid, state_after_left_mover);\";\n          }\n\n          finalCasesCrashPreservation += $@\"\n            lemma_LeftMoverPreservesCrash_{atomicPath.Name}(\n              initial_state, state_after_other_path, state_after_left_mover, other_path, left_mover,\n              mover_tid, other_tid, state_after_both_paths);\";\n\n          if (atomicPath.Stopping) {\n            finalCasesSelfCrashPreservation += $@\"\n              lemma_LeftMoverPreservesSelfCrash_{atomicPath.Name}(\n                initial_state, state_after_other_path, state_after_both_paths, other_path, left_mover,\n                mover_tid, other_tid, state_after_left_mover);\";\n          }\n          else {\n            finalCasesSelfCrashPreservation += $@\"\n              lemma_LAtomic_PathHasPCEffect_{atomicPath.Name}(state_after_other_path, left_mover, mover_tid);\n              assert asf.state_ok(state_after_both_paths);\n              assert false;\";\n          }\n        }\n      }\n\n      string str;\n\n      str = $@\"\n        lemma lemma_LeftMoverCommutativity(\n          initial_state: LPlusState,\n          state_after_other_path: LPlusState,\n          state_after_both_paths: LPlusState,\n          other_path: LAtomic_Path,\n          left_mover: LAtomic_Path,\n          mover_tid: Armada_ThreadHandle,\n          other_tid: Armada_ThreadHandle,\n          state_after_left_mover: LPlusState\n          )\n          requires InductiveInv(initial_state)\n          requires LAtomic_ValidPath(initial_state, other_path, other_tid)\n          requires state_after_other_path == LAtomic_GetStateAfterPath(initial_state, other_path, other_tid)\n          requires !left_mover.LAtomic_Path_Tau?\n          requires LAtomic_ValidPath(state_after_other_path, left_mover, mover_tid)\n          requires state_after_both_paths == LAtomic_GetStateAfterPath(state_after_other_path, left_mover, mover_tid)\n          requires mover_tid in state_after_other_path.s.threads\n          requires IsPhase2PC(state_after_other_path.s.threads[mover_tid].pc)\n          requires other_path.LAtomic_Path_Tau? || other_tid != mover_tid\n          requires state_after_both_paths.s.stop_reason.Armada_NotStopped?\n          requires state_after_left_mover == LAtomic_GetStateAfterPath(initial_state, left_mover, mover_tid);\n          ensures  LAtomic_ValidPath(initial_state, left_mover, mover_tid)\n          ensures  LAtomic_ValidPath(LAtomic_GetStateAfterPath(initial_state, left_mover, mover_tid), other_path, other_tid)\n          ensures  state_after_both_paths == LAtomic_GetStateAfterPath(state_after_left_mover, other_path, other_tid)\n        {{\n          var asf := LAtomic_GetSpecFunctions();\n          match left_mover {{\n            {finalCasesCommutativity}\n          }}\n        }}\n      \";\n      pgp.AddLemma(str);\n\n      str = $@\"\n        lemma lemma_LeftMoverPreservesCrash(\n          initial_state: LPlusState,\n          state_after_other_path: LPlusState,\n          state_after_left_mover: LPlusState,\n          other_path: LAtomic_Path,\n          left_mover: LAtomic_Path,\n          mover_tid: Armada_ThreadHandle,\n          other_tid: Armada_ThreadHandle,\n          state_after_both_paths: LPlusState\n          )\n          requires InductiveInv(initial_state)\n          requires LAtomic_ValidPath(initial_state, other_path, other_tid)\n          requires state_after_other_path == LAtomic_GetStateAfterPath(initial_state, other_path, other_tid)\n          requires LAtomic_ValidPath(initial_state, left_mover, mover_tid)\n          requires state_after_left_mover == LAtomic_GetStateAfterPath(initial_state, left_mover, mover_tid)\n          requires mover_tid in initial_state.s.threads\n          requires IsPhase2PC(initial_state.s.threads[mover_tid].pc)\n          requires !left_mover.LAtomic_Path_Tau?\n          requires other_path.LAtomic_Path_Tau? || other_tid != mover_tid\n          requires !state_after_other_path.s.stop_reason.Armada_NotStopped?\n          requires state_after_both_paths == LAtomic_GetStateAfterPath(state_after_left_mover, other_path, other_tid)\n          ensures  LAtomic_ValidPath(state_after_left_mover, other_path, other_tid)\n          ensures  !state_after_both_paths.s.stop_reason.Armada_NotStopped?\n          ensures  LLPlusStateRefinement(state_after_other_path, state_after_both_paths)\n        {{\n          var asf := LAtomic_GetSpecFunctions();\n          match left_mover {{\n            {finalCasesCrashPreservation}\n          }}\n        }}\n      \";\n      pgp.AddLemma(str);\n\n      str = $@\"\n        lemma lemma_LeftMoverPreservesSelfCrash(\n          initial_state: LPlusState,\n          state_after_other_path: LPlusState,\n          state_after_both_paths: LPlusState,\n          other_path: LAtomic_Path,\n          left_mover: LAtomic_Path,\n          mover_tid: Armada_ThreadHandle,\n          other_tid: Armada_ThreadHandle,\n          state_after_left_mover: LPlusState\n          )\n          requires InductiveInv(initial_state)\n          requires LAtomic_ValidPath(initial_state, other_path, other_tid)\n          requires state_after_other_path == LAtomic_GetStateAfterPath(initial_state, other_path, other_tid)\n          requires LAtomic_ValidPath(state_after_other_path, left_mover, mover_tid)\n          requires state_after_both_paths == LAtomic_GetStateAfterPath(state_after_other_path, left_mover, mover_tid)\n          requires mover_tid in state_after_other_path.s.threads\n          requires IsPhase2PC(state_after_other_path.s.threads[mover_tid].pc)\n          requires !left_mover.LAtomic_Path_Tau?\n          requires other_path.LAtomic_Path_Tau? || other_tid != mover_tid\n          requires initial_state.s.stop_reason.Armada_NotStopped?\n          requires !state_after_both_paths.s.stop_reason.Armada_NotStopped?\n          requires state_after_left_mover == LAtomic_GetStateAfterPath(initial_state, left_mover, mover_tid)\n          ensures  LAtomic_ValidPath(initial_state, left_mover, mover_tid)\n          ensures  !state_after_left_mover.s.stop_reason.Armada_NotStopped?\n          ensures  LLPlusStateRefinement(state_after_both_paths, state_after_left_mover)\n        {{\n          var asf := LAtomic_GetSpecFunctions();\n          match left_mover {{\n            {finalCasesSelfCrashPreservation}\n          }}\n        }}\n      \";\n      pgp.AddLemma(str);\n    }\n\n    private void GenerateLHYieldingCorrespondenceLemma()\n    {\n      string str;\n\n      str = @\"\n        lemma lemma_LHYieldingCorrespondence(arr: ARRequest)\n          requires arr == GetAtomicReductionRequest()\n          ensures LHYieldingCorrespondence(arr)\n        {\n          forall lpc:L.Armada_PC\n            ensures var hpc := arr.lpc_to_hpc(lpc);\n                    arr.h.is_pc_nonyielding(hpc) <==> (arr.l.is_pc_nonyielding(lpc) || arr.is_phase1(lpc) || arr.is_phase2(lpc))\n          {\n            var hpc := arr.lpc_to_hpc(lpc);\n            match lpc {\n      \";\n\n      var pcs = new List<ArmadaPC>();\n      pgp.symbolsLow.AllMethods.AppendAllPCs(pcs);\n      foreach (var pc in pcs)\n      {\n        str += $@\"\n          case {pc} => assert arr.h.is_pc_nonyielding(hpc) <==> (arr.l.is_pc_nonyielding(lpc) || arr.is_phase1(lpc) || arr.is_phase2(lpc));\n        \";\n      }\n\n      str += @\"\n            }\n          }\n        }\n      \";\n      pgp.AddLemma(str);\n    }\n\n    private void GenerateRightMoversPreserveStateRefinementLemma()\n    {\n      string str;\n\n      string finalCases = \"\";\n\n      var pr = new PathPrinter(lAtomic);\n      foreach (var atomicPath in lAtomic.AtomicPaths) {\n        var nameSuffix = atomicPath.Name;\n        str = $@\"\n          lemma lemma_RightMoversPreserveStateRefinement_{nameSuffix}(\n            arr: ARRequest,\n            s: LPlusState,\n            path: LAtomic_Path,\n            tid: Armada_ThreadHandle\n            )\n            requires arr == GetAtomicReductionRequest()\n            requires LAtomic_ValidPath(s, path, tid)\n            requires !path.LAtomic_Path_Tau?\n            requires path.LAtomic_Path_{nameSuffix}?\n            ensures  var s' := LAtomic_GetStateAfterPath(s, path, tid);\n                     var pc' := arr.l.get_thread_pc(s', tid);\n                     (pc'.Some? && arr.is_phase1(pc'.v) && arr.l.state_ok(s') ==> RefinementPair(s', s) in arr.self_relation)\n          {{\n            { pr.GetOpenValidPathInvocation(atomicPath) }\n            ProofCustomizationGoesHere();\n          }}\n        \";\n        pgp.AddLemma(str);\n\n        finalCases += $\"case LAtomic_Path_{nameSuffix}(_) => lemma_RightMoversPreserveStateRefinement_{nameSuffix}(arr, s, path, tid);\\n\";\n      }\n\n      str = $@\"\n        lemma lemma_RightMoversPreserveStateRefinement(arr: ARRequest)\n          requires arr == GetAtomicReductionRequest()\n          ensures RightMoversPreserveStateRefinement(arr)\n        {{\n           forall s, path, tid | arr.l.path_valid(s, path, tid) && !arr.l.path_type(path).AtomicPathType_Tau?\n             ensures var s' := arr.l.path_next(s, path, tid);\n                     var pc' := arr.l.get_thread_pc(s', tid);\n                     (pc'.Some? && arr.is_phase1(pc'.v) && arr.l.state_ok(s') ==> RefinementPair(s', s) in arr.self_relation)\n           {{\n             match path {{\n               {finalCases}\n             }}\n           }}\n        }}\n      \";\n      pgp.AddLemma(str);\n    }\n\n    private void GenerateAtomicPathCantAffectOtherThreadPhaseExceptViaForkLemma()\n    {\n\n      string postcondition = @\"forall other_tid :: tid != other_tid ==>\n                               var s' := asf.path_next(s, path, tid);\n                               var pc := asf.get_thread_pc(s, other_tid);\n                               var pc' := asf.get_thread_pc(s', other_tid);\n                               (pc' != pc ==> pc.None? && !IsPhase1PC(pc'.v) && !IsPhase2PC(pc'.v) && !asf.is_pc_nonyielding(pc'.v))\";\n      lAtomic.GeneratePerAtomicPathLemma(null,\n                                         \"AtomicPathCantAffectOtherThreadPhaseExceptViaFork\",\n                                         atomicPath => true,\n                                         atomicPath => postcondition,\n                                         atomicPath => \"\",\n                                         false);\n      lAtomic.GenerateOverallAtomicPathLemma(null,\n                                             \"AtomicPathCantAffectOtherThreadPhaseExceptViaFork\",\n                                             \"AtomicPathCantAffectOtherThreadPhaseExceptViaFork\",\n                                             postcondition,\n                                             ap => true);\n\n      string str = @\"\n        lemma lemma_ThreadCantAffectOtherThreadPhaseExceptViaFork(arr:ARRequest)\n          requires arr == GetAtomicReductionRequest()\n          ensures  ThreadCantAffectOtherThreadPhaseExceptViaFork(arr)\n        {\n          forall s, path, tid, other_tid | arr.l.path_valid(s, path, tid) && tid != other_tid\n            ensures var s' := arr.l.path_next(s, path, tid);\n                    var pc := arr.l.get_thread_pc(s, other_tid);\n                    var pc' := arr.l.get_thread_pc(s', other_tid);\n                    pc' != pc ==> pc.None? && !arr.is_phase1(pc'.v) && !arr.is_phase2(pc'.v) && !arr.l.is_pc_nonyielding(pc'.v)\n          {\n            lemma_LAtomic_AtomicPathCantAffectOtherThreadPhaseExceptViaFork(arr.l, s, path, tid);\n          }\n        }\n      \";\n      pgp.AddLemma(str);\n    }\n\n    private void GenerateLemmasSupportingValidRequest()\n    {\n      string str;\n\n      lAtomic.GeneratePCEffectLemmas();\n      lAtomic.GenerateAtomicPathRequiresOKLemma();\n      lAtomic.GenerateAtomicSteppingThreadHasPCLemma();\n      lAtomic.GenerateAtomicTauLeavesPCUnchangedLemma();\n      lAtomic.GenerateAtomicPathTypeAlwaysMatchesPCTypesLemma();\n      hAtomic.GeneratePCEffectLemmas();\n      hAtomic.GenerateAtomicPathTypeAlwaysMatchesPCTypesLemma();\n\n      str = @\"\n        lemma lemma_RefinementRelationsSatisfyRequirements(arr: ARRequest)\n          requires arr == GetAtomicReductionRequest()\n          ensures RefinementRelationReflexive(arr.self_relation)\n          ensures RefinementRelationTransitive(arr.self_relation)\n          ensures RefinementRelationsConvolve(arr.self_relation, arr.relation, arr.relation)\n        {\n        }\n      \";\n      pgp.AddLemma(str);\n\n      GenerateGenericAtomicPropertyLemmas();\n\n      str = $@\"\n        lemma lemma_LAtomic_AtomicInitImpliesYielding()\n          ensures AtomicInitImpliesYielding(LAtomic_GetSpecFunctions())\n        {{\n        }}\n      \";\n      pgp.AddLemma(str);\n\n      str = @\"\n        lemma lemma_LStateToHStateMapsPCsCorrectly(arr: ARRequest)\n          requires arr == GetAtomicReductionRequest()\n          ensures LStateToHStateMapsPCsCorrectly(arr)\n        {\n        }\n      \";\n      pgp.AddLemma(str);\n\n      GenerateLHYieldingCorrespondenceLemma();\n\n      str = @\"\n        lemma lemma_LHPathPropertiesMatch(arr: ARRequest)\n          requires arr == GetAtomicReductionRequest()\n          ensures LHPathPropertiesMatch(arr)\n        {\n        }\n      \";\n      pgp.AddLemma(str);\n\n      str = @\"\n        lemma lemma_LPathImpliesHPath(arr: ARRequest)\n          requires arr == GetAtomicReductionRequest()\n          ensures LPathImpliesHPath(arr)\n        {\n          forall ls, lpath, tid | arr.inv(ls) && arr.l.path_valid(ls, lpath, tid)\n            ensures var ls' := arr.l.path_next(ls, lpath, tid);\n                    var hs := arr.lstate_to_hstate(ls);\n                    var hpath := arr.lpath_to_hpath(lpath);\n                    var hs' := arr.lstate_to_hstate(ls');\n                    && arr.h.path_valid(hs, hpath, tid)\n                    && hs' == arr.h.path_next(hs, hpath, tid)\n          {\n            lemma_LiftAtomicPath(ls, lpath, tid);\n          }\n        }\n      \";\n      pgp.AddLemma(str);\n\n      str = @\"\n        lemma lemma_StateConversionPreservesOK(arr: ARRequest)\n          requires arr == GetAtomicReductionRequest()\n          ensures StateConversionPreservesOK(arr)\n        {\n        }\n      \";\n      pgp.AddLemma(str);\n\n      str = @\"\n        lemma lemma_StateConversionSatisfiesRelation(arr: ARRequest)\n          requires arr == GetAtomicReductionRequest()\n          ensures StateConversionSatisfiesRelation(arr)\n        {\n        }\n      \";\n      pgp.AddLemma(str);\n\n      str = @\"\n        lemma lemma_ThreadsDontStartInAnyPhase(arr: ARRequest)\n          requires arr == GetAtomicReductionRequest()\n          ensures ThreadsDontStartInAnyPhase(arr)\n        {\n        }\n      \";\n      pgp.AddLemma(str);\n\n      str = @\"\n        lemma lemma_PhasesDontOverlap(arr: ARRequest)\n          requires arr == GetAtomicReductionRequest()\n          ensures PhasesDontOverlap(arr)\n        {\n        }\n      \";\n      pgp.AddLemma(str);\n\n      GenerateAtomicPathCantAffectOtherThreadPhaseExceptViaForkLemma();\n\n      str = @\"\n        lemma lemma_PhasesPrecededByYielding(arr: ARRequest)\n          requires arr == GetAtomicReductionRequest()\n          ensures PhasesPrecededByYielding(arr)\n        {\n          forall s, path, tid |\n            var s' := arr.l.path_next(s, path, tid);\n            var pc := arr.l.get_thread_pc(s, tid);\n            var pc' := arr.l.get_thread_pc(s', tid);\n            && arr.l.path_valid(s, path, tid)\n            && pc'.Some?\n            && (arr.is_phase1(pc'.v) || arr.is_phase2(pc'.v))\n            && pc.Some?\n            && (!arr.is_phase1(pc.v) && !arr.is_phase2(pc.v))\n            ensures var pc := arr.l.get_thread_pc(s, tid);\n                    !arr.l.is_pc_nonyielding(pc.v)\n          {\n            match path {\n      \";\n      foreach (var atomicPath in lAtomic.AtomicPaths) {\n        str += $@\"\n              case LAtomic_Path_{atomicPath.Name}(_) =>\n                lemma_LAtomic_PathHasPCEffect_{atomicPath.Name}(s, path, tid);\n        \";\n      }\n      str += \"} } }\\n\";\n      pgp.AddLemma(str);\n\n      str = @\"\n        lemma lemma_PhasesSucceededByYielding(arr: ARRequest)\n          requires arr == GetAtomicReductionRequest()\n          ensures PhasesSucceededByYielding(arr)\n        {\n          forall s, path, tid |\n            var s' := arr.l.path_next(s, path, tid);\n            var pc := arr.l.get_thread_pc(s, tid);\n            var pc' := arr.l.get_thread_pc(s', tid);\n            && arr.l.path_valid(s, path, tid)\n            && pc.Some?\n            && (arr.is_phase1(pc.v) || arr.is_phase2(pc.v))\n            && pc'.Some?\n            && (!arr.is_phase1(pc'.v) && !arr.is_phase2(pc'.v))\n            ensures var s' := arr.l.path_next(s, path, tid);\n                    var pc' := arr.l.get_thread_pc(s', tid);\n                    !arr.l.is_pc_nonyielding(pc'.v)\n          {\n            match path {\n      \";\n      foreach (var atomicPath in lAtomic.AtomicPaths) {\n        str += $@\"\n              case LAtomic_Path_{atomicPath.Name}(_) =>\n                lemma_LAtomic_PathHasPCEffect_{atomicPath.Name}(s, path, tid);\n        \";\n      }\n      str += \"} } }\\n\";\n      pgp.AddLemma(str);\n\n      str = @\"\n        lemma lemma_Phase2NotFollowedByPhase1(arr:ARRequest)\n          requires arr == GetAtomicReductionRequest()\n          ensures Phase2NotFollowedByPhase1(arr)\n        {\n          forall s, path, tid |\n            var s' := arr.l.path_next(s, path, tid);\n            var pc := arr.l.get_thread_pc(s, tid);\n            var pc' := arr.l.get_thread_pc(s', tid);\n            && arr.l.path_valid(s, path, tid)\n            && pc.Some?\n            && arr.is_phase2(pc.v)\n            && pc'.Some?\n            && !arr.is_phase2(pc'.v)\n            ensures var s' := arr.l.path_next(s, path, tid);\n                    var pc' := arr.l.get_thread_pc(s', tid);\n                    !arr.is_phase1(pc'.v)\n          {\n            match path {\n      \";\n      foreach (var atomicPath in lAtomic.AtomicPaths) {\n        str += $@\"\n              case LAtomic_Path_{atomicPath.Name}(_) =>\n                lemma_LAtomic_PathHasPCEffect_{atomicPath.Name}(s, path, tid);\n        \";\n      }\n      str += \"} } }\\n\";\n      pgp.AddLemma(str);\n\n      GenerateRightMoversPreserveStateRefinementLemma();\n\n      var pr = new PathPrinter(lAtomic);\n      str = @\"\n        lemma lemma_LeftMoversPreserveStateRefinement(arr: ARRequest)\n          requires arr == GetAtomicReductionRequest()\n          ensures LeftMoversPreserveStateRefinement(arr)\n        {\n          forall s, path, tid | arr.l.path_valid(s, path, tid) && !arr.l.path_type(path).AtomicPathType_Tau?\n            ensures var s' := arr.l.path_next(s, path, tid);\n                    var pc := arr.l.get_thread_pc(s, tid);\n                    (pc.Some? && arr.is_phase2(pc.v) ==> RefinementPair(s, s') in arr.self_relation)\n          {\n            var pc := arr.l.get_thread_pc(s, tid);\n            var s' := arr.l.path_next(s, path, tid);\n            match path {\n      \";\n      str += String.Join(\"\\n\", lAtomic.AtomicPaths.Select(atomicPath => $@\"\n        case LAtomic_Path_{atomicPath.Name}(_) => \" +\n          (phase2PCs.Contains(atomicPath.StartPC)\n             ? $@\"{ pr.GetOpenValidPathInvocation(atomicPath) }\n                  assert RefinementPair(s, s') in arr.self_relation;\"\n             : $@\"lemma_LAtomic_PathHasPCEffect_{atomicPath.Name}(s, path, tid);\n                  assert !arr.is_phase2(pc.v);\")\n      ));\n      str += \"}\\n}\\n}\";\n      pgp.AddLemma(str);\n\n      str = @\"\n        lemma lemma_RightMoversCommute(arr: ARRequest)\n          requires arr == GetAtomicReductionRequest()\n          ensures RightMoversCommute(arr)\n        {\n          forall initial_state, right_mover, other_path, mover_tid, other_tid\n            {:trigger RightMoversCommuteConditions(arr, initial_state, right_mover, other_path, mover_tid, other_tid)}\n            | RightMoversCommuteConditions(arr, initial_state, right_mover, other_path, mover_tid, other_tid)\n            ensures var state_after_right_mover := LAtomic_GetStateAfterPath(initial_state, right_mover, mover_tid);\n                    var state_after_both_paths := LAtomic_GetStateAfterPath(state_after_right_mover, other_path, other_tid);\n                    var state_after_other_path := LAtomic_GetStateAfterPath(initial_state, other_path, other_tid);\n                    && LAtomic_ValidPath(initial_state, other_path, other_tid)\n                    && LAtomic_ValidPath(state_after_other_path, right_mover, mover_tid)\n                    && state_after_both_paths == LAtomic_GetStateAfterPath(state_after_other_path, right_mover, mover_tid)\n          {\n            var state_after_right_mover := LAtomic_GetStateAfterPath(initial_state, right_mover, mover_tid);\n            var state_after_both_paths := LAtomic_GetStateAfterPath(state_after_right_mover, other_path, other_tid);\n            var state_after_other_path := LAtomic_GetStateAfterPath(initial_state, other_path, other_tid);\n            lemma_RightMoverCommutativity(initial_state, state_after_right_mover, state_after_both_paths, right_mover, other_path,\n                                          mover_tid, other_tid, state_after_other_path);\n          }\n        }\n      \";\n      pgp.AddLemma(str);\n\n      str = @\"\n        lemma lemma_RightMoverCrashPreservation(arr: ARRequest)\n          requires arr == GetAtomicReductionRequest()\n          ensures RightMoverCrashPreservation(arr)\n        {\n          forall initial_state, right_mover, other_path, mover_tid, other_tid\n            {:trigger RightMoverCrashPreservationConditions(arr, initial_state, right_mover, other_path, mover_tid, other_tid)}\n            | RightMoverCrashPreservationConditions(arr, initial_state, right_mover, other_path, mover_tid, other_tid)\n            ensures var state_after_right_mover := arr.l.path_next(initial_state, right_mover, mover_tid);\n                    var state_after_both_paths := arr.l.path_next(state_after_right_mover, other_path, other_tid);\n                    var state_after_other_path := arr.l.path_next(initial_state, other_path, other_tid);\n                    && arr.l.path_valid(initial_state, other_path, other_tid)\n                    && !arr.l.state_ok(state_after_other_path)\n                    && RefinementPair(state_after_both_paths, state_after_other_path) in arr.self_relation\n          {\n            var state_after_right_mover := arr.l.path_next(initial_state, right_mover, mover_tid);\n            var state_after_both_paths := arr.l.path_next(state_after_right_mover, other_path, other_tid);\n            var state_after_other_path := arr.l.path_next(initial_state, other_path, other_tid);\n            lemma_RightMoverPreservesCrash(initial_state, state_after_right_mover, state_after_both_paths, right_mover, other_path,\n                                           mover_tid, other_tid, state_after_other_path);\n          }\n        }\n      \";\n      pgp.AddLemma(str);\n\n      str = @\"\n        lemma lemma_LeftMoversCommute(arr: ARRequest)\n          requires arr == GetAtomicReductionRequest()\n          ensures LeftMoversCommute(arr)\n        {\n          forall initial_state, other_path, left_mover, mover_tid, other_tid\n            {:trigger LeftMoversCommuteConditions(arr, initial_state, other_path, left_mover, mover_tid, other_tid)}\n            | LeftMoversCommuteConditions(arr, initial_state, other_path, left_mover, mover_tid, other_tid)\n            ensures var state_after_other_path := arr.l.path_next(initial_state, other_path, other_tid);\n                    var state_after_both_paths := arr.l.path_next(state_after_other_path, left_mover, mover_tid);\n                    var new_middle_state := arr.l.path_next(initial_state, left_mover, mover_tid);\n                    && arr.l.path_valid(initial_state, left_mover, mover_tid)\n                    && arr.l.path_valid(new_middle_state, other_path, other_tid)\n                    && state_after_both_paths == arr.l.path_next(new_middle_state, other_path, other_tid)\n          {\n            var state_after_other_path := arr.l.path_next(initial_state, other_path, other_tid);\n            var state_after_both_paths := arr.l.path_next(state_after_other_path, left_mover, mover_tid);\n            var state_after_left_mover := arr.l.path_next(initial_state, left_mover, mover_tid);\n            lemma_LeftMoverCommutativity(initial_state, state_after_other_path, state_after_both_paths, other_path, left_mover,\n                                         mover_tid, other_tid, state_after_left_mover);\n          }\n        }\n      \";\n      pgp.AddLemma(str);\n\n      str = @\"\n        lemma lemma_LeftMoverCrashPreservation(arr: ARRequest)\n          requires arr == GetAtomicReductionRequest()\n          ensures LeftMoverCrashPreservation(arr)\n        {\n          forall initial_state, left_mover, other_path, mover_tid, other_tid\n            {:trigger LeftMoverCrashPreservationConditions(arr, initial_state, left_mover, other_path, mover_tid, other_tid)}\n            | LeftMoverCrashPreservationConditions(arr, initial_state, left_mover, other_path, mover_tid, other_tid)\n            ensures var state_after_left_mover := arr.l.path_next(initial_state, left_mover, mover_tid);\n                    var state_after_other_path := arr.l.path_next(initial_state, other_path, other_tid);\n                    var state_after_both_paths := arr.l.path_next(state_after_left_mover, other_path, other_tid);\n                    && arr.l.path_valid(state_after_left_mover, other_path, other_tid)\n                    && !arr.l.state_ok(state_after_both_paths)\n                    && RefinementPair(state_after_other_path, state_after_both_paths) in arr.self_relation\n          {\n            var state_after_left_mover := arr.l.path_next(initial_state, left_mover, mover_tid);\n            var state_after_other_path := arr.l.path_next(initial_state, other_path, other_tid);\n            var state_after_both_paths := arr.l.path_next(state_after_left_mover, other_path, other_tid);\n            lemma_LeftMoverPreservesCrash(initial_state, state_after_other_path, state_after_left_mover, other_path, left_mover,\n                                          mover_tid, other_tid, state_after_both_paths);\n          }\n        }\n      \";\n      pgp.AddLemma(str);\n\n      str = @\"\n        lemma lemma_LeftMoverSelfCrashPreservation(arr: ARRequest)\n          requires arr == GetAtomicReductionRequest()\n          ensures LeftMoverSelfCrashPreservation(arr)\n        {\n          forall initial_state, left_mover, other_path, mover_tid, other_tid\n            {:trigger LeftMoverSelfCrashPreservationConditions(arr, initial_state, left_mover, other_path, mover_tid, other_tid)}\n            | LeftMoverSelfCrashPreservationConditions(arr, initial_state, left_mover, other_path, mover_tid, other_tid)\n            ensures var state_after_other_path := arr.l.path_next(initial_state, other_path, other_tid);\n                    var state_after_both_paths := arr.l.path_next(state_after_other_path, left_mover, mover_tid);\n                    var state_after_left_mover := arr.l.path_next(initial_state, left_mover, mover_tid);\n                    && arr.l.path_valid(initial_state, left_mover, mover_tid)\n                    && !arr.l.state_ok(state_after_left_mover)\n                    && RefinementPair(state_after_both_paths, state_after_left_mover) in arr.self_relation\n          {\n            var state_after_other_path := arr.l.path_next(initial_state, other_path, other_tid);\n            var state_after_both_paths := arr.l.path_next(state_after_other_path, left_mover, mover_tid);\n            var state_after_left_mover := arr.l.path_next(initial_state, left_mover, mover_tid);\n            lemma_LeftMoverPreservesSelfCrash(initial_state, state_after_other_path, state_after_both_paths, other_path, left_mover,\n                                              mover_tid, other_tid, state_after_left_mover);\n          }\n        }\n      \";\n      pgp.AddLemma(str);\n\n      GenerateLeftMoverEnablementLemmas();\n    }\n\n    private void GenerateLeftMoverEnablementLemmas()\n    {\n      string str;\n      string body = \"\";\n\n      var pr = new PathPrinter(lAtomic);\n      foreach (KeyValuePair<ArmadaPC, AtomicPath> entry in phase2PCToPath)\n      {\n        var pc = entry.Key;\n        var atomicPath = entry.Value;\n        var nameSuffix = atomicPath.Name;\n        str = $@\"\n          lemma lemma_LeftMoverEnabled_{nameSuffix}(s: LPlusState, tid: Armada_ThreadHandle, path: LAtomic_Path)\n            requires InductiveInv(s)\n            requires s.s.stop_reason.Armada_NotStopped?\n            requires tid in s.s.threads\n            requires s.s.threads[tid].pc.{pc}?\n            requires path == GenerateLeftMover(s, tid)\n            ensures  LAtomic_ValidPath(s, path, tid)\n            ensures  !path.LAtomic_Path_Tau?\n            ensures  0 <= LeftMoverGenerationProgress(LAtomic_GetStateAfterPath(s, path, tid), tid) < LeftMoverGenerationProgress(s, tid)\n          {{\n            assert s.s.threads[tid].top.Armada_StackFrame_{pc.methodName}?;\n            { pr.GetOpenPathInvocation(atomicPath) }\n            ProofCustomizationGoesHere();\n          }}\n        \";\n        pgp.AddLemma(str);\n        body += $@\"\n          if pc.{pc}? {{\n            lemma_LeftMoverEnabled_{nameSuffix}(s, tid, path);\n          }}\n        \";\n      }\n\n      str = $@\"\n        lemma lemma_LeftMoverEnabled(s: LPlusState, tid: Armada_ThreadHandle, path: LAtomic_Path)\n          requires InductiveInv(s)\n          requires s.s.stop_reason.Armada_NotStopped?\n          requires tid in s.s.threads\n          requires IsPhase2PC(s.s.threads[tid].pc)\n          requires path == GenerateLeftMover(s, tid)\n          ensures  LAtomic_ValidPath(s, path, tid)\n          ensures  !path.LAtomic_Path_Tau?\n          ensures  0 <= LeftMoverGenerationProgress(LAtomic_GetStateAfterPath(s, path, tid), tid) < LeftMoverGenerationProgress(s, tid)\n        {{\n          var pc := s.s.threads[tid].pc;\n          { body }\n        }}\n      \";\n      pgp.AddLemma(str);\n\n      str = @\"\n        lemma lemma_LeftMoversAlwaysEnabled(arr: ARRequest)\n          requires arr == GetAtomicReductionRequest()\n          ensures  LeftMoversAlwaysEnabled(arr)\n        {\n          forall s, tid {:trigger LeftMoversAlwaysEnabledConditions(arr, s, tid)}\n            | LeftMoversAlwaysEnabledConditions(arr, s, tid)\n            ensures var path := arr.generate_left_mover(s, tid);\n                    && LAtomic_ValidPath(s, path, tid)\n                    && !arr.l.path_type(path).AtomicPathType_Tau?\n                    && var s' := LAtomic_GetStateAfterPath(s, path, tid);\n                       0 <= arr.left_mover_generation_progress(s', tid) < arr.left_mover_generation_progress(s, tid)\n          {\n            var path := arr.generate_left_mover(s, tid);\n            lemma_LeftMoverEnabled(s, tid, path);\n          }\n        }\n      \";\n      pgp.AddLemma(str);\n    }\n\n    private void GenerateIsValidRequest()\n    {\n      string str = @\"\n        lemma lemma_IsValidAtomicReductionRequest(arr: ARRequest)\n          requires arr == GetAtomicReductionRequest()\n          ensures  ValidAtomicReductionRequest(arr)\n        {\n          lemma_RefinementRelationsSatisfyRequirements(arr);\n          lemma_LInitImpliesHInit(arr);\n          lemma_LAtomic_AtomicInitImpliesInv();\n          lemma_LAtomic_AtomicPathPreservesInv();\n          lemma_LAtomic_AtomicPathRequiresOK();\n          lemma_LAtomic_AtomicInitImpliesYielding();\n          lemma_LAtomic_AtomicInitImpliesOK();\n          lemma_LAtomic_AtomicPathTypeAlwaysMatchesPCTypes();\n          lemma_HAtomic_AtomicPathTypeAlwaysMatchesPCTypes();\n          lemma_LStateToHStateMapsPCsCorrectly(arr);\n          lemma_LHYieldingCorrespondence(arr);\n          lemma_LHPathPropertiesMatch(arr);\n          lemma_LPathImpliesHPath(arr);\n          lemma_StateConversionPreservesOK(arr);\n          lemma_StateConversionSatisfiesRelation(arr);\n          lemma_ThreadsDontStartInAnyPhase(arr);\n          lemma_PhasesDontOverlap(arr);\n          lemma_ThreadCantAffectOtherThreadPhaseExceptViaFork(arr);\n          lemma_PhasesPrecededByYielding(arr);\n          lemma_PhasesSucceededByYielding(arr);\n          lemma_Phase2NotFollowedByPhase1(arr);\n          lemma_LAtomic_AtomicSteppingThreadHasPC();\n          lemma_LAtomic_AtomicTauLeavesPCUnchanged();\n          lemma_RightMoversPreserveStateRefinement(arr);\n          lemma_LeftMoversPreserveStateRefinement(arr);\n          lemma_RightMoversCommute(arr);\n          lemma_LeftMoversCommute(arr);\n          lemma_RightMoverCrashPreservation(arr);\n          lemma_LeftMoverCrashPreservation(arr);\n          lemma_LeftMoverSelfCrashPreservation(arr);\n          lemma_LeftMoversAlwaysEnabled(arr);\n        }\n      \";\n      pgp.AddLemma(str);\n    }\n\n    private void GenerateLiftLAtomicToHAtomicLemma()\n    {\n      var str = @\"\n        lemma lemma_LiftLAtomicToHAtomic() returns (refinement_relation: RefinementRelation<LPlusState, H.Armada_TotalState>)\n          ensures SpecRefinesSpec(AtomicSpec(LAtomic_GetSpecFunctions()), AtomicSpec(HAtomic_GetSpecFunctions()), refinement_relation)\n          ensures refinement_relation == GetLPlusHRefinementRelation()\n        {\n          var arr := GetAtomicReductionRequest();\n          lemma_IsValidAtomicReductionRequest(arr);\n          lemma_PerformAtomicReduction(arr);\n          refinement_relation := GetLPlusHRefinementRelation();\n        }\n      \";\n      pgp.AddLemma(str);\n    }\n  }\n}\n"
  },
  {
    "path": "Source/Armada/RefinementTransformer.cs",
    "content": "//-----------------------------------------------------------------------------\n//\n// Copyright (C) Microsoft Corporation.  All Rights Reserved.\n//\n//-----------------------------------------------------------------------------\n// This file contains the transformations that are applied to a module that is\n// constructed as a refinement of another.  It is invoked during program resolution,\n// so the transformation is done syntactically.  Upon return from the RefinementTransformer,\n// the caller is expected to resolve the resulting module.\n//\n// As for now (and perhaps this is always the right thing to do), attributes do\n// not survive the transformation.\n//-----------------------------------------------------------------------------\n\nusing System;\nusing System.Collections.Generic;\nusing System.Numerics;\nusing System.Diagnostics.Contracts;\nusing IToken = Microsoft.Boogie.IToken;\n\nnamespace Microsoft.Armada\n{\n  public class RefinementToken : TokenWrapper\n  {\n    public readonly ModuleDefinition InheritingModule;\n    public RefinementToken(IToken tok, ModuleDefinition m)\n      : base(tok) {\n      Contract.Requires(tok != null);\n      Contract.Requires(m != null);\n      this.InheritingModule = m;\n    }\n\n    public static bool IsInherited(IToken tok, ModuleDefinition m) {\n      while (tok is NestedToken) {\n        var n = (NestedToken)tok;\n        // check Outer\n        var r = n.Outer as RefinementToken;\n        if (r == null || r.InheritingModule != m) {\n          return false;\n        }\n        // continue to check Inner\n        tok = n.Inner;\n      }\n      var rtok = tok as RefinementToken;\n      return rtok != null && rtok.InheritingModule == m;\n    }\n    public override string filename {\n      get { return WrappedToken.filename + \"[\" + InheritingModule.Name + \"]\"; }\n      set { throw new NotSupportedException(); }\n    }\n  }\n\n  public class RefinementTransformer : IRewriter\n  {\n    Cloner rawCloner; // This cloner just gives exactly the same thing back.\n    RefinementCloner refinementCloner; // This cloner wraps things in a RefinementToken\n\n    Program program;\n\n    public RefinementTransformer(ErrorReporter reporter)\n      : base(reporter) {\n      rawCloner = new Cloner();\n    }\n\n    public RefinementTransformer(Program p)\n      : this(p.reporter) {\n      Contract.Requires(p != null);\n      program = p;\n    }\n\n    private ModuleDefinition moduleUnderConstruction;  // non-null for the duration of Construct calls\n    private Queue<Action> postTasks = new Queue<Action>();  // empty whenever moduleUnderConstruction==null, these tasks are for the post-resolve phase of module moduleUnderConstruction\n    public Queue<Tuple<Method, Method>> translationMethodChecks = new Queue<Tuple<Method, Method>>();  // contains all the methods that need to be checked for structural refinement.\n    private Method currentMethod;\n    public ModuleSignature RefinedSig;  // the intention is to use this field only after a successful PreResolve\n    private ModuleSignature refinedSigOpened;\n\n    internal override void PreResolve(ModuleDefinition m) {\n      if (m.RefinementBaseRoot != null) {\n        RefinedSig = m.RefinementBaseRoot.Signature;\n\n        if (RefinedSig.ModuleDef != null) {\n          if (RefinedSig.ModuleDef.IsProtected) {\n            reporter.Error(MessageSource.RefinementTransformer, m.RefinementBaseName, \"module ({0}) named as a refinement base is marked protected and cannot be refined\", m.RefinementBaseName.val);\n          }\n\n          m.RefinementBase = RefinedSig.ModuleDef;\n          // check that the openess in the imports between refinement and its base matches\n          List<TopLevelDecl> declarations = m.TopLevelDecls;\n          List<TopLevelDecl> baseDeclarations = m.RefinementBase.TopLevelDecls;\n          foreach (var im in declarations) {\n            if (im is ModuleDecl) {\n              ModuleDecl mdecl = (ModuleDecl)im;\n              //find the matching import from the base\n              // TODO: this is a terribly slow algorithm; use the symbol table instead\n              foreach (var bim in baseDeclarations) {\n                if (bim is ModuleDecl && ((ModuleDecl)bim).Name.Equals(mdecl.Name)) {\n                  if (mdecl.Opened != ((ModuleDecl)bim).Opened) {\n                    string message = mdecl.Opened ?\n                      \"{0} in {1} cannot be imported with \\\"opened\\\" because it does not match the corresponding import in the refinement base {2} \" :\n                      \"{0} in {1} must be imported with \\\"opened\\\"  to match the corresponding import in its refinement base {2}.\";\n                    reporter.Error(MessageSource.RefinementTransformer, m.tok, message, im.Name, m.Name, m.RefinementBase.Name);\n                  }\n                  break;\n                }\n                break;\n              }\n            }\n          }\n          PreResolveWorker(m);\n\n        } else {\n          reporter.Error(MessageSource.RefinementTransformer, m.RefinementBaseName, \"module ({0}) named as refinement base does not exist\", m.RefinementBaseName.val);\n        }\n      }\n    }\n\n    void PreResolveWorker(ModuleDefinition m) {\n      Contract.Requires(m != null);\n\n      if (m.RefinementBase == null) return;\n\n      if (moduleUnderConstruction != null) {\n        postTasks.Clear();\n      }\n      moduleUnderConstruction = m;\n      refinementCloner = new RefinementCloner(moduleUnderConstruction);\n      var prev = m.RefinementBase;\n\n      //copy the signature, including its opened imports\n      refinedSigOpened = Resolver.MergeSignature(new ModuleSignature(), RefinedSig);\n      Resolver.ResolveOpenedImports(refinedSigOpened, m.RefinementBase, false, null);\n\n      // Create a simple name-to-decl dictionary.  Ignore any duplicates at this time.\n      var declaredNames = new Dictionary<string, int>();\n      for (int i = 0; i < m.TopLevelDecls.Count; i++) {\n        var d = m.TopLevelDecls[i];\n        if (!declaredNames.ContainsKey(d.Name)) {\n          declaredNames.Add(d.Name, i);\n        }\n\n        // TODO: This is more restrictive than is necessary,\n        // it would be possible to disambiguate these, but it seems like\n        // a lot of work for not much gain\n\n        if (refinedSigOpened.TopLevels.ContainsKey(d.Name) &&\n          !RefinedSig.TopLevels.ContainsKey(d.Name)) {\n          var decl = Resolver.AmbiguousTopLevelDecl.Create(m, d, refinedSigOpened.TopLevels[d.Name]);\n\n          if (decl is Resolver.AmbiguousTopLevelDecl) {\n            reporter.Error(MessageSource.RefinementTransformer, d.tok, \"Base module {0} imports {1} from an opened import, so it cannot be overridden. Give this declaration a unique name to disambiguate.\", prev.Name, d.Name);\n          }\n        }\n      }\n\n      // Merge the declarations of prev into the declarations of m\n      List<string> processedDecl = new List<string>();\n      foreach (var d in prev.TopLevelDecls) {\n        int index;\n        processedDecl.Add(d.Name);\n        if (!declaredNames.TryGetValue(d.Name, out index)) {\n          m.TopLevelDecls.Add(refinementCloner.CloneDeclaration(d, m));\n        } else {\n          var nw = m.TopLevelDecls[index];\n          MergeTopLevelDecls(m, nw, d, index);\n        }\n      }\n\n      // Merge the imports of prev\n      var prevTopLevelDecls = RefinedSig.TopLevels.Values;\n      foreach (var d in prevTopLevelDecls) {\n        int index;\n        if (!processedDecl.Contains(d.Name) && (declaredNames.TryGetValue(d.Name, out index))) {\n          // if it is redefined, we need to merge them.\n          var nw = m.TopLevelDecls[index];\n          MergeTopLevelDecls(m, nw, d, index);\n        }\n      }\n      m.RefinementBaseSig = RefinedSig;\n\n      Contract.Assert(moduleUnderConstruction == m);  // this should be as it was set earlier in this method\n    }\n\n    private void MergeModuleExports(ModuleExportDecl nw, ModuleExportDecl d) {\n      if (nw.IsDefault != d.IsDefault) {\n        reporter.Error(MessageSource.RefinementTransformer, nw, \"can't change if a module export is default ({0})\", nw.Name);\n      }\n\n      nw.Exports.AddRange(d.Exports);\n      nw.Extends.AddRange(d.Extends);\n    }\n\n    private void MergeTopLevelDecls(ModuleDefinition m, TopLevelDecl nw, TopLevelDecl d, int index) {\n      if (d is ModuleDecl) {\n        if (!(nw is ModuleDecl)) {\n          reporter.Error(MessageSource.RefinementTransformer, nw, \"a module ({0}) must refine another module\", nw.Name);\n        } else if (d is ModuleExportDecl) {\n          if (!(nw is ModuleExportDecl)) {\n            reporter.Error(MessageSource.RefinementTransformer, nw, \"a module export ({0}) must refine another export\", nw.Name);\n          } else {\n            MergeModuleExports((ModuleExportDecl)nw,(ModuleExportDecl)d);\n          }\n        } else if (!(d is ModuleFacadeDecl)) {\n          reporter.Error(MessageSource.RefinementTransformer, nw, \"a module ({0}) can only refine a module facade\", nw.Name);\n        } else {\n          // check that the new module refines the previous declaration\n          if (!CheckIsRefinement((ModuleDecl)nw, (ModuleFacadeDecl)d))\n            reporter.Error(MessageSource.RefinementTransformer, nw.tok, \"a module ({0}) can only be replaced by a refinement of the original module\", d.Name);\n        }\n      } else if (d is OpaqueTypeDecl) {\n        if (nw is ModuleDecl) {\n          reporter.Error(MessageSource.RefinementTransformer, nw, \"a module ({0}) must refine another module\", nw.Name);\n        } else {\n          var od = (OpaqueTypeDecl)d;\n          if (nw is OpaqueTypeDecl) {\n            if (od.MustSupportEquality != ((OpaqueTypeDecl)nw).MustSupportEquality) {\n              reporter.Error(MessageSource.RefinementTransformer, nw, \"type declaration '{0}' is not allowed to change the requirement of supporting equality\", nw.Name);\n            }\n            if (od.Characteristics.MustSupportZeroInitialization != ((OpaqueTypeDecl)nw).Characteristics.MustSupportZeroInitialization) {\n              reporter.Error(MessageSource.RefinementTransformer, nw.tok, \"type declaration '{0}' is not allowed to change the requirement of supporting zero initialization\", nw.Name);\n            }\n          } else {\n            if (od.MustSupportEquality) {\n              if (nw is ClassDecl || nw is NewtypeDecl) {\n                // fine\n              } else if (nw is CoDatatypeDecl) {\n                reporter.Error(MessageSource.RefinementTransformer, nw, \"a type declaration that requires equality support cannot be replaced by a codatatype\");\n              } else {\n                Contract.Assert(nw is IndDatatypeDecl || nw is TypeSynonymDecl);\n                // Here, we need to figure out if the new type supports equality.  But we won't know about that until resolution has\n                // taken place, so we defer it until the PostResolve phase.\n                var udt = UserDefinedType.FromTopLevelDecl(nw.tok, nw);\n                postTasks.Enqueue(() => {\n                  if (!udt.SupportsEquality) {\n                    reporter.Error(MessageSource.RefinementTransformer, udt.tok, \"type '{0}', which does not support equality, is used to refine an opaque type with equality support\", udt.Name);\n                  }\n                });\n              }\n            }\n            if (od.Characteristics.MustSupportZeroInitialization) {\n              // We need to figure out if the new type supports zero initialization.  But we won't know about that until resolution has\n              // taken place, so we defer it until the PostResolve phase.\n              var udt = UserDefinedType.FromTopLevelDecl(nw.tok, nw);\n              postTasks.Enqueue(() => {\n                if (!Compiler.HasZeroInitializer(udt)) {\n                  reporter.Error(MessageSource.RefinementTransformer, udt.tok, \"type '{0}', which does not support zero initialization, is used to refine an opaque type that expects zero initialization\", udt.Name);\n                }\n              });\n            }\n          }\n          CheckAgreement_TypeParameters(nw.tok, d.TypeArgs, nw.TypeArgs, nw.Name, \"type\", false);\n        }\n      } else if (nw is OpaqueTypeDecl) {\n        reporter.Error(MessageSource.RefinementTransformer, nw, \"an opaque type declaration ({0}) in a refining module cannot replace a more specific type declaration in the refinement base\", nw.Name);\n      } else if (nw is DatatypeDecl) {\n        reporter.Error(MessageSource.RefinementTransformer, nw, \"a datatype declaration ({0}) in a refinement module can only replace an opaque type declaration\", nw.Name);\n      } else if (nw is IteratorDecl) {\n        if (d is IteratorDecl) {\n          m.TopLevelDecls[index] = MergeIterator((IteratorDecl)nw, (IteratorDecl)d);\n        } else {\n          reporter.Error(MessageSource.RefinementTransformer, nw, \"an iterator declaration ({0}) is a refining module cannot replace a different kind of declaration in the refinement base\", nw.Name);\n        }\n      } else {\n        Contract.Assert(nw is ClassDecl);\n        if (d is DatatypeDecl) {\n          reporter.Error(MessageSource.RefinementTransformer, nw, \"a class declaration ({0}) in a refining module cannot replace a different kind of declaration in the refinement base\", nw.Name);\n        } else {\n          m.TopLevelDecls[index] = MergeClass((ClassDecl)nw, (ClassDecl)d);\n        }\n      }\n    }\n\n    public bool CheckIsRefinement(ModuleDecl derived, ModuleFacadeDecl original) {\n\n\n      // Check explicit refinement\n      // TODO syntactic analysis of export sets is not quite right\n      var derivedPointer = derived.Signature.ModuleDef;\n      while (derivedPointer != null) {\n        if (derivedPointer == original.OriginalSignature.ModuleDef) {\n          HashSet<string> exports;\n          if (derived is AliasModuleDecl) {\n            exports = new HashSet<string>(((AliasModuleDecl)derived).Exports.ConvertAll(t => t.val));\n          } else if (derived is ModuleFacadeDecl) {\n            exports = new HashSet<string>(((ModuleFacadeDecl)derived).Exports.ConvertAll(t => t.val));\n          } else {\n            reporter.Error(MessageSource.RefinementTransformer, derived, \"a module ({0}) can only be refined by an alias module or a module facade\", original.Name);\n            return false;\n          }\n          var oexports = new HashSet<string>(original.Exports.ConvertAll(t => t.val));\n          return oexports.IsSubsetOf(exports);\n        }\n        derivedPointer = derivedPointer.RefinementBase;\n      }\n      return false;\n    }\n\n    // Check that two resolved types are the same in a similar context (the same type parameters, method, class, etc.)\n    // Assumes that prev is in a previous refinement, and next is in some refinement. Note this is not commutative.\n    public bool ResolvedTypesAreTheSame(Type prev, Type next) {\n      Contract.Requires(prev != null);\n      Contract.Requires(next != null);\n\n      prev = prev.NormalizeExpandKeepConstraints();\n      next = next.NormalizeExpandKeepConstraints();\n\n      if (prev is TypeProxy || next is TypeProxy)\n        return false;\n\n      if (prev is BoolType) {\n        return next is BoolType;\n      } else if (prev is CharType) {\n        return next is CharType;\n      } else if (prev is IntType) {\n        return next is IntType;\n      } else if (prev is RealType) {\n        return next is RealType;\n      } else if (prev is SetType) {\n        return next is SetType && ((SetType)prev).Finite == ((SetType)next).Finite &&\n          ResolvedTypesAreTheSame(((SetType)prev).Arg, ((SetType)next).Arg);\n      } else if (prev is MultiSetType) {\n        return next is MultiSetType && ResolvedTypesAreTheSame(((MultiSetType)prev).Arg, ((MultiSetType)next).Arg);\n      } else if (prev is MapType) {\n        return next is MapType && ((MapType)prev).Finite == ((MapType)next).Finite &&\n               ResolvedTypesAreTheSame(((MapType)prev).Domain, ((MapType)next).Domain) && ResolvedTypesAreTheSame(((MapType)prev).Range, ((MapType)next).Range);\n      } else if (prev is SeqType) {\n        return next is SeqType && ResolvedTypesAreTheSame(((SeqType)prev).Arg, ((SeqType)next).Arg);\n      } else if (prev is UserDefinedType) {\n        if (!(next is UserDefinedType)) {\n          return false;\n        }\n        UserDefinedType aa = (UserDefinedType)prev;\n        UserDefinedType bb = (UserDefinedType)next;\n        if (aa.ResolvedClass != null && bb.ResolvedClass != null && aa.ResolvedClass == bb.ResolvedClass) {\n          // these are both resolved class/datatype types\n          Contract.Assert(aa.TypeArgs.Count == bb.TypeArgs.Count);\n          for (int i = 0; i < aa.TypeArgs.Count; i++)\n            if (!ResolvedTypesAreTheSame(aa.TypeArgs[i], bb.TypeArgs[i]))\n              return false;\n          return true;\n        } else if (aa.ResolvedParam != null && bb.ResolvedParam != null) {\n          // these are both resolved type parameters\n          Contract.Assert(aa.TypeArgs.Count == 0 && bb.TypeArgs.Count == 0);\n          // Note that this is only correct if the two types occur in the same context, ie. both from the same method\n          // or class field.\n          return aa.ResolvedParam.PositionalIndex == bb.ResolvedParam.PositionalIndex &&\n                 aa.ResolvedParam.IsToplevelScope == bb.ResolvedParam.IsToplevelScope;\n        } else if (aa.ResolvedParam != null && aa.ResolvedParam.IsAbstractTypeDeclaration && bb.ResolvedClass != null) {\n          return (aa.ResolvedParam.Name == bb.ResolvedClass.Name);\n        } else {\n          // something is wrong; either aa or bb wasn't properly resolved, or they aren't the same\n          return false;\n        }\n\n      } else {\n        Contract.Assert(false); throw new cce.UnreachableException();  // unexpected type\n      }\n    }\n\n    internal override void PostResolve(ModuleDefinition m) {\n      if (m == moduleUnderConstruction) {\n        while (this.postTasks.Count != 0) {\n          var a = postTasks.Dequeue();\n          a();\n        }\n      } else {\n        postTasks.Clear();\n      }\n      moduleUnderConstruction = null;\n    }\n\n    Function CloneFunction(IToken tok, Function f, bool isGhost, List<MaybeFreeExpression> moreEnsures, Formal moreResult, Expression moreBody, Expression replacementBody, bool checkPrevPostconditions, Attributes moreAttributes) {\n      Contract.Requires(tok != null);\n      Contract.Requires(moreBody == null || f is Predicate);\n      Contract.Requires(moreBody == null || replacementBody == null);\n\n      var tps = f.TypeArgs.ConvertAll(refinementCloner.CloneTypeParam);\n      var formals = f.Formals.ConvertAll(refinementCloner.CloneFormal);\n      var req = f.Req.ConvertAll(refinementCloner.CloneMayBeFreeExpr);\n      var reads = f.Reads.ConvertAll(refinementCloner.CloneFrameExpr);\n      var decreases = refinementCloner.CloneSpecExpr(f.Decreases);\n      var result = f.Result ?? moreResult;\n      if (result != null) {\n        result = refinementCloner.CloneFormal(result);\n      }\n\n      List<MaybeFreeExpression> ens;\n      if (checkPrevPostconditions)  // note, if a postcondition includes something that changes in the module, the translator will notice this and still re-check the postcondition\n        ens = f.Ens.ConvertAll(rawCloner.CloneMayBeFreeExpr);\n      else\n        ens = f.Ens.ConvertAll(refinementCloner.CloneMayBeFreeExpr);\n      if (moreEnsures != null) {\n        ens.AddRange(moreEnsures);\n      }\n\n      Expression body;\n      Predicate.BodyOriginKind bodyOrigin;\n      if (replacementBody != null) {\n        body = replacementBody;\n        bodyOrigin = Predicate.BodyOriginKind.DelayedDefinition;\n      } else if (moreBody != null) {\n        if (f.Body == null) {\n          body = moreBody;\n          bodyOrigin = Predicate.BodyOriginKind.DelayedDefinition;\n        } else {\n          body = new BinaryExpr(f.tok, BinaryExpr.Opcode.And, refinementCloner.CloneExpr(f.Body), moreBody);\n          bodyOrigin = Predicate.BodyOriginKind.Extension;\n        }\n      } else {\n        body = refinementCloner.CloneExpr(f.Body);\n        bodyOrigin = Predicate.BodyOriginKind.OriginalOrInherited;\n      }\n\n      if (f is Predicate) {\n        return new Predicate(tok, f.Name, f.HasStaticKeyword, f.IsProtected, isGhost, tps, formals,\n          req, reads, ens, decreases, body, bodyOrigin, refinementCloner.MergeAttributes(f.Attributes, moreAttributes), null);\n      } else if (f is InductivePredicate) {\n        return new InductivePredicate(tok, f.Name, f.HasStaticKeyword, f.IsProtected, ((InductivePredicate)f).TypeOfK, tps, formals,\n          req, reads, ens, body, refinementCloner.MergeAttributes(f.Attributes, moreAttributes), null);\n      } else if (f is CoPredicate) {\n        return new CoPredicate(tok, f.Name, f.HasStaticKeyword, f.IsProtected, ((CoPredicate)f).TypeOfK, tps, formals,\n          req, reads, ens, body, refinementCloner.MergeAttributes(f.Attributes, moreAttributes), null);\n      } else if (f is TwoStatePredicate) {\n        return new TwoStatePredicate(tok, f.Name, f.HasStaticKeyword, tps, formals,\n          req, reads, ens, decreases, body, refinementCloner.MergeAttributes(f.Attributes, moreAttributes), null);\n      } else if (f is TwoStateFunction) {\n        return new TwoStateFunction(tok, f.Name, f.HasStaticKeyword, tps, formals, result, refinementCloner.CloneType(f.ResultType),\n          req, reads, ens, decreases, body, refinementCloner.MergeAttributes(f.Attributes, moreAttributes), null);\n      } else {\n        return new Function(tok, f.Name, f.HasStaticKeyword, f.IsProtected, isGhost, tps, formals, result, refinementCloner.CloneType(f.ResultType),\n          req, reads, ens, decreases, body, refinementCloner.MergeAttributes(f.Attributes, moreAttributes), null);\n      }\n    }\n\n    Method CloneMethod(Method m, List<MaybeFreeExpression> moreEnsures, Specification<Expression> decreases, BlockStmt newBody, bool checkPreviousPostconditions, Attributes moreAttributes) {\n      Contract.Requires(m != null);\n      Contract.Requires(!(m is Constructor) || newBody == null || newBody is DividedBlockStmt);\n      Contract.Requires(decreases != null);\n\n      var tps = m.TypeArgs.ConvertAll(refinementCloner.CloneTypeParam);\n      var ins = m.Ins.ConvertAll(refinementCloner.CloneFormal);\n      var req = m.Req.ConvertAll(refinementCloner.CloneMayBeFreeExpr);\n      var mod = refinementCloner.CloneSpecFrameExpr(m.Mod);\n      var reads = refinementCloner.CloneSpecExpr(m.Reads);\n      var awaits = m.Awaits.ConvertAll(refinementCloner.CloneExpr);\n      var undefinedUnless = m.UndefinedUnless.ConvertAll(refinementCloner.CloneExpr);\n\n      List<MaybeFreeExpression> ens;\n      if (checkPreviousPostconditions)\n        ens = m.Ens.ConvertAll(rawCloner.CloneMayBeFreeExpr);\n      else\n        ens = m.Ens.ConvertAll(refinementCloner.CloneMayBeFreeExpr);\n      if (moreEnsures != null) {\n        ens.AddRange(moreEnsures);\n      }\n\n      if (m is Constructor) {\n        var dividedBody = (DividedBlockStmt)newBody ?? refinementCloner.CloneDividedBlockStmt((DividedBlockStmt)m.BodyForRefinement);\n        return new Constructor(new RefinementToken(m.tok, moduleUnderConstruction), m.Name, tps, ins,\n          req, mod, ens, decreases, dividedBody, refinementCloner.MergeAttributes(m.Attributes, moreAttributes), null);\n      }\n      var body = newBody ?? refinementCloner.CloneBlockStmt(m.BodyForRefinement);\n      if (m is InductiveLemma) {\n        return new InductiveLemma(new RefinementToken(m.tok, moduleUnderConstruction), m.Name, m.HasStaticKeyword, ((InductiveLemma)m).TypeOfK, tps, ins, m.Outs.ConvertAll(refinementCloner.CloneFormal),\n          req, mod, ens, decreases, body, refinementCloner.MergeAttributes(m.Attributes, moreAttributes), null);\n      } else if (m is CoLemma) {\n        return new CoLemma(new RefinementToken(m.tok, moduleUnderConstruction), m.Name, m.HasStaticKeyword, ((CoLemma)m).TypeOfK, tps, ins, m.Outs.ConvertAll(refinementCloner.CloneFormal),\n          req, mod, ens, decreases, body, refinementCloner.MergeAttributes(m.Attributes, moreAttributes), null);\n      } else if (m is Lemma) {\n        return new Lemma(new RefinementToken(m.tok, moduleUnderConstruction), m.Name, m.HasStaticKeyword, tps, ins, m.Outs.ConvertAll(refinementCloner.CloneFormal),\n          req, mod, ens, decreases, body, refinementCloner.MergeAttributes(m.Attributes, moreAttributes), null);\n      } else if (m is TwoStateLemma) {\n        var two = (TwoStateLemma)m;\n        return new TwoStateLemma(new RefinementToken(m.tok, moduleUnderConstruction), m.Name, m.HasStaticKeyword, tps, ins, m.Outs.ConvertAll(refinementCloner.CloneFormal),\n          req, mod, ens, decreases, body, refinementCloner.MergeAttributes(m.Attributes, moreAttributes), null);\n      } else {\n        return new Method(new RefinementToken(m.tok, moduleUnderConstruction), m.Name, m.HasStaticKeyword, m.IsGhost, tps, ins, m.Outs.ConvertAll(refinementCloner.CloneFormal),\n                          req, mod, ens, decreases, reads, awaits, undefinedUnless, body, refinementCloner.MergeAttributes(m.Attributes, moreAttributes), null);\n      }\n    }\n\n    // -------------------------------------------------- Merging ---------------------------------------------------------------\n\n    IteratorDecl MergeIterator(IteratorDecl nw, IteratorDecl prev) {\n      Contract.Requires(nw != null);\n      Contract.Requires(prev != null);\n\n      if (nw.Requires.Count != 0) {\n        reporter.Error(MessageSource.RefinementTransformer, nw.Requires[0].E.tok, \"a refining iterator is not allowed to add preconditions\");\n      }\n      if (nw.YieldRequires.Count != 0) {\n        reporter.Error(MessageSource.RefinementTransformer, nw.YieldRequires[0].E.tok, \"a refining iterator is not allowed to add yield preconditions\");\n      }\n      if (nw.Reads.Expressions.Count != 0) {\n        reporter.Error(MessageSource.RefinementTransformer, nw.Reads.Expressions[0].E.tok, \"a refining iterator is not allowed to extend the reads clause\");\n      }\n      if (nw.Modifies.Expressions.Count != 0) {\n        reporter.Error(MessageSource.RefinementTransformer, nw.Modifies.Expressions[0].E.tok, \"a refining iterator is not allowed to extend the modifies clause\");\n      }\n      if (nw.Decreases.Expressions.Count != 0) {\n        reporter.Error(MessageSource.RefinementTransformer, nw.Decreases.Expressions[0].tok, \"a refining iterator is not allowed to extend the decreases clause\");\n      }\n\n      if (nw.SignatureIsOmitted) {\n        Contract.Assert(nw.TypeArgs.Count == 0);\n        Contract.Assert(nw.Ins.Count == 0);\n        Contract.Assert(nw.Outs.Count == 0);\n        reporter.Info(MessageSource.RefinementTransformer, nw.SignatureEllipsis, Printer.IteratorSignatureToString(prev));\n      } else {\n        CheckAgreement_TypeParameters(nw.tok, prev.TypeArgs, nw.TypeArgs, nw.Name, \"iterator\");\n        CheckAgreement_Parameters(nw.tok, prev.Ins, nw.Ins, nw.Name, \"iterator\", \"in-parameter\");\n        CheckAgreement_Parameters(nw.tok, prev.Outs, nw.Outs, nw.Name, \"iterator\", \"yield-parameter\");\n      }\n\n      BlockStmt newBody;\n      if (nw.Body == null) {\n        newBody = prev.Body;\n      } else if (prev.Body == null) {\n        newBody = nw.Body;\n      } else {\n        newBody = MergeBlockStmt(nw.Body, prev.Body);\n      }\n\n      var ens = prev.Ensures.ConvertAll(rawCloner.CloneMayBeFreeExpr);\n      ens.AddRange(nw.Ensures);\n      var yens = prev.YieldEnsures.ConvertAll(rawCloner.CloneMayBeFreeExpr);\n      yens.AddRange(nw.YieldEnsures);\n\n      return new IteratorDecl(new RefinementToken(nw.tok, moduleUnderConstruction),\n        nw.Name, moduleUnderConstruction,\n        nw.SignatureIsOmitted ? prev.TypeArgs.ConvertAll(refinementCloner.CloneTypeParam) : nw.TypeArgs,\n        nw.SignatureIsOmitted ? prev.Ins.ConvertAll(refinementCloner.CloneFormal) : nw.Ins,\n        nw.SignatureIsOmitted ? prev.Outs.ConvertAll(refinementCloner.CloneFormal) : nw.Outs,\n        refinementCloner.CloneSpecFrameExpr(prev.Reads),\n        refinementCloner.CloneSpecFrameExpr(prev.Modifies),\n        refinementCloner.CloneSpecExpr(prev.Decreases),\n        prev.Requires.ConvertAll(refinementCloner.CloneMayBeFreeExpr),\n        ens,\n        prev.YieldRequires.ConvertAll(refinementCloner.CloneMayBeFreeExpr),\n        yens,\n        newBody,\n        refinementCloner.MergeAttributes(prev.Attributes, nw.Attributes),\n        null);\n    }\n\n    ClassDecl MergeClass(ClassDecl nw, ClassDecl prev) {\n      CheckAgreement_TypeParameters(nw.tok, prev.TypeArgs, nw.TypeArgs, nw.Name, \"class\");\n\n      nw.Attributes = refinementCloner.MergeAttributes(prev.Attributes, nw.Attributes);\n\n      // Create a simple name-to-member dictionary.  Ignore any duplicates at this time.\n      var declaredNames = new Dictionary<string, int>();\n      for (int i = 0; i < nw.Members.Count; i++) {\n        var member = nw.Members[i];\n        if (!declaredNames.ContainsKey(member.Name)) {\n          declaredNames.Add(member.Name, i);\n        }\n\n        if (prev.IsDefaultClass && refinedSigOpened.StaticMembers.ContainsKey(member.Name) &&\n          !RefinedSig.StaticMembers.ContainsKey(member.Name)) {\n            reporter.Error(MessageSource.RefinementTransformer, member.tok, \"Base module {0} imports {1} from an opened import, so it cannot be overridden. Give this declaration a unique name to disambiguate.\", RefinedSig.ModuleDef.Name, member.Name);\n        }\n      }\n\n      // Merge the declarations of prev into the declarations of m\n      foreach (var member in prev.Members) {\n        int index;\n        if (!declaredNames.TryGetValue(member.Name, out index)) {\n          var nwMember = refinementCloner.CloneMember(member);\n          nwMember.RefinementBase = member;\n          nw.Members.Add(nwMember);\n        } else {\n          var nwMember = nw.Members[index];\n          if (nwMember is ConstantField) {\n            var newConst = (ConstantField)nwMember;\n            var origConst = member as ConstantField;\n            if (origConst == null) {\n              reporter.Error(MessageSource.RefinementTransformer, nwMember, \"a const declaration ({0}) in a refining class ({1}) must replace a const in the refinement base\", nwMember.Name, nw.Name);\n            } else if (!(newConst.Type is InferredTypeProxy) && !TypesAreSyntacticallyEqual(newConst.Type, origConst.Type)) {\n              reporter.Error(MessageSource.RefinementTransformer, nwMember, \"the type of a const declaration ({0}) in a refining class ({1}) must be syntactically the same as for the const being refined\", nwMember.Name, nw.Name);\n            } else if (newConst.Rhs != null && origConst.Rhs != null) {\n              reporter.Error(MessageSource.RefinementTransformer, nwMember, \"a const re-declaration ({0}) can give an initializing expression only if the const in the refinement base does not\", nwMember.Name);\n            } else if (newConst.HasStaticKeyword != origConst.HasStaticKeyword) {\n              reporter.Error(MessageSource.RefinementTransformer, nwMember, \"a const in a refining module cannot be changed from static to non-static or vice versa: {0}\", nwMember.Name);\n            } else if (origConst.IsGhost && !newConst.IsGhost) {\n              reporter.Error(MessageSource.RefinementTransformer, nwMember, \"a const re-declaration ({0}) is not allowed to un-ghostify the const\", nwMember.Name);\n            } else if (newConst.Rhs == null && origConst.IsGhost == newConst.IsGhost) {\n              reporter.Error(MessageSource.RefinementTransformer, nwMember, \"a const re-declaration ({0}) must be to ghostify the const{1}\", nwMember.Name, origConst.Rhs == null ? \" or to provide an initializing expression\" : \"\");\n            }\n            nwMember.RefinementBase = member;\n            // we may need to clone the given const declaration if either its type or initializing expression was omitted\n            if (origConst != null) {\n              if ((!(origConst.Type is InferredTypeProxy) && newConst.Type is InferredTypeProxy) || (origConst.Rhs != null && newConst.Rhs == null)) {\n                var typ = newConst.Type is InferredTypeProxy ? refinementCloner.CloneType(origConst.Type) : newConst.Type;\n                var rhs = newConst.Rhs ?? origConst.Rhs;\n                nw.Members[index] = new ConstantField(newConst.tok, newConst.Name, rhs, newConst.HasStaticKeyword, newConst.IsGhost, typ, newConst.Attributes);\n              }\n            }\n\n          } else if (nwMember is Field) {\n            if (!(member is Field) || member is ConstantField) {\n              reporter.Error(MessageSource.RefinementTransformer, nwMember, \"a field declaration ({0}) in a refining class ({1}) must replace a field in the refinement base\", nwMember.Name, nw.Name);\n            } else if (!TypesAreSyntacticallyEqual(((Field)nwMember).Type, ((Field)member).Type)) {\n              reporter.Error(MessageSource.RefinementTransformer, nwMember, \"a field declaration ({0}) in a refining class ({1}) must repeat the syntactically same type as the field has in the refinement base\", nwMember.Name, nw.Name);\n            } else if (member.IsGhost || !nwMember.IsGhost) {\n              reporter.Error(MessageSource.RefinementTransformer, nwMember, \"a field re-declaration ({0}) must be to ghostify the field\", nwMember.Name);\n            }\n            nwMember.RefinementBase = member;\n\n          } else if (nwMember is Function) {\n            var f = (Function)nwMember;\n            bool isPredicate = f is Predicate;\n            bool isIndPredicate = f is InductivePredicate;\n            bool isCoPredicate = f is CoPredicate;\n            if (!(member is Function) ||\n              isPredicate != (member is Predicate) ||\n              (f is InductivePredicate) != (member is InductivePredicate) ||\n              (f is CoPredicate) != (member is CoPredicate) ||\n              (f is TwoStatePredicate) != (member is TwoStatePredicate) ||\n              (f is TwoStateFunction) != (member is TwoStateFunction)) {\n              reporter.Error(MessageSource.RefinementTransformer, nwMember, \"a {0} declaration ({1}) can only refine a {0}\", f.WhatKind, nwMember.Name);\n            } else if (f.IsProtected != ((Function)member).IsProtected) {\n              reporter.Error(MessageSource.RefinementTransformer, f, \"a {0} in a refinement module must be declared 'protected' if and only if the refined {0} is\", f.WhatKind);\n            } else {\n              var prevFunction = (Function)member;\n              if (f.Req.Count != 0) {\n                reporter.Error(MessageSource.RefinementTransformer, f.Req[0].E.tok, \"a refining {0} is not allowed to add preconditions\", f.WhatKind);\n              }\n              if (f.Reads.Count != 0) {\n                reporter.Error(MessageSource.RefinementTransformer, f.Reads[0].E.tok, \"a refining {0} is not allowed to extend the reads clause\", f.WhatKind);\n              }\n              if (f.Decreases.Expressions.Count != 0) {\n                reporter.Error(MessageSource.RefinementTransformer, f.Decreases.Expressions[0].tok, \"decreases clause on refining {0} not supported\", f.WhatKind);\n              }\n\n              if (prevFunction.HasStaticKeyword != f.HasStaticKeyword) {\n                reporter.Error(MessageSource.RefinementTransformer, f, \"a function in a refining module cannot be changed from static to non-static or vice versa: {0}\", f.Name);\n              }\n              if (!prevFunction.IsGhost && f.IsGhost) {\n                reporter.Error(MessageSource.RefinementTransformer, f, \"a function method cannot be changed into a (ghost) function in a refining module: {0}\", f.Name);\n              } else if (prevFunction.IsGhost && !f.IsGhost && prevFunction.Body != null) {\n                reporter.Error(MessageSource.RefinementTransformer, f, \"a function can be changed into a function method in a refining module only if the function has not yet been given a body: {0}\", f.Name);\n              }\n              if (f.SignatureIsOmitted) {\n                Contract.Assert(f.TypeArgs.Count == 0);\n                Contract.Assert(f.Formals.Count == 0);\n                reporter.Info(MessageSource.RefinementTransformer, f.SignatureEllipsis, Printer.FunctionSignatureToString(prevFunction));\n              } else {\n                CheckAgreement_TypeParameters(f.tok, prevFunction.TypeArgs, f.TypeArgs, f.Name, \"function\");\n                CheckAgreement_Parameters(f.tok, prevFunction.Formals, f.Formals, f.Name, \"function\", \"parameter\");\n                if (prevFunction.Result != null && f.Result != null && prevFunction.Result.Name != f.Result.Name) {\n                  reporter.Error(MessageSource.RefinementTransformer, f, \"the name of function return value '{0}'({1}) differs from the name of corresponding function return value in the module it refines ({2})\", f.Name, f.Result.Name, prevFunction.Result.Name);\n                }\n                if (!TypesAreSyntacticallyEqual(prevFunction.ResultType, f.ResultType)) {\n                  reporter.Error(MessageSource.RefinementTransformer, f, \"the result type of function '{0}' ({1}) differs from the result type of the corresponding function in the module it refines ({2})\", f.Name, f.ResultType, prevFunction.ResultType);\n                }\n              }\n\n              Expression moreBody = null;\n              Expression replacementBody = null;\n              if (prevFunction.Body == null) {\n                replacementBody = f.Body;\n              } else if (f.Body != null) {\n                if (isPredicate && f.IsProtected) {\n                  moreBody = f.Body;\n                } else if (isPredicate) {\n                  reporter.Error(MessageSource.RefinementTransformer, nwMember, \"a refining predicate is not allowed to extend/change the body unless it is declared 'protected'\");\n                } else {\n                  reporter.Error(MessageSource.RefinementTransformer, nwMember, \"a refining function is not allowed to extend/change the body\");\n                }\n              }\n              var newF = CloneFunction(f.tok, prevFunction, f.IsGhost, f.Ens, f.Result, moreBody, replacementBody, prevFunction.Body == null, f.Attributes);\n              newF.RefinementBase = member;\n              nw.Members[index] = newF;\n            }\n\n          } else {\n            var m = (Method)nwMember;\n            if (!(member is Method)) {\n              reporter.Error(MessageSource.RefinementTransformer, nwMember, \"a method declaration ({0}) can only refine a method\", nwMember.Name);\n            } else {\n              var prevMethod = (Method)member;\n              if (m.Req.Count != 0) {\n                reporter.Error(MessageSource.RefinementTransformer, m.Req[0].E.tok, \"a refining method is not allowed to add preconditions\");\n              }\n              if (m.Mod.Expressions.Count != 0) {\n                reporter.Error(MessageSource.RefinementTransformer, m.Mod.Expressions[0].E.tok, \"a refining method is not allowed to extend the modifies clause\");\n              }\n              // If the previous method was not specified with \"decreases *\", then the new method is not allowed to provide any \"decreases\" clause.\n              // Any \"decreases *\" clause is not inherited, so if the previous method was specified with \"decreases *\", then the new method needs\n              // to either redeclare \"decreases *\", provided a termination-checking \"decreases\" clause, or give no \"decreases\" clause and thus\n              // get a default \"decreases\" loop.\n              Specification<Expression> decreases;\n              if (m.Decreases.Expressions.Count == 0) {\n                // inherited whatever the previous loop used\n                decreases = refinementCloner.CloneSpecExpr(prevMethod.Decreases);\n              } else {\n                if (!Contract.Exists(prevMethod.Decreases.Expressions, e => e is WildcardExpr)) {\n                  // If the previous loop was not specified with \"decreases *\", then the new loop is not allowed to provide any \"decreases\" clause.\n                  reporter.Error(MessageSource.RefinementTransformer, m.Decreases.Expressions[0].tok, \"decreases clause on refining method not supported, unless the refined method was specified with 'decreases *'\");\n                }\n                decreases = m.Decreases;\n              }\n              if (prevMethod.HasStaticKeyword != m.HasStaticKeyword) {\n                reporter.Error(MessageSource.RefinementTransformer, m, \"a method in a refining module cannot be changed from static to non-static or vice versa: {0}\", m.Name);\n              }\n              if (prevMethod.IsGhost && !m.IsGhost) {\n                reporter.Error(MessageSource.RefinementTransformer, m, \"a method cannot be changed into a ghost method in a refining module: {0}\", m.Name);\n              } else if (!prevMethod.IsGhost && m.IsGhost) {\n                reporter.Error(MessageSource.RefinementTransformer, m, \"a ghost method cannot be changed into a non-ghost method in a refining module: {0}\", m.Name);\n              }\n              if (m.SignatureIsOmitted) {\n                Contract.Assert(m.TypeArgs.Count == 0);\n                Contract.Assert(m.Ins.Count == 0);\n                Contract.Assert(m.Outs.Count == 0);\n                reporter.Info(MessageSource.RefinementTransformer, m.SignatureEllipsis, Printer.MethodSignatureToString(prevMethod));\n              } else {\n                CheckAgreement_TypeParameters(m.tok, prevMethod.TypeArgs, m.TypeArgs, m.Name, \"method\");\n                CheckAgreement_Parameters(m.tok, prevMethod.Ins, m.Ins, m.Name, \"method\", \"in-parameter\");\n                CheckAgreement_Parameters(m.tok, prevMethod.Outs, m.Outs, m.Name, \"method\", \"out-parameter\");\n              }\n              currentMethod = m;\n              var replacementBody = m.BodyForRefinement;\n              if (replacementBody != null) {\n                if (prevMethod.BodyForRefinement == null) {\n                  // cool\n                } else {\n                  replacementBody = MergeBlockStmt(replacementBody, prevMethod.BodyForRefinement);\n                }\n              }\n              var newM = CloneMethod(prevMethod, m.Ens, decreases, replacementBody, prevMethod.BodyForRefinement == null, m.Attributes);\n              newM.RefinementBase = member;\n              nw.Members[index] = newM;\n            }\n          }\n        }\n      }\n\n      return nw;\n    }\n    void CheckAgreement_TypeParameters(IToken tok, List<TypeParameter> old, List<TypeParameter> nw, string name, string thing, bool checkNames = true) {\n      Contract.Requires(tok != null);\n      Contract.Requires(old != null);\n      Contract.Requires(nw != null);\n      Contract.Requires(name != null);\n      Contract.Requires(thing != null);\n      if (old.Count != nw.Count) {\n        reporter.Error(MessageSource.RefinementTransformer, tok, \"{0} '{1}' is declared with a different number of type parameters ({2} instead of {3}) than the corresponding {0} in the module it refines\", thing, name, nw.Count, old.Count);\n      } else {\n        for (int i = 0; i < old.Count; i++) {\n          var o = old[i];\n          var n = nw[i];\n          if (o.Name != n.Name && checkNames) { // if checkNames is false, then just treat the parameters positionally.\n            reporter.Error(MessageSource.RefinementTransformer, n.tok, \"type parameters are not allowed to be renamed from the names given in the {0} in the module being refined (expected '{1}', found '{2}')\", thing, o.Name, n.Name);\n          } else {\n            // This explains what we want to do and why:\n            // switch (o.EqualitySupport) {\n            //   case TypeParameter.EqualitySupportValue.Required:\n            //     // here, we will insist that the new type-parameter also explicitly requires equality support (because we don't want\n            //     // to wait for the inference to run on the new module)\n            //     good = n.EqualitySupport == TypeParameter.EqualitySupportValue.Required;\n            //     break;\n            //   case TypeParameter.EqualitySupportValue.InferredRequired:\n            //     // here, we can allow anything, because even with an Unspecified value, the inference will come up with InferredRequired, like before\n            //     good = true;\n            //     break;\n            //   case TypeParameter.EqualitySupportValue.Unspecified:\n            //     // inference didn't come up with anything on the previous module, so the only value we'll allow here is Unspecified as well\n            //     good = n.EqualitySupport == TypeParameter.EqualitySupportValue.Unspecified;\n            //     break;\n            // }\n            // Here's how we actually compute it:\n            if (o.Characteristics.EqualitySupport != TypeParameter.EqualitySupportValue.InferredRequired && o.Characteristics.EqualitySupport != n.Characteristics.EqualitySupport) {\n              reporter.Error(MessageSource.RefinementTransformer, n.tok, \"type parameter '{0}' is not allowed to change the requirement of supporting equality\", n.Name);\n            }\n            if (o.Characteristics.MustSupportZeroInitialization != n.Characteristics.MustSupportZeroInitialization) {\n              reporter.Error(MessageSource.RefinementTransformer, n.tok, \"type parameter '{0}' is not allowed to change the requirement of supporting zero initialization\", n.Name);\n            }\n            if (o.Characteristics.DisallowReferenceTypes != n.Characteristics.DisallowReferenceTypes) {\n              reporter.Error(MessageSource.RefinementTransformer, n.tok, \"type parameter '{0}' is not allowed to change the no-reference-type requirement\", n.Name);\n            }\n            if (o.Variance != n.Variance) {  // syntax is allowed to be different as long as the meaning is the same (i.e., compare Variance, not VarianceSyntax)\n              var ov = o.Variance == TypeParameter.TPVariance.Co ? \"+\" : o.Variance == TypeParameter.TPVariance.Contra ? \"-\" : \"=\";\n              var nv = n.Variance == TypeParameter.TPVariance.Co ? \"+\" : n.Variance == TypeParameter.TPVariance.Contra ? \"-\" : \"=\";\n              reporter.Error(MessageSource.RefinementTransformer, n.tok, \"type parameter '{0}' is not allowed to change variance (here, from '{1}' to '{2}')\", n.Name, ov, nv);\n            }\n          }\n        }\n      }\n    }\n\n    public void CheckOverride_FunctionParameters(Function nw, Function f)\n    {\n        CheckOverride_TypeParameters(nw.tok, f.TypeArgs, nw.TypeArgs, nw.Name, \"function\", false);\n        CheckOverrideResolvedParameters(nw.tok, f.Formals, nw.Formals, nw.Name, \"function\", \"parameter\");\n        if (!ResolvedTypesAreTheSame(nw.ResultType, f.ResultType))\n        {\n            reporter.Error(MessageSource.RefinementTransformer, nw, \"the result type of function '{0}' ({1}) differs from the result type of the corresponding function in the module it overrides ({2})\", nw.Name, nw.ResultType, f.ResultType);\n        }\n    }\n\n    public void CheckOverride_MethodParameters(Method nw, Method f)\n    {\n        CheckOverride_TypeParameters(nw.tok, f.TypeArgs, nw.TypeArgs, nw.Name, \"method\", false);\n        CheckOverrideResolvedParameters(nw.tok, f.Ins, nw.Ins, nw.Name, \"method\", \"in-parameter\");\n        CheckOverrideResolvedParameters(nw.tok, f.Outs, nw.Outs, nw.Name, \"method\", \"out-parameter\");\n    }\n\n    public void CheckOverride_TypeParameters(IToken tok, List<TypeParameter> old, List<TypeParameter> nw, string name, string thing, bool checkNames = true)\n    {\n        Contract.Requires(tok != null);\n        Contract.Requires(old != null);\n        Contract.Requires(nw != null);\n        Contract.Requires(name != null);\n        Contract.Requires(thing != null);\n        if (old.Count != nw.Count)\n        {\n            reporter.Error(MessageSource.RefinementTransformer, tok, \"{0} '{1}' is declared with a different number of type parameters ({2} instead of {3}) than the corresponding {0} in the module it overrides\", thing, name, nw.Count, old.Count);\n        }\n        else\n        {\n            for (int i = 0; i < old.Count; i++)\n            {\n                var o = old[i];\n                var n = nw[i];\n                if (o.Name != n.Name && checkNames)\n                { // if checkNames is false, then just treat the parameters positionally.\n                    reporter.Error(MessageSource.RefinementTransformer, n.tok, \"type parameters are not allowed to be renamed from the names given in the {0} in the module being overriden (expected '{1}', found '{2}')\", thing, o.Name, n.Name);\n                }\n                else\n                {\n                    // Here's how we actually compute it:\n                    if (o.Characteristics.EqualitySupport != TypeParameter.EqualitySupportValue.InferredRequired && o.Characteristics.EqualitySupport != n.Characteristics.EqualitySupport)\n                    {\n                        reporter.Error(MessageSource.RefinementTransformer, n.tok, \"type parameter '{0}' is not allowed to change the requirement of supporting equality\", n.Name);\n                    }\n                    if (o.Characteristics.MustSupportZeroInitialization != n.Characteristics.MustSupportZeroInitialization) {\n                      reporter.Error(MessageSource.RefinementTransformer, n.tok, \"type parameter '{0}' is not allowed to change the requirement of supporting zero initialization\", n.Name);\n                    }\n                    if (o.Characteristics.DisallowReferenceTypes != n.Characteristics.DisallowReferenceTypes) {\n                      reporter.Error(MessageSource.RefinementTransformer, n.tok, \"type parameter '{0}' is not allowed to change the no-reference-type requirement\", n.Name);\n                    }\n          }\n        }\n        }\n    }\n\n    public void CheckOverrideResolvedParameters(IToken tok, List<Formal> old, List<Formal> nw, string name, string thing, string parameterKind)\n    {\n        Contract.Requires(tok != null);\n        Contract.Requires(old != null);\n        Contract.Requires(nw != null);\n        Contract.Requires(name != null);\n        Contract.Requires(thing != null);\n        Contract.Requires(parameterKind != null);\n        if (old.Count != nw.Count)\n        {\n            reporter.Error(MessageSource.RefinementTransformer, tok, \"{0} '{1}' is declared with a different number of {2} ({3} instead of {4}) than the corresponding {0} in the module it overrides\", thing, name, parameterKind, nw.Count, old.Count);\n        }\n        else\n        {\n            for (int i = 0; i < old.Count; i++)\n            {\n                var o = old[i];\n                var n = nw[i];\n                if (!o.IsGhost && n.IsGhost) {\n                  reporter.Error(MessageSource.RefinementTransformer, n.tok, \"{0} '{1}' of {2} {3} cannot be changed, compared to the corresponding {2} in the module it overrides, from non-ghost to ghost\", parameterKind, n.Name, thing, name);\n                } else if (o.IsGhost && !n.IsGhost) {\n                  reporter.Error(MessageSource.RefinementTransformer, n.tok, \"{0} '{1}' of {2} {3} cannot be changed, compared to the corresponding {2} in the module it overrides, from ghost to non-ghost\", parameterKind, n.Name, thing, name);\n                } else if (!o.IsOld && n.IsOld) {\n                  reporter.Error(MessageSource.RefinementTransformer, n.tok, \"{0} '{1}' of {2} {3} cannot be changed, compared to the corresponding {2} in the module it overrides, from non-new to new\", parameterKind, n.Name, thing, name);\n                } else if (o.IsOld && !n.IsOld) {\n                  reporter.Error(MessageSource.RefinementTransformer, n.tok, \"{0} '{1}' of {2} {3} cannot be changed, compared to the corresponding {2} in the module it overrides, from new to non-new\", parameterKind, n.Name, thing, name);\n                } else if (!ResolvedTypesAreTheSame(o.Type, n.Type)) {\n                  reporter.Error(MessageSource.RefinementTransformer, n.tok, \"the type of {0} '{1}' is different from the type of the same {0} in the corresponding {2} in the module it overrides ('{3}' instead of '{4}')\", parameterKind, n.Name, thing, n.Type, o.Type);\n                }\n            }\n        }\n    }\n\n    void CheckAgreement_Parameters(IToken tok, List<Formal> old, List<Formal> nw, string name, string thing, string parameterKind) {\n      Contract.Requires(tok != null);\n      Contract.Requires(old != null);\n      Contract.Requires(nw != null);\n      Contract.Requires(name != null);\n      Contract.Requires(thing != null);\n      Contract.Requires(parameterKind != null);\n      if (old.Count != nw.Count) {\n        reporter.Error(MessageSource.RefinementTransformer, tok, \"{0} '{1}' is declared with a different number of {2} ({3} instead of {4}) than the corresponding {0} in the module it refines\", thing, name, parameterKind, nw.Count, old.Count);\n      } else {\n        for (int i = 0; i < old.Count; i++) {\n          var o = old[i];\n          var n = nw[i];\n          if (o.Name != n.Name) {\n            reporter.Error(MessageSource.RefinementTransformer, n.tok, \"there is a difference in name of {0} {1} ('{2}' versus '{3}') of {4} {5} compared to corresponding {4} in the module it refines\", parameterKind, i, n.Name, o.Name, thing, name);\n          } else if (!o.IsGhost && n.IsGhost) {\n            reporter.Error(MessageSource.RefinementTransformer, n.tok, \"{0} '{1}' of {2} {3} cannot be changed, compared to the corresponding {2} in the module it refines, from non-ghost to ghost\", parameterKind, n.Name, thing, name);\n          } else if (o.IsGhost && !n.IsGhost) {\n            reporter.Error(MessageSource.RefinementTransformer, n.tok, \"{0} '{1}' of {2} {3} cannot be changed, compared to the corresponding {2} in the module it refines, from ghost to non-ghost\", parameterKind, n.Name, thing, name);\n          } else if (!o.IsOld && n.IsOld) {\n            reporter.Error(MessageSource.RefinementTransformer, n.tok, \"{0} '{1}' of {2} {3} cannot be changed, compared to the corresponding {2} in the module it refines, from non-new to new\", parameterKind, n.Name, thing, name);\n          } else if (o.IsOld && !n.IsOld) {\n            reporter.Error(MessageSource.RefinementTransformer, n.tok, \"{0} '{1}' of {2} {3} cannot be changed, compared to the corresponding {2} in the module it refines, from new to non-new\", parameterKind, n.Name, thing, name);\n          } else if (!TypesAreSyntacticallyEqual(o.Type, n.Type)) {\n            reporter.Error(MessageSource.RefinementTransformer, n.tok, \"the type of {0} '{1}' is different from the type of the same {0} in the corresponding {2} in the module it refines ('{3}' instead of '{4}')\", parameterKind, n.Name, thing, n.Type, o.Type);\n          }\n        }\n      }\n    }\n\n    bool TypesAreSyntacticallyEqual(Type t, Type u) {\n      Contract.Requires(t != null);\n      Contract.Requires(u != null);\n      return t.ToString() == u.ToString();\n    }\n\n    BlockStmt MergeBlockStmt(BlockStmt skeleton, BlockStmt oldStmt) {\n      Contract.Requires(skeleton != null);\n      Contract.Requires(oldStmt != null);\n      Contract.Requires(skeleton is DividedBlockStmt == oldStmt is DividedBlockStmt);\n\n      if (skeleton is DividedBlockStmt) {\n        var sbsSkeleton = (DividedBlockStmt)skeleton;\n        var sbsOldStmt = (DividedBlockStmt)oldStmt;\n        string hoverText;\n        var bodyInit = MergeStmtList(sbsSkeleton.BodyInit, sbsOldStmt.BodyInit, out hoverText);\n        if (hoverText.Length != 0) {\n          reporter.Info(MessageSource.RefinementTransformer, sbsSkeleton.SeparatorTok ?? sbsSkeleton.Tok, hoverText);\n        }\n        var bodyProper = MergeStmtList(sbsSkeleton.BodyProper, sbsOldStmt.BodyProper, out hoverText);\n        if (hoverText.Length != 0) {\n          reporter.Info(MessageSource.RefinementTransformer, sbsSkeleton.EndTok, hoverText);\n        }\n        return new DividedBlockStmt(sbsSkeleton.Tok, sbsSkeleton.EndTok, bodyInit, sbsSkeleton.SeparatorTok, bodyProper);\n      } else {\n        string hoverText;\n        var body = MergeStmtList(skeleton.Body, oldStmt.Body, out hoverText);\n        if (hoverText.Length != 0) {\n          reporter.Info(MessageSource.RefinementTransformer, skeleton.EndTok, hoverText);\n        }\n        return new BlockStmt(skeleton.Tok, skeleton.EndTok, body);\n      }\n    }\n\n    List<Statement> MergeStmtList(List<Statement> skeleton, List<Statement> oldStmt, out string hoverText) {\n      Contract.Requires(skeleton != null);\n      Contract.Requires(oldStmt != null);\n      Contract.Ensures(Contract.ValueAtReturn(out hoverText) != null);\n      Contract.Ensures(Contract.Result<List<Statement>>() != null);\n\n      hoverText = \"\";\n      var body = new List<Statement>();\n      int i = 0, j = 0;\n      while (i < skeleton.Count) {\n        var cur = skeleton[i];\n        if (j == oldStmt.Count) {\n          if (!(cur is SkeletonStatement)) {\n            MergeAddStatement(cur, body);\n          } else if (((SkeletonStatement)cur).S == null) {\n            // the \"...\" matches the empty statement sequence\n          } else {\n            reporter.Error(MessageSource.RefinementTransformer, cur.Tok, \"skeleton statement does not match old statement\");\n          }\n          i++;\n        } else {\n          var oldS = oldStmt[j];\n          /* See how the two statements match up.\n           *   oldS                         cur                         result\n           *   ------                      ------                       ------\n           *   assume E;                    assert ...;                 assert E;\n           *   assert E;                    assert ...;                 assert E;\n           *   assert E;                                                assert E;\n           *\n           *   assume E;                    assume ...;                 assume E;\n           *\n           *   var x;                       var x := E;                 var x := E;\n           *   var x := *;                  var x := E;                 var x := E;\n           *   var x :| P;                  var x := E1;                var x := E1; assert P;\n           *   var VarProduction;                                       var VarProduction;\n           *\n           *   x := *;                      x := E;                     x := E;\n           *   x :| P;                      x := E;                     x := E; assert P;\n           *\n           *   modify E;                    modify ...;                 modify E;\n           *   modify E;                    modify ... { S }            modify E { S }\n           *   modify E { S }               modify ... { S' }           modify E { Merge(S, S') }\n           *\n           *   if (G) Then' else Else'      if ... Then else Else       if (G) Merge(Then,Then') else Merge(Else,Else')\n           *   if (*) Then' else Else'      if (G) Then else Else       if (G) Merge(Then,Then') else Merge(Else,Else')\n           *\n           *   while (G) LoopSpec' Body     while ... LoopSpec ...      while (G) Merge(LoopSpec,LoopSpec') Body\n           *   while (G) LoopSpec' Body'    while ... LoopSpec Body     while (G) Merge(LoopSpec,LoopSpec') Merge(Body,Body')\n           *   while (*) LoopSpec' Body     while (G) LoopSpec ...      while (G) Merge(LoopSpec,LoopSpec') Body\n           *   while (*) LoopSpec' Body'    while (G) LoopSpec Body     while (G) Merge(LoopSpec,LoopSpec') Merge(Body,Body')\n           *\n           *   StmtThatDoesNotMatchS; S'    ... where x = e; S          StatementThatDoesNotMatchS[e/x]; Merge( ... where x = e; S , S')\n           *   StmtThatMatchesS; S'         ... where x = e; S          StmtThatMatchesS; S'\n           *\n           * Note, LoopSpec must contain only invariant declarations (as the parser ensures for the first three cases).\n           * Note, there is an implicit \"...;\" at the end of every block in a skeleton.\n           */\n          if (cur is SkeletonStatement) {\n            var c = (SkeletonStatement)cur;\n            var S = c.S;\n            if (S == null) {\n              var nxt = i + 1 == skeleton.Count ? null : skeleton[i + 1];\n              if (nxt != null && nxt is SkeletonStatement && ((SkeletonStatement)nxt).S == null) {\n                // \"...; ...;\" is the same as just \"...;\", so skip this one\n              } else {\n                SubstitutionCloner subber = null;\n                if (c.NameReplacements != null) {\n                  var subExprs = new Dictionary<string, Expression>();\n                  Contract.Assert(c.NameReplacements.Count == c.ExprReplacements.Count);\n                  for (int k = 0; k < c.NameReplacements.Count; k++) {\n                    if (subExprs.ContainsKey(c.NameReplacements[k].val)) {\n                      reporter.Error(MessageSource.RefinementTransformer, c.NameReplacements[k], \"replacement definition must contain at most one definition for a given label\");\n                    } else subExprs.Add(c.NameReplacements[k].val, c.ExprReplacements[k]);\n                  }\n                  subber = new SubstitutionCloner(subExprs, rawCloner);\n                }\n                // skip up until the next thing that matches \"nxt\"\n                var hoverTextA = \"\";\n                var sepA = \"\";\n                while (nxt == null || !PotentialMatch(nxt, oldS)) {\n                  // loop invariant:  oldS == oldStmt.Body[j]\n                  var s = refinementCloner.CloneStmt(oldS);\n                  if (subber != null)\n                    s = subber.CloneStmt(s);\n                  body.Add(s);\n                  hoverTextA += sepA + Printer.StatementToString(s);\n                  sepA = \"\\n\";\n                  j++;\n                  if (j == oldStmt.Count) { break; }\n                  oldS = oldStmt[j];\n                }\n                if (hoverTextA.Length != 0) {\n                  reporter.Info(MessageSource.RefinementTransformer, c.Tok, hoverTextA);\n                }\n                if (subber != null && subber.SubstitutionsMade.Count < subber.Exprs.Count) {\n                  foreach (var s in subber.SubstitutionsMade)\n                    subber.Exprs.Remove(s);\n                  reporter.Error(MessageSource.RefinementTransformer, c.Tok, \"could not find labeled expression(s): \" + Util.Comma(\", \", subber.Exprs.Keys, x => x));\n                }\n              }\n              i++;\n\n            } else if (S is AssertStmt) {\n              var skel = (AssertStmt)S;\n              Contract.Assert(c.ConditionOmitted);\n              var oldAssume = oldS as PredicateStmt;\n              if (oldAssume == null) {\n                reporter.Error(MessageSource.RefinementTransformer, cur.Tok, \"assert template does not match inherited statement\");\n                i++;\n              } else {\n                // Clone the expression, but among the new assert's attributes, indicate\n                // that this assertion is supposed to be translated into a check.  That is,\n                // it is not allowed to be just assumed in the translation, despite the fact\n                // that the condition is inherited.\n                var e = refinementCloner.CloneExpr(oldAssume.Expr);\n                var attrs = refinementCloner.MergeAttributes(oldAssume.Attributes, skel.Attributes);\n                body.Add(new AssertStmt(new Translator.ForceCheckToken(skel.Tok), new Translator.ForceCheckToken(skel.EndTok),\n                  e, skel.Proof, skel.Label, new Attributes(\"_prependAssertToken\", new List<Expression>(), attrs)));\n                reporter.Info(MessageSource.RefinementTransformer, c.ConditionEllipsis, \"assume->assert: \" + Printer.ExprToString(e));\n                i++; j++;\n              }\n\n            } else if (S is AssumeStmt) {\n              var skel = (AssumeStmt)S;\n              Contract.Assert(c.ConditionOmitted);\n              var oldAssume = oldS as AssumeStmt;\n              if (oldAssume == null) {\n                reporter.Error(MessageSource.RefinementTransformer, cur.Tok, \"assume template does not match inherited statement\");\n                i++;\n              } else {\n                var e = refinementCloner.CloneExpr(oldAssume.Expr);\n                var attrs = refinementCloner.MergeAttributes(oldAssume.Attributes, skel.Attributes);\n                body.Add(new AssumeStmt(skel.Tok, skel.EndTok, e, attrs));\n                reporter.Info(MessageSource.RefinementTransformer, c.ConditionEllipsis, Printer.ExprToString(e));\n                i++; j++;\n              }\n\n            } else if (S is IfStmt) {\n              var skel = (IfStmt)S;\n              Contract.Assert(c.ConditionOmitted);\n              var oldIf = oldS as IfStmt;\n              if (oldIf == null) {\n                reporter.Error(MessageSource.RefinementTransformer, cur.Tok, \"if-statement template does not match inherited statement\");\n                i++;\n              } else {\n                var resultingThen = MergeBlockStmt(skel.Thn, oldIf.Thn);\n                var resultingElse = MergeElse(skel.Els, oldIf.Els);\n                var e = refinementCloner.CloneExpr(oldIf.Guard);\n                var r = new IfStmt(skel.Tok, skel.EndTok, oldIf.IsBindingGuard, e, resultingThen, resultingElse);\n                body.Add(r);\n                reporter.Info(MessageSource.RefinementTransformer, c.ConditionEllipsis, Printer.GuardToString(oldIf.IsBindingGuard, e));\n                i++; j++;\n              }\n\n            } else if (S is WhileStmt) {\n              var skel = (WhileStmt)S;\n              var oldWhile = oldS as WhileStmt;\n              if (oldWhile == null) {\n                reporter.Error(MessageSource.RefinementTransformer, cur.Tok, \"while-statement template does not match inherited statement\");\n                i++;\n              } else {\n                Expression guard;\n                if (c.ConditionOmitted) {\n                  guard = refinementCloner.CloneExpr(oldWhile.Guard);\n                  reporter.Info(MessageSource.RefinementTransformer, c.ConditionEllipsis, Printer.GuardToString(false, oldWhile.Guard));\n                } else {\n                  if (oldWhile.Guard != null) {\n                    reporter.Error(MessageSource.RefinementTransformer, skel.Guard.tok, \"a skeleton while statement with a guard can only replace a while statement with a non-deterministic guard\");\n                  }\n                  guard = skel.Guard;\n                }\n                // Note, if the loop body is omitted in the skeleton, the parser will have set the loop body to an empty block,\n                // which has the same merging behavior.\n                var r = MergeWhileStmt(skel, oldWhile, guard);\n                body.Add(r);\n                i++; j++;\n              }\n\n            } else if (S is ModifyStmt) {\n              var skel = (ModifyStmt)S;\n              Contract.Assert(c.ConditionOmitted);\n              var oldModifyStmt = oldS as ModifyStmt;\n              if (oldModifyStmt == null) {\n                reporter.Error(MessageSource.RefinementTransformer, cur.Tok, \"modify template does not match inherited statement\");\n                i++;\n              } else {\n                var mod = refinementCloner.CloneSpecFrameExpr(oldModifyStmt.Mod);\n                BlockStmt mbody;\n                if (oldModifyStmt.Body == null && skel.Body == null) {\n                  mbody = null;\n                } else if (oldModifyStmt.Body == null) {\n                  mbody = skel.Body;\n                } else if (skel.Body == null) {\n                  reporter.Error(MessageSource.RefinementTransformer, cur.Tok, \"modify template must have a body if the inherited modify statement does\");\n                  mbody = null;\n                } else {\n                  mbody = MergeBlockStmt(skel.Body, oldModifyStmt.Body);\n                }\n                body.Add(new ModifyStmt(skel.Tok, skel.EndTok, mod.Expressions, mod.Attributes, mbody));\n                reporter.Info(MessageSource.RefinementTransformer, c.ConditionEllipsis, Printer.FrameExprListToString(mod.Expressions));\n                i++; j++;\n              }\n\n            } else {\n              Contract.Assume(false);  // unexpected skeleton statement\n            }\n\n          } else if (cur is AssertStmt) {\n            MergeAddStatement(cur, body);\n            i++;\n\n          } else if (cur is VarDeclStmt) {\n            var cNew = (VarDeclStmt)cur;\n            bool doMerge = false;\n            Expression addedAssert = null;\n            if (oldS is VarDeclStmt) {\n              var cOld = (VarDeclStmt)oldS;\n              if (LocalVarsAgree(cOld.Locals, cNew.Locals)) {\n                var update = cNew.Update as UpdateStmt;\n                if (update != null && update.Rhss.TrueForAll(rhs => !rhs.CanAffectPreviouslyKnownExpressions)) {\n                  // Note, we allow switching between ghost and non-ghost, since that seems unproblematic.\n                  if (cOld.Update == null) {\n                    doMerge = true;\n                  } else if (cOld.Update is AssignSuchThatStmt) {\n                    doMerge = true;\n                    addedAssert = refinementCloner.CloneExpr(((AssignSuchThatStmt)cOld.Update).Expr);\n                  } else {\n                    var updateOld = (UpdateStmt)cOld.Update;  // if cast fails, there are more ConcreteUpdateStatement subclasses than expected\n                    doMerge = true;\n                    foreach (var rhs in updateOld.Rhss) {\n                      if (!(rhs is HavocRhs))\n                        doMerge = false;\n                    }\n                  }\n                }\n              }\n            }\n            if (doMerge) {\n              // Go ahead with the merge:\n              body.Add(cNew);\n              i++; j++;\n              if (addedAssert != null) {\n                var tok = new Translator.ForceCheckToken(addedAssert.tok);\n                body.Add(new AssertStmt(tok, tok, addedAssert, null, null, null));\n              }\n            } else {\n              MergeAddStatement(cur, body);\n              i++;\n            }\n\n          } else if (cur is AssignStmt) {\n            var cNew = (AssignStmt)cur;\n            var cOld = oldS as AssignStmt;\n            if (cOld == null && oldS is UpdateStmt) {\n              var us = (UpdateStmt)oldS;\n              if (us.ResolvedStatements.Count == 1) {\n                cOld = us.ResolvedStatements[0] as AssignStmt;\n              }\n            }\n            bool doMerge = false;\n            if (cOld != null && cNew.Lhs.WasResolved() && cOld.Lhs.WasResolved()) {\n              var newLhs = cNew.Lhs.Resolved as IdentifierExpr;\n              var oldLhs = cOld.Lhs.Resolved as IdentifierExpr;\n              if (newLhs != null && oldLhs != null && newLhs.Name == oldLhs.Name) {\n                if (!(cNew.Rhs is TypeRhs) && cOld.Rhs is HavocRhs) {\n                  doMerge = true;\n                }\n              }\n            }\n            if (doMerge) {\n              // Go ahead with the merge:\n              body.Add(cNew);\n              i++; j++;\n            } else {\n              MergeAddStatement(cur, body);\n              i++;\n            }\n\n          } else if (cur is UpdateStmt) {\n            var nw = (UpdateStmt)cur;\n            List<Statement> stmtGenerated = new List<Statement>();\n            bool doMerge = false;\n            if (oldS is UpdateStmt) {\n              var s = (UpdateStmt)oldS;\n              if (LeftHandSidesAgree(s.Lhss, nw.Lhss)) {\n                doMerge = true;\n                stmtGenerated.Add(nw);\n                foreach (var rhs in s.Rhss) {\n                  if (!(rhs is HavocRhs))\n                    doMerge = false;\n                }\n              }\n            } else if (oldS is AssignSuchThatStmt) {\n              var s = (AssignSuchThatStmt)oldS;\n              if (LeftHandSidesAgree(s.Lhss, nw.Lhss)) {\n                doMerge = true;\n                stmtGenerated.Add(nw);\n                var addedAssert = refinementCloner.CloneExpr(s.Expr);\n                var tok = new Translator.ForceCheckToken(addedAssert.tok);\n                stmtGenerated.Add(new AssertStmt(tok, tok, addedAssert, null, null, null));\n              }\n            }\n            if (doMerge) {\n              // Go ahead with the merge:\n              Contract.Assert(cce.NonNullElements(stmtGenerated));\n              body.AddRange(stmtGenerated);\n              i++; j++;\n            } else {\n              MergeAddStatement(cur, body);\n              i++;\n            }\n          } else if (cur is IfStmt) {\n            var cNew = (IfStmt)cur;\n            var cOld = oldS as IfStmt;\n            if (cOld != null && cOld.Guard == null) {\n              var r = new IfStmt(cNew.Tok, cNew.EndTok, cNew.IsBindingGuard, cNew.Guard, MergeBlockStmt(cNew.Thn, cOld.Thn), MergeElse(cNew.Els, cOld.Els));\n              body.Add(r);\n              i++; j++;\n            } else {\n              MergeAddStatement(cur, body);\n              i++;\n            }\n\n          } else if (cur is WhileStmt) {\n            var cNew = (WhileStmt)cur;\n            var cOld = oldS as WhileStmt;\n            if (cOld != null && cOld.Guard == null) {\n              var r = MergeWhileStmt(cNew, cOld, cNew.Guard);\n              body.Add(r);\n              i++; j++;\n            } else {\n              MergeAddStatement(cur, body);\n              i++;\n            }\n\n          } else if (cur is BlockStmt) {\n            var cNew = (BlockStmt)cur;\n            var cOld = oldS as BlockStmt;\n            if (cOld != null) {\n              var r = MergeBlockStmt(cNew, cOld);\n              body.Add(r);\n              i++; j++;\n            } else {\n              MergeAddStatement(cur, body);\n              i++;\n            }\n          } else {\n            MergeAddStatement(cur, body);\n            i++;\n          }\n        }\n      }\n      // implement the implicit \"...;\" at the end of each block statement skeleton\n      var sep = \"\";\n      for (; j < oldStmt.Count; j++) {\n        var b = oldStmt[j];\n        body.Add(refinementCloner.CloneStmt(b));\n        hoverText += sep + Printer.StatementToString(b);\n        sep = \"\\n\";\n      }\n      return body;\n    }\n\n    private bool LeftHandSidesAgree(List<Expression> old, List<Expression> nw) {\n      if (old.Count != nw.Count)\n        return false;\n      for (int i = 0; i < old.Count; i++) {\n        var a = old[i].WasResolved() ? old[i].Resolved as IdentifierExpr : null;\n        var b = nw[i] as NameSegment;\n        if (a != null && b != null && a.Name == b.Name) {\n          // cool\n        } else {\n          return false;\n        }\n      }\n      return true;\n    }\n    private bool LocalVarsAgree(List<LocalVariable> old, List<LocalVariable> nw) {\n      if (old.Count != nw.Count)\n        return false;\n      for (int i = 0; i < old.Count; i++) {\n        if (old[i].Name != nw[i].Name)\n          return false;\n      }\n      return true;\n    }\n\n    bool PotentialMatch(Statement nxt, Statement other) {\n      Contract.Requires(nxt != null);\n      Contract.Requires(!(nxt is SkeletonStatement) || ((SkeletonStatement)nxt).S != null);  // nxt is not \"...;\"\n      Contract.Requires(other != null);\n\n      if (nxt.Labels != null) {\n        for (var olbl = other.Labels; olbl != null; olbl = olbl.Next) {\n          var odata = olbl.Data;\n          for (var l = nxt.Labels; l != null; l = l.Next) {\n            if (odata.Name == l.Data.Name) {\n              return true;\n            }\n          }\n        }\n        return false;  // labels of 'nxt' don't match any label of 'other'\n      } else  if (nxt is SkeletonStatement) {\n        var S = ((SkeletonStatement)nxt).S;\n        if (S is AssertStmt) {\n          return other is PredicateStmt;\n        } else if (S is AssumeStmt) {\n          return other is AssumeStmt;\n        } else if (S is IfStmt) {\n          return other is IfStmt;\n        } else if (S is WhileStmt) {\n          return other is WhileStmt;\n        } else if (S is ModifyStmt) {\n          return other is ModifyStmt;\n        } else {\n          Contract.Assume(false);  // unexpected skeleton\n        }\n\n      } else if (nxt is IfStmt) {\n        var oth = other as IfStmt;\n        return oth != null && oth.Guard == null;\n      } else if (nxt is WhileStmt) {\n        var oth = other as WhileStmt;\n        return oth != null && oth.Guard == null;\n      } else if (nxt is VarDeclStmt) {\n        var oth = other as VarDeclStmt;\n        return oth != null && LocalVarsAgree(((VarDeclStmt)nxt).Locals, oth.Locals);\n      } else if (nxt is BlockStmt) {\n        var b = (BlockStmt)nxt;\n        if (b.Labels != null) {\n          var oth = other as BlockStmt;\n          if (oth != null && oth.Labels != null) {\n            return b.Labels.Data.Name == oth.Labels.Data.Name; // both have the same label\n          }\n        } else if (other is BlockStmt && ((BlockStmt)other).Labels == null) {\n          return true; // both are unlabeled\n        }\n      } else if (nxt is UpdateStmt) {\n        var up = (UpdateStmt)nxt;\n        if (other is AssignSuchThatStmt) {\n          var oth = other as AssignSuchThatStmt;\n          return oth != null && LeftHandSidesAgree(oth.Lhss, up.Lhss);\n        }\n      }\n\n      // not a potential match\n      return false;\n    }\n\n    WhileStmt MergeWhileStmt(WhileStmt cNew, WhileStmt cOld, Expression guard) {\n      Contract.Requires(cNew != null);\n      Contract.Requires(cOld != null);\n\n      // Note, the parser produces errors if there are any decreases or modifies clauses (and it creates\n      // the Specification structures with a null list).\n      Contract.Assume(cNew.Mod.Expressions == null);\n\n      Specification<Expression> decr;\n      if (cNew.Decreases.Expressions.Count == 0) {\n        // inherited whatever the previous loop used\n        decr = refinementCloner.CloneSpecExpr(cOld.Decreases);\n      } else {\n        if (!Contract.Exists(cOld.Decreases.Expressions, e => e is WildcardExpr)) {\n          // If the previous loop was not specified with \"decreases *\", then the new loop is not allowed to provide any \"decreases\" clause.\n          reporter.Error(MessageSource.RefinementTransformer, cNew.Decreases.Expressions[0].tok, \"a refining loop can provide a decreases clause only if the loop being refined was declared with 'decreases *'\");\n        }\n        decr = cNew.Decreases;\n      }\n\n      var invs = cOld.Invariants.ConvertAll(refinementCloner.CloneMayBeFreeExpr);\n      invs.AddRange(cNew.Invariants);\n      var r = new RefinedWhileStmt(cNew.Tok, cNew.EndTok, guard, invs, decr, refinementCloner.CloneSpecFrameExpr(cOld.Mod), MergeBlockStmt(cNew.Body, cOld.Body));\n      return r;\n    }\n\n    Statement MergeElse(Statement skeleton, Statement oldStmt) {\n      Contract.Requires(skeleton == null || skeleton is BlockStmt || skeleton is IfStmt || skeleton is SkeletonStatement);\n      Contract.Requires(oldStmt == null || oldStmt is BlockStmt || oldStmt is IfStmt || oldStmt is SkeletonStatement);\n\n      if (skeleton == null) {\n        return refinementCloner.CloneStmt(oldStmt);\n      } else if (skeleton is IfStmt || skeleton is SkeletonStatement) {\n        // wrap a block statement around the if statement\n        skeleton = new BlockStmt(skeleton.Tok, skeleton.EndTok, new List<Statement>() { skeleton });\n      }\n\n      if (oldStmt == null) {\n        // make it into an empty block statement\n        oldStmt = new BlockStmt(skeleton.Tok, skeleton.EndTok, new List<Statement>());\n      } else if (oldStmt is IfStmt || oldStmt is SkeletonStatement) {\n        // wrap a block statement around the if statement\n        oldStmt = new BlockStmt(oldStmt.Tok, skeleton.EndTok, new List<Statement>() { oldStmt });\n      }\n\n      Contract.Assert(skeleton is BlockStmt && oldStmt is BlockStmt);\n      return MergeBlockStmt((BlockStmt)skeleton, (BlockStmt)oldStmt);\n    }\n\n    /// <summary>\n    /// Add \"s\" to \"stmtList\", but complain if \"s\" contains further occurrences of \"...\", if \"s\" assigns to a\n    /// variable that was not declared in the refining module, or if \"s\" has some control flow that jumps to a\n    /// place outside \"s\".\n    /// </summary>\n    void MergeAddStatement(Statement s, List<Statement> stmtList) {\n      Contract.Requires(s != null);\n      Contract.Requires(stmtList != null);\n      var prevErrorCount = reporter.Count(ErrorLevel.Error);\n      CheckIsOkayNewStatement(s, new Stack<string>(), 0);\n      if (reporter.Count(ErrorLevel.Error) == prevErrorCount) {\n        stmtList.Add(s);\n      }\n    }\n\n    /// <summary>\n    /// See comment on MergeAddStatement.\n    /// </summary>\n    void CheckIsOkayNewStatement(Statement s, Stack<string> labels, int loopLevels) {\n      Contract.Requires(s != null);\n      Contract.Requires(labels != null);\n      Contract.Requires(0 <= loopLevels);\n\n      for (LList<Label> n = s.Labels; n != null; n = n.Next) {\n        labels.Push(n.Data.Name);\n      }\n      if (s is SkeletonStatement) {\n        reporter.Error(MessageSource.RefinementTransformer, s, \"skeleton statement may not be used here; it does not have a matching statement in what is being replaced\");\n      } else if (s is ReturnStmt) {\n        // allow return statements, but make note of that this requires verifying the postcondition\n        ((ReturnStmt)s).ReverifyPost = true;\n      } else if (s is YieldStmt) {\n        reporter.Error(MessageSource.RefinementTransformer, s, \"yield statements are not allowed in skeletons\");\n      } else if (s is BreakStmt) {\n        var b = (BreakStmt)s;\n        if (b.TargetLabel != null ? !labels.Contains(b.TargetLabel) : loopLevels < b.BreakCount) {\n          reporter.Error(MessageSource.RefinementTransformer, s, \"break statement in skeleton is not allowed to break outside the skeleton fragment\");\n        }\n      } else if (s is AssignStmt) {\n        // TODO: To be a refinement automatically (that is, without any further verification), only variables and fields defined\n        // in this module are allowed.  This needs to be checked.  If the LHS refers to an l-value that was not declared within\n        // this module, then either an error should be reported or the Translator needs to know to translate new proof obligations.\n        var a = (AssignStmt)s;\n        reporter.Error(MessageSource.RefinementTransformer, a.Tok, \"cannot have assignment statement\");\n      } else if (s is ConcreteUpdateStatement) {\n        postTasks.Enqueue(() =>\n        {\n          CheckIsOkayUpdateStmt((ConcreteUpdateStatement)s, moduleUnderConstruction);\n        });\n      } else if (s is CallStmt) {\n        reporter.Error(MessageSource.RefinementTransformer, s.Tok, \"cannot have call statement\");\n      } else {\n        if (s is WhileStmt || s is AlternativeLoopStmt) {\n          loopLevels++;\n        }\n        foreach (var ss in s.SubStatements) {\n          CheckIsOkayNewStatement(ss, labels, loopLevels);\n        }\n      }\n\n      for (LList<Label> n = s.Labels; n != null; n = n.Next) {\n        labels.Pop();\n      }\n    }\n\n    // Checks that statement stmt, defined in the constructed module m, is a refinement of skip in the parent module\n    void CheckIsOkayUpdateStmt(ConcreteUpdateStatement stmt, ModuleDefinition m) {\n      foreach (var lhs in stmt.Lhss) {\n        var l = lhs.Resolved;\n        if (l is IdentifierExpr) {\n          var ident = (IdentifierExpr)l;\n          Contract.Assert(ident.Var is LocalVariable || ident.Var is Formal); // LHS identifier expressions must be locals or out parameters (ie. formals)\n          if ((ident.Var is LocalVariable && RefinementToken.IsInherited(((LocalVariable)ident.Var).Tok, m)) || ident.Var is Formal) {\n            // for some reason, formals are not considered to be inherited.\n            reporter.Error(MessageSource.RefinementTransformer, l.tok, \"refinement method cannot assign to variable defined in parent module ('{0}')\", ident.Var.Name);\n          }\n        } else if (l is MemberSelectExpr) {\n          var member = ((MemberSelectExpr)l).Member;\n          if (RefinementToken.IsInherited(member.tok, m)) {\n            reporter.Error(MessageSource.RefinementTransformer, l.tok, \"refinement method cannot assign to a field defined in parent module ('{0}')\", member.Name);\n          }\n        } else {\n          // must be an array element\n          reporter.Error(MessageSource.RefinementTransformer, l.tok, \"new assignments in a refinement method can only assign to state that the module defines (which never includes array elements)\");\n        }\n      }\n      if (stmt is UpdateStmt) {\n        var s = (UpdateStmt)stmt;\n        foreach (var rhs in s.Rhss) {\n          if (rhs.CanAffectPreviouslyKnownExpressions) {\n            reporter.Error(MessageSource.RefinementTransformer, rhs.Tok, \"assignment RHS in refinement method is not allowed to affect previously defined state\");\n          }\n        }\n      }\n    }\n    // ---------------------- additional methods -----------------------------------------------------------------------------\n\n    public static bool ContainsChange(Expression expr, ModuleDefinition m) {\n      Contract.Requires(expr != null);\n      Contract.Requires(m != null);\n\n      if (expr is FunctionCallExpr) {\n        var e = (FunctionCallExpr)expr;\n        if (e.Function.EnclosingClass.Module == m) {\n          var p = e.Function as Predicate;\n          if (p != null && p.BodyOrigin == Predicate.BodyOriginKind.Extension) {\n            return true;\n          }\n        }\n      }\n\n      foreach (var ee in expr.SubExpressions) {\n        if (ContainsChange(ee, m)) {\n          return true;\n        }\n      }\n      return false;\n    }\n  }\n\n  class RefinementCloner : Cloner {\n    ModuleDefinition moduleUnderConstruction;\n    public RefinementCloner(ModuleDefinition m) {\n      moduleUnderConstruction = m;\n    }\n    public override BlockStmt CloneMethodBody(Method m) {\n      if (m.BodyForRefinement is DividedBlockStmt) {\n        return CloneDividedBlockStmt((DividedBlockStmt)m.BodyForRefinement);\n      } else {\n        return CloneBlockStmt(m.BodyForRefinement);\n      }\n    }\n    public override IToken Tok(IToken tok) {\n      return new RefinementToken(tok, moduleUnderConstruction);\n    }\n    public override TopLevelDecl CloneDeclaration(TopLevelDecl d, ModuleDefinition m) {\n      var dd = base.CloneDeclaration(d, m);\n      if (dd is ModuleExportDecl) {\n        ((ModuleExportDecl)dd).SetupDefaultSignature();\n      } else if (d is ModuleDecl) {\n        ((ModuleDecl)dd).Signature = ((ModuleDecl)d).Signature;\n        if (d is ModuleFacadeDecl) {\n          ((ModuleFacadeDecl)dd).OriginalSignature = ((ModuleFacadeDecl)d).OriginalSignature;\n        }\n      }\n      return dd;\n    }\n    public virtual Attributes MergeAttributes(Attributes prevAttrs, Attributes moreAttrs) {\n      if (moreAttrs == null) {\n        return CloneAttributes(prevAttrs);\n      } else if (moreAttrs is UserSuppliedAttributes) {\n        var usa = (UserSuppliedAttributes)moreAttrs;\n        return new UserSuppliedAttributes(Tok(usa.tok), Tok(usa.OpenBrace), Tok(usa.CloseBrace), moreAttrs.Args.ConvertAll(CloneExpr), MergeAttributes(prevAttrs, moreAttrs.Prev));\n      } else {\n        return new Attributes(moreAttrs.Name, moreAttrs.Args.ConvertAll(CloneExpr), MergeAttributes(prevAttrs, moreAttrs.Prev));\n      }\n    }\n  }\n  class SubstitutionCloner : Cloner {\n    public Dictionary<string, Expression> Exprs;\n    public SortedSet<string> SubstitutionsMade;\n    Cloner c;\n    public SubstitutionCloner(Dictionary<string, Expression> subs, Cloner c) {\n      Exprs = subs;\n      SubstitutionsMade = new SortedSet<string>();\n      this.c = c;\n    }\n    public override Expression CloneExpr(Expression expr) {\n      if (expr is NamedExpr) {\n        NamedExpr n = (NamedExpr)expr;\n        Expression E;\n        if (Exprs.TryGetValue(n.Name, out E)) {\n          SubstitutionsMade.Add(n.Name);\n          return new NamedExpr(n.tok, n.Name, E, c.CloneExpr(n.Body), E.tok);\n        }\n      }\n      return base.CloneExpr(expr); // in all other cases, just do what the base class would.\n                                   // note that when we get a named expression that is not in\n                                   // our substitution list, then we call the base class, which\n                                   // recurses on the body of the named expression.\n    }\n  }\n}\n"
  },
  {
    "path": "Source/Armada/Reporting.cs",
    "content": "using Microsoft.Boogie;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text;\n\nnamespace Microsoft.Armada {\n  public enum ErrorLevel {\n    Info, Warning, Error\n  }\n\n  public enum MessageSource {\n    Parser, Resolver, Translator, Rewriter, Other,\n    RefinementTransformer,\n    Cloner,\n    Compiler\n  }\n\n  public struct ErrorMessage {\n    public IToken token;\n    public string message;\n    public MessageSource source;\n  }\n\n  public abstract class ErrorReporter {\n    public bool ErrorsOnly { get; set; }\n    public Dictionary<ErrorLevel, List<ErrorMessage>> AllMessages { get; private set; }\n\n    protected ErrorReporter() {\n      ErrorsOnly = false;\n      AllMessages = new Dictionary<ErrorLevel, List<ErrorMessage>>();\n      AllMessages[ErrorLevel.Error] = new List<ErrorMessage>();\n      AllMessages[ErrorLevel.Warning] = new List<ErrorMessage>();\n      AllMessages[ErrorLevel.Info] = new List<ErrorMessage>();\n    }\n\n    // This is the only thing that needs to be overriden\n    public virtual bool Message(MessageSource source, ErrorLevel level, IToken tok, string msg) {\n      bool discard = (ErrorsOnly && level != ErrorLevel.Error) || // Discard non-errors if ErrorsOnly is set\n                     (tok is TokenWrapper && !(tok is IncludeToken) && !(tok is NestedToken) && !(tok is RefinementToken)); // Discard wrapped tokens, except for included, nested and refinement\n      if (!discard) {\n        AllMessages[level].Add(new ErrorMessage { token = tok, message = msg });\n      }\n      return !discard;\n    }\n\n    public int Count(ErrorLevel level) {\n      return AllMessages[level].Count;\n    }\n\n    public void Error(MessageSource source, IToken tok, string msg) {\n      Contract.Requires(tok != null);\n      Contract.Requires(msg != null);\n      // if the tok is IncludeToken, we need to indicate to the including file\n      // that there are errors in the included file.\n      if (tok is IncludeToken) {\n        IncludeToken includeToken = (IncludeToken) tok;\n        Include include = includeToken.Include;\n        if (!include.ErrorReported) {\n          Message(source, ErrorLevel.Error, include.tok, \"the included file \" + tok.filename + \" contains error(s)\");\n          include.ErrorReported = true;\n        }\n      }\n      Message(source, ErrorLevel.Error, tok, msg);\n    }\n\n    // This method required by the Parser\n    internal void Error(MessageSource source, string filename, int line, int col, string msg) {\n      var tok = new Token(line, col);\n      tok.filename = filename;\n      Error(source, tok, msg);\n    }\n\n    public void Error(MessageSource source, IToken tok, string msg, params object[] args) {\n      Contract.Requires(tok != null);\n      Contract.Requires(msg != null);\n      Contract.Requires(args != null);\n      Error(source, tok, String.Format(msg, args));\n    }\n\n    public void Error(MessageSource source, Declaration d, string msg, params object[] args) {\n      Contract.Requires(d != null);\n      Contract.Requires(msg != null);\n      Contract.Requires(args != null);\n      Error(source, d.tok, msg, args);\n    }\n\n    public void Error(MessageSource source, Statement s, string msg, params object[] args) {\n      Contract.Requires(s != null);\n      Contract.Requires(msg != null);\n      Contract.Requires(args != null);\n      Error(source, s.Tok, msg, args);\n    }\n\n    public void Error(MessageSource source, IVariable v, string msg, params object[] args) {\n      Contract.Requires(v != null);\n      Contract.Requires(msg != null);\n      Contract.Requires(args != null);\n      Error(source, v.Tok, msg, args);\n    }\n\n    public void Error(MessageSource source, Expression e, string msg, params object[] args) {\n      Contract.Requires(e != null);\n      Contract.Requires(msg != null);\n      Contract.Requires(args != null);\n      Error(source, e.tok, msg, args);\n    }\n\n    public void Warning(MessageSource source, IToken tok, string msg) {\n      Contract.Requires(tok != null);\n      Contract.Requires(msg != null);\n      Message(source, ErrorLevel.Warning, tok, msg);\n    }\n\n    public void Deprecated(MessageSource source, IToken tok, string msg, params object[] args) {\n      Contract.Requires(tok != null);\n      Contract.Requires(msg != null);\n      Contract.Requires(args != null);\n      if (ArmadaOptions.O.DeprecationNoise != 0) {\n        Warning(source, tok, String.Format(msg, args));\n      }\n    }\n    public void DeprecatedStyle(MessageSource source, IToken tok, string msg, params object[] args) {\n      Contract.Requires(tok != null);\n      Contract.Requires(msg != null);\n      Contract.Requires(args != null);\n      if (ArmadaOptions.O.DeprecationNoise == 2) {\n        Warning(source, tok, String.Format(msg, args));\n      }\n    }\n\n    public void Warning(MessageSource source, IToken tok, string msg, params object[] args) {\n      Contract.Requires(tok != null);\n      Contract.Requires(msg != null);\n      Contract.Requires(args != null);\n      Warning(source, tok, String.Format(msg, args));\n    }\n\n    public void Info(MessageSource source, IToken tok, string msg) {\n      Contract.Requires(tok != null);\n      Contract.Requires(msg != null);\n      Message(source, ErrorLevel.Info, tok, msg);\n    }\n\n    public void Info(MessageSource source, IToken tok, string msg, params object[] args) {\n      Contract.Requires(tok != null);\n      Contract.Requires(msg != null);\n      Contract.Requires(args != null);\n      Info(source, tok, String.Format(msg, args));\n    }\n\n    public static string ErrorToString(ErrorLevel header, IToken tok, string msg) {\n      return String.Format(\"{0}: {1}{2}\", TokenToString(tok), header.ToString(), \": \" + msg);\n    }\n\n    public static string TokenToString(IToken tok) {\n      return String.Format(\"{0}({1},{2})\", tok.filename, tok.line, tok.col - 1);\n    }\n  }\n\n  public class ConsoleErrorReporter : ErrorReporter {\n    private ConsoleColor ColorForLevel(ErrorLevel level) {\n      switch (level) {\n        case ErrorLevel.Error:\n          return ConsoleColor.Red;\n        case ErrorLevel.Warning:\n          return ConsoleColor.Yellow;\n        case ErrorLevel.Info:\n          return ConsoleColor.Green;\n        default:\n          throw new cce.UnreachableException();\n      }\n    }\n\n    public override bool Message(MessageSource source, ErrorLevel level, IToken tok, string msg) {\n      if (base.Message(source, level, tok, msg) && ((ArmadaOptions.O != null && ArmadaOptions.O.PrintTooltips) || level != ErrorLevel.Info)) {\n        // Extra indent added to make it easier to distinguish multiline error messages for clients that rely on the CLI\n        msg = msg.Replace(Environment.NewLine, Environment.NewLine + \" \");\n\n        ConsoleColor previousColor = Console.ForegroundColor;\n        Console.ForegroundColor = ColorForLevel(level);\n        Console.WriteLine(ErrorToString(level, tok, msg));\n        Console.ForegroundColor = previousColor;\n        return true;\n      } else {\n        return false;\n      }\n    }\n  }\n\n  public class ErrorReporterSink : ErrorReporter {\n    public ErrorReporterSink() {}\n\n    public override bool Message(MessageSource source, ErrorLevel level, IToken tok, string msg) {\n      return false;\n    }\n  }\n\n  public class ErrorReporterWrapper : ErrorReporter {\n\n    private string msgPrefix;\n    public readonly ErrorReporter WrappedReporter;\n\n    public ErrorReporterWrapper(ErrorReporter reporter, string msgPrefix) {\n      this.msgPrefix = msgPrefix;\n      this.WrappedReporter = reporter;\n    }\n\n    public override bool Message(MessageSource source, ErrorLevel level, IToken tok, string msg) {\n      base.Message(source, level, tok, msg);\n      return WrappedReporter.Message(source, level, tok, msgPrefix + msg);\n    }\n  }\n}\n"
  },
  {
    "path": "Source/Armada/ResolutionContext.cs",
    "content": "using System;\nusing System.Numerics;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text;\nusing static Microsoft.Armada.Predicate;\nusing IToken = Microsoft.Boogie.IToken;\nusing Token = Microsoft.Boogie.Token;\n\nnamespace Microsoft.Armada {\n\n  public class ResolutionContext\n  {\n    private readonly string lvalueState;\n    private readonly string rvalueState;\n    public readonly string tid;\n    public readonly string methodName;\n    public readonly ArmadaSymbolTable symbols;\n    public readonly IFailureReporter failureReporter;\n    public readonly string moduleName;\n\n    public ResolutionContext(string i_lvalueState, string i_rvalueState, string i_tid, string i_methodName,\n                             ArmadaSymbolTable i_symbols, IFailureReporter i_failureReporter, string i_moduleName = null)\n    {\n      lvalueState = i_lvalueState;\n      rvalueState = i_rvalueState;\n      tid = i_tid;\n      methodName = i_methodName;\n      symbols = i_symbols;\n      failureReporter = i_failureReporter;\n      moduleName = i_moduleName;\n    }\n\n    public virtual string GetLValueState()\n    {\n      if (lvalueState == null) {\n        Fail(\"Can't get an lvalue state for this context\");\n      }\n      return lvalueState;\n    }\n\n    public virtual string GetRValueState()\n    {\n      if (rvalueState == null) {\n        Fail(\"Can't get an rvalue state for this context\");\n      }\n      return rvalueState;\n    }\n\n    public virtual string GetLValueTopStackFrame()\n    {\n      if (lvalueState == null) {\n        Fail(\"Can't get an lvalue state for this context\");\n        return null;\n      }\n      if (tid == null) {\n        Fail(\"No thread defined in this context, so can't determine top stack frame\");\n        return null;\n      }\n      return $\"({lvalueState}).threads[{tid}].top\";\n    }\n\n    public virtual string GetRValueHeap()\n    {\n      if (rvalueState == null) {\n        Fail(\"Can't get an rvalue state for this context\");\n        return null;\n      }\n      if (tid == null) {\n        Fail(\"No thread defined in this context, so can't determine local view of heap\");\n        return null;\n      }\n      var fnName = AH.AddModuleToIdentifier(moduleName, \"Armada_GetThreadLocalView\");\n      return $\"{fnName}({rvalueState}, {tid}).heap\";\n    }\n\n    public virtual string GetRValueGlobals()\n    {\n      if (rvalueState == null) {\n        Fail(\"Can't get an rvalue state for this context\");\n        return null;\n      }\n      if (tid == null) {\n        Fail(\"No thread defined in this context, so can't determine local view of globals\");\n        return null;\n      }\n      var fnName = AH.AddModuleToIdentifier(moduleName, \"Armada_GetThreadLocalView\");\n      return $\"{fnName}({rvalueState}, {tid}).globals\";\n    }\n\n    public virtual string GetRValueGhosts()\n    {\n      if (rvalueState == null) {\n        Fail(\"Can't get an rvalue state for this context\");\n        return null;\n      }\n      return $\"({rvalueState}).ghosts\";\n    }\n\n    public virtual string GetRValueTopStackFrame()\n    {\n      if (rvalueState == null) {\n        Fail(\"Can't get an rvalue state for this context\");\n        return null;\n      }\n      if (tid == null) {\n        Fail(\"No thread defined in this context, so can't determine top stack frame\");\n        return null;\n      }\n      return $\"({rvalueState}).threads[{tid}].top\";\n    }\n\n    public virtual ArmadaRValue ResolveAsOldRValue(IToken tok, Expression expr)\n    {\n      Fail(tok, \"Can't use old() expression in this context\");\n      return null;\n    }\n\n    public virtual ArmadaRValue ResolveAsMemoryRValue(IToken tok, Expression expr)\n    {\n      var subcontext = new GlobalViewResolutionContext(rvalueState, tid, methodName, symbols, failureReporter, moduleName);\n      return subcontext.ResolveAsRValue(expr);\n    }\n\n    public void Fail(IToken tok, string reason) { failureReporter.Fail(tok, reason); }\n    public void Fail(string reason) { failureReporter.Fail(reason); }\n\n    public ArmadaRValue ResolveArmadaBinaryExpr(IToken tok, Type targetType, BinaryExpr.Opcode op,\n                                                ArmadaRValue operand1, ArmadaRValue operand2,\n                                                Type operand1Type, Type operand2Type)\n    {\n      UndefinedBehaviorAvoidanceConstraint crashAvoidance = operand1.UndefinedBehaviorAvoidance + operand2.UndefinedBehaviorAvoidance;\n\n      // If this is a pointer plus or minus an integer, the semantics is that it produces undefined behavior unless\n      // it stays within an array.\n\n      if ((op == BinaryExpr.Opcode.Add || op == BinaryExpr.Opcode.Sub) && operand1Type is PointerType) {\n        var pt = (PointerType)operand1Type;\n\n        // operand1 in h.valid\n        var h = GetRValueHeap();\n        var operand1_valid = $\"({operand1.Val}) in ({h}).valid\";\n        crashAvoidance.Add(operand1_valid);\n\n        // operand1 in h.tree\n        var tree = $\"({h}).tree\";\n        var operand1_in_tree = $\"{operand1.Val} in {tree}\";\n        crashAvoidance.Add(operand1_in_tree);\n\n        // tree[operand1].child_type.Armada_ChildTypeIndex?\n        // (in other words, operand1 must be a child of its parent via an index field)\n        var is_field_array_index = $\"{tree}[{operand1.Val}].child_type.Armada_ChildTypeIndex?\";\n        crashAvoidance.Add(is_field_array_index);\n\n        // tree[operand1].parent in h.tree\n        var parent = $\"{tree}[{operand1.Val}].parent\";\n        crashAvoidance.Add($\"{parent} in {tree}\");\n\n        // 0 <= (child_type.i <op> operand2) < |tree[operand1.parent].children|\n        var operand2val = AH.ConvertToIntIfNotInt(operand2.Val, operand2Type);\n        var updated_index = $\"{tree}[{operand1.Val}].child_type.i {BinaryExpr.OpcodeString(op)} {operand2val}\";\n        crashAvoidance.Add($\"0 <= {updated_index} < |{tree}[{parent}].children|\");\n\n        // return tree[operand1.parent].children[child_type.i {op} operand2]\n        return new ArmadaRValue(crashAvoidance, $\"{tree}[{parent}].children[{updated_index}]\");\n      }\n\n      // Order-based comparison of pointers is only allowed when they're in the same array.  The semantics for such a\n      // comparison is that their indices within that array have the given comparison relationship.\n\n      if ((op == BinaryExpr.Opcode.Lt || op == BinaryExpr.Opcode.Le || op == BinaryExpr.Opcode.Gt || op == BinaryExpr.Opcode.Ge) &&\n          (operand1Type is PointerType || operand2Type is PointerType))\n      {\n        if (!AH.TypesMatch(operand1Type, operand2Type)) {\n          Fail(tok, \"Can't compare a pointer to anything except a pointer of the same type\");\n          return null;\n        }\n\n        var h = GetRValueHeap();\n\n        // It's undefined behavior if operand 1 or 2 isn't a valid pointer\n        crashAvoidance.Add($\"({operand1.Val}) in ({h}).valid\");\n        crashAvoidance.Add($\"({operand2.Val}) in ({h}).valid\");\n\n        // It's undefined behavior if operand 1 or 2 isn't in the tree\n        var tree = $\"({h}).tree\";\n        crashAvoidance.Add($\"({operand1.Val}) in {tree}\");\n        crashAvoidance.Add($\"({operand2.Val}) in {tree}\");\n\n        // It's undefined behavior if operand 1 or 2 isn't an array element\n        crashAvoidance.Add($\"{tree}[{operand1.Val}].child_type.Armada_ChildTypeIndex?\");\n        crashAvoidance.Add($\"{tree}[{operand2.Val}].child_type.Armada_ChildTypeIndex?\");\n\n        // It's undefined behavior if operands 1 and 2 don't have the same parent\n        crashAvoidance.Add($\"{tree}[{operand1.Val}].parent == {tree}[{operand2.Val}].parent\");\n\n        // The actual comparison is between the field indices of operands 1 and 2\n        var result = $\"{tree}[{operand1.Val}].child_type.i {BinaryExpr.OpcodeString(op)} {tree}[{operand2.Val}].child_type.i\";\n        return new ArmadaRValue(crashAvoidance, result);\n      }\n\n      if (op == BinaryExpr.Opcode.And) {\n        if (operand2.CanCauseUndefinedBehavior) {\n          crashAvoidance = operand1.UndefinedBehaviorAvoidance + $\"({operand1.Val}) ==> ({operand2.UndefinedBehaviorAvoidance.Expr})\";\n        }\n      }\n      else if (op == BinaryExpr.Opcode.Or) {\n        if (operand2.CanCauseUndefinedBehavior) {\n          crashAvoidance = operand1.UndefinedBehaviorAvoidance + $\"({operand1.Val}) || ({operand2.UndefinedBehaviorAvoidance.Expr})\";\n        }\n      }\n      else if (op == BinaryExpr.Opcode.Imp) {\n        if (operand2.CanCauseUndefinedBehavior) {\n          crashAvoidance = operand1.UndefinedBehaviorAvoidance + $\"({operand1.Val}) ==> ({operand2.UndefinedBehaviorAvoidance.Expr})\";\n        }\n      }\n      else if (op == BinaryExpr.Opcode.Exp) {\n        if (operand1.CanCauseUndefinedBehavior) {\n          crashAvoidance = operand2.UndefinedBehaviorAvoidance + $\"({operand2.Val}) ==> ({operand1.UndefinedBehaviorAvoidance.Expr})\";\n        }\n      }\n      else if (op == BinaryExpr.Opcode.Div) {\n        crashAvoidance.Add($\"({operand2.Val}) != 0\");\n      }\n      else if (op == BinaryExpr.Opcode.Mod) {\n        crashAvoidance.Add($\"({operand2.Val}) != 0\");\n      }\n\n      /*\n        It's undefined behavior to compare the value of a freed pointer (even if you don't dereference that value!)\n        since our model of pointers doesn't capture the possibility of reusing the same location after it's freed.\n\n        For example, consider the following code:\n\n          void BadNews()\n          {\n            var p:ptr<int32>, q:ptr<int32>;\n            p = malloc(int32);\n            free(p);\n            q = malloc(int32);\n            free(q);\n            if (p == q) { // Comparing a freed pointer\n              *p := 0;\n            }\n          }\n\n        If we didn't treat comparing the value of a freed pointer as undefined behavior, we'd model the above code as\n        never crashing.  After all, in our model, pointers are never reused after being freed, so the verification would\n        find p is always different from q, so the guard on the if is always false and the store to *p never happens.  In\n        the compiled code, however, it could happen that the pointer was reused and p is equal to q.  In that case the\n        assignment to *p would occur, and potentially crash.  We don't want the code crashing when verification says it\n        won't, so we have to disallow looking at the values of freed pointers.\n      */\n\n      if (op == BinaryExpr.Opcode.Eq || op == BinaryExpr.Opcode.Neq || op == BinaryExpr.Opcode.Lt || op == BinaryExpr.Opcode.Le ||\n          op == BinaryExpr.Opcode.Gt || op == BinaryExpr.Opcode.Ge || op == BinaryExpr.Opcode.In || op == BinaryExpr.Opcode.NotIn)\n      {\n        var h = GetRValueHeap();\n\n        if (operand1Type is PointerType) {\n          crashAvoidance.Add($\"Armada_ComparablePointer({operand1.Val}, {h})\");\n        }\n        if (operand2Type is PointerType) {\n          crashAvoidance.Add($\"Armada_ComparablePointer({operand2.Val}, {h})\");\n        }\n      }\n\n      // Do appropriate conversions\n\n      if (   op == BinaryExpr.Opcode.BitwiseAnd \n          || op == BinaryExpr.Opcode.BitwiseOr \n          || op == BinaryExpr.Opcode.BitwiseXor\n          || op == BinaryExpr.Opcode.LeftShift\n          || op == BinaryExpr.Opcode.RightShift\n          ) {\n        var name = \"\";\n        if (op == BinaryExpr.Opcode.BitwiseAnd) {\n          name = \"bit_and_uint\";\n        } else if (op == BinaryExpr.Opcode.BitwiseOr) {\n          name = \"bit_or_uint\";\n        } else if (op == BinaryExpr.Opcode.BitwiseXor) {\n          name = \"bit_xor_uint\";\n        } else if (op == BinaryExpr.Opcode.LeftShift) {\n          name = \"bit_lshift_uint\";\n        } else if (op == BinaryExpr.Opcode.RightShift) {\n          name = \"bit_rshift_uint\";\n        }\n        name += AH.GetBitWidth(operand1Type as UserDefinedType);\n        var e = $\"{name}({operand1.Val}, {operand2.Val})\";\n        return new ArmadaRValue(crashAvoidance, e);\n      }\n      // For mathematical expressions, we should treat them as if\n      else if (op == BinaryExpr.Opcode.In || op == BinaryExpr.Opcode.NotIn ||\n               op == BinaryExpr.Opcode.Eq || op == BinaryExpr.Opcode.Neq) {\n        var e = $\"({operand1.Val}) {BinaryExpr.OpcodeString(op)} ({operand2.Val})\";\n        return new ArmadaRValue(crashAvoidance, e);\n      }\n      else {\n        var op1val = AH.ConvertToIntIfLimitedSizeInt(operand1.Val, operand1Type);\n        var op2val = AH.ConvertToIntIfLimitedSizeInt(operand2.Val, operand2Type);\n        var e = $\"({op1val}) {BinaryExpr.OpcodeString(op)} ({op2val})\";\n        e = AH.EnsureIntegerFit(e, new IntType(), targetType);\n        return new ArmadaRValue(crashAvoidance, e);\n      }\n    }\n\n    public ArmadaLValue ResolveArmadaDereferenceExprAsLValue(IToken tok, ArmadaRValue addr, Type targetType)\n    {\n      if (targetType == null) {\n        Fail(tok, \"Attempt to dereference a value whose type isn't known\");\n        return null;\n      }\n\n      return new AddressableArmadaLValue(tok, targetType, addr);\n    }\n\n    public ArmadaRValue ResolveArmadaDereferenceExprAsRValue(IToken tok, ArmadaRValue addr, Type targetType)\n    {\n      if (targetType == null) {\n        Fail(tok, \"Attempt to dereference a value whose type isn't known\");\n        return new ArmadaRValue(null);\n      }\n\n      var h = GetRValueHeap();\n\n      var valid = AH.GetInvocationOfValidPointer(h, addr.Val, targetType);\n      if (valid == null) {\n        Fail(tok, $\"Type {targetType} is not supported on the heap, and thus not for dereference operations\");\n        return new ArmadaRValue(null);\n      }\n      var crashAvoidance = addr.UndefinedBehaviorAvoidance + valid;\n\n      var ret = AH.GetInvocationOfDereferencePointer(h, addr.Val, targetType);\n      if (ret == null) {\n        Fail(tok, $\"Type {targetType} is not supported on the heap, and thus not for dereference operations\");\n      }\n      return new ArmadaRValue(crashAvoidance, ret);\n    }\n\n    public ArmadaRValue ResolveAllocatedExpr(IToken tok, ArmadaRValue addr, Type addrType)\n    {\n      if (addrType == null) {\n        Fail(tok, \"Attempt to determine the allocated-ness of a value whose type isn't known\");\n        return new ArmadaRValue(null);\n      }\n\n      Type subtype;\n      string err;\n      if (!AH.GetDereferenceType(addrType, out subtype, out err)) {\n        Fail(tok, err);\n        return new ArmadaRValue(null);\n      }\n\n      var h = GetRValueHeap();\n\n      var valid = AH.GetInvocationOfValidPointer(h, addr.Val, subtype);\n      if (valid == null) {\n        Fail(tok, $\"Type {subtype} is not supported on the heap, and thus not for allocated() expressions\");\n        return new ArmadaRValue(null);\n      }\n\n      return new ArmadaRValue(addr.UndefinedBehaviorAvoidance, valid);\n    }\n\n    public ArmadaRValue ResolveAllocatedArrayExpr(IToken tok, ArmadaRValue addr, Type addrType)\n    {\n      if (addrType == null) {\n        Fail(tok, \"Attempt to determine the allocated-array-ness of a value whose type isn't known\");\n        return new ArmadaRValue(null);\n      }\n\n      Type subtype;\n      string err;\n      if (!AH.GetDereferenceType(addrType, out subtype, out err)) {\n        Fail(tok, err);\n        return new ArmadaRValue(null);\n      }\n\n      var h = GetRValueHeap();\n\n      var valid = AH.GetInvocationOfValidPointer(h, addr.Val, subtype);\n      if (valid == null) {\n        Fail(tok, $\"Type {subtype} is not supported on the heap, and thus not for allocated_array() expressions\");\n        return new ArmadaRValue(null);\n      }\n\n      var node = $\"({h}).tree[{addr.Val}]\";\n      var is_array_field = $\"{node}.child_type.Armada_ChildTypeIndex?\";\n      var parent_valid = $\"Armada_ValidPointer({h}, {node}.parent)\";\n\n      var res = $\"({valid}) && ({is_array_field}) && ({parent_valid})\";\n\n      return new ArmadaRValue(addr.UndefinedBehaviorAvoidance, res);\n    }\n\n    private string ResolveTriggers(Attributes attrs)\n    {\n      if (attrs == null) {\n        return \"\";\n      }\n\n      var prev_triggers = ResolveTriggers(attrs.Prev);\n\n      if (attrs.Name == \"trigger\") {\n        var rs = ResolveAsRValueList(attrs.Args);\n        var s = String.Join(\", \", rs.Vals);\n        return $\"{prev_triggers} {{:trigger {s}}}\";\n      }\n      else {\n        return prev_triggers;\n      }\n    }\n\n    private UndefinedBehaviorAvoidanceConstraint GetQuantifiedUndefinedBehaviorAvoidanceConstraint(\n      ArmadaRValue range,\n      ArmadaRValue term,\n      List<TypeParameter> typeArgs,\n      List<BoundVar> bvars,\n      Attributes attrs\n      )\n    {\n      string body = null;\n      if (range != null && range.CanCauseUndefinedBehavior) {\n        if (term.CanCauseUndefinedBehavior) {\n          body = $\"({range.UndefinedBehaviorAvoidance.Expr}) && (({range.Val}) ==> ({term.UndefinedBehaviorAvoidance.Expr}))\";\n        }\n        else {\n          body = range.UndefinedBehaviorAvoidance.Expr;\n        }\n      }\n      else if (term.CanCauseUndefinedBehavior) {\n        if (range != null && range.Val != null) {\n          body = $\"({range.Val}) ==> ({term.UndefinedBehaviorAvoidance.Expr})\";\n        }\n        else {\n          body = term.UndefinedBehaviorAvoidance.Expr;\n        }\n      }\n\n      if (body == null) {\n        return new UndefinedBehaviorAvoidanceConstraint();\n      }\n\n      // No matter what kind of quantified expression it is, forall or exists, to avoid crashing it must be true for\n      // all elements in the domain.  So we always use a forall expression, even if the quantifier is an exists.\n      // Note that we don't need to put a range on this forall (i.e., we don't need to say | range ::) because\n      // the restriction to the range is already talked about in the body.\n      \n      var avoidanceExpr = \"forall \"\n                          + String.Join(\", \", bvars.Select(bv => $\"{bv.Name}:{bv.Type.ToString()}\"))\n                          + \" \"\n                          + ResolveTriggers(attrs) // intentionally leave out range, since it's in the body\n                          + \" :: \"\n                          + body;\n      return new UndefinedBehaviorAvoidanceConstraint(avoidanceExpr);\n    }\n\n    public ArmadaLValue ResolveAsLValue(Expression expr)\n    {\n      if (expr == null) {\n        return null;\n      }\n\n      if (expr is ParensExpression) {\n        var e = (ParensExpression)expr;\n        return ResolveAsLValue(e.E);\n      }\n\n      if (expr is NameSegment) {\n        var e = (NameSegment)expr;\n        var av = symbols.Lookup(methodName, e.Name);\n        if (av == null) {\n          return null;\n        }\n        else {\n          return av.GetLValue(e.tok, this);\n        }\n      }\n\n      if (expr is ExprDotName) {\n        var e = (ExprDotName)expr;\n        var newLhs = ResolveAsLValue(e.Lhs);\n        if (newLhs == null) {\n          return null;\n        }\n        return newLhs.ApplyExprDotName(e.tok, this, e.SuffixName, expr.Type);\n      }\n\n      if (expr is SeqSelectExpr) {\n        var e = (SeqSelectExpr)expr;\n        var newSeq = ResolveAsLValue(e.Seq);\n\n        if (newSeq == null) {\n          return null;\n        }\n\n        if (!e.SelectOne) {\n          Fail(expr.tok, \"Can't resolve a slice as an lvalue\");\n        }\n\n        var newE0 = ResolveAsRValue(e.E0);\n        return newSeq.ApplySeqSelect(e.tok, this, newE0, e.E0.Type, expr.Type);\n      }\n\n      if (expr is UnaryOpExpr) {\n        var e = (UnaryOpExpr)expr;\n        if (e.Op == UnaryOpExpr.Opcode.Dereference) {\n          var newE = ResolveAsRValue(e.E);\n          return ResolveArmadaDereferenceExprAsLValue(e.tok, newE, expr.Type);\n        }\n        else {\n          Fail(expr.tok, \"Can't resolve unary-operator expression as an lvalue since it's not the dereference operator (*)\");\n        }\n      }\n\n      Fail(expr.tok, $\"Can't resolve the following expression as an lvalue since it has an unexpected expression type:  {expr}\\n\");\n      return null;\n    }\n\n    public ArmadaRValue ResolveAsRValue(Expression expr)\n    {\n      if (expr == null) {\n        return new ArmadaRValue(null);\n      }\n\n      if (expr is ParensExpression) {\n        var e = (ParensExpression)expr;\n        return ResolveAsRValue(e.E);\n      }\n\n      if (expr is ChainingExpression) {\n        var e = (ChainingExpression)expr;\n        ArmadaRValueList newOperands = ResolveAsRValueList(e.Operands);\n        var newOperandStrings = newOperands.Vals;\n        var crashAvoidance = newOperands.UndefinedBehaviorAvoidance;\n        var val = newOperandStrings[0]\n                + String.Concat(Enumerable.Range(0, e.Operands.Count - 1).Select(i => $\" {BinaryExpr.OpcodeString(e.Operators[i])} ({newOperandStrings[i + 1]})\"));\n        return new ArmadaRValue(crashAvoidance, val);\n      }\n\n      if (expr is NegationExpression) {\n        var e = (NegationExpression)expr;\n        var newE = ResolveAsRValue(e.E);\n        var newEAsInt = AH.ConvertToIntIfLimitedSizeInt(newE.Val, e.E.Type);\n        var val = AH.EnsureIntegerFit($\"-({newEAsInt})\", new IntType(), expr.Type);\n        return new ArmadaRValue(newE.UndefinedBehaviorAvoidance, val);\n      }\n\n      if (expr is LiteralExpr) {\n        var e = (LiteralExpr)expr;\n        if (e.Value == null) {\n          // If an expression is null, treat it as the null pointer. That is, treat it as 0.\n          return new ArmadaRValue(\"0\");\n        }\n        else {\n          return new ArmadaRValue(Printer.ExprToString(expr));\n        }\n      }\n\n      if (expr is ThisExpr) {\n        Fail(expr.tok, \"The keyword 'this' isn't supported in Armada\");\n        return new ArmadaRValue(null);\n      }\n\n      if (expr is MeExpr) {\n        if (tid == null) {\n          Fail(expr.tok, \"No thread defined in this context, $me isn't defined\");\n        }\n        return new ArmadaRValue(tid);\n      }\n\n      if (expr is StoreBufferEmptyExpr) {\n        if (tid == null) {\n          Fail(\"No thread defined in this context, so $sb_empty is undefined\");\n          return null;\n        }\n        var storeBufferEmpty = $\"|({GetRValueState()}).threads[{tid}].storeBuffer| == 0\";\n        return new ArmadaRValue(storeBufferEmpty);\n      }\n\n      if (expr is TotalStateExpr) {\n        return new ArmadaRValue(GetRValueState());\n      }\n\n      if (expr is IfUndefinedExpr) {\n        var e = (IfUndefinedExpr)expr;\n        var potentiallyUnsafe = ResolveAsRValue(e.PotentiallyUnsafe);\n        if (!potentiallyUnsafe.CanCauseUndefinedBehavior) {\n          return potentiallyUnsafe;\n        }\n        var safeSubstitution = ResolveAsRValue(e.SafeSubstitution);\n        var undefinedBehaviorAvoidance = new UndefinedBehaviorAvoidanceConstraint();\n        if (safeSubstitution.CanCauseUndefinedBehavior) {\n          undefinedBehaviorAvoidance.Add(\n            $\"({potentiallyUnsafe.UndefinedBehaviorAvoidance.Expr}) || ({safeSubstitution.UndefinedBehaviorAvoidance.Expr})\"\n          );\n        }\n        return new ArmadaRValue(\n          undefinedBehaviorAvoidance,\n          $\"if {potentiallyUnsafe.UndefinedBehaviorAvoidance.Expr} then {potentiallyUnsafe.Val} else {safeSubstitution.Val}\"\n        );\n      }\n\n      if (expr is IdentifierExpr) {\n        Fail(expr.tok, \"Attempt to resolve IdentifierExpr\");\n        return new ArmadaRValue(null);\n      }\n\n      if (expr is SetDisplayExpr) {\n        var e = (SetDisplayExpr)expr;\n        var newElements = ResolveAsRValueList(e.Elements);\n        var v = \"{\" + String.Join(\", \", newElements.Vals) + \"}\";\n        return new ArmadaRValue(newElements.UndefinedBehaviorAvoidance, v);\n      }\n\n      if (expr is MultiSetDisplayExpr) {\n        var e = (MultiSetDisplayExpr)expr;\n        var newElements = ResolveAsRValueList(e.Elements);\n        var v = \"multiset {\" + String.Join(\", \", newElements.Vals) + \"}\";\n        return new ArmadaRValue(newElements.UndefinedBehaviorAvoidance, v);\n      }\n\n      if (expr is SeqDisplayExpr) {\n        var e = (SeqDisplayExpr)expr;\n        var newElements = ResolveAsRValueList(e.Elements);\n        var v = \"[\" + String.Join(\", \", newElements.Vals) + \"]\";\n        return new ArmadaRValue(newElements.UndefinedBehaviorAvoidance, v);\n      }\n\n      if (expr is MapDisplayExpr) {\n        var e = (MapDisplayExpr)expr;\n        var mapElements = new List<string>();\n        var crashAvoidance = new UndefinedBehaviorAvoidanceConstraint();\n        foreach (var pair in e.Elements) {\n          var newA = ResolveAsRValue(pair.A);\n          var newB = ResolveAsRValue(pair.B);\n          mapElements.Add($\"({newA.Val}) := ({newB.Val})\");\n          crashAvoidance.Add(newA.UndefinedBehaviorAvoidance);\n          crashAvoidance.Add(newB.UndefinedBehaviorAvoidance);\n        }\n        var v = \"map [\" + String.Join(\", \", mapElements) + \"]\";\n        return new ArmadaRValue(crashAvoidance, v);\n      }\n\n      if (expr is DatatypeValue) {\n        var e = (DatatypeValue)expr;\n        var newArgs = ResolveAsRValueList(e.Arguments);\n        var v = $\"{e.DatatypeName}.{e.MemberName}\";\n        if (e.Arguments.Any()) {\n          v += \"(\" + String.Join(\", \", newArgs.Vals) + \")\";\n        }\n        return new ArmadaRValue(newArgs.UndefinedBehaviorAvoidance, v);\n      }\n\n      if (expr is NameSegment) {\n        var e = (NameSegment)expr;\n        var av = symbols.Lookup(methodName, e.Name);\n        if (av == null) {\n          return new ArmadaRValue(e.Name);\n        }\n        else {\n          return av.GetRValue(e.tok, this);\n        }\n      }\n\n      if (expr is ExprDotName) {\n        var e = (ExprDotName)expr;\n        var newLhs = ResolveAsRValue(e.Lhs);\n        var newLhsParenthesized = AH.IsJustNames(e.Lhs) ? newLhs.Val : \"(\" + newLhs.Val + \")\";\n        var v = $\"{newLhsParenthesized}.{e.SuffixName}\";\n        return new ArmadaRValue(newLhs.UndefinedBehaviorAvoidance, v);\n      }\n\n      if (expr is ApplySuffix) {\n        var e = (ApplySuffix)expr;\n        var newLhs = ResolveAsRValue(e.Lhs);\n        var newArgs = ResolveAsRValueList(e.Args);\n        var crashAvoidance = newLhs.UndefinedBehaviorAvoidance + newArgs.UndefinedBehaviorAvoidance;\n        var newLhsParenthesized = AH.IsJustNames(e.Lhs) ? newLhs.Val : $\"({newLhs.Val})\";\n        var v = $\"{newLhsParenthesized}(\" + String.Join(\", \", newArgs.Vals) + \")\";\n        return new ArmadaRValue(crashAvoidance, v);\n      }\n\n      if (expr is RevealExpr) {\n        var e = (RevealExpr) expr;\n        var subexpr = ResolveAsRValue(e.Expr);\n        return new ArmadaRValue(subexpr.UndefinedBehaviorAvoidance, $\"reveal {subexpr.Val}\");\n      }\n\n      if (expr is MemberSelectExpr) {\n        Fail(\"Attempt to resolve a MemberSelectExpr\");\n        return new ArmadaRValue(null);\n      }\n\n      if (expr is SeqSelectExpr) {\n        var e = (SeqSelectExpr)expr;\n        var newSeq = ResolveAsRValue(e.Seq);\n        var newE0 = ResolveAsRValue(e.E0);\n        var newE1 = ResolveAsRValue(e.E1);\n        var type = e.Seq.Type;\n\n        var newE0val = (type is MapType) ? newE0.Val : AH.ConvertToIntIfNotInt(newE0.Val, e.E0.Type);\n        var newE1val = (type is MapType) ? newE1.Val\n                                         : ((e.SelectOne || e.E1 == null) ? null : AH.ConvertToIntIfNotInt(newE1.Val, e.E1.Type));\n        var crashAvoidance = newSeq.UndefinedBehaviorAvoidance + newE0.UndefinedBehaviorAvoidance;\n        if (!e.SelectOne && e.E1 != null)\n        {\n          crashAvoidance.Add(newE1.UndefinedBehaviorAvoidance);\n        }\n\n        if (type is SeqType || type is SizedArrayType) {\n          string v;\n          if (e.SelectOne) {\n            crashAvoidance.Add($\"0 <= {newE0val} < |{newSeq.Val}|\");\n            v = $\"({newSeq.Val})[{newE0val}]\";\n          }\n          else if (e.E1 == null) {\n            crashAvoidance.Add($\"0 <= {newE0val} <= |{newSeq.Val}|\");\n            v = $\"({newSeq.Val})[{newE0val}..]\";\n          }\n          else {\n            crashAvoidance.Add($\"0 <= {newE0val} <= {newE1val} <= |{newSeq.Val}|\");\n            v = $\"({newSeq.Val})[{newE0val}..{newE1val}]\";\n          }\n          return new ArmadaRValue(crashAvoidance, v);\n        }\n\n        if (type is MapType) {\n          if (!e.SelectOne) {\n            Fail(e.tok, \"Attempt to take range of map\");\n            return new ArmadaRValue(null);\n          }\n          crashAvoidance.Add($\"({newE0val}) in ({newSeq.Val})\");\n          var v = $\"({newSeq.Val})[{newE0val}]\";\n          return new ArmadaRValue(crashAvoidance, v);\n        }\n\n        Fail(e.tok, $\"Attempt to obtain element of non-array, non-sequence, non-map type {type}\");\n        return new ArmadaRValue(null);\n      }\n\n      if (expr is MultiSelectExpr) {\n        Fail(expr.tok, \"Multi-select expressions aren't supported in Armada\");\n        return new ArmadaRValue(null);\n      }\n\n      if (expr is SeqUpdateExpr) {\n        var e = (SeqUpdateExpr)expr;\n        var newSeq = ResolveAsRValue(e.Seq);\n        var newIndex = ResolveAsRValue(e.Index);\n        var newValue = ResolveAsRValue(e.Value);\n        var crashAvoidance = newSeq.UndefinedBehaviorAvoidance + newIndex.UndefinedBehaviorAvoidance + newValue.UndefinedBehaviorAvoidance;\n        var v = $\"({newSeq.Val})[{newIndex.Val} := {newValue.Val}]\";\n        return new ArmadaRValue(crashAvoidance, v);\n      }\n\n      if (expr is DatatypeUpdateExpr) {\n        var e = (DatatypeUpdateExpr)expr;\n        var newRoot = ResolveAsRValue(e.Root);\n        var newUpdates = new List<string>();\n        var crashAvoidance = newRoot.UndefinedBehaviorAvoidance;\n        foreach (var update in e.Updates) {\n          var newItem3 = ResolveAsRValue(update.Item3);\n          newUpdates.Add($\"{update.Item2} := {newItem3.Val}\");\n          crashAvoidance.Add(newItem3.UndefinedBehaviorAvoidance);\n        }\n        var v = $\"({newRoot.Val}).(\" + String.Join(\", \", newUpdates) + \")\";\n        return new ArmadaRValue(crashAvoidance, v);\n      }\n\n      if (expr is FunctionCallExpr) {\n        var e = (FunctionCallExpr)expr;\n        var newReceiver = ResolveAsRValue(e.Receiver);\n        var newArgs = ResolveAsRValueList(e.Args);\n        var crashAvoidance = newReceiver.UndefinedBehaviorAvoidance + newArgs.UndefinedBehaviorAvoidance;\n        if (e.Receiver != null) {\n          Fail(e.tok, \"Receivers not supported in Armada\");\n          return null;\n        }\n        var v = $\"{e.Name}(\" + String.Join(\", \", newArgs.Vals) + \")\";\n        return new ArmadaRValue(crashAvoidance, v);\n      }\n\n      if (expr is ApplyExpr) {\n        var e = (ApplyExpr)expr;\n        var newFunction = ResolveAsRValue(e.Function);\n        var newArgs = ResolveAsRValueList(e.Args);\n        var crashAvoidance = newFunction.UndefinedBehaviorAvoidance + newArgs.UndefinedBehaviorAvoidance;\n        var newFunctionParenthesized = AH.IsJustNames(e.Function) ? newFunction.Val : $\"({newFunction.Val})\";\n        var v = $\"{newFunctionParenthesized}(\" + String.Join(\", \", newArgs.Vals) + \")\";\n        return new ArmadaRValue(crashAvoidance, v);\n      }\n\n      if (expr is MultiSetFormingExpr) {\n        var e = (MultiSetFormingExpr)expr;\n        var newE = ResolveAsRValue(e.E);\n        var v = $\"multiset ({newE.Val})\";\n        return new ArmadaRValue(newE.UndefinedBehaviorAvoidance, v);\n      }\n\n      if (expr is OldExpr) {\n        var e = (OldExpr)expr;\n\n        if (e.At != null) {\n          Fail(expr.tok, \"Armada doesn't yet support old() expressions that specify a specific program point\");\n          return new ArmadaRValue(null);\n        }\n\n        return ResolveAsOldRValue(e.tok, e.E);\n      }\n\n      if (expr is UnchangedExpr) {\n        Fail(expr.tok, \"unchanged expressions aren't supported by Armada\");\n        return new ArmadaRValue(null);\n      }\n\n      if (expr is UnaryOpExpr) {\n        var e = (UnaryOpExpr)expr;\n        ArmadaRValue newRV;\n        string val;\n        switch (e.Op) {\n          case UnaryOpExpr.Opcode.Not :\n            if (e.Type is PointerType) {\n              Fail(e.tok, \"Can't do not (or any other integer manipulation, for that matter) on a pointer value\");\n              return new ArmadaRValue(null);\n            }\n            newRV = ResolveAsRValue(e.E);\n            val = $\"!({newRV.Val})\";\n            return new ArmadaRValue(newRV.UndefinedBehaviorAvoidance, val);\n\n          case UnaryOpExpr.Opcode.Cardinality :\n            newRV = ResolveAsRValue(e.E);\n            val = $\"|({newRV.Val})|\";\n            return new ArmadaRValue(newRV.UndefinedBehaviorAvoidance, val);\n\n          case UnaryOpExpr.Opcode.Allocated :\n            newRV = ResolveAsRValue(e.E);\n            return ResolveAllocatedExpr(e.tok, newRV, e.E.Type);\n\n          case UnaryOpExpr.Opcode.AddressOf :\n            var newLV = ResolveAsLValue(e.E);\n            if (newLV == null) {\n              Fail(e.tok, \"Attempt to get address of value that isn't an lvalue\");\n              return new ArmadaRValue(null);\n            }\n            var addr = newLV.GetAddress();\n            if (addr == null) {\n              Fail(e.tok, \"Attempt to get address of value without an address\");\n              return new ArmadaRValue(null);\n            }\n            var crashAvoidance = newLV.GetUndefinedBehaviorAvoidanceConstraint();\n            return new ArmadaRValue(crashAvoidance, addr);\n\n          case UnaryOpExpr.Opcode.Dereference :\n            newRV = ResolveAsRValue(e.E);\n            if (newRV == null) {\n              return new ArmadaRValue(null);\n            }\n            return ResolveArmadaDereferenceExprAsRValue(e.tok, newRV, expr.Type);\n\n          case UnaryOpExpr.Opcode.AllocatedArray :\n            newRV = ResolveAsRValue(e.E);\n            return ResolveAllocatedArrayExpr(e.tok, newRV, e.E.Type);\n\n          case UnaryOpExpr.Opcode.GlobalView :\n            return ResolveAsMemoryRValue(e.tok, e.E);\n\n          default :\n            Fail(e.tok, $\"Armada doesn't support the {e.Op.ToString()} operator\");\n            return new ArmadaRValue(null);\n        }\n      }\n\n      if (expr is ConversionExpr) {\n        var e = (ConversionExpr)expr;\n        var newE = ResolveAsRValue(e.E);\n        var v = $\"({newE.Val}) as {e.ToType.ToString()}\";\n        return new ArmadaRValue(newE.UndefinedBehaviorAvoidance, v);\n      }\n\n      if (expr is BinaryExpr) {\n        var e = (BinaryExpr)expr;\n        var newE0 = ResolveAsRValue(e.E0);\n        var newE1 = ResolveAsRValue(e.E1);\n        return ResolveArmadaBinaryExpr(e.tok, e.Type, e.Op, newE0, newE1, e.E0.Type, e.E1.Type);\n      }\n\n      if (expr is TernaryExpr) {\n        var e = (TernaryExpr)expr;\n        Fail(expr.tok, \"Ternary operators not supported in Armada\");\n        return new ArmadaRValue(null);\n        /*\n        var newE0 = ResolveAsRValue(e.E0);\n        var newE1 = ResolveAsRValue(e.E1);\n        var newE2 = ResolveAsRValue(e.E2);\n        var crashAvoidance = newE0.UndefinedBehaviorAvoidance + newE1.UndefinedBehaviorAvoidance + newE2.UndefinedBehaviorAvoidance;\n        var v = ...;\n        return new ArmadaRValue(crashAvoidance, v);\n        */\n      }\n\n      if (expr is LetExpr) {\n        var e = (LetExpr)expr;\n        var newRHSs = ResolveAsRValueList(e.RHSs);\n        var newBody = ResolveAsRValue(e.Body);\n        var crashAvoidance = newRHSs.UndefinedBehaviorAvoidance;\n        var defs = String.Concat(Enumerable.Range(0, e.LHSs.Count).Select(i => $\"var {e.LHSs[i].Id} := {newRHSs.Vals[i]}; \"));\n        if (newBody.CanCauseUndefinedBehavior) {\n          crashAvoidance.Add($\"{defs}{newBody.UndefinedBehaviorAvoidance.Expr}\");\n        }\n        return new ArmadaRValue(crashAvoidance, $\"{defs}{newBody.Val}\");\n      }\n\n      if (expr is NamedExpr) {\n        var e = (NamedExpr)expr;\n        var newBody = ResolveAsRValue(e.Body);\n        var crashAvoidance = newBody.UndefinedBehaviorAvoidance;\n        var v = $\"label {e.Name} : {newBody.Val}\";\n        return new ArmadaRValue(crashAvoidance, v);\n      }\n\n      if (expr is ForallExpr) {\n        var e = (ForallExpr)expr;\n        var newRange = ResolveAsRValue(e.Range);\n        var newTerm = ResolveAsRValue(e.Term);\n        var crashAvoidance = GetQuantifiedUndefinedBehaviorAvoidanceConstraint(newRange, newTerm, e.TypeArgs, e.BoundVars, e.Attributes);\n        var v = \"forall \"\n                + String.Join(\", \", e.BoundVars.Select(bv => $\"{bv.Name}:{bv.Type.ToString()}\"))\n                + \" \"\n                + ResolveTriggers(e.Attributes)\n                + (e.Range != null ? \" | \" + newRange.Val : \"\")\n                + \" :: \"\n                + newTerm.Val;\n        return new ArmadaRValue(crashAvoidance, v);\n      }\n\n      if (expr is ExistsExpr) {\n        var e = (ExistsExpr)expr;\n        var newRange = ResolveAsRValue(e.Range);\n        var newTerm = ResolveAsRValue(e.Term);\n        var crashAvoidance = GetQuantifiedUndefinedBehaviorAvoidanceConstraint(newRange, newTerm, e.TypeArgs, e.BoundVars, e.Attributes);\n        var v = \"exists \"\n                + String.Join(\", \", e.BoundVars.Select(bv => $\"{bv.Name}:{bv.Type.ToString()}\"))\n                + \" \"\n                + ResolveTriggers(e.Attributes)\n                + (e.Range != null ? \" | \" + newRange.Val : \"\")\n                + \" :: \"\n                + newTerm.Val;\n        return new ArmadaRValue(crashAvoidance, v);\n      }\n\n      if (expr is SetComprehension) {\n        var e = (SetComprehension)expr;\n        var newRange = ResolveAsRValue(e.Range);\n        var newTerm = ResolveAsRValue(e.Term);\n        var crashAvoidance = GetQuantifiedUndefinedBehaviorAvoidanceConstraint(newRange, newTerm, new List<TypeParameter>(), e.BoundVars,\n                                                                               e.Attributes);\n        var v = (e.Finite ? \"set \" : \"iset \")\n                + String.Join(\", \", e.BoundVars.Select(bv => $\"{bv.Name}:{bv.Type.ToString()}\"))\n                + ResolveTriggers(e.Attributes)\n                + \" | \"\n                + newRange.Val\n                + (e.Term != null ? \" :: \" + newTerm.Val : \"\");\n        return new ArmadaRValue(crashAvoidance, v);\n      }\n\n      if (expr is MapComprehension) {\n        var e = (MapComprehension)expr;\n        var newRange = ResolveAsRValue(e.Range);\n        var newRightTerm = ResolveAsRValue(e.Term);\n        var newLeftTerm = ResolveAsRValue(e.TermLeft);\n        var crashAvoidance = GetQuantifiedUndefinedBehaviorAvoidanceConstraint(newRange, newRightTerm, new List<TypeParameter>(),\n                                                                               e.BoundVars, e.Attributes);\n        if (e.TermLeft != null) {\n          crashAvoidance += GetQuantifiedUndefinedBehaviorAvoidanceConstraint(newRange, newLeftTerm, new List<TypeParameter>(),\n                                                                              e.BoundVars, e.Attributes);\n        }\n        var v = (e.Finite ? \"map \" : \"imap \")\n                + String.Join(\", \", e.BoundVars.Select(bv => $\"{bv.Name}:{bv.Type.ToString()}\"))\n                + ResolveTriggers(e.Attributes)\n                + (e.Range != null ? \" | \" + newRange.Val : \"\")\n                + \" :: \"\n                + (e.TermLeft != null ? $\"{newLeftTerm.Val} := \" : \"\")\n                + newRightTerm.Val;\n        return new ArmadaRValue(crashAvoidance, v);\n      }\n\n      if (expr is LambdaExpr) {\n        var e = (LambdaExpr)expr;\n        var newRequires = ResolveAsRValue(e.Range);\n        var newBody = ResolveAsRValue(e.Body);\n        if (e.Reads != null && e.Reads.Any()) {\n          Fail(expr.tok, \"Can't resolve a lambda expression with a reads clause\");\n          return new ArmadaRValue(null);\n        }\n        var crashAvoidance = GetQuantifiedUndefinedBehaviorAvoidanceConstraint(newRequires, newBody, new List<TypeParameter>(), e.BoundVars,\n                                                                               null /* no attributes */);\n        var v = \"lambda \"\n                + String.Join(\", \", e.BoundVars.Select(bv => $\"{bv.Name}:{bv.Type.ToString()}\"))\n                + (e.Range != null ? $\" requires {newRequires.Val}\" : \"\")\n                + \" => \"\n                + newBody.Val;\n        return new ArmadaRValue(crashAvoidance, v);\n      }\n\n      if (expr is WildcardExpr) {\n        Fail(\"Can't resolve wildcard expression in this context\");\n        return new ArmadaRValue(null);\n      }\n\n      if (expr is StmtExpr) {\n        Fail(\"Can't resolve statement expression in this context\");\n        return new ArmadaRValue(null);\n      }\n\n      if (expr is ITEExpr) {\n        var e = (ITEExpr)expr;\n        var newTest = ResolveAsRValue(e.Test);\n        var newThn = ResolveAsRValue(e.Thn);\n        var newEls = ResolveAsRValue(e.Els);\n        var crashAvoidance = newTest.UndefinedBehaviorAvoidance;\n        if (newThn.CanCauseUndefinedBehavior) {\n          crashAvoidance.Add($\"({newTest.Val}) ==> ({newThn.UndefinedBehaviorAvoidance.Expr})\");\n        }\n        if (newEls != null && newEls.CanCauseUndefinedBehavior) {\n          crashAvoidance.Add($\"({newTest.Val}) || ({newEls.UndefinedBehaviorAvoidance.Expr})\");\n        }\n        var v = $\"if {newTest.Val} then {newThn.Val} else {newEls.Val}\";\n        return new ArmadaRValue(crashAvoidance, v);\n      }\n\n      if (expr is MatchExpr) {\n        var e = (MatchExpr)expr;\n        var newSource = ResolveAsRValue(e.Source);\n        var newCases = \"\";\n\n        bool canCrash = false;\n        var crashAvoidanceCases = \"\";\n        foreach (var c in e.Cases) {\n          var newBody = ResolveAsRValue(c.Body);\n          // I believe that it's best to always use CasePatterns, because we can't be sure that it's resolved.\n          var cpHeader = $\"case {c.Id}\";\n          if (c.CasePatterns != null) {\n            cpHeader += \"(\" + String.Join(\", \", c.CasePatterns.Select(cp => $\"{cp.Var.Name}:{cp.Var.Type.ToString()}\")) + \")\";\n          }\n          cpHeader += \" => \";\n          newCases += (cpHeader + newBody.Val + \"\\n\");\n\n          // Now, add a case to the list of crash-avoidance cases.  We need to get this case\n          // even if it's empty (true) since some of the cases might not be empty.\n\n          var crashExpr = newBody.UndefinedBehaviorAvoidance.Expr;\n          crashAvoidanceCases += (cpHeader + crashExpr + \"\\n\");\n          if (newBody.CanCauseUndefinedBehavior) {\n            canCrash = true;\n          }\n        }\n\n        // The crash-avoidance constraint includes the source's crash-avoidance constraint.  And, if any of\n        // the cases can crash, we create a match expression to describe the crash-avoidance constraint\n        // and add it to the crash-avoidance constraint.\n\n        var crashAvoidance = newSource.UndefinedBehaviorAvoidance;\n        if (canCrash) {\n          crashAvoidance.Add($\"match {newSource.Val}\\n{crashAvoidanceCases}\");\n        }\n\n        return new ArmadaRValue(crashAvoidance, $\"match {newSource.Val}\\n{newCases}\");\n      }\n\n      Fail(expr.tok, $\"Can't resolve the following expression as an rvalue since it has an unexpected expression type:  {expr}\\n\");\n      return new ArmadaRValue(null);\n    }\n\n    public ArmadaRValueList ResolveAsRValueList(List<Expression> es)\n    {\n      if (es == null) {\n        return null;\n      }\n\n      var ret = new ArmadaRValueList();\n      foreach (var e in es) {\n        ret.Add(ResolveAsRValue(e));\n      }\n      return ret;\n    }\n  }\n\n  public class NormalResolutionContext : ResolutionContext\n  {\n    private readonly string locv;\n    private readonly string t;\n\n    public NormalResolutionContext(NextRoutineConstructor next, ArmadaSymbolTable i_symbols)\n      : base(next.s, next.s, next.tid, next.method.Name, i_symbols, next)\n    {\n      locv = next.locv;\n      t = next.t;\n    }\n\n    public NormalResolutionContext(string i_lvalueState, NextRoutineConstructor next, ArmadaSymbolTable i_symbols)\n      : base(i_lvalueState, next.s, next.tid, next.method.Name, i_symbols, next)\n    {\n      locv = next.locv;\n      t = next.t;\n    }\n\n    public NormalResolutionContext(string moduleName, string methodName, ArmadaSymbolTable i_symbols, IFailureReporter i_failureReporter)\n      : base(\"s\", \"s\", \"tid\", methodName, i_symbols, i_failureReporter, moduleName)\n    {\n      locv = \"locv\";\n      t = \"t\";\n    }\n\n    public override string GetRValueHeap()\n    {\n      return $\"({locv}).heap\";\n    }\n\n    public override string GetRValueGlobals()\n    {\n      return $\"({locv}).globals\";\n    }\n\n    public override string GetRValueTopStackFrame()\n    {\n      return $\"({t}).top\";\n    }\n  }\n\n  public class CustomResolutionContext : ResolutionContext\n  {\n    private readonly string locv;\n    private readonly string top;\n    private readonly string ghosts;\n\n    public CustomResolutionContext(string i_lvalueState, string i_rvalueState, string i_locv, string i_top,\n                                   string i_ghosts, string i_tid, string i_methodName,\n                                   ArmadaSymbolTable i_symbols, IFailureReporter i_failureReporter)\n      : base(i_lvalueState, i_rvalueState, i_tid, i_methodName, i_symbols, i_failureReporter)\n    {\n      locv = i_locv;\n      top = i_top;\n      ghosts = i_ghosts;\n    }\n\n    public override string GetRValueHeap()\n    {\n      return $\"({locv}).heap\";\n    }\n\n    public override string GetRValueGlobals()\n    {\n      return $\"({locv}).globals\";\n    }\n\n    public override string GetRValueGhosts()\n    {\n      return ghosts;\n    }\n\n    public override string GetRValueTopStackFrame()\n    {\n      return top;\n    }\n\n    public override ArmadaRValue ResolveAsMemoryRValue(IToken tok, Expression expr)\n    {\n      Fail(tok, \"Can't use mem() in this context\");\n      return null;\n    }\n  }\n\n  public class GlobalInvariantResolutionContext : ResolutionContext\n  {\n    public GlobalInvariantResolutionContext(string i_s, ArmadaSymbolTable i_symbols, IFailureReporter i_failureReporter,\n                                            string i_moduleName)\n      : base(i_s, i_s, null, null, i_symbols, i_failureReporter, i_moduleName)\n    {\n    }\n\n    public override string GetRValueHeap()\n    {\n      return $\"({GetRValueState()}).mem.heap\";\n    }\n\n    public override string GetRValueGlobals()\n    {\n      return $\"({GetRValueState()}).mem.globals\";\n    }\n\n    public override string GetRValueGhosts()\n    {\n      return $\"({GetRValueState()}).ghosts\";\n    }\n\n    public override string GetRValueTopStackFrame()\n    {\n      Fail(\"Can't refer to a stack variable in a global invariant\");\n      return null;\n    }\n  }\n\n  public class YieldPredicateResolutionContext : ResolutionContext\n  {\n    private readonly string s;\n\n    public YieldPredicateResolutionContext(string i_s, string s_prime, string i_tid,\n                                           ArmadaSymbolTable i_symbols, IFailureReporter i_failureReporter, string i_moduleName)\n      : base(s_prime, s_prime, i_tid, null, i_symbols, i_failureReporter, i_moduleName)\n    {\n      s = i_s;\n    }\n\n    public override string GetRValueTopStackFrame()\n    {\n      Fail(\"Can't refer to a stack variable in a yield predicate\");\n      return null;\n    }\n\n    public override ArmadaRValue ResolveAsOldRValue(IToken tok, Expression expr)\n    {\n      var yrc = new YieldPredicateResolutionContext(s, s, tid, symbols, failureReporter, moduleName);\n      return yrc.ResolveAsRValue(expr);\n    }\n  }\n\n  public class RequiresResolutionContext : ResolutionContext\n  {\n    public RequiresResolutionContext(string i_s, string i_tid, string i_methodName, ArmadaSymbolTable i_symbols,\n                                     IFailureReporter i_failureReporter, string i_moduleName = null)\n      : base(i_s, i_s, i_tid, i_methodName, i_symbols, i_failureReporter, i_moduleName)\n    {\n    }\n  }\n\n  public class EnsuresResolutionContext : ResolutionContext\n  {\n    private readonly string s;\n\n    public EnsuresResolutionContext(string i_s, string s_prime, string i_tid, string i_methodName,\n                                    ArmadaSymbolTable i_symbols, IFailureReporter i_failureReporter, string i_moduleName)\n      : base(s_prime, s_prime, i_tid, i_methodName, i_symbols, i_failureReporter, i_moduleName)\n    {\n      s = i_s;\n    }\n\n    public override ArmadaRValue ResolveAsOldRValue(IToken tok, Expression expr)\n    {\n      var erc = new EnsuresResolutionContext(s, s, tid, methodName, symbols, failureReporter, moduleName);\n      return erc.ResolveAsRValue(expr);\n    }\n  }\n\n  public class BodylessMethodSnapshotResolutionContext : ResolutionContext\n  {\n    private List<Expression> oldValues;\n    private bool resolving;\n\n    public BodylessMethodSnapshotResolutionContext(string i_s, string i_tid, string i_methodName, ArmadaSymbolTable i_symbols,\n                                                   IFailureReporter i_failureReporter)\n      : base(i_s, i_s, i_tid, i_methodName, i_symbols, i_failureReporter, null)\n    {\n      oldValues = new List<Expression>();\n      resolving = false;\n    }\n\n    public override ArmadaRValue ResolveAsOldRValue(IToken tok, Expression expr)\n    {\n      if (resolving) {\n        Fail(tok, \"Nested old() expressions not allowed in the postcondition of a body-less method\");\n        return null;\n      }\n\n      oldValues.Add(expr);\n\n      resolving = true;\n      var retval = ResolveAsRValue(expr);\n      resolving = false;\n\n      return retval;\n    }\n\n    public List<Expression> OldValues { get { return oldValues; } }\n  }\n\n  public class BodylessMethodPostconditionResolutionContext : ResolutionContext\n  {\n    private int numOldResolutions;\n\n    public BodylessMethodPostconditionResolutionContext(NextRoutineConstructor next, ArmadaSymbolTable i_symbols)\n      : base(next.s, next.s, next.tid, next.method.Name, i_symbols, next)\n    {\n      numOldResolutions = 0;\n    }\n\n    public override ArmadaRValue ResolveAsOldRValue(IToken tok, Expression expr)\n    {\n      var v = symbols.Lookup(methodName, $\"Armada_Old{numOldResolutions}\");\n      ++numOldResolutions;\n      return v.GetRValue(tok, this);\n    }\n  }\n\n  public class TSOBypassingResolutionContext : ResolutionContext\n  {\n    private readonly string mem;\n    private readonly string t;\n\n    public TSOBypassingResolutionContext(NextRoutineConstructor next, ArmadaSymbolTable i_symbols)\n      : base(next.s, next.s, next.tid, next.method.Name, i_symbols, next)\n    {\n      mem = $\"({next.s}).mem\";\n      t = next.t;\n    }\n\n    public override string GetRValueHeap()\n    {\n      return $\"({mem}).heap\";\n    }\n\n    public override string GetRValueGlobals()\n    {\n      return $\"({mem}).globals\";\n    }\n\n    public override string GetRValueTopStackFrame()\n    {\n      return $\"({t}).top\";\n    }\n\n    public override ArmadaRValue ResolveAsMemoryRValue(IToken tok, Expression expr)\n    {\n      return ResolveAsRValue(expr);\n    }\n  }\n\n  public class GlobalViewResolutionContext : ResolutionContext\n  {\n    private readonly string mem;\n\n    public GlobalViewResolutionContext(string s, string i_tid, string i_methodName, ArmadaSymbolTable i_symbols,\n                                       IFailureReporter i_failureReporter, string i_moduleName)\n      : base(null, s, i_tid, i_methodName, i_symbols, i_failureReporter, i_moduleName)\n    {\n      mem = $\"({s}).mem\";\n    }\n\n    public override string GetRValueHeap()\n    {\n      return $\"({mem}).heap\";\n    }\n\n    public override string GetRValueGlobals()\n    {\n      return $\"({mem}).globals\";\n    }\n  }\n\n  public class EnablingConstraintResolutionContext : ResolutionContext\n  {\n    private readonly string locv;\n    private readonly string top;\n    private readonly string ghosts;\n\n    public EnablingConstraintResolutionContext(EnablingConstraintCollector ecc, string methodName, ArmadaSymbolTable symbols)\n      : base(ecc.s, ecc.s, ecc.tid, methodName, symbols, ecc)\n    {\n      locv = ecc.locv;\n      top = ecc.top;\n      ghosts = ecc.ghosts;\n    }\n\n    public override string GetRValueHeap()\n    {\n      return $\"({locv}).heap\";\n    }\n\n    public override string GetRValueGlobals()\n    {\n      return $\"({locv}).globals\";\n    }\n\n    public override string GetRValueGhosts()\n    {\n      return ghosts;\n    }\n\n    public override string GetRValueTopStackFrame()\n    {\n      return top;\n    }\n  }\n}\n"
  },
  {
    "path": "Source/Armada/Resolver.cs",
    "content": "#define TI_DEBUG_PRINT\n//-----------------------------------------------------------------------------\n//\n// Copyright (C) Microsoft Corporation.  All Rights Reserved.\n//\n//-----------------------------------------------------------------------------\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Numerics;\nusing System.Diagnostics.Contracts;\nusing Microsoft.Boogie;\n\nnamespace Microsoft.Armada\n{\n  public class Resolver\n  {\n    readonly BuiltIns builtIns;\n\n    ErrorReporter reporter;\n    ModuleSignature moduleInfo = null;\n\n    private bool RevealedInScope(Declaration d) {\n      Contract.Requires(d != null);\n      Contract.Requires(moduleInfo != null);\n      Contract.Requires(moduleInfo.VisibilityScope != null);\n\n      return useCompileSignatures || d.IsRevealedInScope(moduleInfo.VisibilityScope);\n    }\n\n    private bool VisibleInScope(Declaration d) {\n      Contract.Requires(d != null);\n      Contract.Requires(moduleInfo != null);\n      Contract.Requires(moduleInfo.VisibilityScope != null);\n\n      return useCompileSignatures || d.IsVisibleInScope(moduleInfo.VisibilityScope);\n    }\n\n    FreshIdGenerator defaultTempVarIdGenerator;\n    string FreshTempVarName(string prefix, ICodeContext context) {\n      var decl = context as Declaration;\n      if (decl != null) {\n        return decl.IdGenerator.FreshId(prefix);\n      }\n      // TODO(wuestholz): Is the following code ever needed?\n      if (defaultTempVarIdGenerator == null) {\n        defaultTempVarIdGenerator = new FreshIdGenerator();\n      }\n      return defaultTempVarIdGenerator.FreshId(prefix);\n    }\n\n    interface IAmbiguousThing<Thing>\n    {\n      /// <summary>\n      /// Returns a plural number of non-null Thing's\n      /// </summary>\n      ISet<Thing> Pool { get; }\n    }\n    class AmbiguousThingHelper<Thing> where Thing : class\n    {\n      public static Thing Create(ModuleDefinition m, Thing a, Thing b, IEqualityComparer<Thing> eq, out ISet<Thing> s) {\n        Contract.Requires(a != null);\n        Contract.Requires(b != null);\n        Contract.Requires(eq != null);\n        Contract.Ensures(Contract.Result<Thing>() != null || (Contract.ValueAtReturn(out s) != null || 2 <= Contract.ValueAtReturn(out s).Count));\n        s = null;\n        if (eq.Equals(a, b)) {\n          return a;\n        }\n        ISet<Thing> sa = a is IAmbiguousThing<Thing> ? ((IAmbiguousThing<Thing>)a).Pool : new HashSet<Thing>() { a };\n        ISet<Thing> sb = b is IAmbiguousThing<Thing> ? ((IAmbiguousThing<Thing>)b).Pool : new HashSet<Thing>() { b };\n        var union = new HashSet<Thing>(sa.Union(sb, eq));\n        if (sa.Count == union.Count) {\n          // sb is a subset of sa\n          return a;\n        } else if (sb.Count == union.Count) {\n          // sa is a subset of sb\n          return b;\n        } else {\n          s = union;\n          Contract.Assert(2 <= s.Count);\n          return null;\n        }\n      }\n      public static string Name(ISet<Thing> s, Func<Thing, string> name) {\n        Contract.Requires(s != null);\n        Contract.Requires(s.Count != 0);\n        string nm = null;\n        foreach (var thing in s) {\n          string n = name(thing);\n          if (nm == null) {\n            nm = n;\n          } else {\n            nm += \"/\" + n;\n          }\n        }\n        return nm;\n      }\n      public static string ModuleNames(IAmbiguousThing<Thing> amb, Func<Thing, string> moduleName) {\n        Contract.Requires(amb != null);\n        Contract.Ensures(Contract.Result<string>() != null);\n        string nm = null;\n        foreach (var d in amb.Pool) {\n          if (nm == null) {\n            nm = moduleName(d);\n          } else {\n            nm += \", \" + moduleName(d);\n          }\n        }\n        return nm;\n      }\n    }\n\n    public class AmbiguousTopLevelDecl : TopLevelDecl, IAmbiguousThing<TopLevelDecl>  // only used with \"classes\"\n    {\n      public static TopLevelDecl Create(ModuleDefinition m, TopLevelDecl a, TopLevelDecl b) {\n        ISet<TopLevelDecl> s;\n        var t = AmbiguousThingHelper<TopLevelDecl>.Create(m, a, b, new Eq(), out s);\n        return t ?? new AmbiguousTopLevelDecl(m, AmbiguousThingHelper<TopLevelDecl>.Name(s, tld => tld.Name), s);\n      }\n      class Eq : IEqualityComparer<TopLevelDecl>\n      {\n        public bool Equals(TopLevelDecl d0, TopLevelDecl d1) {\n          // We'd like to resolve any AliasModuleDecl to whatever module they refer to.\n          // It seems that the only way to do that is to look at alias.Signature.ModuleDef,\n          // but that is a ModuleDefinition, which is not a TopLevelDecl.  Therefore, we\n          // convert to a ModuleDefinition anything that might refer to something that an\n          // AliasModuleDecl can refer to; this is AliasModuleDecl and LiteralModuleDecl.\n          object a = d0 is ModuleDecl ? ((ModuleDecl)d0).Dereference() : d0;\n          object b = d1 is ModuleDecl ? ((ModuleDecl)d1).Dereference() : d1;\n          return a == b;\n        }\n        public int GetHashCode(TopLevelDecl d) {\n          object a = d is ModuleDecl ? ((ModuleDecl)d).Dereference() : d;\n          return a.GetHashCode();\n        }\n      }\n\n      public override string WhatKind { get { return Pool.First().WhatKind; } }\n      readonly ISet<TopLevelDecl> Pool = new HashSet<TopLevelDecl>();\n      ISet<TopLevelDecl> IAmbiguousThing<TopLevelDecl>.Pool { get { return Pool; } }\n      private AmbiguousTopLevelDecl(ModuleDefinition m, string name, ISet<TopLevelDecl> pool)\n        : base(pool.First().tok, name, m, new List<TypeParameter>(), null) {\n        Contract.Requires(name != null);\n        Contract.Requires(pool != null && 2 <= pool.Count);\n        Pool = pool;\n      }\n      public string ModuleNames() {\n        return AmbiguousThingHelper<TopLevelDecl>.ModuleNames(this, d => d.Module.Name);\n      }\n    }\n\n    class AmbiguousMemberDecl : MemberDecl, IAmbiguousThing<MemberDecl>  // only used with \"classes\"\n    {\n      public static MemberDecl Create(ModuleDefinition m, MemberDecl a, MemberDecl b) {\n        ISet<MemberDecl> s;\n        var t = AmbiguousThingHelper<MemberDecl>.Create(m, a, b, new Eq(), out s);\n        return t ?? new AmbiguousMemberDecl(m, AmbiguousThingHelper<MemberDecl>.Name(s, member => member.Name), s);\n      }\n      class Eq : IEqualityComparer<MemberDecl>\n      {\n        public bool Equals(MemberDecl d0, MemberDecl d1) {\n          return d0 == d1;\n        }\n        public int GetHashCode(MemberDecl d) {\n          return d.GetHashCode();\n        }\n      }\n\n      public override string WhatKind { get { return Pool.First().WhatKind; } }\n      readonly ISet<MemberDecl> Pool = new HashSet<MemberDecl>();\n      ISet<MemberDecl> IAmbiguousThing<MemberDecl>.Pool { get { return Pool; } }\n      private AmbiguousMemberDecl(ModuleDefinition m, string name, ISet<MemberDecl> pool)\n        : base(pool.First().tok, name, true, pool.First().IsGhost, null) {\n        Contract.Requires(name != null);\n        Contract.Requires(pool != null && 2 <= pool.Count);\n        Pool = pool;\n      }\n      public string ModuleNames() {\n        return AmbiguousThingHelper<MemberDecl>.ModuleNames(this, d => d.EnclosingClass.Module.Name);\n      }\n    }\n\n\n    readonly HashSet<RevealableTypeDecl> revealableTypes = new HashSet<RevealableTypeDecl>();\n    //types that have been seen by the resolver - used for constraining type inference during exports\n\n    readonly Dictionary<TopLevelDeclWithMembers, Dictionary<string, MemberDecl>> classMembers = new Dictionary<TopLevelDeclWithMembers, Dictionary<string, MemberDecl>>();\n    readonly Dictionary<DatatypeDecl, Dictionary<string, DatatypeCtor>> datatypeCtors = new Dictionary<DatatypeDecl, Dictionary<string, DatatypeCtor>>();\n    enum ValuetypeVariety { Bool = 0, Int, Real, BigOrdinal, Bitvector, Map, IMap, None }  // note, these are ordered, so they can be used as indices into valuetypeDecls\n    readonly ValuetypeDecl[] valuetypeDecls;\n    private Dictionary<TypeParameter, Type> SelfTypeSubstitution;\n    readonly Graph<ModuleDecl> dependencies = new Graph<ModuleDecl>();\n    private ModuleSignature systemNameInfo = null;\n    private bool useCompileSignatures = false;\n\n    private List<IRewriter> rewriters;\n    private RefinementTransformer refinementTransformer;\n\n    public Resolver(Program prog) {\n      Contract.Requires(prog != null);\n\n      builtIns = prog.BuiltIns;\n      reporter = prog.reporter;\n\n      // Map#Items relies on the two destructors for 2-tuples\n      builtIns.TupleType(Token.NoToken, 2, true);\n      // Several methods and fields rely on 1-argument arrow types\n      builtIns.CreateArrowTypeDecl(1);\n\n      valuetypeDecls = new ValuetypeDecl[] {\n        new ValuetypeDecl(\"bool\", builtIns.SystemModule, 0, t => t.IsBoolType, typeArgs => Type.Bool),\n        new ValuetypeDecl(\"int\", builtIns.SystemModule, 0, t => t.IsNumericBased(Type.NumericPersuation.Int), typeArgs => Type.Int),\n        new ValuetypeDecl(\"real\", builtIns.SystemModule, 0, t => t.IsNumericBased(Type.NumericPersuation.Real), typeArgs => Type.Real),\n        new ValuetypeDecl(\"ORDINAL\", builtIns.SystemModule, 0, t => t.IsBigOrdinalType, typeArgs => Type.BigOrdinal),\n        new ValuetypeDecl(\"bv\", builtIns.SystemModule, 0, t => t.IsBitVectorType, null),  // \"bv\" represents a family of classes, so no typeTester or type creator is supplied\n        new ValuetypeDecl(\"map\", builtIns.SystemModule, 2, t => t.IsMapType, typeArgs => new MapType(true, typeArgs[0], typeArgs[1])),\n        new ValuetypeDecl(\"imap\", builtIns.SystemModule, 2, t => t.IsIMapType, typeArgs => new MapType(false, typeArgs[0], typeArgs[1]))\n      };\n      builtIns.SystemModule.TopLevelDecls.AddRange(valuetypeDecls);\n      // Resolution error handling relies on being able to get to the 0-tuple declaration\n      builtIns.TupleType(Token.NoToken, 0, true);\n\n      // Populate the members of the basic types\n      var floor = new SpecialField(Token.NoToken, \"Floor\", SpecialField.ID.Floor, null, false, false, false, Type.Int, null);\n      floor.AddVisibilityScope(prog.BuiltIns.SystemModule.VisibilityScope, false);\n      valuetypeDecls[(int)ValuetypeVariety.Real].Members.Add(floor.Name, floor);\n\n      var isLimit = new SpecialField(Token.NoToken, \"IsLimit\", SpecialField.ID.IsLimit, null, false, false, false, Type.Bool, null);\n      isLimit.AddVisibilityScope(prog.BuiltIns.SystemModule.VisibilityScope, false);\n      valuetypeDecls[(int)ValuetypeVariety.BigOrdinal].Members.Add(isLimit.Name, isLimit);\n\n      var isSucc = new SpecialField(Token.NoToken, \"IsSucc\", SpecialField.ID.IsSucc, null, false, false, false, Type.Bool, null);\n      isSucc.AddVisibilityScope(prog.BuiltIns.SystemModule.VisibilityScope, false);\n      valuetypeDecls[(int)ValuetypeVariety.BigOrdinal].Members.Add(isSucc.Name, isSucc);\n\n      var limitOffset = new SpecialField(Token.NoToken, \"Offset\", SpecialField.ID.Offset, null, false, false, false, Type.Int, null);\n      limitOffset.AddVisibilityScope(prog.BuiltIns.SystemModule.VisibilityScope, false);\n      valuetypeDecls[(int)ValuetypeVariety.BigOrdinal].Members.Add(limitOffset.Name, limitOffset);\n      builtIns.ORDINAL_Offset = limitOffset;\n\n      var isNat = new SpecialField(Token.NoToken, \"IsNat\", SpecialField.ID.IsNat, null, false, false, false, Type.Bool, null);\n      isNat.AddVisibilityScope(prog.BuiltIns.SystemModule.VisibilityScope, false);\n      valuetypeDecls[(int)ValuetypeVariety.BigOrdinal].Members.Add(isNat.Name, isNat);\n\n      // Add \"Keys\", \"Values\", and \"Items\" to map, imap\n      foreach (var typeVariety in new [] { ValuetypeVariety.Map, ValuetypeVariety.IMap }) {\n        var vtd = valuetypeDecls[(int)typeVariety];\n        var isFinite = typeVariety == ValuetypeVariety.Map;\n\n        var r = new SetType(isFinite, new UserDefinedType(vtd.TypeArgs[0]));\n        var keys = new SpecialField(Token.NoToken, \"Keys\", SpecialField.ID.Keys, null, false, false, false, r, null);\n\n        r = new SetType(isFinite, new UserDefinedType(vtd.TypeArgs[1]));\n        var values = new SpecialField(Token.NoToken, \"Values\", SpecialField.ID.Values, null, false, false, false, r, null);\n\n        var gt = vtd.TypeArgs.ConvertAll(tp => (Type)new UserDefinedType(tp));\n        var dt = builtIns.TupleType(Token.NoToken, 2, true);\n        var tupleType = new UserDefinedType(Token.NoToken, dt.Name, dt, gt);\n        r = new SetType(isFinite, tupleType);\n        var items = new SpecialField(Token.NoToken, \"Items\", SpecialField.ID.Items, null, false, false, false, r, null);\n\n        foreach (var memb in new[] { keys, values, items }) {\n          memb.EnclosingClass = vtd;\n          memb.AddVisibilityScope(prog.BuiltIns.SystemModule.VisibilityScope, false);\n          vtd.Members.Add(memb.Name, memb);\n        }\n      }\n\n\n      // The result type of the following bitvector methods is the type of the bitvector itself. However, we're representing all bitvector types as\n      // a family of types rolled up in one ValuetypeDecl. Therefore, we use the special SelfType as the result type.\n      List<Formal> formals = new List<Formal> { new Formal(Token.NoToken, \"w\", Type.Nat(), true, false, false) };\n      var rotateLeft = new SpecialFunction(Token.NoToken, \"RotateLeft\", prog.BuiltIns.SystemModule, false, false, false, new List<TypeParameter>(), formals, new SelfType(),\n        new List<MaybeFreeExpression>(), new List<FrameExpression>(), new List<MaybeFreeExpression>(), new Specification<Expression>(new List<Expression>(), null), null, null, null);\n      rotateLeft.EnclosingClass = valuetypeDecls[(int)ValuetypeVariety.Bitvector];\n      rotateLeft.AddVisibilityScope(prog.BuiltIns.SystemModule.VisibilityScope, false);\n      valuetypeDecls[(int)ValuetypeVariety.Bitvector].Members.Add(rotateLeft.Name, rotateLeft);\n\n      formals = new List<Formal> { new Formal(Token.NoToken, \"w\", Type.Nat(), true, false, false) };\n      var rotateRight = new SpecialFunction(Token.NoToken, \"RotateRight\", prog.BuiltIns.SystemModule, false, false, false, new List<TypeParameter>(), formals, new SelfType(),\n        new List<MaybeFreeExpression>(), new List<FrameExpression>(), new List<MaybeFreeExpression>(), new Specification<Expression>(new List<Expression>(), null), null, null, null);\n      rotateRight.EnclosingClass = valuetypeDecls[(int)ValuetypeVariety.Bitvector];\n      rotateRight.AddVisibilityScope(prog.BuiltIns.SystemModule.VisibilityScope, false);\n      valuetypeDecls[(int)ValuetypeVariety.Bitvector].Members.Add(rotateRight.Name, rotateRight);\n    }\n\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(builtIns != null);\n      Contract.Invariant(cce.NonNullElements(dependencies.GetVertices()));\n      Contract.Invariant(cce.NonNullDictionaryAndValues(classMembers) && Contract.ForAll(classMembers.Values, v => cce.NonNullDictionaryAndValues(v)));\n      Contract.Invariant(cce.NonNullDictionaryAndValues(datatypeCtors) && Contract.ForAll(datatypeCtors.Values, v => cce.NonNullDictionaryAndValues(v)));\n      Contract.Invariant(!inBodyInitContext || currentMethod is Constructor);\n    }\n\n    public ValuetypeDecl AsValuetypeDecl(Type t) {\n      Contract.Requires(t != null);\n      foreach (var vtd in valuetypeDecls) {\n        if (vtd.IsThisType(t)) {\n          return vtd;\n        }\n      }\n      return null;\n    }\n\n    /// <summary>\n    /// Check that now two modules that are being compiled have the same CompileName.\n    ///\n    /// This could happen if they are given the same name using the 'extern' declaration modifier.\n    /// </summary>\n    /// <param name=\"prog\">The Dafny program being compiled.</param>\n    void CheckDupModuleNames(Program prog) {\n      // Check that none of the modules have the same CompileName.\n      Dictionary<string, ModuleDefinition> compileNameMap = new Dictionary<string, ModuleDefinition>();\n      foreach (ModuleDefinition m in prog.CompileModules) {\n        if (m.IsAbstract) {\n          // the purpose of an abstract module is to skip compilation\n          continue;\n        }\n        string compileName = m.CompileName;\n        ModuleDefinition priorModDef;\n        if (compileNameMap.TryGetValue(compileName, out priorModDef)) {\n          reporter.Error(MessageSource.Resolver, m.tok,\n            \"Modules '{0}' and '{1}' both have CompileName '{2}'.\",\n            priorModDef.tok.val, m.tok.val, compileName);\n        } else {\n          compileNameMap.Add(compileName, m);\n        }\n      }\n    }\n    public void ResolveProgram(Program prog) {\n      Contract.Requires(prog != null);\n      Type.ResetScopes();\n\n      Type.EnableScopes();\n      var origErrorCount = reporter.Count(ErrorLevel.Error); //TODO: This is used further below, but not in the >0 comparisons in the next few lines. Is that right?\n      var bindings = new ModuleBindings(null);\n      var b = BindModuleNames(prog.DefaultModuleDef, bindings);\n      bindings.BindName(prog.DefaultModule.Name, prog.DefaultModule, b);\n      if (reporter.Count(ErrorLevel.Error) > 0) { return; } // if there were errors, then the implict ModuleBindings data structure invariant\n      // is violated, so Processing dependencies will not succeed.\n      ProcessDependencies(prog.DefaultModule, b, dependencies);\n      // check for cycles in the import graph\n      foreach (var cycle in dependencies.AllCycles()) {\n        var cy = Util.Comma(\" -> \", cycle, m => m.Name);\n        reporter.Error(MessageSource.Resolver, cycle[0], \"module definition contains a cycle (note: parent modules implicitly depend on submodules): {0}\", cy);\n      }\n      if (reporter.Count(ErrorLevel.Error) > 0) { return; } // give up on trying to resolve anything else\n\n      // fill in module heights\n      List<ModuleDecl> sortedDecls = dependencies.TopologicallySortedComponents();\n      int h = 0;\n      foreach (ModuleDecl md in sortedDecls) {\n        md.Height = h;\n        if (md is LiteralModuleDecl) {\n          var mdef = ((LiteralModuleDecl)md).ModuleDef;\n          mdef.Height = h;\n          prog.ModuleSigs.Add(mdef, null);\n        }\n        h++;\n      }\n\n      rewriters = new List<IRewriter>();\n      refinementTransformer = new RefinementTransformer(prog);\n      rewriters.Add(refinementTransformer);\n      rewriters.Add(new StateMachineTranslator(prog));\n      rewriters.Add(new AutoContractsRewriter(reporter, builtIns));\n      rewriters.Add(new OpaqueFunctionRewriter(this.reporter));\n      rewriters.Add(new AutoReqFunctionRewriter(this.reporter));\n      rewriters.Add(new TimeLimitRewriter(reporter));\n      rewriters.Add(new ForallStmtRewriter(reporter));\n      rewriters.Add(new ProvideRevealAllRewriter(this.reporter));\n\n      if (ArmadaOptions.O.AutoTriggers) {\n        // rewriters.Add(new QuantifierSplittingRewriter(reporter));\n        // rewriters.Add(new TriggerGeneratingRewriter(reporter));\n      }\n\n      // rewriters.Add(new InductionRewriter(reporter));\n\n      systemNameInfo = RegisterTopLevelDecls(prog.BuiltIns.SystemModule, false);\n      prog.CompileModules.Add(prog.BuiltIns.SystemModule);\n      RevealAllInScope(prog.BuiltIns.SystemModule.TopLevelDecls, systemNameInfo.VisibilityScope);\n      ResolveValuetypeDecls();\n      // The SystemModule is constructed with all its members already being resolved. Except for\n      // the non-null type corresponding to class types.  They are resolved here:\n      var systemModuleClassesWithNonNullTypes = new List<TopLevelDecl>(prog.BuiltIns.SystemModule.TopLevelDecls.Where(d => d is ClassDecl && ((ClassDecl)d).NonNullTypeDecl != null));\n      foreach (var cl in systemModuleClassesWithNonNullTypes) {\n        var d = ((ClassDecl)cl).NonNullTypeDecl;\n        allTypeParameters.PushMarker();\n        ResolveTypeParameters(d.TypeArgs, true, d);\n        ResolveType(d.tok, d.Rhs, d, ResolveTypeOptionEnum.AllowPrefix, d.TypeArgs);\n        allTypeParameters.PopMarker();\n      }\n      ResolveTopLevelDecls_Core(systemModuleClassesWithNonNullTypes, new Graph<IndDatatypeDecl>(), new Graph<CoDatatypeDecl>());\n\n      var compilationModuleClones = new Dictionary<ModuleDefinition, ModuleDefinition>();\n      foreach (var decl in sortedDecls) {\n        if (decl is LiteralModuleDecl) {\n          // The declaration is a literal module, so it has members and such that we need\n          // to resolve. First we do refinement transformation. Then we construct the signature\n          // of the module. This is the public, externally visible signature. Then we add in\n          // everything that the system defines, as well as any \"import\" (i.e. \"opened\" modules)\n          // directives (currently not supported, but this is where we would do it.) This signature,\n          // which is only used while resolving the members of the module is stored in the (basically)\n          // global variable moduleInfo. Then the signatures of the module members are resolved, followed\n          // by the bodies.\n          var literalDecl = (LiteralModuleDecl)decl;\n          var m = literalDecl.ModuleDef;\n\n          if (m.ModuleType == ArmadaModuleType.ArmadaProof) {\n            var rpg = new RefinementProofGenerator(prog, m, b);\n            rpg.GenerateProof();\n          }\n\n          if (m.ModuleType == ArmadaModuleType.ArmadaLevel && m.StructsModuleName != null) {\n            ModuleDecl structsModuleDecl;\n            if (!b.TryLookup(m.StructsModuleName, out structsModuleDecl)) {\n              reporter.Error(MessageSource.Resolver, m.StructsModuleName, \"Could not find structs module named {m.StructsModuleName}\");\n            }\n            else if (!(structsModuleDecl is LiteralModuleDecl)) {\n              reporter.Error(MessageSource.Resolver, m.StructsModuleName, \"Module named {m.StructsModuleName} is not a valid module\");\n            }\n            else {\n              var structsModuleLiteralDecl = (LiteralModuleDecl)structsModuleDecl;\n              var structsModuleDef = structsModuleLiteralDecl.ModuleDef;\n              if (structsModuleDef.ModuleType != ArmadaModuleType.ArmadaStructs) {\n                reporter.Error(MessageSource.Resolver, m.StructsModuleName, \"Module named {m.StructsModuleName} is not a structs module\");\n              }\n              else {\n                m.ArmadaStructs = structsModuleDef.ArmadaStructs;\n              }\n            }\n          }\n\n          var errorCount = reporter.Count(ErrorLevel.Error);\n          foreach (var r in rewriters) {\n            r.PreResolve(m);\n          }\n\n          literalDecl.Signature = RegisterTopLevelDecls(m, true);\n          literalDecl.Signature.Refines = refinementTransformer.RefinedSig;\n\n          var sig = literalDecl.Signature;\n          // set up environment\n          var preResolveErrorCount = reporter.Count(ErrorLevel.Error);\n\n          ResolveModuleExport(literalDecl, sig);\n          var good = ResolveModuleDefinition(m, sig);\n\n          if (good && reporter.Count(ErrorLevel.Error) == preResolveErrorCount) {\n            // Check that the module export gives a self-contained view of the module.\n            CheckModuleExportConsistency(m);\n          }\n\n          var tempVis = new VisibilityScope();\n          tempVis.Augment(sig.VisibilityScope);\n          tempVis.Augment(systemNameInfo.VisibilityScope);\n          Type.PushScope(tempVis);\n\n          prog.ModuleSigs[m] = sig;\n\n          foreach (var r in rewriters) {\n            if (!good || reporter.Count(ErrorLevel.Error) != preResolveErrorCount) {\n              break;\n            }\n            r.PostResolve(m);\n          }\n          if (good && reporter.Count(ErrorLevel.Error) == errorCount) {\n            m.SuccessfullyResolved = true;\n          }\n          Type.PopScope(tempVis);\n\n          if (reporter.Count(ErrorLevel.Error) == errorCount && !m.IsAbstract && m.ModuleType != ArmadaModuleType.ArmadaLevel && m.ModuleType != ArmadaModuleType.ArmadaStructs) {\n            // compilation should only proceed if everything is good, including the signature (which preResolveErrorCount does not include);\n            CompilationCloner cloner = new CompilationCloner(compilationModuleClones);\n            var nw = cloner.CloneModuleDefinition(m, m.CompileName + \"_Compile\");\n            compilationModuleClones.Add(m, nw);\n            var oldErrorsOnly = reporter.ErrorsOnly;\n            reporter.ErrorsOnly = true; // turn off warning reporting for the clone\n            // Next, compute the compile signature\n            Contract.Assert(!useCompileSignatures);\n            useCompileSignatures = true;  // set Resolver-global flag to indicate that Signatures should be followed to their CompiledSignature\n            Type.DisableScopes();\n            var compileSig = RegisterTopLevelDecls(nw, true);\n            compileSig.Refines = refinementTransformer.RefinedSig;\n            sig.CompileSignature = compileSig;\n            foreach (var exportDecl in sig.ExportSets.Values) {\n              exportDecl.Signature.CompileSignature = cloner.CloneModuleSignature(exportDecl.Signature, compileSig);\n            }\n            // Now we're ready to resolve the cloned module definition, using the compile signature\n\n            ResolveModuleDefinition(nw, compileSig);\n            prog.CompileModules.Add(nw);\n            useCompileSignatures = false;  // reset the flag\n            Type.EnableScopes();\n            reporter.ErrorsOnly = oldErrorsOnly;\n          }\n        } else if (decl is AliasModuleDecl) {\n          var alias = (AliasModuleDecl)decl;\n          // resolve the path\n          ModuleSignature p;\n          if (ResolveExport(alias, alias.Root, alias.Module, alias.Path, alias.Exports, out p, reporter)) {\n            if (alias.Signature == null) {\n              alias.Signature = p;\n            }\n          } else {\n            alias.Signature = new ModuleSignature(); // there was an error, give it a valid but empty signature\n          }\n        } else if (decl is ModuleFacadeDecl) {\n          var abs = (ModuleFacadeDecl)decl;\n          ModuleSignature p;\n          if (ResolveExport(abs, abs.Root, abs.Module, abs.Path, abs.Exports, out p, reporter)) {\n            abs.OriginalSignature = p;\n            abs.Signature = MakeAbstractSignature(p, abs.FullCompileName, abs.Height, prog.ModuleSigs, compilationModuleClones);\n          } else {\n            abs.Signature = new ModuleSignature(); // there was an error, give it a valid but empty signature\n          }\n        } else if (decl is ModuleExportDecl) {\n          ((ModuleExportDecl)decl).SetupDefaultSignature();\n\n          Contract.Assert(decl.Signature != null);\n          Contract.Assert(decl.Signature.VisibilityScope != null);\n\n        } else { Contract.Assert(false); }\n        Contract.Assert(decl.Signature != null);\n      }\n      if (reporter.Count(ErrorLevel.Error) != origErrorCount) {\n        // do nothing else\n        return;\n      }\n\n\n\n      // compute IsRecursive bit for mutually recursive functions and methods\n      foreach (var module in prog.Modules()) {\n        foreach (var clbl in ModuleDefinition.AllCallables(module.TopLevelDecls)) {\n          if (clbl is Function) {\n            var fn = (Function)clbl;\n            if (!fn.IsRecursive) {  // note, self-recursion has already been determined\n              int n = module.CallGraph.GetSCCSize(fn);\n              if (2 <= n) {\n                // the function is mutually recursive (note, the SCC does not determine self recursion)\n                fn.IsRecursive = true;\n              }\n            }\n            if (fn.IsRecursive && fn is FixpointPredicate) {\n              // this means the corresponding prefix predicate is also recursive\n              var prefixPred = ((FixpointPredicate)fn).PrefixPredicate;\n              if (prefixPred != null) {\n                prefixPred.IsRecursive = true;\n              }\n            }\n          } else {\n            var m = (Method)clbl;\n            if (!m.IsRecursive) {  // note, self-recursion has already been determined\n              int n = module.CallGraph.GetSCCSize(m);\n              if (2 <= n) {\n                // the function is mutually recursive (note, the SCC does not determine self recursion)\n                m.IsRecursive = true;\n              }\n            }\n          }\n        }\n        foreach (var r in rewriters) {\n          r.PostCyclicityResolve(module);\n        }\n      }\n\n\n      // fill in default decreases clauses:  for functions and methods, and for loops\n      FillInDefaultDecreasesClauses(prog);\n      foreach (var module in prog.Modules()) {\n        foreach (var clbl in ModuleDefinition.AllItersAndCallables(module.TopLevelDecls)) {\n          Statement body = null;\n          if (clbl is Method) {\n            body = ((Method)clbl).Body;\n          } else if (clbl is IteratorDecl) {\n            body = ((IteratorDecl)clbl).Body;\n          }\n          if (body != null) {\n            var c = new FillInDefaultLoopDecreases_Visitor(this, clbl);\n            c.Visit(body);\n          }\n        }\n      }\n      foreach (var module in prog.Modules()) {\n        foreach (var iter in ModuleDefinition.AllIteratorDecls(module.TopLevelDecls)) {\n          reporter.Info(MessageSource.Resolver, iter.tok, Printer.IteratorClassToString(iter));\n        }\n      }\n      // fill in other additional information\n      foreach (var module in prog.Modules()) {\n        foreach (var clbl in ModuleDefinition.AllItersAndCallables(module.TopLevelDecls)) {\n          Statement body = null;\n          if (clbl is FixpointLemma) {\n            body = ((FixpointLemma)clbl).PrefixLemma.Body;\n          } else if (clbl is Method) {\n            body = ((Method)clbl).Body;\n          } else if (clbl is IteratorDecl) {\n            body = ((IteratorDecl)clbl).Body;\n          }\n          if (body != null) {\n            var c = new ReportOtherAdditionalInformation_Visitor(this);\n            c.Visit(body);\n          }\n        }\n      }\n\n      // Determine, for each function, whether someone tries to adjust its fuel parameter\n      foreach (var module in prog.Modules()) {\n        CheckForFuelAdjustments(module.tok, module.Attributes, module);\n        foreach (var clbl in ModuleDefinition.AllItersAndCallables(module.TopLevelDecls)) {\n          Statement body = null;\n          if (clbl is Method) {\n            body = ((Method)clbl).Body;\n            CheckForFuelAdjustments(clbl.Tok, ((Method)clbl).Attributes, module);\n          } else if (clbl is IteratorDecl) {\n            body = ((IteratorDecl)clbl).Body;\n            CheckForFuelAdjustments(clbl.Tok, ((IteratorDecl)clbl).Attributes, module);\n          } else if (clbl is Function) {\n            CheckForFuelAdjustments(clbl.Tok, ((Function)clbl).Attributes, module);\n            var c = new FuelAdjustment_Visitor(this);\n            var bodyExpr = ((Function)clbl).Body;\n            if (bodyExpr != null) {\n              c.Visit(bodyExpr, new FuelAdjustment_Context(module));\n            }\n          }\n          if (body != null) {\n            var c = new FuelAdjustment_Visitor(this);\n            c.Visit(body, new FuelAdjustment_Context(module));\n          }\n        }\n      }\n\n      Type.DisableScopes();\n      CheckDupModuleNames(prog);\n    }\n\n    void FillInDefaultDecreasesClauses(Program prog) {\n      Contract.Requires(prog != null);\n\n      foreach (var module in prog.Modules()) {\n        Contract.Assert(Type.GetScope() != null);\n        foreach (var clbl in ModuleDefinition.AllCallables(module.TopLevelDecls)) {\n          ICallable m;\n          string s;\n          if (clbl is FixpointLemma) {\n            var prefixLemma = ((FixpointLemma)clbl).PrefixLemma;\n            m = prefixLemma;\n            s = prefixLemma.Name + \" \";\n          } else {\n            m = clbl;\n            s = \"\";\n          }\n          var anyChangeToDecreases = FillInDefaultDecreases(m, true);\n\n          if (anyChangeToDecreases || m.InferredDecreases || m is PrefixLemma) {\n            bool showIt = false;\n            if (m is Function) {\n              // show the inferred decreases clause only if it will ever matter, i.e., if the function is recursive\n              showIt = ((Function)m).IsRecursive;\n            } else if (m is PrefixLemma) {\n              // always show the decrease clause, since at the very least it will start with \"_k\", which the programmer did not write explicitly\n              showIt = true;\n            } else {\n              showIt = ((Method)m).IsRecursive;\n            }\n            if (showIt) {\n              s += \"decreases \" + Util.Comma(\", \", m.Decreases.Expressions, Printer.ExprToString);\n              // Note, in the following line, we use the location information for \"clbl\", not \"m\".  These\n              // are the same, except in the case where \"clbl\" is a CoLemma and \"m\" is a prefix lemma.\n              reporter.Info(MessageSource.Resolver, clbl.Tok, s);\n            }\n          }\n        }\n      }\n    }\n\n    /// <summary>\n    /// Return \"true\" if this routine makes any change to the decreases clause.  If the decreases clause\n    /// starts off essentially empty and a default is provided, then clbl.InferredDecreases is also set\n    /// to true.\n    /// </summary>\n    bool FillInDefaultDecreases(ICallable clbl, bool addPrefixInCoClusters) {\n      Contract.Requires(clbl != null);\n\n      if (clbl is FixpointPredicate) {\n        // fixpoint-predicates don't have decreases clauses\n        return false;\n      }\n      var anyChangeToDecreases = false;\n      var decr = clbl.Decreases.Expressions;\n      if (ArmadaOptions.O.Dafnycc) {\n        if (decr.Count > 1) {\n          reporter.Error(MessageSource.Resolver, decr[1].tok, \"In dafnycc mode, only one decreases expression is allowed\");\n        }\n        // In dafnycc mode, only consider first argument\n        if (decr.Count == 0 && clbl.Ins.Count > 0) {\n          var p = clbl.Ins[0];\n          if (!(p is ImplicitFormal) && p.Type.IsOrdered) {\n            var ie = new IdentifierExpr(p.tok, p.Name);\n            ie.Var = p; ie.Type = p.Type;  // resolve it here\n            decr.Add(ie);\n            return true;\n          }\n        }\n        return false;\n      }\n      if (decr.Count == 0 || (clbl is PrefixLemma && decr.Count == 1)) {\n        // The default for a function starts with the function's reads clause, if any\n        if (clbl is Function) {\n          var fn = (Function)clbl;\n          if (fn.Reads.Count != 0) {\n            // start the default lexicographic tuple with the reads clause\n            var r = FrameToObjectSet(fn.Reads);\n            decr.Add(AutoGeneratedExpression.Create(r));\n            anyChangeToDecreases = true;\n          }\n        }\n\n        // Add one component for each parameter, unless the parameter's type is one that\n        // doesn't appear useful to orderings.\n        foreach (var p in clbl.Ins) {\n          if (!(p is ImplicitFormal) && p.Type.IsOrdered) {\n            var ie = new IdentifierExpr(p.tok, p.Name);\n            ie.Var = p; ie.Type = p.Type;  // resolve it here\n            decr.Add(AutoGeneratedExpression.Create(ie));\n            anyChangeToDecreases = true;\n          }\n        }\n\n        clbl.InferredDecreases = true;  // this indicates that finding a default decreases clause was attempted\n      }\n      if (addPrefixInCoClusters && clbl is Function) {\n        var fn = (Function)clbl;\n        switch (fn.CoClusterTarget) {\n          case Function.CoCallClusterInvolvement.None:\n            break;\n          case Function.CoCallClusterInvolvement.IsMutuallyRecursiveTarget:\n            // prefix: decreases 0,\n            clbl.Decreases.Expressions.Insert(0, Expression.CreateIntLiteral(fn.tok, 0));\n            anyChangeToDecreases = true;\n            break;\n          case Function.CoCallClusterInvolvement.CoRecursiveTargetAllTheWay:\n            // prefix: decreases 1,\n            clbl.Decreases.Expressions.Insert(0, Expression.CreateIntLiteral(fn.tok, 1));\n            anyChangeToDecreases = true;\n            break;\n          default:\n            Contract.Assume(false);  // unexpected case\n            break;\n        }\n      }\n      return anyChangeToDecreases;\n    }\n\n    public Expression FrameArrowToObjectSet(Expression e, FreshIdGenerator idGen) {\n      Contract.Requires(e != null);\n      Contract.Requires(idGen != null);\n      return FrameArrowToObjectSet(e, idGen, builtIns);\n    }\n\n    public static Expression FrameArrowToObjectSet(Expression e, FreshIdGenerator idGen, BuiltIns builtIns) {\n      Contract.Requires(e != null);\n      Contract.Requires(idGen != null);\n      Contract.Requires(builtIns != null);\n      var arrTy = e.Type.AsArrowType;\n      if (arrTy != null) {\n        var bvars = new List<BoundVar>();\n        var bexprs = new List<Expression>();\n        foreach (var t in arrTy.Args) {\n          var bv = new BoundVar(e.tok, idGen.FreshId(\"_x\"), t);\n          bvars.Add(bv);\n          bexprs.Add(new IdentifierExpr(e.tok, bv.Name) { Type = bv.Type, Var = bv });\n        }\n        var oVar = new BoundVar(e.tok, idGen.FreshId(\"_o\"), builtIns.ObjectQ());\n        var obj = new IdentifierExpr(e.tok, oVar.Name) { Type = oVar.Type, Var = oVar };\n        bvars.Add(oVar);\n\n        return\n          new SetComprehension(e.tok, true, bvars,\n            new BinaryExpr(e.tok, BinaryExpr.Opcode.In, obj,\n              new ApplyExpr(e.tok, e, bexprs) {\n                Type = new SetType(true, builtIns.ObjectQ())\n              }) {\n              ResolvedOp = BinaryExpr.ResolvedOpcode.InSet,\n              Type = Type.Bool\n            }, obj, null) {\n            Type = new SetType(true, builtIns.ObjectQ())\n          };\n      } else {\n        return e;\n      }\n    }\n\n    public Expression FrameToObjectSet(List<FrameExpression> fexprs) {\n      Contract.Requires(fexprs != null);\n      Contract.Ensures(Contract.Result<Expression>() != null);\n\n      List<Expression> sets = new List<Expression>();\n      List<Expression> singletons = null;\n      var idGen = new FreshIdGenerator();\n      foreach (FrameExpression fe in fexprs) {\n        Contract.Assert(fe != null);\n        if (fe.E is WildcardExpr) {\n          // drop wildcards altogether\n        } else {\n          Expression e = FrameArrowToObjectSet(fe.E, idGen);  // keep only fe.E, drop any fe.Field designation\n          Contract.Assert(e.Type != null);  // should have been resolved already\n          var eType = e.Type.NormalizeExpand();\n          if (eType.IsRefType) {\n            // e represents a singleton set\n            if (singletons == null) {\n              singletons = new List<Expression>();\n            }\n            singletons.Add(e);\n          } else if (eType is SeqType || eType is MultiSetType) {\n            // e represents a sequence or multiset\n            // Add:  set x :: x in e\n            var bv = new BoundVar(e.tok, idGen.FreshId(\"_s2s_\"), ((CollectionType)eType).Arg);\n            var bvIE = new IdentifierExpr(e.tok, bv.Name);\n            bvIE.Var = bv;  // resolve here\n            bvIE.Type = bv.Type;  // resolve here\n            var sInE = new BinaryExpr(e.tok, BinaryExpr.Opcode.In, bvIE, e);\n            if (eType is SeqType) {\n              sInE.ResolvedOp = BinaryExpr.ResolvedOpcode.InSeq;  // resolve here\n            } else {\n              sInE.ResolvedOp = BinaryExpr.ResolvedOpcode.InMultiSet; // resolve here\n            }\n            sInE.Type = Type.Bool;  // resolve here\n            var s = new SetComprehension(e.tok, true, new List<BoundVar>() { bv }, sInE, bvIE, null);\n            s.Type = new SetType(true, builtIns.ObjectQ());  // resolve here\n            sets.Add(s);\n          } else {\n            // e is already a set\n            Contract.Assert(eType is SetType);\n            sets.Add(e);\n          }\n        }\n      }\n      if (singletons != null) {\n        Expression display = new SetDisplayExpr(singletons[0].tok, true, singletons);\n        display.Type = new SetType(true, builtIns.ObjectQ());  // resolve here\n        sets.Add(display);\n      }\n      if (sets.Count == 0) {\n        Expression emptyset = new SetDisplayExpr(Token.NoToken, true, new List<Expression>());\n        emptyset.Type = new SetType(true, builtIns.ObjectQ());  // resolve here\n        return emptyset;\n      } else {\n        Expression s = sets[0];\n        for (int i = 1; i < sets.Count; i++) {\n          BinaryExpr union = new BinaryExpr(s.tok, BinaryExpr.Opcode.Add, s, sets[i]);\n          union.ResolvedOp = BinaryExpr.ResolvedOpcode.Union;  // resolve here\n          union.Type = new SetType(true, builtIns.ObjectQ());  // resolve here\n          s = union;\n        }\n        return s;\n      }\n    }\n\n    private void ResolveValuetypeDecls() {\n      moduleInfo = systemNameInfo;\n      foreach (var valueTypeDecl in valuetypeDecls) {\n        foreach (var kv in valueTypeDecl.Members) {\n          if (kv.Value is Function) {\n            ResolveFunctionSignature((Function)kv.Value);\n          } else if (kv.Value is Method) {\n            ResolveMethodSignature((Method)kv.Value);\n          }\n        }\n      }\n    }\n\n    /// <summary>\n    /// Resolves the module definition.\n    /// A return code of \"false\" is an indication of an error that may or may not have\n    /// been reported in an error message. So, in order to figure out if m was successfully\n    /// resolved, a caller has to check for both a change in error count and a \"false\"\n    /// return value.\n    /// </summary>\n    private bool ResolveModuleDefinition(ModuleDefinition m, ModuleSignature sig) {\n      Contract.Requires(AllTypeConstraints.Count == 0);\n      Contract.Ensures(AllTypeConstraints.Count == 0);\n\n      sig.VisibilityScope.Augment(systemNameInfo.VisibilityScope);\n      // make sure all imported modules were successfully resolved\n      foreach (var d in m.TopLevelDecls) {\n        if (d is AliasModuleDecl || d is ModuleFacadeDecl) {\n          ModuleSignature importSig;\n          if (d is AliasModuleDecl) {\n            var alias = (AliasModuleDecl)d;\n            importSig = alias.Root != null ? alias.Root.Signature : alias.Signature;\n          } else {\n            importSig = ((ModuleFacadeDecl)d).OriginalSignature;\n          }\n          if (importSig.ModuleDef == null || !importSig.ModuleDef.SuccessfullyResolved) {\n            if (!m.IsEssentiallyEmptyModuleBody()) {  // say something only if this will cause any testing to be omitted\n              reporter.Error(MessageSource.Resolver, d, \"not resolving module '{0}' because there were errors in resolving its import '{1}'\", m.Name, d.Name);\n            }\n            return false;\n          }\n        } else if (d is LiteralModuleDecl) {\n          var nested = (LiteralModuleDecl)d;\n          if (!nested.ModuleDef.SuccessfullyResolved) {\n            if (!m.IsEssentiallyEmptyModuleBody()) {  // say something only if this will cause any testing to be omitted\n              reporter.Error(MessageSource.Resolver, nested, \"not resolving module '{0}' because there were errors in resolving its nested module '{1}'\", m.Name, nested.Name);\n            }\n            return false;\n          }\n        }\n      }\n\n      // resolve\n      var oldModuleInfo = moduleInfo;\n      moduleInfo = MergeSignature(sig, systemNameInfo);\n      Type.PushScope(moduleInfo.VisibilityScope);\n      ResolveOpenedImports(moduleInfo, m, useCompileSignatures, this); // opened imports do not persist\n      var datatypeDependencies = new Graph<IndDatatypeDecl>();\n      var codatatypeDependencies = new Graph<CoDatatypeDecl>();\n      int prevErrorCount = reporter.Count(ErrorLevel.Error);\n      ResolveTopLevelDecls_Signatures(m, sig, m.TopLevelDecls, datatypeDependencies, codatatypeDependencies);\n      Contract.Assert(AllTypeConstraints.Count == 0);  // signature resolution does not add any type constraints\n      ResolveAttributes(m.Attributes, m, new ResolveOpts(new NoContext(m.Module), false)); // Must follow ResolveTopLevelDecls_Signatures, in case attributes refer to members\n      SolveAllTypeConstraints();  // solve any type constraints entailed by the attributes\n      if (reporter.Count(ErrorLevel.Error) == prevErrorCount) {\n        ResolveTopLevelDecls_Core(m.TopLevelDecls, datatypeDependencies, codatatypeDependencies);\n      }\n      Type.PopScope(moduleInfo.VisibilityScope);\n      moduleInfo = oldModuleInfo;\n      return true;\n    }\n\n    // Resolve the exports and detect cycles.\n    private void ResolveModuleExport(LiteralModuleDecl literalDecl, ModuleSignature sig) {\n      ModuleDefinition m = literalDecl.ModuleDef;\n      literalDecl.DefaultExport = sig;\n      Graph<ModuleExportDecl> exportDependencies = new Graph<ModuleExportDecl>();\n      foreach (TopLevelDecl toplevel in m.TopLevelDecls) {\n        if (toplevel is ModuleExportDecl) {\n          ModuleExportDecl d = (ModuleExportDecl)toplevel;\n          exportDependencies.AddVertex(d);\n          foreach (string s in d.Extends) {\n            ModuleExportDecl extend;\n            if (sig.ExportSets.TryGetValue(s, out extend)) {\n              d.ExtendDecls.Add(extend);\n              exportDependencies.AddEdge(d, extend);\n            } else {\n              reporter.Error(MessageSource.Resolver, m.tok, s + \" must be an export of \" + m.Name + \" to be extended\");\n            }\n          }\n        }\n      }\n\n      // detect cycles in the extend\n      var cycleError = false;\n      foreach (var cycle in exportDependencies.AllCycles()) {\n        var cy = Util.Comma(\" -> \", cycle, c => c.Name);\n        reporter.Error(MessageSource.Resolver, cycle[0], \"module export contains a cycle: {0}\", cy);\n        cycleError = true;\n      }\n      if (cycleError) { return; } // give up on trying to resolve anything else\n\n      // fill in the exports for the extends.\n      List<ModuleExportDecl> sortedExportDecls = exportDependencies.TopologicallySortedComponents();\n      ModuleExportDecl defaultExport = null;\n      TopLevelDecl defaultClass;\n\n      sig.TopLevels.TryGetValue(\"_default\", out defaultClass);\n      Contract.Assert(defaultClass is ClassDecl);\n      Contract.Assert(((ClassDecl)defaultClass).IsDefaultClass);\n      defaultClass.AddVisibilityScope(m.VisibilityScope, true);\n\n      foreach (var d in sortedExportDecls) {\n\n        defaultClass.AddVisibilityScope(d.ThisScope, true);\n\n        foreach (var eexports in d.ExtendDecls.Select(e => e.Exports)) {\n          d.Exports.AddRange(eexports);\n        }\n\n        if (d.ExtendDecls.Count == 0 && d.Exports.Count == 0) {\n          // This is an empty export.  This is allowed, but unusual.  It could pop up, for example, if\n          // someone temporary comments out everything that the export set provides/reveals.  However,\n          // if the name of the export set coincides with something else that's declared at the top\n          // level of the module, then this export declaration is more likely an error--the user probably\n          // forgot the \"provides\" or \"reveals\" keyword.\n          Dictionary<string, MemberDecl> members;\n          MemberDecl member;\n          // Top-level functions and methods are actually recorded as members of the _default class.  We look up the\n          // export-set name there.  If the export-set name happens to coincide with some other top-level declaration,\n          // then an error will already have been produced (\"duplicate name of top-level declaration\").\n          if (classMembers.TryGetValue((ClassDecl)defaultClass, out members) && members.TryGetValue(d.Name, out member)) {\n            reporter.Warning(MessageSource.Resolver, d.tok, \"note, this export set is empty (did you perhaps forget the 'provides' or 'reveals' keyword?)\");\n          }\n        }\n\n        foreach (ExportSignature export in d.Exports) {\n\n          // check to see if it is a datatype or a member or\n          // static function or method in the enclosing module or its imports\n          TopLevelDecl tdecl;\n          MemberDecl member;\n          TopLevelDecl cldecl;\n\n          Declaration decl = null;\n          string name = export.Id;\n\n          if (export.ClassId != null) {\n            if (sig.TopLevels.TryGetValue(export.ClassId, out cldecl) &&\n              ((cldecl is ClassDecl && ((ClassDecl)cldecl).NonNullTypeDecl == null) || cldecl is NonNullTypeDecl)) {  // we are looking for a class name, not a type name\n              var cl = (ClassDecl)cldecl.ViewAsClass;\n              var lmem = cl.Members.FirstOrDefault(l => l.Name == export.Id);\n              if (lmem != null) {\n                decl = lmem;\n              } else {\n                reporter.Error(MessageSource.Resolver, export.Tok, \"No member '{0}' found in class '{1}'\", export.Id, export.ClassId);\n                continue;\n              }\n            } else {\n              reporter.Error(MessageSource.Resolver, export.ClassIdTok, \"No class '{0}' found\", export.ClassId);\n              continue;\n            }\n          } else if (sig.TopLevels.TryGetValue(name, out tdecl) && (!(tdecl is ClassDecl) || ((ClassDecl)tdecl).NonNullTypeDecl == null)) {  // pretend that C? types are not there\n            // Member of the enclosing module\n            decl = tdecl.ViewAsClass;  // interpret the export as a class name, not a type name\n          } else if (sig.StaticMembers.TryGetValue(name, out member)) {\n            decl = member;\n          } else if (sig.ExportSets.ContainsKey(name)) {\n            reporter.Error(MessageSource.Resolver, export.Tok, \"'{0}' is an export set and cannot be provided/revealed by another export set (did you intend to list it in an \\\"extends\\\"?)\", name);\n            continue;\n          } else {\n            reporter.Error(MessageSource.Resolver, export.Tok, \"'{0}' must be a member of '{1}' to be exported\", name, m.Name);\n            continue;\n          }\n\n          if (!decl.CanBeExported()) {\n            reporter.Error(MessageSource.Resolver, export.Tok, \"'{0}' is not a valid export of '{1}'\", name, m.Name);\n            continue;\n          }\n\n          if (!export.Opaque && !decl.CanBeRevealed()) {\n            reporter.Error(MessageSource.Resolver, export.Tok, \"'{0}' cannot be revealed in an export. Use \\\"provides\\\" instead.\", name);\n            continue;\n          }\n\n          export.Decl = decl;\n          decl.AddVisibilityScope(d.ThisScope, export.Opaque);\n\n          if (export.Decl is ClassDecl) {\n            var cl = (ClassDecl)export.Decl;\n            if (cl.NonNullTypeDecl != null) {\n              cl.NonNullTypeDecl.AddVisibilityScope(d.ThisScope, false);  // the associated non-null type is always exported as revealed\n            }\n            if (!export.Opaque) {\n              foreach (var mdecl in cl.Members) {\n                mdecl.AddVisibilityScope(d.ThisScope, false);\n              }\n            }\n          }\n        }\n      }\n\n      foreach (ModuleExportDecl decl in sortedExportDecls) {\n        if (decl.IsDefault) {\n          if (defaultExport == null) {\n            defaultExport = decl;\n          } else {\n            reporter.Error(MessageSource.Resolver, m.tok, \"more than one default export set declared in module {0}\", m.Name);\n          }\n        }\n        // fill in export signature\n        ModuleSignature signature = decl.Signature;\n        signature.ModuleDef = m;\n\n\n        foreach (var top in sig.TopLevels.Where(t => t.Value.IsVisibleInScope(signature.VisibilityScope) && t.Value.CanBeExported())) {\n          if (!signature.TopLevels.ContainsKey(top.Key)) {\n            signature.TopLevels.Add(top.Key, top.Value);\n          }\n\n          if (top.Value is DatatypeDecl && top.Value.IsRevealedInScope(signature.VisibilityScope)) {\n            foreach (var ctor in ((DatatypeDecl)top.Value).Ctors) {\n              if (!signature.Ctors.ContainsKey(ctor.Name)) {\n                signature.Ctors.Add(ctor.Name, new Tuple<DatatypeCtor, bool>(ctor, false));\n              }\n            }\n          }\n\n          foreach (var mem in sig.StaticMembers.Where(t => t.Value.IsVisibleInScope(signature.VisibilityScope) && t.Value.CanBeExported())) {\n            if (!signature.StaticMembers.ContainsKey(mem.Key)) {\n              signature.StaticMembers.Add(mem.Key, (MemberDecl)mem.Value);\n            }\n          }\n\n        }\n\n      }\n\n\n      // set the default export set, if it exists\n      if (defaultExport != null) {\n        literalDecl.DefaultExport = defaultExport.Signature;\n      } else if (sortedExportDecls.Count > 0) {\n        literalDecl.DefaultExport = null;\n      }\n\n      // final pass to propagate visibility of exported imports\n      var sigs = sortedExportDecls.Select(d => d.Signature).Concat1(sig);\n\n      foreach (var s in sigs) {\n        foreach (var decl in s.TopLevels) {\n          if (decl.Value is ModuleDecl && !(decl.Value is ModuleExportDecl)) {\n            var modDecl = (ModuleDecl)decl.Value;\n            s.VisibilityScope.Augment(modDecl.AccessibleSignature().VisibilityScope);\n          }\n        }\n      }\n\n      HashSet<Tuple<Declaration, bool>> exported = new HashSet<Tuple<Declaration, bool>>();\n\n      //some decls may not be set due to resolution errors\n      foreach (var e in sortedExportDecls.SelectMany(e => e.Exports).Where(e => e.Decl != null)) {\n        var decl = e.Decl;\n        exported.Add(new Tuple<Declaration, bool>(decl, e.Opaque));\n        if (!e.Opaque && decl.CanBeRevealed()) {\n          exported.Add(new Tuple<Declaration, bool>(decl, true));\n        }\n\n        if (decl is ClassDecl && ((ClassDecl)decl).NonNullTypeDecl != null) {\n          decl = ((ClassDecl)decl).NonNullTypeDecl;\n          exported.Add(new Tuple<Declaration, bool>(decl, e.Opaque));\n          if (!e.Opaque && decl.CanBeRevealed()) {\n            exported.Add(new Tuple<Declaration, bool>(decl, true));\n          }\n        }\n\n        if (e.Opaque && (decl is DatatypeDecl || decl is TypeSynonymDecl)) {\n          // Datatypes and type synonyms are marked as _provided when they appear in any provided export.  If a\n          // declaration is never provided, then either it isn't visible outside the module at all or its whole\n          // definition is.  Datatype and type-synonym declarations undergo some inference from their definitions.\n          // Such inference should not be done for provided declarations, since different views of the module\n          // would then get different inferred properties.\n          decl.Attributes = new Attributes(\"_provided\", new List<Expression>(), decl.Attributes);\n          reporter.Info(MessageSource.Resolver, decl.tok, \"{:_provided}\");\n        }\n      }\n\n      Dictionary<RevealableTypeDecl, bool?> declScopes = new Dictionary<RevealableTypeDecl, bool?>();\n      Dictionary<RevealableTypeDecl, bool?> modifies = new Dictionary<RevealableTypeDecl, bool?>();\n\n      //of all existing types, compute the minimum visibility of them for each exported declaration's\n      //body and signature\n      foreach (var e in exported) {\n\n        declScopes.Clear();\n        modifies.Clear();\n\n        foreach (var typ in revealableTypes) {\n          declScopes.Add(typ, null);\n        }\n\n        foreach (var decl in sortedExportDecls) {\n          if (decl.Exports.Exists(ex => ex.Decl == e.Item1 && (e.Item2 || !ex.Opaque))) {\n            //if we are revealed, consider those exports where we are provided as well\n            var scope = decl.Signature.VisibilityScope;\n\n            foreach (var kv in declScopes) {\n              bool? isOpaque = kv.Value;\n              var typ = kv.Key;\n              if (!typ.AsTopLevelDecl.IsVisibleInScope(scope)) {\n                modifies[typ] = null;\n                continue;\n              }\n\n              if (isOpaque.HasValue && isOpaque.Value) {\n                //type is visible here, but known-opaque, so do nothing\n                continue;\n              }\n\n              modifies[typ] = !typ.AsTopLevelDecl.IsRevealedInScope(scope);\n            }\n\n            foreach (var kv in modifies) {\n              if (!kv.Value.HasValue) {\n                declScopes.Remove(kv.Key);\n              } else {\n                var exvis = declScopes[kv.Key];\n                if (exvis.HasValue) {\n                  declScopes[kv.Key] = exvis.Value || kv.Value.Value;\n                } else {\n                  declScopes[kv.Key] = kv.Value;\n                }\n              }\n            }\n            modifies.Clear();\n          }\n        }\n\n        VisibilityScope newscope = new VisibilityScope(true, e.Item1.Name);\n\n        foreach (var rt in declScopes) {\n          if (!rt.Value.HasValue)\n            continue;\n\n          rt.Key.AsTopLevelDecl.AddVisibilityScope(newscope, rt.Value.Value);\n        }\n      }\n    }\n\n    //check for export consistency by resolving internal modules\n    //this should be effect-free, as it only operates on clones\n    private void CheckModuleExportConsistency(ModuleDefinition m) {\n      var oldModuleInfo = moduleInfo;\n      foreach (var top in m.TopLevelDecls) {\n        if (!(top is ModuleExportDecl))\n          continue;\n\n        ModuleExportDecl decl = (ModuleExportDecl)top;\n\n        foreach (var export in decl.Exports) {\n          if (export.Decl is MemberDecl) {\n            var member = (MemberDecl)export.Decl;\n            if (!member.EnclosingClass.IsVisibleInScope(decl.Signature.VisibilityScope)) {\n              reporter.Error(MessageSource.Resolver, export.Tok, \"Cannot export class member '{0}' without providing its enclosing {1} '{2}'\", member.Name, member.EnclosingClass.WhatKind, member.EnclosingClass.Name);\n            }\n          }\n        }\n\n        reporter = new ErrorReporterWrapper(reporter,\n          String.Format(\"Raised while checking export set {0}: \", decl.Name));\n        var scope = decl.Signature.VisibilityScope;\n        Cloner cloner = new ScopeCloner(scope);\n        var exportView = cloner.CloneModuleDefinition(m, m.Name);\n\n        var testSig = RegisterTopLevelDecls(exportView, true);\n        //testSig.Refines = refinementTransformer.RefinedSig;\n        ResolveModuleDefinition(exportView, testSig);\n        var wasError = reporter.Count(ErrorLevel.Error) > 0;\n        reporter = ((ErrorReporterWrapper)reporter).WrappedReporter;\n\n        if (wasError) {\n          reporter.Error(MessageSource.Resolver, decl.tok, \"This export set is not consistent: {0}\", decl.Name);\n        }\n\n      }\n\n\n      moduleInfo = oldModuleInfo;\n    }\n\n    public class ModuleBindings\n    {\n      private ModuleBindings parent;\n      private Dictionary<string, ModuleDecl> modules;\n      private Dictionary<string, ModuleBindings> bindings;\n\n      public ModuleBindings(ModuleBindings p) {\n        parent = p;\n        modules = new Dictionary<string, ModuleDecl>();\n        bindings = new Dictionary<string, ModuleBindings>();\n      }\n      public bool BindName(string name, ModuleDecl subModule, ModuleBindings b) {\n        if (modules.ContainsKey(name)) {\n          return false;\n        } else {\n          modules.Add(name, subModule);\n          bindings.Add(name, b);\n          return true;\n        }\n      }\n\n      public bool TryLookup(IToken name, out ModuleDecl m) {\n        Contract.Requires(name != null);\n        return TryLookupFilter(name, out m, l => true);\n      }\n\n      public bool TryLookupFilter(IToken name, out ModuleDecl m, Func<ModuleDecl, bool> filter) {\n        Contract.Requires(name != null);\n        if (modules.TryGetValue(name.val, out m) && filter(m)) {\n          return true;\n        } else if (parent != null) {\n          return parent.TryLookupFilter(name, out m, filter);\n        } else return false;\n      }\n      public IEnumerable<ModuleDecl> ModuleList {\n        get { return modules.Values; }\n      }\n      public ModuleBindings SubBindings(string name) {\n        ModuleBindings v = null;\n        bindings.TryGetValue(name, out v);\n        return v;\n      }\n    }\n    private ModuleBindings BindModuleNames(ModuleDefinition moduleDecl, ModuleBindings parentBindings) {\n      var bindings = new ModuleBindings(parentBindings);\n\n      // moduleDecl.PrefixNamedModules is a list of pairs like:\n      //     A.B.C  ,  module D { ... }\n      // We collect these according to the first component of the prefix, like so:\n      //     \"A\"   ->   (A.B.C  ,  module D { ... })\n      var prefixNames = new Dictionary<string, List<Tuple<List<IToken>, LiteralModuleDecl>>>();\n      foreach (var tup in moduleDecl.PrefixNamedModules) {\n        var id = tup.Item1[0].val;\n        List<Tuple<List<IToken>, LiteralModuleDecl>> prev;\n        if (!prefixNames.TryGetValue(id, out prev)) {\n          prev = new List<Tuple<List<IToken>, LiteralModuleDecl>>();\n        }\n        prev.Add(tup);\n        prefixNames[id] = prev;\n      }\n      moduleDecl.PrefixNamedModules.Clear();\n\n      foreach (var tld in moduleDecl.TopLevelDecls) {\n        if (tld is LiteralModuleDecl) {\n          var subdecl = (LiteralModuleDecl)tld;\n          // Transfer prefix-named modules downwards into the sub-module\n          List<Tuple<List<IToken>, LiteralModuleDecl>> prefixModules;\n          if (prefixNames.TryGetValue(subdecl.Name, out prefixModules)) {\n            prefixNames.Remove(subdecl.Name);\n            prefixModules = prefixModules.ConvertAll(ShortenPrefix);\n          } else {\n            prefixModules = null;\n          }\n          BindModuleName_LiteralModuleDecl(subdecl, prefixModules, bindings);\n        } else if (tld is ModuleFacadeDecl) {\n          var subdecl = (ModuleFacadeDecl)tld;\n          if (!bindings.BindName(subdecl.Name, subdecl, null)) {\n            if (tld.Module.IsDefaultModule) {\n              // the import is not in a module.\n              reporter.Error(MessageSource.Resolver, subdecl.tok, \"Can't import module {0} when not inside of a module\", subdecl.Name);\n            } else {\n              reporter.Error(MessageSource.Resolver, subdecl.tok, \"Duplicate module name: {0}\", subdecl.Name);\n            }\n          }\n        } else if (tld is AliasModuleDecl) {\n          var subdecl = (AliasModuleDecl)tld;\n          if (!bindings.BindName(subdecl.Name, subdecl, null)) {\n            if (tld.Module.IsDefaultModule) {\n              // the import is not in a module.\n              reporter.Error(MessageSource.Resolver, subdecl.tok, \"Can't import module {0} when not inside of a module\", subdecl.Name);\n            } else {\n              reporter.Error(MessageSource.Resolver, subdecl.tok, \"Duplicate module name: {0}\", subdecl.Name);\n            }\n          }\n        }\n      }\n      // add new modules for any remaining entries in \"prefixNames\"\n      foreach (var entry in prefixNames) {\n        var name = entry.Key;\n        var prefixNamedModules = entry.Value;\n        var tok = prefixNamedModules.First().Item1[0];\n        var modDef = new ModuleDefinition(tok, name, new List<IToken>(), false, false, false, null, moduleDecl, null, false);\n        // Every module is expected to have a default class, so we create and add one now\n        var defaultClass = new DefaultClassDecl(modDef, new List<MemberDecl>());\n        modDef.TopLevelDecls.Add(defaultClass);\n        // Add the new module to the top-level declarations of its parent and then bind its names as usual\n        var subdecl = new LiteralModuleDecl(modDef, moduleDecl);\n        moduleDecl.TopLevelDecls.Add(subdecl);\n        BindModuleName_LiteralModuleDecl(subdecl, prefixNamedModules.ConvertAll(ShortenPrefix), bindings);\n      }\n      return bindings;\n    }\n\n    private Tuple<List<IToken>, LiteralModuleDecl> ShortenPrefix(Tuple<List<IToken>, LiteralModuleDecl> tup)\n    {\n      Contract.Requires(tup.Item1.Count != 0);\n      var rest = tup.Item1.GetRange(1, tup.Item1.Count - 1);\n      return new Tuple<List<IToken>, LiteralModuleDecl>(rest, tup.Item2);\n    }\n\n    private void BindModuleName_LiteralModuleDecl(LiteralModuleDecl litmod, List<Tuple<List<IToken>, LiteralModuleDecl>>/*?*/ prefixModules, ModuleBindings parentBindings) {\n      Contract.Requires(litmod != null);\n      Contract.Requires(parentBindings != null);\n\n      // Transfer prefix-named modules downwards into the sub-module\n      if (prefixModules != null) {\n        foreach (var tup in prefixModules) {\n          if (tup.Item1.Count == 0) {\n            tup.Item2.ModuleDef.Module = litmod.ModuleDef;  // change the parent, now that we have found the right parent module for the prefix-named module\n            var sm = new LiteralModuleDecl(tup.Item2.ModuleDef, litmod.ModuleDef);  // this will create a ModuleDecl with the right parent\n            litmod.ModuleDef.TopLevelDecls.Add(sm);\n          } else {\n            litmod.ModuleDef.PrefixNamedModules.Add(tup);\n          }\n        }\n      }\n\n      var bindings = BindModuleNames(litmod.ModuleDef, parentBindings);\n      if (!parentBindings.BindName(litmod.Name, litmod, bindings)) {\n        reporter.Error(MessageSource.Resolver, litmod.tok, \"Duplicate module name: {0}\", litmod.Name);\n      }\n    }\n\n    private void AddDependencyOnModuleDecl(ModuleDecl decl, ModuleDecl d, ModuleBindings bindings, Graph<ModuleDecl> dependencies) {\n      dependencies.AddEdge(decl, d);\n      var subbindings = bindings.SubBindings(d.Name);\n      ProcessDependencies(d, subbindings ?? bindings, dependencies);\n    }\n\n    private void ProcessDependenciesDefinition(ModuleDecl decl, ModuleDefinition m, ModuleBindings bindings, Graph<ModuleDecl> dependencies) {\n      if (m.RefinementBaseName != null) {\n        ModuleDecl other;\n        if (!bindings.TryLookup(m.RefinementBaseName, out other)) {\n          reporter.Error(MessageSource.Resolver, m.RefinementBaseName, \"module {0} named as refinement base does not exist\", m.RefinementBaseName.val);\n        } else if (other is LiteralModuleDecl && ((LiteralModuleDecl)other).ModuleDef == m) {\n          reporter.Error(MessageSource.Resolver, m.RefinementBaseName, \"module cannot refine itself: {0}\", m.RefinementBaseName.val);\n        } else {\n          Contract.Assert(other != null);  // follows from postcondition of TryGetValue\n          dependencies.AddEdge(decl, other);\n          m.RefinementBaseRoot = other;\n        }\n      }\n      if (m.Abstracts != null) {\n        ModuleDecl other;\n        if (!bindings.TryLookup(m.Abstracts, out other)) {\n          reporter.Error(MessageSource.Resolver, m.Abstracts, \"module {0} named as abstracts level does not exist\", m.Abstracts.val);\n        } else if (other is LiteralModuleDecl && ((LiteralModuleDecl)other).ModuleDef == m) {\n          reporter.Error(MessageSource.Resolver, m.Abstracts, \"module cannot abstract itself: {0}\", m.Abstracts.val);\n        } else {\n          Contract.Assert(other != null);  // follows from postcondition of TryGetValue\n          dependencies.AddEdge(decl, other);\n          m.AbstractsDecl = other;\n        }\n      }\n      foreach (var toplevel in m.TopLevelDecls) {\n        if (toplevel is ModuleDecl) {\n          var d = (ModuleDecl)toplevel;\n          AddDependencyOnModuleDecl(decl, d, bindings, dependencies);\n        }\n        else if (toplevel is RefinementParametersDecl) {\n          var rpd = (RefinementParametersDecl)toplevel;\n          ModuleDecl d;\n          if (bindings.TryLookup(rpd.LowLevel, out d)) {\n            AddDependencyOnModuleDecl(decl, d, bindings, dependencies);\n          }\n          if (bindings.TryLookup(rpd.HighLevel, out d)) {\n            AddDependencyOnModuleDecl(decl, d, bindings, dependencies);\n          }\n        }\n      }\n    }\n    private void ProcessDependencies(ModuleDecl moduleDecl, ModuleBindings bindings, Graph<ModuleDecl> dependencies) {\n      dependencies.AddVertex(moduleDecl);\n      if (moduleDecl is LiteralModuleDecl) {\n        ProcessDependenciesDefinition(moduleDecl, ((LiteralModuleDecl)moduleDecl).ModuleDef, bindings, dependencies);\n      } else if (moduleDecl is AliasModuleDecl) {\n        var alias = moduleDecl as AliasModuleDecl;\n        ModuleDecl root;\n        if (!bindings.TryLookupFilter(alias.Path[0], out root,\n          m => alias != m && (((alias.Module == m.Module) && (alias.Exports.Count == 0)) || m is LiteralModuleDecl)))\n          reporter.Error(MessageSource.Resolver, alias.tok, ModuleNotFoundErrorMessage(0, alias.Path));\n        else {\n          dependencies.AddEdge(moduleDecl, root);\n          alias.Root = root;\n        }\n      } else if (moduleDecl is ModuleFacadeDecl) {\n        var abs = moduleDecl as ModuleFacadeDecl;\n        ModuleDecl root;\n        if (!bindings.TryLookupFilter(abs.Path[0], out root,\n          m => abs != m && (((abs.Module == m.Module) && (abs.Exports.Count == 0)) || m is LiteralModuleDecl)))\n          reporter.Error(MessageSource.Resolver, abs.tok, ModuleNotFoundErrorMessage(0, abs.Path));\n        else {\n          dependencies.AddEdge(moduleDecl, root);\n          abs.Root = root;\n        }\n      }\n    }\n\n    private static string ModuleNotFoundErrorMessage(int i, List<IToken> path) {\n      Contract.Requires(path != null);\n      Contract.Requires(0 <= i && i < path.Count);\n      return \"module \" + path[i].val + \" does not exist\" +\n        (1 < path.Count ? \" (position \" + i.ToString() + \" in path \" + Util.Comma(\".\", path, x => x.val) + \")\" : \"\");\n    }\n\n    [Pure]\n    private static bool EquivIfPresent<T1, T2>(Dictionary<T1, T2> dic, T1 key, T2 val)\n    where T2 : class {\n      T2 val2;\n      if (dic.TryGetValue(key, out val2)) {\n        return val.Equals(val2);\n      }\n      return true;\n    }\n\n    public static ModuleSignature MergeSignature(ModuleSignature m, ModuleSignature system) {\n      Contract.Requires(m != null);\n      Contract.Requires(system != null);\n      var info = new ModuleSignature();\n      // add the system-declared information, among which we know there are no duplicates\n      foreach (var kv in system.TopLevels) {\n        info.TopLevels.Add(kv.Key, kv.Value);\n      }\n      foreach (var kv in system.Ctors) {\n        info.Ctors.Add(kv.Key, kv.Value);\n      }\n      foreach (var kv in system.StaticMembers) {\n        info.StaticMembers.Add(kv.Key, kv.Value);\n      }\n      // add for the module itself\n      foreach (var kv in m.TopLevels) {\n        Contract.Assert(EquivIfPresent(info.TopLevels, kv.Key, kv.Value));\n        info.TopLevels[kv.Key] = kv.Value;\n      }\n      foreach (var kv in m.Ctors) {\n        Contract.Assert(EquivIfPresent(info.Ctors, kv.Key, kv.Value));\n        info.Ctors[kv.Key] = kv.Value;\n      }\n      foreach (var kv in m.StaticMembers) {\n        Contract.Assert(EquivIfPresent(info.StaticMembers, kv.Key, kv.Value));\n        info.StaticMembers[kv.Key] = kv.Value;\n      }\n      info.IsAbstract = m.IsAbstract;\n      info.ModuleType = m.ModuleType;\n      info.VisibilityScope = new VisibilityScope();\n      info.VisibilityScope.Augment(m.VisibilityScope);\n      info.VisibilityScope.Augment(system.VisibilityScope);\n      return info;\n    }\n\n    public static void ResolveOpenedImports(ModuleSignature sig, ModuleDefinition moduleDef, bool useCompileSignatures, Resolver resolver) {\n      var declarations = sig.TopLevels.Values.ToList<TopLevelDecl>();\n      var importedSigs = new HashSet<ModuleSignature>() { sig };\n\n      foreach (var top in declarations) {\n        if (top is ModuleDecl && ((ModuleDecl)top).Opened) {\n          ResolveOpenedImportsWorker(sig, moduleDef, (ModuleDecl)top, importedSigs, useCompileSignatures);\n        }\n      }\n\n      if (resolver != null) { //needed because ResolveOpenedImports is used statically for a refinement check\n        if (sig.TopLevels[\"_default\"] is AmbiguousTopLevelDecl) {\n          Contract.Assert(sig.TopLevels[\"_default\"].WhatKind == \"class\");\n          var cl = new DefaultClassDecl(moduleDef, sig.StaticMembers.Values.ToList());\n          sig.TopLevels[\"_default\"] = cl;\n          resolver.classMembers[cl] = cl.Members.ToDictionary(m => m.Name);\n        }\n      }\n    }\n\n    static void ResolveOpenedImportsWorker(ModuleSignature sig, ModuleDefinition moduleDef, ModuleDecl im, HashSet<ModuleSignature> importedSigs, bool useCompileSignatures) {\n      bool useImports = true;\n      var s = GetSignatureExt(im.AccessibleSignature(useCompileSignatures), useCompileSignatures);\n\n      if (importedSigs.Contains(s)) {\n        return; // we've already got these declarations\n      }\n\n      importedSigs.Add(s);\n\n      if (useImports || ArmadaOptions.O.IronDafny) {\n        // classes:\n        foreach (var kv in s.TopLevels) {\n          if (!kv.Value.CanBeExported())\n            continue;\n\n          if (kv.Value is ModuleDecl && ((ModuleDecl)kv.Value).Opened && ArmadaOptions.O.IronDafny) {\n            ResolveOpenedImportsWorker(sig, moduleDef, (ModuleDecl)kv.Value, importedSigs, useCompileSignatures);\n          }\n\n          if (useImports && moduleDef.ModuleType == ArmadaModuleType.ArmadaLevel &&\n              string.Equals(kv.Key, \"_default\", StringComparison.InvariantCulture)) {\n            ClassDecl importedClass = (ClassDecl)kv.Value;\n            foreach (MemberDecl m in importedClass.Members) {\n              if ((m is Field || m is Method) && !sig.StaticMembers.ContainsKey(m.Name)) {\n                sig.StaticMembers[m.Name] = m;\n              }\n            }\n          }\n          // IronDafny: we need to pull the members of the opened module's _default class in so that they can be merged.\n          else if (useImports || string.Equals(kv.Key, \"_default\", StringComparison.InvariantCulture)) {\n            TopLevelDecl d;\n            if (sig.TopLevels.TryGetValue(kv.Key, out d)) {\n              sig.TopLevels[kv.Key] = AmbiguousTopLevelDecl.Create(moduleDef, d, kv.Value);\n            } else {\n              sig.TopLevels.Add(kv.Key, kv.Value);\n            }\n          }\n        }\n\n        if (useImports) {\n          // constructors:\n          foreach (var kv in s.Ctors) {\n            Tuple<DatatypeCtor, bool> pair;\n            if (sig.Ctors.TryGetValue(kv.Key, out pair)) {\n              // The same ctor can be imported from two different imports (e.g \"diamond\" imports), in which case,\n              // they are not duplicates.\n              if (!Object.ReferenceEquals(kv.Value.Item1, pair.Item1)) {\n                // mark it as a duplicate\n                sig.Ctors[kv.Key] = new Tuple<DatatypeCtor, bool>(pair.Item1, true);\n              }\n            } else {\n              // add new\n              sig.Ctors.Add(kv.Key, kv.Value);\n            }\n          }\n        }\n\n        if (useImports || ArmadaOptions.O.IronDafny) {\n          // static members:\n          foreach (var kv in s.StaticMembers) {\n            if (!kv.Value.CanBeExported())\n              continue;\n\n            MemberDecl md;\n            if (sig.StaticMembers.TryGetValue(kv.Key, out md)) {\n              sig.StaticMembers[kv.Key] = AmbiguousMemberDecl.Create(moduleDef, md, kv.Value);\n            } else {\n              // add new\n              sig.StaticMembers.Add(kv.Key, kv.Value);\n            }\n          }\n        }\n\n      }\n    }\n\n    ModuleSignature RegisterTopLevelDecls(ModuleDefinition moduleDef, bool useImports) {\n      Contract.Requires(moduleDef != null);\n      var sig = new ModuleSignature();\n      sig.ModuleDef = moduleDef;\n      sig.IsAbstract = moduleDef.IsAbstract;\n      sig.ModuleType = moduleDef.ModuleType;\n      sig.VisibilityScope = new VisibilityScope();\n      sig.VisibilityScope.Augment(moduleDef.VisibilityScope);\n\n      List<TopLevelDecl> declarations = moduleDef.TopLevelDecls;\n\n      // This is solely used to detect duplicates amongst the various e\n      Dictionary<string, TopLevelDecl> toplevels = new Dictionary<string, TopLevelDecl>();\n      // Now add the things present\n      foreach (TopLevelDecl d in declarations) {\n        Contract.Assert(d != null);\n\n        if (d is RevealableTypeDecl) {\n          revealableTypes.Add((RevealableTypeDecl)d);\n        }\n\n        // register the class/datatype/module name\n        if (d is ModuleExportDecl export) {\n          if (sig.ExportSets.ContainsKey(d.Name)) {\n            reporter.Error(MessageSource.Resolver, d, \"duplicate name of export set: {0}\", d.Name);\n          } else {\n            sig.ExportSets[d.Name] = export;\n          }\n        } else if (toplevels.ContainsKey(d.Name)) {\n          reporter.Error(MessageSource.Resolver, d, \"duplicate name of top-level declaration: {0}\", d.Name);\n        } else {\n          var cl = d as ClassDecl;\n          TopLevelDecl dprime = cl != null && cl.NonNullTypeDecl != null ? cl.NonNullTypeDecl : d;\n          toplevels[d.Name] = dprime;\n          sig.TopLevels[d.Name] = dprime;\n        }\n        if (d is ModuleDecl) {\n          // nothing to do\n        } else if (d is OpaqueTypeDecl) {\n          // nothing more to register\n        } else if (d is TypeSynonymDecl) {\n          // nothing more to register\n        } else if (d is NewtypeDecl) {\n          var cl = (TopLevelDeclWithMembers)d;\n          // register the names of the type members\n          var members = new Dictionary<string, MemberDecl>();\n          classMembers.Add(cl, members);\n          RegisterMembers(moduleDef, cl, members);\n        } else if (d is IteratorDecl) {\n          var iter = (IteratorDecl)d;\n\n          // register the names of the implicit members\n          var members = new Dictionary<string, MemberDecl>();\n          classMembers.Add(iter, members);\n\n          // First, register the iterator's in- and out-parameters as readonly fields\n          foreach (var p in iter.Ins) {\n            if (members.ContainsKey(p.Name)) {\n              reporter.Error(MessageSource.Resolver, p, \"Name of in-parameter is used by another member of the iterator: {0}\", p.Name);\n            } else {\n              var field = new SpecialField(p.tok, p.Name, SpecialField.ID.UseIdParam, p.CompileName, p.IsGhost, false, false, p.Type, null);\n              field.EnclosingClass = iter;  // resolve here\n              field.InheritVisibility(iter);\n              members.Add(p.Name, field);\n              iter.Members.Add(field);\n            }\n          }\n          var nonDuplicateOuts = new List<Formal>();\n          foreach (var p in iter.Outs) {\n            if (members.ContainsKey(p.Name)) {\n              reporter.Error(MessageSource.Resolver, p, \"Name of yield-parameter is used by another member of the iterator: {0}\", p.Name);\n            } else {\n              nonDuplicateOuts.Add(p);\n              var field = new SpecialField(p.tok, p.Name, SpecialField.ID.UseIdParam, p.CompileName, p.IsGhost, true, true, p.Type, null);\n              field.EnclosingClass = iter;  // resolve here\n              field.InheritVisibility(iter);\n              iter.OutsFields.Add(field);\n              members.Add(p.Name, field);\n              iter.Members.Add(field);\n            }\n          }\n          foreach (var p in nonDuplicateOuts) {\n            var nm = p.Name + \"s\";\n            if (members.ContainsKey(nm)) {\n              reporter.Error(MessageSource.Resolver, p.tok, \"Name of implicit yield-history variable '{0}' is already used by another member of the iterator\", p.Name);\n              nm = p.Name + \"*\";  // bogus name, but at least it'll be unique\n            }\n            // we add some field to OutsHistoryFields, even if there was an error; the name of the field, in case of error, is not so important\n            var tp = new SeqType(p.Type.NormalizeExpand());\n            var field = new SpecialField(p.tok, nm, SpecialField.ID.UseIdParam, nm, true, true, false, tp, null);\n            field.EnclosingClass = iter;  // resolve here\n            field.InheritVisibility(iter);\n            iter.OutsHistoryFields.Add(field);  // for now, just record this field (until all parameters have been added as members)\n          }\n          Contract.Assert(iter.OutsFields.Count == iter.OutsHistoryFields.Count);  // the code above makes sure this holds, even in the face of errors\n          // now that already-used 'ys' names have been checked for, add these yield-history variables\n          iter.OutsHistoryFields.ForEach(f => {\n            members.Add(f.Name, f);\n            iter.Members.Add(f);\n          });\n          // add the additional special variables as fields\n          iter.Member_Reads = new SpecialField(iter.tok, \"_reads\", SpecialField.ID.Reads, null, true, false, false, new SetType(true, builtIns.ObjectQ()), null);\n          iter.Member_Modifies = new SpecialField(iter.tok, \"_modifies\", SpecialField.ID.Modifies, null, true, false, false, new SetType(true, builtIns.ObjectQ()), null);\n          iter.Member_New = new SpecialField(iter.tok, \"_new\", SpecialField.ID.New, null, true, true, true, new SetType(true, builtIns.ObjectQ()), null);\n          foreach (var field in new List<Field>() { iter.Member_Reads, iter.Member_Modifies, iter.Member_New }) {\n            field.EnclosingClass = iter;  // resolve here\n            field.InheritVisibility(iter);\n            members.Add(field.Name, field);\n            iter.Members.Add(field);\n          }\n          // finally, add special variables to hold the components of the (explicit or implicit) decreases clause\n          FillInDefaultDecreases(iter, false);\n          // create the fields; unfortunately, we don't know their types yet, so we'll just insert type proxies for now\n          var i = 0;\n          foreach (var p in iter.Decreases.Expressions) {\n            var nm = \"_decreases\" + i;\n            var field = new SpecialField(p.tok, nm, SpecialField.ID.UseIdParam, nm, true, false, false, new InferredTypeProxy(), null);\n            field.EnclosingClass = iter;  // resolve here\n            field.InheritVisibility(iter);\n            iter.DecreasesFields.Add(field);\n            members.Add(field.Name, field);\n            iter.Members.Add(field);\n            i++;\n          }\n\n          // Note, the typeArgs parameter to the following Method/Predicate constructors is passed in as the empty list.  What that is\n          // saying is that the Method/Predicate does not take any type parameters over and beyond what the enclosing type (namely, the\n          // iterator type) does.\n          // --- here comes the constructor\n          var init = new Constructor(iter.tok, \"_ctor\", new List<TypeParameter>(), iter.Ins,\n            new List<MaybeFreeExpression>(),\n            new Specification<FrameExpression>(new List<FrameExpression>(), null),\n            new List<MaybeFreeExpression>(),\n            new Specification<Expression>(new List<Expression>(), null),\n            null, null, null);\n          // --- here comes predicate Valid()\n          var valid = new Predicate(iter.tok, \"Valid\", false, true, true, new List<TypeParameter>(),\n            new List<Formal>(),\n            new List<MaybeFreeExpression>(),\n            new List<FrameExpression>(),\n            new List<MaybeFreeExpression>(),\n            new Specification<Expression>(new List<Expression>(), null),\n            null, Predicate.BodyOriginKind.OriginalOrInherited, null, null);\n          // --- here comes method MoveNext\n          var moveNext = new Method(iter.tok, \"MoveNext\", false, false, new List<TypeParameter>(),\n            new List<Formal>(), new List<Formal>() { new Formal(iter.tok, \"more\", Type.Bool, false, false) },\n            new List<MaybeFreeExpression>(),\n            new Specification<FrameExpression>(new List<FrameExpression>(), null),\n            new List<MaybeFreeExpression>(),\n            new Specification<Expression>(new List<Expression>(), null),\n            new Specification<Expression>(new List<Expression>(), null),\n            new List<Expression>(),\n            new List<Expression>(),\n            null, null, null);\n          // add these implicit members to the class\n          init.EnclosingClass = iter;\n          init.InheritVisibility(iter);\n          valid.EnclosingClass = iter;\n          valid.InheritVisibility(iter);\n          moveNext.EnclosingClass = iter;\n          moveNext.InheritVisibility(iter);\n          iter.HasConstructor = true;\n          iter.Member_Init = init;\n          iter.Member_Valid = valid;\n          iter.Member_MoveNext = moveNext;\n          MemberDecl member;\n          if (members.TryGetValue(init.Name, out member)) {\n            reporter.Error(MessageSource.Resolver, member.tok, \"member name '{0}' is already predefined for this iterator\", init.Name);\n          } else {\n            members.Add(init.Name, init);\n            iter.Members.Add(init);\n          }\n          // If the name of the iterator is \"Valid\" or \"MoveNext\", one of the following will produce an error message.  That\n          // error message may not be as clear as it could be, but the situation also seems unlikely to ever occur in practice.\n          if (members.TryGetValue(\"Valid\", out member)) {\n            reporter.Error(MessageSource.Resolver, member.tok, \"member name 'Valid' is already predefined for iterators\");\n          } else {\n            members.Add(valid.Name, valid);\n            iter.Members.Add(valid);\n          }\n          if (members.TryGetValue(\"MoveNext\", out member)) {\n            reporter.Error(MessageSource.Resolver, member.tok, \"member name 'MoveNext' is already predefined for iterators\");\n          } else {\n            members.Add(moveNext.Name, moveNext);\n            iter.Members.Add(moveNext);\n          }\n\n        } else if (d is ClassDecl) {\n          var cl = (ClassDecl)d;\n          var preMemberErrs = reporter.Count(ErrorLevel.Error);\n\n          // register the names of the class members\n          var members = new Dictionary<string, MemberDecl>();\n          classMembers.Add(cl, members);\n          RegisterMembers(moduleDef, cl, members);\n\n          Contract.Assert(preMemberErrs != reporter.Count(ErrorLevel.Error) || !cl.Members.Except(members.Values).Any());\n\n          if (cl.IsDefaultClass) {\n            foreach (MemberDecl m in members.Values) {\n              Contract.Assert(!m.HasStaticKeyword || m is ConstantField || ArmadaOptions.O.AllowGlobals);  // note, the IsStatic value isn't available yet; when it becomes available, we expect it will have the value 'true'\n              if (m is Function || m is Method || m is ConstantField) {\n                sig.StaticMembers[m.Name] = m;\n              }\n            }\n          }\n        } else if (d is RefinementConstraintDecl) {\n          // nothing more to register\n        } else if (d is DatatypeDecl) {\n          var dt = (DatatypeDecl)d;\n\n          // register the names of the constructors\n          var ctors = new Dictionary<string, DatatypeCtor>();\n          datatypeCtors.Add(dt, ctors);\n          // ... and of the other members\n          var members = new Dictionary<string, MemberDecl>();\n          classMembers.Add(dt, members);\n\n          foreach (DatatypeCtor ctor in dt.Ctors) {\n            if (ctor.Name.EndsWith(\"?\")) {\n              reporter.Error(MessageSource.Resolver, ctor, \"a datatype constructor name is not allowed to end with '?'\");\n            } else if (ctors.ContainsKey(ctor.Name)) {\n              reporter.Error(MessageSource.Resolver, ctor, \"Duplicate datatype constructor name: {0}\", ctor.Name);\n            } else {\n              ctors.Add(ctor.Name, ctor);\n              ctor.InheritVisibility(dt);\n\n              // create and add the query \"method\" (field, really)\n              string queryName = ctor.Name + \"?\";\n              var query = new SpecialField(ctor.tok, queryName, SpecialField.ID.UseIdParam, \"is_\" + ctor.CompileName, false, false, false, Type.Bool, null);\n              query.InheritVisibility(dt);\n              query.EnclosingClass = dt;  // resolve here\n              members.Add(queryName, query);\n              ctor.QueryField = query;\n\n              // also register the constructor name globally\n              Tuple<DatatypeCtor, bool> pair;\n              if (sig.Ctors.TryGetValue(ctor.Name, out pair)) {\n                // mark it as a duplicate\n                sig.Ctors[ctor.Name] = new Tuple<DatatypeCtor, bool>(pair.Item1, true);\n              } else {\n                // add new\n                sig.Ctors.Add(ctor.Name, new Tuple<DatatypeCtor, bool>(ctor, false));\n              }\n            }\n          }\n          // add deconstructors now (that is, after the query methods have been added)\n          foreach (DatatypeCtor ctor in dt.Ctors) {\n            var formalsUsedInThisCtor = new HashSet<string>();\n            foreach (var formal in ctor.Formals) {\n              MemberDecl previousMember = null;\n              var localDuplicate = false;\n              if (formal.HasName) {\n                if (members.TryGetValue(formal.Name, out previousMember)) {\n                  localDuplicate = formalsUsedInThisCtor.Contains(formal.Name);\n                  if (localDuplicate) {\n                    reporter.Error(MessageSource.Resolver, ctor, \"Duplicate use of deconstructor name in the same constructor: {0}\", formal.Name);\n                  } else if (previousMember is DatatypeDestructor) {\n                    // this is okay, if the destructor has the appropriate type; this will be checked later, after type checking\n                  } else {\n                    reporter.Error(MessageSource.Resolver, ctor, \"Name of deconstructor is used by another member of the datatype: {0}\", formal.Name);\n                  }\n                }\n                formalsUsedInThisCtor.Add(formal.Name);\n              }\n              DatatypeDestructor dtor;\n              if (!localDuplicate && previousMember is DatatypeDestructor) {\n                // a destructor with this name already existed in (a different constructor in) the datatype\n                dtor = (DatatypeDestructor)previousMember;\n                dtor.AddAnotherEnclosingCtor(ctor, formal);\n              } else {\n                // either the destructor has no explicit name, or this constructor declared another destructor with this name, or no previous destructor had this name\n                dtor = new DatatypeDestructor(formal.tok, ctor, formal, formal.Name, \"dtor_\" + formal.CompileName, formal.IsGhost, formal.Type, null);\n                dtor.InheritVisibility(dt);\n                dtor.EnclosingClass = dt;  // resolve here\n                if (formal.HasName && !localDuplicate && previousMember == null) {\n                  // the destructor has an explict name and there was no member at all with this name before\n                  members.Add(formal.Name, dtor);\n                }\n              }\n              ctor.Destructors.Add(dtor);\n            }\n          }\n          // finally, add any additional user-defined members\n          RegisterMembers(moduleDef, dt, members);\n        } else {\n          Contract.Assert(d is ValuetypeDecl);\n        }\n      }\n      // Now, for each class, register its possibly-null type\n      foreach (TopLevelDecl d in declarations) {\n        if ((d as ClassDecl)?.NonNullTypeDecl != null) {\n          var name = d.Name + \"?\";\n          TopLevelDecl prev;\n          if (toplevels.TryGetValue(name, out prev)) {\n            reporter.Error(MessageSource.Resolver, d, \"a module that already contains a top-level declaration '{0}' is not allowed to declare a {1} '{2}'\", name, d.WhatKind, d.Name);\n          } else {\n            toplevels[name] = d;\n            sig.TopLevels[name] = d;\n          }\n        }\n      }\n      return sig;\n    }\n\n    void RegisterMembers(ModuleDefinition moduleDef, TopLevelDeclWithMembers cl, Dictionary<string, MemberDecl> members) {\n      Contract.Requires(moduleDef != null);\n      Contract.Requires(cl != null);\n      Contract.Requires(members != null);\n\n      foreach (MemberDecl m in cl.Members) {\n        if (!members.ContainsKey(m.Name)) {\n          members.Add(m.Name, m);\n          if (m is Constructor) {\n            Contract.Assert(cl is ClassDecl);  // the parser ensures this condition\n            if (cl is TraitDecl) {\n              reporter.Error(MessageSource.Resolver, m.tok, \"a trait is not allowed to declare a constructor\");\n            } else {\n              ((ClassDecl)cl).HasConstructor = true;\n            }\n          } else if (m is FixpointPredicate || m is FixpointLemma) {\n            var extraName = m.Name + \"#\";\n            MemberDecl extraMember;\n            var cloner = new Cloner();\n            var formals = new List<Formal>();\n            Type typeOfK;\n            if ((m is FixpointPredicate && ((FixpointPredicate)m).KNat) || (m is FixpointLemma && ((FixpointLemma)m).KNat)) {\n              typeOfK = new UserDefinedType(m.tok, \"nat\", (List<Type>)null);\n            } else {\n              typeOfK = new BigOrdinalType();\n            }\n            var k = new ImplicitFormal(m.tok, \"_k\", typeOfK, true, false);\n            reporter.Info(MessageSource.Resolver, m.tok, string.Format(\"_k: {0}\", k.Type));\n            formals.Add(k);\n            if (m is FixpointPredicate) {\n              var cop = (FixpointPredicate)m;\n              formals.AddRange(cop.Formals.ConvertAll(cloner.CloneFormal));\n\n              List<TypeParameter> tyvars = cop.TypeArgs.ConvertAll(cloner.CloneTypeParam);\n\n              // create prefix predicate\n              cop.PrefixPredicate = new PrefixPredicate(cop.tok, extraName, cop.HasStaticKeyword, cop.IsProtected,\n                tyvars, k, formals,\n                cop.Req.ConvertAll(cloner.CloneMayBeFreeExpr),\n                cop.Reads.ConvertAll(cloner.CloneFrameExpr),\n                cop.Ens.ConvertAll(cloner.CloneMayBeFreeExpr),\n                new Specification<Expression>(new List<Expression>() { new IdentifierExpr(cop.tok, k.Name) }, null),\n                cop.Body,\n                null,\n                cop);\n              extraMember = cop.PrefixPredicate;\n              // In the call graph, add an edge from P# to P, since this will have the desired effect of detecting unwanted cycles.\n              moduleDef.CallGraph.AddEdge(cop.PrefixPredicate, cop);\n            } else {\n              var com = (FixpointLemma)m;\n              // _k has already been added to 'formals', so append the original formals\n              formals.AddRange(com.Ins.ConvertAll(cloner.CloneFormal));\n              // prepend _k to the given decreases clause\n              var decr = new List<Expression>();\n              decr.Add(new IdentifierExpr(com.tok, k.Name));\n              decr.AddRange(com.Decreases.Expressions.ConvertAll(cloner.CloneExpr));\n              // Create prefix lemma.  Note that the body is not cloned, but simply shared.\n              // For a colemma, the postconditions are filled in after the colemma's postconditions have been resolved.\n              // For an inductive lemma, the preconditions are filled in after the inductive lemma's preconditions have been resolved.\n              var req = com is CoLemma ? com.Req.ConvertAll(cloner.CloneMayBeFreeExpr) : new List<MaybeFreeExpression>();\n              var ens = com is CoLemma ? new List<MaybeFreeExpression>() : com.Ens.ConvertAll(cloner.CloneMayBeFreeExpr);\n              com.PrefixLemma = new PrefixLemma(com.tok, extraName, com.HasStaticKeyword,\n                com.TypeArgs.ConvertAll(cloner.CloneTypeParam), k, formals, com.Outs.ConvertAll(cloner.CloneFormal),\n                req, cloner.CloneSpecFrameExpr(com.Mod), ens,\n                new Specification<Expression>(decr, null),\n                null, // Note, the body for the prefix method will be created once the call graph has been computed and the SCC for the colemma is known\n                cloner.CloneAttributes(com.Attributes), com);\n              extraMember = com.PrefixLemma;\n              // In the call graph, add an edge from M# to M, since this will have the desired effect of detecting unwanted cycles.\n              moduleDef.CallGraph.AddEdge(com.PrefixLemma, com);\n            }\n            extraMember.InheritVisibility(m);\n            members.Add(extraName, extraMember);\n          }\n        } else if (m is Constructor && !((Constructor)m).HasName) {\n          reporter.Error(MessageSource.Resolver, m, \"More than one anonymous constructor\");\n        } else {\n          reporter.Error(MessageSource.Resolver, m, \"Duplicate member name: {0}\", m.Name);\n        }\n      }\n    }\n\n    private ModuleSignature MakeAbstractSignature(ModuleSignature p, string Name, int Height, Dictionary<ModuleDefinition, ModuleSignature> mods, Dictionary<ModuleDefinition, ModuleDefinition> compilationModuleClones) {\n      Contract.Requires(p != null);\n      Contract.Requires(Name != null);\n      Contract.Requires(mods != null);\n      Contract.Requires(compilationModuleClones != null);\n      var errCount = reporter.Count(ErrorLevel.Error);\n\n      var mod = new ModuleDefinition(Token.NoToken, Name + \".Abs\", new List<IToken>(), true, true, true, null, null, null, false);\n      mod.Height = Height;\n      mod.IsToBeVerified = p.ModuleDef.IsToBeVerified;\n      bool hasDefaultClass = false;\n      foreach (var kv in p.TopLevels) {\n        hasDefaultClass = kv.Value is DefaultClassDecl || hasDefaultClass;\n        if (!(kv.Value is NonNullTypeDecl)) {\n          var clone = CloneDeclaration(p.VisibilityScope, kv.Value, mod, mods, Name, compilationModuleClones);\n          mod.TopLevelDecls.Add(clone);\n        }\n      }\n      if (!hasDefaultClass) {\n        DefaultClassDecl cl = new DefaultClassDecl(mod, p.StaticMembers.Values.ToList());\n        mod.TopLevelDecls.Add(CloneDeclaration(p.VisibilityScope, cl, mod, mods, Name, compilationModuleClones));\n      }\n      var sig = RegisterTopLevelDecls(mod, true);\n      sig.Refines = p.Refines;\n      sig.CompileSignature = p;\n      sig.IsAbstract = p.IsAbstract;\n      mods.Add(mod, sig);\n      var good = ResolveModuleDefinition(mod, sig);\n      if (good && reporter.Count(ErrorLevel.Error) == errCount) {\n        mod.SuccessfullyResolved = true;\n      }\n      return sig;\n    }\n\n\n    TopLevelDecl CloneDeclaration(VisibilityScope scope, TopLevelDecl d, ModuleDefinition m, Dictionary<ModuleDefinition, ModuleSignature> mods, string Name, Dictionary<ModuleDefinition, ModuleDefinition> compilationModuleClones) {\n      Contract.Requires(d != null);\n      Contract.Requires(m != null);\n      Contract.Requires(mods != null);\n      Contract.Requires(Name != null);\n      Contract.Requires(compilationModuleClones != null);\n\n      if (d is ModuleFacadeDecl) {\n        var abs = (ModuleFacadeDecl)d;\n        var sig = MakeAbstractSignature(abs.OriginalSignature, Name + \".\" + abs.Name, abs.Height, mods, compilationModuleClones);\n        var a = new ModuleFacadeDecl(abs.Path, abs.tok, m, abs.Opened, abs.Exports);\n        a.Signature = sig;\n        a.OriginalSignature = abs.OriginalSignature;\n        return a;\n      } else {\n        return new AbstractSignatureCloner(scope).CloneDeclaration(d, m);\n      }\n    }\n\n\n    public bool ResolveExport(ModuleDecl alias, ModuleDecl root, ModuleDefinition parent, List<IToken> Path, List<IToken> Exports, out ModuleSignature p, ErrorReporter reporter) {\n      Contract.Requires(Path != null);\n      Contract.Requires(Path.Count > 0);\n      Contract.Requires(Exports != null);\n      Contract.Requires(Exports.Count == 0 || Path.Count == 1); // Path.Count > 1 ==> Exports.Count == 0\n      Contract.Requires(Exports.Count == 0 || root is LiteralModuleDecl); // only literal modules may have exports\n      if (Path.Count == 1 && root is LiteralModuleDecl) {\n        // use the default export set when importing the root\n        LiteralModuleDecl decl = (LiteralModuleDecl)root;\n        if (Exports.Count == 0) {\n          p = decl.DefaultExport;\n          if (p == null) {\n            // no default view is specified.\n            reporter.Error(MessageSource.Resolver, Path[0], \"no default export set declared in module: {0}\", decl.Name);\n            return false;\n          }\n          return true;\n        } else {\n          ModuleExportDecl pp;\n          if (root.Signature.ExportSets.TryGetValue(Exports[0].val, out pp)) {\n            p = pp.Signature;\n          } else {\n            reporter.Error(MessageSource.Resolver, Exports[0], \"no export set '{0}' in module '{1}'\", Exports[0].val, decl.Name);\n            p = null;\n            return false;\n          }\n\n          foreach (IToken export in Exports.Skip(1)) {\n            if (root.Signature.ExportSets.TryGetValue(export.val, out pp)) {\n              Contract.Assert(Object.ReferenceEquals(p.ModuleDef, pp.Signature.ModuleDef));\n              ModuleSignature merged = MergeSignature(p, pp.Signature);\n              merged.ModuleDef = pp.Signature.ModuleDef;\n              merged.CompileSignature = MergeSignature(p.CompileSignature, pp.Signature.CompileSignature);\n              p = merged;\n            } else {\n              reporter.Error(MessageSource.Resolver, export, \"no export set {0} in module {1}\", export.val, decl.Name);\n              p = null;\n              return false;\n            }\n          }\n          return true;\n        }\n      }\n\n      // Although the module is known, we demand it be imported before we're willing to access it.\n      var thisImport = parent.TopLevelDecls.FirstOrDefault(t => t.Name == Path[0].val && t != alias);\n\n      if (thisImport == null || !(thisImport is ModuleDecl)) {\n\n        reporter.Error(MessageSource.Resolver, Path[0], ModuleNotFoundErrorMessage(0, Path));\n        p = null;\n        return false;\n      }\n\n      var psig = ((ModuleDecl)thisImport).AccessibleSignature();\n      int i = 1;\n      while (i < Path.Count) {\n        ModuleSignature pp;\n        if (psig.FindImport(Path[i].val, out pp)) {\n          psig = pp;\n          i++;\n        } else {\n          reporter.Error(MessageSource.Resolver, Path[i], ModuleNotFoundErrorMessage(i, Path));\n          break;\n        }\n      }\n      p = psig;\n      return i == Path.Count;\n    }\n\n    public void RevealAllInScope(List<TopLevelDecl> declarations, VisibilityScope scope) {\n      foreach (TopLevelDecl d in declarations) {\n        d.AddVisibilityScope(scope, false);\n        if (d is TopLevelDeclWithMembers) {\n          var cl = (TopLevelDeclWithMembers)d;\n          foreach (var mem in cl.Members) {\n            if (!mem.ScopeIsInherited) {\n              mem.AddVisibilityScope(scope, false);\n            }\n          }\n          var nnd = (cl as ClassDecl)?.NonNullTypeDecl;\n          if (nnd != null) {\n            nnd.AddVisibilityScope(scope, false);\n          }\n        }\n      }\n    }\n\n    public void ResolveTopLevelDecls_Signatures(ModuleDefinition def, ModuleSignature sig, List<TopLevelDecl/*!*/>/*!*/ declarations, Graph<IndDatatypeDecl/*!*/>/*!*/ datatypeDependencies, Graph<CoDatatypeDecl/*!*/>/*!*/ codatatypeDependencies) {\n      Contract.Requires(declarations != null);\n      Contract.Requires(datatypeDependencies != null);\n      Contract.Requires(codatatypeDependencies != null);\n      RevealAllInScope(declarations, def.VisibilityScope);\n\n      /* Augment the scoping environment for the current module*/\n      foreach (TopLevelDecl d in declarations) {\n        if (d is ModuleDecl && !(d is ModuleExportDecl)) {\n          var decl = (ModuleDecl)d;\n          moduleInfo.VisibilityScope.Augment(decl.AccessibleSignature().VisibilityScope);\n          sig.VisibilityScope.Augment(decl.AccessibleSignature().VisibilityScope);\n        }\n      }\n      /*if (sig.Refines != null) {\n        moduleInfo.VisibilityScope.Augment(sig.Refines.VisibilityScope);\n        sig.VisibilityScope.Augment(sig.Refines.VisibilityScope);\n      }*/\n\n      // resolve the trait names that a class extends and register the trait members in the classes that inherit them\n      foreach (TopLevelDecl d in declarations) {\n        var cl = d as ClassDecl;\n        if (cl != null) {\n          RegisterInheritedMembers(cl);\n        }\n      }\n\n      var typeRedirectionDependencies = new Graph<RedirectingTypeDecl>();  // this concerns the type directions, not their constraints (which are checked for cyclic dependencies later)\n      foreach (TopLevelDecl d in ModuleDefinition.AllDeclarationsAndNonNullTypeDecls(declarations)) {\n        Contract.Assert(d != null);\n        allTypeParameters.PushMarker();\n        ResolveTypeParameters(d.TypeArgs, true, d);\n        if (d is OpaqueTypeDecl) {\n          // do nothing\n        } else if (d is TypeSynonymDecl) {\n          var dd = (TypeSynonymDecl)d;\n          ResolveType(dd.tok, dd.Rhs, dd, ResolveTypeOptionEnum.AllowPrefix, dd.TypeArgs);\n          dd.Rhs.ForeachTypeComponent(ty => {\n            var s = ty.AsRedirectingType;\n            if (s != null) {\n              typeRedirectionDependencies.AddEdge(dd, s);\n            }\n          });\n        } else if (d is NewtypeDecl) {\n          var dd = (NewtypeDecl)d;\n          ResolveType(dd.tok, dd.BaseType, dd, ResolveTypeOptionEnum.DontInfer, null);\n          dd.BaseType.ForeachTypeComponent(ty => {\n            var s = ty.AsRedirectingType;\n            if (s != null) {\n              typeRedirectionDependencies.AddEdge(dd, s);\n            }\n          });\n          ResolveClassMemberTypes(dd);\n        } else if (d is IteratorDecl) {\n          ResolveIteratorSignature((IteratorDecl)d);\n        } else if (d is ClassDecl) {\n          ResolveClassMemberTypes((ClassDecl)d);\n        } else if (d is ModuleDecl) {\n          var decl = (ModuleDecl)d;\n          if (!def.IsAbstract && decl is AliasModuleDecl am && decl.Signature.IsAbstract) {\n            reporter.Error(MessageSource.Resolver, am.Path.Last(), \"a compiled module ({0}) is not allowed to import an abstract module ({1})\", def.Name, Util.Comma(\".\", am.Path, tok => tok.val));\n          }\n        } else if (d is RefinementConstraintDecl) {\n          // do nothing\n        } else {\n          var dd = (DatatypeDecl)d;\n          ResolveCtorTypes(dd, datatypeDependencies, codatatypeDependencies);\n          ResolveClassMemberTypes(dd);\n        }\n        allTypeParameters.PopMarker();\n      }\n\n      // Now that all traits have been resolved, let classes inherit the trait members\n      foreach (var d in declarations) {\n        var cl = d as ClassDecl;\n        if (cl != null) {\n          InheritTraitMembers(cl);\n        }\n      }\n\n      // perform acyclicity test on type synonyms\n      foreach (var cycle in typeRedirectionDependencies.AllCycles()) {\n        Contract.Assert(cycle.Count != 0);\n        var erste = cycle[0];\n        reporter.Error(MessageSource.Resolver, erste.Tok, \"Cycle among redirecting types (newtypes, subset types, type synonyms): {0} -> {1}\", Util.Comma(\" -> \", cycle, syn => syn.Name), erste.Name);\n      }\n    }\n\n    public static readonly List<NativeType> NativeTypes = new List<NativeType>() {\n      new NativeType(\"byte\", 0, 0x100, 8,NativeType.Selection.Byte, ArmadaOptions.CompilationTarget.Clight),\n      new NativeType(\"sbyte\", -0x80, 0x80, 0, NativeType.Selection.SByte, ArmadaOptions.CompilationTarget.Clight),\n      new NativeType(\"ushort\", 0, 0x1_0000, 16, NativeType.Selection.UShort, ArmadaOptions.CompilationTarget.Clight),\n      new NativeType(\"short\", -0x8000, 0x8000, 0, NativeType.Selection.Short, ArmadaOptions.CompilationTarget.Clight),\n      new NativeType(\"uint\", 0, 0x1_0000_0000, 32, NativeType.Selection.UInt, ArmadaOptions.CompilationTarget.Clight),\n      new NativeType(\"int\", -0x8000_0000, 0x8000_0000, 0, NativeType.Selection.Int, ArmadaOptions.CompilationTarget.Clight),\n      new NativeType(\"number\", -0x1f_ffff_ffff_ffff, 0x20_0000_0000_0000, 0, NativeType.Selection.Number, ArmadaOptions.CompilationTarget.Clight),  // JavaScript integers\n      new NativeType(\"ulong\", 0, new BigInteger(0x1_0000_0000) * new BigInteger(0x1_0000_0000), 64, NativeType.Selection.ULong, ArmadaOptions.CompilationTarget.Clight),\n      new NativeType(\"long\", Int64.MinValue, 0x8000_0000_0000_0000, 0, NativeType.Selection.Long, ArmadaOptions.CompilationTarget.Clight),\n    };\n\n    public void ResolveTopLevelDecls_Core(List<TopLevelDecl/*!*/>/*!*/ declarations, Graph<IndDatatypeDecl/*!*/>/*!*/ datatypeDependencies, Graph<CoDatatypeDecl/*!*/>/*!*/ codatatypeDependencies) {\n      Contract.Requires(declarations != null);\n      Contract.Requires(cce.NonNullElements(datatypeDependencies.GetVertices()));\n      Contract.Requires(cce.NonNullElements(codatatypeDependencies.GetVertices()));\n      Contract.Requires(AllTypeConstraints.Count == 0);\n\n      Contract.Ensures(AllTypeConstraints.Count == 0);\n\n      int prevErrorCount = reporter.Count(ErrorLevel.Error);\n\n      // ---------------------------------- Pass 0 ----------------------------------\n      // This pass resolves names, introduces (and may solve) type constraints, and\n      // builds the module's call graph.\n      // For 'newtype' and subset-type declarations, it also checks that all types were fully\n      // determined.\n      // ----------------------------------------------------------------------------\n\n      // Resolve the meat of classes and iterators, the definitions of type synonyms, and the type parameters of all top-level type declarations\n      // In the first two loops below, resolve the newtype/subset-type declarations and their constraint clauses and const definitions, including\n      // filling in .ResolvedOp fields.  This is needed for the resolution of the other declarations, because those other declarations may invoke\n      // DiscoverBounds, which looks at the .Constraint or .Rhs field of any such types involved.\n      // The third loop resolves the other declarations.  It also resolves any witness expressions of newtype/subset-type declarations.\n      foreach (TopLevelDecl topd in declarations) {\n        Contract.Assert(topd != null);\n        Contract.Assert(VisibleInScope(topd));\n        TopLevelDecl d = topd is ClassDecl ? ((ClassDecl)topd).NonNullTypeDecl : topd;\n        if (d is NewtypeDecl) {\n          var dd = (NewtypeDecl)d;\n          ResolveAttributes(d.Attributes, d, new ResolveOpts(new NoContext(d.Module), false));\n          // this check can be done only after it has been determined that the redirected types do not involve cycles\n          AddXConstraint(dd.tok, \"NumericType\", dd.BaseType, \"newtypes must be based on some numeric type (got {0})\");\n          // type check the constraint, if any\n          if (dd.Var == null) {\n            SolveAllTypeConstraints();\n          } else {\n            Contract.Assert(object.ReferenceEquals(dd.Var.Type, dd.BaseType));  // follows from NewtypeDecl invariant\n            Contract.Assert(dd.Constraint != null);  // follows from NewtypeDecl invariant\n\n            scope.PushMarker();\n            var added = scope.Push(dd.Var.Name, dd.Var);\n            Contract.Assert(added == Scope<IVariable>.PushResult.Success);\n            ResolveExpression(dd.Constraint, new ResolveOpts(dd, false));\n            Contract.Assert(dd.Constraint.Type != null);  // follows from postcondition of ResolveExpression\n            ConstrainTypeExprBool(dd.Constraint, \"newtype constraint must be of type bool (instead got {0})\");\n            SolveAllTypeConstraints();\n            if (!CheckTypeInference_Visitor.IsDetermined(dd.BaseType.NormalizeExpand())) {\n              reporter.Error(MessageSource.Resolver, dd.tok, \"newtype's base type is not fully determined; add an explicit type for '{0}'\", dd.Var.Name);\n            }\n            scope.PopMarker();\n          }\n\n        } else if (d is SubsetTypeDecl) {\n          var dd = (SubsetTypeDecl)d;\n\n          allTypeParameters.PushMarker();\n          ResolveTypeParameters(d.TypeArgs, false, d);\n          ResolveAttributes(d.Attributes, d, new ResolveOpts(new NoContext(d.Module), false));\n          // type check the constraint\n          Contract.Assert(object.ReferenceEquals(dd.Var.Type, dd.Rhs));  // follows from SubsetTypeDecl invariant\n          Contract.Assert(dd.Constraint != null);  // follows from SubsetTypeDecl invariant\n          scope.PushMarker();\n          var added = scope.Push(dd.Var.Name, dd.Var);\n          Contract.Assert(added == Scope<IVariable>.PushResult.Success);\n          ResolveExpression(dd.Constraint, new ResolveOpts(dd, false));\n          Contract.Assert(dd.Constraint.Type != null);  // follows from postcondition of ResolveExpression\n          ConstrainTypeExprBool(dd.Constraint, \"subset-type constraint must be of type bool (instead got {0})\");\n          SolveAllTypeConstraints();\n          if (!CheckTypeInference_Visitor.IsDetermined(dd.Rhs.NormalizeExpand())) {\n            reporter.Error(MessageSource.Resolver, dd.tok, \"subset type's base type is not fully determined; add an explicit type for '{0}'\", dd.Var.Name);\n          }\n          scope.PopMarker();\n          allTypeParameters.PopMarker();\n        }\n        if (topd is TopLevelDeclWithMembers) {\n          var cl = (TopLevelDeclWithMembers)topd;\n          currentClass = cl;\n          foreach (var member in cl.Members) {\n            Contract.Assert(VisibleInScope(member));\n            if (member is ConstantField) {\n              var field = (ConstantField)member;\n              var opts = new ResolveOpts(field, false);\n              ResolveAttributes(field.Attributes, field, opts);\n              // Resolve the value expression\n              if (field.Rhs != null) {\n                var ec = reporter.Count(ErrorLevel.Error);\n                ResolveExpression(field.Rhs, opts);\n                if (reporter.Count(ErrorLevel.Error) == ec) {\n                  // make sure initialization only refers to constant field or literal expression\n                  if (CheckIsConstantExpr(field, field.Rhs)) {\n                    AddAssignableConstraint(field.tok, field.Type, field.Rhs.Type, \"type for constant '\" + field.Name + \"' is '{0}', but its initialization value type is '{1}'\");\n                  }\n                }\n              }\n              SolveAllTypeConstraints();\n              if (!CheckTypeInference_Visitor.IsDetermined(field.Type.NormalizeExpand())) {\n                reporter.Error(MessageSource.Resolver, field.tok, \"const field's type is not fully determined\");\n              }\n            }\n            else if (member is Field) {\n              var field = (Field)member;\n              var opts = new ResolveOpts(field, false);\n              if (field.InitialValue != null) {\n                var ec = reporter.Count(ErrorLevel.Error);\n                ResolveExpression(field.InitialValue, opts);\n                if (reporter.Count(ErrorLevel.Error) == ec) {\n                  AddAssignableConstraint(field.tok, field.Type, field.InitialValue.Type, \"type for field '\" + field.Name + \"' is '{0}', but its initialization value type is '{1}'\");\n                }\n              }\n              SolveAllTypeConstraints();\n            }\n          }\n          currentClass = null;\n        }\n      }\n      Contract.Assert(AllTypeConstraints.Count == 0);\n      if (reporter.Count(ErrorLevel.Error) == prevErrorCount) {\n        // Check type inference, which also discovers bounds, in newtype/subset-type constraints and const declarations\n        foreach (TopLevelDecl topd in declarations) {\n          TopLevelDecl d = topd is ClassDecl ? ((ClassDecl)topd).NonNullTypeDecl : topd;\n          if (d is RedirectingTypeDecl dd && dd.Constraint != null) {\n            CheckTypeInference(dd.Constraint, dd);\n          }\n          if (topd is TopLevelDeclWithMembers cl) {\n            foreach (var member in cl.Members) {\n              if (member is ConstantField field && field.Rhs != null) {\n                CheckTypeInference(field.Rhs, field);\n                if (!field.IsGhost) {\n                  CheckIsCompilable(field.Rhs);\n                }\n              }\n            }\n          }\n          // NOTE (Luke): This is is included by git's auto-merge,\n          //              but it's a obsolete code covered by the\n          //              code above (in theory)\n          // if (topd is ClassDecl cl) {\n          //   foreach (var member in cl.Members) {\n          //     var field = member as ConstantField;\n          //     if (field != null && field.Rhs != null) {\n          //       CheckTypeInference(field.Rhs, field);\n          //       if (!field.IsGhost) {\n          //         CheckIsCompilable(field.Rhs);\n          //       }\n          //     }\n          //   }\n          // }\n        }\n      }\n      // Now, we're ready for the other declarations, along with any witness clauses of newtype/subset-type declarations.\n      foreach (TopLevelDecl d in declarations) {\n        Contract.Assert(AllTypeConstraints.Count == 0);\n        if (d is TraitDecl && d.TypeArgs.Count > 0) {\n          reporter.Error(MessageSource.Resolver, d, \"sorry, traits with type parameters are not supported\");\n        }\n        allTypeParameters.PushMarker();\n        ResolveTypeParameters(d.TypeArgs, false, d);\n        if (d is NewtypeDecl || d is SubsetTypeDecl) {\n          // NewTypeDecl's and SubsetTypeDecl's were already processed in the loop above, except for any witness clauses\n          var dd = (RedirectingTypeDecl)d;\n          if (dd.Witness != null) {\n            var prevErrCnt = reporter.Count(ErrorLevel.Error);\n            ResolveExpression(dd.Witness, new ResolveOpts(dd, false));\n            ConstrainSubtypeRelation(dd.Var.Type, dd.Witness.Type, dd.Witness, \"witness expression must have type '{0}' (got '{1}')\", dd.Var.Type, dd.Witness.Type);\n            SolveAllTypeConstraints();\n            if (reporter.Count(ErrorLevel.Error) == prevErrCnt) {\n              CheckTypeInference(dd.Witness, dd);\n            }\n            if (reporter.Count(ErrorLevel.Error) == prevErrCnt && dd.WitnessKind == SubsetTypeDecl.WKind.Compiled) {\n              CheckIsCompilable(dd.Witness);\n            }\n          }\n          if (d is TopLevelDeclWithMembers dm) {\n            ResolveClassMemberBodies(dm);\n          }\n        } else {\n          if (!(d is IteratorDecl)) {\n            // Note, attributes of iterators are resolved by ResolvedIterator, after registering any names in the iterator signature\n            ResolveAttributes(d.Attributes, d, new ResolveOpts(new NoContext(d.Module), false));\n          }\n          if (d is IteratorDecl) {\n            var iter = (IteratorDecl)d;\n            ResolveIterator(iter);\n            ResolveClassMemberBodies(iter);  // resolve the automatically generated members\n          } else if (d is ClassDecl) {\n            var cl = (ClassDecl)d;\n            ResolveClassMemberBodies(cl);\n          } else if (d is DatatypeDecl) {\n            var dt = (DatatypeDecl)d;\n            foreach (var ctor in dt.Ctors) {\n              foreach (var formal in ctor.Formals) {\n                AddTypeDependencyEdges((ICallable)d, formal.Type);\n              }\n            }\n            ResolveClassMemberBodies(dt);\n          }\n        }\n        allTypeParameters.PopMarker();\n      }\n\n      // ---------------------------------- Pass 1 ----------------------------------\n      // This pass:\n      // * checks that type inference was able to determine all types\n      // * check that shared destructors in datatypes are in agreement\n      // * fills in the .ResolvedOp field of binary expressions\n      // * discovers bounds for:\n      //     - forall statements\n      //     - set comprehensions\n      //     - map comprehensions\n      //     - quantifier expressions\n      //     - assign-such-that statements\n      //     - compilable let-such-that expressions\n      //     - newtype constraints\n      //     - subset-type constraints\n      // For each statement body that it successfully typed, this pass also:\n      // * computes ghost interests\n      // * determines/checks tail-recursion.\n      // ----------------------------------------------------------------------------\n\n      if (reporter.Count(ErrorLevel.Error) == prevErrorCount) {\n        // Check that type inference went well everywhere; this will also fill in the .ResolvedOp field in binary expressions\n        // Also, for each datatype, check that shared destructors are in agreement\n        foreach (TopLevelDecl d in declarations) {\n          if (d is IteratorDecl) {\n            var iter = (IteratorDecl)d;\n            var prevErrCnt = reporter.Count(ErrorLevel.Error);\n            iter.Members.Iter(CheckTypeInference_Member);\n            if (prevErrCnt == reporter.Count(ErrorLevel.Error)) {\n              iter.SubExpressions.Iter(e => CheckExpression(e, this, iter));\n            }\n            if (iter.Body != null) {\n              CheckTypeInference(iter.Body, iter);\n              if (prevErrCnt == reporter.Count(ErrorLevel.Error)) {\n                ComputeGhostInterest(iter.Body, false, iter);\n                CheckExpression(iter.Body, this, iter);\n              }\n            }\n          } else if (d is ClassDecl) {\n            var dd = (ClassDecl)d;\n            ResolveClassMembers_Pass1(dd);\n          } else if (d is SubsetTypeDecl) {\n            var dd = (SubsetTypeDecl)d;\n            Contract.Assert(dd.Constraint != null);\n            CheckExpression(dd.Constraint, this, dd);\n          } else if (d is NewtypeDecl) {\n            var dd = (NewtypeDecl)d;\n            if (dd.Var != null) {\n              Contract.Assert(dd.Constraint != null);\n              CheckExpression(dd.Constraint, this, dd);\n            }\n            FigureOutNativeType(dd);\n            ResolveClassMembers_Pass1(dd);\n          } else if (d is DatatypeDecl) {\n            var dd = (DatatypeDecl)d;\n            foreach (var member in classMembers[dd].Values) {\n              var dtor = member as DatatypeDestructor;\n              if (dtor != null) {\n                var rolemodel = dtor.CorrespondingFormals[0];\n                for (int i = 1; i < dtor.CorrespondingFormals.Count; i++) {\n                  var other = dtor.CorrespondingFormals[i];\n                  if (!Type.Equal_Improved(rolemodel.Type, other.Type)) {\n                    reporter.Error(MessageSource.Resolver, other,\n                      \"shared destructors must have the same type, but '{0}' has type '{1}' in constructor '{2}' and type '{3}' in constructor '{4}'\",\n                      rolemodel.Name, rolemodel.Type, dtor.EnclosingCtors[0].Name, other.Type, dtor.EnclosingCtors[i].Name);\n                  } else if (rolemodel.IsGhost != other.IsGhost) {\n                    reporter.Error(MessageSource.Resolver, other,\n                      \"shared destructors must agree on whether or not they are ghost, but '{0}' is {1} in constructor '{2}' and {3} in constructor '{4}'\",\n                      rolemodel.Name,\n                      rolemodel.IsGhost ? \"ghost\" : \"non-ghost\", dtor.EnclosingCtors[0].Name,\n                      other.IsGhost ? \"ghost\" : \"non-ghost\", dtor.EnclosingCtors[i].Name);\n                  }\n                }\n              }\n            }\n            ResolveClassMembers_Pass1(dd);\n          }\n        }\n      }\n\n\n      // ---------------------------------- Pass 2 ----------------------------------\n      // This pass fills in various additional information.\n      // ----------------------------------------------------------------------------\n\n      if (reporter.Count(ErrorLevel.Error) == prevErrorCount) {\n        // fill in the postconditions and bodies of prefix lemmas\n        foreach (var com in ModuleDefinition.AllFixpointLemmas(declarations)) {\n          var prefixLemma = com.PrefixLemma;\n          if (prefixLemma == null) {\n            continue;  // something went wrong during registration of the prefix lemma (probably a duplicated fixpoint-lemma name)\n          }\n          var k = prefixLemma.Ins[0];\n          var focalPredicates = new HashSet<FixpointPredicate>();\n          if (com is CoLemma) {\n            // compute the postconditions of the prefix lemma\n            Contract.Assume(prefixLemma.Ens.Count == 0);  // these are not supposed to have been filled in before\n            foreach (var p in com.Ens) {\n              var coConclusions = new HashSet<Expression>();\n              CollectFriendlyCallsInFixpointLemmaSpecification(p.E, true, coConclusions, true, com);\n              var subst = new FixpointLemmaSpecificationSubstituter(coConclusions, new IdentifierExpr(k.tok, k.Name), this.reporter, true);\n              var post = subst.CloneExpr(p.E);\n              prefixLemma.Ens.Add(new MaybeFreeExpression(post, p.IsFree));\n              foreach (var e in coConclusions) {\n                var fce = e as FunctionCallExpr;\n                if (fce != null) {  // the other possibility is that \"e\" is a BinaryExpr\n                  CoPredicate predicate = (CoPredicate)fce.Function;\n                  focalPredicates.Add(predicate);\n                  // For every focal predicate P in S, add to S all co-predicates in the same strongly connected\n                  // component (in the call graph) as P\n                  foreach (var node in predicate.EnclosingClass.Module.CallGraph.GetSCC(predicate)) {\n                    if (node is CoPredicate) {\n                      focalPredicates.Add((CoPredicate)node);\n                    }\n                  }\n                }\n              }\n            }\n          } else {\n            // compute the preconditions of the prefix lemma\n            Contract.Assume(prefixLemma.Req.Count == 0);  // these are not supposed to have been filled in before\n            foreach (var p in com.Req) {\n              var antecedents = new HashSet<Expression>();\n              CollectFriendlyCallsInFixpointLemmaSpecification(p.E, true, antecedents, false, com);\n              var subst = new FixpointLemmaSpecificationSubstituter(antecedents, new IdentifierExpr(k.tok, k.Name), this.reporter, false);\n              var pre = subst.CloneExpr(p.E);\n              prefixLemma.Req.Add(new MaybeFreeExpression(pre, p.IsFree));\n              foreach (var e in antecedents) {\n                var fce = (FunctionCallExpr)e;  // we expect \"antecedents\" to contain only FunctionCallExpr's\n                InductivePredicate predicate = (InductivePredicate)fce.Function;\n                focalPredicates.Add(predicate);\n                // For every focal predicate P in S, add to S all inductive predicates in the same strongly connected\n                // component (in the call graph) as P\n                foreach (var node in predicate.EnclosingClass.Module.CallGraph.GetSCC(predicate)) {\n                  if (node is InductivePredicate) {\n                    focalPredicates.Add((InductivePredicate)node);\n                  }\n                }\n              }\n            }\n          }\n          reporter.Info(MessageSource.Resolver, com.tok,\n            string.Format(\"{0} with focal predicate{2} {1}\", com.PrefixLemma.Name, Util.Comma(focalPredicates, p => p.Name), focalPredicates.Count == 1 ? \"\" : \"s\"));\n          // Compute the statement body of the prefix lemma\n          Contract.Assume(prefixLemma.Body == null);  // this is not supposed to have been filled in before\n          if (com.Body != null) {\n            var kMinusOne = new BinaryExpr(com.tok, BinaryExpr.Opcode.Sub, new IdentifierExpr(k.tok, k.Name), new LiteralExpr(com.tok, 1));\n            var subst = new FixpointLemmaBodyCloner(com, kMinusOne, focalPredicates, this.reporter);\n            var mainBody = subst.CloneBlockStmt(com.Body);\n            Expression kk;\n            Statement els;\n            if (k.Type.IsBigOrdinalType) {\n              kk = new MemberSelectExpr(k.tok, new IdentifierExpr(k.tok, k.Name), \"Offset\");\n              // As an \"else\" branch, we add recursive calls for the limit case.  When automatic induction is on,\n              // this get handled automatically, but we still want it in the case when automatic inductino has been\n              // turned off.\n              //     forall k', params | k' < _k && Precondition {\n              //       pp(k', params);\n              //     }\n              Contract.Assume(builtIns.ORDINAL_Offset != null);  // should have been filled in earlier\n              var kId = new IdentifierExpr(com.tok, k);\n              var kprimeVar = new BoundVar(com.tok, \"_k'\", Type.BigOrdinal);\n              var kprime = new IdentifierExpr(com.tok, kprimeVar);\n              var smaller = Expression.CreateLess(kprime, kId);\n\n              var bvs = new List<BoundVar>();  // TODO: populate with k', params\n              var substMap = new Dictionary<IVariable, Expression>();\n              foreach (var inFormal in prefixLemma.Ins) {\n                if (inFormal == k) {\n                  bvs.Add(kprimeVar);\n                  substMap.Add(k, kprime);\n                } else {\n                  var bv = new BoundVar(inFormal.tok, inFormal.Name, inFormal.Type);\n                  bvs.Add(bv);\n                  substMap.Add(inFormal, new IdentifierExpr(com.tok, bv));\n                }\n              }\n\n              List<Type> typeApplication;\n              Dictionary<TypeParameter, Type> typeArgumentSubstitutions;  // not used\n              Expression recursiveCallReceiver;\n              List<Expression> recursiveCallArgs;\n              Translator.RecursiveCallParameters(com.tok, prefixLemma, prefixLemma.TypeArgs, prefixLemma.Ins, substMap, out typeApplication, out typeArgumentSubstitutions, out recursiveCallReceiver, out recursiveCallArgs);\n              var methodSel = new MemberSelectExpr(com.tok, recursiveCallReceiver, prefixLemma.Name);\n              methodSel.Member = prefixLemma;  // resolve here\n              methodSel.TypeApplication = typeApplication;\n              methodSel.Type = new InferredTypeProxy();\n              var recursiveCall = new CallStmt(com.tok, com.tok, new List<Expression>(), methodSel, recursiveCallArgs);\n              recursiveCall.IsGhost = prefixLemma.IsGhost;  // resolve here\n\n              var range = smaller;  // The range will be strengthened later with the call's precondition, substituted\n                                    // appropriately (which can only be done once the precondition has been resolved).\n              var attrs = new Attributes(\"_autorequires\", new List<Expression>(), null);\n#if VERIFY_CORRECTNESS_OF_TRANSLATION_FORALL_STATEMENT_RANGE\n              // don't add the :_trustWellformed attribute\n#else\n              attrs = new Attributes(\"_trustWellformed\", new List<Expression>(), attrs);\n#endif\n              attrs = new Attributes(\"auto_generated\", new List<Expression>(), attrs);\n              var forallBody = new BlockStmt(com.tok, com.tok, new List<Statement>() { recursiveCall });\n              var forallStmt = new ForallStmt(com.tok, com.tok, bvs, attrs, range, new List<MaybeFreeExpression>(), forallBody);\n              els = new BlockStmt(com.BodyStartTok, mainBody.EndTok, new List<Statement>() { forallStmt });\n            } else {\n              kk = new IdentifierExpr(k.tok, k.Name);\n              els = null;\n            }\n            var kPositive = new BinaryExpr(com.tok, BinaryExpr.Opcode.Lt, new LiteralExpr(com.tok, 0), kk);\n            var condBody = new IfStmt(com.BodyStartTok, mainBody.EndTok, false, kPositive, mainBody, els);\n            prefixLemma.Body = new BlockStmt(com.tok, condBody.EndTok, new List<Statement>() { condBody });\n          }\n          // The prefix lemma now has all its components, so it's finally time we resolve it\n          currentClass = (ClassDecl)prefixLemma.EnclosingClass;\n          allTypeParameters.PushMarker();\n          ResolveTypeParameters(currentClass.TypeArgs, false, currentClass);\n          ResolveTypeParameters(prefixLemma.TypeArgs, false, prefixLemma);\n          ResolveMethod(prefixLemma);\n          allTypeParameters.PopMarker();\n          currentClass = null;\n          CheckTypeInference_Member(prefixLemma);\n        }\n      }\n\n      // Perform the stratosphere check on inductive datatypes, and compute to what extent the inductive datatypes require equality support\n      foreach (var dtd in datatypeDependencies.TopologicallySortedComponents()) {\n        if (datatypeDependencies.GetSCCRepresentative(dtd) == dtd) {\n          // do the following check once per SCC, so call it on each SCC representative\n          SccStratosphereCheck(dtd, datatypeDependencies);\n          DetermineEqualitySupport(dtd, datatypeDependencies);\n        }\n      }\n\n      // Set the SccRepr field of codatatypes\n      foreach (var repr in codatatypeDependencies.TopologicallySortedComponents()) {\n        foreach (var codt in codatatypeDependencies.GetSCC(repr)) {\n          codt.SscRepr = repr;\n        }\n      }\n\n      if (reporter.Count(ErrorLevel.Error) == prevErrorCount) {  // because CheckCoCalls requires the given expression to have been successfully resolved\n        // Perform the guardedness check on co-datatypes\n        foreach (var repr in ModuleDefinition.AllFunctionSCCs(declarations)) {\n          var module = repr.EnclosingModule;\n          bool dealsWithCodatatypes = false;\n          foreach (var m in module.CallGraph.GetSCC(repr)) {\n            var f = m as Function;\n            if (f != null && f.ResultType.InvolvesCoDatatype) {\n              dealsWithCodatatypes = true;\n              break;\n            }\n          }\n          var coCandidates = new List<CoCallResolution.CoCallInfo>();\n          var hasIntraClusterCallsInDestructiveContexts = false;\n          foreach (var m in module.CallGraph.GetSCC(repr)) {\n            var f = m as Function;\n            if (f != null && f.Body != null) {\n              var checker = new CoCallResolution(f, dealsWithCodatatypes);\n              checker.CheckCoCalls(f.Body);\n              coCandidates.AddRange(checker.FinalCandidates);\n              hasIntraClusterCallsInDestructiveContexts |= checker.HasIntraClusterCallsInDestructiveContexts;\n            } else if (f == null) {\n              // the SCC contains a method, which we always consider to be a destructive context\n              hasIntraClusterCallsInDestructiveContexts = true;\n            }\n          }\n          if (coCandidates.Count != 0) {\n            if (hasIntraClusterCallsInDestructiveContexts) {\n              foreach (var c in coCandidates) {\n                c.CandidateCall.CoCall = FunctionCallExpr.CoCallResolution.NoBecauseRecursiveCallsInDestructiveContext;\n              }\n            } else {\n              foreach (var c in coCandidates) {\n                c.CandidateCall.CoCall = FunctionCallExpr.CoCallResolution.Yes;\n                c.EnclosingCoConstructor.IsCoCall = true;\n                reporter.Info(MessageSource.Resolver, c.CandidateCall.tok, \"co-recursive call\");\n              }\n              // Finally, fill in the CoClusterTarget field\n              // Start by setting all the CoClusterTarget fields to CoRecursiveTargetAllTheWay.\n              foreach (var m in module.CallGraph.GetSCC(repr)) {\n                var f = (Function)m;  // the cast is justified on account of that we allow co-recursive calls only in clusters that have no methods at all\n                f.CoClusterTarget = Function.CoCallClusterInvolvement.CoRecursiveTargetAllTheWay;\n              }\n              // Then change the field to IsMutuallyRecursiveTarget whenever we see a non-self recursive non-co-recursive call\n              foreach (var m in module.CallGraph.GetSCC(repr)) {\n                var f = (Function)m;  // cast is justified just like above\n                foreach (var call in f.AllCalls) {\n                  if (call.CoCall != FunctionCallExpr.CoCallResolution.Yes && call.Function != f && ModuleDefinition.InSameSCC(f, call.Function)) {\n                    call.Function.CoClusterTarget = Function.CoCallClusterInvolvement.IsMutuallyRecursiveTarget;\n                  }\n                }\n              }\n            }\n          }\n        }\n        // Inferred required equality support for datatypes and type synonyms, and for Function and Method signatures.\n        // First, do datatypes and type synonyms until a fixpoint is reached.\n        bool inferredSomething;\n        do {\n          inferredSomething = false;\n          foreach (var d in declarations) {\n            if (Attributes.Contains(d.Attributes, \"_provided\")) {\n              // Don't infer required-equality-support for the type parameters, since there are\n              // scopes that see the name of the declaration but not its body.\n            } else if (d is DatatypeDecl) {\n              var dt = (DatatypeDecl)d;\n              foreach (var tp in dt.TypeArgs) {\n                if (tp.Characteristics.EqualitySupport == TypeParameter.EqualitySupportValue.Unspecified) {\n                  // here's our chance to infer the need for equality support\n                  foreach (var ctor in dt.Ctors) {\n                    foreach (var arg in ctor.Formals) {\n                      if (InferRequiredEqualitySupport(tp, arg.Type)) {\n                        tp.Characteristics.EqualitySupport = TypeParameter.EqualitySupportValue.InferredRequired;\n                        inferredSomething = true;\n                        goto DONE_DT;  // break out of the doubly-nested loop\n                      }\n                    }\n                  }\n                  DONE_DT:;\n                }\n              }\n            } else if (d is TypeSynonymDecl) {\n              var syn = (TypeSynonymDecl)d;\n              foreach (var tp in syn.TypeArgs) {\n                if (tp.Characteristics.EqualitySupport == TypeParameter.EqualitySupportValue.Unspecified) {\n                  // here's our chance to infer the need for equality support\n                  if (InferRequiredEqualitySupport(tp, syn.Rhs)) {\n                    tp.Characteristics.EqualitySupport = TypeParameter.EqualitySupportValue.InferredRequired;\n                    inferredSomething = true;\n                  }\n                }\n              }\n            }\n          }\n        } while (inferredSomething);\n        // Now do it for Function and Method signatures.\n        foreach (var d in declarations) {\n          if (d is IteratorDecl) {\n            var iter = (IteratorDecl)d;\n            var done = false;\n            foreach (var tp in iter.TypeArgs) {\n              if (tp.Characteristics.EqualitySupport == TypeParameter.EqualitySupportValue.Unspecified) {\n                // here's our chance to infer the need for equality support\n                foreach (var p in iter.Ins) {\n                  if (InferRequiredEqualitySupport(tp, p.Type)) {\n                    tp.Characteristics.EqualitySupport = TypeParameter.EqualitySupportValue.InferredRequired;\n                    done = true;\n                    break;\n                  }\n                }\n                foreach (var p in iter.Outs) {\n                  if (done) break;\n                  if (InferRequiredEqualitySupport(tp, p.Type)) {\n                    tp.Characteristics.EqualitySupport = TypeParameter.EqualitySupportValue.InferredRequired;\n                    break;\n                  }\n                }\n              }\n            }\n          } else if (d is ClassDecl) {\n            var cl = (ClassDecl)d;\n            foreach (var member in cl.Members) {\n              if (!member.IsGhost) {\n                if (member is Function) {\n                  var f = (Function)member;\n                  foreach (var tp in f.TypeArgs) {\n                    if (tp.Characteristics.EqualitySupport == TypeParameter.EqualitySupportValue.Unspecified) {\n                      // here's our chance to infer the need for equality support\n                      if (InferRequiredEqualitySupport(tp, f.ResultType)) {\n                        tp.Characteristics.EqualitySupport = TypeParameter.EqualitySupportValue.InferredRequired;\n                      } else {\n                        foreach (var p in f.Formals) {\n                          if (InferRequiredEqualitySupport(tp, p.Type)) {\n                            tp.Characteristics.EqualitySupport = TypeParameter.EqualitySupportValue.InferredRequired;\n                            break;\n                          }\n                        }\n                      }\n                    }\n                  }\n                } else if (member is Method) {\n                  var m = (Method)member;\n                  bool done = false;\n                  foreach (var tp in m.TypeArgs) {\n                    if (tp.Characteristics.EqualitySupport == TypeParameter.EqualitySupportValue.Unspecified) {\n                      // here's our chance to infer the need for equality support\n                      foreach (var p in m.Ins) {\n                        if (InferRequiredEqualitySupport(tp, p.Type)) {\n                          tp.Characteristics.EqualitySupport = TypeParameter.EqualitySupportValue.InferredRequired;\n                          done = true;\n                          break;\n                        }\n                      }\n                      foreach (var p in m.Outs) {\n                        if (done) break;\n                        if (InferRequiredEqualitySupport(tp, p.Type)) {\n                          tp.Characteristics.EqualitySupport = TypeParameter.EqualitySupportValue.InferredRequired;\n                          break;\n                        }\n                      }\n                    }\n                  }\n                }\n              }\n            }\n          }\n        }\n        // Check that functions claiming to be abstemious really are\n        foreach (var fn in ModuleDefinition.AllFunctions(declarations)) {\n          if (fn.Body != null) {\n            var abstemious = true;\n            if (Attributes.ContainsBool(fn.Attributes, \"abstemious\", ref abstemious) && abstemious) {\n              if (CoCallResolution.GuaranteedCoCtors(fn) == 0) {\n                reporter.Error(MessageSource.Resolver, fn, \"the value returned by an abstemious function must come from invoking a co-constructor\");\n              } else {\n                CheckDestructsAreAbstemiousCompliant(fn.Body);\n              }\n            }\n          }\n        }\n        // Check that all == and != operators in non-ghost contexts are applied to equality-supporting types.\n        // Note that this check can only be done after determining which expressions are ghosts.\n        foreach (var d in declarations) {\n          if (d is IteratorDecl) {\n            var iter = (IteratorDecl)d;\n            foreach (var p in iter.Ins) {\n              if (!p.IsGhost) {\n                CheckEqualityTypes_Type(p.tok, p.Type);\n              }\n            }\n            foreach (var p in iter.Outs) {\n              if (!p.IsGhost) {\n                CheckEqualityTypes_Type(p.tok, p.Type);\n              }\n            }\n            if (iter.Body != null) {\n              CheckEqualityTypes_Stmt(iter.Body);\n            }\n          } else if (d is ClassDecl) {\n            var cl = (ClassDecl)d;\n            foreach (var member in cl.Members) {\n              if (!member.IsGhost) {\n                if (member is Field) {\n                  var f = (Field)member;\n                  CheckEqualityTypes_Type(f.tok, f.Type);\n                } else if (member is Function) {\n                  var f = (Function)member;\n                  foreach (var p in f.Formals) {\n                    if (!p.IsGhost) {\n                      CheckEqualityTypes_Type(p.tok, p.Type);\n                    }\n                  }\n                  CheckEqualityTypes_Type(f.tok, f.ResultType);\n                  if (f.Body != null) {\n                    CheckEqualityTypes(f.Body);\n                  }\n                } else if (member is Method) {\n                  var m = (Method)member;\n                  foreach (var p in m.Ins) {\n                    if (!p.IsGhost) {\n                      CheckEqualityTypes_Type(p.tok, p.Type);\n                    }\n                  }\n                  foreach (var p in m.Outs) {\n                    if (!p.IsGhost) {\n                      CheckEqualityTypes_Type(p.tok, p.Type);\n                    }\n                  }\n                  if (m.Body != null) {\n                    CheckEqualityTypes_Stmt(m.Body);\n                  }\n                }\n              }\n            }\n          } else if (d is DatatypeDecl) {\n            var dt = (DatatypeDecl)d;\n            foreach (var ctor in dt.Ctors) {\n              foreach (var p in ctor.Formals) {\n                if (!p.IsGhost) {\n                  CheckEqualityTypes_Type(p.tok, p.Type);\n                }\n              }\n            }\n          } else if (d is TypeSynonymDecl) {\n            var syn = (TypeSynonymDecl)d;\n            CheckEqualityTypes_Type(syn.tok, syn.Rhs);\n            if (syn.MustSupportEquality && !syn.Rhs.SupportsEquality) {\n              reporter.Error(MessageSource.Resolver, syn.tok, \"type '{0}' declared as supporting equality, but the RHS type ({1}) does not\", syn.Name, syn.Rhs);\n            }\n          }\n        }\n        // Check that fixpoint-predicates are not recursive with non-fixpoint-predicate functions (and only\n        // with fixpoint-predicates of the same polarity), and\n        // check that colemmas are not recursive with non-colemma methods.\n        // Also, check that the constraints of newtypes/subset-types do not depend on the type itself.\n        // And check that const initializers are not cyclic.\n        var cycleErrorHasBeenReported = new HashSet<ICallable>();\n        foreach (var d in declarations) {\n          if (d is ClassDecl) {\n            foreach (var member in ((ClassDecl)d).Members) {\n              if (member is FixpointPredicate) {\n                var fn = (FixpointPredicate)member;\n                // Check here for the presence of any 'ensures' clauses, which are not allowed (because we're not sure\n                // of their soundness)\n                if (fn.Ens.Count != 0) {\n                  reporter.Error(MessageSource.Resolver, fn.Ens[0].E.tok, \"a {0} is not allowed to declare any ensures clause\", member.WhatKind);\n                }\n                if (fn.Body != null) {\n                  FixpointPredicateChecks(fn.Body, fn, CallingPosition.Positive);\n                }\n              } else if (member is FixpointLemma) {\n                var m = (FixpointLemma)member;\n                if (m.Body != null) {\n                  FixpointLemmaChecks(m.Body, m);\n                }\n              } else if (member is ConstantField) {\n                var cf = (ConstantField)member;\n                if (cf.EnclosingModule.CallGraph.GetSCCSize(cf) != 1) {\n                  var r = cf.EnclosingModule.CallGraph.GetSCCRepresentative(cf);\n                  if (cycleErrorHasBeenReported.Contains(r)) {\n                    // An error has already been reported for this cycle, so don't report another.\n                    // Note, the representative, \"r\", may itself not be a const.\n                  } else {\n                    cycleErrorHasBeenReported.Add(r);\n                    var cycle = Util.Comma(\" -> \", cf.EnclosingModule.CallGraph.GetSCC(cf), clbl => clbl.NameRelativeToModule);\n                    reporter.Error(MessageSource.Resolver, cf.tok, \"const definition contains a cycle: \" + cycle);\n                  }\n                }\n              }\n            }\n          } else if (d is SubsetTypeDecl || d is NewtypeDecl) {\n            var dd = (RedirectingTypeDecl)d;\n            if (d.Module.CallGraph.GetSCCSize(dd) != 1) {\n              var r = d.Module.CallGraph.GetSCCRepresentative(dd);\n              if (cycleErrorHasBeenReported.Contains(r)) {\n                // An error has already been reported for this cycle, so don't report another.\n                // Note, the representative, \"r\", may itself not be a const.\n              } else {\n                cycleErrorHasBeenReported.Add(r);\n                var cycle = Util.Comma(\" -> \", d.Module.CallGraph.GetSCC(dd), clbl => clbl.NameRelativeToModule);\n                reporter.Error(MessageSource.Resolver, d.tok, \"recursive constraint dependency involving a {0}: {1}\", d.WhatKind, cycle);\n              }\n            }\n          }\n        }\n      }\n\n      // ---------------------------------- Pass 3 ----------------------------------\n      // Further checks\n      // ----------------------------------------------------------------------------\n\n      if (reporter.Count(ErrorLevel.Error) == prevErrorCount) {\n        // Check that type-parameter variance is respected in type definitions\n        foreach (TopLevelDecl d in declarations) {\n          if (d is IteratorDecl || d is ClassDecl) {\n            foreach (var tp in d.TypeArgs) {\n              if (tp.Variance != TypeParameter.TPVariance.Non) {\n                reporter.Error(MessageSource.Resolver, tp.tok, \"{0} declarations only support non-variant type parameters\", d.WhatKind);\n              }\n            }\n          } else if (d is TypeSynonymDecl) {\n            var dd = (TypeSynonymDecl)d;\n            CheckVariance(dd.Rhs, dd, TypeParameter.TPVariance.Co, false);\n          } else if (d is NewtypeDecl) {\n            var dd = (NewtypeDecl)d;\n            CheckVariance(dd.BaseType, dd, TypeParameter.TPVariance.Co, false);\n          } else if (d is DatatypeDecl) {\n            var dd = (DatatypeDecl)d;\n            foreach (var ctor in dd.Ctors) {\n              ctor.Formals.Iter(formal => CheckVariance(formal.Type, dd, TypeParameter.TPVariance.Co, false));\n            }\n          }\n        }\n      }\n\n      if (reporter.Count(ErrorLevel.Error) == prevErrorCount && moduleInfo.ModuleType != ArmadaModuleType.ArmadaLevel\n          && moduleInfo.ModuleType != ArmadaModuleType.ArmadaStructs) {\n        // Check that usage of \"this\" is restricted before \"new;\" in constructor bodies,\n        // and that a class without any constructor only has fields with known initializers.\n        // Also check that static fields (which are necessarily const) have initializers.\n        var cdci = new CheckDividedConstructorInit_Visitor(this);\n        foreach (var cl in ModuleDefinition.AllClasses(declarations)) {\n          if (cl is TraitDecl) {\n            // traits never have constructors, but check for static consts\n            foreach (var member in cl.Members) {\n              if (member is ConstantField && member.IsStatic && !member.IsGhost) {\n                var f = (ConstantField)member;\n                if (!cl.Module.IsAbstract && f.Rhs == null && !Compiler.InitializerIsKnown(f.Type) && !f.IsExtern(out _, out _)) {\n                  reporter.Error(MessageSource.Resolver, f.tok, \"static non-ghost const field '{0}' of type '{1}' (which does not have a default compiled value) must give a defining value\",\n                    f.Name, f.Type);\n                }\n              }\n            }\n            continue;\n          }\n          var hasConstructor = false;\n          Field fieldWithoutKnownInitializer = null;\n          foreach (var member in cl.Members) {\n            if (member is Constructor) {\n              hasConstructor = true;\n              var constructor = (Constructor)member;\n              if (constructor.BodyInit != null) {\n                cdci.CheckInit(constructor.BodyInit);\n              }\n            } else if (member is ConstantField && member.IsStatic && !member.IsGhost) {\n              var f = (ConstantField)member;\n              if (!cl.Module.IsAbstract && f.Rhs == null && !Compiler.InitializerIsKnown(f.Type) && !f.IsExtern(out _, out _)) {\n                reporter.Error(MessageSource.Resolver, f.tok, \"static non-ghost const field '{0}' of type '{1}' (which does not have a default compiled value) must give a defining value\",\n                  f.Name, f.Type);\n              }\n            } else if (member is Field && !member.IsGhost && fieldWithoutKnownInitializer == null) {\n              var f = (Field)member;\n              if (f is ConstantField && ((ConstantField)f).Rhs != null) {\n                // fine\n              } else if (!Compiler.InitializerIsKnown(f.Type)) {\n                fieldWithoutKnownInitializer = f;\n              }\n            }\n          }\n          if (!hasConstructor) {\n            if (fieldWithoutKnownInitializer == null) {\n              // time to check inherited members\n              foreach (var member in cl.InheritedMembers) {\n                if (member is Field && !member.IsGhost) {\n                  var f = (Field)member;\n                  if (f is ConstantField && ((ConstantField)f).Rhs != null) {\n                    // fine\n                  } else if (!Compiler.InitializerIsKnown(f.Type)) {\n                    fieldWithoutKnownInitializer = f;\n                    break;\n                  }\n                }\n              }\n            }\n            // go through inherited members...\n            if (fieldWithoutKnownInitializer != null) {\n              reporter.Error(MessageSource.Resolver, cl.tok, \"class '{0}' with fields without known initializers, like '{1}' of type '{2}', must declare a constructor\",\n                cl.Name, fieldWithoutKnownInitializer.Name, fieldWithoutKnownInitializer.Type);\n            }\n          }\n        }\n      }\n    }\n\n    private void ResolveClassMembers_Pass1(TopLevelDeclWithMembers cl) {\n      foreach (var member in cl.Members) {\n        var prevErrCnt = reporter.Count(ErrorLevel.Error);\n        CheckTypeInference_Member(member);\n        if (prevErrCnt == reporter.Count(ErrorLevel.Error)) {\n          if (member is Method) {\n            var m = (Method)member;\n            if (m.Body != null) {\n              if (Attributes.Contains(cl.Module.Attributes, \"concrete\") || cl.Module.ModuleType == ArmadaModuleType.ArmadaStructs) {\n                ComputeGhostInterest(m.Body, m.IsGhost, m);\n                CheckExpression(m.Body, this, m);\n                DetermineTailRecursion(m);\n              }\n            }\n          } else if (member is Function) {\n            var f = (Function)member;\n            if (!f.IsGhost && f.Body != null) {\n              CheckIsCompilable(f.Body);\n            }\n            DetermineTailRecursion(f);\n          }\n          if (prevErrCnt == reporter.Count(ErrorLevel.Error) && member is ICodeContext) {\n            member.SubExpressions.Iter(e => CheckExpression(e, this, (ICodeContext)member));\n          }\n        }\n      }\n    }\n\n    private void CheckDestructsAreAbstemiousCompliant(Expression expr) {\n      Contract.Assert(expr != null);\n      expr = expr.Resolved;\n      if (expr is MemberSelectExpr) {\n        var e = (MemberSelectExpr)expr;\n        if (e.Member.EnclosingClass is CoDatatypeDecl) {\n          var ide = Expression.StripParens(e.Obj).Resolved as IdentifierExpr;\n          if (ide != null && ide.Var is Formal) {\n            // cool\n          } else {\n            reporter.Error(MessageSource.Resolver, expr, \"an abstemious function is allowed to invoke a codatatype destructor only on its parameters\");\n          }\n          return;\n        }\n      } else if (expr is MatchExpr) {\n        var e = (MatchExpr)expr;\n        if (e.Source.Type.IsCoDatatype) {\n          var ide = Expression.StripParens(e.Source).Resolved as IdentifierExpr;\n          if (ide != null && ide.Var is Formal) {\n            // cool; fall through to check match branches\n          } else {\n            reporter.Error(MessageSource.Resolver, e.Source, \"an abstemious function is allowed to codatatype-match only on its parameters\");\n            return;\n          }\n        }\n      } else if (expr is BinaryExpr) {\n        var e = (BinaryExpr)expr;\n        if (e.ResolvedOp == BinaryExpr.ResolvedOpcode.EqCommon || e.ResolvedOp == BinaryExpr.ResolvedOpcode.NeqCommon) {\n          if (e.E0.Type.IsCoDatatype) {\n            reporter.Error(MessageSource.Resolver, expr, \"an abstemious function is not only allowed to check codatatype equality\");\n            return;\n          }\n        }\n      } else if (expr is StmtExpr) {\n        var e = (StmtExpr)expr;\n        // ignore the statement part\n        CheckDestructsAreAbstemiousCompliant(e.E);\n        return;\n      }\n      expr.SubExpressions.Iter(CheckDestructsAreAbstemiousCompliant);\n    }\n\n    /// <summary>\n    /// Add edges to the callgraph.\n    /// </summary>\n    private void AddTypeDependencyEdges(ICodeContext context, Type type) {\n      Contract.Requires(type != null);\n      Contract.Requires(context != null);\n      var caller = context as ICallable;\n      if (caller != null && type is NonProxyType) {\n        type.ForeachTypeComponent(ty => {\n          var udt = ty as UserDefinedType;\n          var cl = udt == null ? null : udt.ResolvedClass as ICallable;\n          if (cl != null) {\n            caller.EnclosingModule.CallGraph.AddEdge(caller, cl);\n          }\n        });\n      }\n    }\n\n    private void FigureOutNativeType(NewtypeDecl dd) {\n      Contract.Requires(dd != null);\n      bool? boolNativeType = null;\n      NativeType stringNativeType = null;\n      object nativeTypeAttr = true;\n      bool hasNativeTypeAttr = Attributes.ContainsMatchingValue(dd.Attributes, \"nativeType\", ref nativeTypeAttr,\n        new Attributes.MatchingValueOption[] {\n                Attributes.MatchingValueOption.Empty,\n                Attributes.MatchingValueOption.Bool,\n                Attributes.MatchingValueOption.String },\n        err => reporter.Error(MessageSource.Resolver, dd, err));\n      if (hasNativeTypeAttr) {\n        if (nativeTypeAttr is bool) {\n          boolNativeType = (bool)nativeTypeAttr;\n        } else {\n          var keyString = (string)nativeTypeAttr;\n          foreach (var nativeT in NativeTypes) {\n            if (nativeT.Name == keyString) {\n              if ((nativeT.CompilationTargets & ArmadaOptions.O.CompileTarget) == 0) {\n                reporter.Error(MessageSource.Resolver, dd, \"nativeType '{0}' not supported on the current compilation target\", keyString);\n              } else {\n                stringNativeType = nativeT;\n              }\n              break;\n            }\n          }\n          if (stringNativeType == null) {\n            reporter.Error(MessageSource.Resolver, dd, \"nativeType '{0}' not known\", keyString);\n          }\n        }\n      }\n      // Figure out the variable and constraint.  Usually, these would be just .Var and .Constraint, but\n      // in the case .Var is null, these can be computed from the .BaseType recursively.\n      var ddVar = dd.Var;\n      var ddConstraint = dd.Constraint;\n      for (var ddWhereConstraintsAre = dd; ddVar == null;) {\n        ddWhereConstraintsAre = ddWhereConstraintsAre.BaseType.AsNewtype;\n        if (ddWhereConstraintsAre == null) {\n          break;\n        }\n        ddVar = ddWhereConstraintsAre.Var;\n        ddConstraint = ddWhereConstraintsAre.Constraint;\n      }\n      if (stringNativeType != null || boolNativeType == true) {\n        if (!dd.BaseType.IsNumericBased(Type.NumericPersuation.Int)) {\n          reporter.Error(MessageSource.Resolver, dd, \"nativeType can only be used on integral types\");\n        }\n        if (ddVar == null) {\n          reporter.Error(MessageSource.Resolver, dd, \"nativeType can only be used if newtype specifies a constraint\");\n        }\n      }\n      if (ddVar != null) {\n        Func<Expression, BigInteger?> GetConst = null;\n        GetConst = (Expression e) => {\n          int m = 1;\n          BinaryExpr bin = e as BinaryExpr;\n          if (bin != null && bin.Op == BinaryExpr.Opcode.Sub && GetConst(bin.E0) == BigInteger.Zero) {\n            m = -1;\n            e = bin.E1;\n          }\n          LiteralExpr l = e as LiteralExpr;\n          if (l != null && l.Value is BigInteger) {\n            return m * (BigInteger)l.Value;\n          }\n          return null;\n        };\n        var bounds = DiscoverAllBounds_SingleVar(ddVar, ddConstraint);\n        List<NativeType> potentialNativeTypes =\n          (stringNativeType != null) ? new List<NativeType> { stringNativeType } :\n          (boolNativeType == false) ? new List<NativeType>() :\n          NativeTypes.Where(nt => (nt.CompilationTargets & ArmadaOptions.O.CompileTarget) != 0).ToList();\n        foreach (var nt in potentialNativeTypes) {\n          bool lowerOk = false;\n          bool upperOk = false;\n          foreach (var bound in bounds) {\n            if (bound is ComprehensionExpr.IntBoundedPool) {\n              var bnd = (ComprehensionExpr.IntBoundedPool)bound;\n              if (bnd.LowerBound != null) {\n                BigInteger? lower = GetConst(bnd.LowerBound);\n                if (lower != null && nt.LowerBound <= lower) {\n                  lowerOk = true;\n                }\n              }\n              if (bnd.UpperBound != null) {\n                BigInteger? upper = GetConst(bnd.UpperBound);\n                if (upper != null && upper <= nt.UpperBound) {\n                  upperOk = true;\n                }\n              }\n            }\n          }\n          if (lowerOk && upperOk) {\n            dd.NativeType = nt;\n            break;\n          }\n        }\n        if (dd.NativeType == null && (boolNativeType == true || stringNativeType != null)) {\n          reporter.Error(MessageSource.Resolver, dd, \"Dafny's heuristics cannot find a compatible native type.  \" +\n            \"Hint: try writing a newtype constraint of the form 'i:int | lowerBound <= i < upperBound && (...any additional constraints...)'\");\n        }\n        if (dd.NativeType != null && stringNativeType == null) {\n          reporter.Info(MessageSource.Resolver, dd.tok, \"{:nativeType \\\"\" + dd.NativeType.Name + \"\\\"}\");\n        }\n      }\n    }\n\n    TypeProxy NewIntegerBasedProxy(IToken tok) {\n      Contract.Requires(tok != null);\n      var proxy = new InferredTypeProxy();\n      ConstrainSubtypeRelation(new IntVarietiesSupertype(), proxy, tok, \"integer literal used as if it had type {0}\", proxy);\n      return proxy;\n    }\n\n    private bool ConstrainSubtypeRelation(Type super, Type sub, Expression exprForToken, string msg, params object[] msgArgs) {\n      Contract.Requires(sub != null);\n      Contract.Requires(super != null);\n      Contract.Requires(exprForToken != null);\n      Contract.Requires(msg != null);\n      Contract.Requires(msgArgs != null);\n      return ConstrainSubtypeRelation(super, sub, exprForToken.tok, msg, msgArgs);\n    }\n    private void ConstrainTypeExprBool(Expression e, string msg) {\n      Contract.Requires(e != null);\n      Contract.Requires(msg != null);  // expected to have a {0} part\n      ConstrainSubtypeRelation(Type.Bool, e.Type, e, msg, e.Type);\n    }\n    private bool ConstrainSubtypeRelation(Type super, Type sub, IToken tok, string msg, params object[] msgArgs) {\n      Contract.Requires(sub != null);\n      Contract.Requires(super != null);\n      Contract.Requires(tok != null);\n      Contract.Requires(msg != null);\n      Contract.Requires(msgArgs != null);\n      return ConstrainSubtypeRelation(super, sub, new TypeConstraint.ErrorMsgWithToken(tok, msg, msgArgs));\n    }\n\n    private void ConstrainAssignable(NonProxyType lhs, Type rhs, TypeConstraint.ErrorMsg errMsg, out bool moreXConstraints, bool allowDecisions) {\n      Contract.Requires(lhs != null);\n      Contract.Requires(rhs != null);\n      Contract.Requires(errMsg != null);\n\n      bool isRoot, isLeaf, headIsRoot, headIsLeaf;\n      CheckEnds(lhs, out isRoot, out isLeaf, out headIsRoot, out headIsLeaf);\n      if (isRoot) {\n        ConstrainSubtypeRelation(lhs, rhs, errMsg, true, allowDecisions);\n        moreXConstraints = false;\n      } else {\n        var lhsWithProxyArgs = Type.HeadWithProxyArgs(lhs);\n        ConstrainSubtypeRelation(lhsWithProxyArgs, rhs, errMsg, false, allowDecisions);\n        ConstrainAssignableTypeArgs(lhs, lhsWithProxyArgs.TypeArgs, lhs.TypeArgs, errMsg, out moreXConstraints);\n      }\n    }\n\n    private void ConstrainAssignableTypeArgs(Type typeHead, List<Type> A, List<Type> B, TypeConstraint.ErrorMsg errMsg, out bool moreXConstraints) {\n      Contract.Requires(typeHead != null);\n      Contract.Requires(A != null);\n      Contract.Requires(B != null);\n      Contract.Requires(A.Count == B.Count);\n      Contract.Requires(errMsg != null);\n\n      var tok = errMsg.Tok;\n      if (B.Count == 0) {\n        // all done\n        moreXConstraints = false;\n      } else if (typeHead is MapType) {\n        var em = new TypeConstraint.ErrorMsgWithBase(errMsg, \"covariance for type parameter 0 expects {1} <: {0}\", A[0], B[0]);\n        AddAssignableConstraint(tok, A[0], B[0], em);\n        em = new TypeConstraint.ErrorMsgWithBase(errMsg, \"covariance for type parameter 1 expects {1} <: {0}\", A[1], B[1]);\n        AddAssignableConstraint(tok, A[1], B[1], em);\n        moreXConstraints = true;\n      } else if (typeHead is CollectionType) {\n        var em = new TypeConstraint.ErrorMsgWithBase(errMsg, \"covariance for type parameter expects {1} <: {0}\", A[0], B[0]);\n        AddAssignableConstraint(tok, A[0], B[0], em);\n        moreXConstraints = true;\n      } else {\n        var udt = (UserDefinedType)typeHead;  // note, collections, maps, and user-defined types are the only one with TypeArgs.Count != 0\n        var cl = udt.ResolvedClass;\n        Contract.Assert(cl != null);\n        Contract.Assert(cl.TypeArgs.Count == B.Count);\n        moreXConstraints = false;\n        for (int i = 0; i < B.Count; i++) {\n          var msgFormat = \"variance for type parameter\" + (B.Count == 1 ? \"\" : \"\" + i) + \" expects {1} <: {0}\";\n          if (cl.TypeArgs[i].Variance == TypeParameter.TPVariance.Co) {\n            var em = new TypeConstraint.ErrorMsgWithBase(errMsg, \"co\" + msgFormat, A[i], B[i]);\n            AddAssignableConstraint(tok, A[i], B[i], em);\n            moreXConstraints = true;\n          } else if (cl.TypeArgs[i].Variance == TypeParameter.TPVariance.Contra) {\n            var em = new TypeConstraint.ErrorMsgWithBase(errMsg, \"contra\" + msgFormat, B[i], A[i]);\n            AddAssignableConstraint(tok, B[i], A[i], em);\n            moreXConstraints = true;\n          } else {\n            var em = new TypeConstraint.ErrorMsgWithBase(errMsg, \"non\" + msgFormat, A[i], B[i]);\n            ConstrainSubtypeRelation_Equal(A[i], B[i], em);\n          }\n        }\n      }\n    }\n\n    /// <summary>\n    /// Adds the subtyping constraint that \"a\" and \"b\" are the same type.\n    /// </summary>\n    private void ConstrainSubtypeRelation_Equal(Type a, Type b, TypeConstraint.ErrorMsg errMsg) {\n      Contract.Requires(a != null);\n      Contract.Requires(b != null);\n      Contract.Requires(errMsg != null);\n\n      var proxy = a.Normalize() as TypeProxy;\n      if (proxy != null && proxy.T == null && !Reaches(b, proxy, 1, new HashSet<TypeProxy>())) {\n        if (ArmadaOptions.O.TypeInferenceDebug) {\n          Console.WriteLine(\"DEBUG: (invariance) assigning proxy {0}.T := {1}\", proxy, b);\n        }\n        proxy.T = b;\n      }\n      proxy = b.Normalize() as TypeProxy;\n      if (proxy != null && proxy.T == null && !Reaches(a, proxy, 1, new HashSet<TypeProxy>())) {\n        if (ArmadaOptions.O.TypeInferenceDebug) {\n          Console.WriteLine(\"DEBUG: (invariance) assigning proxy {0}.T := {1}\", proxy, a);\n        }\n        proxy.T = a;\n      }\n\n      ConstrainSubtypeRelation(a, b, errMsg, true);\n      ConstrainSubtypeRelation(b, a, errMsg, true);\n    }\n\n    /// <summary>\n    /// Adds the subtyping constraint that \"sub\" is a subtype of \"super\".\n    /// If this constraint seems feasible, returns \"true\".  Otherwise, prints error message (either \"errMsg\" or something\n    /// more specific) and returns \"false\".\n    /// Note, if in doubt, this method can return \"true\", because the constraints will be checked for sure at a later stage.\n    /// </summary>\n    private bool ConstrainSubtypeRelation(Type super, Type sub, TypeConstraint.ErrorMsg errMsg, bool keepConstraints = false, bool allowDecisions = false) {\n      Contract.Requires(sub != null);\n      Contract.Requires(super != null);\n      Contract.Requires(errMsg != null);\n\n      if (!keepConstraints && super is InferredTypeProxy) {\n        var ip = (InferredTypeProxy)super;\n        if (ip.KeepConstraints) {\n          keepConstraints = true;\n        }\n      }\n      if (!keepConstraints && sub is InferredTypeProxy) {\n        var ip = (InferredTypeProxy)sub;\n        if (ip.KeepConstraints) {\n          keepConstraints = true;\n        }\n      }\n\n      super = super.NormalizeExpand(keepConstraints);\n      sub = sub.NormalizeExpand(keepConstraints);\n      var c = new TypeConstraint(super, sub, errMsg, keepConstraints);\n      AllTypeConstraints.Add(c);\n      return ConstrainSubtypeRelation_Aux(super, sub, c, keepConstraints, allowDecisions);\n    }\n    private bool ConstrainSubtypeRelation_Aux(Type super, Type sub, TypeConstraint c, bool keepConstraints, bool allowDecisions) {\n      Contract.Requires(sub != null);\n      Contract.Requires(!(sub is TypeProxy) || ((TypeProxy)sub).T == null);  // caller is expected to have Normalized away proxies\n      Contract.Requires(super != null);\n      Contract.Requires(!(super is TypeProxy) || ((TypeProxy)super).T == null);  // caller is expected to have Normalized away proxies\n      Contract.Requires(c != null);\n\n      if (object.ReferenceEquals(super, sub)) {\n        return true;\n      } else if (super is TypeProxy && sub is TypeProxy) {\n        // both are proxies\n        ((TypeProxy)sub).AddSupertype(c);\n        ((TypeProxy)super).AddSubtype(c);\n        return true;\n      } else if (sub is TypeProxy) {\n        var proxy = (TypeProxy)sub;\n        proxy.AddSupertype(c);\n        AssignKnownEnd(proxy, keepConstraints, allowDecisions);\n        return true;\n      } else if (super is TypeProxy) {\n        var proxy = (TypeProxy)super;\n        proxy.AddSubtype(c);\n        AssignKnownEnd(proxy, keepConstraints, allowDecisions);\n        return true;\n      } else {\n        // two non-proxy types\n        // set \"headSymbolsAgree\" to \"false\" if it's clear the head symbols couldn't be the same; \"true\" means they may be the same\n        bool headSymbolsAgree = Type.IsHeadSupertypeOf(super.NormalizeExpand(keepConstraints), sub);\n        if (!headSymbolsAgree) {\n          c.FlagAsError();\n          return false;\n        }\n        // TODO: inspect type parameters in order to produce some error messages sooner\n        return true;\n      }\n    }\n\n    /// <summary>\n    /// \"root\" says that the type is a non-artificial type with no proper supertypes.\n    /// \"leaf\" says that the only possible proper subtypes are subset types of the type. Thus, the only\n    /// types that are not leaf types are traits and artificial types.\n    /// The \"headIs\" versions speak only about the head symbols, so it is possible that the given\n    /// type arguments would change the root/leaf status of the entire type.\n    /// </summary>\n    void CheckEnds(Type t, out bool isRoot, out bool isLeaf, out bool headIsRoot, out bool headIsLeaf) {\n      Contract.Requires(t != null);\n      Contract.Ensures(!Contract.ValueAtReturn(out isRoot) || Contract.ValueAtReturn(out headIsRoot)); // isRoot ==> headIsRoot\n      Contract.Ensures(!Contract.ValueAtReturn(out isLeaf) || Contract.ValueAtReturn(out headIsLeaf)); // isLeaf ==> headIsLeaf\n      t = t.NormalizeExpandKeepConstraints();\n      if (t.IsBoolType || t.IsCharType || t.IsIntegerType || t.IsRealType || t.AsNewtype != null || t.IsBitVectorType || t.IsBigOrdinalType) {\n        isRoot = true; isLeaf = true;\n        headIsRoot = true; headIsLeaf = true;\n      } else if (t is ArtificialType) {\n        isRoot = false; isLeaf = false;\n        headIsRoot = false; headIsLeaf = false;\n      } else if (t.IsObjectQ) {\n        isRoot = true; isLeaf = false;\n        headIsRoot = true; headIsLeaf = false;\n      } else if (t is ArrowType) {\n        var arr = (ArrowType)t;\n        headIsRoot = true; headIsLeaf = true;  // these are definitely true\n        isRoot = true; isLeaf = true;  // set these to true until proven otherwise\n        Contract.Assert(arr.Arity + 1 == arr.TypeArgs.Count);\n        for (int i = 0; i < arr.TypeArgs.Count; i++) {\n          var arg = arr.TypeArgs[i];\n          bool r, l, hr, hl;\n          CheckEnds(arg, out r, out l, out hr, out hl);\n          if (i < arr.Arity) {\n            isRoot &= l; isLeaf &= r;  // argument types are contravariant\n          } else {\n            isRoot &= r; isLeaf &= l;  // result type is covariant\n          }\n        }\n      } else if (t is UserDefinedType) {\n        var udt = (UserDefinedType)t;\n        var cl = udt.ResolvedClass;\n        if (cl != null) {\n          if (cl is SubsetTypeDecl) {\n            headIsRoot = false; headIsLeaf = true;\n          } else if (cl is TraitDecl) {\n            headIsRoot = false; headIsLeaf = false;\n          } else if (cl is ClassDecl) {\n            headIsRoot = false; headIsLeaf = true;\n          } else if (cl is OpaqueTypeDecl) {\n            headIsRoot = true; headIsLeaf = true;\n          } else if (cl is InternalTypeSynonymDecl) {\n            Contract.Assert(object.ReferenceEquals(t, t.NormalizeExpand())); // should be opaque in scope\n            headIsRoot = true; headIsLeaf = true;\n          } else {\n            Contract.Assert(cl is DatatypeDecl);\n            headIsRoot = true; headIsLeaf = true;\n          }\n          // for \"isRoot\" and \"isLeaf\", also take into consideration the root/leaf status of type arguments\n          isRoot = headIsRoot; isLeaf = headIsLeaf;\n          Contract.Assert(udt.TypeArgs.Count == cl.TypeArgs.Count);\n          for (int i = 0; i < udt.TypeArgs.Count; i++) {\n            var variance = cl.TypeArgs[i].Variance;\n            if (variance != TypeParameter.TPVariance.Non) {\n              bool r, l, hr, hl;\n              CheckEnds(udt.TypeArgs[i], out r, out l, out hr, out hl);\n              if (variance == TypeParameter.TPVariance.Co) {\n                isRoot &= r; isLeaf &= l;\n              } else {\n                isRoot &= l; isLeaf &= r;\n              }\n            }\n          }\n        } else if (t.IsTypeParameter) {\n          var tp = udt.AsTypeParameter;\n          Contract.Assert(tp != null);\n          isRoot = true; isLeaf = true;  // all type parameters are invariant\n          headIsRoot = true; headIsLeaf = true;\n        } else {\n          isRoot = false; isLeaf = false;  // don't know\n          headIsRoot = false; headIsLeaf = false;\n        }\n      } else if (t is MapType) {  // map, imap\n        Contract.Assert(t.TypeArgs.Count == 2);\n        bool r0, l0, r1, l1, hr, hl;\n        CheckEnds(t.TypeArgs[0], out r0, out l0, out hr, out hl);\n        CheckEnds(t.TypeArgs[1], out r1, out l1, out hr, out hl);\n        isRoot = r0 & r1; isLeaf = r0 & r1;  // map types are covariant in both type arguments\n        headIsRoot = true; headIsLeaf = true;\n      } else if (t is CollectionType) {  // set, iset, multiset, seq\n        Contract.Assert(t.TypeArgs.Count == 1);\n        bool hr, hl;\n        CheckEnds(t.TypeArgs[0], out isRoot, out isLeaf, out hr, out hl);  // type is covariant is type argument\n        headIsRoot = true; headIsLeaf = true;\n      } else {\n        isRoot = false; isLeaf = false;  // don't know\n        headIsRoot = false; headIsLeaf = false;\n      }\n    }\n\n    int _recursionDepth = 0;\n    private bool AssignProxyAndHandleItsConstraints(TypeProxy proxy, Type t, bool keepConstraints = false) {\n      Contract.Requires(proxy != null);\n      Contract.Requires(proxy.T == null);\n      Contract.Requires(t != null);\n      Contract.Requires(!(t is TypeProxy));\n      Contract.Requires(!(t is ArtificialType));\n      if (_recursionDepth == 20) {\n        Contract.Assume(false);  // possible infinite recursion\n      }\n      _recursionDepth++;\n      var b = AssignProxyAndHandleItsConstraints_aux(proxy, t, keepConstraints);\n      _recursionDepth--;\n      return b;\n    }\n    /// <summary>\n    /// This method is called if \"proxy\" is an unassigned proxy and \"t\" is a type whose head symbol is known.\n    /// It always sets \"proxy.T\" to \"t\".\n    /// Then, it deals with the constraints of \"proxy\" as follows:\n    /// * If the constraint compares \"t\" with a non-proxy with a head comparable with that of \"t\",\n    ///   then add constraints that the type arguments satisfy the desired subtyping constraint\n    /// * If the constraint compares \"t\" with a non-proxy with a head not comparable with that of \"t\",\n    ///   then report an error\n    /// * If the constraint compares \"t\" with a proxy, then (depending on the constraint and \"t\") attempt\n    ///   to recursively set it\n    /// After this process, the proxy's .Supertypes and .Subtypes lists of constraints are no longer needed.\n    /// If anything is found to be infeasible, \"false\" is returned (and the propagation may be interrupted);\n    /// otherwise, \"true\" is returned.\n    /// </summary>\n    private bool AssignProxyAndHandleItsConstraints_aux(TypeProxy proxy, Type t, bool keepConstraints = false) {\n      Contract.Requires(proxy != null);\n      Contract.Requires(proxy.T == null);\n      Contract.Requires(t != null);\n      Contract.Requires(!(t is TypeProxy));\n      Contract.Requires(!(t is ArtificialType));\n\n      t = keepConstraints ? t.NormalizeExpandKeepConstraints() : t.NormalizeExpand();\n      // never violate the type constraint of a literal expression\n      var followedRequestedAssignment = true;\n      foreach (var su in proxy.Supertypes) {\n        if (su is IntVarietiesSupertype) {\n          var fam = TypeProxy.GetFamily(t);\n          if (fam == TypeProxy.Family.IntLike || fam == TypeProxy.Family.BitVector || fam == TypeProxy.Family.Ordinal) {\n            // good, let's continue with the request to equate the proxy with t\n            // unless...\n            if (t != t.NormalizeExpand()) {\n              // force the type to be a base type\n              if (ArmadaOptions.O.TypeInferenceDebug) {\n                Console.WriteLine(\"DEBUG: hijacking {0}.T := {1} to instead assign {2}\", proxy, t, t.NormalizeExpand());\n              }\n              t = t.NormalizeExpand();\n              followedRequestedAssignment = false;\n            }\n          } else {\n            // hijack the setting of proxy; to do that, we decide on a particular int variety now\n            if (ArmadaOptions.O.TypeInferenceDebug) {\n              Console.WriteLine(\"DEBUG: hijacking {0}.T := {1} to instead assign {2}\", proxy, t, Type.Int);\n            }\n            t = Type.Int;\n            followedRequestedAssignment = false;\n          }\n          break;\n        } else if (su is RealVarietiesSupertype) {\n          if (TypeProxy.GetFamily(t) == TypeProxy.Family.RealLike) {\n            // good, let's continue with the request to equate the proxy with t\n            // unless...\n            if (t != t.NormalizeExpand()) {\n              // force the type to be a base type\n              if (ArmadaOptions.O.TypeInferenceDebug) {\n                Console.WriteLine(\"DEBUG: hijacking {0}.T := {1} to instead assign {2}\", proxy, t, t.NormalizeExpand());\n              }\n              t = t.NormalizeExpand();\n              followedRequestedAssignment = false;\n            }\n          } else {\n            // hijack the setting of proxy; to do that, we decide on a particular real variety now\n            if (ArmadaOptions.O.TypeInferenceDebug) {\n              Console.WriteLine(\"DEBUG: hijacking {0}.T := {1} to instead assign {2}\", proxy, t, Type.Real);\n            }\n            t = Type.Real;\n            followedRequestedAssignment = false;\n          }\n          break;\n        }\n      }\n      // set proxy.T right away, so that we can freely recurse without having to worry about infinite recursion\n      if (ArmadaOptions.O.TypeInferenceDebug) {\n        Console.WriteLine(\"DEBUG: setting proxy {0}.T := {1}\", proxy, t, Type.Real);\n      }\n      proxy.T = t;\n\n      // check feasibility\n      bool isRoot, isLeaf, headRoot, headLeaf;\n      CheckEnds(t, out isRoot, out isLeaf, out headRoot, out headLeaf);\n      // propagate up\n      foreach (var c in proxy.SupertypeConstraints) {\n        var u = keepConstraints ? c.Super.NormalizeExpandKeepConstraints() : c.Super.NormalizeExpand();\n        if (!(u is TypeProxy)) {\n          ImposeSubtypingConstraint(u, t, c.errorMsg);\n        } else if (isRoot) {\n          // If t is a root, we might as well constrain u now.  Otherwise, we'll wait until the .Subtype constraint of u is dealt with.\n          AssignProxyAndHandleItsConstraints((TypeProxy)u, t, keepConstraints);\n        }\n      }\n      // propagate down\n      foreach (var c in proxy.SubtypeConstraints) {\n        var u = keepConstraints ? c.Sub.NormalizeExpandKeepConstraints() : c.Sub.NormalizeExpand();\n        Contract.Assert(!TypeProxy.IsSupertypeOfLiteral(u));  // these should only appear among .Supertypes\n        if (!(u is TypeProxy)) {\n          ImposeSubtypingConstraint(t, u, c.errorMsg);\n        } else if (isLeaf) {\n          // If t is a leaf (no pun intended), we might as well constrain u now.  Otherwise, we'll wait until the .Supertype constraint of u is dealt with.\n          AssignProxyAndHandleItsConstraints((TypeProxy)u, t, keepConstraints);\n        }\n      }\n\n      return followedRequestedAssignment;\n    }\n\n    /// <summary>\n    /// Impose constraints that \"sub\" is a subtype of \"super\", returning \"false\" if this leads to an overconstrained situation.\n    /// In most cases, \"sub\" being a subtype of \"super\" means that \"sub\" and \"super\" have the same head symbol and, therefore, the\n    /// same number of type arguments. Depending on the polarities of the type parameters, the corresponding arguments\n    /// of \"sub\" and \"super\" must be in co-, in-, or contra-variant relationships to each other.\n    /// There are two ways \"sub\" can be a subtype of \"super\" without the two having the same head symbol.\n    /// One way is that \"sub\" is a subset type. In this case, the method starts by moving \"sub\" up toward \"super\".\n    /// The other way is that \"super\" is a trait (possibly\n    /// the trait \"object\").  By a current restriction in Dafny's type system, traits have no type parameters, so in this case, it\n    /// suffices to check that the head symbol of \"super\" is something that derives from \"sub\".\n    /// </summary>\n    private bool ImposeSubtypingConstraint(Type super, Type sub, TypeConstraint.ErrorMsg errorMsg) {\n      Contract.Requires(super != null && !(super is TypeProxy));\n      Contract.Requires(sub != null && !(sub is TypeProxy));\n      Contract.Requires(errorMsg != null);\n      List<int> polarities = ConstrainTypeHead_ModuloSubsetTypeParents(super, ref sub);\n      if (polarities == null) {\n        errorMsg.FlagAsError();\n        return false;\n      }\n      bool keepConstraints = KeepConstraints(super, sub);\n      var p = polarities.Count;\n      Contract.Assert(p == super.TypeArgs.Count);  // postcondition of ConstrainTypeHead\n      Contract.Assert(p == 0 || sub.TypeArgs.Count == super.TypeArgs.Count);  // postcondition of ConstrainTypeHead\n      for (int i = 0; i < p; i++) {\n        var pol = polarities[i];\n        var tp = p == 1 ? \"\" : \" \" + i;\n        var errMsg = new TypeConstraint.ErrorMsgWithBase(errorMsg,\n          pol < 0 ? \"contravariant type parameter{0} would require {1} <: {2}\" :\n          pol > 0 ? \"covariant type parameter{0} would require {2} <: {1}\" :\n          \"invariant type parameter{0} would require {1} = {2}\",\n          tp, super.TypeArgs[i], sub.TypeArgs[i]);\n        if (pol >= 0) {\n          if (!ConstrainSubtypeRelation(super.TypeArgs[i], sub.TypeArgs[i], errMsg, keepConstraints)) {\n            return false;\n          }\n        }\n        if (pol <= 0) {\n          if (!ConstrainSubtypeRelation(sub.TypeArgs[i], super.TypeArgs[i], errMsg, keepConstraints)) {\n            return false;\n          }\n        }\n      }\n      return true;\n    }\n\n    /// <summary>\n    /// This is a more liberal version of \"ConstrainTypeHead\" below. It is willing to move \"sub\"\n    /// upward toward its subset-type parents until it finds a head that matches \"super\", if any.\n    /// </summary>\n    private List<int> ConstrainTypeHead_ModuloSubsetTypeParents(Type super, ref Type sub) {\n      Contract.Requires(super != null);\n      Contract.Requires(sub != null);\n\n      // Before we do anything else, make a note of whether or not both \"a\" and \"b\" are non-null types.\n      var abNonNullTypes = super.IsNonNullRefType && sub.IsNonNullRefType;\n\n      super = super.NormalizeExpandKeepConstraints();\n      var X = sub.NormalizeExpandKeepConstraints();\n      UserDefinedType prevX = null;\n      while (true) {\n        var polarities = ConstrainTypeHead(super, X);\n        if (polarities != null) {\n          sub = X;\n          return polarities;\n        }\n        var udt = X as UserDefinedType;\n        if (udt != null && udt.ResolvedClass is SubsetTypeDecl) {\n          var sst = (SubsetTypeDecl)udt.ResolvedClass;\n          prevX = udt;\n          X = sst.RhsWithArgument(udt.TypeArgs).NormalizeExpandKeepConstraints();\n        } else {\n          // There is one more thing to check.  If we started with two non-null types, then we\n          // have just moved X down from \"sub\" to the base-most type and prevX is the non-null\n          // version of X.  If \"super\" is exactly a non-null type, then the head of \"sub\" is a\n          // subtype of the head of \"super\" if the head of \"sub.parent\" is a subtype of the head\n          // of \"super.parent\".  And since the type parameters of a possibly null type are the\n          // same as those for the corresponding non-null type, we can just answer our question\n          // by asking it for prevX and super.parent.\n          if (abNonNullTypes) {\n            Contract.Assert(prevX != null && prevX.ResolvedClass is NonNullTypeDecl);\n            var udtSuper = super as UserDefinedType;\n            if (udtSuper != null && udtSuper.ResolvedClass is NonNullTypeDecl) {\n              var nnt = (NonNullTypeDecl)udtSuper.ResolvedClass;\n              super = nnt.RhsWithArgument(udtSuper.TypeArgs);\n              polarities = ConstrainTypeHead(super, X);\n              if (polarities != null) {\n                sub = prevX;\n                return polarities;\n              }\n            }\n          }\n          return null;\n        }\n      }\n    }\n\n    /// <summary>\n    /// Determines if the head of \"sub\" can be a subtype of \"super\".\n    /// If this is not possible, null is returned.\n    /// If it is possible, return a list of polarities, one for each type argument of \"sub\".  Polarities\n    /// indicate:\n    ///     +1  co-variant\n    ///      0  invariant\n    ///     -1  contra-variant\n    /// \"sub\" is of some type that can (in general) have type parameters.\n    /// See also note about Dafny's current type system in the description of method \"ImposeSubtypingConstraint\".\n    /// </summary>\n    private List<int> ConstrainTypeHead(Type super, Type sub) {\n      Contract.Requires(super != null && !(super is TypeProxy));\n      Contract.Requires(sub != null && !(sub is TypeProxy));\n      if (super is IntVarietiesSupertype) {\n        var famSub = TypeProxy.GetFamily(sub);\n        if (famSub == TypeProxy.Family.IntLike || famSub == TypeProxy.Family.BitVector || famSub == TypeProxy.Family.Ordinal || super.Equals(sub)) {\n          return new List<int>();\n        } else {\n          return null;\n        }\n      } else if (super is RealVarietiesSupertype) {\n        if (TypeProxy.GetFamily(sub) == TypeProxy.Family.RealLike || super.Equals(sub)) {\n          return new List<int>();\n        } else {\n          return null;\n        }\n      }\n      switch (TypeProxy.GetFamily(super)) {\n        case TypeProxy.Family.Bool:\n        case TypeProxy.Family.Char:\n        case TypeProxy.Family.IntLike:\n        case TypeProxy.Family.RealLike:\n        case TypeProxy.Family.Ordinal:\n        case TypeProxy.Family.BitVector:\n          if (super.Equals(sub)) {\n            return new List<int>();\n          } else {\n            return null;\n          }\n        case TypeProxy.Family.ValueType:\n        case TypeProxy.Family.Ref:\n        case TypeProxy.Family.Opaque:\n          break;  // more elaborate work below\n        case TypeProxy.Family.Unknown:\n        default:  // just in case the family is mentioned explicitly as one of the cases\n          Contract.Assert(false);  // unexpected type (the precondition of ConstrainTypeHead says \"no proxies\")\n          return null;  // please compiler\n      }\n      if (super is SetType) {\n        var tt = (SetType)super;\n        var uu = sub as SetType;\n        return uu != null && tt.Finite == uu.Finite ? new List<int> { 1 } : null;\n      } else if (super is SeqType) {\n        return sub is SeqType ? new List<int> { 1 } : null;\n      } else if (super is SizedArrayType) {\n        return sub is SizedArrayType ? new List<int> { 0 } : null;\n      } else if (super is PointerType) {\n        return sub is PointerType ? new List<int> { 0 } : null;\n      } else if (super is MultiSetType) {\n        return sub is MultiSetType ? new List<int> { 1 } : null;\n      } else if (super is MapType) {\n        var tt = (MapType)super;\n        var uu = sub as MapType;\n        return uu != null && tt.Finite == uu.Finite ? new List<int> { 1, 1 } : null;\n      } else if (super.IsObjectQ) {\n        return sub.IsRefType ? new List<int>() : null;\n      } else {\n        // The only remaining cases are that \"super\" is a (co)datatype, opaque type, or non-object trait/class.\n        // In each of these cases, \"super\" is a UserDefinedType.\n        var udfSuper = (UserDefinedType)super;\n        var clSuper = udfSuper.ResolvedClass;\n        if (clSuper == null) {\n          Contract.Assert(super.TypeArgs.Count == 0);\n          if (super.IsTypeParameter) {\n            // we're looking at a type parameter\n            return super.AsTypeParameter == sub.AsTypeParameter ? new List<int>() : null;\n          } else {\n            Contract.Assert(super.IsInternalTypeSynonym);\n            return super.AsInternalTypeSynonym == sub.AsInternalTypeSynonym ? new List<int>() : null;\n          }\n        }\n        var udfSub = sub as UserDefinedType;\n        var clSub = udfSub == null ? null : udfSub.ResolvedClass;\n        if (clSub == null) {\n          return null;\n        } else if (clSuper == clSub) {\n          // good\n          var polarities = new List<int>();\n          Contract.Assert(clSuper.TypeArgs.Count == udfSuper.TypeArgs.Count);\n          Contract.Assert(clSuper.TypeArgs.Count == udfSub.TypeArgs.Count);\n          foreach (var tp in clSuper.TypeArgs) {\n            var polarity =\n              tp.Variance == TypeParameter.TPVariance.Co ? 1 :\n              tp.Variance == TypeParameter.TPVariance.Contra ? -1 : 0;\n            polarities.Add(polarity);\n          }\n          return polarities;\n        } else if (clSub is ClassDecl && ((ClassDecl)clSub).DerivesFrom(clSuper)) {\n          // cool\n          Contract.Assert(clSuper.TypeArgs.Count == 0);  // traits are currently not allowed to have any type parameters\n          return new List<int>();\n        } else {\n          return null;\n        }\n      }\n    }\n    private bool KeepConstraints(Type super, Type sub) {\n      Contract.Requires(super != null && !(super is TypeProxy));\n      Contract.Requires(sub != null && !(sub is TypeProxy));\n      if (super is IntVarietiesSupertype) {\n        return false;\n      } else if (super is RealVarietiesSupertype) {\n        return false;\n      }\n      switch (TypeProxy.GetFamily(super)) {\n        case TypeProxy.Family.Bool:\n        case TypeProxy.Family.Char:\n        case TypeProxy.Family.IntLike:\n        case TypeProxy.Family.RealLike:\n        case TypeProxy.Family.Ordinal:\n        case TypeProxy.Family.BitVector:\n          return false;\n        case TypeProxy.Family.ValueType:\n        case TypeProxy.Family.Ref:\n        case TypeProxy.Family.Opaque:\n          break;  // more elaborate work below\n        case TypeProxy.Family.Unknown:\n          return false;\n      }\n      if (super is SetType || super is SeqType || super is MultiSetType || super is MapType) {\n        return true;\n      } else if (super is ArrowType) {\n        return false;\n      } else if (super.IsObjectQ) {\n        return false;\n      } else {\n        // super is UserDefinedType\n        return true;\n      }\n    }\n\n    public List<TypeConstraint> AllTypeConstraints = new List<TypeConstraint>();\n    public List<XConstraint> AllXConstraints = new List<XConstraint>();\n\n    public class XConstraint\n    {\n      public readonly IToken tok;\n      public readonly string ConstraintName;\n      public readonly Type[] Types;\n      public readonly TypeConstraint.ErrorMsg errorMsg;\n      public XConstraint(IToken tok, string constraintName, Type[] types, TypeConstraint.ErrorMsg errMsg) {\n        Contract.Requires(tok != null);\n        Contract.Requires(constraintName != null);\n        Contract.Requires(types != null);\n        Contract.Requires(errMsg != null);\n        this.tok = tok;\n        ConstraintName = constraintName;\n        Types = types;\n        errorMsg = errMsg;\n      }\n\n      public override string ToString() {\n        var s = ConstraintName + \":\";\n        foreach (var t in Types) {\n          s += \" \" + t;\n        }\n        return s;\n      }\n\n      /// <summary>\n      /// Tries to confirm the XConstraint.\n      /// If the XConstraint can be confirmed, or at least is plausible enough to have been converted into other type\n      /// constraints or more XConstraints, then \"true\" is returned and the out-parameters \"convertedIntoOtherTypeConstraints\"\n      /// and \"moreXConstraints\" are set to true accordingly.\n      /// If the XConstraint can be refuted, then an error message will be produced and \"true\" is returned (to indicate\n      /// that this XConstraint has finished serving its purpose).\n      /// If there's not enough information to confirm or refute the XConstraint, then \"false\" is returned.\n      /// </summary>\n      public bool Confirm(Resolver resolver, bool fullstrength, out bool convertedIntoOtherTypeConstraints, out bool moreXConstraints) {\n        Contract.Requires(resolver != null);\n        convertedIntoOtherTypeConstraints = false;\n        moreXConstraints = false;\n        var t = Types[0].NormalizeExpand();\n        if (t is TypeProxy) {\n          switch (ConstraintName) {\n            case \"Assignable\":\n            case \"Equatable\":\n            case \"EquatableArg\":\n            case \"Indexable\":\n            case \"Innable\":\n            case \"MultiIndexable\":\n            case \"IntOrORDINAL\":\n              // have a go downstairs\n              break;\n            default:\n              return false;  // there's not enough information to confirm or refute this XConstraint\n          }\n        }\n        bool satisfied;\n        Type tUp, uUp;\n        switch (ConstraintName) {\n          case \"Assignable\": {\n              Contract.Assert(t == t.Normalize());  // it's already been normalized above\n              var u = Types[1].NormalizeExpandKeepConstraints();\n              if (CheckTypeInference_Visitor.IsDetermined(t) &&\n                (fullstrength\n                || !ProxyWithNoSubTypeConstraint(u, resolver)\n                || (Types[0].NormalizeExpandKeepConstraints().IsNonNullRefType && u is TypeProxy && resolver.HasApplicableNullableRefTypeConstraint(new HashSet<TypeProxy>() { (TypeProxy)u })))) {\n                // This is the best case.  We convert Assignable(t, u) to the subtype constraint base(t) :> u.\n                resolver.ConstrainAssignable((NonProxyType)t, u, errorMsg, out moreXConstraints, fullstrength);\n                convertedIntoOtherTypeConstraints = true;\n                return true;\n              } else if (u.IsTypeParameter) {\n                // we need the constraint base(t) :> u, which for a type parameter t can happen iff t :> u\n                resolver.ConstrainSubtypeRelation(t, u, errorMsg);\n                convertedIntoOtherTypeConstraints = true;\n                return true;\n              } else if (Type.FromSameHead(t, u, out tUp, out uUp)) {\n                resolver.ConstrainAssignableTypeArgs(tUp, tUp.TypeArgs, uUp.TypeArgs, errorMsg, out moreXConstraints);\n                return true;\n              } else if (fullstrength && t is NonProxyType) {\n                // We convert Assignable(t, u) to the subtype constraint base(t) :> u.\n                resolver.ConstrainAssignable((NonProxyType)t, u, errorMsg, out moreXConstraints, fullstrength);\n                convertedIntoOtherTypeConstraints = true;\n                return true;\n              } else if (fullstrength && u is NonProxyType) {\n                // We're willing to change \"base(t) :> u\" to the stronger constraint \"t :> u\" for the sake of making progress.\n                resolver.ConstrainSubtypeRelation(t, u, errorMsg);\n                convertedIntoOtherTypeConstraints = true;\n                return true;\n              }\n              // There's not enough information to say anything\n              return false;\n            }\n          case \"NumericType\":\n            satisfied = t.IsNumericBased();\n            break;\n          case \"IntegerType\":\n            satisfied = t.IsNumericBased(Type.NumericPersuation.Int);\n            break;\n          case \"IsBitvector\":\n            satisfied = t.IsBitVectorType;\n            break;\n          case \"IsRefType\":\n            satisfied = t.IsRefType;\n            break;\n          case \"IsNullableRefType\":\n            satisfied = (t.IsRefType && !t.IsNonNullRefType) || t is PointerType;\n            break;\n          case \"Orderable_Lt\":\n            satisfied = t.IsNumericBased() || t.IsBitVectorType || t.IsBigOrdinalType || t.IsCharType || t is SeqType || t is SetType || t is MultiSetType;\n            break;\n          case \"Orderable_Gt\":\n            satisfied = t.IsNumericBased() || t.IsBitVectorType || t.IsBigOrdinalType || t.IsCharType || t is SetType || t is MultiSetType;\n            break;\n          case \"RankOrderable\": {\n              var u = Types[1].NormalizeExpand();\n              if (u is TypeProxy) {\n                return false;  // not enough information\n              }\n              satisfied = (t.IsIndDatatype || t.IsTypeParameter) && u.IsIndDatatype;\n              break;\n            }\n          case \"Plussable\":\n            satisfied = t.IsNumericBased() || t.IsBitVectorType || t.IsBigOrdinalType || t.IsCharType || t is SeqType || t is SetType || t is MultiSetType || t is PointerType;\n            break;\n          case \"PlusRight\": {\n            var xcWithExprs = (XConstraintWithExprs)this;\n            var e = xcWithExprs.Exprs[0];\n            if (t is PointerType) {\n              resolver.ConstrainToIntegerType(e, \"pointer arithmetic requires integral right-hand operand (got {0})\");\n              moreXConstraints = true;\n              return true;\n            } else {\n              resolver.ConstrainSubtypeRelation(t, e.Type, e.tok, \"type of right argument to + ({0}) must agree with the result type ({1})\", e.Type, t);\n              convertedIntoOtherTypeConstraints = true;\n              return true;\n            }\n          }\n          case \"Minusable\":\n            satisfied = t.IsNumericBased() || t.IsBitVectorType || t.IsBigOrdinalType || t.IsCharType || t is SetType || t is MultiSetType || t is PointerType;\n            break;\n          case \"MinusRight\": {\n            var xcWithExprs = (XConstraintWithExprs)this;\n            var e = xcWithExprs.Exprs[0];\n            if (t is PointerType) {\n              resolver.ConstrainToIntegerType(e, \"pointer arithmetic requires integral right-hand operand (got {0})\");\n              moreXConstraints = true;\n              return true;\n            } else {\n              resolver.ConstrainSubtypeRelation(t, e.Type, e.tok, \"type of right argument to - ({0}) must agree with the result type ({1})\", e.Type, t);\n              convertedIntoOtherTypeConstraints = true;\n              return true;\n            }\n          }\n          case \"Mullable\":\n            satisfied = t.IsNumericBased() || t.IsBitVectorType || t is SetType || t is MultiSetType;\n            break;\n          case \"Dereferenceable\":\n            satisfied = t is PointerType;\n            break;\n          case \"DereferenceResult\":\n            if (t is PointerType) {\n              resolver.ConstrainSubtypeRelation_Equal(Types[1], ((PointerType)t).Arg, errorMsg);\n              convertedIntoOtherTypeConstraints = true;\n            }\n            return true;\n          case \"IntOrORDINAL\":\n            if (!(t is TypeProxy)) {\n              if (TernaryExpr.PrefixEqUsesNat) {\n                satisfied = t.IsNumericBased(Type.NumericPersuation.Int);\n              } else {\n                satisfied = t.IsNumericBased(Type.NumericPersuation.Int) || t.IsBigOrdinalType;\n              }\n            } else if (fullstrength) {\n              var proxy = (TypeProxy)t;\n              if (TernaryExpr.PrefixEqUsesNat) {\n                resolver.AssignProxyAndHandleItsConstraints(proxy, Type.Int);\n              } else {\n                // let's choose ORDINAL over int\n                resolver.AssignProxyAndHandleItsConstraints(proxy, Type.BigOrdinal);\n              }\n              convertedIntoOtherTypeConstraints = true;\n              satisfied = true;\n            } else {\n              return false;\n            }\n            break;\n          case \"NumericOrBitvector\":\n            satisfied = t.IsNumericBased() || t.IsBitVectorType;\n            break;\n          case \"NumericOrBitvectorOrCharOrORDINAL\":\n            satisfied = t.IsNumericBased() || t.IsBitVectorType || t.IsCharType || t.IsBigOrdinalType;\n            break;\n          case \"IntLikeOrBitvector\":\n            satisfied = t.IsNumericBased(Type.NumericPersuation.Int) || t.IsBitVectorType;\n            break;\n          case \"BooleanBits\":\n            satisfied = t.IsBoolType || t.IsBitVectorType;\n            break;\n          case \"Sizeable\":\n            satisfied = (t is SetType && ((SetType)t).Finite) || t is MultiSetType || t is SeqType || (t is MapType && ((MapType)t).Finite) || (t is SizedArrayType);\n            break;\n          case \"Disjointable\":\n            satisfied = t is SetType || t is MultiSetType || t is MapType;\n            break;\n          case \"MultiSetConvertible\":\n            satisfied = (t is SetType && ((SetType)t).Finite) || t is SeqType;\n            if (satisfied) {\n              Type elementType = ((CollectionType)t).Arg;\n              var u = Types[1];  // note, it's okay if \"u\" is a TypeProxy\n              var em = new TypeConstraint.ErrorMsgWithBase(errorMsg, \"expecting element type {0} (got {1})\", u, elementType);\n              resolver.ConstrainSubtypeRelation_Equal(elementType, u, em);\n              convertedIntoOtherTypeConstraints = true;\n            }\n            break;\n          case \"IsCoDatatype\":\n            satisfied = t.IsCoDatatype;\n            break;\n          case \"Indexable\":\n            if (!(t is TypeProxy)) {\n              satisfied = t is SeqType || t is MultiSetType || t is MapType || (t.IsArrayType && t.AsArrayType.Dims == 1) || t is SizedArrayType;\n            } else {\n              // t is a proxy, but perhaps it stands for something between \"object\" and \"array<?>\".  If so, we can add a constraint\n              // that it does have the form \"array<?>\", since \"object\" would not be Indexable.\n              var proxy = (TypeProxy)t;\n              Type meet = null;\n              if (resolver.MeetOfAllSubtypes(proxy, ref meet, new HashSet<TypeProxy>()) && meet != null) {\n                var tt = Type.HeadWithProxyArgs(meet);\n                satisfied = tt is SeqType || tt is MultiSetType || tt is MapType || (tt.IsArrayType && tt.AsArrayType.Dims == 1);\n                if (satisfied) {\n                  resolver.AssignProxyAndHandleItsConstraints(proxy, tt);\n                  convertedIntoOtherTypeConstraints = true;\n                }\n              } else {\n                return false;  // we can't determine the answer\n              }\n            }\n            break;\n          case \"MultiIndexable\":\n            if (!(t is TypeProxy)) {\n              satisfied = t is SeqType || (t.IsArrayType && t.AsArrayType.Dims == 1) || t is SizedArrayType;\n            } else {\n              // t is a proxy, but perhaps it stands for something between \"object\" and \"array<?>\".  If so, we can add a constraint\n              // that it does have the form \"array<?>\", since \"object\" would not be Indexable.\n              var proxy = (TypeProxy)t;\n              Type meet = null;\n              if (resolver.MeetOfAllSubtypes(proxy, ref meet, new HashSet<TypeProxy>()) && meet != null) {\n                var tt = Type.HeadWithProxyArgs(meet);\n                satisfied = tt is SeqType || (tt.IsArrayType && tt.AsArrayType.Dims == 1) || tt is SizedArrayType;\n                if (satisfied) {\n                  resolver.AssignProxyAndHandleItsConstraints(proxy, tt);\n                  convertedIntoOtherTypeConstraints = true;\n                }\n              } else {\n                return false;  // we can't determine the answer\n              }\n            }\n            break;\n          case \"Innable\": {\n              var elementType = FindCollectionType(t, true, new HashSet<TypeProxy>()) ?? FindCollectionType(t, false, new HashSet<TypeProxy>());\n              if (elementType != null) {\n                var u = Types[1];  // note, it's okay if \"u\" is a TypeProxy\n                resolver.AddXConstraint(this.tok, \"Equatable\", elementType, u, new TypeConstraint.ErrorMsgWithBase(errorMsg, \"expecting element type to be assignable to {1} (got {0})\", u, elementType));\n                moreXConstraints = true;\n                return true;\n              }\n              if (t is TypeProxy) {\n                return false;  // not enough information to do anything\n              }\n              satisfied = false;\n              break;\n            }\n          case \"SeqUpdatable\": {\n              var xcWithExprs = (XConstraintWithExprs)this;\n              var index = xcWithExprs.Exprs[0];\n              var value = xcWithExprs.Exprs[1];\n              if (t is SeqType) {\n                var s = (SeqType)t;\n                resolver.ConstrainSubtypeRelation(Type.Int, index.Type, index, \"sequence update requires integer index (got {0})\", index.Type);\n                resolver.ConstrainSubtypeRelation(s.Arg, value.Type, value, \"sequence update requires the value to have the element type of the sequence (got {0})\", value.Type);\n              } else if (t is MapType) {\n                var s = (MapType)t;\n                if (s.Finite) {\n                  resolver.ConstrainSubtypeRelation(s.Domain, index.Type, index, \"map update requires domain element to be of type {0} (got {1})\", s.Domain, index.Type);\n                  resolver.ConstrainSubtypeRelation(s.Range, value.Type, value, \"map update requires the value to have the range type {0} (got {1})\", s.Range, value.Type);\n                } else {\n                  resolver.ConstrainSubtypeRelation(s.Domain, index.Type, index, \"imap update requires domain element to be of type {0} (got {1})\", s.Domain, index.Type);\n                  resolver.ConstrainSubtypeRelation(s.Range, value.Type, value, \"imap update requires the value to have the range type {0} (got {1})\", s.Range, value.Type);\n                }\n              } else if (t is MultiSetType) {\n                var s = (MultiSetType)t;\n                resolver.ConstrainSubtypeRelation(s.Arg, index.Type, index, \"multiset update requires domain element to be of type {0} (got {1})\", s.Arg, index.Type);\n                resolver.ConstrainToIntegerType(value, \"multiset update requires integer-based numeric value (got {0})\");\n              } else {\n                satisfied = false;\n                break;\n              }\n              convertedIntoOtherTypeConstraints = true;\n              return true;\n            }\n          case \"ContainerIndex\":\n            // The semantics of this XConstraint is that *if* the head is seq/array/map/multiset, then its element/domain type must a supertype of \"u\"\n            Type indexType;\n            if (t is SeqType) {\n              indexType = resolver.NewIntegerBasedProxy(tok);\n            } else if (t.IsArrayType) {\n              indexType = resolver.NewIntegerBasedProxy(tok);\n            } else if (t is MapType) {\n              indexType = ((MapType)t).Domain;\n            } else if (t is MultiSetType) {\n              indexType = ((MultiSetType)t).Arg;\n            } else if (t is SizedArrayType) {\n              indexType = resolver.NewIntegerBasedProxy(tok);\n            } else {\n              // some other head symbol; that's cool\n              return true;\n            }\n            // note, it's okay if \"Types[1]\" is a TypeProxy\n            resolver.ConstrainSubtypeRelation(indexType, Types[1], errorMsg);  // use the same error message\n            convertedIntoOtherTypeConstraints = true;\n            return true;\n          case \"ContainerResult\":\n            // The semantics of this XConstraint is that *if* the head is seq/array/map/multiset, then the type of a selection must a subtype of \"u\"\n            Type resultType;\n            if (t is SeqType) {\n              resultType = ((SeqType)t).Arg;\n            } else if (t.IsArrayType) {\n              resultType = UserDefinedType.ArrayElementType(t);\n            } else if (t is MapType) {\n              resultType = ((MapType)t).Range;\n            } else if (t is MultiSetType) {\n              resultType = resolver.builtIns.Nat();\n            } else if (t is SizedArrayType) {\n              resultType = ((SizedArrayType)t).Arg;\n            } else {\n              // some other head symbol; that's cool\n              return true;\n            }\n            // note, it's okay if \"Types[1]\" is a TypeProxy\n            resolver.ConstrainSubtypeRelation(Types[1], resultType, errorMsg);\n            convertedIntoOtherTypeConstraints = true;\n            return true;\n          case \"Equatable\": {\n              t = Types[0].NormalizeExpandKeepConstraints();\n              var u = Types[1].NormalizeExpandKeepConstraints();\n              if (object.ReferenceEquals(t, u)) {\n                return true;\n              }\n              if (t is TypeProxy && u is TypeProxy) {\n                return false;  // not enough information to do anything sensible\n              } else if (t is TypeProxy || u is TypeProxy) {\n                TypeProxy proxy;\n                Type other;\n                if (t is TypeProxy) {\n                  proxy = (TypeProxy)t;\n                  other = u;\n                } else {\n                  proxy = (TypeProxy)u;\n                  other = t;\n                }\n                if (other.IsNumericBased() || other.IsBitVectorType || other.IsBigOrdinalType) {\n                  resolver.ConstrainSubtypeRelation(other.NormalizeExpand(), proxy, errorMsg, true);\n                  convertedIntoOtherTypeConstraints = true;\n                  return true;\n                } else if (fullstrength) {\n                  // the following is rather aggressive\n                  if (Resolver.TypeConstraintsIncludeProxy(other, proxy)) {\n                    return false;\n                  } else {\n                    if (other.IsRefType && resolver.HasApplicableNullableRefTypeConstraint_SubDirection(proxy)) {\n                      other = other.NormalizeExpand();  // shave off all constraints\n                    }\n                    satisfied = resolver.AssignProxyAndHandleItsConstraints(proxy, other, true);\n                    convertedIntoOtherTypeConstraints = true;\n                    break;\n                  }\n                } else {\n                  return false;  // not enough information\n                }\n              }\n              Type a,b;\n              satisfied = Type.FromSameHead_Subtype(t, u, resolver.builtIns, out a, out b);\n              if (satisfied) {\n                Contract.Assert(a.TypeArgs.Count == b.TypeArgs.Count);\n                var cl = a is UserDefinedType ? ((UserDefinedType)a).ResolvedClass : null;\n                for (int i = 0; i < a.TypeArgs.Count; i++) {\n                  resolver.AllXConstraints.Add(new XConstraint_EquatableArg(tok,\n                    a.TypeArgs[i], b.TypeArgs[i],\n                    a is CollectionType || (cl != null && cl.TypeArgs[i].Variance != TypeParameter.TPVariance.Non),\n                    a.IsRefType,\n                    errorMsg));\n                  moreXConstraints = true;\n                }\n              }\n              break;\n            }\n          case \"EquatableArg\": {\n              t = Types[0].NormalizeExpandKeepConstraints();\n              var u = Types[1].NormalizeExpandKeepConstraints();\n              var moreExactThis = (XConstraint_EquatableArg)this;\n              if (t is TypeProxy && u is TypeProxy) {\n                return false;  // not enough information to do anything sensible\n              } else if (t is TypeProxy || u is TypeProxy) {\n                TypeProxy proxy;\n                Type other;\n                if (t is TypeProxy) {\n                  proxy = (TypeProxy)t;\n                  other = u;\n                } else {\n                  proxy = (TypeProxy)u;\n                  other = t;\n                }\n                if (other.IsNumericBased() || other.IsBitVectorType || other.IsBigOrdinalType) {\n                  resolver.ConstrainSubtypeRelation(other.NormalizeExpand(), proxy, errorMsg, true);\n                  convertedIntoOtherTypeConstraints = true;\n                  return true;\n                } else if (fullstrength) {\n                  // the following is rather aggressive\n                  if (Resolver.TypeConstraintsIncludeProxy(other, proxy)) {\n                    return false;\n                  } else {\n                    if (other.IsRefType && resolver.HasApplicableNullableRefTypeConstraint_SubDirection(proxy)) {\n                      other = other.NormalizeExpand();  // shave off all constraints\n                    }\n                    satisfied = resolver.AssignProxyAndHandleItsConstraints(proxy, other, true);\n                    convertedIntoOtherTypeConstraints = true;\n                    break;\n                  }\n                } else {\n                  return false;  // not enough information\n                }\n              }\n              if (moreExactThis.TreatTypeParamAsWild && (t.IsTypeParameter || u.IsTypeParameter)) {\n                return true;\n              } else if (!moreExactThis.AllowSuperSub) {\n                resolver.ConstrainSubtypeRelation_Equal(t, u, errorMsg);\n                convertedIntoOtherTypeConstraints = true;\n                return true;\n              }\n              Type a, b;\n              // okay if t<:u or u<:t (this makes type inference more manageable, though it is more liberal than one might wish)\n              satisfied = Type.FromSameHead_Subtype(t, u, resolver.builtIns, out a, out b);\n              if (satisfied) {\n                Contract.Assert(a.TypeArgs.Count == b.TypeArgs.Count);\n                var cl = a is UserDefinedType ? ((UserDefinedType)a).ResolvedClass : null;\n                for (int i = 0; i < a.TypeArgs.Count; i++) {\n                  resolver.AllXConstraints.Add(new XConstraint_EquatableArg(tok,\n                    a.TypeArgs[i], b.TypeArgs[i],\n                    a is CollectionType || (cl != null && cl.TypeArgs[i].Variance != TypeParameter.TPVariance.Non),\n                    false,\n                    errorMsg));\n                  moreXConstraints = true;\n                }\n              }\n              break;\n            }\n          case \"Freshable\": {\n              var collType = t.AsCollectionType;\n              if (collType != null) {\n                t = collType.Arg.NormalizeExpand();\n              }\n              if (t is TypeProxy) {\n                return false;  // there is not enough information\n              }\n              satisfied = t.IsRefType;\n              break;\n            }\n          case \"ModifiesFrame\": {\n              var u = Types[1].NormalizeExpand();  // eventual ref type\n              var collType = t is MapType ? null : t.AsCollectionType;\n              if (collType != null) {\n                t = collType.Arg.NormalizeExpand();\n              }\n              if (t is TypeProxy) {\n                if (collType != null) {\n                  // we know enough to convert into a subtyping constraint\n                  resolver.AddXConstraint(Token.NoToken/*bogus, but it seems this token would be used only when integers are involved*/, \"IsRefType\", t, errorMsg);\n                  moreXConstraints = true;\n                  resolver.ConstrainSubtypeRelation_Equal(u, t, errorMsg);\n                  moreXConstraints = true;\n                  convertedIntoOtherTypeConstraints = true;\n                  return true;\n                } else {\n                  return false;  // there is not enough information\n                }\n              }\n              if (t.IsRefType) {\n                resolver.ConstrainSubtypeRelation_Equal(u, t, errorMsg);\n                convertedIntoOtherTypeConstraints = true;\n                return true;\n              }\n              satisfied = false;\n              break;\n            }\n          case \"ReadsFrame\": {\n              var u = Types[1].NormalizeExpand();  // eventual ref type\n              var arrTy = t.AsArrowType;\n              if (arrTy != null) {\n                t = arrTy.Result.NormalizeExpand();\n              }\n              var collType = t is MapType ? null : t.AsCollectionType;\n              if (collType != null) {\n                t = collType.Arg.NormalizeExpand();\n              }\n              if (t is TypeProxy) {\n                if (collType != null) {\n                  // we know enough to convert into a subtyping constraint\n                  resolver.AddXConstraint(Token.NoToken/*bogus, but it seems this token would be used only when integers are involved*/, \"IsRefType\", t, errorMsg);\n                  resolver.ConstrainSubtypeRelation_Equal(u, t, errorMsg);\n                  moreXConstraints = true;\n                  convertedIntoOtherTypeConstraints = true;\n                  return true;\n                } else {\n                  return false;  // there is not enough information\n                }\n              }\n              if (t.IsRefType) {\n                resolver.ConstrainSubtypeRelation_Equal(u, t, errorMsg);\n                convertedIntoOtherTypeConstraints = true;\n                return true;\n              }\n              satisfied = false;\n              break;\n            }\n          default:\n            Contract.Assume(false);  // unknown XConstraint\n            return false;  // to please the compiler\n        }\n        if (!satisfied) {\n          errorMsg.FlagAsError();\n        }\n        return true;  // the XConstraint has served its purpose\n      }\n\n      public bool ProxyWithNoSubTypeConstraint(Type u, Resolver resolver) {\n        Contract.Requires(u != null);\n        Contract.Requires(resolver != null);\n        var proxy = u as TypeProxy;\n        if (proxy != null) {\n          if (proxy.SubtypeConstraints.Any()) {\n            return false;\n          }\n          foreach (var xc in resolver.AllXConstraints) {\n            if (xc.ConstraintName == \"Assignable\" && xc.Types[0] == proxy) {\n              return false;\n            }\n          }\n          return true;\n        }\n        return false;\n      }\n\n      bool IsEqDetermined(Type t) {\n        Contract.Requires(t != null);\n        switch (TypeProxy.GetFamily(t)) {\n          case TypeProxy.Family.Bool:\n          case TypeProxy.Family.Char:\n          case TypeProxy.Family.IntLike:\n          case TypeProxy.Family.RealLike:\n          case TypeProxy.Family.Ordinal:\n          case TypeProxy.Family.BitVector:\n            return true;\n          case TypeProxy.Family.ValueType:\n          case TypeProxy.Family.Ref:\n          case TypeProxy.Family.Opaque:\n          case TypeProxy.Family.Unknown:\n          default:\n            return false;  // TODO: could be made more exact\n        }\n      }\n\n      internal bool CouldBeAnything() {\n        return Types.All(t => t.NormalizeExpand() is TypeProxy);\n      }\n\n      /// <summary>\n      /// If \"t\" or any type among its transitive sub/super-types (depending on \"towardsSub\")\n      /// is a collection type, then returns the element/domain type of that collection.\n      /// Otherwise, returns null.\n      /// </summary>\n      static Type FindCollectionType(Type t, bool towardsSub, ISet<TypeProxy> visited) {\n        Contract.Requires(t != null);\n        Contract.Requires(visited != null);\n        t = t.NormalizeExpand();\n        if (ArmadaOptions.O.TypeInferenceDebug) {\n          Console.WriteLine(\"DEBUG: FindCollectionType({0}, {1})\", t, towardsSub ? \"sub\" : \"super\");\n        }\n        if (t is CollectionType) {\n          if (ArmadaOptions.O.TypeInferenceDebug) {\n            Console.WriteLine(\"DEBUG: FindCollectionType({0}) = {1}\", t, ((CollectionType)t).Arg);\n          }\n          return ((CollectionType)t).Arg;\n        }\n        var proxy = t as TypeProxy;\n        if (proxy == null || visited.Contains(proxy)) {\n          return null;\n        }\n        visited.Add(proxy);\n        foreach (var sub in towardsSub ? proxy.Subtypes : proxy.Supertypes) {\n          var e = FindCollectionType(sub, towardsSub, visited);\n          if (e != null) {\n            return e;\n          }\n        }\n        return null;\n      }\n    }\n\n    public class XConstraintWithExprs : XConstraint\n    {\n      public readonly Expression[] Exprs;\n      public XConstraintWithExprs(IToken tok, string constraintName, Type[] types, Expression[] exprs, TypeConstraint.ErrorMsg errMsg)\n        : base(tok, constraintName, types, errMsg) {\n        Contract.Requires(tok != null);\n        Contract.Requires(constraintName != null);\n        Contract.Requires(types != null);\n        Contract.Requires(exprs != null);\n        Contract.Requires(errMsg != null);\n        this.Exprs = exprs;\n      }\n    }\n\n    public class XConstraint_EquatableArg : XConstraint\n    {\n      public bool AllowSuperSub;\n      public bool TreatTypeParamAsWild;\n      public XConstraint_EquatableArg(IToken tok, Type a, Type b, bool allowSuperSub, bool treatTypeParamAsWild, TypeConstraint.ErrorMsg errMsg)\n        : base(tok, \"EquatableArg\", new Type[] { a, b }, errMsg) {\n        Contract.Requires(tok != null);\n        Contract.Requires(a != null);\n        Contract.Requires(b != null);\n        Contract.Requires(errMsg != null);\n        AllowSuperSub = allowSuperSub;\n        TreatTypeParamAsWild = treatTypeParamAsWild;\n      }\n    }\n\n    /// <summary>\n    /// Solves or simplifies as many type constraints as possible.\n    /// If \"allowDecisions\" is \"false\", then no decisions, only determined inferences, are made; this mode is\n    /// appropriate for the partial solving that's done before a member lookup.\n    /// </summary>\n    void PartiallySolveTypeConstraints(bool allowDecisions) {\n      int state = 0;\n      while (true) {\n        if (2 <= state && !allowDecisions) {\n          // time to say goodnight to Napoli\n          return;\n        } else if (AllTypeConstraints.Count == 0 && AllXConstraints.Count == 0) {\n          // we're done\n          return;\n        }\n\n        var anyNewConstraints = false;\n        var fullStrength = false;\n        // Process subtyping constraints\n        PrintTypeConstraintState(220 + 2 * state);\n        switch (state) {\n          case 0: {\n              var allTypeConstraints = AllTypeConstraints;\n              AllTypeConstraints = new List<TypeConstraint>();\n              var processed = new HashSet<TypeConstraint>();\n              foreach (var c in allTypeConstraints) {\n                ProcessOneSubtypingConstraintAndItsSubs(c, processed, fullStrength, ref anyNewConstraints);\n              }\n\n              allTypeConstraints = new List<TypeConstraint>(AllTypeConstraints);  // copy the list\n              foreach (var c in allTypeConstraints) {\n                var super = c.Super.NormalizeExpand() as TypeProxy;\n                if (AssignKnownEnd(super, true, fullStrength)) {\n                  anyNewConstraints = true;\n                } else if (super != null && fullStrength && AssignKnownEndsFullstrength(super)) {  // KRML: is this used any more?\n                  anyNewConstraints = true;\n                }\n              }\n            }\n            break;\n\n          case 1: {\n              // Process XConstraints\n              // confirm as many XConstraints as possible, setting \"anyNewConstraints\" to \"true\" if the confirmation\n              // of an XConstraint gives rise to new constraints to be handled in the loop above\n              bool generatedMoreXConstraints;\n              do {\n                generatedMoreXConstraints = false;\n                var allXConstraints = AllXConstraints;\n                AllXConstraints = new List<XConstraint>();\n                foreach (var xc in allXConstraints) {\n                  bool convertedIntoOtherTypeConstraints, moreXConstraints;\n                  if (xc.Confirm(this, fullStrength, out convertedIntoOtherTypeConstraints, out moreXConstraints)) {\n                    if (convertedIntoOtherTypeConstraints) {\n                      anyNewConstraints = true;\n                    } else {\n                      generatedMoreXConstraints = true;\n                    }\n                    if (moreXConstraints) {\n                      generatedMoreXConstraints = true;\n                    }\n                  } else {\n                    AllXConstraints.Add(xc);\n                  }\n                }\n              } while (generatedMoreXConstraints);\n            }\n            break;\n\n          case 2: {\n              var assignables = AllXConstraints.Where(xc => xc.ConstraintName == \"Assignable\").ToList();\n              var postponeForNow = new HashSet<TypeProxy>();\n              foreach (var constraint in AllTypeConstraints) {\n                var lhs = constraint.Super.NormalizeExpandKeepConstraints() as NonProxyType;\n                if (lhs != null) {\n                  foreach (var ta in lhs.TypeArgs) {\n                    AddAllProxies(ta, postponeForNow);\n                  }\n                }\n              }\n              foreach (var constraint in AllTypeConstraints) {\n                var lhs = constraint.Super.Normalize() as TypeProxy;\n                if (lhs != null && !postponeForNow.Contains(lhs)) {\n                  var rhss = assignables.Where(xc => xc.Types[0].Normalize() == lhs).Select(xc => xc.Types[1]).ToList();\n                  if (ProcessAssignable(lhs, rhss)) {\n                    anyNewConstraints = true;  // next time around the big loop, start with state 0 again\n                  }\n                }\n              }\n              foreach (var assignable in assignables) {\n                var lhs = assignable.Types[0].Normalize() as TypeProxy;\n                if (lhs != null && !postponeForNow.Contains(lhs)) {\n                  var rhss = assignables.Where(xc => xc.Types[0].Normalize() == lhs).Select(xc => xc.Types[1]).ToList();\n                  if (ProcessAssignable(lhs, rhss)) {\n                    anyNewConstraints = true;  // next time around the big loop, start with state 0 again\n                                               // process only one Assignable constraint in this way\n                    break;\n                  }\n                }\n              }\n            }\n            break;\n\n          case 3:\n            anyNewConstraints = ConvertAssignableToSubtypeConstraints(null);\n            break;\n\n          case 4: {\n              var allTC = AllTypeConstraints;\n              AllTypeConstraints = new List<TypeConstraint>();\n              var proxyProcessed = new HashSet<TypeProxy>();\n              foreach (var c in allTC) {\n                ProcessFullStrength_SubDirection(c.Super, proxyProcessed, ref anyNewConstraints);\n              }\n              foreach (var xc in AllXConstraints) {\n                if (xc.ConstraintName == \"Assignable\") {\n                  ProcessFullStrength_SubDirection(xc.Types[0], proxyProcessed, ref anyNewConstraints);\n                }\n              }\n              if (!anyNewConstraints) {\n                // only do super-direction if sub-direction had no effect\n                proxyProcessed = new HashSet<TypeProxy>();\n                foreach (var c in allTC) {\n                  ProcessFullStrength_SuperDirection(c.Sub, proxyProcessed, ref anyNewConstraints);\n                }\n                foreach (var xc in AllXConstraints) {\n                  if (xc.ConstraintName == \"Assignable\") {\n                    ProcessFullStrength_SuperDirection(xc.Types[1], proxyProcessed, ref anyNewConstraints);\n                  }\n                }\n              }\n              AllTypeConstraints.AddRange(allTC);\n            }\n            break;\n\n          case 5: {\n              // Process default numeric types\n              var allTypeConstraints = AllTypeConstraints;\n              AllTypeConstraints = new List<TypeConstraint>();\n              foreach (var c in allTypeConstraints) {\n                if (c.Super is ArtificialType) {\n                  var proxy = c.Sub.NormalizeExpand() as TypeProxy;\n                  if (proxy != null) {\n                    AssignProxyAndHandleItsConstraints(proxy, c.Super is IntVarietiesSupertype ? (Type)Type.Int : Type.Real);\n                    anyNewConstraints = true;\n                    continue;\n                  }\n                }\n                AllTypeConstraints.Add(c);\n              }\n            }\n            break;\n\n          case 6: {\n              fullStrength = true;\n              bool generatedMoreXConstraints;\n              do {\n                generatedMoreXConstraints = false;\n                var allXConstraints = AllXConstraints;\n                AllXConstraints = new List<XConstraint>();\n                foreach (var xc in allXConstraints) {\n                  bool convertedIntoOtherTypeConstraints, moreXConstraints;\n                  if ((xc.ConstraintName == \"Equatable\" || xc.ConstraintName == \"EquatableArg\") && xc.Confirm(this, fullStrength, out convertedIntoOtherTypeConstraints, out moreXConstraints)) {\n                    if (convertedIntoOtherTypeConstraints) {\n                      anyNewConstraints = true;\n                    } else {\n                      generatedMoreXConstraints = true;\n                    }\n                    if (moreXConstraints) {\n                      generatedMoreXConstraints = true;\n                    }\n                  } else {\n                    AllXConstraints.Add(xc);\n                  }\n                }\n              } while (generatedMoreXConstraints);\n            }\n            break;\n\n          case 7: {\n              // Process default reference types\n              var allXConstraints = AllXConstraints;\n              AllXConstraints = new List<XConstraint>();\n              foreach (var xc in allXConstraints) {\n                if (xc.ConstraintName == \"IsRefType\" || xc.ConstraintName == \"IsNullableRefType\") {\n                  var proxy = xc.Types[0].Normalize() as TypeProxy;  // before we started processing default types, this would have been a proxy (since it's still in the A\n                  if (proxy != null) {\n                    AssignProxyAndHandleItsConstraints(proxy, builtIns.ObjectQ());\n                    anyNewConstraints = true;\n                    continue;\n                  }\n                }\n                AllXConstraints.Add(xc);\n              }\n            }\n            break;\n\n          case 8: fullStrength = true; goto case 0;\n          case 9: fullStrength = true; goto case 1;\n\n          case 10: {\n              // Finally, collapse constraints involving only proxies, which will have the effect of trading some type error\n              // messages for type-underspecification messages.\n              var allTypeConstraints = AllTypeConstraints;\n              AllTypeConstraints = new List<TypeConstraint>();\n              foreach (var c in allTypeConstraints) {\n                var super = c.Super.NormalizeExpand();\n                var sub = c.Sub.NormalizeExpand();\n                if (super == sub) {\n                  continue;\n                } else if (super is TypeProxy && sub is TypeProxy) {\n                  var proxy = (TypeProxy)super;\n                  if (ArmadaOptions.O.TypeInferenceDebug) {\n                    Console.WriteLine(\"DEBUG: (merge in PartiallySolve) assigning proxy {0}.T := {1}\", proxy, sub);\n                  }\n                  proxy.T = sub;\n                  anyNewConstraints = true;  // signal a change in the constraints\n                  continue;\n                }\n                AllTypeConstraints.Add(c);\n              }\n            }\n            break;\n\n          case 11:\n            // we're so out of here\n            return;\n        }\n        if (anyNewConstraints) {\n          state = 0;\n        } else {\n          state++;\n        }\n      }\n    }\n\n    private void AddAllProxies(Type type, HashSet<TypeProxy> proxies) {\n      Contract.Requires(type != null);\n      Contract.Requires(proxies != null);\n      var proxy = type as TypeProxy;\n      if (proxy != null) {\n        proxies.Add(proxy);\n      } else {\n        foreach (var ta in type.TypeArgs) {\n          AddAllProxies(ta, proxies);\n        }\n      }\n    }\n\n    /// <summary>\n    /// Set \"lhs\" to the meet of \"rhss\" and \"lhs.Subtypes, if possible.\n    /// Returns \"true' if something was done, or \"false\" otherwise.\n    /// </summary>\n    private bool ProcessAssignable(TypeProxy lhs, List<Type> rhss) {\n      Contract.Requires(lhs != null && lhs.T == null);\n      Contract.Requires(rhss != null);\n      if (ArmadaOptions.O.TypeInferenceDebug) {\n        Console.Write(\"DEBUG: ProcessAssignable: {0} with rhss:\", lhs);\n        foreach (var rhs in rhss) {\n          Console.Write(\" {0}\", rhs);\n        }\n        Console.Write(\" subtypes:\");\n        foreach (var sub in lhs.SubtypesKeepConstraints) {\n          Console.Write(\" {0}\", sub);\n        }\n        Console.WriteLine();\n      }\n      Type meet = null;\n      foreach (var rhs in rhss) {\n        if (rhs is TypeProxy) { return false; }\n        meet = meet == null ? rhs : Type.Meet(meet, rhs, builtIns);\n      }\n      foreach (var sub in lhs.SubtypesKeepConstraints) {\n        if (sub is TypeProxy) { return false; }\n        meet = meet == null ? sub : Type.Meet(meet, sub, builtIns);\n      }\n      if (meet == null) {\n        return false;\n      } else if (Reaches(meet, lhs, 1, new HashSet<TypeProxy>())) {\n        // would cause a cycle, so don't do it\n        return false;\n      } else {\n        if (ArmadaOptions.O.TypeInferenceDebug) {\n          Console.WriteLine(\"DEBUG: ProcessAssignable: assigning proxy {0}.T := {1}\", lhs, meet);\n        }\n        lhs.T = meet;\n        return true;\n      }\n    }\n\n    /// <summary>\n    /// Convert each Assignable(A, B) constraint into a subtyping constraint A :> B,\n    /// provided that:\n    ///  - B is a non-proxy, and\n    ///  - either \"proxySpecialization\" is null or some proxy in \"proxySpecializations\" prominently appears in A.\n    /// </summary>\n    bool ConvertAssignableToSubtypeConstraints(ISet<TypeProxy>/*?*/ proxySpecializations) {\n      var anyNewConstraints = false;\n      // If (the head of) the RHS of an Assignable is known, convert the XConstraint into a subtyping constraint\n      var allX = AllXConstraints;\n      AllXConstraints = new List<XConstraint>();\n      foreach (var xc in allX) {\n        if (xc.ConstraintName == \"Assignable\" && xc.Types[1].Normalize() is NonProxyType) {\n          var t0 = xc.Types[0].NormalizeExpand();\n          if (proxySpecializations == null\n            || proxySpecializations.Contains(t0)\n            || t0.TypeArgs.Exists(ta => proxySpecializations.Contains(ta))) {\n            ConstrainSubtypeRelation(t0, xc.Types[1], xc.errorMsg, true);\n            anyNewConstraints = true;\n            continue;\n          }\n        }\n        AllXConstraints.Add(xc);\n      }\n      return anyNewConstraints;\n    }\n\n    bool TightenUpEquatable(ISet<TypeProxy> proxiesOfInterest) {\n      Contract.Requires(proxiesOfInterest != null);\n      var anyNewConstraints = false;\n      var allX = AllXConstraints;\n      AllXConstraints = new List<XConstraint>();\n      foreach (var xc in allX) {\n        if (xc.ConstraintName == \"Equatable\" || xc.ConstraintName == \"EquatableArg\") {\n          var t0 = xc.Types[0].NormalizeExpandKeepConstraints();\n          var t1 = xc.Types[1].NormalizeExpandKeepConstraints();\n          if (proxiesOfInterest.Contains(t0) || proxiesOfInterest.Contains(t1)) {\n            ConstrainSubtypeRelation_Equal(t0, t1, xc.errorMsg);\n            anyNewConstraints = true;\n            continue;\n          }\n        }\n        AllXConstraints.Add(xc);\n      }\n      return anyNewConstraints;\n    }\n\n    void ProcessOneSubtypingConstraintAndItsSubs(TypeConstraint c, ISet<TypeConstraint> processed, bool fullStrength, ref bool anyNewConstraints) {\n      Contract.Requires(c != null);\n      Contract.Requires(processed != null);\n      if (processed.Contains(c)) {\n        return;  // our job has already been done, or is at least in progress\n      }\n      processed.Add(c);\n\n      var super = c.Super.NormalizeExpandKeepConstraints();\n      var sub = c.Sub.NormalizeExpandKeepConstraints();\n      // Process all subtype types before going on\n      var subProxy = sub as TypeProxy;\n      if (subProxy != null) {\n        foreach (var cc in subProxy.SubtypeConstraints) {\n          ProcessOneSubtypingConstraintAndItsSubs(cc, processed, fullStrength, ref anyNewConstraints);\n        }\n      }\n      // the processing may have assigned some proxies, so we'll refresh super and sub\n      super = super.NormalizeExpandKeepConstraints();\n      sub = sub.NormalizeExpandKeepConstraints();\n\n      if (super.Equals(sub)) {\n        // the constraint is satisfied, so just drop it\n      } else if ((super is NonProxyType || super is ArtificialType) && sub is NonProxyType) {\n        ImposeSubtypingConstraint(super, sub, c.errorMsg);\n        anyNewConstraints = true;\n      } else if (AssignKnownEnd(sub as TypeProxy, true, fullStrength)) {\n        anyNewConstraints = true;\n      } else if (sub is TypeProxy && fullStrength && AssignKnownEndsFullstrength((TypeProxy)sub)) {\n        anyNewConstraints = true;\n      } else {\n        // keep the constraint for now\n        AllTypeConstraints.Add(c);\n      }\n    }\n\n    void ProcessFullStrength_SubDirection(Type t, ISet<TypeProxy> processed, ref bool anyNewConstraints) {\n      Contract.Requires(t != null);\n      Contract.Requires(processed != null);\n      var proxy = t.NormalizeExpand() as TypeProxy;\n      if (proxy != null) {\n        if (processed.Contains(proxy)) {\n          return;  // our job has already been done, or is at least in progress\n        }\n        processed.Add(proxy);\n\n        foreach (var u in proxy.SubtypesKeepConstraints_WithAssignable(AllXConstraints)) {\n          ProcessFullStrength_SubDirection(u, processed, ref anyNewConstraints);\n        }\n        proxy = proxy.NormalizeExpand() as TypeProxy;\n        if (proxy != null && AssignKnownEndsFullstrength_SubDirection(proxy)) {\n          anyNewConstraints = true;\n        }\n      }\n    }\n\n    void ProcessFullStrength_SuperDirection(Type t, ISet<TypeProxy> processed, ref bool anyNewConstraints) {\n      Contract.Requires(t != null);\n      Contract.Requires(processed != null);\n      var proxy = t.NormalizeExpand() as TypeProxy;\n      if (proxy != null) {\n        if (processed.Contains(proxy)) {\n          return;  // our job has already been done, or is at least in progress\n        }\n        processed.Add(proxy);\n\n        foreach (var u in proxy.Supertypes) {\n          ProcessFullStrength_SuperDirection(u, processed, ref anyNewConstraints);\n        }\n        proxy = proxy.NormalizeExpand() as TypeProxy;\n        if (proxy != null && AssignKnownEndsFullstrength_SuperDirection(proxy)) {\n          anyNewConstraints = true;\n        }\n      }\n    }\n\n    /// <summary>\n    /// Returns true if anything happened.\n    /// </summary>\n    bool AssignKnownEnd(TypeProxy proxy, bool keepConstraints, bool fullStrength) {\n      Contract.Requires(proxy == null || proxy.T == null);  // caller is supposed to have called NormalizeExpand\n      if (proxy == null) {\n        // nothing to do\n        return false;\n      }\n      // ----- first, go light; also, prefer subtypes over supertypes\n      IEnumerable<Type> subTypes = keepConstraints ? proxy.SubtypesKeepConstraints : proxy.Subtypes;\n      foreach (var su in subTypes) {\n        bool isRoot, isLeaf, headRoot, headLeaf;\n        CheckEnds(su, out isRoot, out isLeaf, out headRoot, out headLeaf);\n        Contract.Assert(!isRoot || headRoot);  // isRoot ==> headRoot\n        if (isRoot) {\n          if (Reaches(su, proxy, 1, new HashSet<TypeProxy>())) {\n            // adding a constraint here would cause a bad cycle, so we don't\n          } else {\n            AssignProxyAndHandleItsConstraints(proxy, su, keepConstraints);\n            return true;\n          }\n        } else if (headRoot) {\n          if (Reaches(su, proxy, 1, new HashSet<TypeProxy>())) {\n            // adding a constraint here would cause a bad cycle, so we don't\n          } else {\n            AssignProxyAndHandleItsConstraints(proxy, TypeProxy.HeadWithProxyArgs(su), keepConstraints);\n            return true;\n          }\n        }\n      }\n      if (fullStrength) {\n        IEnumerable<Type> superTypes = keepConstraints ? proxy.SupertypesKeepConstraints : proxy.Supertypes;\n        foreach (var su in superTypes) {\n          bool isRoot, isLeaf, headRoot, headLeaf;\n          CheckEnds(su, out isRoot, out isLeaf, out headRoot, out headLeaf);\n          Contract.Assert(!isLeaf || headLeaf);  // isLeaf ==> headLeaf\n          if (isLeaf) {\n            if (Reaches(su, proxy, -1, new HashSet<TypeProxy>())) {\n              // adding a constraint here would cause a bad cycle, so we don't\n            } else {\n              AssignProxyAndHandleItsConstraints(proxy, su, keepConstraints);\n              return true;\n            }\n          } else if (headLeaf) {\n            if (Reaches(su, proxy, -1, new HashSet<TypeProxy>())) {\n              // adding a constraint here would cause a bad cycle, so we don't\n            } else {\n              AssignProxyAndHandleItsConstraints(proxy, TypeProxy.HeadWithProxyArgs(su), keepConstraints);\n              return true;\n            }\n          }\n        }\n      }\n      return false;\n    }\n\n    bool AssignKnownEndsFullstrength(TypeProxy proxy) {\n      Contract.Requires(proxy != null);\n      // ----- continue with full strength\n      // If the meet of the subtypes exists, use it\n      var meets = new List<Type>();\n      foreach (var su in proxy.Subtypes) {\n        if (su is TypeProxy) {\n          continue;  // don't include proxies in the meet computation\n        }\n        int i = 0;\n        for (; i < meets.Count; i++) {\n          var j = Type.Meet(meets[i], su, builtIns);\n          if (j != null) {\n            meets[i] = j;\n            break;\n          }\n        }\n        if (i == meets.Count) {\n          // we went to the end without finding a place to meet up\n          meets.Add(su);\n        }\n      }\n      if (meets.Count == 1 && !Reaches(meets[0], proxy, 1, new HashSet<TypeProxy>())) {\n        // we were able to compute a meet of all the subtyping constraints, so use it\n        AssignProxyAndHandleItsConstraints(proxy, meets[0]);\n        return true;\n      }\n      // If the join of the supertypes exists, use it\n      var joins = new List<Type>();\n      foreach (var su in proxy.Supertypes) {\n        if (su is TypeProxy) {\n          continue;  // don't include proxies in the join computation\n        }\n        int i = 0;\n        for (; i < joins.Count; i++) {\n          var j = Type.Join(joins[i], su, builtIns);\n          if (j != null) {\n            joins[i] = j;\n            break;\n          }\n        }\n        if (i == joins.Count) {\n          // we went to the end without finding a place to join in\n          joins.Add(su);\n        }\n      }\n      if (joins.Count == 1 && !(joins[0] is ArtificialType) && !Reaches(joins[0], proxy, -1, new HashSet<TypeProxy>())) {\n        // we were able to compute a join of all the subtyping constraints, so use it\n        AssignProxyAndHandleItsConstraints(proxy, joins[0]);\n        return true;\n      }\n\n      return false;\n    }\n\n    bool AssignKnownEndsFullstrength_SubDirection(TypeProxy proxy) {\n      Contract.Requires(proxy != null && proxy.T == null);\n      // If the meet of the subtypes exists, use it\n      var meets = new List<Type>();\n      var proxySubs = new HashSet<TypeProxy>();\n      proxySubs.Add(proxy);\n      foreach (var su in proxy.SubtypesKeepConstraints_WithAssignable(AllXConstraints)) {\n        if (su is TypeProxy) {\n          proxySubs.Add((TypeProxy)su);\n        } else {\n          int i = 0;\n          for (; i < meets.Count; i++) {\n            var j = Type.Meet(meets[i], su, builtIns);\n            if (j != null) {\n              meets[i] = j;\n              break;\n            }\n          }\n          if (i == meets.Count) {\n            // we went to the end without finding a place to meet up\n            meets.Add(su);\n          }\n        }\n      }\n      if (meets.Count == 1 && !Reaches(meets[0], proxy, 1, new HashSet<TypeProxy>())) {\n        // We were able to compute a meet of all the subtyping constraints, so use it.\n        // Well, maybe.  If \"meets[0]\" denotes a non-null type and \"proxy\" is something\n        // that could be assigned \"null\", then set \"proxy\" to the nullable version of \"meets[0]\".\n        // Stated differently, think of an applicable \"IsNullableRefType\" constraint as\n        // being part of the meet computation, essentially throwing in a \"...?\".\n        // Except: If the meet is a tight bound--meaning, it is also a join--then pick it\n        // after all, because that seems to give rise to less confusing error messages.\n        if (meets[0].IsNonNullRefType) {\n          Type join = null;\n          if (JoinOfAllSupertypes(proxy, ref join, new HashSet<TypeProxy>(), false) && join != null && Type.SameHead(meets[0], join)) {\n            // leave it\n          } else {\n            CloseOverAssignableRhss(proxySubs);\n            if (HasApplicableNullableRefTypeConstraint(proxySubs)) {\n              if (ArmadaOptions.O.TypeInferenceDebug) {\n                Console.WriteLine(\"DEBUG: Found meet {0} for proxy {1}, but weakening it to {2}\", meets[0], proxy, meets[0].NormalizeExpand());\n              }\n              AssignProxyAndHandleItsConstraints(proxy, meets[0].NormalizeExpand(), true);\n              return true;\n            }\n          }\n        }\n        AssignProxyAndHandleItsConstraints(proxy, meets[0], true);\n        return true;\n      }\n      return false;\n    }\n\n    private void CloseOverAssignableRhss(ISet<TypeProxy> proxySet) {\n      Contract.Requires(proxySet != null);\n      while (true) {\n        var moreChanges = false;\n        foreach (var xc in AllXConstraints) {\n          if (xc.ConstraintName == \"Assignable\") {\n            var source = xc.Types[0].Normalize() as TypeProxy;\n            var sink = xc.Types[1].Normalize() as TypeProxy;\n            if (source != null && sink != null && proxySet.Contains(source) && !proxySet.Contains(sink)) {\n              proxySet.Add(sink);\n              moreChanges = true;\n            }\n          }\n        }\n        if (!moreChanges) {\n          return;\n        }\n      }\n    }\n    private bool HasApplicableNullableRefTypeConstraint(ISet<TypeProxy> proxySet) {\n      Contract.Requires(proxySet != null);\n      var nullableProxies = new HashSet<TypeProxy>();\n      foreach (var xc in AllXConstraints) {\n        if (xc.ConstraintName == \"IsNullableRefType\") {\n          var npr = xc.Types[0].Normalize() as TypeProxy;\n          if (npr != null) {\n            nullableProxies.Add(npr);\n          }\n        }\n      }\n      return proxySet.Any(nullableProxies.Contains);\n    }\n    private bool HasApplicableNullableRefTypeConstraint_SubDirection(TypeProxy proxy) {\n      Contract.Requires(proxy != null);\n      var nullableProxies = new HashSet<TypeProxy>();\n      foreach (var xc in AllXConstraints) {\n        if (xc.ConstraintName == \"IsNullableRefType\") {\n          var npr = xc.Types[0].Normalize() as TypeProxy;\n          if (npr != null) {\n            nullableProxies.Add(npr);\n          }\n        }\n      }\n      return HasApplicableNullableRefTypeConstraint_SubDirection_aux(proxy, nullableProxies, new HashSet<TypeProxy>());\n    }\n    private bool HasApplicableNullableRefTypeConstraint_SubDirection_aux(TypeProxy proxy, ISet<TypeProxy> nullableProxies, ISet<TypeProxy> visitedProxies) {\n      Contract.Requires(proxy != null);\n      Contract.Requires(nullableProxies != null);\n      Contract.Requires(visitedProxies != null);\n\n      if (visitedProxies.Contains(proxy)) {\n        return false;\n      }\n      visitedProxies.Add(proxy);\n\n      if (nullableProxies.Contains(proxy)) {\n        return true;\n      }\n\n      foreach (var sub in proxy.SubtypesKeepConstraints_WithAssignable(AllXConstraints)) {\n        var psub = sub as TypeProxy;\n        if (psub != null && HasApplicableNullableRefTypeConstraint_SubDirection_aux(psub, nullableProxies, visitedProxies)) {\n          return true;\n        }\n      }\n      return false;\n    }\n\n    bool AssignKnownEndsFullstrength_SuperDirection(TypeProxy proxy) {\n      Contract.Requires(proxy != null && proxy.T == null);\n      // First, compute the the meet of the Assignable LHSs.  Then, compute\n      // the join of that meet and the supertypes.\n      var meets = new List<Type>();\n      foreach (var xc in AllXConstraints) {\n        if (xc.ConstraintName == \"Assignable\" && xc.Types[1].Normalize() == proxy) {\n          var su = xc.Types[0].NormalizeExpandKeepConstraints();\n          if (su is TypeProxy) {\n            continue;  // don't include proxies in the meet computation\n          }\n          int i = 0;\n          for (; i < meets.Count; i++) {\n            var j = Type.Meet(meets[i], su, builtIns);\n            if (j != null) {\n              meets[i] = j;\n              break;\n            }\n          }\n          if (i == meets.Count) {\n            // we went to the end without finding a place to meet in\n            meets.Add(su);\n          }\n        }\n      }\n      // If the join of the supertypes exists, use it\n      var joins = new List<Type>(meets);\n      foreach (var su in proxy.SupertypesKeepConstraints) {\n        if (su is TypeProxy) {\n          continue;  // don't include proxies in the join computation\n        }\n        int i = 0;\n        for (; i < joins.Count; i++) {\n          var j = Type.Join(joins[i], su, builtIns);\n          if (j != null) {\n            joins[i] = j;\n            break;\n          }\n        }\n        if (i == joins.Count) {\n          // we went to the end without finding a place to join in\n          joins.Add(su);\n        }\n      }\n      if (joins.Count == 1 && !(joins[0] is ArtificialType) && !Reaches(joins[0], proxy, -1, new HashSet<TypeProxy>())) {\n        // we were able to compute a join of all the subtyping constraints, so use it\n        AssignProxyAndHandleItsConstraints(proxy, joins[0], true);\n        return true;\n      }\n      return false;\n    }\n\n    int _reaches_recursion;\n    private bool Reaches(Type t, TypeProxy proxy, int direction, HashSet<TypeProxy> visited) {\n      if (_reaches_recursion == 20) {\n        Contract.Assume(false);  // possible infinite recursion\n      }\n      _reaches_recursion++;\n      var b = Reaches_aux(t, proxy, direction, visited);\n      _reaches_recursion--;\n      return b;\n    }\n    private bool Reaches_aux(Type t, TypeProxy proxy, int direction, HashSet<TypeProxy> visited) {\n      Contract.Requires(t != null);\n      Contract.Requires(proxy != null);\n      Contract.Requires(visited != null);\n      t = t.NormalizeExpand();\n      var tproxy = t as TypeProxy;\n      if (tproxy == null) {\n        var polarities = ConstrainTypeHead(t, t);\n        Contract.Assert(polarities != null);\n        Contract.Assert(polarities.Count <= t.TypeArgs.Count);\n        for (int i = 0; i < polarities.Count; i++) {\n          if (Reaches(t.TypeArgs[i], proxy, direction * polarities[i], visited)) {\n            return true;\n          }\n        }\n        return false;\n      } else if (tproxy == proxy) {\n        return true;\n      } else if (visited.Contains(tproxy)) {\n        return false;\n      } else {\n        visited.Add(tproxy);\n        if (0 <= direction && tproxy.Subtypes.Any(su => Reaches(su, proxy, direction, visited))) {\n          return true;\n        }\n        if (direction <= 0 && tproxy.Supertypes.Any(su => Reaches(su, proxy, direction, visited))) {\n          return true;\n        }\n        return false;\n      }\n    }\n\n    [System.Diagnostics.Conditional(\"TI_DEBUG_PRINT\")]\n    void PrintTypeConstraintState(int lbl) {\n      if (!ArmadaOptions.O.TypeInferenceDebug) {\n        return;\n      }\n      Console.WriteLine(\"DEBUG: ---------- type constraints ---------- {0} {1}\", lbl, lbl == 0 && currentMethod != null ? currentMethod.Name : \"\");\n      foreach (var constraint in AllTypeConstraints) {\n        var super = constraint.Super.Normalize();\n        var sub = constraint.Sub.Normalize();\n        Console.WriteLine(\"    {0} :> {1}\", super is IntVarietiesSupertype ? \"int-like\" : super is RealVarietiesSupertype ? \"real-like\" : super.ToString(), sub);\n      }\n      foreach (var xc in AllXConstraints) {\n        Console.WriteLine(\"    {0}\", xc);\n      }\n      Console.WriteLine();\n      if (lbl % 2 == 1) {\n        Console.WriteLine(\"DEBUG: --------------------------------------\");\n      }\n    }\n\n    /// <summary>\n    /// Attempts to fully solve all type constraints.\n    /// Upon failure, reports errors.\n    /// Clears all constraints.\n    /// </summary>\n    void SolveAllTypeConstraints() {\n      PrintTypeConstraintState(0);\n      PartiallySolveTypeConstraints(true);\n      PrintTypeConstraintState(1);\n      foreach (var constraint in AllTypeConstraints) {\n        if (Type.IsSupertype(constraint.Super, constraint.Sub)) {\n          // unexpected condition -- PartiallySolveTypeConstraints is supposed to have continued until no more sub-typing constraints can be satisfied\n          Contract.Assume(false, string.Format(\"DEBUG: Unexpectedly satisfied supertype relation ({0} :> {1}) |||| \", constraint.Super, constraint.Sub));\n        } else {\n          constraint.FlagAsError();\n        }\n      }\n      foreach (var xc in AllXConstraints) {\n        bool convertedIntoOtherTypeConstraints, moreXConstraints;\n        if (xc.Confirm(this, true, out convertedIntoOtherTypeConstraints, out moreXConstraints)) {\n          // unexpected condition -- PartiallySolveTypeConstraints is supposed to have continued until no more XConstraints were confirmable\n          Contract.Assume(false, string.Format(\"DEBUG: Unexpectedly confirmed XConstraint: {0} |||| \", xc));\n        } else if (xc.CouldBeAnything()) {\n          // suppress the error message; it will later be flagged as an underspecified type\n        } else {\n          xc.errorMsg.FlagAsError();\n        }\n      }\n      TypeConstraint.ReportErrors(reporter);\n      AllTypeConstraints.Clear();\n      AllXConstraints.Clear();\n    }\n\n    public class TypeConstraint\n    {\n      public readonly Type Super;\n      public readonly Type Sub;\n      public readonly bool KeepConstraints;\n\n      private static List<ErrorMsg> ErrorsToBeReported = new List<ErrorMsg>();\n      public static void ReportErrors(ErrorReporter reporter) {\n        Contract.Requires(reporter != null);\n        foreach (var err in ErrorsToBeReported) {\n          err.ReportAsError(reporter);\n        }\n        ErrorsToBeReported.Clear();\n      }\n      abstract public class ErrorMsg\n      {\n        public abstract IToken Tok { get; }\n        bool reported;\n        public void FlagAsError() {\n          TypeConstraint.ErrorsToBeReported.Add(this);\n        }\n        internal void ReportAsError(ErrorReporter reporter) {\n          Contract.Requires(reporter != null);\n          if (!reported) {  // this \"reported\" bit is checked only for the top-level message, but this message and all nested ones get their \"reported\" bit set to \"true\" as a result\n            Reporting(reporter, \"\");\n          }\n        }\n        private void Reporting(ErrorReporter reporter, string suffix) {\n          Contract.Requires(reporter != null);\n          Contract.Requires(suffix != null);\n          if (this is ErrorMsgWithToken) {\n            var err = (ErrorMsgWithToken)this;\n            Contract.Assert(err.Tok != null);\n            reporter.Error(MessageSource.Resolver, err.Tok, err.Msg + suffix, err.MsgArgs);\n          } else {\n            var err = (ErrorMsgWithBase)this;\n            err.BaseMsg.Reporting(reporter, \" (\" + string.Format(err.Msg, err.MsgArgs) + \")\" + suffix);\n          }\n          reported = true;\n        }\n      }\n      public class ErrorMsgWithToken : ErrorMsg\n      {\n        readonly IToken tok;\n        public override IToken Tok {\n          get { return tok; }\n        }\n        public readonly string Msg;\n        public readonly object[] MsgArgs;\n        public ErrorMsgWithToken(IToken tok, string msg, params object[] msgArgs) {\n          Contract.Requires(tok != null);\n          Contract.Requires(msg != null);\n          Contract.Requires(msgArgs != null);\n          this.tok = tok;\n          this.Msg = msg;\n          this.MsgArgs = msgArgs;\n        }\n      }\n      public class ErrorMsgWithBase : ErrorMsg\n      {\n        public override IToken Tok {\n          get { return BaseMsg.Tok; }\n        }\n        public readonly ErrorMsg BaseMsg;\n        public readonly string Msg;\n        public readonly object[] MsgArgs;\n        public ErrorMsgWithBase(ErrorMsg baseMsg, string msg, params object[] msgArgs) {\n          Contract.Requires(baseMsg != null);\n          Contract.Requires(msg != null);\n          Contract.Requires(msgArgs != null);\n          BaseMsg = baseMsg;\n          Msg = msg;\n          MsgArgs = msgArgs;\n        }\n      }\n      public readonly ErrorMsg errorMsg;\n      public TypeConstraint(Type super, Type sub, ErrorMsg errMsg, bool keepConstraints) {\n        Contract.Requires(super != null);\n        Contract.Requires(sub != null);\n        Contract.Requires(errMsg != null);\n        Super = super;\n        Sub = sub;\n        errorMsg = errMsg;\n        KeepConstraints = keepConstraints;\n      }\n      public void FlagAsError() {\n        errorMsg.FlagAsError();\n      }\n    }\n\n    // ------------------------------------------------------------------------------------------------------\n    // ----- Visitors ---------------------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------------------------\n#region Visitors\n    class ResolverBottomUpVisitor : BottomUpVisitor\n    {\n      protected Resolver resolver;\n      public ResolverBottomUpVisitor(Resolver resolver) {\n        Contract.Requires(resolver != null);\n        this.resolver = resolver;\n      }\n    }\n    abstract class ResolverTopDownVisitor<T> : TopDownVisitor<T>\n    {\n      protected Resolver resolver;\n      public ResolverTopDownVisitor(Resolver resolver) {\n        Contract.Requires(resolver != null);\n        this.resolver = resolver;\n      }\n    }\n#endregion Visitors\n\n    // ------------------------------------------------------------------------------------------------------\n    // ----- CheckTypeInference -----------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------------------------\n#region CheckTypeInference\n    private void CheckTypeInference_Member(MemberDecl member) {\n      if (member is ConstantField) {\n        var field = (ConstantField) member;\n        if (field.Rhs != null) {\n          CheckTypeInference(field.Rhs, new NoContext(member.EnclosingClass.Module));\n        }\n        CheckTypeInference(field.Type, new NoContext(member.EnclosingClass.Module), field.tok, \"const\");\n      } else if (member is Method) {\n        var m = (Method)member;\n        m.Req.Iter(mfe => CheckTypeInference_MaybeFreeExpression(mfe, m));\n        m.Ens.Iter(mfe => CheckTypeInference_MaybeFreeExpression(mfe, m));\n        CheckTypeInference_Specification_FrameExpr(m.Mod, m);\n        CheckTypeInference_Specification_Expr(m.Decreases, m);\n        if (m.Body != null) {\n          CheckTypeInference(m.Body, m);\n        }\n      } else if (member is Function) {\n        var f = (Function)member;\n        var errorCount = reporter.Count(ErrorLevel.Error);\n        f.Req.Iter(e => CheckTypeInference(e.E, f));\n        f.Ens.Iter(e => CheckTypeInference(e.E, f));\n        f.Reads.Iter(fe => CheckTypeInference(fe.E, f));\n        CheckTypeInference_Specification_Expr(f.Decreases, f);\n        if (f.Body != null) {\n          CheckTypeInference(f.Body, f);\n        }\n        if (errorCount == reporter.Count(ErrorLevel.Error) && f is FixpointPredicate) {\n          var cop = (FixpointPredicate)f;\n          CheckTypeInference_Member(cop.PrefixPredicate);\n        }\n      }\n    }\n\n    private void CheckTypeInference_MaybeFreeExpression(MaybeFreeExpression mfe, ICodeContext codeContext) {\n      Contract.Requires(mfe != null);\n      Contract.Requires(codeContext != null);\n      foreach (var e in Attributes.SubExpressions(mfe.Attributes)) {\n        CheckTypeInference(e, codeContext);\n      }\n      CheckTypeInference(mfe.E, codeContext);\n    }\n    private void CheckTypeInference_Specification_Expr(Specification<Expression> spec, ICodeContext codeContext) {\n      Contract.Requires(spec != null);\n      Contract.Requires(codeContext != null);\n      foreach (var e in Attributes.SubExpressions(spec.Attributes)) {\n        CheckTypeInference(e, codeContext);\n      }\n      spec.Expressions.Iter(e => CheckTypeInference(e, codeContext));\n    }\n    private void CheckTypeInference_Specification_FrameExpr(Specification<FrameExpression> spec, ICodeContext codeContext) {\n      Contract.Requires(spec != null);\n      Contract.Requires(codeContext != null);\n      foreach (var e in Attributes.SubExpressions(spec.Attributes)) {\n        CheckTypeInference(e, codeContext);\n      }\n      spec.Expressions.Iter(fe => CheckTypeInference(fe.E, codeContext));\n    }\n    void CheckTypeInference(Expression expr, ICodeContext codeContext) {\n      Contract.Requires(expr != null);\n      Contract.Requires(codeContext != null);\n      PartiallySolveTypeConstraints(true);\n      var c = new CheckTypeInference_Visitor(this, codeContext);\n      c.Visit(expr);\n    }\n    void CheckTypeInference(Type type, ICodeContext codeContext, IToken tok, string what) {\n      Contract.Requires(type != null);\n      Contract.Requires(codeContext != null);\n      Contract.Requires(tok != null);\n      Contract.Requires(what != null);\n      PartiallySolveTypeConstraints(true);\n      var c = new CheckTypeInference_Visitor(this, codeContext);\n      c.CheckTypeIsDetermined(tok, type, what);\n    }\n    void CheckTypeInference(Statement stmt, ICodeContext codeContext) {\n      Contract.Requires(stmt != null);\n      Contract.Requires(codeContext != null);\n      PartiallySolveTypeConstraints(true);\n      var c = new CheckTypeInference_Visitor(this, codeContext);\n      c.Visit(stmt);\n    }\n    class CheckTypeInference_Visitor : ResolverBottomUpVisitor\n    {\n      readonly ICodeContext codeContext;\n      public CheckTypeInference_Visitor(Resolver resolver, ICodeContext codeContext)\n        : base(resolver) {\n        Contract.Requires(resolver != null);\n        Contract.Requires(codeContext != null);\n        this.codeContext = codeContext;\n      }\n      protected override void VisitOneStmt(Statement stmt) {\n        if (stmt is VarDeclStmt) {\n          var s = (VarDeclStmt)stmt;\n          foreach (var local in s.Locals) {\n            CheckTypeIsDetermined(local.Tok, local.Type, \"local variable\");\n            CheckTypeArgsContainNoOrdinal(local.Tok, local.type);\n          }\n        } else if (stmt is LetStmt) {\n          var s = (LetStmt)stmt;\n          s.LocalVars.Iter(local => CheckTypeIsDetermined(local.Tok, local.Type, \"local variable\"));\n          s.LocalVars.Iter(local => CheckTypeArgsContainNoOrdinal(local.Tok, local.Type));\n\n        } else if (stmt is ForallStmt) {\n          var s = (ForallStmt)stmt;\n          s.BoundVars.Iter(bv => CheckTypeIsDetermined(bv.tok, bv.Type, \"bound variable\"));\n          s.Bounds = DiscoverBestBounds_MultipleVars(s.BoundVars, s.Range, true, ComprehensionExpr.BoundedPool.PoolVirtues.Enumerable);\n          s.BoundVars.Iter(bv => CheckTypeArgsContainNoOrdinal(bv.tok, bv.Type));\n\n        } else if (stmt is AssignSuchThatStmt) {\n          var s = (AssignSuchThatStmt)stmt;\n          if (s.AssumeToken == null) {\n            var varLhss = new List<IVariable>();\n            foreach (var lhs in s.Lhss) {\n              var ide = (IdentifierExpr)lhs.Resolved;  // successful resolution implies all LHS's are IdentifierExpr's\n              varLhss.Add(ide.Var);\n            }\n            s.Bounds = DiscoverBestBounds_MultipleVars(varLhss, s.Expr, true, ComprehensionExpr.BoundedPool.PoolVirtues.None);\n          }\n          foreach (var lhs in s.Lhss) {\n            var what = lhs is IdentifierExpr ? string.Format(\"variable '{0}'\", ((IdentifierExpr)lhs).Name) : \"LHS\";\n            CheckTypeArgsContainNoOrdinal(lhs.tok, lhs.Type);\n          }\n        } else if (stmt is CalcStmt) {\n          var s = (CalcStmt)stmt;\n          // The resolution of the calc statement builds up .Steps and .Result, which are of the form E0 OP E1, where\n          // E0 and E1 are expressions from .Lines.  These additional expressions still need to have their .ResolvedOp\n          // fields filled in, so we visit them (but not their subexpressions) here.\n          foreach (var e in s.Steps) {\n            Visit(e);\n          }\n          Visit(s.Result);\n        }\n      }\n      protected override void VisitOneExpr(Expression expr) {\n        if (expr is LiteralExpr) {\n          var e = (LiteralExpr)expr;\n          var t = e.Type as BitvectorType;\n          if (t != null) {\n            var n = (BigInteger)e.Value;\n            // check that the given literal fits into the bitvector width\n            if (BigInteger.Pow(2, t.Width) <= n) {\n              resolver.reporter.Error(MessageSource.Resolver, e.tok, \"bitvector literal ({0}) is too large for the type {1}\", e.Value, t);\n            }\n          }\n        } else if (expr is ComprehensionExpr) {\n          var e = (ComprehensionExpr)expr;\n          foreach (var bv in e.BoundVars) {\n            if (!IsDetermined(bv.Type.Normalize())) {\n              resolver.reporter.Error(MessageSource.Resolver, bv.tok, \"type of bound variable '{0}' could not be determined; please specify the type explicitly\", bv.Name);\n            } else if (codeContext is FixpointPredicate) {\n              CheckContainsNoOrdinal(bv.tok, bv.Type, string.Format(\"type of bound variable '{0}' is not allowed to use type ORDINAL\", bv.Name));\n            }\n          }\n          // apply bounds discovery to quantifiers, finite sets, and finite maps\n          string what = null;\n          Expression whereToLookForBounds = null;\n          var polarity = true;\n          if (e is QuantifierExpr) {\n            what = \"quantifier\";\n            whereToLookForBounds = ((QuantifierExpr)e).LogicalBody();\n            polarity = e is ExistsExpr;\n          } else if (e is SetComprehension) {\n            what = \"set comprehension\";\n            whereToLookForBounds = e.Range;\n          } else if (e is MapComprehension) {\n            what = \"map comprehension\";\n            whereToLookForBounds = e.Range;\n          } else {\n            Contract.Assume(e is LambdaExpr);  // otherwise, unexpected ComprehensionExpr\n          }\n          if (whereToLookForBounds != null) {\n            e.Bounds = DiscoverBestBounds_MultipleVars_AllowReordering(e.BoundVars, whereToLookForBounds, polarity, ComprehensionExpr.BoundedPool.PoolVirtues.None);\n            if (2 <= ArmadaOptions.O.Allocated && (codeContext is Function || codeContext is ConstantField || codeContext is RedirectingTypeDecl)) {\n              // functions are not allowed to depend on the set of allocated objects\n              foreach (var bv in ComprehensionExpr.BoundedPool.MissingBounds(e.BoundVars, e.Bounds, ComprehensionExpr.BoundedPool.PoolVirtues.IndependentOfAlloc)) {\n                var msgFormat = \"a {0} involved in a {3} definition is not allowed to depend on the set of allocated references; Dafny's heuristics can't figure out a bound for the values of '{1}'\";\n                if (bv.Type.IsTypeParameter) {\n                  var tp = bv.Type.AsTypeParameter;\n                  msgFormat += \" (perhaps declare its type, '{2}', as '{2}(!new)')\";\n                }\n                var declKind = codeContext is RedirectingTypeDecl ? ((RedirectingTypeDecl)codeContext).WhatKind : ((MemberDecl)codeContext).WhatKind;\n                resolver.reporter.Error(MessageSource.Resolver, e, msgFormat, what, bv.Name, bv.Type, declKind);\n              }\n            }\n            if ((e is SetComprehension && ((SetComprehension)e).Finite) || (e is MapComprehension && ((MapComprehension)e).Finite)) {\n              // the comprehension had better produce a finite set\n              if (e is SetComprehension && e.Type.HasFinitePossibleValues) {\n                // This means the set is finite, regardless of if the Range is bounded.  So, we don't give any error here.\n                // However, if this expression is used in a non-ghost context (which is not yet known at this stage of\n                // resolution), the resolver will generate an error about that later.\n              } else {\n                // we cannot be sure that the set/map really is finite\n                foreach (var bv in ComprehensionExpr.BoundedPool.MissingBounds(e.BoundVars, e.Bounds, ComprehensionExpr.BoundedPool.PoolVirtues.Finite)) {\n                  resolver.reporter.Error(MessageSource.Resolver, e, \"a {0} must produce a finite set, but Dafny's heuristics can't figure out how to produce a bounded set of values for '{1}'\", what, bv.Name);\n                }\n              }\n            }\n          }\n\n\n          if (e is ExistsExpr && e.Range == null) {\n            var binBody = ((ExistsExpr)e).Term as BinaryExpr;\n            if (binBody != null && binBody.Op == BinaryExpr.Opcode.Imp) {  // check Op, not ResolvedOp, in order to distinguish ==> and <==\n              // apply the wisdom of Claude Marche: issue a warning here\n              resolver.reporter.Warning(MessageSource.Resolver, e.tok,\n                \"the quantifier has the form 'exists x :: A ==> B', which most often is a typo for 'exists x :: A && B'; \" +\n                \"if you think otherwise, rewrite as 'exists x :: (A ==> B)' or 'exists x :: !A || B' to suppress this warning\");\n            }\n          }\n\n        } else if (expr is MemberSelectExpr) {\n          var e = (MemberSelectExpr)expr;\n          if (e.Member is Function || e.Member is Method) {\n            foreach (var p in e.TypeApplication) {\n              if (!IsDetermined(p.Normalize())) {\n                resolver.reporter.Error(MessageSource.Resolver, e.tok, \"type '{0}' to the {2} '{1}' is not determined\", p, e.Member.Name, e.Member.WhatKind);\n              } else {\n                CheckContainsNoOrdinal(e.tok, p, string.Format(\"type '{0}' to the {2} '{1}' is not allowed to use ORDINAL\", p, e.Member.Name, e.Member.WhatKind));\n              }\n            }\n          }\n        } else if (expr is FunctionCallExpr) {\n          var e = (FunctionCallExpr)expr;\n          foreach (var p in e.TypeArgumentSubstitutions) {\n            if (!IsDetermined(p.Value.Normalize())) {\n              resolver.reporter.Error(MessageSource.Resolver, e.tok, \"type variable '{0}' in the function call to '{1}' could not be determined{2}\", p.Key.Name, e.Name,\n                (e.Name.StartsWith(\"reveal_\"))\n                ? \". If you are making an opaque function, make sure that the function can be called.\"\n                : \"\"\n              );\n            } else {\n              CheckContainsNoOrdinal(e.tok, p.Value, string.Format(\"type argument to function call '{1}' (for type variable '{0}') is not allowed to use type ORDINAL\", p.Key.Name, e.Name));\n            }\n          }\n        } else if (expr is LetExpr) {\n          var e = (LetExpr)expr;\n          foreach (var p in e.LHSs) {\n            foreach (var x in p.Vars) {\n              if (!IsDetermined(x.Type.Normalize())) {\n                resolver.reporter.Error(MessageSource.Resolver, x.tok, \"the type of the bound variable '{0}' could not be determined\", x.Name);\n              } else {\n                CheckTypeArgsContainNoOrdinal(x.tok, x.Type);\n              }\n            }\n          }\n        } else if (expr is IdentifierExpr) {\n          // by specializing for IdentifierExpr, error messages will be clearer\n          CheckTypeIsDetermined(expr.tok, expr.Type, \"variable\");\n        } else if (CheckTypeIsDetermined(expr.tok, expr.Type, \"expression\")) {\n          if (expr is BinaryExpr) {\n            var e = (BinaryExpr)expr;\n            e.ResolvedOp = ResolveOp(e.Op, e.E1.Type);\n            // Check for useless comparisons with \"null\"\n            Expression other = null;  // if \"null\" if one of the operands, then \"other\" is the other\n            if (e.E0 is LiteralExpr && ((LiteralExpr)e.E0).Value == null) {\n              other = e.E1;\n            } else if (e.E1 is LiteralExpr && ((LiteralExpr)e.E1).Value == null) {\n              other = e.E0;\n            }\n            if (other != null) {\n              bool sense = true;\n              switch (e.ResolvedOp) {\n                case BinaryExpr.ResolvedOpcode.NeqCommon:\n                  sense = false;\n                  goto case BinaryExpr.ResolvedOpcode.EqCommon;\n                case BinaryExpr.ResolvedOpcode.EqCommon: {\n                    var nntUdf = other.Type.AsNonNullRefType;\n                    if (nntUdf != null) {\n                      string name = null;\n                      string hint = \"\";\n                      other = other.Resolved;\n                      if (other is IdentifierExpr) {\n                        name = string.Format(\"variable '{0}'\", ((IdentifierExpr)other).Name);\n                      } else if (other is MemberSelectExpr) {\n                        var field = ((MemberSelectExpr)other).Member as Field;\n                        // The type of the field may be a formal type parameter, in which case the hint is omitted\n                        if (field.Type.IsNonNullRefType) {\n                          name = string.Format(\"field '{0}'\", field.Name);\n                        }\n                      }\n                      if (name != null) {\n                        // The following relies on that a NonNullTypeDecl has a .Rhs that is a\n                        // UserDefinedType denoting the possibly null type declaration and that\n                        // these two types have the same number of type arguments.\n                        var nonNullTypeDecl = (NonNullTypeDecl)nntUdf.ResolvedClass;\n                        var possiblyNullUdf = (UserDefinedType)nonNullTypeDecl.Rhs;\n                        var possiblyNullTypeDecl = (ClassDecl)possiblyNullUdf.ResolvedClass;\n                        Contract.Assert(nonNullTypeDecl.TypeArgs.Count == possiblyNullTypeDecl.TypeArgs.Count);\n                        Contract.Assert(nonNullTypeDecl.TypeArgs.Count == nntUdf.TypeArgs.Count);\n                        var ty = new UserDefinedType(nntUdf.tok, possiblyNullUdf.Name, possiblyNullTypeDecl, nntUdf.TypeArgs);\n\n                        hint = string.Format(\" (to make it possible for {0} to have the value 'null', declare its type to be '{1}')\", name, ty);\n                      }\n                      resolver.reporter.Warning(MessageSource.Resolver, e.tok,\n                        string.Format(\"the type of the other operand is a non-null type, so this comparison with 'null' will always return '{0}'{1}\",\n                        sense ? \"false\" : \"true\", hint));\n                    }\n                    break;\n                  }\n                case BinaryExpr.ResolvedOpcode.NotInSet:\n                case BinaryExpr.ResolvedOpcode.NotInSeq:\n                case BinaryExpr.ResolvedOpcode.NotInMultiSet:\n                  sense = false;\n                  goto case BinaryExpr.ResolvedOpcode.InSet;\n                case BinaryExpr.ResolvedOpcode.InSet:\n                case BinaryExpr.ResolvedOpcode.InSeq:\n                case BinaryExpr.ResolvedOpcode.InMultiSet: {\n                    var ty = other.Type.NormalizeExpand();\n                    var what = ty is SetType ? \"set\" : ty is SeqType ? \"seq\" : \"multiset\";\n                    if (((CollectionType)ty).Arg.IsNonNullRefType) {\n                      resolver.reporter.Warning(MessageSource.Resolver, e.tok,\n                        string.Format(\"the type of the other operand is a {0} of non-null elements, so the {1}inclusion test of 'null' will always return '{2}'\",\n                        what, sense ? \"\" : \"non-\", sense ? \"false\" : \"true\"));\n                    }\n                    break;\n                  }\n                case BinaryExpr.ResolvedOpcode.NotInMap:\n                  goto case BinaryExpr.ResolvedOpcode.InMap;\n                case BinaryExpr.ResolvedOpcode.InMap: {\n                    var ty = other.Type.NormalizeExpand();\n                    if (((MapType)ty).Domain.IsNonNullRefType) {\n                      resolver.reporter.Warning(MessageSource.Resolver, e.tok,\n                        string.Format(\"the type of the other operand is a map to a non-null type, so the inclusion test of 'null' will always return '{0}'\",\n                        sense ? \"false\" : \"true\"));\n                    }\n                    break;\n                  }\n                default:\n                  break;\n              }\n            }\n          } else if (expr is NegationExpression) {\n            var e = (NegationExpression)expr;\n            Expression zero;\n            if (e.E.Type.IsNumericBased(Type.NumericPersuation.Real)) {\n              zero = new LiteralExpr(e.tok, BaseTypes.BigDec.ZERO);\n            } else {\n              Contract.Assert(e.E.Type.IsNumericBased(Type.NumericPersuation.Int) || e.E.Type.IsBitVectorType);\n              zero = new LiteralExpr(e.tok, 0);\n            }\n            zero.Type = expr.Type;\n            var subtract = new BinaryExpr(e.tok, BinaryExpr.Opcode.Sub, zero, e.E);\n            subtract.Type = expr.Type;\n            subtract.ResolvedOp = BinaryExpr.ResolvedOpcode.Sub;\n            e.ResolvedExpression = subtract;\n          }\n        }\n      }\n      public static bool IsDetermined(Type t) {\n        Contract.Requires(t != null);\n        Contract.Requires(!(t is TypeProxy) || ((TypeProxy)t).T == null);\n        // all other proxies indicate the type has not yet been determined, provided their type parameters have been\n        return !(t is TypeProxy) && t.TypeArgs.All(tt => IsDetermined(tt.Normalize()));\n      }\n      ISet<TypeProxy> UnderspecifiedTypeProxies = new HashSet<TypeProxy>();\n      public bool CheckTypeIsDetermined(IToken tok, Type t, string what) {\n        Contract.Requires(tok != null);\n        Contract.Requires(t != null);\n        Contract.Requires(what != null);\n        t = t.NormalizeExpand();\n\n        if (t is TypeProxy) {\n          var proxy = (TypeProxy)t;\n          if (!UnderspecifiedTypeProxies.Contains(proxy)) {\n            // report an error for this TypeProxy only once\n            resolver.reporter.Error(MessageSource.Resolver, tok, \"the type of this {0} is underspecified\", what);\n            UnderspecifiedTypeProxies.Add(proxy);\n          }\n          return false;\n        }\n        // Recurse on type arguments:\n        return t.TypeArgs.All(rg => CheckTypeIsDetermined(tok, rg, what));\n      }\n      public void CheckTypeArgsContainNoOrdinal(IToken tok, Type t) {\n        Contract.Requires(tok != null);\n        Contract.Requires(t != null);\n        t = t.NormalizeExpand();\n        t.TypeArgs.Iter(rg => CheckContainsNoOrdinal(tok, rg, \"an ORDINAL type is not allowed to be used as a type argument\"));\n      }\n      public void CheckContainsNoOrdinal(IToken tok, Type t, string errMsg) {\n        Contract.Requires(tok != null);\n        Contract.Requires(t != null);\n        Contract.Requires(errMsg != null);\n        t = t.NormalizeExpand();\n        if (t.IsBigOrdinalType) {\n          resolver.reporter.Error(MessageSource.Resolver, tok, errMsg);\n        }\n        t.TypeArgs.Iter(rg => CheckContainsNoOrdinal(tok, rg, errMsg));\n      }\n    }\n#endregion CheckTypeInference\n\n    // ------------------------------------------------------------------------------------------------------\n    // ----- CheckExpression --------------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------------------------\n#region CheckExpression\n    /// <summary>\n    /// This method computes ghost interests in the statement portion of StmtExpr's and\n    /// checks for hint restrictions in any CalcStmt.\n    /// </summary>\n    void CheckExpression(Expression expr, Resolver resolver, ICodeContext codeContext) {\n      Contract.Requires(expr != null);\n      Contract.Requires(resolver != null);\n      Contract.Requires(codeContext != null);\n      var v = new CheckExpression_Visitor(resolver, codeContext);\n      v.Visit(expr);\n    }\n    /// <summary>\n    /// This method computes ghost interests in the statement portion of StmtExpr's and\n    /// checks for hint restrictions in any CalcStmt.\n    /// </summary>\n    void CheckExpression(Statement stmt, Resolver resolver, ICodeContext codeContext) {\n      Contract.Requires(stmt != null);\n      Contract.Requires(resolver != null);\n      Contract.Requires(codeContext != null);\n      var v = new CheckExpression_Visitor(resolver, codeContext);\n      v.Visit(stmt);\n    }\n    class CheckExpression_Visitor : ResolverBottomUpVisitor\n    {\n      readonly ICodeContext CodeContext;\n      public CheckExpression_Visitor(Resolver resolver, ICodeContext codeContext)\n        : base(resolver) {\n        Contract.Requires(resolver != null);\n        Contract.Requires(codeContext != null);\n        CodeContext = codeContext;\n      }\n      protected override void VisitOneExpr(Expression expr) {\n        if (expr is StmtExpr) {\n          var e = (StmtExpr)expr;\n          resolver.ComputeGhostInterest(e.S, true, CodeContext);\n        }\n      }\n      protected override void VisitOneStmt(Statement stmt) {\n        if (stmt is CalcStmt) {\n          var s = (CalcStmt)stmt;\n          foreach (var h in s.Hints) {\n            resolver.CheckHintRestrictions(h, new HashSet<LocalVariable>());\n          }\n        }\n      }\n    }\n#endregion\n\n    // ------------------------------------------------------------------------------------------------------\n    // ----- CheckTailRecursive -----------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------------------------\n#region CheckTailRecursive\n    enum TailRecursionStatus\n    {\n      NotTailRecursive, // contains code that makes the enclosing method body not tail recursive (in way that is supported)\n      CanBeFollowedByAnything, // the code just analyzed does not do any recursive calls\n      TailCallSpent, // the method body is tail recursive, provided that all code that follows it in the method body is ghost\n    }\n\n    /// <summary>\n    /// Checks if \"stmts\" can be considered tail recursive, and (provided \"reportsError\" is true) reports an error if not.\n    /// Note, the current implementation is rather conservative in its analysis; upon need, the\n    /// algorithm could be improved.\n    /// In the current implementation, \"enclosingMethod\" is not allowed to be a mutually recursive method.\n    ///\n    /// The incoming value of \"tailCall\" is not used, but it's nevertheless a 'ref' parameter to allow the\n    /// body to return the incoming value or to omit assignments to it.\n    /// If the return value is CanBeFollowedByAnything, \"tailCall\" is unchanged.\n    /// If the return value is TailCallSpent, \"tailCall\" shows one of the calls where the tail call was spent.  (Note,\n    /// there could be several if the statements have branches.)\n    /// If the return value is NoTailRecursive, \"tailCall\" could be anything.  In this case, an error\n    /// message has been reported (provided \"reportsErrors\" is true).\n    /// </summary>\n    TailRecursionStatus CheckTailRecursive(List<Statement> stmts, Method enclosingMethod, ref CallStmt tailCall, bool reportErrors) {\n      Contract.Requires(stmts != null);\n      var status = TailRecursionStatus.CanBeFollowedByAnything;\n      foreach (var s in stmts) {\n        if (!s.IsGhost) {\n          if (s is ReturnStmt && ((ReturnStmt)s).hiddenUpdate == null) {\n            return status;\n          }\n          if (status == TailRecursionStatus.TailCallSpent) {\n            // a tail call cannot be followed by non-ghost code\n            if (reportErrors) {\n              reporter.Error(MessageSource.Resolver, tailCall.Tok, \"this recursive call is not recognized as being tail recursive, because it is followed by non-ghost code\");\n            }\n            return TailRecursionStatus.NotTailRecursive;\n          }\n          status = CheckTailRecursive(s, enclosingMethod, ref tailCall, reportErrors);\n          if (status == TailRecursionStatus.NotTailRecursive) {\n            return status;\n          }\n        }\n      }\n      return status;\n    }\n\n    void DetermineTailRecursion(Function f) {\n      Contract.Requires(f != null);\n      bool tail = true;\n      if (Attributes.ContainsBool(f.Attributes, \"tailrecursion\", ref tail) && tail) {\n        reporter.Error(MessageSource.Resolver, f.tok, \"sorry, tail-call functions are not supported\");\n      }\n    }\n\n    void DetermineTailRecursion(Method m) {\n      Contract.Requires(m != null);\n      bool tail = true;\n      bool hasTailRecursionPreference = Attributes.ContainsBool(m.Attributes, \"tailrecursion\", ref tail);\n      if (hasTailRecursionPreference && !tail) {\n        // the user specifically requested no tail recursion, so do nothing else\n      } else if (hasTailRecursionPreference && tail && m.IsGhost) {\n        reporter.Error(MessageSource.Resolver, m.tok, \"tail recursion can be specified only for methods that will be compiled, not for ghost methods\");\n      } else {\n        var module = m.EnclosingClass.Module;\n        var sccSize = module.CallGraph.GetSCCSize(m);\n        if (hasTailRecursionPreference && 2 <= sccSize) {\n          reporter.Error(MessageSource.Resolver, m.tok, \"sorry, tail-call optimizations are not supported for mutually recursive methods\");\n        } else if (hasTailRecursionPreference || sccSize == 1) {\n          CallStmt tailCall = null;\n          var status = CheckTailRecursive(m.Body.Body, m, ref tailCall, hasTailRecursionPreference);\n          if (status != TailRecursionStatus.NotTailRecursive) {\n            m.IsTailRecursive = true;\n            if (tailCall != null) {\n              // this means there was at least one recursive call\n              reporter.Info(MessageSource.Resolver, m.tok, \"tail recursive\");\n            }\n          }\n        }\n      }\n    }\n\n    /// <summary>\n    /// See CheckTailRecursive(List Statement, ...), including its description of \"tailCall\".\n    /// In the current implementation, \"enclosingMethod\" is not allowed to be a mutually recursive method.\n    /// </summary>\n    TailRecursionStatus CheckTailRecursive(Statement stmt, Method enclosingMethod, ref CallStmt tailCall, bool reportErrors) {\n      Contract.Requires(stmt != null);\n      if (stmt.IsGhost) {\n        return TailRecursionStatus.NotTailRecursive;\n      }\n      if (stmt is PrintStmt) {\n      } else if (stmt is RevealStmt) {\n        var s = (RevealStmt)stmt;\n        return CheckTailRecursive(s.ResolvedStatements, enclosingMethod, ref tailCall, reportErrors);\n      } else if (stmt is SomehowStmt) {\n      } else if (stmt is FenceStmt) {\n      } else if (stmt is GotoStmt) {\n      } else if (stmt is DeallocStmt) {\n      } else if (stmt is JoinStmt) {\n      } else if (stmt is BreakStmt) {\n      } else if (stmt is ContinueStmt) {\n      } else if (stmt is ReturnStmt) {\n        var s = (ReturnStmt)stmt;\n        if (s.hiddenUpdate != null) {\n          return CheckTailRecursive(s.hiddenUpdate, enclosingMethod, ref tailCall, reportErrors);\n        }\n      } else if (stmt is AssignStmt) {\n        var s = (AssignStmt)stmt;\n        var tRhs = s.Rhs as TypeRhs;\n        if (tRhs != null && tRhs.InitCall != null && tRhs.InitCall.Method == enclosingMethod) {\n          // It's a recursive call.  However, it is not a tail call, because after the \"new\" allocation\n          // and init call have taken place, the newly allocated object has yet to be assigned to\n          // the LHS of the assignment statement.\n          if (reportErrors) {\n            reporter.Error(MessageSource.Resolver, tRhs.InitCall.Tok,\n              \"the recursive call to '{0}' is not tail recursive, because the assignment of the LHS happens after the call\",\n              tRhs.InitCall.Method.Name);\n          }\n          return TailRecursionStatus.NotTailRecursive;\n        }\n      } else if (stmt is ModifyStmt) {\n        var s = (ModifyStmt)stmt;\n        if (s.Body != null) {\n          return CheckTailRecursive(s.Body, enclosingMethod, ref tailCall, reportErrors);\n        }\n      } else if (stmt is CallStmt) {\n        var s = (CallStmt)stmt;\n        if (s.Method == enclosingMethod) {\n          // It's a recursive call.  It can be considered a tail call only if the LHS of the call are the\n          // formal out-parameters of the method\n          for (int i = 0; i < s.Lhs.Count; i++) {\n            var formal = enclosingMethod.Outs[i];\n            if (!formal.IsGhost) {\n              var lhs = s.Lhs[i] as IdentifierExpr;\n              if (lhs != null && lhs.Var == formal) {\n                // all is good\n              } else {\n                if (reportErrors) {\n                  reporter.Error(MessageSource.Resolver, s.Tok,\n                    \"the recursive call to '{0}' is not tail recursive because the actual out-parameter{1} is not the formal out-parameter '{2}'\",\n                    s.Method.Name, s.Lhs.Count == 1 ? \"\" : \" \" + i, formal.Name);\n                }\n                return TailRecursionStatus.NotTailRecursive;\n              }\n            }\n          }\n          // Moreover, it can be considered a tail recursive call only if the type parameters are the same\n          // as in the caller.\n          var classTypeParameterCount = s.Method.EnclosingClass.TypeArgs.Count;\n          Contract.Assert(s.MethodSelect.TypeApplication.Count == classTypeParameterCount + s.Method.TypeArgs.Count);\n          for (int i = 0; i < s.Method.TypeArgs.Count; i++) {\n            var formal = s.Method.TypeArgs[i];\n            var actual = s.MethodSelect.TypeApplication[classTypeParameterCount + i].AsTypeParameter;\n            if (formal != actual) {\n              if (reportErrors) {\n                reporter.Error(MessageSource.Resolver, s.Tok,\n                  \"the recursive call to '{0}' is not tail recursive because the actual type parameter{1} is not the formal type parameter '{2}'\",\n                  s.Method.Name, s.Method.TypeArgs.Count == 1 ? \"\" : \" \" + i, formal.Name);\n              }\n              return TailRecursionStatus.NotTailRecursive;\n            }\n          }\n          tailCall = s;\n          return TailRecursionStatus.TailCallSpent;\n        }\n      } else if (stmt is BlockStmt) {\n        var s = (BlockStmt)stmt;\n        return CheckTailRecursive(s.Body, enclosingMethod, ref tailCall, reportErrors);\n      } else if (stmt is IfStmt) {\n        var s = (IfStmt)stmt;\n        var stThen = CheckTailRecursive(s.Thn, enclosingMethod, ref tailCall, reportErrors);\n        if (stThen == TailRecursionStatus.NotTailRecursive) {\n          return stThen;\n        }\n        var stElse = s.Els == null ? TailRecursionStatus.CanBeFollowedByAnything : CheckTailRecursive(s.Els, enclosingMethod, ref tailCall, reportErrors);\n        if (stElse == TailRecursionStatus.NotTailRecursive) {\n          return stElse;\n        } else if (stThen == TailRecursionStatus.TailCallSpent || stElse == TailRecursionStatus.TailCallSpent) {\n          return TailRecursionStatus.TailCallSpent;\n        }\n      } else if (stmt is AlternativeStmt) {\n        var s = (AlternativeStmt)stmt;\n        var status = TailRecursionStatus.CanBeFollowedByAnything;\n        foreach (var alt in s.Alternatives) {\n          var st = CheckTailRecursive(alt.Body, enclosingMethod, ref tailCall, reportErrors);\n          if (st == TailRecursionStatus.NotTailRecursive) {\n            return st;\n          } else if (st == TailRecursionStatus.TailCallSpent) {\n            status = st;\n          }\n        }\n        return status;\n      } else if (stmt is WhileStmt) {\n        var s = (WhileStmt)stmt;\n        var status = TailRecursionStatus.NotTailRecursive;\n        if (s.Body != null) {\n          status = CheckTailRecursive(s.Body, enclosingMethod, ref tailCall, reportErrors);\n        }\n        if (status != TailRecursionStatus.CanBeFollowedByAnything) {\n          if (status == TailRecursionStatus.NotTailRecursive) {\n            // an error has already been reported\n          } else if (reportErrors) {\n            reporter.Error(MessageSource.Resolver, tailCall.Tok, \"a recursive call inside a loop is not recognized as being a tail call\");\n          }\n          return TailRecursionStatus.NotTailRecursive;\n        }\n      } else if (stmt is AlternativeLoopStmt) {\n        var s = (AlternativeLoopStmt)stmt;\n        foreach (var alt in s.Alternatives) {\n          var status = CheckTailRecursive(alt.Body, enclosingMethod, ref tailCall, reportErrors);\n          if (status != TailRecursionStatus.CanBeFollowedByAnything) {\n            if (status == TailRecursionStatus.NotTailRecursive) {\n              // an error has already been reported\n            } else if (reportErrors) {\n              reporter.Error(MessageSource.Resolver, tailCall.Tok, \"a recursive call inside a loop is not recognized as being a tail call\");\n            }\n            return TailRecursionStatus.NotTailRecursive;\n          }\n        }\n      } else if (stmt is ForallStmt) {\n        var s = (ForallStmt)stmt;\n        var status = TailRecursionStatus.NotTailRecursive;\n        if (s.Body != null) {\n          status = CheckTailRecursive(s.Body, enclosingMethod, ref tailCall, reportErrors);\n        }\n        if (status != TailRecursionStatus.CanBeFollowedByAnything) {\n          if (status == TailRecursionStatus.NotTailRecursive) {\n            // an error has already been reported\n          } else if (reportErrors) {\n            reporter.Error(MessageSource.Resolver, tailCall.Tok, \"a recursive call inside a forall statement is not a tail call\");\n          }\n          return TailRecursionStatus.NotTailRecursive;\n        }\n      } else if (stmt is MatchStmt) {\n        var s = (MatchStmt)stmt;\n        var status = TailRecursionStatus.CanBeFollowedByAnything;\n        foreach (var kase in s.Cases) {\n          var st = CheckTailRecursive(kase.Body, enclosingMethod, ref tailCall, reportErrors);\n          if (st == TailRecursionStatus.NotTailRecursive) {\n            return st;\n          } else if (st == TailRecursionStatus.TailCallSpent) {\n            status = st;\n          }\n        }\n        return status;\n      } else if (stmt is AssignSuchThatStmt) {\n      } else if (stmt is AssignOrReturnStmt) {\n        // TODO this should be the conservative choice, but probably we can consider this to be tail-recursive\n        // under some conditions? However, how does this interact with compiling to exceptions?\n        return TailRecursionStatus.NotTailRecursive;\n      } else if (stmt is UpdateStmt) {\n        var s = (UpdateStmt)stmt;\n        return CheckTailRecursive(s.ResolvedStatements, enclosingMethod, ref tailCall, reportErrors);\n      } else if (stmt is VarDeclStmt) {\n        var s = (VarDeclStmt)stmt;\n        if (s.Update != null) {\n          return CheckTailRecursive(s.Update, enclosingMethod, ref tailCall, reportErrors);\n        }\n      } else if (stmt is LetStmt) {\n      } else if (stmt is YieldStmt) {\n      } else {\n        Contract.Assert(false);  // unexpected statement type\n      }\n      return TailRecursionStatus.CanBeFollowedByAnything;\n    }\n#endregion CheckTailRecursive\n\n    // ------------------------------------------------------------------------------------------------------\n    // ----- FuelAdjustmentChecks ---------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------------------------\n#region FuelAdjustmentChecks\n\n    protected void CheckForFuelAdjustments(IToken tok, Attributes attrs, ModuleDefinition currentModule) {\n      List<List<Expression>> results = Attributes.FindAllExpressions(attrs, \"fuel\");\n\n      if (results != null) {\n        foreach (List<Expression> args in results) {\n          if (args != null && args.Count >= 2) {\n            // Try to extract the function from the first argument\n            MemberSelectExpr selectExpr = args[0].Resolved as MemberSelectExpr;\n            if (selectExpr != null) {\n              Function f = selectExpr.Member as Function;\n              if (f != null) {\n                f.IsFueled = true;\n                if (f.IsProtected && currentModule != f.EnclosingClass.Module) {\n                  reporter.Error(MessageSource.Resolver, tok, \"cannot adjust fuel for protected function {0} from another module\", f.Name);\n                }\n                if (args.Count >= 3) {\n                  LiteralExpr literalLow = args[1] as LiteralExpr;\n                  LiteralExpr literalHigh = args[2] as LiteralExpr;\n                  if (literalLow != null && literalLow.Value is BigInteger && literalHigh != null && literalHigh.Value is BigInteger) {\n                    BigInteger low = (BigInteger)literalLow.Value;\n                    BigInteger high = (BigInteger)literalHigh.Value;\n                    if (!(high == low + 1 || (low == 0 && high == 0))) {\n                      reporter.Error(MessageSource.Resolver, tok, \"fuel setting for function {0} must have high value == 1 + low value\", f.Name);\n                    }\n                  }\n                }\n              }\n            }\n          }\n        }\n      }\n    }\n\n    public class FuelAdjustment_Context\n    {\n      public ModuleDefinition currentModule;\n      public FuelAdjustment_Context(ModuleDefinition currentModule) {\n        this.currentModule = currentModule;\n      }\n    }\n\n    class FuelAdjustment_Visitor : ResolverTopDownVisitor<FuelAdjustment_Context>\n    {\n      public FuelAdjustment_Visitor(Resolver resolver)\n        : base(resolver) {\n        Contract.Requires(resolver != null);\n      }\n\n      protected override bool VisitOneStmt(Statement stmt, ref FuelAdjustment_Context st) {\n        resolver.CheckForFuelAdjustments(stmt.Tok, stmt.Attributes, st.currentModule);\n        return true;\n      }\n    }\n\n#endregion FuelAdjustmentChecks\n\n    // ------------------------------------------------------------------------------------------------------\n    // ----- FixpointPredicateChecks ------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------------------------\n#region FixpointPredicateChecks\n    enum CallingPosition { Positive, Negative, Neither }\n    static CallingPosition Invert(CallingPosition cp) {\n      switch (cp) {\n        case CallingPosition.Positive: return CallingPosition.Negative;\n        case CallingPosition.Negative: return CallingPosition.Positive;\n        default: return CallingPosition.Neither;\n      }\n    }\n\n    class FindFriendlyCalls_Visitor : ResolverTopDownVisitor<CallingPosition>\n    {\n      public readonly bool IsCoContext;\n      public readonly bool ContinuityIsImportant;\n      public FindFriendlyCalls_Visitor(Resolver resolver, bool co, bool continuityIsImportant)\n        : base(resolver)\n      {\n        Contract.Requires(resolver != null);\n        this.IsCoContext = co;\n        this.ContinuityIsImportant = continuityIsImportant;\n      }\n\n      protected override bool VisitOneExpr(Expression expr, ref CallingPosition cp) {\n        if (expr is UnaryOpExpr) {\n          var e = (UnaryOpExpr)expr;\n          if (e.Op == UnaryOpExpr.Opcode.Not) {\n            // for the sub-parts, use Invert(cp)\n            cp = Invert(cp);\n            return true;\n          }\n        } else if (expr is BinaryExpr) {\n          var e = (BinaryExpr)expr;\n          switch (e.ResolvedOp) {\n            case BinaryExpr.ResolvedOpcode.And:\n            case BinaryExpr.ResolvedOpcode.Or:\n              return true;  // do the sub-parts with the same \"cp\"\n            case BinaryExpr.ResolvedOpcode.Imp:\n              Visit(e.E0, Invert(cp));\n              Visit(e.E1, cp);\n              return false;  // don't recurse (again) on the sub-parts\n            default:\n              break;\n          }\n        } else if (expr is MatchExpr) {\n          var e = (MatchExpr)expr;\n          Visit(e.Source, CallingPosition.Neither);\n          var theCp = cp;\n          e.Cases.Iter(kase => Visit(kase.Body, theCp));\n          return false;\n        } else if (expr is ITEExpr) {\n          var e = (ITEExpr)expr;\n          Visit(e.Test, CallingPosition.Neither);\n          Visit(e.Thn, cp);\n          Visit(e.Els, cp);\n          return false;\n        } else if (expr is LetExpr) {\n          var e = (LetExpr)expr;\n          foreach (var rhs in e.RHSs) {\n            Visit(rhs, CallingPosition.Neither);\n          }\n          var cpBody = cp;\n          if (!e.Exact) {\n            // a let-such-that expression introduces an existential that may depend on the _k in an inductive/co predicate, so we disallow recursive calls in the body of the let-such-that\n            if (IsCoContext && cp == CallingPosition.Positive) {\n              cpBody = CallingPosition.Neither;\n            } else if (!IsCoContext && cp == CallingPosition.Negative) {\n              cpBody = CallingPosition.Neither;\n            }\n          }\n          Visit(e.Body, cpBody);\n          return false;\n        } else if (expr is QuantifierExpr) {\n          var e = (QuantifierExpr)expr;\n          Contract.Assert(e.SplitQuantifier == null); // No split quantifiers during resolution\n          var cpos = IsCoContext ? cp : Invert(cp);\n          if (ContinuityIsImportant) {\n            if ((cpos == CallingPosition.Positive && e is ExistsExpr) || (cpos == CallingPosition.Negative && e is ForallExpr)) {\n              if (e.Bounds.Exists(bnd => bnd == null || (bnd.Virtues & ComprehensionExpr.BoundedPool.PoolVirtues.Finite) == 0)) {\n                // To ensure continuity of fixpoint predicates, don't allow calls under an existential (resp. universal) quantifier\n                // for co-predicates (resp. inductive predicates).\n                cp = CallingPosition.Neither;\n              }\n            }\n          }\n          Visit(e.LogicalBody(), cp);\n          return false;\n        } else if (expr is StmtExpr) {\n          var e = (StmtExpr)expr;\n          Visit(e.E, cp);\n          Visit(e.S, CallingPosition.Neither);\n          return false;\n        } else if (expr is ConcreteSyntaxExpression) {\n          // do the sub-parts with the same \"cp\"\n          return true;\n        }\n        // do the sub-parts with cp := Neither\n        cp = CallingPosition.Neither;\n        return true;\n      }\n    }\n\n\n    void KNatMismatchError(IToken tok, string contextName, FixpointPredicate.KType contextK, FixpointPredicate.KType calleeK) {\n      var hint = contextK == FixpointPredicate.KType.Unspecified ? string.Format(\" (perhaps try declaring '{0}' as '{0}[nat]')\", contextName) : \"\";\n      reporter.Error(MessageSource.Resolver, tok,\n        \"this call does not type check, because the context uses a _k parameter of type {0} whereas the callee uses a _k parameter of type {1}{2}\",\n        contextK == FixpointPredicate.KType.Nat ? \"nat\" : \"ORDINAL\",\n        calleeK == FixpointPredicate.KType.Nat ? \"nat\" : \"ORDINAL\",\n        hint);\n    }\n\n    class FixpointPredicateChecks_Visitor : FindFriendlyCalls_Visitor\n    {\n      readonly FixpointPredicate context;\n      public FixpointPredicateChecks_Visitor(Resolver resolver, FixpointPredicate context)\n        : base(resolver, context is CoPredicate, context.KNat) {\n        Contract.Requires(resolver != null);\n        Contract.Requires(context != null);\n        this.context = context;\n      }\n      protected override bool VisitOneExpr(Expression expr, ref CallingPosition cp) {\n        if (expr is FunctionCallExpr) {\n          var e = (FunctionCallExpr)expr;\n          if (ModuleDefinition.InSameSCC(context, e.Function)) {\n            var article = context is InductivePredicate ? \"an\" : \"a\";\n            // we're looking at a recursive call\n            if (!(context is InductivePredicate ? e.Function is InductivePredicate : e.Function is CoPredicate)) {\n              resolver.reporter.Error(MessageSource.Resolver, e, \"a recursive call from {0} {1} can go only to other {1}s\", article, context.WhatKind);\n            } else if (context.KNat != ((FixpointPredicate)e.Function).KNat) {\n              resolver.KNatMismatchError(e.tok, context.Name, context.TypeOfK, ((FixpointPredicate)e.Function).TypeOfK);\n            } else if (cp != CallingPosition.Positive) {\n              var msg = string.Format(\"{0} {1} can be called recursively only in positive positions\", article, context.WhatKind);\n              if (ContinuityIsImportant && cp == CallingPosition.Neither) {\n                // this may be inside an non-friendly quantifier\n                msg += string.Format(\" and cannot sit inside an unbounded {0} quantifier\", context is InductivePredicate ? \"universal\" : \"existential\");\n              } else {\n                // we don't care about the continuity restriction or\n                // the fixpoint-call is not inside an quantifier, so don't bother mentioning the part of existentials/universals in the error message\n              }\n              resolver.reporter.Error(MessageSource.Resolver, e, msg);\n            } else {\n              e.CoCall = FunctionCallExpr.CoCallResolution.Yes;\n              resolver.reporter.Info(MessageSource.Resolver, e.tok, e.Function.Name + \"#[_k - 1]\");\n            }\n          }\n          // do the sub-parts with cp := Neither\n          cp = CallingPosition.Neither;\n          return true;\n        }\n        return base.VisitOneExpr(expr, ref cp);\n      }\n      protected override bool VisitOneStmt(Statement stmt, ref CallingPosition st) {\n        if (stmt is CallStmt) {\n          var s = (CallStmt)stmt;\n          if (ModuleDefinition.InSameSCC(context, s.Method)) {\n            // we're looking at a recursive call\n            var article = context is InductivePredicate ? \"an\" : \"a\";\n            resolver.reporter.Error(MessageSource.Resolver, stmt.Tok, \"a recursive call from {0} {1} can go only to other {1}s\", article, context.WhatKind);\n          }\n          // do the sub-parts with the same \"cp\"\n          return true;\n        } else {\n          return base.VisitOneStmt(stmt, ref st);\n        }\n      }\n    }\n\n    void FixpointPredicateChecks(Expression expr, FixpointPredicate context, CallingPosition cp) {\n      Contract.Requires(expr != null);\n      Contract.Requires(context != null);\n      var v = new FixpointPredicateChecks_Visitor(this, context);\n      v.Visit(expr, cp);\n    }\n#endregion FixpointPredicateChecks\n\n    // ------------------------------------------------------------------------------------------------------\n    // ----- FixpointLemmaChecks ----------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------------------------\n#region FixpointLemmaChecks\n    class FixpointLemmaChecks_Visitor : ResolverBottomUpVisitor\n    {\n      FixpointLemma context;\n      public FixpointLemmaChecks_Visitor(Resolver resolver, FixpointLemma context)\n        : base(resolver) {\n        Contract.Requires(resolver != null);\n        Contract.Requires(context != null);\n        this.context = context;\n      }\n      protected override void VisitOneStmt(Statement stmt) {\n        if (stmt is CallStmt) {\n          var s = (CallStmt)stmt;\n          if (s.Method is FixpointLemma || s.Method is PrefixLemma) {\n            // all is cool\n          } else {\n            // the call goes from a fixpoint-lemma context to a non-fixpoint-lemma callee\n            if (ModuleDefinition.InSameSCC(context, s.Method)) {\n              // we're looking at a recursive call (to a non-fixpoint-lemma)\n              var article = context is InductiveLemma ? \"an\" : \"a\";\n              resolver.reporter.Error(MessageSource.Resolver, s.Tok, \"a recursive call from {0} {1} can go only to other {1}s and prefix lemmas\", article, context.WhatKind);\n            }\n          }\n        }\n      }\n      protected override void VisitOneExpr(Expression expr)\n      {\n        if (expr is FunctionCallExpr) {\n          var e = (FunctionCallExpr)expr;\n          // the call goes from a colemma context to a non-colemma callee\n          if (ModuleDefinition.InSameSCC(context, e.Function)) {\n            // we're looking at a recursive call (to a non-colemma)\n            resolver.reporter.Error(MessageSource.Resolver, e.tok, \"a recursive call from a colemma can go only to other colemmas and prefix lemmas\");\n          }\n        }\n      }\n    }\n    void FixpointLemmaChecks(Statement stmt, FixpointLemma context) {\n      Contract.Requires(stmt != null);\n      Contract.Requires(context != null);\n      var v = new FixpointLemmaChecks_Visitor(this, context);\n      v.Visit(stmt);\n    }\n#endregion FixpointLemmaChecks\n\n    // ------------------------------------------------------------------------------------------------------\n    // ----- CheckEqualityTypes -----------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------------------------\n#region CheckEqualityTypes\n    class CheckEqualityTypes_Visitor : ResolverTopDownVisitor<bool>\n    {\n      public CheckEqualityTypes_Visitor(Resolver resolver)\n        : base(resolver) {\n        Contract.Requires(resolver != null);\n      }\n      protected override bool VisitOneStmt(Statement stmt, ref bool st) {\n        if (stmt.IsGhost) {\n          return false;  // no need to recurse to sub-parts, since all sub-parts must be ghost as well\n        } else if (stmt is VarDeclStmt) {\n          var s = (VarDeclStmt)stmt;\n          foreach (var v in s.Locals) {\n            if (!v.IsGhost) {\n              CheckEqualityTypes_Type(v.Tok, v.Type);\n            }\n          }\n        } else if (stmt is LetStmt) {\n          var s = (LetStmt)stmt;\n          foreach (var v in s.LocalVars) {\n            CheckEqualityTypes_Type(v.Tok, v.Type);\n          }\n        } else if (stmt is AssignStmt) {\n          var s = (AssignStmt)stmt;\n          var tRhs = s.Rhs as TypeRhs;\n          if (tRhs != null && tRhs.Type is UserDefinedType) {\n            var udt = (UserDefinedType)tRhs.Type;\n            var formalTypeArgs = udt.ResolvedClass.TypeArgs;\n            var actualTypeArgs = tRhs.Type.TypeArgs;\n            Contract.Assert(formalTypeArgs.Count == actualTypeArgs.Count);\n            var i = 0;\n            foreach (var argType in actualTypeArgs) {\n              var formalTypeArg = formalTypeArgs[i];\n              string whatIsWrong, hint;\n              if (!CheckCharacteristics(formalTypeArg.Characteristics, argType, out whatIsWrong, out hint)) {\n                resolver.reporter.Error(MessageSource.Resolver, tRhs.Tok, \"type parameter{0} ({1}) passed to type {2} must support {4} (got {3}){5}\",\n                  actualTypeArgs.Count == 1 ? \"\" : \" \" + i, formalTypeArg.Name, udt.ResolvedClass.Name, argType, whatIsWrong, hint);\n              }\n              CheckEqualityTypes_Type(tRhs.Tok, argType);\n              i++;\n            }\n          }\n        } else if (stmt is WhileStmt) {\n          var s = (WhileStmt)stmt;\n          // don't recurse on the specification parts, which are ghost\n          if (s.Guard != null) {\n            Visit(s.Guard, st);\n          }\n          // don't recurse on the body, if it's a dirty loop\n          if (s.Body != null) {\n            Visit(s.Body, st);\n          }\n          return false;\n        } else if (stmt is AlternativeLoopStmt) {\n          var s = (AlternativeLoopStmt)stmt;\n          // don't recurse on the specification parts, which are ghost\n          foreach (var alt in s.Alternatives) {\n            Visit(alt.Guard, st);\n            foreach (var ss in alt.Body) {\n              Visit(ss, st);\n            }\n          }\n          return false;\n        } else if (stmt is CallStmt) {\n          var s = (CallStmt)stmt;\n          var subst = s.MethodSelect.TypeArgumentSubstitutions();\n          Contract.Assert(s.Method.TypeArgs.Count <= subst.Count);\n          var i = 0;\n          foreach (var formalTypeArg in s.Method.TypeArgs) {\n            var actualTypeArg = subst[formalTypeArg];\n            CheckEqualityTypes_Type(s.Tok, actualTypeArg);\n            string whatIsWrong, hint;\n            if (!CheckCharacteristics(formalTypeArg.Characteristics, actualTypeArg, out whatIsWrong, out hint)) {\n              resolver.reporter.Error(MessageSource.Resolver, s.Tok, \"type parameter{0} ({1}) passed to method {2} must support {4} (got {3}){5}\",\n                s.Method.TypeArgs.Count == 1 ? \"\" : \" \" + i, formalTypeArg.Name, s.Method.Name, actualTypeArg, whatIsWrong, hint);\n            }\n            i++;\n          }\n          // recursively visit all subexpressions (which are all actual parameters) passed in for non-ghost formal parameters\n          Contract.Assert(s.Lhs.Count == s.Method.Outs.Count);\n          i = 0;\n          foreach (var ee in s.Lhs) {\n            if (!s.Method.Outs[i].IsGhost) {\n              Visit(ee, st);\n            }\n            i++;\n          }\n          Visit(s.Receiver, st);\n          Contract.Assert(s.Args.Count == s.Method.Ins.Count);\n          i = 0;\n          foreach (var ee in s.Args) {\n            if (!s.Method.Ins[i].IsGhost) {\n              Visit(ee, st);\n            }\n            i++;\n          }\n          return false;  // we've done what there is to be done\n        } else if (stmt is ForallStmt) {\n          var s = (ForallStmt)stmt;\n          foreach (var v in s.BoundVars) {\n            CheckEqualityTypes_Type(v.Tok, v.Type);\n          }\n          // do substatements and subexpressions, except attributes and ensures clauses, since they are not compiled\n          foreach (var ss in s.SubStatements) {\n            Visit(ss, st);\n          }\n          if (s.Range != null) {\n            Visit(s.Range, st);\n          }\n          return false;  // we're done\n        }\n        return true;\n      }\n      bool CheckCharacteristics(TypeParameter.TypeParameterCharacteristics formal, Type actual, out string whatIsWrong, out string hint) {\n        Contract.Ensures(Contract.Result<bool>() || (Contract.ValueAtReturn(out whatIsWrong) != null && Contract.ValueAtReturn(out hint) != null));\n        if (formal.EqualitySupport != TypeParameter.EqualitySupportValue.Unspecified && !actual.SupportsEquality) {\n          whatIsWrong = \"equality\";\n          hint = TypeEqualityErrorMessageHint(actual);\n          return false;\n        }\n        if (formal.MustSupportZeroInitialization && !Compiler.HasZeroInitializer(actual)) {\n          whatIsWrong = \"zero initialization\";\n          hint = \"\";\n          return false;\n        }\n        whatIsWrong = null;\n        hint = null;\n        return true;\n      }\n      protected override bool VisitOneExpr(Expression expr, ref bool st) {\n        if (expr is BinaryExpr) {\n          var e = (BinaryExpr)expr;\n          var t0 = e.E0.Type.NormalizeExpand();\n          var t1 = e.E1.Type.NormalizeExpand();\n          switch (e.Op) {\n            case BinaryExpr.Opcode.Eq:\n            case BinaryExpr.Opcode.Neq:\n              // First, check some special cases that can always be compared against--for example, a datatype value (like Nil) that takes no parameters\n              if (CanCompareWith(e.E0)) {\n                // that's cool\n              } else if (CanCompareWith(e.E1)) {\n                // oh yeah!\n              } else if (!t0.SupportsEquality) {\n                resolver.reporter.Error(MessageSource.Resolver, e.E0, \"{0} can only be applied to expressions of types that support equality (got {1}){2}\", BinaryExpr.OpcodeString(e.Op), t0, TypeEqualityErrorMessageHint(t0));\n              } else if (!t1.SupportsEquality) {\n                resolver.reporter.Error(MessageSource.Resolver, e.E1, \"{0} can only be applied to expressions of types that support equality (got {1}){2}\", BinaryExpr.OpcodeString(e.Op), t1, TypeEqualityErrorMessageHint(t1));\n              }\n              break;\n            default:\n              switch (e.ResolvedOp) {\n                // Note, all operations on sets, multisets, and maps are guaranteed to work because of restrictions placed on how\n                // these types are instantiated.  (Except: This guarantee does not apply to equality on maps, because the Range type\n                // of maps is not restricted, only the Domain type.  However, the equality operator is checked above.)\n                case BinaryExpr.ResolvedOpcode.InSeq:\n                case BinaryExpr.ResolvedOpcode.NotInSeq:\n                case BinaryExpr.ResolvedOpcode.Prefix:\n                case BinaryExpr.ResolvedOpcode.ProperPrefix:\n                  if (!t1.SupportsEquality) {\n                    resolver.reporter.Error(MessageSource.Resolver, e.E1, \"{0} can only be applied to expressions of sequence types that support equality (got {1}){2}\", BinaryExpr.OpcodeString(e.Op), t1, TypeEqualityErrorMessageHint(t1));\n                  } else if (!t0.SupportsEquality) {\n                    if (e.ResolvedOp == BinaryExpr.ResolvedOpcode.InSet || e.ResolvedOp == BinaryExpr.ResolvedOpcode.NotInSeq) {\n                      resolver.reporter.Error(MessageSource.Resolver, e.E0, \"{0} can only be applied to expressions of types that support equality (got {1}){2}\", BinaryExpr.OpcodeString(e.Op), t0, TypeEqualityErrorMessageHint(t0));\n                    } else {\n                      resolver.reporter.Error(MessageSource.Resolver, e.E0, \"{0} can only be applied to expressions of sequence types that support equality (got {1}){2}\", BinaryExpr.OpcodeString(e.Op), t0, TypeEqualityErrorMessageHint(t0));\n                    }\n                  }\n                  break;\n                default:\n                  break;\n              }\n              break;\n          }\n        } else if (expr is ComprehensionExpr) {\n          var e = (ComprehensionExpr)expr;\n          foreach (var bv in e.BoundVars) {\n            CheckEqualityTypes_Type(bv.tok, bv.Type);\n          }\n        } else if (expr is LetExpr) {\n          var e = (LetExpr)expr;\n          foreach (var bv in e.BoundVars) {\n            CheckEqualityTypes_Type(bv.tok, bv.Type);\n          }\n        } else if (expr is MemberSelectExpr) {\n          var e = (MemberSelectExpr)expr;\n          if (e.Member is Function || e.Member is Method) {\n            var i = 0;\n            foreach (var tp in ((ICallable)e.Member).TypeArgs) {\n              var actualTp = e.TypeApplication[e.Member.EnclosingClass.TypeArgs.Count + i];\n              CheckEqualityTypes_Type(e.tok, actualTp);\n              string whatIsWrong, hint;\n              if (!CheckCharacteristics(tp.Characteristics, actualTp, out whatIsWrong, out hint)) {\n                resolver.reporter.Error(MessageSource.Resolver, e.tok, \"type parameter{0} ({1}) passed to {2} '{3}' must support {5} (got {4}){6}\",\n                  ((ICallable)e.Member).TypeArgs.Count == 1 ? \"\" : \" \" + i, tp.Name, e.Member.WhatKind, e.Member.Name, actualTp, whatIsWrong, hint);\n              }\n              i++;\n            }\n          }\n        } else if (expr is FunctionCallExpr) {\n          var e = (FunctionCallExpr)expr;\n          Contract.Assert(e.Function.TypeArgs.Count <= e.TypeArgumentSubstitutions.Count);\n          var i = 0;\n          foreach (var formalTypeArg in e.Function.TypeArgs) {\n            var actualTypeArg = e.TypeArgumentSubstitutions[formalTypeArg];\n            CheckEqualityTypes_Type(e.tok, actualTypeArg);\n            string whatIsWrong, hint;\n            if (!CheckCharacteristics(formalTypeArg.Characteristics, actualTypeArg, out whatIsWrong, out hint)) {\n              resolver.reporter.Error(MessageSource.Resolver, e.tok, \"type parameter{0} ({1}) passed to function {2} must support {4} (got {3}){5}\",\n                e.Function.TypeArgs.Count == 1 ? \"\" : \" \" + i, formalTypeArg.Name, e.Function.Name, actualTypeArg, whatIsWrong, hint);\n            }\n            i++;\n          }\n          // recursively visit all subexpressions (which are all actual parameters) passed in for non-ghost formal parameters\n          Visit(e.Receiver, st);\n          Contract.Assert(e.Args.Count == e.Function.Formals.Count);\n          i = 0;\n          foreach (var ee in e.Args) {\n            if (!e.Function.Formals[i].IsGhost) {\n              Visit(ee, st);\n            }\n            i++;\n          }\n          return false;  // we've done what there is to be done\n        } else if (expr is SetDisplayExpr || expr is MultiSetDisplayExpr || expr is MapDisplayExpr || expr is SeqConstructionExpr || expr is MultiSetFormingExpr || expr is StaticReceiverExpr) {\n          // This catches other expressions whose type may potentially be illegal\n          CheckEqualityTypes_Type(expr.tok, expr.Type);\n        }\n        return true;\n      }\n\n      private bool CanCompareWith(Expression expr) {\n        Contract.Requires(expr != null);\n        if (expr.Type.SupportsEquality) {\n          return true;\n        }\n        expr = expr.Resolved;\n        if (expr is DatatypeValue) {\n          var e = (DatatypeValue)expr;\n          for (int i = 0; i < e.Ctor.Formals.Count; i++) {\n            if (e.Ctor.Formals[i].IsGhost) {\n              return false;\n            } else if (!CanCompareWith(e.Arguments[i])) {\n              return false;\n            }\n          }\n          return true;\n        } else if (expr is DisplayExpression) {\n          var e = (DisplayExpression)expr;\n          return e.Elements.Count == 0;\n        } else if (expr is MapDisplayExpr) {\n          var e = (MapDisplayExpr)expr;\n          return e.Elements.Count == 0;\n        }\n        return false;\n      }\n\n      public void CheckEqualityTypes_Type(IToken tok, Type type) {\n        Contract.Requires(tok != null);\n        Contract.Requires(type != null);\n        type = type.Normalize();  // we only do a .Normalize() here, because we want to keep stop at any type synonym or subset type\n        if (type is BasicType) {\n          // fine\n        } else if (type is SetType) {\n          var st = (SetType)type;\n          var argType = st.Arg;\n          if (!argType.SupportsEquality) {\n            resolver.reporter.Error(MessageSource.Resolver, tok, \"{2}set argument type must support equality (got {0}){1}\", argType, TypeEqualityErrorMessageHint(argType), st.Finite ? \"\" : \"i\");\n          }\n          CheckEqualityTypes_Type(tok, argType);\n\n        } else if (type is MultiSetType) {\n          var argType = ((MultiSetType)type).Arg;\n          if (!argType.SupportsEquality) {\n            resolver.reporter.Error(MessageSource.Resolver, tok, \"multiset argument type must support equality (got {0}){1}\", argType, TypeEqualityErrorMessageHint(argType));\n          }\n          CheckEqualityTypes_Type(tok, argType);\n\n        } else if (type is MapType) {\n          var mt = (MapType)type;\n          if (!mt.Domain.SupportsEquality) {\n            resolver.reporter.Error(MessageSource.Resolver, tok, \"{2}map domain type must support equality (got {0}){1}\", mt.Domain, TypeEqualityErrorMessageHint(mt.Domain), mt.Finite ? \"\" : \"i\");\n          }\n          CheckEqualityTypes_Type(tok, mt.Domain);\n          CheckEqualityTypes_Type(tok, mt.Range);\n\n        } else if (type is SeqType) {\n          Type argType = ((SeqType)type).Arg;\n          CheckEqualityTypes_Type(tok, argType);\n\n        } else if (type is UserDefinedType) {\n          var udt = (UserDefinedType)type;\n          List<TypeParameter> formalTypeArgs = null;\n          if (udt.ResolvedClass != null) {\n            formalTypeArgs = udt.ResolvedClass.TypeArgs;\n          } else if (udt.ResolvedParam is OpaqueType_AsParameter) {\n            var t = (OpaqueType_AsParameter)udt.ResolvedParam;\n            formalTypeArgs = t.TypeArgs;\n          }\n          if (formalTypeArgs == null) {\n            Contract.Assert(udt.TypeArgs.Count == 0);\n          } else {\n            Contract.Assert(formalTypeArgs.Count == udt.TypeArgs.Count);\n            var i = 0;\n            foreach (var argType in udt.TypeArgs) {\n              var formalTypeArg = formalTypeArgs[i];\n              string whatIsWrong, hint;\n              if (!CheckCharacteristics(formalTypeArg.Characteristics, argType, out whatIsWrong, out hint)) {\n                resolver.reporter.Error(MessageSource.Resolver, tok, \"type parameter{0} ({1}) passed to type {2} must support {4} (got {3}){5}\",\n                  udt.TypeArgs.Count == 1 ? \"\" : \" \" + i, formalTypeArg.Name, udt.ResolvedClass.Name, argType, whatIsWrong, hint);\n              }\n              CheckEqualityTypes_Type(tok, argType);\n              i++;\n            }\n          }\n\n        } else if (type is SizedArrayType) {\n          // fine\n        } else if (type is PointerType) {\n          // fine\n        } else if (type is TypeProxy) {\n          // the type was underconstrained; this is checked elsewhere, but it is not in violation of the equality-type test\n        } else {\n          Contract.Assert(false); throw new cce.UnreachableException();  // unexpected type\n        }\n      }\n\n      string TypeEqualityErrorMessageHint(Type argType) {\n        Contract.Requires(argType != null);\n        var tp = argType.AsTypeParameter;\n        if (tp != null) {\n          return string.Format(\" (perhaps try declaring type parameter '{0}' on line {1} as '{0}(==)', which says it can only be instantiated with a type that supports equality)\", tp.Name, tp.tok.line);\n        }\n        return \"\";\n      }\n    }\n    void CheckEqualityTypes_Stmt(Statement stmt) {\n      Contract.Requires(stmt != null);\n      var v = new CheckEqualityTypes_Visitor(this);\n      v.Visit(stmt, false);\n    }\n    void CheckEqualityTypes(Expression expr) {\n      Contract.Requires(expr != null);\n      var v = new CheckEqualityTypes_Visitor(this);\n      v.Visit(expr, false);\n    }\n    public void CheckEqualityTypes_Type(IToken tok, Type type) {\n      Contract.Requires(tok != null);\n      Contract.Requires(type != null);\n      var v = new CheckEqualityTypes_Visitor(this);\n      v.CheckEqualityTypes_Type(tok, type);\n    }\n\n#endregion CheckEqualityTypes\n\n    // ------------------------------------------------------------------------------------------------------\n    // ----- ComputeGhostInterest ---------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------------------------\n#region ComputeGhostInterest\n    public void ComputeGhostInterest(Statement stmt, bool mustBeErasable, ICodeContext codeContext) {\n      Contract.Requires(stmt != null);\n      Contract.Requires(codeContext != null);\n      var visitor = new GhostInterest_Visitor(codeContext, this);\n      visitor.Visit(stmt, mustBeErasable);\n    }\n    class GhostInterest_Visitor\n    {\n      readonly ICodeContext codeContext;\n      readonly Resolver resolver;\n      public GhostInterest_Visitor(ICodeContext codeContext, Resolver resolver) {\n        Contract.Requires(codeContext != null);\n        Contract.Requires(resolver != null);\n        this.codeContext = codeContext;\n        this.resolver = resolver;\n      }\n      protected void Error(Statement stmt, string msg, params object[] msgArgs) {\n        Contract.Requires(stmt != null);\n        Contract.Requires(msg != null);\n        Contract.Requires(msgArgs != null);\n        resolver.reporter.Error(MessageSource.Resolver, stmt, msg, msgArgs);\n      }\n      protected void Error(Expression expr, string msg, params object[] msgArgs) {\n        Contract.Requires(expr != null);\n        Contract.Requires(msg != null);\n        Contract.Requires(msgArgs != null);\n        resolver.reporter.Error(MessageSource.Resolver, expr, msg, msgArgs);\n      }\n      protected void Error(IToken tok, string msg, params object[] msgArgs) {\n        Contract.Requires(tok != null);\n        Contract.Requires(msg != null);\n        Contract.Requires(msgArgs != null);\n        resolver.reporter.Error(MessageSource.Resolver, tok, msg, msgArgs);\n      }\n      /// <summary>\n      /// This method does three things, in order:\n      /// 0. Sets .IsGhost to \"true\" if the statement is ghost.  This often depends on some guard of the statement\n      ///    (like the guard of an \"if\" statement) or the LHS of the statement (if it is an assignment).\n      ///    Note, if \"mustBeErasable\", then the statement is already in a ghost context.\n      ///    statement itself is ghost) or and the statement assigns to a non-ghost field\n      /// 1. Determines if the statement and all its subparts are legal under its computed .IsGhost setting.\n      /// 2. ``Upgrades'' .IsGhost to \"true\" if, after investigation of the substatements of the statement, it\n      ///    turns out that the statement can be erased during compilation.\n      /// Notes:\n      /// * Both step (0) and step (2) sets the .IsGhost field.  What step (0) does affects only the\n      ///   rules of resolution, whereas step (2) makes a note for the later compilation phase.\n      /// * It is important to do step (0) before step (1)--that is, it is important to set the statement's ghost\n      ///   status before descending into its sub-statements--because break statements look at the ghost status of\n      ///   its enclosing statements.\n      /// * The method called by a StmtExpr must be ghost; however, this is checked elsewhere.  For\n      ///   this reason, it is not necessary to visit all subexpressions, unless the subexpression\n      ///   matter for the ghost checking/recording of \"stmt\".\n      /// </summary>\n      public void Visit(Statement stmt, bool mustBeErasable) {\n        Contract.Requires(stmt != null);\n        Contract.Assume(!codeContext.IsGhost || mustBeErasable);  // (this is really a precondition) codeContext.IsGhost ==> mustBeErasable\n\n        if (stmt is PredicateStmt) {\n          stmt.IsGhost = true;\n          var assertStmt = stmt as AssertStmt;\n          if (assertStmt != null && assertStmt.Proof != null) {\n            Visit(assertStmt.Proof, true);\n          }\n\n        } else if (stmt is PrintStmt) {\n          var s = (PrintStmt)stmt;\n          if (mustBeErasable) {\n            Error(stmt, \"print statement is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression)\");\n          } else {\n            s.Args.Iter(resolver.CheckIsCompilable);\n          }\n\n        } else if (stmt is RevealStmt) {\n          var s = (RevealStmt)stmt;\n          s.ResolvedStatements.Iter(ss => Visit(ss, mustBeErasable));\n          s.IsGhost = s.ResolvedStatements.All(ss => ss.IsGhost);\n        } else if (stmt is SomehowStmt) {\n          var s = (SomehowStmt)stmt;\n          if (mustBeErasable) {\n            Error(stmt, \"somehow statement is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression)\");\n          }\n        } else if (stmt is FenceStmt) {\n          var s = (FenceStmt)stmt;\n          if (mustBeErasable) {\n            Error(stmt, \"fence statement is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression)\");\n          }\n        } else if (stmt is GotoStmt) {\n          var s = (GotoStmt)stmt;\n          if (mustBeErasable) {\n            Error(stmt, \"goto statement is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression)\");\n          }\n        } else if (stmt is DeallocStmt) {\n          var s = (DeallocStmt)stmt;\n          if (mustBeErasable) {\n            Error(stmt, \"dealloc statement is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression)\");\n          }\n        } else if (stmt is JoinStmt) {\n          var s = (JoinStmt)stmt;\n          if (mustBeErasable) {\n            Error(stmt, \"join statement is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression)\");\n          }\n        } else if (stmt is BreakStmt) {\n          var s = (BreakStmt)stmt;\n          s.IsGhost = mustBeErasable;\n          if (s.IsGhost && !s.TargetStmt.IsGhost) {\n            var targetIsLoop = s.TargetStmt is WhileStmt || s.TargetStmt is AlternativeLoopStmt;\n            Error(stmt, \"ghost-context break statement is not allowed to break out of non-ghost \" + (targetIsLoop ? \"loop\" : \"structure\"));\n          }\n\n        } else if (stmt is ContinueStmt) {\n\n        } else if (stmt is ProduceStmt) {\n          var s = (ProduceStmt)stmt;\n          var kind = stmt is YieldStmt ? \"yield\" : \"return\";\n          if (mustBeErasable && !codeContext.IsGhost) {\n            Error(stmt, \"{0} statement is not allowed in this context (because it is guarded by a specification-only expression)\", kind);\n          }\n          if (s.hiddenUpdate != null) {\n            Visit(s.hiddenUpdate, mustBeErasable);\n          }\n\n        } else if (stmt is AssignSuchThatStmt) {\n          var s = (AssignSuchThatStmt)stmt;\n          s.IsGhost = mustBeErasable || s.AssumeToken != null || s.Lhss.Any(AssignStmt.LhsIsToGhost);\n          if (mustBeErasable && !codeContext.IsGhost) {\n            foreach (var lhs in s.Lhss) {\n              var gk = AssignStmt.LhsIsToGhost_Which(lhs);\n              if (gk != AssignStmt.NonGhostKind.IsGhost) {\n                Error(lhs, \"cannot assign to {0} in a ghost context\", AssignStmt.NonGhostKind_To_String(gk));\n              }\n            }\n          } else if (!mustBeErasable && s.AssumeToken == null && resolver.UsesSpecFeatures(s.Expr)) {\n            foreach (var lhs in s.Lhss) {\n              var gk = AssignStmt.LhsIsToGhost_Which(lhs);\n              if (gk != AssignStmt.NonGhostKind.IsGhost) {\n                Error(lhs, \"{0} cannot be assigned a value that depends on a ghost\", AssignStmt.NonGhostKind_To_String(gk));\n              }\n            }\n          }\n\n        } else if (stmt is UpdateStmt) {\n          var s = (UpdateStmt)stmt;\n          s.ResolvedStatements.Iter(ss => Visit(ss, mustBeErasable));\n          s.IsGhost = s.ResolvedStatements.All(ss => ss.IsGhost);\n\n          if (s.Rhss.Count == 1 && (s.Rhss[0] is CreateThreadRhs || s.Rhss[0] is CompareAndSwapRhs || s.Rhss[0] is AtomicExchangeRhs)) {\n            s.IsGhost = false;\n            if (mustBeErasable) {\n              Error(stmt, \"Effectful statement is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression)\");\n            }\n            foreach (var e in s.Rhss[0].SubExpressions) {\n              resolver.CheckIsCompilable(e);\n            }\n          }\n\n        } else if (stmt is AssignOrReturnStmt) {\n          stmt.IsGhost = false; // TODO when do we want to allow this feature in ghost code? Note that return changes control flow\n\n        } else if (stmt is VarDeclStmt) {\n          var s = (VarDeclStmt)stmt;\n          if (mustBeErasable) {\n            foreach (var local in s.Locals) {\n              // a local variable in a specification-only context might as well be ghost\n              local.IsGhost = true;\n            }\n          }\n          s.IsGhost = (s.Update == null || s.Update.IsGhost) && s.Locals.All(v => v.IsGhost);\n          if (s.Update != null) {\n            Visit(s.Update, mustBeErasable);\n          }\n\n        } else if (stmt is LetStmt) {\n          var s = (LetStmt)stmt;\n          if (mustBeErasable) {\n            foreach (var local in s.LocalVars) {\n              local.IsGhost = true;\n            }\n          }\n          s.IsGhost = s.LocalVars.All(v => v.IsGhost);\n\n        } else if (stmt is AssignStmt) {\n          var s = (AssignStmt)stmt;\n          var lhs = s.Lhs.Resolved;\n          var gk = AssignStmt.LhsIsToGhost_Which(lhs);\n          if (gk == AssignStmt.NonGhostKind.IsGhost) {\n            s.IsGhost = true;\n            if (s.Rhs is TypeRhs) {\n              Error(s.Rhs.Tok, \"'new' is not allowed in ghost contexts\");\n            }\n          } else if (gk == AssignStmt.NonGhostKind.Variable && codeContext.IsGhost) {\n            // cool\n          } else if (mustBeErasable) {\n            Error(stmt, \"Assignment to {0} is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression)\",\n              AssignStmt.NonGhostKind_To_String(gk));\n          } else if (s.Rhs is ExprRhs) {\n            var rhs = (ExprRhs)s.Rhs;\n            resolver.CheckIsCompilable(rhs.Expr);\n          } else if (s.Rhs is HavocRhs) {\n            // cool\n          } else if (s.Rhs is MallocRhs) {\n            if (mustBeErasable) {\n              Error(stmt, \"malloc is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression)\");\n            }\n          } else if (s.Rhs is CallocRhs) {\n            if (mustBeErasable) {\n              Error(stmt, \"calloc is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression)\");\n            }\n          } else {\n            if (gk == AssignStmt.NonGhostKind.Field) {\n              var mse = (MemberSelectExpr)lhs;\n              resolver.CheckIsCompilable(mse.Obj);\n            } else if (gk == AssignStmt.NonGhostKind.ArrayElement) {\n              resolver.CheckIsCompilable(lhs);\n            }\n            if (s.Rhs is ExprRhs) {\n              var rhs = (ExprRhs)s.Rhs;\n              resolver.CheckIsCompilable(rhs.Expr);\n            } else if (s.Rhs is HavocRhs) {\n              // cool\n            } else if (s.Rhs is CreateThreadRhs || s.Rhs is CompareAndSwapRhs || s.Rhs is AtomicExchangeRhs) {\n              // already checked when Update was checked\n            } else {\n              var rhs = (TypeRhs)s.Rhs;\n              if (rhs.ArrayDimensions != null) {\n                rhs.ArrayDimensions.ForEach(resolver.CheckIsCompilable);\n                if (rhs.ElementInit != null) {\n                  resolver.CheckIsCompilable(rhs.ElementInit);\n                }\n                if (rhs.InitDisplay != null) {\n                  rhs.InitDisplay.ForEach(resolver.CheckIsCompilable);\n                }\n              }\n              if (rhs.InitCall != null) {\n                rhs.InitCall.Args.ForEach(resolver.CheckIsCompilable);\n              }\n            }\n          }\n\n        } else if (stmt is CallStmt) {\n          var s = (CallStmt)stmt;\n          var callee = s.Method;\n          Contract.Assert(callee != null);  // follows from the invariant of CallStmt\n          s.IsGhost = callee.IsGhost;\n          // check in-parameters\n          if (mustBeErasable) {\n            if (!s.IsGhost) {\n              Error(s, \"only ghost methods can be called from this context\");\n            }\n          } else {\n            int j;\n            if (!callee.IsGhost) {\n              resolver.CheckIsCompilable(s.Receiver);\n              j = 0;\n              foreach (var e in s.Args) {\n                Contract.Assume(j < callee.Ins.Count);  // this should have already been checked by the resolver\n                if (!callee.Ins[j].IsGhost) {\n                  resolver.CheckIsCompilable(e);\n                }\n                j++;\n              }\n            }\n            j = 0;\n            foreach (var e in s.Lhs) {\n              var resolvedLhs = e.Resolved;\n              if (callee.IsGhost || callee.Outs[j].IsGhost) {\n                // LHS must denote a ghost\n                if (resolvedLhs is IdentifierExpr) {\n                  var ll = (IdentifierExpr)resolvedLhs;\n                  if (!ll.Var.IsGhost) {\n                    if (ll is AutoGhostIdentifierExpr && ll.Var is LocalVariable) {\n                      // the variable was actually declared in this statement, so auto-declare it as ghost\n                      ((LocalVariable)ll.Var).MakeGhost();\n                    } else {\n                      Error(s, \"actual out-parameter{0} is required to be a ghost variable\", s.Lhs.Count == 1 ? \"\" : \" \" + j);\n                    }\n                  }\n                } else if (resolvedLhs is MemberSelectExpr) {\n                  var ll = (MemberSelectExpr)resolvedLhs;\n                  if (!ll.Member.IsGhost) {\n                    Error(s, \"actual out-parameter{0} is required to be a ghost field\", s.Lhs.Count == 1 ? \"\" : \" \" + j);\n                  }\n                } else {\n                  // this is an array update, and arrays are always non-ghost\n                  Error(s, \"actual out-parameter{0} is required to be a ghost variable\", s.Lhs.Count == 1 ? \"\" : \" \" + j);\n                }\n              }\n              j++;\n            }\n          }\n\n        } else if (stmt is BlockStmt) {\n          var s = (BlockStmt)stmt;\n          s.IsGhost = mustBeErasable;  // set .IsGhost before descending into substatements (since substatements may do a 'break' out of this block)\n          s.Body.Iter(ss => Visit(ss, mustBeErasable));\n          s.IsGhost = s.IsGhost || s.Body.All(ss => ss.IsGhost);  // mark the block statement as ghost if all its substatements are ghost\n\n        } else if (stmt is IfStmt) {\n          var s = (IfStmt)stmt;\n          s.IsGhost = mustBeErasable || (s.Guard != null && resolver.UsesSpecFeatures(s.Guard));\n          if (!mustBeErasable && s.IsGhost) {\n            resolver.reporter.Info(MessageSource.Resolver, s.Tok, \"ghost if\");\n          }\n          Visit(s.Thn, s.IsGhost);\n          if (s.Els != null) {\n            Visit(s.Els, s.IsGhost);\n          }\n          // if both branches were all ghost, then we can mark the enclosing statement as ghost as well\n          s.IsGhost = s.IsGhost || (s.Thn.IsGhost && (s.Els == null || s.Els.IsGhost));\n\n        } else if (stmt is AlternativeStmt) {\n          var s = (AlternativeStmt)stmt;\n          s.IsGhost = mustBeErasable || s.Alternatives.Exists(alt => resolver.UsesSpecFeatures(alt.Guard));\n          if (!mustBeErasable && s.IsGhost) {\n            resolver.reporter.Info(MessageSource.Resolver, s.Tok, \"ghost if\");\n          }\n          s.Alternatives.Iter(alt => alt.Body.Iter(ss => Visit(ss, s.IsGhost)));\n          s.IsGhost = s.IsGhost || s.Alternatives.All(alt => alt.Body.All(ss => ss.IsGhost));\n\n        } else if (stmt is WhileStmt) {\n          var s = (WhileStmt)stmt;\n          s.IsGhost = mustBeErasable || (s.Guard != null && resolver.UsesSpecFeatures(s.Guard));\n          if (!mustBeErasable && s.IsGhost) {\n            resolver.reporter.Info(MessageSource.Resolver, s.Tok, \"ghost while\");\n          }\n          if (s.IsGhost && s.Decreases.Expressions.Exists(e => e is WildcardExpr)) {\n            Error(s, \"'decreases *' is not allowed on ghost loops\");\n          }\n          if (s.IsGhost && s.Mod.Expressions != null) {\n            s.Mod.Expressions.Iter(resolver.DisallowNonGhostFieldSpecifiers);\n          }\n          if (s.Body != null) {\n            Visit(s.Body, s.IsGhost);\n          }\n          s.IsGhost = s.IsGhost || s.Body == null || (!s.Decreases.Expressions.Exists(e => e is WildcardExpr) && s.Body.IsGhost);\n\n        } else if (stmt is AlternativeLoopStmt) {\n          var s = (AlternativeLoopStmt)stmt;\n          s.IsGhost = mustBeErasable || s.Alternatives.Exists(alt => resolver.UsesSpecFeatures(alt.Guard));\n          if (!mustBeErasable && s.IsGhost) {\n            resolver.reporter.Info(MessageSource.Resolver, s.Tok, \"ghost while\");\n          }\n          if (s.IsGhost && s.Decreases.Expressions.Exists(e => e is WildcardExpr)) {\n            Error(s, \"'decreases *' is not allowed on ghost loops\");\n          }\n          if (s.IsGhost && s.Mod.Expressions != null) {\n            s.Mod.Expressions.Iter(resolver.DisallowNonGhostFieldSpecifiers);\n          }\n          s.Alternatives.Iter(alt => alt.Body.Iter(ss => Visit(ss, s.IsGhost)));\n          s.IsGhost = s.IsGhost || (!s.Decreases.Expressions.Exists(e => e is WildcardExpr) && s.Alternatives.All(alt => alt.Body.All(ss => ss.IsGhost)));\n\n        } else if (stmt is ForallStmt) {\n          var s = (ForallStmt)stmt;\n          s.IsGhost = mustBeErasable || s.Kind != ForallStmt.BodyKind.Assign || resolver.UsesSpecFeatures(s.Range);\n          if (s.Body != null) {\n            Visit(s.Body, s.IsGhost);\n          }\n          s.IsGhost = s.IsGhost || s.Body == null || s.Body.IsGhost;\n\n          if (!s.IsGhost) {\n            // Since we've determined this is a non-ghost forall statement, we now check that the bound variables have compilable bounds.\n            var uncompilableBoundVars = s.UncompilableBoundVars();\n            if (uncompilableBoundVars.Count != 0) {\n              foreach (var bv in uncompilableBoundVars) {\n                Error(s, \"forall statements in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for '{0}'\", bv.Name);\n              }\n            }\n          }\n\n        } else if (stmt is ModifyStmt) {\n          var s = (ModifyStmt)stmt;\n          s.IsGhost = mustBeErasable;\n          if (s.IsGhost) {\n            s.Mod.Expressions.Iter(resolver.DisallowNonGhostFieldSpecifiers);\n          }\n          if (s.Body != null) {\n            Visit(s.Body, mustBeErasable);\n          }\n\n        } else if (stmt is CalcStmt) {\n          var s = (CalcStmt)stmt;\n          s.IsGhost = true;\n          foreach (var h in s.Hints) {\n            Visit(h, true);\n          }\n\n        } else if (stmt is MatchStmt) {\n          var s = (MatchStmt)stmt;\n          s.IsGhost = mustBeErasable || resolver.UsesSpecFeatures(s.Source);\n          if (!mustBeErasable && s.IsGhost) {\n            resolver.reporter.Info(MessageSource.Resolver, s.Tok, \"ghost match\");\n          }\n          s.Cases.Iter(kase => kase.Body.Iter(ss => Visit(ss, s.IsGhost)));\n          s.IsGhost = s.IsGhost || s.Cases.All(kase => kase.Body.All(ss => ss.IsGhost));\n\n        } else if (stmt is SkeletonStatement) {\n          var s = (SkeletonStatement)stmt;\n          s.IsGhost = mustBeErasable;\n          if (s.S != null) {\n            Visit(s.S, mustBeErasable);\n            s.IsGhost = s.IsGhost || s.S.IsGhost;\n          }\n\n        } else {\n          Contract.Assert(false); throw new cce.UnreachableException();\n        }\n      }\n    }\n#endregion\n\n    // ------------------------------------------------------------------------------------------------------\n    // ----- FillInDefaultLoopDecreases ---------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------------------------\n#region FillInDefaultLoopDecreases\n    class FillInDefaultLoopDecreases_Visitor : ResolverBottomUpVisitor\n    {\n      readonly ICallable EnclosingMethod;\n      public FillInDefaultLoopDecreases_Visitor(Resolver resolver, ICallable enclosingMethod)\n        : base(resolver) {\n        Contract.Requires(resolver != null);\n        Contract.Requires(enclosingMethod != null);\n        EnclosingMethod = enclosingMethod;\n      }\n      protected override void VisitOneStmt(Statement stmt) {\n        if (stmt is WhileStmt) {\n          var s = (WhileStmt)stmt;\n          resolver.FillInDefaultLoopDecreases(s, s.Guard, s.Decreases.Expressions, EnclosingMethod);\n        } else if (stmt is AlternativeLoopStmt) {\n          var s = (AlternativeLoopStmt)stmt;\n          resolver.FillInDefaultLoopDecreases(s, null, s.Decreases.Expressions, EnclosingMethod);\n        }\n      }\n    }\n#endregion FillInDefaultLoopDecreases\n\n    // ------------------------------------------------------------------------------------------------------\n    // ----- ReportMoreAdditionalInformation ----------------------------------------------------------------\n    // ------------------------------------------------------------------------------------------------------\n#region ReportOtherAdditionalInformation_Visitor\n    class ReportOtherAdditionalInformation_Visitor : ResolverBottomUpVisitor\n    {\n      public ReportOtherAdditionalInformation_Visitor(Resolver resolver)\n        : base(resolver) {\n        Contract.Requires(resolver != null);\n      }\n      protected override void VisitOneStmt(Statement stmt) {\n        if (stmt is ForallStmt) {\n          var s = (ForallStmt)stmt;\n          if (s.Kind == ForallStmt.BodyKind.Call) {\n            var cs = (CallStmt)s.S0;\n            // show the callee's postcondition as the postcondition of the 'forall' statement\n            // TODO:  The following substitutions do not correctly take into consideration variable capture; hence, what the hover text displays may be misleading\n            var argsSubstMap = new Dictionary<IVariable, Expression>();  // maps formal arguments to actuals\n            Contract.Assert(cs.Method.Ins.Count == cs.Args.Count);\n            for (int i = 0; i < cs.Method.Ins.Count; i++) {\n              argsSubstMap.Add(cs.Method.Ins[i], cs.Args[i]);\n            }\n            var substituter = new Translator.AlphaConverting_Substituter(cs.Receiver, argsSubstMap, new Dictionary<TypeParameter, Type>());\n            if (!Attributes.Contains(s.Attributes, \"auto_generated\")) {\n              foreach (var ens in cs.Method.Ens) {\n                var p = substituter.Substitute(ens.E);  // substitute the call's actuals for the method's formals\n                resolver.reporter.Info(MessageSource.Resolver, s.Tok, \"ensures \" + Printer.ExprToString(p));\n              }\n            }\n          }\n        }\n      }\n    }\n#endregion ReportOtherAdditionalInformation_Visitor\n\n    // ------------------------------------------------------------------------------------------------------\n    // ----- ReportMoreAdditionalInformation ----------------------------------------------------------------\n    // ------------------------------------------------------------------------------------------------------\n#region CheckDividedConstructorInit\n    class CheckDividedConstructorInit_Visitor : ResolverTopDownVisitor<int>\n    {\n      public CheckDividedConstructorInit_Visitor(Resolver resolver)\n        : base(resolver)\n      {\n        Contract.Requires(resolver != null);\n      }\n      public void CheckInit(List<Statement> initStmts) {\n        Contract.Requires(initStmts != null);\n        initStmts.Iter(CheckInit);\n      }\n      /// <summary>\n      /// This method almost does what Visit(Statement) does, except that it handles assignments to\n      /// fields differently.\n      /// </summary>\n      void CheckInit(Statement stmt) {\n        Contract.Requires(stmt != null);\n        // Visit(stmt) would do:\n        //     stmt.SubExpressions.Iter(Visit);    (*)\n        //     stmt.SubStatements.Iter(Visit);     (**)\n        //     VisitOneStmt(stmt);                 (***)\n        // We may do less for (*), we always use CheckInit instead of Visit in (**), and we do (***) the same.\n        if (stmt is AssignStmt) {\n          var s = stmt as AssignStmt;\n          // The usual visitation of s.SubExpressions.Iter(Visit) would do the following:\n          //   Attributes.SubExpressions(s.Attributes).Iter(Visit);  (+)\n          //   Visit(s.Lhs);                                         (++)\n          //   s.Rhs.SubExpressions.Iter(Visit);                     (+++)\n          // Here, we may do less; in particular, we may omit (++).\n          Attributes.SubExpressions(s.Attributes).Iter(VisitExpr);  // (+)\n          var mse = s.Lhs as MemberSelectExpr;\n          if (mse != null && Expression.AsThis(mse.Obj) != null) {\n            if (s.Rhs is ExprRhs) {\n              // This is a special case we allow.  Omit s.Lhs in the recursive visits.  That is, we omit (++).\n              // Furthermore, because the assignment goes to a field of \"this\" and won't be available until after\n              // the \"new;\", we can allow certain specific (and useful) uses of \"this\" in the RHS.\n              s.Rhs.SubExpressions.Iter(LiberalRHSVisit);  // (+++)\n            } else {\n              s.Rhs.SubExpressions.Iter(VisitExpr);  // (+++)\n            }\n          } else {\n            VisitExpr(s.Lhs);  // (++)\n            s.Rhs.SubExpressions.Iter(VisitExpr);  // (+++)\n          }\n        } else {\n          stmt.SubExpressions.Iter(VisitExpr);  // (*)\n        }\n        stmt.SubStatements.Iter(CheckInit);  // (**)\n        int dummy = 0;\n        VisitOneStmt(stmt, ref dummy);  // (***)\n      }\n      void VisitExpr(Expression expr) {\n        Contract.Requires(expr != null);\n        Visit(expr, 0);\n      }\n      protected override bool VisitOneExpr(Expression expr, ref int unused) {\n        if (expr is MemberSelectExpr) {\n          var e = (MemberSelectExpr)expr;\n          if (e.Member.IsInstanceIndependentConstant && Expression.AsThis(e.Obj) != null) {\n            return false;  // don't continue the recursion\n          }\n        } else if (expr is ThisExpr && !(expr is ImplicitThisExpr_ConstructorCall)) {\n          resolver.reporter.Error(MessageSource.Resolver, expr.tok, \"in the first division of the constructor body (before 'new;'), 'this' can only be used to assign to its fields\");\n        }\n        return base.VisitOneExpr(expr, ref unused);\n      }\n      void LiberalRHSVisit(Expression expr) {\n        Contract.Requires(expr != null);\n        // It is important not to allow \"this\" to flow into something that can be used (for compilation or\n        // verification purposes) before the \"new;\", because, to the verifier, \"this\" has not yet been allocated.\n        // The verifier is told that everything reachable from the heap is expected to be allocated and satisfy all\n        // the usual properties, so \"this\" had better not become reachable from the heap until after the \"new;\"\n        // that does the actual allocation of \"this\".\n        // Within these restrictions, we can allow the (not yet fully available) value \"this\" to flow into values\n        // stored in fields of \"this\".  Such values are naked occurrences of \"this\" and \"this\" occurring\n        // as part of constructing a value type.  Since by this rule, \"this\" may be part of the value stored in\n        // a field of \"this\", we must apply the same rules to uses of the values of fields of \"this\".\n        if (expr is ConcreteSyntaxExpression) {\n        } else if (expr is ThisExpr) {\n        } else if (expr is MeExpr) {\n        } else if (expr is StoreBufferEmptyExpr) {\n        } else if (expr is TotalStateExpr) {\n        } else if (expr is MemberSelectExpr && IsThisDotField((MemberSelectExpr)expr)) {\n        } else if (expr is SetDisplayExpr) {\n        } else if (expr is MultiSetDisplayExpr) {\n        } else if (expr is SeqDisplayExpr) {\n        } else if (expr is MapDisplayExpr) {\n        } else if (expr is BinaryExpr && IsCollectionOperator(((BinaryExpr)expr).ResolvedOp)) {\n        } else if (expr is DatatypeValue) {\n        } else if (expr is ITEExpr) {\n          var e = (ITEExpr)expr;\n          VisitExpr(e.Test);\n          LiberalRHSVisit(e.Thn);\n          LiberalRHSVisit(e.Els);\n          return;\n        } else {\n          // defer to the usual Visit\n          VisitExpr(expr);\n          return;\n        }\n        expr.SubExpressions.Iter(LiberalRHSVisit);\n      }\n      static bool IsThisDotField(MemberSelectExpr expr) {\n        Contract.Requires(expr != null);\n        return Expression.AsThis(expr.Obj) != null && expr.Member is Field;\n      }\n      static bool IsCollectionOperator(BinaryExpr.ResolvedOpcode op) {\n        switch (op) {\n          // sets:  +, *, -\n          case BinaryExpr.ResolvedOpcode.Union:\n          case BinaryExpr.ResolvedOpcode.Intersection:\n          case BinaryExpr.ResolvedOpcode.SetDifference:\n          // multisets: +, *, -\n          case BinaryExpr.ResolvedOpcode.MultiSetUnion:\n          case BinaryExpr.ResolvedOpcode.MultiSetIntersection:\n          case BinaryExpr.ResolvedOpcode.MultiSetDifference:\n           // sequences: +\n          case BinaryExpr.ResolvedOpcode.Concat:\n          // maps: +\n          case BinaryExpr.ResolvedOpcode.MapUnion:\n            return true;\n          default:\n            return false;\n        }\n      }\n    }\n#endregion\n\n    // ------------------------------------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------------------------\n\n    bool InferRequiredEqualitySupport(TypeParameter tp, Type type) {\n      Contract.Requires(tp != null);\n      Contract.Requires(type != null);\n\n      type = type.Normalize();  // we only do a .Normalize() here, because we want to keep stop at any type synonym or subset type\n      if (type is BasicType) {\n      } else if (type is SetType) {\n        var st = (SetType)type;\n        return st.Arg.AsTypeParameter == tp || InferRequiredEqualitySupport(tp, st.Arg);\n      } else if (type is MultiSetType) {\n        var ms = (MultiSetType)type;\n        return ms.Arg.AsTypeParameter == tp || InferRequiredEqualitySupport(tp, ms.Arg);\n      } else if (type is MapType) {\n        var mt = (MapType)type;\n        return mt.Domain.AsTypeParameter == tp || InferRequiredEqualitySupport(tp, mt.Domain) || InferRequiredEqualitySupport(tp, mt.Range);\n      } else if (type is SeqType) {\n        var sq = (SeqType)type;\n        return InferRequiredEqualitySupport(tp, sq.Arg);\n      } else if (type is UserDefinedType) {\n        var udt = (UserDefinedType)type;\n        List<TypeParameter> formalTypeArgs = null;\n        if (udt.ResolvedClass != null) {\n          formalTypeArgs = udt.ResolvedClass.TypeArgs;\n        } else if (udt.ResolvedParam is OpaqueType_AsParameter) {\n          var t = (OpaqueType_AsParameter)udt.ResolvedParam;\n          formalTypeArgs = t.TypeArgs;\n        }\n        if (formalTypeArgs == null) {\n          Contract.Assert(udt.TypeArgs.Count == 0);\n        } else {\n          Contract.Assert(formalTypeArgs.Count == udt.TypeArgs.Count);\n          var i = 0;\n          foreach (var argType in udt.TypeArgs) {\n            var formalTypeArg = formalTypeArgs[i];\n            if ((formalTypeArg.MustSupportEquality && argType.AsTypeParameter == tp) || InferRequiredEqualitySupport(tp, argType)) {\n              return true;\n            }\n            i++;\n          }\n        }\n        if (udt.ResolvedClass is TypeSynonymDecl) {\n          var syn = (TypeSynonymDecl)udt.ResolvedClass;\n          if (syn.IsRevealedInScope(Type.GetScope())) {\n            return InferRequiredEqualitySupport(tp, syn.RhsWithArgument(udt.TypeArgs));\n          }\n        }\n      } else {\n        Contract.Assert(false); throw new cce.UnreachableException();  // unexpected type\n      }\n      return false;\n    }\n\n    TopLevelDeclWithMembers currentClass;\n    Method currentMethod;\n    bool inBodyInitContext;  // \"true\" only if \"currentMethod is Constructor\"\n    readonly Scope<TypeParameter>/*!*/\n      allTypeParameters = new Scope<TypeParameter>();\n    readonly Scope<IVariable>/*!*/ scope = new Scope<IVariable>();\n    Scope<Statement>/*!*/ enclosingStatementLabels = new Scope<Statement>();\n    Scope<Label>/*!*/ dominatingStatementLabels = new Scope<Label>();\n    Scope<Label>/*!*/ methodStatementLabels = new Scope<Label>();\n    List<Statement> loopStack = new List<Statement>();  // the enclosing loops (from which it is possible to break out)\n\n    /// <summary>\n    /// This method resolves the types that have been given after the 'extends' keyword.  Then, it populates\n    /// the string->MemberDecl table for \"cl\" to make sure that all inherited names are accounted for.  Further\n    /// checks are done later, elsewhere.\n    /// </summary>\n    void RegisterInheritedMembers(ClassDecl cl) {\n      Contract.Requires(cl != null);\n      Contract.Requires(currentClass == null);\n      Contract.Ensures(currentClass == null);\n      currentClass = cl;\n\n      if (cl.TraitsTyp.Count > 0 && cl.TypeArgs.Count > 0) {\n        reporter.Error(MessageSource.Resolver, cl.tok, \"sorry, traits are currently supported only for classes that take no type arguments\");  // TODO: do the work to remove this limitation\n      }\n\n      // Resolve names of traits extended\n      foreach (var tt in cl.TraitsTyp) {\n        var prevErrorCount = reporter.Count(ErrorLevel.Error);\n        ResolveType_ClassName(cl.tok, tt, new NoContext(cl.Module), ResolveTypeOptionEnum.DontInfer, null);\n        if (reporter.Count(ErrorLevel.Error) == prevErrorCount) {\n          var udt = tt as UserDefinedType;\n          if (udt != null && udt.ResolvedClass is NonNullTypeDecl && ((NonNullTypeDecl)udt.ResolvedClass).ViewAsClass is TraitDecl) {\n            var trait = (TraitDecl)((NonNullTypeDecl)udt.ResolvedClass).ViewAsClass;\n            //disallowing inheritance in multi module case\n            bool termination = true;\n            if (cl.Module == trait.Module || (Attributes.ContainsBool(trait.Attributes, \"termination\", ref termination) && !termination)) {\n              // all is good (or the user takes responsibility for the lack of termination checking)\n              cl.TraitsObj.Add(trait);\n            } else {\n              reporter.Error(MessageSource.Resolver, udt.tok, \"class '{0}' is in a different module than trait '{1}'. A class may only extend a trait in the same module.\", cl.Name, trait.FullName);\n            }\n          } else {\n            reporter.Error(MessageSource.Resolver, udt != null ? udt.tok : cl.tok, \"a class can only extend traits (found '{0}')\", tt);\n          }\n        }\n      }\n\n      // Inherit members from traits.  What we do here is simply to register names, and in particular to register\n      // names that are no already in the class.\n      var members = classMembers[cl];\n      foreach (var trait in cl.TraitsObj) {\n        foreach (var traitMember in trait.Members) {\n          MemberDecl classMember;\n          if (members.TryGetValue(traitMember.Name, out classMember)) {\n            // the class already declares or inherits a member with this name, so we take no further action at this time\n          } else {\n            // register the trait member in the class\n            members.Add(traitMember.Name, traitMember);\n          }\n        }\n      }\n\n      currentClass = null;\n    }\n\n    /// <summary>\n    /// Assumes type parameters have already been pushed\n    /// </summary>\n    void ResolveClassMemberTypes(TopLevelDeclWithMembers cl) {\n      Contract.Requires(cl != null);\n      Contract.Requires(currentClass == null);\n      Contract.Ensures(currentClass == null);\n\n      currentClass = cl;\n\n      foreach (MemberDecl member in cl.Members) {\n        member.EnclosingClass = cl;\n        if (member is Field) {\n          if (member is ConstantField) {\n            var m = (ConstantField)member;\n            ResolveType(member.tok, ((Field)member).Type, m, ResolveTypeOptionEnum.DontInfer, null);\n          } else {\n            // In the following, we pass in a NoContext, because any cycle formed by a redirecting-type constraints would have to\n            // dereference the heap, and such constraints are not allowed to dereference the heap so an error will be produced\n            // even if we don't detect this cycle.\n            ResolveType(member.tok, ((Field)member).Type, new NoContext(cl.Module), ResolveTypeOptionEnum.DontInfer, null);\n          }\n        } else if (member is Function) {\n          var f = (Function)member;\n          var ec = reporter.Count(ErrorLevel.Error);\n          allTypeParameters.PushMarker();\n          ResolveTypeParameters(f.TypeArgs, true, f);\n          ResolveFunctionSignature(f);\n          allTypeParameters.PopMarker();\n          if (f is FixpointPredicate && ec == reporter.Count(ErrorLevel.Error)) {\n            var ff = ((FixpointPredicate)f).PrefixPredicate;  // note, may be null if there was an error before the prefix predicate was generated\n            if (ff != null) {\n              ff.EnclosingClass = cl;\n              allTypeParameters.PushMarker();\n              ResolveTypeParameters(ff.TypeArgs, true, ff);\n              ResolveFunctionSignature(ff);\n              allTypeParameters.PopMarker();\n            }\n          }\n\n        } else if (member is Method) {\n          var m = (Method)member;\n          var ec = reporter.Count(ErrorLevel.Error);\n          allTypeParameters.PushMarker();\n          ResolveTypeParameters(m.TypeArgs, true, m);\n          ResolveMethodSignature(m);\n          allTypeParameters.PopMarker();\n          var com = m as FixpointLemma;\n          if (com != null && com.PrefixLemma != null && ec == reporter.Count(ErrorLevel.Error)) {\n            var mm = com.PrefixLemma;\n            // resolve signature of the prefix lemma\n            mm.EnclosingClass = cl;\n            allTypeParameters.PushMarker();\n            ResolveTypeParameters(mm.TypeArgs, true, mm);\n            ResolveMethodSignature(mm);\n            allTypeParameters.PopMarker();\n          }\n        } else if (member is GlobalInvariantDecl) {\n          // nothing to do\n        } else if (member is YieldPredicateDecl) {\n          // nothing to do\n        } else if (member is UniversalStepConstraintDecl) {\n          // nothing to do\n        }\n        else {\n          Contract.Assert(false); throw new cce.UnreachableException();  // unexpected member type\n        }\n      }\n\n      currentClass = null;\n    }\n\n    void InheritTraitMembers(ClassDecl cl) {\n      Contract.Requires(cl != null);\n\n      var refinementTransformer = new RefinementTransformer(reporter);\n      //merging class members with parent members if any\n      var clMembers = classMembers[cl];\n      foreach (TraitDecl trait in cl.TraitsObj) {\n        //merging current class members with the inheriting trait\n        foreach (var traitMember in trait.Members) {\n          var clMember = clMembers[traitMember.Name];\n          if (clMember == traitMember) {\n            // The member is the one inherited from the trait (and the class does not itself define a member with this name).  This\n            // is fine for fields and for functions and methods with bodies.  However, for a body-less function or method, the class\n            // is required to at least redeclare the member with its signature.  (It should also provide a stronger specification,\n            // but that will be checked by the verifier.  And it should also have a body, but that will be checked by the compiler.)\n            if (traitMember is Field) {\n              var field = (Field)traitMember;\n              if (!field.IsStatic) {\n                cl.InheritedMembers.Add(field);\n              }\n            } else if (traitMember is Function) {\n              var func = (Function)traitMember;\n              if (func.Body == null) {\n                reporter.Error(MessageSource.Resolver, cl.tok, \"class '{0}' does not implement trait function '{1}.{2}'\", cl.Name, trait.Name, traitMember.Name);\n              } else if (!func.IsStatic) {\n                cl.InheritedMembers.Add(func);\n              }\n            } else if (traitMember is Method) {\n              var method = (Method)traitMember;\n              if (method.Body == null) {\n                reporter.Error(MessageSource.Resolver, cl.tok, \"class '{0}' does not implement trait method '{1}.{2}'\", cl.Name, trait.Name, traitMember.Name);\n              } else if (!method.IsStatic) {\n                cl.InheritedMembers.Add(method);\n              }\n            }\n          } else if (clMember.EnclosingClass != cl) {\n            // The class inherits the member from two places\n            reporter.Error(MessageSource.Resolver, clMember.tok, \"member name '{0}' in class '{1}' inherited from both traits '{2}' and '{3}'\", traitMember.Name, cl.Name, clMember.EnclosingClass.Name, trait.Name);\n\n          } else if (traitMember is Field) {\n            // The class is not allowed to do anything with the field other than silently inherit it.\n            if (clMember is Field) {\n              reporter.Error(MessageSource.Resolver, clMember.tok, \"field '{0}' is inherited from trait '{1}' and is not allowed to be re-declared\", traitMember.Name, trait.Name);\n            } else {\n              reporter.Error(MessageSource.Resolver, clMember.tok, \"member name '{0}' in class '{1}' clashes with inherited field from trait '{2}'\", traitMember.Name, cl.Name, trait.Name);\n            }\n\n          } else if (traitMember is Method) {\n            var traitMethod = (Method)traitMember;\n            if (traitMethod.Body != null) {\n              // The method was defined in the trait, so the class is not allowed to do anything with the method other than silently inherit it.\n              reporter.Error(MessageSource.Resolver, clMember.tok, \"member '{0}' in class '{1}' overrides fully defined method inherited from trait '{2}'\", clMember.Name, cl.Name, trait.Name);\n            } else if (!(clMember is Method)) {\n              reporter.Error(MessageSource.Resolver, clMember.tok, \"non-method member '{0}' overrides method '{1}' inherited from trait '{2}'\", clMember.Name, traitMethod.Name, trait.Name);\n            } else {\n              var classMethod = (Method)clMember;\n\n              // Copy trait's extern attribute onto class if class does not provide one\n              if(!Attributes.Contains(classMethod.Attributes, \"extern\") && Attributes.Contains(traitMethod.Attributes, \"extern\")) {\n                var traitExternArgs = Attributes.FindExpressions(traitMethod.Attributes, \"extern\");\n                classMethod.Attributes = new Attributes(\"extern\", traitExternArgs, classMethod.Attributes);\n              }\n\n              classMethod.OverriddenMethod = traitMethod;\n              //adding a call graph edge from the trait method to that of class\n              cl.Module.CallGraph.AddEdge(traitMethod, classMethod);\n\n              refinementTransformer.CheckOverride_MethodParameters(classMethod, traitMethod);\n\n              var traitMethodAllowsNonTermination = Contract.Exists(traitMethod.Decreases.Expressions, e => e is WildcardExpr);\n              var classMethodAllowsNonTermination = Contract.Exists(classMethod.Decreases.Expressions, e => e is WildcardExpr);\n              if (classMethodAllowsNonTermination && !traitMethodAllowsNonTermination) {\n                reporter.Error(MessageSource.Resolver, classMethod.tok, \"not allowed to override a terminating method with a possibly non-terminating method ('{0}')\", classMethod.Name);\n              }\n            }\n\n          } else if (traitMember is Function) {\n            var traitFunction = (Function)traitMember;\n            if (traitFunction.Body != null) {\n              // The function was defined in the trait, so the class is not allowed to do anything with the function other than silently inherit it.\n              reporter.Error(MessageSource.Resolver, clMember.tok, \"member '{0}' in class '{1}' overrides fully defined function inherited from trait '{2}'\", clMember.Name, cl.Name, trait.Name);\n            } else if (!(clMember is Function)) {\n              reporter.Error(MessageSource.Resolver, clMember.tok, \"non-function member '{0}' overrides function '{1}' inherited from trait '{2}'\", clMember.Name, traitFunction.Name, trait.Name);\n            } else {\n              var classFunction = (Function)clMember;\n              classFunction.OverriddenFunction = traitFunction;\n              //adding a call graph edge from the trait method to that of class\n              cl.Module.CallGraph.AddEdge(traitFunction, classFunction);\n\n              refinementTransformer.CheckOverride_FunctionParameters(classFunction, traitFunction);\n            }\n\n          } else {\n            Contract.Assert(false);  // unexpected member\n          }\n        }\n      }\n    }\n\n    /// <summary>\n    /// Assumes type parameters have already been pushed, and that all types in class members have been resolved\n    /// </summary>\n    void ResolveClassMemberBodies(TopLevelDeclWithMembers cl) {\n      Contract.Requires(cl != null);\n      Contract.Requires(currentClass == null);\n      Contract.Requires(AllTypeConstraints.Count == 0);\n      Contract.Ensures(currentClass == null);\n      Contract.Ensures(AllTypeConstraints.Count == 0);\n\n      currentClass = cl;\n      foreach (MemberDecl member in cl.Members) {\n        Contract.Assert(VisibleInScope(member));\n        if (member is ConstantField) {\n          // don't do anything here, because const fields have already been resolved\n        } else if (member is Field) {\n          var opts = new ResolveOpts(new NoContext(currentClass.Module), false);\n          ResolveAttributes(member.Attributes, member, opts);\n        } else if (member is Function) {\n          var f = (Function)member;\n          var ec = reporter.Count(ErrorLevel.Error);\n          allTypeParameters.PushMarker();\n          ResolveTypeParameters(f.TypeArgs, false, f);\n          ResolveFunction(f);\n          allTypeParameters.PopMarker();\n          if (f is FixpointPredicate && ec == reporter.Count(ErrorLevel.Error)) {\n            var ff = ((FixpointPredicate)f).PrefixPredicate;\n            if (ff != null) {\n              allTypeParameters.PushMarker();\n              ResolveTypeParameters(ff.TypeArgs, false, ff);\n              ResolveFunction(ff);\n              allTypeParameters.PopMarker();\n            }\n          }\n\n        } else if (member is Method) {\n          var m = (Method)member;\n          var ec = reporter.Count(ErrorLevel.Error);\n          allTypeParameters.PushMarker();\n          ResolveTypeParameters(m.TypeArgs, false, m);\n          ResolveMethod(m);\n          allTypeParameters.PopMarker();\n        } else if (member is GlobalInvariantDecl) {\n          var gid = (GlobalInvariantDecl)member;\n          ResolveExpression(gid.Body, new ResolveOpts(new NoContext(currentClass.Module), false));\n          SolveAllTypeConstraints();\n        } else if (member is YieldPredicateDecl) {\n          var ydecl = (YieldPredicateDecl)member;\n          ResolveExpression(ydecl.Body, new ResolveOpts(new NoContext(currentClass.Module), true));\n          SolveAllTypeConstraints();\n        } else if (member is UniversalStepConstraintDecl) {\n          var udecl = (UniversalStepConstraintDecl)member;\n          if (udecl.Body != null) {\n            ResolveExpression(udecl.Body, new ResolveOpts(new NoContext(currentClass.Module), false));\n          }\n          SolveAllTypeConstraints();\n        } else {\n          Contract.Assert(false); throw new cce.UnreachableException();  // unexpected member type\n        }\n        Contract.Assert(AllTypeConstraints.Count == 0);\n      }\n      currentClass = null;\n    }\n\n    /// <summary>\n    /// Checks if \"expr\" is a constant (that is, heap independent) expression that can be assigned to \"field\".\n    /// If it is, return \"true\". Otherwise, report an error and return \"false\".\n    /// This method also adds dependency edges to the module's call graph and checks for self-loops. If a self-loop\n    /// is detected, \"false\" is returned.\n    /// </summary>\n    bool CheckIsConstantExpr(ConstantField field, Expression expr) {\n      Contract.Requires(field != null);\n      Contract.Requires(expr != null);\n      if (expr is MemberSelectExpr) {\n        var e = (MemberSelectExpr)expr;\n        if (e.Member is Field && ((Field)e.Member).IsMutable) {\n          reporter.Error(MessageSource.Resolver, field.tok, \"only constants are allowed in the expression to initialize constant {0}\", field.Name);\n          return false;\n        }\n        if (e.Member is ICallable) {\n          var other = (ICallable)e.Member;\n          field.EnclosingModule.CallGraph.AddEdge(field, other);\n        }\n        // okay so far; now, go on checking subexpressions\n      }\n      return expr.SubExpressions.All(e => CheckIsConstantExpr(field, e));\n    }\n\n    /// <summary>\n    /// Assumes type parameters have already been pushed\n    /// </summary>\n    void ResolveCtorTypes(DatatypeDecl/*!*/ dt, Graph<IndDatatypeDecl/*!*/>/*!*/ dependencies, Graph<CoDatatypeDecl/*!*/>/*!*/ coDependencies) {\n      Contract.Requires(dt != null);\n      Contract.Requires(dependencies != null);\n      Contract.Requires(coDependencies != null);\n      foreach (DatatypeCtor ctor in dt.Ctors) {\n\n        ctor.EnclosingDatatype = dt;\n\n        allTypeParameters.PushMarker();\n        ResolveCtorSignature(ctor, dt.TypeArgs);\n        allTypeParameters.PopMarker();\n\n        if (dt is IndDatatypeDecl) {\n          // The dependencies of interest among inductive datatypes are all (inductive data)types mentioned in the parameter types\n          var idt = (IndDatatypeDecl)dt;\n          dependencies.AddVertex(idt);\n          foreach (Formal p in ctor.Formals) {\n            AddDatatypeDependencyEdge(idt, p.Type, dependencies);\n          }\n        } else {\n          // The dependencies of interest among codatatypes are just the top-level types of parameters.\n          var codt = (CoDatatypeDecl)dt;\n          coDependencies.AddVertex(codt);\n          foreach (var p in ctor.Formals) {\n            var co = p.Type.AsCoDatatype;\n            if (co != null && codt.Module == co.Module) {\n              coDependencies.AddEdge(codt, co);\n            }\n          }\n        }\n      }\n    }\n\n    void AddDatatypeDependencyEdge(IndDatatypeDecl dt, Type tp, Graph<IndDatatypeDecl> dependencies) {\n      Contract.Requires(dt != null);\n      Contract.Requires(tp != null);\n      Contract.Requires(dependencies != null);  // more expensive check: Contract.Requires(cce.NonNullElements(dependencies));\n\n      tp = tp.NormalizeExpand();\n      var dependee = tp.AsIndDatatype;\n      if (dependee != null && dt.Module == dependee.Module) {\n        dependencies.AddEdge(dt, dependee);\n        foreach (var ta in ((UserDefinedType)tp).TypeArgs) {\n          AddDatatypeDependencyEdge(dt, ta, dependencies);\n        }\n      }\n    }\n\n    /// <summary>\n    /// Check that the SCC of 'startingPoint' can be carved up into stratospheres in such a way that each\n    /// datatype has some value that can be constructed from datatypes in lower stratospheres only.\n    /// The algorithm used here is quadratic in the number of datatypes in the SCC.  Since that number is\n    /// deemed to be rather small, this seems okay.\n    ///\n    /// As a side effect of this checking, the DefaultCtor field is filled in (for every inductive datatype\n    /// that passes the check).  It may be that several constructors could be used as the default, but\n    /// only the first one encountered as recorded.  This particular choice is slightly more than an\n    /// implementation detail, because it affects how certain cycles among inductive datatypes (having\n    /// to do with the types used to instantiate type parameters of datatypes) are used.\n    ///\n    /// The role of the SCC here is simply to speed up this method.  It would still be correct if the\n    /// equivalence classes in the given SCC were unions of actual SCC's.  In particular, this method\n    /// would still work if \"dependencies\" consisted of one large SCC containing all the inductive\n    /// datatypes in the module.\n    /// </summary>\n    void SccStratosphereCheck(IndDatatypeDecl startingPoint, Graph<IndDatatypeDecl/*!*/>/*!*/ dependencies) {\n      Contract.Requires(startingPoint != null);\n      Contract.Requires(dependencies != null);  // more expensive check: Contract.Requires(cce.NonNullElements(dependencies));\n\n      var scc = dependencies.GetSCC(startingPoint);\n      int totalCleared = 0;\n      while (true) {\n        int clearedThisRound = 0;\n        foreach (var dt in scc) {\n          if (dt.DefaultCtor != null) {\n            // previously cleared\n          } else if (ComputeDefaultCtor(dt)) {\n            Contract.Assert(dt.DefaultCtor != null);  // should have been set by the successful call to StratosphereCheck)\n            clearedThisRound++;\n            totalCleared++;\n          }\n        }\n        if (totalCleared == scc.Count) {\n          // all is good\n          return;\n        } else if (clearedThisRound != 0) {\n          // some progress was made, so let's keep going\n        } else {\n          // whatever is in scc-cleared now failed to pass the test\n          foreach (var dt in scc) {\n            if (dt.DefaultCtor == null) {\n              reporter.Error(MessageSource.Resolver, dt, \"because of cyclic dependencies among constructor argument types, no instances of datatype '{0}' can be constructed\", dt.Name);\n            }\n          }\n          return;\n        }\n      }\n    }\n\n    /// <summary>\n    /// Check that the datatype has some constructor all whose argument types can be constructed.\n    /// Returns 'true' and sets dt.DefaultCtor if that is the case.\n    /// </summary>\n    bool ComputeDefaultCtor(IndDatatypeDecl dt) {\n      Contract.Requires(dt != null);\n      Contract.Requires(dt.DefaultCtor == null);  // the intention is that this method be called only when DefaultCtor hasn't already been set\n      Contract.Ensures(!Contract.Result<bool>() || dt.DefaultCtor != null);\n\n      // Stated differently, check that there is some constuctor where no argument type goes to the same stratum.\n      DatatypeCtor defaultCtor = null;\n      List<TypeParameter> lastTypeParametersUsed = null;\n      foreach (DatatypeCtor ctor in dt.Ctors) {\n        List<TypeParameter>  typeParametersUsed = new List<TypeParameter>();\n        foreach (Formal p in ctor.Formals) {\n          if (!CheckCanBeConstructed(p.Type, typeParametersUsed)) {\n            // the argument type (has a component which) is not yet known to be constructable\n            goto NEXT_OUTER_ITERATION;\n          }\n        }\n        // this constructor satisfies the requirements, check to see if it is a better fit than the\n        // one found so far. By \"better\" it means fewer type arguments. Between the ones with\n        // the same number of the type arguments, pick the one shows first.\n        if (defaultCtor == null || typeParametersUsed.Count < lastTypeParametersUsed.Count)  {\n          defaultCtor = ctor;\n          lastTypeParametersUsed = typeParametersUsed;\n        }\n\n      NEXT_OUTER_ITERATION: { }\n      }\n\n      if (defaultCtor != null) {\n        dt.DefaultCtor = defaultCtor;\n        dt.TypeParametersUsedInConstructionByDefaultCtor = new bool[dt.TypeArgs.Count];\n        for (int i = 0; i < dt.TypeArgs.Count; i++) {\n          dt.TypeParametersUsedInConstructionByDefaultCtor[i] = lastTypeParametersUsed.Contains(dt.TypeArgs[i]);\n        }\n        return true;\n      }\n\n      // no constructor satisfied the requirements, so this is an illegal datatype declaration\n      return false;\n    }\n\n    bool CheckCanBeConstructed(Type tp, List<TypeParameter> typeParametersUsed) {\n      tp = tp.NormalizeExpand();\n      var dependee = tp.AsIndDatatype;\n      if (dependee == null) {\n        // the type is not an inductive datatype, which means it is always possible to construct it\n        if (tp.IsTypeParameter) {\n          typeParametersUsed.Add(((UserDefinedType)tp).ResolvedParam);\n        }\n        return true;\n      } else if (dependee.DefaultCtor == null) {\n        // the type is an inductive datatype that we don't yet know how to construct\n        return false;\n      }\n      // also check the type arguments of the inductive datatype\n      Contract.Assert(((UserDefinedType)tp).TypeArgs.Count == dependee.TypeParametersUsedInConstructionByDefaultCtor.Length);\n      var i = 0;\n      foreach (var ta in ((UserDefinedType)tp).TypeArgs) {  // note, \"tp\" is known to be a UserDefinedType, because that follows from tp being an inductive datatype\n        if (dependee.TypeParametersUsedInConstructionByDefaultCtor[i] && !CheckCanBeConstructed(ta, typeParametersUsed)) {\n          return false;\n        }\n        i++;\n      }\n      return true;\n    }\n\n    void DetermineEqualitySupport(IndDatatypeDecl startingPoint, Graph<IndDatatypeDecl/*!*/>/*!*/ dependencies) {\n      Contract.Requires(startingPoint != null);\n      Contract.Requires(dependencies != null);  // more expensive check: Contract.Requires(cce.NonNullElements(dependencies));\n\n      var scc = dependencies.GetSCC(startingPoint);\n      // First, the simple case:  If any parameter of any inductive datatype in the SCC is of a codatatype type, then\n      // the whole SCC is incapable of providing the equality operation.  Also, if any parameter of any inductive datatype\n      // is a ghost, then the whole SCC is incapable of providing the equality operation.\n      foreach (var dt in scc) {\n        Contract.Assume(dt.EqualitySupport == IndDatatypeDecl.ES.NotYetComputed);\n        foreach (var ctor in dt.Ctors) {\n          foreach (var arg in ctor.Formals) {\n            var anotherIndDt = arg.Type.AsIndDatatype;\n            if (arg.IsGhost ||\n                (anotherIndDt != null && anotherIndDt.EqualitySupport == IndDatatypeDecl.ES.Never) ||\n                arg.Type.IsCoDatatype ||\n                arg.Type.IsArrowType) {\n              // arg.Type is known never to support equality\n              // So, go around the entire SCC and record what we learnt\n              foreach (var ddtt in scc) {\n                ddtt.EqualitySupport = IndDatatypeDecl.ES.Never;\n              }\n              return;  // we are done\n            }\n          }\n        }\n      }\n\n      // Now for the more involved case:  we need to determine which type parameters determine equality support for each datatype in the SCC\n      // We start by seeing where each datatype's type parameters are used in a place known to determine equality support.\n      bool thingsChanged = false;\n      foreach (var dt in scc) {\n        if (dt.TypeArgs.Count == 0) {\n          // if the datatype has no type parameters, we certainly won't find any type parameters being used in the arguments types to the constructors\n          continue;\n        }\n        foreach (var ctor in dt.Ctors) {\n          foreach (var arg in ctor.Formals) {\n            var typeArg = arg.Type.AsTypeParameter;\n            if (typeArg != null) {\n              typeArg.NecessaryForEqualitySupportOfSurroundingInductiveDatatype = true;\n              thingsChanged = true;\n            } else {\n              var otherDt = arg.Type.AsIndDatatype;\n              if (otherDt != null && otherDt.EqualitySupport == IndDatatypeDecl.ES.ConsultTypeArguments) {  // datatype is in a different SCC\n                var otherUdt = (UserDefinedType)arg.Type.NormalizeExpand();\n                var i = 0;\n                foreach (var otherTp in otherDt.TypeArgs) {\n                  if (otherTp.NecessaryForEqualitySupportOfSurroundingInductiveDatatype) {\n                    var tp = otherUdt.TypeArgs[i].AsTypeParameter;\n                    if (tp != null) {\n                      tp.NecessaryForEqualitySupportOfSurroundingInductiveDatatype = true;\n                      thingsChanged = true;\n                    }\n                  }\n                }\n              }\n            }\n          }\n        }\n      }\n      // Then we propagate this information up through the SCC\n      while (thingsChanged) {\n        thingsChanged = false;\n        foreach (var dt in scc) {\n          if (dt.TypeArgs.Count == 0) {\n            // if the datatype has no type parameters, we certainly won't find any type parameters being used in the arguments types to the constructors\n            continue;\n          }\n          foreach (var ctor in dt.Ctors) {\n            foreach (var arg in ctor.Formals) {\n              var otherDt = arg.Type.AsIndDatatype;\n              if (otherDt != null && otherDt.EqualitySupport == IndDatatypeDecl.ES.NotYetComputed) { // otherDt lives in the same SCC\n                var otherUdt = (UserDefinedType)arg.Type.NormalizeExpand();\n                var i = 0;\n                foreach (var otherTp in otherDt.TypeArgs) {\n                  if (otherTp.NecessaryForEqualitySupportOfSurroundingInductiveDatatype) {\n                    var tp = otherUdt.TypeArgs[i].AsTypeParameter;\n                    if (tp != null && !tp.NecessaryForEqualitySupportOfSurroundingInductiveDatatype) {\n                      tp.NecessaryForEqualitySupportOfSurroundingInductiveDatatype = true;\n                      thingsChanged = true;\n                    }\n                  }\n                  i++;\n                }\n              }\n            }\n          }\n        }\n      }\n      // Now that we have computed the .NecessaryForEqualitySupportOfSurroundingInductiveDatatype values, mark the datatypes as ones\n      // where equality support should be checked by looking at the type arguments.\n      foreach (var dt in scc) {\n        dt.EqualitySupport = IndDatatypeDecl.ES.ConsultTypeArguments;\n      }\n    }\n\n    void ResolveAttributes(Attributes attrs, IAttributeBearingDeclaration attributeHost, ResolveOpts opts) {\n      Contract.Requires(opts != null);\n      // order does not matter much for resolution, so resolve them in reverse order\n      foreach (var attr in attrs.AsEnumerable()) {\n        if (attributeHost != null && attr is UserSuppliedAttributes) {\n          var usa = (UserSuppliedAttributes)attr;\n          usa.Recognized = IsRecognizedAttribute(usa, attributeHost);\n        }\n        if (attr.Args != null) {\n          foreach (var arg in attr.Args) {\n            Contract.Assert(arg != null);\n            int prevErrors = reporter.Count(ErrorLevel.Error);\n            ResolveExpression(arg, opts);\n            if (prevErrors == reporter.Count(ErrorLevel.Error)) {\n              CheckTypeInference(arg, opts.codeContext);\n            }\n          }\n        }\n      }\n    }\n\n    /// <summary>\n    /// Check to see if the attribute is one that is supported by Dafny.  What check performed here is,\n    /// unfortunately, just an approximation, since the usage rules of a particular attribute is checked\n    /// elsewhere (for example, in the compiler or verifier).  It would be nice to improve this.\n    /// </summary>\n    bool IsRecognizedAttribute(UserSuppliedAttributes a, IAttributeBearingDeclaration host) {\n      Contract.Requires(a != null);\n      Contract.Requires(host != null);\n      switch (a.Name) {\n        case \"opaque\":\n          return host is Function && !(host is FixpointPredicate);\n        case \"trigger\":\n          return host is ComprehensionExpr || host is SetComprehension || host is MapComprehension;\n        case \"timeLimit\":\n        case \"timeLimitMultiplier\":\n          return host is TopLevelDecl;\n        case \"tailrecursive\":\n          return host is Method && !((Method)host).IsGhost;\n        case \"autocontracts\":\n          return host is ClassDecl;\n        case \"autoreq\":\n          return host is Function;\n        case \"abstemious\":\n          return host is Function;\n        default:\n          return false;\n      }\n    }\n\n    void ResolveTypeParameters(List<TypeParameter/*!*/>/*!*/ tparams, bool emitErrors, TypeParameter.ParentType/*!*/ parent) {\n      Contract.Requires(tparams != null);\n      Contract.Requires(parent != null);\n      // push non-duplicated type parameter names\n      int index = 0;\n      foreach (TypeParameter tp in tparams) {\n        if (emitErrors) {\n          // we're seeing this TypeParameter for the first time\n          tp.Parent = parent;\n          tp.PositionalIndex = index;\n        }\n        var r = allTypeParameters.Push(tp.Name, tp);\n        if (emitErrors) {\n          if (r == Scope<TypeParameter>.PushResult.Duplicate) {\n            reporter.Error(MessageSource.Resolver, tp, \"Duplicate type-parameter name: {0}\", tp.Name);\n          } else if (r == Scope<TypeParameter>.PushResult.Shadow) {\n            reporter.Warning(MessageSource.Resolver, tp.tok, \"Shadowed type-parameter name: {0}\", tp.Name);\n          }\n        }\n      }\n    }\n\n    void ScopePushAndReport(Scope<IVariable> scope, IVariable v, string kind) {\n      Contract.Requires(scope != null);\n      Contract.Requires(v != null);\n      Contract.Requires(kind != null);\n      ScopePushAndReport(scope, v.Name, v, v.Tok, kind);\n    }\n\n    void ScopePushAndReport<Thing>(Scope<Thing> scope, string name, Thing thing, IToken tok, string kind) where Thing : class {\n      Contract.Requires(scope != null);\n      Contract.Requires(name != null);\n      Contract.Requires(thing != null);\n      Contract.Requires(tok != null);\n      Contract.Requires(kind != null);\n      var r = scope.Push(name, thing);\n      switch (r) {\n        case Scope<Thing>.PushResult.Success:\n          break;\n        case Scope<Thing>.PushResult.Duplicate:\n          reporter.Error(MessageSource.Resolver, tok, \"Duplicate {0} name: {1}\", kind, name);\n          break;\n        case Scope<Thing>.PushResult.Shadow:\n          reporter.Warning(MessageSource.Resolver, tok, \"Shadowed {0} name: {1}\", kind, name);\n          break;\n      }\n    }\n\n    /// <summary>\n    /// Assumes type parameters have already been pushed\n    /// </summary>\n    void ResolveFunctionSignature(Function f) {\n      Contract.Requires(f != null);\n      scope.PushMarker();\n      if (f.SignatureIsOmitted) {\n        reporter.Error(MessageSource.Resolver, f, \"function signature can be omitted only in refining functions\");\n      }\n      var option = f.TypeArgs.Count == 0 ? new ResolveTypeOption(f) : new ResolveTypeOption(ResolveTypeOptionEnum.AllowPrefix);\n      foreach (Formal p in f.Formals) {\n        ScopePushAndReport(scope, p, \"parameter\");\n        ResolveType(p.tok, p.Type, f, option, f.TypeArgs);\n        AddTypeDependencyEdges(f, p.Type);\n      }\n      if (f.Result != null) {\n        ScopePushAndReport(scope, f.Result, \"parameter/return\");\n        ResolveType(f.Result.tok, f.Result.Type, f, option, f.TypeArgs);\n      } else {\n        ResolveType(f.tok, f.ResultType, f, option, f.TypeArgs);\n      }\n      AddTypeDependencyEdges(f, f.ResultType);\n      scope.PopMarker();\n    }\n\n    /// <summary>\n    /// Assumes type parameters have already been pushed\n    /// </summary>\n    void ResolveFunction(Function f) {\n      Contract.Requires(f != null);\n      Contract.Requires(AllTypeConstraints.Count == 0);\n      Contract.Ensures(AllTypeConstraints.Count == 0);\n\n      bool warnShadowingOption = ArmadaOptions.O.WarnShadowing;  // save the original warnShadowing value\n      bool warnShadowing = false;\n\n      scope.PushMarker();\n      if (f.IsStatic) {\n        scope.AllowInstance = false;\n      }\n      foreach (Formal p in f.Formals) {\n        scope.Push(p.Name, p);\n      }\n      ResolveAttributes(f.Attributes, f, new ResolveOpts(f, false));\n      // take care of the warnShadowing attribute\n      if (Attributes.ContainsBool(f.Attributes, \"warnShadowing\", ref warnShadowing)) {\n        ArmadaOptions.O.WarnShadowing = warnShadowing;  // set the value according to the attribute\n      }\n      foreach (MaybeFreeExpression e in f.Req) {\n        Expression r = e.E;\n        ResolveExpression(r, new ResolveOpts(f, f is TwoStateFunction));\n        Contract.Assert(r.Type != null);  // follows from postcondition of ResolveExpression\n        ConstrainTypeExprBool(r, \"Precondition must be a boolean (got {0})\");\n      }\n      foreach (FrameExpression fr in f.Reads) {\n        ResolveFrameExpression(fr, FrameExpressionUse.Reads, f);\n      }\n      foreach (MaybeFreeExpression e in f.Ens) {\n        Expression r = e.E;\n        if (f.Result != null) {\n          scope.PushMarker();\n          scope.Push(f.Result.Name, f.Result);  // function return only visible in post-conditions\n        }\n        ResolveExpression(r, new ResolveOpts(f, f is TwoStateFunction, false, true, false));  // since this is a function, the postcondition is still a one-state predicate, unless it's a two-state function\n        Contract.Assert(r.Type != null);  // follows from postcondition of ResolveExpression\n        ConstrainTypeExprBool(r, \"Postcondition must be a boolean (got {0})\");\n        if (f.Result != null) {\n          scope.PopMarker();\n        }\n      }\n      ResolveAttributes(f.Decreases.Attributes, null, new ResolveOpts(f, f is TwoStateFunction));\n      foreach (Expression r in f.Decreases.Expressions) {\n        ResolveExpression(r, new ResolveOpts(f, f is TwoStateFunction));\n        // any type is fine\n      }\n      SolveAllTypeConstraints();\n\n      if (f.Body != null) {\n        var prevErrorCount = reporter.Count(ErrorLevel.Error);\n        ResolveExpression(f.Body, new ResolveOpts(f, f is TwoStateFunction));\n        Contract.Assert(f.Body.Type != null);  // follows from postcondition of ResolveExpression\n        AddAssignableConstraint(f.tok, f.ResultType, f.Body.Type, \"Function body type mismatch (expected {0}, got {1})\");\n        SolveAllTypeConstraints();\n      }\n\n      scope.PopMarker();\n\n      ArmadaOptions.O.WarnShadowing = warnShadowingOption; // restore the original warnShadowing value\n    }\n\n    public enum FrameExpressionUse { Reads, Modifies, Unchanged }\n\n    void ResolveFrameExpression(FrameExpression fe, FrameExpressionUse use, ICodeContext codeContext) {\n      Contract.Requires(fe != null);\n      Contract.Requires(codeContext != null);\n      ResolveExpression(fe.E, new ResolveOpts(codeContext, codeContext is TwoStateLemma || use == FrameExpressionUse.Unchanged));\n      Type t = fe.E.Type;\n      Contract.Assert(t != null);  // follows from postcondition of ResolveExpression\n      var eventualRefType = new InferredTypeProxy();\n      if (use == FrameExpressionUse.Reads) {\n        AddXConstraint(fe.E.tok, \"ReadsFrame\", t, eventualRefType, \"a reads-clause expression must denote an object or a collection of objects (instead got {0})\");\n      } else {\n          /*\n        AddXConstraint(fe.E.tok, \"ModifiesFrame\", t, eventualRefType,\n          use == FrameExpressionUse.Modifies ?\n          \"a modifies-clause expression must denote an object or a collection of objects (instead got {0})\" :\n          \"an unchanged expression must denote an object or a collection of objects (instead got {0})\");\n          */\n      }\n      if (fe.FieldName != null) {\n        NonProxyType nptype;\n        MemberDecl member = ResolveMember(fe.E.tok, eventualRefType, fe.FieldName, out nptype);\n        UserDefinedType ctype = (UserDefinedType)nptype;  // correctness of cast follows from the DenotesClass test above\n        if (member == null) {\n          // error has already been reported by ResolveMember\n        } else if (!(member is Field)) {\n          reporter.Error(MessageSource.Resolver, fe.E, \"member {0} in type {1} does not refer to a field\", fe.FieldName, ctype.Name);\n        } else if (member is ConstantField) {\n          reporter.Error(MessageSource.Resolver, fe.E, \"expression is not allowed to refer to constant field {0}\", fe.FieldName);\n        } else {\n          Contract.Assert(ctype != null && ctype.ResolvedClass != null);  // follows from postcondition of ResolveMember\n          fe.Field = (Field)member;\n        }\n      }\n    }\n\n    /// <summary>\n    /// This method can be called even if the resolution of \"fe\" failed; in that case, this method will\n    /// not issue any error message.\n    /// </summary>\n    void DisallowNonGhostFieldSpecifiers(FrameExpression fe) {\n      Contract.Requires(fe != null);\n      if (fe.Field != null && !fe.Field.IsGhost) {\n        reporter.Error(MessageSource.Resolver, fe.E, \"in a ghost context, only ghost fields can be mentioned as modifies frame targets ({0})\", fe.FieldName);\n      }\n    }\n\n    /// <summary>\n    /// Assumes type parameters have already been pushed\n    /// </summary>\n    void ResolveMethodSignature(Method m) {\n      Contract.Requires(m != null);\n\n      scope.PushMarker();\n      if (m.SignatureIsOmitted) {\n        reporter.Error(MessageSource.Resolver, m, \"method signature can be omitted only in refining methods\");\n      }\n      var option = m.TypeArgs.Count == 0 ? new ResolveTypeOption(m) : new ResolveTypeOption(ResolveTypeOptionEnum.AllowPrefix);\n      // resolve in-parameters\n      foreach (Formal p in m.Ins) {\n        ScopePushAndReport(scope, p, \"parameter\");\n        ResolveType(p.tok, p.Type, m, option, m.TypeArgs);\n        AddTypeDependencyEdges(m, p.Type);\n      }\n      // resolve out-parameters\n      foreach (Formal p in m.Outs) {\n        ScopePushAndReport(scope, p, \"parameter\");\n        ResolveType(p.tok, p.Type, m, option, m.TypeArgs);\n        AddTypeDependencyEdges(m, p.Type);\n      }\n      scope.PopMarker();\n    }\n\n    /// <summary>\n    /// Assumes type parameters have already been pushed\n    /// </summary>\n    void ResolveMethod(Method m) {\n      Contract.Requires(m != null);\n      Contract.Requires(AllTypeConstraints.Count == 0);\n      Contract.Ensures(AllTypeConstraints.Count == 0);\n\n      try {\n        currentMethod = m;\n\n        bool warnShadowingOption = ArmadaOptions.O.WarnShadowing;  // save the original warnShadowing value\n        bool warnShadowing = false;\n        // take care of the warnShadowing attribute\n        if (Attributes.ContainsBool(m.Attributes, \"warnShadowing\", ref warnShadowing)) {\n          ArmadaOptions.O.WarnShadowing = warnShadowing;  // set the value according to the attribute\n        }\n\n        // Add in-parameters to the scope, but don't care about any duplication errors, since they have already been reported\n        scope.PushMarker();\n        if (m.IsStatic || m is Constructor) {\n          scope.AllowInstance = false;\n        }\n        foreach (Formal p in m.Ins) {\n          scope.Push(p.Name, p);\n        }\n\n        // Start resolving specification...\n        foreach (MaybeFreeExpression e in m.Req) {\n          ResolveAttributes(e.Attributes, null, new ResolveOpts(m, m is TwoStateLemma));\n          ResolveExpression(e.E, new ResolveOpts(m, m is TwoStateLemma));\n          Contract.Assert(e.E.Type != null);  // follows from postcondition of ResolveExpression\n          ConstrainTypeExprBool(e.E, \"Precondition must be a boolean (got {0})\");\n        }\n\n        ResolveAttributes(m.Mod.Attributes, null, new ResolveOpts(m, false));\n        foreach (FrameExpression fe in m.Mod.Expressions) {\n          ResolveFrameExpression(fe, FrameExpressionUse.Modifies, m);\n          if (m is Lemma || m is TwoStateLemma || m is FixpointLemma) {\n            reporter.Error(MessageSource.Resolver, fe.tok, \"{0}s are not allowed to have modifies clauses\", m.WhatKind);\n          } else if (m.IsGhost) {\n            DisallowNonGhostFieldSpecifiers(fe);\n          }\n        }\n        ResolveAttributes(m.Decreases.Attributes, null, new ResolveOpts(m, false));\n        foreach (Expression e in m.Decreases.Expressions) {\n          ResolveExpression(e, new ResolveOpts(m, m is TwoStateLemma));\n          // any type is fine\n        }\n\n        foreach (Expression e in m.Reads.Expressions) {\n          ResolveExpression(e, new ResolveOpts(m, m is TwoStateLemma));\n          // any type is fine\n        }\n\n        foreach (Expression e in m.Awaits) {\n          ResolveExpression(e, new ResolveOpts(m, m is TwoStateLemma));\n          // any type is fine\n        }\n\n        foreach (Expression e in m.UndefinedUnless) {\n          ResolveExpression(e, new ResolveOpts(m, m is TwoStateLemma));\n          // any type is fine\n        }\n\n        if (m is Constructor) {\n          scope.PopMarker();\n          // start the scope again, but this time allowing instance\n          scope.PushMarker();\n          foreach (Formal p in m.Ins) {\n            scope.Push(p.Name, p);\n          }\n        }\n\n        // Add out-parameters to a new scope that will also include the outermost-level locals of the body\n        // Don't care about any duplication errors among the out-parameters, since they have already been reported\n        scope.PushMarker();\n        if (m is FixpointLemma && m.Outs.Count != 0) {\n          reporter.Error(MessageSource.Resolver, m.Outs[0].tok, \"{0}s are not allowed to have out-parameters\", m.WhatKind);\n        } else {\n          foreach (Formal p in m.Outs) {\n            scope.Push(p.Name, p);\n          }\n        }\n\n        // ... continue resolving specification\n        foreach (MaybeFreeExpression e in m.Ens) {\n          ResolveAttributes(e.Attributes, null, new ResolveOpts(m, true));\n          ResolveExpression(e.E, new ResolveOpts(m, true));\n          Contract.Assert(e.E.Type != null);  // follows from postcondition of ResolveExpression\n          ConstrainTypeExprBool(e.E, \"Postcondition must be a boolean (got {0})\");\n        }\n        SolveAllTypeConstraints();\n\n        // Resolve body\n        if (m.Body != null) {\n          var com = m as FixpointLemma;\n          if (com != null && com.PrefixLemma != null) {\n            // The body may mentioned the implicitly declared parameter _k.  Throw it into the\n            // scope before resolving the body.\n            var k = com.PrefixLemma.Ins[0];\n            scope.Push(k.Name, k);  // we expect no name conflict for _k\n          }\n\n          dominatingStatementLabels.PushMarker();\n          foreach (var req in m.Req) {\n            if (req.Label != null) {\n              if (dominatingStatementLabels.Find(req.Label.Name) != null) {\n                reporter.Error(MessageSource.Resolver, req.Label.Tok, \"assert label shadows a dominating label\");\n              } else {\n                var rr = dominatingStatementLabels.Push(req.Label.Name, req.Label);\n                Contract.Assert(rr == Scope<Label>.PushResult.Success);  // since we just checked for duplicates, we expect the Push to succeed\n              }\n            }\n          }\n          methodStatementLabels.PushMarker();\n          AddMethodStatementLabels(m.Body);\n          ResolveBlockStatement(m.Body, m);\n          dominatingStatementLabels.PopMarker();\n          methodStatementLabels.PopMarker();\n          SolveAllTypeConstraints();\n        }\n\n        // attributes are allowed to mention both in- and out-parameters (including the implicit _k, for colemmas)\n        ResolveAttributes(m.Attributes, m, new ResolveOpts(m, false));\n\n        ArmadaOptions.O.WarnShadowing = warnShadowingOption; // restore the original warnShadowing value\n        scope.PopMarker();  // for the out-parameters and outermost-level locals\n        scope.PopMarker();  // for the in-parameters\n      } finally {\n        currentMethod = null;\n      }\n    }\n\n    private void AddMethodStatementLabels(Statement s)\n    {\n      for (var lbl = s.Labels; lbl != null; lbl = lbl.Next) {\n        methodStatementLabels.Push(lbl.Data.Name, lbl.Data);\n      }\n      foreach (var substmt in s.SubStatements) {\n        AddMethodStatementLabels(substmt);\n      }\n    }\n\n    void ResolveCtorSignature(DatatypeCtor ctor, List<TypeParameter> dtTypeArguments) {\n      Contract.Requires(ctor != null);\n      Contract.Requires(ctor.EnclosingDatatype != null);\n      Contract.Requires(dtTypeArguments != null);\n      foreach (Formal p in ctor.Formals) {\n        ResolveType(p.tok, p.Type, ctor.EnclosingDatatype, ResolveTypeOptionEnum.AllowPrefix, dtTypeArguments);\n      }\n    }\n\n    /// <summary>\n    /// Assumes type parameters have already been pushed\n    /// </summary>\n    void ResolveIteratorSignature(IteratorDecl iter) {\n      Contract.Requires(iter != null);\n      scope.PushMarker();\n      if (iter.SignatureIsOmitted) {\n        reporter.Error(MessageSource.Resolver, iter, \"iterator signature can be omitted only in refining methods\");\n      }\n      var initiallyNoTypeArguments = iter.TypeArgs.Count == 0;\n      var option = initiallyNoTypeArguments ? new ResolveTypeOption(iter) : new ResolveTypeOption(ResolveTypeOptionEnum.AllowPrefix);\n      // resolve the types of the parameters\n      var prevErrorCount = reporter.Count(ErrorLevel.Error);\n      foreach (var p in iter.Ins.Concat(iter.Outs)) {\n        ResolveType(p.tok, p.Type, iter, option, iter.TypeArgs);\n      }\n      // resolve the types of the added fields (in case some of these types would cause the addition of default type arguments)\n      if (prevErrorCount == reporter.Count(ErrorLevel.Error)) {\n        foreach (var p in iter.OutsHistoryFields) {\n          ResolveType(p.tok, p.Type, iter, option, iter.TypeArgs);\n        }\n      }\n      if (iter.TypeArgs.Count != iter.NonNullTypeDecl.TypeArgs.Count) {\n        // Apparently, the type resolution automatically added type arguments to the iterator. We'll add these to the\n        // corresponding non-null type as well.\n        Contract.Assert(initiallyNoTypeArguments);\n        Contract.Assert(iter.NonNullTypeDecl.TypeArgs.Count == 0);\n        var nnt = iter.NonNullTypeDecl;\n        nnt.TypeArgs.AddRange(iter.TypeArgs.ConvertAll(tp => new TypeParameter(tp.tok, tp.Name, tp.VarianceSyntax, tp.Characteristics)));\n        var varUdt = (UserDefinedType)nnt.Var.Type;\n        Contract.Assert(varUdt.TypeArgs.Count == 0);\n        varUdt.TypeArgs = nnt.TypeArgs.ConvertAll(tp => (Type)new UserDefinedType(tp));\n      }\n      scope.PopMarker();\n    }\n\n    /// <summary>\n    /// Assumes type parameters have already been pushed\n    /// </summary>\n    void ResolveIterator(IteratorDecl iter) {\n      Contract.Requires(iter != null);\n      Contract.Requires(currentClass == null);\n      Contract.Ensures(currentClass == null);\n\n      var initialErrorCount = reporter.Count(ErrorLevel.Error);\n\n      // Add in-parameters to the scope, but don't care about any duplication errors, since they have already been reported\n      scope.PushMarker();\n      scope.AllowInstance = false;  // disallow 'this' from use, which means that the special fields and methods added are not accessible in the syntactically given spec\n      iter.Ins.ForEach(p => scope.Push(p.Name, p));\n\n      // Start resolving specification...\n      // we start with the decreases clause, because the _decreases<n> fields were only given type proxies before; we'll know\n      // the types only after resolving the decreases clause (and it may be that some of resolution has already seen uses of\n      // these fields; so, with no further ado, here we go\n      Contract.Assert(iter.Decreases.Expressions.Count == iter.DecreasesFields.Count);\n      for (int i = 0; i < iter.Decreases.Expressions.Count; i++) {\n        var e = iter.Decreases.Expressions[i];\n        ResolveExpression(e, new ResolveOpts(iter, false));\n        // any type is fine, but associate this type with the corresponding _decreases<n> field\n        var d = iter.DecreasesFields[i];\n        // If the following type constraint does not hold, then: unfortunately, there was a use--and a bad use--of the field before, so this won't be the best of error messages\n        ConstrainSubtypeRelation(d.Type, e.Type, e, \"type of field {0} is {1}, but has been constrained elsewhere to be of type {2}\", d.Name, e.Type, d.Type);\n      }\n      foreach (FrameExpression fe in iter.Reads.Expressions) {\n        ResolveFrameExpression(fe, FrameExpressionUse.Reads, iter);\n      }\n      foreach (FrameExpression fe in iter.Modifies.Expressions) {\n        ResolveFrameExpression(fe, FrameExpressionUse.Modifies, iter);\n      }\n      foreach (MaybeFreeExpression e in iter.Requires) {\n        ResolveExpression(e.E, new ResolveOpts(iter, false));\n        Contract.Assert(e.E.Type != null);  // follows from postcondition of ResolveExpression\n        ConstrainTypeExprBool(e.E, \"Precondition must be a boolean (got {0})\");\n      }\n\n      scope.PopMarker();  // for the in-parameters\n\n      // We resolve the rest of the specification in an instance context.  So mentions of the in- or yield-parameters\n      // get resolved as field dereferences (with an implicit \"this\")\n      scope.PushMarker();\n      currentClass = iter;\n      Contract.Assert(scope.AllowInstance);\n\n      foreach (MaybeFreeExpression e in iter.YieldRequires) {\n        ResolveExpression(e.E, new ResolveOpts(iter, false));\n        Contract.Assert(e.E.Type != null);  // follows from postcondition of ResolveExpression\n        ConstrainTypeExprBool(e.E, \"Yield precondition must be a boolean (got {0})\");\n      }\n      foreach (MaybeFreeExpression e in iter.YieldEnsures) {\n        ResolveExpression(e.E, new ResolveOpts(iter, true));\n        Contract.Assert(e.E.Type != null);  // follows from postcondition of ResolveExpression\n        ConstrainTypeExprBool(e.E, \"Yield postcondition must be a boolean (got {0})\");\n      }\n      foreach (MaybeFreeExpression e in iter.Ensures) {\n        ResolveExpression(e.E, new ResolveOpts(iter, true));\n        Contract.Assert(e.E.Type != null);  // follows from postcondition of ResolveExpression\n        ConstrainTypeExprBool(e.E, \"Postcondition must be a boolean (got {0})\");\n      }\n      SolveAllTypeConstraints();\n\n      ResolveAttributes(iter.Attributes, iter, new ResolveOpts(iter, false));\n\n      var postSpecErrorCount = reporter.Count(ErrorLevel.Error);\n\n      // Resolve body\n      if (iter.Body != null) {\n        dominatingStatementLabels.PushMarker();\n        foreach (var req in iter.Requires) {\n          if (req.Label != null) {\n            if (dominatingStatementLabels.Find(req.Label.Name) != null) {\n              reporter.Error(MessageSource.Resolver, req.Label.Tok, \"assert label shadows a dominating label\");\n            } else {\n              var rr = dominatingStatementLabels.Push(req.Label.Name, req.Label);\n              Contract.Assert(rr == Scope<Label>.PushResult.Success);  // since we just checked for duplicates, we expect the Push to succeed\n            }\n          }\n        }\n        ResolveBlockStatement(iter.Body, iter);\n        dominatingStatementLabels.PopMarker();\n        SolveAllTypeConstraints();\n      }\n\n      currentClass = null;\n      scope.PopMarker();  // pop off the AllowInstance setting\n\n      if (postSpecErrorCount == initialErrorCount) {\n        CreateIteratorMethodSpecs(iter);\n      }\n    }\n\n    /// <summary>\n    /// Assumes the specification of the iterator itself has been successfully resolved.\n    /// </summary>\n    void CreateIteratorMethodSpecs(IteratorDecl iter) {\n      Contract.Requires(iter != null);\n\n      // ---------- here comes the constructor ----------\n      // same requires clause as the iterator itself\n      iter.Member_Init.Req.AddRange(iter.Requires);\n      var ens = iter.Member_Init.Ens;\n      foreach (var p in iter.Ins) {\n        // ensures this.x == x;\n        ens.Add(new MaybeFreeExpression(new BinaryExpr(p.tok, BinaryExpr.Opcode.Eq,\n          new MemberSelectExpr(p.tok, new ThisExpr(p.tok), p.Name), new IdentifierExpr(p.tok, p.Name))));\n      }\n      foreach (var p in iter.OutsHistoryFields) {\n        // ensures this.ys == [];\n        ens.Add(new MaybeFreeExpression(new BinaryExpr(p.tok, BinaryExpr.Opcode.Eq,\n          new MemberSelectExpr(p.tok, new ThisExpr(p.tok), p.Name), new SeqDisplayExpr(p.tok, new List<Expression>()))));\n      }\n      // ensures this.Valid();\n      var valid_call = new FunctionCallExpr(iter.tok, \"Valid\", new ThisExpr(iter.tok), iter.tok, new List<Expression>());\n      ens.Add(new MaybeFreeExpression(valid_call));\n      // ensures this._reads == old(ReadsClause);\n      var modSetSingletons = new List<Expression>();\n      Expression frameSet = new SetDisplayExpr(iter.tok, true, modSetSingletons);\n      foreach (var fr in iter.Reads.Expressions) {\n        if (fr.FieldName != null) {\n          reporter.Error(MessageSource.Resolver, fr.tok, \"sorry, a reads clause for an iterator is not allowed to designate specific fields\");\n        } else if (fr.E.Type.IsRefType) {\n          modSetSingletons.Add(fr.E);\n        } else {\n          frameSet = new BinaryExpr(fr.tok, BinaryExpr.Opcode.Add, frameSet, fr.E);\n        }\n      }\n      ens.Add(new MaybeFreeExpression(new BinaryExpr(iter.tok, BinaryExpr.Opcode.Eq,\n        new MemberSelectExpr(iter.tok, new ThisExpr(iter.tok), \"_reads\"),\n        new OldExpr(iter.tok, frameSet))));\n      // ensures this._modifies == old(ModifiesClause);\n      modSetSingletons = new List<Expression>();\n      frameSet = new SetDisplayExpr(iter.tok, true, modSetSingletons);\n      foreach (var fr in iter.Modifies.Expressions) {\n        if (fr.FieldName != null) {\n          reporter.Error(MessageSource.Resolver, fr.tok, \"sorry, a modifies clause for an iterator is not allowed to designate specific fields\");\n        } else if (fr.E.Type.IsRefType) {\n          modSetSingletons.Add(fr.E);\n        } else {\n          frameSet = new BinaryExpr(fr.tok, BinaryExpr.Opcode.Add, frameSet, fr.E);\n        }\n      }\n      ens.Add(new MaybeFreeExpression(new BinaryExpr(iter.tok, BinaryExpr.Opcode.Eq,\n        new MemberSelectExpr(iter.tok, new ThisExpr(iter.tok), \"_modifies\"),\n        new OldExpr(iter.tok, frameSet))));\n      // ensures this._new == {};\n      ens.Add(new MaybeFreeExpression(new BinaryExpr(iter.tok, BinaryExpr.Opcode.Eq,\n        new MemberSelectExpr(iter.tok, new ThisExpr(iter.tok), \"_new\"),\n        new SetDisplayExpr(iter.tok, true, new List<Expression>()))));\n      // ensures this._decreases0 == old(DecreasesClause[0]) && ...;\n      Contract.Assert(iter.Decreases.Expressions.Count == iter.DecreasesFields.Count);\n      for (int i = 0; i < iter.Decreases.Expressions.Count; i++) {\n        var p = iter.Decreases.Expressions[i];\n        ens.Add(new MaybeFreeExpression(new BinaryExpr(iter.tok, BinaryExpr.Opcode.Eq,\n          new MemberSelectExpr(iter.tok, new ThisExpr(iter.tok), iter.DecreasesFields[i].Name),\n          new OldExpr(iter.tok, p))));\n      }\n\n      // ---------- here comes predicate Valid() ----------\n      var reads = iter.Member_Valid.Reads;\n      reads.Add(new FrameExpression(iter.tok, new ThisExpr(iter.tok), null));  // reads this;\n      reads.Add(new FrameExpression(iter.tok, new MemberSelectExpr(iter.tok, new ThisExpr(iter.tok), \"_reads\"), null));  // reads this._reads;\n      reads.Add(new FrameExpression(iter.tok, new MemberSelectExpr(iter.tok, new ThisExpr(iter.tok), \"_new\"), null));  // reads this._new;\n\n      // ---------- here comes method MoveNext() ----------\n      // requires this.Valid();\n      var req = iter.Member_MoveNext.Req;\n      valid_call = new FunctionCallExpr(iter.tok, \"Valid\", new ThisExpr(iter.tok), iter.tok, new List<Expression>());\n      req.Add(new MaybeFreeExpression(valid_call));\n      // requires YieldRequires;\n      req.AddRange(iter.YieldRequires);\n      // modifies this, this._modifies, this._new;\n      var mod = iter.Member_MoveNext.Mod.Expressions;\n      mod.Add(new FrameExpression(iter.tok, new ThisExpr(iter.tok), null));\n      mod.Add(new FrameExpression(iter.tok, new MemberSelectExpr(iter.tok, new ThisExpr(iter.tok), \"_modifies\"), null));\n      mod.Add(new FrameExpression(iter.tok, new MemberSelectExpr(iter.tok, new ThisExpr(iter.tok), \"_new\"), null));\n      // ensures fresh(_new - old(_new));\n      ens = iter.Member_MoveNext.Ens;\n      ens.Add(new MaybeFreeExpression(new UnaryOpExpr(iter.tok, UnaryOpExpr.Opcode.Fresh,\n        new BinaryExpr(iter.tok, BinaryExpr.Opcode.Sub,\n          new MemberSelectExpr(iter.tok, new ThisExpr(iter.tok), \"_new\"),\n          new OldExpr(iter.tok, new MemberSelectExpr(iter.tok, new ThisExpr(iter.tok), \"_new\"))))));\n      // ensures null !in _new\n      ens.Add(new MaybeFreeExpression(new BinaryExpr(iter.tok, BinaryExpr.Opcode.NotIn,\n        new LiteralExpr(iter.tok),\n        new MemberSelectExpr(iter.tok, new ThisExpr(iter.tok), \"_new\"))));\n      // ensures more ==> this.Valid();\n      valid_call = new FunctionCallExpr(iter.tok, \"Valid\", new ThisExpr(iter.tok), iter.tok, new List<Expression>());\n      ens.Add(new MaybeFreeExpression(new BinaryExpr(iter.tok, BinaryExpr.Opcode.Imp,\n        new IdentifierExpr(iter.tok, \"more\"),\n        valid_call)));\n      // ensures this.ys == if more then old(this.ys) + [this.y] else old(this.ys);\n      Contract.Assert(iter.OutsFields.Count == iter.OutsHistoryFields.Count);\n      for (int i = 0; i < iter.OutsFields.Count; i++) {\n        var y = iter.OutsFields[i];\n        var ys = iter.OutsHistoryFields[i];\n        var ite = new ITEExpr(iter.tok, false, new IdentifierExpr(iter.tok, \"more\"),\n          new BinaryExpr(iter.tok, BinaryExpr.Opcode.Add,\n            new OldExpr(iter.tok, new MemberSelectExpr(iter.tok, new ThisExpr(iter.tok), ys.Name)),\n            new SeqDisplayExpr(iter.tok, new List<Expression>() { new MemberSelectExpr(iter.tok, new ThisExpr(iter.tok), y.Name) })),\n          new OldExpr(iter.tok, new MemberSelectExpr(iter.tok, new ThisExpr(iter.tok), ys.Name)));\n        var eq = new BinaryExpr(iter.tok, BinaryExpr.Opcode.Eq, new MemberSelectExpr(iter.tok, new ThisExpr(iter.tok), ys.Name), ite);\n        ens.Add(new MaybeFreeExpression(eq));\n      }\n      // ensures more ==> YieldEnsures;\n      foreach (var ye in iter.YieldEnsures) {\n        ens.Add(new MaybeFreeExpression(\n          new BinaryExpr(iter.tok, BinaryExpr.Opcode.Imp, new IdentifierExpr(iter.tok, \"more\"), ye.E),\n          ye.IsFree));\n      }\n      // ensures !more ==> Ensures;\n      foreach (var e in iter.Ensures) {\n        ens.Add(new MaybeFreeExpression(new BinaryExpr(iter.tok, BinaryExpr.Opcode.Imp,\n          new UnaryOpExpr(iter.tok, UnaryOpExpr.Opcode.Not, new IdentifierExpr(iter.tok, \"more\")),\n          e.E),\n          e.IsFree));\n      }\n      // decreases this._decreases0, this._decreases1, ...;\n      Contract.Assert(iter.Decreases.Expressions.Count == iter.DecreasesFields.Count);\n      for (int i = 0; i < iter.Decreases.Expressions.Count; i++) {\n        var p = iter.Decreases.Expressions[i];\n        iter.Member_MoveNext.Decreases.Expressions.Add(new MemberSelectExpr(p.tok, new ThisExpr(p.tok), iter.DecreasesFields[i].Name));\n      }\n      iter.Member_MoveNext.Decreases.Attributes = iter.Decreases.Attributes;\n    }\n\n    // Like the ResolveTypeOptionEnum, but iff the case of AllowPrefixExtend, it also\n    // contains a pointer to its Parent class, to fill in default type parameters properly.\n    public class ResolveTypeOption\n    {\n      public readonly ResolveTypeOptionEnum Opt;\n      public readonly TypeParameter.ParentType Parent;\n      [ContractInvariantMethod]\n      void ObjectInvariant() {\n        Contract.Invariant((Opt == ResolveTypeOptionEnum.AllowPrefixExtend) == (Parent != null));\n      }\n\n      public ResolveTypeOption(ResolveTypeOptionEnum opt) {\n        Contract.Requires(opt != ResolveTypeOptionEnum.AllowPrefixExtend);\n        Parent = null;\n        Opt = opt;\n      }\n\n      public ResolveTypeOption(TypeParameter.ParentType parent) {\n        Contract.Requires(parent != null);\n        Opt = ResolveTypeOptionEnum.AllowPrefixExtend;\n        Parent = parent;\n      }\n    }\n\n    /// <summary>\n    /// If ResolveType/ResolveTypeLenient encounters a (datatype or class) type \"C\" with no supplied arguments, then\n    /// the ResolveTypeOption says what to do.  The last three options take a List as a parameter, which (would have\n    /// been supplied as an argument if C# had datatypes instead of just enums, but since C# doesn't) is supplied\n    /// as another parameter (called 'defaultTypeArguments') to ResolveType/ResolveTypeLenient.\n    /// </summary>\n    public enum ResolveTypeOptionEnum\n    {\n      /// <summary>\n      /// never infer type arguments\n      /// </summary>\n      DontInfer,\n      /// <summary>\n      /// create a new InferredTypeProxy type for each needed argument\n      /// </summary>\n      InferTypeProxies,\n      /// <summary>\n      /// if at most defaultTypeArguments.Count type arguments are needed, use a prefix of defaultTypeArguments\n      /// </summary>\n      AllowPrefix,\n      /// <summary>\n      /// same as AllowPrefix, but if more than defaultTypeArguments.Count type arguments are needed, first\n      /// extend defaultTypeArguments to a sufficient length\n      /// </summary>\n      AllowPrefixExtend,\n    }\n\n    /// <summary>\n    /// See ResolveTypeOption for a description of the option/defaultTypeArguments parameters.\n    /// This method differs from the other ResolveType methods in that it looks at the type name given\n    /// as a class name.  In other words, if \"type\" is given as \"C\" where \"C\" is a class, then \"type\" will\n    /// silently resolve to the class \"C\", not the non-null type \"C\".  Conversely, if \"type\" is given\n    /// as \"C?\" where \"C\" is a class, then an error will be emitted (as, to recover from this error,\n    /// \"type\" will resolve to the class \"C\".\n    /// </summary>\n    public void ResolveType_ClassName(IToken tok, Type type, ICodeContext context, ResolveTypeOptionEnum eopt, List<TypeParameter> defaultTypeArguments) {\n      Contract.Requires(tok != null);\n      Contract.Requires(type != null);\n      Contract.Requires(context != null);\n      Contract.Requires(eopt != ResolveTypeOptionEnum.AllowPrefixExtend);\n      ResolveType(tok, type, context, eopt, defaultTypeArguments);\n    }\n\n    /// <summary>\n    /// See ResolveTypeOption for a description of the option/defaultTypeArguments parameters.\n    /// </summary>\n    public void ResolveType(IToken tok, Type type, ICodeContext context, ResolveTypeOptionEnum eopt, List<TypeParameter> defaultTypeArguments) {\n      Contract.Requires(tok != null);\n      Contract.Requires(type != null);\n      Contract.Requires(context != null);\n      Contract.Requires(eopt != ResolveTypeOptionEnum.AllowPrefixExtend);\n      ResolveType(tok, type, context, new ResolveTypeOption(eopt), defaultTypeArguments);\n    }\n\n    public void ResolveType(IToken tok, Type type, ICodeContext context, ResolveTypeOption option, List<TypeParameter> defaultTypeArguments) {\n      Contract.Requires(tok != null);\n      Contract.Requires(type != null);\n      Contract.Requires(context != null);\n      Contract.Requires(option != null);\n      Contract.Requires((option.Opt == ResolveTypeOptionEnum.DontInfer || option.Opt == ResolveTypeOptionEnum.InferTypeProxies) == (defaultTypeArguments == null));\n      var r = ResolveTypeLenient(tok, type, context, option, defaultTypeArguments, false);\n      Contract.Assert(r == null);\n    }\n\n    public class ResolveTypeReturn\n    {\n      public readonly Type ReplacementType;\n      public readonly ExprDotName LastComponent;\n      public ResolveTypeReturn(Type replacementType, ExprDotName lastComponent) {\n        Contract.Requires(replacementType != null);\n        Contract.Requires(lastComponent != null);\n        ReplacementType = replacementType;\n        LastComponent = lastComponent;\n      }\n    }\n    /// <summary>\n    /// See ResolveTypeOption for a description of the option/defaultTypeArguments parameters.\n    /// One more thing:  if \"allowDanglingDotName\" is true, then if the resolution would have produced\n    ///   an error message that could have been avoided if \"type\" denoted an identifier sequence one\n    ///   shorter, then return an unresolved replacement type where the identifier sequence is one\n    ///   shorter.  (In all other cases, the method returns null.)\n    /// </summary>\n    public ResolveTypeReturn ResolveTypeLenient(IToken tok, Type type, ICodeContext context, ResolveTypeOption option, List<TypeParameter> defaultTypeArguments, bool allowDanglingDotName) {\n      Contract.Requires(tok != null);\n      Contract.Requires(type != null);\n      Contract.Requires(context != null);\n      Contract.Requires((option.Opt == ResolveTypeOptionEnum.DontInfer || option.Opt == ResolveTypeOptionEnum.InferTypeProxies) == (defaultTypeArguments == null));\n      if (type is BitvectorType) {\n        var t = (BitvectorType)type;\n        // nothing to resolve, but record the fact that this bitvector width is in use\n        builtIns.Bitwidths.Add(t.Width);\n      } else if (type is BasicType) {\n        // nothing to resolve\n      } else if (type is MapType) {\n        var mt = (MapType)type;\n        var errorCount = reporter.Count(ErrorLevel.Error);\n        int typeArgumentCount;\n        if (mt.HasTypeArg()) {\n          ResolveType(tok, mt.Domain, context, option, defaultTypeArguments);\n          ResolveType(tok, mt.Range, context, option, defaultTypeArguments);\n          typeArgumentCount = 2;\n        } else if (option.Opt == ResolveTypeOptionEnum.DontInfer) {\n          mt.SetTypeArgs(new InferredTypeProxy(), new InferredTypeProxy());\n          typeArgumentCount = 0;\n        } else {\n          var inferredTypeArgs = new List<Type>();\n          FillInTypeArguments(tok, 2, inferredTypeArgs, defaultTypeArguments, option);\n          Contract.Assert(inferredTypeArgs.Count <= 2);\n          if (inferredTypeArgs.Count == 1) {\n            mt.SetTypeArgs(inferredTypeArgs[0], new InferredTypeProxy());\n            typeArgumentCount = 1;\n          } else if (inferredTypeArgs.Count == 2) {\n            mt.SetTypeArgs(inferredTypeArgs[0], inferredTypeArgs[1]);\n            typeArgumentCount = 2;\n          } else {\n            mt.SetTypeArgs(new InferredTypeProxy(), new InferredTypeProxy());\n            typeArgumentCount = 0;\n          }\n        }\n        // defaults and auto have been applied; check if we now have the right number of arguments\n        if (2 != typeArgumentCount) {\n          reporter.Error(MessageSource.Resolver, tok, \"Wrong number of type arguments ({0} instead of 2) passed to type: {1}\", typeArgumentCount, mt.CollectionTypeName);\n        }\n      } else if (type is CollectionType) {\n        var t = (CollectionType)type;\n        var errorCount = reporter.Count(ErrorLevel.Error);\n        if (t.HasTypeArg()) {\n          ResolveType(tok, t.Arg, context, option, defaultTypeArguments);\n        } else if (option.Opt != ResolveTypeOptionEnum.DontInfer) {\n          var inferredTypeArgs = new List<Type>();\n          FillInTypeArguments(tok, 1, inferredTypeArgs, defaultTypeArguments, option);\n          if (inferredTypeArgs.Count != 0) {\n            Contract.Assert(inferredTypeArgs.Count == 1);\n            t.SetTypeArg(inferredTypeArgs[0]);\n          }\n        }\n        if (!t.HasTypeArg()) {\n          // defaults and auto have been applied; check if we now have the right number of arguments\n          reporter.Error(MessageSource.Resolver, tok, \"Wrong number of type arguments (0 instead of 1) passed to type: {0}\", t.CollectionTypeName);\n          // add a proxy type, to make sure that CollectionType will have have a non-null Arg\n          t.SetTypeArg(new InferredTypeProxy());\n        }\n\n      } else if (type is UserDefinedType) {\n        var t = (UserDefinedType)type;\n        if (t.ResolvedClass != null || t.ResolvedParam != null) {\n          // Apparently, this type has already been resolved\n          return null;\n        }\n        var prevErrorCount = reporter.Count(ErrorLevel.Error);\n        if (t.NamePath is ExprDotName) {\n          var ret = ResolveDotSuffix_Type((ExprDotName)t.NamePath, new ResolveOpts(context, true), allowDanglingDotName, option, defaultTypeArguments);\n          if (ret != null) {\n            return ret;\n          }\n        } else {\n          var s = (NameSegment)t.NamePath;\n          ResolveNameSegment_Type(s, new ResolveOpts(context, true), option, defaultTypeArguments);\n        }\n        if (reporter.Count(ErrorLevel.Error) == prevErrorCount) {\n          var r = t.NamePath.Resolved as Resolver_IdentifierExpr;\n          if (r == null || !(r.Type is Resolver_IdentifierExpr.ResolverType_Type)) {\n            reporter.Error(MessageSource.Resolver, t.tok, \"expected type\");\n          } else if (r.Type is Resolver_IdentifierExpr.ResolverType_Type && r.TypeParamDecl != null) {\n            t.ResolvedParam = r.TypeParamDecl;\n          } else if (r.Type is Resolver_IdentifierExpr.ResolverType_Type) {\n            var d = r.Decl;\n            if (d is OpaqueTypeDecl) {\n              var dd = (OpaqueTypeDecl)d;\n              t.ResolvedParam = dd.TheType;\n              // resolve like a type parameter, and it may have type parameters if it's an opaque type\n              t.ResolvedClass = d;  // Store the decl, so the compiler will generate the fully qualified name\n            } else if (d is SubsetTypeDecl || d is NewtypeDecl) {\n              var dd = (RedirectingTypeDecl)d;\n              var caller = context as ICallable;\n              if (caller != null && !(d is SubsetTypeDecl && caller is SpecialFunction)) {\n                caller.EnclosingModule.CallGraph.AddEdge(caller, dd);\n                if (caller == d) {\n                  // detect self-loops here, since they don't show up in the graph's SSC methods\n                  reporter.Error(MessageSource.Resolver, d.tok, \"recursive constraint dependency involving a {0}: {1} -> {1}\", d.WhatKind, d.Name);\n                }\n              }\n              t.ResolvedClass = d;\n            } else if (d is DatatypeDecl) {\n              var dd = (DatatypeDecl)d;\n              var caller = context as ICallable;\n              if (caller != null) {\n                caller.EnclosingModule.CallGraph.AddEdge(caller, dd);\n              }\n              t.ResolvedClass = d;\n            } else {\n              // d is a coinductive datatype or a class, and it may have type parameters\n              t.ResolvedClass = d;\n            }\n            if (option.Opt == ResolveTypeOptionEnum.DontInfer) {\n              // don't add anything\n            } else if (d.TypeArgs.Count != t.TypeArgs.Count && t.TypeArgs.Count == 0) {\n              FillInTypeArguments(t.tok, d.TypeArgs.Count, t.TypeArgs, defaultTypeArguments, option);\n            }\n            // defaults and auto have been applied; check if we now have the right number of arguments\n            if (d.TypeArgs.Count != t.TypeArgs.Count) {\n              reporter.Error(MessageSource.Resolver, t.tok, \"Wrong number of type arguments ({0} instead of {1}) passed to {2}: {3}\", t.TypeArgs.Count, d.TypeArgs.Count, d.WhatKind, t.Name);\n            }\n\n          }\n        }\n        if (t.ResolvedClass == null && t.ResolvedParam == null) {\n          // There was some error. Still, we will set one of them to some value to prevent some crashes in the downstream resolution.  The\n          // 0-tuple is convenient, because it is always in scope.\n          t.ResolvedClass = builtIns.TupleType(t.tok, 0, false);\n          // clear out the TypeArgs since 0-tuple doesn't take TypeArg\n          t.TypeArgs = new List<Type>();\n        }\n\n      } else if (type is TypeProxy) {\n        TypeProxy t = (TypeProxy)type;\n        if (t.T != null) {\n          ResolveType(tok, t.T, context, option, defaultTypeArguments);\n        }\n      } else if (type is SelfType) {\n        // do nothing.\n      } else {\n        Contract.Assert(false); throw new cce.UnreachableException();  // unexpected type\n      }\n      return null;\n    }\n\n    /// <summary>\n    /// Adds to \"typeArgs\" a list of \"n\" type arguments, possibly extending \"defaultTypeArguments\".\n    /// </summary>\n    static void FillInTypeArguments(IToken tok, int n, List<Type> typeArgs, List<TypeParameter> defaultTypeArguments, ResolveTypeOption option) {\n      Contract.Requires(tok != null);\n      Contract.Requires(0 <= n);\n      Contract.Requires(typeArgs != null && typeArgs.Count == 0);\n      if (option.Opt == ResolveTypeOptionEnum.InferTypeProxies) {\n        // add type arguments that will be inferred\n        for (int i = 0; i < n; i++) {\n          typeArgs.Add(new InferredTypeProxy());\n        }\n      } else if (option.Opt == ResolveTypeOptionEnum.AllowPrefix && defaultTypeArguments.Count < n) {\n        // there aren't enough default arguments, so don't do anything\n      } else {\n        // we'll add arguments\n        if (option.Opt == ResolveTypeOptionEnum.AllowPrefixExtend) {\n          // extend defaultTypeArguments, if needed\n          for (int i = defaultTypeArguments.Count; i < n; i++) {\n            var tp = new TypeParameter(tok, \"_T\" + i, i, option.Parent);\n            if (option.Parent is IteratorDecl) {\n              tp.Characteristics.MustSupportZeroInitialization = true;\n            }\n            defaultTypeArguments.Add(tp);\n          }\n        }\n        Contract.Assert(n <= defaultTypeArguments.Count);\n        // automatically supply a prefix of the arguments from defaultTypeArguments\n        for (int i = 0; i < n; i++) {\n          typeArgs.Add(new UserDefinedType(defaultTypeArguments[i]));\n        }\n      }\n    }\n\n    public static bool TypeConstraintsIncludeProxy(Type t, TypeProxy proxy) {\n      return TypeConstraintsIncludeProxy_Aux(t, proxy, new HashSet<TypeProxy>());\n    }\n    static bool TypeConstraintsIncludeProxy_Aux(Type t, TypeProxy proxy, ISet<TypeProxy> visited) {\n      Contract.Requires(t != null);\n      Contract.Requires(!(t is TypeProxy) || ((TypeProxy)t).T == null);  // t is expected to have been normalized first\n      Contract.Requires(proxy != null && proxy.T == null);\n      Contract.Requires(visited != null);\n      var tproxy = t as TypeProxy;\n      if (tproxy != null) {\n        if (object.ReferenceEquals(tproxy, proxy)) {\n          return true;\n        } else if (visited.Contains(tproxy)) {\n          return false;\n        }\n        visited.Add(tproxy);\n        foreach (var su in tproxy.Subtypes) {\n          if (TypeConstraintsIncludeProxy_Aux(su, proxy, visited)) {\n            return true;\n          }\n        }\n        foreach (var su in tproxy.Supertypes) {\n          if (TypeConstraintsIncludeProxy_Aux(su, proxy, visited)) {\n            return true;\n          }\n        }\n      } else {\n        // check type arguments of t\n        foreach (var ta in t.TypeArgs) {\n          var a = ta.Normalize();\n          if (TypeConstraintsIncludeProxy_Aux(a, proxy, visited)) {\n            return true;\n          }\n        }\n      }\n      return false;\n    }\n\n    /// <summary>\n    /// Returns a resolved type denoting an array type with dimension \"dims\" and element type \"arg\".\n    /// Callers are expected to provide \"arg\" as an already resolved type.  (Note, a proxy type is resolved--\n    /// only types that contain identifiers stand the possibility of not being resolved.)\n    /// </summary>\n    Type ResolvedArrayType(IToken tok, int dims, Type arg, ICodeContext context, bool useClassNameType) {\n      Contract.Requires(tok != null);\n      Contract.Requires(1 <= dims);\n      Contract.Requires(arg != null);\n      var at = builtIns.ArrayType(tok, dims, new List<Type> { arg }, false, useClassNameType);\n      ResolveType(tok, at, context, ResolveTypeOptionEnum.DontInfer, null);\n      return at;\n    }\n\n    public void ResolveStatement(Statement stmt, ICodeContext codeContext) {\n      Contract.Requires(stmt != null);\n      Contract.Requires(codeContext != null);\n      if (!(stmt is ForallStmt)) {  // forall statements do their own attribute resolution below\n        ResolveAttributes(stmt.Attributes, stmt, new ResolveOpts(codeContext, true));\n      }\n      if (stmt is PredicateStmt) {\n        PredicateStmt s = (PredicateStmt)stmt;\n        var assertStmt = stmt as AssertStmt;\n        if (assertStmt != null && assertStmt.Label != null) {\n          if (dominatingStatementLabels.Find(assertStmt.Label.Name) != null) {\n            reporter.Error(MessageSource.Resolver, assertStmt.Label.Tok, \"assert label shadows a dominating label\");\n          } else {\n            var rr = dominatingStatementLabels.Push(assertStmt.Label.Name, assertStmt.Label);\n            Contract.Assert(rr == Scope<Label>.PushResult.Success);  // since we just checked for duplicates, we expect the Push to succeed\n          }\n        }\n        ResolveExpression(s.Expr, new ResolveOpts(codeContext, true));\n        Contract.Assert(s.Expr.Type != null);  // follows from postcondition of ResolveExpression\n        ConstrainTypeExprBool(s.Expr, \"condition is expected to be of type bool, but is {0}\");\n        if (assertStmt != null && assertStmt.Proof != null) {\n          // clear the labels for the duration of checking the proof body, because break statements are not allowed to leave a the proof body\n          var prevLblStmts = enclosingStatementLabels;\n          var prevLoopStack = loopStack;\n          enclosingStatementLabels = new Scope<Statement>();\n          loopStack = new List<Statement>();\n          ResolveStatement(assertStmt.Proof, codeContext);\n          enclosingStatementLabels = prevLblStmts;\n          loopStack = prevLoopStack;\n        }\n\n      } else if (stmt is PrintStmt) {\n        var s = (PrintStmt)stmt;\n        var opts = new ResolveOpts(codeContext, false);\n        s.Args.Iter(e => ResolveExpression(e, opts));\n\n      } else if (stmt is RevealStmt) {\n        var s = (RevealStmt)stmt;\n        foreach (var expr in s.Exprs) {\n          var name = RevealStmt.SingleName(expr);\n          var labeledAssert = name == null ? null : dominatingStatementLabels.Find(name) as AssertLabel;\n          if (labeledAssert != null) {\n            s.LabeledAsserts.Add(labeledAssert);\n          } else {\n            var opts = new ResolveOpts(codeContext, false, true, false, false);\n            if (expr is ApplySuffix) {\n              var e = (ApplySuffix)expr;\n              var methodCallInfo = ResolveApplySuffix(e, opts, true);\n              if (methodCallInfo == null) {\n                reporter.Error(MessageSource.Resolver, expr.tok, \"function {0} does not have the reveal lemma\", e.Lhs);\n              } else {\n                var call = new CallStmt(methodCallInfo.Tok, s.EndTok, new List<Expression>(), methodCallInfo.Callee, methodCallInfo.Args);\n                s.ResolvedStatements.Add(call);\n              }\n            } else {\n              ResolveExpression(expr, opts);\n            }\n            foreach (var a in s.ResolvedStatements) {\n              ResolveStatement(a, codeContext);\n            }\n          }\n        }\n      } else if (stmt is SomehowStmt) {\n        var s = (SomehowStmt)stmt;\n        foreach (var e in s.UndefinedUnless) {\n          ResolveExpression(e, new ResolveOpts(codeContext, false));\n        }\n        ResolveAttributes(s.Mod.Attributes, null, new ResolveOpts(codeContext, false));\n        foreach (var e in s.Mod.Expressions) {\n          ResolveExpression(e, new ResolveOpts(codeContext, false));\n        }\n        foreach (var e in s.Ens) {\n          ResolveExpression(e, new ResolveOpts(codeContext, true));\n        }\n      } else if (stmt is FenceStmt) {\n      } else if (stmt is GotoStmt) {\n        var s = (GotoStmt)stmt;\n        s.TargetLabel = methodStatementLabels.Find(s.Target);\n        if (s.TargetLabel == null) {\n          reporter.Error(MessageSource.Resolver, s, \"no label '{0}' in scope at this time\", s.Target);\n        }\n      } else if (stmt is DeallocStmt) {\n        var s = (DeallocStmt)stmt;\n        ResolveExpression(s.Addr, new ResolveOpts(codeContext, false));\n      } else if (stmt is JoinStmt) {\n        var s = (JoinStmt)stmt;\n        ResolveExpression(s.WhichThread, new ResolveOpts(codeContext, false));\n        var ty = new UserDefinedType(Token.NoToken, \"uint64\", new List<Type>());\n        this.ResolveType(stmt.Tok, ty, codeContext, ResolveTypeOptionEnum.InferTypeProxies, null);\n        AddAssignableConstraint(stmt.Tok, s.WhichThread.Type, ty, \"join argument must be of type {1}, not {0}\");\n      } else if (stmt is BreakStmt) {\n        var s = (BreakStmt)stmt;\n        if (s.TargetLabel != null) {\n          Statement target = enclosingStatementLabels.Find(s.TargetLabel);\n          if (target == null) {\n            reporter.Error(MessageSource.Resolver, s, \"break label is undefined or not in scope: {0}\", s.TargetLabel);\n          } else {\n            s.TargetStmt = target;\n          }\n        } else {\n          if (loopStack.Count < s.BreakCount) {\n            reporter.Error(MessageSource.Resolver, s, \"trying to break out of more loop levels than there are enclosing loops\");\n          } else {\n            Statement target = loopStack[loopStack.Count - s.BreakCount];\n            if (target.Labels == null) {\n              // make sure there is a label, because the compiler and translator will want to see a unique ID\n              target.Labels = new LList<Label>(new Label(target.Tok, null), null);\n            }\n            s.TargetStmt = target;\n          }\n        }\n\n      } else if (stmt is ContinueStmt) {\n      } else if (stmt is ProduceStmt) {\n        var kind = stmt is YieldStmt ? \"yield\" : \"return\";\n        if (stmt is YieldStmt && !(codeContext is IteratorDecl) && moduleInfo.ModuleType != ArmadaModuleType.ArmadaLevel) {\n          reporter.Error(MessageSource.Resolver, stmt, \"yield statement is allowed only in iterators\");\n        } else if (stmt is ReturnStmt && !(codeContext is Method)) {\n          reporter.Error(MessageSource.Resolver, stmt, \"return statement is allowed only in method\");\n        } else if (inBodyInitContext) {\n          reporter.Error(MessageSource.Resolver, stmt, \"return statement is not allowed before 'new;' in a constructor\");\n        }\n        var s = (ProduceStmt)stmt;\n        if (s.rhss != null) {\n          var cmc = codeContext as IMethodCodeContext;\n          if (cmc == null) {\n            // an error has already been reported above\n          } else if (cmc.Outs.Count != s.rhss.Count) {\n            reporter.Error(MessageSource.Resolver, s, \"number of {2} parameters does not match declaration (found {0}, expected {1})\", s.rhss.Count, cmc.Outs.Count, kind);\n          } else {\n            Contract.Assert(s.rhss.Count > 0);\n            // Create a hidden update statement using the out-parameter formals, resolve the RHS, and check that the RHS is good.\n            List<Expression> formals = new List<Expression>();\n            foreach (Formal f in cmc.Outs) {\n              Expression produceLhs;\n              if (stmt is ReturnStmt) {\n                var ident = new IdentifierExpr(f.tok, f.Name);\n                // resolve it here to avoid capture into more closely declared local variables\n                ident.Var = f;\n                ident.Type = ident.Var.Type;\n                Contract.Assert(f.Type != null);\n                produceLhs = ident;\n              } else {\n                var yieldIdent = new MemberSelectExpr(f.tok, new ImplicitThisExpr(f.tok), f.Name);\n                ResolveExpression(yieldIdent, new ResolveOpts(codeContext, true));\n                produceLhs = yieldIdent;\n              }\n              formals.Add(produceLhs);\n            }\n            s.hiddenUpdate = new UpdateStmt(s.Tok, s.EndTok, formals, s.rhss, true);\n            // resolving the update statement will check for return/yield statement specifics.\n            ResolveStatement(s.hiddenUpdate, codeContext);\n          }\n        } else {// this is a regular return/yield statement.\n          s.hiddenUpdate = null;\n        }\n      } else if (stmt is ConcreteUpdateStatement) {\n        ResolveConcreteUpdateStmt((ConcreteUpdateStatement)stmt, codeContext);\n      } else if (stmt is VarDeclStmt) {\n        var s = (VarDeclStmt)stmt;\n        // We have four cases.\n        Contract.Assert(s.Update == null || s.Update is AssignSuchThatStmt || s.Update is UpdateStmt || s.Update is AssignOrReturnStmt);\n        // 0.  There is no .Update.  This is easy, we will just resolve the locals.\n        // 1.  The .Update is an AssignSuchThatStmt.  This is also straightforward:  first\n        //     resolve the locals, which adds them to the scope, and then resolve the .Update.\n        // 2.  The .Update is an UpdateStmt, which, resolved, means either a CallStmt or a bunch\n        //     of parallel AssignStmt's.  Here, the right-hand sides should be resolved before\n        //     the local variables have been added to the scope, but the left-hand sides should\n        //     resolve to the newly introduced variables.\n        // 3.  The .Update is a \":-\" statement, for which resolution does two steps:\n        //     First, desugar, then run the regular resolution on the desugared AST.\n        // To accommodate these options, we first reach into the UpdateStmt, if any, to resolve\n        // the left-hand sides of the UpdateStmt.  This will have the effect of shielding them\n        // from a subsequent resolution (since expression resolution will do nothing if the .Type\n        // field is already assigned.\n        // Alright, so it is:\n\n        // Resolve the types of the locals\n        foreach (var local in s.Locals) {\n          int prevErrorCount = reporter.Count(ErrorLevel.Error);\n          ResolveType(local.Tok, local.OptionalType, codeContext, ResolveTypeOptionEnum.InferTypeProxies, null);\n          if (reporter.Count(ErrorLevel.Error) == prevErrorCount) {\n            local.type = local.OptionalType;\n          } else {\n            local.type = new InferredTypeProxy();\n          }\n        }\n        // Resolve the UpdateStmt, if any\n        if (s.Update is UpdateStmt) {\n          var upd = (UpdateStmt)s.Update;\n          // resolve the LHS\n          Contract.Assert(upd.Lhss.Count == s.Locals.Count);\n          for (int i = 0; i < upd.Lhss.Count; i++) {\n            var local = s.Locals[i];\n            var lhs = (IdentifierExpr)upd.Lhss[i];  // the LHS in this case will be an IdentifierExpr, because that's how the parser creates the VarDeclStmt\n            Contract.Assert(lhs.Type == null);  // not yet resolved\n            lhs.Var = local;\n            lhs.Type = local.Type;\n          }\n          // resolve the whole thing\n          ResolveConcreteUpdateStmt(s.Update, codeContext);\n        }\n        if (s.Update is AssignOrReturnStmt) {\n          var assignOrRet = (AssignOrReturnStmt)s.Update;\n          // resolve the LHS\n          Contract.Assert(assignOrRet.Lhss.Count == 1);\n          Contract.Assert(s.Locals.Count == 1);\n          var local = s.Locals[0];\n          var lhs = (IdentifierExpr)assignOrRet.Lhss[0];  // the LHS in this case will be an IdentifierExpr, because that's how the parser creates the VarDeclStmt\n          Contract.Assert(lhs.Type == null);  // not yet resolved\n          lhs.Var = local;\n          lhs.Type = local.Type;\n\n          // resolve the whole thing\n          ResolveAssignOrReturnStmt(assignOrRet, codeContext);\n        }\n        // Add the locals to the scope\n        foreach (var local in s.Locals) {\n          ScopePushAndReport(scope, local, \"local-variable\");\n        }\n        // With the new locals in scope, it's now time to resolve the attributes on all the locals\n        foreach (var local in s.Locals) {\n          ResolveAttributes(local.Attributes, local, new ResolveOpts(codeContext, true));\n        }\n        // Resolve the AssignSuchThatStmt, if any\n        if (s.Update is AssignSuchThatStmt) {\n          ResolveConcreteUpdateStmt(s.Update, codeContext);\n        }\n        // Update the VarDeclStmt's ghost status according to its components\n        foreach (var local in s.Locals)\n        {\n          if (Attributes.Contains(local.Attributes, \"assumption\"))\n          {\n            if (currentMethod == null)\n            {\n              reporter.Error(MessageSource.Resolver, local.Tok, \"assumption variable can only be declared in a method\");\n            }\n            ConstrainSubtypeRelation(Type.Bool, local.type, local.Tok, \"assumption variable must be of type 'bool'\");\n            if (!local.IsGhost) {\n              reporter.Error(MessageSource.Resolver, local.Tok, \"assumption variable must be ghost\");\n            }\n          }\n        }\n      } else if (stmt is LetStmt) {\n        LetStmt s = (LetStmt)stmt;\n        foreach (var local in s.LocalVars) {\n          int prevErrorCount = reporter.Count(ErrorLevel.Error);\n          ResolveType(local.Tok, local.OptionalType, codeContext, ResolveTypeOptionEnum.InferTypeProxies, null);\n          if (reporter.Count(ErrorLevel.Error) == prevErrorCount) {\n            local.type = local.OptionalType;\n          } else {\n            local.type = new InferredTypeProxy();\n          }\n        }\n        ResolveExpression(s.RHS, new ResolveOpts(codeContext, true));\n        ResolveCasePattern(s.LHS, s.RHS.Type, codeContext);\n        // Check for duplicate names now, because not until after resolving the case pattern do we know if identifiers inside it refer to bound variables or nullary constructors\n        var c = 0;\n        foreach (var bv in s.LHS.Vars) {\n          ScopePushAndReport(scope, bv, \"local_variable\");\n          c++;\n        }\n        if (c == 0) {\n          // Every identifier-looking thing in the pattern resolved to a constructor; that is, this LHS is a constant literal\n          reporter.Error(MessageSource.Resolver, s.LHS.tok, \"LHS is a constant literal; to be legal, it must introduce at least one bound variable\");\n        }\n      } else if (stmt is AssignStmt) {\n        AssignStmt s = (AssignStmt)stmt;\n        int prevErrorCount = reporter.Count(ErrorLevel.Error);\n        ResolveExpression(s.Lhs, new ResolveOpts(codeContext, true));  // allow ghosts for now, tighted up below\n        bool lhsResolvedSuccessfully = reporter.Count(ErrorLevel.Error) == prevErrorCount;\n        Contract.Assert(s.Lhs.Type != null);  // follows from postcondition of ResolveExpression\n        // check that LHS denotes a mutable variable or a field\n        var lhs = s.Lhs.Resolved;\n        if (lhs is IdentifierExpr) {\n          IVariable var = ((IdentifierExpr)lhs).Var;\n          if (var == null) {\n            // the LHS didn't resolve correctly; some error would already have been reported\n          } else {\n            CheckIsLvalue(lhs, codeContext);\n\n            var localVar = var as LocalVariable;\n            if (localVar != null && currentMethod != null && Attributes.Contains(localVar.Attributes, \"assumption\"))\n            {\n              var rhs = s.Rhs as ExprRhs;\n              var expr = (rhs != null ? rhs.Expr : null);\n              var binaryExpr = expr as BinaryExpr;\n              if (binaryExpr != null\n                  && (binaryExpr.Op == BinaryExpr.Opcode.And)\n                  && (binaryExpr.E0.Resolved is IdentifierExpr)\n                  && ((IdentifierExpr)(binaryExpr.E0.Resolved)).Var == localVar\n                  && !currentMethod.AssignedAssumptionVariables.Contains(localVar))\n              {\n                currentMethod.AssignedAssumptionVariables.Add(localVar);\n              }\n              else\n              {\n                reporter.Error(MessageSource.Resolver, stmt, string.Format(\"there may be at most one assignment to an assumption variable, the RHS of which must match the expression \\\"{0} && <boolean expression>\\\"\", localVar.Name));\n              }\n            }\n          }\n        } else if (lhs is MemberSelectExpr) {\n          var fse = (MemberSelectExpr)lhs;\n          if (fse.Member != null) {  // otherwise, an error was reported above\n            CheckIsLvalue(fse, codeContext);\n          }\n        } else if (lhs is SeqSelectExpr) {\n          var slhs = (SeqSelectExpr)lhs;\n          // LHS is fine, provided the \"sequence\" is really an array\n          if (lhsResolvedSuccessfully) {\n            Contract.Assert(slhs.Seq.Type != null);\n            CheckIsLvalue(slhs, codeContext);\n          }\n\n        } else if (lhs is MultiSelectExpr) {\n          CheckIsLvalue(lhs, codeContext);\n\n        } else {\n          CheckIsLvalue(lhs, codeContext);\n        }\n\n        Type lhsType = s.Lhs.Type;\n        if (s.Rhs is ExprRhs) {\n          ExprRhs rr = (ExprRhs)s.Rhs;\n          ResolveExpression(rr.Expr, new ResolveOpts(codeContext, true));\n          Contract.Assert(rr.Expr.Type != null);  // follows from postcondition of ResolveExpression\n          AddAssignableConstraint(stmt.Tok, lhsType, rr.Expr.Type, \"RHS (of type {1}) not assignable to LHS (of type {0})\");\n        } else if (s.Rhs is TypeRhs) {\n          TypeRhs rr = (TypeRhs)s.Rhs;\n          Type t = ResolveTypeRhs(rr, stmt, codeContext);\n          AddAssignableConstraint(stmt.Tok, lhsType, t, \"type {1} is not assignable to LHS (of type {0})\");\n        } else if (s.Rhs is HavocRhs) {\n          // nothing else to do\n        } else if (s.Rhs is CreateThreadRhs) {\n          var ty = new UserDefinedType(Token.NoToken, \"uint64\", new List<Type>());\n          this.ResolveType(stmt.Tok, ty, codeContext, ResolveTypeOptionEnum.InferTypeProxies, null);\n          AddAssignableConstraint(stmt.Tok, lhsType, ty, \"create_thread result must be stored in an LHS of type {1}, not {0}\");\n          // TODO - Check that the argument list matches the called thread routine in both number and types\n        } else if (s.Rhs is MallocRhs) {\n          MallocRhs rr = (MallocRhs)s.Rhs;\n          this.ResolveType(stmt.Tok, rr.AllocatedType, codeContext, ResolveTypeOptionEnum.InferTypeProxies, null);\n          AddAssignableConstraint(stmt.Tok, lhsType, new PointerType(rr.AllocatedType),\n                                  \"Malloc result (of type {1}) not assignable to LHS (of type {0}\");\n        } else if (s.Rhs is CallocRhs) {\n          CallocRhs rr = (CallocRhs)s.Rhs;\n          this.ResolveType(stmt.Tok, rr.AllocatedType, codeContext, ResolveTypeOptionEnum.InferTypeProxies, null);\n          ResolveExpression(rr.Count, new ResolveOpts(codeContext, false));\n          AddAssignableConstraint(stmt.Tok, lhsType, new PointerType(rr.AllocatedType),\n                                  \"Calloc result (of type {1}) not assignable to LHS (of type {0})\");\n        } else if (s.Rhs is CompareAndSwapRhs || s.Rhs is AtomicExchangeRhs) {\n          // already taken care of during Update resolution\n        } else {\n          Contract.Assert(false); throw new cce.UnreachableException();  // unexpected RHS\n        }\n\n      } else if (stmt is CallStmt) {\n        CallStmt s = (CallStmt)stmt;\n        ResolveCallStmt(s, codeContext, null);\n\n      } else if (stmt is BlockStmt) {\n        var s = (BlockStmt)stmt;\n        scope.PushMarker();\n        ResolveBlockStatement(s, codeContext);\n        scope.PopMarker();\n\n      } else if (stmt is IfStmt) {\n        IfStmt s = (IfStmt)stmt;\n        if (s.Guard != null) {\n          ResolveExpression(s.Guard, new ResolveOpts(codeContext, true));\n          Contract.Assert(s.Guard.Type != null);  // follows from postcondition of ResolveExpression\n          ConstrainTypeExprBool(s.Guard, \"condition is expected to be of type bool, but is {0}\");\n        }\n\n        scope.PushMarker();\n        if (s.IsBindingGuard) {\n          var exists = (ExistsExpr)s.Guard;\n          foreach (var v in exists.BoundVars) {\n            ScopePushAndReport(scope, v, \"bound-variable\");\n          }\n        }\n        dominatingStatementLabels.PushMarker();\n        ResolveBlockStatement(s.Thn, codeContext);\n        dominatingStatementLabels.PopMarker();\n        scope.PopMarker();\n\n        if (s.Els != null) {\n          dominatingStatementLabels.PushMarker();\n          ResolveStatement(s.Els, codeContext);\n          dominatingStatementLabels.PopMarker();\n        }\n\n      } else if (stmt is AlternativeStmt) {\n        var s = (AlternativeStmt)stmt;\n        ResolveAlternatives(s.Alternatives, null, codeContext);\n\n      } else if (stmt is WhileStmt) {\n        WhileStmt s = (WhileStmt)stmt;\n        var fvs = new HashSet<IVariable>();\n        if (s.Guard != null) {\n          ResolveExpression(s.Guard, new ResolveOpts(codeContext, true));\n          Contract.Assert(s.Guard.Type != null);  // follows from postcondition of ResolveExpression\n          Translator.ComputeFreeVariables(s.Guard, fvs);\n          ConstrainTypeExprBool(s.Guard, \"condition is expected to be of type bool, but is {0}\");\n        }\n\n        ResolveLoopSpecificationComponents(s.Invariants, s.Ens, s.Decreases, s.Mod, codeContext, fvs);\n\n        if (s.Body != null) {\n          loopStack.Add(s);  // push\n          dominatingStatementLabels.PushMarker();\n          ResolveStatement(s.Body, codeContext);\n          dominatingStatementLabels.PopMarker();\n          loopStack.RemoveAt(loopStack.Count - 1);  // pop\n        } else {\n          reporter.Warning(MessageSource.Resolver, s.Tok, \"note, this loop has no body\");\n          string text = \"havoc {\" + Util.Comma(\", \", fvs, fv => fv.Name) + \"};\";  // always terminate with a semi-colon\n          reporter.Info(MessageSource.Resolver, s.Tok, text);\n        }\n\n      } else if (stmt is AlternativeLoopStmt) {\n        var s = (AlternativeLoopStmt)stmt;\n        ResolveAlternatives(s.Alternatives, s, codeContext);\n        ResolveLoopSpecificationComponents(s.Invariants, new List<Expression>(), s.Decreases, s.Mod, codeContext, null);\n\n      } else if (stmt is ForallStmt) {\n        var s = (ForallStmt)stmt;\n\n        int prevErrorCount = reporter.Count(ErrorLevel.Error);\n        scope.PushMarker();\n        foreach (BoundVar v in s.BoundVars) {\n          ScopePushAndReport(scope, v, \"local-variable\");\n          ResolveType(v.tok, v.Type, codeContext, ResolveTypeOptionEnum.InferTypeProxies, null);\n        }\n        ResolveExpression(s.Range, new ResolveOpts(codeContext, true));\n        Contract.Assert(s.Range.Type != null);  // follows from postcondition of ResolveExpression\n        ConstrainTypeExprBool(s.Range, \"range restriction in forall statement must be of type bool (instead got {0})\");\n        foreach (var ens in s.Ens) {\n          ResolveExpression(ens.E, new ResolveOpts(codeContext, true));\n          Contract.Assert(ens.E.Type != null);  // follows from postcondition of ResolveExpression\n          ConstrainTypeExprBool(ens.E, \"ensures condition is expected to be of type bool, but is {0}\");\n        }\n        // Since the range and postconditions are more likely to infer the types of the bound variables, resolve them\n        // first (above) and only then resolve the attributes (below).\n        ResolveAttributes(s.Attributes, s, new ResolveOpts(codeContext, true));\n\n        if (s.Body != null) {\n          // clear the labels for the duration of checking the body, because break statements are not allowed to leave a forall statement\n          var prevLblStmts = enclosingStatementLabels;\n          var prevLoopStack = loopStack;\n          enclosingStatementLabels = new Scope<Statement>();\n          loopStack = new List<Statement>();\n          ResolveStatement(s.Body, codeContext);\n          enclosingStatementLabels = prevLblStmts;\n          loopStack = prevLoopStack;\n        } else {\n          reporter.Warning(MessageSource.Resolver, s.Tok, \"note, this forall statement has no body\");\n        }\n        scope.PopMarker();\n\n        if (prevErrorCount == reporter.Count(ErrorLevel.Error)) {\n          // determine the Kind and run some additional checks on the body\n          if (s.Ens.Count != 0) {\n            // The only supported kind with ensures clauses is Proof.\n            s.Kind = ForallStmt.BodyKind.Proof;\n          } else {\n            // There are three special cases:\n            // * Assign, which is the only kind of the forall statement that allows a heap update.\n            // * Call, which is a single call statement with no side effects or output parameters.\n            // * A single calc statement, which is a special case of Proof where the postcondition can be inferred.\n            // The effect of Assign and the postcondition of Call will be seen outside the forall\n            // statement.\n            Statement s0 = s.S0;\n            if (s0 is AssignStmt) {\n              s.Kind = ForallStmt.BodyKind.Assign;\n            } else if (s0 is CallStmt) {\n              s.Kind = ForallStmt.BodyKind.Call;\n              var call = (CallStmt)s.S0;\n              var method = call.Method;\n              // if the called method is not in the same module as the ForallCall stmt\n              // don't convert it to ForallExpression since the inlined called method's\n              // ensure clause might not be resolved correctly(test\\dafny3\\GenericSort.dfy)\n              if (method.EnclosingClass.Module != codeContext.EnclosingModule) {\n                s.CanConvert = false;\n              }\n              // Additional information (namely, the postcondition of the call) will be reported later. But it cannot be\n              // done yet, because the specification of the callee may not have been resolved yet.\n            } else if (s0 is CalcStmt) {\n              s.Kind = ForallStmt.BodyKind.Proof;\n              // add the conclusion of the calc as a free postcondition\n              var result = ((CalcStmt)s0).Result;\n              s.Ens.Add(new MaybeFreeExpression(result, true));\n              reporter.Info(MessageSource.Resolver, s.Tok, \"ensures \" + Printer.ExprToString(result));\n            } else {\n              s.Kind = ForallStmt.BodyKind.Proof;\n              if (s.Body is BlockStmt && ((BlockStmt)s.Body).Body.Count == 0) {\n                // an empty statement, so don't produce any warning\n              } else {\n                reporter.Warning(MessageSource.Resolver, s.Tok, \"the conclusion of the body of this forall statement will not be known outside the forall statement; consider using an 'ensures' clause\");\n              }\n            }\n          }\n          if (s.Body != null) {\n            CheckForallStatementBodyRestrictions(s.Body, s.Kind);\n          }\n\n          if (s.ForallExpressions != null) {\n            foreach (Expression expr in s.ForallExpressions) {\n              ResolveExpression(expr, new ResolveOpts(codeContext, true));\n            }\n          }\n        }\n\n      } else if (stmt is ModifyStmt) {\n        var s = (ModifyStmt)stmt;\n        ResolveAttributes(s.Mod.Attributes, null, new ResolveOpts(codeContext, true));\n        foreach (FrameExpression fe in s.Mod.Expressions) {\n          ResolveFrameExpression(fe, FrameExpressionUse.Modifies, codeContext);\n        }\n        if (s.Body != null) {\n          ResolveBlockStatement(s.Body, codeContext);\n        }\n\n      } else if (stmt is CalcStmt) {\n        var prevErrorCount = reporter.Count(ErrorLevel.Error);\n        CalcStmt s = (CalcStmt)stmt;\n        // figure out s.Op\n        Contract.Assert(s.Op == null);  // it hasn't been set yet\n        if (s.UserSuppliedOp != null) {\n          s.Op = s.UserSuppliedOp;\n        } else {\n          // Usually, we'd use == as the default main operator.  However, if the calculation\n          // begins or ends with a boolean literal, then we can do better by selecting ==>\n          // or <==.  Also, if the calculation begins or ends with an empty set, then we can\n          // do better by selecting <= or >=.\n          if (s.Lines.Count == 0) {\n            s.Op = CalcStmt.DefaultOp;\n          } else {\n            bool b;\n            if (Expression.IsBoolLiteral(s.Lines.First(), out b)) {\n              s.Op = new CalcStmt.BinaryCalcOp(b ? BinaryExpr.Opcode.Imp : BinaryExpr.Opcode.Exp);\n            } else if (Expression.IsBoolLiteral(s.Lines.Last(), out b)) {\n              s.Op = new CalcStmt.BinaryCalcOp(b ? BinaryExpr.Opcode.Exp : BinaryExpr.Opcode.Imp);\n            } else if (Expression.IsEmptySetOrMultiset(s.Lines.First())) {\n              s.Op = new CalcStmt.BinaryCalcOp(BinaryExpr.Opcode.Ge);\n            } else if (Expression.IsEmptySetOrMultiset(s.Lines.Last())) {\n              s.Op = new CalcStmt.BinaryCalcOp(BinaryExpr.Opcode.Le);\n            } else {\n              s.Op = CalcStmt.DefaultOp;\n            }\n          }\n          reporter.Info(MessageSource.Resolver, s.Tok, s.Op.ToString());\n        }\n\n        if (s.Lines.Count > 0) {\n          Type lineType = new InferredTypeProxy();\n          var e0 = s.Lines.First();\n          ResolveExpression(e0, new ResolveOpts(codeContext, true));\n          Contract.Assert(e0.Type != null);  // follows from postcondition of ResolveExpression\n          var err = new TypeConstraint.ErrorMsgWithToken(e0.tok, \"all lines in a calculation must have the same type (got {0} after {1})\", e0.Type, lineType);\n          ConstrainSubtypeRelation(lineType, e0.Type, err);\n          for (int i = 1; i < s.Lines.Count; i++) {\n            var e1 = s.Lines[i];\n            ResolveExpression(e1, new ResolveOpts(codeContext, true));\n            Contract.Assert(e1.Type != null);  // follows from postcondition of ResolveExpression\n            // reuse the error object if we're on the dummy line; this prevents a duplicate error message\n            if (i < s.Lines.Count - 1) {\n              err = new TypeConstraint.ErrorMsgWithToken(e1.tok, \"all lines in a calculation must have the same type (got {0} after {1})\", e1.Type, lineType);\n            }\n            ConstrainSubtypeRelation(lineType, e1.Type, err);\n            var step = (s.StepOps[i - 1] ?? s.Op).StepExpr(e0, e1); // Use custom line operator\n            ResolveExpression(step, new ResolveOpts(codeContext, true));\n            s.Steps.Add(step);\n            e0 = e1;\n          }\n\n          // clear the labels for the duration of checking the hints, because break statements are not allowed to leave a forall statement\n          var prevLblStmts = enclosingStatementLabels;\n          var prevLoopStack = loopStack;\n          enclosingStatementLabels = new Scope<Statement>();\n          loopStack = new List<Statement>();\n          foreach (var h in s.Hints) {\n            foreach (var oneHint in h.Body) {\n              dominatingStatementLabels.PushMarker();\n              ResolveStatement(oneHint, codeContext);\n              dominatingStatementLabels.PopMarker();\n            }\n          }\n          enclosingStatementLabels = prevLblStmts;\n          loopStack = prevLoopStack;\n\n        }\n        if (prevErrorCount == reporter.Count(ErrorLevel.Error) && s.Lines.Count > 0) {\n          // do not build Result from the lines if there were errors, as it might be ill-typed and produce unnecessary resolution errors\n          var resultOp = s.StepOps.Aggregate(s.Op, (op0, op1) => op1 == null ? op0 : op0.ResultOp(op1));\n          s.Result = resultOp.StepExpr(s.Lines.First(), s.Lines.Last());\n        } else {\n          s.Result = CalcStmt.DefaultOp.StepExpr(Expression.CreateIntLiteral(s.Tok, 0), Expression.CreateIntLiteral(s.Tok, 0));\n        }\n        ResolveExpression(s.Result, new ResolveOpts(codeContext, true));\n        Contract.Assert(s.Result != null);\n        Contract.Assert(prevErrorCount != reporter.Count(ErrorLevel.Error) || s.Steps.Count == s.Hints.Count);\n\n      } else if (stmt is MatchStmt) {\n        ResolveMatchStmt((MatchStmt)stmt, codeContext);\n      } else if (stmt is SkeletonStatement) {\n        var s = (SkeletonStatement)stmt;\n        reporter.Error(MessageSource.Resolver, s.Tok, \"skeleton statements are allowed only in refining methods\");\n        // nevertheless, resolve the underlying statement; hey, why not\n        if (s.S != null) {\n          ResolveStatement(s.S, codeContext);\n        }\n      } else {\n        Contract.Assert(false); throw new cce.UnreachableException();\n      }\n    }\n\n    private void ResolveLoopSpecificationComponents(List<MaybeFreeExpression> invariants, List<Expression> ens, Specification<Expression> decreases, Specification<FrameExpression> modifies, ICodeContext codeContext, HashSet<IVariable> fvs) {\n      Contract.Requires(invariants != null);\n      Contract.Requires(decreases != null);\n      Contract.Requires(modifies != null);\n      Contract.Requires(codeContext != null);\n\n      foreach (MaybeFreeExpression inv in invariants) {\n        ResolveAttributes(inv.Attributes, null, new ResolveOpts(codeContext, false));\n        ResolveExpression(inv.E, new ResolveOpts(codeContext, true));\n        Contract.Assert(inv.E.Type != null);  // follows from postcondition of ResolveExpression\n        if (fvs != null) {\n          Translator.ComputeFreeVariables(inv.E, fvs);\n        }\n        ConstrainTypeExprBool(inv.E, \"invariant is expected to be of type bool, but is {0}\");\n      }\n\n      foreach (Expression clause in ens) {\n        ResolveExpression(clause, new ResolveOpts(codeContext, true));\n        Contract.Assert(clause.Type != null);  // follows from postcondition of ResolveExpression\n        ConstrainTypeExprBool(clause, \"ensures is expected to be of type bool, but is {0}\");\n      }\n\n      ResolveAttributes(decreases.Attributes, null, new ResolveOpts(codeContext, true));\n      foreach (Expression e in decreases.Expressions) {\n        ResolveExpression(e, new ResolveOpts(codeContext, true));\n        if (e is WildcardExpr) {\n          if (!codeContext.AllowsNontermination && !ArmadaOptions.O.Dafnycc) {\n            reporter.Error(MessageSource.Resolver, e, \"a possibly infinite loop is allowed only if the enclosing method is declared (with 'decreases *') to be possibly non-terminating\");\n          }\n        }\n        // any type is fine\n      }\n\n      ResolveAttributes(modifies.Attributes, null, new ResolveOpts(codeContext, true));\n      if (modifies.Expressions != null) {\n        foreach (FrameExpression fe in modifies.Expressions) {\n          ResolveFrameExpression(fe, FrameExpressionUse.Modifies, codeContext);\n          if (fvs != null) {\n            Translator.ComputeFreeVariables(fe.E, fvs);\n          }\n        }\n      }\n    }\n\n    void ResolveMatchStmt(MatchStmt s, ICodeContext codeContext) {\n      Contract.Requires(s != null);\n      Contract.Requires(codeContext != null);\n      Contract.Requires(s.OrigUnresolved == null);\n\n      // first, clone the original expression\n      s.OrigUnresolved = (MatchStmt)new Cloner().CloneStmt(s);\n      ResolveExpression(s.Source, new ResolveOpts(codeContext, true));\n      Contract.Assert(s.Source.Type != null);  // follows from postcondition of ResolveExpression\n      var errorCount = reporter.Count(ErrorLevel.Error);\n      if (s.Source is DatatypeValue) {\n        var e = (DatatypeValue)s.Source;\n        if (e.Arguments.Count < 1) {\n          reporter.Error(MessageSource.Resolver, s.Tok, \"match source tuple needs at least 1 argument\");\n        }\n        foreach (var arg in e.Arguments) {\n          if (arg is DatatypeValue && ((DatatypeValue)arg).Arguments.Count < 1) {\n            reporter.Error(MessageSource.Resolver, s.Tok, \"match source tuple needs at least 1 argument\");\n          }\n        }\n      }\n      if (reporter.Count(ErrorLevel.Error) != errorCount) {\n        return;\n      }\n      var sourceType = PartiallyResolveTypeForMemberSelection(s.Source.tok, s.Source.Type).NormalizeExpand();\n      var dtd = sourceType.AsDatatype;\n      var subst = new Dictionary<TypeParameter, Type>();\n      Dictionary<string, DatatypeCtor> ctors;\n      if (dtd == null) {\n        reporter.Error(MessageSource.Resolver, s.Source, \"the type of the match source expression must be a datatype (instead found {0})\", s.Source.Type);\n        ctors = null;\n      } else {\n        ctors = datatypeCtors[dtd];\n        Contract.Assert(ctors != null);  // dtd should have been inserted into datatypeCtors during a previous resolution stage\n\n        // build the type-parameter substitution map for this use of the datatype\n        subst = TypeSubstitutionMap(dtd.TypeArgs, sourceType.TypeArgs);\n      }\n\n      // convert CasePattern in MatchCaseExpr to BoundVar and flatten the MatchCaseExpr.\n      List<Tuple<CasePattern<BoundVar>, BoundVar>> patternSubst = new List<Tuple<CasePattern<BoundVar>, BoundVar>>();\n      if (dtd != null) {\n        DesugarMatchCaseStmt(s, dtd, patternSubst, codeContext);\n      }\n\n      ISet<string> memberNamesUsed = new HashSet<string>();\n      foreach (MatchCaseStmt mc in s.Cases) {\n        DatatypeCtor ctor = null;\n        if (ctors != null) {\n          Contract.Assert(dtd != null);\n          var ctorId = mc.Id;\n          if (s.Source.Type.AsDatatype is TupleTypeDecl) {\n            var tuple = (TupleTypeDecl)s.Source.Type.AsDatatype;\n            var dims = tuple.Dims;\n            ctorId = BuiltIns.TupleTypeCtorNamePrefix + dims;\n          }\n          if (!ctors.TryGetValue(ctorId, out ctor)) {\n            reporter.Error(MessageSource.Resolver, mc.tok, \"member {0} does not exist in datatype {1}\", ctorId, dtd.Name);\n          } else {\n            Contract.Assert(ctor != null);  // follows from postcondition of TryGetValue\n            mc.Ctor = ctor;\n            if (ctor.Formals.Count != mc.Arguments.Count) {\n              if (s.Source.Type.AsDatatype is TupleTypeDecl) {\n                reporter.Error(MessageSource.Resolver, mc.tok, \"case arguments count does not match source arguments count\");\n              } else {\n                reporter.Error(MessageSource.Resolver, mc.tok, \"member {0} has wrong number of formals (found {1}, expected {2})\", ctorId, mc.Arguments.Count, ctor.Formals.Count);\n              }\n            }\n            if (memberNamesUsed.Contains(ctorId)) {\n              reporter.Error(MessageSource.Resolver, mc.tok, \"member {0} appears in more than one case\", mc.Id);\n            } else {\n              memberNamesUsed.Add(ctorId);  // add mc.Id to the set of names used\n            }\n          }\n        }\n        scope.PushMarker();\n        int i = 0;\n        if (mc.Arguments != null) {\n          foreach (BoundVar v in mc.Arguments) {\n            scope.Push(v.Name, v);\n            ResolveType(v.tok, v.Type, codeContext, ResolveTypeOptionEnum.InferTypeProxies, null);\n            if (ctor != null && i < ctor.Formals.Count) {\n              Formal formal = ctor.Formals[i];\n              Type st = SubstType(formal.Type, subst);\n              ConstrainSubtypeRelation(v.Type, st, s.Tok,\n                \"the declared type of the formal ({0}) does not agree with the corresponding type in the constructor's signature ({1})\", v.Type, st);\n              v.IsGhost = formal.IsGhost;\n\n              // update the type of the boundvars in the MatchCaseToken\n              if (v.tok is MatchCaseToken) {\n                MatchCaseToken mt = (MatchCaseToken)v.tok;\n                foreach (Tuple<IToken, BoundVar, bool> entry in mt.varList) {\n                  ConstrainSubtypeRelation(entry.Item2.Type, v.Type, entry.Item1, \"incorrect type for bound match-case variable (expected {0}, got {1})\", v.Type, entry.Item2.Type);\n                }\n              }\n            }\n            i++;\n          }\n        }\n        dominatingStatementLabels.PushMarker();\n        foreach (Statement ss in mc.Body) {\n          ResolveStatement(ss, codeContext);\n        }\n        dominatingStatementLabels.PopMarker();\n        // substitute body to replace the case pat with v. This needs to happen\n        // after the body is resolved so we can scope the bv correctly.\n        if (patternSubst.Count > 0) {\n          var cloner = new MatchCaseExprSubstituteCloner(patternSubst);\n          List<Statement> list = new List<Statement>();\n          foreach (Statement ss in mc.Body) {\n            Statement clone = cloner.CloneStmt(ss);\n            // resolve it again since we just cloned it.\n            ResolveStatement(clone, codeContext);\n            list.Add(clone);\n          }\n          mc.UpdateBody(list);\n        }\n\n        scope.PopMarker();\n      }\n      if (dtd != null && memberNamesUsed.Count != dtd.Ctors.Count) {\n        // We could complain about the syntactic omission of constructors:\n        //   reporter.Error(MessageSource.Resolver, stmt, \"match statement does not cover all constructors\");\n        // but instead we let the verifier do a semantic check.\n        // So, for now, record the missing constructors:\n        foreach (var ctr in dtd.Ctors) {\n          if (!memberNamesUsed.Contains(ctr.Name)) {\n            s.MissingCases.Add(ctr);\n          }\n        }\n        Contract.Assert(memberNamesUsed.Count + s.MissingCases.Count == dtd.Ctors.Count);\n      }\n    }\n\n    /*\n     * Convert\n     *   match xs\n     *     case Cons(y, Cons(z, zs)) => last(Cons(z, zs))\n     *     case Cons(y, Nil) => y\n     * To\n     *   match xs\n     *     case Cons(y, ys) => match ys\n     *       case Nil => y\n     *       case Cons(z, zs) => last(ys)\n     */\n    void DesugarMatchCaseStmt(MatchStmt s, DatatypeDecl dtd, List<Tuple<CasePattern<BoundVar>, BoundVar>> patterns, ICodeContext codeContext) {\n      Contract.Assert(dtd != null);\n      Dictionary<string, DatatypeCtor> ctors = datatypeCtors[dtd];\n      if (ctors == null) {\n        // there is no constructor, no need to desugar\n        return;\n      }\n\n      var ctorsList = new List<Dictionary<string, DatatypeCtor>>();\n      if (s.Source.Type.AsDatatype is TupleTypeDecl) {\n        var udt = s.Source.Type.NormalizeExpand() as UserDefinedType;\n        foreach (Type typeArg in udt.TypeArgs) {\n          var t = PartiallyResolveTypeForMemberSelection(s.Tok, typeArg).NormalizeExpand() as UserDefinedType;\n          if (t != null && t.ResolvedClass is DatatypeDecl) {\n            dtd = (DatatypeDecl)t.ResolvedClass;\n            ctorsList.Add(datatypeCtors[dtd]);\n          } else {\n            ctorsList.Add(new Dictionary<string, DatatypeCtor>());\n          }\n        }\n      }\n      bool keepOrigToken = true;\n      foreach (MatchCaseStmt mc in s.Cases) {\n        if (mc.Arguments != null) {\n          // already desugared. This happens during the second pass resolver after cloning.\n          Contract.Assert(mc.CasePatterns == null);\n          return;\n        }\n\n        Contract.Assert(mc.Arguments == null);\n        Contract.Assert(mc.CasePatterns != null);\n        Contract.Assert(ctors != null);\n        DatatypeCtor ctor = null;\n\n        if (ctors.TryGetValue(mc.Id, out ctor) || s.Source.Type.AsDatatype is TupleTypeDecl) {\n          scope.PushMarker();\n          if (s.Source.Type.AsDatatype is TupleTypeDecl) {\n            int i = 0;\n            foreach (var pat in mc.CasePatterns) {\n              FindDuplicateIdentifier(pat, ctorsList[i++], true);\n            }\n          } else {\n            foreach (var pat in mc.CasePatterns) {\n              FindDuplicateIdentifier(pat, ctors, true);\n            }\n          }\n          List<BoundVar> arguments = new List<BoundVar>();\n          List<Statement> body = mc.Body;\n          for (int i = mc.CasePatterns.Count - 1; i >= 0; i--) {\n            string name = \"_ms#\" + i;\n            Type type = new InferredTypeProxy();\n            BoundVar sourceVar = new BoundVar(new MatchCaseToken(mc.tok), name, type);\n            var pat = mc.CasePatterns[i];\n            if (pat.Var != null) {\n              BoundVar v = pat.Var;\n              arguments.Insert(0, v);\n            } else {\n              body = DesugarMatchCasePattern(mc, pat, sourceVar, body, keepOrigToken);\n              patterns.Add(new Tuple<CasePattern<BoundVar>, BoundVar>(pat, sourceVar));\n              arguments.Insert(0, sourceVar);\n            }\n          }\n          keepOrigToken = false;\n          mc.UpdateBody(body);\n          mc.Arguments = arguments;\n          mc.CasePatterns = null;\n          scope.PopMarker();\n        }\n      }\n\n\n      List<MatchCaseStmt> newCases = new List<MatchCaseStmt>();\n\n      // need to consolidate the cases.\n      // Convert\n      //  match xs\n      //    case Cons(y, #mc#0) => match #mc#0\n      //                case Cons((z, zs) => body\n      //    case Cons(y, #mc#0) => match #mc#0\n      //                case Nil => y\n      // into\n      //  match xs\n      //    case Cons(y, #mc#0) => match #mc#0\n      //                case Cons((z, zs) => body\n      //                case Nil => y\n      bool thingsChanged = false;\n      Dictionary<string, MatchCaseStmt> caseMap = new Dictionary<string, MatchCaseStmt>();\n      List<MatchCaseStmt> mcWithWildCard = new List<MatchCaseStmt>();\n      foreach (MatchCaseStmt mc in s.Cases) {\n        // check each CasePattern to see if it has wildcard.\n        if (CaseExprHasWildCard(mc)) {\n          mcWithWildCard.Add(mc);\n        } else {\n          thingsChanged |= CombineMatchCaseStmt(mc, newCases, caseMap, codeContext);\n        }\n      }\n\n      foreach (MatchCaseStmt mc in mcWithWildCard) {\n        // now process with cases with wildcard\n        thingsChanged |= CombineMatchCaseStmt(mc, newCases, caseMap, codeContext);\n      }\n\n      if (thingsChanged) {\n        s.UpdateCases(newCases);\n      }\n    }\n\n    void FindDuplicateIdentifier<VT>(CasePattern<VT> pat, Dictionary<string, DatatypeCtor> ctors, bool topLevel) where VT: IVariable {\n      Contract.Assert(ctors != null);\n      DatatypeCtor ctor = null;\n      // Find the constructor in the given datatype\n      // If what was parsed was just an identifier, we will interpret it as a datatype constructor, if possible\n      if (pat.Var == null || (pat.Var != null && pat.Var.Type is TypeProxy)) {\n        if (ctors.TryGetValue(pat.Id, out ctor)) {\n          pat.Ctor = ctor;\n          pat.Var = default(VT);\n        }\n      }\n      if (pat.Var != null) {\n        IVariable v = pat.Var;\n        if (topLevel) {\n          ScopePushAndReport(scope, v, \"parameter\");\n        } else {\n          // For cons(a, const(b, c)):\n          // this handles check to see if 'b' or 'c' is duplicate with 'a',\n          // the duplication check between 'b' and 'c' is handled in the desugared\n          // form (to avoid reporting the same error twice), that is why we don't\n          // push 'b' and 'c' onto the scope, only find.\n          if (scope.FindInCurrentScope(v.Name) != null) {\n            reporter.Error(MessageSource.Resolver, v, \"Duplicate parameter name: {0}\", v.Name);\n          }\n        }\n      } else {\n        if (pat.Arguments != null) {\n          foreach (CasePattern<VT> cp in pat.Arguments) {\n            FindDuplicateIdentifier(cp, ctors, false);\n          }\n        }\n      }\n    }\n\n    List<Statement> DesugarMatchCasePattern(MatchCaseStmt mc, CasePattern<BoundVar> pat, BoundVar v, List<Statement> body, bool keepToken) {\n      // convert\n      //    case Cons(y, Cons(z, zs)) => body\n      // to\n      //    case Cons(y, #mc#) => match #mc#\n      //            case Cons(z, zs) => body\n\n      Expression source = new NameSegment(new AutoGeneratedToken(pat.tok), v.Name, null);\n      List<MatchCaseStmt> cases = new List<MatchCaseStmt>();\n      cases.Add(new MatchCaseStmt(pat.tok, pat.Id, pat.Arguments == null ? new List<CasePattern<BoundVar>>() : pat.Arguments, body));\n      List<Statement> list = new List<Statement>();\n      if (!keepToken) {\n        AutoGeneratedTokenCloner cloner = new AutoGeneratedTokenCloner();\n        source = cloner.CloneExpr(source);\n      }\n      list.Add(new MatchStmt(pat.tok, pat.tok, source, cases, false));\n      return list;\n    }\n\n    bool CombineMatchCaseStmt(MatchCaseStmt mc, List<MatchCaseStmt> newCases, Dictionary<string, MatchCaseStmt> caseMap, ICodeContext codeContext) {\n      bool thingsChanged = false;\n      MatchCaseStmt old_mc;\n      if (caseMap.TryGetValue(mc.Id, out old_mc)) {\n        // already has a case with the same ctor, try to consolidate the body.\n        List<Statement> oldBody = old_mc.Body;\n        List<Statement> body = mc.Body;\n        if ((oldBody.Count == 1) && (oldBody[0] is MatchStmt)\n            && (body.Count == 1) && (body[0] is MatchStmt)) {\n          // both only have on statement and the statement is MatchStmt\n          if (SameMatchCaseStmt(old_mc, mc, codeContext)) {\n            MatchStmt old = (MatchStmt)old_mc.Body[0];\n            MatchStmt current = (MatchStmt)mc.Body[0];\n            foreach (MatchCaseStmt c in current.Cases) {\n              old.Cases.Add(c);\n            }\n            // add the token from mc to old_mc so the identifiers will show correctly in the IDE\n            List<BoundVar> arguments = new List<BoundVar>();\n            Contract.Assert(old_mc.Arguments.Count == mc.Arguments.Count);\n            for (int i = 0; i < old_mc.Arguments.Count; i++) {\n              var bv = old_mc.Arguments[i];\n              MatchCaseToken mcToken;\n              if (!(bv.tok is MatchCaseToken)) {\n                // create a MatchCaseToken\n                mcToken = new MatchCaseToken(bv.tok);\n                // clone the bv but with the MatchCaseToken\n                var bvNew = new BoundVar(mcToken, bv.Name, bv.Type);\n                bvNew.IsGhost = bv.IsGhost;\n                arguments.Add(bvNew);\n              } else {\n                mcToken = (MatchCaseToken)bv.tok;\n                arguments.Add(bv);\n              }\n              mcToken.AddVar(bv.tok, bv, true);\n              mcToken.AddVar(mc.Arguments[i].tok, mc.Arguments[i], true);\n            }\n            old_mc.Arguments = arguments;\n            thingsChanged = true;\n          }\n        } else {\n          // duplicate cases, do nothing for now. The error will be reported during resolving\n        }\n      } else {\n        // it is a new case.\n        newCases.Add(mc);\n        caseMap.Add(mc.Id, mc);\n      }\n      return thingsChanged;\n    }\n\n    bool SameMatchCaseStmt(MatchCaseStmt one, MatchCaseStmt other, ICodeContext codeContext) {\n      // this method is called after all the CasePattern in the match cases are converted\n      // into BoundVars.\n      Contract.Assert(one.CasePatterns == null && one.Arguments != null);\n      Contract.Assert(other.CasePatterns == null && other.Arguments != null);\n      // In order to combine the two match cases, the bodies need to be a MatchExpr and\n      // the arguments and the source of the body are the same.\n      // We do string equals since they should be in the same scope.\n      if (one.Arguments.Count != other.Arguments.Count) {\n        return false;\n      }\n      List<Statement> body1 = one.Body;\n      List<Statement> body2 = other.Body;\n      if ((body1.Count != 1) || (body2.Count != 1)) {\n        return false;\n      }\n      if (!(body1[0] is MatchStmt) || !(body2[0] is MatchStmt)) {\n       return false;\n      }\n      var source1 = ((MatchStmt)body1[0]).Source;\n      var source2 = ((MatchStmt)body2[0]).Source;\n      if (!(source1 is NameSegment) || !(source2 is NameSegment)) {\n        return false;\n      }\n      if (!((NameSegment)source1).Name.Equals(((NameSegment)source2).Name)) {\n        return false;\n      }\n      for (int i = 0; i < one.Arguments.Count; i++) {\n        BoundVar bv1 = one.Arguments[i];\n        BoundVar bv2 = other.Arguments[i];\n        if (!LocalVariable.HasWildcardName(bv1) && !LocalVariable.HasWildcardName(bv2)) {\n          if (!bv1.Name.Equals(bv2.Name)) {\n            // need to substitute bv2 with bv1 in the matchstmt body\n            // what if match body already has the bv?? need to make a new bv\n            Type type = new InferredTypeProxy();\n            string name = FreshTempVarName(\"_mc#\", codeContext);\n            BoundVar bv = new BoundVar(new MatchCaseToken(one.tok), name, type);\n            ((MatchCaseToken)bv.tok).AddVar(bv1.tok, bv1, true);\n            ((MatchCaseToken)bv.tok).AddVar(bv2.tok, bv2, true);\n            SubstituteMatchCaseBoundVar(one, bv1, bv);\n            SubstituteMatchCaseBoundVar(other, bv2, bv);\n          }\n        }\n      }\n      return true;\n    }\n\n    void SubstituteMatchCaseBoundVar(MatchCaseStmt mc, BoundVar oldBv, BoundVar newBv) {\n      List<BoundVar> arguments = new List<BoundVar>();\n      for (int i = 0; i < mc.Arguments.Count; i++) {\n        BoundVar bv = mc.Arguments[i];\n        if (bv == oldBv) {\n          arguments.Add(newBv);\n        } else {\n          arguments.Add(bv);\n        }\n      }\n      mc.Arguments = arguments;\n\n      // substitue the oldBv with newBv in the body\n      MatchCaseExprSubstituteCloner cloner = new MatchCaseExprSubstituteCloner(oldBv, newBv);\n      List<Statement> list = new List<Statement>();\n      foreach (Statement ss in mc.Body) {\n        Statement clone = cloner.CloneStmt(ss);\n        list.Add(clone);\n      }\n      mc.UpdateBody(list);\n    }\n\n    void FillInDefaultLoopDecreases(LoopStmt loopStmt, Expression guard, List<Expression> theDecreases, ICallable enclosingMethod) {\n      Contract.Requires(loopStmt != null);\n      Contract.Requires(theDecreases != null);\n\n      if (theDecreases.Count == 0 && guard != null) {\n        loopStmt.InferredDecreases = true;\n        Expression prefix = null;\n        foreach (Expression guardConjunct in Expression.Conjuncts(guard)) {\n          Expression guess = null;\n          BinaryExpr bin = guardConjunct as BinaryExpr;\n          if (bin != null) {\n            switch (bin.ResolvedOp) {\n              case BinaryExpr.ResolvedOpcode.Lt:\n              case BinaryExpr.ResolvedOpcode.Le:\n                // for A < B and A <= B, use the decreases B - A\n                guess = Expression.CreateSubtract_TypeConvert(bin.E1, bin.E0);\n                break;\n              case BinaryExpr.ResolvedOpcode.Ge:\n              case BinaryExpr.ResolvedOpcode.Gt:\n                // for A >= B and A > B, use the decreases A - B\n                guess = Expression.CreateSubtract_TypeConvert(bin.E0, bin.E1);\n                break;\n              case BinaryExpr.ResolvedOpcode.NeqCommon:\n                if (bin.E0.Type.IsNumericBased()) {\n                  // for A != B where A and B are numeric, use the absolute difference between A and B (that is: if A <= B then B-A else A-B)\n                  var AminusB = Expression.CreateSubtract_TypeConvert(bin.E0, bin.E1);\n                  var BminusA = Expression.CreateSubtract_TypeConvert(bin.E1, bin.E0);\n                  var test = Expression.CreateAtMost(bin.E0, bin.E1);\n                  guess = Expression.CreateITE(test, BminusA, AminusB);\n                }\n                break;\n              default:\n                break;\n            }\n          }\n          if (guess != null) {\n            if (prefix != null) {\n              // Make the following guess:  if prefix then guess else -1\n              guess = Expression.CreateITE(prefix, guess, Expression.CreateIntLiteral(prefix.tok, -1));\n            }\n            theDecreases.Add(AutoGeneratedExpression.Create(guess));\n            break;  // ignore any further conjuncts\n          }\n          if (prefix == null) {\n            prefix = guardConjunct;\n          } else {\n            prefix = Expression.CreateAnd(prefix, guardConjunct);\n          }\n        }\n      }\n      if (enclosingMethod is IteratorDecl) {\n        var iter = (IteratorDecl)enclosingMethod;\n        var ie = new IdentifierExpr(loopStmt.Tok, iter.YieldCountVariable.Name);\n        ie.Var = iter.YieldCountVariable;  // resolve here\n        ie.Type = iter.YieldCountVariable.Type;  // resolve here\n        theDecreases.Insert(0, AutoGeneratedExpression.Create(ie));\n        loopStmt.InferredDecreases = true;\n      }\n      if (loopStmt.InferredDecreases) {\n        string s = \"decreases \" + Util.Comma(\", \", theDecreases, Printer.ExprToString);\n        reporter.Info(MessageSource.Resolver, loopStmt.Tok, s);\n      }\n    }\n    private void ResolveConcreteUpdateStmt(ConcreteUpdateStatement s, ICodeContext codeContext) {\n      Contract.Requires(codeContext != null);\n\n      // First, resolve all LHS's and expression-looking RHS's.\n      int errorCountBeforeCheckingLhs = reporter.Count(ErrorLevel.Error);\n\n      var lhsNameSet = new HashSet<string>();  // used to check for duplicate identifiers on the left (full duplication checking for references and the like is done during verification)\n      foreach (var lhs in s.Lhss) {\n        var ec = reporter.Count(ErrorLevel.Error);\n        ResolveExpression(lhs, new ResolveOpts(codeContext, true));\n        if (ec == reporter.Count(ErrorLevel.Error)) {\n          if (lhs is SeqSelectExpr && !((SeqSelectExpr)lhs).SelectOne) {\n            reporter.Error(MessageSource.Resolver, lhs, \"cannot assign to a range of array elements (try the 'forall' statement)\");\n          }\n        }\n      }\n\n      // Resolve RHSs\n      if (s is AssignSuchThatStmt) {\n        ResolveAssignSuchThatStmt((AssignSuchThatStmt)s, codeContext);\n      } else if (s is UpdateStmt) {\n        ResolveUpdateStmt((UpdateStmt)s, codeContext, errorCountBeforeCheckingLhs);\n      } else if (s is AssignOrReturnStmt) {\n        ResolveAssignOrReturnStmt((AssignOrReturnStmt)s, codeContext);\n      } else {\n        Contract.Assert(false); throw new cce.UnreachableException();\n      }\n      ResolveAttributes(s.Attributes, s, new ResolveOpts(codeContext, true));\n    }\n    /// <summary>\n    /// Resolve the RHSs and entire UpdateStmt (LHSs should already have been checked by the caller).\n    /// errorCountBeforeCheckingLhs is passed in so that this method can determined if any resolution errors were found during\n    /// LHS or RHS checking, because only if no errors were found is update.ResolvedStmt changed.\n    /// </summary>\n    private void ResolveUpdateStmt(UpdateStmt update, ICodeContext codeContext, int errorCountBeforeCheckingLhs) {\n      Contract.Requires(update != null);\n      Contract.Requires(codeContext != null);\n      IToken firstEffectfulRhs = null;\n      MethodCallInformation methodCallInfo = null;\n      var j = 0;\n      foreach (var rhs in update.Rhss) {\n        bool isEffectful;\n        if (rhs is TypeRhs) {\n          var tr = (TypeRhs)rhs;\n          ResolveTypeRhs(tr, update, codeContext);\n          isEffectful = tr.InitCall != null;\n        } else if (rhs is HavocRhs) {\n          isEffectful = false;\n        } else if (rhs is CreateThreadRhs) {\n          var r = (CreateThreadRhs)rhs;\n          isEffectful = true;\n          foreach (var arg in r.Args) {\n            ResolveExpression(arg, new ResolveOpts(codeContext, false));\n          }\n        } else if (rhs is MallocRhs) {\n          isEffectful = true;\n        } else if (rhs is CallocRhs) {\n          isEffectful = true;\n        } else if (rhs is CompareAndSwapRhs) {\n          var r = (CompareAndSwapRhs)rhs;\n          isEffectful = true;\n          ResolveExpression(r.Target, new ResolveOpts(codeContext, false));\n          ResolveExpression(r.OldVal, new ResolveOpts(codeContext, false));\n          ResolveExpression(r.NewVal, new ResolveOpts(codeContext, false));\n          AddAssignableConstraint(update.Tok, r.Target.Type, r.OldVal.Type, \"Compare-and-swap must use same type for target and comparison value\");\n          AddAssignableConstraint(update.Tok, r.Target.Type, r.NewVal.Type, \"Compare-and-swap must use same type for target and new value\");\n        } else if (rhs is AtomicExchangeRhs) {\n          var r = (AtomicExchangeRhs)rhs;\n          isEffectful = true;\n          ResolveExpression(r.Target, new ResolveOpts(codeContext, false));\n          ResolveExpression(r.NewVal, new ResolveOpts(codeContext, false));\n          AddAssignableConstraint(update.Tok, r.Target.Type, r.NewVal.Type, \"atomic-exchange must use same type for target and new value\");\n        }\n        else {\n          var er = (ExprRhs)rhs;\n          if (er.Expr is ApplySuffix) {\n            var a = (ApplySuffix)er.Expr;\n            var cRhs = ResolveApplySuffix(a, new ResolveOpts(codeContext, true), true);\n            isEffectful = cRhs != null;\n            methodCallInfo = methodCallInfo ?? cRhs;\n          } else if (er.Expr is RevealExpr) {\n            var r = (RevealExpr)er.Expr;\n            var cRhs = ResolveRevealExpr(r, new ResolveOpts(codeContext, true), true);\n            isEffectful = cRhs != null;\n            methodCallInfo = methodCallInfo ?? cRhs;\n          } else {\n            ResolveExpression(er.Expr, new ResolveOpts(codeContext, true));\n            isEffectful = false;\n          }\n        }\n        if (isEffectful && firstEffectfulRhs == null) {\n          firstEffectfulRhs = rhs.Tok;\n        }\n        j++;\n      }\n\n      // figure out what kind of UpdateStmt this is\n      if (firstEffectfulRhs == null) {\n        if (update.Lhss.Count == 0) {\n          Contract.Assert(update.Rhss.Count == 1);  // guaranteed by the parser\n          reporter.Error(MessageSource.Resolver, update, \"expected method call, found expression\");\n        } else if (update.Lhss.Count != update.Rhss.Count) {\n          reporter.Error(MessageSource.Resolver, update, \"the number of left-hand sides ({0}) and right-hand sides ({1}) must match for a multi-assignment\", update.Lhss.Count, update.Rhss.Count);\n        } else if (reporter.Count(ErrorLevel.Error) == errorCountBeforeCheckingLhs) {\n          // add the statements here in a sequence, but don't use that sequence later for translation (instead, should translate properly as multi-assignment)\n          for (int i = 0; i < update.Lhss.Count; i++) {\n            var a = new AssignStmt(update.Tok, update.EndTok, update.Lhss[i].Resolved, update.Rhss[i]);\n            update.ResolvedStatements.Add(a);\n          }\n        }\n\n      } else if (update.CanMutateKnownState) {\n        if (1 < update.Rhss.Count) {\n          reporter.Error(MessageSource.Resolver, firstEffectfulRhs, \"cannot have effectful parameter in multi-return statement.\");\n        } else { // it might be ok, if it is a TypeRhs\n          Contract.Assert(update.Rhss.Count == 1);\n          if (methodCallInfo != null) {\n            reporter.Error(MessageSource.Resolver, methodCallInfo.Tok, \"cannot have method call in return statement.\");\n          } else {\n            // we have a TypeRhs\n            Contract.Assert(update.Rhss[0] is TypeRhs);\n            var tr = (TypeRhs)update.Rhss[0];\n            Contract.Assert(tr.InitCall != null); // there were effects, so this must have been a call.\n            if (tr.CanAffectPreviouslyKnownExpressions) {\n              reporter.Error(MessageSource.Resolver, tr.Tok, \"can only have initialization methods which modify at most 'this'.\");\n            } else if (reporter.Count(ErrorLevel.Error) == errorCountBeforeCheckingLhs) {\n              var a = new AssignStmt(update.Tok, update.EndTok, update.Lhss[0].Resolved, tr);\n              update.ResolvedStatements.Add(a);\n            }\n          }\n        }\n\n      } else {\n        // if there was an effectful RHS, that must be the only RHS\n        if (update.Rhss.Count != 1) {\n          reporter.Error(MessageSource.Resolver, firstEffectfulRhs, \"an update statement is allowed an effectful RHS only if there is just one RHS\");\n        } else if (methodCallInfo == null) {\n          // must be a single TypeRhs\n          if (update.Lhss.Count == 0 && update.Rhss.Count == 1 && (update.Rhss[0] is CreateThreadRhs || update.Rhss[0] is CompareAndSwapRhs || update.Rhss[0] is AtomicExchangeRhs)) {\n          }\n          else if (update.Lhss.Count != 1) {\n            Contract.Assert(2 <= update.Lhss.Count);  // the parser allows 0 Lhss only if the whole statement looks like an expression (not a TypeRhs)\n            reporter.Error(MessageSource.Resolver, update.Lhss[1].tok, \"the number of left-hand sides ({0}) and right-hand sides ({1}) must match for a multi-assignment\", update.Lhss.Count, update.Rhss.Count);\n          } else if (reporter.Count(ErrorLevel.Error) == errorCountBeforeCheckingLhs) {\n            var a = new AssignStmt(update.Tok, update.EndTok, update.Lhss[0].Resolved, update.Rhss[0]);\n            update.ResolvedStatements.Add(a);\n          }\n        } else if (reporter.Count(ErrorLevel.Error) == errorCountBeforeCheckingLhs) {\n          // a call statement\n          var resolvedLhss = new List<Expression>();\n          foreach (var ll in update.Lhss) {\n            resolvedLhss.Add(ll.Resolved);\n          }\n          var a = new CallStmt(methodCallInfo.Tok, update.EndTok, resolvedLhss, methodCallInfo.Callee, methodCallInfo.Args);\n          update.ResolvedStatements.Add(a);\n        }\n      }\n\n      foreach (var a in update.ResolvedStatements) {\n        ResolveStatement(a, codeContext);\n      }\n    }\n\n    private void ResolveAssignSuchThatStmt(AssignSuchThatStmt s, ICodeContext codeContext) {\n      Contract.Requires(s != null);\n      Contract.Requires(codeContext != null);\n\n      if (s.AssumeToken == null) {\n        // to ease in the verification of the existence check, only allow local variables as LHSs\n        foreach (var lhs in s.Lhss) {\n          var ide = lhs.Resolved as IdentifierExpr;\n          if (ide == null) {\n            reporter.Error(MessageSource.Resolver, lhs, \"an assign-such-that statement (without an 'assume' clause) currently only supports local-variable LHSs\");\n          }\n        }\n      }\n\n      ResolveExpression(s.Expr, new ResolveOpts(codeContext, true));\n      ConstrainTypeExprBool(s.Expr, \"type of RHS of assign-such-that statement must be boolean (got {0})\");\n    }\n\n    private Expression VarDotMethod(IToken tok, string varname, string methodname) {\n      return new ApplySuffix(tok, new ExprDotName(tok, new IdentifierExpr(tok, varname), methodname, null), new List<Expression>() { });\n    }\n\n    /// <summary>\n    /// Desugars \"y :- MethodOrExpression\" into\n    /// \"var temp := MethodOrExpression; if temp.IsFailure() { return temp.PropagateFailure(); } y := temp.Extract();\"\n    /// and saves the result into s.ResolvedStatements.\n    /// </summary>\n    private void ResolveAssignOrReturnStmt(AssignOrReturnStmt s, ICodeContext codeContext) {\n      // TODO Do I have any responsibilities regarding the use of codeContext? Is it mutable?\n      // NOTE (Luke): Since Armada does not support AssignOrReturnStmt, and I don't think\n      //              it will be supported in any recent future, this desugaring procedure is\n      //              only filled with nonsense placeholders\n\n      var temp = FreshTempVarName(\"valueOrError\", codeContext);\n      var tempType = new InferredTypeProxy();\n      s.ResolvedStatements.Add(\n        // \"var temp := MethodOrExpression;\"\n                               new VarDeclStmt(s.Tok, s.Tok, new List<LocalVariable>() { new LocalVariable(s.Tok, s.Tok, temp, tempType, false, false) },\n                               new UpdateStmt(s.Tok, s.Tok, new List<Expression>() { new IdentifierExpr(s.Tok, temp) }, new List<AssignmentRhs>() { new ExprRhs(s.Rhs) }), false));\n      s.ResolvedStatements.Add(\n        // \"if temp.IsFailure()\"\n        new IfStmt(s.Tok, s.Tok, false, VarDotMethod(s.Tok, temp, \"IsFailure\"),\n          // THEN: { return temp.PropagateFailure(); }\n          new BlockStmt(s.Tok, s.Tok, new List<Statement>() {\n            new ReturnStmt(s.Tok, s.Tok, new List<AssignmentRhs>() { new ExprRhs(VarDotMethod(s.Tok, temp, \"PropagateFailure\"))}),\n          }),\n          // ELSE: no else block\n          null\n        ));\n\n      Contract.Assert(s.Lhss.Count <= 1);\n      if (s.Lhss.Count == 1)\n      {\n        // \"y := temp.Extract();\"\n        s.ResolvedStatements.Add(\n          new UpdateStmt(s.Tok, s.Tok, s.Lhss, new List<AssignmentRhs>() {\n            new ExprRhs(VarDotMethod(s.Tok, temp, \"Extract\"))}));\n      }\n\n      foreach (var a in s.ResolvedStatements) {\n        ResolveStatement(a, codeContext);\n      }\n      bool expectExtract = s.Lhss.Count != 0;\n      EnsureSupportsErrorHandling(s.Tok, PartiallyResolveTypeForMemberSelection(s.Tok, tempType), expectExtract);\n    }\n\n    private void EnsureSupportsErrorHandling(IToken tok, Type tp, bool expectExtract) {\n      // The \"method not found\" errors which will be generated here were already reported while\n      // resolving the statement, so we don't want them to reappear and redirect them into a sink.\n      var origReporter = this.reporter;\n      this.reporter = new ErrorReporterSink();\n\n      NonProxyType ignoredNptype = null;\n      if (ResolveMember(tok, tp, \"IsFailure\", out ignoredNptype) == null ||\n          ResolveMember(tok, tp, \"PropagateFailure\", out ignoredNptype) == null ||\n          (ResolveMember(tok, tp, \"Extract\", out ignoredNptype) != null) != expectExtract\n      ) {\n        // more details regarding which methods are missing have already been reported by regular resolution\n        origReporter.Error(MessageSource.Resolver, tok,\n          \"The right-hand side of ':-', which is of type '{0}', must have members 'IsFailure()', 'PropagateFailure()', {1} 'Extract()'\",\n          tp, expectExtract ? \"and\" : \"but not\");\n      }\n\n      this.reporter = origReporter;\n    }\n\n    void ResolveAlternatives(List<GuardedAlternative> alternatives, AlternativeLoopStmt loopToCatchBreaks, ICodeContext codeContext) {\n      Contract.Requires(alternatives != null);\n      Contract.Requires(codeContext != null);\n\n      // first, resolve the guards\n      foreach (var alternative in alternatives) {\n        int prevErrorCount = reporter.Count(ErrorLevel.Error);\n        ResolveExpression(alternative.Guard, new ResolveOpts(codeContext, true));\n        Contract.Assert(alternative.Guard.Type != null);  // follows from postcondition of ResolveExpression\n        bool successfullyResolved = reporter.Count(ErrorLevel.Error) == prevErrorCount;\n        ConstrainTypeExprBool(alternative.Guard, \"condition is expected to be of type bool, but is {0}\");\n      }\n\n      if (loopToCatchBreaks != null) {\n        loopStack.Add(loopToCatchBreaks);  // push\n      }\n      foreach (var alternative in alternatives) {\n        scope.PushMarker();\n        dominatingStatementLabels.PushMarker();\n        if (alternative.IsBindingGuard) {\n          var exists = (ExistsExpr)alternative.Guard;\n          foreach (var v in exists.BoundVars) {\n            ScopePushAndReport(scope, v, \"bound-variable\");\n          }\n        }\n        foreach (Statement ss in alternative.Body) {\n          ResolveStatement(ss, codeContext);\n        }\n        dominatingStatementLabels.PopMarker();\n        scope.PopMarker();\n      }\n      if (loopToCatchBreaks != null) {\n        loopStack.RemoveAt(loopStack.Count - 1);  // pop\n      }\n    }\n\n    /// <summary>\n    /// Resolves the given call statement.\n    /// Assumes all LHSs have already been resolved (and checked for mutability).\n    /// </summary>\n    void ResolveCallStmt(CallStmt s, ICodeContext codeContext, Type receiverType) {\n      Contract.Requires(s != null);\n      Contract.Requires(codeContext != null);\n      bool isInitCall = receiverType != null;\n\n      var callee = s.Method;\n      Contract.Assert(callee != null);  // follows from the invariant of CallStmt\n      if (!isInitCall && callee is Constructor) {\n        reporter.Error(MessageSource.Resolver, s, \"a constructor is allowed to be called only when an object is being allocated\");\n      }\n\n      // resolve left-hand sides\n      foreach (var lhs in s.Lhs) {\n        Contract.Assume(lhs.Type != null);  // a sanity check that LHSs have already been resolved\n      }\n      // resolve arguments\n      int j = 0;\n      foreach (Expression e in s.Args) {\n        ResolveExpression(e, new ResolveOpts(codeContext, true));\n        j++;\n      }\n\n      if (callee.Ins.Count != s.Args.Count) {\n        reporter.Error(MessageSource.Resolver, s, \"wrong number of method arguments (got {0}, expected {1})\", s.Args.Count, callee.Ins.Count);\n      } else if (callee.Outs.Count != s.Lhs.Count) {\n        if (isInitCall) {\n          reporter.Error(MessageSource.Resolver, s, \"a method called as an initialization method must not have any result arguments\");\n        } else {\n          reporter.Error(MessageSource.Resolver, s, \"wrong number of method result arguments (got {0}, expected {1})\", s.Lhs.Count, callee.Outs.Count);\n        }\n      } else {\n        if (isInitCall) {\n          if (callee.IsStatic) {\n            reporter.Error(MessageSource.Resolver, s.Tok, \"a method called as an initialization method must not be 'static'\");\n          }\n        } else if (!callee.IsStatic) {\n          if (!scope.AllowInstance && s.Receiver is ThisExpr) {\n            // The call really needs an instance, but that instance is given as 'this', which is not\n            // available in this context.  For more details, see comment in the resolution of a\n            // FunctionCallExpr.\n            reporter.Error(MessageSource.Resolver, s.Receiver, \"'this' is not allowed in a 'static' context\");\n          } else if (s.Receiver is StaticReceiverExpr) {\n            reporter.Error(MessageSource.Resolver, s.Receiver, \"call to instance method requires an instance\");\n          }\n        }\n        // type check the arguments\n        var subst = s.MethodSelect.TypeArgumentSubstitutions();\n        for (int i = 0; i < callee.Ins.Count; i++) {\n          var it = callee.Ins[i].Type;\n          Type st = SubstType(it, subst);\n          AddAssignableConstraint(s.Tok, st, s.Args[i].Type, \"incorrect type of method in-parameter\" + (callee.Ins.Count == 1 ? \"\" : \" \" + i) + \" (expected {0}, got {1})\");\n        }\n        for (int i = 0; i < callee.Outs.Count; i++) {\n          var it = callee.Outs[i].Type;\n          Type st = SubstType(it, subst);\n          var lhs = s.Lhs[i];\n          AddAssignableConstraint(s.Tok, lhs.Type, st, \"incorrect type of method out-parameter\" + (callee.Outs.Count == 1 ? \"\" : \" \" + i) + \" (expected {1}, got {0})\");\n          // LHS must denote a mutable field.\n          CheckIsLvalue(lhs.Resolved, codeContext);\n        }\n\n        // Resolution termination check\n        ModuleDefinition callerModule = codeContext.EnclosingModule;\n        ModuleDefinition calleeModule = ((ICodeContext)callee).EnclosingModule;\n        if (callerModule == calleeModule) {\n          // intra-module call; add edge in module's call graph\n          var caller = codeContext as ICallable;\n          if (caller == null) {\n            // don't add anything to the call graph after all\n          } else if (caller is IteratorDecl) {\n            callerModule.CallGraph.AddEdge(((IteratorDecl)caller).Member_MoveNext, callee);\n          } else {\n            callerModule.CallGraph.AddEdge(caller, callee);\n            if (caller == callee) {\n              callee.IsRecursive = true;  // self recursion (mutual recursion is determined elsewhere)\n            }\n          }\n        }\n      }\n      if (Contract.Exists(callee.Decreases.Expressions, e => e is WildcardExpr) && !codeContext.AllowsNontermination) {\n        reporter.Error(MessageSource.Resolver, s.Tok, \"a call to a possibly non-terminating method is allowed only if the calling method is also declared (with 'decreases *') to be possibly non-terminating\");\n      }\n    }\n\n    /// <summary>\n    /// Checks if lhs, which is expected to be a successfully resolved expression, denotes something\n    /// that can be assigned to.  In particular, this means that lhs denotes a mutable variable, field,\n    /// or array element.  If a violation is detected, an error is reported.\n    /// </summary>\n    void CheckIsLvalue(Expression lhs, ICodeContext codeContext) {\n      Contract.Requires(lhs != null);\n      Contract.Requires(codeContext != null);\n      if (lhs is IdentifierExpr) {\n        var ll = (IdentifierExpr)lhs;\n        if (!ll.Var.IsMutable && moduleInfo.ModuleType != ArmadaModuleType.ArmadaLevel) {\n          reporter.Error(MessageSource.Resolver, lhs, \"LHS of assignment must denote a mutable variable\");\n        }\n      } else if (lhs is MemberSelectExpr) {\n        var ll = (MemberSelectExpr)lhs;\n        var field = ll.Member as Field;\n        if (field == null || !field.IsUserMutable) {\n          var cf = field as ConstantField;\n          if (inBodyInitContext && cf != null && !cf.IsStatic && cf.Rhs == null) {\n            if (Expression.AsThis(ll.Obj) != null) {\n              // it's cool; this field can be assigned to here\n            } else {\n              reporter.Error(MessageSource.Resolver, lhs, \"LHS of assignment must denote a mutable field of 'this'\");\n            }\n          } else if (moduleInfo.ModuleType != ArmadaModuleType.ArmadaLevel) {\n            reporter.Error(MessageSource.Resolver, lhs, \"LHS of assignment must denote a mutable field\");\n          }\n        }\n      } else if (lhs is SeqSelectExpr) {\n        var ll = (SeqSelectExpr)lhs;\n        if (ll.Seq.Type is SizedArrayType) {\n          // do nothing\n        } else if (moduleInfo.ModuleType != ArmadaModuleType.ArmadaLevel) {\n          ConstrainSubtypeRelation(ResolvedArrayType(ll.Seq.tok, 1, new InferredTypeProxy(), codeContext, true), ll.Seq.Type, ll.Seq,\n            \"LHS of array assignment must denote an array element (found {0})\", ll.Seq.Type);\n        }\n        if (!ll.SelectOne) {\n          reporter.Error(MessageSource.Resolver, ll.Seq, \"cannot assign to a range of array elements (try the 'forall' statement)\");\n        }\n      } else if (lhs is MultiSelectExpr) {\n        // nothing to check; this can only denote an array element\n      } else if (lhs is UnaryOpExpr && ((UnaryOpExpr)lhs).Op == UnaryOpExpr.Opcode.Dereference) {\n        // do nothing, this is allowed\n      } else {\n        reporter.Error(MessageSource.Resolver, lhs, \"LHS of assignment must denote a mutable variable or field\");\n      }\n    }\n\n    void ResolveBlockStatement(BlockStmt blockStmt, ICodeContext codeContext) {\n      Contract.Requires(blockStmt != null);\n      Contract.Requires(codeContext != null);\n\n      if (blockStmt is DividedBlockStmt) {\n        var div = (DividedBlockStmt)blockStmt;\n        Contract.Assert(currentMethod is Constructor);  // divided bodies occur only in class constructors\n        Contract.Assert(!inBodyInitContext);  // divided bodies are never nested\n        inBodyInitContext = true;\n        foreach (Statement ss in div.BodyInit) {\n          ResolveStatementWithLabels(ss, codeContext);\n        }\n        Contract.Assert(inBodyInitContext);\n        inBodyInitContext = false;\n        foreach (Statement ss in div.BodyProper) {\n          ResolveStatementWithLabels(ss, codeContext);\n        }\n      } else {\n        foreach (Statement ss in blockStmt.Body) {\n          ResolveStatementWithLabels(ss, codeContext);\n        }\n      }\n    }\n\n    void ResolveStatementWithLabels(Statement stmt, ICodeContext codeContext) {\n      Contract.Requires(stmt != null);\n      Contract.Requires(codeContext != null);\n\n      enclosingStatementLabels.PushMarker();\n      // push labels\n      for (var l = stmt.Labels; l != null; l = l.Next) {\n        var lnode = l.Data;\n        Contract.Assert(lnode.Name != null);  // LabelNode's with .Label==null are added only during resolution of the break statements with 'stmt' as their target, which hasn't happened yet\n        var prev = enclosingStatementLabels.Find(lnode.Name);\n        if (prev == stmt) {\n          reporter.Error(MessageSource.Resolver, lnode.Tok, \"duplicate label\");\n        } else if (prev != null) {\n          reporter.Error(MessageSource.Resolver, lnode.Tok, \"label shadows an enclosing label\");\n        } else {\n          var r = enclosingStatementLabels.Push(lnode.Name, stmt);\n          Contract.Assert(r == Scope<Statement>.PushResult.Success);  // since we just checked for duplicates, we expect the Push to succeed\n          if (dominatingStatementLabels.Find(lnode.Name) != null) {\n            reporter.Error(MessageSource.Resolver, lnode.Tok, \"label shadows a dominating label\");\n          } else {\n            var rr = dominatingStatementLabels.Push(lnode.Name, lnode);\n            Contract.Assert(rr == Scope<Label>.PushResult.Success);  // since we just checked for duplicates, we expect the Push to succeed\n          }\n        }\n      }\n      ResolveStatement(stmt, codeContext);\n      enclosingStatementLabels.PopMarker();\n    }\n\n    /// <summary>\n    /// This method performs some additional checks on the body \"stmt\" of a forall statement of kind \"kind\".\n    /// </summary>\n    public void CheckForallStatementBodyRestrictions(Statement stmt, ForallStmt.BodyKind kind) {\n      Contract.Requires(stmt != null);\n      if (stmt is PredicateStmt) {\n        // cool\n      } else if (stmt is RevealStmt) {\n        var s = (RevealStmt)stmt;\n        foreach (var ss in s.ResolvedStatements) {\n          CheckForallStatementBodyRestrictions(ss, kind);\n        }\n      } else if (stmt is SomehowStmt) {\n        reporter.Error(MessageSource.Resolver, stmt, \"somehow statement is not allowed inside a forall statement\");\n      } else if (stmt is FenceStmt) {\n        reporter.Error(MessageSource.Resolver, stmt, \"fence statement is not allowed inside a forall statement\");\n      } else if (stmt is GotoStmt) {\n        reporter.Error(MessageSource.Resolver, stmt, \"goto statement is not allowed inside a forall statement\");\n      } else if (stmt is DeallocStmt) {\n        reporter.Error(MessageSource.Resolver, stmt, \"dealloc statement is not allowed inside a forall statement\");\n      } else if (stmt is JoinStmt) {\n        reporter.Error(MessageSource.Resolver, stmt, \"join statement is not allowed inside a forall statement\");\n      } else if (stmt is PrintStmt) {\n        reporter.Error(MessageSource.Resolver, stmt, \"print statement is not allowed inside a forall statement\");\n      } else if (stmt is BreakStmt) {\n        // this case is checked already in the first pass through the forall-statement body, by doing so from an empty set of labeled statements and resetting the loop-stack\n      } else if (stmt is ContinueStmt) {\n        reporter.Error(MessageSource.Resolver, stmt, \"continue tatement is not allowed inside a forall statement\");\n      } else if (stmt is ReturnStmt) {\n        reporter.Error(MessageSource.Resolver, stmt, \"return statement is not allowed inside a forall statement\");\n      } else if (stmt is YieldStmt) {\n        reporter.Error(MessageSource.Resolver, stmt, \"yield statement is not allowed inside a forall statement\");\n      } else if (stmt is AssignSuchThatStmt) {\n        var s = (AssignSuchThatStmt)stmt;\n        foreach (var lhs in s.Lhss) {\n          CheckForallStatementBodyLhs(s.Tok, lhs.Resolved, kind);\n        }\n      } else if (stmt is UpdateStmt) {\n        var s = (UpdateStmt)stmt;\n        foreach (var ss in s.ResolvedStatements) {\n          CheckForallStatementBodyRestrictions(ss, kind);\n        }\n      } else if (stmt is VarDeclStmt) {\n        var s = (VarDeclStmt)stmt;\n        if (s.Update != null) {\n          CheckForallStatementBodyRestrictions(s.Update, kind);\n        }\n      } else if (stmt is LetStmt) {\n        // Are we fine?\n      } else if (stmt is AssignStmt) {\n        var s = (AssignStmt)stmt;\n        CheckForallStatementBodyLhs(s.Tok, s.Lhs.Resolved, kind);\n        var rhs = s.Rhs;  // ExprRhs and HavocRhs are fine, but TypeRhs is not\n        if (rhs is TypeRhs) {\n          if (kind == ForallStmt.BodyKind.Assign) {\n            reporter.Error(MessageSource.Resolver, rhs.Tok, \"new allocation not supported in forall statements\");\n          } else {\n            reporter.Error(MessageSource.Resolver, rhs.Tok, \"new allocation not allowed in ghost context\");\n          }\n        }\n      } else if (stmt is CallStmt) {\n        var s = (CallStmt)stmt;\n        foreach (var lhs in s.Lhs) {\n          var idExpr = lhs as IdentifierExpr;\n          if (idExpr != null) {\n            if (scope.ContainsDecl(idExpr.Var)) {\n              reporter.Error(MessageSource.Resolver, stmt, \"body of forall statement is attempting to update a variable declared outside the forall statement\");\n            }\n          } else {\n            reporter.Error(MessageSource.Resolver, stmt, \"the body of the enclosing forall statement is not allowed to update heap locations\");\n          }\n        }\n        if (s.Method.Mod.Expressions.Count != 0) {\n          reporter.Error(MessageSource.Resolver, stmt, \"the body of the enclosing forall statement is not allowed to update heap locations, so any call must be to a method with an empty modifies clause\");\n        }\n        if (!s.Method.IsGhost) {\n          // The reason for this restriction is that the compiler is going to omit the forall statement altogether--it has\n          // no effect.  However, print effects are not documented, so to make sure that the compiler does not omit a call to\n          // a method that prints something, all calls to non-ghost methods are disallowed.  (Note, if this restriction\n          // is somehow lifted in the future, then it is still necessary to enforce s.Method.Mod.Expressions.Count != 0 for\n          // calls to non-ghost methods.)\n          reporter.Error(MessageSource.Resolver, s, \"the body of the enclosing forall statement is not allowed to call non-ghost methods\");\n        }\n\n      } else if (stmt is BlockStmt) {\n        var s = (BlockStmt)stmt;\n        scope.PushMarker();\n        foreach (var ss in s.Body) {\n          CheckForallStatementBodyRestrictions(ss, kind);\n        }\n        scope.PopMarker();\n\n      } else if (stmt is IfStmt) {\n        var s = (IfStmt)stmt;\n        CheckForallStatementBodyRestrictions(s.Thn, kind);\n        if (s.Els != null) {\n          CheckForallStatementBodyRestrictions(s.Els, kind);\n        }\n\n      } else if (stmt is AlternativeStmt) {\n        var s = (AlternativeStmt)stmt;\n        foreach (var alt in s.Alternatives) {\n          foreach (var ss in alt.Body) {\n            CheckForallStatementBodyRestrictions(ss, kind);\n          }\n        }\n\n      } else if (stmt is WhileStmt) {\n        WhileStmt s = (WhileStmt)stmt;\n        if (s.Body != null) {\n          CheckForallStatementBodyRestrictions(s.Body, kind);\n        }\n\n      } else if (stmt is AlternativeLoopStmt) {\n        var s = (AlternativeLoopStmt)stmt;\n        foreach (var alt in s.Alternatives) {\n          foreach (var ss in alt.Body) {\n            CheckForallStatementBodyRestrictions(ss, kind);\n          }\n        }\n\n      } else if (stmt is ForallStmt) {\n        var s = (ForallStmt)stmt;\n        switch (s.Kind) {\n          case ForallStmt.BodyKind.Assign:\n            reporter.Error(MessageSource.Resolver, stmt, \"a forall statement with heap updates is not allowed inside the body of another forall statement\");\n            break;\n          case ForallStmt.BodyKind.Call:\n          case ForallStmt.BodyKind.Proof:\n            // these are fine, since they don't update any non-local state\n            break;\n          default:\n            Contract.Assert(false);  // unexpected kind\n            break;\n        }\n\n      } else if (stmt is CalcStmt) {\n          // cool\n\n      } else if (stmt is MatchStmt) {\n        var s = (MatchStmt)stmt;\n        foreach (var kase in s.Cases) {\n          foreach (var ss in kase.Body) {\n            CheckForallStatementBodyRestrictions(ss, kind);\n          }\n        }\n\n      } else {\n        Contract.Assert(false); throw new cce.UnreachableException();\n      }\n    }\n\n    void CheckForallStatementBodyLhs(IToken tok, Expression lhs, ForallStmt.BodyKind kind) {\n      var idExpr = lhs as IdentifierExpr;\n      if (idExpr != null) {\n        if (scope.ContainsDecl(idExpr.Var)) {\n          reporter.Error(MessageSource.Resolver, tok, \"body of forall statement is attempting to update a variable declared outside the forall statement\");\n        }\n      } else if (kind != ForallStmt.BodyKind.Assign) {\n        reporter.Error(MessageSource.Resolver, tok, \"the body of the enclosing forall statement is not allowed to update heap locations\");\n      }\n    }\n\n    /// <summary>\n    /// Check that a statment is a valid hint for a calculation.\n    /// ToDo: generalize the part for compound statements to take a delegate?\n    /// </summary>\n    public void CheckHintRestrictions(Statement stmt, ISet<LocalVariable> localsAllowedInUpdates) {\n      Contract.Requires(stmt != null);\n      Contract.Requires(localsAllowedInUpdates != null);\n      if (stmt is PredicateStmt) {\n        // cool\n      } else if (stmt is PrintStmt) {\n        // not allowed in ghost context\n      } else if (stmt is RevealStmt) {\n        var s = (RevealStmt)stmt;\n        foreach (var ss in s.ResolvedStatements) {\n          CheckHintRestrictions(ss, localsAllowedInUpdates);\n        }\n      } else if (stmt is SomehowStmt) {\n        reporter.Error(MessageSource.Resolver, stmt, \"somehow statement is not allowed inside a hint\");\n      } else if (stmt is FenceStmt) {\n        reporter.Error(MessageSource.Resolver, stmt, \"fence statement is not allowed inside a hint\");\n      } else if (stmt is GotoStmt) {\n        reporter.Error(MessageSource.Resolver, stmt, \"goto statement is not allowed inside a hint\");\n      } else if (stmt is DeallocStmt) {\n        reporter.Error(MessageSource.Resolver, stmt, \"dealloc statement is not allowed inside a hint\");\n      } else if (stmt is JoinStmt) {\n        reporter.Error(MessageSource.Resolver, stmt, \"join statement is not allowed inside a hint\");\n      } else if (stmt is BreakStmt) {\n        // already checked while resolving hints\n      } else if (stmt is ContinueStmt) {\n        reporter.Error(MessageSource.Resolver, stmt, \"continue statement is not allowed inside a hint\");\n      } else if (stmt is ReturnStmt) {\n        reporter.Error(MessageSource.Resolver, stmt, \"return statement is not allowed inside a hint\");\n      } else if (stmt is YieldStmt) {\n        reporter.Error(MessageSource.Resolver, stmt, \"yield statement is not allowed inside a hint\");\n      } else if (stmt is AssignSuchThatStmt) {\n        var s = (AssignSuchThatStmt)stmt;\n        foreach (var lhs in s.Lhss) {\n          CheckHintLhs(s.Tok, lhs.Resolved, localsAllowedInUpdates);\n        }\n      } else if (stmt is AssignStmt) {\n        var s = (AssignStmt)stmt;\n        CheckHintLhs(s.Tok, s.Lhs.Resolved, localsAllowedInUpdates);\n      } else if (stmt is CallStmt) {\n        var s = (CallStmt)stmt;\n        if (s.Method.Mod.Expressions.Count != 0) {\n          reporter.Error(MessageSource.Resolver, stmt, \"calls to methods with side-effects are not allowed inside a hint\");\n        }\n      } else if (stmt is UpdateStmt) {\n        var s = (UpdateStmt)stmt;\n        foreach (var ss in s.ResolvedStatements) {\n          CheckHintRestrictions(ss, localsAllowedInUpdates);\n        }\n      } else if (stmt is VarDeclStmt) {\n        var s = (VarDeclStmt)stmt;\n        s.Locals.Iter(local => localsAllowedInUpdates.Add(local));\n        if (s.Update != null) {\n          CheckHintRestrictions(s.Update, localsAllowedInUpdates);\n        }\n      } else if (stmt is LetStmt) {\n        // Are we fine?\n      } else if (stmt is BlockStmt) {\n        var s = (BlockStmt)stmt;\n        var newScopeForLocals = new HashSet<LocalVariable>(localsAllowedInUpdates);\n        foreach (var ss in s.Body) {\n          CheckHintRestrictions(ss, newScopeForLocals);\n        }\n\n      } else if (stmt is IfStmt) {\n        var s = (IfStmt)stmt;\n        CheckHintRestrictions(s.Thn, localsAllowedInUpdates);\n        if (s.Els != null) {\n          CheckHintRestrictions(s.Els, localsAllowedInUpdates);\n        }\n\n      } else if (stmt is AlternativeStmt) {\n        var s = (AlternativeStmt)stmt;\n        foreach (var alt in s.Alternatives) {\n          foreach (var ss in alt.Body) {\n            CheckHintRestrictions(ss, localsAllowedInUpdates);\n          }\n        }\n\n      } else if (stmt is WhileStmt) {\n        var s = (WhileStmt)stmt;\n        if (s.Mod.Expressions != null && s.Mod.Expressions.Count != 0) {\n          reporter.Error(MessageSource.Resolver, s.Mod.Expressions[0].tok, \"a while statement used inside a hint is not allowed to have a modifies clause\");\n        }\n        if (s.Body != null) {\n          CheckHintRestrictions(s.Body, localsAllowedInUpdates);\n        }\n\n      } else if (stmt is AlternativeLoopStmt) {\n        var s = (AlternativeLoopStmt)stmt;\n        foreach (var alt in s.Alternatives) {\n          foreach (var ss in alt.Body) {\n            CheckHintRestrictions(ss, localsAllowedInUpdates);\n          }\n        }\n\n      } else if (stmt is ForallStmt) {\n        var s = (ForallStmt)stmt;\n        switch (s.Kind) {\n          case ForallStmt.BodyKind.Assign:\n            reporter.Error(MessageSource.Resolver, stmt, \"a forall statement with heap updates is not allowed inside a hint\");\n            break;\n          case ForallStmt.BodyKind.Call:\n          case ForallStmt.BodyKind.Proof:\n            // these are fine, since they don't update any non-local state\n            break;\n          default:\n            Contract.Assert(false);  // unexpected kind\n            break;\n        }\n\n      } else if (stmt is CalcStmt) {\n        var s = (CalcStmt)stmt;\n        foreach (var h in s.Hints) {\n          CheckHintRestrictions(h, new HashSet<LocalVariable>());\n        }\n\n      } else if (stmt is MatchStmt) {\n        var s = (MatchStmt)stmt;\n        foreach (var kase in s.Cases) {\n          foreach (var ss in kase.Body) {\n            CheckHintRestrictions(ss, localsAllowedInUpdates);\n          }\n        }\n\n      } else {\n        Contract.Assert(false); throw new cce.UnreachableException();\n      }\n    }\n\n    void CheckHintLhs(IToken tok, Expression lhs, ISet<LocalVariable> localsAllowedInUpdates) {\n      Contract.Requires(tok != null);\n      Contract.Requires(lhs != null);\n      Contract.Requires(localsAllowedInUpdates != null);\n      var idExpr = lhs as IdentifierExpr;\n      if (idExpr == null) {\n        reporter.Error(MessageSource.Resolver, tok, \"a hint is not allowed to update heap locations\");\n      } else if (!localsAllowedInUpdates.Contains(idExpr.Var)) {\n        reporter.Error(MessageSource.Resolver, tok, \"a hint is not allowed to update a variable declared outside the hint\");\n      }\n    }\n\n    Type ResolveTypeRhs(TypeRhs rr, Statement stmt, ICodeContext codeContext) {\n      Contract.Requires(rr != null);\n      Contract.Requires(stmt != null);\n      Contract.Requires(codeContext != null);\n      Contract.Ensures(Contract.Result<Type>() != null);\n\n      if (rr.Type == null) {\n        if (rr.ArrayDimensions != null) {\n          // ---------- new T[EE]    OR    new T[EE] (elementInit)\n          Contract.Assert(rr.Arguments == null && rr.Path == null && rr.InitCall == null);\n          ResolveType(stmt.Tok, rr.EType, codeContext, ResolveTypeOptionEnum.InferTypeProxies, null);\n          int i = 0;\n          foreach (Expression dim in rr.ArrayDimensions) {\n            Contract.Assert(dim != null);\n            ResolveExpression(dim, new ResolveOpts(codeContext, false));\n            ConstrainToIntegerType(dim, string.Format(\"new must use an integer-based expression for the array size (got {{0}}{0})\", rr.ArrayDimensions.Count == 1 ? \"\" : \" for index \" + i));\n            i++;\n          }\n          rr.Type = ResolvedArrayType(stmt.Tok, rr.ArrayDimensions.Count, rr.EType, codeContext, false);\n          if (rr.ElementInit != null) {\n            ResolveExpression(rr.ElementInit, new ResolveOpts(codeContext, false));\n            // Check\n            //     int^N -> rr.EType  :>  rr.ElementInit.Type\n            builtIns.CreateArrowTypeDecl(rr.ArrayDimensions.Count);  // TODO: should this be done already in the parser?\n            var args = new List<Type>();\n            for (int ii = 0; ii < rr.ArrayDimensions.Count; ii++) {\n              args.Add(Type.Int);\n            }\n            var arrowType = new ArrowType(rr.ElementInit.tok, builtIns.ArrowTypeDecls[rr.ArrayDimensions.Count], args, rr.EType);\n            string underscores;\n            if (rr.ArrayDimensions.Count == 1) {\n              underscores = \"_\";\n            } else {\n              underscores = \"(\" + Util.Comma(rr.ArrayDimensions.Count, x => \"_\") + \")\";\n            }\n            var hintString = string.Format(\" (perhaps write '{0} =>' in front of the expression you gave in order to make it an arrow type)\", underscores);\n            ConstrainSubtypeRelation(arrowType, rr.ElementInit.Type, rr.ElementInit, \"array-allocation initialization expression expected to have type '{0}' (instead got '{1}'){2}\",\n              arrowType, rr.ElementInit.Type, new LazyString_OnTypeEquals(rr.EType, rr.ElementInit.Type, hintString));\n          } else if (rr.InitDisplay != null) {\n            foreach (var v in rr.InitDisplay) {\n              ResolveExpression(v, new ResolveOpts(codeContext, false));\n              AddAssignableConstraint(v.tok, rr.EType, v.Type, \"initial value must be assignable to array's elements (expected '{0}', got '{1}')\");\n            }\n          }\n        } else {\n          bool callsConstructor = false;\n          if (rr.Arguments == null) {\n            ResolveType_ClassName(stmt.Tok, rr.EType, codeContext, ResolveTypeOptionEnum.InferTypeProxies, null);\n            var udt = rr.EType as UserDefinedType;\n            var cl = udt == null ? null : udt.ResolvedClass as NonNullTypeDecl;\n            if (cl != null && !(rr.EType.IsTraitType && !rr.EType.NormalizeExpand().IsObjectQ)) {\n              // life is good\n            } else {\n              reporter.Error(MessageSource.Resolver, stmt, \"new can be applied only to class types (got {0})\", rr.EType);\n            }\n          } else {\n            string initCallName = null;\n            IToken initCallTok = null;\n            // Resolve rr.Path and do one of three things:\n            // * If rr.Path denotes a type, then set EType,initCallName to rr.Path,\"_ctor\", which sets up a call to the anonymous constructor.\n            // * If the all-but-last components of rr.Path denote a type, then do EType,initCallName := allButLast(EType),last(EType)\n            // * Otherwise, report an error\n            var ret = ResolveTypeLenient(rr.Tok, rr.Path, codeContext, new ResolveTypeOption(ResolveTypeOptionEnum.InferTypeProxies), null, true);\n            if (ret != null) {\n              // The all-but-last components of rr.Path denote a type (namely, ret.ReplacementType).\n              rr.EType = ret.ReplacementType;\n              initCallName = ret.LastComponent.SuffixName;\n              initCallTok = ret.LastComponent.tok;\n            } else {\n              // Either rr.Path resolved correctly as a type or there was no way to drop a last component to make it into something that looked\n              // like a type.  In either case, set EType,initCallName to Path,\"_ctor\" and continue.\n              rr.EType = rr.Path;\n              initCallName = \"_ctor\";\n              initCallTok = rr.Tok;\n            }\n            if (!rr.EType.IsRefType) {\n              reporter.Error(MessageSource.Resolver, stmt, \"new can be applied only to reference types (got {0})\", rr.EType);\n            } else {\n              // ---------- new C.Init(EE)\n              Contract.Assert(initCallName != null);\n              var prevErrorCount = reporter.Count(ErrorLevel.Error);\n\n              // We want to create a MemberSelectExpr for the initializing method.  To do that, we create a throw-away receiver of the appropriate\n              // type, create an dot-suffix expression around this receiver, and then resolve it in the usual way for dot-suffix expressions.\n              var lhs = new ImplicitThisExpr_ConstructorCall(initCallTok) { Type = rr.EType };\n              var callLhs = new ExprDotName(initCallTok, lhs, initCallName, ret == null ? null : ret.LastComponent.OptTypeArguments);\n              ResolveDotSuffix(callLhs, true, rr.Arguments, new ResolveOpts(codeContext, true), true);\n              if (prevErrorCount == reporter.Count(ErrorLevel.Error)) {\n                Contract.Assert(callLhs.ResolvedExpression is MemberSelectExpr);  // since ResolveApplySuffix succeeded and call.Lhs denotes an expression (not a module or a type)\n                var methodSel = (MemberSelectExpr)callLhs.ResolvedExpression;\n                if (methodSel.Member is Method) {\n                  rr.InitCall = new CallStmt(initCallTok, stmt.EndTok, new List<Expression>(), methodSel, rr.Arguments);\n                  ResolveCallStmt(rr.InitCall, codeContext, rr.EType);\n                  if (rr.InitCall.Method is Constructor) {\n                    callsConstructor = true;\n                  }\n                } else {\n                  reporter.Error(MessageSource.Resolver, initCallTok, \"object initialization must denote an initializing method or constructor ({0})\", initCallName);\n                }\n              }\n            }\n          }\n          if (rr.EType.IsRefType) {\n            var udt = rr.EType.NormalizeExpand() as UserDefinedType;\n            if (udt != null) {\n              var cl = (ClassDecl)udt.ResolvedClass;  // cast is guaranteed by the call to rr.EType.IsRefType above, together with the \"rr.EType is UserDefinedType\" test\n              if (!callsConstructor && cl.HasConstructor) {\n                reporter.Error(MessageSource.Resolver, stmt, \"when allocating an object of type '{0}', one of its constructor methods must be called\", cl.Name);\n              }\n            }\n          }\n          rr.Type = rr.EType;\n        }\n      }\n      return rr.Type;\n    }\n\n    class LazyString_OnTypeEquals\n    {\n      Type t0;\n      Type t1;\n      string s;\n      public LazyString_OnTypeEquals(Type t0, Type t1, string s) {\n        Contract.Requires(t0 != null);\n        Contract.Requires(t1 != null);\n        Contract.Requires(s != null);\n        this.t0 = t0;\n        this.t1 = t1;\n        this.s = s;\n      }\n      public override string ToString() {\n        return t0.Equals(t1) ? s : \"\";\n      }\n    }\n\n    MemberDecl ResolveMember(IToken tok, Type receiverType, string memberName, out NonProxyType nptype) {\n      Contract.Requires(tok != null);\n      Contract.Requires(receiverType != null);\n      Contract.Requires(memberName != null);\n      Contract.Ensures(Contract.Result<MemberDecl>() == null || Contract.ValueAtReturn(out nptype) != null);\n\n      receiverType = PartiallyResolveTypeForMemberSelection(tok, receiverType, memberName);\n\n      if (receiverType is TypeProxy) {\n        reporter.Error(MessageSource.Resolver, tok, \"type of the receiver is not fully determined at this program point\", receiverType);\n        nptype = null;\n        return null;\n      }\n      Contract.Assert(receiverType is NonProxyType);  // there are only two kinds of types: proxies and non-proxies\n\n      UserDefinedType ctype = UserDefinedType.DenotesClass(receiverType);\n      if (ctype != null) {\n        var cd = (ClassDecl)ctype.ResolvedClass;  // correctness of cast follows from postcondition of DenotesClass\n        Contract.Assert(ctype.TypeArgs.Count == cd.TypeArgs.Count);  // follows from the fact that ctype was resolved\n        MemberDecl member;\n        if (!classMembers[cd].TryGetValue(memberName, out member)) {\n          if (memberName == \"_ctor\") {\n            reporter.Error(MessageSource.Resolver, tok, \"{0} {1} does not have an anonymous constructor\", cd.WhatKind, cd.Name);\n          } else {\n            reporter.Error(MessageSource.Resolver, tok, \"member {0} does not exist in {2} {1}\", memberName, cd.Name, cd.WhatKind);\n          }\n          nptype = null;\n          return null;\n        } else if (!VisibleInScope(member)) {\n          reporter.Error(MessageSource.Resolver, tok, \"member '{0}' has not been imported in this scope and cannot be accessed here\", memberName);\n        } else {\n          nptype = ctype;\n          return member;\n        }\n      }\n\n      ValuetypeDecl valuet = null;\n      foreach (var vtd in valuetypeDecls) {\n        if (vtd.IsThisType(receiverType)) {\n          valuet = vtd;\n          break;\n        }\n      }\n      if (valuet != null) {\n        MemberDecl member;\n        if (valuet.Members.TryGetValue(memberName, out member)) {\n          nptype = (NonProxyType)receiverType;\n          SelfType resultType = null;\n          if (member is SpecialFunction) {\n            resultType = ((SpecialFunction)member).ResultType as SelfType;\n          } else if (member is SpecialField) {\n            resultType = ((SpecialField)member).Type as SelfType;\n          }\n          if (resultType != null) {\n            SelfTypeSubstitution = new Dictionary<TypeParameter, Type>();\n            SelfTypeSubstitution.Add(resultType.TypeArg, receiverType);\n            resultType.ResolvedType = receiverType;\n          }\n          return member;\n        }\n      }\n\n      TopLevelDeclWithMembers tltwm = receiverType.AsTopLevelTypeWithMembers;\n      if (tltwm != null) {\n        MemberDecl member;\n        if (!classMembers[tltwm].TryGetValue(memberName, out member)) {\n          reporter.Error(MessageSource.Resolver, tok, \"member {0} does not exist in {2} {1}\", memberName, tltwm.Name, tltwm.WhatKind);\n          nptype = null;\n          return null;\n        } else {\n          nptype = (UserDefinedType)receiverType;\n          return member;\n        }\n      }\n\n      reporter.Error(MessageSource.Resolver, tok, \"type {0} does not have a member {1}\", receiverType, memberName);\n      nptype = null;\n      return null;\n    }\n\n    /// <summary>\n    /// Roughly speaking, tries to figure out the head of the type of \"t\", making as few inference decisions as possible.\n    /// More precisely, returns a type that contains all the members of \"t\"; or if \"memberName\" is non-null, a type\n    /// that at least contains the member \"memberName\" of \"t\".  Typically, this type is the head type of \"t\",\n    /// but it may also be a type in a super- or subtype relation to \"t\".\n    /// In some cases, it is necessary to make some inference decisions in order to figure out the type to return.\n    /// </summary>\n    Type PartiallyResolveTypeForMemberSelection(IToken tok, Type t, string memberName = null, int strength = 0) {\n      Contract.Requires(tok != null);\n      Contract.Requires(t != null);\n      Contract.Ensures(Contract.Result<Type>() != null);\n      Contract.Ensures(!(Contract.Result<Type>() is TypeProxy) || ((TypeProxy)Contract.Result<Type>()).T == null);\n      t = t.NormalizeExpand();\n      if (!(t is TypeProxy)) {\n        return t;  // we're good\n      }\n\n      // simplify constraints\n      PrintTypeConstraintState(10);\n      if (strength > 0) {\n        var proxySpecializations = new HashSet<TypeProxy>();\n        GetRelatedTypeProxies(t, proxySpecializations);\n        var anyNewConstraintsAssignable = ConvertAssignableToSubtypeConstraints(proxySpecializations);\n        var anyNewConstraintsEquatable = TightenUpEquatable(proxySpecializations);\n        if ((strength > 1 && !anyNewConstraintsAssignable && !anyNewConstraintsEquatable) || strength == 10) {\n          if (t is TypeProxy) {\n            // One more try\n            var r = GetBaseTypeFromProxy((TypeProxy)t, new Dictionary<TypeProxy, Type>());\n            if (r != null) {\n              if (ArmadaOptions.O.TypeInferenceDebug) {\n                Console.WriteLine(\"  ----> found improvement through GetBaseTypeFromProxy: {0}\", r);\n              }\n              return r;\n            }\n          }\n          if (ArmadaOptions.O.TypeInferenceDebug) {\n            Console.WriteLine(\"  ----> found no improvement, giving up\");\n          }\n          return t;\n        }\n      }\n      PartiallySolveTypeConstraints(false);\n      PrintTypeConstraintState(11);\n      t = t.NormalizeExpandKeepConstraints();\n      var proxy = t as TypeProxy;\n      if (proxy == null) {\n        return t;  // simplification did the trick\n      }\n      if (ArmadaOptions.O.TypeInferenceDebug) {\n        Console.Write(\"DEBUG: Member selection{3}:  {1} :> {0} :> {2}\", t,\n        Util.Comma(proxy.SupertypesKeepConstraints, su => su.ToString()),\n        Util.Comma(proxy.SubtypesKeepConstraints, su => su.ToString()),\n        memberName == null ? \"\" : \" (\" + memberName + \")\");\n      }\n\n      var artificialSuper = proxy.InClusterOfArtificial(AllXConstraints);\n      if (artificialSuper != null) {\n        if (ArmadaOptions.O.TypeInferenceDebug) {\n          Console.WriteLine(\"  ----> use artificial supertype: {0}\", artificialSuper);\n        }\n        return artificialSuper;\n      }\n\n      // Look for a meet of head symbols among the proxy's subtypes\n      Type meet = null;\n      if (MeetOfAllSubtypes(proxy, ref meet, new HashSet<TypeProxy>()) && meet != null) {\n        bool isRoot, isLeaf, headIsRoot, headIsLeaf;\n        CheckEnds(meet, out isRoot, out isLeaf, out headIsRoot, out headIsLeaf);\n        if (meet.IsDatatype) {\n          if (ArmadaOptions.O.TypeInferenceDebug) {\n            Console.WriteLine(\"  ----> meet is a datatype: {0}\", meet);\n          }\n          ConstrainSubtypeRelation(t, meet, tok, \"Member selection requires a supertype of {0} (got something more like {1})\", t, meet);\n          return meet;\n        } else if (headIsRoot) {\n          // we're good to go -- by picking \"meet\" (whose type parameters have been replaced by fresh proxies), we're not losing any generality\n          if (ArmadaOptions.O.TypeInferenceDebug) {\n            Console.WriteLine(\"  ----> improved to {0} through meet\", meet);\n          }\n          AssignProxyAndHandleItsConstraints(proxy, meet, true);\n          return proxy.NormalizeExpand();  // we return proxy.T instead of meet, in case the assignment gets hijacked\n        } else if (memberName == \"_#apply\" || memberName == \"requires\" || memberName == \"reads\") {\n          var generalArrowType = meet.AsArrowType;  // go all the way to the base type, to get to the general arrow type, if any0\n          if (generalArrowType != null) {\n            // pick the supertype \"generalArrowType\" of \"meet\"\n            if (ArmadaOptions.O.TypeInferenceDebug) {\n              Console.WriteLine(\"  ----> improved to {0} through meet and function application\", generalArrowType);\n            }\n            ConstrainSubtypeRelation(generalArrowType, t, tok, \"Function application requires a subtype of {0} (got something more like {1})\", generalArrowType, t);\n            return generalArrowType;\n          }\n        } else if (memberName != null) {\n          // If \"meet\" has a member called \"memberName\" and no supertype of \"meet\" does, then we'll pick this meet\n          if (meet.IsRefType) {\n            var meetExpanded = meet.NormalizeExpand();  // go all the way to the base type, to get to the class\n            if (!meetExpanded.IsObjectQ) {\n              var cl = ((UserDefinedType)meetExpanded).ResolvedClass as ClassDecl;\n              if (cl != null) {\n                // TODO: the following could be improved by also supplying an upper bound of the search (computed as a join of the supertypes)\n                var plausibleMembers = new HashSet<MemberDecl>();\n                FindAllMembers(cl, memberName, plausibleMembers);\n                if (plausibleMembers.Count == 1) {\n                  var mbr = plausibleMembers.First();\n                  if (mbr.EnclosingClass == cl) {\n                    if (ArmadaOptions.O.TypeInferenceDebug) {\n                      Console.WriteLine(\"  ----> improved to {0} through member-selection meet\", meet);\n                    }\n                    var meetRoot = meet.NormalizeExpand();  // blow passed any constraints\n                    ConstrainSubtypeRelation(meetRoot, t, tok, \"Member selection requires a subtype of {0} (got something more like {1})\", meetRoot, t);\n                    return meet;\n                  } else {\n                    // pick the supertype \"mbr.EnclosingClass\" of \"cl\"\n                    Contract.Assert(mbr.EnclosingClass is TraitDecl);  // a proper supertype of a ClassDecl must be a TraitDecl\n                    var pickItFromHere = new UserDefinedType(tok, mbr.EnclosingClass.Name, mbr.EnclosingClass, new List<Type>());\n                    if (ArmadaOptions.O.TypeInferenceDebug) {\n                      Console.WriteLine(\"  ----> improved to {0} through meet and member lookup\", pickItFromHere);\n                    }\n                    ConstrainSubtypeRelation(pickItFromHere, meet, tok, \"Member selection requires a subtype of {0} (got something more like {1})\", pickItFromHere, meet);\n                    return pickItFromHere;\n                  }\n                }\n              }\n            }\n          }\n        }\n        if (ArmadaOptions.O.TypeInferenceDebug) {\n          Console.WriteLine(\"  ----> found no improvement, because meet does not determine type enough\");\n          return t;\n        }\n      }\n\n      // Compute the join of the proxy's supertypes\n      Type join = null;\n      if (JoinOfAllSupertypes(proxy, ref join, new HashSet<TypeProxy>(), false) && join != null) {\n        // If the join does have the member, then this looks promising. It could be that the\n        // type would get further constrained later to pick some subtype (in particular, a\n        // subclass that overrides the member) of this join. But this is the best we can do\n        // now.\n        if (join is TypeProxy) {\n          if (proxy == join.Normalize()) {\n            // can this really ever happen?\n            if (ArmadaOptions.O.TypeInferenceDebug) {\n              Console.WriteLine(\"  ----> found no improvement (other than the proxy itself)\");\n            }\n            return t;\n          } else {\n            if (ArmadaOptions.O.TypeInferenceDebug) {\n              Console.WriteLine(\"  ----> (merging, then trying to improve further) assigning proxy {0}.T := {1}\", proxy, join);\n            }\n            Contract.Assert(proxy != join);\n            proxy.T = join;\n            Contract.Assert(t.NormalizeExpand() == join);\n            return PartiallyResolveTypeForMemberSelection(tok, t, memberName, strength + 1);\n          }\n        }\n        if (ArmadaOptions.O.TypeInferenceDebug) {\n          Console.WriteLine(\"  ----> improved to {0} through join\", join);\n        }\n        if (memberName != null) {\n          AssignProxyAndHandleItsConstraints(proxy, join, true);\n          return proxy.NormalizeExpand();  // we return proxy.T instead of join, in case the assignment gets hijacked\n        } else {\n          return join;\n        }\n      }\n\n      // we weren't able to do it\n      if (ArmadaOptions.O.TypeInferenceDebug) {\n        Console.WriteLine(\"  ----> found no improvement using simple things, trying harder once more\");\n      }\n      return PartiallyResolveTypeForMemberSelection(tok, t, memberName, strength + 1);\n    }\n\n    private Type/*?*/ GetBaseTypeFromProxy(TypeProxy proxy, Dictionary<TypeProxy,Type/*?*/> determinedProxies) {\n      Contract.Requires(proxy != null);\n      Contract.Requires(determinedProxies != null);\n      Type t;\n      if (determinedProxies.TryGetValue(proxy, out t)) {\n        // \"t\" may be null (meaning search for \"proxy\" is underway or was unsuccessful) or non-null (search for\n        // \"proxy\" has completed successfully), but we return it in either case\n        return t;\n      }\n      determinedProxies.Add(proxy, null);  // record that search for \"proxy\" is underway\n      // First, go through subtype constraints, treating each as if it were an equality\n      foreach (var c in AllTypeConstraints) {\n        t = GetBaseTypeFromProxy_Eq(proxy, c.Super, c.Sub, determinedProxies);\n        if (t != null) {\n          determinedProxies[proxy] = t;\n          return t;\n        }\n      }\n      // Next, check XConstraints that can be seen as equality constraints\n      foreach (var xc in AllXConstraints) {\n        switch (xc.ConstraintName) {\n          case \"Assignable\":\n          case \"Equatable\":\n          case \"EquatableArg\":\n            t = GetBaseTypeFromProxy_Eq(proxy, xc.Types[0], xc.Types[1], determinedProxies);\n            if (t != null) {\n              determinedProxies[proxy] = t;\n              return t;\n            }\n            break;\n          case \"InSet\":\n            // etc. TODO\n            break;\n          default:\n            break;\n        }\n      }\n      return null;\n    }\n    /// <summary>\n    /// Tries to find a non-proxy type corresponding to \"proxy\", under the assumption that \"t\" equals \"u\" and\n    /// \"determinedProxies\" assumptions.  In the process, may add to \"determinedProxies\".\n    /// </summary>\n    private Type/*?*/ GetBaseTypeFromProxy_Eq(TypeProxy proxy, Type t, Type u, Dictionary<TypeProxy, Type/*?*/> determinedProxies) {\n      Contract.Requires(proxy != null);\n      Contract.Requires(determinedProxies != null);\n      Contract.Requires(t != null);\n      Contract.Requires(u != null);\n      t = t.NormalizeExpand();\n      u = u.NormalizeExpand();\n      return GetBaseTypeFromProxy_EqAux(proxy, t, u, determinedProxies) ?? GetBaseTypeFromProxy_EqAux(proxy, u, t, determinedProxies);\n    }\n    private Type/*?*/ GetBaseTypeFromProxy_EqAux(TypeProxy proxy, Type t, Type u, Dictionary<TypeProxy, Type/*?*/> determinedProxies) {\n      Contract.Requires(proxy != null);\n      Contract.Requires(determinedProxies != null);\n      Contract.Requires(t != null && (!(t is TypeProxy) || ((TypeProxy)t).T == null));\n      Contract.Requires(u != null && (!(u is TypeProxy) || ((TypeProxy)u).T == null));\n      if (t == proxy) {\n        if (u is TypeProxy) {\n          return GetBaseTypeFromProxy((TypeProxy)u, determinedProxies);\n        } else {\n          return u;\n        }\n      } else if (t.ContainsProxy(proxy)) {\n        if (u is TypeProxy) {\n          u = GetBaseTypeFromProxy((TypeProxy)u, determinedProxies);\n          if (u == null) {\n            return null;\n          }\n        }\n        if (Type.SameHead(t, u)) {\n          Contract.Assert(t.TypeArgs.Count == u.TypeArgs.Count);\n          for (int i = 0; i < t.TypeArgs.Count; i++) {\n            var r = GetBaseTypeFromProxy_Eq(proxy, t.TypeArgs[i], u.TypeArgs[i], determinedProxies);\n            if (r != null) {\n              return r;\n            }\n          }\n        }\n      }\n      return null;\n    }\n\n    private void GetRelatedTypeProxies(Type t, ISet<TypeProxy> proxies) {\n      Contract.Requires(t != null);\n      Contract.Requires(proxies != null);\n      var proxy = t.Normalize() as TypeProxy;\n      if (proxy == null || proxies.Contains(proxy)) {\n        return;\n      }\n      if (ArmadaOptions.O.TypeInferenceDebug) {\n        Console.WriteLine(\"DEBUG: GetRelatedTypeProxies: finding {0} interesting\", proxy);\n      }\n      proxies.Add(proxy);\n      // close over interesting constraints\n      foreach (var c in AllTypeConstraints) {\n        var super = c.Super.Normalize();\n        if (super.TypeArgs.Exists(ta => ta.Normalize() == proxy)) {\n          GetRelatedTypeProxies(c.Sub, proxies);\n        }\n      }\n      foreach (var xc in AllXConstraints) {\n        var xc0 = xc.Types[0].Normalize();\n        if (xc.ConstraintName == \"Assignable\" && (xc0 == proxy || xc0.TypeArgs.Exists(ta => ta.Normalize() == proxy))) {\n          GetRelatedTypeProxies(xc.Types[1], proxies);\n        } else if (xc.ConstraintName == \"Innable\" && xc.Types[1].Normalize() == proxy) {\n          GetRelatedTypeProxies(xc.Types[0], proxies);\n        } else if ((xc.ConstraintName == \"ModifiesFrame\" || xc.ConstraintName == \"ReadsFrame\") && xc.Types[1].Normalize() == proxy) {\n          GetRelatedTypeProxies(xc.Types[0], proxies);\n        }\n      }\n    }\n\n    void FindAllMembers(ClassDecl cl, string memberName, ISet<MemberDecl> foundSoFar) {\n      Contract.Requires(cl != null);\n      Contract.Requires(memberName != null);\n      Contract.Requires(foundSoFar != null);\n      MemberDecl member;\n      if (classMembers[cl].TryGetValue(memberName, out member)) {\n        foundSoFar.Add(member);\n      }\n      cl.TraitsObj.ForEach(trait => FindAllMembers(trait, memberName, foundSoFar));\n    }\n\n    /// <summary>\n    /// Attempts to compute the meet of \"meet\", \"t\", and all of \"t\"'s known subtype( constraint)s.  The meet\n    /// ignores type parameters.  It is assumed that \"meet\" on entry already includes the meet of all proxies\n    /// in \"visited\".  The empty meet is represented by \"null\".\n    /// The return is \"true\" if the meet exists.\n    /// </summary>\n    bool MeetOfAllSubtypes(Type t, ref Type meet, ISet<TypeProxy> visited) {\n      Contract.Requires(t != null);\n      Contract.Requires(visited != null);\n\n      t = t.NormalizeExpandKeepConstraints();\n\n      var proxy = t as TypeProxy;\n      if (proxy != null) {\n        if (visited.Contains(proxy)) {\n          return true;\n        }\n        visited.Add(proxy);\n\n        foreach (var c in proxy.SubtypeConstraints) {\n          var s = c.Sub.NormalizeExpandKeepConstraints();\n          if (!MeetOfAllSubtypes(s, ref meet, visited)) {\n            return false;\n          }\n        }\n        if (meet == null) {\n          // also consider \"Assignable\" constraints\n          foreach (var c in AllXConstraints) {\n            if (c.ConstraintName == \"Assignable\" && c.Types[0].Normalize() == proxy) {\n              var s = c.Types[1].NormalizeExpandKeepConstraints();\n              if (!MeetOfAllSubtypes(s, ref meet, visited)) {\n                return false;\n              }\n            }\n          }\n        }\n        return true;\n      }\n\n      if (meet == null) {\n        meet = Type.HeadWithProxyArgs(t);\n        return true;\n      } else if (Type.IsHeadSupertypeOf(meet, t)) {\n        // stick with what we've got\n        return true;\n      } else if (Type.IsHeadSupertypeOf(t, meet)) {\n        meet = Type.HeadWithProxyArgs(t);\n        return true;\n      } else {\n        meet = Type.Meet(meet, Type.HeadWithProxyArgs(t), builtIns);  // the only way this can succeed is if we obtain a trait\n        Contract.Assert(meet == null || meet.IsObjectQ || (meet is UserDefinedType && ((UserDefinedType)meet).ResolvedClass is TraitDecl));\n        return meet != null;\n      }\n    }\n\n    /// <summary>\n    /// Attempts to compute the join of \"join\", all of \"t\"'s known supertype( constraint)s, and, if \"includeT\"\n    /// and \"t\" has no supertype( constraint)s, \"t\".\n    /// The join ignores type parameters. (Really?? --KRML)\n    /// It is assumed that \"join\" on entry already includes the join of all proxies\n    /// in \"visited\".  The empty join is represented by \"null\".\n    /// The return is \"true\" if the join exists.\n    /// </summary>\n    bool JoinOfAllSupertypes(Type t, ref Type join, ISet<TypeProxy> visited, bool includeT) {\n      Contract.Requires(t != null);\n      Contract.Requires(visited != null);\n\n      t = t.NormalizeExpandKeepConstraints();\n      var proxy = t as TypeProxy;\n      if (proxy != null) {\n        if (visited.Contains(proxy)) {\n          return true;\n        }\n        visited.Add(proxy);\n\n        var delegatedToOthers = false;\n        foreach (var c in proxy.SupertypeConstraints) {\n          var s = c.Super.NormalizeExpandKeepConstraints();\n          delegatedToOthers = true;\n          if (!JoinOfAllSupertypes(s, ref join, visited, true)) {\n            return false;\n          }\n        }\n        if (!delegatedToOthers) {\n          // also consider \"Assignable\" constraints\n          foreach (var c in AllXConstraints) {\n            if (c.ConstraintName == \"Assignable\" && c.Types[1].Normalize() == proxy) {\n              var s = c.Types[0].NormalizeExpandKeepConstraints();\n              delegatedToOthers = true;\n              if (!JoinOfAllSupertypes(s, ref join, visited, true)) {\n                return false;\n              }\n            }\n          }\n        }\n        if (delegatedToOthers) {\n          return true;\n        } else if (!includeT) {\n          return true;\n        } else if (join == null || join.Normalize() == proxy) {\n          join = proxy;\n          return true;\n        } else {\n          return false;\n        }\n      }\n\n      if (join == null) {\n        join = Type.HeadWithProxyArgs(t);\n        return true;\n      } else if (Type.IsHeadSupertypeOf(t, join)) {\n        // stick with what we've got\n        return true;\n      } else if (Type.IsHeadSupertypeOf(join, t)) {\n        join = Type.HeadWithProxyArgs(t);\n        return true;\n      } else {\n        join = Type.Join(join, Type.HeadWithProxyArgs(t), builtIns);\n        return join != null;\n      }\n    }\n\n    public static Dictionary<TypeParameter, Type> TypeSubstitutionMap(List<TypeParameter> formals, List<Type> actuals) {\n      Contract.Requires(formals != null);\n      Contract.Requires(actuals != null);\n      Contract.Requires(formals.Count == actuals.Count);\n      var subst = new Dictionary<TypeParameter, Type>();\n      for (int i = 0; i < formals.Count; i++) {\n        subst.Add(formals[i], actuals[i]);\n      }\n      return subst;\n    }\n\n    /// <summary>\n    /// If the substitution has no effect, the return value is pointer-equal to 'type'\n    /// </summary>\n    public static Type SubstType(Type type, Dictionary<TypeParameter, Type> subst) {\n      Contract.Requires(type != null);\n      Contract.Requires(cce.NonNullDictionaryAndValues(subst));\n      Contract.Ensures(Contract.Result<Type>() != null);\n\n      if (type is BasicType) {\n        return type;\n      } else if (type is SelfType) {\n        Type t;\n        if (subst.TryGetValue(((SelfType)type).TypeArg, out t)) {\n          return cce.NonNull(t);\n        } else {\n          Contract.Assert(false); throw new cce.UnreachableException();  // unresolved SelfType\n        }\n      } else if (type is MapType) {\n        var t = (MapType)type;\n        var dom = SubstType(t.Domain, subst);\n        if (dom is InferredTypeProxy) {\n          ((InferredTypeProxy)dom).KeepConstraints = true;\n        }\n        var ran = SubstType(t.Range, subst);\n        if (ran is InferredTypeProxy) {\n          ((InferredTypeProxy)ran).KeepConstraints = true;\n        }\n        if (dom == t.Domain && ran == t.Range) {\n          return type;\n        } else {\n          return new MapType(t.Finite, dom, ran);\n        }\n      } else if (type is CollectionType) {\n        var t = (CollectionType)type;\n        var arg = SubstType(t.Arg, subst);\n        if (arg is InferredTypeProxy) {\n          ((InferredTypeProxy)arg).KeepConstraints = true;\n        }\n        if (arg == t.Arg) {\n          return type;\n        } else if (type is SetType) {\n          var st = (SetType)type;\n          return new SetType(st.Finite, arg);\n        } else if (type is MultiSetType) {\n          return new MultiSetType(arg);\n        } else if (type is SeqType) {\n          return new SeqType(arg);\n        } else {\n          Contract.Assert(false); throw new cce.UnreachableException();  // unexpected collection type\n        }\n      } else if (type is ArrowType) {\n        var t = (ArrowType)type;\n        var at = new ArrowType(t.tok, t.Args.ConvertAll(u => SubstType(u, subst)), SubstType(t.Result, subst));\n        at.ResolvedClass = t.ResolvedClass;\n        return at;\n      } else if (type is UserDefinedType) {\n        var t = (UserDefinedType)type;\n        if (t.ResolvedParam != null) {\n          Type s;\n          if (subst.TryGetValue(t.ResolvedParam, out s)) {\n            Contract.Assert(t.TypeArgs.Count == 0); // what to do?\n            return cce.NonNull(s);\n          } else {\n            if (t.TypeArgs.Count == 0) {\n              return type;\n            } else {\n              // a type parameter with type arguments--must be an opaque type\n              var otp = (OpaqueType_AsParameter)t.ResolvedParam;\n              var ocl = (OpaqueTypeDecl)t.ResolvedClass;\n              return new UserDefinedType(otp, ocl, t.TypeArgs.ConvertAll(u => SubstType(u, subst)));\n            }\n          }\n        } else if (t.ResolvedClass != null) {\n          List<Type> newArgs = null;  // allocate it lazily\n          var resolvedClass = t.ResolvedClass;\n          var isArrowType = ArrowType.IsPartialArrowTypeName(resolvedClass.Name) || ArrowType.IsTotalArrowTypeName(resolvedClass.Name);\n#if TEST_TYPE_SYNONYM_TRANSPARENCY\n          if (resolvedClass is TypeSynonymDecl && resolvedClass.Name == \"type#synonym#transparency#test\") {\n            // Usually, all type parameters mentioned in the definition of a type synonym are also type parameters\n            // to the type synonym itself, but in this instrumented testing, that is not so, so we also do a substitution\n            // in the .Rhs of the synonym.\n            var syn = (TypeSynonymDecl)resolvedClass;\n            var r = SubstType(syn.Rhs, subst);\n            if (r != syn.Rhs) {\n              resolvedClass = new TypeSynonymDecl(syn.tok, syn.Name, syn.TypeArgs, syn.Module, r, null);\n              newArgs = new List<Type>();\n            }\n          }\n#endif\n          for (int i = 0; i < t.TypeArgs.Count; i++) {\n            Type p = t.TypeArgs[i];\n            Type s = SubstType(p, subst);\n            if (s is InferredTypeProxy && !isArrowType) {\n              ((InferredTypeProxy)s).KeepConstraints = true;\n            }\n            if (s != p && newArgs == null) {\n              // lazily construct newArgs\n              newArgs = new List<Type>();\n              for (int j = 0; j < i; j++) {\n                newArgs.Add(t.TypeArgs[j]);\n              }\n            }\n            if (newArgs != null) {\n              newArgs.Add(s);\n            }\n          }\n          if (newArgs == null) {\n            // there were no substitutions\n            return type;\n          } else {\n            // Note, even if t.NamePath is non-null, we don't care to keep that syntactic part of the expression in what we return here\n            return new UserDefinedType(t.tok, t.Name, resolvedClass, newArgs);\n          }\n        } else {\n          // there's neither a resolved param nor a resolved class, which means the UserDefinedType wasn't\n          // properly resolved; just return it\n          return type;\n        }\n      } else if (type is TypeProxy) {\n        TypeProxy t = (TypeProxy)type;\n        if (t.T == null) {\n          return type;\n        }\n        var s = SubstType(t.T, subst);\n        return s == t.T ? type : s;\n      } else {\n        Contract.Assert(false); throw new cce.UnreachableException();  // unexpected type\n      }\n    }\n\n    /// <summary>\n    /// Check that the type uses formal type parameters in a way that is agreeable with their variance specifications.\n    /// \"context == Co\" says that \"type\" is allowed to vary in the positive direction.\n    /// \"context == Contra\" says that \"type\" is allowed to vary in the negative direction.\n    /// \"context == Inv\" says that \"type\" must not vary at all.\n    /// * \"leftOfArrow\" says that the context is to the left of some arrow\n    /// </summary>\n    public void CheckVariance(Type type, ICallable enclosingTypeDefinition, TypeParameter.TPVariance context, bool leftOfArrow) {\n      Contract.Requires(type != null);\n      Contract.Requires(enclosingTypeDefinition != null);\n\n      type = type.Normalize();  // we keep constraints, since subset types have their own type-parameter variance specifications; we also keep synonys, since that gives rise to better error messages\n      if (type is BasicType) {\n        // fine\n      } else if (type is MapType) {\n        var t = (MapType)type;\n        CheckVariance(t.Domain, enclosingTypeDefinition, context, leftOfArrow);\n        CheckVariance(t.Range, enclosingTypeDefinition, context, leftOfArrow);\n      } else if (type is CollectionType) {\n        var t = (CollectionType)type;\n        CheckVariance(t.Arg, enclosingTypeDefinition, context, leftOfArrow);\n      } else if (type is UserDefinedType) {\n        var t = (UserDefinedType)type;\n        if (t.ResolvedParam != null) {\n          if (t.ResolvedParam.Variance != TypeParameter.TPVariance.Non && t.ResolvedParam.Variance != context) {\n            reporter.Error(MessageSource.Resolver, t.tok, \"formal type parameter '{0}' is not used according to its variance specification\", t.ResolvedParam.Name);\n          } else if (t.ResolvedParam.StrictVariance && leftOfArrow) {\n            string hint;\n            if (t.ResolvedParam.VarianceSyntax == TypeParameter.TPVarianceSyntax.NonVariant_Strict) {\n              hint = string.Format(\" (perhaps try declaring '{0}' as '!{0}')\", t.ResolvedParam.Name);\n            } else {\n              Contract.Assert(t.ResolvedParam.VarianceSyntax == TypeParameter.TPVarianceSyntax.Covariant_Strict);\n              hint = string.Format(\" (perhaps try changing the declaration from '+{0}' to '*{0}')\", t.ResolvedParam.Name);\n            }\n            reporter.Error(MessageSource.Resolver, t.tok, \"formal type parameter '{0}' is not used according to its variance specification (it is used left of an arrow){1}\", t.ResolvedParam.Name, hint);\n          }\n        } else {\n          var resolvedClass = t.ResolvedClass;\n          Contract.Assert(resolvedClass != null);  // follows from that the given type was successfully resolved\n          Contract.Assert(resolvedClass.TypeArgs.Count == t.TypeArgs.Count);\n          if (leftOfArrow) {\n            // we have to be careful about uses of the type being defined\n            var cg = enclosingTypeDefinition.EnclosingModule.CallGraph;\n            var t0 = resolvedClass as ICallable;\n            if (t0 != null && cg.GetSCCRepresentative(t0) == cg.GetSCCRepresentative(enclosingTypeDefinition)) {\n              reporter.Error(MessageSource.Resolver, t.tok, \"using the type being defined ('{0}') here violates strict positivity, that is, it would cause a logical inconsistency by defining a type whose cardinality exceeds itself (like the Continuum Transfunctioner, you might say its power would then be exceeded only by its mystery)\", resolvedClass.Name);\n            }\n          }\n          for (int i = 0; i < t.TypeArgs.Count; i++) {\n            Type p = t.TypeArgs[i];\n            var tpFormal = resolvedClass.TypeArgs[i];\n            CheckVariance(p, enclosingTypeDefinition,\n              context == TypeParameter.TPVariance.Non ? context :\n              context == TypeParameter.TPVariance.Co ? tpFormal.Variance :\n              TypeParameter.Negate(tpFormal.Variance),\n              leftOfArrow || !tpFormal.StrictVariance);\n          }\n        }\n      } else {\n        Contract.Assert(false); throw new cce.UnreachableException();  // unexpected type\n      }\n    }\n\n    public static UserDefinedType GetThisType(IToken tok, TopLevelDeclWithMembers cl) {\n      Contract.Requires(tok != null);\n      Contract.Requires(cl != null);\n      Contract.Ensures(Contract.Result<UserDefinedType>() != null);\n\n      if (cl is ClassDecl cls) {\n        return UserDefinedType.FromTopLevelDecl(tok, cls.NonNullTypeDecl, cls.TypeArgs);\n      } else {\n        return UserDefinedType.FromTopLevelDecl(tok, cl, cl.TypeArgs);\n      }\n    }\n\n    public static UserDefinedType GetReceiverType(IToken tok, MemberDecl member) {\n      Contract.Requires(tok != null);\n      Contract.Requires(member != null);\n      Contract.Ensures(Contract.Result<UserDefinedType>() != null);\n\n      return GetThisType(tok, (TopLevelDeclWithMembers)member.EnclosingClass);\n    }\n\n    public class ResolveOpts\n    {\n      public readonly ICodeContext codeContext;\n      public readonly bool twoState;\n      public readonly bool isReveal;\n      public readonly bool isPostCondition;\n      public readonly bool InsideOld;\n\n      public ResolveOpts(ICodeContext codeContext, bool twoState) {\n        Contract.Requires(codeContext != null);\n        this.codeContext = codeContext;\n        this.twoState = twoState;\n        this.isReveal = false;\n        this.isPostCondition = false;\n      }\n\n      public ResolveOpts(ICodeContext codeContext, bool twoState, bool isReveal, bool isPostCondition, bool insideOld) {\n        Contract.Requires(codeContext != null);\n        this.codeContext = codeContext;\n        this.twoState = twoState;\n        this.isReveal = isReveal;\n        this.isPostCondition = isPostCondition;\n        this.InsideOld = insideOld;\n      }\n    }\n\n    /// <summary>\n    /// \"twoState\" implies that \"old\" and \"fresh\" expressions are allowed.\n    /// </summary>\n    public void ResolveExpression(Expression expr, ResolveOpts opts) {\n#if TEST_TYPE_SYNONYM_TRANSPARENCY\n      ResolveExpressionX(expr, opts);\n      // For testing purposes, change the type of \"expr\" to a type synonym (mwo-ha-ha-ha!)\n      var t = expr.Type;\n      Contract.Assert(t != null);\n      var sd = new TypeSynonymDecl(expr.tok, \"type#synonym#transparency#test\", new List<TypeParameter>(), codeContext.EnclosingModule, t, null);\n      var ts = new UserDefinedType(expr.tok, \"type#synonym#transparency#test\", sd, new List<Type>(), null);\n      expr.DebugTest_ChangeType(ts);\n    }\n    public void ResolveExpressionX(Expression expr, ResolveOpts opts) {\n#endif\n      Contract.Requires(expr != null);\n      Contract.Requires(opts != null);\n      Contract.Ensures(expr.Type != null);\n      if (expr.Type != null) {\n        // expression has already been resovled\n        return;\n      }\n\n      // The following cases will resolve the subexpressions and will attempt to assign a type of expr.  However, if errors occur\n      // and it cannot be determined what the type of expr is, then it is fine to leave expr.Type as null.  In that case, the end\n      // of this method will assign proxy type to the expression, which reduces the number of error messages that are produced\n      // while type checking the rest of the program.\n\n      if (expr is ParensExpression) {\n        var e = (ParensExpression)expr;\n        ResolveExpression(e.E, opts);\n        e.ResolvedExpression = e.E;\n        e.Type = e.E.Type;\n\n      } else if (expr is ChainingExpression) {\n        var e = (ChainingExpression)expr;\n        ResolveExpression(e.E, opts);\n        e.ResolvedExpression = e.E;\n        e.Type = e.E.Type;\n\n      } else if (expr is NegationExpression) {\n        var e = (NegationExpression)expr;\n        var errorCount = reporter.Count(ErrorLevel.Error);\n        ResolveExpression(e.E, opts);\n        e.Type = e.E.Type;\n        AddXConstraint(e.E.tok, \"NumericOrBitvector\", e.E.Type, \"type of unary - must be of a numeric or bitvector type (instead got {0})\");\n        // Note, e.ResolvedExpression will be filled in during CheckTypeInference, at which time e.Type has been determined\n\n      } else if (expr is LiteralExpr) {\n        LiteralExpr e = (LiteralExpr)expr;\n\n        if (e is StaticReceiverExpr) {\n          StaticReceiverExpr eStatic = (StaticReceiverExpr)e;\n          this.ResolveType(eStatic.tok, eStatic.UnresolvedType, opts.codeContext, ResolveTypeOptionEnum.InferTypeProxies, null);\n          eStatic.Type = eStatic.UnresolvedType;\n        } else {\n          if (e.Value == null) {\n            e.Type = new InferredTypeProxy();\n            AddXConstraint(e.tok, \"IsNullableRefType\", e.Type, \"type of 'null' is a reference type, but it is used as {0}\");\n          } else if (e.Value is BigInteger) {\n            var proxy = new InferredTypeProxy();\n            e.Type = proxy;\n            ConstrainSubtypeRelation(new IntVarietiesSupertype(), e.Type, e.tok, \"integer literal used as if it had type {0}\", e.Type);\n          } else if (e.Value is BaseTypes.BigDec) {\n            var proxy = new InferredTypeProxy();\n            e.Type = proxy;\n            ConstrainSubtypeRelation(new RealVarietiesSupertype(), e.Type, e.tok, \"type of real literal is used as {0}\", e.Type);\n          } else if (e.Value is bool) {\n            e.Type = Type.Bool;\n          } else if (e is CharLiteralExpr) {\n            e.Type = Type.Char;\n          } else if (e is StringLiteralExpr) {\n            e.Type = Type.String();\n            ResolveType(e.tok, e.Type, opts.codeContext, ResolveTypeOptionEnum.DontInfer, null);\n          } else {\n            Contract.Assert(false); throw new cce.UnreachableException();  // unexpected literal type\n          }\n        }\n      } else if (expr is ThisExpr) {\n        if (!scope.AllowInstance) {\n          reporter.Error(MessageSource.Resolver, expr, \"'this' is not allowed in a 'static' context\");\n        }\n        if (currentClass is ClassDecl cd && cd.IsDefaultClass) {\n          // there's no type\n        } else {\n          expr.Type = GetThisType(expr.tok, currentClass);  // do this regardless of scope.AllowInstance, for better error reporting\n        }\n      } else if (expr is MeExpr) {\n        var e = (MeExpr)expr;\n        e.Type = new UserDefinedType(Token.NoToken, \"uint64\", new List<Type>());\n        this.ResolveType(e.tok, e.Type, opts.codeContext, ResolveTypeOptionEnum.InferTypeProxies, null);\n\n      } else if (expr is StoreBufferEmptyExpr) {\n        var e = (StoreBufferEmptyExpr)expr;\n        e.Type = new BoolType();\n        this.ResolveType(e.tok, e.Type, opts.codeContext, ResolveTypeOptionEnum.InferTypeProxies, null);\n\n      } else if (expr is TotalStateExpr) {\n        var e = (TotalStateExpr)expr;\n        e.Type = AH.ReferToType(\"ArmadaPlaceholder_TotalState\");\n        this.ResolveType(e.tok, e.Type, opts.codeContext, ResolveTypeOptionEnum.InferTypeProxies, null);\n\n      } else if (expr is IfUndefinedExpr) {\n        var e = (IfUndefinedExpr)expr;\n        Type safeType = new InferredTypeProxy();\n        expr.Type = safeType;\n        ResolveExpression(e.PotentiallyUnsafe, opts);\n        ConstrainSubtypeRelation(safeType, e.PotentiallyUnsafe.Type, e.PotentiallyUnsafe.tok,\n                                 \"The potentially-unsafe expression in this if_undefined expression has type {0}, but must have a common supertype with the safe-substitution expression which has type {1}\",\n                                 e.PotentiallyUnsafe.Type, e.SafeSubstitution.Type);\n        ResolveExpression(e.SafeSubstitution, opts);\n        ConstrainSubtypeRelation(safeType, e.SafeSubstitution.Type, e.SafeSubstitution.tok,\n                                 \"The safe-substitution expression in this if_undefined expression has type {0}, but must have a common supertype with the potentially-unsafe expression which has type {1}\",\n                                 e.SafeSubstitution.Type, e.PotentiallyUnsafe.Type);\n\n      } else if (expr is IdentifierExpr) {\n        var e = (IdentifierExpr)expr;\n        e.Var = scope.Find(e.Name);\n        if (e.Var != null) {\n          expr.Type = e.Var.Type;\n        } else {\n          reporter.Error(MessageSource.Resolver, expr, \"Identifier does not denote a local variable, parameter, or bound variable: {0}\", e.Name);\n        }\n\n      } else if (expr is DatatypeValue) {\n        DatatypeValue dtv = (DatatypeValue)expr;\n        TopLevelDecl d;\n        if (!moduleInfo.TopLevels.TryGetValue(dtv.DatatypeName, out d)) {\n          reporter.Error(MessageSource.Resolver, expr.tok, \"Undeclared datatype: {0}\", dtv.DatatypeName);\n        } else if (d is AmbiguousTopLevelDecl) {\n          var ad = (AmbiguousTopLevelDecl)d;\n          reporter.Error(MessageSource.Resolver, expr.tok, \"The name {0} ambiguously refers to a type in one of the modules {1} (try qualifying the type name with the module name)\", dtv.DatatypeName, ad.ModuleNames());\n        } else if (!(d is DatatypeDecl)) {\n          reporter.Error(MessageSource.Resolver, expr.tok, \"Expected datatype: {0}\", dtv.DatatypeName);\n        } else {\n          ResolveDatatypeValue(opts, dtv, (DatatypeDecl)d, null);\n        }\n\n      } else if (expr is DisplayExpression) {\n        DisplayExpression e = (DisplayExpression)expr;\n        Type elementType = new InferredTypeProxy() { KeepConstraints = true };\n        foreach (Expression ee in e.Elements) {\n          ResolveExpression(ee, opts);\n          Contract.Assert(ee.Type != null);  // follows from postcondition of ResolveExpression\n          ConstrainSubtypeRelation(elementType, ee.Type, ee.tok, \"All elements of display must have some common supertype (got {0}, but needed type or type of previous elements is {1})\", ee.Type, elementType);\n        }\n        if (expr is SetDisplayExpr) {\n          var se = (SetDisplayExpr)expr;\n          expr.Type = new SetType(se.Finite, elementType);\n        } else if (expr is MultiSetDisplayExpr) {\n          expr.Type = new MultiSetType(elementType);\n        } else {\n          expr.Type = new SeqType(elementType);\n        }\n      } else if (expr is MapDisplayExpr) {\n        MapDisplayExpr e = (MapDisplayExpr)expr;\n        Type domainType = new InferredTypeProxy();\n        Type rangeType = new InferredTypeProxy();\n        foreach (ExpressionPair p in e.Elements) {\n          ResolveExpression(p.A, opts);\n          Contract.Assert(p.A.Type != null);  // follows from postcondition of ResolveExpression\n          ConstrainSubtypeRelation(domainType, p.A.Type, p.A.tok, \"All elements of display must have some common supertype (got {0}, but needed type or type of previous elements is {1})\", p.A.Type, domainType);\n          ResolveExpression(p.B, opts);\n          Contract.Assert(p.B.Type != null);  // follows from postcondition of ResolveExpression\n          ConstrainSubtypeRelation(rangeType, p.B.Type, p.B.tok, \"All elements of display must have some common supertype (got {0}, but needed type or type of previous elements is {1})\", p.B.Type, rangeType);\n        }\n        expr.Type = new MapType(e.Finite, domainType, rangeType);\n      } else if (expr is NameSegment) {\n        var e = (NameSegment)expr;\n        ResolveNameSegment(e, true, null, opts, false);\n        if (e.Type is Resolver_IdentifierExpr.ResolverType_Module) {\n          reporter.Error(MessageSource.Resolver, e.tok, \"name of module ({0}) is used as a variable\", e.Name);\n          e.ResetTypeAssignment();  // the rest of type checking assumes actual types\n        } else if (e.Type is Resolver_IdentifierExpr.ResolverType_Type) {\n          reporter.Error(MessageSource.Resolver, e.tok, \"name of type ({0}) is used as a variable\", e.Name);\n          e.ResetTypeAssignment();  // the rest of type checking assumes actual types\n        }\n\n      } else if (expr is ExprDotName) {\n        var e = (ExprDotName)expr;\n        ResolveDotSuffix(e, true, null, opts, false);\n        if (e.Type is Resolver_IdentifierExpr.ResolverType_Module) {\n          reporter.Error(MessageSource.Resolver, e.tok, \"name of module ({0}) is used as a variable\", e.SuffixName);\n          e.ResetTypeAssignment();  // the rest of type checking assumes actual types\n        } else if (e.Type is Resolver_IdentifierExpr.ResolverType_Type) {\n          reporter.Error(MessageSource.Resolver, e.tok, \"name of type ({0}) is used as a variable\", e.SuffixName);\n          e.ResetTypeAssignment();  // the rest of type checking assumes actual types\n        }\n\n      } else if (expr is ApplySuffix) {\n        var e = (ApplySuffix)expr;\n        ResolveApplySuffix(e, opts, false);\n\n      } else if (expr is RevealExpr) {\n        var e = (RevealExpr)expr;\n        ResolveRevealExpr(e, opts, true);\n        e.ResolvedExpression = e.Expr;\n\n      } else if (expr is MemberSelectExpr) {\n        var e = (MemberSelectExpr)expr;\n        ResolveExpression(e.Obj, opts);\n        Contract.Assert(e.Obj.Type != null);  // follows from postcondition of ResolveExpression\n        NonProxyType nptype;\n        MemberDecl member = ResolveMember(expr.tok, e.Obj.Type, e.MemberName, out nptype);\n        if (member == null) {\n          // error has already been reported by ResolveMember\n        } else if (member is Function) {\n          var fn = member as Function;\n          e.Member = fn;\n          if (fn is TwoStateFunction && !opts.twoState) {\n            reporter.Error(MessageSource.Resolver, e.tok, \"a two-state function can be used only in a two-state context\");\n          }\n          // build the type substitution map\n          e.TypeApplication = new List<Type>();\n          Dictionary<TypeParameter, Type> subst;\n          var ctype = nptype as UserDefinedType;\n          if (ctype == null) {\n            subst = new Dictionary<TypeParameter, Type>();\n          } else {\n            subst = TypeSubstitutionMap(ctype.ResolvedClass.TypeArgs, ctype.TypeArgs);\n            // instantiate all type arguments from the functions. no polymorphic application\n            e.TypeApplication.AddRange(ctype.TypeArgs);\n          }\n          foreach (var tp in fn.TypeArgs) {\n            Type prox = new InferredTypeProxy();\n            subst[tp] = prox;\n            e.TypeApplication.Add(prox);\n          }\n          subst = BuildTypeArgumentSubstitute(subst);\n          e.Type = SelectAppropriateArrowType(fn.tok, fn.Formals.ConvertAll(f => SubstType(f.Type, subst)), SubstType(fn.ResultType, subst),\n            fn.Reads.Count != 0, fn.Req.Count != 0);\n          AddCallGraphEdge(opts.codeContext, fn, e, false);\n        } else if (member is Field) {\n          var field = (Field)member;\n          e.Member = field;\n          if (field.EnclosingClass == null) {\n            // \"field\" is some built-in field\n            e.TypeApplication = new List<Type>();\n          } else {\n            e.TypeApplication = field.EnclosingClass.TypeArgs.ConvertAll(tp => (Type)new UserDefinedType(tp));\n          }\n          if (e.Obj is StaticReceiverExpr && !field.IsStatic) {\n            reporter.Error(MessageSource.Resolver, expr, \"a field must be selected via an object, not just a class name\");\n          }\n          var ctype = nptype as UserDefinedType;\n          if (ctype == null) {\n            e.Type = field.Type;\n          } else {\n            Contract.Assert(ctype.ResolvedClass != null); // follows from postcondition of ResolveMember\n            // build the type substitution map\n            var subst = TypeSubstitutionMap(ctype.ResolvedClass.TypeArgs, ctype.TypeArgs);\n            e.Type = SubstType(field.Type, subst);\n          }\n          AddCallGraphEdgeForField(opts.codeContext, field, e);\n        } else {\n          reporter.Error(MessageSource.Resolver, expr, \"member {0} in type {1} does not refer to a field or a function\", e.MemberName, nptype);\n        }\n\n      } else if (expr is SeqSelectExpr) {\n        SeqSelectExpr e = (SeqSelectExpr)expr;\n        ResolveSeqSelectExpr(e, opts);\n\n      } else if (expr is MultiSelectExpr) {\n        MultiSelectExpr e = (MultiSelectExpr)expr;\n\n        ResolveExpression(e.Array, opts);\n        Contract.Assert(e.Array.Type != null);  // follows from postcondition of ResolveExpression\n        Type elementType = new InferredTypeProxy();\n        ConstrainSubtypeRelation(ResolvedArrayType(e.Array.tok, e.Indices.Count, elementType, opts.codeContext, true), e.Array.Type, e.Array,\n          \"array selection requires an array{0} (got {1})\", e.Indices.Count, e.Array.Type);\n        int i = 0;\n        foreach (Expression idx in e.Indices) {\n          Contract.Assert(idx != null);\n          ResolveExpression(idx, opts);\n          Contract.Assert(idx.Type != null);  // follows from postcondition of ResolveExpression\n          ConstrainToIntegerType(idx, \"array selection requires integer-based numeric indices (got {0} for index \" + i + \")\");\n          i++;\n        }\n        e.Type = elementType;\n\n      } else if (expr is SeqUpdateExpr) {\n        SeqUpdateExpr e = (SeqUpdateExpr)expr;\n        ResolveExpression(e.Seq, opts);\n        Contract.Assert(e.Seq.Type != null);  // follows from postcondition of ResolveExpression\n        ResolveExpression(e.Index, opts);\n        ResolveExpression(e.Value, opts);\n        AddXConstraint(expr.tok, \"SeqUpdatable\", e.Seq.Type, e.Index, e.Value, \"update requires a sequence, map, multiset, or datatype (got {0})\");\n        expr.Type = e.Seq.Type;\n\n      } else if (expr is DatatypeUpdateExpr) {\n        var e = (DatatypeUpdateExpr)expr;\n        ResolveExpression(e.Root, opts);\n        var ty = PartiallyResolveTypeForMemberSelection(expr.tok, e.Root.Type);\n        if (!ty.IsDatatype) {\n          reporter.Error(MessageSource.Resolver, expr, \"datatype update expression requires a root expression of a datatype (got {0})\", ty);\n        } else {\n          List<DatatypeCtor> legalSourceConstructors;\n          var let = ResolveDatatypeUpdate(expr.tok, e.Root, ty.AsDatatype, e.Updates, opts, out legalSourceConstructors);\n          if (let != null) {\n            e.ResolvedExpression = let;\n            e.LegalSourceConstructors = legalSourceConstructors;\n            expr.Type = ty;\n          }\n        }\n\n      } else if (expr is FunctionCallExpr) {\n        var e = (FunctionCallExpr)expr;\n        ResolveFunctionCallExpr(e, opts);\n\n      } else if (expr is ApplyExpr) {\n        var e = (ApplyExpr)expr;\n        ResolveExpression(e.Function, opts);\n        foreach (var arg in e.Args) {\n          ResolveExpression(arg, opts);\n        }\n\n        // TODO: the following should be replaced by a type-class constraint that constrains the types of e.Function, e.Args[*], and e.Type\n        var fnType = e.Function.Type.AsArrowType;\n        if (fnType == null) {\n          reporter.Error(MessageSource.Resolver, e.tok,\n            \"non-function expression (of type {0}) is called with parameters\", e.Function.Type);\n        } else if (fnType.Arity != e.Args.Count) {\n          reporter.Error(MessageSource.Resolver, e.tok,\n            \"wrong number of arguments to function application (function type '{0}' expects {1}, got {2})\", fnType,\n            fnType.Arity, e.Args.Count);\n        } else {\n          for (var i = 0; i < fnType.Arity; i++) {\n            AddAssignableConstraint(e.Args[i].tok, fnType.Args[i], e.Args[i].Type,\n              \"type mismatch for argument\" + (fnType.Arity == 1 ? \"\" : \" \" + i) + \" (function expects {0}, got {1})\");\n          }\n        }\n\n        expr.Type = fnType == null ? new InferredTypeProxy() : fnType.Result;\n\n      } else if (expr is SeqConstructionExpr) {\n        var e = (SeqConstructionExpr)expr;\n        var elementType = new InferredTypeProxy();\n        ResolveExpression(e.N, opts);\n        ConstrainToIntegerType(e.N, \"sequence construction must use an integer-based expression for the sequence size (got {0})\");\n        ResolveExpression(e.Initializer, opts);\n        var arrowType = new ArrowType(e.tok, builtIns.ArrowTypeDecls[1], new List<Type>() { Type.Int }, elementType);\n        var hintString = \" (perhaps write '_ =>' in front of the expression you gave in order to make it an arrow type)\";\n        ConstrainSubtypeRelation(arrowType, e.Initializer.Type, e.Initializer, \"sequence-construction initializer expression expected to have type '{0}' (instead got '{1}'){2}\",\n          arrowType, e.Initializer.Type, new LazyString_OnTypeEquals(elementType, e.Initializer.Type, hintString));\n        expr.Type = new SeqType(elementType);\n\n      } else if (expr is MultiSetFormingExpr) {\n        MultiSetFormingExpr e = (MultiSetFormingExpr)expr;\n        ResolveExpression(e.E, opts);\n        var elementType = new InferredTypeProxy();\n        AddXConstraint(e.E.tok, \"MultiSetConvertible\", e.E.Type, elementType, \"can only form a multiset from a seq or set (got {0})\");\n        expr.Type = new MultiSetType(elementType);\n\n      } else if (expr is OldExpr) {\n        OldExpr e = (OldExpr)expr;\n        if (!opts.twoState) {\n          reporter.Error(MessageSource.Resolver, expr, \"old expressions are not allowed in this context\");\n        } else if (e.At != null) {\n          e.AtLabel = dominatingStatementLabels.Find(e.At);\n          if (e.AtLabel == null) {\n            reporter.Error(MessageSource.Resolver, expr, \"no label '{0}' in scope at this time\", e.At);\n          }\n        }\n        ResolveExpression(e.E, new ResolveOpts(opts.codeContext, false, opts.isReveal, opts.isPostCondition, true));\n        expr.Type = e.E.Type;\n\n      } else if (expr is UnchangedExpr) {\n        var e = (UnchangedExpr)expr;\n        if (!opts.twoState) {\n          reporter.Error(MessageSource.Resolver, expr, \"unchanged expressions are not allowed in this context\");\n        } else if (e.At != null) {\n          e.AtLabel = dominatingStatementLabels.Find(e.At);\n          if (e.AtLabel == null) {\n            reporter.Error(MessageSource.Resolver, expr, \"no label '{0}' in scope at this time\", e.At);\n          }\n        }\n        foreach (var fe in e.Frame) {\n          ResolveFrameExpression(fe, FrameExpressionUse.Unchanged, opts.codeContext);\n        }\n        expr.Type = Type.Bool;\n\n      } else if (expr is UnaryOpExpr) {\n        var e = (UnaryOpExpr)expr;\n        ResolveExpression(e.E, opts);\n        Contract.Assert(e.E.Type != null);  // follows from postcondition of ResolveExpression\n        switch (e.Op) {\n          case UnaryOpExpr.Opcode.Not:\n            AddXConstraint(e.E.tok, \"BooleanBits\", e.E.Type, \"logical/bitwise negation expects a boolean or bitvector argument (instead got {0})\");\n            expr.Type = e.E.Type;\n            break;\n          case UnaryOpExpr.Opcode.Cardinality:\n            AddXConstraint(expr.tok, \"Sizeable\", e.E.Type, \"size operator expects a collection argument (instead got {0})\");\n            expr.Type = Type.Int;\n            break;\n          case UnaryOpExpr.Opcode.Fresh:\n            if (!opts.twoState) {\n              reporter.Error(MessageSource.Resolver, expr, \"fresh expressions are not allowed in this context\");\n            }\n            // the type of e.E must be either an object or a collection of objects\n            AddXConstraint(expr.tok, \"Freshable\", e.E.Type, \"the argument of a fresh expression must denote an object or a collection of objects (instead got {0})\");\n            expr.Type = Type.Bool;\n            break;\n          case UnaryOpExpr.Opcode.Allocated:\n          case UnaryOpExpr.Opcode.AllocatedArray:\n            expr.Type = Type.Bool;\n            if (2 <= ArmadaOptions.O.Allocated &&\n              ((opts.codeContext is Function && !opts.InsideOld) || opts.codeContext is ConstantField || opts.codeContext is RedirectingTypeDecl)) {\n              var declKind = opts.codeContext is RedirectingTypeDecl ? ((RedirectingTypeDecl)opts.codeContext).WhatKind : ((MemberDecl)opts.codeContext).WhatKind;\n              reporter.Error(MessageSource.Resolver, expr, \"a {0} definition is not allowed to depend on the set of allocated references\", declKind);\n            }\n            AddXConstraint(e.E.tok, \"Dereferenceable\", e.E.Type, \"allocated operator expects a pointer type (instead got {0})\");\n            break;\n          case UnaryOpExpr.Opcode.GlobalView:\n            expr.Type = e.E.Type;\n            break;\n          case UnaryOpExpr.Opcode.Dereference:\n            AddXConstraint(e.E.tok, \"Dereferenceable\", e.E.Type, \"dereference operator expects a pointer type (instead got {0})\");\n            e.Type = new InferredTypeProxy();\n            AddXConstraint(e.E.tok, \"DereferenceResult\", e.E.Type, e.Type, \"dereference operator expects a pointer type (instead got {0})\");\n            break;\n          case UnaryOpExpr.Opcode.AddressOf:\n            e.Type = new PointerType(e.E.Type);\n            break;\n          default:\n            Contract.Assert(false); throw new cce.UnreachableException();  // unexpected unary operator\n        }\n\n      } else if (expr is ConversionExpr) {\n        var e = (ConversionExpr)expr;\n        ResolveExpression(e.E, opts);\n        var prevErrorCount = reporter.Count(ErrorLevel.Error);\n        ResolveType(e.tok, e.ToType, opts.codeContext, new ResolveTypeOption(ResolveTypeOptionEnum.DontInfer), null);\n        if (reporter.Count(ErrorLevel.Error) == prevErrorCount) {\n          if (e.ToType.IsNumericBased(Type.NumericPersuation.Int)) {\n            AddXConstraint(expr.tok, \"NumericOrBitvectorOrCharOrORDINAL\", e.E.Type, \"type conversion to an int-based type is allowed only from numeric and bitvector types, char, and ORDINAL (got {0})\");\n          } else if (e.ToType.IsNumericBased(Type.NumericPersuation.Real)) {\n            AddXConstraint(expr.tok, \"NumericOrBitvector\", e.E.Type, \"type conversion to a real-based type is allowed only from numeric and bitvector types (got {0})\");\n          } else if (e.ToType.IsBitVectorType) {\n            AddXConstraint(expr.tok, \"NumericOrBitvector\", e.E.Type, \"type conversion to a bitvector-based type is allowed only from numeric and bitvector types (got {0})\");\n          } else if (e.ToType.IsCharType) {\n            AddXConstraint(expr.tok, \"NumericOrBitvector\", e.E.Type, \"type conversion to a char type is allowed only from numeric and bitvector types (got {0})\");\n          } else if (e.ToType.IsBigOrdinalType) {\n            AddXConstraint(expr.tok, \"NumericOrBitvector\", e.E.Type, \"type conversion to an ORDINAL type is allowed only from numeric and bitvector types (got {0})\");\n          } else {\n            reporter.Error(MessageSource.Resolver, expr, \"type conversions are not supported to this type (got {0})\", e.ToType);\n          }\n          e.Type = e.ToType;\n        } else {\n          e.Type = new InferredTypeProxy();\n        }\n\n      } else if (expr is BinaryExpr) {\n        BinaryExpr e = (BinaryExpr)expr;\n        ResolveExpression(e.E0, opts);\n        Contract.Assert(e.E0.Type != null);  // follows from postcondition of ResolveExpression\n        ResolveExpression(e.E1, opts);\n        Contract.Assert(e.E1.Type != null);  // follows from postcondition of ResolveExpression\n        switch (e.Op) {\n          case BinaryExpr.Opcode.Iff:\n          case BinaryExpr.Opcode.Imp:\n          case BinaryExpr.Opcode.Exp:\n          case BinaryExpr.Opcode.And:\n          case BinaryExpr.Opcode.Or: {\n              ConstrainSubtypeRelation(Type.Bool, e.E0.Type, expr, \"first argument to {0} must be of type bool (instead got {1})\", BinaryExpr.OpcodeString(e.Op), e.E0.Type);\n              ConstrainSubtypeRelation(Type.Bool, e.E1.Type, expr, \"second argument to {0} must be of type bool (instead got {1})\", BinaryExpr.OpcodeString(e.Op), e.E1.Type);\n              expr.Type = Type.Bool;\n              break;\n            }\n\n          case BinaryExpr.Opcode.Eq:\n          case BinaryExpr.Opcode.Neq:\n            AddXConstraint(expr.tok, \"Equatable\", e.E0.Type, e.E1.Type, \"arguments must have comparable types (got {0} and {1})\");\n            expr.Type = Type.Bool;\n            break;\n\n          case BinaryExpr.Opcode.Disjoint:\n            Type disjointArgumentsType = new InferredTypeProxy();\n            ConstrainSubtypeRelation(disjointArgumentsType, e.E0.Type, expr, \"arguments to {2} must have a common supertype (got {0} and {1})\", e.E0.Type, e.E1.Type, BinaryExpr.OpcodeString(e.Op));\n            ConstrainSubtypeRelation(disjointArgumentsType, e.E1.Type, expr, \"arguments to {2} must have a common supertype (got {0} and {1})\", e.E0.Type, e.E1.Type, BinaryExpr.OpcodeString(e.Op));\n            AddXConstraint(expr.tok, \"Disjointable\", disjointArgumentsType, \"arguments must be of a [multi]set or map type (got {0})\");\n            expr.Type = Type.Bool;\n            break;\n\n          case BinaryExpr.Opcode.Lt:\n          case BinaryExpr.Opcode.Le: {\n              if (e.Op == BinaryExpr.Opcode.Lt && (e.E0.Type.IsIndDatatype || e.E0.Type.IsTypeParameter || e.E1.Type.IsIndDatatype)) {\n                AddXConstraint(expr.tok, \"RankOrderable\", e.E0.Type, e.E1.Type, \"arguments to rank comparison must be datatypes (got {0} and {1})\");\n                e.ResolvedOp = BinaryExpr.ResolvedOpcode.RankLt;\n              } else if (e.E0.Type is PointerType && e.E1.Type is PointerType) {\n                e.ResolvedOp = ResolveOp(e.Op, e.E0.Type);\n              } else {\n                var cmpType = new InferredTypeProxy();\n                var err = new TypeConstraint.ErrorMsgWithToken(expr.tok, \"arguments to {2} must have a common supertype (got {0} and {1})\", e.E0.Type, e.E1.Type, BinaryExpr.OpcodeString(e.Op));\n                ConstrainSubtypeRelation(cmpType, e.E0.Type, err);\n                ConstrainSubtypeRelation(cmpType, e.E1.Type, err);\n                AddXConstraint(expr.tok, \"Orderable_Lt\", e.E0.Type, e.E1.Type,\n                  \"arguments to \" + BinaryExpr.OpcodeString(e.Op) + \" must be of a numeric type, bitvector type, ORDINAL, char, a sequence type, or a set-like type (instead got {0} and {1})\");\n              }\n              expr.Type = Type.Bool;\n            }\n            break;\n\n          case BinaryExpr.Opcode.Gt:\n          case BinaryExpr.Opcode.Ge: {\n              if (e.Op == BinaryExpr.Opcode.Gt && (e.E0.Type.IsIndDatatype || e.E1.Type.IsIndDatatype || e.E1.Type.IsTypeParameter)) {\n                AddXConstraint(expr.tok, \"RankOrderable\", e.E1.Type, e.E0.Type, \"arguments to rank comparison must be datatypes (got {1} and {0})\");\n                e.ResolvedOp = BinaryExpr.ResolvedOpcode.RankGt;\n              } else if (e.E0.Type is PointerType && e.E1.Type is PointerType) {\n                e.ResolvedOp = ResolveOp(e.Op, e.E0.Type);\n              } else {\n                var cmpType = new InferredTypeProxy();\n                var err = new TypeConstraint.ErrorMsgWithToken(expr.tok, \"arguments to {2} must have a common supertype (got {0} and {1})\", e.E0.Type, e.E1.Type, BinaryExpr.OpcodeString(e.Op));\n                ConstrainSubtypeRelation(cmpType, e.E0.Type, err);\n                ConstrainSubtypeRelation(cmpType, e.E1.Type, err);\n                AddXConstraint(expr.tok, \"Orderable_Gt\", e.E0.Type, e.E1.Type,\n                  \"arguments to \" + BinaryExpr.OpcodeString(e.Op) + \" must be of a numeric type, bitvector type, ORDINAL, char, or a set-like type (instead got {0} and {1})\");\n              }\n              expr.Type = Type.Bool;\n            }\n            break;\n\n          case BinaryExpr.Opcode.LeftShift:\n          case BinaryExpr.Opcode.RightShift: {\n              expr.Type = new InferredTypeProxy();\n              AddXConstraint(e.tok, \"NumericOrBitvector\", expr.Type, \"type of \" + BinaryExpr.OpcodeString(e.Op) + \" must be a numeric or bitvector type (instead got {0})\");\n              ConstrainSubtypeRelation(expr.Type, e.E0.Type, expr.tok, \"type of left argument to \" + BinaryExpr.OpcodeString(e.Op) + \" ({0}) must agree with the result type ({1})\", e.E0.Type, expr.Type);\n              AddXConstraint(expr.tok, \"IntLikeOrBitvector\", e.E1.Type, \"type of right argument to \" + BinaryExpr.OpcodeString(e.Op) + \" ({0}) must be an integer-numeric or bitvector type\");\n            }\n            break;\n\n          case BinaryExpr.Opcode.Add: {\n              expr.Type = new InferredTypeProxy();\n              AddXConstraint(e.tok, \"Plussable\", expr.Type, \"type of + must be of a numeric type, a bitvector type, ORDINAL, char, a sequence type, or a set-like type (instead got {0})\");\n              ConstrainSubtypeRelation(expr.Type, e.E0.Type, expr.tok, \"type of left argument to + ({0}) must agree with the result type ({1})\", e.E0.Type, expr.Type);\n              AddXConstraint(e.tok, \"PlusRight\", expr.Type, e.E1, \"type of right argument to + ({0}) must agree with the result type, or, if result is pointer, must be integral\");\n            }\n            break;\n\n          case BinaryExpr.Opcode.Sub: {\n              expr.Type = new InferredTypeProxy();\n              AddXConstraint(e.tok, \"Minusable\", expr.Type, \"type of - must be of a numeric type, bitvector type, ORDINAL, char, or a set-like type (instead got {0})\");\n              ConstrainSubtypeRelation(expr.Type, e.E0.Type, expr.tok, \"type of left argument to - ({0}) must agree with the result type ({1})\", e.E0.Type, expr.Type);\n              AddXConstraint(e.tok, \"MinusRight\", expr.Type, e.E1, \"type of right argument to - ({0}) must agree with the result type, or, if result is pointer, must be integral\");\n            }\n            break;\n\n            // FIXME: duplicated?\n          // case BinaryExpr.Opcode.Sub: {\n          //     expr.Type = new InferredTypeProxy();\n          //     AddXConstraint(e.tok, \"Minusable\", expr.Type, \"type of - must be of a numeric type, bitvector type, ORDINAL, char, or a set-like type (instead got {0})\");\n          //     ConstrainSubtypeRelation(expr.Type, e.E0.Type, expr.tok, \"type of left argument to - ({0}) must agree with the result type ({1})\", e.E0.Type, expr.Type);\n          //     ConstrainSubtypeRelation(expr.Type, e.E1.Type, expr.tok, \"type of right argument to - ({0}) must agree with the result type ({1})\", e.E1.Type, expr.Type);\n          //   }\n          //   break;\n\n          case BinaryExpr.Opcode.Mul: {\n              expr.Type = new InferredTypeProxy();\n              AddXConstraint(e.tok, \"Mullable\", expr.Type, \"type of * must be of a numeric type, bitvector type, or a set-like type (instead got {0})\");\n              ConstrainSubtypeRelation(expr.Type, e.E0.Type, expr.tok, \"type of left argument to * ({0}) must agree with the result type ({1})\", e.E0.Type, expr.Type);\n              ConstrainSubtypeRelation(expr.Type, e.E1.Type, expr.tok, \"type of right argument to * ({0}) must agree with the result type ({1})\", e.E1.Type, expr.Type);\n            }\n            break;\n\n          case BinaryExpr.Opcode.In:\n          case BinaryExpr.Opcode.NotIn:\n            AddXConstraint(expr.tok, \"Innable\", e.E1.Type, e.E0.Type, \"second argument to \\\"\" + BinaryExpr.OpcodeString(e.Op) + \"\\\" must be a set, multiset, or sequence with elements of type {1}, or a map with domain {1} (instead got {0})\");\n            expr.Type = Type.Bool;\n            break;\n\n          case BinaryExpr.Opcode.Div:\n            expr.Type = new InferredTypeProxy();\n            AddXConstraint(expr.tok, \"NumericOrBitvector\", expr.Type, \"arguments to \" + BinaryExpr.OpcodeString(e.Op) + \" must be numeric or bitvector types (got {0})\");\n            ConstrainSubtypeRelation(expr.Type, e.E0.Type,\n              expr, \"type of left argument to \" + BinaryExpr.OpcodeString(e.Op) + \" ({0}) must agree with the result type ({1})\",\n              e.E0.Type, expr.Type);\n            ConstrainSubtypeRelation(expr.Type, e.E1.Type,\n              expr, \"type of right argument to \" + BinaryExpr.OpcodeString(e.Op) + \" ({0}) must agree with the result type ({1})\",\n              e.E1.Type, expr.Type);\n            break;\n\n          case BinaryExpr.Opcode.Mod:\n            expr.Type = new InferredTypeProxy();\n            AddXConstraint(expr.tok, \"IntLikeOrBitvector\", expr.Type, \"arguments to \" + BinaryExpr.OpcodeString(e.Op) + \" must be integer-numeric or bitvector types (got {0})\");\n            ConstrainSubtypeRelation(expr.Type, e.E0.Type,\n              expr, \"type of left argument to \" + BinaryExpr.OpcodeString(e.Op) + \" ({0}) must agree with the result type ({1})\",\n              e.E0.Type, expr.Type);\n            ConstrainSubtypeRelation(expr.Type, e.E1.Type,\n              expr, \"type of right argument to \" + BinaryExpr.OpcodeString(e.Op) + \" ({0}) must agree with the result type ({1})\",\n              e.E1.Type, expr.Type);\n            break;\n\n          case BinaryExpr.Opcode.BitwiseAnd:\n          case BinaryExpr.Opcode.BitwiseOr:\n          case BinaryExpr.Opcode.BitwiseXor:\n            expr.Type = NewIntegerBasedProxy(expr.tok);\n            var errFormat = \"first argument to \" + BinaryExpr.OpcodeString(e.Op) + \" must be of a numeric or bitvector type (instead got {0})\";\n            ConstrainSubtypeRelation(expr.Type, e.E0.Type, expr, errFormat, e.E0.Type);\n            AddXConstraint(expr.tok, \"NumericOrBitvector\", e.E0.Type, errFormat);\n            errFormat = \"second argument to \" + BinaryExpr.OpcodeString(e.Op) + \" must be of a numeric or bitvector type (instead got {0})\";\n            ConstrainSubtypeRelation(expr.Type, e.E1.Type, expr, errFormat, e.E1.Type);\n            AddXConstraint(expr.tok, \"NumericOrBitvector\", e.E1.Type, errFormat);\n            break;\n\n          default:\n            Contract.Assert(false); throw new cce.UnreachableException();  // unexpected operator\n        }\n        // We should also fill in e.ResolvedOp, but we may not have enough information for that yet.  So, instead, delay\n        // setting e.ResolvedOp until inside CheckTypeInference.\n\n      } else if (expr is TernaryExpr) {\n        var e = (TernaryExpr)expr;\n        ResolveExpression(e.E0, opts);\n        ResolveExpression(e.E1, opts);\n        ResolveExpression(e.E2, opts);\n        switch (e.Op) {\n          case TernaryExpr.Opcode.PrefixEqOp:\n          case TernaryExpr.Opcode.PrefixNeqOp:\n            AddXConstraint(expr.tok, \"IntOrORDINAL\", e.E0.Type, \"prefix-equality limit argument must be an ORDINAL or integer expression (got {0})\");\n            AddXConstraint(expr.tok, \"Equatable\", e.E1.Type, e.E2.Type, \"arguments must have the same type (got {0} and {1})\");\n            AddXConstraint(expr.tok, \"IsCoDatatype\", e.E1.Type, \"arguments to prefix equality must be codatatypes (instead of {0})\");\n            expr.Type = Type.Bool;\n            break;\n          default:\n            Contract.Assert(false);  // unexpected ternary operator\n            break;\n        }\n\n      } else if (expr is LetExpr) {\n        var e = (LetExpr)expr;\n        if (e.Exact) {\n          foreach (var rhs in e.RHSs) {\n            ResolveExpression(rhs, opts);\n          }\n          scope.PushMarker();\n          if (e.LHSs.Count != e.RHSs.Count) {\n            reporter.Error(MessageSource.Resolver, expr, \"let expression must have same number of LHSs (found {0}) as RHSs (found {1})\", e.LHSs.Count, e.RHSs.Count);\n          }\n          var i = 0;\n          foreach (var lhs in e.LHSs) {\n            var rhsType = i < e.RHSs.Count ? e.RHSs[i].Type : new InferredTypeProxy();\n            ResolveCasePattern(lhs, rhsType, opts.codeContext);\n            // Check for duplicate names now, because not until after resolving the case pattern do we know if identifiers inside it refer to bound variables or nullary constructors\n            var c = 0;\n            foreach (var v in lhs.Vars) {\n              ScopePushAndReport(scope, v, \"let-variable\");\n              c++;\n            }\n            if (c == 0) {\n              // Every identifier-looking thing in the pattern resolved to a constructor; that is, this LHS is a constant literal\n              reporter.Error(MessageSource.Resolver, lhs.tok, \"LHS is a constant literal; to be legal, it must introduce at least one bound variable\");\n            }\n            i++;\n          }\n        } else {\n          // let-such-that expression\n          if (e.RHSs.Count != 1) {\n            reporter.Error(MessageSource.Resolver, expr, \"let-such-that expression must have just one RHS (found {0})\", e.RHSs.Count);\n          }\n          // the bound variables are in scope in the RHS of a let-such-that expression\n          scope.PushMarker();\n          foreach (var lhs in e.LHSs) {\n            Contract.Assert(lhs.Var != null);  // the parser already checked that every LHS is a BoundVar, not a general pattern\n            var v = lhs.Var;\n            ScopePushAndReport(scope, v, \"let-variable\");\n            ResolveType(v.tok, v.Type, opts.codeContext, ResolveTypeOptionEnum.InferTypeProxies, null);\n            AddTypeDependencyEdges(opts.codeContext, v.Type);\n          }\n          foreach (var rhs in e.RHSs) {\n            ResolveExpression(rhs, opts);\n            ConstrainTypeExprBool(rhs, \"type of RHS of let-such-that expression must be boolean (got {0})\");\n          }\n        }\n        ResolveExpression(e.Body, opts);\n        ResolveAttributes(e.Attributes, e, opts);\n        scope.PopMarker();\n        expr.Type = e.Body.Type;\n      } else if (expr is LetOrFailExpr) {\n        var e = (LetOrFailExpr)expr;\n        ResolveLetOrFailExpr(e, opts);\n      } else if (expr is NamedExpr) {\n        var e = (NamedExpr)expr;\n        ResolveExpression(e.Body, opts);\n        if (e.Contract != null) ResolveExpression(e.Contract, opts);\n        e.Type = e.Body.Type;\n      } else if (expr is QuantifierExpr) {\n        var e = (QuantifierExpr)expr;\n        if (opts.codeContext is Function) {\n          ((Function)opts.codeContext).ContainsQuantifier = true;\n        }\n        Contract.Assert(e.SplitQuantifier == null); // No split quantifiers during resolution\n        int prevErrorCount = reporter.Count(ErrorLevel.Error);\n        bool _val = true;\n        bool typeQuantifier = Attributes.ContainsBool(e.Attributes, \"typeQuantifier\", ref _val) && _val;\n        allTypeParameters.PushMarker();\n        ResolveTypeParameters(e.TypeArgs, true, e);\n        scope.PushMarker();\n        foreach (BoundVar v in e.BoundVars) {\n          ScopePushAndReport(scope, v, \"bound-variable\");\n          var option = typeQuantifier ? new ResolveTypeOption(e) : new ResolveTypeOption(ResolveTypeOptionEnum.InferTypeProxies);\n          ResolveType(v.tok, v.Type, opts.codeContext, option, typeQuantifier ? e.TypeArgs : null);\n        }\n        if (e.TypeArgs.Count > 0 && !typeQuantifier) {\n          reporter.Error(MessageSource.Resolver, expr, \"a quantifier cannot quantify over types. Possible fix: use the experimental attribute :typeQuantifier\");\n        }\n        if (e.Range != null) {\n          ResolveExpression(e.Range, opts);\n          Contract.Assert(e.Range.Type != null);  // follows from postcondition of ResolveExpression\n          ConstrainTypeExprBool(e.Range, \"range of quantifier must be of type bool (instead got {0})\");\n        }\n        ResolveExpression(e.Term, opts);\n        Contract.Assert(e.Term.Type != null);  // follows from postcondition of ResolveExpression\n        ConstrainTypeExprBool(e.Term, \"body of quantifier must be of type bool (instead got {0})\");\n        // Since the body is more likely to infer the types of the bound variables, resolve it\n        // first (above) and only then resolve the attributes (below).\n        ResolveAttributes(e.Attributes, e, opts);\n        scope.PopMarker();\n        allTypeParameters.PopMarker();\n        expr.Type = Type.Bool;\n\n      } else if (expr is SetComprehension) {\n        var e = (SetComprehension)expr;\n        int prevErrorCount = reporter.Count(ErrorLevel.Error);\n        scope.PushMarker();\n        foreach (BoundVar v in e.BoundVars) {\n          ScopePushAndReport(scope, v, \"bound-variable\");\n          ResolveType(v.tok, v.Type, opts.codeContext, ResolveTypeOptionEnum.InferTypeProxies, null);\n          var inferredProxy = v.Type as InferredTypeProxy;\n          if (inferredProxy != null) {\n            Contract.Assert(!inferredProxy.KeepConstraints);  // in general, this proxy is inferred to be a base type\n          }\n        }\n        ResolveExpression(e.Range, opts);\n        Contract.Assert(e.Range.Type != null);  // follows from postcondition of ResolveExpression\n        ConstrainTypeExprBool(e.Range, \"range of comprehension must be of type bool (instead got {0})\");\n        ResolveExpression(e.Term, opts);\n        Contract.Assert(e.Term.Type != null);  // follows from postcondition of ResolveExpression\n\n        ResolveAttributes(e.Attributes, e, opts);\n        scope.PopMarker();\n        expr.Type = new SetType(e.Finite, e.Term.Type);\n\n      } else if (expr is MapComprehension) {\n        var e = (MapComprehension)expr;\n        int prevErrorCount = reporter.Count(ErrorLevel.Error);\n        scope.PushMarker();\n        Contract.Assert(e.BoundVars.Count == 1 || (1 < e.BoundVars.Count && e.TermLeft != null));\n        foreach (BoundVar v in e.BoundVars) {\n          ScopePushAndReport(scope, v, \"bound-variable\");\n          ResolveType(v.tok, v.Type, opts.codeContext, ResolveTypeOptionEnum.InferTypeProxies, null);\n          var inferredProxy = v.Type as InferredTypeProxy;\n          if (inferredProxy != null) {\n            Contract.Assert(!inferredProxy.KeepConstraints);  // in general, this proxy is inferred to be a base type\n          }\n        }\n        ResolveExpression(e.Range, opts);\n        Contract.Assert(e.Range.Type != null);  // follows from postcondition of ResolveExpression\n        ConstrainTypeExprBool(e.Range, \"range of comprehension must be of type bool (instead got {0})\");\n        if (e.TermLeft != null) {\n          ResolveExpression(e.TermLeft, opts);\n          Contract.Assert(e.TermLeft.Type != null);  // follows from postcondition of ResolveExpression\n        }\n        ResolveExpression(e.Term, opts);\n        Contract.Assert(e.Term.Type != null);  // follows from postcondition of ResolveExpression\n\n        ResolveAttributes(e.Attributes, e, opts);\n        scope.PopMarker();\n        expr.Type = new MapType(e.Finite, e.TermLeft != null ? e.TermLeft.Type : e.BoundVars[0].Type, e.Term.Type);\n\n      } else if (expr is LambdaExpr) {\n        var e = (LambdaExpr)expr;\n        int prevErrorCount = reporter.Count(ErrorLevel.Error);\n        scope.PushMarker();\n        foreach (BoundVar v in e.BoundVars) {\n          ScopePushAndReport(scope, v, \"bound-variable\");\n          ResolveType(v.tok, v.Type, opts.codeContext, ResolveTypeOptionEnum.InferTypeProxies, null);\n        }\n\n        if (e.Range != null) {\n          ResolveExpression(e.Range, opts);\n          Contract.Assert(e.Range.Type != null);  // follows from postcondition of ResolveExpression\n          ConstrainTypeExprBool(e.Range, \"Precondition must be boolean (got {0})\");\n        }\n\n        foreach (var read in e.Reads) {\n          ResolveFrameExpression(read, FrameExpressionUse.Reads, opts.codeContext);\n        }\n\n        ResolveExpression(e.Term, opts);\n        Contract.Assert(e.Term.Type != null);\n        scope.PopMarker();\n        expr.Type = SelectAppropriateArrowType(e.tok, e.BoundVars.ConvertAll(v => v.Type), e.Body.Type, e.Reads.Count != 0, e.Range != null);\n      } else if (expr is WildcardExpr) {\n        expr.Type = new SetType(true, builtIns.ObjectQ());\n      } else if (expr is StmtExpr) {\n        var e = (StmtExpr)expr;\n        int prevErrorCount = reporter.Count(ErrorLevel.Error);\n        ResolveStatement(e.S, opts.codeContext);\n        if (reporter.Count(ErrorLevel.Error) == prevErrorCount) {\n          var r = e.S as UpdateStmt;\n          if (r != null && r.ResolvedStatements.Count == 1) {\n            var call = r.ResolvedStatements[0] as CallStmt;\n            if (call.Method.Mod.Expressions.Count != 0) {\n              reporter.Error(MessageSource.Resolver, call, \"calls to methods with side-effects are not allowed inside a statement expression\");\n            } else if (call.Method is TwoStateLemma && !opts.twoState) {\n              reporter.Error(MessageSource.Resolver, call, \"two-state lemmas can only be used in two-state contexts\");\n            }\n          }\n        }\n        ResolveExpression(e.E, opts);\n        Contract.Assert(e.E.Type != null);  // follows from postcondition of ResolveExpression\n        expr.Type = e.E.Type;\n\n      } else if (expr is ITEExpr) {\n        ITEExpr e = (ITEExpr)expr;\n        ResolveExpression(e.Test, opts);\n        Contract.Assert(e.Test.Type != null);  // follows from postcondition of ResolveExpression\n        ResolveExpression(e.Thn, opts);\n        Contract.Assert(e.Thn.Type != null);  // follows from postcondition of ResolveExpression\n        ResolveExpression(e.Els, opts);\n        Contract.Assert(e.Els.Type != null);  // follows from postcondition of ResolveExpression\n        ConstrainTypeExprBool(e.Test, \"guard condition in if-then-else expression must be a boolean (instead got {0})\");\n        expr.Type = new InferredTypeProxy();\n        ConstrainSubtypeRelation(expr.Type, e.Thn.Type, expr, \"the two branches of an if-then-else expression must have the same type (got {0} and {1})\", e.Thn.Type, e.Els.Type);\n        ConstrainSubtypeRelation(expr.Type, e.Els.Type, expr, \"the two branches of an if-then-else expression must have the same type (got {0} and {1})\", e.Thn.Type, e.Els.Type);\n\n      } else if (expr is MatchExpr) {\n        ResolveMatchExpr((MatchExpr)expr, opts);\n      } else {\n        Contract.Assert(false); throw new cce.UnreachableException();  // unexpected expression\n      }\n\n      if (expr.Type == null) {\n        // some resolution error occurred\n        expr.Type = new InferredTypeProxy();\n      }\n    }\n\n    private Expression VarDotFunction(IToken tok, string varname, string functionname) {\n      return new ApplySuffix(tok, new ExprDotName(tok, new IdentifierExpr(tok, varname), functionname, null), new List<Expression>() { });\n    }\n\n    // TODO search for occurrences of \"new LetExpr\" which could benefit from this helper\n    private LetExpr LetPatIn(IToken tok, CasePattern<BoundVar> lhs, Expression rhs, Expression body) {\n      return new LetExpr(tok, new List<CasePattern<BoundVar>>() { lhs }, new List<Expression>() { rhs }, body, true);\n    }\n\n    private LetExpr LetVarIn(IToken tok, string name, Type tp, Expression rhs, Expression body) {\n      var lhs = new CasePattern<BoundVar>(tok, new BoundVar(tok, name, tp));\n      return LetPatIn(tok, lhs, rhs, body);\n    }\n\n    /// <summary>\n    ///  If expr.Lhs != null: Desugars \"var x: T :- E; F\" into \"var temp := E; if temp.IsFailure() then temp.PropagateFailure() else var x: T := temp.Extract(); F\"\n    ///  If expr.Lhs == null: Desugars \"         :- E; F\" into \"var temp := E; if temp.IsFailure() then temp.PropagateFailure() else                             F\"\n    /// </summary>\n    public void ResolveLetOrFailExpr(LetOrFailExpr expr, ResolveOpts opts) {\n      var temp = FreshTempVarName(\"valueOrError\", opts.codeContext);\n      var tempType = new InferredTypeProxy();\n      // \"var temp := E;\"\n      expr.ResolvedExpression = LetVarIn(expr.tok, temp, tempType, expr.Rhs,\n        // \"if temp.IsFailure()\"\n        new ITEExpr(expr.tok, false, VarDotFunction(expr.tok, temp, \"IsFailure\"),\n          // \"then temp.PropagateFailure()\"\n          VarDotFunction(expr.tok, temp, \"PropagateFailure\"),\n          // \"else\"\n          expr.Lhs == null\n            // \"F\"\n            ? expr.Body\n            // \"var x: T := temp.Extract(); F\"\n            : LetPatIn(expr.tok, expr.Lhs, VarDotFunction(expr.tok, temp, \"Extract\"), expr.Body)));\n\n      ResolveExpression(expr.ResolvedExpression, opts);\n      bool expectExtract = (expr.Lhs != null);\n      EnsureSupportsErrorHandling(expr.tok, PartiallyResolveTypeForMemberSelection(expr.tok, tempType), expectExtract);\n    }\n\n    private Type SelectAppropriateArrowType(IToken tok, List<Type> typeArgs, Type resultType, bool hasReads, bool hasReq) {\n      Contract.Requires(tok != null);\n      Contract.Requires(typeArgs != null);\n      Contract.Requires(resultType != null);\n      var arity = typeArgs.Count;\n      var typeArgsAndResult = Util.Snoc(typeArgs, resultType);\n      if (hasReads) {\n        // any arrow\n        return new ArrowType(tok, builtIns.ArrowTypeDecls[arity], typeArgsAndResult);\n      } else if (hasReq) {\n        // partial arrow\n        return new UserDefinedType(tok, ArrowType.PartialArrowTypeName(arity), builtIns.PartialArrowTypeDecls[arity], typeArgsAndResult);\n      } else {\n        // total arrow\n        return new UserDefinedType(tok, ArrowType.TotalArrowTypeName(arity), builtIns.TotalArrowTypeDecls[arity], typeArgsAndResult);\n      }\n    }\n\n    /// <summary>\n    /// Adds appropriate type constraints that says \"expr\" evaluates to an integer (not a bitvector, but possibly an\n    /// int-based newtype).  The \"errFormat\" string can contain a \"{0}\", referring to the name of the type of \"expr\".\n    /// </summary>\n    void ConstrainToIntegerType(Expression expr, string errFormat) {\n      Contract.Requires(expr != null);\n      Contract.Requires(errFormat != null);\n      // We do two constraints: the first can aid in determining types, but allows bit-vectors; the second excludes bit-vectors.\n      // However, we reuse the error message, so that only one error gets reported.\n      var err = new TypeConstraint.ErrorMsgWithToken(expr.tok, errFormat, expr.Type);\n      ConstrainSubtypeRelation(new IntVarietiesSupertype(), expr.Type, err);\n      AddXConstraint(expr.tok, \"IntegerType\", expr.Type, err);\n    }\n\n    void AddAssignableConstraint(IToken tok, Type lhs, Type rhs, string errMsgFormat) {\n      Contract.Requires(tok != null);\n      Contract.Requires(lhs != null);\n      Contract.Requires(rhs != null);\n      Contract.Requires(errMsgFormat != null);\n      AddXConstraint(tok, \"Assignable\", lhs, rhs, errMsgFormat);\n    }\n    private void AddXConstraint(IToken tok, string constraintName, Type type, string errMsgFormat) {\n      Contract.Requires(tok != null);\n      Contract.Requires(constraintName != null);\n      Contract.Requires(type != null);\n      Contract.Requires(errMsgFormat != null);\n      var types = new Type[] { type };\n      AllXConstraints.Add(new XConstraint(tok, constraintName, types, new TypeConstraint.ErrorMsgWithToken(tok, errMsgFormat, types)));\n    }\n    void AddAssignableConstraint(IToken tok, Type lhs, Type rhs, TypeConstraint.ErrorMsg errMsg) {\n      Contract.Requires(tok != null);\n      Contract.Requires(lhs != null);\n      Contract.Requires(rhs != null);\n      Contract.Requires(errMsg != null);\n      AddXConstraint(tok, \"Assignable\", lhs, rhs, errMsg);\n    }\n    private void AddXConstraint(IToken tok, string constraintName, Type type, TypeConstraint.ErrorMsg errMsg) {\n      Contract.Requires(tok != null);\n      Contract.Requires(constraintName != null);\n      Contract.Requires(type != null);\n      Contract.Requires(errMsg != null);\n      var types = new Type[] { type };\n      AllXConstraints.Add(new XConstraint(tok, constraintName, types, errMsg));\n    }\n    private void AddXConstraint(IToken tok, string constraintName, Type type0, Type type1, string errMsgFormat) {\n      Contract.Requires(tok != null);\n      Contract.Requires(constraintName != null);\n      Contract.Requires(type0 != null);\n      Contract.Requires(type1 != null);\n      Contract.Requires(errMsgFormat != null);\n      var types = new Type[] { type0, type1 };\n      AllXConstraints.Add(new XConstraint(tok, constraintName, types, new TypeConstraint.ErrorMsgWithToken(tok, errMsgFormat, types)));\n    }\n    private void AddXConstraint(IToken tok, string constraintName, Type type0, Type type1, TypeConstraint.ErrorMsg errMsg) {\n      Contract.Requires(tok != null);\n      Contract.Requires(constraintName != null);\n      Contract.Requires(type0 != null);\n      Contract.Requires(type1 != null);\n      Contract.Requires(errMsg != null);\n      var types = new Type[] { type0, type1 };\n      AllXConstraints.Add(new XConstraint(tok, constraintName, types, errMsg));\n    }\n    private void AddXConstraint(IToken tok, string constraintName, Type type, Expression expr, string errMsgFormat) {\n      Contract.Requires(tok != null);\n      Contract.Requires(constraintName != null);\n      Contract.Requires(type != null);\n      Contract.Requires(expr != null);\n      Contract.Requires(errMsgFormat != null);\n      var types = new Type[] { type };\n      var exprs = new Expression[] { expr };\n      AllXConstraints.Add(new XConstraintWithExprs(tok, constraintName, types, exprs, new TypeConstraint.ErrorMsgWithToken(tok, errMsgFormat, types)));\n    }\n    private void AddXConstraint(IToken tok, string constraintName, Type type, Expression expr0, Expression expr1, string errMsgFormat) {\n      Contract.Requires(tok != null);\n      Contract.Requires(constraintName != null);\n      Contract.Requires(type != null);\n      Contract.Requires(expr0 != null);\n      Contract.Requires(expr1 != null);\n      Contract.Requires(errMsgFormat != null);\n      var types = new Type[] { type };\n      var exprs = new Expression[] { expr0, expr1 };\n      AllXConstraints.Add(new XConstraintWithExprs(tok, constraintName, types, exprs, new TypeConstraint.ErrorMsgWithToken(tok, errMsgFormat, types)));\n    }\n\n    /// <summary>\n    /// Attempts to rewrite a datatype update into more primitive operations, after doing the appropriate resolution checks.\n    /// Upon success, returns that rewritten expression and sets \"legalSourceConstructors\".\n    /// Upon some resolution error, return null.\n    /// </summary>\n    Expression ResolveDatatypeUpdate(IToken tok, Expression root, DatatypeDecl dt, List<Tuple<IToken, string, Expression>> memberUpdates, ResolveOpts opts, out List<DatatypeCtor> legalSourceConstructors) {\n      Contract.Requires(tok != null);\n      Contract.Requires(root != null);\n      Contract.Requires(dt != null);\n      Contract.Requires(memberUpdates != null);\n      Contract.Requires(opts != null);\n\n      legalSourceConstructors = null;\n\n      // First, compute the list of candidate result constructors, that is, the constructors\n      // that have all of the mentioned destructors. Issue errors for duplicated names and for\n      // names that are not destructors in the datatype.\n      var candidateResultCtors = dt.Ctors;  // list of constructors that have all the so-far-mentioned destructors\n      var memberNames = new HashSet<string>();\n      var rhsBindings = new Dictionary<string, Tuple<BoundVar/*let variable*/, IdentifierExpr/*id expr for let variable*/, Expression /*RHS in given syntax*/>>();\n      var subst = TypeSubstitutionMap(dt.TypeArgs, root.Type.NormalizeExpand().TypeArgs);\n      foreach (var entry in memberUpdates) {\n        var destructor_str = entry.Item2;\n        if (memberNames.Contains(destructor_str)) {\n          reporter.Error(MessageSource.Resolver, entry.Item1, \"duplicate update member '{0}'\", destructor_str);\n        } else {\n          memberNames.Add(destructor_str);\n          MemberDecl member;\n          if (!classMembers[dt].TryGetValue(destructor_str, out member)) {\n            reporter.Error(MessageSource.Resolver, entry.Item1, \"member '{0}' does not exist in datatype '{1}'\", destructor_str, dt.Name);\n          } else if (!(member is DatatypeDestructor)) {\n            reporter.Error(MessageSource.Resolver, entry.Item1, \"member '{0}' is not a destructor in datatype '{1}'\", destructor_str, dt.Name);\n          } else {\n            var destructor = (DatatypeDestructor)member;\n            var intersection = new List<DatatypeCtor>(candidateResultCtors.Intersect(destructor.EnclosingCtors));\n            if (intersection.Count == 0) {\n              reporter.Error(MessageSource.Resolver, entry.Item1,\n                \"updated datatype members must belong to the same constructor (unlike the previously mentioned destructors, '{0}' does not belong to {1})\",\n                destructor_str, DatatypeDestructor.PrintableCtorNameList(candidateResultCtors, \"or\"));\n            } else {\n              candidateResultCtors = intersection;\n              if (destructor.IsGhost) {\n                rhsBindings.Add(destructor_str, new Tuple<BoundVar, IdentifierExpr, Expression>(null, null, entry.Item3));\n              } else {\n                var xName = FreshTempVarName(string.Format(\"dt_update#{0}#\", destructor_str), opts.codeContext);\n                var xVar = new BoundVar(new AutoGeneratedToken(tok), xName, SubstType(destructor.Type, subst));\n                var x = new IdentifierExpr(new AutoGeneratedToken(tok), xVar);\n                rhsBindings.Add(destructor_str, new Tuple<BoundVar, IdentifierExpr, Expression>(xVar, x, entry.Item3));\n              }\n            }\n          }\n        }\n      }\n      if (candidateResultCtors.Count == 0) {\n        return null;\n      }\n\n      // Check that every candidate result constructor has given a name to all of its parameters.\n      var hasError = false;\n      foreach (var ctor in candidateResultCtors) {\n        if (ctor.Formals.Exists(f => !f.HasName)) {\n          reporter.Error(MessageSource.Resolver, tok,\n            \"candidate result constructor '{0}' has an anonymous parameter (to use in datatype update expression, name all the parameters of the candidate result constructors)\",\n            ctor.Name);\n          hasError = true;\n        }\n      }\n      if (hasError) {\n        return null;\n      }\n\n      // The legal source constructors are the candidate result constructors. (Yep, two names for the same thing.)\n      legalSourceConstructors = candidateResultCtors;\n      Contract.Assert(1 <= legalSourceConstructors.Count);\n\n      // Rewrite the datatype update root.(x := X, y := Y, ...) to:\n      //     var d := root;\n      //     var x := X;  // EXCEPT: don't do this for ghost fields\n      //     var y := Y;\n      //     ..\n      //     if d.CandidateResultConstructor0 then\n      //       CandidateResultConstructor0(x, y, ..., d.f0, d.f1, ...)  // for a ghost field x, use the expression X directly\n      //     else if d.CandidateResultConstructor1 then\n      //       CandidateResultConstructor0(x, y, ..., d.g0, d.g1, ...)\n      //     ...\n      //     else\n      //       CandidateResultConstructorN(x, y, ..., d.k0, d.k1, ...)\n      //\n      Expression rewrite = null;\n      // Create a unique name for d', the variable we introduce in the let expression\n      var dName = FreshTempVarName(\"dt_update_tmp#\", opts.codeContext);\n      var dVar = new BoundVar(new AutoGeneratedToken(tok), dName, root.Type);\n      var d = new IdentifierExpr(new AutoGeneratedToken(tok), dVar);\n      Expression body = null;\n      candidateResultCtors.Reverse();\n      foreach (var crc in candidateResultCtors) {\n        // Build the arguments to the datatype constructor, using the updated value in the appropriate slot\n        var ctor_args = new List<Expression>();\n        foreach (var f in crc.Formals) {\n          Tuple<BoundVar/*let variable*/, IdentifierExpr/*id expr for let variable*/, Expression /*RHS in given syntax*/> info;\n          if (rhsBindings.TryGetValue(f.Name, out info)) {\n            ctor_args.Add(info.Item2 ?? info.Item3);\n          } else {\n            ctor_args.Add(new ExprDotName(tok, d, f.Name, null));\n          }\n        }\n        var ctor_call = new DatatypeValue(tok, crc.EnclosingDatatype.Name, crc.Name, ctor_args);\n        ResolveDatatypeValue(opts, ctor_call, dt, root.Type.NormalizeExpand());  // resolve to root.Type, so that type parameters get filled in appropriately\n        if (body == null) {\n          body = ctor_call;\n        } else {\n          // body = if d.crc? then ctor_call else body\n          var guard = new ExprDotName(tok, d, crc.QueryField.Name, null);\n          body = new ITEExpr(tok, false, guard, ctor_call, body);\n        }\n      }\n      Contract.Assert(body != null);  // because there was at least one element in candidateResultCtors\n\n      // Wrap the let's around body\n      rewrite = body;\n      foreach (var entry in rhsBindings) {\n        if (entry.Value.Item1 != null) {\n          var lhs = new CasePattern<BoundVar>(tok, entry.Value.Item1);\n          rewrite = new LetExpr(tok, new List<CasePattern<BoundVar>>() { lhs }, new List<Expression>() { entry.Value.Item3 }, rewrite, true);\n        }\n      }\n      var dVarPat = new CasePattern<BoundVar>(tok, dVar);\n      rewrite = new LetExpr(tok, new List<CasePattern<BoundVar>>() { dVarPat }, new List<Expression>() { root }, rewrite, true);\n      Contract.Assert(rewrite != null);\n      ResolveExpression(rewrite, opts);\n      return rewrite;\n    }\n\n    void ResolveMatchExpr(MatchExpr me, ResolveOpts opts) {\n      Contract.Requires(me != null);\n      Contract.Requires(opts != null);\n      Contract.Requires(me.OrigUnresolved == null);\n\n      // first, clone the original expression\n      me.OrigUnresolved = (MatchExpr)new Cloner().CloneExpr(me);\n      ResolveExpression(me.Source, opts);\n      Contract.Assert(me.Source.Type != null);  // follows from postcondition of ResolveExpression\n      var errorCount = reporter.Count(ErrorLevel.Error);\n      if (me.Source is DatatypeValue) {\n        var e = (DatatypeValue)me.Source;\n        if (e.Arguments.Count < 1) {\n          reporter.Error(MessageSource.Resolver, me.tok, \"match source tuple needs at least 1 argument\");\n        }\n        foreach (var arg in e.Arguments) {\n          if (arg is DatatypeValue && ((DatatypeValue)arg).Arguments.Count < 1) {\n            reporter.Error(MessageSource.Resolver, me.tok, \"match source tuple needs at least 1 argument\");\n          }\n        }\n      }\n      if (reporter.Count(ErrorLevel.Error) != errorCount) {\n        return;\n      }\n      var sourceType = PartiallyResolveTypeForMemberSelection(me.Source.tok, me.Source.Type).NormalizeExpand();\n      var dtd = sourceType.AsDatatype;\n      var subst = new Dictionary<TypeParameter, Type>();\n      Dictionary<string, DatatypeCtor> ctors;\n      if (dtd == null) {\n        reporter.Error(MessageSource.Resolver, me.Source, \"the type of the match source expression must be a datatype (instead found {0})\", me.Source.Type);\n        ctors = null;\n      } else {\n        Contract.Assert(sourceType != null);  // dtd and sourceType are set together above\n        ctors = datatypeCtors[dtd];\n        Contract.Assert(ctors != null);  // dtd should have been inserted into datatypeCtors during a previous resolution stage\n\n        // build the type-parameter substitution map for this use of the datatype\n        subst = TypeSubstitutionMap(dtd.TypeArgs, sourceType.TypeArgs);\n      }\n\n      // convert CasePattern in MatchCaseExpr to BoundVar and flatten the MatchCaseExpr.\n      List<Tuple<CasePattern<BoundVar>, BoundVar>> patternSubst = new List<Tuple<CasePattern<BoundVar>, BoundVar>>();\n      if (dtd != null) {\n        DesugarMatchCaseExpr(me, dtd, patternSubst, opts.codeContext);\n      }\n\n      ISet<string> memberNamesUsed = new HashSet<string>();\n      me.Type = new InferredTypeProxy();\n      foreach (MatchCaseExpr mc in me.Cases) {\n        DatatypeCtor ctor = null;\n        if (ctors != null) {\n          Contract.Assert(dtd != null);\n          var ctorId = mc.Id;\n          if (me.Source.Type.AsDatatype is TupleTypeDecl) {\n            var tuple = (TupleTypeDecl)me.Source.Type.AsDatatype;\n            var dims = tuple.Dims;\n            ctorId = BuiltIns.TupleTypeCtorNamePrefix + dims;\n          }\n          if (!ctors.TryGetValue(ctorId, out ctor)) {\n            reporter.Error(MessageSource.Resolver, mc.tok, \"member {0} does not exist in datatype {1}\", ctorId, dtd.Name);\n          } else {\n            Contract.Assert(ctor != null);  // follows from postcondition of TryGetValue\n            mc.Ctor = ctor;\n            if (ctor.Formals.Count != mc.Arguments.Count) {\n              if (me.Source.Type.AsDatatype is TupleTypeDecl) {\n                reporter.Error(MessageSource.Resolver, mc.tok, \"case arguments count does not match source arguments count\");\n              } else {\n                reporter.Error(MessageSource.Resolver, mc.tok, \"member {0} has wrong number of formals (found {1}, expected {2})\", ctorId, mc.Arguments.Count, ctor.Formals.Count);\n              }\n            }\n            if (memberNamesUsed.Contains(ctorId)) {\n              reporter.Error(MessageSource.Resolver, mc.tok, \"member {0} appears in more than one case\", mc.Id);\n            } else {\n              memberNamesUsed.Add(ctorId);  // add mc.Id to the set of names used\n            }\n          }\n        }\n        scope.PushMarker();\n        int i = 0;\n        if (mc.Arguments != null) {\n          foreach (BoundVar v in mc.Arguments) {\n            scope.Push(v.Name, v);\n            ResolveType(v.tok, v.Type, opts.codeContext, ResolveTypeOptionEnum.InferTypeProxies, null);\n            if (ctor != null && i < ctor.Formals.Count) {\n              Formal formal = ctor.Formals[i];\n              Type st = SubstType(formal.Type, subst);\n              ConstrainSubtypeRelation(v.Type, st, me,\n                \"the declared type of the formal ({0}) does not agree with the corresponding type in the constructor's signature ({1})\", v.Type, st);\n              v.IsGhost = formal.IsGhost;\n\n              // update the type of the boundvars in the MatchCaseToken\n              if (v.tok is MatchCaseToken) {\n                MatchCaseToken mt = (MatchCaseToken)v.tok;\n                foreach (Tuple<IToken, BoundVar, bool> entry in mt.varList) {\n                  ConstrainSubtypeRelation(entry.Item2.Type, v.Type, entry.Item1, \"incorrect type for bound match-case variable (expected {0}, got {1})\", v.Type, entry.Item2.Type);\n                }\n              }\n            }\n            i++;\n          }\n        }\n        ResolveExpression(mc.Body, opts);\n        // substitute body to replace the case pat with v. This needs to happen\n        // after the body is resolved so we can scope the bv correctly.\n        if (patternSubst.Count > 0) {\n          var cloner = new MatchCaseExprSubstituteCloner(patternSubst);\n          mc.UpdateBody(cloner.CloneExpr(mc.Body));\n          // resolve it again since we just cloned it.\n          ResolveExpression(mc.Body, opts);\n        }\n\n        Contract.Assert(mc.Body.Type != null);  // follows from postcondition of ResolveExpression\n        ConstrainSubtypeRelation(me.Type, mc.Body.Type, mc.Body.tok, \"type of case bodies do not agree (found {0}, previous types {1})\", mc.Body.Type, me.Type);\n        scope.PopMarker();\n      }\n      if (dtd != null && memberNamesUsed.Count != dtd.Ctors.Count) {\n        // We could complain about the syntactic omission of constructors:\n        //   reporter.Error(MessageSource.Resolver, expr, \"match expression does not cover all constructors\");\n        // but instead we let the verifier do a semantic check.\n        // So, for now, record the missing constructors:\n        foreach (var ctr in dtd.Ctors) {\n          if (!memberNamesUsed.Contains(ctr.Name)) {\n            me.MissingCases.Add(ctr);\n          }\n        }\n        Contract.Assert(memberNamesUsed.Count + me.MissingCases.Count == dtd.Ctors.Count);\n      }\n    }\n\n    /*\n     * Convert\n     *   match xs\n     *     case Cons(y, Cons(z, zs)) => last(Cons(z, zs))\n     *     case Cons(y, Nil) => y\n     * To\n     *   match xs\n     *     case Cons(y, ys) => match ys\n     *       case Nil => y\n     *       case Cons(z, zs) => last(ys)\n     * */\n    void DesugarMatchCaseExpr(MatchExpr me, DatatypeDecl dtd, List<Tuple<CasePattern<BoundVar>, BoundVar>> patterns, ICodeContext codeContext) {\n      Contract.Assert(dtd != null);\n      Dictionary<string, DatatypeCtor> ctors = datatypeCtors[dtd];\n      if (ctors == null) {\n        // no constructors, there is no need to desugar\n        return;\n      }\n      // Each tuple element gets mapped to its constructor's dictionary.\n      // Type variables get an empty dictionary.\n      var tupleCtorsList = new List<Dictionary<string, DatatypeCtor>>();\n      if (me.Source.Type.AsDatatype is TupleTypeDecl) {\n        var udt = me.Source.Type.NormalizeExpand() as UserDefinedType;\n        foreach (Type typeArg in udt.TypeArgs) {\n          var t = PartiallyResolveTypeForMemberSelection(me.tok, typeArg).NormalizeExpand() as UserDefinedType;\n          if (t != null) {\n            var cls = t.ResolvedClass as DatatypeDecl;\n            if (cls != null) {\n              tupleCtorsList.Add(datatypeCtors[cls]);\n            } else {\n              tupleCtorsList.Add(new Dictionary<string, DatatypeCtor>());\n            }\n          } else {\n            tupleCtorsList.Add(new Dictionary<string, DatatypeCtor>());\n          }\n        }\n      }\n\n      bool keepOrigToken = true;\n      foreach (MatchCaseExpr mc in me.Cases) {\n        if (mc.Arguments != null) {\n          // already desugared. This happens during the second pass resolver after cloning.\n          Contract.Assert(mc.CasePatterns == null);\n          return;\n        }\n\n        Contract.Assert(mc.Arguments == null);\n        Contract.Assert(mc.CasePatterns != null);\n        Contract.Assert(ctors != null);\n        DatatypeCtor ctor = null;\n        if (ctors.TryGetValue(mc.Id, out ctor) || (me.Source.Type.AsDatatype is TupleTypeDecl)) {\n          scope.PushMarker();\n          if (me.Source.Type.AsDatatype is TupleTypeDecl) {\n            int i = 0;\n            foreach (var pat in mc.CasePatterns) {\n              FindDuplicateIdentifier(pat, tupleCtorsList[i++], true);\n            }\n          } else {\n            foreach (var pat in mc.CasePatterns) {\n              FindDuplicateIdentifier(pat, ctors, true);\n            }\n          }\n          List<BoundVar> arguments = new List<BoundVar>();\n          Expression body = mc.Body;\n          for (int i = mc.CasePatterns.Count-1; i>=0; i--) {\n            string name = \"_ms#\" + i;\n            Type type = new InferredTypeProxy();\n            BoundVar sourceVar = new BoundVar(new MatchCaseToken(me.tok), name, type);\n            var pat = mc.CasePatterns[i];\n            if (pat.Var != null) {\n              BoundVar v = pat.Var;\n              arguments.Insert(0, v);\n            } else {\n              body = DesugarMatchCasePattern(mc, pat, sourceVar, body, keepOrigToken);\n              patterns.Add(new Tuple<CasePattern<BoundVar>, BoundVar>(pat, sourceVar));\n              arguments.Insert(0, sourceVar);\n            }\n          }\n          keepOrigToken = false;\n          mc.UpdateBody(body);\n          mc.Arguments = arguments;\n          mc.CasePatterns = null;\n          scope.PopMarker();\n        } else if (mc.CasePatterns != null) {\n          reporter.Error(MessageSource.Resolver, mc.tok, \"Type mismatch: expected constructor of type {0}.  Got {1}.\", dtd.Name, mc.Id);\n          return;\n        }\n      }\n\n\n      List<MatchCaseExpr> newCases = new List<MatchCaseExpr>();\n\n      // need to consolidate the cases.\n      // Convert\n      //  match xs\n      //    case Cons(y, #mc#0) => match #mc#0\n      //                case Cons((z, zs) => body\n      //    case Cons(y, #mc#0) => match #mc#0\n      //                case Nil => y\n      // into\n      //  match xs\n      //    case Cons(y, #mc#0) => match #mc#0\n      //                case Cons((z, zs) => body\n      //                case Nil => y\n      bool thingsChanged = false;\n      Dictionary<string, MatchCaseExpr> caseMap = new Dictionary<string, MatchCaseExpr>();\n      List<MatchCaseExpr> mcWithWildCard = new List<MatchCaseExpr>();\n      foreach (MatchCaseExpr mc in me.Cases) {\n        // check each CasePattern to see if it has wildcard.\n        if (CaseExprHasWildCard(mc)) {\n          mcWithWildCard.Add(mc);\n        } else {\n          thingsChanged |= CombineMatchCaseExpr(mc, newCases, caseMap, codeContext);\n        }\n      }\n\n      foreach (MatchCaseExpr mc in mcWithWildCard) {\n        // now process with cases with wildcard\n        thingsChanged |= CombineMatchCaseExpr(mc, newCases, caseMap, codeContext);\n      }\n\n      if (thingsChanged) {\n        me.UpdateCases(newCases);\n      }\n    }\n\n    Expression DesugarMatchCasePattern(MatchCaseExpr mc, CasePattern<BoundVar> pat, BoundVar v, Expression body, bool keepToken) {\n      // convert\n      //    case Cons(y, Cons(z, zs)) => body\n      // to\n      //    case Cons(y, #mc#) => match #mc#\n      //            case Cons(z, zs) => body\n\n      Expression source = new NameSegment(new AutoGeneratedToken(pat.tok), v.Name, null);\n      List<MatchCaseExpr> cases = new List<MatchCaseExpr>();\n      cases.Add(new MatchCaseExpr(pat.tok, pat.Id, pat.Arguments == null ? new List<CasePattern<BoundVar>>() : pat.Arguments, body));\n      if (!keepToken) {\n        AutoGeneratedTokenCloner cloner = new AutoGeneratedTokenCloner();\n        source = cloner.CloneExpr(source);\n      }\n      return new MatchExpr(pat.tok, source, cases, false);\n    }\n\n\n    bool CaseExprHasWildCard(MatchCase mc) {\n      if (mc.Arguments != null) {\n        foreach (BoundVar bv in mc.Arguments) {\n          if (LocalVariable.HasWildcardName(bv)) {\n            return true;\n          }\n        }\n      }\n      return false;\n    }\n\n    bool CombineMatchCaseExpr(MatchCaseExpr mc, List<MatchCaseExpr> newCases, Dictionary<string, MatchCaseExpr> caseMap, ICodeContext codeContext) {\n      bool thingsChanged = false;\n      MatchCaseExpr old_mc;\n      if (caseMap.TryGetValue(mc.Id, out old_mc)) {\n        // already has a case with the same ctor, try to consolidate the body.\n        if (SameMatchCaseExpr(old_mc, mc, codeContext)) {\n          MatchExpr old = (MatchExpr)old_mc.Body;\n          MatchExpr current = (MatchExpr)mc.Body;\n          foreach (MatchCaseExpr c in current.Cases) {\n            old.Cases.Add(c);\n          }\n          // add the token from mc to old_mc so the identifiers will show correctly in the IDE\n          List<BoundVar> arguments = new List<BoundVar>();\n          Contract.Assert(old_mc.Arguments.Count == mc.Arguments.Count);\n          for (int i = 0; i < old_mc.Arguments.Count; i++) {\n            var bv = old_mc.Arguments[i];\n            MatchCaseToken mcToken;\n            if (!(bv.tok is MatchCaseToken)) {\n              // create a MatchCaseToken\n              mcToken = new MatchCaseToken(bv.tok);\n              // clone the bv but with the MatchCaseToken\n              var bvNew = new BoundVar(mcToken, bv.Name, bv.Type);\n              bvNew.IsGhost = bv.IsGhost;\n              arguments.Add(bvNew);\n            } else {\n              mcToken = (MatchCaseToken)bv.tok;\n              arguments.Add(bv);\n            }\n            mcToken.AddVar(bv.tok, bv, true);\n            mcToken.AddVar(mc.Arguments[i].tok, mc.Arguments[i], true);\n          }\n          old_mc.Arguments = arguments;\n          thingsChanged = true;\n        } else {\n          // duplicate cases, do nothing for now. The error will be reported during resolving\n        }\n      } else {\n        // it is a new case.\n        newCases.Add(mc);\n        caseMap.Add(mc.Id, mc);\n      }\n      return thingsChanged;\n    }\n\n\n    bool SameMatchCaseExpr(MatchCaseExpr one, MatchCaseExpr other, ICodeContext codeContext) {\n      // this method is called after all the CasePattern in the match cases are converted\n      // into BoundVars.\n      Contract.Assert(one.CasePatterns == null && one.Arguments != null);\n      Contract.Assert(other.CasePatterns == null && other.Arguments != null);\n      // In order to combine the two match cases, the bodies need to be a MatchExpr and\n      // the arguments and the source of the body are the same.\n      // We do string equals since they should be in the same scope.\n      if (one.Arguments.Count != other.Arguments.Count) {\n        return false;\n      }\n      if (!(one.Body is MatchExpr) || !(other.Body is MatchExpr)) {\n        return false;\n      }\n      var source1 = ((MatchExpr)one.Body).Source;\n      var source2 = ((MatchExpr)other.Body).Source;\n      if (!(source1 is NameSegment) || !(source2 is NameSegment)) {\n        return false;\n      }\n      if (!((NameSegment)source1).Name.Equals(((NameSegment)source2).Name)) {\n        return false;\n      }\n      for (int i = 0; i < one.Arguments.Count; i++) {\n        BoundVar bv1 = one.Arguments[i];\n        BoundVar bv2 = other.Arguments[i];\n        if (!LocalVariable.HasWildcardName(bv1) && !LocalVariable.HasWildcardName(bv2)) {\n          if (!bv1.Name.Equals(bv2.Name)) {\n            // need to substitute bv2 with bv1 in the matchstmt body\n            // what if match body already has the bv?? need to make a new bv\n            Type type = new InferredTypeProxy();\n            string name = FreshTempVarName(\"_mc#\", codeContext);\n            MatchCaseToken mcToken = new MatchCaseToken(one.tok);\n            BoundVar bv = new BoundVar(mcToken, name, type);\n            mcToken.AddVar(bv1.tok, bv1, true);\n            mcToken.AddVar(bv2.tok, bv2, true);\n            // substitute the appeareance of old bv with the new bv in the match case\n            SubstituteMatchCaseBoundVar(one, bv1, bv);\n            SubstituteMatchCaseBoundVar(other, bv2, bv);\n          }\n        }\n      }\n      return true;\n    }\n\n    void SubstituteMatchCaseBoundVar(MatchCaseExpr mc, BoundVar oldBv, BoundVar newBv) {\n      List<BoundVar> arguments = new List<BoundVar>();\n      for (int i = 0; i < mc.Arguments.Count; i++) {\n        BoundVar bv = mc.Arguments[i];\n        if (bv == oldBv) {\n          arguments.Add(newBv);\n        } else {\n          arguments.Add(bv);\n        }\n      }\n      mc.Arguments = arguments;\n\n      // substitue the oldBv with newBv in the body\n      MatchCaseExprSubstituteCloner cloner = new MatchCaseExprSubstituteCloner(oldBv, newBv);\n      Expression clone = cloner.CloneExpr(mc.Body);\n      mc.UpdateBody(clone);\n    }\n\n    void ResolveCasePattern<VT>(CasePattern<VT> pat, Type sourceType, ICodeContext context) where VT: IVariable {\n      Contract.Requires(pat != null);\n      Contract.Requires(sourceType != null);\n      Contract.Requires(context != null);\n\n      DatatypeDecl dtd = null;\n      UserDefinedType udt = null;\n      if (sourceType.IsDatatype) {\n        udt = (UserDefinedType)sourceType.NormalizeExpand();\n        dtd = (DatatypeDecl)udt.ResolvedClass;\n      }\n      // Find the constructor in the given datatype\n      // If what was parsed was just an identifier, we will interpret it as a datatype constructor, if possible\n      DatatypeCtor ctor = null;\n      if (dtd != null) {\n        if (pat.Var == null || (pat.Var != null && pat.Var.Type is TypeProxy)) {\n          if (datatypeCtors[dtd].TryGetValue(pat.Id, out ctor)) {\n            pat.Ctor = ctor;\n            pat.Var = default(VT);\n          }\n        }\n      }\n\n      if (pat.Var != null) {\n        // this is a simple resolution\n        var v = pat.Var;\n        ResolveType(v.Tok, v.Type, context, ResolveTypeOptionEnum.InferTypeProxies, null);\n        AddTypeDependencyEdges(context, v.Type);\n        // Note, the following type constraint checks that the RHS type can be assigned to the new variable on the left. In particular, it\n        // does not check that the entire RHS can be assigned to something of the type of the pattern on the left.  For example, consider\n        // a type declared as \"datatype Atom<T> = MakeAtom(T)\", where T is an invariant type argument.  Suppose the RHS has type Atom<nat>\n        // and that the LHS is the pattern MakeAtom(x: int).  This is okay, despite the fact that Atom<nat> is not assignable to Atom<int>.\n        // The reason is that the purpose of the pattern on the left is really just to provide a skeleton to introduce bound variables in.\n        AddAssignableConstraint(v.Tok, v.Type, sourceType, \"type of corresponding source/RHS ({1}) does not match type of bound variable ({0})\");\n        pat.AssembleExpr(null);\n        return;\n      }\n      if (dtd == null) {\n        // look up the name of the pattern's constructor\n        Tuple<DatatypeCtor, bool> pair;\n        if (moduleInfo.Ctors.TryGetValue(pat.Id, out pair) && !pair.Item2) {\n          ctor = pair.Item1;\n          pat.Ctor = ctor;\n          dtd = ctor.EnclosingDatatype;\n          var typeArgs = new List<Type>();\n          foreach (var xt in dtd.TypeArgs) {\n            typeArgs.Add(new InferredTypeProxy());\n          }\n          udt = new UserDefinedType(pat.tok, dtd.Name, dtd, typeArgs);\n          ConstrainSubtypeRelation(udt, sourceType, pat.tok, \"type of RHS ({0}) does not match type of bound variable '{1}'\", sourceType, pat.Id);\n        }\n      }\n      if (dtd == null && ctor == null) {\n        reporter.Error(MessageSource.Resolver, pat.tok, \"to use a pattern, the type of the source/RHS expression must be a datatype (instead found {0})\", sourceType);\n      } else if (ctor == null) {\n        reporter.Error(MessageSource.Resolver, pat.tok, \"constructor {0} does not exist in datatype {1}\", pat.Id, dtd.Name);\n      } else {\n        var argCount = pat.Arguments == null ? 0 : pat.Arguments.Count;\n        if (ctor.Formals.Count != argCount) {\n          reporter.Error(MessageSource.Resolver, pat.tok, \"pattern for constructor {0} has wrong number of formals (found {1}, expected {2})\", pat.Id, argCount, ctor.Formals.Count);\n        }\n        // build the type-parameter substitution map for this use of the datatype\n        Contract.Assert(dtd.TypeArgs.Count == udt.TypeArgs.Count);  // follows from the type previously having been successfully resolved\n        var subst = TypeSubstitutionMap(dtd.TypeArgs, udt.TypeArgs);\n        // recursively call ResolveCasePattern on each of the arguments\n        var j = 0;\n        if (pat.Arguments != null) {\n          foreach (var arg in pat.Arguments) {\n            if (j < ctor.Formals.Count) {\n              var formal = ctor.Formals[j];\n              Type st = SubstType(formal.Type, subst);\n              ResolveCasePattern(arg, st, context);\n            }\n            j++;\n          }\n        }\n        if (j == ctor.Formals.Count) {\n          pat.AssembleExpr(udt.TypeArgs);\n        }\n      }\n    }\n\n    /// <summary>\n    /// Look up expr.Name in the following order:\n    ///  0. Local variable, parameter, or bound variable.\n    ///     (Language design note:  If this clashes with something of interest, one can always rename the local variable locally.)\n    ///  1. Member of enclosing class (an implicit \"this\" is inserted, if needed)\n    ///  2. If isLastNameSegment:\n    ///     Unambiguous constructor name of a datatype in the enclosing module (if two constructors have the same name, an error message is produced here)\n    ///     (Language design note:  If the constructor name is ambiguous or if one of the steps above takes priority, one can qualify the constructor name with the name of the datatype)\n    ///  3. Member of the enclosing module (type name or the name of a module)\n    ///  4. Static function or method in the enclosing module or its imports\n    ///\n    /// </summary>\n    /// <param name=\"expr\"></param>\n    /// <param name=\"isLastNameSegment\">Indicates that the NameSegment is not directly enclosed in another NameSegment or ExprDotName expression.</param>\n    /// <param name=\"args\">If the NameSegment is enclosed in an ApplySuffix, then these are the arguments.  The method returns null to indicate\n    /// that these arguments, if any, were not used.  If args is non-null and the method does use them, the method returns the resolved expression\n    /// that incorporates these arguments.</param>\n    /// <param name=\"opts\"></param>\n    /// <param name=\"allowMethodCall\">If false, generates an error if the name denotes a method. If true and the name denotes a method, returns\n    /// a MemberSelectExpr whose .Member is a Method.</param>\n    Expression ResolveNameSegment(NameSegment expr, bool isLastNameSegment, List<Expression> args, ResolveOpts opts, bool allowMethodCall) {\n      Contract.Requires(expr != null);\n      Contract.Requires(!expr.WasResolved());\n      Contract.Requires(opts != null);\n      Contract.Ensures(Contract.Result<Expression>() == null || args != null);\n\n      if (expr.OptTypeArguments != null) {\n        foreach (var ty in expr.OptTypeArguments) {\n          ResolveType(expr.tok, ty, opts.codeContext, ResolveTypeOptionEnum.InferTypeProxies, null);\n        }\n      }\n\n      Expression r = null;  // the resolved expression, if successful\n      Expression rWithArgs = null;  // the resolved expression after incorporating \"args\"\n\n      // For 0:\n      IVariable v;\n      // For 1:\n      Dictionary<string, MemberDecl> members;\n      // For 1 and 4:\n      MemberDecl member = null;\n      // For 2:\n      Tuple<DatatypeCtor, bool> pair;\n      // For 3:\n      TopLevelDecl decl;\n\n      var name = opts.isReveal ? \"reveal_\" + expr.Name : expr.Name;\n      v = scope.Find(name);\n      if (v != null) {\n        // ----- 0. local variable, parameter, or bound variable\n        if (expr.OptTypeArguments != null) {\n          reporter.Error(MessageSource.Resolver, expr.tok, \"variable '{0}' does not take any type parameters\", name);\n        }\n        r = new IdentifierExpr(expr.tok, v);\n      } else if (currentClass is TopLevelDeclWithMembers cl && classMembers.TryGetValue(cl, out members) && members.TryGetValue(name, out member)) {\n        // ----- 1. member of the enclosing class\n        Expression receiver;\n        if (member.IsStatic) {\n          receiver = new StaticReceiverExpr(expr.tok, (TopLevelDeclWithMembers)member.EnclosingClass, true);\n        } else {\n          if (!scope.AllowInstance) {\n            reporter.Error(MessageSource.Resolver, expr.tok, \"'this' is not allowed in a 'static' context\"); //TODO: Rephrase this\n            // nevertheless, set \"receiver\" to a value so we can continue resolution\n          }\n          receiver = new ImplicitThisExpr(expr.tok);\n          receiver.Type = GetThisType(expr.tok, (TopLevelDeclWithMembers)member.EnclosingClass);  // resolve here\n        }\n        r = ResolveExprDotCall(expr.tok, receiver, null, member, args, expr.OptTypeArguments, opts, allowMethodCall);\n      } else if (isLastNameSegment && moduleInfo.Ctors.TryGetValue(name, out pair)) {\n        // ----- 2. datatype constructor\n        if (pair.Item2) {\n          // there is more than one constructor with this name\n          reporter.Error(MessageSource.Resolver, expr.tok, \"the name '{0}' denotes a datatype constructor, but does not do so uniquely; add an explicit qualification (for example, '{1}.{0}')\", expr.Name, pair.Item1.EnclosingDatatype.Name);\n        } else {\n          if (expr.OptTypeArguments != null) {\n            reporter.Error(MessageSource.Resolver, expr.tok, \"datatype constructor does not take any type parameters ('{0}')\", name);\n          }\n          var rr = new DatatypeValue(expr.tok, pair.Item1.EnclosingDatatype.Name, name, args ?? new List<Expression>());\n          ResolveDatatypeValue(opts, rr, pair.Item1.EnclosingDatatype, null);\n          if (args == null) {\n            r = rr;\n          } else {\n            r = rr;  // this doesn't really matter, since we're returning an \"rWithArgs\" (but if would have been proper to have returned the ctor as a lambda)\n            rWithArgs = rr;\n          }\n        }\n      } else if (moduleInfo.TopLevels.TryGetValue(name, out decl)) {\n        // ----- 3. Member of the enclosing module\n        if (decl is AmbiguousTopLevelDecl) {\n          var ad = (AmbiguousTopLevelDecl)decl;\n          reporter.Error(MessageSource.Resolver, expr.tok, \"The name {0} ambiguously refers to a type in one of the modules {1} (try qualifying the type name with the module name)\", expr.Name, ad.ModuleNames());\n        } else {\n          // We have found a module name or a type name, neither of which is an expression. However, the NameSegment we're\n          // looking at may be followed by a further suffix that makes this into an expresion. We postpone the rest of the\n          // resolution to any such suffix. For now, we create a temporary expression that will never be seen by the compiler\n          // or verifier, just to have a placeholder where we can recorded what we have found.\n          if (!isLastNameSegment) {\n            if (decl is ClassDecl && ((ClassDecl)decl).NonNullTypeDecl != null) {\n              // A possibly-null type C? was mentioned. But it does not have any further members. The program should have used\n              // the name of the class, C. Report an error and continue.\n              reporter.Error(MessageSource.Resolver, expr.tok, \"To access members of {0} '{1}', write '{1}', not '{2}'\", decl.WhatKind, decl.Name, name);\n            } else {\n              decl = decl.ViewAsClass;\n            }\n          }\n          r = CreateResolver_IdentifierExpr(expr.tok, name, expr.OptTypeArguments, decl);\n        }\n\n      } else if (moduleInfo.StaticMembers.TryGetValue(name, out member)) {\n        // ----- 4. static member of the enclosing module\n        Contract.Assert(member.IsStatic); // moduleInfo.StaticMembers is supposed to contain only static members of the module's implicit class _default\n        if (member is AmbiguousMemberDecl) {\n          var ambiguousMember = (AmbiguousMemberDecl)member;\n          reporter.Error(MessageSource.Resolver, expr.tok, \"The name {0} ambiguously refers to a static member in one of the modules {1} (try qualifying the member name with the module name)\", expr.Name, ambiguousMember.ModuleNames());\n        } else {\n          var receiver = new StaticReceiverExpr(expr.tok, (ClassDecl)member.EnclosingClass, true);\n          r = ResolveExprDotCall(expr.tok, receiver, null, member, args, expr.OptTypeArguments, opts, allowMethodCall);\n        }\n\n      } else {\n        // ----- None of the above\n        reporter.Error(MessageSource.Resolver, expr.tok, \"unresolved identifier: {0}\", name);\n      }\n\n      if (r == null) {\n        // an error has been reported above; we won't fill in .ResolvedExpression, but we still must fill in .Type\n        expr.Type = new InferredTypeProxy();\n      } else {\n        expr.ResolvedExpression = r;\n        expr.Type = r.Type;\n      }\n      return rWithArgs;\n    }\n\n    /// <summary>\n    /// Look up expr.Name in the following order:\n    ///  0. Type parameter\n    ///  1. Member of enclosing class (an implicit \"this\" is inserted, if needed)\n    ///  2. Member of the enclosing module (type name or the name of a module)\n    ///  3. Static function or method in the enclosing module or its imports\n    ///\n    /// Note: 1 and 3 are not used now, but they will be of interest when async task types are supported.\n    /// </summary>\n    void ResolveNameSegment_Type(NameSegment expr, ResolveOpts opts, ResolveTypeOption option, List<TypeParameter> defaultTypeArguments) {\n      Contract.Requires(expr != null);\n      Contract.Requires(!expr.WasResolved());\n      Contract.Requires(opts != null);\n      Contract.Requires((option.Opt == ResolveTypeOptionEnum.DontInfer || option.Opt == ResolveTypeOptionEnum.InferTypeProxies) == (defaultTypeArguments == null));\n\n      if (expr.OptTypeArguments != null) {\n        foreach (var ty in expr.OptTypeArguments) {\n          ResolveType(expr.tok, ty, opts.codeContext, option, defaultTypeArguments);\n        }\n      }\n\n      Expression r = null;  // the resolved expression, if successful\n\n      // For 0:\n      TypeParameter tp;\n#if ASYNC_TASK_TYPES\n      // For 1:\n      Dictionary<string, MemberDecl> members;\n      // For 1 and 3:\n      MemberDecl member = null;\n#endif\n      // For 2:\n      TopLevelDecl decl;\n\n      tp = allTypeParameters.Find(expr.Name);\n      if (tp != null) {\n        // ----- 0. type parameter\n        if (expr.OptTypeArguments == null) {\n          r = new Resolver_IdentifierExpr(expr.tok, tp);\n        } else {\n          reporter.Error(MessageSource.Resolver, expr.tok, \"Type parameter expects no type arguments: {0}\", expr.Name);\n        }\n#if ASYNC_TASK_TYPES  // At the moment, there is no way for a class member to part of a type name, but this changes with async task types\n      } else if (currentClass != null && classMembers.TryGetValue(currentClass, out members) && members.TryGetValue(expr.Name, out member)) {\n        // ----- 1. member of the enclosing class\n        Expression receiver;\n        if (member.IsStatic) {\n          receiver = new StaticReceiverExpr(expr.tok, (ClassDecl)member.EnclosingClass);\n        } else {\n          if (!scope.AllowInstance) {\n            reporter.Error(MessageSource.Resolver, expr.tok, \"'this' is not allowed in a 'static' context\");\n            // nevertheless, set \"receiver\" to a value so we can continue resolution\n          }\n          receiver = new ImplicitThisExpr(expr.tok);\n          receiver.Type = GetThisType(expr.tok, (ClassDecl)member.EnclosingClass);  // resolve here\n        }\n        r = ResolveExprDotCall(expr.tok, receiver, member, expr.OptTypeArguments, opts.codeContext, allowMethodCall);\n#endif\n      } else if (moduleInfo.TopLevels.TryGetValue(expr.Name, out decl)) {\n        // ----- 2. Member of the enclosing module\n        if (decl is AmbiguousTopLevelDecl) {\n          var ad = (AmbiguousTopLevelDecl)decl;\n          reporter.Error(MessageSource.Resolver, expr.tok, \"The name {0} ambiguously refers to a type in one of the modules {1} (try qualifying the type name with the module name)\", expr.Name, ad.ModuleNames());\n        } else {\n          // We have found a module name or a type name, neither of which is a type expression. However, the NameSegment we're\n          // looking at may be followed by a further suffix that makes this into a type expresion. We postpone the rest of the\n          // resolution to any such suffix. For now, we create a temporary expression that will never be seen by the compiler\n          // or verifier, just to have a placeholder where we can recorded what we have found.\n          r = CreateResolver_IdentifierExpr(expr.tok, expr.Name, expr.OptTypeArguments, decl);\n        }\n\n#if ASYNC_TASK_TYPES  // At the moment, there is no way for a class member to part of a type name, but this changes with async task types\n      } else if (moduleInfo.StaticMembers.TryGetValue(expr.Name, out member)) {\n        // ----- 3. static member of the enclosing module\n        Contract.Assert(member.IsStatic); // moduleInfo.StaticMembers is supposed to contain only static members of the module's implicit class _default\n        if (ReallyAmbiguousThing(ref member)) {\n          reporter.Error(MessageSource.Resolver, expr.tok, \"The name {0} ambiguously refers to a static member in one of the modules {1} (try qualifying the member name with the module name)\", expr.Name, ((AmbiguousMemberDecl)member).ModuleNames());\n        } else {\n          var receiver = new StaticReceiverExpr(expr.tok, (ClassDecl)member.EnclosingClass);\n          r = ResolveExprDotCall(expr.tok, receiver, member, expr.OptTypeArguments, opts.codeContext, allowMethodCall);\n        }\n#endif\n      } else {\n        // ----- None of the above\n        reporter.Error(MessageSource.Resolver, expr.tok, \"Undeclared top-level type or type parameter: {0} (did you forget to qualify a name or declare a module import 'opened?')\", expr.Name);\n      }\n\n      if (r == null) {\n        // an error has been reported above; we won't fill in .ResolvedExpression, but we still must fill in .Type\n        expr.Type = new InferredTypeProxy();\n      } else {\n        expr.ResolvedExpression = r;\n        expr.Type = r.Type;\n      }\n    }\n\n    Resolver_IdentifierExpr CreateResolver_IdentifierExpr(IToken tok, string name, List<Type> optTypeArguments, TopLevelDecl decl) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Contract.Requires(decl != null);\n      Contract.Ensures(Contract.Result<Resolver_IdentifierExpr>() != null);\n\n      if (!moduleInfo.IsAbstract) {\n        var md = decl as ModuleDecl;\n        if (md != null && md.Signature.IsAbstract) {\n          reporter.Error(MessageSource.Resolver, tok, \"a compiled module is not allowed to use an abstract module ({0})\", decl.Name);\n        }\n      }\n      var n = optTypeArguments == null ? 0 : optTypeArguments.Count;\n      if (optTypeArguments != null) {\n        // type arguments were supplied; they must be equal in number to those expected\n        if (n != decl.TypeArgs.Count) {\n          reporter.Error(MessageSource.Resolver, tok, \"Wrong number of type arguments ({0} instead of {1}) passed to {2}: {3}\", n, decl.TypeArgs.Count, decl.WhatKind, name);\n        }\n      }\n      List<Type> tpArgs = new List<Type>();\n      for (int i = 0; i < decl.TypeArgs.Count; i++) {\n        tpArgs.Add(i < n ? optTypeArguments[i] : new InferredTypeProxy());\n      }\n      return new Resolver_IdentifierExpr(tok, decl, tpArgs);\n    }\n\n    /// <summary>\n    /// To resolve \"id\" in expression \"E . id\", do:\n    ///  * If E denotes a module name M:\n    ///      0. If isLastNameSegment:\n    ///         Unambiguous constructor name of a datatype in module M (if two constructors have the same name, an error message is produced here)\n    ///         (Language design note:  If the constructor name is ambiguous or if one of the steps above takes priority, one can qualify the constructor name with the name of the datatype)\n    ///      1. Member of module M:  sub-module (including submodules of imports), class, datatype, etc.\n    ///         (if two imported types have the same name, an error message is produced here)\n    ///      2. Static function or method of M._default\n    ///    (Note that in contrast to ResolveNameSegment, imported modules, etc. are ignored)\n    ///  * If E denotes a type:\n    ///      3. Look up id as a member of that type\n    ///  * If E denotes an expression:\n    ///      4. Let T be the type of E.  Look up id in T.\n    /// </summary>\n    /// <param name=\"expr\"></param>\n    /// <param name=\"isLastNameSegment\">Indicates that the ExprDotName is not directly enclosed in another ExprDotName expression.</param>\n    /// <param name=\"args\">If the ExprDotName is enclosed in an ApplySuffix, then these are the arguments.  The method returns null to indicate\n    /// that these arguments, if any, were not used.  If args is non-null and the method does use them, the method returns the resolved expression\n    /// that incorporates these arguments.</param>\n    /// <param name=\"opts\"></param>\n    /// <param name=\"allowMethodCall\">If false, generates an error if the name denotes a method. If true and the name denotes a method, returns\n    /// a Resolver_MethodCall.</param>\n    Expression ResolveDotSuffix(ExprDotName expr, bool isLastNameSegment, List<Expression> args, ResolveOpts opts, bool allowMethodCall) {\n      Contract.Requires(expr != null);\n      Contract.Requires(!expr.WasResolved());\n      Contract.Requires(opts != null);\n      Contract.Ensures(Contract.Result<Expression>() == null || args != null);\n\n      // resolve the LHS expression\n      // LHS should not be reveal lemma\n      ResolveOpts nonRevealOpts = new ResolveOpts(opts.codeContext, opts.twoState, false, opts.isPostCondition, opts.InsideOld);\n      if (expr.Lhs is NameSegment) {\n        ResolveNameSegment((NameSegment)expr.Lhs, false, null, nonRevealOpts, false);\n      } else if (expr.Lhs is ExprDotName) {\n        ResolveDotSuffix((ExprDotName)expr.Lhs, false, null, nonRevealOpts, false);\n      } else {\n        ResolveExpression(expr.Lhs, nonRevealOpts);\n      }\n\n      if (expr.OptTypeArguments != null) {\n        foreach (var ty in expr.OptTypeArguments) {\n          ResolveType(expr.tok, ty, opts.codeContext, ResolveTypeOptionEnum.InferTypeProxies, null);\n        }\n      }\n\n      Expression r = null;  // the resolved expression, if successful\n      Expression rWithArgs = null;  // the resolved expression after incorporating \"args\"\n      MemberDecl member = null;\n\n      var name = opts.isReveal ? \"reveal_\" + expr.SuffixName : expr.SuffixName;\n      var lhs = expr.Lhs.Resolved;\n      if (lhs != null && lhs.Type is Resolver_IdentifierExpr.ResolverType_Module) {\n        var ri = (Resolver_IdentifierExpr)lhs;\n        var sig = ((ModuleDecl)ri.Decl).AccessibleSignature(useCompileSignatures);\n        sig = GetSignature(sig);\n        // For 0:\n        Tuple<DatatypeCtor, bool> pair;\n        // For 1:\n        TopLevelDecl decl;\n\n        if (isLastNameSegment && sig.Ctors.TryGetValue(name, out pair)) {\n          // ----- 0. datatype constructor\n          if (pair.Item2) {\n            // there is more than one constructor with this name\n            reporter.Error(MessageSource.Resolver, expr.tok, \"the name '{0}' denotes a datatype constructor in module {2}, but does not do so uniquely; add an explicit qualification (for example, '{1}.{0}')\", name, pair.Item1.EnclosingDatatype.Name, ((ModuleDecl)ri.Decl).Name);\n          } else {\n            if (expr.OptTypeArguments != null) {\n              reporter.Error(MessageSource.Resolver, expr.tok, \"datatype constructor does not take any type parameters ('{0}')\", name);\n            }\n            var rr = new DatatypeValue(expr.tok, pair.Item1.EnclosingDatatype.Name, name, args ?? new List<Expression>());\n            ResolveDatatypeValue(opts, rr, pair.Item1.EnclosingDatatype, null);\n\n            if (args == null) {\n              r = rr;\n            } else {\n              r = rr;  // this doesn't really matter, since we're returning an \"rWithArgs\" (but if would have been proper to have returned the ctor as a lambda)\n              rWithArgs = rr;\n            }\n          }\n        } else if (sig.TopLevels.TryGetValue(name, out decl)) {\n          // ----- 1. Member of the specified module\n          if (decl is AmbiguousTopLevelDecl) {\n            var ad = (AmbiguousTopLevelDecl)decl;\n            reporter.Error(MessageSource.Resolver, expr.tok, \"The name {0} ambiguously refers to a type in one of the modules {1} (try qualifying the type name with the module name)\", expr.SuffixName, ad.ModuleNames());\n          } else {\n            // We have found a module name or a type name, neither of which is an expression. However, the ExprDotName we're\n            // looking at may be followed by a further suffix that makes this into an expresion. We postpone the rest of the\n            // resolution to any such suffix. For now, we create a temporary expression that will never be seen by the compiler\n            // or verifier, just to have a placeholder where we can recorded what we have found.\n            if (!isLastNameSegment) {\n              if (decl is ClassDecl && ((ClassDecl)decl).NonNullTypeDecl != null) {\n                // A possibly-null type C? was mentioned. But it does not have any further members. The program should have used\n                // the name of the class, C. Report an error and continue.\n                reporter.Error(MessageSource.Resolver, expr.tok, \"To access members of {0} '{1}', write '{1}', not '{2}'\", decl.WhatKind, decl.Name, name);\n              } else {\n                decl = decl.ViewAsClass;\n              }\n            }\n            r = CreateResolver_IdentifierExpr(expr.tok, name, expr.OptTypeArguments, decl);\n          }\n        } else if (sig.StaticMembers.TryGetValue(name, out member)) {\n          // ----- 2. static member of the specified module\n          Contract.Assert(member.IsStatic); // moduleInfo.StaticMembers is supposed to contain only static members of the module's implicit class _default\n          if (member is AmbiguousMemberDecl) {\n            var ambiguousMember = (AmbiguousMemberDecl)member;\n            reporter.Error(MessageSource.Resolver, expr.tok, \"The name {0} ambiguously refers to a static member in one of the modules {1} (try qualifying the member name with the module name)\", expr.SuffixName, ambiguousMember.ModuleNames());\n          } else {\n            var receiver = new StaticReceiverExpr(expr.tok, (ClassDecl)member.EnclosingClass, true);\n            r = ResolveExprDotCall(expr.tok, receiver, null, member, args, expr.OptTypeArguments, opts, allowMethodCall);\n          }\n        } else {\n          reporter.Error(MessageSource.Resolver, expr.tok, \"unresolved identifier: {0}\", name);\n        }\n\n      } else if (lhs != null && lhs.Type is Resolver_IdentifierExpr.ResolverType_Type) {\n        var ri = (Resolver_IdentifierExpr)lhs;\n        // ----- 3. Look up name in type\n        Type ty;\n        if (ri.TypeParamDecl != null) {\n          ty = new UserDefinedType(ri.TypeParamDecl);\n        } else {\n          // expand any synonyms\n          ty = new UserDefinedType(expr.tok, ri.Decl.Name, ri.Decl, ri.TypeArgs).NormalizeExpand();\n        }\n        if (ty.IsDatatype) {\n          // ----- LHS is a datatype\n          var dt = ty.AsDatatype;\n          Dictionary<string, DatatypeCtor> members;\n          DatatypeCtor ctor;\n          if (datatypeCtors.TryGetValue(dt, out members) && members.TryGetValue(name, out ctor)) {\n            if (expr.OptTypeArguments != null) {\n              reporter.Error(MessageSource.Resolver, expr.tok, \"datatype constructor does not take any type parameters ('{0}')\", name);\n            }\n            var rr = new DatatypeValue(expr.tok, ctor.EnclosingDatatype.Name, name, args ?? new List<Expression>());\n            ResolveDatatypeValue(opts, rr, ctor.EnclosingDatatype, ty);\n            if (args == null) {\n              r = rr;\n            } else {\n              r = rr;  // this doesn't really matter, since we're returning an \"rWithArgs\" (but if would have been proper to have returned the ctor as a lambda)\n              rWithArgs = rr;\n            }\n          }\n        }\n        if (r == null && ty.IsTopLevelTypeWithMembers) {\n          // ----- LHS is a class\n          var cd = (TopLevelDeclWithMembers)((UserDefinedType)ty).ResolvedClass;\n          Dictionary<string, MemberDecl> members;\n          if (classMembers.TryGetValue(cd, out members) && members.TryGetValue(name, out member)) {\n            if (!VisibleInScope(member)) {\n              reporter.Error(MessageSource.Resolver, expr.tok, \"member '{0}' has not been imported in this scope and cannot be accessed here\", name);\n            }\n            if (!member.IsStatic) {\n              reporter.Error(MessageSource.Resolver, expr.tok, \"accessing member '{0}' requires an instance expression\", name); //TODO Unify with similar error messages\n              // nevertheless, continue creating an expression that approximates a correct one\n            }\n            var receiver = new StaticReceiverExpr(expr.tok, (UserDefinedType)ty.NormalizeExpand(), (TopLevelDeclWithMembers)member.EnclosingClass, false);\n            r = ResolveExprDotCall(expr.tok, receiver, null, member, args, expr.OptTypeArguments, opts, allowMethodCall);\n          }\n        }\n        if (r == null) {\n          reporter.Error(MessageSource.Resolver, expr.tok, \"member '{0}' does not exist in type '{1}'\", name, ri.TypeParamDecl != null ? ri.TypeParamDecl.Name : ri.Decl.Name);\n        }\n      } else if (lhs != null) {\n        // ----- 4. Look up name in the type of the Lhs\n        NonProxyType nptype;\n        member = ResolveMember(expr.tok, expr.Lhs.Type, name, out nptype);\n        if (member != null) {\n          Expression receiver;\n          if (!member.IsStatic) {\n            receiver = expr.Lhs;\n          } else {\n            receiver = new StaticReceiverExpr(expr.tok, (UserDefinedType)nptype, (TopLevelDeclWithMembers)member.EnclosingClass, false);\n          }\n          r = ResolveExprDotCall(expr.tok, receiver, nptype, member, args, expr.OptTypeArguments, opts, allowMethodCall);\n        }\n      }\n\n      if (r == null) {\n        // an error has been reported above; we won't fill in .ResolvedExpression, but we still must fill in .Type\n        expr.Type = new InferredTypeProxy();\n      } else {\n        expr.ResolvedExpression = r;\n        expr.Type = r.Type;\n      }\n      return rWithArgs;\n    }\n\n    /// <summary>\n    /// To resolve \"id\" in expression \"E . id\", do:\n    ///  * If E denotes a module name M:\n    ///      0. Member of module M:  sub-module (including submodules of imports), class, datatype, etc.\n    ///         (if two imported types have the same name, an error message is produced here)\n    ///      1. Static member of M._default denoting an async task type\n    ///    (Note that in contrast to ResolveNameSegment_Type, imported modules, etc. are ignored)\n    ///  * If E denotes a type:\n    ///      2. a. Member of that type denoting an async task type, or:\n    ///         b. If allowDanglingDotName:\n    ///            Return the type \"E\" and the given \"expr\", letting the caller try to make sense of the final dot-name.\n    ///\n    /// Note: 1 and 2a are not used now, but they will be of interest when async task types are supported.\n    /// </summary>\n    ResolveTypeReturn ResolveDotSuffix_Type(ExprDotName expr, ResolveOpts opts, bool allowDanglingDotName, ResolveTypeOption option, List<TypeParameter> defaultTypeArguments) {\n      Contract.Requires(expr != null);\n      Contract.Requires(!expr.WasResolved());\n      Contract.Requires(expr.Lhs is NameSegment || expr.Lhs is ExprDotName);\n      Contract.Requires(opts != null);\n      Contract.Ensures(Contract.Result<ResolveTypeReturn>() == null || allowDanglingDotName);\n\n      // resolve the LHS expression\n      if (expr.Lhs is NameSegment) {\n        ResolveNameSegment_Type((NameSegment)expr.Lhs, opts, option, defaultTypeArguments);\n      } else {\n        ResolveDotSuffix_Type((ExprDotName)expr.Lhs, opts, false, option, defaultTypeArguments);\n      }\n\n      if (expr.OptTypeArguments != null) {\n        foreach (var ty in expr.OptTypeArguments) {\n          ResolveType(expr.tok, ty, opts.codeContext, option, defaultTypeArguments);\n        }\n      }\n\n      Expression r = null;  // the resolved expression, if successful\n\n      var lhs = expr.Lhs.Resolved;\n      if (lhs != null && lhs.Type is Resolver_IdentifierExpr.ResolverType_Module) {\n        var ri = (Resolver_IdentifierExpr)lhs;\n        var sig = ((ModuleDecl)ri.Decl).AccessibleSignature(useCompileSignatures);\n        sig = GetSignature(sig);\n        // For 0:\n        TopLevelDecl decl;\n\n        if (sig.TopLevels.TryGetValue(expr.SuffixName, out decl)) {\n          // ----- 0. Member of the specified module\n          if (decl is AmbiguousTopLevelDecl) {\n            var ad = (AmbiguousTopLevelDecl)decl;\n            reporter.Error(MessageSource.Resolver, expr.tok, \"The name {0} ambiguously refers to a type in one of the modules {1} (try qualifying the type name with the module name)\", expr.SuffixName, ad.ModuleNames());\n          } else {\n            // We have found a module name or a type name.  We create a temporary expression that will never be seen by the compiler\n            // or verifier, just to have a placeholder where we can recorded what we have found.\n            r = CreateResolver_IdentifierExpr(expr.tok, expr.SuffixName, expr.OptTypeArguments, decl);\n          }\n#if ASYNC_TASK_TYPES\n        } else if (sig.StaticMembers.TryGetValue(expr.SuffixName, out member)) {\n          // ----- 1. static member of the specified module\n          Contract.Assert(member.IsStatic); // moduleInfo.StaticMembers is supposed to contain only static members of the module's implicit class _default\n          if (ReallyAmbiguousThing(ref member)) {\n            reporter.Error(MessageSource.Resolver, expr.tok, \"The name {0} ambiguously refers to a static member in one of the modules {1} (try qualifying the member name with the module name)\", expr.SuffixName, ((AmbiguousMemberDecl)member).ModuleNames());\n          } else {\n            var receiver = new StaticReceiverExpr(expr.tok, (ClassDecl)member.EnclosingClass);\n            r = ResolveExprDotCall(expr.tok, receiver, member, expr.OptTypeArguments, opts.codeContext, allowMethodCall);\n          }\n#endif\n        } else {\n          reporter.Error(MessageSource.Resolver, expr.tok, \"module '{0}' does not declare a type '{1}'\", ri.Decl.Name, expr.SuffixName);\n        }\n\n      } else if (lhs != null && lhs.Type is Resolver_IdentifierExpr.ResolverType_Type) {\n        var ri = (Resolver_IdentifierExpr)lhs;\n        // ----- 2. Look up name in type\n        Type ty;\n        if (ri.TypeParamDecl != null) {\n          ty = new UserDefinedType(ri.TypeParamDecl);\n        } else {\n          ty = new UserDefinedType(expr.tok, ri.Decl.Name, ri.Decl, ri.TypeArgs);\n        }\n        if (allowDanglingDotName && ty.IsRefType) {\n          return new ResolveTypeReturn(ty, expr);\n        }\n        if (r == null) {\n          reporter.Error(MessageSource.Resolver, expr.tok, \"member '{0}' does not exist in type '{1}' or cannot be part of type name\", expr.SuffixName, ri.TypeParamDecl != null ? ri.TypeParamDecl.Name : ri.Decl.Name);\n        }\n      }\n\n      if (r == null) {\n        // an error has been reported above; we won't fill in .ResolvedExpression, but we still must fill in .Type\n        expr.Type = new InferredTypeProxy();\n      } else {\n        expr.ResolvedExpression = r;\n        expr.Type = r.Type;\n      }\n      return null;\n    }\n\n    Expression ResolveExprDotCall(IToken tok, Expression receiver, Type receiverTypeBound/*?*/, MemberDecl member, List<Expression> args, List<Type> optTypeArguments, ResolveOpts opts, bool allowMethodCall) {\n      Contract.Requires(tok != null);\n      Contract.Requires(receiver != null);\n      Contract.Requires(receiver.WasResolved());\n      Contract.Requires(member != null);\n      Contract.Requires(opts != null && opts.codeContext != null);\n\n      var rr = new MemberSelectExpr(tok, receiver, member.Name);\n      rr.Member = member;\n\n      // Now, fill in rr.Type.  This requires taking into consideration the type parameters passed to the receiver's type as well as any type\n      // parameters used in this NameSegment/ExprDotName.\n      // Add to \"subst\" the type parameters given to the member's class/datatype\n      rr.TypeApplication = new List<Type>();\n      Dictionary<TypeParameter, Type> subst;\n      var rType = (receiverTypeBound ?? receiver.Type).NormalizeExpand();\n      if (rType is UserDefinedType udt && udt.ResolvedClass != null) {\n        subst = TypeSubstitutionMap(udt.ResolvedClass.TypeArgs, udt.TypeArgs);\n        rr.TypeApplication.AddRange(udt.TypeArgs);\n      } else {\n        var vtd = AsValuetypeDecl(rType);\n        if (vtd != null) {\n          Contract.Assert(vtd.TypeArgs.Count == rType.TypeArgs.Count);\n          subst = TypeSubstitutionMap(vtd.TypeArgs, rType.TypeArgs);\n          rr.TypeApplication.AddRange(rType.TypeArgs);\n        } else {\n          Contract.Assert(rType.TypeArgs.Count == 0);\n          subst = new Dictionary<TypeParameter, Type>();\n        }\n      }\n\n      if (member is Field) {\n        var field = (Field)member;\n        if (optTypeArguments != null) {\n          reporter.Error(MessageSource.Resolver, tok, \"a field ({0}) does not take any type arguments (got {1})\", field.Name, optTypeArguments.Count);\n        }\n        subst = BuildTypeArgumentSubstitute(subst);\n        rr.Type = SubstType(field.Type, subst);\n        AddCallGraphEdgeForField(opts.codeContext, field, rr);\n      } else if (member is Function) {\n        var fn = (Function)member;\n        if (fn is TwoStateFunction && !opts.twoState) {\n          reporter.Error(MessageSource.Resolver, tok, \"two-state function ('{0}') can only be called in a two-state context\", member.Name);\n        }\n        int suppliedTypeArguments = optTypeArguments == null ? 0 : optTypeArguments.Count;\n        if (optTypeArguments != null && suppliedTypeArguments != fn.TypeArgs.Count) {\n          reporter.Error(MessageSource.Resolver, tok, \"function '{0}' expects {1} type arguments (got {2})\", member.Name, fn.TypeArgs.Count, suppliedTypeArguments);\n        }\n        for (int i = 0; i < fn.TypeArgs.Count; i++) {\n          var ta = i < suppliedTypeArguments ? optTypeArguments[i] : new InferredTypeProxy();\n          rr.TypeApplication.Add(ta);\n          subst.Add(fn.TypeArgs[i], ta);\n        }\n        subst = BuildTypeArgumentSubstitute(subst);\n        rr.Type = SelectAppropriateArrowType(fn.tok,\n          fn.Formals.ConvertAll(f => SubstType(f.Type, subst)),\n          SubstType(fn.ResultType, subst),\n          fn.Reads.Count != 0, fn.Req.Count != 0);\n        AddCallGraphEdge(opts.codeContext, fn, rr, IsFunctionReturnValue(fn, args, opts));\n      } else {\n        // the member is a method\n        var m = (Method)member;\n        if (!allowMethodCall) {\n          // it's a method and method calls are not allowed in the given context\n          reporter.Error(MessageSource.Resolver, tok, \"expression is not allowed to invoke a method ({0})\", member.Name);\n        }\n        int suppliedTypeArguments = optTypeArguments == null ? 0 : optTypeArguments.Count;\n        if (optTypeArguments != null && suppliedTypeArguments != m.TypeArgs.Count) {\n          reporter.Error(MessageSource.Resolver, tok, \"method '{0}' expects {1} type arguments (got {2})\", member.Name, m.TypeArgs.Count, suppliedTypeArguments);\n        }\n        for (int i = 0; i < m.TypeArgs.Count; i++) {\n          var ta = i < suppliedTypeArguments ? optTypeArguments[i] : new InferredTypeProxy();\n          rr.TypeApplication.Add(ta);\n        }\n        rr.Type = new InferredTypeProxy();  // fill in this field, in order to make \"rr\" resolved\n      }\n      return rr;\n    }\n\n    private bool IsFunctionReturnValue(Function fn, List<Expression> args, ResolveOpts opts) {\n      bool isFunctionReturnValue = true;\n      // if the call is in post-condition and it is calling itself, and the arguments matches\n      // formal parameter, then it denotes function return value.\n      if (args != null && opts.isPostCondition && opts.codeContext == fn) {\n        foreach (var arg in args) {\n          if (arg is NameSegment) {\n            var name = ((NameSegment)arg).Name;\n            IVariable v = scope.Find(name);\n            if (!(v is Formal)) {\n              isFunctionReturnValue = false;\n            }\n          } else {\n            isFunctionReturnValue = false;\n          }\n        }\n      } else {\n        isFunctionReturnValue = false;\n      }\n      return isFunctionReturnValue;\n    }\n\n    class MethodCallInformation\n    {\n      public readonly IToken Tok;\n      public readonly MemberSelectExpr Callee;\n      public readonly List<Expression> Args;\n\n      [ContractInvariantMethod]\n      void ObjectInvariant() {\n        Contract.Invariant(Tok != null);\n        Contract.Invariant(Callee != null);\n        Contract.Invariant(Callee.Member is Method);\n        Contract.Invariant(cce.NonNullElements(Args));\n      }\n\n      public MethodCallInformation(IToken tok, MemberSelectExpr callee, List<Expression> args) {\n        Contract.Requires(tok != null);\n        Contract.Requires(callee != null);\n        Contract.Requires(callee.Member is Method);\n        Contract.Requires(cce.NonNullElements(args));\n        this.Tok = tok;\n        this.Callee = callee;\n        this.Args = args;\n      }\n    }\n\n    MethodCallInformation ResolveRevealExpr(RevealExpr e, ResolveOpts opts, bool allowMethodCall) {\n      var revealOpts = new ResolveOpts(opts.codeContext, opts.twoState, true, opts.isPostCondition, opts.InsideOld);\n      MethodCallInformation info = null;\n      if (e.Expr is ApplySuffix) {\n        info = ResolveApplySuffix((ApplySuffix)e.Expr, revealOpts, true);\n      } else {\n        ResolveExpression(e.Expr, revealOpts);\n      }\n      return info;\n    }\n\n    MethodCallInformation ResolveApplySuffix(ApplySuffix e, ResolveOpts opts, bool allowMethodCall) {\n      Contract.Requires(e != null);\n      Contract.Requires(opts != null);\n      Contract.Ensures(Contract.Result<MethodCallInformation>() == null || allowMethodCall);\n      Expression r = null;  // upon success, the expression to which the ApplySuffix resolves\n      var errorCount = reporter.Count(ErrorLevel.Error);\n      if (e.Lhs is NameSegment) {\n        r = ResolveNameSegment((NameSegment)e.Lhs, true, e.Args, opts, allowMethodCall);\n        // note, if r is non-null, then e.Args have been resolved and r is a resolved expression that incorporates e.Args\n      } else if (e.Lhs is ExprDotName) {\n        r = ResolveDotSuffix((ExprDotName)e.Lhs, true, e.Args, opts, allowMethodCall);\n        // note, if r is non-null, then e.Args have been resolved and r is a resolved expression that incorporates e.Args\n      } else {\n        ResolveExpression(e.Lhs, opts);\n      }\n      if (r == null) {\n        foreach (var arg in e.Args) {\n          ResolveExpression(arg, opts);\n        }\n        var improvedType = PartiallyResolveTypeForMemberSelection(e.Lhs.tok, e.Lhs.Type, \"_#apply\");\n        var fnType = improvedType.AsArrowType;\n        if (fnType == null) {\n          var lhs = e.Lhs.Resolved;\n          if (lhs != null && lhs.Type is Resolver_IdentifierExpr.ResolverType_Module) {\n            reporter.Error(MessageSource.Resolver, e.tok, \"name of module ({0}) is used as a function\", ((Resolver_IdentifierExpr)lhs).Decl.Name);\n          } else if (lhs != null && lhs.Type is Resolver_IdentifierExpr.ResolverType_Type) {\n            // It may be a conversion expression\n            var ri = (Resolver_IdentifierExpr)lhs;\n            if (ri.TypeParamDecl != null) {\n              reporter.Error(MessageSource.Resolver, e.tok, \"name of type parameter ({0}) is used as a function\", ri.TypeParamDecl.Name);\n            } else {\n              var decl = ri.Decl;\n              var ty = new UserDefinedType(e.tok, decl.Name, decl, ri.TypeArgs);\n              if (ty.AsNewtype != null) {\n                reporter.Deprecated(MessageSource.Resolver, e.tok, \"the syntax \\\"{0}(expr)\\\" for type conversions has been deprecated; the new syntax is \\\"expr as {0}\\\"\", decl.Name);\n                if (e.Args.Count != 1) {\n                  reporter.Error(MessageSource.Resolver, e.tok, \"conversion operation to {0} got wrong number of arguments (expected 1, got {1})\", decl.Name, e.Args.Count);\n                }\n                var conversionArg = 1 <= e.Args.Count ? e.Args[0] :\n                  ty.IsNumericBased(Type.NumericPersuation.Int) ? LiteralExpr.CreateIntLiteral(e.tok, 0) :\n                  LiteralExpr.CreateRealLiteral(e.tok, BaseTypes.BigDec.ZERO);\n                r = new ConversionExpr(e.tok, conversionArg, ty);\n                ResolveExpression(r, opts);\n                // resolve the rest of the arguments, if any\n                for (int i = 1; i < e.Args.Count; i++) {\n                  ResolveExpression(e.Args[i], opts);\n                }\n              } else {\n                reporter.Error(MessageSource.Resolver, e.tok, \"name of type ({0}) is used as a function\", decl.Name);\n              }\n            }\n          } else {\n            if (lhs is MemberSelectExpr && ((MemberSelectExpr)lhs).Member is Method) {\n              var mse = (MemberSelectExpr)lhs;\n              if (allowMethodCall) {\n                var cRhs = new MethodCallInformation(e.tok, mse, e.Args);\n                return cRhs;\n              } else {\n                reporter.Error(MessageSource.Resolver, e.tok, \"method call is not allowed to be used in an expression context ({0})\", mse.Member.Name);\n              }\n            } else if (lhs != null) {  // if e.Lhs.Resolved is null, then e.Lhs was not successfully resolved and an error has already been reported\n              reporter.Error(MessageSource.Resolver, e.tok, \"non-function expression (of type {0}) is called with parameters\", e.Lhs.Type);\n            }\n          }\n        } else {\n          var mse = e.Lhs is NameSegment || e.Lhs is ExprDotName ? e.Lhs.Resolved as MemberSelectExpr : null;\n          var callee = mse == null ? null : mse.Member as Function;\n          if (fnType.Arity != e.Args.Count) {\n            var what = callee != null ? string.Format(\"function '{0}'\", callee.Name) : string.Format(\"function type '{0}'\", fnType);\n            reporter.Error(MessageSource.Resolver, e.tok, \"wrong number of arguments to function application ({0} expects {1}, got {2})\", what, fnType.Arity, e.Args.Count);\n          } else {\n            for (var i = 0; i < fnType.Arity; i++) {\n              AddAssignableConstraint(e.Args[i].tok, fnType.Args[i], e.Args[i].Type, \"type mismatch for argument\" + (fnType.Arity == 1 ? \"\" : \" \" + i) + \" (function expects {0}, got {1})\");\n            }\n            if (errorCount != reporter.Count(ErrorLevel.Error)) {\n              // do nothing else; error has been reported\n            } else if (callee != null) {\n              // produce a FunctionCallExpr instead of an ApplyExpr(MemberSelectExpr)\n              var rr = new FunctionCallExpr(e.Lhs.tok, callee.Name, mse.Obj, e.tok, e.Args);\n              // resolve it here:\n              rr.Function = callee;\n              Contract.Assert(!(mse.Obj is StaticReceiverExpr) || callee.IsStatic);  // this should have been checked already\n              Contract.Assert(callee.Formals.Count == rr.Args.Count);  // this should have been checked already\n              // build the type substitution map\n              rr.TypeArgumentSubstitutions = new Dictionary<TypeParameter, Type>();\n              int enclosingTypeArgsCount = callee.EnclosingClass == null ? 0 : callee.EnclosingClass.TypeArgs.Count;\n              Contract.Assert(mse.TypeApplication.Count == enclosingTypeArgsCount + callee.TypeArgs.Count);\n              for (int i = 0; i < enclosingTypeArgsCount; i++) {\n                rr.TypeArgumentSubstitutions.Add(callee.EnclosingClass.TypeArgs[i], mse.TypeApplication[i]);\n              }\n\n              for (int i = 0; i < callee.TypeArgs.Count; i++) {\n                rr.TypeArgumentSubstitutions.Add(callee.TypeArgs[i], mse.TypeApplication[enclosingTypeArgsCount + i]);\n              }\n              Dictionary<TypeParameter, Type> subst = BuildTypeArgumentSubstitute(rr.TypeArgumentSubstitutions);\n\n              // type check the arguments\n#if DEBUG\n              Contract.Assert(callee.Formals.Count == fnType.Arity);\n              for (int i = 0; i < callee.Formals.Count; i++) {\n                Expression farg = rr.Args[i];\n                Contract.Assert(farg.WasResolved());\n                Contract.Assert(farg.Type != null);\n                Type s = SubstType(callee.Formals[i].Type, subst);\n                Contract.Assert(s.Equals(fnType.Args[i]));\n                Contract.Assert(farg.Type.Equals(e.Args[i].Type));\n              }\n#endif\n              rr.Type = SubstType(callee.ResultType, subst);\n              // further bookkeeping\n              if (callee is FixpointPredicate) {\n                ((FixpointPredicate)callee).Uses.Add(rr);\n              }\n              AddCallGraphEdge(opts.codeContext, callee, rr, IsFunctionReturnValue(callee, e.Args, opts));\n              r = rr;\n            } else {\n              r = new ApplyExpr(e.Lhs.tok, e.Lhs, e.Args);\n              r.Type = fnType.Result;\n            }\n          }\n        }\n      }\n      if (r == null) {\n        // an error has been reported above; we won't fill in .ResolvedExpression, but we still must fill in .Type\n        e.Type = new InferredTypeProxy();\n      } else {\n        e.ResolvedExpression = r;\n        e.Type = r.Type;\n      }\n      return null;\n    }\n\n    private Dictionary<TypeParameter, Type> BuildTypeArgumentSubstitute(Dictionary<TypeParameter, Type> typeArgumentSubstitutions) {\n      Contract.Requires(typeArgumentSubstitutions != null);\n\n      Dictionary<TypeParameter, Type> subst = new Dictionary<TypeParameter, Type>();\n      foreach (var entry in typeArgumentSubstitutions) {\n        subst.Add(entry.Key, entry.Value);\n      }\n\n      if (SelfTypeSubstitution != null) {\n        foreach (var entry in SelfTypeSubstitution) {\n          subst.Add(entry.Key, entry.Value);\n        }\n      }\n      return subst;\n    }\n\n    private void ResolveDatatypeValue(ResolveOpts opts, DatatypeValue dtv, DatatypeDecl dt, Type ty) {\n      Contract.Requires(opts != null);\n      Contract.Requires(dtv != null);\n      Contract.Requires(dt != null);\n      Contract.Requires(ty == null || (ty.AsDatatype == dt && ty.TypeArgs.Count == dt.TypeArgs.Count));\n\n      var gt = new List<Type>(dt.TypeArgs.Count);\n      var subst = new Dictionary<TypeParameter, Type>();\n      for (int i = 0; i < dt.TypeArgs.Count; i++) {\n        Type t = ty == null ? new InferredTypeProxy() : ty.TypeArgs[i];\n        gt.Add(t);\n        dtv.InferredTypeArgs.Add(t);\n        subst.Add(dt.TypeArgs[i], t);\n      }\n      // Construct a resolved type directly, as we know the declaration is dt.\n      dtv.Type = new UserDefinedType(dtv.tok, dt.Name, dt, gt);\n\n      DatatypeCtor ctor;\n      if (!datatypeCtors[dt].TryGetValue(dtv.MemberName, out ctor)) {\n        reporter.Error(MessageSource.Resolver, dtv.tok, \"undeclared constructor {0} in datatype {1}\", dtv.MemberName, dtv.DatatypeName);\n      } else {\n        Contract.Assert(ctor != null);  // follows from postcondition of TryGetValue\n        dtv.Ctor = ctor;\n        if (ctor.Formals.Count != dtv.Arguments.Count) {\n          reporter.Error(MessageSource.Resolver, dtv.tok, \"wrong number of arguments to datatype constructor {0} (found {1}, expected {2})\", ctor.Name, dtv.Arguments.Count, ctor.Formals.Count);\n        }\n      }\n      int j = 0;\n      foreach (var arg in dtv.Arguments) {\n        Formal formal = ctor != null && j < ctor.Formals.Count ? ctor.Formals[j] : null;\n        ResolveExpression(arg, opts);\n        Contract.Assert(arg.Type != null);  // follows from postcondition of ResolveExpression\n        if (formal != null) {\n          Type st = SubstType(formal.Type, subst);\n          AddAssignableConstraint(arg.tok, st, arg.Type, \"incorrect type of datatype constructor argument (found {1}, expected {0})\");\n        }\n        j++;\n      }\n    }\n\n    /// <summary>\n    /// Generate an error for every non-ghost feature used in \"expr\".\n    /// Requires \"expr\" to have been successfully resolved.\n    /// </summary>\n    void CheckIsCompilable(Expression expr) {\n      Contract.Requires(expr != null);\n      Contract.Requires(expr.WasResolved());  // this check approximates the requirement that \"expr\" be resolved\n\n      if (expr is IdentifierExpr) {\n        var e = (IdentifierExpr)expr;\n        if (e.Var != null && e.Var.IsGhost) {\n          reporter.Error(MessageSource.Resolver, expr, \"ghost variables are allowed only in specification contexts\");\n          return;\n        }\n\n      } else if (expr is MemberSelectExpr) {\n        var e = (MemberSelectExpr)expr;\n        if (e.Member != null && e.Member.IsGhost) {\n          reporter.Error(MessageSource.Resolver, expr, \"ghost fields are allowed only in specification contexts\");\n          return;\n        }\n\n      } else if (expr is FunctionCallExpr) {\n        var e = (FunctionCallExpr)expr;\n        if (e.Function != null) {\n          if (e.Function.IsGhost) {\n            reporter.Error(MessageSource.Resolver, expr, \"function calls are allowed only in specification contexts (consider declaring the function a 'function method')\");\n            return;\n          }\n          // function is okay, so check all NON-ghost arguments\n          CheckIsCompilable(e.Receiver);\n          for (int i = 0; i < e.Function.Formals.Count; i++) {\n            if (!e.Function.Formals[i].IsGhost) {\n              CheckIsCompilable(e.Args[i]);\n            }\n          }\n        }\n        return;\n\n      } else if (expr is DatatypeValue) {\n        var e = (DatatypeValue)expr;\n        // check all NON-ghost arguments\n        // note that if resolution is successful, then |e.Arguments| == |e.Ctor.Formals|\n        for (int i = 0; i < e.Arguments.Count; i++) {\n          if (!e.Ctor.Formals[i].IsGhost) {\n            CheckIsCompilable(e.Arguments[i]);\n          }\n        }\n        return;\n\n      } else if (expr is OldExpr) {\n        reporter.Error(MessageSource.Resolver, expr, \"old expressions are allowed only in specification and ghost contexts\");\n        return;\n\n      } else if (expr is UnaryOpExpr) {\n        var e = (UnaryOpExpr)expr;\n        if (e.Op == UnaryOpExpr.Opcode.Fresh) {\n          reporter.Error(MessageSource.Resolver, expr, \"fresh expressions are allowed only in specification and ghost contexts\");\n          return;\n        }\n\n      } else if (expr is UnchangedExpr) {\n        reporter.Error(MessageSource.Resolver, expr, \"unchanged expressions are allowed only in specification and ghost contexts\");\n        return;\n\n      } else if (expr is StmtExpr) {\n        var e = (StmtExpr)expr;\n        // ignore the statement\n        CheckIsCompilable(e.E);\n        return;\n\n      } else if (expr is BinaryExpr) {\n        var e = (BinaryExpr)expr;\n        switch (e.ResolvedOp_PossiblyStillUndetermined) {\n          case BinaryExpr.ResolvedOpcode.RankGt:\n          case BinaryExpr.ResolvedOpcode.RankLt:\n            reporter.Error(MessageSource.Resolver, expr, \"rank comparisons are allowed only in specification and ghost contexts\");\n            return;\n          default:\n            break;\n        }\n\n      } else if (expr is TernaryExpr) {\n        var e = (TernaryExpr)expr;\n        switch (e.Op) {\n          case TernaryExpr.Opcode.PrefixEqOp:\n          case TernaryExpr.Opcode.PrefixNeqOp:\n            reporter.Error(MessageSource.Resolver, expr, \"prefix equalities are allowed only in specification and ghost contexts\");\n            return;\n          default:\n            break;\n        }\n      } else if (expr is LetExpr) {\n        var e = (LetExpr)expr;\n        if (e.Exact) {\n          Contract.Assert(e.LHSs.Count == e.RHSs.Count);\n          var i = 0;\n          foreach (var ee in e.RHSs) {\n            if (!e.LHSs[i].Vars.All(bv => bv.IsGhost)) {\n              CheckIsCompilable(ee);\n            }\n            i++;\n          }\n          CheckIsCompilable(e.Body);\n        } else {\n          Contract.Assert(e.RHSs.Count == 1);\n          var lhsVarsAreAllGhost = e.BoundVars.All(bv => bv.IsGhost);\n          if (!lhsVarsAreAllGhost) {\n            CheckIsCompilable(e.RHSs[0]);\n          }\n          CheckIsCompilable(e.Body);\n\n          // fill in bounds for this to-be-compiled let-such-that expression\n          Contract.Assert(e.RHSs.Count == 1);  // if we got this far, the resolver will have checked this condition successfully\n          var constraint = e.RHSs[0];\n          e.Constraint_Bounds = DiscoverBestBounds_MultipleVars(e.BoundVars.ToList<IVariable>(), constraint, true, ComprehensionExpr.BoundedPool.PoolVirtues.None);\n        }\n        return;\n      } else if (expr is LambdaExpr) {\n        var e = expr as LambdaExpr;\n        CheckIsCompilable(e.Body);\n        return;\n      } else if (expr is ComprehensionExpr) {\n        var e = (ComprehensionExpr)expr;\n        var uncompilableBoundVars = e.UncompilableBoundVars();\n        if (uncompilableBoundVars.Count != 0) {\n          string what;\n          if (e is SetComprehension) {\n            what = ((SetComprehension)e).Finite ? \"set comprehensions\" : \"iset comprehensions\";\n          } else if (e is MapComprehension) {\n            what = ((MapComprehension)e).Finite ? \"map comprehensions\" : \"imap comprehensions\";\n          } else {\n            Contract.Assume(e is QuantifierExpr);  // otherwise, unexpected ComprehensionExpr (since LambdaExpr is handled separately above)\n            Contract.Assert(((QuantifierExpr)e).SplitQuantifier == null); // No split quantifiers during resolution\n            what = \"quantifiers\";\n          }\n          foreach (var bv in uncompilableBoundVars) {\n            reporter.Error(MessageSource.Resolver, expr, \"{0} in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for '{1}'\", what, bv.Name);\n          }\n          return;\n        }\n        // don't recurse down any attributes\n        if (e.Range != null) { CheckIsCompilable(e.Range); }\n        CheckIsCompilable(e.Term);\n        return;\n\n      } else if (expr is NamedExpr) {\n        if (!moduleInfo.IsAbstract)\n          CheckIsCompilable(((NamedExpr)expr).Body);\n        return;\n      } else if (expr is ChainingExpression) {\n        // We don't care about the different operators; we only want the operands, so let's get them directly from\n        // the chaining expression\n        var e = (ChainingExpression)expr;\n        e.Operands.ForEach(CheckIsCompilable);\n        return;\n      }\n\n      foreach (var ee in expr.SubExpressions) {\n        CheckIsCompilable(ee);\n      }\n    }\n\n    public void ResolveFunctionCallExpr(FunctionCallExpr e, ResolveOpts opts) {\n      Contract.Requires(e != null);\n      Contract.Requires(e.Type == null);  // should not have been type checked before\n\n      ResolveReceiver(e.Receiver, opts);\n      Contract.Assert(e.Receiver.Type != null);  // follows from postcondition of ResolveExpression\n      NonProxyType nptype;\n\n      MemberDecl member = ResolveMember(e.tok, e.Receiver.Type, e.Name, out nptype);\n#if !NO_WORK_TO_BE_DONE\n      UserDefinedType ctype = (UserDefinedType)nptype;\n#endif\n      if (member == null) {\n        // error has already been reported by ResolveMember\n      } else if (member is Method) {\n        reporter.Error(MessageSource.Resolver, e, \"member {0} in type {1} refers to a method, but only functions can be used in this context\", e.Name, cce.NonNull(ctype).Name);\n      } else if (!(member is Function)) {\n        reporter.Error(MessageSource.Resolver, e, \"member {0} in type {1} does not refer to a function\", e.Name, cce.NonNull(ctype).Name);\n      } else {\n        Function function = (Function)member;\n        e.Function = function;\n        if (function is FixpointPredicate) {\n          ((FixpointPredicate)function).Uses.Add(e);\n        }\n        if (function is TwoStateFunction && !opts.twoState) {\n          reporter.Error(MessageSource.Resolver, e.tok, \"a two-state function can be used only in a two-state context\");\n        }\n        if (e.Receiver is StaticReceiverExpr && !function.IsStatic) {\n          reporter.Error(MessageSource.Resolver, e, \"an instance function must be selected via an object, not just a class name\");\n        }\n        if (function.Formals.Count != e.Args.Count) {\n          reporter.Error(MessageSource.Resolver, e, \"wrong number of function arguments (got {0}, expected {1})\", e.Args.Count, function.Formals.Count);\n        } else {\n          Contract.Assert(ctype != null);  // follows from postcondition of ResolveMember\n          if (!function.IsStatic) {\n            if (!scope.AllowInstance && e.Receiver is ThisExpr) {\n              // The call really needs an instance, but that instance is given as 'this', which is not\n              // available in this context.  In most cases, occurrences of 'this' inside e.Receiver would\n              // have been caught in the recursive call to resolve e.Receiver, but not the specific case\n              // of e.Receiver being 'this' (explicitly or implicitly), for that case needs to be allowed\n              // in the event that a static function calls another static function (and note that we need the\n              // type of the receiver in order to find the method, so we could not have made this check\n              // earlier).\n              reporter.Error(MessageSource.Resolver, e.Receiver, \"'this' is not allowed in a 'static' context\");\n            } else if (e.Receiver is StaticReceiverExpr) {\n              reporter.Error(MessageSource.Resolver, e.Receiver, \"call to instance function requires an instance\");\n            }\n          }\n          // build the type substitution map\n          e.TypeArgumentSubstitutions = new Dictionary<TypeParameter, Type>();\n          for (int i = 0; i < ctype.TypeArgs.Count; i++) {\n            e.TypeArgumentSubstitutions.Add(cce.NonNull(ctype.ResolvedClass).TypeArgs[i], ctype.TypeArgs[i]);\n          }\n          foreach (TypeParameter p in function.TypeArgs) {\n            e.TypeArgumentSubstitutions.Add(p, new ParamTypeProxy(p));\n          }\n          Dictionary<TypeParameter, Type> subst = BuildTypeArgumentSubstitute(e.TypeArgumentSubstitutions);\n\n          // type check the arguments\n          for (int i = 0; i < function.Formals.Count; i++) {\n            Expression farg = e.Args[i];\n            ResolveExpression(farg, opts);\n            Contract.Assert(farg.Type != null);  // follows from postcondition of ResolveExpression\n            Type s = SubstType(function.Formals[i].Type, subst);\n            AddAssignableConstraint(e.tok, s, farg.Type, \"incorrect type of function argument\" + (function.Formals.Count == 1 ? \"\" : \" \" + i) + \" (expected {0}, got {1})\");\n          }\n          e.Type = SubstType(function.ResultType, subst).NormalizeExpand();\n        }\n        AddCallGraphEdge(opts.codeContext, function, e, IsFunctionReturnValue(function, e.Args, opts));\n      }\n    }\n\n    private void AddCallGraphEdgeForField(ICodeContext callingContext, Field field, Expression e) {\n      Contract.Requires(callingContext != null);\n      Contract.Requires(field != null);\n      Contract.Requires(e != null);\n      var cf = field as ConstantField;\n      if (cf != null) {\n        if (cf == callingContext) {\n          // detect self-loops here, since they don't show up in the graph's SSC methods\n          reporter.Error(MessageSource.Resolver, cf.tok, \"recursive dependency involving constant initialization: {0} -> {0}\", cf.Name);\n        } else {\n          AddCallGraphEdge(callingContext, cf, e, false);\n        }\n      }\n    }\n\n    private static void AddCallGraphEdge(ICodeContext callingContext, ICallable function, Expression e, bool isFunctionReturnValue) {\n      Contract.Requires(callingContext != null);\n      Contract.Requires(function != null);\n      Contract.Requires(e != null);\n      // Resolution termination check\n      ModuleDefinition callerModule = callingContext.EnclosingModule;\n      ModuleDefinition calleeModule = function is SpecialFunction ? null : function.EnclosingModule;\n      if (callerModule == calleeModule) {\n        // intra-module call; add edge in module's call graph\n        var caller = callingContext as ICallable;\n        if (caller == null) {\n          // don't add anything to the call graph after all\n        } else if (caller is IteratorDecl) {\n          callerModule.CallGraph.AddEdge(((IteratorDecl)callingContext).Member_MoveNext, function);\n        } else {\n          callerModule.CallGraph.AddEdge(caller, function);\n          if (caller is Function) {\n            FunctionCallExpr ee = e as FunctionCallExpr;\n            if (ee != null) {\n              ((Function)caller).AllCalls.Add(ee);\n            }\n          }\n          // if the call denotes the function return value in the function postconditions, then we don't\n          // mark it as recursive.\n          if (caller == function && (function is Function) && !isFunctionReturnValue) {\n            ((Function)function).IsRecursive = true;  // self recursion (mutual recursion is determined elsewhere)\n          }\n        }\n      }\n    }\n\n\n    private static ModuleSignature GetSignatureExt(ModuleSignature sig, bool useCompileSignatures) {\n      Contract.Requires(sig != null);\n      Contract.Ensures(Contract.Result<ModuleSignature>() != null);\n      if (useCompileSignatures) {\n        while (sig.CompileSignature != null)\n          sig = sig.CompileSignature;\n      }\n      return sig;\n    }\n\n    private ModuleSignature GetSignature(ModuleSignature sig) {\n      return GetSignatureExt(sig, useCompileSignatures);\n    }\n\n    public static List<ComprehensionExpr.BoundedPool> DiscoverBestBounds_MultipleVars_AllowReordering<VT>(List<VT> bvars, Expression expr, bool polarity, ComprehensionExpr.BoundedPool.PoolVirtues requiredVirtues) where VT : IVariable {\n      Contract.Requires(bvars != null);\n      Contract.Requires(expr != null);\n      Contract.Ensures(Contract.Result<List<ComprehensionExpr.BoundedPool>>() != null);\n      var bounds = DiscoverBestBounds_MultipleVars(bvars, expr, polarity, requiredVirtues);\n      if (bvars.Count > 1) {\n        // It may be helpful to try all permutations (or, better yet, to use an algorithm that keeps track of the dependencies\n        // and discovers good bounds more efficiently). However, all permutations would be expensive. Therefore, we try just one\n        // other permutation, namely the reversal \"bvars\". This covers the important case where there are two bound variables\n        // that work out in the opposite order. It also covers one more case for the (probably rare) case of there being more\n        // than two bound variables.\n        var bvarsMissyElliott = new List<VT>(bvars);  // make a copy\n        bvarsMissyElliott.Reverse();  // and then flip it and reverse it, Ti esrever dna ti pilf nwod gniht ym tup I\n        var boundsMissyElliott = DiscoverBestBounds_MultipleVars(bvarsMissyElliott, expr, polarity, requiredVirtues);\n        // Figure out which one seems best\n        var meBetter = 0;\n        for (int i = 0; i < bvars.Count; i++) {\n          var orig = bounds[i];\n          var me = boundsMissyElliott[i];\n          if (orig == null && me != null) {\n            meBetter = 1; break; // end game\n          } else if (orig != null && me == null) {\n            meBetter = -1; break; // end game\n          } else if (orig != null && me != null) {\n            if ((orig.Virtues & ComprehensionExpr.BoundedPool.PoolVirtues.Finite) != 0) { meBetter--; }\n            if ((orig.Virtues & ComprehensionExpr.BoundedPool.PoolVirtues.Enumerable) != 0) { meBetter--; }\n            if ((me.Virtues & ComprehensionExpr.BoundedPool.PoolVirtues.Finite) != 0) { meBetter++; }\n            if ((me.Virtues & ComprehensionExpr.BoundedPool.PoolVirtues.Enumerable) != 0) { meBetter++; }\n          }\n        }\n        if (meBetter > 0) {\n          // yes, this reordering seems to have been better\n          bvars.Reverse();\n          return boundsMissyElliott;\n        }\n      }\n      return bounds;\n    }\n\n    /// <summary>\n    /// For a list of variables \"bvars\", returns a list of best bounds, subject to the constraint \"requiredVirtues\", for each respective variable.\n    /// If no bound matching \"requiredVirtues\" is found for a variable \"v\", then the bound for \"v\" in the returned list is set to \"null\".\n    /// </summary>\n    public static List<ComprehensionExpr.BoundedPool> DiscoverBestBounds_MultipleVars<VT>(List<VT> bvars, Expression expr, bool polarity, ComprehensionExpr.BoundedPool.PoolVirtues requiredVirtues) where VT : IVariable {\n      Contract.Requires(bvars != null);\n      Contract.Requires(expr != null);\n      Contract.Ensures(Contract.Result<List<ComprehensionExpr.BoundedPool>>() != null);\n      foreach (var bv in bvars) {\n        var c = GetImpliedTypeConstraint(bv, bv.Type);\n        expr = polarity ? Expression.CreateAnd(c, expr) : Expression.CreateImplies(c, expr);\n      }\n      var bests = DiscoverAllBounds_Aux_MultipleVars(bvars, expr, polarity, requiredVirtues);\n      return bests;\n    }\n\n    public static List<ComprehensionExpr.BoundedPool> DiscoverAllBounds_SingleVar<VT>(VT v, Expression expr) where VT : IVariable {\n      expr = Expression.CreateAnd(GetImpliedTypeConstraint(v, v.Type), expr);\n      return DiscoverAllBounds_Aux_SingleVar(new List<VT> { v }, 0, expr, true, new List<ComprehensionExpr.BoundedPool>() { null });\n    }\n\n    private static List<ComprehensionExpr.BoundedPool> DiscoverAllBounds_Aux_MultipleVars<VT>(List<VT> bvars, Expression expr, bool polarity, ComprehensionExpr.BoundedPool.PoolVirtues requiredVirtues) where VT : IVariable {\n      Contract.Requires(bvars != null);\n      Contract.Requires(expr != null);\n      Contract.Ensures(Contract.Result<List<ComprehensionExpr.BoundedPool>>() != null);\n      Contract.Ensures(Contract.Result<List<ComprehensionExpr.BoundedPool>>().Count == bvars.Count);\n      var knownBounds = new List<ComprehensionExpr.BoundedPool>();\n      for (var j = 0; j < bvars.Count; j++) {\n        knownBounds.Add(null);\n      }\n      for (var j = bvars.Count; 0 <= --j; ) {  // important to go backwards, because DiscoverAllBounds_Aux_SingleVar assumes \"knownBounds\" has been filled in for higher-indexed variables\n        var bounds = DiscoverAllBounds_Aux_SingleVar(bvars, j, expr, polarity, knownBounds);\n        knownBounds[j] = ComprehensionExpr.BoundedPool.GetBest(bounds, requiredVirtues);\n#if DEBUG_PRINT\n        if (knownBounds[j] is ComprehensionExpr.IntBoundedPool) {\n          var ib = (ComprehensionExpr.IntBoundedPool)knownBounds[j];\n          var lo = ib.LowerBound == null ? \"\" : Printer.ExprToString(ib.LowerBound);\n          var hi = ib.UpperBound == null ? \"\" : Printer.ExprToString(ib.UpperBound);\n          Console.WriteLine(\"DEBUG: Bound for var {3}, {0}:  {1} .. {2}\", bvars[j].Name, lo, hi, j);\n        } else if (knownBounds[j] is ComprehensionExpr.SetBoundedPool) {\n          Console.WriteLine(\"DEBUG: Bound for var {2}, {0}:  in {1}\", bvars[j].Name, Printer.ExprToString(((ComprehensionExpr.SetBoundedPool)knownBounds[j]).Set), j);\n        } else {\n          Console.WriteLine(\"DEBUG: Bound for var {2}, {0}:  {1}\", bvars[j].Name, knownBounds[j], j);\n        }\n#endif\n      }\n      return knownBounds;\n    }\n\n    /// <summary>\n    /// Returns a list of (possibly partial) bounds for \"bvars[j]\", each of which can be written without mentioning any variable in \"bvars[j..]\" that is not bounded.\n    /// </summary>\n    private static List<ComprehensionExpr.BoundedPool> DiscoverAllBounds_Aux_SingleVar<VT>(List<VT> bvars, int j, Expression expr, bool polarity, List<ComprehensionExpr.BoundedPool> knownBounds) where VT : IVariable {\n      Contract.Requires(bvars != null);\n      Contract.Requires(0 <= j && j < bvars.Count);\n      Contract.Requires(expr != null);\n      Contract.Requires(knownBounds != null);\n      Contract.Requires(knownBounds.Count == bvars.Count);\n      var bv = bvars[j];\n      var bounds = new List<ComprehensionExpr.BoundedPool>();\n\n      // Maybe the type itself gives a bound\n      if (bv.Type.IsBoolType) {\n        bounds.Add(new ComprehensionExpr.BoolBoundedPool());\n      } else if (bv.Type.IsCharType) {\n        bounds.Add(new ComprehensionExpr.CharBoundedPool());\n      } else if (bv.Type.IsDatatype && bv.Type.AsDatatype.HasFinitePossibleValues) {\n        bounds.Add(new ComprehensionExpr.DatatypeBoundedPool(bv.Type.AsIndDatatype));\n      } else if (bv.Type.IsNumericBased(Type.NumericPersuation.Int)) {\n        bounds.Add(new AssignSuchThatStmt.WiggleWaggleBound());\n      } else if (bv.Type.IsAllocFree) {\n        bounds.Add(new ComprehensionExpr.AllocFreeBoundedPool(bv.Type));\n      }\n\n      // Go through the conjuncts of the range expression to look for bounds.\n      foreach (var conjunct in NormalizedConjuncts(expr, polarity)) {\n        if (conjunct is IdentifierExpr) {\n          var ide = (IdentifierExpr)conjunct;\n          if (ide.Var == (IVariable)bv) {\n            Contract.Assert(bv.Type.IsBoolType);\n            bounds.Add(new ComprehensionExpr.ExactBoundedPool(Expression.CreateBoolLiteral(Token.NoToken, true)));\n          }\n          continue;\n        }\n        if (conjunct is UnaryExpr || conjunct is OldExpr) {\n          // we also consider a unary expression sitting immediately inside an old\n          var unary = conjunct as UnaryOpExpr ?? ((OldExpr)conjunct).E.Resolved as UnaryOpExpr;\n          if (unary != null) {\n            var ide = unary.E.Resolved as IdentifierExpr;\n            if (ide != null && ide.Var == (IVariable)bv) {\n              if (unary.Op == UnaryOpExpr.Opcode.Not) {\n                Contract.Assert(bv.Type.IsBoolType);\n                bounds.Add(new ComprehensionExpr.ExactBoundedPool(Expression.CreateBoolLiteral(Token.NoToken, false)));\n              } else if (unary.Op == UnaryOpExpr.Opcode.Allocated || unary.Op == UnaryOpExpr.Opcode.AllocatedArray) {\n                bounds.Add(new ComprehensionExpr.ExplicitAllocatedBoundedPool());\n              }\n            }\n          }\n          continue;\n        }\n        var c = conjunct as BinaryExpr;\n        if (c == null) {\n          // other than what we already covered above, we only know what to do with binary expressions\n          continue;\n        }\n        var e0 = c.E0;\n        var e1 = c.E1;\n        int whereIsBv = SanitizeForBoundDiscovery(bvars, j, c.ResolvedOp, knownBounds, ref e0, ref e1);\n        if (whereIsBv < 0) {\n          continue;\n        }\n        switch (c.ResolvedOp) {\n          case BinaryExpr.ResolvedOpcode.InSet:\n            if (whereIsBv == 0) {\n              bounds.Add(new ComprehensionExpr.SetBoundedPool(e1, e0.Type.Equals(e1.Type.AsSetType.Arg), e1.Type.AsSetType.Finite));\n            }\n            break;\n          case BinaryExpr.ResolvedOpcode.Subset:\n            if (whereIsBv == 0) {\n              bounds.Add(new ComprehensionExpr.SubSetBoundedPool(e1, e1.Type.AsSetType.Finite));\n            } else {\n              bounds.Add(new ComprehensionExpr.SuperSetBoundedPool(e0));\n            }\n            break;\n          case BinaryExpr.ResolvedOpcode.InMultiSet:\n            if (whereIsBv == 0) {\n              bounds.Add(new ComprehensionExpr.MultiSetBoundedPool(e1, e0.Type.Equals(e1.Type.AsMultiSetType.Arg)));\n            }\n            break;\n          case BinaryExpr.ResolvedOpcode.InSeq:\n            if (whereIsBv == 0) {\n              bounds.Add(new ComprehensionExpr.SeqBoundedPool(e1, e0.Type.Equals(e1.Type.AsSeqType.Arg)));\n            }\n            break;\n          case BinaryExpr.ResolvedOpcode.InMap:\n            if (whereIsBv == 0) {\n              bounds.Add(new ComprehensionExpr.MapBoundedPool(e1, e0.Type.Equals(e1.Type.AsMapType.Arg), e1.Type.AsMapType.Finite));\n            }\n            break;\n          case BinaryExpr.ResolvedOpcode.EqCommon:\n          case BinaryExpr.ResolvedOpcode.SetEq:\n          case BinaryExpr.ResolvedOpcode.SeqEq:\n          case BinaryExpr.ResolvedOpcode.MultiSetEq:\n          case BinaryExpr.ResolvedOpcode.MapEq:\n            var otherOperand = whereIsBv == 0 ? e1 : e0;\n            bounds.Add(new ComprehensionExpr.ExactBoundedPool(otherOperand));\n            break;\n          case BinaryExpr.ResolvedOpcode.Gt:\n          case BinaryExpr.ResolvedOpcode.Ge:\n            Contract.Assert(false); throw new cce.UnreachableException();  // promised by postconditions of NormalizedConjunct\n          case BinaryExpr.ResolvedOpcode.Lt:\n            if (e0.Type.IsNumericBased(Type.NumericPersuation.Int)) {\n              if (whereIsBv == 0) {  // bv < E\n                bounds.Add(new ComprehensionExpr.IntBoundedPool(null, e1));\n              } else {  // E < bv\n                bounds.Add(new ComprehensionExpr.IntBoundedPool(Expression.CreateIncrement(e0, 1), null));\n              }\n            }\n            break;\n          case BinaryExpr.ResolvedOpcode.Le:\n            if (e0.Type.IsNumericBased(Type.NumericPersuation.Int)) {\n              if (whereIsBv == 0) {  // bv <= E\n                bounds.Add(new ComprehensionExpr.IntBoundedPool(null, Expression.CreateIncrement(e1, 1)));\n              } else {  // E <= bv\n                bounds.Add(new ComprehensionExpr.IntBoundedPool(e0, null));\n              }\n            }\n            break;\n          case BinaryExpr.ResolvedOpcode.RankLt:\n            if (whereIsBv == 0) {\n              bounds.Add(new ComprehensionExpr.DatatypeInclusionBoundedPool(e0.Type.IsIndDatatype));\n            }\n            break;\n          case BinaryExpr.ResolvedOpcode.RankGt:\n            if (whereIsBv == 1) {\n              bounds.Add(new ComprehensionExpr.DatatypeInclusionBoundedPool(e1.Type.IsIndDatatype));\n            }\n            break;\n          default:\n            break;\n        }\n      }\n      return bounds;\n    }\n\n    private static Translator translator = new Translator(null);\n\n    public static Expression GetImpliedTypeConstraint(IVariable bv, Type ty) {\n      return GetImpliedTypeConstraint(Expression.CreateIdentExpr(bv), ty);\n    }\n\n    public static Expression GetImpliedTypeConstraint(Expression e, Type ty) {\n      Contract.Requires(e != null);\n      Contract.Requires(ty != null);\n      ty = ty.NormalizeExpandKeepConstraints();\n      var udt = ty as UserDefinedType;\n      if (udt != null) {\n        if (udt.ResolvedClass is NewtypeDecl) {\n          var dd = (NewtypeDecl)udt.ResolvedClass;\n          var c = GetImpliedTypeConstraint(e, dd.BaseType);\n          if (dd.Var != null) {\n            Dictionary<IVariable, Expression/*!*/> substMap = new Dictionary<IVariable, Expression>();\n            substMap.Add(dd.Var, e);\n            Translator.Substituter sub = new Translator.Substituter(null, substMap, new Dictionary<TypeParameter, Type>());\n            c = Expression.CreateAnd(c, sub.Substitute(dd.Constraint));\n          }\n          return c;\n        } else if (udt.ResolvedClass is SubsetTypeDecl) {\n          var dd = (SubsetTypeDecl)udt.ResolvedClass;\n          var c = GetImpliedTypeConstraint(e, dd.RhsWithArgument(udt.TypeArgs));\n          Dictionary<IVariable, Expression/*!*/> substMap = new Dictionary<IVariable, Expression>();\n          substMap.Add(dd.Var, e);\n          Translator.Substituter sub = new Translator.Substituter(null, substMap, new Dictionary<TypeParameter, Type>());\n          c = Expression.CreateAnd(c, sub.Substitute(dd.Constraint));\n          return c;\n        }\n      }\n      return Expression.CreateBoolLiteral(e.tok, true);\n    }\n\n    /// <summary>\n    /// If the return value is negative, the resulting \"e0\" and \"e1\" should not be used.\n    /// Otherwise, the following is true on return:\n    /// The new \"e0 op e1\" is equivalent to the old \"e0 op e1\".\n    /// One of \"e0\" and \"e1\" is the identifier \"boundVars[bvi]\"; the return value is either 0 or 1, and indicates which.\n    /// The other of \"e0\" and \"e1\" is an expression whose free variables are not among \"boundVars[bvi..]\".\n    /// Ensures that the resulting \"e0\" and \"e1\" are not ConcreteSyntaxExpression's.\n    /// </summary>\n    static int SanitizeForBoundDiscovery<VT>(List<VT> boundVars, int bvi, BinaryExpr.ResolvedOpcode op, List<ComprehensionExpr.BoundedPool> knownBounds, ref Expression e0, ref Expression e1) where VT : IVariable {\n      Contract.Requires(boundVars != null);\n      Contract.Requires(0 <= bvi && bvi < boundVars.Count);\n      Contract.Requires(knownBounds != null);\n      Contract.Requires(knownBounds.Count == boundVars.Count);\n      Contract.Requires(e0 != null);\n      Contract.Requires(e1 != null);\n      Contract.Ensures(Contract.Result<int>() < 2);\n      Contract.Ensures(!(Contract.ValueAtReturn(out e0) is ConcreteSyntaxExpression));\n      Contract.Ensures(!(Contract.ValueAtReturn(out e1) is ConcreteSyntaxExpression));\n\n      IVariable bv = boundVars[bvi];\n      e0 = e0.Resolved;\n      e1 = e1.Resolved;\n\n      // make an initial assessment of where bv is; to continue, we need bv to appear in exactly one operand\n      var fv0 = FreeVariables(e0);\n      var fv1 = FreeVariables(e1);\n      Expression thisSide;\n      Expression thatSide;\n      int whereIsBv;\n      if (fv0.Contains(bv)) {\n        if (fv1.Contains(bv)) {\n          return -1;\n        }\n        whereIsBv = 0;\n        thisSide = e0; thatSide = e1;\n      } else if (fv1.Contains(bv)) {\n        whereIsBv = 1;\n        thisSide = e1; thatSide = e0;\n      } else {\n        return -1;\n      }\n\n      // Next, clean up the side where bv is by adjusting both sides of the expression\n      switch (op) {\n        case BinaryExpr.ResolvedOpcode.EqCommon:\n        case BinaryExpr.ResolvedOpcode.NeqCommon:\n        case BinaryExpr.ResolvedOpcode.Gt:\n        case BinaryExpr.ResolvedOpcode.Ge:\n        case BinaryExpr.ResolvedOpcode.Le:\n        case BinaryExpr.ResolvedOpcode.Lt:\n          // Repeatedly move additive or subtractive terms from thisSide to thatSide\n          while (true) {\n            var bin = thisSide as BinaryExpr;\n            if (bin == null) {\n              break;  // done simplifying\n\n            } else if (bin.ResolvedOp == BinaryExpr.ResolvedOpcode.Add) {\n              // Change \"A+B op C\" into either \"A op C-B\" or \"B op C-A\", depending on where we find bv among A and B.\n              if (!FreeVariables(bin.E1).Contains(bv)) {\n                thisSide = bin.E0.Resolved;\n                thatSide = new BinaryExpr(bin.tok, BinaryExpr.Opcode.Sub, thatSide, bin.E1);\n              } else if (!FreeVariables(bin.E0).Contains(bv)) {\n                thisSide = bin.E1.Resolved;\n                thatSide = new BinaryExpr(bin.tok, BinaryExpr.Opcode.Sub, thatSide, bin.E0);\n              } else {\n                break;  // done simplifying\n              }\n              ((BinaryExpr)thatSide).ResolvedOp = BinaryExpr.ResolvedOpcode.Sub;\n              thatSide.Type = bin.Type;\n\n            } else if (bin.ResolvedOp == BinaryExpr.ResolvedOpcode.Sub) {\n              // Change \"A-B op C\" in a similar way.\n              if (!FreeVariables(bin.E1).Contains(bv)) {\n                // change to \"A op C+B\"\n                thisSide = bin.E0.Resolved;\n                thatSide = new BinaryExpr(bin.tok, BinaryExpr.Opcode.Add, thatSide, bin.E1);\n                ((BinaryExpr)thatSide).ResolvedOp = BinaryExpr.ResolvedOpcode.Add;\n              } else if (!FreeVariables(bin.E0).Contains(bv)) {\n                // In principle, change to \"-B op C-A\" and then to \"B dualOp A-C\".  But since we don't want\n                // to change \"op\", we instead end with \"A-C op B\" and switch the mapping of thisSide/thatSide\n                // to e0/e1 (by inverting \"whereIsBv\").\n                thisSide = bin.E1.Resolved;\n                thatSide = new BinaryExpr(bin.tok, BinaryExpr.Opcode.Sub, bin.E0, thatSide);\n                ((BinaryExpr)thatSide).ResolvedOp = BinaryExpr.ResolvedOpcode.Sub;\n                whereIsBv = 1 - whereIsBv;\n              } else {\n                break;  // done simplifying\n              }\n              thatSide.Type = bin.Type;\n\n            } else {\n              break;  // done simplifying\n            }\n          }\n          break;\n\n        default:\n          break;\n      }\n      // our transformation above maintained the following invariant:\n      Contract.Assert(!FreeVariables(thatSide).Contains(bv));\n\n      // Now, see if the interesting side is simply bv itself\n      if (thisSide is IdentifierExpr && ((IdentifierExpr)thisSide).Var == bv) {\n        // we're cool\n      } else {\n        // no, the situation is more complicated than we care to understand\n        return -1;\n      }\n\n      // Finally, check the bound variables of \"thatSide\". We allow \"thatSide\" to\n      // depend on bound variables that are listed before \"bv\" (that is, a bound variable\n      // \"boundVars[k]\" where \"k < bvi\"). By construction, \"thatSide\" does not depend\n      // on \"bv\". Generally, for any bound variable \"bj\" that is listed after \"bv\"\n      // (that is, \"bj\" is some \"boundVars[j]\" where \"bvi < j\"), we do not allow\n      // \"thatSide\" to depend on \"bv\", but there is an important exception:\n      // If\n      //   *  \"op\" makes \"thatSide\" denote an integer upper bound on \"bv\" (or, analogously,\n      //      a integer lower bound),\n      //   *  \"thatSide\" depends on \"bj\",\n      //   *  \"thatSide\" is monotonic in \"bj\",\n      //   *  \"bj\" has a known integer upper bound \"u\",\n      //   *  \"u\" does not depend on \"bv\" or any bound variable listed after \"bv\"\n      //      (from the way we're constructing bounds, we already know that \"u\"\n      //      does not depend on \"bj\" or any bound variable listed after \"bj\")\n      // then we can substitute \"u\" for \"bj\" in \"thatSide\".\n      // By going from right to left, we can make the rule above slightly more\n      // liberal by considering a cascade of substitutions.\n      var fvThatSide = FreeVariables(thatSide);\n      for (int j = boundVars.Count; bvi + 1 <= --j; ) {\n        if (fvThatSide.Contains(boundVars[j])) {\n          if (knownBounds[j] is ComprehensionExpr.IntBoundedPool) {\n            var jBounds = (ComprehensionExpr.IntBoundedPool)knownBounds[j];\n            Expression u = null;\n            if (op == BinaryExpr.ResolvedOpcode.Lt || op == BinaryExpr.ResolvedOpcode.Le) {\n              u = whereIsBv == 0 ? jBounds.UpperBound : jBounds.LowerBound;\n            } else if (op == BinaryExpr.ResolvedOpcode.Gt || op == BinaryExpr.ResolvedOpcode.Ge) {\n              u = whereIsBv == 0 ? jBounds.LowerBound : jBounds.UpperBound;\n            }\n            if (u != null && !FreeVariables(u).Contains(bv) && IsMonotonic(u, boundVars[j], true)) {\n              thatSide = Translator.Substitute(thatSide, boundVars[j], u);\n              fvThatSide = FreeVariables(thatSide);\n              continue;\n            }\n          }\n          return -1;  // forget about \"bv OP thatSide\"\n        }\n      }\n\n      // As we return, also return the adjusted sides\n      if (whereIsBv == 0) {\n        e0 = thisSide; e1 = thatSide;\n      } else {\n        e0 = thatSide; e1 = thisSide;\n      }\n      return whereIsBv;\n    }\n\n    /// <summary>\n    /// If \"position\", then returns \"true\" if \"x\" occurs only positively in \"expr\".\n    /// If \"!position\", then returns \"true\" if \"x\" occurs only negatively in \"expr\".\n    /// </summary>\n    public static bool IsMonotonic(Expression expr, IVariable x, bool position) {\n      Contract.Requires(expr != null && expr.Type != null);\n      Contract.Requires(x != null);\n\n      if (expr is IdentifierExpr) {\n        var e = (IdentifierExpr)expr;\n        return e.Var != x || position;\n      } else if (expr is BinaryExpr) {\n        var e = (BinaryExpr)expr;\n        if (e.ResolvedOp == BinaryExpr.ResolvedOpcode.Add) {\n          return IsMonotonic(e.E0, x, position) && IsMonotonic(e.E1, x, position);\n        } else if (e.ResolvedOp == BinaryExpr.ResolvedOpcode.Sub) {\n          return IsMonotonic(e.E0, x, position) && IsMonotonic(e.E1, x, !position);\n        }\n      }\n      return !FreeVariables(expr).Contains(x);\n    }\n\n    /// <summary>\n    /// Returns all conjuncts of \"expr\" in \"polarity\" positions.  That is, if \"polarity\" is \"true\", then\n    /// returns the conjuncts of \"expr\" in positive positions; else, returns the conjuncts of \"expr\" in\n    /// negative positions.  The method considers a canonical-like form of the expression that pushes\n    /// negations inwards far enough that one can determine what the result is going to be (so, almost\n    /// a negation normal form).\n    /// As a convenience, arithmetic inequalities are rewritten so that the negation of an arithmetic\n    /// inequality is never returned and the comparisons > and >= are never returned; the negation of\n    /// a common equality or disequality is rewritten analogously.\n    /// Requires \"expr\" to be successfully resolved.\n    /// Ensures that what is returned is not a ConcreteSyntaxExpression.\n    /// </summary>\n    static IEnumerable<Expression> NormalizedConjuncts(Expression expr, bool polarity) {\n      // We consider 5 cases.  To describe them, define P(e)=Conjuncts(e,true) and N(e)=Conjuncts(e,false).\n      //   *  X ==> Y    is treated as a shorthand for !X || Y, and so is described by the remaining cases\n      //   *  X && Y     P(_) = P(X),P(Y)    and    N(_) = !(X && Y)\n      //   *  X || Y     P(_) = (X || Y)     and    N(_) = N(X),N(Y)\n      //   *  !X         P(_) = N(X)         and    N(_) = P(X)\n      //   *  else       P(_) = else         and    N(_) = !else\n      // So for ==>, we have:\n      //   *  X ==> Y    P(_) = P(!X || Y) = (!X || Y) = (X ==> Y)\n      //                 N(_) = N(!X || Y) = N(!X),N(Y) = P(X),N(Y)\n      expr = expr.Resolved;\n\n      // Binary expressions\n      var b = expr as BinaryExpr;\n      if (b != null) {\n        bool breakDownFurther = false;\n        bool p0 = polarity;\n        switch (b.ResolvedOp) {\n          case BinaryExpr.ResolvedOpcode.And:\n            breakDownFurther = polarity;\n            break;\n          case BinaryExpr.ResolvedOpcode.Or:\n            breakDownFurther = !polarity;\n            break;\n          case BinaryExpr.ResolvedOpcode.Imp:\n            breakDownFurther = !polarity;\n            p0 = !p0;\n            break;\n          default:\n            break;\n        }\n        if (breakDownFurther) {\n          foreach (var c in NormalizedConjuncts(b.E0, p0)) {\n            yield return c;\n          }\n          foreach (var c in NormalizedConjuncts(b.E1, polarity)) {\n            yield return c;\n          }\n          yield break;\n        }\n      }\n\n      // Unary expression\n      var u = expr as UnaryOpExpr;\n      if (u != null && u.Op == UnaryOpExpr.Opcode.Not) {\n        foreach (var c in NormalizedConjuncts(u.E, !polarity)) {\n          yield return c;\n        }\n        yield break;\n      }\n\n      // no other case applied, so return the expression or its negation, but first clean it up a little\n      b = expr as BinaryExpr;\n      if (b != null) {\n        BinaryExpr.Opcode newOp;\n        BinaryExpr.ResolvedOpcode newROp;\n        bool swapOperands;\n        switch (b.ResolvedOp) {\n          case BinaryExpr.ResolvedOpcode.Gt:  // A > B         yield polarity ? (B < A) : (A <= B);\n            newOp = polarity ? BinaryExpr.Opcode.Lt : BinaryExpr.Opcode.Le;\n            newROp = polarity ? BinaryExpr.ResolvedOpcode.Lt : BinaryExpr.ResolvedOpcode.Le;\n            swapOperands = polarity;\n            break;\n          case BinaryExpr.ResolvedOpcode.Ge:  // A >= B        yield polarity ? (B <= A) : (A < B);\n            newOp = polarity ? BinaryExpr.Opcode.Le : BinaryExpr.Opcode.Lt;\n            newROp = polarity ? BinaryExpr.ResolvedOpcode.Le : BinaryExpr.ResolvedOpcode.Lt;\n            swapOperands = polarity;\n            break;\n          case BinaryExpr.ResolvedOpcode.Le:  // A <= B        yield polarity ? (A <= B) : (B < A);\n            newOp = polarity ? BinaryExpr.Opcode.Le : BinaryExpr.Opcode.Lt;\n            newROp = polarity ? BinaryExpr.ResolvedOpcode.Le : BinaryExpr.ResolvedOpcode.Lt;\n            swapOperands = !polarity;\n            break;\n          case BinaryExpr.ResolvedOpcode.Lt:  // A < B         yield polarity ? (A < B) : (B <= A);\n            newOp = polarity ? BinaryExpr.Opcode.Lt : BinaryExpr.Opcode.Le;\n            newROp = polarity ? BinaryExpr.ResolvedOpcode.Lt : BinaryExpr.ResolvedOpcode.Le;\n            swapOperands = !polarity;\n            break;\n          case BinaryExpr.ResolvedOpcode.EqCommon:  // A == B         yield polarity ? (A == B) : (A != B);\n            newOp = polarity ? BinaryExpr.Opcode.Eq : BinaryExpr.Opcode.Neq;\n            newROp = polarity ? BinaryExpr.ResolvedOpcode.EqCommon : BinaryExpr.ResolvedOpcode.NeqCommon;\n            swapOperands = false;\n            break;\n          case BinaryExpr.ResolvedOpcode.NeqCommon:  // A != B         yield polarity ? (A != B) : (A == B);\n            newOp = polarity ? BinaryExpr.Opcode.Neq : BinaryExpr.Opcode.Eq;\n            newROp = polarity ? BinaryExpr.ResolvedOpcode.NeqCommon : BinaryExpr.ResolvedOpcode.EqCommon;\n            swapOperands = false;\n            break;\n          default:\n            goto JUST_RETURN_IT;\n        }\n        if (newROp != b.ResolvedOp || swapOperands) {\n          b = new BinaryExpr(b.tok, newOp, swapOperands ? b.E1 : b.E0, swapOperands ? b.E0 : b.E1);\n          b.ResolvedOp = newROp;\n          b.Type = Type.Bool;\n          yield return b;\n          yield break;\n        }\n      }\n    JUST_RETURN_IT: ;\n      if (polarity) {\n        yield return expr;\n      } else {\n        expr = new UnaryOpExpr(expr.tok, UnaryOpExpr.Opcode.Not, expr);\n        expr.Type = Type.Bool;\n        yield return expr;\n      }\n    }\n\n    /// <summary>\n    /// Returns the set of free variables in \"expr\".\n    /// Requires \"expr\" to be successfully resolved.\n    /// Ensures that the set returned has no aliases.\n    /// </summary>\n    static ISet<IVariable> FreeVariables(Expression expr) {\n      Contract.Requires(expr != null);\n      Contract.Ensures(expr.Type != null);\n\n      if (expr is IdentifierExpr) {\n        var e = (IdentifierExpr)expr;\n        return new HashSet<IVariable>() { e.Var };\n\n      } else if (expr is QuantifierExpr) {\n        var e = (QuantifierExpr)expr;\n        Contract.Assert(e.SplitQuantifier == null); // No split quantifiers during resolution\n\n        var s = FreeVariables(e.LogicalBody());\n        foreach (var bv in e.BoundVars) {\n          s.Remove(bv);\n        }\n        return s;\n\n      } else if (expr is MatchExpr) {\n        var e = (MatchExpr)expr;\n        var s = FreeVariables(e.Source);\n        foreach (MatchCaseExpr mc in e.Cases) {\n          var t = FreeVariables(mc.Body);\n          Contract.Assert(mc.CasePatterns == null);  // CasePatterns should be converted to List<BoundVar> during resolver\n          foreach (var bv in mc.Arguments) {\n            t.Remove(bv);\n          }\n          s.UnionWith(t);\n        }\n        return s;\n\n      } else if (expr is LambdaExpr) {\n        var e = (LambdaExpr)expr;\n        var s = FreeVariables(e.Term);\n        if (e.Range != null) {\n          s.UnionWith(FreeVariables(e.Range));\n        }\n        foreach (var fe in e.Reads) {\n          s.UnionWith(FreeVariables(fe.E));\n        }\n        foreach (var bv in e.BoundVars) {\n          s.Remove(bv);\n        }\n        return s;\n\n      } else {\n        ISet<IVariable> s = null;\n        foreach (var e in expr.SubExpressions) {\n          var t = FreeVariables(e);\n          if (s == null) {\n            s = t;\n          } else {\n            s.UnionWith(t);\n          }\n        }\n        return s == null ? new HashSet<IVariable>() : s;\n      }\n    }\n\n    void ResolveReceiver(Expression expr, ResolveOpts opts) {\n      Contract.Requires(expr != null);\n      Contract.Ensures(expr.Type != null);\n\n      if (expr is ThisExpr && !expr.WasResolved()) {\n        // Allow 'this' here, regardless of scope.AllowInstance.  The caller is responsible for\n        // making sure 'this' does not really get used when it's not available.\n        Contract.Assume(currentClass != null);  // this is really a precondition, in this case\n        expr.Type = GetThisType(expr.tok, currentClass);\n      } else {\n        ResolveExpression(expr, opts);\n      }\n    }\n\n    void ResolveSeqSelectExpr(SeqSelectExpr e, ResolveOpts opts) {\n      Contract.Requires(e != null);\n      if (e.Type != null) {\n        // already resolved\n        return;\n      }\n\n      ResolveExpression(e.Seq, opts);\n      Contract.Assert(e.Seq.Type != null);  // follows from postcondition of ResolveExpression\n\n      if (e.SelectOne) {\n        AddXConstraint(e.tok, \"Indexable\", e.Seq.Type, \"element selection requires a sequence, array, multiset, or map (got {0})\");\n        ResolveExpression(e.E0, opts);\n        AddXConstraint(e.E0.tok, \"ContainerIndex\", e.Seq.Type, e.E0.Type, \"incorrect type for selection into {0} (got {1})\");\n        Contract.Assert(e.E1 == null);\n        e.Type = new InferredTypeProxy() { KeepConstraints = true };\n        AddXConstraint(e.tok, \"ContainerResult\", e.Seq.Type, e.Type, \"type does not agree with element type of {0} (got {1})\");\n      } else {\n        AddXConstraint(e.tok, \"MultiIndexable\", e.Seq.Type, \"multi-selection of elements requires a sequence or array (got {0})\");\n        if (e.E0 != null) {\n          ResolveExpression(e.E0, opts);\n          AddXConstraint(e.E0.tok, \"ContainerIndex\", e.Seq.Type, e.E0.Type, \"incorrect type for selection into {0} (got {1})\");\n          ConstrainSubtypeRelation(NewIntegerBasedProxy(e.tok), e.E0.Type, e.E0, \"wrong number of indices for multi-selection\");\n        }\n        if (e.E1 != null) {\n          ResolveExpression(e.E1, opts);\n          AddXConstraint(e.E1.tok, \"ContainerIndex\", e.Seq.Type, e.E1.Type, \"incorrect type for selection into {0} (got {1})\");\n          ConstrainSubtypeRelation(NewIntegerBasedProxy(e.tok), e.E1.Type, e.E1, \"wrong number of indices for multi-selection\");\n        }\n        var resultType = new InferredTypeProxy() { KeepConstraints = true };\n        e.Type = new SeqType(resultType);\n        AddXConstraint(e.tok, \"ContainerResult\", e.Seq.Type, resultType, \"type does not agree with element type of {0} (got {1})\");\n      }\n    }\n\n    /// <summary>\n    /// Note: this method is allowed to be called even if \"type\" does not make sense for \"op\", as might be the case if\n    /// resolution of the binary expression failed.  If so, an arbitrary resolved opcode is returned.\n    /// </summary>\n    public static BinaryExpr.ResolvedOpcode ResolveOp(BinaryExpr.Opcode op, Type operandType) {\n      Contract.Requires(operandType != null);\n      operandType = operandType.NormalizeExpand();\n      switch (op) {\n        case BinaryExpr.Opcode.Iff: return BinaryExpr.ResolvedOpcode.Iff;\n        case BinaryExpr.Opcode.Imp: return BinaryExpr.ResolvedOpcode.Imp;\n        case BinaryExpr.Opcode.Exp: return BinaryExpr.ResolvedOpcode.Imp;\n        case BinaryExpr.Opcode.And: return BinaryExpr.ResolvedOpcode.And;\n        case BinaryExpr.Opcode.Or: return BinaryExpr.ResolvedOpcode.Or;\n        case BinaryExpr.Opcode.Eq:\n          if (operandType is SetType) {\n            return BinaryExpr.ResolvedOpcode.SetEq;\n          } else if (operandType is MultiSetType) {\n            return BinaryExpr.ResolvedOpcode.MultiSetEq;\n          } else if (operandType is SeqType) {\n            return BinaryExpr.ResolvedOpcode.SeqEq;\n          } else if (operandType is MapType) {\n            return BinaryExpr.ResolvedOpcode.MapEq;\n          } else {\n            return BinaryExpr.ResolvedOpcode.EqCommon;\n          }\n        case BinaryExpr.Opcode.Neq:\n          if (operandType is SetType) {\n            return BinaryExpr.ResolvedOpcode.SetNeq;\n          } else if (operandType is MultiSetType) {\n            return BinaryExpr.ResolvedOpcode.MultiSetNeq;\n          } else if (operandType is SeqType) {\n            return BinaryExpr.ResolvedOpcode.SeqNeq;\n          } else if (operandType is MapType) {\n            return BinaryExpr.ResolvedOpcode.MapNeq;\n          } else {\n            return BinaryExpr.ResolvedOpcode.NeqCommon;\n          }\n        case BinaryExpr.Opcode.Disjoint:\n          if (operandType is MultiSetType) {\n            return BinaryExpr.ResolvedOpcode.MultiSetDisjoint;\n          } else if (operandType is MapType) {\n            return BinaryExpr.ResolvedOpcode.MapDisjoint;\n          } else {\n            return BinaryExpr.ResolvedOpcode.Disjoint;\n          }\n        case BinaryExpr.Opcode.Lt:\n          if (operandType.IsIndDatatype) {\n            return BinaryExpr.ResolvedOpcode.RankLt;\n          } else if (operandType is SetType) {\n            return BinaryExpr.ResolvedOpcode.ProperSubset;\n          } else if (operandType is MultiSetType) {\n            return BinaryExpr.ResolvedOpcode.ProperMultiSubset;\n          } else if (operandType is SeqType) {\n            return BinaryExpr.ResolvedOpcode.ProperPrefix;\n          } else if (operandType is CharType) {\n            return BinaryExpr.ResolvedOpcode.LtChar;\n          } else {\n            return BinaryExpr.ResolvedOpcode.Lt;\n          }\n        case BinaryExpr.Opcode.Le:\n          if (operandType is SetType) {\n            return BinaryExpr.ResolvedOpcode.Subset;\n          } else if (operandType is MultiSetType) {\n            return BinaryExpr.ResolvedOpcode.MultiSubset;\n          } else if (operandType is SeqType) {\n            return BinaryExpr.ResolvedOpcode.Prefix;\n          } else if (operandType is CharType) {\n            return BinaryExpr.ResolvedOpcode.LeChar;\n          } else {\n            return BinaryExpr.ResolvedOpcode.Le;\n          }\n        case BinaryExpr.Opcode.LeftShift:\n          return BinaryExpr.ResolvedOpcode.LeftShift;\n        case BinaryExpr.Opcode.RightShift:\n          return BinaryExpr.ResolvedOpcode.RightShift;\n        case BinaryExpr.Opcode.Add:\n          if (operandType is SetType) {\n            return BinaryExpr.ResolvedOpcode.Union;\n          } else if (operandType is MultiSetType) {\n            return BinaryExpr.ResolvedOpcode.MultiSetUnion;\n          } else if (operandType is MapType) {\n            return BinaryExpr.ResolvedOpcode.MapUnion;\n          } else if (operandType is SeqType) {\n            return BinaryExpr.ResolvedOpcode.Concat;\n          } else {\n            return BinaryExpr.ResolvedOpcode.Add;\n          }\n        case BinaryExpr.Opcode.Sub:\n          if (operandType is SetType) {\n            return BinaryExpr.ResolvedOpcode.SetDifference;\n          } else if (operandType is MultiSetType) {\n            return BinaryExpr.ResolvedOpcode.MultiSetDifference;\n          } else {\n            return BinaryExpr.ResolvedOpcode.Sub;\n          }\n        case BinaryExpr.Opcode.Mul:\n          if (operandType is SetType) {\n            return BinaryExpr.ResolvedOpcode.Intersection;\n          } else if (operandType is MultiSetType) {\n            return BinaryExpr.ResolvedOpcode.MultiSetIntersection;\n          } else {\n            return BinaryExpr.ResolvedOpcode.Mul;\n          }\n        case BinaryExpr.Opcode.Gt:\n          if (operandType.IsDatatype) {\n            return BinaryExpr.ResolvedOpcode.RankGt;\n          } else if (operandType is SetType) {\n            return BinaryExpr.ResolvedOpcode.ProperSuperset;\n          } else if (operandType is MultiSetType) {\n            return BinaryExpr.ResolvedOpcode.ProperMultiSuperset;\n          } else if (operandType is CharType) {\n            return BinaryExpr.ResolvedOpcode.GtChar;\n          } else {\n            return BinaryExpr.ResolvedOpcode.Gt;\n          }\n        case BinaryExpr.Opcode.Ge:\n          if (operandType is SetType) {\n            return BinaryExpr.ResolvedOpcode.Superset;\n          } else if (operandType is MultiSetType) {\n            return BinaryExpr.ResolvedOpcode.MultiSuperset;\n          } else if (operandType is CharType) {\n            return BinaryExpr.ResolvedOpcode.GeChar;\n          } else {\n            return BinaryExpr.ResolvedOpcode.Ge;\n          }\n        case BinaryExpr.Opcode.In:\n          if (operandType is SetType) {\n            return BinaryExpr.ResolvedOpcode.InSet;\n          } else if (operandType is MultiSetType) {\n            return BinaryExpr.ResolvedOpcode.InMultiSet;\n          } else if (operandType is MapType) {\n            return BinaryExpr.ResolvedOpcode.InMap;\n          } else {\n            return BinaryExpr.ResolvedOpcode.InSeq;\n          }\n        case BinaryExpr.Opcode.NotIn:\n          if (operandType is SetType) {\n            return BinaryExpr.ResolvedOpcode.NotInSet;\n          } else if (operandType is MultiSetType) {\n            return BinaryExpr.ResolvedOpcode.NotInMultiSet;\n          } else if (operandType is MapType) {\n            return BinaryExpr.ResolvedOpcode.NotInMap;\n          } else {\n            return BinaryExpr.ResolvedOpcode.NotInSeq;\n          }\n        case BinaryExpr.Opcode.Div: return BinaryExpr.ResolvedOpcode.Div;\n        case BinaryExpr.Opcode.Mod: return BinaryExpr.ResolvedOpcode.Mod;\n        case BinaryExpr.Opcode.BitwiseAnd: return BinaryExpr.ResolvedOpcode.BitwiseAnd;\n        case BinaryExpr.Opcode.BitwiseOr: return BinaryExpr.ResolvedOpcode.BitwiseOr;\n        case BinaryExpr.Opcode.BitwiseXor: return BinaryExpr.ResolvedOpcode.BitwiseXor;\n        default:\n          Contract.Assert(false); throw new cce.UnreachableException();  // unexpected operator\n      }\n    }\n\n    /// <summary>\n    /// Returns whether or not 'expr' has any subexpression that uses some feature (like a ghost or quantifier)\n    /// that is allowed only in specification contexts.\n    /// Requires 'expr' to be a successfully resolved expression.\n    /// </summary>\n    bool UsesSpecFeatures(Expression expr) {\n      Contract.Requires(expr != null);\n      Contract.Requires(expr.WasResolved());  // this check approximates the requirement that \"expr\" be resolved\n\n      if (expr is LiteralExpr) {\n        return false;\n      } else if (expr is ThisExpr) {\n        return false;\n      } else if (expr is MeExpr) {\n        return false;\n      } else if (expr is StoreBufferEmptyExpr) {\n        return false;\n      } else if (expr is TotalStateExpr) {\n        return false;\n      } else if (expr is IdentifierExpr) {\n        IdentifierExpr e = (IdentifierExpr)expr;\n        return cce.NonNull(e.Var).IsGhost;\n      } else if (expr is DatatypeValue) {\n        var e = (DatatypeValue)expr;\n        // check all NON-ghost arguments\n        // note that if resolution is successful, then |e.Arguments| == |e.Ctor.Formals|\n        for (int i = 0; i < e.Arguments.Count; i++) {\n          if (!e.Ctor.Formals[i].IsGhost && UsesSpecFeatures(e.Arguments[i])) {\n            return true;\n          }\n        }\n        return false;\n      } else if (expr is DisplayExpression) {\n        DisplayExpression e = (DisplayExpression)expr;\n        return e.Elements.Exists(ee => UsesSpecFeatures(ee));\n      } else if (expr is MapDisplayExpr) {\n        MapDisplayExpr e = (MapDisplayExpr)expr;\n        return e.Elements.Exists(p => UsesSpecFeatures(p.A) || UsesSpecFeatures(p.B));\n      } else if (expr is MemberSelectExpr) {\n        MemberSelectExpr e = (MemberSelectExpr) expr;\n        if (e.Member != null) {\n          return cce.NonNull(e.Member).IsGhost || UsesSpecFeatures(e.Obj);\n        } else {\n          return false;\n        }\n      } else if (expr is SeqSelectExpr) {\n        SeqSelectExpr e = (SeqSelectExpr)expr;\n        return UsesSpecFeatures(e.Seq) ||\n               (e.E0 != null && UsesSpecFeatures(e.E0)) ||\n               (e.E1 != null && UsesSpecFeatures(e.E1));\n      } else if (expr is MultiSelectExpr) {\n        MultiSelectExpr e = (MultiSelectExpr)expr;\n        return UsesSpecFeatures(e.Array) || e.Indices.Exists(ee => UsesSpecFeatures(ee));\n      } else if (expr is SeqUpdateExpr) {\n        SeqUpdateExpr e = (SeqUpdateExpr)expr;\n        return UsesSpecFeatures(e.Seq) ||\n               UsesSpecFeatures(e.Index) ||\n               UsesSpecFeatures(e.Value);\n      } else if (expr is FunctionCallExpr) {\n        var e = (FunctionCallExpr)expr;\n        if (e.Function.IsGhost) {\n          return true;\n        }\n        // check all NON-ghost arguments\n        if (UsesSpecFeatures(e.Receiver)) {\n          return true;\n        }\n        for (int i = 0; i < e.Function.Formals.Count; i++) {\n          if (!e.Function.Formals[i].IsGhost && UsesSpecFeatures(e.Args[i])) {\n            return true;\n          }\n        }\n        return false;\n      } else if (expr is ApplyExpr) {\n        ApplyExpr e = (ApplyExpr)expr;\n        return UsesSpecFeatures(e.Function) || e.Args.Exists(UsesSpecFeatures);\n      } else if (expr is OldExpr || expr is UnchangedExpr) {\n        return true;\n      } else if (expr is UnaryExpr) {\n        var e = (UnaryExpr)expr;\n        var unaryOpExpr = e as UnaryOpExpr;\n        if (unaryOpExpr != null && (unaryOpExpr.Op == UnaryOpExpr.Opcode.Fresh || unaryOpExpr.Op == UnaryOpExpr.Opcode.Allocated || unaryOpExpr.Op == UnaryOpExpr.Opcode.AllocatedArray)) {\n          return true;\n        }\n        return UsesSpecFeatures(e.E);\n      } else if (expr is BinaryExpr) {\n        BinaryExpr e = (BinaryExpr)expr;\n        switch (e.ResolvedOp_PossiblyStillUndetermined) {\n          case BinaryExpr.ResolvedOpcode.RankGt:\n          case BinaryExpr.ResolvedOpcode.RankLt:\n            return true;\n          default:\n            return UsesSpecFeatures(e.E0) || UsesSpecFeatures(e.E1);\n        }\n      } else if (expr is TernaryExpr) {\n        var e = (TernaryExpr)expr;\n        switch (e.Op) {\n          case TernaryExpr.Opcode.PrefixEqOp:\n          case TernaryExpr.Opcode.PrefixNeqOp:\n            return true;\n          default:\n            break;\n        }\n        return UsesSpecFeatures(e.E0) || UsesSpecFeatures(e.E1) || UsesSpecFeatures(e.E2);\n      } else if (expr is LetExpr) {\n        var e = (LetExpr)expr;\n        if (e.Exact) {\n          return Contract.Exists(e.RHSs, ee => UsesSpecFeatures(ee)) || UsesSpecFeatures(e.Body);\n        } else {\n          return true;  // let-such-that is always ghost\n        }\n      } else if (expr is NamedExpr) {\n        return moduleInfo.IsAbstract ? false : UsesSpecFeatures(((NamedExpr)expr).Body);\n      } else if (expr is QuantifierExpr) {\n        var e = (QuantifierExpr)expr;\n        Contract.Assert(e.SplitQuantifier == null); // No split quantifiers during resolution\n        return e.UncompilableBoundVars().Count != 0 || UsesSpecFeatures(e.LogicalBody());\n      } else if (expr is SetComprehension) {\n        var e = (SetComprehension)expr;\n        return !e.Finite || e.UncompilableBoundVars().Count != 0 || (e.Range != null && UsesSpecFeatures(e.Range)) || (e.Term != null && UsesSpecFeatures(e.Term));\n      } else if (expr is MapComprehension) {\n        var e = (MapComprehension)expr;\n        return !e.Finite || e.UncompilableBoundVars().Count != 0 || UsesSpecFeatures(e.Range) || (e.TermLeft != null && UsesSpecFeatures(e.TermLeft)) || UsesSpecFeatures(e.Term);\n      } else if (expr is LambdaExpr) {\n        var e = (LambdaExpr)expr;\n        return UsesSpecFeatures(e.Term);\n      } else if (expr is WildcardExpr) {\n        return false;\n      } else if (expr is StmtExpr) {\n        var e = (StmtExpr)expr;\n        return UsesSpecFeatures(e.E);\n      } else if (expr is ITEExpr) {\n        ITEExpr e = (ITEExpr)expr;\n        return UsesSpecFeatures(e.Test) || UsesSpecFeatures(e.Thn) || UsesSpecFeatures(e.Els);\n      } else if (expr is MatchExpr) {\n        MatchExpr me = (MatchExpr)expr;\n        if (UsesSpecFeatures(me.Source)) {\n          return true;\n        }\n        return me.Cases.Exists(mc => UsesSpecFeatures(mc.Body));\n      } else if (expr is ConcreteSyntaxExpression) {\n        var e = (ConcreteSyntaxExpression)expr;\n        return e.ResolvedExpression != null && UsesSpecFeatures(e.ResolvedExpression);\n      } else {\n        Contract.Assert(false); throw new cce.UnreachableException();  // unexpected expression\n      }\n    }\n\n\n    /// <summary>\n    /// This method adds to \"friendlyCalls\" all\n    ///     inductive calls                                   if !co\n    ///     copredicate calls and codatatype equalities       if co\n    /// that occur in positive positions and not under\n    ///     universal quantification                          if !co\n    ///     existential quantification.                       if co\n    /// If \"expr\" is the\n    ///     precondition of an inductive lemma                if !co\n    ///     postcondition of a colemma,                       if co\n    /// then the \"friendlyCalls\" are the subexpressions that need to be replaced in order\n    /// to create the\n    ///     precondition                                      if !co\n    ///     postcondition                                     if co\n    /// of the corresponding prefix lemma.\n    /// </summary>\n    void CollectFriendlyCallsInFixpointLemmaSpecification(Expression expr, bool position, ISet<Expression> friendlyCalls, bool co, FixpointLemma context) {\n      Contract.Requires(expr != null);\n      Contract.Requires(friendlyCalls != null);\n      var visitor = new CollectFriendlyCallsInSpec_Visitor(this, friendlyCalls, co, context);\n      visitor.Visit(expr, position ? CallingPosition.Positive : CallingPosition.Negative);\n    }\n\n    class CollectFriendlyCallsInSpec_Visitor : FindFriendlyCalls_Visitor\n    {\n      readonly ISet<Expression> friendlyCalls;\n      readonly FixpointLemma Context;\n      public CollectFriendlyCallsInSpec_Visitor(Resolver resolver, ISet<Expression> friendlyCalls, bool co, FixpointLemma context)\n        : base(resolver, co, context.KNat)\n      {\n        Contract.Requires(resolver != null);\n        Contract.Requires(friendlyCalls != null);\n        Contract.Requires(context != null);\n        this.friendlyCalls = friendlyCalls;\n        this.Context = context;\n      }\n      protected override bool VisitOneExpr(Expression expr, ref CallingPosition cp) {\n        if (cp == CallingPosition.Neither) {\n          // no friendly calls in \"expr\"\n          return false;  // don't recurse into subexpressions\n        }\n        if (expr is FunctionCallExpr) {\n          if (cp == CallingPosition.Positive) {\n            var fexp = (FunctionCallExpr)expr;\n            if (IsCoContext ? fexp.Function is CoPredicate : fexp.Function is InductivePredicate) {\n              if (Context.KNat != ((FixpointPredicate)fexp.Function).KNat) {\n                resolver.KNatMismatchError(expr.tok, Context.Name, Context.TypeOfK, ((FixpointPredicate)fexp.Function).TypeOfK);\n              } else {\n                friendlyCalls.Add(fexp);\n              }\n            }\n          }\n          return false;  // don't explore subexpressions any further\n        } else if (expr is BinaryExpr && IsCoContext) {\n          var bin = (BinaryExpr)expr;\n          if (cp == CallingPosition.Positive && bin.ResolvedOp == BinaryExpr.ResolvedOpcode.EqCommon && bin.E0.Type.IsCoDatatype) {\n            friendlyCalls.Add(bin);\n            return false;  // don't explore subexpressions any further\n          } else if (cp == CallingPosition.Negative && bin.ResolvedOp == BinaryExpr.ResolvedOpcode.NeqCommon && bin.E0.Type.IsCoDatatype) {\n            friendlyCalls.Add(bin);\n            return false;  // don't explore subexpressions any further\n          }\n        }\n        return base.VisitOneExpr(expr, ref cp);\n      }\n    }\n  }\n\n  class CoCallResolution\n  {\n    readonly Function currentFunction;\n    readonly bool dealsWithCodatatypes;\n    public bool HasIntraClusterCallsInDestructiveContexts = false;\n    public readonly List<CoCallInfo> FinalCandidates = new List<CoCallInfo>();\n\n    public CoCallResolution(Function currentFunction, bool dealsWithCodatatypes) {\n      Contract.Requires(currentFunction != null);\n      this.currentFunction = currentFunction;\n      this.dealsWithCodatatypes = dealsWithCodatatypes;\n    }\n\n    /// <summary>\n    /// Determines which calls in \"expr\" can be considered to be co-calls, which co-constructor\n    /// invocations host such co-calls, and which destructor operations are not allowed.\n    /// Also records whether or not there are any intra-cluster calls in a destructive context.\n    /// Assumes \"expr\" to have been successfully resolved.\n    /// </summary>\n    public void CheckCoCalls(Expression expr) {\n      Contract.Requires(expr != null);\n      CheckCoCalls(expr, 0, null, FinalCandidates);\n    }\n\n    public struct CoCallInfo\n    {\n      public readonly FunctionCallExpr CandidateCall;\n      public readonly DatatypeValue EnclosingCoConstructor;\n      public CoCallInfo(FunctionCallExpr candidateCall, DatatypeValue enclosingCoConstructor) {\n        Contract.Requires(candidateCall != null);\n        Contract.Requires(enclosingCoConstructor != null);\n        CandidateCall = candidateCall;\n        EnclosingCoConstructor = enclosingCoConstructor;\n      }\n    }\n\n    /// <summary>\n    /// Recursively goes through the entire \"expr\".  Every call within the same recursive cluster is a potential\n    /// co-call.  If the call is determined not to be a co-recursive call, then its .CoCall field is filled in;\n    /// if the situation deals with co-datatypes, then one of the NoBecause... values is chosen (rather\n    /// than just No), so that any error message that may later be produced when trying to prove termination of the\n    /// recursive call can include a note pointing out that the call was not selected to be a co-call.\n    /// If the call looks like it is guarded, then it is added to the list \"coCandicates\", so that a later analysis\n    /// can either set all of those .CoCall fields to Yes or to NoBecauseRecursiveCallsInDestructiveContext, depending\n    /// on other intra-cluster calls.\n    /// The \"destructionLevel\" indicates how many pending co-destructors the context has.  It may be infinity (int.MaxValue)\n    /// if the enclosing context has no easy way of controlling the uses of \"expr\" (for example, if the enclosing context\n    /// passes \"expr\" to a function or binds \"expr\" to a variable).  It is never negative -- excess co-constructors are\n    /// not considered an asset, and any immediately enclosing co-constructor is passed in as a non-null \"coContext\" anyway.\n    /// \"coContext\" is non-null if the immediate context is a co-constructor.\n    /// </summary>\n    void CheckCoCalls(Expression expr, int destructionLevel, DatatypeValue coContext, List<CoCallInfo> coCandidates, Function functionYouMayWishWereAbstemious = null) {\n      Contract.Requires(expr != null);\n      Contract.Requires(0 <= destructionLevel);\n      Contract.Requires(coCandidates != null);\n\n      expr = expr.Resolved;\n      if (expr is DatatypeValue) {\n        var e = (DatatypeValue)expr;\n        if (e.Ctor.EnclosingDatatype is CoDatatypeDecl) {\n          int dl = destructionLevel == int.MaxValue ? int.MaxValue : destructionLevel == 0 ? 0 : destructionLevel - 1;\n          foreach (var arg in e.Arguments) {\n            CheckCoCalls(arg, dl, e, coCandidates);\n          }\n          return;\n        }\n      } else if (expr is MemberSelectExpr) {\n        var e = (MemberSelectExpr)expr;\n        if (e.Member.EnclosingClass is CoDatatypeDecl) {\n          int dl = destructionLevel == int.MaxValue ? int.MaxValue : destructionLevel + 1;\n          CheckCoCalls(e.Obj, dl, coContext, coCandidates);\n          return;\n        }\n      } else if (expr is BinaryExpr) {\n        var e = (BinaryExpr)expr;\n        if (e.ResolvedOp == BinaryExpr.ResolvedOpcode.EqCommon || e.ResolvedOp == BinaryExpr.ResolvedOpcode.NeqCommon) {\n          // Equality and disequality (for any type that may contain a co-datatype) are as destructive as can be--in essence,\n          // they destruct the values indefinitely--so don't allow any co-recursive calls in the operands.\n          CheckCoCalls(e.E0, int.MaxValue, null, coCandidates);\n          CheckCoCalls(e.E1, int.MaxValue, null, coCandidates);\n          return;\n        }\n      } else if (expr is TernaryExpr) {\n        var e = (TernaryExpr)expr;\n        if (e.Op == TernaryExpr.Opcode.PrefixEqOp || e.Op == TernaryExpr.Opcode.PrefixNeqOp) {\n          // Prefix equality and disequality (for any type that may contain a co-datatype) are destructive.\n          CheckCoCalls(e.E0, int.MaxValue, null, coCandidates);\n          CheckCoCalls(e.E1, int.MaxValue, null, coCandidates);\n          CheckCoCalls(e.E2, int.MaxValue, null, coCandidates);\n          return;\n        }\n      } else if (expr is MatchExpr) {\n        var e = (MatchExpr)expr;\n        CheckCoCalls(e.Source, int.MaxValue, null, coCandidates);\n        foreach (var kase in e.Cases) {\n          CheckCoCalls(kase.Body, destructionLevel, coContext, coCandidates);\n        }\n        return;\n      } else if (expr is ITEExpr) {\n        var e = (ITEExpr)expr;\n        CheckCoCalls(e.Test, int.MaxValue, null, coCandidates);\n        CheckCoCalls(e.Thn, destructionLevel, coContext, coCandidates);\n        CheckCoCalls(e.Els, destructionLevel, coContext, coCandidates);\n        return;\n      } else if (expr is FunctionCallExpr) {\n        var e = (FunctionCallExpr)expr;\n        // First, consider the arguments of the call, making sure that they do not include calls within the recursive cluster,\n        // unless the callee is abstemious.\n        var abstemious = true;\n        if (!Attributes.ContainsBool(e.Function.Attributes, \"abstemious\", ref abstemious)) {\n          abstemious = false;\n        }\n        Contract.Assert(e.Args.Count == e.Function.Formals.Count);\n        for (var i = 0; i < e.Args.Count; i++) {\n          var arg = e.Args[i];\n          if (!e.Function.Formals[i].Type.IsCoDatatype) {\n            CheckCoCalls(arg, int.MaxValue, null, coCandidates);\n          } else if (abstemious) {\n            CheckCoCalls(arg, 0, coContext, coCandidates);\n          } else {\n            // don't you wish the callee were abstemious\n            CheckCoCalls(arg, int.MaxValue, null, coCandidates, e.Function);\n          }\n        }\n        // Second, investigate the possibility that this call itself may be a candidate co-call\n        if (e.Name != \"requires\" && ModuleDefinition.InSameSCC(currentFunction, e.Function)) {\n          // This call goes to another function in the same recursive cluster\n          if (destructionLevel != 0 && GuaranteedCoCtors(e.Function) <= destructionLevel) {\n            // a potentially destructive context\n            HasIntraClusterCallsInDestructiveContexts = true;  // this says we found an intra-cluster call unsuitable for recursion, if there were any co-recursive calls\n            if (!dealsWithCodatatypes) {\n              e.CoCall = FunctionCallExpr.CoCallResolution.No;\n            } else {\n              e.CoCall = FunctionCallExpr.CoCallResolution.NoBecauseRecursiveCallsAreNotAllowedInThisContext;\n              if (functionYouMayWishWereAbstemious != null) {\n                e.CoCallHint = string.Format(\"perhaps try declaring function '{0}' with '{{:abstemious}}'\", functionYouMayWishWereAbstemious.Name);\n              }\n            }\n          } else if (coContext == null) {\n            // no immediately enclosing co-constructor\n            if (!dealsWithCodatatypes) {\n              e.CoCall = FunctionCallExpr.CoCallResolution.No;\n            } else {\n              e.CoCall = FunctionCallExpr.CoCallResolution.NoBecauseIsNotGuarded;\n            }\n          } else if (e.Function.Reads.Count != 0) {\n            // this call is disqualified from being a co-call, because of side effects\n            if (!dealsWithCodatatypes) {\n              e.CoCall = FunctionCallExpr.CoCallResolution.No;\n            } else {\n              e.CoCall = FunctionCallExpr.CoCallResolution.NoBecauseFunctionHasSideEffects;\n            }\n          } else if (e.Function.Ens.Count != 0) {\n            // this call is disqualified from being a co-call, because it has a postcondition\n            // (a postcondition could be allowed, as long as it does not get to be used with\n            // co-recursive calls, because that could be unsound; for example, consider\n            // \"ensures false\")\n            if (!dealsWithCodatatypes) {\n              e.CoCall = FunctionCallExpr.CoCallResolution.No;\n            } else {\n              e.CoCall = FunctionCallExpr.CoCallResolution.NoBecauseFunctionHasPostcondition;\n            }\n          } else {\n            // e.CoCall is not filled in here, but will be filled in when the list of candidates are processed\n            coCandidates.Add(new CoCallInfo(e, coContext));\n          }\n        }\n        return;\n      } else if (expr is LambdaExpr) {\n        var e = (LambdaExpr)expr;\n        CheckCoCalls(e.Body, destructionLevel, coContext, coCandidates);\n        if (e.Range != null) {\n          CheckCoCalls(e.Range, int.MaxValue, null, coCandidates);\n        }\n        foreach (var read in e.Reads) {\n          CheckCoCalls(read.E, int.MaxValue, null, coCandidates);\n        }\n        return;\n      } else if (expr is MapComprehension) {\n        var e = (MapComprehension)expr;\n        foreach (var ee in Attributes.SubExpressions(e.Attributes)) {\n          CheckCoCalls(ee, int.MaxValue, null, coCandidates);\n        }\n        if (e.Range != null) {\n          CheckCoCalls(e.Range, int.MaxValue, null, coCandidates);\n        }\n        // allow co-calls in the term\n        if (e.TermLeft != null) {\n          CheckCoCalls(e.TermLeft, destructionLevel, coContext, coCandidates);\n        }\n        CheckCoCalls(e.Term, destructionLevel, coContext, coCandidates);\n        return;\n      } else if (expr is OldExpr) {\n        var e = (OldExpr)expr;\n        // here, \"coContext\" is passed along (the use of \"old\" says this must be ghost code, so the compiler does not need to handle this case)\n        CheckCoCalls(e.E, destructionLevel, coContext, coCandidates);\n        return;\n      } else if (expr is LetExpr) {\n        var e = (LetExpr)expr;\n        foreach (var rhs in e.RHSs) {\n          CheckCoCalls(rhs, int.MaxValue, null, coCandidates);\n        }\n        CheckCoCalls(e.Body, destructionLevel, coContext, coCandidates);\n        return;\n      } else if (expr is ApplyExpr) {\n        var e = (ApplyExpr)expr;\n        CheckCoCalls(e.Function, int.MaxValue, null, coCandidates);\n        foreach (var ee in e.Args) {\n          CheckCoCalls(ee, destructionLevel, null, coCandidates);\n        }\n        return;\n      }\n\n      // Default handling:\n      foreach (var ee in expr.SubExpressions) {\n        CheckCoCalls(ee, destructionLevel, null, coCandidates);\n      }\n    }\n\n    public static int GuaranteedCoCtors(Function function) {\n      Contract.Requires(function != null);\n      return function.Body != null ? GuaranteedCoCtorsAux(function.Body) : 0;\n    }\n\n    private static int GuaranteedCoCtorsAux(Expression expr) {\n      Contract.Requires(expr != null);\n      expr = expr.Resolved;\n      if (expr is DatatypeValue) {\n        var e = (DatatypeValue)expr;\n        if (e.Ctor.EnclosingDatatype is CoDatatypeDecl) {\n          var minOfArgs = int.MaxValue;  // int.MaxValue means: not yet encountered a formal whose type is a co-datatype\n          Contract.Assert(e.Arguments.Count == e.Ctor.Formals.Count);\n          for (var i = 0; i < e.Arguments.Count; i++) {\n            if (e.Ctor.Formals[i].Type.IsCoDatatype) {\n              var n = GuaranteedCoCtorsAux(e.Arguments[i]);\n              minOfArgs = Math.Min(minOfArgs, n);\n            }\n          }\n          return minOfArgs == int.MaxValue ? 1 : 1 + minOfArgs;\n        }\n      } else if (expr is ITEExpr) {\n        var e = (ITEExpr)expr;\n        var thn = GuaranteedCoCtorsAux(e.Thn);\n        var els = GuaranteedCoCtorsAux(e.Els);\n        return thn < els ? thn : els;\n      } else if (expr is MatchExpr) {\n        var e = (MatchExpr)expr;\n        var min = int.MaxValue;\n        foreach (var kase in e.Cases) {\n          var n = GuaranteedCoCtorsAux(kase.Body);\n          min = Math.Min(min, n);\n        }\n        return min == int.MaxValue ? 0 : min;\n      } else if (expr is LetExpr) {\n        var e = (LetExpr)expr;\n        return GuaranteedCoCtorsAux(e.Body);\n      } else if (expr is IdentifierExpr) {\n        var e = (IdentifierExpr)expr;\n        if (e.Type.IsCoDatatype && e.Var is Formal) {\n          // even though this is not a co-constructor, count this as 1, since that's what we would have done if it were, e.g., \"Cons(s.head, s.tail)\" instead of \"s\"\n          return 1;\n        }\n      }\n      return 0;\n    }\n  }\n\n  class Scope<Thing> where Thing : class\n  {\n    [Rep]\n    readonly List<string> names = new List<string>();  // a null means a marker\n    [Rep]\n    readonly List<Thing> things = new List<Thing>();\n    [ContractInvariantMethod]\n    void ObjectInvariant() {\n      Contract.Invariant(names != null);\n      Contract.Invariant(things != null);\n      Contract.Invariant(names.Count == things.Count);\n      Contract.Invariant(-1 <= scopeSizeWhereInstancesWereDisallowed && scopeSizeWhereInstancesWereDisallowed <= names.Count);\n    }\n\n    int scopeSizeWhereInstancesWereDisallowed = -1;\n\n    public bool AllowInstance {\n      get { return scopeSizeWhereInstancesWereDisallowed == -1; }\n      set {\n        Contract.Requires(AllowInstance && !value);  // only allowed to change from true to false (that's all that's currently needed in Dafny); Pop is what can make the change in the other direction\n        scopeSizeWhereInstancesWereDisallowed = names.Count;\n      }\n    }\n\n    public void PushMarker() {\n      names.Add(null);\n      things.Add(null);\n    }\n\n    public void PopMarker() {\n      int n = names.Count;\n      while (true) {\n        n--;\n        if (names[n] == null) {\n          break;\n        }\n      }\n      names.RemoveRange(n, names.Count - n);\n      things.RemoveRange(n, things.Count - n);\n      if (names.Count < scopeSizeWhereInstancesWereDisallowed) {\n        scopeSizeWhereInstancesWereDisallowed = -1;\n      }\n    }\n\n    public enum PushResult { Duplicate, Shadow, Success }\n\n    /// <summary>\n    /// Pushes name-->thing association and returns \"Success\", if name has not already been pushed since the last marker.\n    /// If name already has been pushed since the last marker, does nothing and returns \"Duplicate\".\n    /// If the appropriate command-line option is supplied, then this method will also check if \"name\" shadows a previous\n    /// name; if it does, then it will return \"Shadow\" instead of \"Success\".\n    /// </summary>\n    public PushResult Push(string name, Thing thing) {\n      Contract.Requires(name != null);\n      Contract.Requires(thing != null);\n      if (Find(name, true) != null) {\n        return PushResult.Duplicate;\n      } else {\n        var r = PushResult.Success;\n        if (ArmadaOptions.O.WarnShadowing && Find(name, false) != null) {\n          r = PushResult.Shadow;\n        }\n        names.Add(name);\n        things.Add(thing);\n        return r;\n      }\n    }\n\n    Thing Find(string name, bool topScopeOnly) {\n      Contract.Requires(name != null);\n      for (int n = names.Count; 0 <= --n; ) {\n        if (names[n] == null) {\n          if (topScopeOnly) {\n            return null;  // not present\n          }\n        } else if (names[n] == name) {\n          Thing t = things[n];\n          Contract.Assert(t != null);\n          return t;\n        }\n      }\n      return null;  // not present\n    }\n\n    public Thing Find(string name) {\n      Contract.Requires(name != null);\n      return Find(name, false);\n    }\n\n    public Thing FindInCurrentScope(string name) {\n      Contract.Requires(name != null);\n      return Find(name, true);\n    }\n\n    public bool ContainsDecl(Thing t) {\n      return things.Exists(thing => thing == t);\n    }\n  }\n}\n"
  },
  {
    "path": "Source/Armada/Rewriter.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics.Contracts;\nusing System.Text;\nusing static Microsoft.Armada.Predicate;\nusing Bpl = Microsoft.Boogie;\nusing IToken = Microsoft.Boogie.IToken;\nusing Token = Microsoft.Boogie.Token;\n\nnamespace Microsoft.Armada {\n  public abstract class IRewriter\n  {\n    protected readonly ErrorReporter reporter;\n\n    public IRewriter(ErrorReporter reporter) {\n      Contract.Requires(reporter != null);\n      this.reporter = reporter;\n    }\n\n    internal virtual void PreResolve(ModuleDefinition m) {\n      Contract.Requires(m != null);\n    }\n\n    internal virtual void PostResolve(ModuleDefinition m) {\n      Contract.Requires(m != null);\n    }\n\n    // After SCC/Cyclicity/Recursivity analysis:\n    internal virtual void PostCyclicityResolve(ModuleDefinition m) {\n      Contract.Requires(m != null);\n    }\n  }\n\n  public class AutoGeneratedToken : TokenWrapper\n  {\n    public AutoGeneratedToken(Boogie.IToken wrappedToken)\n      : base(wrappedToken)\n    {\n      Contract.Requires(wrappedToken != null);\n    }\n  }\n\n  public class TriggerGeneratingRewriter : IRewriter {\n    internal TriggerGeneratingRewriter(ErrorReporter reporter) : base(reporter) {\n      Contract.Requires(reporter != null);\n    }\n\n    internal override void PostCyclicityResolve(ModuleDefinition m) {\n      var finder = new Triggers.QuantifierCollector(reporter);\n\n      foreach (var decl in ModuleDefinition.AllCallables(m.TopLevelDecls)) {\n        finder.Visit(decl, null);\n      }\n\n      var triggersCollector = new Triggers.TriggersCollector(finder.exprsInOldContext);\n      foreach (var quantifierCollection in finder.quantifierCollections) {\n        quantifierCollection.ComputeTriggers(triggersCollector);\n        quantifierCollection.CommitTriggers();\n      }\n    }\n  }\n\n  internal class QuantifierSplittingRewriter : IRewriter {\n    internal QuantifierSplittingRewriter(ErrorReporter reporter) : base(reporter) {\n      Contract.Requires(reporter != null);\n    }\n\n    internal override void PostResolve(ModuleDefinition m) {\n      var splitter = new Triggers.QuantifierSplitter();\n      foreach (var decl in ModuleDefinition.AllCallables(m.TopLevelDecls)) {\n        splitter.Visit(decl);\n      }\n      splitter.Commit();\n    }\n  }\n\n  // write out the quantifier for ForallStmt\n  public class ForallStmtRewriter : IRewriter\n  {\n    public ForallStmtRewriter(ErrorReporter reporter) : base(reporter) {\n      Contract.Requires(reporter != null);\n    }\n\n    internal override void PostResolve(ModuleDefinition m) {\n      var forallvisiter = new ForAllStmtVisitor(reporter);\n      foreach (var decl in ModuleDefinition.AllCallables(m.TopLevelDecls)) {\n        forallvisiter.Visit(decl, true);\n        if (decl is FixpointLemma) {\n          var prefixLemma = ((FixpointLemma)decl).PrefixLemma;\n          if (prefixLemma != null) {\n            forallvisiter.Visit(prefixLemma, true);\n          }\n        }\n      }\n\n    }\n\n    internal class ForAllStmtVisitor : TopDownVisitor<bool>\n    {\n      readonly ErrorReporter reporter;\n      public ForAllStmtVisitor(ErrorReporter reporter) {\n        Contract.Requires(reporter != null);\n        this.reporter = reporter;\n      }\n      protected override bool VisitOneStmt(Statement stmt, ref bool st) {\n        if (stmt is ForallStmt && ((ForallStmt)stmt).CanConvert) {\n          ForallStmt s = (ForallStmt)stmt;\n          if (s.Kind == ForallStmt.BodyKind.Proof) {\n            Expression term = s.Ens.Count != 0 ? s.Ens[0].E : Expression.CreateBoolLiteral(s.Tok, true);\n            for (int i = 1; i < s.Ens.Count; i++) {\n              term = new BinaryExpr(s.Tok, BinaryExpr.ResolvedOpcode.And, term, s.Ens[i].E);\n            }\n            List<Expression> exprList = new List<Expression>();\n            ForallExpr expr = new ForallExpr(s.Tok, s.BoundVars, s.Range, term, s.Attributes);\n            expr.Type = Type.Bool; // resolve here\n            expr.Bounds = s.Bounds;\n            exprList.Add(expr);\n            s.ForallExpressions = exprList;\n          } else if (s.Kind == ForallStmt.BodyKind.Assign) {\n            if (s.BoundVars.Count != 0) {\n              var s0 = (AssignStmt)s.S0;\n              if (s0.Rhs is ExprRhs) {\n                List<Expression> exprList = new List<Expression>();\n                Expression Fi = null;\n                Func<Expression, Expression> lhsBuilder = null;\n                var lhs = s0.Lhs.Resolved;\n                var i = s.BoundVars[0];\n                if (s.BoundVars.Count == 1) {\n                  //var lhsContext = null;\n                  // Detect the following cases:\n                  //   0: forall i | R(i) { F(i).f := E(i); }\n                  //   1: forall i | R(i) { A[F(i)] := E(i); }\n                  //   2: forall i | R(i) { F(i)[N] := E(i); }\n                  if (lhs is MemberSelectExpr) {\n                    var ll = (MemberSelectExpr)lhs;\n                    Fi = ll.Obj;\n                    lhsBuilder = e => {\n                      var l = new MemberSelectExpr(ll.tok, e, ll.MemberName);\n                      l.Member = ll.Member; l.TypeApplication = ll.TypeApplication; l.Type = ll.Type;\n                      return l; };\n                  } else if (lhs is SeqSelectExpr) {\n                    var ll = (SeqSelectExpr)lhs;\n                    Contract.Assert(ll.SelectOne);\n                    if (!Translator.ContainsFreeVariable(ll.Seq, false, i)) {\n                      Fi = ll.E0;\n                      lhsBuilder = e => { var l = new SeqSelectExpr(ll.tok, true, ll.Seq, e, null); l.Type = ll.Type; return l; };\n                    } else if (!Translator.ContainsFreeVariable(ll.E0, false, i)) {\n                      Fi = ll.Seq;\n                      lhsBuilder = e => { var l = new SeqSelectExpr(ll.tok, true, e, ll.E0, null); l.Type = ll.Type; return l; };\n                    }\n                  }\n                }\n                var rhs = ((ExprRhs)s0.Rhs).Expr;\n                bool usedInversion = false;\n                if (Fi != null) {\n                  var j = new BoundVar(i.tok, i.Name + \"#inv\", Fi.Type);\n                  var jj = Expression.CreateIdentExpr(j);\n                  var jList = new List<BoundVar>() { j };\n                  var range = Expression.CreateAnd(Resolver.GetImpliedTypeConstraint(i, i.Type), s.Range);\n                  var vals = InvertExpression(i, j, range, Fi);\n#if DEBUG_PRINT\n          Console.WriteLine(\"DEBUG: Trying to invert:\");\n          Console.WriteLine(\"DEBUG:   \" + Printer.ExprToString(s.Range) + \" && \" + j.Name + \" == \" + Printer.ExprToString(Fi));\n          if (vals == null) {\n            Console.WriteLine(\"DEBUG: Can't\");\n          } else {\n            Console.WriteLine(\"DEBUG: The inverse is the disjunction of the following:\");\n            foreach (var val in vals) {\n              Console.WriteLine(\"DEBUG:   \" + Printer.ExprToString(val.Range) + \" && \" + Printer.ExprToString(val.FInverse) + \" == \" + i.Name);\n            }\n          }\n#endif\n                  if (vals != null) {\n                    foreach (var val in vals) {\n                      lhs = lhsBuilder(jj);\n                      Attributes attributes = new Attributes(\"trigger\", new List<Expression>() { lhs }, s.Attributes);\n                      var newRhs = Substitute(rhs, i, val.FInverse);\n                      var msg = string.Format(\"rewrite: forall {0}: {1} {2}| {3} {{ {4} := {5}; }}\",\n                        j.Name,\n                        j.Type.ToString(),\n                        Printer.AttributesToString(attributes),\n                        Printer.ExprToString(val.Range),\n                        Printer.ExprToString(lhs),\n                        Printer.ExprToString(newRhs));\n                      reporter.Info(MessageSource.Resolver, stmt.Tok, msg);\n\n                      var expr = new ForallExpr(s.Tok, jList, val.Range, new BinaryExpr(s.Tok, BinaryExpr.ResolvedOpcode.EqCommon, lhs, newRhs), attributes);\n                      expr.Type = Type.Bool; //resolve here\n                      exprList.Add(expr);\n                    }\n                    usedInversion = true;\n                  }\n                }\n                if (!usedInversion) {\n                  var expr = new ForallExpr(s.Tok, s.BoundVars, s.Range, new BinaryExpr(s.Tok, BinaryExpr.ResolvedOpcode.EqCommon, lhs, rhs), s.Attributes);\n                  expr.Type = Type.Bool; // resolve here\n                  expr.Bounds = s.Bounds;\n                  exprList.Add(expr);\n                }\n                s.ForallExpressions = exprList;\n              }\n            }\n          } else if (s.Kind == ForallStmt.BodyKind.Call) {\n            var s0 = (CallStmt)s.S0;\n            var argsSubstMap = new Dictionary<IVariable, Expression>();  // maps formal arguments to actuals\n            Contract.Assert(s0.Method.Ins.Count == s0.Args.Count);\n            for (int i = 0; i < s0.Method.Ins.Count; i++) {\n              argsSubstMap.Add(s0.Method.Ins[i], s0.Args[i]);\n            }\n            var substituter = new Translator.AlphaConverting_Substituter(s0.Receiver, argsSubstMap, s0.MethodSelect.TypeArgumentSubstitutions());\n            // Strengthen the range of the \"forall\" statement with the precondition of the call, suitably substituted with the actual parameters.\n            if (Attributes.Contains(s.Attributes, \"_autorequires\")) {\n              var range = s.Range;\n              foreach (var req in s0.Method.Req) {\n                if (!req.IsFree) {\n                  var p = substituter.Substitute(req.E);  // substitute the call's actuals for the method's formals\n                  range = Expression.CreateAnd(range, p);\n                }\n              }\n              s.Range = range;\n            }\n            // substitute the call's actuals for the method's formals\n            Expression term = s0.Method.Ens.Count != 0 ? substituter.Substitute(s0.Method.Ens[0].E) : Expression.CreateBoolLiteral(s.Tok, true);\n            for (int i = 1; i < s0.Method.Ens.Count; i++) {\n              term = new BinaryExpr(s.Tok, BinaryExpr.ResolvedOpcode.And, term, substituter.Substitute(s0.Method.Ens[i].E));\n            }\n            List<Expression> exprList = new List<Expression>();\n            ForallExpr expr = new ForallExpr(s.Tok, s.BoundVars, s.Range, term, s.Attributes);\n            expr.Type = Type.Bool; // resolve here\n            expr.Bounds = s.Bounds;\n            exprList.Add(expr);\n            s.ForallExpressions = exprList;\n          } else {\n            Contract.Assert(false);  // unexpected kind\n          }\n        }\n        return true;  //visit the sub-parts with the same \"st\"\n      }\n\n      internal class ForallStmtTranslationValues\n      {\n        public readonly Expression Range;\n        public readonly Expression FInverse;\n        public ForallStmtTranslationValues(Expression range, Expression fInverse) {\n          Contract.Requires(range != null);\n          Contract.Requires(fInverse != null);\n          Range = range;\n          FInverse = fInverse;\n        }\n        public ForallStmtTranslationValues Subst(IVariable j, Expression e) {\n          Contract.Requires(j != null);\n          Contract.Requires(e != null);\n          Dictionary<TypeParameter, Type> typeMap = new Dictionary<TypeParameter, Type>();\n          var substMap = new Dictionary<IVariable, Expression>();\n          substMap.Add(j, e);\n          Translator.Substituter sub = new Translator.Substituter(null, substMap, typeMap);\n          var v = new ForallStmtTranslationValues(sub.Substitute(Range), sub.Substitute(FInverse));\n          return v;\n        }\n      }\n\n      /// <summary>\n      /// Find piecewise inverse of F under R.  More precisely, find lists of expressions P and F-1\n      /// such that\n      ///     R(i) && j == F(i)\n      /// holds iff the disjunction of the following predicates holds:\n      ///     P_0(j) && F-1_0(j) == i\n      ///     ...\n      ///     P_{n-1}(j) && F-1_{n-1}(j) == i\n      /// If no such disjunction is found, return null.\n      /// If such a disjunction is found, return for each disjunct:\n      ///     * The predicate P_k(j), which is an expression that may have free occurrences of j (but no free occurrences of i)\n      ///     * The expression F-1_k(j), which also may have free occurrences of j but not of i\n      /// </summary>\n      private List<ForallStmtTranslationValues> InvertExpression(BoundVar i, BoundVar j, Expression R, Expression F) {\n        Contract.Requires(i != null);\n        Contract.Requires(j != null);\n        Contract.Requires(R != null);\n        Contract.Requires(F != null);\n        var vals = new List<ForallStmtTranslationValues>(InvertExpressionIter(i, j, R, F));\n        if (vals.Count == 0) {\n          return null;\n        } else {\n          return vals;\n        }\n      }\n      /// <summary>\n      /// See InvertExpression.\n      /// </summary>\n      private IEnumerable<ForallStmtTranslationValues> InvertExpressionIter(BoundVar i, BoundVar j, Expression R, Expression F) {\n        Contract.Requires(i != null);\n        Contract.Requires(j != null);\n        Contract.Requires(R != null);\n        Contract.Requires(F != null);\n        F = F.Resolved;\n        if (!Translator.ContainsFreeVariable(F, false, i)) {\n          // We're looking at R(i) && j == K.\n          // We cannot invert j == K, but if we're lucky, R(i) contains a conjunct i==G.\n          Expression r = Expression.CreateBoolLiteral(R.tok, true);\n          Expression G = null;\n          foreach (var c in Expression.Conjuncts(R)) {\n            if (G == null && c is BinaryExpr) {\n              var bin = (BinaryExpr)c;\n              if (BinaryExpr.IsEqualityOp(bin.ResolvedOp)) {\n                var id = bin.E0.Resolved as IdentifierExpr;\n                if (id != null && id.Var == i) {\n                  G = bin.E1;\n                  continue;\n                }\n                id = bin.E1.Resolved as IdentifierExpr;\n                if (id != null && id.Var == i) {\n                  G = bin.E0;\n                  continue;\n                }\n              }\n            }\n            r = Expression.CreateAnd(r, c);\n          }\n          if (G != null) {\n            var jIsK = Expression.CreateEq(Expression.CreateIdentExpr(j), F, j.Type);\n            var rr = Substitute(r, i, G);\n            yield return new ForallStmtTranslationValues(Expression.CreateAnd(rr, jIsK), G);\n          }\n        } else if (F is IdentifierExpr) {\n          var e = (IdentifierExpr)F;\n          if (e.Var == i) {\n            // We're looking at R(i) && j == i, which is particularly easy to invert:  R(j) && j == i\n            var jj = Expression.CreateIdentExpr(j);\n            yield return new ForallStmtTranslationValues(Substitute(R, i, jj), jj);\n          }\n        } else if (F is BinaryExpr) {\n          var bin = (BinaryExpr)F;\n          if (bin.ResolvedOp == BinaryExpr.ResolvedOpcode.Add && (bin.E0.Type.IsIntegerType || bin.E0.Type.IsRealType)) {\n            if (!Translator.ContainsFreeVariable(bin.E1, false, i)) {\n              // We're looking at:  R(i) && j == f(i) + K.\n              // By a recursive call, we'll ask to invert:  R(i) && j' == f(i).\n              // For each P_0(j') && f-1_0(j') == i we get back, we yield:\n              // P_0(j - K) && f-1_0(j - K) == i\n              var jMinusK = Expression.CreateSubtract(Expression.CreateIdentExpr(j), bin.E1);\n              foreach (var val in InvertExpression(i, j, R, bin.E0)) {\n                yield return val.Subst(j, jMinusK);\n              }\n            } else if (!Translator.ContainsFreeVariable(bin.E0, false, i)) {\n              // We're looking at:  R(i) && j == K + f(i)\n              // Do as in previous case, but with operands reversed.\n              var jMinusK = Expression.CreateSubtract(Expression.CreateIdentExpr(j), bin.E0);\n              foreach (var val in InvertExpression(i, j, R, bin.E1)) {\n                yield return val.Subst(j, jMinusK);\n              }\n            }\n          } else if (bin.ResolvedOp == BinaryExpr.ResolvedOpcode.Sub && (bin.E0.Type.IsIntegerType || bin.E0.Type.IsRealType)) {\n            if (!Translator.ContainsFreeVariable(bin.E1, false, i)) {\n              // We're looking at:  R(i) && j == f(i) - K\n              // Recurse on f(i) and then replace j := j + K\n              var jPlusK = Expression.CreateAdd(Expression.CreateIdentExpr(j), bin.E1);\n              foreach (var val in InvertExpression(i, j, R, bin.E0)) {\n                yield return val.Subst(j, jPlusK);\n              }\n            } else if (!Translator.ContainsFreeVariable(bin.E0, false, i)) {\n              // We're looking at:  R(i) && j == K - f(i)\n              // Recurse on f(i) and then replace j := K - j\n              var kMinusJ = Expression.CreateSubtract(bin.E0, Expression.CreateIdentExpr(j));\n              foreach (var val in InvertExpression(i, j, R, bin.E1)) {\n                yield return val.Subst(j, kMinusJ);\n              }\n            }\n          }\n        } else if (F is ITEExpr) {\n          var ife = (ITEExpr)F;\n          // We're looking at R(i) && j == if A(i) then B(i) else C(i), which is equivalent to the disjunction of:\n          //   R(i) && A(i) && j == B(i)\n          //   R(i) && !A(i) && j == C(i)\n          // We recurse on each one, yielding the results\n          var r = Expression.CreateAnd(R, ife.Test);\n          var valsThen = InvertExpression(i, j, r, ife.Thn);\n          if (valsThen != null) {\n            r = Expression.CreateAnd(R, Expression.CreateNot(ife.tok, ife.Test));\n            var valsElse = InvertExpression(i, j, r, ife.Els);\n            if (valsElse != null) {\n              foreach (var val in valsThen) { yield return val; }\n              foreach (var val in valsElse) { yield return val; }\n            }\n          }\n        }\n      }\n\n      Expression Substitute(Expression expr, IVariable v, Expression e) {\n        Dictionary<IVariable, Expression/*!*/> substMap = new Dictionary<IVariable, Expression>();\n        Dictionary<TypeParameter, Type> typeMap = new Dictionary<TypeParameter, Type>();\n        substMap.Add(v, e);\n        Translator.Substituter sub = new Translator.Substituter(null, substMap, typeMap);\n        return sub.Substitute(expr);\n      }\n    }\n  }\n\n  /// <summary>\n  /// AutoContracts is an experimental feature that will fill much of the dynamic-frames boilerplate\n  /// into a class.  From the user's perspective, what needs to be done is simply:\n  ///  - mark the class with {:autocontracts}\n  ///  - declare a function (or predicate) called Valid()\n  ///\n  /// AutoContracts will then:\n  ///\n  /// Declare, unless there already exist members with these names:\n  ///    ghost var Repr: set(object)\n  ///    predicate Valid()\n  ///\n  /// For function/predicate Valid(), insert:\n  ///    reads this, Repr\n  /// Into body of Valid(), insert (at the beginning of the body):\n  ///    this in Repr && null !in Repr\n  /// and also insert, for every array-valued field A declared in the class:\n  ///    (A != null ==> A in Repr) &&\n  /// and for every field F of a class type T where T has a field called Repr, also insert:\n  ///    (F != null ==> F in Repr && F.Repr SUBSET Repr && this !in Repr && F.Valid())\n  /// Except, if A or F is declared with {:autocontracts false}, then the implication will not\n  /// be added.\n  ///\n  /// For every constructor, add:\n  ///    ensures Valid() && fresh(Repr - {this})\n  /// At the end of the body of the constructor, add:\n  ///    Repr := {this};\n  ///    if (A != null) { Repr := Repr + {A}; }\n  ///    if (F != null) { Repr := Repr + {F} + F.Repr; }\n  ///\n  /// In all the following cases, no \"modifies\" clause or \"reads\" clause is added if the user\n  /// has given one.\n  ///\n  /// For every non-static non-ghost method that is not a \"simple query method\",\n  /// add:\n  ///    requires Valid()\n  ///    modifies Repr\n  ///    ensures Valid() && fresh(Repr - old(Repr))\n  /// At the end of the body of the method, add:\n  ///    if (A != null && !(A in Repr)) { Repr := Repr + {A}; }\n  ///    if (F != null && !(F in Repr && F.Repr SUBSET Repr)) { Repr := Repr + {F} + F.Repr; }\n  /// For every non-static non-twostate method that is either ghost or is a \"simple query method\",\n  /// add:\n  ///    requires Valid()\n  /// For every non-static twostate method, add:\n  ///    requires old(Valid())\n  ///\n  /// For every non-\"Valid\" non-static function, add:\n  ///    requires Valid()\n  ///    reads Repr\n  /// </summary>\n  public class AutoContractsRewriter : IRewriter\n  {\n    readonly BuiltIns builtIns;\n    public AutoContractsRewriter(ErrorReporter reporter, BuiltIns builtIns)\n      : base(reporter) {\n      Contract.Requires(reporter != null);\n      Contract.Requires(builtIns != null);\n      this.builtIns = builtIns;\n    }\n\n    internal override void PreResolve(ModuleDefinition m) {\n      foreach (var d in m.TopLevelDecls) {\n        bool sayYes = true;\n        if (d is ClassDecl && Attributes.ContainsBool(d.Attributes, \"autocontracts\", ref sayYes) && sayYes) {\n          ProcessClassPreResolve((ClassDecl)d);\n        }\n      }\n    }\n\n    void ProcessClassPreResolve(ClassDecl cl) {\n      // Add:  ghost var Repr: set<object>\n      // ...unless a field with that name is already present\n      if (!cl.Members.Exists(member => member is Field && member.Name == \"Repr\")) {\n        Type ty = new SetType(true, builtIns.ObjectQ());\n        var repr = new Field(new AutoGeneratedToken(cl.tok), \"Repr\", true, ty, null);\n        cl.Members.Add(repr);\n        AddHoverText(cl.tok, \"{0}\", Printer.FieldToString(repr));\n      }\n      // Add:  predicate Valid()\n      // ...unless an instance function with that name is already present\n      if (!cl.Members.Exists(member => member is Function && member.Name == \"Valid\" && !member.IsStatic)) {\n        var valid = new Predicate(cl.tok, \"Valid\", false, false, true, new List<TypeParameter>(), new List<Formal>(),\n          new List<MaybeFreeExpression>(), new List<FrameExpression>(), new List<MaybeFreeExpression>(), new Specification<Expression>(new List<Expression>(), null),\n          null, Predicate.BodyOriginKind.OriginalOrInherited, null, null);\n        cl.Members.Add(valid);\n        // It will be added to hover text later\n      }\n\n      foreach (var member in cl.Members) {\n        bool sayYes = true;\n        if (Attributes.ContainsBool(member.Attributes, \"autocontracts\", ref sayYes) && !sayYes) {\n          // the user has excluded this member\n          continue;\n        }\n        if (member.RefinementBase != null) {\n          // member is inherited from a module where it was already processed\n          continue;\n        }\n        Boogie.IToken tok = new AutoGeneratedToken(member.tok);\n        if (member is Function && member.Name == \"Valid\" && !member.IsStatic) {\n          var valid = (Function)member;\n          // reads this, Repr\n          var r0 = new ThisExpr(tok);\n          var r1 = new MemberSelectExpr(tok, new ImplicitThisExpr(tok), \"Repr\");\n          valid.Reads.Add(new FrameExpression(tok, r0, null));\n          valid.Reads.Add(new FrameExpression(tok, r1, null));\n          if (member.tok == cl.tok) {\n            // We added this function above, so produce a hover text for the entire function signature\n            AddHoverText(cl.tok, \"{0}\", Printer.FunctionSignatureToString(valid));\n          } else {\n            AddHoverText(member.tok, \"reads {0}, {1}\", r0, r1);\n          }\n        } else if (member is Function && !member.IsStatic) {\n          var f = (Function)member;\n          // requires Valid()\n          var valid = new FunctionCallExpr(tok, \"Valid\", new ImplicitThisExpr(tok), tok, new List<Expression>());\n          f.Req.Insert(0, new MaybeFreeExpression(valid));\n          var format = \"requires {0}\";\n          var repr = new MemberSelectExpr(tok, new ImplicitThisExpr(tok), \"Repr\");\n          if (f.Reads.Count == 0) {\n            // reads Repr\n            f.Reads.Add(new FrameExpression(tok, repr, null));\n            format += \"\\nreads {1}\";\n          }\n          AddHoverText(member.tok, format, valid, repr);\n        } else if (member is Constructor) {\n          var ctor = (Constructor)member;\n          // ensures Valid();\n          var valid = new FunctionCallExpr(tok, \"Valid\", new ImplicitThisExpr(tok), tok, new List<Expression>());\n          ctor.Ens.Insert(0, new MaybeFreeExpression(valid));\n          // ensures fresh(Repr - {this});\n          var freshness = new UnaryOpExpr(tok, UnaryOpExpr.Opcode.Fresh, new BinaryExpr(tok, BinaryExpr.Opcode.Sub,\n            new MemberSelectExpr(tok, new ImplicitThisExpr(tok), \"Repr\"),\n            new SetDisplayExpr(tok, true, new List<Expression>() { new ThisExpr(tok) })));\n          ctor.Ens.Insert(1, new MaybeFreeExpression(freshness));\n          var m0 = new ThisExpr(tok);\n          AddHoverText(member.tok, \"modifies {0}\\nensures {1} && {2}\", m0, valid, freshness);\n        }\n      }\n    }\n\n    internal override void PostResolve(ModuleDefinition m) {\n      foreach (var d in m.TopLevelDecls) {\n        bool sayYes = true;\n        if (d is ClassDecl && Attributes.ContainsBool(d.Attributes, \"autocontracts\", ref sayYes) && sayYes) {\n          ProcessClassPostResolve((ClassDecl)d);\n        }\n      }\n    }\n\n    void ProcessClassPostResolve(ClassDecl cl) {\n      // Find all fields of a reference type, and make a note of whether or not the reference type has a Repr field.\n      // Also, find the Repr field and the function Valid in class \"cl\"\n      Field ReprField = null;\n      Function Valid = null;\n      var subobjects = new List<Tuple<Field, Field, Function>>();\n      foreach (var member in cl.Members) {\n        var field = member as Field;\n        if (field != null) {\n          bool sayYes = true;\n          if (field.Name == \"Repr\") {\n            ReprField = field;\n          } else if (Attributes.ContainsBool(field.Attributes, \"autocontracts\", ref sayYes) && !sayYes) {\n            // ignore this field\n          } else if (field.Type.IsRefType) {\n            var rcl = (ClassDecl)((UserDefinedType)field.Type.NormalizeExpand()).ResolvedClass;\n            Field rRepr = null;\n            Function rValid = null;\n            foreach (var memb in rcl.Members) {\n              if (memb is Field && memb.Name == \"Repr\") {\n                var f = (Field)memb;\n                var t = f.Type.AsSetType;\n                if (t != null && t.Arg.IsObjectQ) {\n                  rRepr = f;\n                }\n              } else if (memb is Function && memb.Name == \"Valid\" && !memb.IsStatic) {\n                var f = (Function)memb;\n                if (f.Formals.Count == 0 && f.ResultType.IsBoolType) {\n                  rValid = f;\n                }\n              }\n              if (rRepr != null && rValid != null) {\n                break;\n              }\n            }\n            subobjects.Add(new Tuple<Field, Field, Function>(field, rRepr, rValid));\n          }\n        } else if (member is Function && member.Name == \"Valid\" && !member.IsStatic) {\n          var fn = (Function)member;\n          if (fn.Formals.Count == 0 && fn.ResultType.IsBoolType) {\n            Valid = fn;\n          }\n        }\n      }\n      Contract.Assert(ReprField != null);  // we expect there to be a \"Repr\" field, since we added one in PreResolve\n\n      Boogie.IToken clTok = new AutoGeneratedToken(cl.tok);\n      Type ty = Resolver.GetThisType(clTok, cl);\n      var self = new ThisExpr(clTok);\n      self.Type = ty;\n      var implicitSelf = new ImplicitThisExpr(clTok);\n      implicitSelf.Type = ty;\n      var Repr = new MemberSelectExpr(clTok, implicitSelf, ReprField);\n\n      foreach (var member in cl.Members) {\n        bool sayYes = true;\n        if (Attributes.ContainsBool(member.Attributes, \"autocontracts\", ref sayYes) && !sayYes) {\n          continue;\n        }\n        Boogie.IToken tok = new AutoGeneratedToken(member.tok);\n        if (member is Function && member.Name == \"Valid\" && !member.IsStatic) {\n          var valid = (Function)member;\n          var validConjuncts = new List<Expression>();\n          if (valid.IsGhost && valid.ResultType.IsBoolType) {\n            if (valid.RefinementBase == null) {\n              var c0 = BinBoolExpr(tok, BinaryExpr.ResolvedOpcode.InSet, self, Repr);  // this in Repr\n              var c1 = BinBoolExpr(tok, BinaryExpr.ResolvedOpcode.NotInSet, new LiteralExpr(tok) { Type = builtIns.ObjectQ() }, Repr);  // null !in Repr\n              var c = BinBoolExpr(tok, BinaryExpr.ResolvedOpcode.And, c0, c1);\n              validConjuncts.Add(c);\n            }\n\n            foreach (var ff in subobjects) {\n              if (ff.Item1.RefinementBase != null) {\n                // the field has been inherited from a refined module, so don't include it here\n                continue;\n              }\n              var F = new MemberSelectExpr(tok, implicitSelf, ff.Item1);\n              var c0 = IsNotNull(tok, F);\n              var c1 = BinBoolExpr(tok, BinaryExpr.ResolvedOpcode.InSet, F, Repr);\n              if (ff.Item2 == null) {\n                // F != null ==> F in Repr  (so, nothing else to do)\n              } else {\n                // F != null ==> F in Repr && F.Repr <= Repr && this !in F.Repr && F.Valid()\n                var FRepr = new MemberSelectExpr(tok, F, ff.Item2);\n                var c2 = BinBoolExpr(tok, BinaryExpr.ResolvedOpcode.Subset, FRepr, Repr);\n                var c3 = BinBoolExpr(tok, BinaryExpr.ResolvedOpcode.NotInSet, self, FRepr);\n                c1 = BinBoolExpr(tok, BinaryExpr.ResolvedOpcode.And, c1,\n                  BinBoolExpr(tok, BinaryExpr.ResolvedOpcode.And, c2, c3));\n                if (ff.Item3 != null) {\n                  // F.Valid()\n                  c1 = BinBoolExpr(tok, BinaryExpr.ResolvedOpcode.And, c1,\n                    ValidCall(tok, F, ff.Item3, valid));\n                }\n              }\n              validConjuncts.Add(Expression.CreateImplies(c0, c1));\n            }\n\n            var hoverText = \"\";\n            var sep = \"\";\n            if (valid.Body == null) {\n              valid.Body = Expression.CreateBoolLiteral(tok, true);\n              if (validConjuncts.Count == 0) {\n                hoverText = \"true\";\n                sep = \"\\n\";\n              }\n            }\n            for (int i = validConjuncts.Count; 0 <= --i; ) {\n              var c = validConjuncts[i];\n              valid.Body = BinBoolExpr(tok, BinaryExpr.ResolvedOpcode.And, c, valid.Body);\n              hoverText = Printer.ExprToString(c) + sep + hoverText;\n              sep = \"\\n\";\n            }\n            AddHoverText(valid.tok, \"{0}\", hoverText);\n          }\n\n        } else if (member is Constructor) {\n          var ctor = (Constructor)member;\n          if (ctor.Body != null) {\n            var sbs = (DividedBlockStmt)ctor.Body;\n            var n = sbs.Body.Count;\n            if (ctor.RefinementBase == null) {\n              // Repr := {this};\n              var e = new SetDisplayExpr(tok, true, new List<Expression>() { self });\n              e.Type = new SetType(true, builtIns.ObjectQ());\n              Statement s = new AssignStmt(tok, tok, Repr, new ExprRhs(e));\n              s.IsGhost = true;\n              sbs.AppendStmt(s);\n            }\n            AddSubobjectReprs(tok, ctor.BodyEndTok, subobjects, sbs, n, implicitSelf, Repr);\n          }\n\n        } else if (member is Method && !member.IsStatic && Valid != null) {\n          var m = (Method)member;\n          var addStatementsToUpdateRepr = false;\n          if (member.IsGhost || IsSimpleQueryMethod(m)) {\n            if (m.RefinementBase == null) {\n              // requires Valid()\n              var valid = ValidCall(tok, implicitSelf, Valid, m);\n              if (m is TwoStateLemma) {\n                // Instead use:  requires old(Valid())\n                valid = new OldExpr(tok, valid);\n                valid.Type = Type.Bool;\n              }\n              m.Req.Insert(0, new MaybeFreeExpression(valid));\n              AddHoverText(member.tok, \"requires {0}\", valid);\n            }\n          } else if (m.RefinementBase == null) {\n            // requires Valid()\n            var valid = ValidCall(tok, implicitSelf, Valid, m);\n            m.Req.Insert(0, new MaybeFreeExpression(valid));\n            var format = \"requires {0}\";\n            if (m.Mod.Expressions.Count == 0) {\n              // modifies Repr\n              m.Mod.Expressions.Add(new FrameExpression(Repr.tok, Repr, null));\n              format += \"\\nmodifies {1}\";\n              addStatementsToUpdateRepr = true;\n            }\n            // ensures Valid()\n            m.Ens.Insert(0, new MaybeFreeExpression(valid));\n            // ensures fresh(Repr - old(Repr));\n            var e0 = new OldExpr(tok, Repr);\n            e0.Type = Repr.Type;\n            var e1 = new BinaryExpr(tok, BinaryExpr.Opcode.Sub, Repr, e0);\n            e1.ResolvedOp = BinaryExpr.ResolvedOpcode.SetDifference;\n            e1.Type = Repr.Type;\n            var freshness = new UnaryOpExpr(tok, UnaryOpExpr.Opcode.Fresh, e1);\n            freshness.Type = Type.Bool;\n            m.Ens.Insert(1, new MaybeFreeExpression(freshness));\n            AddHoverText(m.tok, format + \"\\nensures {0} && {2}\", valid, Repr, freshness);\n          } else {\n            addStatementsToUpdateRepr = true;\n          }\n\n          if (addStatementsToUpdateRepr && m.Body != null) {\n            var methodBody = (BlockStmt)m.Body;\n            AddSubobjectReprs(tok, methodBody.EndTok, subobjects, methodBody, methodBody.Body.Count, implicitSelf, Repr);\n          }\n        }\n      }\n    }\n\n    void AddSubobjectReprs(IToken tok, IToken endCurlyTok, List<Tuple<Field, Field, Function>> subobjects, BlockStmt block, int hoverTextFromHere,\n      Expression implicitSelf, Expression Repr) {\n      Contract.Requires(tok != null);\n      Contract.Requires(endCurlyTok != null);\n      Contract.Requires(subobjects != null);\n      Contract.Requires(block != null);\n      Contract.Requires(0 <= hoverTextFromHere && hoverTextFromHere <= block.Body.Count);\n      Contract.Requires(implicitSelf != null);\n      Contract.Requires(Repr != null);\n      // TODO: these assignments should be included on every return path\n\n      foreach (var ff in subobjects) {\n        var F = new MemberSelectExpr(tok, implicitSelf, ff.Item1);  // create a resolved MemberSelectExpr\n        Expression e = new SetDisplayExpr(tok, true, new List<Expression>() { F }) {\n          Type = new SetType(true, builtIns.ObjectQ())  // resolve here\n        };\n        var rhs = new BinaryExpr(tok, BinaryExpr.Opcode.Add, Repr, e) {\n          ResolvedOp = BinaryExpr.ResolvedOpcode.Union,\n          Type = Repr.Type\n        };\n        Expression nguard = BinBoolExpr(tok, BinaryExpr.ResolvedOpcode.InSet, F, Repr);  // F in Repr\n        if (ff.Item2 == null) {\n          // Repr := Repr + {F}  (so, nothing else to do)\n        } else {\n          // Repr := Repr + {F} + F.Repr\n          var FRepr = new MemberSelectExpr(tok, F, ff.Item2);  // create resolved MemberSelectExpr\n          rhs = new BinaryExpr(tok, BinaryExpr.Opcode.Add, rhs, FRepr) {\n            ResolvedOp = BinaryExpr.ResolvedOpcode.Union,\n            Type = Repr.Type\n          };\n          var ng = BinBoolExpr(tok, BinaryExpr.ResolvedOpcode.Subset, FRepr, Repr);  // F.Repr <= Repr\n          nguard = Expression.CreateAnd(nguard, ng);\n        }\n        // Repr := Repr + ...;\n        Statement s = new AssignStmt(tok, tok, Repr, new ExprRhs(rhs));\n        s.IsGhost = true;\n        // wrap if statement around s\n        e = Expression.CreateAnd(IsNotNull(tok, F), Expression.CreateNot(tok, nguard));\n        var thn = new BlockStmt(tok, tok, new List<Statement>() { s });\n        thn.IsGhost = true;\n        s = new IfStmt(tok, tok, false, e, thn, null);\n        s.IsGhost = true;\n        // finally, add s to the block\n        block.AppendStmt(s);\n      }\n      if (hoverTextFromHere != block.Body.Count) {\n        var hoverText = \"\";\n        var sep = \"\";\n        for (int i = hoverTextFromHere; i < block.Body.Count; i++) {\n          hoverText += sep + Printer.StatementToString(block.Body[i]);\n          sep = \"\\n\";\n        }\n        AddHoverText(endCurlyTok, \"{0}\", hoverText);\n      }\n    }\n\n    /// <summary>\n    /// Returns an expression denoting \"expr != null\".  If the type\n    /// of \"expr\" already implies \"expr\" is non-null, then an expression\n    /// denoting \"true\" is returned.\n    /// </summary>\n    Expression IsNotNull(IToken tok, Expression expr) {\n      Contract.Requires(tok != null);\n      Contract.Requires(expr != null);\n      if (expr.Type.IsNonNullRefType) {\n        return Expression.CreateBoolLiteral(tok, true);\n      } else {\n        var cNull = new LiteralExpr(tok);\n        cNull.Type = expr.Type;\n        return BinBoolExpr(tok, BinaryExpr.ResolvedOpcode.NeqCommon, expr, cNull);\n      }\n    }\n\n    bool IsSimpleQueryMethod(Method m) {\n      // A simple query method has out parameters, its body has no effect other than to assign to them,\n      // and the postcondition does not explicitly mention the pre-state.\n      return m.Outs.Count != 0 && m.Body != null && LocalAssignsOnly(m.Body) &&\n        m.Ens.TrueForAll(mfe => !MentionsOldState(mfe.E));\n    }\n\n    bool LocalAssignsOnly(Statement s) {\n      Contract.Requires(s != null);\n      if (s is AssignStmt) {\n        var ss = (AssignStmt)s;\n        return ss.Lhs.Resolved is IdentifierExpr;\n      } else if (s is ConcreteUpdateStatement) {\n        var ss = (ConcreteUpdateStatement)s;\n        return ss.Lhss.TrueForAll(e => e.Resolved is IdentifierExpr);\n      } else if (s is CallStmt) {\n        return false;\n      } else {\n        foreach (var ss in s.SubStatements) {\n          if (!LocalAssignsOnly(ss)) {\n            return false;\n          }\n        }\n      }\n      return true;\n    }\n\n    /// <summary>\n    /// Returns true iff 'expr' is a two-state expression, that is, if it mentions \"old/fresh/unchanged(...)\".\n    /// </summary>\n    static bool MentionsOldState(Expression expr) {\n      Contract.Requires(expr != null);\n      if (expr is OldExpr || expr is UnchangedExpr) {\n        return true;\n      } else if (expr is UnaryOpExpr && ((UnaryOpExpr)expr).Op == UnaryOpExpr.Opcode.Fresh) {\n        return true;\n      }\n      foreach (var ee in expr.SubExpressions) {\n        if (MentionsOldState(ee)) {\n          return true;\n        }\n      }\n      return false;\n    }\n\n    /// <summary>\n    /// Returns a resolved expression of the form \"receiver.Valid()\"\n    /// </summary>\n    public static Expression ValidCall(IToken tok, Expression receiver, Function Valid, ICallable callingContext) {\n      Contract.Requires(tok != null);\n      Contract.Requires(receiver != null);\n      Contract.Requires(Valid != null);\n      Contract.Requires(callingContext != null);\n      Contract.Requires(receiver.Type.NormalizeExpand() is UserDefinedType && ((UserDefinedType)receiver.Type.NormalizeExpand()).ResolvedClass == Valid.EnclosingClass);\n      Contract.Requires(receiver.Type.NormalizeExpand().TypeArgs.Count == Valid.EnclosingClass.TypeArgs.Count);\n      var call = new FunctionCallExpr(tok, Valid.Name, receiver, tok, new List<Expression>());\n      call.Function = Valid;\n      call.Type = Type.Bool;\n      // Add the identity substitution to this call\n      call.TypeArgumentSubstitutions = new Dictionary<TypeParameter, Type>();\n      for (int i = 0; i < Valid.EnclosingClass.TypeArgs.Count; i++) {\n        call.TypeArgumentSubstitutions.Add(Valid.EnclosingClass.TypeArgs[i], receiver.Type.TypeArgs[i]);\n      }\n      callingContext.EnclosingModule.CallGraph.AddEdge(callingContext, Valid);\n      return call;\n    }\n\n    public static BinaryExpr BinBoolExpr(Boogie.IToken tok, BinaryExpr.ResolvedOpcode rop, Expression e0, Expression e1) {\n      var p = new BinaryExpr(tok, BinaryExpr.ResolvedOp2SyntacticOp(rop), e0, e1);\n      p.ResolvedOp = rop;  // resolve here\n      p.Type = Type.Bool;  // resolve here\n      return p;\n    }\n\n    void AddHoverText(IToken tok, string format, params object[] args) {\n      Contract.Requires(tok != null);\n      Contract.Requires(format != null);\n      Contract.Requires(args != null);\n      for (int i = 0; i < args.Length; i++) {\n        if (args[i] is Expression) {\n          args[i] = Printer.ExprToString((Expression)args[i]);\n        }\n      }\n      var s = \"autocontracts:\\n\" + string.Format(format, args);\n      reporter.Info(MessageSource.Rewriter, tok, s.Replace(\"\\n\", \"\\n  \"));\n    }\n  }\n\n\n  /// <summary>\n  /// For any function foo() with the :opaque attribute,\n  /// hide the body, so that it can only be seen within its\n  /// recursive clique (if any), or if the programmer\n  /// specifically asks to see it via the reveal_foo() lemma\n  /// </summary>\n  public class OpaqueFunctionRewriter : IRewriter {\n    protected Dictionary<Function, Function> fullVersion; // Given an opaque function, retrieve the full\n    protected Dictionary<Function, Function> original;    // Given a full version of an opaque function, find the original opaque version\n    protected Dictionary<Lemma, Function> revealOriginal; // Map reveal_* lemmas back to their original functions\n\n    public OpaqueFunctionRewriter(ErrorReporter reporter)\n      : base(reporter) {\n      Contract.Requires(reporter != null);\n\n      fullVersion = new Dictionary<Function, Function>();\n      original = new Dictionary<Function, Function>();\n      revealOriginal = new Dictionary<Lemma, Function>();\n    }\n\n    internal override void PreResolve(ModuleDefinition m) {\n      foreach (var d in m.TopLevelDecls) {\n        if (d is ClassDecl) {\n          ProcessOpaqueClassFunctions((ClassDecl)d);\n        }\n      }\n    }\n\n    internal override void PostResolve(ModuleDefinition m) {\n      foreach (var decl in ModuleDefinition.AllCallables(m.TopLevelDecls)) {\n        if (decl is Lemma) {\n          var lem = (Lemma)decl;\n          if (revealOriginal.ContainsKey(lem)) {\n            Function fn = revealOriginal[lem];\n            AnnotateRevealFunction(lem, fn);\n          }\n        }\n      }\n    }\n\n    protected void AnnotateRevealFunction(Lemma lemma, Function f) {\n      Expression receiver;\n      if (f.IsStatic) {\n        receiver = new StaticReceiverExpr(f.tok, (ClassDecl)f.EnclosingClass, true);\n      } else {\n        receiver = new ImplicitThisExpr(f.tok);\n        //receiver.Type = GetThisType(expr.tok, (ClassDecl)member.EnclosingClass);  // resolve here\n      }\n      List<Type> typeApplication = null;\n      if (f.TypeArgs.Count > 0) {\n        typeApplication = new List<Type>();\n        for (int i = 0; i < f.TypeArgs.Count; i++) {\n          // doesn't matter what type, just so we have it to make the resolver happy when resolving function member of\n          // the fuel attribute. This might not be needed after fixing codeplex issue #172.\n          typeApplication.Add(new IntType());\n        }\n      }\n      var nameSegment = new NameSegment(f.tok, f.Name, typeApplication);\n      var rr = new MemberSelectExpr(f.tok, receiver, f.Name);\n      rr.Member = f;\n      rr.TypeApplication = typeApplication ?? new List<Type>();\n      List<Type> args = new List<Type>();\n      for (int i = 0; i < f.Formals.Count; i++) {\n        args.Add(new IntType());\n      }\n      rr.Type = new ArrowType(f.tok, args, new IntType());\n      nameSegment.ResolvedExpression = rr;\n      nameSegment.Type = rr.Type;\n      LiteralExpr low = new LiteralExpr(f.tok, 1);\n      LiteralExpr hi = new LiteralExpr(f.tok, 2);\n      lemma.Attributes = new Attributes(\"fuel\", new List<Expression>() { nameSegment, low, hi }, lemma.Attributes);\n    }\n\n\n    // Tells the function to use 0 fuel by default\n    protected void ProcessOpaqueClassFunctions(ClassDecl c) {\n      List<MemberDecl> newDecls = new List<MemberDecl>();\n      foreach (MemberDecl member in c.Members) {\n        if (member is Function) {\n          var f = (Function)member;\n\n          if (!Attributes.Contains(f.Attributes, \"opaque\")) {\n            // Nothing to do\n          } else if (f.IsProtected) {\n            reporter.Error(MessageSource.Rewriter, f.tok, \":opaque is not allowed to be applied to protected functions (this will be allowed when the language introduces 'opaque'/'reveal' as keywords)\");\n          } else if (!RefinementToken.IsInherited(f.tok, c.Module)) {\n            RewriteOpaqueFunctionUseFuel(f, newDecls);\n          }\n        }\n      }\n      c.Members.AddRange(newDecls);\n    }\n\n    private void RewriteOpaqueFunctionUseFuel(Function f, List<MemberDecl> newDecls) {\n      // mark the opaque function with {:fuel, 0, 0}\n      LiteralExpr amount = new LiteralExpr(f.tok, 0);\n      f.Attributes = new Attributes(\"fuel\", new List<Expression>() { amount, amount }, f.Attributes);\n\n      // That is, given:\n      //   function {:opaque} foo(x:int, y:int) : int\n      //     requires 0 <= x < 5;\n      //     requires 0 <= y < 5;\n      //     ensures foo(x, y) < 10;\n      //   { x + y }\n      // We produce:\n      //   lemma {:axiom} {:auto_generated} {:fuel foo, 1, 2 } reveal_foo()\n      //\n      // The translator, in AddMethod, then adds ensures clauses to bump up the fuel parameters approriately\n\n      var cloner = new Cloner();\n\n      List<TypeParameter> typeVars = new List<TypeParameter>();\n      List<Type> optTypeArgs = new List<Type>();\n      foreach (TypeParameter tp in f.TypeArgs) {\n        typeVars.Add(cloner.CloneTypeParam(tp));\n        // doesn't matter what type, just so we have it to make the resolver happy when resolving function member of\n        // the fuel attribute. This might not be needed after fixing codeplex issue #172.\n        optTypeArgs.Add(new IntType());\n      }\n\n      // Add an axiom attribute so that the compiler won't complain about the lemma's lack of a body\n      Attributes lemma_attrs = BuiltIns.AxiomAttribute();\n      lemma_attrs = new Attributes(\"auto_generated\", new List<Expression>(), lemma_attrs);\n      lemma_attrs = new Attributes(\"opaque_reveal\", new List<Expression>(), lemma_attrs);\n      lemma_attrs = new Attributes(\"verify\", new List<Expression>() { new LiteralExpr(f.tok, false)}, lemma_attrs);\n      var reveal = new Lemma(f.tok, \"reveal_\" + f.Name, f.HasStaticKeyword, new List<TypeParameter>(), new List<Formal>(), new List<Formal>(), new List<MaybeFreeExpression>(),\n                              new Specification<FrameExpression>(new List<FrameExpression>(), null), /* newEnsuresList*/new List<MaybeFreeExpression>(),\n                              new Specification<Expression>(new List<Expression>(), null), null, lemma_attrs, null);\n      newDecls.Add(reveal);\n      revealOriginal[reveal] = f;\n      reveal.InheritVisibility(f, true);\n    }\n\n    class OpaqueFunctionVisitor : TopDownVisitor<bool> {\n      protected override bool VisitOneExpr(Expression expr, ref bool context) {\n        return true;\n      }\n    }\n  }\n\n\n  /// <summary>\n  /// Automatically accumulate requires for function calls within a function body,\n  /// if requested via {:autoreq}\n  /// </summary>\n  public class AutoReqFunctionRewriter : IRewriter {\n    Function parentFunction;\n    bool containsMatch; // TODO: Track this per-requirement, rather than per-function\n\n    public AutoReqFunctionRewriter(ErrorReporter reporter)\n      : base(reporter) {\n      Contract.Requires(reporter != null);\n    }\n\n    internal override void PostResolve(ModuleDefinition m) {\n      var components = m.CallGraph.TopologicallySortedComponents();\n\n      foreach (var scComponent in components) {  // Visit the call graph bottom up, so anything we call already has its prequisites calculated\n        if (scComponent is Function) {\n          Function fn = (Function)scComponent;\n          if (Attributes.ContainsBoolAtAnyLevel(fn, \"autoReq\")) {\n            parentFunction = fn;  // Remember where the recursion started\n            containsMatch = false;  // Assume no match statements are involved\n\n            List<MaybeFreeExpression> auto_reqs = new List<MaybeFreeExpression>();\n\n            // First handle all of the requirements' preconditions\n            foreach (MaybeFreeExpression req in fn.Req) {\n              foreach (Expression e in generateAutoReqs(req.E)) {\n                auto_reqs.Add(new MaybeFreeExpression(e, req.IsFree, req.Attributes));\n              }\n            }\n            fn.Req.InsertRange(0, auto_reqs); // Need to come before the actual requires\n            addAutoReqToolTipInfoToFunction(\"pre\", fn, auto_reqs);\n\n            // Then the body itself, if any\n            if (fn.Body != null) {\n              auto_reqs = new List<MaybeFreeExpression>();\n              foreach (Expression e in generateAutoReqs(fn.Body)) {\n                auto_reqs.Add(new MaybeFreeExpression(e));\n              }\n              fn.Req.AddRange(auto_reqs);\n              addAutoReqToolTipInfoToFunction(\"post\", fn, auto_reqs);\n            }\n          }\n        }\n        else if (scComponent is Method)\n        {\n            Method method = (Method)scComponent;\n            if (Attributes.ContainsBoolAtAnyLevel(method, \"autoReq\"))\n            {\n                parentFunction = null;\n                containsMatch = false; // Assume no match statements are involved\n\n                List<MaybeFreeExpression> auto_reqs = new List<MaybeFreeExpression>();\n                foreach (MaybeFreeExpression req in method.Req)\n                {\n                    List<Expression> local_auto_reqs = generateAutoReqs(req.E);\n                    foreach (Expression local_auto_req in local_auto_reqs)\n                    {\n                        auto_reqs.Add(new MaybeFreeExpression(local_auto_req, !req.IsFree));\n                    }\n                }\n                method.Req.InsertRange(0, auto_reqs); // Need to come before the actual requires\n                addAutoReqToolTipInfoToMethod(\"pre\", method, auto_reqs);\n            }\n        }\n      }\n    }\n\n    Expression subVars(List<Formal> formals, List<Expression> values, Expression e, Expression f_this) {\n      Contract.Assert(formals != null);\n      Contract.Assert(values != null);\n      Contract.Assert(formals.Count == values.Count);\n      Dictionary<IVariable, Expression/*!*/> substMap = new Dictionary<IVariable, Expression>();\n      Dictionary<TypeParameter, Type> typeMap = new Dictionary<TypeParameter, Type>();\n\n      for (int i = 0; i < formals.Count; i++) {\n        substMap.Add(formals[i], values[i]);\n      }\n\n      Translator.Substituter sub = new Translator.Substituter(f_this, substMap, typeMap);\n      return sub.Substitute(e);\n    }\n\n    public void addAutoReqToolTipInfoToFunction(string label, Function f, List<MaybeFreeExpression> reqs) {\n      string prefix = \"auto requires \" + label + \" \";\n      string tip = \"\";\n\n      string sep = \"\";\n      foreach (var req in reqs) {\n        if (containsMatch) {  // Pretty print the requirements\n          tip += sep + prefix + Printer.ExtendedExprToString(req.E) + \";\";\n        } else {\n          tip += sep + prefix + Printer.ExprToString(req.E) + \";\";\n        }\n        sep = \"\\n\";\n      }\n\n      if (!tip.Equals(\"\")) {\n        reporter.Info(MessageSource.Rewriter, f.tok, tip);\n        if (ArmadaOptions.O.AutoReqPrintFile != null) {\n          using (System.IO.TextWriter writer = new System.IO.StreamWriter(ArmadaOptions.O.AutoReqPrintFile, true)) {\n            writer.WriteLine(f.Name);\n            writer.WriteLine(\"\\t\" + tip);\n          }\n        }\n      }\n    }\n\n    public void addAutoReqToolTipInfoToMethod(string label, Method method, List<MaybeFreeExpression> reqs) {\n      string tip = \"\";\n\n      foreach (var req in reqs) {\n        string prefix = \"auto \";\n        if (req.IsFree) {\n          prefix += \"free \";\n        }\n        prefix += \" requires \" + label + \" \";\n        if (containsMatch) {  // Pretty print the requirements\n          tip += prefix + Printer.ExtendedExprToString(req.E) + \";\\n\";\n        } else {\n          tip += prefix + Printer.ExprToString(req.E) + \";\\n\";\n        }\n      }\n\n      if (!tip.Equals(\"\")) {\n        reporter.Info(MessageSource.Rewriter, method.tok, tip);\n        if (ArmadaOptions.O.AutoReqPrintFile != null) {\n          using (System.IO.TextWriter writer = new System.IO.StreamWriter(ArmadaOptions.O.AutoReqPrintFile, true)) {\n            writer.WriteLine(method.Name);\n            writer.WriteLine(\"\\t\" + tip);\n          }\n        }\n      }\n    }\n\n    // Stitch a list of expressions together with logical ands\n    Expression andify(Bpl.IToken tok, List<Expression> exprs) {\n      Expression ret = Expression.CreateBoolLiteral(tok, true);\n\n      foreach (var expr in exprs) {\n        ret = Expression.CreateAnd(ret, expr);\n      }\n\n      return ret;\n    }\n\n    List<Expression> gatherReqs(Function f, List<Expression> args, Expression f_this) {\n      List<Expression> translated_f_reqs = new List<Expression>();\n\n      if (f.Req.Count > 0) {\n        Dictionary<IVariable, Expression/*!*/> substMap = new Dictionary<IVariable,Expression>();\n        Dictionary<TypeParameter, Type> typeMap = new Dictionary<TypeParameter,Type>();\n\n        for (int i = 0; i < f.Formals.Count; i++) {\n          substMap.Add(f.Formals[i], args[i]);\n        }\n\n        foreach (var req in f.Req) {\n          Translator.Substituter sub = new Translator.Substituter(f_this, substMap, typeMap);\n          translated_f_reqs.Add(sub.Substitute(req.E));\n        }\n      }\n\n      return translated_f_reqs;\n    }\n\n    List<Expression> generateAutoReqs(Expression expr) {\n      List<Expression> reqs = new List<Expression>();\n\n      if (expr is LiteralExpr) {\n      } else if (expr is ThisExpr) {\n      } else if (expr is IdentifierExpr) {\n      } else if (expr is SetDisplayExpr) {\n        SetDisplayExpr e = (SetDisplayExpr)expr;\n\n        foreach (var elt in e.Elements) {\n          reqs.AddRange(generateAutoReqs(elt));\n        }\n      } else if (expr is MultiSetDisplayExpr) {\n        MultiSetDisplayExpr e = (MultiSetDisplayExpr)expr;\n        foreach (var elt in e.Elements) {\n          reqs.AddRange(generateAutoReqs(elt));\n        }\n      } else if (expr is SeqDisplayExpr) {\n        SeqDisplayExpr e = (SeqDisplayExpr)expr;\n        foreach (var elt in e.Elements) {\n          reqs.AddRange(generateAutoReqs(elt));\n        }\n      } else if (expr is MapDisplayExpr) {\n        MapDisplayExpr e = (MapDisplayExpr)expr;\n\n        foreach (ExpressionPair p in e.Elements) {\n          reqs.AddRange(generateAutoReqs(p.A));\n          reqs.AddRange(generateAutoReqs(p.B));\n        }\n      } else if (expr is MemberSelectExpr) {\n        MemberSelectExpr e = (MemberSelectExpr)expr;\n        Contract.Assert(e.Member != null && e.Member is Field);\n\n        reqs.AddRange(generateAutoReqs(e.Obj));\n      } else if (expr is SeqSelectExpr) {\n        SeqSelectExpr e = (SeqSelectExpr)expr;\n\n        reqs.AddRange(generateAutoReqs(e.Seq));\n        if (e.E0 != null) {\n          reqs.AddRange(generateAutoReqs(e.E0));\n        }\n\n        if (e.E1 != null) {\n          reqs.AddRange(generateAutoReqs(e.E1));\n        }\n      } else if (expr is SeqUpdateExpr) {\n        SeqUpdateExpr e = (SeqUpdateExpr)expr;\n        reqs.AddRange(generateAutoReqs(e.Seq));\n        reqs.AddRange(generateAutoReqs(e.Index));\n        reqs.AddRange(generateAutoReqs(e.Value));\n      } else if (expr is DatatypeUpdateExpr) {\n        foreach (var ee in expr.SubExpressions) {\n          reqs.AddRange(generateAutoReqs(ee));\n        }\n      } else if (expr is FunctionCallExpr) {\n        FunctionCallExpr e = (FunctionCallExpr)expr;\n\n        // All of the arguments need to be satisfied\n        foreach (var arg in e.Args) {\n          reqs.AddRange(generateAutoReqs(arg));\n        }\n\n        if (parentFunction != null && ModuleDefinition.InSameSCC(e.Function, parentFunction)) {\n          // We're making a call within the same SCC, so don't descend into this function\n        } else {\n          reqs.AddRange(gatherReqs(e.Function, e.Args, e.Receiver));\n        }\n      } else if (expr is DatatypeValue) {\n        DatatypeValue dtv = (DatatypeValue)expr;\n        Contract.Assert(dtv.Ctor != null);  // since dtv has been successfully resolved\n        for (int i = 0; i < dtv.Arguments.Count; i++) {\n          Expression arg = dtv.Arguments[i];\n          reqs.AddRange(generateAutoReqs(arg));\n        }\n      } else if (expr is OldExpr) {\n      } else if (expr is MatchExpr) {\n        MatchExpr e = (MatchExpr)expr;\n        containsMatch = true;\n        reqs.AddRange(generateAutoReqs(e.Source));\n\n        List<MatchCaseExpr> newMatches = new List<MatchCaseExpr>();\n        foreach (MatchCaseExpr caseExpr in e.Cases) {\n          //MatchCaseExpr c = new MatchCaseExpr(caseExpr.tok, caseExpr.Id, caseExpr.Arguments, andify(caseExpr.tok, generateAutoReqs(caseExpr.Body)));\n          //c.Ctor = caseExpr.Ctor; // resolve here\n          MatchCaseExpr c = Expression.CreateMatchCase(caseExpr, andify(caseExpr.tok, generateAutoReqs(caseExpr.Body)));\n          newMatches.Add(c);\n        }\n\n        reqs.Add(Expression.CreateMatch(e.tok, e.Source, newMatches, e.Type));\n      } else if (expr is SeqConstructionExpr) {\n        var e = (SeqConstructionExpr)expr;\n        reqs.AddRange(generateAutoReqs(e.N));\n        reqs.AddRange(generateAutoReqs(e.Initializer));\n      } else if (expr is MultiSetFormingExpr) {\n        MultiSetFormingExpr e = (MultiSetFormingExpr)expr;\n        reqs.AddRange(generateAutoReqs(e.E));\n      } else if (expr is UnaryExpr) {\n        UnaryExpr e = (UnaryExpr)expr;\n        Expression arg = e.E;\n        reqs.AddRange(generateAutoReqs(arg));\n      } else if (expr is BinaryExpr) {\n        BinaryExpr e = (BinaryExpr)expr;\n\n        switch (e.ResolvedOp) {\n          case BinaryExpr.ResolvedOpcode.Imp:\n          case BinaryExpr.ResolvedOpcode.And:\n            reqs.AddRange(generateAutoReqs(e.E0));\n            foreach (var req in generateAutoReqs(e.E1)) {\n              // We only care about this req if E0 is true, since And short-circuits\n              reqs.Add(Expression.CreateImplies(e.E0, req));\n            }\n            break;\n\n          case BinaryExpr.ResolvedOpcode.Or:\n            reqs.AddRange(generateAutoReqs(e.E0));\n            foreach (var req in generateAutoReqs(e.E1)) {\n              // We only care about this req if E0 is false, since Or short-circuits\n              reqs.Add(Expression.CreateImplies(Expression.CreateNot(e.E1.tok, e.E0), req));\n            }\n            break;\n\n          default:\n            reqs.AddRange(generateAutoReqs(e.E0));\n            reqs.AddRange(generateAutoReqs(e.E1));\n            break;\n        }\n      } else if (expr is TernaryExpr) {\n        var e = (TernaryExpr)expr;\n\n        reqs.AddRange(generateAutoReqs(e.E0));\n        reqs.AddRange(generateAutoReqs(e.E1));\n        reqs.AddRange(generateAutoReqs(e.E2));\n      } else if (expr is LetExpr) {\n        var e = (LetExpr)expr;\n\n        if (e.Exact) {\n          foreach (var rhs in e.RHSs) {\n            reqs.AddRange(generateAutoReqs(rhs));\n          }\n          var new_reqs = generateAutoReqs(e.Body);\n          if (new_reqs.Count > 0) {\n            reqs.Add(Expression.CreateLet(e.tok, e.LHSs, e.RHSs, andify(e.tok, new_reqs), e.Exact));\n          }\n        } else {\n          // TODO: Still need to figure out what the right choice is here:\n          // Given: var x :| g(x); f(x, y) do we:\n          //    1) Update the original statement to be: var x :| g(x) && WP(f(x,y)); f(x, y)\n          //    2) Add forall x :: g(x) ==> WP(f(x, y)) to the function's requirements\n          //    3) Current option -- do nothing.  Up to the spec writer to fix\n        }\n      } else if (expr is NamedExpr) {\n        reqs.AddRange(generateAutoReqs(((NamedExpr)expr).Body));\n      } else if (expr is QuantifierExpr) {\n        QuantifierExpr e = (QuantifierExpr)expr;\n\n        // See LetExpr for issues with the e.Range\n\n        var auto_reqs = generateAutoReqs(e.Term);\n        if (auto_reqs.Count > 0) {\n            Expression allReqsSatisfied = andify(e.Term.tok, auto_reqs);\n            Expression allReqsSatisfiedAndTerm = Expression.CreateAnd(allReqsSatisfied, e.Term);\n            e.UpdateTerm(allReqsSatisfiedAndTerm);\n            reporter.Info(MessageSource.Rewriter, e.tok, \"autoreq added (\" + Printer.ExtendedExprToString(allReqsSatisfied) + \") &&\");\n        }\n      } else if (expr is SetComprehension) {\n        var e = (SetComprehension)expr;\n        // Translate \"set xs | R :: T\"\n\n        // See LetExpr for issues with the e.Range\n        //reqs.AddRange(generateAutoReqs(e.Range));\n        var auto_reqs = generateAutoReqs(e.Term);\n        if (auto_reqs.Count > 0) {\n          reqs.Add(Expression.CreateQuantifier(new ForallExpr(e.tok, new List<TypeParameter>(), e.BoundVars, e.Range, andify(e.Term.tok, auto_reqs), e.Attributes), true));\n        }\n      } else if (expr is MapComprehension) {\n        var e = (MapComprehension)expr;\n        // Translate \"map x | R :: T\" into\n        // See LetExpr for issues with the e.Range\n        //reqs.AddRange(generateAutoReqs(e.Range));\n        var auto_reqs = new List<Expression>();\n        if (e.TermLeft != null) {\n          auto_reqs.AddRange(generateAutoReqs(e.TermLeft));\n        }\n        auto_reqs.AddRange(generateAutoReqs(e.Term));\n        if (auto_reqs.Count > 0) {\n          reqs.Add(Expression.CreateQuantifier(new ForallExpr(e.tok, new List<TypeParameter>(), e.BoundVars, e.Range, andify(e.Term.tok, auto_reqs), e.Attributes), true));\n        }\n      } else if (expr is StmtExpr) {\n        var e = (StmtExpr)expr;\n        reqs.AddRange(generateAutoReqs(e.E));\n      } else if (expr is ITEExpr) {\n        ITEExpr e = (ITEExpr)expr;\n        reqs.AddRange(generateAutoReqs(e.Test));\n        reqs.Add(Expression.CreateITE(e.Test, andify(e.Thn.tok, generateAutoReqs(e.Thn)), andify(e.Els.tok, generateAutoReqs(e.Els))));\n      } else if (expr is ConcreteSyntaxExpression) {\n        var e = (ConcreteSyntaxExpression)expr;\n        reqs.AddRange(generateAutoReqs(e.ResolvedExpression));\n      } else {\n        //Contract.Assert(false); throw new cce.UnreachableException();  // unexpected expression\n      }\n\n      return reqs;\n    }\n  }\n\n  public class ProvideRevealAllRewriter : IRewriter {\n    public ProvideRevealAllRewriter(ErrorReporter reporter)\n      : base(reporter) {\n      Contract.Requires(reporter != null);\n    }\n\n    internal override void PreResolve(ModuleDefinition m) {\n      var declarations = m.TopLevelDecls;\n\n      foreach (var d in declarations) {\n        if (d is ModuleExportDecl) {\n          var me = (ModuleExportDecl)d;\n\n          var revealAll = me.RevealAll || ArmadaOptions.O.DisableScopes;\n\n          if (revealAll || me.ProvideAll) {\n\n              foreach (var newt in declarations) {\n                if (!newt.CanBeExported())\n                  continue;\n\n                if (!(newt is DefaultClassDecl)) {\n                  me.Exports.Add(new ExportSignature(newt.tok, newt.Name, !revealAll || !newt.CanBeRevealed()));\n                }\n\n                if (newt is ClassDecl) {\n                  var cl = (ClassDecl)newt;\n\n                  foreach (var mem in cl.Members) {\n                    var opaque = !revealAll || !mem.CanBeRevealed();\n                    if (newt is DefaultClassDecl) {\n                      me.Exports.Add(new ExportSignature(mem.tok, mem.Name, opaque));\n                    } else {\n                      me.Exports.Add(new ExportSignature(cl.tok, cl.Name, mem.tok, mem.Name, opaque));\n                    }\n                  }\n                }\n              }\n            }\n          me.RevealAll = false;\n          me.ProvideAll = false;\n\n        }\n      }\n    }\n  }\n\n\n\n\n  /// <summary>\n  /// Replace all occurrences of attribute {:timeLimitMultiplier X} with {:timeLimit Y}\n  /// where Y = X*default-time-limit or Y = X*command-line-time-limit\n  /// </summary>\n  public class TimeLimitRewriter : IRewriter\n  {\n    public TimeLimitRewriter(ErrorReporter reporter)\n      : base(reporter) {\n      Contract.Requires(reporter != null);\n    }\n\n    internal override void PreResolve(ModuleDefinition m) {\n      foreach (var d in m.TopLevelDecls) {\n        if (d is ClassDecl) {\n          var c = (ClassDecl)d;\n          foreach (MemberDecl member in c.Members)  {\n            if (member is Function || member is Method) {\n              // Check for the timeLimitMultiplier attribute\n              if (Attributes.Contains(member.Attributes, \"timeLimitMultiplier\")) {\n                Attributes attrs = member.Attributes;\n                foreach (var attr in attrs.AsEnumerable()) {\n                  if (attr.Name == \"timeLimitMultiplier\") {\n                    if (attr.Args.Count == 1 && attr.Args[0] is LiteralExpr) {\n                      var arg = attr.Args[0] as LiteralExpr;\n                      System.Numerics.BigInteger value = (System.Numerics.BigInteger)arg.Value;\n                      if (value.Sign > 0) {\n                        int current_limit = ArmadaOptions.O.TimeLimit > 0 ? ArmadaOptions.O.TimeLimit : 10;  // Default to 10 seconds\n                        attr.Args[0] = new LiteralExpr(attr.Args[0].tok, value * current_limit);\n                        attr.Name = \"timeLimit\";\n                      }\n                    }\n                  }\n                }\n              }\n            }\n          }\n        }\n      }\n    }\n  }\n\n\n  class MatchCaseExprSubstituteCloner : Cloner\n  {\n    private List<Tuple<CasePattern<BoundVar>, BoundVar>> patternSubst;\n    private BoundVar oldvar;\n    private BoundVar var;\n\n    // the cloner is called after resolving the body of matchexpr, trying\n    // to replace casepattern in the body that has been replaced by bv\n    public MatchCaseExprSubstituteCloner(List<Tuple<CasePattern<BoundVar>, BoundVar>> subst) {\n      this.patternSubst = subst;\n      this.oldvar = null;\n      this.var = null;\n    }\n\n    public MatchCaseExprSubstituteCloner(BoundVar oldvar, BoundVar var) {\n      this.patternSubst = null;\n      this.oldvar = oldvar;\n      this.var = var;\n    }\n\n    public override BoundVar CloneBoundVar(BoundVar bv) {\n      // replace bv with this.var if bv == oldvar\n      BoundVar bvNew;\n      if (oldvar != null && bv.Name.Equals(oldvar.Name)) {\n        bvNew = new BoundVar(new AutoGeneratedToken(bv.tok), var.Name, CloneType(bv.Type));\n      } else {\n        bvNew = new BoundVar(Tok(bv.tok), bv.Name, CloneType(bv.Type));\n      }\n      bvNew.IsGhost = bv.IsGhost;\n      return bvNew;\n    }\n\n    public override NameSegment CloneNameSegment(Expression expr) {\n      var e = (NameSegment)expr;\n      if (oldvar != null && e.Name.Equals(oldvar.Name)) {\n        return new NameSegment(new AutoGeneratedToken(e.tok), var.Name, e.OptTypeArguments == null ? null : e.OptTypeArguments.ConvertAll(CloneType));\n      } else {\n        return new NameSegment(Tok(e.tok), e.Name, e.OptTypeArguments == null ? null : e.OptTypeArguments.ConvertAll(CloneType));\n      }\n    }\n\n    public override Expression CloneApplySuffix(ApplySuffix e) {\n      // if the ApplySuffix matches the CasePattern, then replace it with the BoundVar.\n      CasePattern<BoundVar> cp = null;\n      BoundVar bv = null;\n      if (FindMatchingPattern(e, out cp, out bv)) {\n        if (bv.tok is MatchCaseToken) {\n          Contract.Assert(e.Args.Count == cp.Arguments.Count);\n          for (int i = 0; i < e.Args.Count; i++) {\n            ((MatchCaseToken)bv.tok).AddVar(e.Args[i].tok, cp.Arguments[i].Var, false);\n          }\n        }\n        return new NameSegment(new AutoGeneratedToken(e.tok), bv.Name, null);\n      } else {\n        return new ApplySuffix(Tok(e.tok), CloneExpr(e.Lhs), e.Args.ConvertAll(CloneExpr));\n      }\n    }\n\n    private bool FindMatchingPattern(ApplySuffix e, out CasePattern<BoundVar> pattern, out BoundVar bv) {\n      pattern = null;\n      bv = null;\n      if (patternSubst == null) {\n        return false;\n      }\n      Expression lhs = e.Lhs;\n      if (!(lhs is NameSegment)) {\n        return false;\n      }\n      string applyName = ((NameSegment)lhs).Name;\n      foreach (Tuple<CasePattern<BoundVar>, BoundVar> pair in patternSubst) {\n        var cp = pair.Item1;\n        string ctorName = cp.Id;\n        if (!(applyName.Equals(ctorName)) || (e.Args.Count != cp.Arguments.Count)) {\n          continue;\n        }\n        bool found = true;\n        for (int i = 0; i < e.Args.Count; i++) {\n          var arg1 = e.Args[i];\n          var arg2 = cp.Arguments[i];\n          if (arg1.Resolved is IdentifierExpr) {\n            var bv1 = ((IdentifierExpr)arg1.Resolved).Var;\n            if (bv1 != arg2.Var) {\n              found = false;\n            }\n          } else {\n            found = false;\n          }\n        }\n        if (found) {\n          pattern = cp;\n          bv = pair.Item2;\n          return true;\n        }\n      }\n      return false;\n    }\n  }\n\n  // MatchCaseToken is used to record BoundVars that are consolidated due to rewrite of\n  // nested match patterns. We want to record the original BoundVars that are consolidated\n  // so that they will show up in the IDE correctly.\n  public class MatchCaseToken : AutoGeneratedToken\n  {\n    public readonly List<Tuple<IToken, BoundVar, bool>> varList;\n    public MatchCaseToken(IToken tok)\n      : base(tok) {\n      varList = new List<Tuple<IToken, BoundVar, bool>>();\n    }\n\n    public void AddVar(IToken tok, BoundVar var, bool isDefinition) {\n      varList.Add(new Tuple<IToken, BoundVar, bool>(tok, var, isDefinition));\n    }\n  }\n\n  // A cloner that replace the original token with AutoGeneratedToken.\n  class AutoGeneratedTokenCloner : Cloner\n  {\n    public override IToken Tok(IToken tok) {\n      return new AutoGeneratedToken(tok);\n    }\n  }\n\n  // ===========================================================================================\n\n  public class InductionRewriter : IRewriter {\n    internal InductionRewriter(ErrorReporter reporter) : base(reporter) {\n      Contract.Requires(reporter != null);\n    }\n\n    internal override void PostCyclicityResolve(ModuleDefinition m) {\n      if (ArmadaOptions.O.Induction == 0) {\n        // Don't bother inferring :induction attributes.  This will also have the effect of not warning about malformed :induction attributes\n      } else {\n        foreach (var decl in m.TopLevelDecls) {\n          if (decl is ClassDecl) {\n            var cl = (ClassDecl)decl;\n            foreach (var member in cl.Members) {\n              if (member is FixpointLemma) {\n                var method = (FixpointLemma)member;\n                ProcessMethodExpressions(method);\n                ComputeLemmaInduction(method.PrefixLemma);\n                ProcessMethodExpressions(method.PrefixLemma);\n              } else if (member is Method) {\n                var method = (Method)member;\n                ComputeLemmaInduction(method);\n                ProcessMethodExpressions(method);\n              } else if (member is FixpointPredicate) {\n                var function = (FixpointPredicate)member;\n                ProcessFunctionExpressions(function);\n                ProcessFunctionExpressions(function.PrefixPredicate);\n              } else if (member is Function) {\n                var function = (Function)member;\n                ProcessFunctionExpressions(function);\n              }\n            }\n          } else if (decl is NewtypeDecl) {\n            var nt = (NewtypeDecl)decl;\n            if (nt.Constraint != null) {\n              var visitor = new Induction_Visitor(this);\n              visitor.Visit(nt.Constraint);\n            }\n          }\n        }\n      }\n    }\n\n    void ProcessMethodExpressions(Method method) {\n      Contract.Requires(method != null);\n      var visitor = new Induction_Visitor(this);\n      method.Req.ForEach(mfe => visitor.Visit(mfe.E));\n      method.Ens.ForEach(mfe => visitor.Visit(mfe.E));\n      if (method.Body != null) {\n        visitor.Visit(method.Body);\n      }\n    }\n\n    void ProcessFunctionExpressions(Function function) {\n      Contract.Requires(function != null);\n      var visitor = new Induction_Visitor(this);\n      function.Req.ForEach(visitor.Visit);\n      function.Ens.ForEach(visitor.Visit);\n      if (function.Body != null) {\n        visitor.Visit(function.Body);\n      }\n    }\n\n    void ComputeLemmaInduction(Method method) {\n      Contract.Requires(method != null);\n      if (method.Body != null && method.IsGhost && method.Mod.Expressions.Count == 0 && method.Outs.Count == 0 && !(method is FixpointLemma)) {\n        var specs = new List<Expression>();\n        method.Req.ForEach(mfe => specs.Add(mfe.E));\n        method.Ens.ForEach(mfe => specs.Add(mfe.E));\n        ComputeInductionVariables(method.tok, method.Ins, specs, method, ref method.Attributes);\n      }\n    }\n\n    void ComputeInductionVariables<VarType>(IToken tok, List<VarType> boundVars, List<Expression> searchExprs, Method lemma, ref Attributes attributes) where VarType : class, IVariable {\n      Contract.Requires(tok != null);\n      Contract.Requires(boundVars != null);\n      Contract.Requires(searchExprs != null);\n      Contract.Requires(ArmadaOptions.O.Induction != 0);\n\n      var args = Attributes.FindExpressions(attributes, \"induction\");  // we only look at the first one we find, since it overrides any other ones\n      if (args == null) {\n        if (ArmadaOptions.O.Induction < 2) {\n          // No explicit induction variables and we're asked not to infer anything, so we're done\n          return;\n        } else if (ArmadaOptions.O.Induction == 2 && lemma != null) {\n          // We're asked to infer induction variables only for quantifiers, not for lemmas\n          return;\n        }\n        // GO INFER below (only select boundVars)\n      } else if (args.Count == 0) {\n        // {:induction} is treated the same as {:induction true}, which says to automatically infer induction variables\n        // GO INFER below (all boundVars)\n      } else if (args.Count == 1 && args[0] is LiteralExpr && ((LiteralExpr)args[0]).Value is bool) {\n        // {:induction false} or {:induction true}\n        if (!(bool)((LiteralExpr)args[0]).Value) {\n          // we're told not to infer anything\n          return;\n        }\n        // GO INFER below (all boundVars)\n      } else {\n        // Here, we're expecting the arguments to {:induction args} to be a sublist of \"boundVars\".\n        var goodArguments = new List<Expression>();\n        var i = 0;\n        foreach (var arg in args) {\n          var ie = arg.Resolved as IdentifierExpr;\n          if (ie != null) {\n            var j = boundVars.FindIndex(i, v => v == ie.Var);\n            if (i <= j) {\n              goodArguments.Add(ie);\n              i = j;\n              continue;\n            }\n            if (0 <= boundVars.FindIndex(v => v == ie.Var)) {\n              reporter.Warning(MessageSource.Rewriter, arg.tok, \"{0}s given as :induction arguments must be given in the same order as in the {1}; ignoring attribute\",\n                lemma != null ? \"lemma parameter\" : \"bound variable\", lemma != null ? \"lemma\" : \"quantifier\");\n              return;\n            }\n          }\n          reporter.Warning(MessageSource.Rewriter, arg.tok, \"invalid :induction attribute argument; expected {0}{1}; ignoring attribute\",\n            i == 0 ? \"'false' or 'true' or \" : \"\",\n            lemma != null ? \"lemma parameter\" : \"bound variable\");\n          return;\n        }\n        // The argument list was legal, so let's use it for the _induction attribute\n        attributes = new Attributes(\"_induction\", goodArguments, attributes);\n        return;\n      }\n\n      // Okay, here we go, coming up with good induction setting for the given situation\n      var inductionVariables = new List<Expression>();\n      foreach (IVariable n in boundVars) {\n        if (!(n.Type.IsTypeParameter || n.Type.IsInternalTypeSynonym) && (args != null || searchExprs.Exists(expr => VarOccursInArgumentToRecursiveFunction(expr, n)))) {\n          inductionVariables.Add(new IdentifierExpr(n.Tok, n));\n        }\n      }\n      if (inductionVariables.Count != 0) {\n        // We found something usable, so let's record that in an attribute\n        attributes = new Attributes(\"_induction\", inductionVariables, attributes);\n        // And since we're inferring something, let's also report that in a hover text.\n        var s = Printer.OneAttributeToString(attributes, \"induction\");\n        if (lemma is PrefixLemma) {\n          s = lemma.Name + \" \" + s;\n        }\n        reporter.Info(MessageSource.Rewriter, tok, s);\n      }\n    }\n    class Induction_Visitor : BottomUpVisitor\n    {\n      readonly InductionRewriter IndRewriter;\n      public Induction_Visitor(InductionRewriter inductionRewriter) {\n        Contract.Requires(inductionRewriter != null);\n        IndRewriter = inductionRewriter;\n      }\n      protected override void VisitOneExpr(Expression expr) {\n        var q = expr as QuantifierExpr;\n        if (q != null && q.SplitQuantifier == null) {\n          IndRewriter.ComputeInductionVariables(q.tok, q.BoundVars, new List<Expression>() { q.LogicalBody() }, null, ref q.Attributes);\n        }\n      }\n      void VisitInductionStmt(Statement stmt) {\n        Contract.Requires(stmt != null);\n        // visit a selection of subexpressions\n        if (stmt is AssertStmt) {\n          var s = (AssertStmt)stmt;\n          Visit(s.Expr);\n        }\n        // recursively visit all substatements\n        foreach (var s in stmt.SubStatements) {\n          VisitInductionStmt(s);\n        }\n      }\n    }\n\n    /// <summary>\n    /// Returns 'true' iff by looking at 'expr' the Induction Heuristic determines that induction should be applied to 'n'.\n    /// More precisely:\n    ///   DafnyInductionHeuristic      Return 'true'\n    ///   -----------------------      -------------\n    ///        0                       always\n    ///        1    if 'n' occurs as   any subexpression (of 'expr')\n    ///        2    if 'n' occurs as   any subexpression of          any index argument of an array/sequence select expression or any                       argument to a recursive function\n    ///        3    if 'n' occurs as   a prominent subexpression of  any index argument of an array/sequence select expression or any                       argument to a recursive function\n    ///        4    if 'n' occurs as   any subexpression of                                                                       any                       argument to a recursive function\n    ///        5    if 'n' occurs as   a prominent subexpression of                                                               any                       argument to a recursive function\n    ///        6    if 'n' occurs as   a prominent subexpression of                                                               any decreases-influencing argument to a recursive function\n    /// Parameter 'n' is allowed to be a ThisSurrogate.\n    /// </summary>\n    public static bool VarOccursInArgumentToRecursiveFunction(Expression expr, IVariable n) {\n      switch (ArmadaOptions.O.InductionHeuristic) {\n        case 0: return true;\n        case 1: return Translator.ContainsFreeVariable(expr, false, n);\n        default: return VarOccursInArgumentToRecursiveFunction(expr, n, false);\n      }\n    }\n\n    /// <summary>\n    /// Worker routine for VarOccursInArgumentToRecursiveFunction(expr,n), where the additional parameter 'exprIsProminent' says whether or\n    /// not 'expr' has prominent status in its context.\n    /// DafnyInductionHeuristic cases 0 and 1 are assumed to be handled elsewhere (i.e., a precondition of this method is DafnyInductionHeuristic is at least 2).\n    /// Parameter 'n' is allowed to be a ThisSurrogate.\n    /// </summary>\n    static bool VarOccursInArgumentToRecursiveFunction(Expression expr, IVariable n, bool exprIsProminent) {\n      Contract.Requires(expr != null);\n      Contract.Requires(n != null);\n\n      // The following variable is what gets passed down to recursive calls if the subexpression does not itself acquire prominent status.\n      var subExprIsProminent = ArmadaOptions.O.InductionHeuristic == 2 || ArmadaOptions.O.InductionHeuristic == 4 ? /*once prominent, always prominent*/exprIsProminent : /*reset the prominent status*/false;\n\n      if (expr is IdentifierExpr) {\n        var e = (IdentifierExpr)expr;\n        return exprIsProminent && e.Var == n;\n      } else if (expr is SeqSelectExpr) {\n        var e = (SeqSelectExpr)expr;\n        var q = ArmadaOptions.O.InductionHeuristic < 4 || subExprIsProminent;\n        return VarOccursInArgumentToRecursiveFunction(e.Seq, n, subExprIsProminent) ||  // this subexpression does not acquire \"prominent\" status\n          (e.E0 != null && VarOccursInArgumentToRecursiveFunction(e.E0, n, q)) ||  // this one does (unless arrays/sequences are excluded)\n          (e.E1 != null && VarOccursInArgumentToRecursiveFunction(e.E1, n, q));    // ditto\n      } else if (expr is MultiSelectExpr) {\n        var e = (MultiSelectExpr)expr;\n        var q = ArmadaOptions.O.InductionHeuristic < 4 || subExprIsProminent;\n        return VarOccursInArgumentToRecursiveFunction(e.Array, n, subExprIsProminent) ||\n          e.Indices.Exists(exp => VarOccursInArgumentToRecursiveFunction(exp, n, q));\n      } else if (expr is FunctionCallExpr) {\n        var e = (FunctionCallExpr)expr;\n        // For recursive functions:  arguments are \"prominent\"\n        // For non-recursive function:  arguments are \"prominent\" if the call is\n        var rec = e.Function.IsRecursive && e.CoCall != FunctionCallExpr.CoCallResolution.Yes;\n        var decr = e.Function.Decreases.Expressions;\n        bool variantArgument;\n        if (ArmadaOptions.O.InductionHeuristic < 6) {\n          variantArgument = rec;\n        } else {\n          // The receiver is considered to be \"variant\" if the function is recursive and the receiver participates\n          // in the effective decreases clause of the function.  The receiver participates if it's a free variable\n          // of a term in the explicit decreases clause.\n          variantArgument = rec && decr.Exists(ee => Translator.ContainsFreeVariable(ee, true, null));\n        }\n        if (VarOccursInArgumentToRecursiveFunction(e.Receiver, n, variantArgument || subExprIsProminent)) {\n          return true;\n        }\n        Contract.Assert(e.Function.Formals.Count == e.Args.Count);\n        for (int i = 0; i < e.Function.Formals.Count; i++) {\n          var f = e.Function.Formals[i];\n          var exp = e.Args[i];\n          if (ArmadaOptions.O.InductionHeuristic < 6) {\n            variantArgument = rec;\n          } else if (rec) {\n            // The argument position is considered to be \"variant\" if the function is recursive and...\n            // ... it has something to do with why the callee is well-founded, which happens when...\n            if (f is ImplicitFormal) {\n              // ... it is the argument is the implicit _k parameter, which is always first in the effective decreases clause of a prefix lemma, or\n              variantArgument = true;\n            } else if (decr.Exists(ee => Translator.ContainsFreeVariable(ee, false, f))) {\n              // ... it participates in the effective decreases clause of the function, which happens when it is\n              // a free variable of a term in the explicit decreases clause, or\n              variantArgument = true;\n            } else {\n              // ... the callee is a prefix predicate.\n              variantArgument = true;\n            }\n          }\n          if (VarOccursInArgumentToRecursiveFunction(exp, n, variantArgument || subExprIsProminent)) {\n            return true;\n          }\n        }\n        return false;\n      } else if (expr is TernaryExpr) {\n        var e = (TernaryExpr)expr;\n        switch (e.Op) {\n          case TernaryExpr.Opcode.PrefixEqOp:\n          case TernaryExpr.Opcode.PrefixNeqOp:\n            return VarOccursInArgumentToRecursiveFunction(e.E0, n, true) ||\n              VarOccursInArgumentToRecursiveFunction(e.E1, n, subExprIsProminent) ||\n              VarOccursInArgumentToRecursiveFunction(e.E2, n, subExprIsProminent);\n          default:\n            Contract.Assert(false); throw new cce.UnreachableException();  // unexpected ternary expression\n        }\n      } else if (expr is DatatypeValue) {\n        var e = (DatatypeValue)expr;\n        var q = n.Type.IsDatatype ? exprIsProminent : subExprIsProminent;  // prominent status continues, if we're looking for a variable whose type is a datatype\n        return e.Arguments.Exists(exp => VarOccursInArgumentToRecursiveFunction(exp, n, q));\n      } else if (expr is UnaryExpr) {\n        var e = (UnaryExpr)expr;\n        // both Not and SeqLength preserve prominence\n        return VarOccursInArgumentToRecursiveFunction(e.E, n, exprIsProminent);\n      } else if (expr is BinaryExpr) {\n        var e = (BinaryExpr)expr;\n        bool q;\n        switch (e.ResolvedOp) {\n          case BinaryExpr.ResolvedOpcode.Add:\n          case BinaryExpr.ResolvedOpcode.Sub:\n          case BinaryExpr.ResolvedOpcode.Mul:\n          case BinaryExpr.ResolvedOpcode.Div:\n          case BinaryExpr.ResolvedOpcode.Mod:\n          case BinaryExpr.ResolvedOpcode.LeftShift:\n          case BinaryExpr.ResolvedOpcode.RightShift:\n          case BinaryExpr.ResolvedOpcode.BitwiseAnd:\n          case BinaryExpr.ResolvedOpcode.BitwiseOr:\n          case BinaryExpr.ResolvedOpcode.BitwiseXor:\n          case BinaryExpr.ResolvedOpcode.Union:\n          case BinaryExpr.ResolvedOpcode.Intersection:\n          case BinaryExpr.ResolvedOpcode.SetDifference:\n          case BinaryExpr.ResolvedOpcode.Concat:\n            // these operators preserve prominence\n            q = exprIsProminent;\n            break;\n          default:\n            // whereas all other binary operators do not\n            q = subExprIsProminent;\n            break;\n        }\n        return VarOccursInArgumentToRecursiveFunction(e.E0, n, q) ||\n          VarOccursInArgumentToRecursiveFunction(e.E1, n, q);\n      } else if (expr is StmtExpr) {\n        var e = (StmtExpr)expr;\n        // ignore the statement\n        return VarOccursInArgumentToRecursiveFunction(e.E, n);\n\n      } else if (expr is ITEExpr) {\n        var e = (ITEExpr)expr;\n        return VarOccursInArgumentToRecursiveFunction(e.Test, n, subExprIsProminent) ||  // test is not \"prominent\"\n          VarOccursInArgumentToRecursiveFunction(e.Thn, n, exprIsProminent) ||  // but the two branches are\n          VarOccursInArgumentToRecursiveFunction(e.Els, n, exprIsProminent);\n      } else if (expr is OldExpr ||\n                 expr is ConcreteSyntaxExpression ||\n                 expr is BoxingCastExpr ||\n                 expr is UnboxingCastExpr) {\n        foreach (var exp in expr.SubExpressions) {\n          if (VarOccursInArgumentToRecursiveFunction(exp, n, exprIsProminent)) {  // maintain prominence\n            return true;\n          }\n        }\n        return false;\n      } else {\n        // in all other cases, reset the prominence status and recurse on the subexpressions\n        foreach (var exp in expr.SubExpressions) {\n          if (VarOccursInArgumentToRecursiveFunction(exp, n, subExprIsProminent)) {\n            return true;\n          }\n        }\n        return false;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "Source/Armada/SccGraph.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics.Contracts;\n\nnamespace Microsoft.Armada {\n\n  public class Graph<Node> where Node : class\n  {\n    public enum VisitedStatus { Unvisited, OnStack, Visited }\n    public class Vertex {\n      public readonly Node N;\n      public readonly List<Vertex/*!*/>/*!*/ Successors = new List<Vertex/*!*/>();\n      public List<Vertex/*!*/> SccMembers;  // non-null only for the representative of the SCC\n      [ContractInvariantMethod]\n      void ObjectInvariant()\n      {\n        Contract.Invariant(cce.NonNullElements(Successors));\n        Contract.Invariant(SccMembers==null || cce.NonNullElements(SccMembers));\n      }\n\n      public Vertex SccRepresentative;  // null if not computed\n\n      public int SccId;  // valid only for SCC representatives; indicates position of this representative vertex in the graph's topological sort\n      // the following field is used during the computation of SCCs and of reachability\n      public VisitedStatus Visited;\n      // the following fields are used during the computation of SCCs:\n      public int DfNumber;\n      public int LowLink;\n      // the following field is used during a Reaches computation\n      public int Gen;  // generation <= Gen means this vertex has been visited in the current generation\n\n      public Vertex(Node n) {\n        N = n;\n      }\n      public void AddSuccessor(Vertex v) {\n        Contract.Requires(v != null);\n        Successors.Add(v);\n      }\n    }\n\n\n    [ContractInvariantMethod]\n    void ObjectInvariant()\n    {\n      Contract.Invariant(vertices!=null);\n      Contract.Invariant(cce.NonNullElements(vertices.Values));\n      Contract.Invariant(topologicallySortedRepresentatives==null || cce.NonNullElements(topologicallySortedRepresentatives));\n      Contract.Invariant(!sccComputed || topologicallySortedRepresentatives != null);\n    }\n\n    Dictionary<Node, Vertex/*!*/>/*!*/ vertices = new Dictionary<Node, Vertex/*!*/>();\n    bool sccComputed = false;\n    List<Vertex/*!*/> topologicallySortedRepresentatives;  // computed by the SCC computation\n\n    public int SccCount {\n      get {\n        ComputeSCCs();\n        Contract.Assert(topologicallySortedRepresentatives != null);  // follows from postcondition of ComputeSCCs and the object invariant\n        return topologicallySortedRepresentatives.Count;\n      }\n    }\n    int generation = 0;\n\n    public Graph()\n    {\n    }\n\n    [Pure]\n    public IEnumerable<Vertex> GetVertices() {\n      return vertices.Values;\n    }\n\n    /// <summary>\n    /// Idempotently adds a vertex 'n' to the graph.\n    /// </summary>\n    public void AddVertex(Node n) {\n      GetVertex(n);\n    }\n\n    /// <summary>\n    /// Idempotently adds a vertex 'n' to the graph and then returns the Vertex for it.\n    /// </summary>\n    Vertex GetVertex(Node n) {\n      Contract.Ensures(Contract.Result<Vertex>() != null);\n\n      Vertex v = FindVertex(n);\n      if (v == null) {\n        v = new Vertex(n);\n        vertices.Add(n, v);\n        if (sccComputed) {\n          Contract.Assert(topologicallySortedRepresentatives != null);  // follows from object invariant\n          v.SccRepresentative = v;\n          v.SccMembers = new List<Vertex>();\n          v.SccMembers.Add(v);\n          v.SccId = topologicallySortedRepresentatives.Count;\n          topologicallySortedRepresentatives.Add(v);\n        }\n      }\n      return v;\n    }\n\n    /// <summary>\n    /// Returns the vertex for 'n' if 'n' is in the graph.  Otherwise, returns null.\n    /// </summary>\n    public Vertex FindVertex(Node n) {\n      Vertex v;\n      if (vertices.TryGetValue(n, out v)) {\n        Contract.Assert(v != null);  // follows from postcondition of TryGetValue (since 'vertices' maps to the type Vertex!)\n        return v;\n      } else {\n        return null;\n      }\n    }\n\n    /// <summary>\n    /// Idempotently adds vertices 'from' and 'to' the graph, and then\n    /// adds an edge from 'from' to 'to'.\n    /// </summary>\n    public void AddEdge(Node from, Node to) {\n      Vertex v0 = GetVertex(from);\n      Vertex v1 = GetVertex(to);\n      v0.AddSuccessor(v1);\n      sccComputed = false;  // the addition of an edge may invalidate any previous computation of the graph's SCCs\n    }\n\n    /// <summary>\n    /// Idempotently adds 'n' as a vertex and then returns a Node that is the representative element of the\n    /// strongly connected component containing 'n'.\n    /// </summary>\n    public Node GetSCCRepresentative(Node n) {\n      return GetSCCRepr(n).N;\n    }\n\n    /// <summary>\n    /// Idempotently adds 'n' as a vertex.  Then, returns the number of SCCs before the SCC of 'n' in the\n    /// topologically sorting of SCCs.\n    /// </summary>\n    public int GetSCCRepresentativeId(Node n) {\n      return GetSCCRepr(n).SccId;\n    }\n\n    Vertex GetSCCRepr(Node n) {\n      Contract.Ensures(Contract.Result<Vertex>() != null);\n\n      Vertex v = GetVertex(n);\n      ComputeSCCs();\n      Contract.Assert(v.SccRepresentative != null);  // follows from what ComputeSCCs does\n      return v.SccRepresentative;\n    }\n\n    /// <summary>\n    /// Returns a list of the topologically sorted SCCs, each represented in the list by its representative node.\n    /// </summary>\n    public List<Node> TopologicallySortedComponents() {\n      Contract.Ensures(cce.NonNullElements(Contract.Result<List<Node>>()));\n      ComputeSCCs();\n      Contract.Assert(topologicallySortedRepresentatives != null);  // follows from object invariant\n      List<Node> nn = new List<Node>();\n      foreach (Vertex v in topologicallySortedRepresentatives) {\n        nn.Add(v.N);\n      }\n      return nn;\n    }\n\n    /// <summary>\n    /// Idempotently adds 'n' as a vertex and then returns the set of Node's in the strongly connected component\n    /// that contains 'n'.\n    /// </summary>\n    public List<Node> GetSCC(Node n) {Contract.Ensures(cce.NonNullElements(Contract.Result<List<Node>>()));\n      Vertex v = GetVertex(n);\n      ComputeSCCs();\n      Vertex repr = v.SccRepresentative;\n      Contract.Assert(repr != null && repr.SccMembers != null);  // follows from postcondition of ComputeSCCs\n      List<Node> nn = new List<Node>();\n      foreach (Vertex w in repr.SccMembers) {\n        nn.Add(w.N);\n      }\n      return nn;\n    }\n\n    /// <summary>\n    /// Idempotently adds 'n' as a vertex and then returns the size of the set of Node's in the strongly connected component\n    /// that contains 'n'.\n    /// </summary>\n    public int GetSCCSize(Node n){\n      Contract.Ensures(1 <= Contract.Result<int>());\n\n      Vertex v = GetVertex(n);\n      ComputeSCCs();\n      Vertex repr = v.SccRepresentative;\n      Contract.Assert(repr != null && repr.SccMembers != null);  // follows from postcondition of ComputeSCCs\n      return repr.SccMembers.Count;\n    }\n\n    /// <summary>\n    /// This method sets the SccRepresentative fields of the graph's vertices so that two\n    /// vertices have the same representative iff they are in the same strongly connected\n    /// component.\n    /// As a side effect, this method may change the Visited, DfNumber, and LowLink fields\n    /// of the vertices.\n    /// </summary>\n    void ComputeSCCs()\n    {\n      Contract.Ensures(sccComputed);\n\n      if (sccComputed) { return; }  // check if already computed\n\n      // reset all SCC information\n      topologicallySortedRepresentatives = new List<Vertex>();\n      foreach (Vertex v in vertices.Values) {\n        v.Visited = VisitedStatus.Unvisited;\n        v.SccMembers = null;\n      }\n      Stack<Vertex> stack = new Stack<Vertex>();\n      int cnt = 0;\n      foreach (Vertex v in vertices.Values) {\n        if (v.Visited == VisitedStatus.Unvisited) {\n          SearchC(v, stack, ref cnt);\n        }\n      }\n      Contract.Assert(cnt == vertices.Count);  // sanity check that everything has been visited\n\n      sccComputed = true;\n    }\n\n    /// <summary>\n    /// This is the 'SearchC' procedure from the Aho, Hopcroft, and Ullman book 'The Design and Analysis of Computer Algorithms'.\n    /// </summary>\n    void SearchC(Vertex/*!*/ v, Stack<Vertex/*!*/>/*!*/ stack, ref int cnt){\n      Contract.Requires(v != null);\n      Contract.Requires(cce.NonNullElements(stack));\n      Contract.Requires(v.Visited == VisitedStatus.Unvisited);\n      Contract.Requires(topologicallySortedRepresentatives != null);\n      Contract.Ensures(v.Visited != VisitedStatus.Unvisited);\n\n      v.DfNumber = cnt;\n      cnt++;\n      v.LowLink = v.DfNumber;\n      stack.Push(v);\n      v.Visited = VisitedStatus.OnStack;\n\n      foreach (Vertex w in v.Successors) {\n        if (w.Visited == VisitedStatus.Unvisited) {\n          SearchC(w, stack, ref cnt);\n          v.LowLink = Math.Min(v.LowLink, w.LowLink);\n        } else if (w.Visited == VisitedStatus.OnStack) {\n          Contract.Assert(w.DfNumber < v.DfNumber || v.LowLink <= w.DfNumber);  // the book also has the guard 'w.DfNumber < v.DfNumber', but that seems unnecessary to me, so this assert is checking my understanding\n          v.LowLink = Math.Min(v.LowLink, w.DfNumber);\n        }\n      }\n\n      if (v.LowLink == v.DfNumber) {\n        // The SCC containing 'v' has now been computed.\n        v.SccId = topologicallySortedRepresentatives.Count;\n        topologicallySortedRepresentatives.Add(v);\n        v.SccMembers = new List<Vertex>();\n        while (true) {\n          Vertex x = stack.Pop();\n          x.Visited = VisitedStatus.Visited;\n          x.SccRepresentative = v;\n          v.SccMembers.Add(x);\n          if (x == v) { break; }\n        }\n      }\n    }\n\n    /// <summary>\n    /// Return all cycles in the graph.\n    /// More precisely, return a maximal set of non-overlapping cycles.\n    /// </summary>\n    public List<List<Node>> AllCycles() {\n      // reset all visited information\n      foreach (Vertex v in vertices.Values) {\n        v.Visited = VisitedStatus.Unvisited;\n      }\n      var stack = new List<Vertex>();\n      var allCycles = new List<List<Node>>();\n      foreach (var v in vertices.Values) {\n        Contract.Assert(v.Visited != VisitedStatus.OnStack);\n        if (v.Visited == VisitedStatus.Unvisited) {\n          AllCycles_aux(v, stack, allCycles);\n        }\n      }\n      return allCycles;\n    }\n\n    private void AllCycles_aux(Vertex vertex, List<Vertex> stack, List<List<Node>> cycles) {\n      Contract.Requires(vertex != null);\n      Contract.Requires(cycles != null);\n      Contract.Requires(vertex.Visited == VisitedStatus.Unvisited);\n      // requires: everything on \"stack\" is either Unvisited or OnStack\n      Contract.Ensures(vertex.Visited == VisitedStatus.Visited);\n\n      vertex.Visited = VisitedStatus.OnStack;\n      stack.Add(vertex);\n      foreach (var succ in vertex.Successors) {\n        switch (succ.Visited) {\n          case VisitedStatus.Visited:\n            // ignore this successor\n            break;\n          case VisitedStatus.Unvisited:\n            AllCycles_aux(succ, stack, cycles);\n            break;\n          case VisitedStatus.OnStack: {\n              // We discovered a cycle. succ is somewhere on the stack.\n              var s = stack.Count;\n              while (true) {\n                --s;\n                if (stack[s].Visited == VisitedStatus.Visited) {\n                  // a cycle involving stack[s] has already been reported, so don't report the new cycle we found\n                  break;\n                }\n                Contract.Assert(stack[s].Visited == VisitedStatus.OnStack);\n                if (stack[s] == succ) {\n                  // this is where the cycle starts\n                  var cycle = new List<Node>();\n                  for (int i = s; i < stack.Count; i++) {\n                    cycle.Add(stack[i].N);\n                    stack[i].Visited = VisitedStatus.Visited;\n                  }\n                  cycles.Add(cycle);\n                  break;\n                }\n              }\n            }\n            break;\n          default:\n            Contract.Assert(false); // unexpected Visited value\n            break;\n        }\n      }\n      stack.RemoveAt(stack.Count - 1);  // pop\n      vertex.Visited = VisitedStatus.Visited;\n    }\n\n    /// <summary>\n    /// Returns null if the graph has no cycles.  If the graph does contain some cycle, returns the list of\n    /// vertices on one such cycle.\n    /// </summary>\n    public List<Node> TryFindCycle() {\n      // reset all visited information\n      foreach (Vertex v in vertices.Values) {\n        v.Visited = VisitedStatus.Unvisited;\n      }\n\n      foreach (Vertex v in vertices.Values) {\n        Contract.Assert(v.Visited != VisitedStatus.OnStack);\n        if (v.Visited == VisitedStatus.Unvisited) {\n          List<Vertex> cycle = CycleSearch(v);\n          if (cycle != null) {\n            List<Node> nodes = new List<Node>();\n            foreach (Vertex v_ in cycle) {\n              nodes.Add(v_.N);\n            }\n            return nodes;  // a cycle is found\n          }\n        }\n      }\n      return null;  // there are no cycles\n    }\n\n    /// <summary>\n    /// A return of null means there are no cycles involving any vertex in the subtree rooted at v.\n    /// A non-null return means a cycle has been found.  Then:\n    /// If v.Visited == Visited, then the entire cycle is described in the returned list.\n    /// If v.Visited == OnStack, then the cycle consists of the vertices strictly deeper than\n    /// w on the stack followed by the vertices (in reverse order) in the returned list, where\n    /// w is the first vertex in the list returned.\n    /// </summary>\n    List<Vertex/*!*/> CycleSearch(Vertex v)\n    {\n      Contract.Requires(v != null);\n      Contract.Requires(v.Visited == VisitedStatus.Unvisited);\n      Contract.Ensures(v.Visited != VisitedStatus.Unvisited);\n      Contract.Ensures(Contract.Result<List<Vertex>>() != null || v.Visited == VisitedStatus.Visited);\n      Contract.Ensures(Contract.Result<List<Vertex>>() == null || Contract.Result<List<Vertex>>().Count != 0);\n\n      v.Visited = VisitedStatus.OnStack;\n      foreach (Vertex succ in v.Successors) {\n        // todo:  I would use a 'switch' statement, but there seems to be a bug in the Spec# compiler's type checking.\n        if (succ.Visited == VisitedStatus.Visited) {\n          // there is no cycle in the subtree rooted at succ, hence this path does not give rise to any cycles\n        } else if (succ.Visited == VisitedStatus.OnStack) {\n          // we found a cycle!\n          List<Vertex> cycle = new List<Vertex>();\n          cycle.Add(succ);\n          if (v == succ) {\n            // entire cycle has been found\n            v.Visited = VisitedStatus.Visited;\n          }\n          return cycle;\n        } else {\n          Contract.Assert(succ.Visited == VisitedStatus.Unvisited);\n          List<Vertex> cycle = CycleSearch(succ);\n          if (cycle != null) {\n            if (succ.Visited == VisitedStatus.Visited) {\n              // the entire cycle has been collected\n              v.Visited = VisitedStatus.Visited;\n              return cycle;\n            } else {\n              cycle.Add(succ);\n              if (v == cycle[0]) {\n                // the entire cycle has been collected and we are the first to find out\n                v.Visited = VisitedStatus.Visited;\n              }\n              return cycle;\n            }\n          }\n        }\n      }\n      v.Visited = VisitedStatus.Visited;  // there are no cycles from here on\n      return null;\n    }\n\n    /// <summary>\n    /// Returns whether or not 'source' reaches 'sink' in the graph.\n    /// 'source' and 'sink' need not be in the graph; if neither is, the return value\n    /// is source==sink.\n    /// </summary>\n    public bool Reaches(Node source, Node sink) {\n      Vertex a = FindVertex(source);\n      Vertex b = FindVertex(sink);\n      if (a == null || b == null) {\n        return source.Equals(sink);\n      }\n      generation++;\n      return ReachSearch(a, b);\n    }\n\n    bool ReachSearch(Vertex source, Vertex sink) {\n      Contract.Requires(source != null);\n      Contract.Requires(sink != null);\n      if (source == sink) {\n        return true;\n      } else if (source.Gen == generation) {\n        // already visited\n        return false;\n      } else {\n        source.Gen = generation;\n        return Contract.Exists(source.Successors,succ=> ReachSearch(succ, sink));\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "Source/Armada/StackVarHiding.cs",
    "content": "using System;\nusing System.Numerics;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text;\nusing System.Text.RegularExpressions;\nusing IToken = Microsoft.Boogie.IToken;\nusing Token = Microsoft.Boogie.Token;\n\nnamespace Microsoft.Armada {\n\n  public class StackVarHidingProofGenerator : VarHidingProofGenerator\n  {\n    private StackVariableHidingStrategyDecl strategy;\n    private string hiddenVariablesMethodName;\n    private HashSet<string> hiddenVariables;\n\n    public StackVarHidingProofGenerator(ProofGenerationParams i_pgp, StackVariableHidingStrategyDecl i_strategy)\n      : base(i_pgp, false)\n    {\n      strategy = i_strategy;\n      hiddenVariablesMethodName = strategy.MethodName;\n      hiddenVariables = new HashSet<string>(strategy.Variables);\n\n      foreach (var varName in strategy.Variables) {\n        var v = pgp.symbolsLow.Lookup(hiddenVariablesMethodName, varName);\n        if (!(v is MethodStackFrameUnaddressableLocalArmadaVariable)) {\n          AH.PrintError(pgp.prog, $\"Variable {hiddenVariablesMethodName}.{varName} isn't a noaddr stack variable, but stack_var_hiding can only hide noaddr stack variables\");\n        }\n      }\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    /// Checking that the layers are similar enough to generate a proof\n    ////////////////////////////////////////////////////////////////////////\n\n    protected override bool CheckVariableNameListEquivalence(IEnumerable<string> varNames_l, IEnumerable<string> varNames_h,\n                                                             ArmadaSingleMethodSymbolTable s_l, ArmadaSingleMethodSymbolTable s_h,\n                                                             string methodName, string descriptor)\n    {\n      string[] vars_l;\n      if (methodName == hiddenVariablesMethodName) {\n        vars_l = varNames_l.Where(v => !hiddenVariables.Contains(v)).ToArray();\n      }\n      else {\n        vars_l = varNames_l.ToArray();\n      }\n      var vars_h = varNames_h.ToArray();\n      if (vars_l.Length != vars_h.Length) {\n        AH.PrintError(pgp.prog, $\"Method {methodName} has {vars_l.Length} {descriptor} non-hidden variables in level {pgp.mLow.Name} but {vars_h.Length} of them in level {pgp.mHigh.Name}\");\n        return false;\n      }\n\n      for (int i = 0; i < vars_l.Length; ++i) {\n        var name_l = vars_l[i];\n        var name_h = vars_h[i];\n        if (name_l != name_h) {\n          AH.PrintError(pgp.prog, $\"In method {methodName}, {descriptor} non-hidden variable number {i+1} is named {name_l} in level {pgp.mLow.Name} but named {name_h} in level {pgp.mHigh.Name}\");\n          return false;\n        }\n        var v_l = s_l.LookupVariable(name_l);\n        var v_h = s_h.LookupVariable(name_h);\n        if (!AH.TypesMatch(v_l.ty, v_h.ty)) {\n          AH.PrintError(pgp.prog, $\"In method {methodName}, the {descriptor} variable named {name_l} has type {v_l.ty} in level {pgp.mLow.Name} but type {v_h.ty} in level {pgp.mHigh.Name}\");\n          return false;\n        }\n      }\n\n      return true;\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    /// Abstraction functions\n    ////////////////////////////////////////////////////////////////////////\n\n    protected override bool IsVariableHidden(string methodName, string varName)\n    {\n      return methodName == hiddenVariablesMethodName && hiddenVariables.Contains(varName);\n    }\n\n    protected override void GenerateConvertStackVars_LH(string methodName)\n    {\n      var smst = pgp.symbolsLow.GetMethodSymbolTable(methodName);\n      var ps = smst.AllVariablesInOrder.Where(v => !IsVariableHidden(methodName, v.FieldName)).Select(v => $\"vs.{v.FieldName}\");\n      var fn = $@\"\n        function ConvertStackVars_LH_{methodName}(vs: L.Armada_StackVars_{methodName}) : H.Armada_StackVars_{methodName}\n        {{\n          H.Armada_StackVars_{methodName}({AH.CombineStringsWithCommas(ps)})\n        }}\n      \";\n      pgp.AddFunction(fn, \"convert\");\n    }\n\n    protected override void GenerateConvertAtomicPath_LH()\n    {\n      var skipped_strs = new List<string>();\n\n      string convert_str = @\"\n        function ConvertAtomicPath_LH(s: LPlusState, path: LAtomic_Path, tid: Armada_ThreadHandle) : HAtomic_Path\n          requires !IsSkippedPath(s, path, tid)\n        {\n          match path\n      \";\n\n      foreach (var lpath in lAtomic.AtomicPaths) {\n        if (pathMap.ContainsKey(lpath)) {\n          var hpath = pathMap[lpath];\n          var n = lpath.NextRoutines.Count;\n          convert_str += $\"case LAtomic_Path_{lpath.Name}(steps) => HAtomic_Path_{hpath.Name}(HAtomic_PathSteps_{hpath.Name}(\";\n          convert_str += String.Join(\", \", Enumerable.Range(0, n)\n                                                     .Where(i => nextRoutineMap.ContainsKey(lpath.NextRoutines[i]))\n                                                     .Select(i => $\"ConvertStep_LH(steps.step{i})\"));\n          convert_str += \"))\\n\";\n        }\n        else {\n          skipped_strs.Add($\"path.LAtomic_Path_{lpath.Name}?\");\n        }\n      }\n\n      convert_str += \"}\\n\";\n\n      pgp.AddPredicate($@\"\n        predicate IsSkippedPath(s: LPlusState, path:LAtomic_Path, tid: Armada_ThreadHandle)\n        {{\n          { AH.CombineStringsWithOr(skipped_strs) }\n        }}\n      \", \"convert\");\n      pgp.AddFunction(convert_str, \"convert\");\n    }\n\n    protected override string GetStepCaseForNormalNextRoutine_LH(NextRoutine nextRoutine)\n    {\n      string nextRoutineName = nextRoutine.NameSuffix;\n\n      var bvs = nextRoutine.HasFormals ? $\"params: L.Armada_StepParams_{nextRoutine.NameSuffix}\" : \"\";\n      var hNextRoutine = LiftNextRoutine(nextRoutine);\n      var ps = hNextRoutine.Formals.Select(f => $\"params.{f.LocalVarName}\");\n      string hname = hNextRoutine.NameSuffix;\n      var caseBody = hNextRoutine.HasFormals ? $\"H.Armada_Step_{hname}(H.Armada_StepParams_{hname}({AH.CombineStringsWithCommas(ps)}))\"\n                                             : $\"H.Armada_Step_{hname}\";\n      return $\"case Armada_Step_{nextRoutineName}({bvs}) => {caseBody}\\n\";\n    }\n  }\n\n}\n"
  },
  {
    "path": "Source/Armada/StackVarIntro.cs",
    "content": "using System.Collections.Generic;\nusing System.Linq;\nusing System;\n\nnamespace Microsoft.Armada\n{\n  public class StackVarIntroProofGenerator : VarIntroProofGenerator\n  {\n    protected StackVariableIntroStrategyDecl strategy;\n    public StackVarIntroProofGenerator(ProofGenerationParams i_pgp, StackVariableIntroStrategyDecl i_strategy)\n      : base(i_pgp, false)\n    {\n      strategy = i_strategy;\n      var v = pgp.symbolsHigh.Lookup(strategy.MethodName, strategy.VariableName);\n      if (!(v is MethodStackFrameUnaddressableLocalArmadaVariable)) {\n        AH.PrintError(pgp.prog, $\"Variable {strategy.MethodName}.{strategy.VariableName} isn't a noaddr stack variable, but stack_var_intro can only introduce noaddr stack variables\");\n      }\n    }\n\n    protected override bool CheckVariableNameListEquivalence(IEnumerable<string> varNames_l, IEnumerable<string> varNames_h,\n                                                            ArmadaSingleMethodSymbolTable s_l, ArmadaSingleMethodSymbolTable s_h,\n                                                            string methodName, string descriptor)\n    {\n      var vars_l = varNames_l.ToArray();\n      string[] vars_h;\n      if (methodName == strategy.MethodName) {\n        vars_h = varNames_h.Where(v => v != strategy.VariableName).ToArray();\n      }\n      else {\n        vars_h = varNames_h.ToArray();\n      }\n\n      if (vars_l.Length != vars_h.Length) {\n        AH.PrintError(pgp.prog, $\"Method {methodName} has {vars_l.Length} {descriptor} variables in level {pgp.mLow.Name} but {vars_h.Length} of them in level {pgp.mHigh.Name}\");\n        return false;\n      }\n\n      for (int i = 0; i < vars_l.Length; ++i) {\n        var name_l = vars_l[i];\n        var name_h = vars_h[i];\n        if (name_l != name_h) {\n          AH.PrintError(pgp.prog, $\"In method {methodName}, {descriptor} non-introduced variable number {i+1} is named {name_l} in level {pgp.mLow.Name} but named {name_h} in level {pgp.mHigh.Name}\");\n          return false;\n        }\n        var v_l = s_l.LookupVariable(name_l);\n        var v_h = s_h.LookupVariable(name_h);\n        if (!AH.TypesMatch(v_l.ty, v_h.ty)) {\n          AH.PrintError(pgp.prog, $\"In method {methodName}, the {descriptor} variable named {name_l} has type {v_l.ty} in level {pgp.mLow.Name} but type {v_h.ty} in level {pgp.mHigh.Name}\");\n          return false;\n        }\n      }\n\n      return true;\n    }\n\n    protected override bool IsIntroducedVariable(string methodName, string varName)\n    {\n      return methodName == strategy.MethodName && varName == strategy.VariableName;\n    }\n\n    protected override void GenerateConvertStackVars_LH(string methodName)\n    {\n      var smst = pgp.symbolsLow.GetMethodSymbolTable(methodName);\n      var ps = new List<string>();\n\n      var lowVarNames = new List<string>(smst.AllVariableNamesInOrder);\n      foreach (var varName in lowVarNames)\n      {\n        var v = smst.LookupVariable(varName);\n        ps.Add($\"vs.{v.FieldName}\");\n      }\n\n      smst = pgp.symbolsHigh.GetMethodSymbolTable(methodName);\n      var highVars = new List<ArmadaVariable>(smst.AllVariablesInOrder);\n\n      if (highVars.Count() != lowVarNames.Count()) {\n        for (var i = 0; i < highVars.Count(); ++i) {\n          if (!lowVarNames.Contains(highVars[i].name)) {\n            var v = highVars[i];\n            ps.Insert(i, strategy.InitializationExpression);\n          }\n        }\n      }\n\n      var fn = $@\"\n        function ConvertStackVars_LH_{methodName}(vs: L.Armada_StackVars_{methodName}) : H.Armada_StackVars_{methodName}\n        {{\n          H.Armada_StackVars_{methodName}({AH.CombineStringsWithCommas(ps)})\n        }}\n      \";\n      pgp.AddFunction(fn, \"convert\");\n    }\n\n    protected override void GenerateConvertStackVars_HL(string methodName)\n    {\n      var smst = pgp.symbolsHigh.GetMethodSymbolTable(methodName);\n      var ps = new List<string>();\n      foreach (var v in smst.AllVariablesInOrder) {\n        if (methodName != strategy.MethodName || v.name != strategy.VariableName) {\n          ps.Add($\"vs.{v.FieldName}\");\n        }\n      }\n      var fn = $@\"\n        function ConvertStackVars_HL_{methodName}(vs: H.Armada_StackVars_{methodName}) : L.Armada_StackVars_{methodName}\n        {{\n          L.Armada_StackVars_{methodName}({AH.CombineStringsWithCommas(ps)})\n        }}\n      \";\n      pgp.AddFunction(fn, \"convert\");\n    }\n\n    protected override string GetStepCaseForNormalNextRoutine_LH(NextRoutine nextRoutine)\n    {\n      var bvs = nextRoutine.HasFormals ? $\"params: L.Armada_StepParams_{nextRoutine.NameSuffix}\" : \"\";\n      var ps = nextRoutine.Formals.Select(f => $\"params.{f.LocalVarName}\").ToList();\n\n      if (nextRoutine.nextType == NextType.Call &&\n          ((ArmadaCallStatement)nextRoutine.armadaStatement).CalleeName == strategy.MethodName ||\n          nextRoutine.nextType == NextType.CreateThread &&\n          ((nextRoutine.stmt as UpdateStmt).Rhss[0] as CreateThreadRhs).MethodName.val == strategy.MethodName) {\n        var highRoutine = LiftNextRoutine(nextRoutine);\n        var highFormals = new List<NextFormal>(highRoutine.Formals);\n        for (var i = 0; i < highFormals.Count(); ++ i) {\n          if (!nextRoutine.Formals.Any(f => f.LocalVarName == highFormals[i].LocalVarName)) {\n            ps.Insert(i, strategy.InitializationExpression);\n            break;\n          }\n        }\n      }\n\n      var hNextRoutine = LiftNextRoutine(nextRoutine);\n      string hname = hNextRoutine.NameSuffix;\n      var caseBody = hNextRoutine.HasFormals ? $\"H.Armada_Step_{hname}(H.Armada_StepParams_{hname}({AH.CombineStringsWithCommas(ps)}))\"\n                                             : $\"H.Armada_Step_{hname}\";\n      return $\"case Armada_Step_{nextRoutine.NameSuffix}({bvs}) => {caseBody}\\n\";\n    }\n  };\n};\n"
  },
  {
    "path": "Source/Armada/StarWeakening.cs",
    "content": "using System;\nusing System.Numerics;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text;\nusing System.Text.RegularExpressions;\nusing static Microsoft.Armada.Predicate;\nusing IToken = Microsoft.Boogie.IToken;\nusing Token = Microsoft.Boogie.Token;\n\nnamespace Microsoft.Armada {\n\n  public class StarWeakeningProofGenerator : AbstractProofGenerator\n  {\n    private StarWeakeningStrategyDecl strategy;\n    private HashSet<ArmadaPC> weakenedPCs;\n\n    public StarWeakeningProofGenerator(ProofGenerationParams i_pgp, StarWeakeningStrategyDecl i_strategy)\n      : base(i_pgp, true)\n    {\n      strategy = i_strategy;\n      weakenedPCs = new HashSet<ArmadaPC>();\n    }\n\n    protected override void AddIncludesAndImports()\n    {\n      base.AddIncludesAndImports();\n      \n      pgp.MainProof.AddImport(\"InvariantsModule\");\n\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/option.s.dfy\");\n      pgp.MainProof.AddImport(\"util_option_s\");\n\n\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/seqs.s.dfy\");\n      pgp.MainProof.AddImport(\"util_collections_seqs_s\");\n\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/seqs.i.dfy\");\n      pgp.MainProof.AddImport(\"util_collections_seqs_i\");\n\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/sets.i.dfy\");\n      pgp.MainProof.AddImport(\"util_collections_sets_i\");\n\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/maps.i.dfy\");\n      pgp.MainProof.AddImport(\"util_collections_maps_i\");\n    }\n\n    protected override void GenerateConvertStep_LH()\n    {\n      var cases = new List<string>();\n\n      foreach (var nextRoutine in pgp.symbolsLow.NextRoutines) {\n        cases.Add(GetStepCaseForNextRoutine_LH(nextRoutine));\n      }\n\n      var fn = $@\"\n        function ConvertStep_LH(ls: LPlusState, step: L.Armada_Step, tid: Armada_ThreadHandle) : H.Armada_Step\n          requires L.Armada_ValidStep(ls.s, step, tid)\n        {{\n          reveal L.Armada_ValidStepCases();\n          var locv := L.Armada_GetThreadLocalView(ls.s, tid);\n          var t := ls.s.threads[tid];\n          match step\n            {String.Concat(cases)}\n        }}\n      \";\n      pgp.AddFunction(fn, \"convert\");\n    }\n\n    public override void GenerateProof()\n    {\n      if (!CheckEquivalence()) {\n        AH.PrintError(pgp.prog, \"Levels {pgp.mLow.Name} and {pgp.mHigh.Name} aren't sufficiently equivalent to perform refinement proof generation using the variable-hiding strategy\");\n        return;\n      }\n      GetWeakenedPCSet();\n      AddIncludesAndImports();\n      MakeTrivialPCMap();\n      GenerateNextRoutineMap();\n      GenerateProofHeader();\n      GenerateAtomicSpecs();\n      GenerateStateAbstractionFunctions_LH();\n      GeneratePCFunctions_L();\n      foreach (var globalVarName in strategy.GlobalVars)\n      {\n        GenerateNoStoreBufferEntriesLemmas(globalVarName);\n      }\n      GenerateConvertStep_LH();\n      GenerateAllConvertImpliesValidStepLemmas();\n      GenerateConvertAtomicPath_LH();\n      GenerateLocalViewCommutativityLemmas();\n      GenerateInvariantProof(pgp);\n      GenerateEstablishInitRequirementsLemma();\n      GenerateEstablishStateOKRequirementLemma();\n      GenerateEstablishRelationRequirementLemma();\n      GenerateLiftingRelation();\n      GenerateLiftAtomicPathLemmas();\n      GenerateEstablishAtomicPathLiftableLemma();\n      GenerateEstablishAtomicPathsLiftableLemma(false, false);\n      GenerateLiftLAtomicToHAtomicLemma(false, false);\n      GenerateFinalProof();\n    }\n\n    private void GetWeakenedPCSet()\n    {\n      foreach (var lbl in strategy.Labels) {\n        var pc = pgp.symbolsLow.GetPCForMethodAndLabel(lbl.val);\n        if (pc == null) {\n          AH.PrintError(pgp.prog, $\"Specified non-existent label {lbl.val} in star-weakening strategy description.  Remember to prefix label names with the method name and an underscore, e.g., use main_lb1 if you have label lb1: in method main.\");\n        }\n        else {\n          weakenedPCs.Add(pc);\n        }\n      }\n    }\n\n    private bool LhsEquivalentAcrossConvert(Expression a, Expression b) {\n      /*\n      if (a is NameSegment) {\n        return (b is NameSegment) && ((NameSegment)a).Name == ((NameSegment)b).Name;\n      }\n      */\n      return Printer.ExprToString(a) == Printer.ExprToString(b);\n    }\n\n    protected string GetStepCaseForUpdateToSomehowNextRoutine_LH(NextRoutine nextRoutine)\n    {\n      var hNextRoutine = nextRoutineMap[nextRoutine];\n      var lowStmt = (UpdateStmt)nextRoutine.armadaStatement.Stmt;\n      var lowExprs = lowStmt.Lhss;\n\n      var hStmt = (SomehowStmt)hNextRoutine.armadaStatement.Stmt;\n      var hExprs = hStmt.Mod.Expressions;\n\n      var pi = GetMatchingLowLevelLhssForHighLevelLhss(lowExprs, hExprs);\n      var bvs = nextRoutine.HasFormals ? $\"params: L.Armada_StepParams_{nextRoutine.NameSuffix}\" : \"\";\n      var ps = nextRoutine.Formals.Select(f => $\"params{f.LocalVarName}\").ToList();\n\n      for (int i = 0; i < hExprs.Count; i++) {\n        var failureReporter = new SimpleFailureReporter(pgp.prog);\n        var context = new NormalResolutionContext(\"L\", nextRoutine.method.Name, pgp.symbolsLow, failureReporter);\n        // Add the pi[i]'th rhs from the low-level update statement\n        var rhs = lowStmt.Rhss.ElementAt(pi[i]);\n        if (rhs is ExprRhs) {\n          var erhs = (ExprRhs)rhs;\n          var newRhsRValue = context.ResolveAsRValue(erhs.Expr);\n          ps.Add(newRhsRValue.Val);\n        }\n        else {\n          AH.PrintError(pgp.prog, \"Havoc RHS not yet supported\");\n          return null;\n        }\n      }\n\n      string hname = hNextRoutine.NameSuffix;\n      var caseBody = hNextRoutine.HasFormals ? $\"H.Armada_Step_{hname}(H.Armada_StepParams_{hname}({AH.CombineStringsWithCommas(ps)}))\"\n                                               : $\"H.Armada_Step_{hname}\";\n      return $\"case Armada_Step_{nextRoutine.NameSuffix}({bvs}) => {caseBody}\\n\";\n    }\n\n    protected List<int> GetMatchingLowLevelLhssForHighLevelLhss(List<Expression> lowLhss, List<Expression> highLhss)\n    {\n      var pi = new List<int>();\n      for (int i = 0; i < highLhss.Count; i++) {\n        int pi_i = -1;\n        for (int j = 0; j < lowLhss.Count; j++) {\n          // Want to find the last lowExpr that matches; this handles `x, x := 1, 2` to `x := *` correctly\n          if(LhsEquivalentAcrossConvert(highLhss[i], lowLhss[j])) {\n            pi_i = j;\n          }\n        }\n        if (pi_i == -1) {\n          AH.PrintError(pgp.prog, $\"Unable to find matching LHS for {Printer.ExprToString(highLhss[i])}\");\n        }\n        pi.Add(pi_i);\n      }\n      return pi;\n    }\n\n    protected string GetStepCaseForUpdateToUpdateNextRoutine_LH(NextRoutine nextRoutine)\n    {\n      var hNextRoutine = nextRoutineMap[nextRoutine];\n      var lowStmt = (UpdateStmt)nextRoutine.armadaStatement.Stmt;\n      var lowExprs = lowStmt.Lhss;\n\n      var hStmt = (UpdateStmt)hNextRoutine.armadaStatement.Stmt;\n      var hExprs = hStmt.Lhss;\n\n      var pi = GetMatchingLowLevelLhssForHighLevelLhss(lowExprs, hExprs);\n      var bvs = nextRoutine.HasFormals ? $\"params: L.Armada_StepParams_{nextRoutine.NameSuffix}\" : \"\";\n      var ps = new List<string>();\n\n      for (int i = 0; i < hExprs.Count; i++) {\n        var failureReporter = new SimpleFailureReporter(pgp.prog);\n        var context = new NormalResolutionContext(\"L\", nextRoutine.method.Name, pgp.symbolsLow, failureReporter);\n        // Add the pi[i]'th rhs from the low-level update statement\n        var rhs = lowStmt.Rhss.ElementAt(pi[i]);\n        string newRhs;\n        if (rhs is ExprRhs) {\n          var erhs = (ExprRhs)rhs;\n          var newRhsRValue = context.ResolveAsRValue(erhs.Expr);\n          newRhs = newRhsRValue.Val;\n        }\n        else { // rhs must be HavocRhs here\n          newRhs = $\"params.nondet{i}\";\n        }\n        if (hStmt.Rhss.ElementAt(i) is HavocRhs) { // If the high level is a havoc-rhs, then it needs to be given the values\n          ps.Add(newRhs);\n        }\n      }\n\n      string hname = hNextRoutine.NameSuffix;\n      var caseBody = hNextRoutine.HasFormals ? $\"H.Armada_Step_{hname}(H.Armada_StepParams_{hname}({AH.CombineStringsWithCommas(ps)}))\"\n                                               : $\"H.Armada_Step_{hname}\";\n      return $\"case Armada_Step_{nextRoutine.NameSuffix}({bvs}) => {caseBody}\\n\";\n    }\n\n    protected string GetStepCaseForIfToIfNextRoutine_LH(NextRoutine nextRoutine)\n    {\n      string hname = nextRoutineMap[nextRoutine].NameSuffix;\n      return $\"case Armada_Step_{nextRoutine.NameSuffix}() => H.Armada_Step_{hname}\\n\";\n    }\n\n    protected override string GetStepCaseForNextRoutine_LH(NextRoutine nextRoutine)\n    {\n      var hNextRoutine = LiftNextRoutine(nextRoutine);\n\n      if (hNextRoutine == null) {\n        return GetStepCaseForSuppressedNextRoutine_LH(nextRoutine);\n      }\n\n      if (hNextRoutine.nextType == NextType.Update\n            && nextRoutine.nextType == NextType.Update) {\n        // e.g.  low-level: v_1 := e_1;\n        //      high-level: v_1 := *\n        //\n        // Also low-level: v_1 ::= e_1;\n        //      high-level: v_1 ::= *\n        return GetStepCaseForUpdateToUpdateNextRoutine_LH(nextRoutine);\n      }\n      else if ((hNextRoutine.nextType == NextType.IfTrue || hNextRoutine.nextType == NextType.IfFalse)\n               && (nextRoutine.nextType == NextType.IfTrue || nextRoutine.nextType == NextType.IfFalse)) {\n        // e.g.  low-level: if p {}\n        //      high-level: if * {}\n        return GetStepCaseForIfToIfNextRoutine_LH(nextRoutine);\n      }\n      else if (hNextRoutine.nextType == NextType.Somehow\n            && nextRoutine.nextType == NextType.Update) {\n        // low-level: v_1, ..., v_n ::= e_1, ..., e_n;\n        // high-level: for some permutation pi \\in S_n,\n        // somehow modifies v_{pi_1}\n        //         ...\n        //         modifies v_{pi_n}\n        //\n        // In order for star weakening to be possible, it is necessary for a permutation as above to exist.\n        // This can be made part of CheckEquivalence\n        //\n        // Then, the low level step of NextStep()\n        // newval{j} is the non-det variable that holds the new value of v_{pi_j}. So,\n        // the j'th value in the list of hstep params given in the constructor called by \n        // ConvertStep_LH should be e_{pi_j}.\n        return GetStepCaseForUpdateToSomehowNextRoutine_LH(nextRoutine);\n      }\n      else if (hNextRoutine.nextType == nextRoutine.nextType) {\n        return GetStepCaseForNormalNextRoutine_LH(nextRoutine);\n      }\n      AH.PrintError(pgp.prog, \"Invalid statement for weakening.\");\n      return null;\n    }\n\n    protected override string GetStepCaseForNormalNextRoutine_LH(NextRoutine nextRoutine)\n    {\n      var bvs = nextRoutine.HasFormals ? $\"params: L.Armada_StepParams_{nextRoutine.NameSuffix}\" : \"\";\n      var ps = nextRoutine.Formals.Select(f => $\"params.{f.LocalVarName}\");\n\n      var hNextRoutine = nextRoutineMap[nextRoutine];\n      string hname = hNextRoutine.NameSuffix;\n      var caseBody = hNextRoutine.HasFormals ? $\"H.Armada_Step_{hname}(H.Armada_StepParams_{hname}({AH.CombineStringsWithCommas(ps)}))\"\n                                             : $\"H.Armada_Step_{hname}\";\n      return $\"case Armada_Step_{nextRoutine.NameSuffix}({bvs}) => {caseBody}\\n\";\n    }\n\n    protected override void GenerateLiftAtomicPathLemmaForNormalPath(AtomicPath atomicPath, string typeComparison,\n                                                                     string extraSignatureLines, string extraProof)\n    {\n      var isValidStepLemmaInvocations = String.Concat(atomicPath.NextRoutines\n          .Where(nextRoutine => nextRoutine.stmt != null && nextRoutine.startPC != null && weakenedPCs.Contains(nextRoutine.startPC))\n          .Select((nextRoutine, idx) => $@\"\n             lemma_Step_{nextRoutine.NameSuffix}_ImpliesConvertedIsValidStep(\n               lstates.s{idx}, lstates.s{idx+1}, lsteps.step{idx}, hsteps.step{idx}, tid);\n          \"));\n      base.GenerateLiftAtomicPathLemmaForNormalPath(atomicPath, typeComparison, extraSignatureLines,\n                                                    extraProof + \"\\n\" + isValidStepLemmaInvocations);\n    }\n\n    private void GenerateConvertImpliesValidStepLemma(NextRoutine nextRoutine)\n    {\n      NextRoutine hNextRoutine = nextRoutineMap[nextRoutine];\n      string hNextRoutineName = hNextRoutine.NameSuffix;\n\n      var hstep_params = String.Join(\"\", hNextRoutine.Formals.Select(f => $\", hentry.{f.GloballyUniqueVarName}\"));\n\n      var lpr = new ModuleStepPrinter(\"L\");\n      lpr.State = \"ls.s\";\n      lpr.NextState = \"ls'.s\";\n      lpr.Step = \"lstep\";\n      var hpr = new ModuleStepPrinter(\"H\");\n      hpr.State = \"hs\";\n      hpr.NextState = \"hs'\";\n      hpr.Step = \"hstep\";\n\n      var str = $@\"\n        lemma lemma_Step_{nextRoutine.NameSuffix}_ImpliesConvertedIsValidStep(\n          ls: LPlusState,\n          ls': LPlusState,\n          lstep: L.Armada_Step,\n          hstep: H.Armada_Step,\n          tid: Armada_ThreadHandle\n          )\n          requires LPlus_ValidStep(ls, lstep, tid)\n          requires ls' == LPlus_GetNextState(ls, lstep, tid)\n          requires lstep.Armada_Step_{nextRoutine.NameSuffix}?\n          requires InductiveInv(ls)\n          requires hstep == ConvertStep_LH(ls, lstep, tid)\n          ensures  H.Armada_ValidStep(ConvertTotalState_LPlusH(ls), hstep, tid)\n        {{\n          { lpr.GetOpenValidStepInvocation(nextRoutine) }\n          var hs := ConvertTotalState_LPlusH(ls);\n          var hs' := H.Armada_GetNextState(hs, hstep, tid);\n          lemma_GetThreadLocalViewAlwaysCommutesWithConvert();\n      \";\n      foreach (var globalVarName in strategy.GlobalVars) {\n        str += $\"lemma_DoesNotAppearInStoreBufferImpliesThreadLocalViewOf_GlobalStaticVar_{globalVarName}_AlwaysMatchesGlobalView();\\n\";\n      }\n      str += hpr.GetOpenStepInvocation(hNextRoutine);\n      str += \"ProofCustomizationGoesHere(); }\";\n      pgp.AddLemma(str, \"lift\");\n    }\n\n    private void GenerateAllConvertImpliesValidStepLemmas()\n    {\n      foreach (var nextRoutine in pgp.symbolsLow.NextRoutines) {\n        if (nextRoutine.stmt != null && nextRoutine.startPC != null && weakenedPCs.Contains(nextRoutine.startPC)) {\n          GenerateConvertImpliesValidStepLemma(nextRoutine);\n        }\n      }\n    }\n\n    private void GenerateNoStoreBufferEntriesLemmas(string globalVarName)\n    {\n      var str =$@\"\n        predicate H_Armada_GlobalStaticVar_{globalVarName}_DoesNotAppearInStoreBuffer(hs: HState)\n        {{\n          forall storeBufferEntry, tid :: tid in hs.threads && storeBufferEntry in hs.threads[tid].storeBuffer && storeBufferEntry.loc.Armada_StoreBufferLocation_Unaddressable?\n            ==> storeBufferEntry.loc.v != H.Armada_GlobalStaticVar_{globalVarName}\n        }}\n      \";\n      pgp.AddPredicate(str, \"defs\");\n\n      \n      str =$@\"\n        predicate L_Armada_GlobalStaticVar_{globalVarName}_DoesNotAppearInStoreBuffer(ls: LPlusState)\n        {{\n          forall storeBufferEntry, tid :: tid in ls.s.threads && storeBufferEntry in ls.s.threads[tid].storeBuffer && storeBufferEntry.loc.Armada_StoreBufferLocation_Unaddressable?\n            ==> storeBufferEntry.loc.v != L.Armada_GlobalStaticVar_{globalVarName}\n        }}\n      \";\n      pgp.AddPredicate(str, \"defs\");\n      AddInvariant(new InternalInvariantInfo($@\"GlobalStaticVar_{globalVarName}_DoesNotAppearInStoreBuffer\", $@\"L_Armada_GlobalStaticVar_{globalVarName}_DoesNotAppearInStoreBuffer\", new List<string>()));\n\n      str = $@\"\n        lemma lemma_DoesNotAppearInStoreBufferImplies_GlobalStaticVar_{globalVarName}_UnchangedByApplyStoreBuffer(mem: H.Armada_SharedMemory, storeBuffer: seq<H.Armada_StoreBufferEntry>)\n          requires forall storeBufferEntry :: storeBufferEntry in storeBuffer && storeBufferEntry.loc.Armada_StoreBufferLocation_Unaddressable?\n          ==> storeBufferEntry.loc.v != H.Armada_GlobalStaticVar_{globalVarName}\n          ensures H.Armada_ApplyStoreBuffer(mem, storeBuffer).globals.{globalVarName} == mem.globals.{globalVarName}\n          decreases |storeBuffer|\n        {{\n          if |storeBuffer| == 0 {{\n          }}\n          else {{\n            var mem' := H.Armada_ApplyStoreBufferEntry(mem, storeBuffer[0]);\n            assert mem'.globals.{globalVarName} == mem.globals.{globalVarName};\n            lemma_DoesNotAppearInStoreBufferImplies_GlobalStaticVar_{globalVarName}_UnchangedByApplyStoreBuffer(mem, storeBuffer[1..]);\n          }}\n        }}\n      \";\n      pgp.AddLemma(str, \"utility\");\n\n      str = $@\"\n        lemma lemma_DoesNotAppearInStoreBufferImpliesThreadLocalViewOf_GlobalStaticVar_{globalVarName}_MatchesGlobalView(hs: HState, tid: Armada_ThreadHandle)\n          requires tid in hs.threads\n          requires H_Armada_GlobalStaticVar_{globalVarName}_DoesNotAppearInStoreBuffer(hs)\n          ensures hs.mem.globals.{globalVarName} == H.Armada_GetThreadLocalView(hs, tid).globals.{globalVarName}\n        {{\n          lemma_DoesNotAppearInStoreBufferImplies_GlobalStaticVar_{globalVarName}_UnchangedByApplyStoreBuffer(hs.mem, hs.threads[tid].storeBuffer);\n        }}\n      \";\n      pgp.AddLemma(str, \"utility\");\n\n      str = $@\"\n        lemma lemma_DoesNotAppearInStoreBufferImpliesThreadLocalViewOf_GlobalStaticVar_{globalVarName}_AlwaysMatchesGlobalView()\n        ensures forall hs, tid :: H_Armada_GlobalStaticVar_{globalVarName}_DoesNotAppearInStoreBuffer(hs) && tid in hs.threads ==> hs.mem.globals.{globalVarName} == H.Armada_GetThreadLocalView(hs, tid).globals.{globalVarName}\n        {{\n          forall hs, tid |\n            H_Armada_GlobalStaticVar_{globalVarName}_DoesNotAppearInStoreBuffer(hs) && tid in hs.threads\n            ensures hs.mem.globals.{globalVarName} == H.Armada_GetThreadLocalView(hs, tid).globals.{globalVarName}\n            {{\n              lemma_DoesNotAppearInStoreBufferImpliesThreadLocalViewOf_GlobalStaticVar_{globalVarName}_MatchesGlobalView(hs, tid);\n            }}\n        }}\n      \";\n      pgp.AddLemma(str, \"utility\");\n\n\n      str = $@\"\n        lemma Armada_GlobalStaticVar_{globalVarName}_DoesNotAppearInStoreBuffer_LPlusImpliesH(ls: LPlusState, hs: HState)\n          requires L_Armada_GlobalStaticVar_{globalVarName}_DoesNotAppearInStoreBuffer(ls)\n          requires hs == ConvertTotalState_LPlusH(ls)\n          ensures H_Armada_GlobalStaticVar_{globalVarName}_DoesNotAppearInStoreBuffer(hs)\n        {{\n        }}\n      \";\n      pgp.AddLemma(str, \"utility\");\n    }\n  }\n}\n"
  },
  {
    "path": "Source/Armada/StateMachineTranslator.cs",
    "content": "﻿using System;\nusing System.Numerics;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text;\nusing static Microsoft.Armada.Predicate;\nusing IToken = Microsoft.Boogie.IToken;\nusing Token = Microsoft.Boogie.Token;\n\nnamespace Microsoft.Armada {\n\n  public class EnclosingWhile {\n    private List<BreakStmt> breakStatements;\n    private List<ContinueStmt> continueStatements;\n\n    public EnclosingWhile()\n    {\n      breakStatements = new List<BreakStmt>();\n      continueStatements = new List<ContinueStmt>();\n    }\n\n    public List<BreakStmt> BreakStatements { get { return breakStatements; } }\n    public List<ContinueStmt> ContinueStatements { get { return continueStatements; } }\n  }\n\n  ////////////////////////////////////////////////////////////////////////////\n  /// STATE MACHINE TRANSLATOR\n  ////////////////////////////////////////////////////////////////////////////\n\n  public class StateMachineTranslator : IRewriter {\n\n    public Program prog;\n\n    public StateMachineTranslator(Program i_prog)\n      : base(i_prog.reporter) {\n      Contract.Requires(i_prog.reporter != null);\n      prog = i_prog;\n    }\n\n    public Expression ParseExpression(string filename, string s) {\n      var e = new Errors(new ErrorReporterWrapper(prog.reporter, s));\n      return Parser.ParseExpression(s, filename, filename, null, prog.DefaultModule, prog.BuiltIns, e);\n    }\n\n    public static string LocalName(string name) {\n      return name + \"Local\";\n    }\n\n    public bool CheckForConcreteStructDefinition(ArmadaStruct s, ArmadaStructs structs)\n    {\n      foreach (var fieldName in s.FieldNames) {\n        var t = s.GetFieldType(fieldName);\n        if (!AH.IsValidHeapType(t, structs)) {\n          AH.PrintError(prog, $\"Struct {s.Name} has a field {fieldName} of type {t}, which is neither a primitive type nor a struct type.\");\n          return false;\n        }\n      }\n      return true;\n    }\n\n    public bool CheckForConcreteStructDefinitions(ArmadaStructs structs)\n    {\n      foreach (var structName in structs.StructNames) {\n        var s = structs.GetStruct(structName);\n        if (!CheckForConcreteStructDefinition(s, structs)) {\n          return false;\n        }\n      }\n      return true;\n    }\n\n    public bool CheckForCyclicStructDefinition(ArmadaStruct outer, ArmadaStruct inner, ArmadaStructs structs) {\n      foreach (var fieldName in inner.FieldNames) {\n        var t = inner.GetFieldType(fieldName);\n        if (t is UserDefinedType u) {\n          if (u.Name == outer.Name) {\n            AH.PrintError(prog, $\"Struct {outer.Name} has a cyclic dependency on itself, specifically in field {fieldName} of component {inner.Name}\");\n            return false;\n          }\n          else if (structs.DoesStructExist(u.Name)) {\n            CheckForCyclicStructDefinition(outer, structs.GetStruct(u.Name), structs);\n          }\n        }\n      }\n      return true;\n    }\n\n    public bool CheckForCyclicStructDefinitions(ArmadaStructs structs) {\n      foreach (var structName in structs.StructNames) {\n        var s = structs.GetStruct(structName);\n        if (!CheckForCyclicStructDefinition(s, s, structs)) {\n          return false;\n        }\n      }\n      return true;\n    }\n\n    public void RemoveAllMethods(ModuleDefinition m)\n    {\n      foreach (var d in m.TopLevelDecls) {\n        if (d is ClassDecl) {\n          var c = (ClassDecl)d;\n          var membersToRemove = new List<MemberDecl>();\n          foreach (MemberDecl member in c.Members) {\n            if (member is Method) {\n              if (!c.IsDefaultClass) {\n                AH.PrintError(prog, $\"Non-default classes aren't permitted to have methods, but class {c.Name} has method {member.Name}\");\n              }\n              membersToRemove.Add(member);\n            }\n          }\n          foreach (var memberToRemove in membersToRemove){\n            c.Members.Remove(memberToRemove);\n          }\n        }\n      }\n    }\n\n    public void GetMethods(ArmadaSymbolTable symbols, ClassDecl c)\n    {\n      foreach (MemberDecl member in c.Members) {\n        if (member is Method) {\n          var method = (Method)member;\n          symbols.AllMethods.AddMethod(symbols, method);\n        }\n      }\n    }\n\n    public void CreateMethodStackFrame(string methodName, ArmadaSymbolTable symbols, DeclCollector declCollector)\n    {\n      var smst = symbols.GetMethodSymbolTable(methodName);\n      var varFormals = smst.AllVariablesInOrder.Select(v => $\"{v.FieldName}: {v.GetFlattenedType(symbols).ToString()}\");\n      declCollector.AddItem($@\"\n        datatype Armada_StackVars_{methodName} = Armada_StackVars_{methodName}({AH.CombineStringsWithCommas(varFormals)})\n      \");\n    }\n\n    public void ParseMethodWithBody(Program prog, MethodInfo methodInfo, ArmadaSymbolTable symbols, DeclCollector declCollector)\n    {\n      var method = methodInfo.method;\n\n      if (method.Awaits.Count > 0) {\n        AH.PrintError(prog, method.tok, \"Awaits clauses can't appear except in body-less methods\");\n        return;\n      }\n\n      methodInfo.ParseMethodBody(symbols);\n    }\n\n    public void CreateNextRoutinesForMethodWithNoBodyPart1(ArmadaSymbolTable symbols, MethodInfo methodInfo,\n                                                           DeclCollector declCollector, ArmadaPC startPC, ArmadaPC midPC)\n    {\n      //\n      // The first next routine to generate is...\n      //   start->middle:   find that the awaits clauses are satisfied, then havoc the write set, then\n      //                    read each element in the read set into Armada_Extern local variables\n      //\n\n      var method = methodInfo.method;\n      var next = new NextRoutineConstructor(prog, symbols, NextType.ExternStart, methodInfo, null, null, startPC, midPC);\n      method.externStartNextRoutineConstructor = next;\n      var read_context = new NormalResolutionContext(next, symbols);\n      List<FrameExpression> modifies = method.Mod.Expressions ?? new List<FrameExpression>();\n      List<Expression> reads = method.Reads.Expressions ?? new List<Expression>();\n\n      // Add each awaits clause as a predicate.\n\n      foreach (var await_clause in method.Awaits) {\n        if (!(await_clause.Type is BoolType)) {\n          next.Fail(await_clause.tok, \"Awaits clauses have to be boolean expressions\");\n          return;\n        }\n        var await_clause_resolved = read_context.ResolveAsRValue(await_clause);\n        next.AddUBAvoidanceConstraintAsDefinedBehaviorConjunct(await_clause_resolved.UndefinedBehaviorAvoidance);\n        next.AddDefinedBehaviorConjunct(await_clause_resolved.Val);\n      }\n\n      // Add each undefined_unless clause as an undefined-behavior constraint, to model that the\n      // method's behavior is undefined if its undefined_unless constraints aren't met at the outset.\n\n      foreach (var undefined_unless_clause in method.UndefinedUnless) {\n        var uuc = read_context.ResolveAsRValue(undefined_unless_clause);\n        next.AddUndefinedBehaviorAvoidanceConstraint(uuc.UndefinedBehaviorAvoidance);\n        next.AddUndefinedBehaviorAvoidanceConstraint(uuc.Val);\n      }\n\n      // Compute each s{i+1} by updating a single modifies element in s{i}.\n\n      var s_current = next.s;\n      for (int i = 0; i < modifies.Count; ++i) {\n        var lhs = modifies.ElementAt(i).E;\n\n        var nextFormal = new NextFormal($\"newval{i}_{startPC}\", $\"newval{i}\", lhs.Type, symbols);\n        var newRhs = next.AddFormal(nextFormal);\n\n        //\n        // It's important that we model the external method as\n        // updating the state using store-buffer entries if the {:tso}\n        // annotation appears on the modifies clause.  If we model it\n        // as updating the state directly, then this doesn't permit\n        // any behavior in which the external method updates the store\n        // buffer and then, after it's returned, a tau causes the\n        // modification to be reflected in real state.\n        //\n\n        // s_current := lhs.update_state(s_current, newRhs);\n        var current_context = new NormalResolutionContext(s_current, next, symbols);\n        var newLhs = current_context.ResolveAsLValue(lhs);\n        if (!(newLhs is ArmadaLValue)) {\n          next.Fail(lhs.tok, \"Modifies element is not a valid lvalue\");\n          return;\n        }\n        next.AddUndefinedBehaviorAvoidanceConstraint(newLhs.GetUndefinedBehaviorAvoidanceConstraint());\n\n        s_current = Attributes.Contains(method.Mod.Attributes, \"tso\") ?\n          newLhs.UpdateTotalStateWithStoreBufferEntry(current_context, next, newRhs, startPC) :\n          newLhs.UpdateTotalStateBypassingStoreBuffer(current_context, next, newRhs);\n        s_current = next.AddVariableDeclaration(\"s\", s_current);\n      }\n\n      if (reads.Count > 0) {\n        // s_current := Armada_UpdateTSFrame(\n        //    s_current, tid,\n        //    Armada_StackFrame_{method.Name}(s_current.threads[tid].top.{method.Name}.(Armada_Extern0 := ..., Armada_Extern1 := ...))\n        // );\n\n        var locv_current = next.AddVariableDeclaration(\"locv\", $\"Armada_GetThreadLocalView({s_current}, {next.tid})\");\n        // The top stack frame hasn't changed since the beginning, since nothing we modify is on the stack\n        var top = read_context.GetRValueTopStackFrame();\n        next.AddUndefinedBehaviorAvoidanceConstraint($\"({top}).Armada_StackFrame_{method.Name}?\");\n        var current_context = new CustomResolutionContext(s_current, s_current, locv_current, top, $\"{s_current}.ghosts\",\n                                                          next.tid, method.Name, symbols, next);\n\n        var updates = new List<string>();\n        for (int i = 0; i < reads.Count; ++i) {\n          var read_expr = reads.ElementAt(i);\n          var read_val = current_context.ResolveAsRValue(read_expr);\n          next.AddUndefinedBehaviorAvoidanceConstraint(read_val.UndefinedBehaviorAvoidance);\n          updates.Add($\"Armada_Extern{i} := {read_val.Val}\");\n        }\n\n        var top_vars = $\"({top}).{method.Name}\";\n        if (updates.Any()) {\n          top_vars += \".(\" + String.Join(\", \", updates) + \")\";\n        }\n        s_current = $\"Armada_UpdateTSFrame({s_current}, {next.tid}, Armada_StackFrame_{method.Name}({top_vars}))\";\n        s_current = next.AddVariableDeclaration(\"s\", s_current);\n      }\n\n      // s_current := Armada_UpdatePC(s_current, tid, midPC);\n\n      s_current = $\"Armada_UpdatePC({s_current}, {next.tid}, {midPC})\";\n      s_current = next.AddVariableDeclaration(\"s\", s_current);\n\n      next.SetNextState(s_current);\n      symbols.AddNextRoutineConstructor(next);\n    }\n\n    public void CreateNextRoutinesForMethodWithNoBodyPart2(ArmadaSymbolTable symbols, MethodInfo methodInfo,\n                                                           DeclCollector declCollector, ArmadaPC midPC)\n    {\n      //\n      // The second next routine to generate is...\n      //   middle->middle:  crash if anything in the read set doesn't match the Armada_Extern variables,\n      //                    then havoc the write set, then read each element in the read set into\n      //                    Armada_Extern local variables\n\n      var method = methodInfo.method;\n      var next = new NextRoutineConstructor(prog, symbols, NextType.ExternContinue, methodInfo, null, null, midPC, midPC);\n      method.externContinueNextRoutineConstructor = next;\n      var read_context = new NormalResolutionContext(next, symbols);\n      List<FrameExpression> modifies = method.Mod.Expressions ?? new List<FrameExpression>();\n      List<Expression> reads = method.Reads.Expressions ?? new List<Expression>();\n\n      // Crash if, for any element in the read set, the current value of that element doesn't\n      // match the corresponding element of the latest snapshot.\n\n      next.AddUndefinedBehaviorAvoidanceConstraint($\"({next.t}).top.Armada_StackFrame_{method.Name}?\");\n\n      for (int i = 0; i < reads.Count; ++i) {\n        var read_expr = reads.ElementAt(i);\n        var current_val = read_context.ResolveAsRValue(read_expr);\n        next.AddUndefinedBehaviorAvoidanceConstraint(current_val.UndefinedBehaviorAvoidance);\n        next.AddUndefinedBehaviorAvoidanceConstraint($\"({current_val.Val}) == ({next.t}).top.{method.Name}.Armada_Extern{i}\");\n      }\n\n      // Compute each s{i+1} by updating a single modifies element in s{i}.\n\n      var s_current = next.s;\n      for (int i = 0; i < modifies.Count; ++i) {\n        var lhs = modifies.ElementAt(i).E;\n\n        var nextFormal = new NextFormal($\"newval{i}_{midPC}\", $\"newval{i}\", lhs.Type, symbols);\n        var newRhs = next.AddFormal(nextFormal);\n\n        //\n        // It's important that we model the external method as\n        // updating the state using store-buffer entries if the {:tso}\n        // annotation appears on the modifies clause.  If we model it\n        // as updating the state directly, then this doesn't permit\n        // any behavior in which the external method updates the store\n        // buffer and then, after it's returned, a tau causes the\n        // modification to be reflected in real state.\n        //\n\n        // s_current := lhs.update_state(s_current, newRhs);\n        var current_context = new NormalResolutionContext(s_current, next, symbols);\n        var newLhs = current_context.ResolveAsLValue(lhs);\n        if (!(newLhs is ArmadaLValue)) {\n          next.Fail(lhs.tok, \"Modifies element is not a valid lvalue\");\n          return;\n        }\n        next.AddUndefinedBehaviorAvoidanceConstraint(newLhs.GetUndefinedBehaviorAvoidanceConstraint());\n\n        s_current = Attributes.Contains(method.Mod.Attributes, \"tso\") ?\n          newLhs.UpdateTotalStateWithStoreBufferEntry(current_context, next, newRhs, midPC) :\n          newLhs.UpdateTotalStateBypassingStoreBuffer(current_context, next, newRhs);\n        s_current = next.AddVariableDeclaration(\"s\", s_current);\n      }\n\n      if (reads.Count > 0) {\n        // s_current := Armada_UpdateTSFrame(\n        //    s_current, tid,\n        //    Armada_StackFrame_{method.Name}(s_current.threads[tid].top.{method.Name}.(Armada_Extern0 := ..., Armada_Extern1 := ...))\n        // );\n\n        var locv_current = next.AddVariableDeclaration(\"locv\", $\"Armada_GetThreadLocalView({s_current}, {next.tid})\");\n        var ghosts_current = $\"{s_current}.ghosts\";\n        var top_current = $\"{s_current}.threads[{next.tid}].top\";\n        var current_context = new CustomResolutionContext(s_current, s_current, locv_current, top_current, ghosts_current,\n                                                          next.tid, method.Name, symbols, next);\n\n        var updates = new List<string>();\n        for (int i = 0; i < reads.Count; ++i) {\n          var read_expr = reads.ElementAt(i);\n          var read_val = current_context.ResolveAsRValue(read_expr);\n          next.AddUndefinedBehaviorAvoidanceConstraint(read_val.UndefinedBehaviorAvoidance);\n          updates.Add($\"Armada_Extern{i} := {read_val.Val}\");\n        }\n\n        var top_vars = $\"({next.t}).top.{method.Name}\";\n        if (updates.Any()) {\n          top_vars += \".(\" + String.Join(\", \", updates) + \")\";\n        }\n        s_current = $\"Armada_UpdateTSFrame({s_current}, {next.tid}, Armada_StackFrame_{method.Name}({top_vars}))\";\n        s_current = next.AddVariableDeclaration(\"s\", s_current);\n      }\n\n      next.SetNextState(s_current);\n      symbols.AddNextRoutineConstructor(next);\n    }\n\n    public void CreateNextRoutinesForMethodWithNoBodyPart3(ArmadaSymbolTable symbols, MethodInfo methodInfo,\n                                                           DeclCollector declCollector, ArmadaPC midPC, ArmadaPC endPC)\n    {\n      //\n      // The third next routine to generate is...\n      //   middle->end:     find that the post-condition is satisfied and append log elements\n      //\n\n      var method = methodInfo.method;\n      var next = new NextRoutineConstructor(prog, symbols, NextType.ExternEnd, methodInfo, null, null, midPC, endPC);\n      method.externEndNextRoutineConstructor = next;\n      var read_context = new BodylessMethodPostconditionResolutionContext(next, symbols);\n\n      foreach (var ensure_raw in method.Ens) {\n        var ensure_resolved = read_context.ResolveAsRValue(ensure_raw.E);\n        next.AddUBAvoidanceConstraintAsDefinedBehaviorConjunct(ensure_resolved.UndefinedBehaviorAvoidance);\n        next.AddDefinedBehaviorConjunct(ensure_resolved.Val);\n      }\n\n      var s_current = next.s;\n\n      // s_current := Armada_UpdatePC(s_current, tid, endPC);\n\n      s_current = $\"Armada_UpdatePC({s_current}, {next.tid}, {endPC})\";\n      s_current = next.AddVariableDeclaration(\"s\", s_current);\n\n      next.SetNextState(s_current);\n      symbols.AddNextRoutineConstructor(next);\n    }\n\n    public void ParseMethodWithNoBody(Program prog, MethodInfo methodInfo, ArmadaSymbolTable symbols, DeclCollector declCollector)\n    {\n      var method = methodInfo.method;\n      if (!Attributes.Contains(method.Attributes, \"extern\")) {\n        AH.PrintError(prog, method.tok, \"Armada doesn't support body-less methods, except external ones marked with {:extern}.\");\n        return;\n      }\n\n      //\n      // There are three PCs, at the start, middle, and end of the method.\n      // There are three transitions:\n      //\n      //   start->middle:   find that the awaits clauses are satisfied, then havoc the write set, then\n      //                    read each element in the read set into Armada_Extern local variables\n      //   middle->middle:  crash if anything in the read set doesn't match the Armada_Extern variables,\n      //                    then havoc the write set, then read each element in the read set into\n      //                    Armada_Extern local variables\n      //   middle->end:     find that the post-condition is satisfied and append log elements\n      //\n\n      // Create the three PC values\n\n      var startPC = methodInfo.GenerateOnePC();\n      var midPC = methodInfo.GenerateOnePC();\n      var endPC = methodInfo.GenerateOnePC();\n      symbols.AssociateLabelWithPC(\"Start\", startPC);\n      symbols.AssociateLabelWithPC(\"Middle\", midPC);\n      symbols.AssociateLabelWithPC(\"End\", endPC);\n\n      // Set the return PC.\n\n      methodInfo.SetReturnPC(endPC);\n    }\n\n    public void CreateNextRoutinesForMethodWithNoBody(Program prog, ArmadaSymbolTable symbols, MethodInfo methodInfo,\n                                                      DeclCollector declCollector)\n    {\n      var methodName = methodInfo.method.Name;\n      var startPC = new ArmadaPC(symbols, methodName, 0);\n      var midPC = new ArmadaPC(symbols, methodName, 1);\n      var endPC = new ArmadaPC(symbols, methodName, 2);\n\n      // Generate the next routines for the three transitions.\n\n      CreateNextRoutinesForMethodWithNoBodyPart1(symbols, methodInfo, declCollector, startPC, midPC);\n      CreateNextRoutinesForMethodWithNoBodyPart2(symbols, methodInfo, declCollector, midPC);\n      CreateNextRoutinesForMethodWithNoBodyPart3(symbols, methodInfo, declCollector, midPC, endPC);\n    }\n\n    public void CreateNextTerminateThread(ArmadaSymbolTable symbols, MethodInfo methodInfo)\n    {\n      var returnPC = methodInfo.ReturnPC;\n      var terminatingProcess = methodInfo.method.Name.Equals(\"main\");\n      var next = new NextRoutineConstructor(prog, symbols, terminatingProcess ? NextType.TerminateProcess : NextType.TerminateThread,\n                                            methodInfo, null, null, returnPC, null);\n      methodInfo.method.terminateNextRoutineConstructor = next;\n\n      var s = $\"({next.s})\";\n      var t = $\"({next.t})\";\n\n      // |t.stack| == 0\n\n      next.AddConjunct($\"|{t}.stack| == 0\");\n\n      // The thread's store buffer contents should be flushed before termination, i.e.,\n      // |t.storeBuffer| == 0\n\n      next.AddConjunct($\"|{t}.storeBuffer| == 0\");\n\n      // s_current := s.(threads := (map other | other in s.threads && other != tid :: s.threads[other]),\n      //                 joinable_tids := s.joinable_tids + {tid})\n\n      var s_current = $@\"\n        {s}.(threads := (map other | other in {s}.threads && other != {next.tid} :: {s}.threads[other]),\n                         joinable_tids := {s}.joinable_tids + {{ {next.tid} }})\n      \";\n      s_current = next.AddVariableDeclaration(\"s\", s_current);\n\n      // Now, we need to free the new_ptrs.  In Dafny, if we denote s_current by s, that's:\n      //\n      // s := s.(mem := s.mem.(heap := s.mem.heap.(valid := s.mem.heap.valid - t.new_ptrs,\n      //                                           freed := s.mem.heap.freed + t.new_ptrs)))\n\n      s = s_current;\n      s_current = $@\"\n        {s}.(mem := {s}.mem.(heap := {s}.mem.heap.(valid := {s}.mem.heap.valid - {t}.new_ptrs,\n                                                   freed := {s}.mem.heap.freed + {t}.new_ptrs)))\n      \";\n      s_current = next.AddVariableDeclaration(\"s\", s_current);\n\n      // Finally, we need to set the stop_reason to Armada_StopReasonTerminated if the terminated\n      // thread was the main thread.\n\n      if (terminatingProcess) {\n        s_current = $\"{s_current}.(stop_reason := Armada_StopReasonTerminated)\";\n        s_current = next.AddVariableDeclaration(\"s\", s_current);\n      }\n\n      next.SetNextState(s_current);\n      symbols.AddNextRoutineConstructor(next);\n    }\n\n    public void ProcessMethods(ArmadaSymbolTable symbols, DeclCollector declCollector)\n    {\n      bool mainFound = false;\n\n      var c = symbols.DefaultClass;\n\n      // First, parse all the methods.  This way, we'll know all the return PCs when\n      // we later generate next routines.\n\n      foreach (var methodName in symbols.AllMethods.AllMethodNames) {\n        var methodInfo = symbols.AllMethods.LookupMethod(methodName);\n        var method = methodInfo.method;\n        if (method.Name == \"main\") {\n          mainFound = true;\n        }\n        if (method.Body is null) {\n          ParseMethodWithNoBody(prog, methodInfo, symbols, declCollector);\n        }\n        else {\n          ParseMethodWithBody(prog, methodInfo, symbols, declCollector);\n        }\n        if (Attributes.Contains(method.Attributes, \"atomic\")) {\n          if (method.Name == \"main\") {\n            AH.PrintWarning(prog, \"Ignoring :atomic on main, since main can't use atomic calls and returns\");\n          }\n          else {\n            methodInfo.UseAtomicCallsAndReturns();\n          }\n        }\n      }\n\n      if (!mainFound) {\n        AH.PrintError(prog, $\"No main routine found\");\n      }\n\n      // Next, generate next routines for all the methods.\n\n      foreach (var methodName in symbols.AllMethods.AllMethodNames) {\n        var methodInfo = symbols.AllMethods.LookupMethod(methodName);\n        var method = methodInfo.method;\n        if (method.Body is null) {\n          CreateNextRoutinesForMethodWithNoBody(prog, symbols, methodInfo, declCollector);\n        }\n        else {\n          methodInfo.ParsedBody.GenerateNextRoutines();\n        }\n      }\n\n      foreach (var methodName in symbols.GetThreadRoutines()) {\n        var methodInfo = symbols.AllMethods.LookupMethod(methodName);\n        CreateNextTerminateThread(symbols, methodInfo);\n      }\n    }\n\n    private string GetStructFieldUpdate(Type innerType, int numArrayDimensions, string currentValue, int currentField)\n    {\n      if (numArrayDimensions == 0) {\n        if (AH.IsPrimitiveType(innerType)) {\n          return $\"value.n_{innerType}\";\n        }\n        else if (innerType is UserDefinedType ut) {\n          return $\"Armada_UpdateStruct_{ut.Name}({currentValue}, fields[{currentField}..], value)\";\n        }\n        else {\n          AH.PrintError(prog, $\"Invalid type {innerType}\");\n          return currentValue;\n        }\n      }\n      else {\n        var subfieldUpdate = GetStructFieldUpdate(innerType, numArrayDimensions - 1,\n                                                  $\"{currentValue}[fields[{currentField}]]\", currentField + 1);\n        return $\"{currentValue}[fields[{currentField}] := {subfieldUpdate}]\";\n      }\n    }\n\n    private string GetGlobalsUpdateConstraints(Type innerType, int numArrayDimensions, string value)\n    {\n      var constraints = new List<string>();\n      if (AH.IsPrimitiveType(innerType)) {\n        constraints.Add($\"|fields| == {numArrayDimensions}\");\n      }\n      else {\n        constraints.Add($\"|fields| >= {numArrayDimensions}\");\n      }\n      for (int i = 0; i < numArrayDimensions; ++i) {\n        constraints.Add($\"0 <= fields[{i}] < |{value}|\");\n        value += $\"[fields[{i}]]\";\n      }\n      if (AH.IsPrimitiveType(innerType)) {\n        constraints.Add($\"value.Armada_PrimitiveValue_{innerType}?\");\n      }\n      return AH.CombineStringsWithAnd(constraints);\n    }\n\n    public void CreateApplyTauUnaddressableFunction(ArmadaSymbolTable symbols, DeclCollector declCollector)\n    {\n      var caseBodies = \"\";\n\n      foreach (var varName in symbols.Globals.VariableNames) {\n        var gv = symbols.Globals.Lookup(varName);\n        if (gv is GlobalUnaddressableArmadaVariable) {\n          Type innerType;\n          var numArrayDimensions = AH.GetNumArrayDimensions(gv.ty, out innerType);\n          var globalsDotVarName = $\"globals.{varName}\";\n          caseBodies += $@\"\n            case Armada_GlobalStaticVar_{varName} =>\n              if {GetGlobalsUpdateConstraints(innerType, numArrayDimensions, globalsDotVarName)} then\n                globals.({varName} := {GetStructFieldUpdate(innerType, numArrayDimensions, globalsDotVarName, 0)})\n              else\n                globals\n          \";\n        }\n      }\n\n      caseBodies += \"case Armada_GlobalStaticVarNone => globals\\n\";\n      declCollector.AddItem($@\"\n        function Armada_ApplyTauUnaddressable(globals: Armada_Globals, v: Armada_GlobalStaticVar, fields: seq<int>,\n                                              value: Armada_PrimitiveValue) : Armada_Globals\n        {{\n          match v\n            {caseBodies}\n        }}\n      \");\n    }\n\n    public void CreateApplyTauAddressableFunction(ArmadaSymbolTable symbols, DeclCollector declCollector)\n    {\n      declCollector.AddItem(@\"\n        function Armada_ApplyTauAddressable(h: Armada_Heap, p: Armada_Pointer, value: Armada_PrimitiveValue) : (h': Armada_Heap)\n          ensures Armada_HeapMetadataUnchangedByTau(h, h')\n        {\n          if && p in h.valid\n             && p in h.tree\n             && p in h.values\n             && h.tree[p].ty.Armada_ObjectTypePrimitive?\n             && Armada_PrimitiveValueMatchesType(value, h.tree[p].ty.pty)\n          then\n            h.(values := Armada_UpdateHeapValuesWithPrimitiveValue(h.values, p, value))\n          else\n            h\n        }\n      \");\n    }\n\n    public void CreateHeapMetadataUnchangedByTau(ArmadaSymbolTable symbols, DeclCollector declCollector)\n    {\n      declCollector.AddItem(@\"\n        predicate Armada_HeapMetadataUnchangedByTau(h: Armada_Heap, h': Armada_Heap)\n        {\n          && h'.valid == h.valid\n          && h'.tree == h.tree\n          && h'.freed == h.freed\n        }\n      \");\n    }\n\n    public void CreateTauNext(ArmadaSymbolTable symbols, DeclCollector declCollector)\n    {\n      CreateHeapMetadataUnchangedByTau(symbols, declCollector);\n      CreateApplyTauUnaddressableFunction(symbols, declCollector);\n      CreateApplyTauAddressableFunction(symbols, declCollector);\n\n      declCollector.AddItem(@\"\n        function Armada_ApplyStoreBufferEntry(mem: Armada_SharedMemory, entry: Armada_StoreBufferEntry) : (mem':Armada_SharedMemory)\n          ensures Armada_HeapMetadataUnchangedByTau(mem.heap, mem'.heap)\n        {\n          match entry.loc\n              case Armada_StoreBufferLocation_Unaddressable(v, fields) =>\n                mem.(globals := Armada_ApplyTauUnaddressable(mem.globals, v, fields, entry.value))\n              case Armada_StoreBufferLocation_Addressable(p) =>\n                mem.(heap := Armada_ApplyTauAddressable(mem.heap, p, entry.value))\n        }\n      \");\n\n      declCollector.AddItem(@\"\n        function Armada_ApplyStoreBuffer(mem: Armada_SharedMemory, storeBuffer: seq<Armada_StoreBufferEntry>) : (mem':Armada_SharedMemory)\n          ensures Armada_HeapMetadataUnchangedByTau(mem.heap, mem'.heap)\n          decreases |storeBuffer|\n        {\n          if |storeBuffer| == 0 then\n            mem\n          else\n            Armada_ApplyStoreBuffer(Armada_ApplyStoreBufferEntry(mem, storeBuffer[0]), storeBuffer[1..])\n        }\n      \");\n\n      declCollector.AddItem(@\"\n        function Armada_GetThreadLocalView(s: Armada_TotalState, tid: Armada_ThreadHandle) : (mem':Armada_SharedMemory)\n          requires tid in s.threads\n          ensures  Armada_HeapMetadataUnchangedByTau(s.mem.heap, mem'.heap)\n        {\n          Armada_ApplyStoreBuffer(s.mem, s.threads[tid].storeBuffer)\n        }\n      \");\n\n      var next = new NextRoutineConstructor(prog, symbols, NextType.Tau, null, null, null, null, null);\n      symbols.TauNextRoutineConstructor = next;\n\n      var s = $\"({next.s})\";\n      var t = $\"({next.t})\";\n\n      // Add conjunct |t.storeBuffer| > 0:\n\n      next.AddConjunct($\"|{t}.storeBuffer| > 0\");\n\n      // Get an expression for the correct final state, which involves popping the first store-buffer entry\n      // and applying it to memory.\n\n      var s_updated = $@\"\n        {s}.(threads := {s}.threads[{next.tid} := {t}.(storeBuffer := {t}.storeBuffer[1..])],\n             mem := Armada_ApplyStoreBufferEntry({s}.mem, {t}.storeBuffer[0]))\n      \";\n      next.SetNextState(s_updated);\n      symbols.AddNextRoutineConstructor(next);\n    }\n\n    public void GenerateEnablingConditions(ArmadaSymbolTable symbols, DeclCollector declCollector)\n    {\n      foreach (var methodName in symbols.AllMethods.AllMethodNames) {\n        var methodInfo = symbols.AllMethods.LookupMethod(methodName);\n        var pcs = new List<ArmadaPC>();\n        methodInfo.AppendAllPCs(pcs);\n        foreach (var pc in pcs) {\n          var collector = methodInfo.GetEnablingConstraintCollector(pc);\n          if (collector == null || collector.Empty) {\n            continue;\n          }\n\n          declCollector.AddItem($@\"\n            predicate Armada_EnablingConditions_{pc}(s: Armada_TotalState, tid: Armada_ThreadHandle)\n              requires tid in s.threads\n              requires s.threads[tid].top.Armada_StackFrame_{methodName}?\n            {{\n              {collector.Extract()}\n            }}\n          \");\n        }\n      }\n    }\n\n    public void GenerateAddressableStaticVariablesPredicates(ArmadaSymbolTable symbols, DeclCollector declCollector)\n    {\n      // Every addressable global variable is a root of the heap\n\n      var root_preds = new List<string>();\n      var validity_preds = new List<string>();\n\n      var previouslySeenAddressableVariableAddrs = new List<string>();\n      foreach (var varName in symbols.Globals.VariableNames) {\n        var v = symbols.Globals.Lookup(varName);\n        if (v is AddressableArmadaVariable) {\n          var addr = $\"s.addrs.{varName}\";\n          foreach (var otherAddr in previouslySeenAddressableVariableAddrs) {\n            root_preds.Add($\"{addr} != {otherAddr}\");\n          }\n          previouslySeenAddressableVariableAddrs.Add(addr);\n          var pointer_valid = AH.GetInvocationOfValidPointer(\"h\", addr, v.ty);\n          if (pointer_valid is null) {\n            AH.PrintError(prog, $\"Invalid type for static variable {varName}\");\n          }\n          else {\n            validity_preds.Add(pointer_valid);\n          }\n          root_preds.Add($\"{addr} in h.tree\");\n          root_preds.Add($\"h.tree[{addr}].child_type.Armada_ChildTypeRoot?\");\n          root_preds.Add($\"h.tree[{addr}].child_type.rt.Armada_RootTypeStaticHeap?\");\n        }\n      }\n\n      var root_pred_list = AH.CombineStringsWithAnd(root_preds);\n      declCollector.AddItem($@\"\n        predicate Armada_AddressableStaticVariablesAreDistinctRoots(s: Armada_TotalState)\n        {{\n          var h := s.mem.heap;\n          {root_pred_list}\n        }}\n      \");\n\n      var validity_pred_list = AH.CombineStringsWithAnd(validity_preds);\n      declCollector.AddItem($@\"\n        predicate Armada_AddressableStaticVariablesAreValid(s: Armada_TotalState, new_ptrs: set<Armada_Pointer>)\n        {{\n          var h := s.mem.heap.(valid := s.mem.heap.valid - new_ptrs);\n          {validity_pred_list}\n        }}\n      \");\n    }\n\n    public void GenerateInitPredicate(ArmadaSymbolTable symbols, DeclCollector declCollector)\n    {\n      var builder = new PredicateBuilder(prog, true);\n\n      builder.AddConjunct(\"s.stop_reason.Armada_NotStopped?\");\n      builder.AddConjunct(\"|s.joinable_tids| == 0\");\n      builder.AddConjunct(\"util_collections_maps_i.MapHasUniqueKey(s.threads, config.tid_init)\");\n      builder.AddConjunct(\"config.tid_init != 0\");\n\n      // var tid := config.tid_init;\n      // var new_ptrs := config.new_ptrs;\n      // var t := s.threads[tid];\n      var tid = builder.AddVariableDeclaration(\"tid\", \"config.tid_init\");\n      var new_ptrs = builder.AddVariableDeclaration(\"new_ptrs\", \"config.new_ptrs\");\n      var t = builder.AddVariableDeclaration(\"t\", \"s.threads[tid]\");\n\n      // t.pc.Armada_PC_main_Start?\n      var startPC = new ArmadaPC(symbols, \"main\", 0);\n      builder.AddConjunct($\"t.pc.{startPC}?\");\n\n      builder.AddConjunct(\"t.top.Armada_StackFrame_main?\");\n      builder.AddConjunct(\"t.new_ptrs == new_ptrs\");\n      builder.AddConjunct(\"|t.stack| == 0\");\n      builder.AddConjunct(\"|t.storeBuffer| == 0\");\n\n      // For each addressable stack variable in the main stack frame, it's valid and among new_ptrs\n\n      var smst = symbols.GetMethodSymbolTable(\"main\");\n      string p_in_new_ptrs = \"\";\n      List<string> addressesOfAddressables = new List<string>();\n      foreach (var v in smst.AllVariablesInOrder.Where(v => v.varType == ArmadaVarType.Local && v is AddressableArmadaVariable))\n      {\n        var new_ptr = $\"t.top.main.AddrOf'{v.name}\";\n\n        // new_ptr is among new_ptrs\n\n        builder.AddConjunct($\"{new_ptr} in new_ptrs\");\n\n        // new_ptr is in s.mem.heap.tree\n\n        builder.AddConjunct($\"{new_ptr} in s.mem.heap.tree\");\n\n        // new_ptr is a stack-based root in s.mem.heap, i.e.,\n        //    && s.mem.heap.tree[new_ptr].child_type.Armada_ChildTypeRoot?\n        //    && s.mem.heap.tree[new_ptr].child_type.rt.Armada_RootTypeStack?\n\n        builder.AddConjunct($\"s.mem.heap.tree[{new_ptr}].child_type.Armada_ChildTypeRoot?\");\n        builder.AddConjunct($\"s.mem.heap.tree[{new_ptr}].child_type.rt.Armada_RootTypeStack?\");\n\n        // new_ptr is a valid pointer in s.mem.heap\n\n        builder.AddConjunct(AH.GetInvocationOfValidPointer(\"s.mem.heap\", new_ptr, v.ty));\n\n        var allocatedByExpr = AH.GetInvocationOfDescendants(\"s.mem.heap\", $\"t.top.main.AddrOf'{v.name}\", v.ty);\n        p_in_new_ptrs += $\"|| p in {allocatedByExpr}\";\n        addressesOfAddressables.Add($\"t.top.main.AddrOf'{v.name}\");\n      }\n\n      if (p_in_new_ptrs.Length > 0) {\n        builder.AddConjunct($\"forall p :: p in new_ptrs <==> ({p_in_new_ptrs})\");\n      }\n      else {\n        builder.AddConjunct(\"|new_ptrs| == 0\");\n      }\n\n      for (int i = 0; i < addressesOfAddressables.Count; i++) {\n        for (int j = i + 1; j < addressesOfAddressables.Count; j++) {\n          builder.AddConjunct(addressesOfAddressables[i] + \" != \" + addressesOfAddressables[j]);\n        }\n      }\n\n      // Initialize stack variables in main\n      foreach (var v in smst.AllVariablesInOrder.Where(v => v.InitialValue != null))\n      {\n        var resContext = new ResolutionContext(\"s\", \"s\", \"tid\", \"main\", symbols, null);\n        var lhsRVal = resContext.ResolveAsRValue(AH.MakeNameSegment(v.name, symbols.FlattenType(v.ty)));\n        var rhsRVal = resContext.ResolveAsRValue(v.InitialValue);\n        builder.AddConjunct($\"({lhsRVal.Val}) == ({rhsRVal.Val})\");\n      }\n\n      // The global static variables are valid, even if new_ptrs are excluded from the list of valid pointers.\n\n      builder.AddConjunct(\"Armada_AddressableStaticVariablesAreValid(s, new_ptrs)\");\n\n      // The global static variables are roots.\n\n      builder.AddConjunct(\"Armada_AddressableStaticVariablesAreDistinctRoots(s)\");\n\n      // Armada_HeapInvariant(s.mem.heap)\n\n      builder.AddConjunct(\"Armada_HeapInvariant(s.mem.heap)\");\n\n      // Any global variable is initialized appropriately: if it's an\n      // unaddressable array, it has the right length, and if it has\n      // an initializer then it has that value.\n\n      var failureReporter = new SimpleFailureReporter(prog);\n      var context = new GlobalInvariantResolutionContext(\"s\", symbols, failureReporter, \"\");\n      foreach (var globalVariableName in symbols.Globals.VariableNames) {\n        var globalVar = symbols.Globals.Lookup(globalVariableName);\n        if (globalVar is GlobalUnaddressableArmadaVariable && globalVar.ty is SizedArrayType) {\n          var gv_expr = globalVar.GetRValue(Token.NoToken, context);\n          var sz = ((SizedArrayType)globalVar.ty).Size;\n          builder.AddConjunct($\"|{gv_expr.Val}| == ({Printer.ExprToString(sz)})\");\n        }\n        if (globalVar.initialValue != null) {\n          var gv_expr = globalVar.GetRValue(Token.NoToken, context);\n          var val_expr = context.ResolveAsRValue(globalVar.initialValue);\n          //\n          // We don't crash if these rvalues aren't valid, since we can't crash at init time.\n          // Instead, we just generate Dafny that won't satisfy validity checks if that's an issue.\n          //\n          builder.AddConjunct($\"({gv_expr.Val}) == ({val_expr.Val})\");\n        }\n      }\n\n      declCollector.AddItem($@\"\n        predicate Armada_InitConfig(s: Armada_TotalState, config: Armada_Config)\n        {{\n          {builder.Extract()}\n        }}\n      \");\n\n      declCollector.AddItem(@\"\n        predicate Armada_Init(s:Armada_TotalState)\n        {\n          exists config :: Armada_InitConfig(s, config)\n        }\n      \");\n    }\n\n    public void GenerateIsNonyieldingPCPredicate(ArmadaSymbolTable symbols, DeclCollector declCollector)\n    {\n      var nonyieldingPCs = new List<ArmadaPC>();\n      symbols.AllMethods.AppendAllNonyieldingPCs(nonyieldingPCs);\n\n      string body = AH.CombineStringsWithOr(nonyieldingPCs.Select(pc => $\"pc.{pc}?\"));\n      declCollector.AddItem($@\"\n        predicate Armada_IsNonyieldingPC(pc:Armada_PC)\n        {{\n          {body}\n        }}\n      \");\n    }\n\n    public void GenerateNextBodies(ArmadaSymbolTable symbols, DeclCollector declCollector)\n    {\n      var stepCtors = new List<string>();\n      foreach (var nrc in symbols.NextRoutineConstructors) {\n        nrc.Extract(symbols, declCollector, stepCtors);\n      }\n      symbols.ClearNextRoutineConstructors();\n\n      if (stepCtors.Count() == 0) {\n        return;\n      }\n\n      var stepDecl = \"datatype Armada_Step = \" + String.Join(\" | \", stepCtors);\n      declCollector.AddItem(stepDecl);\n\n      var pr = new StepPrinter();\n      var matchBody = String.Concat(symbols.NextRoutines.Select(r => $\"{pr.CaseEntry(r)} => {pr.ValidStepInvocation(r)}\\n\"));\n      declCollector.AddItem($@\"\n        predicate {{:opaque}} Armada_ValidStepCases(s: Armada_TotalState, step: Armada_Step, tid: Armada_ThreadHandle)\n          requires tid in s.threads\n        {{\n          match step\n            {matchBody}\n        }}\n      \");\n      \n      declCollector.AddItem(@\"\n        predicate Armada_ValidStep(s: Armada_TotalState, step: Armada_Step, tid: Armada_ThreadHandle)\n        {\n          && tid in s.threads\n          && s.stop_reason.Armada_NotStopped?\n          && Armada_ValidStepCases(s, step, tid)\n        }\n      \");\n\n      matchBody = String.Concat(symbols.NextRoutines.Select(r => $\"{pr.CaseEntry(r)} => {pr.GetNextStateInvocation(r)}\\n\"));\n      declCollector.AddItem($@\"\n        function {{:opaque}} Armada_GetNextState(s: Armada_TotalState, step: Armada_Step, tid: Armada_ThreadHandle)\n          : Armada_TotalState\n        {{\n          reveal Armada_ValidStepCases();\n          if !Armada_ValidStep(s, step, tid) then\n            s\n          else\n            match step\n              {matchBody}\n        }}\n      \");\n\n      declCollector.AddItem(@\"\n        function Armada_GetSpecFunctions() : Armada_SpecFunctions<Armada_TotalState, Armada_Step, Armada_PC>\n        {\n          Armada_SpecFunctions(Armada_Init,\n                               Armada_ValidStep,\n                               Armada_GetNextState,\n                               (step:Armada_Step) => step.Armada_Step_Tau?,\n                               (s:Armada_TotalState) => s.stop_reason.Armada_NotStopped?,\n                               (s:Armada_TotalState, tid:Armada_ThreadHandle) =>\n                                 if tid in s.threads then util_option_s.Some(s.threads[tid].pc) else util_option_s.None,\n                               Armada_IsNonyieldingPC)\n        }\n      \");\n\n      declCollector.AddItem(@\"\n        function Armada_Spec() : GeneralRefinementModule.Spec<Armada_TotalState>\n        {\n          Armada_SpecFunctionsToSpec(Armada_GetSpecFunctions())\n        }\n      \");\n    }\n\n    private string GetStructUpdateConstraints(Type innerType, int numArrayDimensions, int whichField, string fieldName)\n    {\n      var constraints = new List<string>();\n      if (AH.IsPrimitiveType(innerType)) {\n        constraints.Add($\"|fields| == {numArrayDimensions + 1}\");\n      }\n      else {\n        constraints.Add($\"|fields| >= {numArrayDimensions + 1}\");\n      }\n      constraints.Add($\"fields[0] == {whichField}\");\n      var value = $\"v.{fieldName}\";\n      for (int i = 0; i < numArrayDimensions; ++i) {\n        constraints.Add($\"0 <= fields[{i + 1}] < |{value}|\");\n        value += $\"[fields[{i + 1}]]\";\n      }\n      if (AH.IsPrimitiveType(innerType)) {\n        constraints.Add($\"value.Armada_PrimitiveValue_{innerType}?\");\n      }\n      return AH.CombineStringsWithAnd(constraints);\n    }\n\n    private void GenerateStructDatatypesAndFunctions(ArmadaStructs structs, ArmadaStruct s, DeclCollector declCollector)\n    {\n      var structFields =\n        $\"datatype Armada_Struct_{s.Name} = Armada_Struct_{s.Name}(\"\n        + String.Join(\", \", s.FieldNames.Select(fieldName => $\"{fieldName}: {structs.FlattenType(s.GetFieldType(fieldName)).ToString()}\"))\n        + \")\";\n      declCollector.AddItem(structFields);\n\n      var fieldNames = s.FieldNames.ToArray();\n      var fieldTypes = fieldNames.Select(fieldName => s.GetFieldType(fieldName)).ToArray();\n      var numFields = fieldNames.Length;\n\n      var fieldTypeConstructors = fieldTypes.Select(AH.GetObjectType);\n      declCollector.AddItem($@\"\n        function Armada_StructType_{s.Name}() : Armada_ObjectType\n        {{\n          Armada_ObjectTypeStruct([{AH.CombineStringsWithCommas(fieldTypeConstructors)}])\n        }}\n      \");\n\n      foreach (var fieldName in fieldNames) {\n        var fieldType = s.GetFieldType(fieldName);\n        if (!AH.IsValidHeapType(fieldType, structs)) {\n          AH.PrintError(prog, $\"Struct {s.Name} contains field {fieldName} of type {fieldType}, which isn't a valid heap type\");\n        }\n      }\n\n      var fields = String.Join(\", \", Enumerable.Range(0, numFields).Select(fieldIndex =>\n                     AH.GetInvocationOfDereferencePointer(\"h\", $\"h.tree[p].children[{fieldIndex}]\", fieldTypes[fieldIndex])));\n      declCollector.AddItem($@\"\n        function Armada_DereferenceStructPointer_{s.Name}(h: Armada_Heap, p: Armada_Pointer) : Armada_Struct_{s.Name}\n          requires Armada_ValidPointerToObjectType(h, p, Armada_StructType_{s.Name}())\n        {{\n          Armada_Struct_{s.Name}({fields})\n        }}\n      \");\n\n      var updater = $@\"\n        function Armada_UpdateStruct_{s.Name}(v: Armada_Struct_{s.Name}, fields: seq<int>, value: Armada_PrimitiveValue)\n          : Armada_Struct_{s.Name}\n        {{\n      \";\n      for (var fieldIndex = 0; fieldIndex < numFields; ++fieldIndex) {\n        var fieldType = fieldTypes[fieldIndex];\n        var fieldName = fieldNames[fieldIndex];\n        Type innerType;\n        var numArrayDimensions = AH.GetNumArrayDimensions(fieldType, out innerType);\n        var vDotFieldName = $\"v.{fieldName}\";\n        updater += $@\"\n          if {GetStructUpdateConstraints(innerType, numArrayDimensions, fieldIndex, fieldName)} then\n            v.({fieldName} := {GetStructFieldUpdate(innerType, numArrayDimensions, vDotFieldName, 1)})\n          else\n        \";\n      }\n      updater += \"v }\";\n      declCollector.AddItem(updater);\n\n      var updates = AH.CombineStringsWithSetAddition(\n                      Enumerable.Range(0, numFields).Select(fieldIndex =>\n                        AH.GetInvocationOfUpdateValuesViaPointer(\"h\", $\"h.tree[p].children[{fieldIndex}]\",\n                                                                 $\"value.{fieldNames[fieldIndex]}\", fieldTypes[fieldIndex])));\n      updater = $@\"\n        function Armada_UpdateHeapValuesWithStruct_{s.Name}(\n          h: Armada_Heap,\n          p: Armada_Pointer,\n          value: Armada_Struct_{s.Name}\n          ) : (\n          set<(Armada_Pointer, Armada_PrimitiveValue)>\n          )\n        {{\n          if Armada_ValidPointerToObjectType(h, p, Armada_StructType_{s.Name}()) then\n            {updates}\n          else\n            {{ }}\n        }}\n      \";\n      declCollector.AddItem(updater);\n    }\n\n    public void GenerateStructDatatypesAndFunctions(ArmadaStructs structs, DeclCollector declCollector)\n    {\n      foreach (var structName in structs.StructNames) {\n        var s = structs.GetStruct(structName);\n        GenerateStructDatatypesAndFunctions(structs, s, declCollector);\n      }\n    }\n\n    public void GenerateTotalState(ArmadaSymbolTable symbols, DeclCollector declCollector)\n    {\n      var listOfPCs = new List<ArmadaPC>{ };\n      symbols.AllMethods.AppendAllPCs(listOfPCs);\n      declCollector.AddItem(\"datatype Armada_PC = \" + String.Join(\" | \", listOfPCs.Select(pc => pc.ToString())));\n\n      foreach (var methodName in symbols.MethodNames) {\n        CreateMethodStackFrame(methodName, symbols, declCollector);\n      }\n      declCollector.AddItem(\n        \"datatype Armada_StackFrame = \"\n        + String.Join(\" | \", symbols.MethodNames.Select(methodName =>\n                                                        $\"Armada_StackFrame_{methodName}({methodName}: Armada_StackVars_{methodName})\"))\n      );\n\n      List<string> globalFields = new List<string>();\n      List<string> addrFields = new List<string>();\n      List<string> ghostFields = new List<string>();\n      var staticGlobalVars = \"datatype Armada_GlobalStaticVar = Armada_GlobalStaticVarNone\";\n      foreach (var varName in symbols.Globals.VariableNames) {\n        var v = symbols.Globals.Lookup(varName);\n        if (v is GlobalUnaddressableArmadaVariable) {\n          globalFields.Add($\"{varName}: {symbols.FlattenType(v.ty)}\");\n          staticGlobalVars += $\" | Armada_GlobalStaticVar_{varName}\";\n        }\n        else if (v is GlobalAddressableArmadaVariable) {\n          addrFields.Add($\"{varName}: Armada_Pointer\");\n        }\n        else if (v is GlobalGhostArmadaVariable) {\n          ghostFields.Add($\"{varName}: {symbols.FlattenType(v.ty)}\");\n        }\n        else {\n          AH.PrintError(prog, \"Internal error:  variable of unexpected type\");\n        }\n      }\n\n      declCollector.AddItem(\"datatype Armada_Globals = Armada_Globals(\" + String.Join(\", \", globalFields) + \")\");\n      declCollector.AddItem(staticGlobalVars);\n      declCollector.AddItem(\"datatype Armada_Ghosts = Armada_Ghosts(\" + String.Join(\", \", ghostFields) + \")\");\n      declCollector.AddItem(\"datatype Armada_Addrs = Armada_Addrs(\" + String.Join(\", \", addrFields) + \")\");\n\n      declCollector.AddItem(@\"\n        datatype Armada_StoreBufferLocation = Armada_StoreBufferLocation_Unaddressable(v: Armada_GlobalStaticVar, fields: seq<int>)\n                                            | Armada_StoreBufferLocation_Addressable(p: Armada_Pointer)\n      \");\n\n      declCollector.AddItem(@\"\n        datatype Armada_StoreBufferEntry = Armada_StoreBufferEntry(loc: Armada_StoreBufferLocation, value: Armada_PrimitiveValue,\n                                                                   pc: Armada_PC)\n      \");\n\n      declCollector.AddItem(\"datatype Armada_SharedMemory = Armada_SharedMemory(heap: Armada_Heap, globals: Armada_Globals)\");\n      declCollector.AddItem(@\"\n        datatype Armada_ExtendedFrame =\n          Armada_ExtendedFrame(return_pc: Armada_PC, frame: Armada_StackFrame, new_ptrs:set<Armada_Pointer>)\n      \");\n      declCollector.AddItem(@\"\n        datatype Armada_Thread = Armada_Thread(pc: Armada_PC, top: Armada_StackFrame, new_ptrs: set<Armada_Pointer>,\n                                               stack: seq<Armada_ExtendedFrame>, storeBuffer: seq<Armada_StoreBufferEntry>)\n      \");\n      declCollector.AddItem(@\"\n        datatype Armada_TotalState = Armada_TotalState(stop_reason: Armada_StopReason, threads: map<Armada_ThreadHandle, Armada_Thread>,\n                                                       mem: Armada_SharedMemory, ghosts: Armada_Ghosts, addrs: Armada_Addrs,\n                                                       joinable_tids: set<Armada_ThreadHandle>)\n      \");\n\n      GenerateAddressableStaticVariablesPredicates(symbols, declCollector);\n\n      GenerateInitPredicate(symbols, declCollector);\n\n      GenerateIsNonyieldingPCPredicate(symbols, declCollector);\n\n      GenerateNextBodies(symbols, declCollector);\n\n      declCollector.AddItem(@\"\n        function Armada_UpdatePC(s:Armada_TotalState, tid:Armada_ThreadHandle, pc:Armada_PC) : Armada_TotalState\n          requires tid in s.threads\n        {\n          s.(threads := s.threads[tid := s.threads[tid].(pc := pc)])\n        }\n      \");\n\n      declCollector.AddItem(@\"\n        function Armada_UpdateTSFrame(s:Armada_TotalState, tid:Armada_ThreadHandle, frame:Armada_StackFrame) : Armada_TotalState\n          requires tid in s.threads\n        {\n          s.(threads := s.threads[tid := s.threads[tid].(top := frame)])\n        }\n      \");\n\n      declCollector.AddItem(@\"\n        function Armada_StoreBufferAppend(buf:seq<Armada_StoreBufferEntry>, entry:Armada_StoreBufferEntry) : seq<Armada_StoreBufferEntry>\n        {\n          buf + [entry]\n        }\n      \");\n\n      declCollector.AddItem(@\"\n        function Armada_AppendToThreadStoreBuffer(s:Armada_TotalState, tid:Armada_ThreadHandle, entry:Armada_StoreBufferEntry)\n          : Armada_TotalState\n          requires tid in s.threads\n        {\n          s.(threads := s.threads[tid := s.threads[tid].(storeBuffer := Armada_StoreBufferAppend(s.threads[tid].storeBuffer, entry))])\n        }\n      \");\n    }\n\n    public void TranslateGlobalInvariants(ArmadaSymbolTable symbols, DeclCollector declCollector)\n    {\n      foreach (var globalInvariant in symbols.GlobalInvariants.Values) {\n        var gid = globalInvariant.Decl;\n        var failureReporter = new SimpleFailureReporter(prog);\n        var context = new GlobalInvariantResolutionContext(\"s\", symbols, failureReporter, null);\n        var bodyRValue = context.ResolveAsRValue(gid.Body);\n        if (!failureReporter.Valid)\n        {\n          continue;\n        }\n\n        var antecedent = \"s.stop_reason.Armada_NotStopped?\";\n        if (bodyRValue.CanCauseUndefinedBehavior) {\n          antecedent = $\"{antecedent} && ({bodyRValue.UndefinedBehaviorAvoidance.Expr})\";\n        }\n\n        globalInvariant.TranslatedName = $\"Armada_GlobalInv_{gid.Name}\";\n        declCollector.AddItem($@\"\n          predicate {globalInvariant.TranslatedName}(s: Armada_TotalState)\n          {{\n            {antecedent} ==> ({bodyRValue.Val})\n          }}\n        \");\n      }\n    }\n\n    public void TranslateYieldPredicates(ArmadaSymbolTable symbols, DeclCollector declCollector)\n    {\n      foreach (var yieldPredicate in symbols.YieldPredicates.Values) {\n        var yd = yieldPredicate.Decl;\n        var failureReporter = new SimpleFailureReporter(prog);\n        var context = new YieldPredicateResolutionContext(\"s\", \"s'\", \"tid\", symbols, failureReporter, null);\n        var rvalue = context.ResolveAsRValue(yd.Body);\n        if (!failureReporter.Valid)\n        {\n          continue;\n        }\n\n        var body = rvalue.CanCauseUndefinedBehavior ? $\"({rvalue.UndefinedBehaviorAvoidance.Expr}) ==> ({rvalue.Val})\" : rvalue.Val;\n        yieldPredicate.TranslatedName = $\"Armada_YieldPredicate_{yd.Name}\";\n        declCollector.AddItem($@\"\n          predicate {yieldPredicate.TranslatedName}(s: Armada_TotalState, s': Armada_TotalState, tid: Armada_ThreadHandle)\n            requires tid in s.threads\n            requires tid in s'.threads\n          {{\n            {body}\n          }}\n        \");\n      }\n    }\n\n    public void TranslateUniversalStepConstraints(ArmadaSymbolTable symbols, DeclCollector declCollector)\n    {\n      string body;\n\n      foreach (var stepConstraint in symbols.UniversalStepConstraints.Values)\n      {\n        var usc = stepConstraint.Decl;\n\n        if (usc.Body == null) {\n          stepConstraint.TranslatedName = $\"Armada_UniversalStepConstraint_{usc.Name}\";\n          declCollector.AddItem($@\"\n            predicate {stepConstraint.TranslatedName}(s: Armada_TotalState, tid: Armada_ThreadHandle)\n              requires tid in s.threads\n            {{\n              var threads := s.threads;\n              var globals := s.mem.globals;\n              var ghosts := s.ghosts;\n              { usc.Code }\n            }}\n          \");\n          continue;\n        }\n        \n        var failureReporter = new SimpleFailureReporter(prog);\n        var context = new RequiresResolutionContext(\"s\", \"tid\", null, symbols, failureReporter, null);\n        var rvalue = context.ResolveAsRValue(usc.Body);\n        if (!failureReporter.Valid)\n        {\n          continue;\n        }\n\n        body = rvalue.CanCauseUndefinedBehavior ? $\"({rvalue.UndefinedBehaviorAvoidance.Expr}) && ({rvalue.Val})\" : rvalue.Val;\n        stepConstraint.TranslatedName = $\"Armada_UniversalStepConstraint_{usc.Name}\";\n        declCollector.AddItem($@\"\n          predicate {stepConstraint.TranslatedName}(s: Armada_TotalState, tid: Armada_ThreadHandle)\n            requires tid in s.threads\n          {{\n            {body}\n          }}\n        \");\n      }\n\n      body = AH.CombineStringsWithAnd(symbols.UniversalStepConstraints.Values.Select(sc => $\"{sc.TranslatedName}(s, tid)\"));\n      declCollector.AddItem($@\"\n        predicate Armada_UniversalStepConstraint(s: Armada_TotalState, tid: Armada_ThreadHandle)\n          requires tid in s.threads\n        {{\n          {body}\n        }}\n      \");\n    }\n\n    public void RemoveProofElements(ModuleDefinition m)\n    {\n      var declsToRemove = new List<TopLevelDecl>();\n      foreach (var d in m.TopLevelDecls)\n      {\n        if (d is ArmadaProofDecl) {\n          declsToRemove.Add(d);\n        }\n      }\n      foreach (TopLevelDecl d in declsToRemove) {\n        m.TopLevelDecls.Remove(d);\n      }\n    }\n\n    private void CreateStructsTranslation(ModuleDefinition m)\n    {\n      // Put struct and default class into symbols\n\n      var structs = new ArmadaStructs(m.Name);\n      var classes = new Dictionary<string, ClassDecl>();\n      ClassDecl defaultClass = null;\n      foreach (var d in m.TopLevelDecls) {\n        if (d is ClassDecl) {\n          var c = (ClassDecl)d;\n          if (!c.IsDefaultClass) {\n            structs.AddClass(prog, c);\n          }\n          else {\n            structs.SetDefaultClass(c);\n            defaultClass = c;\n          }\n        }\n        else if (d is RefinementConstraintDecl) {\n          structs.AddRefinementConstraint(((RefinementConstraintDecl)d).Body);\n        }\n      }\n      if (!CheckForConcreteStructDefinitions(structs)) {\n        return;\n      }\n      if (!CheckForCyclicStructDefinitions(structs)) {\n        return;\n      }\n\n      // Create m.ArmadaTranslation to hold state-machine translation.\n\n      var declCollector = new DeclCollector(prog);\n\n      declCollector.CopyMathematicalDefaultClassMembers(defaultClass);\n      declCollector.CopyMathematicalTopLevelDecls(m);\n      m.ArmadaStructs = structs;\n      m.ArmadaTranslation = new ModuleDefinition(Token.NoToken, m.Name, new List<IToken>(), false, false, false, null,\n                                                 m.Module /* parent */, null, false);\n      m.ArmadaIncludes = new List<string>();\n      m.ArmadaIncludes.Add(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/maps.i.dfy\");\n      foreach (var include in m.Module.Includes)\n      {\n        if (include.includerFilename == prog.Name && include.includedFullPath.EndsWith(\".dfy\"))\n        {\n          m.ArmadaIncludes.Add(include.includedFilename);\n        }\n      }\n\n      // Start using m.ArmadaTranslation as our new module definition.\n\n      m = m.ArmadaTranslation;\n\n      // Generate the struct-related datatypes and all their attendant definitions\n\n      GenerateStructDatatypesAndFunctions(structs, declCollector);\n\n      // Add headers to the new module.\n\n      m.TopLevelDecls.Add(AH.MakeAliasModuleDecl(\"util_collections_maps_i\", m, false));\n      m.TopLevelDecls.Add(AH.MakeAliasModuleDecl(\"util_collections_seqs_i\", m, false));\n      m.TopLevelDecls.Add(AH.MakeAliasModuleDecl(\"util_option_s\", m, false));\n\n      // Add all the definitions we've created to the module.\n\n      m.TopLevelDecls.Add(new DefaultClassDecl(m, declCollector.NewDefaultClassDecls));\n      m.TopLevelDecls.AddRange(declCollector.NewTopLevelDecls);\n    }\n\n    private void CreateStateMachineTranslation(ModuleDefinition m)\n    {\n      // Put default class info into symbols\n\n      var symbols = new ArmadaSymbolTable(prog, m.ArmadaStructs);\n      var classes = new Dictionary<string, ClassDecl>();\n      var membersToRemove = new List<TopLevelDecl>();\n      symbols.AddClass(m.ArmadaStructs.DefaultClass, true /* from structs module */, m.ArmadaStructs);\n      foreach (var d in m.TopLevelDecls) {\n        if (d is ClassDecl) {\n          var c = (ClassDecl)d;\n          if (c.IsDefaultClass) {\n            symbols.AddClass(c, false /* not from structs module */, m.ArmadaStructs);\n          }\n        }\n      }\n      foreach (var memberToRemove in membersToRemove) {\n        m.TopLevelDecls.Remove(memberToRemove);\n      }\n      if (symbols.DefaultClass == null) {\n        AH.PrintError(prog, \"No default class found\");\n        return;\n      }\n\n      // Create m.ArmadaTranslation to hold state-machine translation.\n\n      var declCollector = new DeclCollector(prog);\n\n      declCollector.CopyMathematicalDefaultClassMembers(symbols.DefaultClass);\n      declCollector.CopyMathematicalTopLevelDecls(m);\n\n      m.ArmadaSymbols = symbols;\n      m.ArmadaTranslation = new ModuleDefinition(Token.NoToken, m.Name, new List<IToken>(), false, false, false, null,\n                                                 m.Module /* parent */, null, false);\n      m.ArmadaIncludes = new List<string>();\n      m.ArmadaIncludes.Add(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/maps.i.dfy\");\n      m.ArmadaIncludes.Add(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/spec/refinement.s.dfy\");\n      if (symbols.StructsModuleName != null) {\n        m.ArmadaIncludes.Add($\"{symbols.StructsModuleName}.dfy\");\n      }\n      foreach (var include in m.Module.Includes)\n      {\n        if (include.includerFilename == prog.Name && include.includedFullPath.EndsWith(\".dfy\"))\n        {\n          m.ArmadaIncludes.Add(include.includedFilename);\n        }\n      }\n\n      // Copy the default class members into symbols.DefaultClass, then remove all the methods from m,\n      // then start using m.ArmadaTranslation as our new module definition.\n\n      symbols.DefaultClass = new DefaultClassDecl(m.ArmadaTranslation, new List<MemberDecl>(symbols.DefaultClass.Members));\n      GetMethods(symbols, symbols.DefaultClass);\n      GetMethods(symbols, m.ArmadaStructs.DefaultClass);\n      RemoveAllMethods(m);\n      m = m.ArmadaTranslation;\n\n      // Create definitions for methods' next routines\n\n      ProcessMethods(symbols, declCollector);\n      CreateTauNext(symbols, declCollector);\n      GenerateEnablingConditions(symbols, declCollector);\n\n      // Generate the total state datatype and all its attendant definitions\n\n      GenerateTotalState(symbols, declCollector);\n\n      // Translate global invariants, yield predicates, and universal step constraints\n\n      TranslateGlobalInvariants(symbols, declCollector);\n      TranslateYieldPredicates(symbols, declCollector);\n      TranslateUniversalStepConstraints(symbols, declCollector);\n\n      // Add headers to the new module.\n\n      m.TopLevelDecls.Add(AH.MakeAliasModuleDecl(\"util_collections_maps_i\", m, false));\n      m.TopLevelDecls.Add(AH.MakeAliasModuleDecl(\"util_collections_seqs_i\", m, false));\n      m.TopLevelDecls.Add(AH.MakeAliasModuleDecl(\"util_option_s\", m, false));\n      m.TopLevelDecls.Add(AH.MakeAliasModuleDecl(\"GeneralRefinementModule\", m, false));\n\n      // Add all the definitions we've created to the module.\n\n      m.TopLevelDecls.Add(new DefaultClassDecl(m, declCollector.NewDefaultClassDecls));\n      m.TopLevelDecls.AddRange(declCollector.NewTopLevelDecls);\n    }\n\n    private bool CheckTypeReferenceCompilationCompatible(ArmadaSymbolTable symbols, Type type) {\n      if (type is SizedArrayType) {\n        return CheckTypeReferenceCompilationCompatible(symbols, ((SizedArrayType)type).Arg);\n      }\n      else if (type is PointerType) {\n        return CheckTypeReferenceCompilationCompatible(symbols, ((PointerType)type).Arg);\n      }\n      if (type is UserDefinedType) {\n        var primitiveTypes = new List<string>{\"int\", \"uint8\", \"uint16\", \"uint32\", \"uint64\", \"int8\", \"int16\", \"int32\", \"int64\", \"bool\"};\n        if (primitiveTypes.Contains(type.ToString())) {\n          return true;\n        }\n        else {\n          if (symbols.LookupStruct(type.ToString()) != null) {\n            return true;\n          }\n          else {\n            AH.PrintWarning(prog, $\"Type {type} is not a compilation-compatible type\");\n            return false;\n          }\n        }\n      }\n      else {\n        AH.PrintWarning(prog, $\"Type {type} is not a compilation-compatible type\");\n        return false;\n      }\n    }\n\n    private bool CheckStructCompilationCompatible(ArmadaSymbolTable symbols, ArmadaStruct structType) {\n      bool compatible = true;\n\n      foreach (var fieldName in structType.FieldNames) {\n        var fieldType = structType.LookupFieldType(fieldName);\n        compatible = CheckTypeReferenceCompilationCompatible(symbols, fieldType) && compatible;\n      }\n      return true;\n    }\n\n    // The memory access counting logic closely follows that in\n    // ResolutionContext.cs, which summaries as follows,\n    // 1. +1 whenever GetLValue in ResolveAsLValue\n    // 2. +1 whenver GetRValue in ResolveAsRValue\n    // 3. +1 whenver UnaryOp.Dereference in ResolveAsRValue\n    // 4. Resolution of LValue caused by UnaryOp.AddressOf doesn't count as a\n    // memory reference. This is dealt after the recursion.\n\n    private bool CheckExprCompilationCompatible(ArmadaSymbolTable symbols, string methodName, Expression expr, ref int memoryAccess) {\n      // shallow check only\n      // [integer, boolean, variable, uop, binop, address of, dereference, field read, subscript of array,\n      //  null , functional call ]\n      var compatible = true;\n      foreach (var subExpr in expr.SubExpressions) {\n        compatible = CheckExprCompilationCompatible(symbols, methodName, subExpr, ref memoryAccess) && compatible;\n      }\n      switch (expr) {\n        case NegationExpression _:\n        case IdentifierExpr _:\n        case ParensExpression _:\n          break;\n        case NameSegment name:\n          var varName = name.Name;\n          if (symbols.Lookup(methodName, varName) is AddressableArmadaVariable) {\n            // Either access to addressable local variable, or any global variable\n            // is counted as access to shared memory\n            ++ memoryAccess;\n          }\n          break;\n        case LiteralExpr literal:\n          if (! (literal.Value == null || literal.Value is BigInteger || literal.Value is BaseTypes.BigDec ||\n                 literal.Value is bool)) {\n            AH.PrintWarning(prog, expr.tok, $\"Literal {literal.Value} is not compilation-compatible\");\n            compatible = false;\n          }\n          break;\n        case UnaryOpExpr unary:\n          if (! (unary.Op == UnaryOpExpr.Opcode.AddressOf || unary.Op == UnaryOpExpr.Opcode.Not ||\n                 unary.Op == UnaryOpExpr.Opcode.Dereference)) {\n            AH.PrintWarning(prog, expr.tok, $\"Unary Operator {unary.Op} is not compilation-compatible\");\n            compatible = false;\n          }\n          if (unary.Op == UnaryOpExpr.Opcode.Dereference) {\n            ++ memoryAccess;\n          } else if (unary.Op == UnaryOpExpr.Opcode.AddressOf) {\n            // it's guaranteed at least one memory is counted already\n            -- memoryAccess;\n          }\n          break;\n        case BinaryExpr binary:\n          var allowedList = new List<BinaryExpr.ResolvedOpcode>{\n            BinaryExpr.ResolvedOpcode.And, BinaryExpr.ResolvedOpcode.Or,\n            BinaryExpr.ResolvedOpcode.EqCommon, BinaryExpr.ResolvedOpcode.NeqCommon,\n            BinaryExpr.ResolvedOpcode.Lt, BinaryExpr.ResolvedOpcode.Le,\n            BinaryExpr.ResolvedOpcode.Gt, BinaryExpr.ResolvedOpcode.Ge,\n            BinaryExpr.ResolvedOpcode.Add, BinaryExpr.ResolvedOpcode.Sub,\n            BinaryExpr.ResolvedOpcode.Mul, BinaryExpr.ResolvedOpcode.Div,\n            BinaryExpr.ResolvedOpcode.Mod, BinaryExpr.ResolvedOpcode.LeftShift,\n            BinaryExpr.ResolvedOpcode.RightShift, BinaryExpr.ResolvedOpcode.BitwiseAnd,\n            BinaryExpr.ResolvedOpcode.BitwiseOr, BinaryExpr.ResolvedOpcode.BitwiseXor\n          };\n          if (! allowedList.Contains(binary.ResolvedOp)) {\n            AH.PrintWarning(prog, expr.tok, $\"Binary Operator {binary.ResolvedOp} is not compilation-compatible\");\n            compatible = false;\n          }\n          break;\n        case ConversionExpr _:\n          break;\n        case ITEExpr _:\n          break;\n        case ApplySuffix AS:\n          /* I don't know why this is not filled with resolution results... */\n          /* since call and return are separated into two next routines,\n             memory accesses caused by evaluation of arguments should not be counted\n             together with LHSes */\n\n          compatible = CheckExprCompilationCompatible(symbols, methodName, AS.Lhs, ref memoryAccess) && compatible;\n          int argMemoryAccess = 0;\n          foreach (var subExpr in AS.Args) {\n            compatible = CheckExprCompilationCompatible(symbols, methodName, subExpr, ref argMemoryAccess) && compatible;\n          }\n          if (argMemoryAccess > 1) {\n            AH.PrintWarning(prog, AS.tok, \"More than one memory access in the expression\");\n            compatible = false;\n          }\n          break;\n        case SuffixExpr _:\n          break;\n        case SeqSelectExpr sel:\n          if (! sel.SelectOne || ! CheckTypeReferenceCompilationCompatible(symbols, sel.Seq.Type)) {\n            AH.PrintWarning(prog, expr.tok, $\"This sort of subscript access is not compilation-compatible\");\n            compatible = false;\n          }\n          break;\n        case MemberSelectExpr sel:\n          if (! (sel.Obj is StaticReceiverExpr) && ! CheckTypeReferenceCompilationCompatible(symbols, sel.Obj.Type)) {\n            AH.PrintWarning(prog, expr.tok, $\"This sort of suffix access is not compilation-compatible\");\n            compatible = false;\n          }\n          break;\n        default:\n          AH.PrintWarning(prog, expr.tok, $\"Expression {expr} is not compilation-compatible\");\n          compatible = false;\n          break;\n      }\n\n      return compatible;\n    }\n\n    private bool CheckListAtomic(IEnumerable<String> inputVariableNames, IEnumerable<Expression> exprs) {\n      if (exprs == null) {\n        return true;\n      }\n      else {\n        return exprs.All(expr => CheckExprAtomic(inputVariableNames, expr));\n      }\n    }\n\n    private bool CheckExprAtomic(IEnumerable<String> inputVariableNames, Expression expr) {\n      Func<Expression, bool> checkExpr = (e => CheckExprAtomic(inputVariableNames, e));\n      Func<IEnumerable<Expression>, bool> checkList = (exprs => CheckListAtomic(inputVariableNames, exprs));\n      if (expr == null) {\n        return true;\n      }\n\n      if (expr is ParensExpression) {\n        var e = (ParensExpression)expr;\n        return checkExpr(e.E);\n      }\n\n      if (expr is ChainingExpression) {\n        var e = (ChainingExpression)expr;\n        return checkList(e.Operands) && checkList(e.PrefixLimits);\n      }\n\n      if (expr is NegationExpression) {\n        var e = (NegationExpression)expr;\n        return checkExpr(e.E);\n      }\n\n      if (expr is LiteralExpr) {\n        return true;\n      }\n\n      if (expr is ThisExpr) {\n        return false;\n      }\n\n      if (expr is MeExpr) {\n        return false;\n      }\n\n      if (expr is StoreBufferEmptyExpr) {\n        return false;\n      }\n\n      if (expr is TotalStateExpr) {\n        return false;\n      }\n\n      if (expr is IfUndefinedExpr) {\n        return false;\n      }\n\n      if (expr is IdentifierExpr) {\n        return false;\n      }\n\n      if (expr is SetDisplayExpr) {\n        var e = (SetDisplayExpr)expr;\n        return checkList(e.Elements);\n      }\n\n      if (expr is MultiSetDisplayExpr) {\n        var e = (MultiSetDisplayExpr)expr;\n        return checkList(e.Elements);\n      }\n\n      if (expr is SeqDisplayExpr) {\n        var e = (SeqDisplayExpr)expr;\n        return checkList(e.Elements);\n      }\n\n      if (expr is MapDisplayExpr) {\n        var e = (MapDisplayExpr)expr;\n        foreach (var pair in e.Elements) {\n          if (! checkExpr(pair.A) || !checkExpr(pair.B)) {\n            return false;\n          }\n        }\n        return true;\n      }\n\n      if (expr is DatatypeValue) {\n        var e = (DatatypeValue)expr;\n        return checkList(e.Arguments);\n      }\n\n      if (expr is NameSegment) {\n        var e = (NameSegment)expr;\n        if (inputVariableNames.Contains(e.Name)) {\n          return true;\n        }\n        else {\n          return false;\n        }\n      }\n\n      if (expr is ExprDotName) {\n        var e = (ExprDotName)expr;\n        return checkExpr(e.Lhs);\n      }\n\n      if (expr is ApplySuffix) {\n        var e = (ApplySuffix)expr;\n        return checkExpr(e.Lhs) && checkList(e.Args);\n      }\n\n      if (expr is RevealExpr) {\n        // FIXME\n        return true;\n      }\n\n      if (expr is MemberSelectExpr) {\n        // FIXME\n        return false;\n      }\n\n      if (expr is SeqSelectExpr) {\n        var e = (SeqSelectExpr)expr;\n        return checkExpr(e.Seq) && checkExpr(e.E0) && checkExpr(e.E1);\n      }\n\n      if (expr is MultiSelectExpr) {\n        // FIXME\n        return false;\n      }\n\n      if (expr is SeqUpdateExpr) {\n        var e = (SeqUpdateExpr)expr;\n        return checkExpr(e.Seq) && checkExpr(e.Index) && checkExpr(e.Value);\n      }\n\n      if (expr is DatatypeUpdateExpr) {\n        var e = (DatatypeUpdateExpr)expr;\n        return checkExpr(e.Root) && checkList(e.Updates.Select(update => update.Item3));\n      }\n\n      if (expr is FunctionCallExpr) {\n        var e = (FunctionCallExpr)expr;\n        return checkExpr(e.Receiver) && checkList(e.Args);\n      }\n\n      if (expr is ApplyExpr) {\n        var e = (ApplyExpr)expr;\n        // assume functions could not have problem\n        return checkList(e.Args);\n      }\n\n      if (expr is MultiSetFormingExpr) {\n        var e = (MultiSetFormingExpr)expr;\n        return checkExpr(e.E);\n      }\n\n      if (expr is OldExpr) {\n        var e = (OldExpr)expr;\n        return checkExpr(e.E);\n      }\n\n      if (expr is UnchangedExpr) {\n        return false;\n      }\n\n      if (expr is UnaryOpExpr) {\n        var e = (UnaryOpExpr)expr;\n        return checkExpr(e.E);\n      }\n\n      if (expr is ConversionExpr) {\n        var e = (ConversionExpr)expr;\n        return checkExpr(e.E);\n      }\n\n      if (expr is BinaryExpr) {\n        var e = (BinaryExpr)expr;\n        return checkExpr(e.E0) && checkExpr(e.E1);\n      }\n\n      if (expr is TernaryExpr) {\n        var e = (TernaryExpr)expr;\n        return checkExpr(e.E0) && checkExpr(e.E1) && checkExpr(e.E2);\n      }\n\n      if (expr is LetExpr) {\n        var e = (LetExpr)expr;\n        return checkList(e.RHSs) && checkExpr(e.Body);\n      }\n\n      if (expr is NamedExpr) {\n        var e = (NamedExpr)expr;\n        return checkExpr(e.Body) && checkExpr(e.Contract);\n      }\n\n      if (expr is ForallExpr) {\n        var e = (ForallExpr)expr;\n        return checkExpr(e.Range) && checkExpr(e.Term);\n      }\n\n      if (expr is ExistsExpr) {\n        var e = (ExistsExpr)expr;\n        return checkExpr(e.Range) && checkExpr(e.Term);\n      }\n\n      if (expr is SetComprehension) {\n        var e = (SetComprehension)expr;\n        return checkExpr(e.Range) && checkExpr(e.Term);\n      }\n\n      if (expr is MapComprehension) {\n        var e = (SetComprehension)expr;\n        return checkExpr(e.Range) && checkExpr(e.Term);\n      }\n\n      if (expr is LambdaExpr) {\n        var e = (LambdaExpr)expr;\n        return checkExpr(e.Range) && checkExpr(e.Body);\n      }\n\n      if (expr is WildcardExpr) {\n        return false;\n      }\n\n      if (expr is StmtExpr) {\n        var e = (StmtExpr)expr;\n        return checkExpr(e.E);\n      }\n\n      if (expr is ITEExpr) {\n        var e = (ITEExpr)expr;\n        return checkExpr(e.Test) && checkExpr(e.Thn) && checkExpr(e.Els);\n      }\n\n      if (expr is MatchExpr) {\n        var e = (MatchExpr)expr;\n        return checkExpr(e.Source) && checkList(e.Cases.Select(c => c.Body));\n      }\n\n      return false;\n    }\n\n    protected bool CheckAtomicInitialization(ArmadaSymbolTable symbols, String method, Expression expr) {\n      var methodSymbolTable = symbols.GetMethodSymbolTable(method);\n\n      // we should allow use of global ghost variables and functions as well\n\n      var globalVariables = symbols.Globals.VariableNames;\n      var globalGhostVariables = globalVariables.Where(name => symbols.Globals.Lookup(name) is GlobalGhostArmadaVariable);\n\n      return CheckExprAtomic(methodSymbolTable.InputVariableNames.Concat(globalGhostVariables).Concat(symbols.AllFunctions), expr);\n    }\n\n    private bool CheckMethodCompilationCompatible(ArmadaSymbolTable symbols, string methodName, MethodInfo methodInfo,\n                                                  ArmadaSingleMethodSymbolTable methodSymbols) {\n      bool compatible = true;\n\n      // check unsupported types\n      // all types to check: [Ins, Outs, {variables in body}]\n      IEnumerable<Type> allTypes = methodSymbols.AllVariables.Select(v => v.ty);\n\n      compatible = allTypes.All(type => CheckTypeReferenceCompilationCompatible(symbols, type)) && compatible;\n\n      if (Attributes.Contains(methodInfo.method.Attributes, \"extern\")) {\n        return compatible;\n      }\n\n      if (Attributes.Contains(methodInfo.method.Attributes, \"atomic\")) {\n        AH.PrintError(prog, methodInfo.method.tok, $\"Method {methodInfo.method.Name} is labeled :atomic, but atomic methods aren't allowed in a concrete layer.\");\n        compatible = false;\n      }\n\n      // check unsupported statements\n      // [somehow, TSO-bypassing, atomic, yield, assert, assume]\n      int memoryAccess;\n      bool initStage = true;\n      foreach (var stmt in methodInfo.ParsedBody) {\n        foreach (var expr in stmt.Stmt.SubExpressions) {\n          memoryAccess = 0;\n          compatible = CheckExprCompilationCompatible(symbols, methodName, expr, ref memoryAccess) && compatible;\n\n          if (memoryAccess > 1) {\n            AH.PrintWarning(prog, expr.tok, \"More than one memory access in the expression\");\n            compatible = false;\n          }\n        }\n        switch (stmt.Stmt) {\n          case SomehowStmt somehow:\n            AH.PrintWarning(prog, somehow.Tok, \"Somehow statements aren't compilation-compatible\");\n            compatible = false;\n            break;\n\n          case UpdateStmt update:\n            memoryAccess = 0;\n            foreach (var expr in update.Lhss.Concat(update.Rhss.SelectMany(rhs => rhs.SubExpressions))) {\n              compatible = CheckExprCompilationCompatible(symbols, methodName, expr, ref memoryAccess) && compatible;\n            }\n            if (memoryAccess > 1) {\n              AH.PrintWarning(prog, update.Tok, \"More than one memory access in the expression\");\n              compatible = false;\n            }\n            if (update.BypassStoreBuffers) {\n              AH.PrintWarning(prog, update.Tok, \"TSO-bypassing updates aren't compilation-compatible\");\n              compatible = false;\n            }\n            break;\n          case VarDeclStmt varDecl:\n            memoryAccess = 0;\n            foreach (var local in varDecl.Locals) {\n              if (symbols.Lookup(methodName, local.Name) is AddressableArmadaVariable) {\n                ++ memoryAccess;\n              }\n            }\n            if (varDecl.Update is UpdateStmt initialUpdate) {\n              foreach (var expr in initialUpdate.Rhss.SelectMany(rhs => rhs.SubExpressions)) {\n                compatible = CheckExprCompilationCompatible(symbols, methodName, expr, ref memoryAccess) && compatible;\n\n                if (! CheckAtomicInitialization(symbols, methodName, expr)) {\n                  AH.PrintWarning(prog, expr.tok, \"The initialization expression is not atomic\");\n                  compatible = false;\n                }\n              }\n              if (memoryAccess > 1) {\n                AH.PrintWarning(prog, varDecl.Tok, \"More than one memory access in the expression\");\n                compatible = false;\n              }\n            }\n            else if (varDecl.Update != null) {\n              AH.PrintWarning(prog, varDecl.Tok, \"Non-update initializations aren't compilation-compatible\");\n              compatible = false;\n            }\n            if (varDecl.BypassStoreBuffers) {\n              AH.PrintWarning(prog, varDecl.Tok, \"TSO-bypassing initializations aren't compilation-compatible\");\n              compatible = false;\n            }\n            if (! initStage) {\n              AH.PrintWarning(prog, varDecl.Tok, \"Declaration of variables at non-entry locations isn't supported\");\n              compatible = false;\n            }\n            break;\n          case ExplicitYieldBlockStmt atomic:\n            AH.PrintWarning(prog, atomic.Tok, \"Explicit-yield blocks aren't compilation-compatible\");\n            compatible = false;\n            break;\n          case YieldStmt yieldStmt:\n            AH.PrintWarning(prog, yieldStmt.Tok, \"Yield statements aren't compilation-compatible\");\n            compatible = false;\n            break;\n          case AssertStmt assert:\n            AH.PrintWarning(prog, assert.Tok, \"Assert statements aren't compilation-compatible\");\n            compatible = false;\n            break;\n          case AssumeStmt assume:\n            AH.PrintWarning(prog, assume.Tok, \"Assume statements aren't compilation-compatible\");\n            compatible = false;\n            break;\n          case WhileStmt whileStmt:\n            if (whileStmt.Invariants.Any()) {\n              AH.PrintWarning(prog, whileStmt.Tok, \"Invariants on while statements aren't compilation-compatible\");\n              compatible = false;\n            }\n            break;\n        }\n        initStage = initStage && (stmt.Stmt is VarDeclStmt || stmt.Stmt is BlockStmt);\n      }\n\n      return compatible;\n    }\n\n    private bool CheckCompilationCompatible(ArmadaSymbolTable symbols) {\n      bool compatible = true;\n\n      foreach (var stepConstraint in symbols.UniversalStepConstraints.Values)\n      {\n        AH.PrintWarning(prog, stepConstraint.Decl.tok, \"Universal step constraints aren't compilation-compatible\");\n        compatible = false;\n      }\n\n      // check all structs\n      foreach (var structName in symbols.StructNames) {\n        CheckStructCompilationCompatible(symbols, symbols.LookupStruct(structName));\n      }\n\n      // check each method\n      foreach (var methodName in symbols.AllMethods.AllMethodNames) {\n        var methodInfo = symbols.AllMethods.LookupMethod(methodName);\n        var methodSymbols = symbols.GetMethodSymbolTable(methodName);\n        compatible = compatible && CheckMethodCompilationCompatible(symbols, methodName, methodInfo, methodSymbols);\n      }\n\n      return compatible;\n    }\n\n    internal override void PreResolve(ModuleDefinition m) {\n      if (m.ModuleType == ArmadaModuleType.ArmadaProof) {\n        RemoveProofElements(m);\n      }\n    }\n\n    internal override void PostResolve(ModuleDefinition m) {\n      if (m.ModuleType == ArmadaModuleType.ArmadaStructs) {\n\n        CreateStructsTranslation(m);\n        // TODO(xueyuanz): We should only add the structs that is used by the concrete layer later.\n        prog.CompileModules.Add(m);\n      }\n      else if (m.ModuleType == ArmadaModuleType.ArmadaLevel) {\n        CreateStateMachineTranslation(m);\n        // take use of existing parsing information\n        if (Attributes.Contains(m.Attributes, \"concrete\")) {\n\n          if (! CheckCompilationCompatible(m.ArmadaSymbols)) {\n            AH.PrintError(prog, $\"Level {m.Name} is attributed {{:concrete}} but fails the check\");\n            return;\n          }\n          prog.CompileModules.Add(m);\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "Source/Armada/StepPrinter.cs",
    "content": "using System;\nusing System.Numerics;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text;\nusing static Microsoft.Armada.Predicate;\nusing IToken = Microsoft.Boogie.IToken;\nusing Token = Microsoft.Boogie.Token;\n\nnamespace Microsoft.Armada\n{\n  public class StepPrinter\n  {\n    private string state;\n    private string nextState;\n    private string tid;\n    private string step;\n    private string paramsParam;\n\n    public StepPrinter()\n    {\n      state = \"s\";\n      nextState = \"s'\";\n      tid = \"tid\";\n      step = \"step\";\n      paramsParam = \"params\";\n    }\n\n    public virtual string State { get { return state; } set { state = value; } }\n    public virtual string NextState { get { return nextState; } set { nextState = value; } }\n    public virtual string Tid { get { return tid; } set { tid = value; } }\n    public virtual string Step { get { return step; } set { step = value; } }\n    public virtual string ParamsParam { get { return paramsParam; } set { paramsParam = value; } }\n\n    public virtual string TotalStateType { get { return \"Armada_TotalState\"; } }\n\n    public virtual string Params(NextRoutine nextRoutine)\n    {\n      return $\"step.params_{nextRoutine.NameSuffix}\";\n    }\n\n    public virtual string CaseEntry(NextRoutine nextRoutine)\n    {\n      var p = nextRoutine.HasFormals ? paramsParam : \"\";\n      return $\"case Armada_Step_{nextRoutine.NameSuffix}({p})\";\n    }\n\n    public virtual string CaseEntryWithUnderscores(NextRoutine nextRoutine)\n    {\n      var p = nextRoutine.HasFormals ? \"_\" : \"\";\n      return $\"case Armada_Step_{nextRoutine.NameSuffix}({p})\";\n    }\n\n    public virtual string StepParams(NextRoutine nextRoutine)\n    {\n      var extra = nextRoutine.HasFormals ? $\", {Params(nextRoutine)}\" : \"\";\n      return $\"{State}, {Tid}{extra}\";\n    }\n\n    public virtual string ValidStepInvocation(NextRoutine nextRoutine)\n    {\n      return $\"Armada_ValidStep_{nextRoutine.NameSuffix}({StepParams(nextRoutine)})\";\n    }\n\n    public virtual string GetNextStateInvocation(NextRoutine nextRoutine)\n    {\n      return $\"Armada_GetNextState_{nextRoutine.NameSuffix}({StepParams(nextRoutine)})\";\n    }\n  }\n\n  public class ModuleStepPrinter : StepPrinter\n  {\n    private string moduleName;\n\n    public ModuleStepPrinter(string i_moduleName)\n    {\n      moduleName = i_moduleName;\n    }\n\n    public override string TotalStateType { get { return $\"{moduleName}.Armada_TotalState\"; } }\n\n    public override string ValidStepInvocation(NextRoutine nextRoutine)\n    {\n      var s = base.ValidStepInvocation(nextRoutine);\n      return $\"{moduleName}.{s}\";\n    }\n\n    public override string GetNextStateInvocation(NextRoutine nextRoutine)\n    {\n      var s = base.GetNextStateInvocation(nextRoutine);\n      return $\"{moduleName}.{s}\";\n    }\n\n    public virtual string GetOpenValidStepInvocation(NextRoutine nextRoutine)\n    {\n      return $@\"\n        lemma_OpenStep_{moduleName}_{nextRoutine.NameSuffix}({State}, {Step}, {Tid});\n      \";\n      /*\n        assert {ValidStepInvocation(nextRoutine)};\n        assert {moduleName}.Armada_GetNextState({State}, {Step}, {Tid}) == {GetNextStateInvocation(nextRoutine)};\n      */\n    }\n\n    public virtual string GetOpenStepInvocation(NextRoutine nextRoutine)\n    {\n      return $@\"\n        lemma_OpenStep_{moduleName}_{nextRoutine.NameSuffix}({State}, {Step}, {Tid});\n      \";\n      /*\n        assert {moduleName}.Armada_ValidStep({State}, {Step}, {Tid}) <==>\n                 {Tid} in {State}.threads && {State}.stop_reason.Armada_NotStopped? && {ValidStepInvocation(nextRoutine)};\n        assert {moduleName}.Armada_ValidStep({State}, {Step}, {Tid}) ==>\n                 {GetNextStateInvocation(nextRoutine)} == {moduleName}.Armada_GetNextState({State}, {Step}, {Tid});\n      */\n    }\n\n    public virtual string GetAssertValidStepInvocation(NextRoutine nextRoutine)\n    {\n      return $@\"\n        assert {ValidStepInvocation(nextRoutine)};\n        assert {moduleName}.Armada_ValidStep({State}, {Step}, {Tid});\n        assert {NextState} == {moduleName}.Armada_GetNextState({State}, {Step}, {Tid});\n      \";\n    }\n  }\n\n  public class LPlusStepPrinter : ModuleStepPrinter\n  {\n    public LPlusStepPrinter() : base(\"L\")\n    {\n      State = State + \".s\";\n    }\n\n    public override string TotalStateType { get { return \"LPlusState\"; } }\n  }\n}\n"
  },
  {
    "path": "Source/Armada/StraightlineBehavior.cs",
    "content": "using System;\nusing System.Numerics;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text;\nusing System.Text.RegularExpressions;\n\nnamespace Microsoft.Armada\n{\n  ////////////////////////////////////////////////////////\n  // Extractors for printing\n  ////////////////////////////////////////////////////////\n\n  abstract class Extractor\n  {\n    public virtual string SB { get { throw new Exception(\"This extractor doesn't support straightline behavior access\"); } }\n    public virtual string Proc { get { throw new Exception(\"This extractor doesn't support proc access\"); } }\n    public virtual string Tid { get { throw new Exception(\"This extractor doesn't support tid access\"); } }\n    public virtual string SStates { get { throw new Exception(\"This extractor doesn't support straightline states access\"); } }\n    public virtual string STrace { get { throw new Exception(\"This extractor doesn't support straightline trace access\"); } }\n\n    public virtual string SState(string pos) { return $\"{SStates}[{pos}]\"; }\n    public virtual string SStep(string pos) { return $\"{STrace}[{pos}]\"; }\n\n    public string SState(int pos) { return SState(pos.ToString()); }\n    public string SStep(int pos) { return SStep(pos.ToString()); }\n\n    public virtual string NumStates { get { return $\"|{SStates}|\"; } }\n    public virtual string NumSteps { get { return $\"|{STrace}|\"; } }\n\n    public virtual string State(string pos) { return $\"{SState(pos)}.state\"; }\n    public virtual string State(int pos, int subpos = 0) { return State(pos.ToString()); }\n\n    public virtual string PathAndTid(string pos) { return $\"{SStep(pos)}.step\"; }\n    public string PathAndTid(int pos) { return PathAndTid(pos.ToString()); }\n\n    public virtual string Path(string pos) { return $\"{PathAndTid(pos)}.path\"; }\n    public string Path(int pos) { return Path(pos.ToString()); }\n\n    public virtual string Step(int pos, int subpos) { return $\"{Path(pos)}.step{subpos}\"; }\n\n    public virtual string StepTid(string pos) { return $\"{PathAndTid(pos)}.tid\"; }\n    public string StepTid(int pos) { return StepTid(pos.ToString()); }\n\n    public virtual string TidInThreads(string pos) { return $\"{Tid} in {State(pos)}.s.threads\"; }\n    public string TidInThreads(int pos) { return TidInThreads(pos.ToString()); }\n\n    public virtual string PC(string pos) { return $\"{State(pos)}.s.threads[{Tid}].pc\"; }\n    public virtual string PC(int pos) { return PC(pos.ToString()); }\n\n    public virtual string Stack(string pos) { return $\"{State(pos)}.s.threads[{Tid}].stack\"; }\n    public virtual string Stack(int pos) { return Stack(pos.ToString()); }\n\n    public virtual string GetOpenValidPathInvocation(AtomicPath path, int pos) { return \"\"; }\n  }\n\n  class ExtractorSB : Extractor\n  {\n    private string sb, tid, proc;\n    public ExtractorSB(string i_sb, string i_tid, string i_proc) { sb = i_sb; tid = i_tid; proc = i_proc; }\n    public override string Tid { get { return tid; } }\n    public override string SB { get { return sb; } }\n    public override string SStates { get { return $\"sb.states\"; } }\n    public override string STrace { get { return $\"sb.trace\"; } }\n    public override string Proc { get { return proc; } }\n  }\n\n  class ExtractorSTrace : Extractor\n  {\n    private string strace, proc;\n    public ExtractorSTrace(string i_strace, string i_proc) { strace = i_strace; proc = i_proc; }\n    public override string STrace { get { return strace; } }\n    public override string Proc { get { return proc; } }\n  }\n\n  class ExtractorEnumeration : Extractor\n  {\n    private AtomicSpec atomicSpec;\n\n    public ExtractorEnumeration(AtomicSpec i_atomicSpec)\n    {\n      atomicSpec = i_atomicSpec;\n    }\n\n    public override string Tid { get { return \"tid\"; } }\n\n    public override string State(int pos, int subpos = 0)\n    {\n      if (subpos == 0) {\n        return $\"s{pos}\";\n      }\n      else {\n        return $\"states{pos}.s{subpos}\";\n      }\n    }\n\n    public override string Step(int pos, int subpos = 0)\n    {\n      return $\"steps{pos}.step{subpos}\";\n    }\n    \n    public override string Path(string pos) { return $\"path{pos}\"; }\n\n    public override string GetOpenValidPathInvocation(AtomicPath path, int pos)\n    {\n      var pr = new PathPrinter(atomicSpec);\n      pr.States = $\"states{pos}\";\n      pr.Steps = $\"steps{pos}\";\n      pr.State = State(pos);\n      pr.Path = Path(pos);\n      return pr.GetOpenValidPathInvocation(path);\n    }\n  }\n\n  class ExtractorExpanded : Extractor\n  {\n    private PathExpander pathExpander;\n\n    public ExtractorExpanded(PathExpander i_pathExpander)\n    {\n      pathExpander = i_pathExpander;\n    }\n\n    public override string Tid { get { return \"tid\"; } }\n    public override string State(int pos, int subpos = 0)\n      { return $\"s{pathExpander.PathIndexToStepIndex(pos) + subpos}\"; }\n    public override string Step(int pos, int subpos)\n      { return $\"step{pathExpander.PathIndexToStepIndex(pos) + subpos}\"; }\n  }\n\n  ////////////////////////////////////////////////////////\n  // Path expanders\n  ////////////////////////////////////////////////////////\n\n  class PathExpander\n  {\n    private List<int> pathIndexToStepIndex;\n    private List<AtomicPath> paths;\n    private int maxStepIndex;\n\n    public PathExpander(StraightlineBehavior sb)\n    {\n      paths = new List<AtomicPath>();\n      maxStepIndex = 0;\n      pathIndexToStepIndex = new List<int>{ 0 };\n      foreach (var path in sb.GetPaths()) {\n        AddPath(path);\n      }\n    }\n\n    public void AddPath(AtomicPath path)\n    {\n      paths.Add(path);\n      maxStepIndex += (path == null) ? 1 : path.NumNextRoutines;\n      pathIndexToStepIndex.Add(maxStepIndex);\n    }\n\n    public int PathIndexToStepIndex(int pathIndex)\n    {\n      return pathIndexToStepIndex[pathIndex];\n    }\n  }\n\n  ////////////////////////////////////////////////////////\n  // Straightline states\n  ////////////////////////////////////////////////////////\n\n  abstract class StraightlineState\n  {\n    protected ArmadaPC pc;\n    protected Dictionary<ArmadaPC, int> visitedLoopHeads;\n    protected int pos;\n\n    public StraightlineState(int i_pos, ArmadaPC i_pc, IDictionary<ArmadaPC, int> i_visitedLoopHeads)\n    {\n      pos = i_pos;\n      pc = i_pc;\n      visitedLoopHeads = new Dictionary<ArmadaPC, int>(i_visitedLoopHeads);\n    }\n\n    public ArmadaPC PC { get { return pc; } }\n\n    public virtual IEnumerable<string> GetEndProperties(Extractor e)\n    {\n      var s = $\"{e.SState(pos)}.aux.visited_loops == map [\";\n      s += String.Join(\", \", visitedLoopHeads.Select(kv => $\"L.{kv.Key} := {e.State(kv.Value)}\"));\n      s += \"]\";\n      yield return s;\n    }\n\n    public abstract IEnumerable<StraightlineStep> GetSuccessorSteps(Dictionary<ArmadaPC, List<AtomicPath>> pathsStartingAtPC,\n                                                                    HashSet<ArmadaPC> loopHeads,\n                                                                    Dictionary<AtomicPath, CHLPathEffect> pathEffectMap,\n                                                                    Dictionary<string, ArmadaPC> returnPCForMethod,\n                                                                    HashSet<ArmadaPC> pcsWithLocalInvariants);\n    public abstract string Name { get; }\n    public IDictionary<ArmadaPC, int> VisitedLoopHeads { get { return visitedLoopHeads; } }\n    public bool IsLoopHeadVisited(ArmadaPC pc) { return visitedLoopHeads.ContainsKey(pc); }\n\n    public virtual IEnumerable<Tuple<AtomicPath, CHLPathEffect>> PotentialSuccessorPaths { get { yield break;  } }\n    public virtual string ProofOfLimitedNextSSteps(Extractor e) { return \"\"; }\n\n    public virtual bool HasLocalInvariant(HashSet<ArmadaPC> pcsWithLocalInvariants,\n                                          Dictionary<string, ArmadaPC> returnPCForMethod)\n    {\n      return pcsWithLocalInvariants.Contains(pc);\n    }\n  }\n\n  class StraightlineStateNormal : StraightlineState\n  {\n    public StraightlineStateNormal(int i_pos, ArmadaPC i_pc, IDictionary<ArmadaPC, int> i_visitedLoopHeads)\n      : base(i_pos, i_pc, i_visitedLoopHeads)\n    {\n    }\n\n    public override IEnumerable<string> GetEndProperties(Extractor e)\n    {\n      yield return $\"{e.SState(pos)}.aux.phase.StraightlinePhaseNormal?\";\n      yield return e.TidInThreads(pos);\n      yield return $\"{e.PC(pos)}.{pc}?\";\n      foreach (var s in base.GetEndProperties(e))\n      {\n        yield return s;\n      }\n    }\n\n    public override IEnumerable<StraightlineStep> GetSuccessorSteps(Dictionary<ArmadaPC, List<AtomicPath>> pathsStartingAtPC,\n                                                                    HashSet<ArmadaPC> loopHeads,\n                                                                    Dictionary<AtomicPath, CHLPathEffect> pathEffectMap,\n                                                                    Dictionary<string, ArmadaPC> returnPCForMethod,\n                                                                    HashSet<ArmadaPC> pcsWithLocalInvariants)\n    {\n      yield return new StraightlineStepYield(pos);\n    }\n\n    public override string Name\n    {\n      get\n      {\n        if (visitedLoopHeads.ContainsKey(pc)) {\n          return $\"NormalRevisited_{pc.Name}\";\n        }\n        else {\n          return $\"Normal_{pc.Name}\";\n        }\n      }\n    }\n  }\n\n  class StraightlineStateLooped : StraightlineState\n  {\n    private List<Tuple<AtomicPath, CHLPathEffect>> potentialSuccessorPaths;\n\n    public StraightlineStateLooped(int i_pos, ArmadaPC i_pc, IDictionary<ArmadaPC, int> i_visitedLoopHeads)\n      : base(i_pos, i_pc, i_visitedLoopHeads)\n    {\n    }\n\n    public override IEnumerable<Tuple<AtomicPath, CHLPathEffect>> PotentialSuccessorPaths { get { return potentialSuccessorPaths; } }\n\n    public override IEnumerable<string> GetEndProperties(Extractor e)\n    {\n      yield return e.TidInThreads(pos);\n      yield return $\"{e.SState(pos)}.aux.phase.StraightlinePhaseLooped?\";\n      yield return $\"{e.PC(pos)}.{pc}?\";\n      foreach (var s in base.GetEndProperties(e))\n      {\n        yield return s;\n      }\n    }\n\n    public override IEnumerable<StraightlineStep> GetSuccessorSteps(Dictionary<ArmadaPC, List<AtomicPath>> pathsStartingAtPC,\n                                                                    HashSet<ArmadaPC> loopHeads,\n                                                                    Dictionary<AtomicPath, CHLPathEffect> pathEffectMap,\n                                                                    Dictionary<string, ArmadaPC> returnPCForMethod,\n                                                                    HashSet<ArmadaPC> pcsWithLocalInvariants)\n    {\n      potentialSuccessorPaths =\n        pathsStartingAtPC[pc].Select(path => new Tuple<AtomicPath, CHLPathEffect>(path, pathEffectMap[path])).ToList();\n      bool hasLocalInvariant = pcsWithLocalInvariants.Contains(pc);\n      foreach (var tup in potentialSuccessorPaths) {\n        var atomicPath = tup.Item1;\n        var effect = tup.Item2;\n        if (effect is CHLPathEffectCall) {\n          var ceffect = (CHLPathEffectCall)effect;\n          yield return new StraightlineStepCall(pos, atomicPath, hasLocalInvariant, ceffect.EffectiveEndPC, ceffect.Callee);\n        }\n        else if (effect is CHLPathEffectNormal) {\n          yield return new StraightlineStepNormal(pos, atomicPath, hasLocalInvariant);\n        }\n        // We don't return or exit in straightline behaviors, so ignore any atomic paths that do those\n      }\n    }\n\n    public override string Name { get { return $\"Looped_{pc.Name}\"; } }\n\n    public override string ProofOfLimitedNextSSteps(Extractor e)\n    {\n      var pos_plus_1 = $\"{pos} + 1\";\n\n      string str = $@\"\n        var s := {e.State(pos)};\n        var s' := {e.State(pos_plus_1)};\n        var path := {e.Path(pos)};\n        lemma_PathPossibilitiesStartingAtPC_{pc}(s, s', path, {e.Tid});\n      \";\n\n      foreach (var tup in potentialSuccessorPaths) {\n        var atomicPath = tup.Item1;\n        var effect = tup.Item2;\n\n        if (effect is CHLPathEffectCall) {\n          continue;\n        }\n\n        if (effect is CHLPathEffectNormal) {\n          continue;\n        }\n\n        str += $@\"\n          if path.LAtomic_Path_{atomicPath.Name}? {{\n            lemma_LAtomic_PathHasPCStackEffect_{atomicPath.Name}(s, s', path, {e.Tid});\n            assert false;\n          }}\n        \";\n      }\n\n      return str;\n    }\n  }\n\n  class StraightlineStateYielded : StraightlineState\n  {\n    private List<Tuple<AtomicPath, CHLPathEffect>> potentialSuccessorPaths;\n    private bool atLoopHead;\n\n    public StraightlineStateYielded(int i_pos, ArmadaPC i_pc, IDictionary<ArmadaPC, int> i_visitedLoopHeads)\n      : base(i_pos, i_pc, i_visitedLoopHeads)\n    {\n      atLoopHead = false;\n    }\n\n    public override IEnumerable<Tuple<AtomicPath, CHLPathEffect>> PotentialSuccessorPaths { get { return potentialSuccessorPaths; } }\n\n    public override IEnumerable<string> GetEndProperties(Extractor e)\n    {\n      yield return $\"{e.SState(pos)}.aux.phase.StraightlinePhaseYielded?\";\n      yield return e.TidInThreads(pos);\n      yield return $\"{e.PC(pos)}.{pc}?\";\n      foreach (var s in base.GetEndProperties(e))\n      {\n        yield return s;\n      }\n    }\n\n    public override IEnumerable<StraightlineStep> GetSuccessorSteps(Dictionary<ArmadaPC, List<AtomicPath>> pathsStartingAtPC,\n                                                                    HashSet<ArmadaPC> loopHeads,\n                                                                    Dictionary<AtomicPath, CHLPathEffect> pathEffectMap,\n                                                                    Dictionary<string, ArmadaPC> returnPCForMethod,\n                                                                    HashSet<ArmadaPC> pcsWithLocalInvariants)\n    {\n      potentialSuccessorPaths =\n        pathsStartingAtPC[pc].Select(path => new Tuple<AtomicPath, CHLPathEffect>(path, pathEffectMap[path])).ToList();\n      atLoopHead = loopHeads.Contains(pc);\n\n      if (visitedLoopHeads.ContainsKey(pc)) {\n        yield break;\n      }\n      else if (atLoopHead) {\n        yield return new StraightlineStepLoopModifies(pos, pc);\n      }\n      else {\n        bool hasLocalInvariant = pcsWithLocalInvariants.Contains(pc);\n        foreach (var tup in potentialSuccessorPaths) {\n          var atomicPath = tup.Item1;\n          var effect = tup.Item2;\n          if (effect is CHLPathEffectCall) {\n            var ceffect = (CHLPathEffectCall)effect;\n            yield return new StraightlineStepCall(pos, atomicPath, hasLocalInvariant, ceffect.EffectiveEndPC, ceffect.Callee);\n          }\n          else if (effect is CHLPathEffectNormal) {\n            yield return new StraightlineStepNormal(pos, atomicPath, hasLocalInvariant);\n          }\n          // We don't return or exit in straightline behaviors, so ignore any atomic paths that do those\n        }\n      }\n    }\n\n    public override string Name\n    {\n      get\n      {\n        if (visitedLoopHeads.ContainsKey(pc)) {\n          return $\"YieldedRevisited_{pc.Name}\";\n        }\n        else {\n          return $\"Yielded_{pc.Name}\";\n        }\n      }\n    }\n\n    public override string ProofOfLimitedNextSSteps(Extractor e)\n    {\n      if (visitedLoopHeads.ContainsKey(pc)) {\n        return $\"assert {e.PC(pos)} in {e.SState(pos)}.aux.visited_loops;\\n\";\n      }\n\n      if (atLoopHead) {\n        return $\"assert IsLoopHead({e.PC(pos)});\\n\";\n      }\n\n      var pos_plus_1 = $\"{pos} + 1\";\n\n      string str = $@\"\n        var s := {e.State(pos)};\n        var s' := {e.State(pos_plus_1)};\n        var path := {e.Path(pos)};\n        lemma_PathPossibilitiesStartingAtPC_{pc}(s, s', path, {e.Tid});\n      \";\n\n      foreach (var tup in potentialSuccessorPaths) {\n        var atomicPath = tup.Item1;\n        var effect = tup.Item2;\n\n        if (effect is CHLPathEffectCall) {\n          continue;\n        }\n\n        if (effect is CHLPathEffectNormal) {\n          continue;\n        }\n\n        str += $@\"\n          if path.LAtomic_Path_{atomicPath.Name}? {{\n            lemma_LAtomic_PathHasPCStackEffect_{atomicPath.Name}(s, s', path, {e.Tid});\n            assert false;\n          }}\n        \";\n      }\n\n      return str;\n    }\n  }\n\n  class StraightlineStateCalled : StraightlineState\n  {\n    private ArmadaPC returnPC;\n    private string callee;\n\n    public StraightlineStateCalled(int i_pos, ArmadaPC i_pc, ArmadaPC i_returnPC, IDictionary<ArmadaPC, int> i_visitedLoopHeads,\n                                   string i_callee)\n      : base(i_pos, i_pc, i_visitedLoopHeads)\n    {\n      returnPC = i_returnPC;\n      callee = i_callee;\n    }\n\n    public override IEnumerable<string> GetEndProperties(Extractor e)\n    {\n      yield return $\"{e.SState(pos)}.aux.phase.StraightlinePhaseCalled?\";\n      yield return e.TidInThreads(pos);\n      yield return $\"{e.PC(pos)}.{pc}?\";\n      yield return $\"|{e.Stack(pos)}| > 0\";\n      yield return $\"{e.Stack(pos)}[0].return_pc.{returnPC}?\";\n      foreach (var s in base.GetEndProperties(e))\n      {\n        yield return s;\n      }\n    }\n\n    public override IEnumerable<StraightlineStep> GetSuccessorSteps(Dictionary<ArmadaPC, List<AtomicPath>> pathsStartingAtPC,\n                                                                    HashSet<ArmadaPC> loopHeads,\n                                                                    Dictionary<AtomicPath, CHLPathEffect> pathEffectMap,\n                                                                    Dictionary<string, ArmadaPC> returnPCForMethod,\n                                                                    HashSet<ArmadaPC> pcsWithLocalInvariants)\n    {\n      yield return new StraightlineStepEnsures(pos, returnPC, callee);\n    }\n\n    public override string Name { get { return $\"Called_{returnPC.Name}\"; } }\n  }\n\n  class StraightlineStateEnsured : StraightlineState\n  {\n    private ArmadaPC returnPC;\n    private string callee;\n    private List<Tuple<AtomicPath, CHLPathEffect>> potentialSuccessorPaths;\n\n    public StraightlineStateEnsured(int i_pos, ArmadaPC i_returnPC, IDictionary<ArmadaPC, int> i_visitedLoopHeads, string i_callee)\n      : base(i_pos, null, i_visitedLoopHeads)\n    {\n      returnPC = i_returnPC;\n      callee = i_callee;\n    }\n\n    public string Callee { get { return callee; } }\n\n    public override IEnumerable<Tuple<AtomicPath, CHLPathEffect>> PotentialSuccessorPaths { get { return potentialSuccessorPaths; } }\n\n    public override IEnumerable<string> GetEndProperties(Extractor e)\n    {\n      yield return $\"{e.SState(pos)}.aux.phase.StraightlinePhaseEnsured?\";\n      yield return e.TidInThreads(pos);\n      yield return $\"PCToProc({e.PC(pos)}).LProcName_{callee}?\";\n      yield return $\"IsReturnSite({e.PC(pos)})\";\n      yield return $\"|{e.Stack(pos)}| > 0\";\n      yield return $\"{e.Stack(pos)}[0].return_pc.{returnPC}?\";\n      foreach (var s in base.GetEndProperties(e))\n      {\n        yield return s;\n      }\n    }\n\n    public override IEnumerable<StraightlineStep> GetSuccessorSteps(Dictionary<ArmadaPC, List<AtomicPath>> pathsStartingAtPC,\n                                                                    HashSet<ArmadaPC> loopHeads,\n                                                                    Dictionary<AtomicPath, CHLPathEffect> pathEffectMap,\n                                                                    Dictionary<string, ArmadaPC> returnPCForMethod,\n                                                                    HashSet<ArmadaPC> pcsWithLocalInvariants)\n    {\n      potentialSuccessorPaths = pathsStartingAtPC[returnPCForMethod[callee]]\n                                  .Select(path => new Tuple<AtomicPath, CHLPathEffect>(path, pathEffectMap[path])).ToList();\n\n      bool hasLocalInvariant = pcsWithLocalInvariants.Contains(pc);\n      foreach (var tup in potentialSuccessorPaths) {\n        var atomicPath = tup.Item1;\n        var effect = tup.Item2;\n        if (effect is CHLPathEffectReturn) {\n          var reffect = (CHLPathEffectReturn)effect;\n          // Only return to the return PC at the top of the stack.\n          if (reffect.EffectiveStartPC.Equals(returnPC)) {\n            yield return new StraightlineStepReturn(pos, atomicPath, hasLocalInvariant, reffect.Returner);\n          }\n        }\n        else if (effect is CHLPathEffectReturnThenCall) {\n          var rceffect = (CHLPathEffectReturnThenCall)effect;\n          // Only return to the return PC at the top of the stack.\n          if (rceffect.EffectiveStartPC.Equals(returnPC)) {\n            yield return new StraightlineStepReturnThenCall(pos, atomicPath, hasLocalInvariant, rceffect.EffectiveEndPC,\n                                                            rceffect.Returner, rceffect.Callee);\n          }\n        }\n        // After satisfying a post-condition, we should return to the caller, not exit.  So, ignore any\n        // paths that exit.\n      }\n    }\n\n    public override string Name { get { return $\"Ensured_{returnPC.Name}\"; } }\n\n    public override string ProofOfLimitedNextSSteps(Extractor e)\n    {\n      var pos_plus_1 = $\"{pos} + 1\";\n\n      string str = $@\"\n        var s := {e.State(pos)};\n        var s' := {e.State(pos_plus_1)};\n        var path := {e.Path(pos)};\n        lemma_PathPossibilitiesReturningFrom_{callee}(s, s', path, {e.Tid});\n      \";\n\n      foreach (var tup in potentialSuccessorPaths) {\n        var atomicPath = tup.Item1;\n        var effect = tup.Item2;\n\n        if (effect is CHLPathEffectReturn) {\n          var reffect = (CHLPathEffectReturn)effect;\n          if (reffect.EffectiveStartPC.Equals(returnPC)) {\n            continue;\n          }\n        }\n\n        if (effect is CHLPathEffectReturnThenCall) {\n          var rceffect = (CHLPathEffectReturnThenCall)effect;\n          if (rceffect.EffectiveStartPC.Equals(returnPC)) {\n            continue;\n          }\n        }\n\n        str += $@\"\n          if path.LAtomic_Path_{atomicPath.Name}? {{\n            lemma_LAtomic_PathHasPCStackEffect_{atomicPath.Name}(s, s', path, {e.Tid});\n            assert false;\n          }}\n        \";\n      }\n\n      return str;\n    }\n\n    public override bool HasLocalInvariant(HashSet<ArmadaPC> pcsWithLocalInvariants,\n                                           Dictionary<string, ArmadaPC> returnPCForMethod)\n    {\n      return pcsWithLocalInvariants.Contains(returnPCForMethod[callee]);\n    }\n  }\n\n  ////////////////////////////////////////////////////////\n  // Straightline steps\n  ////////////////////////////////////////////////////////\n\n  abstract class StraightlineStep\n  {\n    protected int pos;\n\n    public StraightlineStep(int i_pos) { pos = i_pos; }\n    public virtual IEnumerable<string> GetSatisfiesDescriptorClauses(Extractor e)\n    {\n      yield return $\"{e.NumSteps} > {pos}\";\n    }\n\n    public virtual IEnumerable<string> GetEnumerationClauses(Extractor e, bool expanded = false, bool crRelative = false)\n    {\n      yield break;\n    }\n\n    public abstract StraightlineState GetNextState(StraightlineState current);\n    public virtual IEnumerable<bool> BranchOutcomes { get { yield break; } }\n    public virtual IEnumerable<string> GetStatesAndSteps(Extractor e, bool typed) { yield break; }\n    public virtual IEnumerable<string> GetPaths(Extractor e, bool typed) { yield break; }\n    public virtual IEnumerable<string> GetOpenValidPathInvocations(Extractor e) { yield break; }\n  }\n\n  abstract class StraightlineStepPath : StraightlineStep\n  {\n    protected AtomicPath atomicPath;\n    protected bool hasLocalInvariant;\n\n    public StraightlineStepPath(int i_pos, AtomicPath i_atomicPath, bool i_hasLocalInvariant) : base(i_pos)\n    {\n      atomicPath = i_atomicPath;\n      hasLocalInvariant = i_hasLocalInvariant;\n    }\n\n    public AtomicPath Path { get { return atomicPath; } }\n    public override IEnumerable<bool> BranchOutcomes { get { return atomicPath.BranchOutcomes; } }\n\n    public override IEnumerable<string> GetStatesAndSteps(Extractor e, bool typed)\n    {\n      for (var i = 0; i < atomicPath.NumNextRoutines; ++i) {\n        if (i > 0) {\n          yield return typed ? $\"{e.State(pos, i)}: LPlusState\" : e.State(pos, i);\n        }\n        var nextRoutine = atomicPath.NextRoutines[i];\n        yield return typed ? $\"{e.Step(pos, i)}: L.Armada_Step\" : e.Step(pos, i);\n      }\n    }\n    \n    public override IEnumerable<string> GetPaths(Extractor e, bool typed)\n    {\n      yield return typed ? $\"{e.Path(pos)}: LAtomic_Path\" : e.Path(pos);\n    }\n\n    public override IEnumerable<string> GetEnumerationClauses(Extractor e, bool expanded = false, bool crRelative = false)\n    {\n      if (hasLocalInvariant) {\n        var fn = crRelative ? \"cr.local_inv\" : \"LocalInv\";\n        yield return $\"{fn}({e.State(pos)}, {e.Tid})\";\n      }\n\n      if (expanded) {\n        for (var i = 0; i < atomicPath.NumNextRoutines; ++i) {\n          var nextRoutine = atomicPath.NextRoutines[i];\n          var suffix = nextRoutine.NameSuffix;\n          var s = e.State(pos, i);\n          var s_prime = e.State(pos, i + 1);\n          var step = e.Step(pos, i);\n          yield return $\"LPlus_ValidStep({s}, {step}, {e.Tid}) && {s_prime} == LPlus_GetNextState({s}, {step}, {e.Tid})\";\n          if (nextRoutine.HasFormals) {\n            yield return $\"{step}.Armada_Step_{suffix}? && L.Armada_ValidStep_{suffix}({s}.s, {e.Tid}, {step}.params_{suffix}) && {s_prime}.s == L.Armada_GetNextState_{suffix}({s}.s, {e.Tid}, {step}.params_{suffix})\";\n          }\n          else {\n            yield return $\"L.Armada_ValidStep_{suffix}({s}.s, {e.Tid}) && {s_prime}.s == L.Armada_GetNextState_{suffix}({s}.s, {e.Tid})\";\n          }\n        }\n      }\n      else {\n        yield return $\"LAtomic_NextPath({e.State(pos)}, {e.State(pos+1)}, {e.Path(pos)}, {e.Tid}) && {e.Path(pos)}.LAtomic_Path_{atomicPath.Name}?\";\n      }\n    }\n\n    public override IEnumerable<string> GetOpenValidPathInvocations(Extractor e)\n    {\n      yield return e.GetOpenValidPathInvocation(atomicPath, pos);\n    }\n  }\n\n  class StraightlineStepNormal : StraightlineStepPath\n  {\n    public StraightlineStepNormal(int i_pos, AtomicPath i_atomicPath, bool i_hasLocalInvariant)\n      : base(i_pos, i_atomicPath, i_hasLocalInvariant)\n    {\n    }\n\n    public override IEnumerable<string> GetSatisfiesDescriptorClauses(Extractor e)\n    {\n      foreach (var c in base.GetSatisfiesDescriptorClauses(e)) {\n        yield return c;\n      }\n      yield return $\"{e.SStep(pos)}.StraightlineStepNormal?\";\n      yield return $\"{e.Path(pos)}.LAtomic_Path_{atomicPath.Name}?\";\n    }\n\n    public override StraightlineState GetNextState(StraightlineState current)\n    {\n      return new StraightlineStateNormal(pos + 1, atomicPath.EndPC, current.VisitedLoopHeads);\n    }\n  }\n\n  class StraightlineStepLoopModifies : StraightlineStep\n  {\n    private ArmadaPC pc;\n\n    public StraightlineStepLoopModifies(int i_pos, ArmadaPC i_pc) : base(i_pos)\n    {\n      pc = i_pc;\n    }\n\n    public override IEnumerable<string> GetSatisfiesDescriptorClauses(Extractor e)\n    {\n      foreach (var c in base.GetSatisfiesDescriptorClauses(e)) {\n        yield return c;\n      }\n      yield return $\"{e.SStep(pos)}.StraightlineStepLoopModifies?\";\n      yield return $\"{e.SStep(pos)}.pc.{pc}?\";\n    }\n\n    public override StraightlineState GetNextState(StraightlineState current)\n    {\n      var updatedDict = new Dictionary<ArmadaPC, int>(current.VisitedLoopHeads);\n      updatedDict[current.PC] = pos;\n      return new StraightlineStateLooped(pos + 1, current.PC, updatedDict);\n    }\n\n    public override IEnumerable<string> GetEnumerationClauses(Extractor e, bool expanded = false, bool crRelative = false)\n    {\n      var fn = crRelative ? \"cr.loop_modifies_clauses\" : \"LoopModifiesClauses\";\n      yield return $\"{fn}(L.{pc}, {e.State(pos)}, {e.State(pos + 1)}, {e.Tid})\";\n    }\n  }\n\n  class StraightlineStepYield : StraightlineStep\n  {\n    public StraightlineStepYield(int i_pos) : base(i_pos)\n    {\n    }\n\n    public override IEnumerable<string> GetSatisfiesDescriptorClauses(Extractor e)\n    {\n      foreach (var c in base.GetSatisfiesDescriptorClauses(e)) {\n        yield return c;\n      }\n      yield return $\"{e.SStep(pos)}.StraightlineStepYield?\";\n    }\n\n    public override StraightlineState GetNextState(StraightlineState current)\n    {\n      return new StraightlineStateYielded(pos + 1, current.PC, current.VisitedLoopHeads);\n    }\n\n    public override IEnumerable<string> GetEnumerationClauses(Extractor e, bool expanded = false, bool crRelative = false)\n    {\n      var fn = crRelative ? \"cr.yield_pred\" : \"YieldPredicate\";\n      yield return $\"{fn}({e.State(pos)}, {e.State(pos + 1)}, {e.Tid})\";\n    }\n  }\n\n  class StraightlineStepCall : StraightlineStepPath\n  {\n    private ArmadaPC returnPC;\n    private string callee;\n\n    public StraightlineStepCall(int i_pos, AtomicPath i_atomicPath, bool i_hasLocalInvariant, ArmadaPC i_returnPC, string i_callee)\n      : base(i_pos, i_atomicPath, i_hasLocalInvariant)\n    {\n      returnPC = i_returnPC;\n      callee = i_callee;\n    }\n\n    public override IEnumerable<string> GetSatisfiesDescriptorClauses(Extractor e)\n    {\n      foreach (var c in base.GetSatisfiesDescriptorClauses(e)) {\n        yield return c;\n      }\n      yield return $\"{e.SStep(pos)}.StraightlineStepCall?\";\n      yield return $\"{e.Path(pos)}.LAtomic_Path_{atomicPath.Name}?\";\n    }\n\n    public override StraightlineState GetNextState(StraightlineState current)\n    {\n      return new StraightlineStateCalled(pos + 1, atomicPath.EndPC, returnPC, current.VisitedLoopHeads, callee);\n    }\n\n    private string Callee { get { return callee; } }\n\n    public override IEnumerable<string> GetEnumerationClauses(Extractor e, bool expanded = false, bool crRelative = false)\n    {\n      foreach (var s in base.GetEnumerationClauses(e, expanded, crRelative)) {\n        yield return s;\n      }\n\n      var fn = crRelative ? \"cr.requires_clauses\" : \"RequiresClauses\";\n      yield return $\"{fn}(LProcName_{callee}, {e.State(pos + 1)}, {e.Tid})\";\n    }\n  }\n\n  class StraightlineStepEnsures : StraightlineStep\n  {\n    private ArmadaPC returnPC;\n    string callee;\n\n    public StraightlineStepEnsures(int i_pos, ArmadaPC i_returnPC, string i_callee) : base(i_pos)\n    {\n      returnPC = i_returnPC;\n      callee = i_callee;\n    }\n\n    public override IEnumerable<string> GetSatisfiesDescriptorClauses(Extractor e)\n    {\n      foreach (var c in base.GetSatisfiesDescriptorClauses(e)) {\n        yield return c;\n      }\n      yield return $\"{e.SStep(pos)}.StraightlineStepEnsures?\";\n      yield return $\"{e.SStep(pos)}.callee.LProcName_{callee}?\";\n    }\n\n    public override IEnumerable<string> GetEnumerationClauses(Extractor e, bool expanded = false, bool crRelative = false)\n    {\n      var fn = crRelative ? \"cr.ensures_clauses\" : \"EnsuresClauses\";\n      yield return $\"{fn}(LProcName_{callee}, {e.State(pos)}, {e.State(pos + 1)}, {e.Tid}) && ThreadAtReturnSite({e.State(pos+1)}, {e.Tid}, LProcName_{callee})\";\n    }\n\n    public override StraightlineState GetNextState(StraightlineState current)\n    {\n      return new StraightlineStateEnsured(pos + 1, returnPC, current.VisitedLoopHeads, callee);\n    }\n\n    private string Callee { get { return callee; } }\n  }\n\n  class StraightlineStepReturn : StraightlineStepPath\n  {\n    private string returner;\n\n    public StraightlineStepReturn(int i_pos, AtomicPath i_atomicPath, bool i_hasLocalInvariant, string i_returner)\n      : base(i_pos, i_atomicPath, i_hasLocalInvariant)\n    {\n      returner = i_returner;\n    }\n\n    public override IEnumerable<string> GetSatisfiesDescriptorClauses(Extractor e)\n    {\n      foreach (var c in base.GetSatisfiesDescriptorClauses(e)) {\n        yield return c;\n      }\n      yield return $\"{e.SStep(pos)}.StraightlineStepReturn?\";\n      yield return $\"{e.Path(pos)}.LAtomic_Path_{atomicPath.Name}?\";\n    }\n\n    public override StraightlineState GetNextState(StraightlineState current)\n    {\n      return new StraightlineStateNormal(pos + 1, atomicPath.EndPC, current.VisitedLoopHeads);\n    }\n\n    private string Returner { get { return returner; } }\n  }\n\n  class StraightlineStepReturnThenCall : StraightlineStepPath\n  {\n    private ArmadaPC returnPC;\n    private string returner;\n    private string callee;\n\n    public StraightlineStepReturnThenCall(int i_pos, AtomicPath i_atomicPath, bool i_hasLocalInvariant,\n                                          ArmadaPC i_returnPC, string i_returner, string i_callee)\n      : base(i_pos, i_atomicPath, i_hasLocalInvariant)\n    {\n      returnPC = i_returnPC;\n      returner = i_returner;\n      callee = i_callee;\n    }\n\n    public override IEnumerable<string> GetSatisfiesDescriptorClauses(Extractor e)\n    {\n      foreach (var c in base.GetSatisfiesDescriptorClauses(e)) {\n        yield return c;\n      }\n      yield return $\"{e.SStep(pos)}.StraightlineStepReturnThenCall?\";\n      yield return $\"{e.Path(pos)}.LAtomic_Path_{atomicPath.Name}?\";\n    }\n\n    public override IEnumerable<string> GetEnumerationClauses(Extractor e, bool expanded = false, bool crRelative = false)\n    {\n      foreach (var s in base.GetEnumerationClauses(e, expanded, crRelative)) {\n        yield return s;\n      }\n      var fn = crRelative ? \"cr.requires_clauses\" : \"RequiresClauses\";\n      yield return $\"{fn}(LProcName_{callee}, {e.State(pos+1)}, {e.Tid})\";\n    }\n\n    public override StraightlineState GetNextState(StraightlineState current)\n    {\n      return new StraightlineStateCalled(pos + 1, atomicPath.EndPC, returnPC, current.VisitedLoopHeads, callee);\n    }\n\n    private string Returner { get { return returner; } }\n    private string Callee { get { return callee; } }\n  }\n\n  class StraightlineStepBeyondEnd : StraightlineStepPath\n  {\n    public StraightlineStepBeyondEnd(int i_pos, AtomicPath i_atomicPath, bool i_hasLocalInvariant)\n      : base(i_pos, i_atomicPath, i_hasLocalInvariant)\n    {\n    }\n\n    public override IEnumerable<string> GetSatisfiesDescriptorClauses(Extractor e)\n    {\n      throw new Exception(\"Shouldn't invoke GetSatisfiesDescriptorClauses for behavior that goes beyond end\");\n    }\n\n    public override StraightlineState GetNextState(StraightlineState current)\n    {\n      return new StraightlineStateNormal(pos + 1, atomicPath.EndPC, current.VisitedLoopHeads);\n    }\n  }\n\n\n  ////////////////////////////////////////////////////////\n  // Straightline behaviors\n  ////////////////////////////////////////////////////////\n\n  class StraightlineBehavior\n  {\n    private StraightlineBehavior predecessor;\n    private StraightlineStep lastStep;\n    private int numSteps;\n    private StraightlineState lastState;\n    private List<StraightlineBehavior> successors;\n    private string methodName;\n    private string name;\n\n    public StraightlineBehavior(StraightlineBehavior i_predecessor, StraightlineStep i_lastStep)\n    {\n      predecessor = i_predecessor;\n      lastStep = i_lastStep;\n      numSteps = predecessor.NumSteps + 1;\n      lastState = lastStep.GetNextState(predecessor.LastState);\n      successors = new List<StraightlineBehavior>();\n      methodName = predecessor.MethodName;\n      if (lastStep is StraightlineStepBeyondEnd) {\n        name = null;\n      }\n      else {\n        name = MakeName();\n        predecessor.NoteSuccessor(this);\n      }\n    }\n\n    public StraightlineBehavior(ArmadaPC initialPC)\n    {\n      predecessor = null;\n      lastStep = null;\n      numSteps = 0;\n      lastState = new StraightlineStateNormal(0, initialPC, new Dictionary<ArmadaPC, int>());\n      successors = new List<StraightlineBehavior>();\n      methodName = initialPC.methodName;\n      name = MakeName();\n    }\n\n    private void NoteSuccessor(StraightlineBehavior successor) { successors.Add(successor); }\n\n    public int NumSteps { get { return numSteps; } }\n    public StraightlineState LastState { get { return lastState; } }\n    public IEnumerable<StraightlineBehavior> Successors { get { return successors; } }\n    public string MethodName { get { return methodName; } }\n    public string Name { get { return name; } }\n\n    private string MakeName()\n    {\n      string str = methodName;\n      var branchString = String.Concat(BranchOutcomes.Select(b => b ? \"Y\" : \"N\"));\n      if (!String.IsNullOrEmpty(branchString)) {\n        str += \"_\" + branchString;\n      }\n      str += \"_\" + lastState.Name;\n      return str;\n    }\n\n    public IEnumerable<bool> BranchOutcomes\n    {\n      get\n      {\n        if (predecessor == null)\n        {\n          yield break;\n        }\n\n        foreach (var b in predecessor.BranchOutcomes)\n        {\n          yield return b;\n        }\n        foreach (var b in lastStep.BranchOutcomes)\n        {\n          yield return b;\n        }\n      }\n    }\n\n    public IEnumerable<Tuple<AtomicPath, CHLPathEffect>> PotentialSuccessorPaths { get { return lastState.PotentialSuccessorPaths; } }\n\n    public IEnumerable<string> GetSatisfiesDescriptorClauses(Extractor e)\n    {\n      if (lastStep is StraightlineStepBeyondEnd) {\n        throw new Exception(\"Shouldn't invoke GetSatisfiesDescriptorClauses for behavior that goes beyond end\");\n      }\n      if (predecessor == null)\n      {\n        yield return $\"{e.Proc}.LProcName_{methodName}?\";\n      }\n      else\n      {\n        yield return $\"StraightlineBehaviorSatisfiesDescriptor_{predecessor.Name}({e.STrace}, {e.Proc})\";\n      }\n      if (lastStep != null)\n      {\n        foreach (var c in lastStep.GetSatisfiesDescriptorClauses(e))\n        {\n          yield return c;\n        }\n      }\n    }\n\n    public string GetProofOfEndProperties(Extractor e)\n    {\n      string str = \"\";\n\n      if (predecessor != null) {\n        str += $\"lemma_StraightlineBehaviorEndProperties_{predecessor.Name}({e.SB}, {e.Tid}, {e.Proc});\\n\";\n      }\n\n      if (lastStep != null) {\n        var pos = NumSteps - 1;\n        var pos_plus_1 = $\"{NumSteps - 1} + 1\";\n        str += $@\"\n          var sspec := GetLAtomicStraightlineSpec({e.Tid}, {e.Proc});\n          assert ActionTuple({e.SState(pos)}, {e.SState(pos_plus_1)}, {e.SStep(pos)}) in sspec.next;\n        \";\n\n        if (lastStep is StraightlineStepPath) {\n          var pathStep = (StraightlineStepPath)lastStep;\n          var atomicPath = pathStep.Path;\n          str += $\"lemma_LAtomic_PathHasPCStackEffect_{atomicPath.Name}({e.State(pos)}, {e.State(pos_plus_1)}, {e.Path(pos)}, {e.Tid});\\n\";\n        }\n      }\n\n      return str;\n    }\n\n    public IEnumerable<string> GetStatesAndPaths(Extractor e, bool typed)\n    {\n      if (predecessor != null) {\n        foreach (var s in predecessor.GetStatesAndPaths(e, typed)) {\n          yield return s;\n        }\n      }\n\n      if (lastStep != null) {\n        foreach (var s in lastStep.GetPaths(e, typed)) {\n          yield return s;\n        }\n      }\n\n      yield return typed ? $\"{e.State(numSteps)}: LPlusState\" : e.State(numSteps);\n    }\n\n    private IEnumerable<string> GetEnumerationClausesForSteps(Extractor e, bool expanded, bool crRelative)\n    {\n      if (predecessor != null) {\n        foreach (var s in predecessor.GetEnumerationClausesForSteps(e, expanded, crRelative)) {\n          yield return s;\n        }\n      }\n\n      if (lastStep != null) {\n        foreach (var s in lastStep.GetEnumerationClauses(e, expanded, crRelative)) {\n          yield return s;\n        }\n      }\n    }\n\n    private IEnumerable<int> GetNeededInvariantPositions(Extractor e, bool includeFinalState)\n    {\n      if (predecessor != null) {\n        if (lastStep is StraightlineStepBeyondEnd) {\n          // If the last step is beyond the end of the straightline behavior, then just\n          // recursively call the predecessor.\n          \n          foreach (var i in predecessor.GetNeededInvariantPositions(e, includeFinalState)) {\n            yield return i;\n          }\n        }\n        else {\n          // Recursively call GetNeededInvariantPositions on our predecessor to get all\n          // earlier invariant positions.  Pass includedFinalState = false since the\n          // predecessor's final state isn't our final state.\n        \n          foreach (var i in predecessor.GetNeededInvariantPositions(e, false)) {\n            yield return i;\n          }\n\n          // Include the final state if the last step is something other than a path step,\n          // or if the caller of this function set includeFinalState to true.\n\n          if (includeFinalState || !(lastStep is StraightlineStepPath)) {\n            yield return numSteps;\n          }\n        }\n      }\n      else {\n        // If there is no predecessor, include the state (s0).\n\n        yield return numSteps;\n      }\n    }\n\n    public IEnumerable<string> GetEnumerationClauses(Extractor e, bool expanded = false, bool crRelative = false)\n    {\n      var ifn = crRelative ? \"cr.established_inv\" : \"InductiveInv\";\n      var gfn = crRelative ? \"cr.global_inv\" : \"GlobalInv\";\n      var rfn = crRelative ? \"cr.requires_clauses\" : \"RequiresClauses\";\n\n      yield return AH.CombineStringsWithAnd(GetNeededInvariantPositions(e, true).Select(i => $\"{ifn}({e.State(i)})\"));\n      yield return AH.CombineStringsWithAnd(GetNeededInvariantPositions(e, true).Select(i => $\"{gfn}({e.State(i)})\"));\n      yield return $\"{rfn}(LProcName_{methodName}, {e.State(0)}, {e.Tid})\";\n\n      foreach (var s in GetEnumerationClausesForSteps(e, expanded, crRelative)) {\n        yield return s;\n      }\n    }\n\n    public IEnumerable<string> GetOpenValidPathInvocations(Extractor e)\n    {\n      if (predecessor != null) {\n        foreach (var s in predecessor.GetOpenValidPathInvocations(e)) {\n          yield return s;\n        }\n      }\n\n      if (lastStep != null) {\n        foreach (var s in lastStep.GetOpenValidPathInvocations(e)) {\n          yield return s;\n        }\n      }\n    }\n\n    public IEnumerable<AtomicPath> GetPaths()\n    {\n      if (predecessor != null) {\n        foreach (var path in predecessor.GetPaths()) {\n          yield return path;\n        }\n      }\n      if (lastStep is StraightlineStepPath pathStep) {\n        yield return pathStep.Path;\n      }\n      else if (lastStep != null) {\n        yield return null;\n      }\n    }\n\n    public IEnumerable<string> GetStatesAndSteps(Extractor e, bool typed)\n    {\n      if (predecessor != null) {\n        foreach (var s in predecessor.GetStatesAndSteps(e, typed)) {\n          yield return s;\n        }\n      }\n\n      if (lastStep != null) {\n        foreach (var s in lastStep.GetStatesAndSteps(e, typed)) {\n          yield return s;\n        }\n      }\n\n      yield return typed ? $\"{e.State(numSteps, 0)}: LPlusState\" : e.State(numSteps, 0);\n    }\n  }\n}\n"
  },
  {
    "path": "Source/Armada/SymbolTable.cs",
    "content": "using System;\nusing System.Numerics;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text;\nusing static Microsoft.Armada.Predicate;\nusing IToken = Microsoft.Boogie.IToken;\nusing Token = Microsoft.Boogie.Token;\n\nnamespace Microsoft.Armada {\n\n  ////////////////////////////////////////////////////////////////////////////\n  /// ArmadaPC\n  ////////////////////////////////////////////////////////////////////////////\n\n  public class ArmadaPC\n  {\n    private ArmadaSymbolTable symbols;\n    public readonly string methodName;\n    public readonly int instructionCount;\n\n    public ArmadaPC()\n    {\n      symbols = null;\n      methodName = null;\n      instructionCount = 0;\n    }\n\n    public ArmadaPC(ArmadaSymbolTable i_symbols, string i_methodName, int i_instructionCount)\n    {\n      symbols = i_symbols;\n      methodName = i_methodName;\n      instructionCount = i_instructionCount;\n    }\n\n    public override string ToString()\n    {\n      return $\"Armada_PC_{methodName}_{symbols.GetNameForPC(this)}\";\n    }\n\n    public string Name\n    {\n      get {\n        return symbols.GetNameForPC(this);\n      }\n    }\n\n    public override bool Equals(object value)\n    {\n      ArmadaPC pc = value as ArmadaPC;\n\n      return pc != null && pc.methodName == methodName && pc.instructionCount == instructionCount;\n    }\n\n    public override int GetHashCode()\n    {\n      return methodName.GetHashCode() * 397 + instructionCount;\n    }\n\n    public ArmadaPC CloneWithNewSymbolTable(ArmadaSymbolTable newSymbols)\n    {\n      return new ArmadaPC(newSymbols, methodName, instructionCount);\n    }\n  }\n\n  ////////////////////////////////////////////////////////////////////////////\n  /// ArmadaVariable\n  ////////////////////////////////////////////////////////////////////////////\n\n  public enum ArmadaVarType { Ghost, Global, Input, Output, Local, ExternRead, ExternOld };\n\n  public abstract class ArmadaVariable {\n    public readonly string name;\n    public readonly Type ty;\n    public readonly Expression initialValue;\n    public readonly ArmadaVarType varType;\n\n    public ArmadaVariable(string i_name, Type i_ty, Expression i_initialValue, ArmadaVarType i_varType) {\n      name = i_name;\n      ty = i_ty;\n      initialValue = i_initialValue;\n      varType = i_varType;\n    }\n\n    public abstract ArmadaLValue GetLValue(IToken tok, ResolutionContext context);\n    public abstract ArmadaRValue GetRValue(IToken tok, ResolutionContext context);\n    public abstract bool NoTSO();\n\n    public virtual string FieldName { get { return name; } }\n    public virtual Expression InitialValue { get { return initialValue; } }\n    public virtual Type GetFlattenedType(ArmadaSymbolTable symbols, string moduleName = null)\n    {\n      return symbols.FlattenType(ty, moduleName);\n    }\n  }\n\n  public abstract class AddressableArmadaVariable : ArmadaVariable {\n    public AddressableArmadaVariable(string i_name, Type i_ty, Expression i_initialValue, ArmadaVarType i_varType)\n      : base(i_name, i_ty, i_initialValue, i_varType) { }\n\n    public override bool NoTSO() { return false; }\n\n    public override string FieldName { get { return name; } }\n    public override Type GetFlattenedType(ArmadaSymbolTable symbols, string moduleName = null)\n    {\n      return AH.ReferToType(\"Armada_Pointer\");\n    }\n  }\n\n  public abstract class UnaddressableArmadaVariable : ArmadaVariable {\n    public UnaddressableArmadaVariable(string i_name, Type i_ty, Expression i_initialValue, ArmadaVarType i_varType)\n      : base(i_name, i_ty, i_initialValue, i_varType) { }\n  }\n\n  public class GlobalGhostArmadaVariable : UnaddressableArmadaVariable {\n    public GlobalGhostArmadaVariable(string i_name, Type i_ty, Expression i_initialValue)\n      : base(i_name, i_ty, i_initialValue, ArmadaVarType.Ghost)\n    {\n    }\n\n    public override bool NoTSO() { return true; }\n\n    public override ArmadaLValue GetLValue(IToken tok, ResolutionContext context)\n    {\n      return new UnaddressableFieldArmadaLValue(tok, ty, new GhostsArmadaLValue(), new UndefinedBehaviorAvoidanceConstraint(), name,\n                                                0, true);\n    }\n\n    public override ArmadaRValue GetRValue(IToken tok, ResolutionContext context)\n    {\n      var ghosts = context.GetRValueGhosts();\n      var val = $\"({ghosts}).{name}\";\n      return new ArmadaRValue(val);\n    }\n  }\n\n  public class GlobalUnaddressableArmadaVariable : UnaddressableArmadaVariable {\n    public GlobalUnaddressableArmadaVariable(string i_name, Type i_ty, Expression i_initialValue)\n      : base(i_name, i_ty, i_initialValue, ArmadaVarType.Global)\n    {\n    }\n\n    public override bool NoTSO() { return false; }\n\n    public override ArmadaLValue GetLValue(IToken tok, ResolutionContext context)\n    {\n      return new UnaddressableFieldArmadaLValue(tok, ty, new GlobalsArmadaLValue(), new UndefinedBehaviorAvoidanceConstraint(), name,\n                                                0, false);\n    }\n\n    public override ArmadaRValue GetRValue(IToken tok, ResolutionContext context)\n    {\n      var globals = context.GetRValueGlobals();\n      return new ArmadaRValue($\"({globals}).{name}\");\n    }\n  }\n\n  public class GlobalAddressableArmadaVariable : AddressableArmadaVariable {\n    public GlobalAddressableArmadaVariable(string i_name, Type i_ty, Expression i_initialValue)\n      : base(i_name, i_ty, i_initialValue, ArmadaVarType.Global) { }\n\n    public override ArmadaLValue GetLValue(IToken tok, ResolutionContext context)\n    {\n      var addr = $\"({context.GetLValueState()}).addrs.{name}\";\n      return new AddressableArmadaLValue(tok, ty, new ArmadaRValue(addr));\n    }\n\n    public override ArmadaRValue GetRValue(IToken tok, ResolutionContext context)\n    {\n      var addr = $\"({context.GetRValueState()}).addrs.{name}\";\n      var h = context.GetRValueHeap();\n      var valid = AH.GetInvocationOfValidPointer(h, addr, ty);\n      if (valid == null) {\n        context.Fail(tok, $\"Type {ty} is currently not supported in the heap\");\n        return null;\n      }\n      var crashAvoidance = new UndefinedBehaviorAvoidanceConstraint(valid);\n\n      var val = AH.GetInvocationOfDereferencePointer(h, addr, ty);\n      if (val == null) {\n        context.Fail(tok, $\"Type {ty} is currently not supported in the heap\");\n      }\n      return new ArmadaRValue(crashAvoidance, val);\n    }\n  }\n\n  public class MethodStackFrameUnaddressableLocalArmadaVariable : UnaddressableArmadaVariable {\n    private readonly string methodName;\n\n    public override bool NoTSO() { return true; }\n\n    public MethodStackFrameUnaddressableLocalArmadaVariable(\n      string i_name,\n      Type i_ty,\n      Expression i_initialValue,\n      ArmadaVarType i_varType,\n      string i_methodName\n      ) :\n      base(i_name, i_ty, i_initialValue, i_varType) {\n      methodName = i_methodName;\n    }\n\n    public override ArmadaLValue GetLValue(IToken tok, ResolutionContext context)\n    {\n      var crashAvoidance = new UndefinedBehaviorAvoidanceConstraint();\n      var varsVal = new TopStackVarsArmadaLValue(crashAvoidance, methodName);\n      return new UnaddressableFieldArmadaLValue(tok, ty, varsVal, new UndefinedBehaviorAvoidanceConstraint(), name, 0, true);\n    }\n\n    public override ArmadaRValue GetRValue(IToken tok, ResolutionContext context)\n    {\n      var val = $\"({context.GetRValueTopStackFrame()}).{methodName}.{name}\";\n      var crashAvoidance = new UndefinedBehaviorAvoidanceConstraint();\n      return new ArmadaRValue(crashAvoidance, val);\n    }\n  }\n\n  public class MethodStackFrameAddressableLocalArmadaVariable : AddressableArmadaVariable {\n    private readonly string methodName;\n    private readonly bool tsoBypassingInitialization;\n\n    public MethodStackFrameAddressableLocalArmadaVariable(string i_name, Type i_ty, Expression i_initialValue,\n                                                          bool i_tsoBypassingInitialization, string i_methodName)\n      : base(i_name, i_ty, i_initialValue, ArmadaVarType.Local) {\n      methodName = i_methodName;\n      tsoBypassingInitialization = i_tsoBypassingInitialization;\n    }\n\n    public bool TSOBypassingInitialization { get { return tsoBypassingInitialization; } }\n    public override string FieldName { get { return $\"AddrOf'{name}\"; } }\n\n    public override ArmadaLValue GetLValue(IToken tok, ResolutionContext context)\n    {\n      var crashAvoidance = new UndefinedBehaviorAvoidanceConstraint();\n      var addr = $\"({context.GetLValueTopStackFrame()}).{methodName}.AddrOf'{name}\";\n      return new AddressableArmadaLValue(tok, ty, new ArmadaRValue(crashAvoidance, addr));\n    }\n\n    public override ArmadaRValue GetRValue(IToken tok, ResolutionContext context)\n    {\n      var crashAvoidance = new UndefinedBehaviorAvoidanceConstraint();\n      var addr = $\"({context.GetRValueTopStackFrame()}).{methodName}.AddrOf'{name}\";\n      var h = context.GetRValueHeap();\n\n      var valid = AH.GetInvocationOfValidPointer(h, addr, ty);\n      if (valid == null) {\n        context.Fail(tok, $\"Type {ty} is not supported on the heap, and thus not for addressable stack variables either\");\n        return null;\n      }\n      crashAvoidance.Add(valid);\n\n      var val = AH.GetInvocationOfDereferencePointer(h, addr, ty);\n      if (val == null) {\n        context.Fail(tok, $\"Type {ty} is not supported on the heap, and thus not for addressable stack variables either\");\n      }\n      return new ArmadaRValue(crashAvoidance, val);\n    }\n  }\n\n  ////////////////////////////////////////////////////////////////////////////\n  /// PC info\n  ////////////////////////////////////////////////////////////////////////////\n\n  public class MethodInfo {\n    private Program prog;\n    private ArmadaSymbolTable symbols;\n    private int numPCs;\n    private Dictionary<ArmadaPC, EnablingConstraintCollector> constraints;\n    private ArmadaPC returnPC;\n    private HashSet<ArmadaPC> nonyieldingPCs;\n    private ArmadaStatement parsedBody;\n    private bool atomicCallsAndReturns;\n\n    public readonly Method method;\n\n    public MethodInfo(Program i_prog, ArmadaSymbolTable i_symbols, Method i_method)\n    {\n      prog = i_prog;\n      symbols = i_symbols;\n      method = i_method;\n      numPCs = 0;\n      constraints = new Dictionary<ArmadaPC, EnablingConstraintCollector>();\n      returnPC = null;\n      nonyieldingPCs = new HashSet<ArmadaPC>();\n      parsedBody = null;\n      atomicCallsAndReturns = false;\n    }\n\n    public ArmadaPC GenerateOnePC()\n    {\n      int pcVal = numPCs;\n      ++numPCs;\n      var pc = new ArmadaPC(symbols, method.Name, pcVal);\n      symbols.AssociateLabelWithPC(pcVal.ToString(), pc);\n      return pc;\n    }\n\n    public EnablingConstraintCollector GetEnablingConstraintCollector(ArmadaPC pc)\n    {\n      if (constraints.ContainsKey(pc)) {\n        return constraints[pc];\n      }\n      else {\n        return null;\n      }\n    }\n\n    public void AddEnablingConstraint(Program prog, ArmadaPC pc, Expression e)\n    {\n      if (!constraints.ContainsKey(pc)) {\n        constraints[pc] = new EnablingConstraintCollector(prog);\n      }\n      var constraintCollector = constraints[pc];\n      var context = new EnablingConstraintResolutionContext(constraintCollector, method.Name, symbols);\n      var rvalue = context.ResolveAsRValue(e);\n      constraintCollector.AddConjunct(rvalue.UndefinedBehaviorAvoidance);\n      constraintCollector.AddConjunct(rvalue.Val);\n    }\n\n    public void AppendAllPCs(List<ArmadaPC> allPCs)\n    {\n      allPCs.AddRange(Enumerable.Range(0, numPCs).Select(i => new ArmadaPC(symbols, method.Name, i)));\n    }\n\n    public void SetReturnPC(ArmadaPC pc)\n    {\n      returnPC = pc;\n    }\n\n    public ArmadaPC ReturnPC { get { return returnPC; } }\n    public HashSet<ArmadaPC> NonyieldingPCs { get { return nonyieldingPCs; } }\n    public bool IsNonyieldingPC(ArmadaPC pc) { return nonyieldingPCs.Contains(pc); }\n\n    public void UseAtomicCallsAndReturns()\n    {\n      atomicCallsAndReturns = true;\n      nonyieldingPCs.Add(new ArmadaPC(symbols, method.Name, 0));\n      nonyieldingPCs.Add(returnPC);\n    }\n\n    public bool AtomicCallsAndReturns { get { return atomicCallsAndReturns; } }\n\n    public void ParseMethodBody(ArmadaSymbolTable symbols)\n    {\n      var parse = new ParseInfo(prog, symbols, this);\n      parsedBody = ArmadaStatement.ParseStatement(parse, method.Body);\n      var startPC = GenerateOnePC();\n      returnPC = parsedBody.AssignPCs(startPC);\n\n      ArmadaStatement.ComputeNonyieldingPCs(parsedBody, nonyieldingPCs);\n\n      symbols.AssociateLabelWithPC(\"Start\", startPC);\n      symbols.AssociateLabelWithPC(\"End\", returnPC);\n      foreach (var statement in parsedBody) {\n        statement.AssociateLabelsWithPCs();\n        statement.GenerateEnablingConstraints();\n      }\n    }\n\n    public ArmadaStatement ParsedBody { get { return parsedBody; } }\n\n    public void AppendAllNonyieldingPCs(List<ArmadaPC> outNonyieldingPCs)\n    {\n      foreach (var pc in nonyieldingPCs) {\n        outNonyieldingPCs.Add(pc);\n      }\n    }\n\n    public int NumPCs { get { return numPCs; } }\n  }\n\n  public class AllMethodsInfo {\n    private Program prog;\n    private Dictionary<string, MethodInfo> methodPCInfo;\n\n    public AllMethodsInfo(Program i_prog)\n    {\n      prog = i_prog;\n      methodPCInfo = new Dictionary<string, MethodInfo>();\n    }\n\n    public MethodInfo AddMethod(ArmadaSymbolTable symbols, Method method)\n    {\n      if (methodPCInfo.ContainsKey(method.Name)) {\n        AH.PrintError(prog, Token.NoToken, $\"Attempt to add method {method.Name} twice to AllMethodsInfo\");\n        return methodPCInfo[method.Name];\n      }\n      var info = new MethodInfo(prog, symbols, method);\n      methodPCInfo[method.Name] = info;\n      return info;\n    }\n\n    public MethodInfo LookupMethod(string methodName)\n    {\n      if (methodPCInfo.ContainsKey(methodName)) {\n        return methodPCInfo[methodName];\n      }\n      else {\n        return null;\n      }\n    }\n\n    public void AppendAllPCs(List<ArmadaPC> allPCs)\n    {\n      foreach (var info in methodPCInfo.Values) {\n        info.AppendAllPCs(allPCs);\n      }\n    }\n\n    public void AppendAllNonyieldingPCs(List<ArmadaPC> nonyieldingPCs)\n    {\n      foreach (var info in methodPCInfo.Values) {\n        info.AppendAllNonyieldingPCs(nonyieldingPCs);\n      }\n    }\n\n    public IEnumerable<string> AllMethodNames { get { return methodPCInfo.Keys; } }\n  }\n\n  ////////////////////////////////////////////////////////////////////////////\n  /// SYMBOL TABLE\n  ////////////////////////////////////////////////////////////////////////////\n\n  public class ArmadaGlobalVariableSymbolTable {\n    private Dictionary<string, ArmadaVariable> table;\n    private List<string> variableNames;\n\n    public ArmadaGlobalVariableSymbolTable() {\n      table = new Dictionary<string, ArmadaVariable>();\n      variableNames = new List<string>();\n    }\n\n    public void AddClassInfo(Program prog, ClassDecl c, ArmadaStructs structs)\n    {\n      if (!c.IsDefaultClass) {\n        AH.PrintError(prog, \"Internal error:  ArmadaGlobalVariableSymbolTable.AddClassInfo called on non-default class\");\n        return;\n      }\n      foreach (MemberDecl member in c.Members) {\n        if (member is Field) {\n          var f = (Field)member;\n          variableNames.Add(f.Name);\n          ArmadaVariable av = null;\n          if (!AH.IsValidType(f.Type, structs)) {\n            AH.PrintError(prog, $\"Global variable {f.Name} has invalid type {f.Type}\");\n            av = null;\n          }\n          else if (f.IsGhost) {\n            av = new GlobalGhostArmadaVariable(f.Name, f.Type, f.InitialValue);\n          }\n          else if (f.IsNoAddr) {\n            av = new GlobalUnaddressableArmadaVariable(f.Name, f.Type, f.InitialValue);\n          }\n          else {\n            if (AH.IsValidHeapType(f.Type, structs)) {\n              av = new GlobalAddressableArmadaVariable(f.Name, f.Type, f.InitialValue);\n            }\n            else {\n              AH.PrintError(prog, $\"Global variable {f.Name} has type {f.Type} that can't be used on the heap. Consider making it noaddr or ghost.\");\n              av = null;\n            }\n          }\n          table.Add(f.Name, av);\n        }\n      }\n    }\n\n    public ArmadaVariable Lookup(string variableName)\n    {\n      ArmadaVariable v;\n      if (!table.TryGetValue(variableName, out v)) {\n        return null;\n      }\n      return v;\n    }\n\n    public IEnumerable<string> VariableNames { get { return variableNames; } }\n  }\n\n  public class ArmadaSingleMethodSymbolTable {\n    private readonly Method method;\n    private readonly string methodName;\n    private readonly bool isExternal;\n    private readonly bool isFromStructsModule;\n    private Dictionary<string, ArmadaVariable> variablesByName;\n    private List<string> inputVariableNames;\n    private List<string> outputVariableNames;\n    private List<string> variableNamesInOrder;\n\n    public ArmadaSingleMethodSymbolTable(Method i_method, bool i_isExternal, bool i_isFromStructsModule) {\n      method = i_method;\n      methodName = method.Name;\n      isExternal = i_isExternal;\n      isFromStructsModule = i_isFromStructsModule;\n      variablesByName = new Dictionary<string, ArmadaVariable>();\n      inputVariableNames = new List<string>();\n      outputVariableNames = new List<string>();\n      variableNamesInOrder = new List<string>();\n    }\n\n    public Method GetMethod() { return method; }\n    public bool IsExternal { get { return isExternal; } }\n    public bool IsFromStructsModule { get { return isFromStructsModule; } }\n\n    public void AddVariable(Program prog, ArmadaVariable v)\n    {\n      if (variablesByName.ContainsKey(v.name)) {\n        AH.PrintError(prog, $\"Variable {v.name} defined twice in method {methodName}\");\n        return;\n      }\n\n      variablesByName[v.name] = v;\n      variableNamesInOrder.Add(v.name);\n\n      if (v.varType == ArmadaVarType.Input) {\n        inputVariableNames.Add(v.name);\n      }\n      else if (v.varType == ArmadaVarType.Output) {\n        outputVariableNames.Add(v.name);\n      }\n    }\n\n    public ArmadaVariable LookupVariable(string name) {\n      if (variablesByName.ContainsKey(name)) {\n        return variablesByName[name];\n      }\n      else {\n        return null;\n      }\n    }\n\n    public string GetVariableStackFrameFieldName(string localVariableName) {\n      return LookupVariable(localVariableName).FieldName;\n    }\n\n    public ArmadaVariable GetInputVariableByIndex(int idx) {\n      if (idx < 0 || idx >= inputVariableNames.Count) {\n        return null;\n      }\n      string name = inputVariableNames[idx];\n      return variablesByName[name];\n    }\n\n    public int GetNumInputVariables() {\n      return inputVariableNames.Count;\n    }\n\n    public ArmadaVariable GetOutputVariableByIndex(int idx) {\n      if (idx < 0 || idx >= outputVariableNames.Count) {\n        return null;\n      }\n      string name = outputVariableNames[idx];\n      return variablesByName[name];\n    }\n\n    public int GetNumOutputVariables() {\n      return outputVariableNames.Count;\n    }\n\n    public IEnumerable<string> InputVariableNames { get { return inputVariableNames; } }\n    public IEnumerable<string> OutputVariableNames { get { return outputVariableNames; } }\n    public IEnumerable<ArmadaVariable> AllVariables { get { return variablesByName.Values; } }\n    public IEnumerable<string> AllVariableNamesInOrder { get { return variableNamesInOrder; } }\n    public IEnumerable<ArmadaVariable> AllVariablesInOrder { get { return variableNamesInOrder.Select(n => variablesByName[n]); } }\n  }\n\n  public class ArmadaMethodLocalVariableSymbolTable {\n    private Dictionary<string, ArmadaSingleMethodSymbolTable> methodTable;\n\n    public ArmadaMethodLocalVariableSymbolTable() {\n      methodTable = new Dictionary<string, ArmadaSingleMethodSymbolTable>();\n    }\n\n    private void ExtractLocalVariables(Program prog, Statement stmt, string methodName, ArmadaSingleMethodSymbolTable smst,\n                                       ArmadaStructs structs)\n    {\n      if (stmt is BlockStmt) {\n        var s = (BlockStmt)stmt;\n        foreach (var substmt in s.Body) {\n          ExtractLocalVariables(prog, substmt, methodName, smst, structs);\n        }\n      }\n      else if (stmt is IfStmt) {\n        var s = (IfStmt)stmt;\n        ExtractLocalVariables(prog, s.Thn, methodName, smst, structs);\n        ExtractLocalVariables(prog, s.Els, methodName, smst, structs);\n      }\n      else if (stmt is WhileStmt) {\n        var s = (WhileStmt)stmt;\n        ExtractLocalVariables(prog, s.Body, methodName, smst, structs);\n      }\n      else if (stmt is VarDeclStmt) {\n        var s = (VarDeclStmt)stmt;\n        UpdateStmt update = null;\n\n        if (s.Update != null) {\n          if (!(s.Update is UpdateStmt)) {\n            AH.PrintError(prog, stmt.Tok, \"Armada only supports *concrete* assignment of local variables during assignment.\");\n            return;\n          }\n          else {\n            update = (UpdateStmt)s.Update;\n            if (s.Locals.Count != update.Rhss.Count) {\n              AH.PrintError(prog, s.Tok, $\"Number of left-hand sides for assignment ({s.Locals.Count}) statement doesn't match number of right-hand sides ({update.Rhss.Count}).\");\n              return;\n            }\n          }\n        }\n\n        for (int i = 0; i < s.Locals.Count; ++i) {\n          var local = s.Locals[i];\n          if (local.OptionalType is InferredTypeProxy) {\n            AH.PrintError(prog, local.EndTok, \"Local variables in Armada layer methods must be given explicit types.\");\n            continue;\n          }\n\n          Expression initialValue = null;\n          if (update != null) {\n            var rhs = update.Rhss[i];\n            if (rhs is HavocRhs) {\n              // No need to do anything special here because in the absence of an initializer we already havoc\n            }\n            else if (rhs is ExprRhs) {\n              var erhs = (ExprRhs)rhs;\n              initialValue = erhs.Expr;\n            }\n            else if (rhs is CreateThreadRhs) {\n              AH.PrintError(prog, rhs.Tok, \"Create-thread can't be done in a variable-declaration statement\");\n              continue;\n            }\n            else if (rhs is MallocRhs || rhs is CallocRhs) {\n              AH.PrintError(prog, rhs.Tok, \"Allocation can't be done in a variable-declaration statement\");\n              continue;\n            }\n            else {\n              AH.PrintError(prog, rhs.Tok, \"Right-hand side of variable-declaration isn't a valid rvalue\");\n              continue;\n            }\n          }\n\n          if (!AH.IsValidType(local.OptionalType, structs)) {\n            AH.PrintError(prog, stmt.Tok, $\"Local variable {local.Name} in method {methodName} has invalid type {local.OptionalType}\");\n            continue;\n          }\n\n          ArmadaVariable v;\n          if (local.IsNoAddr) {\n            v = new MethodStackFrameUnaddressableLocalArmadaVariable(local.Name, local.OptionalType, initialValue, ArmadaVarType.Local, methodName);\n          }\n          else {\n            if (!AH.IsValidHeapType(local.OptionalType, structs)) {\n              AH.PrintError(prog, stmt.Tok, $\"Local variable {local.Name} in method {methodName} has type {local.OptionalType} that can't be used on the heap. Consider using noaddr instead.\");\n              continue;\n            }\n            v = new MethodStackFrameAddressableLocalArmadaVariable(local.Name, local.OptionalType, initialValue,\n                                                                   s.BypassStoreBuffers, methodName);\n          }\n          smst.AddVariable(prog, v);\n        }\n      }\n    }\n\n    private void ExtractOldVariablesForBodylessMethod(Program prog, ArmadaSymbolTable symbols, Method meth, ArmadaSingleMethodSymbolTable smst)\n    {\n      if (meth.Ens == null) { return; }\n      if (!meth.Ens.Any()) { return; }\n\n      var failureCollector = new SimpleFailureReporter(prog);\n      var ensContext = new BodylessMethodSnapshotResolutionContext(\"s\", \"tid\", meth.Name, symbols, failureCollector);\n      foreach (var ens in meth.Ens)\n      {\n        var ensResolvedJustToGetOldValues = ensContext.ResolveAsRValue(ens.E);\n      }\n      int whichOldValue = 0;\n      foreach (var oldValue in ensContext.OldValues) {\n        var varName = $\"Armada_Old{whichOldValue}\";\n        var v = new MethodStackFrameUnaddressableLocalArmadaVariable(varName, oldValue.Type, oldValue, ArmadaVarType.ExternOld, meth.Name);\n        ++whichOldValue;\n        smst.AddVariable(prog, v);\n      }\n    }\n\n    public void AddMethodInfo(Program prog, ClassDecl c, ArmadaSymbolTable symbols, Method meth, bool fromStructsModule,\n                              ArmadaStructs structs)\n    {\n      bool isExternal = (meth.Body is null || Attributes.Contains(meth.Attributes, \"extern\"));\n\n      var smst = new ArmadaSingleMethodSymbolTable(meth, isExternal, fromStructsModule);\n\n      foreach (var formal in meth.Ins) {\n        var v = new MethodStackFrameUnaddressableLocalArmadaVariable(formal.Name, formal.Type, null, ArmadaVarType.Input, meth.Name);\n        smst.AddVariable(prog, v);\n      }\n\n      foreach (var formal in meth.Outs) {\n        var v = new MethodStackFrameUnaddressableLocalArmadaVariable(formal.Name, formal.Type, null, ArmadaVarType.Output, meth.Name);\n        smst.AddVariable(prog, v);\n      }\n\n      ExtractLocalVariables(prog, meth.Body, meth.Name, smst, structs);\n\n      if (isExternal && meth.Reads.Expressions != null) {\n        var reads = meth.Reads.Expressions;\n        for (int i = 0; i < reads.Count; ++i) {\n          Expression read_expr = reads.ElementAt(i);\n          var varName = $\"Armada_Extern{i}\";\n          var v = new MethodStackFrameUnaddressableLocalArmadaVariable(varName, read_expr.Type, null, ArmadaVarType.ExternRead, meth.Name);\n          smst.AddVariable(prog, v);\n        }\n      }\n\n      if (methodTable.ContainsKey(meth.Name)) {\n        AH.PrintError(prog, $\"Method {meth.Name} already defined\");\n      }\n      else {\n        methodTable[meth.Name] = smst;\n      }\n\n      if (isExternal && meth.Body == null)\n      {\n        ExtractOldVariablesForBodylessMethod(prog, symbols, meth, smst);\n      }\n    }\n\n    public ArmadaVariable Lookup(string methodName, string localVariableName)\n    {\n      ArmadaSingleMethodSymbolTable smst;\n      if (!methodTable.TryGetValue(methodName, out smst)) {\n        return null;\n      }\n      return smst.LookupVariable(localVariableName);\n    }\n\n    public IEnumerable<string> MethodNames { get { return methodTable.Keys; } }\n\n    public bool DoesMethodNameExist(string methodName)\n    {\n      return methodTable.ContainsKey(methodName);\n    }\n\n    public ArmadaSingleMethodSymbolTable GetMethodSymbolTable(string methodName)\n    {\n      return methodTable[methodName];\n    }\n\n    public ArmadaVariable GetInputVariableByIndex(string methodName, int idx)\n    {\n      ArmadaSingleMethodSymbolTable smst;\n      if (!methodTable.TryGetValue(methodName, out smst)) {\n        return null;\n      }\n      return smst.GetInputVariableByIndex(idx);\n    }\n\n    public int GetNumInputVariables(string methodName)\n    {\n      ArmadaSingleMethodSymbolTable smst;\n      if (!methodTable.TryGetValue(methodName, out smst)) {\n        return -1;\n      }\n      return smst.GetNumInputVariables();\n    }\n\n    public ArmadaVariable GetOutputVariableByIndex(string methodName, int idx)\n    {\n      ArmadaSingleMethodSymbolTable smst;\n      if (!methodTable.TryGetValue(methodName, out smst)) {\n        return null;\n      }\n      return smst.GetOutputVariableByIndex(idx);\n    }\n\n    public int GetNumOutputVariables(string methodName)\n    {\n      ArmadaSingleMethodSymbolTable smst;\n      if (!methodTable.TryGetValue(methodName, out smst)) {\n        return -1;\n      }\n      return smst.GetNumOutputVariables();\n    }\n  }\n\n  public class GlobalInvariantInfo\n  {\n    private GlobalInvariantDecl decl;\n    private string translatedName;\n\n    public GlobalInvariantInfo(GlobalInvariantDecl i_decl)\n    {\n      decl = i_decl;\n      translatedName = null;\n    }\n\n    public GlobalInvariantDecl Decl { get { return decl; } }\n    public string Name { get { return decl.Name; } }\n    public string TranslatedName { get { return translatedName; } set { translatedName = value; } }\n  }\n\n  public class YieldPredicateInfo\n  {\n    private YieldPredicateDecl decl;\n    private string translatedName;\n\n    public YieldPredicateInfo(YieldPredicateDecl i_decl)\n    {\n      decl = i_decl;\n      translatedName = null;\n    }\n\n    public YieldPredicateDecl Decl { get { return decl; } }\n    public string Name { get { return decl.Name; } }\n    public string TranslatedName { get { return translatedName; } set { translatedName = value; } }\n  }\n\n  public class UniversalStepConstraintInfo\n  {\n    private UniversalStepConstraintDecl decl;\n    private string translatedName;\n\n    public UniversalStepConstraintInfo(UniversalStepConstraintDecl i_decl)\n    {\n      decl = i_decl;\n      translatedName = null;\n    }\n\n    public UniversalStepConstraintDecl Decl { get { return decl; } }\n    public string Name { get { return decl.Name; } }\n    public string TranslatedName { get { return translatedName; } set { translatedName = value; } }\n  }\n\n  public class ArmadaSymbolTable\n  {\n    private Program prog;\n    private ArmadaGlobalVariableSymbolTable globalVariables;\n    private ArmadaMethodLocalVariableSymbolTable localVariables;\n    private ClassDecl defaultClass;\n    private ArmadaStructs structs;\n    private HashSet<string> threadRoutines;\n    private List<string> functionNames;\n    private List<NextRoutineConstructor> nextRoutineConstructors;\n    private List<NextRoutine> nextRoutines;\n    private AllMethodsInfo allMethodsInfo;\n    private NextRoutineConstructor tauNextRoutineConstructor;\n    private Dictionary<string, ArmadaPC> methodAndLabelToPCMap;\n    private Dictionary<ArmadaPC, string> pcToLabelMap;\n    private Dictionary<string, GlobalInvariantInfo> globalInvariants;\n    private Dictionary<string, YieldPredicateInfo> yieldPredicates;\n    private Dictionary<string, UniversalStepConstraintInfo> universalStepConstraints;\n\n    public ArmadaSymbolTable(Program i_prog, ArmadaStructs i_structs)\n    {\n      prog = i_prog;\n      globalVariables = new ArmadaGlobalVariableSymbolTable();\n      localVariables = new ArmadaMethodLocalVariableSymbolTable();\n      defaultClass = null;\n      if (i_structs == null)\n      {\n        structs = new ArmadaStructs(null);\n      }\n      else\n      {\n        structs = i_structs;\n      }\n      threadRoutines = new HashSet<string> { \"main\" };\n      functionNames = new List<string>{};\n      nextRoutines = new List<NextRoutine>();\n      nextRoutineConstructors = new List<NextRoutineConstructor>();\n      allMethodsInfo = new AllMethodsInfo(prog);\n      tauNextRoutineConstructor = null;\n      methodAndLabelToPCMap = new Dictionary<string, ArmadaPC>();\n      pcToLabelMap = new Dictionary<ArmadaPC, string>();\n      globalInvariants = new Dictionary<string, GlobalInvariantInfo>();\n      yieldPredicates = new Dictionary<string, YieldPredicateInfo>();\n      universalStepConstraints = new Dictionary<string, UniversalStepConstraintInfo>();\n    }\n\n    public void AddClass(ClassDecl c, bool fromStructsModule, ArmadaStructs structs)\n    {\n      if (c.IsDefaultClass)\n      {\n        defaultClass = c;\n        globalVariables.AddClassInfo(prog, defaultClass, structs);\n        foreach (MemberDecl member in defaultClass.Members)\n        {\n          if (member is Method) {\n            var meth = (Method)member;\n            localVariables.AddMethodInfo(prog, defaultClass, this, meth, fromStructsModule, structs);\n          }\n          else if (member is Function) {\n            functionNames.Add(member.Name);\n          }\n          else if (member is GlobalInvariantDecl) {\n            AddGlobalInvariant((GlobalInvariantDecl)member);\n          }\n          else if (member is YieldPredicateDecl) {\n            AddYieldPredicate((YieldPredicateDecl)member);\n          }\n          else if (member is UniversalStepConstraintDecl) {\n            AddUniversalStepConstraint((UniversalStepConstraintDecl)member);\n          }\n        }\n      }\n    }\n\n    public ArmadaGlobalVariableSymbolTable Globals { get { return globalVariables; } }\n\n    public ArmadaVariable Lookup(string methodName, string v)\n    {\n      ArmadaVariable av;\n\n      if (methodName != null)\n      {\n        av = localVariables.Lookup(methodName, v);\n        if (av != null)\n        {\n          return av;\n        }\n      }\n\n      av = globalVariables.Lookup(v);\n      if (av != null)\n      {\n        return av;\n      }\n      return null;\n    }\n\n    public IEnumerable<string> MethodNames { get { return localVariables.MethodNames; } }\n\n    public bool DoesMethodNameExist(string methodName)\n    {\n      return localVariables.DoesMethodNameExist(methodName);\n    }\n\n    public ArmadaSingleMethodSymbolTable GetMethodSymbolTable(string methodName)\n    {\n      return localVariables.GetMethodSymbolTable(methodName);\n    }\n\n    public ArmadaVariable GetInputVariableByIndex(string methodName, int idx)\n    {\n      return localVariables.GetInputVariableByIndex(methodName, idx);\n    }\n\n    public int GetNumInputVariables(string methodName)\n    {\n      return localVariables.GetNumInputVariables(methodName);\n    }\n\n    public ArmadaVariable GetOutputVariableByIndex(string methodName, int idx)\n    {\n      return localVariables.GetOutputVariableByIndex(methodName, idx);\n    }\n\n    public int GetNumOutputVariables(string methodName)\n    {\n      return localVariables.GetNumOutputVariables(methodName);\n    }\n\n    public void UseMethodAsThreadRoutine(string methodName)\n    {\n      if (allMethodsInfo.LookupMethod(methodName).AtomicCallsAndReturns) {\n        AH.PrintError(prog, $\"It's illegal to use create_thread on {methodName} since it uses atomic calls and returns.\");\n      }\n      threadRoutines.Add(methodName);\n    }\n\n    public HashSet<string> GetThreadRoutines()\n    {\n      return threadRoutines;\n    }\n\n    public bool IsThreadRoutine(string methodName)\n    {\n      return threadRoutines.Contains(methodName);\n    }\n\n    public ClassDecl DefaultClass { get { return defaultClass; } set { defaultClass = value; } }\n\n    public IEnumerable<string> StructNames { get { return structs.StructNames; } }\n    public bool DoesStructExist(string structName) { return structs.DoesStructExist(structName); }\n    public ArmadaStruct GetStruct(string structName) { return structs.GetStruct(structName); }\n    public ArmadaStruct LookupStruct(string structName) { return structs.LookupStruct(structName); }\n    public Type GetStructFieldType(string structName, string fieldName) { return structs.GetStructFieldType(structName, fieldName); }\n    public int GetStructFieldPos(string structName, string fieldName) { return structs.GetStructFieldPos(structName, fieldName); }\n    public Type FlattenType(Type t, string moduleName = null) { return structs.FlattenType(t, moduleName); }\n    public string StructsModuleName { get { return structs == null ? null : structs.StructsModuleName; } }\n\n    public void AddNextRoutineConstructor(NextRoutineConstructor nrc) { nextRoutineConstructors.Add(nrc); }\n    public IEnumerable<NextRoutineConstructor> NextRoutineConstructors { get { return nextRoutineConstructors; } }\n    public void ClearNextRoutineConstructors() { nextRoutineConstructors = null; }\n    public void AddNextRoutine(NextRoutine nextRoutine) { nextRoutines.Add(nextRoutine); }\n    public IEnumerable<NextRoutine> NextRoutines { get { return nextRoutines; } }\n    public NextRoutineConstructor TauNextRoutineConstructor {\n      get { return tauNextRoutineConstructor; }\n      set { tauNextRoutineConstructor = value; }\n    }\n    public NextRoutine TauNextRoutine { get { return tauNextRoutineConstructor.DefinedBehaviorNextRoutine; } }\n\n    public AllMethodsInfo AllMethods { get { return allMethodsInfo; } }\n\n    public IEnumerable<string> AllFunctions { get { return functionNames; } }\n\n    public void AssociateLabelWithPC(string labelStr, ArmadaPC pc)\n    {\n      var fullLabelStr = pc.methodName + \"_\" + labelStr;\n      if (methodAndLabelToPCMap.ContainsKey(fullLabelStr)) {\n        AH.PrintError(prog, $\"ERROR:  More than one label named {labelStr} in method {pc.methodName}\");\n      }\n      methodAndLabelToPCMap[fullLabelStr] = pc;\n      pcToLabelMap[pc] = labelStr;\n    }\n\n    public ArmadaPC GetPCForMethodAndLabel(string methodAndLabelStr)\n    {\n      if (methodAndLabelToPCMap.ContainsKey(methodAndLabelStr))\n      {\n        return methodAndLabelToPCMap[methodAndLabelStr];\n      }\n      else\n      {\n        return null;\n      }\n    }\n\n    public string GetLabelForPC(ArmadaPC pc)\n    {\n      if (pcToLabelMap.ContainsKey(pc)) {\n        return pcToLabelMap[pc];\n      }\n      else {\n        return null;\n      }\n    }\n\n    public string GetNameForPC(ArmadaPC pc)\n    {\n      string labelStr = GetLabelForPC(pc);\n      if (labelStr != null) {\n        return labelStr;\n      }\n      return pc.instructionCount.ToString();\n    }\n\n    public void AddGlobalInvariant(GlobalInvariantDecl decl)\n    {\n      globalInvariants[decl.Name] = new GlobalInvariantInfo(decl);\n    }\n\n    public void AddYieldPredicate(YieldPredicateDecl decl)\n    {\n      yieldPredicates[decl.Name] = new YieldPredicateInfo(decl);\n    }\n\n    public void AddUniversalStepConstraint(UniversalStepConstraintDecl decl)\n    {\n      universalStepConstraints[decl.Name] = new UniversalStepConstraintInfo(decl);\n    }\n\n    public Dictionary<string, GlobalInvariantInfo> GlobalInvariants { get { return globalInvariants; } }\n    public Dictionary<string, YieldPredicateInfo> YieldPredicates { get { return yieldPredicates; } }\n    public Dictionary<string, UniversalStepConstraintInfo> UniversalStepConstraints { get { return universalStepConstraints; } }\n\n    public string RefinementConstraint { get { return structs.RefinementConstraint; } }\n\n    public bool IsNonyieldingPC(ArmadaPC pc)\n    {\n      if (pc == null) { return false; }\n      var method = allMethodsInfo.LookupMethod(pc.methodName);\n      return method == null ? false : method.IsNonyieldingPC(pc);\n    }\n\n    public IEnumerable<ArmadaPC> EnumeratePotentialRecurrentPCs()\n    {\n      foreach (var methodName in allMethodsInfo.AllMethodNames) {\n        // Include the start of the method.\n        yield return new ArmadaPC(this, methodName, 0);\n\n        // Include the return site of the method.\n        var methodInfo = allMethodsInfo.LookupMethod(methodName);\n        yield return methodInfo.ReturnPC;\n\n        // Include each loop head in the method, and the PC of any non-forward goto.\n        if (methodInfo.method.Body == null) {\n          // For body-less methods, there's an implicit loop head at PC #1.\n          yield return new ArmadaPC(this, methodName, 1);\n        }\n        else {\n          foreach (var stmt in methodInfo.ParsedBody) {\n            if (stmt is ArmadaWhileStatement) {\n              yield return stmt.StartPC;\n            }\n            else if (stmt is ArmadaGotoStatement) {\n              var startPC = stmt.StartPC;\n              var s = (GotoStmt)(stmt.Stmt);\n              var targetPC = GetPCForMethodAndLabel(methodName + \"_\" + s.Target);\n              if (targetPC != null && targetPC.instructionCount <= startPC.instructionCount) {\n                // If it's not a forward goto, it's potentially recurrent.\n                yield return startPC;\n              }\n            }\n          }\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "Source/Armada/TSOElimination.cs",
    "content": "using System;\nusing System.Numerics;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text;\nusing System.Text.RegularExpressions;\n\nnamespace Microsoft.Armada\n{\n  public abstract class TSOField\n  {\n    public readonly string enclosingFieldSpec;\n\n    public TSOField(string i_enclosingFieldSpec)\n    {\n      enclosingFieldSpec = i_enclosingFieldSpec;\n    }\n\n    public string EnclosingFieldSpec { get { return enclosingFieldSpec; } }\n  }\n\n  public class StructTSOField : TSOField\n  {\n    private ArmadaStruct outerStruct;\n    private string fieldName;\n    private int fieldPos;\n\n    public StructTSOField(string i_enclosingFieldSpec, ArmadaStruct i_outerStruct, string i_fieldName, int i_fieldPos)\n      : base(i_enclosingFieldSpec)\n    {\n      outerStruct = i_outerStruct;\n      fieldName = i_fieldName;\n      fieldPos = i_fieldPos;\n    }\n\n    public ArmadaStruct OuterStruct { get { return outerStruct; } }\n    public string FieldName { get { return fieldName; } }\n    public int FieldPos { get { return fieldPos; } }\n  }\n\n  public class ArrayTSOField : TSOField\n  {\n    private int whichArray;\n\n    public ArrayTSOField(string i_enclosingFieldSpec, int i_whichArray) : base(i_enclosingFieldSpec)\n    {\n      whichArray = i_whichArray;\n    }\n\n    public int WhichArray { get { return whichArray; } }\n  }\n\n  public class TSOFieldList\n  {\n    private bool valid;\n    private string varName;\n    private Type varType;\n    private List<TSOField> fields;\n    private int numArrays;\n    private string fieldSpec;\n    private string indexList;\n    private string indexParamList;\n    private List<string> indexConstraints;\n\n    public TSOFieldList(ProofGenerationParams pgp, TSOEliminationStrategyDecl strategy)\n    {\n      valid = false;\n\n      if (!strategy.Fields.Any()) {\n        AH.PrintError(pgp.prog, \"No field list found in TSO elimination strategy description\");\n        return;\n      }\n\n      varName = strategy.Fields[0];\n      ArmadaVariable v = pgp.symbolsLow.Globals.Lookup(varName);\n      if (v == null) {\n        AH.PrintError(pgp.prog, strategy.tok, $\"No global variable named {varName}\");\n        return;\n      }\n\n      varType = v.ty;\n      fieldSpec = $\".{varName}\";\n      fields = new List<TSOField>();\n      numArrays = 0;\n      indexList = \"\";\n      indexParamList = \"\";\n      indexConstraints = new List<string>();\n\n      Type currentType = varType;\n      int strategyFieldsUsed = 1;\n      while (true) {\n        currentType = AddArrayFields(pgp, currentType);\n        if (strategyFieldsUsed < strategy.Fields.Count) {\n          currentType = AddStructField(pgp, strategy.tok, currentType, strategy.Fields[strategyFieldsUsed]);\n          if (currentType == null) {\n            return;\n          }\n          ++strategyFieldsUsed;\n        }\n        else {\n          break;\n        }\n      }\n\n      if (!AH.IsPrimitiveType(currentType)) {\n        AH.PrintError(pgp.prog, \"The field list given for the TSO-elimination strategy ends in the middle of a struct.  It has to go all the way to a primitive field.\");\n        return;\n      }\n\n      valid = true;\n    }\n\n    private Type AddArrayFields(ProofGenerationParams pgp, Type currentType)\n    {\n      if (!(currentType is SizedArrayType)) {\n        return currentType;\n      }\n\n      var subtype = ((SizedArrayType)currentType).Range;\n      var innerType = AddArrayFields(pgp, subtype);\n      fields.Add(new ArrayTSOField(fieldSpec, numArrays));\n\n      indexConstraints.Add($\"0 <= idx{numArrays} < |g{fieldSpec}|\");\n      fieldSpec += $\"[idx{numArrays}]\";\n      indexList += $\", idx{numArrays}\";\n      indexParamList += $\", idx{numArrays}:int\";\n\n      ++numArrays;\n\n      return innerType;\n    }\n\n    private Type AddStructField(ProofGenerationParams pgp, Microsoft.Boogie.IToken strategyTok, Type currentType, string fieldName)\n    {\n      if (!(currentType is UserDefinedType)) {\n        AH.PrintError(pgp.prog, strategyTok, $\"Can't find field named {fieldName} in non-struct {currentType}\");\n        return null;\n      }\n\n      var structName = ((UserDefinedType)currentType).Name;\n      ArmadaStruct s = pgp.symbolsLow.LookupStruct(structName);\n\n      if (s == null) {\n        AH.PrintError(pgp.prog, strategyTok, $\"Can't find field named {fieldName} within non-struct {structName}\");\n        return null;\n      }\n\n      currentType = s.LookupFieldType(fieldName);\n      if (currentType == null) {\n        AH.PrintError(pgp.prog, strategyTok, $\"No field named {fieldName} exists in struct {s.Name}\");\n        return null;\n      }\n      var fieldPos = s.GetFieldPos(fieldName);\n\n      fields.Add(new StructTSOField(fieldSpec, s, fieldName, fieldPos));\n      fieldSpec += $\".{fieldName}\";\n      return currentType;\n    }\n\n    public bool Valid { get { return valid; } }\n    public string GetVar() { return varName; }\n    public Type GetVarType() { return varType; }\n    public int NumFields { get { return fields.Count(); } }\n    public TSOField GetField(int i) { return fields[i]; }\n    public int NumArrays { get { return numArrays; } }\n    public string FieldSpec { get { return fieldSpec; } }\n    public string IndexList { get { return indexList; } }\n    public string IndexParamList { get { return indexParamList; } }\n    public string IndexListWithoutLeadingComma { get { return indexList.Length > 2 ? indexList.Substring(2) : \"\"; } }\n    public string IndexParamListWithoutLeadingComma { get { return indexParamList.Length > 2 ? indexParamList.Substring(2) : \"\"; } }\n    public List<string> IndexConstraints { get { return indexConstraints; } }\n  }\n\n  public class TSOEliminationNoConflictingOwnershipInvariantInfo : InvariantInfo\n  {\n    private TSOFieldList fields;\n    private string ownershipPredicate;\n\n    public TSOEliminationNoConflictingOwnershipInvariantInfo(TSOFieldList i_fields, string i_ownershipPredicate)\n      : base(\"NoConflictingOwnership\", \"NoConflictingOwnership\", new List<string>{ \"InductiveInv\" }, \"\", false)\n    {\n      fields = i_fields;\n      ownershipPredicate = i_ownershipPredicate;\n    }\n\n    public override string GenerateSpecificNextLemma(ProofGenerationParams pgp, AtomicPath atomicPath,\n                                                     IEnumerable<InvariantInfo> allInvariants, AtomicSpec atomicSpec,\n                                                     bool onlyNonstoppingPaths)\n    {\n      string name = atomicPath.Name;\n      string specificPathLemmaName = $\"lemma_NoConflictingOwnershipPreservedByPath_{name}\";\n\n      var pr = new PathPrinter(atomicSpec);\n      string str = $@\"\n        lemma {specificPathLemmaName}(s: LPlusState, s': LPlusState, path: LAtomic_Path, tid: Armada_ThreadHandle)\n          requires InductiveInv(s)\n          requires LAtomic_NextPath(s, s', path, tid)\n          requires path.LAtomic_Path_{name}?\n          ensures  NoConflictingOwnership(s')\n        {{\n          { pr.GetOpenValidPathInvocation(atomicPath) }\n          ProofCustomizationGoesHere();\n          if s'.s.stop_reason.Armada_NotStopped? {{\n            assert s.s.stop_reason.Armada_NotStopped?;\n            forall tid1, tid2{fields.IndexList} |\n              && tid1 in s'.s.threads\n              && tid2 in s'.s.threads\n              && {ownershipPredicate}(s', tid1{fields.IndexList})\n              && {ownershipPredicate}(s', tid2{fields.IndexList})\n              ensures tid1 == tid2\n            {{\n              assert tid1 in s.s.threads && tid2 in s.s.threads && {ownershipPredicate}(s, tid1{fields.IndexList}) && {ownershipPredicate}(s, tid2{fields.IndexList}) ==> tid1 == tid2;\n            }}\n          }}\n        }}\n      \";\n      pgp.AddLemma(str, \"invariants\");\n\n      return specificPathLemmaName;\n    }\n  }\n\n  public class TSOEliminationNonOwnersLackStoreBufferEntriesInvariantInfo : InvariantInfo\n  {\n    private TSOFieldList fields;\n    private string ownershipPredicate;\n\n    public TSOEliminationNonOwnersLackStoreBufferEntriesInvariantInfo(TSOFieldList i_fields, string i_ownershipPredicate)\n      : base(\"NonOwnersLackStoreBufferEntries\", \"NonOwnersLackStoreBufferEntries\", new List<string>{ \"InductiveInv\" }, \"\", false)\n    {\n      fields = i_fields;\n      ownershipPredicate = i_ownershipPredicate;\n    }\n\n    public override string GenerateSpecificNextLemma(ProofGenerationParams pgp, AtomicPath atomicPath,\n                                                     IEnumerable<InvariantInfo> allInvariants, AtomicSpec atomicSpec,\n                                                     bool onlyNonstoppingPaths)\n    {\n      string name = atomicPath.Name;\n      string specificPathLemmaName = $\"lemma_NonOwnersLackStoreBufferEntriesPreservedByPath_{name}\";\n\n      var pr = new PathPrinter(atomicSpec);\n\n      string str = $@\"\n        lemma {specificPathLemmaName}(s: LPlusState, s': LPlusState, path: LAtomic_Path, tid: Armada_ThreadHandle)\n          requires InductiveInv(s)\n          requires LAtomic_NextPath(s, s', path, tid)\n          requires path.LAtomic_Path_{name}?\n          ensures  NonOwnersLackStoreBufferEntries(s')\n        {{\n          { pr.GetOpenValidPathInvocation(atomicPath) }\n          ProofCustomizationGoesHere();\n          forall any_tid, entry{fields.IndexList} |\n            && any_tid in s'.s.threads\n            && !{ownershipPredicate}(s', any_tid{fields.IndexList})\n            && entry in s'.s.threads[any_tid].storeBuffer\n            ensures !StoreBufferLocationConcernsIndices_L(entry.loc{fields.IndexList})\n          {{\n            if any_tid != tid {{\n              assert !{ownershipPredicate}(s, any_tid{fields.IndexList});\n              assert s'.s.threads[any_tid] == s.s.threads[any_tid];\n              assert entry in s.s.threads[any_tid].storeBuffer;\n              assert !StoreBufferLocationConcernsIndices_L(entry.loc{fields.IndexList});\n            }}\n            else {{\n              assert !{ownershipPredicate}(s, tid{fields.IndexList});\n              if entry in s.s.threads[any_tid].storeBuffer {{\n                assert !StoreBufferLocationConcernsIndices_L(entry.loc{fields.IndexList});\n              }}\n            }}\n          }}\n        }}\n      \";\n      pgp.AddLemma(str, \"invariants\");\n\n      return specificPathLemmaName;\n    }\n  }\n\n  public class TSOEliminationProofGenerator : AbstractProofGenerator\n  {\n    private TSOEliminationStrategyDecl strategy;\n    private TSOFieldList fields;\n    private string ownershipPredicate;\n\n    public TSOEliminationProofGenerator(ProofGenerationParams i_pgp, TSOEliminationStrategyDecl i_strategy)\n      : base(i_pgp)\n    {\n      strategy = i_strategy;\n      ownershipPredicate = null;\n    }\n\n    public override void GenerateProof()\n    {\n      if (!CheckEquivalence()) {\n        AH.PrintError(pgp.prog, $\"Levels {pgp.mLow.Name} and {pgp.mHigh.Name} aren't sufficiently equivalent to perform refinement proof generation using the variable-hiding strategy\");\n        return;\n      }\n\n      fields = new TSOFieldList(pgp, strategy);\n      if (!fields.Valid) {\n        return;\n      }\n\n      AddIncludesAndImports();\n      MakeTrivialPCMap();\n      GenerateNextRoutineMap();\n      GenerateProofGivenMap();\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    /// Includes and imports\n    ////////////////////////////////////////////////////////////////////////\n\n    protected override void AddIncludesAndImports()\n    {\n      base.AddIncludesAndImports();\n\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/option.s.dfy\");\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/seqs.s.dfy\");\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/seqs.i.dfy\");\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/sets.i.dfy\");\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/maps.i.dfy\");\n\n      pgp.MainProof.AddImport(\"InvariantsModule\");\n      pgp.MainProof.AddImport(\"util_option_s\");\n      pgp.MainProof.AddImport(\"util_collections_seqs_s\");\n      pgp.MainProof.AddImport(\"util_collections_seqs_i\");\n      pgp.MainProof.AddImport(\"util_collections_sets_i\");\n      pgp.MainProof.AddImport(\"util_collections_maps_i\");\n    }\n\n    private void InitializeAuxiliaryProofFiles()\n    {\n      var tsoutilFile = pgp.proofFiles.CreateAuxiliaryProofFile(\"tsoutil\");\n      tsoutilFile.IncludeAndImportGeneratedFile(\"specs\");\n      tsoutilFile.IncludeAndImportGeneratedFile(\"convert\");\n      tsoutilFile.IncludeAndImportGeneratedFile(\"defs\");\n      tsoutilFile.IncludeAndImportGeneratedFile(\"invariants\");\n      tsoutilFile.AddIncludeImport(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/option.s.dfy\", \"util_option_s\");\n      tsoutilFile.AddIncludeImport(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/maps.i.dfy\", \"util_collections_maps_i\");\n      tsoutilFile.AddIncludeImport(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/seqs.i.dfy\", \"util_collections_seqs_i\");\n      tsoutilFile.AddImport(\"util_collections_seqs_s\");\n      pgp.proofFiles.MainProof.IncludeAndImportGeneratedFile(\"tsoutil\");\n\n      foreach (var atomicPath in lAtomic.AtomicPaths) {\n        var nextFileName = \"next_\" + atomicPath.Name;\n        var nextFile = pgp.proofFiles.CreateAuxiliaryProofFile(nextFileName);\n        nextFile.IncludeAndImportGeneratedFile(\"specs\");\n        nextFile.IncludeAndImportGeneratedFile(\"revelations\");\n        nextFile.IncludeAndImportGeneratedFile(\"convert\");\n        nextFile.IncludeAndImportGeneratedFile(\"invariants\");\n        nextFile.IncludeAndImportGeneratedFile(\"defs\");\n        nextFile.IncludeAndImportGeneratedFile(\"tsoutil\");\n        nextFile.IncludeAndImportGeneratedFile(\"utility\");\n        nextFile.IncludeAndImportGeneratedFile(\"latomic\");\n        nextFile.IncludeAndImportGeneratedFile(\"hatomic\");\n        nextFile.AddIncludeImport(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/option.s.dfy\", \"util_option_s\");\n        nextFile.AddIncludeImport(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/maps.i.dfy\", \"util_collections_maps_i\");\n        nextFile.AddIncludeImport(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/seqs.i.dfy\", \"util_collections_seqs_i\");\n        nextFile.AddImport(\"util_collections_seqs_s\");\n        pgp.proofFiles.MainProof.IncludeAndImportGeneratedFile(nextFileName);\n      }\n    }\n\n    private void GenerateProofGivenMap()\n    {\n      GenerateProofHeader();\n      GenerateAtomicSpecs();\n      GeneratePCFunctions_L();\n      lAtomic.GeneratePCEffectLemmas();\n      InitializeAuxiliaryProofFiles();\n      AddStackMatchesMethodInvariant();\n      GenerateOwnershipPredicate();\n      GenerateStateAbstractionFunctions_LH();\n      GenerateConvertStep_LH();\n      GenerateConvertAtomicPath_LH();\n      GenerateLocalViewCommutativityLemmas();\n      GenerateStrategyInvariants();\n      GenerateInvariantProof(pgp);\n      GenerateGenericStoreBufferLemmas_L();\n      GenerateEmptyStoreBufferLemmas();\n      GenerateValidIndicesLemmas();\n      GenerateUnchangedLemmas();\n      GenerateStoreBufferMatchesLemmas();\n      GenerateStatesMatchExceptPredicates();\n      GenerateLiftingRelation();\n      GenerateIsSkippedTauPath();\n      GenerateRegularPathsLiftableLemma();\n      GenerateRegularPathMaintainsTotalStateMatchesExceptVar();\n      GenerateRegularPathMaintainsGlobalsNoThreadOwnsMatch();\n      GenerateRegularPathMaintainsHighLevelStoreBuffersLackVar();\n      GenerateRegularPathMaintainsOwnersLocalViewsMatch();\n      GenerateRegularPathMaintainsLiftingRelation();\n      GenerateSkippedTauPathMaintainsRelation();\n      GenerateEstablishInitRequirementsLemma();\n      GenerateEstablishStateOKRequirementLemma();\n      GenerateEstablishRelationRequirementLemma();\n      GenerateEstablishAtomicPathLiftableLemma();\n      GenerateEstablishAtomicPathsLiftableLemma(true, false);\n      GenerateLiftLAtomicToHAtomicLemma(true, false);\n      GenerateFinalProof();\n    }\n\n    protected void GenerateStrategyInvariants()\n    {\n      string str;\n\n      str = $@\"\n        predicate NoConflictingOwnership(s: LPlusState)\n        {{\n          s.s.stop_reason.Armada_NotStopped? ==>\n          forall tid1, tid2{fields.IndexList} ::\n            && tid1 in s.s.threads\n            && tid2 in s.s.threads\n            && {ownershipPredicate}(s, tid1{fields.IndexList})\n            && {ownershipPredicate}(s, tid2{fields.IndexList})\n            ==> tid1 == tid2\n        }}\n      \";\n      pgp.AddPredicate(str, \"defs\");\n      AddInvariant(new TSOEliminationNoConflictingOwnershipInvariantInfo(fields, ownershipPredicate));\n\n      str = @\"\n        predicate NonOwnersLackStoreBufferEntries(s: LPlusState)\n        {\n      \";\n      str += $\"  forall tid{fields.IndexList} ::\\n\";\n      str += \"    && tid in s.s.threads\\n\";\n      str += $\"    && !{ownershipPredicate}(s, tid{fields.IndexList})\\n\";\n      str += $\"    ==> StoreBufferLacksIndices_L(s.s.threads[tid].storeBuffer{fields.IndexList})\\n\";\n      str += \"}\\n\";\n      pgp.AddPredicate(str, \"defs\");\n      AddInvariant(new TSOEliminationNonOwnersLackStoreBufferEntriesInvariantInfo(fields, ownershipPredicate));\n    }\n\n    private void GenerateOwnershipPredicate()\n    {\n      var str = $@\"\n        predicate OwnershipPredicate(s:LPlusState, tid:Armada_ThreadHandle{fields.IndexParamList})\n        {{\n          var threads := s.s.threads;\n          var globals := s.s.mem.globals;\n          var ghosts := s.s.ghosts;\n          var tid_init := s.config.tid_init;\n          { strategy.OwnershipPredicate }\n        }}\n      \";\n      pgp.AddPredicate(str, \"defs\");\n      ownershipPredicate = \"OwnershipPredicate\";\n    }\n\n    private void GenerateStatesMatchExceptPredicates()\n    {\n      string str;\n      TSOField f;\n\n      str = @\"\n        predicate StoreBufferLocationConcernsVar_L(loc:L.Armada_StoreBufferLocation)\n        {\n          && loc.Armada_StoreBufferLocation_Unaddressable?\n      \";\n      str += $\"  && loc.v.Armada_GlobalStaticVar_{fields.GetVar()}?\\n\";\n      str += $\"  && |loc.fields| == {fields.NumFields}\\n\";\n      for (int i = 0; i < fields.NumFields; ++i) {\n        f = fields.GetField(i);\n        if (f is StructTSOField sf) {\n          str += $\"  && loc.fields[{i}] == {sf.FieldPos}\\n\";\n        }\n      }\n      str += \"  }\\n\";\n      pgp.AddPredicate(str, \"defs\");\n\n      str = @\"\n        predicate StoreBufferLocationConcernsVar_H(loc:H.Armada_StoreBufferLocation)\n        {\n          && loc.Armada_StoreBufferLocation_Unaddressable?\n      \";\n      str += $\"  && loc.v.Armada_GlobalStaticVar_{fields.GetVar()}?\\n\";\n      str += $\"  && |loc.fields| == {fields.NumFields}\\n\";\n      for (int i = 0; i < fields.NumFields; ++i) {\n        f = fields.GetField(i);\n        if (f is StructTSOField sf) {\n          str += $\"  && loc.fields[{i}] == {sf.FieldPos}\\n\";\n        }\n      }\n      str += \"  }\\n\";\n      pgp.AddPredicate(str, \"defs\");\n\n      str = @\"\n        predicate StoreBufferMatchesExceptVar(lbuf:seq<L.Armada_StoreBufferEntry>, hbuf:seq<H.Armada_StoreBufferEntry>)\n        {\n          if |lbuf| == 0 then\n            |hbuf| == 0\n          else if StoreBufferLocationConcernsVar_L(lbuf[0].loc) then\n            StoreBufferMatchesExceptVar(lbuf[1..], hbuf)\n          else\n            && |hbuf| > 0\n            && hbuf[0] == ConvertStoreBufferEntry_LH(lbuf[0])\n            && StoreBufferMatchesExceptVar(lbuf[1..], hbuf[1..])\n        }\n      \";\n      pgp.AddPredicate(str, \"defs\");\n\n      var preds = new List<string>();\n      foreach (var varName in pgp.symbolsLow.Globals.VariableNames) {\n        var v = pgp.symbolsLow.Globals.Lookup(varName);\n        if (v is GlobalUnaddressableArmadaVariable && varName != fields.GetVar()) {\n          preds.Add($\"hglobals.{varName} == lglobals.{varName}\");\n        }\n      }\n\n      var indices = new List<string>();\n      var indexConstraints = new List<string>();\n      for (int i = 0; i < fields.NumFields; ++i) {\n        f = fields.GetField(i);\n\n        if (f is StructTSOField sf) {\n          foreach (var otherFieldName in sf.OuterStruct.FieldNames) {\n            if (otherFieldName != sf.FieldName) {\n              if (indices.Any()) {\n                preds.Add($@\"\n                  forall {AH.CombineStringsWithCommas(indices)} ::\n                    {AH.CombineStringsWithAnd(indexConstraints)} ==>\n                    hglobals{f.EnclosingFieldSpec}.{otherFieldName} == lglobals{f.EnclosingFieldSpec}.{otherFieldName}\n                \");\n              }\n              else {\n                preds.Add($\"hglobals{f.EnclosingFieldSpec}.{otherFieldName} == lglobals{f.EnclosingFieldSpec}.{otherFieldName}\");\n              }\n            }\n          }\n        }\n        else if (f is ArrayTSOField af) {\n          if (indices.Any()) {\n            preds.Add($@\"\n              forall {AH.CombineStringsWithCommas(indices)} ::\n                {AH.CombineStringsWithAnd(indexConstraints)} ==>\n                |hglobals{f.EnclosingFieldSpec}| == |lglobals{f.EnclosingFieldSpec}|\n            \");\n          }\n          else {\n            preds.Add($\"|hglobals{f.EnclosingFieldSpec}| == |lglobals{f.EnclosingFieldSpec}|\");\n          }\n          indices.Add($\"idx{af.WhichArray}\");\n          indexConstraints.Add($\"0 <= idx{af.WhichArray} < |lglobals{f.EnclosingFieldSpec}|\");\n        }\n      }\n\n      str = $@\"\n        predicate GlobalsMatchesExceptVar(lglobals: L.Armada_Globals, hglobals: H.Armada_Globals)\n        {{\n          {AH.CombineStringsWithAnd(preds)}\n        }}\n      \";\n      pgp.AddPredicate(str, \"defs\");\n\n      str = @\"\n        predicate SharedMemoryMatchesExceptVar(lmem: L.Armada_SharedMemory, hmem: H.Armada_SharedMemory)\n        {\n          && GlobalsMatchesExceptVar(lmem.globals, hmem.globals)\n          && hmem.heap == lmem.heap\n        }\n      \";\n      pgp.AddPredicate(str, \"defs\");\n\n      str = @\"\n        lemma lemma_GlobalsMatchExceptVarPreservedByApplyingStoreBufferEntryThatDoesntConcernVar_L(\n          lmem: L.Armada_SharedMemory,\n          hmem: H.Armada_SharedMemory,\n          lentry: L.Armada_StoreBufferEntry\n          )\n          requires SharedMemoryMatchesExceptVar(lmem, hmem)\n          requires StoreBufferLocationConcernsVar_L(lentry.loc)\n          ensures  SharedMemoryMatchesExceptVar(L.Armada_ApplyStoreBufferEntry(lmem, lentry), hmem)\n        {\n        }\n      \";\n      pgp.AddLemma(str, \"invariants\");\n\n      str = @\"\n        lemma lemma_GlobalsMatchExceptVarPreservedByApplyingStoreBufferEntryThatDoesntConcernVar_H(\n          lmem: L.Armada_SharedMemory,\n          hmem: H.Armada_SharedMemory,\n          hentry: H.Armada_StoreBufferEntry\n          )\n          requires SharedMemoryMatchesExceptVar(lmem, hmem)\n          requires StoreBufferLocationConcernsVar_H(hentry.loc)\n          ensures  SharedMemoryMatchesExceptVar(lmem, H.Armada_ApplyStoreBufferEntry(hmem, hentry))\n        {\n        }\n      \";\n      pgp.AddLemma(str, \"invariants\");\n\n      str = @\"\n        lemma lemma_GlobalsMatchExceptVarPreservedByApplyingMatchingStoreBufferEntries(\n          lmem: L.Armada_SharedMemory,\n          hmem: H.Armada_SharedMemory,\n          lentry: L.Armada_StoreBufferEntry,\n          hentry: H.Armada_StoreBufferEntry\n          )\n          requires SharedMemoryMatchesExceptVar(lmem, hmem)\n          requires hentry == ConvertStoreBufferEntry_LH(lentry)\n          ensures  SharedMemoryMatchesExceptVar(L.Armada_ApplyStoreBufferEntry(lmem, lentry), H.Armada_ApplyStoreBufferEntry(hmem, hentry))\n        {\n        }\n      \";\n      pgp.AddLemma(str, \"invariants\");\n\n      str = @\"\n        lemma lemma_GlobalsMatchExceptVarImpliesLocalViewGlobalsMatchExceptVar(\n          lmem: L.Armada_SharedMemory,\n          hmem: H.Armada_SharedMemory,\n          lbuf: seq<L.Armada_StoreBufferEntry>,\n          hbuf: seq<H.Armada_StoreBufferEntry>\n          )\n          requires SharedMemoryMatchesExceptVar(lmem, hmem)\n          requires StoreBufferMatchesExceptVar(lbuf, hbuf)\n          ensures  SharedMemoryMatchesExceptVar(L.Armada_ApplyStoreBuffer(lmem, lbuf), H.Armada_ApplyStoreBuffer(hmem, hbuf))\n          decreases |lbuf| + |hbuf|\n        {\n          var llocv := L.Armada_ApplyStoreBuffer(lmem, lbuf);\n          var hlocv := H.Armada_ApplyStoreBuffer(hmem, hbuf);\n      \n          if |lbuf| == 0 {\n          }\n          else if StoreBufferLocationConcernsVar_L(lbuf[0].loc) {\n            lemma_GlobalsMatchExceptVarPreservedByApplyingStoreBufferEntryThatDoesntConcernVar_L(lmem, hmem, lbuf[0]);\n            lemma_GlobalsMatchExceptVarImpliesLocalViewGlobalsMatchExceptVar(L.Armada_ApplyStoreBufferEntry(lmem, lbuf[0]), hmem, lbuf[1..], hbuf);\n          } else {\n            lemma_GlobalsMatchExceptVarPreservedByApplyingMatchingStoreBufferEntries(lmem, hmem, lbuf[0], hbuf[0]);\n            lemma_GlobalsMatchExceptVarImpliesLocalViewGlobalsMatchExceptVar(L.Armada_ApplyStoreBufferEntry(lmem, lbuf[0]), H.Armada_ApplyStoreBufferEntry(hmem, hbuf[0]), lbuf[1..], hbuf[1..]);\n          }\n        }\n      \";\n      pgp.AddLemma(str, \"invariants\");\n\n      str = @\"\n        lemma lemma_GlobalsMatchExceptVarImpliesLocalViewGlobalsMatchExceptVarAlways()\n          ensures forall lmem, hmem, lbuf, hbuf ::\n                    SharedMemoryMatchesExceptVar(lmem, hmem) && StoreBufferMatchesExceptVar(lbuf, hbuf) ==>\n                    SharedMemoryMatchesExceptVar(L.Armada_ApplyStoreBuffer(lmem, lbuf), H.Armada_ApplyStoreBuffer(hmem, hbuf))\n        {\n          forall lmem, hmem, lbuf, hbuf | SharedMemoryMatchesExceptVar(lmem, hmem) && StoreBufferMatchesExceptVar(lbuf, hbuf)\n            ensures SharedMemoryMatchesExceptVar(L.Armada_ApplyStoreBuffer(lmem, lbuf), H.Armada_ApplyStoreBuffer(hmem, hbuf))\n          {\n            lemma_GlobalsMatchExceptVarImpliesLocalViewGlobalsMatchExceptVar(lmem, hmem, lbuf, hbuf);\n          }\n        }\n      \";\n      pgp.AddLemma(str, \"invariants\");\n\n      str = @\"\n        predicate ExtendedFrameMatchesExceptVar(lframe:L.Armada_ExtendedFrame, hframe:H.Armada_ExtendedFrame)\n        {\n          && hframe.return_pc == ConvertPC_LH(lframe.return_pc)\n          && hframe.frame == ConvertStackFrame_LH(lframe.frame)\n          && hframe.new_ptrs == lframe.new_ptrs\n        }\n      \";\n      pgp.AddPredicate(str, \"defs\");\n\n      str = @\"\n        predicate StackMatchesExceptVar(lstack:seq<L.Armada_ExtendedFrame>, hstack:seq<H.Armada_ExtendedFrame>)\n        {\n          && |hstack| == |lstack|\n          && (forall i :: 0 <= i < |lstack| ==> ExtendedFrameMatchesExceptVar(lstack[i], hstack[i]))\n        }\n      \";\n      pgp.AddPredicate(str, \"defs\");\n\n      str = @\"\n        predicate ThreadMatchesExceptVar(lthread:L.Armada_Thread, hthread:H.Armada_Thread)\n        {\n          && hthread.pc == ConvertPC_LH(lthread.pc)\n          && hthread.top == ConvertStackFrame_LH(lthread.top)\n          && hthread.new_ptrs == lthread.new_ptrs\n          && StackMatchesExceptVar(lthread.stack, hthread.stack)\n          && StoreBufferMatchesExceptVar(lthread.storeBuffer, hthread.storeBuffer)\n        }\n      \";\n      pgp.AddPredicate(str, \"defs\");\n\n      str = @\"\n        predicate ThreadsMatchesExceptVar(lthreads:map<Armada_ThreadHandle, L.Armada_Thread>,\n                                          hthreads:map<Armada_ThreadHandle, H.Armada_Thread>)\n        {\n          && (forall tid :: tid in lthreads <==> tid in hthreads)\n          && (forall tid :: tid in lthreads ==> ThreadMatchesExceptVar(lthreads[tid], hthreads[tid]))\n        }\n      \";\n      pgp.AddPredicate(str, \"defs\");\n\n      str = @\"\n        predicate TotalStateMatchesExceptVar(ls:LState, hs:HState)\n        {\n          && hs.stop_reason == ls.stop_reason\n          && ThreadsMatchesExceptVar(ls.threads, hs.threads)\n          && SharedMemoryMatchesExceptVar(ls.mem, hs.mem)\n          && hs.addrs == ConvertAddrs_LH(ls.addrs)\n          && hs.ghosts == ConvertGhosts_LH(ls.ghosts)\n          && hs.joinable_tids == ls.joinable_tids\n        }\n      \";\n      pgp.AddPredicate(str, \"defs\");\n\n      str = @\"\n        predicate LocalViewsMatchExceptVar(ls:LState, hs:HState)\n        {\n          forall any_tid :: any_tid in ls.threads && any_tid in hs.threads ==>\n            SharedMemoryMatchesExceptVar(L.Armada_GetThreadLocalView(ls, any_tid), H.Armada_GetThreadLocalView(hs, any_tid))\n        }\n      \";\n      pgp.AddPredicate(str, \"defs\");\n    }\n\n    private void GenerateIsSkippedTauPath()\n    {\n      string str = @\"\n        predicate IsSkippedTauPath(ls: LPlusState, hs: HState, path: LAtomic_Path, tid: Armada_ThreadHandle)\n        {\n          && path.LAtomic_Path_Tau?\n          && tid in ls.s.threads\n          && |ls.s.threads[tid].storeBuffer| > 0\n          && StoreBufferLocationConcernsVar_L(ls.s.threads[tid].storeBuffer[0].loc)\n          && !(&& tid in hs.threads\n               && |hs.threads[tid].storeBuffer| > 0\n               && hs.threads[tid].storeBuffer[0] == ConvertStoreBufferEntry_LH(ls.s.threads[tid].storeBuffer[0])\n               && StoreBufferMatchesExceptVar(ls.s.threads[tid].storeBuffer[1..], hs.threads[tid].storeBuffer[1..]))\n        }\n      \";\n      pgp.AddPredicate(str, \"defs\");\n    }\n\n    protected override void GenerateLiftingRelation()\n    {\n      string str;\n\n      str = $@\"\n        predicate NoThreadOwns(s: LPlusState{fields.IndexParamList})\n        {{\n          forall tid :: tid in s.s.threads ==> !{ownershipPredicate}(s, tid{fields.IndexList})\n        }}\n      \";\n      pgp.AddPredicate(str, \"defs\");\n\n      str = $@\"\n        predicate ValidIndices_L(g:L.Armada_Globals{fields.IndexParamList})\n        {{\n          {AH.CombineStringsWithAnd(fields.IndexConstraints)}\n        }}\n      \";\n      str += \"{\\n\";\n      pgp.AddPredicate(str, \"defs\");\n\n      str = $@\"\n        predicate ValidIndices_H(g:H.Armada_Globals{fields.IndexParamList})\n        {{\n          {AH.CombineStringsWithAnd(fields.IndexConstraints)}\n        }}\n      \";\n      pgp.AddPredicate(str, \"defs\");\n\n      var preds = new List<string>() { \"StoreBufferLocationConcernsVar_L(loc)\" };\n      for (int i = 0; i < fields.NumFields; ++i) {\n        if (fields.GetField(i) is ArrayTSOField af) {\n          preds.Add($\"loc.fields[{i}] == idx{af.WhichArray}\");\n        }\n      }\n      str = $@\"\n        predicate StoreBufferLocationConcernsIndices_L(loc:L.Armada_StoreBufferLocation{fields.IndexParamList})\n        {{\n          {AH.CombineStringsWithAnd(preds)}\n        }}\n      \";\n      pgp.AddPredicate(str, \"defs\");\n\n      str = $@\"\n        predicate StoreBufferLacksIndices_L(buf: seq<L.Armada_StoreBufferEntry>{fields.IndexParamList})\n        {{\n          forall entry :: entry in buf ==> !StoreBufferLocationConcernsIndices_L(entry.loc{fields.IndexList})\n        }}\n      \";\n      pgp.AddPredicate(str, \"defs\");\n\n      str = @\"\n        predicate StoreBufferLacksVar_H(buf: seq<H.Armada_StoreBufferEntry>)\n        {\n          forall entry :: entry in buf ==> !StoreBufferLocationConcernsVar_H(entry.loc)\n        }\n      \";\n      pgp.AddPredicate(str, \"defs\");\n\n      str = $@\"\n        predicate GlobalsNoThreadOwnsMatchSpecific(ls: LPlusState, hs: HState{fields.IndexParamList})\n        {{\n          var lg, hg := ls.s.mem.globals, hs.mem.globals;\n          && NoThreadOwns(ls{fields.IndexList})\n          && ValidIndices_L(lg{fields.IndexList})\n          && ValidIndices_H(hg{fields.IndexList})\n          ==> hg{fields.FieldSpec} == lg{fields.FieldSpec}\n        }}\n      \";\n      str += \"}\\n\";\n      \n      pgp.AddPredicate(str, \"defs\");\n\n      str = @\"\n        predicate GlobalsNoThreadOwnsMatch(ls: LPlusState, hs: HState)\n        {\n      \";\n      if (fields.NumArrays > 0) {\n        str += $\"  forall {fields.IndexListWithoutLeadingComma} :: \";\n      }\n      str += $\"  GlobalsNoThreadOwnsMatchSpecific(ls, hs{fields.IndexList})\";\n      str += \"}\\n\";\n      \n      pgp.AddPredicate(str, \"defs\");\n\n      str = @\"\n        predicate HighLevelStoreBuffersLackVar(hs: HState)\n        {\n          forall tid :: tid in hs.threads ==> StoreBufferLacksVar_H(hs.threads[tid].storeBuffer)\n        }\n      \";\n      pgp.AddPredicate(str, \"defs\");\n\n      str = $@\"\n        predicate LocalViewsMatchSpecific(ls: LState, hs: HState, tid:Armada_ThreadHandle{fields.IndexParamList})\n          requires tid in ls.threads\n          requires tid in hs.threads\n        {{\n          var lg := L.Armada_GetThreadLocalView(ls, tid).globals;\n          var hg := H.Armada_GetThreadLocalView(hs, tid).globals;\n          && ValidIndices_L(lg{fields.IndexList})\n          && ValidIndices_H(hg{fields.IndexList})\n          ==> lg{fields.FieldSpec} == hg{fields.FieldSpec}\n        }}\n      \";\n      pgp.AddPredicate(str, \"defs\");\n\n      str = @\"\n        predicate OwnersLocalViewsMatch(ls: LPlusState, hs: HState)\n        {\n      \";\n      str += $\"  forall tid{fields.IndexList} ::\\n\";\n      str += $\"    tid in ls.s.threads && tid in hs.threads && {ownershipPredicate}(ls, tid{fields.IndexList}) ==> LocalViewsMatchSpecific(ls.s, hs, tid{fields.IndexList})\\n\";\n      str += \"}\\n\";\n      pgp.AddPredicate(str, \"defs\");\n\n      str = @\"\n        predicate LiftingRelation(ls: LPlusState, hs: HState)\n        {\n          && TotalStateMatchesExceptVar(ls.s, hs)\n          && (ls.s.stop_reason.Armada_NotStopped? ==>\n                && GlobalsNoThreadOwnsMatch(ls, hs)\n                && HighLevelStoreBuffersLackVar(hs)\n                && OwnersLocalViewsMatch(ls, hs)\n             )\n        }\n      \";\n      pgp.AddPredicate(str, \"defs\");\n    }\n\n    protected override void GenerateEstablishInitRequirementsLemma()\n    {\n      GenerateLemmasHelpfulForProvingInitPreservation_LH();\n\n      string str;\n\n      str = $@\"\n        lemma lemma_InitImpliesLiftingRelation(ls: LPlusState, hs: HState)\n          requires LPlus_Init(ls)\n          requires hs == ConvertTotalState_LPlusH(ls)\n          ensures  LiftingRelation(ls, hs)\n        {{\n          assert TotalStateMatchesExceptVar(ls.s, hs);\n          forall tid{fields.IndexList} | tid in ls.s.threads\n              ensures !{ownershipPredicate}(ls, tid{fields.IndexList})\n          {{\n          }}\n          assert GlobalsNoThreadOwnsMatch(ls, hs);\n          assert OwnersLocalViewsMatch(ls, hs);\n        }}\n      \";\n      pgp.AddLemma(str);\n\n      str = @\"\n        lemma lemma_EstablishInitRequirements(\n          lasf:AtomicSpecFunctions<LPlusState, LAtomic_Path, L.Armada_PC>,\n          hasf:AtomicSpecFunctions<HState, HAtomic_Path, H.Armada_PC>,\n          inv:LPlusState->bool,\n          relation:(LPlusState, HState)->bool\n          )\n          requires lasf == LAtomic_GetSpecFunctions()\n          requires hasf == HAtomic_GetSpecFunctions()\n          requires inv == InductiveInv\n          requires relation == LiftingRelation\n          ensures  AtomicInitImpliesInv(lasf, inv)\n          ensures  forall ls :: lasf.init(ls) ==> exists hs :: hasf.init(hs) && relation(ls, hs)\n        {\n          forall ls | lasf.init(ls)\n            ensures inv(ls)\n            ensures exists hs :: hasf.init(hs) && relation(ls, hs)\n          {\n            lemma_InitImpliesInductiveInv(ls);\n            var hs := ConvertTotalState_LPlusH(ls);\n            var hconfig := ConvertConfig_LH(ls.config);\n            assert H.Armada_InitConfig(hs, hconfig);\n            lemma_InitImpliesLiftingRelation(ls, hs);\n            assert hasf.init(hs) && relation(ls, hs);\n          }\n        }\n      \";\n      pgp.AddLemma(str);\n    }\n\n    private void GenerateEmptyStoreBufferLemmas()\n    {\n      string str;\n\n      str = $@\"\n        lemma lemma_IfStoreBufferLacksIndicesThenViewMatches_L(mem: L.Armada_SharedMemory, buf: seq<L.Armada_StoreBufferEntry>, mem': L.Armada_SharedMemory{fields.IndexParamList})\n          requires StoreBufferLacksIndices_L(buf{fields.IndexList})\n          requires ValidIndices_L(L.Armada_ApplyStoreBuffer(mem, buf).globals{fields.IndexList})\n          requires ValidIndices_L(mem.globals{fields.IndexList})\n          requires mem' == L.Armada_ApplyStoreBuffer(mem, buf)\n          ensures  mem'.globals{fields.FieldSpec} == mem.globals{fields.FieldSpec}\n          decreases |buf|\n        {{\n          if |buf| > 0 {{\n            var mem_next := L.Armada_ApplyStoreBufferEntry(mem, buf[0]);\n            assert mem_next.globals{fields.FieldSpec} == mem.globals{fields.FieldSpec};\n            var mem_next' := L.Armada_ApplyStoreBuffer(mem_next, buf[1..]);\n            lemma_IfStoreBufferLacksIndicesThenViewMatches_L(mem_next, buf[1..], mem_next'{fields.IndexList});\n          }}\n        }}\n      \";\n      pgp.AddLemma(str, \"tsoutil\");\n\n      str = $@\"\n        lemma lemma_IfStoreBufferLacksIndicesThenViewMatchesAlways_L({fields.IndexParamListWithoutLeadingComma})\n          ensures forall mem:L.Armada_SharedMemory, buf:seq<L.Armada_StoreBufferEntry> ::\n                    && StoreBufferLacksIndices_L(buf{fields.IndexList})\n                    && ValidIndices_L(L.Armada_ApplyStoreBuffer(mem, buf).globals{fields.IndexList})\n                    && ValidIndices_L(mem.globals{fields.IndexList})\n                    ==> L.Armada_ApplyStoreBuffer(mem, buf).globals{fields.FieldSpec} == mem.globals{fields.FieldSpec}\n        {{\n          forall mem:L.Armada_SharedMemory, buf:seq<L.Armada_StoreBufferEntry> |\n            && StoreBufferLacksIndices_L(buf{fields.IndexList})\n            && ValidIndices_L(L.Armada_ApplyStoreBuffer(mem, buf).globals{fields.IndexList})\n            && ValidIndices_L(mem.globals{fields.IndexList})\n            ensures L.Armada_ApplyStoreBuffer(mem, buf).globals{fields.FieldSpec} == mem.globals{fields.FieldSpec}\n          {{\n            var mem' := L.Armada_ApplyStoreBuffer(mem, buf);\n            lemma_IfStoreBufferLacksIndicesThenViewMatches_L(mem, buf, mem'{fields.IndexList});\n          }}\n        }}\n      \";\n      pgp.AddLemma(str, \"tsoutil\");\n\n      str = $@\"\n        lemma lemma_IfStoreBufferLacksIndicesThenViewMatches_H(mem: H.Armada_SharedMemory, buf: seq<H.Armada_StoreBufferEntry>, mem': H.Armada_SharedMemory{fields.IndexParamList})\n          requires StoreBufferLacksVar_H(buf)\n          requires ValidIndices_H(H.Armada_ApplyStoreBuffer(mem, buf).globals{fields.IndexList})\n          requires ValidIndices_H(mem.globals{fields.IndexList})\n          requires mem' == H.Armada_ApplyStoreBuffer(mem, buf)\n          ensures  mem'.globals{fields.FieldSpec} == mem.globals{fields.FieldSpec}\n          decreases |buf|\n        {{\n          if |buf| > 0 {{\n            var mem_next := H.Armada_ApplyStoreBufferEntry(mem, buf[0]);\n            assert mem_next.globals{fields.FieldSpec} == mem.globals{fields.FieldSpec};\n            var mem_next' := H.Armada_ApplyStoreBuffer(mem_next, buf[1..]);\n            lemma_IfStoreBufferLacksIndicesThenViewMatches_H(mem_next, buf[1..], mem_next'{fields.IndexList});\n          }}\n        }}\n      \";\n      pgp.AddLemma(str, \"tsoutil\");\n\n      str = $@\"\n        lemma lemma_IfStoreBufferLacksIndicesThenViewMatchesAlways_H({fields.IndexParamListWithoutLeadingComma})\n          ensures forall mem:H.Armada_SharedMemory, buf:seq<H.Armada_StoreBufferEntry> ::\n                    && StoreBufferLacksVar_H(buf)\n                    && ValidIndices_H(H.Armada_ApplyStoreBuffer(mem, buf).globals{fields.IndexList})\n                    && ValidIndices_H(mem.globals{fields.IndexList})\n                    ==> H.Armada_ApplyStoreBuffer(mem, buf).globals{fields.FieldSpec} == mem.globals{fields.FieldSpec}\n        {{\n          forall mem:H.Armada_SharedMemory, buf:seq<H.Armada_StoreBufferEntry> |\n            && StoreBufferLacksVar_H(buf)\n            && ValidIndices_H(H.Armada_ApplyStoreBuffer(mem, buf).globals{fields.IndexList})\n            && ValidIndices_H(mem.globals{fields.IndexList})\n            ensures H.Armada_ApplyStoreBuffer(mem, buf).globals{fields.FieldSpec} == mem.globals{fields.FieldSpec}\n          {{\n            var mem' := H.Armada_ApplyStoreBuffer(mem, buf);\n            lemma_IfStoreBufferLacksIndicesThenViewMatches_H(mem, buf, mem'{fields.IndexList});\n          }}\n        }}\n      \";\n      pgp.AddLemma(str, \"tsoutil\");\n    }\n\n    private void GenerateValidIndicesLemmas()\n    {\n      string str;\n\n      str = $@\"\n        lemma lemma_ValidIndicesUnaffectedByApplyStoreBuffer_L(\n          mem: L.Armada_SharedMemory,\n          buf:seq<L.Armada_StoreBufferEntry>,\n          mem': L.Armada_SharedMemory{fields.IndexParamList}\n          )\n          requires mem' == L.Armada_ApplyStoreBuffer(mem, buf)\n          ensures  ValidIndices_L(mem.globals{fields.IndexList}) <==> ValidIndices_L(mem'.globals{fields.IndexList})\n          decreases |buf|\n        {{\n          if |buf| > 0 {{\n            var mem_next := L.Armada_ApplyStoreBufferEntry(mem, buf[0]);\n            lemma_ValidIndicesUnaffectedByApplyStoreBuffer_L(mem_next, buf[1..], mem'{fields.IndexList});\n          }}\n        }}\n      \";\n      pgp.AddLemma(str, \"tsoutil\");\n\n      str = $@\"\n        lemma lemma_ValidIndicesUnaffectedByApplyStoreBufferAlways_L({fields.IndexParamListWithoutLeadingComma})\n          ensures forall mem:L.Armada_SharedMemory, buf:seq<L.Armada_StoreBufferEntry>\n                    {{:trigger L.Armada_ApplyStoreBuffer(mem, buf), ValidIndices_L(mem.globals{fields.IndexList})}}\n                    {{:trigger ValidIndices_L(L.Armada_ApplyStoreBuffer(mem, buf).globals{fields.IndexList})}} ::\n                    var mem' := L.Armada_ApplyStoreBuffer(mem, buf);\n                    ValidIndices_L(mem.globals{fields.IndexList}) <==> ValidIndices_L(mem'.globals{fields.IndexList});\n        {{\n          forall mem:L.Armada_SharedMemory, buf:seq<L.Armada_StoreBufferEntry>\n            {{:trigger L.Armada_ApplyStoreBuffer(mem, buf), ValidIndices_L(mem.globals{fields.IndexList})}}\n            {{:trigger ValidIndices_L(L.Armada_ApplyStoreBuffer(mem, buf).globals{fields.IndexList})}}\n            ensures var mem' := L.Armada_ApplyStoreBuffer(mem, buf);\n                    ValidIndices_L(mem.globals{fields.IndexList}) <==> ValidIndices_L(mem'.globals{fields.IndexList});\n          {{\n            var mem' := L.Armada_ApplyStoreBuffer(mem, buf);\n            lemma_ValidIndicesUnaffectedByApplyStoreBuffer_L(mem, buf, mem'{fields.IndexList});\n          }}\n        }}\n      \";\n      pgp.AddLemma(str, \"tsoutil\");\n\n      str = $@\"\n        lemma lemma_ValidIndicesUnaffectedByApplyStoreBuffer_H(\n          mem: H.Armada_SharedMemory,\n          buf:seq<H.Armada_StoreBufferEntry>,\n          mem': H.Armada_SharedMemory{fields.IndexParamList}\n          )\n          requires mem' == H.Armada_ApplyStoreBuffer(mem, buf)\n          ensures  ValidIndices_H(mem.globals{fields.IndexList}) <==> ValidIndices_H(mem'.globals{fields.IndexList})\n          decreases |buf|\n        {{\n          if |buf| > 0 {{\n            var mem_next := H.Armada_ApplyStoreBufferEntry(mem, buf[0]);\n            lemma_ValidIndicesUnaffectedByApplyStoreBuffer_H(mem_next, buf[1..], mem'{fields.IndexList});\n          }}\n        }}\n      \";\n      pgp.AddLemma(str, \"tsoutil\");\n\n      str = $@\"\n        lemma lemma_ValidIndicesUnaffectedByApplyStoreBufferAlways_H({fields.IndexParamListWithoutLeadingComma})\n          ensures forall mem:H.Armada_SharedMemory, buf:seq<H.Armada_StoreBufferEntry>\n                    {{:trigger H.Armada_ApplyStoreBuffer(mem, buf), ValidIndices_H(mem.globals{fields.IndexList})}}\n                    {{:trigger ValidIndices_H(H.Armada_ApplyStoreBuffer(mem, buf).globals{fields.IndexList})}} ::\n                    var mem' := H.Armada_ApplyStoreBuffer(mem, buf);\n                    ValidIndices_H(mem.globals{fields.IndexList}) <==> ValidIndices_H(mem'.globals{fields.IndexList});\n        {{\n          forall mem:H.Armada_SharedMemory, buf:seq<H.Armada_StoreBufferEntry>\n            {{:trigger H.Armada_ApplyStoreBuffer(mem, buf), ValidIndices_H(mem.globals{fields.IndexList})}}\n            {{:trigger ValidIndices_H(H.Armada_ApplyStoreBuffer(mem, buf).globals{fields.IndexList})}}\n            ensures var mem' := H.Armada_ApplyStoreBuffer(mem, buf);\n                    ValidIndices_H(mem.globals{fields.IndexList}) <==> ValidIndices_H(mem'.globals{fields.IndexList});\n          {{\n            var mem' := H.Armada_ApplyStoreBuffer(mem, buf);\n            lemma_ValidIndicesUnaffectedByApplyStoreBuffer_H(mem, buf, mem'{fields.IndexList});\n          }}\n        }}\n      \";\n      pgp.AddLemma(str, \"tsoutil\");\n    }\n\n    private void GenerateUnchangedLemmas()\n    {\n      string str;\n\n      str = $@\"\n        lemma lemma_IfVarUnchangedAndStoreBufferUnchangedThenViewUnchanged_L(\n          mem1:L.Armada_SharedMemory, mem2: L.Armada_SharedMemory, buf: seq<L.Armada_StoreBufferEntry>{fields.IndexParamList}\n          )\n          requires ValidIndices_L(mem1.globals{fields.IndexList})\n          requires ValidIndices_L(mem2.globals{fields.IndexList})\n          requires ValidIndices_L(L.Armada_ApplyStoreBuffer(mem1, buf).globals{fields.IndexList})\n          requires ValidIndices_L(L.Armada_ApplyStoreBuffer(mem2, buf).globals{fields.IndexList})\n          requires mem1.globals{fields.FieldSpec} == mem2.globals{fields.FieldSpec}\n          ensures  L.Armada_ApplyStoreBuffer(mem1, buf).globals{fields.FieldSpec} == L.Armada_ApplyStoreBuffer(mem2, buf).globals{fields.FieldSpec}\n          decreases |buf|\n        {{\n          if |buf| > 0 {{\n            var mem1' := L.Armada_ApplyStoreBufferEntry(mem1, buf[0]);\n            var mem2' := L.Armada_ApplyStoreBufferEntry(mem2, buf[0]);\n            lemma_IfVarUnchangedAndStoreBufferUnchangedThenViewUnchanged_L(mem1', mem2', buf[1..]{fields.IndexList});\n          }}\n        }}\n      \";\n      pgp.AddLemma(str, \"tsoutil\");\n\n      str = $@\"\n        lemma lemma_IfVarUnchangedAndStoreBufferUnchangedThenViewUnchangedAlways_L({fields.IndexParamListWithoutLeadingComma})\n          ensures forall mem1:L.Armada_SharedMemory, mem2: L.Armada_SharedMemory, buf: seq<L.Armada_StoreBufferEntry>\n                    {{:trigger L.Armada_ApplyStoreBuffer(mem1, buf), L.Armada_ApplyStoreBuffer(mem2, buf)}} ::\n                    && ValidIndices_L(mem1.globals{fields.IndexList})\n                    && ValidIndices_L(mem2.globals{fields.IndexList})\n                    && ValidIndices_L(L.Armada_ApplyStoreBuffer(mem1, buf).globals{fields.IndexList})\n                    && ValidIndices_L(L.Armada_ApplyStoreBuffer(mem2, buf).globals{fields.IndexList})\n                    && mem1.globals{fields.FieldSpec} == mem2.globals{fields.FieldSpec}\n                    ==> L.Armada_ApplyStoreBuffer(mem1, buf).globals{fields.FieldSpec} == L.Armada_ApplyStoreBuffer(mem2, buf).globals{fields.FieldSpec}\n        {{\n          forall mem1:L.Armada_SharedMemory, mem2: L.Armada_SharedMemory, buf: seq<L.Armada_StoreBufferEntry>\n            {{:trigger L.Armada_ApplyStoreBuffer(mem1, buf), L.Armada_ApplyStoreBuffer(mem2, buf)}} |\n            && ValidIndices_L(mem1.globals{fields.IndexList})\n            && ValidIndices_L(mem2.globals{fields.IndexList})\n            && ValidIndices_L(L.Armada_ApplyStoreBuffer(mem1, buf).globals{fields.IndexList})\n            && ValidIndices_L(L.Armada_ApplyStoreBuffer(mem2, buf).globals{fields.IndexList})\n            && mem1.globals{fields.FieldSpec} == mem2.globals{fields.FieldSpec}\n            ensures L.Armada_ApplyStoreBuffer(mem1, buf).globals{fields.FieldSpec} == L.Armada_ApplyStoreBuffer(mem2, buf).globals{fields.FieldSpec}\n          {{\n            lemma_IfVarUnchangedAndStoreBufferUnchangedThenViewUnchanged_L(mem1, mem2, buf{fields.IndexList});\n          }}\n        }}\n      \";\n      pgp.AddLemma(str, \"tsoutil\");\n    }\n\n    private void GenerateStoreBufferMatchesLemmas()\n    {\n      string str;\n\n      str = @\"\n        lemma lemma_AppendVarToStoreBufferDoesntAffectMatch(\n          lbuf: seq<L.Armada_StoreBufferEntry>,\n          hbuf: seq<H.Armada_StoreBufferEntry>,\n          entry: L.Armada_StoreBufferEntry\n          )\n          requires StoreBufferLocationConcernsVar_L(entry.loc)\n          requires StoreBufferMatchesExceptVar(lbuf, hbuf)\n          ensures StoreBufferMatchesExceptVar(lbuf + [entry], hbuf);\n        {\n          assert |lbuf| > 0 ==> lbuf + [entry] == [lbuf[0]] + (lbuf[1..] + [entry]);\n      \n          if |lbuf| == 0 {\n          }\n          else if StoreBufferLocationConcernsVar_L(lbuf[0].loc) {\n            lemma_AppendVarToStoreBufferDoesntAffectMatch(lbuf[1..], hbuf, entry);\n          }\n          else {\n            lemma_AppendVarToStoreBufferDoesntAffectMatch(lbuf[1..], hbuf[1..], entry);\n          }\n        }\n      \";\n      pgp.AddLemma(str, \"tsoutil\");\n\n      str = @\"\n        lemma lemma_AppendVarToStoreBufferDoesntAffectMatchAlways()\n          ensures forall lbuf: seq<L.Armada_StoreBufferEntry>, hbuf: seq<H.Armada_StoreBufferEntry>, entry: L.Armada_StoreBufferEntry\n                  {:trigger StoreBufferMatchesExceptVar(lbuf, hbuf), L.Armada_StoreBufferAppend(lbuf, entry)} ::\n                  && StoreBufferLocationConcernsVar_L(entry.loc)\n                  && StoreBufferMatchesExceptVar(lbuf, hbuf)\n                  ==> StoreBufferMatchesExceptVar(L.Armada_StoreBufferAppend(lbuf, entry), hbuf)\n        {\n          forall lbuf: seq<L.Armada_StoreBufferEntry>, hbuf: seq<H.Armada_StoreBufferEntry>, entry: L.Armada_StoreBufferEntry\n            {:trigger StoreBufferMatchesExceptVar(lbuf, hbuf), L.Armada_StoreBufferAppend(lbuf, entry)}\n            | && StoreBufferLocationConcernsVar_L(entry.loc)\n              && StoreBufferMatchesExceptVar(lbuf, hbuf)\n            ensures StoreBufferMatchesExceptVar(L.Armada_StoreBufferAppend(lbuf, entry), hbuf)\n          {\n            lemma_AppendVarToStoreBufferDoesntAffectMatch(lbuf, hbuf, entry);\n          }\n        }\n      \";\n      pgp.AddLemma(str, \"tsoutil\");\n\n      str = @\"\n        lemma lemma_AppendCorrespondingStoreBufferEntriesMaintainsMatch(\n          lbuf:seq<L.Armada_StoreBufferEntry>,\n          lentry:L.Armada_StoreBufferEntry,\n          hbuf:seq<H.Armada_StoreBufferEntry>,\n          hentry:H.Armada_StoreBufferEntry\n          )\n          requires StoreBufferMatchesExceptVar(lbuf, hbuf)\n          requires !StoreBufferLocationConcernsVar_L(lentry.loc)\n          requires hentry == ConvertStoreBufferEntry_LH(lentry)\n          ensures  StoreBufferMatchesExceptVar(lbuf + [lentry], hbuf + [hentry])\n          decreases |lbuf| + |hbuf|;\n        {\n          var lbuf' := lbuf + [lentry];\n          var hbuf' := hbuf + [hentry];\n      \n          assert |lbuf| > 0 ==> lbuf'[0] == lbuf[0] && lbuf'[1..] == lbuf[1..] + [lentry];\n          assert |hbuf| > 0 ==> hbuf'[0] == hbuf[0] && hbuf'[1..] == hbuf[1..] + [hentry];\n      \n          if |lbuf| == 0 {\n          }\n          else if StoreBufferLocationConcernsVar_L(lbuf[0].loc) {\n            lemma_AppendCorrespondingStoreBufferEntriesMaintainsMatch(lbuf[1..], lentry, hbuf, hentry);\n          }\n          else {\n            lemma_AppendCorrespondingStoreBufferEntriesMaintainsMatch(lbuf[1..], lentry, hbuf[1..], hentry);\n          }\n        }\n      \";\n      pgp.AddLemma(str, \"tsoutil\");\n\n      str = @\"\n        lemma lemma_AppendCorrespondingStoreBufferEntriesMaintainsMatchAlways()\n          ensures forall lbuf: seq<L.Armada_StoreBufferEntry>, lentry, hbuf: seq<H.Armada_StoreBufferEntry>, hentry\n                    {:trigger L.Armada_StoreBufferAppend(lbuf, lentry), H.Armada_StoreBufferAppend(hbuf, hentry)} ::\n                    && hentry == ConvertStoreBufferEntry_LH(lentry)\n                    && StoreBufferMatchesExceptVar(lbuf, hbuf)\n                    && !StoreBufferLocationConcernsVar_L(lentry.loc)\n                    ==> StoreBufferMatchesExceptVar(L.Armada_StoreBufferAppend(lbuf, lentry), H.Armada_StoreBufferAppend(hbuf, hentry))\n        {\n          forall lbuf: seq<L.Armada_StoreBufferEntry>, lentry, hbuf: seq<H.Armada_StoreBufferEntry>, hentry\n            {:trigger L.Armada_StoreBufferAppend(lbuf, lentry), H.Armada_StoreBufferAppend(hbuf, hentry)} |\n            && hentry == ConvertStoreBufferEntry_LH(lentry)\n            && StoreBufferMatchesExceptVar(lbuf, hbuf)\n            && !StoreBufferLocationConcernsVar_L(lentry.loc)\n            ensures StoreBufferMatchesExceptVar(L.Armada_StoreBufferAppend(lbuf, lentry), H.Armada_StoreBufferAppend(hbuf, hentry))\n          {\n            lemma_AppendCorrespondingStoreBufferEntriesMaintainsMatch(lbuf, lentry, hbuf, hentry);\n          }\n        }\n      \";\n      pgp.AddLemma(str, \"tsoutil\");\n    }\n\n    private void GenerateRegularPathsLiftableLemma()\n    {\n      string str;\n\n      string finalCases = \"\";\n\n      var lpr = new PrefixedVarsPathPrinter(lAtomic);\n      var hpr = new PrefixedVarsPathPrinter(hAtomic);\n\n      foreach (var atomicPath in lAtomic.AtomicPaths) {\n        var name = atomicPath.Name;\n\n        str = $@\"\n          lemma lemma_RegularPathLiftable_{name}(ls: LPlusState, ls': LPlusState, lpath: LAtomic_Path, tid: Armada_ThreadHandle, hs: HState)\n            requires InductiveInv(ls)\n            requires TotalStateMatchesExceptVar(ls.s, hs)\n            requires tid in ls.s.threads\n            requires tid in hs.threads\n            requires OwnersLocalViewsMatch(ls, hs)\n            requires LAtomic_NextPath(ls, ls', lpath, tid)\n            requires lpath.LAtomic_Path_{name}?\n            requires !IsSkippedTauPath(ls, hs, lpath, tid)\n            ensures  HAtomic_ValidPath(hs, ConvertAtomicPath_LH(lpath), tid)\n          {{\n            { lpr.GetOpenValidPathInvocation(atomicPath) }\n            var hpath := ConvertAtomicPath_LH(lpath);\n            lemma_GlobalsMatchExceptVarImpliesLocalViewGlobalsMatchExceptVarAlways();\n            { hpr.GetOpenPathInvocation(pathMap[atomicPath]) }\n            ProofCustomizationGoesHere();\n          }}\n        \";\n        pgp.AddLemma(str, \"next_\" + name);\n        finalCases += $\"    case LAtomic_Path_{name}(_) => lemma_RegularPathLiftable_{name}(ls, ls', lpath, tid, hs);\\n\";\n      }\n\n      str = $@\"\n        lemma lemma_RegularPathLiftable(ls: LPlusState, ls': LPlusState, lpath: LAtomic_Path, tid: Armada_ThreadHandle, hs: HState)\n          requires InductiveInv(ls)\n          requires LiftingRelation(ls, hs)\n          requires LAtomic_NextPath(ls, ls', lpath, tid)\n          requires !IsSkippedTauPath(ls, hs, lpath, tid)\n          ensures  HAtomic_ValidPath(hs, ConvertAtomicPath_LH(lpath), tid)\n        {{\n          lemma_LAtomic_PathImpliesThreadRunning(ls, lpath, tid);\n          match lpath {{\n            { finalCases }\n          }}\n        }}\n      \";\n      pgp.AddLemma(str);\n    }\n\n    private void GenerateRegularPathMaintainsTotalStateMatchesExceptVar()\n    {\n      string str;\n\n      string finalCases = \"\";\n\n      var lpr = new PrefixedVarsPathPrinter(lAtomic);\n      var hpr = new PrefixedVarsPathPrinter(hAtomic);\n\n      foreach (var atomicPath in lAtomic.AtomicPaths) {\n        var name = atomicPath.Name;\n\n        str = $@\"\n          lemma lemma_RegularPathMaintainsTotalStateMatchesExceptVar_{name}(\n            ls: LPlusState,\n            ls': LPlusState,\n            lpath: LAtomic_Path,\n            tid: Armada_ThreadHandle,\n            hs: HState,\n            hs': HState,\n            hpath: HAtomic_Path\n            )\n            requires InductiveInv(ls)\n            requires TotalStateMatchesExceptVar(ls.s, hs)\n            requires tid in ls.s.threads\n            requires tid in hs.threads\n            requires OwnersLocalViewsMatch(ls, hs)\n            requires LAtomic_NextPath(ls, ls', lpath, tid)\n            requires lpath.LAtomic_Path_{name}?\n            requires !IsSkippedTauPath(ls, hs, lpath, tid)\n            requires hpath == ConvertAtomicPath_LH(lpath)\n            requires HAtomic_NextPath(hs, hs', hpath, tid)\n            ensures  TotalStateMatchesExceptVar(ls'.s, hs')\n          {{\n            { lpr.GetOpenValidPathInvocation(atomicPath) }\n            lemma_AppendVarToStoreBufferDoesntAffectMatchAlways();\n            lemma_AppendCorrespondingStoreBufferEntriesMaintainsMatchAlways();\n            lemma_IfMapKeysMatchThenCardinalitiesMatch(ls.s.threads, hs.threads);\n            lemma_GlobalsMatchExceptVarImpliesLocalViewGlobalsMatchExceptVarAlways();\n            { hpr.GetOpenValidPathInvocation(pathMap[atomicPath]) }\n            ProofCustomizationGoesHere();\n          }}\n        \";\n        pgp.AddLemma(str, \"next_\" + name);\n        finalCases += $\"    case LAtomic_Path_{name}(_) => lemma_RegularPathMaintainsTotalStateMatchesExceptVar_{name}(ls, ls', lpath, tid, hs, hs', hpath);\\n\";\n      }\n\n      str = $@\"\n        lemma lemma_RegularPathMaintainsTotalStateMatchesExceptVar(\n          ls: LPlusState,\n          ls': LPlusState,\n          lpath: LAtomic_Path,\n          tid: Armada_ThreadHandle,\n          hs: HState,\n          hs': HState,\n          hpath: HAtomic_Path\n          )\n          requires InductiveInv(ls)\n          requires LiftingRelation(ls, hs)\n          requires LAtomic_NextPath(ls, ls', lpath, tid)\n          requires !IsSkippedTauPath(ls, hs, lpath, tid)\n          requires hpath == ConvertAtomicPath_LH(lpath)\n          requires HAtomic_NextPath(hs, hs', hpath, tid)\n          ensures  TotalStateMatchesExceptVar(ls'.s, hs')\n        {{\n          lemma_LAtomic_PathImpliesThreadRunning(ls, lpath, tid);\n          match lpath {{\n            { finalCases }\n          }}\n        }}\n      \";\n      pgp.AddLemma(str);\n    }\n\n    private void GenerateRegularPathMaintainsGlobalsNoThreadOwnsMatch()\n    {\n      string str;\n\n      string finalCases = \"\";\n\n      var lpr = new PrefixedVarsPathPrinter(lAtomic);\n      var hpr = new PrefixedVarsPathPrinter(hAtomic);\n\n      foreach (var atomicPath in lAtomic.AtomicPaths)\n      {\n        var name = atomicPath.Name;\n\n        str = $@\"\n          lemma lemma_RegularPathMaintainsGlobalsNoThreadOwnsMatchSpecific_{name}(\n            ls: LPlusState,\n            ls':LPlusState,\n            lpath: LAtomic_Path,\n            tid: Armada_ThreadHandle,\n            hs: HState,\n            hs': HState,\n            hpath: HAtomic_Path{fields.IndexParamList}\n            )\n            requires InductiveInv(ls)\n            requires TotalStateMatchesExceptVar(ls.s, hs)\n            requires tid in ls.s.threads\n            requires tid in hs.threads\n            requires GlobalsNoThreadOwnsMatchSpecific(ls, hs{fields.IndexList})\n            requires OwnersLocalViewsMatch(ls, hs)\n            requires ls.s.stop_reason.Armada_NotStopped?\n            requires ls'.s.stop_reason.Armada_NotStopped?\n            requires !IsSkippedTauPath(ls, hs, lpath, tid)\n            requires LAtomic_NextPath(ls, ls', lpath, tid)\n            requires lpath.LAtomic_Path_{name}?\n            requires hpath == ConvertAtomicPath_LH(lpath)\n            requires HAtomic_NextPath(hs, hs', hpath, tid)\n            ensures  GlobalsNoThreadOwnsMatchSpecific(ls', hs'{fields.IndexList})\n          {{\n            { lpr.GetOpenValidPathInvocation(atomicPath) }\n            { hpr.GetOpenValidPathInvocation(pathMap[atomicPath]) }\n            var lg', hg' := ls'.s.mem.globals, hs'.mem.globals;\n            lemma_GlobalsMatchExceptVarImpliesLocalViewGlobalsMatchExceptVarAlways();\n            ProofCustomizationGoesHere();\n            if NoThreadOwns(ls'{fields.IndexList}) && ValidIndices_L(lg'{fields.IndexList}) && ValidIndices_H(hg'{fields.IndexList}) {{\n              assert !{ownershipPredicate}(ls', tid{fields.IndexList});\n              if !{ownershipPredicate}(ls, tid{fields.IndexList}) {{\n                forall any_tid | any_tid in ls.s.threads\n                  ensures !{ownershipPredicate}(ls, any_tid{fields.IndexList})\n                {{\n                  assert !{ownershipPredicate}(ls', any_tid{fields.IndexList});\n                  if any_tid != tid {{\n                    assert ls'.s.threads[any_tid] == ls.s.threads[any_tid];\n                  }}\n                }}\n                assert NoThreadOwns(ls{fields.IndexList});\n              }}\n              assert hg'{fields.FieldSpec} == lg'{fields.FieldSpec};\n            }}\n          }}\n        \";\n        pgp.AddLemma(str, \"next_\" + name);\n        finalCases += $\"    case LAtomic_Path_{name}(_) => lemma_RegularPathMaintainsGlobalsNoThreadOwnsMatchSpecific_{name}(ls, ls', lpath, tid, hs, hs', hpath{fields.IndexList});\\n\";\n      }\n\n      str = @\"\n        lemma lemma_RegularPathMaintainsGlobalsNoThreadOwnsMatch(\n          ls: LPlusState,\n          ls':LPlusState,\n          lpath: LAtomic_Path,\n          tid: Armada_ThreadHandle,\n          hs: HState,\n          hs': HState,\n          hpath: HAtomic_Path\n          )\n          requires InductiveInv(ls)\n          requires LiftingRelation(ls, hs)\n          requires ls.s.stop_reason.Armada_NotStopped?\n          requires ls'.s.stop_reason.Armada_NotStopped?\n          requires LAtomic_NextPath(ls, ls', lpath, tid)\n          requires !IsSkippedTauPath(ls, hs, lpath, tid)\n          requires hpath == ConvertAtomicPath_LH(lpath)\n          requires HAtomic_NextPath(hs, hs', hpath, tid)\n          ensures  GlobalsNoThreadOwnsMatch(ls', hs')\n        {\n          var lg', hg' := ls'.s.mem.globals, hs'.mem.globals;\n          lemma_LAtomic_PathImpliesThreadRunning(ls, lpath, tid);\n      \";\n      if (fields.NumArrays > 0) {\n        str += $@\"\n          forall {fields.IndexListWithoutLeadingComma}\n            ensures GlobalsNoThreadOwnsMatchSpecific(ls', hs'{fields.IndexList})\n          {{\n            assert GlobalsNoThreadOwnsMatchSpecific(ls, hs{fields.IndexList});\n            match lpath {{\n              { finalCases }\n            }}\n          }}\n        \";\n      }\n      else {\n        str += $@\"\n          assert GlobalsNoThreadOwnsMatchSpecific(ls, hs);\n          match lpath {{\n            { finalCases }\n          }}\n        \";\n      }\n      str += \"}\\n\";\n      pgp.AddLemma(str);\n    }\n    \n    private void GenerateRegularPathMaintainsHighLevelStoreBuffersLackVar()\n    {\n      string str;\n\n      string finalCases = \"\";\n\n      var lpr = new PrefixedVarsPathPrinter(lAtomic);\n      var hpr = new PrefixedVarsPathPrinter(hAtomic);\n\n      foreach (var atomicPath in lAtomic.AtomicPaths) {\n        var name = atomicPath.Name;\n\n        str = $@\"\n          lemma lemma_RegularPathMaintainsHighLevelStoreBuffersLackVar_{name}(\n            ls: LPlusState,\n            ls':LPlusState,\n            lpath: LAtomic_Path,\n            tid: Armada_ThreadHandle,\n            hs: HState,\n            hs': HState,\n            hpath: HAtomic_Path\n            )\n            requires InductiveInv(ls)\n            requires NonOwnersLackStoreBufferEntries(ls)\n            requires TotalStateMatchesExceptVar(ls.s, hs)\n            requires tid in ls.s.threads\n            requires tid in hs.threads\n            requires OwnersLocalViewsMatch(ls, hs)\n            requires HighLevelStoreBuffersLackVar(hs)\n            requires ls.s.stop_reason.Armada_NotStopped?\n            requires ls'.s.stop_reason.Armada_NotStopped?\n            requires LAtomic_NextPath(ls, ls', lpath, tid)\n            requires lpath.LAtomic_Path_{name}?\n            requires !IsSkippedTauPath(ls, hs, lpath, tid)\n            requires hpath == ConvertAtomicPath_LH(lpath)\n            requires HAtomic_NextPath(hs, hs', hpath, tid)\n            ensures  HighLevelStoreBuffersLackVar(hs')\n          {{\n            { lpr.GetOpenValidPathInvocation(atomicPath) }\n            { hpr.GetOpenValidPathInvocation(pathMap[atomicPath]) }\n            lemma_GlobalsMatchExceptVarImpliesLocalViewGlobalsMatchExceptVarAlways();\n            ProofCustomizationGoesHere();\n          }}\n        \";\n        pgp.AddLemma(str, \"next_\" + name);\n        finalCases += $\"  case LAtomic_Path_{name}(_) => lemma_RegularPathMaintainsHighLevelStoreBuffersLackVar_{name}(ls, ls', lpath, tid, hs, hs', hpath);\\n\";\n      }\n\n      str = $@\"\n        lemma lemma_RegularPathMaintainsHighLevelStoreBuffersLackVar(\n          ls: LPlusState,\n          ls':LPlusState,\n          lpath: LAtomic_Path,\n          tid: Armada_ThreadHandle,\n          hs: HState,\n          hs': HState,\n          hpath: HAtomic_Path\n          )\n          requires InductiveInv(ls)\n          requires LiftingRelation(ls, hs)\n          requires ls.s.stop_reason.Armada_NotStopped?\n          requires ls'.s.stop_reason.Armada_NotStopped?\n          requires LAtomic_NextPath(ls, ls', lpath, tid)\n          requires !IsSkippedTauPath(ls, hs, lpath, tid)\n          requires hpath == ConvertAtomicPath_LH(lpath)\n          requires HAtomic_NextPath(hs, hs', hpath, tid)\n          ensures  HighLevelStoreBuffersLackVar(hs')\n        {{\n          lemma_LAtomic_PathImpliesThreadRunning(ls, lpath, tid);\n          match lpath {{\n            { finalCases }\n          }}\n        }}\n      \";\n      pgp.AddLemma(str);\n    }\n\n    private void GenerateRegularPathMaintainsOwnersLocalViewsMatch()\n    {\n      string str;\n\n      string finalCases = \"\";\n\n      var lpr = new PrefixedVarsPathPrinter(lAtomic);\n      var hpr = new PrefixedVarsPathPrinter(hAtomic);\n\n      foreach (var atomicPath in lAtomic.AtomicPaths) {\n        var name = atomicPath.Name;\n\n        str = $@\"\n          lemma {{:timeLimitMultiplier {2 * atomicPath.NumNextRoutines + 2}}} lemma_RegularPathMaintainsActingOwnersLocalViewsMatchSpecific_{name}(\n            ls: LPlusState,\n            ls':LPlusState,\n            lpath: LAtomic_Path,\n            tid: Armada_ThreadHandle,\n            hs: HState,\n            hs': HState,\n            hpath: HAtomic_Path{fields.IndexParamList}\n            )\n            requires InductiveInv(ls)\n            requires InductiveInv(ls')\n            requires NonOwnersLackStoreBufferEntries(ls)\n            requires TotalStateMatchesExceptVar(ls.s, hs)\n            requires tid in ls.s.threads\n            requires tid in hs.threads\n            requires GlobalsNoThreadOwnsMatchSpecific(ls, hs{fields.IndexList})\n            requires OwnersLocalViewsMatch(ls, hs)\n            requires HighLevelStoreBuffersLackVar(hs)\n            requires ls.s.stop_reason.Armada_NotStopped?\n            requires ls'.s.stop_reason.Armada_NotStopped?\n            requires HighLevelStoreBuffersLackVar(hs')\n            requires LAtomic_NextPath(ls, ls', lpath, tid)\n            requires lpath.LAtomic_Path_{name}?\n            requires !IsSkippedTauPath(ls, hs, lpath, tid)\n            requires hpath == ConvertAtomicPath_LH(lpath)\n            requires HAtomic_NextPath(hs, hs', hpath, tid)\n            requires tid in ls'.s.threads\n            requires tid in hs'.threads\n            requires {ownershipPredicate}(ls', tid{fields.IndexList})\n            ensures  LocalViewsMatchSpecific(ls'.s, hs', tid{fields.IndexList})\n          {{\n            { lpr.GetOpenValidPathInvocation(atomicPath) }\n            { hpr.GetOpenValidPathInvocation(pathMap[atomicPath]) }\n            var lg := L.Armada_GetThreadLocalView(ls.s, tid).globals;\n            var hg := H.Armada_GetThreadLocalView(hs, tid).globals;\n            var lg' := L.Armada_GetThreadLocalView(ls'.s, tid).globals;\n            var hg' := H.Armada_GetThreadLocalView(hs', tid).globals;\n            lemma_GlobalsMatchExceptVarImpliesLocalViewGlobalsMatchExceptVarAlways();\n            ProofCustomizationGoesHere();\n            assert {{:error \"\"The TSO elimination strategy doesn't allow going directly from a state where one thread has ownership to one where a different thread has ownership.  The owning thread must take a step that releases ownership.\"\"}} !{ownershipPredicate}(ls, tid{fields.IndexList}) ==> NoThreadOwns(ls{fields.IndexList});\n            assert {ownershipPredicate}(ls, tid{fields.IndexList}) ==> LocalViewsMatchSpecific(ls.s, hs, tid{fields.IndexList});\n            lemma_IfStoreBufferLacksIndicesThenViewMatchesAlways_L({fields.IndexListWithoutLeadingComma});\n            lemma_IfStoreBufferLacksIndicesThenViewMatchesAlways_H({fields.IndexListWithoutLeadingComma});\n            lemma_IfVarUnchangedAndStoreBufferUnchangedThenViewUnchangedAlways_L({fields.IndexListWithoutLeadingComma});\n            lemma_ApplyStoreBufferCommutesWithAppendAlways_L();\n            lemma_ValidIndicesUnaffectedByApplyStoreBufferAlways_L({fields.IndexListWithoutLeadingComma});\n            assert ls'.s.mem == ls.s.mem && tid in ls.s.threads && ls'.s.threads[tid].storeBuffer == ls.s.threads[tid].storeBuffer ==> lg' == lg;\n            assert hs'.mem == hs.mem && tid in hs.threads && hs'.threads[tid].storeBuffer == hs.threads[tid].storeBuffer ==> hg' == hg;\n            if ValidIndices_L(lg{fields.IndexList}) && ValidIndices_H(hg{fields.IndexList}) {{\n              assert NoThreadOwns(ls{fields.IndexList}) ==> LocalViewsMatchSpecific(ls.s, hs, tid{fields.IndexList});\n              assert hg{fields.FieldSpec} == lg{fields.FieldSpec};\n        \";\n        for (var i = 1; i <= atomicPath.NumNextRoutines; ++i) {\n          str += $@\"\n              var lg{i} := L.Armada_GetThreadLocalView(lstates.s{i}.s, tid).globals;\n              var hg{i} := H.Armada_GetThreadLocalView(hstates.s{i}, tid).globals;\n              if ValidIndices_L(lg{i}{fields.IndexList}) && ValidIndices_H(hg{i}{fields.IndexList}) {{\n                if lg{i}{fields.FieldSpec} == lg{fields.FieldSpec} {{\n                  assert hg{i}{fields.FieldSpec} == hg{fields.FieldSpec};\n                  assert lg{i}{fields.FieldSpec} == hg{i}{fields.FieldSpec};\n                }}\n                  else {{\n                  assert lg{i}{fields.FieldSpec} == hg{i}{fields.FieldSpec};\n                }}\n              }}\n          \";\n        }\n        str += $@\"\n              assert lg' == lg{atomicPath.NumNextRoutines};\n              assert hg' == hg{atomicPath.NumNextRoutines};\n            }}\n          }}\n        \";\n        pgp.AddLemma(str, \"next_\" + name);\n\n        str = $@\"\n          lemma lemma_RegularPathMaintainsOtherOwnersLocalViewsMatchSpecific_{name}(\n            ls: LPlusState,\n            ls':LPlusState,\n            lpath: LAtomic_Path,\n            tid: Armada_ThreadHandle,\n            hs: HState,\n            hs': HState,\n            hpath: HAtomic_Path,\n            other_tid:Armada_ThreadHandle{fields.IndexParamList}\n            )\n            requires InductiveInv(ls)\n            requires NonOwnersLackStoreBufferEntries(ls)\n            requires TotalStateMatchesExceptVar(ls.s, hs)\n            requires tid in ls.s.threads\n            requires tid in hs.threads\n            requires GlobalsNoThreadOwnsMatchSpecific(ls, hs{fields.IndexList})\n            requires OwnersLocalViewsMatch(ls, hs)\n            requires HighLevelStoreBuffersLackVar(hs)\n            requires ls.s.stop_reason.Armada_NotStopped?\n            requires ls'.s.stop_reason.Armada_NotStopped?\n            requires HighLevelStoreBuffersLackVar(hs')\n            requires LAtomic_NextPath(ls, ls', lpath, tid)\n            requires lpath.LAtomic_Path_{name}?\n            requires !IsSkippedTauPath(ls, hs, lpath, tid)\n            requires hpath == ConvertAtomicPath_LH(lpath)\n            requires HAtomic_NextPath(hs, hs', hpath, tid)\n            requires other_tid in ls'.s.threads\n            requires other_tid in hs'.threads\n            requires other_tid != tid\n            requires {ownershipPredicate}(ls', other_tid{fields.IndexList})\n            requires !{ownershipPredicate}(ls', tid{fields.IndexList})\n            ensures  LocalViewsMatchSpecific(ls'.s, hs', other_tid{fields.IndexList})\n          {{\n            { lpr.GetOpenValidPathInvocation(atomicPath) }\n            { hpr.GetOpenValidPathInvocation(pathMap[atomicPath]) }\n            lemma_GlobalsMatchExceptVarImpliesLocalViewGlobalsMatchExceptVarAlways();\n            var lg' := L.Armada_GetThreadLocalView(ls'.s, other_tid).globals;\n            var hg' := H.Armada_GetThreadLocalView(hs', other_tid).globals;\n            lemma_IfStoreBufferLacksIndicesThenViewMatchesAlways_L({fields.IndexListWithoutLeadingComma});\n            lemma_IfStoreBufferLacksIndicesThenViewMatchesAlways_H({fields.IndexListWithoutLeadingComma});\n            lemma_ValidIndicesUnaffectedByApplyStoreBufferAlways_L({fields.IndexListWithoutLeadingComma});\n            lemma_ValidIndicesUnaffectedByApplyStoreBufferAlways_H({fields.IndexListWithoutLeadingComma});\n            lemma_IfVarUnchangedAndStoreBufferUnchangedThenViewUnchangedAlways_L({fields.IndexListWithoutLeadingComma});\n            ProofCustomizationGoesHere();\n            if ValidIndices_L(lg'{fields.IndexList}) && ValidIndices_H(hg'{fields.IndexList}) {{\n              assert lg'{fields.FieldSpec} == hg'{fields.FieldSpec};\n            }}\n          }}\n        \";\n        pgp.AddLemma(str, \"next_\" + name);\n\n        finalCases += $@\"\n          case LAtomic_Path_{name}(_) =>\n            if any_tid == tid {{\n              lemma_RegularPathMaintainsActingOwnersLocalViewsMatchSpecific_{name}(ls, ls', lpath, tid, hs, hs', hpath{fields.IndexList});\n            }}\n            else {{\n              lemma_RegularPathMaintainsOtherOwnersLocalViewsMatchSpecific_{name}(ls, ls', lpath, tid, hs, hs', hpath, any_tid{fields.IndexList});\n            }}\n        \";\n      }\n\n      str = $@\"\n        lemma lemma_RegularPathMaintainsOwnersLocalViewsMatch(\n          ls: LPlusState,\n          ls':LPlusState,\n          lpath: LAtomic_Path,\n          tid: Armada_ThreadHandle,\n          hs: HState,\n          hs': HState,\n          hpath: HAtomic_Path\n          )\n          requires InductiveInv(ls)\n          requires InductiveInv(ls')\n          requires LiftingRelation(ls, hs)\n          requires ls.s.stop_reason.Armada_NotStopped?\n          requires ls'.s.stop_reason.Armada_NotStopped?\n          requires HighLevelStoreBuffersLackVar(hs')\n          requires LAtomic_NextPath(ls, ls', lpath, tid)\n          requires !IsSkippedTauPath(ls, hs, lpath, tid)\n          requires hpath == ConvertAtomicPath_LH(lpath)\n          requires HAtomic_NextPath(hs, hs', hpath, tid)\n          ensures  OwnersLocalViewsMatch(ls', hs')\n        {{\n          lemma_LAtomic_PathImpliesThreadRunning(ls, lpath, tid);\n          forall any_tid{fields.IndexList}\n            | any_tid in ls'.s.threads && any_tid in hs'.threads && {ownershipPredicate}(ls', any_tid{fields.IndexList})\n            ensures LocalViewsMatchSpecific(ls'.s, hs', any_tid{fields.IndexList})\n          {{\n            assert any_tid != tid ==> !{ownershipPredicate}(ls', tid{fields.IndexList});\n            match lpath {{\n              { finalCases }\n            }}\n          }}\n        }}\n      \";\n      pgp.AddLemma(str);\n    }\n\n    private void GenerateRegularPathMaintainsLiftingRelation()\n    {\n      string str;\n\n      str = @\"\n        lemma lemma_RegularPathMaintainsLiftingRelation(\n          ls: LPlusState,\n          ls':LPlusState,\n          lpath: LAtomic_Path,\n          tid: Armada_ThreadHandle,\n          hs: HState,\n          hs': HState,\n          hpath: HAtomic_Path\n          )\n          requires InductiveInv(ls)\n          requires InductiveInv(ls')\n          requires LiftingRelation(ls, hs)\n          requires LAtomic_NextPath(ls, ls', lpath, tid)\n          requires !IsSkippedTauPath(ls, hs, lpath, tid)\n          requires hpath == ConvertAtomicPath_LH(lpath)\n          requires HAtomic_NextPath(hs, hs', hpath, tid)\n          ensures  LiftingRelation(ls', hs')\n        {\n          lemma_LAtomic_PathImpliesThreadRunning(ls, lpath, tid);\n          lemma_RegularPathMaintainsTotalStateMatchesExceptVar(ls, ls', lpath, tid, hs, hs', hpath);\n          if ls'.s.stop_reason.Armada_NotStopped? {\n            lemma_RegularPathMaintainsGlobalsNoThreadOwnsMatch(ls, ls', lpath, tid, hs, hs', hpath);\n            lemma_RegularPathMaintainsHighLevelStoreBuffersLackVar(ls, ls', lpath, tid, hs, hs', hpath);\n            lemma_RegularPathMaintainsOwnersLocalViewsMatch(ls, ls', lpath, tid, hs, hs', hpath);\n          }\n        }\n      \";\n      pgp.AddLemma(str);\n    }\n\n    private void GenerateSkippedTauPathMaintainsRelation()\n    {\n      string str;\n\n      var pr = new PrefixedVarsPathPrinter(lAtomic);\n\n      str = $@\"\n        lemma lemma_SkippedTauPathMaintainsTotalStateMatchesExceptVar(\n          ls: LPlusState,\n          ls': LPlusState,\n          lpath: LAtomic_Path,\n          tid: Armada_ThreadHandle,\n          hs: HState\n          )\n          requires InductiveInv(ls)\n          requires TotalStateMatchesExceptVar(ls.s, hs)\n          requires tid in ls.s.threads\n          requires tid in hs.threads\n          requires SharedMemoryMatchesExceptVar(L.Armada_GetThreadLocalView(ls.s, tid), H.Armada_GetThreadLocalView(hs, tid))\n          requires LAtomic_NextPath(ls, ls', lpath, tid)\n          requires IsSkippedTauPath(ls, hs, lpath, tid)\n          ensures  TotalStateMatchesExceptVar(ls'.s, hs)\n        {{\n          { pr.GetOpenValidPathInvocation(lAtomic.TauPath) }\n          ProofCustomizationGoesHere();\n        }}\n      \";\n      pgp.AddLemma(str);\n\n      str = $@\"\n        lemma lemma_SkippedTauPathMaintainsGlobalsNoThreadOwnsMatch(\n          ls: LPlusState,\n          ls': LPlusState,\n          lpath: LAtomic_Path,\n          tid: Armada_ThreadHandle,\n          hs: HState\n          )\n          requires InductiveInv(ls)\n          requires TotalStateMatchesExceptVar(ls.s, hs)\n          requires tid in ls.s.threads\n          requires tid in hs.threads\n          requires SharedMemoryMatchesExceptVar(L.Armada_GetThreadLocalView(ls.s, tid), H.Armada_GetThreadLocalView(hs, tid))\n          requires GlobalsNoThreadOwnsMatch(ls, hs)\n          requires LAtomic_NextPath(ls, ls', lpath, tid)\n          requires IsSkippedTauPath(ls, hs, lpath, tid)\n          ensures  GlobalsNoThreadOwnsMatch(ls', hs)\n        {{\n          { pr.GetOpenValidPathInvocation(lAtomic.TauPath) }\n          ProofCustomizationGoesHere();\n      \";\n      if (fields.NumArrays > 0) {\n        str += $\"forall {fields.IndexListWithoutLeadingComma} ensures GlobalsNoThreadOwnsMatchSpecific(ls', hs{fields.IndexList}) {{\\n\";\n      }\n      str += $@\"\n            assert L.Armada_ApplyStoreBuffer(ls.s.mem, ls.s.threads[tid].storeBuffer) ==\n                   L.Armada_ApplyStoreBuffer(ls'.s.mem, ls'.s.threads[tid].storeBuffer);\n            var lg, lg', hg := ls.s.mem.globals, ls'.s.mem.globals, hs.mem.globals;\n      \n            if ValidIndices_L(lg'{fields.IndexList}) && ValidIndices_H(hg{fields.IndexList}) {{\n              var buf := ls.s.threads[tid].storeBuffer;\n              var entry := buf[0];\n              if !StoreBufferLocationConcernsIndices_L(entry.loc{fields.IndexList}) {{\n                assert lg'{fields.FieldSpec} == lg{fields.FieldSpec};\n              }}\n\n              if NoThreadOwns(ls'{fields.IndexList}) {{\n                forall any_tid | any_tid in ls.s.threads\n                  ensures !{ownershipPredicate}(ls, any_tid{fields.IndexList})\n                {{\n                  assert !{ownershipPredicate}(ls', any_tid{fields.IndexList});\n                }}\n                assert NoThreadOwns(ls{fields.IndexList});\n      \n                assert GlobalsNoThreadOwnsMatchSpecific(ls, hs{fields.IndexList});\n        \n                if StoreBufferLocationConcernsIndices_L(entry.loc{fields.IndexList}) {{\n                  assert {ownershipPredicate}(ls, tid{fields.IndexList});\n                }}\n             }}\n          }}\n        }}\n      \";\n      if (fields.NumArrays > 0) {\n        str += \"}\\n\";\n      }\n      pgp.AddLemma(str);\n\n      str = $@\"\n        lemma lemma_SkippedTauPathMaintainsOwnersLocalViewsMatch(\n          ls: LPlusState,\n          ls': LPlusState,\n          lpath: LAtomic_Path,\n          tid: Armada_ThreadHandle,\n          hs: HState\n          )\n          requires InductiveInv(ls)\n          requires LiftingRelation(ls, hs)\n          requires tid in ls.s.threads\n          requires tid in hs.threads\n          requires SharedMemoryMatchesExceptVar(L.Armada_GetThreadLocalView(ls.s, tid), H.Armada_GetThreadLocalView(hs, tid))\n          requires LAtomic_NextPath(ls, ls', lpath, tid)\n          requires IsSkippedTauPath(ls, hs, lpath, tid)\n          ensures  OwnersLocalViewsMatch(ls', hs);\n        {{\n          { pr.GetOpenValidPathInvocation(lAtomic.TauPath) }\n          ProofCustomizationGoesHere();\n          assert L.Armada_ApplyStoreBuffer(ls.s.mem, ls.s.threads[tid].storeBuffer) ==\n                 L.Armada_ApplyStoreBuffer(ls'.s.mem, ls'.s.threads[tid].storeBuffer);\n      \n          forall any_tid{fields.IndexList} | any_tid in ls'.s.threads && {ownershipPredicate}(ls', any_tid{fields.IndexList})\n            ensures LocalViewsMatchSpecific(ls'.s, hs, any_tid{fields.IndexList})\n          {{\n            assert {ownershipPredicate}(ls, any_tid{fields.IndexList});\n            assert LocalViewsMatchSpecific(ls.s, hs, any_tid{fields.IndexList});\n            lemma_ValidIndicesUnaffectedByApplyStoreBufferAlways_L({fields.IndexListWithoutLeadingComma});\n            lemma_ValidIndicesUnaffectedByApplyStoreBufferAlways_H({fields.IndexListWithoutLeadingComma});\n            lemma_IfVarUnchangedAndStoreBufferUnchangedThenViewUnchangedAlways_L({fields.IndexListWithoutLeadingComma});\n            var loc := ls.s.threads[tid].storeBuffer[0].loc;\n            if StoreBufferLocationConcernsIndices_L(loc{fields.IndexList}) {{\n              assert LocalViewsMatchSpecific(ls'.s, hs, any_tid{fields.IndexList});\n            }}\n            else {{\n              assert LocalViewsMatchSpecific(ls'.s, hs, any_tid{fields.IndexList});\n            }}\n          }}\n        }}\n      \";\n      pgp.AddLemma(str);\n\n      str = $@\"\n        lemma lemma_SkippedTauPathMaintainsRelation(\n          ls: LPlusState,\n          ls': LPlusState,\n          lpath: LAtomic_Path,\n          tid: Armada_ThreadHandle,\n          hs: HState\n          )\n          requires InductiveInv(ls)\n          requires LiftingRelation(ls, hs)\n          requires tid in ls.s.threads\n          requires tid in hs.threads\n          requires LAtomic_NextPath(ls, ls', lpath, tid)\n          requires IsSkippedTauPath(ls, hs, lpath, tid)\n          ensures  LiftingRelation(ls', hs)\n        {{\n          { pr.GetOpenValidPathInvocation(lAtomic.TauPath) }\n          lemma_GlobalsMatchExceptVarImpliesLocalViewGlobalsMatchExceptVar(ls.s.mem, hs.mem, ls.s.threads[tid].storeBuffer,\n                                                                           hs.threads[tid].storeBuffer);\n          lemma_SkippedTauPathMaintainsTotalStateMatchesExceptVar(ls, ls', lpath, tid, hs);\n          ProofCustomizationGoesHere();\n          if ls'.s.stop_reason.Armada_NotStopped? {{\n            lemma_SkippedTauPathMaintainsGlobalsNoThreadOwnsMatch(ls, ls', lpath, tid, hs);\n            lemma_SkippedTauPathMaintainsOwnersLocalViewsMatch(ls, ls', lpath, tid, hs);\n          }}\n        }}\n      \";\n      pgp.AddLemma(str);\n    }\n\n    protected override void GenerateEstablishAtomicPathLiftableLemma()\n    {\n      string str = @\"\n        lemma lemma_EstablishAtomicPathLiftable(\n          lasf:AtomicSpecFunctions<LPlusState, LAtomic_Path, L.Armada_PC>,\n          hasf:AtomicSpecFunctions<HState, HAtomic_Path, H.Armada_PC>,\n          ls: LPlusState,\n          lpath: LAtomic_Path,\n          tid: Armada_ThreadHandle,\n          hs: HState\n          ) returns (\n          hpath: HAtomic_Path\n          )\n          requires lasf == LAtomic_GetSpecFunctions()\n          requires hasf == HAtomic_GetSpecFunctions()\n          requires InductiveInv(ls)\n          requires LiftingRelation(ls, hs)\n          requires LAtomic_ValidPath(ls, lpath, tid)\n          requires !AtomicPathSkippable(lasf, InductiveInv, LiftingRelation, ls, lpath, tid, hs)\n          ensures  LiftAtomicPathSuccessful(lasf, hasf, InductiveInv, LiftingRelation, ls, lpath, tid, hs, hpath)\n        {\n          var inv := InductiveInv;\n          var relation := LiftingRelation;\n          var ls' := lasf.path_next(ls, lpath, tid);\n          if IsSkippedTauPath(ls, hs, lpath, tid) {\n            lemma_SkippedTauPathMaintainsRelation(ls, ls', lpath, tid, hs);\n            lemma_AtomicPathMaintainsInductiveInv(ls, ls', lpath, tid);\n            lemma_LAtomic_PathHasPCEffect_Tau(ls, lpath, tid);\n            assert AtomicPathSkippable(lasf, inv, relation, ls, lpath, tid, hs);\n            assert false;\n          }\n          else {\n            var ls' := LAtomic_GetStateAfterPath(ls, lpath, tid);\n            lemma_AtomicPathMaintainsInductiveInv(ls, ls', lpath,  tid);\n            assert inv(ls');\n            hpath := ConvertAtomicPath_LH(lpath);\n            lemma_RegularPathLiftable(ls, ls', lpath, tid, hs);\n            var hs' := HAtomic_GetStateAfterPath(hs, hpath, tid);\n            lemma_RegularPathMaintainsLiftingRelation(ls, ls', lpath, tid, hs, hs', hpath);\n            assert LiftAtomicPathSuccessful(lasf, hasf, inv, relation, ls, lpath, tid, hs, hpath);\n          }\n        }\n      \";\n      pgp.AddLemma(str);\n    }\n  }\n}\n"
  },
  {
    "path": "Source/Armada/Translator.cs",
    "content": "﻿//-----------------------------------------------------------------------------\n//\n// Copyright (C) Microsoft Corporation.  All Rights Reserved.\n//\n//-----------------------------------------------------------------------------\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Numerics;\nusing System.Diagnostics.Contracts;\nusing Bpl = Microsoft.Boogie;\nusing BplParser = Microsoft.Boogie.Parser;\nusing System.Text;\nusing Microsoft.Boogie;\n\nnamespace Microsoft.Armada {\n\n  public class FreshIdGenerator\n  {\n    Dictionary<string, int> PrefixToCount = new Dictionary<string, int>();\n\n    public /*spec public*/ readonly Stack<int> Tip = new Stack<int>();\n    string tipString;  // a string representation of Tip\n    int tipChildrenCount = 0;\n    readonly Stack<Dictionary<string, int>> PrefixToCount_Stack = new Stack<Dictionary<string, int>>();  // invariant PrefixToCount_Stack.Count == Tip.Count\n    public void Push() {\n      Tip.Push(tipChildrenCount);\n      tipChildrenCount = 0;\n      tipString = ComputeTipString();\n      PrefixToCount_Stack.Push(PrefixToCount);\n      PrefixToCount = new Dictionary<string, int>();\n    }\n    public void Pop() {\n      Contract.Requires(Tip.Count > 0);\n      int k = Tip.Pop();\n      tipChildrenCount = k + 1;\n      tipString = ComputeTipString();\n      PrefixToCount = PrefixToCount_Stack.Pop();\n    }\n    string ComputeTipString() {\n      string s = null;\n      foreach (var k in Tip) {\n        if (s == null) {\n          s = k.ToString();\n        } else {\n          s = k.ToString() + \"_\" + s;\n        }\n      }\n      return s;\n    }\n\n    readonly string CommonPrefix = \"\";\n\n    public FreshIdGenerator()\n    {\n    }\n\n    private FreshIdGenerator(string commonPrefix)\n    {\n      CommonPrefix = commonPrefix;\n    }\n\n    public void Reset()\n    {\n      lock (PrefixToCount)\n      {\n        PrefixToCount.Clear();\n      }\n    }\n\n    public string FreshId(string prefix)\n    {\n      return CommonPrefix + prefix + FreshNumericId(prefix);\n    }\n\n    public FreshIdGenerator NestedFreshIdGenerator(string prefix)\n    {\n      return new FreshIdGenerator(FreshId(prefix));\n    }\n\n    public string FreshNumericId(string prefix = \"\")\n    {\n      lock (PrefixToCount)\n      {\n        int old;\n        if (!PrefixToCount.TryGetValue(prefix, out old)) {\n          old = 0;\n        }\n        PrefixToCount[prefix] = old + 1;\n        return tipString == null ? old.ToString() : tipString + \"_\" + old.ToString();\n      }\n    }\n  }\n\n  public class Translator {\n    ErrorReporter reporter;\n    // TODO(wuestholz): Enable this once Dafny's recommended Z3 version includes changeset 0592e765744497a089c42021990740f303901e67.\n    public bool UseOptimizationInZ3 { get; set; }\n\n    public class TranslatorFlags {\n      public bool InsertChecksums = 0 < CommandLineOptions.Clo.VerifySnapshots;\n      public string UniqueIdPrefix = null;\n    }\n\n    [NotDelayed]\n    public Translator(ErrorReporter reporter, TranslatorFlags flags = null) {\n      this.reporter = reporter;\n      if (flags == null) {\n        flags = new TranslatorFlags();\n      }\n      this.flags = flags;\n      Bpl.Program boogieProgram = ReadPrelude();\n      if (boogieProgram != null) {\n        sink = boogieProgram;\n        predef = FindPredefinedDecls(boogieProgram);\n      }\n    }\n\n    public void SetReporter(ErrorReporter reporter) {\n      this.reporter = reporter;\n    }\n\n    private void EstablishModuleScope(ModuleDefinition systemModule, ModuleDefinition m){\n      currentScope = new VisibilityScope();\n      verificationScope = new VisibilityScope();\n\n      currentScope.Augment(m.VisibilityScope);\n      verificationScope.Augment(currentScope);\n\n      currentScope.Augment(systemModule.VisibilityScope);\n\n      foreach (var decl in m.TopLevelDecls) {\n        if (decl is ModuleDecl && !(decl is ModuleExportDecl)) {\n          var mdecl = (ModuleDecl)decl;\n          currentScope.Augment(mdecl.AccessibleSignature().VisibilityScope);\n        }\n      }\n\n    }\n\n    // translation state\n    readonly Dictionary<TopLevelDecl/*!*/,Bpl.Constant/*!*/>/*!*/ classes = new Dictionary<TopLevelDecl/*!*/,Bpl.Constant/*!*/>();\n    readonly Dictionary<TopLevelDecl, string>/*!*/ classConstants = new Dictionary<TopLevelDecl, string>();\n    readonly Dictionary<int, string> functionConstants = new Dictionary<int, string>();\n    readonly Dictionary<Function, string> functionHandles = new Dictionary<Function, string>();\n    readonly List<FuelConstant> functionFuel = new List<FuelConstant>();\n    readonly Dictionary<Field/*!*/,Bpl.Constant/*!*/>/*!*/ fields = new Dictionary<Field/*!*/,Bpl.Constant/*!*/>();\n    readonly Dictionary<Field/*!*/, Bpl.Function/*!*/>/*!*/ fieldFunctions = new Dictionary<Field/*!*/, Bpl.Function/*!*/>();\n    readonly Dictionary<string, Bpl.Constant> fieldConstants = new Dictionary<string,Constant>();\n    readonly ISet<string> abstractTypes = new HashSet<string>();\n    readonly ISet<string> opaqueTypes = new HashSet<string>();\n\n    // optimizing translation\n    readonly ISet<MemberDecl> referencedMembers = new HashSet<MemberDecl>();\n\n    public void AddReferencedMember(MemberDecl m) {\n      if (m is Method && !InVerificationScope(m)) {\n        referencedMembers.Add(m);\n      }\n    }\n\n    FuelContext fuelContext = null;\n    IsAllocContext isAllocContext = null;\n    Program program;\n\n    [ContractInvariantMethod]\n    void ObjectInvariant()\n    {\n      Contract.Invariant(cce.NonNullDictionaryAndValues(classes));\n      Contract.Invariant(cce.NonNullDictionaryAndValues(fields));\n      Contract.Invariant(cce.NonNullDictionaryAndValues(fieldFunctions));\n      Contract.Invariant(codeContext == null || codeContext.EnclosingModule == currentModule);\n    }\n\n    [Pure]\n    bool VisibleInScope(Declaration d) {\n      Contract.Requires(d != null);\n      return d.IsVisibleInScope(currentScope);\n    }\n\n    [Pure]\n    bool VisibleInScope(Type t) {\n      if (t is UserDefinedType && ((UserDefinedType)t).ResolvedClass != null) {\n        return VisibleInScope(((UserDefinedType)t).ResolvedClass);\n      }\n      return true;\n    }\n\n    [Pure]\n    bool RevealedInScope(Declaration d) {\n      Contract.Requires(d != null);\n      return d.IsRevealedInScope(currentScope);\n    }\n\n    [Pure]\n    bool RevealedInScope(RevealableTypeDecl d) {\n      Contract.Requires(d != null);\n      return RevealedInScope(d.AsTopLevelDecl);\n    }\n\n    [Pure]\n    bool InVerificationScope(Declaration d) {\n      Contract.Requires(d != null);\n      if (d.tok is IncludeToken && !ArmadaOptions.O.VerifyAllModules) {\n        return false;\n      }\n\n      if (d.IsVisibleInScope(verificationScope)) {\n        Contract.Assert(d.IsRevealedInScope(verificationScope));\n        return true;\n      }\n      return false;\n    }\n\n    [Pure]\n    bool InVerificationScope(RedirectingTypeDecl d) {\n      Contract.Requires(d != null);\n      Contract.Requires(d is Declaration);\n      return InVerificationScope((Declaration)d);\n    }\n\n\n\n    private Bpl.Program sink;\n    private VisibilityScope currentScope;\n    private VisibilityScope verificationScope;\n\n\n    readonly PredefinedDecls predef;\n\n    private TranslatorFlags flags = new TranslatorFlags();\n    private bool InsertChecksums { get { return flags.InsertChecksums; } }\n    private string UniqueIdPrefix { get { return flags.UniqueIdPrefix; } }\n\n    internal class PredefinedDecls {\n      public readonly Bpl.Type CharType;\n      public readonly Bpl.Type RefType;\n      public readonly Bpl.Type BoxType;\n      public Bpl.Type BigOrdinalType {\n        get { return BoxType; }\n      }\n      public readonly Bpl.Type TickType;\n      private readonly Bpl.TypeSynonymDecl setTypeCtor;\n      private readonly Bpl.TypeSynonymDecl isetTypeCtor;\n      private readonly Bpl.TypeSynonymDecl multiSetTypeCtor;\n      private readonly Bpl.TypeCtorDecl mapTypeCtor;\n      private readonly Bpl.TypeCtorDecl imapTypeCtor;\n      public readonly Bpl.Function ArrayLength;\n      public readonly Bpl.Function RealFloor;\n      public readonly Bpl.Function ORDINAL_IsLimit;\n      public readonly Bpl.Function ORDINAL_IsSucc;\n      public readonly Bpl.Function ORDINAL_Offset;\n      public readonly Bpl.Function ORDINAL_IsNat;\n      public readonly Bpl.Function MapDomain;\n      public readonly Bpl.Function IMapDomain;\n      public readonly Bpl.Function MapValues;\n      public readonly Bpl.Function IMapValues;\n      public readonly Bpl.Function MapItems;\n      public readonly Bpl.Function IMapItems;\n      public readonly Bpl.Function Tuple2Destructors0;\n      public readonly Bpl.Function Tuple2Destructors1;\n      private readonly Bpl.TypeCtorDecl seqTypeCtor;\n      public readonly Bpl.Type Bv0Type;\n      readonly Bpl.TypeCtorDecl fieldName;\n      public readonly Bpl.Type HeapType;\n      public readonly string HeapVarName;\n      public readonly Bpl.Type ClassNameType;\n      public readonly Bpl.Type NameFamilyType;\n      public readonly Bpl.Type DatatypeType;\n      public readonly Bpl.Type HandleType;\n      public readonly Bpl.Type LayerType;\n      public readonly Bpl.Type DtCtorId;\n      public readonly Bpl.Type Ty;\n      public readonly Bpl.Type TyTag;\n      public readonly Bpl.Expr Null;\n      public readonly Bpl.Expr NoTraitAtAll;\n      public readonly Bpl.Constant AllocField;\n      [ContractInvariantMethod]\n      void ObjectInvariant() {\n        Contract.Invariant(CharType != null);\n        Contract.Invariant(RefType != null);\n        Contract.Invariant(BoxType != null);\n        Contract.Invariant(TickType != null);\n        Contract.Invariant(setTypeCtor != null);\n        Contract.Invariant(multiSetTypeCtor != null);\n        Contract.Invariant(ArrayLength != null);\n        Contract.Invariant(RealFloor != null);\n        Contract.Invariant(ORDINAL_IsLimit != null);\n        Contract.Invariant(ORDINAL_IsSucc != null);\n        Contract.Invariant(ORDINAL_Offset != null);\n        Contract.Invariant(ORDINAL_IsNat != null);\n        Contract.Invariant(MapDomain != null);\n        Contract.Invariant(IMapDomain != null);\n        Contract.Invariant(MapValues != null);\n        Contract.Invariant(IMapValues != null);\n        Contract.Invariant(MapItems != null);\n        Contract.Invariant(IMapItems != null);\n        Contract.Invariant(Tuple2Destructors0 != null);\n        Contract.Invariant(Tuple2Destructors1 != null);\n        Contract.Invariant(seqTypeCtor != null);\n        Contract.Invariant(fieldName != null);\n        Contract.Invariant(HeapVarName != null);\n        Contract.Invariant(ClassNameType != null);\n        Contract.Invariant(NameFamilyType != null);\n        Contract.Invariant(DatatypeType != null);\n        Contract.Invariant(HandleType != null);\n        Contract.Invariant(LayerType != null);\n        Contract.Invariant(DtCtorId != null);\n        Contract.Invariant(Ty != null);\n        Contract.Invariant(TyTag != null);\n        Contract.Invariant(Null != null);\n        Contract.Invariant(NoTraitAtAll != null);\n        Contract.Invariant(AllocField != null);\n      }\n\n      public Bpl.Type SetType(IToken tok, bool finite, Bpl.Type ty) {\n        Contract.Requires(tok != null);\n        Contract.Requires(ty != null);\n        Contract.Ensures(Contract.Result<Bpl.Type>() != null);\n\n        return new Bpl.TypeSynonymAnnotation(Token.NoToken, finite ? setTypeCtor : isetTypeCtor, new List<Bpl.Type> { ty });\n      }\n\n      public Bpl.Type MultiSetType(IToken tok, Bpl.Type ty) {\n        Contract.Requires(tok != null);\n        Contract.Requires(ty != null);\n        Contract.Ensures(Contract.Result<Bpl.Type>() != null);\n\n        return new Bpl.TypeSynonymAnnotation(Token.NoToken, multiSetTypeCtor, new List<Bpl.Type>{ ty });\n      }\n      public Bpl.Type MapType(IToken tok, bool finite, Bpl.Type tya, Bpl.Type tyb) {\n        Contract.Requires(tok != null);\n        Contract.Requires(tya != null && tyb != null);\n        Contract.Ensures(Contract.Result<Bpl.Type>() != null);\n\n        return new Bpl.CtorType(Token.NoToken, finite ? mapTypeCtor : imapTypeCtor, new List<Bpl.Type> { tya, tyb });\n      }\n\n      public Bpl.Type SeqType(IToken tok, Bpl.Type ty) {\n        Contract.Requires(tok != null);\n        Contract.Requires(ty != null);\n        Contract.Ensures(Contract.Result<Bpl.Type>() != null);\n        return new Bpl.CtorType(Token.NoToken, seqTypeCtor, new List<Bpl.Type>{ ty });\n      }\n\n      public Bpl.Type FieldName(IToken tok, Bpl.Type ty) {\n        Contract.Requires(tok != null);\n        Contract.Requires(ty != null);\n        Contract.Ensures(Contract.Result<Bpl.Type>() != null);\n\n        return new Bpl.CtorType(tok, fieldName, new List<Bpl.Type>{ ty });\n      }\n\n      public Bpl.IdentifierExpr Alloc(IToken tok) {\n        Contract.Requires(tok != null);\n        Contract.Ensures(Contract.Result<Bpl.IdentifierExpr>() != null);\n\n        return new Bpl.IdentifierExpr(tok, AllocField);\n      }\n\n      public PredefinedDecls(Bpl.TypeCtorDecl charType, Bpl.TypeCtorDecl refType, Bpl.TypeCtorDecl boxType, Bpl.TypeCtorDecl tickType,\n                             Bpl.TypeSynonymDecl setTypeCtor, Bpl.TypeSynonymDecl isetTypeCtor, Bpl.TypeSynonymDecl multiSetTypeCtor,\n                             Bpl.TypeCtorDecl mapTypeCtor, Bpl.TypeCtorDecl imapTypeCtor,\n                             Bpl.Function arrayLength, Bpl.Function realFloor,\n                             Bpl.Function ORD_isLimit, Bpl.Function ORD_isSucc, Bpl.Function ORD_offset, Bpl.Function ORD_isNat,\n                             Bpl.Function mapDomain, Bpl.Function imapDomain,\n                             Bpl.Function mapValues, Bpl.Function imapValues, Bpl.Function mapItems, Bpl.Function imapItems,\n                             Bpl.Function tuple2Destructors0, Bpl.Function tuple2Destructors1,\n                             Bpl.TypeCtorDecl seqTypeCtor, Bpl.TypeSynonymDecl bv0TypeDecl,\n                             Bpl.TypeCtorDecl fieldNameType, Bpl.TypeCtorDecl tyType, Bpl.TypeCtorDecl tyTagType,\n                             Bpl.GlobalVariable heap, Bpl.TypeCtorDecl classNameType, Bpl.TypeCtorDecl nameFamilyType,\n                             Bpl.TypeCtorDecl datatypeType, Bpl.TypeCtorDecl handleType, Bpl.TypeCtorDecl layerType, Bpl.TypeCtorDecl dtCtorId,\n                             Bpl.Constant allocField) {\n        #region Non-null preconditions on parameters\n        Contract.Requires(charType != null);\n        Contract.Requires(refType != null);\n        Contract.Requires(boxType != null);\n        Contract.Requires(tickType != null);\n        Contract.Requires(setTypeCtor != null);\n        Contract.Requires(isetTypeCtor != null);\n        Contract.Requires(multiSetTypeCtor != null);\n        Contract.Requires(mapTypeCtor != null);\n        Contract.Requires(imapTypeCtor != null);\n        Contract.Requires(arrayLength != null);\n        Contract.Requires(realFloor != null);\n        Contract.Requires(ORD_isLimit != null);\n        Contract.Requires(ORD_isSucc != null);\n        Contract.Requires(ORD_offset != null);\n        Contract.Requires(ORD_isNat != null);\n        Contract.Requires(mapDomain != null);\n        Contract.Requires(imapDomain != null);\n        Contract.Requires(mapValues != null);\n        Contract.Requires(imapValues != null);\n        Contract.Requires(mapItems != null);\n        Contract.Requires(imapItems != null);\n        Contract.Requires(tuple2Destructors0 != null);\n        Contract.Requires(tuple2Destructors1 != null);\n        Contract.Requires(seqTypeCtor != null);\n        Contract.Requires(bv0TypeDecl != null);\n        Contract.Requires(fieldNameType != null);\n        Contract.Requires(heap != null);\n        Contract.Requires(classNameType != null);\n        Contract.Requires(datatypeType != null);\n        Contract.Requires(layerType != null);\n        Contract.Requires(dtCtorId != null);\n        Contract.Requires(allocField != null);\n        Contract.Requires(tyType != null);\n        Contract.Requires(tyTagType != null);\n        #endregion\n\n        this.CharType = new Bpl.CtorType(Token.NoToken, charType, new List<Bpl.Type>());\n        Bpl.CtorType refT = new Bpl.CtorType(Token.NoToken, refType, new List<Bpl.Type>());\n        this.RefType = refT;\n        this.BoxType = new Bpl.CtorType(Token.NoToken, boxType, new List<Bpl.Type>());\n        this.TickType = new Bpl.CtorType(Token.NoToken, tickType, new List<Bpl.Type>());\n        this.setTypeCtor = setTypeCtor;\n        this.isetTypeCtor = isetTypeCtor;\n        this.multiSetTypeCtor = multiSetTypeCtor;\n        this.mapTypeCtor = mapTypeCtor;\n        this.imapTypeCtor = imapTypeCtor;\n        this.ArrayLength = arrayLength;\n        this.RealFloor = realFloor;\n        this.ORDINAL_IsLimit = ORD_isLimit;\n        this.ORDINAL_IsSucc = ORD_isSucc;\n        this.ORDINAL_Offset = ORD_offset;\n        this.ORDINAL_IsNat= ORD_isNat;\n        this.MapDomain = mapDomain;\n        this.IMapDomain = imapDomain;\n        this.MapValues = mapValues;\n        this.IMapValues = imapValues;\n        this.MapItems = mapItems;\n        this.IMapItems = imapItems;\n        this.Tuple2Destructors0 = tuple2Destructors0;\n        this.Tuple2Destructors1 = tuple2Destructors1;\n        this.seqTypeCtor = seqTypeCtor;\n        this.Bv0Type = new Bpl.TypeSynonymAnnotation(Token.NoToken, bv0TypeDecl, new List<Bpl.Type>());\n        this.fieldName = fieldNameType;\n        this.HeapType = heap.TypedIdent.Type;\n        this.HeapVarName = heap.Name;\n        this.Ty = new Bpl.CtorType(Token.NoToken, tyType, new List<Bpl.Type>());\n        this.TyTag = new Bpl.CtorType(Token.NoToken, tyTagType, new List<Bpl.Type>());\n        this.ClassNameType = new Bpl.CtorType(Token.NoToken, classNameType, new List<Bpl.Type>());\n        this.NameFamilyType = new Bpl.CtorType(Token.NoToken, nameFamilyType, new List<Bpl.Type>());\n        this.DatatypeType = new Bpl.CtorType(Token.NoToken, datatypeType, new List<Bpl.Type>());\n        this.HandleType = new Bpl.CtorType(Token.NoToken, handleType, new List<Bpl.Type>());\n        this.LayerType = new Bpl.CtorType(Token.NoToken, layerType, new List<Bpl.Type>());\n        this.DtCtorId = new Bpl.CtorType(Token.NoToken, dtCtorId, new List<Bpl.Type>());\n        this.AllocField = allocField;\n        this.Null = new Bpl.IdentifierExpr(Token.NoToken, \"null\", refT);\n        this.NoTraitAtAll = new Bpl.IdentifierExpr(Token.NoToken, \"NoTraitAtAll\", ClassNameType);\n      }\n    }\n\n    static PredefinedDecls FindPredefinedDecls(Bpl.Program prog) {\n      Contract.Requires(prog != null);\n      if (prog.Resolve() != 0) {\n        Console.WriteLine(\"Error: resolution errors encountered in Dafny prelude\");\n        return null;\n      }\n\n      Bpl.TypeCtorDecl charType = null;\n      Bpl.TypeCtorDecl refType = null;\n      Bpl.TypeSynonymDecl setTypeCtor = null;\n      Bpl.TypeSynonymDecl isetTypeCtor = null;\n      Bpl.TypeSynonymDecl multiSetTypeCtor = null;\n      Bpl.Function arrayLength = null;\n      Bpl.Function realFloor = null;\n      Bpl.Function ORDINAL_isLimit = null;\n      Bpl.Function ORDINAL_isSucc = null;\n      Bpl.Function ORDINAL_offset = null;\n      Bpl.Function ORDINAL_isNat = null;\n      Bpl.Function mapDomain = null;\n      Bpl.Function imapDomain = null;\n      Bpl.Function mapValues = null;\n      Bpl.Function imapValues = null;\n      Bpl.Function mapItems = null;\n      Bpl.Function imapItems = null;\n      Bpl.Function tuple2Destructors0 = null;\n      Bpl.Function tuple2Destructors1 = null;\n      Bpl.TypeCtorDecl seqTypeCtor = null;\n      Bpl.TypeCtorDecl fieldNameType = null;\n      Bpl.TypeCtorDecl classNameType = null;\n      Bpl.TypeSynonymDecl bv0TypeDecl = null;\n      Bpl.TypeCtorDecl tyType = null;\n      Bpl.TypeCtorDecl tyTagType = null;\n      Bpl.TypeCtorDecl nameFamilyType = null;\n      Bpl.TypeCtorDecl datatypeType = null;\n      Bpl.TypeCtorDecl handleType = null;\n      Bpl.TypeCtorDecl layerType = null;\n      Bpl.TypeCtorDecl dtCtorId = null;\n      Bpl.TypeCtorDecl boxType = null;\n      Bpl.TypeCtorDecl tickType = null;\n      Bpl.TypeCtorDecl mapTypeCtor = null;\n      Bpl.TypeCtorDecl imapTypeCtor = null;\n      Bpl.GlobalVariable heap = null;\n      Bpl.Constant allocField = null;\n      foreach (var d in prog.TopLevelDeclarations) {\n        if (d is Bpl.TypeCtorDecl) {\n          Bpl.TypeCtorDecl dt = (Bpl.TypeCtorDecl)d;\n          if (dt.Name == \"Seq\") {\n            seqTypeCtor = dt;\n          } else if (dt.Name == \"Field\") {\n            fieldNameType = dt;\n          } else if (dt.Name == \"ClassName\") {\n            classNameType = dt;\n          } else if (dt.Name == \"Ty\") {\n            tyType = dt;\n          } else if (dt.Name == \"TyTag\") {\n            tyTagType = dt;\n          } else if (dt.Name == \"DatatypeType\") {\n            datatypeType = dt;\n          } else if (dt.Name == \"HandleType\") {\n            handleType = dt;\n          } else if (dt.Name == \"LayerType\") {\n            layerType = dt;\n          } else if (dt.Name == \"DtCtorId\") {\n            dtCtorId = dt;\n          } else if (dt.Name == \"char\") {\n            charType = dt;\n          } else if (dt.Name == \"ref\") {\n            refType = dt;\n          } else if (dt.Name == \"NameFamily\") {\n            nameFamilyType = dt;\n          } else if (dt.Name == \"Box\") {\n            boxType = dt;\n          } else if (dt.Name == \"TickType\") {\n            tickType = dt;\n          } else if (dt.Name == \"Map\") {\n            mapTypeCtor = dt;\n          } else if (dt.Name == \"IMap\") {\n            imapTypeCtor = dt;\n          }\n        } else if (d is Bpl.TypeSynonymDecl) {\n          Bpl.TypeSynonymDecl dt = (Bpl.TypeSynonymDecl)d;\n          if (dt.Name == \"Set\") {\n            setTypeCtor = dt;\n          } else if (dt.Name == \"MultiSet\") {\n            multiSetTypeCtor = dt;\n          } else if (dt.Name == \"ISet\") {\n            isetTypeCtor = dt;\n          } else if (dt.Name == \"Bv0\") {\n            bv0TypeDecl = dt;\n          }\n        } else if (d is Bpl.Constant) {\n          Bpl.Constant c = (Bpl.Constant)d;\n          if (c.Name == \"alloc\") {\n            allocField = c;\n          }\n        } else if (d is Bpl.GlobalVariable) {\n          Bpl.GlobalVariable v = (Bpl.GlobalVariable)d;\n          if (v.Name == \"$Heap\") {\n            heap = v;\n          }\n        } else if (d is Bpl.Function) {\n          var f = (Bpl.Function)d;\n          if (f.Name == \"_System.array.Length\") {\n            arrayLength = f;\n          } else if (f.Name == \"_System.real.Floor\") {\n            realFloor = f;\n          } else if (f.Name == \"ORD#IsLimit\") {\n            ORDINAL_isLimit = f;\n          } else if (f.Name == \"ORD#IsSucc\") {\n            ORDINAL_isSucc = f;\n          } else if (f.Name == \"ORD#Offset\") {\n            ORDINAL_offset = f;\n          } else if (f.Name == \"ORD#IsNat\") {\n            ORDINAL_isNat = f;\n          } else if (f.Name == \"Map#Domain\") {\n            mapDomain = f;\n          } else if (f.Name == \"IMap#Domain\") {\n            imapDomain = f;\n          } else if (f.Name == \"Map#Values\") {\n            mapValues = f;\n          } else if (f.Name == \"IMap#Values\") {\n            imapValues = f;\n          } else if (f.Name == \"Map#Items\") {\n            mapItems = f;\n          } else if (f.Name == \"IMap#Items\") {\n            imapItems = f;\n          } else if (f.Name == \"_System.Tuple2._0\") {\n            tuple2Destructors0 = f;\n          } else if (f.Name == \"_System.Tuple2._1\") {\n            tuple2Destructors1 = f;\n          }\n        }\n      }\n      if (seqTypeCtor == null) {\n        Console.WriteLine(\"Error: Dafny prelude is missing declaration of type Seq\");\n      } else if (setTypeCtor == null) {\n        Console.WriteLine(\"Error: Dafny prelude is missing declaration of type Set\");\n      } else if (isetTypeCtor == null) {\n        Console.WriteLine(\"Error: Dafny prelude is missing declaration of type ISet\");\n      } else if (multiSetTypeCtor == null) {\n        Console.WriteLine(\"Error: Dafny prelude is missing declaration of type MultiSet\");\n      } else if (mapTypeCtor == null) {\n        Console.WriteLine(\"Error: Dafny prelude is missing declaration of type Map\");\n      } else if (imapTypeCtor == null) {\n        Console.WriteLine(\"Error: Dafny prelude is missing declaration of type IMap\");\n      } else if (arrayLength == null) {\n        Console.WriteLine(\"Error: Dafny prelude is missing declaration of function _System.array.Length\");\n      } else if (realFloor == null) {\n        Console.WriteLine(\"Error: Dafny prelude is missing declaration of function _System.real.Floor\");\n      } else if (ORDINAL_isLimit == null) {\n        Console.WriteLine(\"Error: Dafny prelude is missing declaration of function ORD#IsLimit\");\n      } else if (ORDINAL_isSucc == null) {\n        Console.WriteLine(\"Error: Dafny prelude is missing declaration of function ORD#IsSucc\");\n      } else if (ORDINAL_offset == null) {\n        Console.WriteLine(\"Error: Dafny prelude is missing declaration of function ORD#Offset\");\n      } else if (ORDINAL_isNat == null) {\n        Console.WriteLine(\"Error: Dafny prelude is missing declaration of function ORD#IsNat\");\n      } else if (mapDomain == null) {\n        Console.WriteLine(\"Error: Dafny prelude is missing declaration of function Map#Domain\");\n      } else if (imapDomain == null) {\n        Console.WriteLine(\"Error: Dafny prelude is missing declaration of function IMap#Domain\");\n      } else if (mapValues == null) {\n        Console.WriteLine(\"Error: Dafny prelude is missing declaration of function Map#Values\");\n      } else if (imapValues == null) {\n        Console.WriteLine(\"Error: Dafny prelude is missing declaration of function IMap#Values\");\n      } else if (mapItems == null) {\n        Console.WriteLine(\"Error: Dafny prelude is missing declaration of function Map#Items\");\n      } else if (imapItems == null) {\n        Console.WriteLine(\"Error: Dafny prelude is missing declaration of function IMap#Items\");\n      } else if (tuple2Destructors0 == null) {\n        Console.WriteLine(\"Error: Dafny prelude is missing declaration of function _System.Tuple2._0\");\n      } else if (tuple2Destructors1 == null) {\n        Console.WriteLine(\"Error: Dafny prelude is missing declaration of function _System.Tuple2._1\");\n      } else if (bv0TypeDecl == null) {\n        Console.WriteLine(\"Error: Dafny prelude is missing declaration of type Bv0\");\n      } else if (fieldNameType == null) {\n        Console.WriteLine(\"Error: Dafny prelude is missing declaration of type Field\");\n      } else if (classNameType == null) {\n        Console.WriteLine(\"Error: Dafny prelude is missing declaration of type ClassName\");\n      } else if (tyType == null) {\n        Console.WriteLine(\"Error: Dafny prelude is missing declaration of type Ty\");\n      } else if (tyTagType == null) {\n        Console.WriteLine(\"Error: Dafny prelude is missing declaration of type TyTag\");\n      } else if (nameFamilyType == null) {\n        Console.WriteLine(\"Error: Dafny prelude is missing declaration of type NameFamily\");\n      } else if (datatypeType == null) {\n        Console.WriteLine(\"Error: Dafny prelude is missing declaration of type DatatypeType\");\n      } else if (handleType == null) {\n        Console.WriteLine(\"Error: Dafny prelude is missing declaration of type HandleType\");\n      } else if (layerType == null) {\n        Console.WriteLine(\"Error: Dafny prelude is missing declaration of type LayerType\");\n      } else if (dtCtorId == null) {\n        Console.WriteLine(\"Error: Dafny prelude is missing declaration of type DtCtorId\");\n      } else if (charType == null) {\n        Console.WriteLine(\"Error: Dafny prelude is missing declaration of type char\");\n      } else if (refType == null) {\n        Console.WriteLine(\"Error: Dafny prelude is missing declaration of type ref\");\n      } else if (boxType == null) {\n        Console.WriteLine(\"Error: Dafny prelude is missing declaration of type Box\");\n      } else if (tickType == null) {\n        Console.WriteLine(\"Error: Dafny prelude is missing declaration of type TickType\");\n      } else if (heap == null) {\n        Console.WriteLine(\"Error: Dafny prelude is missing declaration of $Heap\");\n      } else if (allocField == null) {\n        Console.WriteLine(\"Error: Dafny prelude is missing declaration of constant alloc\");\n      } else {\n        return new PredefinedDecls(charType, refType, boxType, tickType,\n                                   setTypeCtor, isetTypeCtor, multiSetTypeCtor,\n                                   mapTypeCtor, imapTypeCtor,\n                                   arrayLength, realFloor,\n                                   ORDINAL_isLimit, ORDINAL_isSucc, ORDINAL_offset, ORDINAL_isNat,\n                                   mapDomain, imapDomain,\n                                   mapValues, imapValues, mapItems, imapItems,\n                                   tuple2Destructors0, tuple2Destructors1,\n                                   seqTypeCtor, bv0TypeDecl,\n                                   fieldNameType, tyType, tyTagType,\n                                   heap, classNameType, nameFamilyType,\n                                   datatypeType, handleType, layerType, dtCtorId,\n                                   allocField);\n      }\n      return null;\n    }\n\n    static Bpl.Program ReadPrelude() {\n      string preludePath = ArmadaOptions.O.DafnyPrelude;\n      if (preludePath == null)\n      {\n          //using (System.IO.Stream stream = cce.NonNull( System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(\"DafnyPrelude.bpl\")) // Use this once Spec#/VSIP supports designating a non-.resx project item as an embedded resource\n          string codebase = cce.NonNull(System.IO.Path.GetDirectoryName(cce.NonNull(System.Reflection.Assembly.GetExecutingAssembly().Location)));\n          preludePath = System.IO.Path.Combine(codebase, \"DafnyPrelude.bpl\");\n      }\n\n      Bpl.Program prelude;\n      var defines = new List<string>();\n      if (6 <= ArmadaOptions.O.ArithMode) {\n        defines.Add(\"ARITH_DISTR\");\n      }\n      if (8 <= ArmadaOptions.O.ArithMode) {\n        defines.Add(\"ARITH_MUL_DIV_MOD\");\n      }\n      if (9 <= ArmadaOptions.O.ArithMode) {\n        defines.Add(\"ARITH_MUL_SIGN\");\n      }\n      if (10 <= ArmadaOptions.O.ArithMode) {\n        defines.Add(\"ARITH_MUL_COMM\");\n        defines.Add(\"ARITH_MUL_ASSOC\");\n      }\n      int errorCount = BplParser.Parse(preludePath, defines, out prelude);\n      if (prelude == null || errorCount > 0) {\n        return null;\n      } else {\n        return prelude;\n      }\n    }\n\n    public Bpl.IdentifierExpr TrVar(IToken tok, IVariable var) {\n      Contract.Requires(var != null);\n      Contract.Requires(tok != null);\n      Contract.Ensures(Contract.Result<Bpl.IdentifierExpr>() != null);\n      return new Bpl.IdentifierExpr(tok, var.AssignUniqueName(currentDeclaration.IdGenerator), TrType(var.Type));\n    }\n\n    private Bpl.Program DoTranslation(Program p, ModuleDefinition forModule) {\n      program = p;\n      Type.EnableScopes();\n\n      EstablishModuleScope(p.BuiltIns.SystemModule, forModule);\n      Type.PushScope(this.currentScope);\n\n      foreach (var w in program.BuiltIns.Bitwidths) {\n        // bitwise operations\n        AddBitvectorFunction(w, \"and_bv\", \"bvand\");\n        AddBitvectorFunction(w, \"or_bv\", \"bvor\");\n        AddBitvectorFunction(w, \"xor_bv\", \"bvxor\");  // Z3 supports this, but it seems not to be in the SMT-LIB 2 standard\n        AddBitvectorFunction(w, \"not_bv\", \"bvnot\", false);\n        // arithmetic operations\n        AddBitvectorFunction(w, \"add_bv\", \"bvadd\");\n        AddBitvectorFunction(w, \"sub_bv\", \"bvsub\");  // Z3 supports this, but it seems not to be in the SMT-LIB 2 standard\n        AddBitvectorFunction(w, \"mul_bv\", \"bvmul\");\n        AddBitvectorFunction(w, \"div_bv\", \"bvudiv\");\n        AddBitvectorFunction(w, \"mod_bv\", \"bvurem\");\n        // comparisons\n        AddBitvectorFunction(w, \"lt_bv\", \"bvult\", true, Bpl.Type.Bool, false);\n        AddBitvectorFunction(w, \"le_bv\", \"bvule\", true, Bpl.Type.Bool, true);  // Z3 supports this, but it seems not to be in the SMT-LIB 2 standard\n        AddBitvectorFunction(w, \"ge_bv\", \"bvuge\", true, Bpl.Type.Bool, true);  // Z3 supports this, but it seems not to be in the SMT-LIB 2 standard\n        AddBitvectorFunction(w, \"gt_bv\", \"bvugt\", true, Bpl.Type.Bool, false);  // Z3 supports this, but it seems not to be in the SMT-LIB 2 standard\n        // shifts\n        AddBitvectorShiftFunction(w, \"LeftShift_bv\", \"bvshl\");\n        AddBitvectorShiftFunction(w, \"RightShift_bv\", \"bvlshr\");\n        // rotates\n        AddBitvectorShiftFunction(w, \"LeftRotate_bv\", \"ext_rotate_left\");\n        AddBitvectorShiftFunction(w, \"RightRotate_bv\", \"ext_rotate_right\");\n        // conversion functions\n        AddBitvectorNatConversionFunction(w);\n      }\n\n      foreach (TopLevelDecl d in program.BuiltIns.SystemModule.TopLevelDecls) {\n        currentDeclaration = d;\n        if (d is OpaqueTypeDecl) {\n          AddTypeDecl((OpaqueTypeDecl)d);\n        } else if (d is NewtypeDecl) {\n          var dd = (NewtypeDecl)d;\n          AddTypeDecl(dd);\n          AddClassMembers(dd, true);\n        } else if (d is SubsetTypeDecl) {\n          AddTypeDecl((SubsetTypeDecl)d);\n        } else if (d is TypeSynonymDecl) {\n          // do nothing, just bypass type synonyms in the translation\n        } else if (d is DatatypeDecl) {\n          var dd = (DatatypeDecl)d;\n          AddDatatype(dd);\n          AddClassMembers(dd, true);\n        } else if (d is ArrowTypeDecl) {\n          var ad = (ArrowTypeDecl)d;\n          GetClassTyCon(ad);\n          AddArrowTypeAxioms(ad);\n        } else if (d is ClassDecl) {\n          var cl = (ClassDecl)d;\n          AddClassMembers(cl, true);\n          if (cl.NonNullTypeDecl != null) {\n            AddTypeDecl(cl.NonNullTypeDecl);\n          }\n        } else {\n          Contract.Assert(d is ValuetypeDecl);\n        }\n      }\n\n      ComputeFunctionFuel(); // compute which function needs fuel constants.\n\n      //translate us first\n      List<ModuleDefinition> mods = program.RawModules().ToList();\n      mods.Remove(forModule);\n      mods.Insert(0, forModule);\n\n      foreach (ModuleDefinition m in mods) {\n        foreach (TopLevelDecl d in m.TopLevelDecls.FindAll(VisibleInScope)) {\n          currentDeclaration = d;\n          if (d is OpaqueTypeDecl) {\n            AddTypeDecl((OpaqueTypeDecl)d);\n          } else if (d is RevealableTypeDecl) {\n            AddTypeDecl((RevealableTypeDecl)d);\n          } else if (d is ModuleDecl) {\n            // submodules have already been added as a top level module, ignore this.\n          } else if (d is ClassDecl) {\n            var cl = (ClassDecl)d;\n            AddClassMembers(cl, ArmadaOptions.O.OptimizeResolution < 1);\n            if (cl.NonNullTypeDecl != null) {\n              AddTypeDecl(cl.NonNullTypeDecl);\n            }\n            if (d is IteratorDecl) {\n              AddIteratorSpecAndBody((IteratorDecl)d);\n            }\n          } else {\n            Contract.Assert(false);\n          }\n        }\n      }\n\n\n      foreach (var c in fieldConstants.Values) {\n        sink.AddTopLevelDeclaration(c);\n      }\n\n      AddTraitParentAxioms();\n\n      if (InsertChecksums) {\n        foreach (var impl in sink.Implementations) {\n          if (impl.FindStringAttribute(\"checksum\") == null) {\n            impl.AddAttribute(\"checksum\", \"stable\");\n          }\n        }\n        foreach (var func in sink.Functions) {\n          if (func.FindStringAttribute(\"checksum\") == null) {\n            func.AddAttribute(\"checksum\", \"stable\");\n          }\n        }\n      }\n\n      Type.PopScope(this.currentScope);\n      Type.DisableScopes();\n      return sink;\n\n    }\n\n    // Don't verify modules which only contain other modules\n    private static bool ShouldVerifyModule(ModuleDefinition m) {\n      if (!m.IsToBeVerified && !ArmadaOptions.O.VerifyAllModules)\n        return false;\n\n      foreach (var top in m.TopLevelDecls) {\n        if (top is DefaultClassDecl) {\n          if (((DefaultClassDecl)top).Members.Count > 0) {\n            return true;\n          }\n        } else if (!(top is ModuleDecl)) {\n          return true;\n        }\n      }\n      return false;\n    }\n\n    public static IEnumerable<ModuleDefinition> VerifiableModules(Program p) {\n        return p.RawModules().Where(ShouldVerifyModule);\n    }\n\n    public static IEnumerable<Tuple<string, Bpl.Program>> Translate(Program p, ErrorReporter reporter, TranslatorFlags flags = null) {\n      Contract.Requires(p != null);\n      Contract.Requires(p.ModuleSigs.Count > 0);\n\n      Type.ResetScopes();\n\n      foreach (ModuleDefinition outerModule in VerifiableModules(p)) {\n\n        var translator = new Translator(reporter, flags);\n\n        if (translator.sink == null || translator.sink == null) {\n          // something went wrong during construction, which reads the prelude; an error has\n          // already been printed, so just return an empty program here (which is non-null)\n          yield return new Tuple<string,Bpl.Program>(outerModule.CompileName, new Bpl.Program());\n        }\n        yield return new Tuple<string, Bpl.Program>(outerModule.CompileName, translator.DoTranslation(p, outerModule));\n      }\n\n    }\n\n    public Bpl.Type BplBvType(int width) {\n      Contract.Requires(0 <= width);\n      if (width == 0) {\n        // Boogie claims to support bv0, but it translates it straight down to the SMT solver's 0-width bitvector type.\n        // However, the SMT-LIB 2 standard does not define such a bitvector width, so this is a bug in Boogie.  The\n        // best would be to fix this in Boogie, but for now, we simply work around it here.\n        return predef.Bv0Type;\n      } else {\n        return Bpl.Type.GetBvType(width);\n      }\n    }\n\n    internal Expr BplBvLiteralExpr(IToken tok, BaseTypes.BigNum n, BitvectorType bitvectorType) {\n      Contract.Requires(tok != null);\n      Contract.Requires(bitvectorType != null);\n      return BplBvLiteralExpr(tok, n, bitvectorType.Width);\n    }\n    internal Expr BplBvLiteralExpr(IToken tok, BaseTypes.BigNum n, int width) {\n      Contract.Requires(tok != null);\n      Contract.Requires(0 <= width);\n      if (width == 0) {\n        // see comment in BplBvType\n        Contract.Assert(n.IsZero);\n        return Bpl.Expr.Literal(0);\n      } else {\n        return new Bpl.LiteralExpr(tok, n, width);\n      }\n    }\n\n    /// <summary>\n    /// Declare and add to the sink a Boogie function named \"namePrefix + w\".\n    /// If \"binary\", then the function takes two arguments; otherwise, it takes one.  Arguments have the type\n    /// corresponding to the Dafny type for w-width bitvectors.\n    /// The function's result type is the same as the argument type, unless \"resultType\" is non-null, in which\n    /// case the function's result type is \"resultType\".\n    /// For w > 0:\n    ///     Attach an attribute {:bvbuiltin smtFunctionName}.\n    /// For w == 0:\n    ///     Attach an attribute {:inline} and add a .Body to the function.\n    ///     If \"resultType\" is null, then use 0 as the body; otherwise, use \"bodyForBv0\" as the body (which\n    ///     assumes \"resultType\" is actually Bpl.Type.Bool).\n    /// </summary>\n    private void AddBitvectorFunction(int w, string namePrefix, string smtFunctionName, bool binary = true, Bpl.Type resultType = null, bool bodyForBv0 = false) {\n      Contract.Requires(0 <= w);\n      Contract.Requires(namePrefix != null);\n      Contract.Requires(smtFunctionName != null);\n      var tok = Token.NoToken;\n      var t = BplBvType(w);\n      List<Bpl.Variable> args;\n      if (binary) {\n        var a0 = BplFormalVar(null, t, true);\n        var a1 = BplFormalVar(null, t, true);\n        args = new List<Variable>() { a0, a1 };\n      } else {\n        var a0 = BplFormalVar(null, t, true);\n        args = new List<Variable>() { a0 };\n      }\n      var r = BplFormalVar(null, resultType ?? t, false);\n      Bpl.QKeyValue attr;\n      if (w == 0) {\n        attr = new QKeyValue(tok, \"inline\", new List<object>(), null);\n      } else {\n        attr = new Bpl.QKeyValue(tok, \"bvbuiltin\", new List<object>() { smtFunctionName }, null);\n      }\n      var func = new Bpl.Function(tok, namePrefix + w, new List<TypeVariable>(), args, r, null, attr);\n      if (w == 0) {\n        if (resultType != null) {\n          func.Body = Bpl.Expr.Literal(bodyForBv0);\n        } else {\n          func.Body = BplBvLiteralExpr(tok, BaseTypes.BigNum.ZERO, w);\n        }\n      }\n      sink.AddTopLevelDeclaration(func);\n    }\n\n    private void AddBitvectorShiftFunction(int w, string namePrefix, string smtFunctionName) {\n      Contract.Requires(0 <= w);\n      Contract.Requires(namePrefix != null);\n      Contract.Requires(smtFunctionName != null);\n      var tok = Token.NoToken;\n      var t = BplBvType(w);\n      List<Bpl.Variable> args;\n      var a0 = BplFormalVar(null, t, true);\n      var a1 = BplFormalVar(null, t, true);\n      args = new List<Variable>() { a0, a1 };\n      var r = BplFormalVar(null, t, false);\n      Bpl.QKeyValue attr;\n      if (w == 0) {\n        attr = new QKeyValue(tok, \"inline\", new List<object>(), null);\n      } else {\n        attr = new Bpl.QKeyValue(tok, \"bvbuiltin\", new List<object>() { smtFunctionName }, null);\n      }\n      var func = new Bpl.Function(tok, namePrefix + w, new List<TypeVariable>(), args, r, null, attr);\n      if (w == 0) {\n        func.Body = BplBvLiteralExpr(tok, BaseTypes.BigNum.ZERO, w);\n      }\n      sink.AddTopLevelDeclaration(func);\n    }\n\n    private void AddBitvectorNatConversionFunction(int w) {\n      Contract.Requires(0 <= w);\n      var tok = Token.NoToken;\n      var bv = BplBvType(w);\n      Bpl.QKeyValue attr;\n      Bpl.Function func;\n\n      // function {:bvbuiltin \"(_ int2bv 67)\"} nat_to_bv67(int) : bv67;\n      // OR:\n      // function {:inline} nat_to_bv0(int) : Bv0 { ZERO }\n      if (w == 0) {\n        attr = new QKeyValue(tok, \"inline\", new List<object>(), null);\n      } else {\n        var smt_int2bv = string.Format(\"(_ int2bv {0})\", w);\n        attr = new Bpl.QKeyValue(tok, \"bvbuiltin\", new List<object>() { smt_int2bv }, null);  // SMT-LIB 2 calls this function nat2bv, but Z3 apparently calls it int2bv\n      }\n      func = new Bpl.Function(tok, \"nat_to_bv\" + w, new List<TypeVariable>(),\n        new List<Variable>() { BplFormalVar(null, Bpl.Type.Int, true) }, BplFormalVar(null, bv, false),\n        null, attr);\n      if (w == 0) {\n        func.Body = BplBvLiteralExpr(tok, BaseTypes.BigNum.ZERO, w);\n      }\n      sink.AddTopLevelDeclaration(func);\n\n      if (w == 0) {\n        // function {:inline} nat_from_bv0_smt(Bv0) : int { 0 }\n        attr = new QKeyValue(tok, \"inline\", new List<object>(), null);\n        func = new Bpl.Function(tok, \"nat_from_bv\" + w, new List<TypeVariable>(),\n          new List<Variable>() { BplFormalVar(null, bv, true) }, BplFormalVar(null, Bpl.Type.Int, false),\n          null, attr);\n        func.Body = Bpl.Expr.Literal(0);\n        sink.AddTopLevelDeclaration(func);\n      } else {\n        // function {:bvbuiltin \"bv2int\"} smt_nat_from_bv67(bv67) : int;\n        attr = new Bpl.QKeyValue(tok, \"bvbuiltin\", new List<object>() { \"bv2int\" }, null);  // SMT-LIB 2 calls this function bv2nat, but Z3 apparently calls it bv2int\n        var smtFunc = new Bpl.Function(tok, \"smt_nat_from_bv\" + w, new List<TypeVariable>(),\n          new List<Variable>() { BplFormalVar(null, bv, true) }, BplFormalVar(null, Bpl.Type.Int, false),\n          null, attr);\n        sink.AddTopLevelDeclaration(smtFunc);\n        // function nat_from_bv67(bv67) : int;\n        func = new Bpl.Function(tok, \"nat_from_bv\" + w, new List<TypeVariable>(),\n          new List<Variable>() { BplFormalVar(null, bv, true) }, BplFormalVar(null, Bpl.Type.Int, false),\n          null, null);\n        sink.AddTopLevelDeclaration(func);\n        // axiom (forall b: bv67 :: { nat_from_bv67(b) }\n        //          0 <= nat_from_bv67(b) && nat_from_bv67(b) < 0x8_0000_0000_0000_0000 &&\n        //          nat_from_bv67(b) == smt_nat_from_bv67(b));\n        var bVar = new Bpl.BoundVariable(tok, new Bpl.TypedIdent(tok, \"b\", BplBvType(w)));\n        var b = new Bpl.IdentifierExpr(tok, bVar);\n        var bv2nat = FunctionCall(tok, \"nat_from_bv\" + w, Bpl.Type.Int, b);\n        var smt_bv2nat = FunctionCall(tok, \"smt_nat_from_bv\" + w, Bpl.Type.Int, b);\n        var body = BplAnd(BplAnd(\n          Bpl.Expr.Le(Bpl.Expr.Literal(0), bv2nat),\n          Bpl.Expr.Lt(bv2nat, Bpl.Expr.Literal(BaseTypes.BigNum.FromBigInt(BigInteger.One << w)))),\n          Bpl.Expr.Eq(bv2nat, smt_bv2nat));\n        var ax = new Bpl.ForallExpr(tok, new List<Variable>() { bVar }, BplTrigger(bv2nat), body);\n        sink.AddTopLevelDeclaration(new Bpl.Axiom(tok, ax));\n      }\n    }\n\n    private void ComputeFunctionFuel() {\n      foreach (ModuleDefinition m in program.RawModules()) {\n        foreach (TopLevelDecl d in m.TopLevelDecls) {\n          if (d is ClassDecl) {\n            ClassDecl c = (ClassDecl)d;\n            foreach (MemberDecl member in c.Members) {\n              if (member is Function && RevealedInScope(member)) {\n                Function f = (Function)member;\n                // declare the fuel constant\n                if (f.IsFueled) {\n                  // const BaseFuel_FunctionA : LayerType\n                  Bpl.Constant baseFuel = new Bpl.Constant(f.tok, new Bpl.TypedIdent(f.tok, \"BaseFuel_\" + f.FullName, predef.LayerType), false);\n                  sink.AddTopLevelDeclaration(baseFuel);\n                  Bpl.Expr baseFuel_expr = new Bpl.IdentifierExpr(f.tok, baseFuel);\n                  // const StartFuel_FunctionA : LayerType\n                  Bpl.Constant startFuel = new Bpl.Constant(f.tok, new Bpl.TypedIdent(f.tok, \"StartFuel_\" + f.FullName, predef.LayerType), false);\n                  sink.AddTopLevelDeclaration(startFuel);\n                  Bpl.Expr startFuel_expr = new Bpl.IdentifierExpr(f.tok, startFuel);\n                  // const StartFuelAssert_FunctionA : LayerType\n                  Bpl.Constant startFuelAssert = new Bpl.Constant(f.tok, new Bpl.TypedIdent(f.tok, \"StartFuelAssert_\" + f.FullName, predef.LayerType), false);\n                  sink.AddTopLevelDeclaration(startFuelAssert);\n                  Bpl.Expr startFuelAssert_expr = new Bpl.IdentifierExpr(f.tok, startFuelAssert);\n                  this.functionFuel.Add(new FuelConstant(f, baseFuel_expr, startFuel_expr, startFuelAssert_expr));\n                }\n              }\n            }\n          }\n        }\n      }\n    }\n\n    /// <summary>\n    /// adding TraitParent axioms\n    /// if a class A extends trait J and B does not extend anything, then this method adds the followings to the sink:\n    ///   axiom TraitParent(class.A) == class.J;\n    ///   axiom TraitParent(class.B) == NoTraitAtAll;\n    /// </summary>\n    private void AddTraitParentAxioms()\n    {\n        foreach (ModuleDefinition m in program.RawModules())\n        {\n            if (m.TopLevelDecls.Any(d => (d is ClassDecl && ((ClassDecl)d).TraitsObj.Count > 0) || (d is TraitDecl)))\n            {\n                foreach (TopLevelDecl d in m.TopLevelDecls)\n                {\n                  if (!VisibleInScope(d)) {\n                    continue;\n                  }\n                    if (d is ClassDecl)\n                    {\n                        var c = (ClassDecl)d;\n                        if (c.TraitsObj.Count > 0)\n                        {\n                            foreach (TraitDecl traitObj in c.TraitsObj)\n                            {\n                              if (!VisibleInScope(traitObj)) {\n                                continue;\n                              }\n                              //this adds: axiom TraitParent(class.A) == class.J; Where A extends J\n                              Bpl.Constant trait = GetClass(traitObj);\n                              Bpl.Expr traitId_expr = new Bpl.IdentifierExpr(traitObj.tok, trait);\n\n                              var id = new Bpl.IdentifierExpr(c.tok, GetClass(c));\n                              var funCallExpr = FunctionCall(c.tok, BuiltinFunction.TraitParent, null, id);\n                              var traitParentAxiom = new Bpl.Axiom(c.tok, Bpl.Expr.Eq(funCallExpr, traitId_expr));\n\n                              sink.AddTopLevelDeclaration(traitParentAxiom);\n                            }\n                        }\n                        else\n                        {\n                          var id = new Bpl.IdentifierExpr(c.tok, GetClass(c));\n                          var funCallExpr = FunctionCall(c.tok, BuiltinFunction.TraitParent, null, id);\n                          var traitParentAxiom = new Bpl.Axiom(c.tok, Bpl.Expr.Eq(funCallExpr, predef.NoTraitAtAll));\n\n                          sink.AddTopLevelDeclaration(traitParentAxiom);\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    /// <summary>\n    /// Construct an expression denoting the equality of e0 and e1, taking advantage of\n    /// any available extensional equality based on the given Dafny type.\n    /// </summary>\n    public Expr TypeSpecificEqual(IToken tok, Microsoft.Armada.Type type, Expr e0, Expr e1) {\n      Contract.Requires(tok != null);\n      Contract.Requires(type != null);\n      Contract.Requires(e0 != null);\n      Contract.Requires(e1 != null);\n\n      if (type.AsSetType != null) {\n        var finite = type.AsSetType.Finite;\n        return FunctionCall(tok, finite ? BuiltinFunction.SetEqual : BuiltinFunction.ISetEqual, null, e0, e1);\n      } else if (type.AsMapType != null) {\n        var finite = type.AsMapType.Finite;\n        return FunctionCall(tok, finite ? BuiltinFunction.MapEqual : BuiltinFunction.IMapEqual, null, e0, e1);\n      } else if (type.AsMultiSetType != null) {\n         return FunctionCall(tok, BuiltinFunction.MultiSetEqual, null, e0, e1);\n      } else if (type.AsSeqType != null) {\n        return FunctionCall(tok, BuiltinFunction.SeqEqual, null, e0, e1);\n      } else if (type.IsIndDatatype) {\n        return FunctionCall(tok, type.AsIndDatatype.FullSanitizedName + \"#Equal\", Bpl.Type.Bool, e0, e1);\n      } else {\n        return Bpl.Expr.Eq(e0, e1);\n      }\n    }\n\n    void AddTypeDecl_Aux(IToken tok, string nm, List<TypeParameter> typeArgs) {\n      Contract.Requires(tok != null);\n      Contract.Requires(nm != null);\n      Contract.Requires(typeArgs != null);\n\n      if (abstractTypes.Contains(nm)) {\n        // nothing to do; has already been added\n        return;\n      }\n      if (typeArgs.Count == 0) {\n        sink.AddTopLevelDeclaration(\n          new Bpl.Constant(tok,\n            new TypedIdent(tok, nm, predef.Ty), false /* not unique */));\n      } else {\n        // Note, the function produced is NOT necessarily injective, because the type may be replaced\n        // in a refinement module in such a way that the type arguments do not matter.\n        var args = new List<Bpl.Variable>(typeArgs.ConvertAll(a => (Bpl.Variable)BplFormalVar(null, predef.Ty, true)));\n        var func = new Bpl.Function(tok, nm, args, BplFormalVar(null, predef.Ty, false));\n        sink.AddTopLevelDeclaration(func);\n      }\n      abstractTypes.Add(nm);\n    }\n\n    void AddTypeDecl(OpaqueTypeDecl td) {\n      Contract.Requires(td != null);\n      var nm = nameTypeParam(td.TheType);\n      AddTypeDecl_Aux(td.tok, nameTypeParam(td.TheType), td.TypeArgs);\n    }\n\n\n    void AddTypeDecl(InternalTypeSynonymDecl td) {\n      Contract.Requires(td != null);\n      Contract.Requires(!RevealedInScope(td));\n      AddTypeDecl_Aux(td.tok, \"#$\" + td.Name, td.TypeArgs);\n    }\n\n    void AddTypeDecl(RevealableTypeDecl d) {\n      Contract.Requires(d != null);\n      if (RevealedInScope(d)) {\n        if (d is NewtypeDecl) {\n          var dd = (NewtypeDecl)d;\n          AddTypeDecl(dd);\n          AddClassMembers(dd, true);\n        } else if (d is DatatypeDecl) {\n          var dd = (DatatypeDecl)d;\n          AddDatatype(dd);\n          AddClassMembers(dd, true);\n        } else if (d is SubsetTypeDecl) {\n          AddTypeDecl((SubsetTypeDecl)d);\n        } else if (d is TypeSynonymDecl) {\n          //do nothing, this type will be transparent to translation\n        } else {\n          Contract.Assert(false);\n        }\n      } else {\n        AddTypeDecl(d.SelfSynonymDecl());\n      }\n    }\n\n    void AddTypeDecl(NewtypeDecl dd) {\n      Contract.Requires(dd != null);\n      Contract.Ensures(fuelContext == Contract.OldValue(fuelContext));\n\n      FuelContext oldFuelContext = this.fuelContext;\n      this.fuelContext = FuelSetting.NewFuelContext(dd);\n\n      if (dd.Var != null) {\n        AddWellformednessCheck(dd);\n        currentModule = dd.Module;\n        // Add $Is and $IsAlloc axioms for the newtype\n        AddRedirectingTypeDeclAxioms(false, dd, dd.FullName);\n        AddRedirectingTypeDeclAxioms(true, dd, dd.FullName);\n        currentModule = null;\n      }\n      this.fuelContext = oldFuelContext;\n    }\n\n    void AddTypeDecl(SubsetTypeDecl dd) {\n      Contract.Requires(dd != null);\n      Contract.Ensures(fuelContext == Contract.OldValue(fuelContext));\n\n      FuelContext oldFuelContext = this.fuelContext;\n      this.fuelContext = FuelSetting.NewFuelContext(dd);\n\n      if (!Attributes.Contains(dd.Attributes, \"axiom\")) {\n        AddWellformednessCheck(dd);\n      }\n      currentModule = dd.Module;\n      // Add $Is and $IsAlloc axioms for the subset type\n      AddRedirectingTypeDeclAxioms(false, dd, dd.FullName);\n      AddRedirectingTypeDeclAxioms(true, dd, dd.FullName);\n      currentModule = null;\n      this.fuelContext = oldFuelContext;\n    }\n    void AddRedirectingTypeDeclAxioms<T>(bool is_alloc, T dd, string fullName) where T : TopLevelDecl, RedirectingTypeDecl {\n      Contract.Requires(dd != null);\n      Contract.Requires(dd.Var != null && dd.Constraint != null);\n      Contract.Requires(fullName != null);\n\n      List<Bpl.Expr> typeArgs;\n      var vars = MkTyParamBinders(dd.TypeArgs, out typeArgs);\n      var o_ty = ClassTyCon(dd, typeArgs);\n\n      var oBplType = TrType(dd.Var.Type);\n      var o = BplBoundVar(dd.Var.AssignUniqueName(dd.IdGenerator), oBplType, vars);\n\n      Bpl.Expr body, is_o;\n      string name = string.Format(\"{0}: {1} \", fullName, dd.WhatKind);\n\n      if (is_alloc) {\n        name += \"$IsAlloc\";\n        var h = BplBoundVar(\"$h\", predef.HeapType, vars);\n        // $IsAlloc(o, ..)\n        is_o = MkIsAlloc(o, o_ty, h, ModeledAsBoxType(dd.Var.Type));\n        if (dd.Var.Type.IsNumericBased() || dd.Var.Type.IsBitVectorType || dd.Var.Type.IsBoolType || dd.Var.Type.IsCharType) {\n          body = is_o;\n        } else {\n          Bpl.Expr rhs = MkIsAlloc(o, dd.Var.Type, h);\n          body = BplIff(is_o, rhs);\n        }\n      } else {\n        name += \"$Is\";\n        // $Is(o, ..)\n        is_o = MkIs(o, o_ty, ModeledAsBoxType(dd.Var.Type));\n        var etran = new ExpressionTranslator(this, predef, new Bpl.IdentifierExpr(dd.tok, \"$OneHeap\", predef.HeapType));\n        Bpl.Expr parentConstraint, constraint;\n        if (dd.Var.Type.IsNumericBased() || dd.Var.Type.IsBitVectorType || dd.Var.Type.IsBoolType) {\n          // optimize this to only use the numeric/bitvector constraint, not the whole $Is thing on the base type\n          parentConstraint = Bpl.Expr.True;\n          var udt = UserDefinedType.FromTopLevelDecl(dd.tok, dd);\n          var c = Resolver.GetImpliedTypeConstraint(dd.Var, udt);\n          constraint = etran.TrExpr(c);\n        } else {\n          parentConstraint = MkIs(o, dd.Var.Type);\n          // conjoin the constraint\n          constraint = etran.TrExpr(dd.Constraint);\n        }\n        body = BplIff(is_o, BplAnd(parentConstraint, constraint));\n      }\n\n      sink.AddTopLevelDeclaration(new Bpl.Axiom(dd.tok, BplForall(vars, BplTrigger(is_o), body), name));\n    }\n\n    void AddDatatype(DatatypeDecl dt) {\n      Contract.Requires(dt != null);\n      Contract.Requires(sink != null && predef != null);\n\n      foreach (DatatypeCtor ctor in dt.Ctors) {\n        // Add:  function #dt.ctor(tyVars, paramTypes) returns (DatatypeType);\n\n        List<Bpl.Variable> argTypes = new List<Bpl.Variable>();\n        foreach (Formal arg in ctor.Formals) {\n          Bpl.Variable a = new Bpl.Formal(arg.tok, new Bpl.TypedIdent(arg.tok, Bpl.TypedIdent.NoName, TrType(arg.Type)), true);\n          argTypes.Add(a);\n        }\n        Bpl.Variable resType = new Bpl.Formal(ctor.tok, new Bpl.TypedIdent(ctor.tok, Bpl.TypedIdent.NoName, predef.DatatypeType), false);\n        Bpl.Function fn = new Bpl.Function(ctor.tok, ctor.FullName, argTypes, resType, \"Constructor function declaration\");\n        if (InsertChecksums) {\n          InsertChecksum(dt, fn);\n        }\n        sink.AddTopLevelDeclaration(fn);\n\n        List<Bpl.Variable> bvs;\n        List<Bpl.Expr> args;\n\n\n        {\n          // Add:  const unique ##dt.ctor: DtCtorId;\n          Bpl.Constant cid = new Bpl.Constant(ctor.tok, new Bpl.TypedIdent(ctor.tok, \"#\" + ctor.FullName, predef.DtCtorId), true);\n          Bpl.Expr c = new Bpl.IdentifierExpr(ctor.tok, cid);\n          sink.AddTopLevelDeclaration(cid);\n\n          {\n            // Add:  axiom (forall params :: DatatypeCtorId(#dt.ctor(params)) == ##dt.ctor);\n            CreateBoundVariables(ctor.Formals, out bvs, out args);\n            var constructor_call = FunctionCall(ctor.tok, ctor.FullName, predef.DatatypeType, args);\n            var lhs = FunctionCall(ctor.tok, BuiltinFunction.DatatypeCtorId, null, constructor_call);\n            Bpl.Expr q = Bpl.Expr.Eq(lhs, c);\n            var trigger = BplTrigger(constructor_call);\n            sink.AddTopLevelDeclaration(new Bpl.Axiom(ctor.tok, BplForall(bvs, trigger, q), \"Constructor identifier\"));\n          }\n\n          {\n            // Add:  function dt.ctor?(this: DatatypeType): bool { DatatypeCtorId(this) == ##dt.ctor }\n            fn = GetReadonlyField(ctor.QueryField);\n            sink.AddTopLevelDeclaration(fn);\n\n            // and here comes the associated axiom:\n\n            Bpl.Expr th; var thVar = BplBoundVar(\"d\", predef.DatatypeType, out th);\n            var queryPredicate = FunctionCall(ctor.tok, fn.Name, Bpl.Type.Bool, th);\n            var ctorId = FunctionCall(ctor.tok, BuiltinFunction.DatatypeCtorId, null, th);\n            var rhs = Bpl.Expr.Eq(ctorId, c);\n            var body = Bpl.Expr.Iff(queryPredicate, rhs);\n            var tr = BplTrigger(queryPredicate);\n            var ax = BplForall(thVar, tr, body);\n            sink.AddTopLevelDeclaration(new Bpl.Axiom(ctor.tok, ax, \"Questionmark and identifier\"));\n          }\n\n        }\n\n\n        {\n          // Add:  axiom (forall d: DatatypeType :: dt.ctor?(d) ==> (exists params :: d == #dt.ctor(params));\n          CreateBoundVariables(ctor.Formals, out bvs, out args);\n          Bpl.Expr rhs = FunctionCall(ctor.tok, ctor.FullName, predef.DatatypeType, args);\n          Bpl.Expr dId; var dBv = BplBoundVar(\"d\", predef.DatatypeType, out dId);\n          Bpl.Expr q = Bpl.Expr.Eq(dId, rhs);\n          if (bvs.Count != 0) {\n            q = new Bpl.ExistsExpr(ctor.tok, bvs, null/*always in a Skolemization context*/, q);\n          }\n          Bpl.Expr dtq = FunctionCall(ctor.tok, ctor.QueryField.FullSanitizedName, Bpl.Type.Bool, dId);\n          var trigger = BplTrigger(dtq);\n          q = BplForall(dBv, trigger, BplImp(dtq, q));\n          sink.AddTopLevelDeclaration(new Bpl.Axiom(ctor.tok, q, \"Constructor questionmark has arguments\"));\n        }\n\n        MapM(Bools, is_alloc => {\n          /*\n            (forall x0 : C0, ..., xn : Cn, G : Ty •\n              { $Is(C(x0,...,xn), T(G)) }\n              $Is(C(x0,...,xn), T(G)) <==>\n              $Is[Box](x0, C0(G)) && ... && $Is[Box](xn, Cn(G)));\n            (forall x0 : C0, ..., xn : Cn, G : Ty, H : Heap •\n                { $IsAlloc(C(G, x0,...,xn), T(G), H) }\n                IsGoodHeap(H) ==>\n                   ($IsAlloc(C(G, x0,...,xn), T(G), H) <==>\n                    $IsAlloc[Box](x0, C0(G), H) && ... && $IsAlloc[Box](xn, Cn(G), H)));\n          */\n          List<Bpl.Expr> tyexprs;\n          var tyvars = MkTyParamBinders(dt.TypeArgs, out tyexprs);\n          CreateBoundVariables(ctor.Formals, out bvs, out args);\n          Bpl.Expr h;\n          var hVar = BplBoundVar(\"$h\", predef.HeapType, out h);\n          Bpl.Expr conj = Bpl.Expr.True;\n          for (var i = 0; i < ctor.Formals.Count; i++) {\n            var arg = ctor.Formals[i];\n            if (is_alloc) {\n              if (CommonHeapUse || (NonGhostsUseHeap && !arg.IsGhost)) {\n                conj = BplAnd(conj, MkIsAlloc(args[i], arg.Type, h));\n              }\n            } else {\n              conj = BplAnd(conj, MkIs(args[i], arg.Type));\n            }\n          }\n          var c_params = FunctionCall(ctor.tok, ctor.FullName, predef.DatatypeType, args);\n          var c_ty = ClassTyCon((TopLevelDecl)dt, tyexprs);\n          bvs.InsertRange(0, tyvars);\n          if (!is_alloc) {\n            var c_is = MkIs(c_params, c_ty);\n            sink.AddTopLevelDeclaration(new Bpl.Axiom(ctor.tok,\n                BplForall(bvs, BplTrigger(c_is), BplIff(c_is, conj)),\n                \"Constructor $Is\"));\n          } else if (is_alloc && (CommonHeapUse || NonGhostsUseHeap)) {\n            var isGoodHeap = FunctionCall(ctor.tok, BuiltinFunction.IsGoodHeap, null, h);\n            var c_alloc = MkIsAlloc(c_params, c_ty, h);\n            bvs.Add(hVar);\n            sink.AddTopLevelDeclaration(new Bpl.Axiom(ctor.tok,\n                BplForall(bvs, BplTrigger(c_alloc),\n                               BplImp(isGoodHeap, BplIff(c_alloc, conj))),\n                \"Constructor $IsAlloc\"));\n          }\n          if (is_alloc && CommonHeapUse && !AlwaysUseHeap) {\n            for (int i = 0; i < ctor.Formals.Count; i++) {\n              var arg = ctor.Formals[i];\n              var dtor = GetReadonlyField(ctor.Destructors[i]);\n              /* (forall d : DatatypeType, G : Ty, H : Heap •\n                     { $IsAlloc[Box](Dtor(d), D(G), H) }\n                     IsGoodHeap(H) &&\n                     C?(d) &&\n                     (exists G' : Ty :: $IsAlloc(d, T(G,G'), H))\n                     ==>\n                         $IsAlloc[Box](Dtor(d), D(G), H))\n               */\n              Bpl.Expr dId; var dBv = BplBoundVar(\"d\", predef.DatatypeType, out dId);\n              var isGoodHeap = FunctionCall(ctor.tok, BuiltinFunction.IsGoodHeap, null, h);\n              Bpl.Expr dtq = FunctionCall(ctor.tok, ctor.QueryField.FullSanitizedName, Bpl.Type.Bool, dId);\n              var c_alloc = MkIsAlloc(dId, c_ty, h);\n              var dtorD = FunctionCall(ctor.tok, dtor.Name, TrType(arg.Type), dId);\n              var d_alloc = MkIsAlloc(dtorD, arg.Type, h);\n\n              // split tyvars into G,G' where G are the type variables that are used in the type of the destructor\n              var freeTypeVars = new HashSet<TypeParameter>();\n              ComputeFreeTypeVariables_All(arg.Type, freeTypeVars);\n              var tyvarsG = new List<Bpl.Variable>();\n              var tyvarsGprime = new List<Bpl.Variable>();\n              Contract.Assert(dt.TypeArgs.Count == tyvars.Count);\n              for (int j = 0; j < dt.TypeArgs.Count; j++) {\n                var tv = tyvars[j];\n                if (freeTypeVars.Contains(dt.TypeArgs[j])) {\n                  tyvarsG.Add(tv);\n                } else {\n                  tyvarsGprime.Add(tv);\n                }\n              }\n\n              bvs = new List<Bpl.Variable>();\n              bvs.Add(dBv);\n              bvs.AddRange(tyvarsG);\n              bvs.Add(hVar);\n              if (tyvarsGprime.Count != 0) {\n                c_alloc = new Bpl.ExistsExpr(ctor.tok, tyvarsGprime, BplTrigger(c_alloc), c_alloc);\n              }\n              sink.AddTopLevelDeclaration(new Bpl.Axiom(ctor.tok,\n                  BplForall(bvs, BplTrigger(d_alloc),\n                                 BplImp(BplAnd(isGoodHeap, BplAnd(dtq, c_alloc)), d_alloc)),\n                  \"Destructor $IsAlloc\"));\n            }\n          }\n        });\n\n        if (dt is IndDatatypeDecl) {\n          // Add Lit axiom:\n          // axiom (forall p0, ..., pn :: #dt.ctor(Lit(p0), ..., Lit(pn)) == Lit(#dt.ctor(p0, .., pn)));\n          CreateBoundVariables(ctor.Formals, out bvs, out args);\n          var litargs = new List<Bpl.Expr>();\n          foreach (Bpl.Expr arg in args) {\n            litargs.Add(Lit(arg));\n          }\n          Bpl.Expr lhs = FunctionCall(ctor.tok, ctor.FullName, predef.DatatypeType, litargs);\n          Bpl.Expr rhs = Lit(FunctionCall(ctor.tok, ctor.FullName, predef.DatatypeType, args), predef.DatatypeType);\n          Bpl.Expr q = BplForall(bvs, BplTrigger(lhs), Bpl.Expr.Eq(lhs, rhs));\n          sink.AddTopLevelDeclaration(new Bpl.Axiom(ctor.tok, q, \"Constructor literal\"));\n        }\n\n        // Injectivity axioms for normal arguments\n        for (int i = 0; i < ctor.Formals.Count; i++) {\n          var arg = ctor.Formals[i];\n          // function ##dt.ctor#i(DatatypeType) returns (Ti);\n          var sf = ctor.Destructors[i];\n          Contract.Assert(sf != null);\n          fn = GetReadonlyField(sf);\n          if (fn == predef.Tuple2Destructors0 || fn == predef.Tuple2Destructors1) {\n            // the two destructors for 2-tuples are predefined in Prelude for use\n            // by the Map#Items axiom\n          } else if (sf.EnclosingCtors[0] != ctor) {\n            // this special field, which comes from a shared destructor, is being declared in a different iteration of this loop\n          } else {\n            sink.AddTopLevelDeclaration(fn);\n          }\n          // axiom (forall params :: ##dt.ctor#i(#dt.ctor(params)) == params_i);\n          CreateBoundVariables(ctor.Formals, out bvs, out args);\n          var inner = FunctionCall(ctor.tok, ctor.FullName, predef.DatatypeType, args);\n          var outer = FunctionCall(ctor.tok, fn.Name, TrType(arg.Type), inner);\n          var q = BplForall(bvs, BplTrigger(inner), Bpl.Expr.Eq(outer, args[i]));\n          sink.AddTopLevelDeclaration(new Bpl.Axiom(ctor.tok, q, \"Constructor injectivity\"));\n\n          if (dt is IndDatatypeDecl) {\n            var argType = arg.Type.NormalizeExpandKeepConstraints();  // TODO: keep constraints -- really?  Write a test case\n            if (argType.IsDatatype || argType.IsTypeParameter) {\n              // for datatype:             axiom (forall params :: {#dt.ctor(params)} DtRank(params_i) < DtRank(#dt.ctor(params)));\n              // for type-parameter type:  axiom (forall params :: {#dt.ctor(params)} BoxRank(params_i) < DtRank(#dt.ctor(params)));\n              CreateBoundVariables(ctor.Formals, out bvs, out args);\n              Bpl.Expr lhs = FunctionCall(ctor.tok, arg.Type.IsDatatype ? BuiltinFunction.DtRank : BuiltinFunction.BoxRank, null, args[i]);\n              /* CHECK\n              Bpl.Expr lhs = FunctionCall(ctor.tok, BuiltinFunction.DtRank, null,\n                argType.IsDatatype ? args[i] : FunctionCall(ctor.tok, BuiltinFunction.Unbox, predef.DatatypeType, args[i]));\n              */\n              Bpl.Expr ct = FunctionCall(ctor.tok, ctor.FullName, predef.DatatypeType, args);\n              var rhs = FunctionCall(ctor.tok, BuiltinFunction.DtRank, null, ct);\n              var trigger = BplTrigger(ct);\n              q = new Bpl.ForallExpr(ctor.tok, bvs, trigger, Bpl.Expr.Lt(lhs, rhs));\n              sink.AddTopLevelDeclaration(new Bpl.Axiom(ctor.tok, q, \"Inductive rank\"));\n            } else if (argType is SeqType) {\n              // axiom (forall params, i: int {#dt.ctor(params)} :: 0 <= i && i < |arg| ==> DtRank(arg[i]) < DtRank(#dt.ctor(params)));\n              // that is:\n              // axiom (forall params, i: int {#dt.ctor(params)} :: 0 <= i && i < |arg| ==> DtRank(Unbox(Seq#Index(arg,i))) < DtRank(#dt.ctor(params)));\n              {\n                CreateBoundVariables(ctor.Formals, out bvs, out args);\n                Bpl.Variable iVar = new Bpl.BoundVariable(arg.tok, new Bpl.TypedIdent(arg.tok, \"i\", Bpl.Type.Int));\n                bvs.Add(iVar);\n                Bpl.IdentifierExpr ie = new Bpl.IdentifierExpr(arg.tok, iVar);\n                Bpl.Expr ante = Bpl.Expr.And(\n                  Bpl.Expr.Le(Bpl.Expr.Literal(0), ie),\n                  Bpl.Expr.Lt(ie, FunctionCall(arg.tok, BuiltinFunction.SeqLength, null, args[i])));\n                var seqIndex = FunctionCall(arg.tok, BuiltinFunction.SeqIndex, predef.DatatypeType, args[i], ie);\n                Bpl.Expr lhs = FunctionCall(ctor.tok, BuiltinFunction.DtRank, null,\n                  FunctionCall(arg.tok, BuiltinFunction.Unbox, predef.DatatypeType, seqIndex));\n                var ct = FunctionCall(ctor.tok, ctor.FullName, predef.DatatypeType, args);\n                var rhs = FunctionCall(ctor.tok, BuiltinFunction.DtRank, null, ct);\n                q = new Bpl.ForallExpr(ctor.tok, bvs, new Trigger(lhs.tok, true, new List<Bpl.Expr> { seqIndex, ct }), Bpl.Expr.Imp(ante, Bpl.Expr.Lt(lhs, rhs)));\n                sink.AddTopLevelDeclaration(new Bpl.Axiom(ctor.tok, q, \"Inductive seq element rank\"));\n              }\n\n              // axiom (forall params {#dt.ctor(params)} :: SeqRank(arg) < DtRank(#dt.ctor(params)));\n              {\n                CreateBoundVariables(ctor.Formals, out bvs, out args);\n                var lhs = FunctionCall(ctor.tok, BuiltinFunction.SeqRank, null, args[i]);\n                var ct = FunctionCall(ctor.tok, ctor.FullName, predef.DatatypeType, args);\n                var rhs = FunctionCall(ctor.tok, BuiltinFunction.DtRank, null, ct);\n                var trigger = BplTrigger(ct);\n                q = new Bpl.ForallExpr(ctor.tok, bvs, trigger, Bpl.Expr.Lt(lhs, rhs));\n                sink.AddTopLevelDeclaration(new Bpl.Axiom(ctor.tok, q, \"Inductive seq rank\"));\n              }\n            } else if (argType is SetType) {\n              // axiom (forall params, d: Datatype {arg[d], #dt.ctor(params)}  :: arg[d] ==> DtRank(d) < DtRank(#dt.ctor(params)));\n              // that is:\n              // axiom (forall params, d: Datatype {arg[Box(d)], #dt.ctor(params)} :: arg[Box(d)] ==> DtRank(d) < DtRank(#dt.ctor(params)));\n              CreateBoundVariables(ctor.Formals, out bvs, out args);\n              Bpl.Variable dVar = new Bpl.BoundVariable(arg.tok, new Bpl.TypedIdent(arg.tok, \"d\", predef.DatatypeType));\n              bvs.Add(dVar);\n              Bpl.IdentifierExpr ie = new Bpl.IdentifierExpr(arg.tok, dVar);\n              Bpl.Expr inSet = Bpl.Expr.SelectTok(arg.tok, args[i], FunctionCall(arg.tok, BuiltinFunction.Box, null, ie));\n              Bpl.Expr lhs = FunctionCall(ctor.tok, BuiltinFunction.DtRank, null, ie);\n              var ct = FunctionCall(ctor.tok, ctor.FullName, predef.DatatypeType, args);\n              var rhs = FunctionCall(ctor.tok, BuiltinFunction.DtRank, null, ct);\n              var trigger = new Bpl.Trigger(ctor.tok, true, new List<Bpl.Expr> { inSet, ct });\n              q = new Bpl.ForallExpr(ctor.tok, bvs, trigger, Bpl.Expr.Imp(inSet, Bpl.Expr.Lt(lhs, rhs)));\n              sink.AddTopLevelDeclaration(new Bpl.Axiom(ctor.tok, q, \"Inductive set element rank\"));\n            } else if (argType is MultiSetType) {\n              // axiom (forall params, d: Datatype {arg[d], #dt.ctor(params)} :: 0 < arg[d] ==> DtRank(d) < DtRank(#dt.ctor(params)));\n              // that is:\n              // axiom (forall params, d: Datatype {arg[Box(d)], #dt.ctor(params)} :: 0 < arg[Box(d)] ==> DtRank(d) < DtRank(#dt.ctor(params)));\n              CreateBoundVariables(ctor.Formals, out bvs, out args);\n              Bpl.Variable dVar = new Bpl.BoundVariable(arg.tok, new Bpl.TypedIdent(arg.tok, \"d\", predef.DatatypeType));\n              bvs.Add(dVar);\n              Bpl.IdentifierExpr ie = new Bpl.IdentifierExpr(arg.tok, dVar);\n              var inMultiset = Bpl.Expr.SelectTok(arg.tok, args[i], FunctionCall(arg.tok, BuiltinFunction.Box, null, ie));\n              Bpl.Expr ante = Bpl.Expr.Gt(inMultiset, Bpl.Expr.Literal(0));\n              Bpl.Expr lhs = FunctionCall(ctor.tok, BuiltinFunction.DtRank, null, ie);\n              var ct = FunctionCall(ctor.tok, ctor.FullName, predef.DatatypeType, args);\n              var rhs = FunctionCall(ctor.tok, BuiltinFunction.DtRank, null, ct);\n              var trigger = new Bpl.Trigger(ctor.tok, true, new List<Bpl.Expr> { inMultiset, ct });\n              q = new Bpl.ForallExpr(ctor.tok, bvs, trigger, Bpl.Expr.Imp(ante, Bpl.Expr.Lt(lhs, rhs)));\n              sink.AddTopLevelDeclaration(new Bpl.Axiom(ctor.tok, q, \"Inductive multiset element rank\"));\n            } else if (argType is MapType) {\n              var finite = ((MapType)argType).Finite;\n              {\n                // axiom (forall params, d: DatatypeType\n                //   { Map#Domain(arg)[$Box(d)], #dt.ctor(params) }\n                //   Map#Domain(arg)[$Box(d)] ==> DtRank(d) < DtRank(#dt.ctor(params)));\n                CreateBoundVariables(ctor.Formals, out bvs, out args);\n                var dVar = new Bpl.BoundVariable(arg.tok, new Bpl.TypedIdent(arg.tok, \"d\", predef.DatatypeType));\n                bvs.Add(dVar);\n                var ie = new Bpl.IdentifierExpr(arg.tok, dVar);\n                var f = finite ? BuiltinFunction.MapDomain : BuiltinFunction.IMapDomain;\n                var domain = FunctionCall(arg.tok, f, predef.MapType(arg.tok, finite, predef.BoxType, predef.BoxType), args[i]);\n                var inDomain = Bpl.Expr.SelectTok(arg.tok, domain, FunctionCall(arg.tok, BuiltinFunction.Box, null, ie));\n                var lhs = FunctionCall(ctor.tok, BuiltinFunction.DtRank, null, ie);\n                var ct = FunctionCall(ctor.tok, ctor.FullName, predef.DatatypeType, args);\n                var rhs = FunctionCall(ctor.tok, BuiltinFunction.DtRank, null, ct);\n                var trigger = new Bpl.Trigger(ctor.tok, true, new List<Bpl.Expr> { inDomain, ct });\n                q = new Bpl.ForallExpr(ctor.tok, bvs, trigger, Bpl.Expr.Imp(inDomain, Bpl.Expr.Lt(lhs, rhs)));\n                sink.AddTopLevelDeclaration(new Bpl.Axiom(ctor.tok, q, \"Inductive map key rank\"));\n              }\n              {\n                // axiom(forall params, bx: Box ::\n                //   { Map#Elements(arg)[bx], #dt.ctor(params) }\n                //   Map#Domain(arg)[bx] ==> DtRank($Unbox(Map#Elements(arg)[bx]): DatatypeType) < DtRank(#dt.ctor(params)));\n                CreateBoundVariables(ctor.Formals, out bvs, out args);\n                var bxVar = new Bpl.BoundVariable(arg.tok, new Bpl.TypedIdent(arg.tok, \"bx\", predef.BoxType));\n                bvs.Add(bxVar);\n                var ie = new Bpl.IdentifierExpr(arg.tok, bxVar);\n                var f = finite ? BuiltinFunction.MapDomain : BuiltinFunction.IMapDomain;\n                var domain = FunctionCall(arg.tok, f, predef.MapType(arg.tok, finite, predef.BoxType, predef.BoxType), args[i]);\n                var inDomain = Bpl.Expr.SelectTok(arg.tok, domain, ie);\n                var ef = finite ? BuiltinFunction.MapElements : BuiltinFunction.IMapElements;\n                var element = FunctionCall(arg.tok, ef, predef.MapType(arg.tok, finite, predef.BoxType, predef.BoxType), args[i]);\n                var elmt = Bpl.Expr.SelectTok(arg.tok, element, ie);\n                var unboxElmt = FunctionCall(arg.tok, BuiltinFunction.Unbox, predef.DatatypeType, elmt);\n                var lhs = FunctionCall(ctor.tok, BuiltinFunction.DtRank, null, unboxElmt);\n                var ct = FunctionCall(ctor.tok, ctor.FullName, predef.DatatypeType, args);\n                var rhs = FunctionCall(ctor.tok, BuiltinFunction.DtRank, null, ct);\n                var trigger = new Bpl.Trigger(ctor.tok, true, new List<Bpl.Expr> { inDomain, ct });\n                q = new Bpl.ForallExpr(ctor.tok, bvs, trigger, Bpl.Expr.Imp(inDomain, Bpl.Expr.Lt(lhs, rhs)));\n                sink.AddTopLevelDeclaration(new Bpl.Axiom(ctor.tok, q, \"Inductive map value rank\"));\n              }\n            }\n          }\n        }\n      }\n\n      {\n        // Add:\n        //   function $IsA#Dt(G: Ty,d: DatatypeType): bool {\n        //     Dt.Ctor0?(G, d) || Dt.Ctor1?(G, d) || ...\n        //   }\n        var cases_dBv = new Bpl.Formal(dt.tok, new Bpl.TypedIdent(dt.tok, Bpl.TypedIdent.NoName, predef.DatatypeType), true);\n        var cases_resType = new Bpl.Formal(dt.tok, new Bpl.TypedIdent(dt.tok, Bpl.TypedIdent.NoName, Bpl.Type.Bool), false);\n        var cases_fn = new Bpl.Function(dt.tok, \"$IsA#\" + dt.FullSanitizedName,\n                                        new List<Variable> { cases_dBv },\n                                        cases_resType,\n                                        \"Depth-one case-split function\");\n\n        if (InsertChecksums) {\n          InsertChecksum(dt, cases_fn);\n        }\n\n        sink.AddTopLevelDeclaration(cases_fn);\n        // and here comes the actual axiom:\n        {\n          Bpl.Expr d;\n          var dVar = BplBoundVar(\"d\", predef.DatatypeType, out d);\n          var lhs = FunctionCall(dt.tok, cases_fn.Name, Bpl.Type.Bool, d);\n          Bpl.Expr cases_body = Bpl.Expr.False;\n          foreach (DatatypeCtor ctor in dt.Ctors) {\n            var disj = FunctionCall(ctor.tok, ctor.QueryField.FullSanitizedName, Bpl.Type.Bool, d);\n            cases_body = BplOr(cases_body, disj);\n          }\n          var ax = BplForall(new List<Variable> { dVar }, BplTrigger(lhs), BplImp(lhs, cases_body));\n          sink.AddTopLevelDeclaration(new Bpl.Axiom(dt.tok, ax, \"Depth-one case-split axiom\"));\n        }\n      }\n\n      // The axiom above ($IsA#Dt(d) <==> Dt.Ctor0?(d) || Dt.Ctor1?(d)) gets triggered only with $IsA#Dt(d).  The $IsA#Dt(d)\n      // predicate is generated only where the translation inserts it; in other words, the user cannot write any assertion\n      // that causes the $IsA#Dt(d) predicate to be emitted.  This is what we want, because making the RHS disjunction be\n      // available too often makes performance go down.  However, we do want to allow the disjunction to be introduced if the\n      // user explicitly talks about one of its disjuncts.  To make this useful, we introduce the following axiom.  Note that\n      // the DtType(d) information is available everywhere.\n      // axiom (forall G: Ty, d: DatatypeType ::\n      //         { Dt.Ctor0?(G,d) }\n      //         { Dt.Ctor1?(G,d) }\n      //         $Is(d, T(G)) ==> Dt.Ctor0?(G,d) || Dt.Ctor1?(G,d) || ...);\n      {\n        List<Bpl.Expr> tyexprs;\n        var tyvars = MkTyParamBinders(dt.TypeArgs, out tyexprs);\n        Bpl.Expr d;\n        var dVar = BplBoundVar(\"d\", predef.DatatypeType, out d);\n        var d_is = MkIs(d, ClassTyCon(dt, tyexprs));\n        Bpl.Expr cases_body = Bpl.Expr.False;\n        Bpl.Trigger tr = null;\n        foreach (DatatypeCtor ctor in dt.Ctors) {\n          var disj = FunctionCall(ctor.tok, ctor.QueryField.FullSanitizedName, Bpl.Type.Bool, d);\n          cases_body = BplOr(cases_body, disj);\n          tr = new Bpl.Trigger(ctor.tok, true, new List<Bpl.Expr> { disj, d_is }, tr);\n        }\n        var body = Bpl.Expr.Imp(d_is, cases_body);\n        var ax = BplForall(Snoc(tyvars, dVar), tr, body);\n        sink.AddTopLevelDeclaration(new Bpl.Axiom(dt.tok, ax, \"Questionmark data type disjunctivity\"));\n      }\n\n      if (dt is IndDatatypeDecl) {\n        var dtEqualName = dt.FullSanitizedName + \"#Equal\";\n\n        // Add function Dt#Equal(DatatypeType, DatatypeType): bool;\n        // For each constructor Ctor(x: X, y: Y), add an axiom of the form\n        //     forall a, b ::\n        //       { Dt#Equal(a, b), Ctor?(a) }\n        //       { Dt#Equal(a, b), Ctor?(b) }\n        //       Ctor?(a) && Ctor?(b)\n        //       ==>\n        //       (Dt#Equal(a, b) <==>\n        //           X#Equal(a.x, b.x) &&\n        //           Y#Equal(a.y, b.y)\n        //       )\n        // where X#Equal is the equality predicate for type X and a.x denotes Dtor#x(a), and similarly\n        // for Y and b.\n        // Except, in the event that the datatype has exactly one constructor, then instead generate:\n        //     forall a, b ::\n        //       { Dt#Equal(a, b) }\n        //       true\n        //       ==>\n        //       ...as before\n        {\n          var args = new List<Variable>();\n          args.Add(new Bpl.Formal(dt.tok, new Bpl.TypedIdent(dt.tok, Bpl.TypedIdent.NoName, predef.DatatypeType), false));\n          args.Add(new Bpl.Formal(dt.tok, new Bpl.TypedIdent(dt.tok, Bpl.TypedIdent.NoName, predef.DatatypeType), false));\n          var ctorEqualResult = new Bpl.Formal(dt.tok, new Bpl.TypedIdent(dt.tok, Bpl.TypedIdent.NoName, Bpl.Type.Bool), false);\n          sink.AddTopLevelDeclaration(new Bpl.Function(dt.tok, dtEqualName, args, ctorEqualResult, \"Datatype extensional equality declaration\"));\n\n          Bpl.Expr a; var aVar = BplBoundVar(\"a\", predef.DatatypeType, out a);\n          Bpl.Expr b; var bVar = BplBoundVar(\"b\", predef.DatatypeType, out b);\n\n          var dtEqual = FunctionCall(dt.tok, dtEqualName, Bpl.Type.Bool, a, b);\n\n          foreach (var ctor in dt.Ctors) {\n            Bpl.Trigger trigger;\n            Bpl.Expr ante;\n            if (dt.Ctors.Count == 1) {\n              ante = Bpl.Expr.True;\n              trigger = BplTrigger(dtEqual);\n            } else {\n              var ctorQ = GetReadonlyField(ctor.QueryField);\n              var ctorQa = FunctionCall(ctor.tok, ctorQ.Name, Bpl.Type.Bool, a);\n              var ctorQb = FunctionCall(ctor.tok, ctorQ.Name, Bpl.Type.Bool, b);\n              ante = BplAnd(ctorQa, ctorQb);\n              trigger = dt.Ctors.Count == 1 ? BplTrigger(dtEqual) :\n                new Bpl.Trigger(ctor.tok, true, new List<Bpl.Expr> { dtEqual, ctorQa },\n                new Bpl.Trigger(ctor.tok, true, new List<Bpl.Expr> { dtEqual, ctorQb }));\n            }\n\n            Bpl.Expr eqs = Bpl.Expr.True;\n            for (var i = 0; i < ctor.Formals.Count; i++) {\n              var arg = ctor.Formals[i];\n              var dtor = GetReadonlyField(ctor.Destructors[i]);\n              var dtorA = FunctionCall(ctor.tok, dtor.Name, TrType(arg.Type), a);\n              var dtorB = FunctionCall(ctor.tok, dtor.Name, TrType(arg.Type), b);\n              var eq = TypeSpecificEqual(ctor.tok, arg.Type, dtorA, dtorB);\n              eqs = BplAnd(eqs, eq);\n            }\n\n            var ax = BplForall(new List<Variable> { aVar, bVar }, trigger, Bpl.Expr.Imp(ante, Bpl.Expr.Iff(dtEqual, eqs)));\n            sink.AddTopLevelDeclaration(new Bpl.Axiom(dt.tok, ax, string.Format(\"Datatype extensional equality definition: {0}\", ctor.FullName)));\n          }\n        }\n\n        // Add extensionality axiom: forall a, b :: { Dt#Equal(a, b) } Dt#Equal(a, b) <==> a == b\n        {\n          Bpl.Expr a; var aVar = BplBoundVar(\"a\", predef.DatatypeType, out a);\n          Bpl.Expr b; var bVar = BplBoundVar(\"b\", predef.DatatypeType, out b);\n\n          var lhs = FunctionCall(dt.tok, dtEqualName, Bpl.Type.Bool, a, b);\n          var rhs = Bpl.Expr.Eq(a, b);\n\n          var ax = BplForall(new List<Variable> { aVar, bVar }, BplTrigger(lhs), Bpl.Expr.Iff(lhs, rhs));\n          sink.AddTopLevelDeclaration(new Bpl.Axiom(dt.tok, ax, string.Format(\"Datatype extensionality axiom: {0}\", dt.FullName)));\n        }\n      }\n\n      if (dt is CoDatatypeDecl) {\n        var codecl = (CoDatatypeDecl)dt;\n\n        Func<Bpl.Expr, Bpl.Expr> MinusOne = k => {\n          if (k == null) {\n            return null;\n          } else if (k.Type.IsInt) {\n            return Bpl.Expr.Sub(k, Bpl.Expr.Literal(1));\n          } else {\n            return FunctionCall(k.tok, \"ORD#Minus\", k.Type, k, FunctionCall(k.tok, \"ORD#FromNat\", k.Type, Bpl.Expr.Literal(1)));\n          };\n        };\n\n        Action<Bpl.Type, Action<Tuple<List<Type>, List<Type>>, List<Bpl.Variable>, List<Bpl.Expr>, List<Bpl.Expr>, Bpl.Variable, Bpl.Expr, Bpl.Expr, Bpl.Expr, Bpl.Expr, Bpl.Expr, Bpl.Expr, Bpl.Expr, Bpl.Expr>> CoAxHelper = (typeOfK, K) => {\n          Func<string, List<TypeParameter>> renew = s =>\n            Map(codecl.TypeArgs, tp =>\n              new TypeParameter(tp.tok, tp.Name + \"#\" + s, tp.PositionalIndex, tp.Parent));\n          List<TypeParameter> typaramsL = renew(\"l\"), typaramsR = renew(\"r\");\n          List<Bpl.Expr> lexprs; var lvars = MkTyParamBinders(typaramsL, out lexprs);\n          List<Bpl.Expr> rexprs; var rvars = MkTyParamBinders(typaramsR, out rexprs);\n          Func<List<TypeParameter>, List<Type>> Types = l => Map(l, tp => (Type)new UserDefinedType(tp));\n          var tyargs = Tuple.Create(Types(typaramsL), Types(typaramsR));\n\n          var vars = Concat(lvars, rvars);\n\n          Bpl.Expr k, kIsValid, kIsNonZero, kHasSuccessor, kIsLimit;\n          Bpl.Variable kVar;\n          if (typeOfK != null) {\n            kVar = BplBoundVar(\"k\", typeOfK, out k); vars.Add(kVar);\n            if (typeOfK.IsInt) {\n              kIsValid = Bpl.Expr.Le(Bpl.Expr.Literal(0), k);\n              kIsNonZero = Bpl.Expr.Neq(Bpl.Expr.Literal(0), k);\n              kHasSuccessor = Bpl.Expr.Lt(Bpl.Expr.Literal(0), k);\n              kIsLimit = Bpl.Expr.False;\n            } else {\n              kIsValid = Bpl.Expr.True;\n              kIsNonZero = Bpl.Expr.Neq(k, FunctionCall(k.tok, \"ORD#FromNat\", Bpl.Type.Int, Bpl.Expr.Literal(0)));\n              kHasSuccessor = Bpl.Expr.Lt(Bpl.Expr.Literal(0), FunctionCall(k.tok, \"ORD#Offset\", Bpl.Type.Int, k));\n              kIsLimit = FunctionCall(k.tok, \"ORD#IsLimit\", Bpl.Type.Bool, k);\n            }\n          } else {\n            kVar = null; k = null;\n            kIsValid = Bpl.Expr.True;\n            kIsNonZero = Bpl.Expr.True;\n            kHasSuccessor = Bpl.Expr.True;\n            kIsLimit = Bpl.Expr.True;\n          }\n          var ly = BplBoundVar(\"ly\", predef.LayerType, vars);\n          var d0 = BplBoundVar(\"d0\", predef.DatatypeType, vars);\n          var d1 = BplBoundVar(\"d1\", predef.DatatypeType, vars);\n\n          K(tyargs, vars, lexprs, rexprs, kVar, k, kIsValid, kIsNonZero, kHasSuccessor, kIsLimit, ly, d0, d1);\n        };\n\n        Action<Bpl.Type> AddAxioms = typeOfK => {\n          {\n            // Add two copies of the type parameter lists!\n            var args = MkTyParamFormals(Concat(GetTypeParams(dt), GetTypeParams(dt)), false);\n            if (typeOfK != null) {\n              args.Add(BplFormalVar(null, typeOfK, true));\n            }\n            args.Add(BplFormalVar(null, predef.LayerType, true));\n            args.Add(BplFormalVar(null, predef.DatatypeType, true));\n            args.Add(BplFormalVar(null, predef.DatatypeType, true));\n            var r = BplFormalVar(null, Bpl.Type.Bool, false);\n            var fn_nm = typeOfK != null ? CoPrefixName(codecl) : CoEqualName(codecl);\n            var fn = new Bpl.Function(dt.tok, fn_nm, args, r);\n            if (InsertChecksums) {\n              InsertChecksum(dt, fn);\n            }\n            sink.AddTopLevelDeclaration(fn);\n          }\n\n          // axiom (forall G0,...,Gn : Ty, k: int, ly : Layer, d0, d1: DatatypeType ::\n          //  { Eq(G0, .., Gn, S(ly), k, d0, d1) }\n          //  Is(d0, T(G0, .., Gn)) && Is(d1, T(G0, ... Gn)) ==>\n          //  (Eq(G0, .., Gn, S(ly), k, d0, d1)\n          //    <==>\n          //      (0 < k.Offset ==>\n          //        (d0.Nil? && d1.Nil?) ||\n          //        (d0.Cons? && d1.Cons? && d0.head == d1.head && Eq(G0, .., Gn, ly, k-1, d0.tail, d1.tail))) &&\n          //      (k != 0 && k.IsLimit ==>                        // for prefix equality only\n          //        FullEq(G0, .., Gn, ly, d0.tail, d1.tail)))    // for prefix equality only\n          CoAxHelper(typeOfK, (tyargs, vars, lexprs, rexprs, kVar, k, kIsValid, kIsNonZero, kHasSuccessor, kIsLimit, ly, d0, d1) => {\n            var eqDt = CoEqualCall(codecl, lexprs, rexprs, k, LayerSucc(ly), d0, d1);\n            var iss = BplAnd(MkIs(d0, ClassTyCon(dt, lexprs)), MkIs(d1, ClassTyCon(dt, rexprs)));\n            var body = BplImp(\n              iss,\n              BplIff(eqDt,\n                BplAnd(\n                  BplImp(kHasSuccessor, BplOr(CoPrefixEquality(dt.tok, codecl, tyargs.Item1, tyargs.Item2, MinusOne(k), ly, d0, d1))),\n                  k == null ? Bpl.Expr.True : BplImp(BplAnd(kIsNonZero, kIsLimit), CoEqualCall(codecl, tyargs.Item1, tyargs.Item2, null, ly, d0, d1)))));\n            var ax = BplForall(vars, BplTrigger(eqDt), body);\n            sink.AddTopLevelDeclaration(new Bpl.Axiom(dt.tok, ax, \"Layered co-equality axiom\"));\n          });\n\n          // axiom (forall G0,...,Gn : Ty, k: int, ly : Layer, d0, d1: DatatypeType ::\n          //  { Eq(G0, .., Gn, S(ly), k, d0, d1) }\n          //    0 < k ==>\n          //      (Eq(G0, .., Gn, S(ly), k, d0, d1) <==>\n          //       Eq(G0, .., Gn, ly, k, d0, d))\n          CoAxHelper(typeOfK, (tyargs, vars, lexprs, rexprs, kVar, k, kIsValid, kIsNonZero, kHasSuccessor, kIsLimit, ly, d0, d1) => {\n            var eqDtSL = CoEqualCall(codecl, lexprs, rexprs, k, LayerSucc(ly), d0, d1);\n            var eqDtL  = CoEqualCall(codecl, lexprs, rexprs, k, ly, d0, d1);\n            var body = BplImp(kIsNonZero, BplIff(eqDtSL, eqDtL));\n            var ax = BplForall(vars, BplTrigger(eqDtSL), body);\n            sink.AddTopLevelDeclaration(new Bpl.Axiom(dt.tok, ax, \"Unbump layer co-equality axiom\"));\n          });\n        };\n\n        AddAxioms(null); // Add the above axioms for $Equal\n\n        // axiom (forall d0, d1: DatatypeType, k: int :: { $Equal(d0, d1) } :: Equal(d0, d1) <==> d0 == d1);\n        CoAxHelper(null, (tyargs, vars, lexprs, rexprs, kVar, k, kIsValid, kIsNonZero, kHasSuccessor, kIsLimit, ly, d0, d1) => {\n          var Eq = CoEqualCall(codecl, lexprs, rexprs, k, LayerSucc(ly), d0, d1);\n          var equal = Bpl.Expr.Eq(d0, d1);\n          sink.AddTopLevelDeclaration(new Axiom(dt.tok,\n            BplForall(vars, BplTrigger(Eq), BplIff(Eq, equal)),\n            \"Equality for codatatypes\"));\n        });\n\n        Bpl.Type theTypeOfK = predef.BigOrdinalType;\n        AddAxioms(predef.BigOrdinalType); // Add the above axioms for $PrefixEqual\n\n        // The connection between the full codatatype equality and its prefix version\n        // axiom (forall d0, d1: DatatypeType :: $Eq#Dt(d0, d1) <==>\n        //                                       (forall k: int :: 0 <= k ==> $PrefixEqual#Dt(k, d0, d1)));\n        CoAxHelper(theTypeOfK, (tyargs, vars, lexprs, rexprs, kVar, k, kIsValid, kIsNonZero, kHasSuccessor, kIsLimit, ly, d0, d1) => {\n          var Eq = CoEqualCall(codecl, lexprs, rexprs, null, LayerSucc(ly), d0, d1);\n          var PEq = CoEqualCall(codecl, lexprs, rexprs, k, LayerSucc(ly), d0, d1);\n          vars.Remove(kVar);\n          sink.AddTopLevelDeclaration(new Axiom(dt.tok,\n            BplForall(vars, BplTrigger(Eq), BplIff(Eq, BplForall(kVar, BplTrigger(PEq), BplImp(kIsValid, PEq)))),\n            \"Coequality and prefix equality connection\"));\n        });\n        // In addition, the following special case holds for $Eq#Dt:\n        // axiom (forall d0, d1: DatatypeType :: $Eq#Dt(d0, d1) <==\n        //                                       (forall k: int :: 0 <= k ==> $PrefixEqual#Dt(ORD#FromNat(k), d0, d1)));\n        if (!theTypeOfK.IsInt) {\n          CoAxHelper(Bpl.Type.Int, (tyargs, vars, lexprs, rexprs, kVar, k, kIsValid, kIsNonZero, kHasSuccessor, kIsLimit, ly, d0, d1) => {\n            var Eq = CoEqualCall(codecl, lexprs, rexprs, null, LayerSucc(ly), d0, d1);\n            var PEq = CoEqualCall(codecl, lexprs, rexprs, FunctionCall(k.tok, \"ORD#FromNat\", predef.BigOrdinalType, k), LayerSucc(ly), d0, d1);\n            vars.Remove(kVar);\n            sink.AddTopLevelDeclaration(new Axiom(dt.tok,\n              BplForall(vars, BplTrigger(Eq), BplImp(BplForall(kVar, BplTrigger(PEq), BplImp(kIsValid, PEq)), Eq)),\n              \"Coequality and prefix equality connection\"));\n          });\n        }\n\n        // A consequence of the definition of prefix equalities is the following:\n        // axiom (forall k, m: int, d0, d1: DatatypeType :: 0 <= k <= m && $PrefixEq#Dt(m, d0, d1) ==> $PrefixEq#0#Dt(k, d0, d1));\n        CoAxHelper(theTypeOfK, (tyargs, vars, lexprs, rexprs, kVar, k, kIsValid, kIsNonZero, kHasSuccessor, kIsLimit, ly, d0, d1) => {\n          var m = BplBoundVar(\"m\", k.Type, vars);\n          var PEqK = CoEqualCall(codecl, lexprs, rexprs, k, LayerSucc(ly), d0, d1);\n          var PEqM = CoEqualCall(codecl, lexprs, rexprs, m, LayerSucc(ly), d0, d1);\n          Bpl.Expr kLtM;\n          if (k.Type.IsInt) {\n            kLtM = Bpl.Expr.Lt(k, m);\n          } else {\n            kLtM = FunctionCall(dt.tok, \"ORD#Less\", Bpl.Type.Bool, k, m);\n          }\n          sink.AddTopLevelDeclaration(new Axiom(dt.tok,\n            BplForall(vars,\n            new Bpl.Trigger(dt.tok, true, new List<Bpl.Expr> { PEqK, PEqM }),\n            BplImp(BplAnd(BplAnd(kIsValid, kLtM), PEqM), PEqK)),\n            \"Prefix equality consequence\"));\n        });\n\n        // With the axioms above, going from d0==d1 to a prefix equality requires going via the full codatatype\n        // equality, which in turn requires the full codatatype equality to be present.  The following axiom\n        // provides a shortcut:\n        // axiom (forall d0, d1: DatatypeType, k: int :: d0 == d1 && 0 <= k ==> $PrefixEqual#_module.Stream(k, d0, d1));\n        CoAxHelper(theTypeOfK, (tyargs, vars, lexprs, rexprs, kVar, k, kIsValid, kIsNonZero, kHasSuccessor, kIsLimit, ly, d0, d1) => {\n          var equal = Bpl.Expr.Eq(d0, d1);\n          var PEq = CoEqualCall(codecl, lexprs, rexprs, k, LayerSucc(ly), d0, d1);\n          var trigger = BplTrigger(PEq);\n          sink.AddTopLevelDeclaration(new Axiom(dt.tok,\n            BplForall(vars, trigger, BplImp(BplAnd(equal, kIsValid), PEq)), \"Prefix equality shortcut\"));\n        });\n      }\n    }\n\n    /// <summary>\n    /// Return a sequence of expressions whose conjunction denotes a memberwise equality of \"dt\".  Recursive\n    /// codatatype equalities are written in one of the following ways:\n    /// If the codatatype equality is on a type outside the SCC of \"dt\", then resort to ordinary equality.\n    /// Else if the k==null, then:\n    ///   Depending on \"limited\", use the #2, #1, or #0 (limited) form of codatatype equality.\n    /// Else:\n    ///   Depending on \"limited\", use the #2, #1, or #0 (limited) form of prefix equality, passing \"k\"\n    ///   as the first argument.\n    /// </summary>\n    IEnumerable<Bpl.Expr> CoPrefixEquality(IToken tok, CoDatatypeDecl dt, List<Type> largs, List<Type> rargs, Bpl.Expr k, Bpl.Expr l, Bpl.Expr A, Bpl.Expr B, bool conjuncts = false) {\n      Contract.Requires(tok != null);\n      Contract.Requires(dt != null);\n      Contract.Requires(A != null);\n      Contract.Requires(B != null);\n      Contract.Requires(l != null);\n      Contract.Requires(predef != null);\n      var etran = new ExpressionTranslator(this, predef, dt.tok);\n      // For example, for possibly infinite lists:\n      //     codatatype SList<T> = Nil | SCons(head: T, tail: SList<T>);\n      // produce with conjucts=false (default):\n      //   (A.Nil? && B.Nil?) ||\n      //   (A.Cons? && B.Cons? && A.head == B.head && Equal(k, A.tail, B.tail))\n      //\n      // with conjuncts=true:\n      //   (A.Nil? ==> B.Nil?) &&\n      //   (A.Cons? ==> (B.Cons? && A.head == B.head && Equal(k, A.tail, B.tail)))\n\n      Dictionary<TypeParameter, Type> lsu = Util.Dict(GetTypeParams(dt), largs);\n      Dictionary<TypeParameter, Type> rsu = Util.Dict(GetTypeParams(dt), rargs);\n\n      foreach (var ctor in dt.Ctors) {\n        Bpl.Expr aq = new Bpl.NAryExpr(tok, new Bpl.FunctionCall(GetReadonlyField(ctor.QueryField)), new List<Bpl.Expr> { A });\n        Bpl.Expr bq = new Bpl.NAryExpr(tok, new Bpl.FunctionCall(GetReadonlyField(ctor.QueryField)), new List<Bpl.Expr> { B });\n        Bpl.Expr chunk = Bpl.Expr.True;\n        foreach (var dtor in ctor.Destructors) {  // note, ctor.Destructors has a field for every constructor parameter, whether or not the parameter was named in the source\n          var a = new Bpl.NAryExpr(tok, new Bpl.FunctionCall(GetReadonlyField(dtor)), new List<Bpl.Expr> { A });\n          var b = new Bpl.NAryExpr(tok, new Bpl.FunctionCall(GetReadonlyField(dtor)), new List<Bpl.Expr> { B });\n          var ty = dtor.Type;\n          Bpl.Expr q;\n          var codecl = ty.AsCoDatatype;\n          if (codecl != null && codecl.SscRepr == dt.SscRepr) {\n            var lexprs = Map(ty.TypeArgs, tt => Resolver.SubstType(tt, lsu));\n            var rexprs = Map(ty.TypeArgs, tt => Resolver.SubstType(tt, rsu));\n            q = CoEqualCall(codecl, lexprs, rexprs, k, l, a, b);\n          } else {\n            // ordinary equality; let the usual translation machinery figure out the translation\n            var equal = new BinaryExpr(tok, BinaryExpr.Opcode.Eq, new BoogieWrapper(a, ty), new BoogieWrapper(b, ty));\n            equal.ResolvedOp = Resolver.ResolveOp(equal.Op, ty);  // resolve here\n            equal.Type = Type.Bool;  // resolve here\n            q = etran.TrExpr(equal);\n          }\n          chunk = BplAnd(chunk, q);\n        }\n        if (conjuncts) {\n          yield return Bpl.Expr.Binary(new NestedToken(tok, ctor.tok), BinaryOperator.Opcode.Imp, aq, BplAnd(bq, chunk));\n        } else {\n          yield return BplAnd(BplAnd(aq, bq), BplImp(BplAnd(aq, bq), chunk));\n        }\n      }\n    }\n\n    public Bpl.Expr LayerSucc(Bpl.Expr e, int amt = 1) {\n      if (amt == 0) {\n        return e;\n      } else if (amt > 0) {\n        return FunctionCall(e.tok, BuiltinFunction.LayerSucc, null, LayerSucc(e, amt-1));\n      } else {\n        Contract.Assert(false);\n        return null;\n      }\n    }\n\n    // Makes a call to equality, if k is null, or otherwise prefix equality. For codatatypes.\n    Bpl.Expr CoEqualCall(CoDatatypeDecl codecl, List<Bpl.Expr> largs, List<Bpl.Expr> rargs, Bpl.Expr k, Bpl.Expr l, Bpl.Expr A, Bpl.Expr B, IToken tok = null) {\n      Contract.Requires(codecl != null);\n      Contract.Requires(largs != null);\n      Contract.Requires(rargs != null);\n      Contract.Requires(l != null);\n      Contract.Requires(A != null);\n      Contract.Requires(B != null);\n      if (tok == null) {\n        tok = A.tok;\n      }\n      List<Bpl.Expr> args = Concat(largs, rargs);\n      if (k != null) {\n        args.Add(k);\n      }\n      args.AddRange(new List<Bpl.Expr> { l, A, B });\n      var fn = k == null ? CoEqualName(codecl) : CoPrefixName(codecl);\n      return FunctionCall(tok, fn, Bpl.Type.Bool, args);\n    }\n\n    // Same as above, but with Dafny-typed type-argument lists\n    Bpl.Expr CoEqualCall(CoDatatypeDecl codecl, List<Type> largs, List<Type> rargs, Bpl.Expr k, Bpl.Expr l, Bpl.Expr A, Bpl.Expr B, IToken tok = null) {\n      Contract.Requires(codecl != null);\n      Contract.Requires(largs != null);\n      Contract.Requires(rargs != null);\n      Contract.Requires(l != null);\n      Contract.Requires(A != null);\n      Contract.Requires(B != null);\n      return CoEqualCall(codecl, Map(largs, TypeToTy), Map(rargs, TypeToTy), k, l, A, B, tok);\n    }\n\n    static string CoEqualName(CoDatatypeDecl codecl) {\n      Contract.Requires(codecl != null);\n      return \"$Eq#\" + codecl.FullSanitizedName;\n    }\n\n    static string CoPrefixName(CoDatatypeDecl codecl) {\n      Contract.Requires(codecl != null);\n      return \"$PrefixEq#\" + codecl.FullSanitizedName;\n    }\n\n    void CreateBoundVariables<VT>(List<VT> formals, out List<Variable> bvs, out List<Bpl.Expr> args) where VT : IVariable {\n      Contract.Requires(formals != null);\n      Contract.Ensures(Contract.ValueAtReturn(out bvs).Count == Contract.ValueAtReturn(out args).Count);\n      Contract.Ensures(Contract.ValueAtReturn(out bvs) != null);\n      Contract.Ensures(cce.NonNullElements(Contract.ValueAtReturn(out args)));\n\n      var varNameGen = CurrentIdGenerator.NestedFreshIdGenerator(\"a#\");\n      bvs = new List<Variable>();\n      args = new List<Bpl.Expr>();\n      foreach (var arg in formals) {\n        Contract.Assert(arg != null);\n        var nm = varNameGen.FreshId(string.Format(\"#{0}#\", bvs.Count));\n        Bpl.Variable bv = new Bpl.BoundVariable(arg.Tok, new Bpl.TypedIdent(arg.Tok, nm, TrType(arg.Type)));\n        bvs.Add(bv);\n        args.Add(new Bpl.IdentifierExpr(arg.Tok, bv));\n      }\n    }\n\n    // This one says that this is /directly/ allocated, not that its \"children\" are,\n    // i.e. h[x, alloc]\n    public Bpl.Expr IsAlloced(IToken tok, Bpl.Expr heapExpr, Bpl.Expr e) {\n      Contract.Requires(tok != null);\n      Contract.Requires(heapExpr != null);\n      Contract.Requires(e != null);\n      Contract.Ensures(Contract.Result<Bpl.Expr>() != null);\n\n      return ReadHeap(tok, heapExpr, e, predef.Alloc(tok));\n    }\n\n    public static Bpl.NAryExpr ReadHeap(IToken tok, Expr heap, Expr r, Expr f) {\n      Contract.Requires(tok != null);\n      Contract.Requires(heap != null);\n      Contract.Requires(r != null);\n      Contract.Requires(f != null);\n      Contract.Ensures(Contract.Result<Bpl.NAryExpr>() != null);\n\n      List<Bpl.Expr> args = new List<Bpl.Expr>();\n      args.Add(heap);\n      args.Add(r);\n      args.Add(f);\n      Bpl.Type t = (f.Type != null) ? f.Type : f.ShallowType;\n      return new Bpl.NAryExpr(tok,\n        new Bpl.FunctionCall(new Bpl.IdentifierExpr(tok, \"read\", t.AsCtor.Arguments[0])),\n        args);\n    }\n\n    public static Bpl.NAryExpr ReadHeap(IToken tok, Expr heap, Expr r)\n    {\n      Contract.Requires(tok != null);\n      Contract.Requires(heap != null);\n      Contract.Requires(r != null);\n      Contract.Ensures(Contract.Result<Bpl.NAryExpr>() != null);\n\n      List<Bpl.Expr> args = new List<Bpl.Expr>();\n      args.Add(heap);\n      args.Add(r);\n      return new Bpl.NAryExpr(tok,\n        new Bpl.MapSelect(tok, 1),\n        args);\n    }\n\n    public Bpl.Expr DType(Bpl.Expr e, Bpl.Expr type) {\n      return Bpl.Expr.Eq(FunctionCall(e.tok, BuiltinFunction.DynamicType, null, e), type);\n    }\n\n    public Bpl.Expr GetArrayIndexFieldName(IToken tok, List<Bpl.Expr> indices) {\n      Bpl.Expr fieldName = null;\n      foreach (Bpl.Expr index in indices) {\n        if (fieldName == null) {\n          // the index in dimension 0:  IndexField(index0)\n          fieldName = FunctionCall(tok, BuiltinFunction.IndexField, null, index);\n        } else {\n          // the index in dimension n:  MultiIndexField(...field name for first n indices..., index_n)\n          fieldName = FunctionCall(tok, BuiltinFunction.MultiIndexField, null, fieldName, index);\n        }\n      }\n      return fieldName;\n    }\n\n    void AddClassMembers(TopLevelDeclWithMembers c, bool includeMethods)\n    {\n      Contract.Requires(sink != null && predef != null);\n      Contract.Requires(c != null);\n      Contract.Ensures(fuelContext == Contract.OldValue(fuelContext));\n      Contract.Assert(VisibleInScope(c));\n\n      sink.AddTopLevelDeclaration(GetClass(c));\n      if (c is ArrayClassDecl) {\n        // classes.Add(c, predef.ClassDotArray);\n        AddAllocationAxiom(null, (ArrayClassDecl)c, true);\n      }\n\n      // Add $Is and $IsAlloc for this class :\n      //    axiom (forall p: ref, G: Ty ::\n      //       { $Is(p, TClassA(G), h) }\n      //       $Is(p, TClassA(G), h) <=> (p == null || dtype(p) == TClassA(G));\n      //    axiom (forall p: ref, h: Heap, G: Ty ::\n      //       { $IsAlloc(p, TClassA(G), h) }\n      //       $IsAlloc(p, TClassA(G), h) => (p == null || h[p, alloc]);\n      MapM(c is ClassDecl ? Bools : new List<bool>(), is_alloc => {\n        List<Bpl.Expr> tyexprs;\n        var vars = MkTyParamBinders(GetTypeParams(c), out tyexprs);\n\n        var o = BplBoundVar(\"$o\", predef.RefType, vars);\n\n        Bpl.Expr body, is_o;\n        Bpl.Expr o_null = Bpl.Expr.Eq(o, predef.Null);\n        Bpl.Expr o_ty = ClassTyCon(c, tyexprs);\n        string name;\n\n        if (is_alloc) {\n          name = c + \": Class $IsAlloc\";\n          var h = BplBoundVar(\"$h\", predef.HeapType, vars);\n          // $IsAlloc(o, ..)\n          is_o = MkIsAlloc(o, o_ty, h);\n          body = BplIff(is_o, BplOr(o_null, IsAlloced(c.tok, h, o)));\n        } else {\n          name = c + \": Class $Is\";\n          // $Is(o, ..)\n          is_o = MkIs(o, o_ty);\n          Bpl.Expr rhs;\n          if (c == program.BuiltIns.ObjectDecl) {\n            rhs = Bpl.Expr.True;\n          } else if (c is TraitDecl) {\n            //generating $o == null || implements$J(dtype(x))\n            var t = (TraitDecl)c;\n            var dtypeFunc = FunctionCall(o.tok, BuiltinFunction.DynamicType, null, o);\n            Bpl.Expr implementsFunc = FunctionCall(t.tok, \"implements$\" + t.FullSanitizedName, Bpl.Type.Bool, new List<Expr> { dtypeFunc });\n            rhs = BplOr(o_null, implementsFunc);\n          } else {\n            rhs = BplOr(o_null, DType(o, o_ty));\n          }\n          body = BplIff(is_o, rhs);\n        }\n\n        sink.AddTopLevelDeclaration(new Bpl.Axiom(c.tok, BplForall(vars, BplTrigger(is_o), body), name));\n      });\n\n      if (c is TraitDecl) {\n        //this adds: function implements$J(Ty): bool;\n        var arg_ref = new Bpl.Formal(c.tok, new Bpl.TypedIdent(c.tok, Bpl.TypedIdent.NoName, predef.Ty), true);\n        var res = new Bpl.Formal(c.tok, new Bpl.TypedIdent(c.tok, Bpl.TypedIdent.NoName, Bpl.Type.Bool), false);\n        var implement_intr = new Bpl.Function(c.tok, \"implements$\" + c.FullSanitizedName, new List<Variable> { arg_ref }, res);\n        sink.AddTopLevelDeclaration(implement_intr);\n      } else if (c is ClassDecl) {\n        //this adds: axiom implements$J(class.C);\n        foreach (var trait in ((ClassDecl)c).TraitsObj) {\n          var arg = ClassTyCon(c, new List<Expr>());  // TODO: this needs more work if overridingClass has type parameters\n          var expr = FunctionCall(c.tok, \"implements$\" + trait.FullSanitizedName, Bpl.Type.Bool, arg);\n          var implements_axiom = new Bpl.Axiom(c.tok, expr);\n          sink.AddTopLevelDeclaration(implements_axiom);\n        }\n      }\n\n      foreach (MemberDecl member in c.Members.FindAll(VisibleInScope)) {\n        Contract.Assert(isAllocContext == null);\n        currentDeclaration = member;\n        if (member is Field) {\n          Field f = (Field)member;\n          if (f is ConstantField) {\n            // The following call has the side effect of idempotently creating and adding the function to the sink's top-level declarations\n            Contract.Assert(currentModule == null);\n            currentModule = f.EnclosingClass.Module;\n            var oldFuelContext = fuelContext;\n            fuelContext = FuelSetting.NewFuelContext(f);\n            var boogieFunction = GetReadonlyField(f);\n            fuelContext = oldFuelContext;\n            currentModule = null;\n            AddAllocationAxiom(f, c);\n          } else {\n            if (f.IsMutable) {\n              Bpl.Constant fc = GetField(f);\n              sink.AddTopLevelDeclaration(fc);\n            } else {\n              Bpl.Function ff = GetReadonlyField(f);\n              if (ff != predef.ArrayLength)\n                sink.AddTopLevelDeclaration(ff);\n            }\n            AddAllocationAxiom(f, c);\n          }\n\n        } else if (member is Function) {\n          AddFunction_Top((Function)member);\n        } else if (member is Method) {\n          if (includeMethods || InVerificationScope(member) || referencedMembers.Contains(member)) {\n            AddMember_Top(member);\n          }\n        } else {\n          Contract.Assert(false); throw new cce.UnreachableException();  // unexpected member\n        }\n      }\n    }\n\n    void AddMember_Top(MemberDecl mem) {\n      Contract.Requires(mem is Method);\n\n      if (mem is Method) {\n        AddMethod_Top((Method)mem);\n      }\n\n    }\n\n    void AddFunction_Top(Function f) {\n      FuelContext oldFuelContext = this.fuelContext;\n      this.fuelContext = FuelSetting.NewFuelContext(f);\n      isAllocContext = new IsAllocContext(true);\n\n      AddClassMember_Function(f);\n\n      if (!f.IsBuiltin && InVerificationScope(f)) {\n        AddWellformednessCheck(f);\n        if (f.OverriddenFunction != null) { //it means that f is overriding its associated parent function\n          AddFunctionOverrideCheckImpl(f);\n        }\n      }\n      var cop = f as FixpointPredicate;\n      if (cop != null) {\n        AddClassMember_Function(cop.PrefixPredicate);\n        // skip the well-formedness check, because it has already been done for the fixpoint-predicate\n      }\n      this.fuelContext = oldFuelContext;\n      isAllocContext = null;\n    }\n\n    void AddMethod_Top(Method m) {\n      FuelContext oldFuelContext = this.fuelContext;\n      this.fuelContext = FuelSetting.NewFuelContext(m);\n\n      // wellformedness check for method specification\n      if (m.EnclosingClass is IteratorDecl && m == ((IteratorDecl)m.EnclosingClass).Member_MoveNext) {\n        // skip the well-formedness check, because it has already been done for the iterator\n      } else {\n        var proc = AddMethod(m, MethodTranslationKind.SpecWellformedness);\n        sink.AddTopLevelDeclaration(proc);\n        if (InVerificationScope(m)) {\n          AddMethodImpl(m, proc, true);\n        }\n        if (m.OverriddenMethod != null && InVerificationScope(m)) //method has overrided a parent method\n        {\n          var procOverrideChk = AddMethod(m, MethodTranslationKind.OverrideCheck);\n          sink.AddTopLevelDeclaration(procOverrideChk);\n          AddMethodOverrideCheckImpl(m, procOverrideChk);\n        }\n      }\n      // the method spec itself\n      sink.AddTopLevelDeclaration(AddMethod(m, MethodTranslationKind.Call));\n      if (m is FixpointLemma) {\n        // Let the CoCall and Impl forms to use m.PrefixLemma signature and specification (and\n        // note that m.PrefixLemma.Body == m.Body.\n        m = ((FixpointLemma)m).PrefixLemma;\n        sink.AddTopLevelDeclaration(AddMethod(m, MethodTranslationKind.CoCall));\n      }\n      if (m.Body != null && InVerificationScope(m)) {\n        // ...and its implementation\n        assertionCount = 0;\n        var proc = AddMethod(m, MethodTranslationKind.Implementation);\n        sink.AddTopLevelDeclaration(proc);\n        AddMethodImpl(m, proc, false);\n      }\n      Reset();\n      this.fuelContext = oldFuelContext;\n\n    }\n\n    /// <summary>\n    /// Returns true if the body of function \"f\" is available in module \"context\".\n    /// This happens when the following conditions all hold:\n    ///   - \"f\" has a body\n    ///   - \"f\" is not opaque\n    ///   - \"f\" is declared as protected, then \"context\" is the current module and parameter \"revealProtectedBody\" is passed in as \"true\".\n    /// </summary>\n    static bool FunctionBodyIsAvailable(Function f, ModuleDefinition context, VisibilityScope scope, bool revealProtectedBody) {\n      Contract.Requires(f != null);\n      Contract.Requires(context != null);\n      return f.Body != null && !IsOpaqueFunction(f) && f.IsRevealedInScope(scope) && (!f.IsProtected || (revealProtectedBody && f.EnclosingClass.Module == context));\n    }\n    static bool IsOpaqueFunction(Function f) {\n      Contract.Requires(f != null);\n      return Attributes.Contains(f.Attributes, \"opaque\");\n    }\n    static bool IsOpaqueRevealLemma(Method m) {\n      Contract.Requires(m != null);\n      return Attributes.Contains(m.Attributes, \"opaque_reveal\");\n    }\n\n    private void AddClassMember_Function(Function f) {\n      Contract.Ensures(currentModule == null && codeContext == null);\n      Contract.Ensures(currentModule == null && codeContext == null);\n\n      currentModule = f.EnclosingClass.Module;\n      codeContext = f;\n\n      // declare function\n      AddFunction(f);\n      // add synonym axiom\n      if (f.IsFuelAware()) {\n        AddLayerSynonymAxiom(f);\n        AddFuelSynonymAxiom(f);\n      }\n      // add frame axiom\n      if (AlwaysUseHeap || f.ReadsHeap) {\n        AddFrameAxiom(f);\n      }\n      // add consequence axiom\n      AddFunctionConsequenceAxiom(f, f.Ens);\n      // add definition axioms, suitably specialized for literals\n      if (f.Body != null && RevealedInScope(f)) {\n        AddFunctionAxiom(f, f.Body.Resolved);\n      } else {\n        // for body-less functions, at least generate its #requires function\n        var b = FunctionAxiom(f, null, null);\n        Contract.Assert(b == null);\n      }\n      // for a function in a class C that overrides a function in a trait J, add an axiom that connects J.F and C.F\n      if (f.OverriddenFunction != null) {\n        AddFunctionOverrideAxiom(f);\n      }\n\n      // supply the connection between inductive/coinductive predicates and prefix predicates\n      if (f is FixpointPredicate) {\n        AddPrefixPredicateAxioms(((FixpointPredicate)f).PrefixPredicate);\n      }\n\n      Reset();\n    }\n\n    void AddIteratorSpecAndBody(IteratorDecl iter) {\n      Contract.Requires(iter != null);\n      Contract.Ensures(fuelContext == Contract.OldValue(fuelContext));\n\n      FuelContext oldFuelContext = this.fuelContext;\n      this.fuelContext = FuelSetting.NewFuelContext(iter);\n      isAllocContext = new IsAllocContext(false);\n\n      // wellformedness check for method specification\n      Bpl.Procedure proc = AddIteratorProc(iter, MethodTranslationKind.SpecWellformedness);\n      sink.AddTopLevelDeclaration(proc);\n      if(InVerificationScope(iter)){\n        AddIteratorWellformed(iter, proc);\n      }\n      // the method itself\n      if (iter.Body != null && InVerificationScope(iter)) {\n        proc = AddIteratorProc(iter, MethodTranslationKind.Implementation);\n        sink.AddTopLevelDeclaration(proc);\n        // ...and its implementation\n        AddIteratorImpl(iter, proc);\n      }\n      this.fuelContext = oldFuelContext;\n      isAllocContext = null;\n    }\n\n    Bpl.Procedure AddIteratorProc(IteratorDecl iter, MethodTranslationKind kind) {\n      Contract.Requires(iter != null);\n      Contract.Requires(kind == MethodTranslationKind.SpecWellformedness || kind == MethodTranslationKind.Implementation);\n      Contract.Requires(predef != null);\n      Contract.Requires(currentModule == null && codeContext == null);\n      Contract.Ensures(currentModule == null && codeContext == null);\n      Contract.Ensures(Contract.Result<Bpl.Procedure>() != null);\n\n      currentModule = iter.Module;\n      codeContext = iter;\n\n      var etran = new ExpressionTranslator(this, predef, iter.tok);\n\n      var inParams = new List<Bpl.Variable>();\n      List<Variable> outParams;\n      GenerateMethodParametersChoose(iter.tok, iter, kind, true, true, false, etran, inParams, out outParams);\n\n      var req = new List<Bpl.Requires>();\n      var mod = new List<Bpl.IdentifierExpr>();\n      var ens = new List<Bpl.Ensures>();\n      // FREE PRECONDITIONS\n      if (kind == MethodTranslationKind.SpecWellformedness || kind == MethodTranslationKind.Implementation) {  // the other cases have no need for a free precondition\n        // free requires mh == ModuleContextHeight && fh = FunctionContextHeight;\n        req.Add(Requires(iter.tok, true, etran.HeightContext(iter), null, null));\n      }\n      mod.Add((Bpl.IdentifierExpr/*TODO: this cast is rather dubious*/)etran.HeapExpr);\n      mod.Add(etran.Tick());\n\n      if (kind != MethodTranslationKind.SpecWellformedness) {\n        // USER-DEFINED SPECIFICATIONS\n        var comment = \"user-defined preconditions\";\n        foreach (var p in iter.Requires) {\n          string errorMessage = CustomErrorMessage(p.Attributes);\n          if (p.Label != null && kind == MethodTranslationKind.Implementation) {\n            // don't include this precondition here, but record it for later use\n            p.Label.E = etran.Old.TrExpr(p.E);\n          } else if (p.IsFree && !ArmadaOptions.O.DisallowSoundnessCheating) {\n            req.Add(Requires(p.E.tok, true, etran.TrExpr(p.E), errorMessage, comment));\n            comment = null;\n          } else {\n            foreach (var s in TrSplitExprForMethodSpec(p.E, etran, kind)) {\n              if (kind == MethodTranslationKind.Call && RefinementToken.IsInherited(s.E.tok, currentModule)) {\n                // this precondition was inherited into this module, so just ignore it\n              } else {\n                req.Add(Requires(s.E.tok, s.IsOnlyFree, s.E, errorMessage, comment));\n                comment = null;\n                // the free here is not linked to the free on the original expression (this is free things generated in the splitting.)\n              }\n            }\n          }\n        }\n        comment = \"user-defined postconditions\";\n        foreach (var p in iter.Ensures) {\n          if (p.IsFree && !ArmadaOptions.O.DisallowSoundnessCheating) {\n            ens.Add(Ensures(p.E.tok, true, etran.TrExpr(p.E), null, comment));\n            comment = null;\n          } else {\n            foreach (var s in TrSplitExprForMethodSpec(p.E, etran, kind)) {\n              if (kind == MethodTranslationKind.Implementation && RefinementToken.IsInherited(s.E.tok, currentModule)) {\n                // this postcondition was inherited into this module, so just ignore it\n              } else {\n                ens.Add(Ensures(s.E.tok, s.IsOnlyFree, s.E, null, comment));\n                comment = null;\n              }\n            }\n          }\n        }\n        foreach (BoilerplateTriple tri in GetTwoStateBoilerplate(iter.tok, iter.Modifies.Expressions, false, etran.Old, etran, etran.Old)) {\n          ens.Add(Ensures(tri.tok, tri.IsFree, tri.Expr, tri.ErrorMessage, tri.Comment));\n        }\n      }\n\n      var name = MethodName(iter, kind);\n      var proc = new Bpl.Procedure(iter.tok, name, new List<Bpl.TypeVariable>(), inParams, outParams, req, mod, ens, etran.TrAttributes(iter.Attributes, null));\n\n      currentModule = null;\n      codeContext = null;\n\n      return proc;\n    }\n\n    void AddEnsures(List<Bpl.Ensures> list, Bpl.Ensures ens) {\n      list.Add(ens);\n      if (!ens.Free) { this.assertionCount++; }\n    }\n\n    void AddIteratorWellformed(IteratorDecl iter, Procedure proc) {\n      Contract.Requires(iter != null);\n      Contract.Requires(proc != null);\n      Contract.Requires(currentModule == null && codeContext == null);\n      Contract.Ensures(currentModule == null && codeContext == null);\n\n      currentModule = iter.Module;\n      codeContext = iter;\n\n      List<Variable> inParams = Bpl.Formal.StripWhereClauses(proc.InParams);\n      Contract.Assert(1 <= inParams.Count);  // there should at least be a receiver parameter\n      Contract.Assert(proc.OutParams.Count == 0);\n\n      var builder = new BoogieStmtListBuilder(this);\n      var etran = new ExpressionTranslator(this, predef, iter.tok);\n      var localVariables = new List<Variable>();\n\n      Bpl.StmtList stmts;\n      // check well-formedness of the preconditions, and then assume each one of them\n      foreach (var p in iter.Requires) {\n        CheckWellformedAndAssume(p.E, new WFOptions(), localVariables, builder, etran);\n      }\n      // check well-formedness of the modifies and reads clauses\n      CheckFrameWellFormed(new WFOptions(), iter.Modifies.Expressions, localVariables, builder, etran);\n      CheckFrameWellFormed(new WFOptions(), iter.Reads.Expressions, localVariables, builder, etran);\n      // check well-formedness of the decreases clauses\n      foreach (var p in iter.Decreases.Expressions) {\n        CheckWellformed(p, new WFOptions(), localVariables, builder, etran);\n      }\n\n      // Next, we assume about this.* whatever we said that the iterator constructor promises\n      foreach (var p in iter.Member_Init.Ens) {\n        builder.Add(TrAssumeCmd(p.E.tok, etran.TrExpr(p.E)));\n      }\n\n      // play havoc with the heap, except at the locations prescribed by (this._reads - this._modifies - {this})\n      var th = new ThisExpr(iter.tok);\n      th.Type = Resolver.GetThisType(iter.tok, iter);  // resolve here\n      var rds = new MemberSelectExpr(iter.tok, th, iter.Member_Reads);\n      var mod = new MemberSelectExpr(iter.tok, th, iter.Member_Modifies);\n      builder.Add(new Bpl.CallCmd(iter.tok, \"$IterHavoc0\",\n        new List<Bpl.Expr>() { etran.TrExpr(th), etran.TrExpr(rds), etran.TrExpr(mod) },\n        new List<Bpl.IdentifierExpr>()));\n\n      // assume the automatic yield-requires precondition (which is always well-formed):  this.Valid()\n      var validCall = new FunctionCallExpr(iter.tok, \"Valid\", th, iter.tok, new List<Expression>());\n      validCall.Function = iter.Member_Valid;  // resolve here\n      validCall.Type = Type.Bool;  // resolve here\n\n      validCall.TypeArgumentSubstitutions = new Dictionary<TypeParameter, Type>();\n      foreach (var p in iter.TypeArgs) {\n        validCall.TypeArgumentSubstitutions[p] = new UserDefinedType(p);\n      } // resolved here.\n\n      builder.Add(TrAssumeCmd(iter.tok, etran.TrExpr(validCall)));\n\n      // check well-formedness of the user-defined part of the yield-requires\n      foreach (var p in iter.YieldRequires) {\n        CheckWellformedAndAssume(p.E, new WFOptions(), localVariables, builder, etran);\n      }\n\n      // save the heap (representing the state where yield-requires holds):  $_OldIterHeap := Heap;\n      var oldIterHeap = new Bpl.LocalVariable(iter.tok, new Bpl.TypedIdent(iter.tok, \"$_OldIterHeap\", predef.HeapType));\n      localVariables.Add(oldIterHeap);\n      builder.Add(Bpl.Cmd.SimpleAssign(iter.tok, new Bpl.IdentifierExpr(iter.tok, oldIterHeap), etran.HeapExpr));\n      // simulate a modifies this, this._modifies, this._new;\n      var nw = new MemberSelectExpr(iter.tok, th, iter.Member_New);\n      builder.Add(new Bpl.CallCmd(iter.tok, \"$IterHavoc1\",\n        new List<Bpl.Expr>() { etran.TrExpr(th), etran.TrExpr(mod), etran.TrExpr(nw) },\n        new List<Bpl.IdentifierExpr>()));\n      // assume the implicit postconditions promised by MoveNext:\n      // assume fresh(_new - old(_new));\n      var yeEtran = new ExpressionTranslator(this, predef, etran.HeapExpr, new Bpl.IdentifierExpr(iter.tok, \"$_OldIterHeap\", predef.HeapType));\n      var old_nw = new OldExpr(iter.tok, nw);\n      old_nw.Type = nw.Type;  // resolve here\n      var setDiff = new BinaryExpr(iter.tok, BinaryExpr.Opcode.Sub, nw, old_nw);\n      setDiff.ResolvedOp = BinaryExpr.ResolvedOpcode.SetDifference; setDiff.Type = nw.Type;  // resolve here\n      Expression cond = new UnaryOpExpr(iter.tok, UnaryOpExpr.Opcode.Fresh, setDiff);\n      cond.Type = Type.Bool;  // resolve here\n      builder.Add(TrAssumeCmd(iter.tok, yeEtran.TrExpr(cond)));\n\n      // check wellformedness of postconditions\n      var yeBuilder = new BoogieStmtListBuilder(this);\n      var endBuilder = new BoogieStmtListBuilder(this);\n      // In the yield-ensures case:  assume this.Valid();\n      yeBuilder.Add(TrAssumeCmd(iter.tok, yeEtran.TrExpr(validCall)));\n      Contract.Assert(iter.OutsFields.Count == iter.OutsHistoryFields.Count);\n      for (int i = 0; i < iter.OutsFields.Count; i++) {\n        var y = iter.OutsFields[i];\n        var ys = iter.OutsHistoryFields[i];\n        var thisY = new MemberSelectExpr(iter.tok, th, y);\n        var thisYs = new MemberSelectExpr(iter.tok, th, ys);\n        var oldThisYs = new OldExpr(iter.tok, thisYs);\n        oldThisYs.Type = thisYs.Type;  // resolve here\n        var singleton = new SeqDisplayExpr(iter.tok, new List<Expression>() { thisY });\n        singleton.Type = thisYs.Type;  // resolve here\n        var concat = new BinaryExpr(iter.tok, BinaryExpr.Opcode.Add, oldThisYs, singleton);\n        concat.ResolvedOp = BinaryExpr.ResolvedOpcode.Concat; concat.Type = oldThisYs.Type;  // resolve here\n\n        // In the yield-ensures case:  assume this.ys == old(this.ys) + [this.y];\n        yeBuilder.Add(TrAssumeCmd(iter.tok, Bpl.Expr.Eq(yeEtran.TrExpr(thisYs), yeEtran.TrExpr(concat))));\n        // In the ensures case:  assume this.ys == old(this.ys);\n        endBuilder.Add(TrAssumeCmd(iter.tok, Bpl.Expr.Eq(yeEtran.TrExpr(thisYs), yeEtran.TrExpr(oldThisYs))));\n      }\n\n      foreach (var p in iter.YieldEnsures) {\n        CheckWellformedAndAssume(p.E, new WFOptions(), localVariables, yeBuilder, yeEtran);\n      }\n      foreach (var p in iter.Ensures) {\n        CheckWellformedAndAssume(p.E, new WFOptions(), localVariables, endBuilder, yeEtran);\n      }\n      builder.Add(new Bpl.IfCmd(iter.tok, null, yeBuilder.Collect(iter.tok), null, endBuilder.Collect(iter.tok)));\n\n      stmts = builder.Collect(iter.tok);\n\n      if (EmitImplementation(iter.Attributes)) {\n        QKeyValue kv = etran.TrAttributes(iter.Attributes, null);\n        Bpl.Implementation impl = new Bpl.Implementation(iter.tok, proc.Name,\n          new List<Bpl.TypeVariable>(), inParams, new List<Variable>(),\n          localVariables, stmts, kv);\n        sink.AddTopLevelDeclaration(impl);\n      }\n\n      Reset();\n    }\n\n    bool EmitImplementation(Attributes attributes) {\n      // emit the impl only when there are proof obligations\n      if (assertionCount > 0) {\n        return true;\n      } else {\n        return false;\n      }\n    }\n    void AddIteratorImpl(IteratorDecl iter, Bpl.Procedure proc) {\n      Contract.Requires(iter != null);\n      Contract.Requires(proc != null);\n      Contract.Requires(sink != null && predef != null);\n      Contract.Requires(iter.Body != null);\n      Contract.Requires(currentModule == null && codeContext == null && yieldCountVariable == null && _tmpIEs.Count == 0);\n      Contract.Ensures(currentModule == null && codeContext == null && yieldCountVariable == null && _tmpIEs.Count == 0);\n\n      currentModule = iter.Module;\n      codeContext = iter;\n\n      List<Variable> inParams = Bpl.Formal.StripWhereClauses(proc.InParams);\n      Contract.Assert(1 <= inParams.Count);  // there should at least be a receiver parameter\n      Contract.Assert(proc.OutParams.Count == 0);\n\n      var builder = new BoogieStmtListBuilder(this);\n      var etran = new ExpressionTranslator(this, predef, iter.tok);\n      var localVariables = new List<Variable>();\n      GenerateIteratorImplPrelude(iter, inParams, new List<Variable>(), builder, localVariables);\n\n      // add locals for the yield-history variables and the extra variables\n      // Assume the precondition and postconditions of the iterator constructor method\n      foreach (var p in iter.Member_Init.Req) {\n        if (p.Label != null) {\n          // don't include this precondition here\n          Contract.Assert(p.Label.E != null);  // it should already have been recorded\n        } else {\n          builder.Add(TrAssumeCmd(p.E.tok, etran.TrExpr(p.E)));\n        }\n      }\n      foreach (var p in iter.Member_Init.Ens) {\n        // these postconditions are two-state predicates, but that's okay, because we haven't changed anything yet\n        builder.Add(TrAssumeCmd(p.E.tok, etran.TrExpr(p.E)));\n      }\n      // add the _yieldCount variable, and assume its initial value to be 0\n      yieldCountVariable = new Bpl.LocalVariable(iter.tok,\n        new Bpl.TypedIdent(iter.tok, iter.YieldCountVariable.AssignUniqueName(currentDeclaration.IdGenerator), TrType(iter.YieldCountVariable.Type)));\n      yieldCountVariable.TypedIdent.WhereExpr = YieldCountAssumption(iter, etran);  // by doing this after setting \"yieldCountVariable\", the variable can be used by YieldCountAssumption\n      localVariables.Add(yieldCountVariable);\n      builder.Add(TrAssumeCmd(iter.tok, Bpl.Expr.Eq(new Bpl.IdentifierExpr(iter.tok, yieldCountVariable), Bpl.Expr.Literal(0))));\n      // add a variable $_OldIterHeap\n      var oih = new Bpl.IdentifierExpr(iter.tok, \"$_OldIterHeap\", predef.HeapType);\n      Bpl.Expr wh = BplAnd(\n        FunctionCall(iter.tok, BuiltinFunction.IsGoodHeap, null, oih),\n        HeapSucc(oih, etran.HeapExpr));\n      localVariables.Add(new Bpl.LocalVariable(iter.tok, new Bpl.TypedIdent(iter.tok, \"$_OldIterHeap\", predef.HeapType, wh)));\n\n      // do an initial YieldHavoc\n      YieldHavoc(iter.tok, iter, builder, etran);\n\n      // translate the body of the iterator\n      var stmts = TrStmt2StmtList(builder, iter.Body, localVariables, etran);\n\n      if (EmitImplementation(iter.Attributes)) {\n        // emit the impl only when there are proof obligations.\n        QKeyValue kv = etran.TrAttributes(iter.Attributes, null);\n\n        Bpl.Implementation impl = new Bpl.Implementation(iter.tok, proc.Name,\n          new List<Bpl.TypeVariable>(), inParams, new List<Variable>(),\n          localVariables, stmts, kv);\n        sink.AddTopLevelDeclaration(impl);\n      }\n\n      yieldCountVariable = null;\n      Reset();\n    }\n\n    private void Reset()\n    {\n      currentModule = null;\n      codeContext = null;\n      CurrentIdGenerator.Reset();\n      _tmpIEs.Clear();\n      assertionCount = 0;\n    }\n\n    Bpl.Expr YieldCountAssumption(IteratorDecl iter, ExpressionTranslator etran) {\n      Contract.Requires(iter != null);\n      Contract.Requires(etran != null);\n      Contract.Requires(yieldCountVariable != null);\n      Bpl.Expr wh = Bpl.Expr.True;\n      foreach (var ys in iter.OutsHistoryFields) {\n        // add the conjunct:  _yieldCount == |this.ys|\n        wh = Bpl.Expr.And(wh, Bpl.Expr.Eq(new Bpl.IdentifierExpr(iter.tok, yieldCountVariable),\n          FunctionCall(iter.tok, BuiltinFunction.SeqLength, null,\n          ReadHeap(iter.tok, etran.HeapExpr,\n            new Bpl.IdentifierExpr(iter.tok, etran.This, predef.RefType),\n            new Bpl.IdentifierExpr(iter.tok, GetField(ys))))));\n      }\n      return wh;\n    }\n\n    class Specialization\n    {\n      public readonly List<Formal/*!*/> Formals;\n      public readonly List<Expression/*!*/> ReplacementExprs;\n      public readonly List<BoundVar/*!*/> ReplacementFormals;\n      public readonly Dictionary<IVariable, Expression> SubstMap;\n      readonly Translator translator;\n      [ContractInvariantMethod]\n      void ObjectInvariant() {\n        Contract.Invariant(cce.NonNullElements(Formals));\n        Contract.Invariant(cce.NonNullElements(ReplacementExprs));\n        Contract.Invariant(Formals.Count == ReplacementExprs.Count);\n        Contract.Invariant(cce.NonNullElements(ReplacementFormals));\n        Contract.Invariant(SubstMap != null);\n      }\n\n      public Specialization(IVariable formal, MatchCase mc, Specialization prev, Translator translator) {\n        Contract.Requires(formal is Formal || formal is BoundVar);\n        Contract.Requires(mc != null);\n        Contract.Requires(prev == null || formal is BoundVar || !prev.Formals.Contains((Formal)formal));\n        Contract.Requires(translator != null);\n\n        this.translator = translator;\n\n        List<Expression> rArgs = new List<Expression>();\n        foreach (BoundVar p in mc.Arguments) {\n          IdentifierExpr ie = new IdentifierExpr(p.tok, p.AssignUniqueName(translator.currentDeclaration.IdGenerator));\n          ie.Var = p; ie.Type = ie.Var.Type;  // resolve it here\n          rArgs.Add(ie);\n        }\n        // create and resolve datatype value\n        var r = new DatatypeValue(mc.tok, mc.Ctor.EnclosingDatatype.Name, mc.Ctor.Name, rArgs);\n        r.Ctor = mc.Ctor;\n        r.Type = new UserDefinedType(mc.tok, mc.Ctor.EnclosingDatatype.Name, new List<Type>()/*this is not right, but it seems like it won't matter here*/);\n\n        Dictionary<IVariable, Expression> substMap = new Dictionary<IVariable, Expression>();\n        substMap.Add(formal, r);\n\n        // Fill in the fields\n        Formals = new List<Formal>();\n        ReplacementExprs = new List<Expression>();\n        ReplacementFormals = new List<BoundVar>();\n        SubstMap = new Dictionary<IVariable, Expression>();\n        if (prev != null) {\n          Formals.AddRange(prev.Formals);\n          foreach (var e in prev.ReplacementExprs) {\n            ReplacementExprs.Add(Translator.Substitute(e, null, substMap));\n          }\n          foreach (var rf in prev.ReplacementFormals) {\n            if (rf != formal) {\n              ReplacementFormals.Add(rf);\n            }\n          }\n          foreach (var entry in prev.SubstMap) {\n            SubstMap.Add(entry.Key, Translator.Substitute(entry.Value, null, substMap));\n          }\n        }\n        if (formal is Formal) {\n          Formals.Add((Formal)formal);\n          ReplacementExprs.Add(r);\n        }\n        ReplacementFormals.AddRange(mc.Arguments);\n        SubstMap.Add(formal, r);\n      }\n    }\n\n    void AddFunctionAxiom(Function f, Expression body) {\n      Contract.Requires(f != null);\n      Contract.Requires(body != null);\n\n      var ax = FunctionAxiom(f, body, null);\n      sink.AddTopLevelDeclaration(ax);\n      // TODO(namin) Is checking f.Reads.Count==0 excluding Valid() of BinaryTree in the right way?\n      //             I don't see how this in the decreasing clause would help there.\n      // danr: Let's create the literal function axioms if there is an arrow type in the signature\n      if (!(f is FixpointPredicate) && f.CoClusterTarget == Function.CoCallClusterInvolvement.None &&\n        (f.Reads.Count == 0 || f.Formals.Exists(a => a.Type.IsArrowType))) {\n        var FVs = new HashSet<IVariable>();\n        foreach (var e in f.Decreases.Expressions) {\n          ComputeFreeVariables(e, FVs);\n        }\n        var decs = new List<Formal>();\n        foreach (var formal in f.Formals) {\n          if (FVs.Contains(formal)) {\n            decs.Add(formal);\n          }\n        }\n        Contract.Assert(decs.Count <= f.Formals.Count);\n        if (0 < decs.Count && decs.Count < f.Formals.Count && !ArmadaOptions.O.Dafnycc) {\n          ax = FunctionAxiom(f, body, decs);\n          sink.AddTopLevelDeclaration(ax);\n        }\n\n        if (!ArmadaOptions.O.Dafnycc) {\n          ax = FunctionAxiom(f, body, f.Formals);\n          sink.AddTopLevelDeclaration(ax);\n        }\n      }\n    }\n\n    void AddFunctionConsequenceAxiom(Function f, List<MaybeFreeExpression> ens) {\n      Contract.Requires(f != null);\n      Contract.Requires(predef != null);\n      Contract.Requires(f.EnclosingClass != null);\n\n      bool readsHeap = AlwaysUseHeap || f.ReadsHeap;\n      foreach (MaybeFreeExpression e in f.Req.Concat(ens)) {\n        readsHeap = readsHeap || UsesHeap(e.E);\n      }\n\n      ExpressionTranslator etranHeap;\n      ExpressionTranslator etran;\n      Bpl.BoundVariable bvPrevHeap = null;\n      if (f is TwoStateFunction) {\n        bvPrevHeap = new Bpl.BoundVariable(f.tok, new Bpl.TypedIdent(f.tok, \"$prevHeap\", predef.HeapType));\n        etran = new ExpressionTranslator(this, predef,\n          f.ReadsHeap ? new Bpl.IdentifierExpr(f.tok, predef.HeapVarName, predef.HeapType) : null,\n          new Bpl.IdentifierExpr(f.tok, bvPrevHeap));\n        etranHeap = etran;\n      } else {\n        etranHeap = new ExpressionTranslator(this, predef, f.tok);\n        etran = readsHeap ? etranHeap : new ExpressionTranslator(this, predef, (Bpl.Expr)null);\n      }\n\n      // This method generate the Consequence Axiom, which has information about the function's\n      // return type and postconditions\n      //\n      // axiom  // consequence axiom\n      //   AXIOM_ACTIVATION\n      //   ==>\n      //   (forall s, $Heap, formals ::                  // let args := $Heap,formals\n      //       { f(s, args) }\n      //       f#canCall(args) || USE_VIA_CONTEXT\n      //       ==>\n      //       ens &&\n      //       f(s, args)-has-the-expected type);\n      //\n      // where:\n      //\n      // AXIOM_ACTIVATION\n      // means:\n      //   mh < ModuleContextHeight ||\n      //   (mh == ModuleContextHeight && fh <= FunctionContextHeight)\n      //\n      // USE_VIA_CONTEXT\n      //   (mh != ModuleContextHeight || fh != FunctionContextHeight) &&\n      //   GOOD_PARAMETERS\n      // where GOOD_PARAMETERS means:\n      //   $IsGoodHeap($Heap) && this != null && formals-have-the-expected-types &&\n      //   Pre($Heap,formals)\n      //\n      // Note, an antecedent $Heap[this,alloc] is intentionally left out:  including it would only weaken\n      // the axiom.  Moreover, leaving it out does not introduce any soundness problem, because the Dafny\n      // allocation statement changes only an allocation bit and then re-assumes $IsGoodHeap; so if it is\n      // sound after that, then it would also have been sound just before the allocation.\n      //\n      List<Bpl.Expr> tyargs;\n      var formals = MkTyParamBinders(GetTypeParams(f), out tyargs);\n      var args = new List<Bpl.Expr>();\n      Bpl.BoundVariable layer;\n      if (f.IsFuelAware()) {\n        layer = new Bpl.BoundVariable(f.tok, new Bpl.TypedIdent(f.tok, \"$ly\", predef.LayerType));\n        formals.Add(layer);\n        etran = etran.WithCustomFuelSetting(new CustomFuelSettings{ {f, new FuelSetting(this, 0, new Bpl.IdentifierExpr(f.tok, layer))} });\n        //etran = etran.WithLayer(new Bpl.IdentifierExpr(f.tok, layer));\n        // Note, \"layer\" is not added to \"args\" here; rather, that's done below, as needed\n      } else {\n        layer = null;\n      }\n\n      Bpl.Expr ante = Bpl.Expr.True;\n      Bpl.Expr anteIsAlloc = Bpl.Expr.True;\n      if (f is TwoStateFunction) {\n        Contract.Assert(bvPrevHeap != null);\n        formals.Add(bvPrevHeap);\n        args.Add(etran.Old.HeapExpr);\n        // ante:  $IsGoodHeap($prevHeap) &&\n        ante = BplAnd(ante, FunctionCall(f.tok, BuiltinFunction.IsGoodHeap, null, etran.Old.HeapExpr));\n      }\n      var bvHeap = new Bpl.BoundVariable(f.tok, new Bpl.TypedIdent(f.tok, predef.HeapVarName, predef.HeapType));\n      if (AlwaysUseHeap || f.ReadsHeap) {\n        args.Add(new Bpl.IdentifierExpr(f.tok, bvHeap));\n      }\n      // ante:  $IsGoodHeap($Heap) && $HeapSucc($prevHeap, $Heap) && this != null && formals-have-the-expected-types &&\n      if (readsHeap) {\n        Bpl.Expr goodHeap = FunctionCall(f.tok, BuiltinFunction.IsGoodHeap, null, etranHeap.HeapExpr);\n        formals.Add(bvHeap);\n        ante = BplAnd(ante, goodHeap);\n      }\n      if (f is TwoStateFunction && f.ReadsHeap) {\n        ante = BplAnd(ante, HeapSucc(etran.Old.HeapExpr, etran.HeapExpr));\n      }\n\n      if (!f.IsStatic) {\n        var bvThis = new Bpl.BoundVariable(f.tok, new Bpl.TypedIdent(f.tok, etran.This, TrReceiverType(f)));\n        formals.Add(bvThis);\n        var bvThisIdExpr = new Bpl.IdentifierExpr(f.tok, bvThis);\n        args.Add(bvThisIdExpr);\n        // add well-typedness conjunct to antecedent\n        Type thisType = Resolver.GetReceiverType(f.tok, f);\n        Bpl.Expr wh = Bpl.Expr.And(\n          ReceiverNotNull(bvThisIdExpr),\n          (f is TwoStateFunction ? etran.Old : etran).GoodRef(f.tok, bvThisIdExpr, thisType));\n        ante = BplAnd(ante, wh);\n      }\n      var substMap = new Dictionary<IVariable, Expression>();\n      foreach (Formal p in f.Formals) {\n        var bv = new Bpl.BoundVariable(p.tok, new Bpl.TypedIdent(p.tok, p.AssignUniqueName(currentDeclaration.IdGenerator), TrType(p.Type)));\n        Bpl.Expr formal = new Bpl.IdentifierExpr(p.tok, bv);\n        formals.Add(bv);\n        args.Add(formal);\n        // add well-typedness conjunct to antecedent\n        Bpl.Expr wh = GetWhereClause(p.tok, formal, p.Type, p.IsOld ? etran.Old : etran, NOALLOC);\n        if (wh != null) { ante = BplAnd(ante, wh); }\n        wh = GetWhereClause(p.tok, formal, p.Type, etranHeap, ISALLOC);\n        if (wh != null) { anteIsAlloc = BplAnd(anteIsAlloc, wh); }\n      }\n\n      Bpl.Expr funcAppl;\n      {\n        var funcID = new Bpl.IdentifierExpr(f.tok, f.FullSanitizedName, TrType(f.ResultType));\n        var funcArgs = new List<Bpl.Expr>();\n        funcArgs.AddRange(tyargs);\n        /*\n        if (f.IsFueled) {\n            funcArgs.Add(etran.layerInterCluster.GetFunctionFuel(f));\n        } else if (layer != null) {\n           var ly = new Bpl.IdentifierExpr(f.tok, layer);\n           funcArgs.Add(FunctionCall(f.tok, BuiltinFunction.LayerSucc, null, ly));\n        }\n         */\n        if (layer != null) {\n          funcArgs.Add(new Bpl.IdentifierExpr(f.tok, layer));\n        }\n\n        funcArgs.AddRange(args);\n        funcAppl = new Bpl.NAryExpr(f.tok, new Bpl.FunctionCall(funcID), funcArgs);\n      }\n\n      Bpl.Expr pre = Bpl.Expr.True;\n      foreach (MaybeFreeExpression req in f.Req) {\n        pre = BplAnd(pre, etran.TrExpr(Substitute(req.E, null, substMap)));\n      }\n      // useViaContext: (mh != ModuleContextHeight || fh != FunctionContextHeight)\n      var mod = f.EnclosingClass.Module;\n      Bpl.Expr useViaContext = !InVerificationScope(f) ? Bpl.Expr.True :\n        (Bpl.Expr)Bpl.Expr.Neq(Bpl.Expr.Literal(mod.CallGraph.GetSCCRepresentativeId(f)), etran.FunctionContextHeight());\n      // useViaCanCall: f#canCall(args)\n      Bpl.IdentifierExpr canCallFuncID = new Bpl.IdentifierExpr(f.tok, f.FullSanitizedName + \"#canCall\", Bpl.Type.Bool);\n      Bpl.Expr useViaCanCall = new Bpl.NAryExpr(f.tok, new Bpl.FunctionCall(canCallFuncID), Concat(tyargs, args));\n\n      // ante := useViaCanCall || (useViaContext && typeAnte && pre)\n      ante = Bpl.Expr.Or(useViaCanCall, BplAnd(useViaContext, BplAnd(ante, pre)));\n\n      Bpl.Trigger tr = BplTriggerHeap(this, f.tok, funcAppl,\n        (AlwaysUseHeap || f.ReadsHeap || !readsHeap) ? null : etran.HeapExpr);\n      Bpl.Expr post = Bpl.Expr.True;\n      // substitute function return value with the function call.\n      if (f.Result != null) {\n        substMap.Add(f.Result, new BoogieWrapper(funcAppl, f.ResultType));\n      }\n      foreach (MaybeFreeExpression p in ens) {\n        Bpl.Expr q = etran.TrExpr(Substitute(p.E, null, substMap));\n        post = BplAnd(post, q);\n      }\n      Bpl.Expr whr = GetWhereClause(f.tok, funcAppl, f.ResultType, etran, NOALLOC);\n      if (whr != null) { post = Bpl.Expr.And(post, whr); }\n\n      Bpl.Expr ax = BplForall(f.tok, new List<Bpl.TypeVariable>(), formals, null, tr, Bpl.Expr.Imp(ante, post));\n      var activate = AxiomActivation(f, etran);\n      string comment = \"consequence axiom for \" + f.FullSanitizedName;\n      sink.AddTopLevelDeclaration(new Bpl.Axiom(f.tok, Bpl.Expr.Imp(activate, ax), comment));\n\n      if (CommonHeapUse && !readsHeap) {\n        whr = GetWhereClause(f.tok, funcAppl, f.ResultType, etranHeap, NOALLOC, true);\n        if (whr != null) {\n          Bpl.Expr goodHeap = FunctionCall(f.tok, BuiltinFunction.IsGoodHeap, null, etranHeap.HeapExpr);\n          formals = Util.Cons(bvHeap, formals);\n          ante = BplAnd(ante, goodHeap);\n          ax = BplForall(f.tok, new List<Bpl.TypeVariable>(), formals, null, BplTrigger(whr), Bpl.Expr.Imp(ante, whr));\n          activate = AxiomActivation(f, etran);\n          sink.AddTopLevelDeclaration(new Bpl.Axiom(f.tok, Bpl.Expr.Imp(activate, ax)));\n        }\n      }\n    }\n\n    Bpl.Expr AxiomActivation(Function f, ExpressionTranslator etran) {\n      Contract.Requires(f != null);\n      Contract.Requires(etran != null);\n      Contract.Requires(VisibleInScope(f));\n      var module = f.EnclosingClass.Module;\n\n      if (InVerificationScope(f)) {\n        return\n          Bpl.Expr.Le(Bpl.Expr.Literal(module.CallGraph.GetSCCRepresentativeId(f)), etran.FunctionContextHeight());\n      } else {\n        return Bpl.Expr.True;\n      }\n    }\n\n    Bpl.Axiom FunctionAxiom(Function f, Expression body, ICollection<Formal> lits, TopLevelDecl overridingClass = null) {\n      Contract.Requires(f != null);\n      Contract.Requires(predef != null);\n      Contract.Requires(f.EnclosingClass != null);\n      Contract.Requires(!f.IsStatic || overridingClass == null);\n      Contract.Requires(overridingClass == null || body is FunctionCallExpr);  // pseudo body (see caller)\n\n      // only if body is null, we will return null:\n      Contract.Ensures((Contract.Result<Bpl.Axiom>() == null) == (body == null));\n\n      bool readsHeap = AlwaysUseHeap || f.ReadsHeap;\n      foreach (MaybeFreeExpression e in f.Req) {\n        readsHeap = readsHeap || UsesHeap(e.E);\n      }\n      if (body != null && UsesHeap(body)) {\n        readsHeap = true;\n      }\n\n      ExpressionTranslator etran;\n      Bpl.BoundVariable bvPrevHeap = null;\n      if (f is TwoStateFunction) {\n        bvPrevHeap = new Bpl.BoundVariable(f.tok, new Bpl.TypedIdent(f.tok, \"$prevHeap\", predef.HeapType));\n        etran = new ExpressionTranslator(this, predef,\n          f.ReadsHeap ? new Bpl.IdentifierExpr(f.tok, predef.HeapVarName, predef.HeapType) : null,\n          new Bpl.IdentifierExpr(f.tok, bvPrevHeap));\n      } else {\n        etran = AlwaysUseHeap || readsHeap ?\n          new ExpressionTranslator(this, predef, f.tok) :\n          new ExpressionTranslator(this, predef, (Bpl.Expr)null);\n      }\n\n      // This method generates the Definition Axiom, suitably modified according to the optional \"lits\".\n      //\n      // axiom  // definition axiom\n      //   AXIOM_ACTIVATION\n      //   ==>\n      //   (forall s, $Heap, formals ::                  // let args := $Heap,formals\n      //       { f(Succ(s), args) }                      // (*)\n      //       (f#canCall(args) || USE_VIA_CONTEXT) &&\n      //       dtype(this) == overridingClass            // if \"overridingClass\" != null\n      //       ==>\n      //       BODY-can-make-its-calls &&\n      //       f(Succ(s), args) == BODY);                // (*)\n      //\n      // where:\n      //\n      // AXIOM_ACTIVATION\n      // for visibility==ForeignModuleOnly, means:\n      //   mh < ModuleContextHeight\n      // for visibility==IntraModuleOnly, means:\n      //   mh == ModuleContextHeight && fh <= FunctionContextHeight\n      //\n      // USE_VIA_CONTEXT\n      // for visibility==ForeignModuleOnly, means:\n      //   GOOD_PARAMETERS\n      // for visibility==IntraModuleOnly, means:\n      //   fh != FunctionContextHeight &&\n      //   GOOD_PARAMETERS\n      // where GOOD_PARAMETERS means:\n      //   $IsGoodHeap($Heap) && this != null && formals-have-the-expected-types &&\n      //   Pre($Heap,formals)\n      //\n      // NOTE: this is lifted out to a #requires function for intra module calls,\n      //       and used in the function pseudo-handles for top level functions.\n      //       For body-less functions, this is emitted when body is null.\n      //\n      // BODY\n      // means:\n      //   the body of f translated with \"s\" as the layer argument\n      //\n      // The variables \"formals\" are the formals of function \"f\".\n      // The list \"args\" is the list of formals of function \"f\".\n      //\n      // The translation of \"body\" uses \"s\" as the layer argument for intra-cluster calls and the default layer argument\n      // (which is Succ(0)) for other calls.  Usually, the layer argument in the LHS of the definition (and also in the trigger,\n      // see the two occurrences of (*) above) use Succ(s) as the layer argument.  However, if \"lits\" are specified, then\n      // then the argument used is just \"s\" (in both the LHS and trigger).\n      //\n      // Note, an antecedent $Heap[this,alloc] is intentionally left out:  including it would only weaken\n      // the axiom.  Moreover, leaving it out does not introduce any soundness problem, because the Dafny\n      // allocation statement changes only an allocation bit and then re-assumes $IsGoodHeap; so if it is\n      // sound after that, then it would also have been sound just before the allocation.\n      //\n\n      // quantify over the type arguments, and add them first to the arguments\n      List<Bpl.Expr> args = new List<Bpl.Expr>();\n      List<Bpl.Expr> reqArgs = new List<Bpl.Expr>();\n      List<Bpl.Expr> tyargs;\n      var forallFormals = MkTyParamBinders(GetTypeParams(f), out tyargs);\n      var funcFormals = MkTyParamBinders(GetTypeParams(f), out tyargs);\n      reqArgs.AddRange(tyargs);\n\n      Bpl.BoundVariable layer;\n      if (f.IsFuelAware()) {\n        layer = new Bpl.BoundVariable(f.tok, new Bpl.TypedIdent(f.tok, \"$ly\", predef.LayerType));\n        forallFormals.Add(layer);\n        funcFormals.Add(layer);\n        reqArgs.Add(new Bpl.IdentifierExpr(f.tok, layer));\n        // Note, \"layer\" is not added to \"args\" here; rather, that's done below, as needed\n      } else {\n        layer = null;\n      }\n\n      Bpl.Expr ante = Bpl.Expr.True;\n      if (f is TwoStateFunction) {\n        Contract.Assert(bvPrevHeap != null);\n        forallFormals.Add(bvPrevHeap);\n        funcFormals.Add(bvPrevHeap);\n        args.Add(etran.Old.HeapExpr);\n        reqArgs.Add(new Bpl.IdentifierExpr(f.tok, bvPrevHeap));\n        // ante:  $IsGoodHeap($prevHeap) &&\n        ante = BplAnd(ante, FunctionCall(f.tok, BuiltinFunction.IsGoodHeap, null, etran.Old.HeapExpr));\n      }\n      Bpl.Expr goodHeap = null;\n      var bv = new Bpl.BoundVariable(f.tok, new Bpl.TypedIdent(f.tok, predef.HeapVarName, predef.HeapType));\n\n      if (AlwaysUseHeap || f.ReadsHeap) {\n        funcFormals.Add(bv);\n        args.Add(new Bpl.IdentifierExpr(f.tok, bv));\n        reqArgs.Add(new Bpl.IdentifierExpr(f.tok, bv));\n      }\n      // ante:  $IsGoodHeap($Heap) && $HeapSucc($prevHeap, $Heap) && this != null && formals-have-the-expected-types &&\n      if (AlwaysUseHeap || readsHeap) {\n        forallFormals.Add(bv);\n        goodHeap = FunctionCall(f.tok, BuiltinFunction.IsGoodHeap, null, etran.HeapExpr);\n        ante = BplAnd(ante, goodHeap);\n      }\n      if (f is TwoStateFunction && f.ReadsHeap) {\n        ante = BplAnd(ante, HeapSucc(etran.Old.HeapExpr, etran.HeapExpr));\n      }\n\n      Bpl.Expr additionalAntecedent = null;\n      if (!f.IsStatic) {\n        var bvThis = new Bpl.BoundVariable(f.tok, new Bpl.TypedIdent(f.tok, etran.This, TrReceiverType(f)));\n        forallFormals.Add(bvThis);\n        funcFormals.Add(bvThis);\n        reqArgs.Add(new Bpl.IdentifierExpr(f.tok, bvThis));\n        var bvThisIdExpr = new Bpl.IdentifierExpr(f.tok, bvThis);\n        args.Add(bvThisIdExpr);\n        // add well-typedness conjunct to antecedent\n        Type thisType = Resolver.GetReceiverType(f.tok, f);\n        Bpl.Expr wh = Bpl.Expr.And(\n          ReceiverNotNull(bvThisIdExpr),\n          (f is TwoStateFunction ? etran.Old : etran).GoodRef(f.tok, bvThisIdExpr, thisType));\n        ante = BplAnd(ante, wh);\n        if (overridingClass != null) {\n          // additionalAntecednet := dtype(this) == overridingClass\n          additionalAntecedent = DType(bvThisIdExpr, ClassTyCon(overridingClass, new List<Expr>()));  // TODO: this needs more work if overridingClass has type parameters\n        }\n      }\n\n      var anteReqAxiom = ante;  // note that antecedent so far is the same for #requires axioms, even the receiver parameter of a two-state function\n      var substMap = new Dictionary<IVariable, Expression>();\n      foreach (Formal p in f.Formals) {\n        bv = new Bpl.BoundVariable(p.tok, new Bpl.TypedIdent(p.tok, p.AssignUniqueName(currentDeclaration.IdGenerator), TrType(p.Type)));\n        forallFormals.Add(bv);\n        funcFormals.Add(bv);\n        reqArgs.Add(new Bpl.IdentifierExpr(f.tok, bv));\n        Bpl.Expr formal = new Bpl.IdentifierExpr(p.tok, bv);\n        if (lits != null && lits.Contains(p) && !substMap.ContainsKey(p)) {\n          args.Add(Lit(formal));\n          var ie = new IdentifierExpr(p.tok, p.AssignUniqueName(f.IdGenerator));\n          ie.Var = p; ie.Type = ie.Var.Type;\n          var l = new UnaryOpExpr(p.tok, UnaryOpExpr.Opcode.Lit, ie);\n          l.Type = ie.Var.Type;\n          substMap.Add(p, l);\n        } else {\n          args.Add(formal);\n        }\n        // add well-typedness conjunct to antecedent\n        Bpl.Expr wh = GetWhereClause(p.tok, formal, p.Type, p.IsOld ? etran.Old : etran, NOALLOC);\n        if (wh != null) { ante = BplAnd(ante, wh); }\n        wh = GetWhereClause(p.tok, formal, p.Type, etran, NOALLOC);\n        if (wh != null) { anteReqAxiom = BplAnd(anteReqAxiom, wh); }\n      }\n\n      Bpl.Expr pre = Bpl.Expr.True;\n      foreach (MaybeFreeExpression req in f.Req) {\n        pre = BplAnd(pre, etran.TrExpr(Substitute(req.E, null, substMap)));\n      }\n      var preReqAxiom = pre;\n      if (f is TwoStateFunction) {\n        // Checked preconditions that old parameters really existed in previous state\n        var index = 0;\n        Bpl.Expr preRA = Bpl.Expr.True;\n        foreach (var formal in f.Formals) {\n          if (formal.IsOld) {\n            var dafnyFormalIdExpr = new IdentifierExpr(formal.tok, formal);\n            preRA = BplAnd(preRA, MkIsAlloc(etran.TrExpr(dafnyFormalIdExpr), formal.Type, etran.Old.HeapExpr));\n          }\n          index++;\n        }\n        preReqAxiom = BplAnd(preRA, pre);\n      }\n\n      // Add the precondition function and its axiom (which is equivalent to the anteReqAxiom)\n      if (body == null || (RevealedInScope(f) && lits == null)) {\n        if (overridingClass == null) {\n          var precondF = new Bpl.Function(f.tok,\n            RequiresName(f), new List<Bpl.TypeVariable>(),\n            funcFormals.ConvertAll(v => (Bpl.Variable)BplFormalVar(null, v.TypedIdent.Type, true)),\n            BplFormalVar(null, Bpl.Type.Bool, false));\n          sink.AddTopLevelDeclaration(precondF);\n        }\n        var appl = FunctionCall(f.tok, RequiresName(f), Bpl.Type.Bool, reqArgs);\n        Bpl.Trigger trig = BplTriggerHeap(this, f.tok, appl,\n          (AlwaysUseHeap || f.ReadsHeap || !readsHeap) ? null : etran.HeapExpr);\n        // axiom (forall params :: { f#requires(params) }  ante ==> f#requires(params) == pre);\n        sink.AddTopLevelDeclaration(new Axiom(f.tok,\n          BplForall(forallFormals, trig, BplImp(anteReqAxiom, Bpl.Expr.Eq(appl, preReqAxiom))),\n          \"#requires axiom for \" + f.FullSanitizedName));\n      }\n      if (body == null || !RevealedInScope(f)) {\n        return null;\n      }\n\n      // useViaContext: (mh != ModuleContextHeight || fh != FunctionContextHeight)\n      ModuleDefinition mod = f.EnclosingClass.Module;\n      Bpl.Expr useViaContext = !InVerificationScope(f) ? (Bpl.Expr)Bpl.Expr.True :\n        Bpl.Expr.Neq(Bpl.Expr.Literal(mod.CallGraph.GetSCCRepresentativeId(f)), etran.FunctionContextHeight());\n      // ante := (useViaContext && typeAnte && pre)\n      ante = BplAnd(useViaContext, BplAnd(ante, pre));\n\n      // useViaCanCall: f#canCall(args)\n      Bpl.IdentifierExpr canCallFuncID = new Bpl.IdentifierExpr(f.tok, f.FullSanitizedName + \"#canCall\", Bpl.Type.Bool);\n      Bpl.Expr useViaCanCall = new Bpl.NAryExpr(f.tok, new Bpl.FunctionCall(canCallFuncID), Concat(tyargs,args));\n\n      // ante := useViaCanCall || (useViaContext && typeAnte && pre)\n      ante = Bpl.Expr.Or(useViaCanCall, ante);\n      if (additionalAntecedent != null) {\n        ante = Bpl.Expr.And(ante, additionalAntecedent);\n      }\n\n      Bpl.Expr funcAppl;\n      {\n        var funcID = new Bpl.IdentifierExpr(f.tok, f.FullSanitizedName, TrType(f.ResultType));\n        var funcArgs = new List<Bpl.Expr>();\n        funcArgs.AddRange(tyargs);\n        if (layer != null) {\n          var ly = new Bpl.IdentifierExpr(f.tok, layer);\n          //if (lits == null) {\n            funcArgs.Add(LayerSucc(ly));\n          //} else {\n          //  funcArgs.Add(ly);\n          //}\n        }\n        funcArgs.AddRange(args);\n        funcAppl = new Bpl.NAryExpr(f.tok, new Bpl.FunctionCall(funcID), funcArgs);\n      }\n\n      Bpl.Trigger tr = BplTriggerHeap(this, f.tok, funcAppl,\n        (AlwaysUseHeap || f.ReadsHeap || !readsHeap) ? null : etran.HeapExpr);\n      Bpl.Expr tastyVegetarianOption;\n      if (!RevealedInScope(f) || (f.IsProtected && !InVerificationScope(f))) {\n        tastyVegetarianOption = Bpl.Expr.True;\n      } else {\n        var bodyWithSubst = Substitute(body, null, substMap);\n        if (f is PrefixPredicate) {\n          var pp = (PrefixPredicate)f;\n          bodyWithSubst = PrefixSubstitution(pp, bodyWithSubst);\n        }\n        Bpl.Expr ly = null;\n        if (layer != null) {\n          ly = new Bpl.IdentifierExpr(f.tok, layer);\n          if (lits != null) {   // Lit axiom doesn't consume any fuel\n            ly = LayerSucc(ly);\n          }\n        }\n        ExpressionTranslator etranBody;\n        if (layer == null) {\n          etranBody = etran;\n        } else if (overridingClass != null) {\n          var pseudoBody = (FunctionCallExpr)body;\n          etranBody = etran.LimitedFunctions(pseudoBody.Function, LayerSucc(ly));\n        } else {\n          etranBody = etran.LimitedFunctions(f, ly);\n        }\n\n        tastyVegetarianOption = BplAnd(CanCallAssumption(bodyWithSubst, etranBody),\n          BplAnd(TrFunctionSideEffect(bodyWithSubst, etranBody),Bpl.Expr.Eq(funcAppl, etranBody.TrExpr(bodyWithSubst))));\n      }\n      QKeyValue kv = null;\n      if (lits != null) {\n        kv = new QKeyValue(f.tok, \"weight\", new List<object>() { Bpl.Expr.Literal(3) }, null);\n      }\n      Bpl.Expr ax = BplForall(f.tok, new List<Bpl.TypeVariable>(), forallFormals, kv, tr, Bpl.Expr.Imp(ante, tastyVegetarianOption));\n      var activate = AxiomActivation(f, etran);\n      string comment;\n      if (overridingClass == null) {\n        comment = \"definition axiom for \" + f.FullSanitizedName;\n      } else {\n        comment = \"override axiom for \" + f.FullSanitizedName + \" in class \" + overridingClass.FullSanitizedName;\n      }\n      if (lits != null) {\n        if (lits.Count == f.Formals.Count) {\n          comment += \" for all literals\";\n        } else {\n          comment += \" for decreasing-related literals\";\n        }\n      }\n      if (RevealedInScope(f)) {\n        comment += \"(revealed)\";\n      } else if (!RevealedInScope(f)) {\n        comment += \" (opaque)\";\n      }\n      return new Bpl.Axiom(f.tok, Bpl.Expr.Imp(activate, ax), comment);\n    }\n\n    Bpl.Type TrReceiverType(MemberDecl f) {\n      Contract.Requires(f != null);\n      return TrType(Resolver.GetReceiverType(f.tok, f));\n    }\n\n    Bpl.Expr ReceiverNotNull(Bpl.Expr th) {\n      Contract.Requires(th != null);\n      if (th.Type == predef.RefType) {\n        return Bpl.Expr.Neq(th, predef.Null);\n      } else {\n        return Bpl.Expr.True;\n      }\n    }\n\n    Expr TrFunctionSideEffect(Expression expr, ExpressionTranslator etran) {\n      Expr e = Bpl.Expr.True;\n      if (expr is StmtExpr) {\n        // if there is a call to reveal_ lemma, we need to record its side effect.\n        var stmt = ((StmtExpr)expr).S;\n        e = TrFunctionSideEffect(stmt, etran);\n      }\n      return e;\n    }\n\n    Expr TrFunctionSideEffect(Statement stmt, ExpressionTranslator etran) {\n      Expr e = Bpl.Expr.True;\n      e = TrStmtSideEffect(e, stmt, etran);\n      foreach (var ss in stmt.SubStatements) {\n        e = TrStmtSideEffect(e, ss, etran);\n      }\n      return e;\n    }\n\n    Expr TrStmtSideEffect(Expr e, Statement stmt, ExpressionTranslator etran) {\n      if (stmt is CallStmt) {\n        var call = (CallStmt)stmt;\n        var m = call.Method;\n        if (IsOpaqueRevealLemma(m)) {\n          List<Expression> args = Attributes.FindExpressions(m.Attributes, \"fuel\");\n          if (args != null) {\n            MemberSelectExpr selectExpr = args[0].Resolved as MemberSelectExpr;\n            if (selectExpr != null) {\n              Function f = selectExpr.Member as Function;\n              FuelConstant fuelConstant = this.functionFuel.Find(x => x.f == f);\n              if (fuelConstant != null) {\n                Bpl.Expr startFuel = fuelConstant.startFuel;\n                Bpl.Expr startFuelAssert = fuelConstant.startFuelAssert;\n                Bpl.Expr moreFuel_expr = fuelConstant.MoreFuel(sink, predef, f.IdGenerator);\n                Bpl.Expr layer = etran.layerInterCluster.LayerN(1, moreFuel_expr);\n                Bpl.Expr layerAssert = etran.layerInterCluster.LayerN(2, moreFuel_expr);\n\n                e = BplAnd(e, Bpl.Expr.Eq(startFuel, layer));\n                e = BplAnd(e, Bpl.Expr.Eq(startFuelAssert, layerAssert));\n                e = BplAnd(e, Bpl.Expr.Eq(this.FunctionCall(f.tok, BuiltinFunction.AsFuelBottom, null, moreFuel_expr), moreFuel_expr));\n              }\n            }\n          }\n        }\n      } else if (stmt is RevealStmt) {\n        var reveal = (RevealStmt)stmt;\n        foreach (var s in reveal.ResolvedStatements) {\n          e = BplAnd(e, TrFunctionSideEffect(s, etran));\n        }\n      }\n      return e;\n    }\n\n    /// <summary>\n    /// For a fixpoint-predicate P, \"pp\" is the prefix predicate for P (such that P = pp.FixpointPred) and\n    /// \"body\" is the body of P.  Return what would be the body of the prefix predicate pp.\n    /// In particular, return\n    /// #if _k has type nat:\n    ///   0 LESS _k  IMPLIES  body'                        // for co-inductive predicates\n    ///   0 LESS _k  AND  body'                            // for inductive predicates\n    /// #elsif _k has type ORDINAL:\n    ///   (0 LESS ORD#Offset(_k)  IMPLIES  body') AND\n    ///   (0 == ORD#Offset(_k) IMPLIES forall _k':ORDINAL :: _k' LESS _k ==> pp(_k', args))  // for co-inductive predicates\n    ///   (0 == ORD#Offset(_k) IMPLIES exists _k':ORDINAL :: _k' LESS _k && pp(_k', args))   // for inductive predicates\n    /// #endif\n    /// where body' is body with the formals of P replaced by the corresponding\n    /// formals of pp and with self-calls P(s) replaced by recursive calls to\n    /// pp(_k - 1, s).\n    /// </summary>\n    Expression PrefixSubstitution(PrefixPredicate pp, Expression body) {\n      Contract.Requires(pp != null);\n\n      var typeMap = Util.Dict<TypeParameter,Type>(pp.FixpointPred.TypeArgs, Map(pp.TypeArgs, x => new UserDefinedType(x)));\n\n      var paramMap = new Dictionary<IVariable, Expression>();\n      for (int i = 0; i < pp.FixpointPred.Formals.Count; i++) {\n        var replacement = pp.Formals[i + 1];  // the +1 is to skip pp's _k parameter\n        var param = new IdentifierExpr(replacement.tok, replacement.Name);\n        param.Var = replacement;  // resolve here\n        param.Type = replacement.Type;  // resolve here\n        paramMap.Add(pp.FixpointPred.Formals[i], param);\n      }\n\n      var k = new IdentifierExpr(pp.tok, pp.K.Name);\n      k.Var = pp.K;  // resolve here\n      k.Type = pp.K.Type;  // resolve here\n      Expression kMinusOne = Expression.CreateSubtract(k, Expression.CreateNatLiteral(pp.tok, 1, pp.K.Type));\n\n      var s = new PrefixCallSubstituter(null, paramMap, typeMap, pp.FixpointPred, kMinusOne);\n      body = s.Substitute(body);\n\n      if (pp.K.Type.IsBigOrdinalType) {\n        // 0 < k.Offset\n        Contract.Assume(program.BuiltIns.ORDINAL_Offset != null);  // should have been filled in by the resolver\n        var kOffset = new MemberSelectExpr(pp.tok, k, program.BuiltIns.ORDINAL_Offset);\n        var kIsPositive = Expression.CreateLess(Expression.CreateIntLiteral(pp.tok, 0), kOffset);\n        var kIsLimit = Expression.CreateEq(Expression.CreateIntLiteral(pp.tok, 0), kOffset, Type.Int);\n        var kprimeVar = new BoundVar(pp.tok, \"_k'\", Type.BigOrdinal);\n        var kprime = new IdentifierExpr(pp.tok, kprimeVar);\n\n        var substMap = new Dictionary<IVariable, Expression>();\n        substMap.Add(pp.K, kprime);\n        List<Type> typeApplication;  // not used\n        Dictionary<TypeParameter, Type> typeArgumentSubstitutions;\n        Expression recursiveCallReceiver;\n        List<Expression> recursiveCallArgs;\n        RecursiveCallParameters(pp.tok, pp, pp.TypeArgs, pp.Formals, substMap, out typeApplication, out typeArgumentSubstitutions, out recursiveCallReceiver, out recursiveCallArgs);\n        var ppCall = new FunctionCallExpr(pp.tok, pp.Name, recursiveCallReceiver, pp.tok, recursiveCallArgs);\n        ppCall.Function = pp;\n        ppCall.Type = Type.Bool;\n        ppCall.TypeArgumentSubstitutions = typeArgumentSubstitutions;\n\n        Attributes triggerAttr = new Attributes(\"trigger\", new List<Expression> { ppCall }, null);\n        Expression limitCalls;\n        if (pp.FixpointPred is CoPredicate) {\n          // forall k':ORDINAL | _k' LESS _k :: pp(_k', args)\n          var smaller = Expression.CreateLess(kprime, k);\n          limitCalls = new ForallExpr(pp.tok, new List<BoundVar> { kprimeVar }, smaller, ppCall, triggerAttr);\n          limitCalls.Type = Type.Bool;  // resolve here\n        } else {\n          // exists k':ORDINAL | _k' LESS _k :: pp(_k', args)\n          // Here, instead of using the usual ORD#Less, we use the semantically equivalent ORD#LessThanLimit, because this\n          // allows us to write a good trigger for a targeted monotonicity axiom.  That axiom, in turn, makes the\n          // automatica verification more powerful for inductive lemmas that have more than one focal-predicate term.\n          var smaller = new BinaryExpr(kprime.tok, BinaryExpr.Opcode.Lt, kprime, k) {\n            ResolvedOp = BinaryExpr.ResolvedOpcode.LessThanLimit,\n            Type = Type.Bool\n          };\n          limitCalls = new ExistsExpr(pp.tok, new List<BoundVar> { kprimeVar }, smaller, ppCall, triggerAttr);\n          limitCalls.Type = Type.Bool;  // resolve here\n        }\n        var a = Expression.CreateImplies(kIsPositive, body);\n        var b = Expression.CreateImplies(kIsLimit, limitCalls);\n        return Expression.CreateAnd(a, b);\n      } else {\n        // 0 < k\n        var kIsPositive = Expression.CreateLess(Expression.CreateIntLiteral(pp.tok, 0), k);\n        if (pp.FixpointPred is CoPredicate) {\n          // add antecedent \"0 < _k ==>\"\n          return Expression.CreateImplies(kIsPositive, body);\n        } else {\n          // add initial conjunct \"0 < _k &&\"\n          return Expression.CreateAnd(kIsPositive, body);\n        }\n      }\n    }\n\n    public static void RecursiveCallParameters(IToken tok, MemberDecl member, List<TypeParameter> typeParams, List<Formal> ins,\n      Dictionary<IVariable, Expression>/*?*/ substMap,\n      out List<Type> typeApplication, out Dictionary<TypeParameter,Type> typeArgumentSubstitutions,\n      out Expression receiver, out List<Expression> arguments) {\n      Contract.Requires(tok != null);\n      Contract.Requires(member != null);\n      Contract.Requires(member.EnclosingClass is TopLevelDeclWithMembers);\n      Contract.Requires(typeParams != null);\n      Contract.Requires(ins != null);\n      Contract.Requires(substMap != null);\n      Contract.Ensures(Contract.ValueAtReturn(out typeApplication) != null);\n      Contract.Ensures(Contract.ValueAtReturn(out typeArgumentSubstitutions) != null);\n      Contract.Ensures(Contract.ValueAtReturn(out receiver) != null);\n      Contract.Ensures(Contract.ValueAtReturn(out arguments) != null);\n\n      if (member.IsStatic) {\n        receiver = new StaticReceiverExpr(tok, (ClassDecl)member.EnclosingClass, true);  // this also resolves it\n      } else {\n        receiver = new ImplicitThisExpr(tok);\n        receiver.Type = Resolver.GetThisType(tok, (TopLevelDeclWithMembers)member.EnclosingClass);  // resolve here\n      }\n\n      arguments = new List<Expression>();\n      foreach (var inFormal in ins) {\n        Expression inE;\n        if (substMap.TryGetValue(inFormal, out inE)) {\n          arguments.Add(inE);\n        } else {\n          var ie = new IdentifierExpr(inFormal.tok, inFormal.Name);\n          ie.Var = inFormal;  // resolve here\n          ie.Type = inFormal.Type;  // resolve here\n          arguments.Add(ie);\n        }\n      }\n\n      typeArgumentSubstitutions = new Dictionary<TypeParameter, Type>();\n      typeApplication = new List<Type>();\n      Contract.Assert(((TopLevelDeclWithMembers)member.EnclosingClass).TypeArgs.Count == receiver.Type.TypeArgs.Count);\n      for (int i = 0; i < receiver.Type.TypeArgs.Count; i++) {\n        var tp = ((TopLevelDeclWithMembers)member.EnclosingClass).TypeArgs[i];\n        var ta = receiver.Type.TypeArgs[i];\n        typeApplication.Add(ta);\n        typeArgumentSubstitutions.Add(tp, ta);\n      }\n      foreach (var tp in typeParams) {\n        var ta = new UserDefinedType(tp);\n        typeApplication.Add(ta);\n        typeArgumentSubstitutions.Add(tp, ta);\n      }\n    }\n\n    void AddLayerSynonymAxiom(Function f) {\n      Contract.Requires(f != null);\n      Contract.Requires(f.IsFuelAware());\n      Contract.Requires(sink != null && predef != null);\n      // axiom  // layer synonym axiom\n      //   (forall s, $Heap, formals ::\n      //       { f(Succ(s), $Heap, formals) }\n      //       f(Succ(s), $Heap, formals) == f(s, $Heap, formals));\n\n      List<Bpl.Expr> tyargs;\n      var formals = MkTyParamBinders(GetTypeParams(f), out tyargs);\n      var args1 = new List<Bpl.Expr>(tyargs);\n      var args0 = new List<Bpl.Expr>(tyargs);\n\n      var bv = new Bpl.BoundVariable(f.tok, new Bpl.TypedIdent(f.tok, \"$ly\", predef.LayerType));\n      formals.Add(bv);\n      var s = new Bpl.IdentifierExpr(f.tok, bv);\n      args1.Add(FunctionCall(f.tok, BuiltinFunction.LayerSucc, null, s));\n      args0.Add(s);\n\n      if (f is TwoStateFunction) {\n        bv = new Bpl.BoundVariable(f.tok, new Bpl.TypedIdent(f.tok, \"$prevHeap\", predef.HeapType));\n        formals.Add(bv);\n        s = new Bpl.IdentifierExpr(f.tok, bv);\n        args1.Add(s);\n        args0.Add(s);\n      }\n      if (AlwaysUseHeap || f.ReadsHeap) {\n        bv = new Bpl.BoundVariable(f.tok, new Bpl.TypedIdent(f.tok, predef.HeapVarName, predef.HeapType));\n        formals.Add(bv);\n        s = new Bpl.IdentifierExpr(f.tok, bv);\n        args1.Add(s);\n        args0.Add(s);\n      }\n\n      if (!f.IsStatic) {\n        bv = new Bpl.BoundVariable(f.tok, new Bpl.TypedIdent(f.tok, \"this\", TrReceiverType(f)));\n        formals.Add(bv);\n        s = new Bpl.IdentifierExpr(f.tok, bv);\n        args1.Add(s);\n        args0.Add(s);\n      }\n      foreach (var p in f.Formals) {\n        bv = new Bpl.BoundVariable(p.tok, new Bpl.TypedIdent(p.tok, p.AssignUniqueName(f.IdGenerator), TrType(p.Type)));\n        formals.Add(bv);\n        s = new Bpl.IdentifierExpr(f.tok, bv);\n        args1.Add(s);\n        args0.Add(s);\n      }\n\n      var funcID = new Bpl.FunctionCall(new Bpl.IdentifierExpr(f.tok, f.FullSanitizedName, TrType(f.ResultType)));\n      var funcAppl1 = new Bpl.NAryExpr(f.tok, funcID, args1);\n      var funcAppl0 = new Bpl.NAryExpr(f.tok, funcID, args0);\n\n      Bpl.Trigger tr = new Bpl.Trigger(f.tok, true, new List<Bpl.Expr> { funcAppl1 });\n      Bpl.Expr ax = new Bpl.ForallExpr(f.tok, new List<Bpl.TypeVariable>(), formals, null, tr, Bpl.Expr.Eq(funcAppl1, funcAppl0));\n      sink.AddTopLevelDeclaration(new Bpl.Axiom(f.tok, ax, \"layer synonym axiom\"));\n    }\n\n    void AddFuelSynonymAxiom(Function f) {\n      // axiom  // fuel axiom\n      //   (forall s, $Heap, formals ::\n      //       { f(AsFuelBottom(s), $Heap, formals) }\n      //       f(s, $Heap, formals) == f($LZ, $Heap, formals));\n      Contract.Requires(f != null);\n      Contract.Requires(f.IsFuelAware());\n      Contract.Requires(sink != null && predef != null);\n\n      List<Bpl.Expr> tyargs;\n      var formals = MkTyParamBinders(GetTypeParams(f), out tyargs);\n      var args2 = new List<Bpl.Expr>(tyargs);\n      var args1 = new List<Bpl.Expr>(tyargs);\n      var args0 = new List<Bpl.Expr>(tyargs);\n\n      var bv = new Bpl.BoundVariable(f.tok, new Bpl.TypedIdent(f.tok, \"$ly\", predef.LayerType));\n      formals.Add(bv);\n      var s = new Bpl.IdentifierExpr(f.tok, bv);\n      args2.Add(FunctionCall(f.tok, BuiltinFunction.AsFuelBottom, null, s));\n      args1.Add(s);\n      args0.Add(new Bpl.IdentifierExpr(f.tok, \"$LZ\",predef.LayerType)); // $LZ\n\n      if (f is TwoStateFunction) {\n        bv = new Bpl.BoundVariable(f.tok, new Bpl.TypedIdent(f.tok, \"$prevHeap\", predef.HeapType));\n        formals.Add(bv);\n        s = new Bpl.IdentifierExpr(f.tok, bv);\n        args2.Add(s);\n        args1.Add(s);\n        args0.Add(s);\n      }\n      if (AlwaysUseHeap || f.ReadsHeap) {\n        bv = new Bpl.BoundVariable(f.tok, new Bpl.TypedIdent(f.tok, predef.HeapVarName, predef.HeapType));\n        formals.Add(bv);\n        s = new Bpl.IdentifierExpr(f.tok, bv);\n        args2.Add(s);\n        args1.Add(s);\n        args0.Add(s);\n      }\n\n      if (!f.IsStatic) {\n        bv = new Bpl.BoundVariable(f.tok, new Bpl.TypedIdent(f.tok, \"this\", TrReceiverType(f)));\n        formals.Add(bv);\n        s = new Bpl.IdentifierExpr(f.tok, bv);\n        args2.Add(s);\n        args1.Add(s);\n        args0.Add(s);\n      }\n      foreach (var p in f.Formals) {\n        bv = new Bpl.BoundVariable(p.tok, new Bpl.TypedIdent(p.tok, p.AssignUniqueName(f.IdGenerator), TrType(p.Type)));\n        formals.Add(bv);\n        s = new Bpl.IdentifierExpr(f.tok, bv);\n        args2.Add(s);\n        args1.Add(s);\n        args0.Add(s);\n      }\n\n      var funcID = new Bpl.FunctionCall(new Bpl.IdentifierExpr(f.tok, f.FullSanitizedName, TrType(f.ResultType)));\n      var funcAppl2 = new Bpl.NAryExpr(f.tok, funcID, args2);\n      var funcAppl1 = new Bpl.NAryExpr(f.tok, funcID, args1);\n      var funcAppl0 = new Bpl.NAryExpr(f.tok, funcID, args0);\n\n      Bpl.Trigger tr = new Bpl.Trigger(f.tok, true, new List<Bpl.Expr> { funcAppl2 });\n      Bpl.Expr ax = new Bpl.ForallExpr(f.tok, new List<Bpl.TypeVariable>(), formals, null, tr, Bpl.Expr.Eq(funcAppl1, funcAppl0));\n      sink.AddTopLevelDeclaration(new Bpl.Axiom(f.tok, ax, \"fuel synonym axiom\"));\n    }\n\n    /// <summary>\n    /// In the following,\n    /// if \"pp\" is a co-predicate, then QQQ and NNN and HHH and EEE stand for \"forall\" and \"\" and \"==>\" and REVERSE-IMPLIES, and\n    /// if \"pp\" is an inductive predicate, then QQQ and NNN and HHH and EEE stand for \"exists\" and \"!\" and \"&&\" and \"==>\".\n    /// ==========  For co-predicates:\n    /// Add the axioms:\n    ///   forall args :: P(args) ==> QQQ k: nat :: P#[k](args)\n    ///   forall args :: (QQQ k: nat :: P#[k](args)) ==> P(args)\n    ///   forall args,k :: k == 0 ==> NNN P#[k](args)\n    /// where \"args\" is \"heap, formals\".  In more details:\n    ///   AXIOM_ACTIVATION ==> forall args :: { P(args) } args-have-appropriate-values && P(args) ==> QQQ k { P#[k](args) } :: 0 ATMOST k HHH P#[k](args)\n    ///   AXIOM_ACTIVATION ==> forall args :: { P(args) } args-have-appropriate-values && (QQQ k :: 0 ATMOST k HHH P#[k](args)) ==> P(args)\n    ///   AXIOM_ACTIVATION ==> forall args,k :: args-have-appropriate-values && k == 0 ==> NNN P#0#[k](args)\n    ///   AXIOM_ACTIVATION ==> forall args,k,m :: args-have-appropriate-values && 0 ATMOST k LESS m ==> (P#[k](args) EEE P#[m](args))  (*)\n    /// where\n    /// AXIOM_ACTIVATION\n    /// means:\n    ///   mh LESS ModuleContextHeight ||\n    ///   (mh == ModuleContextHeight && fh ATMOST FunctionContextHeight)\n    /// There is also a specialized version of (*) for inductive predicates.\n    /// </summary>\n    void AddPrefixPredicateAxioms(PrefixPredicate pp) {\n      Contract.Requires(pp != null);\n      Contract.Requires(predef != null);\n      var co = pp.FixpointPred;\n      var tok = pp.tok;\n      var etran = new ExpressionTranslator(this, predef, tok);\n\n      List<Bpl.Expr> tyexprs;\n      var tyvars = MkTyParamBinders(GetTypeParams(pp), out tyexprs);\n\n      var bvs = new List<Variable>(tyvars);\n      var coArgs = new List<Bpl.Expr>(tyexprs);\n      var prefixArgs = new List<Bpl.Expr>(tyexprs);\n      var prefixArgsLimited = new List<Bpl.Expr>(tyexprs);\n      var prefixArgsLimitedM = new List<Bpl.Expr>(tyexprs);\n      if (pp.IsFuelAware()) {\n        var sV = new Bpl.BoundVariable(tok, new Bpl.TypedIdent(tok, \"$ly\", predef.LayerType));\n        var s = new Bpl.IdentifierExpr(tok, sV);\n        var succS = FunctionCall(tok, BuiltinFunction.LayerSucc, null, s);\n        bvs.Add(sV);\n        coArgs.Add(succS);\n        prefixArgs.Add(succS);\n        prefixArgsLimited.Add(s);\n        prefixArgsLimitedM.Add(s);\n      }\n      Bpl.Expr h;\n      if (AlwaysUseHeap || pp.ReadsHeap) {\n        var heapIdent = new Bpl.TypedIdent(tok, predef.HeapVarName, predef.HeapType);\n        var bv = new Bpl.BoundVariable(tok, heapIdent);\n        h = new Bpl.IdentifierExpr(tok, bv);\n        bvs.Add(bv);\n        coArgs.Add(h);\n        prefixArgs.Add(h);\n        prefixArgsLimited.Add(h);\n        prefixArgsLimitedM.Add(h);\n      } else {\n        h = null;\n      }\n      // ante:  $IsGoodHeap($Heap) && this != null && formals-have-the-expected-types &&\n      Bpl.Expr ante = h != null ? FunctionCall(tok, BuiltinFunction.IsGoodHeap, null, etran.HeapExpr) : (Bpl.Expr)Bpl.Expr.True;\n\n      if (!pp.IsStatic) {\n        var bvThis = new Bpl.BoundVariable(tok, new Bpl.TypedIdent(tok, etran.This, TrReceiverType(pp)));\n        bvs.Add(bvThis);\n        var bvThisIdExpr = new Bpl.IdentifierExpr(tok, bvThis);\n        coArgs.Add(bvThisIdExpr);\n        prefixArgs.Add(bvThisIdExpr);\n        prefixArgsLimited.Add(bvThisIdExpr);\n        prefixArgsLimitedM.Add(bvThisIdExpr);\n        // add well-typedness conjunct to antecedent\n        Type thisType = Resolver.GetReceiverType(tok, pp);\n        Bpl.Expr wh = Bpl.Expr.And(\n          ReceiverNotNull(bvThisIdExpr),\n          GetWhereClause(tok, bvThisIdExpr, thisType, etran, NOALLOC));\n        ante = Bpl.Expr.And(ante, wh);\n      }\n\n      Bpl.Expr kWhere = null, kId = null, mId = null;\n      Bpl.Variable k = null;\n      Bpl.Variable m = null;\n\n      // DR: Changed to add the pp formals instead of co (since types would otherwise be wrong)\n      //     Note that k is not added to bvs or coArgs.\n      foreach (var p in pp.Formals) {\n        bool is_k = p == pp.Formals[0];\n        var bv = new Bpl.BoundVariable(p.tok, new Bpl.TypedIdent(p.tok, p.AssignUniqueName(pp.IdGenerator), TrType(p.Type)));\n        var formal = new Bpl.IdentifierExpr(p.tok, bv);\n        if (!is_k) {\n          coArgs.Add(formal);\n        }\n        prefixArgs.Add(formal);\n        prefixArgsLimited.Add(formal);\n        if (is_k) {\n          m = new Bpl.BoundVariable(p.tok, new Bpl.TypedIdent(p.tok, \"_m\", TrType(p.Type)));\n          mId = new Bpl.IdentifierExpr(m.tok, m);\n          prefixArgsLimitedM.Add(mId);\n        } else {\n          prefixArgsLimitedM.Add(formal);\n        }\n        var wh = GetWhereClause(p.tok, formal, p.Type, etran, NOALLOC);\n        if (is_k) {\n          // add the formal _k\n          k = bv;\n          kId = formal;\n          kWhere = wh;\n        } else {\n          bvs.Add(bv);\n          if (wh != null) {\n            // add well-typedness conjunct to antecedent\n            ante = Bpl.Expr.And(ante, wh);\n          }\n        }\n      }\n      Contract.Assert(k != null && m != null);  // the loop should have filled these in\n\n      var funcID = new Bpl.IdentifierExpr(tok, co.FullSanitizedName, TrType(co.ResultType));\n      var coAppl = new Bpl.NAryExpr(tok, new Bpl.FunctionCall(funcID), coArgs);\n      funcID = new Bpl.IdentifierExpr(tok, pp.FullSanitizedName, TrType(pp.ResultType));\n      var prefixAppl = new Bpl.NAryExpr(tok, new Bpl.FunctionCall(funcID), prefixArgs);\n\n      var activation = AxiomActivation(pp, etran);\n\n      // forall args :: { P(args) } args-have-appropriate-values && P(args) ==> QQQ k { P#[k](args) } :: 0 ATMOST k HHH P#[k](args)\n      var tr = BplTrigger(prefixAppl);\n      var qqqK = pp.FixpointPred is CoPredicate ?\n        (Bpl.Expr)new Bpl.ForallExpr(tok, new List<Variable> { k }, tr, kWhere == null ? prefixAppl : BplImp(kWhere, prefixAppl)) :\n        (Bpl.Expr)new Bpl.ExistsExpr(tok, new List<Variable> { k }, tr, kWhere == null ? prefixAppl : BplAnd(kWhere, prefixAppl));\n      tr = BplTriggerHeap(this, tok, coAppl, AlwaysUseHeap || pp.ReadsHeap ? null : h);\n      var allS = new Bpl.ForallExpr(tok, bvs, tr, BplImp(BplAnd(ante, coAppl), qqqK));\n      sink.AddTopLevelDeclaration(new Bpl.Axiom(tok, Bpl.Expr.Imp(activation, allS),\n        \"1st prefix predicate axiom for \" + pp.FullSanitizedName));\n\n      // forall args :: { P(args) } args-have-appropriate-values && (QQQ k :: 0 ATMOST k HHH P#[k](args)) ==> P(args)\n      allS = new Bpl.ForallExpr(tok, bvs, tr, BplImp(BplAnd(ante, qqqK), coAppl));\n      sink.AddTopLevelDeclaration(new Bpl.Axiom(tok, Bpl.Expr.Imp(activation, allS),\n        \"2nd prefix predicate axiom\"));\n\n      // forall args,k :: args-have-appropriate-values && k == 0 ==> NNN P#0#[k](args)\n      var moreBvs = new List<Variable>();\n      moreBvs.AddRange(bvs);\n      moreBvs.Add(k);\n      var z = Bpl.Expr.Eq(kId, pp.Formals[0].Type.IsBigOrdinalType ?\n        (Bpl.Expr)FunctionCall(tok, \"ORD#FromNat\", predef.BigOrdinalType, Bpl.Expr.Literal(0)) :\n        Bpl.Expr.Literal(0));\n      funcID = new Bpl.IdentifierExpr(tok, pp.FullSanitizedName, TrType(pp.ResultType));\n      Bpl.Expr prefixLimitedBody = new Bpl.NAryExpr(tok, new Bpl.FunctionCall(funcID), prefixArgsLimited);\n      Bpl.Expr prefixLimited = pp.FixpointPred is InductivePredicate ? Bpl.Expr.Not(prefixLimitedBody) : prefixLimitedBody;\n\n      var trigger = BplTriggerHeap(this, prefixLimitedBody.tok, prefixLimitedBody, AlwaysUseHeap || pp.ReadsHeap ? null : h);\n      var trueAtZero = new Bpl.ForallExpr(tok, moreBvs, trigger, BplImp(BplAnd(ante, z), prefixLimited));\n      sink.AddTopLevelDeclaration(new Bpl.Axiom(tok, Bpl.Expr.Imp(activation, trueAtZero),\n        \"3rd prefix predicate axiom\"));\n\n#if WILLING_TO_TAKE_THE_PERFORMANCE_HIT\n      // forall args,k,m :: args-have-appropriate-values && 0 <= k <= m ==> (P#[k](args) EEE P#[m](args))\n      moreBvs = new List<Variable>();\n      moreBvs.AddRange(bvs);\n      moreBvs.Add(k);\n      moreBvs.Add(m);\n      Bpl.Expr smaller;\n      if (kId.Type.IsInt) {\n        smaller = BplAnd(Bpl.Expr.Le(Bpl.Expr.Literal(0), kId), Bpl.Expr.Lt(kId, mId));\n      } else {\n        smaller = FunctionCall(tok, \"ORD#Less\", Bpl.Type.Bool, kId, mId);\n      }\n      funcID = new Bpl.IdentifierExpr(tok, pp.FullSanitizedName, TrType(pp.ResultType));\n      var prefixPred_K = new Bpl.NAryExpr(tok, new Bpl.FunctionCall(funcID), prefixArgsLimited);\n      var prefixPred_M = new Bpl.NAryExpr(tok, new Bpl.FunctionCall(funcID), prefixArgsLimitedM);\n      var direction = pp.FixpointPred is InductivePredicate ? BplImp(prefixPred_K, prefixPred_M) : BplImp(prefixPred_M, prefixPred_K);\n\n      var trigger2 = new Bpl.Trigger(tok, true, new List<Bpl.Expr> { prefixPred_K, prefixPred_M });\n      var monotonicity = new Bpl.ForallExpr(tok, moreBvs, trigger2, BplImp(smaller, direction));\n      sink.AddTopLevelDeclaration(new Bpl.Axiom(tok, Bpl.Expr.Imp(activation, monotonicity),\n        \"prefix predicate monotonicity axiom\"));\n#endif\n      // A more targeted monotonicity axiom used to increase the power of automation for proving the limit case for\n      // inductive predicates that have more than one focal-predicate term.\n      if (pp.FixpointPred is InductivePredicate && pp.Formals[0].Type.IsBigOrdinalType) {\n        // forall args,k,m,limit ::\n        //   { P#[k](args), ORD#LessThanLimit(k,limit), ORD#LessThanLimit(m,limit) }\n        //   args-have-appropriate-values && k < m && P#[k](args) ==> P#[m](args))\n        var limit = new Bpl.BoundVariable(tok, new Bpl.TypedIdent(tok, \"_limit\", TrType(Type.BigOrdinal)));\n        var limitId = new Bpl.IdentifierExpr(limit.tok, limit);\n        moreBvs = new List<Variable>();\n        moreBvs.AddRange(bvs);\n        moreBvs.Add(k);\n        moreBvs.Add(m);\n        moreBvs.Add(limit);\n        var kLessLimit = FunctionCall(tok, \"ORD#LessThanLimit\", Bpl.Type.Bool, kId, limitId);\n        var mLessLimit = FunctionCall(tok, \"ORD#LessThanLimit\", Bpl.Type.Bool, mId, limitId);\n        var kLessM = FunctionCall(tok, \"ORD#Less\", Bpl.Type.Bool, kId, mId);\n        funcID = new Bpl.IdentifierExpr(tok, pp.FullSanitizedName, TrType(pp.ResultType));\n        var prefixPred_K = new Bpl.NAryExpr(tok, new Bpl.FunctionCall(funcID), prefixArgsLimited);\n        var prefixPred_M = new Bpl.NAryExpr(tok, new Bpl.FunctionCall(funcID), prefixArgsLimitedM);\n        var direction = BplImp(prefixPred_K, prefixPred_M);\n\n        var trigger3 = new Bpl.Trigger(tok, true, new List<Bpl.Expr> { prefixPred_K, kLessLimit, mLessLimit });\n        var monotonicity = new Bpl.ForallExpr(tok, moreBvs, trigger3, BplImp(kLessM, direction));\n        sink.AddTopLevelDeclaration(new Bpl.Axiom(tok, Bpl.Expr.Imp(activation, monotonicity),\n          \"targeted prefix predicate monotonicity axiom\"));\n      }\n    }\n\n    /// <summary>\n    /// For a non-static field \"f\" in a class \"c(G)\", generate:\n    ///     // type axiom:\n    ///     // If \"G\" is empty, then TClassA(G) is omitted from trigger.\n    ///     // If \"c\" is an array declaration, then the bound variables also include the index variables \"ii\" and \"h[o, f]\" has the form \"h[o, Index(ii)]\".\n    ///     // If \"f\" is readonly, then \"h[o, f]\" has the form \"f(o)\" (for special fields) or \"f(G,o)\" (for programmer-declared const fields),\n    ///     // so \"h\" and $IsHeap(h) are omitted.\n    ///     axiom fh < FunctionContextHeight ==>\n    ///       (forall o: ref, h: Heap, G : Ty ::\n    ///         { h[o, f], TClassA(G) }  // if \"f\" is a const, omit TClassA(G) from the trigger and just use { f(G,o) }\n    ///         $IsHeap(h) &&\n    ///         o != null && $Is(o, TClassA(G))  // or dtype(o) = TClassA(G)\n    ///         ==>\n    ///         $Is(h[o, f], TT(PP)));\n    ///\n    ///     // allocation axiom:\n    ///     // As above for \"G\" and \"ii\", but \"h\" is included no matter what.\n    ///     axiom fh < FunctionContextHeight ==>\n    ///       (forall o: ref, h: Heap, G : Ty ::\n    ///         { h[o, f], TClassA(G) }  // if \"f\" is a const, use the trigger { f(G,o), h[o, alloc] }; for other readonly fields, use { f(o), h[o, alloc], TClassA(G) }\n    ///         $IsHeap(h) &&\n    ///         o != null && $Is(o, TClassA(G)) &&  // or dtype(o) = TClassA(G)\n    ///         h[o, alloc]\n    ///         ==>\n    ///         $IsAlloc(h[o, f], TT(PP), h));\n    ///\n    /// For a static (necessarily \"const\") field \"f\" in a class \"c(G)\", the expression corresponding to \"h[o, f]\" or \"f(G,o)\" above is \"f(G)\",\n    /// so generate:\n    ///     // type axiom:\n    ///     axiom fh < FunctionContextHeight ==>\n    ///       (forall G : Ty ::\n    ///         { f(G) }\n    ///         $Is(f(G), TT(PP)));\n    ///     // Or in the case where G is empty:\n    ///     axiom $Is(f(G), TT);\n    ///\n    ///     // allocation axiom:\n    ///     axiom fh < FunctionContextHeight ==>\n    ///       (forall h: Heap, G : Ty ::\n    ///         { $IsAlloc(f(G), TT(PP), h) }\n    ///         $IsHeap(h)\n    ///       ==>\n    ///         $IsAlloc(f(G), TT(PP), h));\n    ///\n    ///\n    /// The axioms above could be optimised to something along the lines of:\n    ///     axiom fh < FunctionContextHeight ==>\n    ///       (forall o: ref, h: Heap ::\n    ///         { h[o, f] }\n    ///         $IsHeap(h) && o != null && Tag(dtype(o)) = TagClass\n    ///         ==>\n    ///         (h[o, alloc] ==> $IsAlloc(h[o, f], TT(TClassA_Inv_i(dtype(o)),..), h)) &&\n    ///         $Is(h[o, f], TT(TClassA_Inv_i(dtype(o)),..), h);\n    /// <summary>\n    void AddAllocationAxiom(Field f, TopLevelDeclWithMembers c, bool is_array = false) {\n      Contract.Requires(c != null);\n      // IFF you're adding the array axioms, then the field should be null\n      Contract.Requires(is_array == (f == null));\n      Contract.Requires(sink != null && predef != null);\n\n      Bpl.Expr heightAntecedent = Bpl.Expr.True;\n      if (f is ConstantField) {\n        var cf = (ConstantField)f;\n        AddWellformednessCheck(cf);\n        if (InVerificationScope(cf)) {\n          var etran = new ExpressionTranslator(this, predef, f.tok);\n          heightAntecedent = Bpl.Expr.Lt(Bpl.Expr.Literal(cf.EnclosingModule.CallGraph.GetSCCRepresentativeId(cf)), etran.FunctionContextHeight());\n        }\n      }\n\n      var bvsTypeAxiom = new List<Bpl.Variable>();\n      var bvsAllocationAxiom = new List<Bpl.Variable>();\n\n      // G\n      List<Bpl.Expr> tyexprs;\n      var tyvars = MkTyParamBinders(GetTypeParams(c), out tyexprs);\n      bvsTypeAxiom.AddRange(tyvars);\n      bvsAllocationAxiom.AddRange(tyvars);\n\n      if (f is ConstantField && f.IsStatic) {\n        var oDotF = new Bpl.NAryExpr(c.tok, new Bpl.FunctionCall(GetReadonlyField(f)), tyexprs);\n        var is_hf = MkIs(oDotF, f.Type);              // $Is(h[o, f], ..)\n        Bpl.Expr ax = bvsTypeAxiom.Count == 0 ? is_hf : BplForall(bvsTypeAxiom, BplTrigger(oDotF), is_hf);\n        sink.AddTopLevelDeclaration(new Bpl.Axiom(c.tok, BplImp(heightAntecedent, ax), string.Format(\"{0}.{1}: Type axiom\", c, f)));\n\n        if (CommonHeapUse || (NonGhostsUseHeap && !f.IsGhost)) {\n          Bpl.Expr h;\n          var hVar = BplBoundVar(\"$h\", predef.HeapType, out h);\n          bvsAllocationAxiom.Add(hVar);\n          var isGoodHeap = FunctionCall(c.tok, BuiltinFunction.IsGoodHeap, null, h);\n          var isalloc_hf = MkIsAlloc(oDotF, f.Type, h); // $IsAlloc(h[o, f], ..)\n          ax = BplForall(bvsAllocationAxiom, BplTrigger(isalloc_hf), BplImp(isGoodHeap, isalloc_hf));\n          sink.AddTopLevelDeclaration(new Bpl.Axiom(c.tok, BplImp(heightAntecedent, ax), string.Format(\"{0}.{1}: Allocation axiom\", c, f)));\n        }\n\n      } else {\n        // This is the typical case (that is, f is not a static const field)\n\n        // h, o\n        Bpl.Expr h, o;\n        var hVar = BplBoundVar(\"$h\", predef.HeapType, out h);\n        var oVar = BplBoundVar(\"$o\", TrType(Resolver.GetThisType(c.tok, c)), out o);\n\n        // TClassA(G)\n        Bpl.Expr o_ty = ClassTyCon(c, tyexprs);\n\n        var isGoodHeap = FunctionCall(c.tok, BuiltinFunction.IsGoodHeap, null, h);\n        Bpl.Expr is_o = BplAnd(\n          ReceiverNotNull(o),\n          c is TraitDecl ? MkIs(o, o_ty) : DType(o, o_ty));  // $Is(o, ..)  or  dtype(o) == o_ty\n        var udt = UserDefinedType.FromTopLevelDecl(c.tok, c);\n        Bpl.Expr isalloc_o = c is ClassDecl ? IsAlloced(c.tok, h, o) : MkIsAlloc(o, udt, h);\n\n        Bpl.Expr indexBounds = Bpl.Expr.True;\n        Bpl.Expr oDotF;\n        if (is_array) {\n          // generate h[o,Index(ii)]\n          bvsTypeAxiom.Add(hVar); bvsTypeAxiom.Add(oVar);\n          bvsAllocationAxiom.Add(hVar); bvsAllocationAxiom.Add(oVar);\n\n          var ac = (ArrayClassDecl)c;\n          var ixs = new List<Bpl.Expr>();\n          for (int i = 0; i < ac.Dims; i++) {\n            Bpl.Expr e; Bpl.Variable v = BplBoundVar(\"$i\" + i, Bpl.Type.Int, out e);\n            ixs.Add(e);\n            bvsTypeAxiom.Add(v);\n            bvsAllocationAxiom.Add(v);\n          }\n\n          oDotF = ReadHeap(c.tok, h, o, GetArrayIndexFieldName(c.tok, ixs));\n\n          for (int i = 0; i < ac.Dims; i++) {\n            // 0 <= i && i < _System.array.Length(o)\n            var e1 = Bpl.Expr.Le(Bpl.Expr.Literal(0), ixs[i]);\n            var ff = GetReadonlyField((Field)(ac.Members[i]));\n            var e2 = Bpl.Expr.Lt(ixs[i], new Bpl.NAryExpr(c.tok, new Bpl.FunctionCall(ff), new List<Bpl.Expr> { o }));\n            indexBounds = BplAnd(indexBounds, BplAnd(e1, e2));\n          }\n        } else if (f.IsMutable) {\n          // generate h[o,f]\n          oDotF = ReadHeap(c.tok, h, o, new Bpl.IdentifierExpr(c.tok, GetField(f)));\n          bvsTypeAxiom.Add(hVar); bvsTypeAxiom.Add(oVar);\n          bvsAllocationAxiom.Add(hVar); bvsAllocationAxiom.Add(oVar);\n        } else {\n          // generate f(G,o)\n          var args = new List<Bpl.Expr> { o };\n          if (f is ConstantField) {\n            args = Concat(tyexprs, args);\n          }\n          oDotF = new Bpl.NAryExpr(c.tok, new Bpl.FunctionCall(GetReadonlyField(f)), args);\n          bvsTypeAxiom.Add(oVar);\n          bvsAllocationAxiom.Add(hVar); bvsAllocationAxiom.Add(oVar);\n        }\n\n        // antecedent: some subset of: $IsHeap(h) && o != null && $Is(o, TClassA(G)) && indexBounds\n        Bpl.Expr ante = Bpl.Expr.True;\n        if (is_array || f.IsMutable) {\n          ante = BplAnd(ante, isGoodHeap);\n          // Note: for the allocation axiom, isGoodHeap is added back in for !f.IsMutable below\n        }\n        if (!(f is ConstantField)) {\n          ante = BplAnd(ante, is_o);\n        }\n        ante = BplAnd(ante, indexBounds);\n\n        // trigger\n        var t_es = new List<Bpl.Expr>();\n        t_es.Add(oDotF);\n        if (tyvars.Count > 0 && (is_array || !(f is ConstantField))) {\n          t_es.Add(o_ty);\n        }\n        var tr = new Bpl.Trigger(c.tok, true, t_es);\n\n        // Now for the conclusion of the axioms\n        Bpl.Expr is_hf, isalloc_hf = null;\n        if (is_array) {\n          is_hf = MkIs(oDotF, tyexprs[0], true);\n          if (CommonHeapUse || NonGhostsUseHeap) {\n            isalloc_hf = MkIsAlloc(oDotF, tyexprs[0], h, true);\n          }\n        } else {\n          is_hf = MkIs(oDotF, f.Type);              // $Is(h[o, f], ..)\n          if (CommonHeapUse || (NonGhostsUseHeap && !f.IsGhost)) {\n            isalloc_hf = MkIsAlloc(oDotF, f.Type, h); // $IsAlloc(h[o, f], ..)\n          }\n        }\n\n        Bpl.Expr ax = BplForall(bvsTypeAxiom, tr, BplImp(ante, is_hf));\n        sink.AddTopLevelDeclaration(new Bpl.Axiom(c.tok, BplImp(heightAntecedent, ax), string.Format(\"{0}.{1}: Type axiom\", c, f)));\n\n        if (isalloc_hf != null) {\n          if (!is_array && !f.IsMutable) {\n            // isGoodHeap wasn't added above, so add it now\n            ante = BplAnd(isGoodHeap, ante);\n          }\n          ante = BplAnd(ante, isalloc_o);\n\n          // compute a different trigger\n          t_es = new List<Bpl.Expr>();\n          t_es.Add(oDotF);\n          if (!is_array && !f.IsMutable) {\n            // since \"h\" is not part of oDotF, we add a separate term that mentions \"h\"\n            t_es.Add(isalloc_o);\n          }\n          if (!(f is ConstantField) && tyvars.Count > 0) {\n            t_es.Add(o_ty);\n          }\n          tr = new Bpl.Trigger(c.tok, true, t_es);\n\n          ax = BplForall(bvsAllocationAxiom, tr, BplImp(ante, isalloc_hf));\n          sink.AddTopLevelDeclaration(new Bpl.Axiom(c.tok, BplImp(heightAntecedent, ax), string.Format(\"{0}.{1}: Allocation axiom\", c, f)));\n        }\n      }\n    }\n\n    Bpl.Expr InSeqRange(IToken tok, Bpl.Expr index, Type indexType, Bpl.Expr seq, bool isSequence, Bpl.Expr lowerBound, bool includeUpperBound) {\n      Contract.Requires(tok != null);\n      Contract.Requires(index != null);\n      Contract.Requires(indexType != null);\n      Contract.Requires(seq != null);\n      Contract.Ensures(Contract.Result<Bpl.Expr>() != null);\n\n      if (indexType.IsBitVectorType) {\n        index = ConvertExpression(tok, index, indexType, Type.Int);\n      }\n      Bpl.Expr lower;\n      if (indexType.IsBitVectorType && lowerBound == null) {\n        lower = Bpl.Expr.True;  // bitvectors are always non-negative\n      } else {\n        lower = Bpl.Expr.Le(lowerBound ?? Bpl.Expr.Literal(0), index);\n      }\n      Bpl.Expr length = isSequence ?\n        FunctionCall(tok, BuiltinFunction.SeqLength, null, seq) :\n        ArrayLength(tok, seq, 1, 0);\n      Bpl.Expr upper;\n      if (includeUpperBound) {\n        upper = Bpl.Expr.Le(index, length);\n      } else {\n        upper = Bpl.Expr.Lt(index, length);\n      }\n      return BplAnd(lower, upper);\n    }\n\n    ModuleDefinition currentModule = null;  // the module whose members are currently being translated\n    ICallable codeContext = null;  // the method/iterator whose implementation is currently being translated or the function whose specification is being checked for well-formedness\n    Bpl.LocalVariable yieldCountVariable = null;  // non-null when an iterator body is being translated\n    bool inBodyInitContext = false;  // true during the translation of the .BodyInit portion of a divided constructor body\n    readonly Dictionary<string, Bpl.IdentifierExpr> definiteAssignmentTrackers = new Dictionary<string,Bpl.IdentifierExpr>();\n    bool assertAsAssume = false; // generate assume statements instead of assert statements\n    public enum StmtType { NONE, ASSERT, ASSUME };\n    public StmtType stmtContext = StmtType.NONE;  // the Statement that is currently being translated\n    public bool adjustFuelForExists = true;  // fuel need to be adjusted for exists based on whether exists is in assert or assume stmt.\n\n    public readonly FreshIdGenerator defaultIdGenerator = new FreshIdGenerator();\n\n    public FreshIdGenerator CurrentIdGenerator\n    {\n      get\n      {\n        var decl = codeContext as Declaration;\n        if (decl != null)\n        {\n          return decl.IdGenerator;\n        }\n        return defaultIdGenerator;\n      }\n    }\n\n    Dictionary<string, Bpl.IdentifierExpr> _tmpIEs = new Dictionary<string, Bpl.IdentifierExpr>();\n\n    int assertionCount = 0;\n\n    Bpl.IdentifierExpr GetTmpVar_IdExpr(IToken tok, string name, Bpl.Type ty, List<Variable> locals)  // local variable that's shared between statements that need it\n    {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Contract.Requires(ty != null);\n      Contract.Requires(locals != null);\n      Contract.Ensures(Contract.Result<Bpl.IdentifierExpr>() != null);\n\n      Bpl.IdentifierExpr ie;\n      if (_tmpIEs.TryGetValue(name, out ie)) {\n        Contract.Assume(ie.Type.Equals(ty));\n      } else {\n        // the \"tok\" and \"ty\" of the first request for this variable is the one we use\n        var v = new Bpl.LocalVariable(tok, new Bpl.TypedIdent(tok, name, ty));  // important for the \"$nw\" client: no where clause (see GetNewVar_IdExpr)\n        locals.Add(v);\n        ie = new Bpl.IdentifierExpr(tok, v);\n        _tmpIEs.Add(name, ie);\n      }\n      return ie;\n    }\n\n    Bpl.IdentifierExpr GetPrevHeapVar_IdExpr(IToken tok, List<Variable> locals)  // local variable that's shared between statements that need it\n    {\n      Contract.Requires(tok != null);\n      Contract.Requires(locals != null); Contract.Requires(predef != null);\n      Contract.Ensures(Contract.Result<Bpl.IdentifierExpr>() != null);\n\n      return GetTmpVar_IdExpr(tok, \"$prevHeap\", predef.HeapType, locals);\n    }\n\n    Bpl.IdentifierExpr GetNewVar_IdExpr(IToken tok, List<Variable> locals)  // local variable that's shared between statements that need it\n    {\n      Contract.Requires(tok != null);\n      Contract.Requires(locals != null);\n      Contract.Requires(predef != null);\n      Contract.Ensures(Contract.Result<Bpl.IdentifierExpr>() != null);\n\n      // important: the following declaration produces no where clause (that's why we're going through the trouble of setting of this variable in the first place)\n      return GetTmpVar_IdExpr(tok, \"$nw\", predef.RefType, locals);\n    }\n\n    /// <summary>\n    /// Returns an expression whose value is the same as \"expr\", but that is guaranteed to preserve the its value passed\n    /// the evaluation of other expressions.  If necessary, a new local variable called \"name\" with type \"ty\" is added to \"locals\" and\n    /// assigned in \"builder\" to be used to hold the value of \"expr\".  It is assumed that all requests for a given \"name\"\n    /// have the same type \"ty\" and that these variables can be shared.\n    /// As an optimization, if \"otherExprsCanAffectPreviouslyKnownExpressions\" is \"false\", then \"expr\" itself is returned.\n    /// </summary>\n    Bpl.Expr SaveInTemp(Bpl.Expr expr, bool otherExprsCanAffectPreviouslyKnownExpressions, string name, Bpl.Type ty, BoogieStmtListBuilder builder, List<Variable> locals) {\n      Contract.Requires(expr != null);\n      Contract.Requires(name != null);\n      Contract.Requires(ty != null);\n      Contract.Requires(locals != null);\n      Contract.Ensures(Contract.Result<Bpl.Expr>() != null);\n\n      if (otherExprsCanAffectPreviouslyKnownExpressions) {\n        var save = GetTmpVar_IdExpr(expr.tok, name, ty, locals);\n        builder.Add(Bpl.Cmd.SimpleAssign(expr.tok, save, expr));\n        return save;\n      } else {\n        return expr;\n      }\n    }\n\n    void AddMethodImpl(Method m, Bpl.Procedure proc, bool wellformednessProc)\n    {\n      Contract.Requires(m != null);\n      Contract.Requires(proc != null);\n      Contract.Requires(sink != null && predef != null);\n      Contract.Requires(wellformednessProc || m.Body != null);\n      Contract.Requires(currentModule == null && codeContext == null && _tmpIEs.Count == 0 && isAllocContext == null);\n      Contract.Ensures(currentModule == null && codeContext == null && _tmpIEs.Count == 0 && isAllocContext == null);\n\n      currentModule = m.EnclosingClass.Module;\n      codeContext = m;\n      isAllocContext = new IsAllocContext(m.IsGhost);\n\n      List<Variable> inParams = Bpl.Formal.StripWhereClauses(proc.InParams);\n      List<Variable> outParams = Bpl.Formal.StripWhereClauses(proc.OutParams);\n\n      BoogieStmtListBuilder builder = new BoogieStmtListBuilder(this);\n      builder.Add(new CommentCmd(\"AddMethodImpl: \" + m + \", \" + proc));\n      var etran = new ExpressionTranslator(this, predef, m.tok);\n      InitializeFuelConstant(m.tok, builder, etran);\n      var localVariables = new List<Variable>();\n      GenerateImplPrelude(m, wellformednessProc, inParams, outParams, builder, localVariables);\n\n      if (UseOptimizationInZ3)\n      {\n        // We ask Z3 to minimize all parameters of type 'nat'.\n        foreach (var f in m.Ins)\n        {\n          var udt = f.Type.NormalizeExpandKeepConstraints() as UserDefinedType;\n          if (udt != null && udt.Name == \"nat\")\n          {\n            builder.Add(optimizeExpr(true, new IdentifierExpr(f.tok, f), f.Tok, etran));\n          }\n        }\n      }\n\n      Bpl.StmtList stmts;\n      if (!wellformednessProc) {\n        var inductionVars = ApplyInduction(m.Ins, m.Attributes);\n        if (inductionVars.Count != 0) {\n          // Let the parameters be this,x,y of the method M and suppose ApplyInduction returns y.\n          // Also, let Pre be the precondition and VF be the decreases clause.\n          // Then, insert into the method body what amounts to:\n          //     assume case-analysis-on-parameter[[ y' ]];\n          //     forall (y' | Pre(this, x, y') && VF(this, x, y') << VF(this, x, y)) {\n          //       this.M(x, y');\n          //     }\n          // Generate bound variables for the forall statement, and a substitution for the Pre and VF\n\n          // assume case-analysis-on-parameter[[ y' ]];\n          foreach (var inFormal in m.Ins) {\n            var dt = inFormal.Type.AsDatatype;\n            if (dt != null) {\n              var funcID = new Bpl.FunctionCall(new Bpl.IdentifierExpr(inFormal.tok, \"$IsA#\" + dt.FullSanitizedName, Bpl.Type.Bool));\n              var f = new Bpl.IdentifierExpr(inFormal.tok, inFormal.AssignUniqueName(m.IdGenerator), TrType(inFormal.Type));\n              builder.Add(TrAssumeCmd(inFormal.tok, new Bpl.NAryExpr(inFormal.tok, funcID, new List<Bpl.Expr> { f })));\n            }\n          }\n\n          var parBoundVars = new List<BoundVar>();\n          var parBounds = new List<ComprehensionExpr.BoundedPool>();\n          var substMap = new Dictionary<IVariable, Expression>();\n          foreach (var iv in inductionVars) {\n            BoundVar bv;\n            IdentifierExpr ie;\n            CloneVariableAsBoundVar(iv.tok, iv, \"$ih#\" + iv.Name, out bv, out ie);\n            parBoundVars.Add(bv);\n            parBounds.Add(new ComprehensionExpr.SpecialAllocIndependenceAllocatedBoundedPool());  // record that we don't want alloc antecedents for these variables\n            substMap.Add(iv, ie);\n          }\n\n\n          // Generate a CallStmt for the recursive call\n          List<Type> typeApplication;\n          Dictionary<TypeParameter, Type> typeArgumentSubstitutions;  // not used\n          Expression recursiveCallReceiver;\n          List<Expression> recursiveCallArgs;\n          RecursiveCallParameters(m.tok, m, m.TypeArgs, m.Ins, substMap, out typeApplication, out typeArgumentSubstitutions, out recursiveCallReceiver, out recursiveCallArgs);\n          var methodSel = new MemberSelectExpr(m.tok, recursiveCallReceiver, m.Name);\n          methodSel.Member = m;  // resolve here\n          methodSel.TypeApplication = typeApplication;\n          methodSel.Type = new InferredTypeProxy();\n          var recursiveCall = new CallStmt(m.tok, m.tok, new List<Expression>(), methodSel, recursiveCallArgs);\n          recursiveCall.IsGhost = m.IsGhost;  // resolve here\n\n          Expression parRange = new LiteralExpr(m.tok, true);\n          parRange.Type = Type.Bool;  // resolve here\n          foreach (var pre in m.Req) {\n            if (!pre.IsFree) {\n              parRange = Expression.CreateAnd(parRange, Substitute(pre.E, null, substMap));\n            }\n          }\n          // construct an expression (generator) for:  VF' << VF\n          ExpressionConverter decrCheck = delegate(Dictionary<IVariable, Expression> decrSubstMap, ExpressionTranslator exprTran) {\n            var decrToks = new List<IToken>();\n            var decrTypes = new List<Type>();\n            var decrCallee = new List<Expr>();\n            var decrCaller = new List<Expr>();\n            foreach (var ee in m.Decreases.Expressions) {\n              decrToks.Add(ee.tok);\n              decrTypes.Add(ee.Type.NormalizeExpand());\n              decrCaller.Add(exprTran.TrExpr(ee));\n              Expression es = Substitute(ee, null, substMap);\n              es = Substitute(es, null, decrSubstMap);\n              decrCallee.Add(exprTran.TrExpr(es));\n            }\n            return DecreasesCheck(decrToks, decrTypes, decrTypes, decrCallee, decrCaller, null, null, false, true);\n          };\n\n#if VERIFY_CORRECTNESS_OF_TRANSLATION_FORALL_STATEMENT_RANGE\n          var definedness = new BoogieStmtListBuilder(this);\n          var exporter = new BoogieStmtListBuilder(this);\n          TrForallStmtCall(m.tok, parBoundVars, parRange, decrCheck, null, recursiveCall, definedness, exporter, localVariables, etran);\n          // All done, so put the two pieces together\n          builder.Add(new Bpl.IfCmd(m.tok, null, definedness.Collect(m.tok), null, exporter.Collect(m.tok)));\n#else\n          TrForallStmtCall(m.tok, parBoundVars, parBounds, parRange, decrCheck, null, recursiveCall, null, builder, localVariables, etran);\n#endif\n        }\n        // translate the body of the method\n        Contract.Assert(m.Body != null);  // follows from method precondition and the if guard\n\n        // $_reverifyPost := false;\n        builder.Add(Bpl.Cmd.SimpleAssign(m.tok, new Bpl.IdentifierExpr(m.tok, \"$_reverifyPost\", Bpl.Type.Bool), Bpl.Expr.False));\n        // register output parameters with definite-assignment trackers\n        Contract.Assert(definiteAssignmentTrackers.Count == 0);\n        if (!m.IsGhost) {\n          m.Outs.Iter(p => AddDefiniteAssignmentTracker(p, localVariables));\n        }\n        // translate the body\n        TrStmt(m.Body, builder, localVariables, etran);\n        m.Outs.Iter(p => CheckDefiniteAssignmentReturn(m.BodyEndTok, p, builder));\n        stmts = builder.Collect(m.Body.Tok);\n        // tear down definite-assignment trackers\n        m.Outs.Iter(RemoveDefiniteAssignmentTracker);\n        Contract.Assert(definiteAssignmentTrackers.Count == 0);\n      } else {\n        // check well-formedness of the preconditions, and then assume each one of them\n        foreach (MaybeFreeExpression p in m.Req) {\n          CheckWellformedAndAssume(p.E, new WFOptions(), localVariables, builder, etran);\n        }\n        // check well-formedness of the modifies clauses\n        CheckFrameWellFormed(new WFOptions(), m.Mod.Expressions, localVariables, builder, etran);\n        // check well-formedness of the decreases clauses\n        foreach (Expression p in m.Decreases.Expressions)\n        {\n          CheckWellformed(p, new WFOptions(), localVariables, builder, etran);\n        }\n\n        if (!(m is TwoStateLemma)) {\n          // play havoc with the heap according to the modifies clause\n          builder.Add(new Bpl.HavocCmd(m.tok, new List<Bpl.IdentifierExpr> { (Bpl.IdentifierExpr/*TODO: this cast is rather dubious*/)etran.HeapExpr }));\n          // assume the usual two-state boilerplate information\n          foreach (BoilerplateTriple tri in GetTwoStateBoilerplate(m.tok, m.Mod.Expressions, m.IsGhost, etran.Old, etran, etran.Old)) {\n            if (tri.IsFree) {\n              builder.Add(TrAssumeCmd(m.tok, tri.Expr));\n            }\n          }\n        }\n\n        // also play havoc with the out parameters\n        if (outParams.Count != 0) {  // don't create an empty havoc statement\n          List<Bpl.IdentifierExpr> outH = new List<Bpl.IdentifierExpr>();\n          foreach (Bpl.Variable b in outParams) {\n            Contract.Assert(b != null);\n            outH.Add(new Bpl.IdentifierExpr(b.tok, b));\n          }\n          builder.Add(new Bpl.HavocCmd(m.tok, outH));\n        }\n        // mark the end of the modifles/out-parameter havocking with a CaptureState; make its location be the first ensures clause, if any (and just\n        // omit the CaptureState if there's no ensures clause)\n        if (m.Ens.Count != 0) {\n          builder.Add(CaptureState(m.Ens[0].E.tok, false, \"post-state\"));\n        }\n\n        // check wellformedness of postconditions\n        foreach (MaybeFreeExpression p in m.Ens) {\n          CheckWellformedAndAssume(p.E, new WFOptions(), localVariables, builder, etran);\n        }\n\n        stmts = builder.Collect(m.tok);\n      }\n\n      if (EmitImplementation(m.Attributes)) {\n        // emit impl only when there are proof obligations.\n        QKeyValue kv = etran.TrAttributes(m.Attributes, null);\n        Bpl.Implementation impl = new Bpl.Implementation(m.tok, proc.Name,\n          new List<Bpl.TypeVariable>(), inParams, outParams,\n          localVariables, stmts, kv);\n        sink.AddTopLevelDeclaration(impl);\n\n        if (InsertChecksums) {\n          InsertChecksum(m, impl);\n        }\n      }\n\n      isAllocContext = null;\n      Reset();\n    }\n\n#region Definite-assignment tracking\n    void AddDefiniteAssignmentTracker(IVariable p, List<Variable> localVariables) {\n      Contract.Requires(p != null);\n      Contract.Requires(localVariables != null);\n\n      if (ArmadaOptions.O.DefiniteAssignmentLevel == 0 || p.IsGhost) {\n        return;\n      } else if (ArmadaOptions.O.DefiniteAssignmentLevel == 1 && Compiler.InitializerIsKnown(p.Type)) {\n        return;\n      }\n      var tracker = new Bpl.LocalVariable(p.Tok, new Bpl.TypedIdent(p.Tok, \"defass#\" + p.UniqueName, Bpl.Type.Bool));\n      localVariables.Add(tracker);\n      var ie = new Bpl.IdentifierExpr(p.Tok, tracker);\n      definiteAssignmentTrackers.Add(p.UniqueName, ie);\n    }\n\n    void AddDefiniteAssignmentTrackerSurrogate(Field field, List<Variable> localVariables) {\n      Contract.Requires(field != null);\n      Contract.Requires(localVariables != null);\n\n      if (ArmadaOptions.O.DefiniteAssignmentLevel == 0 || field.IsGhost) {\n        return;\n      } else if (ArmadaOptions.O.DefiniteAssignmentLevel == 1 && Compiler.InitializerIsKnown(field.Type)) {\n        return;\n      }\n      var nm = SurrogateName(field);\n      var tracker = new Bpl.LocalVariable(field.tok, new Bpl.TypedIdent(field.tok, \"defass#\" + nm, Bpl.Type.Bool));\n      localVariables.Add(tracker);\n      var ie = new Bpl.IdentifierExpr(field.tok, tracker);\n      definiteAssignmentTrackers.Add(nm, ie);\n    }\n\n    void RemoveDefiniteAssignmentTrackers(List<Statement> ss, int prevDefAssTrackerCount) {\n      Contract.Requires(ss != null);\n      foreach (var s in ss) {\n        var vdecl = s as VarDeclStmt;\n        if (vdecl != null) {\n          vdecl.Locals.Iter(RemoveDefiniteAssignmentTracker);\n        }\n      }\n      Contract.Assert(prevDefAssTrackerCount == definiteAssignmentTrackers.Count);\n    }\n\n    void RemoveDefiniteAssignmentTracker(IVariable p) {\n      Contract.Requires(p != null);\n      definiteAssignmentTrackers.Remove(p.UniqueName);\n    }\n\n    void RemoveDefiniteAssignmentTrackerSurrogate(Field field) {\n      Contract.Requires(field != null);\n      definiteAssignmentTrackers.Remove(SurrogateName(field));\n    }\n\n    void MarkDefiniteAssignmentTracker(IdentifierExpr expr, BoogieStmtListBuilder builder) {\n      Contract.Requires(expr != null);\n      Contract.Requires(builder != null);\n      MarkDefiniteAssignmentTracker(expr.tok, expr.Var.UniqueName, builder);\n    }\n\n    void MarkDefiniteAssignmentTracker(IToken tok, string name, BoogieStmtListBuilder builder) {\n      Contract.Requires(tok != null);\n      Contract.Requires(name != null);\n      Contract.Requires(builder != null);\n\n      Bpl.IdentifierExpr ie;\n      if (definiteAssignmentTrackers.TryGetValue(name, out ie)) {\n        builder.Add(Bpl.Cmd.SimpleAssign(tok, ie, Bpl.Expr.True));\n      }\n    }\n\n    void CheckDefiniteAssignment(IdentifierExpr expr, BoogieStmtListBuilder builder) {\n      Contract.Requires(expr != null);\n      Contract.Requires(builder!= null);\n\n      Bpl.IdentifierExpr ie;\n      if (definiteAssignmentTrackers.TryGetValue(expr.Var.UniqueName, out ie)) {\n        builder.Add(Assert(expr.tok, ie, string.Format(\"variable '{0}', which is subject to definite-assignment rules, might be used before it has been assigned\", expr.Var.Name)));\n      }\n    }\n\n    void CheckDefiniteAssignmentSurrogate(IToken tok, Field field, bool atNew, BoogieStmtListBuilder builder) {\n      Contract.Requires(tok != null);\n      Contract.Requires(field != null);\n      Contract.Requires(builder != null);\n\n      var nm = SurrogateName(field);\n      Bpl.IdentifierExpr ie;\n      if (definiteAssignmentTrackers.TryGetValue(nm, out ie)) {\n        var msg = string.Format(\"field '{0}', which is subject to definite-assignment rules, {1}\", field.Name,\n          atNew ? \"might not have been defined at this point in the constructor body\" : \"might be used before it has been assigned\");\n        builder.Add(Assert(tok, ie, msg));\n      }\n    }\n\n    void CheckDefiniteAssignmentReturn(IToken tok, Formal p, BoogieStmtListBuilder builder) {\n      Contract.Requires(tok != null);\n      Contract.Requires(p != null && !p.InParam);\n      Contract.Requires(builder != null);\n\n      Bpl.IdentifierExpr ie;\n      if (definiteAssignmentTrackers.TryGetValue(p.UniqueName, out ie)) {\n        builder.Add(Assert(tok, ie, string.Format(\"out-parameter '{0}', which is subject to definite-assignment rules, might not have been defined at this return point\", p.Name)));\n      }\n    }\n#endregion  // definite-assignment tracking\n\n    void InitializeFuelConstant(IToken tok, BoogieStmtListBuilder builder, ExpressionTranslator etran) {\n      if (this.functionFuel.Count > 0) {\n        builder.Add(new CommentCmd(\"initialize fuel constant\"));\n      }\n      FuelContext fuelContext = this.fuelContext;\n      foreach (FuelConstant fuelConstant in this.functionFuel) {\n        Function f = fuelConstant.f;\n        Bpl.Expr baseFuel = fuelConstant.baseFuel;\n        Bpl.Expr startFuel = fuelConstant.startFuel;\n        Bpl.Expr startFuelAssert = fuelConstant.startFuelAssert;\n        // find out what the initial value should be\n        FuelSettingPair settings;\n        var found = fuelContext.TryGetValue(f, out settings);\n        if (!found) {\n          // If the context doesn't define fuel for this function, check for a fuel attribute (which supplies a default value if none is found)\n          settings = FuelSetting.FuelAttrib(f, out found);\n        }\n\n        if (settings.low == 0 && settings.high == 0) {\n            // Don't say anything about what startFuel and startFuel are set to\n            // Just add the fixpoints that allow us to shortcut to LZ:\n            // assume AsFuelBottom(startFuel) == startFuel\n            // assume AsFuelBottom(startFuelAssert) == startFuelAssert\n            builder.Add(TrAssumeCmd(tok, Bpl.Expr.Eq(FunctionCall(f.tok, BuiltinFunction.AsFuelBottom, null, startFuel), startFuel)));\n            builder.Add(TrAssumeCmd(tok, Bpl.Expr.Eq(FunctionCall(f.tok, BuiltinFunction.AsFuelBottom, null, startFuelAssert), startFuelAssert)));\n        } else {\n            Bpl.Expr layer = etran.layerInterCluster.LayerN(settings.low, baseFuel);\n            Bpl.Expr layerAssert = etran.layerInterCluster.LayerN(settings.high, baseFuel);\n            builder.Add(TrAssumeCmd(tok, Bpl.Expr.Eq(startFuel, layer)));\n            builder.Add(TrAssumeCmd(tok, Bpl.Expr.Eq(startFuelAssert, layerAssert)));\n            // assume AsFuelBottom(BaseFuel_F) == BaseFuel_F;\n            builder.Add(TrAssumeCmd(tok, Bpl.Expr.Eq(FunctionCall(f.tok, BuiltinFunction.AsFuelBottom, null, baseFuel), baseFuel)));\n        }\n      }\n    }\n\n    bool DefineFuelConstant(IToken tok, Attributes attribs, BoogieStmtListBuilder builder, ExpressionTranslator etran) {\n      bool defineFuel = false;\n      builder.Add(new CommentCmd(\"Assume Fuel Constant\"));\n      FuelContext fuelContext  = new FuelContext();\n      FuelSetting.FindFuelAttributes(attribs, fuelContext);\n      foreach (KeyValuePair<Function, FuelSettingPair> fuel in fuelContext) {\n        Function f = fuel.Key;\n        FuelSettingPair settings = fuel.Value;\n        FuelConstant fuelConstant = this.functionFuel.Find(x => x.f == f);\n        if (fuelConstant != null) {\n          Bpl.Expr startFuel = fuelConstant.startFuel;\n          Bpl.Expr startFuelAssert = fuelConstant.startFuelAssert;\n          Bpl.Expr moreFuel_expr = fuelConstant.MoreFuel(sink, predef, f.IdGenerator);\n          Bpl.Expr layer = etran.layerInterCluster.LayerN(settings.low, moreFuel_expr);\n          Bpl.Expr layerAssert = etran.layerInterCluster.LayerN(settings.high, moreFuel_expr);\n          builder.Add(TrAssumeCmd(tok, Bpl.Expr.Eq(startFuel, layer)));\n          builder.Add(TrAssumeCmd(tok, Bpl.Expr.Eq(startFuelAssert, layerAssert)));\n          defineFuel = true;\n        }\n      }\n      return defineFuel;\n    }\n\n    internal static AssumeCmd optimizeExpr(bool minimize, Expression expr, IToken tok, ExpressionTranslator etran)\n    {\n      Contract.Requires(expr != null);\n      Contract.Requires(expr.Type.IsIntegerType || expr.Type.IsRealType);\n      Contract.Requires(tok != null && etran != null);\n\n      var assumeCmd = new AssumeCmd(tok, Expr.True);\n      assumeCmd.Attributes = new QKeyValue(expr.tok, (minimize ? \"minimize\" : \"maximize\"), new List<object> { etran.TrExpr(expr) }, null);\n      return assumeCmd;\n    }\n\n    private void AddFunctionOverrideCheckImpl(Function f)\n    {\n        Contract.Requires(f != null);\n        //Contract.Requires(proc != null);\n        Contract.Requires(sink != null && predef != null);\n        Contract.Requires(f.OverriddenFunction != null);\n        Contract.Requires(f.Formals.Count == f.OverriddenFunction.Formals.Count);\n        Contract.Requires(currentModule == null && codeContext == null && _tmpIEs.Count == 0 && isAllocContext != null);\n        Contract.Ensures(currentModule == null && codeContext == null && _tmpIEs.Count == 0 && isAllocContext != null);\n\n#region first procedure, no impl yet\n        //Function nf = new Function(f.tok, \"OverrideCheck_\" + f.Name, f.IsStatic, f.IsGhost, f.TypeArgs, f.OpenParen, f.Formals, f.ResultType, f.Req, f.Reads, f.Ens, f.Decreases, f.Body, f.Attributes, f.SignatureEllipsis);\n        //AddFunction(f);\n        currentModule = f.EnclosingClass.Module;\n        codeContext = f;\n\n        Bpl.Expr prevHeap = null;\n        Bpl.Expr currHeap = null;\n        var ordinaryEtran = new ExpressionTranslator(this, predef, f.tok);\n        ExpressionTranslator etran;\n        var inParams_Heap = new List<Bpl.Variable>();\n        if (f is TwoStateFunction) {\n          var prevHeapVar = new Bpl.Formal(f.tok, new Bpl.TypedIdent(f.tok, \"previous$Heap\", predef.HeapType), true);\n          inParams_Heap.Add(prevHeapVar);\n          prevHeap = new Bpl.IdentifierExpr(f.tok, prevHeapVar);\n          if (f.ReadsHeap) {\n            var currHeapVar = new Bpl.Formal(f.tok, new Bpl.TypedIdent(f.tok, \"current$Heap\", predef.HeapType), true);\n            inParams_Heap.Add(currHeapVar);\n            currHeap = new Bpl.IdentifierExpr(f.tok, currHeapVar);\n          }\n          etran = new ExpressionTranslator(this, predef, currHeap, prevHeap);\n        } else {\n          etran = ordinaryEtran;\n        }\n\n        // parameters of the procedure\n        var typeInParams = MkTyParamFormals(GetTypeParams(f));\n        var inParams = new List<Variable>();\n        var outParams = new List<Bpl.Variable>();\n        if (!f.IsStatic) {\n          var th = new Bpl.IdentifierExpr(f.tok, \"this\", TrReceiverType(f));\n          Bpl.Expr wh = Bpl.Expr.And(\n            ReceiverNotNull(th),\n            etran.GoodRef(f.tok, th, Resolver.GetReceiverType(f.tok, f)));\n          Bpl.Formal thVar = new Bpl.Formal(f.tok, new Bpl.TypedIdent(f.tok, \"this\", TrReceiverType(f), wh), true);\n          inParams.Add(thVar);\n        }\n        foreach (Formal p in f.Formals) {\n          Bpl.Type varType = TrType(p.Type);\n          Bpl.Expr wh = GetWhereClause(p.tok, new Bpl.IdentifierExpr(p.tok, p.AssignUniqueName(f.IdGenerator), varType), p.Type, etran, NOALLOC);\n          inParams.Add(new Bpl.Formal(p.tok, new Bpl.TypedIdent(p.tok, p.AssignUniqueName(f.IdGenerator), varType, wh), true));\n        }\n\n        Formal pOut = null;\n        if (f.Result != null || f.OverriddenFunction.Result != null) {\n          if (f.Result != null) {\n            pOut = f.Result;\n            Contract.Assert(!pOut.IsOld);\n          } else {\n            var pp = f.OverriddenFunction.Result;\n            Contract.Assert(!pp.IsOld);\n            pOut = new Formal(pp.tok, pp.Name, f.ResultType, false, pp.IsGhost);\n          }\n          var varType = TrType(pOut.Type);\n          var wh = GetWhereClause(pOut.tok, new Bpl.IdentifierExpr(pOut.tok, pOut.AssignUniqueName(f.IdGenerator), varType), pOut.Type, etran, NOALLOC);\n          outParams.Add(new Bpl.Formal(pOut.tok, new Bpl.TypedIdent(pOut.tok, pOut.AssignUniqueName(f.IdGenerator), varType, wh), true));\n        }\n        // the procedure itself\n        var req = new List<Bpl.Requires>();\n        // free requires mh == ModuleContextHeight && fh == FunctionContextHeight;\n        req.Add(Requires(f.tok, true, etran.HeightContext(f.OverriddenFunction), null, null));\n        if (f is TwoStateFunction) {\n          // free requires prevHeap == Heap && HeapSucc(prevHeap, currHeap) && IsHeap(currHeap)\n          var a0 = Bpl.Expr.Eq(prevHeap, ordinaryEtran.HeapExpr);\n          var a1 = HeapSucc(prevHeap, currHeap);\n          var a2 = FunctionCall(f.tok, BuiltinFunction.IsGoodHeap, null, currHeap);\n          req.Add(Requires(f.tok, true, BplAnd(a0, BplAnd(a1, a2)), null, null));\n        }\n        // modifies $Heap, $Tick\n        var mod = new List<Bpl.IdentifierExpr> {\n          (Bpl.IdentifierExpr/*TODO: this cast is rather dubious*/)ordinaryEtran.HeapExpr,\n          etran.Tick()\n        };\n        var ens = new List<Bpl.Ensures>();\n\n        var proc = new Bpl.Procedure(f.tok, \"OverrideCheck$$\" + f.FullSanitizedName, new List<Bpl.TypeVariable>(),\n          Concat(Concat(typeInParams, inParams_Heap), inParams), outParams,\n          req, mod, ens, etran.TrAttributes(f.Attributes, null));\n        sink.AddTopLevelDeclaration(proc);\n        var implInParams = Bpl.Formal.StripWhereClauses(inParams);\n        var implOutParams = Bpl.Formal.StripWhereClauses(outParams);\n\n#endregion\n\n        //List<Variable> outParams = Bpl.Formal.StripWhereClauses(proc.OutParams);\n\n        BoogieStmtListBuilder builder = new BoogieStmtListBuilder(this);\n        List<Variable> localVariables = new List<Variable>();\n        //GenerateImplPrelude(m, wellformednessProc, inParams, outParams, builder, localVariables);\n        if (f is TwoStateFunction) {\n          // $Heap := current$Heap;\n          var heap = (Bpl.IdentifierExpr /*TODO: this cast is somewhat dubious*/)ordinaryEtran.HeapExpr;\n          builder.Add(Bpl.Cmd.SimpleAssign(f.tok, heap, etran.HeapExpr));\n          etran = ordinaryEtran;  // we no longer need the special heap names\n        }\n\n        var substMap = new Dictionary<IVariable, Expression>();\n        for (int i = 0; i < f.Formals.Count; i++) {\n          //get corresponsing formal in the class\n          var ie = new IdentifierExpr(f.Formals[i].tok, f.Formals[i].AssignUniqueName(f.IdGenerator));\n          ie.Var = f.Formals[i]; ie.Type = ie.Var.Type;\n          substMap.Add(f.OverriddenFunction.Formals[i], ie);\n        }\n\n        if (f.OverriddenFunction.Result != null) {\n          Contract.Assert(pOut != null);\n          //get corresponsing formal in the class\n          var ie = new IdentifierExpr(pOut.tok, pOut.AssignUniqueName(f.IdGenerator));\n          ie.Var = pOut; ie.Type = ie.Var.Type;\n          substMap.Add(f.OverriddenFunction.Result, ie);\n        }\n\n        Bpl.StmtList stmts;\n        //adding assume Pre’; assert P; // this checks that Pre’ implies P\n        AddFunctionOverrideReqsChk(f, builder, etran, substMap);\n\n        //adding assert R <= Rank’;\n        AddOverrideTerminationChk(f, f.OverriddenFunction, builder, etran, substMap);\n\n        //adding assert W <= Frame’\n        AddFunctionOverrideSubsetChk(f, builder, etran, localVariables, substMap);\n\n        //adding assume Q; assert Post’;\n        AddFunctionOverrideEnsChk(f, builder, etran, substMap, implInParams, implOutParams.Count == 0 ? null : implOutParams[0]);\n\n        stmts = builder.Collect(f.tok);\n\n        if (EmitImplementation(f.Attributes)) {\n          // emit the impl only when there are proof obligations.\n          QKeyValue kv = etran.TrAttributes(f.Attributes, null);\n\n          var impl = new Bpl.Implementation(f.tok, proc.Name, new List<Bpl.TypeVariable>(),\n            Concat(Concat(typeInParams, inParams_Heap), implInParams), implOutParams, localVariables, stmts, kv);\n          sink.AddTopLevelDeclaration(impl);\n        }\n\n        if (InsertChecksums)\n        {\n            InsertChecksum(f, proc, true);\n        }\n\n        Reset();\n    }\n\n    private void AddFunctionOverrideAxiom(Function f)\n    {\n      Contract.Requires(f != null);\n      Contract.Requires(!f.IsStatic);  // only instance functions can be overridden\n      Contract.Requires(sink != null && predef != null);\n\n      // Essentially, the function override axiom looks like:\n      //   axiom (forall $heap: HeapType, this: ref, x#0: int ::\n      //     { J.F($heap, this, x#0) }\n      //     this != null && dtype(this) == class.C\n      //     ==>\n      //     J.F($heap, this, x#0) == C.F($heap, this, x#0));\n      // but it also has the various usual antecedents.  Essentially, the override gives a part of the body of the\n      // trait's function, so we call FunctionAxiom to generate a conditional axiom (that is, we pass in the \"overridingClass\"\n      // parameter to FunctionAxiom, which will add 'dtype(this) == class.C' as an additional antecedent) for a\n      // body of 'C.F(this, x#0)'.\n      // TODO:  More work needs to be done to support any type parameters that class C might have.  These would\n      // need to be quantified (existentially?) in the axiom.\n      var receiver = new ThisExpr(f.tok);\n      receiver.Type = Resolver.GetReceiverType(f.tok, f);\n      var args = f.OverriddenFunction.Formals.ConvertAll(p => (Expression)new IdentifierExpr(p.tok, p.Name) { Var = p, Type = p.Type });\n      var pseudoBody = new FunctionCallExpr(f.tok, f.Name, new ThisExpr(f.tok), f.tok, args);\n      pseudoBody.Function = f;  // resolve here\n      // TODO: the following two lines (incorrectly) assume there are no type parameters\n      pseudoBody.Type = f.ResultType;  // resolve here\n      pseudoBody.TypeArgumentSubstitutions = new Dictionary<TypeParameter,Type>();  // resolve here\n      sink.AddTopLevelDeclaration(FunctionAxiom(f.OverriddenFunction, pseudoBody, null, f.EnclosingClass));\n    }\n\n    private void AddFunctionOverrideEnsChk(Function f, BoogieStmtListBuilder builder, ExpressionTranslator etran, Dictionary<IVariable, Expression> substMap, List<Bpl.Variable> implInParams, Bpl.Variable/*?*/ resultVariable)\n    {\n      //generating class post-conditions\n      foreach (var en in f.Ens)\n      {\n        builder.Add(TrAssumeCmd(f.tok, etran.TrExpr(en.E)));\n      }\n\n      //generating assume J.F(ins) == C.F(ins)\n      Bpl.FunctionCall funcIdC = new Bpl.FunctionCall(new Bpl.IdentifierExpr(f.tok, f.FullSanitizedName, TrType(f.ResultType)));\n      Bpl.FunctionCall funcIdT = new Bpl.FunctionCall(new Bpl.IdentifierExpr(f.OverriddenFunction.tok, f.OverriddenFunction.FullSanitizedName, TrType(f.OverriddenFunction.ResultType)));\n      List<Bpl.Expr> argsC = new List<Bpl.Expr>();\n      List<Bpl.Expr> argsT = new List<Bpl.Expr>();\n      if (f.IsFuelAware())\n      {\n        argsC.Add(etran.layerInterCluster.GetFunctionFuel(f));\n      }\n      if (f.OverriddenFunction.IsFuelAware())\n      {\n        argsT.Add(etran.layerInterCluster.GetFunctionFuel(f));\n      }\n      if (f is TwoStateFunction) {\n        argsC.Add(etran.Old.HeapExpr);\n        argsT.Add(etran.Old.HeapExpr);\n      }\n      if (AlwaysUseHeap || f.ReadsHeap)\n      {\n        argsC.Add(etran.HeapExpr);\n      }\n      if (AlwaysUseHeap || f.OverriddenFunction.ReadsHeap)\n      {\n        argsT.Add(etran.HeapExpr);\n      }\n      foreach (Variable p in implInParams)\n      {\n        argsC.Add(new Bpl.IdentifierExpr(f.tok, p));\n        argsT.Add(new Bpl.IdentifierExpr(f.OverriddenFunction.tok, p));\n      }\n      Bpl.Expr funcExpC = new Bpl.NAryExpr(f.tok, funcIdC, argsC);\n      Bpl.Expr funcExpT = new Bpl.NAryExpr(f.OverriddenFunction.tok, funcIdT, argsT);\n      builder.Add(TrAssumeCmd(f.tok, Bpl.Expr.Eq(funcExpC, funcExpT)));\n\n      //generating assume C.F(ins) == out, if a result variable was given\n      if (resultVariable != null) {\n        var resultVar = new Bpl.IdentifierExpr(resultVariable.tok, resultVariable);\n        builder.Add(TrAssumeCmd(f.tok, Bpl.Expr.Eq(funcExpC, resultVar)));\n      }\n\n      //generating trait post-conditions with class variables\n      foreach (var en in f.OverriddenFunction.Ens) {\n        Expression postcond = Substitute(en.E, null, substMap);\n        bool splitHappened;  // we don't actually care\n        foreach (var s in TrSplitExpr(postcond, etran, false, out splitHappened)) {\n          if (s.IsChecked) {\n            builder.Add(Assert(f.tok, s.E, \"the function must provide an equal or more detailed postcondition than in its parent trait\"));\n          }\n        }\n      }\n    }\n\n    private void HavocFunctionFrameLocations(Function f, BoogieStmtListBuilder builder, ExpressionTranslator etran, List<Variable> localVariables)\n    {\n        // play havoc with the heap according to the modifies clause\n        builder.Add(new Bpl.HavocCmd(f.tok, new List<Bpl.IdentifierExpr> { (Bpl.IdentifierExpr/*TODO: this cast is rather dubious*/)etran.HeapExpr }));\n        // assume the usual two-state boilerplate information\n        foreach (BoilerplateTriple tri in GetTwoStateBoilerplate(f.tok, f.Reads, f.IsGhost, etran.Old, etran, etran.Old))\n        {\n            if (tri.IsFree)\n            {\n                builder.Add(TrAssumeCmd(f.tok, tri.Expr));\n            }\n        }\n    }\n\n    private void AddFunctionOverrideSubsetChk(Function func, BoogieStmtListBuilder builder, ExpressionTranslator etran, List<Variable> localVariables, Dictionary<IVariable, Expression> substMap)\n    {\n        //getting framePrime\n        List<FrameExpression> traitFrameExps = new List<FrameExpression>();\n        foreach (var e in func.OverriddenFunction.Reads)\n        {\n            var newE = Substitute(e.E, null, substMap);\n            FrameExpression fe = new FrameExpression(e.tok, newE, e.FieldName);\n            traitFrameExps.Add(fe);\n        }\n\n        QKeyValue kv = etran.TrAttributes(func.Attributes, null);\n\n        IToken tok = func.tok;\n        // Declare a local variable $_Frame: <alpha>[ref, Field alpha]bool\n        Bpl.IdentifierExpr traitFrame = etran.TheFrame(func.OverriddenFunction.tok);  // this is a throw-away expression, used only to extract the type and name of the $_Frame variable\n        traitFrame.Name = func.EnclosingClass.Name + \"_\" + traitFrame.Name;\n        Contract.Assert(traitFrame.Type != null);  // follows from the postcondition of TheFrame\n        Bpl.LocalVariable frame = new Bpl.LocalVariable(tok, new Bpl.TypedIdent(tok, null ?? traitFrame.Name, traitFrame.Type));\n        localVariables.Add(frame);\n        // $_Frame := (lambda<alpha> $o: ref, $f: Field alpha :: $o != null && $Heap[$o,alloc] ==> ($o,$f) in Modifies/Reads-Clause);\n        Bpl.TypeVariable alpha = new Bpl.TypeVariable(tok, \"alpha\");\n        Bpl.BoundVariable oVar = new Bpl.BoundVariable(tok, new Bpl.TypedIdent(tok, \"$o\", predef.RefType));\n        Bpl.IdentifierExpr o = new Bpl.IdentifierExpr(tok, oVar);\n        Bpl.BoundVariable fVar = new Bpl.BoundVariable(tok, new Bpl.TypedIdent(tok, \"$f\", predef.FieldName(tok, alpha)));\n        Bpl.IdentifierExpr f = new Bpl.IdentifierExpr(tok, fVar);\n        Bpl.Expr ante = Bpl.Expr.And(Bpl.Expr.Neq(o, predef.Null), etran.IsAlloced(tok, o));\n        Bpl.Expr consequent = InRWClause(tok, o, f, traitFrameExps, etran, null, null);\n        Bpl.Expr lambda = new Bpl.LambdaExpr(tok, new List<TypeVariable> { alpha }, new List<Variable> { oVar, fVar }, null,\n                                             Bpl.Expr.Imp(ante, consequent));\n\n        //to initialize $_Frame variable to Frame'\n        builder.Add(Bpl.Cmd.SimpleAssign(tok, new Bpl.IdentifierExpr(tok, frame), lambda));\n\n        // emit: assert (forall<alpha> o: ref, f: Field alpha :: o != null && $Heap[o,alloc] && (o,f) in subFrame ==> $_Frame[o,f]);\n        Bpl.Expr oInCallee = InRWClause(tok, o, f, func.Reads, etran, null, null);\n        Bpl.Expr consequent2 = InRWClause(tok, o, f, traitFrameExps, etran, null, null);\n        Bpl.Expr q = new Bpl.ForallExpr(tok, new List<TypeVariable> { alpha }, new List<Variable> { oVar, fVar },\n                                        Bpl.Expr.Imp(Bpl.Expr.And(ante, oInCallee), consequent2));\n        builder.Add(Assert(tok, q, \"expression may read an object not in the parent trait context's reads clause\", kv));\n    }\n\n    private void AddFunctionOverrideReqsChk(Function f, BoogieStmtListBuilder builder, ExpressionTranslator etran, Dictionary<IVariable, Expression> substMap)\n    {\n      Contract.Requires(f != null);\n      Contract.Requires(builder != null);\n      Contract.Requires(etran != null);\n      Contract.Requires(substMap != null);\n      //generating trait pre-conditions with class variables\n      foreach (var req in f.OverriddenFunction.Req) {\n        Expression precond = Substitute(req.E, null, substMap);\n        builder.Add(TrAssumeCmd(f.tok, etran.TrExpr(precond)));\n      }\n      //generating class pre-conditions\n      foreach (var req in f.Req) {\n        bool splitHappened;  // we actually don't care\n        foreach (var s in TrSplitExpr(req.E, etran, false, out splitHappened)) {\n          if (s.IsChecked) {\n            builder.Add(Assert(f.tok, s.E, \"the function must provide an equal or more permissive precondition than in its parent trait\"));\n          }\n        }\n      }\n    }\n\n    private void AddMethodOverrideCheckImpl(Method m, Bpl.Procedure proc)\n    {\n        Contract.Requires(m != null);\n        Contract.Requires(proc != null);\n        Contract.Requires(sink != null && predef != null);\n        Contract.Requires(m.OverriddenMethod != null);\n        Contract.Requires(m.Ins.Count == m.OverriddenMethod.Ins.Count);\n        Contract.Requires(m.Outs.Count == m.OverriddenMethod.Outs.Count);\n        //Contract.Requires(wellformednessProc || m.Body != null);\n        Contract.Requires(currentModule == null && codeContext == null && _tmpIEs.Count == 0 && isAllocContext == null);\n        Contract.Ensures(currentModule == null && codeContext == null && _tmpIEs.Count == 0 && isAllocContext == null);\n\n        currentModule = m.EnclosingClass.Module;\n        codeContext = m;\n        isAllocContext = new IsAllocContext(m.IsGhost);\n\n        List<Variable> inParams = Bpl.Formal.StripWhereClauses(proc.InParams);\n        List<Variable> outParams = Bpl.Formal.StripWhereClauses(proc.OutParams);\n\n        var builder = new BoogieStmtListBuilder(this);\n        var etran = new ExpressionTranslator(this, predef, m.tok);\n        var localVariables = new List<Variable>();\n        //GenerateImplPrelude(m, wellformednessProc, inParams, outParams, builder, localVariables);\n        if (m is TwoStateLemma) {\n          // $Heap := current$Heap;\n          var heap = (Bpl.IdentifierExpr /*TODO: this cast is somewhat dubious*/)new ExpressionTranslator(this, predef, m.tok).HeapExpr;\n          builder.Add(Bpl.Cmd.SimpleAssign(m.tok, heap, new Bpl.IdentifierExpr(m.tok, \"current$Heap\", predef.HeapType)));\n        }\n\n\n        var substMap = new Dictionary<IVariable, Expression>();\n        for (int i = 0; i < m.Ins.Count; i++)\n        {\n            //get corresponsing formal in the class\n            var ie = new IdentifierExpr(m.Ins[i].tok, m.Ins[i].AssignUniqueName(m.IdGenerator));\n            ie.Var = m.Ins[i]; ie.Type = ie.Var.Type;\n            substMap.Add(m.OverriddenMethod.Ins[i], ie);\n        }\n        for (int i = 0; i < m.Outs.Count; i++)\n        {\n            //get corresponsing formal in the class\n            var ie = new IdentifierExpr(m.Outs[i].tok, m.Outs[i].AssignUniqueName(m.IdGenerator));\n            ie.Var = m.Outs[i]; ie.Type = ie.Var.Type;\n            substMap.Add(m.OverriddenMethod.Outs[i], ie);\n        }\n\n        Bpl.StmtList stmts;\n        //adding assume Pre’; assert P; // this checks that Pre’ implies P\n        AddMethodOverrideReqsChk(m, builder, etran, substMap);\n\n        //adding assert R <= Rank’;\n        AddOverrideTerminationChk(m, m.OverriddenMethod, builder, etran, substMap);\n\n        //adding assert W <= Frame’\n        AddMethodOverrideSubsetChk(m, builder, etran, localVariables, substMap);\n\n        if (!(m is TwoStateLemma)) {\n          //change the heap at locations W\n          HavocMethodFrameLocations(m, builder, etran, localVariables);\n        }\n\n        //adding assume Q; assert Post’;\n        AddMethodOverrideEnsChk(m, builder, etran, substMap);\n\n        stmts = builder.Collect(m.tok);\n\n        if (EmitImplementation(m.Attributes)) {\n          // emit the impl only when there are proof obligations.\n          QKeyValue kv = etran.TrAttributes(m.Attributes, null);\n          Bpl.Implementation impl = new Bpl.Implementation(m.tok, proc.Name, new List<Bpl.TypeVariable>(), inParams, outParams, localVariables, stmts, kv);\n          sink.AddTopLevelDeclaration(impl);\n\n          if (InsertChecksums) {\n            InsertChecksum(m, impl);\n          }\n        }\n\n        isAllocContext = null;\n        Reset();\n    }\n\n    private void HavocMethodFrameLocations(Method m, BoogieStmtListBuilder builder, ExpressionTranslator etran, List<Variable> localVariables)\n    {\n        Contract.Requires(m != null);\n        Contract.Requires(m.EnclosingClass != null && m.EnclosingClass is ClassDecl);\n\n        // play havoc with the heap according to the modifies clause\n        builder.Add(new Bpl.HavocCmd(m.tok, new List<Bpl.IdentifierExpr> { (Bpl.IdentifierExpr/*TODO: this cast is rather dubious*/)etran.HeapExpr }));\n        // assume the usual two-state boilerplate information\n        foreach (BoilerplateTriple tri in GetTwoStateBoilerplate(m.tok, m.Mod.Expressions, m.IsGhost, etran.Old, etran, etran.Old))\n        {\n            if (tri.IsFree)\n            {\n                builder.Add(TrAssumeCmd(m.tok, tri.Expr));\n            }\n        }\n    }\n\n    private void AddMethodOverrideEnsChk(Method m, BoogieStmtListBuilder builder, ExpressionTranslator etran, Dictionary<IVariable, Expression> substMap)\n    {\n      Contract.Requires(m != null);\n      Contract.Requires(builder != null);\n      Contract.Requires(etran != null);\n      Contract.Requires(substMap != null);\n      //generating class post-conditions\n      foreach (var en in m.Ens) {\n        builder.Add(TrAssumeCmd(m.tok, etran.TrExpr(en.E)));\n      }\n      //generating trait post-conditions with class variables\n      foreach (var en in m.OverriddenMethod.Ens) {\n        Expression postcond = Substitute(en.E, null, substMap);\n        bool splitHappened;  // we actually don't care\n        foreach (var s in TrSplitExpr(postcond, etran, false, out splitHappened)) {\n          if (s.IsChecked) {\n            builder.Add(Assert(m.tok, s.E, \"the method must provide an equal or more detailed postcondition than in its parent trait\"));\n          }\n        }\n      }\n    }\n\n    private void AddMethodOverrideReqsChk(Method m, BoogieStmtListBuilder builder, ExpressionTranslator etran, Dictionary<IVariable, Expression> substMap)\n    {\n      Contract.Requires(m != null);\n      Contract.Requires(builder != null);\n      Contract.Requires(etran != null);\n      Contract.Requires(substMap != null);\n      //generating trait pre-conditions with class variables\n      foreach (var req in m.OverriddenMethod.Req) {\n        Expression precond = Substitute(req.E, null, substMap);\n        builder.Add(TrAssumeCmd(m.tok, etran.TrExpr(precond)));\n      }\n      //generating class pre-conditions\n      foreach (var req in m.Req) {\n        bool splitHappened;  // we actually don't care\n        foreach (var s in TrSplitExpr(req.E, etran, false, out splitHappened)) {\n          if (s.IsChecked) {\n            builder.Add(Assert(m.tok, s.E, \"the method must provide an equal or more permissive precondition than in its parent trait\"));\n          }\n        }\n      }\n    }\n\n    private void AddOverrideTerminationChk(ICallable original, ICallable overryd, BoogieStmtListBuilder builder, ExpressionTranslator etran, Dictionary<IVariable, Expression> substMap) {\n      Contract.Requires(original != null);\n      Contract.Requires(overryd != null);\n      Contract.Requires(builder != null);\n      Contract.Requires(etran != null);\n      Contract.Requires(substMap != null);\n      // Note, it is as if the trait's method is calling the class's method.\n      var contextDecreases = overryd.Decreases.Expressions;\n      var calleeDecreases = original.Decreases.Expressions;\n      // We want to check:  calleeDecreases <= contextDecreases (note, we can allow equality, since there is a bounded, namely 1, number of dynamic dispatches)\n      if (Contract.Exists(contextDecreases, e => e is WildcardExpr)) {\n        // no check needed\n        return;\n      }\n\n      int N = Math.Min(contextDecreases.Count, calleeDecreases.Count);\n      var toks = new List<IToken>();\n      var types0 = new List<Type>();\n      var types1 = new List<Type>();\n      var callee = new List<Expr>();\n      var caller = new List<Expr>();\n\n      for (int i = 0; i < N; i++) {\n        Expression e0 = calleeDecreases[i];\n        Expression e1 = Substitute(contextDecreases[i], null, substMap);\n        if (!CompatibleDecreasesTypes(e0.Type, e1.Type)) {\n          N = i;\n          break;\n        }\n        toks.Add(new NestedToken(original.Tok, e1.tok));\n        types0.Add(e0.Type.NormalizeExpand());\n        types1.Add(e1.Type.NormalizeExpand());\n        callee.Add(etran.TrExpr(e0));\n        caller.Add(etran.TrExpr(e1));\n      }\n\n      var decrCountT = contextDecreases.Count;\n      var decrCountC = calleeDecreases.Count;\n      // Generally, we want to produce a check \"decrClass <= decrTrait\", allowing (the common case where) they are equal.\n      // * If N < decrCountC && N < decrCountT, then \"decrClass <= decrTrait\" if the comparison ever gets beyond the\n      //   parts that survived truncation.  Thus, we compare with \"allowNoChange\" set to \"false\".\n      // Otherwise:\n      // * If decrCountC == decrCountT, then the truncation we did above had no effect and we pass in \"allowNoChange\" as \"true\".\n      // * If decrCountC > decrCountT, then we will have truncated decrClass above.  Let x,y and x' denote decrClass and\n      //   decrTrait, respectively, where x and x' have the same length.  Considering how Dafny in effect pads the end of\n      //   decreases tuples with a \\top, we were supposed to evaluate (x,(y,\\top)) <= (x',\\top), which by lexicographic pairs\n      //   we can expand to:\n      //       x <= x' && (x == x' ==> (y,\\top) <= \\top)\n      //   which is equivalent to just x <= x'.  Thus, we called DecreasesCheck to compare x and x' and we pass in \"allowNoChange\"\n      //   as \"true\".\n      // * If decrCountC < decrCountT, then we will have truncated decrTrait above.  Let x and x',y' denote decrClass and\n      //   decrTrait, respectively, where x and x' have the same length.  We then want to check (x,\\top) <= (x',(y',\\top)), which\n      //   expands to:\n      //       x <= x' && (x == x' ==> \\top <= (y',\\top))\n      //    =      { \\top is strictly larger than a pair }\n      //       x <= x' && (x == x' ==> false)\n      //    =\n      //       x < x'\n      //   So we perform our desired check by calling DecreasesCheck to strictly compare x and x', so we pass in \"allowNoChange\"\n      //   as \"false\".\n      bool allowNoChange = N == decrCountT && decrCountT <= decrCountC;\n      var decrChk = DecreasesCheck(toks, types0, types1, callee, caller, null, null, allowNoChange, false);\n      builder.Add(Assert(original.Tok, decrChk, string.Format(\"{0}'s decreases clause must be below or equal to that in the trait\", original.WhatKind)));\n    }\n\n    private void AddMethodOverrideSubsetChk(Method m, BoogieStmtListBuilder builder, ExpressionTranslator etran, List<Variable> localVariables, Dictionary<IVariable, Expression> substMap)\n    {\n        //getting framePrime\n        List<FrameExpression> traitFrameExps = new List<FrameExpression>();\n        List<FrameExpression> classFrameExps = m.Mod != null ? m.Mod.Expressions : new List<FrameExpression>();\n        if (m.OverriddenMethod.Mod != null)\n        {\n            foreach (var e in m.OverriddenMethod.Mod.Expressions)\n            {\n                var newE = Substitute(e.E, null, substMap);\n                FrameExpression fe = new FrameExpression(e.tok, newE, e.FieldName);\n                traitFrameExps.Add(fe);\n            }\n        }\n\n        QKeyValue kv = etran.TrAttributes(m.Attributes, null);\n\n        IToken tok = m.tok;\n        // Declare a local variable $_Frame: <alpha>[ref, Field alpha]bool\n        Bpl.IdentifierExpr traitFrame = etran.TheFrame(m.OverriddenMethod.tok);  // this is a throw-away expression, used only to extract the type and name of the $_Frame variable\n        traitFrame.Name = m.EnclosingClass.Name + \"_\" + traitFrame.Name;\n        Contract.Assert(traitFrame.Type != null);  // follows from the postcondition of TheFrame\n        Bpl.LocalVariable frame = new Bpl.LocalVariable(tok, new Bpl.TypedIdent(tok, null ?? traitFrame.Name, traitFrame.Type));\n        localVariables.Add(frame);\n        // $_Frame := (lambda<alpha> $o: ref, $f: Field alpha :: $o != null && $Heap[$o,alloc] ==> ($o,$f) in Modifies/Reads-Clause);\n        Bpl.TypeVariable alpha = new Bpl.TypeVariable(tok, \"alpha\");\n        Bpl.BoundVariable oVar = new Bpl.BoundVariable(tok, new Bpl.TypedIdent(tok, \"$o\", predef.RefType));\n        Bpl.IdentifierExpr o = new Bpl.IdentifierExpr(tok, oVar);\n        Bpl.BoundVariable fVar = new Bpl.BoundVariable(tok, new Bpl.TypedIdent(tok, \"$f\", predef.FieldName(tok, alpha)));\n        Bpl.IdentifierExpr f = new Bpl.IdentifierExpr(tok, fVar);\n        Bpl.Expr ante = Bpl.Expr.And(Bpl.Expr.Neq(o, predef.Null), etran.IsAlloced(tok, o));\n        Bpl.Expr consequent = InRWClause(tok, o, f, traitFrameExps, etran, null, null);\n        Bpl.Expr lambda = new Bpl.LambdaExpr(tok, new List<TypeVariable> { alpha }, new List<Variable> { oVar, fVar }, null,\n                                             Bpl.Expr.Imp(ante, consequent));\n\n        //to initialize $_Frame variable to Frame'\n        builder.Add(Bpl.Cmd.SimpleAssign(tok, new Bpl.IdentifierExpr(tok, frame), lambda));\n\n        // emit: assert (forall<alpha> o: ref, f: Field alpha :: o != null && $Heap[o,alloc] && (o,f) in subFrame ==> $_Frame[o,f]);\n        Bpl.Expr oInCallee = InRWClause(tok, o, f, classFrameExps, etran, null, null);\n        Bpl.Expr consequent2 = InRWClause(tok, o, f, traitFrameExps, etran, null, null);\n        Bpl.Expr q = new Bpl.ForallExpr(tok, new List<TypeVariable> { alpha }, new List<Variable> { oVar, fVar },\n                                        Bpl.Expr.Imp(Bpl.Expr.And(ante, oInCallee), consequent2));\n        builder.Add(Assert(tok, q, \"expression may modify an object not in the parent trait context's modifies clause\", kv));\n    }\n\n    private void InsertChecksum(Method m, Bpl.Declaration decl, bool specificationOnly = false)\n    {\n      Contract.Requires(VisibleInScope(m));\n      byte[] data;\n      using (var writer = new System.IO.StringWriter())\n      {\n        var printer = new Printer(writer);\n        printer.PrintAttributes(m.Attributes);\n        printer.PrintFormals(m.Ins, m);\n        if (m.Outs.Any())\n        {\n          writer.Write(\"returns \");\n          printer.PrintFormals(m.Outs, m);\n        }\n        printer.PrintSpec(\"\", m.Req, 0);\n        printer.PrintFrameSpecLine(\"\", m.Mod.Expressions, 0, null);\n        printer.PrintSpec(\"\", m.Ens, 0);\n        printer.PrintDecreasesSpec(m.Decreases, 0);\n        if (!specificationOnly && m.Body != null && RevealedInScope(m))\n        {\n          printer.PrintStatement(m.Body, 0);\n        }\n        data = Encoding.UTF8.GetBytes(writer.ToString());\n      }\n\n      InsertChecksum(decl, data);\n    }\n\n    private void InsertChecksum(DatatypeDecl d, Bpl.Declaration decl)\n    {\n      Contract.Requires(VisibleInScope(d));\n      byte[] data;\n      using (var writer = new System.IO.StringWriter())\n      {\n        var printer = new Printer(writer);\n        printer.PrintDatatype(d, 0, null);\n        data = Encoding.UTF8.GetBytes(writer.ToString());\n      }\n\n      InsertChecksum(decl, data);\n    }\n\n    private void InsertChecksum(Expression e, Bpl.Declaration decl)\n    {\n      byte[] data;\n      using (var writer = new System.IO.StringWriter())\n      {\n        var printer = new Printer(writer);\n        printer.PrintExpression(e, false);\n        data = Encoding.UTF8.GetBytes(writer.ToString());\n      }\n\n      InsertChecksum(decl, data);\n    }\n\n    private void InsertChecksum(Function f, Bpl.Declaration decl, bool specificationOnly = false)\n    {\n      Contract.Requires(f != null);\n      Contract.Requires(decl != null);\n      Contract.Requires(VisibleInScope(f));\n      byte[] data;\n      using (var writer = new System.IO.StringWriter())\n      {\n        var printer = new Printer(writer);\n        writer.Write(f.IsGhost ? \"function\" : \"function method\");\n        printer.PrintAttributes(f.Attributes);\n        printer.PrintFormals(f.Formals, f);\n        writer.Write(\": \");\n        printer.PrintType(f.ResultType);\n        printer.PrintSpec(\"\", f.Req, 0);\n        printer.PrintFrameSpecLine(\"\", f.Reads, 0, null);\n        printer.PrintSpec(\"\", f.Ens, 0);\n        printer.PrintDecreasesSpec(f.Decreases, 0);\n        if (!specificationOnly && f.Body != null && RevealedInScope(f))\n        {\n          printer.PrintExpression(f.Body, false);\n        }\n        data = Encoding.UTF8.GetBytes(writer.ToString());\n      }\n\n      InsertChecksum(decl, data);\n    }\n\n    private void InsertChecksum(Bpl.Declaration decl, byte[] data)\n    {\n      Contract.Requires(decl != null);\n      Contract.Requires(data != null);\n      var md5 = System.Security.Cryptography.MD5.Create();\n      var hashedData = md5.ComputeHash(data);\n      var checksum = BitConverter.ToString(hashedData);\n\n      decl.AddAttribute(\"checksum\", checksum);\n\n      InsertUniqueIdForImplementation(decl);\n    }\n\n    public void InsertUniqueIdForImplementation(Bpl.Declaration decl)\n    {\n      var impl = decl as Bpl.Implementation;\n      var prefix = UniqueIdPrefix ?? (decl.tok.filename == null ? \"\" : System.Text.RegularExpressions.Regex.Replace(decl.tok.filename, @\".v\\d+.dfy\", \".dfy\"));\n      if (impl != null && !string.IsNullOrEmpty(prefix))\n      {\n        decl.AddAttribute(\"id\", prefix + \":\" + impl.Name + \":0\");\n      }\n    }\n\n    void CheckFrameWellFormed(WFOptions wfo, List<FrameExpression> fes, List<Variable> locals, BoogieStmtListBuilder builder, ExpressionTranslator etran) {\n      Contract.Requires(fes != null);\n      Contract.Requires(locals != null);\n      Contract.Requires(builder != null);\n      Contract.Requires(etran != null);\n      foreach (var fe in fes) {\n        CheckWellformed(fe.E, wfo, locals, builder, etran);\n        if (fe.Field != null && fe.E.Type.IsRefType) {\n          builder.Add(Assert(fe.tok, Bpl.Expr.Neq(etran.TrExpr(fe.E), predef.Null), \"frame expression may dereference null\"));\n        }\n      }\n    }\n\n    void GenerateImplPrelude(Method m, bool wellformednessProc, List<Variable> inParams, List<Variable> outParams,\n                             BoogieStmtListBuilder builder, List<Variable> localVariables) {\n      Contract.Requires(m != null);\n      Contract.Requires(inParams != null);\n      Contract.Requires(outParams != null);\n      Contract.Requires(builder != null);\n      Contract.Requires(localVariables != null);\n      Contract.Requires(predef != null);\n      Contract.Requires(wellformednessProc || m.Body != null);\n\n      if (m is TwoStateLemma) {\n        // $Heap := current$Heap;\n        var heap = (Bpl.IdentifierExpr /*TODO: this cast is somewhat dubious*/)new ExpressionTranslator(this, predef, m.tok).HeapExpr;\n        builder.Add(Bpl.Cmd.SimpleAssign(m.tok, heap, new Bpl.IdentifierExpr(m.tok, \"current$Heap\", predef.HeapType)));\n      }\n\n      // set up the information used to verify the method's modifies clause\n      DefineFrame(m.tok, m.Mod.Expressions, builder, localVariables, null);\n      if (wellformednessProc) {\n        builder.Add(CaptureState(m.tok, false, \"initial state\"));\n      } else {\n        Contract.Assert(m.Body != null);  // follows from precondition and the if guard\n        // use the position immediately after the open-curly-brace of the body\n        builder.Add(CaptureState(m.Body.Tok, true, \"initial state\"));\n      }\n    }\n\n    void GenerateIteratorImplPrelude(IteratorDecl iter, List<Variable> inParams, List<Variable> outParams,\n                                     BoogieStmtListBuilder builder, List<Variable> localVariables) {\n      Contract.Requires(iter != null);\n      Contract.Requires(inParams != null);\n      Contract.Requires(outParams != null);\n      Contract.Requires(builder != null);\n      Contract.Requires(localVariables != null);\n      Contract.Requires(predef != null);\n\n      // set up the information used to verify the method's modifies clause\n      var iteratorFrame = new List<FrameExpression>();\n      var th = new ThisExpr(iter.tok);\n      th.Type = Resolver.GetThisType(iter.tok, iter);  // resolve here\n      iteratorFrame.Add(new FrameExpression(iter.tok, th, null));\n      iteratorFrame.AddRange(iter.Modifies.Expressions);\n      DefineFrame(iter.tok, iteratorFrame, builder, localVariables, null);\n      builder.Add(CaptureState(iter.tok, false, \"initial state\"));\n    }\n\n    Bpl.Cmd CaptureState(IToken tok, bool isEndToken, string/*?*/ additionalInfo) {\n      Contract.Requires(tok != null);\n      Contract.Ensures(Contract.Result<Bpl.Cmd>() != null);\n      var col = tok.col + (isEndToken ? tok.val.Length : 0);\n      string description = String.Format(\"{0}{1}\", ErrorReporter.TokenToString(tok), additionalInfo == null ? \"\" : (\": \" + additionalInfo));\n      QKeyValue kv = new QKeyValue(tok, \"captureState\", new List<object>() { description }, null);\n      return TrAssumeCmd(tok, Bpl.Expr.True, kv);\n    }\n    Bpl.Cmd CaptureState(Statement stmt) {\n      Contract.Requires(stmt != null);\n      Contract.Ensures(Contract.Result<Bpl.Cmd>() != null);\n      return CaptureState(stmt.EndTok, true, null);\n    }\n\n    void DefineFrame(IToken/*!*/ tok, List<FrameExpression/*!*/>/*!*/ frameClause, BoogieStmtListBuilder/*!*/ builder, List<Variable>/*!*/ localVariables, string name)\n    {\n      Contract.Requires(tok != null);\n      Contract.Requires(cce.NonNullElements(frameClause));\n      Contract.Requires(builder != null);\n      Contract.Requires(cce.NonNullElements(localVariables));\n      Contract.Requires(predef != null);\n\n      var etran = new ExpressionTranslator(this, predef, tok);\n      // Declare a local variable $_Frame: <alpha>[ref, Field alpha]bool\n      Bpl.IdentifierExpr theFrame = etran.TheFrame(tok);  // this is a throw-away expression, used only to extract the type and name of the $_Frame variable\n      Contract.Assert(theFrame.Type != null);  // follows from the postcondition of TheFrame\n      Bpl.LocalVariable frame = new Bpl.LocalVariable(tok, new Bpl.TypedIdent(tok, name ?? theFrame.Name, theFrame.Type));\n      localVariables.Add(frame);\n      // $_Frame := (lambda<alpha> $o: ref, $f: Field alpha :: $o != null && $Heap[$o,alloc] ==> ($o,$f) in Modifies/Reads-Clause);\n      // $_Frame := (lambda<alpha> $o: ref, $f: Field alpha :: $o != null                    ==> ($o,$f) in Modifies/Reads-Clause);\n      Bpl.TypeVariable alpha = new Bpl.TypeVariable(tok, \"alpha\");\n      Bpl.BoundVariable oVar = new Bpl.BoundVariable(tok, new Bpl.TypedIdent(tok, \"$o\", predef.RefType));\n      Bpl.IdentifierExpr o = new Bpl.IdentifierExpr(tok, oVar);\n      Bpl.BoundVariable fVar = new Bpl.BoundVariable(tok, new Bpl.TypedIdent(tok, \"$f\", predef.FieldName(tok, alpha)));\n      Bpl.IdentifierExpr f = new Bpl.IdentifierExpr(tok, fVar);\n      Bpl.Expr oNotNull = Bpl.Expr.Neq(o, predef.Null);\n      Bpl.Expr ante = Bpl.Expr.And(oNotNull, etran.IsAlloced(tok, o));\n      Bpl.Expr consequent = InRWClause(tok, o, f, frameClause, etran, null, null);\n      Bpl.Expr lambda = new Bpl.LambdaExpr(tok, new List<TypeVariable> { alpha }, new List<Variable> { oVar, fVar }, null,\n                                           Bpl.Expr.Imp(ante, consequent));\n\n      builder.Add(Bpl.Cmd.SimpleAssign(tok, new Bpl.IdentifierExpr(tok, frame), lambda));\n    }\n\n    void CheckFrameSubset(IToken tok, List<FrameExpression> calleeFrame,\n                          Expression receiverReplacement, Dictionary<IVariable, Expression /*!*/> substMap,\n                          ExpressionTranslator /*!*/ etran,\n                          BoogieStmtListBuilder /*!*/ builder,\n                          string errorMessage,\n                          Bpl.QKeyValue kv)\n    {\n      CheckFrameSubset(tok, calleeFrame, receiverReplacement, substMap, etran,\n        (t, e, s, q) => builder.Add(Assert(t, e, s, q)), errorMessage, kv);\n    }\n\n    void CheckFrameSubset(IToken tok, List<FrameExpression> calleeFrame,\n                          Expression receiverReplacement, Dictionary<IVariable,Expression/*!*/> substMap,\n                          ExpressionTranslator/*!*/ etran,\n                          Action<IToken, Bpl.Expr, string, Bpl.QKeyValue> MakeAssert,\n                          string errorMessage,\n                          Bpl.QKeyValue kv)\n    {\n      Contract.Requires(tok != null);\n      Contract.Requires(calleeFrame != null);\n      Contract.Requires(receiverReplacement == null || substMap != null);\n      Contract.Requires(etran != null);\n      Contract.Requires(MakeAssert != null);\n      Contract.Requires(errorMessage != null);\n      Contract.Requires(predef != null);\n\n      // emit: assert (forall<alpha> o: ref, f: Field alpha :: o != null && $Heap[o,alloc] && (o,f) in subFrame ==> $_Frame[o,f]);\n      Bpl.TypeVariable alpha = new Bpl.TypeVariable(tok, \"alpha\");\n      Bpl.BoundVariable oVar = new Bpl.BoundVariable(tok, new Bpl.TypedIdent(tok, \"$o\", predef.RefType));\n      Bpl.IdentifierExpr o = new Bpl.IdentifierExpr(tok, oVar);\n      Bpl.BoundVariable fVar = new Bpl.BoundVariable(tok, new Bpl.TypedIdent(tok, \"$f\", predef.FieldName(tok, alpha)));\n      Bpl.IdentifierExpr f = new Bpl.IdentifierExpr(tok, fVar);\n      Bpl.Expr ante = Bpl.Expr.And(Bpl.Expr.Neq(o, predef.Null), etran.IsAlloced(tok, o));\n      Bpl.Expr oInCallee = InRWClause(tok, o, f, calleeFrame, etran, receiverReplacement, substMap);\n      Bpl.Expr inEnclosingFrame = Bpl.Expr.Select(etran.TheFrame(tok), o, f);\n      Bpl.Expr q = new Bpl.ForallExpr(tok, new List<TypeVariable> { alpha }, new List<Variable> { oVar, fVar },\n                                      Bpl.Expr.Imp(Bpl.Expr.And(ante, oInCallee), inEnclosingFrame));\n      MakeAssert(tok, q, errorMessage, kv);\n    }\n\n    /// <summary>\n    /// Generates:\n    ///   axiom (forall s, h0: HeapType, h1: HeapType, formals... ::\n    ///        { IsHeapAnchor(h0), HeapSucc(h0,h1), F(s,h1,formals) }\n    ///        heaps are well-formed and [formals are allocated AND]\n    ///        IsHeapAnchor(h0) AND HeapSucc(h0,h1)\n    ///        AND\n    ///        (forall(alpha) o: ref, f: Field alpha ::\n    ///            o != null [AND h0[o,alloc] AND]  // note that HeapSucc(h0,h1) && h0[o,alloc] ==> h1[o,alloc]\n    ///            o in reads clause of formals in h0\n    ///            IMPLIES h0[o,f] == h1[o,f])\n    ///        IMPLIES\n    ///        F(s,h0,formals) == F(s,h1,formals)\n    ///      );\n    /// Expressions in [...] are omitted if\n    ///   - /allocated:0, or\n    ///   - /allocated:1, or\n    ///   - /allocated:3, except if \"reads\" clause is \"*\" of if the function is a two-state function;\n    /// see comments in AddArrowTypeAxioms\n    /// Also, with /allocated:3, the frame axiom is omitted altogether if the (one-state) function has an\n    /// empty \"reads\" clause (because then the function doesn't take a heap argument at all).\n    /// </summary>\n    void AddFrameAxiom(Function f)\n    {\n      Contract.Requires(f != null);\n      Contract.Requires(sink != null && predef != null);\n\n      var comment = \"frame axiom for \" + f.FullSanitizedName;\n      // This is the general case\n      Bpl.Expr prevH = null;\n      Bpl.BoundVariable prevHVar = null;\n      if (f is TwoStateFunction) {\n        // The previous-heap argument is the same for both function arguments.  That is,\n        // the frame axiom says nothing about functions invoked with different previous heaps.\n        prevHVar = BplBoundVar(\"$prevHeap\", predef.HeapType, out prevH);\n      }\n      Bpl.Expr h0; var h0Var = BplBoundVar(\"$h0\", predef.HeapType, out h0);\n      Bpl.Expr h1; var h1Var = BplBoundVar(\"$h1\", predef.HeapType, out h1);\n\n      var etran0 = new ExpressionTranslator(this, predef, h0);\n      var etran1 = new ExpressionTranslator(this, predef, h1);\n\n      Bpl.Expr wellFormed = Bpl.Expr.And(\n        FunctionCall(f.tok, BuiltinFunction.IsGoodHeap, null, etran0.HeapExpr),\n        FunctionCall(f.tok, BuiltinFunction.IsGoodHeap, null, etran1.HeapExpr));\n\n      Bpl.TypeVariable alpha = new Bpl.TypeVariable(f.tok, \"alpha\");\n      Bpl.Expr o; var oVar = BplBoundVar(\"$o\", predef.RefType, out o);\n      Bpl.Expr field; var fieldVar = BplBoundVar(\"$f\", predef.FieldName(f.tok, alpha), out field);\n      Bpl.Expr oNotNull = Bpl.Expr.Neq(o, predef.Null);\n      Bpl.Expr oNotNullAlloced = !AlwaysUseHeap ? oNotNull : Bpl.Expr.And(oNotNull, etran0.IsAlloced(f.tok, o));\n      Bpl.Expr unchanged = Bpl.Expr.Eq(ReadHeap(f.tok, h0, o, field), ReadHeap(f.tok, h1, o, field));\n\n      Bpl.Expr h0IsHeapAnchor = FunctionCall(h0.tok, BuiltinFunction.IsHeapAnchor, null, h0);\n      Bpl.Expr heapSucc = HeapSucc(h0, h1);\n      Bpl.Expr r0 = InRWClause(f.tok, o, field, f.Reads, etran0, null, null);\n      Bpl.Expr q0 = new Bpl.ForallExpr(f.tok, new List<TypeVariable> { alpha }, new List<Variable> { oVar, fieldVar },\n        Bpl.Expr.Imp(Bpl.Expr.And(oNotNullAlloced, r0), unchanged));\n\n      List<Bpl.Expr> tyexprs;\n      var bvars = MkTyParamBinders(GetTypeParams(f), out tyexprs);\n      var f0args = new List<Bpl.Expr>(tyexprs);\n      var f1args = new List<Bpl.Expr>(tyexprs);\n      var f0argsCanCall = new List<Bpl.Expr>(tyexprs);\n      var f1argsCanCall = new List<Bpl.Expr>(tyexprs);\n      if (f.IsFuelAware()) {\n        Bpl.Expr s; var sV = BplBoundVar(\"$ly\", predef.LayerType, out s);\n        bvars.Add(sV);\n        f0args.Add(s); f1args.Add(s);  // but don't add to f0argsCanCall or f1argsCanCall\n      }\n\n      if (prevH != null) {\n        bvars.Add(prevHVar);\n        f0args.Add(prevH); f1args.Add(prevH); f0argsCanCall.Add(prevH); f1argsCanCall.Add(prevH);\n      }\n      bvars.Add(h0Var); bvars.Add(h1Var);\n      f0args.Add(h0); f1args.Add(h1); f0argsCanCall.Add(h0); f1argsCanCall.Add(h1);\n\n      var useAlloc = CommonHeapUse && !AlwaysUseHeap && f.Reads.Exists(fe => fe.E is WildcardExpr) ? ISALLOC : NOALLOC;\n      if (!f.IsStatic) {\n        Bpl.Expr th; var thVar = BplBoundVar(\"this\", TrReceiverType(f), out th);\n        bvars.Add(thVar);\n        f0args.Add(th); f1args.Add(th); f0argsCanCall.Add(th); f1argsCanCall.Add(th);\n\n        Type thisType = Resolver.GetReceiverType(f.tok, f);\n        Bpl.Expr wh = Bpl.Expr.And(ReceiverNotNull(th), GetWhereClause(f.tok, th, thisType, etran0, useAlloc));\n        wellFormed = Bpl.Expr.And(wellFormed, wh);\n      }\n\n      // (formalsAreWellFormed[h0] || canCallF(h0,...)) && (formalsAreWellFormed[h1] || canCallF(h1,...))\n      Bpl.Expr fwf0 = Bpl.Expr.True;\n      Bpl.Expr fwf1 = Bpl.Expr.True;\n      foreach (Formal p in f.Formals) {\n        Bpl.BoundVariable bv = new Bpl.BoundVariable(p.tok, new Bpl.TypedIdent(p.tok, p.AssignUniqueName(f.IdGenerator), TrType(p.Type)));\n        bvars.Add(bv);\n        Bpl.Expr formal = new Bpl.IdentifierExpr(p.tok, bv);\n        f0args.Add(formal); f1args.Add(formal); f0argsCanCall.Add(formal); f1argsCanCall.Add(formal);\n        Bpl.Expr wh = GetWhereClause(p.tok, formal, p.Type, etran0, useAlloc);\n        if (wh != null) { fwf0 = Bpl.Expr.And(fwf0, wh); }\n      }\n      var canCall = new Bpl.FunctionCall(new Bpl.IdentifierExpr(f.tok, f.FullSanitizedName + \"#canCall\", Bpl.Type.Bool));\n      wellFormed = Bpl.Expr.And(wellFormed, Bpl.Expr.And(\n        Bpl.Expr.Or(new Bpl.NAryExpr(f.tok, canCall, f0argsCanCall), fwf0),\n        Bpl.Expr.Or(new Bpl.NAryExpr(f.tok, canCall, f1argsCanCall), fwf1)));\n\n      /*\n      DR: I conjecture that this should be enough,\n          as the requires is preserved when the frame is:\n\n      wellFormed = Bpl.Expr.And(wellFormed,\n        Bpl.Expr.Or(new Bpl.NAryExpr(f.tok, canCall, f0argsCanCall), fwf0));\n      */\n\n      var fn = new Bpl.FunctionCall(new Bpl.IdentifierExpr(f.tok, f.FullSanitizedName, TrType(f.ResultType)));\n      var F0 = new Bpl.NAryExpr(f.tok, fn, f0args);\n      var F1 = new Bpl.NAryExpr(f.tok, fn, f1args);\n      var eq = Bpl.Expr.Eq(F0, F1);\n      var tr = new Bpl.Trigger(f.tok, true, new List<Bpl.Expr> { h0IsHeapAnchor, heapSucc, F1 });\n\n      var ax = new Bpl.ForallExpr(f.tok, new List<Bpl.TypeVariable>(), bvars, null, tr,\n        Bpl.Expr.Imp(Bpl.Expr.And(wellFormed, Bpl.Expr.And(h0IsHeapAnchor, heapSucc)),\n        Bpl.Expr.Imp(q0, eq)));\n      sink.AddTopLevelDeclaration(new Bpl.Axiom(f.tok, ax, comment));\n    }\n\n    Bpl.Expr InRWClause(IToken tok, Bpl.Expr o, Bpl.Expr f, List<FrameExpression> rw, ExpressionTranslator etran,\n                        Expression receiverReplacement, Dictionary<IVariable, Expression> substMap) {\n      Contract.Requires(tok != null);\n      Contract.Requires(o != null);\n      // Contract.Requires(f != null); // f == null means approximate\n      Contract.Requires(etran != null);\n      Contract.Requires(cce.NonNullElements(rw));\n      Contract.Requires(substMap == null || cce.NonNullDictionaryAndValues(substMap));\n      Contract.Requires(predef != null);\n      Contract.Requires(receiverReplacement == null || substMap != null);\n      Contract.Ensures(Contract.Result<Bpl.Expr>() != null);\n      return InRWClause(tok, o, f, rw, false, etran, receiverReplacement, substMap);\n    }\n    Bpl.Expr InRWClause(IToken tok, Bpl.Expr o, Bpl.Expr f, List<FrameExpression> rw, bool useInUnchanged,\n                        ExpressionTranslator etran,\n                        Expression receiverReplacement, Dictionary<IVariable, Expression> substMap) {\n      Contract.Requires(tok != null);\n      Contract.Requires(o != null);\n      // Contract.Requires(f != null); // f == null means approximate\n      Contract.Requires(etran != null);\n      Contract.Requires(cce.NonNullElements(rw));\n      Contract.Requires(substMap == null || cce.NonNullDictionaryAndValues(substMap));\n      Contract.Requires(predef != null);\n      Contract.Requires(receiverReplacement == null || substMap != null);\n      Contract.Ensures(Contract.Result<Bpl.Expr>() != null);\n      var boxO = FunctionCall(tok, BuiltinFunction.Box, null, o);\n      return InRWClause_Aux(tok, o, boxO, f, rw, useInUnchanged, etran, receiverReplacement, substMap);\n    }\n\n    /// <summary>\n    /// By taking both an \"o\" and a \"boxO\" parameter, the caller has a choice of passing in either\n    /// \"o, Box(o)\" for some \"o\" or \"Unbox(bx), bx\" for some \"bx\".\n    /// </summary>\n    Bpl.Expr InRWClause_Aux(IToken tok, Bpl.Expr o, Bpl.Expr boxO, Bpl.Expr f, List<FrameExpression> rw, bool usedInUnchanged,\n                        ExpressionTranslator etran,\n                        Expression receiverReplacement, Dictionary<IVariable, Expression> substMap) {\n      Contract.Requires(tok != null);\n      Contract.Requires(o != null);\n      Contract.Requires(boxO != null);\n      // Contract.Requires(f != null); // f == null means approximate\n      Contract.Requires(etran != null);\n      Contract.Requires(cce.NonNullElements(rw));\n      Contract.Requires(substMap == null || cce.NonNullDictionaryAndValues(substMap));\n      Contract.Requires(predef != null);\n      Contract.Requires(receiverReplacement == null || substMap != null);\n      Contract.Ensures(Contract.Result<Bpl.Expr>() != null);\n\n      // requires o to denote an expression of type RefType\n      // \"rw\" is is allowed to contain a WildcardExpr\n\n      Bpl.Expr disjunction = Bpl.Expr.False;\n      foreach (FrameExpression rwComponent in rw) {\n        Expression e = rwComponent.E;\n        if (substMap != null) {\n          e = Substitute(e, receiverReplacement, substMap);\n        } else {\n          Contract.Assert(receiverReplacement == null);\n        }\n\n        e = Resolver.FrameArrowToObjectSet(e, CurrentIdGenerator, program.BuiltIns);\n\n        Bpl.Expr disjunct;\n        var eType = e.Type.NormalizeExpand();\n        if (e is WildcardExpr) {\n          // For /allocated:{0,1,3}, \"function f(...)... reads *\"\n          // is more useful if \"reads *\" excludes unallocated references,\n          // because otherwise, \"reads *\" lets f depend on unallocated state,\n          // which means that f may change whenever any new allocation occurs,\n          // which is generally undesirable.  Also, Dafny doesn't let you\n          // say \"reads set o :: allocated(o)\", so it's hard to work around\n          // this issue.\n          disjunct = AlwaysUseHeap ? Bpl.Expr.True : etran.IsAlloced(tok, o);\n        } else if (eType is SetType) {\n          // e[Box(o)]\n          bool pr;\n          disjunct = etran.TrInSet_Aux(tok, o, boxO, e, out pr);\n        } else if (eType is MultiSetType) {\n          // e[Box(o)] > 0\n          disjunct = etran.TrInMultiSet_Aux(tok, o, boxO, e);\n        } else if (eType is SeqType) {\n          // (exists i: int :: 0 <= i && i < Seq#Length(e) && Seq#Index(e,i) == Box(o))\n          Bpl.Variable iVar = new Bpl.BoundVariable(tok, new Bpl.TypedIdent(tok, \"$i\", Bpl.Type.Int));\n          Bpl.Expr i = new Bpl.IdentifierExpr(tok, iVar);\n          Bpl.Expr iBounds = InSeqRange(tok, i, Type.Int, etran.TrExpr(e), true, null, false);\n          Bpl.Expr XsubI = FunctionCall(tok, BuiltinFunction.SeqIndex, predef.BoxType, etran.TrExpr(e), i);\n          // TODO: the equality in the next line should be changed to one that understands extensionality\n          //TRIG (exists $i: int :: 0 <= $i && $i < Seq#Length(read($h0, this, _module.DoublyLinkedList.Nodes)) && Seq#Index(read($h0, this, _module.DoublyLinkedList.Nodes), $i) == $Box($o))\n          disjunct = new Bpl.ExistsExpr(tok, new List<Variable> { iVar }, Bpl.Expr.And(iBounds, Bpl.Expr.Eq(XsubI, boxO)));  // LL_TRIGGER\n        } else {\n          // o == e\n          disjunct = Bpl.Expr.Eq(o, etran.TrExpr(e));\n        }\n        if (rwComponent.Field != null && f != null) {\n          Bpl.Expr q = Bpl.Expr.Eq(f, new Bpl.IdentifierExpr(rwComponent.E.tok, GetField(rwComponent.Field)));\n          if (usedInUnchanged) {\n            q = Bpl.Expr.Or(q,\n              Bpl.Expr.Eq(f, new Bpl.IdentifierExpr(rwComponent.E.tok, predef.AllocField)));\n          }\n          disjunct = Bpl.Expr.And(disjunct, q);\n        }\n        disjunction = BplOr(disjunction, disjunct);\n      }\n      return disjunction;\n    }\n\n    private void AddWellformednessCheck(Function f) {\n      Contract.Requires(f != null);\n      Contract.Requires(sink != null && predef != null);\n      Contract.Requires(f.EnclosingClass != null);\n      Contract.Requires(currentModule == null && codeContext == null && isAllocContext != null);\n      Contract.Ensures(currentModule == null && codeContext == null && isAllocContext != null);\n\n      Contract.Assert(InVerificationScope(f));\n\n      currentModule = f.EnclosingClass.Module;\n      codeContext = f;\n\n      Bpl.Expr prevHeap = null;\n      Bpl.Expr currHeap = null;\n      var ordinaryEtran = new ExpressionTranslator(this, predef, f.tok);\n      ExpressionTranslator etran;\n      var inParams_Heap = new List<Bpl.Variable>();\n      if (f is TwoStateFunction) {\n        var prevHeapVar = new Bpl.Formal(f.tok, new Bpl.TypedIdent(f.tok, \"previous$Heap\", predef.HeapType), true);\n        var currHeapVar = new Bpl.Formal(f.tok, new Bpl.TypedIdent(f.tok, \"current$Heap\", predef.HeapType), true);\n        inParams_Heap.Add(prevHeapVar);\n        inParams_Heap.Add(currHeapVar);\n        prevHeap = new Bpl.IdentifierExpr(f.tok, prevHeapVar);\n        currHeap = new Bpl.IdentifierExpr(f.tok, currHeapVar);\n        etran = new ExpressionTranslator(this, predef, currHeap, prevHeap);\n      } else {\n        etran = ordinaryEtran;\n      }\n\n      // parameters of the procedure\n      var typeInParams = MkTyParamFormals(GetTypeParams(f));\n      var inParams = new List<Bpl.Variable>();\n      var outParams = new List<Bpl.Variable>();\n      if (!f.IsStatic) {\n        var th = new Bpl.IdentifierExpr(f.tok, \"this\", TrReceiverType(f));\n        Bpl.Expr wh = Bpl.Expr.And(\n          ReceiverNotNull(th),\n          (f is TwoStateFunction ? etran.Old : etran).GoodRef(f.tok, th, Resolver.GetReceiverType(f.tok, f)));\n        Bpl.Formal thVar = new Bpl.Formal(f.tok, new Bpl.TypedIdent(f.tok, \"this\", TrReceiverType(f), wh), true);\n        inParams.Add(thVar);\n      }\n      foreach (Formal p in f.Formals) {\n        Bpl.Type varType = TrType(p.Type);\n        Bpl.Expr wh = GetWhereClause(p.tok, new Bpl.IdentifierExpr(p.tok, p.AssignUniqueName(f.IdGenerator), varType), p.Type,\n          p.IsOld ? etran.Old : etran, CommonHeapUse && f is TwoStateFunction ? ISALLOC : NOALLOC);\n        inParams.Add(new Bpl.Formal(p.tok, new Bpl.TypedIdent(p.tok, p.AssignUniqueName(f.IdGenerator), varType, wh), true));\n      }\n      if (f.Result != null) {\n        Formal p = f.Result;\n        Contract.Assert(!p.IsOld);\n        Bpl.Type varType = TrType(p.Type);\n        Bpl.Expr wh = GetWhereClause(p.tok, new Bpl.IdentifierExpr(p.tok, p.AssignUniqueName(f.IdGenerator), varType), p.Type, etran, NOALLOC);\n        outParams.Add(new Bpl.Formal(p.tok, new Bpl.TypedIdent(p.tok, p.AssignUniqueName(f.IdGenerator), varType, wh), true));\n      }\n      // the procedure itself\n      var req = new List<Bpl.Requires>();\n      // free requires mh == ModuleContextHeight && fh == FunctionContextHeight;\n      req.Add(Requires(f.tok, true, etran.HeightContext(f), null, null));\n      if (f is TwoStateFunction) {\n        // free requires prevHeap == Heap && HeapSucc(prevHeap, currHeap) && IsHeap(currHeap)\n        var a0 = Bpl.Expr.Eq(prevHeap, ordinaryEtran.HeapExpr);\n        var a1 = HeapSucc(prevHeap, currHeap);\n        var a2 = FunctionCall(f.tok, BuiltinFunction.IsGoodHeap, null, currHeap);\n        req.Add(Requires(f.tok, true, BplAnd(a0, BplAnd(a1, a2)), null, null));\n      }\n\n      // modifies $Heap, $Tick\n      var mod = new List<Bpl.IdentifierExpr> {\n        (Bpl.IdentifierExpr /*TODO: this cast is rather dubious*/)ordinaryEtran.HeapExpr,\n        etran.Tick()\n      };\n      // check that postconditions hold\n      var ens = new List<Bpl.Ensures>();\n      foreach (MaybeFreeExpression p in f.Ens) {\n        var functionHeight = currentModule.CallGraph.GetSCCRepresentativeId(f);\n        var splits = new List<SplitExprInfo>();\n        bool splitHappened /*we actually don't care*/ = TrSplitExpr(p.E, splits, true, functionHeight, true, true, etran);\n        string errorMessage = CustomErrorMessage(p.Attributes);\n        foreach (var s in splits) {\n          if (s.IsChecked && !RefinementToken.IsInherited(s.E.tok, currentModule)) {\n            AddEnsures(ens, Ensures(s.E.tok, false, s.E, errorMessage, null));\n          }\n        }\n      }\n      var proc = new Bpl.Procedure(f.tok, \"CheckWellformed$$\" + f.FullSanitizedName, new List<Bpl.TypeVariable>(),\n        Concat(Concat(typeInParams, inParams_Heap), inParams), outParams,\n        req, mod, ens, etran.TrAttributes(f.Attributes, null));\n      sink.AddTopLevelDeclaration(proc);\n\n      if (InsertChecksums) {\n        InsertChecksum(f, proc, true);\n      }\n\n      Contract.Assert(proc.InParams.Count == typeInParams.Count + inParams_Heap.Count + inParams.Count);\n      // Changed the next line to strip from inParams instead of proc.InParams\n      // They should be the same, but hence the added contract\n      var implInParams = Bpl.Formal.StripWhereClauses(inParams);\n      var implOutParams = Bpl.Formal.StripWhereClauses(outParams);\n      var locals = new List<Variable>();\n      var builder = new BoogieStmtListBuilder(this);\n      var builderInitializationArea = new BoogieStmtListBuilder(this);\n      builder.Add(new CommentCmd(\"AddWellformednessCheck for function \" + f));\n      if (f is TwoStateFunction) {\n        // $Heap := current$Heap;\n        var heap = (Bpl.IdentifierExpr /*TODO: this cast is somewhat dubious*/)ordinaryEtran.HeapExpr;\n        builder.Add(Bpl.Cmd.SimpleAssign(f.tok, heap, etran.HeapExpr));\n        etran = ordinaryEtran;  // we no longer need the special heap names\n      }\n      builder.Add(CaptureState(f.tok, false, \"initial state\"));\n\n      DefineFrame(f.tok, f.Reads, builder, locals, null);\n      InitializeFuelConstant(f.tok, builder, etran);\n      // Check well-formedness of the preconditions (including termination), and then\n      // assume each one of them.  After all that (in particular, after assuming all\n      // of them), do the postponed reads checks.\n      var wfo = new WFOptions(null, true, true /* do delayed reads checks */);\n      foreach (MaybeFreeExpression p in f.Req) {\n        CheckWellformedAndAssume(p.E, wfo, locals, builder, etran);\n      }\n      wfo.ProcessSavedReadsChecks(locals, builderInitializationArea, builder);\n\n      // Check well-formedness of the reads clause.  Note that this is done after assuming\n      // the preconditions.  In other words, the well-formedness of the reads clause is\n      // allowed to assume the precondition (yet, the requires clause is checked to\n      // read only those things indicated in the reads clause).\n      wfo = new WFOptions(null, true, true /* do delayed reads checks */);\n      CheckFrameWellFormed(wfo, f.Reads, locals, builder, etran);\n      wfo.ProcessSavedReadsChecks(locals, builderInitializationArea, builder);\n\n      // check well-formedness of the decreases clauses (including termination, but no reads checks)\n      foreach (Expression p in f.Decreases.Expressions)\n      {\n        CheckWellformed(p, new WFOptions(null, false), locals, builder, etran);\n      }\n      // Generate:\n      //   if (*) {\n      //     check well-formedness of postcondition\n      //     assume false;  // don't go on to check the postconditions\n      //   } else {\n      //     check well-formedness of body\n      //     // fall through to check the postconditions themselves\n      //   }\n      // Here go the postconditions (termination checks included, but no reads checks)\n      BoogieStmtListBuilder postCheckBuilder = new BoogieStmtListBuilder(this);\n      // Assume the type returned by the call itself respects its type (this matters if the type is \"nat\", for example)\n      {\n        var args = new List<Bpl.Expr>();\n        foreach (var p in GetTypeParams(f)) {\n          args.Add(trTypeParam(p, null));\n        }\n        if (f.IsFuelAware()) {\n          args.Add(etran.layerInterCluster.GetFunctionFuel(f));\n        }\n        if (f is TwoStateFunction) {\n          args.Add(etran.Old.HeapExpr);\n        }\n        if (AlwaysUseHeap || f.ReadsHeap) {\n          args.Add(etran.HeapExpr);\n        }\n        if (!f.IsStatic) {\n          args.Add(new Bpl.IdentifierExpr(f.tok, etran.This));\n        }\n        foreach (var p in f.Formals) {\n          args.Add(new Bpl.IdentifierExpr(p.tok, p.AssignUniqueName(f.IdGenerator), TrType(p.Type)));\n        }\n        Bpl.IdentifierExpr funcID = new Bpl.IdentifierExpr(f.tok, f.FullSanitizedName, TrType(f.ResultType));\n        Bpl.Expr funcAppl = new Bpl.NAryExpr(f.tok, new Bpl.FunctionCall(funcID), args);\n\n        var wh = GetWhereClause(f.tok, funcAppl, f.ResultType, etran, NOALLOC);\n        if (wh != null) {\n          postCheckBuilder.Add(TrAssumeCmd(f.tok, wh));\n        }\n      }\n      // Now for the ensures clauses\n      foreach (MaybeFreeExpression p in f.Ens) {\n        // assume the postcondition for the benefit of checking the remaining postconditions\n        CheckWellformedAndAssume(p.E, new WFOptions(f, false), locals, postCheckBuilder, etran);\n      }\n      // Here goes the body (and include both termination checks and reads checks)\n      BoogieStmtListBuilder bodyCheckBuilder = new BoogieStmtListBuilder(this);\n      if (f.Body == null || !RevealedInScope(f)) {\n        // don't fall through to postcondition checks\n        bodyCheckBuilder.Add(TrAssumeCmd(f.tok, Bpl.Expr.False));\n      } else {\n        Bpl.FunctionCall funcID = new Bpl.FunctionCall(new Bpl.IdentifierExpr(f.tok, f.FullSanitizedName, TrType(f.ResultType)));\n        List<Bpl.Expr> args = new List<Bpl.Expr>();\n        foreach (var p in GetTypeParams(f)) {\n          args.Add(trTypeParam(p, null));\n        }\n        if (f.IsFuelAware()) {\n          args.Add(etran.layerInterCluster.GetFunctionFuel(f));\n        }\n        if (f is TwoStateFunction) {\n          args.Add(etran.Old.HeapExpr);\n        }\n        if (AlwaysUseHeap || f.ReadsHeap) {\n          args.Add(etran.HeapExpr);\n        }\n        foreach (Variable p in implInParams) {\n          args.Add(new Bpl.IdentifierExpr(f.tok, p));\n        }\n        Bpl.Expr funcAppl = new Bpl.NAryExpr(f.tok, funcID, args);\n\n        DefineFrame(f.tok, f.Reads, bodyCheckBuilder\n                   , new List<Variable>() /* dummy local variable list, since frame axiom variable (and its definition)\n                                           * is already added. The only reason why we add the frame axiom definition\n                                           * again is to make boogie gives the same trace as before the change that\n                                           * makes reads clauses also guard the requires */\n                   , null);\n\n        wfo = new WFOptions(null, true, true /* do delayed reads checks */);\n        CheckWellformedWithResult(f.Body, wfo, funcAppl, f.ResultType, locals, bodyCheckBuilder, etran);\n        if (f.Result != null) {\n          bodyCheckBuilder.Add(TrAssumeCmd(f.tok, Bpl.Expr.Eq(funcAppl, TrVar(f.tok, f.Result))));\n        }\n        wfo.ProcessSavedReadsChecks(locals, builderInitializationArea, bodyCheckBuilder);\n      }\n      // Combine the two, letting the postcondition be checked on after the \"bodyCheckBuilder\" branch\n      postCheckBuilder.Add(TrAssumeCmd(f.tok, Bpl.Expr.False));\n      builder.Add(new Bpl.IfCmd(f.tok, null, postCheckBuilder.Collect(f.tok), null, bodyCheckBuilder.Collect(f.tok)));\n\n      var s0 = builderInitializationArea.Collect(f.tok);\n      var s1 = builder.Collect(f.tok);\n      var implBody = new StmtList(new List<BigBlock>(s0.BigBlocks.Concat(s1.BigBlocks)), f.tok);\n\n      if (EmitImplementation(f.Attributes)) {\n        // emit the impl only when there are proof obligations.\n        QKeyValue kv = etran.TrAttributes(f.Attributes, null);\n        var impl = new Bpl.Implementation(f.tok, proc.Name,\n          new List<Bpl.TypeVariable>(), Concat(Concat(typeInParams, inParams_Heap), implInParams), implOutParams,\n          locals, implBody, kv);\n        sink.AddTopLevelDeclaration(impl);\n        if (InsertChecksums) {\n          InsertChecksum(f, impl);\n        }\n      }\n\n      Contract.Assert(currentModule == f.EnclosingClass.Module);\n      Contract.Assert(codeContext == f);\n      Reset();\n    }\n\n    void AddWellformednessCheck(RedirectingTypeDecl decl) {\n      Contract.Requires(decl != null);\n      Contract.Requires(sink != null && predef != null);\n      Contract.Requires(currentModule == null && codeContext == null && isAllocContext == null);\n      Contract.Ensures(currentModule == null && codeContext == null && isAllocContext == null);\n\n      if (!InVerificationScope(decl)) {\n        // Checked in other file\n        return;\n      }\n\n      // If there's no constraint, there's nothing to do\n      if (decl.Var == null) {\n        Contract.Assert(decl.Constraint == null);  // there's a constraint only if there's a variable to be constrained\n        Contract.Assert(decl.WitnessKind == SubsetTypeDecl.WKind.None);  // a witness makes sense only if there is a constraint\n        Contract.Assert(decl.Witness == null);  // a witness makes sense only if there is a constraint\n        return;\n      }\n      Contract.Assert(decl.Constraint != null);  // follows from the test above and the RedirectingTypeDecl class invariant\n\n      currentModule = decl.Module;\n      codeContext = decl;\n      var etran = new ExpressionTranslator(this, predef, decl.tok);\n\n      // parameters of the procedure\n      var inParams = MkTyParamFormals(decl.TypeArgs);\n      Bpl.Type varType = TrType(decl.Var.Type);\n      Bpl.Expr wh = GetWhereClause(decl.Var.tok, new Bpl.IdentifierExpr(decl.Var.tok, decl.Var.AssignUniqueName(decl.IdGenerator), varType), decl.Var.Type, etran, NOALLOC);\n      inParams.Add(new Bpl.Formal(decl.Var.tok, new Bpl.TypedIdent(decl.Var.tok, decl.Var.AssignUniqueName(decl.IdGenerator), varType, wh), true));\n\n      // the procedure itself\n      var req = new List<Bpl.Requires>();\n      // free requires mh == ModuleContextHeight && fh == TypeContextHeight;\n      req.Add(Requires(decl.tok, true, etran.HeightContext(decl), null, null));\n      // modifies $Heap, $Tick\n      var mod = new List<Bpl.IdentifierExpr> {\n        (Bpl.IdentifierExpr /*TODO: this cast is rather dubious*/)etran.HeapExpr,\n        etran.Tick()\n      };\n      var proc = new Bpl.Procedure(decl.tok, \"CheckWellformed$$\" + decl.FullSanitizedName, new List<Bpl.TypeVariable>(),\n        inParams, new List<Variable>(),\n        req, mod, new List<Bpl.Ensures>(), etran.TrAttributes(decl.Attributes, null));\n      sink.AddTopLevelDeclaration(proc);\n\n      // TODO: Can a checksum be inserted here?\n\n      Contract.Assert(proc.InParams.Count == inParams.Count);\n      // Changed the next line to strip from inParams instead of proc.InParams\n      // They should be the same, but hence the added contract\n      var implInParams = Bpl.Formal.StripWhereClauses(inParams);\n      var locals = new List<Variable>();\n      var builder = new BoogieStmtListBuilder(this);\n      builder.Add(new CommentCmd(string.Format(\"AddWellformednessCheck for {0} {1}\", decl.WhatKind, decl)));\n      builder.Add(CaptureState(decl.tok, false, \"initial state\"));\n      isAllocContext = new IsAllocContext(true);\n\n      DefineFrame(decl.tok, new List<FrameExpression>(), builder, locals, null);\n\n      // some initialization stuff;  // This is collected in builderInitializationArea\n      // define frame;\n      // if (*) {\n      //   // The following is collected in constraintCheckBuilder:\n      //   check constraint is well-formed;\n      //   assume constraint;\n      //   do reads checks;\n      // } else {\n      //   // The following is collected in witnessCheckBuilder:\n      //   check witness;\n      // }\n\n      // check well-formedness of the constraint (including termination, and delayed reads checks)\n      var constraintCheckBuilder = new BoogieStmtListBuilder(this);\n      var builderInitializationArea = new BoogieStmtListBuilder(this);\n      var wfo = new WFOptions(null, true, true /* do delayed reads checks */);\n      CheckWellformedAndAssume(decl.Constraint, wfo, locals, constraintCheckBuilder, etran);\n      wfo.ProcessSavedReadsChecks(locals, builderInitializationArea, constraintCheckBuilder);\n\n      // Check that the type is inhabited.\n      // Note, the possible witness in this check should be coordinated with the compiler, so the compiler knows how to do the initialization\n      Expression witnessExpr = null;\n      string witnessErrorMsg = null;\n      var witnessCheckBuilder = new BoogieStmtListBuilder(this);\n      if (decl.Witness != null) {\n        // check well-formedness of the witness expression (including termination, and reads checks)\n        CheckWellformed(decl.Witness, new WFOptions(null, true), locals, witnessCheckBuilder, etran);\n        // check that the witness is assignable to the type of the given bound variable\n        if (decl is SubsetTypeDecl) {\n          // Note, for new-types, this has already been checked by CheckWellformed.\n          CheckResultToBeInType(decl.Witness.tok, decl.Witness, decl.Var.Type, locals, witnessCheckBuilder, etran);\n        }\n        // check that the witness expression checks out\n        witnessExpr = Substitute(decl.Constraint, decl.Var, decl.Witness);\n        witnessErrorMsg = \"the given witness expression might not satisfy constraint\";\n      } else {\n        var witness = Zero(decl.tok, decl.Var.Type);\n        if (witness == null) {\n          witnessCheckBuilder.Add(Assert(decl.tok, Bpl.Expr.False, \"cannot find witness that shows type is inhabited; try giving a hint through a 'witness' or 'ghost witness' clause\"));\n        } else {\n          // before trying 0 as a witness, check that 0 can be assigned to decl.Var\n          CheckResultToBeInType(decl.tok, witness, decl.Var.Type, locals, witnessCheckBuilder, etran, string.Format(\"trying witness {0}: \", Printer.ExprToString(witness)));\n\n          witnessExpr = Substitute(decl.Constraint, decl.Var, witness);\n          witnessErrorMsg =\n            string.Format(\"cannot find witness that shows type is inhabited (only tried {0}); try giving a hint through a 'witness' or 'ghost witness' clause\",\n            Printer.ExprToString(witness));\n        }\n      }\n      if (witnessExpr != null) {\n        Contract.Assert(witnessErrorMsg != null);\n        var witnessCheckTok = decl.Witness != null ? decl.Witness.tok : decl.tok;\n        witnessCheckBuilder.Add(new Bpl.AssumeCmd(witnessCheckTok, CanCallAssumption(witnessExpr, etran)));\n        var witnessCheck = etran.TrExpr(witnessExpr);\n\n        bool splitHappened;\n        var ss = TrSplitExpr(witnessExpr, etran, true, out splitHappened);\n        if (!splitHappened) {\n          witnessCheckBuilder.Add(Assert(witnessCheckTok, etran.TrExpr(witnessExpr), witnessErrorMsg));\n        } else {\n          foreach (var split in ss) {\n            if (split.IsChecked) {\n              var tok = new NestedToken(witnessCheckTok, split.E.tok);\n              witnessCheckBuilder.Add(AssertNS(tok, split.E, witnessErrorMsg));\n            }\n          }\n        }\n      }\n\n      builder.Add(new Bpl.IfCmd(decl.tok, null, constraintCheckBuilder.Collect(decl.tok), null, witnessCheckBuilder.Collect(decl.tok)));\n\n      var s0 = builderInitializationArea.Collect(decl.tok);\n      var s1 = builder.Collect(decl.tok);\n      var implBody = new StmtList(new List<BigBlock>(s0.BigBlocks.Concat(s1.BigBlocks)), decl.tok);\n\n      if (EmitImplementation(decl.Attributes)) {\n        // emit the impl only when there are proof obligations.\n        QKeyValue kv = etran.TrAttributes(decl.Attributes, null);\n\n        var impl = new Bpl.Implementation(decl.tok, proc.Name,\n          new List<Bpl.TypeVariable>(), implInParams, new List<Variable>(),\n          locals, implBody, kv);\n        sink.AddTopLevelDeclaration(impl);\n      }\n\n      // TODO: Should a checksum be inserted here?\n\n      Contract.Assert(currentModule == decl.Module);\n      Contract.Assert(codeContext == decl);\n      isAllocContext = null;\n      Reset();\n    }\n\n    void AddWellformednessCheck(ConstantField decl) {\n      Contract.Requires(decl != null);\n      Contract.Requires(sink != null && predef != null);\n      Contract.Requires(currentModule == null && codeContext == null && isAllocContext == null && fuelContext == null);\n      Contract.Ensures(currentModule == null && codeContext == null && isAllocContext == null && fuelContext == null);\n\n      if (!InVerificationScope(decl)) {\n        // Checked in other file\n        return;\n      }\n\n      // If there's no RHS, there's nothing to do\n      if (decl.Rhs == null) {\n        return;\n      }\n\n      currentModule = decl.EnclosingModule;\n      codeContext = decl;\n      fuelContext = FuelSetting.NewFuelContext(decl);\n      var etran = new ExpressionTranslator(this, predef, decl.tok);\n\n      // parameters of the procedure\n      List<Variable> inParams = MkTyParamFormals(GetTypeParams(decl.EnclosingClass));\n      if (!decl.IsStatic) {\n        var receiverType = Resolver.GetThisType(decl.tok, (TopLevelDeclWithMembers)decl.EnclosingClass);\n        Contract.Assert(VisibleInScope(receiverType));\n\n        var th = new Bpl.IdentifierExpr(decl.tok, \"this\", TrReceiverType(decl));\n        var wh = Bpl.Expr.And(\n          ReceiverNotNull(th),\n          etran.GoodRef(decl.tok, th, receiverType));\n        // for class constructors, the receiver is encoded as an output parameter\n        var thVar = new Bpl.Formal(decl.tok, new Bpl.TypedIdent(decl.tok, \"this\", TrReceiverType(decl), wh), true);\n        inParams.Add(thVar);\n      }\n\n      // the procedure itself\n      var req = new List<Bpl.Requires>();\n      // free requires mh == ModuleContextHeight && fh == TypeContextHeight;\n      req.Add(Requires(decl.tok, true, etran.HeightContext(decl), null, null));\n      var proc = new Bpl.Procedure(decl.tok, \"CheckWellformed$$\" + decl.FullSanitizedName, new List<Bpl.TypeVariable>(),\n        inParams, new List<Variable>(),\n        req, new List<Bpl.IdentifierExpr>(), new List<Bpl.Ensures>(), etran.TrAttributes(decl.Attributes, null));\n      sink.AddTopLevelDeclaration(proc);\n\n      var implInParams = Bpl.Formal.StripWhereClauses(inParams);\n      var locals = new List<Variable>();\n      var builder = new BoogieStmtListBuilder(this);\n      builder.Add(new CommentCmd(string.Format(\"AddWellformednessCheck for {0} {1}\", decl.WhatKind, decl)));\n      builder.Add(CaptureState(decl.tok, false, \"initial state\"));\n      isAllocContext = new IsAllocContext(true);\n\n      DefineFrame(decl.tok, new List<FrameExpression>(), builder, locals, null);\n\n      // check well-formedness of the RHS expression\n      CheckWellformed(decl.Rhs, new WFOptions(null, true), locals, builder, etran);\n      builder.Add(new Bpl.AssumeCmd(decl.Rhs.tok, CanCallAssumption(decl.Rhs, etran)));\n      CheckSubrange(decl.Rhs.tok, etran.TrExpr(decl.Rhs), decl.Rhs.Type, decl.Type, builder);\n\n      if (EmitImplementation(decl.Attributes)) {\n        // emit the impl only when there are proof obligations.\n        QKeyValue kv = etran.TrAttributes(decl.Attributes, null);\n        var implBody = builder.Collect(decl.tok);\n        var impl = new Bpl.Implementation(decl.tok, proc.Name,\n          new List<Bpl.TypeVariable>(), implInParams, new List<Variable>(),\n          locals, implBody, kv);\n        sink.AddTopLevelDeclaration(impl);\n      }\n\n      Contract.Assert(currentModule == decl.EnclosingModule);\n      Contract.Assert(codeContext == decl);\n      isAllocContext = null;\n      fuelContext = null;\n      Reset();\n    }\n\n    /// <summary>\n    /// If \"declareLocals\" is \"false\", then the locals are added only if they are new, that is, if\n    /// they don't already exist in \"locals\".\n    /// </summary>\n    Bpl.Expr CtorInvocation(MatchCase mc, ExpressionTranslator etran, List<Variable> locals, BoogieStmtListBuilder localTypeAssumptions, IsAllocType isAlloc, bool declareLocals = true) {\n      Contract.Requires(mc != null);\n      Contract.Requires(etran != null);\n      Contract.Requires(locals != null);\n      Contract.Requires(localTypeAssumptions != null);\n      Contract.Requires(predef != null);\n      Contract.Ensures(Contract.Result<Bpl.Expr>() != null);\n\n      List<Bpl.Expr> args = new List<Bpl.Expr>();\n      for (int i = 0; i < mc.Arguments.Count; i++) {\n        BoundVar p = mc.Arguments[i];\n        var nm = p.AssignUniqueName(currentDeclaration.IdGenerator);\n        Bpl.Variable local = declareLocals ? null : locals.FirstOrDefault(v => v.Name == nm);  // find previous local\n        if (local == null) {\n          local = new Bpl.LocalVariable(p.tok, new Bpl.TypedIdent(p.tok, nm, TrType(p.Type)));\n          locals.Add(local);\n        } else {\n          Contract.Assert(Bpl.Type.Equals(local.TypedIdent.Type, TrType(p.Type)));\n        }\n        Type t = mc.Ctor.Formals[i].Type;\n        var pIsAlloc = (isAlloc == ISALLOC) ? isAllocContext.Var(p) : NOALLOC;\n        Bpl.Expr wh = GetWhereClause(p.tok, new Bpl.IdentifierExpr(p.tok, local), p.Type, etran, pIsAlloc);\n        if (wh != null) {\n          localTypeAssumptions.Add(TrAssumeCmd(p.tok, wh));\n        }\n        args.Add(CondApplyBox(mc.tok, new Bpl.IdentifierExpr(p.tok, local), cce.NonNull(p.Type), t));\n      }\n      Bpl.IdentifierExpr id = new Bpl.IdentifierExpr(mc.tok, mc.Ctor.FullName, predef.DatatypeType);\n      return new Bpl.NAryExpr(mc.tok, new Bpl.FunctionCall(id), args);\n    }\n\n    Bpl.Expr CtorInvocation(IToken tok, DatatypeCtor ctor, ExpressionTranslator etran, List<Variable> locals, BoogieStmtListBuilder localTypeAssumptions) {\n      Contract.Requires(tok != null);\n      Contract.Requires(ctor != null);\n      Contract.Requires(etran != null);\n      Contract.Requires(locals != null);\n      Contract.Requires(localTypeAssumptions != null);\n      Contract.Requires(predef != null);\n      Contract.Ensures(Contract.Result<Bpl.Expr>() != null);\n\n      // create local variables for the formals\n      var varNameGen = CurrentIdGenerator.NestedFreshIdGenerator(\"a#\");\n      var args = new List<Bpl.Expr>();\n      foreach (Formal arg in ctor.Formals) {\n        Contract.Assert(arg != null);\n        var nm = varNameGen.FreshId(string.Format(\"#{0}#\", args.Count));\n        Bpl.Variable bv = new Bpl.LocalVariable(arg.tok, new Bpl.TypedIdent(arg.tok, nm, TrType(arg.Type)));\n        locals.Add(bv);\n        args.Add(new Bpl.IdentifierExpr(arg.tok, bv));\n      }\n\n      Bpl.IdentifierExpr id = new Bpl.IdentifierExpr(tok, ctor.FullName, predef.DatatypeType);\n      return new Bpl.NAryExpr(tok, new Bpl.FunctionCall(id), args);\n    }\n\n    Bpl.Expr CanCallAssumption(Expression expr, ExpressionTranslator etran) {\n      Contract.Requires(expr != null);\n      Contract.Requires(etran != null);\n      Contract.Requires(predef != null);\n      Contract.Ensures(Contract.Result<Bpl.Expr>() != null);\n\n      if (expr is LiteralExpr || expr is ThisExpr || expr is MeExpr || expr is StoreBufferEmptyExpr || expr is TotalStateExpr || expr is IdentifierExpr || expr is WildcardExpr || expr is BoogieWrapper) {\n        return Bpl.Expr.True;\n      } else if (expr is DisplayExpression) {\n        DisplayExpression e = (DisplayExpression)expr;\n        return CanCallAssumption(e.Elements, etran);\n      } else if (expr is MapDisplayExpr) {\n        MapDisplayExpr e = (MapDisplayExpr)expr;\n        List<Expression> l = new List<Expression>();\n        foreach (ExpressionPair p in e.Elements) {\n          l.Add(p.A); l.Add(p.B);\n        }\n        return CanCallAssumption(l, etran);\n      } else if (expr is MemberSelectExpr) {\n        MemberSelectExpr e = (MemberSelectExpr)expr;\n        var r = CanCallAssumption(e.Obj, etran);\n        if (e.Member is DatatypeDestructor) {\n          var dtor = (DatatypeDestructor)e.Member;\n          if (dtor.EnclosingCtors.Count == dtor.EnclosingCtors[0].EnclosingDatatype.Ctors.Count) {\n            // Every constructor has this destructor; might as well assume that here.\n            var correctConstructor = BplOr(dtor.EnclosingCtors.ConvertAll(\n              ctor => FunctionCall(e.tok, ctor.QueryField.FullSanitizedName, Bpl.Type.Bool, etran.TrExpr(e.Obj))));\n            r = BplAnd(r, correctConstructor);\n          }\n        }\n        return r;\n      } else if (expr is SeqSelectExpr) {\n        SeqSelectExpr e = (SeqSelectExpr)expr;\n        Bpl.Expr total = CanCallAssumption(e.Seq, etran);\n        if (e.E0 != null) {\n          total = BplAnd(total, CanCallAssumption(e.E0, etran));\n        }\n        if (e.E1 != null) {\n          total = BplAnd(total, CanCallAssumption(e.E1, etran));\n        }\n        return total;\n      } else if (expr is MultiSelectExpr) {\n        MultiSelectExpr e = (MultiSelectExpr)expr;\n        Bpl.Expr total = CanCallAssumption(e.Array, etran);\n        foreach (Expression idx in e.Indices) {\n          total = BplAnd(total, CanCallAssumption(idx, etran));\n        }\n        return total;\n      } else if (expr is SeqUpdateExpr) {\n        SeqUpdateExpr e = (SeqUpdateExpr)expr;\n        if (e.ResolvedUpdateExpr != null)\n        {\n          return CanCallAssumption(e.ResolvedUpdateExpr, etran);\n        }\n        Bpl.Expr total = CanCallAssumption(e.Seq, etran);\n        total = BplAnd(total, CanCallAssumption(e.Index, etran));\n        total = BplAnd(total, CanCallAssumption(e.Value, etran));\n        return total;\n      } else if (expr is ApplyExpr) {\n        ApplyExpr e = (ApplyExpr)expr;\n        return BplAnd(\n          Cons(CanCallAssumption(e.Function, etran),\n          e.Args.ConvertAll(ee => CanCallAssumption(ee, etran))));\n      } else if (expr is FunctionCallExpr) {\n        FunctionCallExpr e = (FunctionCallExpr)expr;\n        Bpl.Expr r = CanCallAssumption(e.Receiver, etran);\n        r = BplAnd(r, CanCallAssumption(e.Args, etran));\n        if (!(e.Function is SpecialFunction)) {\n          // get to assume canCall\n          Bpl.IdentifierExpr canCallFuncID = new Bpl.IdentifierExpr(expr.tok, e.Function.FullSanitizedName + \"#canCall\", Bpl.Type.Bool);\n          List<Bpl.Expr> args = etran.FunctionInvocationArguments(e, null);\n          Bpl.Expr canCallFuncAppl = new Bpl.NAryExpr(expr.tok, new Bpl.FunctionCall(canCallFuncID), args);\n          r = BplAnd(r, canCallFuncAppl);\n        }\n        return r;\n      } else if (expr is DatatypeValue) {\n        DatatypeValue dtv = (DatatypeValue)expr;\n        return CanCallAssumption(dtv.Arguments, etran);\n      } else if (expr is SeqConstructionExpr) {\n        var e = (SeqConstructionExpr)expr;\n        return BplAnd(CanCallAssumption(e.N, etran), CanCallAssumption(e.Initializer, etran));\n      } else if (expr is MultiSetFormingExpr) {\n        MultiSetFormingExpr e = (MultiSetFormingExpr)expr;\n        return CanCallAssumption(e.E, etran);\n      } else if (expr is OldExpr) {\n        var e = (OldExpr)expr;\n        return CanCallAssumption(e.E, e.AtLabel == null ? etran.Old : etran.OldAt(e.AtLabel));\n      } else if (expr is UnchangedExpr) {\n        var e = (UnchangedExpr)expr;\n        Bpl.Expr be = Bpl.Expr.True;\n        foreach (var fe in e.Frame) {\n          be = BplAnd(be, CanCallAssumption(fe.E, etran));\n        }\n        return be;\n      } else if (expr is UnaryExpr) {\n        var e = (UnaryExpr)expr;\n        return CanCallAssumption(e.E, etran);\n      } else if (expr is BinaryExpr) {\n        BinaryExpr e = (BinaryExpr)expr;\n        Bpl.Expr t0 = CanCallAssumption(e.E0, etran);\n        Bpl.Expr t1 = CanCallAssumption(e.E1, etran);\n        Bpl.Expr antecedent;\n        switch (e.ResolvedOp) {\n          case BinaryExpr.ResolvedOpcode.And:\n          case BinaryExpr.ResolvedOpcode.Imp: {\n              var be = e.E0 as BinaryExpr;\n              if (be != null && (be.ResolvedOp == BinaryExpr.ResolvedOpcode.And ||\n                be.ResolvedOp == BinaryExpr.ResolvedOpcode.Imp ||\n                be.ResolvedOp == BinaryExpr.ResolvedOpcode.Or)) {\n                antecedent = BplAnd(CanCallAssumption(be.E1, etran), etran.TrExpr(be.E1));\n              } else {\n                antecedent = etran.TrExpr(e.E0);\n              }\n              t1 = BplImp(antecedent, t1);\n            }\n            break;\n          case BinaryExpr.ResolvedOpcode.Or: {\n              var be = e.E0 as BinaryExpr;\n              if (be != null && (be.ResolvedOp == BinaryExpr.ResolvedOpcode.And ||\n                be.ResolvedOp == BinaryExpr.ResolvedOpcode.Imp ||\n                be.ResolvedOp == BinaryExpr.ResolvedOpcode.Or)) {\n                antecedent = BplAnd(CanCallAssumption(be.E1, etran), Bpl.Expr.Not(etran.TrExpr(be.E1)));\n              } else {\n                antecedent = Bpl.Expr.Not(etran.TrExpr(e.E0));\n              }\n              t1 = BplImp(antecedent, t1);\n            }\n            break;\n          case BinaryExpr.ResolvedOpcode.EqCommon:\n          case BinaryExpr.ResolvedOpcode.NeqCommon: {\n              Bpl.Expr r = Bpl.Expr.True;\n              var dt = e.E0.Type.AsDatatype;\n              if (dt != null) {\n                var funcID = new Bpl.FunctionCall(new Bpl.IdentifierExpr(expr.tok, \"$IsA#\" + dt.FullSanitizedName, Bpl.Type.Bool));\n                if (!(e.E0.Resolved is DatatypeValue)) {\n                  r = BplAnd(r, new Bpl.NAryExpr(expr.tok, funcID, new List<Bpl.Expr> { etran.TrExpr(e.E0) }));\n                }\n                if (!(e.E1.Resolved is DatatypeValue)) {\n                  r = BplAnd(r, new Bpl.NAryExpr(expr.tok, funcID, new List<Bpl.Expr> { etran.TrExpr(e.E1) }));\n                }\n              }\n              return BplAnd(r, BplAnd(t0, t1));\n            }\n          case BinaryExpr.ResolvedOpcode.Mul:\n            if (7 <= ArmadaOptions.O.ArithMode) {\n              if (e.E0.Type.IsNumericBased(Type.NumericPersuation.Int) && !ArmadaOptions.O.DisableNLarith) {\n                // Produce a useful fact about the associativity of multiplication. It is a bit dicey to do as an axiom.\n                // Change (k*A)*B or (A*k)*B into (A*B)*k, where k is a numeric literal\n                var left = e.E0.Resolved as BinaryExpr;\n                if (left != null && left.ResolvedOp == BinaryExpr.ResolvedOpcode.Mul) {\n                  Bpl.Expr r = Bpl.Expr.True;\n                  if (left.E0.Resolved is LiteralExpr) {\n                    // (K*A)*B == (A*B)*k\n                    var y = Expression.CreateMul(Expression.CreateMul(left.E1, e.E1), left.E0);\n                    var eq = Expression.CreateEq(e, y, e.E0.Type);\n                    r = BplAnd(r, etran.TrExpr(eq));\n                  }\n                  if (left.E1.Resolved is LiteralExpr) {\n                    // (A*k)*B == (A*B)*k\n                    var y = Expression.CreateMul(Expression.CreateMul(left.E0, e.E1), left.E1);\n                    var eq = Expression.CreateEq(e, y, e.E0.Type);\n                    r = BplAnd(r, etran.TrExpr(eq));\n                  }\n                  if (r != Bpl.Expr.True) {\n                    return BplAnd(BplAnd(t0, t1), r);\n                  }\n                }\n              }\n            }\n            break;\n          // case BinaryExpr.ResolvedOpcode.EqCommon:\n          // case BinaryExpr.ResolvedOpcode.NeqCommon: {\n          //     Bpl.Expr r = Bpl.Expr.True;\n          //     var dt = e.E0.Type.AsDatatype;\n          //     if (dt != null) {\n          //       var funcID = new Bpl.FunctionCall(new Bpl.IdentifierExpr(expr.tok, \"$IsA#\" + dt.FullSanitizedName, Bpl.Type.Bool));\n          //       if (!(e.E0.Resolved is DatatypeValue)) {\n          //         r = BplAnd(r, new Bpl.NAryExpr(expr.tok, funcID, new List<Bpl.Expr> { etran.TrExpr(e.E0) }));\n          //       }\n          //       if (!(e.E1.Resolved is DatatypeValue)) {\n          //         r = BplAnd(r, new Bpl.NAryExpr(expr.tok, funcID, new List<Bpl.Expr> { etran.TrExpr(e.E1) }));\n          //       }\n          //     }\n          //     return BplAnd(r, BplAnd(t0, t1));\n          //   }\n          default:\n            break;\n        }\n        return BplAnd(t0, t1);\n      } else if (expr is TernaryExpr) {\n        var e = (TernaryExpr)expr;\n        return BplAnd(CanCallAssumption(e.E0, etran), BplAnd(CanCallAssumption(e.E1, etran), CanCallAssumption(e.E2, etran)));\n\n      } else if (expr is LetExpr) {\n        var e = (LetExpr)expr;\n        if (!e.Exact) {\n          // CanCall[[ var b0,b1 :| RHS(b0,b1,g); Body(b0,b1,g,h) ]] =\n          //   $let$canCall(g) &&\n          //   CanCall[[ Body($let$b0(g), $let$b1(g), h) ]]\n          LetDesugaring(e);  // call LetDesugaring to prepare the desugaring and populate letSuchThatExprInfo with something for e\n          var info = letSuchThatExprInfo[e];\n          // $let$canCall(g)\n          var canCall = info.CanCallFunctionCall(this, etran);\n          Dictionary<IVariable, Expression> substMap = new Dictionary<IVariable, Expression>();\n          foreach (var bv in e.BoundVars) {\n            // create a call to $let$x(g)\n            var args = info.SkolemFunctionArgs(bv, this, etran);\n            var call = new BoogieFunctionCall(bv.tok, info.SkolemFunctionName(bv), info.UsesHeap, info.UsesOldHeap, info.UsesHeapAt, args.Item1, args.Item2);\n            call.Type = bv.Type;\n            substMap.Add(bv, call);\n          }\n          var p = Substitute(e.Body, null, substMap);\n          var cc = BplAnd(canCall, CanCallAssumption(p, etran));\n          return cc;\n        } else {\n          // CanCall[[ var b := RHS(g); Body(b,g,h) ]] =\n          //   CanCall[[ RHS(g) ]] &&\n          //   (var lhs0,lhs1,... := rhs0,rhs1,...;  CanCall[[ Body ]])\n          Bpl.Expr canCallRHS = Bpl.Expr.True;\n          foreach (var rhs in e.RHSs) {\n            canCallRHS = BplAnd(canCallRHS, CanCallAssumption(rhs, etran));\n          }\n\n          var bodyCanCall = CanCallAssumption(e.Body, etran);\n          // We'd like to compute the free variables if \"bodyCanCall\". It would be nice to use the Boogie\n          // routine Bpl.Expr.ComputeFreeVariables for this purpose. However, calling it requires the Boogie\n          // expression to be resolved. Instead, we do the cheesy thing of computing the set of names of\n          // free variables in \"bodyCanCall\".\n          var vis = new VariableNameVisitor();\n          vis.Visit(bodyCanCall);\n\n          List<Bpl.Variable> lhssAll;\n          List<Bpl.Expr> rhssAll;\n          etran.TrLetExprPieces(e, out lhssAll, out rhssAll);\n          Contract.Assert(lhssAll.Count == rhssAll.Count);\n\n          // prune lhss,rhss to contain only those pairs where the LHS is used in the body\n          var lhssPruned = new List<Bpl.Variable>();\n          var rhssPruned = new List<Bpl.Expr>();\n          for (var i = 0; i < lhssAll.Count; i++) {\n            var bv = lhssAll[i];\n            if (vis.Names.Contains(bv.Name)) {\n              lhssPruned.Add(bv);\n              rhssPruned.Add(rhssAll[i]);\n            }\n          }\n          Bpl.Expr let = lhssPruned.Count == 0 ? bodyCanCall : new Bpl.LetExpr(e.tok, lhssPruned, rhssPruned, null, bodyCanCall);\n          return BplAnd(canCallRHS, let);\n        }\n\n      } else if (expr is NamedExpr) {\n        var e = (NamedExpr)expr;\n        var canCall = CanCallAssumption(e.Body, etran);\n        if (e.Contract != null)\n          return BplAnd(canCall, CanCallAssumption(e.Contract, etran));\n        else return canCall;\n\n      } else if (expr is LambdaExpr) {\n        var e = (LambdaExpr)expr;\n\n        var bvarsAndAntecedents = new List<Tuple<Bpl.Variable, Bpl.Expr>>();\n        var varNameGen = CurrentIdGenerator.NestedFreshIdGenerator(\"$l#\");\n\n        Bpl.Expr heap; var hVar = BplBoundVar(varNameGen.FreshId(\"#heap#\"), predef.HeapType, out heap);\n        var et = new ExpressionTranslator(etran, heap);\n\n        Dictionary<IVariable, Expression> subst = new Dictionary<IVariable, Expression>();\n        foreach (var bv in e.BoundVars) {\n          Bpl.Expr ve; var yVar = BplBoundVar(varNameGen.FreshId(string.Format(\"#{0}#\", bv.Name)), TrType(bv.Type), out ve);\n          var wh = GetWhereClause(bv.tok, new Bpl.IdentifierExpr(bv.tok, yVar), bv.Type, et, NOALLOC);\n          bvarsAndAntecedents.Add(Tuple.Create<Bpl.Variable, Bpl.Expr>(yVar, wh));\n          subst[bv] = new BoogieWrapper(ve, bv.Type);\n        }\n\n        var canCall = CanCallAssumption(Substitute(e.Body, null, subst), et);\n        if (e.Range != null) {\n          var range = Substitute(e.Range, null, subst);\n          canCall = BplAnd(CanCallAssumption(range, etran), BplImp(etran.TrExpr(range), canCall));\n        }\n\n        // It's important to add the heap last to \"bvarsAndAntecedents\", because the heap may occur in the antecedents of\n        // the other variables and BplForallTrim processes the given tuples in order.\n        var goodHeap = FunctionCall(e.tok, BuiltinFunction.IsGoodHeap, null, heap);\n        bvarsAndAntecedents.Add(Tuple.Create<Bpl.Variable, Bpl.Expr>(hVar, goodHeap));\n\n        //TRIG (forall $l#0#heap#0: Heap, $l#0#x#0: int :: true)\n        //TRIG (forall $l#0#heap#0: Heap, $l#0#t#0: DatatypeType :: _module.__default.TMap#canCall(_module._default.TMap$A, _module._default.TMap$B, $l#0#heap#0, $l#0#t#0, f#0))\n        //TRIG (forall $l#4#heap#0: Heap, $l#4#x#0: Box :: _0_Monad.__default.Bind#canCall(Monad._default.Associativity$B, Monad._default.Associativity$C, $l#4#heap#0, Apply1(Monad._default.Associativity$A, #$M$B, f#0, $l#4#heap#0, $l#4#x#0), g#0))\n        return BplForallTrim(bvarsAndAntecedents, null, canCall); // L_TRIGGER\n\n      } else if (expr is ComprehensionExpr) {\n        var e = (ComprehensionExpr)expr;\n        var q = e as QuantifierExpr;\n        if (q != null && q.SplitQuantifier != null) {\n          return CanCallAssumption(q.SplitQuantifierExpression, etran);\n        }\n\n        // Determine the CanCall's for the range and term\n        var canCall = CanCallAssumption(e.Term, etran);\n        if (e.Range != null) {\n          canCall = BplAnd(CanCallAssumption(e.Range, etran), BplImp(etran.TrExpr(e.Range), canCall));\n        }\n        if (expr is MapComprehension mc && mc.IsGeneralMapComprehension) {\n          canCall = BplAnd(canCall, CanCallAssumption(mc.TermLeft, etran));\n\n          // The translation of \"map x,y | R(x,y) :: F(x,y) := G(x,y)\" makes use of projection\n          // functions project_x,project_y.  These are functions defined here by the following axiom:\n          //     forall x,y :: R(x,y) ==> var x',y' := project_x(F(x,y)),project_y(F(x,y)); R(x',y') && F(x',y') == F(x,y)\n          // that is (without the let expression):\n          //     forall x,y :: R(x,y) ==> R(project_x(F(x,y)), project_y(F(x,y))) && F(project_x(F(x,y)), project_y(F(x,y))) == F(x,y)\n          // The triggers for the quantification are:\n          //     { project_x(F(x,y)) } { project_y(F(x,y)) }\n          List<Bpl.Variable> bvs;\n          List<Bpl.Expr> args;\n          CreateBoundVariables(mc.BoundVars, out bvs, out args);\n          Contract.Assert(mc.BoundVars.Count == bvs.Count);\n          CreateMapComprehensionProjectionFunctions(mc);\n          Contract.Assert(mc.ProjectionFunctions != null);\n          Contract.Assert(mc.ProjectionFunctions.Count == mc.BoundVars.Count);\n          var substMap = new Dictionary<IVariable, Expression>();\n          for (var i = 0; i < mc.BoundVars.Count; i++) {\n            substMap.Add(mc.BoundVars[i], new BoogieWrapper(args[i], mc.BoundVars[i].Type));\n          }\n          var R = etran.TrExpr(Substitute(mc.Range, null, substMap));\n          var F = etran.TrExpr(Substitute(mc.TermLeft, null, substMap));\n          substMap = new Dictionary<IVariable, Expression>();\n          Bpl.Trigger trig = null;\n          for (var i = 0; i < mc.BoundVars.Count; i++) {\n            var p = new Bpl.NAryExpr(mc.tok, new Bpl.FunctionCall(mc.ProjectionFunctions[i]), new List<Bpl.Expr> { F });\n            substMap.Add(e.BoundVars[i], new BoogieWrapper(p, e.BoundVars[i].Type));\n            trig = new Bpl.Trigger(mc.tok, true, new List<Bpl.Expr> { p }, trig);\n          }\n          var Rprime = etran.TrExpr(Substitute(mc.Range, null, substMap));\n          var Fprime = etran.TrExpr(Substitute(mc.TermLeft, null, substMap));\n          var defn = BplForall(bvs, trig, BplImp(R, BplAnd(Rprime, Bpl.Expr.Eq(F, Fprime))));\n          canCall = BplAnd(canCall, defn);\n        }\n        // Create a list of all possible bound variables\n        var bvarsAndAntecedents = etran.TrBoundVariables_SeparateWhereClauses(e.BoundVars);\n        if (q != null) {\n          var tyvars = MkTyParamBinders(q.TypeArgs);\n          foreach (var tv in tyvars) {\n            bvarsAndAntecedents.Add(Tuple.Create<Bpl.Variable, Bpl.Expr>(tv, null));\n          }\n        }\n        // Produce the quantified CanCall expression, with a suitably reduced set of bound variables\n        var tr = TrTrigger(etran, e.Attributes, expr.tok);\n        return BplForallTrim(bvarsAndAntecedents, tr, canCall);\n\n      } else if (expr is StmtExpr) {\n        var e = (StmtExpr)expr;\n        return CanCallAssumption(e.E, etran);\n      } else if (expr is ITEExpr) {\n        ITEExpr e = (ITEExpr)expr;\n        Bpl.Expr total = CanCallAssumption(e.Test, etran);\n        Bpl.Expr test = etran.TrExpr(e.Test);\n        total = BplAnd(total, BplImp(test, CanCallAssumption(e.Thn, etran)));\n        total = BplAnd(total, BplImp(Bpl.Expr.Not(test), CanCallAssumption(e.Els, etran)));\n        return total;\n      } else if (expr is ConcreteSyntaxExpression) {\n        var e = (ConcreteSyntaxExpression)expr;\n        return CanCallAssumption(e.ResolvedExpression, etran);\n      } else if (expr is RevealExpr) {\n        var e = (RevealExpr)expr;\n        return CanCallAssumption(e.ResolvedExpression, etran);\n      } else if (expr is BoogieFunctionCall) {\n        var e = (BoogieFunctionCall)expr;\n        return CanCallAssumption(e.Args, etran);\n      } else if (expr is MatchExpr) {\n        var e = (MatchExpr)expr;\n        var ite = etran.DesugarMatchExpr(e);\n        return CanCallAssumption(ite, etran);\n      } else if (expr is BoxingCastExpr) {\n        var e = (BoxingCastExpr)expr;\n        return CanCallAssumption(e.E, etran);\n      } else if (expr is UnboxingCastExpr) {\n        var e = (UnboxingCastExpr)expr;\n        return CanCallAssumption(e.E, etran);\n      } else {\n        Contract.Assert(false); throw new cce.UnreachableException();  // unexpected expression\n      }\n    }\n\n    void AddCasePatternVarSubstitutions(CasePattern<BoundVar> pat, Bpl.Expr rhs, Dictionary<IVariable, Expression> substMap) {\n      Contract.Requires(pat != null);\n      Contract.Requires(rhs != null);\n      Contract.Requires(substMap != null);\n      if (pat.Var != null) {\n        substMap.Add(pat.Var, new BoogieWrapper(rhs, pat.Var.Type));\n      } else if (pat.Arguments != null) {\n        Contract.Assert(pat.Ctor != null);  // follows from successful resolution\n        Contract.Assert(pat.Arguments.Count == pat.Ctor.Destructors.Count);  // follows from successful resolution\n        for (int i = 0; i < pat.Arguments.Count; i++) {\n          var arg = pat.Arguments[i];\n          var dtor = pat.Ctor.Destructors[i];\n          var r = new Bpl.NAryExpr(pat.tok, new Bpl.FunctionCall(GetReadonlyField(dtor)), new List<Bpl.Expr> { rhs });\n          var de = CondApplyUnbox(pat.tok, r, dtor.Type, arg.Expr.Type);\n          AddCasePatternVarSubstitutions(arg, de, substMap);\n        }\n      }\n    }\n\n    void CheckCasePatternShape<VT>(CasePattern<VT> pat, Bpl.Expr rhs, IToken rhsTok, Type rhsType, BoogieStmtListBuilder builder) where VT: IVariable {\n      Contract.Requires(pat != null);\n      Contract.Requires(rhs != null);\n      Contract.Requires(rhsTok != null);\n      Contract.Requires(rhsType != null);\n      Contract.Requires(builder != null);\n      if (pat.Var != null) {\n        CheckSubrange(rhsTok, rhs, rhsType, pat.Var.Type, builder);\n      } else if (pat.Arguments != null) {\n        Contract.Assert(pat.Ctor != null);  // follows from successful resolution\n        Contract.Assert(pat.Arguments.Count == pat.Ctor.Destructors.Count);  // follows from successful resolution\n        rhsType = rhsType.Normalize();\n        Contract.Assert(rhsType is UserDefinedType && ((UserDefinedType)rhsType).ResolvedClass != null);\n        var rhsTypeUdt = (UserDefinedType)rhsType;\n        var typeSubstMap = Resolver.TypeSubstitutionMap(rhsTypeUdt.ResolvedClass.TypeArgs, rhsTypeUdt.TypeArgs);\n        for (int i = 0; i < pat.Arguments.Count; i++) {\n          var arg = pat.Arguments[i];\n          var ctor = pat.Ctor;\n          var dtor = ctor.Destructors[i];\n          var correctConstructor = FunctionCall(pat.tok, ctor.QueryField.FullSanitizedName, Bpl.Type.Bool, rhs);\n          if (ctor.EnclosingDatatype.Ctors.Count == 1) {\n            // There is only one constructor, so the value must have been constructed by it; might as well assume that here.\n            builder.Add(TrAssumeCmd(pat.tok, correctConstructor));\n          } else {\n            builder.Add(Assert(pat.tok, correctConstructor, string.Format(\"RHS is not certain to look like the pattern '{0}'\", ctor.Name)));\n          }\n\n          var r = new Bpl.NAryExpr(arg.tok, new Bpl.FunctionCall(GetReadonlyField(dtor)), new List<Bpl.Expr> { rhs });\n          Type argType = Resolver.SubstType(dtor.Type, typeSubstMap);\n          var de = CondApplyUnbox(arg.tok, r, dtor.Type, argType);\n          CheckCasePatternShape(arg, de, arg.tok, argType, builder);\n        }\n      }\n    }\n\n    Bpl.Expr/*!*/ CanCallAssumption(List<Expression/*!*/>/*!*/ exprs, ExpressionTranslator/*!*/ etran) {\n      Contract.Requires(etran != null);\n      Contract.Requires(exprs != null);\n      Contract.Ensures(Contract.Result<Bpl.Expr>() != null);\n\n      Bpl.Expr total = Bpl.Expr.True;\n      foreach (Expression e in exprs) {\n        Contract.Assert(e != null);\n        total = BplAnd(total, CanCallAssumption(e, etran));\n      }\n      return total;\n    }\n\n    void CheckNonNull(IToken tok, Expression e, BoogieStmtListBuilder builder, ExpressionTranslator etran, Bpl.QKeyValue kv) {\n      Contract.Requires(tok != null);\n      Contract.Requires(e != null);\n      Contract.Requires(builder != null);\n      Contract.Requires(etran != null);\n      Contract.Requires(predef != null);\n\n      if (!e.Type.IsRefType) {\n        // nothing to do\n      } else if (e is ThisExpr) {\n        // already known to be non-null\n      } else if (e is StaticReceiverExpr) {\n        // also ok\n      } else {\n        builder.Add(Assert(tok, Bpl.Expr.Neq(etran.TrExpr(e), predef.Null), \"target object may be null\", kv));\n        if (!CommonHeapUse) {\n          builder.Add(Assert(tok, MkIsAlloc(etran.TrExpr(e), e.Type, etran.HeapExpr), \"target object may not be allocated\", kv));\n        }\n      }\n    }\n\n    /// <summary>\n    /// Instances of WFContext are used as an argument to CheckWellformed, supplying options for the\n    /// checks to be performed.\n    /// If \"SelfCallsAllowance\" is non-null, termination checks will be omitted for calls that look\n    /// like it.  This is useful in function postconditions, where the result of the function is\n    /// syntactically given as what looks like a recursive call with the same arguments.\n    /// \"DoReadsChecks\" indicates whether or not to perform reads checks.  If so, the generated code\n    /// will make references to $_Frame.  If \"saveReadsChecks\" is true, then the reads checks will\n    /// be recorded but postponsed.  In particular, CheckWellformed will append to .Locals a list of\n    /// fresh local variables and will append to .Assert assertions with appropriate error messages\n    /// that can be used later.  As a convenience, the ProcessSavedReadsChecks will make use of .Locals\n    /// and .Asserts (and AssignLocals) and update a given StmtListBuilder.\n    /// \"LValueContext\" indicates that the expression checked for well-formedness is an L-value of\n    /// some assignment.\n    /// </summary>\n    private class WFOptions\n    {\n      public readonly Function SelfCallsAllowance;\n      public readonly bool DoReadsChecks;\n      public readonly List<Bpl.Variable> Locals;\n      public readonly List<Bpl.Cmd> Asserts;\n      public readonly bool LValueContext;\n      public readonly Bpl.QKeyValue AssertKv;\n\n      public WFOptions() {\n      }\n\n      public WFOptions(Function selfCallsAllowance, bool doReadsChecks, bool saveReadsChecks = false) {\n        Contract.Requires(!saveReadsChecks || doReadsChecks);  // i.e., saveReadsChecks ==> doReadsChecks\n        SelfCallsAllowance = selfCallsAllowance;\n        DoReadsChecks = doReadsChecks;\n        if (saveReadsChecks) {\n          Locals = new List<Variable>();\n          Asserts = new List<Bpl.Cmd>();\n        }\n      }\n\n      public WFOptions(Bpl.QKeyValue kv) {\n        AssertKv = kv;\n      }\n\n      /// <summary>\n      /// This constructor clones the given \"options\", but turns off reads checks.  (I wish C# allowed\n      /// me to name the constructor something to indicate this semantics in its name.  Sigh.)\n      /// </summary>\n      public WFOptions(WFOptions options) {\n        Contract.Requires(options != null);\n        SelfCallsAllowance = options.SelfCallsAllowance;\n        DoReadsChecks = false;  // so just leave .Locals and .Asserts as null\n        LValueContext = options.LValueContext;\n        AssertKv = options.AssertKv;\n      }\n\n      /// <summary>\n      /// This constructor clones the given \"options\", but sets \"LValueContext\" to \"lValueContext\".\n      /// (I wish C# allowed me to name the constructor something to indicate this semantics in its name.  Sigh.)\n      /// </summary>\n      public WFOptions(bool lValueContext, WFOptions options) {\n        Contract.Requires(options != null);\n        SelfCallsAllowance = options.SelfCallsAllowance;\n        DoReadsChecks = options.DoReadsChecks;\n        Locals = options.Locals;\n        Asserts = options.Asserts;\n        LValueContext = lValueContext;\n        AssertKv = options.AssertKv;\n      }\n\n      public Action<IToken, Bpl.Expr, string, Bpl.QKeyValue> AssertSink(Translator tran, BoogieStmtListBuilder builder) {\n        return (t, e, s, qk) => {\n          if (Locals != null) {\n            var b = BplLocalVar(tran.CurrentIdGenerator.FreshId(\"b$reqreads#\"), Bpl.Type.Bool, Locals);\n            Asserts.Add(tran.Assert(t, b, s, qk));\n            builder.Add(Bpl.Cmd.SimpleAssign(e.tok, (Bpl.IdentifierExpr)b, e));\n          } else {\n            builder.Add(tran.Assert(t, e, s, qk));\n          }\n        };\n      }\n\n      public List<Bpl.AssignCmd> AssignLocals {\n        get {\n          return Map(Locals, l =>\n            Bpl.Cmd.SimpleAssign(l.tok,\n              new Bpl.IdentifierExpr(Token.NoToken, l),\n              Bpl.Expr.True)\n            );\n        }\n      }\n\n      public void ProcessSavedReadsChecks(List<Variable> locals, BoogieStmtListBuilder builderInitializationArea, BoogieStmtListBuilder builder) {\n        Contract.Requires(locals != null);\n        Contract.Requires(builderInitializationArea != null);\n        Contract.Requires(builder != null);\n        Contract.Requires(Locals != null && Asserts != null);  // ProcessSavedReadsChecks should be called only if the constructor was called with saveReadsChecks\n\n        // var b$reads_guards#0 : bool  ...\n        locals.AddRange(Locals);\n        // b$reads_guards#0 := true   ...\n        foreach (var cmd in AssignLocals) {\n          builderInitializationArea.Add(cmd);\n        }\n        // assert b$reads_guards#0;  ...\n        foreach (var a in Asserts) {\n          builder.Add(a);\n        }\n      }\n    }\n\n    void TrStmt_CheckWellformed(Expression expr, BoogieStmtListBuilder builder, List<Variable> locals, ExpressionTranslator etran, bool subsumption, bool lValueContext = false) {\n      Contract.Requires(expr != null);\n      Contract.Requires(builder != null);\n      Contract.Requires(locals != null);\n      Contract.Requires(etran != null);\n      Contract.Requires(predef != null);\n\n      Bpl.QKeyValue kv;\n      if (subsumption) {\n        kv = null;  // this is the default behavior of Boogie's assert\n      } else {\n        List<object> args = new List<object>();\n        // {:subsumption 0}\n        args.Add(Bpl.Expr.Literal(0));\n        kv = new Bpl.QKeyValue(expr.tok, \"subsumption\", args, null);\n      }\n      var options = new WFOptions(kv);\n      if (lValueContext) {\n        options = new WFOptions(true, options);\n      }\n      CheckWellformed(expr, options, locals, builder, etran);\n      builder.Add(TrAssumeCmd(expr.tok, CanCallAssumption(expr, etran)));\n    }\n\n    void CheckWellformedAndAssume(Expression expr, WFOptions options, List<Variable> locals, BoogieStmtListBuilder builder, ExpressionTranslator etran) {\n      Contract.Requires(expr != null);\n      Contract.Requires(expr.Type != null && expr.Type.IsBoolType);\n      Contract.Requires(options != null);\n      Contract.Requires(locals != null);\n      Contract.Requires(builder != null);\n      Contract.Requires(etran != null);\n      Contract.Requires(predef != null);\n      if (expr is BinaryExpr) {\n        var e = (BinaryExpr)expr;\n        switch (e.ResolvedOp) {\n          case BinaryExpr.ResolvedOpcode.And:\n            // WF[e0]; assume e0; WF[e1]; assume e1;\n            CheckWellformedAndAssume(e.E0, options, locals, builder, etran);\n            CheckWellformedAndAssume(e.E1, options, locals, builder, etran);\n            return;\n          case BinaryExpr.ResolvedOpcode.Imp: {\n              // if (*) {\n              //   WF[e0]; assume e0; WF[e1]; assume e1;\n              // } else {\n              //   assume e0 ==> e1;\n              // }\n              var bAnd = new BoogieStmtListBuilder(this);\n              CheckWellformedAndAssume(e.E0, options, locals, bAnd, etran);\n              CheckWellformedAndAssume(e.E1, options, locals, bAnd, etran);\n              var bImp = new BoogieStmtListBuilder(this);\n              bImp.Add(TrAssumeCmd(expr.tok, etran.TrExpr(expr)));\n              builder.Add(new Bpl.IfCmd(expr.tok, null, bAnd.Collect(expr.tok), null, bImp.Collect(expr.tok)));\n            }\n            return;\n          case BinaryExpr.ResolvedOpcode.Or: {\n              // if (*) {\n              //   WF[e0]; assume e0;\n              // } else {\n              //   assume !e0;\n              //   WF[e1]; assume e1;\n              // }\n              var b0 = new BoogieStmtListBuilder(this);\n              CheckWellformedAndAssume(e.E0, options, locals, b0, etran);\n              var b1 = new BoogieStmtListBuilder(this);\n              b1.Add(TrAssumeCmd(expr.tok, Bpl.Expr.Not(etran.TrExpr(e.E0))));\n              CheckWellformedAndAssume(e.E1, options, locals, b1, etran);\n              builder.Add(new Bpl.IfCmd(expr.tok, null, b0.Collect(expr.tok), null, b1.Collect(expr.tok)));\n            }\n            return;\n          default:\n            break;\n        }\n      } else if (expr is ITEExpr) {\n        var e = (ITEExpr)expr;\n        // if (*) {\n        //   WF[test]; assume test;\n        //   WF[thn]; assume thn;\n        // } else {\n        //   assume !test;\n        //   WF[els]; assume els;\n        // }\n        var bThn = new BoogieStmtListBuilder(this);\n        CheckWellformedAndAssume(e.Test, options, locals, bThn, etran);\n        CheckWellformedAndAssume(e.Thn, options, locals, bThn, etran);\n        var bEls = new BoogieStmtListBuilder(this);\n        bEls.Add(TrAssumeCmd(expr.tok, Bpl.Expr.Not(etran.TrExpr(e.Test))));\n        CheckWellformedAndAssume(e.Els, options, locals, bEls, etran);\n        builder.Add(new Bpl.IfCmd(expr.tok, null, bThn.Collect(expr.tok), null, bEls.Collect(expr.tok)));\n        return;\n      } else if (expr is QuantifierExpr) {\n        var e = (QuantifierExpr)expr;\n        // For (Q x :: body(x)), introduce fresh local variable x'.  Then:\n        //   havoc x'\n        //   WF[body(x')]; assume body(x');\n        // If the quantifier is universal, then continue as:\n        //   assume (\\forall x :: body(x));\n        // Create local variables corresponding to the type arguments:\n\n        var typeArgumentCopies = Map(e.TypeArgs, tp => e.Refresh(tp, CurrentIdGenerator));\n        var typeMap = Util.Dict(e.TypeArgs, Map(typeArgumentCopies, tp => (Type)new UserDefinedType(tp)));\n        var newLocals = Map(typeArgumentCopies, tp => new Bpl.LocalVariable(tp.tok, new TypedIdent(tp.tok, nameTypeParam(tp), predef.Ty)));\n        locals.AddRange(newLocals);\n        // Create local variables corresponding to the bound variables:\n        var substMap = SetupBoundVarsAsLocals(e.BoundVars, builder, locals, etran, typeMap);\n        // Get the body of the quantifier and suitably substitute for the type variables and bound variables\n        var body = Substitute(e.LogicalBody(true), null, substMap, typeMap);\n        CheckWellformedAndAssume(body, options, locals, builder, etran);\n\n        if (e is ForallExpr) {\n          // Although we do the WF check on the original quantifier, we assume the split one.\n          // This ensures that cases like forall x :: x != null && f(x.a) do not fail to verify.\n          builder.Add(TrAssumeCmd(expr.tok, etran.TrExpr(e.SplitQuantifierExpression ?? e)));\n        }\n        return;\n      }\n\n      // resort to the behavior of simply checking well-formedness followed by assuming the translated expression\n      CheckWellformed(expr, options, locals, builder, etran);\n\n      // NOTE: If the CheckWellformed call above found a split quantifier, it ignored\n      //       the splitting and proceeded to decompose the full quantifier as\n      //       normal. This call to TrExpr, on the other hand, will indeed use the\n      //       split quantifier.\n      builder.Add(TrAssumeCmd(expr.tok, etran.TrExpr(expr)));\n    }\n\n    /// <summary>\n    /// Check the well-formedness of \"expr\" (but don't leave around any assumptions that affect control flow)\n    /// </summary>\n    void CheckWellformed(Expression expr, WFOptions options, List<Variable> locals, BoogieStmtListBuilder builder, ExpressionTranslator etran) {\n      Contract.Requires(expr != null);\n      Contract.Requires(options != null);\n      Contract.Requires(locals != null);\n      Contract.Requires(builder != null);\n      Contract.Requires(etran != null);\n      Contract.Requires(predef != null);\n      CheckWellformedWithResult(expr, options, null, null, locals, builder, etran);\n    }\n\n    /// <summary>\n    /// Adds to \"builder\" code that checks the well-formedness of \"expr\".  Any local variables introduced\n    /// in this code are added to \"locals\".\n    /// If \"result\" is non-null, then after checking the well-formedness of \"expr\", the generated code will\n    /// assume the equivalent of \"result == expr\".\n    /// See class WFOptions for descriptions of the specified options.\n    /// </summary>\n    void CheckWellformedWithResult(Expression expr, WFOptions options, Bpl.Expr result, Type resultType,\n                                   List<Bpl.Variable> locals, BoogieStmtListBuilder builder, ExpressionTranslator etran) {\n      Contract.Requires(expr != null);\n      Contract.Requires(options != null);\n      Contract.Requires((result == null) == (resultType == null));\n      Contract.Requires(locals != null);\n      Contract.Requires(builder != null);\n      Contract.Requires(etran != null);\n      Contract.Requires(predef != null);\n\n      var origOptions = options;\n      if (options.LValueContext) {\n        // Turn off LValueContext for any recursive call\n        options = new WFOptions(false, options);\n      }\n\n      if (expr is StaticReceiverExpr) {\n        // yeah, it's okay\n      } else if (expr is LiteralExpr) {\n        CheckResultToBeInType(expr.tok, expr, expr.Type, locals, builder, etran);\n      } else if (expr is ThisExpr || expr is MeExpr || expr is StoreBufferEmptyExpr || expr is TotalStateExpr || expr is IfUndefinedExpr || expr is WildcardExpr || expr is BoogieWrapper) {\n        // always allowed\n      } else if (expr is IdentifierExpr) {\n        var e = (IdentifierExpr)expr;\n        if (!origOptions.LValueContext) {\n          CheckDefiniteAssignment(e, builder);\n        }\n      } else if (expr is DisplayExpression) {\n        DisplayExpression e = (DisplayExpression)expr;\n        Contract.Assert(e.Type is CollectionType);\n        var elementType = ((CollectionType)e.Type).Arg;\n        foreach (Expression el in e.Elements) {\n          CheckWellformed(el, options, locals, builder, etran);\n          CheckSubrange(el.tok, etran.TrExpr(el), el.Type, elementType, builder);\n        }\n      } else if (expr is MapDisplayExpr) {\n        MapDisplayExpr e = (MapDisplayExpr)expr;\n        Contract.Assert(e.Type is MapType);\n        var keyType = ((MapType)e.Type).Domain;\n        var valType = ((MapType)e.Type).Range;\n        foreach (ExpressionPair p in e.Elements) {\n          CheckWellformed(p.A, options, locals, builder, etran);\n          CheckSubrange(p.A.tok, etran.TrExpr(p.A), p.A.Type, keyType, builder);\n          CheckWellformed(p.B, options, locals, builder, etran);\n          CheckSubrange(p.B.tok, etran.TrExpr(p.B), p.B.Type, valType, builder);\n        }\n      } else if (expr is MemberSelectExpr) {\n        MemberSelectExpr e = (MemberSelectExpr)expr;\n        CheckFunctionSelectWF(\"naked function\", builder, etran, e, \" Possible solution: eta expansion.\");\n        CheckWellformed(e.Obj, options, locals, builder, etran);\n        if (e.Obj.Type.IsRefType) {\n          if (inBodyInitContext && Expression.AsThis(e.Obj) != null && !e.Member.IsInstanceIndependentConstant) {\n            // this uses the surrogate local\n            if (!origOptions.LValueContext) {\n              CheckDefiniteAssignmentSurrogate(expr.tok, (Field)e.Member, false, builder);\n            }\n          } else {\n            CheckNonNull(expr.tok, e.Obj, builder, etran, options.AssertKv);\n            // Check that the receiver is available in the state in which the dereference occurs\n            if (etran.UsesOldHeap) {\n              Bpl.Expr wh = GetWhereClause(expr.tok, etran.TrExpr(e.Obj), e.Obj.Type, etran, ISALLOC, true);\n              if (wh != null) {\n                builder.Add(Assert(expr.tok, wh, \"receiver must be allocated in the state in which its fields are accessed\"));\n              }\n            }\n          }\n        } else if (e.Member is DatatypeDestructor) {\n          var dtor = (DatatypeDestructor)e.Member;\n          var correctConstructor = BplOr(dtor.EnclosingCtors.ConvertAll(\n            ctor => FunctionCall(e.tok, ctor.QueryField.FullSanitizedName, Bpl.Type.Bool, etran.TrExpr(e.Obj))));\n          if (dtor.EnclosingCtors.Count == dtor.EnclosingCtors[0].EnclosingDatatype.Ctors.Count) {\n            // Every constructor has this destructor; might as well assume that here.\n            builder.Add(TrAssumeCmd(expr.tok, correctConstructor));\n          } else {\n            builder.Add(Assert(expr.tok, correctConstructor,\n              string.Format(\"destructor '{0}' can only be applied to datatype values constructed by {1}\", dtor.Name, dtor.EnclosingCtorNames(\"or\"))));\n          }\n        }\n        if (options.DoReadsChecks && e.Member is Field && ((Field)e.Member).IsMutable) {\n          options.AssertSink(this, builder)(expr.tok, Bpl.Expr.SelectTok(expr.tok, etran.TheFrame(expr.tok), etran.TrExpr(e.Obj), GetField(e)), \"insufficient reads clause to read field\", options.AssertKv);\n        }\n      } else if (expr is SeqSelectExpr) {\n        SeqSelectExpr e = (SeqSelectExpr)expr;\n        var eSeqType = e.Seq.Type.NormalizeExpand();\n        bool isSequence = eSeqType is SeqType;\n        CheckWellformed(e.Seq, options, locals, builder, etran);\n        Bpl.Expr seq = etran.TrExpr(e.Seq);\n        if (eSeqType.IsArrayType) {\n          builder.Add(Assert(e.Seq.tok, Bpl.Expr.Neq(seq, predef.Null), \"array may be null\"));\n          if (!CommonHeapUse) {\n            builder.Add(Assert(e.Seq.tok, MkIsAlloc(seq, eSeqType, etran.HeapExpr), \"array may not be allocated\"));\n          }\n        }\n        Bpl.Expr e0 = null;\n        if (eSeqType is MapType) {\n          bool finite = ((MapType)eSeqType).Finite;\n          e0 = etran.TrExpr(e.E0);\n          CheckWellformed(e.E0, options, locals, builder, etran);\n          var f = finite ? BuiltinFunction.MapDomain : BuiltinFunction.IMapDomain;\n          Bpl.Expr inDomain = FunctionCall(expr.tok, f, predef.MapType(e.tok, finite, predef.BoxType, predef.BoxType), seq);\n          inDomain = Bpl.Expr.Select(inDomain, BoxIfNecessary(e.tok, e0, e.E0.Type));\n          builder.Add(Assert(expr.tok, inDomain, \"element may not be in domain\", options.AssertKv));\n        } else if (eSeqType is MultiSetType) {\n          // cool\n\n        } else {\n          if (e.E0 != null) {\n            e0 = etran.TrExpr(e.E0);\n            CheckWellformed(e.E0, options, locals, builder, etran);\n            builder.Add(Assert(expr.tok, InSeqRange(expr.tok, e0, e.E0.Type, seq, isSequence, null, !e.SelectOne), e.SelectOne ? \"index out of range\" : \"lower bound out of range\", options.AssertKv));\n          }\n          if (e.E1 != null) {\n            CheckWellformed(e.E1, options, locals, builder, etran);\n            Bpl.Expr lowerBound;\n            if (e0 != null && e.E0.Type.IsBitVectorType) {\n              lowerBound = ConvertExpression(e.E0.tok, e0, e.E0.Type, Type.Int);\n            } else {\n              lowerBound = e0;\n            }\n            builder.Add(Assert(expr.tok, InSeqRange(expr.tok, etran.TrExpr(e.E1), e.E1.Type, seq, isSequence, lowerBound, true), \"upper bound \" + (e.E0 == null ? \"\" : \"below lower bound or \") + \"above length of \" + (isSequence ? \"sequence\" : \"array\"), options.AssertKv));\n          }\n        }\n        if (options.DoReadsChecks && eSeqType.IsArrayType) {\n          if (e.SelectOne) {\n            Contract.Assert(e.E0 != null);\n            Bpl.Expr fieldName = FunctionCall(expr.tok, BuiltinFunction.IndexField, null, etran.TrExpr(e.E0));\n            options.AssertSink(this, builder)(expr.tok, Bpl.Expr.SelectTok(expr.tok, etran.TheFrame(expr.tok), seq, fieldName), \"insufficient reads clause to read array element\", options.AssertKv);\n          } else {\n            Bpl.Expr lowerBound = e.E0 == null ? Bpl.Expr.Literal(0) : etran.TrExpr(e.E0);\n            Contract.Assert(eSeqType.AsArrayType.Dims == 1);\n            Bpl.Expr upperBound = e.E1 == null ? ArrayLength(e.tok, seq, 1, 0) : etran.TrExpr(e.E1);\n            // check that, for all i in lowerBound..upperBound, a[i] is in the frame\n            Bpl.BoundVariable iVar = new Bpl.BoundVariable(e.tok, new Bpl.TypedIdent(e.tok, \"$i\", Bpl.Type.Int));\n            Bpl.IdentifierExpr i = new Bpl.IdentifierExpr(e.tok, iVar);\n            var range = BplAnd(Bpl.Expr.Le(lowerBound, i), Bpl.Expr.Lt(i, upperBound));\n            var fieldName = FunctionCall(e.tok, BuiltinFunction.IndexField, null, i);\n            var allowedToRead = Bpl.Expr.SelectTok(e.tok, etran.TheFrame(e.tok), seq, fieldName);\n            var trigger = BplTrigger(allowedToRead); // Note, the assertion we're about to produce only seems useful in the check-only mode (that is, with subsumption 0), but if it were to be assumed, we'll use this entire RHS as the trigger\n            var qq = new Bpl.ForallExpr(e.tok, new List<Variable> { iVar }, trigger, BplImp(range, allowedToRead));\n            options.AssertSink(this, builder)(expr.tok, qq, \"insufficient reads clause to read the indicated range of array elements\", options.AssertKv);\n          }\n        }\n      } else if (expr is MultiSelectExpr) {\n        MultiSelectExpr e = (MultiSelectExpr)expr;\n        CheckWellformed(e.Array, options, locals, builder, etran);\n        Bpl.Expr array = etran.TrExpr(e.Array);\n        for (int idxId = 0; idxId < e.Indices.Count; idxId++) {\n          var idx = e.Indices[idxId];\n          CheckWellformed(idx, options, locals, builder, etran);\n\n          var index = etran.TrExpr(idx);\n          var lower = Bpl.Expr.Le(Bpl.Expr.Literal(0), index);\n          var length = ArrayLength(idx.tok, array, e.Indices.Count, idxId);\n          var upper = Bpl.Expr.Lt(index, length);\n          var tok = idx is IdentifierExpr ? e.tok : idx.tok; // TODO: Reusing the token of an identifier expression would underline its definition. but this is still not perfect.\n\n          builder.Add(Assert(tok, Bpl.Expr.And(lower, upper), String.Format(\"index {0} out of range\", idxId), options.AssertKv));\n        }\n        if (options.DoReadsChecks) {\n          Bpl.Expr fieldName = etran.GetArrayIndexFieldName(e.tok, e.Indices);\n          options.AssertSink(this, builder)(expr.tok, Bpl.Expr.SelectTok(expr.tok, etran.TheFrame(expr.tok), array, fieldName), \"insufficient reads clause to read array element\", options.AssertKv);\n        }\n      } else if (expr is SeqUpdateExpr) {\n        SeqUpdateExpr e = (SeqUpdateExpr)expr;\n        if (e.ResolvedUpdateExpr != null) {\n          CheckWellformedWithResult(e.ResolvedUpdateExpr, options, result, resultType, locals, builder, etran);\n        } else {\n          CheckWellformed(e.Seq, options, locals, builder, etran);\n          Bpl.Expr seq = etran.TrExpr(e.Seq);\n          Bpl.Expr index = etran.TrExpr(e.Index);\n          Bpl.Expr value = etran.TrExpr(e.Value);\n          CheckWellformed(e.Index, options, locals, builder, etran);\n          var eSeqType = e.Seq.Type.NormalizeExpand();\n          if (eSeqType is SeqType) {\n            builder.Add(Assert(expr.tok, InSeqRange(expr.tok, index, e.Index.Type, seq, true, null, false), \"index out of range\", options.AssertKv));\n          } else if (eSeqType is MapType) {\n            // updates to maps are always valid if the values are well formed\n          } else if (eSeqType is MultiSetType) {\n            builder.Add(Assert(expr.tok, Bpl.Expr.Le(Bpl.Expr.Literal(0), value), \"new number of occurrences might be negative\", options.AssertKv));\n          } else {\n            Contract.Assert(false);\n          }\n          CheckWellformed(e.Value, options, locals, builder, etran);\n        }\n      } else if (expr is ApplyExpr) {\n        var e = (ApplyExpr)expr;\n        int arity = e.Args.Count;\n        var tt = e.Function.Type.AsArrowType;\n        Contract.Assert(tt != null);\n        Contract.Assert(tt.Arity == arity);\n\n        // check WF of receiver and arguments\n        CheckWellformed(e.Function, options, locals, builder, etran);\n        foreach (Expression arg in e.Args) {\n          CheckWellformed(arg, options, locals, builder, etran);\n        }\n\n        // check subranges of arguments\n        for (int i = 0; i < arity; ++i) {\n          CheckSubrange(e.Args[i].tok, etran.TrExpr(e.Args[i]), e.Args[i].Type, tt.Args[i], builder);\n        }\n\n        // check parameter availability\n        if (etran.UsesOldHeap) {\n          Bpl.Expr wh = GetWhereClause(e.Function.tok, etran.TrExpr(e.Function), e.Function.Type, etran, ISALLOC, true);\n          if (wh != null) {\n            builder.Add(Assert(e.Function.tok, wh, \"function must be allocated in the state in which the function is invoked\"));\n          }\n          for (int i = 0; i < e.Args.Count; i++) {\n            Expression ee = e.Args[i];\n            wh = GetWhereClause(ee.tok, etran.TrExpr(ee), ee.Type, etran, ISALLOC, true);\n            if (wh != null) {\n              builder.Add(Assert(ee.tok, wh, \"argument must be allocated in the state in which the function is invoked\"));\n            }\n          }\n        }\n\n        // translate arguments to requires and reads\n        Func<Expression, Bpl.Expr> TrArg = arg => {\n          Bpl.Expr inner = etran.TrExpr(arg);\n          if (ModeledAsBoxType(arg.Type)) {\n            return inner;\n          } else {\n            return FunctionCall(arg.tok, BuiltinFunction.Box, null, inner);\n          }\n        };\n\n        var args = Concat(\n          Map(tt.TypeArgs, TypeToTy),\n          Cons(etran.HeapExpr,\n          Cons(etran.TrExpr(e.Function),\n          e.Args.ConvertAll(arg => TrArg(arg)))));\n\n        // Because type inference often gravitates towards inferring non-constrained types, we'll\n        // do some digging on our own to see if we can discover a more precise type.\n        var fnCore = e.Function;\n        while (true) {\n          var prevCore = fnCore;\n          fnCore = Expression.StripParens(fnCore.Resolved);\n          if (object.ReferenceEquals(fnCore, prevCore)) {\n            break;  // we've done what we can do\n          }\n        }\n        Type fnCoreType;\n        if (fnCore is IdentifierExpr) {\n          var v = (IdentifierExpr)fnCore;\n          fnCoreType = v.Var.Type;\n        } else if (fnCore is MemberSelectExpr) {\n          var m = (MemberSelectExpr)fnCore;\n          fnCoreType = m.Member is Field ? ((Field)m.Member).Type : ((Function)m.Member).Type;\n        } else {\n          fnCoreType = fnCore.Type;\n        }\n\n        if (!fnCoreType.IsArrowTypeWithoutPreconditions) {\n          // check precond\n          var precond = FunctionCall(e.tok, Requires(arity), Bpl.Type.Bool, args);\n          builder.Add(Assert(expr.tok, precond, \"possible violation of function precondition\"));\n        }\n\n        if (options.DoReadsChecks && !fnCoreType.IsArrowTypeWithoutReadEffects) {\n          // check read effects\n          Type objset = new SetType(true, program.BuiltIns.ObjectQ());\n          Expression wrap = new BoogieWrapper(\n            FunctionCall(e.tok, Reads(arity), TrType(objset), args),\n            objset);\n          var reads = new FrameExpression(e.tok, wrap, null);\n          CheckFrameSubset(expr.tok, new List<FrameExpression> { reads }, null, null,\n            etran, options.AssertSink(this, builder), \"insufficient reads clause to invoke function\", options.AssertKv);\n        }\n\n      } else if (expr is FunctionCallExpr) {\n        FunctionCallExpr e = (FunctionCallExpr)expr;\n        Contract.Assert(e.Function != null);  // follows from the fact that expr has been successfully resolved\n        if (e.Function is SpecialFunction) {\n          CheckWellformedSpecialFunction(e, options, null, null, locals, builder, etran);\n        } else {\n          // check well-formedness of receiver\n          CheckWellformed(e.Receiver, options, locals, builder, etran);\n          if (!e.Function.IsStatic && !(e.Receiver is ThisExpr) && !e.Receiver.Type.IsArrowType) {\n            CheckNonNull(expr.tok, e.Receiver, builder, etran, options.AssertKv);\n          } else if (e.Receiver.Type.IsArrowType) {\n            CheckFunctionSelectWF(\"function specification\", builder, etran, e.Receiver, \"\");\n          }\n          // check well-formedness of the other parameters\n          foreach (Expression arg in e.Args) {\n            CheckWellformed(arg, options, locals, builder, etran);\n          }\n          // create a local variable for each formal parameter, and assign each actual parameter to the corresponding local\n          Dictionary<IVariable, Expression> substMap = new Dictionary<IVariable, Expression>();\n          for (int i = 0; i < e.Function.Formals.Count; i++) {\n            Formal p = e.Function.Formals[i];\n            // Note, in the following, the \"##\" makes the variable invisible in BVD.  An alternative would be to communicate\n            // to BVD what this variable stands for and display it as such to the user.\n            Type et = Resolver.SubstType(p.Type, e.TypeArgumentSubstitutions);\n            LocalVariable local = new LocalVariable(p.tok, p.tok, \"##\" + p.Name, et, p.IsGhost, false);\n            local.type = local.OptionalType;  // resolve local here\n            IdentifierExpr ie = new IdentifierExpr(local.Tok, local.AssignUniqueName(currentDeclaration.IdGenerator));\n            ie.Var = local; ie.Type = ie.Var.Type;  // resolve ie here\n            substMap.Add(p, ie);\n            locals.Add(new Bpl.LocalVariable(local.Tok, new Bpl.TypedIdent(local.Tok, local.AssignUniqueName(currentDeclaration.IdGenerator), TrType(local.Type))));\n            Bpl.IdentifierExpr lhs = (Bpl.IdentifierExpr)etran.TrExpr(ie);  // TODO: is this cast always justified?\n            Expression ee = e.Args[i];\n            CheckSubrange(ee.tok, etran.TrExpr(ee), ee.Type, et, builder);\n            Bpl.Cmd cmd = Bpl.Cmd.SimpleAssign(p.tok, lhs, CondApplyBox(p.tok, etran.TrExpr(ee), cce.NonNull(ee.Type), et));\n            builder.Add(cmd);\n            if (CommonHeapUse && !etran.UsesOldHeap) {\n              // the argument can't be assumed to be allocated for the old heap\n              builder.Add(new Bpl.CommentCmd(\"assume allocatedness for argument to function\"));\n              builder.Add(TrAssumeCmd(e.Args[i].tok, MkIsAlloc(lhs, et, etran.HeapExpr)));\n            }\n          }\n\n          // Check that every parameter is available in the state in which the function is invoked; this means checking that it has\n          // the right type and is allocated.  These checks usually hold trivially, on account of that the Dafny language only gives\n          // access to expressions of the appropriate type and that are allocated in the current state.  However, if the function is\n          // invoked in the 'old' state or if the function invoked is a two-state function with a non-new parameter, then we need to\n          // check that its arguments were all available at that time as well.\n          if (etran.UsesOldHeap) {\n            if (!e.Function.IsStatic) {\n              Bpl.Expr wh = GetWhereClause(e.Receiver.tok, etran.TrExpr(e.Receiver), e.Receiver.Type, etran, ISALLOC, true);\n              if (wh != null) {\n                builder.Add(Assert(e.Receiver.tok, wh, \"receiver argument must be allocated in the state in which the function is invoked\"));\n              }\n            }\n            for (int i = 0; i < e.Args.Count; i++) {\n              Expression ee = e.Args[i];\n              Bpl.Expr wh = GetWhereClause(ee.tok, etran.TrExpr(ee), ee.Type, etran, ISALLOC, true);\n              if (wh != null) {\n                builder.Add(Assert(ee.tok, wh, \"argument must be allocated in the state in which the function is invoked\"));\n              }\n            }\n          } else if (e.Function is TwoStateFunction) {\n            if (!e.Function.IsStatic) {\n              Bpl.Expr wh = GetWhereClause(e.Receiver.tok, etran.TrExpr(e.Receiver), e.Receiver.Type, etran.Old, ISALLOC, true);\n              if (wh != null) {\n                builder.Add(Assert(e.Receiver.tok, wh, \"receiver argument must be allocated in the two-state functions's previous state\"));\n              }\n            }\n            Contract.Assert(e.Function.Formals.Count == e.Args.Count);\n            for (int i = 0; i < e.Args.Count; i++) {\n              var formal = e.Function.Formals[i];\n              if (formal.IsOld) {\n                Expression ee = e.Args[i];\n                Bpl.Expr wh = GetWhereClause(ee.tok, etran.TrExpr(ee), ee.Type, etran.Old, ISALLOC, true);\n                if (wh != null) {\n                  builder.Add(Assert(ee.tok, wh, string.Format(\"argument{0} ('{1}') must be allocated in the two-state function's previous state\",\n                    e.Args.Count == 1 ? \"\" : \" \" + i, formal.Name)));\n                }\n              }\n            }\n          }\n          // check that the preconditions for the call hold\n          foreach (MaybeFreeExpression p in e.Function.Req) {\n            Expression precond = Substitute(p.E, e.Receiver, substMap, e.TypeArgumentSubstitutions);\n            bool splitHappened;  // we don't actually care\n            string errorMessage = CustomErrorMessage(p.Attributes);\n            foreach (var ss in TrSplitExpr(precond, etran, true, out splitHappened)) {\n              if (ss.IsChecked) {\n                var tok = new NestedToken(expr.tok, ss.E.tok);\n                if (options.AssertKv != null) {\n                  // use the given assert attribute only\n                  builder.Add(Assert(tok, ss.E, errorMessage ?? \"possible violation of function precondition\", options.AssertKv));\n                } else {\n                  builder.Add(AssertNS(tok, ss.E, errorMessage ?? \"possible violation of function precondition\"));\n                }\n              }\n            }\n            if (options.AssertKv == null) {\n              // assume only if no given assert attribute is given\n              builder.Add(TrAssumeCmd(expr.tok, etran.TrExpr(precond)));\n            }\n          }\n          if (options.DoReadsChecks) {\n            // check that the callee reads only what the caller is already allowed to read\n            var s = new Substituter(null, new Dictionary<IVariable, Expression>(), e.TypeArgumentSubstitutions);\n            CheckFrameSubset(expr.tok,\n              e.Function.Reads.ConvertAll(s.SubstFrameExpr),\n              e.Receiver, substMap, etran, options.AssertSink(this, builder), \"insufficient reads clause to invoke function\", options.AssertKv);\n          }\n\n          Bpl.Expr allowance = null;\n          if (codeContext != null && e.CoCall != FunctionCallExpr.CoCallResolution.Yes && !(e.Function is FixpointPredicate)) {\n            // check that the decreases measure goes down\n            if (ModuleDefinition.InSameSCC(e.Function, codeContext)) {\n              List<Expression> contextDecreases = codeContext.Decreases.Expressions;\n              List<Expression> calleeDecreases = e.Function.Decreases.Expressions;\n              if (e.Function == options.SelfCallsAllowance) {\n                allowance = Bpl.Expr.True;\n                if (!e.Function.IsStatic) {\n                  allowance = BplAnd(allowance, Bpl.Expr.Eq(etran.TrExpr(e.Receiver), new Bpl.IdentifierExpr(e.tok, etran.This)));\n                }\n                for (int i = 0; i < e.Args.Count; i++) {\n                  Expression ee = e.Args[i];\n                  Formal ff = e.Function.Formals[i];\n                  allowance = BplAnd(allowance, Bpl.Expr.Eq(etran.TrExpr(ee), new Bpl.IdentifierExpr(e.tok, ff.AssignUniqueName(currentDeclaration.IdGenerator), TrType(ff.Type))));\n                }\n              }\n              string hint;\n              switch (e.CoCall) {\n                case FunctionCallExpr.CoCallResolution.NoBecauseFunctionHasSideEffects:\n                  hint = \"note that only functions without side effects can be called co-recursively\";\n                  break;\n                case FunctionCallExpr.CoCallResolution.NoBecauseFunctionHasPostcondition:\n                  hint = \"note that only functions without any ensures clause can be called co-recursively\";\n                  break;\n                case FunctionCallExpr.CoCallResolution.NoBecauseIsNotGuarded:\n                  hint = \"note that the call is not sufficiently guarded to be used co-recursively\";\n                  break;\n                case FunctionCallExpr.CoCallResolution.NoBecauseRecursiveCallsAreNotAllowedInThisContext:\n                  hint = \"note that calls cannot be co-recursive in this context\";\n                  break;\n                case FunctionCallExpr.CoCallResolution.NoBecauseRecursiveCallsInDestructiveContext:\n                  hint = \"note that a call can be co-recursive only if all intra-cluster calls are in non-destructive contexts\";\n                  break;\n                case FunctionCallExpr.CoCallResolution.No:\n                  hint = null;\n                  break;\n                default:\n                  Contract.Assert(false);  // unexpected CoCallResolution\n                  goto case FunctionCallExpr.CoCallResolution.No;  // please the compiler\n              }\n              if (e.CoCallHint != null) {\n                hint = hint == null ? e.CoCallHint : string.Format(\"{0}; {1}\", hint, e.CoCallHint);\n              }\n              CheckCallTermination(expr.tok, contextDecreases, calleeDecreases, allowance, e.Receiver, substMap, e.TypeArgumentSubstitutions,\n                etran, etran, builder, codeContext.InferredDecreases, hint);\n            }\n          }\n          // all is okay, so allow this function application access to the function's axiom, except if it was okay because of the self-call allowance.\n          Bpl.IdentifierExpr canCallFuncID = new Bpl.IdentifierExpr(expr.tok, e.Function.FullSanitizedName + \"#canCall\", Bpl.Type.Bool);\n          List<Bpl.Expr> args = etran.FunctionInvocationArguments(e, null);\n          Bpl.Expr canCallFuncAppl = new Bpl.NAryExpr(expr.tok, new Bpl.FunctionCall(canCallFuncID), args);\n          builder.Add(TrAssumeCmd(expr.tok, allowance == null ? canCallFuncAppl : Bpl.Expr.Or(allowance, canCallFuncAppl)));\n\n          var returnType = e.Type.AsDatatype;\n          if (returnType != null && returnType.Ctors.Count == 1) {\n            var correctConstructor = FunctionCall(e.tok, returnType.Ctors[0].QueryField.FullSanitizedName, Bpl.Type.Bool, etran.TrExpr(e));\n            // There is only one constructor, so the value must be been constructed by it; might as well assume that here.\n            builder.Add(TrAssumeCmd(expr.tok, correctConstructor));\n          }\n        }\n      } else if (expr is DatatypeValue) {\n        DatatypeValue dtv = (DatatypeValue)expr;\n        for (int i = 0; i < dtv.Ctor.Formals.Count; i++) {\n          var formal = dtv.Ctor.Formals[i];\n          var arg = dtv.Arguments[i];\n          CheckWellformed(arg, options, locals, builder, etran);\n\n          // Cannot use the datatype's formals, so we substitute the inferred type args:\n          var su = new Dictionary<TypeParameter, Type>();\n          foreach (var p in LinqExtender.Zip(dtv.Ctor.EnclosingDatatype.TypeArgs, dtv.InferredTypeArgs)) {\n            su[p.Item1] = p.Item2;\n          }\n          Type ty = Resolver.SubstType(formal.Type, su);\n          CheckSubrange(arg.tok, etran.TrExpr(arg), arg.Type, ty, builder);\n        }\n      } else if (expr is SeqConstructionExpr) {\n        var e = (SeqConstructionExpr)expr;\n        CheckWellformed(e.N, options, locals, builder, etran);\n        builder.Add(Assert(e.N.tok, Bpl.Expr.Le(Bpl.Expr.Literal(0), etran.TrExpr(e.N)),\n          \"sequence size might be negative\"));\n\n        CheckWellformed(e.Initializer, options, locals, builder, etran);\n        var eType = e.Type.AsSeqType.Arg.NormalizeExpand();\n        CheckElementInit(e.tok, false, new List<Expression>() {e.N}, eType, e.Initializer, null, builder, etran, options);\n      } else if (expr is MultiSetFormingExpr) {\n        MultiSetFormingExpr e = (MultiSetFormingExpr)expr;\n        CheckWellformed(e.E, options, locals, builder, etran);\n      } else if (expr is OldExpr) {\n        var e = (OldExpr)expr;\n        // Anything read inside the 'old' expressions depends only on the old heap, which isn't included in the\n        // frame axiom.  In other words, 'old' expressions have no dependencies on the current heap.  Therefore,\n        // we turn off any reads checks for \"e.E\".\n        CheckWellformed(e.E, new WFOptions(options), locals, builder, etran.Old);\n      } else if (expr is UnchangedExpr) {\n        var e = (UnchangedExpr)expr;\n        foreach (var fe in e.Frame) {\n          CheckWellformed(fe.E, options, locals, builder, etran);\n        }\n      } else if (expr is UnaryExpr) {\n        UnaryExpr e = (UnaryExpr)expr;\n        CheckWellformed(e.E, options, locals, builder, etran);\n        if (e is ConversionExpr) {\n          var ee = (ConversionExpr)e;\n          CheckResultToBeInType(expr.tok, ee.E, ee.ToType, locals, builder, etran);\n        }\n      } else if (expr is BinaryExpr) {\n        BinaryExpr e = (BinaryExpr)expr;\n        CheckWellformed(e.E0, options, locals, builder, etran);\n        switch (e.ResolvedOp) {\n          case BinaryExpr.ResolvedOpcode.And:\n          case BinaryExpr.ResolvedOpcode.Imp: {\n              BoogieStmtListBuilder b = new BoogieStmtListBuilder(this);\n              CheckWellformed(e.E1, options, locals, b, etran);\n              builder.Add(new Bpl.IfCmd(expr.tok, etran.TrExpr(e.E0), b.Collect(expr.tok), null, null));\n            }\n            break;\n          case BinaryExpr.ResolvedOpcode.Or: {\n              BoogieStmtListBuilder b = new BoogieStmtListBuilder(this);\n              CheckWellformed(e.E1, options, locals, b, etran);\n              builder.Add(new Bpl.IfCmd(expr.tok, Bpl.Expr.Not(etran.TrExpr(e.E0)), b.Collect(expr.tok), null, null));\n            }\n            break;\n          case BinaryExpr.ResolvedOpcode.Add:\n          case BinaryExpr.ResolvedOpcode.Sub:\n          case BinaryExpr.ResolvedOpcode.Mul:\n            CheckWellformed(e.E1, options, locals, builder, etran);\n            if (e.ResolvedOp == BinaryExpr.ResolvedOpcode.Sub && e.E0.Type.IsBigOrdinalType) {\n              var rhsIsNat = FunctionCall(expr.tok, \"ORD#IsNat\", Bpl.Type.Bool, etran.TrExpr(e.E1));\n              builder.Add(Assert(expr.tok, rhsIsNat, \"RHS of ORDINAL subtraction must be a natural number, but the given RHS might be larger\"));\n              var offset0 = FunctionCall(expr.tok, \"ORD#Offset\", Bpl.Type.Int, etran.TrExpr(e.E0));\n              var offset1 = FunctionCall(expr.tok, \"ORD#Offset\", Bpl.Type.Int, etran.TrExpr(e.E1));\n              builder.Add(Assert(expr.tok, Bpl.Expr.Le(offset1, offset0), \"ORDINAL subtraction might underflow a limit ordinal (that is, RHS might be too large)\"));\n            } else if (e.Type.IsCharType) {\n              var e0 = FunctionCall(expr.tok, \"char#ToInt\", Bpl.Type.Int, etran.TrExpr(e.E0));\n              var e1 = FunctionCall(expr.tok, \"char#ToInt\", Bpl.Type.Int, etran.TrExpr(e.E1));\n              if (e.ResolvedOp == BinaryExpr.ResolvedOpcode.Add) {\n                builder.Add(Assert(expr.tok, Bpl.Expr.Lt(Bpl.Expr.Binary(BinaryOperator.Opcode.Add, e0, e1), Bpl.Expr.Literal(65536)), \"char addition might overflow\"));\n              } else {\n                Contract.Assert(e.ResolvedOp == BinaryExpr.ResolvedOpcode.Sub);  // .Mul is not supported for char\n                builder.Add(Assert(expr.tok, Bpl.Expr.Le(e1, e0), \"char subtraction might underflow\"));\n              }\n            }\n            CheckResultToBeInType(expr.tok, expr, expr.Type, locals, builder, etran);\n            break;\n          case BinaryExpr.ResolvedOpcode.Div:\n          case BinaryExpr.ResolvedOpcode.Mod: {\n              Bpl.Expr zero;\n              if (e.E1.Type.IsBitVectorType) {\n                zero = BplBvLiteralExpr(e.tok, BaseTypes.BigNum.ZERO, e.E1.Type.AsBitVectorType);\n              } else if (e.E1.Type.IsNumericBased(Type.NumericPersuation.Real)) {\n                zero = Bpl.Expr.Literal(BaseTypes.BigDec.ZERO);\n              } else {\n                zero = Bpl.Expr.Literal(0);\n              }\n              CheckWellformed(e.E1, options, locals, builder, etran);\n              builder.Add(Assert(expr.tok, Bpl.Expr.Neq(etran.TrExpr(e.E1), zero), \"possible division by zero\", options.AssertKv));\n              CheckResultToBeInType(expr.tok, expr, expr.Type, locals, builder, etran);\n            }\n            break;\n          case BinaryExpr.ResolvedOpcode.LeftShift:\n          case BinaryExpr.ResolvedOpcode.RightShift: {\n              CheckWellformed(e.E1, options, locals, builder, etran);\n              var w = e.Type.AsBitVectorType.Width;\n              var upperMsg = string.Format(\"shift amount must not exceed the width of the result ({0})\", w);\n              if (e.E1.Type.IsBitVectorType) {\n                // Known to be non-negative, so we don't need to check lower bound.\n                // Check upper bound, that is, check \"E1 <= w\"\n                var e1Width = e.E1.Type.AsBitVectorType.Width;\n                if (w < (BigInteger.One << e1Width)) {\n                  // w is a number that can be represented in the e.E1.Type, so do the comparison in that bitvector type.\n                  var bound = BplBvLiteralExpr(e.tok, BaseTypes.BigNum.FromInt(w), e1Width);\n                  var cmp = etran.TrToFunctionCall(expr.tok, \"le_bv\" + e1Width, Bpl.Type.Bool, etran.TrExpr(e.E1), bound, false);\n                  builder.Add(Assert(expr.tok, cmp, upperMsg, options.AssertKv));\n                } else {\n                  // In the previous branch, we had:\n                  //     w < 2^e1Width               (*)\n                  // From the type of E1, we have:\n                  //     E1 < 2^e1Width\n                  // In this branch, (*) does not hold, so we therefore have the following:\n                  //     E1 < 2^e1Width <= w\n                  // In other words, the condition\n                  //     E1 <= w\n                  // already holds, so there is no reason to check it.\n                }\n              } else {\n                builder.Add(Assert(expr.tok, Bpl.Expr.Le(Bpl.Expr.Literal(0), etran.TrExpr(e.E1)), \"shift amount must be non-negative\", options.AssertKv));\n                builder.Add(Assert(expr.tok, Bpl.Expr.Le(etran.TrExpr(e.E1), Bpl.Expr.Literal(w)), upperMsg, options.AssertKv));\n              }\n            }\n            break;\n          default:\n            CheckWellformed(e.E1, options, locals, builder, etran);\n            break;\n        }\n\n      } else if (expr is TernaryExpr) {\n        var e = (TernaryExpr)expr;\n        foreach (var ee in e.SubExpressions) {\n          CheckWellformed(ee, options, locals, builder, etran);\n        }\n        switch (e.Op) {\n          case TernaryExpr.Opcode.PrefixEqOp:\n          case TernaryExpr.Opcode.PrefixNeqOp:\n            if (e.E0.Type.IsNumericBased(Type.NumericPersuation.Int)) {\n              builder.Add(Assert(expr.tok, Bpl.Expr.Le(Bpl.Expr.Literal(0), etran.TrExpr(e.E0)), \"prefix-equality limit must be at least 0\", options.AssertKv));\n            }\n            break;\n          default:\n            Contract.Assert(false);  // unexpected ternary expression\n            break;\n        }\n\n      } else if (expr is LetExpr) {\n        result = CheckWellformedLetExprWithResult((LetExpr)expr, options, result, resultType, locals, builder, etran, true);\n\n      } else if (expr is NamedExpr) {\n        var e = (NamedExpr)expr;\n        CheckWellformedWithResult(e.Body, options, result, resultType, locals, builder, etran);\n        if (e.Contract != null) {\n          CheckWellformedWithResult(e.Contract, options, result, resultType, locals, builder, etran);\n          var theSame = Bpl.Expr.Eq(etran.TrExpr(e.Body), etran.TrExpr(e.Contract));\n          builder.Add(Assert(new ForceCheckToken(e.ReplacerToken), theSame, \"replacement must be the same value\"));\n        }\n      } else if (expr is ComprehensionExpr) {\n        var e = (ComprehensionExpr)expr;\n        var q = e as QuantifierExpr;\n        var lam = e as LambdaExpr;\n        var mc = e as MapComprehension;\n        if (mc != null && !mc.IsGeneralMapComprehension) {\n          mc = null;  // mc will be non-null when \"e\" is a general map comprehension\n        }\n\n        // This is a WF check, so we look at the original quantifier, not the split one.\n        // This ensures that cases like forall x :: x != null && f(x.a) do not fail to verify.\n\n        var typeMap = new Dictionary<TypeParameter, Type>();\n        var copies = new List<TypeParameter>();\n        if (q != null) {\n          copies = Map(q.TypeArgs, tp => q.Refresh(tp, CurrentIdGenerator));\n          typeMap = Util.Dict(q.TypeArgs, Map(copies, tp => (Type)new UserDefinedType(tp)));\n        }\n        locals.AddRange(Map(copies,\n          tp => new Bpl.LocalVariable(tp.tok, new TypedIdent(tp.tok, nameTypeParam(tp), predef.Ty))));\n        var substMap = SetupBoundVarsAsLocals(e.BoundVars, builder, locals, etran, typeMap);\n        var s = new Substituter(null, substMap, typeMap);\n        var body = Substitute(e.Term, null, substMap, typeMap);\n        var bodyLeft = mc != null ? Substitute(mc.TermLeft, null, substMap, typeMap) : null;\n        var substMapPrime = mc != null ? SetupBoundVarsAsLocals(e.BoundVars, builder, locals, etran, typeMap, \"#prime\") : null;\n        var bodyLeftPrime = mc != null ? Substitute(mc.TermLeft, null, substMapPrime, typeMap) : null;\n        var bodyPrime = mc != null ? Substitute(e.Term, null, substMapPrime, typeMap) : null;\n        List<FrameExpression> reads = null;\n\n        var newOptions = options;\n        var newEtran = etran;\n        builder.Add(new Bpl.CommentCmd(\"Begin Comprehension WF check\"));\n        BplIfIf(e.tok, lam != null, null, builder, newBuilder => {\n          if (lam != null) {\n            // Havoc heap\n            Bpl.Expr oldHeap;\n            locals.Add(BplLocalVar(CurrentIdGenerator.FreshId(\"$oldHeap#\"), predef.HeapType, out oldHeap));\n            newBuilder.Add(BplSimplestAssign(oldHeap, etran.HeapExpr));\n            newBuilder.Add(new HavocCmd(expr.tok, Singleton((Bpl.IdentifierExpr)etran.HeapExpr)));\n            newBuilder.Add(new AssumeCmd(expr.tok,\n              FunctionCall(expr.tok, BuiltinFunction.IsGoodHeap, null, etran.HeapExpr)));\n            newBuilder.Add(new AssumeCmd(expr.tok, HeapSameOrSucc(oldHeap, etran.HeapExpr)));\n\n            // Set up a new frame\n            var frameName = CurrentIdGenerator.FreshId(\"$_Frame#l\");\n            reads = lam.Reads.ConvertAll(s.SubstFrameExpr);\n            DefineFrame(e.tok, reads, newBuilder, locals, frameName);\n            newEtran = new ExpressionTranslator(newEtran, frameName);\n\n            // Check frame WF and that it read covers itself\n            newOptions = new WFOptions(options.SelfCallsAllowance, true /* check reads clauses */, true /* delay reads checks */);\n            CheckFrameWellFormed(newOptions, reads, locals, newBuilder, newEtran);\n            // new options now contains the delayed reads checks\n            newOptions.ProcessSavedReadsChecks(locals, builder, newBuilder);\n\n            // continue doing reads checks, but don't delay them\n            newOptions = new WFOptions(options.SelfCallsAllowance, true, false);\n          }\n\n          // check requires/range\n          Bpl.Expr guard = null;\n          if (e.Range != null) {\n            var range = Substitute(e.Range, null, substMap);\n            CheckWellformed(range, newOptions, locals, newBuilder, newEtran);\n            guard = etran.TrExpr(range);\n          }\n\n          if (mc != null) {\n            Contract.Assert(bodyLeft != null);\n            BplIfIf(e.tok, guard != null, guard, newBuilder, b => {\n              CheckWellformed(bodyLeft, newOptions, locals, b, newEtran);\n            });\n          }\n          BplIfIf(e.tok, guard != null, guard, newBuilder, b => {\n            CheckWellformed(body, newOptions, locals, b, newEtran);\n          });\n\n          if (mc != null) {\n            Contract.Assert(substMapPrime != null);\n            Contract.Assert(bodyLeftPrime != null);\n            Contract.Assert(bodyPrime != null);\n            Bpl.Expr guardPrime = null;\n            if (guard != null) {\n              Contract.Assert(e.Range != null);\n              var rangePrime = Substitute(e.Range, null, substMapPrime);\n              guardPrime = etran.TrExpr(rangePrime);\n            }\n            BplIfIf(e.tok, guard != null, BplAnd(guard, guardPrime), newBuilder, b => {\n              var different = BplOr(\n                Bpl.Expr.Neq(etran.TrExpr(bodyLeft), etran.TrExpr(bodyLeftPrime)),\n                Bpl.Expr.Eq(etran.TrExpr(body), etran.TrExpr(bodyPrime)));\n              b.Add(Assert(mc.TermLeft.tok, different, \"key expressions may be referring to the same value\"));\n            });\n          }\n\n          if (lam != null) {\n            // assume false (heap was havoced inside an if)\n            Contract.Assert(newBuilder != builder);\n            newBuilder.Add(new AssumeCmd(e.tok, Bpl.Expr.False));\n          }\n        });\n        builder.Add(new Bpl.CommentCmd(\"End Comprehension WF check\"));\n\n      } else if (expr is StmtExpr) {\n        var e = (StmtExpr)expr;\n        TrStmt(e.S, builder, locals, etran);\n        CheckWellformedWithResult(e.E, options, result, resultType, locals, builder, etran);\n        result = null;\n\n      } else if (expr is ITEExpr) {\n        ITEExpr e = (ITEExpr)expr;\n        CheckWellformed(e.Test, options, locals, builder, etran);\n        var bThen = new BoogieStmtListBuilder(this);\n        var bElse = new BoogieStmtListBuilder(this);\n        if (e.IsBindingGuard) {\n          // if it is BindingGuard, e.Thn is a let-such-that created from the BindingGuard.\n          // We don't need to do well-formedness check on the Rhs of the LetExpr since it\n          // has already been checked in e.Test\n          var letExpr = (LetExpr)e.Thn;\n          Contract.Assert(letExpr != null);\n          CheckWellformedLetExprWithResult(letExpr, options, result, resultType, locals, bThen, etran, false);\n        } else {\n          CheckWellformedWithResult(e.Thn, options, result, resultType, locals, bThen, etran);\n        }\n        CheckWellformedWithResult(e.Els, options, result, resultType, locals, bElse, etran);\n        builder.Add(new Bpl.IfCmd(expr.tok, etran.TrExpr(e.Test), bThen.Collect(expr.tok), null, bElse.Collect(expr.tok)));\n        result = null;\n\n      } else if (expr is MatchExpr) {\n        MatchExpr me = (MatchExpr)expr;\n        CheckWellformed(me.Source, options, locals, builder, etran);\n        Bpl.Expr src = etran.TrExpr(me.Source);\n        Bpl.IfCmd ifCmd = null;\n        BoogieStmtListBuilder elsBldr = new BoogieStmtListBuilder(this);\n        elsBldr.Add(TrAssumeCmd(expr.tok, Bpl.Expr.False));\n        StmtList els = elsBldr.Collect(expr.tok);\n        foreach (var missingCtor in me.MissingCases) {\n          // havoc all bound variables\n          var b = new BoogieStmtListBuilder(this);\n          List<Variable> newLocals = new List<Variable>();\n          Bpl.Expr r = CtorInvocation(me.tok, missingCtor, etran, newLocals, b);\n          locals.AddRange(newLocals);\n\n          if (newLocals.Count != 0) {\n            List<Bpl.IdentifierExpr> havocIds = new List<Bpl.IdentifierExpr>();\n            foreach (Variable local in newLocals) {\n              havocIds.Add(new Bpl.IdentifierExpr(local.tok, local));\n            }\n            builder.Add(new Bpl.HavocCmd(me.tok, havocIds));\n          }\n          b.Add(Assert(me.tok, Bpl.Expr.False, \"missing case in case statement: \" + missingCtor.Name));\n\n          Bpl.Expr guard = Bpl.Expr.Eq(src, r);\n          ifCmd = new Bpl.IfCmd(me.tok, guard, b.Collect(me.tok), ifCmd, els);\n          els = null;\n        }\n        for (int i = me.Cases.Count; 0 <= --i;) {\n          MatchCaseExpr mc = me.Cases[i];\n          BoogieStmtListBuilder b = new BoogieStmtListBuilder(this);\n          Bpl.Expr ct = CtorInvocation(mc, etran, locals, b, NOALLOC, false);\n          // generate:  if (src == ctor(args)) { assume args-is-well-typed; mc.Body is well-formed; assume Result == TrExpr(case); } else ...\n          CheckWellformedWithResult(mc.Body, options, result, resultType, locals, b, etran);\n          ifCmd = new Bpl.IfCmd(mc.tok, Bpl.Expr.Eq(src, ct), b.Collect(mc.tok), ifCmd, els);\n          els = null;\n        }\n        builder.Add(ifCmd);\n        result = null;\n\n      } else if (expr is DatatypeUpdateExpr) {\n        var e = (DatatypeUpdateExpr)expr;\n        // check that source expression is created from one of the legal source constructors, then proceed according to the .ResolvedExpression\n        var correctConstructor = BplOr(e.LegalSourceConstructors.ConvertAll(\n          ctor => FunctionCall(e.tok, ctor.QueryField.FullSanitizedName, Bpl.Type.Bool, etran.TrExpr(e.Root))));\n        if (e.LegalSourceConstructors.Count == e.Type.AsDatatype.Ctors.Count) {\n          // Every constructor has this destructor; no need to check anything\n        } else {\n          builder.Add(Assert(expr.tok, correctConstructor,\n            string.Format(\"source of datatype update must be constructed by {0}\", DatatypeDestructor.PrintableCtorNameList(e.LegalSourceConstructors, \"or\"))));\n        }\n\n        CheckWellformedWithResult(e.ResolvedExpression, options, result, resultType, locals, builder, etran);\n        result = null;\n\n      } else if (expr is ConcreteSyntaxExpression) {\n        var e = (ConcreteSyntaxExpression)expr;\n        CheckWellformedWithResult(e.ResolvedExpression, options, result, resultType, locals, builder, etran);\n        result = null;\n\n      } else if (expr is RevealExpr) {\n        var e = (RevealExpr)expr;\n        CheckWellformedWithResult(e.ResolvedExpression, options, result, resultType, locals, builder, etran);\n        result = null;\n\n      } else if (expr is BoogieFunctionCall) {\n        var e = (BoogieFunctionCall)expr;\n        foreach (var arg in e.Args) {\n          CheckWellformed(arg, options, locals, builder, etran);\n        }\n\n      } else {\n        Contract.Assert(false); throw new cce.UnreachableException();  // unexpected expression\n      }\n\n      if (result != null) {\n        Contract.Assert(resultType != null);\n        var bResult = etran.TrExpr(expr);\n        CheckSubrange(expr.tok, bResult, expr.Type, resultType, builder);\n        builder.Add(TrAssumeCmd(expr.tok, Bpl.Expr.Eq(result, bResult)));\n        builder.Add(TrAssumeCmd(expr.tok, CanCallAssumption(expr, etran)));\n        builder.Add(new CommentCmd(\"CheckWellformedWithResult: any expression\"));\n        if (AlwaysUseHeap) {\n          builder.Add(TrAssumeCmd(expr.tok, MkIsAlloc(result, resultType, etran.HeapExpr)));\n        }\n        builder.Add(TrAssumeCmd(expr.tok, MkIs(result, resultType)));\n      }\n    }\n\n    void CheckWellformedSpecialFunction(FunctionCallExpr expr, WFOptions options, Bpl.Expr result, Type resultType, List<Bpl.Variable> locals,\n                               BoogieStmtListBuilder builder, ExpressionTranslator etran) {\n      Contract.Requires(expr.Function is SpecialFunction);\n\n      string name = expr.Function.Name;\n      CheckWellformed(expr.Receiver, options, locals, builder, etran);\n      if (name == \"RotateLeft\" || name == \"RotateRight\") {\n        var w = expr.Type.AsBitVectorType.Width;\n        Expression arg = expr.Args[0];\n        builder.Add(Assert(expr.tok, Bpl.Expr.Le(Bpl.Expr.Literal(0), etran.TrExpr(arg)), \"shift amount must be non-negative\", options.AssertKv));\n        var upperMsg = string.Format(\"shift amount must not exceed the width of the result ({0})\", w);\n        builder.Add(Assert(expr.tok, Bpl.Expr.Le(etran.TrExpr(arg), Bpl.Expr.Literal(w)), upperMsg, options.AssertKv));\n      }\n    }\n\n    Bpl.Expr CheckWellformedLetExprWithResult(LetExpr e, WFOptions options, Bpl.Expr result, Type resultType, List<Bpl.Variable> locals,\n                                BoogieStmtListBuilder builder, ExpressionTranslator etran, bool checkRhs) {\n      if (e.Exact) {\n        var substMap = SetupBoundVarsAsLocals(e.BoundVars.ToList<BoundVar>(), builder, locals, etran);\n        Contract.Assert(e.LHSs.Count == e.RHSs.Count);  // checked by resolution\n        var varNameGen = CurrentIdGenerator.NestedFreshIdGenerator(\"let#\");\n        for (int i = 0; i < e.LHSs.Count; i++) {\n          var pat = e.LHSs[i];\n          var rhs = e.RHSs[i];\n          var nm = varNameGen.FreshId(string.Format(\"#{0}#\", i));\n          var r = new Bpl.LocalVariable(pat.tok, new Bpl.TypedIdent(pat.tok, nm, TrType(rhs.Type)));\n          locals.Add(r);\n          var rIe = new Bpl.IdentifierExpr(rhs.tok, r);\n          CheckWellformedWithResult(e.RHSs[i], options, rIe, pat.Expr.Type, locals, builder, etran);\n          CheckCasePatternShape(pat, rIe, rhs.tok, pat.Expr.Type, builder);\n          builder.Add(TrAssumeCmd(pat.tok, Bpl.Expr.Eq(etran.TrExpr(Substitute(pat.Expr, null, substMap)), rIe)));\n        }\n        CheckWellformedWithResult(Substitute(e.Body, null, substMap), options, result, resultType, locals, builder, etran);\n        result = null;\n\n      } else {\n        // CheckWellformed(var b :| RHS(b); Body(b)) =\n        //   var b where typeAntecedent;\n        //   CheckWellformed(RHS(b));\n        //   assert (exists b' :: typeAntecedent' && RHS(b'));\n        //   assume RHS(b);\n        //   CheckWellformed(Body(b));\n        //   If non-ghost:  var b' where typeAntecedent; assume RHS(b'); assert Body(b) == Body(b');\n        //   assume CanCall\n        Contract.Assert(e.RHSs.Count == 1);  // this is true of all successfully resolved let-such-that expressions\n        List<BoundVar> lhsVars = e.BoundVars.ToList<BoundVar>();\n        var substMap = SetupBoundVarsAsLocals(lhsVars, builder, locals, etran);\n        var rhs = Substitute(e.RHSs[0], null, substMap);\n        if (checkRhs) {\n          CheckWellformed(rhs, options, locals, builder, etran);\n          var bounds = lhsVars.ConvertAll(v => (ComprehensionExpr.BoundedPool)new ComprehensionExpr.SpecialAllocIndependenceAllocatedBoundedPool());  // indicate \"no alloc\" (is this what we want?)\n          GenerateAndCheckGuesses(e.tok, lhsVars, bounds, e.RHSs[0], TrTrigger(etran, e.Attributes, e.tok), builder, etran);\n        }\n        builder.Add(TrAssumeCmd(e.tok, etran.TrExpr(rhs)));\n        var letBody = Substitute(e.Body, null, substMap);\n        CheckWellformed(letBody, options, locals, builder, etran);\n        if (e.Constraint_Bounds != null) {\n          Contract.Assert(!e.BoundVars.All(bv => bv.IsGhost));\n          var substMap_prime = SetupBoundVarsAsLocals(lhsVars, builder, locals, etran);\n          var rhs_prime = Substitute(e.RHSs[0], null, substMap_prime);\n          var letBody_prime = Substitute(e.Body, null, substMap_prime);\n          builder.Add(TrAssumeCmd(e.tok, CanCallAssumption(rhs_prime, etran)));\n          builder.Add(TrAssumeCmd(e.tok, etran.TrExpr(rhs_prime)));\n          builder.Add(TrAssumeCmd(e.tok, CanCallAssumption(letBody_prime, etran)));\n          var eq = Expression.CreateEq(letBody, letBody_prime, e.Body.Type);\n          builder.Add(Assert(e.tok, etran.TrExpr(eq), \"to be compilable, the value of a let-such-that expression must be uniquely determined\"));\n        }\n        // assume $let$canCall(g);\n        LetDesugaring(e);  // call LetDesugaring to prepare the desugaring and populate letSuchThatExprInfo with something for e\n        var info = letSuchThatExprInfo[e];\n        builder.Add(new Bpl.AssumeCmd(e.tok, info.CanCallFunctionCall(this, etran)));\n        // If we are supposed to assume \"result\" to equal this expression, then use the body of the let-such-that, not the generated $let#... function\n        if (result != null) {\n          Contract.Assert(resultType != null);\n          var bResult = etran.TrExpr(letBody);\n          CheckSubrange(letBody.tok, bResult, letBody.Type, resultType, builder);\n          builder.Add(TrAssumeCmd(letBody.tok, Bpl.Expr.Eq(result, bResult)));\n          builder.Add(TrAssumeCmd(letBody.tok, CanCallAssumption(letBody, etran)));\n          builder.Add(new CommentCmd(\"CheckWellformedWithResult: Let expression\"));\n          if (AlwaysUseHeap) {\n            builder.Add(TrAssumeCmd(letBody.tok, MkIsAlloc(result, resultType, etran.HeapExpr)));\n          }\n          builder.Add(TrAssumeCmd(letBody.tok, MkIs(result, resultType)));\n          result = null;\n        }\n      }\n      return result;\n    }\n\n    /// <summary>\n    /// Returns the translation of converting \"r\", whose Dafny type was \"fromType\", to a value of type \"toType\".\n    /// The translation assumes that \"r\" is known to be a value of type \"toType\".\n    /// </summary>\n    Bpl.Expr ConvertExpression(IToken tok, Bpl.Expr r, Type fromType, Type toType) {\n      Contract.Requires(tok != null);\n      Contract.Requires(r != null);\n      Contract.Requires(fromType != null);\n      Contract.Requires(toType != null);\n      toType = toType.NormalizeExpand();\n      fromType = fromType.NormalizeExpand();\n      if (fromType.IsBitVectorType) {\n        var fromWidth = fromType.AsBitVectorType.Width;\n        if (toType.IsBitVectorType) {\n          // conversion from one bitvector type to another\n          var toWidth = toType.AsBitVectorType.Width;\n          if (fromWidth == toWidth) {\n            return r;\n          } else if (fromWidth < toWidth) {\n            var zeros = BplBvLiteralExpr(tok, BaseTypes.BigNum.ZERO, toWidth - fromWidth);\n            if (fromWidth == 0) {\n              return zeros;\n            } else {\n              var concat = new Bpl.BvConcatExpr(tok, zeros, r);\n              // There's a bug in Boogie that causes a warning to be emitted if a BvConcatExpr is passed as the argument\n              // to $Box, which takes a type argument.  The bug can apparently be worked around by giving an explicit\n              // (and other redudant) type conversion.\n              return Bpl.Expr.CoerceType(tok, concat, BplBvType(toWidth));\n            }\n          } else if (toWidth == 0) {\n            return BplBvLiteralExpr(tok, BaseTypes.BigNum.ZERO, toWidth);\n          } else {\n            return new Bpl.BvExtractExpr(tok, r, toWidth, 0);\n          }\n        } else {\n          r = FunctionCall(tok, \"nat_from_bv\" + fromWidth, Bpl.Type.Int, r);\n          if (toType.IsNumericBased(Type.NumericPersuation.Real)) {\n            r = FunctionCall(tok, BuiltinFunction.IntToReal, null, r);\n          }\n          return r;\n        }\n      }\n      if (fromType.IsNumericBased(Type.NumericPersuation.Real)) {\n        if (toType.IsNumericBased(Type.NumericPersuation.Real)) {\n          return r;\n        }\n        r = FunctionCall(tok, BuiltinFunction.RealToInt, null, r);\n        // \"r\" now denotes an integer\n      } else if (fromType.IsCharType) {\n        Contract.Assert(toType.IsNumericBased(Type.NumericPersuation.Int));\n        return FunctionCall(tok, BuiltinFunction.CharToInt, null, r);\n      } else if (fromType.IsBigOrdinalType) {\n        Contract.Assert(toType.IsNumericBased(Type.NumericPersuation.Int));\n        return FunctionCall(tok, \"ORD#Offset\", Bpl.Type.Int, r);\n      } else {\n        Contract.Assert(fromType.IsNumericBased(Type.NumericPersuation.Int));\n        if (toType.IsNumericBased(Type.NumericPersuation.Real)) {\n          return FunctionCall(tok, BuiltinFunction.IntToReal, null, r);\n        } else if (toType.IsBigOrdinalType) {\n          return FunctionCall(tok, \"ORD#FromNat\", predef.BigOrdinalType, r);\n        }\n      }\n      if (toType.IsNumericBased(Type.NumericPersuation.Int)) {\n        return r;\n      } else if (toType.IsCharType) {\n        Contract.Assert(fromType.IsNumericBased(Type.NumericPersuation.Int));\n        return FunctionCall(tok, BuiltinFunction.CharFromInt, null, r);\n      } else {\n        Contract.Assert(toType.IsBitVectorType);\n        var toWidth = toType.AsBitVectorType.Width;\n        if (RemoveLit(r) is Bpl.LiteralExpr) {\n          Bpl.LiteralExpr e = (Bpl.LiteralExpr) RemoveLit(r);\n          if (e.isBigNum) {\n            var toBound = BaseTypes.BigNum.FromBigInt(BigInteger.One << toWidth);  // 1 << toWidth\n            if (e.asBigNum <= toBound) {\n              return BplBvLiteralExpr(r.tok, e.asBigNum, toType.AsBitVectorType);\n            }\n          }\n        }\n        return FunctionCall(tok, \"nat_to_bv\" + toWidth, BplBvType(toWidth), r);\n      }\n    }\n\n    /// <summary>\n    /// Emit checks that \"expr\" (which may or may not be a value of type \"expr.Type\"!) is a value of type \"toType\".\n    /// </summary>\n    void CheckResultToBeInType(IToken tok, Expression expr, Type toType, List<Bpl.Variable> locals, BoogieStmtListBuilder builder, ExpressionTranslator etran, string errorMsgPrefix = \"\") {\n      Contract.Requires(tok != null);\n      Contract.Requires(expr != null);\n      Contract.Requires(toType != null);\n      Contract.Requires(builder != null);\n      Contract.Requires(etran != null);\n      Contract.Requires(errorMsgPrefix != null);\n\n      // Lazily create a local variable \"o\" to hold the value of the from-expression\n      Bpl.IdentifierExpr o = null;\n      System.Action PutSourceIntoLocal = () => {\n        if (o == null) {\n          var oType = expr.Type.IsCharType ? Type.Int : expr.Type;\n          var oVar = new Bpl.LocalVariable(tok, new Bpl.TypedIdent(tok, CurrentIdGenerator.FreshId(\"newtype$check#\"), TrType(oType)));\n          locals.Add(oVar);\n          o = new Bpl.IdentifierExpr(tok, oVar);\n          var rhs = etran.TrExpr(expr);\n          if (expr.Type.IsCharType) {\n            rhs = FunctionCall(expr.tok, \"char#ToInt\", Bpl.Type.Int, rhs);\n          }\n          builder.Add(Bpl.Cmd.SimpleAssign(tok, o, rhs));\n        }\n      };\n\n      if (expr.Type.IsNumericBased(Type.NumericPersuation.Real) && !toType.IsNumericBased(Type.NumericPersuation.Real)) {\n        // this operation is well-formed only if the real-based number represents an integer\n        //   assert Real(Int(o)) == o;\n        PutSourceIntoLocal();\n        var from = FunctionCall(tok, BuiltinFunction.RealToInt, null, o);\n        Bpl.Expr e = FunctionCall(tok, BuiltinFunction.IntToReal, null, from);\n        e = Bpl.Expr.Binary(tok, Bpl.BinaryOperator.Opcode.Eq, e, o);\n        builder.Add(Assert(tok, e, errorMsgPrefix + \"the real-based number must be an integer (if you want truncation, apply .Floor to the real-based number)\"));\n      }\n\n      if (toType.IsBitVectorType) {\n        var toWidth = toType.AsBitVectorType.Width;\n        var toBound = BaseTypes.BigNum.FromBigInt(BigInteger.One << toWidth);  // 1 << toWidth\n        Bpl.Expr boundsCheck = null;\n        if (expr.Type.IsBitVectorType) {\n          var fromWidth = expr.Type.AsBitVectorType.Width;\n          if (toWidth < fromWidth) {\n            // Check \"expr < (1 << toWidth)\" in type \"fromType\" (note that \"1 << toWidth\" is indeed a value in \"fromType\")\n            PutSourceIntoLocal();\n            var bound = BplBvLiteralExpr(tok, toBound, expr.Type.AsBitVectorType);\n            boundsCheck = FunctionCall(expr.tok, \"lt_bv\" + fromWidth, Bpl.Type.Bool, o, bound);\n          }\n        } else if (expr.Type.IsNumericBased(Type.NumericPersuation.Int)) {\n          // Check \"expr < (1 << toWdith)\" in type \"int\"\n          PutSourceIntoLocal();\n          var bound = Bpl.Expr.Literal(toBound);\n          boundsCheck = Bpl.Expr.And(Bpl.Expr.Le(Bpl.Expr.Literal(0), o), Bpl.Expr.Lt(o, bound));\n        } else {\n          Contract.Assert(expr.Type.IsNumericBased(Type.NumericPersuation.Real));\n          // Check \"Int(expr) < (1 << toWdith)\" in type \"int\"\n          PutSourceIntoLocal();\n          var bound = Bpl.Expr.Literal(toBound);\n          var oi = FunctionCall(tok, BuiltinFunction.RealToInt, null, o);\n          boundsCheck = Bpl.Expr.And(Bpl.Expr.Le(Bpl.Expr.Literal(0), oi), Bpl.Expr.Lt(oi, bound));\n        }\n        if (boundsCheck != null) {\n          builder.Add(Assert(tok, boundsCheck, string.Format(\"{0}value to be converted might not fit in {1}\", errorMsgPrefix, toType)));\n        }\n      }\n\n      if (toType.IsCharType) {\n        if (expr.Type.IsNumericBased(Type.NumericPersuation.Int)) {\n          PutSourceIntoLocal();\n          Bpl.Expr boundsCheck = Bpl.Expr.And(Bpl.Expr.Le(Bpl.Expr.Literal(0), o), Bpl.Expr.Lt(o, Bpl.Expr.Literal(65536)));\n          builder.Add(Assert(tok, boundsCheck, string.Format(\"{0}value to be converted might not fit in {1}\", errorMsgPrefix, toType)));\n        }\n      } else if (toType.IsBigOrdinalType && expr.Type.IsNumericBased(Type.NumericPersuation.Int)) {\n        PutSourceIntoLocal();\n        Bpl.Expr boundsCheck = Bpl.Expr.Le(Bpl.Expr.Literal(0), o);\n        builder.Add(Assert(tok, boundsCheck, string.Format(\"{0}a negative integer cannot be converted to an {1}\", errorMsgPrefix, toType)));\n      } else if (expr.Type.IsBigOrdinalType && toType.IsNumericBased(Type.NumericPersuation.Int)) {\n        PutSourceIntoLocal();\n        Bpl.Expr boundsCheck = FunctionCall(tok, \"ORD#IsNat\", Bpl.Type.Bool, o);\n        builder.Add(Assert(tok, boundsCheck, string.Format(\"{0}value to be converted might be bigger than every natural number\", errorMsgPrefix)));\n      }\n\n      if (toType.NormalizeExpandKeepConstraints().AsRedirectingType != null) {\n        PutSourceIntoLocal();\n        Bpl.Expr be;\n        if (expr.Type.IsNumericBased() || expr.Type.IsBitVectorType) {\n          be = ConvertExpression(expr.tok, o, expr.Type, toType);\n        } else {\n          be = o;\n        }\n        var dafnyType = toType.NormalizeExpand();\n        CheckResultToBeInType_Aux(tok, new BoogieWrapper(be, dafnyType), toType.NormalizeExpandKeepConstraints(), builder, etran, errorMsgPrefix);\n      }\n    }\n    void CheckResultToBeInType_Aux(IToken tok, Expression expr, Type toType, BoogieStmtListBuilder builder, ExpressionTranslator etran, string errorMsgPrefix) {\n      Contract.Requires(tok != null);\n      Contract.Requires(expr != null);\n      Contract.Requires(toType != null && toType.AsRedirectingType != null);\n      Contract.Requires(builder != null);\n      Contract.Requires(etran != null);\n      Contract.Requires(errorMsgPrefix != null);\n      // First, check constraints of base types\n      var udt = (UserDefinedType)toType;\n      var rdt = (RedirectingTypeDecl)udt.ResolvedClass;\n      Type baseType;\n      string kind;\n      if (rdt is SubsetTypeDecl) {\n        baseType = ((SubsetTypeDecl)rdt).RhsWithArgument(udt.TypeArgs);\n        kind = \"subset type\";\n      } else {\n        baseType = ((NewtypeDecl)rdt).BaseType;\n        kind = \"newtype\";\n      }\n      if (baseType.AsRedirectingType != null) {\n        CheckResultToBeInType_Aux(tok, expr, baseType, builder, etran, errorMsgPrefix);\n      }\n      // Check any constraint defined in 'dd'\n      if (rdt.Var != null) {\n        // TODO: use TrSplitExpr\n        var substMap = new Dictionary<IVariable, Expression>();\n        substMap.Add(rdt.Var, expr);\n        var typeMap = Resolver.TypeSubstitutionMap(rdt.TypeArgs, udt.TypeArgs);\n        var constraint = etran.TrExpr(Substitute(rdt.Constraint, null, substMap, typeMap));\n        builder.Add(Assert(tok, constraint, string.Format(\"{2}result of operation might violate {1} constraint for '{0}'\", rdt.Name, kind, errorMsgPrefix)));\n      }\n    }\n\n\n    void CheckFunctionSelectWF(string what, BoogieStmtListBuilder builder, ExpressionTranslator etran, Expression e, string hint) {\n      Function fn = null;\n      var sel = e as MemberSelectExpr;\n      if (sel != null) {\n        fn = sel.Member as Function;\n      }\n      if (fn != null) {\n        Bpl.Expr assertion = !InVerificationScope(fn) ? Bpl.Expr.True : Bpl.Expr.Not(etran.HeightContext(fn));\n        builder.Add(Assert(e.tok, assertion,\n          \"cannot use \" + what + \" in recursive setting.\" + hint));\n      }\n    }\n\n    void CloneVariableAsBoundVar(IToken tok, IVariable iv, string prefix, out BoundVar bv, out IdentifierExpr ie) {\n      Contract.Requires(tok != null);\n      Contract.Requires(iv != null);\n      Contract.Requires(prefix != null);\n      Contract.Ensures(Contract.ValueAtReturn(out bv) != null);\n      Contract.Ensures(Contract.ValueAtReturn(out ie) != null);\n\n      bv = new BoundVar(tok, CurrentIdGenerator.FreshId(prefix), iv.Type); // use this temporary variable counter, but for a Dafny name (the idea being that the number and the initial \"_\" in the name might avoid name conflicts)\n      ie = new IdentifierExpr(tok, bv.Name);\n      ie.Var = bv;  // resolve here\n      ie.Type = bv.Type;  // resolve here\n    }\n\n    // Use trType to translate types in the args list\n    Bpl.Expr ClassTyCon(UserDefinedType cl, List<Bpl.Expr> args) {\n      Contract.Requires(cl != null);\n      Contract.Requires(cce.NonNullElements(args));\n      return ClassTyCon(cl.ResolvedClass, args);\n    }\n\n    Bpl.Expr ClassTyCon(TopLevelDecl cl, List<Bpl.Expr> args) {\n      Contract.Requires(cl != null);\n      Contract.Requires(cce.NonNullElements(args));\n      return FunctionCall(cl.tok, GetClassTyCon(cl), predef.Ty, args);\n    }\n\n    // Takes a Bpl.Constant, which typically will be one from GetClass,\n    // or some built-in type which has a class name, like Arrays or Arrows.\n    // Note: Prefer to call ClassTyCon or TypeToTy instead.\n    private string GetClassTyCon(TopLevelDecl dl) {\n      Contract.Requires(dl != null);\n      string name;\n      if (classConstants.TryGetValue(dl, out name)) {\n        Contract.Assert(name != null);\n      } else {\n        name = AddTyAxioms(dl);\n        classConstants.Add(dl, name);\n      }\n      return name;\n    }\n\n    public string Handle(int arity) {\n      return \"Handle\" + arity;\n    }\n\n    public static string Apply(int arity) {\n      return \"Apply\" + arity;\n    }\n\n    public static string Requires(int arity) {\n      return \"Requires\" + arity;\n    }\n\n    public static string Reads(int arity) {\n      return \"Reads\" + arity;\n    }\n\n    public string RequiresName(Function f) {\n      return f.FullSanitizedName + \"#requires\";\n    }\n\n    public string FunctionHandle(Function f) {\n      Contract.Requires(f != null);\n      string name;\n      if (functionHandles.TryGetValue(f, out name)) {\n        Contract.Assert(name != null);\n      } else {\n        name = f.FullSanitizedName + \"#Handle\";\n        functionHandles[f] = name;\n        var args = new List<Bpl.Expr>();\n        var vars = MkTyParamBinders(GetTypeParams(f), out args);\n        var formals = MkTyParamFormals(GetTypeParams(f), false);\n        var tyargs = new List<Bpl.Expr>();\n        foreach (var fm in f.Formals) {\n          tyargs.Add(TypeToTy(fm.Type));\n        }\n        tyargs.Add(TypeToTy(f.ResultType));\n        if (f.IsFuelAware()) {\n          Bpl.Expr ly; vars.Add(BplBoundVar(\"$ly\", predef.LayerType, out ly)); args.Add(ly);\n          formals.Add(BplFormalVar(null, predef.LayerType, true));\n        }\n\n        var enclosingArrow = f.EnclosingClass as ArrowTypeDecl;\n        var fromArrowType = enclosingArrow != null;\n\n        Func<List<Bpl.Expr>, List<Bpl.Expr>> SnocSelf = x => x;\n        Func<List<Bpl.Expr>, List<Bpl.Expr>> SnocPrevH = x => x;\n        Expression selfExpr;\n        Dictionary<IVariable, Expression> rhs_dict = new Dictionary<IVariable, Expression>();\n        if (f is TwoStateFunction) {\n          // also add previous-heap to the list of fixed arguments of the handle\n          var prevH = BplBoundVar(\"$prevHeap\", predef.HeapType, vars);\n          formals.Add(BplFormalVar(null, predef.HeapType, true));\n          SnocPrevH = xs => Snoc(xs, prevH);\n        }\n        if (f.IsStatic) {\n          // the value of 'selfExpr' won't be used, but it has to be non-null to satisfy the precondition of the call to InRWClause below\n          selfExpr = new ThisExpr(Token.NoToken);\n        } else {\n          var selfTy = fromArrowType ? predef.HandleType : predef.RefType;\n          var self = BplBoundVar(\"$self\", selfTy, vars);\n          formals.Add(BplFormalVar(null, selfTy, true));\n          SnocSelf = xs => Snoc(xs, self);\n          selfExpr = new BoogieWrapper(self, fromArrowType ? f.Type : program.BuiltIns.ObjectQ());\n                                          // ^ is this an ok type for this wrapper?\n        }\n\n        // F#Handle(Ty, .., Ty, LayerType, ref) : HandleType\n        sink.AddTopLevelDeclaration(\n          new Bpl.Function(f.tok, name, formals, BplFormalVar(null, predef.HandleType, false)));\n\n        var bvars = new List<Bpl.Variable>();\n        var lhs_args = new List<Bpl.Expr>();\n        var rhs_args = new List<Bpl.Expr>();\n        var func_vars = new List<Bpl.Variable>();\n        var func_args = new List<Bpl.Expr>();\n        var boxed_func_args = new List<Bpl.Expr>();\n\n        var idGen = f.IdGenerator.NestedFreshIdGenerator(\"$fh$\");\n        foreach (var fm in f.Formals) {\n          string fm_name = idGen.FreshId(\"x#\");\n          // Box and its [Unbox]args\n          var fe = BplBoundVar(fm_name, predef.BoxType, bvars);\n          lhs_args.Add(fe);\n          var be = UnboxIfBoxed(fe, fm.Type);\n          rhs_args.Add(be);\n          rhs_dict[fm] = new BoogieWrapper(be, fm.Type);\n          // args and its [Box]args\n          var arg = BplBoundVar(fm_name, TrType(fm.Type), func_vars);\n          func_args.Add(arg);\n          var boxed = BoxIfUnboxed(arg, fm.Type);\n          boxed_func_args.Add(boxed);\n        }\n\n        var h = BplBoundVar(\"$heap\", predef.HeapType, vars);\n\n        int arity = f.Formals.Count;\n\n        {\n          // Apply(Ty.., F#Handle( Ty1, ..., TyN, Layer, self), Heap, arg1, ..., argN)\n          //   = [Box] F(Ty1, .., TyN, Layer, Heap, self, [Unbox] arg1, .., [Unbox] argN)\n\n          var fhandle = FunctionCall(f.tok, name, predef.HandleType, SnocSelf(SnocPrevH(args)));\n          var lhs = FunctionCall(f.tok, Apply(arity), TrType(f.ResultType), Concat(tyargs, Cons(h, Cons(fhandle, lhs_args))));\n          var args_h = AlwaysUseHeap || f.ReadsHeap ? Snoc(SnocPrevH(args), h) : args;\n          var rhs = FunctionCall(f.tok, f.FullSanitizedName, TrType(f.ResultType), Concat(SnocSelf(args_h), rhs_args));\n          var rhs_boxed = BoxIfUnboxed(rhs, f.ResultType);\n\n          sink.AddTopLevelDeclaration(new Axiom(f.tok,\n            BplForall(Concat(vars, bvars), BplTrigger(lhs), Bpl.Expr.Eq(lhs, rhs_boxed))));\n        }\n\n        {\n          // Requires(Ty.., F#Handle( Ty1, ..., TyN, Layer, self), Heap, arg1, ..., argN)\n          //   = F#Requires(Ty1, .., TyN, Layer, Heap, self, [Unbox] arg1, .., [Unbox] argN)\n\n          var fhandle = FunctionCall(f.tok, name, predef.HandleType, SnocSelf(SnocPrevH(args)));\n          var lhs = FunctionCall(f.tok, Requires(arity), Bpl.Type.Bool, Concat(tyargs, Cons(h, Cons(fhandle, lhs_args))));\n          Bpl.Expr rhs;\n          if (fromArrowType) {\n            // In case this is the /requires/ or /reads/ function, then there is no precondition\n            rhs = Bpl.Expr.True;\n          } else {\n            var args_h = AlwaysUseHeap || f.ReadsHeap ? Snoc(SnocPrevH(args), h) : args;\n            rhs = FunctionCall(f.tok, RequiresName(f), Bpl.Type.Bool, Concat(SnocSelf(args_h), rhs_args));\n          }\n\n          sink.AddTopLevelDeclaration(new Axiom(f.tok,\n            BplForall(Concat(vars, bvars), BplTrigger(lhs), Bpl.Expr.Eq(lhs, rhs))));\n        }\n\n        {\n          // Reads(Ty.., F#Handle( Ty1, ..., TyN, Layer, self), Heap, arg1, ..., argN)\n          //   =  $Frame_F(args...)\n\n          var fhandle = FunctionCall(f.tok, name, predef.HandleType, SnocSelf(SnocPrevH(args)));\n          Bpl.Expr lhs_inner = FunctionCall(f.tok, Reads(arity), TrType(new SetType(true, program.BuiltIns.ObjectQ())), Concat(tyargs, Cons(h, Cons(fhandle, lhs_args))));\n\n          Bpl.Expr bx; var bxVar = BplBoundVar(\"$bx\", predef.BoxType, out bx);\n          Bpl.Expr unboxBx = FunctionCall(f.tok, BuiltinFunction.Unbox, predef.RefType, bx);\n          Bpl.Expr lhs = Bpl.Expr.SelectTok(f.tok, lhs_inner, bx);\n\n          var et = new ExpressionTranslator(this, predef, h);\n          var rhs = InRWClause_Aux(f.tok, unboxBx, bx, null, f.Reads, false, et, selfExpr, rhs_dict);\n\n          sink.AddTopLevelDeclaration(new Axiom(f.tok,\n            BplForall(Cons(bxVar, Concat(vars, bvars)), BplTrigger(lhs), Bpl.Expr.Eq(lhs, rhs))));\n        }\n\n        {\n          // F(Ty1, .., TyN, Layer, Heap, self, arg1, .., argN)\n          // = [Unbox]Apply1(Ty.., F#Handle( Ty1, ..., TyN, Layer, self), Heap, [Box]arg1, ..., [Box]argN)\n\n          var fhandle = FunctionCall(f.tok, name, predef.HandleType, SnocSelf(SnocPrevH(args)));\n          var args_h = AlwaysUseHeap || f.ReadsHeap ? Snoc(SnocPrevH(args), h) : args;\n          var lhs = FunctionCall(f.tok, f.FullSanitizedName, TrType(f.ResultType), Concat(SnocSelf(args_h), func_args));\n          var rhs = FunctionCall(f.tok, Apply(arity), TrType(f.ResultType), Concat(tyargs, Cons(h, Cons(fhandle, boxed_func_args))));\n          var rhs_unboxed = UnboxIfBoxed(rhs, f.ResultType);\n          var tr = BplTriggerHeap(this, f.tok, lhs, AlwaysUseHeap || f.ReadsHeap ? null : h);\n\n          sink.AddTopLevelDeclaration(new Axiom(f.tok,\n            BplForall(Concat(vars, func_vars), tr, Bpl.Expr.Eq(lhs, rhs_unboxed))));\n        }\n      }\n      return name;\n    }\n\n    private void AddArrowTypeAxioms(ArrowTypeDecl ad) {\n      Contract.Requires(ad != null);\n      var arity = ad.Arity;\n      var tok = ad.tok;\n\n      // [Heap, Box, ..., Box]\n      var map_args = Cons(predef.HeapType, Map(Enumerable.Range(0, arity), i => predef.BoxType));\n      // [Heap, Box, ..., Box] Box\n      var apply_ty = new Bpl.MapType(tok, new List<Bpl.TypeVariable>(), map_args, predef.BoxType);\n      // [Heap, Box, ..., Box] Bool\n      var requires_ty = new Bpl.MapType(tok, new List<Bpl.TypeVariable>(), map_args, Bpl.Type.Bool);\n      // Set Box\n      var objset_ty = TrType(new SetType(true, program.BuiltIns.ObjectQ()));\n      // [Heap, Box, ..., Box] (Set Box)\n      var reads_ty = new Bpl.MapType(tok, new List<Bpl.TypeVariable>(), map_args, objset_ty);\n\n      {\n        // function HandleN([Heap, Box, ..., Box] Box, [Heap, Box, ..., Box] Bool) : HandleType\n        var res = BplFormalVar(null, predef.HandleType, true);\n        var arg = new List<Bpl.Variable> {\n          BplFormalVar(null, apply_ty, true),\n          BplFormalVar(null, requires_ty, true),\n          BplFormalVar(null, reads_ty, true)\n        };\n        sink.AddTopLevelDeclaration(new Bpl.Function(Token.NoToken, Handle(arity), arg, res));\n      }\n\n      Action<string, Bpl.Type> SelectorFunction = (s, t) => {\n        var args = new List<Bpl.Variable>();\n        MapM(Enumerable.Range(0, arity + 1), i => args.Add(BplFormalVar(null, predef.Ty, true)));\n        args.Add(BplFormalVar(null, predef.HeapType, true));\n        args.Add(BplFormalVar(null, predef.HandleType, true));\n        MapM(Enumerable.Range(0, arity), i => args.Add(BplFormalVar(null, predef.BoxType, true)));\n        sink.AddTopLevelDeclaration(new Bpl.Function(Token.NoToken, s, args, BplFormalVar(null, t, false)));\n      };\n\n      // function ApplyN(Ty, ... Ty, HandleType, Heap, Box, ..., Box) : Box\n      if (arity != 1) {  // Apply1 is already declared in DafnyPrelude.bpl\n        SelectorFunction(Apply(arity), predef.BoxType);\n      }\n      // function RequiresN(Ty, ... Ty, HandleType, Heap, Box, ..., Box) : Bool\n      SelectorFunction(Requires(arity), Bpl.Type.Bool);\n      // function ReadsN(Ty, ... Ty, HandleType, Heap, Box, ..., Box) : Set Box\n      SelectorFunction(Reads(arity), objset_ty);\n\n      {\n        // forall t1, .., tN+1 : Ty, p: [Heap, Box, ..., Box] Box, heap : Heap, b1, ..., bN : Box\n        //      :: ApplyN(t1, .. tN+1, heap, HandleN(h, r, rd), b1, ..., bN) == h[heap, b1, ..., bN]\n        //      :: RequiresN(t1, .. tN+1, heap, HandleN(h, r, rd), b1, ..., bN) <== r[heap, b1, ..., bN]\n        //      :: ReadsN(t1, .. tN+1, heap, HandleN(h, r, rd), b1, ..., bN) == rd[heap, b1, ..., bN]\n        Action<string, Bpl.Type, string, Bpl.Type, string, Bpl.Type> SelectorSemantics = (selector, selectorTy, selectorVar, selectorVarTy, precond, precondTy) => {\n          Contract.Assert((precond == null) == (precondTy == null));\n          var bvars = new List<Bpl.Variable>();\n\n          var types = Map(Enumerable.Range(0, arity + 1), i => BplBoundVar(\"t\" + i, predef.Ty, bvars));\n\n          var heap = BplBoundVar(\"heap\", predef.HeapType, bvars);\n\n          var handleargs = new List<Bpl.Expr> {\n            BplBoundVar(\"h\", apply_ty, bvars),\n            BplBoundVar(\"r\", requires_ty, bvars),\n            BplBoundVar(\"rd\", reads_ty, bvars)\n          };\n\n          var boxes = Map(Enumerable.Range(0, arity), i => BplBoundVar(\"bx\" + i, predef.BoxType, bvars));\n\n          var lhsargs = Concat(types, Cons(heap, Cons(FunctionCall(tok, Handle(arity), predef.HandleType, handleargs), boxes)));\n          Bpl.Expr lhs = FunctionCall(tok, selector, selectorTy, lhsargs);\n          Func<Bpl.Expr, Bpl.Expr> pre = x => x;\n          if (precond != null) {\n            pre = x => FunctionCall(tok, precond, precondTy, lhsargs);\n          }\n\n          Bpl.Expr rhs = new Bpl.NAryExpr(tok, new Bpl.MapSelect(tok, arity + 1),\n            Cons(new Bpl.IdentifierExpr(tok, selectorVar, selectorVarTy), Cons(heap, boxes)));\n          Func<Bpl.Expr, Bpl.Expr, Bpl.Expr> op = Bpl.Expr.Eq;\n          if (selectorVar == \"rd\") {\n            var bx = BplBoundVar(\"bx\", predef.BoxType, bvars);\n            lhs = Bpl.Expr.SelectTok(tok, lhs, bx);\n            rhs = Bpl.Expr.SelectTok(tok, rhs, bx);\n            // op = Bpl.Expr.Imp;\n          }\n          if (selectorVar == \"r\") {\n            op = (u, v) => Bpl.Expr.Imp(v, u);\n          }\n          sink.AddTopLevelDeclaration(new Axiom(tok,\n            BplForall(bvars, BplTrigger(lhs), op(lhs, rhs))));\n        };\n        SelectorSemantics(Apply(arity), predef.BoxType, \"h\", apply_ty, Requires(arity), requires_ty);\n        SelectorSemantics(Requires(arity), Bpl.Type.Bool, \"r\", requires_ty, null, null);\n        SelectorSemantics(Reads(arity), objset_ty, \"rd\", reads_ty, null, null);\n\n        // function {:inline true}\n        //   FuncN._requires#canCall(G...G G: Ty, H:Heap, f:Handle, x ... x :Box): bool\n        //   { true }\n        // + similar for Reads\n        Action<string, Function> UserSelectorFunction = (fname, f) => {\n          var formals = new List<Bpl.Variable>();\n          var rhsargs = new List<Bpl.Expr>();\n\n          MapM(Enumerable.Range(0, arity + 1), i => rhsargs.Add(BplFormalVar(\"t\" + i, predef.Ty, true, formals)));\n\n          var heap = BplFormalVar(\"heap\", predef.HeapType, true, formals);\n          rhsargs.Add(heap);\n          rhsargs.Add(BplFormalVar(\"f\", predef.HandleType, true, formals));\n\n          MapM(Enumerable.Range(0, arity), i => rhsargs.Add(BplFormalVar(\"bx\" + i, predef.BoxType, true, formals)));\n\n          sink.AddTopLevelDeclaration(\n            new Bpl.Function(f.tok, f.FullSanitizedName + \"#canCall\", new List<TypeVariable>(), formals,\n              BplFormalVar(null, Bpl.Type.Bool, false), null,\n              new QKeyValue(f.tok, \"inline\", new List<object>(), null)) {\n                Body = Bpl.Expr.True\n              });\n        };\n\n        UserSelectorFunction(Requires(ad.Arity), ad.Requires);\n        UserSelectorFunction(Reads(ad.Arity), ad.Reads);\n\n        // frame axiom\n        /*\n\n          forall t0..tN+1 : Ty, h0, h1 : Heap, f : Handle, bx1 .. bxN : Box,\n            HeapSucc(h0, h1) && GoodHeap(h0) && GoodHeap(h1)\n            && Is[&IsAllocBox](bxI, tI, h0)              // in h0, not hN\n            && Is[&IsAlloc](f, Func(t1,..,tN, tN+1), h0) // in h0, not hN\n            &&\n            (forall o : ref::\n                 o != null [&& h0[o, alloc] && h1[o, alloc] &&]\n                 Reads(h,hN,bxs)[Box(o)]             // for hN in h0 and h1\n              ==> h0[o,field] == h1[o,field])\n          ==>  Reads(..h0..) == Reads(..h1..)\n           AND Requires(f,h0,bxs) == Requires(f,h1,bxs) // which is needed for the next\n           AND  Apply(f,h0,bxs) == Apply(f,h0,bxs)\n\n           The [...] expressions are omitted for /allocated:0 and /allocated:1:\n             - in these modes, functions are pure values and IsAlloc of a function is trivially true\n             - o may be unallocated even if f reads it, so we require a stronger condition that\n               even fields of *unallocated* objects o are unchanged from h0 to h1\n             - given this stronger condition, we can say that f(bx1...bxN) does not change from h0 to h1\n               even if some of bx1...bxN are unallocated\n             - it's harder to satisfy the stronger condition, but two cases are nevertheless useful:\n               1) f has an empty reads clause\n               2) f explictly states that everything is its reads clause is allocated\n         */\n        {\n          var bvars = new List<Bpl.Variable>();\n\n          var types = Map(Enumerable.Range(0, arity + 1), i => BplBoundVar(\"t\" + i, predef.Ty, bvars));\n\n          var h0 = BplBoundVar(\"h0\", predef.HeapType, bvars);\n          var h1 = BplBoundVar(\"h1\", predef.HeapType, bvars);\n          var heapSucc = HeapSucc(h0, h1);\n          var goodHeaps = BplAnd(\n            FunctionCall(tok, BuiltinFunction.IsGoodHeap, null, h0),\n            FunctionCall(tok, BuiltinFunction.IsGoodHeap, null, h1));\n\n          var f = BplBoundVar(\"f\", predef.HandleType, bvars);\n          var boxes = Map(Enumerable.Range(0, arity), i => BplBoundVar(\"bx\" + i, predef.BoxType, bvars));\n\n          var isness = BplAnd(\n            Snoc(Map(Enumerable.Range(0, arity), i =>\n              BplAnd(MkIs(boxes[i], types[i], true),\n                CommonHeapUse && !FrugalHeapUse ? MkIsAlloc(boxes[i], types[i], h0, true) : Bpl.Expr.True)),\n            BplAnd(MkIs(f, ClassTyCon(ad, types)),\n              CommonHeapUse && !FrugalHeapUse ? MkIsAlloc(f, ClassTyCon(ad, types), h0) : Bpl.Expr.True)));\n\n          Action<Bpl.Expr, string> AddFrameForFunction = (hN, fname) => {\n\n            // inner forall vars\n            var ivars = new List<Bpl.Variable>();\n            var o = BplBoundVar(\"o\", predef.RefType, ivars);\n            var a = new TypeVariable(tok, \"a\");\n            var fld = BplBoundVar(\"fld\", predef.FieldName(tok, a), ivars);\n\n            var inner_forall = new Bpl.ForallExpr(tok, Singleton(a), ivars, BplImp(\n              BplAnd(\n                Bpl.Expr.Neq(o, predef.Null),\n                // Note, the MkIsAlloc conjunct of \"isness\" implies that everything in the reads frame is allocated in \"h0\", which by HeapSucc(h0,h1) also implies the frame is allocated in \"h1\"\n                new Bpl.NAryExpr(tok, new Bpl.MapSelect(tok, 1), new List<Bpl.Expr> {\n                  FunctionCall(tok, Reads(ad.Arity), objset_ty, Concat(types, Cons(hN, Cons(f, boxes)))),\n                  FunctionCall(tok, BuiltinFunction.Box, null, o)\n                })\n              ),\n              Bpl.Expr.Eq(ReadHeap(tok, h0, o, fld), ReadHeap(tok, h1, o, fld))));\n\n            Func<Bpl.Expr, Bpl.Expr> fn = h => FunctionCall(tok, fname, Bpl.Type.Bool, Concat(types, Cons(h, Cons<Bpl.Expr>(f, boxes))));\n\n            sink.AddTopLevelDeclaration(new Axiom(tok,\n              BplForall(bvars,\n                new Bpl.Trigger(tok, true, new List<Bpl.Expr> { heapSucc, fn(h1) }),\n                BplImp(\n                  BplAnd(BplAnd(BplAnd(heapSucc, goodHeaps), isness), inner_forall),\n                  Bpl.Expr.Eq(fn(h0), fn(h1)))), \"frame axiom for \" + fname));\n          };\n\n          AddFrameForFunction(h0, Reads(ad.Arity));\n          AddFrameForFunction(h1, Reads(ad.Arity));\n          AddFrameForFunction(h0, Requires(ad.Arity));\n          AddFrameForFunction(h1, Requires(ad.Arity));\n          AddFrameForFunction(h0, Apply(ad.Arity));\n          AddFrameForFunction(h1, Apply(ad.Arity));\n        }\n\n        /* axiom (forall T..: Ty, heap: Heap, f: HandleType, bx..: Box ::\n         *   { ReadsN(T.., $OneHeap, f, bx..), $IsGoodHeap(heap) }\n         *   { ReadsN(T.., heap, f, bx..) }\n         *   $IsGoodHeap(heap) && Is...(f...bx...) ==>\n         *   Set#Equal(ReadsN(T.., OneHeap, f, bx..), EmptySet) == Set#Equal(ReadsN(T.., heap, f, bx..), EmptySet));\n         */\n        {\n          var bvars = new List<Bpl.Variable>();\n          var types = Map(Enumerable.Range(0, arity + 1), i => BplBoundVar(\"t\" + i, predef.Ty, bvars));\n          var oneheap = new Bpl.IdentifierExpr(tok, \"$OneHeap\", predef.HeapType);\n          var h = BplBoundVar(\"heap\", predef.HeapType, bvars);\n          var f = BplBoundVar(\"f\", predef.HandleType, bvars);\n          var boxes = Map(Enumerable.Range(0, arity), i => BplBoundVar(\"bx\" + i, predef.BoxType, bvars));\n\n          var goodHeap = FunctionCall(tok, BuiltinFunction.IsGoodHeap, null, h);\n\n          var isness = BplAnd(\n            Snoc(Map(Enumerable.Range(0, arity), i =>\n              BplAnd(MkIs(boxes[i], types[i], true),\n                CommonHeapUse && !FrugalHeapUse ? MkIsAlloc(boxes[i], types[i], h, true) : Bpl.Expr.True)),\n            BplAnd(MkIs(f, ClassTyCon(ad, types)),\n              CommonHeapUse && !FrugalHeapUse ? MkIsAlloc(f, ClassTyCon(ad, types), h) : Bpl.Expr.True)));\n\n          var readsOne = FunctionCall(tok, Reads(arity), objset_ty, Concat(types, Cons(oneheap, Cons(f, boxes))));\n          var readsH = FunctionCall(tok, Reads(arity), objset_ty, Concat(types, Cons(h, Cons(f, boxes))));\n          var empty = FunctionCall(tok, BuiltinFunction.SetEmpty, predef.BoxType);\n          var readsNothingOne = FunctionCall(tok, BuiltinFunction.SetEqual, null, readsOne, empty);\n          var readsNothingH = FunctionCall(tok, BuiltinFunction.SetEqual, null, readsH, empty);\n\n          sink.AddTopLevelDeclaration(new Axiom(tok, BplForall(bvars,\n            new Bpl.Trigger(tok, true, new List<Bpl.Expr> { readsOne, goodHeap },\n            new Bpl.Trigger(tok, true, new List<Bpl.Expr> { readsH })),\n            BplImp(\n              BplAnd(goodHeap, isness),\n              BplIff(readsNothingOne, readsNothingH))),\n            string.Format(\"empty-reads property for {0} \", Reads(arity))));\n        }\n\n        /* axiom (forall T..: Ty, heap: Heap, f: HandleType, bx..: Box ::\n         *   { RequiresN(T.., OneHeap, f, bx..), $IsGoodHeap(heap) }\n         *   { RequiresN(T.., heap, f, bx..) }\n         *   $IsGoodHeap(heap) && Is...(f...bx...) &&\n         *   Set#Equal(ReadsN(T.., OneHeap, f, bx..), EmptySet)\n         *   ==>\n         *   RequiresN(T.., OneHeap, f, bx..) == RequiresN(T.., heap, f, bx..));\n         */\n        {\n          var bvars = new List<Bpl.Variable>();\n          var types = Map(Enumerable.Range(0, arity + 1), i => BplBoundVar(\"t\" + i, predef.Ty, bvars));\n          var oneheap = new Bpl.IdentifierExpr(tok, \"$OneHeap\", predef.HeapType);\n          var h = BplBoundVar(\"heap\", predef.HeapType, bvars);\n          var f = BplBoundVar(\"f\", predef.HandleType, bvars);\n          var boxes = Map(Enumerable.Range(0, arity), i => BplBoundVar(\"bx\" + i, predef.BoxType, bvars));\n\n          var goodHeap = FunctionCall(tok, BuiltinFunction.IsGoodHeap, null, h);\n\n          var isness = BplAnd(\n            Snoc(Map(Enumerable.Range(0, arity), i =>\n              BplAnd(MkIs(boxes[i], types[i], true),\n                CommonHeapUse && !FrugalHeapUse ? MkIsAlloc(boxes[i], types[i], h, true) : Bpl.Expr.True)),\n            BplAnd(MkIs(f, ClassTyCon(ad, types)),\n              CommonHeapUse && !FrugalHeapUse ? MkIsAlloc(f, ClassTyCon(ad, types), h) : Bpl.Expr.True)));\n\n          var readsOne = FunctionCall(tok, Reads(arity), objset_ty, Concat(types, Cons(oneheap, Cons(f, boxes))));\n          var empty = FunctionCall(tok, BuiltinFunction.SetEmpty, predef.BoxType);\n          var readsNothingOne = FunctionCall(tok, BuiltinFunction.SetEqual, null, readsOne, empty);\n\n          var requiresOne = FunctionCall(tok, Requires(arity), Bpl.Type.Bool, Concat(types, Cons(oneheap, Cons(f, boxes))));\n          var requiresH = FunctionCall(tok, Requires(arity), Bpl.Type.Bool, Concat(types, Cons(h, Cons(f, boxes))));\n\n          sink.AddTopLevelDeclaration(new Axiom(tok, BplForall(bvars,\n            new Bpl.Trigger(tok, true, new List<Bpl.Expr> { requiresOne, goodHeap },\n            new Bpl.Trigger(tok, true, new List<Bpl.Expr> { requiresH })),\n            BplImp(\n              BplAnd(BplAnd(goodHeap, isness), readsNothingOne),\n              Bpl.Expr.Eq(requiresOne, requiresH))),\n            string.Format(\"empty-reads property for {0}\", Requires(arity))));\n        }\n\n        // $Is and $IsAlloc axioms\n        /*\n          axiom (forall f: HandleType, t0: Ty, t1: Ty ::\n            { $Is(f, Tclass._System.___hFunc1(t0, t1)) }\n            $Is(f, Tclass._System.___hFunc1(t0, t1))\n               <==> (forall h: Heap, bx0: Box ::\n                 { Apply1(t0, t1, f, h, bx0) }\n                 $IsGoodHeap(h) && $IsBox(bx0, t0)\n                 && precondition of f(bx0) holds in h\n                 ==> $IsBox(Apply1(t0, t1, f, h, bx0), t1)));\n        */\n        {\n          var bvarsOuter = new List<Bpl.Variable>();\n          var f = BplBoundVar(\"f\", predef.HandleType, bvarsOuter);\n          var types = Map(Enumerable.Range(0, arity + 1), i => BplBoundVar(\"t\" + i, predef.Ty, bvarsOuter));\n          var Is = MkIs(f, ClassTyCon(ad, types));\n\n          var bvarsInner = new List<Bpl.Variable>();\n          var h = BplBoundVar(\"h\", predef.HeapType, bvarsInner);\n          var boxes = Map(Enumerable.Range(0, arity), i => BplBoundVar(\"bx\" + i, predef.BoxType, bvarsInner));\n          var goodHeap = FunctionCall(tok, BuiltinFunction.IsGoodHeap, null, h);\n          var isBoxes = BplAnd(Map(Enumerable.Range(0, arity), i => MkIs(boxes[i], types[i], true)));\n          var pre = FunctionCall(tok, Requires(ad.Arity), predef.BoxType, Concat(types, Cons(h, Cons<Bpl.Expr>(f, boxes))));\n          var applied = FunctionCall(tok, Apply(ad.Arity), predef.BoxType, Concat(types, Cons(h, Cons<Bpl.Expr>(f, boxes))));\n          var applied_is = MkIs(applied, types[ad.Arity], true);\n\n          sink.AddTopLevelDeclaration(new Axiom(tok,\n            BplForall(bvarsOuter, BplTrigger(Is),\n              BplIff(Is,\n                BplForall(bvarsInner, BplTrigger(applied),\n                  BplImp(BplAnd(BplAnd(goodHeap, isBoxes), pre), applied_is))))));\n        }\n        /*\n           axiom (forall f: HandleType, t0: Ty, t1: Ty, u0: Ty, u1: Ty ::\n             { $Is(f, Tclass._System.___hFunc1(t0, t1)), $Is(f, Tclass._System.___hFunc1(u0, u1)) }\n             $Is(f, Tclass._System.___hFunc1(t0, t1)) &&\n             (forall bx: Box :: { $IsBox(bx, u0), $IsBox(bx, t0) }\n                 $IsBox(bx, u0) ==> $IsBox(bx, t0)) &&  // contravariant arguments\n             (forall bx: Box :: { $IsBox(bx, t1), $IsBox(bx, u1) }\n                 $IsBox(bx, t1) ==> $IsBox(bx, u1))     // covariant result\n             ==>\n             $Is(f, Tclass._System.___hFunc1(u0, u1)));\n        */\n        {\n          var bvarsOuter = new List<Bpl.Variable>();\n          var f = BplBoundVar(\"f\", predef.HandleType, bvarsOuter);\n          var typesT = Map(Enumerable.Range(0, arity + 1), i => BplBoundVar(\"t\" + i, predef.Ty, bvarsOuter));\n          var IsT = MkIs(f, ClassTyCon(ad, typesT));\n          var typesU = Map(Enumerable.Range(0, arity + 1), i => BplBoundVar(\"u\" + i, predef.Ty, bvarsOuter));\n          var IsU = MkIs(f, ClassTyCon(ad, typesU));\n\n          Func<Expr, Expr, Expr> Inner = (a, b) => {\n            var bvarsInner = new List<Bpl.Variable>();\n            var bx = BplBoundVar(\"bx\", predef.BoxType, bvarsInner);\n            var isBoxA = MkIs(bx, a, true);\n            var isBoxB = MkIs(bx, b, true);\n            var tr = new Bpl.Trigger(tok, true, new[] { isBoxA }, new Bpl.Trigger(tok, true, new[] { isBoxB }));\n            var imp = BplImp(isBoxA, isBoxB);\n            return BplForall(bvarsInner, tr, imp);\n          };\n\n          var body = IsT;\n          for (int i = 0; i < arity; i++) {\n            body = BplAnd(body, Inner(typesU[i], typesT[i]));\n          }\n          body = BplAnd(body, Inner(typesT[arity], typesU[arity]));\n          body = BplImp(body, IsU);\n          sink.AddTopLevelDeclaration(new Axiom(tok,\n            BplForall(bvarsOuter, new Bpl.Trigger(tok, true, new[] { IsT, IsU }), body)));\n        }\n        /*  This is the definition of $IsAlloc function the arrow type:\n          axiom (forall f: HandleType, t0: Ty, t1: Ty, h: Heap ::\n            { $IsAlloc(f, Tclass._System.___hFunc1(t0, t1), h) }\n            $IsGoodHeap(h)\n            ==>\n            (\n              $IsAlloc(f, Tclass._System.___hFunc1(t0, t1), h)\n                <==>\n                (forall bx0: Box ::\n                  { Apply1(t0, t1, f, h, bx0) } { Reads1(t0, t1, f, h, bx0) }\n                  $IsBox(bx0, t0) && $IsAllocBox(bx0, t0, h)\n                  && precondition of f(bx0) holds in h\n                  ==>\n                    (everything in reads set of f(bx0) is allocated in h)\n            ));\n          However, for /allocated:0 and /allocated:1, IsAlloc for arrow types is trivially true\n          and implies nothing about the reads set.\n        */\n        {\n          var bvarsOuter = new List<Bpl.Variable>();\n          var f = BplBoundVar(\"f\", predef.HandleType, bvarsOuter);\n          var types = Map(Enumerable.Range(0, arity + 1), i => BplBoundVar(\"t\" + i, predef.Ty, bvarsOuter));\n          var h = BplBoundVar(\"h\", predef.HeapType, bvarsOuter);\n          var goodHeap = FunctionCall(tok, BuiltinFunction.IsGoodHeap, null, h);\n          var isAlloc = MkIsAlloc(f, ClassTyCon(ad, types), h);\n\n          var bvarsInner = new List<Bpl.Variable>();\n          var boxes = Map(Enumerable.Range(0, arity), i => BplBoundVar(\"bx\" + i, predef.BoxType, bvarsInner));\n          var isAllocBoxes = BplAnd(Map(Enumerable.Range(0, arity), i =>\n            BplAnd(MkIs(boxes[i], types[i], true), MkIsAlloc(boxes[i], types[i], h, true))));\n          var pre = FunctionCall(tok, Requires(ad.Arity), predef.BoxType, Concat(types, Cons(h, Cons<Bpl.Expr>(f, boxes))));\n          var applied = FunctionCall(tok, Apply(ad.Arity), predef.BoxType, Concat(types, Cons(h, Cons<Bpl.Expr>(f, boxes))));\n\n          // (forall r: ref :: {Reads1(t0, t1, f, h, bx0)[$Box(r)]}  r != null && Reads1(t0, t1, f, h, bx0)[$Box(r)] ==> h[r, alloc])\n          var bvarsR = new List<Bpl.Variable>();\n          var r = BplBoundVar(\"r\", predef.RefType, bvarsR);\n          var rNonNull = Bpl.Expr.Neq(r, predef.Null);\n          var reads = FunctionCall(tok, Reads(ad.Arity), predef.BoxType, Concat(types, Cons(h, Cons<Bpl.Expr>(f, boxes))));\n          var rInReads = Bpl.Expr.Select(reads, FunctionCall(tok, BuiltinFunction.Box, null, r));\n          var rAlloc = IsAlloced(tok, h, r);\n          var isAllocReads = BplForall(bvarsR, BplTrigger(rInReads), BplImp(BplAnd(rNonNull, rInReads), rAlloc));\n\n          sink.AddTopLevelDeclaration(new Axiom(tok,\n            BplForall(bvarsOuter, BplTrigger(isAlloc),\n              BplImp(goodHeap,\n                BplIff(isAlloc, !CommonHeapUse ? Bpl.Expr.True :\n                  BplForall(bvarsInner,\n                    new Bpl.Trigger(tok, true, new List<Bpl.Expr> { applied }, BplTrigger(reads)),\n                    BplImp(BplAnd(isAllocBoxes, pre), isAllocReads)))))));\n        }\n        /*  This is the allocatedness consequence axiom of arrow types:\n          axiom (forall f: HandleType, t0: Ty, t1: Ty, h: Heap ::\n            { $IsAlloc(f, Tclass._System.___hFunc1(t0, t1), h) }\n            $IsGoodHeap(h) &&\n            $IsAlloc(f, Tclass._System.___hFunc1(t0, t1), h)\n            ==>\n                (forall bx0: Box ::\n                  { Apply1(t0, t1, f, h, bx0) }\n                  $IsAllocBox(bx0, t0, h)\n                  && precondition of f(bx0) holds in h\n                  ==>\n                    $IsAllocBox(Apply1(t0, t1, f, h, bx0), t1, h))\n            ));\n        */\n        if (CommonHeapUse) {\n          var bvarsOuter = new List<Bpl.Variable>();\n          var f = BplBoundVar(\"f\", predef.HandleType, bvarsOuter);\n          var types = Map(Enumerable.Range(0, arity + 1), i => BplBoundVar(\"t\" + i, predef.Ty, bvarsOuter));\n          var h = BplBoundVar(\"h\", predef.HeapType, bvarsOuter);\n          var goodHeap = FunctionCall(tok, BuiltinFunction.IsGoodHeap, null, h);\n          var isAlloc = MkIsAlloc(f, ClassTyCon(ad, types), h);\n\n          var bvarsInner = new List<Bpl.Variable>();\n          var boxes = Map(Enumerable.Range(0, arity), i => BplBoundVar(\"bx\" + i, predef.BoxType, bvarsInner));\n          var isAllocBoxes = BplAnd(Map(Enumerable.Range(0, arity), i => MkIsAlloc(boxes[i], types[i], h, true)));\n          var pre = FunctionCall(tok, Requires(ad.Arity), predef.BoxType, Concat(types, Cons(h, Cons<Bpl.Expr>(f, boxes))));\n          var applied = FunctionCall(tok, Apply(ad.Arity), predef.BoxType, Concat(types, Cons(h, Cons<Bpl.Expr>(f, boxes))));\n          var applied_isAlloc = MkIsAlloc(applied, types[ad.Arity], h, true);\n\n          sink.AddTopLevelDeclaration(new Axiom(tok,\n            BplForall(bvarsOuter, BplTrigger(isAlloc),\n              BplImp(BplAnd(goodHeap, isAlloc),\n                BplForall(bvarsInner, BplTrigger(applied),\n                  BplImp(BplAnd(isAllocBoxes, pre), applied_isAlloc))))));\n        }\n      }\n    }\n\n    private string AddTyAxioms(TopLevelDecl td) {\n      Contract.Requires(td != null);\n      IToken tok = td.tok;\n\n      var ty_repr = TrType(UserDefinedType.FromTopLevelDecl(td.tok, td));\n      var arity = td.TypeArgs.Count;\n      var inner_name = GetClass(td).TypedIdent.Name;\n      string name = \"T\" + inner_name;\n      // Create the type constructor\n      if (!(td is ClassDecl && td.Name == \"object\")) {  // the type constructor for \"object\" is in DafnyPrelude.bpl\n        Bpl.Variable tyVarOut = BplFormalVar(null, predef.Ty, false);\n        List<Bpl.Variable> args = new List<Bpl.Variable>(\n          Enumerable.Range(0, arity).Select(i =>\n            (Bpl.Variable)BplFormalVar(null, predef.Ty, true)));\n        var func = new Bpl.Function(tok, name, args, tyVarOut);\n        sink.AddTopLevelDeclaration(func);\n      }\n\n      // Helper action to create variables and the function call.\n      Action<Action<List<Bpl.Expr>, List<Bpl.Variable>, Bpl.Expr>> Helper = K => {\n        List<Bpl.Expr> argExprs;\n        var args = MkTyParamBinders(td.TypeArgs, out argExprs);\n        var inner = FunctionCall(tok, name, predef.Ty, argExprs);\n        K(argExprs, args, inner);\n      };\n\n      // Create the Tag and calling Tag on this type constructor\n      /*\n         const unique TagList: TyTag;\n         axiom (forall t0: Ty :: { List(t0) } Tag(List(t0)) == TagList);\n      */\n      Helper((argExprs, args, inner) => {\n        Bpl.TypedIdent tag_id = new Bpl.TypedIdent(tok, \"Tag\" + inner_name, predef.TyTag);\n        Bpl.Constant tag = new Bpl.Constant(tok, tag_id, true);\n        Bpl.Expr tag_expr = new Bpl.IdentifierExpr(tok, tag);\n        Bpl.Expr tag_call = FunctionCall(tok, \"Tag\", predef.TyTag, inner);\n        Bpl.Expr qq = BplForall(args, BplTrigger(inner), Bpl.Expr.Eq(tag_call, tag_expr));\n        sink.AddTopLevelDeclaration(new Axiom(tok, qq, name + \" Tag\"));\n        sink.AddTopLevelDeclaration(tag);\n      });\n\n      // Create the injectivity axiom and its function\n      /*\n         function List_0(Ty) : Ty;\n         axiom (forall t0: Ty :: { List(t0) } List_0(List(t0)) == t0);\n      */\n      for (int i = 0; i < arity; i++) {\n        Helper((argExprs, args, inner) => {\n          Bpl.Variable tyVarIn = BplFormalVar(null, predef.Ty, true);\n          Bpl.Variable tyVarOut = BplFormalVar(null, predef.Ty, false);\n          var injname = name + \"_\" + i;\n          var injfunc = new Bpl.Function(tok, injname, Singleton(tyVarIn), tyVarOut);\n          var outer = FunctionCall(tok, injname, args[i].TypedIdent.Type, inner);\n          Bpl.Expr qq = BplForall(args, BplTrigger(inner), Bpl.Expr.Eq(outer, argExprs[i]));\n          sink.AddTopLevelDeclaration(new Axiom(tok, qq, name + \" injectivity \" + i));\n          sink.AddTopLevelDeclaration(injfunc);\n        });\n      }\n\n      // Boxing axiom (important for the properties of unbox)\n      /*\n         axiom (forall T: Ty, bx: Box ::\n           { $IsBox(bx, List(T)) }\n           $IsBox(bx, List(T))\n              ==> $Box($Unbox(bx): DatatypeType) == bx\n               && $Is($Unbox(bx): DatatypeType, List(T)));\n      */\n      if (!ModeledAsBoxType(UserDefinedType.FromTopLevelDecl(td.tok, td))) {\n        Helper((argExprs, args, _inner) => {\n          Bpl.Expr bx; var bxVar = BplBoundVar(\"bx\", predef.BoxType, out bx);\n          var ty = FunctionCall(tok, name, predef.Ty, argExprs);\n          var unbox = FunctionCall(tok, BuiltinFunction.Unbox, ty_repr, bx);\n          var box_is = MkIs(bx, ty, true);\n          var unbox_is = MkIs(unbox, ty, false);\n          var box_unbox = FunctionCall(tok, BuiltinFunction.Box, null, unbox);\n          sink.AddTopLevelDeclaration(\n            new Axiom(tok,\n              BplForall(Snoc(args, bxVar), BplTrigger(box_is),\n                BplImp(box_is, BplAnd(Bpl.Expr.Eq(box_unbox, bx), unbox_is))),\n              \"Box/unbox axiom for \" + name));\n        });\n      }\n\n      return name;\n    }\n\n    Bpl.Constant GetClass(TopLevelDecl cl)\n    {\n      Contract.Requires(cl != null);\n      Contract.Requires(predef != null);\n      Contract.Ensures(Contract.Result<Bpl.Constant>() != null);\n\n      Bpl.Constant cc;\n      if (classes.TryGetValue(cl, out cc)) {\n        Contract.Assert(cc != null);\n      } else {\n        var name = cl.FullSanitizedName;\n        if (cl is ClassDecl && ((ClassDecl)cl).NonNullTypeDecl != null) {\n          name = name + \"?\";  // TODO: this doesn't seem like the best place to do this name transformation\n        }\n        cc = new Bpl.Constant(cl.tok, new Bpl.TypedIdent(cl.tok, \"class.\" + name, predef.ClassNameType), !cl.Module.IsFacade);\n        classes.Add(cl, cc);\n      }\n      return cc;\n    }\n\n    Bpl.Constant GetFieldNameFamily(string n) {\n      Contract.Requires(n != null);\n      Contract.Requires(predef != null);\n      Contract.Ensures(Contract.Result<Bpl.Constant>() != null);\n      Bpl.Constant cc;\n      if (fieldConstants.TryGetValue(n, out cc)) {\n        Contract.Assert(cc != null);\n      } else {\n        cc = new Bpl.Constant(Token.NoToken, new Bpl.TypedIdent(Token.NoToken, \"field$\" + n, predef.NameFamilyType), true);\n        fieldConstants.Add(n, cc);\n      }\n      return cc;\n    }\n\n    Bpl.Constant GetField(Field f)\n    {\n      Contract.Requires(f != null && f.IsMutable);\n      Contract.Requires(sink != null && predef != null);\n      Contract.Ensures(Contract.Result<Bpl.Constant>() != null);\n\n      Contract.Assert(VisibleInScope(f));\n\n      Bpl.Constant fc;\n      if (fields.TryGetValue(f, out fc)) {\n        Contract.Assert(fc != null);\n      } else {\n        // const f: Field ty;\n        Bpl.Type ty = predef.FieldName(f.tok, TrType(f.Type));\n        fc = new Bpl.Constant(f.tok, new Bpl.TypedIdent(f.tok, f.FullSanitizedName, ty), false);\n        fields.Add(f, fc);\n        // axiom FDim(f) == 0 && FieldOfDecl(C, name) == f &&\n        //       $IsGhostField(f);    // if the field is a ghost field\n        // OR:\n        //       !$IsGhostField(f);    // if the field is not a ghost field\n        Bpl.Expr fdim = Bpl.Expr.Eq(FunctionCall(f.tok, BuiltinFunction.FDim, ty, Bpl.Expr.Ident(fc)), Bpl.Expr.Literal(0));\n        Bpl.Expr declType = Bpl.Expr.Eq(FunctionCall(f.tok, BuiltinFunction.FieldOfDecl, ty, new Bpl.IdentifierExpr(f.tok, GetClass(cce.NonNull(f.EnclosingClass))), new Bpl.IdentifierExpr(f.tok, GetFieldNameFamily(f.Name))), Bpl.Expr.Ident(fc));\n        Bpl.Expr cond = Bpl.Expr.And(fdim, declType);\n        var ig = FunctionCall(f.tok, BuiltinFunction.IsGhostField, ty, Bpl.Expr.Ident(fc));\n        cond = Bpl.Expr.And(cond, f.IsGhost ? ig : Bpl.Expr.Not(ig));\n        Bpl.Axiom ax = new Bpl.Axiom(f.tok, cond);\n        sink.AddTopLevelDeclaration(ax);\n      }\n      return fc;\n    }\n\n\n    Bpl.Function GetReadonlyField(Field f)\n    {\n      Contract.Requires(f != null && !f.IsMutable);\n      Contract.Requires(sink != null && predef != null);\n      Contract.Ensures(Contract.Result<Bpl.Function>() != null);\n\n      Contract.Assert(VisibleInScope(f));\n\n      Bpl.Function ff;\n      if (fieldFunctions.TryGetValue(f, out ff)) {\n        Contract.Assert(ff != null);\n      } else {\n        // Here are some built-in functions defined in \"predef\" (so there's no need to cache them in \"fieldFunctions\")\n        if (f.EnclosingClass is ArrayClassDecl && f.Name == \"Length\") {\n          return predef.ArrayLength;\n        } else if (f.EnclosingClass == null && f.Name == \"Floor\") {\n          return predef.RealFloor;\n        } else if (f is SpecialField && (f.Name == \"Keys\" || f.Name == \"Values\" || f.Name == \"Items\")) {\n          Contract.Assert(f.Type is SetType);\n          var setType = (SetType)f.Type;\n          if (f.Name == \"Keys\") {\n            return setType.Finite ? predef.MapDomain : predef.IMapDomain;\n          } else if (f.Name == \"Values\") {\n            return setType.Finite ? predef.MapValues : predef.IMapValues;\n          } else {\n            return setType.Finite ? predef.MapItems : predef.IMapItems;\n          }\n        } else if (f is SpecialField && f.Name == \"IsLimit\") {\n          return predef.ORDINAL_IsLimit;\n        } else if (f is SpecialField && f.Name == \"IsSucc\") {\n          return predef.ORDINAL_IsSucc;\n        } else if (f is SpecialField && f.Name == \"Offset\") {\n          return predef.ORDINAL_Offset;\n        } else if (f is SpecialField && f.Name == \"IsNat\") {\n          return predef.ORDINAL_IsNat;\n        } else if (f.FullSanitizedName == \"_System.Tuple2._0\") {\n          return predef.Tuple2Destructors0;\n        } else if (f.FullSanitizedName == \"_System.Tuple2._1\") {\n          return predef.Tuple2Destructors1;\n        }\n\n        // Create a new function\n        // function f(Ref): ty;\n        List<Variable> formals = new List<Variable>();\n        if (f is ConstantField) {\n          formals.AddRange(MkTyParamFormals(GetTypeParams(f.EnclosingClass)));\n        }\n        if (!f.IsStatic) {\n          var udt = UserDefinedType.FromTopLevelDecl(f.tok, f.EnclosingClass);\n          Bpl.Type receiverType = TrType(udt);\n          formals.Add(new Bpl.Formal(f.tok, new Bpl.TypedIdent(f.tok, f is ConstantField ? \"this\" : Bpl.TypedIdent.NoName, receiverType), true));\n        }\n        Bpl.Formal result = new Bpl.Formal(f.tok, new Bpl.TypedIdent(f.tok, Bpl.TypedIdent.NoName, TrType(f.Type)), false);\n        var inlineAttribute = f.IsInstanceIndependentConstant ? new QKeyValue(f.tok, \"inline\", new List<object>(), null) : null;\n        ff = new Bpl.Function(f.tok, f.FullSanitizedName, new List<TypeVariable>(), formals, result, null, inlineAttribute);\n\n        if (InsertChecksums) {\n          var dt = f.EnclosingClass as DatatypeDecl;\n          if (dt != null) {\n            InsertChecksum(dt, ff);\n          }\n          // TODO(wuestholz): Do we need to handle more cases?\n        }\n\n        // add the newly created function to the cache, so that there will only be one copy of it\n        fieldFunctions.Add(f, ff);\n\n        // declare function among Boogie top-level declarations, if needed, and treat certain fields specially\n        if (f is ConstantField) {\n          // declare the function with its initial value, if any\n          // function QQ():int { 3 }\n          var cf = (ConstantField)f;\n          if (cf.Rhs != null && RevealedInScope(cf)) {\n            var etran = new ExpressionTranslator(this, predef, (Bpl.Expr)null);\n            ff.Body = etran.TrExpr(cf.Rhs);\n          }\n          sink.AddTopLevelDeclaration(ff);\n\n        } else if (f.EnclosingClass is ArrayClassDecl) {\n          // add non-negative-range axioms for array Length fields\n          // axiom (forall o: Ref :: 0 <= array.Length(o));\n          Bpl.BoundVariable oVar = new Bpl.BoundVariable(f.tok, new Bpl.TypedIdent(f.tok, \"o\", predef.RefType));\n          Bpl.IdentifierExpr o = new Bpl.IdentifierExpr(f.tok, oVar);\n          var rhs = new Bpl.NAryExpr(f.tok, new Bpl.FunctionCall(ff), new List<Bpl.Expr> { o });\n          Bpl.Expr body = Bpl.Expr.Le(Bpl.Expr.Literal(0), rhs);\n          var trigger = BplTrigger(rhs);\n          Bpl.Expr qq = new Bpl.ForallExpr(f.tok, new List<Variable> { oVar }, trigger, body);\n          sink.AddTopLevelDeclaration(new Bpl.Axiom(f.tok, qq));\n        }\n      }\n      return ff;\n    }\n\n    Bpl.Expr GetField(MemberSelectExpr fse)\n    {\n      Contract.Requires(fse != null);\n      Contract.Requires(fse.Member != null && fse.Member is Field && ((Field)(fse.Member)).IsMutable);\n      Contract.Ensures(Contract.Result<Bpl.Expr>() != null);\n\n      return new Bpl.IdentifierExpr(fse.tok, GetField((Field)fse.Member));\n    }\n\n    /// <summary>\n    /// This method is expected to be called just once for each function in the program.\n    /// </summary>\n    void AddFunction(Function f) {\n      Contract.Requires(f != null);\n      Contract.Requires(predef != null && sink != null);\n\n      // declare the function\n      if (!f.IsBuiltin) {\n        var formals = new List<Variable>();\n        formals.AddRange(MkTyParamFormals(GetTypeParams(f)));\n        if (f.IsFuelAware()) {\n          formals.Add(new Bpl.Formal(f.tok, new Bpl.TypedIdent(f.tok, \"$ly\", predef.LayerType), true));\n        }\n        if (f is TwoStateFunction) {\n          formals.Add(new Bpl.Formal(f.tok, new Bpl.TypedIdent(f.tok, \"$prevHeap\", predef.HeapType), true));\n        }\n        if (AlwaysUseHeap || f.ReadsHeap) {\n          formals.Add(new Bpl.Formal(f.tok, new Bpl.TypedIdent(f.tok, \"$heap\", predef.HeapType), true));\n        }\n        if (!f.IsStatic) {\n          formals.Add(new Bpl.Formal(f.tok, new Bpl.TypedIdent(f.tok, \"this\", TrReceiverType(f)), true));\n        }\n        foreach (var p in f.Formals) {\n          formals.Add(new Bpl.Formal(p.tok, new Bpl.TypedIdent(p.tok, p.AssignUniqueName(f.IdGenerator), TrType(p.Type)), true));\n        }\n        var res = new Bpl.Formal(f.tok, new Bpl.TypedIdent(f.tok, Bpl.TypedIdent.NoName, TrType(f.ResultType)), false);\n        var func = new Bpl.Function(f.tok, f.FullSanitizedName, new List<Bpl.TypeVariable>(), formals, res, \"function declaration for \" + f.FullName);\n        if (InsertChecksums) {\n          InsertChecksum(f, func);\n        }\n        sink.AddTopLevelDeclaration(func);\n      }\n\n      // declare the corresponding canCall function\n      {\n        var formals = new List<Variable>();\n        formals.AddRange(MkTyParamFormals(GetTypeParams(f)));\n        if (f is TwoStateFunction) {\n          formals.Add(new Bpl.Formal(f.tok, new Bpl.TypedIdent(f.tok, \"$prevHeap\", predef.HeapType), true));\n        }\n        if (AlwaysUseHeap || f.ReadsHeap) {\n          formals.Add(new Bpl.Formal(f.tok, new Bpl.TypedIdent(f.tok, \"$heap\", predef.HeapType), true));\n        }\n        if (!f.IsStatic) {\n          formals.Add(new Bpl.Formal(f.tok, new Bpl.TypedIdent(f.tok, \"this\", TrReceiverType(f)), true));\n        }\n        foreach (var p in f.Formals) {\n          formals.Add(new Bpl.Formal(p.tok, new Bpl.TypedIdent(p.tok, p.AssignUniqueName(f.IdGenerator), TrType(p.Type)), true));\n        }\n        var res = new Bpl.Formal(f.tok, new Bpl.TypedIdent(f.tok, Bpl.TypedIdent.NoName, Bpl.Type.Bool), false);\n        var canCallF = new Bpl.Function(f.tok, f.FullSanitizedName + \"#canCall\", new List<Bpl.TypeVariable>(), formals, res);\n        sink.AddTopLevelDeclaration(canCallF);\n      }\n    }\n\n    /// <summary>\n    /// A method can have several translations, suitable for different purposes.\n    /// SpecWellformedness\n    ///    This procedure is suitable for the wellformedness check of the\n    ///    method's specification.\n    ///    This means the pre- and postconditions are not filled in, since the\n    ///    body of the procedure is going to check that these are well-formed in\n    ///    the first place.\n    /// InterModuleCall\n    ///    This procedure is suitable for inter-module callers.\n    ///    This means that predicate definitions inlined only for non-protected predicates.\n    /// IntraModuleCall\n    ///    This procedure is suitable for non-co-call intra-module callers.\n    ///    This means that predicates can be inlined in the usual way.\n    /// CoCall\n    ///    This procedure is suitable for (intra-module) co-calls.\n    ///    In these calls, some uses of copredicates may be replaced by\n    ///    proof certificates.  Note, unless the method is a colemma, there\n    ///    is no reason to include a procedure for co-calls.\n    /// Implementation\n    ///    This procedure is suitable for checking the implementation of the\n    ///    method.\n    ///    If the method has no body, there is no reason to include this kind\n    ///    of procedure.\n    ///\n    /// Note that SpecWellformedness and Implementation have procedure implementations\n    /// but no callers, and vice versa for InterModuleCall, IntraModuleCall, and CoCall.\n    /// </summary>\n    enum MethodTranslationKind { SpecWellformedness, Call, CoCall, Implementation, OverrideCheck }\n\n    /// <summary>\n    /// This method is expected to be called at most once for each parameter combination, and in particular\n    /// at most once for each value of \"kind\".\n    /// </summary>\n    Bpl.Procedure AddMethod(Method m, MethodTranslationKind kind)\n    {\n      Contract.Requires(m != null);\n      Contract.Requires(m.EnclosingClass != null);\n      Contract.Requires(predef != null);\n      Contract.Requires(currentModule == null && codeContext == null && isAllocContext == null);\n      Contract.Ensures(currentModule == null && codeContext == null && isAllocContext == null);\n      Contract.Ensures(Contract.Result<Bpl.Procedure>() != null);\n      Contract.Assert(VisibleInScope(m));\n\n      currentModule = m.EnclosingClass.Module;\n      codeContext = m;\n      isAllocContext = new IsAllocContext(m.IsGhost);\n\n      Bpl.Expr prevHeap = null;\n      Bpl.Expr currHeap = null;\n      var ordinaryEtran = new ExpressionTranslator(this, predef, m.tok);\n      ExpressionTranslator etran;\n      var inParams = new List<Bpl.Variable>();\n      if (m is TwoStateLemma) {\n        var prevHeapVar = new Bpl.Formal(m.tok, new Bpl.TypedIdent(m.tok, \"previous$Heap\", predef.HeapType), true);\n        var currHeapVar = new Bpl.Formal(m.tok, new Bpl.TypedIdent(m.tok, \"current$Heap\", predef.HeapType), true);\n        inParams.Add(prevHeapVar);\n        inParams.Add(currHeapVar);\n        prevHeap = new Bpl.IdentifierExpr(m.tok, prevHeapVar);\n        currHeap = new Bpl.IdentifierExpr(m.tok, currHeapVar);\n        etran = new ExpressionTranslator(this, predef, currHeap, prevHeap);\n      } else {\n        etran = ordinaryEtran;\n      }\n\n      List<Variable> outParams;\n      GenerateMethodParameters(m.tok, m, kind, etran, inParams, out outParams);\n\n      var req = new List<Bpl.Requires>();\n      var mod = new List<Bpl.IdentifierExpr>();\n      var ens = new List<Bpl.Ensures>();\n      // FREE PRECONDITIONS\n      if (kind == MethodTranslationKind.SpecWellformedness || kind == MethodTranslationKind.Implementation || kind == MethodTranslationKind.OverrideCheck) {  // the other cases have no need for a free precondition\n        // free requires mh == ModuleContextHeight && fh == FunctionContextHeight;\n        req.Add(Requires(m.tok, true, etran.HeightContext(kind == MethodTranslationKind.OverrideCheck ? m.OverriddenMethod : m), null, null));\n        if (m is TwoStateLemma) {\n          // free requires prevHeap == Heap && HeapSucc(prevHeap, currHeap) && IsHeap(currHeap)\n          var a0 = Bpl.Expr.Eq(prevHeap, ordinaryEtran.HeapExpr);\n          var a1 = HeapSucc(prevHeap, currHeap);\n          var a2 = FunctionCall(m.tok, BuiltinFunction.IsGoodHeap, null, currHeap);\n          req.Add(Requires(m.tok, true, BplAnd(a0, BplAnd(a1, a2)), null, null));\n        }\n      }\n      if (m is TwoStateLemma) {\n        // Checked preconditions that old parameters really existed in previous state\n        var index = 0;\n        foreach (var formal in m.Ins) {\n          if (formal.IsOld) {\n            var dafnyFormalIdExpr = new IdentifierExpr(formal.tok, formal);\n            req.Add(Requires(formal.tok, false, MkIsAlloc(etran.TrExpr(dafnyFormalIdExpr), formal.Type, prevHeap),\n              string.Format(\"parameter{0} ('{1}') must be allocated in the two-state lemma's previous state\",\n              m.Ins.Count == 1 ? \"\" : \" \" + index, formal.Name), null));\n          }\n          index++;\n        }\n      }\n      mod.Add((Bpl.IdentifierExpr/*TODO: this cast is somewhat dubious*/)ordinaryEtran.HeapExpr);\n      mod.Add(etran.Tick());\n\n      var bodyKind = kind == MethodTranslationKind.SpecWellformedness || kind == MethodTranslationKind.Implementation;\n\n      if (kind != MethodTranslationKind.SpecWellformedness && kind != MethodTranslationKind.OverrideCheck)\n      {\n        // USER-DEFINED SPECIFICATIONS\n        var comment = \"user-defined preconditions\";\n        foreach (var p in m.Req) {\n          string errorMessage = CustomErrorMessage(p.Attributes);\n          if (p.Label != null && kind == MethodTranslationKind.Implementation) {\n            // don't include this precondition here, but record it for later use\n            p.Label.E = (m is TwoStateLemma ? ordinaryEtran : etran.Old).TrExpr(p.E);\n          } else if (p.IsFree && !ArmadaOptions.O.DisallowSoundnessCheating) {\n            req.Add(Requires(p.E.tok, true, etran.TrExpr(p.E), errorMessage, comment));\n            comment = null;\n          } else {\n            foreach (var s in TrSplitExprForMethodSpec(p.E, etran, kind)) {\n              if (s.IsOnlyChecked && bodyKind) {\n                // don't include in split\n              } else if (s.IsOnlyFree && !bodyKind) {\n                // don't include in split -- it would be ignored, anyhow\n              } else {\n                req.Add(Requires(s.E.tok, s.IsOnlyFree, s.E, errorMessage, comment));\n                comment = null;\n                // the free here is not linked to the free on the original expression (this is free things generated in the splitting.)\n              }\n            }\n          }\n        }\n        comment = \"user-defined postconditions\";\n        foreach (var p in m.Ens) {\n          string errorMessage = CustomErrorMessage(p.Attributes);\n          AddEnsures(ens, Ensures(p.E.tok, true, CanCallAssumption(p.E, etran), errorMessage, comment));\n          comment = null;\n          if (p.IsFree && !ArmadaOptions.O.DisallowSoundnessCheating) {\n            AddEnsures(ens, Ensures(p.E.tok, true, etran.TrExpr(p.E), errorMessage, null));\n          } else {\n            foreach (var s in TrSplitExprForMethodSpec(p.E, etran, kind)) {\n              var post = s.E;\n              if (kind == MethodTranslationKind.Implementation && RefinementToken.IsInherited(s.E.tok, currentModule)) {\n                // this postcondition was inherited into this module, so make it into the form \"$_reverifyPost ==> s.E\"\n                post = Bpl.Expr.Imp(new Bpl.IdentifierExpr(s.E.tok, \"$_reverifyPost\", Bpl.Type.Bool), post);\n              }\n              if (s.IsOnlyFree && bodyKind) {\n                // don't include in split -- it would be ignored, anyhow\n              } else if (s.IsOnlyChecked && !bodyKind) {\n                // don't include in split\n              } else {\n                AddEnsures(ens, Ensures(s.E.tok, s.IsOnlyFree, post, errorMessage, null));\n              }\n            }\n          }\n        }\n        if (m is Constructor && kind == MethodTranslationKind.Call) {\n          var fresh = Bpl.Expr.Not(etran.Old.IsAlloced(m.tok, new Bpl.IdentifierExpr(m.tok, \"this\", TrReceiverType(m))));\n          AddEnsures(ens, Ensures(m.tok, false, fresh, null, \"constructor allocates the object\"));\n        }\n        foreach (BoilerplateTriple tri in GetTwoStateBoilerplate(m.tok, m.Mod.Expressions, m.IsGhost, ordinaryEtran.Old, ordinaryEtran, ordinaryEtran.Old)) {\n          AddEnsures(ens, Ensures(tri.tok, tri.IsFree, tri.Expr, tri.ErrorMessage, tri.Comment));\n        }\n\n        // add the fuel assumption for the reveal method of a opaque method\n        if (IsOpaqueRevealLemma(m)) {\n          List<Expression> args = Attributes.FindExpressions(m.Attributes, \"fuel\");\n          if (args != null) {\n            MemberSelectExpr selectExpr = args[0].Resolved as MemberSelectExpr;\n            if (selectExpr != null) {\n              Function f = selectExpr.Member as Function;\n              FuelConstant fuelConstant = this.functionFuel.Find(x => x.f == f);\n              if (fuelConstant != null) {\n                Bpl.Expr startFuel = fuelConstant.startFuel;\n                Bpl.Expr startFuelAssert = fuelConstant.startFuelAssert;\n                Bpl.Expr moreFuel_expr = fuelConstant.MoreFuel(sink, predef, f.IdGenerator);\n                Bpl.Expr layer = etran.layerInterCluster.LayerN(1, moreFuel_expr);\n                Bpl.Expr layerAssert = etran.layerInterCluster.LayerN(2, moreFuel_expr);\n\n                AddEnsures(ens, Ensures(m.tok, true, Bpl.Expr.Eq(startFuel, layer), null, null));\n                AddEnsures(ens, Ensures(m.tok, true, Bpl.Expr.Eq(startFuelAssert, layerAssert), null, null));\n\n                AddEnsures(ens, Ensures(m.tok, true, Bpl.Expr.Eq(FunctionCall(f.tok, BuiltinFunction.AsFuelBottom, null, moreFuel_expr), moreFuel_expr), null, \"Shortcut to LZ\"));\n                }\n            }\n          }\n        }\n      }\n\n      var name = MethodName(m, kind);\n      var proc = new Bpl.Procedure(m.tok, name, new List<Bpl.TypeVariable>(), inParams, outParams, req, mod, ens, etran.TrAttributes(m.Attributes, null));\n\n      if (InsertChecksums)\n      {\n        InsertChecksum(m, proc, true);\n      }\n\n      currentModule = null;\n      codeContext = null;\n      isAllocContext = null;\n\n      return proc;\n    }\n\n    static string MethodName(ICodeContext m, MethodTranslationKind kind) {\n      Contract.Requires(m != null);\n      switch (kind) {\n        case MethodTranslationKind.SpecWellformedness:\n          return \"CheckWellformed$$\" + m.FullSanitizedName;\n        case MethodTranslationKind.Call:\n          return \"Call$$\" + m.FullSanitizedName;\n        case MethodTranslationKind.CoCall:\n          return \"CoCall$$\" + m.FullSanitizedName;\n        case MethodTranslationKind.Implementation:\n          return \"Impl$$\" + m.FullSanitizedName;\n        case MethodTranslationKind.OverrideCheck:\n          return \"OverrideCheck$$\" + m.FullSanitizedName;\n        default:\n          Contract.Assert(false);  // unexpected kind\n          throw new cce.UnreachableException();\n      }\n    }\n\n    private static CallCmd Call(IToken tok, string methodName, List<Expr> ins, List<Bpl.IdentifierExpr> outs) {\n      Contract.Requires(tok != null);\n      Contract.Requires(methodName != null);\n      Contract.Requires(ins != null);\n      Contract.Requires(outs != null);\n\n      CallCmd call;\n      call = new CallCmd(tok, methodName, ins, outs);\n      // CLEMENT enable this: call.ErrorData = \"possible violation of function precondition\";\n      return call;\n    }\n\n    private static QKeyValue ErrorMessageAttribute(IToken t, string error) {\n      var l = new List<object>(1);\n      l.Add(error);\n      return new QKeyValue(t, \"msg\", l, null);\n    }\n    private static QKeyValue ErrorMessageAttribute(IToken t, string error, QKeyValue qv) {\n      var l = new List<object>(1);\n      l.Add(error);\n      return new QKeyValue(t, \"msg\", l, qv);\n    }\n\n    private void GenerateMethodParameters(IToken tok, Method m, MethodTranslationKind kind, ExpressionTranslator etran, List<Variable> inParams, out List<Variable> outParams) {\n      GenerateMethodParametersChoose(tok, m, kind, !m.IsStatic, true, true, etran, inParams, out outParams);\n    }\n\n    private void GenerateMethodParametersChoose(IToken tok, IMethodCodeContext m, MethodTranslationKind kind, bool includeReceiver, bool includeInParams, bool includeOutParams,\n      ExpressionTranslator etran, List<Variable> inParams, out List<Variable> outParams) {\n      outParams = new List<Variable>();\n      // Add type parameters first, always!\n      inParams.AddRange(MkTyParamFormals(GetTypeParams(m)));\n      if (includeReceiver) {\n        var receiverType = m is MemberDecl ? Resolver.GetReceiverType(tok, (MemberDecl)m) : Resolver.GetThisType(tok, (IteratorDecl)m);\n        Contract.Assert(VisibleInScope(receiverType));\n\n        Bpl.Expr wh;\n        if (m is Constructor && kind == MethodTranslationKind.Implementation) {\n          var th = new Bpl.IdentifierExpr(tok, \"this\", TrType(receiverType));\n          wh = Bpl.Expr.And(\n            ReceiverNotNull(th),\n            GetWhereClause(tok, th, receiverType, etran, NOALLOC));\n        } else {\n          var th = new Bpl.IdentifierExpr(tok, \"this\", TrType(receiverType));\n          wh = Bpl.Expr.And(\n            ReceiverNotNull(th),\n            (m is TwoStateLemma ? etran.Old : etran).GoodRef(tok, th, receiverType));\n        }\n        // for class constructors, the receiver is encoded as an output parameter\n        Bpl.Formal thVar = new Bpl.Formal(tok, new Bpl.TypedIdent(tok, \"this\", TrType(receiverType), wh), !(m is Constructor && kind != MethodTranslationKind.SpecWellformedness));\n        if (thVar.InComing) {\n          inParams.Add(thVar);\n        } else {\n          outParams.Add(thVar);\n        }\n      }\n      if (includeInParams) {\n        foreach (Formal p in m.Ins) {\n          Contract.Assert(VisibleInScope(p.Type));\n          Bpl.Type varType = TrType(p.Type);\n          Bpl.Expr wh = GetExtendedWhereClause(p.tok,\n            new Bpl.IdentifierExpr(p.tok, p.AssignUniqueName(currentDeclaration.IdGenerator), varType),\n            p.Type, p.IsOld ? etran.Old : etran, isAllocContext.Var(p));\n          inParams.Add(new Bpl.Formal(p.tok, new Bpl.TypedIdent(p.tok, p.AssignUniqueName(currentDeclaration.IdGenerator), varType, wh), true));\n        }\n      }\n      if (includeOutParams) {\n        foreach (Formal p in m.Outs) {\n          Contract.Assert(VisibleInScope(p.Type));\n          Contract.Assert(!p.IsOld);  // out-parameters are never old (perhaps we want to relax this condition in the future)\n          Bpl.Type varType = TrType(p.Type);\n          Bpl.Expr wh = GetWhereClause(p.tok,\n            new Bpl.IdentifierExpr(p.tok, p.AssignUniqueName(currentDeclaration.IdGenerator), varType),\n            p.Type, etran, isAllocContext.Var(p));\n          outParams.Add(new Bpl.Formal(p.tok, new Bpl.TypedIdent(p.tok, p.AssignUniqueName(currentDeclaration.IdGenerator), varType, wh), false));\n        }\n        if (kind == MethodTranslationKind.Implementation) {\n          outParams.Add(new Bpl.Formal(tok, new Bpl.TypedIdent(tok, \"$_reverifyPost\", Bpl.Type.Bool), false));\n        }\n      }\n    }\n\n    class BoilerplateTriple\n    {  // a triple that is now a quintuple\n      [ContractInvariantMethod]\n      void ObjectInvariant() {\n        Contract.Invariant(tok != null);\n        Contract.Invariant(Expr != null);\n        Contract.Invariant(IsFree || ErrorMessage != null);\n      }\n\n      public readonly IToken tok;\n      public readonly bool IsFree;\n      public readonly Bpl.Expr Expr;\n      public readonly string ErrorMessage;\n      public readonly string Comment;\n\n\n      public BoilerplateTriple(IToken tok, bool isFree, Bpl.Expr expr, string errorMessage, string comment)\n       {\n        Contract.Requires(tok != null);\n        Contract.Requires(expr != null);\n        Contract.Requires(isFree || errorMessage != null);\n        this.tok = tok;\n        IsFree = isFree;\n        Expr = expr;\n        ErrorMessage = errorMessage;\n        Comment = comment;\n      }\n    }\n\n    /// <summary>\n    /// There are 3 states of interest when generating two-state boilerplate:\n    ///  S0. the beginning of the method or loop, which is where the modifies clause is interpreted\n    ///  S1. the pre-state of the two-state interval\n    ///  S2. the post-state of the two-state interval\n    /// This method assumes that etranPre denotes S1, etran denotes S2, and that etranMod denotes S0.\n    /// </summary>\n    List<BoilerplateTriple/*!*/>/*!*/ GetTwoStateBoilerplate(IToken/*!*/ tok, List<FrameExpression/*!*/>/*!*/ modifiesClause, bool isGhostContext,\n      ExpressionTranslator/*!*/ etranPre, ExpressionTranslator/*!*/ etran, ExpressionTranslator/*!*/ etranMod)\n    {\n      Contract.Requires(tok != null);\n      Contract.Requires(modifiesClause != null);\n      Contract.Requires(etranPre != null);\n      Contract.Requires(etran != null);\n      Contract.Ensures(cce.NonNullElements(Contract.Result<List<BoilerplateTriple>>()));\n\n      var boilerplate = new List<BoilerplateTriple>();\n      if (isGhostContext && modifiesClause.Count == 0) {\n        // plain and simple:  S1 == S2\n        boilerplate.Add(new BoilerplateTriple(tok, true, Bpl.Expr.Eq(etranPre.HeapExpr, etran.HeapExpr), null, \"frame condition\"));\n      } else {\n        bool fieldGranularity = true;\n        bool objectGranularity = !fieldGranularity;\n        // the frame condition, which is free since it is checked with every heap update and call\n        boilerplate.Add(new BoilerplateTriple(tok, true, FrameCondition(tok, modifiesClause, isGhostContext, Resolver.FrameExpressionUse.Modifies, etranPre, etran, etranMod, objectGranularity), null, \"frame condition: object granularity\"));\n        if (modifiesClause.Exists(fe => fe.FieldName != null)) {\n          boilerplate.Add(new BoilerplateTriple(tok, true, FrameCondition(tok, modifiesClause, isGhostContext, Resolver.FrameExpressionUse.Modifies, etranPre, etran, etranMod, fieldGranularity), null, \"frame condition: field granularity\"));\n        }\n        // HeapSucc(S1, S2) or HeapSuccGhost(S1, S2)\n        Bpl.Expr heapSucc = HeapSucc(etranPre.HeapExpr, etran.HeapExpr, isGhostContext);\n        boilerplate.Add(new BoilerplateTriple(tok, true, heapSucc, null, \"boilerplate\"));\n      }\n      return boilerplate;\n    }\n\n    /// <summary>\n    /// There are 3 states of interest when generating a frame condition:\n    ///  S0. the beginning of the method/loop, which is where the frame is interpreted\n    ///  S1. the pre-state of the two-state interval\n    ///  S2. the post-state of the two-state interval\n    /// This method assumes that etranPre denotes S1, etran denotes S2, and that etranMod denotes S0.\n    /// \"use\" being \"Modifies\" says to produce this frame condition:\n    ///      if it's not in the frame, then it is unchanged\n    /// \"use\" being \"Reads\" says to produce this frame condition:\n    ///      if it's in the frame, then it is unchanged\n    /// \"use\" being \"Unchanged\" says to produce this frame condition:\n    ///      if it's in the frame, then it is unchanged,\n    ///      and if it has a field designation, then furthermore 'alloc' is unchanged\n    /// </summary>\n    Bpl.Expr/*!*/ FrameCondition(IToken/*!*/ tok, List<FrameExpression/*!*/>/*!*/ frame, bool isGhostContext, Resolver.FrameExpressionUse use,\n      ExpressionTranslator/*!*/ etranPre, ExpressionTranslator/*!*/ etran, ExpressionTranslator/*!*/ etranMod, bool fieldGranularity)\n    {\n      Contract.Requires(tok != null);\n      Contract.Requires(etran != null);\n      Contract.Requires(etranPre != null);\n      Contract.Requires(cce.NonNullElements(frame));\n      Contract.Requires(predef != null);\n      Contract.Ensures(Contract.Result<Bpl.Expr>() != null);\n\n      // read is handled in AddFrameAxiom\n      //\n      // if field granularity:\n      // generate:\n      //  (forall<alpha> o: ref, f: Field alpha :: { $Heap[o][f] }\n      //      o != null\n      // #if use==Modifies\n      //      && old($Heap)[o][alloc]                     // include only in non-ghost contexts\n      // #endif\n      //      ==>\n      // #if use==Modifies\n      //        $Heap[o][f] == PreHeap[o][f] ||\n      //        (o,f) in modifiesClause)\n      // #else\n      //        (o,f) in readsClause\n      // #if use==Unchanged\n      //        or f==alloc && there's some f' such that (o,f') in readsClause\n      // #endif\n      //        ==>\n      //        $Heap[o][f] == PreHeap[o][f])\n      // #endif\n      //\n      // if object granularity:\n      // generate:\n      //  (forall o: ref :: { $Heap[o] }\n      //      o != null\n      // #if use==Modifies\n      //      && old($Heap)[o][alloc]                     // include only in non-ghost contexts\n      // #endif\n      //      ==>\n      // #if use==Modifies\n      //        $Heap[o] == PreHeap[o] ||\n      //        o in modifiesClause)\n      // #else\n      //        o in readsClause\n      //        ==>\n      //        $Heap[o] == PreHeap[o])\n      // #endif\n      var oVar = new Bpl.BoundVariable(tok, new Bpl.TypedIdent(tok, \"$o\", predef.RefType));\n      var o = new Bpl.IdentifierExpr(tok, oVar);\n\n      Bpl.TypeVariable alpha;\n      Bpl.Expr f;\n      List<Variable> quantifiedVars;\n      List<TypeVariable> typeVars;\n      Bpl.Expr heapOF;\n      Bpl.Expr preHeapOF;\n      if (fieldGranularity) {\n        alpha = new Bpl.TypeVariable(tok, \"alpha\");\n        typeVars = new List<TypeVariable> { alpha };\n        var fVar = new Bpl.BoundVariable(tok, new Bpl.TypedIdent(tok, \"$f\", predef.FieldName(tok, alpha)));\n        f = new Bpl.IdentifierExpr(tok, fVar);\n        quantifiedVars = new List<Variable> { oVar, fVar };\n        heapOF = ReadHeap(tok, etran.HeapExpr, o, f);\n        preHeapOF = ReadHeap(tok, etranPre.HeapExpr, o, f);\n      } else {\n        // object granularity\n        typeVars = new List<TypeVariable>();\n        f = null;\n        quantifiedVars = new List<Variable> { oVar };\n        heapOF = ReadHeap(tok, etran.HeapExpr, o);\n        preHeapOF = ReadHeap(tok, etranPre.HeapExpr, o);\n      }\n\n      Bpl.Expr ante = Bpl.Expr.Neq(o, predef.Null);\n      if (!isGhostContext && use == Resolver.FrameExpressionUse.Modifies) {\n        ante = Bpl.Expr.And(ante, etranMod.IsAlloced(tok, o));\n      }\n      var eq = Bpl.Expr.Eq(heapOF, preHeapOF);\n      var ofInFrame = InRWClause(tok, o, f, frame, use == Resolver.FrameExpressionUse.Unchanged, etranMod, null, null);\n      Bpl.Expr consequent = use == Resolver.FrameExpressionUse.Modifies ? Bpl.Expr.Or(eq, ofInFrame) : Bpl.Expr.Imp(ofInFrame, eq);\n\n      var tr = new Bpl.Trigger(tok, true, new List<Bpl.Expr> { heapOF });\n      return new Bpl.ForallExpr(tok, typeVars, quantifiedVars, null, tr, Bpl.Expr.Imp(ante, consequent));\n    }\n\n    Bpl.Expr/*!*/ FrameConditionUsingDefinedFrame(IToken/*!*/ tok, ExpressionTranslator/*!*/ etranPre, ExpressionTranslator/*!*/ etran, ExpressionTranslator/*!*/ etranMod)\n    {\n      Contract.Requires(tok != null);\n      Contract.Requires(etran != null);\n      Contract.Requires(etranPre != null);\n      Contract.Requires(predef != null);\n      Contract.Ensures(Contract.Result<Bpl.Expr>() != null);\n\n      // generate:\n      //  (forall<alpha> o: ref, f: Field alpha :: { $Heap[o,f] }\n      //      o != null && old($Heap)[o,alloc] ==>\n      //        $Heap[o,f] == PreHeap[o,f] ||\n      //        $_Frame[o,f])\n      Bpl.TypeVariable alpha = new Bpl.TypeVariable(tok, \"alpha\");\n      Bpl.BoundVariable oVar = new Bpl.BoundVariable(tok, new Bpl.TypedIdent(tok, \"$o\", predef.RefType));\n      Bpl.IdentifierExpr o = new Bpl.IdentifierExpr(tok, oVar);\n      Bpl.BoundVariable fVar = new Bpl.BoundVariable(tok, new Bpl.TypedIdent(tok, \"$f\", predef.FieldName(tok, alpha)));\n      Bpl.IdentifierExpr f = new Bpl.IdentifierExpr(tok, fVar);\n\n      Bpl.Expr heapOF = ReadHeap(tok, etran.HeapExpr, o, f);\n      Bpl.Expr preHeapOF = ReadHeap(tok, etranPre.HeapExpr, o, f);\n      Bpl.Expr ante = Bpl.Expr.And(Bpl.Expr.Neq(o, predef.Null), etranPre.IsAlloced(tok, o));\n      Bpl.Expr consequent = Bpl.Expr.Eq(heapOF, preHeapOF);\n\n      consequent = Bpl.Expr.Or(consequent, Bpl.Expr.SelectTok(tok, etranMod.TheFrame(tok), o, f));\n\n      Bpl.Trigger tr = new Bpl.Trigger(tok, true, new List<Bpl.Expr> { heapOF });\n      return new Bpl.ForallExpr(tok, new List<TypeVariable> { alpha }, new List<Variable> { oVar, fVar }, null, tr, Bpl.Expr.Imp(ante, consequent));\n    }\n    // ----- Type ---------------------------------------------------------------------------------\n    // Translates a type into the representation Boogie type,\n    // c.f. TypeToTy which translates a type to its Boogie expression\n    // to be used in $Is and $IsAlloc.\n    Bpl.Type TrType(Type type) {\n      Contract.Requires(type != null);\n      Contract.Requires(predef != null);\n      Contract.Ensures(Contract.Result<Bpl.Type>() != null);\n\n      while (true) {\n        type = type.NormalizeExpand();\n        if (type is TypeProxy) {\n          Contract.Assume(false);  // we assume that all proxies should have been dealt with in the resolver\n        }\n        var d = type.AsNewtype;\n        if (d == null) {\n          break;\n        } else {\n          type = d.BaseType;  // the Boogie type to be used for the newtype is the same as for the base type\n        }\n      }\n\n      if (type is BoolType) {\n        return Bpl.Type.Bool;\n      } else if (type is CharType) {\n        return predef.CharType;\n      } else if (type is IntType) {\n        return Bpl.Type.Int;\n      } else if (type is RealType) {\n        return Bpl.Type.Real;\n      } else if (type is BigOrdinalType) {\n        return predef.BigOrdinalType;\n      } else if (type is BitvectorType) {\n        var t = (BitvectorType)type;\n        return BplBvType(t.Width);\n      } else if (type is IteratorDecl.EverIncreasingType) {\n        return Bpl.Type.Int;\n      } else if (type is ArrowType) {\n        return predef.HandleType;\n      } else if (type.IsTypeParameter) {\n        return predef.BoxType;\n      } else if (type.IsInternalTypeSynonym) {\n        return predef.BoxType;\n      } else if (type.IsRefType) {\n        // object and class types translate to ref\n        return predef.RefType;\n      } else if (type.IsDatatype) {\n        return predef.DatatypeType;\n      } else if (type is SetType) {\n        return predef.SetType(Token.NoToken, ((SetType)type).Finite, predef.BoxType);\n      } else if (type is MultiSetType) {\n        return predef.MultiSetType(Token.NoToken, predef.BoxType);\n      } else if (type is MapType) {\n        return predef.MapType(Token.NoToken, ((MapType)type).Finite, predef.BoxType, predef.BoxType);\n      } else if (type is SeqType) {\n        return predef.SeqType(Token.NoToken, predef.BoxType);\n\n      } else {\n        Contract.Assert(false); throw new cce.UnreachableException();  // unexpected type\n      }\n    }\n\n    public Bpl.Expr CondApplyBox(IToken tok, Bpl.Expr e, Type fromType, Type toType) {\n      Contract.Requires(tok != null);\n      Contract.Requires(e != null);\n      Contract.Requires(fromType != null);\n      Contract.Ensures(Contract.Result<Bpl.Expr>() != null);\n\n      if (!ModeledAsBoxType(fromType) && (toType == null || ModeledAsBoxType(toType))) {\n        // if \"e\" denotes \"Unbox(E): T\", then just return \"E\"\n        var coerce = e as Bpl.NAryExpr;\n        if (coerce != null && coerce.Fun is Bpl.TypeCoercion) {\n          Contract.Assert(coerce.Args.Count == 1);\n          Contract.Assert(Bpl.Type.Equals(((Bpl.TypeCoercion)coerce.Fun).Type, TrType(fromType))); ;\n          var call = coerce.Args[0] as Bpl.NAryExpr;\n          if (call != null && call.Fun is Bpl.FunctionCall) {\n            var fn = (Bpl.FunctionCall)call.Fun;\n            if (fn.FunctionName == \"$Unbox\") {\n              Contract.Assert(call.Args.Count == 1);\n              return call.Args[0];\n            }\n          }\n        }\n        // return \"Box(e)\"\n        return FunctionCall(tok, BuiltinFunction.Box, null, e);\n      } else {\n        return e;\n      }\n    }\n\n    public Bpl.Expr BoxIfNecessary(IToken tok, Bpl.Expr e, Type fromType) {\n      Contract.Requires(tok != null);\n      Contract.Requires(e != null);\n      Contract.Requires(fromType != null);\n      Contract.Ensures(Contract.Result<Bpl.Expr>() != null);\n\n      return CondApplyBox(tok, e, fromType, null);\n    }\n\n    public Bpl.Expr CondApplyUnbox(IToken tok, Bpl.Expr e, Type fromType, Type toType) {\n      Contract.Requires(tok != null);\n      Contract.Requires(e != null);\n      Contract.Requires(fromType != null);\n      Contract.Requires(toType != null);\n      Contract.Ensures(Contract.Result<Bpl.Expr>() != null);\n\n      if (ModeledAsBoxType(fromType) && !ModeledAsBoxType(toType)) {\n        return FunctionCall(tok, BuiltinFunction.Unbox, TrType(toType), e);\n      } else {\n        return e;\n      }\n    }\n\n    /// <summary>\n    ///   If the type is not normally boxed, insert a box around it.\n    ///   For lambda functions.\n    /// </summary>\n    public Bpl.Expr BoxIfUnboxed(Bpl.Expr e, Type t) {\n      if (!ModeledAsBoxType(t)) {\n        return FunctionCall(e.tok, BuiltinFunction.Box, null, e);\n      } else {\n        return e;\n      }\n    }\n\n    /// <summary>\n    ///   If the expression is boxed, but the type is not boxed, this unboxes it.\n    ///   For lambda functions.\n    /// </summary>\n    public Bpl.Expr UnboxIfBoxed(Bpl.Expr e, Type t) {\n      if (!ModeledAsBoxType(t)) {\n        return FunctionCall(e.tok, BuiltinFunction.Unbox, TrType(t), e);\n      } else {\n        return e;\n      }\n    }\n\n    public static bool ModeledAsBoxType(Type t) {\n      Contract.Requires(t != null);\n      t = t.NormalizeExpand();\n      if (t is TypeProxy) {\n        // unresolved proxy\n        return false;\n      }\n      var res = t.IsTypeParameter || t.IsInternalTypeSynonym;\n      Contract.Assert(t.IsArrowType ? !res : true);\n      return res;\n    }\n\n    // ----- Statement ----------------------------------------------------------------------------\n\n    /// <summary>\n    /// A ForceCheckToken is a token wrapper whose purpose is to hide inheritance.\n    /// </summary>\n    public class ForceCheckToken : TokenWrapper\n    {\n      public ForceCheckToken(IToken tok)\n        : base(tok) {\n        Contract.Requires(tok != null);\n      }\n      public static IToken Unwrap(IToken tok) {\n        Contract.Requires(tok != null);\n        Contract.Ensures(Contract.Result<IToken>() != null);\n        var ftok = tok as ForceCheckToken;\n        return ftok != null ? ftok.WrappedToken : tok;\n      }\n    }\n\n    Bpl.PredicateCmd Assert(Bpl.IToken tok, Bpl.Expr condition, string errorMessage) {\n      return Assert(tok, condition, errorMessage, tok);\n    }\n\n    Bpl.PredicateCmd Assert(Bpl.IToken tok, Bpl.Expr condition, string errorMessage, Bpl.IToken refinesToken, Bpl.QKeyValue kv = null) {\n      Contract.Requires(tok != null);\n      Contract.Requires(condition != null);\n      Contract.Requires(errorMessage != null);\n      Contract.Ensures(Contract.Result<Bpl.PredicateCmd>() != null);\n\n      if (assertAsAssume || (RefinementToken.IsInherited(refinesToken, currentModule) && (codeContext == null || !codeContext.MustReverify))) {\n        // produce an assume instead\n        return TrAssumeCmd(tok, condition, kv);\n      } else {\n        var cmd = TrAssertCmd(ForceCheckToken.Unwrap(tok), condition, kv);\n        cmd.ErrorData = \"Error: \" + errorMessage;\n        this.assertionCount++;\n        return cmd;\n      }\n    }\n    Bpl.PredicateCmd AssertNS(Bpl.IToken tok, Bpl.Expr condition, string errorMessage) {\n      return AssertNS(tok, condition, errorMessage, tok, null);\n    }\n    Bpl.PredicateCmd AssertNS(Bpl.IToken tok, Bpl.Expr condition, string errorMessage, Bpl.IToken refinesTok, Bpl.QKeyValue kv)\n    {\n      Contract.Requires(tok != null);\n      Contract.Requires(errorMessage != null);\n      Contract.Requires(condition != null);\n      Contract.Ensures(Contract.Result<Bpl.PredicateCmd>() != null);\n\n      if (RefinementToken.IsInherited(refinesTok, currentModule) && (codeContext == null || !codeContext.MustReverify)) {\n        // produce a \"skip\" instead\n        return TrAssumeCmd(tok, Bpl.Expr.True, kv);\n      } else {\n        tok = ForceCheckToken.Unwrap(tok);\n        var args = new List<object>();\n        args.Add(Bpl.Expr.Literal(0));\n        Bpl.AssertCmd cmd = TrAssertCmd(tok, condition, new Bpl.QKeyValue(tok, \"subsumption\", args, kv));\n        cmd.ErrorData = \"Error: \" + errorMessage;\n        return cmd;\n      }\n    }\n\n    Bpl.PredicateCmd Assert(Bpl.IToken tok, Bpl.Expr condition, string errorMessage, Bpl.QKeyValue kv) {\n      Contract.Requires(tok != null);\n      Contract.Requires(errorMessage != null);\n      Contract.Requires(condition != null);\n      Contract.Ensures(Contract.Result<Bpl.PredicateCmd>() != null);\n\n      if (assertAsAssume || (RefinementToken.IsInherited(tok, currentModule) && (codeContext == null || !codeContext.MustReverify))) {\n        // produce an assume instead\n        return TrAssumeCmd(tok, condition, kv);\n      } else {\n        var cmd = TrAssertCmd(ForceCheckToken.Unwrap(tok), condition, kv);\n        cmd.ErrorData = \"Error: \" + errorMessage;\n        return cmd;\n      }\n    }\n\n    Bpl.Ensures Ensures(IToken tok, bool free, Bpl.Expr condition, string errorMessage, string comment)\n    {\n      Contract.Requires(tok != null);\n      Contract.Requires(condition != null);\n      Contract.Ensures(Contract.Result<Bpl.Ensures>() != null);\n\n      Bpl.Ensures ens = new Bpl.Ensures(ForceCheckToken.Unwrap(tok), free, condition, comment);\n      if (errorMessage != null) {\n        ens.ErrorData = errorMessage;\n      }\n      return ens;\n    }\n\n    Bpl.Requires Requires(IToken tok, bool free, Bpl.Expr condition, string errorMessage, string comment)\n    {\n      Contract.Requires(tok != null);\n      Contract.Requires(condition != null);\n      Contract.Ensures(Contract.Result<Bpl.Requires>() != null);\n      Bpl.Requires req = new Bpl.Requires(ForceCheckToken.Unwrap(tok), free, condition, comment);\n      if (errorMessage != null) {\n        req.ErrorData = errorMessage;\n      }\n      return req;\n    }\n\n    Bpl.StmtList TrStmt2StmtList(BoogieStmtListBuilder builder, Statement block, List<Variable> locals, ExpressionTranslator etran)\n    {\n      Contract.Requires(builder != null);\n      Contract.Requires(block != null);\n      Contract.Requires(locals != null);\n      Contract.Requires(etran != null);\n      Contract.Requires(codeContext != null && predef != null);\n      Contract.Ensures(Contract.Result<Bpl.StmtList>() != null);\n\n      TrStmt(block, builder, locals, etran);\n      return builder.Collect(block.Tok);  // TODO: would be nice to have an end-curly location for \"block\"\n    }\n\n    /// <summary>\n    /// Add to \"builder\" the following:\n    ///     if (*) { S ; assume false; }\n    /// where \"S\" is the given \"builderToCollect\".  This method consumes what has been built up in \"builderToCollect\".\n    /// </summary>\n    void PathAsideBlock(IToken tok, BoogieStmtListBuilder builderToCollect, BoogieStmtListBuilder builder) {\n      Contract.Requires(tok != null);\n      Contract.Requires(builderToCollect != null);\n      Contract.Requires(builderToCollect != null);\n\n      builderToCollect.Add(new Bpl.AssumeCmd(tok, Bpl.Expr.False));\n      var ifCmd = new Bpl.IfCmd(tok, null, builderToCollect.Collect(tok), null, null);\n      builder.Add(ifCmd);\n    }\n\n    string CustomErrorMessage(Attributes attrs)\n    {\n      if (attrs == null) { return null; }\n      List<Expression> args = Attributes.FindExpressions(attrs, \"error\");\n      if (args == null) { return null; }\n      if (args.Count > 0) {\n        StringLiteralExpr l = args[0] as StringLiteralExpr;\n        return (string)l.Value;\n      } else {\n        return null;\n      }\n    }\n\n    void TrStmt(Statement stmt, BoogieStmtListBuilder builder, List<Variable> locals, ExpressionTranslator etran)\n    {\n      Contract.Requires(stmt != null);\n      Contract.Requires(builder != null);\n      Contract.Requires(locals != null);\n      Contract.Requires(etran != null);\n      Contract.Requires(codeContext != null && predef != null);\n      Contract.Ensures(fuelContext == Contract.OldValue(fuelContext));\n\n      stmtContext = StmtType.NONE;\n      adjustFuelForExists = true;  // fuel for exists might need to be adjusted based on whether it's in an assert or assume stmt.\n      if (stmt is PredicateStmt) {\n        var stmtBuilder = new BoogieStmtListBuilder(this);\n        string errorMessage = CustomErrorMessage(stmt.Attributes);\n        this.fuelContext = FuelSetting.ExpandFuelContext(stmt.Attributes, stmt.Tok, this.fuelContext, this.reporter);\n        var defineFuel = DefineFuelConstant(stmt.Tok, stmt.Attributes, stmtBuilder, etran);\n        var b = defineFuel ? stmtBuilder : builder;\n        if (stmt is AssertStmt || ArmadaOptions.O.DisallowSoundnessCheating) {\n          stmtContext = StmtType.ASSERT;\n          AddComment(b, stmt, \"assert statement\");\n          PredicateStmt s = (PredicateStmt)stmt;\n          TrStmt_CheckWellformed(s.Expr, b, locals, etran, false);\n          IToken enclosingToken = null;\n          if (Attributes.Contains(stmt.Attributes, \"_prependAssertToken\")) {\n            enclosingToken = stmt.Tok;\n          }\n          BoogieStmtListBuilder proofBuilder = null;\n          var assertStmt = stmt as AssertStmt;\n          if (assertStmt != null && assertStmt.Proof != null) {\n            proofBuilder = new BoogieStmtListBuilder(this);\n            AddComment(proofBuilder, stmt, \"assert statement proof\");\n            TrStmt(((AssertStmt)stmt).Proof, proofBuilder, locals, etran);\n          } else if (assertStmt != null && assertStmt.Label != null) {\n            proofBuilder = new BoogieStmtListBuilder(this);\n            AddComment(proofBuilder, stmt, \"assert statement proof\");\n          }\n          bool splitHappened;\n          var ss = TrSplitExpr(s.Expr, etran, true, out splitHappened);\n          if (!splitHappened) {\n            var tok = enclosingToken == null ? s.Expr.tok : new NestedToken(enclosingToken, s.Expr.tok);\n            (proofBuilder ?? b).Add(Assert(tok, etran.TrExpr(s.Expr), errorMessage ?? \"assertion violation\", stmt.Tok, etran.TrAttributes(stmt.Attributes, null)));\n          } else {\n            foreach (var split in ss) {\n              if (split.IsChecked) {\n                var tok = enclosingToken == null ? split.E.tok : new NestedToken(enclosingToken, split.E.tok);\n                (proofBuilder ?? b).Add(AssertNS(tok, split.E, errorMessage ?? \"assertion violation\", stmt.Tok, etran.TrAttributes(stmt.Attributes, null)));  // attributes go on every split\n              }\n            }\n          }\n          if (proofBuilder != null) {\n            PathAsideBlock(stmt.Tok, proofBuilder, b);\n          }\n          stmtContext = StmtType.NONE; // done with translating assert stmt\n          if (splitHappened || proofBuilder != null) {\n            if (assertStmt != null && assertStmt.Label != null) {\n              // make copies of the variables used in the assertion\n              var name = \"$Heap_at_\" + assertStmt.Label.AssignUniqueId(CurrentIdGenerator);\n              var heapAt = new Bpl.LocalVariable(stmt.Tok, new Bpl.TypedIdent(stmt.Tok, name, predef.HeapType));\n              locals.Add(heapAt);\n              var h = new Bpl.IdentifierExpr(stmt.Tok, heapAt);\n              b.Add(Bpl.Cmd.SimpleAssign(stmt.Tok, h, etran.HeapExpr));\n              var substMap = new Dictionary<IVariable, Expression>();\n              foreach (var v in ComputeFreeVariables(assertStmt.Expr)) {\n                if (v is LocalVariable) {\n                  var vcopy = new LocalVariable(stmt.Tok, stmt.Tok, string.Format(\"##{0}#{1}\", name, v.Name), v.Type, v.IsGhost, (v as LocalVariable).IsNoAddr);\n                  vcopy.type = vcopy.OptionalType;  // resolve local here\n                  IdentifierExpr ie = new IdentifierExpr(vcopy.Tok, vcopy.AssignUniqueName(currentDeclaration.IdGenerator));\n                  ie.Var = vcopy; ie.Type = ie.Var.Type;  // resolve ie here\n                  substMap.Add(v, ie);\n                  locals.Add(new Bpl.LocalVariable(vcopy.Tok, new Bpl.TypedIdent(vcopy.Tok, vcopy.AssignUniqueName(currentDeclaration.IdGenerator), TrType(vcopy.Type))));\n                  b.Add(Bpl.Cmd.SimpleAssign(stmt.Tok, TrVar(stmt.Tok, vcopy), TrVar(stmt.Tok, v)));\n                }\n              }\n              var exprToBeRevealed = Substitute(assertStmt.Expr, null, substMap);\n              var etr = new ExpressionTranslator(etran, h);\n              assertStmt.Label.E = etr.TrExpr(exprToBeRevealed);\n            } else if (!defineFuel) {\n              // Adding the assume stmt, resetting the stmtContext\n              stmtContext = StmtType.ASSUME;\n              adjustFuelForExists = true;\n              b.Add(TrAssumeCmd(stmt.Tok, etran.TrExpr(s.Expr)));\n              stmtContext = StmtType.NONE;\n            }\n          }\n          if (defineFuel) {\n            var ifCmd = new Bpl.IfCmd(s.Tok, null, b.Collect(s.Tok), null, null);  // BUGBUG: shouldn't this first append \"assume false\" to \"b\"? (use PathAsideBlock to do this)  --KRML\n            builder.Add(ifCmd);\n            // Adding the assume stmt, resetting the stmtContext\n            stmtContext = StmtType.ASSUME;\n            adjustFuelForExists = true;\n            builder.Add(TrAssumeCmd(stmt.Tok, etran.TrExpr(s.Expr)));\n            stmtContext = StmtType.NONE;\n          }\n        } else if (stmt is AssumeStmt) {\n          AddComment(builder, stmt, \"assume statement\");\n          AssumeStmt s = (AssumeStmt)stmt;\n          stmtContext = StmtType.ASSUME;\n          TrStmt_CheckWellformed(s.Expr, builder, locals, etran, false);\n          builder.Add(TrAssumeCmd(stmt.Tok, etran.TrExpr(s.Expr), etran.TrAttributes(stmt.Attributes, null)));\n          stmtContext = StmtType.NONE;  // done with translating assume stmt.\n        }\n        this.fuelContext = FuelSetting.PopFuelContext();\n      } else if (stmt is PrintStmt) {\n        AddComment(builder, stmt, \"print statement\");\n        PrintStmt s = (PrintStmt)stmt;\n        foreach (var arg in s.Args) {\n          TrStmt_CheckWellformed(arg, builder, locals, etran, false);\n        }\n\n      } else if (stmt is RevealStmt) {\n        AddComment(builder, stmt, \"reveal statement\");\n        var s = (RevealStmt)stmt;\n        foreach (var la in s.LabeledAsserts) {\n          Contract.Assert(la.E != null);  // this should have been filled in by now\n          builder.Add(new Bpl.AssumeCmd(s.Tok, la.E));\n        }\n        foreach (var resolved in s.ResolvedStatements) {\n          TrStmt(resolved, builder, locals, etran);\n        }\n\n      } else if (stmt is SomehowStmt) {\n        AddComment(builder, stmt, \"somehow statement\");\n        SomehowStmt s = (SomehowStmt)stmt;\n        reporter.Error(MessageSource.Translator, s.Tok, \"A somehow statement can't be translated\");\n\n      } else if (stmt is FenceStmt) {\n        AddComment(builder, stmt, \"fence statement\");\n        FenceStmt s = (FenceStmt)stmt;\n        reporter.Error(MessageSource.Translator, s.Tok, \"A fence statement can't be translated\");\n\n      } else if (stmt is GotoStmt) {\n        AddComment(builder, stmt, \"goto statement\");\n        GotoStmt s = (GotoStmt)stmt;\n        reporter.Error(MessageSource.Translator, s.Tok, \"A goto statement can't be translated\");\n\n      } else if (stmt is DeallocStmt) {\n        AddComment(builder, stmt, \"dealloc statement\");\n        DeallocStmt s = (DeallocStmt)stmt;\n        reporter.Error(MessageSource.Translator, s.Tok, \"A dealloc statement can't be translated\");\n\n      } else if (stmt is JoinStmt) {\n        AddComment(builder, stmt, \"join statement\");\n        JoinStmt s = (JoinStmt)stmt;\n        reporter.Error(MessageSource.Translator, s.Tok, \"A join statement can't be translated\");\n\n      } else if (stmt is BreakStmt) {\n        AddComment(builder, stmt, \"break statement\");\n        var s = (BreakStmt)stmt;\n        builder.Add(new GotoCmd(s.Tok, new List<String> { \"after_\" + s.TargetStmt.Labels.Data.AssignUniqueId(CurrentIdGenerator) }));\n      } else if (stmt is ReturnStmt) {\n        var s = (ReturnStmt)stmt;\n        AddComment(builder, stmt, \"return statement\");\n        if (s.ReverifyPost) {\n          // $_reverifyPost := true;\n          builder.Add(Bpl.Cmd.SimpleAssign(s.Tok, new Bpl.IdentifierExpr(s.Tok, \"$_reverifyPost\", Bpl.Type.Bool), Bpl.Expr.True));\n        }\n        if (s.hiddenUpdate != null) {\n          TrStmt(s.hiddenUpdate, builder, locals, etran);\n        }\n        if (codeContext is IMethodCodeContext) {\n          var method = (IMethodCodeContext)codeContext;\n          method.Outs.Iter(p => CheckDefiniteAssignmentReturn(stmt.Tok, p, builder));\n        }\n        builder.Add(new Bpl.ReturnCmd(stmt.Tok));\n      } else if (stmt is YieldStmt) {\n        var s = (YieldStmt)stmt;\n        AddComment(builder, s, \"yield statement\");\n        Contract.Assert(codeContext is IteratorDecl);\n        var iter = (IteratorDecl)codeContext;\n        // if the yield statement has arguments, do them first\n        if (s.hiddenUpdate != null) {\n          TrStmt(s.hiddenUpdate, builder, locals, etran);\n        }\n        // this.ys := this.ys + [this.y];\n        var th = new ThisExpr(iter.tok);\n        th.Type = Resolver.GetThisType(iter.tok, iter);  // resolve here\n        Contract.Assert(iter.OutsFields.Count == iter.OutsHistoryFields.Count);\n        for (int i = 0; i < iter.OutsFields.Count; i++) {\n          var y = iter.OutsFields[i];\n          var dafnyY = new MemberSelectExpr(s.Tok, th, y);\n          var ys = iter.OutsHistoryFields[i];\n          var dafnyYs = new MemberSelectExpr(s.Tok, th, ys);\n          var dafnySingletonY = new SeqDisplayExpr(s.Tok, new List<Expression>() { dafnyY });\n          dafnySingletonY.Type = ys.Type;  // resolve here\n          var rhs = new BinaryExpr(s.Tok, BinaryExpr.Opcode.Add, dafnyYs, dafnySingletonY);\n          rhs.ResolvedOp = BinaryExpr.ResolvedOpcode.Concat;\n          rhs.Type = ys.Type;  // resolve here\n          var cmd = Bpl.Cmd.SimpleAssign(s.Tok, (Bpl.IdentifierExpr/*TODO: this cast is rather dubious*/)etran.HeapExpr,\n            ExpressionTranslator.UpdateHeap(s.Tok, etran.HeapExpr, etran.TrExpr(th), new Bpl.IdentifierExpr(s.Tok, GetField(ys)), etran.TrExpr(rhs)));\n          builder.Add(cmd);\n        }\n        // yieldCount := yieldCount + 1;  assume yieldCount == |ys|;\n        var yc = new Bpl.IdentifierExpr(s.Tok, yieldCountVariable);\n        var incYieldCount = Bpl.Cmd.SimpleAssign(s.Tok, yc, Bpl.Expr.Binary(s.Tok, Bpl.BinaryOperator.Opcode.Add, yc, Bpl.Expr.Literal(1)));\n        builder.Add(incYieldCount);\n        builder.Add(TrAssumeCmd(s.Tok, YieldCountAssumption(iter, etran)));\n        // assume $IsGoodHeap($Heap);\n        builder.Add(AssumeGoodHeap(s.Tok, etran));\n        // assert YieldEnsures[subst];  // where 'subst' replaces \"old(E)\" with \"E\" being evaluated in $_OldIterHeap\n        var yeEtran = new ExpressionTranslator(this, predef, etran.HeapExpr, new Bpl.IdentifierExpr(s.Tok, \"$_OldIterHeap\", predef.HeapType));\n        foreach (var p in iter.YieldEnsures) {\n          if (p.IsFree && !ArmadaOptions.O.DisallowSoundnessCheating) {\n            // do nothing\n          } else {\n            bool splitHappened;  // actually, we don't care\n            var ss = TrSplitExpr(p.E, yeEtran, true, out splitHappened);\n            foreach (var split in ss) {\n              if (RefinementToken.IsInherited(split.E.tok, currentModule)) {\n                // this postcondition was inherited into this module, so just ignore it\n              } else if (split.IsChecked) {\n                var yieldToken = new NestedToken(s.Tok, split.E.tok);\n                builder.Add(AssertNS(yieldToken, split.E, \"possible violation of yield-ensures condition\", stmt.Tok, null));\n              }\n            }\n            builder.Add(TrAssumeCmd(stmt.Tok, yeEtran.TrExpr(p.E)));\n          }\n        }\n        YieldHavoc(iter.tok, iter, builder, etran);\n        builder.Add(CaptureState(s));\n\n      } else if (stmt is AssignSuchThatStmt) {\n        var s = (AssignSuchThatStmt)stmt;\n        AddComment(builder, s, \"assign-such-that statement\");\n        // Essentially, treat like an assert, a parallel havoc, and an assume.  However, we also need to check\n        // the well-formedness of the expression, which is easiest to do after the havoc.  So, we do the havoc\n        // first, then the well-formedness check, then the assert (unless the whole statement is an assume), and\n        // finally the assume.\n\n        // Here comes the havoc part\n        var lhss = new List<Expression>();\n        var havocRhss = new List<AssignmentRhs>();\n        foreach (var lhs in s.Lhss) {\n          lhss.Add(lhs.Resolved);\n          havocRhss.Add(new HavocRhs(lhs.tok));  // note, a HavocRhs is constructed as already resolved\n        }\n        List<AssignToLhs> lhsBuilder;\n        List<Bpl.IdentifierExpr> bLhss;\n        Bpl.Expr[] ignore1, ignore2;\n        string[] ignore3;\n        ProcessLhss(lhss, false, true, builder, locals, etran, out lhsBuilder, out bLhss, out ignore1, out ignore2, out ignore3);\n        foreach (var lhs in s.Lhss) {\n          var ide = lhs.Resolved as IdentifierExpr;\n          if (ide != null) {\n            MarkDefiniteAssignmentTracker(ide, builder);\n          }\n        }\n        ProcessRhss(lhsBuilder, bLhss, lhss, havocRhss, builder, locals, etran);\n        // Here comes the well-formedness check\n        TrStmt_CheckWellformed(s.Expr, builder, locals, etran, false);\n        // Here comes the assert part\n        if (s.AssumeToken == null) {\n          var substMap = new Dictionary<IVariable, Expression>();\n          var bvars = new List<BoundVar>();\n          foreach (var lhs in s.Lhss) {\n            var l = lhs.Resolved;\n            if (l is IdentifierExpr) {\n              var x = (IdentifierExpr)l;\n              BoundVar bv;\n              IdentifierExpr ie;\n              CloneVariableAsBoundVar(x.tok, x.Var, \"$as#\" + x.Name, out bv, out ie);\n              bvars.Add(bv);\n              substMap.Add(x.Var, ie);\n            } else {\n              // other forms of LHSs have been ruled out by the resolver (it would be possible to\n              // handle them, but it would involve heap-update expressions--the translation would take\n              // effort, and it's not certain that the existential would be successful in verification).\n              Contract.Assume(false);  // unexpected case\n            }\n          }\n\n          GenerateAndCheckGuesses(s.Tok, bvars, s.Bounds, Substitute(s.Expr, null, substMap), TrTrigger(etran, s.Attributes, s.Tok, substMap), builder, etran);\n        }\n        // End by doing the assume\n        builder.Add(TrAssumeCmd(s.Tok, etran.TrExpr(s.Expr)));\n        builder.Add(CaptureState(s));  // just do one capture state--here, at the very end (that is, don't do one before the assume)\n\n      } else if (stmt is UpdateStmt) {\n        var s = (UpdateStmt)stmt;\n        // This UpdateStmt can be single-target assignment, a multi-assignment, a call statement, or\n        // an array-range update.  Handle the multi-assignment here and handle the others as for .ResolvedStatements.\n        var resolved = s.ResolvedStatements;\n        if (resolved.Count == 1) {\n          TrStmt(resolved[0], builder, locals, etran);\n        } else {\n          AddComment(builder, s, \"update statement\");\n          var lhss = new List<Expression>();\n          foreach (var lhs in s.Lhss) {\n            lhss.Add(lhs.Resolved);\n          }\n          List<AssignToLhs> lhsBuilder;\n          List<Bpl.IdentifierExpr> bLhss;\n          // note: because we have more than one expression, we always must assign to Boogie locals in a two\n          // phase operation. Thus rhssCanAffectPreviouslyKnownExpressions is just true.\n          Contract.Assert(1 < lhss.Count);\n\n          Bpl.Expr[] lhsObjs, lhsFields;\n          string[] lhsNames;\n          ProcessLhss(lhss, true, false, builder, locals, etran, out lhsBuilder, out bLhss, out lhsObjs, out lhsFields, out lhsNames);\n          // We know that, because the translation saves to a local variable, that the RHS always need to\n          // generate a new local, i.e. bLhss is just all nulls.\n          Contract.Assert(Contract.ForAll(bLhss, lhs => lhs == null));\n          // This generates the assignments, and gives them to us as finalRhss.\n          var finalRhss = ProcessUpdateAssignRhss(lhss, s.Rhss, builder, locals, etran);\n          // ProcessLhss has laid down framing conditions and the ProcessUpdateAssignRhss will check subranges (nats),\n          // but we need to generate the distinctness condition (two LHS are equal only when the RHS is also\n          // equal). We need both the LHS and the RHS to do this, which is why we need to do it here.\n          CheckLhssDistinctness(finalRhss, s.Rhss, lhss, builder, etran, lhsObjs, lhsFields, lhsNames);\n          // Now actually perform the assignments to the LHS.\n          for (int i = 0; i < lhss.Count; i++) {\n            lhsBuilder[i](finalRhss[i], s.Rhss[i] is HavocRhs, builder, etran);\n          }\n          builder.Add(CaptureState(s));\n        }\n\n      } else if (stmt is AssignOrReturnStmt) {\n        AddComment(builder, stmt, \"assign-or-return statement (:-)\");\n        AssignOrReturnStmt s = (AssignOrReturnStmt)stmt;\n        TrStmtList(s.ResolvedStatements, builder, locals, etran);\n\n      } else if (stmt is AssignStmt) {\n        AddComment(builder, stmt, \"assignment statement\");\n        AssignStmt s = (AssignStmt)stmt;\n        TrAssignment(stmt, s.Lhs.Resolved, s.Rhs, builder, locals, etran);\n\n      } else if (stmt is CallStmt) {\n        AddComment(builder, stmt, \"call statement\");\n        TrCallStmt((CallStmt)stmt, builder, locals, etran, null);\n\n      } else if (stmt is DividedBlockStmt) {\n        var s = (DividedBlockStmt)stmt;\n        AddComment(builder, stmt, \"divided block before new;\");\n        var prevDefiniteAssignmentTrackerCount = definiteAssignmentTrackers.Count;\n        var tok = s.SeparatorTok ?? s.Tok;\n        // a DividedBlockStmt occurs only inside a Constructor body of a class\n        var cl = (ClassDecl)((Constructor)codeContext).EnclosingClass;\n        var fields = Concat(cl.InheritedMembers, cl.Members).ConvertAll(member =>\n          member is Field && !member.IsStatic && !member.IsInstanceIndependentConstant ? (Field)member : null);\n        fields.RemoveAll(f => f == null);\n        var localSurrogates = fields.ConvertAll(f => new Bpl.LocalVariable(f.tok, new TypedIdent(f.tok, SurrogateName(f), TrType(f.Type))));\n        locals.AddRange(localSurrogates);\n        fields.Iter(f => AddDefiniteAssignmentTrackerSurrogate(f, locals));\n\n        Contract.Assert(!inBodyInitContext);\n        inBodyInitContext = true;\n        TrStmtList(s.BodyInit, builder, locals, etran);\n        Contract.Assert(inBodyInitContext);\n        inBodyInitContext = false;\n\n        // The \"new;\" translates into an allocation of \"this\"\n        AddComment(builder, stmt, \"new;\");\n        fields.Iter(f => CheckDefiniteAssignmentSurrogate(s.SeparatorTok ?? s.EndTok, f, true, builder));\n        fields.Iter(f => RemoveDefiniteAssignmentTrackerSurrogate(f));\n        var th = new ThisExpr(tok);\n        th.Type = Resolver.GetThisType(tok, cl);  // resolve here\n        var bplThis = (Bpl.IdentifierExpr)etran.TrExpr(th);\n        SelectAllocateObject(tok, bplThis, th.Type, false, builder, etran);\n        for (int i = 0; i < fields.Count; i++) {\n          // assume $Heap[this, f] == this.f;\n          var mse = new MemberSelectExpr(tok, th, fields[i]);\n          builder.Add(new Bpl.AssumeCmd(tok, Bpl.Expr.Eq(etran.TrExpr(mse), new Bpl.IdentifierExpr(tok, localSurrogates[i]))));\n        }\n        CommitAllocatedObject(tok, bplThis, null, builder, etran);\n\n        AddComment(builder, stmt, \"divided block after new;\");\n        TrStmtList(s.BodyProper, builder, locals, etran);\n        RemoveDefiniteAssignmentTrackers(s.Body, prevDefiniteAssignmentTrackerCount);\n\n      } else if (stmt is BlockStmt) {\n        var s = (BlockStmt)stmt;\n        var prevDefiniteAssignmentTrackerCount = definiteAssignmentTrackers.Count;\n        TrStmtList(s.Body, builder, locals, etran);\n        RemoveDefiniteAssignmentTrackers(s.Body, prevDefiniteAssignmentTrackerCount);\n      } else if (stmt is IfStmt) {\n        AddComment(builder, stmt, \"if statement\");\n        IfStmt s = (IfStmt)stmt;\n        Expression guard;\n        if (s.Guard == null) {\n          guard = null;\n        } else {\n          guard = s.IsBindingGuard ? AlphaRename((ExistsExpr)s.Guard, \"eg$\") : s.Guard;\n          TrStmt_CheckWellformed(guard, builder, locals, etran, true);\n        }\n        BoogieStmtListBuilder b = new BoogieStmtListBuilder(this);\n        CurrentIdGenerator.Push();\n        if (s.IsBindingGuard) {\n          var exists = (ExistsExpr)s.Guard;  // the original (that is, not alpha-renamed) guard\n          IntroduceAndAssignExistentialVars(exists, b, builder, locals, etran, stmt.IsGhost);\n        }\n        Bpl.StmtList thn = TrStmt2StmtList(b, s.Thn, locals, etran);\n        CurrentIdGenerator.Pop();\n        Bpl.StmtList els;\n        Bpl.IfCmd elsIf = null;\n        b = new BoogieStmtListBuilder(this);\n        if (s.IsBindingGuard) {\n          b.Add(TrAssumeCmd(guard.tok, Bpl.Expr.Not(etran.TrExpr(guard))));\n        }\n        if (s.Els == null) {\n          els = b.Collect(s.Tok);\n        } else {\n          els = TrStmt2StmtList(b, s.Els, locals, etran);\n          if (els.BigBlocks.Count == 1) {\n            Bpl.BigBlock bb = els.BigBlocks[0];\n            if (bb.LabelName == null && bb.simpleCmds.Count == 0 && bb.ec is Bpl.IfCmd) {\n              elsIf = (Bpl.IfCmd)bb.ec;\n              els = null;\n            }\n          }\n        }\n        builder.Add(new Bpl.IfCmd(stmt.Tok, guard == null || s.IsBindingGuard ? null : etran.TrExpr(guard), thn, elsIf, els));\n\n      } else if (stmt is AlternativeStmt) {\n        AddComment(builder, stmt, \"alternative statement\");\n        var s = (AlternativeStmt)stmt;\n        var elseCase = Assert(s.Tok, Bpl.Expr.False, \"alternative cases fail to cover all possibilties\");\n        TrAlternatives(s.Alternatives, elseCase, null, builder, locals, etran, stmt.IsGhost);\n\n      } else if (stmt is WhileStmt) {\n        AddComment(builder, stmt, \"while statement\");\n        this.fuelContext = FuelSetting.ExpandFuelContext(stmt.Attributes, stmt.Tok, this.fuelContext, this.reporter);\n        DefineFuelConstant(stmt.Tok, stmt.Attributes, builder, etran);\n        var s = (WhileStmt)stmt;\n        BodyTranslator bodyTr = null;\n        if (s.Body != null) {\n          bodyTr = delegate(BoogieStmtListBuilder bld, ExpressionTranslator e) {\n            CurrentIdGenerator.Push();\n            TrStmt(s.Body, bld, locals, e);\n            CurrentIdGenerator.Pop();\n          };\n        }\n        TrLoop(s, s.Guard, bodyTr, builder, locals, etran);\n        this.fuelContext = FuelSetting.PopFuelContext();\n      } else if (stmt is AlternativeLoopStmt) {\n        AddComment(builder, stmt, \"alternative loop statement\");\n        var s = (AlternativeLoopStmt)stmt;\n        var tru = new LiteralExpr(s.Tok, true);\n        tru.Type = Type.Bool;  // resolve here\n        TrLoop(s, tru,\n          delegate(BoogieStmtListBuilder bld, ExpressionTranslator e) { TrAlternatives(s.Alternatives, null, new Bpl.BreakCmd(s.Tok, null), bld, locals, e, stmt.IsGhost); },\n          builder, locals, etran);\n\n      } else if (stmt is ModifyStmt) {\n        AddComment(builder, stmt, \"modify statement\");\n        var s = (ModifyStmt)stmt;\n        // check that the modifies is a subset\n        CheckFrameSubset(s.Tok, s.Mod.Expressions, null, null, etran, builder, \"modify statement may violate context's modifies clause\", null);\n        // cause the change of the heap according to the given frame\n        var suffix = CurrentIdGenerator.FreshId(\"modify#\");\n        string modifyFrameName = \"$Frame$\" + suffix;\n        var preModifyHeapVar = new Bpl.LocalVariable(s.Tok, new Bpl.TypedIdent(s.Tok, \"$PreModifyHeap$\" + suffix, predef.HeapType));\n        locals.Add(preModifyHeapVar);\n        DefineFrame(s.Tok, s.Mod.Expressions, builder, locals, modifyFrameName);\n        if (s.Body == null) {\n          var preModifyHeap = new Bpl.IdentifierExpr(s.Tok, preModifyHeapVar);\n          // preModifyHeap := $Heap;\n          builder.Add(Bpl.Cmd.SimpleAssign(s.Tok, preModifyHeap, etran.HeapExpr));\n          // havoc $Heap;\n          builder.Add(new Bpl.HavocCmd(s.Tok, new List<Bpl.IdentifierExpr> { (Bpl.IdentifierExpr/*TODO: this cast is rather dubious*/)etran.HeapExpr }));\n          // assume $HeapSucc(preModifyHeap, $Heap);   OR $HeapSuccGhost\n          builder.Add(TrAssumeCmd(s.Tok, HeapSucc(preModifyHeap, etran.HeapExpr, s.IsGhost)));\n          // assume nothing outside the frame was changed\n          var etranPreLoop = new ExpressionTranslator(this, predef, preModifyHeap);\n          var updatedFrameEtran = new ExpressionTranslator(etran, modifyFrameName);\n          builder.Add(TrAssumeCmd(s.Tok, FrameConditionUsingDefinedFrame(s.Tok, etranPreLoop, etran, updatedFrameEtran)));\n        } else {\n          // do the body, but with preModifyHeapVar as the governing frame\n          var updatedFrameEtran = new ExpressionTranslator(etran, modifyFrameName);\n          TrStmt(s.Body, builder, locals, updatedFrameEtran);\n        }\n        builder.Add(CaptureState(stmt));\n\n      } else if (stmt is ForallStmt) {\n        var s = (ForallStmt)stmt;\n        this.fuelContext = FuelSetting.ExpandFuelContext(stmt.Attributes, stmt.Tok, this.fuelContext, this.reporter);\n\n        if (s.Kind == ForallStmt.BodyKind.Assign) {\n          AddComment(builder, stmt, \"forall statement (assign)\");\n          Contract.Assert(s.Ens.Count == 0);\n          if (s.BoundVars.Count == 0) {\n            TrStmt(s.Body, builder, locals, etran);\n          } else {\n            var s0 = (AssignStmt)s.S0;\n            var definedness = new BoogieStmtListBuilder(this);\n            var updater = new BoogieStmtListBuilder(this);\n            DefineFuelConstant(stmt.Tok, stmt.Attributes, definedness, etran);\n            TrForallAssign(s, s0, definedness, updater, locals, etran);\n            // All done, so put the two pieces together\n            builder.Add(new Bpl.IfCmd(s.Tok, null, definedness.Collect(s.Tok), null, updater.Collect(s.Tok)));\n            builder.Add(CaptureState(stmt));\n          }\n\n        } else if (s.Kind == ForallStmt.BodyKind.Call) {\n          AddComment(builder, stmt, \"forall statement (call)\");\n          Contract.Assert(s.Ens.Count == 0);\n          if (s.BoundVars.Count == 0) {\n            Contract.Assert(LiteralExpr.IsTrue(s.Range));  // follows from the invariant of ForallStmt\n            TrStmt(s.Body, builder, locals, etran);\n          } else {\n            var s0 = (CallStmt)s.S0;\n            if (Attributes.Contains(s.Attributes, \"_trustWellformed\")) {\n              TrForallStmtCall(s.Tok, s.BoundVars, s.Bounds, s.Range, null, s.ForallExpressions, s0, null, builder, locals, etran);\n            } else {\n              var definedness = new BoogieStmtListBuilder(this);\n              DefineFuelConstant(stmt.Tok, stmt.Attributes, definedness, etran);\n              var exporter = new BoogieStmtListBuilder(this);\n              TrForallStmtCall(s.Tok, s.BoundVars, s.Bounds, s.Range, null, s.ForallExpressions, s0, definedness, exporter, locals, etran);\n              // All done, so put the two pieces together\n              builder.Add(new Bpl.IfCmd(s.Tok, null, definedness.Collect(s.Tok), null, exporter.Collect(s.Tok)));\n            }\n            builder.Add(CaptureState(stmt));\n          }\n\n        } else if (s.Kind == ForallStmt.BodyKind.Proof) {\n          AddComment(builder, stmt, \"forall statement (proof)\");\n          var definedness = new BoogieStmtListBuilder(this);\n          var exporter = new BoogieStmtListBuilder(this);\n          DefineFuelConstant(stmt.Tok, stmt.Attributes, definedness, etran);\n          TrForallProof(s, definedness, exporter, locals, etran);\n          // All done, so put the two pieces together\n          builder.Add(new Bpl.IfCmd(s.Tok, null, definedness.Collect(s.Tok), null, exporter.Collect(s.Tok)));\n          builder.Add(CaptureState(stmt));\n\n        } else {\n          Contract.Assert(false);  // unexpected kind\n        }\n        this.fuelContext = FuelSetting.PopFuelContext();\n      } else if (stmt is CalcStmt) {\n        /* Translate into:\n        if (*) {\n            assert wf(line0);\n        } else if (*) {\n            assume wf(line0);\n            // if op is ==>: assume line0;\n            hint0;\n            assert wf(line1);\n            assert line0 op line1;\n            assume false;\n        } else if (*) { ...\n        } else if (*) {\n            assume wf(line<n-1>);\n            // if op is ==>: assume line<n-1>;\n            hint<n-1>;\n            assert wf(line<n>);\n            assert line<n-1> op line<n>;\n            assume false;\n        }\n        assume line<0> op line<n>;\n        */\n        var s = (CalcStmt)stmt;\n        Contract.Assert(s.Steps.Count == s.Hints.Count); // established by the resolver\n        AddComment(builder, stmt, \"calc statement\");\n        this.fuelContext = FuelSetting.ExpandFuelContext(stmt.Attributes, stmt.Tok, this.fuelContext, this.reporter);\n        DefineFuelConstant(stmt.Tok, stmt.Attributes, builder, etran);\n        CurrentIdGenerator.Push();  // put the entire calc statement within its own sub-branch\n        if (s.Lines.Count > 0) {\n          Bpl.IfCmd ifCmd = null;\n          BoogieStmtListBuilder b;\n          // if the dangling hint is empty, do not generate anything for the dummy step\n          var stepCount = s.Hints.Last().Body.Count == 0 ? s.Steps.Count - 1 : s.Steps.Count;\n          // check steps:\n          for (int i = stepCount; 0 <= --i; ) {\n            b = new BoogieStmtListBuilder(this);\n            // assume wf[line<i>]:\n            AddComment(b, stmt, \"assume wf[lhs]\");\n            CurrentIdGenerator.Push();\n            assertAsAssume = true;\n            TrStmt_CheckWellformed(CalcStmt.Lhs(s.Steps[i]), b, locals, etran, false);\n            assertAsAssume = false;\n            if (s.Steps[i] is BinaryExpr && (((BinaryExpr)s.Steps[i]).ResolvedOp == BinaryExpr.ResolvedOpcode.Imp)) {\n              // assume line<i>:\n              AddComment(b, stmt, \"assume lhs\");\n              b.Add(TrAssumeCmd(s.Tok, etran.TrExpr(CalcStmt.Lhs(s.Steps[i]))));\n            }\n            // hint:\n            AddComment(b, stmt, \"Hint\" + i.ToString());\n            TrStmt(s.Hints[i], b, locals, etran);\n            if (i < s.Steps.Count - 1) { // non-dummy step\n              // check well formedness of the goal line:\n              AddComment(b, stmt, \"assert wf[rhs]\");\n              if (s.Steps[i] is TernaryExpr) {\n                // check the prefix-equality limit\n                var index = ((TernaryExpr) s.Steps[i]).E0;\n                TrStmt_CheckWellformed(index, b, locals, etran, false);\n                if (index.Type.IsNumericBased(Type.NumericPersuation.Int)) {\n                  b.Add(AssertNS(index.tok, Bpl.Expr.Le(Bpl.Expr.Literal(0), etran.TrExpr(index)), \"prefix-equality limit must be at least 0\"));\n                }\n              }\n              TrStmt_CheckWellformed(CalcStmt.Rhs(s.Steps[i]), b, locals, etran, false);\n              bool splitHappened;\n              var ss = TrSplitExpr(s.Steps[i], etran, true, out splitHappened);\n              // assert step:\n              AddComment(b, stmt, \"assert line\" + i.ToString() + \" \" + (s.StepOps[i] ?? s.Op).ToString() + \" line\" + (i + 1).ToString());\n              if (!splitHappened) {\n                b.Add(AssertNS(s.Lines[i + 1].tok, etran.TrExpr(s.Steps[i]), \"the calculation step between the previous line and this line might not hold\"));\n              } else {\n                foreach (var split in ss) {\n                  if (split.IsChecked) {\n                    b.Add(AssertNS(s.Lines[i + 1].tok, split.E, \"the calculation step between the previous line and this line might not hold\"));\n                  }\n                }\n              }\n            }\n            b.Add(TrAssumeCmd(s.Tok, Bpl.Expr.False));\n            ifCmd = new Bpl.IfCmd(s.Tok, null, b.Collect(s.Tok), ifCmd, null);\n            CurrentIdGenerator.Pop();\n          }\n          // check well formedness of the first line:\n          b = new BoogieStmtListBuilder(this);\n          AddComment(b, stmt, \"assert wf[initial]\");\n          Contract.Assert(s.Result != null); // established by the resolver\n          TrStmt_CheckWellformed(CalcStmt.Lhs(s.Result), b, locals, etran, false);\n          b.Add(TrAssumeCmd(s.Tok, Bpl.Expr.False));\n          ifCmd = new Bpl.IfCmd(s.Tok, null, b.Collect(s.Tok), ifCmd, null);\n          builder.Add(ifCmd);\n          // assume result:\n          if (s.Steps.Count > 1) {\n            builder.Add(TrAssumeCmd(s.Tok, etran.TrExpr(s.Result)));\n          }\n        }\n        CurrentIdGenerator.Pop();\n        this.fuelContext = FuelSetting.PopFuelContext();\n      } else if (stmt is MatchStmt) {\n        var s = (MatchStmt)stmt;\n        TrStmt_CheckWellformed(s.Source, builder, locals, etran, true);\n        Bpl.Expr source = etran.TrExpr(s.Source);\n\n        var b = new BoogieStmtListBuilder(this);\n        b.Add(TrAssumeCmd(stmt.Tok, Bpl.Expr.False));\n        Bpl.StmtList els = b.Collect(stmt.Tok);\n        Bpl.IfCmd ifCmd = null;\n        foreach (var missingCtor in s.MissingCases) {\n          // havoc all bound variables\n          b = new BoogieStmtListBuilder(this);\n          List<Variable> newLocals = new List<Variable>();\n          Bpl.Expr r = CtorInvocation(s.Tok, missingCtor, etran, newLocals, b);\n          locals.AddRange(newLocals);\n\n          if (newLocals.Count != 0)\n          {\n            List<Bpl.IdentifierExpr> havocIds = new List<Bpl.IdentifierExpr>();\n            foreach (Variable local in newLocals) {\n              havocIds.Add(new Bpl.IdentifierExpr(local.tok, local));\n            }\n            builder.Add(new Bpl.HavocCmd(s.Tok, havocIds));\n          }\n          b.Add(Assert(s.Tok, Bpl.Expr.False, \"missing case in case statement: \" + missingCtor.Name));\n\n          Bpl.Expr guard = Bpl.Expr.Eq(source, r);\n          ifCmd = new Bpl.IfCmd(s.Tok, guard, b.Collect(s.Tok), ifCmd, els);\n          els = null;\n        }\n        for (int i = s.Cases.Count; 0 <= --i; ) {\n          var mc = (MatchCaseStmt)s.Cases[i];\n          CurrentIdGenerator.Push();\n          // havoc all bound variables\n          b = new BoogieStmtListBuilder(this);\n          List<Variable> newLocals = new List<Variable>();\n          Bpl.Expr r = CtorInvocation(mc, etran, newLocals, b, s.IsGhost ? NOALLOC : ISALLOC);\n          locals.AddRange(newLocals);\n\n          if (newLocals.Count != 0)\n          {\n            List<Bpl.IdentifierExpr> havocIds = new List<Bpl.IdentifierExpr>();\n            foreach (Variable local in newLocals) {\n              havocIds.Add(new Bpl.IdentifierExpr(local.tok, local));\n            }\n            builder.Add(new Bpl.HavocCmd(mc.tok, havocIds));\n          }\n\n          // translate the body into b\n          var prevDefiniteAssignmentTrackerCount = definiteAssignmentTrackers.Count;\n          TrStmtList(mc.Body, b, locals, etran);\n          RemoveDefiniteAssignmentTrackers(mc.Body, prevDefiniteAssignmentTrackerCount);\n\n          Bpl.Expr guard = Bpl.Expr.Eq(source, r);\n          ifCmd = new Bpl.IfCmd(mc.tok, guard, b.Collect(mc.tok), ifCmd, els);\n          els = null;\n          CurrentIdGenerator.Pop();\n        }\n        Contract.Assert(ifCmd != null);  // follows from the fact that s.Cases.Count + s.MissingCases.Count != 0.\n        builder.Add(ifCmd);\n\n      } else if (stmt is VarDeclStmt) {\n        var s = (VarDeclStmt)stmt;\n        var newLocalIds = new List<Bpl.IdentifierExpr>();\n        int i = 0;\n        foreach (var local in s.Locals) {\n          Bpl.Type varType = TrType(local.Type);\n          Bpl.Expr wh = GetWhereClause(local.Tok,\n            new Bpl.IdentifierExpr(local.Tok, local.AssignUniqueName(currentDeclaration.IdGenerator), varType),\n            local.Type, etran, isAllocContext.Var(stmt.IsGhost, local));\n          Bpl.LocalVariable var = new Bpl.LocalVariable(local.Tok, new Bpl.TypedIdent(local.Tok, local.AssignUniqueName(currentDeclaration.IdGenerator), varType, wh));\n          var.Attributes = etran.TrAttributes(local.Attributes, null);\n          newLocalIds.Add(new Bpl.IdentifierExpr(local.Tok, var));\n          locals.Add(var);\n          // if needed, register definite-assignment tracking for this local\n          var needDefiniteAssignmentTracking = s.Update == null;\n          if (s.Update is UpdateStmt) {\n            // there is an initial assignment, but we need to look out for \"*\" being that assignment\n            var us = (UpdateStmt)s.Update;\n            if (i < us.Rhss.Count && us.Rhss[i] is HavocRhs) {\n              needDefiniteAssignmentTracking = true;\n            }\n          }\n          if (needDefiniteAssignmentTracking) {\n            AddDefiniteAssignmentTracker(local, locals);\n          }\n          i++;\n        }\n        if (s.Update == null) {\n          // it is necessary to do a havoc here in order to give the variable the correct allocation state\n          builder.Add(new HavocCmd(s.Tok, newLocalIds));\n        }\n        // processing of \"assumption\" variables happens after the variable is possibly havocked above\n        foreach (var local in s.Locals) {\n          if (Attributes.Contains(local.Attributes, \"assumption\")) {\n            Bpl.Type varType = TrType(local.Type);\n            builder.Add(new AssumeCmd(local.Tok, new Bpl.IdentifierExpr(local.Tok, local.AssignUniqueName(currentDeclaration.IdGenerator), varType), new QKeyValue(local.Tok, \"assumption_variable_initialization\", new List<object>(), null)));\n          }\n        }\n        if (s.Update != null) {\n          TrStmt(s.Update, builder, locals, etran);\n        }\n      } else if (stmt is LetStmt) {\n        var s = (LetStmt)stmt;\n        foreach (var local in s.LocalVars) {\n          Bpl.LocalVariable bvar = new Bpl.LocalVariable(local.Tok, new Bpl.TypedIdent(local.Tok, local.AssignUniqueName(currentDeclaration.IdGenerator), TrType(local.Type)));\n          locals.Add(bvar);\n          var bIe = new Bpl.IdentifierExpr(bvar.tok, bvar);\n          builder.Add(new Bpl.HavocCmd(local.Tok, new List<Bpl.IdentifierExpr> { bIe }));\n          Bpl.Expr wh = GetWhereClause(local.Tok, bIe, local.Type, etran, isAllocContext.Var(stmt.IsGhost, local));\n          if (wh != null) {\n            builder.Add(TrAssumeCmd(local.Tok, wh));\n          }\n        }\n        var varNameGen = CurrentIdGenerator.NestedFreshIdGenerator(\"let#\");\n        var pat = s.LHS;\n        var rhs = s.RHS;\n        var nm = varNameGen.FreshId(string.Format(\"#{0}#\", 0));\n        var r = new Bpl.LocalVariable(pat.tok, new Bpl.TypedIdent(pat.tok, nm, TrType(rhs.Type)));\n        locals.Add(r);\n        var rIe = new Bpl.IdentifierExpr(rhs.tok, r);\n        CheckWellformedWithResult(rhs, new WFOptions(null, false, false), rIe, pat.Expr.Type, locals, builder, etran);\n        CheckCasePatternShape(pat, rIe, rhs.tok, pat.Expr.Type, builder);\n        builder.Add(TrAssumeCmd(pat.tok, Bpl.Expr.Eq(etran.TrExpr(pat.Expr), rIe)));\n      } else {\n        Contract.Assert(false); throw new cce.UnreachableException();  // unexpected statement\n      }\n    }\n\n    private void GenerateAndCheckGuesses(IToken tok, List<BoundVar> bvars, List<ComprehensionExpr.BoundedPool> bounds, Expression expr, Trigger triggers, BoogieStmtListBuilder builder, ExpressionTranslator etran) {\n      Contract.Requires(tok != null);\n      Contract.Requires(bvars != null);\n      Contract.Requires(bounds != null);\n      Contract.Requires(expr != null);\n      Contract.Requires(builder != null);\n      Contract.Requires(etran != null);\n\n      List<Tuple<List<Tuple<BoundVar, Expression>>, Expression>> partialGuesses = GeneratePartialGuesses(bvars, expr);\n      Bpl.Expr w = Bpl.Expr.False;\n      foreach (var tup in partialGuesses) {\n        var body = etran.TrExpr(tup.Item2);\n        Bpl.Expr typeConstraints = Bpl.Expr.True;\n        var undetermined = new List<BoundVar>();\n        foreach (var be in tup.Item1) {\n          if (be.Item2 == null) {\n            undetermined.Add(be.Item1);\n          } else {\n            typeConstraints = BplAnd(typeConstraints, MkIs(etran.TrExpr(be.Item2), be.Item1.Type));\n          }\n        }\n        body = BplAnd(typeConstraints, body);\n        if (undetermined.Count != 0) {\n          List<bool> freeOfAlloc = null;\n          if (FrugalHeapUseX) {\n            freeOfAlloc = ComprehensionExpr.BoundedPool.HasBounds(bounds, ComprehensionExpr.BoundedPool.PoolVirtues.IndependentOfAlloc_or_ExplicitAlloc);\n          }\n          var bvs = new List<Variable>();\n          var typeAntecedent = etran.TrBoundVariables(undetermined, bvs, false, freeOfAlloc);\n          body = new Bpl.ExistsExpr(tok, bvs, triggers, BplAnd(typeAntecedent, body));\n        }\n        w = BplOr(body, w);\n      }\n      builder.Add(Assert(tok, w, \"cannot establish the existence of LHS values that satisfy the such-that predicate\"));\n    }\n\n    private void IntroduceAndAssignExistentialVars(ExistsExpr exists, BoogieStmtListBuilder builder, BoogieStmtListBuilder builderOutsideIfConstruct, List<Variable> locals, ExpressionTranslator etran, bool isGhost) {\n      Contract.Requires(exists != null);\n      Contract.Requires(exists.Range == null);\n      Contract.Requires(builder != null);\n      Contract.Requires(builderOutsideIfConstruct != null);\n      Contract.Requires(locals != null);\n      Contract.Requires(etran != null);\n      // declare and havoc the bound variables of 'exists' as local variables\n      var iesForHavoc = new List<Bpl.IdentifierExpr>();\n      foreach (var bv in exists.BoundVars) {\n        Bpl.Type varType = TrType(bv.Type);\n        Bpl.Expr wh = GetWhereClause(bv.Tok,\n          new Bpl.IdentifierExpr(bv.Tok, bv.AssignUniqueName(currentDeclaration.IdGenerator), varType),\n          bv.Type, etran, isAllocContext.Var(isGhost, bv));\n        Bpl.Variable local = new Bpl.LocalVariable(bv.Tok, new Bpl.TypedIdent(bv.Tok, bv.AssignUniqueName(currentDeclaration.IdGenerator), varType, wh));\n        locals.Add(local);\n        iesForHavoc.Add(new Bpl.IdentifierExpr(local.tok, local));\n      }\n      builderOutsideIfConstruct.Add(new Bpl.HavocCmd(exists.tok, iesForHavoc));\n      builder.Add(TrAssumeCmd(exists.tok, etran.TrExpr(exists.Term)));\n    }\n\n    void TrStmtList(List<Statement> stmts, BoogieStmtListBuilder builder, List<Variable> locals, ExpressionTranslator etran) {\n      Contract.Requires(stmts != null);\n      Contract.Requires(builder != null);\n      Contract.Requires(locals != null);\n      Contract.Requires(etran != null);\n      foreach (Statement ss in stmts) {\n        for (var l = ss.Labels; l != null; l = l.Next) {\n          var heapAt = new Bpl.LocalVariable(ss.Tok, new Bpl.TypedIdent(ss.Tok, \"$Heap_at_\" + l.Data.AssignUniqueId(CurrentIdGenerator), predef.HeapType));\n          locals.Add(heapAt);\n          builder.Add(Bpl.Cmd.SimpleAssign(ss.Tok, new Bpl.IdentifierExpr(ss.Tok, heapAt), etran.HeapExpr));\n        }\n        TrStmt(ss, builder, locals, etran);\n        if (ss.Labels != null) {\n          builder.AddLabelCmd(\"after_\" + ss.Labels.Data.AssignUniqueId(CurrentIdGenerator));\n        }\n      }\n    }\n\n    /// <summary>\n    /// Returns an expression like 'exists' but where the bound variables have been renamed to have\n    /// 'prefix' as a prefix to their previous names.\n    /// Assumes the expression has been resolved.\n    /// </summary>\n    public static Expression AlphaRename(ExistsExpr exists, string prefix) {\n      Contract.Requires(exists != null);\n      Contract.Requires(prefix != null);\n\n      if (exists.SplitQuantifier != null) {\n        // TODO: what to do?  Substitute(exists.SplitQuantifierExpression);\n      }\n\n      var substMap = new Dictionary<IVariable, Expression>();\n      var var4var = new Dictionary<BoundVar, BoundVar>();\n      var bvars = new List<BoundVar>();\n      foreach (var bv in exists.BoundVars) {\n        var newBv = new BoundVar(bv.tok, prefix + bv.Name, bv.Type);\n        bvars.Add(newBv);\n        var4var.Add(bv, newBv);\n        var ie = new IdentifierExpr(newBv.tok, newBv.Name);\n        ie.Var = newBv;  // resolve here\n        ie.Type = newBv.Type;  // resolve here\n        substMap.Add(bv, ie);\n      }\n      var s = new Substituter(null, substMap, new Dictionary<TypeParameter, Type>());\n      var range = exists.Range == null ? null : s.Substitute(exists.Range);\n      var term = s.Substitute(exists.Term);\n      var attrs = s.SubstAttributes(exists.Attributes);\n      var ex = new ExistsExpr(exists.tok, exists.TypeArgs, bvars, range, term, attrs);\n      if (exists.Bounds != null) {\n        ex.Bounds = exists.Bounds.ConvertAll(bound => s.SubstituteBoundedPool(bound));\n      }\n      return ex;\n    }\n\n    /// <summary>\n    /// Generate:\n    ///   havoc Heap \\ {this} \\ _reads \\ _new;\n    ///   assume this.Valid();\n    ///   assume YieldRequires;\n    ///   $_OldIterHeap := Heap;\n    /// </summary>\n    void YieldHavoc(IToken tok, IteratorDecl iter, BoogieStmtListBuilder builder, ExpressionTranslator etran) {\n      Contract.Requires(tok != null);\n      Contract.Requires(iter != null);\n      Contract.Requires(builder != null);\n      Contract.Requires(etran != null);\n      // havoc Heap \\ {this} \\ _reads \\ _new;\n      var th = new ThisExpr(tok);\n      th.Type = Resolver.GetThisType(tok, iter);  // resolve here\n      var rds = new MemberSelectExpr(tok, th, iter.Member_Reads);\n      var nw = new MemberSelectExpr(tok, th, iter.Member_New);\n      builder.Add(new Bpl.CallCmd(tok, \"$YieldHavoc\",\n        new List<Bpl.Expr>() { etran.TrExpr(th), etran.TrExpr(rds), etran.TrExpr(nw) },\n        new List<Bpl.IdentifierExpr>()));\n      // assume YieldRequires;\n      foreach (var p in iter.YieldRequires) {\n        builder.Add(TrAssumeCmd(tok, etran.TrExpr(p.E)));\n      }\n      // $_OldIterHeap := Heap;\n      builder.Add(Bpl.Cmd.SimpleAssign(tok, new Bpl.IdentifierExpr(tok, \"$_OldIterHeap\", predef.HeapType), etran.HeapExpr));\n    }\n\n    List<Tuple<List<Tuple<BoundVar, Expression>>, Expression>> GeneratePartialGuesses(List<BoundVar> bvars, Expression expression) {\n      if (bvars.Count == 0) {\n        var tup = new Tuple<List<Tuple<BoundVar, Expression>>, Expression>(new List<Tuple<BoundVar, Expression>>(), expression);\n        return new List<Tuple<List<Tuple<BoundVar, Expression>>, Expression>>() { tup };\n      }\n      var result = new List<Tuple<List<Tuple<BoundVar, Expression>>, Expression>>();\n      var x = bvars[0];\n      var otherBvars = bvars.GetRange(1, bvars.Count - 1);\n      foreach (var tup in GeneratePartialGuesses(otherBvars, expression)) {\n        // in the special case that x does not even occur in expression, we can just ignore x\n        if (!ContainsFreeVariable(tup.Item2, false, x)) {\n          result.Add(tup);\n          continue;\n        }\n        // one possible result is to quantify over all the variables\n        var vs = new List<Tuple<BoundVar, Expression>>() { new Tuple<BoundVar, Expression>(x, null) };\n        vs.AddRange(tup.Item1);\n        result.Add(new Tuple<List<Tuple<BoundVar, Expression>>, Expression>(vs, tup.Item2));\n        // other possibilities involve guessing a value for x\n        foreach (var guess in GuessWitnesses(x, tup.Item2)) {\n          var g = Substitute(tup.Item2, x, guess);\n          vs = new List<Tuple<BoundVar, Expression>>() { new Tuple<BoundVar, Expression>(x, guess) };\n          AddRangeSubst(vs, tup.Item1, x, guess);\n          result.Add(new Tuple<List<Tuple<BoundVar, Expression>>, Expression>(vs, g));\n        }\n      }\n      return result;\n    }\n\n    private void AddRangeSubst(List<Tuple<BoundVar, Expression>> vs, List<Tuple<BoundVar, Expression>> aa, IVariable v, Expression e) {\n      Contract.Requires(vs != null);\n      Contract.Requires(aa != null);\n      Contract.Requires(v != null);\n      Contract.Requires(e != null);\n      foreach (var be in aa) {\n        if (be.Item2 == null) {\n          vs.Add(be);\n        } else {\n          vs.Add(new Tuple<BoundVar, Expression>(be.Item1, Substitute(be.Item2, v, e)));\n        }\n      }\n    }\n\n    IEnumerable<Expression> GuessWitnesses(BoundVar x, Expression expr) {\n      Contract.Requires(x != null);\n      Contract.Requires(expr != null);\n      var xType = x.Type.NormalizeExpand();\n      if (xType is BoolType) {\n        var lit = new LiteralExpr(x.tok, false);\n        lit.Type = Type.Bool;  // resolve here\n        yield return lit;\n        lit = new LiteralExpr(x.tok, true);\n        lit.Type = Type.Bool;  // resolve here\n        yield return lit;\n        yield break;  // there are no more possible witnesses for booleans\n      } else if (xType is CharType) {\n        // TODO: something could be done for character literals\n      } else if (xType.IsBitVectorType) {\n        // TODO: something could be done for bitvectors\n      } else if (xType.IsRefType) {\n        var lit = new LiteralExpr(x.tok);  // null\n        lit.Type = xType;\n        yield return lit;\n      } else if (xType.IsDatatype) {\n        var dt = xType.AsDatatype;\n        Expression zero = Zero(x.tok, xType);\n        if (zero != null) {\n          yield return zero;\n        }\n        foreach (var ctor in dt.Ctors) {\n          if (ctor.Formals.Count == 0) {\n            var v = new DatatypeValue(x.tok, dt.Name, ctor.Name, new List<Expression>());\n            v.Ctor = ctor;  // resolve here\n            v.InferredTypeArgs = xType.TypeArgs; // resolved here.\n            v.Type = xType;  // resolve here\n            yield return v;\n          }\n        }\n      } else if (xType is SetType) {\n        var empty = new SetDisplayExpr(x.tok, ((SetType)xType).Finite, new List<Expression>());\n        empty.Type = xType;\n        yield return empty;\n      } else if (xType is MultiSetType) {\n        var empty = new MultiSetDisplayExpr(x.tok, new List<Expression>());\n        empty.Type = xType;\n        yield return empty;\n      } else if (xType is SeqType) {\n        var empty = new SeqDisplayExpr(x.tok, new List<Expression>());\n        empty.Type = xType;\n        yield return empty;\n      } else if (xType.IsNumericBased(Type.NumericPersuation.Int)) {\n        var lit = new LiteralExpr(x.tok, 0);\n        lit.Type = xType;  // resolve here\n        yield return lit;\n      } else if (xType.IsNumericBased(Type.NumericPersuation.Real)) {\n        var lit = new LiteralExpr(x.tok, BaseTypes.BigDec.ZERO);\n        lit.Type = xType;  // resolve here\n        yield return lit;\n      }\n\n      var bounds = Resolver.DiscoverAllBounds_SingleVar(x, expr);\n      foreach (var bound in bounds) {\n        if (bound is ComprehensionExpr.IntBoundedPool) {\n          var bnd = (ComprehensionExpr.IntBoundedPool)bound;\n          if (bnd.LowerBound != null) yield return bnd.LowerBound;\n          if (bnd.UpperBound != null) yield return Expression.CreateDecrement(bnd.UpperBound, 1);\n        } else if (bound is ComprehensionExpr.SubSetBoundedPool) {\n          var bnd = (ComprehensionExpr.SubSetBoundedPool)bound;\n          yield return bnd.UpperBound;\n        } else if (bound is ComprehensionExpr.SuperSetBoundedPool) {\n          var bnd = (ComprehensionExpr.SuperSetBoundedPool)bound;\n          yield return bnd.LowerBound;\n        } else if (bound is ComprehensionExpr.SetBoundedPool) {\n          var st = ((ComprehensionExpr.SetBoundedPool)bound).Set.Resolved;\n          if (st is DisplayExpression) {\n            var display = (DisplayExpression)st;\n            foreach (var el in display.Elements) {\n              yield return el;\n            }\n          } else if (st is MapDisplayExpr) {\n            var display = (MapDisplayExpr)st;\n            foreach (var maplet in display.Elements) {\n              yield return maplet.A;\n            }\n          }\n        } else if (bound is ComprehensionExpr.MultiSetBoundedPool) {\n          var st = ((ComprehensionExpr.MultiSetBoundedPool)bound).MultiSet.Resolved;\n          if (st is DisplayExpression) {\n            var display = (DisplayExpression)st;\n            foreach (var el in display.Elements) {\n              yield return el;\n            }\n          } else if (st is MapDisplayExpr) {\n            var display = (MapDisplayExpr)st;\n            foreach (var maplet in display.Elements) {\n              yield return maplet.A;\n            }\n          }\n        } else if (bound is ComprehensionExpr.SeqBoundedPool) {\n          var sq = ((ComprehensionExpr.SeqBoundedPool)bound).Seq.Resolved;\n          var display = sq as DisplayExpression;\n          if (display != null) {\n            foreach (var el in display.Elements) {\n              yield return el;\n            }\n          }\n        } else if (bound is ComprehensionExpr.ExactBoundedPool) {\n          yield return ((ComprehensionExpr.ExactBoundedPool)bound).E;\n        }\n      }\n    }\n\n    /// <summary>\n    /// Return a zero-equivalent value for \"typ\", or return null (for any reason whatsoever).\n    /// </summary>\n    Expression Zero(IToken tok, Type typ) {\n      Contract.Requires(tok != null);\n      Contract.Requires(typ != null);\n      typ = typ.NormalizeExpand();\n      if (typ is BoolType) {\n        return Expression.CreateBoolLiteral(tok, false);\n      } else if (typ is CharType) {\n        var z = new CharLiteralExpr(tok, \"\\0\");\n        z.Type = Type.Char;  // resolve here\n        return z;\n      } else if (typ.IsNumericBased(Type.NumericPersuation.Int)) {\n        return Expression.CreateIntLiteral(tok, 0);\n      } else if (typ.IsNumericBased(Type.NumericPersuation.Real)) {\n        return Expression.CreateRealLiteral(tok, BaseTypes.BigDec.ZERO);\n      } else if (typ.IsBigOrdinalType) {\n        return Expression.CreateNatLiteral(tok, 0, Type.BigOrdinal);\n      } else if (typ.IsBitVectorType) {\n        var z = new LiteralExpr(tok, 0);\n        z.Type = typ;\n        return z;\n      } else if (typ.IsRefType) {\n        var z = new LiteralExpr(tok);  // null\n        z.Type = typ;\n        return z;\n      } else if (typ.IsDatatype) {\n        return null;  // this can be improved\n      } else if (typ is SetType) {\n        var empty = new SetDisplayExpr(tok, ((SetType)typ).Finite, new List<Expression>());\n        empty.Type = typ;\n        return empty;\n      } else if (typ is MultiSetType) {\n        var empty = new MultiSetDisplayExpr(tok, new List<Expression>());\n        empty.Type = typ;\n        return empty;\n      } else if (typ is SeqType) {\n        var empty = new SeqDisplayExpr(tok, new List<Expression>());\n        empty.Type = typ;\n        return empty;\n      } else if (typ is MapType) {\n        var empty = new MapDisplayExpr(tok, ((MapType)typ).Finite, new List<ExpressionPair>());\n        empty.Type = typ;\n        return empty;\n      } else if (typ is ArrowType) {\n        // TODO: do better than just returning null\n        return null;\n      } else if (typ.IsOpaqueType || typ.IsInternalTypeSynonym) {\n        return null;\n      } else {\n        Contract.Assume(false);  // unexpected type\n        return null;\n      }\n    }\n\n    void TrForallAssign(ForallStmt s, AssignStmt s0,\n      BoogieStmtListBuilder definedness, BoogieStmtListBuilder updater, List<Variable> locals, ExpressionTranslator etran) {\n      // The statement:\n      //   forall (x,y | Range(x,y)) {\n      //     (a)   E(x,y) . f :=  G(x,y);\n      //     (b)   A(x,y) [ I0(x,y), I1(x,y), ... ] :=  G(x,y);\n      //   }\n      // translate into:\n      //   if (*) {\n      //     // check definedness of Range\n      //     var x,y;\n      //     havoc x,y;\n      //     CheckWellformed( Range );\n      //     assume Range;\n      //     // check definedness of the other expressions\n      //     (a)\n      //       CheckWellformed( E.F );\n      //       check that E.f is in the modifies frame;\n      //       CheckWellformed( G );\n      //       check nat restrictions for the RHS\n      //     (b)\n      //       CheckWellformed( A[I0,I1,...] );\n      //       check that A[I0,I1,...] is in the modifies frame;\n      //       CheckWellformed( G );\n      //       check nat restrictions for the RHS\n      //     // check for duplicate LHSs\n      //     var x', y';\n      //     havoc x', y';\n      //     assume Range[x,y := x',y'];\n      //     assume !(x == x' && y == y');\n      //     (a)\n      //       assert E(x,y) != E(x',y') || G(x,y) == G(x',y');\n      //     (b)\n      //       assert !( A(x,y)==A(x',y') && I0(x,y)==I0(x',y') && I1(x,y)==I1(x',y') && ... ) || G(x,y) == G(x',y');\n      //\n      //     assume false;\n      //\n      //   } else {\n      //     var oldHeap := $Heap;\n      //     havoc $Heap;\n      //     assume $HeapSucc(oldHeap, $Heap);\n      //     (a)\n      //       assume (forall<alpha> o: ref, F: Field alpha ::\n      //         { $Heap[o,F] }\n      //         $Heap[o,F] = oldHeap[o,F] ||\n      //         (exists x,y :: Range(x,y) && o == E(x,y) && F = f));\n      //       assume (forall x,y ::  Range ==> $Heap[ E[$Heap:=oldHeap], F] == G[$Heap:=oldHeap]); (**)\n      //     (b)\n      //       assume (forall<alpha> o: ref, F: Field alpha ::\n      //         { $Heap[o,F] }\n      //         $Heap[o,F] = oldHeap[o,F] ||\n      //         (exists x,y :: Range(x,y) && o == A(x,y) && F = Index(I0,I1,...)));\n      //       assume (forall x,y ::  Range ==> $Heap[ A[$Heap:=oldHeap], Index(I0,I1,...)] == G[$Heap:=oldHeap]); (**)\n      //   }\n      //\n      // Note: In order to get a good trigger for the quantifiers (**), we will attempt to make the parameters\n      // that select from $Heap in the LHS of the equalities as plain as possible.  This involves taking the inverse\n      // of an expression, which isn't always easy or possible, so we settle for handling some common cases.  In\n      // particular, we change:\n      //   0: forall i | R(i) { F(i).f := E(i); }\n      //   1: forall i | R(i) { A[F(i)] := E(i); }\n      //   2: forall i | R(i) { F(i)[N] := E(i); }\n      // where f is some field and A and N are expressions that do not depend on i, into:\n      //   0: forall j | Q(j) { j.f := E(F-1(j)); }\n      //   1: forall j | Q(j) { A[j] := E(F-1(j)); }\n      //   2: forall j | Q(j) { j[N] := E(F-1(j)); }\n      // where we ensure that, for all i and j:\n      //   R(i) && j == F(i)    <==>    Q(j) && F-1(j) == i\n      // If the transformation succeeds, we use, respectively, j.f, A[j], and j[N] (each evaluated in the new heap) as\n      // the trigger of the quantifier generated.\n\n      var substMap = SetupBoundVarsAsLocals(s.BoundVars, definedness, locals, etran);\n      Expression range = Substitute(s.Range, null, substMap);\n      TrStmt_CheckWellformed(range, definedness, locals, etran, false);\n      definedness.Add(TrAssumeCmd(s.Range.tok, etran.TrExpr(range)));\n\n      var lhs = Substitute(s0.Lhs.Resolved, null, substMap);\n      TrStmt_CheckWellformed(lhs, definedness, locals, etran, false);\n      Bpl.Expr obj, F;\n      string description = GetObjFieldDetails(lhs, etran, out obj, out F);\n      definedness.Add(Assert(lhs.tok, Bpl.Expr.SelectTok(lhs.tok, etran.TheFrame(lhs.tok), obj, F),\n        \"assignment may update \" + description + \" not in the enclosing context's modifies clause\"));\n      if (s0.Rhs is ExprRhs) {\n        var r = (ExprRhs)s0.Rhs;\n        var rhs = Substitute(r.Expr, null, substMap);\n        TrStmt_CheckWellformed(rhs, definedness, locals, etran, false);\n        // check nat restrictions for the RHS\n        Type lhsType;\n        if (lhs is MemberSelectExpr) {\n          lhsType = ((MemberSelectExpr)lhs).Type;\n        } else if (lhs is SeqSelectExpr) {\n          lhsType = ((SeqSelectExpr)lhs).Type;\n        } else {\n          lhsType = ((MultiSelectExpr)lhs).Type;\n        }\n        var translatedRhs = etran.TrExpr(rhs);\n        CheckSubrange(r.Tok, translatedRhs, rhs.Type, lhsType, definedness);\n        if (lhs is MemberSelectExpr) {\n          var fse = (MemberSelectExpr)lhs;\n          var field = fse.Member as Field;\n          Contract.Assert(field != null);\n          Check_NewRestrictions(fse.tok, obj, field, translatedRhs, definedness, etran);\n        }\n      }\n\n      // check for duplicate LHSs\n      if (s0.Rhs is ExprRhs) {  // if Rhs denotes a havoc, then no duplicate check is performed\n        var substMapPrime = SetupBoundVarsAsLocals(s.BoundVars, definedness, locals, etran);\n        var lhsPrime = Substitute(s0.Lhs.Resolved, null, substMapPrime);\n        range = Substitute(s.Range, null, substMapPrime);\n        definedness.Add(TrAssumeCmd(range.tok, etran.TrExpr(range)));\n        // assume !(x == x' && y == y');\n        Bpl.Expr eqs = Bpl.Expr.True;\n        foreach (var bv in s.BoundVars) {\n          var x = substMap[bv];\n          var xPrime = substMapPrime[bv];\n          // TODO: in the following line, is the term equality okay, or does it have to include things like Set#Equal sometimes too?\n          eqs = BplAnd(eqs, Bpl.Expr.Eq(etran.TrExpr(x), etran.TrExpr(xPrime)));\n        }\n        definedness.Add(TrAssumeCmd(s.Tok, Bpl.Expr.Not(eqs)));\n        Bpl.Expr objPrime, FPrime;\n        GetObjFieldDetails(lhsPrime, etran, out objPrime, out FPrime);\n        var Rhs = ((ExprRhs)s0.Rhs).Expr;\n        var rhs = etran.TrExpr(Substitute(Rhs, null, substMap));\n        var rhsPrime = etran.TrExpr(Substitute(Rhs, null, substMapPrime));\n        definedness.Add(Assert(s0.Tok,\n          Bpl.Expr.Or(\n            Bpl.Expr.Or(Bpl.Expr.Neq(obj, objPrime), Bpl.Expr.Neq(F, FPrime)),\n            Bpl.Expr.Eq(rhs, rhsPrime)),\n          \"left-hand sides for different forall-statement bound variables may refer to the same location\"));\n      }\n\n      definedness.Add(TrAssumeCmd(s.Tok, Bpl.Expr.False));\n\n      // Now for the translation of the update itself\n\n      Bpl.IdentifierExpr prevHeap = GetPrevHeapVar_IdExpr(s.Tok, locals);\n      var prevEtran = new ExpressionTranslator(this, predef, prevHeap);\n      updater.Add(Bpl.Cmd.SimpleAssign(s.Tok, prevHeap, etran.HeapExpr));\n      updater.Add(new Bpl.HavocCmd(s.Tok, new List<Bpl.IdentifierExpr> { (Bpl.IdentifierExpr/*TODO: this cast is rather dubious*/)etran.HeapExpr }));\n      updater.Add(TrAssumeCmd(s.Tok, HeapSucc(prevHeap, etran.HeapExpr)));\n\n      // Here comes:\n      //   assume (forall<alpha> o: ref, f: Field alpha ::\n      //     { $Heap[o,f] }\n      //     $Heap[o,f] = oldHeap[o,f] ||\n      //     (exists x,y :: Range(x,y)[$Heap:=oldHeap] &&\n      //                    o == Object(x,y)[$Heap:=oldHeap] && f == Field(x,y)[$Heap:=oldHeap]));\n      Bpl.TypeVariable alpha = new Bpl.TypeVariable(s.Tok, \"alpha\");\n      Bpl.BoundVariable oVar = new Bpl.BoundVariable(s.Tok, new Bpl.TypedIdent(s.Tok, \"$o\", predef.RefType));\n      Bpl.IdentifierExpr o = new Bpl.IdentifierExpr(s.Tok, oVar);\n      Bpl.BoundVariable fVar = new Bpl.BoundVariable(s.Tok, new Bpl.TypedIdent(s.Tok, \"$f\", predef.FieldName(s.Tok, alpha)));\n      Bpl.IdentifierExpr f = new Bpl.IdentifierExpr(s.Tok, fVar);\n      Bpl.Expr heapOF = ExpressionTranslator.ReadHeap(s.Tok, etran.HeapExpr, o, f);\n      Bpl.Expr oldHeapOF = ExpressionTranslator.ReadHeap(s.Tok, prevHeap, o, f);\n      List<bool> freeOfAlloc = null;\n      if (FrugalHeapUseX) {\n        freeOfAlloc = ComprehensionExpr.BoundedPool.HasBounds(s.Bounds, ComprehensionExpr.BoundedPool.PoolVirtues.IndependentOfAlloc_or_ExplicitAlloc);\n      }\n      List<Variable> xBvars = new List<Variable>();\n      var xBody = etran.TrBoundVariables(s.BoundVars, xBvars, false, freeOfAlloc);\n      xBody = BplAnd(xBody, prevEtran.TrExpr(s.Range));\n      Bpl.Expr xObj, xField;\n      GetObjFieldDetails(s0.Lhs.Resolved, prevEtran, out xObj, out xField);\n      xBody = BplAnd(xBody, Bpl.Expr.Eq(o, xObj));\n      xBody = BplAnd(xBody, Bpl.Expr.Eq(f, xField));\n      //TRIG (exists k#2: int :: (k#2 == LitInt(0 - 3) || k#2 == LitInt(4)) && $o == read($prevHeap, this, _module.MyClass.arr) && $f == MultiIndexField(IndexField(i#0), j#0))\n      Bpl.Expr xObjField = new Bpl.ExistsExpr(s.Tok, xBvars, xBody);  // LL_TRIGGER\n      Bpl.Expr body = Bpl.Expr.Or(Bpl.Expr.Eq(heapOF, oldHeapOF), xObjField);\n      var tr = new Trigger(s.Tok, true, new List<Expr>() { heapOF });\n      Bpl.Expr qq = new Bpl.ForallExpr(s.Tok, new List<TypeVariable> { alpha }, new List<Variable> { oVar, fVar }, null, tr, body);\n      updater.Add(TrAssumeCmd(s.Tok, qq));\n\n      if (s.ForallExpressions != null) {\n        foreach (ForallExpr expr in s.ForallExpressions) {\n          BinaryExpr term = (BinaryExpr)expr.Term;\n          Contract.Assert(term != null);\n          var e0 = ((BinaryExpr)term).E0.Resolved;\n          var e1 = ((BinaryExpr)term).E1;\n          qq = TrForall_NewValueAssumption(expr.tok, expr.BoundVars, expr.Bounds, expr.Range, e0, e1, expr.Attributes, etran, prevEtran);\n          updater.Add(TrAssumeCmd(s.Tok, qq));\n        }\n      }\n    }\n\n    /// <summary>\n    /// Generate:\n    ///   assume (forall x,y :: Range(x,y)[$Heap:=oldHeap] ==>\n    ///                         $Heap[ Object(x,y)[$Heap:=oldHeap], Field(x,y)[$Heap:=oldHeap] ] == G[$Heap:=oldHeap] ));\n    /// where\n    ///   x,y           represent boundVars\n    ///   Object(x,y)   is the first part of lhs\n    ///   Field(x,y)    is the second part of lhs\n    ///   G             is rhs\n    /// If lhsAsTrigger is true, then use the LHS of the equality above as the trigger; otherwise, don't specify any trigger.\n    /// </summary>\n    private Bpl.Expr TrForall_NewValueAssumption(IToken tok, List<BoundVar> boundVars, List<ComprehensionExpr.BoundedPool> bounds, Expression range, Expression lhs, Expression rhs, Attributes attributes, ExpressionTranslator etran, ExpressionTranslator prevEtran) {\n      Contract.Requires(tok != null);\n      Contract.Requires(boundVars != null);\n      Contract.Requires(!FrugalHeapUseX || bounds != null);\n      Contract.Requires(range != null);\n      Contract.Requires(lhs != null);\n      Contract.Requires(rhs != null);\n      Contract.Requires(etran != null);\n      Contract.Requires(prevEtran != null);\n\n      List<bool> freeOfAlloc = null;\n      if (FrugalHeapUseX) {\n        freeOfAlloc = ComprehensionExpr.BoundedPool.HasBounds(bounds, ComprehensionExpr.BoundedPool.PoolVirtues.IndependentOfAlloc_or_ExplicitAlloc);\n      }\n      var xBvars = new List<Variable>();\n      Bpl.Expr xAnte = etran.TrBoundVariables(boundVars, xBvars, false, freeOfAlloc);\n      xAnte = BplAnd(xAnte, prevEtran.TrExpr(range));\n      var g = prevEtran.TrExpr(rhs);\n      Bpl.Expr obj, field;\n      GetObjFieldDetails(lhs, prevEtran, out obj, out field);\n      var xHeapOF = ExpressionTranslator.ReadHeap(tok, etran.HeapExpr, obj, field);\n\n      Type lhsType = lhs is MemberSelectExpr ? ((MemberSelectExpr)lhs).Type : null;\n      g = CondApplyBox(rhs.tok, g, rhs.Type, lhsType);\n\n      Bpl.Trigger tr = null;\n      var argsEtran = etran.WithNoLits();\n      foreach (var aa in attributes.AsEnumerable()) {\n        if (aa.Name == \"trigger\") {\n          List<Bpl.Expr> tt = new List<Bpl.Expr>();\n          foreach (var arg in aa.Args) {\n            if (arg == lhs) {\n              tt.Add(xHeapOF);\n            } else {\n              tt.Add(argsEtran.TrExpr(arg));\n            }\n          }\n          tr = new Bpl.Trigger(tok, true, tt, tr);\n        }\n      }\n      return new Bpl.ForallExpr(tok, xBvars, tr, Bpl.Expr.Imp(xAnte, Bpl.Expr.Eq(xHeapOF, g)));\n    }\n\n    delegate Bpl.Expr ExpressionConverter(Dictionary<IVariable, Expression> substMap, ExpressionTranslator etran);\n\n    void TrForallStmtCall(IToken tok, List<BoundVar> boundVars, List<ComprehensionExpr.BoundedPool> bounds, Expression range, ExpressionConverter additionalRange, List<Expression> forallExpressions, CallStmt s0,\n      BoogieStmtListBuilder definedness, BoogieStmtListBuilder exporter, List<Variable> locals, ExpressionTranslator etran) {\n      Contract.Requires(tok != null);\n      Contract.Requires(boundVars != null);\n      Contract.Requires(bounds != null);\n      Contract.Requires(range != null);\n      // additionalRange is allowed to be null\n      Contract.Requires(s0 != null);\n      // definedness is allowed to be null\n      Contract.Requires(exporter != null);\n      Contract.Requires(locals != null);\n      Contract.Requires(etran != null);\n\n      // Translate:\n      //   forall (x,y | Range(x,y)) {\n      //     E(x,y) . M( Args(x,y) );\n      //   }\n      // as:\n      //   if (*) {\n      //     var x,y;\n      //     havoc x,y;\n      //     CheckWellformed( Range );\n      //     assume Range(x,y);\n      //     assume additionalRange;\n      //     Tr( Call );\n      //     assume false;\n      //   } else {\n      //     initHeap := $Heap;\n      //     advance $Heap, Tick;\n      //     assume (forall x,y :: (Range(x,y) && additionalRange)[INIT] &&\n      //                           ==> Post[old($Heap) := initHeap]( E(x,y)[INIT], Args(x,y)[INIT] ));\n      //   }\n      // where Post(this,args) is the postcondition of method M and\n      // INIT is the substitution [old($Heap),$Heap := old($Heap),initHeap].\n\n      if (definedness != null) {\n        if (boundVars.Count != 0) {\n          // Note, it would be nicer (and arguably more appropriate) to do a SetupBoundVarsAsLocals\n          // here (rather than a TrBoundVariables).  However, there is currently no way to apply\n          // a substMap to a statement (in particular, to s.Body), so that doesn't work here.\n          List<bool> freeOfAlloc = null;\n          if (FrugalHeapUseX) {\n            freeOfAlloc = ComprehensionExpr.BoundedPool.HasBounds(bounds, ComprehensionExpr.BoundedPool.PoolVirtues.IndependentOfAlloc_or_ExplicitAlloc);\n          }\n          List<Variable> bvars = new List<Variable>();\n          var ante = etran.TrBoundVariables(boundVars, bvars, true, freeOfAlloc);\n          locals.AddRange(bvars);\n          var havocIds = new List<Bpl.IdentifierExpr>();\n          foreach (Bpl.Variable bv in bvars) {\n            havocIds.Add(new Bpl.IdentifierExpr(tok, bv));\n          }\n          definedness.Add(new Bpl.HavocCmd(tok, havocIds));\n          definedness.Add(TrAssumeCmd(tok, ante));\n        }\n        TrStmt_CheckWellformed(range, definedness, locals, etran, false);\n        definedness.Add(TrAssumeCmd(range.tok, etran.TrExpr(range)));\n        if (additionalRange != null) {\n          var es = additionalRange(new Dictionary<IVariable, Expression>(), etran);\n          definedness.Add(TrAssumeCmd(es.tok, es));\n        }\n\n        TrStmt(s0, definedness, locals, etran);\n\n        definedness.Add(TrAssumeCmd(tok, Bpl.Expr.False));\n      }\n\n      // Now for the other branch, where the postcondition of the call is exported.\n      {\n        var initHeapVar = new Bpl.LocalVariable(tok, new Bpl.TypedIdent(tok, CurrentIdGenerator.FreshId(\"$initHeapForallStmt#\"), predef.HeapType));\n        locals.Add(initHeapVar);\n        var initHeap = new Bpl.IdentifierExpr(tok, initHeapVar);\n        var initEtran = new ExpressionTranslator(this, predef, initHeap, etran.Old.HeapExpr);\n        // initHeap := $Heap;\n        exporter.Add(Bpl.Cmd.SimpleAssign(tok, initHeap, etran.HeapExpr));\n        var heapIdExpr = (Bpl.IdentifierExpr/*TODO: this cast is rather dubious*/)etran.HeapExpr;\n        // advance $Heap, Tick;\n        exporter.Add(new Bpl.HavocCmd(tok, new List<Bpl.IdentifierExpr> { heapIdExpr, etran.Tick() }));\n        Contract.Assert(s0.Method.Mod.Expressions.Count == 0);  // checked by the resolver\n        foreach (BoilerplateTriple tri in GetTwoStateBoilerplate(tok, new List<FrameExpression>(), s0.IsGhost, initEtran, etran, initEtran)) {\n          if (tri.IsFree) {\n            exporter.Add(TrAssumeCmd(tok, tri.Expr));\n          }\n        }\n        if (codeContext is IteratorDecl) {\n          var iter = (IteratorDecl)codeContext;\n          RecordNewObjectsIn_New(tok, iter, initHeap, heapIdExpr, exporter, locals, etran);\n        }\n\n        // Note, in the following, we need to do a bit of a song and dance.  The actual arguments of the\n        // call should be translated using \"initEtran\", whereas the method postcondition should be translated\n        // using \"callEtran\".  To accomplish this, we translate the argument and then tuck the resulting\n        // Boogie expressions into BoogieExprWrappers that are used in the DafnyExpr-to-DafnyExpr substitution.\n        // TODO\n        Bpl.Expr qq;\n        var bvars = new List<Variable>();\n        Dictionary<IVariable, Expression> substMap;\n        Bpl.Trigger antitriggerBoundVarTypes;\n        Bpl.Expr ante;\n        var argsSubstMap = new Dictionary<IVariable, Expression>();  // maps formal arguments to actuals\n        Contract.Assert(s0.Method.Ins.Count == s0.Args.Count);\n        var callEtran = new ExpressionTranslator(this, predef, etran.HeapExpr, initHeap);\n        Bpl.Expr post = Bpl.Expr.True;\n        Bpl.Trigger tr;\n        if (forallExpressions != null) {\n          // tranlate based on the forallExpressions since the triggers are computed based on it already.\n          QuantifierExpr expr = (QuantifierExpr)forallExpressions[0];\n          while (expr.SplitQuantifier != null) {\n            expr = (QuantifierExpr)expr.SplitQuantifierExpression;\n          }\n          boundVars = expr.BoundVars;\n          ante = initEtran.TrBoundVariablesRename(boundVars, bvars, out substMap, out antitriggerBoundVarTypes);\n          ante = BplAnd(ante, initEtran.TrExpr(Substitute(expr.Range, null, substMap)));\n          if (additionalRange != null) {\n            ante = BplAnd(ante, additionalRange(substMap, initEtran));\n          }\n          tr = TrTrigger(callEtran, expr.Attributes, expr.tok, bvars, substMap, s0.MethodSelect.TypeArgumentSubstitutions());\n          post = callEtran.TrExpr(Substitute(expr.Term, null, substMap));\n        } else {\n          ante = initEtran.TrBoundVariablesRename(boundVars, bvars, out substMap, out antitriggerBoundVarTypes);\n          for (int i = 0; i < s0.Method.Ins.Count; i++) {\n            var arg = Substitute(s0.Args[i], null, substMap, s0.MethodSelect.TypeArgumentSubstitutions());  // substitute the renamed bound variables for the declared ones\n            argsSubstMap.Add(s0.Method.Ins[i], new BoogieWrapper(initEtran.TrExpr(arg), s0.Args[i].Type));\n          }\n          ante = BplAnd(ante, initEtran.TrExpr(Substitute(range, null, substMap)));\n          if (additionalRange != null) {\n            ante = BplAnd(ante, additionalRange(substMap, initEtran));\n          }\n          var receiver = new BoogieWrapper(initEtran.TrExpr(Substitute(s0.Receiver, null, substMap, s0.MethodSelect.TypeArgumentSubstitutions())), s0.Receiver.Type);\n          foreach (var ens in s0.Method.Ens) {\n            var p = Substitute(ens.E, receiver, argsSubstMap, s0.MethodSelect.TypeArgumentSubstitutions());  // substitute the call's actuals for the method's formals\n            post = BplAnd(post, callEtran.TrExpr(p));\n          }\n          tr = antitriggerBoundVarTypes;\n        }\n\n        // TRIG (forall $ih#s0#0: Seq Box :: $Is($ih#s0#0, TSeq(TChar)) && $IsAlloc($ih#s0#0, TSeq(TChar), $initHeapForallStmt#0) && Seq#Length($ih#s0#0) != 0 && Seq#Rank($ih#s0#0) < Seq#Rank(s#0) ==> (forall i#2: int :: true ==> LitInt(0) <= i#2 && i#2 < Seq#Length($ih#s0#0) ==> char#ToInt(_module.CharChar.MinChar($LS($LZ), $Heap, this, $ih#s0#0)) <= char#ToInt($Unbox(Seq#Index($ih#s0#0, i#2)): char)))\n        // TRIG (forall $ih#pat0#0: Seq Box, $ih#a0#0: Seq Box :: $Is($ih#pat0#0, TSeq(_module._default.Same0$T)) && $IsAlloc($ih#pat0#0, TSeq(_module._default.Same0$T), $initHeapForallStmt#0) && $Is($ih#a0#0, TSeq(_module._default.Same0$T)) && $IsAlloc($ih#a0#0, TSeq(_module._default.Same0$T), $initHeapForallStmt#0) && Seq#Length($ih#pat0#0) <= Seq#Length($ih#a0#0) && Seq#SameUntil($ih#pat0#0, $ih#a0#0, Seq#Length($ih#pat0#0)) && (Seq#Rank($ih#pat0#0) < Seq#Rank(pat#0) || (Seq#Rank($ih#pat0#0) == Seq#Rank(pat#0) && Seq#Rank($ih#a0#0) < Seq#Rank(a#0))) ==> _module.__default.IsRelaxedPrefixAux(_module._default.Same0$T, $LS($LZ), $Heap, $ih#pat0#0, $ih#a0#0, LitInt(1)))'\n        // TRIG (forall $ih#m0#0: DatatypeType, $ih#n0#0: DatatypeType :: $Is($ih#m0#0, Tclass._module.Nat()) && $IsAlloc($ih#m0#0, Tclass._module.Nat(), $initHeapForallStmt#0) && $Is($ih#n0#0, Tclass._module.Nat()) && $IsAlloc($ih#n0#0, Tclass._module.Nat(), $initHeapForallStmt#0) && Lit(true) && (DtRank($ih#m0#0) < DtRank(m#0) || (DtRank($ih#m0#0) == DtRank(m#0) && DtRank($ih#n0#0) < DtRank(n#0))) ==> _module.__default.mult($LS($LZ), $Heap, $ih#m0#0, _module.__default.plus($LS($LZ), $Heap, $ih#n0#0, $ih#n0#0)) == _module.__default.mult($LS($LZ), $Heap, _module.__default.plus($LS($LZ), $Heap, $ih#m0#0, $ih#m0#0), $ih#n0#0))\n        qq = new Bpl.ForallExpr(tok, bvars, tr, Bpl.Expr.Imp(ante, post));  // TODO: Add a SMART_TRIGGER here.  If we can't find one, abort the attempt to do induction automatically\n        exporter.Add(TrAssumeCmd(tok, qq));\n      }\n    }\n\n    void RecordNewObjectsIn_New(IToken tok, IteratorDecl iter, Bpl.Expr initHeap, Bpl.IdentifierExpr currentHeap,\n      BoogieStmtListBuilder builder, List<Variable> locals, ExpressionTranslator etran) {\n      Contract.Requires(tok != null);\n      Contract.Requires(iter != null);\n      Contract.Requires(initHeap != null);\n      Contract.Requires(currentHeap != null);\n      Contract.Requires(builder != null);\n      Contract.Requires(locals != null);\n      Contract.Requires(etran != null);\n      // Add all newly allocated objects to the set this._new\n      var updatedSet = new Bpl.LocalVariable(iter.tok, new Bpl.TypedIdent(iter.tok, CurrentIdGenerator.FreshId(\"$iter_newUpdate\"), predef.SetType(iter.tok, true, predef.BoxType)));\n      locals.Add(updatedSet);\n      var updatedSetIE = new Bpl.IdentifierExpr(iter.tok, updatedSet);\n      // call $iter_newUpdate := $IterCollectNewObjects(initHeap, $Heap, this, _new);\n      var th = new Bpl.IdentifierExpr(iter.tok, etran.This, predef.RefType);\n      var nwField = new Bpl.IdentifierExpr(tok, GetField(iter.Member_New));\n      Bpl.Cmd cmd = new CallCmd(iter.tok, \"$IterCollectNewObjects\",\n        new List<Bpl.Expr>() { initHeap, etran.HeapExpr, th, nwField },\n        new List<Bpl.IdentifierExpr>() { updatedSetIE });\n      builder.Add(cmd);\n      // $Heap[this, _new] := $iter_newUpdate;\n      cmd = Bpl.Cmd.SimpleAssign(iter.tok, currentHeap, ExpressionTranslator.UpdateHeap(iter.tok, currentHeap, th, nwField, updatedSetIE));\n      builder.Add(cmd);\n      // assume $IsGoodHeap($Heap)\n      builder.Add(AssumeGoodHeap(tok, etran));\n    }\n\n    void TrForallProof(ForallStmt s, BoogieStmtListBuilder definedness, BoogieStmtListBuilder exporter, List<Variable> locals, ExpressionTranslator etran) {\n      // Translate:\n      //   forall (x,y | Range(x,y))\n      //     ensures Post(x,y);\n      //   {\n      //     Body;\n      //   }\n      // as:\n      //   if (*) {\n      //     var x,y;\n      //     havoc x,y;\n      //     CheckWellformed( Range );\n      //     assume Range(x,y);\n      //     Tr( Body );\n      //     CheckWellformed( Post );\n      //     assert Post;\n      //     assume false;\n      //   } else {\n      //     assume (forall x,y :: Range(x,y) ==> Post(x,y));\n      //   }\n\n      if (s.BoundVars.Count != 0) {\n        // Note, it would be nicer (and arguably more appropriate) to do a SetupBoundVarsAsLocals\n        // here (rather than a TrBoundVariables).  However, there is currently no way to apply\n        // a substMap to a statement (in particular, to s.Body), so that doesn't work here.\n        List<bool> freeOfAlloc = null;\n        if (FrugalHeapUseX) {\n          freeOfAlloc = ComprehensionExpr.BoundedPool.HasBounds(s.Bounds, ComprehensionExpr.BoundedPool.PoolVirtues.IndependentOfAlloc_or_ExplicitAlloc);\n        }\n        var bVars = new List<Variable>();\n        var typeAntecedent = etran.TrBoundVariables(s.BoundVars, bVars, true, freeOfAlloc);\n        locals.AddRange(bVars);\n        var havocIds = new List<Bpl.IdentifierExpr>();\n        foreach (Bpl.Variable bv in bVars) {\n          havocIds.Add(new Bpl.IdentifierExpr(s.Tok, bv));\n        }\n        definedness.Add(new Bpl.HavocCmd(s.Tok, havocIds));\n        definedness.Add(TrAssumeCmd(s.Tok, typeAntecedent));\n      }\n      TrStmt_CheckWellformed(s.Range, definedness, locals, etran, false);\n      definedness.Add(TrAssumeCmd(s.Range.tok, etran.TrExpr(s.Range)));\n\n      if (s.Body != null) {\n        TrStmt(s.Body, definedness, locals, etran);\n\n        // check that postconditions hold\n        foreach (var ens in s.Ens) {\n          if (!ens.IsFree) {\n            bool splitHappened;  // we actually don't care\n            foreach (var split in TrSplitExpr(ens.E, etran, true, out splitHappened)) {\n              if (split.IsChecked) {\n                definedness.Add(Assert(split.E.tok, split.E, \"possible violation of postcondition of forall statement\"));\n              }\n            }\n          }\n        }\n      }\n\n      definedness.Add(TrAssumeCmd(s.Tok, Bpl.Expr.False));\n\n      // Now for the other branch, where the ensures clauses are exported.\n      // If the forall body has side effect such as call to a reveal function,\n      // it needs to be exported too.\n      var se = s.Body == null ? Bpl.Expr.True : TrFunctionSideEffect(s.Body, etran);\n      var substMap = new Dictionary<IVariable, Expression>();\n      var p = Substitute(s.ForallExpressions[0], null, substMap);\n      var qq = etran.TrExpr(p);\n      if (s.BoundVars.Count != 0) {\n        exporter.Add(TrAssumeCmd(s.Tok, BplAnd(se, qq)));\n      } else {\n        exporter.Add(TrAssumeCmd(s.Tok, BplAnd(se, ((Bpl.ForallExpr)qq).Body)));\n      }\n    }\n\n    private string GetObjFieldDetails(Expression lhs, ExpressionTranslator etran, out Bpl.Expr obj, out Bpl.Expr F) {\n      string description;\n      if (lhs is MemberSelectExpr) {\n        var fse = (MemberSelectExpr)lhs;\n        obj = etran.TrExpr(fse.Obj);\n        F = GetField(fse);\n        description = \"an object field\";\n      } else if (lhs is SeqSelectExpr) {\n        var sel = (SeqSelectExpr)lhs;\n        obj = etran.TrExpr(sel.Seq);\n        F = FunctionCall(sel.tok, BuiltinFunction.IndexField, null, etran.TrExpr(sel.E0));\n        description = \"an array element\";\n      } else {\n        MultiSelectExpr mse = (MultiSelectExpr)lhs;\n        obj = etran.TrExpr(mse.Array);\n        F = etran.GetArrayIndexFieldName(mse.tok, mse.Indices);\n        description = \"an array element\";\n      }\n      return description;\n    }\n\n    Bpl.AssumeCmd TrAssumeCmd(IToken tok, Bpl.Expr expr, Bpl.QKeyValue attributes = null) {\n      var lit = RemoveLit(expr);\n      return attributes == null ? new Bpl.AssumeCmd(tok, lit) : new Bpl.AssumeCmd(tok, lit, attributes);\n    }\n\n    Bpl.AssertCmd TrAssertCmd(IToken tok, Bpl.Expr expr, Bpl.QKeyValue attributes = null) {\n      var lit = RemoveLit(expr);\n      return attributes == null ? new Bpl.AssertCmd(tok, lit) : new Bpl.AssertCmd(tok, lit, attributes);\n    }\n\n    delegate void BodyTranslator(BoogieStmtListBuilder builder, ExpressionTranslator etran);\n\n\n    void TrLoop(LoopStmt s, Expression Guard, BodyTranslator bodyTr,\n                BoogieStmtListBuilder builder, List<Variable> locals, ExpressionTranslator etran) {\n      Contract.Requires(s != null);\n      Contract.Requires(builder != null);\n      Contract.Requires(locals != null);\n      Contract.Requires(etran != null);\n\n      var suffix = CurrentIdGenerator.FreshId(\"loop#\");\n\n      var theDecreases = s.Decreases.Expressions;\n\n      Bpl.LocalVariable preLoopHeapVar = new Bpl.LocalVariable(s.Tok, new Bpl.TypedIdent(s.Tok, \"$PreLoopHeap$\" + suffix, predef.HeapType));\n      locals.Add(preLoopHeapVar);\n      Bpl.IdentifierExpr preLoopHeap = new Bpl.IdentifierExpr(s.Tok, preLoopHeapVar);\n      ExpressionTranslator etranPreLoop = new ExpressionTranslator(this, predef, preLoopHeap);\n      ExpressionTranslator updatedFrameEtran;\n      string loopFrameName = \"$Frame$\" + suffix;\n      if (s.Mod.Expressions != null) {\n        updatedFrameEtran = new ExpressionTranslator(etran, loopFrameName);\n      } else {\n        updatedFrameEtran = etran;\n      }\n\n      if (s.Mod.Expressions != null) { // check that the modifies is a subset\n        CheckFrameSubset(s.Tok, s.Mod.Expressions, null, null, etran, builder, \"loop modifies clause may violate context's modifies clause\", null);\n        DefineFrame(s.Tok, s.Mod.Expressions, builder, locals, loopFrameName);\n      }\n      builder.Add(Bpl.Cmd.SimpleAssign(s.Tok, preLoopHeap, etran.HeapExpr));\n\n      var daTrackersMonotonicity = new List<Tuple<Bpl.IdentifierExpr, Bpl.IdentifierExpr>>();\n      foreach (var dat in definiteAssignmentTrackers.Values) {  // TODO: the order is non-deterministic and may change been invocations of Dafny\n        var preLoopDat = new Bpl.LocalVariable(dat.tok, new Bpl.TypedIdent(dat.tok, \"preLoop$\" + suffix + \"$\" + dat.Name, dat.Type));\n        locals.Add(preLoopDat);\n        var ie = new Bpl.IdentifierExpr(s.Tok, preLoopDat);\n        daTrackersMonotonicity.Add(new Tuple<Bpl.IdentifierExpr, Bpl.IdentifierExpr>(ie, dat));\n        builder.Add(Bpl.Cmd.SimpleAssign(s.Tok, ie, dat));\n      }\n\n      List<Bpl.Expr> initDecr = null;\n      if (!Contract.Exists(theDecreases, e => e is WildcardExpr)) {\n        initDecr = RecordDecreasesValue(theDecreases, builder, locals, etran, \"$decr_init$\" + suffix);\n      }\n\n      // the variable w is used to coordinate the definedness checking of the loop invariant\n      Bpl.LocalVariable wVar = new Bpl.LocalVariable(s.Tok, new Bpl.TypedIdent(s.Tok, \"$w$\" + suffix, Bpl.Type.Bool));\n      Bpl.IdentifierExpr w = new Bpl.IdentifierExpr(s.Tok, wVar);\n      locals.Add(wVar);\n      // havoc w;\n      builder.Add(new Bpl.HavocCmd(s.Tok, new List<Bpl.IdentifierExpr> { w }));\n\n      List<Bpl.PredicateCmd> invariants = new List<Bpl.PredicateCmd>();\n      BoogieStmtListBuilder invDefinednessBuilder = new BoogieStmtListBuilder(this);\n      foreach (MaybeFreeExpression loopInv in s.Invariants) {\n        string errorMessage = CustomErrorMessage(loopInv.Attributes);\n        TrStmt_CheckWellformed(loopInv.E, invDefinednessBuilder, locals, etran, false);\n        invDefinednessBuilder.Add(TrAssumeCmd(loopInv.E.tok, etran.TrExpr(loopInv.E)));\n\n        invariants.Add(TrAssumeCmd(loopInv.E.tok, Bpl.Expr.Imp(w, CanCallAssumption(loopInv.E, etran))));\n        if (loopInv.IsFree && !ArmadaOptions.O.DisallowSoundnessCheating) {\n          invariants.Add(TrAssumeCmd(loopInv.E.tok, Bpl.Expr.Imp(w, etran.TrExpr(loopInv.E))));\n        } else {\n          bool splitHappened;\n          var ss = TrSplitExpr(loopInv.E, etran, false, out splitHappened);\n          if (!splitHappened) {\n            var wInv = Bpl.Expr.Imp(w, etran.TrExpr(loopInv.E));\n            invariants.Add(Assert(loopInv.E.tok, wInv, errorMessage??\"loop invariant violation\"));\n          } else {\n            foreach (var split in ss) {\n              var wInv = Bpl.Expr.Binary(split.E.tok, BinaryOperator.Opcode.Imp, w, split.E);\n              if (split.IsChecked) {\n                invariants.Add(Assert(split.E.tok, wInv, errorMessage??\"loop invariant violation\"));  // TODO: it would be fine to have this use {:subsumption 0}\n              } else {\n                invariants.Add(TrAssumeCmd(split.E.tok, wInv));\n              }\n            }\n          }\n        }\n      }\n      // check definedness of decreases clause\n      // TODO: can this check be omitted if the decreases clause is inferred?\n      foreach (Expression e in theDecreases) {\n        TrStmt_CheckWellformed(e, invDefinednessBuilder, locals, etran, true);\n      }\n      if (codeContext is IMethodCodeContext) {\n        var modifiesClause = ((IMethodCodeContext)codeContext).Modifies.Expressions;\n        // include boilerplate invariants\n        foreach (BoilerplateTriple tri in GetTwoStateBoilerplate(s.Tok, modifiesClause, s.IsGhost, etranPreLoop, etran, etran.Old)) {\n          if (tri.IsFree) {\n            invariants.Add(TrAssumeCmd(s.Tok, tri.Expr));\n          } else {\n            Contract.Assert(tri.ErrorMessage != null);  // follows from BoilerplateTriple invariant\n            invariants.Add(Assert(s.Tok, tri.Expr, tri.ErrorMessage));\n          }\n        }\n        // add a free invariant which says that the heap hasn't changed outside of the modifies clause.\n        invariants.Add(TrAssumeCmd(s.Tok, FrameConditionUsingDefinedFrame(s.Tok, etranPreLoop, etran, updatedFrameEtran)));\n      }\n\n      // include a free invariant that says that all definite-assignment trackers have only become more \"true\"\n      foreach (var pair in daTrackersMonotonicity) {\n        Bpl.Expr monotonic = Bpl.Expr.Imp(pair.Item1, pair.Item2);\n        invariants.Add(TrAssumeCmd(s.Tok, monotonic));\n      }\n\n      // include a free invariant that says that all completed iterations so far have only decreased the termination metric\n      if (initDecr != null) {\n        var toks = new List<IToken>();\n        var types = new List<Type>();\n        var decrs = new List<Expr>();\n        foreach (Expression e in theDecreases) {\n          toks.Add(e.tok);\n          types.Add(e.Type.NormalizeExpand());\n          decrs.Add(etran.TrExpr(e));\n        }\n        Bpl.Expr decrCheck = DecreasesCheck(toks, types, types, decrs, initDecr, null, null, true, false);\n        invariants.Add(TrAssumeCmd(s.Tok, decrCheck));\n      }\n\n      BoogieStmtListBuilder loopBodyBuilder = new BoogieStmtListBuilder(this);\n      loopBodyBuilder.Add(CaptureState(s.Tok, true, \"after some loop iterations\"));\n      // as the first thing inside the loop, generate:  if (!w) { CheckWellformed(inv); assume false; }\n      invDefinednessBuilder.Add(TrAssumeCmd(s.Tok, Bpl.Expr.False));\n      loopBodyBuilder.Add(new Bpl.IfCmd(s.Tok, Bpl.Expr.Not(w), invDefinednessBuilder.Collect(s.Tok), null, null));\n      // generate:  CheckWellformed(guard); if (!guard) { break; }\n      Bpl.Expr guard = null;\n      if (Guard != null) {\n        TrStmt_CheckWellformed(Guard, loopBodyBuilder, locals, etran, true);\n        guard = Bpl.Expr.Not(etran.TrExpr(Guard));\n      }\n      BoogieStmtListBuilder guardBreak = new BoogieStmtListBuilder(this);\n      guardBreak.Add(new Bpl.BreakCmd(s.Tok, null));\n      loopBodyBuilder.Add(new Bpl.IfCmd(s.Tok, guard, guardBreak.Collect(s.Tok), null, null));\n\n      if (bodyTr != null) {\n        // termination checking\n        if (Contract.Exists(theDecreases, e => e is WildcardExpr)) {\n          // omit termination checking for this loop\n          bodyTr(loopBodyBuilder, updatedFrameEtran);\n        } else {\n          List<Bpl.Expr> oldBfs = RecordDecreasesValue(theDecreases, loopBodyBuilder, locals, etran, \"$decr$\" + suffix);\n          // time for the actual loop body\n          bodyTr(loopBodyBuilder, updatedFrameEtran);\n          // check definedness of decreases expressions\n          var toks = new List<IToken>();\n          var types = new List<Type>();\n          var decrs = new List<Expr>();\n          foreach (Expression e in theDecreases) {\n            toks.Add(e.tok);\n            types.Add(e.Type.NormalizeExpand());\n            decrs.Add(etran.TrExpr(e));\n          }\n        AddComment(loopBodyBuilder, s, \"loop termination check\");\n          Bpl.Expr decrCheck = DecreasesCheck(toks, types, types, decrs, oldBfs, loopBodyBuilder, \" at end of loop iteration\", false, false);\n          string msg;\n          if (s.InferredDecreases) {\n            msg = \"cannot prove termination; try supplying a decreases clause for the loop\";\n          } else {\n            msg = \"decreases expression might not decrease\";\n          }\n          loopBodyBuilder.Add(Assert(s.Tok, decrCheck, msg));\n        }\n      } else {\n        loopBodyBuilder.Add(TrAssumeCmd(s.Tok, Bpl.Expr.False));\n        // todo(maria): havoc stuff\n      }\n      // Finally, assume the well-formedness of the invariant (which has been checked once and for all above), so that the check\n      // of invariant-maintenance can use the appropriate canCall predicates.\n      foreach (MaybeFreeExpression loopInv in s.Invariants) {\n        loopBodyBuilder.Add(TrAssumeCmd(loopInv.E.tok, CanCallAssumption(loopInv.E, etran)));\n      }\n      Bpl.StmtList body = loopBodyBuilder.Collect(s.Tok);\n\n      builder.Add(new Bpl.WhileCmd(s.Tok, Bpl.Expr.True, invariants, body));\n    }\n\n    void TrAlternatives(List<GuardedAlternative> alternatives, Bpl.Cmd elseCase0, Bpl.StructuredCmd elseCase1,\n                        BoogieStmtListBuilder builder, List<Variable> locals, ExpressionTranslator etran, bool isGhost) {\n      Contract.Requires(alternatives != null);\n      Contract.Requires((elseCase0 == null) != (elseCase1 == null));  // ugly way of doing a type union\n      Contract.Requires(builder != null);\n      Contract.Requires(locals != null);\n      Contract.Requires(etran != null);\n\n      if (alternatives.Count == 0) {\n        if (elseCase0 != null) {\n          builder.Add(elseCase0);\n        } else {\n          builder.Add(elseCase1);\n        }\n        return;\n      }\n\n      // alpha-rename any binding guards\n      var guards = alternatives.ConvertAll(alt => alt.IsBindingGuard ? AlphaRename((ExistsExpr)alt.Guard, \"eg$\") : alt.Guard);\n\n      // build the negation of the disjunction of all guards (that is, the conjunction of their negations)\n      Bpl.Expr noGuard = Bpl.Expr.True;\n      var b = new BoogieStmtListBuilder(this);\n      foreach (var g in guards) {\n        b.Add(TrAssumeCmd(g.tok, CanCallAssumption(g, etran)));\n        noGuard = BplAnd(noGuard, Bpl.Expr.Not(etran.TrExpr(g)));\n      }\n\n      var elseTok = elseCase0 != null ? elseCase0.tok : elseCase1.tok;\n      b.Add(TrAssumeCmd(elseTok, noGuard));\n      if (elseCase0 != null) {\n        b.Add(elseCase0);\n      } else {\n        b.Add(elseCase1);\n      }\n      Bpl.StmtList els = b.Collect(elseTok);\n\n      Bpl.IfCmd elsIf = null;\n      for (int i = alternatives.Count; 0 <= --i; ) {\n        Contract.Assert(elsIf == null || els == null);  // loop invariant\n        CurrentIdGenerator.Push();\n        var alternative = alternatives[i];\n        b = new BoogieStmtListBuilder(this);\n        TrStmt_CheckWellformed(guards[i], b, locals, etran, true);\n        if (alternative.IsBindingGuard) {\n          var exists = (ExistsExpr)alternative.Guard;  // the original (that is, not alpha-renamed) guard\n          IntroduceAndAssignExistentialVars(exists, b, builder, locals, etran, isGhost);\n        } else {\n          b.Add(new AssumeCmd(alternative.Guard.tok, etran.TrExpr(alternative.Guard)));\n        }\n        var prevDefiniteAssignmentTrackerCount = definiteAssignmentTrackers.Count;\n        foreach (var s in alternative.Body) {\n          TrStmt(s, b, locals, etran);\n        }\n        RemoveDefiniteAssignmentTrackers(alternative.Body, prevDefiniteAssignmentTrackerCount);\n        Bpl.StmtList thn = b.Collect(alternative.Tok);\n        elsIf = new Bpl.IfCmd(alternative.Tok, null, thn, elsIf, els);\n        els = null;\n        CurrentIdGenerator.Pop();\n      }\n      Contract.Assert(elsIf != null && els == null); // follows from loop invariant and the fact that there's more than one alternative\n      builder.Add(elsIf);\n    }\n\n    void TrCallStmt(CallStmt s, BoogieStmtListBuilder builder, List<Variable> locals, ExpressionTranslator etran, Bpl.IdentifierExpr actualReceiver) {\n      Contract.Requires(s != null);\n      Contract.Requires(builder != null);\n      Contract.Requires(locals != null);\n      Contract.Requires(etran != null);\n      Contract.Requires(!(s.Method is Constructor) || (s.Lhs.Count == 0 && actualReceiver != null));\n\n      List<AssignToLhs> lhsBuilders;\n      List<Bpl.IdentifierExpr> bLhss;\n      Bpl.Expr[] ignore1, ignore2;\n      string[] ignore3;\n      var tySubst = s.MethodSelect.TypeArgumentSubstitutions();\n      ProcessLhss(s.Lhs, true, true, builder, locals, etran, out lhsBuilders, out bLhss, out ignore1, out ignore2, out ignore3);\n      Contract.Assert(s.Lhs.Count == lhsBuilders.Count);\n      Contract.Assert(s.Lhs.Count == bLhss.Count);\n      var lhsTypes = new List<Type>();\n      if (s.Method is Constructor) {\n        lhsTypes.Add(s.Receiver.Type);\n        bLhss.Add(actualReceiver);\n      } else {\n        for (int i = 0; i < s.Lhs.Count; i++) {\n          var lhs = s.Lhs[i];\n          lhsTypes.Add(lhs.Type);\n          builder.Add(new CommentCmd(\"TrCallStmt: Adding lhs \" + lhs + \" with type \" + lhs.Type));\n          if (bLhss[i] == null) {  // (in the current implementation, the second parameter \"true\" to ProcessLhss implies that all bLhss[*] will be null)\n            // create temporary local and assign it to bLhss[i]\n            string nm = CurrentIdGenerator.FreshId(\"$rhs##\");\n            var formalOutType = Resolver.SubstType(s.Method.Outs[i].Type, tySubst);\n            var ty = TrType(formalOutType);\n            Bpl.Expr wh = GetWhereClause(lhs.tok, new Bpl.IdentifierExpr(lhs.tok, nm, ty), formalOutType, etran,\n              isAllocContext.Var(s.IsGhost || s.Method.IsGhost, s.Method.Outs[i]));\n            Bpl.LocalVariable var = new Bpl.LocalVariable(lhs.tok, new Bpl.TypedIdent(lhs.tok, nm, ty, wh));\n            locals.Add(var);\n            bLhss[i] = new Bpl.IdentifierExpr(lhs.tok, var.Name, ty);\n          }\n        }\n      }\n      Bpl.IdentifierExpr initHeap = null;\n      if (codeContext is IteratorDecl) {\n        // var initHeap := $Heap;\n        var initHeapVar = new Bpl.LocalVariable(s.Tok, new Bpl.TypedIdent(s.Tok, CurrentIdGenerator.FreshId(\"$initHeapCallStmt#\"), predef.HeapType));\n        locals.Add(initHeapVar);\n        initHeap = new Bpl.IdentifierExpr(s.Tok, initHeapVar);\n        // initHeap := $Heap;\n        builder.Add(Bpl.Cmd.SimpleAssign(s.Tok, initHeap, etran.HeapExpr));\n      }\n      builder.Add(new CommentCmd(\"TrCallStmt: Before ProcessCallStmt\"));\n      ProcessCallStmt(s.Tok, tySubst, GetTypeParams(s.Method), s.Receiver, actualReceiver, s.Method, s.Args, bLhss, lhsTypes, builder, locals, etran);\n      builder.Add(new CommentCmd(\"TrCallStmt: After ProcessCallStmt\"));\n      for (int i = 0; i < lhsBuilders.Count; i++) {\n        var lhs = s.Lhs[i];\n        Type lhsType, rhsTypeConstraint;\n        if (lhs is IdentifierExpr) {\n          var ide = (IdentifierExpr)lhs;\n          lhsType = ide.Var.Type;\n          rhsTypeConstraint = lhsType;\n        } else if (lhs is MemberSelectExpr) {\n          var fse = (MemberSelectExpr)lhs;\n          var field = (Field)fse.Member;\n          Contract.Assert(field != null);\n          Contract.Assert(VisibleInScope(field));\n          lhsType = field.Type;\n          rhsTypeConstraint = Resolver.SubstType(lhsType, fse.TypeArgumentSubstitutions());\n        } else if (lhs is SeqSelectExpr) {\n          var e = (SeqSelectExpr)lhs;\n          lhsType = null;  // for arrays, always make sure the value assigned is boxed\n          rhsTypeConstraint = e.Seq.Type.TypeArgs[0];\n        } else {\n          var e = (MultiSelectExpr)lhs;\n          lhsType = null;  // for arrays, always make sure the value assigned is boxed\n          rhsTypeConstraint = e.Array.Type.TypeArgs[0];\n        }\n\n        Bpl.Expr bRhs = bLhss[i];  // the RHS (bRhs) of the assignment to the actual call-LHS (lhs) was a LHS (bLhss[i]) in the Boogie call statement\n        CheckSubrange(lhs.tok, bRhs, Resolver.SubstType(s.Method.Outs[i].Type, tySubst), rhsTypeConstraint, builder);\n        bRhs = CondApplyBox(lhs.tok, bRhs, lhs.Type, lhsType);\n\n        lhsBuilders[i](bRhs, false, builder, etran);\n      }\n      if (codeContext is IteratorDecl) {\n        var iter = (IteratorDecl)codeContext;\n        Contract.Assert(initHeap != null);\n        RecordNewObjectsIn_New(s.Tok, iter, initHeap, (Bpl.IdentifierExpr/*TODO: this cast is dubious*/)etran.HeapExpr, builder, locals, etran);\n      }\n      builder.Add(CaptureState(s));\n    }\n\n    List<Bpl.Expr> trTypeArgs(Dictionary<TypeParameter, Type> tySubst, List<TypeParameter> tyArgs) {\n      var res = new List<Bpl.Expr>();\n      foreach (var p in tyArgs) {\n        res.Add(TypeToTy(tySubst[p]));\n      }\n      return res;\n    }\n\n    void ProcessCallStmt(IToken tok,\n      Dictionary<TypeParameter, Type> tySubst, List<TypeParameter> tyArgs,\n      Expression dafnyReceiver, Bpl.Expr bReceiver,\n      Method method, List<Expression> Args,\n      List<Bpl.IdentifierExpr> Lhss, List<Type> LhsTypes,\n      BoogieStmtListBuilder builder, List<Variable> locals, ExpressionTranslator etran) {\n\n      Contract.Requires(tok != null);\n      Contract.Requires(dafnyReceiver != null || bReceiver != null);\n      Contract.Requires(method != null);\n      Contract.Requires(VisibleInScope(method));\n      Contract.Requires(Args != null);\n      Contract.Requires(Lhss != null);\n      Contract.Requires(LhsTypes != null);\n      // Note, a Dafny class constructor is declared to have no output parameters, but it is encoded in Boogie as\n      // having an output parameter.\n      Contract.Requires(method is Constructor || method.Outs.Count == Lhss.Count);\n      Contract.Requires(method is Constructor || method.Outs.Count == LhsTypes.Count);\n      Contract.Requires(!(method is Constructor) || (method.Outs.Count == 0 && Lhss.Count == 1 && LhsTypes.Count == 1));\n      Contract.Requires(builder != null);\n      Contract.Requires(locals != null);\n      Contract.Requires(etran != null);\n      Contract.Requires(tySubst != null);\n      Contract.Requires(tyArgs != null);\n      Contract.Requires(tySubst.Count == tyArgs.Count);\n\n      // Figure out if the call is recursive or not, which will be used below to determine the need for a\n      // termination check and the need to include an implicit _k-1 argument.\n      bool isRecursiveCall = false;\n      // consult the call graph to figure out if this is a recursive call\n      var module = method.EnclosingClass.Module;\n      if (codeContext != null && module == currentModule) {\n        // Note, prefix lemmas are not recorded in the call graph, but their corresponding colemmas are.\n        // Similarly, an iterator is not recorded in the call graph, but its MoveNext method is.\n        ICallable cllr =\n          codeContext is PrefixLemma ? ((PrefixLemma)codeContext).FixpointLemma :\n          codeContext is IteratorDecl ? ((IteratorDecl)codeContext).Member_MoveNext :\n          codeContext;\n        if (ModuleDefinition.InSameSCC(method, cllr)) {\n          isRecursiveCall = true;\n        }\n      }\n\n      MethodTranslationKind kind;\n      var callee = method;\n      if (method is FixpointLemma && isRecursiveCall) {\n        kind = MethodTranslationKind.CoCall;\n        callee = ((FixpointLemma)method).PrefixLemma;\n      } else if (method is PrefixLemma) {\n        // an explicit call to a prefix lemma is allowed only inside the SCC of the corresponding colemma,\n        // so we consider this to be a co-call\n        kind = MethodTranslationKind.CoCall;\n      } else {\n        kind = MethodTranslationKind.Call;\n      }\n\n\n      var ins = new List<Bpl.Expr>();\n      if (callee is TwoStateLemma) {\n        ins.Add(etran.Old.HeapExpr);\n        ins.Add(etran.HeapExpr);\n      }\n      // Add type arguments\n      ins.AddRange(trTypeArgs(tySubst, tyArgs));\n\n      // Translate receiver argument, if any\n      Expression receiver = bReceiver == null ? dafnyReceiver : new BoogieWrapper(bReceiver, dafnyReceiver.Type);\n      if (!method.IsStatic && !(method is Constructor)) {\n        if (bReceiver == null && !(dafnyReceiver is ThisExpr)) {\n          CheckNonNull(dafnyReceiver.tok, dafnyReceiver, builder, etran, null);\n        }\n        ins.Add(etran.TrExpr(receiver));\n      }\n\n      // Ideally, the modifies and decreases checks would be done after the precondition check,\n      // but Boogie doesn't give us a hook for that.  So, we set up our own local variables here to\n      // store the actual parameters.\n      // Create a local variable for each formal parameter, and assign each actual parameter to the corresponding local\n      var substMap = new Dictionary<IVariable, Expression>();\n      for (int i = 0; i < callee.Ins.Count; i++) {\n        var formal = callee.Ins[i];\n        var local = new LocalVariable(formal.tok, formal.tok, formal.Name + \"#\", formal.Type, formal.IsGhost, false);\n        local.type = local.OptionalType;  // resolve local here\n        var ie = new IdentifierExpr(local.Tok, local.AssignUniqueName(currentDeclaration.IdGenerator));\n        ie.Var = local; ie.Type = ie.Var.Type;  // resolve ie here\n        substMap.Add(formal, ie);\n        locals.Add(new Bpl.LocalVariable(local.Tok, new Bpl.TypedIdent(local.Tok, local.AssignUniqueName(currentDeclaration.IdGenerator), TrType(local.Type))));\n\n        var param = (Bpl.IdentifierExpr)etran.TrExpr(ie);  // TODO: is this cast always justified?\n        Bpl.Expr bActual;\n        if (i == 0 && method is FixpointLemma && isRecursiveCall) {\n          // Treat this call to M(args) as a call to the corresponding prefix lemma M#(_k - 1, args), so insert an argument here.\n          var k = ((PrefixLemma)codeContext).K;\n          var bplK = new Bpl.IdentifierExpr(k.tok, k.AssignUniqueName(currentDeclaration.IdGenerator), TrType(k.Type));\n          if (k.Type.IsBigOrdinalType) {\n            bActual = FunctionCall(k.tok, \"ORD#Minus\", predef.BigOrdinalType,\n              bplK,\n              FunctionCall(k.tok, \"ORD#FromNat\", predef.BigOrdinalType, Bpl.Expr.Literal(1)));\n          } else {\n            bActual = Bpl.Expr.Sub(bplK, Bpl.Expr.Literal(1));\n          }\n        } else {\n          Expression actual;\n          if (method is FixpointLemma && isRecursiveCall) {\n            actual = Args[i - 1];\n          } else {\n            actual = Args[i];\n          }\n          TrStmt_CheckWellformed(actual, builder, locals, etran, true);\n          builder.Add(new CommentCmd(\"ProcessCallStmt: CheckSubrange\"));\n          // Check the subrange without boxing\n          var beforeBox = etran.TrExpr(actual);\n          CheckSubrange(actual.tok, beforeBox, actual.Type, Resolver.SubstType(formal.Type, tySubst), builder);\n          bActual = CondApplyBox(actual.tok, beforeBox, actual.Type, formal.Type);\n        }\n        Bpl.Cmd cmd = Bpl.Cmd.SimpleAssign(formal.tok, param, bActual);\n        builder.Add(cmd);\n        ins.Add(param);\n      }\n\n      // Check that every parameter is available in the state in which the method is invoked; this means checking that it has\n      // the right type and is allocated.  These checks usually hold trivially, on account of that the Dafny language only gives\n      // access to expressions of the appropriate type and that are allocated in the current state.  However, if the method is\n      // invoked in the 'old' state or if the method invoked is a two-state lemma with a non-new parameter, then we need to\n      // check that its arguments were all available at that time as well.\n      if (etran.UsesOldHeap) {\n        if (!method.IsStatic && !(method is Constructor)) {\n          Bpl.Expr wh = GetWhereClause(receiver.tok, etran.TrExpr(receiver), receiver.Type, etran, ISALLOC, true);\n          if (wh != null) {\n            builder.Add(Assert(receiver.tok, wh, \"receiver argument must be allocated in the state in which the method is invoked\"));\n          }\n        }\n        for (int i = 0; i < Args.Count; i++) {\n          Expression ee = Args[i];\n          Bpl.Expr wh = GetWhereClause(ee.tok, etran.TrExpr(ee), ee.Type, etran, ISALLOC, true);\n          if (wh != null) {\n            builder.Add(Assert(ee.tok, wh, \"argument must be allocated in the state in which the method is invoked\"));\n          }\n        }\n      } else if (method is TwoStateLemma) {\n        if (!method.IsStatic) {\n          Bpl.Expr wh = GetWhereClause(receiver.tok, etran.TrExpr(receiver), receiver.Type, etran.Old, ISALLOC, true);\n          if (wh != null) {\n            builder.Add(Assert(receiver.tok, wh, \"receiver argument must be allocated in the two-state lemma's previous state\"));\n          }\n        }\n        Contract.Assert(callee.Ins.Count == Args.Count);\n        for (int i = 0; i < Args.Count; i++) {\n          var formal = callee.Ins[i];\n          if (formal.IsOld) {\n            Expression ee = Args[i];\n            Bpl.Expr wh = GetWhereClause(ee.tok, etran.TrExpr(ee), ee.Type, etran.Old, ISALLOC, true);\n            if (wh != null) {\n              builder.Add(Assert(ee.tok, wh, string.Format(\"parameter{0} ('{1}') must be allocated in the two-state lemma's previous state\",\n                Args.Count == 1 ? \"\" : \" \" + i, formal.Name)));\n            }\n          }\n        }\n      }\n\n      // Check modifies clause of a subcall is a subset of the current frame.\n      if (codeContext is IMethodCodeContext) {\n        CheckFrameSubset(tok, callee.Mod.Expressions, receiver, substMap, etran, builder, \"call may violate context's modifies clause\", null);\n      }\n\n      // Check termination\n      if (isRecursiveCall) {\n        Contract.Assert(codeContext != null);\n        List<Expression> contextDecreases = codeContext.Decreases.Expressions;\n        List<Expression> calleeDecreases = callee.Decreases.Expressions;\n        CheckCallTermination(tok, contextDecreases, calleeDecreases, null, receiver, substMap, tySubst, etran, etran.Old, builder, codeContext.InferredDecreases, null);\n      }\n\n      // Create variables to hold the output parameters of the call, so that appropriate unboxes can be introduced.\n      var outs = new List<Bpl.IdentifierExpr>();\n      var tmpOuts = new List<Bpl.IdentifierExpr>();\n      if (method is Constructor) {\n        tmpOuts.Add(null);\n        outs.Add(Lhss[0]);\n      } else {\n        for (int i = 0; i < Lhss.Count; i++) {\n          var bLhs = Lhss[i];\n          if (ModeledAsBoxType(callee.Outs[i].Type) && !ModeledAsBoxType(LhsTypes[i])) {\n            // we need an Unbox\n            Bpl.LocalVariable var = new Bpl.LocalVariable(bLhs.tok, new Bpl.TypedIdent(bLhs.tok, CurrentIdGenerator.FreshId(\"$tmp##\"), predef.BoxType));\n            locals.Add(var);\n            Bpl.IdentifierExpr varIdE = new Bpl.IdentifierExpr(bLhs.tok, var.Name, predef.BoxType);\n            tmpOuts.Add(varIdE);\n            outs.Add(varIdE);\n          } else {\n            tmpOuts.Add(null);\n            outs.Add(bLhs);\n          }\n        }\n      }\n\n      builder.Add(new CommentCmd(\"ProcessCallStmt: Make the call\"));\n      // Make the call\n      AddReferencedMember(callee);\n      Bpl.CallCmd call = Call(tok, MethodName(callee, kind), ins, outs);\n      if (module != currentModule && RefinementToken.IsInherited(tok, currentModule) && (codeContext == null || !codeContext.MustReverify)) {\n        // The call statement is inherited, so the refined module already checked that the precondition holds.  Note,\n        // preconditions are not allowed to be strengthened, except if they use a predicate whose body has been strengthened.\n        // But if the callee sits in a different module, then any predicate it uses will be treated as opaque (that is,\n        // uninterpreted) anyway, so the refined module will have checked the call precondition for all possible definitions\n        // of the predicate.\n        call.IsFree = true;\n      }\n      builder.Add(call);\n\n      // Unbox results as needed\n      for (int i = 0; i < Lhss.Count; i++) {\n        Bpl.IdentifierExpr bLhs = Lhss[i];\n        Bpl.IdentifierExpr tmpVarIdE = tmpOuts[i];\n        if (tmpVarIdE != null) {\n          // Instead of an assignment:\n          //    e := UnBox(tmpVar);\n          // we use:\n          //    havoc e; assume e == UnBox(tmpVar);\n          // because that will reap the benefits of e's where clause, so that some additional type information will be known about\n          // the out-parameter.\n          Bpl.Cmd cmd = new Bpl.HavocCmd(bLhs.tok, new List<Bpl.IdentifierExpr> { bLhs });\n          builder.Add(cmd);\n          cmd = TrAssumeCmd(bLhs.tok, Bpl.Expr.Eq(bLhs, FunctionCall(bLhs.tok, BuiltinFunction.Unbox, TrType(LhsTypes[i]), tmpVarIdE)));\n          builder.Add(cmd);\n        }\n      }\n    }\n\n    Dictionary<IVariable, Expression> SetupBoundVarsAsLocals(List<BoundVar> boundVars, BoogieStmtListBuilder builder, List<Variable> locals, ExpressionTranslator etran, Dictionary<TypeParameter, Type> typeMap = null, string nameSuffix = null) {\n      Contract.Requires(boundVars != null);\n      Contract.Requires(builder != null);\n      Contract.Requires(locals != null);\n      Contract.Requires(etran != null);\n\n      if (typeMap == null) {\n        typeMap = new Dictionary<TypeParameter, Type>();\n      }\n      var substMap = new Dictionary<IVariable, Expression>();\n      foreach (BoundVar bv in boundVars) {\n        LocalVariable local = new LocalVariable(bv.tok, bv.tok, nameSuffix == null ? bv.Name : bv.Name + nameSuffix, Resolver.SubstType(bv.Type, typeMap), bv.IsGhost, true);\n        local.type = local.OptionalType;  // resolve local here\n        IdentifierExpr ie = new IdentifierExpr(local.Tok, local.AssignUniqueName(currentDeclaration.IdGenerator));\n        ie.Var = local; ie.Type = ie.Var.Type;  // resolve ie here\n        substMap.Add(bv, ie);\n        Bpl.LocalVariable bvar = new Bpl.LocalVariable(local.Tok, new Bpl.TypedIdent(local.Tok, local.AssignUniqueName(currentDeclaration.IdGenerator), TrType(local.Type)));\n        locals.Add(bvar);\n        var bIe = new Bpl.IdentifierExpr(bvar.tok, bvar);\n        builder.Add(new Bpl.HavocCmd(bv.tok, new List<Bpl.IdentifierExpr> { bIe }));\n        Bpl.Expr wh = GetWhereClause(bv.tok, bIe, local.Type, etran, NOALLOC);\n        if (wh != null) {\n          builder.Add(TrAssumeCmd(bv.tok, wh));\n        }\n      }\n      return substMap;\n    }\n\n    List<Bpl.Expr> RecordDecreasesValue(List<Expression> decreases, BoogieStmtListBuilder builder, List<Variable> locals, ExpressionTranslator etran, string varPrefix)\n    {\n      Contract.Requires(locals != null);\n      Contract.Requires(etran != null);\n      Contract.Requires(varPrefix != null);\n      Contract.Requires(builder != null);\n      Contract.Requires(decreases != null);\n      List<Bpl.Expr> oldBfs = new List<Bpl.Expr>();\n      var idGen = new FreshIdGenerator();\n      foreach (Expression e in decreases) {\n        Contract.Assert(e != null);\n        Bpl.LocalVariable bfVar = new Bpl.LocalVariable(e.tok, new Bpl.TypedIdent(e.tok, idGen.FreshId(varPrefix), TrType(cce.NonNull(e.Type))));\n        locals.Add(bfVar);\n        Bpl.IdentifierExpr bf = new Bpl.IdentifierExpr(e.tok, bfVar);\n        oldBfs.Add(bf);\n        // record value of each decreases expression at beginning of the loop iteration\n        Bpl.Cmd cmd = Bpl.Cmd.SimpleAssign(e.tok, bf, etran.TrExpr(e));\n        builder.Add(cmd);\n      }\n      return oldBfs;\n    }\n\n    /// <summary>\n    /// Emit to \"builder\" a check that calleeDecreases is less than contextDecreases.  More precisely,\n    /// the check is:\n    ///     allowance || (calleeDecreases LESS contextDecreases).\n    /// </summary>\n    void CheckCallTermination(IToken tok, List<Expression> contextDecreases, List<Expression> calleeDecreases,\n                              Bpl.Expr allowance,\n                              Expression receiverReplacement, Dictionary<IVariable,Expression> substMap,\n                              Dictionary<TypeParameter, Type> typeMap,\n                              ExpressionTranslator etranCurrent, ExpressionTranslator etranInitial, BoogieStmtListBuilder builder, bool inferredDecreases, string hint) {\n      Contract.Requires(tok != null);\n      Contract.Requires(cce.NonNullElements(contextDecreases));\n      Contract.Requires(cce.NonNullElements(calleeDecreases));\n      Contract.Requires(cce.NonNullDictionaryAndValues(substMap));\n      Contract.Requires(etranCurrent != null);\n      Contract.Requires(etranInitial != null);\n      Contract.Requires(builder != null);\n\n      // The interpretation of the given decreases-clause expression tuples is as a lexicographic tuple, extended into\n      // an infinite tuple by appending TOP elements.  The TOP element is strictly larger than any other value given\n      // by a Dafny expression.  Each Dafny types has its own ordering, and these orderings are combined into a partial\n      // order where elements from different Dafny types are incomparable.  Thus, as an optimization below, if two\n      // components from different types are compared, the answer is taken to be false.\n\n      if (Contract.Exists(calleeDecreases, e => e is WildcardExpr)) {\n        // no check needed\n        return;\n      }\n\n      int N = Math.Min(contextDecreases.Count, calleeDecreases.Count);\n      var toks = new List<IToken>();\n      var types0 = new List<Type>();\n      var types1 = new List<Type>();\n      var callee = new List<Expr>();\n      var caller = new List<Expr>();\n      if (RefinementToken.IsInherited(tok, currentModule) && contextDecreases.All(e => !RefinementToken.IsInherited(e.tok, currentModule))) {\n        // the call site is inherited but all the context decreases expressions are new\n        tok = new ForceCheckToken(tok);\n      }\n      for (int i = 0; i < N; i++) {\n        Expression e0 = Substitute(calleeDecreases[i], receiverReplacement, substMap, typeMap);\n        Expression e1 = contextDecreases[i];\n        if (!CompatibleDecreasesTypes(e0.Type, e1.Type)) {\n          N = i;\n          break;\n        }\n        toks.Add(new NestedToken(tok, e1.tok));\n        types0.Add(e0.Type.NormalizeExpand());\n        types1.Add(e1.Type.NormalizeExpand());\n        callee.Add(etranCurrent.TrExpr(e0));\n        caller.Add(etranInitial.TrExpr(e1));\n      }\n      bool endsWithWinningTopComparison = N == contextDecreases.Count && N < calleeDecreases.Count;\n      Bpl.Expr decrExpr = DecreasesCheck(toks, types0, types1, callee, caller, builder, \"\", endsWithWinningTopComparison, false);\n      if (allowance != null) {\n        decrExpr = Bpl.Expr.Or(allowance, decrExpr);\n      }\n      string msg = inferredDecreases ? \"cannot prove termination; try supplying a decreases clause\" : \"failure to decrease termination measure\";\n      if (hint != null) {\n        msg += \" (\" + hint + \")\";\n      }\n      builder.Add(Assert(tok, decrExpr, msg));\n    }\n\n    /// <summary>\n    /// Returns the expression that says whether or not the decreases function has gone down (if !allowNoChange)\n    /// or has gone down or stayed the same (if allowNoChange).\n    /// ee0 represents the new values and ee1 represents old values.\n    /// If builder is non-null, then the check '0 ATMOST decr' is generated to builder.\n    /// Requires all types in types0 and types1 to be non-proxy non-synonym types (that is, callers should invoke NormalizeExpand)\n    /// </summary>\n    Bpl.Expr DecreasesCheck(List<IToken> toks, List<Type> types0, List<Type> types1, List<Bpl.Expr> ee0, List<Bpl.Expr> ee1,\n                            BoogieStmtListBuilder builder, string suffixMsg, bool allowNoChange, bool includeLowerBound)\n    {\n      Contract.Requires(cce.NonNullElements(toks));\n      Contract.Requires(cce.NonNullElements(types0));\n      Contract.Requires(cce.NonNullElements(types1));\n      Contract.Requires(cce.NonNullElements(ee0));\n      Contract.Requires(cce.NonNullElements(ee1));\n      Contract.Requires(predef != null);\n      Contract.Requires(types0.Count == types1.Count && types0.Count == ee0.Count && ee0.Count == ee1.Count);\n      Contract.Requires(builder == null || suffixMsg != null);\n      Contract.Ensures(Contract.Result<Bpl.Expr>() != null);\n\n      int N = types0.Count;\n\n      // compute eq and less for each component of the lexicographic tuple\n      List<Bpl.Expr> Eq = new List<Bpl.Expr>(N);\n      List<Bpl.Expr> Less = new List<Bpl.Expr>(N);\n      for (int i = 0; i < N; i++) {\n        Bpl.Expr less, atmost, eq;\n        ComputeLessEq(toks[i], types0[i], types1[i], ee0[i], ee1[i], out less, out atmost, out eq, includeLowerBound);\n        Eq.Add(eq);\n        Less.Add(allowNoChange ? atmost : less);\n      }\n      if (builder != null) {\n        // check: 0 <= ee1\n        // more precisely, for component k of the lexicographic decreases function, check:\n        //   ee0[0] < ee1[0] || ee0[1] < ee1[1] || ... || ee0[k-1] < ee1[k-1] || ee0[k] == ee1[k] || 0 <= ee1[k]\n        for (int k = 0; k < N; k++) {\n          // we only need to check lower bound for integers--sets, sequences, booleans, references, and datatypes all have natural lower bounds\n          Bpl.Expr prefixIsLess = Bpl.Expr.False;\n          for (int i = 0; i < k; i++) {\n            prefixIsLess = Bpl.Expr.Or(prefixIsLess, Less[i]);\n          };\n\n          Bpl.Expr zero = null;\n          string zeroStr = null;\n          if (types0[k].IsNumericBased(Type.NumericPersuation.Int)) {\n            zero = Bpl.Expr.Literal(0);\n            zeroStr = \"0\";\n          } else if (types0[k].IsNumericBased(Type.NumericPersuation.Real)) {\n            zero = Bpl.Expr.Literal(BaseTypes.BigDec.ZERO);\n            zeroStr = \"0.0\";\n          }\n          if (zero != null) {\n            Bpl.Expr bounded = Bpl.Expr.Le(zero, ee1[k]);\n            for (int i = 0; i < k; i++) {\n              bounded = Bpl.Expr.Or(bounded, Less[i]);\n            }\n            string component = N == 1 ? \"\" : \" (component \" + k + \")\";\n            Bpl.Cmd cmd = Assert(toks[k], Bpl.Expr.Or(bounded, Eq[k]), \"decreases expression\" + component + \" must be bounded below by \" + zeroStr + suffixMsg);\n            builder.Add(cmd);\n          }\n        }\n      }\n      // check: ee0 < ee1 (or ee0 <= ee1, if allowNoChange)\n      Bpl.Expr decrCheck = allowNoChange ? Bpl.Expr.True : Bpl.Expr.False;\n      for (int i = N; 0 <= --i; ) {\n        Bpl.Expr less = Less[i];\n        Bpl.Expr eq = Eq[i];\n        if (allowNoChange) {\n          // decrCheck = atmost && (eq ==> decrCheck)\n          decrCheck = Bpl.Expr.And(less, Bpl.Expr.Imp(eq, decrCheck));\n        } else {\n          // decrCheck = less || (eq && decrCheck)\n          decrCheck = Bpl.Expr.Or(less, Bpl.Expr.And(eq, decrCheck));\n        }\n      }\n      return decrCheck;\n    }\n\n    bool CompatibleDecreasesTypes(Type t, Type u) {\n      Contract.Requires(t != null);\n      Contract.Requires(u != null);\n      t = t.NormalizeExpand();\n      u = u.NormalizeExpand();\n      if (t is BoolType) {\n        return u is BoolType;\n      } else if (t is CharType) {\n        return u is CharType;\n      } else if (t.IsNumericBased(Type.NumericPersuation.Int)) {\n        // we can allow different kinds of int-based types\n        return u.IsNumericBased(Type.NumericPersuation.Int);\n      } else if (t.IsNumericBased(Type.NumericPersuation.Real)) {\n        // we can allow different kinds of real-based types\n        return u.IsNumericBased(Type.NumericPersuation.Real);\n      } else if (t is SetType) {\n        return u is SetType;\n      } else if (t is SeqType) {\n        return u is SeqType || u.IsIndDatatype;\n      } else if (t.IsDatatype) {\n        return u.IsDatatype || (t.IsIndDatatype && u is SeqType);\n      } else if (t.IsRefType) {\n        return u.IsRefType;\n      } else if (t is MultiSetType) {\n        return u is MultiSetType;\n      } else if (t is MapType) {\n        return u is MapType && ((MapType)t).Finite == ((MapType)u).Finite;\n      } else if (t is ArrowType) {\n        return u is ArrowType;\n      } else if (t is BitvectorType) {\n        return u is BitvectorType;\n      } else if (t is BigOrdinalType) {\n        return u is BigOrdinalType;\n      } else {\n        Contract.Assert(t.IsTypeParameter || t.IsInternalTypeSynonym);\n        return false;  // don't consider any type parameters to be the same (since we have no comparison function for them anyway)\n      }\n    }\n\n    Nullable<BuiltinFunction> RankFunction(Type/*!*/ ty)\n    {\n      Contract.Ensures(ty != null);\n      if (ty is SeqType)      return BuiltinFunction.SeqRank;\n      else if (ty.IsDatatype) return BuiltinFunction.DtRank;\n      else return null;\n    }\n\n    void ComputeLessEq(IToken tok, Type ty0, Type ty1, Bpl.Expr e0, Bpl.Expr e1, out Bpl.Expr less, out Bpl.Expr atmost, out Bpl.Expr eq, bool includeLowerBound)\n    {\n      Contract.Requires(tok != null);\n      Contract.Requires(ty0 != null);\n      Contract.Requires(ty1 != null);\n      Contract.Requires(e0 != null);\n      Contract.Requires(e1 != null);\n      Contract.Requires(predef != null);\n      Contract.Ensures(Contract.ValueAtReturn(out less)!=null);\n      Contract.Ensures(Contract.ValueAtReturn(out atmost)!=null);\n      Contract.Ensures(Contract.ValueAtReturn(out eq)!=null);\n\n      ty0 = ty0.NormalizeExpand();\n      ty1 = ty1.NormalizeExpand();\n      var rk0 = RankFunction(ty0);\n      var rk1 = RankFunction(ty1);\n      if (rk0 != null && rk1 != null && rk0 != rk1) {\n        eq = Bpl.Expr.False;\n        Bpl.Expr b0 = FunctionCall(tok, rk0.Value, null, e0);\n        Bpl.Expr b1 = FunctionCall(tok, rk1.Value, null, e1);\n        less = Bpl.Expr.Lt(b0, b1);\n        atmost = Bpl.Expr.Le(b0, b1);\n      } else if (ty0 is BoolType) {\n        eq = Bpl.Expr.Iff(e0, e1);\n        less = Bpl.Expr.And(Bpl.Expr.Not(e0), e1);\n        atmost = Bpl.Expr.Imp(e0, e1);\n      } else if (ty0 is CharType) {\n        eq = Bpl.Expr.Eq(e0, e1);\n        var operand0 = FunctionCall(e0.tok, BuiltinFunction.CharToInt, null, e0);\n        var operand1 = FunctionCall(e0.tok, BuiltinFunction.CharToInt, null, e1);\n        less = Bpl.Expr.Binary(tok, BinaryOperator.Opcode.Lt, operand0, operand1);\n        atmost = Bpl.Expr.Binary(tok, BinaryOperator.Opcode.Le, operand0, operand1);\n      } else if (ty0.IsNumericBased(Type.NumericPersuation.Int) || ty0 is SeqType || ty0.IsDatatype) {\n        Bpl.Expr b0, b1;\n        if (ty0.IsNumericBased(Type.NumericPersuation.Int)) {\n          b0 = e0;\n          b1 = e1;\n        } else if (ty0 is SeqType) {\n          b0 = FunctionCall(tok, BuiltinFunction.SeqRank, null, e0);\n          b1 = FunctionCall(tok, BuiltinFunction.SeqRank, null, e1);\n        } else if (ty0.IsDatatype) {\n          b0 = FunctionCall(tok, BuiltinFunction.DtRank, null, e0);\n          b1 = FunctionCall(tok, BuiltinFunction.DtRank, null, e1);\n        } else {\n          Contract.Assert(false); throw new cce.UnreachableException();\n        }\n        eq = Bpl.Expr.Eq(b0, b1);\n        less = Bpl.Expr.Lt(b0, b1);\n        atmost = Bpl.Expr.Le(b0, b1);\n        if (ty0.IsNumericBased(Type.NumericPersuation.Int) && includeLowerBound) {\n          less = Bpl.Expr.And(Bpl.Expr.Le(Bpl.Expr.Literal(0), b0), less);\n          atmost = Bpl.Expr.And(Bpl.Expr.Le(Bpl.Expr.Literal(0), b0), atmost);\n        }\n\n      } else if (ty0.IsNumericBased(Type.NumericPersuation.Real)) {\n        eq = Bpl.Expr.Eq(e0, e1);\n        less = Bpl.Expr.Le(e0, Bpl.Expr.Sub(e1, Bpl.Expr.Literal(BaseTypes.BigDec.FromInt(1))));\n        atmost = Bpl.Expr.Le(e0, e1);\n        if (includeLowerBound) {\n          less = Bpl.Expr.And(Bpl.Expr.Le(Bpl.Expr.Literal(BaseTypes.BigDec.ZERO), e0), less);\n          atmost = Bpl.Expr.And(Bpl.Expr.Le(Bpl.Expr.Literal(BaseTypes.BigDec.ZERO), e0), atmost);\n        }\n\n      } else if (ty0 is IteratorDecl.EverIncreasingType) {\n        eq = Bpl.Expr.Eq(e0, e1);\n        less = Bpl.Expr.Gt(e0, e1);\n        atmost = Bpl.Expr.Ge(e0, e1);\n\n      } else if ((ty0 is SetType && ((SetType)ty0).Finite) || (ty0 is MapType && ((MapType)ty0).Finite)) {\n        Bpl.Expr b0, b1;\n        if (ty0 is SetType && ((SetType)ty0).Finite) {\n          b0 = e0;\n          b1 = e1;\n        } else if (ty0 is MapType && ((MapType)ty0).Finite) {\n          // for maps, compare their domains as sets\n          b0 = FunctionCall(tok, BuiltinFunction.MapDomain, predef.MapType(tok, true, predef.BoxType, predef.BoxType), e0);\n          b1 = FunctionCall(tok, BuiltinFunction.MapDomain, predef.MapType(tok, true, predef.BoxType, predef.BoxType), e1);\n        } else {\n          Contract.Assert(false); throw new cce.UnreachableException();\n        }\n        eq = FunctionCall(tok, BuiltinFunction.SetEqual, null, b0, b1);\n        less = ProperSubset(tok, b0, b1);\n        atmost = FunctionCall(tok, BuiltinFunction.SetSubset, null, b0, b1);\n\n      } else if (ty0 is MultiSetType) {\n        eq = FunctionCall(tok, BuiltinFunction.MultiSetEqual, null, e0, e1);\n        less = ProperMultiset(tok, e0, e1);\n        atmost = FunctionCall(tok, BuiltinFunction.MultiSetSubset, null, e0, e1);\n\n      } else if (ty0 is MapType && !((MapType)ty0).Finite) {\n        eq = Bpl.Expr.False;\n        less = Bpl.Expr.False;\n        atmost = Bpl.Expr.False;\n\n      } else if (ty0 is ArrowType) {\n        // TODO: ComputeLessEq for arrow types\n        // what!?\n        eq = Bpl.Expr.False;\n        less = Bpl.Expr.False;\n        atmost = Bpl.Expr.False;\n\n      } else if (ty0 is BitvectorType) {\n        BitvectorType bv = (BitvectorType)ty0;\n        eq = Bpl.Expr.Eq(e0, e1);\n        less = FunctionCall(tok, \"lt_bv\" + bv.Width, Bpl.Type.Bool, e0, e1);\n        atmost = FunctionCall(tok, \"ge_bv\" + bv.Width, Bpl.Type.Bool, e0, e1);\n\n      } else if (ty0 is BigOrdinalType) {\n        eq = Bpl.Expr.Eq(e0, e1);\n        less = FunctionCall(tok, \"ORD#Less\", Bpl.Type.Bool, e0, e1);\n        atmost = BplOr(eq, less);\n\n      } else {\n        // reference type\n        Contract.Assert(ty0.IsRefType);  // otherwise, unexpected type\n        var b0 = Bpl.Expr.Neq(e0, predef.Null);\n        var b1 = Bpl.Expr.Neq(e1, predef.Null);\n        eq = Bpl.Expr.Iff(b0, b1);\n        less = Bpl.Expr.And(Bpl.Expr.Not(b0), b1);\n        atmost = Bpl.Expr.Imp(b0, b1);\n      }\n    }\n\n    void AddComment(BoogieStmtListBuilder builder, Statement stmt, string comment) {\n      Contract.Requires(builder != null);\n      Contract.Requires(stmt != null);\n      Contract.Requires(comment != null);\n      builder.Add(new Bpl.CommentCmd(string.Format(\"----- {0} ----- {1}({2},{3})\", comment, stmt.Tok.filename, stmt.Tok.line, stmt.Tok.col)));\n    }\n\n    /// <summary>\n    /// Therefore, these properties are applied to method in-parameters.\n    /// For now, this only allows you to case split on incoming data type values.\n    /// This used to add IsGood[Multi]Set_Extendend, but that is always\n    /// added for sets & multisets now in the prelude.\n    /// </summary>\n    Bpl.Expr GetExtendedWhereClause(IToken tok, Bpl.Expr x, Type type, ExpressionTranslator etran, IsAllocType alloc) {\n      Contract.Requires(tok != null);\n      Contract.Requires(x != null);\n      Contract.Requires(type != null);\n      Contract.Requires(etran != null);\n      Contract.Requires(predef != null);\n      var r = GetWhereClause(tok, x, type, etran, alloc);\n      type = type.NormalizeExpand();\n      if (type.IsDatatype) {\n        UserDefinedType udt = (UserDefinedType)type;\n        var oneOfTheCases = FunctionCall(tok, \"$IsA#\" + udt.ResolvedClass.FullSanitizedName, Bpl.Type.Bool, x);\n        return BplAnd(r, oneOfTheCases);\n      } else {\n        return r;\n      }\n    }\n\n    /// <summary>\n    /// Translates an AST Type to a Boogie expression of type Ty.\n    /// </summary>\n    Bpl.Expr TypeToTy(Type type) {\n      Contract.Requires(type != null);\n      Contract.Ensures(Contract.Result<Bpl.Expr>() != null);\n\n      var normType = type.NormalizeExpandKeepConstraints();\n\n      if (normType.IsTypeParameter) {\n        return trTypeParam(normType.AsTypeParameter, normType.TypeArgs);\n      } else if (normType is UserDefinedType) {\n        // Classes, (co-)datatypes, newtypes, subset types, ...\n        var args = normType.TypeArgs.ConvertAll(TypeToTy);\n        return ClassTyCon(((UserDefinedType)normType), args);\n      } else if (normType is SetType) {\n        bool finite = ((SetType)normType).Finite;\n        return FunctionCall(Token.NoToken, finite ? \"TSet\" : \"TISet\", predef.Ty, TypeToTy(((CollectionType)normType).Arg));\n      } else if (normType is MultiSetType) {\n        return FunctionCall(Token.NoToken, \"TMultiSet\", predef.Ty, TypeToTy(((CollectionType)normType).Arg));\n      } else if (normType is SeqType) {\n        return FunctionCall(Token.NoToken, \"TSeq\", predef.Ty, TypeToTy(((CollectionType)normType).Arg));\n      } else if (normType is MapType) {\n        bool finite = ((MapType)normType).Finite;\n        return FunctionCall(Token.NoToken, finite ? \"TMap\" : \"TIMap\", predef.Ty,\n          TypeToTy(((MapType)normType).Domain),\n          TypeToTy(((MapType)normType).Range));\n      } else if (normType is BoolType) {\n        return new Bpl.IdentifierExpr(Token.NoToken, \"TBool\", predef.Ty);\n      } else if (normType is CharType) {\n        return new Bpl.IdentifierExpr(Token.NoToken, \"TChar\", predef.Ty);\n      } else if (normType is RealType) {\n        return new Bpl.IdentifierExpr(Token.NoToken, \"TReal\", predef.Ty);\n      } else if (normType is BitvectorType) {\n        var t = (BitvectorType)normType;\n        return FunctionCall(Token.NoToken, \"TBitvector\", predef.Ty, Bpl.Expr.Literal(t.Width));\n      } else if (normType is IntType) {\n        return new Bpl.IdentifierExpr(Token.NoToken, \"TInt\", predef.Ty);\n      } else if (normType is BigOrdinalType) {\n        return new Bpl.IdentifierExpr(Token.NoToken, \"TORDINAL\", predef.Ty);\n      } else if (normType is ParamTypeProxy) {\n        return trTypeParam(((ParamTypeProxy)normType).orig, null);\n      } else {\n        Contract.Assert(false); throw new cce.UnreachableException();  // unexpected type\n      }\n    }\n\n    static string nameTypeParam(TypeParameter x) {\n      Contract.Requires(x != null);\n      if (x.Parent != null) {\n        return x.Parent.FullName + \"$\" + x.Name;\n      } else {\n        // This happens for builtins, like arrays, that don't have a parent\n        return \"#$\" + x.Name;\n      }\n    }\n\n    Bpl.Expr trTypeParam(TypeParameter x, List<Type> tyArguments) {\n      Contract.Requires(x != null);\n      var nm = nameTypeParam(x);\n      var opaqueType = x as OpaqueType_AsParameter;\n      if (tyArguments != null && tyArguments.Count != 0) {\n          List<Bpl.Expr> args = tyArguments.ConvertAll(TypeToTy);\n          return FunctionCall(x.tok, nm, predef.Ty, args);\n      } else {\n        // return an identifier denoting a constant\n        return new Bpl.IdentifierExpr(x.tok, nm, predef.Ty);\n      }\n    }\n\n    public List<TypeParameter> GetTypeParams(IMethodCodeContext cc) {\n      if (cc is Method) {\n        Method m = (Method)cc;\n        return Concat(GetTypeParams(m.EnclosingClass), m.TypeArgs);\n      } else if (cc is IteratorDecl) {\n        return cc.TypeArgs; // This one cannot be enclosed in a class\n      } else {\n        Contract.Assert(false);\n        return null;\n      }\n    }\n\n    static public List<TypeParameter> GetTypeParams(TopLevelDecl d) {\n      Contract.Requires(d is ClassDecl || d is DatatypeDecl || d is NewtypeDecl || d is ValuetypeDecl);\n      return d.TypeArgs;\n    }\n\n    static List<TypeParameter> GetTypeParams(Function f) {\n      if (f.EnclosingClass == null) {\n        return f.TypeArgs;\n      } else {\n        return Concat(GetTypeParams(f.EnclosingClass), f.TypeArgs);\n      }\n    }\n\n    /// <summary>\n    /// Return $IsBox(x, t).\n    /// </summary>\n    Bpl.Expr MkIsBox(Bpl.Expr x, Type t) {\n      return MkIs(x, TypeToTy(t.NormalizeExpandKeepConstraints()), true);\n    }\n\n    // Boxes, if necessary\n    Bpl.Expr MkIs(Bpl.Expr x, Type t) {\n      return MkIs(x, TypeToTy(t), ModeledAsBoxType(t));\n    }\n\n    Bpl.Expr MkIs(Bpl.Expr x, Bpl.Expr t, bool box = false) {\n      if (box) {\n        return FunctionCall(x.tok, BuiltinFunction.IsBox, null, x, t);\n      } else {\n        return FunctionCall(x.tok, BuiltinFunction.Is, null, x, t);\n      }\n    }\n\n    // Boxes, if necessary\n    Bpl.Expr MkIsAlloc(Bpl.Expr x, Type t, Bpl.Expr h)\n    {\n      return MkIsAlloc(x, TypeToTy(t), h, ModeledAsBoxType(t));\n    }\n\n    Bpl.Expr MkIsAlloc(Bpl.Expr x, Bpl.Expr t, Bpl.Expr h, bool box = false) {\n      if (box) {\n        return FunctionCall(x.tok, BuiltinFunction.IsAllocBox, null, x, t, h);\n      } else {\n        return FunctionCall(x.tok, BuiltinFunction.IsAlloc, null, x, t, h);\n      }\n    }\n\n\n    Bpl.Expr GetWhereClause(IToken tok, Bpl.Expr x, Type type, ExpressionTranslator etran, IsAllocType alloc, bool allocatednessOnly = false) {\n      Contract.Requires(tok != null);\n      Contract.Requires(x != null);\n      Contract.Requires(type != null);\n      Contract.Requires(etran != null);\n      Contract.Requires(predef != null);\n\n      if (type.NormalizeExpand() is TypeProxy) {\n        // Unresolved proxy\n        // Omit where clause (in other places, unresolved proxies are treated as a reference type; we could do that here too, but\n        // we might as well leave out the where clause altogether).\n        return null;\n      }\n\n      var normType = type.NormalizeExpandKeepConstraints();\n      Bpl.Expr isAlloc;\n      if (type.IsNumericBased() || type.IsBitVectorType || type.IsBoolType || type.IsCharType || type.IsBigOrdinalType) {\n        isAlloc = null;\n      } else if ((AlwaysUseHeap || alloc == ISALLOC) && etran.HeapExpr != null) {\n        isAlloc = MkIsAlloc(x, normType, etran.HeapExpr);\n      } else {\n        isAlloc = null;\n      }\n      if (allocatednessOnly) {\n        return isAlloc;\n      }\n\n      Bpl.Expr isPred = null;\n      if (normType is BoolType || normType is IntType || normType is RealType || normType is BigOrdinalType) {\n        // nothing to do\n      } else if (normType is BitvectorType) {\n        var t = (BitvectorType)normType;\n        if (t.Width == 0) {\n          // type bv0 has only one value\n          return Bpl.Expr.Eq(BplBvLiteralExpr(tok, BaseTypes.BigNum.ZERO, t), x);\n        }\n      } else if ((normType.AsTypeSynonym != null || normType.AsNewtype != null) &&\n        (normType.IsNumericBased() || normType.IsBitVectorType || normType.IsBoolType)) {\n        var constraint = Resolver.GetImpliedTypeConstraint(new BoogieWrapper(x, normType), normType);\n        isPred = etran.TrExpr(constraint);\n      } else {\n        // go for the symbolic name\n        isPred = MkIs(x, normType);\n      }\n      return isAlloc == null ? isPred : isPred == null ? isAlloc : BplAnd(isPred, isAlloc);\n    }\n\n    /// <summary>\n    /// \"lhs\" is expected to be a resolved form of an expression, i.e., not a conrete-syntax expression.\n    /// </summary>\n    void TrAssignment(Statement stmt, Expression lhs, AssignmentRhs rhs,\n      BoogieStmtListBuilder builder, List<Variable> locals, ExpressionTranslator etran)\n    {\n      Contract.Requires(stmt != null);\n      Contract.Requires(lhs != null);\n      Contract.Requires(!(lhs is ConcreteSyntaxExpression));\n      Contract.Requires(!(lhs is SeqSelectExpr && !((SeqSelectExpr)lhs).SelectOne));  // these were once allowed, but their functionality is now provided by 'forall' statements\n      Contract.Requires(rhs != null);\n      Contract.Requires(builder != null);\n      Contract.Requires(cce.NonNullElements(locals));\n      Contract.Requires(etran != null);\n      Contract.Requires(predef != null);\n\n      List<AssignToLhs> lhsBuilder;\n      List<Bpl.IdentifierExpr> bLhss;\n      var lhss = new List<Expression>() { lhs };\n      Bpl.Expr[] ignore1, ignore2;\n      string[] ignore3;\n      ProcessLhss(lhss, rhs.CanAffectPreviouslyKnownExpressions, true, builder, locals, etran,\n        out lhsBuilder, out bLhss, out ignore1, out ignore2, out ignore3);\n      Contract.Assert(lhsBuilder.Count == 1 && bLhss.Count == 1);  // guaranteed by postcondition of ProcessLhss\n\n      var rhss = new List<AssignmentRhs>() { rhs };\n      ProcessRhss(lhsBuilder, bLhss, lhss, rhss, builder, locals, etran);\n      builder.Add(CaptureState(stmt));\n    }\n\n    void ProcessRhss(List<AssignToLhs> lhsBuilder, List<Bpl.IdentifierExpr/*may be null*/> bLhss,\n      List<Expression> lhss, List<AssignmentRhs> rhss,\n      BoogieStmtListBuilder builder, List<Variable> locals, ExpressionTranslator etran) {\n      Contract.Requires(lhsBuilder != null);\n      Contract.Requires(bLhss != null);\n      Contract.Requires(cce.NonNullElements(lhss));\n      Contract.Requires(cce.NonNullElements(rhss));\n      Contract.Requires(builder != null);\n      Contract.Requires(cce.NonNullElements(locals));\n      Contract.Requires(etran != null);\n      Contract.Requires(predef != null);\n\n      var finalRhss = new List<Bpl.Expr>();\n      for (int i = 0; i < lhss.Count; i++) {\n        var lhs = lhss[i];\n        // the following assumes are part of the precondition, really\n        Contract.Assume(!(lhs is ConcreteSyntaxExpression));\n        Contract.Assume(!(lhs is SeqSelectExpr && !((SeqSelectExpr)lhs).SelectOne));  // array-range assignments are not allowed\n\n        Type lhsType, rhsTypeConstraint;\n        if (lhs is IdentifierExpr) {\n          var ide = (IdentifierExpr)lhs;\n          lhsType = ide.Var.Type;\n          rhsTypeConstraint = lhsType;\n        } else if (lhs is MemberSelectExpr) {\n          var fse = (MemberSelectExpr)lhs;\n          var field = (Field)fse.Member;\n          Contract.Assert(VisibleInScope(field));\n          lhsType = field.Type;\n          rhsTypeConstraint = Resolver.SubstType(lhsType, fse.TypeArgumentSubstitutions());\n        } else if (lhs is SeqSelectExpr) {\n          var e = (SeqSelectExpr)lhs;\n          lhsType = null;  // for an array update, always make sure the value assigned is boxed\n          rhsTypeConstraint = e.Seq.Type.NormalizeExpand().TypeArgs[0];\n        } else {\n          var e = (MultiSelectExpr)lhs;\n          lhsType = null;  // for an array update, always make sure the value assigned is boxed\n          rhsTypeConstraint = e.Array.Type.NormalizeExpand().TypeArgs[0];\n        }\n        var bRhs = TrAssignmentRhs(rhss[i].Tok, bLhss[i], lhsType, rhss[i], rhsTypeConstraint, builder, locals, etran);\n        if (bLhss[i] != null) {\n          Contract.Assert(bRhs == bLhss[i]);  // this is what the postcondition of TrAssignmentRhs promises\n          // assignment has already been done by TrAssignmentRhs\n          finalRhss.Add(null);\n        } else {\n          Contract.Assert(bRhs != null);  // this is what the postcondition of TrAssignmentRhs promises\n          finalRhss.Add(bRhs);\n        }\n      }\n      for (int i = 0; i < lhss.Count; i++) {\n        lhsBuilder[i](finalRhss[i], rhss[i] is HavocRhs, builder, etran);\n      }\n    }\n\n    List<Bpl.Expr> ProcessUpdateAssignRhss(List<Expression> lhss, List<AssignmentRhs> rhss,\n      BoogieStmtListBuilder builder, List<Variable> locals, ExpressionTranslator etran) {\n      Contract.Requires(cce.NonNullElements(lhss));\n      Contract.Requires(cce.NonNullElements(rhss));\n      Contract.Requires(builder != null);\n      Contract.Requires(cce.NonNullElements(locals));\n      Contract.Requires(etran != null);\n      Contract.Requires(predef != null);\n      Contract.Ensures(Contract.ForAll(Contract.Result<List<Bpl.Expr>>(), i => i != null));\n\n      var finalRhss = new List<Bpl.Expr>();\n      for (int i = 0; i < lhss.Count; i++) {\n        var lhs = lhss[i];\n        // the following assumes are part of the precondition, really\n        Contract.Assume(!(lhs is ConcreteSyntaxExpression));\n        Contract.Assume(!(lhs is SeqSelectExpr && !((SeqSelectExpr)lhs).SelectOne));  // array-range assignments are not allowed\n\n        Type lhsType, rhsTypeConstraint;\n        if (lhs is IdentifierExpr) {\n          lhsType = ((IdentifierExpr)lhs).Var.Type;\n          rhsTypeConstraint = lhsType;\n        } else if (lhs is MemberSelectExpr) {\n          var fse = (MemberSelectExpr)lhs;\n          var field = (Field)fse.Member;\n          Contract.Assert(VisibleInScope(field));\n          lhsType = field.Type;\n          rhsTypeConstraint = Resolver.SubstType(lhsType, fse.TypeArgumentSubstitutions());\n        } else if (lhs is SeqSelectExpr) {\n          var e = (SeqSelectExpr)lhs;\n          lhsType = null;  // for an array update, always make sure the value assigned is boxed\n          rhsTypeConstraint = e.Seq.Type.TypeArgs[0];\n        } else {\n          var e = (MultiSelectExpr)lhs;\n          lhsType = null;  // for an array update, always make sure the value assigned is boxed\n          rhsTypeConstraint = e.Array.Type.TypeArgs[0];\n        }\n        var bRhs = TrAssignmentRhs(rhss[i].Tok, null, lhsType, rhss[i], rhsTypeConstraint, builder, locals, etran);\n        finalRhss.Add(bRhs);\n      }\n      return finalRhss;\n    }\n\n\n    private void CheckLhssDistinctness(List<Bpl.Expr> rhs, List<AssignmentRhs> rhsOriginal, List<Expression> lhss,\n      BoogieStmtListBuilder builder, ExpressionTranslator etran,\n      Bpl.Expr[] objs, Bpl.Expr[] fields, string[] names) {\n      Contract.Requires(rhs != null);\n      Contract.Requires(rhsOriginal != null);\n      Contract.Requires(lhss != null);\n      Contract.Requires(rhs.Count == rhsOriginal.Count);\n      Contract.Requires(lhss.Count == rhsOriginal.Count);\n      Contract.Requires(builder != null);\n      Contract.Requires(etran != null);\n      Contract.Requires(predef != null);\n\n      for (int i = 0; i < lhss.Count; i++) {\n        var lhs = lhss[i];\n        Contract.Assume(!(lhs is ConcreteSyntaxExpression));\n        if (rhsOriginal[i] is HavocRhs) {\n          continue;\n        }\n        IToken tok = lhs.tok;\n\n        if (lhs is IdentifierExpr) {\n          for (int j = 0; j < i; j++) {\n            if (rhsOriginal[j] is HavocRhs) { continue; }\n            var prev = lhss[j] as IdentifierExpr;\n            if (prev != null && names[i] == names[j]) {\n              builder.Add(Assert(tok, Bpl.Expr.Imp(Bpl.Expr.True, Bpl.Expr.Eq(rhs[i], rhs[j])), string.Format(\"when left-hand sides {0} and {1} refer to the same location, they must be assigned the same value\", j, i)));\n            }\n          }\n        } else if (lhs is MemberSelectExpr) {\n          var fse = (MemberSelectExpr)lhs;\n          // check that this LHS is not the same as any previous LHSs\n          for (int j = 0; j < i; j++) {\n            if (rhsOriginal[j] is HavocRhs) { continue; }\n            var prev = lhss[j] as MemberSelectExpr;\n            var field = fse.Member as Field;\n            Contract.Assert(field != null);\n            var prevField = prev == null ? null : prev.Member as Field;\n            if (prev != null && prevField == field) {\n              builder.Add(Assert(tok, Bpl.Expr.Imp(Bpl.Expr.Eq(objs[j], objs[i]), Bpl.Expr.Eq(rhs[i], rhs[j])), string.Format(\"when left-hand sides {0} and {1} refer to the same location, they must be assigned the same value\", j, i)));\n            }\n          }\n        } else if (lhs is SeqSelectExpr) {\n          SeqSelectExpr sel = (SeqSelectExpr)lhs;\n          // check that this LHS is not the same as any previous LHSs\n          for (int j = 0; j < i; j++) {\n            if (rhsOriginal[j] is HavocRhs) { continue; }\n            var prev = lhss[j] as SeqSelectExpr;\n            if (prev != null) {\n              builder.Add(Assert(tok,\n                Bpl.Expr.Imp(Bpl.Expr.And(Bpl.Expr.Eq(objs[j], objs[i]), Bpl.Expr.Eq(fields[j], fields[i])), Bpl.Expr.Eq(rhs[i], rhs[j])),\n                string.Format(\"when left-hand sides {0} and {1} may refer to the same location, they must be assigned the same value\", j, i)));\n            }\n          }\n        } else {\n          MultiSelectExpr mse = (MultiSelectExpr)lhs;\n          // check that this LHS is not the same as any previous LHSs\n          for (int j = 0; j < i; j++) {\n            if (rhsOriginal[j] is HavocRhs) { continue; }\n            var prev = lhss[j] as MultiSelectExpr;\n            if (prev != null) {\n              builder.Add(Assert(tok,\n                Bpl.Expr.Imp(Bpl.Expr.And(Bpl.Expr.Eq(objs[j], objs[i]), Bpl.Expr.Eq(fields[j], fields[i])), Bpl.Expr.Eq(rhs[i], rhs[j])),\n                string.Format(\"when left-hand sides {0} and {1} refer to the same location, they must be assigned the same value\", j, i)));\n            }\n          }\n\n        }\n      }\n    }\n\n    /// <summary>\n    /// Note, if \"rhs\" is \"null\", then the assignment has already been done elsewhere. However, any other bookkeeping\n    /// is still done.\n    /// </summary>\n    delegate void AssignToLhs(Bpl.Expr/*?*/ rhs, bool origRhsIsHavoc, BoogieStmtListBuilder builder, ExpressionTranslator etran);\n\n    /// <summary>\n    /// Creates a list of protected Boogie LHSs for the given Dafny LHSs.  Along the way,\n    /// builds code that checks that the LHSs are well-defined,\n    /// and are allowed by the enclosing modifies clause.\n    /// Checks that they denote different locations iff checkDistinctness is true.\n    /// </summary>\n    void ProcessLhss(List<Expression> lhss, bool rhsCanAffectPreviouslyKnownExpressions, bool checkDistinctness,\n      BoogieStmtListBuilder builder, List<Variable> locals, ExpressionTranslator etran,\n      out List<AssignToLhs> lhsBuilders, out List<Bpl.IdentifierExpr/*may be null*/> bLhss,\n      out Bpl.Expr[] prevObj, out Bpl.Expr[] prevIndex, out string[] prevNames) {\n\n      Contract.Requires(cce.NonNullElements(lhss));\n      Contract.Requires(builder != null);\n      Contract.Requires(cce.NonNullElements(locals));\n      Contract.Requires(etran != null);\n      Contract.Requires(predef != null);\n      Contract.Ensures(Contract.ValueAtReturn(out lhsBuilders).Count == lhss.Count);\n      Contract.Ensures(Contract.ValueAtReturn(out lhsBuilders).Count == Contract.ValueAtReturn(out bLhss).Count);\n\n      rhsCanAffectPreviouslyKnownExpressions = rhsCanAffectPreviouslyKnownExpressions || lhss.Count != 1;\n\n      // for each Dafny LHS, build a protected Boogie LHS for the eventual assignment\n      lhsBuilders = new List<AssignToLhs>();\n      bLhss = new List<Bpl.IdentifierExpr>();\n      prevObj = new Bpl.Expr[lhss.Count];\n      prevIndex = new Bpl.Expr[lhss.Count];\n      prevNames = new string[lhss.Count];\n      int i = 0;\n\n      var lhsNameSet = new Dictionary<string, object>();\n\n      foreach (var lhs in lhss) {\n        Contract.Assume(!(lhs is ConcreteSyntaxExpression));\n        IToken tok = lhs.tok;\n        TrStmt_CheckWellformed(lhs, builder, locals, etran, true, true);\n\n        if (lhs is IdentifierExpr) {\n          var ie = (IdentifierExpr)lhs;\n          // Note, the resolver does not check for duplicate IdentifierExpr's in LHSs, so do it here.\n          if (checkDistinctness) {\n            for (int j = 0; j < i; j++) {\n              var prev = lhss[j] as IdentifierExpr;\n              if (prev != null && ie.Name == prev.Name) {\n                builder.Add(Assert(tok, Bpl.Expr.False, string.Format(\"left-hand sides {0} and {1} refer to the same location\", j, i)));\n              }\n            }\n          }\n          prevNames[i] = ie.Name;\n          var bLhs = (Bpl.IdentifierExpr)etran.TrExpr(lhs);  // TODO: is this cast always justified?\n          bLhss.Add(rhsCanAffectPreviouslyKnownExpressions ? null : bLhs);\n          lhsBuilders.Add(delegate(Bpl.Expr rhs, bool origRhsIsHavoc, BoogieStmtListBuilder bldr, ExpressionTranslator et) {\n            if (rhs != null) {\n              bldr.Add(Bpl.Cmd.SimpleAssign(tok, bLhs, rhs));\n            }\n            if (!origRhsIsHavoc) {\n              MarkDefiniteAssignmentTracker(ie, bldr);\n            }\n          });\n\n        } else if (lhs is MemberSelectExpr) {\n          var fse = (MemberSelectExpr)lhs;\n          var field = fse.Member as Field;\n          Contract.Assert(field != null);\n          Contract.Assert(VisibleInScope(field));\n\n          var useSurrogateLocal = inBodyInitContext && Expression.AsThis(fse.Obj) != null;\n\n          var obj = SaveInTemp(etran.TrExpr(fse.Obj), rhsCanAffectPreviouslyKnownExpressions,\n            \"$obj\" + i, predef.RefType, builder, locals);\n          prevObj[i] = obj;\n          if (!useSurrogateLocal) {\n            // check that the enclosing modifies clause allows this object to be written:  assert $_Frame[obj]);\n            builder.Add(Assert(tok, Bpl.Expr.SelectTok(tok, etran.TheFrame(tok), obj, GetField(fse)), \"assignment may update an object not in the enclosing context's modifies clause\"));\n          }\n\n          if (checkDistinctness) {\n            // check that this LHS is not the same as any previous LHSs\n            for (int j = 0; j < i; j++) {\n              var prev = lhss[j] as MemberSelectExpr;\n              var prevField = prev == null ? null : prev.Member as Field;\n              if (prevField != null && prevField == field) {\n                builder.Add(Assert(tok, Bpl.Expr.Neq(prevObj[j], obj), string.Format(\"left-hand sides {0} and {1} may refer to the same location\", j, i)));\n              }\n            }\n          }\n\n          if (useSurrogateLocal) {\n            var nm = SurrogateName(field);\n            var bLhs = new Bpl.IdentifierExpr(fse.tok, nm, TrType(field.Type));\n            bLhss.Add(rhsCanAffectPreviouslyKnownExpressions ? null : bLhs);\n            lhsBuilders.Add(delegate(Bpl.Expr rhs, bool origRhsIsHavoc, BoogieStmtListBuilder bldr, ExpressionTranslator et) {\n              if (rhs != null) {\n                bldr.Add(Bpl.Cmd.SimpleAssign(tok, bLhs, rhs));\n              }\n              if (!origRhsIsHavoc) {\n                MarkDefiniteAssignmentTracker(lhs.tok, nm, bldr);\n              }\n            });\n          } else {\n            bLhss.Add(null);\n            lhsBuilders.Add(delegate(Bpl.Expr rhs, bool origRhsIsHavoc, BoogieStmtListBuilder bldr, ExpressionTranslator et) {\n              if (rhs != null) {\n                var fseField = fse.Member as Field;\n                Contract.Assert(fseField != null);\n                Check_NewRestrictions(tok, obj, fseField, rhs, bldr, et);\n                var h = (Bpl.IdentifierExpr)et.HeapExpr;  // TODO: is this cast always justified?\n                Bpl.Cmd cmd = Bpl.Cmd.SimpleAssign(tok, h, ExpressionTranslator.UpdateHeap(tok, h, obj, new Bpl.IdentifierExpr(tok, GetField(fseField)), rhs));\n                bldr.Add(cmd);\n                // assume $IsGoodHeap($Heap);\n                bldr.Add(AssumeGoodHeap(tok, et));\n              }\n            });\n          }\n\n        } else if (lhs is SeqSelectExpr) {\n          SeqSelectExpr sel = (SeqSelectExpr)lhs;\n          Contract.Assert(sel.SelectOne);  // array-range assignments are not allowed\n          Contract.Assert(sel.Seq.Type != null && sel.Seq.Type.IsArrayType);\n          Contract.Assert(sel.E0 != null);\n          var obj = SaveInTemp(etran.TrExpr(sel.Seq), rhsCanAffectPreviouslyKnownExpressions,\n            \"$obj\" + i, predef.RefType, builder, locals);\n          var fieldName = SaveInTemp(FunctionCall(tok, BuiltinFunction.IndexField, null, etran.TrExpr(sel.E0)), rhsCanAffectPreviouslyKnownExpressions,\n            \"$index\" + i, predef.FieldName(tok, predef.BoxType), builder, locals);\n          prevObj[i] = obj;\n          prevIndex[i] = fieldName;\n          // check that the enclosing modifies clause allows this object to be written:  assert $_Frame[obj,index]);\n          builder.Add(Assert(tok, Bpl.Expr.SelectTok(tok, etran.TheFrame(tok), obj, fieldName), \"assignment may update an array element not in the enclosing context's modifies clause\"));\n\n          if (checkDistinctness) {\n            // check that this LHS is not the same as any previous LHSs\n            for (int j = 0; j < i; j++) {\n              var prev = lhss[j] as SeqSelectExpr;\n              if (prev != null) {\n                builder.Add(Assert(tok,\n                  Bpl.Expr.Or(Bpl.Expr.Neq(prevObj[j], obj), Bpl.Expr.Neq(prevIndex[j], fieldName)),\n                  string.Format(\"left-hand sides {0} and {1} may refer to the same location\", j, i)));\n              }\n            }\n          }\n          bLhss.Add(null);\n          lhsBuilders.Add(delegate(Bpl.Expr rhs, bool origRhsIsHavoc, BoogieStmtListBuilder bldr, ExpressionTranslator et) {\n            if (rhs != null) {\n              var h = (Bpl.IdentifierExpr)et.HeapExpr;  // TODO: is this cast always justified?\n              Bpl.Cmd cmd = Bpl.Cmd.SimpleAssign(tok, h, ExpressionTranslator.UpdateHeap(tok, h, obj, fieldName, rhs));\n              bldr.Add(cmd);\n              // assume $IsGoodHeap($Heap);\n              bldr.Add(AssumeGoodHeap(tok, et));\n            }\n          });\n\n        } else {\n          MultiSelectExpr mse = (MultiSelectExpr)lhs;\n          Contract.Assert(mse.Array.Type != null && mse.Array.Type.IsArrayType);\n\n          var obj = SaveInTemp(etran.TrExpr(mse.Array), rhsCanAffectPreviouslyKnownExpressions,\n            \"$obj\" + i, predef.RefType, builder, locals);\n          var fieldName = SaveInTemp(etran.GetArrayIndexFieldName(mse.tok, mse.Indices), rhsCanAffectPreviouslyKnownExpressions,\n            \"$index\" + i, predef.FieldName(mse.tok, predef.BoxType), builder, locals);\n          prevObj[i] = obj;\n          prevIndex[i] = fieldName;\n          builder.Add(Assert(tok, Bpl.Expr.SelectTok(tok, etran.TheFrame(tok), obj, fieldName), \"assignment may update an array element not in the enclosing context's modifies clause\"));\n\n          if (checkDistinctness) {\n            // check that this LHS is not the same as any previous LHSs\n            for (int j = 0; j < i; j++) {\n              var prev = lhss[j] as MultiSelectExpr;\n              if (prev != null) {\n                builder.Add(Assert(tok,\n                  Bpl.Expr.Or(Bpl.Expr.Neq(prevObj[j], obj), Bpl.Expr.Neq(prevIndex[j], fieldName)),\n                  string.Format(\"left-hand sides {0} and {1} may refer to the same location\", j, i)));\n              }\n            }\n          }\n          bLhss.Add(null);\n          lhsBuilders.Add(delegate(Bpl.Expr rhs, bool origRhsIsHavoc, BoogieStmtListBuilder bldr, ExpressionTranslator et) {\n            if (rhs != null) {\n              var h = (Bpl.IdentifierExpr)et.HeapExpr;  // TODO: is this cast always justified?\n              Bpl.Cmd cmd = Bpl.Cmd.SimpleAssign(tok, h, ExpressionTranslator.UpdateHeap(tok, h, obj, fieldName, rhs));\n              bldr.Add(cmd);\n              // assume $IsGoodHeap($Heap);\n              bldr.Add(AssumeGoodHeap(tok, etran));\n            }\n          });\n        }\n\n        i++;\n      }\n    }\n\n    /// <summary>\n    /// if \"bGivenLhs\" is non-null, generates an assignment of the translation of \"rhs\" to \"bGivenLhs\" and then returns \"bGivenLhs\".\n    /// If \"bGivenLhs\" is null, then this method will return an expression that in a stable way denotes the translation of \"rhs\";\n    /// this is achieved by creating a new temporary Boogie variable to hold the result and returning an expression that mentions\n    /// that new temporary variable.\n    ///\n    /// Before the assignment, the generated code will check that \"rhs\" obeys any subrange requirements entailed by \"rhsTypeConstraint\".\n    ///\n    /// The purpose of \"lhsType\" is to determine if the expression should be boxed before doing the assignment.  It is allowed to be null,\n    /// which indicates that the result should always be a box.  Note that \"lhsType\" may refer to a formal type parameter that is not in\n    /// scope; this is okay, since the purpose of \"lhsType\" is just to say whether or not the result should be boxed.\n    /// </summary>\n    Bpl.Expr TrAssignmentRhs(IToken tok, Bpl.IdentifierExpr bGivenLhs, Type lhsType, AssignmentRhs rhs, Type rhsTypeConstraint,\n                             BoogieStmtListBuilder builder, List<Variable> locals, ExpressionTranslator etran) {\n      Contract.Requires(tok != null);\n      Contract.Requires(rhs != null);\n      Contract.Requires(rhsTypeConstraint != null);\n      Contract.Requires(builder != null);\n      Contract.Requires(locals != null);\n      Contract.Requires(etran != null);\n      Contract.Requires(predef != null);\n      Contract.Ensures(Contract.Result<Bpl.Expr>() != null);\n      Contract.Ensures(bGivenLhs == null || Contract.Result<Bpl.Expr>() == bGivenLhs);\n\n      Bpl.IdentifierExpr bLhs;\n      if (bGivenLhs != null) {\n        bLhs = bGivenLhs;\n      } else {\n        Type localType = rhsTypeConstraint;  // this is a type that is appropriate for capturing the value of the RHS\n        var ty = TrType(localType);\n        var nm = CurrentIdGenerator.FreshId(\"$rhs#\");\n        Bpl.Expr wh = GetWhereClause(tok, new Bpl.IdentifierExpr(tok, nm, ty), localType, etran, NOALLOC);\n        var v = new Bpl.LocalVariable(tok, new Bpl.TypedIdent(tok, nm, ty, wh));\n        locals.Add(v);\n        bLhs = new Bpl.IdentifierExpr(tok, v);\n      }\n\n      if (rhs is ExprRhs) {\n        var e = (ExprRhs)rhs;\n\n        TrStmt_CheckWellformed(e.Expr, builder, locals, etran, true);\n\n        Bpl.Expr bRhs = etran.TrExpr(e.Expr);\n        CheckSubrange(tok, bRhs, e.Expr.Type, rhsTypeConstraint, builder);\n        if (bGivenLhs != null) {\n          Contract.Assert(bGivenLhs == bLhs);\n          // box the RHS, then do the assignment\n          var cmd = Bpl.Cmd.SimpleAssign(tok, bGivenLhs, CondApplyBox(tok, bRhs, e.Expr.Type, lhsType));\n          builder.Add(cmd);\n          return bGivenLhs;\n        } else {\n          // do the assignment, then box the result\n          var cmd = Bpl.Cmd.SimpleAssign(tok, bLhs, bRhs);\n          builder.Add(cmd);\n          return CondApplyBox(tok, bLhs, e.Expr.Type, lhsType);\n        }\n\n      } else if (rhs is HavocRhs) {\n        builder.Add(new Bpl.HavocCmd(tok, new List<Bpl.IdentifierExpr> { bLhs }));\n        return CondApplyBox(tok, bLhs, rhsTypeConstraint, lhsType);\n      } else {\n        // x := new Something\n        Contract.Assert(rhs is TypeRhs);  // otherwise, an unexpected AssignmentRhs\n        TypeRhs tRhs = (TypeRhs)rhs;\n\n        var callsConstructor = tRhs.InitCall != null && tRhs.InitCall.Method is Constructor;\n\n        if (tRhs.ArrayDimensions == null) {\n          Contract.Assert(tRhs.ElementInit == null && tRhs.InitDisplay == null);\n        } else {\n          int i = 0;\n          foreach (Expression dim in tRhs.ArrayDimensions) {\n            CheckWellformed(dim, new WFOptions(), locals, builder, etran);\n            builder.Add(Assert(dim.tok, Bpl.Expr.Le(Bpl.Expr.Literal(0), etran.TrExpr(dim)),\n              tRhs.ArrayDimensions.Count == 1 ? \"array size might be negative\" : string.Format(\"array size (dimension {0}) might be negative\", i)));\n            i++;\n          }\n          if (tRhs.ElementInit != null) {\n            CheckWellformed(tRhs.ElementInit, new WFOptions(), locals, builder, etran);\n          } else if (tRhs.InitDisplay != null) {\n            var dim = tRhs.ArrayDimensions[0];\n            builder.Add(Assert(dim.tok, Bpl.Expr.Eq(etran.TrExpr(dim), Bpl.Expr.Literal(tRhs.InitDisplay.Count)),\n              string.Format(\"given array size must agree with the number of expressions in the initializing display ({0})\", tRhs.InitDisplay.Count)));\n            foreach (var v in tRhs.InitDisplay) {\n              CheckWellformed(v, new WFOptions(), locals, builder, etran);\n            }\n          } else if (ArmadaOptions.O.DefiniteAssignmentLevel == 0) {\n            // cool\n          } else if (2 <= ArmadaOptions.O.DefiniteAssignmentLevel || !Compiler.InitializerIsKnown(tRhs.EType)) {\n            // this is allowed only if the array size is such that it has no elements\n            Bpl.Expr zeroSize = Bpl.Expr.False;\n            foreach (Expression dim in tRhs.ArrayDimensions) {\n              zeroSize = BplOr(zeroSize, Bpl.Expr.Eq(Bpl.Expr.Literal(0), etran.TrExpr(dim)));\n            }\n            builder.Add(Assert(tRhs.Tok, zeroSize,\n              string.Format(\"unless an initializer is provided for the array elements, a new array of '{0}' must have empty size\", tRhs.EType)));\n          }\n        }\n\n        Bpl.IdentifierExpr nw = GetNewVar_IdExpr(tok, locals);\n        if (!callsConstructor) {\n          SelectAllocateObject(tok, nw, tRhs.Type, true, builder, etran);\n          if (tRhs.ArrayDimensions != null) {\n            int i = 0;\n            foreach (Expression dim in tRhs.ArrayDimensions) {\n              // assume Array#Length($nw, i) == arraySize;\n              Bpl.Expr arrayLength = ArrayLength(tok, nw, tRhs.ArrayDimensions.Count, i);\n              builder.Add(TrAssumeCmd(tok, Bpl.Expr.Eq(arrayLength, etran.TrExpr(dim))));\n              i++;\n            }\n            if (tRhs.ElementInit != null) {\n              CheckElementInit(tok, true, tRhs.ArrayDimensions, tRhs.EType, tRhs.ElementInit, nw, builder, etran, new WFOptions());\n            } else if (tRhs.InitDisplay != null) {\n              int ii = 0;\n              foreach (var v in tRhs.InitDisplay) {\n                var EE_ii = etran.TrExpr(v);\n                // assert EE_ii satisfies any subset-type constraints;\n                CheckSubrange(v.tok, EE_ii, v.Type, tRhs.EType, builder);\n                // assume nw[ii] == EE_ii;\n                var ai = ReadHeap(tok, etran.HeapExpr, nw, GetArrayIndexFieldName(tok, new List<Bpl.Expr> { Bpl.Expr.Literal(ii) }));\n                builder.Add(new Bpl.AssumeCmd(tok, Bpl.Expr.Eq(UnboxIfBoxed(ai, tRhs.EType), EE_ii)));\n                ii++;\n              }\n            }\n          }\n          Bpl.Cmd heapAllocationRecorder = null;\n          if (codeContext is IteratorDecl) {\n            var iter = (IteratorDecl)codeContext;\n            // $Heap[this, _new] := Set#UnionOne<BoxType>($Heap[this, _new], $Box($nw));\n            var th = new Bpl.IdentifierExpr(tok, etran.This, predef.RefType);\n            var nwField = new Bpl.IdentifierExpr(tok, GetField(iter.Member_New));\n            var thisDotNew = ReadHeap(tok, etran.HeapExpr, th, nwField);\n            var unionOne = FunctionCall(tok, BuiltinFunction.SetUnionOne, predef.BoxType, thisDotNew, FunctionCall(tok, BuiltinFunction.Box, null, nw));\n            var heapRhs = ExpressionTranslator.UpdateHeap(tok, etran.HeapExpr, th, nwField, unionOne);\n            heapAllocationRecorder = Bpl.Cmd.SimpleAssign(tok, (Bpl.IdentifierExpr/*TODO: this cast is dubious*/)etran.HeapExpr, heapRhs);\n          }\n          CommitAllocatedObject(tok, nw, heapAllocationRecorder, builder, etran);\n        }\n        if (tRhs.InitCall != null) {\n          AddComment(builder, tRhs.InitCall, \"init call statement\");\n          TrCallStmt(tRhs.InitCall, builder, locals, etran, nw);\n        }\n        // bLhs := $nw;\n        CheckSubrange(tok, nw, tRhs.Type, rhsTypeConstraint, builder);\n        if (bGivenLhs != null) {\n          Contract.Assert(bGivenLhs == bLhs);\n          // box the RHS, then do the assignment\n          builder.Add(Bpl.Cmd.SimpleAssign(tok, bGivenLhs, CondApplyBox(tok, nw, tRhs.Type, lhsType)));\n          return bGivenLhs;\n        } else {\n          // do the assignment, then box the result\n          builder.Add(Bpl.Cmd.SimpleAssign(tok, bLhs, nw));\n          return CondApplyBox(tok, bLhs, tRhs.Type, lhsType);\n        }\n      }\n    }\n\n    /// <summary>\n    /// Check that all indices are in the domain of the given function.  That is, for an array (\"forArray\"):\n    ///     assert (forall i0,i1,i2,... :: 0 <= i0 < dims[0] && ... ==> init.requires(i0,i1,i2,...));\n    /// and for a sequence (\"!forArray\"):\n    ///     assert (forall i0 :: 0 <= i0 < dims[0] && ... ==> init.requires(i0));\n    /// </summary>\n    private void CheckElementInit(IToken tok, bool forArray, List<Expression> dims, Type elementType, Expression init,\n      Bpl.IdentifierExpr/*?*/ nw, BoogieStmtListBuilder builder, ExpressionTranslator etran, WFOptions options) {\n      Contract.Requires(tok != null);\n      Contract.Requires(dims != null && dims.Count != 0);\n      Contract.Requires(elementType != null);\n      Contract.Requires(init != null);\n      Contract.Requires(!forArray || nw != null);\n      Contract.Requires(builder != null);\n      Contract.Requires(etran != null);\n\n      Bpl.Expr ante = Bpl.Expr.True;\n      var varNameGen = CurrentIdGenerator.NestedFreshIdGenerator(forArray ? \"arrayinit#\" : \"seqinit#\");\n      var bvs = new List<Bpl.Variable>();\n      var indices = new List<Bpl.Expr>();\n      for (var i = 0; i < dims.Count; i++) {\n        var nm = varNameGen.FreshId(string.Format(\"#i{0}#\", i));\n        var bv = new Bpl.BoundVariable(tok, new Bpl.TypedIdent(tok, nm, Bpl.Type.Int));\n        bvs.Add(bv);\n        var ie = new Bpl.IdentifierExpr(tok, bv);\n        indices.Add(ie);\n        ante = BplAnd(ante, BplAnd(Bpl.Expr.Le(Bpl.Expr.Literal(0), ie), Bpl.Expr.Lt(ie, etran.TrExpr(dims[i]))));\n      }\n\n      var sourceType = init.Type.AsArrowType;\n      Contract.Assert(sourceType.Args.Count == dims.Count);\n      var args = Concat(\n        Map(Enumerable.Range(0, dims.Count), ii => TypeToTy(sourceType.Args[ii])),\n        Cons(TypeToTy(sourceType.Result),\n          Cons(etran.HeapExpr,\n            Cons(etran.TrExpr(init),\n              indices.ConvertAll(idx => (Bpl.Expr) FunctionCall(tok, BuiltinFunction.Box, null, idx))))));\n      // check precond\n      var pre = FunctionCall(tok, Requires(dims.Count), Bpl.Type.Bool, args);\n      var q = new Bpl.ForallExpr(tok, bvs, Bpl.Expr.Imp(ante, pre));\n      builder.Add(AssertNS(tok, q, string.Format(\"all {0} indices must be in the domain of the initialization function\", forArray ? \"array\" : \"sequence\")));\n      if (!forArray && options.DoReadsChecks) {\n        // check read effects\n        Type objset = new SetType(true, program.BuiltIns.ObjectQ());\n        Expression wrap = new BoogieWrapper(\n          FunctionCall(tok, Reads(1), TrType(objset), args),\n          objset);\n        var reads = new FrameExpression(tok, wrap, null);\n        Action<IToken, Bpl.Expr, string, Bpl.QKeyValue> maker = (t, e, s, qk) => {\n          var qe = new Bpl.ForallExpr(t, bvs, Bpl.Expr.Imp(ante, e));\n          options.AssertSink(this, builder)(t, qe, s, qk);\n        };\n        CheckFrameSubset(tok, new List<FrameExpression> { reads }, null, null,\n          etran, maker,\n          \"insufficient reads clause to invoke the function passed as an argument to the sequence constructor\",\n          options.AssertKv);\n      }\n      // Check that the values coming out of the function satisfy any appropriate subset-type constraints\n      var apply = UnboxIfBoxed(FunctionCall(tok, Apply(dims.Count), TrType(elementType), args), elementType);\n      string msg;\n      var cre = GetSubrangeCheck(apply, sourceType.Result, elementType, out msg);\n      if (cre != null) {\n        // assert (forall i0,i1,i2,... ::\n        //            0 <= i0 < ... && ... ==> init.requires(i0,i1,i2,...) is Subtype);\n        q = new Bpl.ForallExpr(tok, bvs, Bpl.Expr.Imp(ante, cre));\n        builder.Add(AssertNS(init.tok, q, msg));\n      }\n\n      if (forArray) {\n        // Assume that array elements have initial values according to the given initialization function.  That is:\n        // assume (forall i0,i1,i2,... :: { nw[i0,i1,i2,...] }\n        //            0 <= i0 < ... && ... ==> nw[i0,i1,i2,...] == init.requires(i0,i1,i2,...));\n        var ai = ReadHeap(tok, etran.HeapExpr, nw, GetArrayIndexFieldName(tok, indices));\n        var ai_prime = UnboxIfBoxed(ai, elementType);\n        var tr = new Bpl.Trigger(tok, true, new List<Bpl.Expr> {ai});\n        q = new Bpl.ForallExpr(tok, bvs, tr,\n          Bpl.Expr.Imp(ante, Bpl.Expr.Eq(ai_prime, apply))); // TODO: use a more general Equality translation\n        builder.Add(new Bpl.AssumeCmd(tok, q));\n      }\n    }\n\n    private void SelectAllocateObject(IToken tok, Bpl.IdentifierExpr nw, Type type, bool includeHavoc, BoogieStmtListBuilder builder, ExpressionTranslator etran) {\n      Contract.Requires(tok != null);\n      Contract.Requires(nw != null);\n      Contract.Requires(type != null);\n      Contract.Requires(builder != null);\n      Contract.Requires(etran != null);\n      var udt = type as UserDefinedType;\n      if (udt != null && udt.ResolvedClass is NonNullTypeDecl) {\n        var nnt = (NonNullTypeDecl)udt.ResolvedClass;\n        type = nnt.RhsWithArgument(type.TypeArgs);\n      }\n      if (includeHavoc) {\n        // havoc $nw;\n        builder.Add(new Bpl.HavocCmd(tok, new List<Bpl.IdentifierExpr> { nw }));\n        // assume $nw != null && dtype($nw) == RHS;\n        var nwNotNull = Bpl.Expr.Neq(nw, predef.Null);\n        var rightType = DType(nw, TypeToTy(type));\n        builder.Add(TrAssumeCmd(tok, Bpl.Expr.And(nwNotNull, rightType)));\n      }\n      // assume !$Heap[$nw, alloc];\n      var notAlloc = Bpl.Expr.Not(etran.IsAlloced(tok, nw));\n      builder.Add(TrAssumeCmd(tok, notAlloc));\n    }\n\n    private void CommitAllocatedObject(IToken tok, Bpl.IdentifierExpr nw, Bpl.Cmd extraCmd, BoogieStmtListBuilder builder, ExpressionTranslator etran) {\n      Contract.Requires(tok != null);\n      Contract.Requires(nw != null);\n      Contract.Requires(builder != null);\n      Contract.Requires(etran != null);\n\n      // $Heap[$nw, alloc] := true;\n      Bpl.Expr alloc = predef.Alloc(tok);\n      Bpl.IdentifierExpr heap = (Bpl.IdentifierExpr/*TODO: this cast is dubious*/)etran.HeapExpr;\n      Bpl.Cmd cmd = Bpl.Cmd.SimpleAssign(tok, heap, ExpressionTranslator.UpdateHeap(tok, heap, nw, alloc, Bpl.Expr.True));\n      builder.Add(cmd);\n      if (extraCmd != null) {\n        builder.Add(extraCmd);\n      }\n      // assume $IsGoodHeap($Heap);\n      builder.Add(AssumeGoodHeap(tok, etran));\n      // assume $IsHeapAnchor($Heap);\n      builder.Add(new Bpl.AssumeCmd(tok, FunctionCall(tok, BuiltinFunction.IsHeapAnchor, null, etran.HeapExpr)));\n    }\n\n    /// <summary>\n    /// Returns the name of the local variable used as a stand-in for a field in the BodyInit part of a divided\n    /// constructor body.\n    /// </summary>\n    string SurrogateName(Field field) {\n      Contract.Requires(field != null);\n      return \"this.\" + field.Name;\n    }\n\n    Bpl.Expr GetSubrangeCheck(Bpl.Expr bSource, Type sourceType, Type targetType, out string msg) {\n      Contract.Requires(bSource != null);\n      Contract.Requires(sourceType != null);\n      Contract.Requires(targetType != null);\n\n      if (Type.IsSupertype(targetType, sourceType)) {\n        // We should always be able to use Is, but this is an optimisation.\n        msg = null;\n        return null;\n      }\n      targetType = targetType.NormalizeExpandKeepConstraints();\n      var cre = MkIs(bSource, targetType);\n      var udt = targetType as UserDefinedType;\n      if (udt != null && udt.ResolvedClass is NonNullTypeDecl) {\n        var certain = udt.ResolvedClass.TypeArgs.Count == 0;\n        msg = string.Format(\"value does not satisfy the subset constraints of '{0}' ({1}it may be null)\", targetType.Normalize(), certain ? \"\" : \"possible cause: \");\n      } else if (udt != null && ArrowType.IsTotalArrowTypeName(udt.Name)) {\n        msg = string.Format(\"value does not satisfy the subset constraints of '{0}' (possible cause: it may be partial or have read effects)\", targetType.Normalize());\n      } else if (udt != null && ArrowType.IsPartialArrowTypeName(udt.Name)) {\n        msg = string.Format(\"value does not satisfy the subset constraints of '{0}' (possible cause: it may have read effects)\", targetType.Normalize());\n      } else {\n        msg = string.Format(\"value does not satisfy the subset constraints of '{0}'\", targetType.Normalize());\n      }\n      return cre;\n    }\n\n    void CheckSubrange(IToken tok, Bpl.Expr bSource, Type sourceType, Type targetType, BoogieStmtListBuilder builder) {\n      Contract.Requires(tok != null);\n      Contract.Requires(bSource != null);\n      Contract.Requires(sourceType != null);\n      Contract.Requires(targetType != null);\n      Contract.Requires(builder != null);\n\n      string msg;\n      var cre = GetSubrangeCheck(bSource, sourceType, targetType, out msg);\n      if (cre != null) {\n        builder.Add(Assert(tok, cre, msg));\n      }\n    }\n\n    void Check_NewRestrictions(IToken tok, Bpl.Expr obj, Field f, Bpl.Expr rhs, BoogieStmtListBuilder builder, ExpressionTranslator etran) {\n      Contract.Requires(tok != null);\n      Contract.Requires(obj != null);\n      Contract.Requires(f != null);\n      Contract.Requires(rhs != null);\n      Contract.Requires(builder != null);\n      Contract.Requires(etran != null);\n      var iter = f.EnclosingClass as IteratorDecl;\n      if (iter != null && f == iter.Member_New) {\n        // Assignments to an iterator _new field is only allowed to shrink the set, so:\n        // assert Set#Subset(rhs, obj._new);\n        var fId = new Bpl.IdentifierExpr(tok, GetField(f));\n        var subset = FunctionCall(tok, BuiltinFunction.SetSubset, null, rhs, ReadHeap(tok, etran.HeapExpr, obj, fId));\n        builder.Add(Assert(tok, subset, \"an assignment to \" + f.Name + \" is only allowed to shrink the set\"));\n      }\n    }\n\n    Bpl.AssumeCmd AssumeGoodHeap(IToken tok, ExpressionTranslator etran) {\n      Contract.Requires(tok != null);\n      Contract.Requires(etran != null);\n      Contract.Ensures(Contract.Result<AssumeCmd>() != null);\n\n      return TrAssumeCmd(tok, FunctionCall(tok, BuiltinFunction.IsGoodHeap, null, etran.HeapExpr));\n    }\n\n    /// <summary>\n    /// Idempotently fills in \"mc.ProjectionFunctions\"\n    /// </summary>\n    void CreateMapComprehensionProjectionFunctions(MapComprehension mc) {\n      Contract.Requires(mc != null && mc.TermLeft != null);\n      if (mc.ProjectionFunctions == null) {\n        var varNameGen = CurrentIdGenerator.NestedFreshIdGenerator(string.Format(\"map$project${0}#\", projectionFunctionCount));\n        projectionFunctionCount++;\n        mc.ProjectionFunctions = new List<Bpl.Function>();\n        foreach (var bv in mc.BoundVars) {\n          var arg = BplFormalVar(null, TrType(mc.TermLeft.Type), false);\n          var res = BplFormalVar(null, TrType(bv.Type), true);\n          var projectFn = new Bpl.Function(mc.tok, varNameGen.FreshId(string.Format(\"#{0}#\", bv.Name)), new List<Variable>() { arg }, res);\n          mc.ProjectionFunctions.Add(projectFn);\n          sink.AddTopLevelDeclaration(projectFn);\n        }\n      }\n    }\n\n    int projectionFunctionCount = 0;\n\n    /// <summary>\n    /// Fills in, if necessary, the e.translationDesugaring field, and returns it.\n    /// Also, makes sure that letSuchThatExprInfo maps e to something.\n    /// </summary>\n    Expression LetDesugaring(LetExpr e) {\n      Contract.Requires(e != null);\n      Contract.Requires(!e.Exact);\n      Contract.Ensures(Contract.Result<Expression>() != null);\n      if (e.getTranslationDesugaring(this) == null) {\n        // For let-such-that expression:\n        //   var x:X, y:Y :| P(x,y,g); F(...)\n        // where g has type G, declare a function for each bound variable:\n        //   function $let$x(G): X;\n        //   function $let$y(G): Y;\n        //   function $let_canCall(G): bool;\n        // and add an axiom about these functions:\n        //   axiom (forall g:G ::\n        //            { $let$x(g) }\n        //            { $let$y(g) }\n        //            $let$_canCall(g)) ==>\n        //            P($let$x(g), $let$y(g), g));\n        // and create the desugaring:\n        //   var x:X, y:Y := $let$x(g), $let$y(g); F(...)\n        if (e is SubstLetExpr) {\n          // desugar based on the original letexpr.\n          var expr = (SubstLetExpr)e;\n          var orgExpr = expr.orgExpr;\n          Expression d = LetDesugaring(orgExpr);\n          e.setTranslationDesugaring(this, Substitute(d, null, expr.substMap, expr.typeMap));\n          var orgInfo = letSuchThatExprInfo[orgExpr];\n          letSuchThatExprInfo.Add(expr, new LetSuchThatExprInfo(orgInfo, this, expr.substMap, expr.typeMap));\n        } else {\n          // First, determine \"g\" as a list of Dafny variables FVs plus possibly this, $Heap, and old($Heap)\n          LetSuchThatExprInfo info;\n          {\n            var FVs = new HashSet<IVariable>();\n            bool usesHeap = false, usesOldHeap = false;\n            var FVsHeapAt = new HashSet<Label>();\n            Type usesThis = null;\n            ComputeFreeVariables(e.RHSs[0], FVs, ref usesHeap, ref usesOldHeap, FVsHeapAt, ref usesThis);\n            foreach (var bv in e.BoundVars) {\n              FVs.Remove(bv);\n            }\n            var FTVs = new HashSet<TypeParameter>();\n            ComputeFreeTypeVariables(e.RHSs[0], FTVs);\n            info = new LetSuchThatExprInfo(e.tok, letSuchThatExprInfo.Count, FVs.ToList(), FTVs.ToList(), usesHeap, usesOldHeap, FVsHeapAt, usesThis, currentDeclaration);\n            letSuchThatExprInfo.Add(e, info);\n          }\n\n          foreach (var bv in e.BoundVars) {\n            Bpl.Variable resType = new Bpl.Formal(bv.tok, new Bpl.TypedIdent(bv.tok, Bpl.TypedIdent.NoName, TrType(bv.Type)), false);\n            Bpl.Expr ante;\n            List<Variable> formals = info.GAsVars(this, true, out ante, null);\n            var fn = new Bpl.Function(bv.tok, info.SkolemFunctionName(bv), formals, resType);\n\n            if (InsertChecksums) {\n              InsertChecksum(e.Body, fn);\n            }\n\n            sink.AddTopLevelDeclaration(fn);\n          }\n          // add canCall function\n          {\n            Bpl.Variable resType = new Bpl.Formal(e.tok, new Bpl.TypedIdent(e.tok, Bpl.TypedIdent.NoName, Bpl.Type.Bool), false);\n            Bpl.Expr ante;\n            List<Variable> formals = info.GAsVars(this, true, out ante, null);\n            var fn = new Bpl.Function(e.tok, info.CanCallFunctionName(), formals, resType);\n\n            if (InsertChecksums) {\n              InsertChecksum(e.Body, fn);\n            }\n\n            sink.AddTopLevelDeclaration(fn);\n          }\n\n          {\n            var etranCC = new ExpressionTranslator(this, predef, info.HeapExpr(this, false), info.HeapExpr(this, true));\n            Bpl.Expr typeAntecedents;  // later ignored\n            List<Variable> gg = info.GAsVars(this, false, out typeAntecedents, etranCC);\n            var gExprs = new List<Bpl.Expr>();\n            foreach (Bpl.Variable g in gg) {\n              gExprs.Add(new Bpl.IdentifierExpr(g.tok, g));\n            }\n            Bpl.Trigger tr = null;\n            Dictionary<IVariable, Expression> substMap = new Dictionary<IVariable, Expression>();\n            Bpl.Expr antecedent = Bpl.Expr.True;\n            foreach (var bv in e.BoundVars) {\n              // create a call to $let$x(g)\n              var call = FunctionCall(e.tok, info.SkolemFunctionName(bv), TrType(bv.Type), gExprs);\n              tr = new Bpl.Trigger(e.tok, true, new List<Bpl.Expr> { call }, tr);\n              substMap.Add(bv, new BoogieWrapper(call, bv.Type));\n              if (!(bv.Type.IsTypeParameter)) {\n                Bpl.Expr wh = GetWhereClause(bv.tok, call, bv.Type, etranCC, NOALLOC);\n                if (wh != null) {\n                  antecedent = BplAnd(antecedent, wh);\n                }\n              }\n            }\n            var i = info.FTVs.Count + (info.UsesHeap ? 1 : 0) + (info.UsesOldHeap ? 1 : 0) + info.UsesHeapAt.Count;\n            Expression receiverReplacement;\n            if (info.ThisType == null) {\n              receiverReplacement = null;\n            } else {\n              receiverReplacement = new BoogieWrapper(gExprs[i], info.ThisType);\n              i++;\n            }\n            foreach (var fv in info.FVs) {\n              var ge = gExprs[i];\n              substMap.Add(fv, new BoogieWrapper(ge, fv.Type));\n              i++;\n            }\n            var canCall = FunctionCall(e.tok, info.CanCallFunctionName(), Bpl.Type.Bool, gExprs);\n            var p = Substitute(e.RHSs[0], receiverReplacement, substMap);\n            Bpl.Expr ax = Bpl.Expr.Imp(canCall, BplAnd(antecedent, etranCC.TrExpr(p)));\n            ax = BplForall(gg, tr, ax);\n            sink.AddTopLevelDeclaration(new Bpl.Axiom(e.tok, ax));\n          }\n\n          // now that we've declared the functions and axioms, let's prepare the let-such-that desugaring\n          {\n            var etran = new ExpressionTranslator(this, predef, e.tok);\n            var rhss = new List<Expression>();\n            foreach (var bv in e.BoundVars) {\n              var args = info.SkolemFunctionArgs(bv, this, etran);\n              var rhs = new BoogieFunctionCall(bv.tok, info.SkolemFunctionName(bv), info.UsesHeap, info.UsesOldHeap, info.UsesHeapAt, args.Item1, args.Item2);\n              rhs.Type = bv.Type;\n              rhss.Add(rhs);\n            }\n            var expr = new LetExpr(e.tok, e.LHSs, rhss, e.Body, true);\n            expr.Type = e.Type; // resolve here\n            e.setTranslationDesugaring(this, expr);\n          }\n        }\n      }\n      return e.getTranslationDesugaring(this);\n    }\n\n    class LetSuchThatExprInfo\n    {\n      public readonly IToken Tok;\n      public readonly int LetId;\n      public readonly List<IVariable> FVs;\n      public readonly List<Expression> FV_Exprs;  // these are what initially were the free variables, but they may have undergone substitution so they are here Expression's.\n      public readonly List<TypeParameter> FTVs;\n      public readonly List<Type> FTV_Types;\n      public readonly bool UsesHeap;\n      public readonly bool UsesOldHeap;\n      public readonly List<Label> UsesHeapAt;\n      public readonly Type ThisType;  // null if 'this' is not used\n      public LetSuchThatExprInfo(IToken tok, int uniqueLetId,\n      List<IVariable> freeVariables, List<TypeParameter> freeTypeVars,\n      bool usesHeap, bool usesOldHeap, ISet<Label> usesHeapAt, Type thisType, Declaration currentDeclaration) {\n        Tok = tok;\n        LetId = uniqueLetId;\n        FTVs = freeTypeVars;\n        FTV_Types = Map(freeTypeVars, tt => (Type)new UserDefinedType(tt));\n        FVs = freeVariables;\n        FV_Exprs = new List<Expression>();\n        foreach (var v in FVs) {\n          var idExpr = new IdentifierExpr(v.Tok, v.AssignUniqueName(currentDeclaration.IdGenerator));\n          idExpr.Var = v; idExpr.Type = v.Type;  // resolve here\n          FV_Exprs.Add(idExpr);\n        }\n        UsesHeap = usesHeap;\n        UsesOldHeap = usesOldHeap;\n        // we convert the set of heap-at variables to a list here, once and for all; the order itself is not material, what matters is that we always use the same order\n        UsesHeapAt = new List<Label>(usesHeapAt);\n        ThisType = thisType;\n      }\n      public LetSuchThatExprInfo(LetSuchThatExprInfo template, Translator translator,\n           Dictionary<IVariable, Expression> substMap,\n           Dictionary<TypeParameter, Type> typeMap) {\n        Contract.Requires(template != null);\n        Contract.Requires(translator != null);\n        Contract.Requires(substMap != null);\n        Tok = template.Tok;\n        LetId = template.LetId;  // reuse the ID, which ensures we get the same $let functions\n        FTVs = template.FTVs;\n        FTV_Types = template.FTV_Types.ConvertAll(t => Resolver.SubstType(t, typeMap));\n        FVs = template.FVs;\n        FV_Exprs = template.FV_Exprs.ConvertAll(e => Translator.Substitute(e, null, substMap, typeMap));\n        UsesHeap = template.UsesHeap;\n        UsesOldHeap = template.UsesOldHeap;\n        UsesHeapAt = template.UsesHeapAt;\n        ThisType = template.ThisType;\n      }\n      public Tuple<List<Expression>, List<Type>> SkolemFunctionArgs(BoundVar bv, Translator translator, ExpressionTranslator etran) {\n        Contract.Requires(bv != null);\n        Contract.Requires(translator != null);\n        Contract.Requires(etran != null);\n        var args = new List<Expression>();\n        if (ThisType != null) {\n          var th = new ThisExpr(bv.tok);\n          th.Type = ThisType;\n          args.Add(th);\n        }\n        args.AddRange(FV_Exprs);\n        return Tuple.Create(args, new List<Type>(FTV_Types));\n      }\n      public string SkolemFunctionName(BoundVar bv) {\n        Contract.Requires(bv != null);\n        return string.Format(\"$let#{0}_{1}\", LetId, bv.Name);\n      }\n      public Bpl.Expr CanCallFunctionCall(Translator translator, ExpressionTranslator etran) {\n        Contract.Requires(translator != null);\n        Contract.Requires(etran != null);\n        var gExprs = new List<Bpl.Expr>();\n        gExprs.AddRange(Map(FTV_Types, tt => translator.TypeToTy(tt)));\n        if (UsesHeap) {\n          gExprs.Add(etran.HeapExpr);\n        }\n        if (UsesOldHeap) {\n          gExprs.Add(etran.Old.HeapExpr);\n        }\n        foreach (var heapAtLabel in UsesHeapAt) {\n          Bpl.Expr ve;\n          var bv = BplBoundVar(\"$Heap_at_\" + heapAtLabel.AssignUniqueId(translator.CurrentIdGenerator), translator.predef.HeapType, out ve);\n          gExprs.Add(ve);\n        }\n        if (ThisType != null) {\n          var th = new Bpl.IdentifierExpr(Tok, etran.This);\n          gExprs.Add(th);\n        }\n        foreach (var v in FV_Exprs) {\n          gExprs.Add(etran.TrExpr(v));\n        }\n        return translator.FunctionCall(Tok, CanCallFunctionName(), Bpl.Type.Bool, gExprs);\n      }\n      public string CanCallFunctionName() {\n        return string.Format(\"$let#{0}$canCall\", LetId);\n      }\n      public Bpl.Expr HeapExpr(Translator translator, bool old) {\n        Contract.Requires(translator != null);\n        return new Bpl.IdentifierExpr(Tok, old ? \"$heap$old\" : \"$heap\", translator.predef.HeapType);\n      }\n      /// <summary>\n      /// \"wantFormals\" means the returned list will consist of all in-parameters.\n      /// \"!wantFormals\" means the returned list will consist of all bound variables.\n      /// Guarantees that, in the list returned, \"this\" is the parameter immediately following\n      /// the (0, 1, or 2) heap arguments, if there is a \"this\" parameter at all.\n      /// Note, \"typeAntecedents\" is meaningfully filled only if \"etran\" is not null.\n      /// </summary>\n      public List<Variable> GAsVars(Translator translator, bool wantFormals, out Bpl.Expr typeAntecedents, ExpressionTranslator etran) {\n        Contract.Requires(translator != null);\n        var vv = new List<Variable>();\n        // first, add the type variables\n        vv.AddRange(Map(FTVs, tp => NewVar(nameTypeParam(tp), translator.predef.Ty, wantFormals)));\n        typeAntecedents = Bpl.Expr.True;\n        if (UsesHeap) {\n          var nv = NewVar(\"$heap\", translator.predef.HeapType, wantFormals);\n          vv.Add(nv);\n          if (etran != null) {\n            var isGoodHeap = translator.FunctionCall(Tok, BuiltinFunction.IsGoodHeap, null, new Bpl.IdentifierExpr(Tok, nv));\n            typeAntecedents = BplAnd(typeAntecedents, isGoodHeap);\n          }\n        }\n        if (UsesOldHeap) {\n          var nv = NewVar(\"$heap$old\", translator.predef.HeapType, wantFormals);\n          vv.Add(nv);\n          if (etran != null) {\n            var isGoodHeap = translator.FunctionCall(Tok, BuiltinFunction.IsGoodHeap, null, new Bpl.IdentifierExpr(Tok, nv));\n            typeAntecedents = BplAnd(typeAntecedents, isGoodHeap);\n          }\n        }\n        foreach (var heapAtLabel in UsesHeapAt) {\n          var nv = NewVar(\"$Heap_at_\" + heapAtLabel.AssignUniqueId(translator.CurrentIdGenerator), translator.predef.HeapType, wantFormals);\n          vv.Add(nv);\n          if (etran != null) {\n            // TODO: It's not clear to me that $IsGoodHeap predicates are needed for these axioms. (Same comment applies above for $heap$old.)\n            // But $HeapSucc relations among the various heap variables appears not needed for either soundness or completeness, since the\n            // let-such-that functions will always be invoked on arguments for which these properties are known.\n            var isGoodHeap = translator.FunctionCall(Tok, BuiltinFunction.IsGoodHeap, null, new Bpl.IdentifierExpr(Tok, nv));\n            typeAntecedents = BplAnd(typeAntecedents, isGoodHeap);\n          }\n        }\n        if (ThisType != null) {\n          var nv = NewVar(\"this\", translator.TrType(ThisType), wantFormals);\n          vv.Add(nv);\n          if (etran != null) {\n            var th = new Bpl.IdentifierExpr(Tok, nv);\n            typeAntecedents = BplAnd(typeAntecedents, translator.ReceiverNotNull(th));\n            var wh = translator.GetWhereClause(Tok, th, ThisType, etran, NOALLOC);\n            if (wh != null) {\n              typeAntecedents = BplAnd(typeAntecedents, wh);\n            }\n          }\n        }\n        foreach (var v in FVs) {\n          var nv = NewVar(v.Name, translator.TrType(v.Type), wantFormals);\n          vv.Add(nv);\n          if (etran != null) {\n            var wh = translator.GetWhereClause(Tok, new Bpl.IdentifierExpr(Tok, nv), v.Type, etran, NOALLOC);\n            if (wh != null) {\n              typeAntecedents = BplAnd(typeAntecedents, wh);\n            }\n          }\n        }\n        return vv;\n      }\n      Bpl.Variable NewVar(string name, Bpl.Type type, bool wantFormal) {\n        Contract.Requires(name != null);\n        Contract.Requires(type != null);\n        if (wantFormal) {\n          return new Bpl.Formal(Tok, new Bpl.TypedIdent(Tok, name, type), true);\n        } else {\n          return new Bpl.BoundVariable(Tok, new Bpl.TypedIdent(Tok, name, type));\n        }\n      }\n    }\n    Dictionary<LetExpr, LetSuchThatExprInfo> letSuchThatExprInfo = new Dictionary<LetExpr, LetSuchThatExprInfo>();\n    private Declaration currentDeclaration;\n\n    // ----- Expression ---------------------------------------------------------------------------\n\n    /// <summary>\n    /// This class gives a way to represent a Boogie translation target as if it were still a Dafny expression.\n    /// </summary>\n    internal class BoogieWrapper : Expression\n    {\n      public readonly Bpl.Expr Expr;\n      public BoogieWrapper(Bpl.Expr expr, Type dafnyType)\n        : base(expr.tok)\n      {\n        Contract.Requires(expr != null);\n        Contract.Requires(dafnyType != null);\n        Expr = expr;\n        Type = dafnyType;  // resolve immediately\n      }\n    }\n\n    internal class BoogieFunctionCall : Expression\n    {\n      public readonly string FunctionName;\n      public readonly bool UsesHeap;\n      public readonly bool UsesOldHeap;\n      public readonly List<Label> HeapAtLabels;\n      public readonly List<Type> TyArgs; // Note: also has a bunch of type arguments\n      public readonly List<Expression> Args;\n      public BoogieFunctionCall(IToken tok, string functionName, bool usesHeap, bool usesOldHeap, List<Label> heapAtLabels, List<Expression> args, List<Type> tyArgs)\n        : base(tok)\n      {\n        Contract.Requires(tok != null);\n        Contract.Requires(functionName != null);\n        Contract.Requires(heapAtLabels != null);\n        Contract.Requires(args != null);\n        FunctionName = functionName;\n        UsesHeap = usesHeap;\n        UsesOldHeap = usesOldHeap;\n        HeapAtLabels = heapAtLabels;\n        Args = args;\n        TyArgs = tyArgs;\n      }\n      public override IEnumerable<Expression> SubExpressions {\n        get {\n          foreach (var v in Args) {\n            yield return v;\n          }\n        }\n      }\n    }\n\n    internal class SubstLetExpr : LetExpr {\n      public LetExpr orgExpr;\n      public Dictionary<IVariable, Expression> substMap;\n      public Dictionary<TypeParameter, Type> typeMap;\n\n      public SubstLetExpr(IToken tok, List<CasePattern<BoundVar>> lhss, List<Expression> rhss, Expression body, bool exact,\n         LetExpr orgExpr, Dictionary<IVariable, Expression> substMap, Dictionary<TypeParameter, Type> typeMap)\n        : base(tok, lhss, rhss, body, exact)\n      {\n        this.orgExpr = orgExpr;\n        this.substMap = substMap;\n        this.typeMap = typeMap;\n      }\n    }\n\n    internal class BoogieStmtListBuilder\n    {\n      public Bpl.StmtListBuilder builder;\n      public Translator tran;\n\n      public BoogieStmtListBuilder(Translator tran) {\n        builder = new Bpl.StmtListBuilder();\n        this.tran = tran;\n      }\n\n      public void Add(Cmd cmd) {\n        builder.Add(cmd);\n        if (cmd is Bpl.AssertCmd) {\n          tran.assertionCount++;\n        }\n      }\n      public void Add(StructuredCmd scmd) { builder.Add(scmd); }\n      public void Add(TransferCmd tcmd) { builder.Add(tcmd);  }\n      public void AddLabelCmd(string label) { builder.AddLabelCmd(label); }\n      public void AddLocalVariable(string name) { builder.AddLocalVariable(name); }\n\n      public StmtList Collect(IToken tok) {\n        return builder.Collect(tok);\n      }\n    }\n\n    internal class FuelSettingPair\n    {\n      public int low;\n      public int high;\n\n      public FuelSettingPair(int low = (int)FuelSetting.FuelAmount.LOW, int high = (int)FuelSetting.FuelAmount.HIGH) {\n        this.low = low;\n        this.high = high;\n      }\n    }\n\n    // C#'s version of a type alias\n    internal class FuelContext : Dictionary<Function, FuelSettingPair> { }\n    internal class CustomFuelSettings : Dictionary<Function, FuelSetting> {}\n\n    internal class FuelConstant\n    {\n      public Function f;\n      public Bpl.Expr baseFuel;\n      public Bpl.Expr startFuel;\n      public Bpl.Expr startFuelAssert;\n\n      public FuelConstant(Function f, Bpl.Expr baseFuel, Bpl.Expr startFuel, Bpl.Expr startFuelAssert) {\n        this.f = f;\n        this.baseFuel = baseFuel;\n        this.startFuel = startFuel;\n        this.startFuelAssert = startFuelAssert;\n      }\n\n      public Bpl.Expr MoreFuel(Bpl.Program sink, PredefinedDecls predef, FreshIdGenerator idGen) {\n        string uniqueId = idGen.FreshId(\"MoreFuel_\" + f.FullName);\n        Bpl.Constant moreFuel = new Bpl.Constant(f.tok, new Bpl.TypedIdent(f.tok, uniqueId, predef.LayerType), false);\n        sink.AddTopLevelDeclaration(moreFuel);\n        Bpl.Expr moreFuel_expr = new Bpl.IdentifierExpr(f.tok, moreFuel);\n        return moreFuel_expr;\n      }\n    }\n\n    internal class FuelSetting\n    {\n      public enum FuelAmount { NONE, LOW, HIGH };\n      public static Stack<FuelContext> SavedContexts = new Stack<FuelContext>();\n\n      public static FuelSettingPair FuelAttrib(Function f, out bool found) {\n        Contract.Requires(f != null);\n        Contract.Ensures(Contract.Result<FuelSettingPair>() != null);\n        FuelSettingPair setting = new FuelSettingPair();\n        found = false;\n\n        if (f.Attributes != null) {\n          List<Expression> args = Attributes.FindExpressions(f.Attributes, \"fuel\");\n          if (args != null) {\n            found = true;\n            if (args.Count >= 2) {\n              LiteralExpr literalLow = args[0] as LiteralExpr;\n              LiteralExpr literalHigh = args[1] as LiteralExpr;\n\n              if (literalLow != null && literalLow.Value is BigInteger && literalHigh != null && literalHigh.Value is BigInteger) {\n                setting.low = (int)((BigInteger)literalLow.Value);\n                setting.high = (int)((BigInteger)literalHigh.Value);\n              }\n            } else if (args.Count >= 1) {\n              LiteralExpr literal = args[0] as LiteralExpr;\n              if (literal != null && literal.Value is BigInteger) {\n                setting.low = (int)((BigInteger)literal.Value);\n                setting.high = setting.low + 1;\n              }\n            }\n          }\n        }\n\n        return setting;\n      }\n\n      public int amount;        // Amount of fuel above that represented by start\n      private Bpl.Expr start;   // Starting fuel argument (null indicates LZ)\n      private Translator translator;\n      private CustomFuelSettings customFuelSettings;\n\n      public FuelSetting(Translator translator, int amount, Bpl.Expr start = null, CustomFuelSettings customFuelSettings = null) {\n        this.translator = translator;\n        this.amount = amount;\n        this.start = start;\n        this.customFuelSettings = customFuelSettings;\n      }\n\n      public FuelSetting Offset(int offset) {\n        return new FuelSetting(translator, this.amount + offset, start);\n      }\n\n      public FuelSetting Decrease(int offset) {\n        Contract.Ensures(this.amount - offset >= 0);\n        return new FuelSetting(translator, this.amount - offset, start);\n      }\n\n      public FuelSetting WithLayer(Bpl.Expr layer) {\n        return new FuelSetting(translator, amount, layer);\n      }\n\n      public FuelSetting WithContext(CustomFuelSettings settings) {\n        return new FuelSetting(translator, amount, start, settings);\n      }\n\n      public Bpl.Expr LayerZero() {\n        Contract.Ensures(Contract.Result<Bpl.Expr>() != null);\n        return new Bpl.IdentifierExpr(Token.NoToken, \"$LZ\", translator.predef.LayerType);\n      }\n\n      public Bpl.Expr LayerN(int n) {\n        Contract.Requires(0 <= n);\n        Contract.Ensures(Contract.Result<Bpl.Expr>() != null);\n        return translator.LayerSucc(LayerZero(), n);\n      }\n\n      public Bpl.Expr LayerN(int n, Bpl.Expr baseLayer) {\n        Contract.Requires(0 <= n);\n        Contract.Ensures(Contract.Result<Bpl.Expr>() != null);\n        return translator.LayerSucc(baseLayer, n);\n      }\n\n      private Bpl.Expr ToExpr(int amount) {\n        if (start == null) {\n          return LayerN(amount);\n        } else {\n          return translator.LayerSucc(start, amount);\n        }\n      }\n\n      public Bpl.Expr ToExpr() {\n        return this.ToExpr(this.amount);\n      }\n\n      /// <summary>\n      /// Get the fuel value for this function, given the ambient environment (represented by the fuel setting)\n      /// the function itself, and the function call's context (if any)\n      /// </summary>\n      public Bpl.Expr GetFunctionFuel(Function f) {\n        Contract.Requires(f != null);\n        if (customFuelSettings != null && customFuelSettings.ContainsKey(f)) {\n          return customFuelSettings[f].GetFunctionFuel(f);\n        }\n        if (this.amount == (int)FuelAmount.NONE) {\n          return this.ToExpr();\n        } else {\n          FuelSettingPair setting = null;\n          var found = translator.fuelContext.TryGetValue(f, out setting);\n\n          if (!found) {  // If the context doesn't define fuel for this function, check for a fuel attribute (which supplies a default value if none is found)\n            setting = FuelAttrib(f, out found);\n          }\n\n          FuelConstant fuelConstant = translator.functionFuel.Find(x => x.f == f);\n          if (this.amount == (int)FuelAmount.LOW) {\n            return GetFunctionFuel(setting.low > 0 ? setting.low   : this.amount, found, fuelConstant);\n          } else if (this.amount >= (int)FuelAmount.HIGH) {\n            return GetFunctionFuel(setting.high > 0 ? setting.high : this.amount, found, fuelConstant);\n          } else {\n            Contract.Assert(false); // Should not reach here\n            return null;\n          }\n        }\n      }\n\n      private Bpl.Expr GetFunctionFuel(int amount, bool hasFuel, FuelConstant fuelConstant) {\n        if (fuelConstant != null) {\n          /*\n          if (hasFuel) {\n            // it has fuel context\n            return LayerN(amount, fuelConstant.baseFuel);\n          } else {\n           */\n          // startfuel\n          if (amount == (int)FuelAmount.LOW) {\n            return fuelConstant.startFuel;\n          } else {\n            return fuelConstant.startFuelAssert;\n          }\n          //}\n        } else {\n          return ToExpr(amount);\n        }\n      }\n\n      /// <summary>\n      /// Finds all fuel related attributes of the form {:fuel function low [high]}\n      /// Adds the setting to the context _if_ the context does not already have a setting for that function.\n      /// In other words, it should be called in order from most to least specific context scope.\n      /// </summary>\n      public static void FindFuelAttributes(Attributes attribs, FuelContext fuelContext) {\n        Function f = null;\n        FuelSettingPair setting = null;\n\n        if (attribs != null) {\n          List<List<Expression>> results = Attributes.FindAllExpressions(attribs, \"fuel\");\n\n          if (results != null) {\n            foreach (List<Expression> args in results) {\n              if (args != null && args.Count >= 2) {\n                // Try to extract the function from the first argument\n                MemberSelectExpr selectExpr = args[0].Resolved as MemberSelectExpr;\n                if (selectExpr != null) {\n                  f = selectExpr.Member as Function;\n                }\n\n                // Try to extract the lower fuel setting\n                LiteralExpr literalLow = args[1] as LiteralExpr;\n                if (literalLow != null && literalLow.Value is BigInteger) {\n                  setting = new FuelSettingPair();\n                  setting.low = (int)((BigInteger)literalLow.Value);\n                }\n\n                // The user may supply an additional high argument; if not, it defaults to low + 1\n                if (f != null && args.Count >= 3) {\n                  LiteralExpr literalHigh = args[2] as LiteralExpr;\n                  if (setting != null && literalHigh != null && literalHigh.Value is BigInteger) {\n                    setting.high = (int)((BigInteger)literalHigh.Value);\n                    if (!fuelContext.ContainsKey(f)) {\n                      fuelContext.Add(f, setting);\n                    }\n                  }\n                } else if (f != null && setting != null) {\n                  setting.high = setting.low + 1;\n                  if (!fuelContext.ContainsKey(f)) {\n                    fuelContext.Add(f, setting);\n                  }\n                }\n              }\n            }\n          }\n        }\n      }\n\n      /// <summary>\n      /// Extend the given context with fuel information from the declaration itself, and enclosing modules\n      /// </summary>\n      private static void AddFuelContext(FuelContext context, TopLevelDecl decl) {\n        FindFuelAttributes(decl.Attributes, context);\n\n        var module = decl.Module;\n        while (module != null) {\n          FindFuelAttributes(module.Attributes, context);\n          module = module.Module;\n        }\n      }\n\n      /// <summary>\n      /// Creates a summary of all fuel settings in scope, starting from the given class declaration\n      /// </summary>\n      public static FuelContext NewFuelContext(TopLevelDecl decl) {\n        FuelContext context = new FuelContext();\n        AddFuelContext(context, decl);\n        return context;\n      }\n\n      /// <summary>\n      /// Creates a summary of all fuel settings in scope, starting from the given member declaration\n      /// </summary>\n      public static FuelContext NewFuelContext(MemberDecl decl) {\n        FuelContext context = new FuelContext();\n\n        FindFuelAttributes(decl.Attributes, context);\n        AddFuelContext(context, decl.EnclosingClass);\n\n        return context;\n      }\n\n      /// <summary>\n      /// Extends the given fuel context with any new fuel settings found in attribs\n      /// </summary>\n      public static FuelContext ExpandFuelContext(Attributes attribs, IToken tok, FuelContext oldFuelContext, ErrorReporter reporter) {\n        Contract.Ensures(SavedContexts.Count == Contract.OldValue(SavedContexts.Count) + 1);\n        FuelContext newContext = new FuelContext();\n        FindFuelAttributes(attribs, newContext);\n        if (newContext.Count > 0) {\n          // first make sure that the fuel only increase relative to the oldContext\n          foreach (var pair in newContext) {\n            FuelSettingPair newSetting = pair.Value;\n            FuelSettingPair oldSetting;\n            var found = oldFuelContext.TryGetValue(pair.Key, out oldSetting);\n            if (!found) {    // the default is {:fuel, 1, 2}\n              oldSetting = new FuelSettingPair();\n            }\n            // make sure that the fuel can only increase within a given scope\n            if (newSetting.low < oldSetting.low || newSetting.high < oldSetting.high) {\n              reporter.Error(MessageSource.Translator, tok, \"Fuel can only increase within a given scope.\");\n            }\n          }\n          // add oldContext to newContext if it doesn't exist already\n          foreach (var pair in oldFuelContext) {\n            if (!newContext.ContainsKey(pair.Key)) {    // Local setting takes precedence over old context\n              newContext.Add(pair.Key, pair.Value);\n            }\n          }\n        } else {\n          newContext = oldFuelContext;\n        }\n        SavedContexts.Push(oldFuelContext);\n\n        return newContext;\n      }\n\n      public static FuelContext PopFuelContext() {\n        Contract.Requires(SavedContexts.Count > 0);\n        return SavedContexts.Pop();\n      }\n\n    }\n\n    internal enum IsAllocType { ISALLOC, NOALLOC };\n    static IsAllocType ISALLOC { get { return IsAllocType.ISALLOC; } }\n    static IsAllocType NOALLOC { get { return IsAllocType.NOALLOC; } }\n\n    internal class IsAllocContext\n    {\n      internal bool allVarsGhost;\n\n      internal IsAllocContext(bool allVarsGhost) {\n        this.allVarsGhost = allVarsGhost;\n      }\n\n      internal static IsAllocType Var(bool isGhost) {\n        return (CommonHeapUse || (NonGhostsUseHeap && !isGhost)) ? ISALLOC : NOALLOC;\n      }\n\n      internal IsAllocType Var(LocalVariable local) {\n        return Var(allVarsGhost || local.IsGhost);\n      }\n\n      internal IsAllocType Var(NonglobalVariable var) {\n        return Var(allVarsGhost || var.IsGhost);\n      }\n\n      internal IsAllocType Var(bool ghostStmt, LocalVariable var) {\n        return Var(allVarsGhost || ghostStmt || var.IsGhost);\n      }\n\n      internal IsAllocType Var(bool ghostStmt, NonglobalVariable var) {\n        return Var(allVarsGhost || ghostStmt || var.IsGhost);\n      }\n    }\n\n    internal class ExpressionTranslator\n    {\n      // HeapExpr == null ==> translation of pure (no-heap) expression\n      readonly Bpl.Expr _the_heap_expr;\n      public Bpl.Expr HeapExpr {\n        // The increment of Statistics_HeapUses in the following line is a hack and not entirely a good idea.\n        // Not only does one need to be careful not to mention HeapExpr in contracts (in particular, in ObjectInvariant()\n        // below), but also, the debugger may invoke HeapExpr and that will cause an increment as well.\n        get { Statistics_HeapUses++; return _the_heap_expr; }\n      }\n      public readonly PredefinedDecls predef;\n      public readonly Translator translator;\n      public readonly string This;\n      public readonly string modifiesFrame; // the name of the context's frame variable.\n      readonly Function applyLimited_CurrentFunction;\n      public readonly FuelSetting layerInterCluster;\n      public readonly FuelSetting layerIntraCluster = null;  // a value of null says to do the same as for inter-cluster calls\n      public int Statistics_CustomLayerFunctionCount = 0;\n      public int Statistics_HeapAsQuantifierCount = 0;\n      public int Statistics_HeapUses = 0;\n      public readonly bool stripLits = false;\n      [ContractInvariantMethod]\n      void ObjectInvariant()\n      {\n        // In the following line, it is important to use _the_heap_expr directly, rather than HeapExpr, because\n        // the HeapExpr getter has a side effect on Statistics_HeapUses.\n        Contract.Invariant(_the_heap_expr == null || _the_heap_expr is Bpl.OldExpr || _the_heap_expr is Bpl.IdentifierExpr);\n        Contract.Invariant(predef != null);\n        Contract.Invariant(translator != null);\n        Contract.Invariant(This != null);\n        Contract.Invariant(modifiesFrame != null);\n        Contract.Invariant(layerInterCluster != null);\n        Contract.Invariant(0 <= Statistics_CustomLayerFunctionCount);\n      }\n\n      /// <summary>\n      /// This is the most general constructor.  It is private and takes all the parameters.  Whenever\n      /// one ExpressionTranslator is constructed from another, unchanged parameters are just copied in.\n      /// </summary>\n      ExpressionTranslator(Translator translator, PredefinedDecls predef, Bpl.Expr heap, string thisVar,\n        Function applyLimited_CurrentFunction, FuelSetting layerInterCluster, FuelSetting layerIntraCluster, string modifiesFrame, bool stripLits) {\n\n        Contract.Requires(translator != null);\n        Contract.Requires(predef != null);\n        Contract.Requires(thisVar != null);\n        Contract.Requires(modifiesFrame != null);\n\n        this.translator = translator;\n        this.predef = predef;\n        this._the_heap_expr = heap;\n        this.This = thisVar;\n        this.applyLimited_CurrentFunction = applyLimited_CurrentFunction;\n        this.layerInterCluster = layerInterCluster;\n        if (layerIntraCluster == null) {\n          this.layerIntraCluster = layerInterCluster;\n        } else {\n          this.layerIntraCluster = layerIntraCluster;\n        }\n        this.modifiesFrame = modifiesFrame;\n        this.stripLits = stripLits;\n      }\n\n      public ExpressionTranslator(Translator translator, PredefinedDecls predef, IToken heapToken)\n        : this(translator, predef, new Bpl.IdentifierExpr(heapToken, predef.HeapVarName, predef.HeapType)) {\n        Contract.Requires(translator != null);\n        Contract.Requires(predef != null);\n        Contract.Requires(heapToken != null);\n      }\n\n      public ExpressionTranslator(Translator translator, PredefinedDecls predef, Bpl.Expr heap)\n        : this(translator, predef, heap, \"this\") {\n        Contract.Requires(translator != null);\n        Contract.Requires(predef != null);\n      }\n\n      public ExpressionTranslator(Translator translator, PredefinedDecls predef, Bpl.Expr heap, Bpl.Expr oldHeap)\n        : this(translator, predef, heap, \"this\") {\n        Contract.Requires(translator != null);\n        Contract.Requires(predef != null);\n        Contract.Requires(oldHeap != null);\n\n        var old = new ExpressionTranslator(translator, predef, oldHeap);\n        old.oldEtran = old;\n        this.oldEtran = old;\n      }\n\n      public ExpressionTranslator(Translator translator, PredefinedDecls predef, Bpl.Expr heap, string thisVar)\n        : this(translator, predef, heap, thisVar, null, new FuelSetting(translator, 1), null, \"$_Frame\", false) {\n        Contract.Requires(translator != null);\n        Contract.Requires(predef != null);\n        Contract.Requires(thisVar != null);\n      }\n\n      public ExpressionTranslator(ExpressionTranslator etran, Bpl.Expr heap)\n        : this(etran.translator, etran.predef, heap, etran.This, etran.applyLimited_CurrentFunction, etran.layerInterCluster, etran.layerIntraCluster, etran.modifiesFrame, etran.stripLits)\n      {\n        Contract.Requires(etran != null);\n      }\n\n      public ExpressionTranslator(ExpressionTranslator etran, string modifiesFrame)\n        : this(etran.translator, etran.predef, etran.HeapExpr, etran.This, etran.applyLimited_CurrentFunction, etran.layerInterCluster, etran.layerIntraCluster, modifiesFrame, etran.stripLits) {\n        Contract.Requires(etran != null);\n        Contract.Requires(modifiesFrame != null);\n      }\n\n      ExpressionTranslator oldEtran;\n      public ExpressionTranslator Old {\n        get {\n          Contract.Ensures(Contract.Result<ExpressionTranslator>() != null);\n\n          if (oldEtran == null) {\n            oldEtran = new ExpressionTranslator(translator, predef, new Bpl.OldExpr(HeapExpr.tok, HeapExpr), This, applyLimited_CurrentFunction, layerInterCluster, layerIntraCluster, modifiesFrame, stripLits);\n            oldEtran.oldEtran = oldEtran;\n          }\n          return oldEtran;\n        }\n      }\n\n      public ExpressionTranslator OldAt(Label label) {\n        Contract.Requires(label != null);\n        Contract.Ensures(Contract.Result<ExpressionTranslator>() != null);\n        var heapAt = new Bpl.IdentifierExpr(Token.NoToken, \"$Heap_at_\" + label.AssignUniqueId(translator.CurrentIdGenerator), predef.HeapType);\n        return new ExpressionTranslator(translator, predef, heapAt, This, applyLimited_CurrentFunction, layerInterCluster, layerIntraCluster, modifiesFrame, stripLits);\n      }\n\n      public bool UsesOldHeap {\n        get {\n          return HeapExpr is Bpl.OldExpr;\n        }\n      }\n\n      public ExpressionTranslator WithLayer(Bpl.Expr layerArgument)\n      {\n        // different layer and 0 fuel amount.\n        Contract.Requires(layerArgument != null);\n        Contract.Ensures(Contract.Result<ExpressionTranslator>() != null);\n\n        return CloneExpressionTranslator(this, translator, predef, HeapExpr, This, null, new FuelSetting(translator, 0, layerArgument), new FuelSetting(translator, 0, layerArgument), modifiesFrame, stripLits);\n      }\n\n      public ExpressionTranslator WithCustomFuelSetting(CustomFuelSettings customSettings) {\n        // Use the existing layers but with some per-function customizations\n        Contract.Requires(customSettings != null);\n        Contract.Ensures(Contract.Result<ExpressionTranslator>() != null);\n\n        return CloneExpressionTranslator(this, translator, predef, HeapExpr, This, null, layerInterCluster.WithContext(customSettings), layerIntraCluster.WithContext(customSettings), modifiesFrame, stripLits);\n      }\n\n      public ExpressionTranslator ReplaceLayer(Bpl.Expr layerArgument) {\n        // different layer with same fuel amount.\n        Contract.Requires(layerArgument != null);\n        Contract.Ensures(Contract.Result<ExpressionTranslator>() != null);\n\n        return CloneExpressionTranslator(this, translator, predef, HeapExpr, This, applyLimited_CurrentFunction, layerInterCluster.WithLayer(layerArgument), layerIntraCluster.WithLayer(layerArgument), modifiesFrame, stripLits);\n       }\n\n      public ExpressionTranslator WithNoLits() {\n        Contract.Ensures(Contract.Result<ExpressionTranslator>() != null);\n        return CloneExpressionTranslator(this, translator, predef, HeapExpr, This, applyLimited_CurrentFunction, layerInterCluster, layerIntraCluster, modifiesFrame, true);\n      }\n\n      public ExpressionTranslator LimitedFunctions(Function applyLimited_CurrentFunction, Bpl.Expr layerArgument) {\n        Contract.Requires(applyLimited_CurrentFunction != null);\n        Contract.Requires(layerArgument != null);\n        Contract.Ensures(Contract.Result<ExpressionTranslator>() != null);\n\n        return CloneExpressionTranslator(this, translator, predef, HeapExpr, This, applyLimited_CurrentFunction, /* layerArgument */ layerInterCluster, new FuelSetting(translator, 0, layerArgument), modifiesFrame, stripLits);\n      }\n\n      public ExpressionTranslator LayerOffset(int offset) {\n        Contract.Requires(0 <= offset);\n        Contract.Ensures(Contract.Result<ExpressionTranslator>() != null);\n\n        return CloneExpressionTranslator(this, translator, predef, HeapExpr, This, applyLimited_CurrentFunction, layerInterCluster.Offset(offset), layerIntraCluster, modifiesFrame, stripLits);\n      }\n\n      public ExpressionTranslator DecreaseFuel(int offset) {\n        Contract.Requires(0 <= offset);\n        Contract.Ensures(Contract.Result<ExpressionTranslator>() != null);\n\n        return CloneExpressionTranslator(this, translator, predef, HeapExpr, This, applyLimited_CurrentFunction, layerInterCluster.Decrease(offset), layerIntraCluster, modifiesFrame, stripLits);\n      }\n\n      private static ExpressionTranslator CloneExpressionTranslator(ExpressionTranslator orig,\n        Translator translator, PredefinedDecls predef, Bpl.Expr heap, string thisVar,\n        Function applyLimited_CurrentFunction, FuelSetting layerInterCluster, FuelSetting layerIntraCluster, string modifiesFrame, bool stripLits) {\n        var et = new ExpressionTranslator(translator, predef, heap, thisVar, applyLimited_CurrentFunction, layerInterCluster, layerIntraCluster, modifiesFrame, stripLits);\n        if (orig.oldEtran != null) {\n          var etOld = new ExpressionTranslator(translator, predef, orig.Old.HeapExpr, thisVar, applyLimited_CurrentFunction, layerInterCluster, layerIntraCluster, modifiesFrame, stripLits);\n          etOld.oldEtran = etOld;\n          et.oldEtran = etOld;\n        }\n        return et;\n      }\n\n      public Bpl.IdentifierExpr TheFrame(IToken tok)\n      {\n        Contract.Requires(tok != null);\n        Contract.Ensures(Contract.Result<Bpl.IdentifierExpr>() != null);\n        Contract.Ensures(Contract.Result<Bpl.IdentifierExpr>().Type != null);\n\n        Bpl.TypeVariable alpha = new Bpl.TypeVariable(tok, \"beta\");\n        Bpl.Type fieldAlpha = predef.FieldName(tok, alpha);\n        Bpl.Type ty = new Bpl.MapType(tok, new List<TypeVariable> { alpha }, new List<Bpl.Type> { predef.RefType, fieldAlpha }, Bpl.Type.Bool);\n        return new Bpl.IdentifierExpr(tok, this.modifiesFrame, ty);\n      }\n\n      public Bpl.IdentifierExpr Tick() {\n        Contract.Ensures(Contract.Result<Bpl.IdentifierExpr>() != null);\n        Contract.Ensures(Contract.Result<Bpl.IdentifierExpr>().Type != null);\n        return new Bpl.IdentifierExpr(Token.NoToken, \"$Tick\", predef.TickType);\n      }\n\n      public Bpl.IdentifierExpr ArbitraryBoxValue() {\n        Contract.Ensures(Contract.Result<Bpl.IdentifierExpr>() != null);\n        return new Bpl.IdentifierExpr(Token.NoToken, \"$ArbitraryBoxValue\", predef.BoxType);\n      }\n      public Bpl.Expr ArbitraryValue(Type type) {\n        Contract.Ensures(Contract.Result<Bpl.Expr>() != null);\n        var bx = ArbitraryBoxValue();\n        if (!ModeledAsBoxType(type)) {\n          return translator.FunctionCall(Token.NoToken, BuiltinFunction.Unbox, translator.TrType(type), bx);\n        } else {\n          return bx;\n        }\n      }\n\n      public Bpl.IdentifierExpr FunctionContextHeight() {\n        Contract.Ensures(Contract.Result<Bpl.IdentifierExpr>().Type != null);\n        return new Bpl.IdentifierExpr(Token.NoToken, \"$FunctionContextHeight\", Bpl.Type.Int);\n      }\n\n      public Bpl.Expr HeightContext(ICallable m)\n      {\n        Contract.Requires(m != null);\n        // free requires fh == FunctionContextHeight;\n        var module = m.EnclosingModule;\n        Bpl.Expr context =\n          Bpl.Expr.Eq(Bpl.Expr.Literal(module.CallGraph.GetSCCRepresentativeId(m)), FunctionContextHeight());\n        return context;\n      }\n\n      public Expression GetSubstitutedBody(LetExpr e)\n      {\n        Contract.Requires(e != null);\n        Contract.Requires(e.Exact);\n        Contract.Assert(e.LHSs.Count == e.RHSs.Count);  // checked by resolution\n        var substMap = new Dictionary<IVariable, Expression>();\n        for (int i = 0; i < e.LHSs.Count; i++) {\n          translator.AddCasePatternVarSubstitutions(e.LHSs[i], TrExpr(e.RHSs[i]), substMap);\n        }\n        return Translator.Substitute(e.Body, null, substMap);\n      }\n\n      public Expr MaybeLit(Expr expr, Bpl.Type type) {\n        return stripLits ? expr : translator.Lit(expr, type);\n      }\n\n      public Expr MaybeLit(Expr expr) {\n        return stripLits ? expr : translator.Lit(expr);\n      }\n\n      /// <summary>\n      /// Translates Dafny expression \"expr\" into a Boogie expression.  If the type of \"expr\" can be a boolean, then the\n      /// token (source location) of the resulting expression is filled in (it wouldn't hurt if the token were always\n      /// filled in, but it is really necessary for anything that may show up in a Boogie assert, since that location may\n      /// then show up in an error message).\n      /// </summary>\n      public Bpl.Expr TrExpr(Expression expr) {\n        Contract.Requires(expr != null);\n        Contract.Requires(predef != null);\n\n        if (expr is LiteralExpr) {\n          LiteralExpr e = (LiteralExpr)expr;\n          if (e.Value == null) {\n            return predef.Null;\n          } else if (e.Value is bool) {\n            return MaybeLit(new Bpl.LiteralExpr(e.tok, (bool)e.Value));\n          } else if (e is CharLiteralExpr) {\n            // we expect e.Value to be a string representing exactly one char\n            Bpl.Expr rawElement = null;  // assignment to please compiler's definite assignment rule\n            foreach (char ch in Util.UnescapedCharacters((string)e.Value, false)) {\n              Contract.Assert(rawElement == null);  // we should get here only once\n              rawElement = translator.FunctionCall(expr.tok, BuiltinFunction.CharFromInt, null, Bpl.Expr.Literal((int)ch));\n            }\n            Contract.Assert(rawElement != null);  // there should have been an iteration of the loop above\n            return MaybeLit(rawElement, predef.CharType);\n          } else if (e is StringLiteralExpr) {\n            var str = (StringLiteralExpr)e;\n            Bpl.Expr seq = translator.FunctionCall(expr.tok, BuiltinFunction.SeqEmpty, predef.BoxType);\n            foreach (char ch in Util.UnescapedCharacters((string)e.Value, str.IsVerbatim)) {\n              var rawElement = translator.FunctionCall(expr.tok, BuiltinFunction.CharFromInt, null, Bpl.Expr.Literal((int)ch));\n              Bpl.Expr elt = BoxIfNecessary(expr.tok, rawElement, Type.Char);\n              seq = translator.FunctionCall(expr.tok, BuiltinFunction.SeqBuild, predef.BoxType, seq, elt);\n            }\n            return MaybeLit(seq, translator.TrType(new SeqType(Type.Char)));\n          } else if (e.Value is BigInteger) {\n            var n = Microsoft.BaseTypes.BigNum.FromBigInt((BigInteger)e.Value);\n            if (e.Type is BitvectorType) {\n              return MaybeLit(translator.BplBvLiteralExpr(e.tok, n, (BitvectorType)e.Type));\n            } else if (e.Type.IsBigOrdinalType) {\n              var fromNat = translator.FunctionCall(expr.tok, \"ORD#FromNat\", predef.BigOrdinalType, Bpl.Expr.Literal(n));\n              return MaybeLit(fromNat, predef.BigOrdinalType);\n            } else {\n              return MaybeLit(Bpl.Expr.Literal(n));\n            }\n          } else if (e.Value is BaseTypes.BigDec) {\n            return MaybeLit(Bpl.Expr.Literal((BaseTypes.BigDec)e.Value));\n          } else {\n            Contract.Assert(false); throw new cce.UnreachableException();  // unexpected literal\n          }\n\n        } else if (expr is ThisExpr) {\n          return new Bpl.IdentifierExpr(expr.tok, This);\n\n        } else if (expr is IdentifierExpr) {\n          IdentifierExpr e = (IdentifierExpr)expr;\n          Contract.Assert(e.Var != null);\n          return translator.TrVar(expr.tok, e.Var);\n\n        } else if (expr is BoogieWrapper) {\n          var e = (BoogieWrapper)expr;\n          return e.Expr;\n\n\n        } else if (expr is BoogieFunctionCall) {\n          var e = (BoogieFunctionCall)expr;\n          var id = new Bpl.IdentifierExpr(e.tok, e.FunctionName, translator.TrType(e.Type));\n          var args = new List<Bpl.Expr>();\n          foreach (var arg in e.TyArgs) {\n            args.Add(translator.TypeToTy(arg));\n          }\n          if (e.UsesHeap) {\n            args.Add(HeapExpr);\n          }\n          if (e.UsesOldHeap) {\n            args.Add(Old.HeapExpr);\n          }\n          foreach (var heapAtLabel in e.HeapAtLabels) {\n            Bpl.Expr ve;\n            var bv = BplBoundVar(\"$Heap_at_\" + heapAtLabel.AssignUniqueId(translator.CurrentIdGenerator), translator.predef.HeapType, out ve);\n            args.Add(ve);\n          }\n          foreach (var arg in e.Args) {\n            args.Add(TrExpr(arg));\n          }\n          return new Bpl.NAryExpr(e.tok, new Bpl.FunctionCall(id), args);\n\n        } else if (expr is SetDisplayExpr) {\n          SetDisplayExpr e = (SetDisplayExpr)expr;\n          Bpl.Expr s = translator.FunctionCall(expr.tok, e.Finite ? BuiltinFunction.SetEmpty : BuiltinFunction.ISetEmpty, predef.BoxType);\n          var isLit = true;\n          foreach (Expression ee in e.Elements) {\n            var rawElement = TrExpr(ee);\n            isLit = isLit && translator.IsLit(rawElement);\n            Bpl.Expr ss = BoxIfNecessary(expr.tok, rawElement, cce.NonNull(ee.Type));\n            s = translator.FunctionCall(expr.tok, e.Finite ? BuiltinFunction.SetUnionOne : BuiltinFunction.ISetUnionOne, predef.BoxType, s, ss);\n          }\n          if (isLit) {\n            // Lit-lifting: All elements are lit, so the set is Lit too\n            s = MaybeLit(s, predef.BoxType);\n          }\n          return s;\n\n        } else if (expr is MultiSetDisplayExpr) {\n          MultiSetDisplayExpr e = (MultiSetDisplayExpr)expr;\n          Bpl.Expr s = translator.FunctionCall(expr.tok, BuiltinFunction.MultiSetEmpty, predef.BoxType);\n          var isLit = true;\n          foreach (Expression ee in e.Elements) {\n            var rawElement = TrExpr(ee);\n            isLit = isLit && translator.IsLit(rawElement);\n            Bpl.Expr ss = BoxIfNecessary(expr.tok, rawElement, cce.NonNull(ee.Type));\n            s = translator.FunctionCall(expr.tok, BuiltinFunction.MultiSetUnionOne, predef.BoxType, s, ss);\n          }\n          if (isLit) {\n            // Lit-lifting: All elements are lit, so the multiset is Lit too\n            s = MaybeLit(s, predef.BoxType);\n          }\n          return s;\n\n        } else if (expr is SeqDisplayExpr) {\n          SeqDisplayExpr e = (SeqDisplayExpr)expr;\n          // Note: a LiteralExpr(string) is really another kind of SeqDisplayExpr\n          Bpl.Expr s = translator.FunctionCall(expr.tok, BuiltinFunction.SeqEmpty, predef.BoxType);\n          var isLit = true;\n          foreach (Expression ee in e.Elements) {\n            var rawElement = TrExpr(ee);\n            isLit = isLit && translator.IsLit(rawElement);\n            Bpl.Expr elt = BoxIfNecessary(expr.tok, rawElement, ee.Type);\n            s = translator.FunctionCall(expr.tok, BuiltinFunction.SeqBuild, predef.BoxType, s, elt);\n          }\n          if (isLit) {\n            // Lit-lifting: All elements are lit, so the sequence is Lit too\n            s = MaybeLit(s, predef.BoxType);\n          }\n          return s;\n\n        } else if (expr is MapDisplayExpr) {\n          MapDisplayExpr e = (MapDisplayExpr)expr;\n          Bpl.Type maptype = predef.MapType(expr.tok, e.Finite, predef.BoxType, predef.BoxType);\n          Bpl.Expr s = translator.FunctionCall(expr.tok, e.Finite ? BuiltinFunction.MapEmpty : BuiltinFunction.IMapEmpty, predef.BoxType);\n          var isLit = true;\n          foreach (ExpressionPair p in e.Elements) {\n            var rawA = TrExpr(p.A);\n            var rawB = TrExpr(p.B);\n            isLit = isLit && translator.IsLit(rawA) && translator.IsLit(rawB);\n            Bpl.Expr elt = BoxIfNecessary(expr.tok, rawA, cce.NonNull(p.A.Type));\n            Bpl.Expr elt2 = BoxIfNecessary(expr.tok, rawB, cce.NonNull(p.B.Type));\n            s = translator.FunctionCall(expr.tok, e.Finite ? \"Map#Build\" : \"IMap#Build\", maptype, s, elt, elt2);\n          }\n          if (isLit) {\n            // Lit-lifting: All keys and values are lit, so the map is Lit too\n            s = MaybeLit(s, predef.BoxType);\n          }\n          return s;\n\n        } else if (expr is MemberSelectExpr) {\n          var e = (MemberSelectExpr)expr;\n          return e.MemberSelectCase(\n            field => {\n              var useSurrogateLocal = translator.inBodyInitContext && Expression.AsThis(e.Obj) != null && !field.IsInstanceIndependentConstant;\n              if (useSurrogateLocal) {\n                return new Bpl.IdentifierExpr(expr.tok, translator.SurrogateName(field), translator.TrType(field.Type));\n              } else if (field is ConstantField) {\n                var args = e.TypeApplication.ConvertAll(translator.TypeToTy);\n                Bpl.Expr result;\n                if (field.IsStatic) {\n                  result = new Bpl.NAryExpr(expr.tok, new Bpl.FunctionCall(translator.GetReadonlyField(field)), args);\n                } else {\n                  Bpl.Expr obj = TrExpr(e.Obj);\n                  args.Add(obj);\n                  result = new Bpl.NAryExpr(expr.tok, new Bpl.FunctionCall(translator.GetReadonlyField(field)), args);\n                }\n                result = translator.CondApplyUnbox(expr.tok, result, field.Type, expr.Type);\n                return result;\n              } else {\n                Bpl.Expr obj = TrExpr(e.Obj);\n                Bpl.Expr result;\n                if (field.IsMutable) {\n                  result = ReadHeap(expr.tok, HeapExpr, obj, new Bpl.IdentifierExpr(expr.tok, translator.GetField(field)));\n                  return translator.CondApplyUnbox(expr.tok, result, field.Type, expr.Type);\n                } else {\n                  result = new Bpl.NAryExpr(expr.tok, new Bpl.FunctionCall(translator.GetReadonlyField(field)),\n                    new List<Bpl.Expr> { obj });\n                  result = translator.CondApplyUnbox(expr.tok, result, field.Type, expr.Type);\n                  if (translator.IsLit(obj)) {\n                    result = MaybeLit(result, translator.TrType(expr.Type));\n                  }\n                  return result;\n                }\n              }\n            },\n            fn => {\n              var args = e.TypeApplication.ConvertAll(translator.TypeToTy);\n              if (fn.IsFuelAware()) {\n                args.Add(this.layerInterCluster.GetFunctionFuel(fn));\n              }\n              if (fn is TwoStateFunction) {\n                args.Add(Old.HeapExpr);\n              }\n              if (!fn.IsStatic) {\n                args.Add(/* translator.BoxIfUnboxed */(TrExpr(e.Obj)/*, e.Type */));\n              }\n              return translator.FunctionCall(e.tok, translator.FunctionHandle(fn), predef.HandleType, args);\n            });\n        } else if (expr is SeqSelectExpr) {\n          SeqSelectExpr e = (SeqSelectExpr)expr;\n          Bpl.Expr seq = TrExpr(e.Seq);\n          var seqType = e.Seq.Type.NormalizeExpand();\n          Type elmtType = null;\n          Type domainType = null;\n          Contract.Assert(seqType != null);  // the expression has been successfully resolved\n          if (seqType.IsArrayType) {\n            domainType = Type.Int;\n            elmtType = UserDefinedType.ArrayElementType(seqType);\n          } else if (seqType is SeqType) {\n            domainType = Type.Int;\n            elmtType = ((SeqType)seqType).Arg;\n          } else if (seqType is MapType) {\n            domainType = ((MapType)seqType).Domain;\n            elmtType = ((MapType)seqType).Range;\n          } else if (seqType is MultiSetType) {\n            domainType = ((MultiSetType)seqType).Arg;\n            elmtType = Type.Int;\n          } else { Contract.Assert(false); }\n          Bpl.Type elType = translator.TrType(elmtType);\n          Bpl.Type dType = translator.TrType(domainType);\n          Bpl.Expr e0 = e.E0 == null ? null : TrExpr(e.E0);\n          if (e0 != null && e.E0.Type.IsBitVectorType) {\n            e0 = translator.ConvertExpression(e.E0.tok, e0, e.E0.Type, Type.Int);\n          }\n          Bpl.Expr e1 = e.E1 == null ? null : TrExpr(e.E1);\n          if (e1 != null && e.E1.Type.IsBitVectorType) {\n            e1 = translator.ConvertExpression(e.E1.tok, e1, e.E1.Type, Type.Int);\n          }\n          if (e.SelectOne) {\n            Contract.Assert(e1 == null);\n            Bpl.Expr x;\n            if (seqType.IsArrayType) {\n              Bpl.Expr fieldName = translator.FunctionCall(expr.tok, BuiltinFunction.IndexField, null, e0);\n              x = ReadHeap(expr.tok, HeapExpr, TrExpr(e.Seq), fieldName);\n            } else if (seqType is SeqType) {\n              x = translator.FunctionCall(expr.tok, BuiltinFunction.SeqIndex, predef.BoxType, seq, e0);\n            } else if (seqType is MapType) {\n              bool finite = ((MapType)seqType).Finite;\n              var f = finite ? BuiltinFunction.MapElements : BuiltinFunction.IMapElements;\n              x = translator.FunctionCall(expr.tok, f, predef.MapType(e.tok, finite, predef.BoxType, predef.BoxType), seq);\n              x = Bpl.Expr.Select(x, BoxIfNecessary(e.tok, e0, domainType));\n            } else if (seqType is MultiSetType) {\n              x = Bpl.Expr.SelectTok(expr.tok, TrExpr(e.Seq), BoxIfNecessary(expr.tok, e0, domainType));\n            } else { Contract.Assert(false); x = null; }\n            if (!ModeledAsBoxType(elmtType) && !(seqType is MultiSetType)) {\n              x = translator.FunctionCall(expr.tok, BuiltinFunction.Unbox, elType, x);\n            }\n            return x;\n          } else {\n            if (seqType.IsArrayType) {\n              seq = translator.FunctionCall(expr.tok, BuiltinFunction.SeqFromArray, elType, HeapExpr, seq);\n            }\n            var isLit = translator.IsLit(seq);\n            if (e1 != null) {\n              isLit = isLit && translator.IsLit(e1);\n              seq = translator.FunctionCall(expr.tok, BuiltinFunction.SeqTake, elType, seq, e1);\n            }\n            if (e0 != null) {\n              isLit = isLit && translator.IsLit(e0);\n              seq = translator.FunctionCall(expr.tok, BuiltinFunction.SeqDrop, elType, seq, e0);\n            }\n            // if e0 == null && e1 == null, then we have the identity operation seq[..] == seq;\n            if (isLit && (e0 != null || e1 != null)) {\n              // Lit-lift the expression\n              seq = MaybeLit(seq, translator.TrType(expr.Type));\n            }\n            return seq;\n          }\n\n        } else if (expr is SeqUpdateExpr) {\n          SeqUpdateExpr e = (SeqUpdateExpr)expr;\n          if (e.ResolvedUpdateExpr != null)\n          {\n            return TrExpr(e.ResolvedUpdateExpr);\n          }\n          else\n          {\n            Bpl.Expr seq = TrExpr(e.Seq);\n            var seqType = e.Seq.Type.NormalizeExpand();\n            if (seqType is SeqType)\n            {\n              Type elmtType = cce.NonNull((SeqType)seqType).Arg;\n              Bpl.Expr index = TrExpr(e.Index);\n              Bpl.Expr val = BoxIfNecessary(expr.tok, TrExpr(e.Value), elmtType);\n              return translator.FunctionCall(expr.tok, BuiltinFunction.SeqUpdate, predef.BoxType, seq, index, val);\n            }\n            else if (seqType is MapType)\n            {\n              MapType mt = (MapType)seqType;\n              Bpl.Type maptype = predef.MapType(expr.tok, mt.Finite, predef.BoxType, predef.BoxType);\n              Bpl.Expr index = BoxIfNecessary(expr.tok, TrExpr(e.Index), mt.Domain);\n              Bpl.Expr val = BoxIfNecessary(expr.tok, TrExpr(e.Value), mt.Range);\n              return translator.FunctionCall(expr.tok, mt.Finite ? \"Map#Build\" : \"IMap#Build\", maptype, seq, index, val);\n            }\n            else if (seqType is MultiSetType)\n            {\n              Type elmtType = cce.NonNull((MultiSetType)seqType).Arg;\n              Bpl.Expr index = BoxIfNecessary(expr.tok, TrExpr(e.Index), elmtType);\n              Bpl.Expr val = TrExpr(e.Value);\n              return Bpl.Expr.StoreTok(expr.tok, seq, index, val);\n            }\n            else\n            {\n              Contract.Assert(false);\n              throw new cce.UnreachableException();\n            }\n          }\n\n        } else if (expr is MultiSelectExpr) {\n          MultiSelectExpr e = (MultiSelectExpr)expr;\n          Type elmtType = UserDefinedType.ArrayElementType(e.Array.Type);;\n          Bpl.Type elType = translator.TrType(elmtType);\n\n          Bpl.Expr fieldName = GetArrayIndexFieldName(expr.tok, e.Indices);\n          Bpl.Expr x = ReadHeap(expr.tok, HeapExpr, TrExpr(e.Array), fieldName);\n          if (!ModeledAsBoxType(elmtType)) {\n            x = translator.FunctionCall(expr.tok, BuiltinFunction.Unbox, elType, x);\n          }\n          return x;\n\n        } else if (expr is ApplyExpr) {\n          ApplyExpr e = (ApplyExpr)expr;\n          int arity = e.Args.Count;\n          var tt = e.Function.Type.AsArrowType;\n          Contract.Assert(tt != null);\n          Contract.Assert(tt.Arity == arity);\n\n          {\n            // optimisation: if this could have just as well been a FunctionCallExpr, call it as such!\n            var con = e.Function as ConcreteSyntaxExpression;\n            var recv = con == null ? e.Function : con.Resolved;\n            var mem = recv as MemberSelectExpr;\n            var fn = mem == null ? null : mem.Member as Function;\n            if (fn != null) {\n              return TrExpr(new FunctionCallExpr(e.tok, fn.Name, mem.Obj, e.tok, e.Args) {\n                Function = fn,\n                Type = e.Type,\n                TypeArgumentSubstitutions = Util.Dict(GetTypeParams(fn), mem.TypeApplication)\n              });\n            }\n          }\n\n          Func<Expression, Bpl.Expr> TrArg = arg => translator.BoxIfUnboxed(TrExpr(arg), arg.Type);\n\n          var applied = translator.FunctionCall(expr.tok, Translator.Apply(arity), predef.BoxType,\n            Concat(Map(tt.TypeArgs,translator.TypeToTy),\n            Cons(HeapExpr, Cons(TrExpr(e.Function), e.Args.ConvertAll(arg => TrArg(arg))))));\n\n          return translator.UnboxIfBoxed(applied, tt.Result);\n\n        } else if (expr is FunctionCallExpr) {\n          FunctionCallExpr e = (FunctionCallExpr)expr;\n          if (e.Function is SpecialFunction) {\n            return TrExprSpecialFunctionCall(e);\n          } else {\n            Bpl.Expr layerArgument;\n            var etran = this;\n            if (e.Function.ContainsQuantifier && translator.stmtContext == StmtType.ASSUME && translator.adjustFuelForExists) {\n              // we need to increase fuel functions that contain quantifier expr in the assume context.\n              etran = etran.LayerOffset(1);\n              translator.adjustFuelForExists = false;\n            }\n            if (e.Function.IsFuelAware()) {\n              Statistics_CustomLayerFunctionCount++;\n              ModuleDefinition module = e.Function.EnclosingClass.Module;\n              if (etran.applyLimited_CurrentFunction != null &&\n                etran.layerIntraCluster != null &&\n                ModuleDefinition.InSameSCC(e.Function, applyLimited_CurrentFunction)) {\n                layerArgument = etran.layerIntraCluster.GetFunctionFuel(e.Function);\n              } else {\n                layerArgument = etran.layerInterCluster.GetFunctionFuel(e.Function);\n              }\n            } else {\n              layerArgument = null;\n            }\n\n            var ty = translator.TrType(e.Type);\n            var name = e.Function.FullSanitizedName;\n            if (ArmadaOptions.O.IronDafny) {\n              name = e.Function.FullSanitizedRefinementName;\n            }\n            var id = new Bpl.IdentifierExpr(e.tok, name, ty);\n\n            bool argsAreLit;\n            var args = FunctionInvocationArguments(e, layerArgument, false, out argsAreLit);\n            Expr result = new Bpl.NAryExpr(e.tok, new Bpl.FunctionCall(id), args);\n            result = translator.CondApplyUnbox(e.tok, result, e.Function.ResultType, e.Type);\n\n            bool callIsLit = argsAreLit\n              && Translator.FunctionBodyIsAvailable(e.Function, translator.currentModule, translator.currentScope, true)\n              && !e.Function.Reads.Any(); // Function could depend on external values\n            if (callIsLit) {\n              result = MaybeLit(result, ty);\n            }\n\n            return result;\n          }\n        } else if (expr is DatatypeValue) {\n          DatatypeValue dtv = (DatatypeValue)expr;\n          Contract.Assert(dtv.Ctor != null);  // since dtv has been successfully resolved\n          List<Bpl.Expr> args = new List<Bpl.Expr>();\n\n          bool argsAreLit = true;\n          for (int i = 0; i < dtv.Arguments.Count; i++) {\n            Expression arg = dtv.Arguments[i];\n            Type t = dtv.Ctor.Formals[i].Type;\n            var bArg = TrExpr(arg);\n            argsAreLit = argsAreLit && translator.IsLit(bArg);\n            args.Add(translator.CondApplyBox(expr.tok, bArg, cce.NonNull(arg.Type), t));\n          }\n          Bpl.IdentifierExpr id = new Bpl.IdentifierExpr(dtv.tok, dtv.Ctor.FullName, predef.DatatypeType);\n          Bpl.Expr ret = new Bpl.NAryExpr(dtv.tok, new Bpl.FunctionCall(id), args);\n          if (argsAreLit) {\n            // If all arguments are Lit, so is the whole expression\n            ret = MaybeLit(ret, predef.DatatypeType);\n          }\n          return ret;\n\n        } else if (expr is SeqConstructionExpr) {\n          var e = (SeqConstructionExpr)expr;\n          var eType = e.Type.AsSeqType.Arg.NormalizeExpand();\n          return translator.FunctionCall(expr.tok, \"Seq#Create\", predef.SeqType(e.tok, predef.BoxType), translator.TypeToTy(eType), HeapExpr, TrExpr(e.N), TrExpr(e.Initializer));\n\n        } else if (expr is MultiSetFormingExpr) {\n          MultiSetFormingExpr e = (MultiSetFormingExpr)expr;\n          var eType = e.E.Type.NormalizeExpand();\n          if (eType is SetType) {\n            return translator.FunctionCall(expr.tok, BuiltinFunction.MultiSetFromSet, translator.TrType(cce.NonNull((SetType)eType).Arg), TrExpr(e.E));\n          } else if (eType is SeqType) {\n            return translator.FunctionCall(expr.tok, BuiltinFunction.MultiSetFromSeq, translator.TrType(cce.NonNull((SeqType)eType).Arg), TrExpr(e.E));\n          } else {\n            Contract.Assert(false); throw new cce.UnreachableException();\n          }\n\n        } else if (expr is OldExpr) {\n          var e = (OldExpr)expr;\n          return e.AtLabel == null ? Old.TrExpr(e.E) : OldAt(e.AtLabel).TrExpr(e.E);\n\n        } else if (expr is UnchangedExpr) {\n          var e = (UnchangedExpr)expr;\n          return translator.FrameCondition(e.tok, e.Frame, false, Resolver.FrameExpressionUse.Unchanged, e.AtLabel == null ? Old : OldAt(e.AtLabel), this, this, true);\n\n        } else if (expr is UnaryOpExpr) {\n          var e = (UnaryOpExpr)expr;\n          Bpl.Expr arg = TrExpr(e.E);\n          switch (e.Op) {\n            case UnaryOpExpr.Opcode.Lit:\n              return MaybeLit(arg);\n            case UnaryOpExpr.Opcode.Not:\n              if (expr.Type.IsBitVectorType) {\n                var bvWidth = expr.Type.AsBitVectorType.Width;\n                var bvType = translator.BplBvType(bvWidth);\n                Bpl.Expr r = translator.FunctionCall(expr.tok, \"not_bv\" + bvWidth, bvType, arg);\n                if (translator.IsLit(arg)) {\n                  r = MaybeLit(r, bvType);\n                }\n                return r;\n              } else {\n                return Bpl.Expr.Unary(expr.tok, UnaryOperator.Opcode.Not, arg);\n              }\n            case UnaryOpExpr.Opcode.Cardinality:\n              var eType = e.E.Type.NormalizeExpand();\n              if (eType is SeqType) {\n                return translator.FunctionCall(expr.tok, BuiltinFunction.SeqLength, null, arg);\n              } else if (eType is SetType && ((SetType)eType).Finite) {\n                return translator.FunctionCall(expr.tok, BuiltinFunction.SetCard, null, arg);\n              } else if (eType is MultiSetType) {\n                return translator.FunctionCall(expr.tok, BuiltinFunction.MultiSetCard, null, arg);\n              } else if (eType is MapType && ((MapType)eType).Finite) {\n                return translator.FunctionCall(expr.tok, BuiltinFunction.MapCard, null, arg);\n              } else {\n                Contract.Assert(false); throw new cce.UnreachableException();  // unexpected sized type\n              }\n            case UnaryOpExpr.Opcode.Fresh:\n              var eeType = e.E.Type.NormalizeExpand();\n              if (eeType is SetType) {\n                // generate:  (forall $o: ref :: { X[Box($o)] } X[Box($o)] ==> $o != null && !old($Heap)[$o,alloc])\n                // OR, if X[Box($o)] is rewritten into smaller parts, use the less good trigger old($Heap)[$o,alloc]\n                Bpl.Variable oVar = new Bpl.BoundVariable(expr.tok, new Bpl.TypedIdent(expr.tok, \"$o\", predef.RefType));\n                Bpl.Expr o = new Bpl.IdentifierExpr(expr.tok, oVar);\n                Bpl.Expr oNotNull = Bpl.Expr.Neq(o, predef.Null);\n                bool performedInSetRewrite;\n                Bpl.Expr oInSet = TrInSet(expr.tok, o, e.E, ((SetType)eeType).Arg, out performedInSetRewrite);\n                Bpl.Expr oNotFresh = Old.IsAlloced(expr.tok, o);\n                Bpl.Expr oIsFresh = Bpl.Expr.Not(oNotFresh);\n                Bpl.Expr body = Bpl.Expr.Imp(oInSet, Bpl.Expr.And(oNotNull, oIsFresh));\n                var trigger = BplTrigger(performedInSetRewrite ? oNotFresh : oInSet);\n                return new Bpl.ForallExpr(expr.tok, new List<Variable> { oVar }, trigger, body);\n              } else if (eeType is SeqType) {\n                // generate:  (forall $i: int :: 0 <= $i && $i < Seq#Length(X) ==> Unbox(Seq#Index(X,$i)) != null && !old($Heap)[Unbox(Seq#Index(X,$i)),alloc])\n                Bpl.Variable iVar = new Bpl.BoundVariable(expr.tok, new Bpl.TypedIdent(expr.tok, \"$i\", Bpl.Type.Int));\n                Bpl.Expr i = new Bpl.IdentifierExpr(expr.tok, iVar);\n                Bpl.Expr iBounds = translator.InSeqRange(expr.tok, i, Type.Int, TrExpr(e.E), true, null, false);\n                Bpl.Expr XsubI = translator.FunctionCall(expr.tok, BuiltinFunction.SeqIndex, predef.RefType, TrExpr(e.E), i);\n                XsubI = translator.FunctionCall(expr.tok, BuiltinFunction.Unbox, predef.RefType, XsubI);\n                Bpl.Expr oNotFresh = Old.IsAlloced(expr.tok, XsubI);\n                Bpl.Expr oIsFresh = Bpl.Expr.Not(oNotFresh);\n                Bpl.Expr xsubiNotNull = Bpl.Expr.Neq(XsubI, predef.Null);\n                Bpl.Expr body = Bpl.Expr.Imp(iBounds, Bpl.Expr.And(xsubiNotNull, oIsFresh));\n                //TRIGGERS: Does this make sense? dafny0\\SmallTests\n                // BROKEN // NEW_TRIGGER\n                //TRIG (forall $i: int :: 0 <= $i && $i < Seq#Length(Q#0) && $Unbox(Seq#Index(Q#0, $i)): ref != null ==> !read(old($Heap), $Unbox(Seq#Index(Q#0, $i)): ref, alloc))\n                return new Bpl.ForallExpr(expr.tok, new List<Variable> { iVar }, body);\n              } else {\n                // generate:  x != null && !old($Heap)[x]\n                Bpl.Expr oNull = Bpl.Expr.Neq(TrExpr(e.E), predef.Null);\n                Bpl.Expr oIsFresh = Bpl.Expr.Not(Old.IsAlloced(expr.tok, TrExpr(e.E)));\n                return Bpl.Expr.Binary(expr.tok, BinaryOperator.Opcode.And, oNull, oIsFresh);\n              }\n            case UnaryOpExpr.Opcode.Allocated:\n            case UnaryOpExpr.Opcode.AllocatedArray:\n              {\n                var aType = e.E.Type.NormalizeExpand();\n                return translator.MkIsAlloc(TrExpr(e.E), aType, HeapExpr);\n              }\n            default:\n              Contract.Assert(false); throw new cce.UnreachableException();  // unexpected unary expression\n          }\n\n        } else if (expr is ConversionExpr) {\n          var e = (ConversionExpr)expr;\n          return translator.ConvertExpression(e.tok, TrExpr(e.E), e.E.Type, e.ToType);\n\n        } else if (expr is BinaryExpr) {\n          BinaryExpr e = (BinaryExpr)expr;\n          bool isReal = e.E0.Type.IsNumericBased(Type.NumericPersuation.Real);\n          int bvWidth = e.E0.Type.IsBitVectorType ? e.E0.Type.AsBitVectorType.Width : -1;  // -1 indicates \"not a bitvector type\"\n          Bpl.Expr e0 = TrExpr(e.E0);\n          if (e.ResolvedOp == BinaryExpr.ResolvedOpcode.InSet) {\n            bool pr;\n            return TrInSet(expr.tok, e0, e.E1, cce.NonNull(e.E0.Type), out pr);  // let TrInSet translate e.E1\n          } else if (e.ResolvedOp == BinaryExpr.ResolvedOpcode.NotInSet) {\n            bool pr;\n            Bpl.Expr arg = TrInSet(expr.tok, e0, e.E1, cce.NonNull(e.E0.Type), out pr);  // let TrInSet translate e.E1\n            return Bpl.Expr.Unary(expr.tok, UnaryOperator.Opcode.Not, arg);\n          } else if (e.ResolvedOp == BinaryExpr.ResolvedOpcode.InMultiSet) {\n            return TrInMultiSet(expr.tok, e0, e.E1, cce.NonNull(e.E0.Type)); // let TrInMultiSet translate e.E1\n          } else if (e.ResolvedOp == BinaryExpr.ResolvedOpcode.NotInMultiSet) {\n            Bpl.Expr arg = TrInMultiSet(expr.tok, e0, e.E1, cce.NonNull(e.E0.Type));  // let TrInMultiSet translate e.E1\n            return Bpl.Expr.Unary(expr.tok, UnaryOperator.Opcode.Not, arg);\n          }\n          Bpl.Expr e1 = TrExpr(e.E1);\n          BinaryOperator.Opcode bOpcode;\n          Bpl.Type typ;\n          var oe0 = e0;\n          var oe1 = e1;\n          var lit0 = translator.GetLit(e0);\n          var lit1 = translator.GetLit(e1);\n          bool liftLit = lit0 != null && lit1 != null;\n          // NOTE(namin): We usually avoid keeping literals, because their presence might mess up triggers that do not expect them.\n          //              Still for equality-related operations, it's useful to keep them instead of lifting them, so that they can be propagated.\n          bool keepLits = false;\n          if (lit0 != null) {\n            e0 = lit0;\n          }\n          if (lit1 != null) {\n            e1 = lit1;\n          }\n          switch (e.ResolvedOp) {\n            case BinaryExpr.ResolvedOpcode.Iff:\n              typ = Bpl.Type.Bool;\n              bOpcode = BinaryOperator.Opcode.Iff; break;\n            case BinaryExpr.ResolvedOpcode.Imp:\n              typ = Bpl.Type.Bool;\n              bOpcode = BinaryOperator.Opcode.Imp; break;\n            case BinaryExpr.ResolvedOpcode.And:\n              typ = Bpl.Type.Bool;\n              bOpcode = BinaryOperator.Opcode.And; break;\n            case BinaryExpr.ResolvedOpcode.Or:\n              typ = Bpl.Type.Bool;\n              bOpcode = BinaryOperator.Opcode.Or; break;\n\n            case BinaryExpr.ResolvedOpcode.EqCommon:\n              keepLits = true;\n              var cot = e.E0.Type.AsCoDatatype;\n              if (cot != null) {\n                var e0args = e.E0.Type.NormalizeExpand().TypeArgs;\n                var e1args = e.E1.Type.NormalizeExpand().TypeArgs;\n                return translator.CoEqualCall(cot, e0args, e1args, null, this.layerInterCluster.LayerN((int)FuelSetting.FuelAmount.HIGH), e0, e1, expr.tok);\n              }\n              if (e.E0.Type.IsIndDatatype) {\n                return translator.TypeSpecificEqual(expr.tok, e.E0.Type, e0, e1);\n              }\n              typ = Bpl.Type.Bool;\n              bOpcode = BinaryOperator.Opcode.Eq; break;\n            case BinaryExpr.ResolvedOpcode.NeqCommon:\n              var cotx = e.E0.Type.AsCoDatatype;\n              if (cotx != null) {\n                var e0args = e.E0.Type.NormalizeExpand().TypeArgs;\n                var e1args = e.E1.Type.NormalizeExpand().TypeArgs;\n                var eq = translator.CoEqualCall(cotx, e0args, e1args, null, this.layerInterCluster.LayerN((int)FuelSetting.FuelAmount.HIGH), e0, e1, expr.tok);\n                return Bpl.Expr.Unary(expr.tok, UnaryOperator.Opcode.Not, eq);\n              }\n              if (e.E0.Type.IsIndDatatype) {\n                var eq = translator.TypeSpecificEqual(expr.tok, e.E0.Type, e0, e1);\n                return Bpl.Expr.Unary(expr.tok, UnaryOperator.Opcode.Not, eq);\n              }\n              typ = Bpl.Type.Bool;\n              bOpcode = BinaryOperator.Opcode.Neq; break;\n            case BinaryExpr.ResolvedOpcode.Lt:\n              if (0 <= bvWidth) {\n                return TrToFunctionCall(expr.tok, \"lt_bv\" + bvWidth, Bpl.Type.Bool, e0, e1, liftLit);\n              } else if (e.E0.Type.IsBigOrdinalType) {\n                return translator.FunctionCall(expr.tok, \"ORD#Less\", Bpl.Type.Bool, e0, e1);\n              } else if (isReal || !ArmadaOptions.O.DisableNLarith) {\n                typ = Bpl.Type.Bool;\n                bOpcode = BinaryOperator.Opcode.Lt;\n                break;\n              } else {\n                return TrToFunctionCall(expr.tok, \"INTERNAL_lt_boogie\", Bpl.Type.Bool, e0, e1, liftLit);\n              }\n            case BinaryExpr.ResolvedOpcode.LessThanLimit:\n              return translator.FunctionCall(expr.tok, \"ORD#LessThanLimit\", Bpl.Type.Bool, e0, e1);\n            case BinaryExpr.ResolvedOpcode.Le:\n              keepLits = true;\n              if (0 <= bvWidth) {\n                return TrToFunctionCall(expr.tok, \"le_bv\" + bvWidth, Bpl.Type.Bool, e0, e1, false);\n              } else if (e.E0.Type.IsBigOrdinalType) {\n                var less = translator.FunctionCall(expr.tok, \"ORD#Less\", Bpl.Type.Bool, e0, e1);\n                var eq = Bpl.Expr.Eq(e0, e1);\n                return BplOr(eq, less);\n              } else if (isReal || !ArmadaOptions.O.DisableNLarith) {\n                typ = Bpl.Type.Bool;\n                bOpcode = BinaryOperator.Opcode.Le;\n                break;\n              } else {\n                return TrToFunctionCall(expr.tok, \"INTERNAL_le_boogie\", Bpl.Type.Bool, e0, e1, false);\n              }\n            case BinaryExpr.ResolvedOpcode.Ge:\n              keepLits = true;\n              if (0 <= bvWidth) {\n                return TrToFunctionCall(expr.tok, \"ge_bv\" + bvWidth, Bpl.Type.Bool, e0, e1, false);\n              } else if (e.E0.Type.IsBigOrdinalType) {\n                var less = translator.FunctionCall(expr.tok, \"ORD#Less\", Bpl.Type.Bool, e1, e0);\n                var eq = Bpl.Expr.Eq(e1, e0);\n                return BplOr(eq, less);\n              } else if (isReal || !ArmadaOptions.O.DisableNLarith) {\n                typ = Bpl.Type.Bool;\n                bOpcode = BinaryOperator.Opcode.Ge;\n                break;\n              } else {\n                return TrToFunctionCall(expr.tok, \"INTERNAL_ge_boogie\", Bpl.Type.Bool, e0, e1, false);\n              }\n            case BinaryExpr.ResolvedOpcode.Gt:\n              if (0 <= bvWidth) {\n                return TrToFunctionCall(expr.tok, \"gt_bv\" + bvWidth, Bpl.Type.Bool, e0, e1, liftLit);\n              } else if (e.E0.Type.IsBigOrdinalType) {\n                return translator.FunctionCall(expr.tok, \"ORD#Less\", Bpl.Type.Bool, e1, e0);\n              } else if (isReal || !ArmadaOptions.O.DisableNLarith) {\n                typ = Bpl.Type.Bool;\n                bOpcode = BinaryOperator.Opcode.Gt;\n                break;\n              } else {\n                return TrToFunctionCall(expr.tok, \"INTERNAL_gt_boogie\", Bpl.Type.Bool, e0, e1, liftLit);\n              }\n\n            case BinaryExpr.ResolvedOpcode.Add:\n              if (0 <= bvWidth) {\n                return TrToFunctionCall(expr.tok, \"add_bv\" + bvWidth, translator.BplBvType(bvWidth), e0, e1, liftLit);\n              } else if (e.E0.Type.IsBigOrdinalType) {\n                return TrToFunctionCall(expr.tok, \"ORD#Plus\", predef.BigOrdinalType, e0, e1, liftLit);\n              } else if (e.E0.Type.IsCharType) {\n                return TrToFunctionCall(expr.tok, \"char#Plus\", predef.CharType, e0, e1, liftLit);\n              } else if (!isReal && ArmadaOptions.O.DisableNLarith) {\n                return TrToFunctionCall(expr.tok, \"INTERNAL_add_boogie\", Bpl.Type.Int, e0, e1, liftLit);\n              } else if (!isReal && (ArmadaOptions.O.ArithMode == 2 || 5 <= ArmadaOptions.O.ArithMode)) {\n                return TrToFunctionCall(expr.tok, \"Add\", Bpl.Type.Int, oe0, oe1, liftLit);\n              } else {\n                typ = isReal ? Bpl.Type.Real : Bpl.Type.Int;\n                bOpcode = BinaryOperator.Opcode.Add;\n                break;\n              }\n            case BinaryExpr.ResolvedOpcode.Sub:\n              if (0 <= bvWidth) {\n                return TrToFunctionCall(expr.tok, \"sub_bv\" + bvWidth, translator.BplBvType(bvWidth), e0, e1, liftLit);\n              } else if (e.E0.Type.IsBigOrdinalType) {\n                return TrToFunctionCall(expr.tok, \"ORD#Minus\", predef.BigOrdinalType, e0, e1, liftLit);\n              } else if (e.E0.Type.IsCharType) {\n                return TrToFunctionCall(expr.tok, \"char#Minus\", predef.CharType, e0, e1, liftLit);\n              } else if (!isReal && ArmadaOptions.O.DisableNLarith) {\n                return TrToFunctionCall(expr.tok, \"INTERNAL_sub_boogie\", Bpl.Type.Int, e0, e1, liftLit);\n              } else if (!isReal && (ArmadaOptions.O.ArithMode == 2 || 5 <= ArmadaOptions.O.ArithMode)) {\n                return TrToFunctionCall(expr.tok, \"Sub\", Bpl.Type.Int, oe0, oe1, liftLit);\n              } else {\n                typ = isReal ? Bpl.Type.Real : Bpl.Type.Int;\n                bOpcode = BinaryOperator.Opcode.Sub;\n                break;\n              }\n            case BinaryExpr.ResolvedOpcode.Mul:\n              if (0 <= bvWidth) {\n                return TrToFunctionCall(expr.tok, \"mul_bv\" + bvWidth, translator.BplBvType(bvWidth), e0, e1, liftLit);\n              } else if (!isReal && ArmadaOptions.O.DisableNLarith) {\n                return TrToFunctionCall(expr.tok, \"INTERNAL_mul_boogie\", Bpl.Type.Int, e0, e1, liftLit);\n              } else if (!isReal && ArmadaOptions.O.ArithMode != 0 && ArmadaOptions.O.ArithMode != 3) {\n                return TrToFunctionCall(expr.tok, \"Mul\", Bpl.Type.Int, oe0, oe1, liftLit);\n              } else {\n                typ = isReal ? Bpl.Type.Real : Bpl.Type.Int;\n                bOpcode = BinaryOperator.Opcode.Mul;\n                break;\n              }\n            case BinaryExpr.ResolvedOpcode.Div:\n              if (0 <= bvWidth) {\n                return TrToFunctionCall(expr.tok, \"div_bv\" + bvWidth, translator.BplBvType(bvWidth), e0, e1, liftLit);\n              } else if (!isReal && ArmadaOptions.O.DisableNLarith && !isReal) {\n                return TrToFunctionCall(expr.tok, \"INTERNAL_div_boogie\", Bpl.Type.Int, e0, e1, liftLit);\n              } else if (!isReal && ArmadaOptions.O.ArithMode != 0 && ArmadaOptions.O.ArithMode != 3) {\n                return TrToFunctionCall(expr.tok, \"Div\", Bpl.Type.Int, e0, oe1, liftLit);\n              } else if (isReal) {\n                typ = Bpl.Type.Real;\n                bOpcode = BinaryOperator.Opcode.RealDiv;\n                break;\n              } else {\n                typ = Bpl.Type.Int;\n                bOpcode = BinaryOperator.Opcode.Div;\n                break;\n              }\n            case BinaryExpr.ResolvedOpcode.Mod:\n              if (0 <= bvWidth) {\n                return TrToFunctionCall(expr.tok, \"mod_bv\" + bvWidth, translator.BplBvType(bvWidth), e0, e1, liftLit);\n              } else if (ArmadaOptions.O.DisableNLarith && !isReal) {\n                return TrToFunctionCall(expr.tok, \"INTERNAL_mod_boogie\", Bpl.Type.Int, e0, e1, liftLit);\n              } else if (!isReal && ArmadaOptions.O.ArithMode != 0 && ArmadaOptions.O.ArithMode != 3) {\n                return TrToFunctionCall(expr.tok, \"Mod\", Bpl.Type.Int, e0, oe1, liftLit);\n              } else {\n                typ = isReal ? Bpl.Type.Real : Bpl.Type.Int;\n                bOpcode = BinaryOperator.Opcode.Mod;\n                break;\n              }\n\n            case BinaryExpr.ResolvedOpcode.LeftShift: {\n                Contract.Assert(0 <= bvWidth);\n                return TrToFunctionCall(expr.tok, \"LeftShift_bv\" + bvWidth, translator.BplBvType(bvWidth), e0, translator.ConvertExpression(expr.tok, e1, e.E1.Type, e.Type), liftLit);\n              }\n            case BinaryExpr.ResolvedOpcode.RightShift: {\n                Contract.Assert(0 <= bvWidth);\n                return TrToFunctionCall(expr.tok, \"RightShift_bv\" + bvWidth, translator.BplBvType(bvWidth), e0, translator.ConvertExpression(expr.tok, e1, e.E1.Type, e.Type), liftLit);\n              }\n            case BinaryExpr.ResolvedOpcode.BitwiseAnd: {\n              Contract.Assert(0 <= bvWidth);\n              return TrToFunctionCall(expr.tok, \"and_bv\" + bvWidth, translator.BplBvType(bvWidth), e0, e1, liftLit);\n            }\n            case BinaryExpr.ResolvedOpcode.BitwiseOr: {\n                Contract.Assert(0 <= bvWidth);\n                return TrToFunctionCall(expr.tok, \"or_bv\" + bvWidth, translator.BplBvType(bvWidth), e0, e1, liftLit);\n              }\n            case BinaryExpr.ResolvedOpcode.BitwiseXor: {\n                Contract.Assert(0 <= bvWidth);\n                return TrToFunctionCall(expr.tok, \"xor_bv\" + bvWidth, translator.BplBvType(bvWidth), e0, e1, liftLit);\n              }\n\n            case BinaryExpr.ResolvedOpcode.LtChar:\n            case BinaryExpr.ResolvedOpcode.LeChar:\n            case BinaryExpr.ResolvedOpcode.GeChar:\n            case BinaryExpr.ResolvedOpcode.GtChar: {\n                // work off the original operands (that is, allow them to be lit-wrapped)\n                var operand0 = translator.FunctionCall(e0.tok, BuiltinFunction.CharToInt, null, oe0);\n                var operand1 = translator.FunctionCall(e0.tok, BuiltinFunction.CharToInt, null, oe1);\n                BinaryOperator.Opcode bOp;\n                switch (e.ResolvedOp) {\n                  case BinaryExpr.ResolvedOpcode.LtChar:  bOp = BinaryOperator.Opcode.Lt; break;\n                  case BinaryExpr.ResolvedOpcode.LeChar: bOp = BinaryOperator.Opcode.Le; break;\n                  case BinaryExpr.ResolvedOpcode.GeChar: bOp = BinaryOperator.Opcode.Ge; break;\n                  case BinaryExpr.ResolvedOpcode.GtChar: bOp = BinaryOperator.Opcode.Gt; break;\n                  default:\n                    Contract.Assert(false);  // unexpected case\n                    throw new cce.UnreachableException();  // to please compiler\n                }\n                return Bpl.Expr.Binary(expr.tok, bOp, operand0, operand1);\n              }\n\n            case BinaryExpr.ResolvedOpcode.SetEq:\n            case BinaryExpr.ResolvedOpcode.MultiSetEq:\n            case BinaryExpr.ResolvedOpcode.SeqEq:\n            case BinaryExpr.ResolvedOpcode.MapEq:\n              return translator.TypeSpecificEqual(expr.tok, e.E0.Type, e0, e1);\n            case BinaryExpr.ResolvedOpcode.SetNeq:\n            case BinaryExpr.ResolvedOpcode.MultiSetNeq:\n            case BinaryExpr.ResolvedOpcode.SeqNeq:\n            case BinaryExpr.ResolvedOpcode.MapNeq:\n              return Bpl.Expr.Unary(expr.tok, UnaryOperator.Opcode.Not, translator.TypeSpecificEqual(expr.tok, e.E0.Type, e0, e1));\n\n            case BinaryExpr.ResolvedOpcode.ProperSubset: {\n              return translator.ProperSubset(expr.tok, e0, e1);\n            }\n            case BinaryExpr.ResolvedOpcode.Subset: {\n              bool finite = e.E1.Type.AsSetType.Finite;\n              var f = finite ? BuiltinFunction.SetSubset : BuiltinFunction.ISetSubset;\n              return translator.FunctionCall(expr.tok, f, null, e0, e1);\n            }\n            case BinaryExpr.ResolvedOpcode.Superset: {\n              bool finite = e.E1.Type.AsSetType.Finite;\n              var f = finite ? BuiltinFunction.SetSubset : BuiltinFunction.ISetSubset;\n              return translator.FunctionCall(expr.tok, f, null, e1, e0);\n            }\n            case BinaryExpr.ResolvedOpcode.ProperSuperset:\n              return translator.ProperSubset(expr.tok, e1, e0);\n            case BinaryExpr.ResolvedOpcode.Disjoint: {\n              bool finite = e.E1.Type.AsSetType.Finite;\n              var f = finite ? BuiltinFunction.SetDisjoint : BuiltinFunction.ISetDisjoint;\n              return translator.FunctionCall(expr.tok, f, null, e0, e1);\n            }\n            case BinaryExpr.ResolvedOpcode.InSet:\n              Contract.Assert(false); throw new cce.UnreachableException();  // this case handled above\n            case BinaryExpr.ResolvedOpcode.NotInSet:\n              Contract.Assert(false); throw new cce.UnreachableException();  // this case handled above\n            case BinaryExpr.ResolvedOpcode.Union: {\n              bool finite = e.E1.Type.AsSetType.Finite;\n              var f = finite ? BuiltinFunction.SetUnion : BuiltinFunction.ISetUnion;\n              return translator.FunctionCall(expr.tok, f, translator.TrType(expr.Type.AsSetType.Arg), e0, e1);\n            }\n            case BinaryExpr.ResolvedOpcode.Intersection: {\n              bool finite = e.E1.Type.AsSetType.Finite;\n              var f = finite ? BuiltinFunction.SetIntersection : BuiltinFunction.ISetIntersection;\n              return translator.FunctionCall(expr.tok, f, translator.TrType(expr.Type.AsSetType.Arg), e0, e1);\n            }\n            case BinaryExpr.ResolvedOpcode.SetDifference: {\n              bool finite = e.E1.Type.AsSetType.Finite;\n              var f = finite ? BuiltinFunction.SetDifference : BuiltinFunction.ISetDifference;\n              return translator.FunctionCall(expr.tok, f, translator.TrType(expr.Type.AsSetType.Arg), e0, e1);\n            }\n            case BinaryExpr.ResolvedOpcode.ProperMultiSubset:\n              return translator.ProperMultiset(expr.tok, e0, e1);\n            case BinaryExpr.ResolvedOpcode.MultiSubset:\n              return translator.FunctionCall(expr.tok, BuiltinFunction.MultiSetSubset, null, e0, e1);\n            case BinaryExpr.ResolvedOpcode.MultiSuperset:\n              return translator.FunctionCall(expr.tok, BuiltinFunction.MultiSetSubset, null, e1, e0);\n            case BinaryExpr.ResolvedOpcode.ProperMultiSuperset:\n              return translator.ProperMultiset(expr.tok, e1, e0);\n            case BinaryExpr.ResolvedOpcode.MultiSetDisjoint:\n              return translator.FunctionCall(expr.tok, BuiltinFunction.MultiSetDisjoint, null, e0, e1);\n            case BinaryExpr.ResolvedOpcode.InMultiSet:\n              Contract.Assert(false); throw new cce.UnreachableException();  // this case handled above\n            case BinaryExpr.ResolvedOpcode.NotInMultiSet:\n              Contract.Assert(false); throw new cce.UnreachableException();  // this case handled above\n            case BinaryExpr.ResolvedOpcode.MultiSetUnion:\n              return translator.FunctionCall(expr.tok, BuiltinFunction.MultiSetUnion, translator.TrType(expr.Type.AsMultiSetType.Arg), e0, e1);\n            case BinaryExpr.ResolvedOpcode.MultiSetIntersection:\n              return translator.FunctionCall(expr.tok, BuiltinFunction.MultiSetIntersection, translator.TrType(expr.Type.AsMultiSetType.Arg), e0, e1);\n            case BinaryExpr.ResolvedOpcode.MultiSetDifference:\n              return translator.FunctionCall(expr.tok, BuiltinFunction.MultiSetDifference, translator.TrType(expr.Type.AsMultiSetType.Arg), e0, e1);\n\n            case BinaryExpr.ResolvedOpcode.ProperPrefix:\n              return translator.ProperPrefix(expr.tok, e0, e1);\n            case BinaryExpr.ResolvedOpcode.Prefix:\n              {\n                Bpl.Expr len0 = translator.FunctionCall(expr.tok, BuiltinFunction.SeqLength, null, e0);\n                Bpl.Expr len1 = translator.FunctionCall(expr.tok, BuiltinFunction.SeqLength, null, e1);\n                return Bpl.Expr.Binary(expr.tok, BinaryOperator.Opcode.And,\n                  Bpl.Expr.Le(len0, len1),\n                  translator.FunctionCall(expr.tok, BuiltinFunction.SeqSameUntil, null, e0, e1, len0));\n              }\n            case BinaryExpr.ResolvedOpcode.Concat:\n              return translator.FunctionCall(expr.tok, BuiltinFunction.SeqAppend, translator.TrType(expr.Type.AsSeqType.Arg), e0, e1);\n            case BinaryExpr.ResolvedOpcode.InSeq:\n              return translator.FunctionCall(expr.tok, BuiltinFunction.SeqContains, null, e1,\n                       BoxIfNecessary(expr.tok, e0, cce.NonNull(e.E0.Type)));\n            case BinaryExpr.ResolvedOpcode.NotInSeq:\n              Bpl.Expr arg = translator.FunctionCall(expr.tok, BuiltinFunction.SeqContains, null, e1,\n                       BoxIfNecessary(expr.tok, e0, cce.NonNull(e.E0.Type)));\n              return Bpl.Expr.Unary(expr.tok, UnaryOperator.Opcode.Not, arg);\n            case BinaryExpr.ResolvedOpcode.InMap: {\n              bool finite = e.E1.Type.AsMapType.Finite;\n              var f = finite ? BuiltinFunction.MapDomain : BuiltinFunction.IMapDomain;\n              return Bpl.Expr.SelectTok(expr.tok, translator.FunctionCall(expr.tok, f, predef.MapType(e.tok, finite, predef.BoxType, predef.BoxType), e1),\n                                     BoxIfNecessary(expr.tok, e0, e.E0.Type));\n            }\n            case BinaryExpr.ResolvedOpcode.NotInMap: {\n              bool finite = e.E1.Type.AsMapType.Finite;\n              var f = finite ? BuiltinFunction.MapDomain : BuiltinFunction.IMapDomain;\n              Bpl.Expr inMap = Bpl.Expr.SelectTok(expr.tok, translator.FunctionCall(expr.tok, f, predef.MapType(e.tok, finite, predef.BoxType, predef.BoxType), e1),\n                                     BoxIfNecessary(expr.tok, e0, e.E0.Type));\n              return Bpl.Expr.Unary(expr.tok, UnaryOperator.Opcode.Not, inMap);\n            }\n            case BinaryExpr.ResolvedOpcode.MapDisjoint: {\n              return translator.FunctionCall(expr.tok, BuiltinFunction.MapDisjoint, null, e0, e1);\n            }\n\n            case BinaryExpr.ResolvedOpcode.RankLt:\n              return Bpl.Expr.Binary(expr.tok, BinaryOperator.Opcode.Lt,\n                translator.FunctionCall(expr.tok, e.E0.Type.IsDatatype ? BuiltinFunction.DtRank : BuiltinFunction.BoxRank, null, e0),\n                translator.FunctionCall(expr.tok, BuiltinFunction.DtRank, null, e1));\n            case BinaryExpr.ResolvedOpcode.RankGt:\n              return Bpl.Expr.Binary(expr.tok, BinaryOperator.Opcode.Gt,\n                translator.FunctionCall(expr.tok, BuiltinFunction.DtRank, null, e0),\n                translator.FunctionCall(expr.tok, e.E1.Type.IsDatatype ? BuiltinFunction.DtRank: BuiltinFunction.BoxRank, null, e1));\n\n            default:\n              Contract.Assert(false); throw new cce.UnreachableException();  // unexpected binary expression\n          }\n          liftLit = liftLit && !keepLits;\n          var ae0 = keepLits ? oe0 : e0;\n          var ae1 = keepLits ? oe1 : e1;\n          Bpl.Expr re = Bpl.Expr.Binary(expr.tok, bOpcode, ae0, ae1);\n          if (liftLit) {\n            re = MaybeLit(re, typ);\n          }\n          return re;\n        } else if (expr is TernaryExpr) {\n          var e = (TernaryExpr)expr;\n          var e0 = TrExpr(e.E0);\n          if (!TernaryExpr.PrefixEqUsesNat && !e.E0.Type.IsBigOrdinalType) {\n            e0 = translator.FunctionCall(e0.tok, \"ORD#FromNat\", predef.BigOrdinalType, e0);\n          }\n          var e1 = TrExpr(e.E1);\n          var e2 = TrExpr(e.E2);\n          switch (e.Op) {\n            case TernaryExpr.Opcode.PrefixEqOp:\n            case TernaryExpr.Opcode.PrefixNeqOp:\n              var e1type = e.E1.Type.NormalizeExpand();\n              var e2type = e.E2.Type.NormalizeExpand();\n              var cot = e1type.AsCoDatatype;\n              Contract.Assert(cot != null);  // the argument types of prefix equality (and prefix disequality) are codatatypes\n              var r = translator.CoEqualCall(cot, e1type.TypeArgs, e2type.TypeArgs, e0, this.layerInterCluster.LayerN((int)FuelSetting.FuelAmount.HIGH), e1, e2);\n              if (e.Op == TernaryExpr.Opcode.PrefixEqOp) {\n                return r;\n              } else {\n                return Bpl.Expr.Unary(expr.tok, UnaryOperator.Opcode.Not, r);\n              }\n            default:\n              Contract.Assert(false); throw new cce.UnreachableException();  // unexpected ternary expression\n          }\n        } else if (expr is LetExpr) {\n          var e = (LetExpr)expr;\n          if (!e.Exact) {\n            var d = translator.LetDesugaring(e);\n            return TrExpr(d);\n          } else {\n            List<Bpl.Variable> lhss;\n            List<Bpl.Expr> rhss;\n            TrLetExprPieces(e, out lhss, out rhss);\n            // in the following, use the token for Body instead of the token for the whole let expression; this gives better error locations\n            return new Bpl.LetExpr(e.Body.tok, lhss, rhss, null, TrExpr(e.Body));\n          }\n        } else if (expr is NamedExpr) {\n          return TrExpr(((NamedExpr)expr).Body);\n        } else if (expr is QuantifierExpr) {\n          QuantifierExpr e = (QuantifierExpr)expr;\n\n          if (e.SplitQuantifier != null) {\n            return TrExpr(e.SplitQuantifierExpression);\n          } else {\n            List<Variable> tyvars = translator.MkTyParamBinders(e.TypeArgs);\n            List<Variable> bvars = new List<Variable>();\n            var bodyEtran = this;\n            if (e is ExistsExpr && translator.stmtContext == StmtType.ASSERT && translator.adjustFuelForExists) {\n              // assert exists need decrease fuel by 1\n              bodyEtran = bodyEtran.DecreaseFuel(1);\n              // set adjustFuelForExists to false so that we don't keep decrease the fuel in cases like the expr below.\n              // assert exists p:int :: exists t:T :: ToInt(t) > 0;\n              translator.adjustFuelForExists = false;\n            } else if (e is ExistsExpr && translator.stmtContext == StmtType.ASSUME && translator.adjustFuelForExists) {\n              // assume exists need increase fuel by 1\n              bodyEtran = bodyEtran.LayerOffset(1);\n              translator.adjustFuelForExists = false;\n            }\n\n            var initEtran = this;\n            bool _scratch = true;\n\n            Bpl.Expr antecedent = Bpl.Expr.True;\n\n            if (Attributes.ContainsBool(e.Attributes, \"layerQuantifier\", ref _scratch)) {\n              // If this is a layer quantifier, quantify over layers here, and use $LS(ly) layers in the translation of the body\n              var ly = BplBoundVar(e.Refresh(\"q$ly#\", translator.CurrentIdGenerator), predef.LayerType, bvars);\n              bodyEtran = bodyEtran.ReplaceLayer(ly);\n            }\n            if (Attributes.ContainsBool(e.Attributes, \"heapQuantifier\", ref _scratch)) {\n              var h = BplBoundVar(e.Refresh(\"q$heap#\", translator.CurrentIdGenerator), predef.HeapType, bvars);\n              bodyEtran = new ExpressionTranslator(bodyEtran, h);\n              antecedent = BplAnd(new List<Bpl.Expr> {\n                antecedent,\n                translator.FunctionCall(e.tok, BuiltinFunction.IsGoodHeap, null, h),\n                translator.HeapSameOrSucc(initEtran.HeapExpr, h)  // initHeapForAllStmt\n              });\n            }\n\n            List<bool> freeOfAlloc = null;\n            if (FrugalHeapUseX) {\n              freeOfAlloc = ComprehensionExpr.BoundedPool.HasBounds(e.Bounds, ComprehensionExpr.BoundedPool.PoolVirtues.IndependentOfAlloc_or_ExplicitAlloc);\n            }\n            antecedent = BplAnd(antecedent, bodyEtran.TrBoundVariables(e.BoundVars, bvars, false, freeOfAlloc)); // initHeapForAllStmt\n\n            Bpl.QKeyValue kv = TrAttributes(e.Attributes, \"trigger\");\n            Bpl.Trigger tr = translator.TrTrigger(bodyEtran, e.Attributes, e.tok, bvars, null, null);\n\n            if (e.Range != null) {\n              antecedent = BplAnd(antecedent, bodyEtran.TrExpr(e.Range));\n            }\n            Bpl.Expr body = bodyEtran.TrExpr(e.Term);\n\n            if (e is ForallExpr) {\n              return new Bpl.ForallExpr(expr.tok, new List<TypeVariable>(), Concat(tyvars, bvars), kv, tr, Bpl.Expr.Imp(antecedent, body));\n            } else {\n              Contract.Assert(e is ExistsExpr);\n              return new Bpl.ExistsExpr(expr.tok, new List<TypeVariable>(), Concat(tyvars, bvars), kv, tr, Bpl.Expr.And(antecedent, body));\n            }\n          }\n        } else if (expr is SetComprehension) {\n          var e = (SetComprehension)expr;\n          List<bool> freeOfAlloc = null;\n          if (FrugalHeapUseX) {\n            freeOfAlloc = ComprehensionExpr.BoundedPool.HasBounds(e.Bounds, ComprehensionExpr.BoundedPool.PoolVirtues.IndependentOfAlloc_or_ExplicitAlloc);\n          }\n          // Translate \"set xs | R :: T\" into:\n          //     lambda y: BoxType :: (exists xs :: CorrectType(xs) && R && y==Box(T))\n          // or if \"T\" is \"xs\", then:\n          //     lambda y: BoxType :: CorrectType(y) && R[xs := Unbox(y)]\n          var yVar = new Bpl.BoundVariable(expr.tok, new Bpl.TypedIdent(expr.tok, translator.CurrentIdGenerator.FreshId(\"$y#\"), predef.BoxType));\n          Bpl.Expr y = new Bpl.IdentifierExpr(expr.tok, yVar);\n          Bpl.Expr lbody;\n          if (e.TermIsSimple) {\n            // lambda y: BoxType :: CorrectType(y) && R[xs := yUnboxed]\n            var bv = e.BoundVars[0];\n            Bpl.Expr typeAntecedent = translator.MkIsBox(new Bpl.IdentifierExpr(expr.tok, yVar), bv.Type);\n            if (freeOfAlloc != null && !freeOfAlloc[0]) {\n              var isAlloc = translator.MkIsAlloc(new Bpl.IdentifierExpr(expr.tok, yVar), bv.Type, HeapExpr);\n              typeAntecedent = BplAnd(typeAntecedent, isAlloc);\n            }\n            var yUnboxed = translator.UnboxIfBoxed(new Bpl.IdentifierExpr(expr.tok, yVar), bv.Type);\n            var range = Translator.Substitute(e.Range, bv, new BoogieWrapper(yUnboxed, bv.Type));\n            lbody = BplAnd(typeAntecedent, TrExpr(range));\n          } else {\n            // lambda y: BoxType :: (exists xs :: CorrectType(xs) && R && y==Box(T))\n            List<Variable> bvars = new List<Variable>();\n            Bpl.Expr typeAntecedent = TrBoundVariables(e.BoundVars, bvars, false, freeOfAlloc);\n\n            var eq = Bpl.Expr.Eq(y, BoxIfNecessary(expr.tok, TrExpr(e.Term), e.Term.Type));\n            var ebody = Bpl.Expr.And(BplAnd(typeAntecedent, TrExpr(e.Range)), eq);\n            var triggers = translator.TrTrigger(this, e.Attributes, e.tok);\n            lbody = new Bpl.ExistsExpr(expr.tok, bvars, triggers, ebody);\n          }\n          Bpl.QKeyValue kv = TrAttributes(e.Attributes, \"trigger\");\n          return new Bpl.LambdaExpr(expr.tok, new List<TypeVariable>(), new List<Variable> { yVar }, kv, lbody);\n\n        } else if (expr is MapComprehension) {\n          var e = (MapComprehension)expr;\n          // Translate \"map x,y | R(x,y) :: F(x,y) := G(x,y)\" into\n          // Map#Glue(lambda w: BoxType :: exists x,y :: R(x,y) && unbox(w) == F(x,y),\n          //          lambda w: BoxType :: G(project_x(unbox(w)), project_y(unbox(w))),\n          //          type)\".\n          // where project_x and project_y are functions defined (elsewhere, in CanCallAssumption) by the following axiom:\n          //     forall x,y :: R(x,y) ==> var x',y' := project_x(unbox(F(x,y))),project_y(unbox(F(x,y))); R(x',y') && F(x',y') == F(x,y)\n          // that is (without the let expression):\n          //     forall x,y :: R(x,y) ==> R(project_x(unbox(F(x,y))), project_y(unbox(F(x,y)))) && F(project_x(unbox(F(x,y))), project_y(unbox(F(x,y)))) == F(x,y)\n          //\n          // In the common case where F(x,y) is omitted (in which case the list of bound variables is restricted to length 1):\n          // Translate \"map x | R(x) :: G(x)\" into\n          // Map#Glue(lambda w: BoxType :: R(unbox(w)),\n          //          lambda w: BoxType :: G(unbox(w)),\n          //          type)\".\n          List<Variable> bvars = new List<Variable>();\n          List<bool> freeOfAlloc = null;\n          if (FrugalHeapUseX) {\n            freeOfAlloc = ComprehensionExpr.BoundedPool.HasBounds(e.Bounds, ComprehensionExpr.BoundedPool.PoolVirtues.IndependentOfAlloc_or_ExplicitAlloc);\n          }\n          TrBoundVariables(e.BoundVars, bvars, false, freeOfAlloc);\n\n          Bpl.QKeyValue kv = TrAttributes(e.Attributes, \"trigger\");\n\n          var wVar = new Bpl.BoundVariable(expr.tok, new Bpl.TypedIdent(expr.tok, translator.CurrentIdGenerator.FreshId(\"$w#\"), predef.BoxType));\n\n          Bpl.Expr keys, values;\n          if (!e.IsGeneralMapComprehension) {\n            var bv = e.BoundVars[0];\n            Bpl.Expr unboxw = translator.UnboxIfBoxed(new Bpl.IdentifierExpr(expr.tok, wVar), bv.Type);\n            Bpl.Expr typeAntecedent = translator.GetWhereClause(bv.tok, unboxw, bv.Type, this, NOALLOC);\n            var subst = new Dictionary<IVariable,Expression>();\n            subst.Add(bv, new BoogieWrapper(unboxw, bv.Type));\n\n            var ebody = BplAnd(typeAntecedent ?? Bpl.Expr.True, TrExpr(Translator.Substitute(e.Range, null, subst)));\n            keys = new Bpl.LambdaExpr(e.tok, new List<TypeVariable>(), new List<Variable> { wVar }, kv, ebody);\n            ebody = TrExpr(Translator.Substitute(e.Term, null, subst));\n            values = new Bpl.LambdaExpr(e.tok, new List<TypeVariable>(), new List<Variable> { wVar }, kv, BoxIfNecessary(expr.tok, ebody, e.Term.Type));\n          } else {\n            var t = e.TermLeft;\n            Bpl.Expr unboxw = translator.UnboxIfBoxed(new Bpl.IdentifierExpr(expr.tok, wVar), t.Type);\n            Bpl.Expr typeAntecedent = translator.GetWhereClause(t.tok, unboxw, t.Type, this, NOALLOC);\n            List<Bpl.Variable> bvs;\n            List<Bpl.Expr> args;\n            translator.CreateBoundVariables(e.BoundVars, out bvs, out args);\n            Contract.Assert(e.BoundVars.Count == bvs.Count);\n            var subst = new Dictionary<IVariable, Expression>();\n            for (var i = 0; i < e.BoundVars.Count; i++) {\n              subst.Add(e.BoundVars[i], new BoogieWrapper(args[i], e.BoundVars[i].Type));\n            }\n            var rr = TrExpr(Translator.Substitute(e.Range, null, subst));\n            var ff = TrExpr(Translator.Substitute(t, null, subst));\n            var exst_body = BplAnd(rr, Bpl.Expr.Eq(unboxw, ff));\n            var ebody = BplAnd(typeAntecedent ?? Bpl.Expr.True, new Bpl.ExistsExpr(e.tok, bvs, exst_body));\n            keys = new Bpl.LambdaExpr(e.tok, new List<TypeVariable>(), new List<Variable> { wVar }, kv, ebody);\n\n            translator.CreateMapComprehensionProjectionFunctions(e);\n            Contract.Assert(e.ProjectionFunctions != null && e.ProjectionFunctions.Count == e.BoundVars.Count);\n            subst = new Dictionary<IVariable, Expression>();\n            for (var i = 0; i < e.BoundVars.Count; i++) {\n              var p = new Bpl.NAryExpr(e.tok, new Bpl.FunctionCall(e.ProjectionFunctions[i]), new List<Bpl.Expr> { unboxw });\n              var prj = new BoogieWrapper(p, e.BoundVars[i].Type);\n              subst.Add(e.BoundVars[i], prj);\n            }\n            ebody = TrExpr(Translator.Substitute(e.Term, null, subst));\n            values = new Bpl.LambdaExpr(e.tok, new List<TypeVariable>(), new List<Variable> { wVar }, kv, BoxIfNecessary(expr.tok, ebody, e.Term.Type));\n          }\n\n          bool finite = e.Finite;\n          var f = finite ? BuiltinFunction.MapGlue : BuiltinFunction.IMapGlue;\n          return translator.FunctionCall(e.tok, f, null, keys, values, translator.TypeToTy(expr.Type));\n\n        } else if (expr is LambdaExpr) {\n          var e = (LambdaExpr)expr;\n          return TrLambdaExpr(e);\n\n        } else if (expr is StmtExpr) {\n          var e = (StmtExpr)expr;\n          return TrExpr(e.E);\n\n        } else if (expr is ITEExpr) {\n          ITEExpr e = (ITEExpr)expr;\n          var g = translator.RemoveLit(TrExpr(e.Test));\n          var thn = translator.RemoveLit(TrExpr(e.Thn));\n          var els = translator.RemoveLit(TrExpr(e.Els));\n          return new NAryExpr(expr.tok, new IfThenElse(expr.tok), new List<Bpl.Expr> { g, thn, els });\n\n        } else if (expr is MatchExpr) {\n          var e = (MatchExpr)expr;\n          var ite = DesugarMatchExpr(e);\n          return TrExpr(ite);\n\n        } else if (expr is ConcreteSyntaxExpression) {\n          var e = (ConcreteSyntaxExpression)expr;\n          return TrExpr(e.ResolvedExpression);\n\n        } else if (expr is RevealExpr) {\n          var e = (RevealExpr)expr;\n          return TrExpr(e.ResolvedExpression);\n\n        } else if (expr is BoxingCastExpr) {\n          BoxingCastExpr e = (BoxingCastExpr)expr;\n          return translator.CondApplyBox(e.tok, TrExpr(e.E), e.FromType, e.ToType);\n\n        } else if (expr is UnboxingCastExpr) {\n          UnboxingCastExpr e = (UnboxingCastExpr)expr;\n          return translator.CondApplyUnbox(e.tok, TrExpr(e.E), e.FromType, e.ToType);\n\n        } else {\n          Contract.Assert(false); throw new cce.UnreachableException();  // unexpected expression\n        }\n      }\n\n      public Expr TrExprSpecialFunctionCall(FunctionCallExpr expr) {\n        Contract.Requires(expr.Function is SpecialFunction);\n        string name = expr.Function.Name;\n        if (name == \"RotateLeft\") {\n          var w = expr.Type.AsBitVectorType.Width;\n          Expression arg = expr.Args[0];\n          return TrToFunctionCall(expr.tok, \"LeftRotate_bv\" + w, translator.BplBvType(w), TrExpr(expr.Receiver), translator.ConvertExpression(expr.tok, TrExpr(arg), arg.Type, expr.Type), false);\n        } else if (name == \"RotateRight\") {\n          var w = expr.Type.AsBitVectorType.Width;\n          Expression arg = expr.Args[0];\n          return TrToFunctionCall(expr.tok, \"RightRotate_bv\" + w, translator.BplBvType(w), TrExpr(expr.Receiver), translator.ConvertExpression(expr.tok, TrExpr(arg), arg.Type, expr.Type), false);\n        } else {\n          bool argsAreLit_dummy;\n          var args = FunctionInvocationArguments(expr, null, true, out argsAreLit_dummy);\n          var id = new Bpl.IdentifierExpr(expr.tok, expr.Function.FullSanitizedName, translator.TrType(expr.Type));\n          return new Bpl.NAryExpr(expr.tok, new Bpl.FunctionCall(id), args);\n        }\n      }\n      public Expr TrToFunctionCall(IToken tok, string function, Bpl.Type returnType, Bpl.Expr e0, Bpl.Expr e1, bool liftLit) {\n        Bpl.Expr re = translator.FunctionCall(tok, function, returnType, e0, e1);\n        if (liftLit) {\n          re = MaybeLit(re, returnType);\n        }\n        return re;\n      }\n\n      private Expr TrLambdaExpr(LambdaExpr e) {\n        Contract.Requires(e != null);\n\n        var bvars = new List<Bpl.Variable>();\n\n        var varNameGen = translator.CurrentIdGenerator.NestedFreshIdGenerator(\"$l#\");\n\n        var heap = BplBoundVar(varNameGen.FreshId(\"#heap#\"), predef.HeapType, bvars);\n\n        var ves = (from bv in e.BoundVars select\n          BplBoundVar(varNameGen.FreshId(string.Format(\"#{0}#\", bv.Name)), predef.BoxType, bvars)).ToList();\n        var subst = e.BoundVars.Zip(ves, (bv, ve) => {\n          var unboxy = translator.UnboxIfBoxed(ve, bv.Type);\n          return new KeyValuePair<IVariable, Expression>(bv, new BoogieWrapper(unboxy, bv.Type));\n        }).ToDictionary(x => x.Key, x => x.Value);\n        var su = new Substituter(null, subst, new Dictionary<TypeParameter, Type>());\n\n        var et = new ExpressionTranslator(this, heap);\n        var lvars = new List<Bpl.Variable>();\n        var ly = BplBoundVar(varNameGen.FreshId(\"#ly#\"), predef.LayerType, lvars);\n        et = et.WithLayer(ly);\n\n        var ebody = et.TrExpr(Translator.Substitute(e.Body, null, subst));\n        ebody = translator.BoxIfUnboxed(ebody, e.Body.Type);\n\n        var isBoxes = BplAnd(ves.Zip(e.BoundVars, (ve, bv) => translator.MkIsBox(ve, bv.Type)));\n        var reqbody = e.Range == null\n          ? isBoxes\n          : BplAnd(isBoxes, et.TrExpr(Translator.Substitute(e.Range, null, subst)));\n\n        var rdvars = new List<Bpl.Variable>();\n        var o = BplBoundVar(varNameGen.FreshId(\"#o#\"), predef.RefType, rdvars);\n        Bpl.Expr rdbody = new Bpl.LambdaExpr(e.tok, new List<TypeVariable>(), rdvars, null,\n          translator.InRWClause(e.tok, o, null, e.Reads.ConvertAll(su.SubstFrameExpr), et, null, null));\n        rdbody = translator.FunctionCall(e.tok, \"SetRef_to_SetBox\", predef.SetType(e.tok, true, predef.BoxType), rdbody);\n\n        return MaybeLit(\n          translator.FunctionCall(e.tok, BuiltinFunction.AtLayer, predef.HandleType,\n            new Bpl.LambdaExpr(e.tok, new List<TypeVariable>(), lvars, null,\n              translator.FunctionCall(e.tok, translator.Handle(e.BoundVars.Count), predef.BoxType,\n                new Bpl.LambdaExpr(e.tok, new List<TypeVariable>(), bvars, null, ebody),\n                new Bpl.LambdaExpr(e.tok, new List<TypeVariable>(), bvars, null, reqbody),\n                new Bpl.LambdaExpr(e.tok, new List<TypeVariable>(), bvars, null, rdbody))),\n                layerIntraCluster != null ? layerIntraCluster.ToExpr() : layerInterCluster.ToExpr()),\n          predef.HandleType);\n      }\n\n      public void TrLetExprPieces(LetExpr let, out List<Bpl.Variable> lhss, out List<Bpl.Expr> rhss) {\n        Contract.Requires(let != null);\n        var substMap = new Dictionary<IVariable, Expression>();\n        for (int i = 0; i < let.LHSs.Count; i++) {\n          translator.AddCasePatternVarSubstitutions(let.LHSs[i], TrExpr(let.RHSs[i]), substMap);\n        }\n        lhss = new List<Bpl.Variable>();\n        rhss = new List<Bpl.Expr>();\n        foreach (var v in let.BoundVars) {\n          var rhs = substMap[v];  // this should succeed (that is, \"v\" is in \"substMap\"), because the AddCasePatternVarSubstitutions calls above should have added a mapping for each bound variable in let.BoundVars\n          Bpl.Expr bvIde;  // unused\n          var bv = BplBoundVar(v.AssignUniqueName(translator.currentDeclaration.IdGenerator), translator.TrType(v.Type), out bvIde);\n          lhss.Add(bv);\n          rhss.Add(TrExpr(rhs));\n        }\n      }\n\n      public Expression DesugarMatchExpr(MatchExpr e) {\n        Contract.Requires(e != null);\n        // Translate:\n        //   match S\n        //   case C(i, j) => X\n        //   case D(k, l) => Y\n        //   case E(m, n) => Z\n        // into:\n        //   if S.C? then\n        //     X[i,j := S.dC0, S.dC1]\n        //   else if S.D? then\n        //     Y[k,l := S.dD0, S.dD1]\n        //   else\n        //     Z[m,n := S.dE0, S.dE1]\n        // As a special case, when there are no cases at all (which, in a correct program, means the\n        // match expression is unreachable), the translation is:\n        //   t\n        // where is \"t\" is some value (in particular, the default value) of the expected type.\n        Expression r = null;\n        for (int i = e.Cases.Count; 0 <= --i; ) {\n          var mc = e.Cases[i];\n          var substMap = new Dictionary<IVariable, Expression>();\n          var argIndex = 0;\n          foreach (var bv in mc.Arguments) {\n            if (!LocalVariable.HasWildcardName(bv)) {\n              var dtor = mc.Ctor.Destructors[argIndex];\n              var dv = new MemberSelectExpr(bv.tok, e.Source, dtor);\n              substMap.Add(bv, dv);\n            }\n            argIndex++;\n          }\n          var c = Translator.Substitute(mc.Body, null, substMap);\n          if (r == null) {\n            r = c;\n          } else {\n            var test = new MemberSelectExpr(mc.tok, e.Source, mc.Ctor.QueryField);\n            var ite = new ITEExpr(mc.tok, false, test, c, r);\n            ite.Type = e.Type;\n            r = ite;\n          }\n        }\n        return r ?? new BoogieWrapper(ArbitraryValue(e.Type), e.Type);\n      }\n\n      public Bpl.Expr TrBoundVariables(List<BoundVar/*!*/> boundVars, List<Variable> bvars) {\n        return TrBoundVariables(boundVars, bvars, false);\n      }\n\n      public Bpl.Expr TrBoundVariables(List<BoundVar/*!*/> boundVars, List<Variable> bvars, bool translateAsLocals, List<bool>/*?*/ freeOfAlloc = null) {\n        Contract.Requires(boundVars != null);\n        Contract.Requires(bvars != null);\n        Contract.Requires(freeOfAlloc == null || freeOfAlloc.Count == boundVars.Count);\n        Contract.Ensures(Contract.Result<Bpl.Expr>() != null);\n\n        Bpl.Expr typeAntecedent = Bpl.Expr.True;\n        var i = 0;\n        foreach (BoundVar bv in boundVars) {\n          var tid = new Bpl.TypedIdent(bv.tok, bv.AssignUniqueName(translator.currentDeclaration.IdGenerator), translator.TrType(bv.Type));\n          Bpl.Variable bvar;\n          if (translateAsLocals) {\n            bvar = new Bpl.LocalVariable(bv.tok, tid);\n          } else {\n            bvar = new Bpl.BoundVariable(bv.tok, tid);\n          }\n          bvars.Add(bvar);\n          var useAlloc = freeOfAlloc == null || freeOfAlloc[i] ? NOALLOC : ISALLOC;\n          Bpl.Expr wh = translator.GetWhereClause(bv.tok, new Bpl.IdentifierExpr(bv.tok, bvar), bv.Type, this, useAlloc);\n          if (wh != null) {\n            typeAntecedent = BplAnd(typeAntecedent, wh);\n          }\n          i++;\n        }\n        return typeAntecedent;\n      }\n\n      public List<Tuple<Bpl.Variable, Bpl.Expr>> TrBoundVariables_SeparateWhereClauses(List<BoundVar/*!*/> boundVars) {\n        Contract.Requires(boundVars != null);\n        Contract.Ensures(Contract.Result<List<Tuple<Bpl.Variable, Bpl.Expr>>>() != null);\n\n        var varsAndAntecedents = new List<Tuple<Bpl.Variable, Bpl.Expr>>();\n        foreach (BoundVar bv in boundVars) {\n          var tid = new Bpl.TypedIdent(bv.tok, bv.AssignUniqueName(translator.currentDeclaration.IdGenerator), translator.TrType(bv.Type));\n          var bvar = new Bpl.BoundVariable(bv.tok, tid);\n          var wh = translator.GetWhereClause(bv.tok, new Bpl.IdentifierExpr(bv.tok, bvar), bv.Type, this, NOALLOC);\n          varsAndAntecedents.Add(Tuple.Create<Bpl.Variable, Bpl.Expr>(bvar, wh));\n        }\n        return varsAndAntecedents;\n      }\n\n      public Bpl.Expr TrBoundVariablesRename(List<BoundVar> boundVars, List<Variable> bvars, out Dictionary<IVariable, Expression> substMap, out Bpl.Trigger antitriggers) {\n        Contract.Requires(boundVars != null);\n        Contract.Requires(bvars != null);\n\n        substMap = new Dictionary<IVariable, Expression>();\n        antitriggers = null;\n        Bpl.Expr typeAntecedent = Bpl.Expr.True;\n        foreach (BoundVar bv in boundVars) {\n          var newBoundVar = new BoundVar(bv.tok, bv.Name, bv.Type);\n          IdentifierExpr ie = new IdentifierExpr(newBoundVar.tok, newBoundVar.AssignUniqueName(translator.currentDeclaration.IdGenerator));\n          ie.Var = newBoundVar; ie.Type = ie.Var.Type;  // resolve ie here\n          substMap.Add(bv, ie);\n          Bpl.Variable bvar = new Bpl.BoundVariable(newBoundVar.tok, new Bpl.TypedIdent(newBoundVar.tok, newBoundVar.AssignUniqueName(translator.currentDeclaration.IdGenerator), translator.TrType(newBoundVar.Type)));\n          bvars.Add(bvar);\n          var bIe = new Bpl.IdentifierExpr(bvar.tok, bvar);\n          Bpl.Expr wh = translator.GetWhereClause(bv.tok, bIe, newBoundVar.Type, this, NOALLOC);\n          if (wh != null) {\n            typeAntecedent = BplAnd(typeAntecedent, wh);\n          }\n        }\n        return typeAntecedent;\n      }\n\n      public List<Bpl.Expr> FunctionInvocationArguments(FunctionCallExpr e, Bpl.Expr layerArgument) {\n        bool dummy;\n        return FunctionInvocationArguments(e, layerArgument, false, out dummy);\n      }\n\n      public List<Bpl.Expr> FunctionInvocationArguments(FunctionCallExpr e, Bpl.Expr layerArgument, bool omitHeapArgument, out bool argsAreLit) {\n        Contract.Requires(e != null);\n        Contract.Ensures(Contract.Result<List<Bpl.Expr>>() != null);\n\n        var args = new List<Bpl.Expr>();\n\n        // first add type arguments\n        var tyParams = GetTypeParams(e.Function);\n        var tySubst = e.TypeArgumentSubstitutions;\n        Contract.Assert(tyParams.Count == tySubst.Count);\n        args.AddRange(translator.trTypeArgs(tySubst, tyParams));\n\n        if (layerArgument != null) {\n          args.Add(layerArgument);\n        }\n        if (e.Function is TwoStateFunction) {\n          args.Add(Old.HeapExpr);\n        }\n        if (!omitHeapArgument && (AlwaysUseHeap || e.Function.ReadsHeap)) {\n          args.Add(HeapExpr);\n          // if the function doesn't use heaps, but always use heap as an argument\n          // we want to quantify over the heap so that heap in the trigger can match over\n          // heap modifying operations. (see Dafny4/bug144.dfy)\n          bool useHeap = e.Function.ReadsHeap;\n          if (!useHeap) {\n            foreach (var arg in e.Function.Formals) {\n              if (arg.Type.IsRefType) {\n                useHeap = true;\n                break;\n              }\n            }\n          }\n          if (!useHeap) {\n            Statistics_HeapAsQuantifierCount++;\n          }\n        }\n        if (!e.Function.IsStatic) {\n          args.Add(TrExpr(e.Receiver));\n        }\n        argsAreLit = true;\n        for (int i = 0; i < e.Args.Count; i++) {\n          Expression ee = e.Args[i];\n          Type t = e.Function.Formals[i].Type;\n          Expr tr_ee = TrExpr(ee);\n          argsAreLit = argsAreLit && translator.IsLit(tr_ee);\n          args.Add(translator.CondApplyBox(e.tok, tr_ee, cce.NonNull(ee.Type), t));\n        }\n        return args;\n      }\n\n      public Bpl.Expr GetArrayIndexFieldName(IToken tok, List<Expression> indices) {\n        return translator.GetArrayIndexFieldName(tok, Map(indices, TrExpr));\n      }\n\n      public Bpl.Expr BoxIfNecessary(IToken tok, Bpl.Expr e, Type fromType) {\n        Contract.Requires(tok != null);\n        Contract.Requires(e != null);\n        Contract.Requires(fromType != null);\n        Contract.Ensures(Contract.Result<Bpl.Expr>() != null);\n        return translator.BoxIfNecessary(tok, e, fromType);\n      }\n\n      public static Bpl.NAryExpr ReadHeap(IToken tok, Expr heap, Expr r, Expr f) {\n        Contract.Requires(tok != null);\n        Contract.Requires(heap != null);\n        Contract.Requires(r != null);\n        Contract.Requires(f != null);\n        Contract.Ensures(Contract.Result<Bpl.NAryExpr>() != null);\n\n        List<Bpl.Expr> args = new List<Bpl.Expr>();\n        args.Add(heap);\n        args.Add(r);\n        args.Add(f);\n        Bpl.Type t = (f.Type != null) ? f.Type : f.ShallowType;\n        return new Bpl.NAryExpr(tok,\n          new Bpl.FunctionCall(new Bpl.IdentifierExpr(tok, \"read\", t.AsCtor.Arguments[0])),\n          args);\n      }\n\n\n      public static Bpl.NAryExpr UpdateHeap(IToken tok, Expr heap, Expr r, Expr f, Expr v) {\n        Contract.Requires(tok != null);\n        Contract.Requires(heap != null);\n        Contract.Requires(r != null);\n        Contract.Requires(f != null);\n        Contract.Requires(v != null);\n        Contract.Ensures(Contract.Result<Bpl.NAryExpr>() != null);\n\n        List<Bpl.Expr> args = new List<Bpl.Expr>();\n        args.Add(heap);\n        args.Add(r);\n        args.Add(f);\n        args.Add(v);\n        return new Bpl.NAryExpr(tok,\n          new Bpl.FunctionCall(new Bpl.IdentifierExpr(tok, \"update\", heap.Type)),\n          args);\n      }\n\n      /// <summary>\n      /// Translate like s[Box(elmt)], but try to avoid as many set functions as possible in the\n      /// translation, because such functions can mess up triggering.\n      /// </summary>\n      public Bpl.Expr TrInSet(IToken tok, Bpl.Expr elmt, Expression s, Type elmtType, out bool performedRewrite) {\n        Contract.Requires(tok != null);\n        Contract.Requires(elmt != null);\n        Contract.Requires(s != null);\n        Contract.Requires(elmtType != null);\n        Contract.Ensures(Contract.Result<Bpl.Expr>() != null);\n\n        var elmtBox = BoxIfNecessary(tok, elmt, elmtType);\n        return TrInSet_Aux(tok, elmt, elmtBox, s, out performedRewrite);\n      }\n      /// <summary>\n      /// The worker routine for TrInSet.  This method takes both \"elmt\" and \"elmtBox\" as parameters,\n      /// using the former when the unboxed form is needed and the latter when the boxed form is needed.\n      /// This gives the caller the flexibility to pass in either \"o, Box(o)\" or \"Unbox(bx), bx\".\n      /// </summary>\n      public Bpl.Expr TrInSet_Aux(IToken tok, Bpl.Expr elmt, Bpl.Expr elmtBox, Expression s, out bool performedRewrite) {\n        Contract.Requires(tok != null);\n        Contract.Requires(elmt != null);\n        Contract.Requires(elmtBox != null);\n        Contract.Requires(s != null);\n        Contract.Ensures(Contract.Result<Bpl.Expr>() != null);\n\n        performedRewrite = true;  // assume a rewrite will happen\n        bool pr;\n        if (s is BinaryExpr) {\n          BinaryExpr bin = (BinaryExpr)s;\n          switch (bin.ResolvedOp) {\n            case BinaryExpr.ResolvedOpcode.Union:\n              return Bpl.Expr.Or(TrInSet_Aux(tok, elmt, elmtBox, bin.E0, out pr), TrInSet_Aux(tok, elmt, elmtBox, bin.E1, out pr));\n            case BinaryExpr.ResolvedOpcode.Intersection:\n              return Bpl.Expr.And(TrInSet_Aux(tok, elmt, elmtBox, bin.E0, out pr), TrInSet_Aux(tok, elmt, elmtBox, bin.E1, out pr));\n            case BinaryExpr.ResolvedOpcode.SetDifference:\n              return Bpl.Expr.And(TrInSet_Aux(tok, elmt, elmtBox, bin.E0, out pr), Bpl.Expr.Not(TrInSet_Aux(tok, elmt, elmtBox, bin.E1, out pr)));\n            default:\n              break;\n          }\n        } else if (s is SetDisplayExpr) {\n          SetDisplayExpr disp = (SetDisplayExpr)s;\n          Bpl.Expr disjunction = null;\n          foreach (Expression a in disp.Elements) {\n            Bpl.Expr disjunct = Bpl.Expr.Eq(elmt, TrExpr(a));\n            if (disjunction == null) {\n              disjunction = disjunct;\n            } else {\n              disjunction = Bpl.Expr.Or(disjunction, disjunct);\n            }\n          }\n          if (disjunction == null) {\n            return Bpl.Expr.False;\n          } else {\n            return disjunction;\n          }\n        } else if (s is SetComprehension) {\n          var compr = (SetComprehension)s;\n          // Translate \"elmt in set xs | R :: T\" into:\n          //     exists xs :: CorrectType(xs) && R && elmt==T\n          // or if \"T\" is \"xs\", then:\n          //     CorrectType(elmt) && R[xs := elmt]\n          if (compr.TermIsSimple) {\n            // CorrectType(elmt) && R[xs := elmt]\n            // Note, we can always use NOALLOC here.\n            Bpl.Expr typeAntecedent = translator.GetWhereClause(compr.tok, elmt, compr.BoundVars[0].Type, this, NOALLOC) ?? Bpl.Expr.True;\n            var range = Translator.Substitute(compr.Range, compr.BoundVars[0], new BoogieWrapper(elmt, compr.BoundVars[0].Type));\n            return BplAnd(typeAntecedent, TrExpr(range));\n          } else {\n            // exists xs :: CorrectType(xs) && R && elmt==T\n            List<bool> freeOfAlloc = null;\n            if (FrugalHeapUseX) {\n              freeOfAlloc = ComprehensionExpr.BoundedPool.HasBounds(compr.Bounds, ComprehensionExpr.BoundedPool.PoolVirtues.IndependentOfAlloc_or_ExplicitAlloc);\n            }\n            var bvars = new List<Variable>();\n            Bpl.Expr typeAntecedent = TrBoundVariables(compr.BoundVars, bvars, false, freeOfAlloc) ?? Bpl.Expr.True;\n            var eq = Bpl.Expr.Eq(elmtBox, BoxIfNecessary(compr.tok, TrExpr(compr.Term), compr.Term.Type));\n            var ebody = Bpl.Expr.And(BplAnd(typeAntecedent, TrExpr(compr.Range)), eq);\n            var triggers = translator.TrTrigger(this, compr.Attributes, compr.tok);\n            return new Bpl.ExistsExpr(compr.tok, bvars, triggers, ebody);\n          }\n        }\n        performedRewrite = false;\n        return Bpl.Expr.SelectTok(tok, TrExpr(s), elmtBox);\n      }\n\n      /// <summary>\n      /// Translate like 0 < s[Box(elmt)], but try to avoid as many set functions as possible in the\n      /// translation, because such functions can mess up triggering.\n      /// </summary>\n      public Bpl.Expr TrInMultiSet(IToken tok, Bpl.Expr elmt, Expression s, Type elmtType) {\n        Contract.Requires(tok != null);\n        Contract.Requires(elmt != null);\n        Contract.Requires(s != null);\n        Contract.Requires(elmtType != null);\n\n        Contract.Ensures(Contract.Result<Bpl.Expr>() != null);\n        var elmtBox = BoxIfNecessary(tok, elmt, elmtType);\n        return TrInMultiSet_Aux(tok, elmt, elmtBox, s);\n      }\n      public Bpl.Expr TrInMultiSet_Aux(IToken tok, Bpl.Expr elmt, Bpl.Expr elmtBox, Expression s) {\n        Contract.Requires(tok != null);\n        Contract.Requires(elmt != null);\n        Contract.Requires(s != null);\n        Contract.Requires(elmtBox != null);\n\n        Contract.Ensures(Contract.Result<Bpl.Expr>() != null);\n\n        if (s is BinaryExpr) {\n          BinaryExpr bin = (BinaryExpr)s;\n          switch (bin.ResolvedOp) {\n            case BinaryExpr.ResolvedOpcode.MultiSetUnion:\n              return Bpl.Expr.Binary(tok, BinaryOperator.Opcode.Or, TrInMultiSet_Aux(tok, elmt, elmtBox, bin.E0), TrInMultiSet_Aux(tok, elmt, elmtBox, bin.E1));\n            case BinaryExpr.ResolvedOpcode.MultiSetIntersection:\n              return Bpl.Expr.Binary(tok, BinaryOperator.Opcode.And, TrInMultiSet_Aux(tok, elmt, elmtBox, bin.E0), TrInMultiSet_Aux(tok, elmt, elmtBox, bin.E1));\n            default:\n              break;\n          }\n        } else if (s is MultiSetDisplayExpr) {\n          MultiSetDisplayExpr disp = (MultiSetDisplayExpr)s;\n          Bpl.Expr disjunction = null;\n          foreach (Expression a in disp.Elements) {\n            Bpl.Expr disjunct = Bpl.Expr.Eq(elmt, TrExpr(a));\n            if (disjunction == null) {\n              disjunction = disjunct;\n            } else {\n              disjunction = Bpl.Expr.Or(disjunction, disjunct);\n            }\n          }\n          if (disjunction == null) {\n            return Bpl.Expr.False;\n          } else {\n            return disjunction;\n          }\n        }\n        return Bpl.Expr.Gt(Bpl.Expr.SelectTok(tok, TrExpr(s), elmtBox), Bpl.Expr.Literal(0));\n      }\n\n      public Bpl.QKeyValue TrAttributes(Attributes attrs, string skipThisAttribute) {\n        Bpl.QKeyValue kv = null;\n        foreach (var attr in attrs.AsEnumerable()) {\n          if (attr.Name == skipThisAttribute\n           || attr.Name == \"axiom\"  // Dafny's axiom attribute clashes with Boogie's axiom keyword\n           || attr.Name == \"fuel\"   // Fuel often uses function names as arguments, which adds extra axioms unnecessarily\n           || (ArmadaOptions.O.DisallowExterns && (attr.Name == \"extern\" || attr.Name == \"dllimport\")) // omit the extern attribute when /noExterns option is specified.\n             ) {\n            continue;\n          }\n          List<object> parms = new List<object>();\n          foreach (var arg in attr.Args) {\n            var s = arg.AsStringLiteral();\n            if (s != null) {\n              // pass string literals down to Boogie as string literals, not as their expression translation\n              parms.Add(s);\n            } else {\n              var e = TrExpr(arg);\n              e = translator.RemoveLit(e);\n              parms.Add(e);\n            }\n          }\n          kv = new Bpl.QKeyValue(Token.NoToken, attr.Name, parms, kv);\n        }\n        return kv;\n      }\n\n      // --------------- help routines ---------------\n\n      public Bpl.Expr IsAlloced(IToken tok, Bpl.Expr e) {\n        Contract.Requires(HeapExpr != null);\n        return translator.IsAlloced(tok, HeapExpr, e);\n      }\n\n      public Bpl.Expr GoodRef(IToken tok, Bpl.Expr e, Type type) {\n        Contract.Requires(tok != null);\n        Contract.Requires(e != null);\n        Contract.Requires(type != null);\n        Contract.Ensures(Contract.Result<Bpl.Expr>() != null);\n\n        // Add $Is and $IsAlloc\n        return translator.GetWhereClause(tok, e, type, this, ISALLOC);\n      }\n    }\n\n    enum BuiltinFunction\n    {\n      Lit,\n      LitInt,\n      LitReal,\n      LayerSucc,\n      AsFuelBottom,\n      CharFromInt,\n      CharToInt,\n\n      Is, IsBox,\n      IsAlloc, IsAllocBox,\n\n      TraitParent,\n\n      SetCard,\n      SetEmpty,\n      SetUnionOne,\n      SetUnion,\n      SetIntersection,\n      SetDifference,\n      SetEqual,\n      SetSubset,\n      SetDisjoint,\n\n      ISetEmpty,\n      ISetUnionOne,\n      ISetUnion,\n      ISetIntersection,\n      ISetDifference,\n      ISetEqual,\n      ISetSubset,\n      ISetDisjoint,\n\n      MultiSetCard,\n      MultiSetEmpty,\n      MultiSetUnionOne,\n      MultiSetUnion,\n      MultiSetIntersection,\n      MultiSetDifference,\n      MultiSetEqual,\n      MultiSetSubset,\n      MultiSetDisjoint,\n      MultiSetFromSet,\n      MultiSetFromSeq,\n      IsGoodMultiSet,\n\n      SeqLength,\n      SeqEmpty,\n      SeqBuild,\n      SeqAppend,\n      SeqIndex,\n      SeqUpdate,\n      SeqContains,\n      SeqDrop,\n      SeqTake,\n      SeqEqual,\n      SeqSameUntil,\n      SeqFromArray,\n      SeqRank,\n\n      MapEmpty,\n      MapCard,\n      MapDomain,\n      MapElements,\n      MapEqual,\n      MapBuild,\n      MapDisjoint,\n      MapUnion,\n      MapGlue,\n\n      IMapEmpty,\n      IMapDomain,\n      IMapElements,\n      IMapEqual,\n      IMapGlue,\n\n      IndexField,\n      MultiIndexField,\n\n      Box,\n      Unbox,\n\n      RealToInt,\n      IntToReal,\n\n      IsGoodHeap,\n      IsHeapAnchor,\n      HeapSucc,\n      HeapSuccGhost,\n\n      DynamicType,  // allocated type (of object reference)\n      TypeTuple,\n      DeclType,\n      FieldOfDecl,\n      FDim,  // field dimension (0 - named, 1 or more - indexed)\n      IsGhostField,\n\n      DatatypeCtorId,\n      DtRank,\n      BoxRank,\n\n      GenericAlloc,\n\n      AtLayer\n    }\n\n    Bpl.Expr Lit(Bpl.Expr expr, Bpl.Type typ) {\n      Contract.Requires(expr != null);\n      Contract.Requires(typ != null);\n      // To avoid Boogie's int_2_U and U_2_int conversions, which seem to cause problems with\n      // arithmetic reasoning, we use several Lit functions.  In particular, we use one for\n      // integers, one for reals, and one for everything else.\n      if (typ.IsInt) {\n        return FunctionCall(expr.tok, BuiltinFunction.LitInt, null, expr);\n      } else if (typ.IsReal) {\n        return FunctionCall(expr.tok, BuiltinFunction.LitReal, null, expr);\n      } else {\n        return FunctionCall(expr.tok, BuiltinFunction.Lit, typ, expr);\n      }\n    }\n\n\n    Bpl.Expr Lit(Bpl.Expr expr) {\n      return Lit(expr, expr.Type);\n    }\n\n    Bpl.Expr GetLit(Bpl.Expr expr) {\n      if (expr is NAryExpr) {\n        NAryExpr app = (NAryExpr)expr;\n        switch (app.Fun.FunctionName) {\n          case \"LitInt\":\n          case \"LitReal\":\n          case \"Lit\":\n            return app.Args[0];\n          default:\n            break;\n        }\n      }\n      return null;\n    }\n\n    Bpl.Expr RemoveLit(Bpl.Expr expr) {\n      return GetLit(expr) ?? expr;\n    }\n\n    bool IsLit(Bpl.Expr expr) {\n      return GetLit(expr) != null;\n    }\n\n    // The \"typeInstantiation\" argument is passed in to help construct the result type of the function.\n    Bpl.NAryExpr FunctionCall(IToken tok, BuiltinFunction f, Bpl.Type typeInstantiation, params Bpl.Expr[] args)\n    {\n      Contract.Requires(tok != null);\n      Contract.Requires(args != null);\n      Contract.Requires(predef != null);\n      Contract.Ensures(Contract.Result<Bpl.NAryExpr>() != null);\n\n      switch (f) {\n        case BuiltinFunction.LitInt:\n          Contract.Assert(args.Length == 1);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"LitInt\", Bpl.Type.Int, args);\n        case BuiltinFunction.LitReal:\n          Contract.Assert(args.Length == 1);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"LitReal\", Bpl.Type.Real, args);\n        case BuiltinFunction.Lit:\n          Contract.Assert(args.Length == 1);\n          Contract.Assert(typeInstantiation != null);\n          return FunctionCall(tok, \"Lit\", typeInstantiation, args);\n        case BuiltinFunction.LayerSucc:\n          Contract.Assert(args.Length == 1);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"$LS\", predef.LayerType, args);\n        case BuiltinFunction.AsFuelBottom:\n          Contract.Assert(args.Length == 1);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"AsFuelBottom\", predef.LayerType, args);\n        case BuiltinFunction.CharFromInt:\n          Contract.Assert(args.Length == 1);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"char#FromInt\", predef.CharType, args);\n        case BuiltinFunction.CharToInt:\n          Contract.Assert(args.Length == 1);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"char#ToInt\", predef.CharType, args);\n\n        case BuiltinFunction.Is:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"$Is\", Bpl.Type.Bool, args);\n        case BuiltinFunction.IsBox:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"$IsBox\", Bpl.Type.Bool, args);\n        case BuiltinFunction.IsAlloc:\n          Contract.Assert(args.Length == 3);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"$IsAlloc\", Bpl.Type.Bool, args);\n        case BuiltinFunction.IsAllocBox:\n          Contract.Assert(args.Length == 3);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"$IsAllocBox\", Bpl.Type.Bool, args);\n\n        case BuiltinFunction.TraitParent:\n          Contract.Assert(args.Length == 1);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"TraitParent\", predef.ClassNameType, args);\n\n        case BuiltinFunction.SetCard:\n          Contract.Assert(args.Length == 1);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"Set#Card\", Bpl.Type.Int, args);\n        case BuiltinFunction.SetEmpty: {\n          Contract.Assert(args.Length == 0);\n          Contract.Assert(typeInstantiation != null);\n          Bpl.Type resultType = predef.SetType(tok, true, typeInstantiation);\n          return Bpl.Expr.CoerceType(tok, FunctionCall(tok, \"Set#Empty\", resultType, args), resultType);\n        }\n        case BuiltinFunction.SetUnionOne:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation != null);\n          return FunctionCall(tok, \"Set#UnionOne\", predef.SetType(tok, true, typeInstantiation), args);\n        case BuiltinFunction.SetUnion:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation != null);\n          return FunctionCall(tok, \"Set#Union\", predef.SetType(tok, true, typeInstantiation), args);\n        case BuiltinFunction.SetIntersection:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation != null);\n          return FunctionCall(tok, \"Set#Intersection\", predef.SetType(tok, true, typeInstantiation), args);\n        case BuiltinFunction.SetDifference:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation != null);\n          return FunctionCall(tok, \"Set#Difference\", predef.SetType(tok, true, typeInstantiation), args);\n        case BuiltinFunction.SetEqual:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"Set#Equal\", Bpl.Type.Bool, args);\n        case BuiltinFunction.SetSubset:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"Set#Subset\", Bpl.Type.Bool, args);\n        case BuiltinFunction.SetDisjoint:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"Set#Disjoint\", Bpl.Type.Bool, args);\n        case BuiltinFunction.ISetEmpty: {\n            Contract.Assert(args.Length == 0);\n            Contract.Assert(typeInstantiation != null);\n            Bpl.Type resultType = predef.SetType(tok, false, typeInstantiation);\n            return Bpl.Expr.CoerceType(tok, FunctionCall(tok, \"ISet#Empty\", resultType, args), resultType);\n          }\n        case BuiltinFunction.ISetUnionOne:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation != null);\n          return FunctionCall(tok, \"ISet#UnionOne\", predef.SetType(tok, false, typeInstantiation), args);\n        case BuiltinFunction.ISetUnion:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation != null);\n          return FunctionCall(tok, \"ISet#Union\", predef.SetType(tok, false, typeInstantiation), args);\n        case BuiltinFunction.ISetIntersection:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation != null);\n          return FunctionCall(tok, \"ISet#Intersection\", predef.SetType(tok, false, typeInstantiation), args);\n        case BuiltinFunction.ISetDifference:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation != null);\n          return FunctionCall(tok, \"ISet#Difference\", predef.SetType(tok, false, typeInstantiation), args);\n        case BuiltinFunction.ISetEqual:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"ISet#Equal\", Bpl.Type.Bool, args);\n        case BuiltinFunction.ISetSubset:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"ISet#Subset\", Bpl.Type.Bool, args);\n        case BuiltinFunction.ISetDisjoint:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"ISet#Disjoint\", Bpl.Type.Bool, args);\n        case BuiltinFunction.MultiSetCard:\n          Contract.Assert(args.Length == 1);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"MultiSet#Card\", Bpl.Type.Int, args);\n        case BuiltinFunction.MultiSetEmpty: {\n            Contract.Assert(args.Length == 0);\n            Contract.Assert(typeInstantiation != null);\n            Bpl.Type resultType = predef.MultiSetType(tok, typeInstantiation);\n            return Bpl.Expr.CoerceType(tok, FunctionCall(tok, \"MultiSet#Empty\", resultType, args), resultType);\n          }\n        case BuiltinFunction.MultiSetUnionOne:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation != null);\n          return FunctionCall(tok, \"MultiSet#UnionOne\", predef.MultiSetType(tok, typeInstantiation), args);\n        case BuiltinFunction.MultiSetUnion:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation != null);\n          return FunctionCall(tok, \"MultiSet#Union\", predef.MultiSetType(tok, typeInstantiation), args);\n        case BuiltinFunction.MultiSetIntersection:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation != null);\n          return FunctionCall(tok, \"MultiSet#Intersection\", predef.MultiSetType(tok, typeInstantiation), args);\n        case BuiltinFunction.MultiSetDifference:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation != null);\n          return FunctionCall(tok, \"MultiSet#Difference\", predef.MultiSetType(tok, typeInstantiation), args);\n        case BuiltinFunction.MultiSetEqual:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"MultiSet#Equal\", Bpl.Type.Bool, args);\n        case BuiltinFunction.MultiSetSubset:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"MultiSet#Subset\", Bpl.Type.Bool, args);\n        case BuiltinFunction.MultiSetDisjoint:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"MultiSet#Disjoint\", Bpl.Type.Bool, args);\n        case BuiltinFunction.MultiSetFromSet:\n          Contract.Assert(args.Length == 1);\n          Contract.Assert(typeInstantiation != null);\n          return FunctionCall(tok, \"MultiSet#FromSet\", predef.MultiSetType(tok, typeInstantiation), args);\n        case BuiltinFunction.MultiSetFromSeq:\n          Contract.Assert(args.Length == 1);\n          Contract.Assert(typeInstantiation != null);\n          return FunctionCall(tok, \"MultiSet#FromSeq\", predef.MultiSetType(tok, typeInstantiation), args);\n        case BuiltinFunction.IsGoodMultiSet:\n          Contract.Assert(args.Length == 1);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"$IsGoodMultiSet\", Bpl.Type.Bool, args);\n\n        case BuiltinFunction.SeqLength:\n          Contract.Assert(args.Length == 1);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"Seq#Length\", Bpl.Type.Int, args);\n        case BuiltinFunction.SeqEmpty: {\n          Contract.Assert(args.Length == 0);\n          Contract.Assert(typeInstantiation != null);\n          Bpl.Type resultType = predef.SeqType(tok, typeInstantiation);\n          return Bpl.Expr.CoerceType(tok, FunctionCall(tok, \"Seq#Empty\", resultType, args), resultType);\n        }\n        case BuiltinFunction.SeqBuild:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation != null);\n          return FunctionCall(tok, \"Seq#Build\", predef.SeqType(tok, typeInstantiation), args);\n        case BuiltinFunction.SeqAppend:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation != null);\n          return FunctionCall(tok, \"Seq#Append\", predef.SeqType(tok, typeInstantiation), args);\n        case BuiltinFunction.SeqIndex:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation != null);\n          return FunctionCall(tok, \"Seq#Index\", typeInstantiation, args);\n        case BuiltinFunction.SeqUpdate:\n          Contract.Assert(args.Length == 3);\n          Contract.Assert(typeInstantiation != null);\n          return FunctionCall(tok, \"Seq#Update\", predef.SeqType(tok, typeInstantiation), args);\n        case BuiltinFunction.SeqContains:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"Seq#Contains\", Bpl.Type.Bool, args);\n        case BuiltinFunction.SeqDrop:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation != null);\n          return FunctionCall(tok, \"Seq#Drop\", predef.SeqType(tok, typeInstantiation), args);\n        case BuiltinFunction.SeqTake:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation != null);\n          return FunctionCall(tok, \"Seq#Take\", predef.SeqType(tok, typeInstantiation), args);\n        case BuiltinFunction.SeqEqual:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"Seq#Equal\", Bpl.Type.Bool, args);\n        case BuiltinFunction.SeqSameUntil:\n          Contract.Assert(args.Length == 3);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"Seq#SameUntil\", Bpl.Type.Bool, args);\n        case BuiltinFunction.SeqFromArray:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation != null);\n          return FunctionCall(tok, \"Seq#FromArray\", typeInstantiation, args);\n        case BuiltinFunction.SeqRank:\n          Contract.Assert(args.Length == 1);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"Seq#Rank\", Bpl.Type.Int, args);\n\n        case BuiltinFunction.MapEmpty: {\n            Contract.Assert(args.Length == 0);\n            Contract.Assert(typeInstantiation != null);\n            Bpl.Type resultType = predef.MapType(tok, true, typeInstantiation, typeInstantiation);  // use 'typeInstantiation' (which is really always just BoxType anyway) as both type arguments\n            return Bpl.Expr.CoerceType(tok, FunctionCall(tok, \"Map#Empty\", resultType, args), resultType);\n          }\n        case BuiltinFunction.MapCard:\n          Contract.Assert(args.Length == 1);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"Map#Card\", Bpl.Type.Int, args);\n        case BuiltinFunction.MapDomain:\n          Contract.Assert(args.Length == 1);\n          return FunctionCall(tok, \"Map#Domain\", typeInstantiation, args);\n        case BuiltinFunction.MapElements:\n          Contract.Assert(args.Length == 1);\n          return FunctionCall(tok, \"Map#Elements\", typeInstantiation, args);\n        case BuiltinFunction.MapGlue:\n          Contract.Assert(args.Length == 3);\n          return FunctionCall(tok, \"Map#Glue\", predef.MapType(tok, true, predef.BoxType, predef.BoxType), args);\n        case BuiltinFunction.MapEqual:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"Map#Equal\", Bpl.Type.Bool, args);\n        case BuiltinFunction.MapDisjoint:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"Map#Disjoint\", Bpl.Type.Bool, args);\n        case BuiltinFunction.MapUnion:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"Map#Disjoint\", typeInstantiation, args);\n\n        case BuiltinFunction.IMapEmpty: {\n            Contract.Assert(args.Length == 0);\n            Contract.Assert(typeInstantiation != null);\n            Bpl.Type resultType = predef.MapType(tok, false, typeInstantiation, typeInstantiation);  // use 'typeInstantiation' (which is really always just BoxType anyway) as both type arguments\n            return Bpl.Expr.CoerceType(tok, FunctionCall(tok, \"IMap#Empty\", resultType, args), resultType);\n          }\n        case BuiltinFunction.IMapDomain:\n          Contract.Assert(args.Length == 1);\n          return FunctionCall(tok, \"IMap#Domain\", typeInstantiation, args);\n        case BuiltinFunction.IMapElements:\n          Contract.Assert(args.Length == 1);\n          return FunctionCall(tok, \"IMap#Elements\", typeInstantiation, args);\n        case BuiltinFunction.IMapGlue:\n          Contract.Assert(args.Length == 3);\n          return FunctionCall(tok, \"IMap#Glue\", predef.MapType(tok, false, predef.BoxType, predef.BoxType), args);\n        case BuiltinFunction.IMapEqual:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"IMap#Equal\", Bpl.Type.Bool, args);\n\n        case BuiltinFunction.IndexField:\n          Contract.Assert(args.Length == 1);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"IndexField\", predef.FieldName(tok, predef.BoxType), args);\n        case BuiltinFunction.MultiIndexField:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"MultiIndexField\", predef.FieldName(tok, predef.BoxType), args);\n\n        case BuiltinFunction.Box:\n          Contract.Assert(args.Length == 1);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"$Box\", predef.BoxType, args);\n        case BuiltinFunction.Unbox:\n          Contract.Assert(args.Length == 1);\n          Contract.Assert(typeInstantiation != null);\n          return Bpl.Expr.CoerceType(tok, FunctionCall(tok, \"$Unbox\", typeInstantiation, args), typeInstantiation);\n\n        case BuiltinFunction.RealToInt:\n          Contract.Assume(args.Length == 1);\n          Contract.Assume(typeInstantiation == null);\n          return FunctionCall(tok, \"Int\", Bpl.Type.Int, args);\n        case BuiltinFunction.IntToReal:\n          Contract.Assume(args.Length == 1);\n          Contract.Assume(typeInstantiation == null);\n          return FunctionCall(tok, \"Real\", Bpl.Type.Real, args);\n\n        case BuiltinFunction.IsGoodHeap:\n          Contract.Assert(args.Length == 1);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"$IsGoodHeap\", Bpl.Type.Bool, args);\n        case BuiltinFunction.IsHeapAnchor:\n          Contract.Assert(args.Length == 1);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"$IsHeapAnchor\", Bpl.Type.Bool, args);\n        case BuiltinFunction.HeapSucc:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"$HeapSucc\", Bpl.Type.Bool, args);\n        case BuiltinFunction.HeapSuccGhost:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"$HeapSuccGhost\", Bpl.Type.Bool, args);\n\n        case BuiltinFunction.DynamicType:\n          Contract.Assert(args.Length == 1);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"dtype\", predef.ClassNameType, args);\n        case BuiltinFunction.TypeTuple:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"TypeTuple\", predef.ClassNameType, args);\n        case BuiltinFunction.DeclType:\n          Contract.Assert(args.Length == 1);\n          Contract.Assert(typeInstantiation != null);\n          return FunctionCall(tok, \"DeclType\", predef.ClassNameType, args);\n        case BuiltinFunction.FieldOfDecl:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation != null);\n          return FunctionCall(tok, \"FieldOfDecl\", predef.FieldName(tok, typeInstantiation) , args);\n        case BuiltinFunction.FDim:\n          Contract.Assert(args.Length == 1);\n          Contract.Assert(typeInstantiation != null);\n          return FunctionCall(tok, \"FDim\", Bpl.Type.Int, args);\n        case BuiltinFunction.IsGhostField:\n          Contract.Assert(args.Length == 1);\n          Contract.Assert(typeInstantiation != null);\n          return FunctionCall(tok, \"$IsGhostField\", Bpl.Type.Bool, args);\n\n        case BuiltinFunction.DatatypeCtorId:\n          Contract.Assert(args.Length == 1);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"DatatypeCtorId\", predef.DtCtorId, args);\n        case BuiltinFunction.DtRank:\n          Contract.Assert(args.Length == 1);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"DtRank\", Bpl.Type.Int, args);\n        case BuiltinFunction.BoxRank:\n          Contract.Assert(args.Length == 1);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"BoxRank\", Bpl.Type.Int, args);\n\n        case BuiltinFunction.GenericAlloc:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation == null);\n          return FunctionCall(tok, \"GenericAlloc\", Bpl.Type.Bool, args);\n\n        case BuiltinFunction.AtLayer:\n          Contract.Assert(args.Length == 2);\n          Contract.Assert(typeInstantiation != null);\n          return FunctionCall(tok, \"AtLayer\", typeInstantiation, args);\n\n        default:\n          Contract.Assert(false); throw new cce.UnreachableException();  // unexpected built-in function\n      }\n    }\n\n    Bpl.NAryExpr FunctionCall(IToken tok, string function, Bpl.Type returnType, params Bpl.Expr[] args)\n    {\n      Contract.Requires(tok != null);\n      Contract.Requires(function != null);\n      Contract.Requires(returnType != null);\n      Contract.Requires(args != null);\n      Contract.Ensures(Contract.Result<Bpl.NAryExpr>() != null);\n\n      return new Bpl.NAryExpr(tok, new Bpl.FunctionCall(new Bpl.IdentifierExpr(tok, function, returnType)), new List<Bpl.Expr>(args));\n    }\n\n    Bpl.NAryExpr FunctionCall(IToken tok, string function, Bpl.Type returnType, List<Bpl.Expr> args)\n    {\n      Contract.Requires(tok != null);\n      Contract.Requires(function != null);\n      Contract.Requires(returnType != null);\n      Contract.Requires(cce.NonNullElements(args));\n      Contract.Ensures(Contract.Result<Bpl.NAryExpr>() != null);\n\n      List<Bpl.Expr> aa = new List<Bpl.Expr>();\n      foreach (Bpl.Expr arg in args) {\n        aa.Add(arg);\n      }\n      return new Bpl.NAryExpr(tok, new Bpl.FunctionCall(new Bpl.IdentifierExpr(tok, function, returnType)), aa);\n    }\n\n    public Bpl.Expr ProperSubset(IToken tok, Bpl.Expr e0, Bpl.Expr e1) {\n      Contract.Requires(tok != null);\n      Contract.Requires(e0 != null);\n      Contract.Requires(e1 != null);\n      Contract.Ensures(Contract.Result<Bpl.Expr>() != null);\n\n      return Bpl.Expr.Binary(tok, BinaryOperator.Opcode.And,\n        FunctionCall(tok, BuiltinFunction.SetSubset, null, e0, e1),\n        Bpl.Expr.Not(FunctionCall(tok, BuiltinFunction.SetSubset, null, e1, e0)));\n    }\n    public Bpl.Expr ProperMultiset(IToken tok, Bpl.Expr e0, Bpl.Expr e1) {\n      Contract.Requires(tok != null);\n      Contract.Requires(e0 != null);\n      Contract.Requires(e1 != null);\n      return Bpl.Expr.Binary(tok, BinaryOperator.Opcode.And,\n        FunctionCall(tok, BuiltinFunction.MultiSetSubset, null, e0, e1),\n        Bpl.Expr.Not(FunctionCall(tok, BuiltinFunction.MultiSetEqual, null, e0, e1)));\n    }\n    public Bpl.Expr ProperPrefix(IToken tok, Bpl.Expr e0, Bpl.Expr e1) {\n      Contract.Requires(tok != null);\n      Contract.Requires(e0 != null);\n      Contract.Requires(e1 != null);\n      Contract.Ensures(Contract.Result<Bpl.Expr>() != null);\n      Bpl.Expr len0 = FunctionCall(tok, BuiltinFunction.SeqLength, null, e0);\n      Bpl.Expr len1 = FunctionCall(tok, BuiltinFunction.SeqLength, null, e1);\n      return Bpl.Expr.And(\n        Bpl.Expr.Lt(len0, len1),\n        FunctionCall(tok, BuiltinFunction.SeqSameUntil, null, e0, e1, len0));\n    }\n\n    Bpl.Expr ArrayLength(IToken tok, Bpl.Expr arr, int totalDims, int dim) {\n      Contract.Requires(tok != null);\n      Contract.Requires(arr != null);\n      Contract.Requires(1 <= totalDims);\n      Contract.Requires(0 <= dim && dim < totalDims);\n\n      string name = \"_System.\" + BuiltIns.ArrayClassName(totalDims) + \".Length\";\n      if (totalDims != 1) {\n        name += dim;\n      }\n      return new Bpl.NAryExpr(tok, new Bpl.FunctionCall(new Bpl.IdentifierExpr(tok, name, Bpl.Type.Int)), new List<Bpl.Expr> { arr });\n    }\n\n    public class SplitExprInfo\n    {\n      public enum K { Free, Checked, Both }\n      public K Kind;\n      public bool IsOnlyFree { get { return Kind == K.Free; } }\n      public bool IsOnlyChecked { get { return Kind == K.Checked; } }\n      public bool IsChecked { get { return Kind != K.Free; } }\n      public readonly Bpl.Expr E;\n      public SplitExprInfo(K kind, Bpl.Expr e) {\n        Contract.Requires(e != null && e.tok != null);\n        // TODO:  Contract.Requires(kind == K.Free || e.tok.IsValid);\n        Kind = kind;\n        E = e;\n      }\n    }\n\n    List<SplitExprInfo/*!*/>/*!*/ TrSplitExpr(Expression expr, ExpressionTranslator etran, bool apply_induction, out bool splitHappened) {\n      Contract.Requires(expr != null);\n      Contract.Requires(etran != null);\n      Contract.Ensures(Contract.Result<List<SplitExprInfo>>() != null);\n\n      var splits = new List<SplitExprInfo>();\n      splitHappened = TrSplitExpr(expr, splits, true, int.MaxValue, true, apply_induction, etran);\n      return splits;\n    }\n\n    List<SplitExprInfo> TrSplitExprForMethodSpec(Expression expr, ExpressionTranslator etran, MethodTranslationKind kind)\n    {\n      Contract.Requires(expr != null);\n      Contract.Requires(etran != null);\n      Contract.Ensures(Contract.Result<List<SplitExprInfo>>() != null);\n\n      var splits = new List<SplitExprInfo>();\n      var apply_induction = true;/*kind == MethodTranslationKind.Implementation*/;\n      bool splitHappened;  // we don't actually care\n      splitHappened = TrSplitExpr(expr, splits, true, int.MaxValue, kind != MethodTranslationKind.Call, apply_induction, etran);\n      return splits;\n    }\n\n    Bpl.Trigger TrTrigger(ExpressionTranslator etran, Attributes attribs, IToken tok, Dictionary<IVariable, Expression> substMap = null)\n    {\n      Contract.Requires(etran != null);\n      Contract.Requires(tok != null);\n      var argsEtran = etran.WithNoLits();\n      Bpl.Trigger tr = null;\n      foreach (var trigger in attribs.AsEnumerable().Where(aa => aa.Name == \"trigger\").Select(aa => aa.Args)) {\n        List<Bpl.Expr> tt = new List<Bpl.Expr>();\n        foreach (var arg in trigger) {\n          if (substMap == null) {\n            tt.Add(argsEtran.TrExpr(arg));\n          } else {\n            tt.Add(argsEtran.TrExpr(Substitute(arg, null, substMap)));\n          }\n        }\n        tr = new Bpl.Trigger(tok, true, tt, tr);\n      }\n      return tr;\n    }\n\n    Bpl.Trigger TrTrigger(ExpressionTranslator etran, Attributes attribs, IToken tok, List<Variable> bvars, Dictionary<IVariable, Expression> substMap, Dictionary<TypeParameter, Type> typeMap)\n    {\n      Contract.Requires(etran != null);\n      Contract.Requires(tok != null);\n      var argsEtran = etran.WithNoLits();\n      Bpl.Trigger tr = null;\n      var fueledTrigger = new Dictionary<List<Expression>, bool>();\n      // translate the triggers once to see if fuel or the heap is used as quantifier boundvar\n      foreach (var aa in attribs.AsEnumerable()) {\n        if (aa.Name == \"trigger\") {\n          int fuelCount = argsEtran.Statistics_CustomLayerFunctionCount;\n          foreach (var arg in aa.Args) {\n            argsEtran.TrExpr(arg);\n          }\n          fueledTrigger[aa.Args] = argsEtran.Statistics_CustomLayerFunctionCount > fuelCount;\n        }\n      }\n\n      bool useFuelAsQuantifier = argsEtran.Statistics_CustomLayerFunctionCount > 0;\n      bool useHeapAsQuantifier = argsEtran.Statistics_HeapAsQuantifierCount > 0;\n      Expr qly = null;\n      if (useFuelAsQuantifier && ArmadaOptions.O.IronDafny) {\n        qly = BplBoundVar(CurrentIdGenerator.FreshId(\"tr$ly#\"), predef.LayerType, bvars);\n        argsEtran = argsEtran.WithLayer(qly);\n      }\n      if (useHeapAsQuantifier) {\n        var heapExpr = BplBoundVar(CurrentIdGenerator.FreshId(\"tr$heap#\"), predef.HeapType, bvars);\n        argsEtran = new ExpressionTranslator(argsEtran, heapExpr);\n      }\n\n      // now translate it with the correct layer and heapExpr\n      foreach (var trigger in attribs.AsEnumerable().Where(aa => aa.Name == \"trigger\")) {\n        List<Bpl.Expr> tt = new List<Bpl.Expr>();\n        foreach (var arg in trigger.Args) {\n          if (substMap == null) {\n            tt.Add(argsEtran.TrExpr(arg));\n          } else {\n            tt.Add(argsEtran.TrExpr(Substitute(arg, null, substMap, typeMap)));\n          }\n        }\n        if (useHeapAsQuantifier) {\n          tt.Add(FunctionCall(tok, BuiltinFunction.IsGoodHeap, null, argsEtran.HeapExpr));\n        }\n        if (useFuelAsQuantifier && !fueledTrigger[trigger.Args] && ArmadaOptions.O.IronDafny) {\n          // We quantified over fuel, but this particular trigger doesn't use it,\n          // so we need to add a dummy trigger.  Hopefully it will always be in scope when needed.\n          tt.Add(FunctionCall(tok, BuiltinFunction.AsFuelBottom, null, qly));\n        }\n        tr = new Bpl.Trigger(tok, true, tt, tr);\n      }\n      return tr;\n    }\n\n    /// <summary>\n    /// Tries to split the expression into tactical conjuncts (if \"position\") or disjuncts (if \"!position\").\n    /// If a (necessarily boolean) function call appears as a top-level conjunct, then inline the function\n    /// if its body is available in the current context and its height is less than \"heightLimit\" (if \"heightLimit\" is\n    /// passed in as 0, then no functions will be inlined).\n    /// </summary>\n    bool TrSplitExpr(Expression expr, List<SplitExprInfo/*!*/>/*!*/ splits, bool position, int heightLimit, bool inlineProtectedFunctions, bool apply_induction, ExpressionTranslator etran) {\n      Contract.Requires(expr != null);\n      Contract.Requires(expr.Type.IsBoolType || (expr is BoxingCastExpr && ((BoxingCastExpr)expr).E.Type.IsBoolType));\n      Contract.Requires(splits != null);\n      Contract.Requires(etran != null);\n\n      if (expr is BoxingCastExpr) {\n        var bce = (BoxingCastExpr)expr;\n        var ss = new List<SplitExprInfo>();\n        if (TrSplitExpr(bce.E, ss, position, heightLimit, inlineProtectedFunctions, apply_induction, etran)) {\n          foreach (var s in ss) {\n            splits.Add(new SplitExprInfo(s.Kind, CondApplyBox(s.E.tok, s.E, bce.FromType, bce.ToType)));\n          }\n          return true;\n        }\n\n      } else if (expr is ConcreteSyntaxExpression) {\n        var e = (ConcreteSyntaxExpression)expr;\n        return TrSplitExpr(e.ResolvedExpression, splits, position, heightLimit, inlineProtectedFunctions, apply_induction, etran);\n\n      } else if (expr is RevealExpr) {\n        var e = (RevealExpr)expr;\n        return TrSplitExpr(e.ResolvedExpression, splits, position, heightLimit, inlineProtectedFunctions, apply_induction, etran);\n\n      } else if (expr is LetExpr) {\n        var e = (LetExpr)expr;\n        if (!e.Exact) {\n          var d = LetDesugaring(e);\n          return TrSplitExpr(d, splits, position, heightLimit, inlineProtectedFunctions, apply_induction, etran);\n        } else {\n          var ss = new List<SplitExprInfo>();\n          if (TrSplitExpr(e.Body, ss, position, heightLimit, inlineProtectedFunctions, apply_induction, etran)) {\n            // We don't know where the RHSs of the let are used in the body. In particular, we don't know if a RHS\n            // will end up in a spot where TrSplitExpr would like to increase the Layer offset or not. In fact, different\n            // uses of the same let variable may end up needing different Layer constants. The following code will\n            // always bump the Layer offset in the RHS. This seems likely to be desireable in many cases, because the\n            // LetExpr sits in a position for which TrSplitExpr is invoked.\n            List<Bpl.Variable> lhss;\n            List<Bpl.Expr> rhss;\n            etran.LayerOffset(1).TrLetExprPieces(e, out lhss, out rhss);\n            foreach (var s in ss) {\n              // as the source location in the following let, use that of the translated \"s\"\n              splits.Add(new SplitExprInfo(s.Kind, new Bpl.LetExpr(s.E.tok, lhss, rhss, null, s.E)));\n            }\n            return true;\n          }\n        }\n\n      } else if (expr is UnchangedExpr) {\n        var e = (UnchangedExpr)expr;\n        if (position && e.Frame.Count > 1) {\n          // split into a number of UnchangeExpr's, one for each FrameExpression\n          foreach (var fe in e.Frame) {\n            var tok = new NestedToken(e.tok, fe.tok);\n            Expression ee = new UnchangedExpr(tok, new List<FrameExpression> { fe }, e.At) { AtLabel = e.AtLabel };\n            ee.Type = Type.Bool;  // resolve here\n            TrSplitExpr(ee, splits, position, heightLimit, inlineProtectedFunctions, apply_induction, etran);\n          }\n          return true;\n        }\n\n      } else if (expr is UnaryOpExpr) {\n        var e = (UnaryOpExpr)expr;\n        if (e.Op == UnaryOpExpr.Opcode.Not) {\n          var ss = new List<SplitExprInfo>();\n          if (TrSplitExpr(e.E, ss, !position, heightLimit, inlineProtectedFunctions, apply_induction, etran)) {\n            foreach (var s in ss) {\n              splits.Add(new SplitExprInfo(s.Kind, Bpl.Expr.Unary(s.E.tok, UnaryOperator.Opcode.Not, s.E)));\n            }\n            return true;\n          }\n        }\n\n      } else if (expr is BinaryExpr) {\n        var bin = (BinaryExpr)expr;\n        if (position && bin.ResolvedOp == BinaryExpr.ResolvedOpcode.And) {\n          TrSplitExpr(bin.E0, splits, position, heightLimit, inlineProtectedFunctions, apply_induction, etran);\n          TrSplitExpr(bin.E1, splits, position, heightLimit, inlineProtectedFunctions, apply_induction, etran);\n          return true;\n\n        } else  if (!position && bin.ResolvedOp == BinaryExpr.ResolvedOpcode.Or) {\n          TrSplitExpr(bin.E0, splits, position, heightLimit, inlineProtectedFunctions, apply_induction, etran);\n          TrSplitExpr(bin.E1, splits, position, heightLimit, inlineProtectedFunctions, apply_induction, etran);\n          return true;\n\n        } else if (bin.ResolvedOp == BinaryExpr.ResolvedOpcode.Imp) {\n          // non-conditionally split these, so we get the source location to point to a subexpression\n          if (position) {\n            var lhs = etran.TrExpr(bin.E0);\n            var ss = new List<SplitExprInfo>();\n            TrSplitExpr(bin.E1, ss, position, heightLimit, inlineProtectedFunctions, apply_induction, etran);\n            foreach (var s in ss) {\n              // as the source location in the following implication, use that of the translated \"s\"\n              splits.Add(new SplitExprInfo(s.Kind, Bpl.Expr.Binary(s.E.tok, BinaryOperator.Opcode.Imp, lhs, s.E)));\n            }\n          } else {\n            var ss = new List<SplitExprInfo>();\n            TrSplitExpr(bin.E0, ss, !position, heightLimit, inlineProtectedFunctions, apply_induction, etran);\n            var rhs = etran.TrExpr(bin.E1);\n            foreach (var s in ss) {\n              // as the source location in the following implication, use that of the translated \"s\"\n              splits.Add(new SplitExprInfo(s.Kind, Bpl.Expr.Binary(s.E.tok, BinaryOperator.Opcode.Imp, s.E, rhs)));\n            }\n          }\n          return true;\n        }\n\n      } else if (expr is TernaryExpr) {\n        var e = (TernaryExpr)expr;\n        if ((e.Op == TernaryExpr.Opcode.PrefixEqOp && position) || (e.Op == TernaryExpr.Opcode.PrefixNeqOp && !position)) {\n          var e1type = e.E1.Type.NormalizeExpand();\n          var e2type = e.E2.Type.NormalizeExpand();\n          var codecl = e1type.AsCoDatatype;\n          Contract.Assert(codecl != null);\n          var k = etran.TrExpr(e.E0);\n          var A = etran.TrExpr(e.E1);\n          var B = etran.TrExpr(e.E2);\n          // split as shown here for possibly infinite lists:\n          //   checked $PrefixEqual#Dt(k, A, B) || (k_has_successor ==> A.Nil? ==> B.Nil?)\n          //   checked $PrefixEqual#Dt(k, A, B) || (k_has_successor ==> A.Cons? ==> B.Cons? && A.head == B.head && $PrefixEqual#2#Dt(k - 1, A.tail, B.tail))  // note the #2 in the recursive call, just like for user-defined predicates that are inlined by TrSplitExpr\n          //   checked $PrefixEqual#Dt(k, A, B) || (k != 0 && k.IsLimit ==> $Equal#Dt(A, B))  // (*)\n          //   free $PrefixEqual#Dt(k, A, B);\n          // Note:  First off, (*) is used only when ORDINAL is involved. Moreover, if there's an error among the first checked\n          // conditions, it seems confusing to get yet another error message.  Therefore, we add a middle disjunct to (*), namely\n          // the conjunction of all the previous RHSs.\n          var kAsORD = !e.E0.Type.IsBigOrdinalType && !TernaryExpr.PrefixEqUsesNat ? FunctionCall(k.tok, \"ORD#FromNat\", Bpl.Type.Int, k) : k;\n          var prefixEqK = CoEqualCall(codecl, e1type.TypeArgs, e2type.TypeArgs, kAsORD, etran.layerInterCluster.LayerN((int)FuelSetting.FuelAmount.HIGH), A, B); // FunctionCall(expr.tok, CoPrefixName(codecl, 1), Bpl.Type.Bool, k, A, B);\n          Bpl.Expr kHasSuccessor, kMinusOne;\n          if (e.E0.Type.IsBigOrdinalType) {\n            kHasSuccessor = Bpl.Expr.Lt(Bpl.Expr.Literal(0), FunctionCall(k.tok, \"ORD#Offset\", Bpl.Type.Int, k));\n            kMinusOne = FunctionCall(k.tok, \"ORD#Minus\", predef.BigOrdinalType, k, FunctionCall(k.tok, \"ORD#FromNat\", Bpl.Type.Int, Bpl.Expr.Literal(1)));\n          } else {\n            kHasSuccessor = Bpl.Expr.Lt(Bpl.Expr.Literal(0), k);\n            kMinusOne = Bpl.Expr.Sub(k, Bpl.Expr.Literal(1));\n            if (!TernaryExpr.PrefixEqUsesNat) {\n              kMinusOne = FunctionCall(k.tok, \"ORD#FromNat\", Bpl.Type.Int, kMinusOne);\n            }\n          }\n          // for the inlining of the definition of prefix equality, translate the two main equality operands arguments with a higher offset (to obtain #2 functions)\n          var etran2 = etran.LayerOffset(1);\n          var A2 = etran2.TrExpr(e.E1);\n          var B2 = etran2.TrExpr(e.E2);\n          var needsTokenAdjust = TrSplitNeedsTokenAdjustment(expr);\n          var tok = needsTokenAdjust ? new ForceCheckToken(expr.tok) : expr.tok;\n          Bpl.Expr layer = etran.layerInterCluster.LayerN((int)FuelSetting.FuelAmount.HIGH);\n          Bpl.Expr eqComponents = Bpl.Expr.True;\n          foreach (var c in CoPrefixEquality(tok, codecl, e1type.TypeArgs, e2type.TypeArgs, kMinusOne, layer, A2, B2, true)) {\n            eqComponents = BplAnd(eqComponents, c);\n            var p = Bpl.Expr.Binary(c.tok, BinaryOperator.Opcode.Or, prefixEqK, Bpl.Expr.Imp(kHasSuccessor, c));\n            splits.Add(new SplitExprInfo(SplitExprInfo.K.Checked, p));\n          }\n          if (e.E0.Type.IsBigOrdinalType) {\n            var kIsNonZeroLimit = BplAnd(\n              Bpl.Expr.Neq(k, FunctionCall(k.tok, \"ORD#FromNat\", predef.BigOrdinalType, Bpl.Expr.Literal(0))),\n              FunctionCall(k.tok, \"ORD#IsLimit\", Bpl.Type.Bool, k));\n            var eq = CoEqualCall(codecl, e1type.TypeArgs, e2type.TypeArgs, null, etran.layerInterCluster.LayerN((int)FuelSetting.FuelAmount.HIGH), A, B);\n            var p = Bpl.Expr.Binary(tok, BinaryOperator.Opcode.Or, prefixEqK, BplOr(BplImp(kHasSuccessor, eqComponents), Bpl.Expr.Imp(kIsNonZeroLimit, eq)));\n            splits.Add(new SplitExprInfo(SplitExprInfo.K.Checked, p));\n          }\n          splits.Add(new SplitExprInfo(SplitExprInfo.K.Free, prefixEqK));\n          return true;\n        }\n\n      } else if (expr is ITEExpr) {\n        var ite = (ITEExpr)expr;\n\n        var ssThen = new List<SplitExprInfo>();\n        var ssElse = new List<SplitExprInfo>();\n\n        TrSplitExpr(ite.Thn, ssThen, position, heightLimit, inlineProtectedFunctions, apply_induction, etran);\n        TrSplitExpr(ite.Els, ssElse, position, heightLimit, inlineProtectedFunctions, apply_induction, etran);\n\n        var op = position ? BinaryOperator.Opcode.Imp : BinaryOperator.Opcode.And;\n        var test = etran.TrExpr(ite.Test);\n        foreach (var s in ssThen)\n        {\n          // as the source location in the following implication, use that of the translated \"s\"\n          splits.Add(new SplitExprInfo(s.Kind, Bpl.Expr.Binary(s.E.tok, op, test, s.E)));\n        }\n\n        var negatedTest = Bpl.Expr.Not(test);\n        foreach (var s in ssElse)\n        {\n          // as the source location in the following implication, use that of the translated \"s\"\n          splits.Add(new SplitExprInfo(s.Kind, Bpl.Expr.Binary(s.E.tok, op, negatedTest, s.E)));\n        }\n\n        return true;\n      } else if (expr is StmtExpr) {\n        var e = (StmtExpr)expr;\n        // For an expression S;E in split position, the conclusion of S can be used as an assumption.  Unfortunately,\n        // this assumption is not generated in non-split positions (because I don't know how.)\n        // So, treat \"S; E\" like \"SConclusion ==> E\".\n        if (position) {\n          var conclusion = etran.TrExpr(e.GetSConclusion());\n          var ss = new List<SplitExprInfo>();\n          TrSplitExpr(e.E, ss, position, heightLimit, inlineProtectedFunctions, apply_induction, etran);\n          foreach (var s in ss) {\n            // as the source location in the following implication, use that of the translated \"s\"\n            splits.Add(new SplitExprInfo(s.Kind, Bpl.Expr.Binary(s.E.tok, BinaryOperator.Opcode.Imp, conclusion, s.E)));\n          }\n        } else {\n          var ss = new List<SplitExprInfo>();\n          TrSplitExpr(e.GetSConclusion(), ss, !position, heightLimit, inlineProtectedFunctions, apply_induction, etran);\n          var rhs = etran.TrExpr(e.E);\n          foreach (var s in ss) {\n            // as the source location in the following implication, use that of the translated \"s\"\n            splits.Add(new SplitExprInfo(s.Kind, Bpl.Expr.Binary(s.E.tok, BinaryOperator.Opcode.Imp, s.E, rhs)));\n          }\n        }\n        return true;\n\n      } else if (expr is OldExpr) {\n        var e = (OldExpr)expr;\n        return TrSplitExpr(e.E, splits, position, heightLimit, inlineProtectedFunctions, apply_induction, e.AtLabel == null ? etran.Old : etran.OldAt(e.AtLabel));\n\n      } else if (expr is FunctionCallExpr && position) {\n        var fexp = (FunctionCallExpr)expr;\n        var f = fexp.Function;\n        Contract.Assert(f != null);  // filled in during resolution\n        var module = f.EnclosingClass.Module;\n        var functionHeight = module.CallGraph.GetSCCRepresentativeId(f);\n\n        if (functionHeight < heightLimit && f.Body != null && RevealedInScope(f) && !(f.Body.Resolved is MatchExpr)) {\n          if (RefinementToken.IsInherited(fexp.tok, currentModule) &&\n              f is Predicate && ((Predicate)f).BodyOrigin == Predicate.BodyOriginKind.DelayedDefinition &&\n              (codeContext == null || !codeContext.MustReverify)) {\n            // The function was inherited as body-less but is now given a body. Don't inline the body (since, apparently, everything\n            // that needed to be proved about the function was proved already in the previous module, even without the body definition).\n          } else if (!FunctionBodyIsAvailable(f, currentModule, currentScope, inlineProtectedFunctions)) {\n            // Don't inline opaque functions or foreign protected functions\n          } else if (Attributes.Contains(f.Attributes, \"no_inline\")) {\n            // User manually prevented inlining\n          } else {\n            // Produce, for a \"body\" split into b0, b1, b2:\n            //     checked F#canCall(args) ==> F(args) || b0\n            //     checked F#canCall(args) ==> F(args) || b1\n            //     checked F#canCall(args) ==> F(args) || b2\n            //     free F#canCall(args) && F(args) && (b0 && b1 && b2)\n            // For \"inCoContext\", split into:\n            //     checked F#canCall(args) ==> F'(args) || b0''\n            //     checked F#canCall(args) ==> F'(args) || b1''\n            //     checked F#canCall(args) ==> F'(args) || b2''\n            //     free F#canCall(args) && F'(args)\n            // where the primes indicate certificate translations.\n            // The checked conjuncts of the body make use of the type-specialized body.\n\n            // F#canCall(args)\n            Bpl.IdentifierExpr canCallFuncID = new Bpl.IdentifierExpr(expr.tok, f.FullSanitizedName + \"#canCall\", Bpl.Type.Bool);\n            List<Bpl.Expr> args = etran.FunctionInvocationArguments(fexp, null);\n            Bpl.Expr canCall = new Bpl.NAryExpr(expr.tok, new Bpl.FunctionCall(canCallFuncID), args);\n\n            Bpl.Expr fargs;\n            // F(args)\n            fargs = etran.TrExpr(fexp);\n\n            if (!CanSafelyInline(fexp, f)) {\n              // Skip inlining, as it would cause arbitrary expressions to pop up in the trigger\n              // TODO this should appear at the outmost call site, not at the innermost. See SnapshotableTrees.dfy\n              reporter.Info(MessageSource.Translator, fexp.tok, \"Some instances of this call cannot safely be inlined.\");\n              // F#canCall(args) ==> F(args)\n              var p = Bpl.Expr.Binary(fargs.tok, BinaryOperator.Opcode.Imp, canCall, fargs);\n              splits.Add(new SplitExprInfo(SplitExprInfo.K.Checked, p));\n              // F#canCall(args) && F(args)\n              var fr = Bpl.Expr.And(canCall, fargs);\n              splits.Add(new SplitExprInfo(SplitExprInfo.K.Free, fr));\n\n            } else {\n              // inline this body\n              var typeSpecializedBody = GetSubstitutedBody(fexp, f);\n              var typeSpecializedResultType = Resolver.SubstType(f.ResultType, fexp.TypeArgumentSubstitutions);\n\n              // recurse on body\n              var ss = new List<SplitExprInfo>();\n              TrSplitExpr(typeSpecializedBody, ss, position, functionHeight, inlineProtectedFunctions, apply_induction, etran);\n              var needsTokenAdjust = TrSplitNeedsTokenAdjustment(typeSpecializedBody);\n              foreach (var s in ss) {\n                if (s.IsChecked) {\n                  var unboxedConjunct = CondApplyUnbox(s.E.tok, s.E, typeSpecializedResultType, expr.Type);\n                  var bodyOrConjunct = Bpl.Expr.Or(fargs, unboxedConjunct);\n                  var tok = needsTokenAdjust ? (IToken)new ForceCheckToken(typeSpecializedBody.tok) : (IToken)new NestedToken(fexp.tok, s.E.tok);\n                  var p = Bpl.Expr.Binary(tok, BinaryOperator.Opcode.Imp, canCall, bodyOrConjunct);\n                  splits.Add(new SplitExprInfo(SplitExprInfo.K.Checked, p));\n                }\n              }\n\n              // allocatedness for arguments to the inlined call in body\n              if (typeSpecializedBody is FunctionCallExpr) {\n                FunctionCallExpr e = (FunctionCallExpr)typeSpecializedBody;\n                for (int i = 0; i < e.Args.Count; i++) {\n                  Expression ee = e.Args[i];\n                  Type t = e.Function.Formals[i].Type;\n                  Expr tr_ee = etran.TrExpr(ee);\n                  Bpl.Expr wh = GetWhereClause(e.tok, tr_ee, cce.NonNull(ee.Type), etran, NOALLOC);\n                  if (wh != null) { fargs = Bpl.Expr.And(fargs, wh); }\n                }\n              }\n\n              // body\n              var trBody = etran.TrExpr(typeSpecializedBody);\n              trBody = CondApplyUnbox(trBody.tok, trBody, typeSpecializedResultType, expr.Type);\n              // F#canCall(args) && F(args) && (b0 && b1 && b2)\n              var fr = Bpl.Expr.And(canCall, BplAnd(fargs, trBody));\n              splits.Add(new SplitExprInfo(SplitExprInfo.K.Free, fr));\n            }\n\n            return true;\n          }\n        }\n\n      } else if (expr is QuantifierExpr && ((QuantifierExpr)expr).SplitQuantifier != null) {\n        return TrSplitExpr(((QuantifierExpr)expr).SplitQuantifierExpression, splits, position, heightLimit, inlineProtectedFunctions, apply_induction, etran);\n      } else if (((position && expr is ForallExpr) || (!position && expr is ExistsExpr))\n        /* NB: only for type arg less quantifiers for now: */\n            && ((QuantifierExpr)expr).TypeArgs.Count == 0) {\n        var e = (QuantifierExpr)expr;\n        var inductionVariables = ApplyInduction(e.BoundVars, e.Attributes);\n        if (apply_induction && inductionVariables.Count != 0) {\n          // From the given quantifier (forall n :: P(n)), generate the seemingly weaker proof obligation\n          //   (forall n :: (forall k :: k < n ==> P(k)) ==> P(n))\n          // For an existential (exists n :: P(n)), it is\n          //   (exists n :: (forall k :: k < n ==> !P(k)) && P(n))\n          //    ^^^^^^                             ^      ^^        <--- note these 3 differences\n          var kvars = new List<BoundVar>();\n          var kk = new List<Bpl.Expr>();\n          var nn = new List<Bpl.Expr>();\n          var toks = new List<IToken>();\n          var types = new List<Type>();\n          var substMap = new Dictionary<IVariable, Expression>();\n          foreach (var n in inductionVariables) {\n            toks.Add(n.tok);\n            types.Add(n.Type.NormalizeExpandKeepConstraints());\n            BoundVar k = new BoundVar(n.tok, CurrentIdGenerator.FreshId(n.Name + \"$ih#\"), n.Type);\n            kvars.Add(k);\n\n            IdentifierExpr ieK = new IdentifierExpr(k.tok, k.AssignUniqueName(currentDeclaration.IdGenerator));\n            ieK.Var = k; ieK.Type = ieK.Var.Type;  // resolve it here\n            kk.Add(etran.TrExpr(ieK));\n\n            IdentifierExpr ieN = new IdentifierExpr(n.tok, n.AssignUniqueName(currentDeclaration.IdGenerator));\n            ieN.Var = n; ieN.Type = ieN.Var.Type;  // resolve it here\n            nn.Add(etran.TrExpr(ieN));\n\n            substMap.Add(n, ieK);\n          }\n          Expression bodyK = Substitute(e.LogicalBody(), null, substMap);\n          Bpl.Expr less = DecreasesCheck(toks, types, types, kk, nn, null, null, false, true);\n\n          Bpl.Expr ihBody = etran.TrExpr(bodyK);\n          if (!position) {\n            ihBody = Bpl.Expr.Not(ihBody);\n          }\n          ihBody = Bpl.Expr.Imp(less, ihBody);\n          List<Variable> bvars = new List<Variable>();\n          Bpl.Expr typeAntecedent = etran.TrBoundVariables(kvars, bvars);  // no need to use allocation antecedent here, because the well-founded less-than ordering assures kk are allocated\n          Bpl.Expr ih;\n          var tr = TrTrigger(etran, e.Attributes, expr.tok, substMap);\n          ih = new Bpl.ForallExpr(expr.tok, bvars, tr, Bpl.Expr.Imp(typeAntecedent, ihBody));\n\n          // More precisely now:\n          //   (forall n :: n-has-expected-type && (forall k :: k < n ==> P(k)) && case0(n)   ==> P(n))\n          //   (forall n :: n-has-expected-type && (forall k :: k < n ==> P(k)) && case...(n) ==> P(n))\n          // or similar for existentials.\n          var caseProduct = new List<Bpl.Expr>() {\n            // make sure to include the correct token information (so, don't just use Bpl.Expr.True here)\n            new Bpl.LiteralExpr(TrSplitNeedsTokenAdjustment(expr) ? new ForceCheckToken(expr.tok) : expr.tok, true)\n          };\n          var i = 0;\n          foreach (var n in inductionVariables) {\n            var newCases = new List<Bpl.Expr>();\n            foreach (var kase in InductionCases(n.Type, nn[i], etran)) {\n              foreach (var cs in caseProduct) {\n                if (kase != Bpl.Expr.True) {  // if there's no case, don't add anything to the token\n                  newCases.Add(Bpl.Expr.Binary(new NestedToken(cs.tok, kase.tok), Bpl.BinaryOperator.Opcode.And, cs, kase));\n                } else {\n                  newCases.Add(cs);\n                }\n              }\n            }\n            caseProduct = newCases;\n            i++;\n          }\n          List<bool> freeOfAlloc = null;\n          if (FrugalHeapUseX) {\n            freeOfAlloc = ComprehensionExpr.BoundedPool.HasBounds(e.Bounds, ComprehensionExpr.BoundedPool.PoolVirtues.IndependentOfAlloc_or_ExplicitAlloc);\n          }\n          bvars = new List<Variable>();\n          typeAntecedent = etran.TrBoundVariables(e.BoundVars, bvars, false, freeOfAlloc);\n          foreach (var kase in caseProduct) {\n            var ante = BplAnd(BplAnd(typeAntecedent, ih), kase);\n            var etranBody = etran.LayerOffset(1);\n            var bdy = etranBody.TrExpr(e.LogicalBody());\n            Bpl.Expr q;\n            var trig = TrTrigger(etranBody, e.Attributes, expr.tok);\n            if (position) {\n              q = new Bpl.ForallExpr(kase.tok, bvars, trig, Bpl.Expr.Imp(ante, bdy));\n            } else {\n              q = new Bpl.ExistsExpr(kase.tok, bvars, trig, Bpl.Expr.And(ante, bdy));\n            }\n            splits.Add(new SplitExprInfo(SplitExprInfo.K.Checked, q));\n          }\n\n          // Finally, assume the original quantifier (forall/exists n :: P(n))\n          splits.Add(new SplitExprInfo(SplitExprInfo.K.Free, etran.TrExpr(expr)));\n          return true;\n        } else {\n          // Don't use induction on these quantifiers.\n          // Nevertheless, produce two translated versions of the quantifier, one that uses #2 functions (that is, layerOffset 1)\n          // for checking and one that uses #1 functions (that is, layerOffset 0) for assuming.\n          var etranBoost = etran.LayerOffset(1);\n          var r = etranBoost.TrExpr(expr);\n          var needsTokenAdjustment = TrSplitNeedsTokenAdjustment(expr);\n          if (needsTokenAdjustment) {\n            r.tok = new ForceCheckToken(expr.tok);\n          }\n          if (etranBoost.Statistics_CustomLayerFunctionCount == 0) {\n            // apparently, the LayerOffset(1) we did had no effect\n            splits.Add(new SplitExprInfo(SplitExprInfo.K.Both, r));\n            return needsTokenAdjustment;\n          } else {\n            splits.Add(new SplitExprInfo(SplitExprInfo.K.Checked, r));  // check the boosted expression\n            splits.Add(new SplitExprInfo(SplitExprInfo.K.Free, etran.TrExpr(expr)));  // assume the ordinary expression\n            return true;\n          }\n        }\n      } else if (((position && expr is ExistsExpr) || (!position && expr is ForallExpr))\n        /* NB: only for type arg less quantifiers for now: */\n            && ((QuantifierExpr)expr).TypeArgs.Count == 0) {\n        // produce two translated versions of the quantifier, one that uses #1 functions (that is, layerOffset 0)\n        // for checking and one that uses #2 functions (that is, layerOffset 1) for assuming.\n        adjustFuelForExists = false; // based on the above comment, we use the etran with correct fuel amount already. No need to adjust anymore.\n        var etranBoost = etran.LayerOffset(1);\n        var r = etran.TrExpr(expr);\n        var needsTokenAdjustment = TrSplitNeedsTokenAdjustment(expr);\n        if (needsTokenAdjustment) {\n          r.tok = new ForceCheckToken(expr.tok);\n        }\n        if (etran.Statistics_CustomLayerFunctionCount == 0) {\n          // apparently, doesn't use layer\n          splits.Add(new SplitExprInfo(SplitExprInfo.K.Both, r));\n          return needsTokenAdjustment;\n        } else {\n          splits.Add(new SplitExprInfo(SplitExprInfo.K.Checked, r));  // check the ordinary expression\n          splits.Add(new SplitExprInfo(SplitExprInfo.K.Free, etranBoost.TrExpr(expr)));  // assume the boosted expression\n          return true;\n        }\n      }\n\n      Bpl.Expr translatedExpression;\n      bool splitHappened;\n      if ((position && expr is ExistsExpr) || (!position && expr is ForallExpr)) {\n        translatedExpression = etran.TrExpr(expr);\n        splitHappened = false;\n      } else {\n        etran = etran.LayerOffset(1);\n        translatedExpression = etran.TrExpr(expr);\n        splitHappened = etran.Statistics_CustomLayerFunctionCount != 0;  // return true if the LayerOffset(1) came into play\n      }\n      if (TrSplitNeedsTokenAdjustment(expr)) {\n        translatedExpression.tok = new ForceCheckToken(expr.tok);\n        splitHappened = true;\n      }\n      splits.Add(new SplitExprInfo(SplitExprInfo.K.Both, translatedExpression));\n      return splitHappened;\n    }\n\n    private bool CanSafelyInline(FunctionCallExpr fexp, Function f) {\n      var visitor = new TriggersExplorer();\n      visitor.Visit(f);\n      return LinqExtender.Zip(f.Formals, fexp.Args).All(formal_concrete => CanSafelySubstitute(visitor.TriggerVariables, formal_concrete.Item1, formal_concrete.Item2));\n    }\n\n    // Using an empty set of old expressions is ok here; the only uses of the triggersCollector will be to check for trigger killers.\n    Triggers.TriggersCollector triggersCollector = new Triggers.TriggersCollector(new Dictionary<Expression, HashSet<OldExpr>>());\n\n    private bool CanSafelySubstitute(ISet<IVariable> protectedVariables, IVariable variable, Expression substitution) {\n      return !(protectedVariables.Contains(variable) && triggersCollector.IsTriggerKiller(substitution));\n    }\n\n    private class VariablesCollector: BottomUpVisitor {\n      internal ISet<IVariable> variables;\n\n      internal VariablesCollector() {\n        this.variables = new HashSet<IVariable>();\n      }\n\n      protected override void VisitOneExpr(Expression expr) {\n        if (expr is IdentifierExpr) {\n          variables.Add((expr as IdentifierExpr).Var);\n        }\n      }\n    }\n\n    private class TriggersExplorer : BottomUpVisitor {\n      VariablesCollector collector;\n\n      internal ISet<IVariable> TriggerVariables { get { return collector.variables; } }\n\n      internal TriggersExplorer() {\n        collector = new VariablesCollector();\n      }\n\n      protected override void VisitOneExpr(Expression expr) {\n        if (expr is QuantifierExpr) {\n          var e = (QuantifierExpr)expr;\n          if (e.SplitQuantifier == null) {\n            foreach (var trigger in (expr as QuantifierExpr).Attributes.AsEnumerable().Where(a => a.Name == \"trigger\").SelectMany(a => a.Args)) {\n              collector.Visit(trigger);\n            }\n          }\n        }\n      }\n    }\n\n    private Expression GetSubstitutedBody(FunctionCallExpr fexp, Function f) {\n      Contract.Requires(fexp != null);\n      Contract.Requires(f != null);\n      var substMap = new Dictionary<IVariable, Expression>();\n      Contract.Assert(fexp.Args.Count == f.Formals.Count);\n      for (int i = 0; i < f.Formals.Count; i++) {\n        Formal p = f.Formals[i];\n        var formalType = Resolver.SubstType(p.Type, fexp.TypeArgumentSubstitutions);\n        Expression arg = fexp.Args[i];\n        arg = new BoxingCastExpr(arg, cce.NonNull(arg.Type), formalType);\n        arg.Type = formalType;  // resolve here\n        substMap.Add(p, arg);\n      }\n      var body = f.Body;\n      if (f is PrefixPredicate) {\n        var pp = (PrefixPredicate)f;\n        body = PrefixSubstitution(pp, body);\n      }\n      body = Substitute(body, fexp.Receiver, substMap, fexp.TypeArgumentSubstitutions);\n      return body;\n    }\n\n    bool TrSplitNeedsTokenAdjustment(Expression expr) {\n      Contract.Requires(expr != null);\n      return RefinementToken.IsInherited(expr.tok, currentModule) && (codeContext == null || !codeContext.MustReverify) && RefinementTransformer.ContainsChange(expr, currentModule);\n    }\n\n    /// <summary>\n    /// Return a subset of \"boundVars\" (in the order giving in \"boundVars\") to which to apply induction to,\n    /// according to :_induction attribute in \"attributes\".\n    /// </summary>\n    List<VarType> ApplyInduction<VarType>(List<VarType> boundVars, Attributes attributes) where VarType : class, IVariable\n    {\n      Contract.Requires(boundVars != null);\n      Contract.Ensures(Contract.Result<List<VarType>>() != null);\n\n      var args = Attributes.FindExpressions(attributes, \"_induction\");\n      if (args == null) {\n        return new List<VarType>();  // don't apply induction\n      }\n\n      var argsAsVars = new List<VarType>();\n      foreach (var arg in args) {\n        // We expect each \"arg\" to be an IdentifierExpr among \"boundVars\"\n        var id = (IdentifierExpr)arg;\n        var bv = (VarType)id.Var;\n        Contract.Assume(boundVars.Contains(bv));\n        argsAsVars.Add(bv);\n      }\n      return argsAsVars;\n    }\n\n    IEnumerable<Bpl.Expr> InductionCases(Type ty, Bpl.Expr expr, ExpressionTranslator etran) {\n      ty = ty.NormalizeExpand();\n      IndDatatypeDecl dt = ty.AsIndDatatype;\n      if (dt == null) {\n        yield return Bpl.Expr.True;\n      } else {\n        UserDefinedType instantiatedType = (UserDefinedType)ty;  // correctness of cast follows from the non-null return of ty.AsDatatype\n        var subst = new Dictionary<TypeParameter, Type>();\n        for (int i = 0; i < dt.TypeArgs.Count; i++) {\n          subst.Add(dt.TypeArgs[i], instantiatedType.TypeArgs[i]);\n        }\n\n        foreach (DatatypeCtor ctor in dt.Ctors) {\n          List<Variable> bvs;\n          List<Bpl.Expr> args;\n          CreateBoundVariables(ctor.Formals, out bvs, out args);\n          Bpl.Expr ct = FunctionCall(ctor.tok, ctor.FullName, predef.DatatypeType, args);\n          // (exists args :: args-have-the-expected-types && ct(args) == expr)\n          Bpl.Expr q = Bpl.Expr.Binary(ctor.tok, BinaryOperator.Opcode.Eq, ct, expr);\n          if (bvs.Count != 0)\n          {\n            int i = 0;\n            Bpl.Expr typeAntecedent = Bpl.Expr.True;\n            foreach (Formal arg in ctor.Formals) {\n              var instantiatedArgType = Resolver.SubstType(arg.Type, subst);\n              Bpl.Expr wh = GetWhereClause(arg.tok, CondApplyUnbox(arg.tok, args[i], arg.Type, instantiatedArgType), instantiatedArgType, etran, NOALLOC);\n              if (wh != null) {\n                typeAntecedent = BplAnd(typeAntecedent, wh);\n              }\n              i++;\n            }\n            var trigger = BplTrigger(ct);  // this is probably never used, because this quantifier is not expected ever to appear in a context where it needs to be instantiated\n            q = new Bpl.ExistsExpr(ctor.tok, bvs, trigger, BplAnd(typeAntecedent, q));\n          }\n          yield return q;\n        }\n      }\n    }\n\n    /// <summary>\n    /// Returns true iff 'v' occurs as a free variable in 'expr'.\n    /// Parameter 'v' is allowed to be a ThisSurrogate, in which case the method return true iff 'this'\n    /// occurs in 'expr'.\n    /// </summary>\n    public static bool ContainsFreeVariable(Expression expr, bool lookForReceiver, IVariable v) {\n      Contract.Requires(expr != null);\n      Contract.Requires(lookForReceiver || v != null);\n\n      if (expr is ThisExpr) {\n        return lookForReceiver;\n      } else if (expr is IdentifierExpr) {\n        IdentifierExpr e = (IdentifierExpr)expr;\n        return e.Var == v;\n      } else {\n        return Contract.Exists(expr.SubExpressions, ee => ContainsFreeVariable(ee, lookForReceiver, v));\n      }\n    }\n\n    // No expression introduces a type variable\n    static void ComputeFreeTypeVariables(Expression expr, ISet<TypeParameter> fvs) {\n      ComputeFreeTypeVariables(expr.Type, fvs);\n      if (expr is FunctionCallExpr) {\n        var e = (FunctionCallExpr)expr;\n        e.TypeArgumentSubstitutions.Iter(kv => ComputeFreeTypeVariables(kv.Value, fvs));\n      }\n      expr.SubExpressions.Iter(ee => ComputeFreeTypeVariables(ee, fvs));\n    }\n\n    static void ComputeFreeTypeVariables(Type ty, ISet<TypeParameter> fvs) {\n      // Add type parameters, unless they are abstract type declarations: they are in scope\n      if (ty.IsTypeParameter && ! ty.AsTypeParameter.IsAbstractTypeDeclaration) {\n        fvs.Add(ty.AsTypeParameter);\n      }\n      ty.NormalizeExpand().TypeArgs.Iter(tt => ComputeFreeTypeVariables(tt, fvs));\n    }\n\n    static void ComputeFreeTypeVariables_All(Type ty, ISet<TypeParameter> fvs) {\n      // Add type parameters\n      if (ty.IsTypeParameter) {\n        fvs.Add(ty.AsTypeParameter);\n      }\n      ty.NormalizeExpand().TypeArgs.Iter(tt => ComputeFreeTypeVariables_All(tt, fvs));\n    }\n\n    public static ISet<IVariable> ComputeFreeVariables(Expression expr) {\n      Contract.Requires(expr != null);\n      ISet<IVariable> fvs = new HashSet<IVariable>();\n      ComputeFreeVariables(expr, fvs);\n      return fvs;\n    }\n    public static void ComputeFreeVariables(Expression expr, ISet<IVariable> fvs) {\n      Contract.Requires(expr != null);\n      Contract.Requires(fvs != null);\n      bool dontCare0 = false, dontCare1 = false;\n      Type dontCareT = null;\n      var dontCareHeapAt = new HashSet<Label>();\n      ComputeFreeVariables(expr, fvs, ref dontCare0, ref dontCare1, dontCareHeapAt, ref dontCareT);\n    }\n    public static void ComputeFreeVariables(Expression expr, ISet<IVariable> fvs, ref bool usesHeap, ref bool usesOldHeap, ISet<Label> freeHeapAtVariables, ref Type usesThis) {\n      Contract.Requires(expr != null);\n\n      if (expr is ThisExpr) {\n        Contract.Assert(expr.Type != null);\n        usesThis = expr.Type;\n        return;\n      } else if (expr is IdentifierExpr) {\n        var e = (IdentifierExpr)expr;\n        fvs.Add(e.Var);\n        return;\n      } else if (expr is MemberSelectExpr) {\n        var e = (MemberSelectExpr)expr;\n        if (e.Obj.Type.IsRefType && !(e.Member is ConstantField)) {\n          usesHeap = true;\n        }\n      } else if (expr is SeqSelectExpr) {\n        var e = (SeqSelectExpr)expr;\n        if (e.Seq.Type.IsArrayType) {\n          usesHeap = true;\n        }\n      } else if (expr is SeqUpdateExpr) {\n        var e = (SeqUpdateExpr)expr;\n        if (e.Seq.Type.IsArrayType) {\n          usesHeap = true;\n        }\n      } else if (expr is MultiSelectExpr) {\n        usesHeap = true;\n      } else if (expr is FunctionCallExpr) {\n        Function f = ((FunctionCallExpr)expr).Function;\n        if (AlwaysUseHeap || f == null || f.ReadsHeap) {\n          usesHeap = true;\n        }\n      } else if (expr is UnchangedExpr) {\n        var e = (UnchangedExpr)expr;\n        if (e.AtLabel == null) {\n          usesOldHeap = true;\n        } else {\n          freeHeapAtVariables.Add(e.AtLabel);\n        }\n      } else if (expr is ApplyExpr) {\n        usesHeap = true;  // because the translation of an ApplyExpr always throws in the heap variable\n      } else if (expr is UnaryOpExpr && ((UnaryOpExpr)expr).Op == UnaryOpExpr.Opcode.Fresh) {\n        usesOldHeap = true;\n      } else if (expr is UnaryOpExpr && ((UnaryOpExpr)expr).Op == UnaryOpExpr.Opcode.Allocated) {\n        usesHeap = true;\n      } else if (expr is UnaryOpExpr && ((UnaryOpExpr)expr).Op == UnaryOpExpr.Opcode.AllocatedArray) {\n        usesHeap = true;\n      } else if (expr is UnaryOpExpr && ((UnaryOpExpr)expr).Op == UnaryOpExpr.Opcode.GlobalView) {\n        usesHeap = true;\n      }\n\n      // visit subexpressions\n      bool uHeap = false, uOldHeap = false;\n      Type uThis = null;\n      expr.SubExpressions.Iter(ee => ComputeFreeVariables(ee, fvs, ref uHeap, ref uOldHeap, freeHeapAtVariables, ref uThis));\n      Contract.Assert(usesThis == null || uThis == null || usesThis.Equals(uThis));\n      usesThis = usesThis ?? uThis;\n      var asOldExpr = expr as OldExpr;\n      if (asOldExpr != null && asOldExpr.AtLabel == null) {\n        usesOldHeap |= uHeap | uOldHeap;\n      } else if (asOldExpr != null) {\n        if (uHeap) {  // if not, then there was no real point in using an \"old\" expression\n          freeHeapAtVariables.Add(asOldExpr.AtLabel);\n        }\n        usesOldHeap |= uOldHeap;\n      } else {\n        usesHeap |= uHeap;\n        usesOldHeap |= uOldHeap;\n      }\n\n      if (expr is LetExpr) {\n        var e = (LetExpr)expr;\n        foreach (var v in e.BoundVars) {\n          fvs.Remove(v);\n        }\n      } else if (expr is ComprehensionExpr) {\n        var e = (ComprehensionExpr)expr;\n        foreach (var v in e.BoundVars) {\n          fvs.Remove(v);\n        }\n      } else if (expr is MatchExpr me) {\n        foreach (var v in me.Cases.SelectMany(c => c.Arguments)) {\n          fvs.Remove(v);\n        }\n      }\n    }\n\n    public static bool NonGhostsUseHeap { get { return ArmadaOptions.O.Allocated == 1 || ArmadaOptions.O.Allocated == 2; } }\n    public static bool AlwaysUseHeap { get { return ArmadaOptions.O.Allocated == 2; } }\n    public static bool CommonHeapUse { get { return ArmadaOptions.O.Allocated >= 2; } }\n    public static bool FrugalHeapUse { get { return ArmadaOptions.O.Allocated >= 3; } }\n    public static bool FrugalHeapUseX { get { return ArmadaOptions.O.Allocated == 4; } }\n\n    public static bool UsesHeap(Expression expr) {\n      UsesHeapVisitor visitor = new UsesHeapVisitor();\n      visitor.Visit(expr);\n      if (visitor.foundHeap) {\n        return true;\n      }\n      bool usesHeap = false, usesOldHeap = false;\n      var FVsHeapAt = new HashSet<Label>();\n      Type usesThis = null;\n      ComputeFreeVariables(expr, new HashSet<IVariable>(), ref usesHeap, ref usesOldHeap, FVsHeapAt, ref usesThis);\n      return usesHeap || usesOldHeap || FVsHeapAt.Count != 0 || usesThis != null;\n    }\n\n    class UsesHeapVisitor : BottomUpVisitor\n    {\n      internal bool foundHeap = false;\n      Type usesThis = null;\n      protected override void VisitOneExpr(Expression expr) {\n        LetExpr letExpr = expr as LetExpr;\n        if (letExpr != null && !letExpr.Exact) {\n          foundHeap = true; // see comment in LetSuchThatExprInfo: \"UsesHeap = true;  // note, we ignore \"usesHeap\" and always record it as \"true\", because various type antecedents need access to the heap (hopefully, this is okay in the contexts in which the let-such-that expression is used)\"\n        }\n        FunctionCallExpr call = expr as FunctionCallExpr;\n        if (call != null && call.Function != null && call.Function.ReadsHeap) {\n          foundHeap = true;\n        }\n        if (expr is ApplyExpr || expr is SeqConstructionExpr) {\n          foundHeap = true;\n        }\n        ThisExpr thisExpr = expr as ThisExpr;\n        if (thisExpr != null && thisExpr.Type == null) { // this shouldn't happen, but there appears to be a bug in trait resolution (see TraitCompile.dfy); it causes ComputeFreeVariables to blow up\n          foundHeap = true;\n        } else if (thisExpr != null && usesThis != null && !thisExpr.Type.Equals(usesThis)) { // also causes ComputeFreeVariables to blow up (see TraitExample.dfy)\n          foundHeap = true;\n        } else if (thisExpr != null) {\n          usesThis = thisExpr.Type;\n        }\n      }\n    }\n\n    /// <summary>\n    /// Returns an expression like \"expr\", but where free occurrences of \"v\" have been replaced by \"e\".\n    /// </summary>\n    public static Expression Substitute(Expression expr, IVariable v, Expression e) {\n      Contract.Requires(expr != null);\n      Contract.Requires(v != null);\n      Contract.Requires(e != null);\n      Contract.Ensures(Contract.Result<Expression>() != null);\n      var substMap = new Dictionary<IVariable, Expression>();\n      substMap.Add(v, e);\n      return Substitute(expr, null, substMap);\n    }\n\n    public static Expression Substitute(Expression expr, Expression receiverReplacement, Dictionary<IVariable, Expression/*!*/>/*!*/ substMap, Dictionary<TypeParameter, Type>/*?*/ typeMap = null) {\n      Contract.Requires(expr != null);\n      Contract.Requires(cce.NonNullDictionaryAndValues(substMap));\n      Contract.Ensures(Contract.Result<Expression>() != null);\n      var s = new Substituter(receiverReplacement, substMap, typeMap ?? new Dictionary<TypeParameter, Type>());\n      return s.Substitute(expr);\n    }\n\n    public static Expression InlineLet(LetExpr letExpr) {\n      Contract.Requires(letExpr.LHSs.All(p => p.Var != null));\n      var substMap = new Dictionary<IVariable, Expression>();\n      for (var i = 0; i < letExpr.LHSs.Count; i++) {\n        substMap.Add(letExpr.LHSs[i].Var, letExpr.RHSs[i]);\n      }\n      return Translator.Substitute(letExpr.Body, null, substMap);\n    }\n\n    public class FunctionCallSubstituter : Substituter\n    {\n      public readonly Function A, B;\n      public FunctionCallSubstituter(Expression receiverReplacement, Dictionary<IVariable, Expression/*!*/>/*!*/ substMap, Function a, Function b)\n        : base(receiverReplacement, substMap, new Dictionary<TypeParameter,Type>()) {\n        A = a;\n        B = b;\n      }\n      public override Expression Substitute(Expression expr) {\n        if (expr is FunctionCallExpr) {\n          FunctionCallExpr e = (FunctionCallExpr)expr;\n          Expression receiver = Substitute(e.Receiver);\n          List<Expression> newArgs = SubstituteExprList(e.Args);\n          FunctionCallExpr newFce = new FunctionCallExpr(expr.tok, e.Name, receiver, e.OpenParen, newArgs);\n          if (e.Function == A) {\n            newFce.Function = B;\n            newFce.Type = e.Type; // TODO: this may not work with type parameters.\n          } else {\n            newFce.Function = e.Function;\n            newFce.Type = e.Type;\n          }\n          newFce.TypeArgumentSubstitutions = e.TypeArgumentSubstitutions;  // resolve here\n          return newFce;\n        }\n        return base.Substitute(expr);\n      }\n    }\n    public class PrefixCallSubstituter : Substituter\n    {\n      readonly FixpointPredicate fixpointPred;\n      readonly Expression unrollDepth;\n      readonly ModuleDefinition module;\n      public PrefixCallSubstituter(Expression receiverReplacement, Dictionary<IVariable, Expression/*!*/>/*!*/ substMap, Dictionary<TypeParameter, Type> tySubstMap, FixpointPredicate fixpointpred, Expression depth)\n        : base(receiverReplacement, substMap, tySubstMap) {\n        Contract.Requires(fixpointpred != null);\n        Contract.Requires(depth != null);\n        fixpointPred = fixpointpred;\n        unrollDepth = depth;\n        module = fixpointpred.EnclosingClass.Module;\n      }\n      public override Expression Substitute(Expression expr) {\n        if (expr is FunctionCallExpr) {\n          var e = (FunctionCallExpr)expr;\n          var cof = e.Function as FixpointPredicate;\n          if (cof != null && ModuleDefinition.InSameSCC(cof, fixpointPred)) {\n            expr = cof.CreatePrefixPredicateCall(e, unrollDepth);\n          }\n        }\n        return base.Substitute(expr);\n      }\n    }\n\n    public class ExprSubstituter : Substituter {\n      readonly List<Tuple<Expression, IdentifierExpr>> exprSubstMap;\n      List<Tuple<Expression, IdentifierExpr>> usedSubstMap;\n\n      public ExprSubstituter(List<Tuple<Expression, IdentifierExpr>> exprSubstMap)\n        : base(null, new Dictionary<IVariable, Expression>(), new Dictionary<TypeParameter,Type>()) {\n        this.exprSubstMap = exprSubstMap;\n        this.usedSubstMap = new List<Tuple<Expression, IdentifierExpr>>();\n      }\n\n      public bool TryGetExprSubst(Expression expr, out IdentifierExpr ie) {\n        var entry = usedSubstMap.Find(x => Triggers.ExprExtensions.ExpressionEq(expr, x.Item1));\n        if (entry != null) {\n          ie = entry.Item2;\n          return true;\n        }\n        entry = exprSubstMap.Find(x => Triggers.ExprExtensions.ExpressionEq(expr, x.Item1));\n        if (entry != null) {\n          usedSubstMap.Add(entry);\n          ie = entry.Item2;\n          return true;\n        } else {\n          ie = null;\n          return false;\n        }\n      }\n\n      public override Expression Substitute(Expression expr) {\n        IdentifierExpr ie;\n        if (TryGetExprSubst(expr, out ie)) {\n          return cce.NonNull(ie);\n        }\n        if (expr is QuantifierExpr) {\n          var newExpr = expr;\n          var e = expr as QuantifierExpr;\n          var newAttrs = e.Attributes;\n          var newRange = e.Range == null ? null : Substitute(e.Range);\n          var newTerm = Substitute(e.Term);\n          var newBoundVars = new List<BoundVar>();\n          newBoundVars.AddRange(e.BoundVars);\n          var newBounds = e.Bounds == null ? null : e.Bounds.ConvertAll(bound => SubstituteBoundedPool(bound));\n          if (newRange != e.Range || newTerm != e.Term) {\n            if (expr is ForallExpr) {\n              foreach (var entry in usedSubstMap) {\n                newExpr = new BinaryExpr(expr.tok, BinaryExpr.ResolvedOpcode.EqCommon, entry.Item2, entry.Item1);\n                if (newRange == null) {\n                  newRange = newExpr;\n                } else {\n                  newTerm = new BinaryExpr(expr.tok, BinaryExpr.ResolvedOpcode.Imp, newRange, newTerm);\n                  newRange = newExpr;\n                }\n                newBoundVars.Add((BoundVar)entry.Item2.Var);\n                newBounds.Add(new ComprehensionExpr.ExactBoundedPool(entry.Item1));\n              }\n              newExpr = new ForallExpr(expr.tok, ((QuantifierExpr)expr).TypeArgs, newBoundVars, newRange, newTerm, newAttrs) { Bounds = newBounds };\n            } else if (expr is ExistsExpr) {\n              foreach (var entry in usedSubstMap) {\n                newExpr = new BinaryExpr(expr.tok, BinaryExpr.ResolvedOpcode.EqCommon, entry.Item2, entry.Item1);\n                if (newRange == null) {\n                  newRange = newExpr;\n                } else {\n                  newTerm = new BinaryExpr(expr.tok, BinaryExpr.ResolvedOpcode.And, newRange, newTerm);\n                  newRange = newExpr;\n                }\n                newBoundVars.Add((BoundVar)entry.Item2.Var);\n                newBounds.Add(new ComprehensionExpr.ExactBoundedPool(entry.Item1));\n              }\n              newExpr = new ExistsExpr(expr.tok, ((QuantifierExpr)expr).TypeArgs, newBoundVars, newRange, newTerm, newAttrs) { Bounds = newBounds };\n            }\n            usedSubstMap.Clear();\n          }\n          newExpr.Type = expr.Type;\n          return newExpr;\n        }\n        return base.Substitute(expr);\n      }\n    }\n\n    /// <summary>\n    /// The substituter has methods to create an expression from an existing one, where the new one has the indicated\n    /// substitutions for \"this\" (receiverReplacement), variables (substMap), and types (typeMap).\n    /// CAUTION:  The result of the substitution is intended for use by TrExpr, not for well-formedness checks.  In\n    /// particular, the substituter does not copy parts of an expression that are used only for well-formedness checks.\n    /// </summary>\n    public class Substituter\n    {\n      public readonly Expression receiverReplacement;\n      public readonly Dictionary<IVariable, Expression/*!*/>/*!*/ substMap;\n      public readonly Dictionary<TypeParameter, Type/*!*/>/*!*/ typeMap;\n\n      public Substituter(Expression receiverReplacement, Dictionary<IVariable, Expression/*!*/>/*!*/ substMap, Dictionary<TypeParameter, Type> typeMap) {\n        Contract.Requires(substMap != null);\n        Contract.Requires(typeMap != null);\n        this.receiverReplacement = receiverReplacement;\n        this.substMap = substMap;\n        this.typeMap = typeMap;\n      }\n      public virtual Expression Substitute(Expression expr) {\n        Contract.Requires(expr != null);\n        Contract.Ensures(Contract.Result<Expression>() != null);\n\n        Expression newExpr = null;  // set to non-null value only if substitution has any effect; if non-null, the .Type of newExpr will be filled in at end\n\n        if (expr is LiteralExpr || expr is WildcardExpr || expr is BoogieWrapper || expr is MeExpr || expr is StoreBufferEmptyExpr || expr is TotalStateExpr) {\n          // nothing to substitute\n        } else if (expr is IfUndefinedExpr) {\n          IfUndefinedExpr e = (IfUndefinedExpr)expr;\n          var newPotentiallyUnsafe = Substitute(e.PotentiallyUnsafe);\n          var newSafeSubstitution = Substitute(e.SafeSubstitution);\n          newExpr = new IfUndefinedExpr(e.tok, newPotentiallyUnsafe, newSafeSubstitution);\n        } else if (expr is ThisExpr) {\n          return receiverReplacement == null ? expr : receiverReplacement;\n        } else if (expr is IdentifierExpr) {\n          IdentifierExpr e = (IdentifierExpr)expr;\n          Expression substExpr;\n          if (substMap.TryGetValue(e.Var, out substExpr)) {\n            var substIdExpr = substExpr as IdentifierExpr;\n            if (substIdExpr != null) {\n              // clone it, using the source location of the original\n              substExpr = new IdentifierExpr(expr.tok, substIdExpr.Var);\n            }\n            return cce.NonNull(substExpr);\n          }\n        } else if (expr is DisplayExpression) {\n          DisplayExpression e = (DisplayExpression)expr;\n          List<Expression> newElements = SubstituteExprList(e.Elements);\n          if (newElements != e.Elements) {\n            if (expr is SetDisplayExpr) {\n              newExpr = new SetDisplayExpr(expr.tok, ((SetDisplayExpr)expr).Finite, newElements);\n            } else if (expr is MultiSetDisplayExpr) {\n              newExpr = new MultiSetDisplayExpr(expr.tok, newElements);\n            } else {\n              newExpr = new SeqDisplayExpr(expr.tok, newElements);\n            }\n          }\n        } else if (expr is MapDisplayExpr) {\n          var e = (MapDisplayExpr)expr;\n          var elmts = new List<ExpressionPair>();\n          var anyChanges = false;\n          foreach (var ep in e.Elements) {\n            var a = Substitute(ep.A);\n            var b = Substitute(ep.B);\n            elmts.Add(new ExpressionPair(a, b));\n            if (a != ep.A || b != ep.B) {\n              anyChanges = true;\n            }\n          }\n          if (anyChanges) {\n            newExpr = new MapDisplayExpr(expr.tok, e.Finite, elmts);\n          }\n        } else if (expr is MemberSelectExpr) {\n          MemberSelectExpr fse = (MemberSelectExpr)expr;\n          Expression substE = Substitute(fse.Obj);\n          MemberSelectExpr fseNew = new MemberSelectExpr(fse.tok, substE, fse.MemberName);\n          fseNew.Member = fse.Member;\n          fseNew.TypeApplication = fse.TypeApplication.ConvertAll(t => Resolver.SubstType(t, typeMap));\n          newExpr = fseNew;\n        } else if (expr is SeqSelectExpr) {\n          SeqSelectExpr sse = (SeqSelectExpr)expr;\n          Expression seq = Substitute(sse.Seq);\n          Expression e0 = sse.E0 == null ? null : Substitute(sse.E0);\n          Expression e1 = sse.E1 == null ? null : Substitute(sse.E1);\n          if (seq != sse.Seq || e0 != sse.E0 || e1 != sse.E1) {\n            newExpr = new SeqSelectExpr(sse.tok, sse.SelectOne, seq, e0, e1);\n          }\n\n        } else if (expr is SeqUpdateExpr) {\n          var sse = (SeqUpdateExpr)expr;\n          if (sse.ResolvedUpdateExpr != null) {\n            return Substitute(sse.ResolvedUpdateExpr);\n          } else {\n            Expression seq = Substitute(sse.Seq);\n            Expression index = Substitute(sse.Index);\n            Expression val = Substitute(sse.Value);\n            if (seq != sse.Seq || index != sse.Index || val != sse.Value) {\n              newExpr = new SeqUpdateExpr(sse.tok, seq, index, val);\n            }\n          }\n\n        } else if (expr is MultiSelectExpr) {\n          MultiSelectExpr mse = (MultiSelectExpr)expr;\n          Expression array = Substitute(mse.Array);\n          List<Expression> newArgs = SubstituteExprList(mse.Indices);\n          if (array != mse.Array || newArgs != mse.Indices) {\n            newExpr = new MultiSelectExpr(mse.tok, array, newArgs);\n          }\n\n        } else if (expr is FunctionCallExpr) {\n          FunctionCallExpr e = (FunctionCallExpr)expr;\n          Expression receiver = Substitute(e.Receiver);\n          List<Expression> newArgs = SubstituteExprList(e.Args);\n          var newTypeInstantiation = SubstituteTypeMap(e.TypeArgumentSubstitutions);\n          if (receiver != e.Receiver || newArgs != e.Args || newTypeInstantiation != e.TypeArgumentSubstitutions) {\n            FunctionCallExpr newFce = new FunctionCallExpr(expr.tok, e.Name, receiver, e.OpenParen, newArgs);\n            newFce.Function = e.Function;  // resolve on the fly (and set newFce.Type below, at end)\n            newFce.CoCall = e.CoCall;  // also copy the co-call status\n            newFce.CoCallHint = e.CoCallHint;  // and any co-call hint\n            newFce.TypeArgumentSubstitutions = newTypeInstantiation;\n            newExpr = newFce;\n          }\n\n        } else if (expr is ApplyExpr) {\n          ApplyExpr e = (ApplyExpr)expr;\n          Expression fn = Substitute(e.Function);\n          List<Expression> args = SubstituteExprList(e.Args);\n          newExpr = new ApplyExpr(e.tok, fn, args);\n\n        } else if (expr is DatatypeValue) {\n          DatatypeValue dtv = (DatatypeValue)expr;\n          List<Expression> newArgs = SubstituteExprList(dtv.Arguments);\n          if (newArgs != dtv.Arguments) {\n            DatatypeValue newDtv = new DatatypeValue(dtv.tok, dtv.DatatypeName, dtv.MemberName, newArgs);\n            newDtv.Ctor = dtv.Ctor;  // resolve on the fly (and set newDtv.Type below, at end)\n            newDtv.InferredTypeArgs = Map(dtv.InferredTypeArgs, tt => Resolver.SubstType(tt, typeMap));\n                                     // ^ Set the correct type arguments to the constructor\n            newExpr = newDtv;\n          }\n\n        } else if (expr is OldExpr) {\n          var e = (OldExpr)expr;\n          // Note, it is up to the caller to avoid variable capture.  In most cases, this is not a\n          // problem, since variables have unique declarations.  However, it is an issue if the substitution\n          // takes place inside an OldExpr.  In those cases (see LetExpr), the caller can use a\n          // BoogieWrapper before calling Substitute.\n          Expression se = Substitute(e.E);\n          if (se != e.E) {\n            newExpr = new OldExpr(expr.tok, se, e.At) { AtLabel = e.AtLabel };\n          }\n        } else if (expr is UnchangedExpr) {\n          var e = (UnchangedExpr)expr;\n          var fr = new List<FrameExpression>();\n          var anythingChanged = false;\n          foreach (var fe in e.Frame) {\n            var fefe = SubstFrameExpr(fe);\n            if (fefe != fe) {\n              anythingChanged = true;\n            }\n            fr.Add(fefe);\n          }\n          if (anythingChanged) {\n            newExpr = new UnchangedExpr(e.tok, fr, e.At) { AtLabel = e.AtLabel };\n          }\n        } else if (expr is SeqConstructionExpr) {\n          var e = (SeqConstructionExpr)expr;\n          var sn = Substitute(e.N);\n          var sinit = Substitute(e.Initializer);\n          if (sn != e.N || sinit != e.Initializer) {\n            newExpr = new SeqConstructionExpr(expr.tok, sn, sinit);\n          }\n        } else if (expr is MultiSetFormingExpr) {\n          var e = (MultiSetFormingExpr)expr;\n          var se = Substitute(e.E);\n          if (se != e.E) {\n            newExpr = new MultiSetFormingExpr(expr.tok, se);\n          }\n        } else if (expr is BoxingCastExpr) {\n          var e = (BoxingCastExpr)expr;\n          var se = Substitute(e.E);\n          if (se != e.E) {\n            newExpr = new BoxingCastExpr(se, e.FromType, e.ToType);\n          }\n        } else if (expr is UnaryExpr) {\n          var e = (UnaryExpr)expr;\n          Expression se = Substitute(e.E);\n          if (se != e.E) {\n            if (e is UnaryOpExpr) {\n              var ee = (UnaryOpExpr)e;\n              newExpr = new UnaryOpExpr(expr.tok, ee.Op, se);\n            } else if (e is ConversionExpr) {\n              var ee = (ConversionExpr)e;\n              newExpr = new ConversionExpr(expr.tok, se, ee.ToType);\n            } else {\n              Contract.Assert(false);  // unexpected UnaryExpr subtype\n            }\n          }\n        } else if (expr is BinaryExpr) {\n          BinaryExpr e = (BinaryExpr)expr;\n          Expression e0 = Substitute(e.E0);\n          Expression e1 = Substitute(e.E1);\n          if (e0 != e.E0 || e1 != e.E1) {\n            BinaryExpr newBin = new BinaryExpr(expr.tok, e.Op, e0, e1);\n            newBin.ResolvedOp = e.ResolvedOp;  // part of what needs to be done to resolve on the fly (newBin.Type is set below, at end)\n            newExpr = newBin;\n          }\n\n        } else if (expr is TernaryExpr) {\n          var e = (TernaryExpr)expr;\n          var e0 = Substitute(e.E0);\n          var e1 = Substitute(e.E1);\n          var e2 = Substitute(e.E2);\n          if (e0 != e.E0 || e1 != e.E1 || e2 != e.E2) {\n            newExpr = new TernaryExpr(expr.tok, e.Op, e0, e1, e2);\n          }\n\n        } else if (expr is LetExpr) {\n          var e = (LetExpr)expr;\n          if (e.Exact) {\n            var rhss = new List<Expression>();\n            bool anythingChanged = false;\n            foreach (var rhs in e.RHSs) {\n              var r = Substitute(rhs);\n              if (r != rhs) {\n                anythingChanged = true;\n              }\n              rhss.Add(r);\n            }\n            // Note, CreateBoundVarSubstitutions has the side effect of updating the substitution map.\n            // For an Exact let expression, this is something that needs to be done after substituting\n            // in the RHSs.\n            var newCasePatterns = CreateCasePatternSubstitutions(e.LHSs, true);\n            if (newCasePatterns != e.LHSs) {\n              anythingChanged = true;\n            }\n\n            var body = Substitute(e.Body);\n            // undo any changes to substMap (could be optimized to do this only if newBoundVars != e.Vars)\n            foreach (var bv in e.BoundVars) {\n              substMap.Remove(bv);\n            }\n            // Put things together\n            if (anythingChanged || body != e.Body) {\n              newExpr = new LetExpr(e.tok, newCasePatterns, rhss, body, e.Exact);\n            }\n          } else {\n            var rhs = Substitute(e.RHSs[0]);\n            var body = Substitute(e.Body);\n            if (rhs == e.RHSs[0] && body == e.Body) {\n              return e;\n            }\n            // keep copies of the substitution maps so we can reuse them at desugaring time\n            var newSubstMap = new Dictionary<IVariable, Expression>(substMap);\n            var newTypeMap = new Dictionary<TypeParameter, Type>(typeMap);\n            var newLet = new SubstLetExpr(e.tok, e.LHSs, new List<Expression>{ rhs }, body, e.Exact, e, newSubstMap, newTypeMap);\n            newExpr = newLet;\n          }\n\n        } else if (expr is MatchExpr) {\n          var e = (MatchExpr)expr;\n          var src = Substitute(e.Source);\n          bool anythingChanged = src != e.Source;\n          var cases = new List<MatchCaseExpr>();\n          foreach (var mc in e.Cases) {\n            var newBoundVars = CreateBoundVarSubstitutions(mc.Arguments, false);\n            var body = Substitute(mc.Body);\n            // undo any changes to substMap (could be optimized to do this only if newBoundVars != mc.Arguments)\n            foreach (var bv in mc.Arguments) {\n              substMap.Remove(bv);\n            }\n            // Put things together\n            if (newBoundVars != mc.Arguments || body != mc.Body) {\n              anythingChanged = true;\n            }\n            var newCaseExpr = new MatchCaseExpr(mc.tok, mc.Id, newBoundVars, body);\n            newCaseExpr.Ctor = mc.Ctor;  // resolve here\n            cases.Add(newCaseExpr);\n          }\n          if (anythingChanged) {\n            var newME = new MatchExpr(expr.tok, src, cases, e.UsesOptionalBraces);\n            newME.MissingCases.AddRange(e.MissingCases);\n            newExpr = newME;\n          }\n\n        } else if (expr is NamedExpr) {\n          var e = (NamedExpr)expr;\n          var body = Substitute(e.Body);\n          var contract = e.Contract == null ? null : Substitute(e.Contract);\n          newExpr = new NamedExpr(e.tok, e.Name, body, contract, e.ReplacerToken);\n        } else if (expr is ComprehensionExpr) {\n          var e = (ComprehensionExpr)expr;\n          // For quantifiers and setComprehesion we want to make sure that we don't introduce name clashes with\n          // the enclosing scopes.\n\n          var q = e as QuantifierExpr;\n          if (q != null && q.SplitQuantifier != null) {\n            return Substitute(q.SplitQuantifierExpression);\n          }\n\n          var newBoundVars = CreateBoundVarSubstitutions(e.BoundVars, expr is ForallExpr || expr is ExistsExpr || expr is SetComprehension);\n          var newRange = e.Range == null ? null : Substitute(e.Range);\n          var newTerm = Substitute(e.Term);\n          var newAttrs = SubstAttributes(e.Attributes);\n          if (newBoundVars != e.BoundVars || newRange != e.Range || newTerm != e.Term || newAttrs != e.Attributes) {\n            if (e is SetComprehension) {\n              newExpr = new SetComprehension(expr.tok, ((SetComprehension)e).Finite, newBoundVars, newRange, newTerm, newAttrs);\n            } else if (e is MapComprehension) {\n              var mc = (MapComprehension)e;\n              var newTermLeft = mc.IsGeneralMapComprehension ? Substitute(mc.TermLeft) : null;\n              newExpr = new MapComprehension(expr.tok, mc.Finite, newBoundVars, newRange, newTermLeft, newTerm, newAttrs);\n            } else if (expr is ForallExpr) {\n              newExpr = new ForallExpr(expr.tok, ((QuantifierExpr)expr).TypeArgs, newBoundVars, newRange, newTerm, newAttrs);\n            } else if (expr is ExistsExpr) {\n              newExpr = new ExistsExpr(expr.tok, ((QuantifierExpr)expr).TypeArgs, newBoundVars, newRange, newTerm, newAttrs);\n            } else if (expr is LambdaExpr) {\n              var l = (LambdaExpr)expr;\n              newExpr = new LambdaExpr(e.tok, newBoundVars, newRange, l.Reads.ConvertAll(SubstFrameExpr), newTerm);\n            } else {\n              Contract.Assert(false);  // unexpected ComprehensionExpr\n            }\n            if (e.Bounds != null) {\n              ((ComprehensionExpr)newExpr).Bounds = e.Bounds.ConvertAll(bound => SubstituteBoundedPool(bound));\n            }\n          }\n          // undo any changes to substMap (could be optimized to do this only if newBoundVars != e.BoundVars)\n          foreach (var bv in e.BoundVars) {\n            substMap.Remove(bv);\n          }\n\n        } else if (expr is StmtExpr) {\n          var e = (StmtExpr)expr;\n          newExpr = new StmtExpr(e.tok, SubstStmt(e.S), Substitute(e.E));\n\n        } else if (expr is ITEExpr) {\n          ITEExpr e = (ITEExpr)expr;\n          Expression test = Substitute(e.Test);\n          Expression thn = Substitute(e.Thn);\n          Expression els = Substitute(e.Els);\n          if (test != e.Test || thn != e.Thn || els != e.Els) {\n            newExpr = new ITEExpr(expr.tok, e.IsBindingGuard, test, thn, els);\n          }\n\n        } else if (expr is ConcreteSyntaxExpression) {\n          var e = (ConcreteSyntaxExpression)expr;\n          return Substitute(e.ResolvedExpression);\n\n        } else if (expr is RevealExpr) {\n          var e = (RevealExpr)expr;\n          return Substitute(e.ResolvedExpression);\n\n        } else if (expr is BoogieFunctionCall) {\n          var e = (BoogieFunctionCall)expr;\n          bool anythingChanged = false;\n          var newTyArgs = new List<Type>();\n          foreach (var arg in e.TyArgs) {\n            var newArg = Resolver.SubstType(arg, typeMap);\n            if (newArg != arg) {\n              anythingChanged = true;\n            }\n            newTyArgs.Add(newArg);\n          }\n          var newArgs = new List<Expression>();\n          foreach (var arg in e.Args) {\n            var newArg = Substitute(arg);\n            if (newArg != arg) {\n              anythingChanged = true;\n            }\n            newArgs.Add(newArg);\n          }\n          if (anythingChanged) {\n            newExpr = new BoogieFunctionCall(e.tok, e.FunctionName, e.UsesHeap, e.UsesOldHeap, e.HeapAtLabels, newArgs, newTyArgs);\n          }\n\n        } else {\n          Contract.Assume(false); // unexpected Expression\n        }\n\n        if (newExpr == null) {\n          return expr;\n        } else {\n          newExpr.Type = Resolver.SubstType(expr.Type, typeMap);  // resolve on the fly (any additional resolution must be done above)\n          return newExpr;\n        }\n      }\n\n      public ComprehensionExpr.BoundedPool SubstituteBoundedPool(ComprehensionExpr.BoundedPool bound) {\n        if (bound == null) {\n          return null;\n        } else if (bound is ComprehensionExpr.ExactBoundedPool) {\n          var b = (ComprehensionExpr.ExactBoundedPool)bound;\n          return new ComprehensionExpr.ExactBoundedPool(Substitute(b.E));\n        } else if (bound is ComprehensionExpr.BoolBoundedPool) {\n          return bound;  // nothing to substitute\n        } else if (bound is ComprehensionExpr.CharBoundedPool) {\n          return bound;  // nothing to substitute\n        } else if (bound is ComprehensionExpr.IntBoundedPool) {\n          var b = (ComprehensionExpr.IntBoundedPool)bound;\n          return new ComprehensionExpr.IntBoundedPool(b.LowerBound == null ? null : Substitute(b.LowerBound), b.UpperBound == null ? null : Substitute(b.UpperBound));\n        } else if (bound is ComprehensionExpr.SetBoundedPool) {\n          var b = (ComprehensionExpr.SetBoundedPool)bound;\n          return new ComprehensionExpr.SetBoundedPool(Substitute(b.Set), b.ExactTypes, b.IsFiniteCollection);\n        } else if (bound is ComprehensionExpr.MultiSetBoundedPool) {\n          var b = (ComprehensionExpr.MultiSetBoundedPool)bound;\n          return new ComprehensionExpr.MultiSetBoundedPool(Substitute(b.MultiSet), b.ExactTypes);\n        } else if (bound is ComprehensionExpr.SubSetBoundedPool) {\n          var b = (ComprehensionExpr.SubSetBoundedPool)bound;\n          return new ComprehensionExpr.SubSetBoundedPool(Substitute(b.UpperBound), b.IsFiniteCollection);\n        } else if (bound is ComprehensionExpr.SuperSetBoundedPool) {\n          var b = (ComprehensionExpr.SuperSetBoundedPool)bound;\n          return new ComprehensionExpr.SuperSetBoundedPool(Substitute(b.LowerBound));\n        } else if (bound is ComprehensionExpr.MapBoundedPool) {\n          var b = (ComprehensionExpr.MapBoundedPool)bound;\n          return new ComprehensionExpr.MapBoundedPool(Substitute(b.Map), b.ExactTypes, b.IsFiniteCollection);\n        } else if (bound is ComprehensionExpr.SeqBoundedPool) {\n          var b = (ComprehensionExpr.SeqBoundedPool)bound;\n          return new ComprehensionExpr.SeqBoundedPool(Substitute(b.Seq), b.ExactTypes);\n        } else if (bound is ComprehensionExpr.DatatypeBoundedPool) {\n          return bound;  // nothing to substitute\n        } else if (bound is ComprehensionExpr.DatatypeInclusionBoundedPool) {\n          return bound;  // nothing to substitute\n        } else if (bound is ComprehensionExpr.AllocFreeBoundedPool) {\n          return bound;  // nothing to substitute\n        } else if (bound is ComprehensionExpr.ExplicitAllocatedBoundedPool) {\n          return bound;  // nothing to substitute\n        } else if (bound is AssignSuchThatStmt.WiggleWaggleBound) {\n          return bound;  // nothing to substitute\n        } else if (bound is ComprehensionExpr.SpecialAllocIndependenceAllocatedBoundedPool) {\n          return bound;  // nothing to substitute\n        } else {\n          Contract.Assume(false);  // unexpected ComprehensionExpr.BoundedPool\n          throw new cce.UnreachableException();  // to please compiler\n        }\n      }\n\n      /// <summary>\n      /// Return a list of bound variables, of the same length as 'vars' but with possible substitutions.\n      /// For any change necessary, update 'substMap' to reflect the new substitution; the caller is responsible for\n      /// undoing these changes once the updated 'substMap' has been used.\n      /// If no changes are necessary, the list returned is exactly 'vars' and 'substMap' is unchanged.\n      /// </summary>\n      protected virtual List<BoundVar> CreateBoundVarSubstitutions(List<BoundVar> vars, bool forceSubstitutionOfBoundVars) {\n        bool anythingChanged = false;\n        var newBoundVars = new List<BoundVar>();\n        foreach (var bv in vars) {\n          var tt = Resolver.SubstType(bv.Type, typeMap);\n          if (!forceSubstitutionOfBoundVars && tt == bv.Type) {\n            newBoundVars.Add(bv);\n          } else {\n            anythingChanged = true;\n            var newBv = new BoundVar(bv.tok, bv.Name, tt);\n            newBoundVars.Add(newBv);\n            // update substMap to reflect the new BoundVar substitutions\n            var ie = new IdentifierExpr(newBv.tok, newBv.Name);\n            ie.Var = newBv;  // resolve here\n            ie.Type = newBv.Type;  // resolve here\n            substMap.Add(bv, ie);\n          }\n        }\n        return anythingChanged ? newBoundVars : vars;\n      }\n\n      /// <summary>\n      /// Return a list of case patterns, of the same length as 'patterns' but with possible substitutions.\n      /// For any change necessary, update 'substMap' to reflect the new substitution; the caller is responsible for\n      /// undoing these changes once the updated 'substMap' has been used.\n      /// If no changes are necessary, the list returned is exactly 'patterns' and 'substMap' is unchanged.\n      /// </summary>\n      protected virtual List<CasePattern<BoundVar>> CreateCasePatternSubstitutions(List<CasePattern<BoundVar>> patterns, bool forceSubstitutionOfBoundVars) {\n        bool anythingChanged = false;\n        var newPatterns = new List<CasePattern<BoundVar>>();\n        foreach (var pat in patterns) {\n          var newPat = SubstituteCasePattern(pat, forceSubstitutionOfBoundVars);\n          newPatterns.Add(newPat);\n          if (newPat != pat) {\n            anythingChanged = true;\n          }\n        }\n        return anythingChanged ? newPatterns : patterns;\n      }\n      CasePattern<BoundVar> SubstituteCasePattern(CasePattern<BoundVar> pat, bool forceSubstitutionOfBoundVars) {\n        Contract.Requires(pat != null);\n        if (pat.Var != null) {\n          var bv = pat.Var;\n          var tt = Resolver.SubstType(bv.Type, typeMap);\n          if (forceSubstitutionOfBoundVars || tt != bv.Type) {\n            var newBv = new BoundVar(pat.tok, pat.Id, tt);\n            // update substMap to reflect the new BoundVar substitutions\n            var ie = new IdentifierExpr(newBv.tok, newBv.Name);\n            ie.Var = newBv;  // resolve here\n            ie.Type = newBv.Type;  // resolve here\n            substMap.Add(bv, ie);\n            var newPat = new CasePattern<BoundVar>(pat.tok, newBv);\n            newPat.AssembleExpr(null);\n            return newPat;\n          }\n        } else if (pat.Arguments != null) {\n          bool anythingChanged = false;\n          var newArgs = new List<CasePattern<BoundVar>>();\n          foreach (var arg in pat.Arguments) {\n            var newArg = SubstituteCasePattern(arg, forceSubstitutionOfBoundVars);\n            newArgs.Add(newArg);\n            if (newArg != arg) {\n              anythingChanged = true;\n            }\n          }\n          if (anythingChanged) {\n            var patE = (DatatypeValue)pat.Expr;\n            var newPat = new CasePattern<BoundVar>(pat.tok, pat.Id, newArgs);\n            newPat.Ctor = pat.Ctor;\n            newPat.AssembleExpr(patE.InferredTypeArgs.ConvertAll(tp => Resolver.SubstType(tp, typeMap)));\n            return newPat;\n          }\n        }\n        return pat;\n      }\n\n      protected List<Expression/*!*/>/*!*/ SubstituteExprList(List<Expression/*!*/>/*!*/ elist) {\n        Contract.Requires(cce.NonNullElements(elist));\n        Contract.Ensures(cce.NonNullElements(Contract.Result<List<Expression>>()));\n\n        List<Expression> newElist = null;  // initialized lazily\n        for (int i = 0; i < elist.Count; i++) {\n          cce.LoopInvariant(newElist == null || newElist.Count == i);\n\n          Expression substE = Substitute(elist[i]);\n          if (substE != elist[i] && newElist == null) {\n            newElist = new List<Expression>();\n            for (int j = 0; j < i; j++) {\n              newElist.Add(elist[j]);\n            }\n          }\n          if (newElist != null) {\n            newElist.Add(substE);\n          }\n        }\n        if (newElist == null) {\n          return elist;\n        } else {\n          return newElist;\n        }\n      }\n\n      protected Dictionary<TypeParameter, Type> SubstituteTypeMap(Dictionary<TypeParameter, Type> tmap) {\n        Contract.Requires(tmap != null);\n        Contract.Ensures(Contract.Result<Dictionary<TypeParameter, Type>>() != null);\n        if (typeMap.Count == 0) {  // optimization\n          return tmap;\n        }\n        bool anythingChanged = false;\n        var newTmap = new Dictionary<TypeParameter, Type>();\n        var i = 0;\n        foreach (var maplet in tmap) {\n          cce.LoopInvariant(newTmap == null || newTmap.Count == i);\n          var tt = Resolver.SubstType(maplet.Value, typeMap);\n          if (tt != maplet.Value) {\n            anythingChanged = true;\n          }\n          newTmap.Add(maplet.Key, tt);\n          i++;\n        }\n        if (anythingChanged) {\n          return newTmap;\n        } else {\n          return tmap;\n        }\n      }\n\n      /// <summary>\n      /// This method (which currently is used only internally to class Substituter) performs substitutions in\n      /// statements that can occur in a StmtExpr.  (For example, it does not bother to do anything with a\n      /// PrintStmt, ReturnStmt, or YieldStmt.)\n      /// </summary>\n      protected virtual Statement SubstStmt(Statement stmt) {\n        Statement r;\n        if (stmt == null) {\n          return null;\n        } else if (stmt is AssertStmt) {\n          var s = (AssertStmt)stmt;\n          r = new AssertStmt(s.Tok, s.EndTok, Substitute(s.Expr), SubstBlockStmt(s.Proof), s.Label, SubstAttributes(s.Attributes));\n        } else if (stmt is AssumeStmt) {\n          var s = (AssumeStmt)stmt;\n          r = new AssumeStmt(s.Tok, s.EndTok, Substitute(s.Expr), SubstAttributes(s.Attributes));\n        } else if (stmt is BreakStmt) {\n          var s = (BreakStmt)stmt;\n          BreakStmt rr;\n          if (s.TargetLabel != null) {\n            rr = new BreakStmt(s.Tok, s.EndTok, s.TargetLabel);\n          } else {\n            rr = new BreakStmt(s.Tok, s.EndTok, s.BreakCount);\n          }\n          // r.TargetStmt will be filled in as later\n          List<BreakStmt> breaks;\n          if (!BreaksToBeResolved.TryGetValue(s, out breaks)) {\n            breaks = new List<BreakStmt>();\n            BreaksToBeResolved.Add(s, breaks);\n          }\n          breaks.Add(rr);\n          r = rr;\n        } else if (stmt is ContinueStmt) {\n          var s = (ContinueStmt)stmt;\n          r = new ContinueStmt(s.Tok, s.EndTok);\n        } else if (stmt is AssignStmt) {\n          var s = (AssignStmt)stmt;\n          r = new AssignStmt(s.Tok, s.EndTok, Substitute(s.Lhs), SubstRHS(s.Rhs));\n        } else if (stmt is CallStmt) {\n          var s = (CallStmt)stmt;\n          var rr = new CallStmt(s.Tok, s.EndTok, s.Lhs.ConvertAll(Substitute), (MemberSelectExpr)Substitute(s.MethodSelect), s.Args.ConvertAll(Substitute));\n          r = rr;\n        } else if (stmt is DividedBlockStmt) {\n          r = SubstDividedBlockStmt((DividedBlockStmt)stmt);\n        } else if (stmt is BlockStmt) {\n          r = SubstBlockStmt((BlockStmt)stmt);\n        } else if (stmt is IfStmt) {\n          var s = (IfStmt)stmt;\n          r = new IfStmt(s.Tok, s.EndTok, s.IsBindingGuard, Substitute(s.Guard), SubstBlockStmt(s.Thn), SubstStmt(s.Els));\n        } else if (stmt is AlternativeStmt) {\n          var s = (AlternativeStmt)stmt;\n          r = new AlternativeStmt(s.Tok, s.EndTok, s.Alternatives.ConvertAll(SubstGuardedAlternative), s.UsesOptionalBraces);\n        } else if (stmt is WhileStmt) {\n          var s = (WhileStmt)stmt;\n          r = new WhileStmt(s.Tok, s.EndTok, Substitute(s.Guard), s.Invariants.ConvertAll(SubstMayBeFreeExpr), s.Ens.ConvertAll(Substitute), SubstSpecExpr(s.Decreases), SubstSpecFrameExpr(s.Mod), SubstBlockStmt(s.Body));\n        } else if (stmt is AlternativeLoopStmt) {\n          var s = (AlternativeLoopStmt)stmt;\n          r = new AlternativeLoopStmt(s.Tok, s.EndTok, s.Invariants.ConvertAll(SubstMayBeFreeExpr), SubstSpecExpr(s.Decreases), SubstSpecFrameExpr(s.Mod), s.Alternatives.ConvertAll(SubstGuardedAlternative), s.UsesOptionalBraces);\n        } else if (stmt is ForallStmt) {\n          var s = (ForallStmt)stmt;\n          var newBoundVars = CreateBoundVarSubstitutions(s.BoundVars, false);\n          var body = SubstStmt(s.Body);\n          // undo any changes to substMap (could be optimized to do this only if newBoundVars != e.Vars)\n          foreach (var bv in s.BoundVars) {\n            substMap.Remove(bv);\n          }\n          // Put things together\n          var rr = new ForallStmt(s.Tok, s.EndTok, newBoundVars, SubstAttributes(s.Attributes), Substitute(s.Range), s.Ens.ConvertAll(SubstMayBeFreeExpr), body);\n          rr.Kind = s.Kind;\n          r = rr;\n        } else if (stmt is CalcStmt) {\n          var s = (CalcStmt)stmt;\n          var rr = new CalcStmt(s.Tok, s.EndTok, SubstCalcOp(s.UserSuppliedOp), s.Lines.ConvertAll(Substitute), s.Hints.ConvertAll(SubstBlockStmt), s.StepOps.ConvertAll(SubstCalcOp), SubstAttributes(s.Attributes));\n          rr.Op = SubstCalcOp(s.Op);\n          rr.Steps.AddRange(s.Steps.ConvertAll(Substitute));\n          rr.Result = Substitute(s.Result);\n          r = rr;\n        } else if (stmt is MatchStmt) {\n          var s = (MatchStmt)stmt;\n          var rr = new MatchStmt(s.Tok, s.EndTok, Substitute(s.Source), s.Cases.ConvertAll(SubstMatchCaseStmt), s.UsesOptionalBraces);\n          rr.MissingCases.AddRange(s.MissingCases);\n          r = rr;\n        } else if (stmt is AssignSuchThatStmt) {\n          var s = (AssignSuchThatStmt)stmt;\n          r = new AssignSuchThatStmt(s.Tok, s.EndTok, s.Lhss.ConvertAll(Substitute), Substitute(s.Expr), s.AssumeToken == null ? null : s.AssumeToken, null);\n        } else if (stmt is UpdateStmt) {\n          var s = (UpdateStmt)stmt;\n          var resolved = s.ResolvedStatements;\n          UpdateStmt rr;\n          if (resolved.Count == 1) {\n            // when later translating this UpdateStmt, the s.Lhss and s.Rhss components won't be used, only s.ResolvedStatements\n            rr = new UpdateStmt(s.Tok, s.EndTok, s.Lhss, s.Rhss, s.CanMutateKnownState);\n          } else {\n            rr = new UpdateStmt(s.Tok, s.EndTok, s.Lhss.ConvertAll(Substitute), s.Rhss.ConvertAll(SubstRHS), s.CanMutateKnownState);\n          }\n          rr.ResolvedStatements.AddRange(s.ResolvedStatements.ConvertAll(SubstStmt));\n          r = rr;\n        } else if (stmt is VarDeclStmt) {\n          var s = (VarDeclStmt)stmt;\n          var lhss = s.Locals.ConvertAll(c => new LocalVariable(c.Tok, c.EndTok, c.Name, c.OptionalType == null ? null : Resolver.SubstType(c.OptionalType, typeMap), c.IsGhost, c.IsNoAddr));\n          var rr = new VarDeclStmt(s.Tok, s.EndTok, lhss, (ConcreteUpdateStatement)SubstStmt(s.Update), s.BypassStoreBuffers);\n          r = rr;\n        } else if (stmt is RevealStmt) {\n          var s = (RevealStmt)stmt;\n          // don't need to substitute s.Expr since it won't be used, only the s.ResolvedStatements are used.\n          var rr = new RevealStmt(s.Tok, s.EndTok, s.Exprs);\n          rr.LabeledAsserts.AddRange(s.LabeledAsserts);\n          rr.ResolvedStatements.AddRange(s.ResolvedStatements.ConvertAll(SubstStmt));\n          r = rr;\n        } else if (stmt is SomehowStmt) {\n          var s = (SomehowStmt) stmt;\n          r = new SomehowStmt(s.Tok, s.EndTok, s.UndefinedUnless.ConvertAll(Substitute), SubstSpecExpr(s.Mod),\n                              s.Ens.ConvertAll(Substitute));\n        } else if (stmt is FenceStmt) {\n          var s = (FenceStmt) stmt;\n          r = new FenceStmt(s.Tok, s.EndTok);\n        } else if (stmt is GotoStmt) {\n          var s = (GotoStmt) stmt;\n          r = new GotoStmt(s.Tok, s.EndTok, s.Target);\n        } else if (stmt is DeallocStmt) {\n          var s = (DeallocStmt) stmt;\n          r = new DeallocStmt(s.Tok, s.EndTok, Substitute(s.Addr));\n        } else if (stmt is JoinStmt) {\n          var s = (JoinStmt) stmt;\n          r = new JoinStmt(s.Tok, s.EndTok, Substitute(s.WhichThread));\n        } else {\n          Contract.Assert(false); throw new cce.UnreachableException();  // unexpected statement\n        }\n\n        // add labels to the cloned statement\n        AddStmtLabels(r, stmt.Labels);\n        r.Attributes = SubstAttributes(stmt.Attributes);\n        r.IsGhost = stmt.IsGhost;\n        if (stmt.Labels != null || stmt is WhileStmt) {\n          List<BreakStmt> breaks;\n          if (BreaksToBeResolved.TryGetValue(stmt, out breaks)) {\n            foreach (var b in breaks) {\n              b.TargetStmt = r;\n            }\n            BreaksToBeResolved.Remove(stmt);\n          }\n        }\n\n        return r;\n      }\n\n      Dictionary<Statement, List<BreakStmt>> BreaksToBeResolved = new Dictionary<Statement, List<BreakStmt>>();  // old-target -> new-breaks\n\n      protected void AddStmtLabels(Statement s, LList<Label> node) {\n        if (node != null) {\n          AddStmtLabels(s, node.Next);\n          s.Labels = new LList<Label>(node.Data, s.Labels);\n        }\n      }\n\n      protected virtual DividedBlockStmt SubstDividedBlockStmt(DividedBlockStmt stmt) {\n        return stmt == null ? null : new DividedBlockStmt(stmt.Tok, stmt.EndTok, stmt.BodyInit.ConvertAll(SubstStmt), stmt.SeparatorTok, stmt.BodyProper.ConvertAll(SubstStmt));\n      }\n\n      protected virtual BlockStmt SubstBlockStmt(BlockStmt stmt) {\n        return stmt == null ? null : new BlockStmt(stmt.Tok, stmt.EndTok, stmt.Body.ConvertAll(SubstStmt));\n      }\n\n      protected GuardedAlternative SubstGuardedAlternative(GuardedAlternative alt) {\n        Contract.Requires(alt != null);\n        return new GuardedAlternative(alt.Tok, alt.IsBindingGuard, Substitute(alt.Guard), alt.Body.ConvertAll(SubstStmt));\n      }\n\n      protected MaybeFreeExpression SubstMayBeFreeExpr(MaybeFreeExpression expr) {\n        Contract.Requires(expr != null);\n        var mfe = new MaybeFreeExpression(Substitute(expr.E), expr.IsFree);\n        mfe.Attributes = SubstAttributes(expr.Attributes);\n        return mfe;\n      }\n\n      protected Specification<Expression> SubstSpecExpr(Specification<Expression> spec) {\n        var ee = spec.Expressions == null ? null : spec.Expressions.ConvertAll(Substitute);\n        return new Specification<Expression>(ee, SubstAttributes(spec.Attributes));\n      }\n\n      protected Specification<FrameExpression> SubstSpecFrameExpr(Specification<FrameExpression> frame) {\n        var ee = frame.Expressions == null ? null : frame.Expressions.ConvertAll(SubstFrameExpr);\n        return new Specification<FrameExpression>(ee, SubstAttributes(frame.Attributes));\n      }\n\n      public FrameExpression SubstFrameExpr(FrameExpression frame) {\n        Contract.Requires(frame != null);\n        var fe = new FrameExpression(frame.tok, Substitute(frame.E), frame.FieldName);\n        fe.Field = frame.Field;  // resolve here\n        return fe;\n      }\n\n      protected AssignmentRhs SubstRHS(AssignmentRhs rhs) {\n        AssignmentRhs c;\n        if (rhs is ExprRhs) {\n          var r = (ExprRhs)rhs;\n          c = new ExprRhs(Substitute(r.Expr));\n        } else if (rhs is HavocRhs) {\n          c = new HavocRhs(rhs.Tok);\n        } else {\n          // since the Substituter is assumed to operate on statements only if they are part of a StatementExpression, then the TypeRhs case cannot occur\n          Contract.Assume(false); throw new cce.UnreachableException();\n        }\n        c.Attributes = SubstAttributes(rhs.Attributes);\n        return c;\n      }\n\n      protected MatchCaseStmt SubstMatchCaseStmt(MatchCaseStmt c) {\n        Contract.Requires(c != null);\n        var newBoundVars = CreateBoundVarSubstitutions(c.Arguments, false);\n        var r = new MatchCaseStmt(c.tok, c.Id, newBoundVars, c.Body.ConvertAll(SubstStmt));\n        r.Ctor = c.Ctor;\n        // undo any changes to substMap (could be optimized to do this only if newBoundVars != e.Vars)\n        foreach (var bv in c.Arguments) {\n          substMap.Remove(bv);\n        }\n        return r;\n      }\n\n      protected CalcStmt.CalcOp SubstCalcOp(CalcStmt.CalcOp op) {\n        if (op == null) {\n          return null;\n        } else if (op is CalcStmt.BinaryCalcOp) {\n          return new CalcStmt.BinaryCalcOp(((CalcStmt.BinaryCalcOp)op).Op);\n        } else if (op is CalcStmt.TernaryCalcOp) {\n          return new CalcStmt.TernaryCalcOp(Substitute(((CalcStmt.TernaryCalcOp)op).Index));\n        } else {\n          Contract.Assert(false);\n          throw new cce.UnreachableException();\n        }\n      }\n\n      public Attributes SubstAttributes(Attributes attrs) {\n        Contract.Requires(cce.NonNullDictionaryAndValues(substMap));\n        if (attrs != null) {\n          var newArgs = new List<Expression>();  // allocate it eagerly, what the heck, it doesn't seem worth the extra complexity in the code to do it lazily for the infrequently occurring attributes\n          bool anyArgSubst = false;\n          foreach (var arg in attrs.Args) {\n            var argToBeAdded = arg;\n            var substArg = Substitute(arg);\n            if (substArg != arg) {\n              argToBeAdded = substArg;\n              anyArgSubst = true;\n            }\n            newArgs.Add(argToBeAdded);\n          }\n          if (!anyArgSubst) {\n            newArgs = attrs.Args;\n          }\n\n          Attributes prev = SubstAttributes(attrs.Prev);\n          if (newArgs != attrs.Args || prev != attrs.Prev) {\n            if (attrs is UserSuppliedAttributes) {\n              var usa = (UserSuppliedAttributes)attrs;\n              return new UserSuppliedAttributes(usa.tok, usa.OpenBrace, usa.CloseBrace, newArgs, prev);\n            } else {\n              return new Attributes(attrs.Name, newArgs, prev);\n            }\n          }\n        }\n        return attrs;\n      }\n    }\n\n    /// <summary>\n    /// This substituter performs substitutions in such a way that it's okay to print the resulting expression without a human getting confused.\n    /// More precisely, bound variables first gets alpha-renamed.  Also, \"this\" is never left implicit, including in the\n    /// case where \"receiverReplacement\" is given as ImplicitThisExpr (but no attempt is made to substitute for all ImplicitThisExpr's in\n    /// \"receiverReplacement\" and the range of \"substMap\").\n    /// </summary>\n    public class AlphaConverting_Substituter : Substituter\n    {\n      ISet<string> namesToAvoid = new HashSet<string>();\n      public AlphaConverting_Substituter(Expression receiverReplacement, Dictionary<IVariable, Expression> substMap, Dictionary<TypeParameter, Type> typeMap)\n        : base(receiverReplacement is ImplicitThisExpr ? new ThisExpr(receiverReplacement.tok) : receiverReplacement, substMap, typeMap) {\n        Contract.Requires(substMap != null);\n        Contract.Requires(typeMap != null);\n      }\n      protected override List<BoundVar> CreateBoundVarSubstitutions(List<BoundVar> vars, bool forceSubstitutionOfBoundVars) {\n        var newBoundVars = vars.Count == 0 ? vars : new List<BoundVar>();\n        foreach (var bv in vars) {\n          var tt = Resolver.SubstType(bv.Type, typeMap);\n          var newBv = new BoundVar(bv.tok, \"_'\" + bv.Name, tt);\n          newBoundVars.Add(newBv);\n          // update substMap to reflect the new BoundVar substitutions\n          var ie = new IdentifierExpr(newBv.tok, newBv.Name);\n          ie.Var = newBv;  // resolve here\n          ie.Type = newBv.Type;  // resolve here\n          substMap.Add(bv, ie);\n        }\n        return newBoundVars;\n      }\n    }\n\n    Bpl.Expr HeapSameOrSucc(Bpl.Expr oldHeap, Bpl.Expr newHeap) {\n      return Bpl.Expr.Or(\n        Bpl.Expr.Eq(oldHeap, newHeap),\n        FunctionCall(newHeap.tok, BuiltinFunction.HeapSucc, null, oldHeap, newHeap));\n    }\n    Bpl.Expr HeapSucc(Bpl.Expr oldHeap, Bpl.Expr newHeap, bool useGhostHeapSucc = false) {\n      return FunctionCall(newHeap.tok, useGhostHeapSucc ? BuiltinFunction.HeapSuccGhost : BuiltinFunction.HeapSucc, null, oldHeap, newHeap);\n    }\n\n    // Bpl-making-utilities\n\n    /// <summary>\n    /// Create a Boogie quantifier with body \"A ==> body\" and triggers \"trg\", but use only the subset of bound\n    /// variables from \"varsAndAntecedents\" that actually occur free in \"body\" or \"trg\", and \"A\" is the conjunction of\n    /// antecedents for those corresponding bound variables.  If none of the bound variables is used, \"body\"\n    /// is returned. Also, if none of the bound variables is used in \"body\" (whether or not they are used in \"trg\"),\n    /// then \"body\" is returned.\n    /// The order of the contents of \"varsAndAntecedents\" matters: For any index \"i\" into \"varsAndAntecedents\", the\n    /// antecedent varsAndAntecedents[i].Item2 may depend on a variable varsAndAntecedents[j].Item1 if \"j GREATER-OR-EQUAL i\"\n    /// but not if \"j LESS i\".\n    /// Caution: if \"trg\" is null, makes a forall without any triggers.\n    /// </summary>\n    static Bpl.Expr BplForallTrim(IEnumerable<Tuple<Bpl.Variable, Bpl.Expr/*?*/>> varsAndAntecedents, Bpl.Trigger trg, Bpl.Expr body) {\n      Contract.Requires(varsAndAntecedents != null);\n      Contract.Requires(body != null);\n\n      // We'd like to compute the free variables if \"body\" and \"trg\". It would be nice to use the Boogie\n      // routine Bpl.Expr.ComputeFreeVariables for this purpose. However, calling it requires the Boogie\n      // expression to be resolved. Instead, we do the cheesy thing of computing the set of names of\n      // free variables in \"body\" and \"trg\".\n      var vis = new VariableNameVisitor();\n      vis.Visit(body);\n      if (varsAndAntecedents.All(pair => !vis.Names.Contains(pair.Item1.Name))) {\n        // the body doesn't mention any of the bound variables, so no point in wrapping a quantifier around it\n        return body;\n      }\n      for (var tt = trg; tt != null; tt = tt.Next) {\n        tt.Tr.Iter(ee => vis.Visit(ee));\n      }\n\n      var args = new List<Bpl.Variable>();\n      Bpl.Expr typeAntecedent = Bpl.Expr.True;\n      foreach (var pair in varsAndAntecedents) {\n        var bv = pair.Item1;\n        var wh = pair.Item2;\n        if (vis.Names.Contains(bv.Name)) {\n          args.Add(bv);\n          if (wh != null) {\n            typeAntecedent = BplAnd(typeAntecedent, wh);\n            vis.Visit(wh);  // this adds to \"vis.Names\" the free variables of \"wh\"\n          }\n        }\n      }\n      if (args.Count == 0) {\n        return body;\n      } else {\n        return new Bpl.ForallExpr(body.tok, args, trg, BplImp(typeAntecedent, body));\n      }\n    }\n    class VariableNameVisitor : Boogie.StandardVisitor\n    {\n      public readonly HashSet<string> Names = new HashSet<string>();\n      public override Expr VisitIdentifierExpr(Bpl.IdentifierExpr node) {\n        Names.Add(node.Name);\n        return base.VisitIdentifierExpr(node);\n      }\n      public override BinderExpr VisitBinderExpr(BinderExpr node) {\n        var vis = new VariableNameVisitor();\n        vis.Visit(node.Body);\n        var dummyNames = new HashSet<string>(node.Dummies.Select(v => v.Name));\n        foreach (var nm in vis.Names) {\n          if (!dummyNames.Contains(nm)) {\n            Names.Add(nm);\n          }\n        }\n        return base.VisitBinderExpr(node);\n      }\n    }\n\n    static Bpl.Expr BplForall(IEnumerable<Bpl.Variable> args_in, Bpl.Expr body) {\n      Contract.Requires(args_in != null);\n      Contract.Requires(body != null);\n      Contract.Ensures(Contract.Result<Bpl.Expr>() != null);\n      var args = new List<Bpl.Variable>(args_in);\n      if (args.Count == 0) {\n        return body;\n      } else {\n        return new Bpl.ForallExpr(body.tok, args, body); // NO_TRIGGER\n      }\n    }\n\n    // Note: if the trigger is null, makes a forall without any triggers\n    static Bpl.Expr BplForall(IEnumerable<Bpl.Variable> args_in, Bpl.Trigger trg, Bpl.Expr body) {\n      if (trg == null) {\n        return BplForall(args_in, body); // NO_TRIGGER\n      } else {\n        var args = new List<Bpl.Variable>(args_in);\n        if (args.Count == 0) {\n          return body;\n        } else {\n          return new Bpl.ForallExpr(body.tok, args, trg, body);\n        }\n      }\n    }\n\n    static Bpl.Expr BplForall(Bpl.Variable arg, Bpl.Trigger trg, Bpl.Expr body) {\n      return BplForall(Singleton(arg), trg, body);\n    }\n\n    static Bpl.Expr BplForall(IToken tok, List<TypeVariable> typeParams,\n      List<Variable> formals, QKeyValue kv, Trigger triggers, Bpl.Expr body, bool immutable = false)\n    {\n      return (typeParams.Count == 0 && formals.Count == 0) ? body\n        : new Bpl.ForallExpr(tok, typeParams, formals, kv, triggers, body, immutable);\n    }\n\n    static Bpl.Expr BplAnd(IEnumerable<Bpl.Expr> conjuncts) {\n      Contract.Requires(conjuncts != null);\n      Bpl.Expr eq = Bpl.Expr.True;\n      foreach (var c in conjuncts) {\n        eq = BplAnd(eq, c);\n      }\n      return eq;\n    }\n\n    static Bpl.Expr BplAnd(Bpl.Expr a, Bpl.Expr b) {\n      Contract.Requires(a != null);\n      Contract.Requires(b != null);\n      Contract.Ensures(Contract.Result<Bpl.Expr>() != null);\n\n      if (a == Bpl.Expr.True) {\n        return b;\n      } else if (b == Bpl.Expr.True) {\n        return a;\n      } else {\n        return Bpl.Expr.Binary(a.tok, BinaryOperator.Opcode.And, a, b);\n      }\n    }\n\n    static Bpl.Expr BplOr(IEnumerable<Bpl.Expr> disjuncts) {\n      Contract.Requires(disjuncts != null);\n      Bpl.Expr eq = Bpl.Expr.False;\n      foreach (var d in disjuncts) {\n        eq = BplOr(eq, d);\n      }\n      return eq;\n    }\n\n    static Bpl.Expr BplOr(Bpl.Expr a, Bpl.Expr b) {\n      Contract.Requires(a != null);\n      Contract.Requires(b != null);\n      Contract.Ensures(Contract.Result<Bpl.Expr>() != null);\n\n      if (a == Bpl.Expr.False) {\n        return b;\n      } else if (b == Bpl.Expr.False) {\n        return a;\n      } else {\n        return Bpl.Expr.Binary(a.tok, BinaryOperator.Opcode.Or, a, b);\n      }\n    }\n\n    Bpl.Expr BplIff(Bpl.Expr a, Bpl.Expr b) {\n      Contract.Requires(a != null);\n      Contract.Requires(b != null);\n      Contract.Ensures(Contract.Result<Bpl.Expr>() != null);\n\n      if (a == Bpl.Expr.True) {\n        return b;\n      } else if (b == Bpl.Expr.True) {\n        return a;\n      } else {\n        return Bpl.Expr.Iff(a, b);\n      }\n    }\n\n    static Bpl.Expr BplImp(Bpl.Expr a, Bpl.Expr b) {\n      Contract.Requires(a != null);\n      Contract.Requires(b != null);\n      Contract.Ensures(Contract.Result<Bpl.Expr>() != null);\n\n      if (a == Bpl.Expr.True || b == Bpl.Expr.True) {\n        return b;\n      } else if (a == Bpl.Expr.False) {\n        return Bpl.Expr.True;\n      } else {\n        return Bpl.Expr.Imp(a, b);\n      }\n    }\n\n    private static void BplIfIf(IToken tk, bool yes, Bpl.Expr guard, BoogieStmtListBuilder builder, Action<BoogieStmtListBuilder> k) {\n      if (yes) {\n        var newBuilder = new BoogieStmtListBuilder(builder.tran);\n        k(newBuilder);\n        builder.Add(new Bpl.IfCmd(tk, guard, newBuilder.Collect(tk), null, null));\n      } else {\n        k(builder);\n      }\n    }\n\n    /// <summary>\n    /// lhs should be a Bpl.IdentifierExpr.\n    /// Creates lhs := rhs;\n    /// </summary>\n    static Bpl.Cmd BplSimplestAssign(Bpl.Expr lhs, Bpl.Expr rhs) {\n      Contract.Requires(lhs is Bpl.IdentifierExpr);\n      return new Bpl.AssignCmd(rhs.tok,\n        Singleton((AssignLhs)new SimpleAssignLhs(rhs.tok, (Bpl.IdentifierExpr)lhs)),\n        Singleton(rhs));\n    }\n\n    /// Makes a simple trigger\n    static Bpl.Trigger BplTrigger(Bpl.Expr e) {\n      return new Bpl.Trigger(e.tok, true, new List<Bpl.Expr> { e });\n    }\n\n    static Bpl.Trigger BplTriggerHeap(Translator translator, IToken tok, Bpl.Expr e, Bpl.Expr optionalHeap) {\n      return (optionalHeap == null) ? new Bpl.Trigger(tok, true, new List<Bpl.Expr> { e }) :\n        new Bpl.Trigger(tok, true, new List<Bpl.Expr> {\n          e, translator.FunctionCall(tok, BuiltinFunction.IsGoodHeap, null, optionalHeap) });\n    }\n\n    static Bpl.Axiom BplAxiom(Bpl.Expr e) {\n      return new Bpl.Axiom(e.tok, e);\n    }\n\n    static Bpl.Expr BplLocalVar(string name, Bpl.Type ty, List<Bpl.Variable> lvars) {\n      Bpl.Expr v;\n      lvars.Add(BplLocalVar(name, ty, out v));\n      return v;\n    }\n\n    static Bpl.LocalVariable BplLocalVar(string name, Bpl.Type ty, out Bpl.Expr e) {\n      Contract.Requires(ty != null);\n      var v = new Bpl.LocalVariable(ty.tok, new Bpl.TypedIdent(ty.tok, name, ty));\n      e = new Bpl.IdentifierExpr(ty.tok, name, ty);\n      return v;\n    }\n\n    /* This function allows you to replace, for example:\n\n           Bpl.BoundVariable iVar = new Bpl.BoundVariable(e.tok, new Bpl.TypedIdent(e.tok, \"$i\", Bpl.Type.Int));\n           Bpl.IdentifierExpr i = new Bpl.IdentifierExpr(e.tok, iVar);\n\n       with:\n\n           Bpl.Expr i; var iVar = BplBoundVar(\"$i\", Bpl.Type.Int, out i);\n    */\n    static Bpl.BoundVariable BplBoundVar(string name, Bpl.Type ty, out Bpl.Expr e) {\n      Contract.Requires(ty != null);\n      var v = new Bpl.BoundVariable(ty.tok, new Bpl.TypedIdent(ty.tok, name, ty));\n      e = new Bpl.IdentifierExpr(ty.tok, name, ty);\n      return v;\n    }\n\n    static Bpl.Expr BplBoundVar(string name, Bpl.Type ty, List<Bpl.Variable> bvars) {\n      Bpl.Expr e;\n      bvars.Add(BplBoundVar(name, ty, out e));\n      return e;\n    }\n\n    // Makes a formal variable\n    static Bpl.Formal BplFormalVar(string/*?*/ name, Bpl.Type ty, bool incoming) {\n      Bpl.Expr _scratch;\n      return BplFormalVar(name, ty, incoming, out _scratch);\n    }\n\n    static Bpl.Formal BplFormalVar(string/*?*/ name, Bpl.Type ty, bool incoming, out Bpl.Expr e) {\n      Bpl.Formal res;\n      if (name == null) {\n        name = Bpl.TypedIdent.NoName;\n      }\n      res = new Bpl.Formal(ty.tok, new TypedIdent(ty.tok, name, ty), incoming);\n      e = new Bpl.IdentifierExpr(ty.tok, res);\n      return res;\n    }\n\n    static Bpl.Expr BplFormalVar(string name, Bpl.Type ty, bool incoming, List<Bpl.Variable> fvars) {\n      Bpl.Expr e;\n      fvars.Add(BplFormalVar(name, ty, incoming, out e));\n      return e;\n    }\n\n    List<Bpl.Variable> MkTyParamBinders(List<TypeParameter> args) {\n      List<Bpl.Expr> _scratch;\n      return MkTyParamBinders(args, out _scratch);\n    }\n\n    List<Bpl.Variable> MkTyParamBinders(List<TypeParameter> args, out List<Bpl.Expr> exprs) {\n      List<Bpl.Variable> vars = new List<Bpl.Variable>();\n      exprs = new List<Bpl.Expr>();\n      foreach (TypeParameter v in args) {\n        Bpl.Expr e;\n        vars.Add(BplBoundVar(nameTypeParam(v), predef.Ty, out e));\n        exprs.Add(e);\n      }\n      return vars;\n    }\n\n    // For incoming formals\n    List<Bpl.Variable> MkTyParamFormals(List<TypeParameter> args, bool named = true) {\n      List<Bpl.Expr> _scratch;\n      return MkTyParamFormals(args, out _scratch, named);\n    }\n\n    // For incoming formals\n    List<Bpl.Variable> MkTyParamFormals(List<TypeParameter> args, out List<Bpl.Expr> exprs, bool named = true) {\n      List<Bpl.Variable> vars = new List<Bpl.Variable>();\n      exprs = new List<Bpl.Expr>();\n      foreach (TypeParameter v in args) {\n        Bpl.Expr e;\n        vars.Add(BplFormalVar(named ? nameTypeParam(v) : null, predef.Ty, true, out e));\n        exprs.Add(e);\n      }\n      return vars;\n    }\n\n    // Utilities for lists and dicts...\n\n    static List<A> Singleton<A>(A x) {\n      return Util.Singleton(x);\n    }\n\n    static List<A> Cons<A>(A x, List<A> xs) {\n      return Util.Cons(x, xs);\n    }\n\n    static List<A> Snoc<A>(List<A> xs, A x) {\n      return Util.Snoc(xs, x);\n    }\n\n    static List<A> Concat<A>(List<A> xs, List<A> ys) {\n      return Util.Concat(xs, ys);\n    }\n\n    public static List<B> Map<A,B>(IEnumerable<A> xs, Func<A,B> f) {\n      return Util.Map(xs, f);\n    }\n\n    public static void MapM<A>(IEnumerable<A> xs, Action<A> K)\n    {\n      Contract.Requires(xs != null);\n      Contract.Requires(K != null);\n      foreach (A x in xs) {\n        K(x);\n      }\n    }\n\n    static readonly List<Boolean> Bools = new List<Boolean> { false, true };\n  }\n}\n"
  },
  {
    "path": "Source/Armada/Triggers/QuantifierSplitter.cs",
    "content": "using Microsoft.Boogie;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text;\n\nnamespace Microsoft.Armada.Triggers\n{\n  class QuantifierSplitter : BottomUpVisitor\n  {\n    /// This cache was introduced because some statements (notably calc) return the same SubExpression multiple times.\n    /// This ended up causing an inconsistent situation when the calc statement's subexpressions contained the same quantifier\n    /// twice: on the first pass that quantifier got its SplitQuantifiers generated, and on the the second pass these\n    /// split quantifiers got re-split, creating a situation where the direct children of a split quantifier were\n    /// also split quantifiers.\n    private Dictionary<QuantifierExpr, List<Expression>> splits = new Dictionary<QuantifierExpr, List<Expression>>();\n\n    private static BinaryExpr.Opcode FlipOpcode(BinaryExpr.Opcode opCode) {\n      if (opCode == BinaryExpr.Opcode.And) {\n        return BinaryExpr.Opcode.Or;\n      } else if (opCode == BinaryExpr.Opcode.Or) {\n        return BinaryExpr.Opcode.And;\n      } else {\n        throw new ArgumentException();\n      }\n    }\n\n    // NOTE: If we wanted to split quantifiers as far as possible, it would be\n    // enough to put the formulas in DNF (for foralls) or CNF (for exists).\n    // Unfortunately, this would cause ill-behaved quantifiers to produce\n    // exponentially many smaller quantifiers. Thus we only do one step of\n    // distributing, which takes care of the usual precondition case:\n    //   forall x :: P(x) ==> (Q(x) && R(x))\n\n    private static UnaryOpExpr Not(Expression expr) {\n      return new UnaryOpExpr(expr.tok, UnaryOpExpr.Opcode.Not, expr) { Type = expr.Type };\n    }\n\n    internal static IEnumerable<Expression> SplitExpr(Expression expr, BinaryExpr.Opcode separator) {\n      expr = expr.Resolved;\n      var unary = expr as UnaryOpExpr;\n      var binary = expr as BinaryExpr;\n\n      if (unary != null && unary.Op == UnaryOpExpr.Opcode.Not) {\n        foreach (var e in SplitExpr(unary.E, FlipOpcode(separator))) { yield return Not(e); }\n      } else if (binary != null && binary.Op == separator) {\n        foreach (var e in SplitExpr(binary.E0, separator)) { yield return e; }\n        foreach (var e in SplitExpr(binary.E1, separator)) { yield return e; }\n      } else if (binary != null && binary.Op == BinaryExpr.Opcode.Imp && separator == BinaryExpr.Opcode.Or) {\n        foreach (var e in SplitExpr(Not(binary.E0), separator)) { yield return e; }\n        foreach (var e in SplitExpr(binary.E1, separator)) { yield return e; }\n      } else {\n        yield return expr;\n      }\n    }\n\n    internal static IEnumerable<Expression> SplitAndStich(BinaryExpr pair, BinaryExpr.Opcode separator) {\n      foreach (var e1 in SplitExpr(pair.E1, separator)) {\n        // Notice the token. This makes triggers/splitting-picks-the-right-tokens.dfy possible\n        yield return new BinaryExpr(e1.tok, pair.Op, pair.E0, e1) { ResolvedOp = pair.ResolvedOp, Type = pair.Type };\n      }\n    }\n\n    internal static IEnumerable<Expression> SplitQuantifier(ComprehensionExpr quantifier) {\n      var body = quantifier.Term;\n      var binary = body as BinaryExpr;\n\n      if (quantifier is ForallExpr) {\n        IEnumerable<Expression> stream;\n        if (binary != null && (binary.Op == BinaryExpr.Opcode.Imp || binary.Op == BinaryExpr.Opcode.Or)) {\n          stream = SplitAndStich(binary, BinaryExpr.Opcode.And);\n        } else {\n          stream = SplitExpr(body, BinaryExpr.Opcode.And);\n        }\n        foreach (var e in stream) {\n          var tok = new NestedToken(quantifier.tok, e.tok);\n          yield return new ForallExpr(tok, ((ForallExpr)quantifier).TypeArgs, quantifier.BoundVars, quantifier.Range, e, TriggerUtils.CopyAttributes(quantifier.Attributes)) { Type = quantifier.Type, Bounds = quantifier.Bounds };\n        }\n      } else if (quantifier is ExistsExpr) {\n        IEnumerable<Expression> stream;\n        if (binary != null && binary.Op == BinaryExpr.Opcode.And) {\n          stream = SplitAndStich(binary, BinaryExpr.Opcode.Or);\n        } else {\n          stream = SplitExpr(body, BinaryExpr.Opcode.Or);\n        }\n        foreach (var e in stream) {\n          var tok = new NestedToken(quantifier.tok, e.tok);\n          yield return new ExistsExpr(tok, ((ExistsExpr)quantifier).TypeArgs, quantifier.BoundVars, quantifier.Range, e, TriggerUtils.CopyAttributes(quantifier.Attributes)) { Type = quantifier.Type, Bounds = quantifier.Bounds };\n        }\n      } else {\n        yield return quantifier;\n      }\n    }\n\n    private static bool AllowsSplitting(ComprehensionExpr quantifier) {\n      // allow split if attributes doesn't contains \"split\" or it is \"split: true\" and it is not an empty QuantifierExpr (boundvar.count>0)\n      bool splitAttr = true;\n      return (!Attributes.ContainsBool(quantifier.Attributes, \"split\", ref splitAttr) || splitAttr) && (quantifier.BoundVars.Count > 0);\n    }\n\n    protected override void VisitOneExpr(Expression expr) {\n      var quantifier = expr as QuantifierExpr;\n      if (quantifier != null) {\n        Contract.Assert(quantifier.SplitQuantifier == null);\n        if (!splits.ContainsKey(quantifier) && AllowsSplitting(quantifier)) {\n          splits[quantifier] = SplitQuantifier(quantifier).ToList();\n        }\n      }\n    }\n\n    protected override void VisitOneStmt(Statement stmt) {\n      if (stmt is ForallStmt) {\n        ForallStmt s = (ForallStmt)stmt;\n        if (s.ForallExpressions != null) {\n          foreach (Expression expr in s.ForallExpressions) {\n            VisitOneExpr(expr);\n          }\n        }\n      }\n    }\n\n    /// <summary>\n    /// See comments above definition of splits for reason why this method exists\n    /// </summary>\n    internal void Commit() {\n      foreach (var quantifier in splits.Keys) {\n        quantifier.SplitQuantifier = splits[quantifier];\n      }\n    }\n  }\n\n  class MatchingLoopRewriter\n  {\n    TriggersCollector triggersCollector = new Triggers.TriggersCollector(new Dictionary<Expression, HashSet<OldExpr>>());\n    List<Tuple<Expression, IdentifierExpr>> substMap;\n\n    public QuantifierExpr RewriteMatchingLoops(QuantifierWithTriggers q)\n    {\n      // rewrite quantifier to avoid matching loops\n      // before:\n      //    assert forall i :: 0 <= i < a.Length-1 ==> a[i] <= a[i+1];\n      // after:\n      //    assert forall i,j :: j == i+1 ==> 0 <= i < a.Length-1 ==> a[i] <= a[j];\n      substMap = new List<Tuple<Expression, IdentifierExpr>>();\n      foreach (var m in q.LoopingMatches) {\n        var e = m.OriginalExpr;\n        if (TriggersCollector.IsPotentialTriggerCandidate(e) && triggersCollector.IsTriggerKiller(e)) {\n          foreach (var sub in e.SubExpressions) {\n            if (triggersCollector.IsTriggerKiller(sub) && (!TriggersCollector.IsPotentialTriggerCandidate(sub))) {\n              var entry = substMap.Find(x => ExprExtensions.ExpressionEq(sub, x.Item1));\n              if (entry == null) {\n                var newBv = new BoundVar(sub.tok, \"_t#\" + substMap.Count, sub.Type);\n                var ie = new IdentifierExpr(sub.tok, newBv.Name);\n                ie.Var = newBv;\n                ie.Type = newBv.Type;\n                substMap.Add(new Tuple<Expression,IdentifierExpr>(sub, ie));\n              }\n            }\n          }\n        }\n      }\n\n      var expr = (QuantifierExpr) q.quantifier;\n      if (substMap.Count > 0) {\n        var s = new Translator.ExprSubstituter(substMap);\n        expr = s.Substitute(q.quantifier) as QuantifierExpr;\n      } else {\n        // make a copy of the expr\n        if (expr is ForallExpr) {\n          expr = new ForallExpr(expr.tok, expr.TypeArgs, expr.BoundVars, expr.Range, expr.Term, TriggerUtils.CopyAttributes(expr.Attributes)) { Type = expr.Type, Bounds = expr.Bounds };\n        } else {\n          expr = new ExistsExpr(expr.tok, expr.TypeArgs, expr.BoundVars, expr.Range, expr.Term, TriggerUtils.CopyAttributes(expr.Attributes)) { Type = expr.Type, Bounds = expr.Bounds };\n        }\n      }\n      return expr;\n    }\n  }\n}\n"
  },
  {
    "path": "Source/Armada/Triggers/QuantifiersCollection.cs",
    "content": "#define QUANTIFIER_WARNINGS\n\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing Microsoft.Boogie;\nusing System.Diagnostics.Contracts;\n\nnamespace Microsoft.Armada.Triggers {\n  class QuantifierWithTriggers {\n    internal ComprehensionExpr quantifier;\n    internal List<TriggerTerm> CandidateTerms;\n    internal List<TriggerCandidate> Candidates;\n    internal List<TriggerCandidate> RejectedCandidates;\n    internal List<TriggerMatch> LoopingMatches;\n\n    internal bool AllowsLoops { get { return TriggerUtils.AllowsMatchingLoops(quantifier); } }\n    internal bool CouldSuppressLoops { get; set; }\n\n    internal QuantifierWithTriggers(ComprehensionExpr quantifier) {\n      this.quantifier = quantifier;\n      this.RejectedCandidates = new List<TriggerCandidate>();\n    }\n\n    internal void TrimInvalidTriggers() {\n      Contract.Requires(CandidateTerms != null);\n      Contract.Requires(Candidates != null);\n      Candidates = TriggerUtils.Filter(Candidates, tr => tr, (tr, _) => tr.MentionsAll(quantifier.BoundVars), (tr, _) => { }).ToList();\n    }\n  }\n\n  class QuantifiersCollection {\n    readonly ErrorReporter reporter;\n    readonly ComprehensionExpr expr;  //  the expression where the splits are originated from\n    List<QuantifierWithTriggers> quantifiers;\n\n    internal QuantifiersCollection(ComprehensionExpr expr, IEnumerable<ComprehensionExpr> quantifiers, ErrorReporter reporter) {\n      Contract.Requires(quantifiers.All(q => !(q is QuantifierExpr) || ((QuantifierExpr)q).SplitQuantifier == null));\n      this.reporter = reporter;\n      this.expr = expr;\n      this.quantifiers = quantifiers.Select(q => new QuantifierWithTriggers(q)).ToList();\n    }\n\n    internal void ComputeTriggers(TriggersCollector triggersCollector) {\n      CollectAndShareTriggers(triggersCollector);\n      TrimInvalidTriggers();\n      BuildDependenciesGraph();\n      if(SuppressMatchingLoops() && RewriteMatchingLoop()) {\n        CollectWithoutShareTriggers(triggersCollector);\n        TrimInvalidTriggers();\n        SuppressMatchingLoops();\n      }\n      SelectTriggers();\n      CombineSplitQuantifier();\n    }\n\n    private bool SubsetGenerationPredicate(TriggerUtils.SetOfTerms terms, TriggerTerm additionalTerm) {\n      return true; // FIXME Remove this\n      //return additionalTerm.Variables.Where(v => v is BoundVar && !terms.Any(t => t.Variables.Contains(v))).Any();\n    }\n\n    /// <summary>\n    /// Collect triggers from the body of each quantifier, and share them\n    /// between all quantifiers. This method assumes that all quantifiers\n    /// actually come from the same context, and were the result of a split that\n    /// gave them all the same variables.\n    /// </summary>\n    /// <param name=\"triggersCollector\"></param>\n    void CollectAndShareTriggers(TriggersCollector triggersCollector) {\n      List<TriggerTerm> pool = new List<TriggerTerm>();\n      foreach (var q in quantifiers) {\n        var candidates = triggersCollector.CollectTriggers(q.quantifier).Deduplicate(TriggerTerm.Eq);\n        // filter out the candidates that was \"second-class\"\n        var filtered = TriggerUtils.Filter(candidates, tr => tr, (tr, _) => !tr.IsTranslatedToFunctionCall(), (tr, _) => { }).ToList();\n        // if there are only \"second-class\" candidates, add them back.\n        if (filtered.Count == 0) {\n          filtered = candidates;\n        }\n        pool.AddRange(filtered);\n      }\n      var distinctPool = pool.Deduplicate(TriggerTerm.Eq);\n\n      foreach (var q in quantifiers) {\n        q.CandidateTerms = distinctPool; // The list of candidate terms is immutable\n        q.Candidates = TriggerUtils.AllNonEmptySubsets(distinctPool, SubsetGenerationPredicate, q.quantifier.BoundVars).Select(set => set.ToTriggerCandidate()).ToList();\n      }\n    }\n\n    void CollectWithoutShareTriggers(TriggersCollector triggersCollector)\n    {\n      foreach (var q in quantifiers) {\n        var candidates = triggersCollector.CollectTriggers(q.quantifier).Deduplicate(TriggerTerm.Eq);\n        q.CandidateTerms = candidates; // The list of candidate terms is immutable\n        q.Candidates = TriggerUtils.AllNonEmptySubsets(candidates, SubsetGenerationPredicate, q.quantifier.BoundVars).Select(set => set.ToTriggerCandidate()).ToList();\n      }\n    }\n\n    private void TrimInvalidTriggers() {\n      foreach (var q in quantifiers) {\n        q.TrimInvalidTriggers();\n      }\n    }\n\n    void BuildDependenciesGraph() {\n      // The problem of finding matching loops between multiple-triggers is hard; it\n      // seems to require one to track exponentially-sized dependencies between parts\n      // of triggers and quantifiers. For now, we only do single-quantifier loop\n      // detection\n    }\n\n    bool SuppressMatchingLoops() {\n      // NOTE: This only looks for self-loops; that is, loops involving a single\n      // quantifier.\n\n      // For a given quantifier q, we introduce a triggering relation between trigger\n      // candidates by writing t1 → t2 if instantiating q from t1 introduces a ground\n      // term that matches t2. Then, we notice that this relation is transitive, since\n      // all triggers yield the same set of terms. This means that any matching loop\n      // t1 → ... → t1 can be reduced to a self-loop t1 → t1. Detecting such\n      // self-loops is then only a matter of finding terms in the body of the\n      // quantifier that match a given trigger.\n\n      // Of course, each trigger that actually appears in the body of the quantifier\n      // yields a trivial self-loop (e.g. P(i) in [∀ i {P(i)} ⋅ P(i)]), so we\n      // ignore this type of loops. In fact, we ignore any term in the body of the\n      // quantifier that matches one of the terms of the trigger (this ensures that\n      // [∀ x {f(x), f(f(x))} ⋅ f(x) = f(f(x))] is not a loop). And we even\n      // ignore terms that almost match a trigger term, modulo a single variable\n      // (this ensures that [∀ x y {a(x, y)} ⋅ a(x, y) == a(y, x)] is not a loop).\n      // In addition, we ignore cases where the only differences between a trigger\n      // and a trigger match are places where a variable is replaced with an\n      // expression whose free variables do not intersect that of the quantifier\n      // in which that expression is found. For examples of this behavious, see\n      // triggers/literals-do-not-cause-loops.\n      // This ignoring logic is implemented by the CouldCauseLoops method.\n      bool foundloop = false;\n      foreach (var q in quantifiers) {\n        var looping = new List<TriggerCandidate>();\n        var loopingMatches = new List<TriggerMatch>();\n\n        var safe = TriggerUtils.Filter(\n          q.Candidates,\n          candidate => candidate.LoopingSubterms(q.quantifier).ToList(),\n          (candidate, loopingSubterms) => !loopingSubterms.Any(),\n          (candidate, loopingSubterms) => {\n            looping.Add(candidate);\n            loopingMatches = loopingSubterms.ToList();\n            candidate.Annotation = \"may loop with \" + loopingSubterms.MapConcat(t => \"\\\"\" + Printer.ExprToString(t.OriginalExpr) + \"\\\"\", \", \");\n          }).ToList();\n\n        q.CouldSuppressLoops = safe.Count > 0;\n        q.LoopingMatches = loopingMatches;\n        if (!q.AllowsLoops && q.CouldSuppressLoops) {\n          q.Candidates = safe;\n          q.RejectedCandidates.AddRange(looping);\n        }\n\n        if (looping.Count > 0)\n          foundloop = true;\n      }\n      return foundloop;\n    }\n\n    bool RewriteMatchingLoop()\n    {\n      if (expr is QuantifierExpr) {\n        QuantifierExpr quantifier = (QuantifierExpr)expr;\n        var l = new List<QuantifierWithTriggers>();\n        List<Expression> splits = new List<Expression>();\n        bool rewritten = false;\n        foreach (var q in quantifiers) {\n          if (TriggerUtils.NeedsAutoTriggers(q.quantifier) && TriggerUtils.WantsMatchingLoopRewrite(q.quantifier)) {\n            var matchingLoopRewriter = new MatchingLoopRewriter();\n            var qq = matchingLoopRewriter.RewriteMatchingLoops(q);\n            splits.Add(qq);\n            l.Add(new QuantifierWithTriggers(qq));\n            rewritten = true;\n          } else {\n            // don't rewrite the quantifier if we are not auto generate triggers.\n            // This is because rewriting introduces new boundvars and will cause\n            // user provided triggers not mention all boundvars\n            splits.Add(q.quantifier);\n            l.Add(q);\n          }\n        }\n        if (rewritten) {\n          quantifier.SplitQuantifier = splits;\n          quantifiers = l;\n          return true;\n        }\n      }\n      return false;\n    }\n\n    void SelectTriggers() {\n      foreach (var q in quantifiers) { //FIXME Check whether this makes verification faster\n        q.Candidates = TriggerUtils.Filter(q.Candidates,\n          candidate => q.Candidates.Where(candidate.IsStrongerThan).ToList(),\n          (candidate, weakerCandidates) => !weakerCandidates.Any(),\n          (candidate, weakerCandidates) => {\n            q.RejectedCandidates.Add(candidate);\n            candidate.Annotation = \"more specific than \" + String.Join(\", \", weakerCandidates);\n          }).ToList();\n      }\n    }\n\n    internal class QuantifierGroup\n    {\n      internal QuantifierWithTriggers quantifier;\n      internal List<ComprehensionExpr> expressions;\n\n      public QuantifierGroup(QuantifierWithTriggers q, List<ComprehensionExpr> expressions) {\n        this.quantifier = q;\n        this.expressions = expressions;\n      }\n    }\n\n    // group split quantifier by what triggers they got, and merged them back into one quantifier.\n    private void CombineSplitQuantifier() {\n      if (quantifiers.Count > 1) {\n        List<QuantifierGroup> groups = new List<QuantifierGroup>();\n        groups.Add(new QuantifierGroup(quantifiers[0], new List<ComprehensionExpr> { quantifiers[0].quantifier }));\n        for (int i = 1; i < quantifiers.Count; i++) {\n          bool found = false;\n          for (int j = 0; j < groups.Count; j++) {\n            if (HasSameTriggers(quantifiers[i], groups[j].quantifier)) {\n              // belong to the same group\n              groups[j].expressions.Add(quantifiers[i].quantifier);\n              found = true;\n              break;\n            }\n          }\n          if (!found) {\n            // start a new group\n            groups.Add(new QuantifierGroup(quantifiers[i], new List<ComprehensionExpr> { quantifiers[i].quantifier }));\n          }\n        }\n        if (groups.Count == quantifiers.Count) {\n          // have the same number of splits, so no splits are combined.\n          return;\n        }\n        // merge expressions in each group back to one quantifier.\n        List<QuantifierWithTriggers> list = new List<QuantifierWithTriggers>();\n        List<Expression> splits = new List<Expression>();\n        foreach (var group in groups) {\n          QuantifierWithTriggers q = group.quantifier;\n          if (q.quantifier is ForallExpr) {\n            ForallExpr quantifier = (ForallExpr)q.quantifier;\n            Expression expr = QuantifiersToExpression(quantifier.tok, BinaryExpr.ResolvedOpcode.And, group.expressions);\n            q.quantifier = new ForallExpr(quantifier.tok, quantifier.TypeArgs, quantifier.BoundVars, quantifier.Range, expr, TriggerUtils.CopyAttributes(quantifier.Attributes)) { Type = quantifier.Type, Bounds = quantifier.Bounds };\n          } else if (q.quantifier is ExistsExpr) {\n            ExistsExpr quantifier = (ExistsExpr)q.quantifier;\n            Expression expr = QuantifiersToExpression(quantifier.tok, BinaryExpr.ResolvedOpcode.Or, group.expressions);\n            q.quantifier = new ExistsExpr(quantifier.tok, quantifier.TypeArgs, quantifier.BoundVars, quantifier.Range, expr, TriggerUtils.CopyAttributes(quantifier.Attributes)) { Type = quantifier.Type, Bounds = quantifier.Bounds };\n          }\n          list.Add(q);\n          splits.Add(q.quantifier);\n        }\n        this.quantifiers = list;\n        Contract.Assert(this.expr is QuantifierExpr); // only QuantifierExpr has SplitQuantifier\n        ((QuantifierExpr)this.expr).SplitQuantifier = splits;\n      }\n    }\n\n    private bool HasSameTriggers(QuantifierWithTriggers one, QuantifierWithTriggers other) {\n      return TriggerUtils.SameLists(one.Candidates, other.Candidates, SameTriggerCandidate);\n    }\n\n    private static bool SameTriggerCandidate(TriggerCandidate arg1, TriggerCandidate arg2) {\n      return TriggerUtils.SameLists(arg1.Terms, arg2.Terms, TriggerTerm.Eq);\n    }\n\n    private Expression QuantifiersToExpression(IToken tok, BinaryExpr.ResolvedOpcode op, List<ComprehensionExpr> expressions) {\n      var expr = expressions[0].Term;\n      for (int i = 1; i < expressions.Count; i++) {\n        expr = new BinaryExpr(tok, op, expr, expressions[i].Term);\n      }\n      return expr;\n    }\n\n    private void CommitOne(QuantifierWithTriggers q, bool addHeader) {\n      var errorLevel = ErrorLevel.Info;\n      var msg = new StringBuilder();\n      var indent = addHeader ? \"  \" : \"\";\n      bool suppressWarnings = Attributes.Contains(q.quantifier.Attributes, \"nowarn\");\n\n      if (!TriggerUtils.NeedsAutoTriggers(q.quantifier)) { // NOTE: split and autotriggers attributes are passed down to Boogie\n        var extraMsg = TriggerUtils.WantsAutoTriggers(q.quantifier) ? \"\" : \" Note that {:autotriggers false} can cause instabilities. Consider using {:nowarn}, {:matchingloop} (not great either), or a manual trigger instead.\";\n        msg.AppendFormat(\"Not generating triggers for \\\"{0}\\\".{1}\", Printer.ExprToString(q.quantifier.Term), extraMsg).AppendLine();\n      } else {\n        if (addHeader) {\n          msg.AppendFormat(\"For expression \\\"{0}\\\":\", Printer.ExprToString(q.quantifier.Term)).AppendLine();\n        }\n\n        foreach (var candidate in q.Candidates) {\n          q.quantifier.Attributes = new Attributes(\"trigger\", candidate.Terms.Select(t => t.Expr).ToList(), q.quantifier.Attributes);\n        }\n\n        AddTriggersToMessage(\"Selected triggers:\", q.Candidates, msg, indent);\n        AddTriggersToMessage(\"Rejected triggers:\", q.RejectedCandidates, msg, indent, true);\n\n#if QUANTIFIER_WARNINGS\n        var WARN_TAG = ArmadaOptions.O.UnicodeOutput ? \"⚠ \" : \"/!\\\\ \";\n        var WARN_TAG_OVERRIDE = suppressWarnings ? \"(Suppressed warning) \" : WARN_TAG;\n        var WARN_LEVEL = suppressWarnings ? ErrorLevel.Info : ErrorLevel.Warning;\n        var WARN = indent + WARN_TAG_OVERRIDE;\n        if (!q.CandidateTerms.Any()) {\n          errorLevel = WARN_LEVEL;\n          msg.Append(WARN).AppendLine(\"No terms found to trigger on.\");\n        } else if (!q.Candidates.Any()) {\n          errorLevel = WARN_LEVEL;\n          msg.Append(WARN).AppendLine(\"No trigger covering all quantified variables found.\");\n        } else if (!q.CouldSuppressLoops && !q.AllowsLoops) {\n          errorLevel = WARN_LEVEL;\n          msg.Append(WARN).AppendLine(\"Suppressing loops would leave this expression without triggers.\");\n        } else if (suppressWarnings) {\n          errorLevel = ErrorLevel.Warning;\n          msg.Append(indent).Append(WARN_TAG).AppendLine(\"There is no warning here to suppress.\");\n        }\n#endif\n      }\n\n      if (msg.Length > 0) {\n        var msgStr = msg.ToString().TrimEnd(\"\\r\\n \".ToCharArray());\n        reporter.Message(MessageSource.Rewriter, errorLevel, q.quantifier.tok, msgStr);\n      }\n    }\n\n    private static void AddTriggersToMessage<T>(string header, List<T> triggers, StringBuilder msg, string indent, bool newlines = false) {\n      if (triggers.Any()) {\n        msg.Append(indent).Append(header);\n        if (triggers.Count == 1) {\n          msg.Append(\" \");\n        } else if (triggers.Count > 1) {\n          msg.AppendLine().Append(indent).Append(\"  \");\n        }\n        var separator = newlines && triggers.Count > 1 ? Environment.NewLine + indent + \"  \" : \", \";\n        msg.AppendLine(String.Join(separator, triggers));\n      }\n    }\n\n    internal void CommitTriggers() {\n      foreach (var q in quantifiers) {\n        CommitOne(q, quantifiers.Count > 1);\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "Source/Armada/Triggers/QuantifiersCollector.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing Microsoft.Boogie;\nusing System.Collections.ObjectModel;\nusing System.Diagnostics.Contracts;\n\nnamespace Microsoft.Armada.Triggers {\n  internal class QuantifierCollector : TopDownVisitor<OldExpr/*?*/> {\n    readonly ErrorReporter reporter;\n    private readonly HashSet<Expression> quantifiers = new HashSet<Expression>();\n    internal readonly Dictionary<Expression, HashSet<OldExpr>> exprsInOldContext = new Dictionary<Expression, HashSet<OldExpr>>();\n    internal readonly List<QuantifiersCollection> quantifierCollections = new List<QuantifiersCollection>();\n\n    public QuantifierCollector(ErrorReporter reporter) {\n      Contract.Requires(reporter != null);\n      this.reporter = reporter;\n    }\n\n    protected override bool VisitOneExpr(Expression expr, ref OldExpr/*?*/ enclosingOldContext) {\n      var e = expr as ComprehensionExpr;\n\n      // only consider quantifiers that are not empty (Bound.Vars.Count > 0)\n      if (e != null && e.BoundVars.Count > 0 && !quantifiers.Contains(e)) {\n        if (e is SetComprehension || e is MapComprehension) {\n          quantifiers.Add(e);\n          quantifierCollections.Add(new QuantifiersCollection(e, Enumerable.Repeat(e, 1), reporter));\n        } else if (e is ForallExpr || e is ExistsExpr) {\n          var quantifier = e as QuantifierExpr;\n          quantifiers.Add(quantifier);\n          if (quantifier.SplitQuantifier != null) {\n            var collection = quantifier.SplitQuantifier.Select(q => q as ComprehensionExpr).Where(q => q != null);\n            quantifierCollections.Add(new QuantifiersCollection(e, collection, reporter));\n            quantifiers.UnionWith(quantifier.SplitQuantifier);\n          } else {\n            quantifierCollections.Add(new QuantifiersCollection(e, Enumerable.Repeat(quantifier, 1), reporter));\n          }\n        }\n      }\n\n      if (expr is OldExpr) {\n        enclosingOldContext = (OldExpr)expr;\n      } else if (enclosingOldContext != null) { // FIXME be more restrctive on the type of stuff that we annotate\n        // Add the association (expr, oldContext) to exprsInOldContext. However, due to chaining expressions,\n        // expr may already be a key in exprsInOldContext.\n        HashSet<OldExpr> prevValue;\n        if (exprsInOldContext.TryGetValue(expr, out prevValue)) {\n          prevValue.Add(enclosingOldContext);\n        } else {\n          var single = new HashSet<OldExpr>() { enclosingOldContext };\n          exprsInOldContext.Add(expr, single);\n        }\n      }\n\n      return true;\n    }\n\n    protected override bool VisitOneStmt(Statement stmt, ref OldExpr/*?*/ st) {\n      if (stmt is ForallStmt) {\n        ForallStmt s = (ForallStmt)stmt;\n        if (s.ForallExpressions != null) {\n          foreach (Expression expr in s.ForallExpressions) {\n            VisitOneExpr(expr, ref st);\n          }\n        }\n      }\n      return true;\n    }\n  }\n}\n"
  },
  {
    "path": "Source/Armada/Triggers/TriggerExtensions.cs",
    "content": "#define THROW_UNSUPPORTED_COMPARISONS\n\nusing Microsoft.Armada;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text;\n\nnamespace Microsoft.Armada.Triggers {\n  internal static class DeduplicateExtension {\n    public static List<T> Deduplicate<T>(this IEnumerable<T> seq, Func<T, T, bool> eq) {\n      List<T> deduplicated = new List<T>();\n\n      foreach (var elem in seq) {\n        if (!deduplicated.Any(other => eq(elem, other))) {\n          deduplicated.Add(elem);\n        }\n      }\n\n      return deduplicated;\n    }\n  }\n\n  internal struct TriggerMatch {\n    internal Expression Expr;\n    internal Expression OriginalExpr;\n    internal Dictionary<IVariable, Expression> Bindings;\n\n    internal static bool Eq(TriggerMatch t1, TriggerMatch t2) {\n      return ExprExtensions.ExpressionEq(t1.Expr, t2.Expr);\n    }\n\n    /// <summary>\n    ///  This method checks whether this match could actually cause a loop, given a set of terms participating in a trigger;\n    ///  to compute an answer, we match the Expr of this match against the Exprs of each of these term, allowing for harmless\n    ///  variations. If any of these tests does match, this term likely won't cause a loop.\n    ///  The boundVars list is useful to determine that forall x :: P(x) == P(y+z) does not loop.\n    /// </summary>\n    internal bool CouldCauseLoops(List<TriggerTerm> terms, ISet<BoundVar> boundVars) {\n      var expr = Expr;\n      return !terms.Any(term => term.Expr.ExpressionEqModuloExpressionsNotInvolvingBoundVariables(expr, boundVars));\n    }\n  }\n\n  internal static class ExprExtensions {\n    internal static bool IsInlineable(this LetExpr expr) {\n      return expr.LHSs.All(p => p.Var != null) && expr.Exact;\n    }\n\n    internal static IEnumerable<Expression> AllSubExpressions(this Expression expr, bool wrapOld, bool strict, bool inlineLets = false) {\n      var isOld = expr is OldExpr ? new HashSet<OldExpr>() { expr as OldExpr } : null;\n\n      if (inlineLets && expr is LetExpr && ((LetExpr)expr).IsInlineable()) {\n        var le = (LetExpr)expr;\n        foreach (var subexpr in AllSubExpressions(Translator.InlineLet(le), wrapOld, strict, inlineLets)) {\n          yield return subexpr;\n        }\n        // If strict is false, then the recursive call will already yield a copy of (the inlined version) of expr,\n        // so there's no need to yield expr itself below.\n        yield break;\n      }\n\n      foreach (var subexpr in expr.SubExpressions) {\n        foreach (var r_subexpr in AllSubExpressions(subexpr, wrapOld, false, inlineLets)) {\n          foreach (var e in TriggerUtils.MaybeWrapInOld(r_subexpr, isOld)) {\n            yield return e;\n          }\n        }\n      }\n\n      if (expr is StmtExpr) {\n        foreach (var r_subexpr in AllSubExpressions(((StmtExpr)expr).S, wrapOld, false, inlineLets)) {\n          foreach (var e in TriggerUtils.MaybeWrapInOld(r_subexpr, isOld)) {\n            yield return e;\n          }\n        }\n      }\n\n      if (!strict) {\n        yield return expr;\n      }\n    }\n\n    internal static IEnumerable<Expression> AllSubExpressions(this Statement stmt, bool wrapOld, bool strict, bool inlineLets = false) {\n      foreach (var subexpr in stmt.SubExpressions) {\n        foreach (var r_subexpr in AllSubExpressions(subexpr, wrapOld, false, inlineLets)) {\n          yield return r_subexpr;\n        }\n      }\n\n      foreach (var substmt in stmt.SubStatements) {\n        foreach (var r_subexpr in AllSubExpressions(substmt, wrapOld, false, inlineLets)) {\n          yield return r_subexpr;\n        }\n      }\n    }\n\n    internal static bool ExpressionEq(this Expression expr1, Expression expr2) {\n      expr1 = expr1.Resolved;\n      expr2 = expr2.Resolved;\n\n      return ShallowEq_Top(expr1, expr2) && TriggerUtils.SameLists(expr1.SubExpressions, expr2.SubExpressions, (e1, e2) => ExpressionEq(e1, e2));\n    }\n\n    internal static bool ExpressionEqModuloExpressionsNotInvolvingBoundVariables(this Expression expr1, Expression expr2, ISet<BoundVar> boundVars) {\n      expr1 = expr1.Resolved;\n      expr2 = expr2.Resolved;\n\n      if (expr1 is IdentifierExpr) {\n        if (expr2 is IdentifierExpr) {\n          return true;\n        } else {\n          var freeInE2 = Translator.ComputeFreeVariables(expr2);\n          freeInE2.IntersectWith(boundVars);\n          return !freeInE2.Any();\n        }\n      }\n\n      return ShallowEq_Top(expr1, expr2) && TriggerUtils.SameLists(expr1.SubExpressions,\n        expr2.SubExpressions, (e1, e2) => ExpressionEqModuloExpressionsNotInvolvingBoundVariables(e1, e2, boundVars));\n    }\n\n    internal static bool MatchesTrigger(this Expression expr, Expression trigger, ISet<BoundVar> holes, Dictionary<IVariable, Expression> bindings) {\n      expr = expr.Resolved;\n      trigger = trigger.Resolved;\n\n      if (trigger is IdentifierExpr) {\n        var var = ((IdentifierExpr)trigger).Var;\n\n        if (holes.Contains(var)) {\n          Expression existing_binding = null;\n          if (bindings.TryGetValue(var, out existing_binding)) {\n            return ExpressionEq(expr, existing_binding);\n          } else {\n            bindings[var] = expr;\n            return true;\n          }\n        }\n      }\n\n      return ShallowEq_Top(expr, trigger) && TriggerUtils.SameLists(expr.SubExpressions, trigger.SubExpressions, (e1, e2) => MatchesTrigger(e1, e2, holes, bindings));\n    }\n\n    private static TriggerMatch? MatchAgainst(this Expression expr, Expression trigger, IEnumerable<BoundVar> holes, Expression originalExpr) {\n      var bindings = new Dictionary<IVariable, Expression>();\n      if (expr.MatchesTrigger(trigger, new HashSet<BoundVar>(holes), bindings)) {\n        return new TriggerMatch { Expr = expr, OriginalExpr = originalExpr ?? expr, Bindings = bindings };\n      } else {\n        return null;\n      }\n    }\n\n    internal static IEnumerable<TriggerMatch> SubexpressionsMatchingTrigger(this ComprehensionExpr quantifier, Expression trigger) {\n      return quantifier.AllSubExpressions(true, true, true)\n        .Select(e => TriggerUtils.PrepareExprForInclusionInTrigger(e).MatchAgainst(trigger, quantifier.BoundVars, e))\n        .Where(e => e.HasValue).Select(e => e.Value);\n    }\n\n    private static bool ShallowSameAttributes(Attributes attributes1, Attributes attributes2) {\n      return TriggerUtils.SameLists(attributes1.AsEnumerable(), attributes2.AsEnumerable(), ShallowSameSingleAttribute);\n    }\n\n    private static bool ShallowSameSingleAttribute(Attributes arg1, Attributes arg2) {\n      return arg1.Name == arg2.Name;\n    }\n\n    private static bool SameBoundVar(IVariable arg1, IVariable arg2) {\n      return arg1 == arg2 ||\n             (arg1.Name == arg2.Name &&\n              arg1.CompileName == arg2.CompileName &&\n              arg1.DisplayName == arg2.DisplayName &&\n              arg1.UniqueName == arg2.UniqueName &&\n              arg1.IsGhost == arg2.IsGhost &&\n              arg1.IsMutable == arg2.IsMutable &&\n              ((arg1.Type == null && arg2.Type == null) || arg1.Type.Equals(arg2.Type)));\n    }\n\n    /// <summary>\n    /// Compares two abstract syntax expressions, looking only at their direct members. Subexpressions and substatements are not compared.\n    /// </summary>\n    /// <returns></returns>\n    internal static bool ShallowEq_Top(Expression expr1, Expression expr2) {\n      Contract.Requires(expr1 != null);\n      Contract.Requires(expr2 != null);\n\n      // We never compare concrete expressions\n      Contract.Requires(!(expr1 is ConcreteSyntaxExpression));\n      Contract.Requires(!(expr2 is ConcreteSyntaxExpression));\n\n      // CPC: Hey future editor: the following block of code is auto-generated. Just add your own cases at the end.\n      //      This could be a visitor pattern, except I need to visit a pair of nodes.\n      //      It could also be implemented in each individual class. I'd have a slight preference for that.\n      //      This really just wants to use double dispatch.\n      if (expr1 is UnboxingCastExpr && expr2 is UnboxingCastExpr) {\n        return ShallowEq((UnboxingCastExpr)expr1, (UnboxingCastExpr)expr2);\n      } else if (expr1 is BoxingCastExpr && expr2 is BoxingCastExpr) {\n        return ShallowEq((BoxingCastExpr)expr1, (BoxingCastExpr)expr2);\n      } else if (expr1 is MatchExpr && expr2 is MatchExpr) {\n        return ShallowEq((MatchExpr)expr1, (MatchExpr)expr2);\n      } else if (expr1 is ITEExpr && expr2 is ITEExpr) {\n        return ShallowEq((ITEExpr)expr1, (ITEExpr)expr2);\n      } else if (expr1 is StmtExpr && expr2 is StmtExpr) {\n        return ShallowEq((StmtExpr)expr1, (StmtExpr)expr2);\n      } else if (expr1 is WildcardExpr && expr2 is WildcardExpr) {\n        return ShallowEq((WildcardExpr)expr1, (WildcardExpr)expr2);\n      } else if (expr1 is ComprehensionExpr && expr2 is ComprehensionExpr) {\n        return ShallowEq((ComprehensionExpr)expr1, (ComprehensionExpr)expr2);\n      } else if (expr1 is NamedExpr && expr2 is NamedExpr) {\n        return ShallowEq((NamedExpr)expr1, (NamedExpr)expr2);\n      } else if (expr1 is LetExpr && expr2 is LetExpr) {\n        return ShallowEq((LetExpr)expr1, (LetExpr)expr2);\n      } else if (expr1 is TernaryExpr && expr2 is TernaryExpr) {\n        return ShallowEq((TernaryExpr)expr1, (TernaryExpr)expr2);\n      } else if (expr1 is BinaryExpr && expr2 is BinaryExpr) {\n        return ShallowEq((BinaryExpr)expr1, (BinaryExpr)expr2);\n      } else if (expr1 is UnaryExpr && expr2 is UnaryExpr) {\n        return ShallowEq((UnaryExpr)expr1, (UnaryExpr)expr2);\n      } else if (expr1 is SeqConstructionExpr && expr2 is SeqConstructionExpr) {\n        return ShallowEq((SeqConstructionExpr)expr1, (SeqConstructionExpr)expr2);\n      } else if (expr1 is MultiSetFormingExpr && expr2 is MultiSetFormingExpr) {\n        return ShallowEq((MultiSetFormingExpr)expr1, (MultiSetFormingExpr)expr2);\n      } else if (expr1 is OldExpr && expr2 is OldExpr) {\n        return ShallowEq((OldExpr)expr1, (OldExpr)expr2);\n      } else if (expr1 is FunctionCallExpr && expr2 is FunctionCallExpr) {\n        return ShallowEq((FunctionCallExpr)expr1, (FunctionCallExpr)expr2);\n      } else if (expr1 is ApplyExpr && expr2 is ApplyExpr) {\n        return ShallowEq((ApplyExpr)expr1, (ApplyExpr)expr2);\n      } else if (expr1 is SeqUpdateExpr && expr2 is SeqUpdateExpr) {\n        return ShallowEq((SeqUpdateExpr)expr1, (SeqUpdateExpr)expr2);\n      } else if (expr1 is MultiSelectExpr && expr2 is MultiSelectExpr) {\n        return ShallowEq((MultiSelectExpr)expr1, (MultiSelectExpr)expr2);\n      } else if (expr1 is SeqSelectExpr && expr2 is SeqSelectExpr) {\n        return ShallowEq((SeqSelectExpr)expr1, (SeqSelectExpr)expr2);\n      } else if (expr1 is MemberSelectExpr && expr2 is MemberSelectExpr) {\n        return ShallowEq((MemberSelectExpr)expr1, (MemberSelectExpr)expr2);\n      } else if (expr1 is MapDisplayExpr && expr2 is MapDisplayExpr) { //Note: MapDisplayExpr is not a DisplayExpression\n        return ShallowEq((MapDisplayExpr)expr1, (MapDisplayExpr)expr2);\n      } else if (expr1 is DisplayExpression && expr2 is DisplayExpression) {\n        return ShallowEq((DisplayExpression)expr1, (DisplayExpression)expr2);\n      } else if (expr1 is IdentifierExpr && expr2 is IdentifierExpr) {\n        return ShallowEq((IdentifierExpr)expr1, (IdentifierExpr)expr2);\n      } else if (expr1 is ThisExpr && expr2 is ThisExpr) {\n        return ShallowEq((ThisExpr)expr1, (ThisExpr)expr2);\n      } else if (expr1 is DatatypeValue && expr2 is DatatypeValue) {\n        return ShallowEq((DatatypeValue)expr1, (DatatypeValue)expr2);\n      } else if (expr1 is LiteralExpr && expr2 is LiteralExpr) {\n        return ShallowEq((LiteralExpr)expr1, (LiteralExpr)expr2);\n      } else {\n        // If this assertion fail, then a new abstract AST node was probably introduced but not registered here.\n        Contract.Assert(expr1.GetType() != expr2.GetType());\n        return false;\n      }\n    }\n\n    private static bool ShallowEq(UnboxingCastExpr expr1, UnboxingCastExpr expr2) {\n      Contract.Requires(false);\n      throw new InvalidOperationException();\n    }\n\n    private static bool ShallowEq(BoxingCastExpr expr1, BoxingCastExpr expr2) {\n      return expr1.FromType == expr2.FromType &&\n             expr1.ToType == expr2.ToType;\n    }\n\n    private static bool ShallowEq(MatchExpr expr1, MatchExpr expr2) {\n      return true;\n    }\n\n    private static bool ShallowEq(ITEExpr expr1, ITEExpr expr2) {\n      return true;\n    }\n\n    private static bool ShallowEq(StmtExpr expr1, StmtExpr expr2) {\n#if THROW_UNSUPPORTED_COMPARISONS\n      Contract.Assume(false); // This kind of expression never appears in a trigger\n      throw new NotImplementedException();\n#else\n      return expr1.S == expr2.S;\n#endif\n    }\n\n    private static bool ShallowEq(WildcardExpr expr1, WildcardExpr expr2) {\n      return true;\n    }\n\n    private static bool ShallowEq(LambdaExpr expr1, LambdaExpr expr2) {\n#if THROW_UNSUPPORTED_COMPARISONS\n      Contract.Assume(false); // This kind of expression never appears in a trigger\n      throw new NotImplementedException();\n#else\n      return false;\n#endif\n    }\n\n    private static bool ShallowEq(MapComprehension expr1, MapComprehension expr2) {\n      return expr1.Finite == expr2.Finite;\n    }\n\n    private static bool ShallowEq(SetComprehension expr1, SetComprehension expr2) {\n      return expr1.TermIsImplicit == expr2.TermIsImplicit && //TODO\n             expr1.Finite == expr2.Finite;\n    }\n\n    private static bool ShallowEq(ExistsExpr expr1, ExistsExpr expr2) {\n      return true;\n    }\n\n    private static bool ShallowEq(ForallExpr expr1, ForallExpr expr2) {\n      return true;\n    }\n\n    private static bool ShallowEq(QuantifierExpr expr1, QuantifierExpr expr2) {\n      if (!TriggerUtils.SameNullity(expr1.SplitQuantifier, expr2.SplitQuantifier)) {\n        return false;\n      }\n\n      if (expr1.SplitQuantifier != null && expr2.SplitQuantifier != null) {\n        return ShallowEq_Top(expr1.SplitQuantifierExpression, expr2.SplitQuantifierExpression);\n      }\n\n      if (expr1.TypeArgs.Count != expr2.TypeArgs.Count ||\n          !TriggerUtils.SameNullity(expr1.Range, expr2.Range)) {\n        return false;\n      }\n\n      if (expr1 is ExistsExpr && expr2 is ExistsExpr) {\n        return ShallowEq((ExistsExpr)expr1, (ExistsExpr)expr2);\n      } else if (expr1 is ForallExpr && expr2 is ForallExpr) {\n        return ShallowEq((ForallExpr)expr1, (ForallExpr)expr2);\n      } else {\n        return false;\n      }\n    }\n\n    private static bool ShallowEq(ComprehensionExpr expr1, ComprehensionExpr expr2) {\n      if (!TriggerUtils.SameLists(expr1.BoundVars, expr2.BoundVars, SameBoundVar) ||\n          !ShallowSameAttributes(expr1.Attributes, expr2.Attributes) ||\n        // Filled in during resolution: !SameLists(expr1.Bounds, expr2.Bounds, ReferenceCompare) ||\n        //                              !SameLists(expr1.MissingBounds, expr2.MissingBounds, SameBoundVar) ||\n          !TriggerUtils.SameNullity(expr1.Range, expr2.Range)) { //TODO Check\n        return false;\n      }\n\n      if (expr1 is LambdaExpr && expr2 is LambdaExpr) {\n        return ShallowEq((LambdaExpr)expr1, (LambdaExpr)expr2);\n      } else if (expr1 is MapComprehension && expr2 is MapComprehension) {\n        return ShallowEq((MapComprehension)expr1, (MapComprehension)expr2);\n      } else if (expr1 is SetComprehension && expr2 is SetComprehension) {\n        return ShallowEq((SetComprehension)expr1, (SetComprehension)expr2);\n      } else if (expr1 is QuantifierExpr && expr2 is QuantifierExpr) {\n        return ShallowEq((QuantifierExpr)expr1, (QuantifierExpr)expr2);\n      } else {\n        return false; // ComprehensionExpr is abstract\n      }\n    }\n\n    private static bool ShallowEq(NamedExpr expr1, NamedExpr expr2) {\n      return expr1.Name == expr2.Name &&\n             TriggerUtils.SameNullity(expr1.Contract, expr2.Contract);\n    }\n\n    private static bool ShallowEq(LetExpr expr1, LetExpr expr2) {\n      return expr1.Exact == expr2.Exact &&\n             ShallowSameAttributes(expr1.Attributes, expr2.Attributes);\n    }\n\n    private static bool ShallowEq(TernaryExpr expr1, TernaryExpr expr2) {\n      return expr1.Op == expr2.Op;\n    }\n\n    private static bool ShallowEq(BinaryExpr expr1, BinaryExpr expr2) {\n      Contract.Requires(expr1.ResolvedOp != BinaryExpr.ResolvedOpcode.YetUndetermined);\n      Contract.Requires(expr2.ResolvedOp != BinaryExpr.ResolvedOpcode.YetUndetermined);\n      return expr1.ResolvedOp == expr2.ResolvedOp;\n    }\n\n    private static bool ShallowEq(ConversionExpr expr1, ConversionExpr expr2) {\n      return expr1.Type == expr2.Type; //TODO equality on types?\n    }\n\n    private static bool ShallowEq(UnaryOpExpr expr1, UnaryOpExpr expr2) {\n      return expr1.Op == expr2.Op;\n    }\n\n    private static bool ShallowEq(UnaryExpr expr1, UnaryExpr expr2) {\n      if (expr1 is ConversionExpr && expr2 is ConversionExpr) {\n        return ShallowEq((ConversionExpr)expr1, (ConversionExpr)expr2);\n      } else if (expr1 is UnaryOpExpr && expr2 is UnaryOpExpr) {\n        return ShallowEq((UnaryOpExpr)expr1, (UnaryOpExpr)expr2);\n      } else {\n        return false; // UnaryExpr is abstract\n      }\n    }\n\n    private static bool ShallowEq(MultiSetFormingExpr expr1, MultiSetFormingExpr expr2) {\n      return true;\n    }\n\n    private static bool ShallowEq(SeqConstructionExpr expr1, SeqConstructionExpr expr2) {\n      return true;\n    }\n\n    private static bool ShallowEq(OldExpr expr1, OldExpr expr2) {\n      return true;\n    }\n\n    private static bool ShallowEq(FunctionCallExpr expr1, FunctionCallExpr expr2) {\n      return expr1.Name == expr2.Name &&\n             expr1.CoCall == expr2.CoCall && //TODO\n             expr1.Function == expr2.Function; // TODO TypeArgumentSubstitutions?\n    }\n\n    private static bool ShallowEq(ApplyExpr expr1, ApplyExpr expr2) {\n      return true;\n    }\n\n    private static bool ShallowEq(SeqUpdateExpr expr1, SeqUpdateExpr expr2) {\n      if (expr1.ResolvedUpdateExpr == null) {\n        Contract.Assert(expr2.ResolvedUpdateExpr == null);\n      }\n      return true;\n    }\n\n    private static bool ShallowEq(MultiSelectExpr expr1, MultiSelectExpr expr2) {\n      return true;\n    }\n\n    private static bool ShallowEq(SeqSelectExpr expr1, SeqSelectExpr expr2) {\n      return expr1.SelectOne == expr2.SelectOne &&\n             TriggerUtils.SameNullity(expr1.Seq, expr2.Seq) &&\n             TriggerUtils.SameNullity(expr1.E0, expr2.E0) &&\n             TriggerUtils.SameNullity(expr1.E1, expr2.E1);\n    }\n\n    private static bool ShallowEq(MemberSelectExpr expr1, MemberSelectExpr expr2) {\n      return expr1.MemberName == expr2.MemberName &&\n             expr1.Member == expr2.Member &&\n             TriggerUtils.SameLists(expr1.TypeApplication, expr2.TypeApplication, TypeEq);\n    }\n\n    internal static bool TypeEq(Type type1, Type type2) {\n      return type1.Equals(type2);\n    }\n\n    private static bool ShallowEq(SeqDisplayExpr expr1, SeqDisplayExpr expr2) {\n      return true;\n    }\n\n    private static bool ShallowEq(MapDisplayExpr expr1, MapDisplayExpr expr2) {\n      return expr1.Finite == expr2.Finite;\n    }\n\n    private static bool ShallowEq(MultiSetDisplayExpr expr1, MultiSetDisplayExpr expr2) {\n      return true;\n    }\n\n    private static bool ShallowEq(SetDisplayExpr expr1, SetDisplayExpr expr2) {\n      return expr1.Finite == expr2.Finite;\n    }\n\n    private static bool ShallowEq(DisplayExpression expr1, DisplayExpression expr2) {\n      if (expr1 is SeqDisplayExpr && expr2 is SeqDisplayExpr) {\n        return ShallowEq((SeqDisplayExpr)expr1, (SeqDisplayExpr)expr2);\n      } else if (expr1 is MultiSetDisplayExpr && expr2 is MultiSetDisplayExpr) {\n        return ShallowEq((MultiSetDisplayExpr)expr1, (MultiSetDisplayExpr)expr2);\n      } else if (expr1 is SetDisplayExpr && expr2 is SetDisplayExpr) {\n        return ShallowEq((SetDisplayExpr)expr1, (SetDisplayExpr)expr2);\n      } else {\n        return false;\n      }\n    }\n\n    private static bool ShallowEq(AutoGhostIdentifierExpr expr1, AutoGhostIdentifierExpr expr2) {\n      return true;\n    }\n\n    private static bool ShallowEq(IdentifierExpr expr1, IdentifierExpr expr2) {\n      if (expr1.Name != expr2.Name ||\n          expr1.Var != expr2.Var) {\n        return false;\n      }\n\n      if (expr1 is AutoGhostIdentifierExpr && expr2 is AutoGhostIdentifierExpr) {\n        return ShallowEq((AutoGhostIdentifierExpr)expr1, (AutoGhostIdentifierExpr)expr2);\n      } else {\n        return true;\n      }\n    }\n\n    private static bool ShallowEq(ImplicitThisExpr expr1, ImplicitThisExpr expr2) {\n      return true;\n    }\n\n    private static bool ShallowEq(ThisExpr expr1, ThisExpr expr2) {\n      if (expr1 is ImplicitThisExpr && expr2 is ImplicitThisExpr) {\n        return ShallowEq((ImplicitThisExpr)expr1, (ImplicitThisExpr)expr2);\n      } else {\n        return (expr1.GetType() == expr2.GetType()); // LiteralExpr is not abstract\n      }\n    }\n\n    private static bool ShallowEq(DatatypeValue expr1, DatatypeValue expr2) {\n      return // Implied by Ctor equality: expr1.DatatypeName == expr2.DatatypeName &&\n        // Implied by Ctor equality: expr1.MemberName == expr2.MemberName &&\n             expr1.Ctor == expr2.Ctor &&\n        // Contextual information: expr1.IsCoCall == expr2.IsCoCall &&\n             TriggerUtils.SameLists(expr1.InferredTypeArgs, expr2.InferredTypeArgs, TypeEq);\n    }\n\n    private static bool ShallowEq(StringLiteralExpr expr1, StringLiteralExpr expr2) {\n      return true;\n    }\n\n    private static bool ShallowEq(CharLiteralExpr expr1, CharLiteralExpr expr2) {\n      return true;\n    }\n\n    private static bool ShallowEq(StaticReceiverExpr expr1, StaticReceiverExpr expr2) {\n      return true;\n    }\n\n    private static bool ShallowEq(LiteralExpr expr1, LiteralExpr expr2) {\n      if (!TriggerUtils.SameNullity(expr1.Value, expr2.Value) || (expr1.Value != null && !expr1.Value.Equals(expr2.Value))) {\n        return false;\n      }\n\n      if (expr1 is StringLiteralExpr && expr2 is StringLiteralExpr) {\n        return ShallowEq((StringLiteralExpr)expr1, (StringLiteralExpr)expr2);\n      } else if (expr1 is CharLiteralExpr && expr2 is CharLiteralExpr) {\n        return ShallowEq((CharLiteralExpr)expr1, (CharLiteralExpr)expr2);\n      } else if (expr1 is StaticReceiverExpr && expr2 is StaticReceiverExpr) {\n        return ShallowEq((StaticReceiverExpr)expr1, (StaticReceiverExpr)expr2);\n      } else {\n        return (expr1.GetType() == expr2.GetType()); // LiteralExpr is not abstract\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "Source/Armada/Triggers/TriggerUtils.cs",
    "content": "#define DEBUG_AUTO_TRIGGERS\n\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text;\n\nnamespace Microsoft.Armada.Triggers {\n  class TriggerUtils {\n    internal static List<T> CopyAndAdd<T>(List<T> seq, T elem) {\n      var copy = new List<T>(seq);\n      copy.Add(elem);\n      return copy;\n    }\n\n    public static Attributes CopyAttributes(Attributes source) {\n      if (source == null) {\n        return null;\n      } else {\n        return new Attributes(source.Name, source.Args, CopyAttributes(source.Prev));\n      }\n    }\n\n    internal class SetOfTerms {\n      internal bool IsRedundant { get; private set; }\n      internal List<TriggerTerm> Terms { get; set; }\n\n      private ISet<BoundVar> variables;\n      private Dictionary<BoundVar, TriggerTerm> termOwningAUniqueVar;\n      private Dictionary<TriggerTerm, ISet<BoundVar>> uniqueVarsOwnedByATerm;\n\n      public int Count { get { return Terms.Count; } }\n\n      private SetOfTerms() { }\n\n      internal TriggerCandidate ToTriggerCandidate() {\n        return new TriggerCandidate(Terms);\n      }\n\n      internal static SetOfTerms Empty() {\n        var newSet = new SetOfTerms();\n        newSet.IsRedundant = false;\n        newSet.Terms = new List<TriggerTerm>();\n        newSet.variables = new HashSet<BoundVar>();\n        newSet.termOwningAUniqueVar = new Dictionary<BoundVar, TriggerTerm>();\n        newSet.uniqueVarsOwnedByATerm = new Dictionary<TriggerTerm, ISet<BoundVar>>();\n        return newSet;\n      }\n\n      /// <summary>\n      /// Simple formulas like [P0(i) && P1(i) && P2(i) && P3(i) && P4(i)] yield very\n      /// large numbers of multi-triggers, most of which are useless. As it copies its\n      /// argument, this method updates various datastructures that allow it to\n      /// efficiently track ownership relations between formulae and bound variables,\n      /// and sets the IsRedundant flag of the returned set, allowing the caller to\n      /// discard that set of terms, and the ones that would have been built on top of\n      /// it, thus ensuring that the only sets of terms produced in the end are sets\n      /// of terms in which each element contributes (owns) at least one variable.\n      ///\n      /// Note that this is trickier than just checking every term for new variables;\n      /// indeed, a new term that does bring new variables in can make an existing\n      /// term redundant (see redundancy-detection-does-its-job-properly.dfy).\n      /// </summary>\n      internal SetOfTerms CopyWithAdd(TriggerTerm term, ISet<BoundVar> relevantVariables) {\n        var copy = new SetOfTerms();\n        copy.Terms = new List<TriggerTerm>(Terms);\n        copy.variables = new HashSet<BoundVar>(variables);\n        copy.termOwningAUniqueVar = new Dictionary<BoundVar, TriggerTerm>(termOwningAUniqueVar);\n        copy.uniqueVarsOwnedByATerm = new Dictionary<TriggerTerm, ISet<BoundVar>>(uniqueVarsOwnedByATerm);\n\n        copy.Terms.Add(term);\n\n        var varsInNewTerm = new HashSet<BoundVar>(term.BoundVars);\n        varsInNewTerm.IntersectWith(relevantVariables);\n\n        var ownedByNewTerm = new HashSet<BoundVar>();\n\n        // Check #0: does this term bring anything new?\n        copy.IsRedundant = IsRedundant || varsInNewTerm.All(bv => copy.variables.Contains(bv));\n        copy.variables.UnionWith(varsInNewTerm);\n\n        // Check #1: does this term claiming ownership of all its variables cause another term to become useless?\n        foreach (var v in varsInNewTerm) {\n          TriggerTerm originalOwner;\n          if (copy.termOwningAUniqueVar.TryGetValue(v, out originalOwner)) {\n            var alsoOwnedByOriginalOwner = copy.uniqueVarsOwnedByATerm[originalOwner];\n            alsoOwnedByOriginalOwner.Remove(v);\n            if (!alsoOwnedByOriginalOwner.Any()) {\n              copy.IsRedundant = true;\n            }\n          } else {\n            ownedByNewTerm.Add(v);\n            copy.termOwningAUniqueVar[v] = term;\n          }\n        }\n\n        // Actually claim ownership\n        copy.uniqueVarsOwnedByATerm[term] = ownedByNewTerm;\n\n        return copy;\n      }\n    }\n\n    internal static IEnumerable<SetOfTerms> AllSubsets(IList<TriggerTerm> source, Func<SetOfTerms, TriggerTerm, bool> predicate, int offset, ISet<BoundVar> relevantVariables) {\n      if (offset >= source.Count) {\n        yield return SetOfTerms.Empty();\n        yield break;\n      }\n\n      foreach (var subset in AllSubsets(source, predicate, offset + 1, relevantVariables)) {\n        var newSet = subset.CopyWithAdd(source[offset], relevantVariables);\n        if (!newSet.IsRedundant && predicate(subset, source[offset])) { // Fixme remove the predicate?\n          yield return newSet;\n        }\n        yield return subset;\n      }\n    }\n\n    internal static IEnumerable<SetOfTerms> AllNonEmptySubsets(IList<TriggerTerm> source, Func<SetOfTerms, TriggerTerm, bool> predicate, IEnumerable<BoundVar> relevantVariables) {\n      foreach (var subset in AllSubsets(source, predicate, 0, new HashSet<BoundVar>(relevantVariables))) {\n        if (subset.Count > 0) {\n          yield return subset;\n        }\n      }\n    }\n\n    internal static List<T> MergeAlterFirst<T>(List<T> a, List<T> b) {\n      Contract.Requires(a != null);\n      Contract.Requires(b != null);\n      a.AddRange(b);\n      return a;\n    }\n\n    internal static ISet<T> MergeAlterFirst<T>(ISet<T> a, ISet<T> b) {\n      Contract.Requires(a != null);\n      Contract.Requires(b != null);\n      a.UnionWith(b);\n      return a;\n    }\n\n    internal static bool SameLists<T>(IEnumerable<T> list1, IEnumerable<T> list2, Func<T, T, bool> comparer) {\n      if (ReferenceEquals(list1, list2)) {\n        return true;\n      } else if ((list1 == null) != (list2 == null)) {\n        return false;\n      }\n\n      var it1 = list1.GetEnumerator();\n      var it2 = list2.GetEnumerator();\n      bool it1_has, it2_has;\n      bool acc = true;\n\n      do {\n        it1_has = it1.MoveNext();\n        it2_has = it2.MoveNext();\n\n        if (it1_has == true && it2_has == true) {\n          acc = acc && comparer(it1.Current, it2.Current);\n        }\n      } while (it1_has && it2_has);\n\n      return it1_has == it2_has && acc;\n    }\n\n    internal static IEnumerable<T> Filter<T, U>(IEnumerable<T> elements, Func<T, U> Converter, Func<T, U, bool> predicate, Action<T, U> reject) {\n      var positive = new List<T>();\n      foreach (var elem in elements) {\n        var conv = Converter(elem);\n        if (predicate(elem, conv)) {\n          yield return elem;\n        } else {\n          reject(elem, conv);\n        }\n      }\n    }\n\n    internal static bool SameNullity<T>(T x1, T x2) where T : class {\n      return (x1 == null) == (x2 == null);\n    }\n\n    internal string JoinStringsWithHeader(string header, IEnumerable<string> lines) {\n      return header + String.Join(Environment.NewLine + new String(' ', header.Length), lines);\n    }\n\n    [Conditional(\"DEBUG_AUTO_TRIGGERS\")]\n    internal static void DebugTriggers(string format, params object[] more) {\n      Console.Error.WriteLine(format, more);\n    }\n\n    internal static bool AllowsMatchingLoops(ComprehensionExpr quantifier) {\n      Contract.Requires(!(quantifier is QuantifierExpr) || ((QuantifierExpr)quantifier).SplitQuantifier == null); // Don't call this on a quantifier with a Split clause: it's not a real quantifier\n      // This is different from nowarn: it won't remove loops at all, even if another trigger is available.\n      return Attributes.Contains(quantifier.Attributes, \"matchingloop\");\n    }\n\n    internal static bool WantsAutoTriggers(ComprehensionExpr quantifier) {\n      Contract.Requires(!(quantifier is QuantifierExpr) || ((QuantifierExpr)quantifier).SplitQuantifier == null); // Don't call this on a quantifier with a Split clause: it's not a real quantifier\n      bool wantsAutoTriggers = true;\n      return !Attributes.ContainsBool(quantifier.Attributes, \"autotriggers\", ref wantsAutoTriggers) || wantsAutoTriggers;\n    }\n\n    internal static bool NeedsAutoTriggers(ComprehensionExpr quantifier) {\n      Contract.Requires(!(quantifier is QuantifierExpr) || ((QuantifierExpr)quantifier).SplitQuantifier == null); // Don't call this on a quantifier with a Split clause: it's not a real quantifier\n      return !Attributes.Contains(quantifier.Attributes, \"trigger\") && WantsAutoTriggers(quantifier);\n    }\n\n    internal static bool WantsMatchingLoopRewrite(ComprehensionExpr quantifier)\n    {\n      Contract.Requires(!(quantifier is QuantifierExpr) || ((QuantifierExpr)quantifier).SplitQuantifier == null);\n      bool wantsMatchingLoopRewrite = true;\n      return (!Attributes.ContainsBool(quantifier.Attributes, \"matchinglooprewrite\", ref wantsMatchingLoopRewrite) || wantsMatchingLoopRewrite) && WantsAutoTriggers(quantifier);\n    }\n\n    internal static BinaryExpr.ResolvedOpcode RemoveNotInBinaryExprIn(BinaryExpr.ResolvedOpcode opcode) {\n      switch (opcode) {\n        case BinaryExpr.ResolvedOpcode.NotInMap:\n          return BinaryExpr.ResolvedOpcode.InMap;\n        case BinaryExpr.ResolvedOpcode.NotInSet:\n          return BinaryExpr.ResolvedOpcode.InSet;\n        case BinaryExpr.ResolvedOpcode.NotInSeq:\n          return BinaryExpr.ResolvedOpcode.InSeq;\n        case BinaryExpr.ResolvedOpcode.NotInMultiSet:\n          return BinaryExpr.ResolvedOpcode.InMultiSet;\n      }\n\n      Contract.Assert(false);\n      throw new ArgumentException();\n    }\n\n    internal static Expression PrepareExprForInclusionInTrigger(Expression expr, out bool isKiller) {\n      isKiller = false;\n\n      var ret = expr;\n      if (ret is BinaryExpr) {\n        ret = PrepareInMultisetForInclusionInTrigger(PrepareNotInForInclusionInTrigger((BinaryExpr)ret), ref isKiller);\n      }\n\n      return ret;\n    }\n\n    private static BinaryExpr PrepareNotInForInclusionInTrigger(BinaryExpr bexpr) {\n      if (bexpr.Op == BinaryExpr.Opcode.NotIn) {\n        var new_expr = new BinaryExpr(bexpr.tok, BinaryExpr.Opcode.In, bexpr.E0, bexpr.E1);\n        new_expr.ResolvedOp = RemoveNotInBinaryExprIn(bexpr.ResolvedOp);\n        new_expr.Type = bexpr.Type;\n        return new_expr;\n      } else {\n        return bexpr;\n      }\n    }\n\n    private static Expression PrepareInMultisetForInclusionInTrigger(BinaryExpr bexpr, ref bool isKiller) {\n      if (bexpr.ResolvedOp == BinaryExpr.ResolvedOpcode.InMultiSet) {\n        var new_expr = new SeqSelectExpr(bexpr.tok, true, bexpr.E1, bexpr.E0, null);\n        new_expr.Type = bexpr.Type;\n        isKiller = true; // [a in s] becomes [s[a] > 0], which is a trigger killer\n        return new_expr;\n      } else {\n        return bexpr;\n      }\n    }\n\n    internal static Expression PrepareExprForInclusionInTrigger(Expression expr) {\n      bool _;\n      return PrepareExprForInclusionInTrigger(expr, out _);\n    }\n\n    internal static IEnumerable<Expression> MaybeWrapInOld(Expression expr, HashSet<OldExpr>/*?*/ wrap) {\n      Contract.Requires(expr != null);\n      Contract.Requires(wrap == null || wrap.Count != 0);\n      if (wrap != null && !(expr is NameSegment) && !(expr is IdentifierExpr)) {\n        foreach (var w in wrap) {\n          var newExpr = new OldExpr(expr.tok, expr, w.At) { AtLabel = w.AtLabel };\n          newExpr.Type = expr.Type;\n          yield return newExpr;\n        }\n      } else {\n        yield return expr;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "Source/Armada/Triggers/TriggersCollector.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing Microsoft.Boogie;\nusing System.Diagnostics.Contracts;\nusing System.Diagnostics;\n\nnamespace Microsoft.Armada.Triggers {\n  class TriggerTerm {\n    internal Expression Expr { get; set; }\n    internal Expression OriginalExpr { get; set; }\n    internal ISet<IVariable> Variables { get; set; }\n    internal IEnumerable<BoundVar> BoundVars {\n      get {\n        return Variables.Select(v => v as BoundVar).Where(v => v != null);\n      }\n    }\n\n    public override string ToString() {\n      return Printer.ExprToString(Expr);\n      // NOTE: Using OriginalExpr here could cause some confusion:\n      // for example, {a !in b} is a binary expression, yielding\n      // trigger {a in b}. Saying the trigger is a !in b would be\n      // rather misleading.\n    }\n\n    internal enum TermComparison {\n      SameStrength = 0, Stronger = 1, NotStronger = -1\n    }\n\n    internal TermComparison CompareTo(TriggerTerm other) {\n      if (this == other) {\n        return TermComparison.SameStrength;\n      } else if (Expr.AllSubExpressions(true, true).Any(other.Expr.ExpressionEq)) {\n        return TermComparison.Stronger;\n      } else {\n        return TermComparison.NotStronger;\n      }\n    }\n\n    internal static bool Eq(TriggerTerm t1, TriggerTerm t2) {\n      return ExprExtensions.ExpressionEq(t1.Expr, t2.Expr);\n    }\n\n    internal bool IsTranslatedToFunctionCall() {\n      return (TriggersCollector.TranslateToFunctionCall(this.Expr)) ? true : false;\n    }\n\n  }\n\n  class TriggerCandidate {\n    internal List<TriggerTerm> Terms { get; set; }\n    internal string Annotation { get; set; }\n\n    internal TriggerCandidate(List<TriggerTerm> terms) {\n      this.Terms = terms;\n    }\n\n    public TriggerCandidate(TriggerCandidate candidate) {\n      this.Terms = candidate.Terms;\n    }\n\n    internal bool MentionsAll(List<BoundVar> vars) {\n      return vars.All(x => Terms.Any(term => term.Variables.Contains(x)));\n    }\n\n    internal string Repr { get { return String.Join(\", \", Terms); } }\n\n    public override string ToString() {\n      return \"{\" + Repr + \"}\" + (String.IsNullOrWhiteSpace(Annotation) ? \"\" : \" (\" + Annotation + \")\");\n    }\n\n    internal IEnumerable<TriggerMatch> LoopingSubterms(ComprehensionExpr quantifier) {\n      Contract.Requires(!(quantifier is QuantifierExpr) || ((QuantifierExpr)quantifier).SplitQuantifier == null); // Don't call this on a quantifier with a Split clause: it's not a real quantifier\n      var matchingSubterms = this.MatchingSubterms(quantifier);\n      var boundVars = new HashSet<BoundVar>(quantifier.BoundVars);\n      return matchingSubterms.Where(tm => tm.CouldCauseLoops(Terms, boundVars));\n    }\n\n    internal List<TriggerMatch> MatchingSubterms(ComprehensionExpr quantifier) {\n      Contract.Requires(!(quantifier is QuantifierExpr) || ((QuantifierExpr)quantifier).SplitQuantifier == null); // Don't call this on a quantifier with a Split clause: it's not a real quantifier\n      return Terms.SelectMany(term => quantifier.SubexpressionsMatchingTrigger(term.Expr)).Deduplicate(TriggerMatch.Eq);\n    }\n\n    internal bool IsStrongerThan(TriggerCandidate that) {\n      if (this == that) {\n        return false;\n      }\n\n      var hasStrictlyStrongerTerm = false;\n      foreach (var t in Terms) {\n        var comparison = that.Terms.Select(t.CompareTo).Max();\n\n        // All terms of `this` must be at least as strong as a term of `that`\n        if (comparison == TriggerTerm.TermComparison.NotStronger) { return false; }\n\n        // Did we find a strictly stronger term?\n        hasStrictlyStrongerTerm = hasStrictlyStrongerTerm || comparison == TriggerTerm.TermComparison.Stronger;\n      }\n\n      return hasStrictlyStrongerTerm;\n    }\n  }\n\n  internal class TriggerAnnotation {\n    internal bool IsTriggerKiller;\n    internal ISet<IVariable> Variables;\n    internal readonly List<TriggerTerm> PrivateTerms;\n    internal readonly List<TriggerTerm> ExportedTerms;\n\n    internal TriggerAnnotation(bool IsTriggerKiller, IEnumerable<IVariable> Variables, IEnumerable<TriggerTerm> AllTerms, IEnumerable<TriggerTerm> PrivateTerms = null) {\n      this.IsTriggerKiller = IsTriggerKiller;\n      this.Variables = new HashSet<IVariable>(Variables);\n      this.PrivateTerms = new List<TriggerTerm>(PrivateTerms == null ? Enumerable.Empty<TriggerTerm>() : PrivateTerms);\n      this.ExportedTerms = new List<TriggerTerm>(AllTerms == null ? Enumerable.Empty<TriggerTerm>() : AllTerms.Except(this.PrivateTerms));\n    }\n\n    public override string ToString() {\n      StringBuilder sb = new StringBuilder();\n      string indent = \"  {0}\", nindent = \"\\n  - {0}\", subindent = \"\\n    * {0}\";\n\n      sb.AppendFormat(indent, IsTriggerKiller);\n\n      sb.AppendFormat(nindent, \"Variables:\");\n      foreach (var bv in Variables) {\n        sb.AppendFormat(subindent, bv.Name);\n      }\n\n      sb.AppendFormat(nindent, \"Exported terms:\");\n      foreach (var term in ExportedTerms) {\n        sb.AppendFormat(subindent, term);\n      }\n\n      if (PrivateTerms.Any()) {\n        sb.AppendFormat(nindent, \"Private terms:\");\n        foreach (var term in PrivateTerms) {\n          sb.AppendFormat(subindent, term);\n        }\n      }\n\n      return sb.ToString();\n    }\n  }\n\n  internal class TriggerAnnotationsCache {\n    public readonly Dictionary<Expression, HashSet<OldExpr>> exprsInOldContext;\n    public readonly Dictionary<Expression, TriggerAnnotation> annotations;\n\n    /// <summary>\n    /// For certain operations, the TriggersCollector class needs to know whether\n    /// a particular expression is under an old(...) wrapper. This is in particular\n    /// true for generating trigger terms (but it is not for checking whether something\n    /// is a trigger killer, so passing an empty set here for that case would be fine.\n    /// </summary>\n    public TriggerAnnotationsCache(Dictionary<Expression, HashSet<OldExpr>> exprsInOldContext) {\n      this.exprsInOldContext = exprsInOldContext;\n      annotations = new Dictionary<Expression, TriggerAnnotation>();\n    }\n  }\n\n  internal class TriggersCollector {\n    TriggerAnnotationsCache cache;\n\n    internal TriggersCollector(Dictionary<Expression, HashSet<OldExpr>> exprsInOldContext) {\n      this.cache = new TriggerAnnotationsCache(exprsInOldContext);\n    }\n\n    private T ReduceAnnotatedSubExpressions<T>(Expression expr, T seed, Func<TriggerAnnotation, T> map, Func<T, T, T> reduce) {\n      return expr.SubExpressions.Select(e => map(Annotate(e)))\n                                .Aggregate(seed, (acc, e) => reduce(acc, e));\n    }\n\n    private List<TriggerTerm> CollectExportedCandidates(Expression expr) {\n      return ReduceAnnotatedSubExpressions<List<TriggerTerm>>(expr, new List<TriggerTerm>(), a => a.ExportedTerms, TriggerUtils.MergeAlterFirst);\n    }\n\n    private ISet<IVariable> CollectVariables(Expression expr) {\n      return ReduceAnnotatedSubExpressions(expr, new HashSet<IVariable>(), a => a.Variables, TriggerUtils.MergeAlterFirst);\n    }\n\n    private bool CollectIsKiller(Expression expr) {\n      return ReduceAnnotatedSubExpressions(expr, false, a => a.IsTriggerKiller, (a, b) => a || b);\n    }\n\n    private IEnumerable<TriggerTerm> OnlyPrivateCandidates(List<TriggerTerm> terms, IEnumerable<IVariable> privateVars) {\n      return terms.Where(c => privateVars.Intersect(c.Variables).Any()); //TODO Check perf\n    }\n\n    private TriggerAnnotation Annotate(Expression expr) {\n      TriggerAnnotation cached;\n      if (cache.annotations.TryGetValue(expr, out cached)) {\n        return cached;\n      }\n\n      TriggerAnnotation annotation = null; // TODO: Using ApplySuffix fixes the unresolved members problem in GenericSort\n\n      if (expr is LetExpr) {\n        var le = (LetExpr)expr;\n        if (le.LHSs.All(p => p.Var != null) && le.Exact) {\n          // Inline the let expression before doing trigger selection.\n          annotation = Annotate(Translator.InlineLet(le));\n        }\n      }\n\n      if (annotation == null) {\n        expr.SubExpressions.Iter(e => Annotate(e));\n\n        if (IsPotentialTriggerCandidate(expr)) {\n          annotation = AnnotatePotentialCandidate(expr);\n        } else if (expr is QuantifierExpr) {\n          annotation = AnnotateQuantifier((QuantifierExpr)expr);\n        } else if (expr is LetExpr) {\n          annotation = AnnotateLetExpr((LetExpr)expr);\n        } else if (expr is IdentifierExpr) {\n          annotation = AnnotateIdentifier((IdentifierExpr)expr);\n        } else if (expr is ApplySuffix) {\n          annotation = AnnotateApplySuffix((ApplySuffix)expr);\n        } else if (expr is MatchExpr) {\n          annotation = AnnotateMatchExpr((MatchExpr)expr);\n        } else if (expr is ComprehensionExpr) {\n          annotation = AnnotateComprehensionExpr((ComprehensionExpr)expr);\n        } else if (expr is ConcreteSyntaxExpression ||\n                   expr is LiteralExpr ||\n                   expr is ThisExpr ||\n                   expr is BoxingCastExpr ||\n                   expr is MultiSetFormingExpr ||\n                   expr is SeqConstructionExpr) {\n          annotation = AnnotateOther(expr, false);\n        } else {\n          annotation = AnnotateOther(expr, true);\n        }\n      }\n\n      TriggerUtils.DebugTriggers(\"{0} ({1})\\n{2}\", Printer.ExprToString(expr), expr.GetType(), annotation);\n      cache.annotations[expr] = annotation;\n      return annotation;\n    }\n\n    public static bool IsPotentialTriggerCandidate(Expression expr) {\n      if (expr is FunctionCallExpr ||\n          expr is SeqSelectExpr ||\n          expr is MultiSelectExpr ||\n          expr is MemberSelectExpr ||\n          expr is OldExpr ||\n          expr is ApplyExpr ||\n          expr is DisplayExpression ||\n          expr is DatatypeValue ||\n          TranslateToFunctionCall(expr)) {\n        return true;\n      } else if (expr is BinaryExpr) {\n        var e = (BinaryExpr)expr;\n        if ((e.Op == BinaryExpr.Opcode.NotIn || e.Op == BinaryExpr.Opcode.In) && !(e.E1 is DisplayExpression)) {\n          return true;\n        } else if (e.E0.Type.IsBigOrdinalType &&\n          (e.ResolvedOp == BinaryExpr.ResolvedOpcode.Lt || e.ResolvedOp == BinaryExpr.ResolvedOpcode.LessThanLimit || e.ResolvedOp == BinaryExpr.ResolvedOpcode.Gt)) {\n          return true;\n        } else {\n          return false;\n        }\n      } else if (expr is UnaryOpExpr) {\n        var e = (UnaryOpExpr)expr;\n        return e.Op == UnaryOpExpr.Opcode.Cardinality;  // FIXME || e.Op == UnaryOpExpr.Opcode.Fresh doesn't work, as fresh is a pretty tricky predicate when it's not about datatypes. See translator.cs:10944\n      } else if (expr is ConversionExpr) {\n        var e = (ConversionExpr)expr;\n        return e.ToType.IsBigOrdinalType;\n      } else {\n        return false;\n      }\n    }\n\n    // math operations can be turned into a Boogie-level function as in the\n    // case with /noNLarith.\n    public static bool TranslateToFunctionCall(Expression expr) {\n      if (!(expr is BinaryExpr)) {\n        return false;\n      }\n      BinaryExpr e = (BinaryExpr) expr;\n      bool isReal = e.E0.Type.IsNumericBased(Type.NumericPersuation.Real);\n      switch (e.ResolvedOp) {\n        case BinaryExpr.ResolvedOpcode.Lt:\n        case BinaryExpr.ResolvedOpcode.Le:\n        case BinaryExpr.ResolvedOpcode.Ge:\n        case BinaryExpr.ResolvedOpcode.Gt:\n        case BinaryExpr.ResolvedOpcode.Add:\n        case BinaryExpr.ResolvedOpcode.Sub:\n          if (!isReal && !e.E0.Type.IsBitVectorType && !e.E0.Type.IsBigOrdinalType && ArmadaOptions.O.DisableNLarith) {\n            return true;\n          }\n          break;\n        case BinaryExpr.ResolvedOpcode.Mul:\n        case BinaryExpr.ResolvedOpcode.Div:\n        case BinaryExpr.ResolvedOpcode.Mod:\n          if (!isReal && !e.E0.Type.IsBitVectorType && !e.E0.Type.IsBigOrdinalType) {\n            if (ArmadaOptions.O.DisableNLarith || (ArmadaOptions.O.ArithMode != 0 && ArmadaOptions.O.ArithMode != 3)) {\n              return true;\n            }\n          }\n          break;\n      }\n      return false;\n    }\n    private TriggerAnnotation AnnotatePotentialCandidate(Expression expr) {\n      bool expr_is_killer = false;\n      HashSet<OldExpr> oldExprSet;\n      if (cache.exprsInOldContext.TryGetValue(expr, out oldExprSet)) {\n        // oldExpr has been set to the value found\n      } else {\n        oldExprSet = null;\n      }\n      var new_exprs = TriggerUtils.MaybeWrapInOld(TriggerUtils.PrepareExprForInclusionInTrigger(expr, out expr_is_killer), oldExprSet);\n      // We expect there to be at least one \"new_exprs\".\n      // We also expect that the computation of new_term.Variables, collected_terms, and children_contain_killers will be the\n      // same for each of the \"new_exprs\".\n      // Therefore, we use the values of these variables from the last iteration in the expression that is ultimately returned.\n      TriggerTerm new_term = null;\n      List<TriggerTerm> collected_terms = null;\n      var children_contain_killers = false;\n      foreach (var new_expr in new_exprs) {\n        new_term = new TriggerTerm { Expr = new_expr, OriginalExpr = expr, Variables = CollectVariables(expr) };\n\n        collected_terms = CollectExportedCandidates(expr);\n        children_contain_killers = CollectIsKiller(expr);\n\n        if (!children_contain_killers) {\n          // Add only if the children are not killers; the head has been cleaned up into non-killer form\n          collected_terms.Add(new_term);\n        }\n      }\n      Contract.Assert(new_term != null);  // this checks our assumption that \"new_exprs\" contains at least one value.\n\n      // This new node is a killer if its children were killers, or if it's non-cleaned-up head is a killer\n      return new TriggerAnnotation(children_contain_killers || expr_is_killer, new_term.Variables, collected_terms);\n    }\n\n    private TriggerAnnotation AnnotateApplySuffix(ApplySuffix expr) {\n      // This is a bit tricky. A funcall node is generally meaningful as a trigger candidate,\n      // but when it's part of an ApplySuffix the function call itself may not resolve properly\n      // when the second round of resolving is done after modules are duplicated.\n      // Thus first we annotate expr and create a trigger candidate, and then we remove the\n      // candidate matching its direct subexpression if needed. Note that function calls are not the\n      // only possible child here; there can be DatatypeValue nodes, for example (see vstte2012/Combinators.dfy).\n      var annotation = AnnotatePotentialCandidate(expr);\n      // Comparing by reference is fine here. Using sets could yield a small speedup\n      annotation.ExportedTerms.RemoveAll(term => expr.SubExpressions.Contains(term.Expr));\n      return annotation;\n    }\n\n    private TriggerAnnotation AnnotateQuantifierOrLetExpr(Expression expr, IEnumerable<BoundVar> boundVars) {\n      var terms = CollectExportedCandidates(expr);\n      return new TriggerAnnotation(true, CollectVariables(expr), terms, OnlyPrivateCandidates(terms, boundVars));\n    }\n\n    private TriggerAnnotation AnnotateQuantifier(QuantifierExpr expr) {\n      return AnnotateQuantifierOrLetExpr(expr, expr.BoundVars);\n    }\n\n    private TriggerAnnotation AnnotateLetExpr(LetExpr expr) {\n      return AnnotateQuantifierOrLetExpr(expr, expr.BoundVars);\n    }\n\n    private TriggerAnnotation AnnotateIdentifier(IdentifierExpr expr) {\n      return new TriggerAnnotation(false, Enumerable.Repeat(expr.Var, 1), null);\n    }\n\n    private TriggerAnnotation AnnotateComprehensionExpr(ComprehensionExpr expr) {\n      var terms = CollectExportedCandidates(expr);\n      return new TriggerAnnotation(true, CollectVariables(expr), terms,  OnlyPrivateCandidates(terms, expr.BoundVars));\n    }\n\n    private TriggerAnnotation AnnotateMatchExpr(MatchExpr expr)\n    {\n      var pts = CollectExportedCandidates(expr);\n      // collects that argument boundvar of matchcaseexpr\n      var variables = expr.Cases.Select(e => e.Arguments).\n        Aggregate(new List<BoundVar>(), (acc, e) => TriggerUtils.MergeAlterFirst(acc, e));\n      // remove terms that mentions argument boundvar of matchcaseexpr\n      var terms = new List<TriggerTerm>();\n      foreach (var term in pts) {\n        if (!(variables.All(x => term.Variables.Contains(x)))) {\n          terms.Add(term);\n        }\n      }\n      return new TriggerAnnotation(true, CollectVariables(expr), terms);\n    }\n\n    private TriggerAnnotation AnnotateOther(Expression expr, bool isTriggerKiller) {\n      return new TriggerAnnotation(isTriggerKiller || CollectIsKiller(expr), CollectVariables(expr), CollectExportedCandidates(expr));\n    }\n\n    /// <summary>\n    /// Collect terms in the body of the subexpressions of the argument that look like quantifiers. The results of this function can contain duplicate terms.\n    /// </summary>\n    internal List<TriggerTerm> CollectTriggers(ComprehensionExpr quantifier) {\n      Contract.Requires(!(quantifier is QuantifierExpr) || ((QuantifierExpr)quantifier).SplitQuantifier == null); // Don't call this on a quantifier with a Split clause: it's not a real quantifier\n      // NOTE: We could check for existing trigger attributes and return that instead\n      return Annotate(quantifier).PrivateTerms;\n    }\n\n    internal bool IsTriggerKiller(Expression expr) {\n      return Annotate(expr).IsTriggerKiller;\n    }\n  }\n}\n"
  },
  {
    "path": "Source/Armada/Util.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Diagnostics.Contracts;\n\nusing Microsoft.Boogie;\n\n\nnamespace Microsoft.Armada {\n  public class Util\n  {\n    public static string Comma(IEnumerable<string> l) {\n      return Comma(l, s => s);\n    }\n\n    public static string Comma<T>(IEnumerable<T> l, Func<T, string> f) {\n      return Comma(\",\", l, f);\n    }\n\n    public static string Comma<T>(string comma, IEnumerable<T> l, Func<T,string> f) {\n      Contract.Requires(comma != null);\n      string res = \"\";\n      string c = \"\";\n      foreach(var t in l) {\n        res += c + f(t);\n        c = comma;\n      }\n      return res;\n    }\n\n    public static string Comma(int count, Func<int, string> f) {\n      Contract.Requires(0 <= count);\n      return Comma(\",\", count, f);\n    }\n\n    public static string Comma(string comma, int count, Func<int, string> f) {\n      Contract.Requires(comma != null);\n      Contract.Requires(0 <= count);\n      string res = \"\";\n      string c = \"\";\n      for (int i = 0; i < count; i++) {\n        res += c + f(i);\n        c = comma;\n      }\n      return res;\n    }\n\n    public static string Repeat(string str, int times) {\n      Contract.Requires(times >= 0);\n      Contract.Requires(str != null);\n\n      var ans = \"\";\n      for (var i = 0; i < times; i++) {\n        ans += str;\n      }\n      return ans;\n    }\n\n    public static List<B> Map<A, B>(IEnumerable<A> xs, Func<A, B> f)\n    {\n      List<B> ys = new List<B>();\n      foreach (A x in xs) {\n        ys.Add(f(x));\n      }\n      return ys;\n    }\n\n    public static List<A> Nil<A>() {\n      return new List<A>();\n    }\n\n    public static List<A> Singleton<A>(A x) {\n      return new List<A> { x };\n    }\n\n    public static List<A> Cons<A>(A x, List<A> xs) {\n      return Concat(Singleton(x), xs);\n    }\n\n    public static List<A> Snoc<A>(List<A> xs, A x) {\n      return Concat(xs, Singleton(x));\n    }\n\n    public static List<A> Concat<A>(List<A> xs, List<A> ys) {\n      List<A> cpy = new List<A>(xs);\n      cpy.AddRange(ys);\n      return cpy;\n    }\n\n    public static Dictionary<A,B> Dict<A,B>(IEnumerable<A> xs, IEnumerable<B> ys) {\n      return Dict<A,B>(LinqExtender.Zip(xs, ys));\n    }\n\n    public static Dictionary<A,B> Dict<A,B>(IEnumerable<Tuple<A,B>> xys) {\n      Dictionary<A,B> res = new Dictionary<A,B>();\n      foreach (var p in xys) {\n        res[p.Item1] = p.Item2;\n      }\n      return res;\n    }\n\n    /// <summary>\n    /// Returns s but with all occurrences of '_' removed.\n    /// </summary>\n    public static string RemoveUnderscores(string s) {\n      Contract.Requires(s != null);\n      return s.Replace(\"_\", \"\");\n    }\n\n    /// <summary>\n    /// For \"S\" returns S and false.\n    /// For @\"S\" return S and true.\n    /// Assumes that s has one of these forms.\n    /// </summary>\n    public static string RemoveParsedStringQuotes(string s, out bool isVerbatimString) {\n      Contract.Requires(s != null);\n      var len = s.Length;\n      if (s[0] == '@') {\n        isVerbatimString = true;\n        return s.Substring(2, len - 3);\n      } else {\n        isVerbatimString = false;\n        return s.Substring(1, len - 2);\n      }\n    }\n\n    /// <summary>\n    /// For \"S\" returns S and false.\n    /// For @\"S\" return S and true.\n    /// Assumes that s has one of these forms.\n    /// </summary>\n    public static string RemoveParsedStringQuotesSimple(string s) {\n      if (s == null) {\n        return null;\n      }\n      bool isVerbatimString;\n      return RemoveParsedStringQuotes(s, out isVerbatimString);\n    }\n\n    /// <summary>\n    /// Replaced any escaped characters in s by the actual character that the escaping represents.\n    /// Assumes s to be a well-parsed string.\n    /// </summary>\n    public static string RemoveEscaping(string s, bool isVerbatimString) {\n      Contract.Requires(s != null);\n      var sb = new StringBuilder();\n      UnescapedCharacters(s, isVerbatimString).Iter(ch => sb.Append(ch));\n      return sb.ToString();\n    }\n    /// <summary>\n    /// Returns the characters of the well-parsed string p, replacing any\n    /// escaped characters by the actual characters.\n    /// </summary>\n    public static IEnumerable<char> UnescapedCharacters(string p, bool isVerbatimString) {\n      Contract.Requires(p != null);\n      if (isVerbatimString) {\n        var skipNext = false;\n        foreach (var ch in p) {\n          if (skipNext) {\n            skipNext = false;\n          } else {\n            yield return ch;\n            if (ch == '\"') {\n              skipNext = true;\n            }\n          }\n        }\n      } else {\n        var i = 0;\n        while (i < p.Length) {\n          char special = ' ';  // ' ' indicates not special\n          if (p[i] == '\\\\') {\n            switch (p[i + 1]) {\n              case '\\'': special = '\\''; break;\n              case '\\\"': special = '\\\"'; break;\n              case '\\\\': special = '\\\\'; break;\n              case '0': special = '\\0'; break;\n              case 'n': special = '\\n'; break;\n              case 'r': special = '\\r'; break;\n              case 't': special = '\\t'; break;\n              case 'u':\n                int ch = HexValue(p[i + 2]);\n                ch = 16 * ch + HexValue(p[i + 3]);\n                ch = 16 * ch + HexValue(p[i + 4]);\n                ch = 16 * ch + HexValue(p[i + 5]);\n                yield return (char)ch;\n                i += 6;\n                continue;\n              default:\n                break;\n            }\n          }\n          if (special != ' ') {\n            yield return special;\n            i += 2;\n          } else {\n            yield return p[i];\n            i++;\n          }\n        }\n      }\n    }\n\n    /// <summary>\n    /// Converts a hexadecimal digit to an integer.\n    /// Assumes ch does represent a hexadecimal digit; alphabetic digits can be in either case.\n    /// </summary>\n    public static int HexValue(char ch) {\n      if ('a' <= ch && ch <= 'f') {\n        return ch - 'a' + 10;\n      } else if ('A' <= ch && ch <= 'F') {\n        return ch - 'A' + 10;\n      } else {\n        return ch - '0';\n      }\n    }\n\n    /// <summary>\n    /// Add \"fe\" to \"mod\", if \"performThisDeprecationCheck\" is \"false\".\n    /// Otherwise, first strip \"fe\" of certain easy occurrences of \"this\", and for each one giving a warning about\n    /// that \"this\" is deprecated in modifies clauses of constructors.\n    /// This method may modify \"fe\" and the subexpressions contained within \"fe\".\n    /// </summary>\n    public static void AddFrameExpression(List<FrameExpression> mod, FrameExpression fe, bool performThisDeprecationCheck, Errors errors) {\n      Contract.Requires(mod != null);\n      Contract.Requires(fe != null);\n      Contract.Requires(errors != null);\n      if (performThisDeprecationCheck) {\n        if (fe.E is ThisExpr) {\n          errors.Deprecated(fe.E.tok, \"Constructors and destructors don't need 'this' to be listed in modifies clauses\");\n          return;\n        } else if (fe.E is SetDisplayExpr) {\n          var s = (SetDisplayExpr)fe.E;\n          var deprecated = s.Elements.FindAll(e => e is ThisExpr);\n          if (deprecated.Count != 0) {\n            foreach (var e in deprecated) {\n              errors.Deprecated(e.tok, \"Constructors and destructors don't need 'this' to be listed in modifies clauses\");\n            }\n            s.Elements.RemoveAll(e => e is ThisExpr);\n            if (s.Elements.Count == 0) {\n              return;\n            }\n          }\n        }\n      }\n      mod.Add(fe);\n    }\n\n    /// <summary>\n    /// Class dedicated to traversing the function call graph\n    /// </summary>\n    class FunctionCallFinder : TopDownVisitor<List<Function>> {\n      protected override bool VisitOneExpr(Expression expr, ref List<Function> calls) {\n        if (expr is FunctionCallExpr) {\n          calls.Add(((FunctionCallExpr)expr).Function);\n        }\n        return true;\n      }\n    }\n\n    static Graph<Function> BuildFunctionCallGraph(Microsoft.Armada.Program program) {\n      Graph<Function> functionCallGraph = new Graph<Function>();\n      FunctionCallFinder callFinder = new FunctionCallFinder();\n\n      foreach (var module in program.Modules()) {\n        foreach (var decl in module.TopLevelDecls) {\n          if (decl is ClassDecl) {\n            var c = (ClassDecl)decl;\n            foreach (var member in c.Members) {\n              if (member is Function) {\n                var f = (Function)member;\n\n                List<Function> calls = new List<Function>();\n                foreach (var e in f.Reads) { if (e != null && e.E != null) { callFinder.Visit(e.E, calls); } }\n                foreach (var e in f.Req) { if (e != null) { callFinder.Visit(e, calls); } }\n                foreach (var e in f.Ens) { if (e != null) { callFinder.Visit(e, calls); } }\n                if (f.Body != null) {\n                  callFinder.Visit(f.Body, calls);\n                }\n\n                foreach (var callee in calls) {\n                  functionCallGraph.AddEdge(f, callee);\n                }\n              }\n            }\n          }\n        }\n      }\n\n      return functionCallGraph;\n    }\n\n    /// <summary>\n    /// Prints the program's function call graph in a format suitable for consumption in other tools\n    /// </summary>\n    public static void PrintFunctionCallGraph(Microsoft.Armada.Program program) {\n      var functionCallGraph = BuildFunctionCallGraph(program);\n\n      foreach (var vertex in functionCallGraph.GetVertices()) {\n        var func = vertex.N;\n        Console.Write(\"{0},{1}=\", func.CompileName, func.EnclosingClass.Module.CompileName);\n        foreach (var callee in vertex.Successors) {\n          Console.Write(\"{0} \", callee.N.CompileName);\n        }\n        Console.Write(\"\\n\");\n      }\n    }\n\n    /// <summary>\n    /// Generic statistic counter\n    /// </summary>\n    static void IncrementStat(IDictionary<string, ulong> stats, string stat) {\n      ulong currentValue;\n      if (stats.TryGetValue(stat, out currentValue)) {\n        stats[stat] += 1;\n      } else {\n        stats.Add(stat, 1);\n      }\n    }\n\n    /// <summary>\n    /// Track the maximum value of some statistic\n    /// </summary>\n    static void UpdateMax(IDictionary<string, ulong> stats, string stat, ulong val) {\n      ulong currentValue;\n      if (stats.TryGetValue(stat, out currentValue)) {\n        if (val > currentValue) {\n          stats[stat] = val;\n        }\n      } else {\n        stats.Add(stat, val);\n      }\n    }\n\n    /// <summary>\n    /// Compute various interesting statistics about the Dafny program\n    /// </summary>\n    public static void PrintStats(Microsoft.Armada.Program program) {\n      SortedDictionary<string, ulong> stats = new SortedDictionary<string, ulong>();\n\n      foreach (var module in program.Modules()) {\n        IncrementStat(stats, \"Modules\");\n        UpdateMax(stats, \"Module height (max)\", (ulong)module.Height);\n\n        ulong num_scc = (ulong)module.CallGraph.TopologicallySortedComponents().Count;\n        UpdateMax(stats, \"Call graph width (max)\", num_scc);\n\n        foreach (var decl in module.TopLevelDecls) {\n          if (decl is DatatypeDecl) {\n            IncrementStat(stats, \"Datatypes\");\n          } else if (decl is ClassDecl) {\n            var c = (ClassDecl)decl;\n            if (c.Name != \"_default\") {\n              IncrementStat(stats, \"Classes\");\n            }\n\n            foreach (var member in c.Members) {\n              if (member is Function) {\n                IncrementStat(stats, \"Functions (total)\");\n                var f = (Function)member;\n                if (f.IsRecursive) {\n                  IncrementStat(stats, \"Functions recursive\");\n                }\n              } else if (member is Method) {\n                IncrementStat(stats, \"Methods (total)\");\n                var method = (Method)member;\n                if (method.IsRecursive) {\n                  IncrementStat(stats, \"Methods recursive\");\n                }\n                if (method.IsGhost) {\n                  IncrementStat(stats, \"Methods ghost\");\n                }\n              }\n            }\n          }\n        }\n      }\n\n      // Print out the results, with some nice formatting\n      Console.WriteLine(\"\");\n      Console.WriteLine(\"Statistics\");\n      Console.WriteLine(\"----------\");\n\n      int max_key_length = 0;\n      foreach (var key in stats.Keys) {\n        if (key.Length > max_key_length) {\n          max_key_length = key.Length;\n        }\n      }\n\n      foreach (var keypair in stats) {\n        string keyString = keypair.Key.PadRight(max_key_length + 2);\n        Console.WriteLine(\"{0} {1,4}\", keyString, keypair.Value);\n      }\n    }\n  }\n\n  public class DependencyMap\n  {\n    private Dictionary<string, SortedSet<string>> dependencies;\n\n    public DependencyMap() {\n      dependencies = new Dictionary<string, SortedSet<string>>();\n    }\n\n    public void AddInclude(Include include) {\n      SortedSet<string> existingDependencies = null;\n      string key = include.includerFilename == null ? \"roots\" : include.includerFilename;\n      bool found = dependencies.TryGetValue(key, out existingDependencies);\n      if (found) {\n        existingDependencies.Add(include.includedFullPath);\n      } else {\n        dependencies[key] = new SortedSet<string>() { include.includedFullPath };\n      }\n    }\n\n    public void AddIncludes(IEnumerable<Include> includes) {\n      // Reconstruct the dependency map\n      Dictionary<string, List<string>> dependencies = new Dictionary<string, List<string>>();\n      foreach (Include include in includes) {\n        AddInclude(include);\n      }\n    }\n\n    public void PrintMap() {\n      SortedSet<string> leaves = new SortedSet<string>(); // Files that don't themselves include any files\n      foreach (string target in dependencies.Keys) {\n        System.Console.Write(target);\n        foreach (string dependency in dependencies[target]) {\n          System.Console.Write(\";\" + dependency);\n          if (!dependencies.ContainsKey(dependency)) {\n            leaves.Add(dependency);\n          }\n        }\n        System.Console.WriteLine();\n      }\n      foreach (string leaf in leaves) {\n        System.Console.WriteLine(leaf);\n      }\n    }\n  }\n\n  public class DisjointSet\n  {\n    private int[] parent;\n\n    public DisjointSet(int size)\n    {\n      parent = new int[size];\n      for (int i = 0; i < size; i++) {\n        parent[i] = i;\n      }\n    }\n\n    public int Find(int a)\n    {\n      if (parent[a] == a) {\n        return a;\n      }\n      else {\n        int p = Find(parent[a]);\n        parent[a] = p;\n        return p;\n      }\n    }\n\n    public void Join(int a, int b)\n    {\n      int pa = Find(a);\n      int pb = Find(b);\n\n      parent[pa] = pb;\n    }\n  }\n}\n"
  },
  {
    "path": "Source/Armada/VarHiding.cs",
    "content": "using System;\nusing System.Numerics;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text;\nusing System.Text.RegularExpressions;\nusing static Microsoft.Armada.Predicate;\nusing IToken = Microsoft.Boogie.IToken;\nusing Token = Microsoft.Boogie.Token;\n\nnamespace Microsoft.Armada {\n\n  public abstract class VarHidingProofGenerator : AbstractProofGenerator\n  {\n    protected bool canHideTau;\n\n    public VarHidingProofGenerator(ProofGenerationParams i_pgp, bool i_canHideTau)\n      : base(i_pgp, true)\n    {\n      canHideTau = i_canHideTau;\n    }\n\n    public override void GenerateProof()\n    {\n      if (!CheckEquivalence()) {\n        AH.PrintError(pgp.prog, \"Levels {pgp.mLow.Name} and {pgp.mHigh.Name} aren't sufficiently equivalent to perform refinement proof generation using the variable-hiding strategy\");\n        return;\n      }\n\n      AddIncludesAndImports();\n\n      GenerateVarHidingPCMap();\n      ExtendPCMapWithExternalAndStructsMethods();\n      GenerateNextRoutineMap(false); // Don't warn on missing next routines, since some low-level routines don't map to high-level ones\n      GenerateProofGivenMap();\n    }\n\n    protected void GenerateProofGivenMap()\n    {\n      GenerateProofHeader();\n      GenerateAtomicSpecs(false);\n      GenerateStateAbstractionFunctions_LH();\n      GenerateConvertStep_LH();\n      GenerateInvariantProof(pgp);\n      GenerateLocalViewCommutativityLemmas();\n      GenerateConvertAtomicPath_LH();\n      GenerateEstablishInitRequirementsLemma();\n      GenerateEstablishStateOKRequirementLemma();\n      GenerateEstablishRelationRequirementLemma();\n      GenerateLiftingRelation();\n      GenerateLiftAtomicPathLemmas(\n        \"HAtomic_GetPathType(hpath) == ty\",\n        \"requires !IsSkippedPath(ls, lpath, tid)\",\n        canHideTau ? \"lemma_AppendingHiddenStoreBufferEntryAlwaysDoesntAffectHighLevel(tid);\" : \"\"\n      );\n      GenerateSkippablePathsLiftableLemma();\n      GenerateEstablishAtomicPathLiftableLemma();\n      GenerateEstablishAtomicPathsLiftableLemma(true, false);\n      GenerateLiftLAtomicToHAtomicLemma(true, false);\n      GenerateFinalProof();\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    /// Includes and imports\n    ////////////////////////////////////////////////////////////////////////\n\n    protected override void AddIncludesAndImports()\n    {\n      base.AddIncludesAndImports();\n\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/option.s.dfy\");\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/seqs.s.dfy\");\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/seqs.i.dfy\");\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/sets.i.dfy\");\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/maps.i.dfy\");\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/strategies/generic/GenericArmadaLemmas.i.dfy\");\n\n      pgp.MainProof.AddImport(\"InvariantsModule\");\n      pgp.MainProof.AddImport(\"util_option_s\");\n      pgp.MainProof.AddImport(\"util_collections_seqs_s\");\n      pgp.MainProof.AddImport(\"util_collections_seqs_i\");\n      pgp.MainProof.AddImport(\"util_collections_sets_i\");\n      pgp.MainProof.AddImport(\"util_collections_maps_i\");\n      pgp.MainProof.AddImport(\"GenericArmadaLemmasModule\");\n\n      pgp.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/option.s.dfy\", \"convert\");\n      pgp.AddImport(\"util_option_s\", null, \"convert\");\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    // PC mapping\n    ////////////////////////////////////////////////////////////////////////\n\n    protected abstract bool IsVariableHidden(string methodName, string varName);\n\n    private bool IsHiddenStatement(string methodName, ArmadaStatement stmt)\n    {\n      if (stmt is ArmadaUpdateStatement aus) {\n        var us = (UpdateStmt)aus.Stmt;\n        return us.Lhss.All(lhs => IsVariableHidden(methodName, AH.GetLValueRootVariable(lhs)));\n      }\n      else if (stmt is ArmadaSomehowStatement ashs) {\n        var shs = (SomehowStmt)ashs.Stmt;\n        return shs.Mod.Expressions.Any() &&\n               shs.Mod.Expressions.All(lhs => IsVariableHidden(methodName, AH.GetLValueRootVariable(lhs)));\n      }\n      else if (stmt is ArmadaVarDeclStatement avds) {\n        var vds = (VarDeclStmt)avds.Stmt;\n        return vds.Locals.All(v => IsVariableHidden(methodName, v.Name));\n      }\n\n      return false;\n    }\n\n    private void GenerateVarHidingPCMapForBlocks(string methodName, ArmadaStatement blockLow, ArmadaStatement blockHigh)\n    {\n      if (blockLow == null) {\n        return;\n      }\n\n      if (blockHigh == null) {\n        AH.PrintError(pgp.prog, $\"No block in high level corresponding to block at {AH.TokenToString(blockLow.Stmt.Tok)} in low level.\");\n        return;\n      }\n\n      var pcLow = blockLow.StartPC;\n      var pcHigh = blockHigh.StartPC;\n      pcMap[pcLow] = pcHigh;\n\n      var stmtsHigh = blockHigh.GetStatementsInBody().ToArray();\n\n      int whichStmtHigh = 0;\n      foreach (var stmtLow in blockLow.GetStatementsInBody()) {\n\n        if (IsHiddenStatement(methodName, stmtLow)) {\n          pcMap[stmtLow.EndPC] = pcHigh;\n          continue;\n        }\n\n        if (whichStmtHigh >= stmtsHigh.Length) {\n          AH.PrintError(pgp.prog, $\"Could not figure out how the low-level statement at {AH.TokenToString(stmtLow.Stmt.Tok)} is a hidden-variable assignment, but it doesn't seem to correspond to any high-level statement.\");\n          pcMap[stmtLow.EndPC] = pcHigh;\n          continue;\n        }\n\n        var stmtHigh = stmtsHigh[whichStmtHigh];\n        if (stmtLow.RoughlyMatches(stmtHigh)) {\n          if (stmtLow is ArmadaIfStatement ifLow) {\n            var ifHigh = (ArmadaIfStatement)stmtHigh;\n            GenerateVarHidingPCMapForBlocks(methodName, ifLow.ThenClause, ifHigh.ThenClause);\n            GenerateVarHidingPCMapForBlocks(methodName, ifLow.ElseClause, ifHigh.ElseClause);\n          }\n          else if (stmtLow is ArmadaWhileStatement whileLow) {\n            var whileHigh = (ArmadaWhileStatement)stmtHigh;\n            GenerateVarHidingPCMapForBlocks(methodName, whileLow.Body, whileHigh.Body);\n          }\n        }\n        else {\n          AH.PrintError(pgp.prog, $\"Could not figure out how the low-level statement at {AH.TokenToString(stmtLow.Stmt.Tok)} correponds to the high-level statement at {AH.TokenToString(stmtHigh.Stmt.Tok)}.\");\n        }\n\n        pcHigh = stmtHigh.EndPC;\n        pcMap[stmtLow.EndPC] = pcHigh;\n        ++whichStmtHigh;\n      }\n    }\n\n    private void GenerateVarHidingPCMapForMethod(string methodName)\n    {\n      if (!pgp.symbolsHigh.DoesMethodNameExist(methodName)) {\n        AH.PrintError(pgp.prog, $\"There's a method named {methodName} in the low level but not the high level.\");\n        return;\n      }\n\n      var bodyLow = pgp.symbolsLow.AllMethods.LookupMethod(methodName).ParsedBody;\n      var bodyHigh = pgp.symbolsHigh.AllMethods.LookupMethod(methodName).ParsedBody;\n\n      GenerateVarHidingPCMapForBlocks(methodName, bodyLow, bodyHigh);\n    }\n\n    private void GenerateVarHidingPCMap()\n    {\n      pcMap = new Dictionary<ArmadaPC, ArmadaPC>();\n\n      foreach (var methodName in pgp.symbolsLow.MethodNames) {\n        var st = pgp.symbolsLow.GetMethodSymbolTable(methodName);\n        if (!st.IsExternal && !st.IsFromStructsModule) {\n          GenerateVarHidingPCMapForMethod(methodName);\n        }\n      }\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    /// Lifting lemmas\n    ////////////////////////////////////////////////////////////////////////\n\n    private bool IsSuppressedNextRoutine(NextRoutine nextRoutine)\n    {\n      return nextRoutine.nextType is NextType.Update && pcMap[nextRoutine.stmt.Parsed.StartPC] == pcMap[nextRoutine.stmt.Parsed.EndPC];\n    }\n\n    protected override string GetStepCaseForNextRoutine_LH(NextRoutine nextRoutine)\n    {\n      if (IsSuppressedNextRoutine(nextRoutine)) {\n        // This is the case of an update statement that gets suppressed because it only updates hidden variables.\n        return GetStepCaseForSuppressedNextRoutine_LH(nextRoutine);\n      }\n      else {\n        return GetStepCaseForNormalNextRoutine_LH(nextRoutine);\n      }\n    }\n\n    private void GenerateSkippablePathsLiftableLemma()\n    {\n      string str;\n\n      string finalCases = \"\";\n\n      var lpr = new PrefixedVarsPathPrinter(lAtomic);\n\n      if (canHideTau) {\n        str = $@\"\n          lemma lemma_SkippablePathLiftable_Tau(ls: LPlusState, ls': LPlusState, lpath: LAtomic_Path, tid: Armada_ThreadHandle)\n            requires InductiveInv(ls)\n            requires LAtomic_NextPath(ls, ls', lpath, tid)\n            requires lpath.LAtomic_Path_Tau?\n            requires IsSkippedTauPath(ls, lpath, tid)\n            ensures  ConvertTotalState_LPlusH(ls) == ConvertTotalState_LPlusH(ls')\n            ensures  ls'.s.stop_reason.Armada_NotStopped?\n          {{\n            { lpr.GetOpenValidPathInvocation(lAtomic.TauPath) }\n  \n            var hs := ConvertTotalState_LPlusH(ls);\n            var hs' := ConvertTotalState_LPlusH(ls');\n            var lentry := ls.s.threads[tid].storeBuffer[0];\n            ProofCustomizationGoesHere();\n            assert !CanConvertStoreBufferEntry_LH(lentry);\n            assert hs'.threads[tid].storeBuffer == hs.threads[tid].storeBuffer;\n            assert hs'.threads[tid] == hs.threads[tid];\n            assert hs'.threads == hs.threads;\n            assert hs'.stop_reason == hs.stop_reason;\n            assert hs' == hs;\n          }}\n        \";\n        pgp.AddLemma(str, \"lift\");\n        finalCases += \"    case LAtomic_Path_Tau(_) => lemma_SkippablePathLiftable_Tau(ls, ls', lpath, tid);\\n\";\n      }\n      else {\n        finalCases += \"    case LAtomic_Path_Tau(_) => assert false;\\n\";\n      }\n\n      var extraProof = canHideTau ? \"lemma_AppendingHiddenStoreBufferEntryAlwaysDoesntAffectHighLevel(tid);\" : \"\";\n\n      foreach (var atomicPath in lAtomic.AtomicPaths.Where(ap => !pathMap.ContainsKey(ap))) {\n        var name = atomicPath.Name;\n\n        str = $@\"\n          lemma lemma_SkippablePathLiftable_{name}(ls: LPlusState, ls': LPlusState, lpath: LAtomic_Path, tid: Armada_ThreadHandle)\n            requires InductiveInv(ls)\n            requires LAtomic_NextPath(ls, ls', lpath, tid)\n            requires lpath.LAtomic_Path_{name}?\n            ensures  ConvertTotalState_LPlusH(ls) == ConvertTotalState_LPlusH(ls')\n            ensures  ls'.s.stop_reason.Armada_NotStopped?\n          {{\n            { lpr.GetOpenValidPathInvocation(atomicPath) }\n\n            var hs := ConvertTotalState_LPlusH(ls);\n            var hs' := ConvertTotalState_LPlusH(ls');\n            { extraProof }\n            ProofCustomizationGoesHere();\n            assert hs'.stop_reason == hs.stop_reason;\n            if tid in hs'.threads {{\n              assert hs'.threads[tid] == hs.threads[tid];\n            }}\n            assert hs'.threads == hs.threads;\n            assert hs'.mem == hs.mem;\n            assert hs' == hs;\n          }}\n        \";\n        pgp.AddLemma(str, \"lift\");\n        finalCases += $\"    case LAtomic_Path_{name}(_) => lemma_SkippablePathLiftable_{name}(ls, ls', lpath, tid);\\n\";\n      }\n\n      str = $@\"\n        lemma lemma_SkippablePathLiftable(ls: LPlusState, ls': LPlusState, lpath: LAtomic_Path, tid: Armada_ThreadHandle)\n          requires InductiveInv(ls)\n          requires LAtomic_NextPath(ls, ls', lpath, tid)\n          requires IsSkippedPath(ls, lpath, tid)\n          ensures  ConvertTotalState_LPlusH(ls) == ConvertTotalState_LPlusH(ls')\n          ensures  ls'.s.stop_reason.Armada_NotStopped?\n        {{\n          match lpath {{\n            { finalCases }\n          }}\n        }}\n      \";\n      pgp.AddLemma(str, \"lift\");\n    }\n\n    protected override void GenerateLiftAtomicPathLemmaForTauPath(AtomicPath atomicPath, string typeComparison,\n                                                                  string extraSignatureLines)\n    {\n      if (!canHideTau) {\n        base.GenerateLiftAtomicPathLemmaForTauPath(atomicPath, typeComparison, extraSignatureLines);\n        return;\n      }\n\n      var lpr = new PrefixedVarsPathPrinter(lAtomic);\n      var hpr = new PrefixedVarsPathPrinter(hAtomic);\n\n      string str = $@\"\n        lemma lemma_LiftAtomicPath_Tau(ls: LPlusState, lpath: LAtomic_Path, tid: Armada_ThreadHandle)\n          requires InductiveInv(ls)\n          requires LAtomic_ValidPath(ls, lpath, tid)\n          requires lpath.LAtomic_Path_Tau?\n          requires !IsSkippedTauPath(ls, lpath, tid)\n          ensures  var ls' := LAtomic_GetStateAfterPath(ls, lpath, tid);\n                   var hs := ConvertTotalState_LPlusH(ls);\n                   var hpath := ConvertAtomicPath_LH(ls, lpath, tid);\n                   var hs' := HAtomic_GetStateAfterPath(hs, hpath, tid);\n                   var ty := LAtomic_GetPathType(lpath);\n                   && HAtomic_GetPathType(hpath) == ty\n                   && HAtomic_ValidPath(hs, hpath, tid)\n                   && hs' == ConvertTotalState_LPlusH(ls')\n                   && ls'.s.stop_reason.Armada_NotStopped? == hs'.stop_reason.Armada_NotStopped?\n        {{\n          { lpr.GetOpenValidPathInvocation(lAtomic.TauPath) }\n\n          var ls' := LAtomic_GetStateAfterPath(ls, lpath, tid);\n          var hs := ConvertTotalState_LPlusH(ls);\n          var hpath := ConvertAtomicPath_LH(ls, lpath, tid);\n          var hs' := ConvertTotalState_LPlusH(ls');\n\n          { hpr.GetOpenPathInvocation(hAtomic.TauPath) }\n\n          var lentry := ls.s.threads[tid].storeBuffer[0];\n          assert CanConvertStoreBufferEntry_LH(lentry);\n          var hentry := hs.threads[tid].storeBuffer[0];\n          var lmem := ls.s.mem;\n          var hmem1 := ConvertSharedMemory_LH(L.Armada_ApplyStoreBufferEntry(lmem, lentry));\n          var hmem2 := H.Armada_ApplyStoreBufferEntry(ConvertSharedMemory_LH(lmem), hentry);\n          lemma_ApplyStoreBufferEntryCommutesWithConvert(lmem, lentry, hentry, hmem1, hmem2);\n\n          var alt_hs' := HAtomic_GetStateAfterPath(hs, hpath, tid);\n          ProofCustomizationGoesHere();\n\n          assert hs'.threads[tid] == alt_hs'.threads[tid];\n          assert hs'.threads == alt_hs'.threads;\n          assert hs' == alt_hs';\n\n          /* { hpr.GetAssertValidPathInvocation(hAtomic.TauPath) } */\n        }}\n      \";\n      pgp.AddLemma(str, \"lift\");\n    }\n\n    protected override void GenerateEstablishAtomicPathLiftableLemma()\n    {\n      string str = @\"\n        lemma lemma_EstablishAtomicPathLiftable(\n          lasf:AtomicSpecFunctions<LPlusState, LAtomic_Path, L.Armada_PC>,\n          hasf:AtomicSpecFunctions<HState, HAtomic_Path, H.Armada_PC>,\n          ls: LPlusState,\n          lpath: LAtomic_Path,\n          tid: Armada_ThreadHandle,\n          hs: HState\n          ) returns (\n          hpath: HAtomic_Path\n          )\n          requires lasf == LAtomic_GetSpecFunctions()\n          requires hasf == HAtomic_GetSpecFunctions()\n          requires InductiveInv(ls)\n          requires LiftingRelation(ls, hs)\n          requires LAtomic_ValidPath(ls, lpath, tid)\n          requires !AtomicPathSkippable(lasf, InductiveInv, LiftingRelation, ls, lpath, tid, hs)\n          ensures  LiftAtomicPathSuccessful(lasf, hasf, InductiveInv, LiftingRelation, ls, lpath, tid, hs, hpath)\n        {\n          var inv := InductiveInv;\n          var relation := LiftingRelation;\n          var ls' := lasf.path_next(ls, lpath, tid);\n          if IsSkippedPath(ls, lpath, tid) {\n            lemma_SkippablePathLiftable(ls, ls', lpath, tid);\n            lemma_AtomicPathMaintainsInductiveInv(ls, ls', lpath, tid);\n            assert AtomicPathSkippable(lasf, inv, relation, ls, lpath, tid, hs);\n            assert false;\n          }\n          else {\n            var ls' := LAtomic_GetStateAfterPath(ls, lpath, tid);\n            lemma_AtomicPathMaintainsInductiveInv(ls, ls', lpath, tid);\n            assert inv(ls');\n            hpath := ConvertAtomicPath_LH(ls, lpath, tid);\n            lemma_LiftAtomicPath(ls, lpath, tid);\n            assert LiftAtomicPathSuccessful(lasf, hasf, inv, relation, ls, lpath, tid, hs, hpath);\n          }\n        }\n      \";\n      pgp.AddLemma(str);\n    }\n  }\n\n}\n"
  },
  {
    "path": "Source/Armada/VarIntro.cs",
    "content": "using System.Collections.Generic;\nusing System.Linq;\nusing System;\n\nnamespace Microsoft.Armada\n{\n  public abstract class VarIntroProofGenerator : AbstractProofGenerator\n  {\n    protected bool canIntroduceTau;\n    protected Dictionary<ArmadaPC, ArmadaPC> reversePCMap;\n    protected Dictionary<NextRoutine, NextRoutine> reverseNextRoutineMap;\n    protected Dictionary<AtomicPath, AtomicPath> reverseAtomicPathMap;\n    protected Dictionary<ArmadaPC, List<AtomicPath>> pcToIntroducedPaths;\n\n    public VarIntroProofGenerator(ProofGenerationParams i_pgp, bool i_canIntroduceTau) : base(i_pgp)\n    {\n      canIntroduceTau = i_canIntroduceTau;\n    }\n\n    public override void GenerateProof()\n    {\n      if (!CheckEquivalence()) {\n        AH.PrintError(pgp.prog, \"Levels {pgp.mLow.Name} and {pgp.mHigh.Name} aren't sufficiently equivalent to perform refinement proof generation using the variable-introduction strategy\");\n        return;\n      }\n\n      GenerateVarIntroReversePCMap();\n      GeneratePCMapFromReversePCMap();\n\n      if (!CheckAllIntroducedAreUpdates()) {\n        AH.PrintError(pgp.prog, \"Higher level introduced non-update instructions, which is not supported\");\n        return;\n      }\n\n      AddIncludesAndImports();\n      GenerateNextRoutineMap();\n      GenerateReverseNextRoutineMap();\n\n      GenerateProofGivenMap();\n    }\n\n    protected override void AddIncludesAndImports()\n    {\n      base.AddIncludesAndImports();\n\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/strategies/generic/GenericArmadaLemmas.i.dfy\");\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/option.s.dfy\");\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/seqs.s.dfy\");\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/seqs.i.dfy\");\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/sets.i.dfy\");\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/maps.i.dfy\");\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/MapSum.i.dfy\");\n\n      pgp.MainProof.AddImport(\"InvariantsModule\");\n      pgp.MainProof.AddImport(\"util_option_s\");\n      pgp.MainProof.AddImport(\"util_collections_seqs_s\");\n      pgp.MainProof.AddImport(\"util_collections_seqs_i\");\n      pgp.MainProof.AddImport(\"util_collections_sets_i\");\n      pgp.MainProof.AddImport(\"util_collections_maps_i\");\n      pgp.MainProof.AddImport(\"util_collections_MapSum_i\");\n      pgp.MainProof.AddImport(\"GenericArmadaLemmasModule\");\n\n      pgp.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/option.s.dfy\", \"convert\");\n      pgp.AddImport(\"util_option_s\", null, \"convert\");\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    // PC mapping\n    ////////////////////////////////////////////////////////////////////////\n\n    protected abstract bool IsIntroducedVariable(string methodName, string varName);\n\n    private bool IsIntroducedStatement(string methodName, ArmadaStatement stmt)\n    {\n      if (stmt is ArmadaUpdateStatement aus) {\n        var us = (UpdateStmt)aus.Stmt;\n        return us.Lhss.All(lhs => IsIntroducedVariable(methodName, AH.GetLValueRootVariable(lhs)));\n      }\n      else if (stmt is ArmadaSomehowStatement ashs) {\n        var shs = (SomehowStmt)ashs.Stmt;\n        return shs.Mod.Expressions.Any() && shs.Mod.Expressions.All(lhs => IsIntroducedVariable(methodName, AH.GetLValueRootVariable(lhs)));\n      }\n      else if (stmt is ArmadaVarDeclStatement avds) {\n        var vds = (VarDeclStmt)avds.Stmt;\n        return vds.Locals.All(v => IsIntroducedVariable(methodName, v.Name));\n      }\n\n      return false;\n    }\n\n    private void GenerateVarIntroReversePCMapForBlocks(string methodName, ArmadaStatement blockLow, ArmadaStatement blockHigh)\n    {\n      if (blockHigh == null) {\n        return;\n      }\n\n      if (blockLow == null) {\n        AH.PrintError(pgp.prog, $\"No block in low level corresponding to block at {AH.TokenToString(blockHigh.Stmt.Tok)} in high level.\");\n        return;\n      }\n\n      var pcLow = blockLow.StartPC;\n      var pcHigh = blockHigh.StartPC;\n      reversePCMap[pcHigh] = pcLow;\n\n      var stmtsLow = blockLow.GetStatementsInBody().ToArray();\n\n      int whichStmtLow = 0;\n      foreach (var stmtHigh in blockHigh.GetStatementsInBody()) {\n\n        if (IsIntroducedStatement(methodName, stmtHigh)) {\n          reversePCMap[stmtHigh.EndPC] = pcLow;\n          continue;\n        }\n\n        if (whichStmtLow >= stmtsLow.Length) {\n          AH.PrintError(pgp.prog, $\"Could not figure out how the high-level statement at {AH.TokenToString(stmtHigh.Stmt.Tok)} is an introduced-variable assignment, but it doesn't seem to correspond to any low-level statement.\");\n          reversePCMap[stmtHigh.EndPC] = pcLow;\n          continue;\n        }\n\n        var stmtLow = stmtsLow[whichStmtLow];\n        if (stmtLow.RoughlyMatches(stmtHigh)) {\n          if (stmtLow is ArmadaIfStatement ifLow) {\n            var ifHigh = (ArmadaIfStatement)stmtHigh;\n            GenerateVarIntroReversePCMapForBlocks(methodName, ifLow.ThenClause, ifHigh.ThenClause);\n            GenerateVarIntroReversePCMapForBlocks(methodName, ifLow.ElseClause, ifHigh.ElseClause);\n          }\n          else if (stmtLow is ArmadaWhileStatement whileLow) {\n            var whileHigh = (ArmadaWhileStatement)stmtHigh;\n            GenerateVarIntroReversePCMapForBlocks(methodName, whileLow.Body, whileHigh.Body);\n          }\n        }\n        else {\n          AH.PrintError(pgp.prog, $\"Could not figure out how the low-level statement at {AH.TokenToString(stmtLow.Stmt.Tok)} correponds to the high-level statement at {AH.TokenToString(stmtHigh.Stmt.Tok)}.\");\n        }\n\n        pcLow = stmtLow.EndPC;\n        reversePCMap[stmtHigh.EndPC] = pcLow;\n        ++whichStmtLow;\n      }\n    }\n\n    private void GenerateVarIntroReversePCMapForMethod(string methodName)\n    {\n      if (!pgp.symbolsLow.DoesMethodNameExist(methodName)) {\n        AH.PrintError(pgp.prog, $\"There's a method named {methodName} in the high level but not the low level.\");\n        return;\n      }\n\n      var bodyLow = pgp.symbolsLow.AllMethods.LookupMethod(methodName).ParsedBody;\n      var bodyHigh = pgp.symbolsHigh.AllMethods.LookupMethod(methodName).ParsedBody;\n\n      GenerateVarIntroReversePCMapForBlocks(methodName, bodyLow, bodyHigh);\n    }\n\n    private void GenerateVarIntroReversePCMap()\n    {\n      reversePCMap = new Dictionary<ArmadaPC, ArmadaPC>();\n\n      foreach (var methodName in pgp.symbolsHigh.MethodNames) {\n        var st = pgp.symbolsHigh.GetMethodSymbolTable(methodName);\n        if (st.IsExternal || st.IsFromStructsModule) {\n          List<ArmadaPC> allPCs = new List<ArmadaPC>();\n          pgp.symbolsHigh.AllMethods.LookupMethod(methodName).AppendAllPCs(allPCs);\n          foreach (var pc in allPCs) {\n            reversePCMap[pc] = pc.CloneWithNewSymbolTable(pgp.symbolsLow);\n          }\n        }\n        else {\n          GenerateVarIntroReversePCMapForMethod(methodName);\n        }\n      }\n    }\n\n    private void GeneratePCMapFromReversePCMap()\n    {\n      pcMap = new Dictionary<ArmadaPC, ArmadaPC>();\n\n      foreach (var entry in reversePCMap) {\n        if (!pcMap.ContainsKey(entry.Value)) {\n          pcMap[entry.Value] = entry.Key;\n        }\n      }\n    }\n\n    private ArmadaPC LowerPC(ArmadaPC pc)\n    {\n      if (pc == null) {\n        return null;\n      }\n      return reversePCMap[pc];\n    }\n\n    protected override void GenerateNextRoutineMap(bool warnOnMissingRoutines = true)\n    {\n      nextRoutineMap = new Dictionary<NextRoutine, NextRoutine>();\n      var hmap = new Dictionary<Tuple<ArmadaPC, ArmadaPC, bool, bool>, NextRoutine>();\n      foreach (var nextRoutine in pgp.symbolsHigh.NextRoutines) {\n        var startPC = LowerPC(nextRoutine.startPC);\n        var endPC = LowerPC(nextRoutine.endPC);\n        var t = new Tuple<ArmadaPC, ArmadaPC, bool, bool>(startPC, endPC, nextRoutine.UndefinedBehavior,\n                                                          nextRoutine.BranchOutcome);\n\n        // If more than one high-level next routine maps to the same low-level startPC/endPC combination,\n        // use the one earlier in its method.\n        \n        if (!hmap.ContainsKey(t) || nextRoutine.startPC.instructionCount < hmap[t].startPC.instructionCount) {\n          hmap[t] = nextRoutine;\n        }\n      }\n\n      foreach (var nextRoutine in pgp.symbolsLow.NextRoutines) {\n        var t = new Tuple<ArmadaPC, ArmadaPC, bool, bool>(nextRoutine.startPC, nextRoutine.endPC, nextRoutine.UndefinedBehavior,\n                                                          nextRoutine.BranchOutcome);\n        if (hmap.ContainsKey(t)) {\n          nextRoutineMap[nextRoutine] = hmap[t];\n        }\n        else if (warnOnMissingRoutines) {\n          AH.PrintWarning(pgp.prog, $\"No next routine found in high level from {nextRoutine.startPC} to {nextRoutine.endPC}\");\n        }\n      }\n    }\n\n    protected void GenerateReverseNextRoutineMap()\n    {\n      reverseNextRoutineMap = new Dictionary<NextRoutine, NextRoutine>();\n      var hmap = new Dictionary<Tuple<ArmadaPC, ArmadaPC, bool, bool>, NextRoutine>();\n      foreach (var nextRoutine in pgp.symbolsLow.NextRoutines) {\n        var t = new Tuple<ArmadaPC, ArmadaPC, bool, bool>(nextRoutine.startPC, nextRoutine.endPC, nextRoutine.UndefinedBehavior,\n                                                          nextRoutine.BranchOutcome);\n        if (hmap.ContainsKey(t)) {\n          AH.PrintError(pgp.prog,\n                        $\"More than one next routine from PC {nextRoutine.startPC} to {nextRoutine.endPC} in level {pgp.mLow.Name}\");\n          hmap.Remove(t);\n        }\n        else {\n          hmap[t] = nextRoutine;\n        }\n      }\n\n      foreach (var nextRoutine in pgp.symbolsHigh.NextRoutines) {\n        var startPC = LowerPC(nextRoutine.startPC);\n        var endPC = LowerPC(nextRoutine.endPC);\n        var t = new Tuple<ArmadaPC, ArmadaPC, bool, bool>(startPC, endPC, nextRoutine.UndefinedBehavior, nextRoutine.BranchOutcome);\n        if (hmap.ContainsKey(t)) {\n          reverseNextRoutineMap[nextRoutine] = hmap[t];\n        }\n      }\n    }\n\n    protected void GenerateReverseAtomicPathMap()\n    {\n      reverseAtomicPathMap = hAtomic.CreatePathMap(lAtomic, reverseNextRoutineMap);\n    }\n\n    protected void RegenerateAtomicPathMap()\n    {\n      pathMap = new Dictionary<AtomicPath, AtomicPath>();\n      foreach (var entry in reverseAtomicPathMap)\n      {\n        pathMap[entry.Value] = entry.Key;\n      }\n    }\n\n    protected void GeneratePCToIntroducedPathsMap()\n    {\n      pcToIntroducedPaths = new Dictionary<ArmadaPC, List<AtomicPath>>();\n\n      foreach (var hAtomicPath in hAtomic.AtomicPaths.Where(ap => !ap.Tau && !reverseAtomicPathMap.ContainsKey(ap) &&\n                                                                  ap.StartType == ap.EndType && !ap.Stopping))\n      {\n        var startPC = LowerPC(hAtomicPath.StartPC);\n        if (pcToIntroducedPaths.ContainsKey(startPC)) {\n          pcToIntroducedPaths[startPC].Add(hAtomicPath);\n        }\n        else {\n          pcToIntroducedPaths[startPC] = new List<AtomicPath>{ hAtomicPath };\n        }\n      }\n    }\n\n    protected bool CheckAllIntroducedAreUpdates() {\n      foreach (var routine in pgp.symbolsHigh.NextRoutines) {\n        if (routine.nextType != NextType.Update && routine.startPC != routine.endPC && routine.endPC != null && LowerPC(routine.startPC) == LowerPC(routine.endPC)) {\n          AH.PrintError(pgp.prog, routine.armadaStatement.Stmt.Tok, $\"Can't introduce non-assignment statement\");\n          return false;\n        }\n      }\n      return true;\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    // Proof\n    ////////////////////////////////////////////////////////////////////////\n\n    protected void GenerateProofGivenMap() {\n      GenerateProofHeader();\n      GenerateAtomicSpecs();\n      GenerateReverseAtomicPathMap();\n      RegenerateAtomicPathMap();\n      GeneratePCToIntroducedPathsMap();\n\n      // the state conversion functions are required from H to L\n      GenerateStateAbstractionFunctions_HL(reversePCMap);\n      // the step conversion functions are required from L to H\n\n      GenerateStateAbstractionFunctions_LH();\n      GenerateConvertStep_LH();\n      GenerateConvertAtomicPath_LH();\n      GeneratePCFunctions_H();\n      GenerateIsReturnSite_H();\n      GenerateLiftingRelation();\n      if (canIntroduceTau) {\n        GenerateCanIntroduceTau();\n      }\n      GenerateProgressMeasure();\n\n      // lemma generation\n\n      lAtomic.GeneratePCEffectLemmas();\n      GenerateInvariantProof(pgp);\n      GenerateLocalViewCommutativityLemmas();\n      GenerateEstablishInitRequirementsLemma();\n      GenerateEstablishStateOKRequirementLemma();\n      GenerateEstablishRelationRequirementLemma();\n      GenerateIntroduceOrLiftAtomicPathLemmas();\n      GenerateEstablishAtomicPathsLiftableLemma(false, true);\n      GenerateLiftLAtomicToHAtomicLemma(false, true);\n      GenerateFinalProof();\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    // Abstraction\n    ////////////////////////////////////////////////////////////////////////\n\n    protected override void GenerateConvertAtomicPath_LH()\n    {\n      string str = @\"\n        function ConvertAtomicPath_LH(lpath: LAtomic_Path) : HAtomic_Path\n        {\n          match lpath\n      \";\n      foreach (var entry in pathMap)\n      {\n        var lPath = entry.Key;\n        var hPath = entry.Value;\n\n        var steps = new List<string>();\n        var numLNextRoutinesUsed = 0;\n        for (int i = 0; i < hPath.NumNextRoutines; ++i) {\n          var hNextRoutine = hPath.NextRoutines[i];\n          if (reverseNextRoutineMap.ContainsKey(hNextRoutine)) {\n            steps.Add($\"ConvertStep_LH(steps.step{numLNextRoutinesUsed})\");\n            ++numLNextRoutinesUsed;\n          }\n          else {\n            if (hNextRoutine.HasFormals) {\n              // TODO: this does not work with introduced statements with *\n              AH.PrintError(pgp.prog, \"The variable-introduction proof generator doesn't support introducing a non-deterministic statement.\");\n            }\n            steps.Add($\"H.Armada_Step_{hNextRoutine.NameSuffix}()\");\n          }\n        }\n\n        str += $\"case LAtomic_Path_{lPath.Name}(steps) => HAtomic_Path_{hPath.Name}(HAtomic_PathSteps_{hPath.Name}(\";\n        str += String.Join(\", \", steps);\n        str += \"))\\n\";\n      }\n      str += \"}\\n\";\n      pgp.AddFunction(str, \"convert\");\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    // Commutativity lemmas\n    ////////////////////////////////////////////////////////////////////////\n\n    protected override void GenerateLocalViewCommutativityLemmas()\n    {\n      string str;\n\n      string cases = \"\";\n      foreach (var varName in pgp.symbolsLow.Globals.VariableNames) {\n        var globalVar = pgp.symbolsLow.Globals.Lookup(varName);\n        if (globalVar is AddressableArmadaVariable || globalVar.NoTSO()) {\n          continue;\n        }\n        cases += $\"case Armada_GlobalStaticVar_{varName} => {{ }}\\n\";\n      }\n\n      var extraRequires = canIntroduceTau ? \"requires CanConvertGlobalStaticVar_HL(hv)\" : \"\";\n      str = $@\"\n        lemma lemma_ApplyStoreBufferEntryUnaddressableCommutesWithConvert(\n          hglobals:H.Armada_Globals, hv:H.Armada_GlobalStaticVar, fields:seq<int>, value:Armada_PrimitiveValue,\n          lv:L.Armada_GlobalStaticVar, lglobals1:L.Armada_Globals, lglobals2:L.Armada_Globals)\n          { extraRequires }\n          requires lv == ConvertGlobalStaticVar_HL(hv)\n          requires lglobals1 == ConvertGlobals_HL(H.Armada_ApplyTauUnaddressable(hglobals, hv, fields, value))\n          requires lglobals2 == L.Armada_ApplyTauUnaddressable(ConvertGlobals_HL(hglobals), lv, fields, value)\n          ensures  lglobals1 == lglobals2\n        {{\n          match hv\n            case Armada_GlobalStaticVarNone =>\n            {{\n              var lglobals := ConvertGlobals_HL(hglobals);\n              assert lglobals1 == lglobals == lglobals2;\n            }}\n            { cases }\n        }}\n      \";\n      pgp.AddLemma(str, \"utility\");\n\n      if (canIntroduceTau) {\n        str = @\"\n          lemma lemma_ApplyingUnconvertibleStoreBufferEntryDoesntChangeHState(\n            hmem:H.Armada_SharedMemory,\n            hentry:H.Armada_StoreBufferEntry\n            )\n            requires !CanConvertStoreBufferEntry_HL(hentry)\n            ensures  ConvertSharedMemory_HL(H.Armada_ApplyStoreBufferEntry(hmem, hentry)) == ConvertSharedMemory_HL(hmem)\n          {\n          }\n        \";\n        pgp.AddLemma(str, \"utility\");\n      }\n\n      extraRequires = canIntroduceTau ? \"requires CanConvertStoreBufferEntry_HL(hentry)\" : \"\";\n      str = $@\"\n        lemma lemma_ApplyStoreBufferEntryCommutesWithConvert(hmem:H.Armada_SharedMemory, hentry:H.Armada_StoreBufferEntry,\n                                                             lentry:L.Armada_StoreBufferEntry, lmem1:L.Armada_SharedMemory,\n                                                             lmem2:L.Armada_SharedMemory)\n          { extraRequires }\n          requires lentry == ConvertStoreBufferEntry_HL(hentry)\n          requires lmem1 == ConvertSharedMemory_HL(H.Armada_ApplyStoreBufferEntry(hmem, hentry))\n          requires lmem2 == L.Armada_ApplyStoreBufferEntry(ConvertSharedMemory_HL(hmem), lentry)\n          ensures  lmem1 == lmem2\n        {{\n          match hentry.loc\n            case Armada_StoreBufferLocation_Unaddressable(hv, hfields) =>\n            {{\n              var lv := ConvertGlobalStaticVar_HL(hv);\n              lemma_ApplyStoreBufferEntryUnaddressableCommutesWithConvert(hmem.globals, hv, hfields, hentry.value, lv,\n                                                                          lmem1.globals, lmem2.globals);\n            }}\n            case Armada_StoreBufferLocation_Addressable(p) =>\n            {{\n            }}\n        }}\n      \";\n      pgp.AddLemma(str, \"utility\");\n\n      var mainProof = @\"\n        var lmem1' := ConvertSharedMemory_HL(H.Armada_ApplyStoreBufferEntry(hmem, hbuf[0]));\n        var lmem2' := L.Armada_ApplyStoreBufferEntry(ConvertSharedMemory_HL(hmem), lbuf[0]);\n        lemma_ApplyStoreBufferEntryCommutesWithConvert(hmem, hbuf[0], lbuf[0], lmem1', lmem2');\n        lemma_ApplyStoreBufferCommutesWithConvert(hmem', hbuf[1..], lbuf[1..], lmem1, lmem2);\n      \";\n      if (canIntroduceTau) {\n        mainProof = $@\"\n          if CanConvertStoreBufferEntry_HL(hbuf[0]) {{\n            { mainProof }\n          }}\n          else {{\n            lemma_ApplyingUnconvertibleStoreBufferEntryDoesntChangeHState(hmem, hbuf[0]);\n            assert ConvertSharedMemory_HL(hmem') == ConvertSharedMemory_HL(hmem);\n            assert lbuf == ConvertStoreBuffer_HL(hbuf[1..]);\n            lemma_ApplyStoreBufferCommutesWithConvert(hmem', hbuf[1..], lbuf, lmem1, lmem2);\n          }}\n        \";\n      }\n\n      str = $@\"\n        lemma lemma_ApplyStoreBufferCommutesWithConvert(hmem:H.Armada_SharedMemory, hbuf:seq<H.Armada_StoreBufferEntry>,\n                                                        lbuf:seq<L.Armada_StoreBufferEntry>, lmem1:L.Armada_SharedMemory,\n                                                        lmem2:L.Armada_SharedMemory)\n          requires lbuf == ConvertStoreBuffer_HL(hbuf)\n          requires lmem1 == ConvertSharedMemory_HL(H.Armada_ApplyStoreBuffer(hmem, hbuf))\n          requires lmem2 == L.Armada_ApplyStoreBuffer(ConvertSharedMemory_HL(hmem), lbuf)\n          ensures  lmem1 == lmem2\n          decreases |hbuf| + |lbuf|\n        {{\n          if |hbuf| == 0 {{\n            return;\n          }}\n\n          var hmem' := H.Armada_ApplyStoreBufferEntry(hmem, hbuf[0]);\n\n          { mainProof }\n        }}\n      \";\n      pgp.AddLemma(str, \"utility\");\n\n      str = @\"\n        lemma lemma_GetThreadLocalViewCommutesWithConvert(hs:HState, ls:LState, tid:Armada_ThreadHandle)\n          requires ls == ConvertTotalState_HL(hs)\n          requires tid in hs.threads;\n          ensures  ConvertSharedMemory_HL(H.Armada_GetThreadLocalView(hs, tid)) == L.Armada_GetThreadLocalView(ls, tid)\n        {\n          assert tid in ls.threads;\n          lemma_ApplyStoreBufferCommutesWithConvert(hs.mem, hs.threads[tid].storeBuffer,\n                                                    ls.threads[tid].storeBuffer,\n                                                    ConvertSharedMemory_HL(H.Armada_GetThreadLocalView(hs, tid)),\n                                                    L.Armada_GetThreadLocalView(ls, tid));\n        }\n      \";\n      pgp.AddLemma(str, \"utility\");\n\n      str = @\"\n        lemma lemma_GetThreadLocalViewAlwaysCommutesWithConvert()\n          ensures forall hs:H.Armada_TotalState, tid:Armada_ThreadHandle\n                    {:trigger H.Armada_GetThreadLocalView(hs, tid)}\n                    :: tid in hs.threads ==>\n                    ConvertSharedMemory_HL(H.Armada_GetThreadLocalView(hs, tid)) ==\n                    L.Armada_GetThreadLocalView(ConvertTotalState_HL(hs), tid)\n        {\n          forall hs:H.Armada_TotalState, tid:Armada_ThreadHandle\n            {:trigger H.Armada_GetThreadLocalView(hs, tid)}\n            | tid in hs.threads\n            ensures ConvertSharedMemory_HL(H.Armada_GetThreadLocalView(hs, tid)) ==\n                    L.Armada_GetThreadLocalView(ConvertTotalState_HL(hs), tid)\n          {\n            var ls := ConvertTotalState_HL(hs);\n            lemma_GetThreadLocalViewCommutesWithConvert(hs, ls, tid);\n          }\n        }\n      \";\n      pgp.AddLemma(str, \"utility\");\n\n      if (canIntroduceTau) {\n        str = @\"\n          lemma lemma_StoreBufferAppendConversion(buf: seq<H.Armada_StoreBufferEntry>, entry: H.Armada_StoreBufferEntry)\n            ensures  ConvertStoreBuffer_HL(buf + [entry]) ==\n                       if CanConvertStoreBufferEntry_HL(entry) then\n                         ConvertStoreBuffer_HL(buf) + [ConvertStoreBufferEntry_HL(entry)]\n                       else\n                         ConvertStoreBuffer_HL(buf)\n          {\n            assert [entry][1..] == [];\n  \n            if |buf| == 0 {\n              assert buf + [entry] == [entry];\n              assert ConvertStoreBuffer_HL(buf + [entry]) == ConvertStoreBuffer_HL([entry]);\n              assert ConvertStoreBuffer_HL(buf) == [];\n  \n              if CanConvertStoreBufferEntry_HL(entry) {\n                calc {\n                    ConvertStoreBuffer_HL([entry]);\n                    [ConvertStoreBufferEntry_HL(entry)] + ConvertStoreBuffer_HL([entry][1..]);\n                    [ConvertStoreBufferEntry_HL(entry)] + ConvertStoreBuffer_HL([]);\n                    [ConvertStoreBufferEntry_HL(entry)] + [];\n                    [ConvertStoreBufferEntry_HL(entry)];\n                }\n              }\n              else {\n                calc {\n                    ConvertStoreBuffer_HL([entry]);\n                    ConvertStoreBuffer_HL([entry][1..]);\n                    ConvertStoreBuffer_HL([]);\n                    [];\n                }\n              }\n            }\n            else {\n              calc {\n                ConvertStoreBuffer_HL(buf + [entry]);\n                {\n                  assert buf == [buf[0]] + buf[1..];\n                }\n                ConvertStoreBuffer_HL([buf[0]] + buf[1..] + [entry]);\n                {\n                  assert [buf[0]] + buf[1..] + [entry] == [buf[0]] + (buf[1..] + [entry]);\n                }\n                ConvertStoreBuffer_HL([buf[0]] + (buf[1..] + [entry]));\n              }\n              if CanConvertStoreBufferEntry_HL(buf[0]) {\n                calc {\n                  ConvertStoreBuffer_HL(buf + [entry]);\n                  ConvertStoreBuffer_HL([buf[0]] + (buf[1..] + [entry]));\n                  [ConvertStoreBufferEntry_HL(buf[0])] + ConvertStoreBuffer_HL(buf[1..] + [entry]);\n                }\n                lemma_StoreBufferAppendConversion(buf[1..], entry);\n                if CanConvertStoreBufferEntry_HL(entry) {\n                  calc {\n                    ConvertStoreBuffer_HL(buf + [entry]);\n                    [ConvertStoreBufferEntry_HL(buf[0])] + (ConvertStoreBuffer_HL(buf[1..]) + [ConvertStoreBufferEntry_HL(entry)]);\n                    [ConvertStoreBufferEntry_HL(buf[0])] + ConvertStoreBuffer_HL(buf[1..]) + [ConvertStoreBufferEntry_HL(entry)];\n                    ConvertStoreBuffer_HL(buf) + [ConvertStoreBufferEntry_HL(entry)];\n                  }\n                }\n                else {\n                  calc {\n                    ConvertStoreBuffer_HL(buf + [entry]);\n                    [ConvertStoreBufferEntry_HL(buf[0])] + ConvertStoreBuffer_HL(buf[1..]);\n                    ConvertStoreBuffer_HL(buf);\n                  }\n                }\n              }\n              else {\n                assert ConvertStoreBuffer_HL(buf) == ConvertStoreBuffer_HL(buf[1..]);\n                calc {\n                  ConvertStoreBuffer_HL(buf + [entry]);\n                  ConvertStoreBuffer_HL([buf[0]] + (buf[1..] + [entry]));\n                  ConvertStoreBuffer_HL((buf[1..] + [entry]));\n                }\n                lemma_StoreBufferAppendConversion(buf[1..], entry);\n                if CanConvertStoreBufferEntry_HL(entry) {\n                  calc {\n                    ConvertStoreBuffer_HL(buf + [entry]);\n                    ConvertStoreBuffer_HL(buf[1..]) + [ConvertStoreBufferEntry_HL(entry)];\n                    ConvertStoreBuffer_HL(buf) + [ConvertStoreBufferEntry_HL(entry)];\n                  }\n                }\n                else {\n                  calc {\n                    ConvertStoreBuffer_HL(buf + [entry]);\n                    ConvertStoreBuffer_HL(buf[1..]);\n                    ConvertStoreBuffer_HL(buf);\n                  }\n                }\n              }\n            }\n          }\n        \";\n        pgp.AddLemma(str, \"utility\");\n\n        str = @\"\n          lemma lemma_StoreBufferAppendAlwaysCommutesWithConvert()\n          ensures forall hbuf: seq<H.Armada_StoreBufferEntry>, hentry: H.Armada_StoreBufferEntry\n            {:trigger ConvertStoreBuffer_HL(H.Armada_StoreBufferAppend(hbuf, hentry))} ::\n            CanConvertStoreBufferEntry_HL(hentry) ==>\n            L.Armada_StoreBufferAppend(ConvertStoreBuffer_HL(hbuf), ConvertStoreBufferEntry_HL(hentry)) ==\n            ConvertStoreBuffer_HL(H.Armada_StoreBufferAppend(hbuf, hentry))\n        {\n          forall hbuf: seq<H.Armada_StoreBufferEntry>, hentry: H.Armada_StoreBufferEntry\n            {:trigger ConvertStoreBuffer_HL(H.Armada_StoreBufferAppend(hbuf, hentry))}\n            | CanConvertStoreBufferEntry_HL(hentry)\n            ensures L.Armada_StoreBufferAppend(ConvertStoreBuffer_HL(hbuf), ConvertStoreBufferEntry_HL(hentry)) ==\n                    ConvertStoreBuffer_HL(H.Armada_StoreBufferAppend(hbuf, hentry))\n          {\n            lemma_StoreBufferAppendConversion(hbuf, hentry);\n          }\n        }\n        \";\n        pgp.AddLemma(str, \"utility\");\n\n        str = @\"\n          lemma lemma_ConvertStoreBufferCommutesOverBeheadment(buf:seq<H.Armada_StoreBufferEntry>)\n            requires |buf| > 0\n            requires CanConvertStoreBufferEntry_HL(buf[0])\n            ensures  ConvertStoreBuffer_HL(buf[1..]) == ConvertStoreBuffer_HL(buf)[1..]\n          {\n            var hbuf1 := ConvertStoreBuffer_HL(buf[1..]);\n            var hbuf2 := ConvertStoreBuffer_HL(buf)[1..];\n            assert |hbuf1| == |hbuf2|;\n\n            forall i | 0 <= i < |buf| - 1\n              ensures hbuf1[i] == hbuf2[i]\n            {\n            }\n\n            assert hbuf1 == hbuf2;\n          }\n        \";\n        pgp.AddLemma(str, \"utility\");\n\n        str = @\"\n          lemma lemma_AppendingHiddenStoreBufferEntryAlwaysDoesntAffectLowLevel(tid:Armada_ThreadHandle)\n            ensures forall s:H.Armada_TotalState, entry:H.Armada_StoreBufferEntry\n                      {:trigger H.Armada_AppendToThreadStoreBuffer(s, tid, entry)} ::\n                      tid in s.threads && !CanConvertStoreBufferEntry_HL(entry) ==>\n                      ConvertTotalState_HL(H.Armada_AppendToThreadStoreBuffer(s, tid, entry)) == ConvertTotalState_HL(s)\n          {\n            forall s:H.Armada_TotalState, entry:H.Armada_StoreBufferEntry {:trigger H.Armada_AppendToThreadStoreBuffer(s, tid, entry)} |\n              tid in s.threads && !CanConvertStoreBufferEntry_HL(entry)\n              ensures ConvertTotalState_HL(H.Armada_AppendToThreadStoreBuffer(s, tid, entry)) == ConvertTotalState_HL(s)\n            {\n              var hs := ConvertTotalState_HL(s);\n              var hs' := ConvertTotalState_HL(H.Armada_AppendToThreadStoreBuffer(s, tid, entry));\n              lemma_StoreBufferAppendConversion(s.threads[tid].storeBuffer, entry);\n              assert hs.threads[tid].storeBuffer == hs'.threads[tid].storeBuffer;\n              assert hs.threads == hs'.threads;\n              assert hs == hs';\n            }\n          }\n        \";\n        pgp.AddLemma(str, \"utility\");\n\n        str = @\"\n          lemma lemma_IfLStoreBufferEmptyAndCantIntroduceTauThenHStoreBufferEmpty(\n            ls: LState,\n            hs: HState,\n            tid: Armada_ThreadHandle\n            )\n            requires ls == ConvertTotalState_HL(hs)\n            requires tid in ls.threads\n            requires |ls.threads[tid].storeBuffer| == 0\n            requires !CanIntroduceTau(hs, tid)\n            ensures  tid in hs.threads\n            ensures  |hs.threads[tid].storeBuffer| == 0\n          {\n            assert tid in hs.threads;\n            var lsb := ls.threads[tid].storeBuffer;\n            var hsb := hs.threads[tid].storeBuffer;\n            if |hsb| == 0 {\n              return;\n            }\n            assert CanConvertStoreBufferEntry_HL(hsb[0]);\n            assert lsb == ConvertStoreBuffer_HL(hsb);\n            calc {\n              lsb;\n              FilterMapSeqToSeq(hsb, ConvertStoreBufferEntryTotal_HL);\n              [ ConvertStoreBufferEntry_HL(hsb[0]) ] + FilterMapSeqToSeq(hsb[1..], ConvertStoreBufferEntryTotal_HL);\n            }\n            assert |lsb| > 0;\n            assert false;\n          }\n        \";\n        pgp.AddLemma(str, \"utility\");\n\n        str = @\"\n          lemma lemma_AlwaysIfLStoreBufferEmptyAndCantIntroduceTauThenHStoreBufferEmpty()\n            ensures forall ls: LPlusState, hs: HState, tid: Armada_ThreadHandle\n                      {:trigger LiftingRelation(ls, hs), CanIntroduceTau(hs, tid)} ::\n                      && LiftingRelation(ls, hs)\n                      && tid in ls.s.threads\n                      && |ls.s.threads[tid].storeBuffer| == 0\n                      && !CanIntroduceTau(hs, tid)\n                      ==> tid in hs.threads &&  |hs.threads[tid].storeBuffer| == 0\n          {\n            forall ls: LPlusState, hs: HState, tid: Armada_ThreadHandle\n              {:trigger LiftingRelation(ls, hs), CanIntroduceTau(hs, tid)} |\n              && LiftingRelation(ls, hs)\n              && tid in ls.s.threads\n              && |ls.s.threads[tid].storeBuffer| == 0\n              && !CanIntroduceTau(hs, tid)\n              ensures tid in hs.threads\n              ensures |hs.threads[tid].storeBuffer| == 0\n            {\n              lemma_IfLStoreBufferEmptyAndCantIntroduceTauThenHStoreBufferEmpty(ls.s, hs, tid);\n            }\n          }\n        \";\n        pgp.AddLemma(str, \"utility\");\n      }\n      else {\n        str = @\"\n          lemma lemma_StoreBufferAppendConversion(buf: seq<H.Armada_StoreBufferEntry>, entry: H.Armada_StoreBufferEntry)\n            ensures  ConvertStoreBuffer_HL(buf + [entry]) == ConvertStoreBuffer_HL(buf) + [ConvertStoreBufferEntry_HL(entry)]\n          {\n            assert [entry][1..] == [];\n  \n            if |buf| == 0 {\n              assert buf + [entry] == [entry];\n              assert ConvertStoreBuffer_HL(buf + [entry]) == ConvertStoreBuffer_HL([entry]);\n              assert ConvertStoreBuffer_HL(buf) == [];\n  \n              calc {\n                ConvertStoreBuffer_HL([entry]);\n                [ConvertStoreBufferEntry_HL(entry)] + ConvertStoreBuffer_HL([entry][1..]);\n                [ConvertStoreBufferEntry_HL(entry)] + ConvertStoreBuffer_HL([]);\n                [ConvertStoreBufferEntry_HL(entry)] + [];\n                [ConvertStoreBufferEntry_HL(entry)];\n              }\n            }\n            else {\n              calc {\n                ConvertStoreBuffer_HL(buf + [entry]);\n                {\n                  assert buf == [buf[0]] + buf[1..];\n                }\n                ConvertStoreBuffer_HL([buf[0]] + buf[1..] + [entry]);\n                {\n                  assert [buf[0]] + buf[1..] + [entry] == [buf[0]] + (buf[1..] + [entry]);\n                }\n                ConvertStoreBuffer_HL([buf[0]] + (buf[1..] + [entry]));\n              }\n              calc {\n                ConvertStoreBuffer_HL(buf + [entry]);\n                ConvertStoreBuffer_HL([buf[0]] + (buf[1..] + [entry]));\n                [ConvertStoreBufferEntry_HL(buf[0])] + ConvertStoreBuffer_HL(buf[1..] + [entry]);\n              }\n              lemma_StoreBufferAppendConversion(buf[1..], entry);\n              calc {\n                ConvertStoreBuffer_HL(buf + [entry]);\n                [ConvertStoreBufferEntry_HL(buf[0])] + (ConvertStoreBuffer_HL(buf[1..]) + [ConvertStoreBufferEntry_HL(entry)]);\n                [ConvertStoreBufferEntry_HL(buf[0])] + ConvertStoreBuffer_HL(buf[1..]) + [ConvertStoreBufferEntry_HL(entry)];\n                ConvertStoreBuffer_HL(buf) + [ConvertStoreBufferEntry_HL(entry)];\n              }\n            }\n          }\n        \";\n        pgp.AddLemma(str, \"utility\");\n\n        str = @\"\n          lemma lemma_StoreBufferAppendAlwaysCommutesWithConvert()\n          ensures forall hbuf: seq<H.Armada_StoreBufferEntry>, hentry: H.Armada_StoreBufferEntry\n            {:trigger ConvertStoreBuffer_HL(H.Armada_StoreBufferAppend(hbuf, hentry))} ::\n            L.Armada_StoreBufferAppend(ConvertStoreBuffer_HL(hbuf), ConvertStoreBufferEntry_HL(hentry)) ==\n            ConvertStoreBuffer_HL(H.Armada_StoreBufferAppend(hbuf, hentry))\n        {\n          forall hbuf: seq<H.Armada_StoreBufferEntry>, hentry: H.Armada_StoreBufferEntry\n            {:trigger ConvertStoreBuffer_HL(H.Armada_StoreBufferAppend(hbuf, hentry))}\n            ensures L.Armada_StoreBufferAppend(ConvertStoreBuffer_HL(hbuf), ConvertStoreBufferEntry_HL(hentry)) ==\n                    ConvertStoreBuffer_HL(H.Armada_StoreBufferAppend(hbuf, hentry))\n          {\n            lemma_StoreBufferAppendConversion(hbuf, hentry);\n          }\n        }\n        \";\n        pgp.AddLemma(str, \"utility\");\n      }\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    // VarIntro-specific functions\n    ////////////////////////////////////////////////////////////////////////\n\n    private void GenerateCanIntroduceTau()\n    {\n      string str = @\"\n        predicate CanIntroduceTau(hs: HState, tid: Armada_ThreadHandle)\n        {\n          && tid in hs.threads\n          && |hs.threads[tid].storeBuffer| > 0\n          && !CanConvertStoreBufferEntry_HL(hs.threads[tid].storeBuffer[0])\n        }\n      \";\n\n      pgp.AddPredicate(str, \"utility\");\n    }\n\n    private void GenerateProgressMeasure()\n    {\n      string secondProgressElement = canIntroduceTau ? \"|t.storeBuffer|\" : \"0\";\n\n      string str = $@\"\n        function ProgressMeasure(hs: HState, lpath: LAtomic_Path, tid: Armada_ThreadHandle) : (v:(int, int))\n          ensures v.0 >= 0\n          ensures v.1 >= 0\n        {{\n          if tid in hs.threads then\n            var t := hs.threads[tid];\n            (MaxPCInstructionCount_H() - PCToInstructionCount_H(t.pc), {secondProgressElement})\n          else\n            (0, 0)\n        }}\n      \";\n      pgp.AddFunction(str, \"utility\");\n    }\n\n    private void GenerateIsReturnSite_H()\n    {\n      string body = String.Join(\" || \",\n                                pgp.symbolsHigh.NextRoutines\n                                .Where(r => r.nextType == NextType.Return)\n                                .Select(r => r.endPC)\n                                .Distinct()\n                                .Select(pc => $\"pc.{pc}?\"));\n      if (body.Length == 0) { body = \"false\"; }\n\n      string str = \"predicate IsReturnSite_H(pc:H.Armada_PC) { \" + body + \"}\";\n      pgp.AddPredicate(str, \"defs\");\n    }\n\n    protected override void GenerateLiftingRelation()\n    {\n      string str;\n\n      str = @\"\n        predicate VarIntroThreadInvariant(hs: HState, tid: Armada_ThreadHandle)\n          requires tid in hs.threads\n        {\n          var t := hs.threads[tid];\n          var pc := t.pc;\n          && StackMatchesMethod_H(t.top, PCToMethod_H(pc))\n          && (forall eframe :: eframe in t.stack ==> IsReturnSite_H(eframe.return_pc))\n          && (!hs.stop_reason.Armada_NotStopped? || !H.Armada_IsNonyieldingPC(pc) || HAtomic_IsRecurrentPC(pc))\n        }\n      \";\n      pgp.AddPredicate(str, \"defs\");\n\n      str = @\"\n        predicate LiftingRelation(ls: LPlusState, hs: HState)\n        {\n          && ls.s == ConvertTotalState_HL(hs)\n          && (forall tid :: tid in hs.threads ==> VarIntroThreadInvariant(hs, tid))\n        }\n      \";\n      pgp.AddPredicate(str, \"defs\");\n    }\n\n    protected override void GenerateEstablishInitRequirementsLemma()\n    {\n      string str = @\"\n        lemma lemma_EstablishInitRequirements(\n          lasf:AtomicSpecFunctions<LPlusState, LAtomic_Path, L.Armada_PC>,\n          hasf:AtomicSpecFunctions<HState, HAtomic_Path, H.Armada_PC>,\n          inv:LPlusState->bool,\n          relation:(LPlusState, HState)->bool\n          )\n          requires lasf == LAtomic_GetSpecFunctions()\n          requires hasf == HAtomic_GetSpecFunctions()\n          requires inv == InductiveInv\n          requires relation == LiftingRelation\n          ensures  AtomicInitImpliesInv(lasf, inv)\n          ensures  forall ls :: lasf.init(ls) ==> exists hs :: hasf.init(hs) && relation(ls, hs)\n        {\n          forall ls | lasf.init(ls)\n            ensures inv(ls)\n            ensures exists hs :: hasf.init(hs) && relation(ls, hs)\n          {\n            lemma_InitImpliesInductiveInv(ls);\n            var hs := ConvertTotalState_LPlusH(ls);\n            var hconfig := ConvertConfig_LH(ls.config);\n            assert H.Armada_InitConfig(hs, hconfig);\n            var tid_init := ls.config.tid_init;\n            var ls_alt := ConvertTotalState_HL(hs);\n            assert ls.s.threads[tid_init] == ls_alt.threads[tid_init];\n            assert hasf.init(hs) && relation(ls, hs);\n          }\n        }\n      \";\n      pgp.AddLemma(str);\n    }\n\n    private void GenerateIntroduceAtomicPathLemmaForNormalPath(AtomicPath atomicPath)\n    {\n      var name = atomicPath.Name;\n\n      var lpc = LowerPC(atomicPath.StartPC);\n\n      string tyConstraint =\n        atomicPath.StartType == PCAtomicType.Yielding\n          ? \"ty.AtomicPathType_YY? || ty.AtomicPathType_YS? || ty.AtomicPathType_YR?\"\n          : \"ty.AtomicPathType_RY? || ty.AtomicPathType_RS? || ty.AtomicPathType_RR?\";\n      string yieldingDependentRequires =\n        (pgp.symbolsLow.IsNonyieldingPC(lpc) || !canIntroduceTau) ? \"\" : \"requires !CanIntroduceTau(hs, tid)\";\n      string pathConstructor = hAtomic.GetConstructorString(atomicPath);\n      string extraProof = canIntroduceTau ? \"lemma_AppendingHiddenStoreBufferEntryAlwaysDoesntAffectLowLevel(tid);\" : \"\";\n\n      var hpr = new PrefixedVarsPathPrinter(hAtomic);\n\n      string str = $@\"\n        lemma lemma_IntroduceAtomicPath_{name}(\n          lasf: AtomicSpecFunctions<LPlusState, LAtomic_Path, L.Armada_PC>,\n          hasf: AtomicSpecFunctions<HState, HAtomic_Path, H.Armada_PC>,\n          ls: LPlusState,\n          lpath: LAtomic_Path,\n          tid: Armada_ThreadHandle,\n          hs: HState\n          ) returns (\n          hpath: HAtomic_Path\n          )\n          requires lasf == LAtomic_GetSpecFunctions()\n          requires hasf == HAtomic_GetSpecFunctions()\n          requires InductiveInv(ls)\n          requires LiftingRelation(ls, hs)\n          requires LAtomic_ValidPath(ls, lpath, tid)\n          requires ls.s.stop_reason.Armada_NotStopped?\n          requires tid in ls.s.threads\n          requires tid in hs.threads\n          requires ls.s.threads[tid].pc.{lpc}?\n          { yieldingDependentRequires }\n          requires var ty := lasf.path_type(lpath); {tyConstraint}\n          requires hs.threads[tid].pc.{atomicPath.StartPC}?\n          ensures  AtomicPathIntroduced(lasf, hasf, LiftingRelation, ProgressMeasure, ls, lpath, tid, hs, hpath)\n        {{\n          hpath := { pathConstructor };\n          var hs' := HAtomic_GetStateAfterPath(hs, hpath, tid);\n\n          { hpr.GetOpenPathInvocation(atomicPath) }\n\n          assert hs'.stop_reason.Armada_NotStopped?;\n          assert PCToInstructionCount_H(hs'.threads[tid].pc) > PCToInstructionCount_H(hs.threads[tid].pc);\n\n          { extraProof }\n          ProofCustomizationGoesHere();\n          assert VarIntroThreadInvariant(hs', tid);\n\n          /* { hpr.GetAssertValidPathInvocation(atomicPath) } */\n        }}\n      \";\n      pgp.AddLemma(str, \"lift\");\n    }\n\n    private void GenerateIntroduceNormalPathLemmas()\n    {\n      foreach (var atomicPaths in pcToIntroducedPaths.Values) {\n        foreach (var atomicPath in atomicPaths) {\n          GenerateIntroduceAtomicPathLemmaForNormalPath(atomicPath);\n        }\n      }\n    }\n\n    private void GenerateIntroduceAtomicPathLemmaForTauPath()\n    {\n      var pr = new PrefixedVarsPathPrinter(hAtomic);\n\n      string str = $@\"\n        lemma lemma_IntroduceAtomicPath_Tau(\n          lasf: AtomicSpecFunctions<LPlusState, LAtomic_Path, L.Armada_PC>,\n          hasf: AtomicSpecFunctions<HState, HAtomic_Path, H.Armada_PC>,\n          ls: LPlusState,\n          lpath: LAtomic_Path,\n          tid: Armada_ThreadHandle,\n          hs: HState\n          ) returns (\n          hpath: HAtomic_Path\n          )\n          requires lasf == LAtomic_GetSpecFunctions()\n          requires hasf == HAtomic_GetSpecFunctions()\n          requires InductiveInv(ls)\n          requires LiftingRelation(ls, hs)\n          requires LAtomic_ValidPath(ls, lpath, tid)\n          requires ls.s.stop_reason.Armada_NotStopped?\n          requires tid in ls.s.threads\n          requires !L.Armada_IsNonyieldingPC(ls.s.threads[tid].pc) || lpath.LAtomic_Path_Tau?\n          requires CanIntroduceTau(hs, tid)\n          ensures  AtomicPathIntroduced(lasf, hasf, LiftingRelation, ProgressMeasure, ls, lpath, tid, hs, hpath)\n        {{\n          var lty := lasf.path_type(lpath);\n          if lty.AtomicPathType_RY? || lty.AtomicPathType_RS? || lty.AtomicPathType_RR? {{\n            assert !L.Armada_IsNonyieldingPC(ls.s.threads[tid].pc);\n            assert false;\n          }}\n\n          hpath := HAtomic_Path_Tau(HAtomic_PathSteps_Tau(H.Armada_Step_Tau()));\n          var hs' := HAtomic_GetStateAfterPath(hs, hpath, tid);\n\n          { pr.GetOpenPathInvocation(hAtomic.TauPath) }\n          ProofCustomizationGoesHere();\n\n          assert ProgressMeasure(hs', lpath, tid).1 == |hs'.threads[tid].storeBuffer|;\n          assert ProgressMeasure(hs, lpath, tid).1 == |hs.threads[tid].storeBuffer|;\n          assert 0 <= ProgressMeasure(hs', lpath, tid).0 == ProgressMeasure(hs, lpath, tid).0;\n          assert 0 <= ProgressMeasure(hs', lpath, tid).1 < ProgressMeasure(hs, lpath, tid).1;\n        }}\n      \";\n      pgp.AddLemma(str, \"lift\");\n    }\n\n    private void GenerateLiftAtomicPathLemmaForTauPath()\n    {\n      var lpr = new PrefixedVarsPathPrinter(lAtomic);\n      var hpr = new PrefixedVarsPathPrinter(hAtomic);\n      var extraRequires = canIntroduceTau ? \"requires !CanIntroduceTau(hs, tid)\" : \"\";\n\n      string str = $@\"\n        lemma lemma_LiftAtomicPath_Tau(\n          lasf: AtomicSpecFunctions<LPlusState, LAtomic_Path, L.Armada_PC>,\n          hasf: AtomicSpecFunctions<HState, HAtomic_Path, H.Armada_PC>,\n          ls: LPlusState,\n          lpath: LAtomic_Path,\n          tid: Armada_ThreadHandle,\n          hs: HState\n          ) returns (\n          hpath: HAtomic_Path\n          )\n          requires lasf == LAtomic_GetSpecFunctions()\n          requires hasf == HAtomic_GetSpecFunctions()\n          requires InductiveInv(ls)\n          requires LiftingRelation(ls, hs)\n          requires LAtomic_ValidPath(ls, lpath, tid)\n          requires lpath.LAtomic_Path_Tau?\n          { extraRequires }\n          ensures  LiftAtomicPathSuccessful(lasf, hasf, InductiveInv, LiftingRelation, ls, lpath, tid, hs, hpath)\n        {{\n          { lpr.GetOpenValidPathInvocation(lAtomic.TauPath) }\n\n          var ls' := LAtomic_GetStateAfterPath(ls, lpath, tid);\n          hpath := ConvertAtomicPath_LH(lpath);\n\n          lemma_AtomicPathMaintainsInductiveInv(ls, ls', lpath, tid);\n\n          { hpr.GetOpenPathInvocation(hAtomic.TauPath) }\n          ProofCustomizationGoesHere();\n          assert ls'.s.threads[tid] == ConvertTotalState_HL(hasf.path_next(hs, hpath, tid)).threads[tid];\n        }}\n      \";\n      pgp.AddLemma(str, \"lift\");\n    }\n\n    private void GenerateLiftAtomicPathLemmaForNormalPath(AtomicPath lAtomicPath, AtomicPath hAtomicPath)\n    {\n      var lname = lAtomicPath.Name;\n      var hname = hAtomicPath.Name;\n\n      var lpr = new PrefixedVarsPathPrinter(lAtomic);\n      var hpr = new PrefixedVarsPathPrinter(hAtomic);\n\n      string extraProof = \"\";\n      if (lAtomicPath.StartType == PCAtomicType.Yielding)\n      {\n        extraProof = @\"\n          var lpc := ls.s.threads[tid].pc;\n          assert !L.Armada_IsNonyieldingPC(lpc);\n        \";\n        if (canIntroduceTau)\n        {\n          extraProof += @\"\n          assert !CanIntroduceTau(hs, tid);\n          lemma_AlwaysIfLStoreBufferEmptyAndCantIntroduceTauThenHStoreBufferEmpty();\n          lemma_AppendingHiddenStoreBufferEntryAlwaysDoesntAffectLowLevel(tid);\n          \";\n        }\n      }\n      string yieldingDependentRequires =\n        (lAtomicPath.StartType == PCAtomicType.Yielding && canIntroduceTau) ? \"requires !CanIntroduceTau(hs, tid)\" : \"\";\n\n      string str = $@\"\n        lemma lemma_VarIntroThreadInvariantMaintainedByAtomicPath_{lname}(\n          lasf: AtomicSpecFunctions<LPlusState, LAtomic_Path, L.Armada_PC>,\n          hasf: AtomicSpecFunctions<HState, HAtomic_Path, H.Armada_PC>,\n          ls: LPlusState,\n          lpath: LAtomic_Path,\n          tid: Armada_ThreadHandle,\n          hs: HState,\n          hpath: HAtomic_Path,\n          hs': HState\n          )\n          requires lasf == LAtomic_GetSpecFunctions()\n          requires hasf == HAtomic_GetSpecFunctions()\n          requires LiftingRelation(ls, hs)\n          requires LAtomic_ValidPath(ls, lpath, tid)\n          requires lpath.LAtomic_Path_{lname}?\n          requires tid in ls.s.threads\n          requires tid in hs.threads\n          { yieldingDependentRequires }\n          requires hs.threads[tid].pc.{hAtomicPath.StartPC}?\n          requires hpath == ConvertAtomicPath_LH(lpath)\n          requires HAtomic_ValidPath(hs, hpath, tid)\n          requires hs' == HAtomic_GetStateAfterPath(hs, hpath, tid)\n          ensures  forall other_tid :: other_tid in hs'.threads ==> VarIntroThreadInvariant(hs', other_tid)\n        {{\n          { lpr.GetOpenValidPathInvocation(lAtomicPath) }\n\n          var ls' := LAtomic_GetStateAfterPath(ls, lpath, tid);\n\n          { hpr.GetOpenPathInvocation(hAtomicPath) }\n          ProofCustomizationGoesHere();\n\n          forall other_tid | other_tid in hs'.threads\n            ensures VarIntroThreadInvariant(hs', other_tid)\n          {{\n            assert other_tid in hs.threads ==> VarIntroThreadInvariant(hs, other_tid);\n            if other_tid == tid {{\n              assert VarIntroThreadInvariant(hs', other_tid);\n            }}\n            else {{\n              assert VarIntroThreadInvariant(hs', other_tid);\n            }}\n          }}\n        }}\n      \";\n      pgp.AddLemma(str, \"lift\");\n\n      if (!lAtomicPath.Stopping)\n      {\n        string postcondition;\n        if (lAtomicPath.LastNextRoutine.nextType == NextType.TerminateThread)\n        {\n          postcondition = \"tid !in ls'.s.threads && tid !in alt_ls'.threads\";\n        }\n        else\n        {\n          postcondition = \"tid in ls'.s.threads && tid in alt_ls'.threads && ls'.s.threads[tid] == alt_ls'.threads[tid]\";\n        }\n        str = $@\"\n        lemma lemma_ActingThreadMatchesLHMaintainedByAtomicPath_{lname}(\n          lasf: AtomicSpecFunctions<LPlusState, LAtomic_Path, L.Armada_PC>,\n          hasf: AtomicSpecFunctions<HState, HAtomic_Path, H.Armada_PC>,\n          ls: LPlusState,\n          lpath: LAtomic_Path,\n          tid: Armada_ThreadHandle,\n          hs: HState,\n          hpath: HAtomic_Path,\n          hs': HState\n          )\n          requires lasf == LAtomic_GetSpecFunctions()\n          requires hasf == HAtomic_GetSpecFunctions()\n          requires LiftingRelation(ls, hs)\n          requires LAtomic_ValidPath(ls, lpath, tid)\n          requires lpath.LAtomic_Path_{lname}?\n          requires tid in ls.s.threads\n          requires tid in hs.threads\n          { yieldingDependentRequires }\n          requires hs.threads[tid].pc.{hAtomicPath.StartPC}?\n          requires hpath == ConvertAtomicPath_LH(lpath)\n          requires HAtomic_ValidPath(hs, hpath, tid)\n          requires hs' == HAtomic_GetStateAfterPath(hs, hpath, tid)\n          ensures  var ls' := LAtomic_GetStateAfterPath(ls, lpath, tid);\n                   var alt_ls' := ConvertTotalState_HL(hs');\n                   { postcondition }\n        {{\n          { lpr.GetOpenValidPathInvocation(lAtomicPath) }\n\n          var ls' := LAtomic_GetStateAfterPath(ls, lpath, tid);\n\n          { hpr.GetOpenPathInvocation(hAtomicPath) }\n          ProofCustomizationGoesHere();\n          { extraProof }\n\n          lemma_GetThreadLocalViewAlwaysCommutesWithConvert();\n          lemma_StoreBufferAppendAlwaysCommutesWithConvert();\n        }}\n        \";\n        pgp.AddLemma(str, \"lift\");\n\n        foreach (var tup in lAtomicPath.NextRoutinesWithIndices)\n        {\n          var nextRoutine = tup.Item1;\n          if (nextRoutine.nextType == NextType.CreateThread)\n          {\n            var whichStep = tup.Item2;\n            str = $@\"\n        lemma lemma_ThreadCreatedInStep{whichStep}MatchesLHMaintainedByAtomicPath_{lname}(\n          lasf: AtomicSpecFunctions<LPlusState, LAtomic_Path, L.Armada_PC>,\n          hasf: AtomicSpecFunctions<HState, HAtomic_Path, H.Armada_PC>,\n          ls: LPlusState,\n          lpath: LAtomic_Path,\n          tid: Armada_ThreadHandle,\n          hs: HState,\n          hpath: HAtomic_Path,\n          hs': HState\n          )\n          requires lasf == LAtomic_GetSpecFunctions()\n          requires hasf == HAtomic_GetSpecFunctions()\n          requires LiftingRelation(ls, hs)\n          requires LAtomic_ValidPath(ls, lpath, tid)\n          requires lpath.LAtomic_Path_{lname}?\n          requires tid in ls.s.threads\n          requires tid in hs.threads\n          { yieldingDependentRequires }\n          requires hs.threads[tid].pc.{hAtomicPath.StartPC}?\n          requires hpath == ConvertAtomicPath_LH(lpath)\n          requires HAtomic_ValidPath(hs, hpath, tid)\n          requires hs' == HAtomic_GetStateAfterPath(hs, hpath, tid)\n          requires lpath.steps_{lAtomicPath.Name}.step{whichStep}.Armada_Step_{nextRoutine.NameSuffix}?\n          ensures  var ls' := LAtomic_GetStateAfterPath(ls, lpath, tid);\n                   var alt_ls' := ConvertTotalState_HL(hs');\n                   var newtid := lpath.steps_{lAtomicPath.Name}.step{whichStep}.params_{nextRoutine.NameSuffix}.newtid;\n                   newtid in ls'.s.threads && newtid in alt_ls'.threads && ls'.s.threads[newtid] == alt_ls'.threads[newtid]\n        {{\n          { lpr.GetOpenValidPathInvocation(lAtomicPath) }\n\n          var ls' := LAtomic_GetStateAfterPath(ls, lpath, tid);\n\n          { hpr.GetOpenPathInvocation(hAtomicPath) }\n          ProofCustomizationGoesHere();\n          { extraProof }\n\n          lemma_GetThreadLocalViewAlwaysCommutesWithConvert();\n          lemma_StoreBufferAppendAlwaysCommutesWithConvert();\n        }}\n          \";\n            pgp.AddLemma(str, \"lift\");\n          }\n        }\n\n        var threadNotCreatedRequires = String.Concat(lAtomicPath.NextRoutinesWithIndices\n          .Where(tup => tup.Item1.nextType == NextType.CreateThread)\n          .Select(tup => $@\"\n             requires lpath.steps_{lAtomicPath.Name}.step{tup.Item2}.Armada_Step_{tup.Item1.NameSuffix}?\n             requires any_tid != lpath.steps_{lAtomicPath.Name}.step{tup.Item2}.params_{tup.Item1.NameSuffix}.newtid\n          \")\n        );\n        str = $@\"\n        lemma lemma_NonactingThreadMatchesLHMaintainedByAtomicPath_{lname}(\n          lasf: AtomicSpecFunctions<LPlusState, LAtomic_Path, L.Armada_PC>,\n          hasf: AtomicSpecFunctions<HState, HAtomic_Path, H.Armada_PC>,\n          ls: LPlusState,\n          lpath: LAtomic_Path,\n          tid: Armada_ThreadHandle,\n          hs: HState,\n          hpath: HAtomic_Path,\n          hs': HState,\n          any_tid: Armada_ThreadHandle\n          )\n          requires lasf == LAtomic_GetSpecFunctions()\n          requires hasf == HAtomic_GetSpecFunctions()\n          requires LiftingRelation(ls, hs)\n          requires LAtomic_ValidPath(ls, lpath, tid)\n          requires lpath.LAtomic_Path_{lname}?\n          requires tid in ls.s.threads\n          requires tid in hs.threads\n          { yieldingDependentRequires }\n          requires hs.threads[tid].pc.{hAtomicPath.StartPC}?\n          requires hpath == ConvertAtomicPath_LH(lpath)\n          requires HAtomic_ValidPath(hs, hpath, tid)\n          requires hs' == HAtomic_GetStateAfterPath(hs, hpath, tid)\n          requires any_tid != tid\n          { threadNotCreatedRequires }\n          ensures  var ls' := LAtomic_GetStateAfterPath(ls, lpath, tid);\n                   var alt_ls' := ConvertTotalState_HL(hs');\n                   if any_tid !in ls'.s.threads then\n                     any_tid !in alt_ls'.threads\n                   else\n                     && any_tid in alt_ls'.threads\n                     && ls'.s.threads[any_tid] == alt_ls'.threads[any_tid]\n        {{\n          { lpr.GetOpenValidPathInvocation(lAtomicPath) }\n\n          var ls' := LAtomic_GetStateAfterPath(ls, lpath, tid);\n\n          { hpr.GetOpenPathInvocation(hAtomicPath) }\n          ProofCustomizationGoesHere();\n          { extraProof }\n\n          lemma_GetThreadLocalViewAlwaysCommutesWithConvert();\n          lemma_StoreBufferAppendAlwaysCommutesWithConvert();\n        }}\n        \";\n        pgp.AddLemma(str, \"lift\");\n      }\n\n      str = $@\"\n        lemma lemma_LiftAtomicPath_{lname}(\n          lasf: AtomicSpecFunctions<LPlusState, LAtomic_Path, L.Armada_PC>,\n          hasf: AtomicSpecFunctions<HState, HAtomic_Path, H.Armada_PC>,\n          ls: LPlusState,\n          lpath: LAtomic_Path,\n          tid: Armada_ThreadHandle,\n          hs: HState\n          ) returns (\n          hpath: HAtomic_Path\n          )\n          requires lasf == LAtomic_GetSpecFunctions()\n          requires hasf == HAtomic_GetSpecFunctions()\n          requires InductiveInv(ls)\n          requires LiftingRelation(ls, hs)\n          requires LAtomic_ValidPath(ls, lpath, tid)\n          requires lpath.LAtomic_Path_{lname}?\n          requires tid in ls.s.threads\n          requires tid in hs.threads\n          { yieldingDependentRequires }\n          requires hs.threads[tid].pc.{hAtomicPath.StartPC}?\n          ensures  LiftAtomicPathSuccessful(lasf, hasf, InductiveInv, LiftingRelation, ls, lpath, tid, hs, hpath)\n        {{\n          { lpr.GetOpenValidPathInvocation(lAtomicPath) }\n\n          var locv: H.Armada_SharedMemory := H.Armada_GetThreadLocalView(hs, tid);\n          var ls' := LAtomic_GetStateAfterPath(ls, lpath, tid);\n          hpath := ConvertAtomicPath_LH(lpath);\n          var hs' := HAtomic_GetStateAfterPath(hs, hpath, tid);\n\n          { hpr.GetOpenPathInvocation(hAtomicPath) }\n          ProofCustomizationGoesHere();\n          { extraProof }\n\n          lemma_AtomicPathMaintainsInductiveInv(ls, ls', lpath, tid);\n          assert InductiveInv(ls');\n          lemma_GetThreadLocalViewAlwaysCommutesWithConvert();\n          lemma_StoreBufferAppendAlwaysCommutesWithConvert();\n\n          assert HAtomic_ValidPath(hs, hpath, tid);\n      \";\n      if (lAtomicPath.Stopping)\n      {\n        str += @\"\n          assert !ls'.s.stop_reason.Armada_NotStopped?;\n        \";\n      }\n      else\n      {\n        str += $@\"\n          assert ls'.s.stop_reason.Armada_NotStopped?;\n          var alt_ls' := ConvertTotalState_HL(hs');\n          assert ls'.s.stop_reason == alt_ls'.stop_reason;\n          forall any_tid\n            ensures any_tid !in ls'.s.threads ==> any_tid !in alt_ls'.threads\n            ensures any_tid in ls'.s.threads ==> any_tid in alt_ls'.threads && ls'.s.threads[any_tid] == alt_ls'.threads[any_tid]\n          {{\n            if any_tid == tid {{\n              lemma_ActingThreadMatchesLHMaintainedByAtomicPath_{lname}(lasf, hasf, ls, lpath, tid, hs, hpath, hs');\n            }}\n        \";\n        foreach (var tup in lAtomicPath.NextRoutinesWithIndices)\n        {\n          var nextRoutine = tup.Item1;\n          if (nextRoutine.nextType == NextType.CreateThread)\n          {\n            var whichStep = tup.Item2;\n            str += $@\"\n            else if any_tid == lsteps.step{whichStep}.params_{nextRoutine.NameSuffix}.newtid {{\n              lemma_ThreadCreatedInStep{whichStep}MatchesLHMaintainedByAtomicPath_{lname}(lasf, hasf, ls, lpath, tid, hs, hpath, hs');\n            }}\n            \";\n          }\n        }\n        str += $@\"\n            else {{\n              lemma_NonactingThreadMatchesLHMaintainedByAtomicPath_{lname}(lasf, hasf, ls, lpath, tid, hs, hpath, hs', any_tid);\n            }}\n          }}\n          assert ls'.s.threads == alt_ls'.threads;\n          assert ls'.s.mem == alt_ls'.mem;\n          assert ls'.s == alt_ls';\n        \";\n      }\n      str += $@\"\n          lemma_VarIntroThreadInvariantMaintainedByAtomicPath_{lname}(lasf, hasf, ls, lpath, tid, hs, hpath, hs');\n          assert LiftingRelation(ls', hs');\n        }}\n      \";\n      pgp.AddLemma(str, \"lift\");\n    }\n\n    private void GenerateIntroduceOrLiftAtomicPathLemmaForNormalPath(AtomicPath lAtomicPath)\n    {\n      var name = lAtomicPath.Name;\n\n      string finalCases = \"\";\n\n      var hAtomicPath = pathMap[lAtomicPath];\n      GenerateLiftAtomicPathLemmaForNormalPath(lAtomicPath, hAtomicPath);\n\n      finalCases += $@\"\n        if hpc.{hAtomicPath.StartPC}? {{\n          hpath := lemma_LiftAtomicPath_{name}(lasf, hasf, ls, lpath, tid, hs);\n          assert LiftAtomicPathSuccessful(lasf, hasf, InductiveInv, LiftingRelation, ls, lpath, tid, hs, hpath);\n          return;\n        }}\n      \";\n\n      List<AtomicPath> introducedPaths;\n      if (pcToIntroducedPaths.TryGetValue(lAtomicPath.StartPC, out introducedPaths)) {\n        foreach (var introducedPath in introducedPaths) {\n          finalCases += $@\"\n            if hpc.{introducedPath.StartPC}? {{\n              hpath := lemma_IntroduceAtomicPath_{introducedPath.Name}(lasf, hasf, ls, lpath, tid, hs);\n              assert AtomicPathIntroduced(lasf, hasf, LiftingRelation, ProgressMeasure, ls, lpath, tid, hs, hpath);\n              return;\n            }}\n          \";\n        }\n      }\n\n      string extraProof = \"\";\n      if (lAtomicPath.StartType == PCAtomicType.Yielding) {\n        extraProof = \"assert !L.Armada_IsNonyieldingPC(lpc);\\n\";\n        if (canIntroduceTau) {\n          extraProof += \"assert !CanIntroduceTau(hs, tid);\\n\";\n        }\n      }\n\n      string yieldingRequires =\n        canIntroduceTau ? \"requires !Armada_ThreadYielding(LPlus_GetSpecFunctions(), ls, tid) || !CanIntroduceTau(hs, tid)\" : \"\";\n\n      string str = $@\"\n        lemma lemma_IntroduceOrLiftAtomicPath_{name}(\n          lasf: AtomicSpecFunctions<LPlusState, LAtomic_Path, L.Armada_PC>,\n          hasf: AtomicSpecFunctions<HState, HAtomic_Path, H.Armada_PC>,\n          ls: LPlusState,\n          lpath: LAtomic_Path,\n          tid: Armada_ThreadHandle,\n          hs: HState\n          ) returns (\n          hpath: HAtomic_Path\n          )\n          requires lasf == LAtomic_GetSpecFunctions()\n          requires hasf == HAtomic_GetSpecFunctions()\n          requires InductiveInv(ls)\n          requires LiftingRelation(ls, hs)\n          requires LAtomic_ValidPath(ls, lpath, tid)\n          requires lpath.LAtomic_Path_{name}?\n          { yieldingRequires }\n          ensures  LiftAtomicPathSuccessful(lasf, hasf, InductiveInv, LiftingRelation, ls, lpath, tid, hs, hpath)\n                   || AtomicPathIntroduced(lasf, hasf, LiftingRelation, ProgressMeasure, ls, lpath, tid, hs, hpath)\n        {{\n          lemma_LAtomic_PathHasPCEffect_{lAtomicPath.Name}(ls, lpath, tid);\n          assert tid in ls.s.threads;\n          assert tid in hs.threads;\n          var lpc := ls.s.threads[tid].pc;\n          var hpc := hs.threads[tid].pc;\n          assert lpc.{lAtomicPath.StartPC}?;\n          assert VarIntroThreadInvariant(hs, tid);\n          { extraProof }\n          { finalCases }\n          assert false;\n        }}\n      \";\n      pgp.AddLemma(str, \"lift\");\n    }\n\n    private void GenerateIntroduceOrLiftAtomicPathLemmas()\n    {\n      GenerateIntroduceNormalPathLemmas();\n      if (canIntroduceTau) {\n        GenerateIntroduceAtomicPathLemmaForTauPath();\n      }\n      GenerateLiftAtomicPathLemmaForTauPath();\n\n      var finalCases = @\"\n        case LAtomic_Path_Tau(_) =>\n          hpath := lemma_LiftAtomicPath_Tau(lasf, hasf, ls, lpath, tid, hs);\n          assert LiftAtomicPathSuccessful(lasf, hasf, InductiveInv, LiftingRelation, ls, lpath, tid, hs, hpath);\n      \";\n\n      foreach (var atomicPath in lAtomic.AtomicPaths.Where(ap => !ap.Tau)) {\n        GenerateIntroduceOrLiftAtomicPathLemmaForNormalPath(atomicPath);\n        finalCases += $@\"\n          case LAtomic_Path_{atomicPath.Name}(_) =>\n            hpath := lemma_IntroduceOrLiftAtomicPath_{atomicPath.Name}(lasf, hasf, ls, lpath, tid, hs);\n        \";\n      }\n\n      string tauIntroduction = \"\";\n      if (canIntroduceTau) {\n        tauIntroduction = $@\"\n          if (lpath.LAtomic_Path_Tau? || Armada_ThreadYielding(LPlus_GetSpecFunctions(), ls, tid)) && CanIntroduceTau(hs, tid) {{\n            hpath := lemma_IntroduceAtomicPath_Tau(lasf, hasf, ls, lpath, tid, hs);\n            assert AtomicPathIntroduced(lasf, hasf, LiftingRelation, ProgressMeasure, ls, lpath, tid, hs, hpath);\n            return;\n          }}\n        \";\n      }\n\n      string str = $@\"\n        lemma lemma_EstablishAtomicPathLiftable(\n          lasf: AtomicSpecFunctions<LPlusState, LAtomic_Path, L.Armada_PC>,\n          hasf: AtomicSpecFunctions<HState, HAtomic_Path, H.Armada_PC>,\n          ls: LPlusState,\n          lpath: LAtomic_Path,\n          tid: Armada_ThreadHandle,\n          hs: HState\n          ) returns (\n          hpath: HAtomic_Path\n          )\n          requires lasf == LAtomic_GetSpecFunctions()\n          requires hasf == HAtomic_GetSpecFunctions()\n          requires InductiveInv(ls)\n          requires LiftingRelation(ls, hs)\n          requires LAtomic_ValidPath(ls, lpath, tid)\n          ensures  LiftAtomicPathSuccessful(lasf, hasf, InductiveInv, LiftingRelation, ls, lpath, tid, hs, hpath)\n                   || AtomicPathIntroduced(lasf, hasf, LiftingRelation, ProgressMeasure, ls, lpath, tid, hs, hpath)\n        {{\n          lemma_LAtomic_PathImpliesThreadRunning(ls, lpath, tid);\n          { tauIntroduction }\n\n          match lpath {{\n            { finalCases }\n          }}\n        }}\n      \";\n      pgp.AddLemma(str);\n    }\n  };\n};\n"
  },
  {
    "path": "Source/Armada/Weakening.cs",
    "content": "using System;\nusing System.Numerics;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text;\nusing System.Text.RegularExpressions;\nusing static Microsoft.Armada.Predicate;\nusing IToken = Microsoft.Boogie.IToken;\nusing Token = Microsoft.Boogie.Token;\n\nnamespace Microsoft.Armada {\n\n  public class WeakeningProofGenerator : AbstractProofGenerator\n  {\n    private WeakeningStrategyDecl strategy;\n\n    public WeakeningProofGenerator(ProofGenerationParams i_pgp, WeakeningStrategyDecl i_strategy)\n      : base(i_pgp)\n    {\n      strategy = i_strategy;\n    }\n\n    protected override void AddIncludesAndImports()\n    {\n      base.AddIncludesAndImports();\n      \n      pgp.MainProof.AddImport(\"InvariantsModule\");\n\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/option.s.dfy\");\n      pgp.MainProof.AddImport(\"util_option_s\");\n\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/seqs.s.dfy\");\n      pgp.MainProof.AddImport(\"util_collections_seqs_s\");\n\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/seqs.i.dfy\");\n      pgp.MainProof.AddImport(\"util_collections_seqs_i\");\n\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/sets.i.dfy\");\n      pgp.MainProof.AddImport(\"util_collections_sets_i\");\n\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/util/collections/maps.i.dfy\");\n      pgp.MainProof.AddImport(\"util_collections_maps_i\");\n\n      pgp.MainProof.AddInclude(ArmadaOptions.O.ArmadaCommonDefsPath + \"/Armada/strategies/generic/GenericArmadaLemmas.i.dfy\");\n      pgp.MainProof.AddImport(\"GenericArmadaLemmasModule\");\n    }\n\n    public override void GenerateProof()\n    {\n      if (!CheckEquivalence()) {\n        AH.PrintError(pgp.prog, \"Levels {pgp.mLow.Name} and {pgp.mHigh.Name} aren't sufficiently equivalent to perform refinement proof generation using the variable-hiding strategy\");\n        return;\n      }\n      AddIncludesAndImports();\n\n      GeneratePCFunctions_L();\n      MakeTrivialPCMap();\n      GenerateNextRoutineMap();\n      GenerateProofHeader();\n      GenerateAtomicSpecs();\n      GenerateInvariantProof(pgp);\n      GenerateStateAbstractionFunctions_LH();\n      GenerateConvertStep_LH();\n      GenerateConvertAtomicPath_LH();\n      GenerateLocalViewCommutativityLemmas();\n      GenerateLiftingRelation();\n      GenerateLiftAtomicPathLemmas();\n      GenerateEstablishInitRequirementsLemma();\n      GenerateEstablishStateOKRequirementLemma();\n      GenerateEstablishRelationRequirementLemma();\n      GenerateEstablishAtomicPathLiftableLemma();\n      GenerateEstablishAtomicPathsLiftableLemma(false, false);\n      GenerateLiftLAtomicToHAtomicLemma(false, false);\n      GenerateFinalProof();\n    }\n  }\n}\n"
  },
  {
    "path": "Source/Armada.sln",
    "content": "﻿\r\nMicrosoft Visual Studio Solution File, Format Version 12.00\r\n# Visual Studio 15\r\nVisualStudioVersion = 15.0.26124.0\r\nMinimumVisualStudioVersion = 15.0.26124.0\r\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ArmadaPipeline\", \"Armada\\ArmadaPipeline.csproj\", \"{72BD1091-3EA2-4AC0-9389-5D010673F0B2}\"\r\nEndProject\r\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"ArmadaDriver\", \"ArmadaDriver\\ArmadaDriver.csproj\", \"{F433648A-954A-4326-B37E-3383095D2EB4}\"\r\nEndProject\r\nGlobal\r\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\r\n\t\tDebug|Any CPU = Debug|Any CPU\r\n\t\tDebug|x64 = Debug|x64\r\n\t\tDebug|x86 = Debug|x86\r\n\t\tRelease|Any CPU = Release|Any CPU\r\n\t\tRelease|x64 = Release|x64\r\n\t\tRelease|x86 = Release|x86\r\n\tEndGlobalSection\r\n\tGlobalSection(SolutionProperties) = preSolution\r\n\t\tHideSolutionNode = FALSE\r\n\tEndGlobalSection\r\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\r\n\t\t{72BD1091-3EA2-4AC0-9389-5D010673F0B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{72BD1091-3EA2-4AC0-9389-5D010673F0B2}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{72BD1091-3EA2-4AC0-9389-5D010673F0B2}.Debug|x64.ActiveCfg = Debug|Any CPU\r\n\t\t{72BD1091-3EA2-4AC0-9389-5D010673F0B2}.Debug|x64.Build.0 = Debug|Any CPU\r\n\t\t{72BD1091-3EA2-4AC0-9389-5D010673F0B2}.Debug|x86.ActiveCfg = Debug|Any CPU\r\n\t\t{72BD1091-3EA2-4AC0-9389-5D010673F0B2}.Debug|x86.Build.0 = Debug|Any CPU\r\n\t\t{72BD1091-3EA2-4AC0-9389-5D010673F0B2}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{72BD1091-3EA2-4AC0-9389-5D010673F0B2}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{72BD1091-3EA2-4AC0-9389-5D010673F0B2}.Release|x64.ActiveCfg = Release|Any CPU\r\n\t\t{72BD1091-3EA2-4AC0-9389-5D010673F0B2}.Release|x64.Build.0 = Release|Any CPU\r\n\t\t{72BD1091-3EA2-4AC0-9389-5D010673F0B2}.Release|x86.ActiveCfg = Release|Any CPU\r\n\t\t{72BD1091-3EA2-4AC0-9389-5D010673F0B2}.Release|x86.Build.0 = Release|Any CPU\r\n\t\t{F433648A-954A-4326-B37E-3383095D2EB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{F433648A-954A-4326-B37E-3383095D2EB4}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{F433648A-954A-4326-B37E-3383095D2EB4}.Debug|x64.ActiveCfg = Debug|Any CPU\r\n\t\t{F433648A-954A-4326-B37E-3383095D2EB4}.Debug|x64.Build.0 = Debug|Any CPU\r\n\t\t{F433648A-954A-4326-B37E-3383095D2EB4}.Debug|x86.ActiveCfg = Debug|Any CPU\r\n\t\t{F433648A-954A-4326-B37E-3383095D2EB4}.Debug|x86.Build.0 = Debug|Any CPU\r\n\t\t{F433648A-954A-4326-B37E-3383095D2EB4}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{F433648A-954A-4326-B37E-3383095D2EB4}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{F433648A-954A-4326-B37E-3383095D2EB4}.Release|x64.ActiveCfg = Release|Any CPU\r\n\t\t{F433648A-954A-4326-B37E-3383095D2EB4}.Release|x64.Build.0 = Release|Any CPU\r\n\t\t{F433648A-954A-4326-B37E-3383095D2EB4}.Release|x86.ActiveCfg = Release|Any CPU\r\n\t\t{F433648A-954A-4326-B37E-3383095D2EB4}.Release|x86.Build.0 = Release|Any CPU\r\n\tEndGlobalSection\r\nEndGlobal\r\n"
  },
  {
    "path": "Source/ArmadaDriver/ArmadaDriver.cs",
    "content": "//-----------------------------------------------------------------------------\n//\n// Copyright (C) Microsoft Corporation.  All Rights Reserved.\n//\n//-----------------------------------------------------------------------------\n//---------------------------------------------------------------------------------------------\n// DafnyDriver\n//       - main program for taking a Dafny program and verifying it\n//---------------------------------------------------------------------------------------------\n\nnamespace Microsoft.Armada\n{\n  using System;\n  using System.Collections.Generic;\n  using System.Collections.ObjectModel;\n  using System.Diagnostics.Contracts;\n  using System.IO;\n  using System.Linq;\n\n  using Microsoft.Boogie;\n  using Bpl = Microsoft.Boogie;\n  using System.Diagnostics;\n\n  public class DafnyDriver\n  {\n    public enum ExitValue { VERIFIED = 0, PREPROCESSING_ERROR, DAFNY_ERROR, COMPILE_ERROR, NOT_VERIFIED }\n\n    public static int Main(string[] args)\n    {\n      Console.WriteLine(\"Starting Armada\");\n      int ret = 0;\n      var thread = new System.Threading.Thread(\n        new System.Threading.ThreadStart(() =>\n          { ret = ThreadMain(args); }),\n          0x10000000); // 256MB stack size to prevent stack overflow\n      thread.Start();\n      thread.Join();\n      return ret;\n    }\n\n    public static int ThreadMain(string[] args)\n    {\n      Contract.Requires(cce.NonNullElements(args));\n\n      ErrorReporter reporter = new ConsoleErrorReporter();\n      ExecutionEngine.printer = new DafnyConsolePrinter(); // For boogie errors\n\n      ArmadaOptions.Install(new ArmadaOptions(reporter));\n\n      List<DafnyFile> dafnyFiles;\n      List<string> otherFiles;\n\n      ExitValue exitValue = ProcessCommandLineArguments(args, out dafnyFiles, out otherFiles);\n\n      if (exitValue == ExitValue.VERIFIED)\n      {\n        exitValue = ProcessFiles(dafnyFiles, otherFiles.AsReadOnly(), reporter);\n      }\n\n      if (CommandLineOptions.Clo.XmlSink != null) {\n        CommandLineOptions.Clo.XmlSink.Close();\n      }\n      if (CommandLineOptions.Clo.Wait)\n      {\n        Console.WriteLine(\"Press Enter to exit.\");\n        Console.ReadLine();\n      }\n      if (!ArmadaOptions.O.CountVerificationErrors && exitValue != ExitValue.PREPROCESSING_ERROR)\n      {\n        return 0;\n      }\n      //Console.ReadKey();\n      return (int)exitValue;\n    }\n\n    public static ExitValue ProcessCommandLineArguments(string[] args, out List<DafnyFile> dafnyFiles, out List<string> otherFiles)\n    {\n      dafnyFiles = new List<DafnyFile>();\n      otherFiles = new List<string>();\n\n      CommandLineOptions.Clo.RunningBoogieFromCommandLine = true;\n      try {\n        if (!CommandLineOptions.Clo.Parse(args)) {\n          return ExitValue.PREPROCESSING_ERROR;\n        }\n      } catch (ProverException pe) {\n        ExecutionEngine.printer.ErrorWriteLine(Console.Out, \"*** ProverException: {0}\", pe.Message);\n        return ExitValue.PREPROCESSING_ERROR;\n      }\n\n      if (CommandLineOptions.Clo.Files.Count == 0)\n      {\n        ExecutionEngine.printer.ErrorWriteLine(Console.Out, \"*** Error: No input files were specified.\");\n        return ExitValue.PREPROCESSING_ERROR;\n      }\n      if (CommandLineOptions.Clo.XmlSink != null) {\n        string errMsg = CommandLineOptions.Clo.XmlSink.Open();\n        if (errMsg != null) {\n          ExecutionEngine.printer.ErrorWriteLine(Console.Out, \"*** Error: \" + errMsg);\n          return ExitValue.PREPROCESSING_ERROR;\n        }\n      }\n      if (CommandLineOptions.Clo.ShowEnv == CommandLineOptions.ShowEnvironment.Always)\n      {\n        Console.WriteLine(\"---Command arguments\");\n        foreach (string arg in args)\n        {Contract.Assert(arg != null);\n          Console.WriteLine(arg);\n        }\n        Console.WriteLine(\"--------------------\");\n      }\n\n      foreach (string file in CommandLineOptions.Clo.Files)\n      { Contract.Assert(file != null);\n        string extension = Path.GetExtension(file);\n        if (extension != null) { extension = extension.ToLower(); }\n        try { dafnyFiles.Add(new DafnyFile(file)); } catch (IllegalDafnyFile) {\n          if (ArmadaOptions.O.CompileTarget == ArmadaOptions.CompilationTarget.Clight) {\n            if (extension == \".h\") {\n              otherFiles.Add(file);\n            } else {\n              ExecutionEngine.printer.ErrorWriteLine(Console.Out, \"*** Error: '{0}': Filename extension '{1}' is not supported. Input files must be Dafny programs (.dfy) or C headers (.h)\", file,\n                extension == null ? \"\" : extension);\n              return ExitValue.PREPROCESSING_ERROR;\n            }\n          }\n        }\n      }\n      return ExitValue.VERIFIED;\n    }\n\n    static ExitValue ProcessFiles(IList<DafnyFile/*!*/>/*!*/ dafnyFiles, ReadOnlyCollection<string> otherFileNames,\n                                  ErrorReporter reporter, bool lookForSnapshots = true, string programId = null)\n   {\n      Contract.Requires(cce.NonNullElements(dafnyFiles));\n      var dafnyFileNames = DafnyFile.fileNames(dafnyFiles);\n\n      ExitValue exitValue = ExitValue.VERIFIED;\n      if (CommandLineOptions.Clo.VerifySeparately && 1 < dafnyFiles.Count)\n      {\n        foreach (var f in dafnyFiles)\n        {\n          Console.WriteLine();\n          Console.WriteLine(\"-------------------- {0} --------------------\", f);\n          var ev = ProcessFiles(new List<DafnyFile> { f }, new List<string>().AsReadOnly(), reporter, lookForSnapshots, f.FilePath);\n          if (exitValue != ev && ev != ExitValue.VERIFIED)\n          {\n            exitValue = ev;\n          }\n        }\n        return exitValue;\n      }\n\n      if (0 <= CommandLineOptions.Clo.VerifySnapshots && lookForSnapshots)\n      {\n        var snapshotsByVersion = ExecutionEngine.LookForSnapshots(dafnyFileNames);\n        foreach (var s in snapshotsByVersion)\n        {\n          var snapshots = new List<DafnyFile>();\n          foreach (var f in s) {\n            snapshots.Add(new DafnyFile(f));\n          }\n          var ev = ProcessFiles(snapshots, new List<string>().AsReadOnly(), reporter, false, programId);\n          if (exitValue != ev && ev != ExitValue.VERIFIED)\n          {\n            exitValue = ev;\n          }\n        }\n        return exitValue;\n      }\n\n      Microsoft.Armada.Program dafnyProgram;\n      string programName = dafnyFileNames.Count == 1 ? dafnyFileNames[0] : \"the program\";\n      string err = Microsoft.Armada.Main.ParseCheck(dafnyFiles, programName, reporter, out dafnyProgram);\n\n      if (err != null) {\n        exitValue = ExitValue.DAFNY_ERROR;\n        ExecutionEngine.printer.ErrorWriteLine(Console.Out, err);\n      } else if (dafnyProgram != null && !CommandLineOptions.Clo.NoResolve && !CommandLineOptions.Clo.NoTypecheck\n          && ArmadaOptions.O.DafnyVerify) {\n        var boogiePrograms = Translate(dafnyProgram);\n\n        Dictionary<string, PipelineStatistics> statss;\n        PipelineOutcome oc;\n        string baseName = cce.NonNull(Path.GetFileName(dafnyFileNames[dafnyFileNames.Count - 1]));\n        var verified = Boogie(baseName, boogiePrograms, programId, out statss, out oc);\n        var compiled = Compile(dafnyFileNames[0], otherFileNames, dafnyProgram, oc, statss, verified);\n        exitValue = verified && compiled ? ExitValue.VERIFIED : !verified ? ExitValue.NOT_VERIFIED : ExitValue.COMPILE_ERROR;\n      }\n      else\n      {\n        // Console.WriteLine(\"Force compiling!\");\n        Dictionary<string, PipelineStatistics> statss;\n        PipelineOutcome oc;\n        oc = PipelineOutcome.VerificationCompleted;\n        statss = new Dictionary<string, PipelineStatistics>();\n\n        var compiled = Compile(dafnyFileNames[0], otherFileNames, dafnyProgram, oc, statss, false);\n      }\n\n      if (err == null && dafnyProgram != null && ArmadaOptions.O.PrintStats) {\n        Util.PrintStats(dafnyProgram);\n      }\n      if (err == null && dafnyProgram != null && ArmadaOptions.O.PrintFunctionCallGraph) {\n        Util.PrintFunctionCallGraph(dafnyProgram);\n      }\n      return exitValue;\n    }\n\n    private static string BoogieProgramSuffix(string printFile, string suffix) {\n      var baseName = Path.GetFileNameWithoutExtension(printFile);\n      var dirName = Path.GetDirectoryName(printFile);\n\n      return Path.Combine(dirName, baseName + \"_\" + suffix + Path.GetExtension(printFile));\n    }\n\n    public static IEnumerable<Tuple<string, Bpl.Program>> Translate(Program dafnyProgram) {\n      var nmodules = Translator.VerifiableModules(dafnyProgram).Count();\n\n\n      foreach (var prog in Translator.Translate(dafnyProgram, dafnyProgram.reporter)) {\n\n        if (CommandLineOptions.Clo.PrintFile != null) {\n\n          var nm = nmodules > 1 ? BoogieProgramSuffix(CommandLineOptions.Clo.PrintFile, prog.Item1) : CommandLineOptions.Clo.PrintFile;\n\n          ExecutionEngine.PrintBplFile(nm, prog.Item2, false, false, CommandLineOptions.Clo.PrettyPrint);\n        }\n\n        yield return prog;\n\n      }\n    }\n\n    public static bool BoogieOnce(string baseFile, string moduleName, Bpl.Program boogieProgram, string programId,\n                              out PipelineStatistics stats, out PipelineOutcome oc)\n    {\n      if (programId == null)\n      {\n        programId = \"main_program_id\";\n      }\n      programId += \"_\" + moduleName;\n\n      string bplFilename;\n      if (CommandLineOptions.Clo.PrintFile != null)\n      {\n        bplFilename = CommandLineOptions.Clo.PrintFile;\n      }\n      else\n      {\n        string baseName = cce.NonNull(Path.GetFileName(baseFile));\n        baseName = cce.NonNull(Path.ChangeExtension(baseName, \"bpl\"));\n        bplFilename = Path.Combine(Path.GetTempPath(), baseName);\n      }\n\n      bplFilename = BoogieProgramSuffix(bplFilename, moduleName);\n      stats = null;\n      oc = BoogiePipelineWithRerun(boogieProgram, bplFilename, out stats, 1 < Microsoft.Armada.ArmadaOptions.Clo.VerifySnapshots ? programId : null);\n      return (oc == PipelineOutcome.Done || oc == PipelineOutcome.VerificationCompleted) && stats.ErrorCount == 0 && stats.InconclusiveCount == 0 && stats.TimeoutCount == 0 && stats.OutOfMemoryCount == 0;\n    }\n\n    public static bool Boogie(string baseName, IEnumerable<Tuple<string, Bpl.Program>> boogiePrograms, string programId, out Dictionary<string, PipelineStatistics> statss, out PipelineOutcome oc) {\n\n      bool isVerified = true;\n      oc = PipelineOutcome.VerificationCompleted;\n      statss = new Dictionary<string, PipelineStatistics>();\n\n      Stopwatch watch = new Stopwatch();\n      watch.Start();\n\n      foreach (var prog in boogiePrograms) {\n        PipelineStatistics newstats;\n        PipelineOutcome newoc;\n\n        if (ArmadaOptions.O.SeparateModuleOutput) {\n          ExecutionEngine.printer.AdvisoryWriteLine(\"For module: {0}\", prog.Item1);\n        }\n\n        isVerified = BoogieOnce(baseName, prog.Item1, prog.Item2, programId, out newstats, out newoc) && isVerified;\n\n        watch.Stop();\n\n        if ((oc == PipelineOutcome.VerificationCompleted || oc == PipelineOutcome.Done) && newoc != PipelineOutcome.VerificationCompleted) {\n          oc = newoc;\n        }\n\n        if (ArmadaOptions.O.SeparateModuleOutput) {\n          TimeSpan ts = watch.Elapsed;\n          string elapsedTime = String.Format(\"{0:00}:{1:00}:{2:00}\",\n            ts.Hours, ts.Minutes, ts.Seconds);\n\n          ExecutionEngine.printer.AdvisoryWriteLine(\"Elapsed time: {0}\", elapsedTime);\n          ExecutionEngine.printer.WriteTrailer(newstats);\n        }\n\n        statss.Add(prog.Item1, newstats);\n        watch.Restart();\n      }\n      watch.Stop();\n\n      return isVerified;\n    }\n\n    private static void WriteStatss(Dictionary<string, PipelineStatistics> statss) {\n      var statSum = new PipelineStatistics();\n      foreach (var stats in statss) {\n        statSum.VerifiedCount += stats.Value.VerifiedCount;\n        statSum.ErrorCount += stats.Value.ErrorCount;\n        statSum.TimeoutCount += stats.Value.TimeoutCount;\n        statSum.OutOfMemoryCount += stats.Value.OutOfMemoryCount;\n        statSum.CachedErrorCount += stats.Value.CachedErrorCount;\n        statSum.CachedInconclusiveCount += stats.Value.CachedInconclusiveCount;\n        statSum.CachedOutOfMemoryCount += stats.Value.CachedOutOfMemoryCount;\n        statSum.CachedTimeoutCount += stats.Value.CachedTimeoutCount;\n        statSum.CachedVerifiedCount += stats.Value.CachedVerifiedCount;\n        statSum.InconclusiveCount += stats.Value.InconclusiveCount;\n      }\n      ExecutionEngine.printer.WriteTrailer(statSum);\n    }\n\n\n    public static bool Compile(string fileName, ReadOnlyCollection<string> otherFileNames, Program dafnyProgram,\n                               PipelineOutcome oc, Dictionary<string, PipelineStatistics> statss, bool verified)\n    {\n      var resultFileName = ArmadaOptions.O.DafnyPrintCompiledFile ?? fileName;\n      bool compiled = true;\n      switch (oc)\n      {\n        case PipelineOutcome.VerificationCompleted:\n          // WriteStatss(statss);\n          if ((ArmadaOptions.O.Compile && verified && CommandLineOptions.Clo.UserConstrainedProcsToCheck) || ArmadaOptions.O.ForceCompile) {\n            Console.WriteLine(\"Invoke Compiler = True\");\n            compiled = CompileDafnyProgram(dafnyProgram, resultFileName, otherFileNames, true);\n          } else if ((2 <= ArmadaOptions.O.SpillTargetCode && verified && !CommandLineOptions.Clo.UserConstrainedProcsToCheck) || 3 <= ArmadaOptions.O.SpillTargetCode) {\n            Console.WriteLine(\"Invoke Compiler = False\");\n            compiled = CompileDafnyProgram(dafnyProgram, resultFileName, otherFileNames, false);\n          }\n          break;\n        case PipelineOutcome.Done:\n          // Console.WriteLine(\"Done\");\n          // WriteStatss(statss);\n          if (ArmadaOptions.O.ForceCompile || 3 <= ArmadaOptions.O.SpillTargetCode) {\n            compiled = CompileDafnyProgram(dafnyProgram, resultFileName, otherFileNames, ArmadaOptions.O.ForceCompile);\n          }\n          break;\n        default:\n          // error has already been reported to user\n          break;\n      }\n      return compiled;\n    }\n\n    /// <summary>\n    /// Resolve, type check, infer invariants for, and verify the given Boogie program.\n    /// The intention is that this Boogie program has been produced by translation from something\n    /// else.  Hence, any resolution errors and type checking errors are due to errors in\n    /// the translation.\n    /// The method prints errors for resolution and type checking errors, but still returns\n    /// their error code.\n    /// </summary>\n    static PipelineOutcome BoogiePipelineWithRerun(Bpl.Program/*!*/ program, string/*!*/ bplFileName,\n        out PipelineStatistics stats, string programId)\n    {\n      Contract.Requires(program != null);\n      Contract.Requires(bplFileName != null);\n      Contract.Ensures(0 <= Contract.ValueAtReturn(out stats).InconclusiveCount && 0 <= Contract.ValueAtReturn(out stats).TimeoutCount);\n\n      stats = new PipelineStatistics();\n      CivlTypeChecker ctc;\n      PipelineOutcome oc = ExecutionEngine.ResolveAndTypecheck(program, bplFileName, out ctc);\n      switch (oc) {\n        case PipelineOutcome.Done:\n          return oc;\n\n        case PipelineOutcome.ResolutionError:\n        case PipelineOutcome.TypeCheckingError:\n          {\n            ExecutionEngine.PrintBplFile(bplFileName, program, false, false, CommandLineOptions.Clo.PrettyPrint);\n            Console.WriteLine();\n            Console.WriteLine(\"*** Encountered internal translation error - re-running Boogie to get better debug information\");\n            Console.WriteLine();\n\n            List<string/*!*/>/*!*/ fileNames = new List<string/*!*/>();\n            fileNames.Add(bplFileName);\n            Bpl.Program reparsedProgram = ExecutionEngine.ParseBoogieProgram(fileNames, true);\n            if (reparsedProgram != null) {\n              ExecutionEngine.ResolveAndTypecheck(reparsedProgram, bplFileName, out ctc);\n            }\n          }\n          return oc;\n\n        case PipelineOutcome.ResolvedAndTypeChecked:\n          ExecutionEngine.EliminateDeadVariables(program);\n          ExecutionEngine.CollectModSets(program);\n          ExecutionEngine.CoalesceBlocks(program);\n          ExecutionEngine.Inline(program);\n          return ExecutionEngine.InferAndVerify(program, stats, programId);\n\n        default:\n          Contract.Assert(false); throw new cce.UnreachableException();  // unexpected outcome\n      }\n    }\n\n\n    #region Output\n\n    class DafnyConsolePrinter : ConsolePrinter\n    {\n      public override void ReportBplError(IToken tok, string message, bool error, TextWriter tw, string category = null)\n      {\n        // Dafny has 0-indexed columns, but Boogie counts from 1\n        var realigned_tok = new Token(tok.line, tok.col - 1);\n        realigned_tok.kind = tok.kind;\n        realigned_tok.pos = tok.pos;\n        realigned_tok.val = tok.val;\n        realigned_tok.filename = tok.filename;\n        base.ReportBplError(realigned_tok, message, error, tw, category);\n\n        if (tok is Microsoft.Armada.NestedToken)\n        {\n          var nt = (Microsoft.Armada.NestedToken)tok;\n          ReportBplError(nt.Inner, \"Related location\", false, tw);\n        }\n      }\n    }\n\n    #endregion\n\n\n    #region Compilation\n\n    static string WriteDafnyProgramToFiles(string dafnyProgramName, string targetProgram, bool completeProgram, Dictionary<String, String> otherFiles, TextWriter outputWriter)\n    {\n\n      outputWriter.WriteLine(\"Running WriteDafnyProgramToFiles!\");\n      string targetExtension;\n      string baseName = Path.GetFileNameWithoutExtension(dafnyProgramName);\n      string targetBaseDir = \"\";\n      switch (ArmadaOptions.O.CompileTarget) {\n        case ArmadaOptions.CompilationTarget.Clight:\n          targetExtension = \"c\";\n          targetBaseDir = \"\";\n          break;\n        default:\n          Contract.Assert(false);\n          throw new cce.UnreachableException();\n      }\n      string targetBaseName = Path.ChangeExtension(dafnyProgramName, targetExtension);\n      string targetDir = Path.Combine(Path.GetDirectoryName(dafnyProgramName), targetBaseDir);\n      string targetFilename = Path.Combine(targetDir, targetBaseName);\n      if (targetProgram != null) {\n        WriteFile(targetFilename, targetProgram);\n      }\n\n      string relativeTarget = Path.Combine(targetBaseDir, targetBaseName);\n      if (completeProgram && targetProgram != null) {\n        if (ArmadaOptions.O.CompileVerbose) {\n          outputWriter.WriteLine(\"Compiled program written to {0}\", relativeTarget);\n        }\n      }\n      else {\n        outputWriter.WriteLine(\"File {0} contains the partially compiled program\", relativeTarget);\n      }\n\n      foreach (var entry in otherFiles) {\n        var filename = entry.Key;\n        WriteFile(Path.Combine(targetDir, filename), entry.Value);\n        if (ArmadaOptions.O.CompileVerbose) {\n          outputWriter.WriteLine(\"Additional code written to {0}\", Path.Combine(targetBaseDir, filename));\n        }\n      }\n      return targetFilename;\n    }\n\n    static void WriteFile(string filename, string text) {\n      var dir = Path.GetDirectoryName(filename);\n      if (dir != \"\") {\n        Directory.CreateDirectory(dir);\n      }\n\n      using (TextWriter target = new StreamWriter(new FileStream(filename, System.IO.FileMode.Create))) {\n        target.Write(text);\n      }\n    }\n\n    /// <summary>\n    /// Generate a C# program from the Dafny program and, if \"invokeCompiler\" is \"true\", invoke\n    /// the C# compiler to compile it.\n    /// </summary>\n    public static bool CompileDafnyProgram(Microsoft.Armada.Program dafnyProgram, string dafnyProgramName,\n                                           ReadOnlyCollection<string> otherFileNames, bool invokeCompiler,\n                                           TextWriter outputWriter = null)\n    {\n      Contract.Requires(dafnyProgram != null);\n      Contract.Assert(dafnyProgramName != null);\n      Console.WriteLine(\"Running CompileDafnyProgram : {0}\", dafnyProgramName);\n      Console.WriteLine(\"Number of modules = {0}\", dafnyProgram.CompileModules.Count);\n\n      if (outputWriter == null)\n      {\n        outputWriter = Console.Out;\n      }\n\n      // Compile the Dafny program into a string that contains the target program\n      var oldErrorCount = dafnyProgram.reporter.Count(ErrorLevel.Error);\n      Microsoft.Armada.Compiler compiler;\n\n      switch (ArmadaOptions.O.CompileTarget) {\n        case ArmadaOptions.CompilationTarget.Clight:\n        default:\n          compiler = new Microsoft.Armada.ClightTsoCompiler(dafnyProgram.reporter, otherFileNames);\n          break;\n      }\n\n      Method mainMethod;\n      var hasMain = compiler.HasMain(dafnyProgram, out mainMethod);\n      string targetProgramText;\n      var otherFiles = new Dictionary<string, string>();\n      {\n        var fileQueue = new Queue<FileTargetWriter>();\n        using (var wr = new TargetWriter(0)) {\n          compiler.Compile(dafnyProgram, wr);\n          var sw = new StringWriter();\n          wr.Collect(sw, fileQueue);\n          targetProgramText = sw.ToString();\n        }\n\n        while (fileQueue.Count > 0) {\n          var wr = fileQueue.Dequeue();\n          var sw = new StringWriter();\n          wr.Collect(sw, fileQueue);\n          otherFiles.Add(wr.Filename, sw.ToString());\n        }\n      }\n      string baseName = Path.GetFileNameWithoutExtension(dafnyProgramName);\n      string callToMain = null;\n      if (hasMain) {\n        using (var wr = new TargetWriter(0)) {\n          compiler.EmitCallToMain(mainMethod, wr);\n          callToMain = wr.ToString(); // assume there aren't multiple files just to call main\n        }\n      }\n      bool completeProgram = dafnyProgram.reporter.Count(ErrorLevel.Error) == oldErrorCount;\n\n      // blurt out the code to a file, if requested, or if other files were specified for the C# command line.\n      string targetFilename = null;\n      if (ArmadaOptions.O.SpillTargetCode > 0 || otherFileNames.Count > 0 || (invokeCompiler && !compiler.SupportsInMemoryCompilation))\n      {\n        var p = callToMain == null ? targetProgramText : targetProgramText + callToMain;\n        targetFilename = WriteDafnyProgramToFiles(dafnyProgramName, p, completeProgram, otherFiles, outputWriter);\n      }\n\n      // compile the program into an assembly\n      if (!completeProgram || !invokeCompiler) {\n        // don't compile\n        // Caller interprets this as success/fail and returns an error if false,\n        //  but we didn't actually hit an error, we just didn't invoke the compiler\n        return true;\n      }\n\n      // compile the program into an assembly\n      object compilationResult;\n      var compiledCorrectly = compiler.CompileTargetProgram(dafnyProgramName, targetProgramText, callToMain, targetFilename, otherFileNames,\n        hasMain, hasMain && ArmadaOptions.O.RunAfterCompile, outputWriter, out compilationResult);\n      if (compiledCorrectly && ArmadaOptions.O.RunAfterCompile) {\n        if (hasMain) {\n          if (ArmadaOptions.O.CompileVerbose) {\n            outputWriter.WriteLine(\"Running...\");\n            outputWriter.WriteLine();\n          }\n          compiledCorrectly = compiler.RunTargetProgram(dafnyProgramName, targetProgramText, callToMain, targetFilename, otherFileNames, compilationResult, outputWriter);\n        } else {\n          // make sure to give some feedback to the user\n          if (ArmadaOptions.O.CompileVerbose) {\n            outputWriter.WriteLine(\"Program compiled successfully\");\n          }\n        }\n      }\n      return compiledCorrectly;\n    }\n\n    #endregion\n\n  }\n}\n"
  },
  {
    "path": "Source/ArmadaDriver/ArmadaDriver.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\r\n\r\n  <ItemGroup>\r\n    <ProjectReference Include=\"..\\Armada\\ArmadaPipeline.csproj\" />\r\n  </ItemGroup>\r\n\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net5.0|AnyCPU'\">\r\n    <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>\r\n    <AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>\r\n  </PropertyGroup>\r\n\r\n  <PropertyGroup>\r\n    <OutputType>Exe</OutputType>\r\n    <AssemblyName>Armada</AssemblyName>\r\n    <TargetFramework>net5.0</TargetFramework>\r\n    <OutputPath>..\\..\\Binaries\\</OutputPath>\r\n  </PropertyGroup>\r\n\r\n</Project>\r\n"
  },
  {
    "path": "Source/Directory.Build.props",
    "content": "<Project>\n\n  <!-- Target framework -->\n  <PropertyGroup>\n    <TargetFramework>net5.0</TargetFramework>\n  </PropertyGroup>\n\n  <!-- Boogie dependency -->\n  <ItemGroup>\n    <PackageReference Include=\"Boogie.ExecutionEngine\" Version=\"2.8.21\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "Source/dotnet-tools.json",
    "content": "{\n  \"version\": 1,\n  \"isRoot\": true,\n  \"tools\": {\n    \"cocor\": {\n      \"version\": \"2014.12.23\",\n      \"commands\": [\n        \"coco\"\n      ]\n    }\n  }\n}\n"
  },
  {
    "path": "Test/armada-parser/.gitignore",
    "content": "*.dfy\n"
  },
  {
    "path": "Test/armada-parser/OGcounter.arm",
    "content": "// mono --debug $CDFY /compile:0 /dafnyVerify:0 src/armada-parser/Counter_No_CLass.arm\ninclude \"../../Armada/ArmadaCommonDefinitions.dfy\"\ninclude \"../../Armada/util/option.s.dfy\"\n\nlevel CounterLayer1 {\n\tvar x: int32;\n\tvar acquired: Option<uint64>;\n\t// Error: Invalid type for static variable {f.Name}\n\t//ghost var counter_map: map<int, int>;\n\n\t// decl acquire lock\n\tmethod {:extern} Acquire() \n\t\tawaits acquired == None\n\t\tmodifies acquired\n\t\tensures acquired == Some($me)\n\n\t// decl release lock\n\tmethod {:extern} Release() \n\t\trequires acquired == Some($me)\n\t\tmodifies acquired\n\t\tensures acquired == None\n\t\n\t// how to prove / annotate this is an atomic action?\n\tmethod Worker_thread()\n\t{\t\n\t\t//label1:\n\t\tAcquire();\n\t\tx := x + 1;\n\t\t//label2:\n\t\tRelease();\n\t}\n\n\tmethod main() \n\t{\n\t\tx := 0;\n\t\tacquired := Some(-1);\n\t\tvar t1: uint64;\n\t\tvar t2: uint64;\n\t\tt1 := create_thread Worker_thread();\n\t\tt2 := create_thread Worker_thread();\n\t\tjoin t1;\n\t\tjoin t2;\n\t}\n}\n\n// Hide the acquired/lock?\nlevel CounterLayer2 {\n\tvar x: int32;\n\t//var acquired: int32;\n\n\t/*\n\t// decl acquire lock\n\tmethod {:extern} Acquire(tid:int32) \n\t\tawaits acquired == -1\n\t\tmodifies acquired\n\t\tensures acquired == tid\n\n\t// decl release lock\n\tmethod {:extern} Release(tid:int32) \n\t\trequires acquired == tid\n\t\tmodifies acquired\n\t\tensures acquired == -1\n\t*/\n\n\t// Need keyword action ?\n\tmethod Worker_thread(tid:int32)\n\t{\t\n\t\t//Acquire(tid);\n\t\tx := x + 1;\n\t\t//Release(tid);\n\t}\n\n\tmethod main() \n\t{\n\t\tx := 0;\n\t\tvar t1: uint64;\n\t\tvar t2: uint64;\n\t\tt1 := create_thread Worker_thread(1);\n\t\tt2 := create_thread Worker_thread(2);\n\t\tjoin t1;\n\t\tjoin t2;\n\t}\n}\n\n// Remove the thread?\nlevel CounterLayer3 {\n\tvar x: int32;\n\tmethod main()\n\t{\n\t\tx := 0;\n\t\t// par x := x + 1 | x := x + 1;\n\t\tassert(x == 2);\n\t\t// print(x);\n\t}\n\t\n}\n\n\n// Hide the x?\nlevel CounterLayer4 {\n\tmethod main()\n\t{\n\t\tprint(2);\n\t}\n}\n\n\n/*proof level1to2refinement {\n\trefinement CounterLayer1 CounterLayer2\n    // reduction \n\t//var_hiding acquired\n\n}*/\n/*\nproof level3to4refinement {\n\trefinement CounterLayer3 CounterLayer4\n    var_hiding x\n}*/\n"
  },
  {
    "path": "Test/armada-parser/scheduler_atomic.arm",
    "content": "// mono --debug $CDFY /compile:0 /dafnyVerify:0 src/armada-parser/scheduler_atomic.arm\ninclude \"../../Armada/ArmadaCommonDefinitions.dfy\"\ninclude \"../../Armada/option.s.dfy\"\n\n// The level after replacing all locks and cvs with explicit_yield block.\n// Also add some annotation for the servicer.\nlevel atomic_level {\n    type Tid = uint64\n    \n    // the data structure for disk schedule requests.\n    struct Request {\n        // The tid of process sending the request\n        var tid: Option<Tid>;\n\n        // The target disk track.  \n        var track: int32;\n    }\n\n    function method min(a: int32, b: int32): int32 \n    {   \n        if a <= b then a else b\n    }\n\n    function method abs(a: int32): int32 \n    {\n        if a >= 0 then a else -a\n    }\n    \n    // define the global variables\n    var requesterTids: Tid[5];          // The Tid of requesters\n    var servicerTid: Tid;               // The Tid of the servicer\n    var requests: Request[5];           // The request that each requester is currently waiting on\n    var maxDiskQueue: int32;            // The size of the disk queue\n    var currentTrack: int32;            // The current disk track\n    var NumberOfActiveThreads: int32;   // The number of request threads currently alive \n    var NumberOfRequests: int32;        // The number of outstanding requests\n\n    \n    // The external method to get new requests.\n    // will block if there is no new request\n    method {:extern} getNewRequest(tid:Tid) returns (request: Request)\n\n     method Servicer()\n    {\n       explicit_yield {\n           while true {\n                // See failed_10.arm, Error: yield statement is allowed only in iterators\n                // yield;\n                assume NumberOfRequests == min(NumberOfActiveThreads,maxDiskQueue) && NumberOfActiveThreads != 0;\n\n                var winnerIndex: int32;\n                var distance:int32;\n                var winnerDistance:int32;\n                var currentIndex:int32;\n\n                winnerIndex := 0;\n                winnerDistance := 0; \n                currentIndex := 0;\n                \n                while currentIndex < 5\n                    modifies winnerIndex, winnerDistance, currentIndex\n                    invariant forall i :: 0 < i < currentIndex ==> requests[i].tid == None || abs(requests[i].track - currentTrack) >= winnerDistance\n                {\n                    var currentRequest: Request;\n                    currentRequest := requests[currentIndex];\n                    if currentRequest.tid == None {\n                            continue;\n                    } else {\n                        distance := abs(currentRequest.track - currentTrack);\n                        if distance < winnerDistance {\n                            winnerDistance := distance;\n                            winnerIndex := currentIndex;\n                        }  \n                    }\n                    currentIndex := currentIndex + 1; \n                }\n                // No available request, then retry...\n                if requests[winnerIndex].tid == None {\n                    continue;\n                }\n                assert requests[winnerIndex].tid != None && forall i :: 0 < i < currentIndex ==> requests[i].tid == None || abs(requests[i].track - currentTrack) >= winnerDistance;\n                currentTrack := requests[winnerIndex].track;\n                requests[winnerIndex].tid := None;\n                requests[winnerIndex].track := -1;\n                NumberOfRequests := NumberOfRequests - 1;\n            }\n       }\n    }\n\n    method Requester(index:int32) {\n        NumberOfActiveThreads := NumberOfActiveThreads + 1;\n        var request: Request;\n        while(true) {\n            request := getNewRequest($me);\n            explicit_yield {\n                // See failed_10.arm, Error: yield statement is allowed only in iterators\n                // yield;\n                assume NumberOfRequests < maxDiskQueue;\n                NumberOfRequests := NumberOfRequests + 1;\n                requests[index] := request;\n                // See failed_10.arm, Error: yield statement is allowed only in iterators\n                // yield;\n                assume requests[index].tid == None;\n            }\n        }\n        NumberOfActiveThreads := NumberOfActiveThreads - 1;\n    }\n\n    method main() \n    {\n        maxDiskQueue := 3;\n        currentTrack := 0;\n\n        var i:int32;\n        i := 0;\n        while(i < 5) {\n            requests[i].tid := None;\n            requests[i].track := -1;\n            i := i + 1;\n        }\n\n        i := 0;\n        while (i < 5) {\n            // Error: Element of type {st.Range} used as type {ty}\n            //requesterTids[i] := create_thread Requester(i);\n            i := i + 1;\n        }\n        servicerTid := create_thread Servicer();\n    }\n}\n"
  },
  {
    "path": "Test/armada-parser/scheduler_impl.arm",
    "content": "// mono --debug $CDFY /compile:0 /dafnyVerify:0 src/armada-parser/scheduler_impl.arm\ninclude \"../../Armada/ArmadaCommonDefinitions.dfy\"\ninclude \"../../Armada/option.s.dfy\"\n\nlevel impl_level {\n    type Tid = uint64\n    \n    type Mutex = Option<Tid>\n    // External method for acquiring the lock\n    method {:extern} Acquire(mut:ptr<Mutex>) \n\t\tawaits *mut == None\n\t\tmodifies *mut\n\t\tensures *mut == Some($me)\n\n    // External method for releasing the lock\n    method {:extern} Release(mut:ptr<Mutex>) \n\t\trequires *mut == Some($me)\n\t\tmodifies *mut\n\t\tensures *mut == None\n\n    \n    // the data structure for disk schedule requests.\n    struct Request {\n        // The tid of process sending the request\n        var tid: Option<Tid>;\n\n        // The target disk track.  \n        var track: int32;\n    }\n\n\n    // the condition variable data structure\n    struct CondVar {\n\n        // The mut is used to protect the critical section of \n        // code that test the lock or change the locks state.\n        var mut: ptr<Mutex>;\n    }\n\n\n    // Exteral method for \"cv.wait\" \n    method {:extern} Wait(cv:ptr<CondVar>)\n        modifies *cv\n        modifies (*cv).mut\n        requires *((*cv).mut) == Some($me)\n        ensures *((*cv).mut) == Some($me)\n    \n    // External method for \"cv.singal\"\n    method {:extern} Signal(cv: ptr<CondVar>)\n        modifies *cv\n        modifies (*cv).mut\n    \n    \n    method InitCondVar(cv:ptr<CondVar>, mut:ptr<Mutex>) \n        modifies *cv;\n        reads *mut;\n        reads mut;\n    {\n        (*cv).mut := mut;\n    }\n\n    function method min(a: int32, b: int32): int32 \n    {   \n        if a <= b then a else b\n    }\n\n    function method abs(a: int32): int32 \n    {\n        if a >= 0 then a else -a\n    }\n    \n    // define the global variables\n    var mut: Mutex;                     // The global lock\n    var requesterTids: Tid[5];          // The Tid of requesters\n    var servicerTid: Tid;               // The Tid of the servicer\n    var queueFullCV: CondVar;           // The CondVar for the service thread to wait for for the queue to be full\n    var queueNotFullCV: CondVar;        // The CondVar for the requester threads to wait for the queue to be not full\n    var requester_CVs: CondVar[5];      // The CondVar for the requester threads to wati for their requests to be processed\n    var requests: Request[5];           // The request that each requester is currently waiting on\n    var maxDiskQueue: int32;            // The size of the disk queue\n    var currentTrack: int32;            // The current disk track\n    var NumberOfActiveThreads: int32;   // The number of request threads currently alive \n    var NumberOfRequests: int32;        // The number of outstanding requests\n\n    \n    // The external method to get new requests.\n    // will block if there is no new request\n    method {:extern} getNewRequest(tid:Tid) returns (request: Request)\n\n    method Servicer()\n    {\n       Acquire(&mut);\n       while true {\n\n           // Maybe we should run this serciver forever ?\n           while (NumberOfRequests < min(NumberOfActiveThreads,maxDiskQueue) \n                || NumberOfActiveThreads == 0) {\n               Wait(&queueFullCV);\n           }\n           \n           var winnerIndex: int32;\n           var distance:int32;\n           var winnerDistance:int32;\n           var currentIndex:int32;\n           \n\n           winnerIndex := 0;\n           winnerDistance := 0; \n           currentIndex := 0;\n           \n           while currentIndex < 5 {\n               var currentRequest: Request;\n               currentRequest := requests[currentIndex];\n               if currentRequest.tid == None {\n                    continue;\n               } else {\n                   distance := abs(currentRequest.track - currentTrack);\n                   if distance <= winnerDistance {\n                       winnerDistance := distance;\n                       winnerIndex := currentIndex;\n                   }  \n               }\n               currentIndex := currentIndex + 1; \n           }\n           \n           // No available request, then retry...\n           if requests[winnerIndex].tid == None {\n               continue;\n           }\n           \n           currentTrack := requests[winnerIndex].track;\n           requests[winnerIndex].tid := None;\n           requests[winnerIndex].track := -1;\n           NumberOfRequests := NumberOfRequests - 1;\n           \n           Signal(&requester_CVs[winnerIndex]);\n           Signal(&queueNotFullCV);\n\n       }\n       Release(&mut);\n    }\n\n    method Requester(index:int32) {\n        // Do we need to hold the lock for this ?\n        NumberOfActiveThreads := NumberOfActiveThreads + 1;\n        var request: Request;\n        while(true) {\n            request := getNewRequest($me);\n            Acquire(&mut);\n            while(NumberOfRequests >= maxDiskQueue) {\n                Wait(&queueNotFullCV);\n            }\n            NumberOfRequests := NumberOfRequests + 1;\n            requests[index] := request;\n            \n            Signal(&queueFullCV);\n            while(requests[index].tid != None) {\n                Wait(&requester_CVs[index]);\n            }\n            Release(&mut);\n        }\n        NumberOfActiveThreads := NumberOfActiveThreads - 1;\n        Signal(&queueFullCV);\n    }\n\n    method main() \n    {\n        mut := None;\n        maxDiskQueue := 3;\n        currentTrack := 0;\n\n        InitCondVar(&queueFullCV, &mut); \n        InitCondVar(&queueNotFullCV, &mut);\n\n        var i:int32;\n        i := 0;\n        while(i < 5) {\n            InitCondVar(&requester_CVs[i], &mut); \n            requests[i].tid := None;\n            requests[i].track := -1;\n            i := i + 1;\n        }\n\n        i := 0;\n        while (i < 5) {\n            // Error: Element of type {st.Range} used as type {ty}\n            //requesterTids[i] := create_thread Requester(i);\n            i := i + 1;\n        }\n        servicerTid := create_thread Servicer();\n    }\n}\n"
  },
  {
    "path": "Test/armada-parser/scheduler_simplify.arm",
    "content": "// mono --debug $CDFY /compile:0 /dafnyVerify:0 src/armada-parser/scheduler_simplify.arm\ninclude \"../../Armada/ArmadaCommonDefinitions.dfy\"\ninclude \"../../Armada/option.s.dfy\"\n\n// replace the serciver implementaion with somehow.\nlevel simplify_level {\n    type Tid = uint64\n    \n    // the data structure for disk schedule requests.\n    struct Request {\n        // The tid of process sending the request\n        var tid: Option<Tid>;\n\n        // The target disk track.  \n        var track: int32;\n    }\n\n    function method min(a: int32, b: int32): int32 \n    {   \n        if a <= b then a else b\n    }\n\n    function method abs(a: int32): int32 \n    {\n        if a >= 0 then a else -a\n    }\n    \n    // define the global variables\n    var requesterTids: Tid[5];          // The Tid of requesters\n    var servicerTid: Tid;               // The Tid of the servicer\n    var requests: Request[5];           // The request that each requester is currently waiting on\n    var maxDiskQueue: int32;            // The size of the disk queue\n    var currentTrack: int32;            // The current disk track\n    var NumberOfActiveThreads: int32;   // The number of request threads currently alive \n    var NumberOfRequests: int32;        // The number of outstanding requests\n\n    \n    // The external method to get new requests.\n    // will block if there is no new request\n    method {:extern} getNewRequest(tid:Tid) returns (request: Request)\n\n     method Servicer()\n    {\n       explicit_yield {\n           while true {\n                // See failed_10.arm, Error: yield statement is allowed only in iterators\n                // yield;\n                var winnerIndex: int32;\n                assume NumberOfRequests == min(NumberOfActiveThreads,maxDiskQueue) && NumberOfActiveThreads != 0;\n                somehow modifies winnerIndex ensures 0 <= winnerIndex < 5 && requests[winnerIndex].tid != None && (forall i :: 0 <= i < 5 ==> requests[i].tid == None || abs(requests[i].track - currentTrack) >= abs(requests[winnerIndex].track - currentTrack));\n                currentTrack := requests[winnerIndex].track;\n                requests[winnerIndex].tid := None;\n                requests[winnerIndex].track := -1;\n                NumberOfRequests := NumberOfRequests - 1;\n            }\n       }\n    }\n\n    method Requester(index:int32) {\n        NumberOfActiveThreads := NumberOfActiveThreads + 1;\n        var request: Request;\n        while(true) {\n            request := getNewRequest($me);\n            explicit_yield {\n                // See failed_10.arm, Error: yield statement is allowed only in iterators\n                // yield;\n                assume NumberOfRequests < maxDiskQueue;\n                NumberOfRequests := NumberOfRequests + 1;\n                requests[index] := request;\n                // See failed_10.arm, Error: yield statement is allowed only in iterators\n                // yield;\n                assume requests[index].tid == None;\n            }\n        }\n        NumberOfActiveThreads := NumberOfActiveThreads - 1;\n    }\n\n    method main() \n    {\n        maxDiskQueue := 3;\n        currentTrack := 0;\n\n        var i:int32;\n        i := 0;\n        while(i < 5) {\n            requests[i].tid := None;\n            requests[i].track := -1;\n            i := i + 1;\n        }\n\n        i := 0;\n        while (i < 5) {\n            // Error: Element of type {st.Range} used as type {ty}\n            //requesterTids[i] := create_thread Requester(i);\n            i := i + 1;\n        }\n        servicerTid := create_thread Servicer();\n    }\n}\n"
  },
  {
    "path": "Test/armada-parser/scheduler_spec.arm",
    "content": "// mono --debug $CDFY /compile:0 /dafnyVerify:0 src/armada-parser/scheduler_spec.arm\ninclude \"../../Armada/ArmadaCommonDefinitions.dfy\"\ninclude \"../../Armada/option.s.dfy\"\n\n\nlevel spec_level {\n    type Tid = uint64\n    // the data structure for disk schedule requests.\n    struct Request {\n        // The tid of process sending the request\n        var tid: Option<Tid>;\n        // The target disk track.  \n        var track: int32;\n    }\n    function method min(a: int32, b: int32): int32 \n    {   \n        if a <= b then a else b\n    }\n\n    function method abs(a: int32): int32 \n    {\n        if a >= 0 then a else -a\n    }\n    \n\n    // define the global variables\n    var requesterTids: Tid[5];          // The Tid of requesters\n    var servicerTid: Tid;               // The Tid of the servicer\n    var requests: Request[5];           // The request that each requester is currently waiting on\n    var maxDiskQueue: int32;            // The size of the disk queue\n    var currentTrack: int32;            // The current disk track\n    var NumberOfActiveThreads: int32;   // The number of request threads currently alive \n    var NumberOfRequests: int32;        // The number of outstanding requests\n\n    \n    // The external method to get new requests.\n    // will block if there is no new request\n    method {:extern} getNewRequest(tid:Tid) returns (request: Request)\n\n    method Servicer() \n    {\n        while (true) {\n            explicit_yield {\n                assume NumberOfRequests == min(NumberOfActiveThreads,maxDiskQueue) && NumberOfActiveThreads != 0;\n                var winnerIndex: int32;\n                somehow modifies winnerIndex ensures 0 <= winnerIndex < 5 && requests[winnerIndex].tid != None && (forall i :: 0 <= i < 5 ==> requests[i].tid == None || abs(requests[i].track - currentTrack) >= abs(requests[winnerIndex].track - currentTrack));\n                currentTrack := requests[winnerIndex].track;\n                requests[winnerIndex].tid, requests[winnerIndex].track := None, -1;\n                NumberOfRequests := NumberOfRequests - 1;\n            }\n        }\n    }\n\n    method Requester(index:int32) {\n        var request: Request;\n        NumberOfActiveThreads := NumberOfActiveThreads + 1;\n        while(true) {\n            request := getNewRequest($me);\n            explicit_yield {\n                assume NumberOfRequests < maxDiskQueue && requests[index].tid == None;  \n                NumberOfRequests, requests[index]  := NumberOfRequests + 1, request;\n            }\n        } \n        NumberOfActiveThreads := NumberOfActiveThreads - 1;\n    }\n\n    method main() \n    {\n        maxDiskQueue := 3;\n        currentTrack := 0;\n\n        var i:int32;\n        i := 0;\n        while(i < 5) {\n            requests[i].tid := None;\n            requests[i].track := -1;\n            i := i + 1;\n        }\n\n        i := 0;\n        while (i < 5) {\n            //Error: Element of type {st.Range} used as type {ty}\n            //requesterTids[i] := create_thread Requester(i);\n            i := i + 1;\n        }\n        servicerTid := create_thread Servicer();\n    }\n}\n"
  },
  {
    "path": "Test/armada-parser/test-var-hiding-fail.arm",
    "content": "level A {\n    var x:int32;\n    var y:int32;\n    var z:int32;\n\n    method main()\n    {\n        x ::= 3;\n        z ::= 5;\n        y ::= z;  // should fail since z is used, so it can't be hidden\n    }\n}\n\nlevel B {\n    var x:int32;\n    var y:int32;\n\n    method main()\n    {\n        x ::= 3;\n        y ::= 4;\n    }\n}\n\n\nproof AB {\n\n    refinement A B\n    var_hiding z\n\n}\n"
  },
  {
    "path": "Test/armada-parser/test.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs\n{\n    struct C1 {\n        var x:int32[4];\n        var y:int32[8];\n    }\n\n    struct C2 {\n        var a:int32\n        var b:C1\n    }\n\n    struct C3 {\n        var mno:C2\n        var pqr:C2\n        var s:int64\n    }\n\n    struct C4 {\n    }\n\n    datatype MyLogEntry = MyLogEntryInt(i:int)\n\n    ghost var log:seq<MyLogEntry> := [];\n\n    refinement_constraint @\"\n       || (ls.stop_reason == hs.stop_reason && ls.ghosts.log == hs.ghosts.log)\n       || (ls.stop_reason.Armada_NotStopped? && ls.ghosts.log <= hs.ghosts.log)\n    \"\n}\n\nlevel A using SharedStructs\n{\n    datatype DT1 = DT1(a:int, b:set<int>)\n\n    var w:int32 := 66;\n    noaddr var x:int32 := 0;\n    var y:int32\n    noaddr var z:int32 := 7;\n    var g1:uint8[10];\n    var g2:C2;\n    var g3:C2[5];\n    noaddr var g4:C3;\n    ghost var g5:seq<int> := [3, 4, 5];\n    ghost var g6:DT1;\n\n    method {:extern} ExternalMethod(a:uint32, p:ptr<int32>) returns (b:uint32)\n        reads    x, g2.a\n        undefined_unless allocated(p)\n        modifies y, g1[4], log\n        ensures  y == old(y + *p) + 3\n        ensures  b == a * 2\n        ensures  log == old(log) + [MyLogEntryInt(2), MyLogEntryInt(47)]\n\n    function method increment(x:uint32) : uint32\n    {\n        if (0 < x < 10) then x + 1 else 0\n    }\n\n    method {:atomic} C1Test(ths:ptr<C1>)\n    {\n        var w:int32;\n        noaddr var z:int32;\n        noaddr var a:uint32;\n        assert allocated(ths);\n        z ::= (*ths).x[2];\n        assume z - (*ths).x[2] == 0;\n        wait_until w > 3;\n        (*ths).x[2] ::= z + 3;\n        a := ExternalMethod(a, &w);\n        create_thread ExternalMethod(a, &w);\n        g5 ::= [1, 2, 3];\n        g6.b := g6.b + {3};\n    }\n\n    method C2Help(ths:ptr<C2>)\n    {\n        noaddr var q:int32[4];\n    }\n\n    method InterestingControlFlow(a:int32, b:int64, p:ptr<int32>)\n    {\n        while (a > *p) {\n            if (b < 3) {\n                a := a - 1;\n                assume a != 13;\n                continue;\n            }\n            else if (b > 10) {\n                a := a - 2;\n                b := b - 1;\n                return;\n            }\n            else {\n                assume b > 17;\n                break;\n            }\n            *p := *p + 1;\n            assert *p > 7;\n        }\n        if *p == 10 {\n            *p := 11;\n        }\n    }\n\n    method Foo(a:uint32, b:uint64) returns (c:uint32, d:uint64)\n    {\n        noaddr var z:uint64;\n        var x:uint64;\n        var y:uint64;\n        noaddr var cnew:C2;\n\n        x := (var q:bool := (b == 9); if q then 3 as uint64 else 17);\n        y := if (a > 3) then 4 else 0;\n        {\n           z := y / b;\n           y := z;\n        }\n        atomic {\n           c := a + a;\n           d := z - 6;\n        }\n    }\n\n    method Bar(a:int16, b:uint32) returns (c:uint32, d:uint32)\n    {\n        var z:int16 ::= a + 33;\n        var w:C2[10];\n        var v:uint32 := b + 44;\n        noaddr var x:uint32 := b * 77;\n        noaddr var y:int16 := z - 22;\n        noaddr var q:C2[8];\n        var p:ptr<C2>;\n\n        x, y, c := 5, 6, x + 1;\n        a := -a;\n        b := increment(c);\n\n        p := &w[0];\n        while (p <= &w[9]) {\n          p := p + 1;\n          return;\n        }\n    }\n\n    method Baz(p:ptr<int16>, q:ptr<uint32>) returns (c:uint32)\n    {\n        var d:uint32;\n        var h:uint64;\n\n        *q, *(q+1) := Bar(*p, *q);\n        h := create_thread Bar(4, 6);\n        g4.mno.b.x[2] := 3;\n    }\n\n    method main(p: ptr<int32>, c:C1) {\n        var a:int16, b:uint32, rc:uint32, rd:uint32;\n        *p, *(p+1), c.x[3] := 0, 1, 78;\n        rc, rd := Bar(a, b);\n    }\n\n    universal_step_constraint WAlwaysNonnegative\n    {\n        w >= 0\n    }\n\n    universal_step_constraint AlwaysNotJoinable\n    {\n        $me !in $state.joinable_tids\n    }\n\n    universal_step_constraint ZNotInStoreBuffer @\"\n       forall entry :: entry in s.threads[tid].storeBuffer && entry.loc.Armada_StoreBufferLocation_Unaddressable? ==>\n                  !entry.loc.v.Armada_GlobalStaticVar_z?\n    \"\n}\n"
  },
  {
    "path": "Test/armada-parser/test2.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs2\n{\n    struct S1 {\n       var a:int32;\n       var b:int32[10];\n    }\n}\n\nlevel B using SharedStructs2\n{\n    noaddr var v: int32 := 0;\n    noaddr var w: int32 := 56;\n    var a: int32[10];\n    var x: int32;\n    var s: S1;\n    ghost var g: seq<int32>;\n\n    function TriggerInt(x: int) : int { x }\n\n    method {:extern} ExternalMethod(p: ptr<S1>)\n        undefined_unless x > 0\n        undefined_unless forall i {:trigger TriggerInt(i)} :: 0 <= TriggerInt(i) < 10 ==> allocated(p+i)\n        ensures  $sb_empty  // fence\n\n    method main()\n    {\n        var y: ptr<int32>;\n        var z: int32;\n        var sarr: S1[10];\n        noaddr var res:set<int32>;\n\n        y := null;\n        y := &x;\n        y := &s.a;\n        if (&s.a == null) {\n            y := &s.b[3];\n            z := *y;\n        }\n        fence;\n        z := if_undefined(*y, 42);            // If *y isn't defined (e.g., if y is null or freed), then 42\n        s ::= if_undefined(sarr[v], sarr[w]); // If sarr[v] isn't defined (e.g., if v is out of the array's bounds), then sarr[w]\n        z := if_undefined(0, 42);             // Always 0 since 0 is always defined\n        z := global_view(*y);\n        g := a[1..4];\n        a[a[x]] ::= a[z];\n\n        assert 0 <= z < 10 ==> *(y+z) == *y;\n        assert exists i {:trigger TriggerInt(i)} :: 0 <= TriggerInt(i) < 20 && *(y+i) == 0;\n        z := if (exists i {:trigger TriggerInt(i)} :: 0 <= TriggerInt(i) < 30 && allocated(&y) && allocated_array(y) && allocated(y+i) && *(y+i) > 0) then 55 else 66;\n        res := set i | 0 <= i < 40 && allocated(&y) && allocated_array(y) && allocated(y+i) && *(y+i) > 0 :: *(y+i);\n        ExternalMethod(&sarr[0]);\n    }\n}\n"
  },
  {
    "path": "Test/armada-parser/test3.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs3\n{\n    struct C1 {\n        var x:int32[4];\n        var y:int32[8];\n    }\n\n    struct C2 {\n        var a:int32\n        var b:C1\n    }\n\n    struct C3 {\n        var mno:C2\n        var pqr:C2\n        var s:int64\n    }\n\n    struct C4 {\n    }\n\n    ghost var log:seq<int> := [];\n\n    refinement_constraint @\"\n       || (ls.stop_reason == hs.stop_reason && ls.ghosts.log == hs.ghosts.log)\n       || (ls.stop_reason.Armada_NotStopped? && ls.ghosts.log <= hs.ghosts.log)\n    \"\n}\n\nlevel C using SharedStructs3\n{\n    datatype DT1 = DT1(a:int, b:set<int>)\n\n    var w:int32\n    noaddr var x:int32 := 0;\n    var y:int32\n    noaddr var z:int32 := 7;\n    var g1:uint8[10];\n    var g2:C2;\n    var g3:C2[5];\n    noaddr var g4:C3;\n    ghost var g5:seq<int>;\n    ghost var g6:DT1;\n\n    method {:extern} ExternalMethod(a:uint32, p:ptr<int32>) returns (b:uint32)\n        reads    x, g2.a\n        modifies y, g1[4], log\n        ensures  y == old(y + *p) + 3\n        ensures  b == a * 2\n        ensures  log == old(log) + [2, 47]\n\n    function method increment(x:uint32) : uint32\n    {\n        if (0 < x < 10) then x + 1 else 0\n    }\n\n    method C1Test(ths:ptr<C1>)\n    {\n        explicit_yield {\n            var w:int32;\n            noaddr var z:int32;\n            z ::= (*ths).x[2];\n            yield;\n            assume z - (*ths).x[2] == 0;\n            wait_until w > 3;\n            (*ths).x[2] ::= z + 3;\n            g5 ::= [1, 2, 3];\n            g6.b := g6.b + {3};\n        }\n    }\n\n    method C2Help(ths:ptr<C2>)\n    {\n        noaddr var q:int32[4];\n    }\n\n    method InterestingControlFlow(a:int32, b:int64, p:ptr<int32>)\n    {\n        explicit_yield {\n            yield;\n            while (a > *p) {\n                if (b < 3) {\n                    a := a - 1;\n                    yield;\n                    assume a != 13;\n                    continue;\n                }\n                else if (b > 10) {\n                    a := a - 2;\n                    b := b - 1;\n                    return;\n                }\n                else {\n                    assume b > 17;\n                    break;\n                }\n                *p := *p + 1;\n                yield;\n                assert *p > 7;\n            }\n        }\n        if *p == 10 {\n            *p := 11;\n        }\n    }\n\n    method Foo(a:uint32, b:uint64) returns (c:uint32, d:uint64)\n    {\n        noaddr var z:uint64;\n        var x:uint64;\n        var y:uint64;\n        noaddr var cnew:C2;\n\n        explicit_yield {\n            x := (var q:bool := (b == 9); if q then 3 as uint64 else 17);\n            y := if (a > 3) then 4 else 0;\n            {\n               yield;\n               z := y / b;\n               yield;\n               y := z;\n            }\n            atomic {\n               c := a + a;\n               d := z - 6;\n            }\n        }\n    }\n\n    method Bar(a:int16, b:uint32) returns (c:uint32, d:uint32)\n    {\n        var z:int32 := 88;\n        var w:C2[10];\n        noaddr var x:uint32 := 37;\n        noaddr var y:int32, q:C2[8];\n\n        x, y, c := 5, 6, x + 1;\n        a := -a;\n        b := increment(c);\n    }\n\n    method Baz(p:ptr<int16>, q:ptr<uint32>) returns (c:uint32)\n    {\n        var d:uint32;\n        var h:uint64;\n\n        *q, *(q+1) := Bar(*p, *q);\n        h := create_thread Bar(4, 6);\n        g4.mno.b.x[2] := 3;\n    }\n\n    method main(p: ptr<int32>, c:C1) {\n        *p, *(p+1), c.x[3] := 0, 1, 78;\n    }\n\n}\n"
  },
  {
    "path": "Test/armada-parser/test4.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\ninclude \"test4defs.dfy\"\n\nstructs SharedStructs4\n{\n    struct S1 {\n        var i:int32\n        var j:int32[8]\n    }\n\n    struct S2 {\n        var a:S1\n        var b:S1[4]\n    }\n\n    struct S3 {\n        var x:S1\n        var y:S2[3]\n    }\n\n    ghost var log:seq<int> := []\n\n    refinement_constraint @\"\n       || (ls.stop_reason == hs.stop_reason && ls.ghosts.log == hs.ghosts.log)\n       || (ls.stop_reason.Armada_NotStopped? && ls.ghosts.log <= hs.ghosts.log)\n    \"\n}\n\nlevel D using SharedStructs4\n{\n    noaddr var g:S3\n    var g_heap:S3\n    var i_heap:int32\n    noaddr var my_tid:uint64;\n    var h:int32;\n    ghost var z:int := 0;\n\n    import opened test4defs\n\n    method {:extern} ExternalPrint(n:int32)\n        awaits   g.x.i >= 0\n        awaits   i_heap >= 0\n        modifies g.x.i\n        modifies g.y\n        modifies g_heap.x.i\n        modifies g_heap.y\n        modifies log\n        ensures  g.x == old(g.x)\n        ensures  g_heap.x != old(g_heap.x)\n        ensures  log == old(log) + [n as int]\n\n    invariant Invariant1\n    {\n        g.x.i >= 0\n    }\n\n    method Test(s:seq<int32>, t:seq<int>, u:map<int, seq<int32>>, p:ptr<int32>)\n    {\n        noaddr var i:int32, j:int, b:int32;\n\n        i := s[3];\n        j := t[2];\n        i := u[7][8] / u[7][7];\n        assert *p > 7;\n        assert *(p+1) > 7;\n        goto lbl1;\n        compare_and_swap(h, i + 1, 12 as int32);\n        b := compare_and_swap(h, i, h + 1);\nlabel lbl1:\n        atomic_exchange(h, 12 as int32);\n        b := atomic_exchange(h, 12 as int32);\n    }\n\n    method main(a:S1) {\n        noaddr var b:S3;\n        var p:ptr<int32>;\n        var q:ptr<S3>;\n        noaddr var n:int32;\n\n        while (*) {\n            b ::= g_heap;\n        }\nlabel lbl1:\n        g_heap ::= b;\n        b, g.x.i ::= g, *;\n        p := &g_heap.x.i;\n        if * {\n            my_tid := $me;\n        }\n        z := Successor(z);\n        p := calloc(int32, *p);\n        q ::= malloc(S3);\n        dealloc q;\n        dealloc p+1;\n        my_tid := create_thread ExternalPrint(7 as int32);\n        join my_tid;\n        assert g.x.i == 3;\n        assume g_heap.x.i == 3;\n        assume i_heap == 3;\n        somehow undefined_unless g.x.i > 0 modifies g_heap, log ensures i_heap > 0 ensures log == old(log) + [3];\n        assert |$state.threads[$me].stack| == 0;\n        ExternalPrint(b.x.i);\n        Test([], [], map [], p);\n    }\n}\n"
  },
  {
    "path": "Test/armada-parser/test5.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs5\n{\n    struct S1 {\n       var a:int32;\n       var b:int32[10];\n    }\n}\n\nlevel E using SharedStructs5\n{\n    var x: int32;\n    var s: S1;\n\n    method main()\n    {\n        var y: ptr<int32>;\n\tvar z: int32;\n\n\ty := &x;\n        y := &s.a;\n        y := &s.b[3];\n\tz := *y;\n    }\n}\n"
  },
  {
    "path": "Test/armada-parser/test6.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs6\n{\n    struct S1 {\n        var x:int32[10];\n    }\n}\n\nlevel F using SharedStructs6 {\n    noaddr var my_tid:uint64;\n    var g:S1;\n\n    method main() {\n        noaddr var p:ptr<int32[10]>;\n        noaddr var n:int32;\n        noaddr var q:ptr<int32>;\n\n        p ::= &g.x;\n        n ::= (*p)[1];\n        q ::= &g.x[0];\n        n ::= *(q+1);\n    }\n}\n"
  },
  {
    "path": "Test/armada-parser/test7.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs7 {}\n\nlevel {:concrete} G using SharedStructs7 {\n  var a: int64;\n  var b: int64;\n\n  var p: ptr<int64>;\n\n  method foobar(v: int64) returns (x: int64) {\n    x := 0;\n  }\n\n  method main() {\n    noaddr var c: int64;\n\n    *(&a + 4) := 0;\n    c := *(&a);\n    p := &a;\n\n    a, c := 1, 1;\n    a := foobar(b);\n  }\n}\n"
  },
  {
    "path": "Test/assume-intro/.gitignore",
    "content": "A.dfy\nB.dfy\nAB.dfy\nSharedStructs.dfy\nC.dfy\nD.dfy\nCD.dfy\nSharedStructs2.dfy\nE.dfy\nF.dfy\nEF.dfy\nSharedStructs3.dfy\nAB/\nCD/\nEF/\n\n"
  },
  {
    "path": "Test/assume-intro/ABHelpers.dfy",
    "content": "include \"A.dfy\"\ninclude \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nmodule ABHelpers\n{\n  import opened ArmadaCommonDefinitions = ArmadaCommonDefinitions\n  import L = A\n\n  predicate MyGlobalInvariant(s:L.Armada_TotalState)\n  {\n    && (forall tid :: tid in s.threads ==> tid == s.tid_init)\n    && (forall tid :: tid in s.threads ==> s.threads[tid].storeBuffer == [])\n  }\n\n  predicate MyYieldPredicate(s:L.Armada_TotalState, s':L.Armada_TotalState, tid:Armada_ThreadHandle)\n  {\n    && s'.mem.globals.x == s.mem.globals.x\n    && s'.mem.globals.y == s.mem.globals.y\n    && s'.mem.globals.z == s.mem.globals.z\n  }\n}\n"
  },
  {
    "path": "Test/assume-intro/test.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs {\n\n}\n\nlevel A using SharedStructs {\n    noaddr var x:int32;\n    noaddr var y:int32;\n    noaddr var z:int32 := 0;\n    noaddr var p:ptr<int32>;\n\n    method {:extern} DoubleX()\n        reads x\n        modifies x\n        ensures x == old(x) * 2\n\n    method Test()\n    {\n        noaddr var i:int32;\n\n        i ::= 1;\n        x ::= 0;\n        label loop:\n        while i < 10\n        {\n            x ::= i;\n            i ::= i + 1;\n        }\n    }\n\n    method main()\n    {\n        x ::= 3;\n        y ::= 4;\nlabel before_z:\n        goto after_z;\n        z ::= 5;\nlabel after_z:\n        x ::= 6;\n        Test();\n    }\n\n    invariant Inv1\n    {\n        z > 0 ==> y == 4\n    }\n\n    yield_predicate YP1\n    {\n        x >= old(x)\n    }\n}\n\nlevel B using SharedStructs {\n    noaddr var x:int32;\n    noaddr var y:int32;\n    noaddr var z:int32 := 0;\n    noaddr var p:ptr<int32>;\n\n    method {:extern} DoubleX()\n        reads x\n        modifies x\n        ensures x == old(x) * 2\n\n    method Test()\n        requires x > 2\n        ensures  x == 9\n        ensures  y == old(y)\n        ensures  z == old(z)\n    {\n        noaddr var i:int32;\n\n        i ::= 1;\n        x ::= 0;\n        label loop:\n        while i < 10\n            invariant 1 <= i\n            invariant i <= 10\n            invariant x == i - 1\n            ensures   y == old(y)\n            ensures   z == old(z)\n        {\n            x ::= i;\n            i ::= i + 1;\n        }\n    }\n\n    method main()\n        ensures y == 4\n        modifies x, y, z\n    {\n        x ::= 3;\n        y ::= 4;\nlabel before_z:\n        goto after_z;\n        z ::= 5;\nlabel after_z:\n        assume x == 3 && y == 4;\n        x ::= 6;\n        Test();\n    }\n\n    universal_step_constraint ZPositiveImpliesYFour\n    {\n        z > 0 ==> y == 4\n    }\n}\n\nproof AB {\n    refinement A B\n    assume_intro\n\n    chl_invariant MyGlobalInvariant @\"\n      && (forall tid :: tid in threads ==> tid == tid_init)\n      && (forall tid :: tid in threads ==> threads[tid].storeBuffer == [])\n    \"\n\n    chl_invariant Inv1\n    chl_local_invariant main_before_z XIs3 \"globals.x == 3\"\n    chl_yield_pred {:excludeAll} YP1\n\n    chl_yield_pred {:excludeAll} MyYieldPredicate @\"\n      && globals'.x == globals.x\n      && globals'.y == globals.y\n      && globals'.z == globals.z\n    \"\n}\n"
  },
  {
    "path": "Test/assume-intro/test2.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs2 {\n\n}\n\nlevel C using SharedStructs2 {\n  ghost var x:int := 0;\n  ghost var y:int := 0;\n\n  method Test()\n  {\n    y := y + 1;\n  }\n\n  method main()\n  {\n    y := 4;\n    Test();\n\n    x := 3;\nlabel myloop:\n    while x < 10\n    {\n      x := x + 1;\n    }\n    y := 6;\n  }\n}\n\nlevel D using SharedStructs2 {\n  ghost var x:int := 0;\n  ghost var y:int := 0;\n\n  method Test()\n  {\n    y := y + 1;\n  }\n\n  method main()\n  {\n    y := 4;\n    Test();\n\n    assume y == 5;\n    x := 3;\nlabel myloop:\n    while x < 10\n    {\n      x := x + 1;\n    }\n\n    assume x == 10;\n    y := 6;\n  }\n}\n\nproof CD {\n  refinement C D\n  assume_intro\n\n  chl_invariant only_one_thread \"forall tid :: tid in threads ==> tid == tid_init\"\n  chl_yield_pred {:excludeAll} ghosts_unchanged \"ghosts' == ghosts\"\n  chl_precondition Test y_is_four \"ghosts.y == 4\"\n  chl_postcondition Test y_is_five \"ghosts'.y == 5\"\n  chl_loop_modifies main_myloop x_between_3_and_10 \"3 <= ghosts'.x <= 10\"\n\n}\n"
  },
  {
    "path": "Test/assume-intro/test3.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs3 {\n\n}\n\nlevel E using SharedStructs3 {\n    noaddr var y:int32;\n    ghost var z:int := 0;\n\n    method Worker(n:int32)\n    {\n        noaddr var x:int32;\n        x := n;\n        atomic {\n            y := 4;\n            z := 1;\n            z := 0;\n        }\n    }\n\n    method main()\n    {\n        create_thread Worker(1);\n        create_thread Worker(2);\n    }\n}\n\nlevel F using SharedStructs3 {\n    noaddr var y:int32;\n    ghost var z:int := 0;\n\n    method Worker(n:int32)\n    {\n        noaddr var x:int32;\n        x := n;\n        atomic {\n            assume x == n;\n            y := 4;\n            z := 1;\n            z := 0;\n        }\n    }\n\n    method main()\n    {\n        create_thread Worker(1);\n        create_thread Worker(2);\n    }\n}\n\nproof EF {\n    refinement E F\n    assume_intro\n\n    chl_invariant z_always_zero \"s.s.ghosts.z == 0\"\n}\n"
  },
  {
    "path": "Test/barrier/.gitignore",
    "content": "Impl.dfy\nSharedStructs.dfy\nL1.dfy\nL2.dfy\nL1RefinesL2.dfy\nImplRefinesL1.dfy\nImplRefinesL1/\nL1RefinesL2/\n"
  },
  {
    "path": "Test/barrier/barrier.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs\n{\n  ghost var log:seq<uint32> := [];\n\n  refinement_constraint @\"\n     || (ls.stop_reason == hs.stop_reason && ls.ghosts.log == hs.ghosts.log)\n     || (ls.stop_reason.Armada_NotStopped? && ls.ghosts.log <= hs.ghosts.log)\n  \"\n}\n\nlevel {:concrete} Impl using SharedStructs\n{\n  noaddr var barrier:uint32[10];\n\n  method {:extern} print_uint32(i:uint32)\n  {\n    log := log + [i];\n  }\n\n  method worker(id:uint32)\n  {\n    noaddr var waiting_for_barrier:int8 := 1;\n    noaddr var i:uint32;\n\n    print_uint32(id);\n\n    barrier[id] := 1;\n    while waiting_for_barrier != 0\n    {\n      waiting_for_barrier := 0;\n      i := 0;\n      while i < 10\n      {\n        if barrier[i] == 0\n        {\n          waiting_for_barrier := 1;\n        }\n        i := i + 1;\n      }\n    }\n\n    print_uint32(id + 100);\n  }\n\n  method main()\n  {\n    noaddr var i:uint32;\n    noaddr var tids:uint64[10];\n\n    i := 0;\n    while i < 10\n    {\n      barrier[i] := 0;\n      i := i + 1;\n    }\n\n    fence;\n\n    i := 0;\n    while i < 10\n    {\n      tids[i] := create_thread worker(i);\n      i := i + 1;\n    }\n\n    i := 0;\n    while i < 10\n    {\n      join tids[i];\n      i := i + 1;\n    }\n  }\n\n}\n\nlevel L1 using SharedStructs\n{\n  noaddr var barrier:uint32[10];\n  ghost var barrier_initialized:seq<bool> := [false, false, false, false, false, false, false, false, false, false];\n  ghost var all_initialized:bool := false;\n  ghost var threads_past_barrier:seq<bool> := [];\n\n  method {:extern} print_uint32(i:uint32)\n  {\n    log := log + [i];\n  }\n\n  method worker(id:uint32)\n  {\n    noaddr var waiting_for_barrier:int8 := 1;\n    noaddr var i:uint32;\n\n    print_uint32(id);\n\n    threads_past_barrier := if 0 <= id as int < |threads_past_barrier| then threads_past_barrier[id as int := true] else threads_past_barrier;\n    barrier[id] := 1;\n    while waiting_for_barrier != 0\n    {\n      waiting_for_barrier := 0;\n      i := 0;\n      while i < 10\n      {\n        if barrier[i] == 0\n        {\n          waiting_for_barrier := 1;\n        }\n        i := i + 1;\n      }\n    }\n\n    print_uint32(id + 100);\n  }\n\n  method main()\n  {\n    noaddr var i:uint32;\n    noaddr var tids:uint64[10];\n\n    i := 0;\n    while i < 10\n    {\n      atomic {\n        barrier[i] := 0;\n        barrier_initialized := if 0 <= i as int < |barrier_initialized| then barrier_initialized[i as int := true] else barrier_initialized;\n      }\n      i := i + 1;\n    }\n\n    fence;\n\n  label post_fence:\n    threads_past_barrier := [false, false, false, false, false, false, false, false, false, false];\n    all_initialized := true;\n\n    i := 0;\n    while i < 10\n    {\n      tids[i] := create_thread worker(i);\n      i := i + 1;\n    }\n\n    i := 0;\n    while i < 10\n    {\n      join tids[i];\n      i := i + 1;\n    }\n  }\n}\n\nproof ImplRefinesL1\n{\n  refinement Impl L1\n  var_intro barrier_initialized, all_initialized, threads_past_barrier\n}\n\nlevel L2 using SharedStructs\n{\n  noaddr var barrier:uint32[10];\n  ghost var barrier_initialized:seq<bool> := [false, false, false, false, false, false, false, false, false, false];\n  ghost var all_initialized:bool := false;\n  ghost var threads_past_barrier:seq<bool> := [];\n\n  method {:extern} print_uint32(i:uint32)\n    ensures old(|barrier_initialized|) == |barrier_initialized|\n  {\n    log := log + [i];\n  }\n\n  method worker(id:uint32)\n    requires all_initialized\n    requires |threads_past_barrier| == 10\n    requires 0 <= id < 10\n  {\n    noaddr var waiting_for_barrier:int8 := 1;\n    noaddr var i:uint32;\n\n    print_uint32(id);\n\n    assume 0 <= id as int < |threads_past_barrier|;\n    threads_past_barrier := if 0 <= id as int < |threads_past_barrier| then threads_past_barrier[id as int := true] else threads_past_barrier;\n    barrier[id] := 1;\n    while waiting_for_barrier != 0\n      invariant all_initialized\n      invariant waiting_for_barrier == 0 ==> forall j :: 0 <= j < |threads_past_barrier| ==> threads_past_barrier[j]\n    {\n      waiting_for_barrier := 0;\n      i := 0;\n      while i < 10\n        invariant 0 <= i <= 10\n        invariant all_initialized\n        invariant waiting_for_barrier == 0 ==> forall j :: 0 <= j < i as int && j < |threads_past_barrier| ==> threads_past_barrier[j]\n      {\n        if barrier[i] == 0\n        {\n          waiting_for_barrier := 1;\n        }\n        i := i + 1;\n      }\n    }\n\n    assume |threads_past_barrier| == 10 && forall j :: 0 <= j < 10 ==> threads_past_barrier[j];\n    print_uint32(id + 100);\n  }\n\n  method main()\n    requires !all_initialized\n  {\n    noaddr var i:uint32;\n    noaddr var tids:uint64[10];\n\n    i := 0;\n    while i < 10\n      invariant 0 <= i <= 10\n      invariant |barrier_initialized| == 10 && forall j :: 0 <= j < i as int && j < |barrier_initialized| ==> barrier_initialized[j]\n      invariant !all_initialized\n    {\n      atomic {\n        barrier[i] := 0;\n        barrier_initialized := if 0 <= i as int < |barrier_initialized| then barrier_initialized[i as int := true] else barrier_initialized;\n      }\n      i := i + 1;\n    }\n\n    fence;\n\n  label post_fence:\n    threads_past_barrier := [false, false, false, false, false, false, false, false, false, false];\n    all_initialized := true;\n\n    i := 0;\n    while i < 10\n      invariant $sb_empty\n      invariant 0 <= i <= 10\n      invariant all_initialized\n      invariant forall j :: 0 <= j < |barrier_initialized| ==> barrier_initialized[j]\n    {\n      tids[i] := create_thread worker(i);\n      i := i + 1;\n    }\n\n    i := 0;\n    while i < 10\n      invariant 0 <= i <= 10\n    {\n      join tids[i];\n      i := i + 1;\n    }\n  }\n}\n\nproof L1RefinesL2\n{\n  refinement L1 L2\n  assume_intro\n\n  include_file \"extra.dfy\"\n  import_module L1RefinesL2Helpers\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesLocalInvariant_worker_YYN_YieldedRevisited_6_Then_From_worker_6_T_To_worker_7\n        \"L1RefinesL2Helpers.lemma_BarrierNonzeroInLocalViewImpliesStoreBuffer1OrBarrier1(s19.s);\"\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesLocalInvariant_worker_YYN_YieldedRevisited_6_Then_From_worker_6_F_To_worker_JumpBack_11\n        \"L1RefinesL2Helpers.lemma_BarrierNonzeroInLocalViewImpliesStoreBuffer1OrBarrier1(s19.s);\"\n\n  inductive_invariant BarrierSize10 \"|ghosts.barrier_initialized| == 10 && |globals.barrier| == 10\"\n\n  chl_yield_pred BarrierYieldPredUniversal @\"\n    && (forall j :: 0 <= j < |ghosts.barrier_initialized| && ghosts.barrier_initialized[j]\n               ==> j < |ghosts'.barrier_initialized| && ghosts'.barrier_initialized[j])\n    && (ghosts.all_initialized ==> ghosts'.all_initialized &&\n          (forall j :: 0 <= j < |ghosts.threads_past_barrier| && ghosts.threads_past_barrier[j]\n                  ==> j < |ghosts'.threads_past_barrier| && ghosts'.threads_past_barrier[j]))\n    && (|ghosts.threads_past_barrier| == 10 ==> |ghosts'.threads_past_barrier| == 10)\n  \"\n\n  chl_yield_pred {:excludeAll} BarrierYieldPred @\"\n    && (tid in threads ==> tid in threads' && |threads'[tid].storeBuffer| <= |threads[tid].storeBuffer|)\n    && (!ghosts.all_initialized ==> ghosts' == ghosts)\n  \"\n\n  chl_invariant InitializationInvariant @\"\n    if ghosts.all_initialized then\n      && |ghosts.threads_past_barrier| == 10\n      && |ghosts.barrier_initialized| == 10\n      && (forall j :: 0 <= j < 10 ==> ghosts.barrier_initialized[j])\n    else\n      (forall tid :: tid in threads ==> tid == tid_init)\n  \"\n  chl_invariant WaitingForBarrierStoreBufferAlways0Or1 @\"\n    forall tid, entry :: && tid in threads\n                    && entry in threads[tid].storeBuffer\n                    && entry.loc.Armada_StoreBufferLocation_Unaddressable?\n                    && entry.loc.v.Armada_GlobalStaticVar_barrier?\n                    && |entry.loc.fields| == 1\n                    && entry.value.Armada_PrimitiveValue_uint32?\n                    ==> entry.value.n_uint32 == 0 || entry.value.n_uint32 == 1\"\n  chl_invariant NotAllInitializedImpliesOnly0InStoreBuffer @\"\n    !ghosts.all_initialized ==>\n    (forall entry :: && tid_init in threads\n                && entry in threads[tid_init].storeBuffer\n                && entry.loc.Armada_StoreBufferLocation_Unaddressable?\n                && entry.loc.v.Armada_GlobalStaticVar_barrier?\n                ==>\n                (&& |entry.loc.fields| == 1\n                 && entry.value.Armada_PrimitiveValue_uint32?\n                 && entry.value.n_uint32 == 0))\"\n  chl_invariant BarrierInitializedAndNotAllInitializedImplies0Pending @\"\n    && !ghosts.all_initialized\n    && |ghosts.barrier_initialized| == 10\n    && |globals.barrier| == 10\n    ==>\n    (forall j :: && 0 <= j < 10\n            && ghosts.barrier_initialized[j]\n            && globals.barrier[j] != 0\n            ==> && tid_init in threads\n                && (exists entry ::\n                      && entry in threads[tid_init].storeBuffer\n                      && entry.loc.Armada_StoreBufferLocation_Unaddressable?\n                      && entry.loc.v.Armada_GlobalStaticVar_barrier?\n                      && |entry.loc.fields| == 1\n                      && entry.loc.fields[0] == j\n                      && entry.value.Armada_PrimitiveValue_uint32?\n                      && entry.value.n_uint32 == 0))\"\n  chl_invariant WaitingForBarrierStoreBufferAlways1AfterAllInitialized @\"\n    forall tid, entry :: && ghosts.all_initialized\n                    && tid in threads\n                    && entry in threads[tid].storeBuffer\n                    && entry.loc.Armada_StoreBufferLocation_Unaddressable?\n                    && entry.loc.v.Armada_GlobalStaticVar_barrier?\n                    && |entry.loc.fields| == 1\n                    && entry.value.Armada_PrimitiveValue_uint32?\n                    ==> entry.value.n_uint32 == 1\"\n  chl_invariant StoreBuffer1ImpliesThreadPastBarrier @\"\n    forall tid, entry :: && ghosts.all_initialized\n                    && |ghosts.threads_past_barrier| == 10\n                    && tid in threads\n                    && entry in threads[tid].storeBuffer\n                    && entry.loc.Armada_StoreBufferLocation_Unaddressable?\n                    && entry.loc.v.Armada_GlobalStaticVar_barrier?\n                    && |entry.loc.fields| == 1\n                    && entry.value.Armada_PrimitiveValue_uint32?\n                    && entry.value.n_uint32 == 1\n                    ==> var which_thread := entry.loc.fields[0];\n                        && 0 <= which_thread < 10\n                        && ghosts.threads_past_barrier[which_thread]\"\n  chl_invariant BarrierAlways0Or1 @\"\n    forall which_thread :: && ghosts.all_initialized\n                      && |globals.barrier| == 10\n                      && 0 <= which_thread < 10\n                      ==> var b := globals.barrier[which_thread]; b == 0 || b == 1\"\n  chl_invariant Barrier1ImpliesThreadPastBarrier @\"\n    forall which_thread :: && ghosts.all_initialized\n                      && |globals.barrier| == 10\n                      && |ghosts.threads_past_barrier| == 10\n                      && 0 <= which_thread < 10\n                      && globals.barrier[which_thread] != 0\n                      ==> ghosts.threads_past_barrier[which_thread]\"\n}\n"
  },
  {
    "path": "Test/barrier/extra.dfy",
    "content": "include \"L1.dfy\"\n\nmodule L1RefinesL2Helpers {\n\n  import opened L = L1\n\n  lemma lemma_FindStoreBuffer1WhenLocalViewSeesIt(\n    which_thread:int,\n    mem:L.Armada_SharedMemory,\n    storeBuffer:seq<L.Armada_StoreBufferEntry>\n    ) returns (\n    entry:L.Armada_StoreBufferEntry\n    )\n    requires forall entry' :: && entry' in storeBuffer\n                        && entry'.loc.Armada_StoreBufferLocation_Unaddressable?\n                        && entry'.loc.v.Armada_GlobalStaticVar_barrier?\n                        && |entry'.loc.fields| == 1\n                        && entry'.value.Armada_PrimitiveValue_uint32?\n                        ==> entry'.value.n_uint32 == 0 || entry'.value.n_uint32 == 1\n    requires |mem.globals.barrier| == 10\n    requires 0 <= which_thread < 10\n    requires var locv := L.Armada_ApplyStoreBuffer(mem, storeBuffer);\n             which_thread < |locv.globals.barrier| && locv.globals.barrier[which_thread] != 0\n    requires mem.globals.barrier[which_thread] == 0\n    ensures  entry in storeBuffer\n    ensures  entry.loc.Armada_StoreBufferLocation_Unaddressable?\n    ensures  entry.loc.v.Armada_GlobalStaticVar_barrier?\n    ensures  |entry.loc.fields| == 1\n    ensures  entry.loc.fields[0] == which_thread\n    ensures  entry.value.Armada_PrimitiveValue_uint32?\n    ensures  entry.value.n_uint32 == 1\n    decreases |storeBuffer|\n  {\n    if |storeBuffer| == 0 {\n      assert false;\n    }\n\n    var entry0 := storeBuffer[0];\n    if && entry0.loc.Armada_StoreBufferLocation_Unaddressable?\n       && entry0.loc.v.Armada_GlobalStaticVar_barrier?\n       && |entry0.loc.fields| == 1\n       && entry0.loc.fields[0] == which_thread\n       && entry0.value.Armada_PrimitiveValue_uint32?\n    {\n      if entry0.value.n_uint32 == 1 {\n        entry := entry0;\n      }\n      else {\n        assert entry0.value.n_uint32 == 0;\n        entry := lemma_FindStoreBuffer1WhenLocalViewSeesIt(which_thread, L.Armada_ApplyStoreBufferEntry(mem, entry0), storeBuffer[1..]);\n      }\n    }\n    else {\n      entry := lemma_FindStoreBuffer1WhenLocalViewSeesIt(which_thread, L.Armada_ApplyStoreBufferEntry(mem, entry0), storeBuffer[1..]);\n    }\n  }\n\n  lemma lemma_BarrierNonzeroInLocalViewImpliesStoreBuffer1OrBarrier1(s:L.Armada_TotalState)\n    requires forall tid, entry :: \n      tid in s.threads &&\n      entry in s.threads[tid].storeBuffer &&\n      entry.loc.Armada_StoreBufferLocation_Unaddressable? &&\n      entry.loc.v.Armada_GlobalStaticVar_barrier? &&\n      |entry.loc.fields| == 1 &&\n      entry.value.Armada_PrimitiveValue_uint32? ==>\n      entry.value.n_uint32 == 0 || entry.value.n_uint32 == 1\n\n    requires forall tid, entry :: \n      s.ghosts.all_initialized &&\n      |s.ghosts.threads_past_barrier| == 10 &&\n      tid in s.threads &&\n      entry in s.threads[tid].storeBuffer &&\n      entry.loc.Armada_StoreBufferLocation_Unaddressable? &&\n      entry.loc.v.Armada_GlobalStaticVar_barrier? &&\n      |entry.loc.fields| == 1 &&\n      entry.value.Armada_PrimitiveValue_uint32? &&\n      entry.value.n_uint32 == 1 ==>\n        var which_thread := entry.loc.fields[0]; 0 <= which_thread < 10 && s.ghosts.threads_past_barrier[which_thread]\n\n    requires forall which_thread :: \n      s.ghosts.all_initialized &&\n      |s.mem.globals.barrier| == 10 &&\n      |s.ghosts.threads_past_barrier| == 10 &&\n      0 <= which_thread < 10 &&\n      s.mem.globals.barrier[which_thread] != 0 ==>\n      s.ghosts.threads_past_barrier[which_thread]\n\n    ensures forall which_thread, viewing_thread :: \n      s.ghosts.all_initialized &&\n      |s.mem.globals.barrier| == 10 &&\n      |s.ghosts.threads_past_barrier| == 10 &&\n      0 <= which_thread < 10 &&\n      viewing_thread in s.threads &&\n      (var locv := L.Armada_GetThreadLocalView(s, viewing_thread);\n       which_thread < |locv.globals.barrier| && locv.globals.barrier[which_thread] != 0) ==>\n        s.ghosts.threads_past_barrier[which_thread]\n  {\n    forall which_thread, viewing_thread |\n      && s.ghosts.all_initialized\n      && |s.mem.globals.barrier| == 10\n      && |s.ghosts.threads_past_barrier| == 10\n      && 0 <= which_thread < 10\n      && viewing_thread in s.threads\n      && (var locv := L.Armada_GetThreadLocalView(s, viewing_thread);\n         which_thread < |locv.globals.barrier| && locv.globals.barrier[which_thread] != 0)\n      ensures s.ghosts.threads_past_barrier[which_thread]\n    {\n      if s.mem.globals.barrier[which_thread] != 0 {\n        assert s.ghosts.threads_past_barrier[which_thread];\n      }\n      else {\n        var entry := lemma_FindStoreBuffer1WhenLocalViewSeesIt(which_thread, s.mem, s.threads[viewing_thread].storeBuffer);\n        assert s.ghosts.threads_past_barrier[which_thread];\n      }\n    }\n  }\n\n}\n"
  },
  {
    "path": "Test/bitvector/.gitignore",
    "content": "A.dfy\nAB.dfy\nAB/\nB.dfy\nSharedStructs.dfy\n"
  },
  {
    "path": "Test/bitvector/bv.dfy",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nmodule BitVectorTest1 {\n\nimport opened ArmadaCommonDefinitions\n\n\nlemma mask_equiv_bv_wrapped(y:bv32)\n  ensures bit_mod32(y, 512) == bit_and32(y, 511);\n{\n  reveal bit_mod32();\n  reveal bit_and32();\n}\n\nlemma mask_equiv_wrapped(x:uint32)\n  ensures bit_mod_uint32(x, 512) == bit_and_uint32(x, 511);\n{\n  assert B32(512) == 512 by { reveal B32(); }\n  assert B32(511) == 511 by { reveal B32(); }\n  calc {\n    bit_mod_uint32(x, 512);\n      { reveal bit_mod_uint32(); reveal B32(); }\n    U32(bit_mod32(B32(x), B32(512)));\n      { mask_equiv_bv_wrapped(B32(x)); assert bit_mod32(B32(x), 512) == bit_and32(B32(x), 511); }\n    U32(bit_and32(B32(x), B32(511)));\n      { reveal bit_and_uint32(); }\n    bit_and_uint32(x, 511);\n  }\n}\n\n\nlemma bit_mod_equiv(u0:uint32, u1:uint32)\n  requires u1 != 0;\n  ensures bit_mod_uint32(u0, u1) == u0 % u1;\n{\n  reveal bit_mod_uint32();\n  bv_core_properties();\n  assert B32(u1) != 0 by { reveal B32(); }\n  assert bit_mod32(B32(u0), B32(u1)) >= 0;\n}\n\nlemma mask_equiv_specific(x:uint32)\n  ensures x % 512 == bit_and_uint32(x, 511);\n{\n  calc {\n    x % 512;\n      { bit_mod_equiv(x, 512); }\n    bit_mod_uint32(x, 512);\n      { mask_equiv_wrapped(x); }\n    bit_and_uint32(x, 511);\n  }\n}\n\n\nlemma mask_equiv()\n  ensures forall x:uint32 :: x % 512 == bit_and_uint32(x, 511);\n{\n   reveal bit_and_uint32();  // Without this, Dafny can't seem to translate the forall statement to the forall expression\n\n  forall x:uint32 \n    ensures x % 512 == bit_and_uint32(x, 511);\n  {\n    mask_equiv_specific(x);\n  }\n}\n\n}\n\n"
  },
  {
    "path": "Test/bitvector/test.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs {\n}\n\nlevel A using SharedStructs {\n    method main()\n    {\n        noaddr var a:uint64, b:uint64, c:uint64;\n        noaddr var x:uint32;\n\n        assert a & 0 == 0;\n\n        c := a & b;\n        c := a | b;\n        c := a ^ b;\n        c := c << 32;\n        c := c >> 32;\n\n        assert x % 512 == x & 511;\n    }\n}\n\nlevel B using SharedStructs {\n    method main()\n    {\n        noaddr var a:uint64, b:uint64, c:uint64;\n        noaddr var x:uint32;\n\n        assert true;\n\n        c := a & b;\n        c := a | b;\n        c := a ^ b;\n        c := c << 32;\n        c := c >> 32;\n        \n        assert true;\n    }\n}\n\nproof AB {\n  refinement A B\n  weakening\n  \n  include_file \"bv.dfy\" \n  import_module BitVectorTest1\n  extra lemma_LiftAtomicPath_From_main_Start_F_To_main_1 \"bv64_properties();\"\n  extra lemma_LiftAtomicPath_From_main_6_F_To_main_End \"mask_equiv();\"\n}\n\n\n"
  },
  {
    "path": "Test/clight/.gitignore",
    "content": "Impl.dfy\nSharedStructs.dfy\nbarrier.c\n"
  },
  {
    "path": "Test/clight/Makefile",
    "content": "\nDAFNYS=$(wildcard *.arm)\nCPPS=$(subst .arm,.c,$(DAFNYS))\nEXECS=$(subst .arm,,$(DAFNYS))\nDAFNY_DIR=../..\nDAFNY=$(DAFNY_DIR)/Binaries/Dafny.exe\nDAFNY_RUNTIME_DIR=$(DAFNY_DIR)/Binaries\nDAFNY_RUNTIME_CPP=$(DAFNY_RUNTIME_DIR)/DafnyRuntime.h\nDAFNY_DEPS=$(DAFNY) $(DAFNY_RUNTIME_DIR)/Dafny.exe $(DAFNY_RUNTIME_DIR)/DafnyPipeline.dll $(DAFNY_RUNTIME_CPP)\nTEST_LOG=tests.log\nifeq ($(OS),Windows_NT)\n\tMONO=\"\"\nelse \n\tMONO=\"mono\"\nendif\n CFLAGS += -Wall -Wextra -Wpedantic -I$(DAFNY_RUNTIME_DIR)\n\n.SECONDARY: $(CPPS)\n\nall:$(EXECS)\n#all:hello ints\n\nvars:\n\techo $(DAFNYS)\n\techo $(CPPS)\n\techo $(EXECS)\n\n%.c: %.arm $(DAFNY) $(DAFNY_DEPS)\n\t$(MONO) $(DAFNY) /compile:0 /spillTargetCode:3 /compileTarget:clight extern.h $<\n\n%.cs: %.arm $(DAFNY) $(DAFNY_DEPS)\n\t$(MONO) $(DAFNY) /noVerify /compile:0 /spillTargetCode:3 /compileTarget:cs $<\n\n$(EXECS): % : %.c $(DAFNY_RUNTIME_CPP)\n\t$(CC) $(CFLAGS) -o $@ $<\n\ntest: $(EXECS)\n\tfor e in $(EXECS); do echo; echo \"*******************\"; echo \"Running $$e\"; echo \"*******************\"; echo; ./$$e; done | tee $(TEST_LOG)\n#\tgrep unexpected $(TEST_LOG)\n#\tif [ $$? -ne 0 ]; then\n#\t  echo \"FAILED A TEST\"\n#\telse\n#\t\techo \"SUCCESS!\"\n#\tfi\n\nclean:\n\trm -f *.c *.dfy $(EXECS) $(TEST_LOG)\n"
  },
  {
    "path": "Test/clight/barrier.arm",
    "content": "// Compile with:  ../../Binaries/Armada.exe /compile:0 /spillTargetCode:3 /compileTarget:clight extern.h barrier.arm\n\ninclude \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs\n{\n  ghost var log:seq<uint32> := [];\n\n  refinement_constraint @\"\n     || (ls.stop_reason == hs.stop_reason && ls.ghosts.log == hs.ghosts.log)\n     || (ls.stop_reason.Armada_NotStopped? && ls.ghosts.log <= hs.ghosts.log)\n  \"\n}\n\nlevel {:concrete} Impl using SharedStructs\n{\n  noaddr var barrier:uint32[10];\n\n  method {:extern} print_uint32(i:uint32)\n  {\n    log := log + [i];\n  }\n\n  method worker(id:uint32)\n  {\n    noaddr var waiting_for_barrier:int8 := 1;\n    noaddr var i:uint32;\n     \n    print_uint32(id);\n\n    barrier[id] := 1;\n    while waiting_for_barrier != 0\n    {\n      waiting_for_barrier := 0;\n      i := 0;\n      while i < 10\n      {\n        if barrier[i] == 0\n        {\n          waiting_for_barrier := 1;\n        }\n        i := i + 1;\n      }\n    }\n\n    print_uint32(id + 100);\n  }\n\n  method main()\n  {\n    noaddr var i:uint32;\n    noaddr var tids:uint64[10];\n\n    i := 0;\n    while i < 10\n    {\n      barrier[i] := 0;\n      i := i + 1;\n    }\n\n    fence;\n\n    i := 0;\n    while i < 10\n    {\n      tids[i] := create_thread worker(i);\n      i := i + 1;\n    }\n\n    i := 0;\n    while i < 10\n    {\n      join tids[i];\n      i := i + 1;\n    }\n  }\n\n}\n"
  },
  {
    "path": "Test/clight/bench/bench_armada.c",
    "content": "// This file contains the benchmark for armada implementation of bounded_singleproducer_singleconsumer queue.\n\n\n// 1. Armada with CompCertTSO\n//    First copy bench_armada.c, extern.h and DafnyRuntime.h to the CompCertTSO directory,\n//    Then run the following instruction to compile:\n//    ./ccomp -ralloc -stdlib runtime -lpthread -o bench_armada bench_armada.c\n\n// To run the benchmark:\n// ./bench_armada number_elements number_of_runs | tee log_{number_elements}_{number_of_runs}.txt\n\n// number_elements is the size of the queue, it has to be 2^n, n > 0;\n// number_of_runs is the number of runs we want to exec.\n// The program will print total_time(secs) and throughput(ops/sec) for each run to stdout\n// and tee will log the reults to the file.\n\n#include <stdio.h>\n#include <string.h>\n#include <pthread.h>\n#include <stdlib.h> \n#include <time.h>\n\n// Dafny program queue.arm compiled into ClightTSO\n#include \"DafnyRuntime.h\"\n#include \"extern.h\"\n// namespace _8_SharedStructs \nstruct BSSQueueElement;\ntypedef struct BSSQueueElement BSSQueueElement;\nstruct BSSQueueElement {\n  uint32 key;\n  uint32 value;\n};\nstruct QbssState;\ntypedef struct QbssState QbssState;\nstruct QbssState {\n  uint32 array_size;\n  uint32 mask;\n  uint32 read_index;\n  uint32 write_index;\n  struct BSSQueueElement* element_array;\n  uint32* user_state;\n};\n// namespace _11_EnqueueBSS \n// Global Variables\n// Param Stucts\nstruct _params_of_enqueue_log;\ntypedef struct _params_of_enqueue_log _params_of_enqueue_log;\nstruct _params_of_enqueue_log {\n  uint32 k;\n  uint32 v;\n};\nstruct _params_of_dequeue_log;\ntypedef struct _params_of_dequeue_log _params_of_dequeue_log;\nstruct _params_of_dequeue_log {\n  uint32 k;\n  uint32 v;\n};\nstruct _params_of_enqueue;\ntypedef struct _params_of_enqueue _params_of_enqueue;\nstruct _params_of_enqueue {\n  struct QbssState* state;\n  uint32 k;\n  uint32 v;\n};\nstruct _params_of_dequeue;\ntypedef struct _params_of_dequeue _params_of_dequeue;\nstruct _params_of_dequeue {\n  struct QbssState* state;\n  uint32* k;\n  uint32* v;\n};\nstruct _params_of_init_queue;\ntypedef struct _params_of_init_queue _params_of_init_queue;\nstruct _params_of_init_queue {\n  struct QbssState* que;\n  uint32 size;\n};\nstruct _params_of__main;\ntypedef struct _params_of__main _params_of__main;\nstruct _params_of__main {\n};\n// Method Decls\nvoid* _thread_of_enqueue_log (void* vargs);\nvoid* _thread_of_dequeue_log (void* vargs);\nuint32 enqueue(struct QbssState* state, uint32 k, uint32 v);\nvoid* _thread_of_enqueue (void* vargs);\nuint32 dequeue(struct QbssState* state, uint32* k, uint32* v);\nvoid* _thread_of_dequeue (void* vargs);\nvoid init_queue(struct QbssState* que, uint32 size);\nvoid* _thread_of_init_queue (void* vargs);\nvoid _main();\nvoid* _thread_of__main (void* vargs);\n// Methods Defns\n// Skipped extern method enqueue_log\nvoid* _thread_of_enqueue_log (void* vargs) {\n  _params_of_enqueue_log args = *((_params_of_enqueue_log *) vargs);\n  enqueue_log (args.k,args.v);\n  return NULL;\n}\n// Skipped extern method dequeue_log\nvoid* _thread_of_dequeue_log (void* vargs) {\n  _params_of_dequeue_log args = *((_params_of_dequeue_log *) vargs);\n  dequeue_log (args.k,args.v);\n  return NULL;\n}\n// Beginning of method enqueue\nuint32 enqueue(struct QbssState* state, uint32 k, uint32 v)\n{\n  uint32 ret = 0;\n  uint32 _0_write__index;\n  _0_write__index = (*(state)).write_index;\nafter_0: ;\n  uint32 _1_mask;\n  _1_mask = (*(state)).mask;\n  uint32 _2_read__index;\n  _2_read__index = (*(state)).read_index;\n  struct BSSQueueElement* _3_e = NULL;\n  if ((((_0_write__index) + ((uint32)1)) & (_1_mask)) != (_2_read__index)) {\n    _3_e = ((*(state)).element_array) + (_0_write__index);\n  after_2: ;\n    (*(_3_e)).key = k;\n  after_3: ;\n    (*(_3_e)).value = v;\n  after_4: ;\n    (*(state)).write_index = ((_0_write__index) + ((uint32)1)) & (_1_mask);\n  after_5: ;\n    ret = (uint32)1;\n    return ret;\n  after_6: ;\n  }\nafter_1: ;\n  ret = (uint32)0;\n  return ret;\n}\nvoid* _thread_of_enqueue (void* vargs) {\n  _params_of_enqueue args = *((_params_of_enqueue *) vargs);\n  enqueue (args.state,args.k,args.v);\n  return NULL;\n}\n// End of method enqueue\n\n// Beginning of method dequeue\nuint32 dequeue(struct QbssState* state, uint32* k, uint32* v)\n{\n  uint32 ret = 0;\n  uint32 _4_write__index;\n  _4_write__index = (*(state)).write_index;\n  uint32 _5_mask;\n  _5_mask = (*(state)).mask;\n  uint32 _6_read__index;\n  _6_read__index = (*(state)).read_index;\n  struct BSSQueueElement* _7_e = NULL;\n  uint32 _8_key = 0;\n  uint32 _9_value = 0;\n  if ((_6_read__index) != (_4_write__index)) {\n    _7_e = ((*(state)).element_array) + (_6_read__index);\n    if ((k) != (NULL)) {\n      _8_key = (*(_7_e)).key;\n      *k = _8_key;\n    }\n    if ((v) != (NULL)) {\n      _9_value = (*(_7_e)).value;\n      *v = _9_value;\n    }\n    (*(state)).read_index = ((_6_read__index) + ((uint32)1)) & (_5_mask);\n    ret = (uint32)1;\n    return ret;\n  }\n  ret = (uint32)0;\n  return ret;\n}\nvoid* _thread_of_dequeue (void* vargs) {\n  _params_of_dequeue args = *((_params_of_dequeue *) vargs);\n  dequeue (args.state,args.k,args.v);\n  return NULL;\n}\n// End of method dequeue\n\n// Beginning of method init_queue\nvoid init_queue(struct QbssState* que, uint32 size)\n{\n  (*(que)).array_size = size;\n  (*(que)).user_state = NULL;\n  (*(que)).mask = (size) - ((uint32)1);\n  (*(que)).element_array = (struct BSSQueueElement*) calloc((size_t)(size), sizeof(struct BSSQueueElement));\n  (*(que)).write_index = (uint32)0;\n  (*(que)).read_index = (uint32)0;\n}\nvoid* _thread_of_init_queue (void* vargs) {\n  _params_of_init_queue args = *((_params_of_init_queue *) vargs);\n  init_queue (args.que,args.size);\n  return NULL;\n}\n// End of method init_queue\n\n\n// Beginning of Bench code\n\nvoid cleanup_queue(struct QbssState* que) {\n  free((*que).element_array); \n}\n\nstruct param {\n  uint32 warmup_queires;\n  uint32 total_queries;\n};\n\n\nstruct QbssState qbsss;\n\nvoid run_enqueue(uint32 warmup_queires ,uint32 total_queries) {\n  //printf(\"enqueue warmup_queires = %u total_queries = %u\\n\",warmup_queires,total_queries);\n  int ret;\n  uint32 value;\n  for(int i = 0; i < warmup_queires; ++i) {\n    value = i;\n    do {\n      ret = enqueue( &qbsss, (uint32)0, (void*) value );\n    } while(!ret);\n    //printf(\"Warm-up Enqueued = %d\\n\", value);\n  }\n  struct timespec start, stop;\n  clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start);\n  for(int i = 0; i < total_queries; ++i) {\n    value = i;\n    do {\n      ret = enqueue( &qbsss, (uint32)0, (void*) value );\n    } while(!ret);\n    //printf(\"Enqueued = %d\\n\", value);\n  }\n  clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &stop);\n  double total_time_in_sec =  (stop.tv_sec - start.tv_sec) + (stop.tv_nsec - start.tv_nsec) / 1e9;\n  double tput = (double) total_queries / total_time_in_sec;\n  printf(\"%.f, %.f\\n\",total_time_in_sec, tput);\n  fflush(stdout);\n}\n\n\nvoid run_dequeue(uint32 warmup_queires ,uint32 total_queries) {\n  //printf(\"dequeue warmup_queires = %u total_queries = %u\\n\",warmup_queires,total_queries);\n  uint32 value;\n  int ret;\n  for(int i = 0; i < warmup_queires; ++i) {\n    do {\n      ret = dequeue( &qbsss, NULL, (void**) &value );\n    } while(!ret);\n  }\n  for(int i = 0; i < total_queries; ++i) {\n      do {\n      ret = dequeue( &qbsss, NULL, (void**) &value );\n    } while(!ret);\n  }\n}\n\nvoid* thread_run_enqueue(void* vargs) {\n  struct param* args = (struct param*) vargs;\n  run_enqueue(args->warmup_queires, args->total_queries);\n}\n\nvoid* thread_run_dequeue(void* vargs) {\n  struct param* args = (struct param*) vargs;\n  run_dequeue(args->warmup_queires, args->total_queries);\n}\n\n\n\nvoid bench(uint32 number_elements, uint32 warmup_queires ,uint32 total_queries) {\n  pthread_t tid1, tid2;\n  struct param \n    param;\n  param.warmup_queires = warmup_queires;\n  param.total_queries = total_queries;\n  init_queue( &qbsss, number_elements);\n  pthread_create(&tid1, NULL, thread_run_enqueue, &param);\n  pthread_create(&tid2, NULL, thread_run_dequeue, &param);\n  pthread_join(tid1, NULL);\n  pthread_join(tid2, NULL);\n  cleanup_queue(&qbsss);\n }\n\nint main(int argc, char *argv[])\n{\n  if(argc != 3) {\n    printf(\"Invalid number of args\\n\");\n    return -1;\n  }\n  uint32 number_elements = (uint32)atoi(argv[1]);\n  uint32 number_of_runs = (uint32) atoi(argv[2]);\n  uint32 warmup = 5000000;\n  uint32 total =  50000000;\n  printf(\"number_elements = %u, warmup_queires = %u, total_queries = %u\\n\",number_elements,warmup,total);\n  printf(\"total_time(secs), throughput(ops/sec)\\n\");\n  fflush(stdout);\n  for(int i = 0; i < number_of_runs; ++i) {\n    bench(number_elements, warmup, total);\n  }\n  return 0;\n}"
  },
  {
    "path": "Test/clight/bench/bench_armada_gcc.c",
    "content": "// This file contains the benchmark for aramda implementation of bounded_singleproducer_singleconsumer queue.\n\n// To compile the benchmark:\n// Without -O2:\n// gcc -fno-strict-aliasing -llfds711 -lpthread -o bench_armada_gcc bench_armada_gcc.c\n// With -O2:\n// gcc -fno-strict-aliasing -O2 -DNDEBUG  -llfds711 -lpthread -o bench_armada_gcc bench_armada_gcc.c\n\n// To run the benchmark:\n// ./bench_armada_gcc number_elements number_of_runs | tee log_{number_elements}_{number_of_runs}.txt\n// number_elements is the size of the queue, it has to be 2^n, n > 0;\n// number_of_runs is the number of runs we want to exec.\n\n// The program will print total_time(secs) and throughput(ops/sec) for each run to stdout\n// and tee will log the reults to the file.\n\n#include <stdio.h>\n#include <string.h>\n#include <pthread.h>\n#include <stdlib.h> \n#include <time.h>\n#include \"liblfds711.h\"\n\ntypedef unsigned long      uint32;\n\nstruct param {\n  uint32 warmup_queires;\n  uint32 total_queries;\n};\n\nstruct armada_QbssState \n  qbsss;\n\n\nvoid run_enqueue(uint32 warmup_queires ,uint32 total_queries) {\n  //printf(\"enqueue warmup_queires = %u total_queries = %u\\n\",warmup_queires,total_queries);\n  int ret;\n  uint32 value;\n  for(int i = 0; i < warmup_queires; ++i) {\n    value = i;\n    do {\n      ret = armada_enqueue( &qbsss, 0, value );\n    } while(!ret);\n    //printf(\"Warm-up Enqueued = %d\\n\", value);\n  }\n  struct timespec start, stop;\n  clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start);\n  for(int i = 0; i < total_queries; ++i) {\n    value = i;\n    do {\n      ret = armada_enqueue( &qbsss, 0, value );\n    } while(!ret);\n    //printf(\"Enqueued = %d\\n\", value);\n  }\n  clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &stop);\n  double total_time_in_sec =  (stop.tv_sec - start.tv_sec) + (stop.tv_nsec - start.tv_nsec) / 1e9;\n  double tput = (double) total_queries / total_time_in_sec;\n  printf(\"%.f, %.f\\n\",total_time_in_sec, tput);\n  fflush(stdout);\n}\n\n\nvoid run_dequeue(uint32 warmup_queires ,uint32 total_queries) {\n  //printf(\"dequeue warmup_queires = %u total_queries = %u\\n\",warmup_queires,total_queries);\n  uint32 value;\n  int ret;\n  for(int i = 0; i < warmup_queires; ++i) {\n    do {\n      ret = armada_dequeue( &qbsss, NULL, (void**) &value );\n    } while(!ret);\n  }\n  for(int i = 0; i < total_queries; ++i) {\n      do {\n      ret = armada_dequeue( &qbsss, NULL, (void**) &value );\n    } while(!ret);\n  }\n}\n\nvoid* thread_run_enqueue(void* vargs) {\n  struct param* args = (struct param*) vargs;\n  run_enqueue(args->warmup_queires, args->total_queries);\n}\n\nvoid* thread_run_dequeue(void* vargs) {\n  struct param* args = (struct param*) vargs;\n  run_dequeue(args->warmup_queires, args->total_queries);\n}\n\n\n\nvoid bench(uint32 number_elements, uint32 warmup_queires ,uint32 total_queries) {\n  struct armada_BSSQueueElement* \n    qbsse = calloc(number_elements, sizeof(struct armada_BSSQueueElement));\n  pthread_t tid1, tid2;\n  struct param \n    param;\n  param.warmup_queires = warmup_queires;\n  param.total_queries = total_queries;\n\n  armada_init_queue( &qbsss, qbsse, number_elements, NULL );\n  pthread_create(&tid1, NULL, thread_run_enqueue, &param);\n  pthread_create(&tid2, NULL, thread_run_dequeue, &param);\n  pthread_join(tid1, NULL);\n  pthread_join(tid2, NULL);\n }\n\nint main(int argc, char *argv[])\n{\n  if(argc != 3) {\n    printf(\"Invalid number of args\\n\");\n    return -1;\n  }\n  uint32 number_elements = (uint32)atoi(argv[1]);\n  uint32 number_of_runs = (uint32) atoi(argv[2]);\n  uint32 warmup = 5000000;\n  uint32 total =  50000000;\n  printf(\"number_elements = %u, warmup_queires = %u, total_queries = %u\\n\",number_elements,warmup,total);\n  printf(\"total_time(secs), throughput(ops/sec)\\n\");\n  fflush(stdout);\n  for(int i = 0; i < number_of_runs; ++i) {\n    bench(number_elements, warmup, total);\n  }\n  return 0;\n}"
  },
  {
    "path": "Test/clight/bench/bench_lfds.c",
    "content": "// This file contains the benchmark for liblfds implementation of bounded_singleproducer_singleconsumer queue.\n\n// You need to first build and install liblfds:\n// 0. Download the liblfds7.1.1 repo: git clone https://github.com/liblfds/liblfds7.1.1.git\n// 1. Go to liblfds7.1.1/liblfds711/build/gcc_gnumake\n// 2. Run \"sudo make so_uninstall\" to clean up the env.\n// 3. Run \"make clean\" to clean up the cache.\n// 4. Run \"make so_rel\" to build with release flag (-O2), or \"make so_vanilla\" to build with no flag.\n// 5. Run \"sudo make so_install\" to install the lib. \n\n\n// To setput the following configs:\n// 1. liblfds with bitmask: build the original lib with \"so_vanilla\".\n// 2. liblfds with bitmask (-O2): build the original lib with \"so_rel\"\n// 3. liblfds with modulo: \n//     (1). Modify line 31 of the file liblfds7.1.1/liblfds711/src/lfds711_queue_bounded_singleproducer_singleconsumer/lfds711_queue_bounded_singleproducer_singleconsumer_enqueue.c:\n//        \"qbsss->write_index = (qbsss->write_index + 1) & qbsss->mask;\" -> \"qbsss->write_index = (qbsss->write_index + 1) % qbsss->number_elements;\"\n//     (2). Modify line 32 of the file liblfds7.1.1/liblfds711/src/lfds711_queue_bounded_singleproducer_singleconsumer/lfds711_queue_bounded_singleproducer_singleconsumer_dequeue.c:\n//        \"qbsss->read_index = (qbsss->read_index + 1) & qbsss->mask;\" -> \"qbsss->read_index = (qbsss->read_index + 1) % qbsss->number_elements;\"\n//     (3). Build and install with flag \"so_vanilla\".\n// 4. liblfds with modulo (-O2):\n//      (1) : same as \"liblfds with modulo\"\n//      (2) : same as \"liblfds with modulo\"\n//      (3) : Build and install with flag \"so_rel\"\n\n\n// To compile the benchmark:\n// Without -O2:\n// gcc -fno-strict-aliasing -llfds711 -lpthread -o bench_lfds bench_lfds.c\n// With -O2:\n// gcc -fno-strict-aliasing -O2 -DNDEBUG  -llfds711 -lpthread -o bench_lfds bench_lfds.c\n\n// To run the benchmark:\n// ./bench_lfds number_elements number_of_runs | tee log_{number_elements}_{number_of_runs}.txt\n// number_elements is the size of the queue, it has to be 2^n, n > 0;\n// number_of_runs is the number of runs we want to exec.\n\n// The program will print total_time(secs) and throughput(ops/sec) for each run to stdout\n// and tee will log the reults to the file.\n\n#include <stdio.h>\n#include <string.h>\n#include <pthread.h>\n#include <stdlib.h> \n#include <time.h>\n#include \"liblfds711.h\"\n\ntypedef unsigned long      uint32;\n\nstruct param {\n  uint32 warmup_queires;\n  uint32 total_queries;\n};\n\nstruct lfds711_queue_bss_state \n  qbsss;\n\n\nvoid run_enqueue(uint32 warmup_queires ,uint32 total_queries) {\n  //printf(\"enqueue warmup_queires = %u total_queries = %u\\n\",warmup_queires,total_queries);\n  int ret;\n  uint32 value;\n  for(int i = 0; i < warmup_queires; ++i) {\n    value = i;\n    do {\n      ret = lfds711_queue_bss_enqueue( &qbsss, NULL, (void*)&value );\n    } while(!ret);\n    //printf(\"Warm-up Enqueued = %d\\n\", value);\n  }\n  struct timespec start, stop;\n  clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start);\n  for(int i = 0; i < total_queries; ++i) {\n    value = i;\n    do {\n      ret = lfds711_queue_bss_enqueue( &qbsss, NULL, (void*)&value );\n    } while(!ret);\n    //printf(\"Enqueued = %d\\n\", value);\n  }\n  clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &stop);\n  double total_time_in_sec =  (stop.tv_sec - start.tv_sec) + (stop.tv_nsec - start.tv_nsec) / 1e9;\n  double tput = (double) total_queries / total_time_in_sec;\n  printf(\"%.f, %.f\\n\",total_time_in_sec, tput);\n  fflush(stdout);\n}\n\n\nvoid run_dequeue(uint32 warmup_queires ,uint32 total_queries) {\n  //printf(\"dequeue warmup_queires = %u total_queries = %u\\n\",warmup_queires,total_queries);\n  uint32 value;\n  int ret;\n  for(int i = 0; i < warmup_queires; ++i) {\n    do {\n      ret = lfds711_queue_bss_dequeue( &qbsss, NULL, (void**) &value );\n    } while(!ret);\n  }\n  for(int i = 0; i < total_queries; ++i) {\n      do {\n      ret = lfds711_queue_bss_dequeue( &qbsss, NULL, (void**) &value );\n    } while(!ret);\n  }\n}\n\nvoid* thread_run_enqueue(void* vargs) {\n  struct param* args = (struct param*) vargs;\n  run_enqueue(args->warmup_queires, args->total_queries);\n}\n\nvoid* thread_run_dequeue(void* vargs) {\n  struct param* args = (struct param*) vargs;\n  run_dequeue(args->warmup_queires, args->total_queries);\n}\n\n\n\nvoid bench(uint32 number_elements, uint32 warmup_queires ,uint32 total_queries) {\n  struct lfds711_queue_bss_element* \n    qbsse = calloc(number_elements, sizeof(struct lfds711_queue_bss_element));\n  pthread_t tid1, tid2;\n  struct param \n    param;\n  param.warmup_queires = warmup_queires;\n  param.total_queries = total_queries;\n\n  lfds711_queue_bss_init_valid_on_current_logical_core( &qbsss, qbsse, number_elements, NULL );\n  pthread_create(&tid1, NULL, thread_run_enqueue, &param);\n  pthread_create(&tid2, NULL, thread_run_dequeue, &param);\n  pthread_join(tid1, NULL);\n  pthread_join(tid2, NULL);\n  lfds711_queue_bss_cleanup( &qbsss, NULL );\n }\n\nint main(int argc, char *argv[])\n{\n  if(argc != 3) {\n    printf(\"Invalid number of args\\n\");\n    return -1;\n  }\n  uint32 number_elements = (uint32)atoi(argv[1]);\n  uint32 number_of_runs = (uint32) atoi(argv[2]);\n  uint32 warmup = 5000000;\n  uint32 total =  50000000;\n  printf(\"number_elements = %u, warmup_queires = %u, total_queries = %u\\n\",number_elements,warmup,total);\n  printf(\"total_time(secs), throughput(ops/sec)\\n\");\n  fflush(stdout);\n  for(int i = 0; i < number_of_runs; ++i) {\n    bench(number_elements, warmup, total);\n  }\n  return 0;\n}\n"
  },
  {
    "path": "Test/clight/bench/bench_sound_queue.c",
    "content": "// Dafny program queue.arm compiled into ClightTSO\n#include \"DafnyRuntime.h\"\n#include \"extern.h\"\n// namespace _8_SharedStructs \nstruct BSSQueueElement;\ntypedef struct BSSQueueElement BSSQueueElement;\nstruct BSSQueueElement {\n  uint64 key;\nuint64 value;\n};\nstruct QbssState;\ntypedef struct QbssState QbssState;\nstruct QbssState {\n  uint64 number_elements;\nuint64 mask;\nuint64 write_index;\nuint64 read_index;\nstruct BSSQueueElement* element_array;\nuint64 array_size;\n};\nstruct BackoffState;\ntypedef struct BackoffState BackoffState;\nstruct BackoffState {\n  uint64 lock;\nuint64 backoff_iteration_frequency_counters[2];uint64 metric;\nuint64 total_operations;\n};\n// namespace _11_QueueBSS__TSObypass \n// Global Variables\nstruct QbssState queue;\n// Param Stucts\nstruct _params_of_init_queue;\ntypedef struct _params_of_init_queue _params_of_init_queue;\nstruct _params_of_init_queue {\n  uint64 size;\n};\nstruct _params_of_enqueue;\ntypedef struct _params_of_enqueue _params_of_enqueue;\nstruct _params_of_enqueue {\n  uint64 k;\nuint64 v;\n};\nstruct _params_of_dequeue;\ntypedef struct _params_of_dequeue _params_of_dequeue;\nstruct _params_of_dequeue {\n  uint64* k;\nuint64* v;\n};\nstruct _params_of__main;\ntypedef struct _params_of__main _params_of__main;\nstruct _params_of__main {\n};\n// Method Decls\nvoid init_queue(uint64 size);\nvoid* _thread_of_init_queue (void* vargs);\nuint64 enqueue(uint64 k, uint64 v);\nvoid* _thread_of_enqueue (void* vargs);\nuint64 dequeue(uint64* k, uint64* v);\nvoid* _thread_of_dequeue (void* vargs);\nvoid _main();\nvoid* _thread_of__main (void* vargs);\n// Methods Defns\n// Beginning of method init_queue\nvoid init_queue(uint64 size)\n{\n  (queue).array_size = size;\n  (queue).read_index = (uint64)0;\n  (queue).write_index = (uint64)0;\n  (queue).element_array = (struct BSSQueueElement*) calloc((size_t)((queue).array_size), sizeof(struct BSSQueueElement));\n}\nvoid* _thread_of_init_queue (void* vargs) {\n  _params_of_init_queue args = *((_params_of_init_queue *) vargs);\ninit_queue (args.size);\nreturn NULL;\n}\n// End of method init_queue\n\n// Beginning of method enqueue\nuint64 enqueue(uint64 k, uint64 v)\n{\n  uint64 ret = 0;\n  struct BSSQueueElement* _0_e = NULL;\n  uint64 _1_read__index = 0;\n  uint64 _2_array__size = 0;\n  uint64 _3_write__index = 0;\n  uint64 _4_modulo = 0;\n  uint64 _5_tmp__write__index = 0;\n  struct BSSQueueElement* _6_element = NULL;\n  struct BSSQueueElement* _7_tmp__array = NULL;\n  _3_write__index = (queue).write_index;\nafter_0: ;\n  _5_tmp__write__index = (_3_write__index) + ((uint64)1);\nafter_1: ;\n  _2_array__size = (queue).array_size;\nafter_2: ;\n  _4_modulo = (_5_tmp__write__index) % (_2_array__size);\nafter_3: ;\n  _1_read__index = (queue).read_index;\n  if ((_1_read__index) != (_4_modulo)) {\n    _3_write__index = (queue).write_index;\n  after_5: ;\n    _7_tmp__array = (queue).element_array;\n    _6_element = ((queue).element_array) + (_3_write__index);\n    _0_e = _6_element;\n  after_6: ;\n    (*(_0_e)).key = k;\n  after_7: ;\n    (*(_0_e)).value = v;\n  after_8: ;\n    _3_write__index = (queue).write_index;\n    _5_tmp__write__index = (_3_write__index) + ((uint64)1);\n    _2_array__size = (queue).array_size;\n    _4_modulo = (_5_tmp__write__index) % (_2_array__size);\n    (queue).write_index = _4_modulo;\n  after_9: ;\n    ret = (uint64)1;\nreturn ret;\n  }\nafter_4: ;\n  ret = (uint64)0;\nreturn ret;\n  return ret;\n}\nvoid* _thread_of_enqueue (void* vargs) {\n  _params_of_enqueue args = *((_params_of_enqueue *) vargs);\nenqueue (args.k,args.v);\nreturn NULL;\n}\n// End of method enqueue\n\n// Beginning of method dequeue\nuint64 dequeue(uint64* k, uint64* v)\n{\n  uint64 ret = 0;\n  struct BSSQueueElement* _8_e = NULL;\n  uint64 _9_read__index = 0;\n  uint64 _10_array__size = 0;\n  uint64 _11_write__index = 0;\n  uint64 _12_modulo = 0;\n  uint64 _13_tmp__read__index = 0;\n  uint64 _14_tmp__int = 0;\n  struct BSSQueueElement* _15_tmp__array = NULL;\n  struct BSSQueueElement* _16_element = NULL;\n  _9_read__index = (queue).read_index;\nafter_10: ;\n  _11_write__index = (queue).write_index;\n  if ((_9_read__index) != (_11_write__index)) {\n    _9_read__index = (queue).read_index;\n  after_12: ;\n    _15_tmp__array = (queue).element_array;\n    _16_element = (_15_tmp__array) + (_9_read__index);\n    _8_e = _16_element;\n    if ((k) != (NULL)) {\n      _14_tmp__int = (*(_8_e)).key;\n      *k = _14_tmp__int;\n    }\n    if ((v) != (NULL)) {\n      _14_tmp__int = (*(_8_e)).value;\n      *v = _14_tmp__int;\n    }\n    _9_read__index = (queue).read_index;\n    _13_tmp__read__index = (_9_read__index) + ((uint64)1);\n  after_13: ;\n    _10_array__size = (queue).array_size;\n  after_14: ;\n    _12_modulo = (_13_tmp__read__index) % (_10_array__size);\n  after_15: ;\n    (queue).read_index = _12_modulo;\n  after_16: ;\n    ret = (uint64)1;\nreturn ret;\n  }\nafter_11: ;\n  ret = (uint64)0;\nreturn ret;\n  return ret;\n}\nvoid* _thread_of_dequeue (void* vargs) {\n  _params_of_dequeue args = *((_params_of_dequeue *) vargs);\ndequeue (args.k,args.v);\nreturn NULL;\n}\n// End of method dequeue\n\n// Beginning of method _main\nvoid _main()\n{\n  uint64 _17_tid1;\n  _17_tid1 = (uint64)0;\n  uint64 _18_tid2;\n  _18_tid2 = (uint64)0;\n  uint64* _19_k;\n  _19_k = NULL;\n  uint64* _20_v;\n  _20_v = NULL;\n  _19_k = (uint64*) calloc((size_t)1, sizeof(uint64));\n  _20_v = (uint64*) calloc((size_t)1, sizeof(uint64));\n  (queue).array_size = (uint64)4;\nafter_17: ;\n  (queue).read_index = (uint64)0;\nafter_18: ;\n  (queue).write_index = (uint64)0;\nafter_19: ;\n  (queue).element_array = (struct BSSQueueElement*) calloc((size_t)((queue).array_size), sizeof(struct BSSQueueElement));\n  // Marked as Ghost\nif (((((queue).element_array) != (NULL)) && ((_19_k) != (NULL))) && ((_20_v) != (NULL))) {\n  }\n}\nvoid* _thread_of__main (void* vargs) {\n  _params_of__main args = *((_params_of__main *) vargs);\n_main ();\nreturn NULL;\n}\n////////////////////////////////////////////////////////////////////////////////\n// Beginning of benchmark code\n////////////////////////////////////////////////////////////////////////////////\n\nvoid cleanup_queue(struct QbssState* que) {\n  free((*que).element_array); \n}\n\nstruct param {\n  uint64 warmup_queires;\n  uint64 total_queries;\n};\n\n\nstruct QbssState qbsss;\n\nvoid run_enqueue(uint64 warmup_queires ,uint64 total_queries) {\n  //printf(\"enqueue warmup_queires = %u total_queries = %u\\n\",warmup_queires,total_queries);\n  int ret;\n  uint64 value;\n  for(int i = 0; i < warmup_queires; ++i) {\n    value = i;\n    do {\n      ret = enqueue(0, value);\n    } while(!ret);\n    //printf(\"Warm-up Enqueued = %d\\n\", value);\n  }\n  struct timespec start, stop;\n  clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start);\n  for(int i = 0; i < total_queries; ++i) {\n    value = i;\n    do {\n      ret = enqueue((uint64)0, value );\n    } while(!ret);\n    //printf(\"Enqueued = %d\\n\", value);\n  }\n  clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &stop);\n  double total_time_in_sec =  (stop.tv_sec - start.tv_sec) + (stop.tv_nsec - start.tv_nsec) / 1e9;\n  double tput = (double) total_queries / total_time_in_sec;\n  printf(\"%.f, %.f\\n\",total_time_in_sec, tput);\n  fflush(stdout);\n}\n\n\nvoid run_dequeue(uint64 warmup_queires ,uint64 total_queries) {\n  //printf(\"dequeue warmup_queires = %u total_queries = %u\\n\",warmup_queires,total_queries);\n  uint64 value;\n  int ret;\n  for(int i = 0; i < warmup_queires; ++i) {\n    do {\n      ret = dequeue(NULL, &value );\n    } while(!ret);\n  }\n  for(int i = 0; i < total_queries; ++i) {\n      do {\n      ret = dequeue(NULL, &value );\n    } while(!ret);\n  }\n}\n\nvoid* thread_run_enqueue(void* vargs) {\n  struct param* args = (struct param*) vargs;\n  run_enqueue(args->warmup_queires, args->total_queries);\n}\n\nvoid* thread_run_dequeue(void* vargs) {\n  struct param* args = (struct param*) vargs;\n  run_dequeue(args->warmup_queires, args->total_queries);\n}\n\n\n\nvoid bench(uint64 number_elements, uint64 warmup_queires ,uint64 total_queries) {\n  pthread_t tid1, tid2;\n  struct param \n    param;\n  param.warmup_queires = warmup_queires;\n  param.total_queries = total_queries;\n  init_queue(number_elements);\n  pthread_create(&tid1, NULL, thread_run_enqueue, &param);\n  pthread_create(&tid2, NULL, thread_run_dequeue, &param);\n  pthread_join(tid1, NULL);\n  pthread_join(tid2, NULL);\n  cleanup_queue(&qbsss);\n }\n\nint main(int argc, char *argv[])\n{\n  if(argc != 3) {\n    printf(\"Invalid number of args\\n\");\n    return -1;\n  }\n  uint64 number_elements = (uint64)atoi(argv[1]);\n  uint64 number_of_runs = (uint64) atoi(argv[2]);\n  uint64 warmup = 5000000;\n  uint64 total =  50000000;\n  printf(\"number_elements = %u, warmup_queires = %u, total_queries = %u\\n\",number_elements,warmup,total);\n  printf(\"total_time(secs), throughput(ops/sec)\\n\");\n  fflush(stdout);\n  for(int i = 0; i < number_of_runs; ++i) {\n    bench(number_elements, warmup, total);\n  }\n  return 0;\n}\n"
  },
  {
    "path": "Test/clight/extern.h",
    "content": "#pragma once\n#include \"DafnyRuntime.h\"\n\n// Extern for sqrt\nuint32 rnd()\n{\n  uint32 x = (uint32) rand() % 0xFFFF;\n  return x;\n}\n\nvoid init_random()\n{\n  srand(time(NULL));\n}\n\nvoid print_uint32(uint32 i)\n{\n  printf(\"%lu\\n\", i);\n}\n\n\n// Extern for lock\n// testing\nchar messages[6][50] =\n  {\n   \"thread 1\",\n   \"thread 2\",\n   \"thread 3\",\n   \"thread 4\",\n   \"thread 5\",\n   \"Finished thread creation\"\n};\n\nvoid my_puts_unlocked(uint32 i) {\n  char* str = messages[i];\n  while (*str != '\\0') {\n    #ifdef __GNUC__\n    putc_unlocked(*str, stdout);\n    #else \n    putc(*str, stdout);\n    #endif\n    ++ str;\n  }\n   #ifdef __GNUC__\n    putc_unlocked('\\n', stdout);\n    #else \n    putc('\\n', stdout);\n    #endif\n}\n\nvoid my_sleep(uint32 n) {\n  sleep(n);\n}\n\n// Extern for enqueue\nvoid enqueue_log(uint32 k, uint32 v) {}\nvoid dequeue_log(uint32 k, uint32 v) {}\n"
  },
  {
    "path": "Test/clight/failed/failed_0.c",
    "content": "struct lock;\ntypedef struct lock lock;\nstruct lock {\n  int wait;\n  lock* next;\n};\n\n// There might be some bug in CompCertTSO compiler.\n// Defining global variable lock caused stack overflow of compcertTSO\n// This only happens when lock has a field of type lock* and there\n// is a typedef naming \"struct lock\" to \"lock\"\nlock lock;\n\n// For example \n//struct lock;\n//typedef struct lock lock;\n//struct lock {\n//  int wait;\n//  struct lock* next;\n//};\n// won't fail.\n\nint main() {\n        return 0;\n}"
  },
  {
    "path": "Test/clight/failed/failed_1.c",
    "content": "#include <stdio.h>\nint main()\n{\n\t// Fatal error: glibc detected an invalid stdio handle\n    // Aborted (core dumped)\n\tputc_unlocked('\\n', stdout);\n\treturn 0;\n}\n"
  },
  {
    "path": "Test/clight/lock.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs MCSLock {\n  struct lock {\n    var wait: uint32;\n    var next: ptr<lock>;\n  }\n}\n\nlayer {:concrete} Impl using MCSLock {\n\n  var locks: lock[6];\n  var tail: ptr<lock>;\n  method {:extern} CAS (addr: ptr<ptr<lock>>, setVal: ptr<lock>, compVal: ptr<lock>) returns (readVal: ptr<lock>) \n\n  method {:extern} MFENCE()\n    ensures $sb_empty\n\n  method {:extern} my_puts_unlocked(i:uint32)\n  method {:extern} my_sleep(n:uint32)\n\n  method acquire(tail: ptr<ptr<lock>>, myLock: ptr<lock>) {\n    var oldTail: ptr<lock>;\n    var readTail: ptr<lock>;\n    (*myLock).next := null;\n\n    oldTail := *tail;\n    readTail := CAS(tail, myLock, oldTail);\n    while readTail != oldTail {\n      oldTail := *tail;\n      readTail := CAS(tail, myLock, oldTail);\n    }\n\n    if oldTail != null {\n      (*myLock).wait := 1;\n      MFENCE(); // this should not be necessary in TSO\n      (*oldTail).next := myLock;\n      while ((*myLock).wait != 0) {}\n    }\n  }\n\n\n  method release(tail: ptr<ptr<lock>>, myLock: ptr<lock>) {\n    var nextLock: ptr<lock>;\n    var readTail: ptr<lock>;\n    readTail := CAS(tail, null, myLock);\n    // This used to be !=, probably a bug.\n    if readTail == myLock {\n\n    }\n    else {\n      while ((*myLock).next == null) {}\n      nextLock := (*myLock).next;\n      (*nextLock).wait := 0;\n    }\n  }\n\n  method racy_printer(index: uint32) {\n    var i : int32 := 0;\n    while(i < 10) {\n      acquire(&tail, &locks[index]);\n      my_puts_unlocked(index);\n      release(&tail, &locks[index]);\n      i := i + 1;\n    }\n  } \n\n  method main() {\n    var pids : uint64[5];\n    var i: uint32 := 0;\n\n    tail := null;\n    acquire(&tail, &locks[5]);\n    while (i < 5) {\n      pids[i] := create_thread racy_printer(i);\n      i := i + 1;\n    }\n    my_puts_unlocked(5);\n    release(&tail, &locks[5]);\n    my_sleep(1);\n  }\n}\n"
  },
  {
    "path": "Test/clight/queue.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs {\n\n    //type uint64 /*Key*/ = uint64\n    //type uint64 /*Value*/ = uint64\n    \n    struct BSSQueueElement {\n        var key:uint64 /*Key*/;\n        var value:uint64 /*Value*/;    \n    }\n    \n    struct QbssState {\n        var number_elements:uint64;\n        var mask:uint64;\n        var write_index:uint64;\n        var read_index:uint64;\n        var element_array:ptr<BSSQueueElement>; // need to make sure the array is 2^N = number_elements\n        var array_size:uint64;\n    }\n\n    struct BackoffState {\n        var lock:uint64;\n        var backoff_iteration_frequency_counters:uint64[2];\n        var metric:uint64;\n        var total_operations:uint64;\n    }\n\n    datatype QbssLogEntry = EnqueueLogEntry(key:uint64, value:uint64) | DequeueLogEntry(key:uint64, value:uint64)   \n    ghost var log:seq<QbssLogEntry> := [];\n\n    refinement_constraint @\"\n       || (ls.stop_reason == hs.stop_reason && ls.ghosts.log == hs.ghosts.log)\n       || (ls.stop_reason.Armada_NotStopped? && ls.ghosts.log <= hs.ghosts.log)\n    \"\n}\n\nlevel {:concrete} QueueBSS using SharedStructs {\n    noaddr var queue:QbssState;\n\n    method init_queue(size:uint64) {\n        queue.array_size := size;\n        queue.read_index := 0;\n        queue.write_index := 0;\n        queue.element_array := calloc(BSSQueueElement, queue.array_size);\n    }\n\n    method enqueue(k:uint64, v:uint64) returns (ret:uint64) {\n        noaddr var e:ptr<BSSQueueElement>;\n        noaddr var read_index:uint64;\n        noaddr var array_size:uint64;\n        noaddr var write_index:uint64;\n        noaddr var modulo:uint64;\n        noaddr var tmp_write_index:uint64;\n        noaddr var element:ptr<BSSQueueElement>;\n        noaddr var tmp_array:ptr<BSSQueueElement>;\n\n        write_index := queue.write_index;\n        tmp_write_index := write_index + 1;\n        array_size := queue.array_size;\n        modulo := tmp_write_index % array_size;\n        read_index := queue.read_index;\n        if(read_index != modulo) {\n            write_index := queue.write_index;\n            tmp_array := queue.element_array;\n            element := queue.element_array + write_index; \n            e := element;\n            (*e).key := k;\n            (*e).value := v;\n            write_index := queue.write_index;\n            tmp_write_index := write_index + 1;\n            array_size := queue.array_size;\n            modulo := tmp_write_index % array_size;\n            queue.write_index := modulo;\n            return 1;\n        }\n        return 0;\n    }\n\n    method dequeue(k:ptr<uint64>, v:ptr<uint64>) returns (ret:uint64) {\n        noaddr var e:ptr<BSSQueueElement>;\n        noaddr var read_index:uint64;\n        noaddr var array_size:uint64;\n        noaddr var write_index:uint64;\n        noaddr var modulo:uint64;\n        noaddr var tmp_read_index:uint64;\n        noaddr var tmp_int:uint64;\n        noaddr var tmp_array:ptr<BSSQueueElement>;\n        noaddr var element:ptr<BSSQueueElement>;\n        read_index := queue.read_index;\n        write_index := queue.write_index;\n        if(read_index != write_index) {\n            read_index := queue.read_index;\n            tmp_array := queue.element_array;\n            element := tmp_array + read_index; \n            e := element;\n            if(k != null) {\n                tmp_int := (*e).key;\n                *k := tmp_int;\n            }\n            if(v != null) {\n                tmp_int := (*e).value;\n                *v := tmp_int;\n            }\n            read_index := queue.read_index;\n            tmp_read_index := read_index + 1;\n            array_size := queue.array_size;\n            modulo := tmp_read_index % array_size;\n            queue.read_index := modulo;\n            return 1;\n        }\n        return 0;\n    }\n\n\n\n    method main() {\n        noaddr var tid1:uint64 :=0;\n      noaddr var tid2:uint64 :=0;\n        noaddr var k:ptr<uint64> := null;\n        noaddr var v:ptr<uint64> := null;\n        k := malloc(uint64);\n        v := malloc(uint64);\n      label mn_array_size_init:\n        queue.array_size := 4;\n      label mn_read_index_init:\n        queue.read_index := 0;\n      label mn_write_index_init:\n        queue.write_index := 0;\n        queue.element_array := calloc(BSSQueueElement, queue.array_size);\n        if (queue.element_array != null && k != null && v != null) {\n//label BeforeEnqueueCreate:\n            //tid1 := create_thread enqueue(*k,*v);\n//label BeforeDequeueCreate:\n            //tid2 := create_thread dequeue(k,v);\n        }\n    }\n}\n"
  },
  {
    "path": "Test/clight/sqrt.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs { }\n\nlayer {:concrete} A using SharedStructs {\n\n  var mutex:uint64\n  noaddr var best_guess:uint32 := 0\n\n  method {:extern} rnd() returns (x:uint32)\n    ensures 0 <= x < 0xFFFF\n\n  method {:extern} print_uint32(i:uint32)\n\n  method {:extern} init_random()\n\n  method worker(n:uint32)\n  {\n    noaddr var i:int32 := 0;\n    noaddr var g:uint32;\n    noaddr var m:uint32;\n\n    init_random(); // On Microsoft platforms, srand is per-thread so you have to call it from worker\n    while (i < 10000) {\n      i := i + 1;\n      g := rnd();\n      m := g * g;\n      if (m > n) {\n        continue;\n      }\nlabel lb_to_be_weakened:\n      if (g <= best_guess) {\n        continue;\n      }\n      // assume mutex == 0; somehow modifies mutex ensures mutex == $me;\n      if (g > best_guess) {\n        best_guess := g;\n      }\n      // assume mutex == $me && $sb_empty; somehow modifies mutex ensures mutex == 0;\n    }\n  }\n\n  method main() returns (x:int32)\n  {\n    var arg:uint32 := 100000000;\n    noaddr var tid1:uint64 := 0;\n    noaddr var tid2:uint64 := 0;\n    noaddr var tid3:uint64 := 0;\n\n    tid1 := create_thread worker(arg);\n    tid2 := create_thread worker(arg);\n    tid3 := create_thread worker(arg);\n\n    join tid1;\n    join tid2;\n    join tid3;\n\n    print_uint32(best_guess);\n  }\n\n}\n"
  },
  {
    "path": "Test/clight/upload.sh",
    "content": "echo rsync -avz  $2  fedora@$1:~/\n rsync -avz  $2  fedora@$1:~/\n"
  },
  {
    "path": "Test/combining/.gitignore",
    "content": "SharedStructs.dfy\nA.dfy\nB.dfy\nAB.dfy\nAB/\n"
  },
  {
    "path": "Test/combining/test.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs {\n\n}\n\nlevel A using SharedStructs {\n    noaddr var w:int32;\n    noaddr var x:int32;\n    noaddr var y:int32;\n    noaddr var z:int32 := 0;\n\n    method main()\n    {\n        w ::= 2;\n        atomic {\nlabel lbstart:\n            x ::= 3;\nlabel lbnext:\n            if x == 3 {\n              y ::= 4;\n            }\n            else {\n              assume false;\n              y ::= 18;\n            }\nlabel lbend:\n            z ::= 5;\n        }\n    }\n}\n\nlevel B using SharedStructs {\n    noaddr var w:int32;\n    noaddr var x:int32;\n    noaddr var y:int32;\n    noaddr var z:int32 := 0;\n\n    method main()\n    {\n        w ::= 2;\nlabel lbsingle:\n        x, y, z ::= 3, 4, 5;\n    }\n}\n\nproof AB {\n    refinement A B\n    combining main_lbstart main_lbend main_lbsingle\n}\n"
  },
  {
    "path": "Test/counter/.gitignore",
    "content": "A.dfy\nAB.dfy\nAB/\nB.dfy\nBC.dfy\nBC/\nC.dfy\nCD.dfy\nCD/\nD.dfy\nDE.dfy\nDE/\nE.dfy\nEF.dfy\nEF/\nF.dfy\nFG.dfy\nFG/\nG.dfy\nGI.dfy\nGI/\nI.dfy\nIJ.dfy\nIJ/\nJ.dfy\nSharedStructs.dfy\n"
  },
  {
    "path": "Test/counter/A.arm",
    "content": "include \"SharedStructs.arm\"\n\nlevel A using SharedStructs {\n    noaddr var x:uint32 := 0;\n    ghost var acquire_map: map<uint64, OptionalThread> := map[];\n\n    method {:extern} print_uint32(i:uint32)\n\n    method {:extern} Mutex_Init() returns (m: uint64)\n        ensures m in acquire_map && acquire_map[m] == OptionalNone()\n        ensures m != 0\n    {\n        atomic {\n            somehow modifies m \n                ensures (m !in acquire_map) && (m != 0);\n            acquire_map := acquire_map[m := OptionalNone()];\n        }\n    }\n\n    // decl acquire lock\n    method {:extern} Acquire(m: uint64)\n        ensures m in acquire_map && acquire_map[m] == OptionalSome($me)\n    {\n        assume acquire_map[m].OptionalNone?;\n        acquire_map[m] := OptionalSome($me);\n    }\n\n    // decl release lock\n    method {:extern} Release(m: uint64)\n        ensures m in acquire_map && acquire_map[m] != OptionalSome($me)\n    {\n        atomic {\n            assume $sb_empty;\n            assert acquire_map[m] == OptionalSome($me);\n            acquire_map[m] := OptionalNone();\n        }\n    }\n \n    method inc(m: uint64)\n    {\n        noaddr var y: uint32;\n        Acquire(m);\n        \n        y := x + 1;\n        x := y;\n\n        Release(m);\n    }\n\n    method main()\n    {\n        noaddr var tid1:uint64 := 0;\n        noaddr var tid2:uint64 := 0;\n        noaddr var m:uint64 := 0;\n\n        m := Mutex_Init();\n\n        tid1 := create_thread inc(m);\n        tid2 := create_thread inc(m);\n\n        join tid1;\n        join tid2;\n        \n        print_uint32(x);\n    }\n}\n        \n"
  },
  {
    "path": "Test/counter/AB.arm",
    "content": "include \"A.arm\"\ninclude \"B.arm\"\n\nproof AB {\n    refinement A B\n    var_intro mutex, inc1, inc2, done, main_reading\n}\n"
  },
  {
    "path": "Test/counter/B.arm",
    "content": "include \"SharedStructs.arm\"\n\nlevel B using SharedStructs{\n    noaddr var x:uint32 := 0;\n    ghost var mutex:uint64 := 0;\n    ghost var acquire_map: map<uint64, OptionalThread> := map[];\n    ghost var inc1:uint64 := 0;\n    ghost var inc2:uint64 := 0;\n    ghost var done: set<uint64> := {};\n    ghost var main_reading: uint8 := 0;\n\n    method {:extern} print_uint32(i:uint32)\n\n    method {:extern} Mutex_Init() returns (m: uint64)\n        ensures m in acquire_map && acquire_map[m] == OptionalNone()\n        ensures m != 0\n    {\n        atomic {\n            somehow modifies m\n                ensures (m !in acquire_map) && (m != 0);\n            acquire_map := acquire_map[m := OptionalNone()];\n        }\n    }\n\n    // decl acquire lock\n    method {:extern} Acquire(m: uint64)\n        requires m in acquire_map\n        ensures m in acquire_map && acquire_map[m] == OptionalSome($me)\n        ensures m == old(m)\n    {\n        assume acquire_map[m].OptionalNone?;\n        acquire_map[m] := OptionalSome($me);\n    }\n\n    // decl release lock\n    method {:extern} Release(m: uint64)\n        requires m in acquire_map\n        ensures m in acquire_map && acquire_map[m] != OptionalSome($me)\n        ensures m == old(m)\n    {\n        atomic {\n            assume $sb_empty;\n            assert acquire_map[m] == OptionalSome($me);\n            acquire_map[m] := OptionalNone();\n        }\n    }\n \n    method inc(m: uint64)\n        requires m == mutex\n    {\n        noaddr var y: uint32;\n        Acquire(m);\n        \n        y := x + 1;\n        atomic {\n        x := y;\n        done := done + {$me};\n        }\n\n        Release(m);\n    }\n\n    method main()\n        requires mutex == 0\n    {\n        noaddr var tid1:uint64 := 0;\n        noaddr var tid2:uint64 := 0;\n        noaddr var m:uint64 := 0;\n        \n        m := Mutex_Init();\n        \n        mutex := m;\n\n        atomic {\n            tid1 := create_thread inc(m);\n            inc1 ::= tid1;\n        }\n\n        atomic {\n            tid2 := create_thread inc(m);\n            inc2 := tid2;\n        }\n\n        join tid1;\n        join tid2;\n        \n        main_reading := 1;\n\n        print_uint32(x);\n    }\n\n    invariant only_mutex_is_used\n    {\n        forall m :: m in acquire_map ==> m == mutex || acquire_map[m].OptionalNone?\n    }\n\n    yield_predicate YP1 \n    {\n        (old(inc1) != 0 ==> inc1 == old(inc1)) &&\n        (old(inc2) != 0 ==> inc2 == old(inc2)) &&\n        (old(mutex) != 0 ==> mutex == old(mutex)) &&\n        (forall m :: m in old(acquire_map) ==> m in acquire_map)\n    }\n\n    yield_predicate YP2\n    {\n        (old(mutex) in old(acquire_map) && old(acquire_map[mutex]) == OptionalSome($me) ==> mutex in acquire_map && acquire_map[mutex] == OptionalSome($me)) &&\n        (old(mutex) in old(acquire_map) && old(acquire_map[mutex]) != OptionalSome($me) ==> mutex in acquire_map && acquire_map[mutex] != OptionalSome($me))\n    }\n}\n"
  },
  {
    "path": "Test/counter/BC.arm",
    "content": "include \"B.arm\"\ninclude \"C.arm\"\n\nproof BC {\n    refinement B C\n    assume_intro\n\n    inductive_invariant no_joinable \"forall jtid :: jtid in s.s.joinable_tids ==> jtid !in threads\"\n\n    inductive_invariant zero_is_not_a_mutex \"0 !in ghosts.acquire_map\"\n\n    chl_invariant no_other_threads @\"\n      && (forall tid :: tid in threads ==> (tid == ghosts.inc1 || tid == ghosts.inc2 || tid == tid_init))\n    \"\n\n    chl_invariant inc1_2_uses_mutex @\"\n      forall tid :: tid in {ghosts.inc1, ghosts.inc2} && tid in threads ==> \n        && (threads[tid].top.Armada_StackFrame_Acquire? ==> threads[tid].top.Acquire.m == ghosts.mutex)\n        && (threads[tid].top.Armada_StackFrame_Release? ==> threads[tid].top.Release.m == ghosts.mutex)\n    \"\n\n    chl_invariant no_threads_when_main_reading @\"\n      forall tid :: tid in threads && tid != tid_init ==> ghosts.main_reading == 0\n    \"\n\n    chl_invariant only_mutex_is_used\n\n    chl_invariant GlobalInvariant @\"\n        (ghosts.mutex in ghosts.acquire_map && ghosts.acquire_map[ghosts.mutex].OptionalSome? ==> ghosts.acquire_map[ghosts.mutex].tid in threads)\n    \"\n\n    inductive_invariant One_Main @\"\n        forall tid :: (tid in threads && (threads[tid].top.Armada_StackFrame_main? || \n                                     threads[tid].top.Armada_StackFrame_print_uint32? ||\n                                     threads[tid].top.Armada_StackFrame_Mutex_Init?))\n                  <==> \n                 (tid in threads && tid == tid_init)\n    \"\n\n    chl_yield_pred inc_threads @\"\n        && (ghosts.inc1 != 0 && ghosts.inc1 !in threads ==> ghosts'.inc1 !in threads')\n        && (ghosts.inc2 != 0 && ghosts.inc2 !in threads ==> ghosts'.inc2 !in threads')\n    \"\n\n    chl_yield_pred main_owns_incs_and_mutex_and_reading @\"\n        && ghosts.mutex == ghosts'.mutex\n        && (tid == tid_init ==> (ghosts.inc1 == ghosts'.inc1 && ghosts.inc2 == ghosts'.inc2 && ghosts.mutex == ghosts'.mutex && ghosts.main_reading == ghosts'.main_reading))\n    \"\n\n    chl_yield_pred YP1\n    //chl_yield_pred {:excludeMethod Acquire, Release, inc} YP2\n    chl_yield_pred {:excludeMethod Acquire, Release, inc} YP2 @\"\n        && (ghosts.mutex in ghosts.acquire_map ==> ghosts'.mutex in ghosts'.acquire_map)\n        && (ghosts.mutex in ghosts.acquire_map && ghosts.acquire_map[ghosts.mutex] == OptionalSome(tid) ==> ghosts'.acquire_map[ghosts'.mutex] == OptionalSome(tid))\n        && (ghosts.mutex in ghosts.acquire_map && ghosts.acquire_map[ghosts.mutex] != OptionalSome(tid) ==> ghosts'.acquire_map[ghosts'.mutex] != OptionalSome(tid))\n    \"\n}\n"
  },
  {
    "path": "Test/counter/C.arm",
    "content": "include \"SharedStructs.arm\"\n\nlevel C using SharedStructs {\n    noaddr var x:uint32 := 0;\n    ghost var mutex:uint64 := 0;\n    ghost var acquire_map: map<uint64, OptionalThread> := map[];\n    ghost var inc1:uint64 := 0;\n    ghost var inc2:uint64 := 0;\n    ghost var done: set<uint64> := {};\n    ghost var main_reading: uint8 := 0;\n\n    method {:extern} print_uint32(i:uint32)\n\n    method {:extern} Mutex_Init() returns (m: uint64)\n        requires mutex == 0\n        ensures m in acquire_map && acquire_map[m] == OptionalNone()\n        ensures m != 0\n    {\n        atomic {\n            somehow modifies m\n                ensures (m !in acquire_map) && (m != 0);\n            acquire_map := acquire_map[m := OptionalNone()];\n            //acquire_map[m] := OptionalNone();\n        }\n    }\n\n    // decl acquire lock\n    method {:extern} Acquire(m: uint64)\n        requires m in acquire_map && m != 0\n        ensures m in acquire_map && acquire_map[m] == OptionalSome($me)\n        ensures m == old(m)\n    {\n        assume acquire_map[m].OptionalNone?;\n        assume main_reading == 0;\n        acquire_map[m] := OptionalSome($me);\n    }\n\n    // decl release lock\n    method {:extern} Release(m: uint64)\n        requires m in acquire_map && acquire_map[m] == OptionalSome($me)\n        ensures m in acquire_map && acquire_map[m] != OptionalSome($me)\n        ensures m == old(m)\n    {\n        atomic {\n            assume $sb_empty;\n            assert acquire_map[m] == OptionalSome($me);\n            acquire_map[m] := OptionalNone();\n        }\n    }\n \n    method inc(m: uint64)\n        requires m == mutex\n        requires m != 0 && m in acquire_map\n    {\n        noaddr var y: uint32;\n        assume m == mutex;\n        Acquire(m);\n        \n        assume acquire_map[mutex] == OptionalSome($me);\n        y := x + 1;\n\n        assume acquire_map[mutex] == OptionalSome($me);\n        atomic {\n        x := y;\n        done := done + {$me};\n        }\n\n        assume acquire_map[mutex] == OptionalSome($me);\n        assume m == mutex;\n        Release(m);\n    }\n\n    method main()\n        requires mutex == 0\n        requires inc1 == 0\n        requires inc2 == 0\n        requires main_reading == 0\n    {\n        noaddr var tid1:uint64 := 0;\n        noaddr var tid2:uint64 := 0;\n        noaddr var m:uint64 := 0;\n        \n        m := Mutex_Init();\n        \n        assume mutex == 0;\n        mutex := m;\n\n        atomic {\n            tid1 := create_thread inc(m);\n            inc1 ::= tid1;\n        }\n\n        atomic {\n            tid2 := create_thread inc(m);\n            inc2 := tid2;\n        }\n\n        join tid1;\n        join tid2;\n\n        main_reading := 1;\n        \n        assume main_reading == 1;\n        assume mutex in acquire_map;\n        assume acquire_map[mutex].OptionalNone? || acquire_map[mutex] == OptionalSome($me);\n        print_uint32(x);\n    }\n}\n"
  },
  {
    "path": "Test/counter/CD.arm",
    "content": "include \"C.arm\"\ninclude \"D.arm\"\n\nproof CD {\n    refinement C D\n    tso_elim x @\"\n        && ghosts.mutex in ghosts.acquire_map\n        && tid in threads\n        && (var acquired := ghosts.acquire_map[ghosts.mutex];\n             acquired == OptionalSome(tid) ||\n            (acquired == OptionalNone() && tid == tid_init && ghosts.main_reading == 1))\n    \"\n\n    inductive_invariant zero_is_not_a_mutex \"0 !in ghosts.acquire_map\"\n\n    inductive_invariant One_Main @\"\n        forall tid :: (tid in threads && (threads[tid].top.Armada_StackFrame_main? || \n                  threads[tid].top.Armada_StackFrame_print_uint32? ||\n                  threads[tid].top.Armada_StackFrame_Mutex_Init?))\n                 <==> \n                 (tid in threads && tid == tid_init)\n    \"\n\n    inductive_invariant EmptyBuffer @\"\n      forall tid :: tid in threads && tid == tid_init ==> (|threads[tid].storeBuffer| == 0)\n    \" depends_on One_Main\n}\n"
  },
  {
    "path": "Test/counter/D.arm",
    "content": "include \"SharedStructs.arm\"\n\nlevel D using SharedStructs {\n    noaddr var x:uint32 := 0;\n    ghost var mutex:uint64 := 0;\n    ghost var acquire_map: map<uint64, OptionalThread> := map[];\n    ghost var inc1:uint64 := 0;\n    ghost var inc2:uint64 := 0;\n    ghost var done: set<uint64> := {};\n    ghost var main_reading: uint8 := 0;\n\n    method {:extern} print_uint32(i:uint32)\n\n    method {:extern} Mutex_Init() returns (m: uint64)\n        requires mutex == 0\n        ensures m in acquire_map && acquire_map[m] == OptionalNone()\n        ensures m != 0\n    {\n        atomic {\n            somehow modifies m\n                ensures (m !in acquire_map) && (m != 0);\n            acquire_map := acquire_map[m := OptionalNone()];\n            //acquire_map[m] := OptionalNone();\n        }\n    }\n\n    // decl acquire lock\n    method {:extern} Acquire(m: uint64)\n        requires m in acquire_map && m != 0\n        ensures m in acquire_map && acquire_map[m] == OptionalSome($me)\n        ensures m == old(m)\n    {\n        assume acquire_map[m].OptionalNone?;\n        acquire_map[m] := OptionalSome($me);\n    }\n\n    // decl release lock\n    method {:extern} Release(m: uint64)\n        requires m in acquire_map && acquire_map[m] == OptionalSome($me)\n        ensures m in acquire_map && acquire_map[m] != OptionalSome($me)\n        ensures m == old(m)\n    {\n        atomic {\n            assume $sb_empty;\n            assert acquire_map[m] == OptionalSome($me);\n            acquire_map[m] := OptionalNone();\n        }\n    }\n \n    method inc(m: uint64)\n        requires m == mutex\n        requires m != 0 && m in acquire_map\n    {\n        noaddr var y: uint32;\n        assume m == mutex;\n        Acquire(m);\n        \n        assume acquire_map[mutex] == OptionalSome($me);\n        y := x + 1;\n\n        assume acquire_map[mutex] == OptionalSome($me);\n        label lb1:\n        atomic {\n        x ::= y;\n        done := done + {$me};\n        }\n\n        assume acquire_map[mutex] == OptionalSome($me);\n        assume m == mutex;\n        Release(m);\n    }\n\n    method main()\n        requires mutex == 0\n        requires inc1 == 0\n        requires inc2 == 0\n    {\n        noaddr var tid1:uint64 := 0;\n        noaddr var tid2:uint64 := 0;\n        noaddr var m:uint64 := 0;\n        \n        m := Mutex_Init();\n\n        assume mutex == 0;\n        mutex := m;\n\n        atomic {\n            tid1 := create_thread inc(m);\n            inc1 ::= tid1;\n        }\n\n        atomic {\n            tid2 := create_thread inc(m);\n            inc2 := tid2;\n        }\n\n        join tid1;\n        join tid2;\n\n        main_reading := 1;\n        \n        assume main_reading == 1;\n        assume mutex in acquire_map;\n        assume acquire_map[mutex].OptionalNone? || acquire_map[mutex] == OptionalSome($me);\n        print_uint32(x);\n    }\n}\n"
  },
  {
    "path": "Test/counter/DE.arm",
    "content": "include \"D.arm\"\ninclude \"E.arm\"\n\nproof DE {\n    refinement D E\n    reduction phase1 inc_lb1\n    use_address_invariant\n\n    inductive_invariant EmptyBuffer @\"\n      && (forall tid :: tid in threads ==> (threads[tid].storeBuffer == []))\n    \"\n\n    inductive_invariant zero_is_not_a_mutex \"0 !in ghosts.acquire_map\"\n}\n"
  },
  {
    "path": "Test/counter/E.arm",
    "content": "include \"SharedStructs.arm\"\n\nlevel E using SharedStructs {\n    noaddr var x:uint32 := 0;\n    ghost var mutex:uint64 := 0;\n    ghost var acquire_map: map<uint64, OptionalThread> := map[];\n    ghost var inc1:uint64 := 0;\n    ghost var inc2:uint64 := 0;\n    ghost var done: set<uint64> := {};\n    ghost var main_reading: uint8 := 0;\n\n    method {:extern} print_uint32(i:uint32)\n\n    method {:extern} Mutex_Init() returns (m: uint64)\n    {\n        atomic {\n            somehow modifies m\n                ensures (m !in acquire_map) && (m != 0);\n            acquire_map := acquire_map[m := OptionalNone()];\n            //acquire_map[m] := OptionalNone();\n        }\n    }\n\n    // decl acquire lock\n    method {:extern} Acquire(m: uint64)\n    {\n        assume acquire_map[m].OptionalNone?;\n        acquire_map[m] := OptionalSome($me);\n    }\n\n    // decl release lock\n    method {:extern} Release(m: uint64)\n    {\n        atomic {\n            assume $sb_empty;\n            assert acquire_map[m] == OptionalSome($me);\n            acquire_map[m] := OptionalNone();\n        }\n    }\n \n    method inc(m: uint64)\n        requires m == mutex\n        requires m != 0 && m in acquire_map\n    {\n        noaddr var y: uint32;\n        assume m == mutex;\n        Acquire(m);\n        \n        assume acquire_map[mutex] == OptionalSome($me);\n        atomic {\n            y := x + 1;\n            x ::= y;\n            done := done + {$me};\n        }\n\n        assume acquire_map[mutex] == OptionalSome($me);\n        assume m == mutex;\n        Release(m);\n    }\n\n    method main()\n        requires mutex == 0\n        requires inc1 == 0\n        requires inc2 == 0\n    {\n        noaddr var tid1:uint64 := 0;\n        noaddr var tid2:uint64 := 0;\n        noaddr var m:uint64 := 0;\n        \n        m := Mutex_Init();\n\n        mutex := m;\n\n        atomic {\n            tid1 := create_thread inc(m);\n            inc1 ::= tid1;\n        }\n\n        atomic {\n            tid2 := create_thread inc(m);\n            inc2 := tid2;\n        }\n\n        join tid1;\n        join tid2;\n\n        main_reading := 1;\n        \n        print_uint32(x);\n    }\n}\n"
  },
  {
    "path": "Test/counter/EF.arm",
    "content": "include \"E.arm\"\ninclude \"F.arm\"\n\nproof EF {\n    refinement E F\n    stack_var_hiding inc y\n}\n"
  },
  {
    "path": "Test/counter/F.arm",
    "content": "include \"SharedStructs.arm\"\n\nlevel F using SharedStructs {\n    noaddr var x:uint32 := 0;\n    ghost var mutex:uint64 := 0;\n    ghost var acquire_map: map<uint64, OptionalThread> := map[];\n    ghost var inc1:uint64 := 0;\n    ghost var inc2:uint64 := 0;\n    ghost var done: set<uint64> := {};\n    ghost var main_reading: uint8 := 0;\n\n    method {:extern} print_uint32(i:uint32)\n\n    method {:extern} Mutex_Init() returns (m: uint64)\n    {\n        atomic {\n            somehow modifies m\n                ensures (m !in acquire_map) && (m != 0);\n            acquire_map := acquire_map[m := OptionalNone()];\n            //acquire_map[m] := OptionalNone();\n        }\n    }\n\n    // decl acquire lock\n    method {:extern} Acquire(m: uint64)\n    {\n        assume acquire_map[m].OptionalNone?;\n        acquire_map[m] := OptionalSome($me);\n    }\n\n    // decl release lock\n    method {:extern} Release(m: uint64)\n    {\n        atomic {\n            assume $sb_empty;\n            assert acquire_map[m] == OptionalSome($me);\n            acquire_map[m] := OptionalNone();\n        }\n    }\n \n    method inc(m: uint64)\n        requires $me !in done\n    {\n        assume m == mutex;\n        Acquire(m);\n        \n        assume acquire_map[mutex] == OptionalSome($me);\n        atomic {\n            x ::= x + 1;\n            done := done + {$me};\n        }\n\n        assume acquire_map[mutex] == OptionalSome($me);\n        assume m == mutex;\n        Release(m);\n    }\n\n    method main()\n        requires mutex == 0\n        requires inc1 == 0\n        requires inc2 == 0\n    {\n        noaddr var tid1:uint64 := 0;\n        noaddr var tid2:uint64 := 0;\n        noaddr var m:uint64 := 0;\n        \n        m := Mutex_Init();\n\n        mutex := m;\n\n        atomic {\n            tid1 := create_thread inc(m);\n            inc1 ::= tid1;\n        }\n\n        atomic {\n            tid2 := create_thread inc(m);\n            inc2 := tid2;\n        }\n\n        join tid1;\n        join tid2;\n\n        main_reading := 1;\n        \n        print_uint32(x);\n    }\n\n    yield_predicate YP1\n    {\n        $me !in old(done) ==> $me !in done\n    }\n\n    yield_predicate YP2\n    {\n        (old(inc1) != 0 ==> inc1 == old(inc1)) &&\n        (old(inc2) != 0 ==> inc2 == old(inc2)) &&\n        (forall tid :: tid in old(done) ==> tid in done)\n    }\n\n    invariant Inv1\n    {\n        (x as int == |done|) && \n        (done <= {inc1, inc2}) &&\n        (inc1 != 0 ==> inc1 != inc2) &&\n        (0 !in done)\n    }\n}\n"
  },
  {
    "path": "Test/counter/FG.arm",
    "content": "include \"F.arm\"\ninclude \"G.arm\"\n\nproof FG {\n    refinement F G\n    assume_intro\n    \n    include_file \"extra.dfy\"\n    import_module sets_helpers\n    extra lemma_ExpandedStraightlineBehaviorSatisfiesGlobalInvariant_Inv1_inc_Yielded_1_Then_From_inc_1_To_inc_3\n            \"sets_helpers.Cardinality(s5.s.ghosts.done, {s5.s.ghosts.inc1, s5.s.ghosts.inc2});\"\n    extra lemma_ExpandedStraightlineBehaviorSatisfiesLocalInvariant_main_Yielded_9_Then_From_main_9_To_print_uint32_Start @\"\n      assert s19.s.ghosts.done == {s19.s.ghosts.inc1, s19.s.ghosts.inc2} <==>\n             var hs := ConvertTotalState_LPlusH(s19); hs.ghosts.done == {hs.ghosts.inc1, hs.ghosts.inc2};\n    \"\n\n    inductive_invariant no_joinable \"forall jtid :: jtid in s.s.joinable_tids ==> jtid !in threads\"\n\n    inductive_invariant EmptyBuffer @\"\n      && (forall tid :: tid in threads ==> (threads[tid].storeBuffer == []))\n    \"\n\n    inductive_invariant One_Main @\"\n        forall tid :: (tid in threads && (threads[tid].top.Armada_StackFrame_main? || \n                                     threads[tid].top.Armada_StackFrame_print_uint32? ||\n                                     threads[tid].top.Armada_StackFrame_Mutex_Init?))\n                  <==> \n                 (tid in threads && tid == tid_init)\n    \"\n\n    chl_invariant Inv1\n\n    chl_invariant no_other_threads @\"\n      && (forall tid :: tid in threads ==> (tid == ghosts.inc1 || tid == ghosts.inc2 || tid == tid_init))\n    \"\n\n    chl_invariant GlobalInvariant @\"\n      && (ghosts.inc1 != 0 && ghosts.inc1 !in threads ==> ghosts.inc1 in ghosts.done)\n      && (ghosts.inc2 != 0 && ghosts.inc2 !in threads ==> ghosts.inc2 in ghosts.done)\n    \"\n\n    chl_yield_pred {:excludeMethod inc} YP1\n    chl_yield_pred YP2\n\n    chl_yield_pred inc_threads @\"\n        && (ghosts.inc1 != 0 && ghosts.inc1 !in threads ==> s'.s.ghosts.inc1 !in threads')\n        && (ghosts.inc2 != 0 && ghosts.inc2 !in threads ==> s'.s.ghosts.inc2 !in threads')\n    \"\n\n    chl_yield_pred main_owns_incs @\"\n        && (tid == tid_init ==> (ghosts.inc1 == s'.s.ghosts.inc1 && ghosts.inc2 == s'.s.ghosts.inc2))\n        && (tid == tid_init && ghosts.inc1 in s.s.joinable_tids ==> s'.s.ghosts.inc1 in s'.s.joinable_tids)\n        && (tid == tid_init && ghosts.inc1 in threads ==> (s'.s.ghosts.inc1 in s'.s.joinable_tids || s'.s.ghosts.inc1 in threads'))\n    \"\n}\n"
  },
  {
    "path": "Test/counter/G.arm",
    "content": "include \"SharedStructs.arm\"\n\nlevel G using SharedStructs {\n    noaddr var x:uint32 := 0;\n    ghost var mutex:uint64 := 0;\n    ghost var acquire_map: map<uint64, OptionalThread> := map[];\n    ghost var inc1:uint64 := 0;\n    ghost var inc2:uint64 := 0;\n    ghost var done: set<uint64> := {};\n    ghost var main_reading: uint8 := 0;\n\n    method {:extern} print_uint32(i:uint32)\n\n    method {:extern} Mutex_Init() returns (m: uint64)\n    {\n        atomic {\n            somehow modifies m\n                ensures (m !in acquire_map) && (m != 0);\n            acquire_map := acquire_map[m := OptionalNone()];\n            //acquire_map[m] := OptionalNone();\n        }\n    }\n\n    // decl acquire lock\n    method {:extern} Acquire(m: uint64)\n    {\n        assume acquire_map[m].OptionalNone?;\n        acquire_map[m] := OptionalSome($me);\n    }\n\n    // decl release lock\n    method {:extern} Release(m: uint64)\n    {\n        atomic {\n            assume $sb_empty;\n            assert acquire_map[m] == OptionalSome($me);\n            acquire_map[m] := OptionalNone();\n        }\n    }\n \n    method inc(m: uint64)\n        requires $me !in done\n    {\n        Acquire(m);\n        \n        atomic {\n            x ::= x + 1;\n            done := done + {$me};\n        }\n\n        Release(m);\n    }\n\n    method main()\n        requires mutex == 0\n        requires inc1 == 0\n        requires inc2 == 0\n    {\n        noaddr var tid1:uint64 := 0;\n        noaddr var tid2:uint64 := 0;\n        noaddr var m:uint64 := 0;\n        \n        m := Mutex_Init();\n\n        mutex := m;\n\n        atomic {\n            tid1 := create_thread inc(m);\n            inc1 ::= tid1;\n        }\n\n        atomic {\n            tid2 := create_thread inc(m);\n            inc2 := tid2;\n        }\n\n        join tid1;\n        join tid2;\n\n        main_reading := 1;\n        \n        assume done == {inc1, inc2};\n        assume x == 2;\n        print_uint32(x);\n    }\n}\n"
  },
  {
    "path": "Test/counter/GI.arm",
    "content": "include \"G.arm\"\ninclude \"I.arm\"\n\nproof GI {\n    refinement G I\n    weakening\n}\n"
  },
  {
    "path": "Test/counter/I.arm",
    "content": "include \"SharedStructs.arm\"\n\nlevel I using SharedStructs {\n    noaddr var x:uint32 := 0;\n    ghost var mutex:uint64 := 0;\n    ghost var acquire_map: map<uint64, OptionalThread> := map[];\n    ghost var inc1:uint64 := 0;\n    ghost var inc2:uint64 := 0;\n    ghost var done: set<uint64> := {};\n    ghost var main_reading: uint8 := 0;\n\n    method {:extern} print_uint32(i:uint32)\n\n    method {:extern} Mutex_Init() returns (m: uint64)\n    {\n        atomic {\n            somehow modifies m\n                ensures (m !in acquire_map) && (m != 0);\n            acquire_map := acquire_map[m := OptionalNone()];\n            //acquire_map[m] := OptionalNone();\n        }\n    }\n\n    // decl acquire lock\n    method {:extern} Acquire(m: uint64)\n    {\n        assume acquire_map[m].OptionalNone?;\n        acquire_map[m] := OptionalSome($me);\n    }\n\n    // decl release lock\n    method {:extern} Release(m: uint64)\n    {\n        atomic {\n            assume $sb_empty;\n            assert acquire_map[m] == OptionalSome($me);\n            acquire_map[m] := OptionalNone();\n        }\n    }\n \n    method inc(m: uint64)\n    {\n        Acquire(m);\n        \n        atomic {\n            x ::= x + 1;\n            done := done + {$me};\n        }\n\n        Release(m);\n    }\n\n    method main()\n    {\n        noaddr var tid1:uint64 := 0;\n        noaddr var tid2:uint64 := 0;\n        noaddr var m:uint64 := 0;\n        \n        m := Mutex_Init();\n\n        mutex := m;\n\n        atomic {\n            tid1 := create_thread inc(m);\n            inc1 ::= tid1;\n        }\n\n        atomic {\n            tid2 := create_thread inc(m);\n            inc2 := tid2;\n        }\n\n        join tid1;\n        join tid2;\n\n        main_reading := 1;\n        \n        print_uint32(2);\n    }\n}\n"
  },
  {
    "path": "Test/counter/IJ.arm",
    "content": "include \"I.arm\"\ninclude \"J.arm\"\n\nproof IJ {\n    refinement I J\n    var_hiding done, inc1, inc2, main_reading\n}\n"
  },
  {
    "path": "Test/counter/J.arm",
    "content": "include \"SharedStructs.arm\"\n\nlevel J using SharedStructs {\n    noaddr var x:uint32 := 0;\n    ghost var mutex:uint64 := 0;\n    ghost var acquire_map: map<uint64, OptionalThread> := map[];\n\n    method {:extern} print_uint32(i:uint32)\n\n    method {:extern} Mutex_Init() returns (m: uint64)\n    {\n        atomic {\n            somehow modifies m\n                ensures (m !in acquire_map) && (m != 0);\n            acquire_map := acquire_map[m := OptionalNone()];\n            //acquire_map[m] := OptionalNone();\n        }\n    }\n\n    // decl acquire lock\n    method {:extern} Acquire(m: uint64)\n    {\n        assume acquire_map[m].OptionalNone?;\n        acquire_map[m] := OptionalSome($me);\n    }\n\n    // decl release lock\n    method {:extern} Release(m: uint64)\n    {\n        atomic {\n            assume $sb_empty;\n            assert acquire_map[m] == OptionalSome($me);\n            acquire_map[m] := OptionalNone();\n        }\n    }\n \n    method inc(m: uint64)\n    {\n        Acquire(m);\n        \n        atomic {\n            x ::= x + 1;\n        }\n\n        Release(m);\n    }\n\n    method main()\n    {\n        noaddr var tid1:uint64 := 0;\n        noaddr var tid2:uint64 := 0;\n        noaddr var m:uint64 := 0;\n        \n        m := Mutex_Init();\n\n        mutex := m;\n\n        atomic {\n            tid1 := create_thread inc(m);\n        }\n\n        atomic {\n            tid2 := create_thread inc(m);\n        }\n\n        join tid1;\n        join tid2;\n        \n        print_uint32(2);\n    }\n}\n"
  },
  {
    "path": "Test/counter/SharedStructs.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs\n{\n    datatype OptionalThread = OptionalSome(tid:uint64) | OptionalNone()\n}\n"
  },
  {
    "path": "Test/counter/Z.arm",
    "content": "include \"SharedStructs.arm\"\n\nlevel Z using SharedStructs {\n    noaddr var x:uint32 := 0;\n\n    method {:extern} print_uint32(i:uint32)\n \n    method inc()\n    {\n    }\n\n    method main()\n    {\n        print_uint32(2);\n    }\n}\n"
  },
  {
    "path": "Test/counter/extra.dfy",
    "content": "module sets_helpers {\n\nlemma Cardinality<T>(x:set<T>, y:set<T>)\n    ensures x<y ==> |x|<|y|;\n    ensures x<=y ==> |x|<=|y|;\n{\n    if (x!={}) {\n        var e :| e in x;\n        Cardinality(x-{e}, y-{e});\n    }\n}\n\n}\n"
  },
  {
    "path": "Test/estimate-sqrt/.gitignore",
    "content": "SharedStructs.dfy\nA.dfy\nB.dfy\nC.dfy\nD.dfy\nAB.dfy\nBC.dfy\nCD.dfy\nAB/\nBC/\nCD/\n"
  },
  {
    "path": "Test/estimate-sqrt/sqrt.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs\n{\n  ghost var log:seq<uint32> := [];\n\n  refinement_constraint @\"\n     || (ls.stop_reason == hs.stop_reason && ls.ghosts.log == hs.ghosts.log)\n     || (ls.stop_reason.Armada_NotStopped? && ls.ghosts.log <= hs.ghosts.log)\n  \"\n}\n\nlevel A using SharedStructs {\n\n  var mutex:uint64\n  noaddr var best_guess:uint32 := 0\n\n  method {:extern} rnd() returns (x:uint32)\n\n  method {:extern} printf(i:uint32)\n  {\n    log := log + [i];\n  }\n\n  method worker(n:uint64)\n  {\n    noaddr var i:int32 := 0;\n    noaddr var g:uint32;\n    noaddr var m:uint64;\n\n    while (i < 10000) {\n      i := i + 1;\n      g := rnd();\n      m := g as uint64 * g as uint64;\n      if (m > n) {\n        continue;\n      }\nlabel lb_to_be_weakened:\n      if (g <= best_guess) {\n        continue;\n      }\n      assume mutex == 0;\n      somehow modifies mutex ensures mutex == $me;\n      if (g > best_guess) {\n        best_guess := g;\n      }\n      assume mutex == $me && $sb_empty;\n      somehow modifies mutex ensures mutex == 0;\n    }\n  }\n\n  method main(arg:uint64)\n  {\n    noaddr var tid1:uint64 := 0;\n    noaddr var tid2:uint64 := 0;\n    noaddr var tid3:uint64 := 0;\n\n    tid1 := create_thread worker(arg);\n    tid2 := create_thread worker(arg);\n    tid3 := create_thread worker(arg);\n\n    join tid1;\n    join tid2;\n    join tid3;\n\n    printf(best_guess);\n  }\n\n}\n\nlevel B using SharedStructs {\n\n  var mutex:uint64\n  noaddr var best_guess:uint32 := 0\n\n  method {:extern} rnd() returns (x:uint32)\n\n  method {:extern} printf(i:uint32)\n  {\n    log := log + [i];\n  }\n\n  method worker(n:uint64)\n  {\n    noaddr var i:int32 := 0;\n    noaddr var g:uint32;\n    noaddr var m:uint64;\n\n    while (i < 10000) {\n      i := i + 1;\n      g := rnd();\n      m := g as uint64 * g as uint64;\n      if (m > n) {\n        continue;\n      }\n      if * {\n        continue;\n      }\n      assume mutex == 0;\n      somehow modifies mutex ensures mutex == $me;\n      if (g > best_guess) {\n        best_guess := g;\n      }\n      assume mutex == $me && $sb_empty;\n      somehow modifies mutex ensures mutex == 0;\n    }\n  }\n\n  method main(arg:uint64)\n  {\n    noaddr var tid1:uint64 := 0;\n    noaddr var tid2:uint64 := 0;\n    noaddr var tid3:uint64 := 0;\n\n    tid1 := create_thread worker(arg);\n    tid2 := create_thread worker(arg);\n    tid3 := create_thread worker(arg);\n\n    join tid1;\n    join tid2;\n    join tid3;\n\n    printf(best_guess);\n  }\n\n}\n\nlevel C using SharedStructs {\n\n  var mutex:uint64\n  noaddr var best_guess:uint32 := 0\n\n  method {:extern} rnd() returns (x:uint32)\n\n  method {:extern} printf(i:uint32)\n  {\n    log := log + [i];\n  }\n\n  method worker(n:uint64)\n  {\n    noaddr var i:int32 := 0;\n    noaddr var g:uint32;\n    noaddr var m:uint64;\n\n    while (i < 10000) {\n      i := i + 1;\n      g := rnd();\n      m := g as uint64 * g as uint64;\n      if (m > n) {\n        continue;\n      }\n      if * {\n        continue;\n      }\n      assume mutex == 0;\n      somehow modifies mutex ensures mutex == $me;\n      if (g > best_guess) {\n        assume mutex == $me;\n        best_guess := g;\n      }\n      assume mutex == $me && $sb_empty;\n      somehow modifies mutex ensures mutex == 0;\n    }\n  }\n\n  method main(arg:uint64)\n  {\n    noaddr var tid1:uint64 := 0;\n    noaddr var tid2:uint64 := 0;\n    noaddr var tid3:uint64 := 0;\n\n    tid1 := create_thread worker(arg);\n    tid2 := create_thread worker(arg);\n    tid3 := create_thread worker(arg);\n\n    join tid1;\n    join tid2;\n    join tid3;\n\n    assume tid1 != 0 && tid2 != 0 && tid3 != 0;\n    printf(best_guess);\n  }\n\n}\n\nlevel D using SharedStructs {\n\n  var mutex:uint64\n  noaddr var best_guess:uint32 := 0\n\n  method {:extern} rnd() returns (x:uint32)\n\n  method {:extern} printf(i:uint32)\n  {\n    log := log + [i];\n  }\n\n  method worker(n:uint64)\n  {\n    noaddr var i:int32 := 0;\n    noaddr var g:uint32;\n    noaddr var m:uint64;\n\n    while (i < 10000) {\n      i := i + 1;\n      g := rnd();\n      m := g as uint64 * g as uint64;\n      if (m > n) {\n        continue;\n      }\n      if * {\n        continue;\n      }\n      assume mutex == 0;\n      somehow modifies mutex ensures mutex == $me;\n      assume mutex == $me;\n      if (g > best_guess) {\n        assume mutex == $me;\n        best_guess ::= g;\n      }\n      assume mutex == $me && $sb_empty;\n      somehow modifies mutex ensures mutex == 0;\n    }\n  }\n\n  method main(arg:uint64)\n  {\n    noaddr var tid1:uint64 := 0;\n    noaddr var tid2:uint64 := 0;\n    noaddr var tid3:uint64 := 0;\n\n    tid1 := create_thread worker(arg);\n    tid2 := create_thread worker(arg);\n    tid3 := create_thread worker(arg);\n\n    join tid1;\n    join tid2;\n    join tid3;\n\n    assume tid1 != 0 && tid2 != 0 && tid3 != 0;\n    printf(best_guess);\n  }\n\n}\n\nproof AB\n{\n  refinement A B\n  starweakening statements worker_lb_to_be_weakened variables best_guess\n}\n\nproof BC\n{\n  refinement B C\n  assume_intro\n}              \n\nproof CD\n{\n  refinement C D\n\n  inductive_invariant ZeroNotATid \"0 !in threads\"\n\n  inductive_invariant OnlyCertainTids @\"\n    if tid_init !in threads then\n      (forall tid :: tid !in threads)\n    else\n      var t := threads[tid_init];\n      && (if |t.stack| == 0 then\n            t.top.Armada_StackFrame_main?\n          else\n            && t.stack[|t.stack|-1].frame.Armada_StackFrame_main?\n            && !t.top.Armada_StackFrame_main?\n            && (forall i :: 0 <= i < |t.stack|-1 ==> !t.stack[i].frame.Armada_StackFrame_main?)\n         )\n      && var frame := if |t.stack| == 0 then t.top else t.stack[|t.stack|-1].frame;\n      && var pc := if |t.stack| == 0 then t.pc else t.stack[|t.stack|-1].return_pc;\n      && var tid1 := frame.main.tid1;\n      && var tid2 := frame.main.tid2;\n      && var tid3 := frame.main.tid3;\n      && (tid_init in threads ==> !threads[tid_init].top.Armada_StackFrame_worker?\n                                  && (forall eframe :: eframe in threads[tid_init].stack ==> !eframe.frame.Armada_StackFrame_worker?))\n      && (tid1 in threads ==> !threads[tid1].top.Armada_StackFrame_main?\n                              && (forall eframe :: eframe in threads[tid1].stack ==> !eframe.frame.Armada_StackFrame_main?))\n      && (tid2 in threads ==> !threads[tid2].top.Armada_StackFrame_main?\n                              && (forall eframe :: eframe in threads[tid2].stack ==> !eframe.frame.Armada_StackFrame_main?))\n      && (tid3 in threads ==> !threads[tid3].top.Armada_StackFrame_main?\n                              && (forall eframe :: eframe in threads[tid3].stack ==> !eframe.frame.Armada_StackFrame_main?))\n      && (pc.Armada_PC_main_Start? ==> forall tid :: tid in threads ==> tid == tid_init)\n      && (pc.Armada_PC_main_1? ==> forall tid :: tid in threads ==> tid == tid_init || tid == tid1)\n      && (pc.Armada_PC_main_2? ==> forall tid :: tid in threads ==> tid == tid_init || tid == tid1 || tid == tid2)\n      && (pc.Armada_PC_main_3? ==> forall tid :: tid in threads ==> tid == tid_init || tid == tid1 || tid == tid2 || tid == tid3)\n      && (pc.Armada_PC_main_4? ==> forall tid :: tid in threads ==> tid == tid_init || tid == tid2 || tid == tid3)\n      && (pc.Armada_PC_main_5? ==> forall tid :: tid in threads ==> tid == tid_init || tid == tid3)\n      && (pc.Armada_PC_main_6? ==> forall tid :: tid in threads ==> tid == tid_init)\n      && (pc.Armada_PC_main_End? ==> forall tid :: tid in threads ==> tid == tid_init)\n  \" depends_on ZeroNotATid, StackMatchesMethodInv\n\n  tso_elim best_guess @\"\n    && tid in threads\n    && var t := threads[tid];\n    && var pc := t.pc;\n    && (|| (&& |t.stack| == 0\n            && t.top.Armada_StackFrame_main?\n            && pc.Armada_PC_6_main?\n           )\n        || (&& |t.stack| == 0\n            && t.top.Armada_StackFrame_worker?\n            && (pc.Armada_PC_9_worker? || pc.Armada_PC_10_worker? || pc.Armada_PC_11_worker?)\n            && Armada_ValidPointerToPrimitive(s.s.mem.heap, s.s.addrs.mutex, Armada_PrimitiveType_uint64)\n            && Armada_DereferencePointerToPrimitive_uint64(s.s.mem.heap, s.s.addrs.mutex) == tid\n           )\n       )\n  \"\n}\n"
  },
  {
    "path": "Test/mcslock/.gitignore",
    "content": "*.dfy\n*.dfy.log\npseudo_impl.dfy\nL1.dfy\npseudo_impl_L1.dfy\npseudo_impl_L1/\nL2.dfy\nL1_L2.dfy\nL1_L2/\nL3.dfy\nL2_L3.dfy\nL2_L3/\n"
  },
  {
    "path": "Test/mcslock/lock-array.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs MCSLock {\n  struct lock {\n    var wait: uint32;\n    var next: uint64;\n  }\n\n  datatype MyLogEntry = Left(tid: uint64) | Right(tid: uint64)\n\n  ghost var log:seq<MyLogEntry> := [];\n\n  refinement_constraint @\"\n    || (ls.stop_reason == hs.stop_reason && ls.ghosts.log == hs.ghosts.log)\n    || (ls.stop_reason.Armada_NotStopped? && ls.ghosts.log <= hs.ghosts.log)\n    \"\n}\n\nlevel pseudo_impl using MCSLock {\n  noaddr var locks: lock[18446744073709551616];\n  noaddr var tail: uint64 := 0;\n  method acquire(myLock: uint64) {\n    noaddr var prev: uint64 := 0;\n    locks[myLock].next := 0;\n\n    prev := atomic_exchange(tail, myLock);\n\n    if prev != 0 {\n      locks[myLock].wait := 1;\n      locks[prev].next := myLock;\n      label wait:\n        while (locks[myLock].wait != 0) {}\n    }\n  }\n\n  method release(myLock: uint64) {\n    noaddr var nextLock: uint64 := 0;\n    noaddr var readTail: uint64 := 0;\n    readTail := compare_and_swap(tail, myLock, 0);\n    if readTail != myLock {\n      while (locks[myLock].next == 0) {}\n\n      nextLock := locks[myLock].next;\n      locks[nextLock].wait := 0;\n    }\n  }\n\n  method client() {\n    while true {\n      acquire($me);\n      label first:\n        log ::= log + [Left($me)];\n      label second:\n        log ::= log + [Right($me)];\n      label third:\n      release($me);\n    }\n  }\n\n  method main() {\n    while true\n    {\n      create_thread client();\n    }\n  }\n}\n\nlevel L1 using MCSLock {\n  noaddr var locks: lock[18446744073709551616];\n  noaddr var tail: uint64 := 0;\n  method acquire(myLock: uint64) {\n    noaddr var prev: uint64 := 0;\n    locks[$me].next := 0;\n\n    prev := atomic_exchange(tail, $me);\n\n    if prev != 0 {\n      locks[$me].wait := 1;\n      locks[prev].next := $me;\n      label wait:\n        while (locks[$me].wait != 0) {}\n    }\n  }\n\n  method release(myLock: uint64) {\n    noaddr var nextLock: uint64 := 0;\n    noaddr var readTail: uint64 := 0;\n    readTail := compare_and_swap(tail, $me, 0);\n    if readTail != $me {\n      while (locks[$me].next == 0) {}\n\n      nextLock := locks[$me].next;\n      locks[nextLock].wait := 0;\n    }\n  }\n\n  method client() {\n    while true {\n      acquire($me);\n      label first:\n        log ::= log + [Left($me)];\n      label second:\n        log ::= log + [Right($me)];\n      label third:\n      release($me);\n    }\n  }\n\n  method main() {\n    while true\n    {\n      create_thread client();\n    }\n  }\n}\n\nlevel L2 using MCSLock {\n  noaddr var locks: lock[18446744073709551616];\n  noaddr var tail: uint64 := 0;\n  ghost var ghost_tail: uint64 := 0;\n  ghost var old_owner: uint64 := 0;\n  ghost var Q: seq<uint64> := [];\n  ghost var placeholder: uint64 := 0;\n  method acquire(myLock: uint64) {\n    noaddr var prev: uint64 := 0;\n    locks[$me].next := 0;\n\n    atomic {\n      prev := atomic_exchange(tail, $me);\n      ghost_tail := $me;\n      Q ::= Q + [$me];\n    }\n\n    if prev != 0 {\n      locks[$me].wait := 1;\n      locks[prev].next := $me;\n      label wait:\n        while (locks[$me].wait != 0) {}\n    }\n  }\n\n  method release(myLock: uint64) {\n    noaddr var nextLock: uint64 := 0;\n    noaddr var readTail: uint64 := 0;\n    atomic {\n      readTail := compare_and_swap(tail, $me, 0);\n      ghost_tail := if readTail == $me then 0 else ghost_tail;\n      Q ::= if readTail == $me then [] else Q;\n    }\n    if readTail != $me {\n      while (locks[$me].next == 0) {}\n\n      nextLock := locks[$me].next;\n      atomic {\n        Q, old_owner ::= if |Q| == 0 then [] else Q[1..], $me;\n        locks[nextLock].wait := 0;\n      }\n    }\n  }\n\n  method client() {\n    while true {\n      acquire($me);\n      placeholder := 0;\n      label first:\n        log ::= log + [Left($me)];\n      label second:\n        log ::= log + [Right($me)];\n      label third:\n        release($me);\n    }\n  }\n\n  method main() {\n    while true\n    {\n      create_thread client();\n    }\n  }\n}\n\nlevel L3 using MCSLock {\n  noaddr var locks: lock[18446744073709551616];\n  noaddr var tail: uint64 := 0;\n  ghost var ghost_tail: uint64 := 0;\n  ghost var old_owner: uint64 := 0;\n  ghost var Q: seq<uint64> := [];\n  ghost var placeholder: uint64 := 0;\n  method acquire(myLock: uint64) {\n    noaddr var prev: uint64 := 0;\n    locks[$me].next := 0;\n\n    atomic {\n      prev := atomic_exchange(ghost_tail, $me);\n      tail ::= $me;\n      Q ::= Q + [$me];\n    }\n\n    if prev != 0 {\n      locks[$me].wait := 1;\n      locks[prev].next := $me;\n      label wait:\n        while (locks[$me].wait != 0) {}\n    }\n  }\n\n  method release(myLock: uint64) {\n    noaddr var nextLock: uint64 := 0;\n    noaddr var readTail: uint64 := 0;\n    atomic {\n      readTail := compare_and_swap(ghost_tail, $me, 0);\n      tail ::= if readTail == $me then 0 else tail;\n      Q ::= if readTail == $me then [] else Q;\n    }\n    if readTail != $me {\n      while (locks[$me].next == 0) {}\n\n      nextLock := locks[$me].next;\n      atomic {\n        Q, old_owner ::= if |Q| == 0 then [] else Q[1..], $me;\n        locks[nextLock].wait := 0;\n      }\n    }\n  }\n\n  method client() {\n    while true {\n      acquire($me);\n      placeholder := 0;\n      label first:\n        log ::= log + [Left($me)];\n      label second:\n        log ::= log + [Right($me)];\n      label third:\n        release($me);\n    }\n  }\n\n  method main() {\n    while true\n    {\n      create_thread client();\n    }\n  }\n}\n\nlevel L4 using MCSLock {\n  noaddr var locks: lock[18446744073709551616];\n  ghost var ghost_tail: uint64 := 0;\n  ghost var old_owner: uint64 := 0;\n  ghost var Q: seq<uint64> := [];\n  ghost var placeholder: uint64 := 0;\n  method acquire(myLock: uint64) {\n    noaddr var prev: uint64 := 0;\n    locks[$me].next := 0;\n\n    atomic {\n      prev := atomic_exchange(ghost_tail, $me);\n      Q ::= Q + [$me];\n    }\n\n    if prev != 0 {\n      locks[$me].wait := 1;\n      locks[prev].next := $me;\n      label wait:\n        while (locks[$me].wait != 0) {}\n    }\n  }\n\n  method release(myLock: uint64) {\n    noaddr var nextLock: uint64 := 0;\n    noaddr var readTail: uint64 := 0;\n    atomic {\n      readTail := compare_and_swap(ghost_tail, $me, 0);\n      Q ::= if readTail == $me then [] else Q;\n    }\n    if readTail != $me {\n      while (locks[$me].next == 0) {}\n\n      nextLock := locks[$me].next;\n      atomic {\n        Q, old_owner ::= if |Q| == 0 then [] else Q[1..], $me;\n        locks[nextLock].wait := 0;\n      }\n    }\n  }\n\n  method client() {\n    while true {\n      acquire($me);\n      placeholder := 0;\n      label first:\n        log ::= log + [Left($me)];\n      label second:\n        log ::= log + [Right($me)];\n      label third:\n        release($me);\n    }\n  }\n\n  method main() {\n    while true\n    {\n      create_thread client();\n    }\n  }\n}\n\nlevel L5 using MCSLock {\n  noaddr var locks: lock[18446744073709551616];\n  ghost var ghost_tail: uint64 := 0;\n  ghost var old_owner: uint64 := 0;\n  ghost var Q: seq<uint64> := [];\n  ghost var placeholder: uint64 := 0;\n  method acquire(myLock: uint64)\n    requires $me !in Q\n    ensures |Q| != 0 && Q[0] == $me\n    ensures $sb_empty\n  {\n    noaddr var prev: uint64 := 0;\n    locks[$me].next := 0;\n\n    atomic {\n      prev := atomic_exchange(ghost_tail, $me);\n      Q ::= Q + [$me];\n    }\n\n    if prev != 0 {\n      locks[$me].wait := 1;\n      locks[prev].next := $me;\n      label wait:\n        while (locks[$me].wait != 0)\n        {}\n    }\n  }\n\n  method release(myLock: uint64)\n    requires $sb_empty\n    requires |Q| != 0 && Q[0] == $me\n    ensures $me !in Q\n  {\n    noaddr var nextLock: uint64 := 0;\n    noaddr var readTail: uint64 := 0;\n    assume |Q| != 0 && Q[0] == $me;\n    atomic {\n      readTail := compare_and_swap(ghost_tail, $me, 0);\n      Q ::= if readTail == $me then [] else Q;\n    }\n    if readTail != $me {\n      while (locks[$me].next == 0)\n      {}\n\n      nextLock := locks[$me].next;\n      assume |Q| > 0 && Q[0] == $me;\n      atomic {\n        Q, old_owner ::= if |Q| == 0 then [] else Q[1..], $me;\n        locks[nextLock].wait := 0;\n      }\n    }\n  }\n\n  method client()\n    requires $me !in Q\n  {\n    while true\n      invariant $me !in Q\n    {\n      acquire($me);\n      assume |Q| > 0 && Q[0] == $me;\n      placeholder := 0;\n      label first:\n        assume |Q| > 0 && Q[0] == $me;\n        log ::= log + [Left($me)];\n        label second:\n          assume |Q| > 0 && Q[0] == $me;\n        log ::= log + [Right($me)];\n      label third:\n        release($me);\n    }\n  }\n\n  method main() {\n    while true\n    {\n      create_thread client();\n    }\n  }\n}\n\nlevel L6 using MCSLock {\n  noaddr var locks: lock[18446744073709551616];\n  ghost var ghost_tail: uint64 := 0;\n  ghost var old_owner: uint64 := 0;\n  ghost var Q: seq<uint64> := [];\n  ghost var placeholder: uint64 := 0;\n  method acquire(myLock: uint64)\n    requires $me !in Q\n    ensures |Q| != 0 && Q[0] == $me\n    ensures $sb_empty\n  {\n    noaddr var prev: uint64 := 0;\n    locks[$me].next := 0;\n\n    atomic {\n      prev := atomic_exchange(ghost_tail, $me);\n      Q ::= Q + [$me];\n    }\n\n    if prev != 0 {\n      locks[$me].wait := 1;\n      locks[prev].next := $me;\n      label wait:\n        while (locks[$me].wait != 0)\n        {}\n    }\n  }\n\n  method release(myLock: uint64)\n    requires $sb_empty\n    requires |Q| != 0 && Q[0] == $me\n    ensures $me !in Q\n  {\n    noaddr var nextLock: uint64 := 0;\n    noaddr var readTail: uint64 := 0;\n    assume |Q| != 0 && Q[0] == $me;\n    atomic {\n      readTail := compare_and_swap(ghost_tail, $me, 0);\n      Q ::= if readTail == $me then [] else Q;\n    }\n    if readTail != $me {\n      while (locks[$me].next == 0)\n      {}\n\n      nextLock := locks[$me].next;\n      assume |Q| > 0 && Q[0] == $me;\n      atomic {\n        Q, old_owner ::= if |Q| == 0 then [] else Q[1..], $me;\n        // Q ::= if |Q| == 0 then [] else Q[1..];\n        locks[nextLock].wait := 0;\n      }\n    }\n  }\n\n  method client()\n    requires $me !in Q\n  {\n    while true\n      invariant $me !in Q\n    {\n      acquire($me);\n      assume |Q| > 0 && Q[0] == $me;\n      placeholder := 0;\n      atomic {\n        label first:\n          assume |Q| > 0 && Q[0] == $me;\n          log ::= log + [Left($me)];\n        label second:\n          assume |Q| > 0 && Q[0] == $me;\n          log ::= log + [Right($me)];\n      }\n      label third:\n        release($me);\n    }\n  }\n\n  method main() {\n    while true\n    {\n      create_thread client();\n    }\n  }\n}\n\nproof pseudo_impl_L1 {\n  refinement pseudo_impl L1\n  weakening\n\n  inductive_invariant acquire_myLock @\"\n    forall tid :: tid in threads && threads[tid].top.Armada_StackFrame_acquire? ==>\n      threads[tid].top.acquire.myLock == tid\n  \"\n\n  inductive_invariant release_myLock @\"\n    forall tid :: tid in threads && threads[tid].top.Armada_StackFrame_release? ==>\n      threads[tid].top.release.myLock == tid\n  \"\n}\n\nproof L1_L2 {\n  refinement L1 L2\n  var_intro Q, ghost_tail, old_owner, placeholder\n}\n\nproof L2_L3 {\n  refinement L2 L3\n  weakening\n\n  inductive_invariant tail_match @\"\n    ghosts.ghost_tail == globals.tail &&\n    forall tid, entry :: tid in threads && entry in threads[tid].storeBuffer ==> entry.loc.Armada_StoreBufferLocation_Unaddressable? && !entry.loc.v.Armada_GlobalStaticVar_tail?\n  \"\n}\n\nproof L3_L4 {\n  refinement L3 L4\n  var_hiding tail\n}\n\nproof L4_L5 {\n  refinement L4 L5\n  assume_intro\n\n  include_file \"L4_L5_helper.dfy\"\n  import_module Helper\n\n  inductive_invariant {:opaque} trivial_inv \"Helper.inv_trivial(s.s)\"\n\n  inductive_invariant inv_wf \"Helper.inv_wf(s.s)\" depends_on trivial_inv\n\n  chl_yield_pred {:opaque} {:excludeMethod acquire, release} {:excludeLoop client_Start} yp_nolocks \"Helper.yp_nolocks(s.s, s'.s, tid)\"\n\n  chl_yield_pred {:opaque} {:excludeMethod acquire, release} {:excludeLoop client_Start} yp_locks \"Helper.yp_locks(s.s, s'.s, tid)\"\n\n  chl_invariant {:opaque} inv_Q \"Helper.inv_Q(s.s)\"\n\n  chl_invariant {:opaque} inv_sb \"Helper.inv_sb(s.s)\"\n\n  chl_invariant {:opaque} inv_wait_clear \"Helper.inv_wait_clear(s.s)\"\n\n  chl_invariant {:opaque} inv_next_deliver \"Helper.inv_next_deliver(s.s)\"\n\n  chl_local_invariant {:opaque} acquire_1 inv_Q_tail \"(|ghosts.Q| == 0 <==> ghosts.ghost_tail == 0) && (|ghosts.Q| != 0 ==> ghosts.ghost_tail == ghosts.Q[|s.s.ghosts.Q|-1])\"\n\n  chl_local_invariant {:opaque} acquire_3 inv_prev \"tid in ghosts.Q && threads[tid].top.acquire.prev == if owner_of(tid, ghosts.Q) then 0 else Helper.pred(tid, ghosts.Q)\"\n\n  chl_local_invariant {:opaque} release_5 inv_next_correct \"|ghosts.Q| > 1 && globals.locks[tid].next == ghosts.Q[1]\"\n\n  chl_local_invariant {:opaque} release_6 inv_head_waiting \"|ghosts.Q| > 1 && owner_of(tid, ghosts.Q) && globals.locks[ghosts.Q[1]].wait != 0 && ghosts.Q[1] in threads && waiting_pc(threads[ghosts.Q[1]].pc)\"\n\n  // loop entry\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesLoopModifiesClausesOnEntry_acquire_Y_Yielded_wait @\"\n    reveal UserInv_inv_Q();\n    reveal UserYP_yp_nolocks();\n    reveal UserYP_yp_locks();\n    reveal yp_storebuffer();\n  \"\n\n  // loop back\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesLoopModifiesClausesOnJumpBack_acquire_YY_YieldedRevisited_wait @\"\n    reveal UserInv_inv_sb();\n    reveal UserYP_yp_nolocks();\n    reveal UserYP_yp_locks();\n    yp_storebuffer_trans();\n  \"\n\n  // postconditions\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesPostcondition_release_YN_Yielded_End @\"\n    reveal UserInv_inv_Q();\n    reveal UserYP_yp_nolocks();\n    Q_pop_facts(s11.s.ghosts.Q);\n  \"\n\n  // local invs\n\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesLocalInvariant_release_YN_Yielded_6_Then_From_release_6_To_release_End @\"\n    reveal UserLocalInvariant_release_6_inv_head_waiting();\n    reveal UserInv_inv_Q();\n    reveal UserInv_inv_next_deliver();\n    reveal UserYP_yp_nolocks();\n    reveal UserYP_yp_locks();\n    unique_Q_facts(s11.s.ghosts.Q);\n  \"\n\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesLocalInvariant_release_YN_Yielded_6_Then_UB_From_release_6_To_release_End @\"\n    reveal UserInv_inv_Q();\n    reveal UserYP_yp_nolocks();\n    reveal UserYP_yp_locks();\n    unique_Q_facts(s11.s.ghosts.Q);\n  \"\n\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesLocalInvariant_release_YN_Yielded_5_Then_From_release_5_To_release_6 @\"\n    reveal UserLocalInvariant_release_5_inv_next_correct();\n    reveal UserInv_inv_Q();\n    reveal UserYP_yp_nolocks();\n    reveal UserYP_yp_locks();\n    unique_Q_facts(s9.s.ghosts.Q);\n  \"\n\n  // inv_wf\n\n  extra lemma_InvariantPredicateMaintainedByPath_inv_wf_From_main_1_To_main_JumpBack_2 \"assert new_tid_trigger(steps.step0.params_CreateThread_main_1.newtid);\"\n\n  // inv_sb\n\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesGlobalInvariant_inv_sb_acquire_Yielded_1_Then_From_acquire_1_To_acquire_3 @\"\n    reveal UserInv_inv_Q();\n    reveal UserInv_inv_sb();\n    reveal UserYP_yp_nolocks();\n    reveal UserYP_yp_locks();\n    Q_push_facts(s3.s.ghosts.Q, tid);\n  \"\n\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesGlobalInvariant_inv_sb_acquire_YY_Yielded_JumpBack_7_Then_From_acquire_JumpBack_7_To_acquire_wait @\"\n    reveal UserInv_inv_sb();\n  \"\n\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesGlobalInvariant_inv_sb_acquire_Y_Yielded_5_Then_From_acquire_5_To_acquire_wait @\"\n    reveal UserInv_inv_Q();\n    reveal UserInv_inv_sb();\n    reveal UserYP_yp_nolocks();\n    reveal UserYP_yp_locks();\n    assert waiting_pc(s11.s.threads[tid].pc);\n  \"\n\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesGlobalInvariant_inv_sb_release_Yielded_Start_Then_From_release_Start_To_release_2 @\"\n    reveal UserInv_inv_Q();\n    reveal UserInv_inv_sb();\n    unique_Q_singleton(s1.s.ghosts.Q);\n  \"\n\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesGlobalInvariant_inv_sb_release_YN_Yielded_6_Then_From_release_6_To_release_End @\"\n    reveal UserInv_inv_Q();\n    reveal UserInv_inv_sb();\n    reveal UserInv_inv_next_deliver();\n    reveal UserYP_yp_nolocks();\n    reveal UserYP_yp_locks();\n    Q_pop_facts(s11.s.ghosts.Q);\n    unique_Q_facts(s11.s.ghosts.Q);\n\n    forall other_tid {:trigger s13.s.threads[other_tid].storeBuffer} | other_tid in s13.s.threads\n      ensures inv_sb_thread(other_tid, s13.s.threads[other_tid].storeBuffer, s13.s)\n    {\n    }\n  \"\n\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesGlobalInvariant_inv_sb_client_Y_Yielded_JumpBack_6_Then_From_client_JumpBack_6_To_client_Start @\"\n    reveal UserInv_inv_Q();\n    reveal UserInv_inv_sb();\n    assert !waiting_pc(s19.s.threads[tid].pc);\n  \"\n\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesGlobalInvariant_inv_sb_acquire_YY_YieldedRevisited_wait_Then_From_acquire_wait_T_To_acquire_JumpBack_7 @\"\n    reveal UserInv_inv_sb();\n  \"\n\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesGlobalInvariant_inv_sb_acquire_YY_YieldedRevisited_wait_Then_From_acquire_wait_F_To_acquire_End @\"\n    reveal UserInv_inv_sb();\n    reveal UserInv_inv_wait_clear();\n  \"\n\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesGlobalInvariant_inv_sb_client_Y_YieldedRevisited_Start_Then_From_client_Start_T_To_client_1 @\"\n    reveal UserInv_inv_sb();\n  \"\n\n  // inv_next_deliver\n\n  extra lemma_ActorlessStepsMaintainSpecificGlobalInv_inv_next_deliver @\"\n    reveal UserInv_inv_Q();\n    reveal UserInv_inv_sb();\n    reveal UserInv_inv_next_deliver();\n    forall tid' | tid' in s'.s.ghosts.Q && !owner_of(tid', s'.s.ghosts.Q) && s'.s.mem.globals.locks[pred(tid', s'.s.ghosts.Q)].next != 0\n      ensures s'.s.mem.globals.locks[tid'].wait != 0\n      ensures waiting_pc(s'.s.threads[tid'].pc)\n      ensures |s'.s.threads[tid'].storeBuffer| == 0\n      ensures forall tid'' :: tid'' in s'.s.threads ==> next_entry(pred(tid', s'.s.ghosts.Q), tid'', L.Armada_PC_acquire_5) !in s'.s.threads[tid''].storeBuffer\n    {\n      assert tid' in s.s.ghosts.Q;\n      assert !owner_of(tid', s.s.ghosts.Q);\n      if tid' == tid {\n        var entry := s.s.threads[tid].storeBuffer[0];\n        if inv_entry_acquire_5(tid, entry, s.s) {\n          assert s'.s.mem.globals.locks[tid'].wait != 0;\n\n          forall tid'' | tid'' in s'.s.threads && tid'' != tid'\n            ensures next_entry(pred(tid', s'.s.ghosts.Q), tid'', L.Armada_PC_acquire_5) !in s'.s.threads[tid''].storeBuffer\n          {\n            if next_entry(pred(tid', s'.s.ghosts.Q), tid'', L.Armada_PC_acquire_5) in s'.s.threads[tid''].storeBuffer {\n              assert inv_entry_acquire_5(tid'', next_entry(pred(tid', s'.s.ghosts.Q), tid'', L.Armada_PC_acquire_5), s'.s);\n              assert pred(tid', s'.s.ghosts.Q) == pred(tid'', s'.s.ghosts.Q);\n              unique_Q_facts(s'.s.ghosts.Q);\n            }\n          }\n        }\n      } else {\n        assert s.s.ghosts.Q == s'.s.ghosts.Q;\n\n        var entry := s.s.threads[tid].storeBuffer[0];\n        if inv_entry_acquire_5(tid, entry, s.s) {\n          forall\n            ensures pred(tid', s.s.ghosts.Q) != pred(tid, s.s.ghosts.Q)\n          {\n            unique_Q_facts(s.s.ghosts.Q);\n          }\n          assert s.s.mem.globals.locks[pred(tid', s.s.ghosts.Q)].next == s'.s.mem.globals.locks[pred(tid', s.s.ghosts.Q)].next;\n        }\n      }\n    }\"\n\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesGlobalInvariant_inv_next_deliver_acquire_Yielded_1_Then_From_acquire_1_To_acquire_3 @\"\n    reveal UserInv_inv_Q();\n    reveal UserInv_inv_next_deliver();\n    reveal UserYP_yp_nolocks();\n    Q_push_facts(s3.s.ghosts.Q, tid);\n  \"\n\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesGlobalInvariant_inv_next_deliver_acquire_YY_YieldedRevisited_wait_Then_From_acquire_wait_T_To_acquire_JumpBack_7 @\"\n    reveal UserInv_inv_Q();\n    reveal UserInv_inv_wait_clear();\n    reveal UserInv_inv_next_deliver();\n    reveal UserYP_yp_locks();\n  \"\n\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesGlobalInvariant_inv_next_deliver_acquire_YY_YieldedRevisited_wait_Then_From_acquire_wait_F_To_acquire_End @\"\n    reveal UserInv_inv_Q();\n    reveal UserInv_inv_next_deliver();\n  \"\n\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesGlobalInvariant_inv_next_deliver_release_YN_Yielded_6_Then_From_release_6_To_release_End @\"\n    reveal UserInv_inv_Q();\n    reveal UserInv_inv_next_deliver();\n    var threads, Q := s11.s.threads, s11.s.ghosts.Q;\n    var threads', Q' := s13.s.threads, s13.s.ghosts.Q;\n\n    Q_pop_facts(Q);\n    simple_unique_Q_facts(Q);\n\n    forall other_tid {:trigger pred(other_tid, Q')}\n      | other_tid in Q' && !owner_of(other_tid, Q') && s13.s.mem.globals.locks[pred(other_tid, Q')].next != 0\n      ensures s13.s.mem.globals.locks[other_tid].wait != 0\n      ensures waiting_pc(threads[other_tid].pc)\n      ensures |threads[other_tid].storeBuffer| == 0\n      ensures forall tid' {:trigger threads'[tid'].storeBuffer} ::\n        tid' in threads' ==> next_entry(pred(other_tid, Q'), tid', L.Armada_PC_acquire_5) !in threads'[tid'].storeBuffer\n    {\n      assert s11.s.mem.globals.locks[pred(other_tid, Q)].next != 0;\n      forall tid' {:trigger threads'[tid'].storeBuffer} | tid' in threads'\n        ensures next_entry(pred(other_tid, Q'), tid', L.Armada_PC_acquire_5) !in threads'[tid'].storeBuffer\n      {\n        assert next_entry(pred(other_tid, Q), tid', L.Armada_PC_acquire_5) !in threads[tid'].storeBuffer;\n      }\n    }\n\n    assert inv_next_deliver(s13.s);\n  \"\n\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesGlobalInvariant_inv_next_deliver_acquire_Y_Yielded_wait_Then_From_acquire_wait_T_To_acquire_JumpBack_7 @\"\n    reveal UserInv_inv_Q();\n    reveal UserInv_inv_next_deliver();\n    assert waiting_pc(s12.s.threads[tid].pc);\n  \"\n\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesGlobalInvariant_inv_next_deliver_acquire_YY_Yielded_JumpBack_7_Then_From_acquire_JumpBack_7_To_acquire_wait @\"\n    reveal UserInv_inv_Q();\n    reveal UserInv_inv_next_deliver();\n    assert waiting_pc(s15.s.threads[tid].pc);\n  \"\n\n  // inv_Q\n  extra lemma_GlobalInvariantSatisfiedInitially_inv_Q @\"\n    reveal UserInv_trivial_inv();\n    reveal UserInv_inv_Q();\n    empty_Q_unique();\n  \"\n\n  extra lemma_ActorlessStepsMaintainSpecificGlobalInv_inv_Q @\"\n    reveal UserInv_inv_Q();\n    reveal UserInv_inv_sb();\n    unique_Q_facts(s'.s.ghosts.Q);\n  \"\n\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesGlobalInvariant_inv_Q_acquire_Yielded_1_Then_From_acquire_1_To_acquire_3 @\"\n    reveal UserInv_trivial_inv();\n    reveal UserLocalInvariant_acquire_1_inv_Q_tail();\n    reveal UserInv_inv_Q();\n    reveal UserYP_yp_nolocks();\n    reveal UserYP_yp_locks();\n    Q_push_facts(s3.s.ghosts.Q, tid);\n  \"\n\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesGlobalInvariant_inv_Q_release_YN_Yielded_6_Then_From_release_6_To_release_End @\"\n    reveal UserInv_trivial_inv();\n    reveal UserLocalInvariant_release_6_inv_head_waiting();\n    reveal UserInv_inv_Q();\n    reveal UserYP_yp_nolocks();\n    reveal UserYP_yp_locks();\n    Q_pop_facts(s11.s.ghosts.Q);\n  \"\n\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesGlobalInvariant_inv_Q_release_Yielded_Start_Then_From_release_Start_To_release_2 @\"\n    reveal UserInv_trivial_inv();\n    reveal UserInv_inv_Q();\n    reveal UserYP_yp_nolocks();\n    reveal UserYP_yp_locks();\n    empty_Q_unique();\n  \"\n\n  // inv_wait_clear\n\n  extra lemma_ActorlessStepsMaintainSpecificGlobalInv_inv_wait_clear @\"\n    reveal UserInv_trivial_inv();\n    reveal UserInv_inv_sb();\n    reveal UserInv_inv_wait_clear();\n    forall tid' | tid' in s'.s.threads\n      ensures Armada_GetThreadLocalViewLength(s'.s, tid').globals.locks[tid'].wait == 0 ==> s'.s.mem.globals.locks[tid'].wait == 0\n      ensures Armada_GetThreadLocalViewLength(s'.s, tid').globals.locks[tid'].wait == 0 && waiting_pc(s'.s.threads[tid'].pc) ==> owner_of(tid', s'.s.ghosts.Q)\n    {\n      if Armada_GetThreadLocalViewLength(s'.s, tid').globals.locks[tid'].wait == 0 &&\n         Armada_GetThreadLocalViewLength(s.s, tid').globals.locks[tid'].wait != 0 {\n        reveal Armada_ApplyStoreBufferEntryLength();\n        wait_cleared_shared_memory_changed(s.s.mem, s'.s.mem, s.s.threads[tid'].storeBuffer, tid');\n        wait_cleared_entry_release_7(s.s, tid, tid');\n        assert owner_of(tid', s.s.ghosts.Q);\n      }\n    }\n  \"\n\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesGlobalInvariant_inv_wait_clear_acquire_Yielded_Start_Then_From_acquire_Start_To_acquire_1 @\"\n    reveal UserInv_inv_wait_clear();\n    next_wait_non_interference(s1.s, tid, next_entry(tid, 0, L.Armada_PC_acquire_Start));\n  \"\n\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesGlobalInvariant_inv_wait_clear_acquire_Yielded_1_Then_From_acquire_1_To_acquire_3 @\"\n    reveal UserInv_inv_wait_clear();\n    storebuffer_same_localview_general(s3.s, s5.s);\n  \"\n\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesGlobalInvariant_inv_wait_clear_acquire_Y_Yielded_4_Then_From_acquire_4_To_acquire_5 @\"\n    reveal UserInv_inv_wait_clear();\n    var mem' := apply_storebuffer_snoc(s9.s.mem, s8.s.threads[tid].storeBuffer, wait_entry(tid, 1, L.Armada_PC_acquire_4));\n    reveal Armada_ApplyStoreBufferEntryLength();\n    assert Armada_ApplyStoreBufferEntryLength(mem', wait_entry(tid, 1, L.Armada_PC_acquire_4)).globals.locks[tid].wait != 0;\n  \"\n\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesGlobalInvariant_inv_wait_clear_acquire_Y_Yielded_5_Then_From_acquire_5_To_acquire_wait @\"\n    reveal UserInv_inv_wait_clear();\n    reveal UserYP_yp_nolocks();\n    reveal UserYP_yp_locks();\n    next_wait_non_interference(s10.s, tid, next_entry(s10.s.threads[tid].top.acquire.prev, tid, L.Armada_PC_acquire_5));\n    reveal Armada_GetThreadLocalViewLength();\n    reveal Armada_ApplyStoreBufferLength();\n    reveal Armada_ApplyStoreBufferEntryLength();\n  \"\n\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesGlobalInvariant_inv_wait_clear_acquire_YY_Yielded_JumpBack_7_Then_From_acquire_JumpBack_7_To_acquire_wait @\"\n    reveal UserInv_inv_wait_clear();\n  \"\n\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesGlobalInvariant_inv_wait_clear_acquire_YY_YieldedRevisited_wait_Then_From_acquire_wait_T_To_acquire_JumpBack_7 @\"\n    reveal UserInv_inv_wait_clear();\n  \"\n\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesGlobalInvariant_inv_wait_clear_acquire_YY_YieldedRevisited_wait_Then_From_acquire_wait_F_To_acquire_End @\"\n    reveal UserInv_inv_wait_clear();\n  \"\n\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesGlobalInvariant_inv_wait_clear_release_YN_Yielded_6_Then_From_release_6_To_release_End @\"\n    reveal UserLocalInvariant_release_5_inv_next_correct();\n    reveal UserLocalInvariant_release_6_inv_head_waiting();\n    reveal UserInv_inv_wait_clear();\n    reveal UserYP_yp_nolocks();\n    wait_wait_non_interference(s12.s, tid, wait_entry(s12.s.threads[tid].top.release.nextLock, 0, L.Armada_PC_release_7));\n  \"\n\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesGlobalInvariant_inv_wait_clear_client_Y_Ensured_2_Then_From_acquire_End_To_client_2 @\"\n    reveal UserInv_inv_wait_clear();\n    reveal Armada_GetThreadLocalViewLength();locks_independence_generalized(s6.s.mem, s7.s.mem);\n  \"\n\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesGlobalInvariant_inv_wait_clear_client_Y_Ensured_JumpBack_6_Then_From_release_End_To_client_JumpBack_6 @\"\n    reveal UserInv_inv_wait_clear();\n    reveal Armada_GetThreadLocalViewLength();locks_independence_generalized(s16.s.mem, s17.s.mem);\n  \"\n\n  // yp_nolocks\n\n  extra lemma_YieldPredicateTransitive_yp_nolocks @\"\n    reveal UserYP_yp_nolocks();\n    forall ensures yp_storebuffer(s1.s.threads[actor].storeBuffer, s3.s.threads[actor].storeBuffer) {\n      reveal yp_storebuffer();\n    }\n  \"\n\n  extra lemma_ActorlessStepsMaintainYieldPredicate_yp_nolocks @\"\n    reveal UserYP_yp_nolocks();\n    reveal yp_storebuffer();\n  \"\n\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesYieldPredicate_yp_nolocks_acquire_Yielded_1_Then_From_acquire_1_To_acquire_3 @\"\n    reveal UserInv_inv_Q();\n    reveal UserYP_yp_nolocks();\n    Q_push_facts(s3.s.ghosts.Q, tid);\n  \"\n\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesYieldPredicate_yp_nolocks_release_Yielded_Start_Then_From_release_Start_To_release_2 @\"\n    reveal UserInv_inv_Q();\n    reveal UserYP_yp_nolocks();\n    empty_Q_unique();\n    unique_Q_singleton(s1.s.ghosts.Q);\n  \"\n\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesYieldPredicate_yp_nolocks_release_YN_Yielded_6_Then_From_release_6_To_release_End @\"\n    reveal UserInv_inv_Q();\n    reveal UserInv_inv_next_deliver();\n    reveal UserYP_yp_nolocks();\n    reveal UserYP_yp_locks();\n    Q_pop_facts(s11.s.ghosts.Q);\n    unique_Q_facts(s11.s.ghosts.Q);\n  \"\n\n  // yp_locks\n  extra lemma_YieldPredicateTransitive_yp_locks @\"\n    reveal UserInv_inv_Q();\n    reveal UserInv_inv_sb();\n    reveal UserInv_inv_wait_clear();\n    reveal UserInv_inv_next_deliver();\n    reveal UserYP_yp_nolocks();\n    reveal UserYP_yp_locks();\n    reveal yp_storebuffer();\n    var sb1, sb2, sb3 := s1.s.threads[actor].storeBuffer, s2.s.threads[actor].storeBuffer,s3.s.threads[actor].storeBuffer;\n    if !owner_of(actor, s1.s.ghosts.Q) && actor in s1.s.ghosts.Q && 0 < pred(actor, s1.s.ghosts.Q) as int < |s1.s.mem.globals.locks| {\n      if Armada_ApplyStoreBufferLength(s1.s.mem, sb1).globals.locks[actor].wait != 0 &&\n        Armada_ApplyStoreBufferLength(s3.s.mem, sb3).globals.locks[actor].wait == 0 {\n      }\n    }\n  \"\n\n  extra lemma_ActorlessStepsMaintainYieldPredicate_yp_locks @\"\n    reveal UserInv_inv_Q();\n    reveal UserInv_inv_sb();\n    reveal UserYP_yp_locks();\n    reveal Armada_GetThreadLocalViewLength();\n    reveal Armada_ApplyStoreBufferLength();\n    reveal Armada_ApplyStoreBufferEntryLength();\n  \"\n\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesYieldPredicate_yp_locks_acquire_Yielded_1_Then_From_acquire_1_To_acquire_3 @\"\n    reveal UserInv_inv_Q();\n    reveal UserYP_yp_nolocks();\n    reveal UserYP_yp_locks();\n    Q_push_facts(s3.s.ghosts.Q, tid);\n  \"\n\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesYieldPredicate_yp_locks_client_Y_Ensured_2_Then_From_acquire_End_To_client_2 @\"\n    reveal UserYP_yp_locks();\n    locks_independence(s6.s.mem, s7.s.mem, s6.s.threads[other_tid].storeBuffer);\n  \"\n\n  extra lemma_ExpandedStraightlineBehaviorSatisfiesYieldPredicate_yp_locks_client_Y_Ensured_JumpBack_6_Then_From_release_End_To_client_JumpBack_6 @\"\n    reveal UserYP_yp_locks();\n    locks_independence(s16.s.mem, s17.s.mem, s16.s.threads[other_tid].storeBuffer);\n  \"\n}\n\nproof L5_L6 {\n  refinement L5 L6\n    reduction phase2 client_second\n\n    include_file \"L5_L6_helper.dfy\"\n    import_module Helper\n\n    inductive_invariant non_terminate_inv @\"\n      forall tid :: tid in s.s.threads ==>\n        var thread := s.s.threads[tid];\n        !thread.pc.Armada_PC_main_End? && !thread.pc.Armada_PC_client_End?\n    \"\n\n    inductive_invariant length_inv @\"\n      forall tid :: tid in s.s.threads ==>\n        Helper.Armada_GetThreadLocalViewLength(s.s, tid) == L.Armada_GetThreadLocalView(s.s, tid) &&\n        |s.s.mem.globals.locks| == 18446744073709551616\n    \"\n\n    inductive_invariant ownership_inv @\"\n      forall tid :: tid in s.s.threads ==>\n        (s.s.threads[tid].pc.Armada_PC_client_first? || s.s.threads[tid].pc.Armada_PC_client_second?) ==>\n        |s.s.ghosts.Q| > 0 && s.s.ghosts.Q[0] == tid\n    \"\n}\n"
  },
  {
    "path": "Test/mcslock/lock.c",
    "content": "#include <stdint.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include <unistd.h>\n\nstruct lock {\n  uint32_t wait;\n  struct lock *next;\n};\n\ntypedef struct lock lock;\n\n#ifdef __GNUC__\n\n#define CAS(_a, _n, _o)                                                 \\\n  ({ __typeof__(_o) __o = _o;                                           \\\n    __asm__ __volatile__(                                               \\\n                         \"lock cmpxchg %3,%1\"                           \\\n                         : \"=a\" (__o), \"=m\" (*(volatile unsigned int *)(_a)) \\\n                         :  \"0\" (__o), \"r\" (_n) );                      \\\n    __o;                                                                \\\n  })\n\n#define MFENCE() asm volatile (\"mfence\" ::: \"memory\")\n\n#endif\n\nvoid acquire(lock **tail, lock *myLock) {\n  lock *oldTail;\n  lock *readTail;\n\n  (*myLock).next = NULL;\n\n  oldTail = *tail;\n  readTail = CAS(tail, myLock, oldTail);\n  while (readTail != oldTail) {\n    oldTail = *tail;\n    readTail = CAS(tail, myLock, oldTail);\n  }\n\n  if (oldTail != NULL) {\n    (*myLock).wait = 1;\n    MFENCE();\n    (*oldTail).next = myLock;\n    while ((*myLock).wait != 0) {}\n  }\n}\n\nvoid release(lock **tail, lock* myLock) {\n  lock *nextLock;\n  lock *readTail;\n\n  readTail = CAS(tail, NULL, myLock);\n  if (readTail == myLock) {\n  }\n  else {\n    while ((*myLock).next == NULL) {}\n\n    nextLock = (*myLock).next;\n    (*nextLock).wait = 0;\n  }\n}\n\n// testing\nlock locks[6];\nchar messages[5][20] =\n  {\n   \"thread 1\",\n   \"thread 2\",\n   \"thread 3\",\n   \"thread 4\",\n   \"thread 5\"\n};\nlock *tail;\n\nvoid my_puts_unlocked(char *str) {\n  while (*str != '\\0') {\n    putc_unlocked(*str, stdout);\n    ++ str;\n  }\n  putc_unlocked('\\n', stdout);\n}\n\nvoid racy_printer(void *arg) {\n  uint32_t index = (uint32_t) arg;\n  index = index;\n  for (int i = 0; i < 10; ++ i) {\n    acquire(&tail, &locks[index]);\n    my_puts_unlocked(messages[index]);\n    release(&tail, &locks[index]);\n  }\n}\n\n#ifdef __GNUC__\n\n#include <pthread.h>\n\nvoid thread_create(void (*thread) (void *), void *arg) {\n  pthread_t pthread;\n\n  pthread_create(&pthread, NULL, (void * (*) (void *))thread, arg);\n}\n\n#endif\n\nint main() {\n  tail = NULL;\n  acquire(&tail, &locks[5]);\n  for (int i = 0; i < 5; ++ i) {\n    thread_create(racy_printer, (void *)i);\n  }\n  my_puts_unlocked(\"Finished thread creation\");\n  release(&tail, &locks[5]);\n  sleep(1);\n  return 0;\n}\n"
  },
  {
    "path": "Test/qbss/.gitignore",
    "content": "CombineDequeueAtomicAbstractQueue.dfy\nCombineDequeueAtomicAbstractQueue/\nCombineEnqueueAtomicAbstractQueue.dfy\nCombineEnqueueAtomicAbstractQueue/\nHideDequeueLocals.dfy\nHideDequeueLocals/\nHideEnqueueLocals.dfy\nHideEnqueueLocals/\nHideGlobal.dfy\nHideGlobal/\nNoTSOIntroduceAbstractQueue.dfy\nNoTSOIntroduceAbstractQueue/\nNoTSOStarWeaken.dfy\nNoTSOStarWeaken/\nNoTSOUseAbstractQueueForLog.dfy\nNoTSOUseAbstractQueueForLog/\nQueueBSSNoTSO.dfy\nQueueBSSNoTSO_AbstractLogs.dfy\nQueueBSSNoTSO_AbstractLogsStarweakened.dfy\nQueueBSSNoTSO_AbstractQueueIntroduced.dfy\nQueueBSSNoTSO_AbstractQueueIntroduced_CombinedEnqueue.dfy\nQueueBSSNoTSO_HiddenEnqDeqLocals.dfy\nQueueBSSNoTSO_HiddenEnqLocals.dfy\nQueueBSSNoTSO_HiddenImpl.dfy\nQueueBSSNoTSO_WithAbstractQueue.dfy\nSharedStructs.dfy\n"
  },
  {
    "path": "Test/qbss/assumeintroproof_invariant.dfy",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\ninclude \"QueueBSS_TSObypass.dfy\"\ninclude \"QueueBSS_Assume.dfy\"\ninclude \"AssumeIntroProof/specs.dfy\"\n\nmodule assumeintroproof_invariant {\nimport opened ArmadaModule_specs\nimport opened ArmadaCommonDefinitions = ArmadaCommonDefinitions\n\n/*\n   EnqueueRegion = set{enqueue.e, AddrOf((*e).key), AddrOf((*e).value) }\n\n   All store buffer entries in enqueue write to EnqueueRegion.\n\n   e == queue.element_array + write_index\n\n   storeBuffer != [] ==> write_index \n\n   This will alow us to commute tau steps from different threads.\n\n   Need to commute tau of enqueue with dequeue steps.\n   EnqTau with read of e.key and e.value should work if we add to the invariant\n   the following:\n\n   enqueue.storeBuffer only contains writes to e.key, e.value, queue.write\n   enqueue.storeBuffer != [] ==> e == queue.element_array + write_index\n\n   enqueue.storeBuffer != [] && deq.pc in range \n    ==> enqueue.write_index != dequeue.read_index\n  \n   applying any entry of enqueue.storeBuffer preserves DequeueLocalToGlobalInv\n\n*/\n\npredicate MainInitInvariant(s:LPlusState) {\n  && (forall tid ::\n    && tid in s.s.threads\n    && s.s.threads[tid].top.Armada_StackFrame_main?\n    && PCToInstructionCount_L(L.Armada_PC_main_mn_array_size_init) < PCToInstructionCount_L(s.s.threads[tid].pc)\n    ==> s.s.mem.globals.queue.array_size as int != 0)\n\n    && (forall tid ::\n    && tid in s.s.threads\n    && s.s.threads[tid].top.Armada_StackFrame_main?\n    && PCToInstructionCount_L(L.Armada_PC_main_mn_write_index_init) < PCToInstructionCount_L(s.s.threads[tid].pc)\n    ==> 0 <= s.s.mem.globals.queue.write_index < s.s.mem.globals.queue.array_size)\n\n    && (forall tid ::\n    && tid in s.s.threads\n    && s.s.threads[tid].top.Armada_StackFrame_main?\n    && PCToInstructionCount_L(L.Armada_PC_main_mn_read_index_init) < PCToInstructionCount_L(s.s.threads[tid].pc)\n    ==> 0 <= s.s.mem.globals.queue.read_index < s.s.mem.globals.queue.array_size)\n\n    && (forall tid :: tid in s.s.threads && s.s.threads[tid].top.Armada_StackFrame_enqueue?\n    ==> \n    && s.s.mem.globals.queue.array_size as int > 0\n    && 0 <= s.s.mem.globals.queue.write_index < s.s.mem.globals.queue.array_size\n    && 0 <= s.s.mem.globals.queue.read_index < s.s.mem.globals.queue.array_size\n    )\n\n    && (forall tid :: tid in s.s.threads && s.s.threads[tid].top.Armada_StackFrame_dequeue?\n    ==> \n    && s.s.mem.globals.queue.array_size as int > 0\n    && 0 <= s.s.mem.globals.queue.write_index < s.s.mem.globals.queue.array_size\n    && 0 <= s.s.mem.globals.queue.read_index < s.s.mem.globals.queue.array_size\n    )\n}\n\npredicate EnqueueInitInvariant(s:LPlusState)\n  requires MainInitInvariant(s)\n{\n    // Self contained invariant. However, the subclauses depend upon one another.\n    && (forall tid1 ::\n        && tid1 in s.s.threads \n        && s.s.threads[tid1].top.Armada_StackFrame_enqueue?\n        ==> (\n        var pc := s.s.threads[tid1].pc; var queue := s.s.mem.globals.queue;\n        var frame := s.s.threads[tid1].top;\n\n        // EnqInitWriteIndexIsGlobalWriteIndex\n        && (\n            && (PCToInstructionCount_L(L.Armada_PC_enqueue_write_index_init) <\n                PCToInstructionCount_L(pc) <=\n                PCToInstructionCount_L(L.Armada_PC_enqueue_assume_end))\n            ==> frame.enqueue'write_index == queue.write_index\n        )\n\n        // EnqInitTmpWriteIndexIsGlobalWriteIndexPlusOne\n        && (\n            && (PCToInstructionCount_L(L.Armada_PC_enqueue_tmp_write_index_init) <\n                PCToInstructionCount_L(pc) <=\n                PCToInstructionCount_L(L.Armada_PC_enqueue_assume_end))\n            ==> frame.enqueue'tmp_write_index == Armada_CastTo_uint64(queue.write_index as int + 1 as int)\n        )\n\n        // EnqInitArraySizeIsGlobalArraySize\n        && (\n            && (PCToInstructionCount_L(L.Armada_PC_enqueue_array_size_init) <\n                PCToInstructionCount_L(pc) <=\n                PCToInstructionCount_L(L.Armada_PC_enqueue_assume_end))\n            ==> frame.enqueue'array_size == queue.array_size\n        )\n\n        // EnqInitModuloIsGlobalWriteIndexPlusOneModGlobalArraySize\n        && (\n            && (PCToInstructionCount_L(L.Armada_PC_enqueue_modulo_init) <\n                PCToInstructionCount_L(pc) <=\n                PCToInstructionCount_L(L.Armada_PC_enqueue_assume_end))\n            ==> frame.enqueue'modulo ==\n        Armada_CastTo_uint64((Armada_CastTo_uint64((queue.write_index as int + 1 as int) as int) as int % queue.array_size as int) as int)\n        )\n\n        )\n    )\n}\n\npredicate DequeueInitInvariant(s:LPlusState) \n  requires MainInitInvariant(s)\n{\n    && (forall tid2 ::\n        && tid2 in s.s.threads \n        && s.s.threads[tid2].top.Armada_StackFrame_dequeue?\n        ==> (\n        var pc := s.s.threads[tid2].pc; var queue := s.s.mem.globals.queue;\n        var frame := s.s.threads[tid2].top;\n        && (\n        // DeqInitReadIndexIsGlobalReadIndex\n            && (PCToInstructionCount_L(L.Armada_PC_dequeue_read_index_init) <\n                PCToInstructionCount_L(pc) <=\n                PCToInstructionCount_L(L.Armada_PC_dequeue_assume_end))\n            ==> frame.dequeue'read_index == queue.read_index\n        )\n\n        && (\n        // DeqInitTmpReadIndexIsGlobalReadIndexPlusOne\n            && (PCToInstructionCount_L(L.Armada_PC_dequeue_tmp_read_index_init) <\n                PCToInstructionCount_L(pc) <=\n                PCToInstructionCount_L(L.Armada_PC_dequeue_assume_end))\n            ==> frame.dequeue'tmp_read_index == Armada_CastTo_uint64(queue.read_index as int + 1 as int)\n        )\n\n        && (\n        // DeqInitArraySizeIsGlobalArraySize\n            && (PCToInstructionCount_L(L.Armada_PC_dequeue_array_size_init) <\n                PCToInstructionCount_L(pc) <=\n                PCToInstructionCount_L(L.Armada_PC_dequeue_assume_end))\n            ==> frame.dequeue'array_size == queue.array_size\n        )\n\n        && (\n        // DeqInitModuloIsGlobalReadIndexPlusOneModGlobalArraySize\n            && (PCToInstructionCount_L(L.Armada_PC_dequeue_modulo_init) <\n                PCToInstructionCount_L(pc) <=\n                PCToInstructionCount_L(L.Armada_PC_dequeue_assume_end))\n            ==> frame.dequeue'modulo ==\n        Armada_CastTo_uint64((Armada_CastTo_uint64((queue.read_index as int + 1 as int) as int) as int % queue.array_size as int) as int)\n        )\n\n        )\n        )\n}\n\npredicate EnqueueIfGuard(s:LPlusState) {\n  (forall tid1 ::\n    && tid1 in s.s.threads \n    && s.s.threads[tid1].top.Armada_StackFrame_enqueue?\n    && (PCToInstructionCount_L(L.Armada_PC_enqueue_if_start) <=\n        PCToInstructionCount_L(s.s.threads[tid1].pc) <=\n        PCToInstructionCount_L(L.Armada_PC_enqueue_assume_end))\n    ==> s.s.threads[tid1].top.enqueue'read_index != s.s.threads[tid1].top.enqueue'modulo\n    )\n}\npredicate DequeueIfGuard(s:LPlusState) {\n  (forall tid2 ::\n    && tid2 in s.s.threads \n    && s.s.threads[tid2].top.Armada_StackFrame_dequeue?\n    && (PCToInstructionCount_L(L.Armada_PC_dequeue_if_start) <=\n        PCToInstructionCount_L(s.s.threads[tid2].pc) <=\n        PCToInstructionCount_L(L.Armada_PC_dequeue_assume_end))\n    ==> s.s.threads[tid2].top.dequeue'read_index != s.s.threads[tid2].top.dequeue'write_index\n    )\n}\n\npredicate EnqLocalSpaceImpliesGlobal(s:LPlusState)\n  requires MainInitInvariant(s)\n{\n    // EnqueueAssumeInvariant\n    // Depends on: DequeueAssumeInvariant,\n    // EnqInitModuloIsGlobalWriteIndexPlusOneModGlobalArraySize,\n    // DequeueIfGuard\n    (forall tid1 ::\n     && tid1 in s.s.threads \n     && s.s.threads[tid1].top.Armada_StackFrame_enqueue?\n     && (PCToInstructionCount_L(L.Armada_PC_enqueue_assume_start) <=\n         PCToInstructionCount_L(s.s.threads[tid1].pc) <=\n         PCToInstructionCount_L(L.Armada_PC_enqueue_assume_end))\n     ==> (s.s.threads[tid1].top.enqueue'read_index != s.s.threads[tid1].top.enqueue'modulo\n          ==> s.s.mem.globals.queue.read_index != Armada_CastTo_uint64((Armada_CastTo_uint64((s.s.mem.globals.queue.write_index as int + 1 as int) as int) as int % s.s.mem.globals.queue.array_size as int) as int))\n    )\n}\n\npredicate DeqLocalNonemptyImpliesGlobal(s:LPlusState) {\n    // DequeueAssumeInvariant\n    // Depends on: EnqueueAssumeInvariant, DeqInitReadIndexIsGlobalReadIndex,\n    // EnqueueIfGuard\n    (forall tid2 ::\n      && tid2 in s.s.threads \n      && s.s.threads[tid2].top.Armada_StackFrame_dequeue?\n      && (PCToInstructionCount_L(L.Armada_PC_dequeue_assume_start) <=\n          PCToInstructionCount_L(s.s.threads[tid2].pc) <=\n          PCToInstructionCount_L(L.Armada_PC_dequeue_assume_end))\n      ==> (s.s.threads[tid2].top.dequeue'read_index != s.s.threads[tid2].top.dequeue'write_index ==> s.s.mem.globals.queue.read_index != s.s.mem.globals.queue.write_index)\n        )\n}\n\npredicate AssumeInvariant_mem(s:LPlusState) {\n  && MainInitInvariant(s)\n  && EnqueueInitInvariant(s)\n  && EnqueueIfGuard(s)\n  && DequeueInitInvariant(s)\n  && DequeueIfGuard(s)\n  && DeqLocalNonemptyImpliesGlobal(s)\n  && EnqLocalSpaceImpliesGlobal(s)\n}\n\npredicate AssumeInvariant_ext(s:LPlusState) {\n  AssumeInvariant_mem(s)\n\n    && (forall tid, storeBufferEntry,\n        stop_reason, threads, mem, ghosts, addrs, config ::\n        storeBufferEntry in s.s.threads[tid].storeBuffer &&\n        AssumeInvariant_mem(LPlusState(L.Armada_TotalState(stop_reason, threads, mem, ghosts, addrs), config))\n        ==> AssumeInvariant_mem(LPlusState(L.Armada_TotalState(stop_reason, threads, L.Armada_ApplyStoreBufferEntry(mem, storeBufferEntry), ghosts, addrs), config))\n        )\n}\n\n  lemma {:verify false} lemma_HoldsForAllStoreBuffersImpliesInLocalView(s:LPlusState, f:LPlusState->bool, tid:Armada_ThreadHandle)\n    requires tid in s.s.threads\n    ensures var mem' := L.Armada_GetThreadLocalView(s.s, tid); var s' := LPlusState(L.Armada_TotalState(s.s.stop_reason, s.s.threads, mem', s.s.ghosts, s.s.addrs), s.config);\n        f(s')\n  {\n    \n  }\n\n  lemma {:verify false} lemma_GenericHoldsAcrossTauImpliesHoldsInLocalView(f:LPlusState->bool)\n    ensures (forall s:LPlusState, tid {:trigger L.Armada_GetThreadLocalView(s.s, tid)}:: tid in s.s.threads ==> \n    var mem' := L.Armada_GetThreadLocalView(s.s, tid);\n    var s' := LPlusState(L.Armada_TotalState(s.s.stop_reason, s.s.threads, mem', s.s.ghosts, s.s.addrs), s.config);\n    f(s'))\n  {\n    \n  }\n\n}\n"
  },
  {
    "path": "Test/qbss/auxiliary_helper.dfy",
    "content": "include \"QueueBSS_WithAbstractQueue.dfy\"\n  include \"../../Armada/util/collections/seqs.i.dfy\"\ninclude \"SharedStructs.dfy\"\n\nmodule auxiliary_helper {\n  import opened ArmadaCommonDefinitions = ArmadaCommonDefinitions\n  import opened util_collections_seqs_i = util_collections_seqs_i\n  import opened SharedStructs = SharedStructs\n\n  import L = QueueBSS_WithAbstractQueue\n  datatype WriteIndexSBEntry = WriteIndexSBEntry(position:int, value:uint64)\n\n  function DecrementPosition(w:WriteIndexSBEntry): WriteIndexSBEntry\n  {\n    w.(position := w.position - 1)\n  }\n\n  function TauUpdateWriteSequence(ws:seq<WriteIndexSBEntry>) : seq<WriteIndexSBEntry>\n  {\n    if ws == [] then\n      []\n    else\n      if ws[0].position == 0 then\n      MapSeqToSeq(ws[1..], DecrementPosition)\n      else\n        MapSeqToSeq(ws, DecrementPosition)\n  }\n\n  function StoreBufferUpdateWriteSequence(sb:seq<L.Armada_StoreBufferEntry>, sb':seq<L.Armada_StoreBufferEntry>, ws:seq<WriteIndexSBEntry>) :\n    seq<WriteIndexSBEntry>\n  {\n    if sb == sb' || sb' == [] then\n      ws\n    else if sb'[|sb'| - 1].loc == L.Armada_StoreBufferLocation_Unaddressable(L.Armada_GlobalStaticVar_queue, [Armada_FieldStruct(Armada_FieldType_QbssState'write_index)])\n      && sb'[|sb'| - 1].value.Armada_PrimitiveValue_uint64? then\n      ws + [WriteIndexSBEntry(|sb'| - 1, sb'[|sb'| - 1].value.n_uint64)]\n    else\n      ws\n  }\n\n}\n"
  },
  {
    "path": "Test/qbss/bv.dfy",
    "content": "//  mask == 2^x as \"mask+1 & (mask) ) == 0\n\nnewtype uint32 = n: int | 0 <= n < 4294967296\n\nmethod bitwise_and(x:uint32, y:uint32) returns (z:uint32)\n  ensures z == bit_and_uint32(x, y)\n\nfunction {:opaque} U(b:bv32) : uint32 { b as uint32 }\nfunction {:opaque} B(u:uint32) : bv32 { u as bv32 }\n\nfunction {:opaque} bit_lshift(b0:bv32, amt:nat) : bv32\n  requires amt < 32;\n{\n  b0 << amt\n}\n\nfunction {:opaque} bit_and(b0:bv32, b1:bv32) : bv32 \n  { b0 & b1 }\n\nfunction {:opaque} bit_mod(b0:bv32, b1:bv32) : bv32 \n  requires b1 != 0;\n  { b0 % b1 }\n\nfunction {:opaque} bit_mod_uint32(u0:uint32, u1:uint32) : uint32 \n  requires u1 != 0;\n{\n  reveal B();\n  U(bit_mod(B(u0), B(u1)))\n}\n\nfunction {:opaque} bit_and_uint32(x:uint32, y:uint32) : uint32\n{\n  U(bit_and(B(x), B(y)))\n}\n\nlemma {:axiom} bv_properties()\n  ensures forall u:uint32 :: U(B(u)) == u;\n  ensures forall b:bv32 :: B(U(b)) == b;\n  ensures forall x:uint32, m:uint32 :: \n                 m != 0 && B(m) != 0 ==> (x % m) == U(bit_mod(B(x), B(m)));\n\nlemma mask_equiv_bv(y:bv32)\n  ensures y % 512 == y & 511;\n{\n}\n\nlemma mask_equiv_bv_wrapped(y:bv32)\n  ensures bit_mod(y, 512) == bit_and(y, 511);\n{\n  reveal bit_mod();\n  reveal bit_and();\n}\n\nlemma mask_equiv_wrapped(x:uint32)\n  ensures bit_mod_uint32(x, 512) == bit_and_uint32(x, 511);\n{\n  assert B(512) == 512 by { reveal B(); }\n  assert B(511) == 511 by { reveal B(); }\n  calc {\n    bit_mod_uint32(x, 512);\n      { reveal bit_mod_uint32(); reveal B(); }\n    U(bit_mod(B(x), B(512)));\n      { mask_equiv_bv_wrapped(B(x)); assert bit_mod(B(x), 512) == bit_and(B(x), 511); }\n    U(bit_and(B(x), B(511)));\n      { reveal bit_and_uint32(); }\n    bit_and_uint32(x, 511);\n  }\n}\n\nlemma bit_mod_equiv(u0:uint32, u1:uint32)\n  requires u1 != 0;\n  ensures bit_mod_uint32(u0, u1) == u0 % u1;\n{\n  reveal bit_mod_uint32();\n  bv_properties();\n  assert B(u1) != 0 by { reveal B(); }\n  assert bit_mod(B(u0), B(u1)) >= 0;\n}\n\nlemma mask_equiv(x:uint32)\n  ensures x % 512 == bit_and_uint32(x, 511);\n{\n  calc {\n    x % 512;\n      { bit_mod_equiv(x, 512); }\n    bit_mod_uint32(x, 512);\n      { mask_equiv_wrapped(x); }\n    bit_and_uint32(x, 511);\n  }\n}\n\nlemma armada_mask_equiv(x:uint32)\n  ensures ((x as bv32) & (511 as bv32)) as uint32 == x % 512\n{\n  calc {\n    (x as bv32 & 511 as bv32) as uint32;\n      { reveal U(); }\n    U(x as bv32 & 511 as bv32); \n      { reveal B(); }\n    U(B(x) & B(511)); \n      { reveal bit_and(); }\n    U(bit_and(B(x), B(511))); \n      { reveal bit_and_uint32(); }\n    bit_and_uint32(x, 511);\n      { mask_equiv(x); }\n    x % 512;\n  }\n}\n\n\n"
  },
  {
    "path": "Test/qbss/queue.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs {\n    struct BSSQueueElement {\n        var key:uint64 /*Key*/;\n        var value:uint64 /*Value*/;    \n    }\n\n    struct QbssState {\n        var number_elements:uint64;\n        var mask:uint64;\n        var write_index:uint64;\n        var read_index:uint64;\n        var element_array:ptr<BSSQueueElement>; // need to make sure the array is 2^N = number_elements\n        var array_size:uint64;\n    }\n\n    datatype QbssElement = QbssElement(key:uint64, value:uint64)\n\n    datatype QbssLogEntry = EnqueueLogEntry(key:uint64, value:uint64) | DequeueLogEntry(key:uint64, value:uint64)   \n    ghost var log:seq<QbssLogEntry> := [];\n\n    refinement_constraint @\"\n       || (ls.stop_reason == hs.stop_reason && ls.ghosts.log == hs.ghosts.log)\n       || (ls.stop_reason.Armada_NotStopped? && ls.ghosts.log <= hs.ghosts.log)\n    \"\n}\n\nlevel QueueBSSNoTSO using SharedStructs {\n    noaddr var queue:QbssState;\n\n    method enqueue(k:uint64, v:uint64) {\n        noaddr var e:ptr<BSSQueueElement>;\n        noaddr var read_index:uint64;\n        noaddr var write_index:uint64;\n        noaddr var modulo:uint64;\n        noaddr var tmp_write_index:uint64;\n\n        write_index := queue.write_index;\n        tmp_write_index := write_index + 1;\n        modulo := tmp_write_index % queue.number_elements;\n        read_index := queue.read_index;\n        if(read_index != modulo) {\n            write_index := queue.write_index;\n\n            e := queue.element_array + write_index; \n            (*e).key ::= k;\n            (*e).value ::= v;\n            write_index := queue.write_index;\n\n\n            tmp_write_index := write_index + 1;\n            modulo := tmp_write_index % queue.number_elements;\n            somehow modifies log ensures log == old(log) + [EnqueueLogEntry(k,v)];\n            queue.write_index ::= modulo;\n        }\n    }\n\n    method dequeue(k:ptr<uint64>, v:ptr<uint64>) {\n        noaddr var e:ptr<BSSQueueElement>;\n        noaddr var read_index:uint64;\n        noaddr var write_index:uint64;\n        noaddr var modulo:uint64;\n        noaddr var tmp_read_index:uint64;\n        noaddr var tmp_int:uint64;\n\n        read_index := queue.read_index;\n        write_index := queue.write_index;\n        if(read_index != write_index) {\n            read_index := queue.read_index;\n            e := queue.element_array + read_index; \n\n            if(k != null) {\n            tmp_int := (*e).key;\n                *k ::= tmp_int;\n            }\n            if(v != null) {\n                tmp_int := (*e).value;\n                *v ::= tmp_int;\n            }\n\n            read_index := queue.read_index;\n            tmp_read_index := read_index + 1;\n            modulo := tmp_read_index % queue.number_elements;\n            somehow modifies log ensures log == old(log) + [DequeueLogEntry((*e).key,(*e).value)];\n            queue.read_index ::= modulo;\n        }\n    }\n\n    method main() {\n        noaddr var tid1:uint64 :=0;\n      noaddr var tid2:uint64 :=0;\n        noaddr var k:ptr<uint64> := null;\n        noaddr var v:ptr<uint64> := null;\n        noaddr var a:ptr<BSSQueueElement> := null;\n        k ::= malloc(uint64);\n        v ::= malloc(uint64);\n        queue.number_elements ::= 512;\n        queue.read_index ::= 0;\n        queue.write_index ::= 0;\n        a ::= calloc(BSSQueueElement, 512);\n        queue.element_array ::= a;\n        if (queue.element_array != null && k != null && v != null) {\n            tid1 ::= create_thread enqueue(*k,*v);\n            tid2 ::= create_thread dequeue(k,v);\n        }\n    }\n}\n\nlevel QueueBSSNoTSO_AbstractQueueIntroduced using SharedStructs {\n    noaddr var queue:QbssState;\n    ghost noaddr var q:seq<QbssElement> := [];\n\n    method enqueue(k:uint64, v:uint64) {\n        noaddr var e:ptr<BSSQueueElement>;\n        noaddr var read_index:uint64;\n        noaddr var write_index:uint64;\n        noaddr var modulo:uint64;\n        noaddr var tmp_write_index:uint64;\n\n        write_index := queue.write_index;\n        tmp_write_index := write_index + 1;\n        modulo := tmp_write_index % queue.number_elements;\n        read_index := queue.read_index;\n        if(read_index != modulo) {\n            write_index := queue.write_index;\n\n            e := queue.element_array + write_index; \n            (*e).key ::= k;\n            (*e).value ::= v;\n            write_index := queue.write_index;\n\n\n            tmp_write_index := write_index + 1;\n            modulo := tmp_write_index % queue.number_elements;\n            somehow modifies log ensures log == old(log) + [EnqueueLogEntry(k,v)];\n            atomic {\n        label start:\n                queue.write_index ::= modulo;\n        label end:\n                q ::= q + [QbssElement(k, v)];\n            }\n        }\n    }\n\n    method dequeue(k:ptr<uint64>, v:ptr<uint64>) {\n        noaddr var e:ptr<BSSQueueElement>;\n        noaddr var read_index:uint64;\n        noaddr var write_index:uint64;\n        noaddr var modulo:uint64;\n        noaddr var tmp_read_index:uint64;\n        noaddr var tmp_int:uint64;\n\n        read_index := queue.read_index;\n        write_index := queue.write_index;\n        if(read_index != write_index) {\n            read_index := queue.read_index;\n            e := queue.element_array + read_index; \n\n            if(k != null) {\n            tmp_int := (*e).key;\n                *k ::= tmp_int;\n            }\n            if(v != null) {\n                tmp_int := (*e).value;\n                *v ::= tmp_int;\n            }\n\n            read_index := queue.read_index;\n            tmp_read_index := read_index + 1;\n            modulo := tmp_read_index % queue.number_elements;\n            somehow modifies log ensures log == old(log) + [DequeueLogEntry((*e).key,(*e).value)];\n            atomic {\n                queue.read_index ::= modulo;\n                q ::= if q != [] then q[1..] else q;\n            }\n        }\n    }\n\n    method main() {\n        noaddr var tid1:uint64 :=0;\n      noaddr var tid2:uint64 :=0;\n        noaddr var k:ptr<uint64> := null;\n        noaddr var v:ptr<uint64> := null;\n        noaddr var a:ptr<BSSQueueElement> := null;\n        k ::= malloc(uint64);\n        v ::= malloc(uint64);\n        queue.number_elements ::= 512;\n        queue.read_index ::= 0;\n        queue.write_index ::= 0;\n        a ::= calloc(BSSQueueElement, 512);\n        queue.element_array ::= a;\n        if (queue.element_array != null && k != null && v != null) {\n            tid1 ::= create_thread enqueue(*k,*v);\n            tid2 ::= create_thread dequeue(k,v);\n        }\n    }\n}\n\nproof NoTSOIntroduceAbstractQueue {\n    refinement QueueBSSNoTSO QueueBSSNoTSO_AbstractQueueIntroduced\n    var_intro q\n}\n\nlevel QueueBSSNoTSO_AbstractQueueIntroduced_CombinedEnqueue using SharedStructs {\n    noaddr var queue:QbssState;\n    ghost noaddr var q:seq<QbssElement> := [];\n\n    method enqueue(k:uint64, v:uint64) {\n        noaddr var e:ptr<BSSQueueElement>;\n        noaddr var read_index:uint64;\n        noaddr var write_index:uint64;\n        noaddr var modulo:uint64;\n        noaddr var tmp_write_index:uint64;\n\n        write_index := queue.write_index;\n        tmp_write_index := write_index + 1;\n        modulo := tmp_write_index % queue.number_elements;\n        read_index := queue.read_index;\n        if(read_index != modulo) {\n            write_index := queue.write_index;\n\n            e := queue.element_array + write_index; \n            (*e).key ::= k;\n            (*e).value ::= v;\n            write_index := queue.write_index;\n\n\n            tmp_write_index := write_index + 1;\n            modulo := tmp_write_index % queue.number_elements;\n            somehow modifies log ensures log == old(log) + [EnqueueLogEntry(k,v)];\n        label single:\n            queue.write_index, q ::= modulo, q + [QbssElement(k, v)];\n        }\n    }\n\n    method dequeue(k:ptr<uint64>, v:ptr<uint64>) {\n        noaddr var e:ptr<BSSQueueElement>;\n        noaddr var read_index:uint64;\n        noaddr var write_index:uint64;\n        noaddr var modulo:uint64;\n        noaddr var tmp_read_index:uint64;\n        noaddr var tmp_int:uint64;\n\n        read_index := queue.read_index;\n        write_index := queue.write_index;\n        if(read_index != write_index) {\n            read_index := queue.read_index;\n            e := queue.element_array + read_index; \n\n            if(k != null) {\n            tmp_int := (*e).key;\n                *k ::= tmp_int;\n            }\n            if(v != null) {\n                tmp_int := (*e).value;\n                *v ::= tmp_int;\n            }\n\n            read_index := queue.read_index;\n            tmp_read_index := read_index + 1;\n            modulo := tmp_read_index % queue.number_elements;\n            somehow modifies log ensures log == old(log) + [DequeueLogEntry((*e).key,(*e).value)];\n            atomic {\n        label start:\n                queue.read_index ::= modulo;\n        label end:\n                q ::= if q != [] then q[1..] else q;\n            }\n        }\n    }\n\n    method main() {\n        noaddr var tid1:uint64 :=0;\n      noaddr var tid2:uint64 :=0;\n        noaddr var k:ptr<uint64> := null;\n        noaddr var v:ptr<uint64> := null;\n        noaddr var a:ptr<BSSQueueElement> := null;\n        k ::= malloc(uint64);\n        v ::= malloc(uint64);\n        queue.number_elements ::= 512;\n        queue.read_index ::= 0;\n        queue.write_index ::= 0;\n        a ::= calloc(BSSQueueElement, 512);\n        queue.element_array ::= a;\n        if (queue.element_array != null && k != null && v != null) {\n            tid1 ::= create_thread enqueue(*k,*v);\n            tid2 ::= create_thread dequeue(k,v);\n        }\n    }\n}\n\nproof CombineEnqueueAtomicAbstractQueue {\n    refinement QueueBSSNoTSO_AbstractQueueIntroduced QueueBSSNoTSO_AbstractQueueIntroduced_CombinedEnqueue\n    combining enqueue_start enqueue_end enqueue_single\n}\n\nlevel QueueBSSNoTSO_WithAbstractQueue using SharedStructs {\n    noaddr var queue:QbssState;\n    ghost noaddr var q:seq<QbssElement> := [];\n\n    method enqueue(k:uint64, v:uint64) {\n        noaddr var e:ptr<BSSQueueElement>;\n        noaddr var read_index:uint64;\n        noaddr var write_index:uint64;\n        noaddr var modulo:uint64;\n        noaddr var tmp_write_index:uint64;\n\n    label write_index_init:\n        write_index := queue.write_index;\n    label tmp_write_index_init:\n        tmp_write_index := write_index + 1;\n    label modulo_init:\n        modulo := tmp_write_index % queue.number_elements;\n    label read_index_init:\n        read_index := queue.read_index;\n        if(read_index != modulo) {\n    label inside_if_start:\n            write_index := queue.write_index;\n\n    label e_init:\n            e := queue.element_array + write_index; \n    label k_update:\n            (*e).key ::= k;\n    label v_update:\n            (*e).value ::= v;\n            write_index := queue.write_index;\n\n\n            tmp_write_index := write_index + 1;\n            modulo := tmp_write_index % queue.number_elements;\n            somehow modifies log ensures log == old(log) + [EnqueueLogEntry(k,v)];\n    label write_index_update:\n    // label abs_queue_update:\n            // q ::= q + [QbssElement(k, v)];\n            queue.write_index, q ::= modulo, q + [QbssElement(k, v)];\n        }\n    }\n\n    method dequeue(k:ptr<uint64>, v:ptr<uint64>) {\n        noaddr var e:ptr<BSSQueueElement>;\n        noaddr var read_index:uint64;\n        noaddr var write_index:uint64;\n        noaddr var modulo:uint64;\n        noaddr var tmp_read_index:uint64;\n        noaddr var tmp_int:uint64;\n\n    label read_index_init:\n        read_index := queue.read_index;\n    label write_index_init:\n        write_index := queue.write_index;\n        if(read_index != write_index) {\n    label inside_if_start:\n            read_index := queue.read_index;\n    label e_init:\n            e := queue.element_array + read_index; \n\n            if(k != null) {\n    label tmp_int_update_key:\n            tmp_int := (*e).key;\n    label k_update: \n                *k ::= tmp_int;\n            }\n            if(v != null) {\n    label tmp_int_update_value:\n                tmp_int := (*e).value;\n    label v_update: \n                *v ::= tmp_int;\n            }\n\n            read_index := queue.read_index;\n    label tmp_read_index_init:\n            tmp_read_index := read_index + 1;\n    label modulo_init:\n            modulo := tmp_read_index % queue.number_elements;\n            somehow modifies log ensures log == old(log) + [DequeueLogEntry((*e).key,(*e).value)];\n    label read_index_update:\n                queue.read_index, q ::= modulo , if q != [] then q[1..] else q;\n        }\n    }\n\n    method main() {\n        noaddr var tid1:uint64 :=0;\n        noaddr var tid2:uint64 :=0;\n        noaddr var k:ptr<uint64> := null;\n        noaddr var v:ptr<uint64> := null;\n        noaddr var a:ptr<BSSQueueElement> := null;\n    label k_alloc:\n        k ::= malloc(uint64);\n    label v_alloc:\n        v ::= malloc(uint64);\n    label number_elements_init:\n        queue.number_elements ::= 512;\n    label read_index_init:\n        queue.read_index ::= 0;\n    label write_index_init:\n        queue.write_index ::= 0;\n    label array_calloc:\n        a ::= calloc(BSSQueueElement, 512);\n    label element_array_alloc:\n        queue.element_array ::= a;\n    label before_if:\n        if (queue.element_array != null && k != null && v != null) {\n    label BeforeEnqueueCreate: \n            tid1 ::= create_thread enqueue(*k,*v);\n    label BeforeDequeueCreate: \n            tid2 ::= create_thread dequeue(k,v);\n        }\n    }\n}\n\nproof CombineDequeueAtomicAbstractQueue {\n    refinement QueueBSSNoTSO_AbstractQueueIntroduced_CombinedEnqueue QueueBSSNoTSO_WithAbstractQueue\n    combining dequeue_start dequeue_end dequeue_read_index_update\n}\n\nlevel QueueBSSNoTSO_AbstractLogs using SharedStructs {\n    noaddr var queue:QbssState;\n    ghost noaddr var q:seq<QbssElement> := [];\n\n    method enqueue(k:uint64, v:uint64) {\n        noaddr var e:ptr<BSSQueueElement>;\n        noaddr var read_index:uint64;\n        noaddr var write_index:uint64;\n        noaddr var modulo:uint64;\n        noaddr var tmp_write_index:uint64;\n\n        write_index := *;\n        tmp_write_index := *;\n\n        assume queue.number_elements > 0;\n        modulo := tmp_write_index % queue.number_elements;\n        read_index := *;\n        if(*) {\n            write_index := *;\n            assume queue.element_array + write_index == queue.element_array + write_index; \n            e := queue.element_array + write_index; \n\n            assume allocated(e);\n            (*e).key ::= *;\n            assume allocated(e);\n            (*e).value ::= *;\n            write_index := *;\n\n            tmp_write_index := *;\n            assume queue.number_elements > 0;\n            modulo := tmp_write_index % queue.number_elements;\n            somehow modifies log ensures log == old(log) + [EnqueueLogEntry(k,v)];\n            queue.write_index, q ::= *, q + [QbssElement(k, v)];\n        }\n    }\n\n    method dequeue(k:ptr<uint64>, v:ptr<uint64>) {\n        noaddr var e:ptr<BSSQueueElement>;\n        noaddr var read_index:uint64;\n        noaddr var write_index:uint64;\n        noaddr var modulo:uint64;\n        noaddr var tmp_read_index:uint64;\n        noaddr var tmp_int:uint64;\n\n        read_index := *;\n        write_index := *;\n        if(*) {\n            read_index := *;\n            assume queue.element_array + read_index == queue.element_array + read_index;\n            e := queue.element_array + read_index; \n\n            if(k != null) {\n                assume allocated(e);\n                tmp_int := (*e).key;\n                assume q != [];\n                *k ::= q[0].key;\n            }\n            if(v != null) {\n                assume allocated(e);\n                tmp_int := (*e).value;\n                assume q != [];\n                *v ::= q[0].value;\n            }\n\n            read_index := *;\n            tmp_read_index := *;\n            assume queue.number_elements > 0;\n            modulo := tmp_read_index % queue.number_elements;\n            assume q != [];\n            somehow modifies log ensures log == old(log) + [DequeueLogEntry(q[0].key, q[0].value)];\n            assume q != [];\n            queue.read_index, q ::= * , q[1..];\n        }\n    }\n\n    method main() {\n        noaddr var tid1:uint64 :=0;\n      noaddr var tid2:uint64 :=0;\n        noaddr var k:ptr<uint64> := null;\n        noaddr var v:ptr<uint64> := null;\n        noaddr var a:ptr<BSSQueueElement> := null;\n        k ::= malloc(uint64);\n        v ::= malloc(uint64);\n        queue.number_elements ::= *;\n        queue.read_index ::= *;\n        queue.write_index ::= *;\n        a ::= calloc(BSSQueueElement, 512);\n        queue.element_array ::= a;\n        if (*) {\n            assume k != null && v != null;\n            tid1 ::= create_thread enqueue(*k,*v);\n            tid2 ::= create_thread dequeue(k,v);\n        }\n    }\n}\n\nproof NoTSOUseAbstractQueueForLog {\n    refinement QueueBSSNoTSO_WithAbstractQueue QueueBSSNoTSO_AbstractLogs\n    starweakening\n\n    include_file \"queue_tsobypassing_abstractloginvariant.dfy\" which_includes \"NoTSOUseAbstractQueueForLog/specs.dfy\"\n    import_module queue_tsobypassing_abstractloginvariant which_imports ArmadaModule_specs\n\n    include_file \"../../Armada/util/math/mod_auto.i.dfy\"\n    import_module Math__mod_auto_i\n\n    inductive_invariant WeakeningInvariant \"WeakeningInvariant_ext(s)\" depends_on AddressableInvariant\n\n    use_address_invariant\n\n    extra lemma_InvariantPredicateImpliedByInit_WeakeningInvariant @\"\n      var h := s.s.mem.heap;\n      lemma_NoSetIntersectionImpliesNoCommonElements(h.valid, h.freed);\n    \"\n\n    extra lemma_InvariantPredicateMaintainedByPath_WeakeningInvariant_From_main_BeforeDequeueCreate_To_main_End @\"\n      assert s'.s.mem == s.s.mem;\n      assert WeakeningInvariant_ext(s');\n    \"\n\n    extra lemma_InvariantPredicateMaintainedByPath_WeakeningInvariant_From_enqueue_write_index_update_To_enqueue_End @\"\n      lemma_mod_auto(s.s.mem.globals.queue.number_elements as int);\n      assert MemorySafetyElementArray(s'.s.mem);\n      assert WeakeningInvariant_ext(s');\n    \"\n\n    extra lemma_InvariantPredicateMaintainedByPath_WeakeningInvariant_From_enqueue_End_to_exit @\"\n      assert MemorySafetyElementArray(s'.s.mem);\n      assert WeakeningInvariant_ext(s');\n    \"\n\n    extra lemma_InvariantPredicateMaintainedByPath_WeakeningInvariant_From_dequeue_read_index_update_To_dequeue_End @\"\n      lemma_mod_auto(s.s.mem.globals.queue.number_elements as int);\n      assert MemorySafetyElementArray(s'.s.mem);\n      assert WeakeningInvariant_ext(s');\n    \"\n\n    extra lemma_InvariantPredicateMaintainedByPath_WeakeningInvariant_From_dequeue_2_T_To_dequeue_inside_if_start @\"\n      lemma_mod_auto(s.s.mem.globals.queue.number_elements as int);\n      assert WeakeningInvariant_ext(s');\n    \"\n\n    extra lemma_InvariantPredicateMaintainedByPath_WeakeningInvariant_From_dequeue_e_init_To_dequeue_5 @\"\n      lemma_mod_auto(s.s.mem.globals.queue.number_elements as int);\n      assert WeakeningInvariant_ext(s');\n    \"\n\n    extra lemma_InvariantPredicateMaintainedByPath_WeakeningInvariant_From_enqueue_k_update_To_enqueue_v_update @\"\n      lemma_mod_auto(s.s.mem.globals.queue.number_elements as int);\n      assert MemorySafetyElementArray(s'.s.mem);\n      assert WeakeningInvariant_ext(s');\n    \"\n\n    extra lemma_InvariantPredicateMaintainedByPath_WeakeningInvariant_From_enqueue_v_update_To_enqueue_9 @\"\n      lemma_mod_auto(s.s.mem.globals.queue.number_elements as int);\n      assert MemorySafetyElementArray(s'.s.mem);\n      assert WeakeningInvariant_ext(s');\n    \"\n\n    extra lemma_InvariantPredicateMaintainedByPath_WeakeningInvariant_From_dequeue_k_update_To_dequeue_8 @\"\n      lemma_mod_auto(s.s.mem.globals.queue.number_elements as int);\n      assert MemorySafetyElementArray(s'.s.mem);\n      assert WeakeningInvariant_ext(s');\n    \"\n\n    extra lemma_InvariantPredicateMaintainedByPath_WeakeningInvariant_From_dequeue_v_update_To_dequeue_11 @\"\n      lemma_mod_auto(s.s.mem.globals.queue.number_elements as int);\n      assert MemorySafetyElementArray(s'.s.mem);\n      assert WeakeningInvariant_ext(s');\n    \"\n\n    extra lemma_InvariantPredicateMaintainedByPath_WeakeningInvariant_From_dequeue_End_to_exit @\"\n      lemma_mod_auto(s.s.mem.globals.queue.number_elements as int);\n      assert MemorySafetyElementArray(s'.s.mem);\n      assert WeakeningInvariant_ext(s');\n    \"\n\n    extra lemma_InvariantPredicateMaintainedByPath_WeakeningInvariant_From_main_array_calloc_T_To_main_element_array_alloc @\"\n      assert forall tid1 :: tid1 in s'.s.threads ==> !s'.s.threads[tid].top.Armada_StackFrame_dequeue?;\n      assert forall tid1 :: tid1 in s'.s.threads ==> !s'.s.threads[tid].top.Armada_StackFrame_enqueue?;\n      assert MemorySafetyElementArrayCustomPointer(s'.s.threads[tid].top.main.a, s'.s.mem);\n      assert WeakeningInvariant_ext(s');\n    \"\n}\n\nlevel QueueBSSNoTSO_AbstractLogsStarweakened using SharedStructs {\n    noaddr var queue:QbssState;\n    ghost noaddr var q:seq<QbssElement> := [];\n\n    method enqueue(k:uint64, v:uint64) {\n        noaddr var e:ptr<BSSQueueElement>;\n        noaddr var read_index:uint64;\n        noaddr var write_index:uint64;\n        noaddr var modulo:uint64;\n        noaddr var tmp_write_index:uint64;\n\n        write_index := *;\n        tmp_write_index := *;\n\n        modulo := *;\n        read_index := *;\n        if(*) {\n            write_index := *;\n            e := *;\n\n            assume allocated(e);\n            (*e).key ::= *;\n            assume allocated(e);\n            (*e).value ::= *;\n            write_index := *;\n\n            tmp_write_index := *;\n            modulo := *;\n            somehow modifies log ensures log == old(log) + [EnqueueLogEntry(k,v)];\n            queue.write_index, q ::= *, q + [QbssElement(k, v)];\n        }\n    }\n\n    method dequeue(k:ptr<uint64>, v:ptr<uint64>) {\n        noaddr var e:ptr<BSSQueueElement>;\n        noaddr var read_index:uint64;\n        noaddr var write_index:uint64;\n        noaddr var modulo:uint64;\n        noaddr var tmp_read_index:uint64;\n        noaddr var tmp_int:uint64;\n\n        read_index := *;\n        write_index := *;\n        if(*) {\n            read_index := *;\n            e := *;\n\n            if(k != null) {\n                tmp_int := *;\n                assume q != [];\n                *k ::= q[0].key;\n            }\n            if(v != null) {\n                tmp_int := *;\n                assume q != [];\n                *v ::= q[0].value;\n            }\n\n            read_index := *;\n            tmp_read_index := *;\n            modulo := *;\n            assume q != [];\n            somehow modifies log ensures log == old(log) + [DequeueLogEntry(q[0].key, q[0].value)];\n            assume q != [];\n            queue.read_index, q ::= * , q[1..];\n        }\n    }\n\n    method main() {\n        noaddr var tid1:uint64 := 0;\n      noaddr var tid2:uint64 := 0;\n        noaddr var k:ptr<uint64> := null;\n        noaddr var v:ptr<uint64> := null;\n        noaddr var a:ptr<BSSQueueElement> := null;\n        k ::= malloc(uint64);\n        v ::= malloc(uint64);\n        queue.number_elements ::= *;\n        queue.read_index ::= *;\n        queue.write_index ::= *;\n        a ::= calloc(BSSQueueElement, 512);\n        queue.element_array ::= a;\n        if (*) {\n            assume k != null && v != null;\n            tid1 ::= create_thread enqueue(*k,*v);\n            tid2 ::= create_thread dequeue(k,v);\n        }\n    }\n}\n\nproof NoTSOStarWeaken {\n  refinement QueueBSSNoTSO_AbstractLogs QueueBSSNoTSO_AbstractLogsStarweakened\n  starweakening\n}\n\nlevel QueueBSSNoTSO_HiddenEnqLocals using SharedStructs {\n    noaddr var queue:QbssState;\n    ghost noaddr var q:seq<QbssElement> := [];\n\n    method enqueue(k:uint64, v:uint64) {\n        noaddr var e:ptr<BSSQueueElement>;\n        if(*) {\n            e := *;\n            assume allocated(e);\n            (*e).key ::= *;\n            assume allocated(e);\n            (*e).value ::= *;\n\n            somehow modifies log ensures log == old(log) + [EnqueueLogEntry(k,v)];\n            queue.write_index, q ::= *, q + [QbssElement(k, v)];\n        }\n    }\n\n    method dequeue(k:ptr<uint64>, v:ptr<uint64>) {\n        noaddr var e:ptr<BSSQueueElement>;\n        noaddr var read_index:uint64;\n        noaddr var write_index:uint64;\n        noaddr var modulo:uint64;\n        noaddr var tmp_read_index:uint64;\n        noaddr var tmp_int:uint64;\n\n        read_index := *;\n        write_index := *;\n        if(*) {\n            read_index := *;\n            e := *;\n\n            if(k != null) {\n                tmp_int := *;\n                assume q != [];\n                *k ::= q[0].key;\n            }\n            if(v != null) {\n                tmp_int := *;\n                assume q != [];\n                *v ::= q[0].value;\n            }\n\n            read_index := *;\n            tmp_read_index := *;\n            modulo := *;\n            assume q != [];\n            somehow modifies log ensures log == old(log) + [DequeueLogEntry(q[0].key, q[0].value)];\n            assume q != [];\n            queue.read_index, q ::= * , q[1..];\n        }\n    }\n\n    method main() {\n        noaddr var tid1:uint64 :=0;\n      noaddr var tid2:uint64 :=0;\n        noaddr var k:ptr<uint64> := null;\n        noaddr var v:ptr<uint64> := null;\n        noaddr var a:ptr<BSSQueueElement> := null;\n        k ::= malloc(uint64);\n        v ::= malloc(uint64);\n        queue.number_elements ::= *;\n        queue.read_index ::= *;\n        queue.write_index ::= *;\n        a ::= calloc(BSSQueueElement, 512);\n        queue.element_array ::= a;\n        if (*) {\n            assume k != null && v != null;\n            tid1 ::= create_thread enqueue(*k,*v);\n            tid2 ::= create_thread dequeue(k,v);\n        }\n    }\n}\n\nproof HideEnqueueLocals {\n    refinement QueueBSSNoTSO_AbstractLogsStarweakened QueueBSSNoTSO_HiddenEnqLocals\n\n    stack_var_hiding enqueue read_index, write_index, modulo, tmp_write_index\n}\n\nlevel QueueBSSNoTSO_HiddenEnqDeqLocals using SharedStructs {\n    noaddr var queue:QbssState;\n    ghost noaddr var q:seq<QbssElement> := [];\n\n    method enqueue(k:uint64, v:uint64) {\n        noaddr var e:ptr<BSSQueueElement>;\n        if(*) {\n            e := *;\n            assume allocated(e);\n            (*e).key ::= *;\n            assume allocated(e);\n            (*e).value ::= *;\n\n            somehow modifies log ensures log == old(log) + [EnqueueLogEntry(k,v)];\n            queue.write_index, q ::= *, q + [QbssElement(k, v)];\n        }\n    }\n\n    method dequeue(k:ptr<uint64>, v:ptr<uint64>) {\n        if(*) {\n            if(k != null) {\n                assume q != [];\n                *k ::= q[0].key;\n            }\n            if(v != null) {\n                assume q != [];\n                *v ::= q[0].value;\n            }\n\n            assume q != [];\n            somehow modifies log ensures log == old(log) + [DequeueLogEntry(q[0].key, q[0].value)];\n            assume q != [];\n            queue.read_index, q ::= * , q[1..];\n        }\n    }\n\n    method main() {\n        noaddr var tid1:uint64 :=0;\n      noaddr var tid2:uint64 :=0;\n        noaddr var k:ptr<uint64> := null;\n        noaddr var v:ptr<uint64> := null;\n        noaddr var a:ptr<BSSQueueElement> := null;\n        k ::= malloc(uint64);\n        v ::= malloc(uint64);\n        queue.number_elements ::= *;\n        queue.read_index ::= *;\n        queue.write_index ::= *;\n        a ::= calloc(BSSQueueElement, 512);\n        queue.element_array ::= a;\n        if (*) {\n            assume k != null && v != null;\n            tid1 ::= create_thread enqueue(*k,*v);\n            tid2 ::= create_thread dequeue(k,v);\n        }\n    }\n}\n\nproof HideDequeueLocals {\n    refinement QueueBSSNoTSO_HiddenEnqLocals QueueBSSNoTSO_HiddenEnqDeqLocals\n\n    stack_var_hiding dequeue e, read_index, write_index, modulo, tmp_read_index, tmp_int\n}\n\nlevel QueueBSSNoTSO_HiddenImpl using SharedStructs {\n    ghost noaddr var q:seq<QbssElement> := [];\n\n    method enqueue(k:uint64, v:uint64) {\n        noaddr var e:ptr<BSSQueueElement>;\n        if(*) {\n            e := *;\n            assume allocated(e);\n            (*e).key ::= *;\n            assume allocated(e);\n            (*e).value ::= *;\n\n            somehow modifies log ensures log == old(log) + [EnqueueLogEntry(k,v)];\n            q ::= q + [QbssElement(k, v)];\n        }\n    }\n\n    method dequeue(k:ptr<uint64>, v:ptr<uint64>) {\n        if(*) {\n            if(k != null) {\n                assume q != [];\n                *k ::= q[0].key;\n            }\n            if(v != null) {\n                assume q != [];\n                *v ::= q[0].value;\n            }\n\n            assume q != [];\n            somehow modifies log ensures log == old(log) + [DequeueLogEntry(q[0].key, q[0].value)];\n            assume q != [];\n            q ::= q[1..];\n        }\n    }\n\n    method main() {\n        noaddr var tid1:uint64 :=0;\n        noaddr var tid2:uint64 :=0;\n        noaddr var k:ptr<uint64> := null;\n        noaddr var v:ptr<uint64> := null;\n        noaddr var a:ptr<BSSQueueElement> := null;\n        k ::= malloc(uint64);\n        v ::= malloc(uint64);\n        a ::= calloc(BSSQueueElement, 512);\n        if (*) {\n            assume k != null && v != null;\n            tid1 ::= create_thread enqueue(*k,*v);\n            tid2 ::= create_thread dequeue(k,v);\n        }\n    }\n}\n\nproof HideGlobal {\n    refinement QueueBSSNoTSO_HiddenEnqDeqLocals QueueBSSNoTSO_HiddenImpl\n    var_hiding queue\n}\n"
  },
  {
    "path": "Test/qbss/queue_abstractloginvariant.dfy",
    "content": "include \"QueueBSS_WithAbstractQueue.dfy\"\ninclude \"UseAbstractQueueForLog/specs.dfy\"\ninclude \"SharedStructs.dfy\"\ninclude \"auxiliary_helper.dfy\"\n\nmodule queue_abstractloginvariant {\nimport opened ArmadaCommonDefinitions = ArmadaCommonDefinitions\nimport opened QueueBSS_WithAbstractQueue = QueueBSS_WithAbstractQueue\nimport opened ArmadaModule_specs = ArmadaModule_specs\nimport opened SharedStructs = SharedStructs\nimport opened auxiliary_helper = auxiliary_helper\n\n// This is the target invariant.\n// (a) element_array[d!r .. w] == abstract_queue[..(w - d!r) % array_size ]\n\npredicate {:verify false} WeakHeapInvariant(h: Armada_Heap)\n{\n    && h.valid * h.freed == {}\n    && 0 in h.freed\n    && !(0 in h.valid)\n    && Armada_TreeProperties(h.tree)\n    && (forall p {:trigger Armada_TriggerPointer(p)} :: \n        Armada_TriggerPointer(p) &&\n        p in h.tree &&\n        h.tree[p].ty.Armada_ObjectType_primitive? ==>\n          p in h.values &&\n          Armada_PrimitiveValueMatchesType(h.values[p], h.tree[p].ty.pty))\n}\n\n// This ensures that queue.element_array is an array with the appropriate number\n// of elements and should allow GetQbssElement to be well-defined\npredicate {:verify false} MemorySafetyElementArray(locv:Armada_SharedMemory)\n  requires WeakHeapInvariant(locv.heap)\n{\n  var e := locv.globals.queue.element_array;\n    && e in locv.heap.tree\n    && locv.heap.tree[e].field_of_parent == Armada_FieldArrayIndex(0)\n    && locv.globals.queue.number_elements as int > 0\n    && var a := locv.heap.tree[e].parent; Armada_ValidPointerToStructSizedArray_BSSQueueElement(locv.heap, a, locv.globals.queue.number_elements as int)\n}\n\nfunction {:verify false} GetQbssElement(locv:Armada_SharedMemory, j:int) : QbssElement\n  requires WeakHeapInvariant(locv.heap)\n  requires MemorySafetyElementArray(locv)\n  requires 0 <= j < locv.globals.queue.number_elements as int\n{\n  var qbsse := Armada_DereferencePointerToStruct_BSSQueueElement(locv.heap,\n    GetPointerToQbssElement(locv, j)\n    );\n    QbssElement(qbsse.key, qbsse.value)\n}\n\nfunction {:verify false} GetPointerToQbssElement(locv:Armada_SharedMemory, j:int) : Armada_Pointer\n  requires WeakHeapInvariant(locv.heap)\n  requires MemorySafetyElementArray(locv)\n  requires 0 <= j < locv.globals.queue.number_elements as int\n{\n    locv.heap.tree[locv.heap.tree[locv.globals.queue.element_array].parent].children[Armada_FieldArrayIndex(locv.heap.tree[locv.globals.queue.element_array].field_of_parent.i + j)]\n}\n\nfunction {:verify false} GetPointerToQbssElementKey(locv:Armada_SharedMemory, j:int) : Armada_Pointer\n  requires WeakHeapInvariant(locv.heap)\n  requires MemorySafetyElementArray(locv)\n  requires 0 <= j < locv.globals.queue.number_elements as int\n{\n  locv.heap.tree[GetPointerToQbssElement(locv, j)].children[Armada_FieldStruct(Armada_FieldType_BSSQueueElement'key)]\n}\n\nfunction {:verify false} GetPointerToQbssElementValue(locv:Armada_SharedMemory, j:int) : Armada_Pointer\n  requires WeakHeapInvariant(locv.heap)\n  requires MemorySafetyElementArray(locv)\n  requires 0 <= j < locv.globals.queue.number_elements as int\n{\n  locv.heap.tree[GetPointerToQbssElement(locv, j)].children[Armada_FieldStruct(Armada_FieldType_BSSQueueElement'value)]\n}\n\npredicate StoreBufferDoesNotConcernQbssElementKey(buf: seq<Armada_StoreBufferEntry>, locv:Armada_SharedMemory, j:int)\n  requires WeakHeapInvariant(locv.heap)\n  requires MemorySafetyElementArray(locv)\n  requires 0 <= j < locv.globals.queue.number_elements as int\n{\n  && StoreBufferDoesNotConcernAddress(buf, GetPointerToQbssElementKey(locv, j))\n}\n\npredicate StoreBufferDoesNotConcernQbssElementValue(buf: seq<Armada_StoreBufferEntry>, locv:Armada_SharedMemory, j:int)\n  requires WeakHeapInvariant(locv.heap)\n  requires MemorySafetyElementArray(locv)\n  requires 0 <= j < locv.globals.queue.number_elements as int\n{\n  && StoreBufferDoesNotConcernAddress(buf, GetPointerToQbssElementValue(locv, j))\n}\n\npredicate StoreBufferDoesNotConcernAddress(buf: seq<Armada_StoreBufferEntry>, p:Armada_Pointer)\n{\n  forall entry ::\n    entry in buf ==>\n    entry.loc != Armada_StoreBufferLocation_Addressable(p)\n}\n\npredicate StoreBufferDoesNotConcernQbssElement(buf: seq<Armada_StoreBufferEntry>, locv:Armada_SharedMemory, j:int)\n  requires WeakHeapInvariant(locv.heap)\n  requires MemorySafetyElementArray(locv)\n  requires 0 <= j < locv.globals.queue.number_elements as int\n{\n  && StoreBufferDoesNotConcernQbssElementKey(buf, locv, j)\n    && StoreBufferDoesNotConcernQbssElementValue(buf, locv, j)\n}\n\nlemma lemma_IfStoreBufferDoesNotConcernAddressThenViewMatches(mem:L.Armada_SharedMemory, buf:seq<L.Armada_StoreBufferEntry>, mem':L.Armada_SharedMemory, p:Armada_Pointer)\n  requires StoreBufferDoesNotConcernAddress(buf, p)\n  requires p in mem.heap.values\n  requires mem' == L.Armada_ApplyStoreBuffer(mem, buf)\n  ensures p in mem'.heap.values\n  ensures (mem.heap.values[p] == mem'.heap.values[p])\n  decreases |buf|\n{\n    if |buf| > 0 {\n      var mem_next := L.Armada_ApplyStoreBufferEntry(mem, buf[0]);\n      assert mem.heap.values[p] == mem_next.heap.values[p];\n      var mem_next' := L.Armada_ApplyStoreBuffer(mem_next, buf[1..]);\n      lemma_IfStoreBufferDoesNotConcernAddressThenViewMatches(mem_next, buf[1..], mem_next', p);\n    }\n}\n\nlemma lemma_IfStoreBufferDoesNotConcernAddressThenViewMatchesAlways(p:Armada_Pointer)\n  ensures forall mem: L.Armada_SharedMemory, buf: seq<L.Armada_StoreBufferEntry> :: StoreBufferDoesNotConcernAddress(buf, p) && p in mem.heap.values ==> p in L.Armada_ApplyStoreBuffer(mem, buf).heap.values && L.Armada_ApplyStoreBuffer(mem, buf).heap.values[p] == mem.heap.values[p]\n{\n  forall mem: L.Armada_SharedMemory, buf: seq<L.Armada_StoreBufferEntry> |\n    StoreBufferDoesNotConcernAddress(buf, p) && p in mem.heap.values\n    ensures p in L.Armada_ApplyStoreBuffer(mem, buf).heap.values && L.Armada_ApplyStoreBuffer(mem, buf).heap.values[p] == mem.heap.values[p]\n    {\n      lemma_IfStoreBufferDoesNotConcernAddressThenViewMatches(mem, buf, L.Armada_ApplyStoreBuffer(mem,buf), p);\n    }\n}\n\npredicate Queue_TriggerIndex(i:int)\n{\n  true\n}\n\npredicate DequeueDoesNotConcernQbssElement(s:LPlusState)\n{\n  forall tid2 :: tid2 in s.s.threads\n    && s.s.threads[tid2].top.Armada_StackFrame_dequeue?\n    ==>\n    && WeakHeapInvariant(s.s.mem.heap)\n    && MemorySafetyElementArray(s.s.mem)\n    && (forall j {:trigger Queue_TriggerIndex(j)} :: 0 <= j < s.s.mem.globals.queue.number_elements as int && Queue_TriggerIndex(j) ==> StoreBufferDoesNotConcernQbssElement(s.s.threads[tid2].storeBuffer, s.s.mem, j))\n}\n\n// We will need to verify that this holds across any instruction that performs a\n// store-buffer update and across a tau; the tau situation seems more difficult\npredicate {:verify false} ElementArrayLocalViewMatchesGlobal(s:LPlusState, tid:Armada_ThreadHandle)\n  requires tid in s.s.threads\n{\n  var locv := Armada_GetThreadLocalView(s.s, tid);\n  && WeakHeapInvariant(s.s.mem.heap)\n    && WeakHeapInvariant(locv.heap)\n    && locv.globals.queue.number_elements == s.s.mem.globals.queue.number_elements\n    && MemorySafetyElementArray(s.s.mem)\n    && MemorySafetyElementArray(locv)\n    && s.s.mem.globals.queue.element_array == locv.globals.queue.element_array\n    && (forall i:int {:trigger Queue_TriggerIndex(i)}:: 0 <= i < s.s.mem.globals.queue.number_elements as int\n        && Queue_TriggerIndex(i)\n        ==>\n        && GetPointerToQbssElement(locv, i) == GetPointerToQbssElement(s.s.mem, i)\n        && GetQbssElement(locv, i) == GetQbssElement(s.s.mem, i)\n       )\n}\n\n// This is the invariant we actually want; in order to support it, I need to \npredicate {:verify false} ElementArrayDeqLocalMatchesGlobal(s:LPlusState) {\n  forall tid2 :: tid2 in s.s.threads\n    && s.s.threads[tid2].top.Armada_StackFrame_dequeue?\n    ==> ElementArrayLocalViewMatchesGlobal(s, tid2)\n}\n\npredicate {:verify false} LocalViewOfNumberElementsAlwaysMatchsGlobalInEnqOrDeq(s:LPlusState)\n{\n  && (forall tid2 :: tid2 in s.s.threads\n    && s.s.threads[tid2].top.Armada_StackFrame_dequeue?\n    ==> \n    var locv := Armada_GetThreadLocalView(s.s, tid2);\n    locv.globals.queue.number_elements == s.s.mem.globals.queue.number_elements)\n\n\n  && (forall tid1 :: tid1 in s.s.threads\n    && s.s.threads[tid1].top.Armada_StackFrame_enqueue?\n    ==> \n    var locv := Armada_GetThreadLocalView(s.s, tid1);\n    locv.globals.queue.number_elements == s.s.mem.globals.queue.number_elements)\n}\n\n// In order to demonstrate this, we will simply require k and v to be roots in\n// the tree\npredicate {:verify false} DequeueInputPointersDoNotAliasElementArray(s:LPlusState)\n{\n  forall tid2 :: tid2 in s.s.threads\n    && s.s.threads[tid2].top.Armada_StackFrame_dequeue?\n    ==>\n    var k := s.s.threads[tid2].top.dequeue.k;\n    var v := s.s.threads[tid2].top.dequeue.v;\n    && k in s.s.mem.heap.tree && s.s.mem.heap.tree[k].field_of_parent.Armada_FieldNone?\n    && v in s.s.mem.heap.tree && s.s.mem.heap.tree[v].field_of_parent.Armada_FieldNone?\n\n}\n\npredicate {:verify false} TmpIntProperties(s:LPlusState)\n  requires ElementArrayDeqLocalMatchesGlobal(s)\n  requires LocalIndicesOfDequeueAlwaysWithinBounds(s)\n{\n    && (forall tid2 :: tid2 in s.s.threads\n        && s.s.threads[tid2].top.Armada_StackFrame_dequeue?\n        && PCToInstructionCount_L(Armada_PC_dequeue_tmp_int_update_key)\n           < PCToInstructionCount_L(s.s.threads[tid2].pc) <=\n           PCToInstructionCount_L(Armada_PC_dequeue_k_update)\n           ==>\n            var f := s.s.threads[tid2].top;\n            var locv := Armada_GetThreadLocalView(s.s, tid2);\n            &&  f.dequeue.tmp_int == GetQbssElement(locv, f.dequeue.read_index as int % s.s.mem.globals.queue.number_elements as int).key\n       )\n\n    && (forall tid2 :: tid2 in s.s.threads\n        && s.s.threads[tid2].top.Armada_StackFrame_dequeue?\n        && PCToInstructionCount_L(Armada_PC_dequeue_tmp_int_update_value)\n           < PCToInstructionCount_L(s.s.threads[tid2].pc) <=\n           PCToInstructionCount_L(Armada_PC_dequeue_v_update)\n           ==>\n            var f := s.s.threads[tid2].top;\n            var locv := Armada_GetThreadLocalView(s.s, tid2);\n            &&  f.dequeue.tmp_int == GetQbssElement(locv, f.dequeue.read_index as int % s.s.mem.globals.queue.number_elements as int).value\n       )\n}\n\npredicate {:verify false} LocalViewOfEltArrayAddressAlwaysMatchesGlobal(s:LPlusState)\n{\n  forall tid :: tid in s.s.threads\n    ==>\n    var locv := Armada_GetThreadLocalView(s.s, tid);\n    s.s.mem.globals.queue.element_array == locv.globals.queue.element_array\n}\n\n// Relies on:\n// LocalViewOfEltArrayAddressAlwaysMatchesGlobal\npredicate {:verify false} EnqueueEIsEltArrayPlusWriteIndex(s:LPlusState)\n  requires WeakHeapInvariant(s.s.mem.heap)\n  requires MemorySafetyElementArrayIfInEnqueue(s)\n  requires IndicesAlwaysWithinBounds(s)\n{\n    && (forall tid1 :: tid1 in s.s.threads\n        && s.s.threads[tid1].top.Armada_StackFrame_enqueue?\n        && PCToInstructionCount_L(Armada_PC_enqueue_e_init)\n           < PCToInstructionCount_L(s.s.threads[tid1].pc) <=\n           PCToInstructionCount_L(Armada_PC_enqueue_write_index_update)\n        ==> \n        var f := s.s.threads[tid1].top;\n        && f.enqueue.e == GetPointerToQbssElement(s.s.mem, f.enqueue.write_index as int)\n        )\n}\n\n// Relies on:\n// LocalViewOfEltArrayAddressAlwaysMatchesGlobal\npredicate {:verify false} DequeueEisEltArrayPlusReadIndex(s:LPlusState)\n  requires WeakHeapInvariant(s.s.mem.heap)\n  requires MemorySafetyElementArrayIfInDequeue(s)\n  requires IndicesAlwaysWithinBounds(s)\n{\n    && (forall tid2 :: tid2 in s.s.threads\n        && s.s.threads[tid2].top.Armada_StackFrame_dequeue?\n        && PCToInstructionCount_L(Armada_PC_dequeue_e_init)\n           < PCToInstructionCount_L(s.s.threads[tid2].pc) <=\n           PCToInstructionCount_L(Armada_PC_dequeue_read_index_update)\n        ==> \n        var f := s.s.threads[tid2].top;\n\n        && f.dequeue.e == GetPointerToQbssElement(s.s.mem, f.dequeue.read_index as int % s.s.mem.globals.queue.number_elements as int)\n        )\n}\n\npredicate {:verify false} LocalNumberElementsAlwaysMatchesGlobal(s:LPlusState)\n{\n  && (forall tid :: tid in s.s.threads ==>\n        var locv := Armada_GetThreadLocalView(s.s, tid);\n        locv.globals.queue.number_elements == s.s.mem.globals.queue.number_elements\n    )\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// Memory safety invariant and invariants necessary to support lifting\n// create_thread steps\n////////////////////////////////////////////////////////////////////////////////\n\npredicate {:verify false} MemorySafetyElementArrayIfInEnqueue(s:LPlusState)\n  requires WeakHeapInvariant(s.s.mem.heap)\n{\n  && (forall tid1 :: tid1 in s.s.threads\n    && s.s.threads[tid1].top.Armada_StackFrame_enqueue?\n    ==>\n    // var locv := Armada_GetThreadLocalView(s.s, tid1);\n    && MemorySafetyElementArray(s.s.mem)\n    // && MemorySafetyElementArray(locv)\n    )\n}\n\npredicate {:verify false} MemorySafetyElementArrayIfInDequeue(s:LPlusState)\n  requires WeakHeapInvariant(s.s.mem.heap)\n{\n  && (forall tid1 :: tid1 in s.s.threads\n    && s.s.threads[tid1].top.Armada_StackFrame_dequeue?\n    ==>\n    var locv := Armada_GetThreadLocalView(s.s, tid1);\n    && MemorySafetyElementArray(s.s.mem)\n      // && MemorySafetyElementArray(locv)\n    )\n}\n\npredicate {:verify false} MainSbEmpty(s:LPlusState)\n{\n  && (forall tid :: tid in s.s.threads\n    && s.s.threads[tid].top.Armada_StackFrame_main?\n    ==>\n    s.s.threads[tid].storeBuffer == []\n    )\n}\n\npredicate {:verify false} MainIfGuard(s:LPlusState)\n{\n  && (forall tid :: tid in s.s.threads\n    && s.s.threads[tid].top.Armada_StackFrame_main?\n    && (s.s.threads[tid].pc == Armada_PC_main_BeforeEnqueueCreate\n     || s.s.threads[tid].pc == Armada_PC_main_BeforeDequeueCreate)\n     ==>\n     s.s.mem.globals.queue.element_array != 0\n     && s.s.threads[tid].top.main.k != 0\n     && s.s.threads[tid].top.main.v != 0\n    )\n}\n\npredicate {:verify false} ConditionalMemorySafetyElementInMainAfterCalloc(s:LPlusState)\n{\n  && MainSbEmpty(s)\n  && WeakHeapInvariant(s.s.mem.heap)\n\n  && (forall tid :: tid in s.s.threads\n    && s.s.threads[tid].top.Armada_StackFrame_main?\n    && PCToInstructionCount_L(s.s.threads[tid].pc) > PCToInstructionCount_L(Armada_PC_main_number_elements_init)\n    ==>\n    && s.s.mem.globals.queue.number_elements > 0\n    )\n\n  && (forall tid :: tid in s.s.threads\n    && s.s.threads[tid].top.Armada_StackFrame_main?\n    && PCToInstructionCount_L(s.s.threads[tid].pc) > PCToInstructionCount_L(Armada_PC_main_element_array_alloc)\n    ==>\n    && (s.s.mem.globals.queue.element_array != 0) ==> MemorySafetyElementArray(s.s.mem)\n    )\n\n  && (forall tid :: tid in s.s.threads\n    && s.s.threads[tid].top.Armada_StackFrame_main?\n    && PCToInstructionCount_L(s.s.threads[tid].pc) > PCToInstructionCount_L(Armada_PC_main_k_alloc)\n    ==>\n    &&  var k := s.s.threads[tid].top.main.k;\n    (k != 0 ==> k in s.s.mem.heap.tree && s.s.mem.heap.tree[k].field_of_parent.Armada_FieldNone?)\n    )\n\n  && (forall tid :: tid in s.s.threads\n    && s.s.threads[tid].top.Armada_StackFrame_main?\n    && PCToInstructionCount_L(s.s.threads[tid].pc) > PCToInstructionCount_L(Armada_PC_main_v_alloc)\n    ==>\n    &&  var v := s.s.threads[tid].top.main.v;\n    (v != 0 ==> v in s.s.mem.heap.tree && s.s.mem.heap.tree[v].field_of_parent.Armada_FieldNone?)\n    )\n\n  && (forall tid :: tid in s.s.threads\n    && s.s.threads[tid].top.Armada_StackFrame_main?\n    && PCToInstructionCount_L(s.s.threads[tid].pc) > PCToInstructionCount_L(Armada_PC_main_read_index_init)\n    ==>\n    && 0 <= s.s.mem.globals.queue.read_index as int < s.s.mem.globals.queue.number_elements as int\n    )\n\n  && (forall tid :: tid in s.s.threads\n    && s.s.threads[tid].top.Armada_StackFrame_main?\n    && PCToInstructionCount_L(s.s.threads[tid].pc) > PCToInstructionCount_L(Armada_PC_main_write_index_init)\n    ==>\n    && 0 <= s.s.mem.globals.queue.write_index as int < s.s.mem.globals.queue.number_elements as int\n    )\n}\n\npredicate {:verify false} MemorySafetyInvariant(s:LPlusState)\n{\n  && MainIfGuard(s)\n  && ConditionalMemorySafetyElementInMainAfterCalloc(s)\n  && WeakHeapInvariant(s.s.mem.heap)\n  && MemorySafetyElementArrayIfInDequeue(s)\n  && MemorySafetyElementArrayIfInEnqueue(s)\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// Invariant regarding bounds on read_index and write_index (within array\n// bounds, never overflows uint64)\n////////////////////////////////////////////////////////////////////////////////\n\npredicate {:verify false} DeqGlobalAndLocalViewOfIndicesAlwaysWithinBounds(s:LPlusState)\n{\n  forall tid2 :: tid2 in s.s.threads\n    && s.s.threads[tid2].top.Armada_StackFrame_dequeue?\n    ==>\n    var f := s.s.threads[tid2].top;\n    var locv := Armada_GetThreadLocalView(s.s, tid2);\n    && 0 <= locv.globals.queue.read_index as int < s.s.mem.globals.queue.number_elements as int\n    && 0 <= s.s.mem.globals.queue.read_index as int < s.s.mem.globals.queue.number_elements as int\n    && 0 <= s.s.mem.globals.queue.write_index as int < s.s.mem.globals.queue.number_elements as int\n}\n\npredicate {:verify false} EnqGlobalAndLocalViewOfIndicesAlwaysWithinBounds(s:LPlusState)\n{\n  forall tid1 :: tid1 in s.s.threads\n    && s.s.threads[tid1].top.Armada_StackFrame_enqueue?\n    ==>\n    var f := s.s.threads[tid1].top;\n    var locv := Armada_GetThreadLocalView(s.s, tid1);\n    0 <= locv.globals.queue.write_index as int < s.s.mem.globals.queue.number_elements as int\n    && 0 <= s.s.mem.globals.queue.write_index as int < s.s.mem.globals.queue.number_elements as int\n    && 0 <= s.s.mem.globals.queue.read_index as int < s.s.mem.globals.queue.number_elements as int\n}\n\n// Relies on DeqGlobalAndLocalViewOfIndicesAlwaysWithinBounds\npredicate {:verify false} LocalIndicesOfDequeueAlwaysWithinBounds(s:LPlusState)\n{\n  forall tid2 :: tid2 in s.s.threads\n    && s.s.threads[tid2].top.Armada_StackFrame_dequeue?\n    && PCToInstructionCount_L(s.s.threads[tid2].pc) > PCToInstructionCount_L(Armada_PC_dequeue_read_index_init)\n    ==>\n    var f := s.s.threads[tid2].top;\n    0 <= f.dequeue.read_index as int < s.s.mem.globals.queue.number_elements as int\n}\n// Relies on EnqGlobalAndLocalViewOfIndicesAlwaysWithinBounds\npredicate {:verify false} LocalIndicesOfEnqueueAlwaysWithinBounds(s:LPlusState)\n{\n  forall tid1 :: tid1 in s.s.threads\n    && s.s.threads[tid1].top.Armada_StackFrame_enqueue?\n    && PCToInstructionCount_L(s.s.threads[tid1].pc) > PCToInstructionCount_L(Armada_PC_enqueue_write_index_init)\n    ==>\n    var f := s.s.threads[tid1].top;\n    0 <= f.enqueue.write_index as int < s.s.mem.globals.queue.number_elements as int\n}\n\npredicate {:verify false} IndicesAlwaysWithinBounds(s:LPlusState)\n{\n  && EnqGlobalAndLocalViewOfIndicesAlwaysWithinBounds(s)\n  && DeqGlobalAndLocalViewOfIndicesAlwaysWithinBounds(s)\n  && LocalIndicesOfEnqueueAlwaysWithinBounds(s)\n    && LocalIndicesOfDequeueAlwaysWithinBounds(s)\n}\n\npredicate {:verify false} DeqLocalReadIndexMatchesLocalViewAfterInit(s:LPlusState)\n{\n  forall tid2 :: tid2 in s.s.threads\n    && s.s.threads[tid2].top.Armada_StackFrame_dequeue?\n    && PCToInstructionCount_L(Armada_PC_dequeue_read_index_init)\n    < PCToInstructionCount_L(s.s.threads[tid2].pc) <=\n    PCToInstructionCount_L(Armada_PC_dequeue_read_index_update)\n    ==>\n  var locv := Armada_GetThreadLocalView(s.s, tid2);\n  && s.s.threads[tid2].top.dequeue.read_index == locv.globals.queue.read_index\n}\n\npredicate {:verify false} EnqLocalWriteIndexMatchesLocalViewAfterInit(s:LPlusState)\n{\n  forall tid1 :: tid1 in s.s.threads\n    && s.s.threads[tid1].top.Armada_StackFrame_enqueue?\n    &&\n    PCToInstructionCount_L(Armada_PC_enqueue_write_index_init)\n    < PCToInstructionCount_L(s.s.threads[tid1].pc) <=\n    PCToInstructionCount_L(Armada_PC_enqueue_write_index_update)\n    ==>\n  var locv := Armada_GetThreadLocalView(s.s, tid1);\n  && s.s.threads[tid1].top.enqueue.write_index == locv.globals.queue.write_index\n}\n\n/*\npredicate {:verify false} GhostReadIndexMatchesDeqLocalView(s:LPlusState) {\n  forall tid2 :: tid2 in s.s.threads\n    && s.s.threads[tid2].top.Armada_StackFrame_dequeue?\n    && !s.s.threads[tid2].pc.Armada_PC_dequeue_inside_read_update_block?\n    ==>\n  var locv := Armada_GetThreadLocalView(s.s, tid2);\n  && locv.globals.queue.read_index == s.s.ghosts.d_r\n}\n\npredicate {:verify false} GhostWriteIndexMatchesEnqLocalView(s:LPlusState) {\n  forall tid1 :: tid1 in s.s.threads\n    && s.s.threads[tid1].top.Armada_StackFrame_enqueue?\n    && !s.s.threads[tid1].pc.Armada_PC_enqueue_inside_write_update_block?\n    ==>\n  var locv := Armada_GetThreadLocalView(s.s, tid1);\n  && locv.globals.queue.read_index == s.s.ghosts.d_r\n}\n*/\n\npredicate {:verify false} IndicesProperties(s:LPlusState) {\n  // && GhostReadIndexMatchesDeqLocalView(s)\n    // && GhostWriteIndexMatchesEnqLocalView(s)\n    && DeqLocalReadIndexMatchesLocalViewAfterInit(s)\n    && EnqLocalWriteIndexMatchesLocalViewAfterInit(s)\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// If inside dequeue if, then deq_size > 0 is non-empty\n// Local space ==> global space, local\n////////////////////////////////////////////////////////////////////////////////\n\npredicate {:verify false} EnqueueLocalViewOfReadIndexIsGlobal(s:LPlusState)\n{\n  && (forall tid1 ::\n      && tid1 in s.s.threads \n      && s.s.threads[tid1].top.Armada_StackFrame_enqueue?\n      ==>\n      var locv := Armada_GetThreadLocalView(s.s, tid1);\n      locv.globals.queue.read_index == s.s.mem.globals.queue.read_index\n      )\n}\n\npredicate {:verify false} DequeueLocalViewOfWriteIndexIsGlobal(s:LPlusState)\n{\n  && (forall tid2 ::\n      && tid2 in s.s.threads \n      && s.s.threads[tid2].top.Armada_StackFrame_dequeue?\n      ==>\n      var locv := Armada_GetThreadLocalView(s.s, tid2);\n      locv.globals.queue.write_index == s.s.mem.globals.queue.write_index\n      )\n}\n\npredicate {:verify false} DequeueLocalSpaceImpliesGlobalSpace(s:LPlusState)\n{\n  && DequeueLocalViewOfWriteIndexIsGlobal(s)\n    \n  && (forall tid2 ::\n      && tid2 in s.s.threads \n      && s.s.threads[tid2].top.Armada_StackFrame_dequeue?\n      && (PCToInstructionCount_L(L.Armada_PC_dequeue_write_index_init) <\n          PCToInstructionCount_L(s.s.threads[tid2].pc) <=\n          PCToInstructionCount_L(L.Armada_PC_dequeue_read_index_update))\n          ==>\n          var locv := Armada_GetThreadLocalView(s.s, tid2);\n      (s.s.threads[tid2].top.dequeue.read_index != s.s.threads[tid2].top.dequeue.write_index ==> locv.globals.queue.read_index != locv.globals.queue.write_index)\n  )\n}\n\npredicate {:verify false} DequeueIfProperties(s:LPlusState)\n{\n  (forall tid2 :: tid2 in s.s.threads\n    && s.s.threads[tid2].top.Armada_StackFrame_dequeue?\n    && PCToInstructionCount_L(Armada_PC_dequeue_inside_if_start) <= PCToInstructionCount_L(s.s.threads[tid2].pc)\n    <= PCToInstructionCount_L(Armada_PC_dequeue_read_index_update)\n    ==>\n    s.s.threads[tid2].top.dequeue.read_index != s.s.threads[tid2].top.dequeue.write_index\n    )\n\n  && (forall tid2 :: tid2 in s.s.threads\n    && s.s.threads[tid2].top.Armada_StackFrame_dequeue?\n    && PCToInstructionCount_L(Armada_PC_dequeue_inside_if_start) <= PCToInstructionCount_L(s.s.threads[tid2].pc)\n    <= PCToInstructionCount_L(Armada_PC_dequeue_read_index_update)\n    ==>\n    && Armada_GetThreadLocalView(s.s, tid2).globals.queue.number_elements as int > 0\n    && (\n        var locv := Armada_GetThreadLocalView(s.s, tid2);\n        var deq_size := (locv.globals.queue.write_index as int - locv.globals.queue.read_index as int) % locv.globals.queue.number_elements as int;\n        && locv.globals.queue.write_index as int != locv.globals.queue.read_index as int\n        && 0 <= locv.globals.queue.write_index as int < locv.globals.queue.number_elements as int\n        && 0 <= locv.globals.queue.read_index as int < locv.globals.queue.number_elements as int\n        && deq_size > 0\n    )\n  )\n}\n\npredicate WeakHeapInvariantAlways(s:LPlusState)\n{\n  && WeakHeapInvariant(s.s.mem.heap)\n  && forall tid :: tid in s.s.threads\n    ==>\n    var locv := Armada_GetThreadLocalView(s.s, tid);\n    WeakHeapInvariant(locv.heap)\n}\n\npredicate {:verify false} AbstractQueueMatchesImpl(s:LPlusState)\n{\n  && (\n    forall tid2 :: tid2 in s.s.threads\n        && s.s.threads[tid2].top.Armada_StackFrame_dequeue?\n        && ! (PCToInstructionCount_L(Armada_PC_dequeue_abs_queue_update) < PCToInstructionCount_L(s.s.threads[tid2].pc) <= PCToInstructionCount_L(Armada_PC_dequeue_read_index_update))\n        ==>\n        && Armada_GetThreadLocalView(s.s, tid2).globals.queue.number_elements as int > 0\n        && (\n            var locv := Armada_GetThreadLocalView(s.s, tid2);\n            var deq_size := (s.s.mem.globals.queue.write_index as int - locv.globals.queue.read_index as int) % locv.globals.queue.number_elements as int;\n            && WeakHeapInvariant(locv.heap)\n            && MemorySafetyElementArray(locv)\n            && 0 <= deq_size < |s.s.ghosts.q|\n            && (forall i :: 0 <= i < deq_size ==>\n            s.s.ghosts.q[i] == GetQbssElement(locv, (i + locv.globals.queue.read_index as int) % locv.globals.queue.number_elements as int))\n        )\n  )\n\n  && (\n    forall tid2 :: tid2 in s.s.threads\n        && s.s.threads[tid2].top.Armada_StackFrame_dequeue?\n        && (PCToInstructionCount_L(Armada_PC_dequeue_abs_queue_update) < PCToInstructionCount_L(s.s.threads[tid2].pc) <= PCToInstructionCount_L(Armada_PC_dequeue_read_index_update))\n        ==>\n        && Armada_GetThreadLocalView(s.s, tid2).globals.queue.number_elements as int > 0\n        && (\n            var locv := Armada_GetThreadLocalView(s.s, tid2);\n            var deq_size := (s.s.mem.globals.queue.write_index as int - (locv.globals.queue.read_index as int + 1)) % locv.globals.queue.number_elements as int;\n            && WeakHeapInvariant(locv.heap)\n            && MemorySafetyElementArray(locv)\n            && 0 <= deq_size < |s.s.ghosts.q|\n            && locv.globals.queue.number_elements > 0\n            && (forall i :: 0 <= i < deq_size ==>\n            s.s.ghosts.q[i] == GetQbssElement(locv, (i + locv.globals.queue.read_index as int + 1) % locv.globals.queue.number_elements as int)\n            )\n        )\n  )\n}\n\npredicate {:verify false} EnqueueInitInvariant(s:LPlusState)\n{\n  forall tid1 :: tid1 in s.s.threads\n    && s.s.threads[tid1].top.Armada_StackFrame_enqueue?\n    && PCToInstructionCount_L(s.s.threads[tid1].pc) <= PCToInstructionCount_L(Armada_PC_enqueue_write_index_update)\n    ==>\n    var pc := s.s.threads[tid1].pc;\n    var f := s.s.threads[tid1].top;\n    var locv := Armada_GetThreadLocalView(s.s, tid1);\n    (\n      && (\n      PCToInstructionCount_L(Armada_PC_enqueue_tmp_write_index_init) < PCToInstructionCount_L(pc)\n      ==> f.enqueue.tmp_write_index == Armada_CastTo_uint64(f.enqueue.write_index as int + 1)\n      )\n\n      && (\n      PCToInstructionCount_L(Armada_PC_enqueue_modulo_init) < PCToInstructionCount_L(pc)\n      ==> locv.globals.queue.number_elements as int > 0 && f.enqueue.modulo == Armada_CastTo_uint64((f.enqueue.tmp_write_index as int % locv.globals.queue.number_elements as int) as int)\n      )\n    )\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// Invariant for queue.read_index := queue.read_indeax + 1;\n////////////////////////////////////////////////////////////////////////////////\n\npredicate {:verify false} DequeueReadIndexUpdateInvariant(s:LPlusState)\n{\n  forall tid2 :: tid2 in s.s.threads\n    && s.s.threads[tid2].top.Armada_StackFrame_dequeue?\n    && PCToInstructionCount_L(s.s.threads[tid2].pc) <= PCToInstructionCount_L(Armada_PC_dequeue_read_index_update)\n    ==>\n    var pc := s.s.threads[tid2].pc;\n    var f := s.s.threads[tid2].top;\n    var locv := Armada_GetThreadLocalView(s.s, tid2);\n    (\n      && (\n      PCToInstructionCount_L(Armada_PC_dequeue_tmp_read_index_init) < PCToInstructionCount_L(pc)\n      ==> f.dequeue.tmp_read_index == Armada_CastTo_uint64(f.dequeue.read_index as int + 1)\n      )\n\n      && (\n      PCToInstructionCount_L(Armada_PC_dequeue_modulo_init) < PCToInstructionCount_L(pc)\n      ==> locv.globals.queue.number_elements as int > 0 && f.dequeue.modulo == Armada_CastTo_uint64((f.dequeue.tmp_read_index as int % locv.globals.queue.number_elements as int) as int)\n      )\n    )\n}\n\npredicate {:verify false} ThreadsInv(s:LPlusState)\n{\n        && (forall tid :: tid in s.s.threads ==> (s.s.threads[tid].top.Armada_StackFrame_main? <==> tid == s.config.tid_init))\n        && (forall tid1, tid2 :: tid1 in s.s.threads && tid2 in s.s.threads && s.s.threads[tid1].top.Armada_StackFrame_enqueue? && s.s.threads[tid2].top.Armada_StackFrame_enqueue? ==> tid1 == tid2)\n        && (forall tid1, tid2 :: tid1 in s.s.threads && tid2 in s.s.threads && s.s.threads[tid1].top.Armada_StackFrame_dequeue? && s.s.threads[tid2].top.Armada_StackFrame_dequeue? ==> tid1 == tid2)\n        && (forall tid1, tid2 :: tid1 in s.s.threads && tid2 in s.s.threads && s.s.threads[tid1].top.Armada_StackFrame_main? && PCToInstructionCount_L(s.s.threads[tid1].pc) <= PCToInstructionCount_L(L.Armada_PC_main_BeforeEnqueueCreate) ==> !s.s.threads[tid2].top.Armada_StackFrame_enqueue?)\n        && (forall tid1, tid2 :: tid1 in s.s.threads && tid2 in s.s.threads && s.s.threads[tid1].top.Armada_StackFrame_main? && PCToInstructionCount_L(s.s.threads[tid1].pc) <= PCToInstructionCount_L(L.Armada_PC_main_BeforeDequeueCreate) ==> !s.s.threads[tid2].top.Armada_StackFrame_dequeue?)\n        && (forall tid :: tid in s.s.threads ==> s.s.threads[tid].stack == [])\n        && (forall tid :: tid in s.s.threads && s.s.threads[tid].top.Armada_StackFrame_main? ==> s.s.threads[tid].storeBuffer == [])\n}\n\npredicate {:verify false} AbstractReadsMatchImplQueueValuesInDequeue(s:LPlusState)\n{\n    && (forall tid2 :: tid2 in s.s.threads\n        && s.s.threads[tid2].top.Armada_StackFrame_dequeue?\n        && PCToInstructionCount_L(Armada_PC_dequeue_abs_queue_update) \n           < PCToInstructionCount_L(s.s.threads[tid2].pc) <=\n           PCToInstructionCount_L(Armada_PC_dequeue_read_index_update)\n        ==>\n        var f := s.s.threads[tid2].top;\n        var locv := Armada_GetThreadLocalView(s.s, tid2);\n        && WeakHeapInvariant(locv.heap)\n        && MemorySafetyElementArray(locv)\n        && s.s.mem.globals.queue.number_elements as int > 0\n        && QbssElement(f.dequeue.i_k, f.dequeue.i_v) == GetQbssElement(locv, f.dequeue.read_index as int % locv.globals.queue.number_elements as int))\n}\n\n\n////////////////////////////////////////////////////////////////////////////////\n// Store buffer invariants\n////////////////////////////////////////////////////////////////////////////////\n\n// Idea: make an auxiliary holding the positions of the store buffer entries\n// updated queue.write. Can have an invariant asserting that the only writes to\n// queue.write are those described by the aux.\n// \n// The aux can even track the value being written to write_index.\n// Can this somehow help with preserving the local space implies global space invariant?\n//\n// I think it can. Can assert that the store buffer entry \"write_index := j\" has\n// the property that applying it to a state where write_index == j - 1 and where\n// write_index != read_index will ensure that write_index != read_index is still true.\n// This can be guaranteed by way of \n\npredicate {:verify false} AuxDescribesStoreBuffer(s:LPlusState)\n{\n  && (forall tid :: tid in s.s.threads\n    && s.s.threads[tid].top.Armada_StackFrame_main?\n    && PCToInstructionCount_L(s.s.threads[tid].pc) <= PCToInstructionCount_L(Armada_PC_main_BeforeEnqueueCreate)\n    ==>\n    s.w_i_seq == []\n    )\n\n    && (forall i, j :: 0 <= i < j < |s.w_i_seq|\n        ==> s.w_i_seq[i].position < s.w_i_seq[j].position\n    )\n\n  && (forall tid1 :: tid1 in s.s.threads\n    && s.s.threads[tid1].top.Armada_StackFrame_enqueue?\n    ==>\n    (forall i :: 0 <= i < |s.s.threads[tid1].storeBuffer|\n    && s.s.threads[tid1].storeBuffer[i].loc ==\n    L.Armada_StoreBufferLocation_Unaddressable(L.Armada_GlobalStaticVar_queue, [Armada_FieldStruct(Armada_FieldType_QbssState'write_index)])\n    ==>\n    && s.s.threads[tid1].storeBuffer[i].value.Armada_PrimitiveValue_uint64?\n    && WriteIndexSBEntry(i, s.s.threads[tid1].storeBuffer[i].value.n_uint64) in s.w_i_seq\n    )\n  )\n\n  && (forall tid1 :: tid1 in s.s.threads\n    && s.s.threads[tid1].top.Armada_StackFrame_enqueue?\n    ==>\n    && (forall w :: w in s.w_i_seq\n    ==>\n    0 <= w.position < |s.s.threads[tid1].storeBuffer|\n    && s.s.threads[tid1].storeBuffer[w.position].loc == L.Armada_StoreBufferLocation_Unaddressable(L.Armada_GlobalStaticVar_queue, [Armada_FieldStruct(Armada_FieldType_QbssState'write_index)])\n    && s.s.threads[tid1].storeBuffer[w.position].value == Armada_PrimitiveValue_uint64(w.value)\n    )\n  )\n}\n\n// All the things that should never be in the store buffers of different threads\npredicate {:verify false} StoreBufferDoesNotContainInvariant(s:LPlusState)\n{\n  && (forall tid :: tid in s.s.threads\n    ==>\n    (forall e :: e in s.s.threads[tid].storeBuffer ==>\n    && e.loc != L.Armada_StoreBufferLocation_Unaddressable(L.Armada_GlobalStaticVar_queue, [Armada_FieldStruct(Armada_FieldType_QbssState'number_elements)])\n    && e.loc != L.Armada_StoreBufferLocation_Unaddressable(L.Armada_GlobalStaticVar_queue, [Armada_FieldStruct(Armada_FieldType_QbssState'element_array)])\n    )\n    )\n\n  && (forall tid :: tid in s.s.threads\n    && s.s.threads[tid].top.Armada_StackFrame_dequeue?\n    ==>\n    && (forall e :: e in s.s.threads[tid].storeBuffer ==>\n        && e.loc != L.Armada_StoreBufferLocation_Unaddressable(L.Armada_GlobalStaticVar_queue, [Armada_FieldStruct(Armada_FieldType_QbssState'write_index)])\n      )\n\n    && (forall e :: e in s.s.threads[tid].storeBuffer\n        && e.loc == L.Armada_StoreBufferLocation_Unaddressable(L.Armada_GlobalStaticVar_queue, [Armada_FieldStruct(Armada_FieldType_QbssState'read_index)])\n        ==> e.value.Armada_PrimitiveValue_uint64? && 0 <= e.value.n_uint64 < s.s.mem.globals.queue.number_elements\n      )\n    )\n\n  && (forall tid :: tid in s.s.threads\n    && s.s.threads[tid].top.Armada_StackFrame_enqueue?\n    ==>\n    && (forall e :: e in s.s.threads[tid].storeBuffer ==>\n        && e.loc != L.Armada_StoreBufferLocation_Unaddressable(L.Armada_GlobalStaticVar_queue, [Armada_FieldStruct(Armada_FieldType_QbssState'read_index)])\n      )\n\n    && (forall e :: e in s.s.threads[tid].storeBuffer\n        && e.loc == L.Armada_StoreBufferLocation_Unaddressable(L.Armada_GlobalStaticVar_queue, [Armada_FieldStruct(Armada_FieldType_QbssState'write_index)])\n        ==> e.value.Armada_PrimitiveValue_uint64? && 0 <= e.value.n_uint64 < s.s.mem.globals.queue.number_elements\n      )\n    )\n\n    // && DequeueStoreBufferDoesNotWriteToWriteIndex(s)\n    // && EnqueueStoreBufferDoesNotWriteToReadIndex(s)\n}\n\npredicate {:verify false} EnqueueStoreBufferDoesNotWriteToReadIndex(s:LPlusState)\n{\n  (forall tid1 :: tid1 in s.s.threads\n    && s.s.threads[tid1].top.Armada_StackFrame_enqueue?\n    ==>\n    && (forall mem :: var mem' := Armada_ApplyStoreBuffer(mem, s.s.threads[tid1].storeBuffer); mem.globals.queue.read_index == mem'.globals.queue.read_index)\n    && (forall mem :: var mem' := Armada_ApplyStoreBuffer(mem, s.s.threads[tid1].storeBuffer); mem.globals.queue.number_elements == mem'.globals.queue.number_elements)\n  )\n}\n\npredicate {:verify false} DequeueStoreBufferDoesNotWriteToWriteIndex(s:LPlusState)\n{\n  (forall tid1 :: tid1 in s.s.threads\n    && s.s.threads[tid1].top.Armada_StackFrame_dequeue?\n    ==>\n    && (forall mem :: var mem' := Armada_ApplyStoreBuffer(mem, s.s.threads[tid1].storeBuffer); mem.globals.queue.write_index == mem'.globals.queue.write_index)\n    && (forall mem :: var mem' := Armada_ApplyStoreBuffer(mem, s.s.threads[tid1].storeBuffer); mem.globals.queue.number_elements == mem'.globals.queue.number_elements)\n  )\n}\n\npredicate {:verify false} StoreBufferInvariant(s:LPlusState)\n{\n  StoreBufferDoesNotContainInvariant(s)\n}\n\npredicate {:verify false} WeakeningInvariant_ext(s:LPlusState)\n{\n  && ThreadsInv(s)\n  && WeakHeapInvariant(s.s.mem.heap)\n\n  && MemorySafetyInvariant(s)\n\n    && ElementArrayDeqLocalMatchesGlobal(s)\n\n    && EnqueueLocalViewOfReadIndexIsGlobal(s)\n    && LocalViewOfNumberElementsAlwaysMatchsGlobalInEnqOrDeq(s)\n    && EnqueueInitInvariant(s)\n    && DequeueReadIndexUpdateInvariant(s)\n    && IndicesProperties(s)\n    && IndicesAlwaysWithinBounds(s)\n\n    && DequeueInputPointersDoNotAliasElementArray(s)\n    && TmpIntProperties(s)\n\n    && LocalViewOfEltArrayAddressAlwaysMatchesGlobal(s)\n    && EnqueueEIsEltArrayPlusWriteIndex(s)\n    && DequeueEisEltArrayPlusReadIndex(s)\n\n    && DequeueLocalSpaceImpliesGlobalSpace(s)\n    && DequeueIfProperties(s)\n    && WeakHeapInvariantAlways(s)\n\n    && AuxDescribesStoreBuffer(s)\n    && StoreBufferInvariant(s)\n    && DequeueDoesNotConcernQbssElement(s)\n\n    && AbstractQueueMatchesImpl(s)\n\n    && AbstractReadsMatchImplQueueValuesInDequeue(s)\n}\n\n}\n"
  },
  {
    "path": "Test/qbss/queue_tsobypassing_abstractloginvariant.dfy",
    "content": "include \"QueueBSSNoTSO_WithAbstractQueue.dfy\"\ninclude \"NoTSOUseAbstractQueueForLog/specs.dfy\"\ninclude \"SharedStructs.dfy\"\n\nmodule queue_tsobypassing_abstractloginvariant {\nimport opened ArmadaCommonDefinitions = ArmadaCommonDefinitions\nimport opened QueueBSSNoTSO_WithAbstractQueue = QueueBSSNoTSO_WithAbstractQueue\nimport opened ArmadaModule_specs = ArmadaModule_specs\nimport opened SharedStructs = SharedStructs\n\n\nlemma lemma_NoSetIntersectionImpliesNoCommonElements<T>(a:set<T>, b:set<T>)\n  requires (a * b) == {}\n  ensures forall i :: i in a ==> i !in b\n{\n    forall i | i in a\n      ensures i !in b\n    {\n      assert i in (a * b) ==> a * b != {};\n    }\n}\n\n// This is the target invariant.\n// (a) element_array[d!r .. w] == abstract_queue[..(w - d!r) % array_size ]\n\npredicate WeakHeapInvariant(h: Armada_Heap)\n{\n    && (forall p :: p in h.valid ==> p !in h.freed)\n    && 0 in h.freed\n    && !(0 in h.valid)\n    && Armada_TreeProperties(h.tree)\n    && (forall p {:trigger Armada_TriggerPointer(p)} :: \n        Armada_TriggerPointer(p) in h.tree &&\n        h.tree[p].ty.Armada_ObjectTypePrimitive? ==>\n          p in h.values &&\n          Armada_PrimitiveValueMatchesType(h.values[p], h.tree[p].ty.pty))\n}\n\n// This ensures that queue.element_array is an array with the appropriate number\n// of elements and should allow GetQbssElement to be well-defined\npredicate MemorySafetyElementArray(locv:Armada_SharedMemory)\n  requires WeakHeapInvariant(locv.heap)\n{\n  MemorySafetyElementArrayCustomPointer(locv.globals.queue.element_array, locv)\n}\n\npredicate MemorySafetyElementArrayCustomPointer(pointer:Armada_Pointer, locv:Armada_SharedMemory)\n  requires WeakHeapInvariant(locv.heap)\n{\n  var e := pointer;\n    && e in locv.heap.tree\n    && e in locv.heap.valid\n    && locv.heap.tree[e].child_type == Armada_ChildTypeIndex(0)\n    && locv.globals.queue.number_elements as int > 0\n    && Armada_ComparablePointer(e, locv.heap)\n    && var a := locv.heap.tree[e].parent;\n    && Armada_ValidPointerToObjectType(locv.heap, a, Armada_ObjectTypeArray(Armada_StructType_BSSQueueElement(), locv.globals.queue.number_elements as int))\n    && (forall i {:trigger locv.heap.tree[a].children[i]} :: 0 <= i < locv.globals.queue.number_elements as int ==> Armada_ValidPointerToObjectType(locv.heap, locv.heap.tree[a].children[i], Armada_StructType_BSSQueueElement()))\n}\n\n\nfunction GetQbssElement(locv:Armada_SharedMemory, j:int) : QbssElement\n  requires WeakHeapInvariant(locv.heap)\n  requires MemorySafetyElementArray(locv)\n  requires 0 <= j < locv.globals.queue.number_elements as int\n{\n  var qbsse := Armada_DereferenceStructPointer_BSSQueueElement(locv.heap, GetPointerToQbssElement(locv, j));\n  QbssElement(qbsse.key, qbsse.value)\n}\n\nfunction GetPointerToQbssElement(locv:Armada_SharedMemory, j:int) : Armada_Pointer\n  requires WeakHeapInvariant(locv.heap)\n  requires MemorySafetyElementArray(locv)\n  requires 0 <= j < locv.globals.queue.number_elements as int\n{\n  locv.heap.tree[locv.heap.tree[locv.globals.queue.element_array].parent].children[locv.heap.tree[locv.globals.queue.element_array].child_type.i + j]\n}\n\nfunction GetPointerToQbssElementKey(locv:Armada_SharedMemory, j:int) : Armada_Pointer\n  requires WeakHeapInvariant(locv.heap)\n  requires MemorySafetyElementArray(locv)\n  requires 0 <= j < locv.globals.queue.number_elements as int\n{\n  locv.heap.tree[GetPointerToQbssElement(locv, j)].children[0 /* key is field 0 of BSSQueueElement */]\n}\n\nfunction GetPointerToQbssElementValue(locv:Armada_SharedMemory, j:int) : Armada_Pointer\n  requires WeakHeapInvariant(locv.heap)\n  requires MemorySafetyElementArray(locv)\n  requires 0 <= j < locv.globals.queue.number_elements as int\n{\n  locv.heap.tree[GetPointerToQbssElement(locv, j)].children[1 /* value is field 1 of BSSQueueElement */]\n}\n\n// In order to demonstrate this, we will simply require k and v to be roots in\n// the tree\npredicate DequeueInputPointersDoNotAliasElementArray(s:LPlusState)\n{\n  forall tid2 :: tid2 in s.s.threads\n    && s.s.threads[tid2].top.Armada_StackFrame_dequeue?\n    ==>\n    var k := s.s.threads[tid2].top.dequeue.k;\n    var v := s.s.threads[tid2].top.dequeue.v;\n    && k in s.s.mem.heap.tree && s.s.mem.heap.tree[k].child_type.Armada_ChildTypeRoot?\n    && v in s.s.mem.heap.tree && s.s.mem.heap.tree[v].child_type.Armada_ChildTypeRoot?\n\n}\n\npredicate TmpIntProperties(s:LPlusState)\n  requires LocalIndicesOfDequeueAlwaysWithinBounds(s)\n  requires WeakHeapInvariant(s.s.mem.heap)\n  requires MemorySafetyElementArrayIfInDequeue(s)\n{\n    && (forall tid2 :: tid2 in s.s.threads\n        && s.s.threads[tid2].top.Armada_StackFrame_dequeue?\n        && PCToInstructionCount_L(Armada_PC_dequeue_tmp_int_update_key)\n           < PCToInstructionCount_L(s.s.threads[tid2].pc) <=\n           PCToInstructionCount_L(Armada_PC_dequeue_k_update)\n           ==>\n            var f := s.s.threads[tid2].top;\n            && s.s.mem.globals.queue.number_elements > 0\n            &&  f.dequeue.tmp_int == GetQbssElement(s.s.mem, f.dequeue.read_index as int % s.s.mem.globals.queue.number_elements as int).key\n       )\n\n    && (forall tid2 :: tid2 in s.s.threads\n        && s.s.threads[tid2].top.Armada_StackFrame_dequeue?\n        && PCToInstructionCount_L(Armada_PC_dequeue_tmp_int_update_value)\n           < PCToInstructionCount_L(s.s.threads[tid2].pc) <=\n           PCToInstructionCount_L(Armada_PC_dequeue_v_update)\n           ==>\n            var f := s.s.threads[tid2].top;\n            && s.s.mem.globals.queue.number_elements > 0\n            &&  f.dequeue.tmp_int == GetQbssElement(s.s.mem, f.dequeue.read_index as int % s.s.mem.globals.queue.number_elements as int).value\n       )\n}\n\npredicate EnqueueEIsEltArrayPlusWriteIndex(s:LPlusState)\n  requires WeakHeapInvariant(s.s.mem.heap)\n  requires MemorySafetyElementArrayIfInEnqueue(s)\n  requires IndicesAlwaysWithinBounds(s)\n{\n    && (forall tid1 :: tid1 in s.s.threads\n        && s.s.threads[tid1].top.Armada_StackFrame_enqueue?\n        && PCToInstructionCount_L(Armada_PC_enqueue_e_init)\n           < PCToInstructionCount_L(s.s.threads[tid1].pc) <=\n           PCToInstructionCount_L(Armada_PC_enqueue_write_index_update)\n        ==> \n        var f := s.s.threads[tid1].top;\n        && f.enqueue.e == GetPointerToQbssElement(s.s.mem, f.enqueue.write_index as int)\n        )\n}\n\npredicate DequeueEisEltArrayPlusReadIndex(s:LPlusState)\n  requires WeakHeapInvariant(s.s.mem.heap)\n  requires MemorySafetyElementArrayIfInDequeue(s)\n  requires IndicesAlwaysWithinBounds(s)\n{\n    && (forall tid2 :: tid2 in s.s.threads\n        && s.s.threads[tid2].top.Armada_StackFrame_dequeue?\n        && PCToInstructionCount_L(Armada_PC_dequeue_e_init)\n           < PCToInstructionCount_L(s.s.threads[tid2].pc) <=\n           PCToInstructionCount_L(Armada_PC_dequeue_read_index_update)\n        ==> \n        var f := s.s.threads[tid2].top;\n\n        && f.dequeue.e == GetPointerToQbssElement(s.s.mem, f.dequeue.read_index as int % s.s.mem.globals.queue.number_elements as int)\n        )\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// Memory safety invariant and invariants necessary to support lifting\n// create_thread steps\n////////////////////////////////////////////////////////////////////////////////\n\npredicate MemorySafetyElementArrayIfInEnqueue(s:LPlusState)\n  requires WeakHeapInvariant(s.s.mem.heap)\n{\n  && (forall tid1 :: tid1 in s.s.threads\n    && s.s.threads[tid1].top.Armada_StackFrame_enqueue?\n    ==>\n    && MemorySafetyElementArray(s.s.mem)\n    )\n}\n\npredicate MemorySafetyElementArrayIfInDequeue(s:LPlusState)\n  requires WeakHeapInvariant(s.s.mem.heap)\n{\n  && (forall tid1 :: tid1 in s.s.threads\n    && s.s.threads[tid1].top.Armada_StackFrame_dequeue?\n    ==>\n    && MemorySafetyElementArray(s.s.mem)\n    )\n}\n\npredicate MainIfGuard(s:LPlusState)\n{\n  && (forall tid :: tid in s.s.threads\n    && s.s.threads[tid].top.Armada_StackFrame_main?\n    && (s.s.threads[tid].pc == Armada_PC_main_BeforeEnqueueCreate\n     || s.s.threads[tid].pc == Armada_PC_main_BeforeDequeueCreate)\n     ==>\n     s.s.mem.globals.queue.element_array != 0\n     && s.s.threads[tid].top.main.k != 0\n     && s.s.threads[tid].top.main.v != 0\n    )\n}\n\npredicate ConditionalMemorySafetyElementInMainAfterCalloc(s:LPlusState)\n{\n  && WeakHeapInvariant(s.s.mem.heap)\n\n  && (forall tid :: tid in s.s.threads\n    && s.s.threads[tid].top.Armada_StackFrame_main?\n    && PCToInstructionCount_L(s.s.threads[tid].pc) > PCToInstructionCount_L(Armada_PC_main_number_elements_init)\n    ==>\n    && s.s.mem.globals.queue.number_elements == 512\n    )\n\n  && (forall tid :: tid in s.s.threads\n    && s.s.threads[tid].top.Armada_StackFrame_main?\n    && PCToInstructionCount_L(s.s.threads[tid].pc) > PCToInstructionCount_L(Armada_PC_main_array_calloc)\n    ==>\n    && (s.s.threads[tid].top.main.a != 0 ==> MemorySafetyElementArrayCustomPointer(s.s.threads[tid].top.main.a, s.s.mem)\n    )\n    )\n\n  && (forall tid :: tid in s.s.threads\n    && s.s.threads[tid].top.Armada_StackFrame_main?\n    && PCToInstructionCount_L(s.s.threads[tid].pc) > PCToInstructionCount_L(Armada_PC_main_element_array_alloc)\n    ==>\n    && (s.s.mem.globals.queue.element_array != 0) ==> MemorySafetyElementArray(s.s.mem)\n    )\n\n  && (forall tid :: tid in s.s.threads\n    && s.s.threads[tid].top.Armada_StackFrame_main?\n    && PCToInstructionCount_L(s.s.threads[tid].pc) > PCToInstructionCount_L(Armada_PC_main_k_alloc)\n    ==>\n    &&  var k := s.s.threads[tid].top.main.k;\n    (k != 0 ==> k in s.s.mem.heap.tree && s.s.mem.heap.tree[k].child_type.Armada_ChildTypeRoot?\n    && Armada_ComparablePointer(k, s.s.mem.heap)\n      )\n    )\n\n  && (forall tid :: tid in s.s.threads\n    && s.s.threads[tid].top.Armada_StackFrame_main?\n    && PCToInstructionCount_L(s.s.threads[tid].pc) > PCToInstructionCount_L(Armada_PC_main_v_alloc)\n    ==>\n    &&  var v := s.s.threads[tid].top.main.v;\n    (v != 0 ==> v in s.s.mem.heap.tree && s.s.mem.heap.tree[v].child_type.Armada_ChildTypeRoot?\n    && Armada_ComparablePointer(v, s.s.mem.heap)\n      )\n    )\n\n  && (forall tid :: tid in s.s.threads\n    && s.s.threads[tid].top.Armada_StackFrame_main?\n    && PCToInstructionCount_L(s.s.threads[tid].pc) > PCToInstructionCount_L(Armada_PC_main_read_index_init)\n    ==>\n    && 0 <= s.s.mem.globals.queue.read_index as int < s.s.mem.globals.queue.number_elements as int\n    )\n\n  && (forall tid :: tid in s.s.threads\n    && s.s.threads[tid].top.Armada_StackFrame_main?\n    && PCToInstructionCount_L(s.s.threads[tid].pc) > PCToInstructionCount_L(Armada_PC_main_write_index_init)\n    ==>\n    && 0 <= s.s.mem.globals.queue.write_index as int < s.s.mem.globals.queue.number_elements as int\n    )\n\n\n  && (forall tid :: tid in s.s.threads\n    && s.s.threads[tid].top.Armada_StackFrame_main?\n    && PCToInstructionCount_L(Armada_PC_main_BeforeEnqueueCreate) >= PCToInstructionCount_L(s.s.threads[tid].pc) > PCToInstructionCount_L(Armada_PC_main_write_index_init)\n    ==>\n    && 0 == s.s.mem.globals.queue.write_index as int\n    )\n\n  && (forall tid :: tid in s.s.threads\n    && s.s.threads[tid].top.Armada_StackFrame_main?\n    && PCToInstructionCount_L(Armada_PC_main_BeforeEnqueueCreate) >= PCToInstructionCount_L(s.s.threads[tid].pc) > PCToInstructionCount_L(Armada_PC_main_read_index_init)\n    ==>\n    && 0 == s.s.mem.globals.queue.read_index as int\n    )\n}\n\npredicate MemorySafetyInvariant(s:LPlusState)\n{\n  && MainIfGuard(s)\n  && ConditionalMemorySafetyElementInMainAfterCalloc(s)\n  && WeakHeapInvariant(s.s.mem.heap)\n  && MemorySafetyElementArrayIfInDequeue(s)\n  && MemorySafetyElementArrayIfInEnqueue(s)\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// Invariant regarding bounds on read_index and write_index (within array\n// bounds, never overflows uint64)\n////////////////////////////////////////////////////////////////////////////////\n\npredicate DeqGlobalAndLocalViewOfIndicesAlwaysWithinBounds(s:LPlusState)\n{\n  forall tid2 :: tid2 in s.s.threads\n    && s.s.threads[tid2].top.Armada_StackFrame_dequeue?\n    ==>\n    var f := s.s.threads[tid2].top;\n    && 0 <= s.s.mem.globals.queue.read_index as int < s.s.mem.globals.queue.number_elements as int\n    && 0 <= s.s.mem.globals.queue.write_index as int < s.s.mem.globals.queue.number_elements as int\n}\n\npredicate EnqGlobalAndLocalViewOfIndicesAlwaysWithinBounds(s:LPlusState)\n{\n  forall tid1 :: tid1 in s.s.threads\n    && s.s.threads[tid1].top.Armada_StackFrame_enqueue?\n    ==>\n    var f := s.s.threads[tid1].top;\n    && 0 <= s.s.mem.globals.queue.write_index as int < s.s.mem.globals.queue.number_elements as int\n    && 0 <= s.s.mem.globals.queue.read_index as int < s.s.mem.globals.queue.number_elements as int\n}\n\n// Relies on DeqGlobalAndLocalViewOfIndicesAlwaysWithinBounds\npredicate LocalIndicesOfDequeueAlwaysWithinBounds(s:LPlusState)\n{\n  forall tid2 :: tid2 in s.s.threads\n    && s.s.threads[tid2].top.Armada_StackFrame_dequeue?\n    && PCToInstructionCount_L(s.s.threads[tid2].pc) > PCToInstructionCount_L(Armada_PC_dequeue_read_index_init)\n    ==>\n    var f := s.s.threads[tid2].top;\n    0 <= f.dequeue.read_index as int < s.s.mem.globals.queue.number_elements as int\n}\n// Relies on EnqGlobalAndLocalViewOfIndicesAlwaysWithinBounds\npredicate LocalIndicesOfEnqueueAlwaysWithinBounds(s:LPlusState)\n{\n  forall tid1 :: tid1 in s.s.threads\n    && s.s.threads[tid1].top.Armada_StackFrame_enqueue?\n    && PCToInstructionCount_L(s.s.threads[tid1].pc) > PCToInstructionCount_L(Armada_PC_enqueue_write_index_init)\n    ==>\n    var f := s.s.threads[tid1].top;\n    0 <= f.enqueue.write_index as int < s.s.mem.globals.queue.number_elements as int\n}\n\npredicate IndicesAlwaysWithinBounds(s:LPlusState)\n{\n  && EnqGlobalAndLocalViewOfIndicesAlwaysWithinBounds(s)\n  && DeqGlobalAndLocalViewOfIndicesAlwaysWithinBounds(s)\n  && LocalIndicesOfEnqueueAlwaysWithinBounds(s)\n    && LocalIndicesOfDequeueAlwaysWithinBounds(s)\n}\n\npredicate DeqLocalReadIndexMatchesLocalViewAfterInit(s:LPlusState)\n{\n  forall tid2 :: tid2 in s.s.threads\n    && s.s.threads[tid2].top.Armada_StackFrame_dequeue?\n    && PCToInstructionCount_L(Armada_PC_dequeue_read_index_init)\n    < PCToInstructionCount_L(s.s.threads[tid2].pc) <=\n    PCToInstructionCount_L(Armada_PC_dequeue_read_index_update)\n    ==>\n  && s.s.threads[tid2].top.dequeue.read_index == s.s.mem.globals.queue.read_index\n}\n\npredicate EnqLocalWriteIndexMatchesLocalViewAfterInit(s:LPlusState)\n{\n  forall tid1 :: tid1 in s.s.threads\n    && s.s.threads[tid1].top.Armada_StackFrame_enqueue?\n    &&\n    PCToInstructionCount_L(Armada_PC_enqueue_write_index_init)\n    < PCToInstructionCount_L(s.s.threads[tid1].pc) <=\n    PCToInstructionCount_L(Armada_PC_enqueue_write_index_update)\n    ==>\n  && s.s.threads[tid1].top.enqueue.write_index == s.s.mem.globals.queue.write_index\n}\n\npredicate IndicesProperties(s:LPlusState) {\n    && DeqLocalReadIndexMatchesLocalViewAfterInit(s)\n    && EnqLocalWriteIndexMatchesLocalViewAfterInit(s)\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// If inside dequeue if, then deq_size > 0 is non-empty\n// Local space ==> global space, local\n////////////////////////////////////////////////////////////////////////////////\n\npredicate DequeueLocalNonEmptyImpliesGlobalNonEmpty(s:LPlusState)\n{\n  && (forall tid2 ::\n      && tid2 in s.s.threads \n      && s.s.threads[tid2].top.Armada_StackFrame_dequeue?\n      && (PCToInstructionCount_L(L.Armada_PC_dequeue_write_index_init) <\n          PCToInstructionCount_L(s.s.threads[tid2].pc) <=\n          PCToInstructionCount_L(L.Armada_PC_dequeue_read_index_update))\n          ==>\n      (s.s.threads[tid2].top.dequeue.read_index != s.s.threads[tid2].top.dequeue.write_index ==> s.s.mem.globals.queue.read_index != s.s.mem.globals.queue.write_index)\n  )\n}\n\npredicate EnqueueLocalSpaceImpliesGlobalSpace(s:LPlusState)\n{\n    (forall tid1 ::\n     && tid1 in s.s.threads \n     && s.s.threads[tid1].top.Armada_StackFrame_enqueue?\n     && (PCToInstructionCount_L(L.Armada_PC_enqueue_read_index_init) <\n         PCToInstructionCount_L(s.s.threads[tid1].pc) <=\n         PCToInstructionCount_L(L.Armada_PC_enqueue_write_index_update))\n         ==>\n         && s.s.mem.globals.queue.number_elements as int > 0\n         && (s.s.threads[tid1].top.enqueue.read_index != s.s.threads[tid1].top.enqueue.modulo\n          ==> s.s.mem.globals.queue.read_index != Armada_CastTo_uint64((Armada_CastTo_uint64((s.s.mem.globals.queue.write_index as int + 1 as int) as int) as int % s.s.mem.globals.queue.number_elements as int) as int))\n    )\n}\n\npredicate DequeueIfProperties(s:LPlusState)\n{\n  (forall tid2 :: tid2 in s.s.threads\n    && s.s.threads[tid2].top.Armada_StackFrame_dequeue?\n    && PCToInstructionCount_L(Armada_PC_dequeue_inside_if_start) <= PCToInstructionCount_L(s.s.threads[tid2].pc)\n    <= PCToInstructionCount_L(Armada_PC_dequeue_read_index_update)\n    ==>\n    && (s.s.threads[tid2].top.dequeue.read_index != s.s.threads[tid2].top.dequeue.write_index)\n    && (s.s.mem.globals.queue.read_index != s.s.mem.globals.queue.write_index)\n    )\n\n  && (forall tid2 :: tid2 in s.s.threads\n    && s.s.threads[tid2].top.Armada_StackFrame_dequeue?\n    && PCToInstructionCount_L(Armada_PC_dequeue_inside_if_start) <= PCToInstructionCount_L(s.s.threads[tid2].pc)\n    <= PCToInstructionCount_L(Armada_PC_dequeue_read_index_update)\n    ==>\n    && s.s.mem.globals.queue.number_elements as int > 0\n    && (\n        var queue := s.s.mem.globals.queue;\n        var deq_size := (queue.write_index as int - queue.read_index as int) % queue.number_elements as int;\n        && queue.write_index as int != queue.read_index as int\n        && 0 <= queue.write_index as int < queue.number_elements as int\n        && 0 <= queue.read_index as int < queue.number_elements as int\n        && deq_size > 0\n    )\n  )\n}\n\n\npredicate EnqueueIfProperties(s:LPlusState)\n{\n  (forall tid1 :: tid1 in s.s.threads\n    && s.s.threads[tid1].top.Armada_StackFrame_enqueue?\n    && PCToInstructionCount_L(Armada_PC_enqueue_inside_if_start) <= PCToInstructionCount_L(s.s.threads[tid1].pc)\n    <= PCToInstructionCount_L(Armada_PC_enqueue_write_index_update)\n    ==>\n    s.s.threads[tid1].top.enqueue.modulo != s.s.threads[tid1].top.enqueue.read_index\n    )\n}\n\npredicate BothIfProperties(s:LPlusState)\n{\n  (forall tid1, tid2 :: tid1 in s.s.threads && tid2 in s.s.threads\n    && s.s.threads[tid1].top.Armada_StackFrame_enqueue?\n    && PCToInstructionCount_L(Armada_PC_enqueue_inside_if_start) <= PCToInstructionCount_L(s.s.threads[tid1].pc)\n    <= PCToInstructionCount_L(Armada_PC_enqueue_write_index_update)\n\n    && s.s.threads[tid2].top.Armada_StackFrame_dequeue?\n    && PCToInstructionCount_L(Armada_PC_dequeue_inside_if_start) <= PCToInstructionCount_L(s.s.threads[tid2].pc)\n    <= PCToInstructionCount_L(Armada_PC_dequeue_read_index_update)\n    ==>\n    s.s.threads[tid1].top.enqueue.write_index != s.s.threads[tid2].top.dequeue.read_index\n    )\n}\n\npredicate AbstractQueueMatchesImplBetweenIndices(s:LPlusState, start:uint64, end:uint64)\n  requires 0 <= start < s.s.mem.globals.queue.number_elements\n  requires 0 <= end < s.s.mem.globals.queue.number_elements\n{\n  var q_size := (end as int - start as int) % s.s.mem.globals.queue.number_elements as int;\n  && WeakHeapInvariant(s.s.mem.heap)\n    && MemorySafetyElementArray(s.s.mem)\n    && 0 <= q_size == |s.s.ghosts.q|\n    && (forall i :: 0 <= i < q_size ==>\n    s.s.ghosts.q[i] == GetQbssElement(s.s.mem, (i + start as int) % s.s.mem.globals.queue.number_elements as int))\n}\n\npredicate EnqueueAfterAssignmentQueueMatchesKV(s:LPlusState)\n{\n  && (forall tid1 :: tid1 in s.s.threads\n    && s.s.threads[tid1].top.Armada_StackFrame_enqueue?\n    && PCToInstructionCount_L(Armada_PC_enqueue_k_update)\n    < PCToInstructionCount_L(s.s.threads[tid1].pc)\n    <= PCToInstructionCount_L(Armada_PC_enqueue_write_index_update)\n    ==>\n    && s.s.mem.globals.queue.number_elements > 0\n  && WeakHeapInvariant(s.s.mem.heap)\n    && MemorySafetyElementArray(s.s.mem)\n    && s.s.threads[tid1].top.enqueue.k == GetQbssElement(s.s.mem, s.s.mem.globals.queue.write_index as int % s.s.mem.globals.queue.number_elements as int).key\n    )\n\n  && (forall tid1 :: tid1 in s.s.threads\n    && s.s.threads[tid1].top.Armada_StackFrame_enqueue?\n    && PCToInstructionCount_L(Armada_PC_enqueue_v_update)\n    < PCToInstructionCount_L(s.s.threads[tid1].pc)\n    <= PCToInstructionCount_L(Armada_PC_enqueue_write_index_update)\n    ==>\n    && s.s.mem.globals.queue.number_elements > 0\n    && s.s.threads[tid1].top.enqueue.v == GetQbssElement(s.s.mem, s.s.mem.globals.queue.write_index as int % s.s.mem.globals.queue.number_elements as int).value\n    )\n}\n\npredicate AbstractQueueMatchesImpl(s:LPlusState)\n{\n  && (\n    forall tid :: tid in s.s.threads\n     && s.s.threads[tid].top.Armada_StackFrame_main?\n     && PCToInstructionCount_L(s.s.threads[tid].pc) <= PCToInstructionCount_L(Armada_PC_main_BeforeEnqueueCreate)\n     ==>\n     && s.s.ghosts.q == []\n    )\n\n  && (\n    forall tid2 :: tid2 in s.s.threads\n    && (s.s.threads[tid2].top.Armada_StackFrame_enqueue?\n    || s.s.threads[tid2].top.Armada_StackFrame_dequeue?\n    || (s.s.threads[tid2].top.Armada_StackFrame_main?\n        && (PCToInstructionCount_L(s.s.threads[tid2].pc) == PCToInstructionCount_L(Armada_PC_main_BeforeEnqueueCreate)\n           || PCToInstructionCount_L(s.s.threads[tid2].pc) == PCToInstructionCount_L(Armada_PC_main_BeforeDequeueCreate))\n       )\n    )\n    ==>\n    && s.s.mem.globals.queue.number_elements as int > 0\n    && 0 <= s.s.mem.globals.queue.read_index < s.s.mem.globals.queue.number_elements\n    && 0 <= s.s.mem.globals.queue.write_index < s.s.mem.globals.queue.number_elements\n    && (\n    AbstractQueueMatchesImplBetweenIndices(s, s.s.mem.globals.queue.read_index, s.s.mem.globals.queue.write_index)\n    )\n    )\n}\n\npredicate EnqueueInitInvariant(s:LPlusState)\n{\n  forall tid1 :: tid1 in s.s.threads\n    && s.s.threads[tid1].top.Armada_StackFrame_enqueue?\n    && PCToInstructionCount_L(s.s.threads[tid1].pc) <= PCToInstructionCount_L(Armada_PC_enqueue_write_index_update)\n    ==>\n    var pc := s.s.threads[tid1].pc;\n    var f := s.s.threads[tid1].top;\n    (\n      && (\n      PCToInstructionCount_L(Armada_PC_enqueue_tmp_write_index_init) < PCToInstructionCount_L(pc)\n      ==> f.enqueue.tmp_write_index == Armada_CastTo_uint64(f.enqueue.write_index as int + 1)\n      )\n\n      && (\n      PCToInstructionCount_L(Armada_PC_enqueue_modulo_init) < PCToInstructionCount_L(pc)\n      ==> s.s.mem.globals.queue.number_elements as int > 0 && f.enqueue.modulo == Armada_CastTo_uint64((f.enqueue.tmp_write_index as int % s.s.mem.globals.queue.number_elements as int) as int)\n      )\n    )\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// Invariant for queue.read_index := queue.read_indeax + 1;\n////////////////////////////////////////////////////////////////////////////////\n\npredicate DequeueReadIndexUpdateInvariant(s:LPlusState)\n{\n  forall tid2 :: tid2 in s.s.threads\n    && s.s.threads[tid2].top.Armada_StackFrame_dequeue?\n    && PCToInstructionCount_L(s.s.threads[tid2].pc) <= PCToInstructionCount_L(Armada_PC_dequeue_read_index_update)\n    ==>\n    var pc := s.s.threads[tid2].pc;\n    var f := s.s.threads[tid2].top;\n    (\n      && (\n      PCToInstructionCount_L(Armada_PC_dequeue_tmp_read_index_init) < PCToInstructionCount_L(pc)\n      ==> f.dequeue.tmp_read_index == Armada_CastTo_uint64(f.dequeue.read_index as int + 1)\n      )\n\n      && (\n      PCToInstructionCount_L(Armada_PC_dequeue_modulo_init) < PCToInstructionCount_L(pc)\n      ==> s.s.mem.globals.queue.number_elements as int > 0 && f.dequeue.modulo == Armada_CastTo_uint64((f.dequeue.tmp_read_index as int % s.s.mem.globals.queue.number_elements as int) as int)\n      )\n    )\n}\n\npredicate ThreadsInv(s:LPlusState)\n{\n        && (forall tid :: tid in s.s.threads ==> (s.s.threads[tid].top.Armada_StackFrame_main? <==> tid == s.config.tid_init))\n        && (forall tid1, tid2 :: tid1 in s.s.threads && tid2 in s.s.threads && s.s.threads[tid1].top.Armada_StackFrame_enqueue? && s.s.threads[tid2].top.Armada_StackFrame_enqueue? ==> tid1 == tid2)\n        && (forall tid1, tid2 :: tid1 in s.s.threads && tid2 in s.s.threads && s.s.threads[tid1].top.Armada_StackFrame_dequeue? && s.s.threads[tid2].top.Armada_StackFrame_dequeue? ==> tid1 == tid2)\n        && (forall tid1, tid2 :: tid1 in s.s.threads && tid2 in s.s.threads && s.s.threads[tid1].top.Armada_StackFrame_main? && PCToInstructionCount_L(s.s.threads[tid1].pc) <= PCToInstructionCount_L(L.Armada_PC_main_BeforeEnqueueCreate) ==> !s.s.threads[tid2].top.Armada_StackFrame_enqueue?)\n        && (forall tid1, tid2 :: tid1 in s.s.threads && tid2 in s.s.threads && s.s.threads[tid1].top.Armada_StackFrame_main? && PCToInstructionCount_L(s.s.threads[tid1].pc) <= PCToInstructionCount_L(L.Armada_PC_main_BeforeDequeueCreate) ==> !s.s.threads[tid2].top.Armada_StackFrame_dequeue?)\n        && (forall tid :: tid in s.s.threads ==> s.s.threads[tid].stack == [])\n        && (forall tid :: tid in s.s.threads ==> s.s.threads[tid].storeBuffer == [])\n        && (forall tid :: tid in s.s.threads && s.s.threads[tid].top.Armada_StackFrame_main? ==> s.s.threads[tid].storeBuffer == [])\n}\n\npredicate WeakeningInvariant_ext(s:LPlusState)\n{\n  && ThreadsInv(s)\n  && WeakHeapInvariant(s.s.mem.heap)\n\n  && MemorySafetyInvariant(s)\n\n    && EnqueueInitInvariant(s)\n    && DequeueReadIndexUpdateInvariant(s)\n    && IndicesProperties(s)\n    && IndicesAlwaysWithinBounds(s)\n\n    && DequeueInputPointersDoNotAliasElementArray(s)\n    && TmpIntProperties(s)\n\n    && EnqueueEIsEltArrayPlusWriteIndex(s)\n    && DequeueEisEltArrayPlusReadIndex(s)\n\n    && DequeueLocalNonEmptyImpliesGlobalNonEmpty(s)\n    && EnqueueLocalSpaceImpliesGlobalSpace(s)\n    && DequeueIfProperties(s)\n    && EnqueueIfProperties(s)\n    && BothIfProperties(s)\n\n    && EnqueueAfterAssignmentQueueMatchesKV(s)\n    && AbstractQueueMatchesImpl(s)\n\n    // && AbstractReadsMatchImplQueueValuesInDequeue(s)\n}\n\n}\n"
  },
  {
    "path": "Test/qbss/tau_invariant_helper.dfy",
    "content": "include \"QueueBSS_WithAbstractQueue.dfy\"\ninclude \"UseAbstractQueueForLog/specs.dfy\"\ninclude \"SharedStructs.dfy\"\ninclude \"auxiliary_helper.dfy\"\ninclude \"queue_abstractloginvariant.dfy\"\ninclude \"../../Armada/util/math/mod_auto.i.dfy\"\n\n\n  module tau_invariant_helper {\nimport opened ArmadaCommonDefinitions = ArmadaCommonDefinitions\nimport opened QueueBSS_WithAbstractQueue = QueueBSS_WithAbstractQueue\nimport opened ArmadaModule_specs = ArmadaModule_specs\nimport opened queue_abstractloginvariant = queue_abstractloginvariant\nimport opened Math__mod_auto_i = Math__mod_auto_i\nimport opened SharedStructs = SharedStructs\nimport opened auxiliary_helper = auxiliary_helper\n\nlemma {:verify false} ApplyStoreBufferMaintainsWeakHeapInvariant(mem: L.Armada_SharedMemory, buf:seq<L.Armada_StoreBufferEntry>, mem':L.Armada_SharedMemory)\n requires mem' == L.Armada_ApplyStoreBuffer(mem, buf)\n requires WeakHeapInvariant(mem.heap)\n ensures WeakHeapInvariant(mem'.heap)\n decreases |buf|\n{\n  if |buf| > 0 {\n    var mem_next := Armada_ApplyStoreBufferEntry(mem, buf[0]);\n    assert WeakHeapInvariant(mem_next.heap);\n    var mem_next' := L.Armada_ApplyStoreBuffer(mem_next, buf[1..]);\n    ApplyStoreBufferMaintainsWeakHeapInvariant(mem_next, buf[1..], mem_next');\n  }\n}\n\nlemma {:verify false} ApplyStoreBufferMaintainsWeakHeapInvariantAlways()\n ensures forall mem : L.Armada_SharedMemory, buf : seq<L.Armada_StoreBufferEntry> :: \n && WeakHeapInvariant(mem.heap)\n ==> WeakHeapInvariant(L.Armada_ApplyStoreBuffer(mem, buf).heap)\n{\n  forall mem : L.Armada_SharedMemory, buf : seq<L.Armada_StoreBufferEntry> | && WeakHeapInvariant(mem.heap)\n    ensures WeakHeapInvariant(L.Armada_ApplyStoreBuffer(mem, buf).heap)\n    {\n      ApplyStoreBufferMaintainsWeakHeapInvariant(mem, buf, L.Armada_ApplyStoreBuffer(mem, buf));\n    }\n}\n\nlemma {:verify false} lemma_HeapMetaDataUnchanged_PrimitiveProperties()\n  ensures forall h, h', p :: Armada_TriggerPointer(p) && Armada_HeapMetadataUnchangedByTau(h, h') ==> (\n  Armada_ValidPointerToPrimitive(h, p, Armada_PrimitiveType_uint64) ==> Armada_ValidPointerToPrimitive(h', p, Armada_PrimitiveType_uint64)\n  )\n{\n  \n}\n\nlemma {:verify false} lemma_HeapmetaDataUnchangedProperties()\n  ensures forall h, h', p :: Armada_TriggerPointer(p) && Armada_HeapMetadataUnchangedByTau(h, h') ==> (\n  Armada_ValidPointerToStructArray_BSSQueueElement(h, p) <==> Armada_ValidPointerToStructArray_BSSQueueElement(h', p)\n  )\n{\n  forall h, h', p : Armada_Pointer |\n    && Armada_TriggerPointer(p)\n    && Armada_HeapMetadataUnchangedByTau(h, h')\n    ensures (Armada_ValidPointerToStructArray_BSSQueueElement(h, p) ==> Armada_ValidPointerToStructArray_BSSQueueElement(h', p))\n  {\n    if (Armada_ValidPointerToStructArray_BSSQueueElement(h, p))\n    {\n      forall i |\n        0 <= i < h.tree[p].ty.sz\n\n        ensures Armada_ValidPointerToStruct_BSSQueueElement(h', h'.tree[p].children[Armada_FieldArrayIndex(i)])\n      {\n        var idx := Armada_FieldArrayIndex(i);\n        assert Armada_TriggerField(idx);\n        assert idx in h'.tree[p].children;\n        lemma_HeapMetaDataUnchanged_PrimitiveProperties();\n        assert Armada_ValidPointerToStruct_BSSQueueElement(h', h'.tree[p].children[idx]);\n      }\n      // && var ty := h.tree[p].ty; ty.Armada_ObjectType_array? && ty.subtype.Armada_ObjectType_struct? && ty.subtype.s.Armada_StructType_BSSQueueElement? && ty.sz >= 0 && forall i :: 0 <= i < ty.sz ==> var idx := Armada_FieldArrayIndex(i); Armada_TriggerField(idx) && idx in h.tree[p].children && Armada_ValidPointerToStruct_BSSQueueElement(h, h.tree[p].children[idx])\n\n      assert Armada_ValidPointerToStructArray_BSSQueueElement(h', p);\n    }\n  }\n}\n\nlemma {:verify false} lemma_ApplyStoreBufferMaintainsMemorySafety(mem:Armada_SharedMemory, buf:seq<Armada_StoreBufferEntry>, mem':Armada_SharedMemory)\n  requires WeakHeapInvariant(mem.heap)\n  requires WeakHeapInvariant(mem'.heap)\n  requires MemorySafetyElementArray(mem)\n  requires mem'.globals.queue.number_elements == mem.globals.queue.number_elements\n  requires mem'.globals.queue.element_array == mem.globals.queue.element_array\n  requires mem'.heap.tree == mem.heap.tree\n  requires mem'.heap.valid == mem.heap.valid\n  requires mem'.heap.freed == mem.heap.freed\n\n  ensures MemorySafetyElementArray(mem')\n{\n  var e' := mem'.globals.queue.element_array;\n  var a' := mem'.heap.tree[e'].parent;\n  assert Armada_TriggerPointer(a');\n  lemma_HeapmetaDataUnchangedProperties();\n\n  // assert Armada_ValidPointerToStructSizedArray_BSSQueueElement(mem'.heap, a', mem.globals.queue.number_elements as int);\n  /*\n  assert forall i :: 0 <= i < s'.s.mem.globals.queue.number_elements as int ==> Armada_TriggerField<Armada_FieldType>(Armada_FieldArrayIndex(i));\n  assert s'.s.mem.heap.tree == locv'.heap.tree;\n  assert Armada_ValidPointerToStructArray_BSSQueueElement(locv'.heap, a');\n  assert Armada_ValidPointerToStructSizedArray_BSSQueueElement(locv'.heap, a', s'.s.mem.globals.queue.number_elements as int);\n   */\n}\n\nlemma lemma_ApplyStoreBufferPreservesValuesMetadata(mem:Armada_SharedMemory, buf:seq<Armada_StoreBufferEntry>, mem':Armada_SharedMemory)\n  requires mem' == L.Armada_ApplyStoreBuffer(mem, buf)\n  ensures forall p :: p in mem.heap.values ==> p in mem'.heap.values;\n  ensures forall p :: p in mem.heap.values && mem.heap.values[p].Armada_PrimitiveValue_uint64?\n    ==> p in mem'.heap.values && mem'.heap.values[p].Armada_PrimitiveValue_uint64?;\n{\n  if |buf| > 0 {\n    var mem_next := Armada_ApplyStoreBufferEntry(mem, buf[0]);\n    var mem_next' := L.Armada_ApplyStoreBuffer(mem_next, buf[1..]);\n\n    assert forall p :: p in mem.heap.values ==> p in mem_next.heap.values;\n    assert forall p :: p in mem.heap.values && mem.heap.values[p].Armada_PrimitiveValue_uint64?\n      ==> p in mem_next.heap.values && mem_next.heap.values[p].Armada_PrimitiveValue_uint64?;\n\n    ApplyStoreBufferMaintainsWeakHeapInvariant(mem_next, buf[1..], mem_next');\n  }\n}\n\nlemma lemma_DequeueDoesNotConcernImpliesElementArrayLocalMatchesGlobal(s:LPlusState, s':LPlusState, step: L.Armada_TraceEntry)\n  requires WeakeningInvariant_ext(s)\n  requires step.Armada_TraceEntry_Tau?\n  requires LPlus_NextOneStep(s, s', step)\n  ensures DequeueDoesNotConcernQbssElement(s') && ElementArrayDeqLocalMatchesGlobal(s')\n{\n  lemma_VariableUnchangedAndStoreBufferSameImpliesLocalViewIsSame();\n  lemma_IfStoreBufferLacksIndicesThenViewMatchesAlways();\n  ApplyStoreBufferMaintainsWeakHeapInvariantAlways();\n\n  forall tid | tid in s'.s.threads && tid != step.tid\n    && s'.s.threads[tid].top.Armada_StackFrame_dequeue?\n    ensures ElementArrayLocalViewMatchesGlobal(s', tid)\n    {\n      forall j |\n        0 <= j < s.s.mem.globals.queue.number_elements as int\n        && Queue_TriggerIndex(j)\n        ensures StoreBufferDoesNotConcernQbssElement(s'.s.threads[tid].storeBuffer, s'.s.mem, j)\n      {\n        assert StoreBufferDoesNotConcernQbssElement(s.s.threads[tid].storeBuffer, s.s.mem, j);\n      }\n      assert DequeueDoesNotConcernQbssElement(s');\n\n      var locv' := L.Armada_GetThreadLocalView(s'.s, tid);\n\n      var buf := s'.s.threads[tid].storeBuffer;\n      assume |buf| > 0;\n\n      assert WeakHeapInvariant(s'.s.mem.heap);\n      lemma_ApplyStoreBufferPreservesValuesMetadata(s'.s.mem, buf, locv');\n      assert forall p :: p in s'.s.mem.heap.values ==> p in locv'.heap.values;\n      assert forall p :: p in s'.s.mem.heap.values && s'.s.mem.heap.values[p].Armada_PrimitiveValue_uint64?\n        ==> p in locv'.heap.values && locv'.heap.values[p].Armada_PrimitiveValue_uint64?;\n\n      assert Armada_HeapMetadataUnchangedByTau(s'.s.mem.heap, locv'.heap);\n      assert WeakHeapInvariant(locv'.heap);\n      assert MemorySafetyElementArray(s'.s.mem);\n      assert locv'.globals.queue.number_elements as int == s'.s.mem.globals.queue.number_elements as int;\n      assert locv'.globals.queue.element_array as int == s'.s.mem.globals.queue.element_array as int;\n\n      assert MemorySafetyElementArray(locv');\n\n      forall j |\n        0 <= j < s'.s.mem.globals.queue.number_elements as int\n        && Queue_TriggerIndex(j)\n        ensures GetQbssElement(locv', j) == GetQbssElement(s'.s.mem, j)\n      {\n        assert StoreBufferDoesNotConcernQbssElement(buf, s'.s.mem, j);\n        assert StoreBufferDoesNotConcernAddress(buf, GetPointerToQbssElementKey(s'.s.mem, j));\n        assert StoreBufferDoesNotConcernAddress(buf, GetPointerToQbssElementValue(s'.s.mem, j));\n\n        lemma_IfStoreBufferDoesNotConcernAddressThenViewMatchesAlways(GetPointerToQbssElementKey(s'.s.mem, j));\n        lemma_IfStoreBufferDoesNotConcernAddressThenViewMatchesAlways(GetPointerToQbssElementValue(s'.s.mem, j));\n      }\n    }\n}\n\n    lemma {:verify false} lemma_InvariantPredicateMaintainedByNext_WeakeningInvariant_Tau_dequeue(s: LPlusState, s': LPlusState, step: L.Armada_TraceEntry)\n      requires WeakeningInvariant_ext(s)\n      requires step.Armada_TraceEntry_Tau?\n      requires LPlus_NextOneStep(s, s', step)\n      requires s.s.threads[step.tid].top.Armada_StackFrame_dequeue?\n      ensures WeakeningInvariant_ext(s')\n    {\n      // assert s'.s.mem.globals.queue.read_index == s.s.mem.globals.queue.read_index;\n      // assert s'.s.mem.globals.queue.element_array == s.s.mem.globals.queue.element_array;\n\n      lemma_VariableUnchangedAndStoreBufferSameImpliesLocalViewIsSame();\n      lemma_mod_auto(s.s.mem.globals.queue.number_elements as int);\n      lemma_IfStoreBufferLacksIndicesThenViewMatchesAlways();\n      lemma_DequeueDoesNotConcernImpliesElementArrayLocalMatchesGlobal(s, s', step);\n\n      assert forall entry :: entry in s'.s.threads[step.tid].storeBuffer ==> entry in s.s.threads[step.tid].storeBuffer;\n      assert s'.s.mem.globals.queue.number_elements == s.s.mem.globals.queue.number_elements;\n      assert WeakeningInvariant_ext(s');\n    }\n\n    lemma {:verify false} lemma_Tau_enqueue_maintains_AuxDescribesStoreBuffer(s: LPlusState, s': LPlusState, step: L.Armada_TraceEntry)\n      requires AuxDescribesStoreBuffer(s)\n      requires ThreadsInv(s)\n      requires step.Armada_TraceEntry_Tau?\n      requires LPlus_NextOneStep(s, s', step)\n      requires s.s.threads[step.tid].top.Armada_StackFrame_enqueue?\n      ensures AuxDescribesStoreBuffer(s');\n    {\n      var tid1 := step.tid;\n      if s.w_i_seq != []\n      {\n        if s.w_i_seq[0].position > 0 {\n\n          forall i | 0 <= i < |s'.s.threads[tid1].storeBuffer|\n            && s'.s.threads[tid1].storeBuffer[i].loc == L.Armada_StoreBufferLocation_Unaddressable(L.Armada_GlobalStaticVar_queue, [Armada_FieldStruct(Armada_FieldType_QbssState'write_index)])\n            ensures\n            && s'.s.threads[tid1].storeBuffer[i].value.Armada_PrimitiveValue_uint64?\n            && WriteIndexSBEntry(i, s'.s.threads[tid1].storeBuffer[i].value.n_uint64) in s'.w_i_seq\n          {\n            var sb' := s'.s.threads[tid1].storeBuffer;\n            var sb := s.s.threads[tid1].storeBuffer;\n            // assert sb'[i] == sb[i + 1];\n            // assert sb[i + 1].loc == L.Armada_StoreBufferLocation_Unaddressable(L.Armada_GlobalStaticVar_queue, [Armada_FieldStruct(Armada_FieldType_QbssState'write_index)]);\n\n            // assert sb[i + 1].value.Armada_PrimitiveValue_uint64?;\n            // assert WriteIndexSBEntry(i + 1, sb'[i].value.n_uint64) in s.w_i_seq;\n            assert DecrementPosition(WriteIndexSBEntry(i + 1, sb'[i].value.n_uint64)) in s'.w_i_seq;\n            // assert WriteIndexSBEntry(i, sb'[i].value.n_uint64) in s'.w_i_seq;\n          }\n\n          assert AuxDescribesStoreBuffer(s');\n        }\n        else {\n          forall i | 0 <= i < |s'.s.threads[tid1].storeBuffer|\n            && s'.s.threads[tid1].storeBuffer[i].loc == L.Armada_StoreBufferLocation_Unaddressable(L.Armada_GlobalStaticVar_queue, [Armada_FieldStruct(Armada_FieldType_QbssState'write_index)])\n            ensures\n            && s'.s.threads[tid1].storeBuffer[i].value.Armada_PrimitiveValue_uint64?\n            && WriteIndexSBEntry(i, s'.s.threads[tid1].storeBuffer[i].value.n_uint64) in s'.w_i_seq\n          {\n            var sb' := s'.s.threads[tid1].storeBuffer;\n            var sb := s.s.threads[tid1].storeBuffer;\n            // assert sb'[i] == sb[i + 1];\n            // assert sb[i + 1].loc == L.Armada_StoreBufferLocation_Unaddressable(L.Armada_GlobalStaticVar_queue, [Armada_FieldStruct(Armada_FieldType_QbssState'write_index)]);\n\n            // assert sb[i + 1].value.Armada_PrimitiveValue_uint64?;\n            // assert WriteIndexSBEntry(i + 1, sb'[i].value.n_uint64) in s.w_i_seq;\n            assert DecrementPosition(WriteIndexSBEntry(i + 1, sb'[i].value.n_uint64)) in s'.w_i_seq;\n            // assert WriteIndexSBEntry(i, sb'[i].value.n_uint64) in s'.w_i_seq;\n          }\n\n          assert AuxDescribesStoreBuffer(s');\n        }\n      }\n    }\n\n    lemma {:verify false} lemma_InvariantPredicateMaintainedByNext_WeakeningInvariant_Tau_enqueue(s: LPlusState, s': LPlusState, step: L.Armada_TraceEntry)\n      requires WeakeningInvariant_ext(s)\n      requires step.Armada_TraceEntry_Tau?\n      requires LPlus_NextOneStep(s, s', step)\n      requires s.s.threads[step.tid].top.Armada_StackFrame_enqueue?\n      ensures WeakeningInvariant_ext(s')\n    {\n      // assert s'.s.mem.globals.queue.read_index == s.s.mem.globals.queue.read_index;\n      // assert s'.s.mem.globals.queue.element_array == s.s.mem.globals.queue.element_array;\n      // assert s'.s.mem.globals.queue.number_elements == s.s.mem.globals.queue.number_elements;\n\n      lemma_Tau_enqueue_maintains_AuxDescribesStoreBuffer(s, s', step);\n      assert AuxDescribesStoreBuffer(s');\n      lemma_DequeueDoesNotConcernImpliesElementArrayLocalMatchesGlobal(s, s', step);\n\n      lemma_VariableUnchangedAndStoreBufferSameImpliesLocalViewIsSame();\n      lemma_mod_auto(s.s.mem.globals.queue.number_elements as int);\n      lemma_IfStoreBufferLacksIndicesThenViewMatchesAlways();\n      assert DequeueLocalSpaceImpliesGlobalSpace(s');\n      assert WeakeningInvariant_ext(s');\n    }\n\n  lemma {:verify false} lemma_IfVarUnchangedAndStoreBufferUnchangedThenViewUnchanged_L_read_index(mem1: L.Armada_SharedMemory, mem2: L.Armada_SharedMemory, buf: seq<L.Armada_StoreBufferEntry>)\n    requires mem1.globals.queue.read_index == mem2.globals.queue.read_index\n    ensures L.Armada_ApplyStoreBuffer(mem1, buf).globals.queue.read_index == L.Armada_ApplyStoreBuffer(mem2, buf).globals.queue.read_index\n    decreases |buf|\n  {\n    if |buf| > 0 {\n      var mem1' := L.Armada_ApplyStoreBufferEntry(mem1, buf[0]);\n      var mem2' := L.Armada_ApplyStoreBufferEntry(mem2, buf[0]);\n      lemma_IfVarUnchangedAndStoreBufferUnchangedThenViewUnchanged_L_read_index(mem1', mem2', buf[1..]);\n    }\n  }\n\n  lemma {:verify false} lemma_VariableUnchangedAndStoreBufferSameImpliesLocalViewIsSame_read_index()\n    ensures forall mem1: L.Armada_SharedMemory, mem2: L.Armada_SharedMemory, buf: seq<L.Armada_StoreBufferEntry> {:trigger L.Armada_ApplyStoreBuffer(mem1, buf), L.Armada_ApplyStoreBuffer(mem2, buf)} :: && mem1.globals.queue.read_index == mem2.globals.queue.read_index ==> L.Armada_ApplyStoreBuffer(mem1, buf).globals.queue.read_index == L.Armada_ApplyStoreBuffer(mem2, buf).globals.queue.read_index\n\n    {\n      forall mem1: L.Armada_SharedMemory, mem2: L.Armada_SharedMemory, buf: seq<L.Armada_StoreBufferEntry> {:trigger L.Armada_ApplyStoreBuffer(mem1, buf), L.Armada_ApplyStoreBuffer(mem2, buf)}\n       | && mem1.globals.queue.read_index == mem2.globals.queue.read_index\n        ensures L.Armada_ApplyStoreBuffer(mem1, buf).globals.queue.read_index == L.Armada_ApplyStoreBuffer(mem2, buf).globals.queue.read_index\n        {\n          lemma_IfVarUnchangedAndStoreBufferUnchangedThenViewUnchanged_L_read_index(mem1, mem2, buf);\n        }\n    }\n\n  lemma {:verify false} lemma_IfVarUnchangedAndStoreBufferUnchangedThenViewUnchanged_L_write_index(mem1: L.Armada_SharedMemory, mem2: L.Armada_SharedMemory, buf: seq<L.Armada_StoreBufferEntry>)\n    requires mem1.globals.queue.write_index == mem2.globals.queue.write_index\n    ensures L.Armada_ApplyStoreBuffer(mem1, buf).globals.queue.write_index == L.Armada_ApplyStoreBuffer(mem2, buf).globals.queue.write_index\n    decreases |buf|\n  {\n    if |buf| > 0 {\n      var mem1' := L.Armada_ApplyStoreBufferEntry(mem1, buf[0]);\n      var mem2' := L.Armada_ApplyStoreBufferEntry(mem2, buf[0]);\n      lemma_IfVarUnchangedAndStoreBufferUnchangedThenViewUnchanged_L_write_index(mem1', mem2', buf[1..]);\n    }\n  }\n\n  lemma {:verify false} lemma_VariableUnchangedAndStoreBufferSameImpliesLocalViewIsSame_write_index()\n    ensures forall mem1: L.Armada_SharedMemory, mem2: L.Armada_SharedMemory, buf: seq<L.Armada_StoreBufferEntry> {:trigger L.Armada_ApplyStoreBuffer(mem1, buf), L.Armada_ApplyStoreBuffer(mem2, buf)} :: && mem1.globals.queue.write_index == mem2.globals.queue.write_index ==> L.Armada_ApplyStoreBuffer(mem1, buf).globals.queue.write_index == L.Armada_ApplyStoreBuffer(mem2, buf).globals.queue.write_index\n\n    {\n      forall mem1: L.Armada_SharedMemory, mem2: L.Armada_SharedMemory, buf: seq<L.Armada_StoreBufferEntry> {:trigger L.Armada_ApplyStoreBuffer(mem1, buf), L.Armada_ApplyStoreBuffer(mem2, buf)}\n       | && mem1.globals.queue.write_index == mem2.globals.queue.write_index\n        ensures L.Armada_ApplyStoreBuffer(mem1, buf).globals.queue.write_index == L.Armada_ApplyStoreBuffer(mem2, buf).globals.queue.write_index\n        {\n          lemma_IfVarUnchangedAndStoreBufferUnchangedThenViewUnchanged_L_write_index(mem1, mem2, buf);\n        }\n    }\n\n  lemma {:verify false} lemma_IfVarUnchangedAndStoreBufferUnchangedThenViewUnchanged_L_number_elements(mem1: L.Armada_SharedMemory, mem2: L.Armada_SharedMemory, buf: seq<L.Armada_StoreBufferEntry>)\n    requires mem1.globals.queue.number_elements == mem2.globals.queue.number_elements\n    ensures L.Armada_ApplyStoreBuffer(mem1, buf).globals.queue.number_elements == L.Armada_ApplyStoreBuffer(mem2, buf).globals.queue.number_elements\n    decreases |buf|\n  {\n    if |buf| > 0 {\n      var mem1' := L.Armada_ApplyStoreBufferEntry(mem1, buf[0]);\n      var mem2' := L.Armada_ApplyStoreBufferEntry(mem2, buf[0]);\n      lemma_IfVarUnchangedAndStoreBufferUnchangedThenViewUnchanged_L_number_elements(mem1', mem2', buf[1..]);\n    }\n  }\n\n  lemma {:verify false} lemma_VariableUnchangedAndStoreBufferSameImpliesLocalViewIsSame_number_elements()\n    ensures forall mem1: L.Armada_SharedMemory, mem2: L.Armada_SharedMemory, buf: seq<L.Armada_StoreBufferEntry> {:trigger L.Armada_ApplyStoreBuffer(mem1, buf), L.Armada_ApplyStoreBuffer(mem2, buf)} :: && mem1.globals.queue.number_elements == mem2.globals.queue.number_elements ==> L.Armada_ApplyStoreBuffer(mem1, buf).globals.queue.number_elements == L.Armada_ApplyStoreBuffer(mem2, buf).globals.queue.number_elements\n\n  {\n    forall mem1: L.Armada_SharedMemory, mem2: L.Armada_SharedMemory, buf: seq<L.Armada_StoreBufferEntry> {:trigger L.Armada_ApplyStoreBuffer(mem1, buf), L.Armada_ApplyStoreBuffer(mem2, buf)}\n    | && mem1.globals.queue.number_elements == mem2.globals.queue.number_elements\n      ensures L.Armada_ApplyStoreBuffer(mem1, buf).globals.queue.number_elements == L.Armada_ApplyStoreBuffer(mem2, buf).globals.queue.number_elements\n        {\n          lemma_IfVarUnchangedAndStoreBufferUnchangedThenViewUnchanged_L_number_elements(mem1, mem2, buf);\n        }\n  }\n\n  lemma {:verify false} lemma_IfVarUnchangedAndStoreBufferUnchangedThenViewUnchanged_L_element_array(mem1: L.Armada_SharedMemory, mem2: L.Armada_SharedMemory, buf: seq<L.Armada_StoreBufferEntry>)\n    requires mem1.globals.queue.element_array == mem2.globals.queue.element_array\n    ensures L.Armada_ApplyStoreBuffer(mem1, buf).globals.queue.element_array == L.Armada_ApplyStoreBuffer(mem2, buf).globals.queue.element_array\n    decreases |buf|\n  {\n    if |buf| > 0 {\n      var mem1' := L.Armada_ApplyStoreBufferEntry(mem1, buf[0]);\n      var mem2' := L.Armada_ApplyStoreBufferEntry(mem2, buf[0]);\n      lemma_IfVarUnchangedAndStoreBufferUnchangedThenViewUnchanged_L_element_array(mem1', mem2', buf[1..]);\n    }\n  }\n\n  lemma {:verify false} lemma_VariableUnchangedAndStoreBufferSameImpliesLocalViewIsSame_element_array()\n    ensures forall mem1: L.Armada_SharedMemory, mem2: L.Armada_SharedMemory, buf: seq<L.Armada_StoreBufferEntry> {:trigger L.Armada_ApplyStoreBuffer(mem1, buf), L.Armada_ApplyStoreBuffer(mem2, buf)} :: && mem1.globals.queue.element_array == mem2.globals.queue.element_array ==> L.Armada_ApplyStoreBuffer(mem1, buf).globals.queue.element_array == L.Armada_ApplyStoreBuffer(mem2, buf).globals.queue.element_array\n\n  {\n    forall mem1: L.Armada_SharedMemory, mem2: L.Armada_SharedMemory, buf: seq<L.Armada_StoreBufferEntry> {:trigger L.Armada_ApplyStoreBuffer(mem1, buf), L.Armada_ApplyStoreBuffer(mem2, buf)}\n    | && mem1.globals.queue.element_array == mem2.globals.queue.element_array\n      ensures L.Armada_ApplyStoreBuffer(mem1, buf).globals.queue.element_array == L.Armada_ApplyStoreBuffer(mem2, buf).globals.queue.element_array\n        {\n          lemma_IfVarUnchangedAndStoreBufferUnchangedThenViewUnchanged_L_element_array(mem1, mem2, buf);\n        }\n  }\n\n  lemma {:verify false} lemma_VariableUnchangedAndStoreBufferSameImpliesLocalViewIsSame()\n    ensures forall mem1: L.Armada_SharedMemory, mem2: L.Armada_SharedMemory, buf: seq<L.Armada_StoreBufferEntry> {:trigger L.Armada_ApplyStoreBuffer(mem1, buf), L.Armada_ApplyStoreBuffer(mem2, buf)} :: && mem1.globals.queue.read_index == mem2.globals.queue.read_index ==> L.Armada_ApplyStoreBuffer(mem1, buf).globals.queue.read_index == L.Armada_ApplyStoreBuffer(mem2, buf).globals.queue.read_index\n    ensures forall mem1: L.Armada_SharedMemory, mem2: L.Armada_SharedMemory, buf: seq<L.Armada_StoreBufferEntry> {:trigger L.Armada_ApplyStoreBuffer(mem1, buf), L.Armada_ApplyStoreBuffer(mem2, buf)} :: && mem1.globals.queue.write_index == mem2.globals.queue.write_index ==> L.Armada_ApplyStoreBuffer(mem1, buf).globals.queue.write_index == L.Armada_ApplyStoreBuffer(mem2, buf).globals.queue.write_index\n    ensures forall mem1: L.Armada_SharedMemory, mem2: L.Armada_SharedMemory, buf: seq<L.Armada_StoreBufferEntry> {:trigger L.Armada_ApplyStoreBuffer(mem1, buf), L.Armada_ApplyStoreBuffer(mem2, buf)} :: && mem1.globals.queue.number_elements == mem2.globals.queue.number_elements ==> L.Armada_ApplyStoreBuffer(mem1, buf).globals.queue.number_elements == L.Armada_ApplyStoreBuffer(mem2, buf).globals.queue.number_elements\n    ensures forall mem1: L.Armada_SharedMemory, mem2: L.Armada_SharedMemory, buf: seq<L.Armada_StoreBufferEntry> {:trigger L.Armada_ApplyStoreBuffer(mem1, buf), L.Armada_ApplyStoreBuffer(mem2, buf)} :: && mem1.globals.queue.element_array == mem2.globals.queue.element_array ==> L.Armada_ApplyStoreBuffer(mem1, buf).globals.queue.element_array == L.Armada_ApplyStoreBuffer(mem2, buf).globals.queue.element_array\n  {\n    lemma_VariableUnchangedAndStoreBufferSameImpliesLocalViewIsSame_read_index();\n    lemma_VariableUnchangedAndStoreBufferSameImpliesLocalViewIsSame_write_index();\n    lemma_VariableUnchangedAndStoreBufferSameImpliesLocalViewIsSame_number_elements();\n    lemma_VariableUnchangedAndStoreBufferSameImpliesLocalViewIsSame_element_array();\n  }\n\n  predicate {:verify false} StoreBufferLocationConcernsVar_L_write_index(loc: L.Armada_StoreBufferLocation)\n  {\n    && loc == L.Armada_StoreBufferLocation_Unaddressable(L.Armada_GlobalStaticVar_queue, [Armada_FieldStruct(Armada_FieldType_QbssState'write_index)])\n  }\n\n  predicate {:verify false} StoreBufferLacksIndices_L_write_index(buf: seq<L.Armada_StoreBufferEntry>)\n  {\n    forall entry ::\n      entry in buf ==>\n        !StoreBufferLocationConcernsVar_L_write_index(entry.loc)\n  }\n\n  lemma {:verify false} lemma_IfStoreBufferLacksIndicesThenViewMatches_L_write_index(mem: L.Armada_SharedMemory, buf: seq<L.Armada_StoreBufferEntry>, mem': L.Armada_SharedMemory)\n    requires StoreBufferLacksIndices_L_write_index(buf)\n    requires mem' == L.Armada_ApplyStoreBuffer(mem, buf)\n    ensures mem'.globals.queue.write_index == mem.globals.queue.write_index\n    decreases |buf|\n  {\n    if |buf| > 0 {\n      var mem_next := L.Armada_ApplyStoreBufferEntry(mem, buf[0]);\n      assert mem_next.globals.queue.write_index == mem.globals.queue.write_index;\n      var mem_next' := L.Armada_ApplyStoreBuffer(mem_next, buf[1..]);\n      lemma_IfStoreBufferLacksIndicesThenViewMatches_L_write_index(mem_next, buf[1..], mem_next');\n    }\n  }\n\n  lemma {:verify false} lemma_IfStoreBufferLacksIndicesThenViewMatchesAlways_L_write_index()\n    ensures forall mem: L.Armada_SharedMemory, buf: seq<L.Armada_StoreBufferEntry> :: StoreBufferLacksIndices_L_write_index(buf) ==> L.Armada_ApplyStoreBuffer(mem, buf).globals.queue.write_index == mem.globals.queue.write_index\n  {\n    forall mem: L.Armada_SharedMemory, buf: seq<L.Armada_StoreBufferEntry> | StoreBufferLacksIndices_L_write_index(buf)\n      ensures L.Armada_ApplyStoreBuffer(mem, buf).globals.queue.write_index == mem.globals.queue.write_index\n    {\n      var mem' := L.Armada_ApplyStoreBuffer(mem, buf);\n      lemma_IfStoreBufferLacksIndicesThenViewMatches_L_write_index(mem, buf, mem');\n    }\n  }\n\n\n  predicate {:verify false} StoreBufferLocationConcernsVar_L_read_index(loc: L.Armada_StoreBufferLocation)\n  {\n    && loc == L.Armada_StoreBufferLocation_Unaddressable(L.Armada_GlobalStaticVar_queue, [Armada_FieldStruct(Armada_FieldType_QbssState'read_index)])\n  }\n\n  predicate {:verify false} StoreBufferLacksIndices_L_read_index(buf: seq<L.Armada_StoreBufferEntry>)\n  {\n    forall entry ::\n      entry in buf ==>\n        !StoreBufferLocationConcernsVar_L_read_index(entry.loc)\n  }\n\n  lemma {:verify false} lemma_IfStoreBufferLacksIndicesThenViewMatches_L_read_index(mem: L.Armada_SharedMemory, buf: seq<L.Armada_StoreBufferEntry>, mem': L.Armada_SharedMemory)\n    requires StoreBufferLacksIndices_L_read_index(buf)\n    requires mem' == L.Armada_ApplyStoreBuffer(mem, buf)\n    ensures mem'.globals.queue.read_index == mem.globals.queue.read_index\n    decreases |buf|\n  {\n    if |buf| > 0 {\n      var mem_next := L.Armada_ApplyStoreBufferEntry(mem, buf[0]);\n      assert mem_next.globals.queue.read_index == mem.globals.queue.read_index;\n      var mem_next' := L.Armada_ApplyStoreBuffer(mem_next, buf[1..]);\n      lemma_IfStoreBufferLacksIndicesThenViewMatches_L_read_index(mem_next, buf[1..], mem_next');\n    }\n  }\n\n  lemma {:verify false} lemma_IfStoreBufferLacksIndicesThenViewMatchesAlways_L_read_index()\n    ensures forall mem: L.Armada_SharedMemory, buf: seq<L.Armada_StoreBufferEntry> :: StoreBufferLacksIndices_L_read_index(buf) ==> L.Armada_ApplyStoreBuffer(mem, buf).globals.queue.read_index == mem.globals.queue.read_index\n  {\n    forall mem: L.Armada_SharedMemory, buf: seq<L.Armada_StoreBufferEntry> | StoreBufferLacksIndices_L_read_index(buf)\n      ensures L.Armada_ApplyStoreBuffer(mem, buf).globals.queue.read_index == mem.globals.queue.read_index\n    {\n      var mem' := L.Armada_ApplyStoreBuffer(mem, buf);\n      lemma_IfStoreBufferLacksIndicesThenViewMatches_L_read_index(mem, buf, mem');\n    }\n  }\n\n\n  predicate {:verify false} StoreBufferLocationConcernsVar_L_number_elements(loc: L.Armada_StoreBufferLocation)\n  {\n    && loc == L.Armada_StoreBufferLocation_Unaddressable(L.Armada_GlobalStaticVar_queue, [Armada_FieldStruct(Armada_FieldType_QbssState'number_elements)])\n  }\n\n  predicate {:verify false} StoreBufferLacksIndices_L_number_elements(buf: seq<L.Armada_StoreBufferEntry>)\n  {\n    forall entry ::\n      entry in buf ==>\n        !StoreBufferLocationConcernsVar_L_number_elements(entry.loc)\n  }\n\n  lemma {:verify false} lemma_IfStoreBufferLacksIndicesThenViewMatches_L_number_elements(mem: L.Armada_SharedMemory, buf: seq<L.Armada_StoreBufferEntry>, mem': L.Armada_SharedMemory)\n    requires StoreBufferLacksIndices_L_number_elements(buf)\n    requires mem' == L.Armada_ApplyStoreBuffer(mem, buf)\n    ensures mem'.globals.queue.number_elements == mem.globals.queue.number_elements\n    decreases |buf|\n  {\n    if |buf| > 0 {\n      var mem_next := L.Armada_ApplyStoreBufferEntry(mem, buf[0]);\n      assert mem_next.globals.queue.number_elements == mem.globals.queue.number_elements;\n      var mem_next' := L.Armada_ApplyStoreBuffer(mem_next, buf[1..]);\n      lemma_IfStoreBufferLacksIndicesThenViewMatches_L_number_elements(mem_next, buf[1..], mem_next');\n    }\n  }\n\n  lemma {:verify false} lemma_IfStoreBufferLacksIndicesThenViewMatchesAlways_L_number_elements()\n    ensures forall mem: L.Armada_SharedMemory, buf: seq<L.Armada_StoreBufferEntry> :: StoreBufferLacksIndices_L_number_elements(buf) ==> L.Armada_ApplyStoreBuffer(mem, buf).globals.queue.number_elements == mem.globals.queue.number_elements\n  {\n    forall mem: L.Armada_SharedMemory, buf: seq<L.Armada_StoreBufferEntry> | StoreBufferLacksIndices_L_number_elements(buf)\n      ensures L.Armada_ApplyStoreBuffer(mem, buf).globals.queue.number_elements == mem.globals.queue.number_elements\n    {\n      var mem' := L.Armada_ApplyStoreBuffer(mem, buf);\n      lemma_IfStoreBufferLacksIndicesThenViewMatches_L_number_elements(mem, buf, mem');\n    }\n  }\n\n\n  predicate {:verify false} StoreBufferLocationConcernsVar_L_element_array(loc: L.Armada_StoreBufferLocation)\n  {\n    && loc == L.Armada_StoreBufferLocation_Unaddressable(L.Armada_GlobalStaticVar_queue, [Armada_FieldStruct(Armada_FieldType_QbssState'element_array)])\n  }\n\n  predicate {:verify false} StoreBufferLacksIndices_L_element_array(buf: seq<L.Armada_StoreBufferEntry>)\n  {\n    forall entry ::\n      entry in buf ==>\n        !StoreBufferLocationConcernsVar_L_element_array(entry.loc)\n  }\n\n  lemma {:verify false} lemma_IfStoreBufferLacksIndicesThenViewMatches_L_element_array(mem: L.Armada_SharedMemory, buf: seq<L.Armada_StoreBufferEntry>, mem': L.Armada_SharedMemory)\n    requires StoreBufferLacksIndices_L_element_array(buf)\n    requires mem' == L.Armada_ApplyStoreBuffer(mem, buf)\n    ensures mem'.globals.queue.element_array == mem.globals.queue.element_array\n    decreases |buf|\n  {\n    if |buf| > 0 {\n      var mem_next := L.Armada_ApplyStoreBufferEntry(mem, buf[0]);\n      assert mem_next.globals.queue.element_array == mem.globals.queue.element_array;\n      var mem_next' := L.Armada_ApplyStoreBuffer(mem_next, buf[1..]);\n      lemma_IfStoreBufferLacksIndicesThenViewMatches_L_element_array(mem_next, buf[1..], mem_next');\n    }\n  }\n\n  lemma {:verify false} lemma_IfStoreBufferLacksIndicesThenViewMatchesAlways_L_element_array()\n    ensures forall mem: L.Armada_SharedMemory, buf: seq<L.Armada_StoreBufferEntry> :: StoreBufferLacksIndices_L_element_array(buf) ==> L.Armada_ApplyStoreBuffer(mem, buf).globals.queue.element_array == mem.globals.queue.element_array\n  {\n    forall mem: L.Armada_SharedMemory, buf: seq<L.Armada_StoreBufferEntry> | StoreBufferLacksIndices_L_element_array(buf)\n      ensures L.Armada_ApplyStoreBuffer(mem, buf).globals.queue.element_array == mem.globals.queue.element_array\n    {\n      var mem' := L.Armada_ApplyStoreBuffer(mem, buf);\n      lemma_IfStoreBufferLacksIndicesThenViewMatches_L_element_array(mem, buf, mem');\n    }\n  }\n\n  lemma {:verify false} lemma_IfStoreBufferLacksIndicesThenViewMatchesAlways()\n    ensures forall mem: L.Armada_SharedMemory, buf: seq<L.Armada_StoreBufferEntry> :: StoreBufferLacksIndices_L_element_array(buf) ==> L.Armada_ApplyStoreBuffer(mem, buf).globals.queue.element_array == mem.globals.queue.element_array\n    ensures forall mem: L.Armada_SharedMemory, buf: seq<L.Armada_StoreBufferEntry> :: StoreBufferLacksIndices_L_number_elements(buf) ==> L.Armada_ApplyStoreBuffer(mem, buf).globals.queue.number_elements == mem.globals.queue.number_elements\n    ensures forall mem: L.Armada_SharedMemory, buf: seq<L.Armada_StoreBufferEntry> :: StoreBufferLacksIndices_L_write_index(buf) ==> L.Armada_ApplyStoreBuffer(mem, buf).globals.queue.write_index == mem.globals.queue.write_index\n    ensures forall mem: L.Armada_SharedMemory, buf: seq<L.Armada_StoreBufferEntry> :: StoreBufferLacksIndices_L_read_index(buf) ==> L.Armada_ApplyStoreBuffer(mem, buf).globals.queue.read_index == mem.globals.queue.read_index\n  {\n    lemma_IfStoreBufferLacksIndicesThenViewMatchesAlways_L_element_array();\n    lemma_IfStoreBufferLacksIndicesThenViewMatchesAlways_L_number_elements();\n    lemma_IfStoreBufferLacksIndicesThenViewMatchesAlways_L_write_index();\n    lemma_IfStoreBufferLacksIndicesThenViewMatchesAlways_L_read_index();\n  }\n  }\n"
  },
  {
    "path": "Test/qbss_benchmark/.gitignore",
    "content": "queue.c\nqueue.o\nbenchmark\nbenchmark_lfds\n*.csv\n*.pdf\n"
  },
  {
    "path": "Test/qbss_benchmark/Makefile",
    "content": "ARMADA_ROOT := ../../\nC_FLAGS_RELEASE := -O2 -DNDEBUG\nC_FLAGS := $(C_FLAGS_RELEASE)\n\nCC := gcc $(C_FLAGS)\n\nqueue.c: queue.arm queue.patch\n\tdotnet $(ARMADA_ROOT)/Binaries/Armada.dll /armadaPath:$(ARMADA_ROOT) queue.arm /compileTarget:clight /spillTargetCode:3\n\tpatch queue.c queue.patch\n\nqueue.o: queue.c\n\t$(CC) queue.c -I$(ARMADA_ROOT)/Binaries/ -lpthread -c -o queue.o -Iliblfds711_modulo/inc/\n\n.PHONY: liblfds_modulo\n\nliblfds_modulo:\n\t$(MAKE) --directory=liblfds711_modulo/build/gcc_gnumake/ ar_rel\n\nliblfds:\n\t$(MAKE) --directory=liblfds711/build/gcc_gnumake/ ar_rel\n\nbenchmark_lfds_modulo: liblfds_modulo\n\t$(CC) benchmark_lfds.c -o benchmark_lfds_modulo -Iliblfds711_modulo/inc/ -lpthread -Lliblfds711_modulo/bin -llfds711\n\nbenchmark_lfds: liblfds\n\t$(CC) benchmark_lfds.c -o benchmark_lfds -Iliblfds711/inc/ -lpthread -Lliblfds711/bin -llfds711\n\nbenchmark: benchmark.c queue.o\n\t$(CC) benchmark.c queue.o -o benchmark -I$(ARMADA_ROOT)/Binaries/ -lpthread \n\n.PHONY: all\nall: benchmark benchmark_lfds benchmark_lfds_modulo\n\n.PHONY: clean\nclean:\n\trm -f benchmark queue.o queue.c benchmark_lfds benchmark_lfds_modulo\n"
  },
  {
    "path": "Test/qbss_benchmark/benchmark.c",
    "content": "#include <stdio.h>\n#include <string.h>\n#include <pthread.h>\n#include <stdlib.h> \n#include <time.h>\n\n#include \"DafnyRuntime.h\"\n\n// Definitions for Armada datatypes\nstruct BSSQueueElement;\ntypedef struct BSSQueueElement BSSQueueElement;\nstruct BSSQueueElement {\n  uint64 key;\n  uint64 value;\n};\n\nstruct QbssState;\ntypedef struct QbssState QbssState;\nstruct QbssState {\nvolatile uint64 number_elements;\nvolatile uint64 mask;\nvolatile uint64 write_index;\nvolatile uint64 read_index;\nvolatile struct BSSQueueElement* element_array;\n};\n\n// Method Decls\nvoid init_queue(struct QbssState* qbss, uint64 size);\nvoid* _thread_of_init_queue (void* vargs);\nuint64 enqueue(struct QbssState* qbss, uint64 k, uint64 v);\nvoid* _thread_of_enqueue (void* vargs);\nuint64 dequeue(struct QbssState* qbss, uint64* k, uint64* v);\nvoid* _thread_of_dequeue (void* vargs);\n\n// Beginning of Bench code\n\nvoid cleanup_queue(struct QbssState* que) {\n  free((*que).element_array); \n}\n\nstruct param {\n  uint64 warmup_queires;\n  uint64 total_queries;\n};\n\nstruct QbssState qbss;\nvoid run_enqueue_armada(uint32 warmup_queires ,uint32 total_queries) {\n  //printf(\"enqueue warmup_queires = %u total_queries = %u\\n\",warmup_queires,total_queries);\n  int ret;\n  uint32 value;\n  for(uint32 i = 0; i < warmup_queires; ++i) {\n    value = i;\n    do {\n      ret = enqueue(&qbss, (uint64)0, (uint64)value);\n    } while(!ret);\n  }\n  struct timespec start, stop;\n  clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start);\n  for(int i = 0; i < total_queries; ++i) {\n    value = i;\n    do {\n      ret = enqueue(&qbss, (uint64)0, (void*)value );\n    } while(!ret);\n  }\n  clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &stop);\n  double total_time_in_sec =  (stop.tv_sec - start.tv_sec) + (stop.tv_nsec - start.tv_nsec) / 1e9f;\n  double tput = (double) total_queries / total_time_in_sec;\n  printf(\"%.f, %.f\\n\",total_time_in_sec, tput);\n  fflush(stdout);\n}\n\nvoid run_dequeue_armada(uint32 warmup_queires ,uint32 total_queries) {\n  uint32 value;\n  int ret;\n  for(uint32 i = 0; i < warmup_queires; ++i) {\n    do {\n      ret = dequeue(&qbss, NULL, (void*) &value );\n    } while(!ret);\n  }\n  for(uint32 i = 0; i < total_queries; ++i) {\n      do {\n        ret = dequeue(&qbss, NULL, (void*) &value );\n    } while(!ret);\n  }\n}\n\nvoid* thread_run_enqueue_armada(void* vargs) {\n  struct param* args = (struct param*) vargs;\n  run_enqueue_armada(args->warmup_queires, args->total_queries);\n}\n\nvoid* thread_run_dequeue_armada(void* vargs) {\n  struct param* args = (struct param*) vargs;\n  run_dequeue_armada(args->warmup_queires, args->total_queries);\n}\n\nvoid bench(uint64 number_elements, uint64 warmup_queires, uint64 total_queries) {\n  pthread_t tid1, tid2;\n  struct param \n    param;\n  param.warmup_queires = warmup_queires;\n  param.total_queries = total_queries;\n  init_queue(&qbss, number_elements);\n  pthread_create(&tid1, NULL, thread_run_enqueue_armada, &param);\n  pthread_create(&tid2, NULL, thread_run_dequeue_armada, &param);\n  pthread_join(tid1, NULL);\n  pthread_join(tid2, NULL);\n  cleanup_queue(&qbss);\n}\n\nint main(int argc, char *argv[])\n{\n  if(argc != 3) {\n    printf(\"Invalid number of args\\n\");\n    return -1;\n  }\n  uint32 number_elements = (uint32)atoi(argv[1]);\n  uint32 number_of_runs = (uint32) atoi(argv[2]);\n  uint32 warmup = 5000000;\n  uint32 total =  50000000;\n  // printf(\"number_elements = %u, warmup_queires = %u, total_queries = %u\\n\",number_elements,warmup,total);\n  printf(\"total_time(secs), throughput(ops/sec)\\n\");\n  fflush(stdout);\n  for(int i = 0; i < number_of_runs; ++i) {\n    bench(number_elements, warmup, total);\n  }\n  return 0;\n}\n"
  },
  {
    "path": "Test/qbss_benchmark/benchmark_lfds.c",
    "content": "// this file contains the benchmark for liblfds implementation of bounded_singleproducer_singleconsumer queue.\n\n// you need to first build and install liblfds:\n// 0. download the liblfds7.1.1 repo: git clone https://github.com/liblfds/liblfds7.1.1.git\n// 1. go to liblfds7.1.1/liblfds711/build/gcc_gnumake\n// 2. run \"sudo make so_uninstall\" to clean up the env.\n// 3. run \"make clean\" to clean up the cache.\n// 4. run \"make so_rel\" to build with release flag (-o2), or \"make so_vanilla\" to build with no flag.\n// 5. run \"sudo make so_install\" to install the lib. \n\n\n// to setput the following configs:\n// 1. liblfds with bitmask: build the original lib with \"so_vanilla\".\n// 2. liblfds with bitmask (-o2): build the original lib with \"so_rel\"\n// 3. liblfds with modulo: \n//     (1). modify line 31 of the file liblfds7.1.1/liblfds711/src/lfds711_queue_bounded_singleproducer_singleconsumer/lfds711_queue_bounded_singleproducer_singleconsumer_enqueue.c:\n//        \"qbsss->write_index = (qbsss->write_index + 1) & qbsss->mask;\" -> \"qbsss->write_index = (qbsss->write_index + 1) % qbsss->number_elements;\"\n//     (2). modify line 32 of the file liblfds7.1.1/liblfds711/src/lfds711_queue_bounded_singleproducer_singleconsumer/lfds711_queue_bounded_singleproducer_singleconsumer_dequeue.c:\n//        \"qbsss->read_index = (qbsss->read_index + 1) & qbsss->mask;\" -> \"qbsss->read_index = (qbsss->read_index + 1) % qbsss->number_elements;\"\n//     (3). build and install with flag \"so_vanilla\".\n// 4. liblfds with modulo (-o2):\n//      (1) : same as \"liblfds with modulo\"\n//      (2) : same as \"liblfds with modulo\"\n//      (3) : build and install with flag \"so_rel\"\n\n\n// to compile the benchmark:\n// without -o2:\n// gcc -fno-strict-aliasing -llfds711 -lpthread -o bench_lfds bench_lfds.c\n// with -o2:\n// gcc -fno-strict-aliasing -o2 -dndebug  -llfds711 -lpthread -o bench_lfds bench_lfds.c\n\n// to run the benchmark:\n// ./bench_lfds number_elements number_of_runs | tee log_{number_elements}_{number_of_runs}.txt\n// number_elements is the size of the queue, it has to be 2^n, n > 0;\n// number_of_runs is the number of runs we want to exec.\n\n// the program will print total_time(secs) and throughput(ops/sec) for each run to stdout\n// and tee will log the reults to the file.\n\n#include <stdio.h>\n#include <string.h>\n#include <pthread.h>\n#include <stdlib.h> \n#include <time.h>\n#include \"liblfds711.h\"\n\ntypedef unsigned long      uint32;\n\nstruct param {\n  uint32 warmup_queires;\n  uint32 total_queries;\n};\n\nstruct lfds711_queue_bss_state \n  qbsss;\n\n\nvoid run_enqueue(uint32 warmup_queires ,uint32 total_queries) {\n  //printf(\"enqueue warmup_queires = %u total_queries = %u\\n\",warmup_queires,total_queries);\n  int ret;\n  uint32 value;\n  for(int i = 0; i < warmup_queires; ++i) {\n    value = i;\n    do {\n      ret = lfds711_queue_bss_enqueue( &qbsss, NULL, (void*)&value );\n    } while(!ret);\n    //printf(\"warm-up enqueued = %d\\n\", value);\n  }\n  struct timespec start, stop;\n  clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start);\n  for(int i = 0; i < total_queries; ++i) {\n    value = i;\n    do {\n      ret = lfds711_queue_bss_enqueue( &qbsss, NULL, (void*)&value );\n    } while(!ret);\n    //printf(\"enqueued = %d\\n\", value);\n  }\n  clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &stop);\n  double total_time_in_sec =  (stop.tv_sec - start.tv_sec) + (stop.tv_nsec - start.tv_nsec) / 1e9;\n  double tput = (double) total_queries / total_time_in_sec;\n  printf(\"%.f, %.f\\n\",total_time_in_sec, tput);\n  fflush(stdout);\n}\n\n\nvoid run_dequeue(uint32 warmup_queires ,uint32 total_queries) {\n  //printf(\"dequeue warmup_queires = %u total_queries = %u\\n\",warmup_queires,total_queries);\n  uint32 value;\n  int ret;\n  for(int i = 0; i < warmup_queires; ++i) {\n    do {\n      ret = lfds711_queue_bss_dequeue( &qbsss, NULL, (void**) &value );\n    } while(!ret);\n  }\n  for(int i = 0; i < total_queries; ++i) {\n      do {\n        ret = lfds711_queue_bss_dequeue( &qbsss, NULL, (void**) &value );\n    } while(!ret);\n  }\n}\n\nvoid* thread_run_enqueue(void* vargs) {\n  struct param* args = (struct param*) vargs;\n  run_enqueue(args->warmup_queires, args->total_queries);\n}\n\nvoid* thread_run_dequeue(void* vargs) {\n  struct param* args = (struct param*) vargs;\n  run_dequeue(args->warmup_queires, args->total_queries);\n}\n\nvoid bench(uint32 number_elements, uint32 warmup_queires ,uint32 total_queries) {\n  struct lfds711_queue_bss_element* \n    qbsse = calloc(number_elements, sizeof(struct lfds711_queue_bss_element));\n  pthread_t tid1, tid2;\n  struct param \n    param;\n  param.warmup_queires = warmup_queires;\n  param.total_queries = total_queries;\n\n  lfds711_queue_bss_init_valid_on_current_logical_core( &qbsss, qbsse, number_elements, NULL);\n  pthread_create(&tid1, NULL, thread_run_enqueue, &param);\n  pthread_create(&tid2, NULL, thread_run_dequeue, &param);\n  pthread_join(tid1, NULL);\n  pthread_join(tid2, NULL);\n  lfds711_queue_bss_cleanup( &qbsss, NULL );\n }\n\nint main(int argc, char *argv[])\n{\n  if(argc != 3) {\n    printf(\"invalid number of args\\n\");\n    return -1;\n  }\n  uint32 number_elements = (uint32)atoi(argv[1]);\n  uint32 number_of_runs = (uint32) atoi(argv[2]);\n  uint32 warmup = 5000000;\n  uint32 total =  50000000;\n  printf(\"total_time(secs), throughput(ops/sec)\\n\");\n  fflush(stdout);\n  for(int i = 0; i < number_of_runs; ++i) {\n    bench(number_elements, warmup, total);\n  }\n  return 0;\n}\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/build/gcc_gnumake/Makefile",
    "content": "##### notes #####\n# TRD : -fno-strict-aliasing is needed because GCC has messed up type punning and __may_alias__ does absolutely nothing\n#       -Wno-unused-but-set-variable and -Wno-uninitialized are needed because GCC seems confused by the atomic intrinsics\n#       the code base for release has been compiled with those warnings enabled, to show any valid errors\n\n##### paths #####\nBINDIR    := ../../bin\nINCDIR    := ../../inc\nOBJDIR    := ../../obj\nSRCDIR    := ../../src\nINSINCDIR := /usr/local/include/\nINSLIBDIR := /usr/local/lib/\n\n##### misc #####\nQUIETLY        := 1>/dev/null 2>/dev/null\nVERSION_NUMBER := 1\nMINOR_NUMBER   := 0\nRELEASE_NUMBER := 0\n\n##### sources, objects and libraries #####\nBINNAME    := liblfds711\nARFILENAME := $(BINNAME).a\nARPATHNAME := $(BINDIR)/$(ARFILENAME)\nSOBASENAME := $(BINNAME).so\nSONAME     := $(SOBASENAME).$(VERSION_NUMBER)\nSOFILENAME := $(SONAME).$(MINOR_NUMBER).$(RELEASE_NUMBER)\nSOPATHNAME := $(BINDIR)/$(SOFILENAME)\nINCNAME    := $(INCDIR)/$(BINNAME).h\nSRCDIRS    := lfds711_btree_addonly_unbalanced lfds711_freelist lfds711_hash_addonly lfds711_list_addonly_singlylinked_ordered lfds711_list_addonly_singlylinked_unordered lfds711_misc lfds711_prng lfds711_queue_bounded_manyproducer_manyconsumer lfds711_queue_bounded_singleproducer_singleconsumer lfds711_queue_unbounded_manyproducer_manyconsumer lfds711_ringbuffer lfds711_stack\nSOURCES    := lfds711_hash_addonly_cleanup.c lfds711_hash_addonly_get.c lfds711_hash_addonly_init.c lfds711_hash_addonly_insert.c lfds711_hash_addonly_iterate.c lfds711_hash_addonly_query.c \\\n              lfds711_list_addonly_singlylinked_ordered_cleanup.c lfds711_list_addonly_singlylinked_ordered_get.c lfds711_list_addonly_singlylinked_ordered_init.c lfds711_list_addonly_singlylinked_ordered_insert.c lfds711_list_addonly_singlylinked_ordered_query.c \\\n              lfds711_list_addonly_singlylinked_unordered_cleanup.c lfds711_list_addonly_singlylinked_unordered_get.c lfds711_list_addonly_singlylinked_unordered_init.c lfds711_list_addonly_singlylinked_unordered_insert.c lfds711_list_addonly_singlylinked_unordered_query.c \\\n              lfds711_btree_addonly_unbalanced_cleanup.c lfds711_btree_addonly_unbalanced_get.c lfds711_btree_addonly_unbalanced_init.c lfds711_btree_addonly_unbalanced_insert.c lfds711_btree_addonly_unbalanced_query.c \\\n              lfds711_freelist_cleanup.c lfds711_freelist_init.c lfds711_freelist_pop.c lfds711_freelist_push.c lfds711_freelist_query.c \\\n              lfds711_misc_internal_backoff_init.c lfds711_misc_globals.c lfds711_misc_query.c \\\n              lfds711_prng_init.c \\\n              lfds711_queue_bounded_manyproducer_manyconsumer_cleanup.c lfds711_queue_bounded_manyproducer_manyconsumer_dequeue.c lfds711_queue_bounded_manyproducer_manyconsumer_enqueue.c lfds711_queue_bounded_manyproducer_manyconsumer_init.c lfds711_queue_bounded_manyproducer_manyconsumer_query.c \\\n              lfds711_queue_bounded_singleproducer_singleconsumer_cleanup.c lfds711_queue_bounded_singleproducer_singleconsumer_dequeue.c lfds711_queue_bounded_singleproducer_singleconsumer_enqueue.c lfds711_queue_bounded_singleproducer_singleconsumer_init.c lfds711_queue_bounded_singleproducer_singleconsumer_query.c \\\n              lfds711_queue_unbounded_manyproducer_manyconsumer_cleanup.c lfds711_queue_unbounded_manyproducer_manyconsumer_dequeue.c lfds711_queue_unbounded_manyproducer_manyconsumer_enqueue.c lfds711_queue_unbounded_manyproducer_manyconsumer_init.c lfds711_queue_unbounded_manyproducer_manyconsumer_query.c \\\n              lfds711_ringbuffer_cleanup.c lfds711_ringbuffer_init.c lfds711_ringbuffer_query.c lfds711_ringbuffer_read.c lfds711_ringbuffer_write.c \\\n              lfds711_stack_cleanup.c lfds711_stack_init.c lfds711_stack_pop.c lfds711_stack_push.c lfds711_stack_query.c\nOBJECTS    := $(patsubst %.c,$(OBJDIR)/%.o,$(notdir $(SOURCES)))\nSYSLIBS    := -lgcc\n\n##### tools #####\nDG                     := gcc\nDGFLAGS_MANDATORY      := -MM\nDGFLAGS_OPTIONAL       := -std=gnu89\n\nCC                     := gcc\nCFLAGS_MANDATORY       := -c -fno-strict-aliasing\nCFLAGS_OPTIONAL        := -ffreestanding -nostdinc -std=gnu89 -Wall -Werror -Wno-unknown-pragmas -Wno-unused-but-set-variable -Wno-uninitialized\nCFLAGS_MANDATORY_COV   := -O0 -ggdb -DCOVERAGE -fprofile-arcs -ftest-coverage\nCFLAGS_MANDATORY_DBG   := -O0 -ggdb -D_DEBUG\nCFLAGS_MANDATORY_PROF  := -O0 -ggdb -DPROF     -pg\nCFLAGS_MANDATORY_REL   := -O2       -DNDEBUG\nCFLAGS_MANDATORY_TSAN  := -O0 -ggdb -DTSAN     -fsanitize=thread -fPIC\n\nAR                     := ar\nARFLAGS                :=\nARFLAGS_MANDATORY      := rcs\nARFLAGS_OPTIONAL       :=\n\nLD                     := gcc\nLDFLAGS_MANDATORY      := -shared -Wl,-soname,$(SONAME) -o $(SOPATHNAME)\nLDFLAGS_OPTIONAL       := -nodefaultlibs -nostdlib -std=gnu89 -Wall -Werror\nLDFLAGS_MANDATORY_COV  := -O0 -fprofile-arcs -ftest-coverage\nLDFLAGS_MANDATORY_DBG  := -O0 -ggdb\nLDFLAGS_MANDATORY_PROF := -O0 -pg\nLDFLAGS_MANDATORY_REL  := -O2 -s\nLDFLAGS_MANDATORY_TSAN := -O0 -fsanitize=thread -fPIC\n\n##### build variants #####\nifeq ($(findstring so,$(MAKECMDGOALS)),so)\n  CFLAGS_MANDATORY += -fPIC\nendif\n\n# TRD : default to debug\nifeq ($(MAKECMDGOALS),)\n  CFLAGS_MANDATORY  += $(CFLAGS_MANDATORY_DBG)\n  LDFLAGS_MANDATORY += $(LDFLAGS_MANDATORY_DBG)\nendif\n\nifeq ($(findstring cov,$(MAKECMDGOALS)),cov)\n  CFLAGS_MANDATORY  += $(CFLAGS_MANDATORY_COV)\n  LDFLAGS_MANDATORY += $(LDFLAGS_MANDATORY_COV)\n  SYSLIBS += -lgcov\nendif\n\nifeq ($(findstring dbg,$(MAKECMDGOALS)),dbg)\n  CFLAGS_MANDATORY  += $(CFLAGS_MANDATORY_DBG)\n  LDFLAGS_MANDATORY += $(LDFLAGS_MANDATORY_DBG)\nendif\n\nifeq ($(findstring prof,$(MAKECMDGOALS)),prof)\n  CFLAGS_MANDATORY  += $(CFLAGS_MANDATORY_PROF)\n  LDFLAGS_MANDATORY += $(LDFLAGS_MANDATORY_PROF)\nendif\n\nifeq ($(findstring rel,$(MAKECMDGOALS)),rel)\n  CFLAGS_MANDATORY  += $(CFLAGS_MANDATORY_REL)\n  LDFLAGS_MANDATORY += $(LDFLAGS_MANDATORY_REL)\nendif\n\nifeq ($(findstring tsan,$(MAKECMDGOALS)),tsan)\n  CFLAGS_MANDATORY  += $(CFLAGS_MANDATORY_TSAN)\n  LDFLAGS_MANDATORY += $(LDFLAGS_MANDATORY_TSAN)\nendif\n\n##### search paths #####\nvpath %.c $(patsubst %,$(SRCDIR)/%:,$(SRCDIRS))\n\n##### implicit rules #####\n$(OBJDIR)/%.o : %.c\n\t$(DG) $(DGFLAGS_OPTIONAL) $(DGFLAGS) $(DGFLAGS_MANDATORY) $< >$(OBJDIR)/$*.d\n\t$(CC) $(CFLAGS_OPTIONAL) $(CFLAGS) $(CFLAGS_MANDATORY) -o $@ $<\n\n##### explicit rules #####\n$(ARPATHNAME) : $(OBJECTS)\n\t$(AR) $(ARFLAGS_OPTIONAL) $(ARFLAGS) $(ARFLAGS_MANDATORY) $(ARPATHNAME) $(OBJECTS)\n\n$(SOPATHNAME) : $(OBJECTS)\n\t$(LD) $(LDFLAGS_OPTIONAL) $(LDFLAGS) $(LDFLAGS_MANDATORY) $(OBJECTS) -lgcov -lgcc -o $(SOPATHNAME)\n\t@ln -fs $(SOFILENAME) $(BINDIR)/$(SONAME)\n\t@ln -fs $(SOFILENAME) $(BINDIR)/$(SOBASENAME)\n\n##### phony #####\n.PHONY : clean ar_cov ar_dbg ar_prof ar_rel ar_tsan ar_vanilla ar_install ar_uninstall so_dbg so_prof so_rel so_tsan so_vanilla so_install so_uninstall\n\nclean : \n\t@rm -f $(BINDIR)/* $(OBJDIR)/*\n\nar_cov       : $(ARPATHNAME) # archive (.a), coverage\nar_dbg       : $(ARPATHNAME) # archive (.a), debug\nar_prof      : $(ARPATHNAME) # archive (.a), profiling\nar_rel       : $(ARPATHNAME) # archive (.a), release\nar_tsan      : $(ARPATHNAME) # archive (.a), thread sanitizer\nar_vanilla   : $(ARPATHNAME) # archive (.a), no specific-build arguments\nar_install   :\n  # TRD : leading backslash to use command rather than alias\n  #       as many Linux distros have a built-in alias to force\n  #       a prompt (\"y/n?\") on file overwrite - silent and\n  #       unexpected interference which breaks a makefile\n\t@mkdir -p $(INSLIBDIR)\n\t@\\cp $(ARPATHNAME) $(INSLIBDIR)\n\t@mkdir -p $(INSINCDIR)\n\t@\\cp -r $(INCDIR)/* $(INSINCDIR)\nar_uninstall :\n\t@rm    $(INSLIBDIR)/$(ARFILENAME)\n\t@rm -r $(INSINCDIR)/$(BINNAME)\n\t@rm -r $(INSINCDIR)/$(BINNAME).h\n\n# TRD : so_cov currently disabled as it cannot work with -nostdlib -nodefaultlibs\n# so_cov       : $(SOPATHNAME) # shared (.so), coverage\nso_dbg       : $(SOPATHNAME) # shared (.so), debug\nso_prof      : $(SOPATHNAME) # shared (.so), profiling\nso_rel       : $(SOPATHNAME) # shared (.so), release\nso_tsan      : $(SOPATHNAME) # shared (.so), thread sanitizer\nso_vanilla   : $(SOPATHNAME) # shared (.so), no specific-build arguments\nso_install   : \n\t@mkdir -p $(INSINCDIR)\n\t@\\cp $(SOPATHNAME) $(INSLIBDIR)\n\t@ldconfig -vn $(INSLIBDIR)\n\t@ln -s $(SONAME) $(INSLIBDIR)/$(SOBASENAME)\n\t@mkdir -p $(INSLIBDIR)\n\t@\\cp -r $(INCDIR)/* $(INSINCDIR)\nso_uninstall : \n\t@rm -f $(INSLIBDIR)/$(SOFILENAME)\n\t@rm -f $(INSLIBDIR)/$(SOBASENAME)\n\t@rm -f $(INSLIBDIR)/$(SONAME)\n\t@rm -r $(INSINCDIR)/$(BINNAME)\n\t@rm -r $(INSINCDIR)/$(BINNAME).h\n\n##### dependencies #####\n-include $(DEPENDS)\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/build/gcc_gnumake_kbuild/Kbuild",
    "content": "lib-y :=\n\nlib-y += ../../src/lfds711_btree_addonly_unbalanced/lfds711_btree_addonly_unbalanced_cleanup.o\nlib-y += ../../src/lfds711_btree_addonly_unbalanced/lfds711_btree_addonly_unbalanced_get.o\nlib-y += ../../src/lfds711_btree_addonly_unbalanced/lfds711_btree_addonly_unbalanced_init.o\nlib-y += ../../src/lfds711_btree_addonly_unbalanced/lfds711_btree_addonly_unbalanced_insert.o\nlib-y += ../../src/lfds711_btree_addonly_unbalanced/lfds711_btree_addonly_unbalanced_query.o\n\nlib-y += ../../src/lfds711_freelist/lfds711_freelist_cleanup.o\nlib-y += ../../src/lfds711_freelist/lfds711_freelist_init.o\nlib-y += ../../src/lfds711_freelist/lfds711_freelist_pop.o\nlib-y += ../../src/lfds711_freelist/lfds711_freelist_push.o\nlib-y += ../../src/lfds711_freelist/lfds711_freelist_query.o\n\nlib-y += ../../src/lfds711_hash_addonly/lfds711_hash_addonly_cleanup.o\nlib-y += ../../src/lfds711_hash_addonly/lfds711_hash_addonly_get.o\nlib-y += ../../src/lfds711_hash_addonly/lfds711_hash_addonly_init.o\nlib-y += ../../src/lfds711_hash_addonly/lfds711_hash_addonly_insert.o\nlib-y += ../../src/lfds711_hash_addonly/lfds711_hash_addonly_iterate.o\nlib-y += ../../src/lfds711_hash_addonly/lfds711_hash_addonly_query.o\n\nlib-y += ../../src/lfds711_list_addonly_singlylinked_ordered/lfds711_list_addonly_singlylinked_ordered_cleanup.o\nlib-y += ../../src/lfds711_list_addonly_singlylinked_ordered/lfds711_list_addonly_singlylinked_ordered_get.o\nlib-y += ../../src/lfds711_list_addonly_singlylinked_ordered/lfds711_list_addonly_singlylinked_ordered_init.o\nlib-y += ../../src/lfds711_list_addonly_singlylinked_ordered/lfds711_list_addonly_singlylinked_ordered_insert.o\nlib-y += ../../src/lfds711_list_addonly_singlylinked_ordered/lfds711_list_addonly_singlylinked_ordered_query.o\n\nlib-y += ../../src/lfds711_list_addonly_singlylinked_unordered/lfds711_list_addonly_singlylinked_unordered_cleanup.o\nlib-y += ../../src/lfds711_list_addonly_singlylinked_unordered/lfds711_list_addonly_singlylinked_unordered_get.o\nlib-y += ../../src/lfds711_list_addonly_singlylinked_unordered/lfds711_list_addonly_singlylinked_unordered_init.o\nlib-y += ../../src/lfds711_list_addonly_singlylinked_unordered/lfds711_list_addonly_singlylinked_unordered_insert.o\nlib-y += ../../src/lfds711_list_addonly_singlylinked_unordered/lfds711_list_addonly_singlylinked_unordered_query.o\n\nlib-y += ../../src/lfds711_misc/lfds711_misc_internal_backoff_init.o\nlib-y += ../../src/lfds711_misc/lfds711_misc_globals.o\nlib-y += ../../src/lfds711_misc/lfds711_misc_query.o\n\nlib-y += ../../src/lfds711_prng/lfds711_prng_init.o\n\nlib-y += ../../src/lfds711_queue_bounded_manyproducer_manyconsumer/lfds711_queue_bounded_manyproducer_manyconsumer_cleanup.o\nlib-y += ../../src/lfds711_queue_bounded_manyproducer_manyconsumer/lfds711_queue_bounded_manyproducer_manyconsumer_dequeue.o\nlib-y += ../../src/lfds711_queue_bounded_manyproducer_manyconsumer/lfds711_queue_bounded_manyproducer_manyconsumer_enqueue.o\nlib-y += ../../src/lfds711_queue_bounded_manyproducer_manyconsumer/lfds711_queue_bounded_manyproducer_manyconsumer_init.o\nlib-y += ../../src/lfds711_queue_bounded_manyproducer_manyconsumer/lfds711_queue_bounded_manyproducer_manyconsumer_query.o\n\nlib-y += ../../src/lfds711_queue_bounded_singleproducer_singleconsumer/lfds711_queue_bounded_singleproducer_singleconsumer_cleanup.o\nlib-y += ../../src/lfds711_queue_bounded_singleproducer_singleconsumer/lfds711_queue_bounded_singleproducer_singleconsumer_dequeue.o\nlib-y += ../../src/lfds711_queue_bounded_singleproducer_singleconsumer/lfds711_queue_bounded_singleproducer_singleconsumer_enqueue.o\nlib-y += ../../src/lfds711_queue_bounded_singleproducer_singleconsumer/lfds711_queue_bounded_singleproducer_singleconsumer_init.o\nlib-y += ../../src/lfds711_queue_bounded_singleproducer_singleconsumer/lfds711_queue_bounded_singleproducer_singleconsumer_query.o\n\nlib-y += ../../src/lfds711_queue_unbounded_manyproducer_manyconsumer/lfds711_queue_unbounded_manyproducer_manyconsumer_cleanup.o\nlib-y += ../../src/lfds711_queue_unbounded_manyproducer_manyconsumer/lfds711_queue_unbounded_manyproducer_manyconsumer_dequeue.o\nlib-y += ../../src/lfds711_queue_unbounded_manyproducer_manyconsumer/lfds711_queue_unbounded_manyproducer_manyconsumer_enqueue.o\nlib-y += ../../src/lfds711_queue_unbounded_manyproducer_manyconsumer/lfds711_queue_unbounded_manyproducer_manyconsumer_init.o\nlib-y += ../../src/lfds711_queue_unbounded_manyproducer_manyconsumer/lfds711_queue_unbounded_manyproducer_manyconsumer_query.o\n\nlib-y += ../../src/lfds711_ringbuffer/lfds711_ringbuffer_cleanup.o\nlib-y += ../../src/lfds711_ringbuffer/lfds711_ringbuffer_init.o\nlib-y += ../../src/lfds711_ringbuffer/lfds711_ringbuffer_query.o\nlib-y += ../../src/lfds711_ringbuffer/lfds711_ringbuffer_read.o\nlib-y += ../../src/lfds711_ringbuffer/lfds711_ringbuffer_write.o\n\nlib-y += ../../src/lfds711_stack/lfds711_stack_cleanup.o\nlib-y += ../../src/lfds711_stack/lfds711_stack_init.o\nlib-y += ../../src/lfds711_stack/lfds711_stack_pop.o\nlib-y += ../../src/lfds711_stack/lfds711_stack_push.o\nlib-y += ../../src/lfds711_stack/lfds711_stack_query.o\n\nlibs-y := ../../bin/\n\nccflags-y := -I$(src)/../../inc\nccflags-y += -I$(src)/../../inc/liblfds711\nccflags-y += -DKERNEL_MODE\nccflags-y += -DNDEBUG\nccflags-y += -fno-strict-aliasing\nccflags-y += -std=gnu89\nccflags-y += -Wall\nccflags-y += -Werror\nccflags-y += -Wno-unknown-pragmas\nccflags-y += -Wno-unused-but-set-variable\nccflags-y += -Wno-uninitialized\n\n\n\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/build/gcc_gnumake_kbuild/Makefile",
    "content": "default:\n\t$(MAKE) -C /lib/modules/`uname -r`/build M=$(PWD)\n\nclean:\n\t$(MAKE) -C /lib/modules/`uname -r`/build M=$(PWD) clean\n\tfind ../../src/ -name \"*.o\" -type f -delete\n\nhelp:\n\t$(MAKE) -C /lib/modules/`uname -r`/build M=$(PWD) help\n\nmodules:\n\t$(MAKE) -C /lib/modules/`uname -r`/build M=$(PWD) modules\n\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/build/msvc_gnumake/liblfds711.def",
    "content": "EXPORTS\n\nlfds711_btree_au_init_valid_on_current_logical_core = lfds711_btree_au_init_valid_on_current_logical_core\nlfds711_btree_au_cleanup = lfds711_btree_au_cleanup\nlfds711_btree_au_insert = lfds711_btree_au_insert\nlfds711_btree_au_get_by_key = lfds711_btree_au_get_by_key\nlfds711_btree_au_get_by_absolute_position_and_then_by_relative_position = lfds711_btree_au_get_by_absolute_position_and_then_by_relative_position\nlfds711_btree_au_get_by_absolute_position = lfds711_btree_au_get_by_absolute_position\nlfds711_btree_au_get_by_relative_position = lfds711_btree_au_get_by_relative_position\nlfds711_btree_au_query = lfds711_btree_au_query\n\nlfds711_freelist_init_valid_on_current_logical_core = lfds711_freelist_init_valid_on_current_logical_core\nlfds711_freelist_cleanup = lfds711_freelist_cleanup\nlfds711_freelist_push = lfds711_freelist_push\nlfds711_freelist_pop = lfds711_freelist_pop\nlfds711_freelist_query = lfds711_freelist_query\n\nlfds711_hash_a_init_valid_on_current_logical_core = lfds711_hash_a_init_valid_on_current_logical_core\nlfds711_hash_a_cleanup = lfds711_hash_a_cleanup\nlfds711_hash_a_insert = lfds711_hash_a_insert\nlfds711_hash_a_get_by_key = lfds711_hash_a_get_by_key\nlfds711_hash_a_iterate_init = lfds711_hash_a_iterate_init\nlfds711_hash_a_iterate = lfds711_hash_a_iterate\nlfds711_hash_a_query = lfds711_hash_a_query\n\nlfds711_list_aso_init_valid_on_current_logical_core = lfds711_list_aso_init_valid_on_current_logical_core\nlfds711_list_aso_cleanup = lfds711_list_aso_cleanup\nlfds711_list_aso_insert = lfds711_list_aso_insert\nlfds711_list_aso_get_by_key = lfds711_list_aso_get_by_key\nlfds711_list_aso_query = lfds711_list_aso_query\n\nlfds711_list_asu_init_valid_on_current_logical_core = lfds711_list_asu_init_valid_on_current_logical_core\nlfds711_list_asu_cleanup = lfds711_list_asu_cleanup\nlfds711_list_asu_insert_at_position = lfds711_list_asu_insert_at_position\nlfds711_list_asu_insert_at_start = lfds711_list_asu_insert_at_start\nlfds711_list_asu_insert_at_end = lfds711_list_asu_insert_at_end\nlfds711_list_asu_insert_after_element = lfds711_list_asu_insert_after_element\nlfds711_list_asu_get_by_key = lfds711_list_asu_get_by_key\nlfds711_list_asu_query = lfds711_list_asu_query\n\nlfds711_misc_query = lfds711_misc_query\n\nlfds711_prng_init_valid_on_current_logical_core = lfds711_prng_init_valid_on_current_logical_core\nlfds711_prng_st_init = lfds711_prng_st_init\n\nlfds711_queue_bmm_init_valid_on_current_logical_core = lfds711_queue_bmm_init_valid_on_current_logical_core\nlfds711_queue_bmm_cleanup = lfds711_queue_bmm_cleanup\nlfds711_queue_bmm_enqueue = lfds711_queue_bmm_enqueue\nlfds711_queue_bmm_dequeue = lfds711_queue_bmm_dequeue\nlfds711_queue_bmm_query = lfds711_queue_bmm_query\n\nlfds711_queue_bss_init_valid_on_current_logical_core = lfds711_queue_bss_init_valid_on_current_logical_core\nlfds711_queue_bss_cleanup = lfds711_queue_bss_cleanup\nlfds711_queue_bss_enqueue = lfds711_queue_bss_enqueue\nlfds711_queue_bss_dequeue = lfds711_queue_bss_dequeue\nlfds711_queue_bss_query = lfds711_queue_bss_query\n\nlfds711_queue_umm_init_valid_on_current_logical_core = lfds711_queue_umm_init_valid_on_current_logical_core\nlfds711_queue_umm_cleanup = lfds711_queue_umm_cleanup\nlfds711_queue_umm_enqueue = lfds711_queue_umm_enqueue\nlfds711_queue_umm_dequeue = lfds711_queue_umm_dequeue\nlfds711_queue_umm_query = lfds711_queue_umm_query\n\nlfds711_ringbuffer_init_valid_on_current_logical_core = lfds711_ringbuffer_init_valid_on_current_logical_core\nlfds711_ringbuffer_cleanup = lfds711_ringbuffer_cleanup\nlfds711_ringbuffer_read = lfds711_ringbuffer_read\nlfds711_ringbuffer_write = lfds711_ringbuffer_write\nlfds711_ringbuffer_query = lfds711_ringbuffer_query\n\nlfds711_stack_init_valid_on_current_logical_core = lfds711_stack_init_valid_on_current_logical_core\nlfds711_stack_cleanup = lfds711_stack_cleanup\nlfds711_stack_push = lfds711_stack_push\nlfds711_stack_pop = lfds711_stack_pop\nlfds711_stack_query = lfds711_stack_query\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/build/msvc_gnumake/makefile",
    "content": "##### paths #####\nBINDIR := ..\\..\\bin\nINCDIR := ..\\..\\inc\nOBJDIR := ..\\..\\obj\nSRCDIR := ..\\..\\src\n\n##### misc #####\nQUIETLY := 1>nul 2>nul\nNULL := \nSPACE := $(NULL) # TRD : with a trailing space\n\n##### sources, objects and libraries #####\nBINNAME    := liblfds711\nLIB_BINARY := $(BINDIR)\\$(BINNAME).lib\nDLL_BINARY := $(BINDIR)\\$(BINNAME).dll\nSRCDIRS    := lfds711_btree_addonly_unbalanced lfds711_freelist lfds711_hash_addonly lfds711_list_addonly_singlylinked_ordered lfds711_list_addonly_singlylinked_unordered lfds711_misc lfds711_prng lfds711_queue_bounded_manyproducer_manyconsumer lfds711_queue_bounded_singleproducer_singleconsumer lfds711_queue_unbounded_manyproducer_manyconsumer lfds711_ringbuffer lfds711_stack\nSOURCES    := lfds711_hash_addonly_cleanup.c lfds711_hash_addonly_get.c lfds711_hash_addonly_init.c lfds711_hash_addonly_insert.c lfds711_hash_addonly_iterate.c lfds711_hash_addonly_query.c \\\n              lfds711_list_addonly_singlylinked_ordered_cleanup.c lfds711_list_addonly_singlylinked_ordered_get.c lfds711_list_addonly_singlylinked_ordered_init.c lfds711_list_addonly_singlylinked_ordered_insert.c lfds711_list_addonly_singlylinked_ordered_query.c \\\n              lfds711_list_addonly_singlylinked_unordered_cleanup.c lfds711_list_addonly_singlylinked_unordered_get.c lfds711_list_addonly_singlylinked_unordered_init.c lfds711_list_addonly_singlylinked_unordered_insert.c lfds711_list_addonly_singlylinked_unordered_query.c \\\n              lfds711_btree_addonly_unbalanced_cleanup.c lfds711_btree_addonly_unbalanced_get.c lfds711_btree_addonly_unbalanced_init.c lfds711_btree_addonly_unbalanced_insert.c lfds711_btree_addonly_unbalanced_query.c \\\n              lfds711_freelist_cleanup.c lfds711_freelist_init.c lfds711_freelist_pop.c lfds711_freelist_push.c lfds711_freelist_query.c \\\n              lfds711_misc_internal_backoff_init.c lfds711_misc_globals.c lfds711_misc_query.c \\\n              lfds711_prng_init.c \\\n              lfds711_queue_bounded_manyproducer_manyconsumer_cleanup.c lfds711_queue_bounded_manyproducer_manyconsumer_dequeue.c lfds711_queue_bounded_manyproducer_manyconsumer_enqueue.c lfds711_queue_bounded_manyproducer_manyconsumer_init.c lfds711_queue_bounded_manyproducer_manyconsumer_query.c \\\n              lfds711_queue_bounded_singleproducer_singleconsumer_cleanup.c lfds711_queue_bounded_singleproducer_singleconsumer_dequeue.c lfds711_queue_bounded_singleproducer_singleconsumer_enqueue.c lfds711_queue_bounded_singleproducer_singleconsumer_init.c lfds711_queue_bounded_singleproducer_singleconsumer_query.c \\\n              lfds711_queue_unbounded_manyproducer_manyconsumer_cleanup.c lfds711_queue_unbounded_manyproducer_manyconsumer_dequeue.c lfds711_queue_unbounded_manyproducer_manyconsumer_enqueue.c lfds711_queue_unbounded_manyproducer_manyconsumer_init.c lfds711_queue_unbounded_manyproducer_manyconsumer_query.c \\\n              lfds711_ringbuffer_cleanup.c lfds711_ringbuffer_init.c lfds711_ringbuffer_query.c lfds711_ringbuffer_read.c lfds711_ringbuffer_write.c \\\n              lfds711_stack_cleanup.c lfds711_stack_init.c lfds711_stack_pop.c lfds711_stack_push.c lfds711_stack_query.c\nOBJECTS    := $(patsubst %.c,$(OBJDIR)/%.obj,$(notdir $(SOURCES)))\nSYSLIBS    := kernel32.lib\n\n##### default paths fix up #####\nINCDIRS := $(patsubst %,%;,$(INCDIR))\nINCLUDE += $(subst $(SPACE),,$(INCDIRS))\n\n##### tools #####\nCC                    := cl\nCFLAGS_MANDATORY      := /c \"/Fd$(BINDIR)\\$(BINNAME).pdb\" /wd 4068\nCFLAGS_OPTIONAL       := /DWIN32_LEAN_AND_MEAN /DUNICODE /D_UNICODE /nologo /W4 /WX\nCFLAGS_MANDATORY_DBG  := /Od /Gm /Zi /D_DEBUG\nCFLAGS_MANDATORY_REL  := /Ox /DNDEBUG\n\nAR                    := lib\nARFLAGS               :=\nARFLAGS_MANDATORY     := /subsystem:console\nARFLAGS_OPTIONAL      := /nologo /wx /verbose\n\nLD                    := link\nLDFLAGS_MANDATORY     := /def:$(BINNAME).def /dll /nodefaultlib /subsystem:console\nLDFLAGS_OPTIONAL      := /nologo /nxcompat /wx\nLDFLAGS_MANDATORY_DBG := /debug \"/pdb:$(BINDIR)\\$(BINNAME).pdb\"\nLDFLAGS_MANDATORY_REL := /incremental:no\n\n##### variants #####\nifeq ($(MAKECMDGOALS),) # TRD : default to debug lib\n  CFLAGS_MANDATORY  += $(CFLAGS_MANDATORY_DBG)\n  LDFLAGS_MANDATORY += $(LDFLAGS_MANDATORY_DBG)\n  CLIB              := libcmtd.lib\nendif\n\nifeq ($(MAKECMDGOALS),libdbg)\n  CFLAGS_MANDATORY  += $(CFLAGS_MANDATORY_DBG)\n  LDFLAGS_MANDATORY += $(LDFLAGS_MANDATORY_DBG)\n  CLIB              := libcmtd.lib\nendif\n\nifeq ($(MAKECMDGOALS),librel)\n  CFLAGS_MANDATORY  += $(CFLAGS_MANDATORY_REL)\n  LDFLAGS_MANDATORY += $(LDFLAGS_MANDATORY_REL)\n  CLIB              := libcmt.lib\nendif\n\nifeq ($(MAKECMDGOALS),dlldbg)\n  CFLAGS_MANDATORY  += $(CFLAGS_MANDATORY_DBG)\n  LDFLAGS_MANDATORY += $(LDFLAGS_MANDATORY_DBG)\n  CLIB              := msvcrtd.lib\nendif\n\nifeq ($(MAKECMDGOALS),dllrel)\n  CFLAGS_MANDATORY  += $(CFLAGS_MANDATORY_REL)\n  LDFLAGS_MANDATORY += $(LDFLAGS_MANDATORY_REL)\n  CLIB              := msvcrt.lib\nendif\n\n##### search paths #####\nvpath %.c $(patsubst %,$(SRCDIR)/%;,$(SRCDIRS))\n\n##### implicit rules #####\n$(OBJDIR)/%.obj : %.c\n\t$(CC) $(CFLAGS_OPTIONAL) $(CFLAGS) $(CFLAGS_MANDATORY) \"/Fo$@\" $<\n\n##### explicit rules #####\n$(LIB_BINARY) : $(OBJECTS)\n\t$(AR) $(ARFLAGS_OPTIONAL) $(ARFLAGS) $(ARFLAGS_MANDATORY) $(OBJECTS) /out:$(LIB_BINARY)\n\n$(DLL_BINARY) : $(OBJECTS)\n\t$(LD) $(LDFLAGS_OPTIONAL) $(LDFLAGS) $(LDFLAGS_MANDATORY) $(CLIB) $(SYSLIBS) $(OBJECTS) /out:$(DLL_BINARY)\n\n##### phony #####\n.PHONY : clean librel libdbg dllrel dlldbg\n\nclean : \n\t@erase /Q $(BINDIR)\\$(BINNAME).* $(OBJDIR)\\*.obj $(QUIETLY)\n\ndllrel : $(DLL_BINARY)\ndlldbg : $(DLL_BINARY)\n\nlibrel : $(LIB_BINARY)\nlibdbg : $(LIB_BINARY)\n\n##### notes #####\n# /wd 4068 : turn off \"unknown pragma\" warning\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/build/wdk_7.1/dirs",
    "content": "DIRS = single_dir_for_windows_kernel\n\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/build/wdk_7.1/driver_entry_renamed_to_avoid_compiler_warning.c",
    "content": "#include \"liblfds711_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nDRIVER_INITIALIZE DriverEntry;\n\n\n\n\n\n/****************************************************************************/\n#pragma warning( disable : 4100 )\n\nNTSTATUS DriverEntry( struct _DRIVER_OBJECT *DriverObject, PUNICODE_STRING RegistryPath )\n{\n\treturn STATUS_SUCCESS;\n}\n\n#pragma warning( default : 4100 )\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/build/wdk_7.1/liblfds711.def",
    "content": "EXPORTS\n\nlfds711_btree_au_init_valid_on_current_logical_core = lfds711_btree_au_init_valid_on_current_logical_core\nlfds711_btree_au_cleanup = lfds711_btree_au_cleanup\nlfds711_btree_au_insert = lfds711_btree_au_insert\nlfds711_btree_au_get_by_key = lfds711_btree_au_get_by_key\nlfds711_btree_au_get_by_absolute_position_and_then_by_relative_position = lfds711_btree_au_get_by_absolute_position_and_then_by_relative_position\nlfds711_btree_au_get_by_absolute_position = lfds711_btree_au_get_by_absolute_position\nlfds711_btree_au_get_by_relative_position = lfds711_btree_au_get_by_relative_position\nlfds711_btree_au_query = lfds711_btree_au_query\n\nlfds711_freelist_init_valid_on_current_logical_core = lfds711_freelist_init_valid_on_current_logical_core\nlfds711_freelist_cleanup = lfds711_freelist_cleanup\nlfds711_freelist_push = lfds711_freelist_push\nlfds711_freelist_pop = lfds711_freelist_pop\nlfds711_freelist_query = lfds711_freelist_query\n\nlfds711_hash_a_init_valid_on_current_logical_core = lfds711_hash_a_init_valid_on_current_logical_core\nlfds711_hash_a_cleanup = lfds711_hash_a_cleanup\nlfds711_hash_a_insert = lfds711_hash_a_insert\nlfds711_hash_a_get_by_key = lfds711_hash_a_get_by_key\nlfds711_hash_a_iterate_init = lfds711_hash_a_iterate_init\nlfds711_hash_a_iterate = lfds711_hash_a_iterate\nlfds711_hash_a_query = lfds711_hash_a_query\n\nlfds711_list_aso_init_valid_on_current_logical_core = lfds711_list_aso_init_valid_on_current_logical_core\nlfds711_list_aso_cleanup = lfds711_list_aso_cleanup\nlfds711_list_aso_insert = lfds711_list_aso_insert\nlfds711_list_aso_get_by_key = lfds711_list_aso_get_by_key\nlfds711_list_aso_query = lfds711_list_aso_query\n\nlfds711_list_asu_init_valid_on_current_logical_core = lfds711_list_asu_init_valid_on_current_logical_core\nlfds711_list_asu_cleanup = lfds711_list_asu_cleanup\nlfds711_list_asu_insert_at_position = lfds711_list_asu_insert_at_position\nlfds711_list_asu_insert_at_start = lfds711_list_asu_insert_at_start\nlfds711_list_asu_insert_at_end = lfds711_list_asu_insert_at_end\nlfds711_list_asu_insert_after_element = lfds711_list_asu_insert_after_element\nlfds711_list_asu_get_by_key = lfds711_list_asu_get_by_key\nlfds711_list_asu_query = lfds711_list_asu_query\n\nlfds711_misc_query = lfds711_misc_query\n\nlfds711_prng_init_valid_on_current_logical_core = lfds711_prng_init_valid_on_current_logical_core\nlfds711_prng_st_init = lfds711_prng_st_init\n\nlfds711_queue_bmm_init_valid_on_current_logical_core = lfds711_queue_bmm_init_valid_on_current_logical_core\nlfds711_queue_bmm_cleanup = lfds711_queue_bmm_cleanup\nlfds711_queue_bmm_enqueue = lfds711_queue_bmm_enqueue\nlfds711_queue_bmm_dequeue = lfds711_queue_bmm_dequeue\nlfds711_queue_bmm_query = lfds711_queue_bmm_query\n\nlfds711_queue_bss_init_valid_on_current_logical_core = lfds711_queue_bss_init_valid_on_current_logical_core\nlfds711_queue_bss_cleanup = lfds711_queue_bss_cleanup\nlfds711_queue_bss_enqueue = lfds711_queue_bss_enqueue\nlfds711_queue_bss_dequeue = lfds711_queue_bss_dequeue\nlfds711_queue_bss_query = lfds711_queue_bss_query\n\nlfds711_queue_umm_init_valid_on_current_logical_core = lfds711_queue_umm_init_valid_on_current_logical_core\nlfds711_queue_umm_cleanup = lfds711_queue_umm_cleanup\nlfds711_queue_umm_enqueue = lfds711_queue_umm_enqueue\nlfds711_queue_umm_dequeue = lfds711_queue_umm_dequeue\nlfds711_queue_umm_query = lfds711_queue_umm_query\n\nlfds711_ringbuffer_init_valid_on_current_logical_core = lfds711_ringbuffer_init_valid_on_current_logical_core\nlfds711_ringbuffer_cleanup = lfds711_ringbuffer_cleanup\nlfds711_ringbuffer_read = lfds711_ringbuffer_read\nlfds711_ringbuffer_write = lfds711_ringbuffer_write\nlfds711_ringbuffer_query = lfds711_ringbuffer_query\n\nlfds711_stack_init_valid_on_current_logical_core = lfds711_stack_init_valid_on_current_logical_core\nlfds711_stack_cleanup = lfds711_stack_cleanup\nlfds711_stack_push = lfds711_stack_push\nlfds711_stack_pop = lfds711_stack_pop\nlfds711_stack_query = lfds711_stack_query\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/build/wdk_7.1/readme_before_win_kernel_build.txt",
    "content": "The Windows kernel build environment is primitive and has a number\nof severe limitations; in particular, all source files must be in\none directory and it is not possible to choose the output binary type\n(static or dynamic library) from the build command line; rather,\na string has to be modified in a text file used by the build (!)\n\nTo deal with these limitations, it is necessary for a Windows kernel\nbuild to run a batch file prior to building.\n\nThere are two batch files, one for static library builds and the other\nfor dynamic library builds.\n\nThey are both idempotent; you can run them as often as you like and\nswitch between them as often as you want.  It's all fine; whenever\nyou run one of them, it will take you from whatever state you were\npreviously in, into the state you want to be in.\n\nBoth batch files copy all the sources file into a single directory,\n\"/src/single_dir_for_windows_kernel/\".\n\nThe static library batch file will then copy \"/sources.static\" into\n\"/src/single_dir_for_windows_kernel/\", which will cause a static\nlibrary to be built.\n\nThe dynamic library batch file will then copy \"/sources.dynamic\" into\n\"/src/single_dir_for_windows_kernel/\", which will cause a dynamic\nlibrary to be built.  It will also copy \"src/driver_entry.c\" into\n\"/src/single_dir_for_windows_kernel/\", since the linker requires\nthe DriverEntry function to exist for dynamic libraries, even\nthough it's not used.\n\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/build/wdk_7.1/runme_before_win_kernel_dynamic_lib_build.bat",
    "content": "@echo off\r\nrmdir /q /s single_dir_for_windows_kernel                                                                              1>nul 2>nul\r\nmkdir single_dir_for_windows_kernel                                                                                    1>nul 2>nul\r\n\r\ncopy /y ..\\..\\src\\lfds711_btree_addonly_unbalanced\\*                     single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_freelist\\*                                     single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_hash_addonly\\*                                 single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_list_addonly_singlylinked_ordered\\*            single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_list_addonly_singlylinked_unordered\\*          single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_misc\\*                                         single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_prng\\*                                         single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_queue_bounded_manyproducer_manyconsumer\\*      single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_queue_bounded_singleproducer_singleconsumer\\*  single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_queue_unbounded_manyproducer_manyconsumer\\*    single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_ringbuffer\\*                                   single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_stack\\*                                        single_dir_for_windows_kernel\\                1>nul 2>nul\r\n\r\ncopy /y ..\\..\\src\\liblfds711_internal.h                                  single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y driver_entry_renamed_to_avoid_compiler_warning.c                 single_dir_for_windows_kernel\\driver_entry.c  1>nul 2>nul\r\ncopy /y sources.dynamic                                                  single_dir_for_windows_kernel\\sources         1>nul 2>nul\r\n\r\necho Windows kernel dynamic library build directory structure created.\r\necho (Note the effects of this batch file are idempotent).\r\n\r\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/build/wdk_7.1/runme_before_win_kernel_static_lib_build.bat",
    "content": "@echo off\r\nrmdir /q /s single_dir_for_windows_kernel                                                                              1>nul 2>nul\r\nmkdir single_dir_for_windows_kernel                                                                                    1>nul 2>nul\r\n\r\ncopy /y ..\\..\\src\\lfds711_btree_addonly_unbalanced\\*                     single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_freelist\\*                                     single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_hash_addonly\\*                                 single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_list_addonly_singlylinked_ordered\\*            single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_list_addonly_singlylinked_unordered\\*          single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_misc\\*                                         single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_prng\\*                                         single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_queue_bounded_manyproducer_manyconsumer\\*      single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_queue_bounded_singleproducer_singleconsumer\\*  single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_queue_unbounded_manyproducer_manyconsumer\\*    single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_ringbuffer\\*                                   single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_stack\\*                                        single_dir_for_windows_kernel\\                1>nul 2>nul\r\n\r\ncopy /y ..\\..\\src\\liblfds711_internal.h                                  single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y sources.static                                                   single_dir_for_windows_kernel\\sources         1>nul 2>nul\r\n\r\necho Windows kernel static library build directory structure created.\r\necho (Note the effects of this batch file are idempotent).\r\n\r\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/build/wdk_7.1/sources.dynamic",
    "content": "MSC_WARNING_LEVEL = /WX /wd4127 /W4\nDLLDEF            = ../liblfds711.def\nTARGETNAME        = liblfds711\nTARGETPATH        = ../../../bin/\nTARGETTYPE        = EXPORT_DRIVER\nUMTYPE            = nt\nUSER_C_FLAGS      = /DKERNEL_MODE /DNDEBUG\n\nINCLUDES = ../../../inc/\nSOURCES  = lfds711_btree_addonly_unbalanced_cleanup.c \\\n           lfds711_btree_addonly_unbalanced_get.c \\\n           lfds711_btree_addonly_unbalanced_init.c \\\n           lfds711_btree_addonly_unbalanced_insert.c \\\n           lfds711_btree_addonly_unbalanced_query.c \\\n           lfds711_freelist_cleanup.c \\\n           lfds711_freelist_init.c \\\n           lfds711_freelist_pop.c \\\n           lfds711_freelist_push.c \\\n           lfds711_freelist_query.c \\\n           lfds711_hash_addonly_cleanup.c \\\n           lfds711_hash_addonly_get.c \\\n           lfds711_hash_addonly_init.c \\\n           lfds711_hash_addonly_insert.c \\\n           lfds711_hash_addonly_iterate.c \\\n           lfds711_hash_addonly_query.c \\\n           lfds711_list_addonly_singlylinked_ordered_cleanup.c \\\n           lfds711_list_addonly_singlylinked_ordered_get.c \\\n           lfds711_list_addonly_singlylinked_ordered_init.c \\\n           lfds711_list_addonly_singlylinked_ordered_insert.c \\\n           lfds711_list_addonly_singlylinked_ordered_query.c \\\n           lfds711_list_addonly_singlylinked_unordered_cleanup.c \\\n           lfds711_list_addonly_singlylinked_unordered_get.c \\\n           lfds711_list_addonly_singlylinked_unordered_init.c \\\n           lfds711_list_addonly_singlylinked_unordered_insert.c \\\n           lfds711_list_addonly_singlylinked_unordered_query.c \\\n           lfds711_misc_globals.c \\\n           lfds711_misc_internal_backoff_init.c \\\n           lfds711_misc_query.c \\\n           lfds711_prng_init.c \\\n           lfds711_queue_bounded_manyproducer_manyconsumer_cleanup.c \\\n           lfds711_queue_bounded_manyproducer_manyconsumer_dequeue.c \\\n           lfds711_queue_bounded_manyproducer_manyconsumer_enqueue.c \\\n           lfds711_queue_bounded_manyproducer_manyconsumer_init.c \\\n           lfds711_queue_bounded_manyproducer_manyconsumer_query.c \\\n           lfds711_queue_bounded_singleproducer_singleconsumer_cleanup.c \\\n           lfds711_queue_bounded_singleproducer_singleconsumer_dequeue.c \\\n           lfds711_queue_bounded_singleproducer_singleconsumer_enqueue.c \\\n           lfds711_queue_bounded_singleproducer_singleconsumer_init.c \\\n           lfds711_queue_bounded_singleproducer_singleconsumer_query.c \\\n           lfds711_queue_unbounded_manyproducer_manyconsumer_cleanup.c \\\n           lfds711_queue_unbounded_manyproducer_manyconsumer_dequeue.c \\\n           lfds711_queue_unbounded_manyproducer_manyconsumer_enqueue.c \\\n           lfds711_queue_unbounded_manyproducer_manyconsumer_init.c \\\n           lfds711_queue_unbounded_manyproducer_manyconsumer_query.c \\\n           lfds711_ringbuffer_cleanup.c \\\n           lfds711_ringbuffer_init.c \\\n           lfds711_ringbuffer_query.c \\\n           lfds711_ringbuffer_read.c \\\n           lfds711_ringbuffer_write.c \\\n           lfds711_stack_cleanup.c \\\n           lfds711_stack_init.c \\\n           lfds711_stack_pop.c \\\n           lfds711_stack_push.c \\\n           lfds711_stack_query.c \\\n           driver_entry.c\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/build/wdk_7.1/sources.static",
    "content": "MSC_WARNING_LEVEL = /WX /wd4127 /W4\nTARGETNAME        = liblfds711\nTARGETPATH        = ../../../bin/\nTARGETTYPE        = DRIVER_LIBRARY\nUMTYPE            = nt\nUSER_C_FLAGS      = /DKERNEL_MODE /DNDEBUG\n\nINCLUDES = ../../../inc/\nSOURCES  = lfds711_btree_addonly_unbalanced_cleanup.c \\\n           lfds711_btree_addonly_unbalanced_get.c \\\n           lfds711_btree_addonly_unbalanced_init.c \\\n           lfds711_btree_addonly_unbalanced_insert.c \\\n           lfds711_btree_addonly_unbalanced_query.c \\\n           lfds711_freelist_cleanup.c \\\n           lfds711_freelist_init.c \\\n           lfds711_freelist_pop.c \\\n           lfds711_freelist_push.c \\\n           lfds711_freelist_query.c \\\n           lfds711_hash_addonly_cleanup.c \\\n           lfds711_hash_addonly_get.c \\\n           lfds711_hash_addonly_init.c \\\n           lfds711_hash_addonly_insert.c \\\n           lfds711_hash_addonly_iterate.c \\\n           lfds711_hash_addonly_query.c \\\n           lfds711_list_addonly_singlylinked_ordered_cleanup.c \\\n           lfds711_list_addonly_singlylinked_ordered_get.c \\\n           lfds711_list_addonly_singlylinked_ordered_init.c \\\n           lfds711_list_addonly_singlylinked_ordered_insert.c \\\n           lfds711_list_addonly_singlylinked_ordered_query.c \\\n           lfds711_list_addonly_singlylinked_unordered_cleanup.c \\\n           lfds711_list_addonly_singlylinked_unordered_get.c \\\n           lfds711_list_addonly_singlylinked_unordered_init.c \\\n           lfds711_list_addonly_singlylinked_unordered_insert.c \\\n           lfds711_list_addonly_singlylinked_unordered_query.c \\\n           lfds711_misc_globals.c \\\n           lfds711_misc_internal_backoff_init.c \\\n           lfds711_misc_query.c \\\n           lfds711_prng_init.c \\\n           lfds711_queue_bounded_manyproducer_manyconsumer_cleanup.c \\\n           lfds711_queue_bounded_manyproducer_manyconsumer_dequeue.c \\\n           lfds711_queue_bounded_manyproducer_manyconsumer_enqueue.c \\\n           lfds711_queue_bounded_manyproducer_manyconsumer_init.c \\\n           lfds711_queue_bounded_manyproducer_manyconsumer_query.c \\\n           lfds711_queue_bounded_singleproducer_singleconsumer_cleanup.c \\\n           lfds711_queue_bounded_singleproducer_singleconsumer_dequeue.c \\\n           lfds711_queue_bounded_singleproducer_singleconsumer_enqueue.c \\\n           lfds711_queue_bounded_singleproducer_singleconsumer_init.c \\\n           lfds711_queue_bounded_singleproducer_singleconsumer_query.c \\\n           lfds711_queue_unbounded_manyproducer_manyconsumer_cleanup.c \\\n           lfds711_queue_unbounded_manyproducer_manyconsumer_dequeue.c \\\n           lfds711_queue_unbounded_manyproducer_manyconsumer_enqueue.c \\\n           lfds711_queue_unbounded_manyproducer_manyconsumer_init.c \\\n           lfds711_queue_unbounded_manyproducer_manyconsumer_query.c \\\n           lfds711_ringbuffer_cleanup.c \\\n           lfds711_ringbuffer_init.c \\\n           lfds711_ringbuffer_query.c \\\n           lfds711_ringbuffer_read.c \\\n           lfds711_ringbuffer_write.c \\\n           lfds711_stack_cleanup.c \\\n           lfds711_stack_init.c \\\n           lfds711_stack_pop.c \\\n           lfds711_stack_push.c \\\n           lfds711_stack_query.c\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/inc/liblfds711/lfds711_btree_addonly_unbalanced.h",
    "content": "/***** defines *****/\n#define LFDS711_BTREE_AU_GET_KEY_FROM_ELEMENT( btree_au_element )             ( (btree_au_element).key )\n#define LFDS711_BTREE_AU_SET_KEY_IN_ELEMENT( btree_au_element, new_key )      ( (btree_au_element).key = (void *) (lfds711_pal_uint_t) (new_key) )\n#define LFDS711_BTREE_AU_GET_VALUE_FROM_ELEMENT( btree_au_element )           ( LFDS711_MISC_BARRIER_LOAD, (btree_au_element).value )\n#define LFDS711_BTREE_AU_SET_VALUE_IN_ELEMENT( btree_au_element, new_value )  { LFDS711_PAL_ATOMIC_SET( &(btree_au_element).value, new_value ); }\n#define LFDS711_BTREE_AU_GET_USER_STATE_FROM_STATE( btree_au_state )          ( (btree_au_state).user_state )\n\n/***** enums *****/\nenum lfds711_btree_au_absolute_position\n{\n  LFDS711_BTREE_AU_ABSOLUTE_POSITION_ROOT,\n  LFDS711_BTREE_AU_ABSOLUTE_POSITION_SMALLEST_IN_TREE,\n  LFDS711_BTREE_AU_ABSOLUTE_POSITION_LARGEST_IN_TREE\n};\n\nenum lfds711_btree_au_existing_key\n{\n  LFDS711_BTREE_AU_EXISTING_KEY_OVERWRITE,\n  LFDS711_BTREE_AU_EXISTING_KEY_FAIL\n};\n\nenum lfds711_btree_au_insert_result\n{\n  LFDS711_BTREE_AU_INSERT_RESULT_FAILURE_EXISTING_KEY,\n  LFDS711_BTREE_AU_INSERT_RESULT_SUCCESS_OVERWRITE,\n  LFDS711_BTREE_AU_INSERT_RESULT_SUCCESS\n};\n\nenum lfds711_btree_au_query\n{\n  LFDS711_BTREE_AU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT,\n  LFDS711_BTREE_AU_QUERY_SINGLETHREADED_VALIDATE\n};\n\nenum lfds711_btree_au_relative_position\n{\n  LFDS711_BTREE_AU_RELATIVE_POSITION_UP,\n  LFDS711_BTREE_AU_RELATIVE_POSITION_LEFT,\n  LFDS711_BTREE_AU_RELATIVE_POSITION_RIGHT,\n  LFDS711_BTREE_AU_RELATIVE_POSITION_SMALLEST_ELEMENT_BELOW_CURRENT_ELEMENT,\n  LFDS711_BTREE_AU_RELATIVE_POSITION_LARGEST_ELEMENT_BELOW_CURRENT_ELEMENT,\n  LFDS711_BTREE_AU_RELATIVE_POSITION_NEXT_SMALLER_ELEMENT_IN_ENTIRE_TREE,\n  LFDS711_BTREE_AU_RELATIVE_POSITION_NEXT_LARGER_ELEMENT_IN_ENTIRE_TREE\n};\n\n/***** structs *****/\nstruct lfds711_btree_au_element\n{\n  /* TRD : we are add-only, so these elements are only written once\n           as such, the write is wholly negligible\n           we are only concerned with getting as many structs in one cache line as we can\n  */\n\n  struct lfds711_btree_au_element LFDS711_PAL_ALIGN(LFDS711_PAL_ALIGN_SINGLE_POINTER)\n    *volatile left,\n    *volatile right,\n    *volatile up;\n\n  void LFDS711_PAL_ALIGN(LFDS711_PAL_ALIGN_SINGLE_POINTER)\n    *volatile value;\n\n  void\n    *key;\n};\n\nstruct lfds711_btree_au_state\n{\n  struct lfds711_btree_au_element LFDS711_PAL_ALIGN(LFDS711_PAL_ALIGN_SINGLE_POINTER)\n    *volatile root;\n\n  int\n    (*key_compare_function)( void const *new_key, void const *existing_key );\n\n  enum lfds711_btree_au_existing_key \n    existing_key;\n\n  void\n    *user_state;\n\n  struct lfds711_misc_backoff_state\n    insert_backoff;\n};\n\n/***** public prototypes *****/\nvoid lfds711_btree_au_init_valid_on_current_logical_core( struct lfds711_btree_au_state *baus,\n                                                          int (*key_compare_function)(void const *new_key, void const *existing_key),\n                                                          enum lfds711_btree_au_existing_key existing_key,\n                                                          void *user_state );\n  // TRD : used in conjunction with the #define LFDS711_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE\n\nvoid lfds711_btree_au_cleanup( struct lfds711_btree_au_state *baus,\n                               void (*element_cleanup_callback)(struct lfds711_btree_au_state *baus, struct lfds711_btree_au_element *baue) );\n\nenum lfds711_btree_au_insert_result lfds711_btree_au_insert( struct lfds711_btree_au_state *baus,\n                                                             struct lfds711_btree_au_element *baue,\n                                                             struct lfds711_btree_au_element **existing_baue );\n  // TRD : if a link collides with an existing key and existing_baue is non-NULL, existing_baue is set to the existing element\n\nint lfds711_btree_au_get_by_key( struct lfds711_btree_au_state *baus, \n                                 int (*key_compare_function)(void const *new_key, void const *existing_key),\n                                 void *key,\n                                 struct lfds711_btree_au_element **baue );\n\nint lfds711_btree_au_get_by_absolute_position_and_then_by_relative_position( struct lfds711_btree_au_state *baus,\n                                                                             struct lfds711_btree_au_element **baue,\n                                                                             enum lfds711_btree_au_absolute_position absolute_position,\n                                                                             enum lfds711_btree_au_relative_position relative_position );\n  // TRD : if *baue is NULL, we get the element at position, otherwise we move from *baue according to direction\n\nint lfds711_btree_au_get_by_absolute_position( struct lfds711_btree_au_state *baus,\n                                               struct lfds711_btree_au_element **baue,\n                                               enum lfds711_btree_au_absolute_position absolute_position );\n\nint lfds711_btree_au_get_by_relative_position( struct lfds711_btree_au_element **baue,\n                                               enum lfds711_btree_au_relative_position relative_position );\n\nvoid lfds711_btree_au_query( struct lfds711_btree_au_state *baus,\n                             enum lfds711_btree_au_query query_type,\n                             void *query_input,\n                             void *query_output );\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/inc/liblfds711/lfds711_freelist.h",
    "content": "/***** defines *****/\n#define LFDS711_FREELIST_GET_KEY_FROM_ELEMENT( freelist_element )             ( (freelist_element).key )\n#define LFDS711_FREELIST_SET_KEY_IN_ELEMENT( freelist_element, new_key )      ( (freelist_element).key = (void *) (lfds711_pal_uint_t) (new_key) )\n#define LFDS711_FREELIST_GET_VALUE_FROM_ELEMENT( freelist_element )           ( (freelist_element).value )\n#define LFDS711_FREELIST_SET_VALUE_IN_ELEMENT( freelist_element, new_value )  ( (freelist_element).value = (void *) (lfds711_pal_uint_t) (new_value) )\n#define LFDS711_FREELIST_GET_USER_STATE_FROM_STATE( freelist_state )          ( (freelist_state).user_state )\n\n#define LFDS711_FREELIST_ELIMINATION_ARRAY_ELEMENT_SIZE_IN_FREELIST_ELEMENTS  ( LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES / sizeof(struct lfds711_freelist_element *) )\n\n/***** enums *****/\nenum lfds711_freelist_query\n{\n  LFDS711_FREELIST_QUERY_SINGLETHREADED_GET_COUNT,\n  LFDS711_FREELIST_QUERY_SINGLETHREADED_VALIDATE,\n  LFDS711_FREELIST_QUERY_GET_ELIMINATION_ARRAY_EXTRA_ELEMENTS_IN_FREELIST_ELEMENTS\n};\n\n/***** structures *****/\nstruct lfds711_freelist_element\n{\n  struct lfds711_freelist_element\n    *next;\n\n  void\n    *key,\n    *value;\n};\n\nstruct lfds711_freelist_state\n{\n  struct lfds711_freelist_element LFDS711_PAL_ALIGN(LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES)\n    *volatile top[PAC_SIZE];\n\n  lfds711_pal_uint_t LFDS711_PAL_ALIGN(LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES)\n    elimination_array_size_in_elements;\n\n  struct lfds711_freelist_element * volatile\n    (*elimination_array)[LFDS711_FREELIST_ELIMINATION_ARRAY_ELEMENT_SIZE_IN_FREELIST_ELEMENTS];\n\n  void\n    *user_state;\n\n  struct lfds711_misc_backoff_state\n    pop_backoff,\n    push_backoff;\n};\n\n/***** public prototypes *****/\nvoid lfds711_freelist_init_valid_on_current_logical_core( struct lfds711_freelist_state *fs,\n                                                          struct lfds711_freelist_element * volatile (*elimination_array)[LFDS711_FREELIST_ELIMINATION_ARRAY_ELEMENT_SIZE_IN_FREELIST_ELEMENTS],\n                                                          lfds711_pal_uint_t elimination_array_size_in_elements,\n                                                          void *user_state );\n  // TRD : used in conjunction with the #define LFDS711_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE\n\nvoid lfds711_freelist_cleanup( struct lfds711_freelist_state *fs,\n                               void (*element_cleanup_callback)(struct lfds711_freelist_state *fs, struct lfds711_freelist_element *fe) );\n\nvoid lfds711_freelist_push( struct lfds711_freelist_state *fs,\n                                   struct lfds711_freelist_element *fe,\n                                   struct lfds711_prng_st_state *psts );\n\nint lfds711_freelist_pop( struct lfds711_freelist_state *fs,\n                          struct lfds711_freelist_element **fe,\n                          struct lfds711_prng_st_state *psts );\n\nvoid lfds711_freelist_query( struct lfds711_freelist_state *fs,\n                             enum lfds711_freelist_query query_type,\n                             void *query_input,\n                             void *query_output );\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/inc/liblfds711/lfds711_hash_addonly.h",
    "content": "/***** defines *****/\n#define LFDS711_HASH_A_GET_KEY_FROM_ELEMENT( hash_a_element )             ( (hash_a_element).key )\n#define LFDS711_HASH_A_SET_KEY_IN_ELEMENT( hash_a_element, new_key )      ( (hash_a_element).key = (void *) (lfds711_pal_uint_t) (new_key) )\n#define LFDS711_HASH_A_GET_VALUE_FROM_ELEMENT( hash_a_element )           ( LFDS711_MISC_BARRIER_LOAD, (hash_a_element).value )\n#define LFDS711_HASH_A_SET_VALUE_IN_ELEMENT( hash_a_element, new_value )  { LFDS711_PAL_ATOMIC_SET( &(hash_a_element).value, new_value ); }\n#define LFDS711_HASH_A_GET_USER_STATE_FROM_STATE( hash_a_state )          ( (hash_a_state).user_state )\n\n// TRD : a quality hash function, provided for user convenience - note hash must be initialized to 0 before the first call by the user\n\n#if( LFDS711_PAL_ALIGN_SINGLE_POINTER == 4 )\n  // TRD : void *data, lfds711_pal_uint_t data_length_in_bytes, lfds711_pal_uint_t hash\n  #define LFDS711_HASH_A_HASH_FUNCTION( data, data_length_in_bytes, hash )  {                                                           \\\n                                                                              lfds711_pal_uint_t                                        \\\n                                                                                loop;                                                   \\\n                                                                                                                                        \\\n                                                                              for( loop = 0 ; loop < (data_length_in_bytes) ; loop++ )  \\\n                                                                              {                                                         \\\n                                                                                (hash) += *( (char unsigned *) (data) + loop );         \\\n                                                                                (hash) = ((hash) ^ ((hash) >> 16)) * 0x85ebca6bUL;      \\\n                                                                                (hash) = ((hash) ^ ((hash) >> 13)) * 0xc2b2ae35UL;      \\\n                                                                                (hash) = (hash ^ (hash >> 16));                         \\\n                                                                              }                                                         \\\n                                                                            }\n#endif\n\n#if( LFDS711_PAL_ALIGN_SINGLE_POINTER == 8 )\n  // TRD : void *data, lfds711_pal_uint_t data_length_in_bytes, lfds711_pal_uint_t hash\n  #define LFDS711_HASH_A_HASH_FUNCTION( data, data_length_in_bytes, hash )  {                                                                \\\n                                                                              lfds711_pal_uint_t                                             \\\n                                                                                loop;                                                        \\\n                                                                                                                                             \\\n                                                                              for( loop = 0 ; loop < (data_length_in_bytes) ; loop++ )       \\\n                                                                              {                                                              \\\n                                                                                (hash) += *( (char unsigned *) (data) + loop );              \\\n                                                                                (hash) = ((hash) ^ ((hash) >> 30)) * 0xBF58476D1CE4E5B9ULL;  \\\n                                                                                (hash) = ((hash) ^ ((hash) >> 27)) * 0x94D049BB133111EBULL;  \\\n                                                                                (hash) = (hash ^ (hash >> 31));                              \\\n                                                                              }                                                              \\\n                                                                            }\n#endif\n\n/***** enums *****/\nenum lfds711_hash_a_existing_key\n{\n  LFDS711_HASH_A_EXISTING_KEY_OVERWRITE,\n  LFDS711_HASH_A_EXISTING_KEY_FAIL\n};\n\nenum lfds711_hash_a_insert_result\n{\n  LFDS711_HASH_A_PUT_RESULT_FAILURE_EXISTING_KEY,\n  LFDS711_HASH_A_PUT_RESULT_SUCCESS_OVERWRITE,\n  LFDS711_HASH_A_PUT_RESULT_SUCCESS\n};\n\nenum lfds711_hash_a_query\n{\n  LFDS711_HASH_A_QUERY_GET_POTENTIALLY_INACCURATE_COUNT,\n  LFDS711_HASH_A_QUERY_SINGLETHREADED_VALIDATE\n};\n\n/***** structs *****/\nstruct lfds711_hash_a_element\n{\n  struct lfds711_btree_au_element\n    baue;\n\n  void\n    *key;\n\n  void LFDS711_PAL_ALIGN(LFDS711_PAL_ALIGN_SINGLE_POINTER)\n    *volatile value;\n};\n\nstruct lfds711_hash_a_iterate\n{\n  struct lfds711_btree_au_element\n    *baue;\n\n  struct lfds711_btree_au_state\n    *baus,\n    *baus_end;\n};\n\nstruct lfds711_hash_a_state\n{\n  enum lfds711_hash_a_existing_key\n    existing_key;\n\n  int\n    (*key_compare_function)( void const *new_key, void const *existing_key );\n\n  lfds711_pal_uint_t\n    array_size;\n\n  struct lfds711_btree_au_state\n    *baus_array;\n\n  void\n    (*element_cleanup_callback)( struct lfds711_hash_a_state *has, struct lfds711_hash_a_element *hae ),\n    (*key_hash_function)( void const *key, lfds711_pal_uint_t *hash ),\n    *user_state;\n};\n\n/***** public prototypes *****/\nvoid lfds711_hash_a_init_valid_on_current_logical_core( struct lfds711_hash_a_state *has,\n                                                        struct lfds711_btree_au_state *baus_array,\n                                                        lfds711_pal_uint_t array_size,\n                                                        int (*key_compare_function)(void const *new_key, void const *existing_key),\n                                                        void (*key_hash_function)(void const *key, lfds711_pal_uint_t *hash),\n                                                        enum lfds711_hash_a_existing_key existing_key,\n                                                        void *user_state );\n  // TRD : used in conjunction with the #define LFDS711_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE\n\nvoid lfds711_hash_a_cleanup( struct lfds711_hash_a_state *has,\n                             void (*element_cleanup_function)(struct lfds711_hash_a_state *has, struct lfds711_hash_a_element *hae) );\n\nenum lfds711_hash_a_insert_result lfds711_hash_a_insert( struct lfds711_hash_a_state *has,\n                                                         struct lfds711_hash_a_element *hae,\n                                                         struct lfds711_hash_a_element **existing_hae );\n  // TRD : if existing_value is not NULL and the key exists, existing_hae is set to the hash element of the existing key\n\nint lfds711_hash_a_get_by_key( struct lfds711_hash_a_state *has,\n                               int (*key_compare_function)(void const *new_key, void const *existing_key),\n                               void (*key_hash_function)(void const *key, lfds711_pal_uint_t *hash),\n                               void *key,\n                               struct lfds711_hash_a_element **hae );\n\nvoid lfds711_hash_a_iterate_init( struct lfds711_hash_a_state *has, struct lfds711_hash_a_iterate *hai );\nint lfds711_hash_a_iterate( struct lfds711_hash_a_iterate *hai, struct lfds711_hash_a_element **hae );\n\nvoid lfds711_hash_a_query( struct lfds711_hash_a_state *has,\n                           enum lfds711_hash_a_query query_type,\n                           void *query_input,\n                           void *query_output );\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/inc/liblfds711/lfds711_list_addonly_singlylinked_ordered.h",
    "content": "/***** defines *****/\n#define LFDS711_LIST_ASO_GET_START( list_aso_state )                                             ( LFDS711_MISC_BARRIER_LOAD, (list_aso_state).start->next )\n#define LFDS711_LIST_ASO_GET_NEXT( list_aso_element )                                            ( LFDS711_MISC_BARRIER_LOAD, (list_aso_element).next )\n#define LFDS711_LIST_ASO_GET_START_AND_THEN_NEXT( list_aso_state, pointer_to_list_aso_element )  ( (pointer_to_list_aso_element) == NULL ? ( (pointer_to_list_aso_element) = LFDS711_LIST_ASO_GET_START(list_aso_state) ) : ( (pointer_to_list_aso_element) = LFDS711_LIST_ASO_GET_NEXT(*(pointer_to_list_aso_element)) ) )\n#define LFDS711_LIST_ASO_GET_KEY_FROM_ELEMENT( list_aso_element )                                ( (list_aso_element).key )\n#define LFDS711_LIST_ASO_SET_KEY_IN_ELEMENT( list_aso_element, new_key )                         ( (list_aso_element).key = (void *) (lfds711_pal_uint_t) (new_key) )\n#define LFDS711_LIST_ASO_GET_VALUE_FROM_ELEMENT( list_aso_element )                              ( LFDS711_MISC_BARRIER_LOAD, (list_aso_element).value )\n#define LFDS711_LIST_ASO_SET_VALUE_IN_ELEMENT( list_aso_element, new_value )                     { LFDS711_PAL_ATOMIC_SET( &(list_aso_element).value, new_value ); }\n#define LFDS711_LIST_ASO_GET_USER_STATE_FROM_STATE( list_aso_state )                             ( (list_aso_state).user_state )\n\n/***** enums *****/\nenum lfds711_list_aso_existing_key\n{\n  LFDS711_LIST_ASO_EXISTING_KEY_OVERWRITE,\n  LFDS711_LIST_ASO_EXISTING_KEY_FAIL\n};\n\nenum lfds711_list_aso_insert_result\n{\n  LFDS711_LIST_ASO_INSERT_RESULT_FAILURE_EXISTING_KEY,\n  LFDS711_LIST_ASO_INSERT_RESULT_SUCCESS_OVERWRITE,\n  LFDS711_LIST_ASO_INSERT_RESULT_SUCCESS\n};\n\nenum lfds711_list_aso_query\n{\n  LFDS711_LIST_ASO_QUERY_GET_POTENTIALLY_INACCURATE_COUNT,\n  LFDS711_LIST_ASO_QUERY_SINGLETHREADED_VALIDATE\n};\n\n/***** structures *****/\nstruct lfds711_list_aso_element\n{\n  struct lfds711_list_aso_element LFDS711_PAL_ALIGN(LFDS711_PAL_ALIGN_SINGLE_POINTER)\n    *volatile next;\n\n  void LFDS711_PAL_ALIGN(LFDS711_PAL_ALIGN_SINGLE_POINTER)\n    *volatile value;\n\n  void\n    *key;\n};\n\nstruct lfds711_list_aso_state\n{\n  struct lfds711_list_aso_element LFDS711_PAL_ALIGN(LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES)\n    dummy_element;\n\n  struct lfds711_list_aso_element LFDS711_PAL_ALIGN(LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES)\n    *start;\n\n  int\n    (*key_compare_function)( void const *new_key, void const *existing_key );\n\n  enum lfds711_list_aso_existing_key\n    existing_key;\n\n  void\n    *user_state;\n\n  struct lfds711_misc_backoff_state\n    insert_backoff;\n};\n\n/***** public prototypes *****/\nvoid lfds711_list_aso_init_valid_on_current_logical_core( struct lfds711_list_aso_state *lasos,\n                                                          int (*key_compare_function)(void const *new_key, void const *existing_key),\n                                                          enum lfds711_list_aso_existing_key existing_key,\n                                                          void *user_state );\n  // TRD : used in conjunction with the #define LFDS711_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE\n\nvoid lfds711_list_aso_cleanup( struct lfds711_list_aso_state *lasos,\n                               void (*element_cleanup_callback)(struct lfds711_list_aso_state *lasos, struct lfds711_list_aso_element *lasoe) );\n\nenum lfds711_list_aso_insert_result lfds711_list_aso_insert( struct lfds711_list_aso_state *lasos,\n                                                             struct lfds711_list_aso_element *lasoe,\n                                                             struct lfds711_list_aso_element **existing_lasoe );\n\nint lfds711_list_aso_get_by_key( struct lfds711_list_aso_state *lasos,\n                                 void *key,\n                                 struct lfds711_list_aso_element **lasoe );\n\nvoid lfds711_list_aso_query( struct lfds711_list_aso_state *lasos,\n                             enum lfds711_list_aso_query query_type,\n                             void *query_input,\n                             void *query_output );\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/inc/liblfds711/lfds711_list_addonly_singlylinked_unordered.h",
    "content": "/***** defines *****/\n#define LFDS711_LIST_ASU_GET_START( list_asu_state )                                             ( LFDS711_MISC_BARRIER_LOAD, (list_asu_state).start->next )\n#define LFDS711_LIST_ASU_GET_NEXT( list_asu_element )                                            ( LFDS711_MISC_BARRIER_LOAD, (list_asu_element).next )\n#define LFDS711_LIST_ASU_GET_START_AND_THEN_NEXT( list_asu_state, pointer_to_list_asu_element )  ( (pointer_to_list_asu_element) == NULL ? ( (pointer_to_list_asu_element) = LFDS711_LIST_ASU_GET_START(list_asu_state) ) : ( (pointer_to_list_asu_element) = LFDS711_LIST_ASU_GET_NEXT(*(pointer_to_list_asu_element)) ) )\n#define LFDS711_LIST_ASU_GET_KEY_FROM_ELEMENT( list_asu_element )                                ( (list_asu_element).key )\n#define LFDS711_LIST_ASU_SET_KEY_IN_ELEMENT( list_asu_element, new_key )                         ( (list_asu_element).key = (void *) (lfds711_pal_uint_t) (new_key) )\n#define LFDS711_LIST_ASU_GET_VALUE_FROM_ELEMENT( list_asu_element )                              ( LFDS711_MISC_BARRIER_LOAD, (list_asu_element).value )\n#define LFDS711_LIST_ASU_SET_VALUE_IN_ELEMENT( list_asu_element, new_value )                     { LFDS711_PAL_ATOMIC_SET( &(list_asu_element).value, new_value ); }\n#define LFDS711_LIST_ASU_GET_USER_STATE_FROM_STATE( list_asu_state )                             ( (list_asu_state).user_state )\n\n/***** enums *****/\nenum lfds711_list_asu_position\n{\n  LFDS711_LIST_ASU_POSITION_START,\n  LFDS711_LIST_ASU_POSITION_END,\n  LFDS711_LIST_ASU_POSITION_AFTER\n};\n\nenum lfds711_list_asu_query\n{\n  LFDS711_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT,\n  LFDS711_LIST_ASU_QUERY_SINGLETHREADED_VALIDATE\n};\n\n/***** structures *****/\nstruct lfds711_list_asu_element\n{\n  struct lfds711_list_asu_element LFDS711_PAL_ALIGN(LFDS711_PAL_ALIGN_SINGLE_POINTER)\n    *volatile next;\n\n  void LFDS711_PAL_ALIGN(LFDS711_PAL_ALIGN_SINGLE_POINTER)\n    *volatile value;\n\n  void\n    *key;\n};\n\nstruct lfds711_list_asu_state\n{\n  struct lfds711_list_asu_element LFDS711_PAL_ALIGN(LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES)\n    dummy_element;\n\n  struct lfds711_list_asu_element LFDS711_PAL_ALIGN(LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES)\n    *volatile end;\n\n  struct lfds711_list_asu_element LFDS711_PAL_ALIGN(LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES)\n    *start;\n\n  void\n    *user_state;\n\n  struct lfds711_misc_backoff_state\n    after_backoff,\n    end_backoff,\n    start_backoff;\n};\n\n/***** public prototypes *****/\nvoid lfds711_list_asu_init_valid_on_current_logical_core( struct lfds711_list_asu_state *lasus,\n                                                          void *user_state );\n  // TRD : used in conjunction with the #define LFDS711_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE\n\nvoid lfds711_list_asu_cleanup( struct lfds711_list_asu_state *lasus,\n                               void (*element_cleanup_callback)(struct lfds711_list_asu_state *lasus, struct lfds711_list_asu_element *lasue) );\n\nvoid lfds711_list_asu_insert_at_position( struct lfds711_list_asu_state *lasus,\n                                          struct lfds711_list_asu_element *lasue,\n                                          struct lfds711_list_asu_element *lasue_predecessor,\n                                          enum lfds711_list_asu_position position );\n\nvoid lfds711_list_asu_insert_at_start( struct lfds711_list_asu_state *lasus,\n                                       struct lfds711_list_asu_element *lasue );\n\nvoid lfds711_list_asu_insert_at_end( struct lfds711_list_asu_state *lasus,\n                                     struct lfds711_list_asu_element *lasue );\n\nvoid lfds711_list_asu_insert_after_element( struct lfds711_list_asu_state *lasus,\n                                            struct lfds711_list_asu_element *lasue,\n                                            struct lfds711_list_asu_element *lasue_predecessor );\n\nint lfds711_list_asu_get_by_key( struct lfds711_list_asu_state *lasus,\n                                 int (*key_compare_function)(void const *new_key, void const *existing_key),\n                                 void *key, \n                                 struct lfds711_list_asu_element **lasue );\n\nvoid lfds711_list_asu_query( struct lfds711_list_asu_state *lasus,\n                             enum lfds711_list_asu_query query_type,\n                             void *query_input,\n                             void *query_output );\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/inc/liblfds711/lfds711_misc.h",
    "content": "/***** defines *****/\n#define LFDS711_MISC_VERSION_STRING   \"7.1.1\"\n#define LFDS711_MISC_VERSION_INTEGER  711\n\n#ifndef NULL\n  #define NULL ( (void *) 0 )\n#endif\n\n#define POINTER   0\n#define COUNTER   1\n#define PAC_SIZE  2\n\n#define LFDS711_MISC_DELIBERATELY_CRASH  { char *c = 0; *c = 0; }\n\n#if( !defined LFDS711_PAL_ATOMIC_ADD )\n  #define LFDS711_PAL_NO_ATOMIC_ADD\n  #define LFDS711_MISC_ATOMIC_SUPPORT_ADD 0\n  #define LFDS711_PAL_ATOMIC_ADD( pointer_to_target, value, result, result_type )        \\\n  {                                                                                      \\\n    LFDS711_PAL_ASSERT( !\"LFDS711_PAL_ATOMIC_ADD not implemented for this platform.\" );  \\\n    LFDS711_MISC_DELIBERATELY_CRASH;                                                     \\\n  }\n#else\n  #define LFDS711_MISC_ATOMIC_SUPPORT_ADD 1\n#endif\n\n#if( !defined LFDS711_PAL_ATOMIC_CAS )\n  #define LFDS711_PAL_NO_ATOMIC_CAS\n  #define LFDS711_MISC_ATOMIC_SUPPORT_CAS 0\n  #define LFDS711_PAL_ATOMIC_CAS( pointer_to_destination, pointer_to_compare, new_destination, cas_strength, result )  \\\n  {                                                                                                                    \\\n    LFDS711_PAL_ASSERT( !\"LFDS711_PAL_ATOMIC_CAS not implemented for this platform.\" );                                \\\n    (result) = 0;                                                                                                      \\\n    LFDS711_MISC_DELIBERATELY_CRASH;                                                                                   \\\n  }\n#else\n  #define LFDS711_MISC_ATOMIC_SUPPORT_CAS 1\n#endif\n\n#if( !defined LFDS711_PAL_ATOMIC_DWCAS )\n  #define LFDS711_PAL_NO_ATOMIC_DWCAS\n  #define LFDS711_MISC_ATOMIC_SUPPORT_DWCAS 0\n  #define LFDS711_PAL_ATOMIC_DWCAS( pointer_to_destination, pointer_to_compare, pointer_to_new_destination, cas_strength, result )  \\\n  {                                                                                                                                 \\\n    LFDS711_PAL_ASSERT( !\"LFDS711_PAL_ATOMIC_DWCAS not implemented for this platform.\" );                                           \\\n    (result) = 0;                                                                                                                   \\\n    LFDS711_MISC_DELIBERATELY_CRASH;                                                                                                \\\n  }\n#else\n  #define LFDS711_MISC_ATOMIC_SUPPORT_DWCAS 1\n#endif\n\n#if( !defined LFDS711_PAL_ATOMIC_EXCHANGE )\n  #define LFDS711_PAL_NO_ATOMIC_EXCHANGE\n  #define LFDS711_MISC_ATOMIC_SUPPORT_EXCHANGE 0\n  #define LFDS711_PAL_ATOMIC_EXCHANGE( pointer_to_destination, new_value, original_value, value_type )  \\\n  {                                                                                                     \\\n    LFDS711_PAL_ASSERT( !\"LFDS711_PAL_ATOMIC_EXCHANGE not implemented for this platform.\" );            \\\n    LFDS711_MISC_DELIBERATELY_CRASH;                                                                    \\\n  }\n#else\n  #define LFDS711_MISC_ATOMIC_SUPPORT_EXCHANGE 1\n#endif\n\n#if( !defined LFDS711_PAL_ATOMIC_SET )\n  #define LFDS711_PAL_NO_ATOMIC_SET\n  #define LFDS711_MISC_ATOMIC_SUPPORT_SET 0\n  #define LFDS711_PAL_ATOMIC_SET( pointer_to_destination, new_value )                    \\\n  {                                                                                      \\\n    LFDS711_PAL_ASSERT( !\"LFDS711_PAL_ATOMIC_SET not implemented for this platform.\" );  \\\n    LFDS711_MISC_DELIBERATELY_CRASH;                                                     \\\n  }\n#else\n  #define LFDS711_MISC_ATOMIC_SUPPORT_SET 1\n#endif\n\n#if( defined LFDS711_PAL_BARRIER_COMPILER_LOAD && defined LFDS711_PAL_BARRIER_PROCESSOR_LOAD )\n  #define LFDS711_MISC_BARRIER_LOAD  ( LFDS711_PAL_BARRIER_COMPILER_LOAD, LFDS711_PAL_BARRIER_PROCESSOR_LOAD, LFDS711_PAL_BARRIER_COMPILER_LOAD )\n#endif\n\n#if( (!defined LFDS711_PAL_BARRIER_COMPILER_LOAD || defined LFDS711_PAL_COMPILER_BARRIERS_MISSING_PRESUMED_HAVING_A_GOOD_TIME) && defined LFDS711_PAL_BARRIER_PROCESSOR_LOAD )\n  #define LFDS711_MISC_BARRIER_LOAD  LFDS711_PAL_BARRIER_PROCESSOR_LOAD\n#endif\n\n#if( defined LFDS711_PAL_BARRIER_COMPILER_LOAD && !defined LFDS711_PAL_BARRIER_PROCESSOR_LOAD )\n  #define LFDS711_MISC_BARRIER_LOAD  LFDS711_PAL_BARRIER_COMPILER_LOAD\n#endif\n\n#if( !defined LFDS711_PAL_BARRIER_COMPILER_LOAD && !defined LFDS711_PAL_BARRIER_PROCESSOR_LOAD )\n  #define LFDS711_MISC_BARRIER_LOAD\n#endif\n\n#if( defined LFDS711_PAL_BARRIER_COMPILER_STORE && defined LFDS711_PAL_BARRIER_PROCESSOR_STORE )\n  #define LFDS711_MISC_BARRIER_STORE  ( LFDS711_PAL_BARRIER_COMPILER_STORE, LFDS711_PAL_BARRIER_PROCESSOR_STORE, LFDS711_PAL_BARRIER_COMPILER_STORE )\n#endif\n\n#if( (!defined LFDS711_PAL_BARRIER_COMPILER_STORE || defined LFDS711_PAL_COMPILER_BARRIERS_MISSING_PRESUMED_HAVING_A_GOOD_TIME) && defined LFDS711_PAL_BARRIER_PROCESSOR_STORE )\n  #define LFDS711_MISC_BARRIER_STORE  LFDS711_PAL_BARRIER_PROCESSOR_STORE\n#endif\n\n#if( defined LFDS711_PAL_BARRIER_COMPILER_STORE && !defined LFDS711_PAL_BARRIER_PROCESSOR_STORE )\n  #define LFDS711_MISC_BARRIER_STORE  LFDS711_PAL_BARRIER_COMPILER_STORE\n#endif\n\n#if( !defined LFDS711_PAL_BARRIER_COMPILER_STORE && !defined LFDS711_PAL_BARRIER_PROCESSOR_STORE )\n  #define LFDS711_MISC_BARRIER_STORE\n#endif\n\n#if( defined LFDS711_PAL_BARRIER_COMPILER_FULL && defined LFDS711_PAL_BARRIER_PROCESSOR_FULL )\n  #define LFDS711_MISC_BARRIER_FULL  ( LFDS711_PAL_BARRIER_COMPILER_FULL, LFDS711_PAL_BARRIER_PROCESSOR_FULL, LFDS711_PAL_BARRIER_COMPILER_FULL )\n#endif\n\n#if( (!defined LFDS711_PAL_BARRIER_COMPILER_FULL || defined LFDS711_PAL_COMPILER_BARRIERS_MISSING_PRESUMED_HAVING_A_GOOD_TIME) && defined LFDS711_PAL_BARRIER_PROCESSOR_FULL )\n  #define LFDS711_MISC_BARRIER_FULL  LFDS711_PAL_BARRIER_PROCESSOR_FULL\n#endif\n\n#if( defined LFDS711_PAL_BARRIER_COMPILER_FULL && !defined LFDS711_PAL_BARRIER_PROCESSOR_FULL )\n  #define LFDS711_MISC_BARRIER_FULL  LFDS711_PAL_BARRIER_COMPILER_FULL\n#endif\n\n#if( !defined LFDS711_PAL_BARRIER_COMPILER_FULL && !defined LFDS711_PAL_BARRIER_PROCESSOR_FULL )\n  #define LFDS711_MISC_BARRIER_FULL\n#endif\n\n#if( (defined LFDS711_PAL_BARRIER_COMPILER_LOAD && defined LFDS711_PAL_BARRIER_COMPILER_STORE && defined LFDS711_PAL_BARRIER_COMPILER_FULL) || (defined LFDS711_PAL_COMPILER_BARRIERS_MISSING_PRESUMED_HAVING_A_GOOD_TIME) )\n  #define LFDS711_MISC_ATOMIC_SUPPORT_COMPILER_BARRIERS  1\n#else\n  #define LFDS711_MISC_ATOMIC_SUPPORT_COMPILER_BARRIERS  0\n#endif\n\n#if( defined LFDS711_PAL_BARRIER_PROCESSOR_LOAD && defined LFDS711_PAL_BARRIER_PROCESSOR_STORE && defined LFDS711_PAL_BARRIER_PROCESSOR_FULL )\n  #define LFDS711_MISC_ATOMIC_SUPPORT_PROCESSOR_BARRIERS  1\n#else\n  #define LFDS711_MISC_ATOMIC_SUPPORT_PROCESSOR_BARRIERS  0\n#endif\n\n#define LFDS711_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE  LFDS711_MISC_BARRIER_LOAD\n#define LFDS711_MISC_FLUSH                                                                                    { LFDS711_MISC_BARRIER_STORE; lfds711_misc_force_store(); }\n\n/***** enums *****/\nenum lfds711_misc_cas_strength\n{\n  // TRD : GCC defined values\n  LFDS711_MISC_CAS_STRENGTH_STRONG = 0,\n  LFDS711_MISC_CAS_STRENGTH_WEAK   = 1,\n};\n\nenum lfds711_misc_validity\n{\n  LFDS711_MISC_VALIDITY_UNKNOWN,\n  LFDS711_MISC_VALIDITY_VALID,\n  LFDS711_MISC_VALIDITY_INVALID_LOOP,\n  LFDS711_MISC_VALIDITY_INVALID_MISSING_ELEMENTS,\n  LFDS711_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS,\n  LFDS711_MISC_VALIDITY_INVALID_TEST_DATA,\n  LFDS711_MISC_VALIDITY_INVALID_ORDER,\n  LFDS711_MISC_VALIDITY_INVALID_ATOMIC_FAILED,\n  LFDS711_MISC_VALIDITY_INDETERMINATE_NONATOMIC_PASSED,\n};\n\nenum lfds711_misc_flag\n{\n  LFDS711_MISC_FLAG_LOWERED,\n  LFDS711_MISC_FLAG_RAISED\n};\n\nenum lfds711_misc_query\n{\n  LFDS711_MISC_QUERY_GET_BUILD_AND_VERSION_STRING\n};\n\nenum lfds711_misc_data_structure\n{\n  LFDS711_MISC_DATA_STRUCTURE_BTREE_AU,\n  LFDS711_MISC_DATA_STRUCTURE_FREELIST,\n  LFDS711_MISC_DATA_STRUCTURE_HASH_A,\n  LFDS711_MISC_DATA_STRUCTURE_LIST_AOS,\n  LFDS711_MISC_DATA_STRUCTURE_LIST_ASU,\n  LFDS711_MISC_DATA_STRUCTURE_QUEUE_BMM,\n  LFDS711_MISC_DATA_STRUCTURE_QUEUE_BSS,\n  LFDS711_MISC_DATA_STRUCTURE_QUEUE_UMM,\n  LFDS711_MISC_DATA_STRUCTURE_RINGBUFFER,\n  LFDS711_MISC_DATA_STRUCTURE_STACK,\n  LFDS711_MISC_DATA_STRUCTURE_COUNT\n};\n\n/***** struct *****/\nstruct lfds711_misc_backoff_state\n{\n  lfds711_pal_uint_t volatile LFDS711_PAL_ALIGN(LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES)\n    lock;\n\n  lfds711_pal_uint_t\n    backoff_iteration_frequency_counters[2],\n    metric,\n    total_operations;\n};\n\nstruct lfds711_misc_globals\n{\n  struct lfds711_prng_state\n    ps;\n};\n\nstruct lfds711_misc_validation_info\n{\n  lfds711_pal_uint_t\n    min_elements,\n    max_elements;\n};\n\n/***** externs *****/\nextern struct lfds711_misc_globals\n  lfds711_misc_globals;\n\n/***** public prototypes *****/\nstatic LFDS711_PAL_INLINE void lfds711_misc_force_store( void );\n\nvoid lfds711_misc_query( enum lfds711_misc_query query_type, void *query_input, void *query_output );\n\n/***** public in-line functions *****/\n#pragma prefast( disable : 28112, \"blah\" )\n\nstatic LFDS711_PAL_INLINE void lfds711_misc_force_store()\n{\n  lfds711_pal_uint_t volatile LFDS711_PAL_ALIGN(LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES)\n    destination;\n\n  LFDS711_PAL_ATOMIC_SET( &destination, 0 );\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/inc/liblfds711/lfds711_porting_abstraction_layer_compiler.h",
    "content": "/****************************************************************************/\n#if( defined __GNUC__ )\n  // TRD : makes checking GCC versions much tidier\n  #define LFDS711_PAL_GCC_VERSION ( __GNUC__ * 100 + __GNUC_MINOR__ * 10 + __GNUC_PATCHLEVEL__ )\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined _MSC_VER && _MSC_VER >= 1400 )\n\n  #ifdef LFDS711_PAL_COMPILER\n    #error More than one porting abstraction layer matches the current platform in lfds711_porting_abstraction_layer_compiler.h\n  #endif\n\n  #define LFDS711_PAL_COMPILER\n\n  #define LFDS711_PAL_COMPILER_STRING            \"MSVC\"\n\n  #define LFDS711_PAL_ALIGN(alignment)           __declspec( align(alignment) )\n  #define LFDS711_PAL_INLINE                     __forceinline\n\n  #define LFDS711_PAL_BARRIER_COMPILER_LOAD      _ReadBarrier()\n  #define LFDS711_PAL_BARRIER_COMPILER_STORE     _WriteBarrier()\n  #define LFDS711_PAL_BARRIER_COMPILER_FULL      _ReadWriteBarrier()\n\n  /* TRD : there are four processors to consider;\n\n           . ARM32    (32 bit, ADD, CAS, DWCAS, EXCHANGE, SET) (defined _M_ARM)\n           . Itanium  (64 bit, ADD, CAS,        EXCHANGE, SET) (defined _M_IA64)\n           . x64      (64 bit, ADD, CAS, DWCAS, EXCHANGE, SET) (defined _M_X64 || defined _M_AMD64)\n           . x86      (32 bit, ADD, CAS, DWCAS, EXCHANGE, SET) (defined _M_IX86)\n\n           can't find any indications of 64-bit ARM support yet\n\n           ARM has better intrinsics than the others, as there are no-fence variants\n\n           in theory we also have to deal with 32-bit Windows on a 64-bit platform,\n           and I presume we'd see the compiler properly indicate this in its macros,\n           but this would require that we use 32-bit atomics on the 64-bit platforms,\n           while keeping 64-bit cache line lengths and so on, and this is just so\n           wierd a thing to do these days that it's not supported\n  */\n\n  #if( defined _M_ARM )\n    #define LFDS711_PAL_BARRIER_PROCESSOR_LOAD   __dmb( _ARM_BARRIER_ISH )\n    #define LFDS711_PAL_BARRIER_PROCESSOR_STORE  __dmb( _ARM_BARRIER_ISHST )\n    #define LFDS711_PAL_BARRIER_PROCESSOR_FULL   __dmb( _ARM_BARRIER_ISH )\n\n    #define LFDS711_PAL_ATOMIC_ADD( pointer_to_target, value, result, result_type )                                  \\\n    {                                                                                                                \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                             \\\n      (result) = (result_type) _InterlockedAdd_nf( (int long volatile *) (pointer_to_target), (int long) (value) );  \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                             \\\n    }\n\n    #define LFDS711_PAL_ATOMIC_CAS( pointer_to_destination, pointer_to_compare, new_destination, cas_strength, result )                                                                                          \\\n    {                                                                                                                                                                                                            \\\n      lfds711_pal_uint_t                                                                                                                                                                                         \\\n        original_compare;                                                                                                                                                                                        \\\n                                                                                                                                                                                                                 \\\n      original_compare = (lfds711_pal_uint_t) *(pointer_to_compare);                                                                                                                                             \\\n                                                                                                                                                                                                                 \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                                                                                                         \\\n      *(lfds711_pal_uint_t *) (pointer_to_compare) = (lfds711_pal_uint_t) _InterlockedCompareExchange_nf( (long volatile *) (pointer_to_destination), (long) (new_destination), (long) *(pointer_to_compare) );  \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                                                                                                         \\\n                                                                                                                                                                                                                 \\\n      result = (char unsigned) ( original_compare == (lfds711_pal_uint_t) *(pointer_to_compare) );                                                                                                               \\\n    }\n\n    #define LFDS711_PAL_ATOMIC_DWCAS( pointer_to_destination, pointer_to_compare, pointer_to_new_destination, cas_strength, result )                                                                        \\\n    {                                                                                                                                                                                                       \\\n      __int64                                                                                                                                                                                               \\\n        original_compare;                                                                                                                                                                                   \\\n                                                                                                                                                                                                            \\\n      original_compare = *(__int64 *) (pointer_to_compare);                                                                                                                                                 \\\n                                                                                                                                                                                                            \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                                                                                                    \\\n      *(__int64 *) (pointer_to_compare) = _InterlockedCompareExchange64_nf( (__int64 volatile *) (pointer_to_destination), *(__int64 *) (pointer_to_new_destination), *(__int64 *) (pointer_to_compare) );  \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                                                                                                    \\\n                                                                                                                                                                                                            \\\n      (result) = (char unsigned) ( *(__int64 *) (pointer_to_compare) == original_compare );                                                                                                                 \\\n    }\n\n    #define LFDS711_PAL_ATOMIC_EXCHANGE( pointer_to_destination, exchange, exchange_type )                                            \\\n    {                                                                                                                                 \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                              \\\n      (exchange) = (exchange_type) _InterlockedExchange_nf( (int long volatile *) (pointer_to_destination), (int long) (exchange) );  \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                              \\\n    }\n\n    #define LFDS711_PAL_ATOMIC_SET( pointer_to_destination, new_value )                                          \\\n    {                                                                                                            \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                         \\\n      (void) _InterlockedExchange_nf( (int long volatile *) (pointer_to_destination), (int long) (new_value) );  \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                         \\\n    }\n  #endif\n\n  #if( defined _M_IA64 )\n    #define LFDS711_PAL_BARRIER_PROCESSOR_LOAD   __mf()\n    #define LFDS711_PAL_BARRIER_PROCESSOR_STORE  __mf()\n    #define LFDS711_PAL_BARRIER_PROCESSOR_FULL   __mf()\n\n    #define LFDS711_PAL_ATOMIC_ADD( pointer_to_target, value, result, result_type )                                   \\\n    {                                                                                                                 \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                              \\\n      (result) = (result_type) _InterlockedAdd64_acq( (__int64 volatile *) (pointer_to_target), (__int64) (value) );  \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                              \\\n    }\n\n    #define LFDS711_PAL_ATOMIC_CAS( pointer_to_destination, pointer_to_compare, new_destination, cas_strength, result )                                                                                                      \\\n    {                                                                                                                                                                                                                        \\\n      lfds711_pal_uint_t                                                                                                                                                                                                     \\\n        original_compare;                                                                                                                                                                                                    \\\n                                                                                                                                                                                                                             \\\n      original_compare = (lfds711_pal_uint_t) *(pointer_to_compare);                                                                                                                                                         \\\n                                                                                                                                                                                                                             \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                                                                                                                     \\\n      *(lfds711_pal_uint_t *) (pointer_to_compare) = (lfds711_pal_uint_t) _InterlockedCompareExchange64_acq( (__int64 volatile *) (pointer_to_destination), (__int64) (new_destination), (__int64) *(pointer_to_compare) );  \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                                                                                                                     \\\n                                                                                                                                                                                                                             \\\n      result = (char unsigned) ( original_compare == (lfds711_pal_uint_t) *(pointer_to_compare) );                                                                                                                           \\\n    }\n\n    #define LFDS711_PAL_ATOMIC_EXCHANGE( pointer_to_destination, exchange, exchange_type )                                             \\\n    {                                                                                                                                  \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                               \\\n      (exchange) = (exchange_type) _InterlockedExchange64_acq( (__int64 volatile *) (pointer_to_destination), (__int64) (exchange) );  \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                               \\\n    }\n\n    #define LFDS711_PAL_ATOMIC_SET( pointer_to_destination, new_value )                                           \\\n    {                                                                                                             \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                          \\\n      (void) _InterlockedExchange64_acq( (__int64 volatile *) (pointer_to_destination), (__int64) (new_value) );  \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                          \\\n    }\n  #endif\n\n  #if( defined _M_X64 || defined _M_AMD64 )\n    #define LFDS711_PAL_BARRIER_PROCESSOR_LOAD   _mm_lfence()\n    #define LFDS711_PAL_BARRIER_PROCESSOR_STORE  _mm_sfence()\n    #define LFDS711_PAL_BARRIER_PROCESSOR_FULL   _mm_mfence()\n\n    // TRD : no _InterlockedAdd64 for x64 - only the badly named _InterlockedExchangeAdd64, which is the same as _InterlockedAdd64 but returns the *original* value (which we must then add to before we return)\n    #define LFDS711_PAL_ATOMIC_ADD( pointer_to_target, value, result, result_type )                                       \\\n    {                                                                                                                     \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                  \\\n      (result) = (result_type) _InterlockedExchangeAdd64( (__int64 volatile *) (pointer_to_target), (__int64) (value) );  \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                  \\\n      result += value;                                                                                                    \\\n    }\n\n    #define LFDS711_PAL_ATOMIC_CAS( pointer_to_destination, pointer_to_compare, new_destination, cas_strength, result )                                                                                                  \\\n    {                                                                                                                                                                                                                    \\\n      lfds711_pal_uint_t                                                                                                                                                                                                 \\\n        original_compare;                                                                                                                                                                                                \\\n                                                                                                                                                                                                                         \\\n      original_compare = (lfds711_pal_uint_t) *(pointer_to_compare);                                                                                                                                                     \\\n                                                                                                                                                                                                                         \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                                                                                                                 \\\n      *(lfds711_pal_uint_t *) (pointer_to_compare) = (lfds711_pal_uint_t) _InterlockedCompareExchange64( (__int64 volatile *) (pointer_to_destination), (__int64) (new_destination), (__int64) *(pointer_to_compare) );  \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                                                                                                                 \\\n                                                                                                                                                                                                                         \\\n      result = (char unsigned) ( original_compare == (lfds711_pal_uint_t) *(pointer_to_compare) );                                                                                                                       \\\n    }\n\n    #if( _MSC_VER >= 1500 )\n      #define LFDS711_PAL_ATOMIC_DWCAS( pointer_to_destination, pointer_to_compare, pointer_to_new_destination, cas_strength, result )                                                                                                       \\\n      {                                                                                                                                                                                                                                      \\\n        LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                                                                                                                                   \\\n        (result) = (char unsigned) _InterlockedCompareExchange128( (__int64 volatile *) (pointer_to_destination), (__int64) (pointer_to_new_destination[1]), (__int64) (pointer_to_new_destination[0]), (__int64 *) (pointer_to_compare) );  \\\n        LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                                                                                                                                   \\\n      }\n    #endif\n\n    #define LFDS711_PAL_ATOMIC_EXCHANGE( pointer_to_destination, exchange, exchange_type )                                         \\\n    {                                                                                                                              \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                           \\\n      (exchange) = (exchange_type) _InterlockedExchange64( (__int64 volatile *) (pointer_to_destination), (__int64) (exchange) );  \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                           \\\n    }\n\n    #define LFDS711_PAL_ATOMIC_SET( pointer_to_destination, new_value )                                       \\\n    {                                                                                                         \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                      \\\n      (void) _InterlockedExchange64( (__int64 volatile *) (pointer_to_destination), (__int64) (new_value) );  \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                      \\\n    }\n  #endif\n\n  #if( defined _M_IX86 )\n    #define LFDS711_PAL_BARRIER_PROCESSOR_LOAD   lfds711_misc_force_store()\n    #define LFDS711_PAL_BARRIER_PROCESSOR_STORE  lfds711_misc_force_store()\n    #define LFDS711_PAL_BARRIER_PROCESSOR_FULL   lfds711_misc_force_store()\n\n    // TRD : no _InterlockedAdd for x86 - only the badly named _InterlockedExchangeAdd, which is the same as _InterlockedAdd but returns the *original* value (which we must then add to before we return)\n    #define LFDS711_PAL_ATOMIC_ADD( pointer_to_target, value, result, result_type )                                     \\\n    {                                                                                                                   \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                \\\n      (result) = (result_type) _InterlockedExchangeAdd( (__int64 volatile *) (pointer_to_target), (__int64) (value) );  \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                \\\n      result += value;                                                                                                  \\\n    }\n\n    #define LFDS711_PAL_ATOMIC_CAS( pointer_to_destination, pointer_to_compare, new_destination, cas_strength, result )                                                                                       \\\n    {                                                                                                                                                                                                         \\\n      lfds711_pal_uint_t                                                                                                                                                                                      \\\n        original_compare;                                                                                                                                                                                     \\\n                                                                                                                                                                                                              \\\n      /* LFDS711_PAL_ASSERT( (pointer_to_destination) != NULL ); */                                                                                                                                           \\\n      /* LFDS711_PAL_ASSERT( (pointer_to_compare) != NULL ); */                                                                                                                                               \\\n      /* TRD : new_destination can be any value in its range */                                                                                                                                               \\\n      /* TRD : cas_strength can be any value in its range */                                                                                                                                                  \\\n      /* TRD : result can be any value in its range */                                                                                                                                                        \\\n                                                                                                                                                                                                              \\\n      original_compare = (lfds711_pal_uint_t) *(pointer_to_compare);                                                                                                                                          \\\n                                                                                                                                                                                                              \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                                                                                                      \\\n      *(lfds711_pal_uint_t *) (pointer_to_compare) = (lfds711_pal_uint_t) _InterlockedCompareExchange( (long volatile *) (pointer_to_destination), (long) (new_destination), (long) *(pointer_to_compare) );  \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                                                                                                      \\\n                                                                                                                                                                                                              \\\n      result = (char unsigned) ( original_compare == (lfds711_pal_uint_t) *(pointer_to_compare) );                                                                                                            \\\n    }\n\n    #define LFDS711_PAL_ATOMIC_DWCAS( pointer_to_destination, pointer_to_compare, pointer_to_new_destination, cas_strength, result )                                                                     \\\n    {                                                                                                                                                                                                    \\\n      __int64                                                                                                                                                                                            \\\n        original_compare;                                                                                                                                                                                \\\n                                                                                                                                                                                                         \\\n      original_compare = *(__int64 *) (pointer_to_compare);                                                                                                                                              \\\n                                                                                                                                                                                                         \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                                                                                                 \\\n      *(__int64 *) (pointer_to_compare) = _InterlockedCompareExchange64( (__int64 volatile *) (pointer_to_destination), *(__int64 *) (pointer_to_new_destination), *(__int64 *) (pointer_to_compare) );  \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                                                                                                 \\\n                                                                                                                                                                                                         \\\n      (result) = (char unsigned) ( *(__int64 *) (pointer_to_compare) == original_compare );                                                                                                              \\\n    }\n\n    #define LFDS711_PAL_ATOMIC_EXCHANGE( pointer_to_destination, exchange, exchange_type )                                         \\\n    {                                                                                                                              \\\n      /* LFDS711_PAL_ASSERT( (pointer_to_destination) != NULL ); */                                                                \\\n      /* LFDS711_PAL_ASSERT( (pointer_to_exchange) != NULL ); */                                                                   \\\n                                                                                                                                   \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                           \\\n      (exchange) = (exchange_type) _InterlockedExchange( (int long volatile *) (pointer_to_destination), (int long) (exchange) );  \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                           \\\n    }\n\n    #define LFDS711_PAL_ATOMIC_SET( pointer_to_destination, new_value )                                       \\\n    {                                                                                                         \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                      \\\n      (void) _InterlockedExchange( (int long volatile *) (pointer_to_destination), (int long) (new_value) );  \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                      \\\n    }\n  #endif\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined __GNUC__ && LFDS711_PAL_GCC_VERSION >= 412 && LFDS711_PAL_GCC_VERSION < 473 )\n\n  #ifdef LFDS711_PAL_COMPILER\n    #error More than one porting abstraction layer matches the current platform in lfds711_porting_abstraction_layer_compiler.h\n  #endif\n\n  #define LFDS711_PAL_COMPILER\n\n  #define LFDS711_PAL_COMPILER_STRING          \"GCC < 4.7.3\"\n\n  #define LFDS711_PAL_ALIGN(alignment)         __attribute__( (aligned(alignment)) )\n  #define LFDS711_PAL_INLINE                   inline\n\n  static LFDS711_PAL_INLINE void lfds711_pal_barrier_compiler( void )\n  {\n    __asm__ __volatile__ ( \"\" : : : \"memory\" );\n  }\n\n  #define LFDS711_PAL_BARRIER_COMPILER_LOAD    lfds711_pal_barrier_compiler()\n  #define LFDS711_PAL_BARRIER_COMPILER_STORE   lfds711_pal_barrier_compiler()\n  #define LFDS711_PAL_BARRIER_COMPILER_FULL    lfds711_pal_barrier_compiler()\n\n  #define LFDS711_PAL_BARRIER_PROCESSOR_LOAD   __sync_synchronize()\n  #define LFDS711_PAL_BARRIER_PROCESSOR_STORE  __sync_synchronize()\n  #define LFDS711_PAL_BARRIER_PROCESSOR_FULL   __sync_synchronize()\n\n  #define LFDS711_PAL_ATOMIC_ADD( pointer_to_target, value, result, result_type )                                               \\\n  {                                                                                                                             \\\n    LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                          \\\n    (result) = (result_type) __sync_add_and_fetch( (lfds711_pal_uint_t *) (pointer_to_target), (lfds711_pal_uint_t) (value) );  \\\n    LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                          \\\n  }\n\n  #define LFDS711_PAL_ATOMIC_CAS( pointer_to_destination, pointer_to_compare, new_destination, cas_strength, result )       \\\n  {                                                                                                                         \\\n    lfds711_pal_uint_t                                                                                                      \\\n      original_compare;                                                                                                     \\\n                                                                                                                            \\\n    original_compare = (lfds711_pal_uint_t) *(pointer_to_compare);                                                          \\\n                                                                                                                            \\\n    LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                      \\\n    *(pointer_to_compare) = __sync_val_compare_and_swap( pointer_to_destination, *(pointer_to_compare), new_destination );  \\\n    LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                      \\\n                                                                                                                            \\\n    result = (unsigned char) ( original_compare == (lfds711_pal_uint_t) *(pointer_to_compare) );                            \\\n  }\n\n  #if( defined __x86_64__ )\n    /* TRD : On 64 bit platforms, unsigned long long int is 64 bit, so we must manually use cmpxchg16b, \n             as the atomic intrinsics will only emit cmpxchg8b\n    */\n\n    // TRD : lfds711_pal_uint_t volatile (*destination)[2], lfds711_pal_uint_t (*compare)[2], lfds711_pal_uint_t (*new_destination)[2], enum lfds711_misc_cas_strength cas_strength, char unsigned result\n\n    #define LFDS711_PAL_ATOMIC_DWCAS( pointer_to_destination, pointer_to_compare, pointer_to_new_destination, cas_strength, result )                             \\\n    {                                                                                                                                                            \\\n      (result) = 0;                                                                                                                                              \\\n                                                                                                                                                                 \\\n      __asm__ __volatile__                                                                                                                                       \\\n      (                                                                                                                                                          \\\n        \"lock;\"           /* make cmpxchg16b atomic        */                                                                                                    \\\n        \"cmpxchg16b %0;\"  /* cmpxchg16b sets ZF on success */                                                                                                    \\\n        \"setz       %4;\"  /* if ZF set, set result to 1    */                                                                                                    \\\n                                                                                                                                                                 \\\n        /* output */                                                                                                                                             \\\n        : \"+m\" ((pointer_to_destination)[0]), \"+m\" ((pointer_to_destination)[1]), \"+a\" ((pointer_to_compare)[0]), \"+d\" ((pointer_to_compare)[1]), \"=q\" (result)  \\\n                                                                                                                                                                 \\\n        /* input */                                                                                                                                              \\\n        : \"b\" ((pointer_to_new_destination)[0]), \"c\" ((pointer_to_new_destination)[1])                                                                           \\\n                                                                                                                                                                 \\\n        /* clobbered */                                                                                                                                          \\\n        :                                                                                                                                                        \\\n      );                                                                                                                                                         \\\n    }\n  #endif\n\n  // TRD : ARM and x86 have DWCAS which we can get via GCC intrinsics\n  #if( defined __arm__ || defined __i686__ || defined __i586__ || defined __i486__ )\n    #define LFDS711_PAL_ATOMIC_DWCAS( pointer_to_destination, pointer_to_compare, pointer_to_new_destination, cas_strength, result )                                                                                                   \\\n    {                                                                                                                                                                                                                                  \\\n      int long long unsigned                                                                                                                                                                                                           \\\n        original_destination;                                                                                                                                                                                                          \\\n                                                                                                                                                                                                                                       \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                                                                                                                               \\\n      original_destination = __sync_val_compare_and_swap( (int long long unsigned volatile *) (pointer_to_destination), *(int long long unsigned *) (pointer_to_compare), *(int long long unsigned *) (pointer_to_new_destination) );  \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                                                                                                                               \\\n                                                                                                                                                                                                                                       \\\n      (result) = (char unsigned) ( original_destination == *(int long long unsigned *) (pointer_to_compare) );                                                                                                                         \\\n                                                                                                                                                                                                                                       \\\n      *(int long long unsigned *) (pointer_to_compare) = original_destination;                                                                                                                                                         \\\n    }\n  #endif\n\n  #define LFDS711_PAL_ATOMIC_EXCHANGE( pointer_to_destination, exchange, exchange_type )          \\\n  {                                                                                               \\\n    /* LFDS711_PAL_ASSERT( (pointer_to_destination) != NULL ); */                                 \\\n    /* TRD : exchange can be any value in its range */                                            \\\n    /* TRD : exchange_type can be any value in its range */                                       \\\n                                                                                                  \\\n    LFDS711_PAL_BARRIER_COMPILER_FULL;                                                            \\\n    (exchange) = (exchange_type) __sync_lock_test_and_set( pointer_to_destination, (exchange) );  \\\n    LFDS711_PAL_BARRIER_COMPILER_FULL;                                                            \\\n  }\n\n  #define LFDS711_PAL_ATOMIC_SET( pointer_to_destination, new_value )        \\\n  {                                                                          \\\n    LFDS711_PAL_BARRIER_COMPILER_FULL;                                       \\\n    (void) __sync_lock_test_and_set( pointer_to_destination, (new_value) );  \\\n    LFDS711_PAL_BARRIER_COMPILER_FULL;                                       \\\n  }\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined __GNUC__ && LFDS711_PAL_GCC_VERSION >= 473 )\n\n  #ifdef LFDS711_PAL_COMPILER\n    #error More than one porting abstraction layer matches the current platform in lfds711_porting_abstraction_layer_compiler.h\n  #endif\n\n  #define LFDS711_PAL_COMPILER\n\n  #define LFDS711_PAL_COMPILER_STRING          \"GCC >= 4.7.3\"\n\n  #define LFDS711_PAL_ALIGN(alignment)         __attribute__( (aligned(alignment)) )\n  #define LFDS711_PAL_INLINE                   inline\n\n  // TRD : GCC >= 4.7.3 compiler barriers are built into the intrinsics\n  #define LFDS711_PAL_COMPILER_BARRIERS_MISSING_PRESUMED_HAVING_A_GOOD_TIME\n\n  #define LFDS711_PAL_BARRIER_PROCESSOR_LOAD   __atomic_thread_fence( __ATOMIC_ACQUIRE )\n  #define LFDS711_PAL_BARRIER_PROCESSOR_STORE  __atomic_thread_fence( __ATOMIC_RELEASE )\n  #define LFDS711_PAL_BARRIER_PROCESSOR_FULL   __atomic_thread_fence( __ATOMIC_ACQ_REL )\n\n  #define LFDS711_PAL_ATOMIC_ADD( pointer_to_target, value, result, result_type )                   \\\n  {                                                                                                 \\\n    (result) = (result_type) __atomic_add_fetch( (pointer_to_target), (value), __ATOMIC_RELAXED );  \\\n  }\n\n  #define LFDS711_PAL_ATOMIC_CAS( pointer_to_destination, pointer_to_compare, new_destination, cas_strength, result )                                                       \\\n  {                                                                                                                                                                         \\\n    result = (char unsigned) __atomic_compare_exchange_n( pointer_to_destination, pointer_to_compare, new_destination, cas_strength, __ATOMIC_RELAXED, __ATOMIC_RELAXED );  \\\n  }\n\n  // TRD : ARM and x86 have DWCAS which we can get via GCC intrinsics\n  #if( defined __arm__ || defined __i686__ || defined __i586__ || defined __i486__ )\n    #define LFDS711_PAL_ATOMIC_DWCAS( pointer_to_destination, pointer_to_compare, pointer_to_new_destination, cas_strength, result )                                                                                                                                                          \\\n    {                                                                                                                                                                                                                                                                                         \\\n      (result) = (char unsigned) __atomic_compare_exchange_n( (int long long unsigned volatile *) (pointer_to_destination), (int long long unsigned *) (pointer_to_compare), *(int long long unsigned *) (pointer_to_new_destination), (cas_strength), __ATOMIC_RELAXED, __ATOMIC_RELAXED );  \\\n    }\n  #endif\n\n  #if( defined __x86_64__ )\n    /* TRD : On 64 bit platforms, unsigned long long int is 64 bit, so we must manually use cmpxchg16b, \n             as __sync_val_compare_and_swap() will only emit cmpxchg8b\n    */\n\n    // TRD : lfds711_pal_uint_t volatile (*destination)[2], lfds711_pal_uint_t (*compare)[2], lfds711_pal_uint_t (*new_destination)[2], enum lfds711_misc_cas_strength cas_strength, char unsigned result\n\n    #define LFDS711_PAL_ATOMIC_DWCAS( pointer_to_destination, pointer_to_compare, pointer_to_new_destination, cas_strength, result )                             \\\n    {                                                                                                                                                            \\\n      (result) = 0;                                                                                                                                              \\\n                                                                                                                                                                 \\\n      __asm__ __volatile__                                                                                                                                       \\\n      (                                                                                                                                                          \\\n        \"lock;\"           /* make cmpxchg16b atomic        */                                                                                                    \\\n        \"cmpxchg16b %0;\"  /* cmpxchg16b sets ZF on success */                                                                                                    \\\n        \"setz       %4;\"  /* if ZF set, set result to 1    */                                                                                                    \\\n                                                                                                                                                                 \\\n        /* output */                                                                                                                                             \\\n        : \"+m\" ((pointer_to_destination)[0]), \"+m\" ((pointer_to_destination)[1]), \"+a\" ((pointer_to_compare)[0]), \"+d\" ((pointer_to_compare)[1]), \"=q\" (result)  \\\n                                                                                                                                                                 \\\n        /* input */                                                                                                                                              \\\n        : \"b\" ((pointer_to_new_destination)[0]), \"c\" ((pointer_to_new_destination)[1])                                                                           \\\n                                                                                                                                                                 \\\n        /* clobbered */                                                                                                                                          \\\n        :                                                                                                                                                        \\\n      );                                                                                                                                                         \\\n    }\n  #endif\n\n  #define LFDS711_PAL_ATOMIC_EXCHANGE( pointer_to_destination, exchange, exchange_type )                         \\\n  {                                                                                                              \\\n    (exchange) = (exchange_type) __atomic_exchange_n( (pointer_to_destination), (exchange), __ATOMIC_RELAXED );  \\\n  }\n\n  #define LFDS711_PAL_ATOMIC_SET( pointer_to_destination, new_value )                       \\\n  {                                                                                         \\\n    (void) __atomic_exchange_n( (pointer_to_destination), (new_value), __ATOMIC_RELAXED );  \\\n  }\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( !defined LFDS711_PAL_COMPILER )\n\n  #error No matching porting abstraction layer in lfds711_porting_abstraction_layer_compiler.h\n\n#endif\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/inc/liblfds711/lfds711_porting_abstraction_layer_operating_system.h",
    "content": "/****************************************************************************/\n#if( defined _WIN32 && !defined KERNEL_MODE )\n\n  #ifdef LFDS711_PAL_OPERATING_SYSTEM\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_operating_system.h\".\n  #endif\n\n  #define LFDS711_PAL_OPERATING_SYSTEM\n\n  #include <assert.h>\n\n  #define LFDS711_PAL_OS_STRING             \"Windows\"\n  #define LFDS711_PAL_ASSERT( expression )  if( !(expression) ) LFDS711_MISC_DELIBERATELY_CRASH;\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined _WIN32 && defined KERNEL_MODE )\n\n  #ifdef LFDS711_PAL_OPERATING_SYSTEM\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_operating_system.h\".\n  #endif\n\n  #define LFDS711_PAL_OPERATING_SYSTEM\n\n  #include <assert.h>\n  #include <wdm.h>\n\n  #define LFDS711_PAL_OS_STRING             \"Windows\"\n  #define LFDS711_PAL_ASSERT( expression )  if( !(expression) ) LFDS711_MISC_DELIBERATELY_CRASH;\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined __linux__ && !defined KERNEL_MODE )\n\n  #ifdef LFDS711_PAL_OPERATING_SYSTEM\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_operating_system.h\".\n  #endif\n\n  #define LFDS711_PAL_OPERATING_SYSTEM\n\n  #define LFDS711_PAL_OS_STRING             \"Linux\"\n  #define LFDS711_PAL_ASSERT( expression )  if( !(expression) ) LFDS711_MISC_DELIBERATELY_CRASH;\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined __linux__ && defined KERNEL_MODE )\n\n  #ifdef LFDS711_PAL_OPERATING_SYSTEM\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_operating_system.h\".\n  #endif\n\n  #define LFDS711_PAL_OPERATING_SYSTEM\n\n  #include <linux/module.h>\n\n  #define LFDS711_PAL_OS_STRING             \"Linux\"\n  #define LFDS711_PAL_ASSERT( expression )  BUG_ON( expression )\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( !defined LFDS711_PAL_OPERATING_SYSTEM )\n\n  #error No matching porting abstraction layer in lfds711_porting_abstraction_layer_operating_system.h\n\n#endif\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/inc/liblfds711/lfds711_porting_abstraction_layer_processor.h",
    "content": "/****************************************************************************/\n#if( defined _MSC_VER && defined _M_IX86 )\n\n  #ifdef LFDS711_PAL_PROCESSOR\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_processor.h\".\n  #endif\n\n  #define LFDS711_PAL_PROCESSOR\n\n  typedef int long          lfds711_pal_int_t;\n  typedef int long unsigned lfds711_pal_uint_t;\n\n  #define LFDS711_PAL_PROCESSOR_STRING            \"x86\"\n\n  #define LFDS711_PAL_ALIGN_SINGLE_POINTER        4\n  #define LFDS711_PAL_ALIGN_DOUBLE_POINTER        8\n\n  #define LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES   32\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined _MSC_VER && (defined _M_X64 || defined _M_AMD64) )\n\n  #ifdef LFDS711_PAL_PROCESSOR\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_processor.h\".\n  #endif\n\n  #define LFDS711_PAL_PROCESSOR\n\n  typedef int long long          lfds711_pal_int_t;\n  typedef int long long unsigned lfds711_pal_uint_t;\n\n  #define LFDS711_PAL_PROCESSOR_STRING            \"x64\"\n\n  #define LFDS711_PAL_ALIGN_SINGLE_POINTER        8\n  #define LFDS711_PAL_ALIGN_DOUBLE_POINTER        16\n\n  // TRD : Intel bring over two cache lines at once, always, unless disabled in BIOS\n  #define LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES   128\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined _MSC_VER && defined _M_IA64 )\n\n  #ifdef LFDS711_PAL_PROCESSOR\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_processor.h\".\n  #endif\n\n  #define LFDS711_PAL_PROCESSOR\n\n  typedef int long long          lfds711_pal_int_t;\n  typedef int long long unsigned lfds711_pal_uint_t;\n\n  #define LFDS711_PAL_PROCESSOR_STRING            \"IA64\"\n\n  #define LFDS711_PAL_ALIGN_SINGLE_POINTER        8\n  #define LFDS711_PAL_ALIGN_DOUBLE_POINTER        16\n\n  #define LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES   64\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined _MSC_VER && defined _M_ARM )\n\n  #ifdef LFDS711_PAL_PROCESSOR\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_processor.h\".\n  #endif\n\n  #define LFDS711_PAL_PROCESSOR\n\n  typedef int long          lfds711_pal_int_t;\n  typedef int long unsigned lfds711_pal_uint_t;\n\n  #define LFDS711_PAL_PROCESSOR_STRING            \"ARM (32-bit)\"\n\n  #define LFDS711_PAL_ALIGN_SINGLE_POINTER        4\n  #define LFDS711_PAL_ALIGN_DOUBLE_POINTER        8\n\n  /* TRD : ARM is LL/SC and uses a reservation granule of 8 to 2048 bytes\n           so the isolation value used here is worst-case - be sure to set\n           this correctly, otherwise structures are painfully large\n\n           the test application has an argument, \"-e\", which attempts to\n           determine the ERG length\n  */\n\n  #define LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES   2048\n\n#endif\n  \n  \n  \n  \n  \n/****************************************************************************/\n#if( defined __GNUC__ && defined __arm__ )\n\n  #ifdef LFDS711_PAL_PROCESSOR\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_processor.h\".\n  #endif\n\n  #define LFDS711_PAL_PROCESSOR\n\n  typedef int long          lfds711_pal_int_t;\n  typedef int long unsigned lfds711_pal_uint_t;\n\n  #define LFDS711_PAL_PROCESSOR_STRING            \"ARM (32-bit)\"\n\n  #define LFDS711_PAL_ALIGN_SINGLE_POINTER        4\n  #define LFDS711_PAL_ALIGN_DOUBLE_POINTER        8\n\n  /* TRD : ARM is LL/SC and uses a reservation granule of 8 to 2048 bytes\n           so the isolation value used here is worst-case - be sure to set\n           this correctly, otherwise structures are painfully large\n\n           the test application has an argument, \"-e\", which attempts to\n           determine the ERG length\n  */\n\n  #define LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES   2048\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined __GNUC__ && defined __aarch64__ )\n\n  #ifdef LFDS711_PAL_PROCESSOR\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_processor.h\".\n  #endif\n\n  #define LFDS711_PAL_PROCESSOR\n\n  typedef int long long          lfds711_pal_int_t;\n  typedef int long long unsigned lfds711_pal_uint_t;\n\n  #define LFDS711_PAL_PROCESSOR_STRING            \"ARM (64-bit)\"\n\n  #define LFDS711_PAL_ALIGN_SINGLE_POINTER        8\n  #define LFDS711_PAL_ALIGN_DOUBLE_POINTER        16\n\n  /* TRD : ARM is LL/SC and uses a reservation granule of 8 to 2048 bytes\n           so the isolation value used here is worst-case - be sure to set\n           this correctly, otherwise structures are painfully large\n\n           the test application has an argument, \"-e\", which attempts to\n           determine the ERG length\n  */\n\n  #define LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES   2048\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined __GNUC__ && (defined __i686__ || defined __i586__ || defined __i486__) )\n\n  #ifdef LFDS711_PAL_PROCESSOR\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_processor.h\".\n  #endif\n\n  #define LFDS711_PAL_PROCESSOR\n\n  typedef int long          lfds711_pal_int_t;\n  typedef int long unsigned lfds711_pal_uint_t;\n\n  #define LFDS711_PAL_PROCESSOR_STRING            \"x86\"\n\n  #define LFDS711_PAL_ALIGN_SINGLE_POINTER        4\n  #define LFDS711_PAL_ALIGN_DOUBLE_POINTER        8\n\n  #define LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES   32\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined __GNUC__ && defined __x86_64__ )\n\n  #ifdef LFDS711_PAL_PROCESSOR\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_processor.h\".\n  #endif\n\n  #define LFDS711_PAL_PROCESSOR\n\n  typedef int long long          lfds711_pal_int_t;\n  typedef int long long unsigned lfds711_pal_uint_t;\n\n  #define LFDS711_PAL_PROCESSOR_STRING            \"x64\"\n\n  #define LFDS711_PAL_ALIGN_SINGLE_POINTER        8\n  #define LFDS711_PAL_ALIGN_DOUBLE_POINTER        16\n\n  #define LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES   128\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined __GNUC__ && defined __alpha__ )\n\n  #ifdef LFDS711_PAL_PROCESSOR\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_processor.h\".\n  #endif\n\n  #define LFDS711_PAL_PROCESSOR\n\n  typedef int long          lfds711_pal_int_t;\n  typedef int long unsigned lfds711_pal_uint_t;\n\n  #define LFDS711_PAL_PROCESSOR_STRING            \"alpha\"\n\n  #define LFDS711_PAL_ALIGN_SINGLE_POINTER        8\n  #define LFDS711_PAL_ALIGN_DOUBLE_POINTER        16\n\n  #define LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES   64\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined __GNUC__ && defined __ia64__ )\n\n  #ifdef LFDS711_PAL_PROCESSOR\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_processor.h\".\n  #endif\n\n  #define LFDS711_PAL_PROCESSOR\n\n  typedef int long long          lfds711_pal_int_t;\n  typedef int long long unsigned lfds711_pal_uint_t;\n\n  #define LFDS711_PAL_PROCESSOR_STRING            \"IA64\"\n\n  #define LFDS711_PAL_ALIGN_SINGLE_POINTER        8\n  #define LFDS711_PAL_ALIGN_DOUBLE_POINTER        16\n\n  #define LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES   64\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined __GNUC__ && defined __mips__ && !defined __mips64 )\n\n  #ifdef LFDS711_PAL_PROCESSOR\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_processor.h\".\n  #endif\n\n  #define LFDS711_PAL_PROCESSOR\n\n  typedef int long          lfds711_pal_int_t;\n  typedef int long unsigned lfds711_pal_uint_t;\n\n  #define LFDS711_PAL_PROCESSOR_STRING            \"MIPS (32-bit)\"\n\n  #define LFDS711_PAL_ALIGN_SINGLE_POINTER        4\n  #define LFDS711_PAL_ALIGN_DOUBLE_POINTER        8\n\n  #define LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES   32\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined __GNUC__ && defined __mips__ && defined __mips64 )\n\n  #ifdef LFDS711_PAL_PROCESSOR\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_processor.h\".\n  #endif\n\n  #define LFDS711_PAL_PROCESSOR\n\n  typedef int long long          lfds711_pal_int_t;\n  typedef int long long unsigned lfds711_pal_uint_t;\n\n  #define LFDS711_PAL_PROCESSOR_STRING            \"MIPS (64-bit)\"\n\n  #define LFDS711_PAL_ALIGN_SINGLE_POINTER        8\n  #define LFDS711_PAL_ALIGN_DOUBLE_POINTER        16\n\n  #define LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES   64\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined __GNUC__ && defined __ppc__ )\n\n  #ifdef LFDS711_PAL_PROCESSOR\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_processor.h\".\n  #endif\n\n  #define LFDS711_PAL_PROCESSOR\n\n  typedef int long          lfds711_pal_int_t;\n  typedef int long unsigned lfds711_pal_uint_t;\n\n  #define LFDS711_PAL_PROCESSOR_STRING            \"POWERPC (32-bit)\"\n\n  #define LFDS711_PAL_ALIGN_SINGLE_POINTER        4\n  #define LFDS711_PAL_ALIGN_DOUBLE_POINTER        8\n\n  // TRD : this value is not very certain\n  #define LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES   128\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined __GNUC__ && defined __ppc64__ )\n\n  #ifdef LFDS711_PAL_PROCESSOR\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_processor.h\".\n  #endif\n\n  #define LFDS711_PAL_PROCESSOR\n\n  typedef int long long          lfds711_pal_int_t;\n  typedef int long long unsigned lfds711_pal_uint_t;\n\n  #define LFDS711_PAL_PROCESSOR_STRING            \"POWERPC (64-bit)\"\n\n  #define LFDS711_PAL_ALIGN_SINGLE_POINTER        8\n  #define LFDS711_PAL_ALIGN_DOUBLE_POINTER        16\n\n  // TRD : this value is not very certain\n  #define LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES   128\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined __GNUC__ && defined __sparc__ && !defined __sparc_v9__ )\n\n  #ifdef LFDS711_PAL_PROCESSOR\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_processor.h\".\n  #endif\n\n  #define LFDS711_PAL_PROCESSOR\n\n  typedef int long          lfds711_pal_int_t;\n  typedef int long unsigned lfds711_pal_uint_t;\n\n  #define LFDS711_PAL_PROCESSOR_STRING            \"SPARC (32-bit)\"\n\n  #define LFDS711_PAL_ALIGN_SINGLE_POINTER        4\n  #define LFDS711_PAL_ALIGN_DOUBLE_POINTER        8\n\n  #define LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES   32\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined __GNUC__ && defined __sparc__ && defined __sparc_v9__ )\n\n  #ifdef LFDS711_PAL_PROCESSOR\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_processor.h\".\n  #endif\n\n  #define LFDS711_PAL_PROCESSOR\n\n  typedef int long long          lfds711_pal_int_t;\n  typedef int long long unsigned lfds711_pal_uint_t;\n\n  #define LFDS711_PAL_PROCESSOR_STRING            \"SPARC (64-bit)\"\n\n  #define LFDS711_PAL_ALIGN_SINGLE_POINTER        8\n  #define LFDS711_PAL_ALIGN_DOUBLE_POINTER        16\n\n  #define LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES   64\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined __GNUC__ && defined __m68k__ )\n\n  #ifdef LFDS711_PAL_PROCESSOR\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_processor.h\".\n  #endif\n\n  #define LFDS711_PAL_PROCESSOR\n\n  typedef int long          lfds711_pal_int_t;\n  typedef int long unsigned lfds711_pal_uint_t;\n\n  #define LFDS711_PAL_PROCESSOR_STRING            \"680x0\"\n\n  #define LFDS711_PAL_ALIGN_SINGLE_POINTER        4\n  #define LFDS711_PAL_ALIGN_DOUBLE_POINTER        8\n\n  #define LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES   32\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( !defined LFDS711_PAL_PROCESSOR )\n\n  #error No matching porting abstraction layer in \"lfds711_porting_abstraction_layer_processor.h\".\n\n#endif\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/inc/liblfds711/lfds711_prng.h",
    "content": "/***** defines *****/\n#define LFDS711_PRNG_MAX  ( (lfds711_pal_uint_t) -1 )\n\n/* TRD : the seed is from an on-line hardware RNG, using atmospheric noise\n         the URL below will generate another 16 random hex digits (e.g. a 64-bit number) and is\n         the RNG used to generate the number above (0x0a34655d34c092fe)\n\n         http://www.random.org/integers/?num=16&min=0&max=15&col=1&base=16&format=plain&rnd=new\n\n         the 32 bit seed is the upper half of the 64 bit seed\n\n         the \"SplitMix\" PRNG is from from Sebastiano vigna's site, CC0 license, http://xorshift.di.unimi.it/splitmix64.c\n         the 64-bit constants come directly from the source, the 32-bt constants are in fact the 32-bit murmurhash3 constants\n*/\n\n#if( LFDS711_PAL_ALIGN_SINGLE_POINTER == 4 )\n  #define LFDS711_PRNG_SEED                            0x0a34655dUL\n  #define LFDS711_PRNG_SPLITMIX_MAGIC_RATIO            0x9E3779B9UL\n  #define LFDS711_PRNG_SPLITMIX_SHIFT_CONSTANT_ONE     16\n  #define LFDS711_PRNG_SPLITMIX_SHIFT_CONSTANT_TWO     13\n  #define LFDS711_PRNG_SPLITMIX_SHIFT_CONSTANT_THREE   16\n  #define LFDS711_PRNG_SPLITMIX_MULTIPLY_CONSTANT_ONE  0x85ebca6bUL\n  #define LFDS711_PRNG_SPLITMIX_MULTIPLY_CONSTANT_TWO  0xc2b2ae35UL\n#endif\n\n#if( LFDS711_PAL_ALIGN_SINGLE_POINTER == 8 )\n  #define LFDS711_PRNG_SEED                            0x0a34655d34c092feULL\n  #define LFDS711_PRNG_SPLITMIX_MAGIC_RATIO            0x9E3779B97F4A7C15ULL\n  #define LFDS711_PRNG_SPLITMIX_SHIFT_CONSTANT_ONE     30\n  #define LFDS711_PRNG_SPLITMIX_SHIFT_CONSTANT_TWO     27\n  #define LFDS711_PRNG_SPLITMIX_SHIFT_CONSTANT_THREE   31\n  #define LFDS711_PRNG_SPLITMIX_MULTIPLY_CONSTANT_ONE  0xBF58476D1CE4E5B9ULL\n  #define LFDS711_PRNG_SPLITMIX_MULTIPLY_CONSTANT_TWO  0x94D049BB133111EBULL\n#endif\n\n// TRD : struct lfds711_prng_state prng_state, lfds711_pal_uint_t random_value\n#define LFDS711_PRNG_GENERATE( prng_state, random_value )                                                                  \\\n{                                                                                                                          \\\n  LFDS711_PAL_ATOMIC_ADD( &(prng_state).entropy, LFDS711_PRNG_SPLITMIX_MAGIC_RATIO, (random_value), lfds711_pal_uint_t );  \\\n  LFDS711_PRNG_ST_MIXING_FUNCTION( random_value );                                                                         \\\n}\n\n// TRD : struct lfds711_prng_state prng_st_state, lfds711_pal_uint_t random_value\n#define LFDS711_PRNG_ST_GENERATE( prng_st_state, random_value )                       \\\n{                                                                                     \\\n  (random_value) = ( (prng_st_state).entropy += LFDS711_PRNG_SPLITMIX_MAGIC_RATIO );  \\\n  LFDS711_PRNG_ST_MIXING_FUNCTION( random_value );                                    \\\n}\n\n// TRD : lfds711_pal_uint_t random_value\n#define LFDS711_PRNG_ST_MIXING_FUNCTION( random_value )                                                                                            \\\n{                                                                                                                                                  \\\n  (random_value) = ((random_value) ^ ((random_value) >> LFDS711_PRNG_SPLITMIX_SHIFT_CONSTANT_ONE)) * LFDS711_PRNG_SPLITMIX_MULTIPLY_CONSTANT_ONE;  \\\n  (random_value) = ((random_value) ^ ((random_value) >> LFDS711_PRNG_SPLITMIX_SHIFT_CONSTANT_TWO)) * LFDS711_PRNG_SPLITMIX_MULTIPLY_CONSTANT_TWO;  \\\n  (random_value) = (random_value ^ (random_value >> LFDS711_PRNG_SPLITMIX_SHIFT_CONSTANT_THREE));                                                  \\\n}\n\n/***** structs *****/\nstruct lfds711_prng_state\n{\n  lfds711_pal_uint_t volatile LFDS711_PAL_ALIGN(LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES)\n    entropy;\n};\n\nstruct lfds711_prng_st_state\n{\n  lfds711_pal_uint_t\n    entropy;\n};\n\n/***** public prototypes *****/\nvoid lfds711_prng_init_valid_on_current_logical_core( struct lfds711_prng_state *ps, lfds711_pal_uint_t seed );\nvoid lfds711_prng_st_init( struct lfds711_prng_st_state *psts, lfds711_pal_uint_t seed );\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/inc/liblfds711/lfds711_queue_bounded_manyproducer_manyconsumer.h",
    "content": "/***** defines *****/\n#define LFDS711_QUEUE_BMM_GET_USER_STATE_FROM_STATE( queue_bmm_state )  ( (queue_bmm_state).user_state )\n\n/***** enums *****/\nenum lfds711_queue_bmm_query\n{\n  LFDS711_QUEUE_BMM_QUERY_GET_POTENTIALLY_INACCURATE_COUNT,\n  LFDS711_QUEUE_BMM_QUERY_SINGLETHREADED_VALIDATE\n};\n\n/***** structures *****/\nstruct lfds711_queue_bmm_element\n{\n  lfds711_pal_uint_t volatile\n    sequence_number;\n\n  void\n    *volatile key,\n    *volatile value;\n};\n\nstruct lfds711_queue_bmm_state\n{\n  lfds711_pal_uint_t\n    number_elements,\n    mask;\n\n  lfds711_pal_uint_t volatile LFDS711_PAL_ALIGN(LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES)\n    read_index,\n    write_index;\n\n  struct lfds711_queue_bmm_element\n    *element_array;\n\n  void\n    *user_state;\n\n  struct lfds711_misc_backoff_state\n    dequeue_backoff,\n    enqueue_backoff;\n};\n\n/***** public prototypes *****/\nvoid lfds711_queue_bmm_init_valid_on_current_logical_core( struct lfds711_queue_bmm_state *qbmms,\n                                                           struct lfds711_queue_bmm_element *element_array,\n                                                           lfds711_pal_uint_t number_elements,\n                                                           void *user_state );\n\nvoid lfds711_queue_bmm_cleanup( struct lfds711_queue_bmm_state *qbmms,\n                                void (*element_cleanup_callback)(struct lfds711_queue_bmm_state *qbmms,\n                                                                 void *key,\n                                                                 void *value) );\n\nint lfds711_queue_bmm_enqueue( struct lfds711_queue_bmm_state *qbmms,\n                               void *key,\n                               void *value );\n\nint lfds711_queue_bmm_dequeue( struct lfds711_queue_bmm_state *qbmms,\n                                      void **key,\n                                      void **value );\n\nvoid lfds711_queue_bmm_query( struct lfds711_queue_bmm_state *qbmms,\n                              enum lfds711_queue_bmm_query query_type,\n                              void *query_input,\n                              void *query_output );\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/inc/liblfds711/lfds711_queue_bounded_singleproducer_singleconsumer.h",
    "content": "/***** defines *****/\n#define LFDS711_QUEUE_BSS_GET_USER_STATE_FROM_STATE( queue_bss_state )  ( (queue_bss_state).user_state )\n\n/***** enums *****/\nenum lfds711_queue_bss_query\n{\n  LFDS711_QUEUE_BSS_QUERY_GET_POTENTIALLY_INACCURATE_COUNT,\n  LFDS711_QUEUE_BSS_QUERY_VALIDATE\n};\n\n/***** structures *****/\nstruct lfds711_queue_bss_element\n{\n  void\n    *volatile key,\n    *volatile value;\n};\n\nstruct lfds711_queue_bss_state\n{\n  lfds711_pal_uint_t\n    number_elements,\n    mask;\n\n  lfds711_pal_uint_t volatile\n    read_index,\n    write_index;\n\n  struct lfds711_queue_bss_element\n    *element_array;\n\n  void\n    *user_state;\n};\n\n/***** public prototypes *****/\nvoid lfds711_queue_bss_init_valid_on_current_logical_core( struct lfds711_queue_bss_state *qbsss, \n                                                           struct lfds711_queue_bss_element *element_array,\n                                                           lfds711_pal_uint_t number_elements,\n                                                           void *user_state );\n  // TRD : number_elements must be a positive integer power of 2\n  // TRD : used in conjunction with the #define LFDS711_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE\n\nvoid lfds711_queue_bss_cleanup( struct lfds711_queue_bss_state *qbsss,\n                                void (*element_cleanup_callback)(struct lfds711_queue_bss_state *qbsss, void *key, void *value) );\n\nint lfds711_queue_bss_enqueue( struct lfds711_queue_bss_state *qbsss,\n                               void *key,\n                               void *value );\n\nint lfds711_queue_bss_dequeue( struct lfds711_queue_bss_state *qbsss,\n                               void **key,\n                               void **value );\n\nvoid lfds711_queue_bss_query( struct lfds711_queue_bss_state *qbsss,\n                              enum lfds711_queue_bss_query query_type,\n                              void *query_input,\n                              void *query_output );\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/inc/liblfds711/lfds711_queue_unbounded_manyproducer_manyconsumer.h",
    "content": "/***** defines *****/\n#define LFDS711_QUEUE_UMM_GET_KEY_FROM_ELEMENT( queue_umm_element )             ( (queue_umm_element).key )\n#define LFDS711_QUEUE_UMM_SET_KEY_IN_ELEMENT( queue_umm_element, new_key )      ( (queue_umm_element).key = (void *) (lfds711_pal_uint_t) (new_key) )\n#define LFDS711_QUEUE_UMM_GET_VALUE_FROM_ELEMENT( queue_umm_element )           ( (queue_umm_element).value )\n#define LFDS711_QUEUE_UMM_SET_VALUE_IN_ELEMENT( queue_umm_element, new_value )  ( (queue_umm_element).value = (void *) (lfds711_pal_uint_t) (new_value) )\n#define LFDS711_QUEUE_UMM_GET_USER_STATE_FROM_STATE( queue_umm_state )          ( (queue_umm_state).user_state )\n\n/***** enums *****/\nenum lfds711_queue_umm_query\n{\n  LFDS711_QUEUE_UMM_QUERY_SINGLETHREADED_GET_COUNT,\n  LFDS711_QUEUE_UMM_QUERY_SINGLETHREADED_VALIDATE\n};\n\n/***** structures *****/\nstruct lfds711_queue_umm_element\n{\n  struct lfds711_queue_umm_element LFDS711_PAL_ALIGN(LFDS711_PAL_ALIGN_DOUBLE_POINTER)\n    *volatile next[PAC_SIZE];\n\n  void\n    *key,\n    *value;\n};\n\nstruct lfds711_queue_umm_state\n{\n  struct lfds711_queue_umm_element LFDS711_PAL_ALIGN(LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES)\n    *volatile enqueue[PAC_SIZE],\n    *volatile dequeue[PAC_SIZE];\n\n  lfds711_pal_uint_t volatile LFDS711_PAL_ALIGN(LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES)\n    aba_counter;\n\n  void LFDS711_PAL_ALIGN(LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES)\n    *user_state;\n\n  struct lfds711_misc_backoff_state\n    dequeue_backoff,\n    enqueue_backoff;\n};\n\n/***** public prototypes *****/\nvoid lfds711_queue_umm_init_valid_on_current_logical_core( struct lfds711_queue_umm_state *qumms,\n                                                           struct lfds711_queue_umm_element *qumme_dummy,\n                                                           void *user_state );\n  // TRD : used in conjunction with the #define LFDS711_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE\n\nvoid lfds711_queue_umm_cleanup( struct lfds711_queue_umm_state *qumms,\n                                void (*element_cleanup_callback)(struct lfds711_queue_umm_state *qumms, struct lfds711_queue_umm_element *qumme, enum lfds711_misc_flag dummy_element_flag) );\n\nvoid lfds711_queue_umm_enqueue( struct lfds711_queue_umm_state *qumms,\n                                struct lfds711_queue_umm_element *qumme );\n\nint lfds711_queue_umm_dequeue( struct lfds711_queue_umm_state *qumms,\n                               struct lfds711_queue_umm_element **qumme );\n\nvoid lfds711_queue_umm_query( struct lfds711_queue_umm_state *qumms,\n                              enum lfds711_queue_umm_query query_type,\n                              void *query_input,\n                              void *query_output );\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/inc/liblfds711/lfds711_ringbuffer.h",
    "content": "/***** enums *****/\n#define LFDS711_RINGBUFFER_GET_USER_STATE_FROM_STATE( ringbuffer_state )  ( (ringbuffer_state).user_state )\n\n/***** enums *****/\nenum lfds711_ringbuffer_query\n{\n  LFDS711_RINGBUFFER_QUERY_SINGLETHREADED_GET_COUNT,\n  LFDS711_RINGBUFFER_QUERY_SINGLETHREADED_VALIDATE\n};\n\n/***** structures *****/\nstruct lfds711_ringbuffer_element\n{\n  struct lfds711_freelist_element\n    fe;\n\n  struct lfds711_queue_umm_element\n    qumme;\n\n  struct lfds711_queue_umm_element\n    *qumme_use; // TRD : hack; we need a new queue with no dummy element\n\n  void\n    *key,\n    *value;\n};\n\nstruct lfds711_ringbuffer_state\n{\n  struct lfds711_freelist_state\n    fs;\n\n  struct lfds711_queue_umm_state\n    qumms;\n\n  void\n    (*element_cleanup_callback)( struct lfds711_ringbuffer_state *rs, void *key, void *value, enum lfds711_misc_flag unread_flag ),\n    *user_state;\n};\n\n/***** public prototypes *****/\nvoid lfds711_ringbuffer_init_valid_on_current_logical_core( struct lfds711_ringbuffer_state *rs,\n                                                            struct lfds711_ringbuffer_element *re_array_inc_dummy,\n                                                            lfds711_pal_uint_t number_elements_inc_dummy,\n                                                            void *user_state );\n  // TRD : used in conjunction with the #define LFDS711_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE\n\nvoid lfds711_ringbuffer_cleanup( struct lfds711_ringbuffer_state *rs,\n                                 void (*element_cleanup_callback)(struct lfds711_ringbuffer_state *rs, void *key, void *value, enum lfds711_misc_flag unread_flag) );\n\nint lfds711_ringbuffer_read( struct lfds711_ringbuffer_state *rs,\n                             void **key,\n                             void **value );\n\nvoid lfds711_ringbuffer_write( struct lfds711_ringbuffer_state *rs,\n                               void *key,\n                               void *value,\n                               enum lfds711_misc_flag *overwrite_occurred_flag,\n                               void **overwritten_key,\n                               void **overwritten_value );\n\nvoid lfds711_ringbuffer_query( struct lfds711_ringbuffer_state *rs,\n                               enum lfds711_ringbuffer_query query_type,\n                               void *query_input,\n                               void *query_output );\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/inc/liblfds711/lfds711_stack.h",
    "content": "/***** defines *****/\n#define LFDS711_STACK_GET_KEY_FROM_ELEMENT( stack_element )             ( (stack_element).key )\n#define LFDS711_STACK_SET_KEY_IN_ELEMENT( stack_element, new_key )      ( (stack_element).key = (void *) (lfds711_pal_uint_t) (new_key) )\n#define LFDS711_STACK_GET_VALUE_FROM_ELEMENT( stack_element )           ( (stack_element).value )\n#define LFDS711_STACK_SET_VALUE_IN_ELEMENT( stack_element, new_value )  ( (stack_element).value = (void *) (lfds711_pal_uint_t) (new_value) )\n#define LFDS711_STACK_GET_USER_STATE_FROM_STATE( stack_state )          ( (stack_state).user_state )\n\n/***** enums *****/\nenum lfds711_stack_query\n{\n  LFDS711_STACK_QUERY_SINGLETHREADED_GET_COUNT,\n  LFDS711_STACK_QUERY_SINGLETHREADED_VALIDATE\n};\n\n/***** structures *****/\nstruct lfds711_stack_element\n{\n  struct lfds711_stack_element\n    *next;\n\n  void\n    *key,\n    *value;\n};\n\nstruct lfds711_stack_state\n{\n  struct lfds711_stack_element LFDS711_PAL_ALIGN(LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES)\n    *volatile top[PAC_SIZE];\n\n  void LFDS711_PAL_ALIGN(LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES)\n    *user_state;\n\n  struct lfds711_misc_backoff_state\n    pop_backoff,\n    push_backoff;\n};\n\n/***** public prototypes *****/\nvoid lfds711_stack_init_valid_on_current_logical_core( struct lfds711_stack_state *ss,\n                                                       void *user_state );\n  // TRD : used in conjunction with the #define LFDS711_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE\n\nvoid lfds711_stack_cleanup( struct lfds711_stack_state *ss,\n                            void (*element_cleanup_callback)(struct lfds711_stack_state *ss, struct lfds711_stack_element *se) );\n\nvoid lfds711_stack_push( struct lfds711_stack_state *ss,\n                         struct lfds711_stack_element *se );\n\nint lfds711_stack_pop( struct lfds711_stack_state *ss,\n                       struct lfds711_stack_element **se );\n\nvoid lfds711_stack_query( struct lfds711_stack_state *ss,\n                          enum lfds711_stack_query query_type,\n                          void *query_input,\n                          void *query_output );\n\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/inc/liblfds711.h",
    "content": "#ifndef LIBLFDS711_H\n\n  /***** defines *****/\n  #define LIBLFDS711_H\n\n  /***** pragmas on *****/\n  #pragma warning( push )\n  #pragma warning( disable : 4324 )                                          // TRD : 4324 disables MSVC warnings for structure alignment padding due to alignment specifiers\n  #pragma prefast( disable : 28113 28182 28183, \"blah\" )\n\n  /***** includes *****/\n  #include \"liblfds711/lfds711_porting_abstraction_layer_compiler.h\"\n  #include \"liblfds711/lfds711_porting_abstraction_layer_operating_system.h\"\n  #include \"liblfds711/lfds711_porting_abstraction_layer_processor.h\"\n\n  #include \"liblfds711/lfds711_prng.h\"                                       // TRD : misc requires prng\n  #include \"liblfds711/lfds711_misc.h\"                                       // TRD : everything after depends on misc\n  #include \"liblfds711/lfds711_btree_addonly_unbalanced.h\"                   // TRD : hash_addonly depends on btree_addonly_unbalanced\n  #include \"liblfds711/lfds711_freelist.h\"\n  #include \"liblfds711/lfds711_hash_addonly.h\"\n  #include \"liblfds711/lfds711_list_addonly_singlylinked_ordered.h\"\n  #include \"liblfds711/lfds711_list_addonly_singlylinked_unordered.h\"\n  #include \"liblfds711/lfds711_queue_bounded_manyproducer_manyconsumer.h\"\n  #include \"liblfds711/lfds711_queue_bounded_singleproducer_singleconsumer.h\"\n  #include \"liblfds711/lfds711_queue_unbounded_manyproducer_manyconsumer.h\"\n  #include \"liblfds711/lfds711_ringbuffer.h\"\n  #include \"liblfds711/lfds711_stack.h\"\n\n  /***** pragmas off *****/\n  #pragma warning( pop )\n\n#endif\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/obj/.gitkeep",
    "content": ""
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_btree_addonly_unbalanced/lfds711_btree_addonly_unbalanced_cleanup.c",
    "content": "/***** includes *****/\n#include \"lfds711_btree_addonly_unbalanced_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_btree_au_cleanup( struct lfds711_btree_au_state *baus,\n                               void (*element_cleanup_callback)(struct lfds711_btree_au_state *baus, struct lfds711_btree_au_element *baue) )\n{\n  enum lfds711_btree_au_delete_action\n    delete_action = LFDS711_BTREE_AU_DELETE_SELF; // TRD : to remove compiler warning\n\n  struct lfds711_btree_au_element\n    *baue;\n\n  struct lfds711_btree_au_element\n    *temp;\n\n  LFDS711_PAL_ASSERT( baus != NULL );\n  // TRD : element_delete_function can be NULL\n\n  /* TRD : we're not lock-free now, so delete at will\n           but be iterative, so can be used in kernels (where there's little stack)\n           and be performant, since the user may be\n           creating/destroying many of these trees\n           also remember the user may be deallocating user data\n           so we cannot visit an element twice\n\n           we start at the root and iterate till we go to NULL\n           if the element has zero children, we delete it and move up to its parent\n           if the element has one child, we delete it, move its child into its place, and continue from its child\n           if the element has two children, we move left\n\n           the purpose of this is to minimize walking around the tree\n           to prevent visiting an element twice\n           while also minimizing code complexity\n  */\n\n  if( element_cleanup_callback == NULL )\n    return;\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  lfds711_btree_au_get_by_absolute_position( baus, &baue, LFDS711_BTREE_AU_ABSOLUTE_POSITION_ROOT );\n\n  while( baue != NULL )\n  {\n    if( baue->left == NULL and baue->right == NULL )\n      delete_action = LFDS711_BTREE_AU_DELETE_SELF;\n\n    if( baue->left != NULL and baue->right == NULL )\n      delete_action = LFDS711_BTREE_AU_DELETE_SELF_REPLACE_WITH_LEFT_CHILD;\n\n    if( baue->left == NULL and baue->right != NULL )\n      delete_action = LFDS711_BTREE_AU_DELETE_SELF_REPLACE_WITH_RIGHT_CHILD;\n\n    if( baue->left != NULL and baue->right != NULL )\n      delete_action = LFDS711_BTREE_AU_DELETE_MOVE_LEFT;\n\n    switch( delete_action )\n    {\n      case LFDS711_BTREE_AU_DELETE_SELF:\n        // TRD : if we have a parent (we could be root) set his point to us to NULL\n        if( baue->up != NULL )\n        {\n          if( baue->up->left == baue )\n            baue->up->left = NULL;\n          if( baue->up->right == baue )\n            baue->up->right = NULL;\n        }\n\n        temp = baue;\n        lfds711_btree_au_get_by_relative_position( &baue, LFDS711_BTREE_AU_RELATIVE_POSITION_UP );\n        element_cleanup_callback( baus, temp );\n      break;\n\n      case LFDS711_BTREE_AU_DELETE_SELF_REPLACE_WITH_LEFT_CHILD:\n        baue->left->up = baue->up;\n        if( baue->up != NULL )\n        {\n          if( baue->up->left == baue )\n            baue->up->left = baue->left;\n          if( baue->up->right == baue )\n            baue->up->right = baue->left;\n        }\n\n        temp = baue;\n        lfds711_btree_au_get_by_relative_position( &baue, LFDS711_BTREE_AU_RELATIVE_POSITION_LEFT );\n        element_cleanup_callback( baus, temp );\n      break;\n\n      case LFDS711_BTREE_AU_DELETE_SELF_REPLACE_WITH_RIGHT_CHILD:\n        baue->right->up = baue->up;\n        if( baue->up != NULL )\n        {\n          if( baue->up->left == baue )\n            baue->up->left = baue->right;\n          if( baue->up->right == baue )\n            baue->up->right = baue->right;\n        }\n\n        temp = baue;\n        lfds711_btree_au_get_by_relative_position( &baue, LFDS711_BTREE_AU_RELATIVE_POSITION_RIGHT );\n        element_cleanup_callback( baus, temp );\n      break;\n\n      case LFDS711_BTREE_AU_DELETE_MOVE_LEFT:\n        lfds711_btree_au_get_by_relative_position( &baue, LFDS711_BTREE_AU_RELATIVE_POSITION_LEFT );\n      break;\n    }\n  }\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_btree_addonly_unbalanced/lfds711_btree_addonly_unbalanced_get.c",
    "content": "/***** includes *****/\n#include \"lfds711_btree_addonly_unbalanced_internal.h\"\n\n/***** private prototypes *****/\nstatic void lfds711_btree_au_internal_inorder_walk_from_largest_get_next_smallest_element( struct lfds711_btree_au_element **baue );\nstatic void lfds711_btree_au_internal_inorder_walk_from_smallest_get_next_largest_element( struct lfds711_btree_au_element **baue );\n\n\n\n\n\n/****************************************************************************/\nint lfds711_btree_au_get_by_key( struct lfds711_btree_au_state *baus,\n                                 int (*key_compare_function)(void const *new_key, void const *existing_key),\n                                 void *key,\n                                 struct lfds711_btree_au_element **baue )\n{\n  int\n    compare_result = !0,\n    rv = 1;\n\n  LFDS711_PAL_ASSERT( baus != NULL );\n  // TRD : key_compare_function can be NULL\n  // TRD : key can be NULL\n  LFDS711_PAL_ASSERT( baue != NULL );\n\n  if( key_compare_function == NULL )\n    key_compare_function = baus->key_compare_function;\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  *baue = baus->root;\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  while( *baue != NULL and compare_result != 0 )\n  {\n    compare_result = key_compare_function( key, (*baue)->key );\n\n    if( compare_result < 0 )\n    {\n      *baue = (*baue)->left;\n      LFDS711_MISC_BARRIER_LOAD;\n    }\n\n    if( compare_result > 0 )\n    {\n      *baue = (*baue)->right;\n      LFDS711_MISC_BARRIER_LOAD;\n    }\n  }\n\n  if( *baue == NULL )\n    rv = 0;\n\n  return rv;\n}\n\n\n\n\n\n/****************************************************************************/\nint lfds711_btree_au_get_by_absolute_position( struct lfds711_btree_au_state *baus,\n                                               struct lfds711_btree_au_element **baue,\n                                               enum lfds711_btree_au_absolute_position absolute_position )\n{\n  int\n    rv = 1;\n\n  LFDS711_PAL_ASSERT( baus != NULL );\n  LFDS711_PAL_ASSERT( baue != NULL );\n  // TRD : absolute_position can be any value in its range\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  *baue = baus->root;\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  switch( absolute_position )\n  {\n    case LFDS711_BTREE_AU_ABSOLUTE_POSITION_ROOT:\n    break;\n\n    case LFDS711_BTREE_AU_ABSOLUTE_POSITION_LARGEST_IN_TREE:\n      if( *baue != NULL )\n        while( (*baue)->right != NULL )\n        {\n          *baue = (*baue)->right;\n          LFDS711_MISC_BARRIER_LOAD;\n        }\n    break;\n\n    case LFDS711_BTREE_AU_ABSOLUTE_POSITION_SMALLEST_IN_TREE:\n      if( *baue != NULL )\n        while( (*baue)->left != NULL )\n        {\n          *baue = (*baue)->left;\n          LFDS711_MISC_BARRIER_LOAD;\n        }\n    break;\n  }\n\n  if( *baue == NULL )\n    rv = 0;\n\n  return rv;\n}\n\n\n\n\n\n/****************************************************************************/\nint lfds711_btree_au_get_by_relative_position( struct lfds711_btree_au_element **baue,\n                                               enum lfds711_btree_au_relative_position relative_position )\n{\n  int\n    rv = 1;\n\n  LFDS711_PAL_ASSERT( baue != NULL );\n  // TRD : relative_position can baue any value in its range\n\n  if( *baue == NULL )\n    return 0;\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  switch( relative_position )\n  {\n    case LFDS711_BTREE_AU_RELATIVE_POSITION_UP:\n      *baue = (*baue)->up;\n      // TRD : no load barrier - up already existed, so is known to be safely propagated\n    break;\n\n    case LFDS711_BTREE_AU_RELATIVE_POSITION_LEFT:\n      *baue = (*baue)->left;\n      LFDS711_MISC_BARRIER_LOAD;\n    break;\n\n    case LFDS711_BTREE_AU_RELATIVE_POSITION_RIGHT:\n      *baue = (*baue)->right;\n      LFDS711_MISC_BARRIER_LOAD;\n    break;\n\n    case LFDS711_BTREE_AU_RELATIVE_POSITION_SMALLEST_ELEMENT_BELOW_CURRENT_ELEMENT:\n      *baue = (*baue)->left;\n      if( *baue != NULL )\n      {\n        LFDS711_MISC_BARRIER_LOAD;\n        while( (*baue)->right != NULL )\n        {\n          *baue = (*baue)->right;\n          LFDS711_MISC_BARRIER_LOAD;\n        }\n      }\n    break;\n\n    case LFDS711_BTREE_AU_RELATIVE_POSITION_LARGEST_ELEMENT_BELOW_CURRENT_ELEMENT:\n      *baue = (*baue)->right;\n      if( *baue != NULL )\n      {\n        LFDS711_MISC_BARRIER_LOAD;\n        while( (*baue)->left != NULL )\n        {\n          *baue = (*baue)->left;\n          LFDS711_MISC_BARRIER_LOAD;\n        }\n      }\n    break;\n\n    case LFDS711_BTREE_AU_RELATIVE_POSITION_NEXT_SMALLER_ELEMENT_IN_ENTIRE_TREE:\n      lfds711_btree_au_internal_inorder_walk_from_largest_get_next_smallest_element( baue );\n    break;\n\n    case LFDS711_BTREE_AU_RELATIVE_POSITION_NEXT_LARGER_ELEMENT_IN_ENTIRE_TREE:\n      lfds711_btree_au_internal_inorder_walk_from_smallest_get_next_largest_element( baue );\n    break;\n  }\n\n  if( *baue == NULL )\n    rv = 0;\n\n  return rv;\n}\n\n\n\n\n\n/****************************************************************************/\nstatic void lfds711_btree_au_internal_inorder_walk_from_largest_get_next_smallest_element( struct lfds711_btree_au_element **baue )\n{\n  enum lfds711_btree_au_move\n    action = LFDS711_BTREE_AU_MOVE_INVALID;\n\n  enum lfds711_misc_flag\n    finished_flag = LFDS711_MISC_FLAG_LOWERED,\n    load_finished_flag = LFDS711_MISC_FLAG_LOWERED;\n\n  struct lfds711_btree_au_element\n    *left = NULL,\n    *right = NULL,\n    *up = NULL,\n    *up_left = NULL,\n    *up_right = NULL;\n\n  LFDS711_PAL_ASSERT( baue != NULL );\n\n  /* TRD : from any given element, the next smallest element is;\n           1. if we have a left, it's the largest element on the right branch of our left child\n           2. if we don't have a left, and we're on the right of our parent, then it's our parent\n           3. if we don't have a left, and we're on the left of our parent or we have no parent,\n              iterative up the tree until we find the first child who is on the right of its parent; then it's the parent\n  */\n\n  /* TRD : we need to ensure the variables we use to decide our action are self-consistent\n           to do this, we make local copies of them all\n           then, if they are all not NULL, we can know they cannot change and we can continue\n           if however any of them are NULL, they could have changed while we were reading\n           and so our variables could be non-self-consistent\n           to check for this, we issue another processor read barrier\n           and then compare our local variables with the values in the tree\n           if they all match, then we know our variable set is self-consistent\n           (even though it may now be wrong - but we will discover this when we try the atomic operation)\n  */\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  while( load_finished_flag == LFDS711_MISC_FLAG_LOWERED )\n  {\n    left = (*baue)->left;\n    right = (*baue)->right;\n    up = (*baue)->up;\n    if( up != NULL )\n    {\n      up_left = (*baue)->up->left;\n      up_right = (*baue)->up->right;\n    }\n\n    // TRD : optimization - if all already not NULL, given we're add-only, they won't change\n    if( left != NULL and right != NULL and (up == NULL or (up != NULL and up_left != NULL and up_right != NULL)) )\n      break;\n\n    LFDS711_MISC_BARRIER_LOAD;\n\n    if( left == (*baue)->left and right == (*baue)->right and (up == NULL or (up != NULL and up == (*baue)->up and up_left == (*baue)->up->left and up_right == (*baue)->up->right)) )\n      load_finished_flag = LFDS711_MISC_FLAG_RAISED;\n  }\n\n  if( left != NULL )\n    action = LFDS711_BTREE_AU_MOVE_LARGEST_FROM_LEFT_CHILD;\n\n  if( left == NULL and up != NULL and up_right == *baue )\n    action = LFDS711_BTREE_AU_MOVE_GET_PARENT;\n\n  if( (left == NULL and up == NULL) or (up != NULL and up_left == *baue and left == NULL) )\n    action = LFDS711_BTREE_AU_MOVE_MOVE_UP_TREE;\n\n  switch( action )\n  {\n    case LFDS711_BTREE_AU_MOVE_INVALID:\n    case LFDS711_BTREE_AU_MOVE_SMALLEST_FROM_RIGHT_CHILD:\n      // TRD : eliminates a compiler warning\n    break;\n\n    case LFDS711_BTREE_AU_MOVE_LARGEST_FROM_LEFT_CHILD:\n      *baue = left;\n      if( *baue != NULL )\n      {\n        LFDS711_MISC_BARRIER_LOAD;\n        while( (*baue)->right != NULL )\n        {\n          *baue = (*baue)->right;\n          LFDS711_MISC_BARRIER_LOAD;\n        }\n      }\n    break;\n\n    case LFDS711_BTREE_AU_MOVE_GET_PARENT:\n      *baue = up;\n    break;\n\n    case LFDS711_BTREE_AU_MOVE_MOVE_UP_TREE:\n      while( finished_flag == LFDS711_MISC_FLAG_LOWERED )\n      {\n        load_finished_flag = LFDS711_MISC_FLAG_LOWERED;\n\n        while( load_finished_flag == LFDS711_MISC_FLAG_LOWERED )\n        {\n          up = (*baue)->up;\n          if( up != NULL )\n            up_left = (*baue)->up->left;\n\n          // TRD : optimization - if all already not NULL, given we're add-only, they won't change\n          if( up == NULL or (up != NULL and up_left != NULL) )\n            break;\n\n          LFDS711_MISC_BARRIER_LOAD;\n\n          if( up == (*baue)->up and up_left == (*baue)->up->left )\n            load_finished_flag = LFDS711_MISC_FLAG_RAISED;\n        }\n\n        if( *baue != NULL and up != NULL and *baue == up_left )\n          *baue = up;\n        else\n          finished_flag = LFDS711_MISC_FLAG_RAISED;\n      }\n\n      *baue = up;\n\n      /*\n\n      while( *baue != NULL and (*baue)->up != NULL and *baue == (*baue)->up->left )\n        *baue = (*baue)->up;\n\n      *baue = (*baue)->up;\n\n      */\n    break;\n  }\n\n  return;\n}\n\n\n\n\n\n/****************************************************************************/\nstatic void lfds711_btree_au_internal_inorder_walk_from_smallest_get_next_largest_element( struct lfds711_btree_au_element **baue )\n{\n  enum lfds711_btree_au_move\n    action = LFDS711_BTREE_AU_MOVE_INVALID;\n\n  enum lfds711_misc_flag\n    finished_flag = LFDS711_MISC_FLAG_LOWERED,\n    load_finished_flag = LFDS711_MISC_FLAG_LOWERED;\n\n  struct lfds711_btree_au_element\n    *left = NULL,\n    *right = NULL,\n    *up = NULL,\n    *up_left = NULL,\n    *up_right = NULL;\n\n  LFDS711_PAL_ASSERT( baue != NULL );\n\n  /* TRD : from any given element, the next largest element is;\n           1. if we have a right, it's the smallest element on the left branch of our right child\n           2. if we don't have a right, and we're on the left of our parent, then it's our parent\n           3. if we don't have a right, and we're on the right of our parent or we have no parent,\n              iterate up the tree until we find the first child who is on the left of its parent; then it's the parent\n  */\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  while( load_finished_flag == LFDS711_MISC_FLAG_LOWERED )\n  {\n    left = (*baue)->left;\n    right = (*baue)->right;\n    up = (*baue)->up;\n    if( up != NULL )\n    {\n      up_left = (*baue)->up->left;\n      up_right = (*baue)->up->right;\n    }\n\n    // TRD : optimization - if all already not NULL, given we're add-only, they won't change\n    if( left != NULL and right != NULL and (up == NULL or (up != NULL and up_left != NULL and up_right != NULL)) )\n      break;\n\n    LFDS711_MISC_BARRIER_LOAD;\n\n    if( left == (*baue)->left and right == (*baue)->right and (up == NULL or (up != NULL and up == (*baue)->up and up_left == (*baue)->up->left and up_right == (*baue)->up->right)) )\n      load_finished_flag = LFDS711_MISC_FLAG_RAISED;\n  }\n\n  if( right != NULL )\n    action = LFDS711_BTREE_AU_MOVE_SMALLEST_FROM_RIGHT_CHILD;\n\n  if( right == NULL and up != NULL and up_left == *baue )\n    action = LFDS711_BTREE_AU_MOVE_GET_PARENT;\n\n  if( (right == NULL and up == NULL) or (up != NULL and up_right == *baue and right == NULL) )\n    action = LFDS711_BTREE_AU_MOVE_MOVE_UP_TREE;\n\n  switch( action )\n  {\n    case LFDS711_BTREE_AU_MOVE_INVALID:\n    case LFDS711_BTREE_AU_MOVE_LARGEST_FROM_LEFT_CHILD:\n      // TRD : remove compiler warning\n    break;\n\n    case LFDS711_BTREE_AU_MOVE_SMALLEST_FROM_RIGHT_CHILD:\n      *baue = right;\n      if( *baue != NULL )\n      {\n        LFDS711_MISC_BARRIER_LOAD;\n        while( (*baue)->left != NULL )\n        {\n          *baue = (*baue)->left;\n          LFDS711_MISC_BARRIER_LOAD;\n        }\n      }\n    break;\n\n    case LFDS711_BTREE_AU_MOVE_GET_PARENT:\n      *baue = up;\n    break;\n\n    case LFDS711_BTREE_AU_MOVE_MOVE_UP_TREE:\n      while( finished_flag == LFDS711_MISC_FLAG_LOWERED )\n      {\n        load_finished_flag = LFDS711_MISC_FLAG_LOWERED;\n\n        while( load_finished_flag == LFDS711_MISC_FLAG_LOWERED )\n        {\n          up = (*baue)->up;\n          if( up != NULL )\n            up_right = (*baue)->up->right;\n\n          // TRD : optimization - if all already not NULL, given we're add-only, they won't change\n          if( up == NULL or (up != NULL and up_right != NULL) )\n            break;\n\n          LFDS711_MISC_BARRIER_LOAD;\n\n          if( up == (*baue)->up and up_right == (*baue)->up->right )\n            load_finished_flag = LFDS711_MISC_FLAG_RAISED;\n        }\n\n        if( *baue != NULL and up != NULL and *baue == up_right )\n          *baue = up;\n        else\n          finished_flag = LFDS711_MISC_FLAG_RAISED;\n      }\n\n      *baue = up;\n\n      /*\n\n      while( *baue != NULL and (*baue)->up != NULL and *baue == (*baue)->up->right )\n        *baue = (*baue)->up;\n\n      *baue = (*baue)->up;\n\n      */\n    break;\n  }\n\n  return;\n}\n\n\n\n\n\n/****************************************************************************/\nint lfds711_btree_au_get_by_absolute_position_and_then_by_relative_position( struct lfds711_btree_au_state *baus,\n                                                                             struct lfds711_btree_au_element **baue,\n                                                                             enum lfds711_btree_au_absolute_position absolute_position,\n                                                                             enum lfds711_btree_au_relative_position relative_position )\n{\n  int\n    rv;\n\n  LFDS711_PAL_ASSERT( baus != NULL );\n  LFDS711_PAL_ASSERT( baue != NULL );\n  // TRD: absolute_position can be any value in its range\n  // TRD: relative_position can be any value in its range\n\n  if( *baue == NULL )\n    rv = lfds711_btree_au_get_by_absolute_position( baus, baue, absolute_position );\n  else\n    rv = lfds711_btree_au_get_by_relative_position( baue, relative_position );\n\n  return rv;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_btree_addonly_unbalanced/lfds711_btree_addonly_unbalanced_init.c",
    "content": "/***** includes *****/\n#include \"lfds711_btree_addonly_unbalanced_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_btree_au_init_valid_on_current_logical_core( struct lfds711_btree_au_state *baus,\n                                                          int (*key_compare_function)(void const *new_key, void const *existing_key),\n                                                          enum lfds711_btree_au_existing_key existing_key,\n                                                          void *user_state )\n{\n  LFDS711_PAL_ASSERT( baus != NULL );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &baus->root % LFDS711_PAL_ALIGN_SINGLE_POINTER == 0 );\n  LFDS711_PAL_ASSERT( key_compare_function != NULL );\n  // TRD : existing_key can be any value in its range\n  // TRD : user_state can be NULL\n\n  baus->root = NULL;\n  baus->key_compare_function = key_compare_function;\n  baus->existing_key = existing_key;\n  baus->user_state = user_state;\n\n  lfds711_misc_internal_backoff_init( &baus->insert_backoff );\n\n  LFDS711_MISC_BARRIER_STORE;\n\n  lfds711_misc_force_store();\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_btree_addonly_unbalanced/lfds711_btree_addonly_unbalanced_insert.c",
    "content": "/***** includes *****/\n#include \"lfds711_btree_addonly_unbalanced_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nenum lfds711_btree_au_insert_result lfds711_btree_au_insert( struct lfds711_btree_au_state *baus,\n                                                             struct lfds711_btree_au_element *baue,\n                                                             struct lfds711_btree_au_element **existing_baue )\n{\n  char unsigned \n    result = 0;\n\n  int\n    compare_result = 0;\n\n  lfds711_pal_uint_t\n    backoff_iteration = LFDS711_BACKOFF_INITIAL_VALUE;\n\n  struct lfds711_btree_au_element\n    *compare = NULL,\n    *volatile baue_next = NULL,\n    *volatile baue_parent = NULL,\n    *volatile baue_temp;\n\n  LFDS711_PAL_ASSERT( baus != NULL );\n  LFDS711_PAL_ASSERT( baue != NULL );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &baue->left % LFDS711_PAL_ALIGN_SINGLE_POINTER == 0 );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &baue->right % LFDS711_PAL_ALIGN_SINGLE_POINTER == 0 );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &baue->up % LFDS711_PAL_ALIGN_SINGLE_POINTER == 0 );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &baue->value % LFDS711_PAL_ALIGN_SINGLE_POINTER == 0 );\n  // TRD : existing_baue can be NULL\n\n  /* TRD : we follow a normal search for the insert node and which side to insert\n\n           the difference is that insertion may fail because someone else inserts\n           there before we do\n\n           in this case, we resume searching for the insert node from the node\n           we were attempting to insert upon\n\n           (if we attempted to insert the root node and this failed, i.e. we thought\n            the tree was empty but then it wasn't, then we start searching from the\n            new root)\n  */\n\n  baue->up = baue->left = baue->right = NULL;\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  baue_temp = baus->root;\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  while( result == 0 )\n  {\n    // TRD : first we find where to insert\n    while( baue_temp != NULL )\n    {\n      compare_result = baus->key_compare_function( baue->key, baue_temp->key );\n\n      if( compare_result == 0 )\n      {\n        if( existing_baue != NULL )\n          *existing_baue = baue_temp;\n\n        switch( baus->existing_key )\n        {\n          case LFDS711_BTREE_AU_EXISTING_KEY_OVERWRITE:\n            LFDS711_BTREE_AU_SET_VALUE_IN_ELEMENT( *baue_temp, baue->value );\n            return LFDS711_BTREE_AU_INSERT_RESULT_SUCCESS_OVERWRITE;\n          break;\n\n          case LFDS711_BTREE_AU_EXISTING_KEY_FAIL:\n            return LFDS711_BTREE_AU_INSERT_RESULT_FAILURE_EXISTING_KEY;\n          break;\n        }\n      }\n\n      if( compare_result < 0 )\n        baue_next = baue_temp->left;\n\n      if( compare_result > 0 )\n        baue_next = baue_temp->right;\n\n      baue_parent = baue_temp;\n      baue_temp = baue_next;\n      if( baue_temp != NULL )\n        LFDS711_MISC_BARRIER_LOAD;\n    }\n\n    /* TRD : second, we actually insert\n\n             at this point baue_temp has come to NULL\n             and baue_parent is the element to insert at\n             and result of the last compare indicates\n             the direction of insertion\n\n             it may be that another tree has already inserted an element with\n             the same key as ourselves, or other elements which mean our position\n             is now wrong\n\n             in this case, it is either inserted in the position we're trying\n             to insert in now, in which case our insert will fail\n\n             or, similarly, other elements will have come in where we are,\n             and our insert will fail\n    */\n\n    if( baue_parent == NULL )\n    {\n      compare = NULL;\n      baue->up = baus->root;\n      LFDS711_MISC_BARRIER_STORE;\n      LFDS711_PAL_ATOMIC_CAS( &baus->root, &compare, baue, LFDS711_MISC_CAS_STRENGTH_WEAK, result );\n\n      if( result == 0 )\n        baue_temp = baus->root;\n    }\n\n    if( baue_parent != NULL )\n    {\n      if( compare_result <= 0 )\n      {\n        compare = NULL;\n        baue->up = baue_parent;\n        LFDS711_MISC_BARRIER_STORE;\n        LFDS711_PAL_ATOMIC_CAS( &baue_parent->left, &compare, baue, LFDS711_MISC_CAS_STRENGTH_WEAK, result );\n      }\n\n      if( compare_result > 0 )\n      {\n        compare = NULL;\n        baue->up = baue_parent;\n        LFDS711_MISC_BARRIER_STORE;\n        LFDS711_PAL_ATOMIC_CAS( &baue_parent->right, &compare, baue, LFDS711_MISC_CAS_STRENGTH_WEAK, result );\n      }\n\n      // TRD : if the insert fails, then resume searching at the insert node\n      if( result == 0 )\n        baue_temp = baue_parent;\n    }\n\n    if( result == 0 )\n      LFDS711_BACKOFF_EXPONENTIAL_BACKOFF( baus->insert_backoff, backoff_iteration );\n  }\n\n  LFDS711_BACKOFF_AUTOTUNE( baus->insert_backoff, backoff_iteration );\n\n  // TRD : if we get to here, we added (not failed or overwrite on exist) a new element\n  if( existing_baue != NULL )\n    *existing_baue = NULL;\n\n  return LFDS711_BTREE_AU_INSERT_RESULT_SUCCESS;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_btree_addonly_unbalanced/lfds711_btree_addonly_unbalanced_internal.h",
    "content": "/***** the library-wide header file *****/\n#include \"../liblfds711_internal.h\"\n\n/***** enums *****/\nenum lfds711_btree_au_move\n{\n  LFDS711_BTREE_AU_MOVE_INVALID,\n  LFDS711_BTREE_AU_MOVE_SMALLEST_FROM_RIGHT_CHILD,\n  LFDS711_BTREE_AU_MOVE_LARGEST_FROM_LEFT_CHILD,\n  LFDS711_BTREE_AU_MOVE_GET_PARENT,\n  LFDS711_BTREE_AU_MOVE_MOVE_UP_TREE\n};\n\nenum lfds711_btree_au_delete_action\n{\n  LFDS711_BTREE_AU_DELETE_SELF,\n  LFDS711_BTREE_AU_DELETE_SELF_REPLACE_WITH_LEFT_CHILD,\n  LFDS711_BTREE_AU_DELETE_SELF_REPLACE_WITH_RIGHT_CHILD,\n  LFDS711_BTREE_AU_DELETE_MOVE_LEFT\n};\n\n/***** private prototypes *****/\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_btree_addonly_unbalanced/lfds711_btree_addonly_unbalanced_query.c",
    "content": "/***** includes *****/\n#include \"lfds711_btree_addonly_unbalanced_internal.h\"\n\n/***** private prototypes *****/\nstatic void lfds711_btree_au_internal_validate( struct lfds711_btree_au_state *abs, struct lfds711_misc_validation_info *vi, enum lfds711_misc_validity *lfds711_btree_au_validity );\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_btree_au_query( struct lfds711_btree_au_state *baus,\n                             enum lfds711_btree_au_query query_type,\n                             void *query_input,\n                             void *query_output )\n{\n  LFDS711_PAL_ASSERT( baus != NULL );\n  // TRD : query_type can be any value in its range\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  switch( query_type )\n  {\n    case LFDS711_BTREE_AU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT:\n    {\n      struct lfds711_btree_au_element\n        *baue = NULL;\n\n      LFDS711_PAL_ASSERT( query_input == NULL );\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      *(lfds711_pal_uint_t *) query_output = 0;\n\n      while( lfds711_btree_au_get_by_absolute_position_and_then_by_relative_position(baus, &baue, LFDS711_BTREE_AU_ABSOLUTE_POSITION_SMALLEST_IN_TREE, LFDS711_BTREE_AU_RELATIVE_POSITION_NEXT_LARGER_ELEMENT_IN_ENTIRE_TREE) )\n        ( *(lfds711_pal_uint_t *) query_output )++;\n    }\n    break;\n\n    case LFDS711_BTREE_AU_QUERY_SINGLETHREADED_VALIDATE:\n      // TRD : query_input can be NULL\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      lfds711_btree_au_internal_validate( baus, (struct lfds711_misc_validation_info *) query_input, (enum lfds711_misc_validity *) query_output );\n    break;\n  }\n\n  return;\n}\n\n\n\n\n\n/****************************************************************************/\nstatic void lfds711_btree_au_internal_validate( struct lfds711_btree_au_state *baus,\n                                                struct lfds711_misc_validation_info *vi,\n                                                enum lfds711_misc_validity *lfds711_btree_au_validity )\n{\n  lfds711_pal_uint_t\n    number_elements_from_query_tree = 0,\n    number_elements_from_walk = 0;\n\n  struct lfds711_btree_au_element\n    *baue = NULL,\n    *baue_prev = NULL;\n\n  LFDS711_PAL_ASSERT( baus!= NULL );\n  // TRD : vi can be NULL\n  LFDS711_PAL_ASSERT( lfds711_btree_au_validity != NULL );\n\n  *lfds711_btree_au_validity = LFDS711_MISC_VALIDITY_VALID;\n\n  /* TRD : validation is performed by;\n\n           performing an in-order walk\n           we should see every element is larger than the preceeding element\n           we count elements as we go along (visited elements, that is)\n           and check our tally equals the expected count\n  */\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  while( lfds711_btree_au_get_by_absolute_position_and_then_by_relative_position(baus, &baue, LFDS711_BTREE_AU_ABSOLUTE_POSITION_SMALLEST_IN_TREE, LFDS711_BTREE_AU_RELATIVE_POSITION_NEXT_LARGER_ELEMENT_IN_ENTIRE_TREE) )\n  {\n    // TRD : baue_prev should always be smaller than or equal to baue\n    if( baue_prev != NULL )\n      if( baus->key_compare_function(baue_prev->key, baue->key) > 0 )\n      {\n        *lfds711_btree_au_validity = LFDS711_MISC_VALIDITY_INVALID_ORDER;\n        return;\n      }\n\n    baue_prev = baue;\n    number_elements_from_walk++;\n  }\n\n  if( *lfds711_btree_au_validity == LFDS711_MISC_VALIDITY_VALID )\n  {\n    lfds711_btree_au_query( (struct lfds711_btree_au_state *) baus, LFDS711_BTREE_AU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, &number_elements_from_query_tree );\n\n    if( number_elements_from_walk > number_elements_from_query_tree )\n      *lfds711_btree_au_validity = LFDS711_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS;\n\n    if( number_elements_from_walk < number_elements_from_query_tree )\n      *lfds711_btree_au_validity = LFDS711_MISC_VALIDITY_INVALID_MISSING_ELEMENTS;\n  }\n\n  /* TRD : now check for expected number of elements\n           vi can be NULL, in which case we do not check\n           we know we don't have a loop from our earlier check\n  */\n\n  if( *lfds711_btree_au_validity == LFDS711_MISC_VALIDITY_VALID and vi != NULL )\n  {\n    lfds711_btree_au_query( (struct lfds711_btree_au_state *) baus, LFDS711_BTREE_AU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, &number_elements_from_query_tree );\n\n    if( number_elements_from_query_tree < vi->min_elements )\n      *lfds711_btree_au_validity = LFDS711_MISC_VALIDITY_INVALID_MISSING_ELEMENTS;\n\n    if( number_elements_from_query_tree > vi->max_elements )\n      *lfds711_btree_au_validity = LFDS711_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS;\n  }\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_freelist/lfds711_freelist_cleanup.c",
    "content": "/***** includes *****/\n#include \"lfds711_freelist_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_freelist_cleanup( struct lfds711_freelist_state *fs,\n                               void (*element_cleanup_callback)(struct lfds711_freelist_state *fs, struct lfds711_freelist_element *fe) )\n{\n  struct lfds711_freelist_element\n    *fe,\n    *fe_temp;\n\n  LFDS711_PAL_ASSERT( fs != NULL );\n  // TRD : element_cleanup_callback can be NULL\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  if( element_cleanup_callback != NULL )\n  {\n    fe = fs->top[POINTER];\n\n    while( fe != NULL )\n    {\n      fe_temp = fe;\n      fe = fe->next;\n\n      element_cleanup_callback( fs, fe_temp );\n    }\n  }\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_freelist/lfds711_freelist_init.c",
    "content": "/***** includes *****/\n#include \"lfds711_freelist_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_freelist_init_valid_on_current_logical_core( struct lfds711_freelist_state *fs,\n                                                          struct lfds711_freelist_element * volatile (*elimination_array)[LFDS711_FREELIST_ELIMINATION_ARRAY_ELEMENT_SIZE_IN_FREELIST_ELEMENTS],\n                                                          lfds711_pal_uint_t elimination_array_size_in_elements,\n                                                          void *user_state )\n{\n  lfds711_pal_uint_t\n    loop,\n    subloop;\n\n  LFDS711_PAL_ASSERT( fs != NULL );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) fs->top % LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &fs->elimination_array_size_in_elements % LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 );\n  // TRD : elimination_array can be NULL\n  LFDS711_PAL_ASSERT( (elimination_array == NULL) or \n                      ( (elimination_array != NULL) and (lfds711_pal_uint_t) elimination_array % LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ) );\n  LFDS711_PAL_ASSERT( (elimination_array == NULL and elimination_array_size_in_elements == 0) or \n                      (elimination_array != NULL and elimination_array_size_in_elements >= 2 and (elimination_array_size_in_elements & (elimination_array_size_in_elements-1)) == 0) );\n  // TRD : user_state can be NULL\n\n  fs->top[POINTER] = NULL;\n  fs->top[COUNTER] = 0;\n\n  fs->elimination_array = elimination_array;\n  fs->elimination_array_size_in_elements = elimination_array_size_in_elements;\n  fs->user_state = user_state;\n\n  for( loop = 0 ; loop < elimination_array_size_in_elements ; loop++ )\n    for( subloop = 0 ; subloop < LFDS711_FREELIST_ELIMINATION_ARRAY_ELEMENT_SIZE_IN_FREELIST_ELEMENTS ; subloop++ )\n      fs->elimination_array[loop][subloop] = NULL;\n\n  lfds711_misc_internal_backoff_init( &fs->pop_backoff );\n  lfds711_misc_internal_backoff_init( &fs->push_backoff );\n\n  LFDS711_MISC_BARRIER_STORE;\n\n  lfds711_misc_force_store();\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_freelist/lfds711_freelist_internal.h",
    "content": "/***** the library wide include file *****/\n#include \"../liblfds711_internal.h\"\n\n/***** private prototypes *****/\nvoid lfds711_freelist_internal_push_without_ea( struct lfds711_freelist_state *fs,\n                                                struct lfds711_freelist_element *fe );\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_freelist/lfds711_freelist_pop.c",
    "content": "/***** includes *****/\n#include \"lfds711_freelist_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nint lfds711_freelist_pop( struct lfds711_freelist_state *fs,\n                          struct lfds711_freelist_element **fe,\n                          struct lfds711_prng_st_state *psts )\n{\n  char unsigned\n    result;\n\n  lfds711_pal_uint_t\n    backoff_iteration = LFDS711_BACKOFF_INITIAL_VALUE,\n    elimination_array_index,\n    loop,\n    random_value;\n\n  struct lfds711_freelist_element LFDS711_PAL_ALIGN(LFDS711_PAL_ALIGN_DOUBLE_POINTER)\n    *new_top[PAC_SIZE],\n    *volatile original_top[PAC_SIZE];\n\n  LFDS711_PAL_ASSERT( fs != NULL );\n  LFDS711_PAL_ASSERT( fe != NULL );\n  // TRD : psts can be NULL\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  if( fs->elimination_array_size_in_elements > 0 )\n  {\n    if( psts != NULL )\n    {\n      LFDS711_PRNG_ST_GENERATE( *psts, random_value );\n      elimination_array_index = ( random_value & (fs->elimination_array_size_in_elements-1) );\n    }\n    else\n    {\n      elimination_array_index = (lfds711_pal_uint_t) fe;\n      LFDS711_PRNG_ST_MIXING_FUNCTION( elimination_array_index );\n      elimination_array_index = ( elimination_array_index & (fs->elimination_array_size_in_elements-1) );\n    }\n\n    // TRD : full scan of one cache line, max pointers per cache line\n\n    *fe = NULL;\n\n    for( loop = 0 ; loop < LFDS711_FREELIST_ELIMINATION_ARRAY_ELEMENT_SIZE_IN_FREELIST_ELEMENTS ; loop++ )\n      if( fs->elimination_array[elimination_array_index][loop] != NULL )\n      {\n        LFDS711_PAL_ATOMIC_EXCHANGE( &fs->elimination_array[elimination_array_index][loop], *fe, struct lfds711_freelist_element * );\n        if( *fe != NULL )\n          return 1;\n      }\n  }\n\n  original_top[COUNTER] = fs->top[COUNTER];\n  original_top[POINTER] = fs->top[POINTER];\n\n  do\n  {\n    if( original_top[POINTER] == NULL )\n    {\n      *fe = NULL;\n      return 0;\n    }\n\n    new_top[COUNTER] = original_top[COUNTER] + 1;\n    new_top[POINTER] = original_top[POINTER]->next;\n\n    LFDS711_PAL_ATOMIC_DWCAS( fs->top, original_top, new_top, LFDS711_MISC_CAS_STRENGTH_WEAK, result );\n\n    if( result == 0 )\n    {\n      LFDS711_BACKOFF_EXPONENTIAL_BACKOFF( fs->pop_backoff, backoff_iteration );\n      LFDS711_MISC_BARRIER_LOAD;\n    }\n  }\n  while( result == 0 );\n\n  *fe = original_top[POINTER];\n\n  LFDS711_BACKOFF_AUTOTUNE( fs->pop_backoff, backoff_iteration );\n\n  return 1;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_freelist/lfds711_freelist_push.c",
    "content": "/***** includes *****/\n#include \"lfds711_freelist_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_freelist_push( struct lfds711_freelist_state *fs,\n                            struct lfds711_freelist_element *fe,\n                            struct lfds711_prng_st_state *psts )\n{\n  char unsigned\n    result;\n\n  lfds711_pal_uint_t\n    backoff_iteration = LFDS711_BACKOFF_INITIAL_VALUE,\n    elimination_array_index,\n    loop,\n    random_value;\n\n  struct lfds711_freelist_element LFDS711_PAL_ALIGN(LFDS711_PAL_ALIGN_DOUBLE_POINTER)\n    *new_top[PAC_SIZE],\n    *volatile original_top[PAC_SIZE];\n\n  LFDS711_PAL_ASSERT( fs != NULL );\n  LFDS711_PAL_ASSERT( fe != NULL );\n  // TRD : psts can be NULL\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  if( fs->elimination_array_size_in_elements > 0 )\n  {\n    if( psts != NULL )\n    {\n      LFDS711_PRNG_ST_GENERATE( *psts, random_value );\n      elimination_array_index = ( random_value & (fs->elimination_array_size_in_elements-1) );\n    }\n    else\n    {\n      elimination_array_index = (lfds711_pal_uint_t) fe;\n      LFDS711_PRNG_ST_MIXING_FUNCTION( elimination_array_index );\n      elimination_array_index = ( elimination_array_index & (fs->elimination_array_size_in_elements-1) );\n    }\n\n    // TRD : full scan of one cache line, max pointers per cache line\n\n    for( loop = 0 ; loop < LFDS711_FREELIST_ELIMINATION_ARRAY_ELEMENT_SIZE_IN_FREELIST_ELEMENTS ; loop++ )\n      if( fs->elimination_array[elimination_array_index][loop] == NULL )\n      {\n        LFDS711_PAL_ATOMIC_EXCHANGE( &fs->elimination_array[elimination_array_index][loop], fe, struct lfds711_freelist_element * );\n        if( fe == NULL )\n          return;\n      }\n  }\n\n  new_top[POINTER] = fe;\n\n  original_top[COUNTER] = fs->top[COUNTER];\n  original_top[POINTER] = fs->top[POINTER];\n\n  do\n  {\n    fe->next = original_top[POINTER];\n    LFDS711_MISC_BARRIER_STORE;\n\n    new_top[COUNTER] = original_top[COUNTER] + 1;\n    LFDS711_PAL_ATOMIC_DWCAS( fs->top, original_top, new_top, LFDS711_MISC_CAS_STRENGTH_WEAK, result );\n\n    if( result == 0 )\n      LFDS711_BACKOFF_EXPONENTIAL_BACKOFF( fs->push_backoff, backoff_iteration );\n  }\n  while( result == 0 );\n\n  LFDS711_BACKOFF_AUTOTUNE( fs->push_backoff, backoff_iteration );\n\n  return;\n}\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_freelist_internal_push_without_ea( struct lfds711_freelist_state *fs,\n                                                struct lfds711_freelist_element *fe )\n{\n  char unsigned\n    result;\n\n  lfds711_pal_uint_t\n    backoff_iteration = LFDS711_BACKOFF_INITIAL_VALUE;\n\n  struct lfds711_freelist_element LFDS711_PAL_ALIGN(LFDS711_PAL_ALIGN_DOUBLE_POINTER)\n    *new_top[PAC_SIZE],\n    *volatile original_top[PAC_SIZE];\n\n  LFDS711_PAL_ASSERT( fs != NULL );\n  LFDS711_PAL_ASSERT( fe != NULL );\n\n  new_top[POINTER] = fe;\n\n  original_top[COUNTER] = fs->top[COUNTER];\n  original_top[POINTER] = fs->top[POINTER];\n\n  do\n  {\n    fe->next = original_top[POINTER];\n    LFDS711_MISC_BARRIER_STORE;\n\n    new_top[COUNTER] = original_top[COUNTER] + 1;\n    LFDS711_PAL_ATOMIC_DWCAS( fs->top, original_top, new_top, LFDS711_MISC_CAS_STRENGTH_WEAK, result );\n\n    if( result == 0 )\n      LFDS711_BACKOFF_EXPONENTIAL_BACKOFF( fs->push_backoff, backoff_iteration );\n  }\n  while( result == 0 );\n\n  LFDS711_BACKOFF_AUTOTUNE( fs->push_backoff, backoff_iteration );\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_freelist/lfds711_freelist_query.c",
    "content": "/***** includes *****/\n#include \"lfds711_freelist_internal.h\"\n\n/***** private prototypes *****/\nstatic void lfds711_freelist_internal_freelist_validate( struct lfds711_freelist_state *fs,\n                                                         struct lfds711_misc_validation_info *vi,\n                                                         enum lfds711_misc_validity *lfds711_freelist_validity );\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_freelist_query( struct lfds711_freelist_state *fs,\n                             enum lfds711_freelist_query query_type,\n                             void *query_input,\n                             void *query_output )\n{\n  struct lfds711_freelist_element\n    *fe;\n\n  LFDS711_PAL_ASSERT( fs != NULL );\n  // TRD : query_type can be any value in its range\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  switch( query_type )\n  {\n    case LFDS711_FREELIST_QUERY_SINGLETHREADED_GET_COUNT:\n    {\n      lfds711_pal_uint_t\n        loop,\n        subloop;\n\n      LFDS711_PAL_ASSERT( query_input == NULL );\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      *(lfds711_pal_uint_t *) query_output = 0;\n\n      // TRD : count the elements in the elimination array\n      for( loop = 0 ; loop < fs->elimination_array_size_in_elements ; loop++ )\n        for( subloop = 0 ; subloop < LFDS711_FREELIST_ELIMINATION_ARRAY_ELEMENT_SIZE_IN_FREELIST_ELEMENTS ; subloop++ )\n          if( fs->elimination_array[loop][subloop] != NULL )\n            ( *(lfds711_pal_uint_t *) query_output )++;\n\n      // TRD : count the elements on the freelist\n      fe = (struct lfds711_freelist_element *) fs->top[POINTER];\n\n      while( fe != NULL )\n      {\n        ( *(lfds711_pal_uint_t *) query_output )++;\n        fe = (struct lfds711_freelist_element *) fe->next;\n      }\n    }\n    break;\n\n    case LFDS711_FREELIST_QUERY_SINGLETHREADED_VALIDATE:\n      // TRD : query_input can be NULL\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      lfds711_freelist_internal_freelist_validate( fs, (struct lfds711_misc_validation_info *) query_input, (enum lfds711_misc_validity *) query_output );\n    break;\n\n    case LFDS711_FREELIST_QUERY_GET_ELIMINATION_ARRAY_EXTRA_ELEMENTS_IN_FREELIST_ELEMENTS:\n    {\n      LFDS711_PAL_ASSERT( query_input == NULL );\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      ( *(lfds711_pal_uint_t *) query_output ) = (fs->elimination_array_size_in_elements-1) * LFDS711_FREELIST_ELIMINATION_ARRAY_ELEMENT_SIZE_IN_FREELIST_ELEMENTS;\n    }\n    break;\n  }\n\n  return;\n}\n\n\n\n\n\n/****************************************************************************/\nstatic void lfds711_freelist_internal_freelist_validate( struct lfds711_freelist_state *fs,\n                                                         struct lfds711_misc_validation_info *vi,\n                                                         enum lfds711_misc_validity *lfds711_freelist_validity )\n{\n  lfds711_pal_uint_t\n    number_elements = 0;\n\n  struct lfds711_freelist_element\n    *fe_slow,\n    *fe_fast;\n\n  LFDS711_PAL_ASSERT( fs != NULL );\n  // TRD : vi can be NULL\n  LFDS711_PAL_ASSERT( lfds711_freelist_validity != NULL );\n\n  *lfds711_freelist_validity = LFDS711_MISC_VALIDITY_VALID;\n\n  fe_slow = fe_fast = (struct lfds711_freelist_element *) fs->top[POINTER];\n\n  /* TRD : first, check for a loop\n           we have two pointers\n           both of which start at the top of the freelist\n           we enter a loop\n           and on each iteration\n           we advance one pointer by one element\n           and the other by two\n\n           we exit the loop when both pointers are NULL\n           (have reached the end of the freelist)\n\n           or\n\n           if we fast pointer 'sees' the slow pointer\n           which means we have a loop\n  */\n\n  if( fe_slow != NULL )\n    do\n    {\n      fe_slow = fe_slow->next;\n\n      if( fe_fast != NULL )\n        fe_fast = fe_fast->next;\n\n      if( fe_fast != NULL )\n        fe_fast = fe_fast->next;\n    }\n    while( fe_slow != NULL and fe_fast != fe_slow );\n\n  if( fe_fast != NULL and fe_slow != NULL and fe_fast == fe_slow )\n    *lfds711_freelist_validity = LFDS711_MISC_VALIDITY_INVALID_LOOP;\n\n  /* TRD : now check for expected number of elements\n           vi can be NULL, in which case we do not check\n           we know we don't have a loop from our earlier check\n  */\n\n  if( *lfds711_freelist_validity == LFDS711_MISC_VALIDITY_VALID and vi != NULL )\n  {\n    lfds711_freelist_query( fs, LFDS711_FREELIST_QUERY_SINGLETHREADED_GET_COUNT, NULL, (void *) &number_elements );\n\n    if( number_elements < vi->min_elements )\n      *lfds711_freelist_validity = LFDS711_MISC_VALIDITY_INVALID_MISSING_ELEMENTS;\n\n    if( number_elements > vi->max_elements )\n      *lfds711_freelist_validity = LFDS711_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS;\n  }\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_hash_addonly/lfds711_hash_addonly_cleanup.c",
    "content": "/***** includes *****/\n#include \"lfds711_hash_addonly_internal.h\"\n\n/***** private prototypes*****/\nstatic void btree_au_element_cleanup_function( struct lfds711_btree_au_state *baus,\n                                               struct lfds711_btree_au_element *baue );\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_hash_a_cleanup( struct lfds711_hash_a_state *has,\n                             void (*element_cleanup_callback)(struct lfds711_hash_a_state *has, struct lfds711_hash_a_element *hae) )\n{\n  lfds711_pal_uint_t\n    loop;\n\n  LFDS711_PAL_ASSERT( has != NULL );\n  // TRD : element_cleanup_callback can be NULL\n\n  if( element_cleanup_callback == NULL )\n    return;\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  has->element_cleanup_callback = element_cleanup_callback;\n\n  for( loop = 0 ; loop < has->array_size ; loop++ )\n    lfds711_btree_au_cleanup( has->baus_array+loop, btree_au_element_cleanup_function );\n\n  return;\n}\n\n\n\n\n\n/****************************************************************************/\n#pragma warning( disable : 4100 )\n\nstatic void btree_au_element_cleanup_function( struct lfds711_btree_au_state *baus,\n                                               struct lfds711_btree_au_element *baue )\n{\n  struct lfds711_hash_a_state\n    *has;\n\n  struct lfds711_hash_a_element\n    *hae;\n\n  LFDS711_PAL_ASSERT( baus != NULL );\n  LFDS711_PAL_ASSERT( baue != NULL );\n\n  hae = (struct lfds711_hash_a_element *) LFDS711_BTREE_AU_GET_VALUE_FROM_ELEMENT( *baue );\n  has = (struct lfds711_hash_a_state *) LFDS711_BTREE_AU_GET_USER_STATE_FROM_STATE( *baus );\n\n  has->element_cleanup_callback( has, hae );\n\n  return;\n}\n\n#pragma warning( default : 4100 )\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_hash_addonly/lfds711_hash_addonly_get.c",
    "content": "/***** includes *****/\n#include \"lfds711_hash_addonly_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nint lfds711_hash_a_get_by_key( struct lfds711_hash_a_state *has,\n                               int (*key_compare_function)(void const *new_key, void const *existing_key),\n                               void (*key_hash_function)(void const *key, lfds711_pal_uint_t *hash),\n                               void *key,\n                               struct lfds711_hash_a_element **hae )\n{\n  int\n    rv;\n\n  lfds711_pal_uint_t\n    hash = 0;\n\n  struct lfds711_btree_au_element\n    *baue;\n\n  LFDS711_PAL_ASSERT( has != NULL );\n  // TRD : key_compare_function can be NULL\n  // TRD : key_hash_function can be NULL\n  // TRD : key can be NULL\n  LFDS711_PAL_ASSERT( hae != NULL );\n\n  if( key_compare_function == NULL )\n    key_compare_function = has->key_compare_function;\n\n  if( key_hash_function == NULL )\n    key_hash_function = has->key_hash_function;\n\n  key_hash_function( key, &hash );\n\n  rv = lfds711_btree_au_get_by_key( has->baus_array + (hash % has->array_size), key_compare_function, key, &baue );\n\n  if( rv == 1 )\n    *hae = LFDS711_BTREE_AU_GET_VALUE_FROM_ELEMENT( *baue );\n  else\n    *hae = NULL;\n\n  return rv;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_hash_addonly/lfds711_hash_addonly_init.c",
    "content": "/***** includes *****/\n#include \"lfds711_hash_addonly_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_hash_a_init_valid_on_current_logical_core( struct lfds711_hash_a_state *has,\n                                                        struct lfds711_btree_au_state *baus_array,\n                                                        lfds711_pal_uint_t array_size,\n                                                        int (*key_compare_function)(void const *new_key, void const *existing_key),\n                                                        void (*key_hash_function)(void const *key, lfds711_pal_uint_t *hash),\n                                                        enum lfds711_hash_a_existing_key existing_key,\n                                                        void *user_state )\n{\n  enum lfds711_btree_au_existing_key\n    btree_au_existing_key = LFDS711_BTREE_AU_EXISTING_KEY_OVERWRITE; // TRD : for compiler warning\n\n  lfds711_pal_uint_t\n    loop;\n\n  LFDS711_PAL_ASSERT( has != NULL );\n  LFDS711_PAL_ASSERT( baus_array != NULL );\n  LFDS711_PAL_ASSERT( array_size > 0 );\n  LFDS711_PAL_ASSERT( key_compare_function != NULL );\n  LFDS711_PAL_ASSERT( key_hash_function != NULL );\n  // TRD : existing_key can be any value in its range\n  // TRD : user_state can be NULL\n\n  has->array_size = array_size;\n  has->key_compare_function = key_compare_function;\n  has->key_hash_function = key_hash_function;\n  has->existing_key = existing_key;\n  has->baus_array = baus_array;\n  has->user_state = user_state;\n\n  if( has->existing_key == LFDS711_HASH_A_EXISTING_KEY_OVERWRITE )\n    btree_au_existing_key = LFDS711_BTREE_AU_EXISTING_KEY_OVERWRITE;\n\n  if( has->existing_key == LFDS711_HASH_A_EXISTING_KEY_FAIL )\n    btree_au_existing_key = LFDS711_BTREE_AU_EXISTING_KEY_FAIL;\n\n  // TRD : since the addonly_hash atomic counts, if that flag is set, the btree_addonly_unbalanceds don't have to\n  for( loop = 0 ; loop < array_size ; loop++ )\n    lfds711_btree_au_init_valid_on_current_logical_core( has->baus_array+loop, key_compare_function, btree_au_existing_key, user_state );\n\n  LFDS711_MISC_BARRIER_STORE;\n\n  lfds711_misc_force_store();\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_hash_addonly/lfds711_hash_addonly_insert.c",
    "content": "/***** includes *****/\n#include \"lfds711_hash_addonly_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nenum lfds711_hash_a_insert_result lfds711_hash_a_insert( struct lfds711_hash_a_state *has,\n                                                         struct lfds711_hash_a_element *hae,\n                                                         struct lfds711_hash_a_element **existing_hae )\n{\n  enum lfds711_hash_a_insert_result\n    apr = LFDS711_HASH_A_PUT_RESULT_SUCCESS;\n\n  enum lfds711_btree_au_insert_result\n    alr;\n\n  lfds711_pal_uint_t\n    hash = 0;\n\n  struct lfds711_btree_au_element\n    *existing_baue;\n\n  LFDS711_PAL_ASSERT( has != NULL );\n  LFDS711_PAL_ASSERT( hae != NULL );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &hae->value % LFDS711_PAL_ALIGN_SINGLE_POINTER == 0 );\n  // TRD : existing_hae can be NULL\n\n  // TRD : alignment checks\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &hae->baue % LFDS711_PAL_ALIGN_SINGLE_POINTER == 0 );\n\n  has->key_hash_function( hae->key, &hash );\n\n  LFDS711_BTREE_AU_SET_KEY_IN_ELEMENT( hae->baue, hae->key );\n  LFDS711_BTREE_AU_SET_VALUE_IN_ELEMENT( hae->baue, hae );\n\n  alr = lfds711_btree_au_insert( has->baus_array + (hash % has->array_size), &hae->baue, &existing_baue );\n\n  switch( alr )\n  {\n    case LFDS711_BTREE_AU_INSERT_RESULT_FAILURE_EXISTING_KEY:\n      if( existing_hae != NULL )\n        *existing_hae = LFDS711_BTREE_AU_GET_VALUE_FROM_ELEMENT( *existing_baue );\n\n      apr = LFDS711_HASH_A_PUT_RESULT_FAILURE_EXISTING_KEY;\n    break;\n\n    case LFDS711_BTREE_AU_INSERT_RESULT_SUCCESS_OVERWRITE:\n      apr = LFDS711_HASH_A_PUT_RESULT_SUCCESS_OVERWRITE;\n    break;\n\n    case LFDS711_BTREE_AU_INSERT_RESULT_SUCCESS:\n      apr = LFDS711_HASH_A_PUT_RESULT_SUCCESS;\n    break;\n  }\n\n  return apr;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_hash_addonly/lfds711_hash_addonly_internal.h",
    "content": "/***** the library wide include file *****/\n#include \"../liblfds711_internal.h\"\n\n/***** private prototypes *****/\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_hash_addonly/lfds711_hash_addonly_iterate.c",
    "content": "/***** includes *****/\n#include \"lfds711_hash_addonly_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_hash_a_iterate_init( struct lfds711_hash_a_state *has,\n                                  struct lfds711_hash_a_iterate *hai )\n{\n  LFDS711_PAL_ASSERT( has != NULL );\n  LFDS711_PAL_ASSERT( hai != NULL );\n\n  hai->baus = has->baus_array;\n  hai->baus_end = has->baus_array + has->array_size;\n  hai->baue = NULL;\n\n  return;\n}\n\n\n\n\n\n/****************************************************************************/\nint lfds711_hash_a_iterate( struct lfds711_hash_a_iterate *hai,\n                            struct lfds711_hash_a_element **hae )\n{\n  enum lfds711_misc_flag\n    finished_flag = LFDS711_MISC_FLAG_LOWERED;\n\n  int\n    rv = 0;\n\n  LFDS711_PAL_ASSERT( hai != NULL );\n  LFDS711_PAL_ASSERT( hae != NULL );\n\n  while( finished_flag == LFDS711_MISC_FLAG_LOWERED )\n  {\n    lfds711_btree_au_get_by_absolute_position_and_then_by_relative_position( hai->baus, &hai->baue, LFDS711_BTREE_AU_ABSOLUTE_POSITION_SMALLEST_IN_TREE, LFDS711_BTREE_AU_RELATIVE_POSITION_NEXT_LARGER_ELEMENT_IN_ENTIRE_TREE );\n\n    if( hai->baue != NULL )\n    {\n      *hae = LFDS711_BTREE_AU_GET_VALUE_FROM_ELEMENT( *hai->baue );\n      finished_flag = LFDS711_MISC_FLAG_RAISED;\n      rv = 1;\n    }\n\n    if( hai->baue == NULL )\n      if( ++hai->baus == hai->baus_end )\n      {\n        *hae = NULL;\n        finished_flag = LFDS711_MISC_FLAG_RAISED;\n      }\n  }\n\n  return rv;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_hash_addonly/lfds711_hash_addonly_query.c",
    "content": "/***** includes *****/\n#include \"lfds711_hash_addonly_internal.h\"\n\n/***** private prototypes *****/\nstatic void lfds711_hash_a_internal_validate( struct lfds711_hash_a_state *has,\n                                              struct lfds711_misc_validation_info *vi,\n                                              enum lfds711_misc_validity *lfds711_hash_a_validity );\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_hash_a_query( struct lfds711_hash_a_state *has,\n                           enum lfds711_hash_a_query query_type,\n                           void *query_input,\n                           void *query_output )\n{\n  LFDS711_PAL_ASSERT( has != NULL );\n  // TRD : query_type can be any value in its range\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  switch( query_type )\n  {\n    case LFDS711_HASH_A_QUERY_GET_POTENTIALLY_INACCURATE_COUNT:\n    {\n      struct lfds711_hash_a_iterate\n        ai;\n\n      struct lfds711_hash_a_element\n        *hae;\n\n      LFDS711_PAL_ASSERT( query_input == NULL );\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      *(lfds711_pal_uint_t *) query_output = 0;\n\n      lfds711_hash_a_iterate_init( has, &ai );\n\n      while( lfds711_hash_a_iterate(&ai, &hae) )\n        ( *(lfds711_pal_uint_t *) query_output )++;\n    }\n    break;\n\n    case LFDS711_HASH_A_QUERY_SINGLETHREADED_VALIDATE:\n      // TRD: query_input can be any value in its range\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      lfds711_hash_a_internal_validate( has, (struct lfds711_misc_validation_info *) query_input, (enum lfds711_misc_validity *) query_output );\n    break;\n  }\n\n  return;\n}\n\n\n\n\n\n/****************************************************************************/\nstatic void lfds711_hash_a_internal_validate( struct lfds711_hash_a_state *has,\n                                              struct lfds711_misc_validation_info *vi,\n                                              enum lfds711_misc_validity *lfds711_hash_a_validity )\n{\n  lfds711_pal_uint_t\n    lfds711_hash_a_total_number_elements = 0,\n    lfds711_btree_au_total_number_elements = 0,\n    number_elements;\n\n  lfds711_pal_uint_t\n    loop;\n\n  LFDS711_PAL_ASSERT( has!= NULL );\n  // TRD : vi can be NULL\n  LFDS711_PAL_ASSERT( lfds711_hash_a_validity != NULL );\n\n  /* TRD : validate every btree_addonly_unbalanced in the addonly_hash\n           sum elements in each btree_addonly_unbalanced\n           check matches expected element counts (if vi is provided)\n  */\n\n  *lfds711_hash_a_validity = LFDS711_MISC_VALIDITY_VALID;\n\n  for( loop = 0 ; *lfds711_hash_a_validity == LFDS711_MISC_VALIDITY_VALID and loop < has->array_size ; loop++ )\n    lfds711_btree_au_query( has->baus_array+loop, LFDS711_BTREE_AU_QUERY_SINGLETHREADED_VALIDATE, NULL, (void *) lfds711_hash_a_validity );\n\n  if( *lfds711_hash_a_validity == LFDS711_MISC_VALIDITY_VALID )\n  {\n    for( loop = 0 ; loop < has->array_size ; loop++ )\n    {\n      lfds711_btree_au_query( has->baus_array+loop, LFDS711_BTREE_AU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void *) &number_elements );\n      lfds711_btree_au_total_number_elements += number_elements;\n    }\n\n    // TRD : first, check btree_addonly_unbalanced total vs the addonly_hash total\n    lfds711_hash_a_query( has, LFDS711_HASH_A_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, &lfds711_hash_a_total_number_elements );\n\n    // TRD : the btree_addonly_unbalanceds are assumed to speak the truth\n    if( lfds711_hash_a_total_number_elements < lfds711_btree_au_total_number_elements )\n      *lfds711_hash_a_validity = LFDS711_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS;\n\n    if( lfds711_hash_a_total_number_elements > lfds711_btree_au_total_number_elements )\n      *lfds711_hash_a_validity = LFDS711_MISC_VALIDITY_INVALID_MISSING_ELEMENTS;\n\n    // TRD : second, if we're still valid and vi is provided, check the btree_addonly_unbalanced total against vi\n    if( *lfds711_hash_a_validity == LFDS711_MISC_VALIDITY_VALID and vi != NULL )\n    {\n      if( lfds711_btree_au_total_number_elements < vi->min_elements )\n        *lfds711_hash_a_validity = LFDS711_MISC_VALIDITY_INVALID_MISSING_ELEMENTS;\n\n      if( lfds711_btree_au_total_number_elements > vi->max_elements )\n        *lfds711_hash_a_validity = LFDS711_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS;\n    }\n  }\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_list_addonly_singlylinked_ordered/lfds711_list_addonly_singlylinked_ordered_cleanup.c",
    "content": "/***** includes *****/\n#include \"lfds711_list_addonly_singlylinked_ordered_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_list_aso_cleanup( struct lfds711_list_aso_state *lasos,\n                               void (*element_cleanup_callback)(struct lfds711_list_aso_state *lasos, struct lfds711_list_aso_element *lasoe) )\n{\n  struct lfds711_list_aso_element\n    *lasoe,\n    *temp;\n\n  LFDS711_PAL_ASSERT( lasos != NULL );\n  // TRD : element_cleanup_callback can be NULL\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  if( element_cleanup_callback == NULL )\n    return;\n\n  lasoe = LFDS711_LIST_ASO_GET_START( *lasos );\n\n  while( lasoe != NULL )\n  {\n    temp = lasoe;\n\n    lasoe = LFDS711_LIST_ASO_GET_NEXT( *lasoe );\n\n    element_cleanup_callback( lasos, temp );\n  }\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_list_addonly_singlylinked_ordered/lfds711_list_addonly_singlylinked_ordered_get.c",
    "content": "/***** includes *****/\n#include \"lfds711_list_addonly_singlylinked_ordered_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nint lfds711_list_aso_get_by_key( struct lfds711_list_aso_state *lasos,\n                                 void *key,\n                                 struct lfds711_list_aso_element **lasoe )\n{\n  int\n    cr = !0,\n    rv = 1;\n\n  LFDS711_PAL_ASSERT( lasos != NULL );\n  // TRD : key can be NULL\n  LFDS711_PAL_ASSERT( lasoe != NULL );\n\n  while( cr != 0 and LFDS711_LIST_ASO_GET_START_AND_THEN_NEXT(*lasos, *lasoe) )\n    cr = lasos->key_compare_function( key, (*lasoe)->key );\n\n  if( *lasoe == NULL )\n    rv = 0;\n\n  return rv;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_list_addonly_singlylinked_ordered/lfds711_list_addonly_singlylinked_ordered_init.c",
    "content": "/***** includes *****/\n#include \"lfds711_list_addonly_singlylinked_ordered_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_list_aso_init_valid_on_current_logical_core( struct lfds711_list_aso_state *lasos,\n                                                          int (*key_compare_function)(void const *new_key, void const *existing_key),\n                                                          enum lfds711_list_aso_existing_key existing_key,\n                                                          void *user_state )\n{\n  LFDS711_PAL_ASSERT( lasos != NULL );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &lasos->dummy_element % LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &lasos->start % LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 );\n  LFDS711_PAL_ASSERT( key_compare_function != NULL );\n  // TRD : existing_key can be any value in its range\n  // TRD : user_state can be NULL\n\n  // TRD : dummy start element - makes code easier when you can always use ->next\n  lasos->start = &lasos->dummy_element;\n\n  lasos->start->next = NULL;\n  lasos->start->value = NULL;\n  lasos->key_compare_function = key_compare_function;\n  lasos->existing_key = existing_key;\n  lasos->user_state = user_state;\n\n  lfds711_misc_internal_backoff_init( &lasos->insert_backoff );\n\n  LFDS711_MISC_BARRIER_STORE;\n\n  lfds711_misc_force_store();\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_list_addonly_singlylinked_ordered/lfds711_list_addonly_singlylinked_ordered_insert.c",
    "content": "/***** includes *****/\n#include \"lfds711_list_addonly_singlylinked_ordered_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nenum lfds711_list_aso_insert_result lfds711_list_aso_insert( struct lfds711_list_aso_state *lasos,\n                                                             struct lfds711_list_aso_element *lasoe,\n                                                             struct lfds711_list_aso_element **existing_lasoe )\n{\n  char unsigned \n    result;\n\n  enum lfds711_misc_flag\n    finished_flag = LFDS711_MISC_FLAG_LOWERED;\n\n  int\n    compare_result = 0;\n\n  lfds711_pal_uint_t\n    backoff_iteration = LFDS711_BACKOFF_INITIAL_VALUE;\n\n  struct lfds711_list_aso_element\n    *volatile lasoe_temp = NULL,\n    *volatile lasoe_trailing;\n\n  LFDS711_PAL_ASSERT( lasos != NULL );\n  LFDS711_PAL_ASSERT( lasoe != NULL );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &lasoe->next % LFDS711_PAL_ALIGN_SINGLE_POINTER == 0 );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &lasoe->value % LFDS711_PAL_ALIGN_SINGLE_POINTER == 0 );\n  // TRD : existing_lasoe can be NULL\n\n  /* TRD : imagine a list, sorted small to large\n\n           we arrive at an element\n           we obtain its next pointer\n           we check we are greater than the current element and smaller than the next element\n           this means we have found the correct location to insert\n           we try to CAS ourselves in; in the meantime,\n           someone else has *aready* swapped in an element which is smaller than we are\n\n           e.g.\n\n           the list is { 1, 10 } and we are the value 5\n\n           we arrive at 1; we check the next element and see it is 10\n           so we are larger than the current element and smaller than the next\n           we are in the correct location to insert and we go to insert...\n\n           in the meantime, someone else with the value 3 comes along\n           he too finds this is the correct location and inserts before we do\n           the list is now { 1, 3, 10 } and we are trying to insert now after\n           1 and before 3!\n\n           our insert CAS fails, because the next pointer of 1 has changed aready;\n           but we see we are in the wrong location - we need to move forward an\n           element\n  */\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  /* TRD : we need to begin with the leading dummy element\n           as the element to be inserted\n           may be smaller than all elements in the list\n  */\n\n  lasoe_trailing = lasos->start;\n  lasoe_temp = lasos->start->next;\n\n  while( finished_flag == LFDS711_MISC_FLAG_LOWERED )\n  {\n    if( lasoe_temp == NULL )\n      compare_result = -1;\n\n    if( lasoe_temp != NULL )\n    {\n      LFDS711_MISC_BARRIER_LOAD;\n      compare_result = lasos->key_compare_function( lasoe->key, lasoe_temp->key );\n    }\n\n    if( compare_result == 0 )\n    {\n      if( existing_lasoe != NULL )\n        *existing_lasoe = lasoe_temp;\n\n      switch( lasos->existing_key )\n      {\n        case LFDS711_LIST_ASO_EXISTING_KEY_OVERWRITE:\n          LFDS711_LIST_ASO_SET_VALUE_IN_ELEMENT( *lasoe_temp, lasoe->value );\n          return LFDS711_LIST_ASO_INSERT_RESULT_SUCCESS_OVERWRITE;\n        break;\n\n        case LFDS711_LIST_ASO_EXISTING_KEY_FAIL:\n          return LFDS711_LIST_ASO_INSERT_RESULT_FAILURE_EXISTING_KEY;\n        break;\n      }\n\n      finished_flag = LFDS711_MISC_FLAG_RAISED;\n    }\n\n    if( compare_result < 0 )\n    {\n      lasoe->next = lasoe_temp;\n      LFDS711_MISC_BARRIER_STORE;\n      LFDS711_PAL_ATOMIC_CAS( &lasoe_trailing->next, (struct lfds711_list_aso_element **) &lasoe->next, lasoe, LFDS711_MISC_CAS_STRENGTH_WEAK, result );\n\n      if( result == 1 )\n        finished_flag = LFDS711_MISC_FLAG_RAISED;\n      else\n      {\n        LFDS711_BACKOFF_EXPONENTIAL_BACKOFF( lasos->insert_backoff, backoff_iteration );\n        // TRD : if we fail to link, someone else has linked and so we need to redetermine our position is correct\n        lasoe_temp = lasoe_trailing->next;\n      }\n    }\n\n    if( compare_result > 0 )\n    {\n      // TRD : move trailing along by one element\n      lasoe_trailing = lasoe_trailing->next;\n\n      /* TRD : set temp as the element after trailing\n               if the new element we're linking is larger than all elements in the list,\n               lasoe_temp will now go to NULL and we'll link at the end\n      */\n      lasoe_temp = lasoe_trailing->next;\n    }\n  }\n\n  LFDS711_BACKOFF_AUTOTUNE( lasos->insert_backoff, backoff_iteration );\n\n  return LFDS711_LIST_ASO_INSERT_RESULT_SUCCESS;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_list_addonly_singlylinked_ordered/lfds711_list_addonly_singlylinked_ordered_internal.h",
    "content": "/***** the library wide include file *****/\n#include \"../liblfds711_internal.h\"\n\n/***** private prototypes *****/\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_list_addonly_singlylinked_ordered/lfds711_list_addonly_singlylinked_ordered_query.c",
    "content": "/***** includes *****/\n#include \"lfds711_list_addonly_singlylinked_ordered_internal.h\"\n\n/***** private prototypes *****/\nstatic void lfds711_list_aso_internal_validate( struct lfds711_list_aso_state *lasos,\n                                                struct lfds711_misc_validation_info *vi,\n                                                enum lfds711_misc_validity *lfds711_list_aso_validity );\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_list_aso_query( struct lfds711_list_aso_state *lasos,\n                             enum lfds711_list_aso_query query_type,\n                             void *query_input,\n                             void *query_output )\n{\n  LFDS711_PAL_ASSERT( lasos != NULL );\n  // TRD : query_type can be any value in its range\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  switch( query_type )\n  {\n    case LFDS711_LIST_ASO_QUERY_GET_POTENTIALLY_INACCURATE_COUNT:\n    {\n      struct lfds711_list_aso_element\n        *lasoe = NULL;\n\n      LFDS711_PAL_ASSERT( query_input == NULL );\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      *(lfds711_pal_uint_t *) query_output = 0;\n\n      while( LFDS711_LIST_ASO_GET_START_AND_THEN_NEXT(*lasos, lasoe) )\n        ( *(lfds711_pal_uint_t *) query_output )++;\n    }\n    break;\n\n    case LFDS711_LIST_ASO_QUERY_SINGLETHREADED_VALIDATE:\n      // TRD : query_input can be NULL\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      lfds711_list_aso_internal_validate( lasos, (struct lfds711_misc_validation_info *) query_input, (enum lfds711_misc_validity *) query_output );\n    break;\n  }\n\n  return;\n}\n\n\n\n\n\n\n/****************************************************************************/\nstatic void lfds711_list_aso_internal_validate( struct lfds711_list_aso_state *lasos,\n                                                struct lfds711_misc_validation_info *vi,\n                                                enum lfds711_misc_validity *lfds711_list_aso_validity )\n{\n  lfds711_pal_uint_t\n    number_elements = 0;\n\n  struct lfds711_list_aso_element\n    *lasoe_fast,\n    *lasoe_slow;\n\n  LFDS711_PAL_ASSERT( lasos!= NULL );\n  // TRD : vi can be NULL\n  LFDS711_PAL_ASSERT( lfds711_list_aso_validity != NULL );\n\n  *lfds711_list_aso_validity = LFDS711_MISC_VALIDITY_VALID;\n\n  lasoe_slow = lasoe_fast = lasos->start->next;\n\n  /* TRD : first, check for a loop\n           we have two pointers\n           both of which start at the start of the list\n           we enter a loop\n           and on each iteration\n           we advance one pointer by one element\n           and the other by two\n\n           we exit the loop when both pointers are NULL\n           (have reached the end of the queue)\n\n           or\n\n           if we fast pointer 'sees' the slow pointer\n           which means we have a loop\n  */\n\n  if( lasoe_slow != NULL )\n    do\n    {\n      lasoe_slow = lasoe_slow->next;\n\n      if( lasoe_fast != NULL )\n        lasoe_fast = lasoe_fast->next;\n\n      if( lasoe_fast != NULL )\n        lasoe_fast = lasoe_fast->next;\n    }\n    while( lasoe_slow != NULL and lasoe_fast != lasoe_slow );\n\n  if( lasoe_fast != NULL and lasoe_slow != NULL and lasoe_fast == lasoe_slow )\n    *lfds711_list_aso_validity = LFDS711_MISC_VALIDITY_INVALID_LOOP;\n\n  /* TRD : now check for expected number of elements\n           vi can be NULL, in which case we do not check\n           we know we don't have a loop from our earlier check\n  */\n\n  if( *lfds711_list_aso_validity == LFDS711_MISC_VALIDITY_VALID and vi != NULL )\n  {\n    lfds711_list_aso_query( lasos, LFDS711_LIST_ASO_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, &number_elements );\n\n    if( number_elements < vi->min_elements )\n      *lfds711_list_aso_validity = LFDS711_MISC_VALIDITY_INVALID_MISSING_ELEMENTS;\n\n    if( number_elements > vi->max_elements )\n      *lfds711_list_aso_validity = LFDS711_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS;\n  }\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_list_addonly_singlylinked_unordered/lfds711_list_addonly_singlylinked_unordered_cleanup.c",
    "content": "/***** includes *****/\n#include \"lfds711_list_addonly_singlylinked_unordered_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_list_asu_cleanup( struct lfds711_list_asu_state *lasus,\n                               void (*element_cleanup_callback)(struct lfds711_list_asu_state *lasus, struct lfds711_list_asu_element *lasue) )\n{\n  struct lfds711_list_asu_element\n    *lasue,\n    *temp;\n\n  LFDS711_PAL_ASSERT( lasus != NULL );\n  // TRD : element_cleanup_callback can be NULL\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  if( element_cleanup_callback == NULL )\n    return;\n\n  lasue = LFDS711_LIST_ASU_GET_START( *lasus );\n\n  while( lasue != NULL )\n  {\n    temp = lasue;\n\n    lasue = LFDS711_LIST_ASU_GET_NEXT( *lasue );\n\n    element_cleanup_callback( lasus, temp );\n  }\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_list_addonly_singlylinked_unordered/lfds711_list_addonly_singlylinked_unordered_get.c",
    "content": "/***** includes *****/\n#include \"lfds711_list_addonly_singlylinked_unordered_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nint lfds711_list_asu_get_by_key( struct lfds711_list_asu_state *lasus,\n                                 int (*key_compare_function)(void const *new_key, void const *existing_key),\n                                 void *key, \n                                 struct lfds711_list_asu_element **lasue )\n{\n  int\n    cr = !0,\n    rv = 1;\n\n  LFDS711_PAL_ASSERT( lasus != NULL );\n  LFDS711_PAL_ASSERT( key_compare_function != NULL );\n  // TRD : key can be NULL\n  LFDS711_PAL_ASSERT( lasue != NULL );\n\n  *lasue = NULL;\n\n  while( cr != 0 and LFDS711_LIST_ASU_GET_START_AND_THEN_NEXT(*lasus, *lasue) )\n    cr = key_compare_function( key, (*lasue)->key );\n\n  if( *lasue == NULL )\n    rv = 0;\n\n  return rv;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_list_addonly_singlylinked_unordered/lfds711_list_addonly_singlylinked_unordered_init.c",
    "content": "/***** includes *****/\n#include \"lfds711_list_addonly_singlylinked_unordered_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_list_asu_init_valid_on_current_logical_core( struct lfds711_list_asu_state *lasus,\n                                                          void *user_state )\n{\n  LFDS711_PAL_ASSERT( lasus != NULL );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &lasus->dummy_element % LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &lasus->end % LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &lasus->start % LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 );\n  // TRD : user_state can be NULL\n\n  // TRD : dummy start element - makes code easier when you can always use ->next\n  lasus->start = lasus->end = &lasus->dummy_element;\n\n  lasus->start->next = NULL;\n  lasus->start->value = NULL;\n  lasus->user_state = user_state;\n\n  lfds711_misc_internal_backoff_init( &lasus->after_backoff );\n  lfds711_misc_internal_backoff_init( &lasus->start_backoff );\n  lfds711_misc_internal_backoff_init( &lasus->end_backoff );\n\n  LFDS711_MISC_BARRIER_STORE;\n\n  lfds711_misc_force_store();\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_list_addonly_singlylinked_unordered/lfds711_list_addonly_singlylinked_unordered_insert.c",
    "content": "/***** includes *****/\n#include \"lfds711_list_addonly_singlylinked_unordered_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_list_asu_insert_at_position( struct lfds711_list_asu_state *lasus,\n                                          struct lfds711_list_asu_element *lasue,\n                                          struct lfds711_list_asu_element *lasue_predecessor,\n                                          enum lfds711_list_asu_position position )\n{\n  LFDS711_PAL_ASSERT( lasus != NULL );\n  LFDS711_PAL_ASSERT( lasue != NULL );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &lasue->next % LFDS711_PAL_ALIGN_SINGLE_POINTER == 0 );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &lasue->value % LFDS711_PAL_ALIGN_SINGLE_POINTER == 0 );\n  // TRD : lasue_predecessor asserted in the switch\n  // TRD : position can be any value in its range\n\n  switch( position )\n  {\n    case LFDS711_LIST_ASU_POSITION_START:\n      lfds711_list_asu_insert_at_start( lasus, lasue );\n    break;\n\n    case LFDS711_LIST_ASU_POSITION_END:\n      lfds711_list_asu_insert_at_end( lasus, lasue );\n    break;\n\n    case LFDS711_LIST_ASU_POSITION_AFTER:\n      lfds711_list_asu_insert_after_element( lasus, lasue, lasue_predecessor );\n    break;\n  }\n\n  return;\n}\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_list_asu_insert_at_start( struct lfds711_list_asu_state *lasus,\n                                       struct lfds711_list_asu_element *lasue )\n{\n  char unsigned \n    result;\n\n  lfds711_pal_uint_t\n    backoff_iteration = LFDS711_BACKOFF_INITIAL_VALUE;\n\n  LFDS711_PAL_ASSERT( lasus != NULL );\n  LFDS711_PAL_ASSERT( lasue != NULL );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &lasue->next % LFDS711_PAL_ALIGN_SINGLE_POINTER == 0 );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &lasue->value % LFDS711_PAL_ALIGN_SINGLE_POINTER == 0 );\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  lasue->next = lasus->start->next;\n\n  do\n  {\n    LFDS711_MISC_BARRIER_STORE;\n    LFDS711_PAL_ATOMIC_CAS( &lasus->start->next, (struct lfds711_list_asu_element **) &lasue->next, lasue, LFDS711_MISC_CAS_STRENGTH_WEAK, result );\n    if( result == 0 )\n      LFDS711_BACKOFF_EXPONENTIAL_BACKOFF( lasus->start_backoff, backoff_iteration );\n  }\n  while( result == 0 );\n\n  LFDS711_BACKOFF_AUTOTUNE( lasus->start_backoff, backoff_iteration );\n\n  return;\n}\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_list_asu_insert_at_end( struct lfds711_list_asu_state *lasus,\n                                     struct lfds711_list_asu_element *lasue )\n{\n  char unsigned \n    result;\n\n  enum lfds711_misc_flag\n    finished_flag = LFDS711_MISC_FLAG_LOWERED;\n\n  lfds711_pal_uint_t\n    backoff_iteration = LFDS711_BACKOFF_INITIAL_VALUE;\n\n  struct lfds711_list_asu_element LFDS711_PAL_ALIGN(LFDS711_PAL_ALIGN_SINGLE_POINTER)\n    *compare;\n\n  struct lfds711_list_asu_element\n    *volatile lasue_next,\n    *volatile lasue_end;\n\n  LFDS711_PAL_ASSERT( lasus != NULL );\n  LFDS711_PAL_ASSERT( lasue != NULL );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &lasue->next % LFDS711_PAL_ALIGN_SINGLE_POINTER == 0 );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &lasue->value % LFDS711_PAL_ALIGN_SINGLE_POINTER == 0 );\n\n  /* TRD : begin by assuming end is correctly pointing to the final element\n           try to link (comparing for next being NULL)\n           if we fail, move down list till we find last element\n           and retry\n           when successful, update end to ourselves\n\n           note there's a leading dummy element\n           so lasus->end always points to an element\n  */\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  lasue->next = NULL;\n  lasue_end = lasus->end;\n\n  while( finished_flag == LFDS711_MISC_FLAG_LOWERED )\n  {\n    compare = NULL;\n\n    LFDS711_MISC_BARRIER_STORE;\n    LFDS711_PAL_ATOMIC_CAS( &lasue_end->next, &compare, lasue, LFDS711_MISC_CAS_STRENGTH_STRONG, result );\n\n    if( result == 1 )\n      finished_flag = LFDS711_MISC_FLAG_RAISED;\n    else\n    {\n      LFDS711_BACKOFF_EXPONENTIAL_BACKOFF( lasus->end_backoff, backoff_iteration );\n\n      lasue_end = compare;\n      lasue_next = LFDS711_LIST_ASU_GET_NEXT( *lasue_end );\n\n      while( lasue_next != NULL )\n      {\n        lasue_end = lasue_next;\n        lasue_next = LFDS711_LIST_ASU_GET_NEXT( *lasue_end );\n      }\n    }\n  }\n\n  lasus->end = lasue;\n\n  LFDS711_BACKOFF_AUTOTUNE( lasus->end_backoff, backoff_iteration );\n\n  return;\n}\n\n\n\n\n\n/****************************************************************************/\n#pragma warning( disable : 4100 )\n\nvoid lfds711_list_asu_insert_after_element( struct lfds711_list_asu_state *lasus,\n                                            struct lfds711_list_asu_element *lasue,\n                                            struct lfds711_list_asu_element *lasue_predecessor )\n{\n  char unsigned \n    result;\n\n  lfds711_pal_uint_t\n    backoff_iteration = LFDS711_BACKOFF_INITIAL_VALUE;\n\n  LFDS711_PAL_ASSERT( lasus != NULL );\n  LFDS711_PAL_ASSERT( lasue != NULL );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &lasue->next % LFDS711_PAL_ALIGN_SINGLE_POINTER == 0 );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &lasue->value % LFDS711_PAL_ALIGN_SINGLE_POINTER == 0 );\n  LFDS711_PAL_ASSERT( lasue_predecessor != NULL );\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  lasue->next = lasue_predecessor->next;\n\n  do\n  {\n    LFDS711_MISC_BARRIER_STORE;\n    LFDS711_PAL_ATOMIC_CAS( &lasue_predecessor->next, (struct lfds711_list_asu_element **) &lasue->next, lasue, LFDS711_MISC_CAS_STRENGTH_WEAK, result );\n    if( result == 0 )\n      LFDS711_BACKOFF_EXPONENTIAL_BACKOFF( lasus->after_backoff, backoff_iteration );\n  }\n  while( result == 0 );\n\n  LFDS711_BACKOFF_AUTOTUNE( lasus->after_backoff, backoff_iteration );\n\n  return;\n}\n\n#pragma warning( default : 4100 )\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_list_addonly_singlylinked_unordered/lfds711_list_addonly_singlylinked_unordered_internal.h",
    "content": "/***** the library wide include file *****/\n#include \"../liblfds711_internal.h\"\n\n/***** private prototypes *****/\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_list_addonly_singlylinked_unordered/lfds711_list_addonly_singlylinked_unordered_query.c",
    "content": "/***** includes *****/\n#include \"lfds711_list_addonly_singlylinked_unordered_internal.h\"\n\n/***** private prototypes *****/\nstatic void lfds711_list_asu_internal_validate( struct lfds711_list_asu_state *lasus,\n                                                struct lfds711_misc_validation_info *vi,\n                                                enum lfds711_misc_validity *lfds711_list_asu_validity );\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_list_asu_query( struct lfds711_list_asu_state *lasus,\n                             enum lfds711_list_asu_query query_type,\n                             void *query_input,\n                             void *query_output )\n{\n  LFDS711_PAL_ASSERT( lasus != NULL );\n  // TRD : query_type can be any value in its range\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  switch( query_type )\n  {\n    case LFDS711_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT:\n    {\n      struct lfds711_list_asu_element\n        *lasue = NULL;\n\n      LFDS711_PAL_ASSERT( query_input == NULL );\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      *(lfds711_pal_uint_t *) query_output = 0;\n\n      while( LFDS711_LIST_ASU_GET_START_AND_THEN_NEXT(*lasus, lasue) )\n        ( *(lfds711_pal_uint_t *) query_output )++;\n    }\n    break;\n\n    case LFDS711_LIST_ASU_QUERY_SINGLETHREADED_VALIDATE:\n      // TRD : query_input can be NULL\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      lfds711_list_asu_internal_validate( lasus, (struct lfds711_misc_validation_info *) query_input, (enum lfds711_misc_validity *) query_output );\n    break;\n  }\n\n  return;\n}\n\n\n\n\n\n\n/****************************************************************************/\nstatic void lfds711_list_asu_internal_validate( struct lfds711_list_asu_state *lasus,\n                                                struct lfds711_misc_validation_info *vi,\n                                                enum lfds711_misc_validity *lfds711_list_asu_validity )\n{\n  lfds711_pal_uint_t\n    number_elements = 0;\n\n  struct lfds711_list_asu_element\n    *lasue_fast,\n    *lasue_slow;\n\n  LFDS711_PAL_ASSERT( lasus!= NULL );\n  // TRD : vi can be NULL\n  LFDS711_PAL_ASSERT( lfds711_list_asu_validity != NULL );\n\n  *lfds711_list_asu_validity = LFDS711_MISC_VALIDITY_VALID;\n\n  lasue_slow = lasue_fast = lasus->start->next;\n\n  /* TRD : first, check for a loop\n           we have two pointers\n           both of which start at the start of the list\n           we enter a loop\n           and on each iteration\n           we advance one pointer by one element\n           and the other by two\n\n           we exit the loop when both pointers are NULL\n           (have reached the end of the queue)\n\n           or\n\n           if we fast pointer 'sees' the slow pointer\n           which means we have a loop\n  */\n\n  if( lasue_slow != NULL )\n    do\n    {\n      lasue_slow = lasue_slow->next;\n\n      if( lasue_fast != NULL )\n        lasue_fast = lasue_fast->next;\n\n      if( lasue_fast != NULL )\n        lasue_fast = lasue_fast->next;\n    }\n    while( lasue_slow != NULL and lasue_fast != lasue_slow );\n\n  if( lasue_fast != NULL and lasue_slow != NULL and lasue_fast == lasue_slow )\n    *lfds711_list_asu_validity = LFDS711_MISC_VALIDITY_INVALID_LOOP;\n\n  /* TRD : now check for expected number of elements\n           vi can be NULL, in which case we do not check\n           we know we don't have a loop from our earlier check\n  */\n\n  if( *lfds711_list_asu_validity == LFDS711_MISC_VALIDITY_VALID and vi != NULL )\n  {\n    lfds711_list_asu_query( lasus, LFDS711_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, &number_elements );\n\n    if( number_elements < vi->min_elements )\n      *lfds711_list_asu_validity = LFDS711_MISC_VALIDITY_INVALID_MISSING_ELEMENTS;\n\n    if( number_elements > vi->max_elements )\n      *lfds711_list_asu_validity = LFDS711_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS;\n  }\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_misc/lfds711_misc_globals.c",
    "content": "/***** includes *****/\n#include \"lfds711_misc_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nstruct lfds711_misc_globals\n  lfds711_misc_globals = \n  {\n    { LFDS711_PRNG_SEED }\n  };\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_misc/lfds711_misc_internal.h",
    "content": "/***** the library wide include file *****/\n#include \"../liblfds711_internal.h\"\n\n/***** private prototypes *****/\nvoid lfds711_misc_prng_internal_big_slow_high_quality_init( int long long unsigned seed );\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_misc/lfds711_misc_internal_backoff_init.c",
    "content": "/***** includes *****/\n#include \"lfds711_misc_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_misc_internal_backoff_init( struct lfds711_misc_backoff_state *bs )\n{\n  LFDS711_PAL_ASSERT( bs != NULL );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &bs->lock % LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 );\n\n  bs->lock = LFDS711_MISC_FLAG_LOWERED;\n  bs->backoff_iteration_frequency_counters[0] = 0;\n  bs->backoff_iteration_frequency_counters[1] = 0;\n  bs->metric = 1;\n  bs->total_operations = 0;\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_misc/lfds711_misc_query.c",
    "content": "/***** includes *****/\n#include \"lfds711_misc_internal.h\"\n\n\n\n\n\n/****************************************************************************/\n#pragma warning( disable : 4100 )\n\nvoid lfds711_misc_query( enum lfds711_misc_query query_type,\n                         void *query_input,\n                         void *query_output )\n{\n  // TRD : query type can be any value in its range\n  // TRD : query_input can be NULL in some cases\n  // TRD : query_outputput can be NULL in some cases\n\n  switch( query_type )\n  {\n    case LFDS711_MISC_QUERY_GET_BUILD_AND_VERSION_STRING:\n    {\n      char static const\n        * const build_and_version_string = \"liblfds \" LFDS711_MISC_VERSION_STRING \" (\" BUILD_TYPE_STRING \", \" LFDS711_PAL_OS_STRING \", \" MODE_TYPE_STRING \", \" LFDS711_PAL_PROCESSOR_STRING \", \" LFDS711_PAL_COMPILER_STRING \")\";\n\n      LFDS711_PAL_ASSERT( query_input == NULL );\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      *(char const **) query_output = build_and_version_string;\n    }\n    break;\n  }\n\n  return;\n}\n\n#pragma warning( default : 4100 )\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_prng/lfds711_prng_init.c",
    "content": "/***** includes *****/\n#include \"lfds711_prng_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_prng_init_valid_on_current_logical_core( struct lfds711_prng_state *ps, lfds711_pal_uint_t seed )\n{\n  LFDS711_PAL_ASSERT( ps != NULL );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &ps->entropy % LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 );\n  // TRD : seed can be any value in its range (unlike for the mixing function)\n\n  LFDS711_PRNG_ST_MIXING_FUNCTION( seed );\n\n  ps->entropy = seed;\n\n  LFDS711_MISC_BARRIER_STORE;\n\n  lfds711_misc_force_store();\n\n  return;\n}\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_prng_st_init( struct lfds711_prng_st_state *psts, lfds711_pal_uint_t seed )\n{\n  LFDS711_PAL_ASSERT( psts != NULL );\n  LFDS711_PAL_ASSERT( seed != 0 );\n\n  LFDS711_PRNG_ST_MIXING_FUNCTION( seed );\n\n  psts->entropy = seed;\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_prng/lfds711_prng_internal.h",
    "content": "/***** the library wide include file *****/\n#include \"../liblfds711_internal.h\"\n\n/***** private prototypes *****/\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_queue_bounded_manyproducer_manyconsumer/lfds711_queue_bounded_manyproducer_manyconsumer_cleanup.c",
    "content": "/***** includes *****/\n#include \"lfds711_queue_bounded_manyproducer_manyconsumer_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_queue_bmm_cleanup( struct lfds711_queue_bmm_state *qbmms,\n                                void (*element_cleanup_callback)(struct lfds711_queue_bmm_state *qbmms, void *key, void *value) )\n{\n  void\n    *key,\n    *value;\n\n  LFDS711_PAL_ASSERT( qbmms != NULL );\n  // TRD : element_cleanup_callback can be NULL\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  if( element_cleanup_callback != NULL )\n    while( lfds711_queue_bmm_dequeue(qbmms,&key,&value) )\n      element_cleanup_callback( qbmms, key, value );\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_queue_bounded_manyproducer_manyconsumer/lfds711_queue_bounded_manyproducer_manyconsumer_dequeue.c",
    "content": "/***** includes *****/\n#include \"lfds711_queue_bounded_manyproducer_manyconsumer_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nint lfds711_queue_bmm_dequeue( struct lfds711_queue_bmm_state *qbmms,\n                               void **key,\n                               void **value )\n{\n  char unsigned\n    result;\n\n  enum lfds711_misc_flag\n    finished_flag = LFDS711_MISC_FLAG_LOWERED;\n\n  int\n    rv = 1;\n\n  lfds711_pal_uint_t\n    read_index,\n    sequence_number;\n\n  lfds711_pal_int_t\n    difference;\n\n  lfds711_pal_uint_t\n    backoff_iteration = LFDS711_BACKOFF_INITIAL_VALUE;\n\n  struct lfds711_queue_bmm_element\n    *qbmme = NULL;\n\n  LFDS711_PAL_ASSERT( qbmms != NULL );\n  // TRD : key can be NULL\n  // TRD : value can be NULL\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  read_index = qbmms->read_index;\n\n  while( finished_flag == LFDS711_MISC_FLAG_LOWERED )\n  {\n    qbmme = &qbmms->element_array[ read_index & qbmms->mask ];\n    LFDS711_MISC_BARRIER_LOAD;\n    sequence_number = qbmme->sequence_number;\n    difference = (lfds711_pal_int_t) sequence_number - (lfds711_pal_int_t) (read_index + 1);\n\n    if( difference == 0 )\n    {\n      LFDS711_PAL_ATOMIC_CAS( &qbmms->read_index, &read_index, read_index + 1, LFDS711_MISC_CAS_STRENGTH_WEAK, result );\n      if( result == 0 )\n        LFDS711_BACKOFF_EXPONENTIAL_BACKOFF( qbmms->dequeue_backoff, backoff_iteration );\n      if( result == 1 )\n        finished_flag = LFDS711_MISC_FLAG_RAISED;\n    }\n\n    if( difference < 0 )\n    {\n      rv = 0;\n      finished_flag = LFDS711_MISC_FLAG_RAISED;\n    }\n\n    if( difference > 0 )\n    {\n      LFDS711_MISC_BARRIER_LOAD;\n      read_index = qbmms->read_index;\n    }\n  }\n\n  if( rv == 1 )\n  {\n    if( key != NULL )\n      *key = qbmme->key;\n    if( value != NULL )\n      *value = qbmme->value;\n    LFDS711_MISC_BARRIER_STORE;\n    qbmme->sequence_number = read_index + qbmms->mask + 1;\n  }\n\n  LFDS711_BACKOFF_AUTOTUNE( qbmms->dequeue_backoff, backoff_iteration );\n\n  return rv;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_queue_bounded_manyproducer_manyconsumer/lfds711_queue_bounded_manyproducer_manyconsumer_enqueue.c",
    "content": "/***** includes *****/\n#include \"lfds711_queue_bounded_manyproducer_manyconsumer_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nint lfds711_queue_bmm_enqueue( struct lfds711_queue_bmm_state *qbmms,\n                               void *key,\n                               void *value )\n{\n  char unsigned\n    result;\n\n  enum lfds711_misc_flag\n    finished_flag = LFDS711_MISC_FLAG_LOWERED;\n\n  int\n    rv = 1;\n\n  lfds711_pal_uint_t\n    sequence_number,\n    write_index;\n\n  lfds711_pal_int_t\n    difference;\n\n  lfds711_pal_uint_t\n    backoff_iteration = LFDS711_BACKOFF_INITIAL_VALUE;\n\n  struct lfds711_queue_bmm_element\n    *qbmme = NULL;\n\n  LFDS711_PAL_ASSERT( qbmms != NULL );\n  // TRD : key can be NULL\n  // TRD : value can be NULL\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  write_index = qbmms->write_index;\n\n  while( finished_flag == LFDS711_MISC_FLAG_LOWERED )\n  {\n    qbmme = &qbmms->element_array[ write_index & qbmms->mask ];\n    LFDS711_MISC_BARRIER_LOAD;\n    sequence_number = qbmme->sequence_number;\n    difference = (lfds711_pal_int_t) sequence_number - (lfds711_pal_int_t) write_index;\n\n    if( difference == 0 )\n    {\n      LFDS711_PAL_ATOMIC_CAS( &qbmms->write_index, &write_index, write_index + 1, LFDS711_MISC_CAS_STRENGTH_WEAK, result );\n      if( result == 0 )\n        LFDS711_BACKOFF_EXPONENTIAL_BACKOFF( qbmms->enqueue_backoff, backoff_iteration );\n      if( result == 1 )\n        finished_flag = LFDS711_MISC_FLAG_RAISED;\n    }\n\n    if( difference < 0 )\n    {\n      rv = 0;\n      finished_flag = LFDS711_MISC_FLAG_RAISED;\n    }\n\n    if( difference > 0 )\n    {\n      LFDS711_MISC_BARRIER_LOAD;\n      write_index = qbmms->write_index;\n    }\n  }\n\n  if( rv == 1 )\n  {\n    qbmme->key = key;\n    qbmme->value = value;\n    LFDS711_MISC_BARRIER_STORE;\n    qbmme->sequence_number = write_index + 1;\n  }\n\n  LFDS711_BACKOFF_AUTOTUNE( qbmms->enqueue_backoff, backoff_iteration );\n\n  return rv;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_queue_bounded_manyproducer_manyconsumer/lfds711_queue_bounded_manyproducer_manyconsumer_init.c",
    "content": "/***** includes *****/\n#include \"lfds711_queue_bounded_manyproducer_manyconsumer_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_queue_bmm_init_valid_on_current_logical_core( struct lfds711_queue_bmm_state *qbmms,\n                                                           struct lfds711_queue_bmm_element *element_array,\n                                                           lfds711_pal_uint_t number_elements,\n                                                           void *user_state )\n{\n  lfds711_pal_uint_t\n    loop;\n\n  LFDS711_PAL_ASSERT( qbmms != NULL );\n  LFDS711_PAL_ASSERT( element_array != NULL );\n  LFDS711_PAL_ASSERT( number_elements >= 2 );\n  LFDS711_PAL_ASSERT( ( number_elements & (number_elements-1) ) == 0 ); // TRD : number_elements must be a positive integer power of 2\n  // TRD : user_state can be NULL\n\n  qbmms->number_elements = number_elements;\n  qbmms->mask = qbmms->number_elements - 1;\n  qbmms->read_index = 0;\n  qbmms->write_index = 0;\n  qbmms->element_array = element_array;\n  qbmms->user_state = user_state;\n\n  for( loop = 0 ; loop < qbmms->number_elements ; loop++ )\n    qbmms->element_array[loop].sequence_number = loop;\n\n  lfds711_misc_internal_backoff_init( &qbmms->dequeue_backoff );\n  lfds711_misc_internal_backoff_init( &qbmms->enqueue_backoff );\n\n  LFDS711_MISC_BARRIER_STORE;\n\n  lfds711_misc_force_store();\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_queue_bounded_manyproducer_manyconsumer/lfds711_queue_bounded_manyproducer_manyconsumer_internal.h",
    "content": "/***** the library wide include file *****/\n#include \"../liblfds711_internal.h\"\n\n/***** private prototypes *****/\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_queue_bounded_manyproducer_manyconsumer/lfds711_queue_bounded_manyproducer_manyconsumer_query.c",
    "content": "/***** includes *****/\n#include \"lfds711_queue_bounded_manyproducer_manyconsumer_internal.h\"\n\n/***** private prototypes *****/\nstatic void lfds711_queue_bmm_internal_validate( struct lfds711_queue_bmm_state *qbmms,\n                                                 struct lfds711_misc_validation_info *vi,\n                                                 enum lfds711_misc_validity *lfds711_validity );\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_queue_bmm_query( struct lfds711_queue_bmm_state *qbmms,\n                              enum lfds711_queue_bmm_query query_type,\n                              void *query_input,\n                              void *query_output )\n{\n  LFDS711_PAL_ASSERT( qbmms != NULL );\n  // TRD : query_type can be any value in its range\n\n  switch( query_type )\n  {\n    case LFDS711_QUEUE_BMM_QUERY_GET_POTENTIALLY_INACCURATE_COUNT:\n    {\n      lfds711_pal_uint_t\n        local_read_index,\n        local_write_index;\n\n      LFDS711_PAL_ASSERT( query_input == NULL );\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      LFDS711_MISC_BARRIER_LOAD;\n\n      local_read_index = qbmms->read_index;\n      local_write_index = qbmms->write_index;\n\n      *(lfds711_pal_uint_t *) query_output = +( local_write_index - local_read_index );\n\n      if( local_read_index > local_write_index )\n        *(lfds711_pal_uint_t *) query_output = ((lfds711_pal_uint_t) -1) - *(lfds711_pal_uint_t *) query_output;\n    }\n    break;\n\n    case LFDS711_QUEUE_BMM_QUERY_SINGLETHREADED_VALIDATE:\n      // TRD : query_input can be NULL\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      lfds711_queue_bmm_internal_validate( qbmms, (struct lfds711_misc_validation_info *) query_input, (enum lfds711_misc_validity *) query_output );\n    break;\n  }\n\n  return;\n}\n\n\n\n\n\n/****************************************************************************/\nstatic void lfds711_queue_bmm_internal_validate( struct lfds711_queue_bmm_state *qbmms,\n                                                 struct lfds711_misc_validation_info *vi,\n                                                 enum lfds711_misc_validity *lfds711_validity )\n{\n  lfds711_pal_uint_t\n    expected_sequence_number,\n    loop,\n    number_elements,\n    sequence_number;\n\n  LFDS711_PAL_ASSERT( qbmms != NULL );\n  // TRD : vi can be NULL\n  LFDS711_PAL_ASSERT( lfds711_validity != NULL );\n\n  *lfds711_validity = LFDS711_MISC_VALIDITY_VALID;\n\n  /* TRD : starting from the read_index, we should find number_elements of incrementing sequence numbers\n           we then perform a second scan from the write_index onwards, which should have (max elements in queue - number_elements) incrementing sequence numbers\n  */\n\n  lfds711_queue_bmm_query( qbmms, LFDS711_QUEUE_BMM_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void *) &number_elements );\n\n  expected_sequence_number = qbmms->element_array[ qbmms->read_index & qbmms->mask ].sequence_number;\n\n  for( loop = 0 ; loop < number_elements ; loop++ )\n  {\n    sequence_number = qbmms->element_array[ (qbmms->read_index + loop) & qbmms->mask ].sequence_number;\n\n    if( sequence_number != expected_sequence_number )\n      *lfds711_validity = LFDS711_MISC_VALIDITY_INVALID_ORDER;\n\n    if( sequence_number == expected_sequence_number )\n      expected_sequence_number = sequence_number + 1;\n  }\n\n  // TRD : now the write_index onwards\n\n  expected_sequence_number = qbmms->element_array[ qbmms->write_index & qbmms->mask ].sequence_number;\n\n  for( loop = 0 ; loop < qbmms->number_elements - number_elements ; loop++ )\n  {\n    sequence_number = qbmms->element_array[ (qbmms->write_index + loop) & qbmms->mask ].sequence_number;\n\n    if( sequence_number != expected_sequence_number )\n      *lfds711_validity = LFDS711_MISC_VALIDITY_INVALID_ORDER;\n\n    if( sequence_number == expected_sequence_number )\n      expected_sequence_number = sequence_number + 1;\n  }\n\n  // TRD : now check against the expected number of elements\n\n  if( *lfds711_validity == LFDS711_MISC_VALIDITY_VALID and vi != NULL )\n  {\n    lfds711_pal_uint_t\n      number_elements;\n\n    lfds711_queue_bmm_query( qbmms, LFDS711_QUEUE_BMM_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void *) &number_elements );\n\n    if( number_elements < vi->min_elements )\n      *lfds711_validity = LFDS711_MISC_VALIDITY_INVALID_MISSING_ELEMENTS;\n\n    if( number_elements > vi->max_elements )\n      *lfds711_validity = LFDS711_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS;\n  }\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_queue_bounded_singleproducer_singleconsumer/lfds711_queue_bounded_singleproducer_singleconsumer_cleanup.c",
    "content": "/***** includes *****/\n#include \"lfds711_queue_bounded_singleproducer_singleconsumer_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_queue_bss_cleanup( struct lfds711_queue_bss_state *qbsss,\n                                void (*element_cleanup_callback)(struct lfds711_queue_bss_state *qbsss, void *key, void *value) )\n{\n  lfds711_pal_uint_t\n    loop;\n\n  struct lfds711_queue_bss_element\n    *qbsse;\n\n  LFDS711_PAL_ASSERT( qbsss != NULL );\n  // TRD : element_cleanup_callback can be NULL\n\n  if( element_cleanup_callback != NULL )\n    for( loop = qbsss->read_index ; loop < qbsss->read_index + qbsss->number_elements ; loop++ )\n    {\n      qbsse = qbsss->element_array + (loop % qbsss->number_elements);\n      element_cleanup_callback( qbsss, qbsse->key, qbsse->value );\n    }\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_queue_bounded_singleproducer_singleconsumer/lfds711_queue_bounded_singleproducer_singleconsumer_dequeue.c",
    "content": "/***** includes *****/\n#include \"lfds711_queue_bounded_singleproducer_singleconsumer_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nint lfds711_queue_bss_dequeue( struct lfds711_queue_bss_state *qbsss,\n                               void **key,\n                               void **value )\n{\n  struct lfds711_queue_bss_element\n    *qbsse;\n\n  LFDS711_PAL_ASSERT( qbsss != NULL );\n  // TRD : key can be NULL\n  // TRD : value can be NULL\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  if( qbsss->read_index != qbsss->write_index )\n  {\n    qbsse = qbsss->element_array + qbsss->read_index;\n\n    if( key != NULL )\n      *key = qbsse->key;\n\n    if( value != NULL )\n      *value = qbsse->value;\n\n    qbsss->read_index = (qbsss->read_index + 1) & qbsss->mask;\n\n    LFDS711_MISC_BARRIER_STORE;\n\n    return 1;\n  }\n\n  return 0;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_queue_bounded_singleproducer_singleconsumer/lfds711_queue_bounded_singleproducer_singleconsumer_enqueue.c",
    "content": "/***** includes *****/\n#include \"lfds711_queue_bounded_singleproducer_singleconsumer_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nint lfds711_queue_bss_enqueue( struct lfds711_queue_bss_state *qbsss,\n                               void *key,\n                               void *value )\n{\n  struct lfds711_queue_bss_element\n    *qbsse;\n\n  LFDS711_PAL_ASSERT( qbsss != NULL );\n  // TRD : key can be NULL\n  // TRD : value can be NULL\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  if( ( (qbsss->write_index+1) & qbsss->mask ) != qbsss->read_index )\n  {\n    qbsse = qbsss->element_array + qbsss->write_index;\n\n    qbsse->key = key;\n    qbsse->value = value;\n\n    LFDS711_MISC_BARRIER_STORE;\n\n    qbsss->write_index = (qbsss->write_index + 1) & qbsss->mask;\n\n    return 1;\n  }\n\n  return 0;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_queue_bounded_singleproducer_singleconsumer/lfds711_queue_bounded_singleproducer_singleconsumer_enqueue.ll",
    "content": "; ModuleID = 'lfds711_queue_bounded_singleproducer_singleconsumer_enqueue.c'\nsource_filename = \"lfds711_queue_bounded_singleproducer_singleconsumer_enqueue.c\"\ntarget datalayout = \"e-m:e-i64:64-f80:128-n8:16:32:64-S128\"\ntarget triple = \"x86_64-pc-linux-gnu\"\n\n%struct.lfds711_queue_bss_state = type { i64, i64, i64, i64, %struct.lfds711_queue_bss_element*, i8* }\n%struct.lfds711_queue_bss_element = type { i8*, i8* }\n\n; Function Attrs: noinline nounwind optnone sspstrong uwtable\ndefine dso_local i32 @lfds711_queue_bss_enqueue(%struct.lfds711_queue_bss_state*, i8*, i8*) #0 {\n  %4 = alloca i32, align 4\n  %5 = alloca %struct.lfds711_queue_bss_state*, align 8\n  %6 = alloca i8*, align 8\n  %7 = alloca i8*, align 8\n  %8 = alloca %struct.lfds711_queue_bss_element*, align 8\n  %9 = alloca i8*, align 8\n  store %struct.lfds711_queue_bss_state* %0, %struct.lfds711_queue_bss_state** %5, align 8\n  store i8* %1, i8** %6, align 8\n  store i8* %2, i8** %7, align 8\n  %10 = load %struct.lfds711_queue_bss_state*, %struct.lfds711_queue_bss_state** %5, align 8\n  %11 = icmp ne %struct.lfds711_queue_bss_state* %10, null\n  br i1 %11, label %14, label %12\n\n12:                                               ; preds = %3\n  store i8* null, i8** %9, align 8\n  %13 = load i8*, i8** %9, align 8\n  store i8 0, i8* %13, align 1\n  br label %14\n\n14:                                               ; preds = %12, %3\n  call void @lfds711_pal_barrier_compiler()\n  fence seq_cst\n  call void @lfds711_pal_barrier_compiler()\n  %15 = load %struct.lfds711_queue_bss_state*, %struct.lfds711_queue_bss_state** %5, align 8\n  %16 = getelementptr inbounds %struct.lfds711_queue_bss_state, %struct.lfds711_queue_bss_state* %15, i32 0, i32 3\n  %17 = load volatile i64, i64* %16, align 8\n  %18 = add i64 %17, 1\n  %19 = load %struct.lfds711_queue_bss_state*, %struct.lfds711_queue_bss_state** %5, align 8\n  %20 = getelementptr inbounds %struct.lfds711_queue_bss_state, %struct.lfds711_queue_bss_state* %19, i32 0, i32 1\n  %21 = load i64, i64* %20, align 8\n  %22 = and i64 %18, %21\n  %23 = load %struct.lfds711_queue_bss_state*, %struct.lfds711_queue_bss_state** %5, align 8\n  %24 = getelementptr inbounds %struct.lfds711_queue_bss_state, %struct.lfds711_queue_bss_state* %23, i32 0, i32 2\n  %25 = load volatile i64, i64* %24, align 8\n  %26 = icmp ne i64 %22, %25\n  br i1 %26, label %27, label %51\n\n27:                                               ; preds = %14\n  %28 = load %struct.lfds711_queue_bss_state*, %struct.lfds711_queue_bss_state** %5, align 8\n  %29 = getelementptr inbounds %struct.lfds711_queue_bss_state, %struct.lfds711_queue_bss_state* %28, i32 0, i32 4\n  %30 = load %struct.lfds711_queue_bss_element*, %struct.lfds711_queue_bss_element** %29, align 8\n  %31 = load %struct.lfds711_queue_bss_state*, %struct.lfds711_queue_bss_state** %5, align 8\n  %32 = getelementptr inbounds %struct.lfds711_queue_bss_state, %struct.lfds711_queue_bss_state* %31, i32 0, i32 3\n  %33 = load volatile i64, i64* %32, align 8\n  %34 = getelementptr inbounds %struct.lfds711_queue_bss_element, %struct.lfds711_queue_bss_element* %30, i64 %33\n  store %struct.lfds711_queue_bss_element* %34, %struct.lfds711_queue_bss_element** %8, align 8\n  %35 = load i8*, i8** %6, align 8\n  %36 = load %struct.lfds711_queue_bss_element*, %struct.lfds711_queue_bss_element** %8, align 8\n  %37 = getelementptr inbounds %struct.lfds711_queue_bss_element, %struct.lfds711_queue_bss_element* %36, i32 0, i32 0\n  store volatile i8* %35, i8** %37, align 8\n  %38 = load i8*, i8** %7, align 8\n  %39 = load %struct.lfds711_queue_bss_element*, %struct.lfds711_queue_bss_element** %8, align 8\n  %40 = getelementptr inbounds %struct.lfds711_queue_bss_element, %struct.lfds711_queue_bss_element* %39, i32 0, i32 1\n  store volatile i8* %38, i8** %40, align 8\n  call void @lfds711_pal_barrier_compiler()\n  fence seq_cst\n  call void @lfds711_pal_barrier_compiler()\n  %41 = load %struct.lfds711_queue_bss_state*, %struct.lfds711_queue_bss_state** %5, align 8\n  %42 = getelementptr inbounds %struct.lfds711_queue_bss_state, %struct.lfds711_queue_bss_state* %41, i32 0, i32 3\n  %43 = load volatile i64, i64* %42, align 8\n  %44 = add i64 %43, 1\n  %45 = load %struct.lfds711_queue_bss_state*, %struct.lfds711_queue_bss_state** %5, align 8\n  %46 = getelementptr inbounds %struct.lfds711_queue_bss_state, %struct.lfds711_queue_bss_state* %45, i32 0, i32 1\n  %47 = load i64, i64* %46, align 8\n  %48 = and i64 %44, %47\n  %49 = load %struct.lfds711_queue_bss_state*, %struct.lfds711_queue_bss_state** %5, align 8\n  %50 = getelementptr inbounds %struct.lfds711_queue_bss_state, %struct.lfds711_queue_bss_state* %49, i32 0, i32 3\n  store volatile i64 %48, i64* %50, align 8\n  store i32 1, i32* %4, align 4\n  br label %52\n\n51:                                               ; preds = %14\n  store i32 0, i32* %4, align 4\n  br label %52\n\n52:                                               ; preds = %51, %27\n  %53 = load i32, i32* %4, align 4\n  ret i32 %53\n}\n\n; Function Attrs: noinline nounwind optnone sspstrong uwtable\ndefine internal void @lfds711_pal_barrier_compiler() #0 {\n  call void asm sideeffect \"\", \"~{memory},~{dirflag},~{fpsr},~{flags}\"() #1, !srcloc !4\n  ret void\n}\n\nattributes #0 = { noinline nounwind optnone sspstrong uwtable \"correctly-rounded-divide-sqrt-fp-math\"=\"false\" \"disable-tail-calls\"=\"false\" \"less-precise-fpmad\"=\"false\" \"min-legal-vector-width\"=\"0\" \"no-frame-pointer-elim\"=\"true\" \"no-frame-pointer-elim-non-leaf\" \"no-infs-fp-math\"=\"false\" \"no-jump-tables\"=\"false\" \"no-nans-fp-math\"=\"false\" \"no-signed-zeros-fp-math\"=\"false\" \"no-trapping-math\"=\"false\" \"stack-protector-buffer-size\"=\"8\" \"target-cpu\"=\"x86-64\" \"target-features\"=\"+cx8,+fxsr,+mmx,+sse,+sse2,+x87\" \"unsafe-fp-math\"=\"false\" \"use-soft-float\"=\"false\" }\nattributes #1 = { nounwind }\n\n!llvm.module.flags = !{!0, !1, !2}\n!llvm.ident = !{!3}\n\n!0 = !{i32 1, !\"wchar_size\", i32 4}\n!1 = !{i32 7, !\"PIC Level\", i32 2}\n!2 = !{i32 7, !\"PIE Level\", i32 2}\n!3 = !{!\"clang version 9.0.1 \"}\n!4 = !{i32 51241}\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_queue_bounded_singleproducer_singleconsumer/lfds711_queue_bounded_singleproducer_singleconsumer_init.c",
    "content": "/***** includes *****/\n#include \"lfds711_queue_bounded_singleproducer_singleconsumer_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_queue_bss_init_valid_on_current_logical_core( struct lfds711_queue_bss_state *qbsss,\n                                                           struct lfds711_queue_bss_element *element_array,\n                                                           lfds711_pal_uint_t number_elements,\n                                                           void *user_state )\n{\n  LFDS711_PAL_ASSERT( qbsss != NULL );\n  LFDS711_PAL_ASSERT( element_array != NULL );\n  LFDS711_PAL_ASSERT( number_elements >= 2 );\n  LFDS711_PAL_ASSERT( ( number_elements & (number_elements-1) ) == 0 ); // TRD : number_elements must be a positive integer power of 2\n  // TRD : user_state can be NULL\n\n  /* TRD : the use of mask and the restriction on a power of two\n           upon the number of elements bears some remark\n\n           in this queue, there are a fixed number of elements\n           we have a read index and a write index\n           when we write, and thre is space to write, we increment the write index\n           (if no space to write, we just return)\n           when we read, and there are elements to be read, we after reading increment the read index\n           (if no elements to read, we just return)\n           the problem is - how do we handle wrap around?\n           e.g. when I write, but my write index is now equal to the number of elements\n           the usual solution is to modulus the write index by the nunmber of elements\n           problem is modulus is slow\n           there is a better way\n           first, we restrict the number of elements to be a power of two\n           so imagine we have a 64-bit system and we set the number of elements to be 2^64\n           this gives us a bit pattern of 1000 0000 0000 0000 (...etc, lots of zeros)\n           now (just roll with this for a bit) subtract one from this\n           this gives us a mask (on a two's compliment machine)\n           0111 1111 1111 1111 (...etc, lots of ones)\n           so what we do now, when we increment an index (think of the write index as the example)\n           we bitwise and it with the mask\n           now think about thwt happens\n           all the numbers up to 2^64 will be unchanged - their MSB is never set, and we and with all the other bits\n           but when we finally hit 2^64 and need to roll over... bingo!\n           we drop MSB (which we finally have) and have the value 0!\n           this is exactly what we want\n           bitwise and is much faster than modulus\n  */\n\n  qbsss->number_elements = number_elements;\n  qbsss->mask = qbsss->number_elements - 1;\n  qbsss->read_index = 0;\n  qbsss->write_index = 0;\n  qbsss->element_array = element_array;\n  qbsss->user_state = user_state;\n\n  LFDS711_MISC_BARRIER_STORE;\n\n  lfds711_misc_force_store();\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_queue_bounded_singleproducer_singleconsumer/lfds711_queue_bounded_singleproducer_singleconsumer_internal.h",
    "content": "/***** the library wide include file *****/\n#include \"../liblfds711_internal.h\"\n\n/***** private prototypes *****/\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_queue_bounded_singleproducer_singleconsumer/lfds711_queue_bounded_singleproducer_singleconsumer_query.c",
    "content": "/***** includes *****/\n#include \"lfds711_queue_bounded_singleproducer_singleconsumer_internal.h\"\n\n/***** private prototypes *****/\nstatic void lfds711_queue_bss_internal_validate( struct lfds711_queue_bss_state *qbsss,\n                                                 struct lfds711_misc_validation_info *vi,\n                                                 enum lfds711_misc_validity *lfds711_validity );\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_queue_bss_query( struct lfds711_queue_bss_state *qbsss,\n                              enum lfds711_queue_bss_query query_type,\n                              void *query_input,\n                              void *query_output )\n{\n  LFDS711_PAL_ASSERT( qbsss != NULL );\n  // TRD : query_type can be any value in its range\n\n  switch( query_type )\n  {\n    case LFDS711_QUEUE_BSS_QUERY_GET_POTENTIALLY_INACCURATE_COUNT:\n    {\n      lfds711_pal_uint_t\n        local_read_index,\n        local_write_index;\n\n      LFDS711_PAL_ASSERT( query_input == NULL );\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      LFDS711_MISC_BARRIER_LOAD;\n\n      local_read_index = qbsss->read_index;\n      local_write_index = qbsss->write_index;\n\n      *(lfds711_pal_uint_t *) query_output = +( local_write_index - local_read_index );\n\n      if( local_read_index > local_write_index )\n        *(lfds711_pal_uint_t *) query_output = qbsss->number_elements - *(lfds711_pal_uint_t *) query_output;\n    }\n    break;\n\n    case LFDS711_QUEUE_BSS_QUERY_VALIDATE:\n      // TRD : query_input can be NULL\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      lfds711_queue_bss_internal_validate( qbsss, (struct lfds711_misc_validation_info *) query_input, (enum lfds711_misc_validity *) query_output );\n    break;\n  }\n\n  return;\n}\n\n\n\n\n\n/****************************************************************************/\nstatic void lfds711_queue_bss_internal_validate( struct lfds711_queue_bss_state *qbsss,\n                                                 struct lfds711_misc_validation_info *vi,\n                                                 enum lfds711_misc_validity *lfds711_validity )\n{\n  LFDS711_PAL_ASSERT( qbsss != NULL );\n  // TRD : vi can be NULL\n  LFDS711_PAL_ASSERT( lfds711_validity != NULL );\n\n  *lfds711_validity = LFDS711_MISC_VALIDITY_VALID;\n\n  if( vi != NULL )\n  {\n    lfds711_pal_uint_t\n      number_elements;\n\n    lfds711_queue_bss_query( qbsss, LFDS711_QUEUE_BSS_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void *) &number_elements );\n\n    if( number_elements < vi->min_elements )\n      *lfds711_validity = LFDS711_MISC_VALIDITY_INVALID_MISSING_ELEMENTS;\n\n    if( number_elements > vi->max_elements )\n      *lfds711_validity = LFDS711_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS;\n  }\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_queue_bounded_singleproducer_singleconsumer/test.ll",
    "content": "; ModuleID = 'lfds711_queue_bounded_singleproducer_singleconsumer_enqueue.c'\nsource_filename = \"lfds711_queue_bounded_singleproducer_singleconsumer_enqueue.c\"\ntarget datalayout = \"e-m:e-i64:64-f80:128-n8:16:32:64-S128\"\ntarget triple = \"x86_64-pc-linux-gnu\"\n\n%struct.lfds711_queue_bss_state = type { i64, i64, i64, i64, %struct.lfds711_queue_bss_element*, i8* }\n%struct.lfds711_queue_bss_element = type { i8*, i8* }\n\n; Function Attrs: noinline nounwind optnone sspstrong uwtable\ndefine dso_local i32 @lfds711_queue_bss_enqueue(%struct.lfds711_queue_bss_state* %qbsss, i8* %key, i8* %value) #0 {\nentry:\n  %retval = alloca i32, align 4\n  %qbsss.addr = alloca %struct.lfds711_queue_bss_state*, align 8\n  %key.addr = alloca i8*, align 8\n  %value.addr = alloca i8*, align 8\n  %qbsse = alloca %struct.lfds711_queue_bss_element*, align 8\n  %c = alloca i8*, align 8\n  store %struct.lfds711_queue_bss_state* %qbsss, %struct.lfds711_queue_bss_state** %qbsss.addr, align 8\n  store i8* %key, i8** %key.addr, align 8\n  store i8* %value, i8** %value.addr, align 8\n  %0 = load %struct.lfds711_queue_bss_state*, %struct.lfds711_queue_bss_state** %qbsss.addr, align 8\n  %cmp = icmp ne %struct.lfds711_queue_bss_state* %0, null\n  br i1 %cmp, label %if.end, label %if.then\n\nif.then:                                          ; preds = %entry\n  store i8* null, i8** %c, align 8\n  %1 = load i8*, i8** %c, align 8\n  store i8 0, i8* %1, align 1\n  br label %if.end\n\nif.end:                                           ; preds = %if.then, %entry\n  call void @lfds711_pal_barrier_compiler()\n  fence seq_cst\n  call void @lfds711_pal_barrier_compiler()\n  %2 = load %struct.lfds711_queue_bss_state*, %struct.lfds711_queue_bss_state** %qbsss.addr, align 8\n  %write_index = getelementptr inbounds %struct.lfds711_queue_bss_state, %struct.lfds711_queue_bss_state* %2, i32 0, i32 3\n  %3 = load volatile i64, i64* %write_index, align 8\n  %add = add i64 %3, 1\n  %4 = load %struct.lfds711_queue_bss_state*, %struct.lfds711_queue_bss_state** %qbsss.addr, align 8\n  %mask = getelementptr inbounds %struct.lfds711_queue_bss_state, %struct.lfds711_queue_bss_state* %4, i32 0, i32 1\n  %5 = load i64, i64* %mask, align 8\n  %and = and i64 %add, %5\n  %6 = load %struct.lfds711_queue_bss_state*, %struct.lfds711_queue_bss_state** %qbsss.addr, align 8\n  %read_index = getelementptr inbounds %struct.lfds711_queue_bss_state, %struct.lfds711_queue_bss_state* %6, i32 0, i32 2\n  %7 = load volatile i64, i64* %read_index, align 8\n  %cmp1 = icmp ne i64 %and, %7\n  br i1 %cmp1, label %if.then2, label %if.end11\n\nif.then2:                                         ; preds = %if.end\n  %8 = load %struct.lfds711_queue_bss_state*, %struct.lfds711_queue_bss_state** %qbsss.addr, align 8\n  %element_array = getelementptr inbounds %struct.lfds711_queue_bss_state, %struct.lfds711_queue_bss_state* %8, i32 0, i32 4\n  %9 = load %struct.lfds711_queue_bss_element*, %struct.lfds711_queue_bss_element** %element_array, align 8\n  %10 = load %struct.lfds711_queue_bss_state*, %struct.lfds711_queue_bss_state** %qbsss.addr, align 8\n  %write_index3 = getelementptr inbounds %struct.lfds711_queue_bss_state, %struct.lfds711_queue_bss_state* %10, i32 0, i32 3\n  %11 = load volatile i64, i64* %write_index3, align 8\n  %add.ptr = getelementptr inbounds %struct.lfds711_queue_bss_element, %struct.lfds711_queue_bss_element* %9, i64 %11\n  store %struct.lfds711_queue_bss_element* %add.ptr, %struct.lfds711_queue_bss_element** %qbsse, align 8\n  %12 = load i8*, i8** %key.addr, align 8\n  %13 = load %struct.lfds711_queue_bss_element*, %struct.lfds711_queue_bss_element** %qbsse, align 8\n  %key4 = getelementptr inbounds %struct.lfds711_queue_bss_element, %struct.lfds711_queue_bss_element* %13, i32 0, i32 0\n  store volatile i8* %12, i8** %key4, align 8\n  %14 = load i8*, i8** %value.addr, align 8\n  %15 = load %struct.lfds711_queue_bss_element*, %struct.lfds711_queue_bss_element** %qbsse, align 8\n  %value5 = getelementptr inbounds %struct.lfds711_queue_bss_element, %struct.lfds711_queue_bss_element* %15, i32 0, i32 1\n  store volatile i8* %14, i8** %value5, align 8\n  call void @lfds711_pal_barrier_compiler()\n  fence seq_cst\n  call void @lfds711_pal_barrier_compiler()\n  %16 = load %struct.lfds711_queue_bss_state*, %struct.lfds711_queue_bss_state** %qbsss.addr, align 8\n  %write_index6 = getelementptr inbounds %struct.lfds711_queue_bss_state, %struct.lfds711_queue_bss_state* %16, i32 0, i32 3\n  %17 = load volatile i64, i64* %write_index6, align 8\n  %add7 = add i64 %17, 1\n  %18 = load %struct.lfds711_queue_bss_state*, %struct.lfds711_queue_bss_state** %qbsss.addr, align 8\n  %mask8 = getelementptr inbounds %struct.lfds711_queue_bss_state, %struct.lfds711_queue_bss_state* %18, i32 0, i32 1\n  %19 = load i64, i64* %mask8, align 8\n  %and9 = and i64 %add7, %19\n  %20 = load %struct.lfds711_queue_bss_state*, %struct.lfds711_queue_bss_state** %qbsss.addr, align 8\n  %write_index10 = getelementptr inbounds %struct.lfds711_queue_bss_state, %struct.lfds711_queue_bss_state* %20, i32 0, i32 3\n  store volatile i64 %and9, i64* %write_index10, align 8\n  store i32 1, i32* %retval, align 4\n  br label %return\n\nif.end11:                                         ; preds = %if.end\n  store i32 0, i32* %retval, align 4\n  br label %return\n\nreturn:                                           ; preds = %if.end11, %if.then2\n  %21 = load i32, i32* %retval, align 4\n  ret i32 %21\n}\n\n; Function Attrs: noinline nounwind optnone sspstrong uwtable\ndefine internal void @lfds711_pal_barrier_compiler() #0 {\nentry:\n  call void asm sideeffect \"\", \"~{memory},~{dirflag},~{fpsr},~{flags}\"() #1, !srcloc !4\n  ret void\n}\n\nattributes #0 = { noinline nounwind optnone sspstrong uwtable \"correctly-rounded-divide-sqrt-fp-math\"=\"false\" \"disable-tail-calls\"=\"false\" \"less-precise-fpmad\"=\"false\" \"min-legal-vector-width\"=\"0\" \"no-frame-pointer-elim\"=\"true\" \"no-frame-pointer-elim-non-leaf\" \"no-infs-fp-math\"=\"false\" \"no-jump-tables\"=\"false\" \"no-nans-fp-math\"=\"false\" \"no-signed-zeros-fp-math\"=\"false\" \"no-trapping-math\"=\"false\" \"stack-protector-buffer-size\"=\"8\" \"target-cpu\"=\"x86-64\" \"target-features\"=\"+cx8,+fxsr,+mmx,+sse,+sse2,+x87\" \"unsafe-fp-math\"=\"false\" \"use-soft-float\"=\"false\" }\nattributes #1 = { nounwind }\n\n!llvm.module.flags = !{!0, !1, !2}\n!llvm.ident = !{!3}\n\n!0 = !{i32 1, !\"wchar_size\", i32 4}\n!1 = !{i32 7, !\"PIC Level\", i32 2}\n!2 = !{i32 7, !\"PIE Level\", i32 2}\n!3 = !{!\"clang version 9.0.1 \"}\n!4 = !{i32 51241}\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_queue_unbounded_manyproducer_manyconsumer/lfds711_queue_unbounded_manyproducer_manyconsumer_cleanup.c",
    "content": "/***** includes *****/\n#include \"lfds711_queue_unbounded_manyproducer_manyconsumer_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_queue_umm_cleanup( struct lfds711_queue_umm_state *qumms,\n                                void (*element_cleanup_callback)(struct lfds711_queue_umm_state *qumms, struct lfds711_queue_umm_element *qumme, enum lfds711_misc_flag dummy_element_flag) )\n{\n  struct lfds711_queue_umm_element\n    *qumme;\n\n  void\n    *value;\n\n  LFDS711_PAL_ASSERT( qumms != NULL );\n  // TRD : element_cleanup_callback can be NULL\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  if( element_cleanup_callback != NULL )\n  {\n    while( qumms->dequeue[POINTER] != qumms->enqueue[POINTER] )\n    {\n      // TRD : trailing dummy element, so the first real value is in the next element\n      value = qumms->dequeue[POINTER]->next[POINTER]->value;\n\n      // TRD : user is given back *an* element, but not the one his user data was in\n      qumme = qumms->dequeue[POINTER];\n\n      // TRD : remove the element from queue\n      qumms->dequeue[POINTER] = qumms->dequeue[POINTER]->next[POINTER];\n\n      // TRD : write value into the qumme we're going to give the user\n      qumme->value = value;\n\n      element_cleanup_callback( qumms, qumme, LFDS711_MISC_FLAG_LOWERED );\n    }\n\n    // TRD : and now the final element\n    element_cleanup_callback( qumms, (struct lfds711_queue_umm_element *) qumms->dequeue[POINTER], LFDS711_MISC_FLAG_RAISED );\n  }\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_queue_unbounded_manyproducer_manyconsumer/lfds711_queue_unbounded_manyproducer_manyconsumer_dequeue.c",
    "content": "/***** includes *****/\n#include \"lfds711_queue_unbounded_manyproducer_manyconsumer_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nint lfds711_queue_umm_dequeue( struct lfds711_queue_umm_state *qumms,\n                               struct lfds711_queue_umm_element **qumme )\n{\n  char unsigned\n    result = 0;\n\n  enum lfds711_misc_flag\n    backoff_flag = LFDS711_MISC_FLAG_RAISED,\n    finished_flag = LFDS711_MISC_FLAG_LOWERED;\n\n  enum lfds711_queue_umm_queue_state\n    state = LFDS711_QUEUE_UMM_QUEUE_STATE_UNKNOWN;\n\n  int\n    rv = 1;\n\n  lfds711_pal_uint_t\n    backoff_iteration = LFDS711_BACKOFF_INITIAL_VALUE;\n\n  struct lfds711_queue_umm_element LFDS711_PAL_ALIGN(LFDS711_PAL_ALIGN_DOUBLE_POINTER)\n    *dequeue[PAC_SIZE],\n    *enqueue[PAC_SIZE],\n    *next[PAC_SIZE];\n\n  void\n    *key = NULL,\n    *value = NULL;\n\n  LFDS711_PAL_ASSERT( qumms != NULL );\n  LFDS711_PAL_ASSERT( qumme != NULL );\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  do\n  {\n    /* TRD : note here the deviation from the white paper\n             in the white paper, next is loaded from dequeue, not from qumms->dequeue\n             what concerns me is that between the load of dequeue and the load of\n             enqueue->next, the element can be dequeued by another thread *and freed*\n\n             by ordering the loads (load barriers), and loading both from qumms,\n             the following if(), which checks dequeue is still the same as qumms->enqueue\n             still continues to ensure next belongs to enqueue, while avoiding the\n             problem with free\n    */\n\n    dequeue[COUNTER] = qumms->dequeue[COUNTER];\n    dequeue[POINTER] = qumms->dequeue[POINTER];\n\n    LFDS711_MISC_BARRIER_LOAD;\n\n    enqueue[COUNTER] = qumms->enqueue[COUNTER];\n    enqueue[POINTER] = qumms->enqueue[POINTER];\n\n    next[COUNTER] = qumms->dequeue[POINTER]->next[COUNTER];\n    next[POINTER] = qumms->dequeue[POINTER]->next[POINTER];\n\n    LFDS711_MISC_BARRIER_LOAD;\n\n    if( qumms->dequeue[COUNTER] == dequeue[COUNTER] and qumms->dequeue[POINTER] == dequeue[POINTER] )\n    {\n      if( enqueue[POINTER] == dequeue[POINTER] and next[POINTER] == NULL )\n        state = LFDS711_QUEUE_UMM_QUEUE_STATE_EMPTY;\n\n      if( enqueue[POINTER] == dequeue[POINTER] and next[POINTER] != NULL )\n        state = LFDS711_QUEUE_UMM_QUEUE_STATE_ENQUEUE_OUT_OF_PLACE;\n\n      if( enqueue[POINTER] != dequeue[POINTER] )\n        state = LFDS711_QUEUE_UMM_QUEUE_STATE_ATTEMPT_DEQUEUE;\n\n      switch( state )\n      {\n        case LFDS711_QUEUE_UMM_QUEUE_STATE_UNKNOWN:\n          // TRD : eliminates compiler warning\n        break;\n\n        case LFDS711_QUEUE_UMM_QUEUE_STATE_EMPTY:\n          rv = 0;\n          *qumme = NULL;\n          result = 0;\n          backoff_flag = LFDS711_MISC_FLAG_LOWERED;\n          finished_flag = LFDS711_MISC_FLAG_RAISED;\n        break;\n\n        case LFDS711_QUEUE_UMM_QUEUE_STATE_ENQUEUE_OUT_OF_PLACE:\n          next[COUNTER] = enqueue[COUNTER] + 1;\n          LFDS711_PAL_ATOMIC_DWCAS( qumms->enqueue, enqueue, next, LFDS711_MISC_CAS_STRENGTH_WEAK, result );\n          // TRD : in fact if result is 1 (successful) I think we can now simply drop down into the dequeue attempt\n        break;\n\n        case LFDS711_QUEUE_UMM_QUEUE_STATE_ATTEMPT_DEQUEUE:\n          key = next[POINTER]->key;\n          value = next[POINTER]->value;\n\n          next[COUNTER] = qumms->dequeue[COUNTER] + 1;\n          LFDS711_PAL_ATOMIC_DWCAS( qumms->dequeue, dequeue, next, LFDS711_MISC_CAS_STRENGTH_WEAK, result );\n\n          if( result == 1 )\n          {\n            backoff_flag = LFDS711_MISC_FLAG_LOWERED;\n            finished_flag = LFDS711_MISC_FLAG_RAISED;\n          }\n        break;\n      }\n    }\n    else\n      backoff_flag = LFDS711_MISC_FLAG_RAISED;\n\n    if( backoff_flag == LFDS711_MISC_FLAG_RAISED )\n      LFDS711_BACKOFF_EXPONENTIAL_BACKOFF( qumms->dequeue_backoff, backoff_iteration );\n  }\n  while( finished_flag == LFDS711_MISC_FLAG_LOWERED );\n\n  if( result == 1 )\n  {\n    *qumme = dequeue[POINTER];\n    (*qumme)->key = key;\n    (*qumme)->value = value;\n  }\n\n  LFDS711_BACKOFF_AUTOTUNE( qumms->dequeue_backoff, backoff_iteration );\n\n  return rv;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_queue_unbounded_manyproducer_manyconsumer/lfds711_queue_unbounded_manyproducer_manyconsumer_enqueue.c",
    "content": "/***** includes *****/\n#include \"lfds711_queue_unbounded_manyproducer_manyconsumer_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_queue_umm_enqueue( struct lfds711_queue_umm_state *qumms,\n                                struct lfds711_queue_umm_element *qumme )\n{\n  char unsigned\n    result = 0;\n\n  enum lfds711_misc_flag\n    finished_flag = LFDS711_MISC_FLAG_LOWERED;\n\n  lfds711_pal_uint_t\n    backoff_iteration = LFDS711_BACKOFF_INITIAL_VALUE;\n\n  struct lfds711_queue_umm_element LFDS711_PAL_ALIGN(LFDS711_PAL_ALIGN_DOUBLE_POINTER)\n    *volatile enqueue[PAC_SIZE],\n    *new_enqueue[PAC_SIZE],\n    *volatile next[PAC_SIZE];\n\n  LFDS711_PAL_ASSERT( qumms != NULL );\n  LFDS711_PAL_ASSERT( qumme != NULL );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) qumme->next % LFDS711_PAL_ALIGN_DOUBLE_POINTER == 0 );\n\n  qumme->next[POINTER] = NULL;\n  LFDS711_PAL_ATOMIC_ADD( &qumms->aba_counter, 1, qumme->next[COUNTER], struct lfds711_queue_umm_element * );\n  LFDS711_MISC_BARRIER_STORE;\n\n  new_enqueue[POINTER] = qumme;\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  do\n  {\n    /* TRD : note here the deviation from the white paper\n             in the white paper, next is loaded from enqueue, not from qumms->enqueue\n             what concerns me is that between the load of enqueue and the load of\n             enqueue->next, the element can be dequeued by another thread *and freed*\n\n             by ordering the loads (load barriers), and loading both from qumms,\n             the following if(), which checks enqueue is still the same as qumms->enqueue\n             still continues to ensure next belongs to enqueue, while avoiding the\n             problem with free\n    */\n\n    enqueue[COUNTER] = qumms->enqueue[COUNTER];\n    enqueue[POINTER] = qumms->enqueue[POINTER];\n\n    LFDS711_MISC_BARRIER_LOAD;\n\n    next[COUNTER] = qumms->enqueue[POINTER]->next[COUNTER];\n    next[POINTER] = qumms->enqueue[POINTER]->next[POINTER];\n\n    LFDS711_MISC_BARRIER_LOAD;\n\n    if( qumms->enqueue[COUNTER] == enqueue[COUNTER] and qumms->enqueue[POINTER] == enqueue[POINTER] )\n    {\n      if( next[POINTER] == NULL )\n      {\n        new_enqueue[COUNTER] = next[COUNTER] + 1;\n        LFDS711_PAL_ATOMIC_DWCAS( enqueue[POINTER]->next, next, new_enqueue, LFDS711_MISC_CAS_STRENGTH_WEAK, result );\n        if( result == 1 )\n          finished_flag = LFDS711_MISC_FLAG_RAISED;\n      }\n      else\n      {\n        next[COUNTER] = enqueue[COUNTER] + 1;\n        // TRD : strictly, this is a weak CAS, but we do an extra iteration of the main loop on a fake failure, so we set it to be strong\n        LFDS711_PAL_ATOMIC_DWCAS( qumms->enqueue, enqueue, next, LFDS711_MISC_CAS_STRENGTH_STRONG, result );\n      }\n    }\n    else\n      result = 0;\n\n    if( result == 0 )\n      LFDS711_BACKOFF_EXPONENTIAL_BACKOFF( qumms->enqueue_backoff, backoff_iteration );\n  }\n  while( finished_flag == LFDS711_MISC_FLAG_LOWERED );\n\n  // TRD : move enqueue along; only a weak CAS as the dequeue will solve this if it's out of place\n  new_enqueue[COUNTER] = enqueue[COUNTER] + 1;\n  LFDS711_PAL_ATOMIC_DWCAS( qumms->enqueue, enqueue, new_enqueue, LFDS711_MISC_CAS_STRENGTH_WEAK, result );\n\n  if( result == 0 )\n    LFDS711_BACKOFF_EXPONENTIAL_BACKOFF( qumms->enqueue_backoff, backoff_iteration );\n\n  LFDS711_BACKOFF_AUTOTUNE( qumms->enqueue_backoff, backoff_iteration );\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_queue_unbounded_manyproducer_manyconsumer/lfds711_queue_unbounded_manyproducer_manyconsumer_init.c",
    "content": "/***** includes *****/\n#include \"lfds711_queue_unbounded_manyproducer_manyconsumer_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_queue_umm_init_valid_on_current_logical_core( struct lfds711_queue_umm_state *qumms,\n                                                           struct lfds711_queue_umm_element *qumme_dummy,\n                                                           void *user_state )\n{\n  LFDS711_PAL_ASSERT( qumms != NULL );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &qumms->enqueue % LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &qumms->dequeue % LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &qumms->user_state % LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 );\n  LFDS711_PAL_ASSERT( qumme_dummy != NULL );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) qumme_dummy->next % LFDS711_PAL_ALIGN_DOUBLE_POINTER == 0 );\n  // TRD : user_state can be NULL\n\n  /* TRD : qumme_dummy is a dummy element, needed for init\n           the qumms->enqueue and qumms->dequeue counters do not need to be initialized\n           but it does no harm to do so, and stops a valgrind complaint\n  */\n\n  LFDS711_PRNG_GENERATE( lfds711_misc_globals.ps, qumms->aba_counter );\n\n  qumms->enqueue[POINTER] = qumme_dummy;\n  qumms->enqueue[COUNTER] = (struct lfds711_queue_umm_element *) 0;\n  qumms->dequeue[POINTER] = qumme_dummy;\n  qumms->dequeue[COUNTER] = (struct lfds711_queue_umm_element *) 0;\n\n  qumme_dummy->next[POINTER] = NULL;\n  // TRD : no need here for an atomic add as we have a store barrier and force store below\n  qumme_dummy->next[COUNTER] = (struct lfds711_queue_umm_element *) qumms->aba_counter++;\n  qumme_dummy->key = NULL;\n  qumme_dummy->value = NULL;\n\n  qumms->user_state = user_state;\n\n  lfds711_misc_internal_backoff_init( &qumms->dequeue_backoff );\n  lfds711_misc_internal_backoff_init( &qumms->enqueue_backoff );\n\n  LFDS711_MISC_BARRIER_STORE;\n\n  lfds711_misc_force_store();\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_queue_unbounded_manyproducer_manyconsumer/lfds711_queue_unbounded_manyproducer_manyconsumer_internal.h",
    "content": "/***** the library wide include file *****/\n#include \"../liblfds711_internal.h\"\n\n/***** enums *****/\nenum lfds711_queue_umm_queue_state\n{\n  LFDS711_QUEUE_UMM_QUEUE_STATE_UNKNOWN, \n  LFDS711_QUEUE_UMM_QUEUE_STATE_EMPTY,\n  LFDS711_QUEUE_UMM_QUEUE_STATE_ENQUEUE_OUT_OF_PLACE,\n  LFDS711_QUEUE_UMM_QUEUE_STATE_ATTEMPT_DEQUEUE\n};\n\n/***** private prototypes *****/\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_queue_unbounded_manyproducer_manyconsumer/lfds711_queue_unbounded_manyproducer_manyconsumer_query.c",
    "content": "/***** includes *****/\n#include \"lfds711_queue_unbounded_manyproducer_manyconsumer_internal.h\"\n\n/***** private prototypes *****/\nstatic void lfds711_queue_umm_internal_validate( struct lfds711_queue_umm_state *qumms,\n                                                 struct lfds711_misc_validation_info *vi,\n                                                 enum lfds711_misc_validity *lfds711_queue_umm_validity );\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_queue_umm_query( struct lfds711_queue_umm_state *qumms,\n                              enum lfds711_queue_umm_query query_type,\n                              void *query_input,\n                              void *query_output )\n{\n  struct lfds711_queue_umm_element\n    *qumme;\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  LFDS711_PAL_ASSERT( qumms != NULL );\n  // TRD : query_type can be any value in its range\n\n  switch( query_type )\n  {\n    case LFDS711_QUEUE_UMM_QUERY_SINGLETHREADED_GET_COUNT:\n      LFDS711_PAL_ASSERT( query_input == NULL );\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      *(lfds711_pal_uint_t *) query_output = 0;\n\n      qumme = (struct lfds711_queue_umm_element *) qumms->dequeue[POINTER];\n\n      while( qumme != NULL )\n      {\n        ( *(lfds711_pal_uint_t *) query_output )++;\n        qumme = (struct lfds711_queue_umm_element *) qumme->next[POINTER];\n      }\n\n      // TRD : remember there is a dummy element in the queue\n      ( *(lfds711_pal_uint_t *) query_output )--;\n    break;\n\n    case LFDS711_QUEUE_UMM_QUERY_SINGLETHREADED_VALIDATE:\n      // TRD : query_input can be NULL\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      lfds711_queue_umm_internal_validate( qumms, (struct lfds711_misc_validation_info *) query_input, (enum lfds711_misc_validity *) query_output );\n    break;\n  }\n\n  return;\n}\n\n\n\n\n\n/****************************************************************************/\nstatic void lfds711_queue_umm_internal_validate( struct lfds711_queue_umm_state *qumms,\n                                                 struct lfds711_misc_validation_info *vi,\n                                                 enum lfds711_misc_validity *lfds711_queue_umm_validity )\n{\n  lfds711_pal_uint_t\n    number_elements = 0;\n\n  struct lfds711_queue_umm_element\n    *qumme_fast,\n    *qumme_slow;\n\n  LFDS711_PAL_ASSERT( qumms != NULL );\n  // TRD : vi can be NULL\n  LFDS711_PAL_ASSERT( lfds711_queue_umm_validity != NULL );\n\n  *lfds711_queue_umm_validity = LFDS711_MISC_VALIDITY_VALID;\n\n  qumme_slow = qumme_fast = (struct lfds711_queue_umm_element *) qumms->dequeue[POINTER];\n\n  /* TRD : first, check for a loop\n           we have two pointers\n           both of which start at the dequeue end of the queue\n           we enter a loop\n           and on each iteration\n           we advance one pointer by one element\n           and the other by two\n\n           we exit the loop when both pointers are NULL\n           (have reached the end of the queue)\n\n           or\n\n           if we fast pointer 'sees' the slow pointer\n           which means we have a loop\n  */\n\n  if( qumme_slow != NULL )\n    do\n    {\n      qumme_slow = qumme_slow->next[POINTER];\n\n      if( qumme_fast != NULL )\n        qumme_fast = qumme_fast->next[POINTER];\n\n      if( qumme_fast != NULL )\n        qumme_fast = qumme_fast->next[POINTER];\n    }\n    while( qumme_slow != NULL and qumme_fast != qumme_slow );\n\n  if( qumme_fast != NULL and qumme_slow != NULL and qumme_fast == qumme_slow )\n    *lfds711_queue_umm_validity = LFDS711_MISC_VALIDITY_INVALID_LOOP;\n\n  /* TRD : now check for expected number of elements\n           vi can be NULL, in which case we do not check\n           we know we don't have a loop from our earlier check\n  */\n\n  if( *lfds711_queue_umm_validity == LFDS711_MISC_VALIDITY_VALID and vi != NULL )\n  {\n    lfds711_queue_umm_query( qumms, LFDS711_QUEUE_UMM_QUERY_SINGLETHREADED_GET_COUNT, NULL, (void *) &number_elements );\n\n    if( number_elements < vi->min_elements )\n      *lfds711_queue_umm_validity = LFDS711_MISC_VALIDITY_INVALID_MISSING_ELEMENTS;\n\n    if( number_elements > vi->max_elements )\n      *lfds711_queue_umm_validity = LFDS711_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS;\n  }\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_ringbuffer/lfds711_ringbuffer_cleanup.c",
    "content": "/***** includes *****/\n#include \"lfds711_ringbuffer_internal.h\"\n\n/***** private prototypes *****/\nstatic void lfds711_ringbuffer_internal_queue_umm_element_cleanup_callback( struct lfds711_queue_umm_state *qumms,\n                                                                            struct lfds711_queue_umm_element *qumme,\n                                                                            enum lfds711_misc_flag dummy_element_flag );\nstatic void lfds711_ringbuffer_internal_freelist_element_cleanup_callback( struct lfds711_freelist_state *fs,\n                                                                           struct lfds711_freelist_element *fe );\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_ringbuffer_cleanup( struct lfds711_ringbuffer_state *rs,\n                                 void (*element_cleanup_callback)(struct lfds711_ringbuffer_state *rs, void *key, void *value, enum lfds711_misc_flag unread_flag) )\n{\n  LFDS711_PAL_ASSERT( rs != NULL );\n  // TRD : element_cleanup_callback can be NULL\n\n  if( element_cleanup_callback != NULL )\n  {\n    rs->element_cleanup_callback = element_cleanup_callback;\n    lfds711_queue_umm_cleanup( &rs->qumms, lfds711_ringbuffer_internal_queue_umm_element_cleanup_callback );\n    lfds711_freelist_cleanup( &rs->fs, lfds711_ringbuffer_internal_freelist_element_cleanup_callback );\n  }\n\n  return;\n}\n\n\n\n\n\n/****************************************************************************/\n#pragma warning( disable : 4100 )\n\nstatic void lfds711_ringbuffer_internal_queue_umm_element_cleanup_callback( struct lfds711_queue_umm_state *qumms,\n                                                                            struct lfds711_queue_umm_element *qumme,\n                                                                            enum lfds711_misc_flag dummy_element_flag )\n{\n  struct lfds711_ringbuffer_element\n    *re;\n\n  struct lfds711_ringbuffer_state\n    *rs;\n\n  LFDS711_PAL_ASSERT( qumms != NULL );\n  LFDS711_PAL_ASSERT( qumme != NULL );\n  // TRD : dummy_element can be any value in its range\n\n  rs = (struct lfds711_ringbuffer_state *) LFDS711_QUEUE_UMM_GET_USER_STATE_FROM_STATE( *qumms );\n  re = (struct lfds711_ringbuffer_element *) LFDS711_QUEUE_UMM_GET_VALUE_FROM_ELEMENT( *qumme );\n\n  if( dummy_element_flag == LFDS711_MISC_FLAG_LOWERED )\n    rs->element_cleanup_callback( rs, re->key, re->value, LFDS711_MISC_FLAG_RAISED );\n\n  return;\n}\n\n#pragma warning( default : 4100 )\n\n\n\n\n\n/****************************************************************************/\n#pragma warning( disable : 4100 )\n\nstatic void lfds711_ringbuffer_internal_freelist_element_cleanup_callback( struct lfds711_freelist_state *fs,\n                                                                           struct lfds711_freelist_element *fe )\n{\n  struct lfds711_ringbuffer_element\n    *re;\n\n  struct lfds711_ringbuffer_state\n    *rs;\n\n  LFDS711_PAL_ASSERT( fs != NULL );\n  LFDS711_PAL_ASSERT( fe != NULL );\n\n  rs = (struct lfds711_ringbuffer_state *) LFDS711_FREELIST_GET_USER_STATE_FROM_STATE( *fs );\n  re = (struct lfds711_ringbuffer_element *) LFDS711_FREELIST_GET_VALUE_FROM_ELEMENT( *fe );\n\n  rs->element_cleanup_callback( rs, re->key, re->value, LFDS711_MISC_FLAG_LOWERED );\n\n  return;\n}\n\n#pragma warning( default : 4100 )\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_ringbuffer/lfds711_ringbuffer_init.c",
    "content": "/***** includes *****/\n#include \"lfds711_ringbuffer_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_ringbuffer_init_valid_on_current_logical_core( struct lfds711_ringbuffer_state *rs,\n                                                            struct lfds711_ringbuffer_element *re_array_inc_dummy,\n                                                            lfds711_pal_uint_t number_elements_inc_dummy,\n                                                            void *user_state )\n{\n  lfds711_pal_uint_t\n    loop;\n\n  LFDS711_PAL_ASSERT( rs != NULL );\n  LFDS711_PAL_ASSERT( re_array_inc_dummy != NULL );\n  LFDS711_PAL_ASSERT( number_elements_inc_dummy >= 2 );\n  // TRD : user_state can be NULL\n\n  rs->user_state = user_state;\n\n  re_array_inc_dummy[0].qumme_use = &re_array_inc_dummy[0].qumme;\n\n  lfds711_freelist_init_valid_on_current_logical_core( &rs->fs, NULL, 0, rs );\n  lfds711_queue_umm_init_valid_on_current_logical_core( &rs->qumms, &re_array_inc_dummy[0].qumme, rs );\n\n  for( loop = 1 ; loop < number_elements_inc_dummy ; loop++ )\n  {\n    re_array_inc_dummy[loop].qumme_use = &re_array_inc_dummy[loop].qumme;\n    LFDS711_FREELIST_SET_VALUE_IN_ELEMENT( re_array_inc_dummy[loop].fe, &re_array_inc_dummy[loop] );\n    lfds711_freelist_push( &rs->fs, &re_array_inc_dummy[loop].fe, NULL );\n  }\n\n  LFDS711_MISC_BARRIER_STORE;\n\n  lfds711_misc_force_store();\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_ringbuffer/lfds711_ringbuffer_internal.h",
    "content": "/***** the library wide include file *****/\n#include \"../liblfds711_internal.h\"\n\n/***** private prototypes *****/\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_ringbuffer/lfds711_ringbuffer_query.c",
    "content": "/***** includes *****/\n#include \"lfds711_ringbuffer_internal.h\"\n\n/***** private prototypes *****/\nstatic void lfds711_ringbuffer_internal_validate( struct lfds711_ringbuffer_state *rs,\n                                                  struct lfds711_misc_validation_info *vi,\n                                                  enum lfds711_misc_validity *lfds711_queue_umm_validity,\n                                                  enum lfds711_misc_validity *lfds711_freelist_validity );\n\n\n\n/****************************************************************************/\nvoid lfds711_ringbuffer_query( struct lfds711_ringbuffer_state *rs,\n                               enum lfds711_ringbuffer_query query_type,\n                               void *query_input,\n                               void *query_output )\n{\n  LFDS711_PAL_ASSERT( rs != NULL );\n  // TRD : query_type can be any value in its range\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  switch( query_type )\n  {\n    case LFDS711_RINGBUFFER_QUERY_SINGLETHREADED_GET_COUNT:\n      LFDS711_PAL_ASSERT( query_input == NULL );\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      lfds711_queue_umm_query( &rs->qumms, LFDS711_QUEUE_UMM_QUERY_SINGLETHREADED_GET_COUNT, NULL, query_output );\n    break;\n\n    case LFDS711_RINGBUFFER_QUERY_SINGLETHREADED_VALIDATE:\n      // TRD : query_input can be NULL\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      lfds711_ringbuffer_internal_validate( rs, (struct lfds711_misc_validation_info *) query_input, (enum lfds711_misc_validity *) query_output, ((enum lfds711_misc_validity *) query_output)+1 );\n    break;\n  }\n\n  return;\n}\n\n\n\n\n\n/****************************************************************************/\nstatic void lfds711_ringbuffer_internal_validate( struct lfds711_ringbuffer_state *rs,\n                                                  struct lfds711_misc_validation_info *vi,\n                                                  enum lfds711_misc_validity *lfds711_queue_umm_validity,\n                                                  enum lfds711_misc_validity *lfds711_freelist_validity )\n{\n  LFDS711_PAL_ASSERT( rs != NULL );\n  // TRD : vi can be NULL\n  LFDS711_PAL_ASSERT( lfds711_queue_umm_validity != NULL );\n  LFDS711_PAL_ASSERT( lfds711_freelist_validity != NULL );\n\n  if( vi == NULL )\n  {\n    lfds711_queue_umm_query( &rs->qumms, LFDS711_QUEUE_UMM_QUERY_SINGLETHREADED_VALIDATE, NULL, lfds711_queue_umm_validity );\n    lfds711_freelist_query( &rs->fs, LFDS711_FREELIST_QUERY_SINGLETHREADED_VALIDATE, NULL, lfds711_freelist_validity );\n  }\n\n  if( vi != NULL )\n  {\n    struct lfds711_misc_validation_info\n      freelist_vi,\n      queue_vi;\n\n    queue_vi.min_elements = 0;\n    freelist_vi.min_elements = 0;\n    queue_vi.max_elements = vi->max_elements;\n    freelist_vi.max_elements = vi->max_elements;\n\n    lfds711_queue_umm_query( &rs->qumms, LFDS711_QUEUE_UMM_QUERY_SINGLETHREADED_VALIDATE, &queue_vi, lfds711_queue_umm_validity );\n    lfds711_freelist_query( &rs->fs, LFDS711_FREELIST_QUERY_SINGLETHREADED_VALIDATE, &freelist_vi, lfds711_freelist_validity );\n  }\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_ringbuffer/lfds711_ringbuffer_read.c",
    "content": "/***** includes *****/\n#include \"lfds711_ringbuffer_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nint lfds711_ringbuffer_read( struct lfds711_ringbuffer_state *rs,\n                             void **key,\n                             void **value )\n{\n  int\n    rv;\n\n  struct lfds711_queue_umm_element\n    *qumme;\n\n  struct lfds711_ringbuffer_element\n    *re;\n\n  LFDS711_PAL_ASSERT( rs != NULL );\n  // TRD : key can be NULL\n  // TRD : value can be NULL\n  // TRD : psts can be NULL\n\n  rv = lfds711_queue_umm_dequeue( &rs->qumms, &qumme );\n\n  if( rv == 1 )\n  {\n    re = LFDS711_QUEUE_UMM_GET_VALUE_FROM_ELEMENT( *qumme );\n    re->qumme_use = (struct lfds711_queue_umm_element *) qumme;\n    if( key != NULL )\n      *key = re->key;\n    if( value != NULL )\n      *value = re->value;\n    LFDS711_FREELIST_SET_VALUE_IN_ELEMENT( re->fe, re );\n    lfds711_freelist_push( &rs->fs, &re->fe, NULL );\n  }\n\n  return rv;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_ringbuffer/lfds711_ringbuffer_write.c",
    "content": "/***** includes *****/\n#include \"lfds711_ringbuffer_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_ringbuffer_write( struct lfds711_ringbuffer_state *rs,\n                               void *key,\n                               void *value,\n                               enum lfds711_misc_flag *overwrite_occurred_flag,\n                               void **overwritten_key,\n                               void **overwritten_value )\n{\n  int\n    rv = 0;\n\n  struct lfds711_freelist_element\n    *fe;\n\n  struct lfds711_queue_umm_element\n    *qumme;\n\n  struct lfds711_ringbuffer_element\n    *re = NULL;\n\n  LFDS711_PAL_ASSERT( rs != NULL );\n  // TRD : key can be NULL\n  // TRD : value can be NULL\n  // TRD : overwrite_occurred_flag can be NULL\n  // TRD : overwritten_key can be NULL\n  // TRD : overwritten_value can be NULL\n  // TRD : psts can be NULL\n\n  if( overwrite_occurred_flag != NULL )\n    *overwrite_occurred_flag = LFDS711_MISC_FLAG_LOWERED;\n\n  do\n  {\n    rv = lfds711_freelist_pop( &rs->fs, &fe, NULL );\n\n    if( rv == 1 )\n      re = LFDS711_FREELIST_GET_VALUE_FROM_ELEMENT( *fe );\n\n    if( rv == 0 )\n    {\n      // TRD : the queue can return empty as well - remember, we're lock-free; anything could have happened since the previous instruction\n      rv = lfds711_queue_umm_dequeue( &rs->qumms, &qumme );\n\n      if( rv == 1 )\n      {\n        re = LFDS711_QUEUE_UMM_GET_VALUE_FROM_ELEMENT( *qumme );\n        re->qumme_use = (struct lfds711_queue_umm_element *) qumme;\n\n        if( overwrite_occurred_flag != NULL )\n          *overwrite_occurred_flag = LFDS711_MISC_FLAG_RAISED;\n\n        if( overwritten_key != NULL )\n          *overwritten_key = re->key;\n\n        if( overwritten_value != NULL )\n          *overwritten_value = re->value;\n      }\n    }\n  }\n  while( rv == 0 );\n\n  re->key = key;\n  re->value = value;\n\n  LFDS711_QUEUE_UMM_SET_VALUE_IN_ELEMENT( *re->qumme_use, re );\n  lfds711_queue_umm_enqueue( &rs->qumms, re->qumme_use );\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_stack/lfds711_stack_cleanup.c",
    "content": "/***** includes *****/\n#include \"lfds711_stack_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_stack_cleanup( struct lfds711_stack_state *ss,\n                            void (*element_cleanup_callback)(struct lfds711_stack_state *ss, struct lfds711_stack_element *se) )\n{\n  struct lfds711_stack_element\n    *se,\n    *se_temp;\n\n  LFDS711_PAL_ASSERT( ss != NULL );\n  // TRD : element_cleanup_callback can be NULL\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  if( element_cleanup_callback != NULL )\n  {\n    se = ss->top[POINTER];\n\n    while( se != NULL )\n    {\n      se_temp = se;\n      se = se->next;\n\n      element_cleanup_callback( ss, se_temp );\n    }\n  }\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_stack/lfds711_stack_init.c",
    "content": "/***** includes *****/\n#include \"lfds711_stack_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_stack_init_valid_on_current_logical_core( struct lfds711_stack_state *ss,\n                                                       void *user_state )\n{\n  LFDS711_PAL_ASSERT( ss != NULL );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) ss->top % LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &ss->user_state % LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 );\n  // TRD : user_state can be NULL\n\n  ss->top[POINTER] = NULL;\n  ss->top[COUNTER] = 0;\n\n  ss->user_state = user_state;\n\n  lfds711_misc_internal_backoff_init( &ss->pop_backoff );\n  lfds711_misc_internal_backoff_init( &ss->push_backoff );\n\n  LFDS711_MISC_BARRIER_STORE;\n\n  lfds711_misc_force_store();\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_stack/lfds711_stack_internal.h",
    "content": "/***** the library wide include file *****/\n#include \"../liblfds711_internal.h\"\n\n/***** private prototypes *****/\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_stack/lfds711_stack_pop.c",
    "content": "/***** includes *****/\n#include \"lfds711_stack_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nint lfds711_stack_pop( struct lfds711_stack_state *ss,\n                       struct lfds711_stack_element **se )\n{\n  char unsigned\n    result;\n\n  lfds711_pal_uint_t\n    backoff_iteration = LFDS711_BACKOFF_INITIAL_VALUE;\n\n  struct lfds711_stack_element LFDS711_PAL_ALIGN(LFDS711_PAL_ALIGN_DOUBLE_POINTER)\n    *new_top[PAC_SIZE],\n    *volatile original_top[PAC_SIZE];\n\n  LFDS711_PAL_ASSERT( ss != NULL );\n  LFDS711_PAL_ASSERT( se != NULL );\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  original_top[COUNTER] = ss->top[COUNTER];\n  original_top[POINTER] = ss->top[POINTER];\n\n  do\n  {\n    if( original_top[POINTER] == NULL )\n    {\n      *se = NULL;\n      return 0;\n    }\n\n    new_top[COUNTER] = original_top[COUNTER] + 1;\n    new_top[POINTER] = original_top[POINTER]->next;\n\n    LFDS711_PAL_ATOMIC_DWCAS( ss->top, original_top, new_top, LFDS711_MISC_CAS_STRENGTH_WEAK, result );\n\n    if( result == 0 )\n    {\n      LFDS711_BACKOFF_EXPONENTIAL_BACKOFF( ss->pop_backoff, backoff_iteration );\n      LFDS711_MISC_BARRIER_LOAD;\n    }\n  }\n  while( result == 0 );\n\n  *se = original_top[POINTER];\n\n  LFDS711_BACKOFF_AUTOTUNE( ss->pop_backoff, backoff_iteration );\n\n  return 1;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_stack/lfds711_stack_push.c",
    "content": "/***** includes *****/\n#include \"lfds711_stack_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_stack_push( struct lfds711_stack_state *ss,\n                         struct lfds711_stack_element *se )\n{\n  char unsigned\n    result;\n\n  lfds711_pal_uint_t\n    backoff_iteration = LFDS711_BACKOFF_INITIAL_VALUE;\n\n  struct lfds711_stack_element LFDS711_PAL_ALIGN(LFDS711_PAL_ALIGN_DOUBLE_POINTER)\n    *new_top[PAC_SIZE],\n    *volatile original_top[PAC_SIZE];\n\n  LFDS711_PAL_ASSERT( ss != NULL );\n  LFDS711_PAL_ASSERT( se != NULL );\n\n  new_top[POINTER] = se;\n\n  original_top[COUNTER] = ss->top[COUNTER];\n  original_top[POINTER] = ss->top[POINTER];\n\n  do\n  {\n    se->next = original_top[POINTER];\n    LFDS711_MISC_BARRIER_STORE;\n\n    new_top[COUNTER] = original_top[COUNTER] + 1;\n    LFDS711_PAL_ATOMIC_DWCAS( ss->top, original_top, new_top, LFDS711_MISC_CAS_STRENGTH_WEAK, result );\n\n    if( result == 0 )\n      LFDS711_BACKOFF_EXPONENTIAL_BACKOFF( ss->push_backoff, backoff_iteration );\n  }\n  while( result == 0 );\n\n  LFDS711_BACKOFF_AUTOTUNE( ss->push_backoff, backoff_iteration );\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/lfds711_stack/lfds711_stack_query.c",
    "content": "/***** includes *****/\n#include \"lfds711_stack_internal.h\"\n\n/***** private prototypes *****/\nstatic void lfds711_stack_internal_stack_validate( struct lfds711_stack_state *ss,\n                                                   struct lfds711_misc_validation_info *vi,\n                                                   enum lfds711_misc_validity *lfds711_stack_validity );\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_stack_query( struct lfds711_stack_state *ss,\n                          enum lfds711_stack_query query_type,\n                          void *query_input,\n                          void *query_output )\n{\n  struct lfds711_stack_element\n    *se;\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  LFDS711_PAL_ASSERT( ss != NULL );\n  // TRD : query_type can be any value in its range\n\n  switch( query_type )\n  {\n    case LFDS711_STACK_QUERY_SINGLETHREADED_GET_COUNT:\n      LFDS711_PAL_ASSERT( query_input == NULL );\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      *(lfds711_pal_uint_t *) query_output = 0;\n\n      se = (struct lfds711_stack_element *) ss->top[POINTER];\n\n      while( se != NULL )\n      {\n        ( *(lfds711_pal_uint_t *) query_output )++;\n        se = (struct lfds711_stack_element *) se->next;\n      }\n    break;\n\n    case LFDS711_STACK_QUERY_SINGLETHREADED_VALIDATE:\n      // TRD : query_input can be NULL\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      lfds711_stack_internal_stack_validate( ss, (struct lfds711_misc_validation_info *) query_input, (enum lfds711_misc_validity *) query_output );\n    break;\n  }\n\n  return;\n}\n\n\n\n\n\n/****************************************************************************/\nstatic void lfds711_stack_internal_stack_validate( struct lfds711_stack_state *ss,\n                                                   struct lfds711_misc_validation_info *vi,\n                                                   enum lfds711_misc_validity *lfds711_stack_validity )\n{\n  lfds711_pal_uint_t\n    number_elements = 0;\n\n  struct lfds711_stack_element\n    *se_fast,\n    *se_slow;\n\n  LFDS711_PAL_ASSERT( ss != NULL );\n  // TRD : vi can be NULL\n  LFDS711_PAL_ASSERT( lfds711_stack_validity != NULL );\n\n  *lfds711_stack_validity = LFDS711_MISC_VALIDITY_VALID;\n\n  se_slow = se_fast = (struct lfds711_stack_element *) ss->top[POINTER];\n\n  /* TRD : first, check for a loop\n           we have two pointers\n           both of which start at the top of the stack\n           we enter a loop\n           and on each iteration\n           we advance one pointer by one element\n           and the other by two\n\n           we exit the loop when both pointers are NULL\n           (have reached the end of the stack)\n\n           or\n\n           if we fast pointer 'sees' the slow pointer\n           which means we have a loop\n  */\n\n  if( se_slow != NULL )\n    do\n    {\n      se_slow = se_slow->next;\n\n      if( se_fast != NULL )\n        se_fast = se_fast->next;\n\n      if( se_fast != NULL )\n        se_fast = se_fast->next;\n    }\n    while( se_slow != NULL and se_fast != se_slow );\n\n  if( se_fast != NULL and se_slow != NULL and se_fast == se_slow )\n    *lfds711_stack_validity = LFDS711_MISC_VALIDITY_INVALID_LOOP;\n\n  /* TRD : now check for expected number of elements\n           vi can be NULL, in which case we do not check\n           we know we don't have a loop from our earlier check\n  */\n\n  if( *lfds711_stack_validity == LFDS711_MISC_VALIDITY_VALID and vi != NULL )\n  {\n    lfds711_stack_query( ss, LFDS711_STACK_QUERY_SINGLETHREADED_GET_COUNT, NULL, (void *) &number_elements );\n\n    if( number_elements < vi->min_elements )\n      *lfds711_stack_validity = LFDS711_MISC_VALIDITY_INVALID_MISSING_ELEMENTS;\n\n    if( number_elements > vi->max_elements )\n      *lfds711_stack_validity = LFDS711_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS;\n  }\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711/src/liblfds711_internal.h",
    "content": "/***** public prototypes *****/\n#include \"../inc/liblfds711.h\"\n\n/***** defines *****/\n#define and &&\n#define or  ||\n\n#define NO_FLAGS 0x0\n\n#define LFDS711_VERSION_STRING   \"7.1.1\"\n#define LFDS711_VERSION_INTEGER  711\n\n#if( defined KERNEL_MODE )\n  #define MODE_TYPE_STRING \"kernel-mode\"\n#endif\n\n#if( !defined KERNEL_MODE )\n  #define MODE_TYPE_STRING \"user-mode\"\n#endif\n\n#if( defined NDEBUG && !defined COVERAGE && !defined TSAN && !defined PROF )\n  #define BUILD_TYPE_STRING \"release\"\n#endif\n\n#if( !defined NDEBUG && !defined COVERAGE && !defined TSAN && !defined PROF )\n  #define BUILD_TYPE_STRING \"debug\"\n#endif\n\n#if( !defined NDEBUG && defined COVERAGE && !defined TSAN && !defined PROF )\n  #define BUILD_TYPE_STRING \"coverage\"\n#endif\n\n#if( !defined NDEBUG && !defined COVERAGE && defined TSAN && !defined PROF )\n  #define BUILD_TYPE_STRING \"threadsanitizer\"\n#endif\n\n#if( !defined NDEBUG && !defined COVERAGE && !defined TSAN && defined PROF )\n  #define BUILD_TYPE_STRING \"profiling\"\n#endif\n\n#define LFDS711_BACKOFF_INITIAL_VALUE  0\n#define LFDS711_BACKOFF_LIMIT          10\n\n#define LFDS711_BACKOFF_EXPONENTIAL_BACKOFF( backoff_state, backoff_iteration )                \\\n{                                                                                              \\\n  lfds711_pal_uint_t volatile                                                                  \\\n    loop;                                                                                      \\\n                                                                                               \\\n  lfds711_pal_uint_t                                                                           \\\n    endloop;                                                                                   \\\n                                                                                               \\\n  if( (backoff_iteration) == LFDS711_BACKOFF_LIMIT )                                           \\\n    (backoff_iteration) = LFDS711_BACKOFF_INITIAL_VALUE;                                       \\\n  else                                                                                         \\\n  {                                                                                            \\\n    endloop = ( ((lfds711_pal_uint_t) 0x1) << (backoff_iteration) ) * (backoff_state).metric;  \\\n    for( loop = 0 ; loop < endloop ; loop++ );                                                 \\\n  }                                                                                            \\\n                                                                                               \\\n  (backoff_iteration)++;                                                                       \\\n}\n\n#define LFDS711_BACKOFF_AUTOTUNE( bs, backoff_iteration )                                                                           \\\n{                                                                                                                                   \\\n  if( (backoff_iteration) < 2 )                                                                                                     \\\n    (bs).backoff_iteration_frequency_counters[(backoff_iteration)]++;                                                               \\\n                                                                                                                                    \\\n  if( ++(bs).total_operations >= 10000 and (bs).lock == LFDS711_MISC_FLAG_LOWERED )                                                 \\\n  {                                                                                                                                 \\\n    char unsigned                                                                                                                   \\\n      result;                                                                                                                       \\\n                                                                                                                                    \\\n    lfds711_pal_uint_t LFDS711_PAL_ALIGN(LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES)                                                     \\\n      compare = LFDS711_MISC_FLAG_LOWERED;                                                                                          \\\n                                                                                                                                    \\\n    LFDS711_PAL_ATOMIC_CAS( &(bs).lock, &compare, LFDS711_MISC_FLAG_RAISED, LFDS711_MISC_CAS_STRENGTH_WEAK, result );               \\\n                                                                                                                                    \\\n    if( result == 1 )                                                                                                               \\\n    {                                                                                                                               \\\n      /* TRD : if E[1] is less than 1/100th of E[0], decrease the metric, to increase E[1] */                                       \\\n      if( (bs).backoff_iteration_frequency_counters[1] < (bs).backoff_iteration_frequency_counters[0] / 100 )                       \\\n      {                                                                                                                             \\\n        if( (bs).metric >= 11 )                                                                                                     \\\n          (bs).metric -= 10;                                                                                                        \\\n      }                                                                                                                             \\\n      else                                                                                                                          \\\n        (bs).metric += 10;                                                                                                          \\\n                                                                                                                                    \\\n      (bs).backoff_iteration_frequency_counters[0] = 0;                                                                             \\\n      (bs).backoff_iteration_frequency_counters[1] = 0;                                                                             \\\n      (bs).total_operations = 0;                                                                                                    \\\n                                                                                                                                    \\\n      LFDS711_MISC_BARRIER_STORE;                                                                                                   \\\n                                                                                                                                    \\\n      LFDS711_PAL_ATOMIC_SET( &(bs).lock, LFDS711_MISC_FLAG_LOWERED );                                                              \\\n    }                                                                                                                               \\\n  }                                                                                                                                 \\\n}\n\n/***** library-wide prototypes *****/\nvoid lfds711_misc_internal_backoff_init( struct lfds711_misc_backoff_state *bs );\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/build/gcc_gnumake/Makefile",
    "content": "##### notes #####\n# TRD : -fno-strict-aliasing is needed because GCC has messed up type punning and __may_alias__ does absolutely nothing\n#       -Wno-unused-but-set-variable and -Wno-uninitialized are needed because GCC seems confused by the atomic intrinsics\n#       the code base for release has been compiled with those warnings enabled, to show any valid errors\n\n##### paths #####\nBINDIR    := ../../bin\nINCDIR    := ../../inc\nOBJDIR    := ../../obj\nSRCDIR    := ../../src\nINSINCDIR := /usr/local/include/\nINSLIBDIR := /usr/local/lib/\n\n##### misc #####\nQUIETLY        := 1>/dev/null 2>/dev/null\nVERSION_NUMBER := 1\nMINOR_NUMBER   := 0\nRELEASE_NUMBER := 0\n\n##### sources, objects and libraries #####\nBINNAME    := liblfds711\nARFILENAME := $(BINNAME).a\nARPATHNAME := $(BINDIR)/$(ARFILENAME)\nSOBASENAME := $(BINNAME).so\nSONAME     := $(SOBASENAME).$(VERSION_NUMBER)\nSOFILENAME := $(SONAME).$(MINOR_NUMBER).$(RELEASE_NUMBER)\nSOPATHNAME := $(BINDIR)/$(SOFILENAME)\nINCNAME    := $(INCDIR)/$(BINNAME).h\nSRCDIRS    := lfds711_btree_addonly_unbalanced lfds711_freelist lfds711_hash_addonly lfds711_list_addonly_singlylinked_ordered lfds711_list_addonly_singlylinked_unordered lfds711_misc lfds711_prng lfds711_queue_bounded_manyproducer_manyconsumer lfds711_queue_bounded_singleproducer_singleconsumer lfds711_queue_unbounded_manyproducer_manyconsumer lfds711_ringbuffer lfds711_stack\nSOURCES    := lfds711_hash_addonly_cleanup.c lfds711_hash_addonly_get.c lfds711_hash_addonly_init.c lfds711_hash_addonly_insert.c lfds711_hash_addonly_iterate.c lfds711_hash_addonly_query.c \\\n              lfds711_list_addonly_singlylinked_ordered_cleanup.c lfds711_list_addonly_singlylinked_ordered_get.c lfds711_list_addonly_singlylinked_ordered_init.c lfds711_list_addonly_singlylinked_ordered_insert.c lfds711_list_addonly_singlylinked_ordered_query.c \\\n              lfds711_list_addonly_singlylinked_unordered_cleanup.c lfds711_list_addonly_singlylinked_unordered_get.c lfds711_list_addonly_singlylinked_unordered_init.c lfds711_list_addonly_singlylinked_unordered_insert.c lfds711_list_addonly_singlylinked_unordered_query.c \\\n              lfds711_btree_addonly_unbalanced_cleanup.c lfds711_btree_addonly_unbalanced_get.c lfds711_btree_addonly_unbalanced_init.c lfds711_btree_addonly_unbalanced_insert.c lfds711_btree_addonly_unbalanced_query.c \\\n              lfds711_freelist_cleanup.c lfds711_freelist_init.c lfds711_freelist_pop.c lfds711_freelist_push.c lfds711_freelist_query.c \\\n              lfds711_misc_internal_backoff_init.c lfds711_misc_globals.c lfds711_misc_query.c \\\n              lfds711_prng_init.c \\\n              lfds711_queue_bounded_manyproducer_manyconsumer_cleanup.c lfds711_queue_bounded_manyproducer_manyconsumer_dequeue.c lfds711_queue_bounded_manyproducer_manyconsumer_enqueue.c lfds711_queue_bounded_manyproducer_manyconsumer_init.c lfds711_queue_bounded_manyproducer_manyconsumer_query.c \\\n              lfds711_queue_bounded_singleproducer_singleconsumer_cleanup.c lfds711_queue_bounded_singleproducer_singleconsumer_dequeue.c lfds711_queue_bounded_singleproducer_singleconsumer_enqueue.c lfds711_queue_bounded_singleproducer_singleconsumer_init.c lfds711_queue_bounded_singleproducer_singleconsumer_query.c \\\n              lfds711_queue_unbounded_manyproducer_manyconsumer_cleanup.c lfds711_queue_unbounded_manyproducer_manyconsumer_dequeue.c lfds711_queue_unbounded_manyproducer_manyconsumer_enqueue.c lfds711_queue_unbounded_manyproducer_manyconsumer_init.c lfds711_queue_unbounded_manyproducer_manyconsumer_query.c \\\n              lfds711_ringbuffer_cleanup.c lfds711_ringbuffer_init.c lfds711_ringbuffer_query.c lfds711_ringbuffer_read.c lfds711_ringbuffer_write.c \\\n              lfds711_stack_cleanup.c lfds711_stack_init.c lfds711_stack_pop.c lfds711_stack_push.c lfds711_stack_query.c\nOBJECTS    := $(patsubst %.c,$(OBJDIR)/%.o,$(notdir $(SOURCES)))\nSYSLIBS    := -lgcc\n\n##### tools #####\nDG                     := gcc\nDGFLAGS_MANDATORY      := -MM\nDGFLAGS_OPTIONAL       := -std=gnu89\n\nCC                     := gcc\nCFLAGS_MANDATORY       := -c -fno-strict-aliasing\nCFLAGS_OPTIONAL        := -ffreestanding -nostdinc -std=gnu89 -Wall -Werror -Wno-unknown-pragmas -Wno-unused-but-set-variable -Wno-uninitialized\nCFLAGS_MANDATORY_COV   := -O0 -ggdb -DCOVERAGE -fprofile-arcs -ftest-coverage\nCFLAGS_MANDATORY_DBG   := -O0 -ggdb -D_DEBUG\nCFLAGS_MANDATORY_PROF  := -O0 -ggdb -DPROF     -pg\nCFLAGS_MANDATORY_REL   := -O2       -DNDEBUG\nCFLAGS_MANDATORY_TSAN  := -O0 -ggdb -DTSAN     -fsanitize=thread -fPIC\n\nAR                     := ar\nARFLAGS                :=\nARFLAGS_MANDATORY      := rcs\nARFLAGS_OPTIONAL       :=\n\nLD                     := gcc\nLDFLAGS_MANDATORY      := -shared -Wl,-soname,$(SONAME) -o $(SOPATHNAME)\nLDFLAGS_OPTIONAL       := -nodefaultlibs -nostdlib -std=gnu89 -Wall -Werror\nLDFLAGS_MANDATORY_COV  := -O0 -fprofile-arcs -ftest-coverage\nLDFLAGS_MANDATORY_DBG  := -O0 -ggdb\nLDFLAGS_MANDATORY_PROF := -O0 -pg\nLDFLAGS_MANDATORY_REL  := -O2 -s\nLDFLAGS_MANDATORY_TSAN := -O0 -fsanitize=thread -fPIC\n\n##### build variants #####\nifeq ($(findstring so,$(MAKECMDGOALS)),so)\n  CFLAGS_MANDATORY += -fPIC\nendif\n\n# TRD : default to debug\nifeq ($(MAKECMDGOALS),)\n  CFLAGS_MANDATORY  += $(CFLAGS_MANDATORY_DBG)\n  LDFLAGS_MANDATORY += $(LDFLAGS_MANDATORY_DBG)\nendif\n\nifeq ($(findstring cov,$(MAKECMDGOALS)),cov)\n  CFLAGS_MANDATORY  += $(CFLAGS_MANDATORY_COV)\n  LDFLAGS_MANDATORY += $(LDFLAGS_MANDATORY_COV)\n  SYSLIBS += -lgcov\nendif\n\nifeq ($(findstring dbg,$(MAKECMDGOALS)),dbg)\n  CFLAGS_MANDATORY  += $(CFLAGS_MANDATORY_DBG)\n  LDFLAGS_MANDATORY += $(LDFLAGS_MANDATORY_DBG)\nendif\n\nifeq ($(findstring prof,$(MAKECMDGOALS)),prof)\n  CFLAGS_MANDATORY  += $(CFLAGS_MANDATORY_PROF)\n  LDFLAGS_MANDATORY += $(LDFLAGS_MANDATORY_PROF)\nendif\n\nifeq ($(findstring rel,$(MAKECMDGOALS)),rel)\n  CFLAGS_MANDATORY  += $(CFLAGS_MANDATORY_REL)\n  LDFLAGS_MANDATORY += $(LDFLAGS_MANDATORY_REL)\nendif\n\nifeq ($(findstring tsan,$(MAKECMDGOALS)),tsan)\n  CFLAGS_MANDATORY  += $(CFLAGS_MANDATORY_TSAN)\n  LDFLAGS_MANDATORY += $(LDFLAGS_MANDATORY_TSAN)\nendif\n\n##### search paths #####\nvpath %.c $(patsubst %,$(SRCDIR)/%:,$(SRCDIRS))\n\n##### implicit rules #####\n$(OBJDIR)/%.o : %.c\n\t$(DG) $(DGFLAGS_OPTIONAL) $(DGFLAGS) $(DGFLAGS_MANDATORY) $< >$(OBJDIR)/$*.d\n\t$(CC) $(CFLAGS_OPTIONAL) $(CFLAGS) $(CFLAGS_MANDATORY) -o $@ $<\n\n##### explicit rules #####\n$(ARPATHNAME) : $(OBJECTS)\n\t$(AR) $(ARFLAGS_OPTIONAL) $(ARFLAGS) $(ARFLAGS_MANDATORY) $(ARPATHNAME) $(OBJECTS)\n\n$(SOPATHNAME) : $(OBJECTS)\n\t$(LD) $(LDFLAGS_OPTIONAL) $(LDFLAGS) $(LDFLAGS_MANDATORY) $(OBJECTS) -lgcov -lgcc -o $(SOPATHNAME)\n\t@ln -fs $(SOFILENAME) $(BINDIR)/$(SONAME)\n\t@ln -fs $(SOFILENAME) $(BINDIR)/$(SOBASENAME)\n\n##### phony #####\n.PHONY : clean ar_cov ar_dbg ar_prof ar_rel ar_tsan ar_vanilla ar_install ar_uninstall so_dbg so_prof so_rel so_tsan so_vanilla so_install so_uninstall\n\nclean : \n\t@rm -f $(BINDIR)/* $(OBJDIR)/*\n\nar_cov       : $(ARPATHNAME) # archive (.a), coverage\nar_dbg       : $(ARPATHNAME) # archive (.a), debug\nar_prof      : $(ARPATHNAME) # archive (.a), profiling\nar_rel       : $(ARPATHNAME) # archive (.a), release\nar_tsan      : $(ARPATHNAME) # archive (.a), thread sanitizer\nar_vanilla   : $(ARPATHNAME) # archive (.a), no specific-build arguments\nar_install   :\n  # TRD : leading backslash to use command rather than alias\n  #       as many Linux distros have a built-in alias to force\n  #       a prompt (\"y/n?\") on file overwrite - silent and\n  #       unexpected interference which breaks a makefile\n\t@mkdir -p $(INSLIBDIR)\n\t@\\cp $(ARPATHNAME) $(INSLIBDIR)\n\t@mkdir -p $(INSINCDIR)\n\t@\\cp -r $(INCDIR)/* $(INSINCDIR)\nar_uninstall :\n\t@rm    $(INSLIBDIR)/$(ARFILENAME)\n\t@rm -r $(INSINCDIR)/$(BINNAME)\n\t@rm -r $(INSINCDIR)/$(BINNAME).h\n\n# TRD : so_cov currently disabled as it cannot work with -nostdlib -nodefaultlibs\n# so_cov       : $(SOPATHNAME) # shared (.so), coverage\nso_dbg       : $(SOPATHNAME) # shared (.so), debug\nso_prof      : $(SOPATHNAME) # shared (.so), profiling\nso_rel       : $(SOPATHNAME) # shared (.so), release\nso_tsan      : $(SOPATHNAME) # shared (.so), thread sanitizer\nso_vanilla   : $(SOPATHNAME) # shared (.so), no specific-build arguments\nso_install   : \n\t@mkdir -p $(INSINCDIR)\n\t@\\cp $(SOPATHNAME) $(INSLIBDIR)\n\t@ldconfig -vn $(INSLIBDIR)\n\t@ln -s $(SONAME) $(INSLIBDIR)/$(SOBASENAME)\n\t@mkdir -p $(INSLIBDIR)\n\t@\\cp -r $(INCDIR)/* $(INSINCDIR)\nso_uninstall : \n\t@rm -f $(INSLIBDIR)/$(SOFILENAME)\n\t@rm -f $(INSLIBDIR)/$(SOBASENAME)\n\t@rm -f $(INSLIBDIR)/$(SONAME)\n\t@rm -r $(INSINCDIR)/$(BINNAME)\n\t@rm -r $(INSINCDIR)/$(BINNAME).h\n\n##### dependencies #####\n-include $(DEPENDS)\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/build/gcc_gnumake_kbuild/Kbuild",
    "content": "lib-y :=\n\nlib-y += ../../src/lfds711_btree_addonly_unbalanced/lfds711_btree_addonly_unbalanced_cleanup.o\nlib-y += ../../src/lfds711_btree_addonly_unbalanced/lfds711_btree_addonly_unbalanced_get.o\nlib-y += ../../src/lfds711_btree_addonly_unbalanced/lfds711_btree_addonly_unbalanced_init.o\nlib-y += ../../src/lfds711_btree_addonly_unbalanced/lfds711_btree_addonly_unbalanced_insert.o\nlib-y += ../../src/lfds711_btree_addonly_unbalanced/lfds711_btree_addonly_unbalanced_query.o\n\nlib-y += ../../src/lfds711_freelist/lfds711_freelist_cleanup.o\nlib-y += ../../src/lfds711_freelist/lfds711_freelist_init.o\nlib-y += ../../src/lfds711_freelist/lfds711_freelist_pop.o\nlib-y += ../../src/lfds711_freelist/lfds711_freelist_push.o\nlib-y += ../../src/lfds711_freelist/lfds711_freelist_query.o\n\nlib-y += ../../src/lfds711_hash_addonly/lfds711_hash_addonly_cleanup.o\nlib-y += ../../src/lfds711_hash_addonly/lfds711_hash_addonly_get.o\nlib-y += ../../src/lfds711_hash_addonly/lfds711_hash_addonly_init.o\nlib-y += ../../src/lfds711_hash_addonly/lfds711_hash_addonly_insert.o\nlib-y += ../../src/lfds711_hash_addonly/lfds711_hash_addonly_iterate.o\nlib-y += ../../src/lfds711_hash_addonly/lfds711_hash_addonly_query.o\n\nlib-y += ../../src/lfds711_list_addonly_singlylinked_ordered/lfds711_list_addonly_singlylinked_ordered_cleanup.o\nlib-y += ../../src/lfds711_list_addonly_singlylinked_ordered/lfds711_list_addonly_singlylinked_ordered_get.o\nlib-y += ../../src/lfds711_list_addonly_singlylinked_ordered/lfds711_list_addonly_singlylinked_ordered_init.o\nlib-y += ../../src/lfds711_list_addonly_singlylinked_ordered/lfds711_list_addonly_singlylinked_ordered_insert.o\nlib-y += ../../src/lfds711_list_addonly_singlylinked_ordered/lfds711_list_addonly_singlylinked_ordered_query.o\n\nlib-y += ../../src/lfds711_list_addonly_singlylinked_unordered/lfds711_list_addonly_singlylinked_unordered_cleanup.o\nlib-y += ../../src/lfds711_list_addonly_singlylinked_unordered/lfds711_list_addonly_singlylinked_unordered_get.o\nlib-y += ../../src/lfds711_list_addonly_singlylinked_unordered/lfds711_list_addonly_singlylinked_unordered_init.o\nlib-y += ../../src/lfds711_list_addonly_singlylinked_unordered/lfds711_list_addonly_singlylinked_unordered_insert.o\nlib-y += ../../src/lfds711_list_addonly_singlylinked_unordered/lfds711_list_addonly_singlylinked_unordered_query.o\n\nlib-y += ../../src/lfds711_misc/lfds711_misc_internal_backoff_init.o\nlib-y += ../../src/lfds711_misc/lfds711_misc_globals.o\nlib-y += ../../src/lfds711_misc/lfds711_misc_query.o\n\nlib-y += ../../src/lfds711_prng/lfds711_prng_init.o\n\nlib-y += ../../src/lfds711_queue_bounded_manyproducer_manyconsumer/lfds711_queue_bounded_manyproducer_manyconsumer_cleanup.o\nlib-y += ../../src/lfds711_queue_bounded_manyproducer_manyconsumer/lfds711_queue_bounded_manyproducer_manyconsumer_dequeue.o\nlib-y += ../../src/lfds711_queue_bounded_manyproducer_manyconsumer/lfds711_queue_bounded_manyproducer_manyconsumer_enqueue.o\nlib-y += ../../src/lfds711_queue_bounded_manyproducer_manyconsumer/lfds711_queue_bounded_manyproducer_manyconsumer_init.o\nlib-y += ../../src/lfds711_queue_bounded_manyproducer_manyconsumer/lfds711_queue_bounded_manyproducer_manyconsumer_query.o\n\nlib-y += ../../src/lfds711_queue_bounded_singleproducer_singleconsumer/lfds711_queue_bounded_singleproducer_singleconsumer_cleanup.o\nlib-y += ../../src/lfds711_queue_bounded_singleproducer_singleconsumer/lfds711_queue_bounded_singleproducer_singleconsumer_dequeue.o\nlib-y += ../../src/lfds711_queue_bounded_singleproducer_singleconsumer/lfds711_queue_bounded_singleproducer_singleconsumer_enqueue.o\nlib-y += ../../src/lfds711_queue_bounded_singleproducer_singleconsumer/lfds711_queue_bounded_singleproducer_singleconsumer_init.o\nlib-y += ../../src/lfds711_queue_bounded_singleproducer_singleconsumer/lfds711_queue_bounded_singleproducer_singleconsumer_query.o\n\nlib-y += ../../src/lfds711_queue_unbounded_manyproducer_manyconsumer/lfds711_queue_unbounded_manyproducer_manyconsumer_cleanup.o\nlib-y += ../../src/lfds711_queue_unbounded_manyproducer_manyconsumer/lfds711_queue_unbounded_manyproducer_manyconsumer_dequeue.o\nlib-y += ../../src/lfds711_queue_unbounded_manyproducer_manyconsumer/lfds711_queue_unbounded_manyproducer_manyconsumer_enqueue.o\nlib-y += ../../src/lfds711_queue_unbounded_manyproducer_manyconsumer/lfds711_queue_unbounded_manyproducer_manyconsumer_init.o\nlib-y += ../../src/lfds711_queue_unbounded_manyproducer_manyconsumer/lfds711_queue_unbounded_manyproducer_manyconsumer_query.o\n\nlib-y += ../../src/lfds711_ringbuffer/lfds711_ringbuffer_cleanup.o\nlib-y += ../../src/lfds711_ringbuffer/lfds711_ringbuffer_init.o\nlib-y += ../../src/lfds711_ringbuffer/lfds711_ringbuffer_query.o\nlib-y += ../../src/lfds711_ringbuffer/lfds711_ringbuffer_read.o\nlib-y += ../../src/lfds711_ringbuffer/lfds711_ringbuffer_write.o\n\nlib-y += ../../src/lfds711_stack/lfds711_stack_cleanup.o\nlib-y += ../../src/lfds711_stack/lfds711_stack_init.o\nlib-y += ../../src/lfds711_stack/lfds711_stack_pop.o\nlib-y += ../../src/lfds711_stack/lfds711_stack_push.o\nlib-y += ../../src/lfds711_stack/lfds711_stack_query.o\n\nlibs-y := ../../bin/\n\nccflags-y := -I$(src)/../../inc\nccflags-y += -I$(src)/../../inc/liblfds711\nccflags-y += -DKERNEL_MODE\nccflags-y += -DNDEBUG\nccflags-y += -fno-strict-aliasing\nccflags-y += -std=gnu89\nccflags-y += -Wall\nccflags-y += -Werror\nccflags-y += -Wno-unknown-pragmas\nccflags-y += -Wno-unused-but-set-variable\nccflags-y += -Wno-uninitialized\n\n\n\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/build/gcc_gnumake_kbuild/Makefile",
    "content": "default:\n\t$(MAKE) -C /lib/modules/`uname -r`/build M=$(PWD)\n\nclean:\n\t$(MAKE) -C /lib/modules/`uname -r`/build M=$(PWD) clean\n\tfind ../../src/ -name \"*.o\" -type f -delete\n\nhelp:\n\t$(MAKE) -C /lib/modules/`uname -r`/build M=$(PWD) help\n\nmodules:\n\t$(MAKE) -C /lib/modules/`uname -r`/build M=$(PWD) modules\n\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/build/msvc_gnumake/liblfds711.def",
    "content": "EXPORTS\n\nlfds711_btree_au_init_valid_on_current_logical_core = lfds711_btree_au_init_valid_on_current_logical_core\nlfds711_btree_au_cleanup = lfds711_btree_au_cleanup\nlfds711_btree_au_insert = lfds711_btree_au_insert\nlfds711_btree_au_get_by_key = lfds711_btree_au_get_by_key\nlfds711_btree_au_get_by_absolute_position_and_then_by_relative_position = lfds711_btree_au_get_by_absolute_position_and_then_by_relative_position\nlfds711_btree_au_get_by_absolute_position = lfds711_btree_au_get_by_absolute_position\nlfds711_btree_au_get_by_relative_position = lfds711_btree_au_get_by_relative_position\nlfds711_btree_au_query = lfds711_btree_au_query\n\nlfds711_freelist_init_valid_on_current_logical_core = lfds711_freelist_init_valid_on_current_logical_core\nlfds711_freelist_cleanup = lfds711_freelist_cleanup\nlfds711_freelist_push = lfds711_freelist_push\nlfds711_freelist_pop = lfds711_freelist_pop\nlfds711_freelist_query = lfds711_freelist_query\n\nlfds711_hash_a_init_valid_on_current_logical_core = lfds711_hash_a_init_valid_on_current_logical_core\nlfds711_hash_a_cleanup = lfds711_hash_a_cleanup\nlfds711_hash_a_insert = lfds711_hash_a_insert\nlfds711_hash_a_get_by_key = lfds711_hash_a_get_by_key\nlfds711_hash_a_iterate_init = lfds711_hash_a_iterate_init\nlfds711_hash_a_iterate = lfds711_hash_a_iterate\nlfds711_hash_a_query = lfds711_hash_a_query\n\nlfds711_list_aso_init_valid_on_current_logical_core = lfds711_list_aso_init_valid_on_current_logical_core\nlfds711_list_aso_cleanup = lfds711_list_aso_cleanup\nlfds711_list_aso_insert = lfds711_list_aso_insert\nlfds711_list_aso_get_by_key = lfds711_list_aso_get_by_key\nlfds711_list_aso_query = lfds711_list_aso_query\n\nlfds711_list_asu_init_valid_on_current_logical_core = lfds711_list_asu_init_valid_on_current_logical_core\nlfds711_list_asu_cleanup = lfds711_list_asu_cleanup\nlfds711_list_asu_insert_at_position = lfds711_list_asu_insert_at_position\nlfds711_list_asu_insert_at_start = lfds711_list_asu_insert_at_start\nlfds711_list_asu_insert_at_end = lfds711_list_asu_insert_at_end\nlfds711_list_asu_insert_after_element = lfds711_list_asu_insert_after_element\nlfds711_list_asu_get_by_key = lfds711_list_asu_get_by_key\nlfds711_list_asu_query = lfds711_list_asu_query\n\nlfds711_misc_query = lfds711_misc_query\n\nlfds711_prng_init_valid_on_current_logical_core = lfds711_prng_init_valid_on_current_logical_core\nlfds711_prng_st_init = lfds711_prng_st_init\n\nlfds711_queue_bmm_init_valid_on_current_logical_core = lfds711_queue_bmm_init_valid_on_current_logical_core\nlfds711_queue_bmm_cleanup = lfds711_queue_bmm_cleanup\nlfds711_queue_bmm_enqueue = lfds711_queue_bmm_enqueue\nlfds711_queue_bmm_dequeue = lfds711_queue_bmm_dequeue\nlfds711_queue_bmm_query = lfds711_queue_bmm_query\n\nlfds711_queue_bss_init_valid_on_current_logical_core = lfds711_queue_bss_init_valid_on_current_logical_core\nlfds711_queue_bss_cleanup = lfds711_queue_bss_cleanup\nlfds711_queue_bss_enqueue = lfds711_queue_bss_enqueue\nlfds711_queue_bss_dequeue = lfds711_queue_bss_dequeue\nlfds711_queue_bss_query = lfds711_queue_bss_query\n\nlfds711_queue_umm_init_valid_on_current_logical_core = lfds711_queue_umm_init_valid_on_current_logical_core\nlfds711_queue_umm_cleanup = lfds711_queue_umm_cleanup\nlfds711_queue_umm_enqueue = lfds711_queue_umm_enqueue\nlfds711_queue_umm_dequeue = lfds711_queue_umm_dequeue\nlfds711_queue_umm_query = lfds711_queue_umm_query\n\nlfds711_ringbuffer_init_valid_on_current_logical_core = lfds711_ringbuffer_init_valid_on_current_logical_core\nlfds711_ringbuffer_cleanup = lfds711_ringbuffer_cleanup\nlfds711_ringbuffer_read = lfds711_ringbuffer_read\nlfds711_ringbuffer_write = lfds711_ringbuffer_write\nlfds711_ringbuffer_query = lfds711_ringbuffer_query\n\nlfds711_stack_init_valid_on_current_logical_core = lfds711_stack_init_valid_on_current_logical_core\nlfds711_stack_cleanup = lfds711_stack_cleanup\nlfds711_stack_push = lfds711_stack_push\nlfds711_stack_pop = lfds711_stack_pop\nlfds711_stack_query = lfds711_stack_query\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/build/msvc_gnumake/makefile",
    "content": "##### paths #####\nBINDIR := ..\\..\\bin\nINCDIR := ..\\..\\inc\nOBJDIR := ..\\..\\obj\nSRCDIR := ..\\..\\src\n\n##### misc #####\nQUIETLY := 1>nul 2>nul\nNULL := \nSPACE := $(NULL) # TRD : with a trailing space\n\n##### sources, objects and libraries #####\nBINNAME    := liblfds711\nLIB_BINARY := $(BINDIR)\\$(BINNAME).lib\nDLL_BINARY := $(BINDIR)\\$(BINNAME).dll\nSRCDIRS    := lfds711_btree_addonly_unbalanced lfds711_freelist lfds711_hash_addonly lfds711_list_addonly_singlylinked_ordered lfds711_list_addonly_singlylinked_unordered lfds711_misc lfds711_prng lfds711_queue_bounded_manyproducer_manyconsumer lfds711_queue_bounded_singleproducer_singleconsumer lfds711_queue_unbounded_manyproducer_manyconsumer lfds711_ringbuffer lfds711_stack\nSOURCES    := lfds711_hash_addonly_cleanup.c lfds711_hash_addonly_get.c lfds711_hash_addonly_init.c lfds711_hash_addonly_insert.c lfds711_hash_addonly_iterate.c lfds711_hash_addonly_query.c \\\n              lfds711_list_addonly_singlylinked_ordered_cleanup.c lfds711_list_addonly_singlylinked_ordered_get.c lfds711_list_addonly_singlylinked_ordered_init.c lfds711_list_addonly_singlylinked_ordered_insert.c lfds711_list_addonly_singlylinked_ordered_query.c \\\n              lfds711_list_addonly_singlylinked_unordered_cleanup.c lfds711_list_addonly_singlylinked_unordered_get.c lfds711_list_addonly_singlylinked_unordered_init.c lfds711_list_addonly_singlylinked_unordered_insert.c lfds711_list_addonly_singlylinked_unordered_query.c \\\n              lfds711_btree_addonly_unbalanced_cleanup.c lfds711_btree_addonly_unbalanced_get.c lfds711_btree_addonly_unbalanced_init.c lfds711_btree_addonly_unbalanced_insert.c lfds711_btree_addonly_unbalanced_query.c \\\n              lfds711_freelist_cleanup.c lfds711_freelist_init.c lfds711_freelist_pop.c lfds711_freelist_push.c lfds711_freelist_query.c \\\n              lfds711_misc_internal_backoff_init.c lfds711_misc_globals.c lfds711_misc_query.c \\\n              lfds711_prng_init.c \\\n              lfds711_queue_bounded_manyproducer_manyconsumer_cleanup.c lfds711_queue_bounded_manyproducer_manyconsumer_dequeue.c lfds711_queue_bounded_manyproducer_manyconsumer_enqueue.c lfds711_queue_bounded_manyproducer_manyconsumer_init.c lfds711_queue_bounded_manyproducer_manyconsumer_query.c \\\n              lfds711_queue_bounded_singleproducer_singleconsumer_cleanup.c lfds711_queue_bounded_singleproducer_singleconsumer_dequeue.c lfds711_queue_bounded_singleproducer_singleconsumer_enqueue.c lfds711_queue_bounded_singleproducer_singleconsumer_init.c lfds711_queue_bounded_singleproducer_singleconsumer_query.c \\\n              lfds711_queue_unbounded_manyproducer_manyconsumer_cleanup.c lfds711_queue_unbounded_manyproducer_manyconsumer_dequeue.c lfds711_queue_unbounded_manyproducer_manyconsumer_enqueue.c lfds711_queue_unbounded_manyproducer_manyconsumer_init.c lfds711_queue_unbounded_manyproducer_manyconsumer_query.c \\\n              lfds711_ringbuffer_cleanup.c lfds711_ringbuffer_init.c lfds711_ringbuffer_query.c lfds711_ringbuffer_read.c lfds711_ringbuffer_write.c \\\n              lfds711_stack_cleanup.c lfds711_stack_init.c lfds711_stack_pop.c lfds711_stack_push.c lfds711_stack_query.c\nOBJECTS    := $(patsubst %.c,$(OBJDIR)/%.obj,$(notdir $(SOURCES)))\nSYSLIBS    := kernel32.lib\n\n##### default paths fix up #####\nINCDIRS := $(patsubst %,%;,$(INCDIR))\nINCLUDE += $(subst $(SPACE),,$(INCDIRS))\n\n##### tools #####\nCC                    := cl\nCFLAGS_MANDATORY      := /c \"/Fd$(BINDIR)\\$(BINNAME).pdb\" /wd 4068\nCFLAGS_OPTIONAL       := /DWIN32_LEAN_AND_MEAN /DUNICODE /D_UNICODE /nologo /W4 /WX\nCFLAGS_MANDATORY_DBG  := /Od /Gm /Zi /D_DEBUG\nCFLAGS_MANDATORY_REL  := /Ox /DNDEBUG\n\nAR                    := lib\nARFLAGS               :=\nARFLAGS_MANDATORY     := /subsystem:console\nARFLAGS_OPTIONAL      := /nologo /wx /verbose\n\nLD                    := link\nLDFLAGS_MANDATORY     := /def:$(BINNAME).def /dll /nodefaultlib /subsystem:console\nLDFLAGS_OPTIONAL      := /nologo /nxcompat /wx\nLDFLAGS_MANDATORY_DBG := /debug \"/pdb:$(BINDIR)\\$(BINNAME).pdb\"\nLDFLAGS_MANDATORY_REL := /incremental:no\n\n##### variants #####\nifeq ($(MAKECMDGOALS),) # TRD : default to debug lib\n  CFLAGS_MANDATORY  += $(CFLAGS_MANDATORY_DBG)\n  LDFLAGS_MANDATORY += $(LDFLAGS_MANDATORY_DBG)\n  CLIB              := libcmtd.lib\nendif\n\nifeq ($(MAKECMDGOALS),libdbg)\n  CFLAGS_MANDATORY  += $(CFLAGS_MANDATORY_DBG)\n  LDFLAGS_MANDATORY += $(LDFLAGS_MANDATORY_DBG)\n  CLIB              := libcmtd.lib\nendif\n\nifeq ($(MAKECMDGOALS),librel)\n  CFLAGS_MANDATORY  += $(CFLAGS_MANDATORY_REL)\n  LDFLAGS_MANDATORY += $(LDFLAGS_MANDATORY_REL)\n  CLIB              := libcmt.lib\nendif\n\nifeq ($(MAKECMDGOALS),dlldbg)\n  CFLAGS_MANDATORY  += $(CFLAGS_MANDATORY_DBG)\n  LDFLAGS_MANDATORY += $(LDFLAGS_MANDATORY_DBG)\n  CLIB              := msvcrtd.lib\nendif\n\nifeq ($(MAKECMDGOALS),dllrel)\n  CFLAGS_MANDATORY  += $(CFLAGS_MANDATORY_REL)\n  LDFLAGS_MANDATORY += $(LDFLAGS_MANDATORY_REL)\n  CLIB              := msvcrt.lib\nendif\n\n##### search paths #####\nvpath %.c $(patsubst %,$(SRCDIR)/%;,$(SRCDIRS))\n\n##### implicit rules #####\n$(OBJDIR)/%.obj : %.c\n\t$(CC) $(CFLAGS_OPTIONAL) $(CFLAGS) $(CFLAGS_MANDATORY) \"/Fo$@\" $<\n\n##### explicit rules #####\n$(LIB_BINARY) : $(OBJECTS)\n\t$(AR) $(ARFLAGS_OPTIONAL) $(ARFLAGS) $(ARFLAGS_MANDATORY) $(OBJECTS) /out:$(LIB_BINARY)\n\n$(DLL_BINARY) : $(OBJECTS)\n\t$(LD) $(LDFLAGS_OPTIONAL) $(LDFLAGS) $(LDFLAGS_MANDATORY) $(CLIB) $(SYSLIBS) $(OBJECTS) /out:$(DLL_BINARY)\n\n##### phony #####\n.PHONY : clean librel libdbg dllrel dlldbg\n\nclean : \n\t@erase /Q $(BINDIR)\\$(BINNAME).* $(OBJDIR)\\*.obj $(QUIETLY)\n\ndllrel : $(DLL_BINARY)\ndlldbg : $(DLL_BINARY)\n\nlibrel : $(LIB_BINARY)\nlibdbg : $(LIB_BINARY)\n\n##### notes #####\n# /wd 4068 : turn off \"unknown pragma\" warning\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/build/wdk_7.1/dirs",
    "content": "DIRS = single_dir_for_windows_kernel\n\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/build/wdk_7.1/driver_entry_renamed_to_avoid_compiler_warning.c",
    "content": "#include \"liblfds711_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nDRIVER_INITIALIZE DriverEntry;\n\n\n\n\n\n/****************************************************************************/\n#pragma warning( disable : 4100 )\n\nNTSTATUS DriverEntry( struct _DRIVER_OBJECT *DriverObject, PUNICODE_STRING RegistryPath )\n{\n\treturn STATUS_SUCCESS;\n}\n\n#pragma warning( default : 4100 )\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/build/wdk_7.1/liblfds711.def",
    "content": "EXPORTS\n\nlfds711_btree_au_init_valid_on_current_logical_core = lfds711_btree_au_init_valid_on_current_logical_core\nlfds711_btree_au_cleanup = lfds711_btree_au_cleanup\nlfds711_btree_au_insert = lfds711_btree_au_insert\nlfds711_btree_au_get_by_key = lfds711_btree_au_get_by_key\nlfds711_btree_au_get_by_absolute_position_and_then_by_relative_position = lfds711_btree_au_get_by_absolute_position_and_then_by_relative_position\nlfds711_btree_au_get_by_absolute_position = lfds711_btree_au_get_by_absolute_position\nlfds711_btree_au_get_by_relative_position = lfds711_btree_au_get_by_relative_position\nlfds711_btree_au_query = lfds711_btree_au_query\n\nlfds711_freelist_init_valid_on_current_logical_core = lfds711_freelist_init_valid_on_current_logical_core\nlfds711_freelist_cleanup = lfds711_freelist_cleanup\nlfds711_freelist_push = lfds711_freelist_push\nlfds711_freelist_pop = lfds711_freelist_pop\nlfds711_freelist_query = lfds711_freelist_query\n\nlfds711_hash_a_init_valid_on_current_logical_core = lfds711_hash_a_init_valid_on_current_logical_core\nlfds711_hash_a_cleanup = lfds711_hash_a_cleanup\nlfds711_hash_a_insert = lfds711_hash_a_insert\nlfds711_hash_a_get_by_key = lfds711_hash_a_get_by_key\nlfds711_hash_a_iterate_init = lfds711_hash_a_iterate_init\nlfds711_hash_a_iterate = lfds711_hash_a_iterate\nlfds711_hash_a_query = lfds711_hash_a_query\n\nlfds711_list_aso_init_valid_on_current_logical_core = lfds711_list_aso_init_valid_on_current_logical_core\nlfds711_list_aso_cleanup = lfds711_list_aso_cleanup\nlfds711_list_aso_insert = lfds711_list_aso_insert\nlfds711_list_aso_get_by_key = lfds711_list_aso_get_by_key\nlfds711_list_aso_query = lfds711_list_aso_query\n\nlfds711_list_asu_init_valid_on_current_logical_core = lfds711_list_asu_init_valid_on_current_logical_core\nlfds711_list_asu_cleanup = lfds711_list_asu_cleanup\nlfds711_list_asu_insert_at_position = lfds711_list_asu_insert_at_position\nlfds711_list_asu_insert_at_start = lfds711_list_asu_insert_at_start\nlfds711_list_asu_insert_at_end = lfds711_list_asu_insert_at_end\nlfds711_list_asu_insert_after_element = lfds711_list_asu_insert_after_element\nlfds711_list_asu_get_by_key = lfds711_list_asu_get_by_key\nlfds711_list_asu_query = lfds711_list_asu_query\n\nlfds711_misc_query = lfds711_misc_query\n\nlfds711_prng_init_valid_on_current_logical_core = lfds711_prng_init_valid_on_current_logical_core\nlfds711_prng_st_init = lfds711_prng_st_init\n\nlfds711_queue_bmm_init_valid_on_current_logical_core = lfds711_queue_bmm_init_valid_on_current_logical_core\nlfds711_queue_bmm_cleanup = lfds711_queue_bmm_cleanup\nlfds711_queue_bmm_enqueue = lfds711_queue_bmm_enqueue\nlfds711_queue_bmm_dequeue = lfds711_queue_bmm_dequeue\nlfds711_queue_bmm_query = lfds711_queue_bmm_query\n\nlfds711_queue_bss_init_valid_on_current_logical_core = lfds711_queue_bss_init_valid_on_current_logical_core\nlfds711_queue_bss_cleanup = lfds711_queue_bss_cleanup\nlfds711_queue_bss_enqueue = lfds711_queue_bss_enqueue\nlfds711_queue_bss_dequeue = lfds711_queue_bss_dequeue\nlfds711_queue_bss_query = lfds711_queue_bss_query\n\nlfds711_queue_umm_init_valid_on_current_logical_core = lfds711_queue_umm_init_valid_on_current_logical_core\nlfds711_queue_umm_cleanup = lfds711_queue_umm_cleanup\nlfds711_queue_umm_enqueue = lfds711_queue_umm_enqueue\nlfds711_queue_umm_dequeue = lfds711_queue_umm_dequeue\nlfds711_queue_umm_query = lfds711_queue_umm_query\n\nlfds711_ringbuffer_init_valid_on_current_logical_core = lfds711_ringbuffer_init_valid_on_current_logical_core\nlfds711_ringbuffer_cleanup = lfds711_ringbuffer_cleanup\nlfds711_ringbuffer_read = lfds711_ringbuffer_read\nlfds711_ringbuffer_write = lfds711_ringbuffer_write\nlfds711_ringbuffer_query = lfds711_ringbuffer_query\n\nlfds711_stack_init_valid_on_current_logical_core = lfds711_stack_init_valid_on_current_logical_core\nlfds711_stack_cleanup = lfds711_stack_cleanup\nlfds711_stack_push = lfds711_stack_push\nlfds711_stack_pop = lfds711_stack_pop\nlfds711_stack_query = lfds711_stack_query\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/build/wdk_7.1/readme_before_win_kernel_build.txt",
    "content": "The Windows kernel build environment is primitive and has a number\nof severe limitations; in particular, all source files must be in\none directory and it is not possible to choose the output binary type\n(static or dynamic library) from the build command line; rather,\na string has to be modified in a text file used by the build (!)\n\nTo deal with these limitations, it is necessary for a Windows kernel\nbuild to run a batch file prior to building.\n\nThere are two batch files, one for static library builds and the other\nfor dynamic library builds.\n\nThey are both idempotent; you can run them as often as you like and\nswitch between them as often as you want.  It's all fine; whenever\nyou run one of them, it will take you from whatever state you were\npreviously in, into the state you want to be in.\n\nBoth batch files copy all the sources file into a single directory,\n\"/src/single_dir_for_windows_kernel/\".\n\nThe static library batch file will then copy \"/sources.static\" into\n\"/src/single_dir_for_windows_kernel/\", which will cause a static\nlibrary to be built.\n\nThe dynamic library batch file will then copy \"/sources.dynamic\" into\n\"/src/single_dir_for_windows_kernel/\", which will cause a dynamic\nlibrary to be built.  It will also copy \"src/driver_entry.c\" into\n\"/src/single_dir_for_windows_kernel/\", since the linker requires\nthe DriverEntry function to exist for dynamic libraries, even\nthough it's not used.\n\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/build/wdk_7.1/runme_before_win_kernel_dynamic_lib_build.bat",
    "content": "@echo off\r\nrmdir /q /s single_dir_for_windows_kernel                                                                              1>nul 2>nul\r\nmkdir single_dir_for_windows_kernel                                                                                    1>nul 2>nul\r\n\r\ncopy /y ..\\..\\src\\lfds711_btree_addonly_unbalanced\\*                     single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_freelist\\*                                     single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_hash_addonly\\*                                 single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_list_addonly_singlylinked_ordered\\*            single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_list_addonly_singlylinked_unordered\\*          single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_misc\\*                                         single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_prng\\*                                         single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_queue_bounded_manyproducer_manyconsumer\\*      single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_queue_bounded_singleproducer_singleconsumer\\*  single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_queue_unbounded_manyproducer_manyconsumer\\*    single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_ringbuffer\\*                                   single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_stack\\*                                        single_dir_for_windows_kernel\\                1>nul 2>nul\r\n\r\ncopy /y ..\\..\\src\\liblfds711_internal.h                                  single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y driver_entry_renamed_to_avoid_compiler_warning.c                 single_dir_for_windows_kernel\\driver_entry.c  1>nul 2>nul\r\ncopy /y sources.dynamic                                                  single_dir_for_windows_kernel\\sources         1>nul 2>nul\r\n\r\necho Windows kernel dynamic library build directory structure created.\r\necho (Note the effects of this batch file are idempotent).\r\n\r\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/build/wdk_7.1/runme_before_win_kernel_static_lib_build.bat",
    "content": "@echo off\r\nrmdir /q /s single_dir_for_windows_kernel                                                                              1>nul 2>nul\r\nmkdir single_dir_for_windows_kernel                                                                                    1>nul 2>nul\r\n\r\ncopy /y ..\\..\\src\\lfds711_btree_addonly_unbalanced\\*                     single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_freelist\\*                                     single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_hash_addonly\\*                                 single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_list_addonly_singlylinked_ordered\\*            single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_list_addonly_singlylinked_unordered\\*          single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_misc\\*                                         single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_prng\\*                                         single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_queue_bounded_manyproducer_manyconsumer\\*      single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_queue_bounded_singleproducer_singleconsumer\\*  single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_queue_unbounded_manyproducer_manyconsumer\\*    single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_ringbuffer\\*                                   single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y ..\\..\\src\\lfds711_stack\\*                                        single_dir_for_windows_kernel\\                1>nul 2>nul\r\n\r\ncopy /y ..\\..\\src\\liblfds711_internal.h                                  single_dir_for_windows_kernel\\                1>nul 2>nul\r\ncopy /y sources.static                                                   single_dir_for_windows_kernel\\sources         1>nul 2>nul\r\n\r\necho Windows kernel static library build directory structure created.\r\necho (Note the effects of this batch file are idempotent).\r\n\r\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/build/wdk_7.1/sources.dynamic",
    "content": "MSC_WARNING_LEVEL = /WX /wd4127 /W4\nDLLDEF            = ../liblfds711.def\nTARGETNAME        = liblfds711\nTARGETPATH        = ../../../bin/\nTARGETTYPE        = EXPORT_DRIVER\nUMTYPE            = nt\nUSER_C_FLAGS      = /DKERNEL_MODE /DNDEBUG\n\nINCLUDES = ../../../inc/\nSOURCES  = lfds711_btree_addonly_unbalanced_cleanup.c \\\n           lfds711_btree_addonly_unbalanced_get.c \\\n           lfds711_btree_addonly_unbalanced_init.c \\\n           lfds711_btree_addonly_unbalanced_insert.c \\\n           lfds711_btree_addonly_unbalanced_query.c \\\n           lfds711_freelist_cleanup.c \\\n           lfds711_freelist_init.c \\\n           lfds711_freelist_pop.c \\\n           lfds711_freelist_push.c \\\n           lfds711_freelist_query.c \\\n           lfds711_hash_addonly_cleanup.c \\\n           lfds711_hash_addonly_get.c \\\n           lfds711_hash_addonly_init.c \\\n           lfds711_hash_addonly_insert.c \\\n           lfds711_hash_addonly_iterate.c \\\n           lfds711_hash_addonly_query.c \\\n           lfds711_list_addonly_singlylinked_ordered_cleanup.c \\\n           lfds711_list_addonly_singlylinked_ordered_get.c \\\n           lfds711_list_addonly_singlylinked_ordered_init.c \\\n           lfds711_list_addonly_singlylinked_ordered_insert.c \\\n           lfds711_list_addonly_singlylinked_ordered_query.c \\\n           lfds711_list_addonly_singlylinked_unordered_cleanup.c \\\n           lfds711_list_addonly_singlylinked_unordered_get.c \\\n           lfds711_list_addonly_singlylinked_unordered_init.c \\\n           lfds711_list_addonly_singlylinked_unordered_insert.c \\\n           lfds711_list_addonly_singlylinked_unordered_query.c \\\n           lfds711_misc_globals.c \\\n           lfds711_misc_internal_backoff_init.c \\\n           lfds711_misc_query.c \\\n           lfds711_prng_init.c \\\n           lfds711_queue_bounded_manyproducer_manyconsumer_cleanup.c \\\n           lfds711_queue_bounded_manyproducer_manyconsumer_dequeue.c \\\n           lfds711_queue_bounded_manyproducer_manyconsumer_enqueue.c \\\n           lfds711_queue_bounded_manyproducer_manyconsumer_init.c \\\n           lfds711_queue_bounded_manyproducer_manyconsumer_query.c \\\n           lfds711_queue_bounded_singleproducer_singleconsumer_cleanup.c \\\n           lfds711_queue_bounded_singleproducer_singleconsumer_dequeue.c \\\n           lfds711_queue_bounded_singleproducer_singleconsumer_enqueue.c \\\n           lfds711_queue_bounded_singleproducer_singleconsumer_init.c \\\n           lfds711_queue_bounded_singleproducer_singleconsumer_query.c \\\n           lfds711_queue_unbounded_manyproducer_manyconsumer_cleanup.c \\\n           lfds711_queue_unbounded_manyproducer_manyconsumer_dequeue.c \\\n           lfds711_queue_unbounded_manyproducer_manyconsumer_enqueue.c \\\n           lfds711_queue_unbounded_manyproducer_manyconsumer_init.c \\\n           lfds711_queue_unbounded_manyproducer_manyconsumer_query.c \\\n           lfds711_ringbuffer_cleanup.c \\\n           lfds711_ringbuffer_init.c \\\n           lfds711_ringbuffer_query.c \\\n           lfds711_ringbuffer_read.c \\\n           lfds711_ringbuffer_write.c \\\n           lfds711_stack_cleanup.c \\\n           lfds711_stack_init.c \\\n           lfds711_stack_pop.c \\\n           lfds711_stack_push.c \\\n           lfds711_stack_query.c \\\n           driver_entry.c\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/build/wdk_7.1/sources.static",
    "content": "MSC_WARNING_LEVEL = /WX /wd4127 /W4\nTARGETNAME        = liblfds711\nTARGETPATH        = ../../../bin/\nTARGETTYPE        = DRIVER_LIBRARY\nUMTYPE            = nt\nUSER_C_FLAGS      = /DKERNEL_MODE /DNDEBUG\n\nINCLUDES = ../../../inc/\nSOURCES  = lfds711_btree_addonly_unbalanced_cleanup.c \\\n           lfds711_btree_addonly_unbalanced_get.c \\\n           lfds711_btree_addonly_unbalanced_init.c \\\n           lfds711_btree_addonly_unbalanced_insert.c \\\n           lfds711_btree_addonly_unbalanced_query.c \\\n           lfds711_freelist_cleanup.c \\\n           lfds711_freelist_init.c \\\n           lfds711_freelist_pop.c \\\n           lfds711_freelist_push.c \\\n           lfds711_freelist_query.c \\\n           lfds711_hash_addonly_cleanup.c \\\n           lfds711_hash_addonly_get.c \\\n           lfds711_hash_addonly_init.c \\\n           lfds711_hash_addonly_insert.c \\\n           lfds711_hash_addonly_iterate.c \\\n           lfds711_hash_addonly_query.c \\\n           lfds711_list_addonly_singlylinked_ordered_cleanup.c \\\n           lfds711_list_addonly_singlylinked_ordered_get.c \\\n           lfds711_list_addonly_singlylinked_ordered_init.c \\\n           lfds711_list_addonly_singlylinked_ordered_insert.c \\\n           lfds711_list_addonly_singlylinked_ordered_query.c \\\n           lfds711_list_addonly_singlylinked_unordered_cleanup.c \\\n           lfds711_list_addonly_singlylinked_unordered_get.c \\\n           lfds711_list_addonly_singlylinked_unordered_init.c \\\n           lfds711_list_addonly_singlylinked_unordered_insert.c \\\n           lfds711_list_addonly_singlylinked_unordered_query.c \\\n           lfds711_misc_globals.c \\\n           lfds711_misc_internal_backoff_init.c \\\n           lfds711_misc_query.c \\\n           lfds711_prng_init.c \\\n           lfds711_queue_bounded_manyproducer_manyconsumer_cleanup.c \\\n           lfds711_queue_bounded_manyproducer_manyconsumer_dequeue.c \\\n           lfds711_queue_bounded_manyproducer_manyconsumer_enqueue.c \\\n           lfds711_queue_bounded_manyproducer_manyconsumer_init.c \\\n           lfds711_queue_bounded_manyproducer_manyconsumer_query.c \\\n           lfds711_queue_bounded_singleproducer_singleconsumer_cleanup.c \\\n           lfds711_queue_bounded_singleproducer_singleconsumer_dequeue.c \\\n           lfds711_queue_bounded_singleproducer_singleconsumer_enqueue.c \\\n           lfds711_queue_bounded_singleproducer_singleconsumer_init.c \\\n           lfds711_queue_bounded_singleproducer_singleconsumer_query.c \\\n           lfds711_queue_unbounded_manyproducer_manyconsumer_cleanup.c \\\n           lfds711_queue_unbounded_manyproducer_manyconsumer_dequeue.c \\\n           lfds711_queue_unbounded_manyproducer_manyconsumer_enqueue.c \\\n           lfds711_queue_unbounded_manyproducer_manyconsumer_init.c \\\n           lfds711_queue_unbounded_manyproducer_manyconsumer_query.c \\\n           lfds711_ringbuffer_cleanup.c \\\n           lfds711_ringbuffer_init.c \\\n           lfds711_ringbuffer_query.c \\\n           lfds711_ringbuffer_read.c \\\n           lfds711_ringbuffer_write.c \\\n           lfds711_stack_cleanup.c \\\n           lfds711_stack_init.c \\\n           lfds711_stack_pop.c \\\n           lfds711_stack_push.c \\\n           lfds711_stack_query.c\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/inc/liblfds711/lfds711_btree_addonly_unbalanced.h",
    "content": "/***** defines *****/\n#define LFDS711_BTREE_AU_GET_KEY_FROM_ELEMENT( btree_au_element )             ( (btree_au_element).key )\n#define LFDS711_BTREE_AU_SET_KEY_IN_ELEMENT( btree_au_element, new_key )      ( (btree_au_element).key = (void *) (lfds711_pal_uint_t) (new_key) )\n#define LFDS711_BTREE_AU_GET_VALUE_FROM_ELEMENT( btree_au_element )           ( LFDS711_MISC_BARRIER_LOAD, (btree_au_element).value )\n#define LFDS711_BTREE_AU_SET_VALUE_IN_ELEMENT( btree_au_element, new_value )  { LFDS711_PAL_ATOMIC_SET( &(btree_au_element).value, new_value ); }\n#define LFDS711_BTREE_AU_GET_USER_STATE_FROM_STATE( btree_au_state )          ( (btree_au_state).user_state )\n\n/***** enums *****/\nenum lfds711_btree_au_absolute_position\n{\n  LFDS711_BTREE_AU_ABSOLUTE_POSITION_ROOT,\n  LFDS711_BTREE_AU_ABSOLUTE_POSITION_SMALLEST_IN_TREE,\n  LFDS711_BTREE_AU_ABSOLUTE_POSITION_LARGEST_IN_TREE\n};\n\nenum lfds711_btree_au_existing_key\n{\n  LFDS711_BTREE_AU_EXISTING_KEY_OVERWRITE,\n  LFDS711_BTREE_AU_EXISTING_KEY_FAIL\n};\n\nenum lfds711_btree_au_insert_result\n{\n  LFDS711_BTREE_AU_INSERT_RESULT_FAILURE_EXISTING_KEY,\n  LFDS711_BTREE_AU_INSERT_RESULT_SUCCESS_OVERWRITE,\n  LFDS711_BTREE_AU_INSERT_RESULT_SUCCESS\n};\n\nenum lfds711_btree_au_query\n{\n  LFDS711_BTREE_AU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT,\n  LFDS711_BTREE_AU_QUERY_SINGLETHREADED_VALIDATE\n};\n\nenum lfds711_btree_au_relative_position\n{\n  LFDS711_BTREE_AU_RELATIVE_POSITION_UP,\n  LFDS711_BTREE_AU_RELATIVE_POSITION_LEFT,\n  LFDS711_BTREE_AU_RELATIVE_POSITION_RIGHT,\n  LFDS711_BTREE_AU_RELATIVE_POSITION_SMALLEST_ELEMENT_BELOW_CURRENT_ELEMENT,\n  LFDS711_BTREE_AU_RELATIVE_POSITION_LARGEST_ELEMENT_BELOW_CURRENT_ELEMENT,\n  LFDS711_BTREE_AU_RELATIVE_POSITION_NEXT_SMALLER_ELEMENT_IN_ENTIRE_TREE,\n  LFDS711_BTREE_AU_RELATIVE_POSITION_NEXT_LARGER_ELEMENT_IN_ENTIRE_TREE\n};\n\n/***** structs *****/\nstruct lfds711_btree_au_element\n{\n  /* TRD : we are add-only, so these elements are only written once\n           as such, the write is wholly negligible\n           we are only concerned with getting as many structs in one cache line as we can\n  */\n\n  struct lfds711_btree_au_element LFDS711_PAL_ALIGN(LFDS711_PAL_ALIGN_SINGLE_POINTER)\n    *volatile left,\n    *volatile right,\n    *volatile up;\n\n  void LFDS711_PAL_ALIGN(LFDS711_PAL_ALIGN_SINGLE_POINTER)\n    *volatile value;\n\n  void\n    *key;\n};\n\nstruct lfds711_btree_au_state\n{\n  struct lfds711_btree_au_element LFDS711_PAL_ALIGN(LFDS711_PAL_ALIGN_SINGLE_POINTER)\n    *volatile root;\n\n  int\n    (*key_compare_function)( void const *new_key, void const *existing_key );\n\n  enum lfds711_btree_au_existing_key \n    existing_key;\n\n  void\n    *user_state;\n\n  struct lfds711_misc_backoff_state\n    insert_backoff;\n};\n\n/***** public prototypes *****/\nvoid lfds711_btree_au_init_valid_on_current_logical_core( struct lfds711_btree_au_state *baus,\n                                                          int (*key_compare_function)(void const *new_key, void const *existing_key),\n                                                          enum lfds711_btree_au_existing_key existing_key,\n                                                          void *user_state );\n  // TRD : used in conjunction with the #define LFDS711_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE\n\nvoid lfds711_btree_au_cleanup( struct lfds711_btree_au_state *baus,\n                               void (*element_cleanup_callback)(struct lfds711_btree_au_state *baus, struct lfds711_btree_au_element *baue) );\n\nenum lfds711_btree_au_insert_result lfds711_btree_au_insert( struct lfds711_btree_au_state *baus,\n                                                             struct lfds711_btree_au_element *baue,\n                                                             struct lfds711_btree_au_element **existing_baue );\n  // TRD : if a link collides with an existing key and existing_baue is non-NULL, existing_baue is set to the existing element\n\nint lfds711_btree_au_get_by_key( struct lfds711_btree_au_state *baus, \n                                 int (*key_compare_function)(void const *new_key, void const *existing_key),\n                                 void *key,\n                                 struct lfds711_btree_au_element **baue );\n\nint lfds711_btree_au_get_by_absolute_position_and_then_by_relative_position( struct lfds711_btree_au_state *baus,\n                                                                             struct lfds711_btree_au_element **baue,\n                                                                             enum lfds711_btree_au_absolute_position absolute_position,\n                                                                             enum lfds711_btree_au_relative_position relative_position );\n  // TRD : if *baue is NULL, we get the element at position, otherwise we move from *baue according to direction\n\nint lfds711_btree_au_get_by_absolute_position( struct lfds711_btree_au_state *baus,\n                                               struct lfds711_btree_au_element **baue,\n                                               enum lfds711_btree_au_absolute_position absolute_position );\n\nint lfds711_btree_au_get_by_relative_position( struct lfds711_btree_au_element **baue,\n                                               enum lfds711_btree_au_relative_position relative_position );\n\nvoid lfds711_btree_au_query( struct lfds711_btree_au_state *baus,\n                             enum lfds711_btree_au_query query_type,\n                             void *query_input,\n                             void *query_output );\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/inc/liblfds711/lfds711_freelist.h",
    "content": "/***** defines *****/\n#define LFDS711_FREELIST_GET_KEY_FROM_ELEMENT( freelist_element )             ( (freelist_element).key )\n#define LFDS711_FREELIST_SET_KEY_IN_ELEMENT( freelist_element, new_key )      ( (freelist_element).key = (void *) (lfds711_pal_uint_t) (new_key) )\n#define LFDS711_FREELIST_GET_VALUE_FROM_ELEMENT( freelist_element )           ( (freelist_element).value )\n#define LFDS711_FREELIST_SET_VALUE_IN_ELEMENT( freelist_element, new_value )  ( (freelist_element).value = (void *) (lfds711_pal_uint_t) (new_value) )\n#define LFDS711_FREELIST_GET_USER_STATE_FROM_STATE( freelist_state )          ( (freelist_state).user_state )\n\n#define LFDS711_FREELIST_ELIMINATION_ARRAY_ELEMENT_SIZE_IN_FREELIST_ELEMENTS  ( LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES / sizeof(struct lfds711_freelist_element *) )\n\n/***** enums *****/\nenum lfds711_freelist_query\n{\n  LFDS711_FREELIST_QUERY_SINGLETHREADED_GET_COUNT,\n  LFDS711_FREELIST_QUERY_SINGLETHREADED_VALIDATE,\n  LFDS711_FREELIST_QUERY_GET_ELIMINATION_ARRAY_EXTRA_ELEMENTS_IN_FREELIST_ELEMENTS\n};\n\n/***** structures *****/\nstruct lfds711_freelist_element\n{\n  struct lfds711_freelist_element\n    *next;\n\n  void\n    *key,\n    *value;\n};\n\nstruct lfds711_freelist_state\n{\n  struct lfds711_freelist_element LFDS711_PAL_ALIGN(LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES)\n    *volatile top[PAC_SIZE];\n\n  lfds711_pal_uint_t LFDS711_PAL_ALIGN(LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES)\n    elimination_array_size_in_elements;\n\n  struct lfds711_freelist_element * volatile\n    (*elimination_array)[LFDS711_FREELIST_ELIMINATION_ARRAY_ELEMENT_SIZE_IN_FREELIST_ELEMENTS];\n\n  void\n    *user_state;\n\n  struct lfds711_misc_backoff_state\n    pop_backoff,\n    push_backoff;\n};\n\n/***** public prototypes *****/\nvoid lfds711_freelist_init_valid_on_current_logical_core( struct lfds711_freelist_state *fs,\n                                                          struct lfds711_freelist_element * volatile (*elimination_array)[LFDS711_FREELIST_ELIMINATION_ARRAY_ELEMENT_SIZE_IN_FREELIST_ELEMENTS],\n                                                          lfds711_pal_uint_t elimination_array_size_in_elements,\n                                                          void *user_state );\n  // TRD : used in conjunction with the #define LFDS711_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE\n\nvoid lfds711_freelist_cleanup( struct lfds711_freelist_state *fs,\n                               void (*element_cleanup_callback)(struct lfds711_freelist_state *fs, struct lfds711_freelist_element *fe) );\n\nvoid lfds711_freelist_push( struct lfds711_freelist_state *fs,\n                                   struct lfds711_freelist_element *fe,\n                                   struct lfds711_prng_st_state *psts );\n\nint lfds711_freelist_pop( struct lfds711_freelist_state *fs,\n                          struct lfds711_freelist_element **fe,\n                          struct lfds711_prng_st_state *psts );\n\nvoid lfds711_freelist_query( struct lfds711_freelist_state *fs,\n                             enum lfds711_freelist_query query_type,\n                             void *query_input,\n                             void *query_output );\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/inc/liblfds711/lfds711_hash_addonly.h",
    "content": "/***** defines *****/\n#define LFDS711_HASH_A_GET_KEY_FROM_ELEMENT( hash_a_element )             ( (hash_a_element).key )\n#define LFDS711_HASH_A_SET_KEY_IN_ELEMENT( hash_a_element, new_key )      ( (hash_a_element).key = (void *) (lfds711_pal_uint_t) (new_key) )\n#define LFDS711_HASH_A_GET_VALUE_FROM_ELEMENT( hash_a_element )           ( LFDS711_MISC_BARRIER_LOAD, (hash_a_element).value )\n#define LFDS711_HASH_A_SET_VALUE_IN_ELEMENT( hash_a_element, new_value )  { LFDS711_PAL_ATOMIC_SET( &(hash_a_element).value, new_value ); }\n#define LFDS711_HASH_A_GET_USER_STATE_FROM_STATE( hash_a_state )          ( (hash_a_state).user_state )\n\n// TRD : a quality hash function, provided for user convenience - note hash must be initialized to 0 before the first call by the user\n\n#if( LFDS711_PAL_ALIGN_SINGLE_POINTER == 4 )\n  // TRD : void *data, lfds711_pal_uint_t data_length_in_bytes, lfds711_pal_uint_t hash\n  #define LFDS711_HASH_A_HASH_FUNCTION( data, data_length_in_bytes, hash )  {                                                           \\\n                                                                              lfds711_pal_uint_t                                        \\\n                                                                                loop;                                                   \\\n                                                                                                                                        \\\n                                                                              for( loop = 0 ; loop < (data_length_in_bytes) ; loop++ )  \\\n                                                                              {                                                         \\\n                                                                                (hash) += *( (char unsigned *) (data) + loop );         \\\n                                                                                (hash) = ((hash) ^ ((hash) >> 16)) * 0x85ebca6bUL;      \\\n                                                                                (hash) = ((hash) ^ ((hash) >> 13)) * 0xc2b2ae35UL;      \\\n                                                                                (hash) = (hash ^ (hash >> 16));                         \\\n                                                                              }                                                         \\\n                                                                            }\n#endif\n\n#if( LFDS711_PAL_ALIGN_SINGLE_POINTER == 8 )\n  // TRD : void *data, lfds711_pal_uint_t data_length_in_bytes, lfds711_pal_uint_t hash\n  #define LFDS711_HASH_A_HASH_FUNCTION( data, data_length_in_bytes, hash )  {                                                                \\\n                                                                              lfds711_pal_uint_t                                             \\\n                                                                                loop;                                                        \\\n                                                                                                                                             \\\n                                                                              for( loop = 0 ; loop < (data_length_in_bytes) ; loop++ )       \\\n                                                                              {                                                              \\\n                                                                                (hash) += *( (char unsigned *) (data) + loop );              \\\n                                                                                (hash) = ((hash) ^ ((hash) >> 30)) * 0xBF58476D1CE4E5B9ULL;  \\\n                                                                                (hash) = ((hash) ^ ((hash) >> 27)) * 0x94D049BB133111EBULL;  \\\n                                                                                (hash) = (hash ^ (hash >> 31));                              \\\n                                                                              }                                                              \\\n                                                                            }\n#endif\n\n/***** enums *****/\nenum lfds711_hash_a_existing_key\n{\n  LFDS711_HASH_A_EXISTING_KEY_OVERWRITE,\n  LFDS711_HASH_A_EXISTING_KEY_FAIL\n};\n\nenum lfds711_hash_a_insert_result\n{\n  LFDS711_HASH_A_PUT_RESULT_FAILURE_EXISTING_KEY,\n  LFDS711_HASH_A_PUT_RESULT_SUCCESS_OVERWRITE,\n  LFDS711_HASH_A_PUT_RESULT_SUCCESS\n};\n\nenum lfds711_hash_a_query\n{\n  LFDS711_HASH_A_QUERY_GET_POTENTIALLY_INACCURATE_COUNT,\n  LFDS711_HASH_A_QUERY_SINGLETHREADED_VALIDATE\n};\n\n/***** structs *****/\nstruct lfds711_hash_a_element\n{\n  struct lfds711_btree_au_element\n    baue;\n\n  void\n    *key;\n\n  void LFDS711_PAL_ALIGN(LFDS711_PAL_ALIGN_SINGLE_POINTER)\n    *volatile value;\n};\n\nstruct lfds711_hash_a_iterate\n{\n  struct lfds711_btree_au_element\n    *baue;\n\n  struct lfds711_btree_au_state\n    *baus,\n    *baus_end;\n};\n\nstruct lfds711_hash_a_state\n{\n  enum lfds711_hash_a_existing_key\n    existing_key;\n\n  int\n    (*key_compare_function)( void const *new_key, void const *existing_key );\n\n  lfds711_pal_uint_t\n    array_size;\n\n  struct lfds711_btree_au_state\n    *baus_array;\n\n  void\n    (*element_cleanup_callback)( struct lfds711_hash_a_state *has, struct lfds711_hash_a_element *hae ),\n    (*key_hash_function)( void const *key, lfds711_pal_uint_t *hash ),\n    *user_state;\n};\n\n/***** public prototypes *****/\nvoid lfds711_hash_a_init_valid_on_current_logical_core( struct lfds711_hash_a_state *has,\n                                                        struct lfds711_btree_au_state *baus_array,\n                                                        lfds711_pal_uint_t array_size,\n                                                        int (*key_compare_function)(void const *new_key, void const *existing_key),\n                                                        void (*key_hash_function)(void const *key, lfds711_pal_uint_t *hash),\n                                                        enum lfds711_hash_a_existing_key existing_key,\n                                                        void *user_state );\n  // TRD : used in conjunction with the #define LFDS711_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE\n\nvoid lfds711_hash_a_cleanup( struct lfds711_hash_a_state *has,\n                             void (*element_cleanup_function)(struct lfds711_hash_a_state *has, struct lfds711_hash_a_element *hae) );\n\nenum lfds711_hash_a_insert_result lfds711_hash_a_insert( struct lfds711_hash_a_state *has,\n                                                         struct lfds711_hash_a_element *hae,\n                                                         struct lfds711_hash_a_element **existing_hae );\n  // TRD : if existing_value is not NULL and the key exists, existing_hae is set to the hash element of the existing key\n\nint lfds711_hash_a_get_by_key( struct lfds711_hash_a_state *has,\n                               int (*key_compare_function)(void const *new_key, void const *existing_key),\n                               void (*key_hash_function)(void const *key, lfds711_pal_uint_t *hash),\n                               void *key,\n                               struct lfds711_hash_a_element **hae );\n\nvoid lfds711_hash_a_iterate_init( struct lfds711_hash_a_state *has, struct lfds711_hash_a_iterate *hai );\nint lfds711_hash_a_iterate( struct lfds711_hash_a_iterate *hai, struct lfds711_hash_a_element **hae );\n\nvoid lfds711_hash_a_query( struct lfds711_hash_a_state *has,\n                           enum lfds711_hash_a_query query_type,\n                           void *query_input,\n                           void *query_output );\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/inc/liblfds711/lfds711_list_addonly_singlylinked_ordered.h",
    "content": "/***** defines *****/\n#define LFDS711_LIST_ASO_GET_START( list_aso_state )                                             ( LFDS711_MISC_BARRIER_LOAD, (list_aso_state).start->next )\n#define LFDS711_LIST_ASO_GET_NEXT( list_aso_element )                                            ( LFDS711_MISC_BARRIER_LOAD, (list_aso_element).next )\n#define LFDS711_LIST_ASO_GET_START_AND_THEN_NEXT( list_aso_state, pointer_to_list_aso_element )  ( (pointer_to_list_aso_element) == NULL ? ( (pointer_to_list_aso_element) = LFDS711_LIST_ASO_GET_START(list_aso_state) ) : ( (pointer_to_list_aso_element) = LFDS711_LIST_ASO_GET_NEXT(*(pointer_to_list_aso_element)) ) )\n#define LFDS711_LIST_ASO_GET_KEY_FROM_ELEMENT( list_aso_element )                                ( (list_aso_element).key )\n#define LFDS711_LIST_ASO_SET_KEY_IN_ELEMENT( list_aso_element, new_key )                         ( (list_aso_element).key = (void *) (lfds711_pal_uint_t) (new_key) )\n#define LFDS711_LIST_ASO_GET_VALUE_FROM_ELEMENT( list_aso_element )                              ( LFDS711_MISC_BARRIER_LOAD, (list_aso_element).value )\n#define LFDS711_LIST_ASO_SET_VALUE_IN_ELEMENT( list_aso_element, new_value )                     { LFDS711_PAL_ATOMIC_SET( &(list_aso_element).value, new_value ); }\n#define LFDS711_LIST_ASO_GET_USER_STATE_FROM_STATE( list_aso_state )                             ( (list_aso_state).user_state )\n\n/***** enums *****/\nenum lfds711_list_aso_existing_key\n{\n  LFDS711_LIST_ASO_EXISTING_KEY_OVERWRITE,\n  LFDS711_LIST_ASO_EXISTING_KEY_FAIL\n};\n\nenum lfds711_list_aso_insert_result\n{\n  LFDS711_LIST_ASO_INSERT_RESULT_FAILURE_EXISTING_KEY,\n  LFDS711_LIST_ASO_INSERT_RESULT_SUCCESS_OVERWRITE,\n  LFDS711_LIST_ASO_INSERT_RESULT_SUCCESS\n};\n\nenum lfds711_list_aso_query\n{\n  LFDS711_LIST_ASO_QUERY_GET_POTENTIALLY_INACCURATE_COUNT,\n  LFDS711_LIST_ASO_QUERY_SINGLETHREADED_VALIDATE\n};\n\n/***** structures *****/\nstruct lfds711_list_aso_element\n{\n  struct lfds711_list_aso_element LFDS711_PAL_ALIGN(LFDS711_PAL_ALIGN_SINGLE_POINTER)\n    *volatile next;\n\n  void LFDS711_PAL_ALIGN(LFDS711_PAL_ALIGN_SINGLE_POINTER)\n    *volatile value;\n\n  void\n    *key;\n};\n\nstruct lfds711_list_aso_state\n{\n  struct lfds711_list_aso_element LFDS711_PAL_ALIGN(LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES)\n    dummy_element;\n\n  struct lfds711_list_aso_element LFDS711_PAL_ALIGN(LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES)\n    *start;\n\n  int\n    (*key_compare_function)( void const *new_key, void const *existing_key );\n\n  enum lfds711_list_aso_existing_key\n    existing_key;\n\n  void\n    *user_state;\n\n  struct lfds711_misc_backoff_state\n    insert_backoff;\n};\n\n/***** public prototypes *****/\nvoid lfds711_list_aso_init_valid_on_current_logical_core( struct lfds711_list_aso_state *lasos,\n                                                          int (*key_compare_function)(void const *new_key, void const *existing_key),\n                                                          enum lfds711_list_aso_existing_key existing_key,\n                                                          void *user_state );\n  // TRD : used in conjunction with the #define LFDS711_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE\n\nvoid lfds711_list_aso_cleanup( struct lfds711_list_aso_state *lasos,\n                               void (*element_cleanup_callback)(struct lfds711_list_aso_state *lasos, struct lfds711_list_aso_element *lasoe) );\n\nenum lfds711_list_aso_insert_result lfds711_list_aso_insert( struct lfds711_list_aso_state *lasos,\n                                                             struct lfds711_list_aso_element *lasoe,\n                                                             struct lfds711_list_aso_element **existing_lasoe );\n\nint lfds711_list_aso_get_by_key( struct lfds711_list_aso_state *lasos,\n                                 void *key,\n                                 struct lfds711_list_aso_element **lasoe );\n\nvoid lfds711_list_aso_query( struct lfds711_list_aso_state *lasos,\n                             enum lfds711_list_aso_query query_type,\n                             void *query_input,\n                             void *query_output );\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/inc/liblfds711/lfds711_list_addonly_singlylinked_unordered.h",
    "content": "/***** defines *****/\n#define LFDS711_LIST_ASU_GET_START( list_asu_state )                                             ( LFDS711_MISC_BARRIER_LOAD, (list_asu_state).start->next )\n#define LFDS711_LIST_ASU_GET_NEXT( list_asu_element )                                            ( LFDS711_MISC_BARRIER_LOAD, (list_asu_element).next )\n#define LFDS711_LIST_ASU_GET_START_AND_THEN_NEXT( list_asu_state, pointer_to_list_asu_element )  ( (pointer_to_list_asu_element) == NULL ? ( (pointer_to_list_asu_element) = LFDS711_LIST_ASU_GET_START(list_asu_state) ) : ( (pointer_to_list_asu_element) = LFDS711_LIST_ASU_GET_NEXT(*(pointer_to_list_asu_element)) ) )\n#define LFDS711_LIST_ASU_GET_KEY_FROM_ELEMENT( list_asu_element )                                ( (list_asu_element).key )\n#define LFDS711_LIST_ASU_SET_KEY_IN_ELEMENT( list_asu_element, new_key )                         ( (list_asu_element).key = (void *) (lfds711_pal_uint_t) (new_key) )\n#define LFDS711_LIST_ASU_GET_VALUE_FROM_ELEMENT( list_asu_element )                              ( LFDS711_MISC_BARRIER_LOAD, (list_asu_element).value )\n#define LFDS711_LIST_ASU_SET_VALUE_IN_ELEMENT( list_asu_element, new_value )                     { LFDS711_PAL_ATOMIC_SET( &(list_asu_element).value, new_value ); }\n#define LFDS711_LIST_ASU_GET_USER_STATE_FROM_STATE( list_asu_state )                             ( (list_asu_state).user_state )\n\n/***** enums *****/\nenum lfds711_list_asu_position\n{\n  LFDS711_LIST_ASU_POSITION_START,\n  LFDS711_LIST_ASU_POSITION_END,\n  LFDS711_LIST_ASU_POSITION_AFTER\n};\n\nenum lfds711_list_asu_query\n{\n  LFDS711_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT,\n  LFDS711_LIST_ASU_QUERY_SINGLETHREADED_VALIDATE\n};\n\n/***** structures *****/\nstruct lfds711_list_asu_element\n{\n  struct lfds711_list_asu_element LFDS711_PAL_ALIGN(LFDS711_PAL_ALIGN_SINGLE_POINTER)\n    *volatile next;\n\n  void LFDS711_PAL_ALIGN(LFDS711_PAL_ALIGN_SINGLE_POINTER)\n    *volatile value;\n\n  void\n    *key;\n};\n\nstruct lfds711_list_asu_state\n{\n  struct lfds711_list_asu_element LFDS711_PAL_ALIGN(LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES)\n    dummy_element;\n\n  struct lfds711_list_asu_element LFDS711_PAL_ALIGN(LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES)\n    *volatile end;\n\n  struct lfds711_list_asu_element LFDS711_PAL_ALIGN(LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES)\n    *start;\n\n  void\n    *user_state;\n\n  struct lfds711_misc_backoff_state\n    after_backoff,\n    end_backoff,\n    start_backoff;\n};\n\n/***** public prototypes *****/\nvoid lfds711_list_asu_init_valid_on_current_logical_core( struct lfds711_list_asu_state *lasus,\n                                                          void *user_state );\n  // TRD : used in conjunction with the #define LFDS711_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE\n\nvoid lfds711_list_asu_cleanup( struct lfds711_list_asu_state *lasus,\n                               void (*element_cleanup_callback)(struct lfds711_list_asu_state *lasus, struct lfds711_list_asu_element *lasue) );\n\nvoid lfds711_list_asu_insert_at_position( struct lfds711_list_asu_state *lasus,\n                                          struct lfds711_list_asu_element *lasue,\n                                          struct lfds711_list_asu_element *lasue_predecessor,\n                                          enum lfds711_list_asu_position position );\n\nvoid lfds711_list_asu_insert_at_start( struct lfds711_list_asu_state *lasus,\n                                       struct lfds711_list_asu_element *lasue );\n\nvoid lfds711_list_asu_insert_at_end( struct lfds711_list_asu_state *lasus,\n                                     struct lfds711_list_asu_element *lasue );\n\nvoid lfds711_list_asu_insert_after_element( struct lfds711_list_asu_state *lasus,\n                                            struct lfds711_list_asu_element *lasue,\n                                            struct lfds711_list_asu_element *lasue_predecessor );\n\nint lfds711_list_asu_get_by_key( struct lfds711_list_asu_state *lasus,\n                                 int (*key_compare_function)(void const *new_key, void const *existing_key),\n                                 void *key, \n                                 struct lfds711_list_asu_element **lasue );\n\nvoid lfds711_list_asu_query( struct lfds711_list_asu_state *lasus,\n                             enum lfds711_list_asu_query query_type,\n                             void *query_input,\n                             void *query_output );\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/inc/liblfds711/lfds711_misc.h",
    "content": "/***** defines *****/\n#define LFDS711_MISC_VERSION_STRING   \"7.1.1\"\n#define LFDS711_MISC_VERSION_INTEGER  711\n\n#ifndef NULL\n  #define NULL ( (void *) 0 )\n#endif\n\n#define POINTER   0\n#define COUNTER   1\n#define PAC_SIZE  2\n\n#define LFDS711_MISC_DELIBERATELY_CRASH  { char *c = 0; *c = 0; }\n\n#if( !defined LFDS711_PAL_ATOMIC_ADD )\n  #define LFDS711_PAL_NO_ATOMIC_ADD\n  #define LFDS711_MISC_ATOMIC_SUPPORT_ADD 0\n  #define LFDS711_PAL_ATOMIC_ADD( pointer_to_target, value, result, result_type )        \\\n  {                                                                                      \\\n    LFDS711_PAL_ASSERT( !\"LFDS711_PAL_ATOMIC_ADD not implemented for this platform.\" );  \\\n    LFDS711_MISC_DELIBERATELY_CRASH;                                                     \\\n  }\n#else\n  #define LFDS711_MISC_ATOMIC_SUPPORT_ADD 1\n#endif\n\n#if( !defined LFDS711_PAL_ATOMIC_CAS )\n  #define LFDS711_PAL_NO_ATOMIC_CAS\n  #define LFDS711_MISC_ATOMIC_SUPPORT_CAS 0\n  #define LFDS711_PAL_ATOMIC_CAS( pointer_to_destination, pointer_to_compare, new_destination, cas_strength, result )  \\\n  {                                                                                                                    \\\n    LFDS711_PAL_ASSERT( !\"LFDS711_PAL_ATOMIC_CAS not implemented for this platform.\" );                                \\\n    (result) = 0;                                                                                                      \\\n    LFDS711_MISC_DELIBERATELY_CRASH;                                                                                   \\\n  }\n#else\n  #define LFDS711_MISC_ATOMIC_SUPPORT_CAS 1\n#endif\n\n#if( !defined LFDS711_PAL_ATOMIC_DWCAS )\n  #define LFDS711_PAL_NO_ATOMIC_DWCAS\n  #define LFDS711_MISC_ATOMIC_SUPPORT_DWCAS 0\n  #define LFDS711_PAL_ATOMIC_DWCAS( pointer_to_destination, pointer_to_compare, pointer_to_new_destination, cas_strength, result )  \\\n  {                                                                                                                                 \\\n    LFDS711_PAL_ASSERT( !\"LFDS711_PAL_ATOMIC_DWCAS not implemented for this platform.\" );                                           \\\n    (result) = 0;                                                                                                                   \\\n    LFDS711_MISC_DELIBERATELY_CRASH;                                                                                                \\\n  }\n#else\n  #define LFDS711_MISC_ATOMIC_SUPPORT_DWCAS 1\n#endif\n\n#if( !defined LFDS711_PAL_ATOMIC_EXCHANGE )\n  #define LFDS711_PAL_NO_ATOMIC_EXCHANGE\n  #define LFDS711_MISC_ATOMIC_SUPPORT_EXCHANGE 0\n  #define LFDS711_PAL_ATOMIC_EXCHANGE( pointer_to_destination, new_value, original_value, value_type )  \\\n  {                                                                                                     \\\n    LFDS711_PAL_ASSERT( !\"LFDS711_PAL_ATOMIC_EXCHANGE not implemented for this platform.\" );            \\\n    LFDS711_MISC_DELIBERATELY_CRASH;                                                                    \\\n  }\n#else\n  #define LFDS711_MISC_ATOMIC_SUPPORT_EXCHANGE 1\n#endif\n\n#if( !defined LFDS711_PAL_ATOMIC_SET )\n  #define LFDS711_PAL_NO_ATOMIC_SET\n  #define LFDS711_MISC_ATOMIC_SUPPORT_SET 0\n  #define LFDS711_PAL_ATOMIC_SET( pointer_to_destination, new_value )                    \\\n  {                                                                                      \\\n    LFDS711_PAL_ASSERT( !\"LFDS711_PAL_ATOMIC_SET not implemented for this platform.\" );  \\\n    LFDS711_MISC_DELIBERATELY_CRASH;                                                     \\\n  }\n#else\n  #define LFDS711_MISC_ATOMIC_SUPPORT_SET 1\n#endif\n\n#if( defined LFDS711_PAL_BARRIER_COMPILER_LOAD && defined LFDS711_PAL_BARRIER_PROCESSOR_LOAD )\n  #define LFDS711_MISC_BARRIER_LOAD  ( LFDS711_PAL_BARRIER_COMPILER_LOAD, LFDS711_PAL_BARRIER_PROCESSOR_LOAD, LFDS711_PAL_BARRIER_COMPILER_LOAD )\n#endif\n\n#if( (!defined LFDS711_PAL_BARRIER_COMPILER_LOAD || defined LFDS711_PAL_COMPILER_BARRIERS_MISSING_PRESUMED_HAVING_A_GOOD_TIME) && defined LFDS711_PAL_BARRIER_PROCESSOR_LOAD )\n  #define LFDS711_MISC_BARRIER_LOAD  LFDS711_PAL_BARRIER_PROCESSOR_LOAD\n#endif\n\n#if( defined LFDS711_PAL_BARRIER_COMPILER_LOAD && !defined LFDS711_PAL_BARRIER_PROCESSOR_LOAD )\n  #define LFDS711_MISC_BARRIER_LOAD  LFDS711_PAL_BARRIER_COMPILER_LOAD\n#endif\n\n#if( !defined LFDS711_PAL_BARRIER_COMPILER_LOAD && !defined LFDS711_PAL_BARRIER_PROCESSOR_LOAD )\n  #define LFDS711_MISC_BARRIER_LOAD\n#endif\n\n#if( defined LFDS711_PAL_BARRIER_COMPILER_STORE && defined LFDS711_PAL_BARRIER_PROCESSOR_STORE )\n  #define LFDS711_MISC_BARRIER_STORE  ( LFDS711_PAL_BARRIER_COMPILER_STORE, LFDS711_PAL_BARRIER_PROCESSOR_STORE, LFDS711_PAL_BARRIER_COMPILER_STORE )\n#endif\n\n#if( (!defined LFDS711_PAL_BARRIER_COMPILER_STORE || defined LFDS711_PAL_COMPILER_BARRIERS_MISSING_PRESUMED_HAVING_A_GOOD_TIME) && defined LFDS711_PAL_BARRIER_PROCESSOR_STORE )\n  #define LFDS711_MISC_BARRIER_STORE  LFDS711_PAL_BARRIER_PROCESSOR_STORE\n#endif\n\n#if( defined LFDS711_PAL_BARRIER_COMPILER_STORE && !defined LFDS711_PAL_BARRIER_PROCESSOR_STORE )\n  #define LFDS711_MISC_BARRIER_STORE  LFDS711_PAL_BARRIER_COMPILER_STORE\n#endif\n\n#if( !defined LFDS711_PAL_BARRIER_COMPILER_STORE && !defined LFDS711_PAL_BARRIER_PROCESSOR_STORE )\n  #define LFDS711_MISC_BARRIER_STORE\n#endif\n\n#if( defined LFDS711_PAL_BARRIER_COMPILER_FULL && defined LFDS711_PAL_BARRIER_PROCESSOR_FULL )\n  #define LFDS711_MISC_BARRIER_FULL  ( LFDS711_PAL_BARRIER_COMPILER_FULL, LFDS711_PAL_BARRIER_PROCESSOR_FULL, LFDS711_PAL_BARRIER_COMPILER_FULL )\n#endif\n\n#if( (!defined LFDS711_PAL_BARRIER_COMPILER_FULL || defined LFDS711_PAL_COMPILER_BARRIERS_MISSING_PRESUMED_HAVING_A_GOOD_TIME) && defined LFDS711_PAL_BARRIER_PROCESSOR_FULL )\n  #define LFDS711_MISC_BARRIER_FULL  LFDS711_PAL_BARRIER_PROCESSOR_FULL\n#endif\n\n#if( defined LFDS711_PAL_BARRIER_COMPILER_FULL && !defined LFDS711_PAL_BARRIER_PROCESSOR_FULL )\n  #define LFDS711_MISC_BARRIER_FULL  LFDS711_PAL_BARRIER_COMPILER_FULL\n#endif\n\n#if( !defined LFDS711_PAL_BARRIER_COMPILER_FULL && !defined LFDS711_PAL_BARRIER_PROCESSOR_FULL )\n  #define LFDS711_MISC_BARRIER_FULL\n#endif\n\n#if( (defined LFDS711_PAL_BARRIER_COMPILER_LOAD && defined LFDS711_PAL_BARRIER_COMPILER_STORE && defined LFDS711_PAL_BARRIER_COMPILER_FULL) || (defined LFDS711_PAL_COMPILER_BARRIERS_MISSING_PRESUMED_HAVING_A_GOOD_TIME) )\n  #define LFDS711_MISC_ATOMIC_SUPPORT_COMPILER_BARRIERS  1\n#else\n  #define LFDS711_MISC_ATOMIC_SUPPORT_COMPILER_BARRIERS  0\n#endif\n\n#if( defined LFDS711_PAL_BARRIER_PROCESSOR_LOAD && defined LFDS711_PAL_BARRIER_PROCESSOR_STORE && defined LFDS711_PAL_BARRIER_PROCESSOR_FULL )\n  #define LFDS711_MISC_ATOMIC_SUPPORT_PROCESSOR_BARRIERS  1\n#else\n  #define LFDS711_MISC_ATOMIC_SUPPORT_PROCESSOR_BARRIERS  0\n#endif\n\n#define LFDS711_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE  LFDS711_MISC_BARRIER_LOAD\n#define LFDS711_MISC_FLUSH                                                                                    { LFDS711_MISC_BARRIER_STORE; lfds711_misc_force_store(); }\n\n/***** enums *****/\nenum lfds711_misc_cas_strength\n{\n  // TRD : GCC defined values\n  LFDS711_MISC_CAS_STRENGTH_STRONG = 0,\n  LFDS711_MISC_CAS_STRENGTH_WEAK   = 1,\n};\n\nenum lfds711_misc_validity\n{\n  LFDS711_MISC_VALIDITY_UNKNOWN,\n  LFDS711_MISC_VALIDITY_VALID,\n  LFDS711_MISC_VALIDITY_INVALID_LOOP,\n  LFDS711_MISC_VALIDITY_INVALID_MISSING_ELEMENTS,\n  LFDS711_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS,\n  LFDS711_MISC_VALIDITY_INVALID_TEST_DATA,\n  LFDS711_MISC_VALIDITY_INVALID_ORDER,\n  LFDS711_MISC_VALIDITY_INVALID_ATOMIC_FAILED,\n  LFDS711_MISC_VALIDITY_INDETERMINATE_NONATOMIC_PASSED,\n};\n\nenum lfds711_misc_flag\n{\n  LFDS711_MISC_FLAG_LOWERED,\n  LFDS711_MISC_FLAG_RAISED\n};\n\nenum lfds711_misc_query\n{\n  LFDS711_MISC_QUERY_GET_BUILD_AND_VERSION_STRING\n};\n\nenum lfds711_misc_data_structure\n{\n  LFDS711_MISC_DATA_STRUCTURE_BTREE_AU,\n  LFDS711_MISC_DATA_STRUCTURE_FREELIST,\n  LFDS711_MISC_DATA_STRUCTURE_HASH_A,\n  LFDS711_MISC_DATA_STRUCTURE_LIST_AOS,\n  LFDS711_MISC_DATA_STRUCTURE_LIST_ASU,\n  LFDS711_MISC_DATA_STRUCTURE_QUEUE_BMM,\n  LFDS711_MISC_DATA_STRUCTURE_QUEUE_BSS,\n  LFDS711_MISC_DATA_STRUCTURE_QUEUE_UMM,\n  LFDS711_MISC_DATA_STRUCTURE_RINGBUFFER,\n  LFDS711_MISC_DATA_STRUCTURE_STACK,\n  LFDS711_MISC_DATA_STRUCTURE_COUNT\n};\n\n/***** struct *****/\nstruct lfds711_misc_backoff_state\n{\n  lfds711_pal_uint_t volatile LFDS711_PAL_ALIGN(LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES)\n    lock;\n\n  lfds711_pal_uint_t\n    backoff_iteration_frequency_counters[2],\n    metric,\n    total_operations;\n};\n\nstruct lfds711_misc_globals\n{\n  struct lfds711_prng_state\n    ps;\n};\n\nstruct lfds711_misc_validation_info\n{\n  lfds711_pal_uint_t\n    min_elements,\n    max_elements;\n};\n\n/***** externs *****/\nextern struct lfds711_misc_globals\n  lfds711_misc_globals;\n\n/***** public prototypes *****/\nstatic LFDS711_PAL_INLINE void lfds711_misc_force_store( void );\n\nvoid lfds711_misc_query( enum lfds711_misc_query query_type, void *query_input, void *query_output );\n\n/***** public in-line functions *****/\n#pragma prefast( disable : 28112, \"blah\" )\n\nstatic LFDS711_PAL_INLINE void lfds711_misc_force_store()\n{\n  lfds711_pal_uint_t volatile LFDS711_PAL_ALIGN(LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES)\n    destination;\n\n  LFDS711_PAL_ATOMIC_SET( &destination, 0 );\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/inc/liblfds711/lfds711_porting_abstraction_layer_compiler.h",
    "content": "/****************************************************************************/\n#if( defined __GNUC__ )\n  // TRD : makes checking GCC versions much tidier\n  #define LFDS711_PAL_GCC_VERSION ( __GNUC__ * 100 + __GNUC_MINOR__ * 10 + __GNUC_PATCHLEVEL__ )\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined _MSC_VER && _MSC_VER >= 1400 )\n\n  #ifdef LFDS711_PAL_COMPILER\n    #error More than one porting abstraction layer matches the current platform in lfds711_porting_abstraction_layer_compiler.h\n  #endif\n\n  #define LFDS711_PAL_COMPILER\n\n  #define LFDS711_PAL_COMPILER_STRING            \"MSVC\"\n\n  #define LFDS711_PAL_ALIGN(alignment)           __declspec( align(alignment) )\n  #define LFDS711_PAL_INLINE                     __forceinline\n\n  #define LFDS711_PAL_BARRIER_COMPILER_LOAD      _ReadBarrier()\n  #define LFDS711_PAL_BARRIER_COMPILER_STORE     _WriteBarrier()\n  #define LFDS711_PAL_BARRIER_COMPILER_FULL      _ReadWriteBarrier()\n\n  /* TRD : there are four processors to consider;\n\n           . ARM32    (32 bit, ADD, CAS, DWCAS, EXCHANGE, SET) (defined _M_ARM)\n           . Itanium  (64 bit, ADD, CAS,        EXCHANGE, SET) (defined _M_IA64)\n           . x64      (64 bit, ADD, CAS, DWCAS, EXCHANGE, SET) (defined _M_X64 || defined _M_AMD64)\n           . x86      (32 bit, ADD, CAS, DWCAS, EXCHANGE, SET) (defined _M_IX86)\n\n           can't find any indications of 64-bit ARM support yet\n\n           ARM has better intrinsics than the others, as there are no-fence variants\n\n           in theory we also have to deal with 32-bit Windows on a 64-bit platform,\n           and I presume we'd see the compiler properly indicate this in its macros,\n           but this would require that we use 32-bit atomics on the 64-bit platforms,\n           while keeping 64-bit cache line lengths and so on, and this is just so\n           wierd a thing to do these days that it's not supported\n  */\n\n  #if( defined _M_ARM )\n    #define LFDS711_PAL_BARRIER_PROCESSOR_LOAD   __dmb( _ARM_BARRIER_ISH )\n    #define LFDS711_PAL_BARRIER_PROCESSOR_STORE  __dmb( _ARM_BARRIER_ISHST )\n    #define LFDS711_PAL_BARRIER_PROCESSOR_FULL   __dmb( _ARM_BARRIER_ISH )\n\n    #define LFDS711_PAL_ATOMIC_ADD( pointer_to_target, value, result, result_type )                                  \\\n    {                                                                                                                \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                             \\\n      (result) = (result_type) _InterlockedAdd_nf( (int long volatile *) (pointer_to_target), (int long) (value) );  \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                             \\\n    }\n\n    #define LFDS711_PAL_ATOMIC_CAS( pointer_to_destination, pointer_to_compare, new_destination, cas_strength, result )                                                                                          \\\n    {                                                                                                                                                                                                            \\\n      lfds711_pal_uint_t                                                                                                                                                                                         \\\n        original_compare;                                                                                                                                                                                        \\\n                                                                                                                                                                                                                 \\\n      original_compare = (lfds711_pal_uint_t) *(pointer_to_compare);                                                                                                                                             \\\n                                                                                                                                                                                                                 \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                                                                                                         \\\n      *(lfds711_pal_uint_t *) (pointer_to_compare) = (lfds711_pal_uint_t) _InterlockedCompareExchange_nf( (long volatile *) (pointer_to_destination), (long) (new_destination), (long) *(pointer_to_compare) );  \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                                                                                                         \\\n                                                                                                                                                                                                                 \\\n      result = (char unsigned) ( original_compare == (lfds711_pal_uint_t) *(pointer_to_compare) );                                                                                                               \\\n    }\n\n    #define LFDS711_PAL_ATOMIC_DWCAS( pointer_to_destination, pointer_to_compare, pointer_to_new_destination, cas_strength, result )                                                                        \\\n    {                                                                                                                                                                                                       \\\n      __int64                                                                                                                                                                                               \\\n        original_compare;                                                                                                                                                                                   \\\n                                                                                                                                                                                                            \\\n      original_compare = *(__int64 *) (pointer_to_compare);                                                                                                                                                 \\\n                                                                                                                                                                                                            \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                                                                                                    \\\n      *(__int64 *) (pointer_to_compare) = _InterlockedCompareExchange64_nf( (__int64 volatile *) (pointer_to_destination), *(__int64 *) (pointer_to_new_destination), *(__int64 *) (pointer_to_compare) );  \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                                                                                                    \\\n                                                                                                                                                                                                            \\\n      (result) = (char unsigned) ( *(__int64 *) (pointer_to_compare) == original_compare );                                                                                                                 \\\n    }\n\n    #define LFDS711_PAL_ATOMIC_EXCHANGE( pointer_to_destination, exchange, exchange_type )                                            \\\n    {                                                                                                                                 \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                              \\\n      (exchange) = (exchange_type) _InterlockedExchange_nf( (int long volatile *) (pointer_to_destination), (int long) (exchange) );  \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                              \\\n    }\n\n    #define LFDS711_PAL_ATOMIC_SET( pointer_to_destination, new_value )                                          \\\n    {                                                                                                            \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                         \\\n      (void) _InterlockedExchange_nf( (int long volatile *) (pointer_to_destination), (int long) (new_value) );  \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                         \\\n    }\n  #endif\n\n  #if( defined _M_IA64 )\n    #define LFDS711_PAL_BARRIER_PROCESSOR_LOAD   __mf()\n    #define LFDS711_PAL_BARRIER_PROCESSOR_STORE  __mf()\n    #define LFDS711_PAL_BARRIER_PROCESSOR_FULL   __mf()\n\n    #define LFDS711_PAL_ATOMIC_ADD( pointer_to_target, value, result, result_type )                                   \\\n    {                                                                                                                 \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                              \\\n      (result) = (result_type) _InterlockedAdd64_acq( (__int64 volatile *) (pointer_to_target), (__int64) (value) );  \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                              \\\n    }\n\n    #define LFDS711_PAL_ATOMIC_CAS( pointer_to_destination, pointer_to_compare, new_destination, cas_strength, result )                                                                                                      \\\n    {                                                                                                                                                                                                                        \\\n      lfds711_pal_uint_t                                                                                                                                                                                                     \\\n        original_compare;                                                                                                                                                                                                    \\\n                                                                                                                                                                                                                             \\\n      original_compare = (lfds711_pal_uint_t) *(pointer_to_compare);                                                                                                                                                         \\\n                                                                                                                                                                                                                             \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                                                                                                                     \\\n      *(lfds711_pal_uint_t *) (pointer_to_compare) = (lfds711_pal_uint_t) _InterlockedCompareExchange64_acq( (__int64 volatile *) (pointer_to_destination), (__int64) (new_destination), (__int64) *(pointer_to_compare) );  \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                                                                                                                     \\\n                                                                                                                                                                                                                             \\\n      result = (char unsigned) ( original_compare == (lfds711_pal_uint_t) *(pointer_to_compare) );                                                                                                                           \\\n    }\n\n    #define LFDS711_PAL_ATOMIC_EXCHANGE( pointer_to_destination, exchange, exchange_type )                                             \\\n    {                                                                                                                                  \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                               \\\n      (exchange) = (exchange_type) _InterlockedExchange64_acq( (__int64 volatile *) (pointer_to_destination), (__int64) (exchange) );  \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                               \\\n    }\n\n    #define LFDS711_PAL_ATOMIC_SET( pointer_to_destination, new_value )                                           \\\n    {                                                                                                             \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                          \\\n      (void) _InterlockedExchange64_acq( (__int64 volatile *) (pointer_to_destination), (__int64) (new_value) );  \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                          \\\n    }\n  #endif\n\n  #if( defined _M_X64 || defined _M_AMD64 )\n    #define LFDS711_PAL_BARRIER_PROCESSOR_LOAD   _mm_lfence()\n    #define LFDS711_PAL_BARRIER_PROCESSOR_STORE  _mm_sfence()\n    #define LFDS711_PAL_BARRIER_PROCESSOR_FULL   _mm_mfence()\n\n    // TRD : no _InterlockedAdd64 for x64 - only the badly named _InterlockedExchangeAdd64, which is the same as _InterlockedAdd64 but returns the *original* value (which we must then add to before we return)\n    #define LFDS711_PAL_ATOMIC_ADD( pointer_to_target, value, result, result_type )                                       \\\n    {                                                                                                                     \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                  \\\n      (result) = (result_type) _InterlockedExchangeAdd64( (__int64 volatile *) (pointer_to_target), (__int64) (value) );  \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                  \\\n      result += value;                                                                                                    \\\n    }\n\n    #define LFDS711_PAL_ATOMIC_CAS( pointer_to_destination, pointer_to_compare, new_destination, cas_strength, result )                                                                                                  \\\n    {                                                                                                                                                                                                                    \\\n      lfds711_pal_uint_t                                                                                                                                                                                                 \\\n        original_compare;                                                                                                                                                                                                \\\n                                                                                                                                                                                                                         \\\n      original_compare = (lfds711_pal_uint_t) *(pointer_to_compare);                                                                                                                                                     \\\n                                                                                                                                                                                                                         \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                                                                                                                 \\\n      *(lfds711_pal_uint_t *) (pointer_to_compare) = (lfds711_pal_uint_t) _InterlockedCompareExchange64( (__int64 volatile *) (pointer_to_destination), (__int64) (new_destination), (__int64) *(pointer_to_compare) );  \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                                                                                                                 \\\n                                                                                                                                                                                                                         \\\n      result = (char unsigned) ( original_compare == (lfds711_pal_uint_t) *(pointer_to_compare) );                                                                                                                       \\\n    }\n\n    #if( _MSC_VER >= 1500 )\n      #define LFDS711_PAL_ATOMIC_DWCAS( pointer_to_destination, pointer_to_compare, pointer_to_new_destination, cas_strength, result )                                                                                                       \\\n      {                                                                                                                                                                                                                                      \\\n        LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                                                                                                                                   \\\n        (result) = (char unsigned) _InterlockedCompareExchange128( (__int64 volatile *) (pointer_to_destination), (__int64) (pointer_to_new_destination[1]), (__int64) (pointer_to_new_destination[0]), (__int64 *) (pointer_to_compare) );  \\\n        LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                                                                                                                                   \\\n      }\n    #endif\n\n    #define LFDS711_PAL_ATOMIC_EXCHANGE( pointer_to_destination, exchange, exchange_type )                                         \\\n    {                                                                                                                              \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                           \\\n      (exchange) = (exchange_type) _InterlockedExchange64( (__int64 volatile *) (pointer_to_destination), (__int64) (exchange) );  \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                           \\\n    }\n\n    #define LFDS711_PAL_ATOMIC_SET( pointer_to_destination, new_value )                                       \\\n    {                                                                                                         \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                      \\\n      (void) _InterlockedExchange64( (__int64 volatile *) (pointer_to_destination), (__int64) (new_value) );  \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                      \\\n    }\n  #endif\n\n  #if( defined _M_IX86 )\n    #define LFDS711_PAL_BARRIER_PROCESSOR_LOAD   lfds711_misc_force_store()\n    #define LFDS711_PAL_BARRIER_PROCESSOR_STORE  lfds711_misc_force_store()\n    #define LFDS711_PAL_BARRIER_PROCESSOR_FULL   lfds711_misc_force_store()\n\n    // TRD : no _InterlockedAdd for x86 - only the badly named _InterlockedExchangeAdd, which is the same as _InterlockedAdd but returns the *original* value (which we must then add to before we return)\n    #define LFDS711_PAL_ATOMIC_ADD( pointer_to_target, value, result, result_type )                                     \\\n    {                                                                                                                   \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                \\\n      (result) = (result_type) _InterlockedExchangeAdd( (__int64 volatile *) (pointer_to_target), (__int64) (value) );  \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                \\\n      result += value;                                                                                                  \\\n    }\n\n    #define LFDS711_PAL_ATOMIC_CAS( pointer_to_destination, pointer_to_compare, new_destination, cas_strength, result )                                                                                       \\\n    {                                                                                                                                                                                                         \\\n      lfds711_pal_uint_t                                                                                                                                                                                      \\\n        original_compare;                                                                                                                                                                                     \\\n                                                                                                                                                                                                              \\\n      /* LFDS711_PAL_ASSERT( (pointer_to_destination) != NULL ); */                                                                                                                                           \\\n      /* LFDS711_PAL_ASSERT( (pointer_to_compare) != NULL ); */                                                                                                                                               \\\n      /* TRD : new_destination can be any value in its range */                                                                                                                                               \\\n      /* TRD : cas_strength can be any value in its range */                                                                                                                                                  \\\n      /* TRD : result can be any value in its range */                                                                                                                                                        \\\n                                                                                                                                                                                                              \\\n      original_compare = (lfds711_pal_uint_t) *(pointer_to_compare);                                                                                                                                          \\\n                                                                                                                                                                                                              \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                                                                                                      \\\n      *(lfds711_pal_uint_t *) (pointer_to_compare) = (lfds711_pal_uint_t) _InterlockedCompareExchange( (long volatile *) (pointer_to_destination), (long) (new_destination), (long) *(pointer_to_compare) );  \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                                                                                                      \\\n                                                                                                                                                                                                              \\\n      result = (char unsigned) ( original_compare == (lfds711_pal_uint_t) *(pointer_to_compare) );                                                                                                            \\\n    }\n\n    #define LFDS711_PAL_ATOMIC_DWCAS( pointer_to_destination, pointer_to_compare, pointer_to_new_destination, cas_strength, result )                                                                     \\\n    {                                                                                                                                                                                                    \\\n      __int64                                                                                                                                                                                            \\\n        original_compare;                                                                                                                                                                                \\\n                                                                                                                                                                                                         \\\n      original_compare = *(__int64 *) (pointer_to_compare);                                                                                                                                              \\\n                                                                                                                                                                                                         \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                                                                                                 \\\n      *(__int64 *) (pointer_to_compare) = _InterlockedCompareExchange64( (__int64 volatile *) (pointer_to_destination), *(__int64 *) (pointer_to_new_destination), *(__int64 *) (pointer_to_compare) );  \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                                                                                                 \\\n                                                                                                                                                                                                         \\\n      (result) = (char unsigned) ( *(__int64 *) (pointer_to_compare) == original_compare );                                                                                                              \\\n    }\n\n    #define LFDS711_PAL_ATOMIC_EXCHANGE( pointer_to_destination, exchange, exchange_type )                                         \\\n    {                                                                                                                              \\\n      /* LFDS711_PAL_ASSERT( (pointer_to_destination) != NULL ); */                                                                \\\n      /* LFDS711_PAL_ASSERT( (pointer_to_exchange) != NULL ); */                                                                   \\\n                                                                                                                                   \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                           \\\n      (exchange) = (exchange_type) _InterlockedExchange( (int long volatile *) (pointer_to_destination), (int long) (exchange) );  \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                           \\\n    }\n\n    #define LFDS711_PAL_ATOMIC_SET( pointer_to_destination, new_value )                                       \\\n    {                                                                                                         \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                      \\\n      (void) _InterlockedExchange( (int long volatile *) (pointer_to_destination), (int long) (new_value) );  \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                      \\\n    }\n  #endif\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined __GNUC__ && LFDS711_PAL_GCC_VERSION >= 412 && LFDS711_PAL_GCC_VERSION < 473 )\n\n  #ifdef LFDS711_PAL_COMPILER\n    #error More than one porting abstraction layer matches the current platform in lfds711_porting_abstraction_layer_compiler.h\n  #endif\n\n  #define LFDS711_PAL_COMPILER\n\n  #define LFDS711_PAL_COMPILER_STRING          \"GCC < 4.7.3\"\n\n  #define LFDS711_PAL_ALIGN(alignment)         __attribute__( (aligned(alignment)) )\n  #define LFDS711_PAL_INLINE                   inline\n\n  static LFDS711_PAL_INLINE void lfds711_pal_barrier_compiler( void )\n  {\n    __asm__ __volatile__ ( \"\" : : : \"memory\" );\n  }\n\n  #define LFDS711_PAL_BARRIER_COMPILER_LOAD    lfds711_pal_barrier_compiler()\n  #define LFDS711_PAL_BARRIER_COMPILER_STORE   lfds711_pal_barrier_compiler()\n  #define LFDS711_PAL_BARRIER_COMPILER_FULL    lfds711_pal_barrier_compiler()\n\n  #define LFDS711_PAL_BARRIER_PROCESSOR_LOAD   __sync_synchronize()\n  #define LFDS711_PAL_BARRIER_PROCESSOR_STORE  __sync_synchronize()\n  #define LFDS711_PAL_BARRIER_PROCESSOR_FULL   __sync_synchronize()\n\n  #define LFDS711_PAL_ATOMIC_ADD( pointer_to_target, value, result, result_type )                                               \\\n  {                                                                                                                             \\\n    LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                          \\\n    (result) = (result_type) __sync_add_and_fetch( (lfds711_pal_uint_t *) (pointer_to_target), (lfds711_pal_uint_t) (value) );  \\\n    LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                          \\\n  }\n\n  #define LFDS711_PAL_ATOMIC_CAS( pointer_to_destination, pointer_to_compare, new_destination, cas_strength, result )       \\\n  {                                                                                                                         \\\n    lfds711_pal_uint_t                                                                                                      \\\n      original_compare;                                                                                                     \\\n                                                                                                                            \\\n    original_compare = (lfds711_pal_uint_t) *(pointer_to_compare);                                                          \\\n                                                                                                                            \\\n    LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                      \\\n    *(pointer_to_compare) = __sync_val_compare_and_swap( pointer_to_destination, *(pointer_to_compare), new_destination );  \\\n    LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                      \\\n                                                                                                                            \\\n    result = (unsigned char) ( original_compare == (lfds711_pal_uint_t) *(pointer_to_compare) );                            \\\n  }\n\n  #if( defined __x86_64__ )\n    /* TRD : On 64 bit platforms, unsigned long long int is 64 bit, so we must manually use cmpxchg16b, \n             as the atomic intrinsics will only emit cmpxchg8b\n    */\n\n    // TRD : lfds711_pal_uint_t volatile (*destination)[2], lfds711_pal_uint_t (*compare)[2], lfds711_pal_uint_t (*new_destination)[2], enum lfds711_misc_cas_strength cas_strength, char unsigned result\n\n    #define LFDS711_PAL_ATOMIC_DWCAS( pointer_to_destination, pointer_to_compare, pointer_to_new_destination, cas_strength, result )                             \\\n    {                                                                                                                                                            \\\n      (result) = 0;                                                                                                                                              \\\n                                                                                                                                                                 \\\n      __asm__ __volatile__                                                                                                                                       \\\n      (                                                                                                                                                          \\\n        \"lock;\"           /* make cmpxchg16b atomic        */                                                                                                    \\\n        \"cmpxchg16b %0;\"  /* cmpxchg16b sets ZF on success */                                                                                                    \\\n        \"setz       %4;\"  /* if ZF set, set result to 1    */                                                                                                    \\\n                                                                                                                                                                 \\\n        /* output */                                                                                                                                             \\\n        : \"+m\" ((pointer_to_destination)[0]), \"+m\" ((pointer_to_destination)[1]), \"+a\" ((pointer_to_compare)[0]), \"+d\" ((pointer_to_compare)[1]), \"=q\" (result)  \\\n                                                                                                                                                                 \\\n        /* input */                                                                                                                                              \\\n        : \"b\" ((pointer_to_new_destination)[0]), \"c\" ((pointer_to_new_destination)[1])                                                                           \\\n                                                                                                                                                                 \\\n        /* clobbered */                                                                                                                                          \\\n        :                                                                                                                                                        \\\n      );                                                                                                                                                         \\\n    }\n  #endif\n\n  // TRD : ARM and x86 have DWCAS which we can get via GCC intrinsics\n  #if( defined __arm__ || defined __i686__ || defined __i586__ || defined __i486__ )\n    #define LFDS711_PAL_ATOMIC_DWCAS( pointer_to_destination, pointer_to_compare, pointer_to_new_destination, cas_strength, result )                                                                                                   \\\n    {                                                                                                                                                                                                                                  \\\n      int long long unsigned                                                                                                                                                                                                           \\\n        original_destination;                                                                                                                                                                                                          \\\n                                                                                                                                                                                                                                       \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                                                                                                                               \\\n      original_destination = __sync_val_compare_and_swap( (int long long unsigned volatile *) (pointer_to_destination), *(int long long unsigned *) (pointer_to_compare), *(int long long unsigned *) (pointer_to_new_destination) );  \\\n      LFDS711_PAL_BARRIER_COMPILER_FULL;                                                                                                                                                                                               \\\n                                                                                                                                                                                                                                       \\\n      (result) = (char unsigned) ( original_destination == *(int long long unsigned *) (pointer_to_compare) );                                                                                                                         \\\n                                                                                                                                                                                                                                       \\\n      *(int long long unsigned *) (pointer_to_compare) = original_destination;                                                                                                                                                         \\\n    }\n  #endif\n\n  #define LFDS711_PAL_ATOMIC_EXCHANGE( pointer_to_destination, exchange, exchange_type )          \\\n  {                                                                                               \\\n    /* LFDS711_PAL_ASSERT( (pointer_to_destination) != NULL ); */                                 \\\n    /* TRD : exchange can be any value in its range */                                            \\\n    /* TRD : exchange_type can be any value in its range */                                       \\\n                                                                                                  \\\n    LFDS711_PAL_BARRIER_COMPILER_FULL;                                                            \\\n    (exchange) = (exchange_type) __sync_lock_test_and_set( pointer_to_destination, (exchange) );  \\\n    LFDS711_PAL_BARRIER_COMPILER_FULL;                                                            \\\n  }\n\n  #define LFDS711_PAL_ATOMIC_SET( pointer_to_destination, new_value )        \\\n  {                                                                          \\\n    LFDS711_PAL_BARRIER_COMPILER_FULL;                                       \\\n    (void) __sync_lock_test_and_set( pointer_to_destination, (new_value) );  \\\n    LFDS711_PAL_BARRIER_COMPILER_FULL;                                       \\\n  }\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined __GNUC__ && LFDS711_PAL_GCC_VERSION >= 473 )\n\n  #ifdef LFDS711_PAL_COMPILER\n    #error More than one porting abstraction layer matches the current platform in lfds711_porting_abstraction_layer_compiler.h\n  #endif\n\n  #define LFDS711_PAL_COMPILER\n\n  #define LFDS711_PAL_COMPILER_STRING          \"GCC >= 4.7.3\"\n\n  #define LFDS711_PAL_ALIGN(alignment)         __attribute__( (aligned(alignment)) )\n  #define LFDS711_PAL_INLINE                   inline\n\n  // TRD : GCC >= 4.7.3 compiler barriers are built into the intrinsics\n  #define LFDS711_PAL_COMPILER_BARRIERS_MISSING_PRESUMED_HAVING_A_GOOD_TIME\n\n  #define LFDS711_PAL_BARRIER_PROCESSOR_LOAD   __atomic_thread_fence( __ATOMIC_ACQUIRE )\n  #define LFDS711_PAL_BARRIER_PROCESSOR_STORE  __atomic_thread_fence( __ATOMIC_RELEASE )\n  #define LFDS711_PAL_BARRIER_PROCESSOR_FULL   __atomic_thread_fence( __ATOMIC_ACQ_REL )\n\n  #define LFDS711_PAL_ATOMIC_ADD( pointer_to_target, value, result, result_type )                   \\\n  {                                                                                                 \\\n    (result) = (result_type) __atomic_add_fetch( (pointer_to_target), (value), __ATOMIC_RELAXED );  \\\n  }\n\n  #define LFDS711_PAL_ATOMIC_CAS( pointer_to_destination, pointer_to_compare, new_destination, cas_strength, result )                                                       \\\n  {                                                                                                                                                                         \\\n    result = (char unsigned) __atomic_compare_exchange_n( pointer_to_destination, pointer_to_compare, new_destination, cas_strength, __ATOMIC_RELAXED, __ATOMIC_RELAXED );  \\\n  }\n\n  // TRD : ARM and x86 have DWCAS which we can get via GCC intrinsics\n  #if( defined __arm__ || defined __i686__ || defined __i586__ || defined __i486__ )\n    #define LFDS711_PAL_ATOMIC_DWCAS( pointer_to_destination, pointer_to_compare, pointer_to_new_destination, cas_strength, result )                                                                                                                                                          \\\n    {                                                                                                                                                                                                                                                                                         \\\n      (result) = (char unsigned) __atomic_compare_exchange_n( (int long long unsigned volatile *) (pointer_to_destination), (int long long unsigned *) (pointer_to_compare), *(int long long unsigned *) (pointer_to_new_destination), (cas_strength), __ATOMIC_RELAXED, __ATOMIC_RELAXED );  \\\n    }\n  #endif\n\n  #if( defined __x86_64__ )\n    /* TRD : On 64 bit platforms, unsigned long long int is 64 bit, so we must manually use cmpxchg16b, \n             as __sync_val_compare_and_swap() will only emit cmpxchg8b\n    */\n\n    // TRD : lfds711_pal_uint_t volatile (*destination)[2], lfds711_pal_uint_t (*compare)[2], lfds711_pal_uint_t (*new_destination)[2], enum lfds711_misc_cas_strength cas_strength, char unsigned result\n\n    #define LFDS711_PAL_ATOMIC_DWCAS( pointer_to_destination, pointer_to_compare, pointer_to_new_destination, cas_strength, result )                             \\\n    {                                                                                                                                                            \\\n      (result) = 0;                                                                                                                                              \\\n                                                                                                                                                                 \\\n      __asm__ __volatile__                                                                                                                                       \\\n      (                                                                                                                                                          \\\n        \"lock;\"           /* make cmpxchg16b atomic        */                                                                                                    \\\n        \"cmpxchg16b %0;\"  /* cmpxchg16b sets ZF on success */                                                                                                    \\\n        \"setz       %4;\"  /* if ZF set, set result to 1    */                                                                                                    \\\n                                                                                                                                                                 \\\n        /* output */                                                                                                                                             \\\n        : \"+m\" ((pointer_to_destination)[0]), \"+m\" ((pointer_to_destination)[1]), \"+a\" ((pointer_to_compare)[0]), \"+d\" ((pointer_to_compare)[1]), \"=q\" (result)  \\\n                                                                                                                                                                 \\\n        /* input */                                                                                                                                              \\\n        : \"b\" ((pointer_to_new_destination)[0]), \"c\" ((pointer_to_new_destination)[1])                                                                           \\\n                                                                                                                                                                 \\\n        /* clobbered */                                                                                                                                          \\\n        :                                                                                                                                                        \\\n      );                                                                                                                                                         \\\n    }\n  #endif\n\n  #define LFDS711_PAL_ATOMIC_EXCHANGE( pointer_to_destination, exchange, exchange_type )                         \\\n  {                                                                                                              \\\n    (exchange) = (exchange_type) __atomic_exchange_n( (pointer_to_destination), (exchange), __ATOMIC_RELAXED );  \\\n  }\n\n  #define LFDS711_PAL_ATOMIC_SET( pointer_to_destination, new_value )                       \\\n  {                                                                                         \\\n    (void) __atomic_exchange_n( (pointer_to_destination), (new_value), __ATOMIC_RELAXED );  \\\n  }\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( !defined LFDS711_PAL_COMPILER )\n\n  #error No matching porting abstraction layer in lfds711_porting_abstraction_layer_compiler.h\n\n#endif\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/inc/liblfds711/lfds711_porting_abstraction_layer_operating_system.h",
    "content": "/****************************************************************************/\n#if( defined _WIN32 && !defined KERNEL_MODE )\n\n  #ifdef LFDS711_PAL_OPERATING_SYSTEM\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_operating_system.h\".\n  #endif\n\n  #define LFDS711_PAL_OPERATING_SYSTEM\n\n  #include <assert.h>\n\n  #define LFDS711_PAL_OS_STRING             \"Windows\"\n  #define LFDS711_PAL_ASSERT( expression )  if( !(expression) ) LFDS711_MISC_DELIBERATELY_CRASH;\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined _WIN32 && defined KERNEL_MODE )\n\n  #ifdef LFDS711_PAL_OPERATING_SYSTEM\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_operating_system.h\".\n  #endif\n\n  #define LFDS711_PAL_OPERATING_SYSTEM\n\n  #include <assert.h>\n  #include <wdm.h>\n\n  #define LFDS711_PAL_OS_STRING             \"Windows\"\n  #define LFDS711_PAL_ASSERT( expression )  if( !(expression) ) LFDS711_MISC_DELIBERATELY_CRASH;\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined __linux__ && !defined KERNEL_MODE )\n\n  #ifdef LFDS711_PAL_OPERATING_SYSTEM\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_operating_system.h\".\n  #endif\n\n  #define LFDS711_PAL_OPERATING_SYSTEM\n\n  #define LFDS711_PAL_OS_STRING             \"Linux\"\n  #define LFDS711_PAL_ASSERT( expression )  if( !(expression) ) LFDS711_MISC_DELIBERATELY_CRASH;\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined __linux__ && defined KERNEL_MODE )\n\n  #ifdef LFDS711_PAL_OPERATING_SYSTEM\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_operating_system.h\".\n  #endif\n\n  #define LFDS711_PAL_OPERATING_SYSTEM\n\n  #include <linux/module.h>\n\n  #define LFDS711_PAL_OS_STRING             \"Linux\"\n  #define LFDS711_PAL_ASSERT( expression )  BUG_ON( expression )\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( !defined LFDS711_PAL_OPERATING_SYSTEM )\n\n  #error No matching porting abstraction layer in lfds711_porting_abstraction_layer_operating_system.h\n\n#endif\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/inc/liblfds711/lfds711_porting_abstraction_layer_processor.h",
    "content": "/****************************************************************************/\n#if( defined _MSC_VER && defined _M_IX86 )\n\n  #ifdef LFDS711_PAL_PROCESSOR\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_processor.h\".\n  #endif\n\n  #define LFDS711_PAL_PROCESSOR\n\n  typedef int long          lfds711_pal_int_t;\n  typedef int long unsigned lfds711_pal_uint_t;\n\n  #define LFDS711_PAL_PROCESSOR_STRING            \"x86\"\n\n  #define LFDS711_PAL_ALIGN_SINGLE_POINTER        4\n  #define LFDS711_PAL_ALIGN_DOUBLE_POINTER        8\n\n  #define LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES   32\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined _MSC_VER && (defined _M_X64 || defined _M_AMD64) )\n\n  #ifdef LFDS711_PAL_PROCESSOR\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_processor.h\".\n  #endif\n\n  #define LFDS711_PAL_PROCESSOR\n\n  typedef int long long          lfds711_pal_int_t;\n  typedef int long long unsigned lfds711_pal_uint_t;\n\n  #define LFDS711_PAL_PROCESSOR_STRING            \"x64\"\n\n  #define LFDS711_PAL_ALIGN_SINGLE_POINTER        8\n  #define LFDS711_PAL_ALIGN_DOUBLE_POINTER        16\n\n  // TRD : Intel bring over two cache lines at once, always, unless disabled in BIOS\n  #define LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES   128\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined _MSC_VER && defined _M_IA64 )\n\n  #ifdef LFDS711_PAL_PROCESSOR\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_processor.h\".\n  #endif\n\n  #define LFDS711_PAL_PROCESSOR\n\n  typedef int long long          lfds711_pal_int_t;\n  typedef int long long unsigned lfds711_pal_uint_t;\n\n  #define LFDS711_PAL_PROCESSOR_STRING            \"IA64\"\n\n  #define LFDS711_PAL_ALIGN_SINGLE_POINTER        8\n  #define LFDS711_PAL_ALIGN_DOUBLE_POINTER        16\n\n  #define LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES   64\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined _MSC_VER && defined _M_ARM )\n\n  #ifdef LFDS711_PAL_PROCESSOR\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_processor.h\".\n  #endif\n\n  #define LFDS711_PAL_PROCESSOR\n\n  typedef int long          lfds711_pal_int_t;\n  typedef int long unsigned lfds711_pal_uint_t;\n\n  #define LFDS711_PAL_PROCESSOR_STRING            \"ARM (32-bit)\"\n\n  #define LFDS711_PAL_ALIGN_SINGLE_POINTER        4\n  #define LFDS711_PAL_ALIGN_DOUBLE_POINTER        8\n\n  /* TRD : ARM is LL/SC and uses a reservation granule of 8 to 2048 bytes\n           so the isolation value used here is worst-case - be sure to set\n           this correctly, otherwise structures are painfully large\n\n           the test application has an argument, \"-e\", which attempts to\n           determine the ERG length\n  */\n\n  #define LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES   2048\n\n#endif\n  \n  \n  \n  \n  \n/****************************************************************************/\n#if( defined __GNUC__ && defined __arm__ )\n\n  #ifdef LFDS711_PAL_PROCESSOR\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_processor.h\".\n  #endif\n\n  #define LFDS711_PAL_PROCESSOR\n\n  typedef int long          lfds711_pal_int_t;\n  typedef int long unsigned lfds711_pal_uint_t;\n\n  #define LFDS711_PAL_PROCESSOR_STRING            \"ARM (32-bit)\"\n\n  #define LFDS711_PAL_ALIGN_SINGLE_POINTER        4\n  #define LFDS711_PAL_ALIGN_DOUBLE_POINTER        8\n\n  /* TRD : ARM is LL/SC and uses a reservation granule of 8 to 2048 bytes\n           so the isolation value used here is worst-case - be sure to set\n           this correctly, otherwise structures are painfully large\n\n           the test application has an argument, \"-e\", which attempts to\n           determine the ERG length\n  */\n\n  #define LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES   2048\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined __GNUC__ && defined __aarch64__ )\n\n  #ifdef LFDS711_PAL_PROCESSOR\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_processor.h\".\n  #endif\n\n  #define LFDS711_PAL_PROCESSOR\n\n  typedef int long long          lfds711_pal_int_t;\n  typedef int long long unsigned lfds711_pal_uint_t;\n\n  #define LFDS711_PAL_PROCESSOR_STRING            \"ARM (64-bit)\"\n\n  #define LFDS711_PAL_ALIGN_SINGLE_POINTER        8\n  #define LFDS711_PAL_ALIGN_DOUBLE_POINTER        16\n\n  /* TRD : ARM is LL/SC and uses a reservation granule of 8 to 2048 bytes\n           so the isolation value used here is worst-case - be sure to set\n           this correctly, otherwise structures are painfully large\n\n           the test application has an argument, \"-e\", which attempts to\n           determine the ERG length\n  */\n\n  #define LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES   2048\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined __GNUC__ && (defined __i686__ || defined __i586__ || defined __i486__) )\n\n  #ifdef LFDS711_PAL_PROCESSOR\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_processor.h\".\n  #endif\n\n  #define LFDS711_PAL_PROCESSOR\n\n  typedef int long          lfds711_pal_int_t;\n  typedef int long unsigned lfds711_pal_uint_t;\n\n  #define LFDS711_PAL_PROCESSOR_STRING            \"x86\"\n\n  #define LFDS711_PAL_ALIGN_SINGLE_POINTER        4\n  #define LFDS711_PAL_ALIGN_DOUBLE_POINTER        8\n\n  #define LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES   32\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined __GNUC__ && defined __x86_64__ )\n\n  #ifdef LFDS711_PAL_PROCESSOR\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_processor.h\".\n  #endif\n\n  #define LFDS711_PAL_PROCESSOR\n\n  typedef int long long          lfds711_pal_int_t;\n  typedef int long long unsigned lfds711_pal_uint_t;\n\n  #define LFDS711_PAL_PROCESSOR_STRING            \"x64\"\n\n  #define LFDS711_PAL_ALIGN_SINGLE_POINTER        8\n  #define LFDS711_PAL_ALIGN_DOUBLE_POINTER        16\n\n  #define LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES   128\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined __GNUC__ && defined __alpha__ )\n\n  #ifdef LFDS711_PAL_PROCESSOR\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_processor.h\".\n  #endif\n\n  #define LFDS711_PAL_PROCESSOR\n\n  typedef int long          lfds711_pal_int_t;\n  typedef int long unsigned lfds711_pal_uint_t;\n\n  #define LFDS711_PAL_PROCESSOR_STRING            \"alpha\"\n\n  #define LFDS711_PAL_ALIGN_SINGLE_POINTER        8\n  #define LFDS711_PAL_ALIGN_DOUBLE_POINTER        16\n\n  #define LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES   64\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined __GNUC__ && defined __ia64__ )\n\n  #ifdef LFDS711_PAL_PROCESSOR\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_processor.h\".\n  #endif\n\n  #define LFDS711_PAL_PROCESSOR\n\n  typedef int long long          lfds711_pal_int_t;\n  typedef int long long unsigned lfds711_pal_uint_t;\n\n  #define LFDS711_PAL_PROCESSOR_STRING            \"IA64\"\n\n  #define LFDS711_PAL_ALIGN_SINGLE_POINTER        8\n  #define LFDS711_PAL_ALIGN_DOUBLE_POINTER        16\n\n  #define LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES   64\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined __GNUC__ && defined __mips__ && !defined __mips64 )\n\n  #ifdef LFDS711_PAL_PROCESSOR\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_processor.h\".\n  #endif\n\n  #define LFDS711_PAL_PROCESSOR\n\n  typedef int long          lfds711_pal_int_t;\n  typedef int long unsigned lfds711_pal_uint_t;\n\n  #define LFDS711_PAL_PROCESSOR_STRING            \"MIPS (32-bit)\"\n\n  #define LFDS711_PAL_ALIGN_SINGLE_POINTER        4\n  #define LFDS711_PAL_ALIGN_DOUBLE_POINTER        8\n\n  #define LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES   32\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined __GNUC__ && defined __mips__ && defined __mips64 )\n\n  #ifdef LFDS711_PAL_PROCESSOR\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_processor.h\".\n  #endif\n\n  #define LFDS711_PAL_PROCESSOR\n\n  typedef int long long          lfds711_pal_int_t;\n  typedef int long long unsigned lfds711_pal_uint_t;\n\n  #define LFDS711_PAL_PROCESSOR_STRING            \"MIPS (64-bit)\"\n\n  #define LFDS711_PAL_ALIGN_SINGLE_POINTER        8\n  #define LFDS711_PAL_ALIGN_DOUBLE_POINTER        16\n\n  #define LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES   64\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined __GNUC__ && defined __ppc__ )\n\n  #ifdef LFDS711_PAL_PROCESSOR\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_processor.h\".\n  #endif\n\n  #define LFDS711_PAL_PROCESSOR\n\n  typedef int long          lfds711_pal_int_t;\n  typedef int long unsigned lfds711_pal_uint_t;\n\n  #define LFDS711_PAL_PROCESSOR_STRING            \"POWERPC (32-bit)\"\n\n  #define LFDS711_PAL_ALIGN_SINGLE_POINTER        4\n  #define LFDS711_PAL_ALIGN_DOUBLE_POINTER        8\n\n  // TRD : this value is not very certain\n  #define LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES   128\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined __GNUC__ && defined __ppc64__ )\n\n  #ifdef LFDS711_PAL_PROCESSOR\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_processor.h\".\n  #endif\n\n  #define LFDS711_PAL_PROCESSOR\n\n  typedef int long long          lfds711_pal_int_t;\n  typedef int long long unsigned lfds711_pal_uint_t;\n\n  #define LFDS711_PAL_PROCESSOR_STRING            \"POWERPC (64-bit)\"\n\n  #define LFDS711_PAL_ALIGN_SINGLE_POINTER        8\n  #define LFDS711_PAL_ALIGN_DOUBLE_POINTER        16\n\n  // TRD : this value is not very certain\n  #define LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES   128\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined __GNUC__ && defined __sparc__ && !defined __sparc_v9__ )\n\n  #ifdef LFDS711_PAL_PROCESSOR\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_processor.h\".\n  #endif\n\n  #define LFDS711_PAL_PROCESSOR\n\n  typedef int long          lfds711_pal_int_t;\n  typedef int long unsigned lfds711_pal_uint_t;\n\n  #define LFDS711_PAL_PROCESSOR_STRING            \"SPARC (32-bit)\"\n\n  #define LFDS711_PAL_ALIGN_SINGLE_POINTER        4\n  #define LFDS711_PAL_ALIGN_DOUBLE_POINTER        8\n\n  #define LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES   32\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined __GNUC__ && defined __sparc__ && defined __sparc_v9__ )\n\n  #ifdef LFDS711_PAL_PROCESSOR\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_processor.h\".\n  #endif\n\n  #define LFDS711_PAL_PROCESSOR\n\n  typedef int long long          lfds711_pal_int_t;\n  typedef int long long unsigned lfds711_pal_uint_t;\n\n  #define LFDS711_PAL_PROCESSOR_STRING            \"SPARC (64-bit)\"\n\n  #define LFDS711_PAL_ALIGN_SINGLE_POINTER        8\n  #define LFDS711_PAL_ALIGN_DOUBLE_POINTER        16\n\n  #define LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES   64\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( defined __GNUC__ && defined __m68k__ )\n\n  #ifdef LFDS711_PAL_PROCESSOR\n    #error More than one porting abstraction layer matches the current platform in \"lfds711_porting_abstraction_layer_processor.h\".\n  #endif\n\n  #define LFDS711_PAL_PROCESSOR\n\n  typedef int long          lfds711_pal_int_t;\n  typedef int long unsigned lfds711_pal_uint_t;\n\n  #define LFDS711_PAL_PROCESSOR_STRING            \"680x0\"\n\n  #define LFDS711_PAL_ALIGN_SINGLE_POINTER        4\n  #define LFDS711_PAL_ALIGN_DOUBLE_POINTER        8\n\n  #define LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES   32\n\n#endif\n\n\n\n\n\n/****************************************************************************/\n#if( !defined LFDS711_PAL_PROCESSOR )\n\n  #error No matching porting abstraction layer in \"lfds711_porting_abstraction_layer_processor.h\".\n\n#endif\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/inc/liblfds711/lfds711_prng.h",
    "content": "/***** defines *****/\n#define LFDS711_PRNG_MAX  ( (lfds711_pal_uint_t) -1 )\n\n/* TRD : the seed is from an on-line hardware RNG, using atmospheric noise\n         the URL below will generate another 16 random hex digits (e.g. a 64-bit number) and is\n         the RNG used to generate the number above (0x0a34655d34c092fe)\n\n         http://www.random.org/integers/?num=16&min=0&max=15&col=1&base=16&format=plain&rnd=new\n\n         the 32 bit seed is the upper half of the 64 bit seed\n\n         the \"SplitMix\" PRNG is from from Sebastiano vigna's site, CC0 license, http://xorshift.di.unimi.it/splitmix64.c\n         the 64-bit constants come directly from the source, the 32-bt constants are in fact the 32-bit murmurhash3 constants\n*/\n\n#if( LFDS711_PAL_ALIGN_SINGLE_POINTER == 4 )\n  #define LFDS711_PRNG_SEED                            0x0a34655dUL\n  #define LFDS711_PRNG_SPLITMIX_MAGIC_RATIO            0x9E3779B9UL\n  #define LFDS711_PRNG_SPLITMIX_SHIFT_CONSTANT_ONE     16\n  #define LFDS711_PRNG_SPLITMIX_SHIFT_CONSTANT_TWO     13\n  #define LFDS711_PRNG_SPLITMIX_SHIFT_CONSTANT_THREE   16\n  #define LFDS711_PRNG_SPLITMIX_MULTIPLY_CONSTANT_ONE  0x85ebca6bUL\n  #define LFDS711_PRNG_SPLITMIX_MULTIPLY_CONSTANT_TWO  0xc2b2ae35UL\n#endif\n\n#if( LFDS711_PAL_ALIGN_SINGLE_POINTER == 8 )\n  #define LFDS711_PRNG_SEED                            0x0a34655d34c092feULL\n  #define LFDS711_PRNG_SPLITMIX_MAGIC_RATIO            0x9E3779B97F4A7C15ULL\n  #define LFDS711_PRNG_SPLITMIX_SHIFT_CONSTANT_ONE     30\n  #define LFDS711_PRNG_SPLITMIX_SHIFT_CONSTANT_TWO     27\n  #define LFDS711_PRNG_SPLITMIX_SHIFT_CONSTANT_THREE   31\n  #define LFDS711_PRNG_SPLITMIX_MULTIPLY_CONSTANT_ONE  0xBF58476D1CE4E5B9ULL\n  #define LFDS711_PRNG_SPLITMIX_MULTIPLY_CONSTANT_TWO  0x94D049BB133111EBULL\n#endif\n\n// TRD : struct lfds711_prng_state prng_state, lfds711_pal_uint_t random_value\n#define LFDS711_PRNG_GENERATE( prng_state, random_value )                                                                  \\\n{                                                                                                                          \\\n  LFDS711_PAL_ATOMIC_ADD( &(prng_state).entropy, LFDS711_PRNG_SPLITMIX_MAGIC_RATIO, (random_value), lfds711_pal_uint_t );  \\\n  LFDS711_PRNG_ST_MIXING_FUNCTION( random_value );                                                                         \\\n}\n\n// TRD : struct lfds711_prng_state prng_st_state, lfds711_pal_uint_t random_value\n#define LFDS711_PRNG_ST_GENERATE( prng_st_state, random_value )                       \\\n{                                                                                     \\\n  (random_value) = ( (prng_st_state).entropy += LFDS711_PRNG_SPLITMIX_MAGIC_RATIO );  \\\n  LFDS711_PRNG_ST_MIXING_FUNCTION( random_value );                                    \\\n}\n\n// TRD : lfds711_pal_uint_t random_value\n#define LFDS711_PRNG_ST_MIXING_FUNCTION( random_value )                                                                                            \\\n{                                                                                                                                                  \\\n  (random_value) = ((random_value) ^ ((random_value) >> LFDS711_PRNG_SPLITMIX_SHIFT_CONSTANT_ONE)) * LFDS711_PRNG_SPLITMIX_MULTIPLY_CONSTANT_ONE;  \\\n  (random_value) = ((random_value) ^ ((random_value) >> LFDS711_PRNG_SPLITMIX_SHIFT_CONSTANT_TWO)) * LFDS711_PRNG_SPLITMIX_MULTIPLY_CONSTANT_TWO;  \\\n  (random_value) = (random_value ^ (random_value >> LFDS711_PRNG_SPLITMIX_SHIFT_CONSTANT_THREE));                                                  \\\n}\n\n/***** structs *****/\nstruct lfds711_prng_state\n{\n  lfds711_pal_uint_t volatile LFDS711_PAL_ALIGN(LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES)\n    entropy;\n};\n\nstruct lfds711_prng_st_state\n{\n  lfds711_pal_uint_t\n    entropy;\n};\n\n/***** public prototypes *****/\nvoid lfds711_prng_init_valid_on_current_logical_core( struct lfds711_prng_state *ps, lfds711_pal_uint_t seed );\nvoid lfds711_prng_st_init( struct lfds711_prng_st_state *psts, lfds711_pal_uint_t seed );\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/inc/liblfds711/lfds711_queue_bounded_manyproducer_manyconsumer.h",
    "content": "/***** defines *****/\n#define LFDS711_QUEUE_BMM_GET_USER_STATE_FROM_STATE( queue_bmm_state )  ( (queue_bmm_state).user_state )\n\n/***** enums *****/\nenum lfds711_queue_bmm_query\n{\n  LFDS711_QUEUE_BMM_QUERY_GET_POTENTIALLY_INACCURATE_COUNT,\n  LFDS711_QUEUE_BMM_QUERY_SINGLETHREADED_VALIDATE\n};\n\n/***** structures *****/\nstruct lfds711_queue_bmm_element\n{\n  lfds711_pal_uint_t volatile\n    sequence_number;\n\n  void\n    *volatile key,\n    *volatile value;\n};\n\nstruct lfds711_queue_bmm_state\n{\n  lfds711_pal_uint_t\n    number_elements,\n    mask;\n\n  lfds711_pal_uint_t volatile LFDS711_PAL_ALIGN(LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES)\n    read_index,\n    write_index;\n\n  struct lfds711_queue_bmm_element\n    *element_array;\n\n  void\n    *user_state;\n\n  struct lfds711_misc_backoff_state\n    dequeue_backoff,\n    enqueue_backoff;\n};\n\n/***** public prototypes *****/\nvoid lfds711_queue_bmm_init_valid_on_current_logical_core( struct lfds711_queue_bmm_state *qbmms,\n                                                           struct lfds711_queue_bmm_element *element_array,\n                                                           lfds711_pal_uint_t number_elements,\n                                                           void *user_state );\n\nvoid lfds711_queue_bmm_cleanup( struct lfds711_queue_bmm_state *qbmms,\n                                void (*element_cleanup_callback)(struct lfds711_queue_bmm_state *qbmms,\n                                                                 void *key,\n                                                                 void *value) );\n\nint lfds711_queue_bmm_enqueue( struct lfds711_queue_bmm_state *qbmms,\n                               void *key,\n                               void *value );\n\nint lfds711_queue_bmm_dequeue( struct lfds711_queue_bmm_state *qbmms,\n                                      void **key,\n                                      void **value );\n\nvoid lfds711_queue_bmm_query( struct lfds711_queue_bmm_state *qbmms,\n                              enum lfds711_queue_bmm_query query_type,\n                              void *query_input,\n                              void *query_output );\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/inc/liblfds711/lfds711_queue_bounded_singleproducer_singleconsumer.h",
    "content": "/***** defines *****/\n#define LFDS711_QUEUE_BSS_GET_USER_STATE_FROM_STATE( queue_bss_state )  ( (queue_bss_state).user_state )\n\n/***** enums *****/\nenum lfds711_queue_bss_query\n{\n  LFDS711_QUEUE_BSS_QUERY_GET_POTENTIALLY_INACCURATE_COUNT,\n  LFDS711_QUEUE_BSS_QUERY_VALIDATE\n};\n\n/***** structures *****/\nstruct lfds711_queue_bss_element\n{\n  void\n    *volatile key,\n    *volatile value;\n};\n\nstruct lfds711_queue_bss_state\n{\n  lfds711_pal_uint_t\n    number_elements,\n    mask;\n\n  lfds711_pal_uint_t volatile\n    read_index,\n    write_index;\n\n  struct lfds711_queue_bss_element\n    *element_array;\n\n  void\n    *user_state;\n};\n\n/***** public prototypes *****/\nvoid lfds711_queue_bss_init_valid_on_current_logical_core( struct lfds711_queue_bss_state *qbsss, \n                                                           struct lfds711_queue_bss_element *element_array,\n                                                           lfds711_pal_uint_t number_elements,\n                                                           void *user_state );\n  // TRD : number_elements must be a positive integer power of 2\n  // TRD : used in conjunction with the #define LFDS711_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE\n\nvoid lfds711_queue_bss_cleanup( struct lfds711_queue_bss_state *qbsss,\n                                void (*element_cleanup_callback)(struct lfds711_queue_bss_state *qbsss, void *key, void *value) );\n\nint lfds711_queue_bss_enqueue( struct lfds711_queue_bss_state *qbsss,\n                               void *key,\n                               void *value );\n\nint lfds711_queue_bss_dequeue( struct lfds711_queue_bss_state *qbsss,\n                               void **key,\n                               void **value );\n\nvoid lfds711_queue_bss_query( struct lfds711_queue_bss_state *qbsss,\n                              enum lfds711_queue_bss_query query_type,\n                              void *query_input,\n                              void *query_output );\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/inc/liblfds711/lfds711_queue_unbounded_manyproducer_manyconsumer.h",
    "content": "/***** defines *****/\n#define LFDS711_QUEUE_UMM_GET_KEY_FROM_ELEMENT( queue_umm_element )             ( (queue_umm_element).key )\n#define LFDS711_QUEUE_UMM_SET_KEY_IN_ELEMENT( queue_umm_element, new_key )      ( (queue_umm_element).key = (void *) (lfds711_pal_uint_t) (new_key) )\n#define LFDS711_QUEUE_UMM_GET_VALUE_FROM_ELEMENT( queue_umm_element )           ( (queue_umm_element).value )\n#define LFDS711_QUEUE_UMM_SET_VALUE_IN_ELEMENT( queue_umm_element, new_value )  ( (queue_umm_element).value = (void *) (lfds711_pal_uint_t) (new_value) )\n#define LFDS711_QUEUE_UMM_GET_USER_STATE_FROM_STATE( queue_umm_state )          ( (queue_umm_state).user_state )\n\n/***** enums *****/\nenum lfds711_queue_umm_query\n{\n  LFDS711_QUEUE_UMM_QUERY_SINGLETHREADED_GET_COUNT,\n  LFDS711_QUEUE_UMM_QUERY_SINGLETHREADED_VALIDATE\n};\n\n/***** structures *****/\nstruct lfds711_queue_umm_element\n{\n  struct lfds711_queue_umm_element LFDS711_PAL_ALIGN(LFDS711_PAL_ALIGN_DOUBLE_POINTER)\n    *volatile next[PAC_SIZE];\n\n  void\n    *key,\n    *value;\n};\n\nstruct lfds711_queue_umm_state\n{\n  struct lfds711_queue_umm_element LFDS711_PAL_ALIGN(LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES)\n    *volatile enqueue[PAC_SIZE],\n    *volatile dequeue[PAC_SIZE];\n\n  lfds711_pal_uint_t volatile LFDS711_PAL_ALIGN(LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES)\n    aba_counter;\n\n  void LFDS711_PAL_ALIGN(LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES)\n    *user_state;\n\n  struct lfds711_misc_backoff_state\n    dequeue_backoff,\n    enqueue_backoff;\n};\n\n/***** public prototypes *****/\nvoid lfds711_queue_umm_init_valid_on_current_logical_core( struct lfds711_queue_umm_state *qumms,\n                                                           struct lfds711_queue_umm_element *qumme_dummy,\n                                                           void *user_state );\n  // TRD : used in conjunction with the #define LFDS711_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE\n\nvoid lfds711_queue_umm_cleanup( struct lfds711_queue_umm_state *qumms,\n                                void (*element_cleanup_callback)(struct lfds711_queue_umm_state *qumms, struct lfds711_queue_umm_element *qumme, enum lfds711_misc_flag dummy_element_flag) );\n\nvoid lfds711_queue_umm_enqueue( struct lfds711_queue_umm_state *qumms,\n                                struct lfds711_queue_umm_element *qumme );\n\nint lfds711_queue_umm_dequeue( struct lfds711_queue_umm_state *qumms,\n                               struct lfds711_queue_umm_element **qumme );\n\nvoid lfds711_queue_umm_query( struct lfds711_queue_umm_state *qumms,\n                              enum lfds711_queue_umm_query query_type,\n                              void *query_input,\n                              void *query_output );\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/inc/liblfds711/lfds711_ringbuffer.h",
    "content": "/***** enums *****/\n#define LFDS711_RINGBUFFER_GET_USER_STATE_FROM_STATE( ringbuffer_state )  ( (ringbuffer_state).user_state )\n\n/***** enums *****/\nenum lfds711_ringbuffer_query\n{\n  LFDS711_RINGBUFFER_QUERY_SINGLETHREADED_GET_COUNT,\n  LFDS711_RINGBUFFER_QUERY_SINGLETHREADED_VALIDATE\n};\n\n/***** structures *****/\nstruct lfds711_ringbuffer_element\n{\n  struct lfds711_freelist_element\n    fe;\n\n  struct lfds711_queue_umm_element\n    qumme;\n\n  struct lfds711_queue_umm_element\n    *qumme_use; // TRD : hack; we need a new queue with no dummy element\n\n  void\n    *key,\n    *value;\n};\n\nstruct lfds711_ringbuffer_state\n{\n  struct lfds711_freelist_state\n    fs;\n\n  struct lfds711_queue_umm_state\n    qumms;\n\n  void\n    (*element_cleanup_callback)( struct lfds711_ringbuffer_state *rs, void *key, void *value, enum lfds711_misc_flag unread_flag ),\n    *user_state;\n};\n\n/***** public prototypes *****/\nvoid lfds711_ringbuffer_init_valid_on_current_logical_core( struct lfds711_ringbuffer_state *rs,\n                                                            struct lfds711_ringbuffer_element *re_array_inc_dummy,\n                                                            lfds711_pal_uint_t number_elements_inc_dummy,\n                                                            void *user_state );\n  // TRD : used in conjunction with the #define LFDS711_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE\n\nvoid lfds711_ringbuffer_cleanup( struct lfds711_ringbuffer_state *rs,\n                                 void (*element_cleanup_callback)(struct lfds711_ringbuffer_state *rs, void *key, void *value, enum lfds711_misc_flag unread_flag) );\n\nint lfds711_ringbuffer_read( struct lfds711_ringbuffer_state *rs,\n                             void **key,\n                             void **value );\n\nvoid lfds711_ringbuffer_write( struct lfds711_ringbuffer_state *rs,\n                               void *key,\n                               void *value,\n                               enum lfds711_misc_flag *overwrite_occurred_flag,\n                               void **overwritten_key,\n                               void **overwritten_value );\n\nvoid lfds711_ringbuffer_query( struct lfds711_ringbuffer_state *rs,\n                               enum lfds711_ringbuffer_query query_type,\n                               void *query_input,\n                               void *query_output );\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/inc/liblfds711/lfds711_stack.h",
    "content": "/***** defines *****/\n#define LFDS711_STACK_GET_KEY_FROM_ELEMENT( stack_element )             ( (stack_element).key )\n#define LFDS711_STACK_SET_KEY_IN_ELEMENT( stack_element, new_key )      ( (stack_element).key = (void *) (lfds711_pal_uint_t) (new_key) )\n#define LFDS711_STACK_GET_VALUE_FROM_ELEMENT( stack_element )           ( (stack_element).value )\n#define LFDS711_STACK_SET_VALUE_IN_ELEMENT( stack_element, new_value )  ( (stack_element).value = (void *) (lfds711_pal_uint_t) (new_value) )\n#define LFDS711_STACK_GET_USER_STATE_FROM_STATE( stack_state )          ( (stack_state).user_state )\n\n/***** enums *****/\nenum lfds711_stack_query\n{\n  LFDS711_STACK_QUERY_SINGLETHREADED_GET_COUNT,\n  LFDS711_STACK_QUERY_SINGLETHREADED_VALIDATE\n};\n\n/***** structures *****/\nstruct lfds711_stack_element\n{\n  struct lfds711_stack_element\n    *next;\n\n  void\n    *key,\n    *value;\n};\n\nstruct lfds711_stack_state\n{\n  struct lfds711_stack_element LFDS711_PAL_ALIGN(LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES)\n    *volatile top[PAC_SIZE];\n\n  void LFDS711_PAL_ALIGN(LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES)\n    *user_state;\n\n  struct lfds711_misc_backoff_state\n    pop_backoff,\n    push_backoff;\n};\n\n/***** public prototypes *****/\nvoid lfds711_stack_init_valid_on_current_logical_core( struct lfds711_stack_state *ss,\n                                                       void *user_state );\n  // TRD : used in conjunction with the #define LFDS711_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE\n\nvoid lfds711_stack_cleanup( struct lfds711_stack_state *ss,\n                            void (*element_cleanup_callback)(struct lfds711_stack_state *ss, struct lfds711_stack_element *se) );\n\nvoid lfds711_stack_push( struct lfds711_stack_state *ss,\n                         struct lfds711_stack_element *se );\n\nint lfds711_stack_pop( struct lfds711_stack_state *ss,\n                       struct lfds711_stack_element **se );\n\nvoid lfds711_stack_query( struct lfds711_stack_state *ss,\n                          enum lfds711_stack_query query_type,\n                          void *query_input,\n                          void *query_output );\n\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/inc/liblfds711.h",
    "content": "#ifndef LIBLFDS711_H\n\n  /***** defines *****/\n  #define LIBLFDS711_H\n\n  /***** pragmas on *****/\n  #pragma warning( push )\n  #pragma warning( disable : 4324 )                                          // TRD : 4324 disables MSVC warnings for structure alignment padding due to alignment specifiers\n  #pragma prefast( disable : 28113 28182 28183, \"blah\" )\n\n  /***** includes *****/\n  #include \"liblfds711/lfds711_porting_abstraction_layer_compiler.h\"\n  #include \"liblfds711/lfds711_porting_abstraction_layer_operating_system.h\"\n  #include \"liblfds711/lfds711_porting_abstraction_layer_processor.h\"\n\n  #include \"liblfds711/lfds711_prng.h\"                                       // TRD : misc requires prng\n  #include \"liblfds711/lfds711_misc.h\"                                       // TRD : everything after depends on misc\n  #include \"liblfds711/lfds711_btree_addonly_unbalanced.h\"                   // TRD : hash_addonly depends on btree_addonly_unbalanced\n  #include \"liblfds711/lfds711_freelist.h\"\n  #include \"liblfds711/lfds711_hash_addonly.h\"\n  #include \"liblfds711/lfds711_list_addonly_singlylinked_ordered.h\"\n  #include \"liblfds711/lfds711_list_addonly_singlylinked_unordered.h\"\n  #include \"liblfds711/lfds711_queue_bounded_manyproducer_manyconsumer.h\"\n  #include \"liblfds711/lfds711_queue_bounded_singleproducer_singleconsumer.h\"\n  #include \"liblfds711/lfds711_queue_unbounded_manyproducer_manyconsumer.h\"\n  #include \"liblfds711/lfds711_ringbuffer.h\"\n  #include \"liblfds711/lfds711_stack.h\"\n\n  /***** pragmas off *****/\n  #pragma warning( pop )\n\n#endif\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/obj/.gitkeep",
    "content": ""
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_btree_addonly_unbalanced/lfds711_btree_addonly_unbalanced_cleanup.c",
    "content": "/***** includes *****/\n#include \"lfds711_btree_addonly_unbalanced_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_btree_au_cleanup( struct lfds711_btree_au_state *baus,\n                               void (*element_cleanup_callback)(struct lfds711_btree_au_state *baus, struct lfds711_btree_au_element *baue) )\n{\n  enum lfds711_btree_au_delete_action\n    delete_action = LFDS711_BTREE_AU_DELETE_SELF; // TRD : to remove compiler warning\n\n  struct lfds711_btree_au_element\n    *baue;\n\n  struct lfds711_btree_au_element\n    *temp;\n\n  LFDS711_PAL_ASSERT( baus != NULL );\n  // TRD : element_delete_function can be NULL\n\n  /* TRD : we're not lock-free now, so delete at will\n           but be iterative, so can be used in kernels (where there's little stack)\n           and be performant, since the user may be\n           creating/destroying many of these trees\n           also remember the user may be deallocating user data\n           so we cannot visit an element twice\n\n           we start at the root and iterate till we go to NULL\n           if the element has zero children, we delete it and move up to its parent\n           if the element has one child, we delete it, move its child into its place, and continue from its child\n           if the element has two children, we move left\n\n           the purpose of this is to minimize walking around the tree\n           to prevent visiting an element twice\n           while also minimizing code complexity\n  */\n\n  if( element_cleanup_callback == NULL )\n    return;\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  lfds711_btree_au_get_by_absolute_position( baus, &baue, LFDS711_BTREE_AU_ABSOLUTE_POSITION_ROOT );\n\n  while( baue != NULL )\n  {\n    if( baue->left == NULL and baue->right == NULL )\n      delete_action = LFDS711_BTREE_AU_DELETE_SELF;\n\n    if( baue->left != NULL and baue->right == NULL )\n      delete_action = LFDS711_BTREE_AU_DELETE_SELF_REPLACE_WITH_LEFT_CHILD;\n\n    if( baue->left == NULL and baue->right != NULL )\n      delete_action = LFDS711_BTREE_AU_DELETE_SELF_REPLACE_WITH_RIGHT_CHILD;\n\n    if( baue->left != NULL and baue->right != NULL )\n      delete_action = LFDS711_BTREE_AU_DELETE_MOVE_LEFT;\n\n    switch( delete_action )\n    {\n      case LFDS711_BTREE_AU_DELETE_SELF:\n        // TRD : if we have a parent (we could be root) set his point to us to NULL\n        if( baue->up != NULL )\n        {\n          if( baue->up->left == baue )\n            baue->up->left = NULL;\n          if( baue->up->right == baue )\n            baue->up->right = NULL;\n        }\n\n        temp = baue;\n        lfds711_btree_au_get_by_relative_position( &baue, LFDS711_BTREE_AU_RELATIVE_POSITION_UP );\n        element_cleanup_callback( baus, temp );\n      break;\n\n      case LFDS711_BTREE_AU_DELETE_SELF_REPLACE_WITH_LEFT_CHILD:\n        baue->left->up = baue->up;\n        if( baue->up != NULL )\n        {\n          if( baue->up->left == baue )\n            baue->up->left = baue->left;\n          if( baue->up->right == baue )\n            baue->up->right = baue->left;\n        }\n\n        temp = baue;\n        lfds711_btree_au_get_by_relative_position( &baue, LFDS711_BTREE_AU_RELATIVE_POSITION_LEFT );\n        element_cleanup_callback( baus, temp );\n      break;\n\n      case LFDS711_BTREE_AU_DELETE_SELF_REPLACE_WITH_RIGHT_CHILD:\n        baue->right->up = baue->up;\n        if( baue->up != NULL )\n        {\n          if( baue->up->left == baue )\n            baue->up->left = baue->right;\n          if( baue->up->right == baue )\n            baue->up->right = baue->right;\n        }\n\n        temp = baue;\n        lfds711_btree_au_get_by_relative_position( &baue, LFDS711_BTREE_AU_RELATIVE_POSITION_RIGHT );\n        element_cleanup_callback( baus, temp );\n      break;\n\n      case LFDS711_BTREE_AU_DELETE_MOVE_LEFT:\n        lfds711_btree_au_get_by_relative_position( &baue, LFDS711_BTREE_AU_RELATIVE_POSITION_LEFT );\n      break;\n    }\n  }\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_btree_addonly_unbalanced/lfds711_btree_addonly_unbalanced_get.c",
    "content": "/***** includes *****/\n#include \"lfds711_btree_addonly_unbalanced_internal.h\"\n\n/***** private prototypes *****/\nstatic void lfds711_btree_au_internal_inorder_walk_from_largest_get_next_smallest_element( struct lfds711_btree_au_element **baue );\nstatic void lfds711_btree_au_internal_inorder_walk_from_smallest_get_next_largest_element( struct lfds711_btree_au_element **baue );\n\n\n\n\n\n/****************************************************************************/\nint lfds711_btree_au_get_by_key( struct lfds711_btree_au_state *baus,\n                                 int (*key_compare_function)(void const *new_key, void const *existing_key),\n                                 void *key,\n                                 struct lfds711_btree_au_element **baue )\n{\n  int\n    compare_result = !0,\n    rv = 1;\n\n  LFDS711_PAL_ASSERT( baus != NULL );\n  // TRD : key_compare_function can be NULL\n  // TRD : key can be NULL\n  LFDS711_PAL_ASSERT( baue != NULL );\n\n  if( key_compare_function == NULL )\n    key_compare_function = baus->key_compare_function;\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  *baue = baus->root;\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  while( *baue != NULL and compare_result != 0 )\n  {\n    compare_result = key_compare_function( key, (*baue)->key );\n\n    if( compare_result < 0 )\n    {\n      *baue = (*baue)->left;\n      LFDS711_MISC_BARRIER_LOAD;\n    }\n\n    if( compare_result > 0 )\n    {\n      *baue = (*baue)->right;\n      LFDS711_MISC_BARRIER_LOAD;\n    }\n  }\n\n  if( *baue == NULL )\n    rv = 0;\n\n  return rv;\n}\n\n\n\n\n\n/****************************************************************************/\nint lfds711_btree_au_get_by_absolute_position( struct lfds711_btree_au_state *baus,\n                                               struct lfds711_btree_au_element **baue,\n                                               enum lfds711_btree_au_absolute_position absolute_position )\n{\n  int\n    rv = 1;\n\n  LFDS711_PAL_ASSERT( baus != NULL );\n  LFDS711_PAL_ASSERT( baue != NULL );\n  // TRD : absolute_position can be any value in its range\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  *baue = baus->root;\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  switch( absolute_position )\n  {\n    case LFDS711_BTREE_AU_ABSOLUTE_POSITION_ROOT:\n    break;\n\n    case LFDS711_BTREE_AU_ABSOLUTE_POSITION_LARGEST_IN_TREE:\n      if( *baue != NULL )\n        while( (*baue)->right != NULL )\n        {\n          *baue = (*baue)->right;\n          LFDS711_MISC_BARRIER_LOAD;\n        }\n    break;\n\n    case LFDS711_BTREE_AU_ABSOLUTE_POSITION_SMALLEST_IN_TREE:\n      if( *baue != NULL )\n        while( (*baue)->left != NULL )\n        {\n          *baue = (*baue)->left;\n          LFDS711_MISC_BARRIER_LOAD;\n        }\n    break;\n  }\n\n  if( *baue == NULL )\n    rv = 0;\n\n  return rv;\n}\n\n\n\n\n\n/****************************************************************************/\nint lfds711_btree_au_get_by_relative_position( struct lfds711_btree_au_element **baue,\n                                               enum lfds711_btree_au_relative_position relative_position )\n{\n  int\n    rv = 1;\n\n  LFDS711_PAL_ASSERT( baue != NULL );\n  // TRD : relative_position can baue any value in its range\n\n  if( *baue == NULL )\n    return 0;\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  switch( relative_position )\n  {\n    case LFDS711_BTREE_AU_RELATIVE_POSITION_UP:\n      *baue = (*baue)->up;\n      // TRD : no load barrier - up already existed, so is known to be safely propagated\n    break;\n\n    case LFDS711_BTREE_AU_RELATIVE_POSITION_LEFT:\n      *baue = (*baue)->left;\n      LFDS711_MISC_BARRIER_LOAD;\n    break;\n\n    case LFDS711_BTREE_AU_RELATIVE_POSITION_RIGHT:\n      *baue = (*baue)->right;\n      LFDS711_MISC_BARRIER_LOAD;\n    break;\n\n    case LFDS711_BTREE_AU_RELATIVE_POSITION_SMALLEST_ELEMENT_BELOW_CURRENT_ELEMENT:\n      *baue = (*baue)->left;\n      if( *baue != NULL )\n      {\n        LFDS711_MISC_BARRIER_LOAD;\n        while( (*baue)->right != NULL )\n        {\n          *baue = (*baue)->right;\n          LFDS711_MISC_BARRIER_LOAD;\n        }\n      }\n    break;\n\n    case LFDS711_BTREE_AU_RELATIVE_POSITION_LARGEST_ELEMENT_BELOW_CURRENT_ELEMENT:\n      *baue = (*baue)->right;\n      if( *baue != NULL )\n      {\n        LFDS711_MISC_BARRIER_LOAD;\n        while( (*baue)->left != NULL )\n        {\n          *baue = (*baue)->left;\n          LFDS711_MISC_BARRIER_LOAD;\n        }\n      }\n    break;\n\n    case LFDS711_BTREE_AU_RELATIVE_POSITION_NEXT_SMALLER_ELEMENT_IN_ENTIRE_TREE:\n      lfds711_btree_au_internal_inorder_walk_from_largest_get_next_smallest_element( baue );\n    break;\n\n    case LFDS711_BTREE_AU_RELATIVE_POSITION_NEXT_LARGER_ELEMENT_IN_ENTIRE_TREE:\n      lfds711_btree_au_internal_inorder_walk_from_smallest_get_next_largest_element( baue );\n    break;\n  }\n\n  if( *baue == NULL )\n    rv = 0;\n\n  return rv;\n}\n\n\n\n\n\n/****************************************************************************/\nstatic void lfds711_btree_au_internal_inorder_walk_from_largest_get_next_smallest_element( struct lfds711_btree_au_element **baue )\n{\n  enum lfds711_btree_au_move\n    action = LFDS711_BTREE_AU_MOVE_INVALID;\n\n  enum lfds711_misc_flag\n    finished_flag = LFDS711_MISC_FLAG_LOWERED,\n    load_finished_flag = LFDS711_MISC_FLAG_LOWERED;\n\n  struct lfds711_btree_au_element\n    *left = NULL,\n    *right = NULL,\n    *up = NULL,\n    *up_left = NULL,\n    *up_right = NULL;\n\n  LFDS711_PAL_ASSERT( baue != NULL );\n\n  /* TRD : from any given element, the next smallest element is;\n           1. if we have a left, it's the largest element on the right branch of our left child\n           2. if we don't have a left, and we're on the right of our parent, then it's our parent\n           3. if we don't have a left, and we're on the left of our parent or we have no parent,\n              iterative up the tree until we find the first child who is on the right of its parent; then it's the parent\n  */\n\n  /* TRD : we need to ensure the variables we use to decide our action are self-consistent\n           to do this, we make local copies of them all\n           then, if they are all not NULL, we can know they cannot change and we can continue\n           if however any of them are NULL, they could have changed while we were reading\n           and so our variables could be non-self-consistent\n           to check for this, we issue another processor read barrier\n           and then compare our local variables with the values in the tree\n           if they all match, then we know our variable set is self-consistent\n           (even though it may now be wrong - but we will discover this when we try the atomic operation)\n  */\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  while( load_finished_flag == LFDS711_MISC_FLAG_LOWERED )\n  {\n    left = (*baue)->left;\n    right = (*baue)->right;\n    up = (*baue)->up;\n    if( up != NULL )\n    {\n      up_left = (*baue)->up->left;\n      up_right = (*baue)->up->right;\n    }\n\n    // TRD : optimization - if all already not NULL, given we're add-only, they won't change\n    if( left != NULL and right != NULL and (up == NULL or (up != NULL and up_left != NULL and up_right != NULL)) )\n      break;\n\n    LFDS711_MISC_BARRIER_LOAD;\n\n    if( left == (*baue)->left and right == (*baue)->right and (up == NULL or (up != NULL and up == (*baue)->up and up_left == (*baue)->up->left and up_right == (*baue)->up->right)) )\n      load_finished_flag = LFDS711_MISC_FLAG_RAISED;\n  }\n\n  if( left != NULL )\n    action = LFDS711_BTREE_AU_MOVE_LARGEST_FROM_LEFT_CHILD;\n\n  if( left == NULL and up != NULL and up_right == *baue )\n    action = LFDS711_BTREE_AU_MOVE_GET_PARENT;\n\n  if( (left == NULL and up == NULL) or (up != NULL and up_left == *baue and left == NULL) )\n    action = LFDS711_BTREE_AU_MOVE_MOVE_UP_TREE;\n\n  switch( action )\n  {\n    case LFDS711_BTREE_AU_MOVE_INVALID:\n    case LFDS711_BTREE_AU_MOVE_SMALLEST_FROM_RIGHT_CHILD:\n      // TRD : eliminates a compiler warning\n    break;\n\n    case LFDS711_BTREE_AU_MOVE_LARGEST_FROM_LEFT_CHILD:\n      *baue = left;\n      if( *baue != NULL )\n      {\n        LFDS711_MISC_BARRIER_LOAD;\n        while( (*baue)->right != NULL )\n        {\n          *baue = (*baue)->right;\n          LFDS711_MISC_BARRIER_LOAD;\n        }\n      }\n    break;\n\n    case LFDS711_BTREE_AU_MOVE_GET_PARENT:\n      *baue = up;\n    break;\n\n    case LFDS711_BTREE_AU_MOVE_MOVE_UP_TREE:\n      while( finished_flag == LFDS711_MISC_FLAG_LOWERED )\n      {\n        load_finished_flag = LFDS711_MISC_FLAG_LOWERED;\n\n        while( load_finished_flag == LFDS711_MISC_FLAG_LOWERED )\n        {\n          up = (*baue)->up;\n          if( up != NULL )\n            up_left = (*baue)->up->left;\n\n          // TRD : optimization - if all already not NULL, given we're add-only, they won't change\n          if( up == NULL or (up != NULL and up_left != NULL) )\n            break;\n\n          LFDS711_MISC_BARRIER_LOAD;\n\n          if( up == (*baue)->up and up_left == (*baue)->up->left )\n            load_finished_flag = LFDS711_MISC_FLAG_RAISED;\n        }\n\n        if( *baue != NULL and up != NULL and *baue == up_left )\n          *baue = up;\n        else\n          finished_flag = LFDS711_MISC_FLAG_RAISED;\n      }\n\n      *baue = up;\n\n      /*\n\n      while( *baue != NULL and (*baue)->up != NULL and *baue == (*baue)->up->left )\n        *baue = (*baue)->up;\n\n      *baue = (*baue)->up;\n\n      */\n    break;\n  }\n\n  return;\n}\n\n\n\n\n\n/****************************************************************************/\nstatic void lfds711_btree_au_internal_inorder_walk_from_smallest_get_next_largest_element( struct lfds711_btree_au_element **baue )\n{\n  enum lfds711_btree_au_move\n    action = LFDS711_BTREE_AU_MOVE_INVALID;\n\n  enum lfds711_misc_flag\n    finished_flag = LFDS711_MISC_FLAG_LOWERED,\n    load_finished_flag = LFDS711_MISC_FLAG_LOWERED;\n\n  struct lfds711_btree_au_element\n    *left = NULL,\n    *right = NULL,\n    *up = NULL,\n    *up_left = NULL,\n    *up_right = NULL;\n\n  LFDS711_PAL_ASSERT( baue != NULL );\n\n  /* TRD : from any given element, the next largest element is;\n           1. if we have a right, it's the smallest element on the left branch of our right child\n           2. if we don't have a right, and we're on the left of our parent, then it's our parent\n           3. if we don't have a right, and we're on the right of our parent or we have no parent,\n              iterate up the tree until we find the first child who is on the left of its parent; then it's the parent\n  */\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  while( load_finished_flag == LFDS711_MISC_FLAG_LOWERED )\n  {\n    left = (*baue)->left;\n    right = (*baue)->right;\n    up = (*baue)->up;\n    if( up != NULL )\n    {\n      up_left = (*baue)->up->left;\n      up_right = (*baue)->up->right;\n    }\n\n    // TRD : optimization - if all already not NULL, given we're add-only, they won't change\n    if( left != NULL and right != NULL and (up == NULL or (up != NULL and up_left != NULL and up_right != NULL)) )\n      break;\n\n    LFDS711_MISC_BARRIER_LOAD;\n\n    if( left == (*baue)->left and right == (*baue)->right and (up == NULL or (up != NULL and up == (*baue)->up and up_left == (*baue)->up->left and up_right == (*baue)->up->right)) )\n      load_finished_flag = LFDS711_MISC_FLAG_RAISED;\n  }\n\n  if( right != NULL )\n    action = LFDS711_BTREE_AU_MOVE_SMALLEST_FROM_RIGHT_CHILD;\n\n  if( right == NULL and up != NULL and up_left == *baue )\n    action = LFDS711_BTREE_AU_MOVE_GET_PARENT;\n\n  if( (right == NULL and up == NULL) or (up != NULL and up_right == *baue and right == NULL) )\n    action = LFDS711_BTREE_AU_MOVE_MOVE_UP_TREE;\n\n  switch( action )\n  {\n    case LFDS711_BTREE_AU_MOVE_INVALID:\n    case LFDS711_BTREE_AU_MOVE_LARGEST_FROM_LEFT_CHILD:\n      // TRD : remove compiler warning\n    break;\n\n    case LFDS711_BTREE_AU_MOVE_SMALLEST_FROM_RIGHT_CHILD:\n      *baue = right;\n      if( *baue != NULL )\n      {\n        LFDS711_MISC_BARRIER_LOAD;\n        while( (*baue)->left != NULL )\n        {\n          *baue = (*baue)->left;\n          LFDS711_MISC_BARRIER_LOAD;\n        }\n      }\n    break;\n\n    case LFDS711_BTREE_AU_MOVE_GET_PARENT:\n      *baue = up;\n    break;\n\n    case LFDS711_BTREE_AU_MOVE_MOVE_UP_TREE:\n      while( finished_flag == LFDS711_MISC_FLAG_LOWERED )\n      {\n        load_finished_flag = LFDS711_MISC_FLAG_LOWERED;\n\n        while( load_finished_flag == LFDS711_MISC_FLAG_LOWERED )\n        {\n          up = (*baue)->up;\n          if( up != NULL )\n            up_right = (*baue)->up->right;\n\n          // TRD : optimization - if all already not NULL, given we're add-only, they won't change\n          if( up == NULL or (up != NULL and up_right != NULL) )\n            break;\n\n          LFDS711_MISC_BARRIER_LOAD;\n\n          if( up == (*baue)->up and up_right == (*baue)->up->right )\n            load_finished_flag = LFDS711_MISC_FLAG_RAISED;\n        }\n\n        if( *baue != NULL and up != NULL and *baue == up_right )\n          *baue = up;\n        else\n          finished_flag = LFDS711_MISC_FLAG_RAISED;\n      }\n\n      *baue = up;\n\n      /*\n\n      while( *baue != NULL and (*baue)->up != NULL and *baue == (*baue)->up->right )\n        *baue = (*baue)->up;\n\n      *baue = (*baue)->up;\n\n      */\n    break;\n  }\n\n  return;\n}\n\n\n\n\n\n/****************************************************************************/\nint lfds711_btree_au_get_by_absolute_position_and_then_by_relative_position( struct lfds711_btree_au_state *baus,\n                                                                             struct lfds711_btree_au_element **baue,\n                                                                             enum lfds711_btree_au_absolute_position absolute_position,\n                                                                             enum lfds711_btree_au_relative_position relative_position )\n{\n  int\n    rv;\n\n  LFDS711_PAL_ASSERT( baus != NULL );\n  LFDS711_PAL_ASSERT( baue != NULL );\n  // TRD: absolute_position can be any value in its range\n  // TRD: relative_position can be any value in its range\n\n  if( *baue == NULL )\n    rv = lfds711_btree_au_get_by_absolute_position( baus, baue, absolute_position );\n  else\n    rv = lfds711_btree_au_get_by_relative_position( baue, relative_position );\n\n  return rv;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_btree_addonly_unbalanced/lfds711_btree_addonly_unbalanced_init.c",
    "content": "/***** includes *****/\n#include \"lfds711_btree_addonly_unbalanced_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_btree_au_init_valid_on_current_logical_core( struct lfds711_btree_au_state *baus,\n                                                          int (*key_compare_function)(void const *new_key, void const *existing_key),\n                                                          enum lfds711_btree_au_existing_key existing_key,\n                                                          void *user_state )\n{\n  LFDS711_PAL_ASSERT( baus != NULL );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &baus->root % LFDS711_PAL_ALIGN_SINGLE_POINTER == 0 );\n  LFDS711_PAL_ASSERT( key_compare_function != NULL );\n  // TRD : existing_key can be any value in its range\n  // TRD : user_state can be NULL\n\n  baus->root = NULL;\n  baus->key_compare_function = key_compare_function;\n  baus->existing_key = existing_key;\n  baus->user_state = user_state;\n\n  lfds711_misc_internal_backoff_init( &baus->insert_backoff );\n\n  LFDS711_MISC_BARRIER_STORE;\n\n  lfds711_misc_force_store();\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_btree_addonly_unbalanced/lfds711_btree_addonly_unbalanced_insert.c",
    "content": "/***** includes *****/\n#include \"lfds711_btree_addonly_unbalanced_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nenum lfds711_btree_au_insert_result lfds711_btree_au_insert( struct lfds711_btree_au_state *baus,\n                                                             struct lfds711_btree_au_element *baue,\n                                                             struct lfds711_btree_au_element **existing_baue )\n{\n  char unsigned \n    result = 0;\n\n  int\n    compare_result = 0;\n\n  lfds711_pal_uint_t\n    backoff_iteration = LFDS711_BACKOFF_INITIAL_VALUE;\n\n  struct lfds711_btree_au_element\n    *compare = NULL,\n    *volatile baue_next = NULL,\n    *volatile baue_parent = NULL,\n    *volatile baue_temp;\n\n  LFDS711_PAL_ASSERT( baus != NULL );\n  LFDS711_PAL_ASSERT( baue != NULL );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &baue->left % LFDS711_PAL_ALIGN_SINGLE_POINTER == 0 );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &baue->right % LFDS711_PAL_ALIGN_SINGLE_POINTER == 0 );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &baue->up % LFDS711_PAL_ALIGN_SINGLE_POINTER == 0 );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &baue->value % LFDS711_PAL_ALIGN_SINGLE_POINTER == 0 );\n  // TRD : existing_baue can be NULL\n\n  /* TRD : we follow a normal search for the insert node and which side to insert\n\n           the difference is that insertion may fail because someone else inserts\n           there before we do\n\n           in this case, we resume searching for the insert node from the node\n           we were attempting to insert upon\n\n           (if we attempted to insert the root node and this failed, i.e. we thought\n            the tree was empty but then it wasn't, then we start searching from the\n            new root)\n  */\n\n  baue->up = baue->left = baue->right = NULL;\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  baue_temp = baus->root;\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  while( result == 0 )\n  {\n    // TRD : first we find where to insert\n    while( baue_temp != NULL )\n    {\n      compare_result = baus->key_compare_function( baue->key, baue_temp->key );\n\n      if( compare_result == 0 )\n      {\n        if( existing_baue != NULL )\n          *existing_baue = baue_temp;\n\n        switch( baus->existing_key )\n        {\n          case LFDS711_BTREE_AU_EXISTING_KEY_OVERWRITE:\n            LFDS711_BTREE_AU_SET_VALUE_IN_ELEMENT( *baue_temp, baue->value );\n            return LFDS711_BTREE_AU_INSERT_RESULT_SUCCESS_OVERWRITE;\n          break;\n\n          case LFDS711_BTREE_AU_EXISTING_KEY_FAIL:\n            return LFDS711_BTREE_AU_INSERT_RESULT_FAILURE_EXISTING_KEY;\n          break;\n        }\n      }\n\n      if( compare_result < 0 )\n        baue_next = baue_temp->left;\n\n      if( compare_result > 0 )\n        baue_next = baue_temp->right;\n\n      baue_parent = baue_temp;\n      baue_temp = baue_next;\n      if( baue_temp != NULL )\n        LFDS711_MISC_BARRIER_LOAD;\n    }\n\n    /* TRD : second, we actually insert\n\n             at this point baue_temp has come to NULL\n             and baue_parent is the element to insert at\n             and result of the last compare indicates\n             the direction of insertion\n\n             it may be that another tree has already inserted an element with\n             the same key as ourselves, or other elements which mean our position\n             is now wrong\n\n             in this case, it is either inserted in the position we're trying\n             to insert in now, in which case our insert will fail\n\n             or, similarly, other elements will have come in where we are,\n             and our insert will fail\n    */\n\n    if( baue_parent == NULL )\n    {\n      compare = NULL;\n      baue->up = baus->root;\n      LFDS711_MISC_BARRIER_STORE;\n      LFDS711_PAL_ATOMIC_CAS( &baus->root, &compare, baue, LFDS711_MISC_CAS_STRENGTH_WEAK, result );\n\n      if( result == 0 )\n        baue_temp = baus->root;\n    }\n\n    if( baue_parent != NULL )\n    {\n      if( compare_result <= 0 )\n      {\n        compare = NULL;\n        baue->up = baue_parent;\n        LFDS711_MISC_BARRIER_STORE;\n        LFDS711_PAL_ATOMIC_CAS( &baue_parent->left, &compare, baue, LFDS711_MISC_CAS_STRENGTH_WEAK, result );\n      }\n\n      if( compare_result > 0 )\n      {\n        compare = NULL;\n        baue->up = baue_parent;\n        LFDS711_MISC_BARRIER_STORE;\n        LFDS711_PAL_ATOMIC_CAS( &baue_parent->right, &compare, baue, LFDS711_MISC_CAS_STRENGTH_WEAK, result );\n      }\n\n      // TRD : if the insert fails, then resume searching at the insert node\n      if( result == 0 )\n        baue_temp = baue_parent;\n    }\n\n    if( result == 0 )\n      LFDS711_BACKOFF_EXPONENTIAL_BACKOFF( baus->insert_backoff, backoff_iteration );\n  }\n\n  LFDS711_BACKOFF_AUTOTUNE( baus->insert_backoff, backoff_iteration );\n\n  // TRD : if we get to here, we added (not failed or overwrite on exist) a new element\n  if( existing_baue != NULL )\n    *existing_baue = NULL;\n\n  return LFDS711_BTREE_AU_INSERT_RESULT_SUCCESS;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_btree_addonly_unbalanced/lfds711_btree_addonly_unbalanced_internal.h",
    "content": "/***** the library-wide header file *****/\n#include \"../liblfds711_internal.h\"\n\n/***** enums *****/\nenum lfds711_btree_au_move\n{\n  LFDS711_BTREE_AU_MOVE_INVALID,\n  LFDS711_BTREE_AU_MOVE_SMALLEST_FROM_RIGHT_CHILD,\n  LFDS711_BTREE_AU_MOVE_LARGEST_FROM_LEFT_CHILD,\n  LFDS711_BTREE_AU_MOVE_GET_PARENT,\n  LFDS711_BTREE_AU_MOVE_MOVE_UP_TREE\n};\n\nenum lfds711_btree_au_delete_action\n{\n  LFDS711_BTREE_AU_DELETE_SELF,\n  LFDS711_BTREE_AU_DELETE_SELF_REPLACE_WITH_LEFT_CHILD,\n  LFDS711_BTREE_AU_DELETE_SELF_REPLACE_WITH_RIGHT_CHILD,\n  LFDS711_BTREE_AU_DELETE_MOVE_LEFT\n};\n\n/***** private prototypes *****/\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_btree_addonly_unbalanced/lfds711_btree_addonly_unbalanced_query.c",
    "content": "/***** includes *****/\n#include \"lfds711_btree_addonly_unbalanced_internal.h\"\n\n/***** private prototypes *****/\nstatic void lfds711_btree_au_internal_validate( struct lfds711_btree_au_state *abs, struct lfds711_misc_validation_info *vi, enum lfds711_misc_validity *lfds711_btree_au_validity );\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_btree_au_query( struct lfds711_btree_au_state *baus,\n                             enum lfds711_btree_au_query query_type,\n                             void *query_input,\n                             void *query_output )\n{\n  LFDS711_PAL_ASSERT( baus != NULL );\n  // TRD : query_type can be any value in its range\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  switch( query_type )\n  {\n    case LFDS711_BTREE_AU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT:\n    {\n      struct lfds711_btree_au_element\n        *baue = NULL;\n\n      LFDS711_PAL_ASSERT( query_input == NULL );\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      *(lfds711_pal_uint_t *) query_output = 0;\n\n      while( lfds711_btree_au_get_by_absolute_position_and_then_by_relative_position(baus, &baue, LFDS711_BTREE_AU_ABSOLUTE_POSITION_SMALLEST_IN_TREE, LFDS711_BTREE_AU_RELATIVE_POSITION_NEXT_LARGER_ELEMENT_IN_ENTIRE_TREE) )\n        ( *(lfds711_pal_uint_t *) query_output )++;\n    }\n    break;\n\n    case LFDS711_BTREE_AU_QUERY_SINGLETHREADED_VALIDATE:\n      // TRD : query_input can be NULL\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      lfds711_btree_au_internal_validate( baus, (struct lfds711_misc_validation_info *) query_input, (enum lfds711_misc_validity *) query_output );\n    break;\n  }\n\n  return;\n}\n\n\n\n\n\n/****************************************************************************/\nstatic void lfds711_btree_au_internal_validate( struct lfds711_btree_au_state *baus,\n                                                struct lfds711_misc_validation_info *vi,\n                                                enum lfds711_misc_validity *lfds711_btree_au_validity )\n{\n  lfds711_pal_uint_t\n    number_elements_from_query_tree = 0,\n    number_elements_from_walk = 0;\n\n  struct lfds711_btree_au_element\n    *baue = NULL,\n    *baue_prev = NULL;\n\n  LFDS711_PAL_ASSERT( baus!= NULL );\n  // TRD : vi can be NULL\n  LFDS711_PAL_ASSERT( lfds711_btree_au_validity != NULL );\n\n  *lfds711_btree_au_validity = LFDS711_MISC_VALIDITY_VALID;\n\n  /* TRD : validation is performed by;\n\n           performing an in-order walk\n           we should see every element is larger than the preceeding element\n           we count elements as we go along (visited elements, that is)\n           and check our tally equals the expected count\n  */\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  while( lfds711_btree_au_get_by_absolute_position_and_then_by_relative_position(baus, &baue, LFDS711_BTREE_AU_ABSOLUTE_POSITION_SMALLEST_IN_TREE, LFDS711_BTREE_AU_RELATIVE_POSITION_NEXT_LARGER_ELEMENT_IN_ENTIRE_TREE) )\n  {\n    // TRD : baue_prev should always be smaller than or equal to baue\n    if( baue_prev != NULL )\n      if( baus->key_compare_function(baue_prev->key, baue->key) > 0 )\n      {\n        *lfds711_btree_au_validity = LFDS711_MISC_VALIDITY_INVALID_ORDER;\n        return;\n      }\n\n    baue_prev = baue;\n    number_elements_from_walk++;\n  }\n\n  if( *lfds711_btree_au_validity == LFDS711_MISC_VALIDITY_VALID )\n  {\n    lfds711_btree_au_query( (struct lfds711_btree_au_state *) baus, LFDS711_BTREE_AU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, &number_elements_from_query_tree );\n\n    if( number_elements_from_walk > number_elements_from_query_tree )\n      *lfds711_btree_au_validity = LFDS711_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS;\n\n    if( number_elements_from_walk < number_elements_from_query_tree )\n      *lfds711_btree_au_validity = LFDS711_MISC_VALIDITY_INVALID_MISSING_ELEMENTS;\n  }\n\n  /* TRD : now check for expected number of elements\n           vi can be NULL, in which case we do not check\n           we know we don't have a loop from our earlier check\n  */\n\n  if( *lfds711_btree_au_validity == LFDS711_MISC_VALIDITY_VALID and vi != NULL )\n  {\n    lfds711_btree_au_query( (struct lfds711_btree_au_state *) baus, LFDS711_BTREE_AU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, &number_elements_from_query_tree );\n\n    if( number_elements_from_query_tree < vi->min_elements )\n      *lfds711_btree_au_validity = LFDS711_MISC_VALIDITY_INVALID_MISSING_ELEMENTS;\n\n    if( number_elements_from_query_tree > vi->max_elements )\n      *lfds711_btree_au_validity = LFDS711_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS;\n  }\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_freelist/lfds711_freelist_cleanup.c",
    "content": "/***** includes *****/\n#include \"lfds711_freelist_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_freelist_cleanup( struct lfds711_freelist_state *fs,\n                               void (*element_cleanup_callback)(struct lfds711_freelist_state *fs, struct lfds711_freelist_element *fe) )\n{\n  struct lfds711_freelist_element\n    *fe,\n    *fe_temp;\n\n  LFDS711_PAL_ASSERT( fs != NULL );\n  // TRD : element_cleanup_callback can be NULL\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  if( element_cleanup_callback != NULL )\n  {\n    fe = fs->top[POINTER];\n\n    while( fe != NULL )\n    {\n      fe_temp = fe;\n      fe = fe->next;\n\n      element_cleanup_callback( fs, fe_temp );\n    }\n  }\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_freelist/lfds711_freelist_init.c",
    "content": "/***** includes *****/\n#include \"lfds711_freelist_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_freelist_init_valid_on_current_logical_core( struct lfds711_freelist_state *fs,\n                                                          struct lfds711_freelist_element * volatile (*elimination_array)[LFDS711_FREELIST_ELIMINATION_ARRAY_ELEMENT_SIZE_IN_FREELIST_ELEMENTS],\n                                                          lfds711_pal_uint_t elimination_array_size_in_elements,\n                                                          void *user_state )\n{\n  lfds711_pal_uint_t\n    loop,\n    subloop;\n\n  LFDS711_PAL_ASSERT( fs != NULL );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) fs->top % LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &fs->elimination_array_size_in_elements % LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 );\n  // TRD : elimination_array can be NULL\n  LFDS711_PAL_ASSERT( (elimination_array == NULL) or \n                      ( (elimination_array != NULL) and (lfds711_pal_uint_t) elimination_array % LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 ) );\n  LFDS711_PAL_ASSERT( (elimination_array == NULL and elimination_array_size_in_elements == 0) or \n                      (elimination_array != NULL and elimination_array_size_in_elements >= 2 and (elimination_array_size_in_elements & (elimination_array_size_in_elements-1)) == 0) );\n  // TRD : user_state can be NULL\n\n  fs->top[POINTER] = NULL;\n  fs->top[COUNTER] = 0;\n\n  fs->elimination_array = elimination_array;\n  fs->elimination_array_size_in_elements = elimination_array_size_in_elements;\n  fs->user_state = user_state;\n\n  for( loop = 0 ; loop < elimination_array_size_in_elements ; loop++ )\n    for( subloop = 0 ; subloop < LFDS711_FREELIST_ELIMINATION_ARRAY_ELEMENT_SIZE_IN_FREELIST_ELEMENTS ; subloop++ )\n      fs->elimination_array[loop][subloop] = NULL;\n\n  lfds711_misc_internal_backoff_init( &fs->pop_backoff );\n  lfds711_misc_internal_backoff_init( &fs->push_backoff );\n\n  LFDS711_MISC_BARRIER_STORE;\n\n  lfds711_misc_force_store();\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_freelist/lfds711_freelist_internal.h",
    "content": "/***** the library wide include file *****/\n#include \"../liblfds711_internal.h\"\n\n/***** private prototypes *****/\nvoid lfds711_freelist_internal_push_without_ea( struct lfds711_freelist_state *fs,\n                                                struct lfds711_freelist_element *fe );\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_freelist/lfds711_freelist_pop.c",
    "content": "/***** includes *****/\n#include \"lfds711_freelist_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nint lfds711_freelist_pop( struct lfds711_freelist_state *fs,\n                          struct lfds711_freelist_element **fe,\n                          struct lfds711_prng_st_state *psts )\n{\n  char unsigned\n    result;\n\n  lfds711_pal_uint_t\n    backoff_iteration = LFDS711_BACKOFF_INITIAL_VALUE,\n    elimination_array_index,\n    loop,\n    random_value;\n\n  struct lfds711_freelist_element LFDS711_PAL_ALIGN(LFDS711_PAL_ALIGN_DOUBLE_POINTER)\n    *new_top[PAC_SIZE],\n    *volatile original_top[PAC_SIZE];\n\n  LFDS711_PAL_ASSERT( fs != NULL );\n  LFDS711_PAL_ASSERT( fe != NULL );\n  // TRD : psts can be NULL\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  if( fs->elimination_array_size_in_elements > 0 )\n  {\n    if( psts != NULL )\n    {\n      LFDS711_PRNG_ST_GENERATE( *psts, random_value );\n      elimination_array_index = ( random_value & (fs->elimination_array_size_in_elements-1) );\n    }\n    else\n    {\n      elimination_array_index = (lfds711_pal_uint_t) fe;\n      LFDS711_PRNG_ST_MIXING_FUNCTION( elimination_array_index );\n      elimination_array_index = ( elimination_array_index & (fs->elimination_array_size_in_elements-1) );\n    }\n\n    // TRD : full scan of one cache line, max pointers per cache line\n\n    *fe = NULL;\n\n    for( loop = 0 ; loop < LFDS711_FREELIST_ELIMINATION_ARRAY_ELEMENT_SIZE_IN_FREELIST_ELEMENTS ; loop++ )\n      if( fs->elimination_array[elimination_array_index][loop] != NULL )\n      {\n        LFDS711_PAL_ATOMIC_EXCHANGE( &fs->elimination_array[elimination_array_index][loop], *fe, struct lfds711_freelist_element * );\n        if( *fe != NULL )\n          return 1;\n      }\n  }\n\n  original_top[COUNTER] = fs->top[COUNTER];\n  original_top[POINTER] = fs->top[POINTER];\n\n  do\n  {\n    if( original_top[POINTER] == NULL )\n    {\n      *fe = NULL;\n      return 0;\n    }\n\n    new_top[COUNTER] = original_top[COUNTER] + 1;\n    new_top[POINTER] = original_top[POINTER]->next;\n\n    LFDS711_PAL_ATOMIC_DWCAS( fs->top, original_top, new_top, LFDS711_MISC_CAS_STRENGTH_WEAK, result );\n\n    if( result == 0 )\n    {\n      LFDS711_BACKOFF_EXPONENTIAL_BACKOFF( fs->pop_backoff, backoff_iteration );\n      LFDS711_MISC_BARRIER_LOAD;\n    }\n  }\n  while( result == 0 );\n\n  *fe = original_top[POINTER];\n\n  LFDS711_BACKOFF_AUTOTUNE( fs->pop_backoff, backoff_iteration );\n\n  return 1;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_freelist/lfds711_freelist_push.c",
    "content": "/***** includes *****/\n#include \"lfds711_freelist_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_freelist_push( struct lfds711_freelist_state *fs,\n                            struct lfds711_freelist_element *fe,\n                            struct lfds711_prng_st_state *psts )\n{\n  char unsigned\n    result;\n\n  lfds711_pal_uint_t\n    backoff_iteration = LFDS711_BACKOFF_INITIAL_VALUE,\n    elimination_array_index,\n    loop,\n    random_value;\n\n  struct lfds711_freelist_element LFDS711_PAL_ALIGN(LFDS711_PAL_ALIGN_DOUBLE_POINTER)\n    *new_top[PAC_SIZE],\n    *volatile original_top[PAC_SIZE];\n\n  LFDS711_PAL_ASSERT( fs != NULL );\n  LFDS711_PAL_ASSERT( fe != NULL );\n  // TRD : psts can be NULL\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  if( fs->elimination_array_size_in_elements > 0 )\n  {\n    if( psts != NULL )\n    {\n      LFDS711_PRNG_ST_GENERATE( *psts, random_value );\n      elimination_array_index = ( random_value & (fs->elimination_array_size_in_elements-1) );\n    }\n    else\n    {\n      elimination_array_index = (lfds711_pal_uint_t) fe;\n      LFDS711_PRNG_ST_MIXING_FUNCTION( elimination_array_index );\n      elimination_array_index = ( elimination_array_index & (fs->elimination_array_size_in_elements-1) );\n    }\n\n    // TRD : full scan of one cache line, max pointers per cache line\n\n    for( loop = 0 ; loop < LFDS711_FREELIST_ELIMINATION_ARRAY_ELEMENT_SIZE_IN_FREELIST_ELEMENTS ; loop++ )\n      if( fs->elimination_array[elimination_array_index][loop] == NULL )\n      {\n        LFDS711_PAL_ATOMIC_EXCHANGE( &fs->elimination_array[elimination_array_index][loop], fe, struct lfds711_freelist_element * );\n        if( fe == NULL )\n          return;\n      }\n  }\n\n  new_top[POINTER] = fe;\n\n  original_top[COUNTER] = fs->top[COUNTER];\n  original_top[POINTER] = fs->top[POINTER];\n\n  do\n  {\n    fe->next = original_top[POINTER];\n    LFDS711_MISC_BARRIER_STORE;\n\n    new_top[COUNTER] = original_top[COUNTER] + 1;\n    LFDS711_PAL_ATOMIC_DWCAS( fs->top, original_top, new_top, LFDS711_MISC_CAS_STRENGTH_WEAK, result );\n\n    if( result == 0 )\n      LFDS711_BACKOFF_EXPONENTIAL_BACKOFF( fs->push_backoff, backoff_iteration );\n  }\n  while( result == 0 );\n\n  LFDS711_BACKOFF_AUTOTUNE( fs->push_backoff, backoff_iteration );\n\n  return;\n}\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_freelist_internal_push_without_ea( struct lfds711_freelist_state *fs,\n                                                struct lfds711_freelist_element *fe )\n{\n  char unsigned\n    result;\n\n  lfds711_pal_uint_t\n    backoff_iteration = LFDS711_BACKOFF_INITIAL_VALUE;\n\n  struct lfds711_freelist_element LFDS711_PAL_ALIGN(LFDS711_PAL_ALIGN_DOUBLE_POINTER)\n    *new_top[PAC_SIZE],\n    *volatile original_top[PAC_SIZE];\n\n  LFDS711_PAL_ASSERT( fs != NULL );\n  LFDS711_PAL_ASSERT( fe != NULL );\n\n  new_top[POINTER] = fe;\n\n  original_top[COUNTER] = fs->top[COUNTER];\n  original_top[POINTER] = fs->top[POINTER];\n\n  do\n  {\n    fe->next = original_top[POINTER];\n    LFDS711_MISC_BARRIER_STORE;\n\n    new_top[COUNTER] = original_top[COUNTER] + 1;\n    LFDS711_PAL_ATOMIC_DWCAS( fs->top, original_top, new_top, LFDS711_MISC_CAS_STRENGTH_WEAK, result );\n\n    if( result == 0 )\n      LFDS711_BACKOFF_EXPONENTIAL_BACKOFF( fs->push_backoff, backoff_iteration );\n  }\n  while( result == 0 );\n\n  LFDS711_BACKOFF_AUTOTUNE( fs->push_backoff, backoff_iteration );\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_freelist/lfds711_freelist_query.c",
    "content": "/***** includes *****/\n#include \"lfds711_freelist_internal.h\"\n\n/***** private prototypes *****/\nstatic void lfds711_freelist_internal_freelist_validate( struct lfds711_freelist_state *fs,\n                                                         struct lfds711_misc_validation_info *vi,\n                                                         enum lfds711_misc_validity *lfds711_freelist_validity );\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_freelist_query( struct lfds711_freelist_state *fs,\n                             enum lfds711_freelist_query query_type,\n                             void *query_input,\n                             void *query_output )\n{\n  struct lfds711_freelist_element\n    *fe;\n\n  LFDS711_PAL_ASSERT( fs != NULL );\n  // TRD : query_type can be any value in its range\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  switch( query_type )\n  {\n    case LFDS711_FREELIST_QUERY_SINGLETHREADED_GET_COUNT:\n    {\n      lfds711_pal_uint_t\n        loop,\n        subloop;\n\n      LFDS711_PAL_ASSERT( query_input == NULL );\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      *(lfds711_pal_uint_t *) query_output = 0;\n\n      // TRD : count the elements in the elimination array\n      for( loop = 0 ; loop < fs->elimination_array_size_in_elements ; loop++ )\n        for( subloop = 0 ; subloop < LFDS711_FREELIST_ELIMINATION_ARRAY_ELEMENT_SIZE_IN_FREELIST_ELEMENTS ; subloop++ )\n          if( fs->elimination_array[loop][subloop] != NULL )\n            ( *(lfds711_pal_uint_t *) query_output )++;\n\n      // TRD : count the elements on the freelist\n      fe = (struct lfds711_freelist_element *) fs->top[POINTER];\n\n      while( fe != NULL )\n      {\n        ( *(lfds711_pal_uint_t *) query_output )++;\n        fe = (struct lfds711_freelist_element *) fe->next;\n      }\n    }\n    break;\n\n    case LFDS711_FREELIST_QUERY_SINGLETHREADED_VALIDATE:\n      // TRD : query_input can be NULL\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      lfds711_freelist_internal_freelist_validate( fs, (struct lfds711_misc_validation_info *) query_input, (enum lfds711_misc_validity *) query_output );\n    break;\n\n    case LFDS711_FREELIST_QUERY_GET_ELIMINATION_ARRAY_EXTRA_ELEMENTS_IN_FREELIST_ELEMENTS:\n    {\n      LFDS711_PAL_ASSERT( query_input == NULL );\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      ( *(lfds711_pal_uint_t *) query_output ) = (fs->elimination_array_size_in_elements-1) * LFDS711_FREELIST_ELIMINATION_ARRAY_ELEMENT_SIZE_IN_FREELIST_ELEMENTS;\n    }\n    break;\n  }\n\n  return;\n}\n\n\n\n\n\n/****************************************************************************/\nstatic void lfds711_freelist_internal_freelist_validate( struct lfds711_freelist_state *fs,\n                                                         struct lfds711_misc_validation_info *vi,\n                                                         enum lfds711_misc_validity *lfds711_freelist_validity )\n{\n  lfds711_pal_uint_t\n    number_elements = 0;\n\n  struct lfds711_freelist_element\n    *fe_slow,\n    *fe_fast;\n\n  LFDS711_PAL_ASSERT( fs != NULL );\n  // TRD : vi can be NULL\n  LFDS711_PAL_ASSERT( lfds711_freelist_validity != NULL );\n\n  *lfds711_freelist_validity = LFDS711_MISC_VALIDITY_VALID;\n\n  fe_slow = fe_fast = (struct lfds711_freelist_element *) fs->top[POINTER];\n\n  /* TRD : first, check for a loop\n           we have two pointers\n           both of which start at the top of the freelist\n           we enter a loop\n           and on each iteration\n           we advance one pointer by one element\n           and the other by two\n\n           we exit the loop when both pointers are NULL\n           (have reached the end of the freelist)\n\n           or\n\n           if we fast pointer 'sees' the slow pointer\n           which means we have a loop\n  */\n\n  if( fe_slow != NULL )\n    do\n    {\n      fe_slow = fe_slow->next;\n\n      if( fe_fast != NULL )\n        fe_fast = fe_fast->next;\n\n      if( fe_fast != NULL )\n        fe_fast = fe_fast->next;\n    }\n    while( fe_slow != NULL and fe_fast != fe_slow );\n\n  if( fe_fast != NULL and fe_slow != NULL and fe_fast == fe_slow )\n    *lfds711_freelist_validity = LFDS711_MISC_VALIDITY_INVALID_LOOP;\n\n  /* TRD : now check for expected number of elements\n           vi can be NULL, in which case we do not check\n           we know we don't have a loop from our earlier check\n  */\n\n  if( *lfds711_freelist_validity == LFDS711_MISC_VALIDITY_VALID and vi != NULL )\n  {\n    lfds711_freelist_query( fs, LFDS711_FREELIST_QUERY_SINGLETHREADED_GET_COUNT, NULL, (void *) &number_elements );\n\n    if( number_elements < vi->min_elements )\n      *lfds711_freelist_validity = LFDS711_MISC_VALIDITY_INVALID_MISSING_ELEMENTS;\n\n    if( number_elements > vi->max_elements )\n      *lfds711_freelist_validity = LFDS711_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS;\n  }\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_hash_addonly/lfds711_hash_addonly_cleanup.c",
    "content": "/***** includes *****/\n#include \"lfds711_hash_addonly_internal.h\"\n\n/***** private prototypes*****/\nstatic void btree_au_element_cleanup_function( struct lfds711_btree_au_state *baus,\n                                               struct lfds711_btree_au_element *baue );\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_hash_a_cleanup( struct lfds711_hash_a_state *has,\n                             void (*element_cleanup_callback)(struct lfds711_hash_a_state *has, struct lfds711_hash_a_element *hae) )\n{\n  lfds711_pal_uint_t\n    loop;\n\n  LFDS711_PAL_ASSERT( has != NULL );\n  // TRD : element_cleanup_callback can be NULL\n\n  if( element_cleanup_callback == NULL )\n    return;\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  has->element_cleanup_callback = element_cleanup_callback;\n\n  for( loop = 0 ; loop < has->array_size ; loop++ )\n    lfds711_btree_au_cleanup( has->baus_array+loop, btree_au_element_cleanup_function );\n\n  return;\n}\n\n\n\n\n\n/****************************************************************************/\n#pragma warning( disable : 4100 )\n\nstatic void btree_au_element_cleanup_function( struct lfds711_btree_au_state *baus,\n                                               struct lfds711_btree_au_element *baue )\n{\n  struct lfds711_hash_a_state\n    *has;\n\n  struct lfds711_hash_a_element\n    *hae;\n\n  LFDS711_PAL_ASSERT( baus != NULL );\n  LFDS711_PAL_ASSERT( baue != NULL );\n\n  hae = (struct lfds711_hash_a_element *) LFDS711_BTREE_AU_GET_VALUE_FROM_ELEMENT( *baue );\n  has = (struct lfds711_hash_a_state *) LFDS711_BTREE_AU_GET_USER_STATE_FROM_STATE( *baus );\n\n  has->element_cleanup_callback( has, hae );\n\n  return;\n}\n\n#pragma warning( default : 4100 )\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_hash_addonly/lfds711_hash_addonly_get.c",
    "content": "/***** includes *****/\n#include \"lfds711_hash_addonly_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nint lfds711_hash_a_get_by_key( struct lfds711_hash_a_state *has,\n                               int (*key_compare_function)(void const *new_key, void const *existing_key),\n                               void (*key_hash_function)(void const *key, lfds711_pal_uint_t *hash),\n                               void *key,\n                               struct lfds711_hash_a_element **hae )\n{\n  int\n    rv;\n\n  lfds711_pal_uint_t\n    hash = 0;\n\n  struct lfds711_btree_au_element\n    *baue;\n\n  LFDS711_PAL_ASSERT( has != NULL );\n  // TRD : key_compare_function can be NULL\n  // TRD : key_hash_function can be NULL\n  // TRD : key can be NULL\n  LFDS711_PAL_ASSERT( hae != NULL );\n\n  if( key_compare_function == NULL )\n    key_compare_function = has->key_compare_function;\n\n  if( key_hash_function == NULL )\n    key_hash_function = has->key_hash_function;\n\n  key_hash_function( key, &hash );\n\n  rv = lfds711_btree_au_get_by_key( has->baus_array + (hash % has->array_size), key_compare_function, key, &baue );\n\n  if( rv == 1 )\n    *hae = LFDS711_BTREE_AU_GET_VALUE_FROM_ELEMENT( *baue );\n  else\n    *hae = NULL;\n\n  return rv;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_hash_addonly/lfds711_hash_addonly_init.c",
    "content": "/***** includes *****/\n#include \"lfds711_hash_addonly_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_hash_a_init_valid_on_current_logical_core( struct lfds711_hash_a_state *has,\n                                                        struct lfds711_btree_au_state *baus_array,\n                                                        lfds711_pal_uint_t array_size,\n                                                        int (*key_compare_function)(void const *new_key, void const *existing_key),\n                                                        void (*key_hash_function)(void const *key, lfds711_pal_uint_t *hash),\n                                                        enum lfds711_hash_a_existing_key existing_key,\n                                                        void *user_state )\n{\n  enum lfds711_btree_au_existing_key\n    btree_au_existing_key = LFDS711_BTREE_AU_EXISTING_KEY_OVERWRITE; // TRD : for compiler warning\n\n  lfds711_pal_uint_t\n    loop;\n\n  LFDS711_PAL_ASSERT( has != NULL );\n  LFDS711_PAL_ASSERT( baus_array != NULL );\n  LFDS711_PAL_ASSERT( array_size > 0 );\n  LFDS711_PAL_ASSERT( key_compare_function != NULL );\n  LFDS711_PAL_ASSERT( key_hash_function != NULL );\n  // TRD : existing_key can be any value in its range\n  // TRD : user_state can be NULL\n\n  has->array_size = array_size;\n  has->key_compare_function = key_compare_function;\n  has->key_hash_function = key_hash_function;\n  has->existing_key = existing_key;\n  has->baus_array = baus_array;\n  has->user_state = user_state;\n\n  if( has->existing_key == LFDS711_HASH_A_EXISTING_KEY_OVERWRITE )\n    btree_au_existing_key = LFDS711_BTREE_AU_EXISTING_KEY_OVERWRITE;\n\n  if( has->existing_key == LFDS711_HASH_A_EXISTING_KEY_FAIL )\n    btree_au_existing_key = LFDS711_BTREE_AU_EXISTING_KEY_FAIL;\n\n  // TRD : since the addonly_hash atomic counts, if that flag is set, the btree_addonly_unbalanceds don't have to\n  for( loop = 0 ; loop < array_size ; loop++ )\n    lfds711_btree_au_init_valid_on_current_logical_core( has->baus_array+loop, key_compare_function, btree_au_existing_key, user_state );\n\n  LFDS711_MISC_BARRIER_STORE;\n\n  lfds711_misc_force_store();\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_hash_addonly/lfds711_hash_addonly_insert.c",
    "content": "/***** includes *****/\n#include \"lfds711_hash_addonly_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nenum lfds711_hash_a_insert_result lfds711_hash_a_insert( struct lfds711_hash_a_state *has,\n                                                         struct lfds711_hash_a_element *hae,\n                                                         struct lfds711_hash_a_element **existing_hae )\n{\n  enum lfds711_hash_a_insert_result\n    apr = LFDS711_HASH_A_PUT_RESULT_SUCCESS;\n\n  enum lfds711_btree_au_insert_result\n    alr;\n\n  lfds711_pal_uint_t\n    hash = 0;\n\n  struct lfds711_btree_au_element\n    *existing_baue;\n\n  LFDS711_PAL_ASSERT( has != NULL );\n  LFDS711_PAL_ASSERT( hae != NULL );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &hae->value % LFDS711_PAL_ALIGN_SINGLE_POINTER == 0 );\n  // TRD : existing_hae can be NULL\n\n  // TRD : alignment checks\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &hae->baue % LFDS711_PAL_ALIGN_SINGLE_POINTER == 0 );\n\n  has->key_hash_function( hae->key, &hash );\n\n  LFDS711_BTREE_AU_SET_KEY_IN_ELEMENT( hae->baue, hae->key );\n  LFDS711_BTREE_AU_SET_VALUE_IN_ELEMENT( hae->baue, hae );\n\n  alr = lfds711_btree_au_insert( has->baus_array + (hash % has->array_size), &hae->baue, &existing_baue );\n\n  switch( alr )\n  {\n    case LFDS711_BTREE_AU_INSERT_RESULT_FAILURE_EXISTING_KEY:\n      if( existing_hae != NULL )\n        *existing_hae = LFDS711_BTREE_AU_GET_VALUE_FROM_ELEMENT( *existing_baue );\n\n      apr = LFDS711_HASH_A_PUT_RESULT_FAILURE_EXISTING_KEY;\n    break;\n\n    case LFDS711_BTREE_AU_INSERT_RESULT_SUCCESS_OVERWRITE:\n      apr = LFDS711_HASH_A_PUT_RESULT_SUCCESS_OVERWRITE;\n    break;\n\n    case LFDS711_BTREE_AU_INSERT_RESULT_SUCCESS:\n      apr = LFDS711_HASH_A_PUT_RESULT_SUCCESS;\n    break;\n  }\n\n  return apr;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_hash_addonly/lfds711_hash_addonly_internal.h",
    "content": "/***** the library wide include file *****/\n#include \"../liblfds711_internal.h\"\n\n/***** private prototypes *****/\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_hash_addonly/lfds711_hash_addonly_iterate.c",
    "content": "/***** includes *****/\n#include \"lfds711_hash_addonly_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_hash_a_iterate_init( struct lfds711_hash_a_state *has,\n                                  struct lfds711_hash_a_iterate *hai )\n{\n  LFDS711_PAL_ASSERT( has != NULL );\n  LFDS711_PAL_ASSERT( hai != NULL );\n\n  hai->baus = has->baus_array;\n  hai->baus_end = has->baus_array + has->array_size;\n  hai->baue = NULL;\n\n  return;\n}\n\n\n\n\n\n/****************************************************************************/\nint lfds711_hash_a_iterate( struct lfds711_hash_a_iterate *hai,\n                            struct lfds711_hash_a_element **hae )\n{\n  enum lfds711_misc_flag\n    finished_flag = LFDS711_MISC_FLAG_LOWERED;\n\n  int\n    rv = 0;\n\n  LFDS711_PAL_ASSERT( hai != NULL );\n  LFDS711_PAL_ASSERT( hae != NULL );\n\n  while( finished_flag == LFDS711_MISC_FLAG_LOWERED )\n  {\n    lfds711_btree_au_get_by_absolute_position_and_then_by_relative_position( hai->baus, &hai->baue, LFDS711_BTREE_AU_ABSOLUTE_POSITION_SMALLEST_IN_TREE, LFDS711_BTREE_AU_RELATIVE_POSITION_NEXT_LARGER_ELEMENT_IN_ENTIRE_TREE );\n\n    if( hai->baue != NULL )\n    {\n      *hae = LFDS711_BTREE_AU_GET_VALUE_FROM_ELEMENT( *hai->baue );\n      finished_flag = LFDS711_MISC_FLAG_RAISED;\n      rv = 1;\n    }\n\n    if( hai->baue == NULL )\n      if( ++hai->baus == hai->baus_end )\n      {\n        *hae = NULL;\n        finished_flag = LFDS711_MISC_FLAG_RAISED;\n      }\n  }\n\n  return rv;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_hash_addonly/lfds711_hash_addonly_query.c",
    "content": "/***** includes *****/\n#include \"lfds711_hash_addonly_internal.h\"\n\n/***** private prototypes *****/\nstatic void lfds711_hash_a_internal_validate( struct lfds711_hash_a_state *has,\n                                              struct lfds711_misc_validation_info *vi,\n                                              enum lfds711_misc_validity *lfds711_hash_a_validity );\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_hash_a_query( struct lfds711_hash_a_state *has,\n                           enum lfds711_hash_a_query query_type,\n                           void *query_input,\n                           void *query_output )\n{\n  LFDS711_PAL_ASSERT( has != NULL );\n  // TRD : query_type can be any value in its range\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  switch( query_type )\n  {\n    case LFDS711_HASH_A_QUERY_GET_POTENTIALLY_INACCURATE_COUNT:\n    {\n      struct lfds711_hash_a_iterate\n        ai;\n\n      struct lfds711_hash_a_element\n        *hae;\n\n      LFDS711_PAL_ASSERT( query_input == NULL );\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      *(lfds711_pal_uint_t *) query_output = 0;\n\n      lfds711_hash_a_iterate_init( has, &ai );\n\n      while( lfds711_hash_a_iterate(&ai, &hae) )\n        ( *(lfds711_pal_uint_t *) query_output )++;\n    }\n    break;\n\n    case LFDS711_HASH_A_QUERY_SINGLETHREADED_VALIDATE:\n      // TRD: query_input can be any value in its range\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      lfds711_hash_a_internal_validate( has, (struct lfds711_misc_validation_info *) query_input, (enum lfds711_misc_validity *) query_output );\n    break;\n  }\n\n  return;\n}\n\n\n\n\n\n/****************************************************************************/\nstatic void lfds711_hash_a_internal_validate( struct lfds711_hash_a_state *has,\n                                              struct lfds711_misc_validation_info *vi,\n                                              enum lfds711_misc_validity *lfds711_hash_a_validity )\n{\n  lfds711_pal_uint_t\n    lfds711_hash_a_total_number_elements = 0,\n    lfds711_btree_au_total_number_elements = 0,\n    number_elements;\n\n  lfds711_pal_uint_t\n    loop;\n\n  LFDS711_PAL_ASSERT( has!= NULL );\n  // TRD : vi can be NULL\n  LFDS711_PAL_ASSERT( lfds711_hash_a_validity != NULL );\n\n  /* TRD : validate every btree_addonly_unbalanced in the addonly_hash\n           sum elements in each btree_addonly_unbalanced\n           check matches expected element counts (if vi is provided)\n  */\n\n  *lfds711_hash_a_validity = LFDS711_MISC_VALIDITY_VALID;\n\n  for( loop = 0 ; *lfds711_hash_a_validity == LFDS711_MISC_VALIDITY_VALID and loop < has->array_size ; loop++ )\n    lfds711_btree_au_query( has->baus_array+loop, LFDS711_BTREE_AU_QUERY_SINGLETHREADED_VALIDATE, NULL, (void *) lfds711_hash_a_validity );\n\n  if( *lfds711_hash_a_validity == LFDS711_MISC_VALIDITY_VALID )\n  {\n    for( loop = 0 ; loop < has->array_size ; loop++ )\n    {\n      lfds711_btree_au_query( has->baus_array+loop, LFDS711_BTREE_AU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void *) &number_elements );\n      lfds711_btree_au_total_number_elements += number_elements;\n    }\n\n    // TRD : first, check btree_addonly_unbalanced total vs the addonly_hash total\n    lfds711_hash_a_query( has, LFDS711_HASH_A_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, &lfds711_hash_a_total_number_elements );\n\n    // TRD : the btree_addonly_unbalanceds are assumed to speak the truth\n    if( lfds711_hash_a_total_number_elements < lfds711_btree_au_total_number_elements )\n      *lfds711_hash_a_validity = LFDS711_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS;\n\n    if( lfds711_hash_a_total_number_elements > lfds711_btree_au_total_number_elements )\n      *lfds711_hash_a_validity = LFDS711_MISC_VALIDITY_INVALID_MISSING_ELEMENTS;\n\n    // TRD : second, if we're still valid and vi is provided, check the btree_addonly_unbalanced total against vi\n    if( *lfds711_hash_a_validity == LFDS711_MISC_VALIDITY_VALID and vi != NULL )\n    {\n      if( lfds711_btree_au_total_number_elements < vi->min_elements )\n        *lfds711_hash_a_validity = LFDS711_MISC_VALIDITY_INVALID_MISSING_ELEMENTS;\n\n      if( lfds711_btree_au_total_number_elements > vi->max_elements )\n        *lfds711_hash_a_validity = LFDS711_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS;\n    }\n  }\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_list_addonly_singlylinked_ordered/lfds711_list_addonly_singlylinked_ordered_cleanup.c",
    "content": "/***** includes *****/\n#include \"lfds711_list_addonly_singlylinked_ordered_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_list_aso_cleanup( struct lfds711_list_aso_state *lasos,\n                               void (*element_cleanup_callback)(struct lfds711_list_aso_state *lasos, struct lfds711_list_aso_element *lasoe) )\n{\n  struct lfds711_list_aso_element\n    *lasoe,\n    *temp;\n\n  LFDS711_PAL_ASSERT( lasos != NULL );\n  // TRD : element_cleanup_callback can be NULL\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  if( element_cleanup_callback == NULL )\n    return;\n\n  lasoe = LFDS711_LIST_ASO_GET_START( *lasos );\n\n  while( lasoe != NULL )\n  {\n    temp = lasoe;\n\n    lasoe = LFDS711_LIST_ASO_GET_NEXT( *lasoe );\n\n    element_cleanup_callback( lasos, temp );\n  }\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_list_addonly_singlylinked_ordered/lfds711_list_addonly_singlylinked_ordered_get.c",
    "content": "/***** includes *****/\n#include \"lfds711_list_addonly_singlylinked_ordered_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nint lfds711_list_aso_get_by_key( struct lfds711_list_aso_state *lasos,\n                                 void *key,\n                                 struct lfds711_list_aso_element **lasoe )\n{\n  int\n    cr = !0,\n    rv = 1;\n\n  LFDS711_PAL_ASSERT( lasos != NULL );\n  // TRD : key can be NULL\n  LFDS711_PAL_ASSERT( lasoe != NULL );\n\n  while( cr != 0 and LFDS711_LIST_ASO_GET_START_AND_THEN_NEXT(*lasos, *lasoe) )\n    cr = lasos->key_compare_function( key, (*lasoe)->key );\n\n  if( *lasoe == NULL )\n    rv = 0;\n\n  return rv;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_list_addonly_singlylinked_ordered/lfds711_list_addonly_singlylinked_ordered_init.c",
    "content": "/***** includes *****/\n#include \"lfds711_list_addonly_singlylinked_ordered_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_list_aso_init_valid_on_current_logical_core( struct lfds711_list_aso_state *lasos,\n                                                          int (*key_compare_function)(void const *new_key, void const *existing_key),\n                                                          enum lfds711_list_aso_existing_key existing_key,\n                                                          void *user_state )\n{\n  LFDS711_PAL_ASSERT( lasos != NULL );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &lasos->dummy_element % LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &lasos->start % LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 );\n  LFDS711_PAL_ASSERT( key_compare_function != NULL );\n  // TRD : existing_key can be any value in its range\n  // TRD : user_state can be NULL\n\n  // TRD : dummy start element - makes code easier when you can always use ->next\n  lasos->start = &lasos->dummy_element;\n\n  lasos->start->next = NULL;\n  lasos->start->value = NULL;\n  lasos->key_compare_function = key_compare_function;\n  lasos->existing_key = existing_key;\n  lasos->user_state = user_state;\n\n  lfds711_misc_internal_backoff_init( &lasos->insert_backoff );\n\n  LFDS711_MISC_BARRIER_STORE;\n\n  lfds711_misc_force_store();\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_list_addonly_singlylinked_ordered/lfds711_list_addonly_singlylinked_ordered_insert.c",
    "content": "/***** includes *****/\n#include \"lfds711_list_addonly_singlylinked_ordered_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nenum lfds711_list_aso_insert_result lfds711_list_aso_insert( struct lfds711_list_aso_state *lasos,\n                                                             struct lfds711_list_aso_element *lasoe,\n                                                             struct lfds711_list_aso_element **existing_lasoe )\n{\n  char unsigned \n    result;\n\n  enum lfds711_misc_flag\n    finished_flag = LFDS711_MISC_FLAG_LOWERED;\n\n  int\n    compare_result = 0;\n\n  lfds711_pal_uint_t\n    backoff_iteration = LFDS711_BACKOFF_INITIAL_VALUE;\n\n  struct lfds711_list_aso_element\n    *volatile lasoe_temp = NULL,\n    *volatile lasoe_trailing;\n\n  LFDS711_PAL_ASSERT( lasos != NULL );\n  LFDS711_PAL_ASSERT( lasoe != NULL );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &lasoe->next % LFDS711_PAL_ALIGN_SINGLE_POINTER == 0 );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &lasoe->value % LFDS711_PAL_ALIGN_SINGLE_POINTER == 0 );\n  // TRD : existing_lasoe can be NULL\n\n  /* TRD : imagine a list, sorted small to large\n\n           we arrive at an element\n           we obtain its next pointer\n           we check we are greater than the current element and smaller than the next element\n           this means we have found the correct location to insert\n           we try to CAS ourselves in; in the meantime,\n           someone else has *aready* swapped in an element which is smaller than we are\n\n           e.g.\n\n           the list is { 1, 10 } and we are the value 5\n\n           we arrive at 1; we check the next element and see it is 10\n           so we are larger than the current element and smaller than the next\n           we are in the correct location to insert and we go to insert...\n\n           in the meantime, someone else with the value 3 comes along\n           he too finds this is the correct location and inserts before we do\n           the list is now { 1, 3, 10 } and we are trying to insert now after\n           1 and before 3!\n\n           our insert CAS fails, because the next pointer of 1 has changed aready;\n           but we see we are in the wrong location - we need to move forward an\n           element\n  */\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  /* TRD : we need to begin with the leading dummy element\n           as the element to be inserted\n           may be smaller than all elements in the list\n  */\n\n  lasoe_trailing = lasos->start;\n  lasoe_temp = lasos->start->next;\n\n  while( finished_flag == LFDS711_MISC_FLAG_LOWERED )\n  {\n    if( lasoe_temp == NULL )\n      compare_result = -1;\n\n    if( lasoe_temp != NULL )\n    {\n      LFDS711_MISC_BARRIER_LOAD;\n      compare_result = lasos->key_compare_function( lasoe->key, lasoe_temp->key );\n    }\n\n    if( compare_result == 0 )\n    {\n      if( existing_lasoe != NULL )\n        *existing_lasoe = lasoe_temp;\n\n      switch( lasos->existing_key )\n      {\n        case LFDS711_LIST_ASO_EXISTING_KEY_OVERWRITE:\n          LFDS711_LIST_ASO_SET_VALUE_IN_ELEMENT( *lasoe_temp, lasoe->value );\n          return LFDS711_LIST_ASO_INSERT_RESULT_SUCCESS_OVERWRITE;\n        break;\n\n        case LFDS711_LIST_ASO_EXISTING_KEY_FAIL:\n          return LFDS711_LIST_ASO_INSERT_RESULT_FAILURE_EXISTING_KEY;\n        break;\n      }\n\n      finished_flag = LFDS711_MISC_FLAG_RAISED;\n    }\n\n    if( compare_result < 0 )\n    {\n      lasoe->next = lasoe_temp;\n      LFDS711_MISC_BARRIER_STORE;\n      LFDS711_PAL_ATOMIC_CAS( &lasoe_trailing->next, (struct lfds711_list_aso_element **) &lasoe->next, lasoe, LFDS711_MISC_CAS_STRENGTH_WEAK, result );\n\n      if( result == 1 )\n        finished_flag = LFDS711_MISC_FLAG_RAISED;\n      else\n      {\n        LFDS711_BACKOFF_EXPONENTIAL_BACKOFF( lasos->insert_backoff, backoff_iteration );\n        // TRD : if we fail to link, someone else has linked and so we need to redetermine our position is correct\n        lasoe_temp = lasoe_trailing->next;\n      }\n    }\n\n    if( compare_result > 0 )\n    {\n      // TRD : move trailing along by one element\n      lasoe_trailing = lasoe_trailing->next;\n\n      /* TRD : set temp as the element after trailing\n               if the new element we're linking is larger than all elements in the list,\n               lasoe_temp will now go to NULL and we'll link at the end\n      */\n      lasoe_temp = lasoe_trailing->next;\n    }\n  }\n\n  LFDS711_BACKOFF_AUTOTUNE( lasos->insert_backoff, backoff_iteration );\n\n  return LFDS711_LIST_ASO_INSERT_RESULT_SUCCESS;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_list_addonly_singlylinked_ordered/lfds711_list_addonly_singlylinked_ordered_internal.h",
    "content": "/***** the library wide include file *****/\n#include \"../liblfds711_internal.h\"\n\n/***** private prototypes *****/\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_list_addonly_singlylinked_ordered/lfds711_list_addonly_singlylinked_ordered_query.c",
    "content": "/***** includes *****/\n#include \"lfds711_list_addonly_singlylinked_ordered_internal.h\"\n\n/***** private prototypes *****/\nstatic void lfds711_list_aso_internal_validate( struct lfds711_list_aso_state *lasos,\n                                                struct lfds711_misc_validation_info *vi,\n                                                enum lfds711_misc_validity *lfds711_list_aso_validity );\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_list_aso_query( struct lfds711_list_aso_state *lasos,\n                             enum lfds711_list_aso_query query_type,\n                             void *query_input,\n                             void *query_output )\n{\n  LFDS711_PAL_ASSERT( lasos != NULL );\n  // TRD : query_type can be any value in its range\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  switch( query_type )\n  {\n    case LFDS711_LIST_ASO_QUERY_GET_POTENTIALLY_INACCURATE_COUNT:\n    {\n      struct lfds711_list_aso_element\n        *lasoe = NULL;\n\n      LFDS711_PAL_ASSERT( query_input == NULL );\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      *(lfds711_pal_uint_t *) query_output = 0;\n\n      while( LFDS711_LIST_ASO_GET_START_AND_THEN_NEXT(*lasos, lasoe) )\n        ( *(lfds711_pal_uint_t *) query_output )++;\n    }\n    break;\n\n    case LFDS711_LIST_ASO_QUERY_SINGLETHREADED_VALIDATE:\n      // TRD : query_input can be NULL\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      lfds711_list_aso_internal_validate( lasos, (struct lfds711_misc_validation_info *) query_input, (enum lfds711_misc_validity *) query_output );\n    break;\n  }\n\n  return;\n}\n\n\n\n\n\n\n/****************************************************************************/\nstatic void lfds711_list_aso_internal_validate( struct lfds711_list_aso_state *lasos,\n                                                struct lfds711_misc_validation_info *vi,\n                                                enum lfds711_misc_validity *lfds711_list_aso_validity )\n{\n  lfds711_pal_uint_t\n    number_elements = 0;\n\n  struct lfds711_list_aso_element\n    *lasoe_fast,\n    *lasoe_slow;\n\n  LFDS711_PAL_ASSERT( lasos!= NULL );\n  // TRD : vi can be NULL\n  LFDS711_PAL_ASSERT( lfds711_list_aso_validity != NULL );\n\n  *lfds711_list_aso_validity = LFDS711_MISC_VALIDITY_VALID;\n\n  lasoe_slow = lasoe_fast = lasos->start->next;\n\n  /* TRD : first, check for a loop\n           we have two pointers\n           both of which start at the start of the list\n           we enter a loop\n           and on each iteration\n           we advance one pointer by one element\n           and the other by two\n\n           we exit the loop when both pointers are NULL\n           (have reached the end of the queue)\n\n           or\n\n           if we fast pointer 'sees' the slow pointer\n           which means we have a loop\n  */\n\n  if( lasoe_slow != NULL )\n    do\n    {\n      lasoe_slow = lasoe_slow->next;\n\n      if( lasoe_fast != NULL )\n        lasoe_fast = lasoe_fast->next;\n\n      if( lasoe_fast != NULL )\n        lasoe_fast = lasoe_fast->next;\n    }\n    while( lasoe_slow != NULL and lasoe_fast != lasoe_slow );\n\n  if( lasoe_fast != NULL and lasoe_slow != NULL and lasoe_fast == lasoe_slow )\n    *lfds711_list_aso_validity = LFDS711_MISC_VALIDITY_INVALID_LOOP;\n\n  /* TRD : now check for expected number of elements\n           vi can be NULL, in which case we do not check\n           we know we don't have a loop from our earlier check\n  */\n\n  if( *lfds711_list_aso_validity == LFDS711_MISC_VALIDITY_VALID and vi != NULL )\n  {\n    lfds711_list_aso_query( lasos, LFDS711_LIST_ASO_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, &number_elements );\n\n    if( number_elements < vi->min_elements )\n      *lfds711_list_aso_validity = LFDS711_MISC_VALIDITY_INVALID_MISSING_ELEMENTS;\n\n    if( number_elements > vi->max_elements )\n      *lfds711_list_aso_validity = LFDS711_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS;\n  }\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_list_addonly_singlylinked_unordered/lfds711_list_addonly_singlylinked_unordered_cleanup.c",
    "content": "/***** includes *****/\n#include \"lfds711_list_addonly_singlylinked_unordered_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_list_asu_cleanup( struct lfds711_list_asu_state *lasus,\n                               void (*element_cleanup_callback)(struct lfds711_list_asu_state *lasus, struct lfds711_list_asu_element *lasue) )\n{\n  struct lfds711_list_asu_element\n    *lasue,\n    *temp;\n\n  LFDS711_PAL_ASSERT( lasus != NULL );\n  // TRD : element_cleanup_callback can be NULL\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  if( element_cleanup_callback == NULL )\n    return;\n\n  lasue = LFDS711_LIST_ASU_GET_START( *lasus );\n\n  while( lasue != NULL )\n  {\n    temp = lasue;\n\n    lasue = LFDS711_LIST_ASU_GET_NEXT( *lasue );\n\n    element_cleanup_callback( lasus, temp );\n  }\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_list_addonly_singlylinked_unordered/lfds711_list_addonly_singlylinked_unordered_get.c",
    "content": "/***** includes *****/\n#include \"lfds711_list_addonly_singlylinked_unordered_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nint lfds711_list_asu_get_by_key( struct lfds711_list_asu_state *lasus,\n                                 int (*key_compare_function)(void const *new_key, void const *existing_key),\n                                 void *key, \n                                 struct lfds711_list_asu_element **lasue )\n{\n  int\n    cr = !0,\n    rv = 1;\n\n  LFDS711_PAL_ASSERT( lasus != NULL );\n  LFDS711_PAL_ASSERT( key_compare_function != NULL );\n  // TRD : key can be NULL\n  LFDS711_PAL_ASSERT( lasue != NULL );\n\n  *lasue = NULL;\n\n  while( cr != 0 and LFDS711_LIST_ASU_GET_START_AND_THEN_NEXT(*lasus, *lasue) )\n    cr = key_compare_function( key, (*lasue)->key );\n\n  if( *lasue == NULL )\n    rv = 0;\n\n  return rv;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_list_addonly_singlylinked_unordered/lfds711_list_addonly_singlylinked_unordered_init.c",
    "content": "/***** includes *****/\n#include \"lfds711_list_addonly_singlylinked_unordered_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_list_asu_init_valid_on_current_logical_core( struct lfds711_list_asu_state *lasus,\n                                                          void *user_state )\n{\n  LFDS711_PAL_ASSERT( lasus != NULL );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &lasus->dummy_element % LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &lasus->end % LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &lasus->start % LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 );\n  // TRD : user_state can be NULL\n\n  // TRD : dummy start element - makes code easier when you can always use ->next\n  lasus->start = lasus->end = &lasus->dummy_element;\n\n  lasus->start->next = NULL;\n  lasus->start->value = NULL;\n  lasus->user_state = user_state;\n\n  lfds711_misc_internal_backoff_init( &lasus->after_backoff );\n  lfds711_misc_internal_backoff_init( &lasus->start_backoff );\n  lfds711_misc_internal_backoff_init( &lasus->end_backoff );\n\n  LFDS711_MISC_BARRIER_STORE;\n\n  lfds711_misc_force_store();\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_list_addonly_singlylinked_unordered/lfds711_list_addonly_singlylinked_unordered_insert.c",
    "content": "/***** includes *****/\n#include \"lfds711_list_addonly_singlylinked_unordered_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_list_asu_insert_at_position( struct lfds711_list_asu_state *lasus,\n                                          struct lfds711_list_asu_element *lasue,\n                                          struct lfds711_list_asu_element *lasue_predecessor,\n                                          enum lfds711_list_asu_position position )\n{\n  LFDS711_PAL_ASSERT( lasus != NULL );\n  LFDS711_PAL_ASSERT( lasue != NULL );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &lasue->next % LFDS711_PAL_ALIGN_SINGLE_POINTER == 0 );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &lasue->value % LFDS711_PAL_ALIGN_SINGLE_POINTER == 0 );\n  // TRD : lasue_predecessor asserted in the switch\n  // TRD : position can be any value in its range\n\n  switch( position )\n  {\n    case LFDS711_LIST_ASU_POSITION_START:\n      lfds711_list_asu_insert_at_start( lasus, lasue );\n    break;\n\n    case LFDS711_LIST_ASU_POSITION_END:\n      lfds711_list_asu_insert_at_end( lasus, lasue );\n    break;\n\n    case LFDS711_LIST_ASU_POSITION_AFTER:\n      lfds711_list_asu_insert_after_element( lasus, lasue, lasue_predecessor );\n    break;\n  }\n\n  return;\n}\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_list_asu_insert_at_start( struct lfds711_list_asu_state *lasus,\n                                       struct lfds711_list_asu_element *lasue )\n{\n  char unsigned \n    result;\n\n  lfds711_pal_uint_t\n    backoff_iteration = LFDS711_BACKOFF_INITIAL_VALUE;\n\n  LFDS711_PAL_ASSERT( lasus != NULL );\n  LFDS711_PAL_ASSERT( lasue != NULL );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &lasue->next % LFDS711_PAL_ALIGN_SINGLE_POINTER == 0 );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &lasue->value % LFDS711_PAL_ALIGN_SINGLE_POINTER == 0 );\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  lasue->next = lasus->start->next;\n\n  do\n  {\n    LFDS711_MISC_BARRIER_STORE;\n    LFDS711_PAL_ATOMIC_CAS( &lasus->start->next, (struct lfds711_list_asu_element **) &lasue->next, lasue, LFDS711_MISC_CAS_STRENGTH_WEAK, result );\n    if( result == 0 )\n      LFDS711_BACKOFF_EXPONENTIAL_BACKOFF( lasus->start_backoff, backoff_iteration );\n  }\n  while( result == 0 );\n\n  LFDS711_BACKOFF_AUTOTUNE( lasus->start_backoff, backoff_iteration );\n\n  return;\n}\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_list_asu_insert_at_end( struct lfds711_list_asu_state *lasus,\n                                     struct lfds711_list_asu_element *lasue )\n{\n  char unsigned \n    result;\n\n  enum lfds711_misc_flag\n    finished_flag = LFDS711_MISC_FLAG_LOWERED;\n\n  lfds711_pal_uint_t\n    backoff_iteration = LFDS711_BACKOFF_INITIAL_VALUE;\n\n  struct lfds711_list_asu_element LFDS711_PAL_ALIGN(LFDS711_PAL_ALIGN_SINGLE_POINTER)\n    *compare;\n\n  struct lfds711_list_asu_element\n    *volatile lasue_next,\n    *volatile lasue_end;\n\n  LFDS711_PAL_ASSERT( lasus != NULL );\n  LFDS711_PAL_ASSERT( lasue != NULL );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &lasue->next % LFDS711_PAL_ALIGN_SINGLE_POINTER == 0 );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &lasue->value % LFDS711_PAL_ALIGN_SINGLE_POINTER == 0 );\n\n  /* TRD : begin by assuming end is correctly pointing to the final element\n           try to link (comparing for next being NULL)\n           if we fail, move down list till we find last element\n           and retry\n           when successful, update end to ourselves\n\n           note there's a leading dummy element\n           so lasus->end always points to an element\n  */\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  lasue->next = NULL;\n  lasue_end = lasus->end;\n\n  while( finished_flag == LFDS711_MISC_FLAG_LOWERED )\n  {\n    compare = NULL;\n\n    LFDS711_MISC_BARRIER_STORE;\n    LFDS711_PAL_ATOMIC_CAS( &lasue_end->next, &compare, lasue, LFDS711_MISC_CAS_STRENGTH_STRONG, result );\n\n    if( result == 1 )\n      finished_flag = LFDS711_MISC_FLAG_RAISED;\n    else\n    {\n      LFDS711_BACKOFF_EXPONENTIAL_BACKOFF( lasus->end_backoff, backoff_iteration );\n\n      lasue_end = compare;\n      lasue_next = LFDS711_LIST_ASU_GET_NEXT( *lasue_end );\n\n      while( lasue_next != NULL )\n      {\n        lasue_end = lasue_next;\n        lasue_next = LFDS711_LIST_ASU_GET_NEXT( *lasue_end );\n      }\n    }\n  }\n\n  lasus->end = lasue;\n\n  LFDS711_BACKOFF_AUTOTUNE( lasus->end_backoff, backoff_iteration );\n\n  return;\n}\n\n\n\n\n\n/****************************************************************************/\n#pragma warning( disable : 4100 )\n\nvoid lfds711_list_asu_insert_after_element( struct lfds711_list_asu_state *lasus,\n                                            struct lfds711_list_asu_element *lasue,\n                                            struct lfds711_list_asu_element *lasue_predecessor )\n{\n  char unsigned \n    result;\n\n  lfds711_pal_uint_t\n    backoff_iteration = LFDS711_BACKOFF_INITIAL_VALUE;\n\n  LFDS711_PAL_ASSERT( lasus != NULL );\n  LFDS711_PAL_ASSERT( lasue != NULL );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &lasue->next % LFDS711_PAL_ALIGN_SINGLE_POINTER == 0 );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &lasue->value % LFDS711_PAL_ALIGN_SINGLE_POINTER == 0 );\n  LFDS711_PAL_ASSERT( lasue_predecessor != NULL );\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  lasue->next = lasue_predecessor->next;\n\n  do\n  {\n    LFDS711_MISC_BARRIER_STORE;\n    LFDS711_PAL_ATOMIC_CAS( &lasue_predecessor->next, (struct lfds711_list_asu_element **) &lasue->next, lasue, LFDS711_MISC_CAS_STRENGTH_WEAK, result );\n    if( result == 0 )\n      LFDS711_BACKOFF_EXPONENTIAL_BACKOFF( lasus->after_backoff, backoff_iteration );\n  }\n  while( result == 0 );\n\n  LFDS711_BACKOFF_AUTOTUNE( lasus->after_backoff, backoff_iteration );\n\n  return;\n}\n\n#pragma warning( default : 4100 )\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_list_addonly_singlylinked_unordered/lfds711_list_addonly_singlylinked_unordered_internal.h",
    "content": "/***** the library wide include file *****/\n#include \"../liblfds711_internal.h\"\n\n/***** private prototypes *****/\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_list_addonly_singlylinked_unordered/lfds711_list_addonly_singlylinked_unordered_query.c",
    "content": "/***** includes *****/\n#include \"lfds711_list_addonly_singlylinked_unordered_internal.h\"\n\n/***** private prototypes *****/\nstatic void lfds711_list_asu_internal_validate( struct lfds711_list_asu_state *lasus,\n                                                struct lfds711_misc_validation_info *vi,\n                                                enum lfds711_misc_validity *lfds711_list_asu_validity );\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_list_asu_query( struct lfds711_list_asu_state *lasus,\n                             enum lfds711_list_asu_query query_type,\n                             void *query_input,\n                             void *query_output )\n{\n  LFDS711_PAL_ASSERT( lasus != NULL );\n  // TRD : query_type can be any value in its range\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  switch( query_type )\n  {\n    case LFDS711_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT:\n    {\n      struct lfds711_list_asu_element\n        *lasue = NULL;\n\n      LFDS711_PAL_ASSERT( query_input == NULL );\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      *(lfds711_pal_uint_t *) query_output = 0;\n\n      while( LFDS711_LIST_ASU_GET_START_AND_THEN_NEXT(*lasus, lasue) )\n        ( *(lfds711_pal_uint_t *) query_output )++;\n    }\n    break;\n\n    case LFDS711_LIST_ASU_QUERY_SINGLETHREADED_VALIDATE:\n      // TRD : query_input can be NULL\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      lfds711_list_asu_internal_validate( lasus, (struct lfds711_misc_validation_info *) query_input, (enum lfds711_misc_validity *) query_output );\n    break;\n  }\n\n  return;\n}\n\n\n\n\n\n\n/****************************************************************************/\nstatic void lfds711_list_asu_internal_validate( struct lfds711_list_asu_state *lasus,\n                                                struct lfds711_misc_validation_info *vi,\n                                                enum lfds711_misc_validity *lfds711_list_asu_validity )\n{\n  lfds711_pal_uint_t\n    number_elements = 0;\n\n  struct lfds711_list_asu_element\n    *lasue_fast,\n    *lasue_slow;\n\n  LFDS711_PAL_ASSERT( lasus!= NULL );\n  // TRD : vi can be NULL\n  LFDS711_PAL_ASSERT( lfds711_list_asu_validity != NULL );\n\n  *lfds711_list_asu_validity = LFDS711_MISC_VALIDITY_VALID;\n\n  lasue_slow = lasue_fast = lasus->start->next;\n\n  /* TRD : first, check for a loop\n           we have two pointers\n           both of which start at the start of the list\n           we enter a loop\n           and on each iteration\n           we advance one pointer by one element\n           and the other by two\n\n           we exit the loop when both pointers are NULL\n           (have reached the end of the queue)\n\n           or\n\n           if we fast pointer 'sees' the slow pointer\n           which means we have a loop\n  */\n\n  if( lasue_slow != NULL )\n    do\n    {\n      lasue_slow = lasue_slow->next;\n\n      if( lasue_fast != NULL )\n        lasue_fast = lasue_fast->next;\n\n      if( lasue_fast != NULL )\n        lasue_fast = lasue_fast->next;\n    }\n    while( lasue_slow != NULL and lasue_fast != lasue_slow );\n\n  if( lasue_fast != NULL and lasue_slow != NULL and lasue_fast == lasue_slow )\n    *lfds711_list_asu_validity = LFDS711_MISC_VALIDITY_INVALID_LOOP;\n\n  /* TRD : now check for expected number of elements\n           vi can be NULL, in which case we do not check\n           we know we don't have a loop from our earlier check\n  */\n\n  if( *lfds711_list_asu_validity == LFDS711_MISC_VALIDITY_VALID and vi != NULL )\n  {\n    lfds711_list_asu_query( lasus, LFDS711_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, &number_elements );\n\n    if( number_elements < vi->min_elements )\n      *lfds711_list_asu_validity = LFDS711_MISC_VALIDITY_INVALID_MISSING_ELEMENTS;\n\n    if( number_elements > vi->max_elements )\n      *lfds711_list_asu_validity = LFDS711_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS;\n  }\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_misc/lfds711_misc_globals.c",
    "content": "/***** includes *****/\n#include \"lfds711_misc_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nstruct lfds711_misc_globals\n  lfds711_misc_globals = \n  {\n    { LFDS711_PRNG_SEED }\n  };\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_misc/lfds711_misc_internal.h",
    "content": "/***** the library wide include file *****/\n#include \"../liblfds711_internal.h\"\n\n/***** private prototypes *****/\nvoid lfds711_misc_prng_internal_big_slow_high_quality_init( int long long unsigned seed );\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_misc/lfds711_misc_internal_backoff_init.c",
    "content": "/***** includes *****/\n#include \"lfds711_misc_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_misc_internal_backoff_init( struct lfds711_misc_backoff_state *bs )\n{\n  LFDS711_PAL_ASSERT( bs != NULL );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &bs->lock % LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 );\n\n  bs->lock = LFDS711_MISC_FLAG_LOWERED;\n  bs->backoff_iteration_frequency_counters[0] = 0;\n  bs->backoff_iteration_frequency_counters[1] = 0;\n  bs->metric = 1;\n  bs->total_operations = 0;\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_misc/lfds711_misc_query.c",
    "content": "/***** includes *****/\n#include \"lfds711_misc_internal.h\"\n\n\n\n\n\n/****************************************************************************/\n#pragma warning( disable : 4100 )\n\nvoid lfds711_misc_query( enum lfds711_misc_query query_type,\n                         void *query_input,\n                         void *query_output )\n{\n  // TRD : query type can be any value in its range\n  // TRD : query_input can be NULL in some cases\n  // TRD : query_outputput can be NULL in some cases\n\n  switch( query_type )\n  {\n    case LFDS711_MISC_QUERY_GET_BUILD_AND_VERSION_STRING:\n    {\n      char static const\n        * const build_and_version_string = \"liblfds \" LFDS711_MISC_VERSION_STRING \" (\" BUILD_TYPE_STRING \", \" LFDS711_PAL_OS_STRING \", \" MODE_TYPE_STRING \", \" LFDS711_PAL_PROCESSOR_STRING \", \" LFDS711_PAL_COMPILER_STRING \")\";\n\n      LFDS711_PAL_ASSERT( query_input == NULL );\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      *(char const **) query_output = build_and_version_string;\n    }\n    break;\n  }\n\n  return;\n}\n\n#pragma warning( default : 4100 )\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_prng/lfds711_prng_init.c",
    "content": "/***** includes *****/\n#include \"lfds711_prng_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_prng_init_valid_on_current_logical_core( struct lfds711_prng_state *ps, lfds711_pal_uint_t seed )\n{\n  LFDS711_PAL_ASSERT( ps != NULL );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &ps->entropy % LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 );\n  // TRD : seed can be any value in its range (unlike for the mixing function)\n\n  LFDS711_PRNG_ST_MIXING_FUNCTION( seed );\n\n  ps->entropy = seed;\n\n  LFDS711_MISC_BARRIER_STORE;\n\n  lfds711_misc_force_store();\n\n  return;\n}\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_prng_st_init( struct lfds711_prng_st_state *psts, lfds711_pal_uint_t seed )\n{\n  LFDS711_PAL_ASSERT( psts != NULL );\n  LFDS711_PAL_ASSERT( seed != 0 );\n\n  LFDS711_PRNG_ST_MIXING_FUNCTION( seed );\n\n  psts->entropy = seed;\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_prng/lfds711_prng_internal.h",
    "content": "/***** the library wide include file *****/\n#include \"../liblfds711_internal.h\"\n\n/***** private prototypes *****/\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_queue_bounded_manyproducer_manyconsumer/lfds711_queue_bounded_manyproducer_manyconsumer_cleanup.c",
    "content": "/***** includes *****/\n#include \"lfds711_queue_bounded_manyproducer_manyconsumer_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_queue_bmm_cleanup( struct lfds711_queue_bmm_state *qbmms,\n                                void (*element_cleanup_callback)(struct lfds711_queue_bmm_state *qbmms, void *key, void *value) )\n{\n  void\n    *key,\n    *value;\n\n  LFDS711_PAL_ASSERT( qbmms != NULL );\n  // TRD : element_cleanup_callback can be NULL\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  if( element_cleanup_callback != NULL )\n    while( lfds711_queue_bmm_dequeue(qbmms,&key,&value) )\n      element_cleanup_callback( qbmms, key, value );\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_queue_bounded_manyproducer_manyconsumer/lfds711_queue_bounded_manyproducer_manyconsumer_dequeue.c",
    "content": "/***** includes *****/\n#include \"lfds711_queue_bounded_manyproducer_manyconsumer_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nint lfds711_queue_bmm_dequeue( struct lfds711_queue_bmm_state *qbmms,\n                               void **key,\n                               void **value )\n{\n  char unsigned\n    result;\n\n  enum lfds711_misc_flag\n    finished_flag = LFDS711_MISC_FLAG_LOWERED;\n\n  int\n    rv = 1;\n\n  lfds711_pal_uint_t\n    read_index,\n    sequence_number;\n\n  lfds711_pal_int_t\n    difference;\n\n  lfds711_pal_uint_t\n    backoff_iteration = LFDS711_BACKOFF_INITIAL_VALUE;\n\n  struct lfds711_queue_bmm_element\n    *qbmme = NULL;\n\n  LFDS711_PAL_ASSERT( qbmms != NULL );\n  // TRD : key can be NULL\n  // TRD : value can be NULL\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  read_index = qbmms->read_index;\n\n  while( finished_flag == LFDS711_MISC_FLAG_LOWERED )\n  {\n    qbmme = &qbmms->element_array[ read_index & qbmms->mask ];\n    LFDS711_MISC_BARRIER_LOAD;\n    sequence_number = qbmme->sequence_number;\n    difference = (lfds711_pal_int_t) sequence_number - (lfds711_pal_int_t) (read_index + 1);\n\n    if( difference == 0 )\n    {\n      LFDS711_PAL_ATOMIC_CAS( &qbmms->read_index, &read_index, read_index + 1, LFDS711_MISC_CAS_STRENGTH_WEAK, result );\n      if( result == 0 )\n        LFDS711_BACKOFF_EXPONENTIAL_BACKOFF( qbmms->dequeue_backoff, backoff_iteration );\n      if( result == 1 )\n        finished_flag = LFDS711_MISC_FLAG_RAISED;\n    }\n\n    if( difference < 0 )\n    {\n      rv = 0;\n      finished_flag = LFDS711_MISC_FLAG_RAISED;\n    }\n\n    if( difference > 0 )\n    {\n      LFDS711_MISC_BARRIER_LOAD;\n      read_index = qbmms->read_index;\n    }\n  }\n\n  if( rv == 1 )\n  {\n    if( key != NULL )\n      *key = qbmme->key;\n    if( value != NULL )\n      *value = qbmme->value;\n    LFDS711_MISC_BARRIER_STORE;\n    qbmme->sequence_number = read_index + qbmms->mask + 1;\n  }\n\n  LFDS711_BACKOFF_AUTOTUNE( qbmms->dequeue_backoff, backoff_iteration );\n\n  return rv;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_queue_bounded_manyproducer_manyconsumer/lfds711_queue_bounded_manyproducer_manyconsumer_enqueue.c",
    "content": "/***** includes *****/\n#include \"lfds711_queue_bounded_manyproducer_manyconsumer_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nint lfds711_queue_bmm_enqueue( struct lfds711_queue_bmm_state *qbmms,\n                               void *key,\n                               void *value )\n{\n  char unsigned\n    result;\n\n  enum lfds711_misc_flag\n    finished_flag = LFDS711_MISC_FLAG_LOWERED;\n\n  int\n    rv = 1;\n\n  lfds711_pal_uint_t\n    sequence_number,\n    write_index;\n\n  lfds711_pal_int_t\n    difference;\n\n  lfds711_pal_uint_t\n    backoff_iteration = LFDS711_BACKOFF_INITIAL_VALUE;\n\n  struct lfds711_queue_bmm_element\n    *qbmme = NULL;\n\n  LFDS711_PAL_ASSERT( qbmms != NULL );\n  // TRD : key can be NULL\n  // TRD : value can be NULL\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  write_index = qbmms->write_index;\n\n  while( finished_flag == LFDS711_MISC_FLAG_LOWERED )\n  {\n    qbmme = &qbmms->element_array[ write_index & qbmms->mask ];\n    LFDS711_MISC_BARRIER_LOAD;\n    sequence_number = qbmme->sequence_number;\n    difference = (lfds711_pal_int_t) sequence_number - (lfds711_pal_int_t) write_index;\n\n    if( difference == 0 )\n    {\n      LFDS711_PAL_ATOMIC_CAS( &qbmms->write_index, &write_index, write_index + 1, LFDS711_MISC_CAS_STRENGTH_WEAK, result );\n      if( result == 0 )\n        LFDS711_BACKOFF_EXPONENTIAL_BACKOFF( qbmms->enqueue_backoff, backoff_iteration );\n      if( result == 1 )\n        finished_flag = LFDS711_MISC_FLAG_RAISED;\n    }\n\n    if( difference < 0 )\n    {\n      rv = 0;\n      finished_flag = LFDS711_MISC_FLAG_RAISED;\n    }\n\n    if( difference > 0 )\n    {\n      LFDS711_MISC_BARRIER_LOAD;\n      write_index = qbmms->write_index;\n    }\n  }\n\n  if( rv == 1 )\n  {\n    qbmme->key = key;\n    qbmme->value = value;\n    LFDS711_MISC_BARRIER_STORE;\n    qbmme->sequence_number = write_index + 1;\n  }\n\n  LFDS711_BACKOFF_AUTOTUNE( qbmms->enqueue_backoff, backoff_iteration );\n\n  return rv;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_queue_bounded_manyproducer_manyconsumer/lfds711_queue_bounded_manyproducer_manyconsumer_init.c",
    "content": "/***** includes *****/\n#include \"lfds711_queue_bounded_manyproducer_manyconsumer_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_queue_bmm_init_valid_on_current_logical_core( struct lfds711_queue_bmm_state *qbmms,\n                                                           struct lfds711_queue_bmm_element *element_array,\n                                                           lfds711_pal_uint_t number_elements,\n                                                           void *user_state )\n{\n  lfds711_pal_uint_t\n    loop;\n\n  LFDS711_PAL_ASSERT( qbmms != NULL );\n  LFDS711_PAL_ASSERT( element_array != NULL );\n  LFDS711_PAL_ASSERT( number_elements >= 2 );\n  LFDS711_PAL_ASSERT( ( number_elements & (number_elements-1) ) == 0 ); // TRD : number_elements must be a positive integer power of 2\n  // TRD : user_state can be NULL\n\n  qbmms->number_elements = number_elements;\n  qbmms->mask = qbmms->number_elements - 1;\n  qbmms->read_index = 0;\n  qbmms->write_index = 0;\n  qbmms->element_array = element_array;\n  qbmms->user_state = user_state;\n\n  for( loop = 0 ; loop < qbmms->number_elements ; loop++ )\n    qbmms->element_array[loop].sequence_number = loop;\n\n  lfds711_misc_internal_backoff_init( &qbmms->dequeue_backoff );\n  lfds711_misc_internal_backoff_init( &qbmms->enqueue_backoff );\n\n  LFDS711_MISC_BARRIER_STORE;\n\n  lfds711_misc_force_store();\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_queue_bounded_manyproducer_manyconsumer/lfds711_queue_bounded_manyproducer_manyconsumer_internal.h",
    "content": "/***** the library wide include file *****/\n#include \"../liblfds711_internal.h\"\n\n/***** private prototypes *****/\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_queue_bounded_manyproducer_manyconsumer/lfds711_queue_bounded_manyproducer_manyconsumer_query.c",
    "content": "/***** includes *****/\n#include \"lfds711_queue_bounded_manyproducer_manyconsumer_internal.h\"\n\n/***** private prototypes *****/\nstatic void lfds711_queue_bmm_internal_validate( struct lfds711_queue_bmm_state *qbmms,\n                                                 struct lfds711_misc_validation_info *vi,\n                                                 enum lfds711_misc_validity *lfds711_validity );\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_queue_bmm_query( struct lfds711_queue_bmm_state *qbmms,\n                              enum lfds711_queue_bmm_query query_type,\n                              void *query_input,\n                              void *query_output )\n{\n  LFDS711_PAL_ASSERT( qbmms != NULL );\n  // TRD : query_type can be any value in its range\n\n  switch( query_type )\n  {\n    case LFDS711_QUEUE_BMM_QUERY_GET_POTENTIALLY_INACCURATE_COUNT:\n    {\n      lfds711_pal_uint_t\n        local_read_index,\n        local_write_index;\n\n      LFDS711_PAL_ASSERT( query_input == NULL );\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      LFDS711_MISC_BARRIER_LOAD;\n\n      local_read_index = qbmms->read_index;\n      local_write_index = qbmms->write_index;\n\n      *(lfds711_pal_uint_t *) query_output = +( local_write_index - local_read_index );\n\n      if( local_read_index > local_write_index )\n        *(lfds711_pal_uint_t *) query_output = ((lfds711_pal_uint_t) -1) - *(lfds711_pal_uint_t *) query_output;\n    }\n    break;\n\n    case LFDS711_QUEUE_BMM_QUERY_SINGLETHREADED_VALIDATE:\n      // TRD : query_input can be NULL\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      lfds711_queue_bmm_internal_validate( qbmms, (struct lfds711_misc_validation_info *) query_input, (enum lfds711_misc_validity *) query_output );\n    break;\n  }\n\n  return;\n}\n\n\n\n\n\n/****************************************************************************/\nstatic void lfds711_queue_bmm_internal_validate( struct lfds711_queue_bmm_state *qbmms,\n                                                 struct lfds711_misc_validation_info *vi,\n                                                 enum lfds711_misc_validity *lfds711_validity )\n{\n  lfds711_pal_uint_t\n    expected_sequence_number,\n    loop,\n    number_elements,\n    sequence_number;\n\n  LFDS711_PAL_ASSERT( qbmms != NULL );\n  // TRD : vi can be NULL\n  LFDS711_PAL_ASSERT( lfds711_validity != NULL );\n\n  *lfds711_validity = LFDS711_MISC_VALIDITY_VALID;\n\n  /* TRD : starting from the read_index, we should find number_elements of incrementing sequence numbers\n           we then perform a second scan from the write_index onwards, which should have (max elements in queue - number_elements) incrementing sequence numbers\n  */\n\n  lfds711_queue_bmm_query( qbmms, LFDS711_QUEUE_BMM_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void *) &number_elements );\n\n  expected_sequence_number = qbmms->element_array[ qbmms->read_index & qbmms->mask ].sequence_number;\n\n  for( loop = 0 ; loop < number_elements ; loop++ )\n  {\n    sequence_number = qbmms->element_array[ (qbmms->read_index + loop) & qbmms->mask ].sequence_number;\n\n    if( sequence_number != expected_sequence_number )\n      *lfds711_validity = LFDS711_MISC_VALIDITY_INVALID_ORDER;\n\n    if( sequence_number == expected_sequence_number )\n      expected_sequence_number = sequence_number + 1;\n  }\n\n  // TRD : now the write_index onwards\n\n  expected_sequence_number = qbmms->element_array[ qbmms->write_index & qbmms->mask ].sequence_number;\n\n  for( loop = 0 ; loop < qbmms->number_elements - number_elements ; loop++ )\n  {\n    sequence_number = qbmms->element_array[ (qbmms->write_index + loop) & qbmms->mask ].sequence_number;\n\n    if( sequence_number != expected_sequence_number )\n      *lfds711_validity = LFDS711_MISC_VALIDITY_INVALID_ORDER;\n\n    if( sequence_number == expected_sequence_number )\n      expected_sequence_number = sequence_number + 1;\n  }\n\n  // TRD : now check against the expected number of elements\n\n  if( *lfds711_validity == LFDS711_MISC_VALIDITY_VALID and vi != NULL )\n  {\n    lfds711_pal_uint_t\n      number_elements;\n\n    lfds711_queue_bmm_query( qbmms, LFDS711_QUEUE_BMM_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void *) &number_elements );\n\n    if( number_elements < vi->min_elements )\n      *lfds711_validity = LFDS711_MISC_VALIDITY_INVALID_MISSING_ELEMENTS;\n\n    if( number_elements > vi->max_elements )\n      *lfds711_validity = LFDS711_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS;\n  }\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_queue_bounded_singleproducer_singleconsumer/lfds711_queue_bounded_singleproducer_singleconsumer_cleanup.c",
    "content": "/***** includes *****/\n#include \"lfds711_queue_bounded_singleproducer_singleconsumer_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_queue_bss_cleanup( struct lfds711_queue_bss_state *qbsss,\n                                void (*element_cleanup_callback)(struct lfds711_queue_bss_state *qbsss, void *key, void *value) )\n{\n  lfds711_pal_uint_t\n    loop;\n\n  struct lfds711_queue_bss_element\n    *qbsse;\n\n  LFDS711_PAL_ASSERT( qbsss != NULL );\n  // TRD : element_cleanup_callback can be NULL\n\n  if( element_cleanup_callback != NULL )\n    for( loop = qbsss->read_index ; loop < qbsss->read_index + qbsss->number_elements ; loop++ )\n    {\n      qbsse = qbsss->element_array + (loop % qbsss->number_elements);\n      element_cleanup_callback( qbsss, qbsse->key, qbsse->value );\n    }\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_queue_bounded_singleproducer_singleconsumer/lfds711_queue_bounded_singleproducer_singleconsumer_dequeue.c",
    "content": "/***** includes *****/\n#include \"lfds711_queue_bounded_singleproducer_singleconsumer_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nint lfds711_queue_bss_dequeue( struct lfds711_queue_bss_state *qbsss,\n                               void **key,\n                               void **value )\n{\n  struct lfds711_queue_bss_element\n    *qbsse;\n\n  LFDS711_PAL_ASSERT( qbsss != NULL );\n  // TRD : key can be NULL\n  // TRD : value can be NULL\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  if( qbsss->read_index != qbsss->write_index )\n  {\n    qbsse = qbsss->element_array + qbsss->read_index;\n\n    if( key != NULL )\n      *key = qbsse->key;\n\n    if( value != NULL )\n      *value = qbsse->value;\n\n    qbsss->read_index = (qbsss->read_index + 1) % qbsss->number_elements;\n\n    LFDS711_MISC_BARRIER_STORE;\n\n    return 1;\n  }\n\n  return 0;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_queue_bounded_singleproducer_singleconsumer/lfds711_queue_bounded_singleproducer_singleconsumer_enqueue.c",
    "content": "/***** includes *****/\n#include \"lfds711_queue_bounded_singleproducer_singleconsumer_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nint lfds711_queue_bss_enqueue( struct lfds711_queue_bss_state *qbsss,\n                               void *key,\n                               void *value )\n{\n  struct lfds711_queue_bss_element\n    *qbsse;\n\n  LFDS711_PAL_ASSERT( qbsss != NULL );\n  // TRD : key can be NULL\n  // TRD : value can be NULL\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  if( ( (qbsss->write_index+1) % qbsss->number_elements ) != qbsss->read_index )\n  {\n    qbsse = qbsss->element_array + qbsss->write_index;\n\n    qbsse->key = key;\n    qbsse->value = value;\n\n    LFDS711_MISC_BARRIER_STORE;\n\n    qbsss->write_index = (qbsss->write_index + 1) % qbsss->number_elements;\n\n    return 1;\n  }\n\n  return 0;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_queue_bounded_singleproducer_singleconsumer/lfds711_queue_bounded_singleproducer_singleconsumer_enqueue.ll",
    "content": "; ModuleID = 'lfds711_queue_bounded_singleproducer_singleconsumer_enqueue.c'\nsource_filename = \"lfds711_queue_bounded_singleproducer_singleconsumer_enqueue.c\"\ntarget datalayout = \"e-m:e-i64:64-f80:128-n8:16:32:64-S128\"\ntarget triple = \"x86_64-pc-linux-gnu\"\n\n%struct.lfds711_queue_bss_state = type { i64, i64, i64, i64, %struct.lfds711_queue_bss_element*, i8* }\n%struct.lfds711_queue_bss_element = type { i8*, i8* }\n\n; Function Attrs: noinline nounwind optnone sspstrong uwtable\ndefine dso_local i32 @lfds711_queue_bss_enqueue(%struct.lfds711_queue_bss_state*, i8*, i8*) #0 {\n  %4 = alloca i32, align 4\n  %5 = alloca %struct.lfds711_queue_bss_state*, align 8\n  %6 = alloca i8*, align 8\n  %7 = alloca i8*, align 8\n  %8 = alloca %struct.lfds711_queue_bss_element*, align 8\n  %9 = alloca i8*, align 8\n  store %struct.lfds711_queue_bss_state* %0, %struct.lfds711_queue_bss_state** %5, align 8\n  store i8* %1, i8** %6, align 8\n  store i8* %2, i8** %7, align 8\n  %10 = load %struct.lfds711_queue_bss_state*, %struct.lfds711_queue_bss_state** %5, align 8\n  %11 = icmp ne %struct.lfds711_queue_bss_state* %10, null\n  br i1 %11, label %14, label %12\n\n12:                                               ; preds = %3\n  store i8* null, i8** %9, align 8\n  %13 = load i8*, i8** %9, align 8\n  store i8 0, i8* %13, align 1\n  br label %14\n\n14:                                               ; preds = %12, %3\n  call void @lfds711_pal_barrier_compiler()\n  fence seq_cst\n  call void @lfds711_pal_barrier_compiler()\n  %15 = load %struct.lfds711_queue_bss_state*, %struct.lfds711_queue_bss_state** %5, align 8\n  %16 = getelementptr inbounds %struct.lfds711_queue_bss_state, %struct.lfds711_queue_bss_state* %15, i32 0, i32 3\n  %17 = load volatile i64, i64* %16, align 8\n  %18 = add i64 %17, 1\n  %19 = load %struct.lfds711_queue_bss_state*, %struct.lfds711_queue_bss_state** %5, align 8\n  %20 = getelementptr inbounds %struct.lfds711_queue_bss_state, %struct.lfds711_queue_bss_state* %19, i32 0, i32 1\n  %21 = load i64, i64* %20, align 8\n  %22 = and i64 %18, %21\n  %23 = load %struct.lfds711_queue_bss_state*, %struct.lfds711_queue_bss_state** %5, align 8\n  %24 = getelementptr inbounds %struct.lfds711_queue_bss_state, %struct.lfds711_queue_bss_state* %23, i32 0, i32 2\n  %25 = load volatile i64, i64* %24, align 8\n  %26 = icmp ne i64 %22, %25\n  br i1 %26, label %27, label %51\n\n27:                                               ; preds = %14\n  %28 = load %struct.lfds711_queue_bss_state*, %struct.lfds711_queue_bss_state** %5, align 8\n  %29 = getelementptr inbounds %struct.lfds711_queue_bss_state, %struct.lfds711_queue_bss_state* %28, i32 0, i32 4\n  %30 = load %struct.lfds711_queue_bss_element*, %struct.lfds711_queue_bss_element** %29, align 8\n  %31 = load %struct.lfds711_queue_bss_state*, %struct.lfds711_queue_bss_state** %5, align 8\n  %32 = getelementptr inbounds %struct.lfds711_queue_bss_state, %struct.lfds711_queue_bss_state* %31, i32 0, i32 3\n  %33 = load volatile i64, i64* %32, align 8\n  %34 = getelementptr inbounds %struct.lfds711_queue_bss_element, %struct.lfds711_queue_bss_element* %30, i64 %33\n  store %struct.lfds711_queue_bss_element* %34, %struct.lfds711_queue_bss_element** %8, align 8\n  %35 = load i8*, i8** %6, align 8\n  %36 = load %struct.lfds711_queue_bss_element*, %struct.lfds711_queue_bss_element** %8, align 8\n  %37 = getelementptr inbounds %struct.lfds711_queue_bss_element, %struct.lfds711_queue_bss_element* %36, i32 0, i32 0\n  store volatile i8* %35, i8** %37, align 8\n  %38 = load i8*, i8** %7, align 8\n  %39 = load %struct.lfds711_queue_bss_element*, %struct.lfds711_queue_bss_element** %8, align 8\n  %40 = getelementptr inbounds %struct.lfds711_queue_bss_element, %struct.lfds711_queue_bss_element* %39, i32 0, i32 1\n  store volatile i8* %38, i8** %40, align 8\n  call void @lfds711_pal_barrier_compiler()\n  fence seq_cst\n  call void @lfds711_pal_barrier_compiler()\n  %41 = load %struct.lfds711_queue_bss_state*, %struct.lfds711_queue_bss_state** %5, align 8\n  %42 = getelementptr inbounds %struct.lfds711_queue_bss_state, %struct.lfds711_queue_bss_state* %41, i32 0, i32 3\n  %43 = load volatile i64, i64* %42, align 8\n  %44 = add i64 %43, 1\n  %45 = load %struct.lfds711_queue_bss_state*, %struct.lfds711_queue_bss_state** %5, align 8\n  %46 = getelementptr inbounds %struct.lfds711_queue_bss_state, %struct.lfds711_queue_bss_state* %45, i32 0, i32 1\n  %47 = load i64, i64* %46, align 8\n  %48 = and i64 %44, %47\n  %49 = load %struct.lfds711_queue_bss_state*, %struct.lfds711_queue_bss_state** %5, align 8\n  %50 = getelementptr inbounds %struct.lfds711_queue_bss_state, %struct.lfds711_queue_bss_state* %49, i32 0, i32 3\n  store volatile i64 %48, i64* %50, align 8\n  store i32 1, i32* %4, align 4\n  br label %52\n\n51:                                               ; preds = %14\n  store i32 0, i32* %4, align 4\n  br label %52\n\n52:                                               ; preds = %51, %27\n  %53 = load i32, i32* %4, align 4\n  ret i32 %53\n}\n\n; Function Attrs: noinline nounwind optnone sspstrong uwtable\ndefine internal void @lfds711_pal_barrier_compiler() #0 {\n  call void asm sideeffect \"\", \"~{memory},~{dirflag},~{fpsr},~{flags}\"() #1, !srcloc !4\n  ret void\n}\n\nattributes #0 = { noinline nounwind optnone sspstrong uwtable \"correctly-rounded-divide-sqrt-fp-math\"=\"false\" \"disable-tail-calls\"=\"false\" \"less-precise-fpmad\"=\"false\" \"min-legal-vector-width\"=\"0\" \"no-frame-pointer-elim\"=\"true\" \"no-frame-pointer-elim-non-leaf\" \"no-infs-fp-math\"=\"false\" \"no-jump-tables\"=\"false\" \"no-nans-fp-math\"=\"false\" \"no-signed-zeros-fp-math\"=\"false\" \"no-trapping-math\"=\"false\" \"stack-protector-buffer-size\"=\"8\" \"target-cpu\"=\"x86-64\" \"target-features\"=\"+cx8,+fxsr,+mmx,+sse,+sse2,+x87\" \"unsafe-fp-math\"=\"false\" \"use-soft-float\"=\"false\" }\nattributes #1 = { nounwind }\n\n!llvm.module.flags = !{!0, !1, !2}\n!llvm.ident = !{!3}\n\n!0 = !{i32 1, !\"wchar_size\", i32 4}\n!1 = !{i32 7, !\"PIC Level\", i32 2}\n!2 = !{i32 7, !\"PIE Level\", i32 2}\n!3 = !{!\"clang version 9.0.1 \"}\n!4 = !{i32 51241}\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_queue_bounded_singleproducer_singleconsumer/lfds711_queue_bounded_singleproducer_singleconsumer_init.c",
    "content": "/***** includes *****/\n#include \"lfds711_queue_bounded_singleproducer_singleconsumer_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_queue_bss_init_valid_on_current_logical_core( struct lfds711_queue_bss_state *qbsss,\n                                                           struct lfds711_queue_bss_element *element_array,\n                                                           lfds711_pal_uint_t number_elements,\n                                                           void *user_state )\n{\n  LFDS711_PAL_ASSERT( qbsss != NULL );\n  LFDS711_PAL_ASSERT( element_array != NULL );\n  LFDS711_PAL_ASSERT( number_elements >= 2 );\n  LFDS711_PAL_ASSERT( ( number_elements & (number_elements-1) ) == 0 ); // TRD : number_elements must be a positive integer power of 2\n  // TRD : user_state can be NULL\n\n  /* TRD : the use of mask and the restriction on a power of two\n           upon the number of elements bears some remark\n\n           in this queue, there are a fixed number of elements\n           we have a read index and a write index\n           when we write, and thre is space to write, we increment the write index\n           (if no space to write, we just return)\n           when we read, and there are elements to be read, we after reading increment the read index\n           (if no elements to read, we just return)\n           the problem is - how do we handle wrap around?\n           e.g. when I write, but my write index is now equal to the number of elements\n           the usual solution is to modulus the write index by the nunmber of elements\n           problem is modulus is slow\n           there is a better way\n           first, we restrict the number of elements to be a power of two\n           so imagine we have a 64-bit system and we set the number of elements to be 2^64\n           this gives us a bit pattern of 1000 0000 0000 0000 (...etc, lots of zeros)\n           now (just roll with this for a bit) subtract one from this\n           this gives us a mask (on a two's compliment machine)\n           0111 1111 1111 1111 (...etc, lots of ones)\n           so what we do now, when we increment an index (think of the write index as the example)\n           we bitwise and it with the mask\n           now think about thwt happens\n           all the numbers up to 2^64 will be unchanged - their MSB is never set, and we and with all the other bits\n           but when we finally hit 2^64 and need to roll over... bingo!\n           we drop MSB (which we finally have) and have the value 0!\n           this is exactly what we want\n           bitwise and is much faster than modulus\n  */\n\n  qbsss->number_elements = number_elements;\n  qbsss->mask = qbsss->number_elements - 1;\n  qbsss->read_index = 0;\n  qbsss->write_index = 0;\n  qbsss->element_array = element_array;\n  qbsss->user_state = user_state;\n\n  LFDS711_MISC_BARRIER_STORE;\n\n  lfds711_misc_force_store();\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_queue_bounded_singleproducer_singleconsumer/lfds711_queue_bounded_singleproducer_singleconsumer_internal.h",
    "content": "/***** the library wide include file *****/\n#include \"../liblfds711_internal.h\"\n\n/***** private prototypes *****/\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_queue_bounded_singleproducer_singleconsumer/lfds711_queue_bounded_singleproducer_singleconsumer_query.c",
    "content": "/***** includes *****/\n#include \"lfds711_queue_bounded_singleproducer_singleconsumer_internal.h\"\n\n/***** private prototypes *****/\nstatic void lfds711_queue_bss_internal_validate( struct lfds711_queue_bss_state *qbsss,\n                                                 struct lfds711_misc_validation_info *vi,\n                                                 enum lfds711_misc_validity *lfds711_validity );\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_queue_bss_query( struct lfds711_queue_bss_state *qbsss,\n                              enum lfds711_queue_bss_query query_type,\n                              void *query_input,\n                              void *query_output )\n{\n  LFDS711_PAL_ASSERT( qbsss != NULL );\n  // TRD : query_type can be any value in its range\n\n  switch( query_type )\n  {\n    case LFDS711_QUEUE_BSS_QUERY_GET_POTENTIALLY_INACCURATE_COUNT:\n    {\n      lfds711_pal_uint_t\n        local_read_index,\n        local_write_index;\n\n      LFDS711_PAL_ASSERT( query_input == NULL );\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      LFDS711_MISC_BARRIER_LOAD;\n\n      local_read_index = qbsss->read_index;\n      local_write_index = qbsss->write_index;\n\n      *(lfds711_pal_uint_t *) query_output = +( local_write_index - local_read_index );\n\n      if( local_read_index > local_write_index )\n        *(lfds711_pal_uint_t *) query_output = qbsss->number_elements - *(lfds711_pal_uint_t *) query_output;\n    }\n    break;\n\n    case LFDS711_QUEUE_BSS_QUERY_VALIDATE:\n      // TRD : query_input can be NULL\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      lfds711_queue_bss_internal_validate( qbsss, (struct lfds711_misc_validation_info *) query_input, (enum lfds711_misc_validity *) query_output );\n    break;\n  }\n\n  return;\n}\n\n\n\n\n\n/****************************************************************************/\nstatic void lfds711_queue_bss_internal_validate( struct lfds711_queue_bss_state *qbsss,\n                                                 struct lfds711_misc_validation_info *vi,\n                                                 enum lfds711_misc_validity *lfds711_validity )\n{\n  LFDS711_PAL_ASSERT( qbsss != NULL );\n  // TRD : vi can be NULL\n  LFDS711_PAL_ASSERT( lfds711_validity != NULL );\n\n  *lfds711_validity = LFDS711_MISC_VALIDITY_VALID;\n\n  if( vi != NULL )\n  {\n    lfds711_pal_uint_t\n      number_elements;\n\n    lfds711_queue_bss_query( qbsss, LFDS711_QUEUE_BSS_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void *) &number_elements );\n\n    if( number_elements < vi->min_elements )\n      *lfds711_validity = LFDS711_MISC_VALIDITY_INVALID_MISSING_ELEMENTS;\n\n    if( number_elements > vi->max_elements )\n      *lfds711_validity = LFDS711_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS;\n  }\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_queue_bounded_singleproducer_singleconsumer/test.ll",
    "content": "; ModuleID = 'lfds711_queue_bounded_singleproducer_singleconsumer_enqueue.c'\nsource_filename = \"lfds711_queue_bounded_singleproducer_singleconsumer_enqueue.c\"\ntarget datalayout = \"e-m:e-i64:64-f80:128-n8:16:32:64-S128\"\ntarget triple = \"x86_64-pc-linux-gnu\"\n\n%struct.lfds711_queue_bss_state = type { i64, i64, i64, i64, %struct.lfds711_queue_bss_element*, i8* }\n%struct.lfds711_queue_bss_element = type { i8*, i8* }\n\n; Function Attrs: noinline nounwind optnone sspstrong uwtable\ndefine dso_local i32 @lfds711_queue_bss_enqueue(%struct.lfds711_queue_bss_state* %qbsss, i8* %key, i8* %value) #0 {\nentry:\n  %retval = alloca i32, align 4\n  %qbsss.addr = alloca %struct.lfds711_queue_bss_state*, align 8\n  %key.addr = alloca i8*, align 8\n  %value.addr = alloca i8*, align 8\n  %qbsse = alloca %struct.lfds711_queue_bss_element*, align 8\n  %c = alloca i8*, align 8\n  store %struct.lfds711_queue_bss_state* %qbsss, %struct.lfds711_queue_bss_state** %qbsss.addr, align 8\n  store i8* %key, i8** %key.addr, align 8\n  store i8* %value, i8** %value.addr, align 8\n  %0 = load %struct.lfds711_queue_bss_state*, %struct.lfds711_queue_bss_state** %qbsss.addr, align 8\n  %cmp = icmp ne %struct.lfds711_queue_bss_state* %0, null\n  br i1 %cmp, label %if.end, label %if.then\n\nif.then:                                          ; preds = %entry\n  store i8* null, i8** %c, align 8\n  %1 = load i8*, i8** %c, align 8\n  store i8 0, i8* %1, align 1\n  br label %if.end\n\nif.end:                                           ; preds = %if.then, %entry\n  call void @lfds711_pal_barrier_compiler()\n  fence seq_cst\n  call void @lfds711_pal_barrier_compiler()\n  %2 = load %struct.lfds711_queue_bss_state*, %struct.lfds711_queue_bss_state** %qbsss.addr, align 8\n  %write_index = getelementptr inbounds %struct.lfds711_queue_bss_state, %struct.lfds711_queue_bss_state* %2, i32 0, i32 3\n  %3 = load volatile i64, i64* %write_index, align 8\n  %add = add i64 %3, 1\n  %4 = load %struct.lfds711_queue_bss_state*, %struct.lfds711_queue_bss_state** %qbsss.addr, align 8\n  %mask = getelementptr inbounds %struct.lfds711_queue_bss_state, %struct.lfds711_queue_bss_state* %4, i32 0, i32 1\n  %5 = load i64, i64* %mask, align 8\n  %and = and i64 %add, %5\n  %6 = load %struct.lfds711_queue_bss_state*, %struct.lfds711_queue_bss_state** %qbsss.addr, align 8\n  %read_index = getelementptr inbounds %struct.lfds711_queue_bss_state, %struct.lfds711_queue_bss_state* %6, i32 0, i32 2\n  %7 = load volatile i64, i64* %read_index, align 8\n  %cmp1 = icmp ne i64 %and, %7\n  br i1 %cmp1, label %if.then2, label %if.end11\n\nif.then2:                                         ; preds = %if.end\n  %8 = load %struct.lfds711_queue_bss_state*, %struct.lfds711_queue_bss_state** %qbsss.addr, align 8\n  %element_array = getelementptr inbounds %struct.lfds711_queue_bss_state, %struct.lfds711_queue_bss_state* %8, i32 0, i32 4\n  %9 = load %struct.lfds711_queue_bss_element*, %struct.lfds711_queue_bss_element** %element_array, align 8\n  %10 = load %struct.lfds711_queue_bss_state*, %struct.lfds711_queue_bss_state** %qbsss.addr, align 8\n  %write_index3 = getelementptr inbounds %struct.lfds711_queue_bss_state, %struct.lfds711_queue_bss_state* %10, i32 0, i32 3\n  %11 = load volatile i64, i64* %write_index3, align 8\n  %add.ptr = getelementptr inbounds %struct.lfds711_queue_bss_element, %struct.lfds711_queue_bss_element* %9, i64 %11\n  store %struct.lfds711_queue_bss_element* %add.ptr, %struct.lfds711_queue_bss_element** %qbsse, align 8\n  %12 = load i8*, i8** %key.addr, align 8\n  %13 = load %struct.lfds711_queue_bss_element*, %struct.lfds711_queue_bss_element** %qbsse, align 8\n  %key4 = getelementptr inbounds %struct.lfds711_queue_bss_element, %struct.lfds711_queue_bss_element* %13, i32 0, i32 0\n  store volatile i8* %12, i8** %key4, align 8\n  %14 = load i8*, i8** %value.addr, align 8\n  %15 = load %struct.lfds711_queue_bss_element*, %struct.lfds711_queue_bss_element** %qbsse, align 8\n  %value5 = getelementptr inbounds %struct.lfds711_queue_bss_element, %struct.lfds711_queue_bss_element* %15, i32 0, i32 1\n  store volatile i8* %14, i8** %value5, align 8\n  call void @lfds711_pal_barrier_compiler()\n  fence seq_cst\n  call void @lfds711_pal_barrier_compiler()\n  %16 = load %struct.lfds711_queue_bss_state*, %struct.lfds711_queue_bss_state** %qbsss.addr, align 8\n  %write_index6 = getelementptr inbounds %struct.lfds711_queue_bss_state, %struct.lfds711_queue_bss_state* %16, i32 0, i32 3\n  %17 = load volatile i64, i64* %write_index6, align 8\n  %add7 = add i64 %17, 1\n  %18 = load %struct.lfds711_queue_bss_state*, %struct.lfds711_queue_bss_state** %qbsss.addr, align 8\n  %mask8 = getelementptr inbounds %struct.lfds711_queue_bss_state, %struct.lfds711_queue_bss_state* %18, i32 0, i32 1\n  %19 = load i64, i64* %mask8, align 8\n  %and9 = and i64 %add7, %19\n  %20 = load %struct.lfds711_queue_bss_state*, %struct.lfds711_queue_bss_state** %qbsss.addr, align 8\n  %write_index10 = getelementptr inbounds %struct.lfds711_queue_bss_state, %struct.lfds711_queue_bss_state* %20, i32 0, i32 3\n  store volatile i64 %and9, i64* %write_index10, align 8\n  store i32 1, i32* %retval, align 4\n  br label %return\n\nif.end11:                                         ; preds = %if.end\n  store i32 0, i32* %retval, align 4\n  br label %return\n\nreturn:                                           ; preds = %if.end11, %if.then2\n  %21 = load i32, i32* %retval, align 4\n  ret i32 %21\n}\n\n; Function Attrs: noinline nounwind optnone sspstrong uwtable\ndefine internal void @lfds711_pal_barrier_compiler() #0 {\nentry:\n  call void asm sideeffect \"\", \"~{memory},~{dirflag},~{fpsr},~{flags}\"() #1, !srcloc !4\n  ret void\n}\n\nattributes #0 = { noinline nounwind optnone sspstrong uwtable \"correctly-rounded-divide-sqrt-fp-math\"=\"false\" \"disable-tail-calls\"=\"false\" \"less-precise-fpmad\"=\"false\" \"min-legal-vector-width\"=\"0\" \"no-frame-pointer-elim\"=\"true\" \"no-frame-pointer-elim-non-leaf\" \"no-infs-fp-math\"=\"false\" \"no-jump-tables\"=\"false\" \"no-nans-fp-math\"=\"false\" \"no-signed-zeros-fp-math\"=\"false\" \"no-trapping-math\"=\"false\" \"stack-protector-buffer-size\"=\"8\" \"target-cpu\"=\"x86-64\" \"target-features\"=\"+cx8,+fxsr,+mmx,+sse,+sse2,+x87\" \"unsafe-fp-math\"=\"false\" \"use-soft-float\"=\"false\" }\nattributes #1 = { nounwind }\n\n!llvm.module.flags = !{!0, !1, !2}\n!llvm.ident = !{!3}\n\n!0 = !{i32 1, !\"wchar_size\", i32 4}\n!1 = !{i32 7, !\"PIC Level\", i32 2}\n!2 = !{i32 7, !\"PIE Level\", i32 2}\n!3 = !{!\"clang version 9.0.1 \"}\n!4 = !{i32 51241}\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_queue_unbounded_manyproducer_manyconsumer/lfds711_queue_unbounded_manyproducer_manyconsumer_cleanup.c",
    "content": "/***** includes *****/\n#include \"lfds711_queue_unbounded_manyproducer_manyconsumer_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_queue_umm_cleanup( struct lfds711_queue_umm_state *qumms,\n                                void (*element_cleanup_callback)(struct lfds711_queue_umm_state *qumms, struct lfds711_queue_umm_element *qumme, enum lfds711_misc_flag dummy_element_flag) )\n{\n  struct lfds711_queue_umm_element\n    *qumme;\n\n  void\n    *value;\n\n  LFDS711_PAL_ASSERT( qumms != NULL );\n  // TRD : element_cleanup_callback can be NULL\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  if( element_cleanup_callback != NULL )\n  {\n    while( qumms->dequeue[POINTER] != qumms->enqueue[POINTER] )\n    {\n      // TRD : trailing dummy element, so the first real value is in the next element\n      value = qumms->dequeue[POINTER]->next[POINTER]->value;\n\n      // TRD : user is given back *an* element, but not the one his user data was in\n      qumme = qumms->dequeue[POINTER];\n\n      // TRD : remove the element from queue\n      qumms->dequeue[POINTER] = qumms->dequeue[POINTER]->next[POINTER];\n\n      // TRD : write value into the qumme we're going to give the user\n      qumme->value = value;\n\n      element_cleanup_callback( qumms, qumme, LFDS711_MISC_FLAG_LOWERED );\n    }\n\n    // TRD : and now the final element\n    element_cleanup_callback( qumms, (struct lfds711_queue_umm_element *) qumms->dequeue[POINTER], LFDS711_MISC_FLAG_RAISED );\n  }\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_queue_unbounded_manyproducer_manyconsumer/lfds711_queue_unbounded_manyproducer_manyconsumer_dequeue.c",
    "content": "/***** includes *****/\n#include \"lfds711_queue_unbounded_manyproducer_manyconsumer_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nint lfds711_queue_umm_dequeue( struct lfds711_queue_umm_state *qumms,\n                               struct lfds711_queue_umm_element **qumme )\n{\n  char unsigned\n    result = 0;\n\n  enum lfds711_misc_flag\n    backoff_flag = LFDS711_MISC_FLAG_RAISED,\n    finished_flag = LFDS711_MISC_FLAG_LOWERED;\n\n  enum lfds711_queue_umm_queue_state\n    state = LFDS711_QUEUE_UMM_QUEUE_STATE_UNKNOWN;\n\n  int\n    rv = 1;\n\n  lfds711_pal_uint_t\n    backoff_iteration = LFDS711_BACKOFF_INITIAL_VALUE;\n\n  struct lfds711_queue_umm_element LFDS711_PAL_ALIGN(LFDS711_PAL_ALIGN_DOUBLE_POINTER)\n    *dequeue[PAC_SIZE],\n    *enqueue[PAC_SIZE],\n    *next[PAC_SIZE];\n\n  void\n    *key = NULL,\n    *value = NULL;\n\n  LFDS711_PAL_ASSERT( qumms != NULL );\n  LFDS711_PAL_ASSERT( qumme != NULL );\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  do\n  {\n    /* TRD : note here the deviation from the white paper\n             in the white paper, next is loaded from dequeue, not from qumms->dequeue\n             what concerns me is that between the load of dequeue and the load of\n             enqueue->next, the element can be dequeued by another thread *and freed*\n\n             by ordering the loads (load barriers), and loading both from qumms,\n             the following if(), which checks dequeue is still the same as qumms->enqueue\n             still continues to ensure next belongs to enqueue, while avoiding the\n             problem with free\n    */\n\n    dequeue[COUNTER] = qumms->dequeue[COUNTER];\n    dequeue[POINTER] = qumms->dequeue[POINTER];\n\n    LFDS711_MISC_BARRIER_LOAD;\n\n    enqueue[COUNTER] = qumms->enqueue[COUNTER];\n    enqueue[POINTER] = qumms->enqueue[POINTER];\n\n    next[COUNTER] = qumms->dequeue[POINTER]->next[COUNTER];\n    next[POINTER] = qumms->dequeue[POINTER]->next[POINTER];\n\n    LFDS711_MISC_BARRIER_LOAD;\n\n    if( qumms->dequeue[COUNTER] == dequeue[COUNTER] and qumms->dequeue[POINTER] == dequeue[POINTER] )\n    {\n      if( enqueue[POINTER] == dequeue[POINTER] and next[POINTER] == NULL )\n        state = LFDS711_QUEUE_UMM_QUEUE_STATE_EMPTY;\n\n      if( enqueue[POINTER] == dequeue[POINTER] and next[POINTER] != NULL )\n        state = LFDS711_QUEUE_UMM_QUEUE_STATE_ENQUEUE_OUT_OF_PLACE;\n\n      if( enqueue[POINTER] != dequeue[POINTER] )\n        state = LFDS711_QUEUE_UMM_QUEUE_STATE_ATTEMPT_DEQUEUE;\n\n      switch( state )\n      {\n        case LFDS711_QUEUE_UMM_QUEUE_STATE_UNKNOWN:\n          // TRD : eliminates compiler warning\n        break;\n\n        case LFDS711_QUEUE_UMM_QUEUE_STATE_EMPTY:\n          rv = 0;\n          *qumme = NULL;\n          result = 0;\n          backoff_flag = LFDS711_MISC_FLAG_LOWERED;\n          finished_flag = LFDS711_MISC_FLAG_RAISED;\n        break;\n\n        case LFDS711_QUEUE_UMM_QUEUE_STATE_ENQUEUE_OUT_OF_PLACE:\n          next[COUNTER] = enqueue[COUNTER] + 1;\n          LFDS711_PAL_ATOMIC_DWCAS( qumms->enqueue, enqueue, next, LFDS711_MISC_CAS_STRENGTH_WEAK, result );\n          // TRD : in fact if result is 1 (successful) I think we can now simply drop down into the dequeue attempt\n        break;\n\n        case LFDS711_QUEUE_UMM_QUEUE_STATE_ATTEMPT_DEQUEUE:\n          key = next[POINTER]->key;\n          value = next[POINTER]->value;\n\n          next[COUNTER] = qumms->dequeue[COUNTER] + 1;\n          LFDS711_PAL_ATOMIC_DWCAS( qumms->dequeue, dequeue, next, LFDS711_MISC_CAS_STRENGTH_WEAK, result );\n\n          if( result == 1 )\n          {\n            backoff_flag = LFDS711_MISC_FLAG_LOWERED;\n            finished_flag = LFDS711_MISC_FLAG_RAISED;\n          }\n        break;\n      }\n    }\n    else\n      backoff_flag = LFDS711_MISC_FLAG_RAISED;\n\n    if( backoff_flag == LFDS711_MISC_FLAG_RAISED )\n      LFDS711_BACKOFF_EXPONENTIAL_BACKOFF( qumms->dequeue_backoff, backoff_iteration );\n  }\n  while( finished_flag == LFDS711_MISC_FLAG_LOWERED );\n\n  if( result == 1 )\n  {\n    *qumme = dequeue[POINTER];\n    (*qumme)->key = key;\n    (*qumme)->value = value;\n  }\n\n  LFDS711_BACKOFF_AUTOTUNE( qumms->dequeue_backoff, backoff_iteration );\n\n  return rv;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_queue_unbounded_manyproducer_manyconsumer/lfds711_queue_unbounded_manyproducer_manyconsumer_enqueue.c",
    "content": "/***** includes *****/\n#include \"lfds711_queue_unbounded_manyproducer_manyconsumer_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_queue_umm_enqueue( struct lfds711_queue_umm_state *qumms,\n                                struct lfds711_queue_umm_element *qumme )\n{\n  char unsigned\n    result = 0;\n\n  enum lfds711_misc_flag\n    finished_flag = LFDS711_MISC_FLAG_LOWERED;\n\n  lfds711_pal_uint_t\n    backoff_iteration = LFDS711_BACKOFF_INITIAL_VALUE;\n\n  struct lfds711_queue_umm_element LFDS711_PAL_ALIGN(LFDS711_PAL_ALIGN_DOUBLE_POINTER)\n    *volatile enqueue[PAC_SIZE],\n    *new_enqueue[PAC_SIZE],\n    *volatile next[PAC_SIZE];\n\n  LFDS711_PAL_ASSERT( qumms != NULL );\n  LFDS711_PAL_ASSERT( qumme != NULL );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) qumme->next % LFDS711_PAL_ALIGN_DOUBLE_POINTER == 0 );\n\n  qumme->next[POINTER] = NULL;\n  LFDS711_PAL_ATOMIC_ADD( &qumms->aba_counter, 1, qumme->next[COUNTER], struct lfds711_queue_umm_element * );\n  LFDS711_MISC_BARRIER_STORE;\n\n  new_enqueue[POINTER] = qumme;\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  do\n  {\n    /* TRD : note here the deviation from the white paper\n             in the white paper, next is loaded from enqueue, not from qumms->enqueue\n             what concerns me is that between the load of enqueue and the load of\n             enqueue->next, the element can be dequeued by another thread *and freed*\n\n             by ordering the loads (load barriers), and loading both from qumms,\n             the following if(), which checks enqueue is still the same as qumms->enqueue\n             still continues to ensure next belongs to enqueue, while avoiding the\n             problem with free\n    */\n\n    enqueue[COUNTER] = qumms->enqueue[COUNTER];\n    enqueue[POINTER] = qumms->enqueue[POINTER];\n\n    LFDS711_MISC_BARRIER_LOAD;\n\n    next[COUNTER] = qumms->enqueue[POINTER]->next[COUNTER];\n    next[POINTER] = qumms->enqueue[POINTER]->next[POINTER];\n\n    LFDS711_MISC_BARRIER_LOAD;\n\n    if( qumms->enqueue[COUNTER] == enqueue[COUNTER] and qumms->enqueue[POINTER] == enqueue[POINTER] )\n    {\n      if( next[POINTER] == NULL )\n      {\n        new_enqueue[COUNTER] = next[COUNTER] + 1;\n        LFDS711_PAL_ATOMIC_DWCAS( enqueue[POINTER]->next, next, new_enqueue, LFDS711_MISC_CAS_STRENGTH_WEAK, result );\n        if( result == 1 )\n          finished_flag = LFDS711_MISC_FLAG_RAISED;\n      }\n      else\n      {\n        next[COUNTER] = enqueue[COUNTER] + 1;\n        // TRD : strictly, this is a weak CAS, but we do an extra iteration of the main loop on a fake failure, so we set it to be strong\n        LFDS711_PAL_ATOMIC_DWCAS( qumms->enqueue, enqueue, next, LFDS711_MISC_CAS_STRENGTH_STRONG, result );\n      }\n    }\n    else\n      result = 0;\n\n    if( result == 0 )\n      LFDS711_BACKOFF_EXPONENTIAL_BACKOFF( qumms->enqueue_backoff, backoff_iteration );\n  }\n  while( finished_flag == LFDS711_MISC_FLAG_LOWERED );\n\n  // TRD : move enqueue along; only a weak CAS as the dequeue will solve this if it's out of place\n  new_enqueue[COUNTER] = enqueue[COUNTER] + 1;\n  LFDS711_PAL_ATOMIC_DWCAS( qumms->enqueue, enqueue, new_enqueue, LFDS711_MISC_CAS_STRENGTH_WEAK, result );\n\n  if( result == 0 )\n    LFDS711_BACKOFF_EXPONENTIAL_BACKOFF( qumms->enqueue_backoff, backoff_iteration );\n\n  LFDS711_BACKOFF_AUTOTUNE( qumms->enqueue_backoff, backoff_iteration );\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_queue_unbounded_manyproducer_manyconsumer/lfds711_queue_unbounded_manyproducer_manyconsumer_init.c",
    "content": "/***** includes *****/\n#include \"lfds711_queue_unbounded_manyproducer_manyconsumer_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_queue_umm_init_valid_on_current_logical_core( struct lfds711_queue_umm_state *qumms,\n                                                           struct lfds711_queue_umm_element *qumme_dummy,\n                                                           void *user_state )\n{\n  LFDS711_PAL_ASSERT( qumms != NULL );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &qumms->enqueue % LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &qumms->dequeue % LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &qumms->user_state % LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 );\n  LFDS711_PAL_ASSERT( qumme_dummy != NULL );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) qumme_dummy->next % LFDS711_PAL_ALIGN_DOUBLE_POINTER == 0 );\n  // TRD : user_state can be NULL\n\n  /* TRD : qumme_dummy is a dummy element, needed for init\n           the qumms->enqueue and qumms->dequeue counters do not need to be initialized\n           but it does no harm to do so, and stops a valgrind complaint\n  */\n\n  LFDS711_PRNG_GENERATE( lfds711_misc_globals.ps, qumms->aba_counter );\n\n  qumms->enqueue[POINTER] = qumme_dummy;\n  qumms->enqueue[COUNTER] = (struct lfds711_queue_umm_element *) 0;\n  qumms->dequeue[POINTER] = qumme_dummy;\n  qumms->dequeue[COUNTER] = (struct lfds711_queue_umm_element *) 0;\n\n  qumme_dummy->next[POINTER] = NULL;\n  // TRD : no need here for an atomic add as we have a store barrier and force store below\n  qumme_dummy->next[COUNTER] = (struct lfds711_queue_umm_element *) qumms->aba_counter++;\n  qumme_dummy->key = NULL;\n  qumme_dummy->value = NULL;\n\n  qumms->user_state = user_state;\n\n  lfds711_misc_internal_backoff_init( &qumms->dequeue_backoff );\n  lfds711_misc_internal_backoff_init( &qumms->enqueue_backoff );\n\n  LFDS711_MISC_BARRIER_STORE;\n\n  lfds711_misc_force_store();\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_queue_unbounded_manyproducer_manyconsumer/lfds711_queue_unbounded_manyproducer_manyconsumer_internal.h",
    "content": "/***** the library wide include file *****/\n#include \"../liblfds711_internal.h\"\n\n/***** enums *****/\nenum lfds711_queue_umm_queue_state\n{\n  LFDS711_QUEUE_UMM_QUEUE_STATE_UNKNOWN, \n  LFDS711_QUEUE_UMM_QUEUE_STATE_EMPTY,\n  LFDS711_QUEUE_UMM_QUEUE_STATE_ENQUEUE_OUT_OF_PLACE,\n  LFDS711_QUEUE_UMM_QUEUE_STATE_ATTEMPT_DEQUEUE\n};\n\n/***** private prototypes *****/\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_queue_unbounded_manyproducer_manyconsumer/lfds711_queue_unbounded_manyproducer_manyconsumer_query.c",
    "content": "/***** includes *****/\n#include \"lfds711_queue_unbounded_manyproducer_manyconsumer_internal.h\"\n\n/***** private prototypes *****/\nstatic void lfds711_queue_umm_internal_validate( struct lfds711_queue_umm_state *qumms,\n                                                 struct lfds711_misc_validation_info *vi,\n                                                 enum lfds711_misc_validity *lfds711_queue_umm_validity );\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_queue_umm_query( struct lfds711_queue_umm_state *qumms,\n                              enum lfds711_queue_umm_query query_type,\n                              void *query_input,\n                              void *query_output )\n{\n  struct lfds711_queue_umm_element\n    *qumme;\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  LFDS711_PAL_ASSERT( qumms != NULL );\n  // TRD : query_type can be any value in its range\n\n  switch( query_type )\n  {\n    case LFDS711_QUEUE_UMM_QUERY_SINGLETHREADED_GET_COUNT:\n      LFDS711_PAL_ASSERT( query_input == NULL );\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      *(lfds711_pal_uint_t *) query_output = 0;\n\n      qumme = (struct lfds711_queue_umm_element *) qumms->dequeue[POINTER];\n\n      while( qumme != NULL )\n      {\n        ( *(lfds711_pal_uint_t *) query_output )++;\n        qumme = (struct lfds711_queue_umm_element *) qumme->next[POINTER];\n      }\n\n      // TRD : remember there is a dummy element in the queue\n      ( *(lfds711_pal_uint_t *) query_output )--;\n    break;\n\n    case LFDS711_QUEUE_UMM_QUERY_SINGLETHREADED_VALIDATE:\n      // TRD : query_input can be NULL\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      lfds711_queue_umm_internal_validate( qumms, (struct lfds711_misc_validation_info *) query_input, (enum lfds711_misc_validity *) query_output );\n    break;\n  }\n\n  return;\n}\n\n\n\n\n\n/****************************************************************************/\nstatic void lfds711_queue_umm_internal_validate( struct lfds711_queue_umm_state *qumms,\n                                                 struct lfds711_misc_validation_info *vi,\n                                                 enum lfds711_misc_validity *lfds711_queue_umm_validity )\n{\n  lfds711_pal_uint_t\n    number_elements = 0;\n\n  struct lfds711_queue_umm_element\n    *qumme_fast,\n    *qumme_slow;\n\n  LFDS711_PAL_ASSERT( qumms != NULL );\n  // TRD : vi can be NULL\n  LFDS711_PAL_ASSERT( lfds711_queue_umm_validity != NULL );\n\n  *lfds711_queue_umm_validity = LFDS711_MISC_VALIDITY_VALID;\n\n  qumme_slow = qumme_fast = (struct lfds711_queue_umm_element *) qumms->dequeue[POINTER];\n\n  /* TRD : first, check for a loop\n           we have two pointers\n           both of which start at the dequeue end of the queue\n           we enter a loop\n           and on each iteration\n           we advance one pointer by one element\n           and the other by two\n\n           we exit the loop when both pointers are NULL\n           (have reached the end of the queue)\n\n           or\n\n           if we fast pointer 'sees' the slow pointer\n           which means we have a loop\n  */\n\n  if( qumme_slow != NULL )\n    do\n    {\n      qumme_slow = qumme_slow->next[POINTER];\n\n      if( qumme_fast != NULL )\n        qumme_fast = qumme_fast->next[POINTER];\n\n      if( qumme_fast != NULL )\n        qumme_fast = qumme_fast->next[POINTER];\n    }\n    while( qumme_slow != NULL and qumme_fast != qumme_slow );\n\n  if( qumme_fast != NULL and qumme_slow != NULL and qumme_fast == qumme_slow )\n    *lfds711_queue_umm_validity = LFDS711_MISC_VALIDITY_INVALID_LOOP;\n\n  /* TRD : now check for expected number of elements\n           vi can be NULL, in which case we do not check\n           we know we don't have a loop from our earlier check\n  */\n\n  if( *lfds711_queue_umm_validity == LFDS711_MISC_VALIDITY_VALID and vi != NULL )\n  {\n    lfds711_queue_umm_query( qumms, LFDS711_QUEUE_UMM_QUERY_SINGLETHREADED_GET_COUNT, NULL, (void *) &number_elements );\n\n    if( number_elements < vi->min_elements )\n      *lfds711_queue_umm_validity = LFDS711_MISC_VALIDITY_INVALID_MISSING_ELEMENTS;\n\n    if( number_elements > vi->max_elements )\n      *lfds711_queue_umm_validity = LFDS711_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS;\n  }\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_ringbuffer/lfds711_ringbuffer_cleanup.c",
    "content": "/***** includes *****/\n#include \"lfds711_ringbuffer_internal.h\"\n\n/***** private prototypes *****/\nstatic void lfds711_ringbuffer_internal_queue_umm_element_cleanup_callback( struct lfds711_queue_umm_state *qumms,\n                                                                            struct lfds711_queue_umm_element *qumme,\n                                                                            enum lfds711_misc_flag dummy_element_flag );\nstatic void lfds711_ringbuffer_internal_freelist_element_cleanup_callback( struct lfds711_freelist_state *fs,\n                                                                           struct lfds711_freelist_element *fe );\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_ringbuffer_cleanup( struct lfds711_ringbuffer_state *rs,\n                                 void (*element_cleanup_callback)(struct lfds711_ringbuffer_state *rs, void *key, void *value, enum lfds711_misc_flag unread_flag) )\n{\n  LFDS711_PAL_ASSERT( rs != NULL );\n  // TRD : element_cleanup_callback can be NULL\n\n  if( element_cleanup_callback != NULL )\n  {\n    rs->element_cleanup_callback = element_cleanup_callback;\n    lfds711_queue_umm_cleanup( &rs->qumms, lfds711_ringbuffer_internal_queue_umm_element_cleanup_callback );\n    lfds711_freelist_cleanup( &rs->fs, lfds711_ringbuffer_internal_freelist_element_cleanup_callback );\n  }\n\n  return;\n}\n\n\n\n\n\n/****************************************************************************/\n#pragma warning( disable : 4100 )\n\nstatic void lfds711_ringbuffer_internal_queue_umm_element_cleanup_callback( struct lfds711_queue_umm_state *qumms,\n                                                                            struct lfds711_queue_umm_element *qumme,\n                                                                            enum lfds711_misc_flag dummy_element_flag )\n{\n  struct lfds711_ringbuffer_element\n    *re;\n\n  struct lfds711_ringbuffer_state\n    *rs;\n\n  LFDS711_PAL_ASSERT( qumms != NULL );\n  LFDS711_PAL_ASSERT( qumme != NULL );\n  // TRD : dummy_element can be any value in its range\n\n  rs = (struct lfds711_ringbuffer_state *) LFDS711_QUEUE_UMM_GET_USER_STATE_FROM_STATE( *qumms );\n  re = (struct lfds711_ringbuffer_element *) LFDS711_QUEUE_UMM_GET_VALUE_FROM_ELEMENT( *qumme );\n\n  if( dummy_element_flag == LFDS711_MISC_FLAG_LOWERED )\n    rs->element_cleanup_callback( rs, re->key, re->value, LFDS711_MISC_FLAG_RAISED );\n\n  return;\n}\n\n#pragma warning( default : 4100 )\n\n\n\n\n\n/****************************************************************************/\n#pragma warning( disable : 4100 )\n\nstatic void lfds711_ringbuffer_internal_freelist_element_cleanup_callback( struct lfds711_freelist_state *fs,\n                                                                           struct lfds711_freelist_element *fe )\n{\n  struct lfds711_ringbuffer_element\n    *re;\n\n  struct lfds711_ringbuffer_state\n    *rs;\n\n  LFDS711_PAL_ASSERT( fs != NULL );\n  LFDS711_PAL_ASSERT( fe != NULL );\n\n  rs = (struct lfds711_ringbuffer_state *) LFDS711_FREELIST_GET_USER_STATE_FROM_STATE( *fs );\n  re = (struct lfds711_ringbuffer_element *) LFDS711_FREELIST_GET_VALUE_FROM_ELEMENT( *fe );\n\n  rs->element_cleanup_callback( rs, re->key, re->value, LFDS711_MISC_FLAG_LOWERED );\n\n  return;\n}\n\n#pragma warning( default : 4100 )\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_ringbuffer/lfds711_ringbuffer_init.c",
    "content": "/***** includes *****/\n#include \"lfds711_ringbuffer_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_ringbuffer_init_valid_on_current_logical_core( struct lfds711_ringbuffer_state *rs,\n                                                            struct lfds711_ringbuffer_element *re_array_inc_dummy,\n                                                            lfds711_pal_uint_t number_elements_inc_dummy,\n                                                            void *user_state )\n{\n  lfds711_pal_uint_t\n    loop;\n\n  LFDS711_PAL_ASSERT( rs != NULL );\n  LFDS711_PAL_ASSERT( re_array_inc_dummy != NULL );\n  LFDS711_PAL_ASSERT( number_elements_inc_dummy >= 2 );\n  // TRD : user_state can be NULL\n\n  rs->user_state = user_state;\n\n  re_array_inc_dummy[0].qumme_use = &re_array_inc_dummy[0].qumme;\n\n  lfds711_freelist_init_valid_on_current_logical_core( &rs->fs, NULL, 0, rs );\n  lfds711_queue_umm_init_valid_on_current_logical_core( &rs->qumms, &re_array_inc_dummy[0].qumme, rs );\n\n  for( loop = 1 ; loop < number_elements_inc_dummy ; loop++ )\n  {\n    re_array_inc_dummy[loop].qumme_use = &re_array_inc_dummy[loop].qumme;\n    LFDS711_FREELIST_SET_VALUE_IN_ELEMENT( re_array_inc_dummy[loop].fe, &re_array_inc_dummy[loop] );\n    lfds711_freelist_push( &rs->fs, &re_array_inc_dummy[loop].fe, NULL );\n  }\n\n  LFDS711_MISC_BARRIER_STORE;\n\n  lfds711_misc_force_store();\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_ringbuffer/lfds711_ringbuffer_internal.h",
    "content": "/***** the library wide include file *****/\n#include \"../liblfds711_internal.h\"\n\n/***** private prototypes *****/\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_ringbuffer/lfds711_ringbuffer_query.c",
    "content": "/***** includes *****/\n#include \"lfds711_ringbuffer_internal.h\"\n\n/***** private prototypes *****/\nstatic void lfds711_ringbuffer_internal_validate( struct lfds711_ringbuffer_state *rs,\n                                                  struct lfds711_misc_validation_info *vi,\n                                                  enum lfds711_misc_validity *lfds711_queue_umm_validity,\n                                                  enum lfds711_misc_validity *lfds711_freelist_validity );\n\n\n\n/****************************************************************************/\nvoid lfds711_ringbuffer_query( struct lfds711_ringbuffer_state *rs,\n                               enum lfds711_ringbuffer_query query_type,\n                               void *query_input,\n                               void *query_output )\n{\n  LFDS711_PAL_ASSERT( rs != NULL );\n  // TRD : query_type can be any value in its range\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  switch( query_type )\n  {\n    case LFDS711_RINGBUFFER_QUERY_SINGLETHREADED_GET_COUNT:\n      LFDS711_PAL_ASSERT( query_input == NULL );\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      lfds711_queue_umm_query( &rs->qumms, LFDS711_QUEUE_UMM_QUERY_SINGLETHREADED_GET_COUNT, NULL, query_output );\n    break;\n\n    case LFDS711_RINGBUFFER_QUERY_SINGLETHREADED_VALIDATE:\n      // TRD : query_input can be NULL\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      lfds711_ringbuffer_internal_validate( rs, (struct lfds711_misc_validation_info *) query_input, (enum lfds711_misc_validity *) query_output, ((enum lfds711_misc_validity *) query_output)+1 );\n    break;\n  }\n\n  return;\n}\n\n\n\n\n\n/****************************************************************************/\nstatic void lfds711_ringbuffer_internal_validate( struct lfds711_ringbuffer_state *rs,\n                                                  struct lfds711_misc_validation_info *vi,\n                                                  enum lfds711_misc_validity *lfds711_queue_umm_validity,\n                                                  enum lfds711_misc_validity *lfds711_freelist_validity )\n{\n  LFDS711_PAL_ASSERT( rs != NULL );\n  // TRD : vi can be NULL\n  LFDS711_PAL_ASSERT( lfds711_queue_umm_validity != NULL );\n  LFDS711_PAL_ASSERT( lfds711_freelist_validity != NULL );\n\n  if( vi == NULL )\n  {\n    lfds711_queue_umm_query( &rs->qumms, LFDS711_QUEUE_UMM_QUERY_SINGLETHREADED_VALIDATE, NULL, lfds711_queue_umm_validity );\n    lfds711_freelist_query( &rs->fs, LFDS711_FREELIST_QUERY_SINGLETHREADED_VALIDATE, NULL, lfds711_freelist_validity );\n  }\n\n  if( vi != NULL )\n  {\n    struct lfds711_misc_validation_info\n      freelist_vi,\n      queue_vi;\n\n    queue_vi.min_elements = 0;\n    freelist_vi.min_elements = 0;\n    queue_vi.max_elements = vi->max_elements;\n    freelist_vi.max_elements = vi->max_elements;\n\n    lfds711_queue_umm_query( &rs->qumms, LFDS711_QUEUE_UMM_QUERY_SINGLETHREADED_VALIDATE, &queue_vi, lfds711_queue_umm_validity );\n    lfds711_freelist_query( &rs->fs, LFDS711_FREELIST_QUERY_SINGLETHREADED_VALIDATE, &freelist_vi, lfds711_freelist_validity );\n  }\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_ringbuffer/lfds711_ringbuffer_read.c",
    "content": "/***** includes *****/\n#include \"lfds711_ringbuffer_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nint lfds711_ringbuffer_read( struct lfds711_ringbuffer_state *rs,\n                             void **key,\n                             void **value )\n{\n  int\n    rv;\n\n  struct lfds711_queue_umm_element\n    *qumme;\n\n  struct lfds711_ringbuffer_element\n    *re;\n\n  LFDS711_PAL_ASSERT( rs != NULL );\n  // TRD : key can be NULL\n  // TRD : value can be NULL\n  // TRD : psts can be NULL\n\n  rv = lfds711_queue_umm_dequeue( &rs->qumms, &qumme );\n\n  if( rv == 1 )\n  {\n    re = LFDS711_QUEUE_UMM_GET_VALUE_FROM_ELEMENT( *qumme );\n    re->qumme_use = (struct lfds711_queue_umm_element *) qumme;\n    if( key != NULL )\n      *key = re->key;\n    if( value != NULL )\n      *value = re->value;\n    LFDS711_FREELIST_SET_VALUE_IN_ELEMENT( re->fe, re );\n    lfds711_freelist_push( &rs->fs, &re->fe, NULL );\n  }\n\n  return rv;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_ringbuffer/lfds711_ringbuffer_write.c",
    "content": "/***** includes *****/\n#include \"lfds711_ringbuffer_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_ringbuffer_write( struct lfds711_ringbuffer_state *rs,\n                               void *key,\n                               void *value,\n                               enum lfds711_misc_flag *overwrite_occurred_flag,\n                               void **overwritten_key,\n                               void **overwritten_value )\n{\n  int\n    rv = 0;\n\n  struct lfds711_freelist_element\n    *fe;\n\n  struct lfds711_queue_umm_element\n    *qumme;\n\n  struct lfds711_ringbuffer_element\n    *re = NULL;\n\n  LFDS711_PAL_ASSERT( rs != NULL );\n  // TRD : key can be NULL\n  // TRD : value can be NULL\n  // TRD : overwrite_occurred_flag can be NULL\n  // TRD : overwritten_key can be NULL\n  // TRD : overwritten_value can be NULL\n  // TRD : psts can be NULL\n\n  if( overwrite_occurred_flag != NULL )\n    *overwrite_occurred_flag = LFDS711_MISC_FLAG_LOWERED;\n\n  do\n  {\n    rv = lfds711_freelist_pop( &rs->fs, &fe, NULL );\n\n    if( rv == 1 )\n      re = LFDS711_FREELIST_GET_VALUE_FROM_ELEMENT( *fe );\n\n    if( rv == 0 )\n    {\n      // TRD : the queue can return empty as well - remember, we're lock-free; anything could have happened since the previous instruction\n      rv = lfds711_queue_umm_dequeue( &rs->qumms, &qumme );\n\n      if( rv == 1 )\n      {\n        re = LFDS711_QUEUE_UMM_GET_VALUE_FROM_ELEMENT( *qumme );\n        re->qumme_use = (struct lfds711_queue_umm_element *) qumme;\n\n        if( overwrite_occurred_flag != NULL )\n          *overwrite_occurred_flag = LFDS711_MISC_FLAG_RAISED;\n\n        if( overwritten_key != NULL )\n          *overwritten_key = re->key;\n\n        if( overwritten_value != NULL )\n          *overwritten_value = re->value;\n      }\n    }\n  }\n  while( rv == 0 );\n\n  re->key = key;\n  re->value = value;\n\n  LFDS711_QUEUE_UMM_SET_VALUE_IN_ELEMENT( *re->qumme_use, re );\n  lfds711_queue_umm_enqueue( &rs->qumms, re->qumme_use );\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_stack/lfds711_stack_cleanup.c",
    "content": "/***** includes *****/\n#include \"lfds711_stack_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_stack_cleanup( struct lfds711_stack_state *ss,\n                            void (*element_cleanup_callback)(struct lfds711_stack_state *ss, struct lfds711_stack_element *se) )\n{\n  struct lfds711_stack_element\n    *se,\n    *se_temp;\n\n  LFDS711_PAL_ASSERT( ss != NULL );\n  // TRD : element_cleanup_callback can be NULL\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  if( element_cleanup_callback != NULL )\n  {\n    se = ss->top[POINTER];\n\n    while( se != NULL )\n    {\n      se_temp = se;\n      se = se->next;\n\n      element_cleanup_callback( ss, se_temp );\n    }\n  }\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_stack/lfds711_stack_init.c",
    "content": "/***** includes *****/\n#include \"lfds711_stack_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_stack_init_valid_on_current_logical_core( struct lfds711_stack_state *ss,\n                                                       void *user_state )\n{\n  LFDS711_PAL_ASSERT( ss != NULL );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) ss->top % LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 );\n  LFDS711_PAL_ASSERT( (lfds711_pal_uint_t) &ss->user_state % LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES == 0 );\n  // TRD : user_state can be NULL\n\n  ss->top[POINTER] = NULL;\n  ss->top[COUNTER] = 0;\n\n  ss->user_state = user_state;\n\n  lfds711_misc_internal_backoff_init( &ss->pop_backoff );\n  lfds711_misc_internal_backoff_init( &ss->push_backoff );\n\n  LFDS711_MISC_BARRIER_STORE;\n\n  lfds711_misc_force_store();\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_stack/lfds711_stack_internal.h",
    "content": "/***** the library wide include file *****/\n#include \"../liblfds711_internal.h\"\n\n/***** private prototypes *****/\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_stack/lfds711_stack_pop.c",
    "content": "/***** includes *****/\n#include \"lfds711_stack_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nint lfds711_stack_pop( struct lfds711_stack_state *ss,\n                       struct lfds711_stack_element **se )\n{\n  char unsigned\n    result;\n\n  lfds711_pal_uint_t\n    backoff_iteration = LFDS711_BACKOFF_INITIAL_VALUE;\n\n  struct lfds711_stack_element LFDS711_PAL_ALIGN(LFDS711_PAL_ALIGN_DOUBLE_POINTER)\n    *new_top[PAC_SIZE],\n    *volatile original_top[PAC_SIZE];\n\n  LFDS711_PAL_ASSERT( ss != NULL );\n  LFDS711_PAL_ASSERT( se != NULL );\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  original_top[COUNTER] = ss->top[COUNTER];\n  original_top[POINTER] = ss->top[POINTER];\n\n  do\n  {\n    if( original_top[POINTER] == NULL )\n    {\n      *se = NULL;\n      return 0;\n    }\n\n    new_top[COUNTER] = original_top[COUNTER] + 1;\n    new_top[POINTER] = original_top[POINTER]->next;\n\n    LFDS711_PAL_ATOMIC_DWCAS( ss->top, original_top, new_top, LFDS711_MISC_CAS_STRENGTH_WEAK, result );\n\n    if( result == 0 )\n    {\n      LFDS711_BACKOFF_EXPONENTIAL_BACKOFF( ss->pop_backoff, backoff_iteration );\n      LFDS711_MISC_BARRIER_LOAD;\n    }\n  }\n  while( result == 0 );\n\n  *se = original_top[POINTER];\n\n  LFDS711_BACKOFF_AUTOTUNE( ss->pop_backoff, backoff_iteration );\n\n  return 1;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_stack/lfds711_stack_push.c",
    "content": "/***** includes *****/\n#include \"lfds711_stack_internal.h\"\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_stack_push( struct lfds711_stack_state *ss,\n                         struct lfds711_stack_element *se )\n{\n  char unsigned\n    result;\n\n  lfds711_pal_uint_t\n    backoff_iteration = LFDS711_BACKOFF_INITIAL_VALUE;\n\n  struct lfds711_stack_element LFDS711_PAL_ALIGN(LFDS711_PAL_ALIGN_DOUBLE_POINTER)\n    *new_top[PAC_SIZE],\n    *volatile original_top[PAC_SIZE];\n\n  LFDS711_PAL_ASSERT( ss != NULL );\n  LFDS711_PAL_ASSERT( se != NULL );\n\n  new_top[POINTER] = se;\n\n  original_top[COUNTER] = ss->top[COUNTER];\n  original_top[POINTER] = ss->top[POINTER];\n\n  do\n  {\n    se->next = original_top[POINTER];\n    LFDS711_MISC_BARRIER_STORE;\n\n    new_top[COUNTER] = original_top[COUNTER] + 1;\n    LFDS711_PAL_ATOMIC_DWCAS( ss->top, original_top, new_top, LFDS711_MISC_CAS_STRENGTH_WEAK, result );\n\n    if( result == 0 )\n      LFDS711_BACKOFF_EXPONENTIAL_BACKOFF( ss->push_backoff, backoff_iteration );\n  }\n  while( result == 0 );\n\n  LFDS711_BACKOFF_AUTOTUNE( ss->push_backoff, backoff_iteration );\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/lfds711_stack/lfds711_stack_query.c",
    "content": "/***** includes *****/\n#include \"lfds711_stack_internal.h\"\n\n/***** private prototypes *****/\nstatic void lfds711_stack_internal_stack_validate( struct lfds711_stack_state *ss,\n                                                   struct lfds711_misc_validation_info *vi,\n                                                   enum lfds711_misc_validity *lfds711_stack_validity );\n\n\n\n\n\n/****************************************************************************/\nvoid lfds711_stack_query( struct lfds711_stack_state *ss,\n                          enum lfds711_stack_query query_type,\n                          void *query_input,\n                          void *query_output )\n{\n  struct lfds711_stack_element\n    *se;\n\n  LFDS711_MISC_BARRIER_LOAD;\n\n  LFDS711_PAL_ASSERT( ss != NULL );\n  // TRD : query_type can be any value in its range\n\n  switch( query_type )\n  {\n    case LFDS711_STACK_QUERY_SINGLETHREADED_GET_COUNT:\n      LFDS711_PAL_ASSERT( query_input == NULL );\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      *(lfds711_pal_uint_t *) query_output = 0;\n\n      se = (struct lfds711_stack_element *) ss->top[POINTER];\n\n      while( se != NULL )\n      {\n        ( *(lfds711_pal_uint_t *) query_output )++;\n        se = (struct lfds711_stack_element *) se->next;\n      }\n    break;\n\n    case LFDS711_STACK_QUERY_SINGLETHREADED_VALIDATE:\n      // TRD : query_input can be NULL\n      LFDS711_PAL_ASSERT( query_output != NULL );\n\n      lfds711_stack_internal_stack_validate( ss, (struct lfds711_misc_validation_info *) query_input, (enum lfds711_misc_validity *) query_output );\n    break;\n  }\n\n  return;\n}\n\n\n\n\n\n/****************************************************************************/\nstatic void lfds711_stack_internal_stack_validate( struct lfds711_stack_state *ss,\n                                                   struct lfds711_misc_validation_info *vi,\n                                                   enum lfds711_misc_validity *lfds711_stack_validity )\n{\n  lfds711_pal_uint_t\n    number_elements = 0;\n\n  struct lfds711_stack_element\n    *se_fast,\n    *se_slow;\n\n  LFDS711_PAL_ASSERT( ss != NULL );\n  // TRD : vi can be NULL\n  LFDS711_PAL_ASSERT( lfds711_stack_validity != NULL );\n\n  *lfds711_stack_validity = LFDS711_MISC_VALIDITY_VALID;\n\n  se_slow = se_fast = (struct lfds711_stack_element *) ss->top[POINTER];\n\n  /* TRD : first, check for a loop\n           we have two pointers\n           both of which start at the top of the stack\n           we enter a loop\n           and on each iteration\n           we advance one pointer by one element\n           and the other by two\n\n           we exit the loop when both pointers are NULL\n           (have reached the end of the stack)\n\n           or\n\n           if we fast pointer 'sees' the slow pointer\n           which means we have a loop\n  */\n\n  if( se_slow != NULL )\n    do\n    {\n      se_slow = se_slow->next;\n\n      if( se_fast != NULL )\n        se_fast = se_fast->next;\n\n      if( se_fast != NULL )\n        se_fast = se_fast->next;\n    }\n    while( se_slow != NULL and se_fast != se_slow );\n\n  if( se_fast != NULL and se_slow != NULL and se_fast == se_slow )\n    *lfds711_stack_validity = LFDS711_MISC_VALIDITY_INVALID_LOOP;\n\n  /* TRD : now check for expected number of elements\n           vi can be NULL, in which case we do not check\n           we know we don't have a loop from our earlier check\n  */\n\n  if( *lfds711_stack_validity == LFDS711_MISC_VALIDITY_VALID and vi != NULL )\n  {\n    lfds711_stack_query( ss, LFDS711_STACK_QUERY_SINGLETHREADED_GET_COUNT, NULL, (void *) &number_elements );\n\n    if( number_elements < vi->min_elements )\n      *lfds711_stack_validity = LFDS711_MISC_VALIDITY_INVALID_MISSING_ELEMENTS;\n\n    if( number_elements > vi->max_elements )\n      *lfds711_stack_validity = LFDS711_MISC_VALIDITY_INVALID_ADDITIONAL_ELEMENTS;\n  }\n\n  return;\n}\n\n"
  },
  {
    "path": "Test/qbss_benchmark/liblfds711_modulo/src/liblfds711_internal.h",
    "content": "/***** public prototypes *****/\n#include \"../inc/liblfds711.h\"\n\n/***** defines *****/\n#define and &&\n#define or  ||\n\n#define NO_FLAGS 0x0\n\n#define LFDS711_VERSION_STRING   \"7.1.1\"\n#define LFDS711_VERSION_INTEGER  711\n\n#if( defined KERNEL_MODE )\n  #define MODE_TYPE_STRING \"kernel-mode\"\n#endif\n\n#if( !defined KERNEL_MODE )\n  #define MODE_TYPE_STRING \"user-mode\"\n#endif\n\n#if( defined NDEBUG && !defined COVERAGE && !defined TSAN && !defined PROF )\n  #define BUILD_TYPE_STRING \"release\"\n#endif\n\n#if( !defined NDEBUG && !defined COVERAGE && !defined TSAN && !defined PROF )\n  #define BUILD_TYPE_STRING \"debug\"\n#endif\n\n#if( !defined NDEBUG && defined COVERAGE && !defined TSAN && !defined PROF )\n  #define BUILD_TYPE_STRING \"coverage\"\n#endif\n\n#if( !defined NDEBUG && !defined COVERAGE && defined TSAN && !defined PROF )\n  #define BUILD_TYPE_STRING \"threadsanitizer\"\n#endif\n\n#if( !defined NDEBUG && !defined COVERAGE && !defined TSAN && defined PROF )\n  #define BUILD_TYPE_STRING \"profiling\"\n#endif\n\n#define LFDS711_BACKOFF_INITIAL_VALUE  0\n#define LFDS711_BACKOFF_LIMIT          10\n\n#define LFDS711_BACKOFF_EXPONENTIAL_BACKOFF( backoff_state, backoff_iteration )                \\\n{                                                                                              \\\n  lfds711_pal_uint_t volatile                                                                  \\\n    loop;                                                                                      \\\n                                                                                               \\\n  lfds711_pal_uint_t                                                                           \\\n    endloop;                                                                                   \\\n                                                                                               \\\n  if( (backoff_iteration) == LFDS711_BACKOFF_LIMIT )                                           \\\n    (backoff_iteration) = LFDS711_BACKOFF_INITIAL_VALUE;                                       \\\n  else                                                                                         \\\n  {                                                                                            \\\n    endloop = ( ((lfds711_pal_uint_t) 0x1) << (backoff_iteration) ) * (backoff_state).metric;  \\\n    for( loop = 0 ; loop < endloop ; loop++ );                                                 \\\n  }                                                                                            \\\n                                                                                               \\\n  (backoff_iteration)++;                                                                       \\\n}\n\n#define LFDS711_BACKOFF_AUTOTUNE( bs, backoff_iteration )                                                                           \\\n{                                                                                                                                   \\\n  if( (backoff_iteration) < 2 )                                                                                                     \\\n    (bs).backoff_iteration_frequency_counters[(backoff_iteration)]++;                                                               \\\n                                                                                                                                    \\\n  if( ++(bs).total_operations >= 10000 and (bs).lock == LFDS711_MISC_FLAG_LOWERED )                                                 \\\n  {                                                                                                                                 \\\n    char unsigned                                                                                                                   \\\n      result;                                                                                                                       \\\n                                                                                                                                    \\\n    lfds711_pal_uint_t LFDS711_PAL_ALIGN(LFDS711_PAL_ATOMIC_ISOLATION_IN_BYTES)                                                     \\\n      compare = LFDS711_MISC_FLAG_LOWERED;                                                                                          \\\n                                                                                                                                    \\\n    LFDS711_PAL_ATOMIC_CAS( &(bs).lock, &compare, LFDS711_MISC_FLAG_RAISED, LFDS711_MISC_CAS_STRENGTH_WEAK, result );               \\\n                                                                                                                                    \\\n    if( result == 1 )                                                                                                               \\\n    {                                                                                                                               \\\n      /* TRD : if E[1] is less than 1/100th of E[0], decrease the metric, to increase E[1] */                                       \\\n      if( (bs).backoff_iteration_frequency_counters[1] < (bs).backoff_iteration_frequency_counters[0] / 100 )                       \\\n      {                                                                                                                             \\\n        if( (bs).metric >= 11 )                                                                                                     \\\n          (bs).metric -= 10;                                                                                                        \\\n      }                                                                                                                             \\\n      else                                                                                                                          \\\n        (bs).metric += 10;                                                                                                          \\\n                                                                                                                                    \\\n      (bs).backoff_iteration_frequency_counters[0] = 0;                                                                             \\\n      (bs).backoff_iteration_frequency_counters[1] = 0;                                                                             \\\n      (bs).total_operations = 0;                                                                                                    \\\n                                                                                                                                    \\\n      LFDS711_MISC_BARRIER_STORE;                                                                                                   \\\n                                                                                                                                    \\\n      LFDS711_PAL_ATOMIC_SET( &(bs).lock, LFDS711_MISC_FLAG_LOWERED );                                                              \\\n    }                                                                                                                               \\\n  }                                                                                                                                 \\\n}\n\n/***** library-wide prototypes *****/\nvoid lfds711_misc_internal_backoff_init( struct lfds711_misc_backoff_state *bs );\n\n"
  },
  {
    "path": "Test/qbss_benchmark/queue.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs {\n\n    //type uint64 /*Key*/ = uint64\n    //type uint64 /*Value*/ = uint64\n    \n    struct BSSQueueElement {\n        var key:uint64 /*Key*/;\n        var value:uint64 /*Value*/;    \n    }\n    \n    struct QbssState {\n        var number_elements:uint64;\n        var mask:uint64;\n        var write_index:uint64;\n        var read_index:uint64;\n        var element_array:ptr<BSSQueueElement>; // need to make sure the array is 2^N = number_elements\n    }\n\n    struct BackoffState {\n        var lock:uint64;\n        var backoff_iteration_frequency_counters:uint64[2];\n        var metric:uint64;\n        var total_operations:uint64;\n    }\n\n    datatype QbssLogEntry = EnqueueLogEntry(key:uint64, value:uint64) | DequeueLogEntry(key:uint64, value:uint64)   \n    ghost var log:seq<QbssLogEntry> := [];\n\n    refinement_constraint @\"\n       || (ls.stop_reason == hs.stop_reason && ls.ghosts.log == hs.ghosts.log)\n       || (ls.stop_reason.Armada_NotStopped? && ls.ghosts.log <= hs.ghosts.log)\n    \"\n}\n\nlevel {:concrete} QueueBSS using SharedStructs {\n    noaddr var queue:QbssState;\n\n    method init_queue(qbss:ptr<QbssState>, size:uint64) {\n        (*qbss).number_elements := size;\n        (*qbss).read_index := 0;\n        (*qbss).write_index := 0;\n        (*qbss).element_array := calloc(BSSQueueElement, size);\n    }\n\n    method enqueue(qbss:ptr<QbssState>, k:uint64, v:uint64) returns (ret:uint64) {\n        noaddr var e:ptr<BSSQueueElement>;\n        noaddr var read_index:uint64;\n        noaddr var number_elements:uint64;\n        noaddr var write_index:uint64;\n        noaddr var modulo:uint64;\n        noaddr var tmp_write_index:uint64;\n        noaddr var element:ptr<BSSQueueElement>;\n        noaddr var tmp_array:ptr<BSSQueueElement>;\n\n        write_index := (*qbss).write_index;\n        tmp_write_index := write_index + 1;\n        number_elements := (*qbss).number_elements;\n        modulo := tmp_write_index % number_elements;\n        read_index := (*qbss).read_index;\n        if(read_index != modulo) {\n            write_index := (*qbss).write_index;\n            tmp_array := (*qbss).element_array;\n            element := (*qbss).element_array + write_index; \n            e := element;\n            (*e).key := k;\n            (*e).value := v;\n            write_index := (*qbss).write_index;\n            tmp_write_index := write_index + 1;\n            number_elements := (*qbss).number_elements;\n            modulo := tmp_write_index % number_elements;\n            (*qbss).write_index := modulo;\nret := 1;\n            return;\n        }\nret := 0;\n        return;\n    }\n\n    method dequeue(qbss:ptr<QbssState>, k:ptr<uint64>, v:ptr<uint64>) returns (ret:uint64) {\n        noaddr var e:ptr<BSSQueueElement>;\n        noaddr var read_index:uint64;\n        noaddr var number_elements:uint64;\n        noaddr var write_index:uint64;\n        noaddr var modulo:uint64;\n        noaddr var tmp_read_index:uint64;\n        noaddr var tmp_int:uint64;\n        noaddr var tmp_array:ptr<BSSQueueElement>;\n        noaddr var element:ptr<BSSQueueElement>;\n        read_index := (*qbss).read_index;\n        write_index := (*qbss).write_index;\n        if(read_index != write_index) {\n            read_index := (*qbss).read_index;\n            tmp_array := (*qbss).element_array;\n            element := tmp_array + read_index; \n            e := element;\n            if(k != null) {\n                tmp_int := (*e).key;\n                *k := tmp_int;\n            }\n            if(v != null) {\n                tmp_int := (*e).value;\n                *v := tmp_int;\n            }\n            read_index := (*qbss).read_index;\n            tmp_read_index := read_index + 1;\n            number_elements := (*qbss).number_elements;\n            modulo := tmp_read_index % number_elements;\n            (*qbss).read_index := modulo;\nret := 1;\n            return;\n        }\nret := 0;\n        return ;\n    }\n\n    method main() {\n        noaddr var tid1:uint64 :=0;\n      noaddr var tid2:uint64 :=0;\n        noaddr var k:ptr<uint64> := null;\n        noaddr var v:ptr<uint64> := null;\n        k := malloc(uint64);\n        v := malloc(uint64);\n      label mn_number_elements_init:\n        queue.number_elements := 4;\n      label mn_read_index_init:\n        queue.read_index := 0;\n      label mn_write_index_init:\n        queue.write_index := 0;\n        queue.element_array := calloc(BSSQueueElement, queue.number_elements);\n        if (queue.element_array != null && k != null && v != null) {\n//label BeforeEnqueueCreate:\n            //tid1 := create_thread enqueue(*k,*v);\n//label BeforeDequeueCreate:\n            //tid2 := create_thread dequeue(k,v);\n        }\n    }\n}\n"
  },
  {
    "path": "Test/qbss_benchmark/queue.patch",
    "content": "--- queue.c\t2020-02-18 15:08:59.145036241 -0500\n+++ queue.c_correct\t2020-02-18 15:08:56.175036382 -0500\n@@ -1,5 +1,6 @@\n // Dafny program queue.arm compiled into ClightTSO\n #include \"DafnyRuntime.h\"\n+#include \"liblfds711.h\"\n // namespace _12_SharedStructs \n struct BSSQueueElement;\n typedef struct BSSQueueElement BSSQueueElement;\n@@ -88,6 +89,10 @@\n   uint64 _5_tmp__write__index = 0;\n   struct BSSQueueElement* _6_element = NULL;\n   struct BSSQueueElement* _7_tmp__array = NULL;\n+\n+  LFDS711_PAL_ASSERT( qbss != NULL );\n+  LFDS711_MISC_BARRIER_LOAD;\n+\n   _3_write__index = (*(qbss)).write_index;\n   _5_tmp__write__index = (_3_write__index) + ((uint64)1);\n   _2_number__elements = (*(qbss)).number_elements;\n@@ -100,6 +105,9 @@\n     _0_e = _6_element;\n     (*(_0_e)).key = k;\n     (*(_0_e)).value = v;\n+\n+    LFDS711_MISC_BARRIER_STORE;\n+\n     _3_write__index = (*(qbss)).write_index;\n     _5_tmp__write__index = (_3_write__index) + ((uint64)1);\n     _2_number__elements = (*(qbss)).number_elements;\n@@ -132,6 +140,10 @@\n   uint64 _14_tmp__int = 0;\n   struct BSSQueueElement* _15_tmp__array = NULL;\n   struct BSSQueueElement* _16_element = NULL;\n+\n+  LFDS711_PAL_ASSERT( qbss != NULL );\n+  LFDS711_MISC_BARRIER_LOAD;\n+\n   _9_read__index = (*(qbss)).read_index;\n   _11_write__index = (*(qbss)).write_index;\n   if ((_9_read__index) != (_11_write__index)) {\n@@ -152,6 +164,9 @@\n     _10_number__elements = (*(qbss)).number_elements;\n     _12_modulo = (_13_tmp__read__index) % (_10_number__elements);\n     (*(qbss)).read_index = _12_modulo;\n+\n+    LFDS711_MISC_BARRIER_STORE;\n+\n     ret = (uint64)1;\n return ret;\n   }\n@@ -196,7 +211,3 @@\n return NULL;\n }\n // End of method _main\n-\n-int main() {\n-  _main();\n-}\n"
  },
  {
    "path": "Test/qbss_benchmark/run_benchmarks.py",
    "content": "#!/bin/env python\nimport subprocess\nimport csv\nimport numpy as np\nfrom math import sqrt\n\nimport matplotlib\nmatplotlib.use('PS')\nimport matplotlib.pyplot as plt\n\nqueue_capacity = 512\nnum_iterations = 1000\n\ndef run_benchmark(bench_name):\n    outfilename = bench_name + \"_data.csv\"\n    with open(outfilename, 'w') as fp:\n        result = subprocess.run([\"./\" + bench_name,\n                str(queue_capacity),\n                str(num_iterations)],\n            stdout=fp)\n    return outfilename\n\ndef parse_benchmark_results(csvfilename):\n    with open(csvfilename, 'r') as csvfile:\n        reader = csv.reader(csvfile, delimiter=',')\n        next(reader)\n        values = []\n        for row in reader:\n            values.append(int(row[1]))\n        return values\n\ndef mean_confidence_interval(data):\n    a = 1.0 * np.array(data)\n    n = len(a)\n\n    m = np.mean(a)\n    h = 1.96 * np.std(a)/sqrt(n)  # 95% confidence interval\n    return m, h\n\n\ndef get_benchmark_statistics(bench_name):\n    csvfilename = run_benchmark(bench_name)\n    v = parse_benchmark_results(csvfilename)\n    s = mean_confidence_interval(v)\n    return s\n\ndef plot(values):\n    plt.rc('text', usetex='True')\n    plt.rc('font', family='Serif', size=11)\n\n\n    w = 6\n    h = 4\n    d = 70\n    plt.figure(figsize=(w, h), dpi=d)\n\n    means = [values[0][0], values[1][0], values[2][0], values[3][0]]\n    xs = [\"liblfds (GCC)\", \"liblfds-modulo (GCC)\", \"Anon (GCC)\",\n          \"Anon (CompCert)\"]\n    std = [values[0][1], values[1][1], values[2][1], values[3][1]]\n\n    plt.ylabel(\"Throughput (ops/sec)\")\n    plt.xticks(rotation=10)\n    plt.grid(True, \"major\", axis=\"y\")\n    plt.bar(xs, means, color=\"#FF8000\", edgecolor=\"000000\", yerr=std,\n            capsize=5, width=0.3)\n    plt.tight_layout()\n    plt.savefig(\"qbss_performance_graph.pdf\")\n\n\ndef main():\n    subprocess.run([\"make\", \"all\"])\n    print(\"\\n\\nFinished building\\nRunning benchmarks now\")\n    values = [get_benchmark_statistics(\"benchmark_lfds\"),\n              get_benchmark_statistics(\"benchmark_lfds_modulo\"),\n              get_benchmark_statistics(\"benchmark\"),\n              (0, 0)\n              ]\n    plot(values)\n\n#values = [(1e7, 1e5), (1.5e7, 0.5e5),\n#        (1.2e7, 1e5), (1.3e7, 1.4e5)\n#        ]\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "Test/reduction/.gitignore",
    "content": "SharedStructs.dfy\nSharedStructs2.dfy\nSharedStructs3.dfy\nA.dfy\nB.dfy\nC.dfy\nD.dfy\nE.dfy\nF.dfy\nG.dfy\nH.dfy\nAB.dfy\nAB*.dfy\nCD.dfy\nEF.dfy\nGH.dfy\nAB/\nCD/\nEF/\nGH/\n"
  },
  {
    "path": "Test/reduction/test.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs {\n\n}\n\nlevel A using SharedStructs {\n    noaddr var x:int32;\n    noaddr var y:int32;\n    noaddr var z:int32 := 0;\n\n    method main()\n    {\n        x ::= 3;\nlabel lbl1:\n        y ::= 4;\nlabel lbl2:\n        z ::= 5;\n        atomic {\n            z ::= 7;\nlabel lbl3:\n            goto lbl3;\n        }\n    }\n}\n\nlevel B using SharedStructs {\n    noaddr var x:int32;\n    noaddr var y:int32;\n    noaddr var z:int32 := 0;\n\n    method main()\n    {\n        atomic {\n            x ::= 3;\n            y ::= 4;\n            z ::= 5;\n        }\n        atomic {\n            z ::= 7;\nlabel lbl3:\n            goto lbl3;\n        }\n    }\n}\n\nproof AB {\n    refinement A B\n    reduction phase1 main_1, main_2\n\n    inductive_invariant MyGlobalInvariant @\"\n      forall tid :: tid in threads ==> threads[tid].storeBuffer == []\n    \"\n}\n"
  },
  {
    "path": "Test/reduction/test2.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs2 {\n\n}\n\nlevel C using SharedStructs2 {\n    noaddr var p:ptr<int32>;\n    noaddr var v:int32;\n    noaddr var w:int32;\n    noaddr var x:int32;\n    noaddr var y:int32;\n    noaddr var z:int32;\n\n    method crasher()\n    {\n        *p ::= 0;\n    }\n\n    method main()\n    {\n        v ::= 3;\nlabel lbl1:\n        w ::= 4;\nlabel lbl2:\n        atomic {\n            x ::= 5;\n            y ::= 6;\n        }\nlabel lbl3:\n        z ::= 7;\n    }\n}\n\nlevel D using SharedStructs2 {\n    noaddr var p:ptr<int32>;\n    noaddr var v:int32;\n    noaddr var w:int32;\n    noaddr var x:int32;\n    noaddr var y:int32;\n    noaddr var z:int32;\n\n    method crasher()\n    {\n        *p ::= 0;\n    }\n\n    method main()\n    {\n        atomic {\n            v ::= 3;\n            w ::= 4;\n            x ::= 5;\n            y ::= 6;\n            z ::= 7;\n        }\n    }\n}\n\nproof CD {\n    refinement C D\n    reduction phase1 main_lbl1 phase2 main_lbl2-main_lbl3\n\n    inductive_invariant MyGlobalInvariant @\"\n      forall tid :: tid in threads ==> threads[tid].storeBuffer == []\n    \"\n}\n"
  },
  {
    "path": "Test/regions/.gitignore",
    "content": "SharedStructs1.dfy\nSharedStructs2.dfy\nSharedStructs3.dfy\nSharedStructs4.dfy\nSharedStructsPointers.dfy\nA.dfy\nB.dfy\nAB.dfy\nAB/\nC.dfy\nD.dfy\nCD.dfy\nCD/\nE.dfy\nF.dfy\nEF.dfy\nEF/\nG.dfy\nH.dfy\nGH.dfy\nGH/\nSharedStructs.dfy\nlevel0.dfy\nlevel1.dfy\nlevel01proof/\nlevel01proof.dfy\n"
  },
  {
    "path": "Test/regions/pointers.arm",
    "content": "// Test the regions invariant generation \ninclude \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructsPointers {\n}\n\nlayer level0 using SharedStructsPointers {\n    noaddr var g_p:ptr<int32> := null;\n    var x:int32;\n    var z:int32;\n\n    method store_arg_unknown_callee(arg:ptr<int32>) {\n        g_p := arg;\n    }\n\n    method test_store_arg_unknown(x:ptr<int32>) {\n        var a:int32;\n        var b:int32;\n        var p:ptr<int32> ::= null;\n\n        p := &a;\n        store_arg_unknown_callee(p);\n\nlabel stmt1:\n        b, *p ::= 1, 2;\nlabel stmt2:\n        b, *g_p ::= 3, 4;\n    }\n\n    method main() \n    {\n        noaddr var p1:ptr<int32> := null;\n        noaddr var p2:ptr<int32> := null;\n        noaddr var y:ptr<int32> := null;\n        test_store_arg_unknown(y);\n \n        p1 := &x;\n        p2 := malloc(int32);\n        *p1, *p2 ::= 1, 2;\n    }\n}\n\nlayer level1 using SharedStructsPointers {\n    noaddr var g_p:ptr<int32> := null;\n    var x:int32;\n    var z:int32;\n\n    method store_arg_unknown_callee(arg:ptr<int32>) {\n        g_p := arg;\n    }\n\n    method test_store_arg_unknown(x:ptr<int32>) {\n        var a:int32;\n        var b:int32;\n        var p:ptr<int32> ::= null;\n\n        p := &a;\n        store_arg_unknown_callee(p);\n\n        *p, b ::= 2, 1;\n        *g_p, b ::= 4, 3;\n    }\n\n    method main() \n    {\n        noaddr var p1:ptr<int32> := null;\n        noaddr var p2:ptr<int32> := null;\n        noaddr var y:ptr<int32> := null;\n        test_store_arg_unknown(y);\n \n        p1 := &x;\n        p2 := malloc(int32);\n        *p2, *p1 ::= 2, 1;\n    }\n}\n\nproof level01proof {\n    refinement level0 level1\n    weakening\n    use_regions\n\n    extra lemma_LiftNext_Update_test_store_arg_unknown_stmt1 \"lemma_RegionInvariantOnGlobalViewAlwaysImpliesRegionInvariantOnLocalView();\"\n    extra lemma_LiftNext_Update_test_store_arg_unknown_stmt2 \"lemma_RegionInvariantOnGlobalViewAlwaysImpliesRegionInvariantOnLocalView();\"\n    extra lemma_LiftAtomicPath_From_test_store_arg_unknown_stmt1_To_test_store_arg_unknown_stmt2 @\"\n      lemma_RegionInvariantOnGlobalViewAlwaysImpliesRegionInvariantOnLocalView();\n    \"\n    extra lemma_LiftAtomicPath_From_test_store_arg_unknown_stmt2_To_test_store_arg_unknown_End @\"\n      lemma_RegionInvariantOnGlobalViewAlwaysImpliesRegionInvariantOnLocalView();\n    \"\n}\n"
  },
  {
    "path": "Test/regions/test.arm",
    "content": "// Test the regions invariant generation\n\ninclude \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs {\n\n}\n\n// Want to show the following invariants:\n// a.p == null or region_map[a.p] == Region_X\n// b.p == null or region_map[b.p] == Region_Y\n//\n// Initialize region_map[AddrOf'x] == Region_X\n// Initialize region_map[AddrOf'y] == Region_X\n//\nlayer A using SharedStructs {\n    var x:int32;\n    var y:int32;\n\n    method a(p: ptr<int32>) \n    {\n        *p := 0;\n    }\n\n    method b(p: ptr<int32>) \n    {\n        *p := 1;\n    }\n\n    method main()\n    {\n        noaddr var p1:ptr<int32> := null;\n        noaddr var p2:ptr<int32> := null;\n        p1 := &x;\n        p2 := &y;\n        \n        create_thread a(p1);\n        create_thread b(p2);\n    }\n}\n\nlayer B using SharedStructs {\n    var x:int32;\n    var y:int32;\n\n    method a(p: ptr<int32>) \n    {\n        *p := 0;\n    }\n\n    method b(p: ptr<int32>) \n    {\n        *p := 1;\n    }\n    \n    method main()\n    {\n        noaddr var p1:ptr<int32> := null;\n        noaddr var p2:ptr<int32> := null;\n        p1 := &x;\n        p2 := &y;\n\n        create_thread a(p1);\n        create_thread b(p2);\n    }\n}\n\nproof AB {\n    refinement A B\n    weakening\n    use_regions\n}\n"
  },
  {
    "path": "Test/regions/test2.arm",
    "content": "// Test the regions invariant generation\n\ninclude \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs2 {\n\n}\n\nlayer C using SharedStructs2 {\n    var x:int32;\n    var y:int32;\n\n    method main()\n    {\n        noaddr var p1:ptr<int32> := null;\n        noaddr var p2:ptr<int32> := null;\n        p1 := &x;\n        p2 := malloc(int32);\n        *p2, *p1 ::= 2, 1;\n    }\n}\n\nlayer D using SharedStructs2 {\n    var x:int32;\n    var y:int32;\n\n    method main()\n    {\n        noaddr var p1:ptr<int32> := null;\n        noaddr var p2:ptr<int32> := null;\n        p1 := &x;\n        p2 := malloc(int32);\n        *p1, *p2 ::= 1, 2;\n    }\n}\n\nproof CD {\n    refinement C D\n    weakening\n    use_regions\n}\n"
  },
  {
    "path": "Test/regions/test3.arm",
    "content": "// Test the regions invariant generation\n\ninclude \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs3 {\n    struct S1 {\n        var a:int32;\n        var b:int32;\n    }\n}\n\nlayer E using SharedStructs3 {\n    var x : S1;\n    var y : S1;\n\n    method main()\n    {\n        noaddr var p:ptr<int32> := null;\n        x.a, y.a ::= 1, 2;\n        x.a, x.b ::= 3, 4;\n    }\n}\n\nlayer F using SharedStructs3 {\n    var x : S1;\n    var y : S1;\n\n    method main()\n    {\n        noaddr var p:ptr<int32> := null;\n        y.a, x.a ::= 2, 1;\n        x.b, x.a ::= 4, 3;\n    }\n}\n\nproof EF {\n    refinement E F\n    weakening\n    use_regions\n}\n"
  },
  {
    "path": "Test/regions/test4.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs4 {\n}\n\nlayer G using SharedStructs4 {\n           var g_x:int32;\n    noaddr var g_y:int32;\n\n           var g_p:ptr<int32> := null;\n    noaddr var g_q:ptr<int32> := null;\n\n    noaddr var p_p:ptr<ptr<int32>> := null;\n\n    method a()\n    {\n               var n: int32;\n        noaddr var m: int32;\n\n               var s: ptr<int32> ::= null;\n        noaddr var t: ptr<int32> := null;\n\n        n := 1;\n        s := &n;\n        t := &n;\n    }\n\n    method main()\n    {\n        var u:int32;\n        u := 2;\n\n        g_p := &g_x;\n        g_q := &g_x;\n\n        p_p := &g_p;\n        create_thread a();\n        a();\n    }\n}\n\nlayer H using SharedStructs4 {\n               var g_x:int32;\n    noaddr var g_y:int32;\n\n           var g_p:ptr<int32> := null;\n    noaddr var g_q:ptr<int32> := null;\n\n    noaddr var p_p:ptr<ptr<int32>> := null;\n\n    method a()\n    {\n               var n: int32;\n        noaddr var m: int32;\n\n               var s: ptr<int32> ::= null;\n        noaddr var t: ptr<int32> := null;\n\n        n := 1;\n        s := &n;\n        t := &n;\n    }\n\n    method main()\n    {\n        var u:int32;\n        u := 2;\n\n        g_p := &g_x;\n        g_q := &g_x;\n\n        p_p := &g_p;\n        create_thread a();\n        a();\n    }\n\n}\n\nproof GH {\n    refinement G H\n    weakening\n    use_regions\n}\n"
  },
  {
    "path": "Test/starweakening/.gitignore",
    "content": "SharedStructs.dfy\nA.dfy\nB.dfy\nAB.dfy\nSharedStructs2.dfy\nC.dfy\nD.dfy\nCD.dfy\nSharedStructs3.dfy\nE.dfy\nF.dfy\nEF.dfy\nSharedStructs4.dfy\nG.dfy\nH.dfy\nGH.dfy\nAB/\nCD/\nEF/\nGH/\n"
  },
  {
    "path": "Test/starweakening/test.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs {\n\n}\n\nlevel A using SharedStructs {\n    noaddr var x:int32;\n   \n    method main()\n    {\n        x, x ::= 1, 2;\n    }\n}\n\nlevel B using SharedStructs {\n    noaddr var x:int32;\n   \n    method main()\n    {\n               somehow modifies x;\n       }\n}\n\nproof AB {\n       refinement A B\n       starweakening\n}\n"
  },
  {
    "path": "Test/starweakening/test2.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs2 {\n\n}\n\nlevel C using SharedStructs2 {\n    noaddr var y:int32;\n    \n    method main()\n    {\nlabel lbl1:   y ::= y + 1;\n    }\n}\n\nlevel D using SharedStructs2 {\n    noaddr var y:int32;\n    \n    method main()\n    {\n        somehow modifies y\n            ensures y == old(y) + 1;\n    }\n}\n\nproof CD {\n    refinement C D\n    starweakening statements main_lbl1 variables y\n}\n"
  },
  {
    "path": "Test/starweakening/test3.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs3 {\n\n}\n\nlevel E using SharedStructs3 {\n    noaddr var x:int32;\n    noaddr var y:int32;\n    \n    method main()\n    {\n        x, y := 0, *;\n    }\n}\n\nlevel F using SharedStructs3 {\n    noaddr var x:int32;\n    noaddr var y:int32;\n    \n    method main()\n    {\n        x, y := *, *;\n    }\n}\n\nproof EF {\n    refinement E F\n    starweakening\n}\n"
  },
  {
    "path": "Test/starweakening/test4.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs4 {\n\n}\n\nlevel G using SharedStructs4 {\n    noaddr var x:int32;\n    noaddr var y:int32;\n    \n    method main()\n    {\n        x, y ::= 0, *;\n    }\n}\n\nlevel H using SharedStructs4 {\n    noaddr var x:int32;\n    noaddr var y:int32;\n    \n    method main()\n    {\n        x, y ::= *, *;\n    }\n}\n\nproof GH {\n    refinement G H\n    starweakening\n}\n"
  },
  {
    "path": "Test/tsoelim/.gitignore",
    "content": "SharedStructs.dfy\nSharedStructs2.dfy\nSharedStructs3.dfy\nSharedStructs4.dfy\nA.dfy\nB.dfy\nC.dfy\nD.dfy\nE.dfy\nF.dfy\nG.dfy\nH.dfy\nAB.dfy\nCD.dfy\nEF.dfy\nGH.dfy\nAB/\nCD/\nEF/\nGH/\n"
  },
  {
    "path": "Test/tsoelim/test.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs {\n\n  datatype OptionalThread = OptionalThreadSome(tid:uint64) | OptionalThreadNone\n\n  struct S1 {\n    var e:uint32[10];\n    var f:uint32[10];\n  }\n\n  struct S2 {\n    var c:S1[20];\n    var d:S1[20];\n  }\n\n  struct S3 {\n    var a:S2[30];\n    var b:S2[30];\n  }\n\n}\n\nlevel A using SharedStructs {\n\n  ghost var lock_holder:seq<OptionalThread>\n  var w:int32;\n  noaddr var x:S3[10];\n  noaddr var y:int32 := 0;\n  noaddr var z:int32 := 0;\n\n  method Worker(i:int)\n  {\n    assume 0 <= i < |lock_holder| && lock_holder[i].OptionalThreadNone?;\n    somehow modifies lock_holder ensures lock_holder == old(lock_holder)[i := OptionalThreadSome($me)];\n\n    label lb1:\n    assume 0 <= i < |lock_holder| && lock_holder[i] == OptionalThreadSome($me);\n    x[4].a[7].c[i].e[3] := x[4].a[7].c[i].e[3] + 1;\n\n    label lb2:\n    assume 0 <= i < |lock_holder| && lock_holder[i] == OptionalThreadSome($me);\n    y := y + 1;\n\n    label lb3:\n    assume 0 <= i < |lock_holder| && lock_holder[i] == OptionalThreadSome($me);\n    z ::= z + 1;\n\n    label lb4:\n    assume 0 <= i < |lock_holder| && lock_holder[i] == OptionalThreadSome($me) && $sb_empty;\n    somehow modifies lock_holder ensures lock_holder == old(lock_holder)[i := OptionalThreadNone];\n\n    w := w + 1;\n\n    assert true;\n  }\n\n  method main()\n  {\n    create_thread Worker(1);\n    create_thread Worker(2);\n    atomic {\n      w := w + 1;\n      while (*) {\n        y ::= y + 1;\n        z := z + 1;\n      }\n    }\n  }\n\n}\n\nlevel B using SharedStructs {\n\n  ghost var lock_holder:seq<OptionalThread>\n  var w:int32;\n  noaddr var x:S3[10];\n  noaddr var y:int32 := 0;\n  noaddr var z:int32 := 0;\n\n  method Worker(i:int)\n  {\n    assume 0 <= i < |lock_holder| && lock_holder[i].OptionalThreadNone?;\n    somehow modifies lock_holder ensures lock_holder == old(lock_holder)[i := OptionalThreadSome($me)];\n\n    assume 0 <= i < |lock_holder| && lock_holder[i] == OptionalThreadSome($me);\n    x[4].a[7].c[i].e[3] ::= x[4].a[7].c[i].e[3] + 1;\n\n    assume 0 <= i < |lock_holder| && lock_holder[i] == OptionalThreadSome($me);\n    y := y + 1;\n\n    assume 0 <= i < |lock_holder| && lock_holder[i] == OptionalThreadSome($me);\n    z ::= z + 1;\n\n    assume 0 <= i < |lock_holder| && lock_holder[i] == OptionalThreadSome($me) && $sb_empty;\n    somehow modifies lock_holder ensures lock_holder == old(lock_holder)[i := OptionalThreadNone];\n\n    w := w + 1;\n\n    assert true;\n  }\n\n  method main()\n  {\n    create_thread Worker(1);\n    create_thread Worker(2);\n    atomic {\n      w := w + 1;\n      while (*) {\n        y ::= y + 1;\n        z := z + 1;\n      }\n    }\n  }\n\n}\n\nproof AB\n{\n  refinement A B\n\n  tso_elim x.a.c.e @\"\n    && tid in threads\n    && (var pc := threads[tid].pc;\n       || pc.Armada_PC_Worker_lb1?\n       || pc.Armada_PC_Worker_lb2?\n       || pc.Armada_PC_Worker_lb3?\n       || pc.Armada_PC_Worker_lb4?)\n    && threads[tid].top.Armada_StackFrame_Worker?\n    && idx0 == 4\n    && idx1 == 7\n    && idx2 == threads[tid].top.Worker.i\n    && idx3 == 3\n    && 0 <= idx2 < |ghosts.lock_holder|\n    && ghosts.lock_holder[idx2] == OptionalThreadSome(tid)\n  \"\n}\n"
  },
  {
    "path": "Test/tsoelim/test2.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs2 {\n\n  datatype OptionalThread = OptionalThreadSome(tid:uint64) | OptionalThreadNone\n\n  struct S1 {\n    var e:uint32[10];\n    var f:uint32[10];\n  }\n\n  struct S2 {\n    var c:S1[20];\n    var d:S1[20];\n  }\n\n  struct S3 {\n    var a:S2[30];\n    var b:S2[30];\n  }\n\n}\n\nlevel C using SharedStructs2 {\n\n  ghost var lock_holder:OptionalThread := OptionalThreadNone\n  ghost var save_lock_holder:OptionalThread;\n  noaddr var x:int32 := 0;\n  noaddr var y:int32 := 0;\n  noaddr var z:S3[10];\n\n  method Worker()\n  {\n    label acq:\n    assume lock_holder.OptionalThreadNone?;\n    somehow modifies lock_holder ensures lock_holder == OptionalThreadSome($me);\n    x := x + 1;\n    atomic {\n      save_lock_holder := lock_holder;\n      lock_holder := OptionalThreadNone;\n      lock_holder := save_lock_holder;\n    }\n    y := y + 1;\n    label rel:\n    assume lock_holder == OptionalThreadSome($me) && $sb_empty;\n    somehow modifies lock_holder ensures lock_holder == OptionalThreadNone();\n  }\n\n  method main()\n  {\n    create_thread Worker();\n    create_thread Worker();\n    z[1].a[2].c[3].e[4] := z[1].a[2].c[3].e[4] + 1;\n  }\n\n}\n\nlevel D using SharedStructs2 {\n\n  ghost var lock_holder:OptionalThread := OptionalThreadNone\n  ghost var save_lock_holder:OptionalThread;\n  noaddr var x:int32 := 0;\n  noaddr var y:int32 := 0;\n  noaddr var z:S3[10];\n\n  method Worker()\n  {\n    assume lock_holder.OptionalThreadNone?;\n    somehow modifies lock_holder ensures lock_holder == OptionalThreadSome($me);\n    x ::= x + 1;\n    atomic {\n      save_lock_holder := lock_holder;\n      lock_holder := OptionalThreadNone;\n      lock_holder := save_lock_holder;\n    }\n    y := y + 1;\n    assume lock_holder == OptionalThreadSome($me) && $sb_empty;\n    somehow modifies lock_holder ensures lock_holder == OptionalThreadNone();\n  }\n\n  method main()\n  {\n    create_thread Worker();\n    create_thread Worker();\n    z[1].a[2].c[3].e[4] := z[1].a[2].c[3].e[4] + 1;\n  }\n\n}\n\nproof CD\n{\n  refinement C D\n\n  inductive_invariant LockHolderInv @\"\n    forall tid :: \n      ghosts.lock_holder == OptionalThreadSome(tid) <==>\n      (&& tid in threads\n       && var pc := threads[tid].pc;\n       && var ins := PCToInstructionCount_L(pc);\n       && PCToMethod_L(pc).LMethodName_Worker?\n       && ins > PCToInstructionCount_L(L.Armada_PC_Worker_acq)\n       && ins <= PCToInstructionCount_L(L.Armada_PC_Worker_rel))\n  \"\n\n  tso_elim x \"ghosts.lock_holder == OptionalThreadSome(tid)\"\n}\n"
  },
  {
    "path": "Test/tsoelim/test3.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs3 {\n\n  datatype OptionalThread = OptionalThreadSome(tid:uint64) | OptionalThreadNone\n\n  struct S1 {\n    var e:uint32[10];\n    var f:uint32[10];\n  }\n\n  struct S2 {\n    var c:S1[20];\n    var d:S1[20];\n  }\n\n  struct S3 {\n    var a:S2[30];\n    var b:S2[30];\n  }\n\n}\n\nlevel E using SharedStructs3 {\n\n  ghost var lock_holder:seq<OptionalThread>\n  noaddr var x:int32[10];\n  noaddr var y:int32 := 0;\n  noaddr var z:S3[10];\n\n  method Worker(i:int)\n  {\n    assume 0 <= i < |lock_holder| && lock_holder[i].OptionalThreadNone?;\n    somehow modifies lock_holder ensures lock_holder == old(lock_holder)[i := OptionalThreadSome($me)];\n\n    label lb1:\n    assume 0 <= i < |lock_holder| && lock_holder[i] == OptionalThreadSome($me);\n    x[i] := x[i] + 1;\n\n    label lb2:\n    assume 0 <= i < |lock_holder| && lock_holder[i] == OptionalThreadSome($me);\n    y := y + 1;\n\n    label lb3:\n    assume 0 <= i < |lock_holder| && lock_holder[i] == OptionalThreadSome($me) && $sb_empty;\n    somehow modifies lock_holder ensures lock_holder == old(lock_holder)[i := OptionalThreadNone];\n\n    assert true;\n  }\n\n  method main()\n  {\n    create_thread Worker(1);\n    create_thread Worker(2);\n    z[1].a[2].c[3].e[4] := z[1].a[2].c[3].e[4] + 1;\n  }\n\n}\n\nlevel F using SharedStructs3 {\n\n  ghost var lock_holder:seq<OptionalThread>\n  noaddr var x:int32[10];\n  noaddr var y:int32 := 0;\n  noaddr var z:S3[10];\n\n  method Worker(i:int)\n  {\n    assume 0 <= i < |lock_holder| && lock_holder[i].OptionalThreadNone?;\n    somehow modifies lock_holder ensures lock_holder == old(lock_holder)[i := OptionalThreadSome($me)];\n\n    assume 0 <= i < |lock_holder| && lock_holder[i] == OptionalThreadSome($me);\n    x[i] ::= x[i] + 1;\n\n    assume 0 <= i < |lock_holder| && lock_holder[i] == OptionalThreadSome($me);\n    y := y + 1;\n\n    assume 0 <= i < |lock_holder| && lock_holder[i] == OptionalThreadSome($me) && $sb_empty;\n    somehow modifies lock_holder ensures lock_holder == old(lock_holder)[i := OptionalThreadNone];\n\n    assert true;\n  }\n\n  method main()\n  {\n    create_thread Worker(1);\n    create_thread Worker(2);\n    z[1].a[2].c[3].e[4] := z[1].a[2].c[3].e[4] + 1;\n  }\n\n}\n\nproof EF\n{\n  refinement E F\n\n  tso_elim x @\"\n    && tid in threads\n    && (var pc := threads[tid].pc;\n       || pc.Armada_PC_Worker_lb1?\n       || pc.Armada_PC_Worker_lb2?\n       || pc.Armada_PC_Worker_lb3?)\n    && threads[tid].top.Armada_StackFrame_Worker?\n    && idx0 == threads[tid].top.Worker.i\n    && 0 <= idx0 < |ghosts.lock_holder|\n    && ghosts.lock_holder[idx0] == OptionalThreadSome(tid)\n  \"\n}\n"
  },
  {
    "path": "Test/tsoelim/test4.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs4 {\n\n  datatype OptionalThread = OptionalThreadSome(tid:uint64) | OptionalThreadNone\n\n}\n\nlevel G using SharedStructs4 {\n\n  ghost var lock_holder:OptionalThread\n  noaddr var x:int32 := 0;\n  noaddr var y:int32 := 0;\n\n  method Worker()\n  {\n    assume lock_holder.OptionalThreadNone?;\n    somehow modifies lock_holder ensures lock_holder == OptionalThreadSome($me);\n\n    explicit_yield {\n\n      label lb1:\n      assume lock_holder == OptionalThreadSome($me);\n      x := x + 1;\n\n      label lb2:\n      assume lock_holder == OptionalThreadSome($me);\n      y := y + 1;\n\n    }\n\n    label lb3:\n    assume lock_holder == OptionalThreadSome($me) && $sb_empty;\n    somehow modifies lock_holder ensures lock_holder == OptionalThreadNone();\n\n    assert true;\n  }\n\n  method main()\n  {\n    create_thread Worker();\n    create_thread Worker();\n  }\n\n}\n\nlevel H using SharedStructs4 {\n\n  ghost var lock_holder:OptionalThread\n  noaddr var x:int32 := 0;\n  noaddr var y:int32 := 0;\n\n  method Worker()\n  {\n    assume lock_holder.OptionalThreadNone?;\n    somehow modifies lock_holder ensures lock_holder == OptionalThreadSome($me);\n\n    explicit_yield {\n\n      assume lock_holder == OptionalThreadSome($me);\n      x ::= x + 1;\n\n      assume lock_holder == OptionalThreadSome($me);\n      y := y + 1;\n\n    }\n\n    assume lock_holder == OptionalThreadSome($me) && $sb_empty;\n    somehow modifies lock_holder ensures lock_holder == OptionalThreadNone();\n\n    assert true;\n  }\n\n  method main()\n  {\n    create_thread Worker();\n    create_thread Worker();\n  }\n\n}\n\nproof GH\n{\n  refinement G H\n\n  tso_elim x @\"\n    && tid in threads\n    && (var pc := threads[tid].pc;\n       || pc.Armada_PC_Worker_lb1?\n       || pc.Armada_PC_Worker_lb2?\n       || pc.Armada_PC_Worker_lb3?)\n    && ghosts.lock_holder == OptionalThreadSome(tid)\n  \"\n}\n"
  },
  {
    "path": "Test/varhiding/.gitignore",
    "content": "A.dfy\nB.dfy\nAB.dfy\nSharedStructs.dfy\nC.dfy\nD.dfy\nCD.dfy\nSharedStructs2.dfy\nE.dfy\nF.dfy\nEF.dfy\nSharedStructs3.dfy\nG.dfy\nH.dfy\nGH.dfy\nSharedStructs4.dfy\nI.dfy\nJ.dfy\nIJ.dfy\nSharedStructs5.dfy\nAB/\nCD/\nEF/\nGH/\nIJ/\n"
  },
  {
    "path": "Test/varhiding/VarHidingManualProof.i.dfy",
    "content": "include \"A.dfy\"\ninclude \"B.dfy\"\ninclude \"../../Armada/strategies/VarHiding/VarHiding.i.dfy\"\ninclude \"../../Armada/strategies/refinement/AnnotatedBehavior.i.dfy\"\ninclude \"../../Armada/util/option.s.dfy\"\ninclude \"../../Armada/util/collections/seqs.s.dfy\"\ninclude \"../../Armada/util/collections/seqs.i.dfy\"\ninclude \"../../Armada/util/collections/sets.i.dfy\"\ninclude \"../../Armada/util/collections/maps.i.dfy\"\n\nmodule AB {\n    import A\n    import B\n    import opened ArmadaCommonDefinitions\n    import opened InvariantsModule\n    import opened VarHidingSpecModule\n    import opened VarHidingModule\n    import opened util_option_s\n    import opened util_collections_seqs_s\n    import opened util_collections_seqs_i\n    import opened util_collections_sets_i\n    import opened util_collections_maps_i\n    import opened GeneralRefinementModule\n    import opened AnnotatedBehaviorModule\n\n    function ConvertPC_AB(pc:A.Armada_PC) : B.Armada_PC\n    {\n        match pc\n            case Armada_PC_None => B.Armada_PC_None\n            case Armada_PC_main'0 => B.Armada_PC_main'0\n            case Armada_PC_main'1 => B.Armada_PC_main'1\n            case Armada_PC_main'2 => B.Armada_PC_main'2\n            case Armada_PC_main'3 => B.Armada_PC_main'2\n    }\n\n    function ConvertStackFrame_AB(frame:A.Armada_StackFrame) : B.Armada_StackFrame\n    {\n        match frame\n            case Armada_StackFrame_main() => B.Armada_StackFrame_main()\n    }\n\n    function ConvertFieldType_AB(fieldType:A.Armada_FieldType) : (result:B.Armada_FieldType)\n        ensures ConvertFieldType_BA(result) == fieldType\n    {\n        match fieldType\n            case Armada_FieldTypeNone => B.Armada_FieldTypeNone\n    }\n\n    function ConvertFieldType_BA(fieldType:B.Armada_FieldType) : A.Armada_FieldType\n    {\n        match fieldType\n            case Armada_FieldTypeNone => A.Armada_FieldTypeNone\n    }\n\n    lemma lemma_ConvertFieldTypeIsBijective()\n        ensures Inverses(ConvertFieldType_AB, ConvertFieldType_BA)\n    {\n        forall a:A.Armada_FieldType\n            ensures ConvertFieldType_BA(ConvertFieldType_AB(a)) == a\n        {\n            match a {\n                case Armada_FieldTypeNone => assert ConvertFieldType_BA(ConvertFieldType_AB(a)) == a;\n            }\n        }\n\n        forall b:B.Armada_FieldType\n            ensures ConvertFieldType_AB(ConvertFieldType_BA(b)) == b\n        {\n            match b {\n                case Armada_FieldTypeNone => assert ConvertFieldType_AB(ConvertFieldType_BA(b)) == b;\n            }\n        }\n    }\n\n    function ConvertStructType_AB(structType:A.Armada_StructType) : B.Armada_StructType\n    {\n        match structType\n            case Armada_StructTypeNone => B.Armada_StructTypeNone\n    }\n\n    function ConvertObjectType_AB(objectType:A.Armada_ObjectType) : B.Armada_ObjectType\n    {\n        match objectType\n            case Armada_ObjectType_primitive(pty) => Armada_ObjectType_primitive(pty)\n            case Armada_ObjectType_struct(s) => Armada_ObjectType_struct(ConvertStructType_AB(s))\n            case Armada_ObjectType_array(subtype, sz) => Armada_ObjectType_array(ConvertObjectType_AB(subtype), sz)\n    }\n\n    function ConvertField_AB(field:A.Armada_Field) : (result:B.Armada_Field)\n    {\n        match field\n            case Armada_FieldNone => Armada_FieldNone\n            case Armada_FieldArrayIndex(i) => Armada_FieldArrayIndex(i)\n            case Armada_FieldStruct(f) => Armada_FieldStruct(ConvertFieldType_AB(f))\n    }\n\n    function ConvertField_BA(field:B.Armada_Field) : A.Armada_Field\n    {\n        match field\n            case Armada_FieldNone => Armada_FieldNone\n            case Armada_FieldArrayIndex(i) => Armada_FieldArrayIndex(i)\n            case Armada_FieldStruct(f) => Armada_FieldStruct(ConvertFieldType_BA(f))\n    }\n\n    function ConvertFieldSeq_AB(fields:seq<A.Armada_Field>) : seq<B.Armada_Field>\n    {\n        MapSeqToSeq(fields, ConvertField_AB)\n    }\n\n    lemma lemma_ConvertFieldIsBijective()\n        ensures Inverses(ConvertField_AB, ConvertField_BA)\n    {\n        lemma_ConvertFieldTypeIsBijective();\n    }\n\n    function ConvertChildren_AB(children:map<A.Armada_Field, Armada_Pointer>) : map<B.Armada_Field, Armada_Pointer>\n    {\n        lemma_ConvertFieldIsBijective();\n        Map2MapToMap(children, ConvertField_AB, ConvertField_BA, p=>p)\n    }\n\n    function ConvertNode_AB(node:A.Armada_Node) : B.Armada_Node\n    {\n        Armada_Node(node.parent, ConvertField_AB(node.field_of_parent), ConvertChildren_AB(node.children),\n                    ConvertObjectType_AB(node.ty), node.level)\n    }\n\n    function ConvertTree_AB(tree:map<Armada_Pointer, A.Armada_Node>) : map<Armada_Pointer, B.Armada_Node>\n    {\n        MapMapToMap(tree, ConvertNode_AB)\n    }\n\n    function ConvertHeap_AB(heap:A.Armada_Heap) : B.Armada_Heap\n    {\n        Armada_Heap(ConvertTree_AB(heap.tree), heap.valid, heap.freed, heap.values)\n    }\n\n    function ConvertRegions_AB(regions:A.Armada_Regions) : B.Armada_Regions\n    {\n        B.Armada_Regions(ConvertHeap_AB(regions.default))\n    }\n\n    function ConvertRegionID_AB(regionID:A.Armada_RegionID) : B.Armada_RegionID\n    {\n        match regionID\n            case Armada_RegionID_default => B.Armada_RegionID_default\n    }\n\n    function ConvertGlobals_AB(globals:A.Armada_Globals) : B.Armada_Globals\n    {\n        B.Armada_Globals(globals.x, globals.y)\n    }\n\n    function ConvertSnapshot_AB(snap:A.Armada_Snapshot) : B.Armada_Snapshot\n    {\n        B.Armada_Snapshot(ConvertStackFrame_AB(snap.top), ConvertRegions_AB(snap.regions), ConvertGlobals_AB(snap.globals))\n    }\n\n    function ConvertExtendedFrame_AB(eframe:A.Armada_ExtendedFrame) : B.Armada_ExtendedFrame\n    {\n        B.Armada_ExtendedFrame(ConvertPC_AB(eframe.return_pc), ConvertStackFrame_AB(eframe.frame), ConvertSnapshot_AB(eframe.snap))\n    }\n\n    function ConvertStack_AB(stack:seq<A.Armada_ExtendedFrame>) : seq<B.Armada_ExtendedFrame>\n    {\n        MapSeqToSeq(stack, ConvertExtendedFrame_AB)\n    }\n\n    predicate CanConvertStoreBufferEntry_AB(entry:A.Armada_StoreBufferEntry)\n    {\n        entry.Armada_StoreBufferEntry_Unaddressable? ==> CanConvertGlobalStaticVar_AB(entry.v)\n    }\n\n    function ConvertStoreBufferEntry_AB(entry:A.Armada_StoreBufferEntry) : B.Armada_StoreBufferEntry\n        requires CanConvertStoreBufferEntry_AB(entry)\n    {\n        match entry\n            case Armada_StoreBufferEntry_Unaddressable(v, fields, value) =>\n                B.Armada_StoreBufferEntry_Unaddressable(ConvertGlobalStaticVar_AB(v), ConvertFieldSeq_AB(fields), value)\n            case Armada_StoreBufferEntry_Addressable(p, region, value) =>\n                B.Armada_StoreBufferEntry_Addressable(p, ConvertRegionID_AB(region), value)\n    }\n\n    function ConvertStoreBuffer_AB(entries:seq<A.Armada_StoreBufferEntry>) : seq<B.Armada_StoreBufferEntry>\n    {\n        FilterMapSeqToSeq(entries, e => if CanConvertStoreBufferEntry_AB(e) then Some(ConvertStoreBufferEntry_AB(e)) else None)\n    }\n\n    function ConvertThread_AB(t:A.Armada_Thread) : B.Armada_Thread\n    {\n        B.Armada_Thread(ConvertPC_AB(t.pc), ConvertStackFrame_AB(t.top), ConvertSnapshot_AB(t.snap), ConvertStack_AB(t.stack),\n                        ConvertStoreBuffer_AB(t.storeBuffer))\n    }\n\n    function ConvertThreads_AB(threads:map<Armada_ThreadHandle, A.Armada_Thread>) : map<Armada_ThreadHandle, B.Armada_Thread>\n    {\n        MapMapToMap(threads, ConvertThread_AB)\n    }\n\n    predicate CanConvertGlobalStaticVar_AB(v:A.Armada_GlobalStaticVar)\n    {\n        !v.Armada_GlobalStaticVar_z?\n    }\n\n    function ConvertGlobalStaticVar_AB(v:A.Armada_GlobalStaticVar) : B.Armada_GlobalStaticVar\n        requires CanConvertGlobalStaticVar_AB(v)\n    {\n        match v\n            case Armada_GlobalStaticVarNone => B.Armada_GlobalStaticVarNone\n            case Armada_GlobalStaticVar_x => B.Armada_GlobalStaticVar_x\n            case Armada_GlobalStaticVar_y => B.Armada_GlobalStaticVar_y\n    }\n\n    function ConvertTS_AB(s:A.Armada_TotalState) : B.Armada_TotalState\n    {\n        B.Armada_TotalState(s.ok, s.log, ConvertThreads_AB(s.threads), ConvertRegions_AB(s.regions), ConvertGlobals_AB(s.globals))\n    }\n\n    function ConvertConfig_AB(config:A.Armada_Config) : B.Armada_Config\n    {\n        B.Armada_Config(config.tid_init)\n    }\n\n    function ConvertTraceEntry_AB(entry:A.Armada_TraceEntry) : B.Armada_TraceEntry\n    {\n        match entry\n            case Armada_TraceEntry_Armada_PC_main'0(tid) => B.Armada_TraceEntry_Armada_PC_main'0(tid)\n            case Armada_TraceEntry_Armada_PC_main'1(tid) => B.Armada_TraceEntry_Armada_PC_main'1(tid)\n            case Armada_TraceEntry_Armada_PC_main'2(tid) =>\n               // The mapping of this step is arbitrary since it's going to be turned into a stutter step.\n               // So we arbitrarily map it to the start step of the program.\n               B.Armada_TraceEntry_Armada_PC_main'0(tid)\n            case Armada_TraceEntry_Terminate'main(tid) => B.Armada_TraceEntry_Terminate'main(tid)\n            case Armada_TraceEntry_Tau(tid) => B.Armada_TraceEntry_Tau(tid)\n    }\n\n    type LState = A.Armada_TotalState\n    type HState = B.Armada_TotalState\n    type LStep = A.Armada_TraceEntry\n    type HStep = B.Armada_TraceEntry\n    type LSpec = AnnotatedBehaviorSpec<LState, LStep>\n    type HSpec = AnnotatedBehaviorSpec<HState, HStep>\n    type LConfig = A.Armada_Config\n    type HConfig = B.Armada_Config\n    type VHRequest = VarHidingRequest<LState, HState, LStep, HStep>\n\n    function GetVarHidingInvariant() : iset<LState>\n    {\n        iset s | true\n    }\n\n    function GetLSpec() : LSpec\n    {\n        AnnotatedBehaviorSpec(iset s, config | A.Armada_Init(s, config) :: s,\n                              iset s, s', entry | A.Armada_Next(s, s', entry) :: ActionTuple(s, s', entry))\n    }\n\n    function GetHSpec() : HSpec\n    {\n        AnnotatedBehaviorSpec(iset s, config | B.Armada_Init(s, config) :: s,\n                              iset s, s', entry | B.Armada_Next(s, s', entry) :: ActionTuple(s, s', entry))\n    }\n\n    predicate ABStateRefinement(ls:LState, hs:HState)\n    {\n        && (ls.ok ==> hs.ok)\n        && ls.log <= hs.log\n    }\n\n    function GetABRefinementRelation() : RefinementRelation<LState, HState>\n    {\n        iset p:RefinementPair<LState, HState> | ABStateRefinement(p.low, p.high)\n    }\n\n    function GetVarHidingRequest() : VHRequest\n    {\n        VarHidingRequest(GetLSpec(), GetHSpec(), GetABRefinementRelation(), GetVarHidingInvariant(), ConvertTS_AB, ConvertTraceEntry_AB)\n    }\n\n    lemma lemma_IsInvariantOfSpec(vr:VHRequest)\n        requires vr == GetVarHidingRequest()\n        ensures  IsInvariantOfSpec(vr.inv, vr.lspec)\n    {\n    }\n\n    lemma lemma_HidingSatisfiesRelation(vr:VHRequest)\n        requires vr == GetVarHidingRequest()\n        ensures  HidingSatisfiesRelation(vr)\n    {\n    }\n\n    lemma lemma_HidingPreservesInit_HeapInvariant(vr:VHRequest, ls:LState, hs:HState, lconfig:LConfig, hconfig:HConfig)\n        requires vr == GetVarHidingRequest()\n        requires A.Armada_Init(ls, lconfig)\n        requires hs == vr.hider(ls)\n        requires hconfig == ConvertConfig_AB(lconfig)\n        ensures  B.Armada_HeapInvariant(hs.regions.default)\n    {\n        var ltree := ls.regions.default.tree;\n        var htree := hs.regions.default.tree;\n\n        forall p, f {:trigger Armada_TriggerPointer(p), Armada_TriggerField(f)} |\n            Armada_TriggerPointer(p) && Armada_TriggerField(f) && p in htree && f in htree[p].children\n            ensures var q := htree[p].children[f]; q in htree && htree[q].parent == p && htree[q].field_of_parent == f\n        {\n            assert Armada_TriggerField(ConvertField_BA(f));\n        }\n        forall p, f {:trigger Armada_TriggerPointer(p), Armada_TriggerField(f)} |\n            Armada_TriggerPointer(p) && Armada_TriggerField(f) && p in htree && htree[p].ty.Armada_ObjectType_array? && f in htree[p].children\n            ensures f.Armada_FieldArrayIndex? && 0 <= f.i < htree[p].ty.sz\n        {\n            assert Armada_TriggerField(ConvertField_BA(f));\n        }\n        forall p, f {:trigger Armada_TriggerPointer(p), Armada_TriggerField(f)} |\n            Armada_TriggerPointer(p) && Armada_TriggerField(f) && p in htree && htree[p].ty.Armada_ObjectType_primitive?\n            ensures f !in htree[p].children\n        {\n            assert Armada_TriggerField(ConvertField_BA(f));\n        }\n        forall q {:trigger Armada_TriggerPointer(q)} |\n           Armada_TriggerPointer(q) && q in htree && !htree[q].field_of_parent.Armada_FieldNone?\n           ensures var p, f := htree[q].parent, htree[q].field_of_parent; p in htree && f in htree[p].children && htree[p].children[f] == q\n       {\n           assert Armada_TriggerPointer(q) && q in ltree && !ltree[q].field_of_parent.Armada_FieldNone?;\n           var p, f := ltree[q].parent, ltree[q].field_of_parent;\n           assert p in ltree && f in ltree[p].children && ltree[p].children[f] == q;\n       }\n    }\n\n    lemma lemma_HidingPreservesInit(vr:VHRequest)\n        requires vr == GetVarHidingRequest()\n        ensures  HidingPreservesInit(vr)\n    {\n        forall ls | ls in vr.lspec.init\n            ensures vr.hider(ls) in vr.hspec.init\n        {\n            var lconfig :| A.Armada_Init(ls, lconfig);\n            var hs := vr.hider(ls);\n            var hconfig := ConvertConfig_AB(lconfig);\n\n            lemma_HidingPreservesInit_HeapInvariant(vr, ls, hs, lconfig, hconfig);\n            assert B.Armada_Init(hs, hconfig);\n        }\n    }\n\n    lemma lemma_LiftNext_Armada_PC_main'0(vr:VHRequest, ls:LState, ls':LState, lstep:LStep)\n        requires vr == GetVarHidingRequest()\n        requires A.Armada_Next(ls, ls', lstep)\n        requires lstep.Armada_TraceEntry_Armada_PC_main'0?\n        requires vr.hider(ls) != vr.hider(ls')\n        ensures  ActionTuple(vr.hider(ls), vr.hider(ls'), vr.step_refiner(lstep)) in vr.hspec.next\n    {\n        var hs := vr.hider(ls);\n        var hs' := vr.hider(ls');\n        var tid := lstep.tid;\n\n        assert hs'.threads == hs.threads[tid := hs'.threads[tid]];\n    }\n\n    lemma lemma_LiftNext_Armada_PC_main'1(vr:VHRequest, ls:LState, ls':LState, lstep:LStep)\n        requires vr == GetVarHidingRequest()\n        requires A.Armada_Next(ls, ls', lstep)\n        requires lstep.Armada_TraceEntry_Armada_PC_main'1?\n        requires vr.hider(ls) != vr.hider(ls')\n        ensures  ActionTuple(vr.hider(ls), vr.hider(ls'), vr.step_refiner(lstep)) in vr.hspec.next\n    {\n        var hs := vr.hider(ls);\n        var hs' := vr.hider(ls');\n        var tid := lstep.tid;\n\n        assert hs'.threads == hs.threads[tid := hs'.threads[tid]];\n    }\n\n    lemma lemma_LiftNext_Armada_PC_main'2(vr:VHRequest, ls:LState, ls':LState, lstep:LStep)\n        requires vr == GetVarHidingRequest()\n        requires A.Armada_Next(ls, ls', lstep)\n        requires lstep.Armada_TraceEntry_Armada_PC_main'2?\n        requires vr.hider(ls) != vr.hider(ls')\n        ensures  ActionTuple(vr.hider(ls), vr.hider(ls'), vr.step_refiner(lstep)) in vr.hspec.next\n    {\n        var hs := vr.hider(ls);\n        var hs' := vr.hider(ls');\n        var tid := lstep.tid;\n\n        assert hs'.threads[tid] == hs.threads[tid];\n        assert hs'.threads == hs.threads;\n        assert hs' == hs;\n        assert false;\n    }\n\n    lemma lemma_LiftNext_Tau(vr:VHRequest, ls:LState, ls':LState, lstep:LStep)\n        requires vr == GetVarHidingRequest()\n        requires A.Armada_Next(ls, ls', lstep)\n        requires lstep.Armada_TraceEntry_Tau?\n        requires vr.hider(ls) != vr.hider(ls')\n        ensures  ActionTuple(vr.hider(ls), vr.hider(ls'), vr.step_refiner(lstep)) in vr.hspec.next\n    {\n        var hs := vr.hider(ls);\n        var hs' := vr.hider(ls');\n        var tid := lstep.tid;\n\n        var entry := ls.threads[tid].storeBuffer[0];\n        if entry.Armada_StoreBufferEntry_Unaddressable? && entry.v.Armada_GlobalStaticVar_z? {\n            assert hs'.threads[tid].storeBuffer == hs.threads[tid].storeBuffer;\n            assert hs'.threads[tid] == hs.threads[tid];\n            assert hs'.threads == hs.threads;\n            assert hs.ok;\n            assert hs' == hs;\n            assert false;\n        }\n        else {\n            assert hs'.threads[tid].storeBuffer == hs.threads[tid].storeBuffer[1..];\n            assert hs'.threads[tid] == hs.threads[tid].(storeBuffer := hs'.threads[tid].storeBuffer);\n            assert hs'.threads == hs.threads[tid := hs'.threads[tid]];\n            assert B.Armada_Next_Tau(hs, hs', tid);\n        }\n    }\n\n    lemma lemma_LiftNext_Terminate'main(vr:VHRequest, ls:LState, ls':LState, lstep:LStep)\n        requires vr == GetVarHidingRequest()\n        requires A.Armada_Next(ls, ls', lstep)\n        requires lstep.Armada_TraceEntry_Terminate'main?\n        requires vr.hider(ls) != vr.hider(ls')\n        ensures  ActionTuple(vr.hider(ls), vr.hider(ls'), vr.step_refiner(lstep)) in vr.hspec.next\n    {\n        var hs := vr.hider(ls);\n        var hs' := vr.hider(ls');\n        var tid := lstep.tid;\n\n        var hs'_alt := B.Armada_GetNextState_Terminate'main(hs, tid);\n        assert hs'.threads == hs'_alt.threads;\n        assert hs' == hs'_alt;\n        assert B.Armada_Next_Terminate'main(hs, hs', tid);\n    }\n\n    lemma lemma_LiftActionWithoutVariable(vr:VHRequest, ls:LState, ls':LState, lstep:LStep)\n        requires vr == GetVarHidingRequest()\n        requires ls in vr.inv\n        requires ActionTuple(ls, ls', lstep) in vr.lspec.next\n        requires vr.hider(ls) != vr.hider(ls')\n        ensures  ActionTuple(vr.hider(ls), vr.hider(ls'), vr.step_refiner(lstep)) in vr.hspec.next\n    {\n        match lstep {\n            case Armada_TraceEntry_Armada_PC_main'0(_) =>\n                lemma_LiftNext_Armada_PC_main'0(vr, ls, ls', lstep);\n            case Armada_TraceEntry_Armada_PC_main'1(_) =>\n                lemma_LiftNext_Armada_PC_main'1(vr, ls, ls', lstep);\n            case Armada_TraceEntry_Armada_PC_main'2(_) =>\n                lemma_LiftNext_Armada_PC_main'2(vr, ls, ls', lstep);\n            case Armada_TraceEntry_Tau(_) =>\n                lemma_LiftNext_Tau(vr, ls, ls', lstep);\n            case Armada_TraceEntry_Terminate'main(_) =>\n                lemma_LiftNext_Terminate'main(vr, ls, ls', lstep);\n        }\n    }\n\n    lemma lemma_AllActionsLiftableWithoutVariable(vr:VHRequest)\n        requires vr == GetVarHidingRequest()\n        ensures  AllActionsLiftableWithoutVariable(vr)\n    {\n        forall s, s', lstep |\n            && ActionTuple(s, s', lstep) in vr.lspec.next\n            && s in vr.inv\n            && vr.hider(s) != vr.hider(s')\n            ensures ActionTuple(vr.hider(s), vr.hider(s'), vr.step_refiner(lstep)) in vr.hspec.next\n        {\n            lemma_LiftActionWithoutVariable(vr, s, s', lstep);\n        }\n    }\n\n    lemma lemma_ValidVarHidingRequest(vr:VHRequest)\n        requires vr == GetVarHidingRequest()\n        ensures  ValidVarHidingRequest(vr)\n    {\n        lemma_IsInvariantOfSpec(vr);\n        lemma_AllActionsLiftableWithoutVariable(vr);\n        lemma_HidingSatisfiesRelation(vr);\n        lemma_HidingPreservesInit(vr);\n    }\n\n    lemma lemma_GetLAnnotatedBehavior(lb:seq<A.Armada_TotalState>) returns (alb:AnnotatedBehavior<LState, LStep>)\n        requires BehaviorSatisfiesSpec(lb, A.Armada_Spec())\n        ensures  AnnotatedBehaviorSatisfiesSpec(alb, GetLSpec())\n        ensures  alb.states == lb\n    {\n        if |lb| == 1 {\n            return AnnotatedBehavior(lb, []);\n        }\n\n        var pos := |lb|-2;\n        var alb_prev := lemma_GetLAnnotatedBehavior(all_but_last(lb));\n        assert 0 <= pos < |lb|-1;\n        assert StatePair(lb[pos], lb[pos+1]) in A.Armada_Spec().next;\n        var entry :| A.Armada_Next(lb[pos], lb[pos+1], entry);\n        alb := AnnotatedBehavior(lb, alb_prev.trace + [entry]);\n    }\n\n    lemma lemma_IfAnnotatedBehaviorSatisfiesSpecThenBehaviorDoes(hb:AnnotatedBehavior<HState, HStep>)\n        requires AnnotatedBehaviorSatisfiesSpec(hb, GetHSpec())\n        ensures  BehaviorSatisfiesSpec(hb.states, B.Armada_Spec())\n    {\n        var b := hb.states;\n\n        forall i | 0 <= i < |b|-1\n            ensures StatePair(b[i], b[i+1]) in B.Armada_Spec().next\n        {\n            assert ActionTuple(hb.states[i], hb.states[i+1], hb.trace[i]) in GetHSpec().next;\n        }\n    }\n\n    lemma lemma_ProveRefinementViaVarHiding()\n        ensures SpecRefinesSpec(A.Armada_Spec(), B.Armada_Spec(), GetABRefinementRelation())\n    {\n        var lspec := A.Armada_Spec();\n        var hspec := B.Armada_Spec();\n        var vr := GetVarHidingRequest();\n\n        forall lb | BehaviorSatisfiesSpec(lb, lspec)\n            ensures BehaviorRefinesSpec(lb, hspec, vr.relation)\n        {\n            var alb := lemma_GetLAnnotatedBehavior(lb);\n            lemma_ValidVarHidingRequest(vr);\n            var ahb := lemma_PerformVarHiding(vr, alb);\n            assert BehaviorRefinesBehavior(alb.states, ahb.states, vr.relation);\n            lemma_IfAnnotatedBehaviorSatisfiesSpecThenBehaviorDoes(ahb);\n        }\n    }\n}\n"
  },
  {
    "path": "Test/varhiding/test.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs {\n\n    struct S1\n    {\n      var e:int32[4];\n      var f:int32[8];\n    }\n\n    struct S2\n    {\n       var g:S1[10];\n    }\n\n    struct S3\n    {\n    }\n\n}\n\nlevel A using SharedStructs {\n    noaddr var x:S1;\n    noaddr var y:int32 := 0;\n    noaddr var z:int32;\n    noaddr var q:S1;\n    noaddr var r:S2[8];\n    ghost var g:seq<int>;\n    var s:S1[3];\n\n    method {:extern} ExternalMethod()\n      reads x\n\n    method main(a:S1) returns (b:S2)\n    {\n        var c:S2[3];\n        noaddr var d:S2[4];\n\n        g[3] := 7;\n        label lb1:\n        atomic {\n            x ::= *;\n            label lb2:\n            y ::= 4;\n        }\n        z ::= 5;\n    }\n\n    invariant YZeroOrFour\n    {\n        y == 0 || y == 4\n    }\n\n    invariant YNonNegative\n    {\n        y >= 0\n    }\n}\n\nlevel B using SharedStructs {\n    noaddr var x:S1;\n    noaddr var y:int32 := 0;\n    noaddr var q:S1;\n    noaddr var r:S2[8];\n    ghost var g:seq<int>;\n    var s:S1[3];\n\n    method {:extern} ExternalMethod()\n      reads x\n\n    method main(a:S1) returns (b:S2)\n    {\n        var c:S2[3];\n        noaddr var d:S2[4];\n\n        g[3] := 7;\n        atomic {\n            x ::= *;\n            y ::= 4;\n        }\n    }\n}\n\nproof AB {\n    refinement A B\n    var_hiding z\n\n    auxiliary num_steps\n    \"int\"\n    \"datatype MyInt = MyInt(x:int)\"\n    \"0\"\n    \"s.num_steps + 1\"\n\n    inductive_invariant YZeroOrFour depends_on YNeverInStoreBuffers\n    inductive_invariant YNonNegative depends_on YNeverInStoreBuffers\n    inductive_invariant YNeverInStoreBuffers @\"\n      forall tid, entry ::\n        && tid in threads\n        && entry in threads[tid].storeBuffer\n        && entry.loc.Armada_StoreBufferLocation_Unaddressable?\n        ==> !entry.loc.v.Armada_GlobalStaticVar_y?\n    \"\n\n    inductive_invariant NumStepsPositive \"s.num_steps >= 0\"\n}\n"
  },
  {
    "path": "Test/varhiding/test2.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs2\n{\n    struct C1 {\n        var x:int32[4];\n        var y:int32[8];\n    }\n\n    struct C2 {\n        var a:int32\n        var b:C1\n    }\n\n    struct C3 {\n        var mno:C2\n        var pqr:C2\n        var s:int64\n    }\n\n    struct C4 {\n    }\n\n    datatype MyLogEntry = MyLogEntryInt(i:int) | MyLogEntryBool(b:bool)\n    ghost var log:seq<MyLogEntry> := [];\n\n    refinement_constraint @\"\n       || (ls.stop_reason == hs.stop_reason && ls.ghosts.log == hs.ghosts.log)\n       || (ls.stop_reason.Armada_NotStopped? && ls.ghosts.log <= hs.ghosts.log)\n    \"\n}\n\nlevel C using SharedStructs2\n{\n    noaddr var w:int32\n    noaddr var x:int32\n    var y:int32\n    noaddr var z:int32\n    var g1:uint8[10];\n    var g2:C2;\n    var g3:C2[5];\n    noaddr var g4:C3;\n\n    method {:extern} ExternalMethod(a:uint32, p:ptr<int32>) returns (b:uint32)\n        reads    x, g2.a\n        modifies y, g1[4], log\n        ensures  y == old(y + *p) + 3\n        ensures  b == a * 2\n        ensures  log == old(log) + [MyLogEntryInt(2), MyLogEntryInt(47), MyLogEntryBool(true)]\n\n    function method increment(x:uint32) : uint32\n    {\n        if (0 < x < 10) then x + 1 else 0\n    }\n\n    method C1Test(ths:ptr<C1>)\n    {\n        noaddr var z:int32;\n        z ::= (*ths).x[2];\n        assume z - (*ths).x[2] == 0;\n        assume x > 3;\n        (*ths).x[2] ::= z + 3;\n    }\n\n    method C2Help(ths:ptr<C2>)\n    {\n        noaddr var q:int32[4];\n    }\n\n    method InterestingControlFlow(a:int32, b:int64, p:ptr<int32>)\n    {\n        while (a > *p) {\n            if (b < 3) {\n                a := a - 1;\n                assume a != 13;\n                continue;\n            }\n            else if (b > 10) {\n                a := a - 2;\n                b := b - 1;\n                return;\n            }\n            else {\n                assume b > 17;\n                break;\n            }\n            *p := *p + 1;\n            assert *p > 7;\n        }\n        if *p == 10 {\n            *p := 11;\n        }\n        w := 7;\n    }\n\n    method Foo(a:uint32, b:uint64) returns (c:uint32, d:uint64)\n    {\n        noaddr var z:uint64;\n        var x:uint64;\n        var y:uint64;\n        noaddr var cnew:C2;\n\n        x := (var q:bool := (b == 9); if q then 3 as uint64 else 17);\n        y := if (a > 3) then 4 else 0;\n        {\n           z := y + b;\n           y := z;\n        }\n        explicit_yield {\n           c := a + a;\n           d := z - 6;\n        }\n        w := 8;\n    }\n\n    method Bar(a:int16, b:uint32) returns (c:uint32, d:uint32)\n    {\n        var z:int32;\n        noaddr var x:uint32, y:int32, q:C2[8];\n\n        x, y, c := 5, 6, x + 1;\n        a := -a;\n        b := increment(c);\n    }\n\n    method Baz(p:ptr<int16>, q:ptr<uint32>) returns (c:uint32)\n    {\n        var d:uint32;\n        var h:uint64;\n\n        *q, *(q+1) := Bar(*p, *q);\n        h := create_thread Bar(4, 6);\n        w := 10;\n        g4.mno.b.x[2] := 3;\n    }\n\n    method main(p: ptr<int32>, c:C1) {\n        *p, *(p+1), c.x[3] := 0, 1, 78;\n        w := 11;\n    }\n\n}\n\nlevel D using SharedStructs2\n{\n    noaddr var x:int32\n    var y:int32\n    noaddr var z:int32\n    var g1:uint8[10];\n    var g2:C2;\n    var g3:C2[5];\n    noaddr var g4:C3;\n\n    method {:extern} ExternalMethod(a:uint32, p:ptr<int32>) returns (b:uint32)\n        reads    x, g2.a\n        modifies y, g1[4], log\n        ensures  y == old(y + *p) + 3\n        ensures  b == a * 2\n        ensures  log == old(log) + [MyLogEntryInt(2), MyLogEntryInt(47), MyLogEntryBool(true)]\n\n    function method increment(x:uint32) : uint32\n    {\n        if (0 < x < 10) then x + 1 else 0\n    }\n\n    method C1Test(ths:ptr<C1>)\n    {\n        noaddr var z:int32;\n        z ::= (*ths).x[2];\n        assume z - (*ths).x[2] == 0;\n        assume x > 3;\n        (*ths).x[2] ::= z + 3;\n    }\n\n    method C2Help(ths:ptr<C2>)\n    {\n        noaddr var q:int32[4];\n    }\n\n    method InterestingControlFlow(a:int32, b:int64, p:ptr<int32>)\n    {\n        while (a > *p) {\n            if (b < 3) {\n                a := a - 1;\n                assume a != 13;\n                continue;\n            }\n            else if (b > 10) {\n                a := a - 2;\n                b := b - 1;\n                return;\n            }\n            else {\n                assume b > 17;\n                break;\n            }\n            *p := *p + 1;\n            assert *p > 7;\n        }\n        if *p == 10 {\n            *p := 11;\n        }\n    }\n\n    method Foo(a:uint32, b:uint64) returns (c:uint32, d:uint64)\n    {\n        noaddr var z:uint64;\n        var x:uint64;\n        var y:uint64;\n        noaddr var cnew:C2;\n\n        x := (var q:bool := (b == 9); if q then 3 as uint64 else 17);\n        y := if (a > 3) then 4 else 0;\n        {\n           z := y + b;\n           y := z;\n        }\n        explicit_yield {\n           c := a + a;\n           d := z - 6;\n        }\n    }\n\n    method Bar(a:int16, b:uint32) returns (c:uint32, d:uint32)\n    {\n        var z:int32;\n        noaddr var x:uint32, y:int32, q:C2[8];\n\n        x, y, c := 5, 6, x + 1;\n        a := -a;\n        b := increment(c);\n    }\n\n    method Baz(p:ptr<int16>, q:ptr<uint32>) returns (c:uint32)\n    {\n        var d:uint32;\n        var h:uint64;\n\n        *q, *(q+1) := Bar(*p, *q);\n        h := create_thread Bar(4, 6);\n        g4.mno.b.x[2] := 3;\n    }\n\n    method main(p: ptr<int32>, c:C1) {\n        *p, *(p+1), c.x[3] := 0, 1, 78;\n    }\n\n}\n\nproof CD {\n\n    refinement C D\n    var_hiding  w\n\n}\n"
  },
  {
    "path": "Test/varhiding/test3.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs3 {\n\n}\n\nlevel E using SharedStructs3 {\n    noaddr var x:uint32 := 0;\n    noaddr var y:uint32 := 0;\n    noaddr var z:uint32 := 0;\n\n    method main()\n    {\n        explicit_yield\n        {\n            y := 7;\n            x := 3;\n            y := 8;\n            z := 5;\n            y := 4;\n        }\n    }\n}\n\nlevel F using SharedStructs3 {\n    noaddr var x:uint32 := 0;\n    noaddr var z:uint32 := 0;\n\n    method main()\n    {\n        explicit_yield\n        {\n            x := 3;\n            z := 5;\n        }\n    }\n}\n\nproof EF {\n    refinement E F\n    var_hiding y\n}\n"
  },
  {
    "path": "Test/varhiding/test4.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs4 {\n\n}\n\nlevel G using SharedStructs4 {\n  noaddr var x:int32;\n  noaddr var y:int32;\n\n  method main()\n  {\n    noaddr var a:int32;\n    noaddr var b:int32;\n    noaddr var c:int32;\n\n    atomic {\n      x := 1;\n      a := 2;\n    }\n\n    y := 3;\n    b := 4;\n\n    atomic {\n      b := 5;\n      c := 6;\n    }\n  }\n}\n\nlevel H using SharedStructs4 {\n  noaddr var x:int32;\n  noaddr var y:int32;\n\n  method main()\n  {\n    noaddr var c:int32;\n\n    x := 1;\n    y := 3;\n    c := 6;\n  }\n}\n\nproof GH {\n  refinement G H\n  stack_var_hiding main a, b\n}\n"
  },
  {
    "path": "Test/varhiding/test5.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs5 {\n\n}\n\nlevel I using SharedStructs5 {\n  ghost var w:int32;\n  ghost var x:int32;\n  ghost var y:int32;\n  ghost var z:int32;\n\n  method {:atomic} foo()\n  {\n    x := 3;\n  }\n\n  method bar()\n  {\n    atomic {\n      if (x > 2) {\n        y := 4;\n      }\n      else {\n        while (x > 3) {\n          y := 5;\n          yield;\n          y := 4;\n          w := w + 1;\n        }\n        y := 2;\n        foo();\n      }\n    }\n    z := 6;\n  }\n\n  method main()\n  {\n    x := 3;\n    atomic {\n      y := 8;\n      foo();\n      w := 7;\n      z := 5;\n    }\n  }\n}\n\nlevel J using SharedStructs5 {\n  ghost var x:int32;\n  ghost var y:int32;\n  ghost var z:int32;\n\n  method {:atomic} foo()\n  {\n    x := 3;\n  }\n\n  method bar()\n  {\n    atomic {\n      if (x > 2) {\n        y := 4;\n      }\n      else {\n        while (x > 3) {\n          y := 5;\n          yield;\n          y := 4;\n        }\n        y := 2;\n        foo();\n      }\n    }\n    z := 6;\n  }\n\n  method main()\n  {\n    x := 3;\n    atomic {\n      y := 8;\n      foo();\n      z := 5;\n    }\n  }\n}\n\nproof IJ {\n  refinement I J\n  var_hiding w\n}\n"
  },
  {
    "path": "Test/varintro/.gitignore",
    "content": "A.dfy\nB.dfy\nAB.dfy\nSharedStructs.dfy\nC.dfy\nD.dfy\nCD.dfy\nSharedStructs2.dfy\nE.dfy\nF.dfy\nEF.dfy\nSharedStructs3.dfy\nG.dfy\nH.dfy\nGH.dfy\nSharedStructs4.dfy\nAB/\nCD/\nEF/\nGH/\n"
  },
  {
    "path": "Test/varintro/test.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\n// this is failing because ReturnTo_1_main is translated into ReturnTo_2_main which does not exist\n\nstructs SharedStructs {\n\n    struct S1\n    {\n      var e:int32[4];\n      var f:int32[8];\n    }\n\n    struct S2\n    {\n       var g:S1[10];\n    }\n\n    struct S3\n    {\n    }\n\n}\n\nlevel B using SharedStructs {\n    noaddr var x:int32;\n    noaddr var y:int32;\n    noaddr var z:int32 := 0;\n    ghost noaddr var w:int32 := 42;\n\n    method foo() returns (bar: int32)\n    {\n      bar ::= 41;\n      return;\n      bar ::= 42;\n    }\n\n    method main()\n    {\n        x := foo();\n        z ::= 42;\n        y := *;\n        z := 5;\n        w ::= 43;\n        z := 6;\n        y := 41;\n    }\n}\n\nlevel A using SharedStructs {\n    noaddr var x:int32;\n    noaddr var y:int32\n\n    method foo() returns (bar: int32)\n    {\n      bar ::= 41;\n      return;\n      bar ::= 42;\n    }\n\n    method main()\n    {\n        x := foo();\n        y := *;\n        y := 41;\n    }\n}\n\nproof AB {\n    refinement A B\n    var_intro z, w\n}\n"
  },
  {
    "path": "Test/varintro/test2.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs2 {\n\n    struct S1\n    {\n      var e:int32[4];\n      var f:int32[8];\n    }\n\n    struct S2\n    {\n       var g:S1[10];\n    }\n\n    struct S3\n    {\n    }\n\n}\n\nlevel C using SharedStructs2 {\n    noaddr var x:int32;\n    noaddr var y:int32\n\n    method foo() returns (bar: int32)\n    {\n        bar := 41;\n    }\n    method main()\n    {\n        x := foo();\n        y := *;\n    }\n}\n\nlevel D using SharedStructs2 {\n    noaddr var x:int32;\n    noaddr var y:int32;\n\n    method foo() returns (bar: int32)\n    {\n        noaddr var foo: uint32;\n        foo := 42;\n        bar := 41;\n    }\n\n    method main()\n    {\n        x := foo();\n        y := *;\n    }\n}\n\nproof CD {\n    refinement C D\n    stack_var_intro foo foo \"1 - 1 + 1\"\n}\n"
  },
  {
    "path": "Test/varintro/test3.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs3 {\n\n    struct S1\n    {\n      var e:int32[4];\n      var f:int32[8];\n    }\n\n    struct S2\n    {\n       var g:S1[10];\n    }\n\n    struct S3\n    {\n    }\n\n}\n\nlevel E using SharedStructs3 {\n    noaddr var x:int32;\n    noaddr var y:int32\n\n    method foo() returns (bar: int32)\n    {\n      bar ::= 41;\n      return;\n      bar ::= 42;\n    }\n\n    method main()\n    {\n        x := 41;\n        y := *;\n    }\n}\n\nlevel F using SharedStructs3 {\n    noaddr var x:int32;\n    noaddr var y:int32;\n    noaddr var z:int32 := 0;\n\n    method foo() returns (bar: int32)\n    {\n      bar ::= 41;\n      return;\n      atomic {\n        bar ::= 42;\n        z := 7;\n      }\n    }\n\n    method main()\n    {\n        x := 41;\n        atomic {\n          z ::= 42;\n          y := *;\n          z := 5;\n        }\n        z := 6;\n    }\n}\n\nproof EF {\n    refinement E F\n    var_intro z\n}\n"
  },
  {
    "path": "Test/varintro/test4.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\n\nstructs SharedStructs4 {\n  struct S1\n  {\n    var e:int32[4];\n    var f:int32[8];\n  }\n\n  struct S2\n  {\n    var g:S1[10];\n  }\n\n  struct S3\n  {\n  }\n}\n\n\nlevel G using SharedStructs4 {\n  var x: int32;\n  var y: int32;\n\n  method main()\n  {\n    x, y := 31, 41;\n    x, y := 30, 40;\n    x, y := 33, 43;\n    y, x := 42, 32;\n  }\n}\n\nlevel H using SharedStructs4 {\n  var x: int32;\n  var y: int32;\n  ghost var z: int64 := 0;\n  noaddr var w: int64 := 0;\n\n  method main()\n  {\n    x, y := 31, 41;\n    x, y := 30, 40;\n    x, y := 33, 43;\n    z := 0;\n    w, w, w := 0, 1, 2;\n    y, x := 42, 32;\n  }\n}\n\nproof GH {\n    refinement G H\n    var_intro z, w\n}\n"
  },
  {
    "path": "Test/weakening/.gitignore",
    "content": "A.dfy\nB.dfy\nAB.dfy\nSharedStructs.dfy\nC.dfy\nD.dfy\nCD.dfy\nSharedStructs2.dfy\nE.dfy\nF.dfy\nEF.dfy\nSharedStructs3.dfy\nAB/\nCD/\nEF/\n"
  },
  {
    "path": "Test/weakening/ArithmeticFacts.dfy",
    "content": "// Use /arith:2 to verify this file\n\ninclude \"../../Armada/ArmadaCommonDefinitions.dfy\"\ninclude \"EF/specs.dfy\"\n\nmodule ArithmeticFactsModule\n{\n  import opened ArmadaCommonDefinitions\n  import opened ArmadaModule_specs\n\n  function ThreadToInstructionCount_LPlus(s:LPlusState, tid:Armada_ThreadHandle) : (v:int)\n  {\n    if tid in s.s.threads then PCToInstructionCount_L(s.s.threads[tid].pc) else -1\n  }\n\n  lemma lemma_Equivalence(x:int)\n    ensures (x + 1) * (x + 1) == x * x + 2 * x + 1\n  {\n  }\n}\n\n"
  },
  {
    "path": "Test/weakening/TestWeakeningProof.dfy",
    "content": "include \"SharedStructs.dfy\"\ninclude \"A.dfy\"\ninclude \"B.dfy\"\ninclude \"../../Armada/strategies/weakening/Weakening.i.dfy\"\ninclude \"../../Armada/strategies/refinement/AnnotatedBehavior.i.dfy\"\ninclude \"../../Armada/util/option.s.dfy\"\ninclude \"../../Armada/util/collections/seqs.s.dfy\"\ninclude \"../../Armada/util/collections/seqs.i.dfy\"\ninclude \"../../Armada/util/collections/sets.i.dfy\"\ninclude \"../../Armada/util/collections/maps.i.dfy\"\n\nmodule AB {\n import opened ArmadaCommonDefinitions = ArmadaCommonDefinitions\n\n  import opened GeneralRefinementModule = GeneralRefinementModule\n\n  import L = A\n\n  import H = B\n\n  import opened AnnotatedBehaviorModule = AnnotatedBehaviorModule\n\n  import opened SharedStructs = SharedStructs\n\n  import opened InvariantsModule = InvariantsModule\n\n  import opened WeakeningSpecModule = WeakeningSpecModule\n\n  import opened WeakeningModule = WeakeningModule\n\n  import opened util_option_s = util_option_s\n\n  import opened util_collections_seqs_s = util_collections_seqs_s\n\n  import opened util_collections_seqs_i = util_collections_seqs_i\n\n  import opened util_collections_sets_i = util_collections_sets_i\n\n  import opened util_collections_maps_i = util_collections_maps_i\n  datatype MyInt = MyInt(x: int)\n\n  type LState = L.Armada_TotalState\n\n  type HState = H.Armada_TotalState\n\n  type LStep = L.Armada_StepSequence\n\n  type HStep = H.Armada_StepSequence\n\n  type LSpec = AnnotatedBehaviorSpec<LState, LStep>\n\n  type HSpec = AnnotatedBehaviorSpec<HState, HStep>\n\n  type LConfig = L.Armada_Config\n\n  type WRequest = WeakeningRequest<LState, HState, LStep, HStep>\n\n  predicate LHStateRefinement(ls: LState, hs: HState)\n  {\n    && (hs.ok ==>\n      ls.ok)\n    && ls.log <= hs.log\n  }\n\n  function GetLHRefinementRelation(): RefinementRelation<LState, HState>\n  {\n    iset p: RefinementPair<LState, HState> | LHStateRefinement(p.low, p.high)\n  }\n\n  function GetLSpec(): LSpec\n  {\n    AnnotatedBehaviorSpec(iset s, config | L.Armada_Init(s, config) :: s, iset s, s', entry | L.Armada_Next(s, s', entry) :: ActionTuple(s, s', entry))\n  }\n\n  function GetHSpec_State(): HSpec\n  {\n     AnnotatedBehaviorSpec(iset s, config | H.Armada_Init(s, config) :: s, iset s, s', entry | H.Armada_Next(s, s', entry) :: ActionTuple(s, s', entry))\n  }\n\n  function GetHSpec(): HSpec\n  {\n    AnnotatedBehaviorSpec(iset s, config | H.Armada_Init(s, config) :: s, iset s, s', entry | H.Armada_Next(s, s', entry) :: ActionTuple(s, s', entry))\n  }\n\n  lemma lemma_GetLAnnotatedBehavior(lb: seq<L.Armada_TotalState>) returns (alb: AnnotatedBehavior<LState, LStep>)\n    requires BehaviorSatisfiesSpec(lb, L.Armada_Spec())\n    ensures AnnotatedBehaviorSatisfiesSpec(alb, GetLSpec())\n    ensures alb.states == lb\n  {\n    if |lb| == 1 {\n      return AnnotatedBehavior(lb, []);\n    }\n    var pos := |lb| - 2;\n    var alb_prev := lemma_GetLAnnotatedBehavior(all_but_last(lb));\n    assert 0 <= pos < |lb| - 1;\n    assert StatePair(lb[pos], lb[pos + 1]) in L.Armada_Spec().next;\n    var entry :| L.Armada_Next(lb[pos], lb[pos + 1], entry);\n    alb := AnnotatedBehavior(lb, alb_prev.trace + [entry]);\n  }\n\n  predicate InductiveInv(s: LState)\n  {\n    true\n  }\n\n  lemma lemma_IfAnnotatedBehaviorSatisfiesSpecThenBehaviorDoes(hb: AnnotatedBehavior<HState, HStep>)\n    requires AnnotatedBehaviorSatisfiesSpec(hb, GetHSpec())\n    ensures BehaviorSatisfiesSpec(hb.states, H.Armada_Spec())\n  {\n    var b := hb.states;\n    forall i | 0 <= i < |b| - 1\n      ensures StatePair(b[i], b[i + 1]) in H.Armada_Spec().next\n    {\n      assert ActionTuple(hb.states[i], hb.states[i + 1], hb.trace[i]) in GetHSpec().next;\n    }\n  }\n\n  function ConvertPC_LH(pc: L.Armada_PC): H.Armada_PC\n  {\n    match pc\n    case Armada_PC_None =>\n      H.Armada_PC_None\n    case Armada_PC_0_main =>\n      H.Armada_PC_0_main\n    case Armada_PC_1_main =>\n      H.Armada_PC_1_main\n    case Armada_PC_2_main =>\n      H.Armada_PC_2_main\n  }\n\n  function ConvertStackFrame_LH(frame: L.Armada_StackFrame): H.Armada_StackFrame\n  {\n    match frame\n    case Armada_StackFrame_main =>\n      H.Armada_StackFrame_main()\n  }\n\n  function ConvertRegions_LH(regions: L.Armada_Regions): H.Armada_Regions\n  {\n    H.Armada_Regions(regions.default)\n  }\n\n  function ConvertRegionID_LH(regionID: L.Armada_RegionID): H.Armada_RegionID\n  {\n    match regionID\n    case Armada_RegionID_default =>\n      H.Armada_RegionID_default\n  }\n\n  function ConvertGlobals_LH(globals: L.Armada_Globals): H.Armada_Globals\n  {\n    H.Armada_Globals(globals.x)\n  }\n\n  function ConvertGhosts_LH(ghosts: L.Armada_Ghosts): H.Armada_Ghosts\n  {\n    H.Armada_Ghosts()\n  }\n\n  function ConvertAddrs_LH(addrs: L.Armada_Addrs): H.Armada_Addrs\n  {\n    H.Armada_Addrs()\n  }\n\n  function ConvertGlobalStaticVar_LH(v: L.Armada_GlobalStaticVar): H.Armada_GlobalStaticVar\n  {\n    match v\n    case Armada_GlobalStaticVarNone =>\n      H.Armada_GlobalStaticVarNone\n    case Armada_GlobalStaticVar_x =>\n      H.Armada_GlobalStaticVar_x\n  }\n\n  function ConvertSharedMemory_LH(mem: L.Armada_SharedMemory): H.Armada_SharedMemory\n  {\n    H.Armada_SharedMemory(ConvertRegions_LH(mem.regions), ConvertGlobals_LH(mem.globals))\n  }\n\n  function ConvertStoreBufferLocation_LH(loc: L.Armada_StoreBufferLocation): H.Armada_StoreBufferLocation\n  {\n    match loc\n    case Armada_StoreBufferLocation_Unaddressable(v, fields) =>\n      H.Armada_StoreBufferLocation_Unaddressable(ConvertGlobalStaticVar_LH(v), fields)\n    case Armada_StoreBufferLocation_Addressable(p, r) =>\n      H.Armada_StoreBufferLocation_Addressable(p, ConvertRegionID_LH(r))\n  }\n\n  predicate CanConvertGlobalStaticVar_LH(v: L.Armada_GlobalStaticVar)\n  {\n    true\n  }\n\n  predicate CanConvertStoreBufferLocation_LH(loc: L.Armada_StoreBufferLocation)\n  {\n    loc.Armada_StoreBufferLocation_Unaddressable? ==>\n      CanConvertGlobalStaticVar_LH(loc.v)\n  }\n\n  predicate CanConvertStoreBufferEntry_LH(entry: L.Armada_StoreBufferEntry)\n  {\n    CanConvertStoreBufferLocation_LH(entry.loc)\n  }\n\n\n  function ConvertStoreBufferEntry_LH(entry: L.Armada_StoreBufferEntry): H.Armada_StoreBufferEntry\n  {\n    H.Armada_StoreBufferEntry(ConvertStoreBufferLocation_LH(entry.loc), entry.value)\n  }\n\n  function ConvertStoreBuffer_LH(entries: seq<L.Armada_StoreBufferEntry>): seq<H.Armada_StoreBufferEntry>\n  {\n    MapSeqToSeq(entries, ConvertStoreBufferEntry_LH)\n  }\n\n  function ConvertSnapshot_LH(snap: L.Armada_Snapshot): H.Armada_Snapshot\n  {\n    H.Armada_Snapshot(ConvertStackFrame_LH(snap.top), ConvertSharedMemory_LH(snap.mem), ConvertGhosts_LH(snap.ghosts))\n  }\n\n  function ConvertExtendedFrame_LH(eframe: L.Armada_ExtendedFrame): H.Armada_ExtendedFrame\n  {\n    H.Armada_ExtendedFrame(ConvertPC_LH(eframe.return_pc), ConvertStackFrame_LH(eframe.frame), ConvertSnapshot_LH(eframe.snap), eframe.new_ptrs)\n  }\n\n  function ConvertStack_LH(stack: seq<L.Armada_ExtendedFrame>): seq<H.Armada_ExtendedFrame>\n  {\n    MapSeqToSeq(stack, ConvertExtendedFrame_LH)\n  }\n\n  function ConvertThread_LH(t: L.Armada_Thread): H.Armada_Thread\n  {\n    H.Armada_Thread(ConvertPC_LH(t.pc), ConvertStackFrame_LH(t.top), ConvertSnapshot_LH(t.snap), t.new_ptrs, ConvertStack_LH(t.stack), ConvertStoreBuffer_LH(t.storeBuffer))\n  }\n\n  function ConvertThreads_LH(threads: map<Armada_ThreadHandle, L.Armada_Thread>): map<Armada_ThreadHandle, H.Armada_Thread>\n  {\n    MapMapToMap(threads, ConvertThread_LH)\n  }\n\n  function ConvertTotalState_LH(s: L.Armada_TotalState): H.Armada_TotalState\n  {\n    H.Armada_TotalState(s.ok, s.log, ConvertThreads_LH(s.threads), ConvertSharedMemory_LH(s.mem), ConvertGhosts_LH(s.ghosts), ConvertAddrs_LH(s.addrs))\n  }\n\n  function ConvertConfig_LH(config: L.Armada_Config): H.Armada_Config\n  {\n    H.Armada_Config(config.tid_init, config.new_ptrs)\n  }\n\n  function ConvertTraceEntry_LH(entry: L.Armada_TraceEntry): H.Armada_TraceEntry\n  {\n    match entry\n    case Armada_TraceEntry_Update_0_main(tid: Armada_ThreadHandle) =>\n      H.Armada_TraceEntry_Update_0_main(tid)\n    case Armada_TraceEntry_Update_1_main(tid: Armada_ThreadHandle) =>\n      H.Armada_TraceEntry_Update_1_main(tid)\n    case Armada_TraceEntry_Terminate_main(tid: Armada_ThreadHandle) =>\n      H.Armada_TraceEntry_Terminate_main(tid)\n    case Armada_TraceEntry_Tau(tid: Armada_ThreadHandle) =>\n      H.Armada_TraceEntry_Tau(tid)\n  }\n\n  function ConvertStepSequence_LH(entry: LStep): HStep\n  {\n    H.Armada_StepSequence(entry.tau, entry.tid, MapSeqToSeq(entry.steps, ConvertTraceEntry_LH))\n  }\n\n  function GetWeakeningRequest(): WRequest\n  {\n    WeakeningRequest(GetLSpec(), GetHSpec(), GetLHRefinementRelation(), iset ls | InductiveInv(ls) :: ls, ConvertTotalState_LH, ConvertStepSequence_LH)\n  }\n\n  lemma lemma_ApplyStoreBufferEntryCommutesWithConvert(lmem: L.Armada_SharedMemory, lentry: L.Armada_StoreBufferEntry, hentry: H.Armada_StoreBufferEntry, hmem1: H.Armada_SharedMemory, hmem2: H.Armada_SharedMemory)\n    requires hentry == ConvertStoreBufferEntry_LH(lentry)\n    requires hmem1 == ConvertSharedMemory_LH(L.Armada_ApplyStoreBufferEntry(lmem, lentry))\n    requires hmem2 == H.Armada_ApplyStoreBufferEntry(ConvertSharedMemory_LH(lmem), hentry)\n    ensures hmem1 == hmem2\n  {\n  }\n\n    lemma lemma_ApplyStoreBufferCommutesWithConvert(lmem: L.Armada_SharedMemory, lbuf: seq<L.Armada_StoreBufferEntry>, hbuf: seq<H.Armada_StoreBufferEntry>, hmem1: H.Armada_SharedMemory, hmem2: H.Armada_SharedMemory)\n    requires hbuf == ConvertStoreBuffer_LH(lbuf)\n    requires hmem1 == ConvertSharedMemory_LH(L.Armada_ApplyStoreBuffer(lmem, lbuf))\n    requires hmem2 == H.Armada_ApplyStoreBuffer(ConvertSharedMemory_LH(lmem), hbuf)\n    ensures hmem1 == hmem2\n    decreases |lbuf| + |hbuf|\n  {\n    if |lbuf| == 0 {\n      return;\n    }\n    var lmem' := L.Armada_ApplyStoreBufferEntry(lmem, lbuf[0]);\n    var hmem1' := ConvertSharedMemory_LH(L.Armada_ApplyStoreBufferEntry(lmem, lbuf[0]));\n    var hmem2' := H.Armada_ApplyStoreBufferEntry(ConvertSharedMemory_LH(lmem), hbuf[0]);\n    lemma_ApplyStoreBufferEntryCommutesWithConvert(lmem, lbuf[0], hbuf[0], hmem1', hmem2');\n    lemma_ApplyStoreBufferCommutesWithConvert(lmem', lbuf[1..], hbuf[1..], hmem1, hmem2);\n  }\n\n  lemma lemma_GetThreadLocalViewCommutesWithConvert(ls: LState, hs: HState, tid: Armada_ThreadHandle)\n    requires hs == ConvertTotalState_LH(ls)\n    requires tid in ls.threads\n    ensures ConvertSharedMemory_LH(L.Armada_GetThreadLocalView(ls, tid)) == H.Armada_GetThreadLocalView(hs, tid)\n  {\n    assert tid in hs.threads;\n    lemma_ApplyStoreBufferCommutesWithConvert(ls.mem, ls.threads[tid].storeBuffer, hs.threads[tid].storeBuffer, ConvertSharedMemory_LH(L.Armada_GetThreadLocalView(ls, tid)), H.Armada_GetThreadLocalView(hs, tid));\n  }\n\n  lemma lemma_GetThreadLocalViewAlwaysCommutesWithConvert()\n    ensures forall ls: L.Armada_TotalState, tid: Armada_ThreadHandle :: tid in ls.threads ==> ConvertSharedMemory_LH(L.Armada_GetThreadLocalView(ls, tid)) == H.Armada_GetThreadLocalView(ConvertTotalState_LH(ls), tid)\n  {\n    forall ls: L.Armada_TotalState, tid: Armada_ThreadHandle | tid in ls.threads\n      ensures ConvertSharedMemory_LH(L.Armada_GetThreadLocalView(ls, tid)) == H.Armada_GetThreadLocalView(ConvertTotalState_LH(ls), tid)\n    {\n      var hs := ConvertTotalState_LH(ls);\n      lemma_GetThreadLocalViewCommutesWithConvert(ls, hs, tid);\n    }\n  }\n\n  lemma lemma_StoreBufferAppendAlwaysCommutesWithConvert()\n    ensures forall lbuf: seq<L.Armada_StoreBufferEntry>, lentry: L.Armada_StoreBufferEntry {:trigger L.Armada_StoreBufferAppend(lbuf, lentry)} :: true ==> H.Armada_StoreBufferAppend(ConvertStoreBuffer_LH(lbuf), ConvertStoreBufferEntry_LH(lentry)) == ConvertStoreBuffer_LH(L.Armada_StoreBufferAppend(lbuf, lentry))\n  {\n  }\n\n  lemma lemma_LiftNext_Update_0_main(wr: WRequest, ls: LState, ls':LState, lstep: L.Armada_TraceEntry)\n    requires wr == GetWeakeningRequest()\n    requires L.Armada_NextOneStep(ls, ls', lstep)\n    requires lstep.Armada_TraceEntry_Update_0_main?\n    ensures H.Armada_NextOneStep(ConvertTotalState_LH(ls), ConvertTotalState_LH(ls'), ConvertTraceEntry_LH(lstep))\n  {\n    var hs := wr.converter(ls);\n    var hs' := wr.converter(ls');\n    var tid := lstep.tid;\n    var hstep := ConvertTraceEntry_LH(lstep);\n    lemma_GetThreadLocalViewAlwaysCommutesWithConvert();\n    lemma_StoreBufferAppendAlwaysCommutesWithConvert();\n    assert H.Armada_ValidStep_Update_0_main(hs, tid);\n    if L.Armada_CrashAvoidance_Update_0_main(ls, tid) {\n      assert H.Armada_CrashAvoidance_Update_0_main(hs, tid);\n      var alt_hs' := H.Armada_GetNextState_Update_0_main(hs, tid);\n      assert hs'.ok == alt_hs'.ok;\n      assert hs'.log == alt_hs'.log;\n      if tid in hs'.threads {\n        assert hs'.threads[tid] == alt_hs'.threads[tid];\n      }\n      assert hs'.threads == alt_hs'.threads;\n      assert hs'.mem == alt_hs'.mem;\n      assert hs' == alt_hs';\n      assert H.Armada_Next_Update_0_main(hs, hs', tid);\n    } else {\n      assert !H.Armada_CrashAvoidance_Update_0_main(hs, tid);\n    }\n  }\n\n  lemma lemma_LiftNext_Update_1_main(wr: WRequest, ls: LState, ls':LState, lentry: L.Armada_TraceEntry)\n    requires wr == GetWeakeningRequest()\n    requires L.Armada_NextOneStep(ls, ls', lentry)\n    requires lentry.Armada_TraceEntry_Update_1_main?\n    ensures H.Armada_NextOneStep(ConvertTotalState_LH(ls), ConvertTotalState_LH(ls'), ConvertTraceEntry_LH(lentry))\n  {\n    var hs := wr.converter(ls);\n    var hs' := wr.converter(ls');\n    var tid := lentry.tid;\n    var hstep := ConvertTraceEntry_LH(lentry);\n    lemma_GetThreadLocalViewAlwaysCommutesWithConvert();\n    lemma_StoreBufferAppendAlwaysCommutesWithConvert();\n    assert H.Armada_ValidStep_Update_1_main(hs, tid);\n    if L.Armada_CrashAvoidance_Update_1_main(ls, tid) {\n      assert H.Armada_CrashAvoidance_Update_1_main(hs, tid);\n      var alt_hs' := H.Armada_GetNextState_Update_1_main(hs, tid);\n      assert hs'.ok == alt_hs'.ok;\n      assert hs'.log == alt_hs'.log;\n      if tid in hs'.threads {\n        assert hs'.threads[tid] == alt_hs'.threads[tid];\n      }\n      assert hs'.threads == alt_hs'.threads;\n      assert hs'.mem == alt_hs'.mem;\n      assert hs' == alt_hs';\n      assert H.Armada_Next_Update_1_main(hs, hs', tid);\n    } else {\n      assert !H.Armada_CrashAvoidance_Update_1_main(hs, tid);\n    }\n  }\n\n  lemma lemma_LiftNext_Terminate_main(wr: WRequest, ls: LState, ls':LState, lstep: L.Armada_TraceEntry)\n    requires wr == GetWeakeningRequest()\n    requires L.Armada_NextOneStep(ls, ls', lstep)\n    requires lstep.Armada_TraceEntry_Terminate_main?\n    ensures H.Armada_NextOneStep(ConvertTotalState_LH(ls), ConvertTotalState_LH(ls'), ConvertTraceEntry_LH(lstep))\n  {\n    var hs := wr.converter(ls);\n    var hs' := wr.converter(ls');\n    var tid := lstep.tid;\n    var hstep := ConvertTraceEntry_LH(lstep);\n    lemma_GetThreadLocalViewAlwaysCommutesWithConvert();\n    lemma_StoreBufferAppendAlwaysCommutesWithConvert();\n    assert H.Armada_ValidStep_Terminate_main(hs, tid);\n    if L.Armada_CrashAvoidance_Terminate_main(ls, tid) {\n      assert H.Armada_CrashAvoidance_Terminate_main(hs, tid);\n      var alt_hs' := H.Armada_GetNextState_Terminate_main(hs, tid);\n      assert hs'.ok == alt_hs'.ok;\n      assert hs'.log == alt_hs'.log;\n      if tid in hs'.threads {\n        assert hs'.threads[tid] == alt_hs'.threads[tid];\n      }\n      assert hs'.threads == alt_hs'.threads;\n      assert hs'.mem == alt_hs'.mem;\n      assert hs' == alt_hs';\n      assert H.Armada_Next_Terminate_main(hs, hs', tid);\n    } else {\n      assert !H.Armada_CrashAvoidance_Terminate_main(hs, tid);\n    }\n\n  }\n\n  lemma lemma_LiftNext_Tau(wr: WRequest, ls: LState, ls':LState, lstep: L.Armada_TraceEntry)\n    requires wr == GetWeakeningRequest()\n    requires L.Armada_NextOneStep(ls, ls', lstep)\n    requires lstep.Armada_TraceEntry_Tau?\n    ensures H.Armada_NextOneStep(ConvertTotalState_LH(ls), ConvertTotalState_LH(ls'), ConvertTraceEntry_LH(lstep))\n  {\n    var hs := wr.converter(ls);\n    var hs' := wr.converter(ls');\n    var tid := lstep.tid;\n    var hstep := ConvertTraceEntry_LH(lstep);\n    var lentry := ls.threads[tid].storeBuffer[0];\n    assert H.Armada_ValidStep_Tau(hs, tid);\n    assert H.Armada_CrashAvoidance_Tau(hs, tid);\n    var hentry := hs.threads[tid].storeBuffer[0];\n    var lmem := ls.mem;\n    var hmem1 := ConvertSharedMemory_LH(L.Armada_ApplyStoreBufferEntry(lmem, lentry));\n    var hmem2 := H.Armada_ApplyStoreBufferEntry(ConvertSharedMemory_LH(lmem), hentry);\n    lemma_ApplyStoreBufferEntryCommutesWithConvert(lmem, lentry, hentry, hmem1, hmem2);\n    var alt_hs' := H.Armada_GetNextState_Tau(hs, tid);\n    assert hmem1 == hmem2;\n    assert hs'.threads[tid].storeBuffer == alt_hs'.threads[tid].storeBuffer;\n    assert hs'.threads[tid] == alt_hs'.threads[tid];\n    assert hs'.threads == alt_hs'.threads;\n    assert hs' == alt_hs';\n    assert H.Armada_Next_Tau(hs, hs', tid);\n  }\n\n  lemma lemma_LNextOneImpliesHNextOne(ls:LState, ls':LState, hs:HState, hs':HState,\n    lentry:L.Armada_TraceEntry, hentry:H.Armada_TraceEntry)\n    \n    requires L.Armada_NextOneStep(ls, ls', lentry)\n    requires hs == ConvertTotalState_LH(ls)\n    requires hs' == ConvertTotalState_LH(ls')\n    requires hentry == ConvertTraceEntry_LH(lentry)\n    ensures H.Armada_NextOneStep(hs, hs', hentry)\n  {\n    var wr := GetWeakeningRequest();\n    match lentry {\n      case Armada_TraceEntry_Update_0_main(tid: Armada_ThreadHandle) =>\n        lemma_LiftNext_Update_0_main(wr, ls, ls', lentry);\n      case Armada_TraceEntry_Update_1_main(tid: Armada_ThreadHandle) =>\n        lemma_LiftNext_Update_1_main(wr, ls, ls', lentry);\n      case Armada_TraceEntry_Terminate_main(tid: Armada_ThreadHandle) =>\n        lemma_LiftNext_Terminate_main(wr, ls, ls', lentry);\n      case Armada_TraceEntry_Tau(tid: Armada_ThreadHandle) =>\n        lemma_LiftNext_Tau(wr, ls, ls', lentry);\n    }\n  }\n\n  lemma lemma_LNextMultipleImpliesHNextMultiple(wr: WRequest, ls: LState, ls': LState, steps: seq<L.Armada_TraceEntry>)\n    requires wr == GetWeakeningRequest()\n    requires ls in wr.inv\n    requires L.Armada_NextMultipleSteps(ls, ls', steps)\n    ensures H.Armada_NextMultipleSteps(ConvertTotalState_LH(ls),  ConvertTotalState_LH(ls'), MapSeqToSeq(steps, ConvertTraceEntry_LH))\n    decreases |steps|\n  {\n    if |steps| == 0 {\n      return;\n    }\n\n    var ls_next := L.Armada_GetNextStateAlways(ls, steps[0]);\n    var hs, hs_next, hs' := ConvertTotalState_LH(ls), ConvertTotalState_LH(ls_next), ConvertTotalState_LH(ls');\n    var hsteps := MapSeqToSeq(steps, ConvertTraceEntry_LH);\n    \n    lemma_LNextMultipleImpliesHNextMultiple(wr, ls_next, ls', steps[1..]);\n    assert H.Armada_NextMultipleSteps(ConvertTotalState_LH(ls_next), ConvertTotalState_LH(ls'), MapSeqToSeq(steps[1..], ConvertTraceEntry_LH));\n    assert MapSeqToSeq(steps[1..], ConvertTraceEntry_LH) == MapSeqToSeq(steps, ConvertTraceEntry_LH)[1..] == hsteps[1..];\n    assert H.Armada_NextMultipleSteps(hs_next, hs', hsteps[1..]); \n    lemma_LNextOneImpliesHNextOne(ls, ls_next, hs, hs_next, steps[0], hsteps[0]); \n  }\n\n  lemma lemma_IntermediateStatesNonyielding(wr: WRequest, ls: LState, ls': LState, hs: HState, hs': HState, lsteps: seq<L.Armada_TraceEntry>, hsteps: seq<H.Armada_TraceEntry>, tid: Armada_ThreadHandle, tau: bool, lstates: seq<L.Armada_TotalState>)\n    requires wr == GetWeakeningRequest()\n    requires ls in wr.inv\n    requires L.Armada_NextMultipleSteps(ls, ls', lsteps)\n    requires tid in ls.threads ==> !L.Armada_IsNonyieldingPC(ls.threads[tid].pc)\n    requires tid in ls'.threads ==> !L.Armada_IsNonyieldingPC(ls'.threads[tid].pc)\n    requires forall step :: step in lsteps ==> step.tid == tid\n    requires forall step :: step in lsteps ==> step.Armada_TraceEntry_Tau? == tau\n    requires lstates == L.Armada_GetStateSequence(ls, lsteps)\n    requires forall i :: 0 < i < |lsteps| ==> tid in lstates[i].threads && L.Armada_IsNonyieldingPC(lstates[i].threads[tid].pc)\n    requires hs == ConvertTotalState_LH(ls)\n    requires hs' == ConvertTotalState_LH(ls')\n    requires hsteps == MapSeqToSeq(lsteps, ConvertTraceEntry_LH)\n    requires H.Armada_NextMultipleSteps(hs, hs', hsteps)\n    requires forall step :: step in hsteps ==> step.tid == tid\n    requires forall step :: step in hsteps ==> step.Armada_TraceEntry_Tau? == tau\n    ensures var hstates := H.Armada_GetStateSequence(hs, hsteps); forall i :: 0 < i < |hsteps| ==> tid in hstates[i].threads && H.Armada_IsNonyieldingPC(hstates[i].threads[tid].pc)\n    ensures tid in hs'.threads ==> !H.Armada_IsNonyieldingPC(hs'.threads[tid].pc)\n  {\n  }\n\n  lemma lemma_LNextImpliesHNext(ls:LState, ls':LState, lstep:LStep)\n    requires L.Armada_Next(ls, ls', lstep)\n    ensures H.Armada_Next(ConvertTotalState_LH(ls), ConvertTotalState_LH(ls'), GetWeakeningRequest().step_refiner(lstep))\n  {\n    var hs, hs' := ConvertTotalState_LH(ls), ConvertTotalState_LH(ls');\n    var hstep := GetWeakeningRequest().step_refiner(lstep);\n\n    lemma_LNextMultipleImpliesHNextMultiple(GetWeakeningRequest(), ls, ls', lstep.steps);\n    assert H.Armada_NextMultipleSteps(ConvertTotalState_LH(ls), ConvertTotalState_LH(ls'), hstep.steps);\n\n    assert (hstep.tid in hs.threads ==>\n      !H.Armada_IsNonyieldingPC(hs.threads[hstep.tid].pc));\n\n    assert (hstep.tid in hs'.threads ==>\n      !H.Armada_IsNonyieldingPC(hs'.threads[hstep.tid].pc));\n\n    assert (forall step :: \n      step in hstep.steps ==>\n      step.tid == hstep.tid);\n\n    var states := H.Armada_GetStateSequence(hs, hstep.steps);\n\n    assert (forall step :: \n      step in lstep.steps ==>\n      step.Armada_TraceEntry_Tau? == lstep.tau);\n\n    forall i |\n      0 <= i < |hstep.steps|\n      ensures hstep.steps[i].Armada_TraceEntry_Tau? == hstep.tau\n    {\n      assert lstep.steps[i].Armada_TraceEntry_Tau? == lstep.tau;\n      assert hstep.steps[i].Armada_TraceEntry_Tau? == lstep.steps[i].Armada_TraceEntry_Tau?;\n    }\n\n    var wr := GetWeakeningRequest();\n    lemma_IntermediateStatesNonyielding(wr, ls, ls', hs, hs', lstep.steps, hstep.steps, lstep.tid, lstep.tau, L.Armada_GetStateSequence(ls, lstep.steps));\n  }\n\n  lemma lemma_AllActionsLiftableWeakened()\n    ensures WeakeningSpecModule.AllActionsLiftableWeakened(GetWeakeningRequest())\n  {\n    var wr := GetWeakeningRequest();\n\n    forall s, s', lstep |\n      && ActionTuple(s, s', lstep) in wr.lspec.next\n      && s in wr.inv\n      ensures ActionTuple(wr.converter(s), wr.converter(s'), wr.step_refiner(lstep)) in wr.hspec.next;\n    {\n      lemma_LNextImpliesHNext(s, s', lstep);\n    }\n  }\n\n  lemma lemma_LInitImpliesHInit(ls:LState, hs:HState, lconf:L.Armada_Config, hconf:H.Armada_Config)\n    requires L.Armada_Init(ls, lconf)\n    requires hs == ConvertTotalState_LH(ls)\n    requires hconf == ConvertConfig_LH(lconf)\n    ensures H.Armada_Init(hs, hconf)\n  {\n  }\n\n  lemma lemma_InitStatesEquivalent(wr:WRequest)\n    requires wr == GetWeakeningRequest()\n    ensures InitStatesEquivalent(wr)\n  {\n    forall initial_ls | initial_ls in wr.lspec.init\n      ensures wr.converter(initial_ls) in wr.hspec.init\n    {\n      assert exists config :: L.Armada_Init(initial_ls, config);\n      var lconf :| L.Armada_Init(initial_ls, lconf);\n      lemma_LInitImpliesHInit(initial_ls, ConvertTotalState_LH(initial_ls), lconf, ConvertConfig_LH(lconf));\n    }\n  }\n\n  lemma lemma_ProveRefinementViaVarHiding()\n    ensures SpecRefinesSpec(L.Armada_Spec(), H.Armada_Spec(), GetLHRefinementRelation())\n  {\n    var lspec := L.Armada_Spec();\n    var hspec := H.Armada_Spec();\n    var wr := GetWeakeningRequest();\n    \n    forall lb | BehaviorSatisfiesSpec(lb, lspec)\n      ensures BehaviorRefinesSpec(lb, hspec, GetLHRefinementRelation())\n    {\n      var alb := lemma_GetLAnnotatedBehavior(lb);\n\n      lemma_InitStatesEquivalent(wr);\n      lemma_AllActionsLiftableWeakened();\n      \n      assert ValidWeakeningRequest(wr);\n      var ahb := lemma_PerformWeakening(wr, alb);\n      lemma_IfAnnotatedBehaviorSatisfiesSpecThenBehaviorDoes(ahb);\n    }\n  }\n}\n"
  },
  {
    "path": "Test/weakening/test.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs {\n\n}\n\nlevel A using SharedStructs {\n    noaddr var x:int32;\n\n    method main()\n    {\n        x := 3;\n        assume x == 3;\n        x := x + 1;\n    }\n}\n\nlevel B using SharedStructs {\n    noaddr var x:int32;\n\n    method main()\n    {\n        x := 3;\n        assume x >= 3;\n        x := x + 1;\n    }\n}\n\nproof AB {\n    refinement A B\n    weakening\n}\n"
  },
  {
    "path": "Test/weakening/test2.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs2 {\n\n}\n\nlevel C using SharedStructs2 {\n  ghost var x:int32 := 0;\n\n  method t1()\n  {\n    atomic {\n      x ::= 1;\n      x ::= 2;\n    }\n  }\n\n  method t2()\n  {\n    if (x == 1) {\n      x ::= 3;\n    }\n  }\n\n  method {:atomic} recur()\n  {\n    atomic {\n      x ::= x;\n      if (*) {\n        recur();\n      }\n    }\n  }\n\n  method main()\n  {\n    create_thread t1();\n    create_thread t2();\n  }\n\n  invariant XNotOne\n  {\n    x != 1\n  }\n}\n\nlevel D using SharedStructs2 {\n  ghost var x:int32 := 0;\n\n  method t1()\n  {\n    atomic {\n      x ::= 1;\n      x ::= 2;\n    }\n  }\n\n  method t2()\n  {\n    if (false) {\n      x ::= 3;\n    }\n  }\n\n  method {:atomic} recur()\n  {\n    atomic {\n      x ::= x;\n      if (*) {\n        recur();\n      }\n    }\n  }\n\n  method main()\n  {\n    create_thread t1();\n    create_thread t2();\n  }\n}\n\nproof CD {\n  refinement C D\n  weakening\n  inductive_invariant {:opaque} XNotOne\n}\n"
  },
  {
    "path": "Test/weakening/test3.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs3 {\n\n}\n\nlevel E using SharedStructs3 {\n    ghost var x:int;\n    ghost var y:int;\n\n    method main()\n    {\n        label lb:\n        y := (x + 1) * (x + 1);\n    }\n}\n\nlevel F using SharedStructs3 {\n    ghost var x:int;\n    ghost var y:int;\n\n    method main()\n    {\n        y := x * x + x * 2 + 1;\n    }\n}\n\nproof EF {\n    refinement E F\n    weakening\n\n    include_file \"ArithmeticFacts.dfy\" which_includes \"EF/specs.dfy\"\n    import_module ArithmeticFactsModule which_imports ArmadaModule_specs\n    extra lemma_LiftAtomicPath_From_main_lb_To_main_End \"ArithmeticFactsModule.lemma_Equivalence(ls.s.ghosts.x as int);\"\n}\n"
  },
  {
    "path": "experimental/.gitignore",
    "content": "Binary/\n.sconsign.dblite\n.DS_Store\n.vscode/\n_*/\n**/TAGS\n\n"
  },
  {
    "path": "experimental/EditorPlugins/mle-vscode/.eslintrc.json",
    "content": "{\n    \"root\": true,\n    \"parser\": \"@typescript-eslint/parser\",\n    \"parserOptions\": {\n        \"ecmaVersion\": 6,\n        \"sourceType\": \"module\"\n    },\n    \"plugins\": [\n        \"@typescript-eslint\"\n    ],\n    \"rules\": {\n        \"@typescript-eslint/naming-convention\": \"warn\",\n        \"@typescript-eslint/semi\": \"warn\",\n        \"curly\": \"warn\",\n        \"eqeqeq\": \"warn\",\n        \"no-throw-literal\": \"warn\",\n        \"semi\": \"off\"\n    },\n    \"ignorePatterns\": [\n        \"out\",\n        \"dist\",\n        \"**/*.d.ts\"\n    ]\n}\n"
  },
  {
    "path": "experimental/EditorPlugins/mle-vscode/.gitignore",
    "content": "out\ndist\nnode_modules\n.vscode-test/\n*.vsix\n"
  },
  {
    "path": "experimental/EditorPlugins/mle-vscode/.vscodeignore",
    "content": ".vscode/**\n.vscode-test/**\nsrc/**\n.gitignore\n.yarnrc\nvsc-extension-quickstart.md\n**/tsconfig.json\n**/.eslintrc.json\n**/*.map\n**/*.ts\n"
  },
  {
    "path": "experimental/EditorPlugins/mle-vscode/changelog.md",
    "content": "# Change Log\n\nAll notable changes to the \"starmada\" extension will be documented in this file.\n\nCheck [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.\n\n## [Unreleased]\n\n- Initial release"
  },
  {
    "path": "experimental/EditorPlugins/mle-vscode/notes.md",
    "content": "# Notes for VSCode extension development\n\n## Logging\n\n```ts\n// Use the console to output diagnostic information (console.log) and errors (console.error)\nconsole.log('Congratulations, your extension \"starmada\" is now active!');\n```\n\n## Window\n"
  },
  {
    "path": "experimental/EditorPlugins/mle-vscode/package.json",
    "content": "{\n  \"name\": \"starmada-mle\",\n  \"displayName\": \"Starmada MLE\",\n  \"description\": \"Starmada multi-level editor that provides multi-level refactoring utilities.\",\n  \"repository\": \"https://github.com/GLaDOS-Michigan/starmada\",\n  \"publisher\": \"starmada-team\",\n  \"version\": \"0.1.0\",\n  \"engines\": {\n    \"vscode\": \"^1.65.0\"\n  },\n  \"categories\": [\n    \"Other\"\n  ],\n  \"activationEvents\": [\n    \"onCommand:starmada.backup\",\n    \"onCommand:starmada.extract\",\n    \"onCommand:starmada.apply\",\n    \"onCommand:starmada.restore\",\n    \"onView:starmada.refactorView\"\n  ],\n  \"main\": \"./out/extension.js\",\n  \"contributes\": {\n    \"commands\": [\n      {\n        \"command\": \"starmada.backup\",\n        \"title\": \"Starmada: Backup\"\n      },\n      {\n        \"command\": \"starmada.extract\",\n        \"title\": \"Starmada: Extract\"\n      },\n      {\n        \"command\": \"starmada.apply\",\n        \"title\": \"Starmada: Apply\"\n      },\n      {\n        \"command\": \"starmada.restore\",\n        \"title\": \"Starmada: Restore\"\n      }\n    ],\n    \"configuration\": {\n      \"title\": \"Starmada\",\n      \"properties\": {\n        \"starmada.path.serverPath\": {\n          \"type\": \"string\",\n          \"default\": \"\",\n          \"description\": \"Specifies the server binary's path.\"\n        }\n      }\n    },\n    \"viewsContainers\": {\n      \"activitybar\": [\n        {\n          \"id\": \"starmada-mle\",\n          \"title\": \"Starmada MLE\",\n          \"icon\": \"resources/starmada-mle.svg\"\n        }\n      ]\n    },\n    \"views\": {\n      \"starmada-mle\": [\n        {\n\t\t\t\t\t\"type\": \"webview\",\n          \"id\": \"starmada.refactorView\",\n          \"name\": \"Refactor\"\n        }\n      ]\n    }\n  },\n  \"scripts\": {\n    \"vscode:prepublish\": \"npm run compile\",\n    \"compile\": \"tsc -p ./\",\n    \"watch\": \"tsc -watch -p ./\",\n    \"pretest\": \"npm run compile && npm run lint\",\n    \"lint\": \"eslint src --ext ts\",\n    \"test\": \"node ./out/test/runTest.js\"\n  },\n  \"devDependencies\": {\n    \"@types/vscode\": \"^1.65.0\",\n    \"@types/glob\": \"^7.2.0\",\n    \"@types/mocha\": \"^9.1.0\",\n    \"@types/node\": \"14.x\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.12.1\",\n    \"@typescript-eslint/parser\": \"^5.12.1\",\n    \"eslint\": \"^8.9.0\",\n    \"glob\": \"^7.2.0\",\n    \"mocha\": \"^9.2.1\",\n    \"typescript\": \"^4.5.5\",\n    \"@vscode/test-electron\": \"^2.1.2\"\n  }\n}"
  },
  {
    "path": "experimental/EditorPlugins/mle-vscode/readme.md",
    "content": "# Starmada MLE\n\nStarmada Multi-Level Editor. Refactor multiple levels in a flash.\n\n## Requirements\n\nThe editor backend installed, and the path to its binary properly set in the settings.\n"
  },
  {
    "path": "experimental/EditorPlugins/mle-vscode/src/extension.ts",
    "content": "import { ExtensionContext, commands, window } from \"vscode\";\nimport RefactorViewProvider from \"./refactor-view\";\n\n// this method is called when your extension is activated\nexport function activate(context: ExtensionContext) {\n  const provider = new RefactorViewProvider(context.extensionUri);\n\n  context.subscriptions.push(\n    window.registerWebviewViewProvider(\n      RefactorViewProvider.viewId,\n      provider\n    )\n  );\n\n  context.subscriptions.push(\n    commands.registerCommand(\"starmada.backup\", () => {\n      RefactorViewProvider.backup();\n    })\n  );\n\n  context.subscriptions.push(\n    commands.registerCommand(\"starmada.extract\", () => {\n      provider.extract();\n    })\n  );\n\n  context.subscriptions.push(\n    commands.registerCommand(\"starmada.apply\", () => {\n      RefactorViewProvider.apply();\n    })\n  );\n\n  context.subscriptions.push(\n    commands.registerCommand(\"starmada.restore\", () => {\n      RefactorViewProvider.restore();\n    })\n  );\n}\n\n// this method is called when your extension is deactivated\nexport function deactivate() {}\n"
  },
  {
    "path": "experimental/EditorPlugins/mle-vscode/src/refactor-view.ts",
    "content": "import * as vscode from \"vscode\";\nimport { exec } from \"child_process\";\nimport {\n  getCmdHead,\n  getActiveFilePath,\n  getActivePosition,\n  openCandidates,\n  getCandidatesUri,\n} from \"./utils\";\n\nclass RefactorViewProvider implements vscode.WebviewViewProvider {\n  public static readonly viewId = \"starmada.refactorView\";\n\n  private _state: {\n    llevel: string;\n    hlevel: string;\n  };\n\n  constructor(private readonly _extensionUri: vscode.Uri) {\n    this._state = {\n      llevel: \"\",\n      hlevel: \"\",\n    };\n  }\n\n  public static backup() {\n    const cmd = `${getCmdHead()} backup`;\n    console.log(cmd);\n    exec(cmd, (err, _out, _) => {\n      if (err) {\n        console.log(err);\n      }\n      return;\n    });\n  }\n\n  public extract() {\n    const lv = (lv: string, pre: string) => {\n      return lv === \"\" ? \"\" : ` ${pre} ${lv}`;\n    };\n    const llv = lv(this._state.llevel, \"-l\");\n    const hlv = lv(this._state.hlevel, \"-h\");\n    const cmd =\n      `${getCmdHead()} extract -f ${getActiveFilePath()} -p ${getActivePosition()}` +\n      llv +\n      hlv;\n    console.log(cmd);\n    exec(cmd, (err, _out, _) => {\n      if (err) {\n        console.log(err);\n      }\n      return;\n    });\n  }\n\n  public static apply() {\n    const cmd = `${getCmdHead()} apply`;\n    console.log(cmd);\n    exec(cmd, (err, _out, _) => {\n      if (err) {\n        console.log(err);\n      }\n      return;\n    });\n  }\n\n  public static restore() {\n    const cmd = `${getCmdHead()} restore`;\n    console.log(cmd);\n    exec(cmd, (err, _out, _) => {\n      if (err) {\n        console.log(err);\n      }\n      return;\n    });\n  }\n\n  public resolveWebviewView(\n    webviewView: vscode.WebviewView,\n    context: vscode.WebviewViewResolveContext,\n    _token: vscode.CancellationToken\n  ) {\n    webviewView.webview.options = {\n      // Allow scripts in the webview\n      enableScripts: true,\n\n      localResourceRoots: [this._extensionUri],\n    };\n\n    webviewView.webview.html = this._getHtmlForWebview(webviewView.webview);\n\n    webviewView.webview.onDidReceiveMessage((data) => {\n      switch (data.type) {\n        case \"onChange\": {\n          console.log(\"onChange\");\n          this._state = data.value;\n          console.log(this._state);\n          break;\n        }\n        case \"onExtract\": {\n          RefactorViewProvider.backup();\n          this.extract();\n          openCandidates();\n          break;\n        }\n        case \"onApply\": {\n          RefactorViewProvider.apply();\n          break;\n        }\n        case \"onRestore\": {\n          RefactorViewProvider.restore();\n          break;\n        }\n      }\n    });\n  }\n\n  private _getHtmlForWebview(webview: vscode.Webview) {\n    // Get the local path to main script run in the webview, then convert it to a uri we can use in the webview.\n    const scriptUri = webview.asWebviewUri(\n      vscode.Uri.joinPath(this._extensionUri, \"view\", \"main.js\")\n    );\n\n    // Do the same for the stylesheet.\n    const styleResetUri = webview.asWebviewUri(\n      vscode.Uri.joinPath(this._extensionUri, \"view\", \"reset.css\")\n    );\n    const styleVSCodeUri = webview.asWebviewUri(\n      vscode.Uri.joinPath(this._extensionUri, \"view\", \"vscode.css\")\n    );\n    const styleMainUri = webview.asWebviewUri(\n      vscode.Uri.joinPath(this._extensionUri, \"view\", \"main.css\")\n    );\n\n    // Use a nonce to only allow a specific script to be run.\n    const nonce = getNonce();\n\n    return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n\n  <!--\n    Use a content security policy to only allow loading images from https or from our extension directory,\n    and only allow scripts that have a specific nonce.\n  -->\n  <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'none'; style-src ${webview.cspSource}; script-src 'nonce-${nonce}';\">\n\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n\n  <link href=\"${styleResetUri}\" rel=\"stylesheet\">\n  <link href=\"${styleVSCodeUri}\" rel=\"stylesheet\">\n  <link href=\"${styleMainUri}\" rel=\"stylesheet\">\n    \n  <title>Starmada Refactor Panel</title>\n</head>\n<body>\n  <h3>Level Range</h3>\n  <span>Low Level</span>\n  <input id=\"llevel\" class=\"level-input\"/>\n\n  <span>High Level</span>\n  <input id=\"hlevel\" class=\"level-input\"/>\n\n  <div></div>\n\n  <h3>Actions</h3>\n\n  <button id=\"extract-btn\" class=\"op-btn\">\n    <span class=\"sym\">⊣ </span>\n    <span class=\"txt\">Extract</span>\n  </button>\n  <button id=\"apply-btn\" class=\"op-btn\">\n    <span class=\"sym\">☑ </span>\n    <span class=\"txt\">Apply</span>\n  </button>\n  <button id=\"restore-btn\" class=\"op-btn\">\n    <span class=\"sym\">⦾ </span>\n    <span class=\"txt\">Restore</span>\n  </button>\n\n  <script nonce=\"${nonce}\" src=\"${scriptUri}\"></script>\n</body>\n</html>`;\n  }\n}\n\nfunction getNonce() {\n  let text = \"\";\n  const possible =\n    \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\";\n  for (let i = 0; i < 32; i++) {\n    text += possible.charAt(Math.floor(Math.random() * possible.length));\n  }\n  return text;\n}\n\nlet candidateOpens = false;\n\nvscode.window.onDidChangeVisibleTextEditors(\n  (data: readonly vscode.TextEditor[]) => {\n    let candidateDoc = data.find(\n      (e: vscode.TextEditor) => e.document.uri.path === getCandidatesUri().path\n    );\n    if (!candidateOpens && candidateDoc) {\n      candidateOpens = true;\n    } else if (candidateOpens && !candidateDoc) {\n      RefactorViewProvider.apply();\n      candidateOpens = false;\n    }\n  }\n);\n\nexport default RefactorViewProvider;\n"
  },
  {
    "path": "experimental/EditorPlugins/mle-vscode/src/test/runTest.ts",
    "content": "import * as path from 'path';\n\nimport { runTests } from '@vscode/test-electron';\n\nasync function main() {\n\ttry {\n\t\t// The folder containing the Extension Manifest package.json\n\t\t// Passed to `--extensionDevelopmentPath`\n\t\tconst extensionDevelopmentPath = path.resolve(__dirname, '../../');\n\n\t\t// The path to test runner\n\t\t// Passed to --extensionTestsPath\n\t\tconst extensionTestsPath = path.resolve(__dirname, './suite/index');\n\n\t\t// Download VS Code, unzip it and run the integration test\n\t\tawait runTests({ extensionDevelopmentPath, extensionTestsPath });\n\t} catch (err) {\n\t\tconsole.error('Failed to run tests');\n\t\tprocess.exit(1);\n\t}\n}\n\nmain();\n"
  },
  {
    "path": "experimental/EditorPlugins/mle-vscode/src/test/suite/extension.test.ts",
    "content": "import * as assert from 'assert';\n\n// You can import and use all API from the 'vscode' module\n// as well as import your extension to test it\nimport * as vscode from 'vscode';\n// import * as myExtension from '../../extension';\n\nsuite('Extension Test Suite', () => {\n\tvscode.window.showInformationMessage('Start all tests.');\n\n\ttest('Sample test', () => {\n\t\tassert.strictEqual(-1, [1, 2, 3].indexOf(5));\n\t\tassert.strictEqual(-1, [1, 2, 3].indexOf(0));\n\t});\n});\n"
  },
  {
    "path": "experimental/EditorPlugins/mle-vscode/src/test/suite/index.ts",
    "content": "import * as path from 'path';\nimport * as Mocha from 'mocha';\nimport * as glob from 'glob';\n\nexport function run(): Promise<void> {\n\t// Create the mocha test\n\tconst mocha = new Mocha({\n\t\tui: 'tdd',\n\t\tcolor: true\n\t});\n\n\tconst testsRoot = path.resolve(__dirname, '..');\n\n\treturn new Promise((c, e) => {\n\t\tglob('**/**.test.js', { cwd: testsRoot }, (err, files) => {\n\t\t\tif (err) {\n\t\t\t\treturn e(err);\n\t\t\t}\n\n\t\t\t// Add files to the test suite\n\t\t\tfiles.forEach(f => mocha.addFile(path.resolve(testsRoot, f)));\n\n\t\t\ttry {\n\t\t\t\t// Run the mocha test\n\t\t\t\tmocha.run(failures => {\n\t\t\t\t\tif (failures > 0) {\n\t\t\t\t\t\te(new Error(`${failures} tests failed.`));\n\t\t\t\t\t} else {\n\t\t\t\t\t\tc();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t} catch (err) {\n\t\t\t\tconsole.error(err);\n\t\t\t\te(err);\n\t\t\t}\n\t\t});\n\t});\n}\n"
  },
  {
    "path": "experimental/EditorPlugins/mle-vscode/src/utils.ts",
    "content": "import { window, Position, workspace, Uri, commands } from \"vscode\";\n\nexport const getServerPath = (): string => {\n  const p: string | undefined = workspace\n    .getConfiguration(\"starmada.path\")\n    .get(\"serverPath\");\n  if (!p) {\n    throw new Error(\"ServerPath must be assigned.\");\n  }\n  return p;\n};\n\nexport const getWorkspacePath = (): string => {\n  let p = workspace.workspaceFolders?.[0].uri.path;\n  if (!p) {\n    throw new Error(\"Must be in a workspace.\");\n  }\n  return p;\n};\n\nexport const getCmdHead = (): string => {\n  const serverPath = getServerPath();\n  const wsPath = getWorkspacePath();\n  const cmd = `cd ${wsPath} && ${serverPath}`;\n  return cmd;\n};\n\nexport const getActiveFilePath = (): string => {\n  let p = window.activeTextEditor?.document.uri.path;\n  if (!p) {\n    throw new Error(\"Must be in a file.\");\n  }\n  return p;\n};\n\nexport const getActivePosition = (): string => {\n  const editor = window.activeTextEditor;\n  if (!editor) {\n    throw new Error(\"Must be in an active editor.\");\n  }\n  const selection = editor.selection;\n\n  const posToStr = (pos: Position) => `${pos.line + 1}:${pos.character + 1}`;\n\n  const start = posToStr(selection.start);\n  const end = posToStr(selection.end);\n  return start === end ? `${start}` : `${start}-${end}`;\n};\n\nexport const getCandidatesUri = (): Uri => {\n  const uri = Uri.joinPath(\n    Uri.file(getWorkspacePath()),\n    \".build\",\n    \"candidates\"\n  );\n  return uri;\n};\n\nexport const openCandidates = (): void => {\n  const uri = getCandidatesUri();\n  commands.executeCommand(\"vscode.open\", uri);\n};\n"
  },
  {
    "path": "experimental/EditorPlugins/mle-vscode/tsconfig.json",
    "content": "{\n\t\"compilerOptions\": {\n\t\t\"module\": \"commonjs\",\n\t\t\"target\": \"ES2020\",\n\t\t\"outDir\": \"out\",\n\t\t\"lib\": [\n\t\t\t\"ES2020\"\n\t\t],\n\t\t\"sourceMap\": true,\n\t\t\"rootDir\": \"src\",\n\t\t\"strict\": true   /* enable all strict type-checking options */\n\t\t/* Additional Checks */\n\t\t// \"noImplicitReturns\": true, /* Report error when not all code paths in function return a value. */\n\t\t// \"noFallthroughCasesInSwitch\": true, /* Report errors for fallthrough cases in switch statement. */\n\t\t// \"noUnusedParameters\": true,  /* Report errors on unused parameters. */\n\t}\n}\n"
  },
  {
    "path": "experimental/EditorPlugins/mle-vscode/view/main.css",
    "content": "body {\n\tbackground-color: transparent;\n}\n\n.op-btn {\n\tdisplay: block;\n\tborder: none;\n\t/* margin: 0 auto; */\n}\n\n.sym {\n\tfont-size: large;\n}\n\n.txt {\n\tdisplay: inline-block;\n\twidth: 20%;\n\ttext-align: left;\n}"
  },
  {
    "path": "experimental/EditorPlugins/mle-vscode/view/main.js",
    "content": "// @ts-nocheck\n\n// This script will be run within the webview itself\n// It cannot access the main VS Code APIs directly.\n(function () {\n    const vscode = acquireVsCodeApi();\n\n    const state = vscode.getState() || { llevel: \"\", hlevel: \"\" };\n\n    updateState(state);\n\n    document.querySelector('.level-input').addEventListener('input', () => {\n        const state = onChange();\n        updateState(state);\n    });\n\n    function addBtnListener(selector, then) {\n        document.querySelector(selector).addEventListener('click', then);\n    }\n\n    addBtnListener('#extract-btn', postMessageVoid(\"onExtract\"));\n    addBtnListener('#apply-btn', postMessageVoid(\"onApply\"));\n    addBtnListener('#restore-btn', postMessageVoid(\"onRestore\"));\n\n    function updateState(state) {\n        // Update the saved state\n        vscode.setState(state);\n    }\n\n    function onChange() {\n        const state = {\n            llevel: document.querySelector('#llevel').value,\n            hlevel: document.querySelector('#hlevel').value\n        };\n        vscode.postMessage({ type: 'onChange', value: state });\n        return state;\n    }\n\n    function postMessageVoid(type) {\n        return () => vscode.postMessage({ type: type, value: {} });\n    }\n}());\n\n\n"
  },
  {
    "path": "experimental/EditorPlugins/mle-vscode/view/reset.css",
    "content": "html {\n\tbox-sizing: border-box;\n\tfont-size: 13px;\n}\n\n*,\n*:before,\n*:after {\n\tbox-sizing: inherit;\n}\n\nbody,\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\np,\nol,\nul {\n\tmargin: 0;\n\tpadding: 0;\n\tfont-weight: normal;\n}\n\nimg {\n\tmax-width: 100%;\n\theight: auto;\n}\n"
  },
  {
    "path": "experimental/EditorPlugins/mle-vscode/view/vscode.css",
    "content": ":root {\n\t--container-paddding: 20px;\n\t--input-padding-vertical: 6px;\n\t--input-padding-horizontal: 4px;\n\t--input-margin-vertical: 4px;\n\t--input-margin-horizontal: 0;\n}\n\nbody {\n\tpadding: 0 var(--container-paddding);\n\tcolor: var(--vscode-foreground);\n\tfont-size: var(--vscode-font-size);\n\tfont-weight: var(--vscode-font-weight);\n\tfont-family: var(--vscode-font-family);\n\tbackground-color: var(--vscode-editor-background);\n}\n\nol,\nul {\n\tpadding-left: var(--container-paddding);\n}\n\nbody > *,\nform > * {\n\tmargin-block-start: var(--input-margin-vertical);\n\tmargin-block-end: var(--input-margin-vertical);\n}\n\n*:focus {\n\toutline-color: var(--vscode-focusBorder) !important;\n}\n\na {\n\tcolor: var(--vscode-textLink-foreground);\n}\n\na:hover,\na:active {\n\tcolor: var(--vscode-textLink-activeForeground);\n}\n\ncode {\n\tfont-size: var(--vscode-editor-font-size);\n\tfont-family: var(--vscode-editor-font-family);\n}\n\nbutton {\n\tborder: none;\n\tpadding: var(--input-padding-vertical) var(--input-padding-horizontal);\n\twidth: 100%;\n\ttext-align: center;\n\toutline: 1px solid transparent;\n\toutline-offset: 2px !important;\n\tcolor: var(--vscode-button-foreground);\n\tbackground: var(--vscode-button-background);\n}\n\nbutton:hover {\n\tcursor: pointer;\n\tbackground: var(--vscode-button-hoverBackground);\n}\n\nbutton:focus {\n\toutline-color: var(--vscode-focusBorder);\n}\n\nbutton.secondary {\n\tcolor: var(--vscode-button-secondaryForeground);\n\tbackground: var(--vscode-button-secondaryBackground);\n}\n\nbutton.secondary:hover {\n\tbackground: var(--vscode-button-secondaryHoverBackground);\n}\n\ninput:not([type='checkbox']),\ntextarea {\n\tdisplay: block;\n\twidth: 100%;\n\tborder: none;\n\tfont-family: var(--vscode-font-family);\n\tpadding: var(--input-padding-vertical) var(--input-padding-horizontal);\n\tcolor: var(--vscode-input-foreground);\n\toutline-color: var(--vscode-input-border);\n\tbackground-color: var(--vscode-input-background);\n}\n\ninput::placeholder,\ntextarea::placeholder {\n\tcolor: var(--vscode-input-placeholderForeground);\n}\n"
  },
  {
    "path": "experimental/EditorPlugins/mle-vscode/vsc-extension-quickstart.md",
    "content": "# Welcome to your VS Code Extension\n\n## What's in the folder\n\n* This folder contains all of the files necessary for your extension.\n* `package.json` - this is the manifest file in which you declare your extension and command.\n  * The sample plugin registers a command and defines its title and command name. With this information VS Code can show the command in the command palette. It doesn’t yet need to load the plugin.\n* `src/extension.ts` - this is the main file where you will provide the implementation of your command.\n  * The file exports one function, `activate`, which is called the very first time your extension is activated (in this case by executing the command). Inside the `activate` function we call `registerCommand`.\n  * We pass the function containing the implementation of the command as the second parameter to `registerCommand`.\n\n## Get up and running straight away\n\n* Press `F5` to open a new window with your extension loaded.\n* Run your command from the command palette by pressing (`Ctrl+Shift+P` or `Cmd+Shift+P` on Mac) and typing `Hello World`.\n* Set breakpoints in your code inside `src/extension.ts` to debug your extension.\n* Find output from your extension in the debug console.\n\n## Make changes\n\n* You can relaunch the extension from the debug toolbar after changing code in `src/extension.ts`.\n* You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes.\n\n\n## Explore the API\n\n* You can open the full set of our API when you open the file `node_modules/@types/vscode/index.d.ts`.\n\n## Run tests\n\n* Open the debug viewlet (`Ctrl+Shift+D` or `Cmd+Shift+D` on Mac) and from the launch configuration dropdown pick `Extension Tests`.\n* Press `F5` to run the tests in a new window with your extension loaded.\n* See the output of the test result in the debug console.\n* Make changes to `src/test/suite/extension.test.ts` or create new test files inside the `test/suite` folder.\n  * The provided test runner will only consider files matching the name pattern `**.test.ts`.\n  * You can create folders inside the `test` folder to structure your tests any way you want.\n\n## Go further\n\n * Reduce the extension size and improve the startup time by [bundling your extension](https://code.visualstudio.com/api/working-with-extensions/bundling-extension).\n * [Publish your extension](https://code.visualstudio.com/api/working-with-extensions/publishing-extension) on the VSCode extension marketplace.\n * Automate builds by setting up [Continuous Integration](https://code.visualstudio.com/api/working-with-extensions/continuous-integration).\n"
  },
  {
    "path": "experimental/README.md",
    "content": "# Starmada\n\n## Installation\n\nStarmada requires the following prerequisites to run:\n- dotnet 6.0\n- FStar\n\nTo build and check everything, run\n```\nscons --all\n```\n\nAfter installing the above applications, you can compile Starmada using either of the following commands:\n\n```\ndotnet build Source/Armada.sln\nscons --build\n```\n\n\nIn order to generate fstar files (.fst) from .arm files, you can run the following command (N is the level of parallelism to run the commands):\n```\nscons --generate-fstar [-jN]\n```\n\nAfterwards, to verify the correctness of the generated files, and run FStar, you can run the following command:\n```\nscons --run-fstar [-jN]\n```\n\nTo verify the sample proofs that exercise the library, you can run the following command (N is the level of parallelism):\n```\nscons --verify-lib [-jN]\n```\n\n# Build using docker\n\nIn order to build Starmada using docker, you can use the following instructions:\n```\ncd docker\nsudo docker build ../ -f Dockerfile\n```"
  },
  {
    "path": "experimental/SConstruct",
    "content": "# -*- python -*-\nimport filecmp\nimport re\nimport sys\nimport os, os.path\nimport subprocess\nimport traceback\nimport pdb\nimport SCons.Util\nimport atexit\nimport platform\nimport argparse\nimport glob\n\nImport(\"*\")\n\nenv = Environment(ENV = {'PATH' : os.environ['PATH']})\nif sys.platform != 'win32' and sys.platform != 'cygwin':\n  env['DOTNET'] = 'dotnet'\n\n# def check_test_output(filename, expected):\n#     if not filecmp.cmp(filename, expected):\n#         os.system(\"rm %s\" % (filename))\n#         raise Exception(\"FAILURE: %s did not match expected %s\" % (filename, expected))\n#     os.system(\"rm %s\" % (filename))\n\n# CheckOutput = SCons.Action.ActionFactory(check_test_output, lambda x, y: \"Checking \" + x)\n\n####################################################################\n#\n#   Define Armada Builders\n#\n####################################################################\n\narmada_proj = os.path.abspath('Source/Armada.sln')\n\ndef build_armada(env):\n    if env.Execute(\"DOTNET_CLI_HOME=/tmp dotnet build %s\" % (armada_proj)):\n        print('A problem occurred while building Starmada.')\n        Exit(1)\n\ndef generate_armada_actions(source, target, env, for_signature):\n    source_path = File(source[0]).path\n\n    output_path = source_path + \".out\"\n    expect_path = source_path + \".expect\"\n    if diff_check :\n        return [\n            \"DOTNET_CLI_HOME=/tmp dotnet ./Binary/Armada.dll %s --verbose > %s\" % (source_path, output_path),\n            \"diff -wB %s %s\" % (output_path, expect_path),\n            \"rm %s\" % (output_path)\n        ]\n    elif fstar_output:\n        return [\n            \"DOTNET_CLI_HOME=/tmp dotnet ./Binary/Armada.dll %s -f -a > /dev/null\" % (source_path),\n        ]\n    else:\n        return [\n            \"DOTNET_CLI_HOME=/tmp dotnet ./Binary/Armada.dll %s > /dev/null\" % (source_path),\n        ]\n\ndef generate_fstar_actions(source, target, env, for_signature):\n    actions = []\n    for f in source:\n        actions.append(f\"fstar.exe --include lib/ --include {os.path.dirname(str(f))} {f}\")\n    return actions\n\ndef generate_verify_lib_actions(source, target, env, for_signature):\n    actions = [f\"cd lib; make verify-all\"]\n    return actions\n\ndef add_armada(env):\n    armada = Builder(generator=generate_armada_actions)\n    env.Append(BUILDERS = {'Armada' : armada})\n\ndef add_fstar(env):\n    fstar = Builder(generator=generate_fstar_actions)\n    env.Append(BUILDERS = {'FStar' : fstar})\n\ndef add_verify_lib(env):\n    verify_lib = Builder(generator=generate_verify_lib_actions)\n    env.Append(BUILDERS = {'VerifyLib' : verify_lib})\n\ndef add_diff_checker(env):\n    diff_checker = Builder(generator=generate_diff_checker)\n    env.Append(BUILDERS = {'CheckOutput' : diff_checker})\n\n####################################################################\n#\n#   Put it all together\n#\n####################################################################\n\n# If you want to run diff for a test, you need to set diff_check\n# to True\ndiff_check = False\nAddOption('--parser-tests',\n          dest='parser_tests',\n          action='store_true',\n          help='run parser tests')\n\nAddOption('--editor-tests',\n          dest='editor_tests',\n          action='store_true',\n          help='run editor tests')\n\nfstar_output = False\nAddOption('--run-fstar',\n          dest='run_fstar',\n          action='store_true',\n          help='run fstar tests')\n\ngenerate_fstar = False\nAddOption('--generate-fstar',\n          dest='generate_fstar',\n          action='store_true',\n          help='generate fstar files')\n\nverify_lib = False\nAddOption('--verify-lib',\n          dest='verify_lib',\n          action='store_true',\n          help='verify the Starmada library')\n\nAddOption('--build',\n          action='store_true',\n          help='enable building of Starmada')\n\nAddOption('--all',\n          action='store_true',\n          help='build and check everything')\n\nadd_armada(env)\nadd_fstar(env)\nadd_verify_lib(env)\n\n####################################################################\n#\n#   Create dependencies\n#\n####################################################################\n\ndef run_parser_test(dir_name, entries):\n  for armada_file in entries:\n    source = \"Tests/parser/%s/%s.arm\" % (dir_name, armada_file)\n    # target = \"Tests/parser/%s/%s\" % (dir_name, test_name)\n    env.Armada(source)\n\ndef run_editor_test(dir_name, entries):\n  for test_name in entries:\n    target = f\"Tests/editor/{dir_name}/{test_name}\"\n    test_item = target\n    proj_root = f\"{test_item}/proj\"\n    dump_root = f\"{test_item}/dump\"\n    expect_root = f\"{test_item}/expect\"\n    test_input = f\"{test_item}/in\"\n    test_arg = f\"{test_item}/arg\"\n\n    with open(test_arg, 'r') as f:\n      arguments = \"-f \" + proj_root + \"/\" + \" \".join(f.readlines())\n\n    cmds = [\n      f\"DOTNET_CLI_HOME=/tmp dotnet ./Binary/Editor.dll shoot {proj_root} -o {dump_root} {arguments} < {test_input}\",\n      f\"diff -r {dump_root} {expect_root}\",\n      f\"rm -rf {dump_root}\",\n    ]\n\n    for cmd in cmds:\n      os.system(cmd)\n\ndef run_fstar(dir_name):\n  env.FStar(glob.glob(dir_name + '/*.fst'))\n\ndef generate_fstar(dir_name):\n  files_list = glob.glob(dir_name + '/*.arm')\n  for f in files_list:\n    print(f)\n    env.Armada(f)\n\ndef verify_lib(target, source):\n  env.VerifyLib(target, source)\n\ndef shouldRun(taskName):\n  return (GetOption('all') == True) or (GetOption(taskName) == True)\n\nif shouldRun('build'):\n  build_armada(env)\n\nif shouldRun('clean'):\n  find_cmd = \"find Tests -iname '*.fst'\"\n  git_ls_cmd = \"xargs git ls-files\"\n  guard_cmd = f\"[ `{find_cmd} | {git_ls_cmd} | wc -l` = 0 ]\"\n  env.Execute(f\"{guard_cmd} && {find_cmd} | xargs rm\")\n\nif shouldRun('generate_fstar'):\n  fstar_output = True\n  for f in glob.glob(\"Tests/parser/fstar/*\"):\n    generate_fstar(f)\n  generate_fstar(\"Tests/proof/globalVarsUnmodifiable\")\n\nif shouldRun('run_fstar'):\n  for f in glob.glob(\"Tests/parser/fstar/*\"):\n    run_fstar(f)\n  run_fstar(\"Tests/proof/globalVarsUnmodifiable\")\n\nif shouldRun('parser_tests'):\n  diff_check = True\n  run_parser_test(\"includeTest\", [\n    \"A\",\n    \"B\",\n    \"C\"\n  ])\n  run_parser_test(\"AST\", [\n    \"A\",\n    # \"AB\",\n    \"B\",\n    # \"BC\",\n    \"C\",\n    # \"CD\",\n    \"D\",\n    # \"EndlessExpression\",\n    \"Statement\",\n    \"state\",\n    \"struct\",\n    \"suffix\"\n  ])\n  run_parser_test(\"TypeResolver\", [\n    \"boundedInt\"\n  ])\n\nif shouldRun('verify_lib'):\n  verify_lib(\"lib/MyProgramProof.fst.checked\", \"lib/MyProgramProof.fst\")\n\nif shouldRun('editor_tests'):\n  run_editor_test(\"basic\", [\"ab\", \"if\", \"ifcond\", \"while\"])\n  run_editor_test(\"range\", [\"AST\", \"ASTC\", \"ASTS\"])\n"
  },
  {
    "path": "experimental/Source/.gitignore",
    "content": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n##\n## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore\n\n# User-specific files\n*.rsuser\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n\n# User-specific files (MonoDevelop/Xamarin Studio)\n*.userprefs\n\n# Mono auto generated files\nmono_crash.*\n\n# Build results\n[Dd]ebug/\n[Dd]ebugPublic/\n[Rr]elease/\n[Rr]eleases/\nx64/\nx86/\n[Aa][Rr][Mm]/\n[Aa][Rr][Mm]64/\nbld/\n[Bb]in/\n[Oo]bj/\n[Ll]og/\n[Ll]ogs/\n\n# Visual Studio 2015/2017 cache/options directory\n.vs/\n# Uncomment if you have tasks that create the project's static files in wwwroot\n#wwwroot/\n\n# Visual Studio 2017 auto generated files\nGenerated\\ Files/\n\n# MSTest test Results\n[Tt]est[Rr]esult*/\n[Bb]uild[Ll]og.*\n\n# NUnit\n*.VisualState.xml\nTestResult.xml\nnunit-*.xml\n\n# Build Results of an ATL Project\n[Dd]ebugPS/\n[Rr]eleasePS/\ndlldata.c\n\n# Benchmark Results\nBenchmarkDotNet.Artifacts/\n\n# .NET Core\nproject.lock.json\nproject.fragment.lock.json\nartifacts/\n\n# Tye\n.tye/\n\n# StyleCop\nStyleCopReport.xml\n\n# Files built by Visual Studio\n*_i.c\n*_p.c\n*_h.h\n*.ilk\n*.meta\n*.obj\n*.iobj\n*.pch\n*.pdb\n*.ipdb\n*.pgc\n*.pgd\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.tmp_proj\n*_wpftmp.csproj\n*.log\n*.vspscc\n*.vssscc\n.builds\n*.pidb\n*.svclog\n*.scc\n\n# Chutzpah Test files\n_Chutzpah*\n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opendb\n*.opensdf\n*.sdf\n*.cachefile\n*.VC.db\n*.VC.VC.opendb\n\n# Visual Studio profiler\n*.psess\n*.vsp\n*.vspx\n*.sap\n\n# Visual Studio Trace Files\n*.e2e\n\n# TFS 2012 Local Workspace\n$tf/\n\n# Guidance Automation Toolkit\n*.gpState\n\n# ReSharper is a .NET coding add-in\n_ReSharper*/\n*.[Rr]e[Ss]harper\n*.DotSettings.user\n\n# TeamCity is a build add-in\n_TeamCity*\n\n# DotCover is a Code Coverage Tool\n*.dotCover\n\n# AxoCover is a Code Coverage Tool\n.axoCover/*\n!.axoCover/settings.json\n\n# Coverlet is a free, cross platform Code Coverage Tool\ncoverage*[.json, .xml, .info]\n\n# Visual Studio code coverage results\n*.coverage\n*.coveragexml\n\n# NCrunch\n_NCrunch_*\n.*crunch*.local.xml\nnCrunchTemp_*\n\n# MightyMoose\n*.mm.*\nAutoTest.Net/\n\n# Web workbench (sass)\n.sass-cache/\n\n# Installshield output folder\n[Ee]xpress/\n\n# DocProject is a documentation generator add-in\nDocProject/buildhelp/\nDocProject/Help/*.HxT\nDocProject/Help/*.HxC\nDocProject/Help/*.hhc\nDocProject/Help/*.hhk\nDocProject/Help/*.hhp\nDocProject/Help/Html2\nDocProject/Help/html\n\n# Click-Once directory\npublish/\n\n# Publish Web Output\n*.[Pp]ublish.xml\n*.azurePubxml\n# Note: Comment the next line if you want to checkin your web deploy settings,\n# but database connection strings (with potential passwords) will be unencrypted\n*.pubxml\n*.publishproj\n\n# Microsoft Azure Web App publish settings. Comment the next line if you want to\n# checkin your Azure Web App publish settings, but sensitive information contained\n# in these scripts will be unencrypted\nPublishScripts/\n\n# NuGet Packages\n*.nupkg\n# NuGet Symbol Packages\n*.snupkg\n# The packages folder can be ignored because of Package Restore\n**/[Pp]ackages/*\n# except build/, which is used as an MSBuild target.\n!**/[Pp]ackages/build/\n# Uncomment if necessary however generally it will be regenerated when needed\n#!**/[Pp]ackages/repositories.config\n# NuGet v3's project.json files produces more ignorable files\n*.nuget.props\n*.nuget.targets\n\n# Microsoft Azure Build Output\ncsx/\n*.build.csdef\n\n# Microsoft Azure Emulator\necf/\nrcf/\n\n# Windows Store app package directories and files\nAppPackages/\nBundleArtifacts/\nPackage.StoreAssociation.xml\n_pkginfo.txt\n*.appx\n*.appxbundle\n*.appxupload\n\n# Visual Studio cache files\n# files ending in .cache can be ignored\n*.[Cc]ache\n# but keep track of directories ending in .cache\n!?*.[Cc]ache/\n\n# Others\nClientBin/\n~$*\n*~\n*.dbmdl\n*.dbproj.schemaview\n*.jfm\n*.pfx\n*.publishsettings\norleans.codegen.cs\n\n# Including strong name files can present a security risk\n# (https://github.com/github/gitignore/pull/2483#issue-259490424)\n#*.snk\n\n# Since there are multiple workflows, uncomment next line to ignore bower_components\n# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)\n#bower_components/\n\n# RIA/Silverlight projects\nGenerated_Code/\n\n# Backup & report files from converting an old project file\n# to a newer Visual Studio version. Backup files are not needed,\n# because we have git ;-)\n_UpgradeReport_Files/\nBackup*/\nUpgradeLog*.XML\nUpgradeLog*.htm\nServiceFabricBackup/\n*.rptproj.bak\n\n# SQL Server files\n*.mdf\n*.ldf\n*.ndf\n\n# Business Intelligence projects\n*.rdl.data\n*.bim.layout\n*.bim_*.settings\n*.rptproj.rsuser\n*- [Bb]ackup.rdl\n*- [Bb]ackup ([0-9]).rdl\n*- [Bb]ackup ([0-9][0-9]).rdl\n\n# Microsoft Fakes\nFakesAssemblies/\n\n# GhostDoc plugin setting file\n*.GhostDoc.xml\n\n# Node.js Tools for Visual Studio\n.ntvs_analysis.dat\nnode_modules/\n\n# Visual Studio 6 build log\n*.plg\n\n# Visual Studio 6 workspace options file\n*.opt\n\n# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)\n*.vbw\n\n# Visual Studio LightSwitch build output\n**/*.HTMLClient/GeneratedArtifacts\n**/*.DesktopClient/GeneratedArtifacts\n**/*.DesktopClient/ModelManifest.xml\n**/*.Server/GeneratedArtifacts\n**/*.Server/ModelManifest.xml\n_Pvt_Extensions\n\n# Paket dependency manager\n.paket/paket.exe\npaket-files/\n\n# FAKE - F# Make\n.fake/\n\n# Ionide - VsCode extension for F# Support\n.ionide/\n\n# CodeRush personal settings\n.cr/personal\n\n# Python Tools for Visual Studio (PTVS)\n__pycache__/\n*.pyc\n\n# Cake - Uncomment if you are using it\n# tools/**\n# !tools/packages.config\n\n# Tabs Studio\n*.tss\n\n# Telerik's JustMock configuration file\n*.jmconfig\n\n# BizTalk build output\n*.btp.cs\n*.btm.cs\n*.odx.cs\n*.xsd.cs\n\n# OpenCover UI analysis results\nOpenCover/\n\n# Azure Stream Analytics local run output\nASALocalRun/\n\n# MSBuild Binary and Structured Log\n*.binlog\n\n# NVidia Nsight GPU debugger configuration file\n*.nvuser\n\n# MFractors (Xamarin productivity tool) working folder\n.mfractor/\n\n# Local History for Visual Studio\n.localhistory/\n\n# BeatPulse healthcheck temp database\nhealthchecksdb\n\n# Backup folder for Package Reference Convert tool in Visual Studio 2017\nMigrationBackup/\n\n# Ionide (cross platform F# VS Code tools) working folder\n.ionide/\n\n##\n## Visual studio for Mac\n##\n\n\n# globs\nMakefile.in\n*.userprefs\n*.usertasks\nconfig.make\nconfig.status\naclocal.m4\ninstall-sh\nautom4te.cache/\n*.tar.gz\ntarballs/\ntest-results/\n\n# Mac bundle stuff\n*.dmg\n*.app\n\n# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore\n# General\n.DS_Store\n.AppleDouble\n.LSOverride\n\n# Icon must end with two \\r\nIcon\n\n\n# Thumbnails\n._*\n\n# Files that might appear in the root of a volume\n.DocumentRevisions-V100\n.fseventsd\n.Spotlight-V100\n.TemporaryItems\n.Trashes\n.VolumeIcon.icns\n.com.apple.timemachine.donotpresent\n\n# Directories potentially created on remote AFP share\n.AppleDB\n.AppleDesktop\nNetwork Trash Folder\nTemporary Items\n.apdisk\n\n# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore\n# Windows thumbnail cache files\nThumbs.db\nehthumbs.db\nehthumbs_vista.db\n\n# Dump file\n*.stackdump\n\n# Folder config file\n[Dd]esktop.ini\n\n# Recycle Bin used on file shares\n$RECYCLE.BIN/\n\n# Windows Installer files\n*.cab\n*.msi\n*.msix\n*.msm\n*.msp\n\n# Windows shortcuts\n*.lnk\n\n# JetBrains Rider\n.idea/\n*.sln.iml\n\n##\n## Visual Studio Code\n##\n.vscode/*\n!.vscode/settings.json\n!.vscode/tasks.json\n!.vscode/launch.json\n!.vscode/extensions.json\n"
  },
  {
    "path": "experimental/Source/Armada/.gitignore",
    "content": "Parser.cs*\nScanner.cs*\n"
  },
  {
    "path": "experimental/Source/Armada/AST/Base.cs",
    "content": "using System;\nusing System.IO;\nusing System.Collections.Generic;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\n\nnamespace Microsoft.Starmada\n{\n    /*\n     * For now, using Token class from Scanner.frame\n    public class Token {\n        public int kind;\n        public string str;\n\n        public string filename;\n        public int startLine;\n        public int startCh;\n        public int endLine;\n        public int endCh;\n    }\n    */\n\n    // All AST node classes should be subclasses of this.\n    // Can put helper functions (e.g. ToString) in this for convenience.\n    //\n    // Might decide to get rid of this entirely later.\n    public abstract class AstNode\n    {\n        public Token FirstTok;\n        public Token LastTok;\n        public Scope Sc;\n        public string PC;\n        public string NextPC;\n        // labelOn stands for label_enable\n        public abstract string ToString(int indentation, bool labelOn);\n        public abstract string ToCProgram(int indentation);\n        public abstract string ToFStarLang(int indentation);\n\n        /// <summary>This function looks at the children nodes of this AST node\n        // and try to type resolve this AST node (Bottom-up resolution).</summary>\n        /// <param name=\"currentScope\">includes all variables defined until now.</param>\n        /// <param name=\"enforcingType\">In case of top-down resolution,\n        // this parameters indicates the enforcing type.</param>\n        public abstract void TypeResolve(Type enforcingType, ref Errors errors);\n\n        /// <summary>This function sets the program counter of each AST Node\n        // based on its definition and its parent PC.</summary>\n        /// <param name=\"parentPC\">The program counter of the parent.</param>\n        /// <param name=\"index\">The index of this AST node in parent.</param>\n        public abstract void SetProgramCounter(string parentPC, int index);\n        /// <summary>This function sets the program counter of the statement after this\n        // statement.</summary>\n        /// <param name=\"nextPC\">The next program counter of this statement.</param>\n        public abstract void SetNextProgramCounter(string nextPC);\n        /// <summary>This function returns all the child AstNode of this AstNode.</summary>\n        public abstract IEnumerable<AstNode> AllChildren();\n        // FIXME: add clone()?\n\n        public AstNode(Token firstTok)\n        {\n            this.FirstTok = firstTok;\n        }\n    }\n\n    // A complete Starmada program, with all the levels and proof steps.\n    public class StarmadaProgram : AstNode\n    {\n        public List<string> Includes;\n        public string Name;\n        public List<StructDecl> StructDecls;\n        public List<DatatypeDecl> DatatypeDecls;\n        public List<LevelDecl> Levels;\n        public List<ProofDecl> Proofs;\n        public Errors errors;\n        public ErrorReporter reporter;\n\n        public StarmadaProgram(Token tok, string name, Errors errors, ErrorReporter reporter) : base(tok)\n        {\n            this.Name = name;\n            this.errors = errors;\n            this.reporter = reporter;\n            Includes = new List<string>();\n            StructDecls = new List<StructDecl>();\n            DatatypeDecls = new List<DatatypeDecl>();\n            Levels = new List<LevelDecl>();\n            Proofs = new List<ProofDecl>();\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + this.Name + \"\\n\";\n            foreach (var inc in this.Includes)\n            {\n                str = str + indentationStr + $\"include {inc}\\n\";\n            }\n            foreach (var structDecl in this.StructDecls)\n            {\n                str = str + structDecl.ToString(indentation, labelOn) + \"\\n\";\n            }\n            foreach (var dataTypeDecl in this.DatatypeDecls)\n            {\n                str = str + dataTypeDecl.ToString(indentation, labelOn) + \"\\n\";\n            }\n            foreach (var level in this.Levels)\n            {\n                str = str + level.ToString(indentation, labelOn) + \"\\n\";\n            }\n            foreach (var proof in this.Proofs)\n            {\n                str = str + proof.ToString(indentation, labelOn) + \"\\n\";\n            }\n            return str;\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n\n            // TODO: Make a single runtime header which includes all necessary files + definitions\n            str = str + \"#include <stdint.h>\\n\";\n            str = str + \"#include <pthread.h>\\n\";\n            str = str + \"#include <assert.h>\\n\";\n            str = str + \"#include <stdio.h>\\n\";\n            str = str + \"#include <stdlib.h>\\n\";\n            str = str + \"#include <stdatomic.h>\\n\";\n\n            foreach (var structDecl in this.StructDecls)\n            {\n                str = str + structDecl.ToCProgram(indentation) + \"\\n\";\n            }\n            foreach (var dataTypeDecl in this.DatatypeDecls)\n            {\n                str = str + dataTypeDecl.ToCProgram(indentation) + \"\\n\";\n            }\n            foreach (var level in this.Levels)\n            {\n                str = str + level.ToCProgram(indentation) + \"\\n\";\n            }\n\n            // Add main method\n            str = str + \"int main() {\\n\";\n            str = str + \"  _main();\\n\";\n            str = str + \"  pthread_exit(NULL);\\n}\\n\";\n            return str;\n        }\n\n        public override string ToFStarLang(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            var moduleName = Path.GetFileNameWithoutExtension(this.Name);\n            moduleName = char.ToUpper(moduleName[0]) + moduleName.Substring(1);\n            str += Printer.GetFStarHeaderForModule(moduleName) + '\\n';\n            str += \"let finite_map_insert (#a: eqtype) (#b: Type u#b) (m: FStar.FiniteMap.Base.map a b) (k: a) (v: b) = ComputationProduces (FStar.FiniteMap.Base.insert #a #b k v m)\\n\";\n            str += \"let map_insert #key #value m k v = ComputationProduces (FStar.Map.upd #key #value m k v)\\n\";\n            str += \"let set_singleton #a x = ComputationProduces (FStar.Set.singleton #a x)\\n\";\n            str += \"let set_union #a s1 s2 = ComputationProduces (FStar.Set.union #a s1 s2)\\n\";\n            str += \"let finite_set_insert (#a: eqtype) (x: a) (s: FStar.FiniteSet.Base.set a) = ComputationProduces (FStar.FiniteSet.Base.insert #a x s)\\n\";\n            str += \"let seq_build (#ty: Type) (s: seq ty) (v: ty) = ComputationProduces (build #ty s v)\\n\";\n            str += \"let seq_index (#ty: Type) (s: seq ty) (i: nat): conditional_computation_t ty = if i < length s then ComputationProduces (index #ty s i) else ComputationUndefined\\n\";\n            str += \"let seq_range (#ty: Type) (s: seq ty) (startIndex: nat) (endIndex: nat): conditional_computation_t (seq ty) = if startIndex <= endIndex && endIndex <= length s then ComputationProduces (drop #ty (take #ty s endIndex) startIndex) else ComputationUndefined\\n\";\n            str += \"let map_select #key #value m k = ComputationProduces (FStar.Map.sel #key #value m k)\\n\";\n            str += \"let finite_map_select (#a: eqtype) (#b: Type u#b) (m: FStar.FiniteMap.Base.map a b) (k: a) = match (FStar.FiniteMap.Base.elements m) k with | None -> ComputationUndefined | Some v -> ComputationProduces v\\n\";\n            str += \"let seq_update (#ty: Type) (s: seq ty) (i: nat) (v: ty): conditional_computation_t (seq ty) = if i < length s then ComputationProduces (update #ty s i v) else ComputationUndefined\\n\";\n            str += \"let map_update #key #value m k v = ComputationProduces (FStar.Map.upd #key #value m k v)\\n\";\n            str += \"let finite_map_update (#a: eqtype) (#b: Type u#b) (m: FStar.FiniteMap.Base.map a b) (k: a) (v: b) = ComputationProduces (FStar.FiniteMap.Base.insert #a #b k v m)\\n\";\n            str += \"let seq_contains (#ty: Type) (v: ty) (s: seq ty) = ComputationProduces (u2b (contains #ty s v))\\n\";\n            str += \"let set_contains #a x s = ComputationProduces (FStar.Set.mem #a x s)\\n\";\n            str += \"let finite_set_contains (#a: eqtype) (x: a) (s: FStar.FiniteSet.Base.set a) = ComputationProduces (FStar.FiniteSet.Base.mem #a x s)\\n\";\n            str += \"let map_contains #key #value k m = ComputationProduces (FStar.Map.contains #key #value m k)\\n\";\n            str += \"let finite_map_contains #key #value k m = ComputationProduces (FStar.FiniteMap.Base.mem #key #value k m)\\n\";\n            str += \"let not_seq_contains (#ty: Type) (v: ty) (s: seq ty) = ComputationProduces (not (u2b (contains #ty s v)))\\n\";\n            str += \"let not_set_contains #a x s = ComputationProduces (not (FStar.Set.mem #a x s))\\n\";\n            str += \"let not_finite_set_contains (#a: eqtype) (x: a) (s: FStar.FiniteSet.Base.set a) = ComputationProduces (not (FStar.FiniteSet.Base.mem #a x s))\\n\";\n            str += \"let not_map_contains #key #value k m = ComputationProduces (not (FStar.Map.contains #key #value m k))\\n\";\n            str += \"let not_finite_map_contains #key #value k m = ComputationProduces (not (FStar.FiniteMap.Base.mem #key #value k m))\\n\";\n            str += \"let set_disjoint (#a:eqtype) (s1: FStar.Set.set a) (s2: FStar.Set.set a) = ComputationProduces (u2b (FStar.Set.disjoint #a s1 s2))\\n\";\n            str += \"let finiteset_disjoint (#a: eqtype) (s1: FStar.FiniteSet.Base.set a) (s2: FStar.FiniteSet.Base.set a) = ComputationProduces (u2b (FStar.FiniteSet.Base.disjoint #a s1 s2))\\n\";\n            str += \"let seq_cardinality (#ty: Type) (s: seq ty) = ComputationProduces (length s)\\n\";\n            str += \"let finiteset_cardinality (#a: eqtype) (s: FStar.FiniteSet.Base.set a) = ComputationProduces (FStar.FiniteSet.Base.cardinality #a s)\\n\";\n            str += \"let finitemap_cardinality #key #value  m = ComputationProduces (FStar.FiniteMap.Base.cardinality #key #value m)\\n\";\n            str += \"\\n\";\n\n            foreach (var structDecl in this.StructDecls)\n            {\n                str += structDecl.ToFStarLang(indentation) + \"\\n\";\n            }\n            foreach (var dataTypeDecl in this.DatatypeDecls)\n            {\n                str += dataTypeDecl.ToFStarLang(indentation) + \"\\n\";\n            }\n            foreach (var dataTypeDecl in this.DatatypeDecls)\n            {\n                str += indentationStr + dataTypeDecl.GenerateFstarFunctions() + \"\\n\";\n            }\n            foreach (var level in Levels) {\n                foreach (var node in level.AllChildren()) {\n                    if (node is MethodDecl) {\n                        var methodDecl = node as MethodDecl;\n                        str += methodDecl.GetStackInitializer(indentation) + \"\\n\";\n                    }\n                }\n            }\n            return str;\n        }\n\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            var structDatatypeNamesToTokenDict = new Dictionary<string, Token>();\n            foreach (var structDecl in this.StructDecls) {\n                var structName = structDecl.Name.Name.ToLower();\n                if (structDatatypeNamesToTokenDict.ContainsKey(structName)) {\n                    errors.SemErr(structDecl.FirstTok, $\"{structName} is already defined at line {structDatatypeNamesToTokenDict[structName].line}:{structDatatypeNamesToTokenDict[structName].col} (uppercase neglected)!\");\n                }\n                structDatatypeNamesToTokenDict[structName] = structDecl.Name.FirstTok;\n            }\n            foreach (var datatypeDecl in this.DatatypeDecls) {\n                var datatypeName = datatypeDecl.Ty.Name.Name.ToLower();\n                if (structDatatypeNamesToTokenDict.ContainsKey(datatypeName)) {\n                    errors.SemErr(datatypeDecl.FirstTok, $\"{datatypeName} is already defined at line {structDatatypeNamesToTokenDict[datatypeName].line}:{structDatatypeNamesToTokenDict[datatypeName].col} (uppercase neglected)!\");\n                }\n                structDatatypeNamesToTokenDict[datatypeName] = datatypeDecl.FirstTok;\n            }\n            \n            // Add all defined structs and datatypes to the current scope\n            foreach (var structDecl in this.StructDecls)\n            {\n                Sc.Push(structDecl);\n            }\n            foreach (var datatypeDecl in this.DatatypeDecls)\n            {\n                Sc.Push(datatypeDecl);\n            }\n\n            foreach (var structDecl in this.StructDecls)\n            {\n                structDecl.Sc = new Scope(Sc);\n                structDecl.Sc.EnclosingNode = structDecl;\n                structDecl.TypeResolve(null, ref errors);\n            }\n            foreach (var datatypeDecl in this.DatatypeDecls)\n            {\n                datatypeDecl.Sc = Sc;\n                datatypeDecl.TypeResolve(null, ref errors);\n            }\n            foreach (var levelDecl in this.Levels)\n            {\n                levelDecl.Sc = new Scope(Sc);\n                levelDecl.Sc.EnclosingNode = levelDecl;\n                levelDecl.TypeResolve(null, ref errors);\n            }\n            foreach (var proofDecl in this.Proofs)\n            {\n                proofDecl.Sc = new Scope(Sc);\n                proofDecl.Sc.EnclosingNode = proofDecl;\n                proofDecl.TypeResolve(null, ref errors);\n            }\n            // TODO: Implement this function\n        }\n        public override void SetProgramCounter(string parentPC, int index)\n        {\n            foreach (var levelDecl in this.Levels)\n            {\n                levelDecl.SetProgramCounter(\"\", 0);\n            }\n        }\n        public override void SetNextProgramCounter(string nextPC)\n        {\n            throw new NotImplementedException();\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var structDecl in StructDecls)\n            {\n                foreach (var node in structDecl.AllChildren())\n                    yield return node;\n                yield return structDecl;\n            }\n            foreach (var datatypeDecl in DatatypeDecls)\n            {\n                foreach (var node in datatypeDecl.AllChildren())\n                    yield return node;\n                yield return datatypeDecl;\n            }\n            foreach (var level in Levels)\n            {\n                foreach (var node in level.AllChildren())\n                    yield return node;\n                yield return level;\n            }\n            foreach (var proof in Proofs)\n            {\n                foreach (var node in proof.AllChildren())\n                    yield return node;\n                yield return proof;\n            }\n        }\n    }\n\n    public class StructDecl : AstNode\n    {\n        public Ident Name;\n        public List<VarDecl> Decls; // must have at least one entry\n        public StructDecl(Token tok, Ident name) : base(tok)\n        {\n            this.Name = name;\n            this.Decls = new List<VarDecl>();\n        }\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"struct \" + this.Name.ToString(0, labelOn) + \" {\\n\";\n            foreach (var decl in this.Decls)\n            {\n                str = str + decl.ToString(indentation + 2, labelOn) + \"\\n\";\n            }\n            str = str + indentationStr + \"}\";\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            foreach (var decl in this.Decls)\n            {\n                decl.Sc = Sc;\n                decl.TypeResolve(null, ref errors);\n            }\n        }\n        public override void SetProgramCounter(string parentPC, int index)\n        {\n            throw new NotImplementedException();\n        }\n        public override void SetNextProgramCounter(string nextPC)\n        {\n            throw new NotImplementedException();\n        }\n        public override string ToCProgram(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"struct \" + this.Name.ToString(0, false) + \" {\\n\";\n            foreach (var decl in this.Decls)\n            {\n                str = str + decl.ToCProgram(indentation + 2) + \"\\n\";\n            }\n            str = str + indentationStr + \"};\";\n            return str;\n        }\n        public VarDecl GetField(string name)\n        {\n            foreach (var decl in this.Decls)\n            {\n                if (decl.Name.Name == name)\n                {\n                    return decl;\n                }\n            }\n            return null;\n        }\n        public string GetFieldAccessInFStar(string fieldName, string firstOp)\n        {\n            int fieldId = -1;\n            for (int i = 0; i < Decls.Count; i++)\n            {\n                if (Decls[i].Name.Name == fieldName) {\n                    fieldId = i;\n                    break;\n                }\n            }\n            if (fieldId == -1) {\n                throw new ArgumentException($\"Field {fieldName} doesn't exist in {Name} struct declaration\");\n            }\n            string str = $\"(ExpressionFieldOf (_user_defined_struct__{this.Name.ToString(0, false).ToLower()}) ({firstOp}) {fieldId})\";\n            return str;\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str += indentationStr + \"type _user_defined_struct__\" + Name.ToString(0, false).ToLower() + \" = (ObjectTDStruct (singleton \\n\";\n            string sep = indentationStr + \"  \";\n            foreach (var field in this.Decls) {\n                str += sep + \"( \" + field.Ty.ToFStarLang(0, true) + \" )\";\n                sep = \" $::\\n\" + indentationStr + \"  \";\n            }\n            str += \"\\n\" + indentationStr + \"))\";\n            return str;\n        }\n\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            yield return Name;\n            foreach (var vardecl in Decls)\n            {\n                foreach (var node in vardecl.AllChildren())\n                    yield return node;\n                yield return vardecl;\n            }\n        }\n    }\n\n    public class DatatypeDecl : AstNode\n    {\n        public UserDefinedType Ty;\n        public List<DatatypeMemberDecl> MemberDeclList = new List<DatatypeMemberDecl>();\n\n        private Dictionary<string, int> GenericTypeDict = new Dictionary<string, int>(); // filled in during type resolution\n        private Dictionary<string, int> MatchDict = new Dictionary<string, int>(); // filled in during type resolution\n\n        class Fn\n        {\n            public Type astType; // return type\n            public string ty; // function return type\n            public string parameterTy; // function parameter type\n            public List<DatatypeMemberDecl> members;\n            public string name; // function name\n            public string definition; // function definition\n            public string invocation; // string format for function invocation\n        }\n\n        // For resolution of D.x, generating F* functions\n        private Dictionary<string, Fn> name2fn = new Dictionary<string, Fn>();\n\n        public DatatypeDecl(Token tok, UserDefinedType ty) : base(tok)\n        {\n            this.Ty = ty;\n        }\n\n        // FIXME: unsupported; seems not fully supported by grammar\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"datatype \" + Ty.ToString(0) + \" = \";\n            var sep = \"\";\n            foreach (var member in this.MemberDeclList)\n            {\n                str += sep + member.ToString(0, false);\n                sep = \" | \";\n            }\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            if (Ty.ArgumentList != null)\n            {\n                for (int i = 0; i < Ty.ArgumentList.Count; i++)\n                {\n                    var genericType = Ty.ArgumentList[i] as UserDefinedType;\n                    if (genericType == null)\n                    {\n                        errors.SemErr(Ty.Name.FirstTok, \"Invalid generic type list!\");\n                    }\n                    GenericTypeDict.Add(genericType.Name.Name, i);\n                }\n            }\n            foreach (var datatypeMemberDecl in MemberDeclList)\n            {\n                foreach (Parameter parameter in datatypeMemberDecl.Arguments)\n                {\n                    bool isDefinedType = Sc.IsDefinedType(parameter.Ty);\n                    bool isGenericType = false;\n                    if (!isDefinedType && Ty.ArgumentList != null && parameter.Ty is UserDefinedType)\n                    {\n                        var ut = parameter.Ty as UserDefinedType;\n                        int index = -1;\n                        isGenericType = GenericTypeDict.TryGetValue(ut.Name.Name, out index);\n                        parameter.Ty = new GenericType(ut.Name.Name, index);\n                    }\n                    if (!isDefinedType && !isGenericType)\n                    {\n                        errors.SemErr(parameter.FirstTok, parameter.Ty.ToString(0) + \"'s type is not defined.\");\n                    }\n                    string name = parameter.Name.Name;\n                    if (name2fn.ContainsKey(name))\n                    {\n                        if (name2fn[name].ty != parameter.Ty.ToString(0))\n                        {\n                            errors.SemErr(parameter.FirstTok, \"Parameter with the same name must has the same type.\");\n                        }\n                    }\n                    else\n                    {\n                        name2fn[name] = new Fn();\n                        name2fn[name].astType = parameter.Ty;\n                        name2fn[name].ty = parameter.Ty.ToString(0);\n                        name2fn[name].members = new List<DatatypeMemberDecl>();\n                    }\n                    name2fn[name].members.Add(datatypeMemberDecl);\n                }\n                var datatypeMember = Sc.GetDatatypeMemberDecl(datatypeMemberDecl.Name.Name);\n                if (datatypeMember != null)\n                {\n                    errors.SemErr(FirstTok, $\"{Ty.Name.ToString(0, false).ToLower()} is already defined at line {datatypeMember.FirstTok.line}:{datatypeMember.FirstTok.col}!\");\n                }\n                Sc.Push(datatypeMemberDecl);\n            }\n            // Prepare for generating fstar functions\n            foreach (KeyValuePair<string, Fn> entry in name2fn)\n            {\n                string indentation = new string(' ', 4);\n                string name = entry.Key;\n                Fn fn = entry.Value;\n                string baseName = Ty.Name.Name.ToLower();\n                fn.name = $\"_{baseName}_{name}\";\n                List<string> typesStr = fn.members.ConvertAll(member => $\"{member.Name.Name}?gt\");\n                fn.parameterTy = $\"gt: {baseName}{{{String.Join(\" \\\\/ \", typesStr)}}}\";\n                string body = $\"let {fn.name} (base: ({fn.parameterTy})): conditional_computation_t {fn.ty} = \";\n                if (fn.members.Count == 1)\n                {\n                    DatatypeMemberDecl member = fn.members[0];\n                    body += $\"ComputationProduces ({member.Name.Name}?.{name} base)\\n\";\n                }\n                else\n                {\n                    body += '\\n' + \"ComputationProduces (\\n\";\n                    body += indentation + $\"match base with\\n\";\n                    foreach (DatatypeMemberDecl member in fn.members)\n                    {\n                        body += indentation + $\"| {member.Name.Name} {String.Join(' ', member.Arguments.ConvertAll(arg => arg.Name.Name))} -> {name}\\n\";\n                    }\n                    body += \")\\n\";\n                }\n                fn.definition = body;\n                fn.invocation = $\"ExpressionApplyFunction ({fn.astType.ToFStarLang(0, true)}) [!!] {fn.ty} [{fn.parameterTy}] {fn.name}\";\n            }\n            // Set the match list\n            for (int i = 0; i < MemberDeclList.Count; i++)\n            {\n                MatchDict.Add(MemberDeclList[i].Name.Name, i);\n            }\n            Sc.Push(this);\n        }\n        public int GetMemberDeclIndex(string name)\n        {\n            int index = -1;\n            MatchDict.TryGetValue(name, out index);\n            return index;\n        }\n        public List<DatatypeMemberDecl> GetDefinedMemberList(List<Type> definedTypes)\n        {\n            if (Ty.ArgumentList == null || Ty.ArgumentList.Count == 0)\n            {\n                return MemberDeclList;\n            }\n            var definedMemberList = new List<DatatypeMemberDecl>();\n            foreach (var datatypeMemberDecl in MemberDeclList)\n            {\n                var newParameters = new List<Parameter>();\n                foreach (var parameter in datatypeMemberDecl.Arguments)\n                {\n                    if (parameter.Ty is GenericType)\n                    {\n                        newParameters.Add(new Parameter(parameter.FirstTok, parameter.Name, definedTypes[(parameter.Ty as GenericType).Index]));\n                    }\n                    else\n                    {\n                        newParameters.Add(parameter);\n                    }\n                }\n                definedMemberList.Add(new DatatypeMemberDecl(datatypeMemberDecl.Name, newParameters));\n            }\n            return definedMemberList;\n        }\n        public override void SetProgramCounter(string parentPC, int index)\n        {\n            return;\n        }\n        public override void SetNextProgramCounter(string nextPC)\n        {\n            return;\n        }\n        public override string ToCProgram(int indentation)\n        {\n            throw new NotImplementedException();\n        }\n\n        public string GenerateFstarFunctions()\n        {\n            List<string> fnStr = new List<string>();\n            foreach (Fn fn in name2fn.Values)\n            {\n                fnStr.Add(fn.definition);\n            }\n            return String.Join('\\n', fnStr);\n        }\n\n        public string GetFunctionInvocation(string name, string fstarExpr)\n        {\n            if (!name2fn.ContainsKey(name))\n            {\n                return null;\n            }\n            string[] s = name2fn[name].invocation.Split(\"!!\");\n            return s[0] + fstarExpr + s[1];\n        }\n\n        public override string ToFStarLang(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str += indentationStr + \"type \" + Ty.ToFStarLang(0, false) + \" = \\n\";\n            foreach (var member in MemberDeclList)\n            {\n                str += member.ToFStarLang(indentation + 4) + Ty.ToFStarLang(0, false) + \"\\n\";\n            }\n            return str;\n        }\n\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var member in MemberDeclList)\n            {\n                foreach (var node in member.AllChildren())\n                    yield return node;\n                yield return member;\n            }\n        }\n    }\n\n    public class DatatypeMemberDecl : AstNode\n    {\n        public Ident Name;\n        public List<Parameter> Arguments;\n        public DatatypeDecl parent;\n        public DatatypeMemberDecl(Ident name, List<Parameter> args) : base(name.FirstTok)\n        {\n            this.Name = name;\n            this.Arguments = args;\n        }\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + Name.ToString(0, false);\n            if (Arguments != null && Arguments.Count > 0)\n            {\n                str = str + \"(\";\n                var sep = \"\";\n                foreach (Parameter p in Arguments)\n                {\n                    str += sep + p.ToString(0, false);\n                    sep = \", \";\n                }\n                str += \")\";\n            }\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            throw new NotImplementedException();\n        }\n        public override void SetProgramCounter(string parentPC, int index)\n        {\n            throw new NotImplementedException();\n        }\n        public override void SetNextProgramCounter(string nextPC)\n        {\n            throw new NotImplementedException();\n        }\n        public override string ToCProgram(int indentation)\n        {\n            throw new NotSupportedException();\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str += indentationStr + \"| \" + Name.ToString(0, false) + \": \";\n            foreach (Parameter arg in Arguments)\n            {\n                str += $\"({arg.ToFStarLang(0)})\";\n                str += \" -> \";\n            }\n            return str;\n        }\n\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            yield return Name;\n            foreach (Parameter arg in Arguments)\n            {\n                foreach (var node in arg.AllChildren())\n                    yield return node;\n                yield return arg;\n            }\n        }\n    }\n\n    public class LevelDecl : AstNode\n    {\n        public Ident Name;\n        public List<VarDecl> Globals;\n        public List<MemberDecl> Members;\n        public List<InvariantDecl> Invariants;\n        public Ident SharedStructName;\n        private int FunctionCount = 0;\n        // FIXME: want to use option type, perhaps impl ourselves\n        // TODO: ref to shared structs\n\n        public string MainStartPC = \"main.1\";\n\n        public LevelDecl(Token tok, Ident name) : base(tok)\n        {\n            this.Name = name;\n            Globals = new List<VarDecl>();\n            Members = new List<MemberDecl>();\n            Invariants = new List<InvariantDecl>();\n        }\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"level \" + Name.ToString(0, labelOn) + \" {\\n\";\n            foreach (var decl in Globals)\n            {\n                str = str + decl.ToString(indentation + 2, labelOn) + \"\\n\";\n            }\n            foreach (var member in Members)\n            {\n                str = str + member.ToString(indentation + 2, labelOn) + \"\\n\";\n            }\n            foreach (var inv in Invariants)\n            {\n                str = str + inv.ToString(indentation + 2, labelOn) + \"\\n\";\n            }\n            str = str + indentationStr + \"}\";\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            // TODO: Implement this function, now it is just for test\n            foreach (var global in Globals)\n            {\n                global.Sc = Sc;\n                global.TypeResolve(null, ref errors);\n            }\n            foreach (var member in Members)\n            {\n                Sc.Push(member);\n            }\n            foreach (var inv in Invariants)\n            {\n                Sc.Push(inv);\n            }\n            foreach (var member in Members)\n            {\n                member.Sc = new Scope(Sc);\n                member.Sc.EnclosingNode = member;\n                if (member is MethodDecl methodDecl) {\n                    methodDecl.EnclosingLevel = this;\n                }\n                foreach (var node in member.AllChildren())\n                {\n                    if (node is not Statement)\n                    {\n                        continue;\n                    }\n                    Statement stmt = node as Statement;\n                    if (stmt.PC != null)\n                    {\n                        member.Sc.PC2Stmt[stmt.PC] = stmt;\n                    }\n                }\n                member.TypeResolve(null, ref errors);\n            }\n            foreach (var inv in Invariants)\n            {\n                inv.Sc = new Scope(Sc);\n                inv.Sc.EnclosingNode = inv;\n                inv.TypeResolve(null, ref errors);\n            }\n            // TODO: deal with SharedStructName\n        }\n        public override void SetProgramCounter(string parentPC, int index)\n        {\n            foreach (var member in Members)\n            {\n                member.SetProgramCounter(\"\", 0);\n            }\n        }\n        public override void SetNextProgramCounter(string nextPC)\n        {\n            throw new NotSupportedException();\n        }\n        public override string ToCProgram(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            foreach (var decl in Globals)\n            {\n                str = str + decl.ToCProgram(indentation) + \"\\n\";\n            }\n            foreach (var member in Members)\n            {\n                str = str + member.ToCProgram(indentation) + \"\\n\";\n            }\n            return str;\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            foreach (var node in AllChildren())\n            {\n                if (node is MatchExpr)\n                {\n                    MatchExpr matchExpr = node as MatchExpr;\n                    str += matchExpr.ToFStarFunction(indentation, $\"func_{FunctionCount}\") + '\\n';\n                    FunctionCount++;\n                }\n                if (node is QuantifierExpr)\n                {\n                    QuantifierExpr quantifierExpr = node as QuantifierExpr;\n                    str += quantifierExpr.ToFStarFunction(indentation, $\"func_{FunctionCount}\") + '\\n';\n                    FunctionCount++;\n                }\n                if (node is ComprehensionExpr)\n                {\n                    ComprehensionExpr comprehensionExpr = node as ComprehensionExpr;\n                    str += comprehensionExpr.ToFStarMapFunction(indentation, $\"func_{FunctionCount}\") + '\\n';\n                    FunctionCount++;\n                }\n            }\n            str += indentationStr + $\"let global_initializers: list initializer_t =\\n\";\n            str += indentationStr + \"  [\\n\";\n            var sep = \"\";\n            foreach (var global in Globals)\n            {\n                if (global.Ty is TypeSuffix)\n                {\n                    string arrayName = global.Name.ToString(0, false);\n                    if (global.Value != null && global.Value is SeqDisplayExpr)\n                    {\n                        SeqDisplayExpr seqInit = global.Value as SeqDisplayExpr;\n                        str += sep + new string(' ', indentation + 4) + $\"{{ var_id = \\\"_{arrayName}_array\\\"; iv = InitializerSpecific ({seqInit.ToFStarObjectValue()}); weakly_consistent = false; }}\";\n                        global.Value = new ArrayPointer(global.FirstTok, arrayName);\n                    }\n                    else if (global.Value == null)\n                    {\n                        str += sep + new string(' ', indentation + 4) + $\"{{ var_id = \\\"_{arrayName}_array\\\"; iv = InitializerArbitrary ({(global.Ty as TypeSuffix).ToArrayFStarLang()}); weakly_consistent = false; }}\";\n                        global.Value = new ArrayPointer(global.FirstTok, arrayName);\n                    }\n                    else\n                    {\n                        throw new NotSupportedException();\n                    }\n                    sep = \" ;\\n\";\n                }\n                str += sep + global.ToFStarLang(indentation + 4);\n                sep = \" ;\\n\";\n            }\n            str += indentationStr + \"\\n  ]\\n\";\n            foreach (var member in Members)\n            {\n                str = str + member.ToFStarLang(indentation) + \"\\n\";\n            }\n            str += indentationStr + \"let propagate_statement = { start_pc = None; end_pc = None; starts_atomic_block = true; ends_atomic_block = true; statement = PropagateWriteMessageStatement }\\n\";\n            str += indentationStr + $\"let program_statements = \\n  [\\n\";\n            sep = \"\";\n            foreach (var member in Members)\n            {\n                if (member is MethodDecl method) {\n                    if (method.Name.Name == \"main\")\n                    {\n                        if (method.FStarStmts.Count == 0)\n                        {\n                            throw new Exception(\"no actual statements in main function\");\n                        }\n                        MainStartPC = method.FStarStmts[0].StartPC;\n                    }\n                }\n                str += sep + indentationStr + \"    \" + member.Name.ToString(0, false).ToLower() + \"_func_statements\";\n                sep = \";\\n\";\n            }\n            str += \"\\n  ]\\n\";\n            str += indentationStr + \"let prog: Armada.Program.t = {\\n\";\n            str += indentationStr + \"  main_method_id = \\\"main\\\";\\n\";\n            str += indentationStr + $\"  main_start_pc = \\\"{MainStartPC}\\\";\\n\";\n            str += indentationStr + \"  global_initializers = global_initializers;\\n\";\n            str += indentationStr + $\"  main_stack_initializers = level_{Name.Name}_main_stack_initializers;\\n\";\n            str += indentationStr + \"  program_statements = propagate_statement :: flatten program_statements;\\n\";\n            str += indentationStr + \"}\\n\";\n            return str;\n        }\n\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            yield return Name;\n            foreach (var global in Globals)\n            {\n                foreach (var node in global.AllChildren())\n                    yield return node;\n                yield return global;\n            }\n            foreach (var member in Members)\n            {\n                foreach (var node in member.AllChildren())\n                    yield return node;\n                yield return member;\n            }\n            foreach (var inv in Invariants)\n            {\n                foreach (var node in inv.AllChildren())\n                    yield return node;\n                yield return inv;\n            }\n        }\n    }\n\n    public abstract class MemberDecl : AstNode\n    {\n        public Ident Name;\n        public MemberDecl(Token tok) : base(tok) { }\n    }\n\n    public class MethodDecl : MemberDecl\n    {\n        public List<Parameter> Args;\n        public List<MethodSpec> Specs;\n        public Parameter Ret;\n        // FIXME: impl method spec\n        public List<VarDecl> VarDeclList; // filled in during type resolution\n        public List<Statement> Stmts;\n        // For each caller, there would be an element in this list.\n        public List<FunctionCallStatement> CallerStmtList;\n        private bool IsCalledWithThread = false;\n        private bool IsExternal = false;\n        public bool IsAtomic = false;\n        public List<Attribute> Attrs;\n        public LevelDecl EnclosingLevel = null;\n\n        public List<FStarStmt> FStarStmts;\n\n        public MethodDecl(Token tok) : base(tok)\n        {\n            Args = new List<Parameter>();\n            Specs = new List<MethodSpec>();\n            VarDeclList = new List<VarDecl>();\n            Stmts = new List<Statement>();\n            CallerStmtList = new List<FunctionCallStatement>();\n            Attrs = new List<Attribute>();\n            FStarStmts = new();\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str += indentationStr + \"method \";\n            foreach (var attr in Attrs)\n            {\n                str += $\"{{:{attr.Name.Name}}} \";\n            }\n            str += Name.ToString(0, labelOn) + \" (\";\n            for (int i = 0; i < Args.Count; i++)\n            {\n                str = str + Args[i].ToString(0, labelOn);\n                if (i != Args.Count - 1)\n                {\n                    str = str + \", \";\n                }\n            }\n            str = str + \")\";\n            if (Ret != null)\n            {\n                str = str + \" returns (\" + Ret.ToString(0, labelOn) + \")\";\n            }\n            foreach (var spec in Specs)\n            {\n                str += \"\\n\" + spec.ToString(indentation + 2, labelOn);\n            }\n            str = str + \"\\n\" + indentationStr + \"{\\n\";\n            foreach (var stmt in VarDeclList)\n            {\n                str = str + stmt.ToString(indentation + 2, labelOn) + \"\\n\";\n            }\n            foreach (var stmt in Stmts)\n            {\n                str = str + stmt.ToString(indentation + 2, labelOn) + \"\\n\";\n            }\n            str = str + indentationStr + \"}\";\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            // TODO: Implement this function, now it is just for test\n            foreach (var attr in Attrs)\n            {\n                if (attr.Name.Name == \"extern\")\n                {\n                    IsExternal = true;\n                }\n                else if (attr.Name.Name == \"atomic_method\")\n                {\n                    IsAtomic = true;\n                }\n            }\n            foreach (var arg in Args)\n            {\n                arg.Sc = Sc;\n                arg.TypeResolve(null, ref errors);\n                Sc.Push(arg);\n            }\n            if (Ret != null)\n            {\n                Ret.Sc = Sc;\n                Ret.TypeResolve(null, ref errors);\n                Sc.Push(Ret);\n            }\n            foreach (var spec in Specs)\n            {\n                spec.Sc = Sc;\n                spec.TypeResolve(null, ref errors);\n            }\n            if (IsAtomic)\n            {\n                foreach (var stmt in Stmts)\n                {\n                    stmt.InAtomicBlock = true;\n                    stmt.StartsAtomicBlock = false;\n                    stmt.EndsAtomicBlock = false;\n                }\n            }\n            // Add label statement to scope\n            foreach (Statement stmt in Stmts)\n            {\n                if (stmt.Label != null)\n                {\n                    Sc.Push(stmt);\n                }\n            }\n            foreach (Statement stmt in Stmts)\n            {\n                stmt.Sc = Sc;\n                stmt.TypeResolve(enforcingType, ref errors);\n            }\n\n            // Seperate VarDecls and other statements\n            bool endVarDecl = false;\n            foreach (Statement stmt in Stmts)\n            {\n                if (stmt is VarDecl)\n                {\n                    if (endVarDecl)\n                    {\n                        errors.SemErr(stmt.FirstTok, \"Variable declaration should be at the top of the method declaration!\");\n                    }\n                    VarDeclList.Add(stmt as VarDecl);\n                }\n                else\n                {\n                    endVarDecl = true;\n                }\n            }\n            Stmts.RemoveRange(0, VarDeclList.Count);\n\n            List<Statement> generatedAssigns = new List<Statement>();\n            string prefix = Name.ToString(0, false).ToLower();\n            int count = 1;\n            foreach (VarDecl vardecl in VarDeclList)\n            {\n                if (vardecl.Value != null && vardecl.Value is not FStarExpressionConstant)\n                {\n                    var assignStatement = new AssignStatement(vardecl.FirstTok, vardecl.Name, vardecl.Value, false);\n                    assignStatement.PC = $\"{prefix}.{count}\";\n                    count += 1;\n                    assignStatement.NextPC = $\"{prefix}.{count}\";\n                    assignStatement.Sc = Sc;\n                    assignStatement.TypeResolve(null, ref errors);\n                    generatedAssigns.Add(assignStatement);\n                    vardecl.Value = null;\n                }\n            }\n            if (generatedAssigns.Count > 0)\n            {\n                if (Stmts.Count > 0)\n                {\n                    generatedAssigns[generatedAssigns.Count - 1].NextPC = Stmts[0].PC;\n                }\n                else\n                {\n                    generatedAssigns[generatedAssigns.Count - 1].NextPC = $\"{prefix}.End\";\n                }\n            }\n            else if (Stmts.Count > 0)\n            {\n                Stmts[0].PC = $\"{prefix}.1\";\n            }\n            Stmts.InsertRange(0, generatedAssigns);\n        }\n        public void AddCaller(Expr destination, bool isSequential, string nextPC)\n        {\n            var funcCallStmt = new FunctionCallStatement(this, destination,\n              Ret == null ? null : Ret.Name,\n              isSequential, Name.ToString(0, false).ToLower() + \".End\", nextPC);\n            if (IsAtomic)\n            {\n                funcCallStmt.InAtomicBlock = true;\n                funcCallStmt.StartsAtomicBlock = false;\n                funcCallStmt.EndsAtomicBlock = false;\n            }\n            CallerStmtList.Add(funcCallStmt);\n        }\n        public void AddThreadCaller()\n        {\n            IsCalledWithThread = true;\n        }\n        public override void SetProgramCounter(string parentPC, int index)\n        {\n            for (int i = 0; i < Stmts.Count; i++)\n            {\n                Stmts[i].SetProgramCounter(Name.ToString(0, false).ToLower(), i + 1);\n            }\n            // TODO: implement SetNextProgramCounter\n            if (Stmts.Count > 0)\n            {\n                for (int i = 0; i < Stmts.Count - 1; i++)\n                {\n                    Stmts[i].SetNextProgramCounter(Stmts[i + 1].PC);\n                }\n                Stmts[Stmts.Count - 1].SetNextProgramCounter(Name.ToString(0, false).ToLower() + \".End\");\n                this.PC = Stmts[0].PC;\n            }\n        }\n        public override void SetNextProgramCounter(string nextPC)\n        {\n            throw new NotSupportedException();\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr;\n\n            if (Ret != null)\n            {\n                str = str + Ret.ToCProgram(0) + \" \";\n            }\n            else\n            {\n                str = str + \"void \";\n            }\n\n            if (Name.ToCProgram(0) == \"main\")\n            {\n                str = str + \"_main\" + \"(\";\n            }\n            else\n            {\n                str = str + Name.ToCProgram(0) + \"(\";\n            }\n\n            for (int i = 0; i < Args.Count; i++)\n            {\n                str = str + Args[i].ToCProgram(0);\n                if (i != Args.Count - 1)\n                {\n                    str = str + \", \";\n                }\n            }\n            str = str + \")\";\n            str = str + \" {\\n\";\n            foreach (var stmt in Stmts)\n            {\n                str = str + stmt.ToCProgram(indentation + 2) + \"\\n\";\n            }\n            str = str + indentationStr + \"}\\n\";\n\n            // Create an arg struct and function wrapper for thread invocations of this method\n            if (Name.ToCProgram(0) != \"main\")\n            {\n                if (Args.Count > 0)\n                {\n                    str = str + indentationStr + createArgStruct();\n                }\n                str = str + indentationStr + getThreadWrapper();\n            }\n\n            return str;\n        }\n\n        private string createArgStruct()\n        {\n            string structType = \"struct _\" + Name.ToCProgram(0) + \"Args\";\n            string indentationStr = new string(' ', 2);\n            string structStr = structType + \"{\\n\";\n            for (int i = 0; i < Args.Count; i++)\n            {\n                structStr = structStr + indentationStr + Args[i].ToCProgram(0) + \";\\n\";\n            }\n            structStr = structStr + \"};\\n\";\n            return structStr;\n        }\n\n        private string getThreadWrapper()\n        {\n            string structType = \"struct _\" + Name.ToCProgram(0) + \"Args\";\n            string indentationStr = new string(' ', 2);\n\n            string str = \"void _\" + Name.ToCProgram(0) + \"Wrapper\";\n\n            if (Args.Count > 0)\n            {\n                str = str + \"(void * args) {\\n\";\n                str = str + indentationStr + structType + \"* func_args = (\" + structType + \"*) args;\\n\";\n            }\n            else\n            {\n                str = str + \"() {\\n\";\n            }\n\n            str = str + indentationStr + Name.ToCProgram(0) + \"(\";\n            if (Args.Count > 0)\n            {\n                for (int i = 0; i < Args.Count; i++)\n                {\n                    str = str + \"func_args->\" + Args[i].Name.ToCProgram(0);\n                    if (i != Args.Count - 1)\n                    {\n                        str = str + \", \";\n                    }\n                }\n            }\n            str = str + \");\\n\";\n            if (Args.Count > 0)\n            {\n                str = str + indentationStr + \"free(args);\\n\";\n            }\n            str = str + \"}\\n\";\n            return str;\n        }\n\n        public string GetStackInitializer(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            // define stack variables\n            str += indentationStr + $\"let level_{EnclosingLevel.Name.Name}_{Name.ToString(0, false).ToLower()}_stack_initializers: list initializer_t = \\n  [\";\n            if (VarDeclList.Count == 0 && !IsExternal) {\n                str += \" ]\\n\";\n                return str;\n            }\n            var sep = \"\\n\";\n            foreach (var vardecl in VarDeclList)\n            {\n                str += sep + vardecl.ToFStarLang(indentation + 4);\n                sep = \" ;\\n\";\n            }\n            if (IsExternal)\n            {\n                foreach (var spec in Specs)\n                {\n                    if (spec is MethodSpecReads)\n                    {\n                        var msr = spec as MethodSpecReads;\n                        str += sep + msr.ToFStarLang(indentation + 4);\n                        sep = \" ;\\n\";\n                    }\n                }\n            }\n            str += indentationStr + \"\\n  ]\\n\";\n            return str;\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n\n            // define function statements\n            str += indentationStr + $\"let {Name.ToString(0, false).ToLower()}_func_statements = \\n  [\\n\";\n            var sep = \"\";\n            if (IsExternal)\n            {\n                Expr awaitsSpec = null;\n                Expr undefinedUnlessSpec = null;\n                Expr ensuresSpec = null;\n                List<Expr> modifiesSpec = new List<Expr>();\n                List<Expr> readsSpec = new List<Expr>();\n                List<Expr> logsSpec = new List<Expr>();\n                foreach (var spec in Specs)\n                {\n                    if (spec is MethodSpecReads)\n                    {\n                        readsSpec.AddRange(spec.Elements);\n                    }\n                    else if (spec is MethodSpecAwaits)\n                    {\n                        awaitsSpec = awaitsSpec == null ? spec.overallExpr : new BinaryExpr(awaitsSpec.FirstTok, awaitsSpec, spec.overallExpr, Opcode.And);\n                    }\n                    else if (spec is MethodSpecUndefinedUnless)\n                    {\n                        undefinedUnlessSpec = undefinedUnlessSpec == null ? spec.overallExpr : new BinaryExpr(undefinedUnlessSpec.FirstTok, undefinedUnlessSpec, spec.overallExpr, Opcode.And);\n                    }\n                    else if (spec is MethodSpecModifies)\n                    {\n                        modifiesSpec.Add(spec.overallExpr);\n                    }\n                    else if (spec is MethodSpecEnsures)\n                    {\n                        ensuresSpec = ensuresSpec == null ? spec.overallExpr : new BinaryExpr(ensuresSpec.FirstTok, ensuresSpec, spec.overallExpr, Opcode.And);\n                    }\n                    else if (spec is MethodSpecLogs)\n                    {\n                        logsSpec.AddRange(spec.Elements);\n                    }\n                }\n                string awaitsSpecStr = awaitsSpec != null ? awaitsSpec.ToFStarLang(0) : \"ExpressionConstant (ObjectValueAbstract bool true)\";\n                string undefinedUnlessSpecStr = undefinedUnlessSpec != null ? undefinedUnlessSpec.ToFStarLang(0) : \"ExpressionConstant (ObjectValueAbstract bool true)\";\n                string ensuresSpecStr = ensuresSpec != null ? ensuresSpec.ToFStarLang(0) : \"ExpressionConstant (ObjectValueAbstract bool true)\";\n                string modifiesSpecStr = \"[ \" + string.Join(\"; \", modifiesSpec.Select(x => x.ToFStarLang(0)).ToArray()) + \" ]\";\n                string readsSpecStr = \"[ \" + string.Join(\"; \", readsSpec.Select((x, index) => $\"(\\\"_snapshot_var_{index}\\\", {x.ToFStarLang(0)})\").ToArray()) + \" ]\";\n                string logsSpecStr = \"[ \" + string.Join(\"; \", logsSpec.Select(x => $\"({x.ToFStarLang(0)})\").ToArray()) + \" ]\";\n                // TODO set bypassing write buffer from attributes\n                // TODO set read clauses\n                str += sep + (new FStarStmt($\"{Name.ToString(0, false)}.End\", null, false, false,\n                  $\"ExternalMethodStartStatement\\n{indentationStr}        \" +\n                  $\"({awaitsSpecStr})\\n{indentationStr}        \" +\n                  $\"({undefinedUnlessSpecStr})\\n{indentationStr}        \" +\n                  $\"false\\n{indentationStr}        \" +\n                  $\"{modifiesSpecStr}\\n{indentationStr}        \" +\n                  $\"{readsSpecStr}\")).GetFStarCodeOfStatement(indentation + 4);\n                sep = \";\\n\";\n\n                str += sep + (new FStarStmt($\"{Name.ToString(0, false)}.End\", null, false, false,\n                  $\"ExternalMethodMiddleStatement\\n{indentationStr}        \" +\n                  $\"false\\n{indentationStr}        \" +\n                  $\"{modifiesSpecStr}\\n{indentationStr}        \" +\n                  $\"{readsSpecStr}\")).GetFStarCodeOfStatement(indentation + 4);\n                sep = \";\\n\";\n\n                str += sep + (new FStarStmt($\"{Name.ToString(0, false)}.End\", null, false, false,\n                  $\"ExternalMethodEndStatement\\n{indentationStr}        \" + \n                  $\"({ensuresSpecStr})\\n{indentationStr}        \" +\n                  $\"{logsSpecStr}\")).GetFStarCodeOfStatement(indentation + 4);\n                sep = \";\\n\";\n            }\n            foreach (var statement in Stmts)\n            {\n                statement.ToFStarLang(indentation + 4);\n                FStarStmts.AddRange(statement.FStarStmts);\n            }\n            foreach (var callerStmt in CallerStmtList)\n            {\n                callerStmt.ToFStarLang(indentation + 4);\n                FStarStmts.AddRange(callerStmt.FStarStmts);\n            }\n            if (IsCalledWithThread)\n            {\n                FStarStmts.Add(new FStarStmt($\"{Name.ToString(0, false)}.End\", null, false, false, \n                    $\"TerminateThreadStatement \\\"{Name.ToString(0, false)}\\\"\"));\n            }\n            str += sep + String.Join(\";\\n\", FStarStmts.ConvertAll(stmt => stmt.GetFStarCodeOfStatement(indentation + 4)));\n            str += indentationStr + \"\\n  ]\";\n            return str;\n        }\n\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            yield return Name;\n            foreach (var arg in Args)\n            {\n                foreach (var node in arg.AllChildren())\n                    yield return node;\n                yield return arg;\n            }\n            if (Ret != null)\n            {\n                foreach (var node in Ret.AllChildren())\n                    yield return node;\n                yield return Ret;\n            }\n            foreach (var spec in Specs)\n            {\n                foreach (var node in spec.AllChildren())\n                    yield return node;\n                yield return spec;\n            }\n            foreach (var varDecl in VarDeclList)\n            {\n                foreach (var node in varDecl.AllChildren())\n                    yield return node;\n                yield return varDecl;\n            }\n            foreach (var stmt in Stmts)\n            {\n                foreach (var node in stmt.AllChildren())\n                    yield return node;\n                yield return stmt;\n            }\n            foreach (var attr in Attrs)\n            {\n                foreach (var node in attr.AllChildren())\n                    yield return node;\n                yield return attr;\n            }\n        }\n    }\n\n    public abstract class MethodSpec : AstNode\n    {\n        public List<Expr> Elements;\n        public Expr overallExpr = null;\n        public List<Attribute> Attrs = null;\n        public MethodSpec(Token firstTok, List<Expr> elements) : base(firstTok)\n        {\n            this.Elements = elements;\n        }\n\n        public override void SetProgramCounter(string parentPC, int index)\n        {\n            throw new NotSupportedException();\n        }\n        public override void SetNextProgramCounter(string nextPC)\n        {\n            throw new NotSupportedException();\n        }\n        public override string ToCProgram(int indentation)\n        {\n            throw new NotSupportedException();\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var e in Attrs)\n            {\n                foreach (var node in e.AllChildren())\n                    yield return node;\n                yield return e;\n            }\n            foreach (var e in Elements)\n            {\n                foreach (var node in e.AllChildren())\n                    yield return node;\n                yield return e;\n            }\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            if (overallExpr != null)\n            {\n                return overallExpr.ToFStarLang(indentation);\n            }\n            else\n            {\n                throw new NotImplementedException();\n            }\n        }\n    }\n\n    public class MethodSpecAwaits : MethodSpec\n    {\n        public MethodSpecAwaits(Token firstTok, List<Expr> elements) : base(firstTok, elements)\n        { }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"awaits \";\n            var sep = \"\";\n            foreach (var element in Elements)\n            {\n                str += sep + element.ToString(0, false);\n                sep = \", \";\n            }\n            return str;\n        }\n\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            foreach (var e in Elements)\n            {\n                e.Sc = Sc;\n                e.TypeResolve(new PredefinedType(PredefinedTypeEnum.Bool), ref errors);\n            }\n            overallExpr = Elements[0];\n            for (int i = 1; i < Elements.Count; i++)\n            {\n                overallExpr = new BinaryExpr(overallExpr.FirstTok, overallExpr, Elements[i], Opcode.And, false);\n            }\n        }\n    }\n\n    public class MethodSpecUndefinedUnless : MethodSpec\n    {\n        public MethodSpecUndefinedUnless(Token firstTok, List<Expr> elements) : base(firstTok, elements)\n        { }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"undefined_unless \";\n            var sep = \"\";\n            foreach (var element in Elements)\n            {\n                str += sep + element.ToString(0, false);\n                sep = \", \";\n            }\n            return str;\n        }\n\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            foreach (var e in Elements)\n            {\n                e.Sc = Sc;\n                e.TypeResolve(new PredefinedType(PredefinedTypeEnum.Bool), ref errors);\n            }\n            overallExpr = Elements[0];\n            for (int i = 1; i < Elements.Count; i++)\n            {\n                overallExpr = new BinaryExpr(overallExpr.FirstTok, overallExpr, Elements[i], Opcode.And, false);\n            }\n        }\n    }\n\n    public class MethodSpecEnsures : MethodSpec\n    {\n        public MethodSpecEnsures(Token firstTok, List<Expr> elements) : base(firstTok, elements)\n        { }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"ensures \";\n            var sep = \"\";\n            foreach (var element in Elements)\n            {\n                str += sep + element.ToString(0, false);\n                sep = \", \";\n            }\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            foreach (var e in Elements)\n            {\n                e.Sc = Sc;\n                e.TypeResolve(new PredefinedType(PredefinedTypeEnum.Bool), ref errors);\n            }\n            overallExpr = Elements[0];\n            for (int i = 1; i < Elements.Count; i++)\n            {\n                overallExpr = new BinaryExpr(overallExpr.FirstTok, overallExpr, Elements[i], Opcode.And, false);\n            }\n        }\n    }\n\n    public class MethodSpecModifies : MethodSpec\n    {\n        public MethodSpecModifies(Token firstTok, List<Expr> elements) : base(firstTok, elements)\n        { }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"modifies \";\n            var sep = \"\";\n            foreach (var element in Elements)\n            {\n                str += sep + element.ToString(0, false);\n                sep = \", \";\n            }\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            foreach (var e in Elements)\n            {\n                e.Sc = Sc;\n                e.TypeResolve(null, ref errors);\n            }\n            overallExpr = Elements[0];\n            for (int i = 1; i < Elements.Count; i++)\n            {\n                overallExpr = new BinaryExpr(overallExpr.FirstTok, overallExpr, Elements[i], Opcode.And, false);\n            }\n        }\n    }\n\n    public class MethodSpecReads : MethodSpec\n    {\n        public List<Ident> Variables = new List<Ident>();\n        public MethodSpecReads(Token firstTok, List<Expr> elements) : base(firstTok, elements)\n        { }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"reads \";\n            var sep = \"\";\n            foreach (var element in Elements)\n            {\n                str += sep + element.ToString(0, false);\n                sep = \", \";\n            }\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            foreach (var e in Elements)\n            {\n                e.Sc = Sc;\n                e.TypeResolve(null, ref errors);\n                Contract.Assert(e is Ident);\n                Variables.Add(e as Ident);\n            }\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            var sep = \"\";\n            foreach (var v in Variables)\n            {\n                str += sep + indentationStr + $\"{{ var_id = \\\"{v.ToString(0, false)}\\\"; \";\n                str += $\"iv = \";\n                str += \"InitializerArbitrary\";\n                str += $\" ({v.Ty.ToFStarLang(0, true)});\";\n                str += \" weakly_consistent = false; }\";\n                sep = \" ;\\n\";\n            }\n            return str;\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var node in base.AllChildren())\n            {\n                yield return node;\n            }\n            foreach (var e in Variables)\n            {\n                foreach (var node in e.AllChildren())\n                    yield return node;\n                yield return e;\n            }\n        }\n    }\n\n    public class MethodSpecRequires : MethodSpec\n    {\n        public MethodSpecRequires(Token firstTok, List<Expr> elements) : base(firstTok, elements)\n        { }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"requires \";\n            var sep = \"\";\n            foreach (var element in Elements)\n            {\n                str += sep + element.ToString(0, false);\n                sep = \", \";\n            }\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            foreach (var e in Elements)\n            {\n                e.Sc = Sc;\n                e.TypeResolve(new PredefinedType(PredefinedTypeEnum.Bool), ref errors);\n            }\n            overallExpr = Elements[0];\n            for (int i = 1; i < Elements.Count; i++)\n            {\n                overallExpr = new BinaryExpr(overallExpr.FirstTok, overallExpr, Elements[i], Opcode.And, false);\n            }\n        }\n    }\n\n    public class MethodSpecLogs : MethodSpec\n    {\n        public MethodSpecLogs(Token firstTok, List<Expr> elements) : base(firstTok, elements)\n        { }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"logs \";\n            var sep = \"\";\n            foreach (var element in Elements)\n            {\n                str += sep + element.ToString(0, false);\n                sep = \", \";\n            }\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            foreach (var e in Elements)\n            {\n                e.Sc = Sc;\n                e.TypeResolve(null, ref errors);\n            }\n            overallExpr = Elements[0];\n            for (int i = 1; i < Elements.Count; i++)\n            {\n                overallExpr = new BinaryExpr(overallExpr.FirstTok, overallExpr, Elements[i], Opcode.And, false);\n            }\n        }\n    }\n\n    public enum InvariantType {\n        MAINTAINED_IF_STATEMENT_SATISFIES = 1,\n        MAINTAINED_IF_VARS_UNCHANGED = 2\n    }\n\n    public class InvariantDecl : MemberDecl\n    {\n        public Expr Body;\n        public InvariantType InvType;\n        public List<Ident> UnchangedVars;\n\n        public InvariantDecl(Token tok, Ident name, Expr body, InvariantType invType, List<Ident> unchangedVars) : base(tok)\n        {\n            this.Name = name;\n            this.Body = body;\n            this.InvType = invType;\n            this.UnchangedVars = unchangedVars;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"invariant \" + this.Name.ToString(0, labelOn) + \" {\\n\";\n            str = str + this.Body.ToString(indentation + 2, labelOn) + \"\\n\";\n            str = str + indentationStr + \"} by \";\n            if (InvType == InvariantType.MAINTAINED_IF_STATEMENT_SATISFIES) {\n                str += \"maintained_if_statement_satisfies\";\n            } else if (InvType == InvariantType.MAINTAINED_IF_VARS_UNCHANGED) {\n                str += \"maintained_if_vars_unchanged\";\n            } else {\n                throw new NotSupportedException();\n            }\n            var sep = \" \";\n            foreach (var id in UnchangedVars) {\n                str += sep + id.ToString(0, false);\n                sep = \", \";\n            }\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            Body.Sc = Sc;\n            Body.TypeResolve(new PredefinedType(PredefinedTypeEnum.Bool), ref errors);\n        }\n        public override void SetProgramCounter(string parentPC, int index)\n        {\n            throw new NotSupportedException();\n        }\n        public override void SetNextProgramCounter(string nextPC)\n        {\n            throw new NotSupportedException();\n        }\n        public override string ToCProgram(int indentation)\n        {\n            throw new NotSupportedException();\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            throw new NotSupportedException();\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var child in Body.AllChildren()) {\n                yield return child;\n            }\n            yield return Body;\n            foreach (var id in UnchangedVars) {\n                yield return id;\n            }\n        }\n    }\n\n    public class YieldPredicateDecl : MemberDecl\n    {\n        public Expr Body;\n\n        public YieldPredicateDecl(Token tok, Ident name, Expr body) : base(tok)\n        {\n            this.Name = name;\n            this.Body = body;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"yield predicate \" + this.Name.ToString(0, labelOn) + \" {\\n\";\n            str = str + indentationStr + this.Body.ToString(0, labelOn) + \"\\n\";\n            str = str + indentationStr + \"}\";\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            throw new NotImplementedException();\n        }\n        public override void SetProgramCounter(string parentPC, int index)\n        {\n            throw new NotImplementedException();\n        }\n        public override void SetNextProgramCounter(string nextPC)\n        {\n            throw new NotImplementedException();\n        }\n        public override string ToCProgram(int indentation)\n        {\n            throw new NotSupportedException();\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            throw new NotImplementedException();\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            throw new NotImplementedException();\n        }\n    }\n\n\n    public class Parameter : VarDecl\n    {\n        public Parameter(Token tok, Ident name, Type ty) : base(tok, name, ty)\n        {\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + Name.ToString(0, labelOn) + \":\" + Ty.ToString(0);\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            base.TypeResolve(enforcingType, ref errors);\n        }\n        public override void SetProgramCounter(string parentPC, int index)\n        {\n            throw new NotImplementedException();\n        }\n        public override string ToCProgram(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + Ty.ToCProgram(0) + \" \" + Name.ToCProgram(0);\n            return str;\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + Name.ToString(0, false) + \":\" + Ty.ToFStarLang(0, false);\n            return str;\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            yield return Name;\n        }\n    }\n\n    public class ProofDecl : AstNode\n    {\n        public Ident Name;\n        public Ident LLevelName;\n        public Ident HLevelName;\n        public ProofStrategy Strategy;\n        public ProofDecl(Token tok, Ident name, Ident LName, Ident HName, ProofStrategy strategy) : base(tok)\n        {\n            this.Name = name;\n            this.LLevelName = LName;\n            this.HLevelName = HName;\n            this.Strategy = strategy;\n        }\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"proof \" + Name.ToString(0, labelOn) + \" {\\n\";\n            str = str + indentationStr + \"  refinement \" + LLevelName.ToString(0, labelOn) + \" \" + HLevelName.ToString(0, labelOn) + \"\\n\";\n            str = str + Strategy.ToString(indentation + 2, labelOn) + \"\\n\";\n            str = str + indentationStr + \"}\";\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            // throw new NotImplementedException();\n            // TODO: implement it\n        }\n        public override void SetProgramCounter(string parentPC, int index)\n        {\n            throw new NotImplementedException();\n        }\n        public override void SetNextProgramCounter(string nextPC)\n        {\n            throw new NotImplementedException();\n        }\n        public override string ToCProgram(int indentation)\n        {\n            throw new NotSupportedException();\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            throw new NotImplementedException();\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            yield return Name;\n            yield return LLevelName;\n            yield return HLevelName;\n            foreach (var node in Strategy.AllChildren())\n                yield return node;\n            yield return Strategy;\n        }\n    }\n\n    public class Ident : Expr\n    {\n        public string Name;\n        public VarDecl Declaration;\n\n        public Ident(Token tok, string name)\n        : base(tok)\n        {\n            this.Name = name;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string indentationStr = new string(' ', indentation);\n            string str = indentationStr + Name;\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            VarDecl varDeclaration = Sc.GetVariableDecl(this, false);\n            if (varDeclaration != null)\n            {\n                this.Ty = varDeclaration.Ty;\n            }\n            else\n            {\n                errors.SemErr(FirstTok, $\"{Name} is not defined!\");\n                return;\n            }\n            this.Declaration = varDeclaration;\n            this.Ty = varDeclaration.Ty;\n            CheckCompatiblity(enforcingType, ref errors);\n        }\n\n        public override void SetProgramCounter(string parentPC, int index)\n        {\n            this.PC = $\"{parentPC}.{index}\";\n        }\n        public override void SetNextProgramCounter(string nextPC)\n        {\n            this.NextPC = nextPC;\n        }\n        public bool FitsInInt8()\n        {\n            sbyte value;\n            return sbyte.TryParse(Name, out value);\n        }\n        public bool FitsInInt16()\n        {\n            Int16 value;\n            return Int16.TryParse(Name, out value);\n        }\n        public bool FitsInInt32()\n        {\n            Int32 value;\n            return Int32.TryParse(Name, out value);\n        }\n        public bool FitsInInt64()\n        {\n            Int64 value;\n            return Int64.TryParse(Name, out value);\n        }\n        public bool FitsInUInt8()\n        {\n            byte value;\n            return byte.TryParse(Name, out value);\n        }\n        public bool FitsInUInt16()\n        {\n            UInt16 value;\n            return UInt16.TryParse(Name, out value);\n        }\n        public bool FitsInUInt32()\n        {\n            UInt32 value;\n            return UInt32.TryParse(Name, out value);\n        }\n        public bool FitsInUInt64()\n        {\n            UInt64 value;\n            return UInt64.TryParse(Name, out value);\n        }\n        public override string ToCProgram(int indentation)\n        {\n            return ToString(indentation, false);\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            var declInLocalScope = Sc.GetVariableDecl(this, true);\n            if (declInLocalScope == Declaration)\n            {\n                // local variable\n                return $\"ExpressionLocalVariable ({this.Ty.ToFStarLang(0, true)}) \\\"{this.ToString(0, false)}\\\"\";\n            }\n            else\n            {\n                // global variable\n                return $\"ExpressionGlobalVariable ({this.Ty.ToFStarLang(0, true)}) \\\"{this.ToString(0, false)}\\\"\";\n            }\n        }\n        public override string ToFStarExpr(string armadaStateName)\n        {\n            if (armadaStateName == \"\") {\n                return Name;\n            } else {\n                return $\"{armadaStateName}.mem (RootIdGlobal \\\"{Name}\\\")\";\n            }\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            yield break;\n        }\n    }\n}\n"
  },
  {
    "path": "experimental/Source/Armada/AST/Expr.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Diagnostics.Contracts;\n\nnamespace Microsoft.Starmada\n{\n    public abstract class Expr : AstNode\n    {\n        // TODO: Token class variable\n        public Expr(Token tok) : base(tok)\n        {\n            Contract.Requires(tok != null);\n        }\n\n        public Type Ty;\n\n        // public override string ToString(int indentation, bool labelOn) {\n        //     string str = \"\";\n        //     string indentationStr = new string(' ', indentation);\n        //     str = str + indentationStr + \"undefined expr\";\n        //     return str;\n        // }\n\n        // Setting Program Counter for Expressions is generic\n        public override void SetProgramCounter(string parentPC, int index)\n        {\n            // TODO: Implement this function\n            this.PC = parentPC;\n        }\n        public override void SetNextProgramCounter(string nextPC)\n        {\n            this.NextPC = nextPC;\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            return ToString(indentation, false);\n        }\n\n        public abstract string ToFStarExpr(string armadaStateName);\n\n        public void CheckCompatiblity(Type enforcingType, ref Errors errors) {\n            if (enforcingType != null)\n            {   \n                if (!(this.Ty.CompatibleType(enforcingType))) {\n                    errors.SemErr(FirstTok, $\"Type checking fails: expected: {enforcingType.ToString(0)}, got: {this.Ty.ToString(0)}.\");\n                }\n                this.Ty = enforcingType;\n            }\n        }\n    }\n\n    public interface FStarExpressionConstant\n    {\n        string ToFStarObjectValue();\n    }\n\n    public class ConstantExpr : Expr, FStarExpressionConstant\n    {\n        Ident Value;\n        public ConstantExpr(Token tok, Ident value)\n        : base(tok)\n        {\n            this.Value = value;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + Value.ToString(0, labelOn);\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            Contract.Requires(this.Ty != null);\n            Contract.Requires(Value.Ty is PredefinedType);\n            Contract.Requires(enforcingType == null || enforcingType is PredefinedType);\n\n            var pdt = Value.Ty as PredefinedType;\n            if (enforcingType == null)\n            {\n                this.Ty = Value.Ty;\n                if (Value.FirstTok.val.StartsWith(\"-\") && pdt.IsBoundedInt())\n                {\n                    if ((pdt.Kind == PredefinedTypeEnum.UInt64) ||\n                        (pdt.Kind == PredefinedTypeEnum.UInt32))\n                    {\n                        errors.Warning(Value.FirstTok,\n                                    $\"{Value.FirstTok.val} is both negative and unsigned! \" +\n                                    $\"It will be casted to {this.Ty.ToString(0)}\");\n                    }\n                }\n            }\n            else\n            {\n                var enforcingPred = enforcingType as PredefinedType;\n                if (enforcingPred.IsBoundedInt())\n                {\n                    this.Ty = enforcingType;\n                    switch (enforcingPred.Kind)\n                    {\n                        case PredefinedTypeEnum.Int8:\n                            if (!Value.FitsInInt8())\n                            {\n                                errors.Warning(Value.FirstTok,\n                                    $\"{Value.FirstTok.val} doesn't fit in int8!\");\n                            }\n                            break;\n                        case PredefinedTypeEnum.Int16:\n                            if (!Value.FitsInInt16())\n                            {\n                                errors.Warning(Value.FirstTok,\n                                    $\"{Value.FirstTok.val} doesn't fit in int16!\");\n                            }\n                            break;\n                        case PredefinedTypeEnum.Int32:\n                            if (!Value.FitsInInt32())\n                            {\n                                errors.Warning(Value.FirstTok,\n                                    $\"{Value.FirstTok.val} doesn't fit in int32!\");\n                            }\n                            break;\n                        case PredefinedTypeEnum.Int64:\n                            if (!Value.FitsInInt64())\n                            {\n                                errors.Warning(Value.FirstTok,\n                                    $\"{Value.FirstTok.val} doesn't fit in int64!\");\n                            }\n                            break;\n                        case PredefinedTypeEnum.UInt8:\n                            if (!Value.FitsInUInt8())\n                            {\n                                errors.Warning(Value.FirstTok,\n                                    $\"{Value.FirstTok.val} doesn't fit in uint8!\");\n                            }\n                            if (Value.FirstTok.val.StartsWith(\"-\"))\n                            {\n                                errors.Warning(Value.FirstTok,\n                                    $\"{Value.FirstTok.val} is both negative and unsigned! \" +\n                                    $\"It will be casted to {this.Ty.ToString(0)}\");\n                            }\n                            break;\n                        case PredefinedTypeEnum.UInt16:\n                            if (!Value.FitsInUInt16())\n                            {\n                                errors.Warning(Value.FirstTok,\n                                    $\"{Value.FirstTok.val} doesn't fit in uint16!\");\n                            }\n                            if (Value.FirstTok.val.StartsWith(\"-\"))\n                            {\n                                errors.Warning(Value.FirstTok,\n                                    $\"{Value.FirstTok.val} is both negative and unsigned! \" +\n                                    $\"It will be casted to {this.Ty.ToString(0)}\");\n                            }\n                            break;\n                        case PredefinedTypeEnum.UInt32:\n                            if (!Value.FitsInUInt32())\n                            {\n                                errors.Warning(Value.FirstTok,\n                                    $\"{Value.FirstTok.val} doesn't fit in uint32!\");\n                            }\n                            if (Value.FirstTok.val.StartsWith(\"-\"))\n                            {\n                                errors.Warning(Value.FirstTok,\n                                    $\"{Value.FirstTok.val} is both negative and unsigned! \" +\n                                    $\"It will be casted to {this.Ty.ToString(0)}\");\n                            }\n                            break;\n                        case PredefinedTypeEnum.UInt64:\n                            if (!Value.FitsInUInt64())\n                            {\n                                errors.Warning(Value.FirstTok,\n                                    $\"{Value.FirstTok.val} doesn't fit in uint64!\");\n                            }\n                            if (Value.FirstTok.val.StartsWith(\"-\"))\n                            {\n                                errors.Warning(Value.FirstTok,\n                                    $\"{Value.FirstTok.val} is both negative and unsigned! \" +\n                                    $\"It will be casted to {this.Ty.ToString(0)}\");\n                            }\n                            break;\n                        default:\n                            errors.SemErr(Value.FirstTok, \"unsupported type!\");\n                            break;\n                    }\n                }\n                else if (enforcingPred.Kind == PredefinedTypeEnum.Int || enforcingPred.Kind == PredefinedTypeEnum.Nat) {\n                    this.Ty = enforcingType;\n                }\n                else if (enforcingPred.Kind == PredefinedTypeEnum.ThreadId) {\n                    if (!Value.FitsInUInt32())\n                    {\n                        errors.SemErr(Value.FirstTok,\n                            $\"{Value.FirstTok.val} is not a valid thread id!\");\n                    }\n                    this.Ty = enforcingType;\n                }\n                else {\n                    errors.SemErr(Value.FirstTok, $\"Unsupported type {enforcingType.ToString(0)}\");\n                }\n            }\n        }\n\n        public string ToFStarObjectValue()\n        {\n            string str = \"\";\n            if (this.Ty is PredefinedType)\n            {\n                var pt = this.Ty as PredefinedType;\n                if (pt.IsBoundedInt())\n                {\n                    str += $\"ObjectValuePrimitive (PrimitiveBoxBoundedInt {Ty.ToFStarLang(0, false)} ({Value.ToString(0, false)}))\";\n                }\n                else\n                {\n                    str += \"ObjectValueAbstract \" + Ty.ToFStarLang(0, false) + \" (\" + Value.ToString(0, false) + \")\";\n                }\n            }\n            else\n            {\n                throw new NotImplementedException();\n            }\n            return str;\n        }\n\n        public override string ToFStarLang(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str += indentationStr + \"ExpressionConstant (\" + ToFStarObjectValue() + \")\";\n            return str;\n        }\n\n        public override string ToFStarExpr(string armadaStateName)\n        {\n            if (armadaStateName == \"\") {\n                return ToString(0, false);\n            } else {\n                return $\"RootGlobal (ObjectStorageAbstract {Ty.ToFStarLang(0, false)} ( {Value.ToString(0, false)} ))\";\n            }\n        }\n\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            yield return Value;\n        }\n    }\n\n    public class Attribute : AstNode\n    {\n        public Ident Name;\n        public List<Expr> Exprs;\n\n        public Attribute(Token tok, Ident name, List<Expr> exprs)\n        : base(tok)\n        {\n            Contract.Requires(name != null);\n            Contract.Requires(exprs != null);\n            Name = name;\n            Exprs = exprs;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + \"{: \" + Name.ToString(0, labelOn) + \" \" + Util.ListExprsToString(Exprs, labelOn) + \"}\";\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            throw new NotImplementedException();\n        }\n        public override void SetProgramCounter(string parentPC, int index)\n        {\n            throw new NotImplementedException();\n        }\n        public override void SetNextProgramCounter(string nextPC)\n        {\n            throw new NotImplementedException();\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            throw new NotSupportedException();\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            throw new NotImplementedException();\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            yield return Name;\n            foreach (var expr in Exprs)\n            {\n                foreach (var node in expr.AllChildren())\n                    yield return node;\n                yield return expr;\n            }\n        }\n    }\n\n    public class WildcardExpr : Expr\n    {\n        public WildcardExpr(Token tok) : base(tok)\n        {\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string indentationStr = new string(' ', indentation);\n            return indentationStr + \"*\";\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            throw new NotImplementedException();\n        }\n\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            this.Ty = enforcingType;\n            return;\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            throw new NotImplementedException();\n        }\n        public override string ToFStarExpr(string armadaStateName)\n        {\n            throw new NotImplementedException();\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            yield break;\n        }\n    }\n\n    public class UnaryExpr : Expr\n    {\n        public Expr operand;\n        public Opcode opcode;\n        public bool lvalue;\n        public UnaryExpr(Token tok, Expr operand, Opcode op, bool lvalue = false)\n        : base(tok)\n        {\n            this.operand = operand;\n            this.opcode = op;\n            this.lvalue = lvalue;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            if (opcode == Opcode.Cardinality)\n            {\n                str = str + indentationStr + \"|\" + this.operand.ToString(0, labelOn) + \"|\";\n            }\n            else\n            {\n                str = str + indentationStr + OpcodeToString.OpToStr(opcode) + this.operand.ToString(0, labelOn);\n            }\n            return str;\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            if (opcode == Opcode.Cardinality)\n            {\n                throw new NotSupportedException();\n            }\n            return ToString(indentation, false);\n        }\n\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            // TODO: check compatibility according to opcode and deal with enforcing type.\n            operand.Sc = Sc;\n            switch (opcode)\n            {\n                case Opcode.Neg:\n                case Opcode.BitwiseNot:\n                    // TODO: operand should be numbers\n                    operand.TypeResolve(enforcingType, ref errors);\n                    this.Ty = operand.Ty;\n                    if (Ty is PredefinedType)\n                    {\n                        var pt = (Ty as PredefinedType);\n                        if (pt.Kind == PredefinedTypeEnum.Bool \n                            || pt.Kind == PredefinedTypeEnum.ThreadId\n                            || pt.Kind == PredefinedTypeEnum.Char\n                            || pt.Kind == PredefinedTypeEnum.String)\n                        {\n                            errors.SemErr(operand.FirstTok, $\"{operand.FirstTok.val} cannot be negated.\");\n                            return;\n                        }\n                    }\n                    break;\n                case Opcode.Not:\n                    operand.TypeResolve(new PredefinedType(PredefinedTypeEnum.Bool), ref errors);\n                    this.Ty = operand.Ty;\n                    break;\n                case Opcode.AddressOf:\n                    operand.TypeResolve(null, ref errors);\n                    this.Ty = new PointerType(operand.Ty);\n                    break;\n                case Opcode.Dereference:\n                    operand.TypeResolve(null, ref errors);\n                    PointerType ty = (PointerType)operand.Ty;\n                    if (ty == null)\n                    {\n                        errors.SemErr(operand.FirstTok, $\"{operand.FirstTok.val} is not a pointer.\");\n                        return;\n                    }\n                    this.Ty = ty.EntityType;\n                    break;\n                case Opcode.Allocated:\n                case Opcode.AllocatedArray:\n                    operand.TypeResolve(null, ref errors);\n                    ty = (PointerType)operand.Ty;\n                    if (ty == null)\n                    {\n                        errors.SemErr(operand.FirstTok, $\"{operand.FirstTok.val} is not a pointer.\");\n                    }\n                    this.Ty = new PredefinedType(PredefinedTypeEnum.Bool);\n                    break;\n                case Opcode.GlobalView:\n                    operand.TypeResolve(enforcingType, ref errors);\n                    this.Ty = operand.Ty;\n                    break;\n                case Opcode.Cardinality:\n                    operand.TypeResolve(null, ref errors);\n                    if (!(operand.Ty is CollectionType))\n                    {\n                        errors.SemErr(operand.FirstTok, $\"{operand.FirstTok.val} is not of a collection type.\");\n                    }\n                    this.Ty = new PredefinedType(PredefinedTypeEnum.Nat);\n                    // TODO: check compatibility\n                    break;\n                default: throw new NotImplementedException();\n            }\n            CheckCompatiblity(enforcingType, ref errors);\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            string opcodeFStar = \"\";\n            string prefix = \"Armada.UnaryOp.UnaryOp\";\n            bool bounded = false;\n            if (operand.Ty is PredefinedType && (operand.Ty as PredefinedType).IsBoundedInt())\n            {\n                bounded = true;\n            }\n            switch (opcode)\n            {\n                case Opcode.Neg: opcodeFStar = prefix + (bounded ? $\"BoundedNeg {operand.Ty.ToFStarLang(0, false)}\" : \"Neg\"); break;\n                case Opcode.BitwiseNot: \n                    if (!bounded) {\n                        throw new NotSupportedException(\"bitwise operation for unbounded values not supported\");\n                    }\n                    opcodeFStar = prefix + $\"BitwiseNot {operand.Ty.ToFStarLang(0, false)}\";\n                    break;\n                case Opcode.Not: opcodeFStar = prefix + (bounded ? $\"BoundedNot {operand.Ty.ToFStarLang(0, false)}\" : \"Not\"); break;\n                case Opcode.AddressOf: return new string(' ', indentation) + $\"ExpressionAddressOf ({operand.ToFStarLang(0)})\";\n                case Opcode.Dereference: return new string(' ', indentation) + $\"ExpressionDereference ({operand.Ty.ToFStarLang(0, true)}) ({operand.ToFStarLang(0)})\";\n                // case Opcode.Allocated: opcodeFStar = prefix + (bounded ? $\"BoundedMod {firstOp.Ty.ToFStarLang(0, false)}\" : \"ModInt\"); break;\n                // case Opcode.AllocatedArray: opcodeFStar = prefix + \"LeftShift\"; break;\n                // case Opcode.GlobalView: opcodeFStar = prefix + \"RightShift\"; break;\n                case Opcode.Cardinality:\n                    string fn = \"\";\n                    if (operand.Ty is SeqType)\n                    {\n                        fn += \"seq_cardinality\";\n                    }\n                    else if (operand.Ty is SetType)\n                    {\n                        fn += (operand.Ty as SetType).IsInfinite ? \"set_cardinality\" : \"finiteset_cardinality\";\n                    }\n                    else if (operand.Ty is MapType)\n                    {\n                        fn += (operand.Ty as MapType).IsInfinite ? \"map_cardinality\" : \"finitemap_cardinality\";\n                    }\n                    else\n                    {\n                        throw new NotImplementedException();\n                    }\n                    return new string(' ', indentation) + $\"ExpressionApplyFunction (ObjectTDAbstract nat) [{operand.ToFStarLang(0)}] nat [{operand.Ty.ToFStarLang(0, false)}] {fn}\";\n                default: throw new NotImplementedException();\n            }\n            // return \"\";\n            return new string(' ', indentation) + $\"ExpressionUnaryOperator ({operand.Ty.ToFStarLang(0, true)}) ({Ty.ToFStarLang(0, true)}) ({opcodeFStar}) ({operand.ToFStarLang(0)})\";\n\n        }\n        public override string ToFStarExpr(string armadaStateName)\n        {\n            throw new NotImplementedException();\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var node in operand.AllChildren())\n                yield return node;\n            yield return operand;\n        }\n    }\n\n\n    public class BinaryExpr : Expr\n    {\n        public Expr firstOp;\n        public Expr secondOp;\n        public Opcode opcode;\n        public bool lvalue;\n        public BinaryExpr(Token tok, Expr firstOp, Expr secondOp = null, Opcode op = Opcode.Add, bool lvalue = false)\n        : base(tok)\n        {\n            this.firstOp = firstOp;\n            this.secondOp = secondOp;\n            this.opcode = op;\n            this.lvalue = lvalue;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + this.firstOp.ToString(0, labelOn); ;\n            if (opcode == Opcode.Dot)\n            {\n                str = str + OpcodeToString.OpToStr(opcode);\n            }\n            else\n            {\n                str = str + \" \" + OpcodeToString.OpToStr(opcode) + \" \";\n            }\n            str = str + this.secondOp.ToString(0, labelOn);\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            firstOp.Sc = Sc;\n            secondOp.Sc = Sc;\n            switch (opcode)\n            {\n                case Opcode.Add:\n                    firstOp.TypeResolve(enforcingType, ref errors);\n                    if (firstOp.Ty is PointerType) {\n                        secondOp.TypeResolve(new PredefinedType(PredefinedTypeEnum.Int), ref errors);\n                    }\n                    else {\n                        secondOp.TypeResolve(firstOp.Ty, ref errors);\n                    }\n                    this.Ty = firstOp.Ty;\n                    break;\n                case Opcode.Sub:\n                case Opcode.Div:\n                    firstOp.TypeResolve(enforcingType, ref errors);\n                    secondOp.TypeResolve(firstOp.Ty, ref errors);\n                    this.Ty = enforcingType;\n                    break;\n                case Opcode.Mul: // TODO: first bouned multiplication type checking\n                    firstOp.TypeResolve(null, ref errors);\n                    secondOp.TypeResolve(firstOp.Ty, ref errors);\n                    if (enforcingType != null) {\n                        this.Ty = enforcingType;\n                    }\n                    else {\n                        this.Ty = firstOp.Ty;\n                    }\n                    return;\n                case Opcode.Mod:\n                    firstOp.TypeResolve(enforcingType, ref errors);\n                    secondOp.TypeResolve(firstOp.Ty, ref errors);\n                    this.Ty = firstOp.Ty;\n                    break;\n                case Opcode.LeftShift:\n                case Opcode.RightShift:\n                    firstOp.TypeResolve(null, ref errors);\n                    secondOp.TypeResolve(new PredefinedType(PredefinedTypeEnum.Nat), ref errors);\n                    this.Ty = firstOp.Ty;\n                    break;\n                case Opcode.Equal:\n                case Opcode.NotEqual:\n                    firstOp.TypeResolve(null, ref errors);\n                    secondOp.TypeResolve(firstOp.Ty, ref errors);\n                    this.Ty = new PredefinedType(PredefinedTypeEnum.Bool);\n                    break;\n                case Opcode.Lt:\n                case Opcode.Le:\n                case Opcode.Gt:\n                case Opcode.Ge:\n                    // Lt, Le, Gt, Ge support Int, BoundedInt, Pointer\n                    firstOp.TypeResolve(null, ref errors);\n                    secondOp.TypeResolve(firstOp.Ty, ref errors);\n                    this.Ty = new PredefinedType(PredefinedTypeEnum.Bool);\n                    break;\n                case Opcode.In:\n                case Opcode.NotIn:\n                    firstOp.TypeResolve(null, ref errors);\n                    secondOp.TypeResolve(null, ref errors);\n                    if (!(secondOp.Ty is CollectionType))\n                    {\n                        errors.SemErr(secondOp.FirstTok, $\"{secondOp.FirstTok.val} is not of a collection type.\");\n                    }\n                    this.Ty = new PredefinedType(PredefinedTypeEnum.Bool);\n                    break;\n                case Opcode.Disjoint:\n                    firstOp.TypeResolve(null, ref errors);\n                    secondOp.TypeResolve(firstOp.Ty, ref errors);\n                    if (!(secondOp.Ty is SetType))\n                    {\n                        errors.SemErr(secondOp.FirstTok, $\"{secondOp.FirstTok.val} is not of a set type.\");\n                    }\n                    this.Ty = new PredefinedType(PredefinedTypeEnum.Bool);\n                    break;\n                case Opcode.And:\n                case Opcode.Or:\n                    firstOp.TypeResolve(new PredefinedType(PredefinedTypeEnum.Bool), ref errors);\n                    secondOp.TypeResolve(firstOp.Ty, ref errors);\n                    this.Ty = secondOp.Ty;\n                    break;\n                case Opcode.BitwiseAnd:\n                case Opcode.BitwiseOr:\n                case Opcode.BitwiseXor:\n                    firstOp.TypeResolve(enforcingType, ref errors);\n                    secondOp.TypeResolve(firstOp.Ty, ref errors);\n                    this.Ty = secondOp.Ty;\n                    break;\n                case Opcode.Dot:\n                    firstOp.TypeResolve(null, ref errors);\n                    if (firstOp.Ty is not UserDefinedType)\n                    {\n                        errors.SemErr(firstOp.FirstTok, $\"Datatype {firstOp.ToString(0, false)} not found.\");\n                    }\n                    string name = (firstOp.Ty as UserDefinedType).Name.Name;\n                    StructDecl structDecl = Sc.GetStructDecl(name);\n                    DatatypeDecl datatypeDecl = Sc.GetDatatypeDecl(name);\n                    if (structDecl == null && datatypeDecl == null)\n                    {\n                        errors.SemErr(firstOp.FirstTok, $\"Datatype {name} not found.\");\n                    }\n                    if (secondOp is not Ident)\n                    {\n                        errors.SemErr(secondOp.FirstTok, $\"{secondOp.FirstTok.val} is not a valid field.\");\n                    }\n                    string fieldName = (secondOp as Ident).Name;\n                    if (datatypeDecl != null && datatypeDecl.GetFunctionInvocation(fieldName, \"\") == null)\n                    {\n                        errors.SemErr(secondOp.FirstTok, $\"{fieldName} is not a valid field.\");\n                    }\n                    if (structDecl != null)\n                    {\n                        var fieldDecl = structDecl.GetField(fieldName);\n                        if (fieldDecl == null)\n                        {\n                            errors.SemErr(secondOp.FirstTok, $\"{fieldName} is not a valid field.\");\n                        }\n                        this.Ty = fieldDecl.Ty;\n                    }\n                    // TODO: check secondOp is valid?\n                    break;\n                case Opcode.Equiv:\n                case Opcode.Imply:\n                case Opcode.Exply:\n                    firstOp.TypeResolve(new PredefinedType(PredefinedTypeEnum.Bool), ref errors);\n                    secondOp.TypeResolve(new PredefinedType(PredefinedTypeEnum.Bool), ref errors);\n                    this.Ty = new PredefinedType(PredefinedTypeEnum.Bool);\n                    break;\n                default: break;\n            }\n            CheckCompatiblity(enforcingType, ref errors);\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            switch (opcode)\n            {\n                case Opcode.Equiv:\n                case Opcode.Imply:\n                case Opcode.Exply:\n                case Opcode.Disjoint:\n                case Opcode.In:\n                case Opcode.NotIn:\n                    throw new NotSupportedException();\n                default:\n                    break;\n            }\n            return ToString(indentation, false);\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            string opcodeFStar = \"\";\n            string prefix = \"Armada.BinaryOp.BinaryOp\";\n            bool bounded = false;\n            bool pointer = false;\n            if (firstOp.Ty is PredefinedType && (firstOp.Ty as PredefinedType).IsBoundedInt() &&\n                secondOp.Ty is PredefinedType && (secondOp.Ty as PredefinedType).IsBoundedInt())\n            {\n                bounded = true;\n            }\n            if (firstOp.Ty is PointerType && secondOp.Ty is PointerType)\n            {\n                pointer = true;\n            }\n            switch (opcode)\n            {\n                case Opcode.Add:\n                    if (firstOp.Ty is PointerType) {\n                        return $\"(ExpressionPointerOffset ({firstOp.ToFStarLang(0)}) ({secondOp.ToFStarLang(0)}))\";\n                    }\n                    else {\n                        opcodeFStar = prefix + (bounded ? $\"BoundedAdd {firstOp.Ty.ToFStarLang(0, false)}\" : \"AddInt\");\n                    }\n                    break;\n                case Opcode.Sub: opcodeFStar = prefix + (bounded ? $\"BoundedSub {firstOp.Ty.ToFStarLang(0, false)}\" : \"SubInt\"); break;\n                case Opcode.Mul: opcodeFStar = prefix + (bounded ? $\"BoundedMul {firstOp.Ty.ToFStarLang(0, false)}\" : \"MulInt\"); break;\n                case Opcode.Div: opcodeFStar = prefix + (bounded ? $\"BoundedDiv {firstOp.Ty.ToFStarLang(0, false)}\" : \"DivInt\"); break;\n                case Opcode.Mod: opcodeFStar = prefix + (bounded ? $\"BoundedMod {firstOp.Ty.ToFStarLang(0, false)}\" : \"ModInt\"); break;\n                case Opcode.LeftShift: \n                    if (firstOp.Ty is PredefinedType && (firstOp.Ty as PredefinedType).IsBoundedInt()) {\n                        opcodeFStar = prefix + $\"BitwiseLeftShift {firstOp.Ty.ToFStarLang(0, false)}\";\n                    }\n                    else {\n                        opcodeFStar = prefix + $\"LeftShift\";\n                    }\n                    break;\n                case Opcode.RightShift: \n                if (firstOp.Ty is PredefinedType && (firstOp.Ty as PredefinedType).IsBoundedInt()) {\n                        opcodeFStar = prefix + $\"BitwiseRightShift {firstOp.Ty.ToFStarLang(0, false)}\";\n                    }\n                    else {\n                        opcodeFStar = prefix + $\"RightShift\";\n                    }\n                break;\n                case Opcode.Equal:\n                    opcodeFStar = $\"{prefix}Eq ({firstOp.Ty.ToFStarLang(0, true)})\";\n                    break;\n                case Opcode.NotEqual:\n                    opcodeFStar = $\"{prefix}Neq ({firstOp.Ty.ToFStarLang(0, true)})\";\n                    break;\n                case Opcode.Lt: opcodeFStar = prefix + (pointer ? \"PtrLt\" : (bounded ? $\"BoundedLt {firstOp.Ty.ToFStarLang(0, false)}\" : \"LtInt\")); break;\n                case Opcode.Le: opcodeFStar = prefix + (pointer ? \"PtrLe\" : (bounded ? $\"BoundedLe {firstOp.Ty.ToFStarLang(0, false)}\" : \"LeInt\")); break;\n                case Opcode.Gt: opcodeFStar = prefix + (pointer ? \"PtrGt\" : (bounded ? $\"BoundedGt {firstOp.Ty.ToFStarLang(0, false)}\" : \"GtInt\")); break;\n                case Opcode.Ge: opcodeFStar = prefix + (pointer ? \"PtrGe\" : (bounded ? $\"BoundedGe {firstOp.Ty.ToFStarLang(0, false)}\" : \"GeInt\")); break;\n                case Opcode.In:\n                case Opcode.NotIn:\n                    string fn = (opcode == Opcode.NotIn) ? \"not_\" : \"\";\n                    if (secondOp.Ty is SeqType)\n                    {\n                        fn += \"seq_contains\";\n                    }\n                    else if (secondOp.Ty is SetType)\n                    {\n                        fn += (secondOp.Ty as SetType).IsInfinite ? \"set_contains\" : \"finite_set_contains\";\n                    }\n                    else if (secondOp.Ty is MapType)\n                    {\n                        fn += (secondOp.Ty as MapType).IsInfinite ? \"map_contains\" : \"finite_map_contains\";\n                    }\n                    else\n                    {\n                        throw new NotImplementedException();\n                    }\n                    return new string(' ', indentation) + $\"ExpressionApplyFunction (ObjectTDPrimitive PrimitiveTDBool) [{firstOp.ToFStarLang(0)}; {secondOp.ToFStarLang(0)}] bool [{firstOp.Ty.ToFStarLang(0, false)}; {secondOp.Ty.ToFStarLang(0, false)}] {fn}\";\n                case Opcode.Disjoint:\n                    string disjoint_fn = (firstOp.Ty as SetType).IsInfinite ? \"set_disjoint\" : \"finiteset_disjoint\";\n                    return new string(' ', indentation) + $\"ExpressionApplyFunction (ObjectTDPrimitive PrimitiveTDBool) [{firstOp.ToFStarLang(0)}; {secondOp.ToFStarLang(0)}] bool [{firstOp.Ty.ToFStarLang(0, false)}; {secondOp.Ty.ToFStarLang(0, false)}] {disjoint_fn}\";\n                case Opcode.And: opcodeFStar = prefix + \"And\"; break;\n                case Opcode.Or: opcodeFStar = prefix + \"Or\"; break;\n                // The Bitwise operators are not supported\n                case Opcode.BitwiseAnd: \n                    if (!bounded) {\n                        throw new NotSupportedException(\"bitwise operation for unbounded values not supported\");\n                    }\n                    opcodeFStar = prefix + $\"BitwiseAnd {firstOp.Ty.ToFStarLang(0, false)}\";\n                    break;\n                case Opcode.BitwiseOr: \n                    if (!bounded) {\n                        throw new NotSupportedException(\"bitwise operation for unbounded values not supported\");\n                    }\n                    opcodeFStar = prefix + $\"BitwiseOr {firstOp.Ty.ToFStarLang(0, false)}\";\n                    break;\n                case Opcode.BitwiseXor: \n                    if (!bounded) {\n                        throw new NotSupportedException(\"bitwise operation for unbounded values not supported\");\n                    }\n                    opcodeFStar = prefix + $\"BitwiseXor {firstOp.Ty.ToFStarLang(0, false)}\";\n                    break;\n                case Opcode.Dot:\n                    string name = (firstOp.Ty as UserDefinedType).Name.Name;\n                    StructDecl structDecl = Sc.GetStructDecl(name);\n                    DatatypeDecl datatypeDecl = Sc.GetDatatypeDecl(name);\n                    string fieldName = (secondOp as Ident).Name;\n                    if (datatypeDecl != null)\n                    {\n                        return datatypeDecl.GetFunctionInvocation(fieldName, firstOp.ToFStarLang(0));\n                    }\n                    else if (structDecl != null)\n                    {\n                        if (firstOp.ToString(0, false) == \"$state\")\n                        {\n                            if (secondOp.ToString(0, false) == \"initial_tid\")\n                            {\n                                return \"ExpressionInitialTid\";\n                            }\n                            else if (secondOp.ToString(0, false) == \"uniqs_used\")\n                            {\n                                return \"ExpressionUniqsUsed\";\n                            }\n                            else if (secondOp.ToString(0, false) == \"stop_reason\")\n                            {\n                                return \"ExpressionStopReason\";\n                            }\n                            else\n                            {\n                                throw new NotSupportedException();\n                            }\n                        }\n                        return structDecl.GetFieldAccessInFStar(fieldName, firstOp.ToFStarLang(0));\n                    }\n                    break;\n                case Opcode.Equiv: opcodeFStar = prefix + \"Equiv\"; break;\n                case Opcode.Imply: opcodeFStar = prefix + \"Imply\"; break;\n                case Opcode.Exply: opcodeFStar = prefix + \"Exply\"; break;\n                default: throw new NotImplementedException();\n            }\n            return new string(' ', indentation) + $\"ExpressionBinaryOperator ({firstOp.Ty.ToFStarLang(0, true)}) ({secondOp.Ty.ToFStarLang(0, true)}) ({Ty.ToFStarLang(0, true)}) ({opcodeFStar}) ({firstOp.ToFStarLang(0)}) ({secondOp.ToFStarLang(0)})\";\n        }\n        public override string ToFStarExpr(string armadaStateName)\n        {\n            string op1 = $\"{firstOp.ToFStarExpr(armadaStateName)}\";\n            string op2 = $\"{secondOp.ToFStarExpr(armadaStateName)}\";\n            switch (opcode)\n            {\n                case Opcode.Add:\n                    return $\"({op1}) + ({op2})\";\n                case Opcode.Sub:\n                    return $\"({op1}) - ({op2})\";\n                case Opcode.Mul:\n                    return $\"op_Multiply ({op1}) ({op2})\";\n                case Opcode.Div: throw new NotImplementedException();\n                case Opcode.Mod: throw new NotImplementedException();\n                case Opcode.LeftShift: throw new NotImplementedException();\n                case Opcode.RightShift: throw new NotImplementedException();\n                case Opcode.Equal:\n                    return $\"({op1}) == ({op2})\";\n                case Opcode.NotEqual: throw new NotImplementedException();\n                case Opcode.Lt: throw new NotImplementedException();\n                case Opcode.Le: throw new NotImplementedException();\n                case Opcode.Gt: throw new NotImplementedException();\n                case Opcode.Ge: throw new NotImplementedException();\n                case Opcode.In:\n                    if (secondOp.Ty is SeqType)\n                    {\n                        return $\"contains ({op2}) ({op1})\";\n                    }\n                    else if (secondOp.Ty is SetType)\n                    {\n                        return (secondOp.Ty as SetType).IsInfinite ? $\"FStar.Set.mem ({op1}) ({op2})\" : $\"FStar.FiniteSet.Base.mem ({op1}) ({op2})\";\n                    }\n                    else if (secondOp.Ty is MapType)\n                    {\n                        return (secondOp.Ty as MapType).IsInfinite ? $\"FStar.Map.contains ({op2}) ({op1})\" : $\"FStar.FiniteMap.Base.mem ({op1}) ({op2})\";\n                    }\n                    else\n                    {\n                        throw new NotImplementedException();\n                    }\n                case Opcode.NotIn: throw new NotImplementedException();\n                case Opcode.Disjoint: throw new NotImplementedException();\n                case Opcode.And: throw new NotImplementedException();\n                case Opcode.Or: throw new NotImplementedException();\n                case Opcode.BitwiseAnd: throw new NotImplementedException();\n                case Opcode.BitwiseOr: throw new NotImplementedException();\n                case Opcode.BitwiseXor: throw new NotImplementedException();\n                case Opcode.Dot: throw new NotImplementedException();\n                case Opcode.Equiv: throw new NotImplementedException();\n                case Opcode.Imply: throw new NotImplementedException();\n                case Opcode.Exply: throw new NotImplementedException();\n                default: throw new NotImplementedException();\n            }\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var node in firstOp.AllChildren())\n                yield return node;\n            yield return firstOp;\n            foreach (var node in secondOp.AllChildren())\n                yield return node;\n            yield return secondOp;\n        }\n    }\n\n    public class IfExpr : Expr\n    {\n        public Expr Cond;\n        public Expr ThenExpr;\n        public Expr ElseExpr;\n        public IfExpr(Token tok, Expr cond, Expr thenExpr, Expr elseExpr)\n        : base(tok)\n        {\n            Contract.Requires(cond != null);\n            Contract.Requires(thenExpr != null);\n            Contract.Requires(elseExpr != null);\n            this.Cond = cond;\n            this.ThenExpr = thenExpr;\n            this.ElseExpr = elseExpr;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"if \" + Cond.ToString(0, labelOn) +\n                  \" then \" + ThenExpr.ToString(0, labelOn) + \" else \" + ElseExpr.ToString(0, labelOn);\n            return str;\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"(\" + Cond.ToCProgram(0) + \") ? \"\n                  + ThenExpr.ToCProgram(indentation + 2) + \" : \"\n                  + ElseExpr.ToCProgram(indentation + 2);\n            return str;\n        }\n\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            Cond.Sc = Sc;\n            ThenExpr.Sc = Sc;\n            ElseExpr.Sc = Sc;\n            Cond.TypeResolve(new PredefinedType(PredefinedTypeEnum.Bool), ref errors);\n            ThenExpr.TypeResolve(enforcingType, ref errors);\n            ElseExpr.TypeResolve(ThenExpr.Ty, ref errors);\n            this.Ty = ElseExpr.Ty;\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str += $\"ExpressionIf ({ThenExpr.Ty.ToFStarLang(0, true)}) ({Cond.ToFStarLang(0)}) ({ThenExpr.ToFStarLang(0)}) ({ElseExpr.ToFStarLang(0)})\";\n            return str;\n        }\n        public override string ToFStarExpr(string armadaStateName)\n        {\n            throw new NotImplementedException();\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var node in Cond.AllChildren())\n                yield return node;\n            yield return Cond;\n            foreach (var node in ThenExpr.AllChildren())\n                yield return node;\n            yield return ThenExpr;\n            foreach (var node in ElseExpr.AllChildren())\n                yield return node;\n            yield return ElseExpr;\n        }\n    }\n\n    public class LiteralExpr : Expr, FStarExpressionConstant\n    {\n        public readonly object Value;\n\n        public LiteralExpr(Token tok)\n        : base(tok)\n        {\n            this.Value = null;\n        }\n\n        public LiteralExpr(Token tok, bool b)\n        : base(tok)\n        {\n            this.Value = b;\n        }\n\n        public LiteralExpr(Token tok, int n)\n        : base(tok)\n        {\n            this.Value = n;\n        }\n\n        // This constructor is used by CharLiteralExpr and StringLiteralExpr\n        protected LiteralExpr(Token tok, string s)\n        : base(tok)\n        {\n            Contract.Requires(s != null);\n            this.Value = s;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            if (Value == null) {\n                str = str + indentationStr + \"null\";\n            }\n            else {\n                string valueStr = (Value is bool) ? Value.ToString().ToLower() : Value.ToString();\n                str = str + indentationStr + valueStr;\n            }\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            if (Value == null)\n            {\n                Contract.Assert(enforcingType is PointerType);\n                this.Ty = enforcingType;\n            }\n            else if (Value is int)\n            {\n                this.Ty = new PredefinedType(PredefinedTypeEnum.Int);\n            }\n            else if (Value is bool)\n            {\n                this.Ty = new PredefinedType(PredefinedTypeEnum.Bool);\n            }\n            CheckCompatiblity(enforcingType, ref errors);\n        }\n        public string ToFStarObjectValue()\n        {\n            if (Value is bool)\n            {\n                return $\"ObjectValuePrimitive (PrimitiveBoxBool {ToString(0, false)})\";\n            }\n            return \"ObjectValueAbstract \" + Ty.ToString(0) + \" \" + ToString(0, false);\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str += indentationStr + \"ExpressionConstant (\" + ToFStarObjectValue() + \")\";\n            return str;\n        }\n        public override string ToFStarExpr(string armadaStateName)\n        {\n            return ToString(0, false);\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            yield break;\n        }\n    }\n\n    public class CharLiteralExpr : LiteralExpr\n    {\n        public CharLiteralExpr(Token tok, string s)\n        : base(tok, s)\n        { }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"'\" + this.Value.ToString() + \"'\";\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            this.Ty = new PredefinedType(PredefinedTypeEnum.Char);\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            yield break;\n        }\n    }\n\n    public class StringLiteralExpr : LiteralExpr\n    {\n        public readonly bool IsVerbatim;\n\n        public StringLiteralExpr(Token tok, string s, bool isVerbatim)\n        : base(tok, s)\n        {\n            this.IsVerbatim = isVerbatim;\n        }\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"\\\"\" + this.Value.ToString() + \"\\\"\";\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            this.Ty = new PredefinedType(PredefinedTypeEnum.String);\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            yield break;\n        }\n    }\n\n    public class NullPointerExpr : Expr\n    {\n        public NullPointerExpr(Token tok)\n        : base(tok) { }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"null\";\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            this.Ty = enforcingType;\n            CheckCompatiblity(enforcingType, ref errors);\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            return ToString(indentation, false);\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str += indentationStr + $\"ExpressionConstant (ObjectValuePrimitive (PrimitiveBoxPointer PointerNull))\";\n            return str;\n        }\n        public override string ToFStarExpr(string armadaStateName)\n        {\n            throw new NotImplementedException();\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            yield break;\n        }\n    }\n\n    public class MeExpr : Expr\n    {\n        public MeExpr(Token tok)\n        : base(tok) { }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"$me\";\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            this.Ty = new PredefinedType(PredefinedTypeEnum.ThreadId);\n            CheckCompatiblity(enforcingType, ref errors);\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            throw new NotSupportedException();\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            throw new NotImplementedException();\n        }\n        public override string ToFStarExpr(string armadaStateName)\n        {\n            throw new NotImplementedException();\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            yield break;\n        }\n    }\n\n    public class StoreBufferEmptyExpr : Expr\n    {\n        public StoreBufferEmptyExpr(Token tok)\n        : base(tok) { }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"$sb_empty\";\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            // TODO: Implement this function\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            throw new NotSupportedException();\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            throw new NotImplementedException();\n        }\n        public override string ToFStarExpr(string armadaStateName)\n        {\n            throw new NotImplementedException();\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            yield break;\n        }\n    }\n\n    public class IfUndefinedExpr : Expr\n    {\n        public Expr PotentiallyUnsafe, SafeSubstitution;\n\n        public IfUndefinedExpr(Token tok, Expr potentiallyUnsafe, Expr safeSubstitution)\n        : base(tok)\n        {\n            this.PotentiallyUnsafe = potentiallyUnsafe;\n            this.SafeSubstitution = safeSubstitution;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"if_undefined (\" +\n                  PotentiallyUnsafe.ToString(0, labelOn) + \", \" + SafeSubstitution.ToString(0, labelOn) + \")\";\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            // The type for PotentiallyUnsafe and SafeSubstitution should be the same\n            PotentiallyUnsafe.Sc = Sc;\n            SafeSubstitution.Sc = Sc;\n            PotentiallyUnsafe.TypeResolve(enforcingType, ref errors);\n            SafeSubstitution.TypeResolve(enforcingType, ref errors);\n            this.Ty = SafeSubstitution.Ty;\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            throw new NotSupportedException();\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str += indentationStr + $\"ExpressionIfUndefined ({this.Ty.ToFStarLang(0, true)}) ({PotentiallyUnsafe.ToFStarLang(0)}) ({SafeSubstitution.ToFStarLang(0)})\";\n            return str;\n        }\n        public override string ToFStarExpr(string armadaStateName)\n        {\n            throw new NotImplementedException();\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var node in PotentiallyUnsafe.AllChildren())\n                yield return node;\n            yield return PotentiallyUnsafe;\n            foreach (var node in SafeSubstitution.AllChildren())\n                yield return node;\n            yield return SafeSubstitution;\n        }\n    }\n\n    public class MapDisplayExpr : Expr\n    {\n        public bool Finite;\n        public Dictionary<Expr, Expr> Elements;\n\n        public MapDisplayExpr(Token tok, bool finite, Dictionary<Expr, Expr> elements)\n        : base(tok)\n        {\n            // Contract.Requires(cce.NonNullElements(elements));\n            Finite = finite;\n            Elements = elements;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            List<string> elementsStr = new List<string>();\n            foreach (var kv in Elements)\n            {\n                elementsStr.Add(kv.Key.ToString(0, labelOn) + \":=\" + kv.Value.ToString(0, labelOn));\n            }\n            str = str + indentationStr + FirstTok.val + \" [\" + string.Join(\", \", elementsStr) + \"]\";\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            Type prevElementKeyType = null;\n            Type prevElementValueType = null;\n            if (enforcingType != null)\n            {\n                if (enforcingType is not MapType)\n                {\n                    errors.SemErr(FirstTok, $\"Cannot convert {this.ToString(0, false)} to non-map type.\");\n                }\n                MapType enforcingMapType = (enforcingType as MapType);\n                if (enforcingMapType.IsInfinite == Finite)\n                {\n                    errors.SemErr(FirstTok, $\"The finite of map does not match.\");\n                }\n                prevElementKeyType = enforcingMapType.KeyType;\n                prevElementValueType = enforcingMapType.EntityType;\n            }\n            foreach (var kv in Elements)\n            {\n                kv.Key.Sc = Sc;\n                kv.Value.Sc = Sc;\n                kv.Key.TypeResolve(prevElementKeyType, ref errors);\n                prevElementKeyType = kv.Key.Ty;\n                kv.Value.TypeResolve(prevElementValueType, ref errors);\n                prevElementValueType = kv.Value.Ty;\n            }\n            this.Ty = new MapType(prevElementKeyType, prevElementValueType, !Finite);\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            throw new NotSupportedException();\n        }\n\n        public override string ToFStarLang(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str += indentationStr;\n            string emptyStr = Finite ? \"FStar.FiniteMap.Base.emptymap\" : \"(FStar.Map.const 0)\";\n            string expressionStr = $\"ExpressionConstant (ObjectValueAbstract ({this.Ty.ToFStarLang(0, false)}) {emptyStr})\";\n            Type keyTy = (this.Ty as MapType).KeyType;\n            Type valueTy = (this.Ty as MapType).EntityType;\n            if (Elements.Count > 0)\n            {\n                foreach (var kv in Elements)\n                {\n                    var key = kv.Key;\n                    var value = kv.Value;\n                    string insertStr = Finite ? \"finite_map_insert\" : \"map_insert\";\n                    expressionStr = $\"ExpressionApplyFunction ({this.Ty.ToFStarLang(0, true)}) [{expressionStr}; {key.ToFStarLang(0)}; {value.ToFStarLang(0)}] ({this.Ty.ToFStarLang(0, false)}) [{this.Ty.ToFStarLang(0, false)}; {keyTy.ToFStarLang(0, false)}; {valueTy.ToFStarLang(0, false)}] {insertStr}\";\n                }\n            }\n            str += expressionStr;\n            return str;\n        }\n        public override string ToFStarExpr(string armadaStateName)\n        {\n            throw new NotImplementedException();\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (KeyValuePair<Expr, Expr> entry in Elements)\n            {\n                foreach (var node in entry.Key.AllChildren())\n                    yield return node;\n                yield return entry.Key;\n                foreach (var node in entry.Value.AllChildren())\n                    yield return node;\n                yield return entry.Value;\n            }\n        }\n    }\n\n    public abstract class DisplayExpr : Expr\n    {\n        public readonly List<Expr> Elements;\n\n        public DisplayExpr(Token tok, List<Expr> elements)\n        : base(tok)\n        {\n            // Contract.Requires(cce.NonNullElements(elements));\n            Elements = elements;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            List<string> elementsStr = new List<string>();\n            foreach (Expr expr in Elements)\n            {\n                elementsStr.Add(expr.ToString(0, labelOn));\n            }\n            str = str + indentationStr + string.Join(\", \", elementsStr);\n            return str;\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            throw new NotSupportedException();\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            throw new NotImplementedException();\n        }\n        public override string ToFStarExpr(string armadaStateName)\n        {\n            throw new NotImplementedException();\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var element in Elements)\n            {\n                foreach (var node in element.AllChildren())\n                    yield return node;\n                yield return element;\n            }\n        }\n    }\n\n    public class SetDisplayExpr : DisplayExpr\n    {\n        public bool Finite;\n\n        public SetDisplayExpr(Token tok, bool finite, List<Expr> elements)\n        : base(tok, elements)\n        {\n            Finite = finite;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"{\" + base.ToString(0, labelOn) + \"}\";\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            Type prevElementType = null;\n            if (enforcingType != null)\n            {\n                if (enforcingType is not SetType)\n                {\n                    errors.SemErr(FirstTok, $\"Cannot convert {this.ToString(0, false)} to non-set type.\");\n                }\n                SetType enforcingSetType = (enforcingType as SetType);\n                if (enforcingSetType.IsInfinite == Finite)\n                {\n                    errors.SemErr(FirstTok, $\"The finite of set does not match.\");\n                }\n                prevElementType = enforcingSetType.EntityType;\n            }\n            foreach (var element in Elements)\n            {\n                element.Sc = Sc;\n                element.TypeResolve(prevElementType, ref errors);\n                prevElementType = element.Ty;\n            }\n            this.Ty = new SetType(prevElementType, !Finite);\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            throw new NotSupportedException();\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str += indentationStr;\n            Type elementTy = (this.Ty as SetType).EntityType;\n            string emptyStr = Finite ? \"FStar.FiniteSet.Base.emptyset\" : \"FStar.Set.empty\";\n            string expressionStr = $\"ExpressionConstant (ObjectValueAbstract ({this.Ty.ToFStarLang(0, false)}) {emptyStr})\";\n            if (!Finite)\n            {\n                if (Elements.Count > 0)\n                {\n                    List<string> exprStrs = new List<string>();\n                    foreach (var expr in Elements)\n                    {\n                        exprStrs.Add($\"ExpressionApplyFunction ({this.Ty.ToFStarLang(0, true)}) [{expr.ToFStarLang(0)}] ({this.Ty.ToFStarLang(0, false)}) [{elementTy.ToFStarLang(0, false)}] set_singleton\");\n                    }\n                    expressionStr = exprStrs[0];\n                    for (int i = 1; i < Elements.Count; i++)\n                    {\n                        expressionStr = $\"ExpressionApplyFunction ({this.Ty.ToFStarLang(0, true)}) [{expressionStr}; {exprStrs[i]}] ({this.Ty.ToFStarLang(0, false)}) [{this.Ty.ToFStarLang(0, false)}; {this.Ty.ToFStarLang(0, false)}] set_union\";\n                    }\n                }\n            }\n            else\n            {\n                if (Elements.Count > 0)\n                {\n                    foreach (var expr in Elements)\n                    {\n                        expressionStr = $\"ExpressionApplyFunction ({this.Ty.ToFStarLang(0, true)}) [{expr.ToFStarLang(0)}; {expressionStr}] ({this.Ty.ToFStarLang(0, false)}) [{elementTy.ToFStarLang(0, false)}; {this.Ty.ToFStarLang(0, false)}] finite_set_insert\";\n                    }\n                }\n            }\n            str += expressionStr;\n            return str;\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var node in base.AllChildren())\n                yield return node;\n        }\n    }\n\n    public class SeqDisplayExpr : DisplayExpr\n    {\n        public SeqDisplayExpr(Token tok, List<Expr> elements)\n        : base(tok, elements) { }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"[\" + base.ToString(0, labelOn) + \"]\";\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            Type prevElementType = null;\n            bool checkConstant = false;\n            if (enforcingType != null)\n            {\n                if (enforcingType is SeqType)\n                {\n                    prevElementType = (enforcingType as SeqType).EntityType;\n                    this.Ty = new SeqType(prevElementType);\n                }\n                else if (enforcingType is TypeSuffix)\n                {\n                    prevElementType = (enforcingType as TypeSuffix).EntityType;\n                    var size = (enforcingType as TypeSuffix).Size;\n                    int count = Int32.Parse(size.ToString(0, false));\n                    if (count != Elements.Count)\n                    {\n                        errors.SemErr(FirstTok, $\"Array Size mismatch, expected: {count}, got {Elements.Count}.\");\n                    }\n                    this.Ty = new TypeSuffix(prevElementType, size);\n                    checkConstant = true;\n                }\n                else\n                {\n                    errors.SemErr(FirstTok, $\"Cannot convert {this.ToString(0, false)} to non-seq type.\");\n                }\n            }\n            foreach (var element in Elements)\n            {\n                if (checkConstant)\n                {\n                    if (element is not FStarExpressionConstant)\n                    {\n                        errors.SemErr(element.FirstTok, $\"You must initialize an array with constant values.\");\n                    }\n                }\n                element.Sc = Sc;\n                element.TypeResolve(prevElementType, ref errors);\n                prevElementType = element.Ty;\n            }\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            throw new NotSupportedException();\n        }\n\n        public string ToFStarObjectValue()\n        {\n            if (this.Ty is TypeSuffix)\n            {\n                Type elementTy = (this.Ty as TypeSuffix).EntityType;\n                string expressionStr = \"empty\";\n                if (Elements.Count > 0)\n                {\n                    foreach (var expr in Elements)\n                    {\n                        expressionStr = $\"build ({expressionStr}) ({(expr as FStarExpressionConstant).ToFStarObjectValue()})\";\n                    }\n                }\n                return $\"ObjectValueArray ({elementTy.ToFStarLang(0, true)}) ({expressionStr})\";\n            }\n            else\n            {\n                throw new NotSupportedException();\n            }\n        }\n\n        public override string ToFStarLang(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str += indentationStr;\n            if (this.Ty is SeqType)\n            {\n                Type elementTy = (this.Ty as SeqType).EntityType;\n                string expressionStr = $\"ExpressionConstant (ObjectValueAbstract ({this.Ty.ToFStarLang(0, false)}) empty)\";\n                if (Elements.Count > 0)\n                {\n                    foreach (var expr in Elements)\n                    {\n                        expressionStr = $\"ExpressionApplyFunction ({this.Ty.ToFStarLang(0, true)}) [{expressionStr}; {expr.ToFStarLang(0)}] ({this.Ty.ToFStarLang(0, false)}) [{this.Ty.ToFStarLang(0, false)}; {elementTy.ToFStarLang(0, false)}] seq_build\";\n                    }\n                }\n                str += expressionStr;\n            }\n            else if (this.Ty is TypeSuffix)\n            {\n                str += $\"ExpressionConstant ({ToFStarObjectValue()})\";\n            }\n            return str;\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var node in base.AllChildren())\n                yield return node;\n        }\n    }\n\n    // To be deleted\n    public class MultiSetDisplayExpr : DisplayExpr\n    {\n        public MultiSetDisplayExpr(Token tok, List<Expr> elements)\n        : base(tok, elements) { }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"multiset\" + \"{\" + base.ToString(0, labelOn) + \"}\";\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            // TODO: Implement this function\n            Type prevElementType = null;\n            foreach (var element in Elements)\n            {\n                element.Sc = Sc;\n                element.TypeResolve(prevElementType, ref errors);\n                prevElementType = element.Ty;\n            }\n            this.Ty = new SetType(prevElementType, false);\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            throw new NotSupportedException();\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            throw new NotImplementedException();\n        }\n        public override string ToFStarExpr(string armadaStateName)\n        {\n            throw new NotImplementedException();\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var node in base.AllChildren())\n                yield return node;\n        }\n    }\n\n    // To be deleted\n    public class MultiSetFormingExpr : Expr\n    {\n        public readonly Expr Expression;\n\n        public MultiSetFormingExpr(Token tok, Expr expr)\n        : base(tok)\n        {\n            Contract.Requires(expr != null);\n            // cce.Owner.AssignSame(this, expr);\n            Expression = expr;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"multiset\" + \"(\" + Expression.ToString(0, labelOn) + \")\";\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            Expression.Sc = Sc;\n            Expression.TypeResolve(null, ref errors);\n            if (!(Expression.Ty is CollectionType))\n            {\n                errors.SemErr(Expression.FirstTok, $\"{Expression.FirstTok.val} is not of a collection type.\");\n            }\n            CollectionType ty = (CollectionType)Expression.Ty;\n            this.Ty = new SetType(ty.EntityType, false);\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            throw new NotSupportedException();\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            throw new NotImplementedException();\n        }\n        public override string ToFStarExpr(string armadaStateName)\n        {\n            throw new NotImplementedException();\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var node in Expression.AllChildren())\n                yield return node;\n            yield return Expression;\n        }\n    }\n\n    // To be deleted\n    public class SeqConstructionExpr : Expr\n    {\n        public Expr N;\n        public Expr Initializer;\n        public SeqConstructionExpr(Token tok, Expr length, Expr initializer)\n        : base(tok)\n        {\n            Contract.Requires(length != null);\n            Contract.Requires(initializer != null);\n            N = length;\n            Initializer = initializer;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"seq\" + \"(\" + N.ToString(0, labelOn) + \", \" + Initializer.ToString(0, labelOn) + \")\";\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            N.Sc = Sc;\n            Initializer.Sc = Sc;\n            N.TypeResolve(new PredefinedType(PredefinedTypeEnum.Nat), ref errors);\n            // TODO: Initializer's type should be enforced to boolean, right?\n            // In seq(k, n => n+1), n => n+1 should be boolean.\n            // We may need to enforce the type of Initializer to be ImpliesExpression, and\n            // set the type of Set to be the same as the type of second operand in ImpliesExpression.\n            // potential BUG here.\n            Initializer.TypeResolve(null, ref errors);\n            this.Ty = new SetType(Initializer.Ty, false);\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            throw new NotSupportedException();\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            throw new NotImplementedException();\n        }\n        public override string ToFStarExpr(string armadaStateName)\n        {\n            throw new NotImplementedException();\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var node in N.AllChildren())\n                yield return node;\n            yield return N;\n            foreach (var node in Initializer.AllChildren())\n                yield return node;\n            yield return Initializer;\n        }\n    }\n\n    public class ConversionExpr : Expr\n    {\n        public readonly Expr Expression;\n        public readonly Type ToType;\n\n        public ConversionExpr(Token tok, Expr expr, Type toType)\n        : base(tok)\n        {\n            Contract.Requires(expr != null);\n            Contract.Requires(toType != null);\n            this.Expression = expr;\n            this.ToType = toType;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + ToType.ToString(0) + \"(\" + Expression.ToString(0, labelOn) + \")\";\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            Expression.Sc = Sc;\n            Expression.TypeResolve(null, ref errors);\n            if (ToType is not PredefinedType || !(ToType as PredefinedType).IsBoundedInt())\n            {\n                errors.SemErr(FirstTok, \"The type should be bounded int type.\");\n            }\n            this.Ty = ToType;\n            CheckCompatiblity(enforcingType, ref errors);\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"(\" + ToType.ToString(0) + \")\" + Expression.ToCProgram(0);\n            return str;\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str += indentationStr + $\"ExpressionUnaryOperator ({Expression.Ty.ToFStarLang(0, true)}) ({Ty.ToFStarLang(0, true)}) (Armada.UnaryOp.UnaryOpCast {Expression.Ty.ToFStarLang(0, false)} {Ty.ToFStarLang(0, false)}) ({Expression.ToFStarLang(0)})\";\n            return str;\n        }\n        public override string ToFStarExpr(string armadaStateName)\n        {\n            throw new NotImplementedException();\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var node in Expression.AllChildren())\n                yield return node;\n            yield return Expression;\n        }\n    }\n\n    // To be deleted\n    public class LabelExpr : Expr\n    {\n        public readonly string Name;\n        public readonly Expr Body;\n\n        public LabelExpr(Token tok, string p, Expr body)\n        : base(tok)\n        {\n            Name = p;\n            Body = body;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"label \" + Name + \": \" + Body.ToString(0, labelOn);\n            return str;\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            // TODO: Implement this\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            return str;\n        }\n\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            Body.Sc = Sc;\n            Body.TypeResolve(null, ref errors);\n            // TODO: set this.ty\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            throw new NotImplementedException();\n        }\n        public override string ToFStarExpr(string armadaStateName)\n        {\n            throw new NotImplementedException();\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var node in Body.AllChildren())\n                yield return node;\n            yield return Body;\n        }\n    }\n\n    public abstract class QuantifierExpr : Expr\n    {\n        public List<Ident> Idents;\n        public Expr Range;\n        public Expr Body;\n        public Attribute Attrs;\n\n        public string fnInvocation;\n\n        public QuantifierExpr(Token tok, List<Ident> idents, Expr range, Expr body, Attribute attrs)\n        : base(tok)\n        {\n            Idents = idents;\n            Range = range;\n            Body = body;\n            Attrs = attrs;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            string indentsStr = Util.ListIdentsToString(Idents, labelOn) + \" \";\n            string attrsStr = (Attrs == null) ? \"\" : Attrs.ToString(0, labelOn) + \" \";\n            string rangeStr = (Range == null) ? \"\" : \"| \" + Range.ToString(0, labelOn) + \" \";\n            string quantifierDomainStr = indentsStr + attrsStr + rangeStr;\n            str = str + indentationStr + FirstTok.val + \" \" + quantifierDomainStr + \":: \" + Body.ToString(0, labelOn);\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            foreach (Ident ident in Idents)\n            {\n                BoundVarDecl bv = new BoundVarDecl(ident.FirstTok, ident, ident.Ty);\n                bv.Sc = Sc;\n                bv.TypeResolve(null, ref errors); // bv will be pushed into scope in TypeResolve\n            }\n            if (Attrs != null)\n            {\n                Attrs.Sc = Sc;\n                Attrs.TypeResolve(null, ref errors);\n            }\n            if (Range != null)\n            {\n                Range.Sc = Sc;\n                Range.TypeResolve(new PredefinedType(PredefinedTypeEnum.Bool), ref errors);\n            }\n            if (Body != null)\n            {\n                Body.Sc = Sc;\n                Body.TypeResolve(new PredefinedType(PredefinedTypeEnum.Bool), ref errors);\n            }\n            foreach (Ident ident in Idents)\n            {\n                Sc.Pop();\n            }\n            this.Ty = new PredefinedType(PredefinedTypeEnum.Bool);\n            CheckCompatiblity(enforcingType, ref errors);\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            throw new NotSupportedException();\n        }\n\n        private List<Ident> getFnParameters()\n        {\n            List<Ident> idents = new List<Ident>();\n            HashSet<string> names = new HashSet<string>();\n            foreach (Ident bv in this.Idents)\n            {\n                names.Add(bv.Name);\n            }\n            foreach (AstNode node in AllChildren())\n            {\n                Ident ident = node as Ident;\n                if (ident == null || ident.Declaration == null)\n                {\n                    continue;\n                }\n                if (names.Contains(ident.Name))\n                {\n                    continue;\n                }\n                idents.Add(ident);\n                names.Add(ident.Name);\n            }\n            return idents;\n        }\n\n        public string ToFStarFunction(int indentation, string name)\n        {\n            // TODO: add attributes\n            string fnStr = $\"let {name} \";\n            List<string> fstarStrs = new List<string>();\n            List<string> typeStrs = new List<string>();\n            foreach (Ident ident in getFnParameters())\n            {\n                fnStr += $\"({ident.Name}: {ident.Ty.ToFStarLang(0, false)}) \";\n                fstarStrs.Add(ident.ToFStarLang(0));\n                typeStrs.Add(ident.Ty.ToFStarLang(0, false));\n            }\n            List<string> bvStrs = new List<string>();\n            foreach (Ident bv in this.Idents)\n            {\n                bvStrs.Add($\"({bv.Name}: {bv.Ty.ToFStarLang(0, false)})\");\n            }\n            fnStr += $\"= ComputationProduces (u2b (forall {string.Join(' ', bvStrs)}. {Range.ToFStarExpr(\"\")} ==> {Body.ToFStarExpr(\"\")}))\";\n            fnInvocation = $\"ExpressionApplyFunction ({this.Ty.ToFStarLang(0, true)}) [{string.Join(';', fstarStrs)}] ({this.Ty.ToFStarLang(0, false)}) [{string.Join(';', typeStrs)}] {name}\";\n\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str += indentationStr + fnStr;\n            return str;\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str += indentationStr + fnInvocation;\n            return str;\n        }\n        public override string ToFStarExpr(string armadaStateName)\n        {\n            throw new NotImplementedException();\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var ident in Idents)\n            {\n                foreach (var node in ident.AllChildren())\n                    yield return node;\n                yield return ident;\n            }\n            if (Range != null)\n            {\n                foreach (var node in Range.AllChildren())\n                    yield return node;\n                yield return Range;\n            }\n            if (Body != null)\n            {\n                foreach (var node in Body.AllChildren())\n                    yield return node;\n                yield return Body;\n            }\n            if (Attrs != null)\n            {\n                foreach (var node in Attrs.AllChildren())\n                    yield return node;\n                yield return Attrs;\n            }\n        }\n    }\n\n    public class ForallExpr : QuantifierExpr\n    {\n        public ForallExpr(Token tok, List<Ident> idents, Expr range, Expr body, Attribute attrs)\n        : base(tok, idents, range, body, attrs) { }\n        public override string ToFStarLang(int indentation)\n        {\n            return base.ToFStarLang(0);\n        }\n    }\n\n    public class ExistsExpr : QuantifierExpr\n    {\n        public ExistsExpr(Token tok, List<Ident> idents, Expr range, Expr body, Attribute attrs)\n        : base(tok, idents, range, body, attrs) { }\n        public override string ToFStarLang(int indentation)\n        {\n            return base.ToFStarLang(0);\n        }\n    }\n\n    public abstract class ComprehensionExpr : Expr\n    {\n        public readonly List<Ident> Idents;\n        public readonly Expr Range;\n        public Expr Term;\n        public Attribute Attributes;\n        public string fnInvocation;\n\n        public ComprehensionExpr(Token tok, List<Ident> idents, Expr range, Expr term, Attribute attrs)\n        : base(tok)\n        {\n            // Contract.Requires(cce.NonNullElements(idents));\n            Contract.Requires(term != null);\n\n            this.Idents = idents;\n            this.Range = range;\n            this.Term = term;\n            this.Attributes = attrs;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            string idensStr = Util.ListIdentsToString(Idents, labelOn) + \" \";\n            string attrsStr = (Attributes == null) ? \"\" : Attributes.ToString(0, labelOn) + \" \";\n            string rangeStr = (Range == null) ? \"\" : \"| \" + Range.ToString(0, labelOn) + \" \";\n            string bodyStr = (Term == null) ? \"\" : \":: \" + Term.ToString(0, labelOn);\n            str = str + indentationStr + FirstTok.val + \" \" + idensStr + attrsStr + rangeStr + bodyStr;\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            foreach (Ident ident in Idents)\n            {\n                BoundVarDecl bv = new BoundVarDecl(ident.FirstTok, ident, ident.Ty);\n                bv.Sc = Sc;\n                bv.TypeResolve(null, ref errors); // bv will be pushed into scope in TypeResolve\n            }\n            if (Attributes != null)\n            {\n                Attributes.Sc = Sc;\n                Attributes.TypeResolve(null, ref errors);\n            }\n            if (Range != null)\n            {\n                Range.Sc = Sc;\n                Range.TypeResolve(new PredefinedType(PredefinedTypeEnum.Bool), ref errors);\n            }\n            if (Term != null)\n            {\n                Term.Sc = Sc;\n                Term.TypeResolve(enforcingType, ref errors);\n            }\n            if (Range is not BinaryExpr || (Range as BinaryExpr).opcode != Opcode.In)\n            {\n                errors.SemErr(Range.FirstTok, $\"Comprehension expression only supports container range expressions like \\\"x in s\\\"\");\n            }\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            throw new NotSupportedException();\n        }\n        public override string ToFStarExpr(string armadaStateName)\n        {\n            throw new NotImplementedException();\n        }\n        public List<Ident> getFnParameters(Expr boundedExpr)\n        {\n            List<Ident> idents = new List<Ident>();\n            HashSet<string> names = new HashSet<string>();\n            foreach (Ident bv in this.Idents)\n            {\n                names.Add(bv.Name);\n            }\n            foreach (AstNode node in boundedExpr.AllChildren())\n            {\n                Ident ident = node as Ident;\n                if (ident == null || ident.Declaration == null)\n                {\n                    continue;\n                }\n                if (names.Contains(ident.Name))\n                {\n                    continue;\n                }\n                idents.Add(ident);\n                names.Add(ident.Name);\n            }\n            return idents;\n        }\n\n        public string ToFStarMapFunction(int indentation, string name)\n        {\n            string mapFn = name + \"_fn\";\n            string fnStr = $\"let {mapFn} \";\n            List<string> fstarStrs = new List<string>();\n            foreach (Ident ident in getFnParameters(Term))\n            {\n                fnStr += $\"({ident.Name}: {ident.Ty.ToFStarLang(0, false)}) \";\n                fstarStrs.Add(ident.ToFStarLang(0));\n            }\n            foreach (Ident bv in this.Idents)\n            {\n                fnStr += $\"({bv.Name}: {bv.Ty.ToFStarLang(0, false)}) \";\n            }\n            fnStr += $\"= {Term.ToFStarExpr(\"\")}\\n\";\n\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str += indentationStr + fnStr;\n            str += ToFStarFunction(indentation, name);\n            return str;\n        }\n        abstract public string ToFStarFunction(int indentation, string name);\n\n        public override string ToFStarLang(int indentation)\n        {            \n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str += indentationStr + fnInvocation;\n            return str;\n        }\n\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var ident in Idents)\n            {\n                foreach (var node in ident.AllChildren())\n                    yield return node;\n                yield return ident;\n            }\n            if (Attributes != null)\n            {\n                foreach (var node in Attributes.AllChildren())\n                    yield return node;\n                yield return Attributes;\n            }\n            if (Range != null)\n            {\n                foreach (var node in Range.AllChildren())\n                    yield return node;\n                yield return Range;\n            }\n            if (Term != null)\n            {\n                foreach (var node in Term.AllChildren())\n                    yield return node;\n                yield return Term;\n            }\n        }\n    }\n\n    public class SetComprehension : ComprehensionExpr\n    {\n        public readonly bool Finite;\n        public readonly bool TermIsImplicit;  // records the given syntactic form\n\n        public SetComprehension(Token tok, bool finite, List<Ident> idents, Expr range, Expr term, Attribute attrs)\n        : base(tok, idents, range, term ?? new Ident(tok, idents[0].Name), attrs)\n        {\n            Contract.Requires(tok != null);\n            // Contract.Requires(cce.NonNullElements(idents));\n            Contract.Requires(1 <= idents.Count);\n            Contract.Requires(range != null);\n            Contract.Requires(term != null || idents.Count == 1);\n\n            TermIsImplicit = term == null;\n            Finite = finite;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            return base.ToString(indentation, labelOn);\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            Type elementType = null;\n            if (enforcingType != null)\n            {\n                if (enforcingType is not SetType)\n                {\n                    errors.SemErr(FirstTok, $\"Cannot convert {this.ToString(0, false)} to non-set type.\");\n                }\n                SetType enforcingSetType = (enforcingType as SetType);\n                if (enforcingSetType.IsInfinite == Finite)\n                {\n                    errors.SemErr(FirstTok, $\"The finite of set does not match.\");\n                }\n                elementType = enforcingSetType.EntityType;\n            }\n            base.TypeResolve(elementType, ref errors);\n            if (Finite)\n            {\n                Expr collection = (Range as BinaryExpr).secondOp;\n                if ((collection.Ty is SetType && (collection.Ty as SetType).IsInfinite) ||\n                    (collection.Ty is MapType && (collection.Ty as MapType).IsInfinite))\n                {\n                    errors.SemErr(FirstTok, \"Cannot build a finite set from comprehension of infinite collection.\");\n                }\n            }\n            foreach (Ident ident in Idents)\n            {\n                Sc.Pop();\n            }\n            this.Ty = new SetType(elementType, !Finite);\n        }\n        public override string ToFStarFunction(int indentation, string name)\n        {\n            // TODO: add attributes\n            string fnStr = $\"let rec {name}_map \";\n            BinaryExpr range = Range as BinaryExpr;\n            if (range.secondOp.Ty is not SeqType)\n            {\n                throw new NotImplementedException();\n            }\n            Type typeA = range.firstOp.Ty;\n            Type typeB = Term.Ty;\n            Type collectionType = range.secondOp.Ty;\n            List<string> fstarStrs = new List<string>();\n            List<string> nameStrs = new List<string>();\n            List<string> typeStrs = new List<string>();\n            string extraParameters = \"\";\n            foreach (Ident ident in getFnParameters(Term))\n            {\n                extraParameters += $\"({ident.Name}: {ident.Ty.ToFStarLang(0, false)}) \";\n                fstarStrs.Add(ident.ToFStarLang(0));\n                nameStrs.Add(ident.Name);\n                typeStrs.Add(ident.Ty.ToFStarLang(0, false));\n            }\n            fstarStrs.Add(range.secondOp.ToFStarLang(0));\n            typeStrs.Add(collectionType.ToFStarLang(0, false));\n            fnStr += extraParameters;\n            fnStr += $\"(s: {collectionType.ToFStarLang(0, false)})\";\n            fnStr += $\": GTot ({this.Ty.ToFStarLang(0, false)}) (decreases rank s) =\\n\";\n            string oneIndentStr = new string(' ', indentation + 2);\n            string twoIndentStr = new string(' ', indentation + 4);\n            fnStr += oneIndentStr + \"if length s = 0 then\\n\";\n            fnStr += twoIndentStr + (Finite ? \"FStar.FiniteSet.Base.emptyset\" : \"FStar.Set.empty\") + '\\n';\n            fnStr += oneIndentStr + \"else\\n\" + twoIndentStr;\n            if (Finite)\n            {\n                fnStr += $\"FStar.FiniteSet.Base.insert ({name}_fn {string.Join(' ', nameStrs)} (index s 0)) ({name}_map {string.Join(' ', nameStrs)} (drop s 1))\";\n            }\n            else\n            {\n                fnStr += $\"FStar.Set.union (FStar.Set.singleton ({name}_fn {string.Join(' ', nameStrs)} (index s 0))) ({name}_map {string.Join(' ', nameStrs)} (drop s 1))\";\n            }\n\n            fnStr += '\\n';\n            fnStr += $\"let {name} {extraParameters}(s: {collectionType.ToFStarLang(0, false)}) = ComputationProduces ({name}_map {string.Join(' ', nameStrs)} s)\";\n            fnInvocation = $\"ExpressionApplyFunction ({this.Ty.ToFStarLang(0, true)}) [{string.Join(';', fstarStrs)}] ({this.Ty.ToFStarLang(0, false)}) [{string.Join(';', typeStrs)}] {name}\";\n\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str += indentationStr + fnStr;\n            return str;\n        }\n    }\n\n    public class MapComprehension : ComprehensionExpr\n    {\n        public readonly bool Finite;\n        public readonly Expr ValueExpr;\n\n        public MapComprehension(Token tok, bool finite, List<Ident> idents, Expr range, Expr keyExpr, Expr valueExpr, Attribute attrs)\n          : base(tok, idents, range, keyExpr, attrs)\n        {\n            Contract.Requires(tok != null);\n            // Contract.Requires(cce.NonNullElements(idents));\n            Contract.Requires(1 <= idents.Count);\n            Contract.Requires(keyExpr != null);\n            Contract.Requires(valueExpr != null || idents.Count == 1);\n\n            Finite = finite;\n            ValueExpr = valueExpr;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string valueStr = (ValueExpr == null) ? \"\" : \" := \" + ValueExpr.ToString(0, labelOn);\n            return base.ToString(indentation, labelOn) + valueStr;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            Type prevElementKeyType = null;\n            Type prevElementValueType = null;\n            if (enforcingType != null)\n            {\n                if (enforcingType is not MapType)\n                {\n                    errors.SemErr(FirstTok, $\"Cannot convert {this.ToString(0, false)} to non-map type.\");\n                }\n                MapType enforcingMapType = (enforcingType as MapType);\n                if (enforcingMapType.IsInfinite == Finite)\n                {\n                    errors.SemErr(FirstTok, $\"The finite of map does not match.\");\n                }\n                prevElementKeyType = enforcingMapType.KeyType;\n                prevElementValueType = enforcingMapType.EntityType;\n            }\n            if (Finite)\n            {\n                Expr collection = (Range as BinaryExpr).secondOp;\n                if ((collection.Ty is SetType && (collection.Ty as SetType).IsInfinite) ||\n                    (collection.Ty is MapType && (collection.Ty as MapType).IsInfinite))\n                {\n                    errors.SemErr(FirstTok, \"Cannot build a finite map from comprehension of infinite collection.\");\n                }\n            }\n            base.TypeResolve(prevElementKeyType, ref errors);\n            ValueExpr.Sc = Sc;\n            ValueExpr.TypeResolve(prevElementValueType, ref errors);\n            foreach (Ident ident in Idents) // pop the boundvardecl after all exprs are resolved\n            {\n                Sc.Pop();\n            }\n            this.Ty = new MapType(prevElementKeyType, prevElementValueType, !Finite);\n        }\n        public override string ToFStarFunction(int indentation, string name)\n        {\n            // TODO: add attributes\n            // Value mapping function\n            string valueFn = name + \"_value\";\n            string fnStr = new string(' ', indentation) + $\"let {valueFn} \";\n            string extraParameters = \"\";\n            List<string> fstarStrs = new List<string>();\n            List<string> nameStrs = new List<string>();\n            List<string> keyParaStrs = new List<string>();\n            List<string> valueParaStrs = new List<string>();\n            List<string> typeStrs = new List<string>();\n            foreach (Ident ident in getFnParameters(ValueExpr))\n            {\n                extraParameters += $\"({ident.Name}: {ident.Ty.ToFStarLang(0, false)}) \"; \n                fstarStrs.Add(ident.ToFStarLang(0));\n                valueParaStrs.Add(ident.Name);\n                nameStrs.Add(ident.Name);\n                typeStrs.Add(ident.Ty.ToFStarLang(0, false));\n            }\n            fnStr += extraParameters;\n            foreach (Ident bv in this.Idents)\n            {\n                fnStr += $\"({bv.Name}: {bv.Ty.ToFStarLang(0, false)}) \";\n            }\n            fnStr += $\"= {ValueExpr.ToFStarExpr(\"\")}\\n\";\n            // Recursive function\n            fnStr += $\"let rec {name}_map \";\n            BinaryExpr range = Range as BinaryExpr;\n            if (range.secondOp.Ty is not SeqType)\n            {\n                throw new NotImplementedException();\n            }\n            Type typeA = range.firstOp.Ty;\n            Type typeB = Term.Ty;\n            Type collectionType = range.secondOp.Ty;\n            foreach (Ident ident in getFnParameters(Term))\n            {\n                extraParameters += $\"({ident.Name}: {ident.Ty.ToFStarLang(0, false)}) \";\n                fstarStrs.Add(ident.ToFStarLang(0));\n                keyParaStrs.Add(ident.Name);\n                nameStrs.Add(ident.Name);\n                typeStrs.Add(ident.Ty.ToFStarLang(0, false));\n            }\n            fstarStrs.Add(range.secondOp.ToFStarLang(0));\n            typeStrs.Add(collectionType.ToFStarLang(0, false));\n            fnStr += extraParameters;\n            fnStr += $\"(s: {collectionType.ToFStarLang(0, false)})\";\n            fnStr += $\": GTot ({this.Ty.ToFStarLang(0, false)}) (decreases rank s) =\\n\";\n            string oneIndentStr = new string(' ', indentation + 2);\n            string twoIndentStr = new string(' ', indentation + 4);\n            fnStr += oneIndentStr + \"if length s = 0 then\\n\";\n            fnStr += twoIndentStr + (Finite ? \"FStar.FiniteMap.Base.emptymap\" : \"(FStar.Map.const 0)\") + '\\n';\n            fnStr += oneIndentStr + \"else\\n\" + twoIndentStr;\n            // FStar.Map.upd m k v\n            string m = $\"({name}_map {string.Join(' ', nameStrs)} (drop s 1))\";\n            string k = $\"({name}_fn {string.Join(' ', keyParaStrs)} (index s 0))\";\n            string v = $\"({name}_value {string.Join(' ', valueParaStrs)} (index s 0))\";\n            if (Finite)\n            {\n                fnStr += $\"FStar.FiniteMap.Base.insert {k} {v} {m}\";\n            }\n            else\n            {\n                fnStr += $\"FStar.Map.upd {m} {k} {v}\";\n            }\n\n            fnStr += '\\n';\n            fnStr += $\"let {name} {extraParameters}(s: {collectionType.ToFStarLang(0, false)}) = ComputationProduces ({name}_map {string.Join(' ', nameStrs)} s)\";\n            fnInvocation = $\"ExpressionApplyFunction ({this.Ty.ToFStarLang(0, true)}) [{string.Join(';', fstarStrs)}] ({this.Ty.ToFStarLang(0, false)}) [{string.Join(';', typeStrs)}] {name}\";\n\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str += indentationStr + fnStr;\n            return str;\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var node in base.AllChildren())\n                yield return node;\n            foreach (var node in ValueExpr.AllChildren())\n                yield return node;\n            yield return ValueExpr;\n        }\n    }\n\n    public abstract class SuffixExpr : Expr\n    {\n        // BaseExpr could be seq or map, index could be natural number or key\n        public Expr BaseExpr;\n\n        public SuffixExpr(Token tok, Expr baseExpr)\n        : base(tok)\n        {\n            Contract.Requires(baseExpr != null);\n            BaseExpr = baseExpr;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + BaseExpr.ToString(0, labelOn);\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            BaseExpr.Sc = Sc;\n            BaseExpr.TypeResolve(null, ref errors);\n            if (!(BaseExpr.Ty is SeqType || BaseExpr.Ty is MapType || BaseExpr.Ty is TypeSuffix))\n            {\n                errors.SemErr(BaseExpr.FirstTok, $\"{BaseExpr.FirstTok.val} is not a sequence, array or map.\");\n            }\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + BaseExpr.ToCProgram(0);\n            return str;\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var node in BaseExpr.AllChildren())\n                yield return node;\n            yield return BaseExpr;\n        }\n    }\n\n    public class SeqSelectExpr : SuffixExpr\n    {\n        public Expr IndexExpr;\n\n        public SeqSelectExpr(Token tok, Expr baseExpr, Expr indexExpr)\n        : base(tok, baseExpr)\n        {\n            Contract.Requires(indexExpr != null);\n            IndexExpr = indexExpr;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = base.ToString(indentation, labelOn) + \"[\" + IndexExpr.ToString(0, labelOn) + \"]\";\n            return str;\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            string str = base.ToCProgram(indentation) + \"[\" + IndexExpr.ToCProgram(0) + \"]\";\n            return str;\n        }\n\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            base.TypeResolve(enforcingType, ref errors);\n            IndexExpr.Sc = Sc;\n            if (BaseExpr.Ty is SeqType)\n            {\n                IndexExpr.TypeResolve(new PredefinedType(PredefinedTypeEnum.Nat), ref errors);\n                this.Ty = ((CollectionType)BaseExpr.Ty).EntityType;\n            }\n            else if (BaseExpr.Ty is MapType)\n            {\n                IndexExpr.TypeResolve(((MapType)BaseExpr.Ty).KeyType, ref errors);\n                this.Ty = ((CollectionType)BaseExpr.Ty).EntityType;\n            }\n            else if (BaseExpr.Ty is TypeSuffix)\n            {\n                IndexExpr.TypeResolve(new PredefinedType(PredefinedTypeEnum.Nat), ref errors);\n                this.Ty = ((TypeSuffix)BaseExpr.Ty).EntityType;\n            }\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str += indentationStr;\n            if (BaseExpr.Ty is SeqType)\n            {\n                str += $\"ExpressionApplyFunction ({this.Ty.ToFStarLang(0, true)}) [{BaseExpr.ToFStarLang(0)}; {IndexExpr.ToFStarLang(0)}] ({this.Ty.ToFStarLang(0, false)}) [{BaseExpr.Ty.ToFStarLang(0, false)}; nat] seq_index\";\n            }\n            else if (BaseExpr.Ty is MapType)\n            {\n                MapType baseTy = BaseExpr.Ty as MapType;\n                string selectFn = (baseTy.IsInfinite) ? \"map_select\" : \"finite_map_select\";\n                str += $\"ExpressionApplyFunction ({this.Ty.ToFStarLang(0, true)}) [{BaseExpr.ToFStarLang(0)}; {IndexExpr.ToFStarLang(0)}] ({this.Ty.ToFStarLang(0, false)}) [{BaseExpr.Ty.ToFStarLang(0, false)}; {IndexExpr.Ty.ToFStarLang(0, false)}] {selectFn}\";\n            }\n            else if (BaseExpr.Ty is TypeSuffix)\n            {\n                TypeSuffix baseTy = BaseExpr.Ty as TypeSuffix;\n                str += $\"ExpressionDereference ({baseTy.EntityType.ToFStarLang(0, true)}) (ExpressionPointerOffset ({BaseExpr.ToFStarLang(0)}) ({IndexExpr.ToFStarLang(0)}))\";\n            }\n            return str;\n        }\n        public override string ToFStarExpr(string armadaStateName)\n        {\n            throw new NotImplementedException();\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var node in base.AllChildren())\n                yield return node;\n            foreach (var node in IndexExpr.AllChildren())\n                yield return node;\n            yield return IndexExpr;\n        }\n    }\n\n    public class SeqRangeExpr : SuffixExpr\n    {\n        public Expr StartIndex;\n        public Expr EndIndex;\n\n        public SeqRangeExpr(Token tok, Expr baseExpr, Expr startIndex, Expr endIndex)\n        : base(tok, baseExpr)\n        {\n            // both StartIndex and EndIndex can be null\n            StartIndex = startIndex;\n            EndIndex = endIndex;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string startStr = (StartIndex == null) ? \"\" : StartIndex.ToString(0, labelOn);\n            string endStr = (EndIndex == null) ? \"\" : EndIndex.ToString(0, labelOn);\n            string str = base.ToString(indentation, labelOn) + \"[\" + startStr + \"..\" + endStr + \"]\";\n            return str;\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            throw new NotSupportedException();\n        }\n\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            Type entityType = null;\n            BaseExpr.Sc = Sc;\n            BaseExpr.TypeResolve(null, ref errors);\n            if (BaseExpr.Ty is SeqType)\n            {\n                entityType = ((SeqType)BaseExpr.Ty).EntityType;\n            }\n            else if (BaseExpr.Ty is TypeSuffix)\n            {\n                entityType = ((TypeSuffix)BaseExpr.Ty).EntityType;\n            }\n            else\n            {\n                errors.SemErr(BaseExpr.FirstTok, $\"{BaseExpr.FirstTok.val} is not a sequence or array.\");\n            }\n            if (StartIndex != null)\n            {\n                StartIndex.Sc = Sc;\n                StartIndex.TypeResolve(new PredefinedType(PredefinedTypeEnum.Nat), ref errors);\n            }\n            if (EndIndex != null)\n            {\n                EndIndex.Sc = Sc;\n                EndIndex.TypeResolve(new PredefinedType(PredefinedTypeEnum.Nat), ref errors);\n            }\n            this.Ty = new SeqType(entityType);\n            CheckCompatiblity(enforcingType, ref errors);\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str += indentationStr;\n            if (BaseExpr.Ty is SeqType)\n            {\n                str += $\"ExpressionApplyFunction ({this.Ty.ToFStarLang(0, true)}) [{BaseExpr.ToFStarLang(0)}; {StartIndex.ToFStarLang(0)}; {EndIndex.ToFStarLang(0)}] ({this.Ty.ToFStarLang(0, false)}) [{BaseExpr.Ty.ToFStarLang(0, false)}; nat; nat] seq_range\";\n            }\n            else\n            {\n                throw new NotImplementedException();\n            }\n            return str;\n        }\n        public override string ToFStarExpr(string armadaStateName)\n        {\n            throw new NotImplementedException();\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var node in base.AllChildren())\n                yield return node;\n            if (StartIndex != null)\n            {\n                foreach (var node in StartIndex.AllChildren())\n                    yield return node;\n                yield return StartIndex;\n            }\n            if (EndIndex != null)\n            {\n                foreach (var node in EndIndex.AllChildren())\n                    yield return node;\n                yield return EndIndex;\n            }\n        }\n    }\n\n    public class SeqAssignExpr : SuffixExpr\n    {\n        public Expr IndexExpr;\n        public Expr ValExpr;\n\n        public SeqAssignExpr(Token tok, Expr baseExpr, Expr indexExpr, Expr valExpr)\n        : base(tok, baseExpr)\n        {\n            Contract.Requires(indexExpr != null);\n            Contract.Requires(valExpr != null);\n            IndexExpr = indexExpr;\n            ValExpr = valExpr;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = base.ToString(indentation, labelOn) + \"[\" +\n                         IndexExpr.ToString(0, labelOn) + \":= \" + ValExpr.ToString(0, labelOn) + \"]\";\n            return str;\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            throw new NotSupportedException();\n        }\n\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            base.TypeResolve(enforcingType, ref errors);\n            IndexExpr.Sc = Sc;\n            if (BaseExpr.Ty is SeqType)\n            {\n                IndexExpr.TypeResolve(new PredefinedType(PredefinedTypeEnum.Nat), ref errors);\n            }\n            else if (BaseExpr.Ty is MapType)\n            {\n                IndexExpr.TypeResolve(((MapType)BaseExpr.Ty).KeyType, ref errors);\n            }\n            else\n            {\n                errors.SemErr(BaseExpr.FirstTok, \"Invalid base type for SeqAssignExpr.\");\n            }\n            CollectionType baseType = (CollectionType)BaseExpr.Ty;\n            ValExpr.Sc = Sc;\n            ValExpr.TypeResolve(baseType.EntityType, ref errors);\n            this.Ty = BaseExpr.Ty;\n            CheckCompatiblity(enforcingType, ref errors);\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str += indentationStr;\n            string updateFn = \"\";\n            if (BaseExpr.Ty is SeqType)\n            {\n                updateFn = \"seq_update\";\n            }\n            else if (BaseExpr.Ty is MapType)\n            {\n                updateFn = ((BaseExpr.Ty as MapType).IsInfinite) ? \"map_update\" : \"finite_map_update\";\n            }\n            str += $\"ExpressionApplyFunction ({this.Ty.ToFStarLang(0, true)}) [{BaseExpr.ToFStarLang(0)}; {IndexExpr.ToFStarLang(0)}; {ValExpr.ToFStarLang(0)}] ({this.Ty.ToFStarLang(0, false)}) [{BaseExpr.Ty.ToFStarLang(0, false)}; {IndexExpr.Ty.ToFStarLang(0, false)}; {ValExpr.Ty.ToFStarLang(0, false)}] {updateFn}\";\n            return str;\n        }\n        public override string ToFStarExpr(string armadaStateName)\n        {\n            throw new NotImplementedException();\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var node in base.AllChildren())\n                yield return node;\n            foreach (var node in IndexExpr.AllChildren())\n                yield return node;\n            yield return IndexExpr;\n            foreach (var node in ValExpr.AllChildren())\n                yield return node;\n            yield return ValExpr;\n        }\n    }\n\n    public class ApplySuffix : SuffixExpr\n    {\n        public List<Expr> Args;\n\n        // Filled in during resolution, then FunctionCall will be changed to another class\n        public DatatypeMemberDecl datatypeMember;\n        public MethodDecl Callee;\n\n\n        public ApplySuffix(Token tok, Expr baseExpr, List<Expr> args)\n        : base(tok, baseExpr)\n        {\n            Contract.Requires(args != null);\n            Args = args;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = base.ToString(indentation, labelOn) + \"(\" + Util.ListExprsToString(Args, labelOn) + \")\";\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            if (this.BaseExpr is not Ident)\n            {\n                errors.SemErr(this.BaseExpr.FirstTok, $\"{this.BaseExpr.ToString(0, false)} is not a memberDecl.\");\n            }\n            Ident memberId = this.BaseExpr as Ident;\n            List<Type> argTypes = new List<Type>();\n            foreach (Expr arg in Args)\n            {\n                arg.Sc = Sc;\n                arg.TypeResolve(null, ref errors);\n                argTypes.Add(arg.Ty);\n            }\n            List<string> typesStr = new List<string>();\n            foreach (Type ty in argTypes)\n            {\n                typesStr.Add(ty.ToString(0));\n            }\n            MemberDecl memberDecl = Sc.GetMemberDecl(memberId, false, argTypes);\n            datatypeMember = Sc.GetDatatypeMemberDecl(memberId.Name);\n            if (memberDecl == null && datatypeMember == null)\n            {\n                errors.SemErr(memberId.FirstTok, $\"{memberId.FirstTok.val} with arg types ({string.Join(\", \", typesStr)}) is not found!\");\n            }\n            if (memberDecl is MethodDecl) // function call\n            {\n                Callee = memberDecl as MethodDecl;\n                if (Callee.Ret != null)\n                {\n                    this.Ty = Callee.Ret.Ty;\n                }\n            }\n            else if (datatypeMember != null) // datatypemember constructor\n            {\n                if (datatypeMember.Arguments.Count != argTypes.Count)\n                {\n                    errors.SemErr(datatypeMember.FirstTok, $\"datatype member {memberId.FirstTok.val} with arg types ({string.Join(\", \", typesStr)}) is not found!\");\n                }\n                for (int i = 0; i < argTypes.Count; i++)\n                {\n                    // check generic type\n                    // TODO: change to compatible type\n                    if (datatypeMember.Arguments[i].Ty is not GenericType &&\n                        datatypeMember.Arguments[i].Ty.ToString(0) != argTypes[i].ToString(0))\n                    {\n                        errors.SemErr(datatypeMember.FirstTok, $\"datatype member {memberId.FirstTok.val} with arg types ({string.Join(\", \", typesStr)}) is not found!\");\n                    }\n                }\n                this.Ty = datatypeMember.parent.Ty;\n            }\n            CheckCompatiblity(enforcingType, ref errors);\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            string str = base.ToCProgram(indentation) + \"(\" + Util.ListExprsToString(Args, false) + \")\";\n            return str;\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str += indentationStr;\n            str += $\"ExpressionConstant (ObjectValueAbstract ({Ty.ToFStarLang(0, false)}) ({datatypeMember.Name.Name} \";\n            str += $\"{string.Join(' ', Args.ConvertAll(arg => arg.ToString(0, false)))}))\";\n            return str;\n        }\n        public override string ToFStarExpr(string armadaStateName)\n        {\n            throw new NotImplementedException();\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var arg in Args)\n            {\n                foreach (var node in arg.AllChildren())\n                    yield return node;\n                yield return arg;\n            }\n        }\n    }\n\n    public class FunctionCall : ApplySuffix\n    {\n        public FunctionCall(Token tok, Expr baseExpr, List<Expr> args, MethodDecl callee)\n        : base(tok, baseExpr, args)\n        {\n            this.Callee = callee;\n        }\n\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            throw new NotSupportedException();\n        }\n\n        public string ToFStarLang(int indentation, bool stackOverflow)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str += indentationStr;\n            str = \"MethodCallStatement \";\n            str += $\"\\\"{Callee.Name.ToString(0, false).ToLower()}\\\" \";\n            str += $\"\\\"{NextPC}\\\" \";\n            str += \"[\";\n            var sep = \"\";\n            foreach (var arg in Callee.Args)\n            {\n                str += sep + $\"\\\"{arg.Name.ToString(0, false)}\\\"\";\n                sep = \"; \";\n            }\n            str += \"] [\";\n            sep = \"\";\n            foreach (var arg in Args)\n            {\n                str += sep + arg.ToFStarLang(0);\n                sep = \"; \";\n            }\n            str += \"]\";\n            str += $\" level_{Callee.EnclosingLevel.Name.Name}_{Callee.Name.ToString(0, false).ToLower()}_stack_initializers\";\n            str += stackOverflow ? \" true\" : \" false\";\n            return str;\n        }\n    }\n\n    public class CasePattern : AstNode\n    {\n        public Ident Id;\n        public List<CasePattern> Arguments;\n\n        public CasePattern(Token tok, Ident id, List<CasePattern> arguments = null)\n        : base(tok)\n        {\n            Contract.Requires(id != null);\n            Id = id;\n            Arguments = arguments;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            string identifierStr = (Id == null) ? \"\" : Id.ToString(0, labelOn);\n            string argumentsStr = \"\";\n            if (Arguments != null)\n            {\n                List<string> elementsStr = new List<string>();\n                foreach (CasePattern casePattern in Arguments)\n                {\n                    elementsStr.Add(casePattern.ToString(0, labelOn));\n                }\n                argumentsStr = \"(\" + string.Join(\", \", elementsStr) + \")\";\n            }\n            str = str + indentationStr + identifierStr + argumentsStr;\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            // TODO: It might be better to change Ident to VarDecl here\n            // no need to set this.Ty because this class is not an expression\n            if (Arguments == null)\n            {\n                BoundVarDecl bv = new BoundVarDecl(FirstTok, Id, enforcingType);\n                bv.Sc = Sc;\n                bv.TypeResolve(null, ref errors); // bv will be pushed into scope in TypeResolve\n                return;\n            }\n            if (enforcingType is not UserDefinedType)\n            {\n                errors.SemErr(Id.FirstTok, \"Datatype mismatch!\");\n                return;\n            }\n            UserDefinedType ut = enforcingType as UserDefinedType;\n            DatatypeDecl datatypeDecl = Sc.GetDatatypeDecl(ut.Name.Name);\n            var datatypeMemberDecls = datatypeDecl.GetDefinedMemberList(ut.ArgumentList);\n            int datatypeIndex = datatypeDecl.GetMemberDeclIndex(Id.Name);\n            if (datatypeIndex == -1)\n            {\n                errors.SemErr(Id.FirstTok, $\"This match case '{Id.Name}' does not match any datatype member!\");\n                return;\n            }\n            List<Parameter> parameters = datatypeMemberDecls[datatypeIndex].Arguments;\n            if (Arguments.Count != parameters.Count)\n            {\n                errors.SemErr(Id.FirstTok, $\"The datatype member {Id.Name} has {parameters.Count} parameters but this match case has {Arguments.Count} parameters!\");\n                return;\n            }\n            for (int i = 0; i < Arguments.Count; i++)\n            {\n                CasePattern cp = Arguments[i];\n                cp.Sc = Sc;\n                cp.TypeResolve(parameters[i].Ty, ref errors);\n            }\n            // no need to set this.Ty because this class is not an expression\n        }\n        public override void SetProgramCounter(string parentPC, int index)\n        {\n            throw new NotImplementedException();\n        }\n        public override void SetNextProgramCounter(string nextPC)\n        {\n            throw new NotImplementedException();\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            throw new NotSupportedException();\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            if (Arguments == null)\n            {\n                return str + indentationStr + Id.Name;\n            }\n            str += indentationStr + \"(\" + Id.Name;\n            foreach (CasePattern cp in Arguments)\n            {\n                str += \" \" + cp.ToFStarLang(0);\n            }\n            str += \")\";\n            return str;\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            yield return Id;\n            if (Arguments != null)\n            {\n                foreach (var cp in Arguments)\n                {\n                    foreach (var node in cp.AllChildren())\n                        yield return node;\n                    yield return cp;\n                }\n            }\n        }\n    }\n\n    public abstract class MatchCase : AstNode\n    {\n        public readonly string Id;\n        public List<CasePattern> CasePatterns;\n        public DatatypeMemberDecl datatypeMember;  // filled in during resolution\n\n        public MatchCase(Token tok, string id, List<CasePattern> cps)\n        : base(tok)\n        {\n            Contract.Requires(id != null);\n            // Contract.Requires(cce.NonNullElements(cps));\n            this.Id = id;\n            this.CasePatterns = cps;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            string casePatternsStr = \"\";\n            if (CasePatterns.Count != 0)\n            {\n                List<string> elementsStr = new List<string>();\n                foreach (CasePattern casePattern in CasePatterns)\n                {\n                    elementsStr.Add(casePattern.ToString(0, labelOn));\n                }\n                casePatternsStr = \" (\" + string.Join(\", \", elementsStr) + \")\";\n            }\n            str = str + indentationStr + \"case \" + Id + casePatternsStr + \" => \";\n            return str;\n        }\n\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            // check mismatch string\n            if (CasePatterns.Count != datatypeMember.Arguments.Count)\n            {\n                errors.SemErr(this.FirstTok, $\"The datatype member {Id} has {datatypeMember.Arguments.Count} parameters but this match case has {CasePatterns.Count} parameters!\");\n                return;\n            }\n            for (int i = 0; i < CasePatterns.Count; i++)\n            {\n                var casePattern = CasePatterns[i];\n                if (casePattern.Id.Name == \"_\")\n                {\n                    continue; // no need to add bounded variable _\n                }\n                var parameter = datatypeMember.Arguments[i];\n                casePattern.Sc = Sc;\n                casePattern.TypeResolve(parameter.Ty, ref errors);\n            }\n            // no need to set this.Ty because this class is not an expression\n        }\n        public override void SetProgramCounter(string parentPC, int index)\n        {\n            throw new NotImplementedException();\n        }\n        public override void SetNextProgramCounter(string nextPC)\n        {\n            throw new NotImplementedException();\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str += indentationStr + Id;\n            foreach (CasePattern cp in CasePatterns)\n            {\n                str += \" \" + cp.ToFStarLang(0);\n            }\n            return str;\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var cp in CasePatterns)\n            {\n                foreach (var node in cp.AllChildren())\n                    yield return node;\n                yield return cp;\n            }\n        }\n    }\n\n    public class MatchCaseExpr : MatchCase\n    {\n        public Expr Body;\n\n        public MatchCaseExpr(Token tok, string id, List<CasePattern> cps, Expr body)\n          : base(tok, id, cps)\n        {\n            Contract.Requires(id != null);\n            // Contract.Requires(cce.NonNullElements(cps));\n            Contract.Requires(body != null);\n            this.Body = body;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            return base.ToString(indentation, labelOn) + Body.ToString(0, labelOn);\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            int originCount = Sc.DefinedEntities.Count;\n            base.TypeResolve(null, ref errors);\n            Body.Sc = Sc;\n            Body.TypeResolve(enforcingType, ref errors);\n            int scopePopCount = Sc.DefinedEntities.Count - originCount;\n            for (int i = 0; i < scopePopCount; i++)\n            {\n                Sc.Pop();\n            }\n            // no need to set this.Ty because this class is not an expression\n        }\n        public override string ToCProgram(int indentation)\n        {\n            throw new NotImplementedException();\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str += indentationStr + \" | \" + base.ToFStarLang(0) + \" -> \" + Body.ToFStarExpr(\"\");\n            return str;\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var node in base.AllChildren())\n                yield return node;\n            foreach (var node in Body.AllChildren())\n                yield return node;\n            yield return Body;\n        }\n    }\n\n    public class MatchExpr : Expr\n    {  // a MatchExpr is an \"extended expression\" and is only allowed in certain places\n        private Expr source;\n        private List<MatchCaseExpr> cases;\n        private DatatypeDecl datatypeDecl; // filled in during resolution\n        private string FunctionName; // filled in during F* generation\n        public readonly bool UsesOptionalBraces;\n\n        public MatchExpr(Token tok, Expr source, List<MatchCaseExpr> cases, bool usesOptionalBraces)\n        : base(tok)\n        {\n            Contract.Requires(source != null);\n            // Contract.Requires(cce.NonNullElements(cases));\n            this.source = source;\n            this.cases = cases;\n            this.UsesOptionalBraces = usesOptionalBraces;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            List<string> elementsStr = new List<string>();\n            foreach (MatchCaseExpr expr in cases)\n            {\n                elementsStr.Add(expr.ToString(0, labelOn));\n            }\n            string CasesStr = string.Join(\" \", elementsStr);\n            if (UsesOptionalBraces)\n            {\n                CasesStr = \"{\" + CasesStr + \"}\";\n            }\n            str = str + indentationStr + \"match \" + source.ToString(0, labelOn) + \" \" + CasesStr;\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            source.Sc = Sc;\n            source.TypeResolve(null, ref errors);\n            if (source.Ty is not UserDefinedType)\n            {\n                errors.SemErr(source.FirstTok, \"The source of match expression should be user defined datatype!\");\n            }\n            UserDefinedType t = source.Ty as UserDefinedType;\n            datatypeDecl = Sc.GetDatatypeDecl(t.Name.Name);\n            var datatypeMemberDeclList = datatypeDecl.GetDefinedMemberList(t.ArgumentList);\n            Type preType = enforcingType;\n            foreach (MatchCaseExpr matchCase in cases)\n            {\n                matchCase.Sc = Sc;\n                int datatypeIndex = datatypeDecl.GetMemberDeclIndex(matchCase.Id);\n                if (datatypeIndex < 0)\n                {\n                    errors.SemErr(matchCase.FirstTok, $\"This match case '{matchCase.Id}' does not match any datatype member!\");\n                    return;\n                }\n                matchCase.datatypeMember = datatypeMemberDeclList[datatypeIndex];\n                matchCase.TypeResolve(preType, ref errors);\n                preType = matchCase.Body.Ty;\n            }\n            this.Ty = preType;\n        }\n\n        public string ToFStarFunction(int indentation, string functionName)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            this.FunctionName = functionName;\n            str += indentationStr + $\"let {functionName}({source.ToString(0, false)}: {source.Ty.ToFStarLang(0, false)}): conditional_computation_t ({this.Ty.ToFStarLang(0, false)}) =\\n\";\n            str += indentationStr + \"ComputationProduces (\\n\";\n            str += indentationStr + \"match \" + source.ToString(0, false) + \" with \\n\";\n            foreach (MatchCaseExpr oneCase in cases)\n            {\n                str += oneCase.ToFStarLang(indentation + 4) + '\\n';\n            }\n            str += indentationStr + \")\\n\";\n            return str;\n        }\n\n        public override string ToFStarLang(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str += indentationStr + $\"ExpressionApplyFunction ({this.Ty.ToFStarLang(0, true)}) [{source.ToFStarLang(0)}] {this.Ty.ToString(0)} [{source.Ty.ToFStarLang(0, false)}] {FunctionName}\";\n            return str;\n        }\n        public override string ToFStarExpr(string armadaStateName)\n        {\n            throw new NotImplementedException();\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var node in source.AllChildren())\n                yield return node;\n            yield return source;\n            foreach (var matchCase in cases)\n            {\n                foreach (var node in matchCase.AllChildren())\n                    yield return node;\n                yield return matchCase;\n            }\n        }\n    }\n\n    public class AllocRhs : Expr\n    {\n        public Type AllocType;\n        public Expr Count;\n        public bool IsCalloc;\n        public bool IsSequential = false; // filled in during resolution\n        public Expr Lhs; // filled in during resolution\n\n        public AllocRhs(Token tok, Type allocType, Expr count, bool isCalloc)\n        : base(tok)\n        {\n            Contract.Requires(allocType != null);\n            Contract.Requires(count != null);\n            AllocType = allocType;\n            Count = count;\n            IsCalloc = isCalloc;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + (IsCalloc ? \"calloc\" : \"malloc\") + \"(\" + AllocType.ToString(0) + \", \" + Count.ToString(0, labelOn) + \")\";\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            Count.Sc = Sc;\n            Count.TypeResolve(new PredefinedType(PredefinedTypeEnum.Nat), ref errors);\n            bool isDefinedType = Sc.IsDefinedType(AllocType);\n            if (!isDefinedType)\n            {\n                errors.SemErr(FirstTok, AllocType.ToString(0) + \"'s type is not defined.\");\n            }\n            this.Ty = new PointerType(AllocType);\n            CheckCompatiblity(enforcingType, ref errors);\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            if (IsCalloc)\n            {\n                str = str + indentationStr + \"(\" + AllocType.ToCProgram(0) + \"*) calloc(sizeof(\" + AllocType.ToCProgram(0) + \"), \" + Count.ToCProgram(0) + \")\";\n            }\n            else\n            {\n                str = str + indentationStr + \"(\" + AllocType.ToCProgram(0) + \"*) malloc(sizeof(\" + AllocType.ToCProgram(0) + \") * \" + Count.ToCProgram(0) + \")\";\n            }\n            return str;\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str += indentationStr;\n            str += IsCalloc ? \"CallocSuccessfulStatement \" : \"MallocSuccessfulStatement \";\n            str += IsSequential ? \"true \" : \"false \";\n            str += $\"({Lhs.ToFStarLang(0)}) ({AllocType.ToFStarLang(0, true)}) ({Count.ToFStarLang(0)}) \\n\";\n            str += IsCalloc ? \"CallocReturningNullStatement \" : \"MallocReturningNullStatement \";\n            str += IsSequential ? \"true \" : \"false \";\n            str += $\"({Lhs.ToFStarLang(0)}) ({Count.ToFStarLang(0)}) \\n\";\n            return str;\n        }\n        public override string ToFStarExpr(string armadaStateName)\n        {\n            throw new NotImplementedException();\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var node in Count.AllChildren())\n                yield return node;\n            yield return Count;\n        }\n    }\n\n    public class CreateThreadRhs : Expr\n    {\n        public Ident Id;\n        public List<Expr> Exprs;\n        public string threadIDName;\n        private bool threadIDChanged;\n        public MethodDecl Callee;\n        public bool IsSequential = false; // filled in during resolution\n        public Expr OptionalResult = null; // filled in during resolution\n\n        public CreateThreadRhs(Token tok, Ident id, List<Expr> exprs)\n        : base(tok)\n        {\n            Contract.Requires(id != null);\n            Contract.Requires(exprs != null);\n            Id = id;\n            Exprs = exprs;\n            threadIDName = \"_\" + Id.ToCProgram(0) + \"ID\";\n            threadIDChanged = false;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"create_thread \" + Id.ToString(0, labelOn) +\n                  \"(\" + Util.ListExprsToString(Exprs, labelOn) + \")\";\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            Id.Sc = Sc;\n            List<Type> argTypes = new List<Type>();\n            foreach (Expr expr in Exprs)\n            {\n                expr.Sc = Sc;\n                expr.TypeResolve(null, ref errors);\n                argTypes.Add(expr.Ty);\n            }\n            MemberDecl memberDecl = Sc.GetMemberDecl(Id, false, argTypes);\n\n            if (memberDecl == null || memberDecl is not MethodDecl)\n            {\n                List<string> typesStr = new List<string>();\n                foreach (Type ty in argTypes)\n                {\n                    typesStr.Add(ty.ToString(0));\n                }\n                errors.SemErr(Id.FirstTok, $\"MethodDecl {Id.FirstTok.val} with arg types ({string.Join(\", \", typesStr)}) is not found!\");\n            }\n            else\n            {\n                Callee = memberDecl as MethodDecl;\n                if (Callee.Ret != null)\n                {\n                    errors.SemErr(Id.FirstTok, $\"{Id.FirstTok.val} must be void!\");\n                }\n            }\n            this.Ty = new PredefinedType(PredefinedTypeEnum.ThreadId);\n            CheckCompatiblity(enforcingType, ref errors);\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n\n            string threadWrapperName = \"_\" + Id.ToCProgram(0) + \"Wrapper\";\n            string structType = \"struct _\" + Id.ToCProgram(0) + \"Args\";\n            string argsVar = \"_\" + Id.ToCProgram(0) + \"WrapperArgs\";\n\n            // Create thread ID if necessary\n            if (!threadIDChanged)\n            {\n                str = str + indentationStr + \"pthread_t \" + threadIDName + \";\\n\";\n            }\n\n            if (Exprs.Count > 0)\n            {\n                // Create args struct\n                str = str + indentationStr + structType + \" temp\" + argsVar + \" = {\" + Util.ListExprsToString(Exprs, false) + \"};\\n\";\n                str = str + indentationStr + structType + \"* \" + argsVar + \" = malloc(sizeof(\" + structType + \"));\\n\";\n                str = str + indentationStr + \"*\" + argsVar + \" = temp\" + argsVar + \";\\n\";\n            }\n\n            // Spin up new thread\n            str = str + indentationStr + \"pthread_create((pthread_t *) &\" + threadIDName +\n                    \", NULL, (void *) &\" + threadWrapperName + \", \";\n            if (Exprs.Count > 0)\n            {\n                str = str + \"(void *)\" + argsVar + \")\";\n            }\n            else\n            {\n                str = str + \"NULL)\";\n            }\n            return str;\n        }\n\n        public void SetThreadIDName(string threadIDName)\n        {\n            this.threadIDName = threadIDName;\n            threadIDChanged = true;\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str += indentationStr;\n            str += \"CreateThreadStatement \";\n            str += $\"\\\"{Callee.Name.ToString(0, false)}\\\" \";\n            str += $\"\\\"{Callee.PC}\\\" \";\n            str += IsSequential ? \"true \" : \"false \";\n            str += (OptionalResult == null) ? \"None \" : $\"(Some ({OptionalResult.ToFStarLang(0)})) \";\n            str += \"[\";\n            var sep = \"\";\n            foreach (var arg in Callee.Args)\n            {\n                str += sep + $\"\\\"{arg.Name.ToString(0, false)}\\\"\";\n                sep = \"; \";\n            }\n            str += \"] [\";\n            sep = \"\";\n            foreach (var arg in Exprs)\n            {\n                str += sep + arg.ToFStarLang(0);\n                sep = \"; \";\n            }\n            str += \"]\";\n            str += $\" level_{Callee.EnclosingLevel.Name.Name}_{Callee.Name.ToString(0, false)}_stack_initializers\";\n            return str;\n        }\n        public override string ToFStarExpr(string armadaStateName)\n        {\n            throw new NotImplementedException();\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            yield return Id;\n            foreach (var expr in Exprs)\n            {\n                foreach (var node in expr.AllChildren())\n                    yield return node;\n                yield return expr;\n            }\n        }\n    }\n\n    public class CompareAndSwapRhs : Expr\n    {\n        public Expr Target;\n        public Expr Oldval;\n        public Expr Newval;\n\n        public bool IsSequential;\n        public Expr OptionalResult;\n\n        public CompareAndSwapRhs(Token tok, Expr target, Expr oldval, Expr newval)\n        : base(tok)\n        {\n            Contract.Requires(target != null);\n            Contract.Requires(oldval != null);\n            Contract.Requires(newval != null);\n            Target = target;\n            Oldval = oldval;\n            Newval = newval;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"compare_and_swap(\" + Target.ToString(0, labelOn) + \", \" +\n                  Oldval.ToString(0, labelOn) + \", \" + Newval.ToString(0, labelOn) + \")\";\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            Target.Sc = Sc;\n            Target.TypeResolve(null, ref errors);\n            Oldval.Sc = Sc;\n            Oldval.TypeResolve(null, ref errors);\n            Newval.Sc = Sc;\n            Newval.TypeResolve(null, ref errors);\n            this.Ty = new PredefinedType(PredefinedTypeEnum.Bool);\n            CheckCompatiblity(enforcingType, ref errors);\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"compare_and_swap(&\" + Target.ToCProgram(0) + \", \" +\n                  Oldval.ToCProgram(0) + \", \" + Newval.ToCProgram(0) + \")\";\n            return str;\n        }\n\n        public override string ToFStarLang(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            string compareStatement = $\"CompareAndSwapStatement ({Target.ToFStarLang(0)}) ({Oldval.ToFStarLang(0)}) ({Newval.ToFStarLang(0)}) {IsSequential.ToString().ToLower()} \";\n            compareStatement += (OptionalResult == null) ? \"None\" : $\"(Some ({OptionalResult.ToFStarLang(0)}))\";\n            return str + indentationStr + compareStatement;\n        }\n        public override string ToFStarExpr(string armadaStateName)\n        {\n            throw new NotImplementedException();\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var node in Target.AllChildren())\n                yield return node;\n            yield return Target;\n            foreach (var node in Oldval.AllChildren())\n                yield return node;\n            yield return Oldval;\n            foreach (var node in Newval.AllChildren())\n                yield return node;\n            yield return Newval;\n        }\n    }\n\n    public class AtomicExchangeRhs : Expr\n    {\n        public Expr Target;\n        public Expr Newval;\n        public Expr Lhs = null; // filled in during resolution\n\n        public AtomicExchangeRhs(Token tok, Expr target, Expr newval)\n        : base(tok)\n        {\n            Contract.Requires(target != null);\n            Contract.Requires(newval != null);\n            Target = target;\n            Newval = newval;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"atomic_exchange(\" + Target.ToString(0, labelOn) + \", \" + Newval.ToString(0, labelOn) + \")\";\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            Target.Sc = Sc;\n            Target.TypeResolve(null, ref errors);\n            Newval.Sc = Sc;\n            Newval.TypeResolve(Target.Ty, ref errors);\n            this.Ty = Target.Ty;\n            CheckCompatiblity(enforcingType, ref errors);\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"atomic_exchange(&\" + Target.ToCProgram(0) + \", \" + Newval.ToCProgram(0) + \")\";\n            return str;\n        }\n\n        public override string ToFStarLang(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str += indentationStr + $\"AtomicExchangeStatement ({Lhs.ToFStarLang(0)}) ({Target.ToFStarLang(0)}) ({Newval.ToFStarLang(0)})\";\n            return str;\n        }\n        public override string ToFStarExpr(string armadaStateName)\n        {\n            throw new NotImplementedException();\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var node in Target.AllChildren())\n                yield return node;\n            yield return Target;\n            foreach (var node in Newval.AllChildren())\n                yield return node;\n            yield return Newval;\n        }\n    }\n\n    public class ArrayPointer : Expr, FStarExpressionConstant\n    {\n        public string ArrayName;\n        public ArrayPointer(Token tok, string arrayName)\n        : base(tok)\n        {\n            ArrayName = arrayName;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            return new string(' ', indentation) + ArrayName;\n        }\n\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            this.Ty = enforcingType;\n        }\n\n        public string ToFStarObjectValue()\n        {\n            return $\"ObjectValuePrimitive (PrimitiveBoxPointer (PointerIndex (PointerRoot (RootIdGlobal \\\"_{ArrayName}_array\\\")) 0))\";\n        }\n\n        public override string ToFStarLang(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str += $\"ExpressionConstant ({ToFStarObjectValue()})\";\n            return str;\n        }\n        public override string ToFStarExpr(string armadaStateName)\n        {\n            throw new NotImplementedException();\n        }\n\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            yield break;\n        }\n    }\n\n    public enum Opcode\n    {\n        Nop,\n        LeftShift,\n        RightShift, // Arithmatic right shift\n        Add,\n        Sub,\n        Mul,\n        Div,\n        Neg,\n        Mod,\n        Equal,\n        NotEqual,\n        Lt,\n        Le,\n        Gt,\n        Ge,\n        In,\n        NotIn,\n        Not,\n        Disjoint,\n        And,\n        Or,\n        BitwiseAnd,\n        BitwiseOr,\n        BitwiseXor,\n        BitwiseNot,\n        AddressOf,\n        Dereference,\n        Dot,\n        Equiv,\n        Imply,\n        Exply,\n        Allocated,\n        AllocatedArray,\n        GlobalView,\n        Cardinality,\n    }\n\n    public class OpcodeToString\n    {\n        public static string OpToStr(Opcode opcode)\n        {\n            switch (opcode)\n            {\n                case Opcode.Add:\n                    return \"+\";\n                case Opcode.AddressOf:\n                    return \"&\";\n                case Opcode.Allocated:\n                    return \"allocated\";\n                case Opcode.AllocatedArray:\n                    return \"allocated_array\";\n                case Opcode.And:\n                    return \"&&\";\n                case Opcode.BitwiseAnd:\n                    return \"&\";\n                case Opcode.BitwiseNot:\n                    return \"~\";\n                case Opcode.BitwiseOr:\n                    return \"|\";\n                case Opcode.BitwiseXor:\n                    return \"^\";\n                case Opcode.Cardinality:\n                    return \"| |\";\n                case Opcode.Dereference:\n                    return \" *\";\n                case Opcode.Disjoint:\n                    return \"!! \";\n                case Opcode.Div:\n                    return \"/ \";\n                case Opcode.Dot:\n                    return \".\";\n                case Opcode.Equal:\n                    return \"==\";\n                case Opcode.Equiv:\n                    return \"<==>\";\n                case Opcode.Exply:\n                    return \"<==\";\n                case Opcode.Ge:\n                    return \">=\";\n                case Opcode.GlobalView:\n                    return \"global_view\";\n                case Opcode.Gt:\n                    return \">\";\n                case Opcode.Imply:\n                    return \"==>\";\n                case Opcode.In:\n                    return \"in\";\n                case Opcode.Le:\n                    return \"<=\";\n                case Opcode.LeftShift:\n                    return \"<<\";\n                case Opcode.Lt:\n                    return \"<\";\n                case Opcode.Mod:\n                    return \"%\";\n                case Opcode.Mul:\n                    return \"*\";\n                case Opcode.Neg:\n                    return \"-\";\n                case Opcode.Nop:\n                    return \"nop\";\n                case Opcode.Not:\n                    return \"!\";\n                case Opcode.NotEqual:\n                    return \"!=\";\n                case Opcode.NotIn:\n                    return \"notIn\";\n                case Opcode.Or:\n                    return \"||\";\n                case Opcode.RightShift:\n                    return \">>\";\n                case Opcode.Sub:\n                    return \"-\";\n                default:\n                    return \" undefined opcode \";\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "experimental/Source/Armada/AST/Printer.cs",
    "content": "using System;\nusing System.IO;\nusing System.Collections.Generic;\n\nnamespace Microsoft.Starmada\n{\n    public class Printer\n    {\n        static public string GetFStarHeaderForModule(string moduleName) {\n            var str = \"\";\n            str += \"module \" + moduleName + \"\\n\\n\";\n            str += \"open Armada.Action\\n\";\n            str += \"open Armada.Base\\n\";\n            str += \"open Armada.Expression\\n\";\n            str += \"open Armada.Init\\n\";\n            str += \"open Armada.Memory\\n\";\n            str += \"open Armada.Program\\n\";\n            str += \"open Armada.State\\n\";\n            str += \"open Armada.Statement\\n\";\n            str += \"open Armada.Type\\n\";\n            str += \"open Armada.Pointer\\n\";\n            str += \"open Armada.Computation\\n\";\n            str += \"open FStar.List.Tot\\n\";\n            str += \"open FStar.Char\\n\";\n            str += \"open FStar.Sequence.Base\\n\";\n            str += \"open Spec.Behavior\\n\";\n            str += \"open Spec.Ubool\\n\";\n            return str;\n        }\n\n        static public string GetFStarAtomicHeader() {\n            string str = \"\";\n            str += \"open Strategies.Atomic\\n\";\n            str += \"open Strategies.Semantics\\n\";\n            str += \"open Strategies.Semantics.Armada\\n\";\n            str += \"open Strategies.AtomicToRegular.Armada\\n\";\n            str += \"open Strategies.RegularToAtomic.Armada\\n\";\n            str += \"open Strategies.PCIndices\\n\";\n            str += \"open Util.ImmutableArray\\n\";\n            str += \"open Util.Nth\\n\";\n            return str;\n        }\n\n        static public string GetFStarProofHeader(ProofDecl proof) {\n            string str = \"\";\n            if (proof.Strategy is WeakeningStrategy)\n            {\n                str += \"open Armada.Transition\\n\";\n                str += \"open FStar.List.Tot.Base\\n\";\n                str += \"open FStar.Tactics\\n\";\n                str += \"open Spec.List\\n\";\n                str += \"open Strategies.Atomic\\n\";\n                str += \"open Strategies.Invariant\\n\";\n                str += \"open Strategies.Invariant.Armada.Atomic\\n\";\n                str += \"open Strategies.Semantics\\n\";\n                str += \"open Strategies.Semantics.Armada\\n\";\n                str += \"open Strategies.Weakening.Armada\\n\";\n                str += \"open Util.Behavior\\n\";\n                str += \"open Util.ImmutableArray\\n\";\n                str += \"open Util.List\\n\";\n            }\n            else if (proof.Strategy is VarIntroStrategy)\n            {\n                str += \"open Armada.Thread\\n\";\n                str += \"open Armada.Transition\\n\";\n                str += \"open Strategies.ArmadaStatement.ThreadState\\n\";\n                str += \"open Strategies.Atomic\\n\";\n                str += \"open Strategies.GlobalVars.Types\\n\";\n                str += \"open Strategies.Semantics\\n\";\n                str += \"open Strategies.Semantics.Armada\\n\";\n                str += \"open Strategies.PCIndices\\n\";\n                str += \"open Strategies.VarIntro.Defs\\n\";\n                str += \"open Strategies.VarIntro.Efficient\\n\";\n                str += \"open Util.ImmutableArray\\n\";\n            }\n            else if (proof.Strategy is VarHidingStrategy)\n            {\n                str += \"open Armada.Thread\\n\";\n                str += \"open Armada.Transition\\n\";\n                str += \"open Strategies.ArmadaStatement.ThreadState\\n\";\n                str += \"open Strategies.Atomic\\n\";\n                str += \"open Strategies.GlobalVars\\n\";\n                str += \"open Strategies.GlobalVars.Types\\n\";\n                str += \"open Strategies.Nonyielding\\n\";\n                str += \"open Strategies.Semantics\\n\";\n                str += \"open Strategies.Semantics.Armada\\n\";\n                str += \"open Strategies.PCIndices\\n\";\n                str += \"open Strategies.VarHiding.Defs\\n\";\n                str += \"open Strategies.VarHiding.Efficient\\n\";\n                str += \"open Util.ImmutableArray\\n\";\n            }\n            return str;\n        }\n\n        static public string GetFStarInvariantHeader(ProofDecl proof) {\n            string str = \"\";\n            if (proof == null) {\n                str += \"open Armada.Step\\n\";\n                str += \"open Armada.Transition\\n\";\n                str += \"open Strategies.Atomic\\n\";\n                str += \"open Strategies.GlobalVars\\n\";\n                str += \"open Strategies.GlobalVars.Types\\n\";\n                str += \"open Strategies.Invariant\\n\";\n                str += \"open Strategies.Invariant.Armada\\n\";\n                str += \"open Strategies.Invariant.Armada.Atomic\\n\";\n                str += \"open Strategies.Semantics\\n\";\n                str += \"open Strategies.Semantics.Armada\\n\";\n                str += \"open Spec.List\\n\";\n                str += \"open Spec.Ubool\\n\";\n                str += \"open Util.List\\n\";\n\n                str += \"open Strategies.ArmadaInvariant.PositionsValid\\n\";\n                str += \"open Strategies.ArmadaInvariant.RootsMatch\\n\";\n                str += \"open Strategies.GlobalVars\\n\";\n                str += \"open Strategies.GlobalVars.Init\\n\";\n                str += \"open Strategies.GlobalVarsProof\\n\";\n                str += \"open Strategies.GlobalVars.UnaddressedStatement\\n\";\n            }\n            else if (proof.Strategy is VarIntroStrategy || proof.Strategy is VarHidingStrategy)\n            {\n                str += \"open Armada.Step\\n\";\n                str += \"open Armada.Transition\\n\";\n                str += \"open Strategies.Atomic\\n\";\n                str += \"open Strategies.GlobalVars.Types\\n\";\n                str += \"open Strategies.Invariant\\n\";\n                str += \"open Strategies.Invariant.Armada\\n\";\n                str += \"open Strategies.Invariant.Armada.AtomicSubstep\\n\";\n                str += \"open Strategies.Semantics\\n\";\n                str += \"open Strategies.Semantics.Armada\\n\";\n                str += \"open Spec.List\\n\";\n                str += \"open Spec.Ubool\\n\";\n                str += \"open Util.List\\n\";\n            }\n            else if (proof.Strategy is WeakeningStrategy)\n            {\n                str += \"open Armada.Transition\\n\";\n                str += \"open FStar.List.Tot.Base\\n\";\n                str += \"open FStar.Tactics\\n\";\n                str += \"open Spec.List\\n\";\n                str += \"open Strategies.Atomic\\n\";\n                str += \"open Strategies.Invariant\\n\";\n                str += \"open Strategies.Invariant.Armada.Atomic\\n\";\n                str += \"open Strategies.Semantics\\n\";\n                str += \"open Strategies.Semantics.Armada\\n\";\n                str += \"open Strategies.Weakening.Armada\\n\";\n                str += \"open Util.Behavior\\n\";\n                str += \"open Util.ImmutableArray\\n\";\n                str += \"open Util.List\\n\";\n            }\n            return str;\n        }\n\n        static public string GetFStarProofHeader(ProofDecl proof, string L, string H) {\n            string str = GetFStarProofHeader(proof);\n            str += $\"open AtomicToRegularRefinement{H}\\n\";\n            str += $\"open RegularToAtomicRefinement{L}\\n\";\n            if (proof.Strategy is WeakeningStrategy) {\n                str += $\"open Invariant{L}{H}\\n\";\n            }\n            return str;\n        }\n    }\n}\n"
  },
  {
    "path": "experimental/Source/Armada/AST/ProofStrategy.cs",
    "content": "using System;\nusing System.Collections.Generic;\n\nnamespace Microsoft.Starmada\n{\n    public abstract class ProofStrategy : AstNode\n    {\n        public ProofStrategy(Token tok) : base(tok) { }\n        \n        // Proof strategies don't have program counter.\n        public override void SetProgramCounter(string parentPC, int index) {\n            throw new NotSupportedException();\n        }\n        public override void SetNextProgramCounter(string nextPC)\n        {\n            throw new NotSupportedException();\n        }\n        public override string ToCProgram(int indentation)\n        {\n            throw new NotSupportedException();\n        }\n    }\n\n    public class TSOElimStrategy : ProofStrategy\n    {\n        public Ident Id;\n\n        public TSOElimStrategy(Token tok, Ident id) : base(tok)\n        {\n            this.Id = id;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"tso_elim \" + Id.ToString(0, labelOn) + \"\\n\";\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            // TODO: Implement this function\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            throw new NotImplementedException();\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            yield return Id;\n        }\n    }\n\n    public class WeakeningStrategy : ProofStrategy\n    {\n        public WeakeningStrategy(Token tok) : base(tok) { }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"weakening \\n\";\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            // TODO: Implement this function\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            throw new NotImplementedException();\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            yield break;\n        }\n    }\n\n    public class CombiningStrategy : ProofStrategy\n    {\n        public Ident startLabel;\n        public Ident endLabel;\n        public Ident newLabel;\n        public CombiningStrategy(Token tok, Ident startLabel, Ident endLabel, Ident newLabel) : base(tok)\n        {\n            this.startLabel = startLabel;\n            this.endLabel = endLabel;\n            this.newLabel = newLabel;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"combining \" +\n              startLabel.ToString(0, labelOn) + \" \" +\n              endLabel.ToString(0, labelOn) + \" \" +\n              newLabel.ToString(0, labelOn);\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            // TODO: Implement this function\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            throw new NotImplementedException();\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            yield return startLabel;\n            yield return endLabel;\n            yield return newLabel;\n        }\n    }\n\n    public class AssumeIntroStrategy : ProofStrategy\n    {\n        public AssumeIntroStrategy(Token tok) : base(tok) { }\n        \n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"assume_intro \\n\";\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            // TODO: Implement this function\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            throw new NotImplementedException();\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            throw new NotImplementedException();\n        }\n    }\n\n    public class VarIntroStrategy : ProofStrategy\n    {\n        public List<Ident> Variables;\n\n        public VarIntroStrategy(Token tok) : base(tok)\n        {\n            Variables = new List<Ident>();\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"var_intro \";\n            for (int i = 0; i < Variables.Count; i++)\n            {\n                str = str + Variables[i].ToString(0, labelOn);\n                if (i != Variables.Count - 1)\n                {\n                    str = str + \", \";\n                }\n            }\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            // TODO: Implement this function\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            throw new NotImplementedException();\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var variable in Variables)\n            {\n                yield return variable;\n            }\n        }\n    }\n\n    public class VarHidingStrategy : ProofStrategy\n    {\n        public List<Ident> Variables;\n\n        public VarHidingStrategy(Token tok) : base(tok)\n        {\n            Variables = new List<Ident>();\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"var_hiding \";\n            for (int i = 0; i < Variables.Count; i++)\n            {\n                str = str + Variables[i].ToString(0, labelOn);\n                if (i != Variables.Count - 1)\n                {\n                    str = str + \", \";\n                }\n            }\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            // TODO: Implement this function\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            throw new NotImplementedException();\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var variable in Variables)\n            {\n                yield return variable;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "experimental/Source/Armada/AST/Scope.cs",
    "content": "using System.Diagnostics.Contracts;\nusing System.Collections.Generic;\nusing System;\n\nnamespace Microsoft.Starmada\n{\n    public class Scope\n    {\n        public List<AstNode> DefinedEntities = new List<AstNode>();\n        public Scope Parent;\n        public AstNode EnclosingNode;\n        public Dictionary<string, Statement> PC2Stmt = new Dictionary<string, Statement>();\n\n        public Scope(Scope parent = null)\n        {\n            this.Parent = parent;\n        }\n\n        public void Push(AstNode node)\n        {\n            DefinedEntities.Add(node);\n            // if (Parent != null)\n            // {\n            //     Parent.Push(node);\n            // }\n        }\n        public void Pop()\n        {\n            DefinedEntities.RemoveAt(DefinedEntities.Count - 1);\n        }\n\n        public bool IsDefinedType(Type type)\n        {\n            Contract.Requires(type != null);\n            bool foundMatch = false;\n            if (type is UserDefinedType)\n            {\n                var udt = (UserDefinedType)type;\n                for (int i = DefinedEntities.Count - 1; i >= 0; i--)\n                {\n                    var entity = DefinedEntities[i];\n                    if (entity is DatatypeDecl)\n                    {\n                        var typeDecl = (DatatypeDecl)entity;\n                        if (typeDecl.Ty.Name.Name.ToLower() == udt.Name.Name.ToLower())\n                        {\n                            if (typeDecl.Ty.ArgumentList.Count != udt.ArgumentList.Count)\n                                continue;\n                            foundMatch = true;\n                            foreach (var arg in udt.ArgumentList)\n                            {\n                                if (!IsDefinedType(arg))\n                                {\n                                    foundMatch = false;\n                                }\n                            }\n                            if (!foundMatch)\n                            {\n                                continue;\n                            }\n                            udt.TypeDeclaration = typeDecl;\n                            break;\n                        }\n                    }\n                    if (entity is StructDecl)\n                    {\n                        var structDecl = (StructDecl)entity;\n                        if (structDecl.Name.Name.ToLower() == udt.Name.Name.ToLower())\n                        {\n                            foundMatch = true;\n                            udt.TypeDeclaration = structDecl;\n                            break;\n                        }\n                    }\n                }\n                if (!foundMatch && Parent != null)\n                {\n                    return Parent.IsDefinedType(type);\n                }\n                else\n                {\n                    return foundMatch;\n                }\n            }\n            else if (type is PredefinedType)\n            {\n                return true;\n            }\n            else if (type is PointerType)\n            {\n                return IsDefinedType((type as PointerType).EntityType);\n            }\n            else if (type is SeqType)\n            {\n                return IsDefinedType((type as SeqType).EntityType);\n            }\n            else if (type is SetType)\n            {\n                return IsDefinedType((type as SetType).EntityType);\n            }\n            else if (type is MapType)\n            {\n                return IsDefinedType((type as MapType).KeyType) && IsDefinedType((type as MapType).EntityType);\n            }\n            else if (type is TypeSuffix)\n            {\n                return IsDefinedType((type as TypeSuffix).EntityType);\n            }\n            else\n            {\n                throw new ArgumentException($\"Unknown type {type.ToString(0)}\");\n            }\n        }\n\n        /// <summary>This function returns the variable declaration of the given identifier.</summary>\n        /// <param name=\"ident\">The name of the identifier to be looked up.</param>\n        /// <param name=\"shallowLookup\">If true, it will only look up at the declarations in this scope.\n        /// Otherwise, it will look up all the way to parent(s).</param>\n        public VarDecl GetVariableDecl(Ident ident, bool shallowLookup)\n        {\n            for (int i = DefinedEntities.Count - 1; i >= 0; i--)\n            {\n                var entity = DefinedEntities[i];\n                if (entity is BoundVarDecl)\n                {\n                    var bv = entity as BoundVarDecl;\n                    if (bv.Name.Name == ident.Name)\n                    {\n                        return bv;\n                    }\n                }\n                else if (entity is VarDecl)\n                {\n                    var vd = entity as VarDecl;\n                    if (vd.Name.Name == ident.Name)\n                    {\n                        return vd;\n                    }\n                }\n                else if (entity is Parameter)\n                {\n                    var pr = entity as Parameter;\n                    if (pr.Name.Name == ident.Name)\n                    {\n                        return pr;\n                    }\n                }\n            }\n            if (shallowLookup == false && Parent != null)\n            {\n                return Parent.GetVariableDecl(ident, shallowLookup);\n            }\n            return null;\n        }\n\n        public StructDecl GetStructDecl(string name)\n        {\n            for (int i = DefinedEntities.Count - 1; i >= 0; i--)\n            {\n                var entity = DefinedEntities[i];\n                if (entity is StructDecl)\n                {\n                    var structDecl = entity as StructDecl;\n                    if (structDecl.Name.Name.ToLower() == name.ToLower())\n                    {\n                        return structDecl;\n                    }\n                }\n            }\n            if (Parent != null)\n            {\n                return Parent.GetStructDecl(name);\n            }\n            return null;\n        }\n\n        public DatatypeDecl GetDatatypeDecl(string name)\n        {\n            for (int i = DefinedEntities.Count - 1; i >= 0; i--)\n            {\n                var entity = DefinedEntities[i];\n                if (entity is DatatypeDecl)\n                {\n                    var datatypeDecl = entity as DatatypeDecl;\n                    if (datatypeDecl.Ty.Name.Name.ToLower() == name.ToLower())\n                    {\n                        return datatypeDecl;\n                    }\n                }\n            }\n            if (Parent != null)\n            {\n                return Parent.GetDatatypeDecl(name);\n            }\n            return null;\n        }\n\n        public DatatypeMemberDecl GetDatatypeMemberDecl(string name)\n        {\n            for (int i = DefinedEntities.Count - 1; i >= 0; i--)\n            {\n                var entity = DefinedEntities[i];\n                if (entity is DatatypeMemberDecl)\n                {\n                    var datatypeMemberDecl = entity as DatatypeMemberDecl;\n                    if (datatypeMemberDecl.Name.Name == name)\n                    {\n                        return datatypeMemberDecl;\n                    }\n                }\n            }\n            if (Parent != null)\n            {\n                return Parent.GetDatatypeMemberDecl(name);\n            }\n            return null;\n        }\n\n        public MemberDecl GetMemberDecl(Ident ident, bool shallowLookup, List<Type> argTypes)\n        {\n            for (int i = DefinedEntities.Count - 1; i >= 0; i--)\n            {\n                var entity = DefinedEntities[i];\n                if (entity is MemberDecl)\n                {\n                    var md = entity as MemberDecl;\n                    if (md.Name.Name == ident.Name)\n                    {\n                        if (md is MethodDecl)\n                        {\n                            var methodDecl = md as MethodDecl;\n                            if (methodDecl.Args.Count == argTypes.Count)\n                            {\n                                bool match = true;\n                                for (int j = 0; j < methodDecl.Args.Count; j++)\n                                {\n                                    // TODO: change to compatible type\n                                    if (methodDecl.Args[j].Ty.ToString(0) != argTypes[j].ToString(0))\n                                    {\n                                        match = false;\n                                        break;\n                                    }\n                                }\n                                if (match)\n                                {\n                                    return methodDecl;\n                                }\n                            }\n                        }\n                        else if (md is InvariantDecl || md is YieldPredicateDecl)\n                        {\n                            if (argTypes.Count == 1 && argTypes[0].ToString(0) == \"bool\")\n                            {\n                                return md;\n                            }\n                        }\n                    }\n                }\n            }\n            if (shallowLookup == false && Parent != null)\n            {\n                return Parent.GetMemberDecl(ident, shallowLookup, argTypes);\n            }\n            return null;\n        }\n\n        public Statement GetLabelStatement(Ident ident)\n        {\n            for (int i = DefinedEntities.Count - 1; i >= 0; i--)\n            {\n                var entity = DefinedEntities[i];\n                if (entity is Statement)\n                {\n                    var stmt = entity as Statement;\n                    if (stmt.Label.Name == ident.Name)\n                    {\n                        return stmt;\n                    }\n                }\n            }\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "experimental/Source/Armada/AST/Statement.cs",
    "content": "using System;\nusing System.Linq;\nusing System.Collections.Generic;\nusing System.Diagnostics.Contracts;\n\nnamespace Microsoft.Starmada\n{\n    public class FStarStmt\n    {\n        public string StartPC;\n        public string EndPC;\n        public bool StartsAtomicBlock;\n        public bool EndsAtomicBlock;\n        public string Statement;\n        public string Comment;\n\n        public FStarStmt(string startPC, string endPC, bool startsAtomicBlock, bool endsAtomicBlock, string statement, string comment = null)\n        {\n            Contract.Requires(startPC != null);\n            Contract.Requires(statement != null);\n            this.StartPC = startPC;\n            this.EndPC = endPC;\n            this.StartsAtomicBlock = startsAtomicBlock;\n            this.EndsAtomicBlock = endsAtomicBlock;\n            this.Statement = statement;\n            this.Comment = comment;\n        }\n\n        public override bool Equals(object o)\n        {\n            if (o == null)\n                return false;\n            var second = o as FStarStmt;\n            return StartPC == second.StartPC && EndPC == second.EndPC && StartsAtomicBlock == second.StartsAtomicBlock && EndsAtomicBlock == second.EndsAtomicBlock && Statement == second.Statement;\n        }\n\n        public override int GetHashCode()\n        {\n            return (StartPC + EndPC + $\"{StartsAtomicBlock}{EndsAtomicBlock}\" + Statement).GetHashCode();\n        }\n\n        public static bool operator==(FStarStmt a, FStarStmt b){\n            return a.Equals(b);\n        }   \n        public static bool operator!=(FStarStmt a, FStarStmt b){\n            return !a.Equals(b);\n        }\n\n        public string GetFStarCodeOfStatement(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            if (Comment != null && Comment.Length > 0)\n                str += indentationStr + $\"(* {Comment} *)\\n\";\n            str += indentationStr + \"{\\n\";\n            str += indentationStr + $\"  start_pc = {(StartPC != null ? $\"Some \\\"{StartPC}\\\"\" : \"None\")};\\n\";\n            str += indentationStr + $\"  end_pc = {(EndPC != null ? $\"Some \\\"{EndPC}\\\"\" : \"None\")};\\n\";\n            str += indentationStr + $\"  starts_atomic_block = \";\n            str += StartsAtomicBlock ? \"true;\\n\" : \"false;\\n\";\n            str += indentationStr + $\"  ends_atomic_block = \";\n            str += EndsAtomicBlock ? \"true;\\n\" : \"false;\\n\";\n            str += indentationStr + $\"  statement = {Statement};\\n\";\n            str += indentationStr + \"}\";\n            return str;\n        }\n    }\n\n    public abstract class Statement : AstNode\n    {\n        public Ident Label;\n        public bool StartsAtomicBlock = true;\n        public bool EndsAtomicBlock = true;\n        public bool InAtomicBlock = false;\n        public List<FStarStmt> FStarStmts;\n\n        public Statement(Token tok) : base(tok)\n        {\n            FStarStmts = new List<FStarStmt>();\n        }\n\n        // Translate? Pretty printing?\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            if (Label != null && labelOn)\n            {\n                str = str + indentationStr + \"label \" + Label.ToString(0, true) + \":\";\n            }\n            return str;\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            return ToString(indentation, false);\n        }\n\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            yield return Label;\n        }\n    }\n\n    public class VarDecl : Statement\n    {\n        public Ident Name;\n        public Type Ty;\n        public Expr Value; // Want option\n        public bool IsGhost;\n        public bool IsNoaddr;\n        public bool IsConst;\n        public bool IsStronglyConsistent;\n\n        public VarDecl(Token tok, Ident name, Type type = null, Expr expr = null, bool isGhost = false, bool isNoaddr = false, bool isConst = false, bool isStronglyConsistent = false) : base(tok)\n        {\n            this.Name = name;\n            this.Ty = type;\n            this.Value = expr;\n            this.IsGhost = isGhost;\n            this.IsNoaddr = isNoaddr;\n            this.IsConst = isConst;\n            this.IsStronglyConsistent = isStronglyConsistent;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            string preStr = \"\";\n            if (IsGhost)\n            {\n                preStr += \"ghost \";\n            }\n            if (IsNoaddr)\n            {\n                preStr += \"noaddr \";\n            }\n            if (IsConst)\n            {\n                preStr += \"const \";\n            }\n            if (IsStronglyConsistent)\n            {\n                preStr += \"sc \";\n            }\n            if (Ty == null)\n            {\n                str = str + indentationStr + base.ToString(0, labelOn) +\n                  preStr + \"var \" + Name.ToString(0, labelOn);\n            }\n            else\n            {\n                str = str + indentationStr + base.ToString(0, labelOn) +\n                  preStr + \"var \" + Name.ToString(0, labelOn) + \":\" + Ty.ToString(0); // TODO: Fix it: T could be null, it will cause System.NullReferenceException:\n            }\n            if (Value != null)\n            {\n                str = str + \" := \" + Value.ToString(0, labelOn);\n            }\n            str = str + \";\";\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            // Variable declaration type cannot be enforced\n            Contract.Requires(enforcingType == null);\n            // Variable declaration's type should be specified\n            if (Ty == null)\n            {\n                // During err output labels are always printed\n                // FIXME: fixed Name.Tok to make it compile\n                errors.SemErr(Name.FirstTok, Name.ToString(0, true) + \"'s type is not defined.\");\n            }\n            VarDecl varDeclaration = Sc.GetVariableDecl(Name, true);\n            if (varDeclaration != null)\n            {\n                errors.SemErr(FirstTok, $\"{Name.ToString(0, false)} is already defined at line {varDeclaration.FirstTok.line}:{varDeclaration.FirstTok.col}!\");\n            }\n            // TODO check if Ty is inside the scope as a user-defined type or not.\n            bool isDefinedType = Sc.IsDefinedType(Ty);\n            if (!isDefinedType)\n            {\n                errors.SemErr(FirstTok, Ty.ToString(0) + \"'s type is not defined.\");\n            }\n            Sc.Push(this);\n            if (Value != null)\n            {\n                Value.Sc = Sc;\n                Value.TypeResolve(Ty, ref errors);\n                if (Ty == null)\n                {\n                    Ty = Value.Ty;\n                }\n            }\n            Name.Sc = Sc;\n            Name.Ty = Ty;\n            // currentScope.Pop();\n            // if (Ty != null)\n            //     Console.WriteLine($\"{Name.ToString(0, true)} : {Ty.ToString(0)}\");\n            // else\n            //     Console.WriteLine($\"{Name.ToString(0, true)} : undefined\");\n            // TODO: Check for incompatibility\n        }\n        public override void SetProgramCounter(string parentPC, int index)\n        {\n            // TODO: Implement this function\n            this.PC = $\"{parentPC}.{index}\";\n            if (Value != null)\n            {\n                Value.SetProgramCounter(this.PC, 0);\n            }\n        }\n\n        public override void SetNextProgramCounter(string nextPC)\n        {\n            this.NextPC = nextPC;\n            if (Value != null)\n            {\n                Value.SetNextProgramCounter(this.NextPC);\n            }\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            string preStr = \"\";\n            if (IsGhost || Ty == null)\n            {\n                return \"\";\n            }\n            if (IsConst)\n            {\n                preStr += \"const \";\n            }\n\n            if (Ty is PointerType)\n            {\n                PointerType pt = (PointerType)Ty;\n                str = str + indentationStr + //base.ToCProgram(0) +\n                    preStr + pt.EntityType.ToCProgram(0) + \"* \" + Name.ToCProgram(0);\n            }\n            else if (Ty is TypeSuffix)\n            {\n                // Array case\n                str = str + indentationStr + preStr + ((TypeSuffix)Ty).EntityType.ToCProgram(0)\n                    + \" \" + Name.ToCProgram(0) + Ty.ToCProgram(0);\n            }\n            else\n            {\n                str = str + indentationStr + preStr\n                    + Ty.ToCProgram(0) + \" \" + Name.ToCProgram(0);\n            }\n\n            if (Value != null)\n            {\n                str = str + \" = \" + Value.ToCProgram(0);\n            }\n            str = str + \";\";\n            return str;\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str += indentationStr + $\"{{ var_id = \\\"{Name.ToString(0, false)}\\\"; \";\n            str += $\"iv = \";\n            if (Value == null)\n            {\n                str += \"InitializerArbitrary\";\n                str += $\" ({Ty.ToFStarLang(0, true)});\";\n            }\n            else\n            {\n                str += \"InitializerSpecific\";\n                var constantValue = Value as FStarExpressionConstant;\n                str += $\" ({constantValue.ToFStarObjectValue()});\";\n            }\n            str += $\" weakly_consistent = \";\n            if (IsGhost | IsStronglyConsistent) {\n                str += \"false\";\n            }\n            else {\n                str += \"true\";\n            }\n            str += \"; }\";\n            return str;\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            yield return Name;\n            if (Value != null)\n            {\n                yield return Value;\n            }\n        }\n    }\n\n    public class BoundVarDecl : VarDecl\n    {\n        public BoundVarDecl(Token tok, Ident name, Type type = null)\n        : base(tok, name, type, null, false, false, false) { }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + Name.ToString(0, labelOn) + ':' + Ty.ToString(0);\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            // Variable declaration type cannot be enforced\n            Contract.Requires(enforcingType == null);\n            // Variable declaration's type should be specified\n            if (Ty == null)\n            {\n                // During err output labels are always printed\n                // FIXME: fixed Name.Tok to make it compile\n                errors.SemErr(Name.FirstTok, Name.ToString(0, true) + \"'s type is not defined.\");\n            }\n            // We allow variable shadowing in BoundVarDecl\n            // TODO check if Ty is inside the scope as a user-defined type or not.\n            bool isDefinedType = Sc.IsDefinedType(Ty);\n            if (!isDefinedType)\n            {\n                errors.SemErr(FirstTok, Ty.ToString(0) + \"'s type is not defined.\");\n            }\n            Sc.Push(this);\n            // currentScope.Pop();\n            // if (Ty != null)\n            //     Console.WriteLine($\"{Name.ToString(0, true)} : {Ty.ToString(0)}\");\n            // else\n            //     Console.WriteLine($\"{Name.ToString(0, true)} : undefined\");\n            // TODO: Check for incompatibility\n        }\n        public override void SetProgramCounter(string parentPC, int index)\n        {\n            if (index == 0)\n                this.PC = $\"{parentPC}\";\n            else\n                this.PC = $\"{parentPC}.{index}\";\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            throw new NotImplementedException();\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            throw new NotSupportedException();\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var node in base.AllChildren())\n                yield return node;\n        }\n    }\n\n    public class BlockStatement : Statement\n    {\n        public List<Statement> Stmts;\n\n        public BlockStatement(Token tok) : base(tok)\n        {\n            Stmts = new List<Statement>();\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"{\\n\";\n            foreach (var stmt in Stmts)\n            {\n                str = str + stmt.ToString(indentation + 2, labelOn) + \"\\n\";\n            }\n            str = str + indentationStr + \"}\";\n            return str;\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"{\\n\";\n            foreach (var stmt in Stmts)\n            {\n                str = str + stmt.ToCProgram(indentation + 2) + \"\\n\";\n            }\n            str = str + indentationStr + \"}\";\n            return str;\n        }\n\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            if (Stmts.Count == 0)\n            {\n                errors.SemErr(this.FirstTok, \"Empty block statement is not allowed!\");\n            }\n\n            // Set StartsAtomicBlock and EndsAtomicBlock\n            Contract.Requires(InAtomicBlock || (!InAtomicBlock && StartsAtomicBlock && EndsAtomicBlock));\n            if (InAtomicBlock)\n            {\n                // Remove nested atomic blocks\n                for (int i = 0; i < Stmts.Count; i++)\n                {\n                    if (Stmts[i] is AtomicStatement)\n                    {\n                        var removedBlock = (Stmts[i] as AtomicStatement).BlockStmt;\n                        Stmts.RemoveAt(i);\n                        Stmts.InsertRange(i, removedBlock.Stmts);\n                        i--;\n                    }\n                }\n                foreach (var stmt in Stmts)\n                {\n                    stmt.StartsAtomicBlock = false;\n                    stmt.EndsAtomicBlock = false;\n                    stmt.InAtomicBlock = true;\n                }\n                if (Stmts.Count != 0)\n                {\n                    Stmts[0].StartsAtomicBlock = StartsAtomicBlock;\n                    Stmts[Stmts.Count - 1].EndsAtomicBlock = Stmts[Stmts.Count - 1].EndsAtomicBlock || EndsAtomicBlock;\n                }\n            }\n\n            for (int i = 0; i < Stmts.Count; i++)\n            {\n                var stmt = Stmts[i];\n                stmt.Sc = Sc;\n                stmt.TypeResolve(null, ref errors);\n            }\n        }\n        public override void SetProgramCounter(string parentPC, int index)\n        {\n            if (index != 0)\n                this.PC = $\"{parentPC}.{index}\";\n            else\n                this.PC = parentPC;\n            for (int i = 0; i < Stmts.Count; i++)\n            {\n                Stmts[i].SetProgramCounter(this.PC, i + 1);\n            }\n            for (int i = 0; i < Stmts.Count - 1; i++)\n            {\n                Stmts[i].SetNextProgramCounter(Stmts[i + 1].PC);\n            }\n            if (Stmts.Count > 0)\n                this.PC = Stmts[0].PC;\n        }\n        public override void SetNextProgramCounter(string nextPC)\n        {\n            if (Stmts.Count > 0)\n            {\n                Stmts[Stmts.Count - 1].SetNextProgramCounter(nextPC);\n                this.NextPC = Stmts[Stmts.Count - 1].NextPC;\n            }\n            else\n            {\n                this.NextPC = nextPC;\n            }\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            foreach (var stmt in Stmts)\n            {\n                stmt.ToFStarLang(indentation);\n                FStarStmts.AddRange(stmt.FStarStmts);\n            }\n            return String.Join(\";\\n\", FStarStmts.ConvertAll(stmt => stmt.GetFStarCodeOfStatement(indentation)));\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var stmt in Stmts)\n            {\n                foreach (var node in stmt.AllChildren())\n                    yield return node;\n                yield return stmt;\n            }\n        }\n    }\n\n    public class FunctionCallStatement : Statement\n    {\n        Expr Destination;\n        Expr Source;\n        bool IsSequential;\n        MethodDecl Caller;\n        public FunctionCallStatement(MethodDecl caller,\n            Expr destination, Expr source, bool isSequential, string PC, string nextPC)\n          : base(caller.FirstTok)\n        {\n            this.Caller = caller;\n            this.Destination = destination;\n            this.IsSequential = isSequential;\n            this.Source = source;\n            this.PC = PC;\n            this.NextPC = nextPC;\n        }\n        public override string ToString(int indentation, bool labelOn)\n        {\n            return \"\";\n        }\n        public override string ToCProgram(int indentation)\n        {\n            throw new NotImplementedException();\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            throw new NotImplementedException();\n        }\n        public override void SetProgramCounter(string parentPC, int index)\n        {\n            throw new NotImplementedException();\n        }\n        public override void SetNextProgramCounter(string nextPC)\n        {\n            throw new NotImplementedException();\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            string statement = $\"ReturnStatement \\\"{Caller.Name.ToString(0, false).ToLower()}\\\" \";\n            if (IsSequential)\n                statement += \"true\";\n            else\n                statement += \"false\";\n            if (Destination != null)\n            {\n                statement += $\" ([{Destination.ToFStarLang(0)}]) ([{Source.ToFStarLang(0)}])\";\n            }\n            else\n            {\n                Contract.Assert(Source == null);\n                statement += $\" [] []\";\n            }\n            FStarStmts.Add(new FStarStmt(PC, NextPC, StartsAtomicBlock, \n                (NextPC.EndsWith(\".R\") ? false : EndsAtomicBlock),\n                statement, $\"return from {PC} to {NextPC}\"));\n            return String.Join(\";\\n\", FStarStmts.ConvertAll(stmt => stmt.GetFStarCodeOfStatement(indentation)));\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var node in Destination.AllChildren())\n                yield return node;\n            yield return Destination;\n            foreach (var node in Source.AllChildren())\n                yield return node;\n            yield return Source;\n            foreach (var node in Caller.AllChildren())\n                yield return node;\n            yield return Caller;\n        }\n    }\n\n    public class ApplySuffixStatement : Statement\n    {\n        ApplySuffix FunctionCall;\n        public ApplySuffixStatement(ApplySuffix functionCall) : base(functionCall.FirstTok)\n        {\n            this.FunctionCall = functionCall;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            return FunctionCall.ToString(indentation, labelOn);\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            return FunctionCall.ToCProgram(indentation);\n        }\n\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            FunctionCall.Sc = Sc;\n            FunctionCall.TypeResolve(enforcingType, ref errors);\n            if (FunctionCall.Callee == null)\n            {\n                errors.SemErr(FunctionCall.FirstTok, \"datatype member constructor can't be called without an lhs.\");\n            }\n            var callee = FunctionCall.Callee;\n            if (callee.Ret != null)\n            {\n                errors.SemErr(FirstTok, \"returned value is ignored!\");\n            }\n            callee.AddCaller(null, false, PC + \".R\");\n        }\n        public override void SetProgramCounter(string parentPC, int index)\n        {\n            this.PC = $\"{parentPC}.{index}\";\n            this.FunctionCall.SetProgramCounter(this.PC, 0);\n        }\n        public override void SetNextProgramCounter(string nextPC)\n        {\n            this.NextPC = nextPC;\n            this.FunctionCall.SetNextProgramCounter(this.NextPC);\n        }\n\n        public override string ToFStarLang(int indentation)\n        {\n            string endPC = $\"{FunctionCall.Callee.Name.ToString(0, false).ToLower()}.1\";\n            bool atomicMethod = FunctionCall.Callee.IsAtomic;\n            var functionCall = new FunctionCall(FunctionCall.FirstTok, FunctionCall.BaseExpr, FunctionCall.Args, FunctionCall.Callee);\n            functionCall.NextPC = PC + \".R\";\n            FStarStmts.Add(new FStarStmt(PC, endPC, StartsAtomicBlock, !atomicMethod, \n              functionCall.ToFStarLang(0, false /* no stack overflow */), this.ToString(0, false)));\n            FStarStmts.Add(new FStarStmt(PC, endPC, StartsAtomicBlock, true /* stack overflow always ends atomic block */,\n              functionCall.ToFStarLang(0, true /* stack overflow */), this.ToString(0, false)));\n            FStarStmts.Add(new FStarStmt(PC + \".R\", this.NextPC, false, EndsAtomicBlock, \"UnconditionalJumpStatement\", \"return from method\"));\n            return String.Join(\";\\n\", FStarStmts.ConvertAll(stmt => stmt.GetFStarCodeOfStatement(indentation)));\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var node in FunctionCall.AllChildren())\n                yield return node;\n            yield return FunctionCall;\n        }\n    }\n\n    public class AssignStatement : Statement\n    {\n        public Expr Lhs;\n        public Expr Rhs;\n        public bool IsSequential;\n\n        public AssignStatement(Token tok, Expr lhs, Expr rhs, bool isSequential) : base(tok)\n        {\n            this.Lhs = lhs;\n            this.Rhs = rhs;\n            this.IsSequential = isSequential;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            if (base.ToString(0, labelOn) != \"\")\n            {\n                str = str + indentationStr + base.ToString(0, labelOn) + \"\\n\";\n            }\n            str = str + indentationStr + Lhs.ToString(0, labelOn);\n            if (Rhs != null)\n            {\n                str = str + (IsSequential ? \" ::= \" : \" := \") + Rhs.ToString(0, labelOn);\n            }\n            str = str + \";\";\n            return str;\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            if (IsSequential)\n            {\n                throw new NotSupportedException();\n            }\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            if (Rhs != null)\n            {\n                // Special case for create thread call\n                if (Rhs is CreateThreadRhs)\n                {\n                    ((CreateThreadRhs)Rhs).SetThreadIDName(Lhs.ToCProgram(0));\n                    str = str + Rhs.ToCProgram(indentation);\n                }\n                else\n                {\n                    str = str + indentationStr + Lhs.ToCProgram(0);\n                    str = str + \" = \" + Rhs.ToCProgram(0);\n                }\n            }\n            else\n            {\n                str = str + indentationStr + Lhs.ToCProgram(0);\n            }\n            str = str + \";\";\n            return str;\n        }\n\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            Lhs.Sc = Sc;\n            Lhs.TypeResolve(enforcingType, ref errors);\n            if (Lhs is SeqSelectExpr && (Lhs as SeqSelectExpr).BaseExpr.Ty is not TypeSuffix)\n            {\n                errors.SemErr(Lhs.FirstTok, \"Update a sequence or map using sequence assign expression (eg. new_s := s[0:=1];).\");\n            }\n            if (Rhs != null)\n            {\n                Rhs.Sc = Sc;\n                Rhs.TypeResolve(Lhs.Ty, ref errors);\n                // Convert Rhs to function call\n                if (Rhs is ApplySuffix && (Rhs as ApplySuffix).Callee != null)\n                {\n                    var funcCallExpr = Rhs as ApplySuffix;\n                    Rhs = new FunctionCall(funcCallExpr.FirstTok, funcCallExpr.BaseExpr, funcCallExpr.Args, funcCallExpr.Callee);\n                }\n                foreach (var node in Rhs.AllChildren())\n                {\n                    if (node is ApplySuffix && (node as ApplySuffix).Callee != null)\n                    {\n                        errors.SemErr(node.FirstTok, \"Function call must be in an assign statement! Example: a := f(x)\");\n                    }\n                }\n                if (Rhs is FunctionCall)\n                {\n                    var funcCallExpr = Rhs as FunctionCall;\n                    var callee = funcCallExpr.Callee;\n                    callee.AddCaller(Lhs, IsSequential, PC + \".R\");\n                }\n                else if (Rhs is CreateThreadRhs)\n                {\n                    var funcCallExpr = Rhs as CreateThreadRhs;\n                    var callee = funcCallExpr.Callee;\n                    funcCallExpr.IsSequential = IsSequential;\n                    funcCallExpr.OptionalResult = Lhs;\n                    callee.AddThreadCaller();\n                }\n                else if (Rhs is AtomicExchangeRhs)\n                {\n                    var atomicExchangeExpr = Rhs as AtomicExchangeRhs;\n                    atomicExchangeExpr.Lhs = Lhs;\n                }\n                else if (Rhs is AllocRhs)\n                {\n                    var allocRhs = Rhs as AllocRhs;\n                    allocRhs.IsSequential = IsSequential;\n                    allocRhs.Lhs = Lhs;\n                }\n                else if (Rhs is CompareAndSwapRhs)\n                {\n                    var compareAndSwapRhs = Rhs as CompareAndSwapRhs;\n                    compareAndSwapRhs.IsSequential = IsSequential;\n                    compareAndSwapRhs.OptionalResult = Lhs;\n                }\n            }\n            // TODO: check compatibility\n        }\n        public override void SetProgramCounter(string parentPC, int index)\n        {\n            // TODO: Implement this function\n            // Console.WriteLine($\"Setting program counter to {parentPC}_{index} for {this.ToString(0, false)}\");\n            this.PC = $\"{parentPC}.{index}\";\n            this.Lhs.SetProgramCounter(this.PC, 0);\n            if (this.Rhs != null)\n            {\n                this.Rhs.SetProgramCounter(this.PC, 0);\n            }\n        }\n        public override void SetNextProgramCounter(string nextPC)\n        {\n            this.NextPC = nextPC;\n            this.Lhs.SetNextProgramCounter(this.NextPC);\n            if (Rhs != null)\n            {\n                this.Rhs.SetNextProgramCounter(this.NextPC);\n            }\n        }\n\n        public override string ToFStarLang(int indentation)\n        {\n            string endPC = NextPC;\n            string statement;\n            if (Rhs is FunctionCall)\n            {\n                var funcCallExpr = Rhs as FunctionCall;\n                funcCallExpr.NextPC = PC + \".R\";\n                endPC = $\"{funcCallExpr.Callee.Name.ToString(0, false).ToLower()}.1\";\n                bool atomicMethod = funcCallExpr.Callee.IsAtomic;\n                FStarStmts.Add(new FStarStmt(PC, endPC, StartsAtomicBlock, !atomicMethod, \n                  funcCallExpr.ToFStarLang(0, false /* no stack overflow */), this.ToString(0, false)));\n                FStarStmts.Add(new FStarStmt(PC, endPC, StartsAtomicBlock, true /* stack overflow always ends atomic block */, \n                  funcCallExpr.ToFStarLang(0, true /* stack overflow */), this.ToString(0, false)));\n                FStarStmts.Add(new FStarStmt(PC + \".R\", this.NextPC, false, EndsAtomicBlock, \"UnconditionalJumpStatement\", \"return from method\"));\n            }\n            else if (Rhs is CreateThreadRhs)\n            {\n                var createThreadExpr = Rhs as CreateThreadRhs;\n                statement = createThreadExpr.ToFStarLang(0);\n                FStarStmts.Add(new FStarStmt(PC, endPC, StartsAtomicBlock, EndsAtomicBlock, statement, this.ToString(0, false)));\n            }\n            else if (Rhs is AtomicExchangeRhs)\n            {\n                var atomicExchangeExpr = Rhs as AtomicExchangeRhs;\n                statement = atomicExchangeExpr.ToFStarLang(0);\n                FStarStmts.Add(new FStarStmt(PC, endPC, StartsAtomicBlock, EndsAtomicBlock, statement, this.ToString(0, false)));\n            }\n            else if (Rhs is AllocRhs)\n            {\n                var allocRhs = Rhs as AllocRhs;\n                var statements = allocRhs.ToFStarLang(0).Split('\\n');                \n                FStarStmts.Add(new FStarStmt(PC, endPC, StartsAtomicBlock, EndsAtomicBlock, statements[0], this.ToString(0, false)));\n                FStarStmts.Add(new FStarStmt(PC, endPC, StartsAtomicBlock, EndsAtomicBlock, statements[1], this.ToString(0, false)));\n            }\n            else if (Rhs is CompareAndSwapRhs)\n            {\n                var compareAndSwapRhs = Rhs as CompareAndSwapRhs;\n                statement = compareAndSwapRhs.ToFStarLang(0);\n                FStarStmts.Add(new FStarStmt(PC, endPC, StartsAtomicBlock, EndsAtomicBlock, statement, this.ToString(0, false)));\n            }\n            else if (Rhs is WildcardExpr)\n            {\n                statement = \"NondeterministicUpdateStatement \";\n                statement += IsSequential ? \"true\" : \"false\";\n                statement += $\" ({Lhs.ToFStarLang(0)})\";\n                FStarStmts.Add(new FStarStmt(PC, endPC, StartsAtomicBlock, EndsAtomicBlock, statement, this.ToString(0, false)));\n            }\n            else\n            {\n                statement = \"UpdateStatement \";\n                if (IsSequential)\n                    statement += \"true\";\n                else\n                    statement += \"false\";\n                statement += $\" ({Lhs.ToFStarLang(0)}) ({Rhs.ToFStarLang(0)})\";\n                FStarStmts.Add(new FStarStmt(PC, endPC, StartsAtomicBlock, EndsAtomicBlock, statement, this.ToString(0, false)));\n            }\n            return String.Join(\";\\n\", FStarStmts.ConvertAll(stmt => stmt.GetFStarCodeOfStatement(indentation)));\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var node in Lhs.AllChildren())\n                yield return node;\n            yield return Lhs;\n            if (Rhs != null)\n            {\n                foreach (var node in Rhs.AllChildren())\n                    yield return node;\n            }\n            yield return Rhs;\n        }\n    }\n\n    public class AtomicStatement : Statement\n    {\n        public BlockStatement BlockStmt;\n\n        public AtomicStatement(Token tok, BlockStatement block) : base(tok)\n        {\n            this.BlockStmt = block;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            if (base.ToString(0, labelOn) != \"\")\n            {\n                str = str + indentationStr + base.ToString(0, labelOn) + \"\\n\";\n            }\n            str = str + indentationStr + FirstTok.val + \"\\n\" + BlockStmt.ToString(indentation, labelOn);\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            // Set StartsAtomicBlock and EndsAtomicBlock\n            Contract.Requires(InAtomicBlock || (!InAtomicBlock && StartsAtomicBlock && EndsAtomicBlock));\n            BlockStmt.StartsAtomicBlock = !InAtomicBlock || StartsAtomicBlock;\n            BlockStmt.EndsAtomicBlock = !InAtomicBlock || EndsAtomicBlock;\n            BlockStmt.InAtomicBlock = true;\n\n            BlockStmt.Sc = Sc;\n            BlockStmt.TypeResolve(enforcingType, ref errors);\n        }\n        public override void SetProgramCounter(string parentPC, int index)\n        {\n            BlockStmt.SetProgramCounter($\"{parentPC}.{index}\", 0);\n            this.PC = BlockStmt.PC;\n        }\n        public override void SetNextProgramCounter(string nextPC)\n        {\n            BlockStmt.SetNextProgramCounter(nextPC);\n            this.NextPC = BlockStmt.NextPC;\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            throw new NotSupportedException();\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            BlockStmt.ToFStarLang(indentation);\n            this.FStarStmts = BlockStmt.FStarStmts;\n            return String.Join(\";\\n\", FStarStmts.ConvertAll(stmt => stmt.GetFStarCodeOfStatement(indentation)));\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var node in BlockStmt.AllChildren())\n                yield return node;\n            yield return BlockStmt;\n        }\n    }\n\n    public class AssertStatement : Statement\n    {\n        public Expr Cond;\n\n        public AssertStatement(Token tok, Expr cond) : base(tok)\n        {\n            this.Cond = cond;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"assert \" + Cond.ToString(0, labelOn) + \";\";\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            Cond.Sc = Sc;\n            Cond.TypeResolve(new PredefinedType(PredefinedTypeEnum.Bool), ref errors);\n        }\n        public override void SetProgramCounter(string parentPC, int index)\n        {\n            // TODO: Implement this function\n            this.PC = $\"{parentPC}.{index}\";\n            Cond.SetProgramCounter(this.PC, 0);\n        }\n        public override void SetNextProgramCounter(string nextPC)\n        {\n            this.NextPC = nextPC;\n            this.Cond.SetNextProgramCounter(this.NextPC);\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"assert(\" + Cond.ToCProgram(0) + \");\";\n            return str;\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            string assertTrueStatement = \"AssertTrueStatement (\" + Cond.ToFStarLang(0) + \")\";\n            string assertFalseStatement = \"AssertFalseStatement (\" + Cond.ToFStarLang(0) + \")\";\n            FStarStmts.Add(new FStarStmt(PC, NextPC, StartsAtomicBlock, EndsAtomicBlock, assertTrueStatement, ToString(0, false) + \" true\"));\n            FStarStmts.Add(new FStarStmt(PC, NextPC, StartsAtomicBlock, EndsAtomicBlock, assertFalseStatement, ToString(0, false) + \" false\"));\n            return String.Join(\";\\n\", FStarStmts.ConvertAll(stmt => stmt.GetFStarCodeOfStatement(indentation)));;\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var node in Cond.AllChildren())\n                yield return node;\n            yield return Cond;\n        }\n    }\n\n    public class AssumeStatement : Statement\n    {\n        public Expr Cond;\n\n        public AssumeStatement(Token tok, Expr cond) : base(tok)\n        {\n            this.Cond = cond;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + FirstTok.val + \" \" + Cond.ToString(0, labelOn) + \";\";\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            Cond.Sc = Sc;\n            Cond.TypeResolve(new PredefinedType(PredefinedTypeEnum.Bool), ref errors);\n        }\n        public override void SetProgramCounter(string parentPC, int index)\n        {\n            this.PC = $\"{parentPC}.{index}\";\n            this.Cond.SetProgramCounter(this.PC, 0);\n        }\n        public override void SetNextProgramCounter(string nextPC)\n        {\n            this.NextPC = nextPC;\n            this.Cond.SetNextProgramCounter(this.NextPC);\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            throw new NotSupportedException();\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            string assumeStatement = \"AssumeExpressionStatement (\" + Cond.ToFStarLang(0) + \")\";\n            FStarStmts.Add(new FStarStmt(PC, NextPC, StartsAtomicBlock, EndsAtomicBlock, assumeStatement, ToString(0, false)));\n            return String.Join(\";\\n\", FStarStmts.ConvertAll(stmt => stmt.GetFStarCodeOfStatement(indentation)));\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var node in Cond.AllChildren())\n                yield return node;\n            yield return Cond;\n        }\n    }\n\n    public class JoinStatement : Statement\n    {\n        public Expr threadId;\n\n        public JoinStatement(Token tok, Expr tid) : base(tok)\n        {\n            this.threadId = tid;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"join \" + threadId.ToString(0, labelOn) + \";\";\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            threadId.Sc = Sc;\n            threadId.TypeResolve(new PredefinedType(PredefinedTypeEnum.ThreadId), ref errors);\n        }\n        public override void SetProgramCounter(string parentPC, int index)\n        {\n            this.PC = $\"{parentPC}.{index}\";\n            this.threadId.SetProgramCounter(this.PC, 0);\n        }\n        public override void SetNextProgramCounter(string nextPC)\n        {\n            this.NextPC = nextPC;\n            this.threadId.SetNextProgramCounter(this.NextPC);\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"pthread_join(\" + threadId.ToCProgram(0) + \", NULL);\";\n            return str;\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            string statement = $\"JoinStatement ({threadId.ToFStarLang(0)})\";\n            FStarStmts.Add(new FStarStmt(PC, NextPC, StartsAtomicBlock, EndsAtomicBlock, statement, ToString(0, false)));\n            return String.Join(\";\\n\", FStarStmts.ConvertAll(stmt => stmt.GetFStarCodeOfStatement(indentation)));\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var node in threadId.AllChildren())\n                yield return node;\n            yield return threadId;\n        }\n    }\n\n    public class WhileBlock : Statement\n    {\n        public Expr Cond;\n        // FIXME: method/invariant spec\n        public BlockStatement BlockStmt;\n\n        public WhileBlock(Token tok, Expr cond, BlockStatement block) : base(tok)\n        {\n            this.Cond = cond;\n            this.BlockStmt = block;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"while \" + Cond.ToString(0, labelOn) + \"\\n\" + BlockStmt.ToString(indentation, labelOn);\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            // Set StartsAtomicBlock and EndsAtomicBlock\n            if (InAtomicBlock)\n            {\n                BlockStmt.StartsAtomicBlock = false;\n                BlockStmt.EndsAtomicBlock = this.EndsAtomicBlock;\n                BlockStmt.InAtomicBlock = true;\n            }\n            this.EndsAtomicBlock = false;\n\n            Cond.Sc = Sc;\n            Cond.TypeResolve(new PredefinedType(PredefinedTypeEnum.Bool), ref errors);\n            BlockStmt.Sc = Sc;\n            BlockStmt.TypeResolve(null, ref errors);\n        }\n        public override void SetProgramCounter(string parentPC, int index)\n        {\n            this.PC = $\"{parentPC}.{index}\";\n            Cond.SetProgramCounter(this.PC + \".C\", 0);\n            BlockStmt.SetProgramCounter(this.PC + \".Loop\", 0);\n        }\n        public override void SetNextProgramCounter(string nextPC)\n        {\n            BlockStmt.SetNextProgramCounter(Cond.PC);\n            Cond.SetNextProgramCounter(BlockStmt.PC);\n            this.NextPC = nextPC;\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"while (\" + Cond.ToCProgram(0) + \")\\n\" + BlockStmt.ToCProgram(indentation);\n            return str;\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            // unconditional jump\n            FStarStmt jump = new FStarStmt(this.PC, Cond.PC, StartsAtomicBlock, false, \"UnconditionalJumpStatement\", \"UnconditionalJumpStatement\");\n            FStarStmts.Add(jump);\n            if (Cond is WildcardExpr)\n            {\n                FStarStmts.Add(new FStarStmt(Cond.PC, Cond.NextPC, false, EndsAtomicBlock, \"UnconditionalJumpStatement\", \"while * --taken\"));\n                FStarStmts.Add(new FStarStmt(Cond.PC, this.NextPC, false, BlockStmt.EndsAtomicBlock, \"UnconditionalJumpStatement\", \"while * --not taken\"));\n            }\n            else\n            {\n                // cond -> loop\n                string thenStatement = $\"ConditionalJumpStatement ({Cond.ToFStarLang(0)})\";\n                FStarStmts.Add(new FStarStmt(Cond.PC, Cond.NextPC, false, EndsAtomicBlock, thenStatement, $\"while {Cond.ToString(0, false)}\"));\n                // cond -> out loop\n                string elseStatement = $\"ConditionalJumpStatement \";\n                elseStatement += $\"(ExpressionUnaryOperator (ObjectTDPrimitive PrimitiveTDBool) (ObjectTDPrimitive PrimitiveTDBool) Armada.UnaryOp.UnaryOpNot ({Cond.ToFStarLang(0)}))\";\n                FStarStmts.Add(new FStarStmt(Cond.PC, this.NextPC, false, BlockStmt.EndsAtomicBlock, elseStatement, $\"!({Cond.ToString(0, false)})\"));\n            }\n            // loop\n            BlockStmt.ToFStarLang(indentation);\n            FStarStmts.AddRange(BlockStmt.FStarStmts);\n            return String.Join(\";\\n\", FStarStmts.ConvertAll(stmt => stmt.GetFStarCodeOfStatement(indentation)));\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var node in Cond.AllChildren())\n                yield return node;\n            yield return Cond;\n            foreach (var node in BlockStmt.AllChildren())\n                yield return node;\n            yield return BlockStmt;\n        }\n    }\n\n    public class IfStatement : Statement\n    {\n        public Expr Cond;\n        public BlockStatement Then;\n        public Statement Else; // FIXME: Optional\n\n        public string IfElseNextPC;\n        public bool IfElseEndsAtomicBlock = false;\n\n        public IfStatement(Token tok, Expr condition, BlockStatement thenPath, Statement elsePath = null) : base(tok)\n        {\n            Contract.Requires(condition != null);\n            Contract.Requires(thenPath != null);\n            Cond = condition;\n            Then = thenPath;\n            Else = elsePath;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"if \" + Cond.ToString(0, labelOn) + \"\\n\" + Then.ToString(indentation, labelOn);\n            if (Else != null)\n            {\n                str = str + \"\\n\" + indentationStr + \"else\\n\" + Else.ToString(indentation, labelOn);\n            }\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            // Set StartsAtomicBlock and EndsAtomicBlock\n            if (InAtomicBlock)\n            {\n                Then.StartsAtomicBlock = false;\n                Then.EndsAtomicBlock = this.EndsAtomicBlock;\n                Then.InAtomicBlock = true;\n                if (Else != null)\n                {\n                    Else.StartsAtomicBlock = false;\n                    Else.EndsAtomicBlock = this.EndsAtomicBlock;\n                    Else.InAtomicBlock = true;\n                    this.IfElseEndsAtomicBlock = false;\n                }\n                else\n                {\n                    this.IfElseEndsAtomicBlock = this.EndsAtomicBlock;\n                }\n                this.EndsAtomicBlock = false;\n            }\n\n            Cond.Sc = Sc;\n            Cond.TypeResolve(new PredefinedType(PredefinedTypeEnum.Bool), ref errors);\n            Then.Sc = Sc;\n            Then.TypeResolve(null, ref errors);\n\n            if (Else != null)\n            {\n                Else.Sc = Sc;\n                Else.TypeResolve(null, ref errors);\n            }\n        }\n        public override void SetProgramCounter(string parentPC, int index)\n        {\n            this.PC = $\"{parentPC}.{index}\";\n            Cond.SetProgramCounter(this.PC, 0);\n            Then.SetProgramCounter(this.PC + \".T\", 0);\n            if (Else != null)\n            {\n                Else.SetProgramCounter(this.PC + \".F\", 0);\n            }\n        }\n        public override void SetNextProgramCounter(string nextPC)\n        {\n            Then.SetNextProgramCounter(nextPC);\n            if (Else != null)\n            {\n                Else.SetNextProgramCounter(nextPC);\n                IfElseNextPC = Else.PC;\n            }\n            else\n            {\n                IfElseNextPC = nextPC;\n            }\n            Cond.SetNextProgramCounter(Then.PC);\n            this.NextPC = nextPC;\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"if (\" + Cond.ToCProgram(0) + \")\\n\" + Then.ToCProgram(indentation);\n            if (Else != null)\n            {\n                str = str + \"\\n\" + indentationStr + \"else\\n\" + Else.ToCProgram(indentation);\n            }\n            return str;\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            if (Cond is WildcardExpr)\n            {\n                FStarStmts.Add(new FStarStmt(PC, Cond.NextPC, StartsAtomicBlock, EndsAtomicBlock, \"UnconditionalJumpStatement\", \"if * --taken\"));\n                FStarStmts.Add(new FStarStmt(PC, IfElseNextPC, StartsAtomicBlock, IfElseEndsAtomicBlock, \"UnconditionalJumpStatement\", \"if * --not taken\"));\n            }\n            else\n            {\n                // cond -> then\n                string thenStatement = $\"ConditionalJumpStatement ({Cond.ToFStarLang(0)})\";\n                FStarStmts.Add(new FStarStmt(PC, Cond.NextPC, StartsAtomicBlock, EndsAtomicBlock, thenStatement, $\"if {Cond.ToString(0, false)}\"));\n                // cond -> else\n                string elseStatement = $\"ConditionalJumpStatement \";\n                elseStatement += $\"(ExpressionUnaryOperator (ObjectTDPrimitive PrimitiveTDBool) (ObjectTDPrimitive PrimitiveTDBool) Armada.UnaryOp.UnaryOpNot ({Cond.ToFStarLang(0)}))\";\n                FStarStmts.Add(new FStarStmt(PC, IfElseNextPC, StartsAtomicBlock, IfElseEndsAtomicBlock, elseStatement, $\"!({Cond.ToString(0, false)})\"));\n            }\n            // then\n            Then.ToFStarLang(indentation);\n            FStarStmts.AddRange(Then.FStarStmts);\n            // optinal else\n            if (Else != null)\n            {\n                Else.ToFStarLang(indentation);\n                FStarStmts.AddRange(Else.FStarStmts);\n            }\n            return String.Join(\";\\n\", FStarStmts.ConvertAll(stmt => stmt.GetFStarCodeOfStatement(indentation)));\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var node in Cond.AllChildren())\n                yield return node;\n            yield return Cond;\n            foreach (var node in Then.AllChildren())\n                yield return node;\n            yield return Then;\n            if (Else != null)\n            {\n                foreach (var node in Else.AllChildren())\n                    yield return node;\n                yield return Else;\n            }\n        }\n    }\n\n    public class SomehowStatement : Statement\n    {\n        public readonly Expr UndefinedUnless;\n        public readonly List<Ident> Mod;\n        public readonly Expr Ens;\n        public readonly List<Attribute> Attrs;\n        public bool IsSequential = false;\n\n        public SomehowStatement(Token tok, List<Expr> undefinedUnless, List<Ident> mod, List<Expr> ens, List<Attribute> attrs) : base(tok)\n        {\n            Contract.Requires(undefinedUnless != null);\n            Contract.Requires(mod != null);\n            Contract.Requires(ens != null);\n\n            if (undefinedUnless.Count == 0)\n            {\n                UndefinedUnless = null;\n            }\n            else\n            {\n                UndefinedUnless = undefinedUnless[0];\n                for (int i = 1; i < undefinedUnless.Count; i++)\n                {\n                    UndefinedUnless = new BinaryExpr(UndefinedUnless.FirstTok,\n                      UndefinedUnless, undefinedUnless[i], Opcode.And);\n                }\n                UndefinedUnless.LastTok = undefinedUnless[undefinedUnless.Count - 1].LastTok;\n            }\n            this.Mod = mod;\n            if (ens.Count == 0)\n            {\n                Ens = null;\n            }\n            else\n            {\n                Ens = ens[0];\n                for (int i = 1; i < ens.Count; i++)\n                {\n                    Ens = new BinaryExpr(Ens.FirstTok,\n                      Ens, ens[i], Opcode.And);\n                }\n                Ens.LastTok = ens[ens.Count - 1].LastTok;\n            }\n            this.Attrs = attrs;\n            foreach (var attr in Attrs)\n            {\n                // check for bypass write buffer (bwb) attribute\n                if (attr.Name.Name == \"bwb\")\n                {\n                    IsSequential = true;\n                }\n            }\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"somehow\";\n            if (Mod.Count != 0)\n            {\n                str += \"\\n\" + indentationStr + \"  modifies \";\n                var sep = \"\";\n                foreach (var m in Mod)\n                {\n                    str += sep + m.ToString(0, labelOn);\n                    sep = \", \";\n                }\n            }\n            if (Ens != null)\n            {\n                str += \"\\n\" + indentationStr + \"  ensures \" + Ens.ToString(0, labelOn);\n            }\n            if (UndefinedUnless != null)\n            {\n                str += \"\\n\" + indentationStr + \"  undefined_unless \" + UndefinedUnless.ToString(0, labelOn);\n            }\n            str += \";\";\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            if (UndefinedUnless != null)\n            {\n                UndefinedUnless.Sc = Sc;\n                UndefinedUnless.TypeResolve(new PredefinedType(PredefinedTypeEnum.Bool), ref errors);\n            }\n            foreach (var e in Mod)\n            {\n                e.Sc = Sc;\n                e.TypeResolve(null, ref errors);\n            }\n            if (Ens != null)\n            {\n                Ens.Sc = Sc;\n                Ens.TypeResolve(new PredefinedType(PredefinedTypeEnum.Bool), ref errors);\n            }\n        }\n        public override void SetProgramCounter(string parentPC, int index)\n        {\n            // TODO: Implement this function\n            this.PC = $\"{parentPC}.{index}\";\n            if (UndefinedUnless != null)\n                UndefinedUnless.SetProgramCounter(this.PC, 0);\n            foreach (var expr in Mod)\n            {\n                expr.SetProgramCounter(this.PC, 0);\n            }\n            if (Ens != null)\n                Ens.SetProgramCounter(this.PC, 0);\n        }\n        public override void SetNextProgramCounter(string nextPC)\n        {\n            this.NextPC = nextPC;\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            throw new NotSupportedException();\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            string indentationStr = new string(' ', indentation);\n            string statement = \"SomehowStatement \";\n            if (UndefinedUnless == null)\n            {\n                statement += \"(ExpressionConstant (ObjectValueAbstract bool true)) \";\n            }\n            else\n            {\n                statement += \"( \" + UndefinedUnless.ToFStarLang(0) + \") \";\n            }\n            statement += (IsSequential ? \"true\\n\" : \"false\\n\");\n            statement += indentationStr + \"    [ \";\n            var sep = \"\";\n            foreach (var id in Mod)\n            {\n                statement += sep + \"(\" + id.ToFStarLang(0) + \")\";\n                sep = \"; \";\n            }\n            statement += \" ]\\n\";\n            if (Ens == null)\n            {\n                statement += indentationStr + \"    (ExpressionConstant (ObjectValueAbstract bool true)) \";\n            }\n            else\n            {\n                statement += indentationStr + \"    (\" + Ens.ToFStarLang(0) + \") \";\n            }\n            FStarStmts.Add(new FStarStmt(PC, NextPC, StartsAtomicBlock, EndsAtomicBlock, statement, this.ToString(indentation, false)));\n            return String.Join(\";\\n\", FStarStmts.ConvertAll(stmt => stmt.GetFStarCodeOfStatement(indentation)));\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            yield return UndefinedUnless;\n            foreach (var expr in Mod)\n            {\n                foreach (var node in expr.AllChildren())\n                    yield return node;\n                yield return expr;\n            }\n            yield return Ens;\n        }\n    }\n\n    public class MatchCaseStmt : MatchCase\n    {\n        public List<Statement> Stmts;\n\n        public MatchCaseStmt(Token tok, string id, List<CasePattern> cps, List<Statement> stmts)\n          : base(tok, id, cps)\n        {\n            Contract.Requires(id != null);\n            // Contract.Requires(cce.NonNullElements(cps));\n            Contract.Requires(stmts != null);\n            this.Stmts = stmts;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = base.ToString(indentation, labelOn);\n            List<string> stmtsStr = new List<string>();\n            foreach (Statement stmt in Stmts)\n            {\n                stmtsStr.Add(stmt.ToString(0, labelOn));\n            }\n            str += string.Join(\"; \", stmtsStr);\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            base.TypeResolve(null, ref errors);\n            foreach (Statement stmt in Stmts)\n            {\n                stmt.Sc = Sc;\n                stmt.TypeResolve(null, ref errors);\n            }\n            // no need to set this.Ty because this class is not an expression\n        }\n        public override void SetProgramCounter(string parentPC, int index)\n        {\n            throw new NotImplementedException();\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            List<string> stmtsStr = new List<string>();\n            foreach (Statement stmt in Stmts)\n            {\n                stmtsStr.Add(stmt.ToCProgram(0));\n            }\n            str += string.Join(\"; \", stmtsStr);\n            return str;\n        }\n\n        public override string ToFStarLang(int indentation)\n        {\n            throw new NotImplementedException();\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var node in base.AllChildren())\n                yield return node;\n            foreach (var stmt in Stmts)\n            {\n                foreach (var node in stmt.AllChildren())\n                    yield return node;\n                yield return stmt;\n            }\n        }\n    }\n\n    public class MatchStatement : Statement\n    {\n        private Expr source;\n        private List<MatchCaseStmt> cases;\n        public readonly bool UsesOptionalBraces;\n\n        public MatchStatement(Token tok, Expr source, List<MatchCaseStmt> cases, bool usesOptionalBraces)\n        : base(tok)\n        {\n            Contract.Requires(source != null);\n            // Contract.Requires(cce.NonNullElements(cases));\n            this.source = source;\n            this.cases = cases;\n            this.UsesOptionalBraces = usesOptionalBraces;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            List<string> elementsStr = new List<string>();\n            foreach (MatchCaseStmt stmt in cases)\n            {\n                elementsStr.Add(stmt.ToString(0, labelOn));\n            }\n            string CasesStr = string.Join(\" \", elementsStr);\n            if (UsesOptionalBraces)\n            {\n                CasesStr = \"{\" + CasesStr + \"}\";\n            }\n            str = str + indentationStr + \"match \" + source.ToString(0, labelOn) + \" \" + CasesStr;\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            source.Sc = Sc;\n            source.TypeResolve(null, ref errors);\n            foreach (MatchCaseStmt matchCase in cases)\n            {\n                matchCase.Sc = Sc;\n                matchCase.TypeResolve(null, ref errors);\n            }\n        }\n\n        public override void SetProgramCounter(string parentPC, int index)\n        {\n            this.PC = $\"{parentPC}.{index}\";\n            for (int i = 0; i < cases.Count; i++)\n            {\n                cases[i].SetProgramCounter(this.PC, i);\n            }\n        }\n        public override void SetNextProgramCounter(string nextPC)\n        {\n            foreach (MatchCaseStmt matchCase in cases)\n            {\n                matchCase.SetNextProgramCounter(nextPC);\n            }\n            this.NextPC = nextPC;\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            throw new NotImplementedException();\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var node in source.AllChildren())\n                yield return node;\n            yield return source;\n            foreach (var caseStmt in cases)\n            {\n                foreach (var node in caseStmt.AllChildren())\n                    yield return node;\n                yield return caseStmt;\n            }\n        }\n    }\n\n    public class ExprStatement : Statement\n    {\n        public Expr Expression;\n\n        public ExprStatement(Token tok, Expr expr)\n        : base(tok)\n        {\n            Contract.Requires(expr != null);\n            Contract.Requires(expr is CreateThreadRhs || expr is CompareAndSwapRhs);\n            Expression = expr;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + Expression.ToString(0, labelOn) + ';';\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            Expression.Sc = Sc;\n            Expression.TypeResolve(null, ref errors);\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + Expression.ToCProgram(0) + ';';\n            return str;\n        }\n\n        // TODO: programCounter may change\n        public override void SetProgramCounter(string parentPC, int index)\n        {\n            this.PC = $\"{parentPC}.{index}\";\n        }\n        public override void SetNextProgramCounter(string nextPC)\n        {\n            this.NextPC = nextPC;\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            if (Expression is CreateThreadRhs)\n            {\n                CreateThreadRhs createThreadExpr = Expression as CreateThreadRhs;\n                FStarStmts.Add(new FStarStmt(PC, NextPC, StartsAtomicBlock, EndsAtomicBlock, createThreadExpr.ToFStarLang(0), ToString(0, false)));\n            }\n            else if (Expression is CompareAndSwapRhs)\n            {\n                CompareAndSwapRhs exprStmt = Expression as CompareAndSwapRhs;\n                string compareStatement = exprStmt.ToFStarLang(0);\n                FStarStmts.Add(new FStarStmt(PC, NextPC, StartsAtomicBlock, EndsAtomicBlock, compareStatement, ToString(0, false)));\n            }\n            return String.Join(\";\\n\", FStarStmts.ConvertAll(stmt => stmt.GetFStarCodeOfStatement(indentation)));\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var node in Expression.AllChildren())\n                yield return node;\n            yield return Expression;\n        }\n    }\n\n    public class ContinueStatement : Statement\n    {\n\n        public ContinueStatement(Token tok)\n        : base(tok)\n        {\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"continue;\";\n            return str;\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"continue;\";\n            return str;\n        }\n\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            if (PC.LastIndexOf(\".Loop\") == -1) {\n                errors.SemErr(this.FirstTok, $\"continue is not used inside a while loop!\");\n            }\n        }\n        public override void SetProgramCounter(string parentPC, int index)\n        {\n            this.PC = $\"{parentPC}.{index}\";\n        }\n        public override void SetNextProgramCounter(string nextPC)\n        {\n            if (PC.LastIndexOf(\".Loop\") != -1) {\n                var startOfLatestLoopPC = this.PC.Substring(0, this.PC.LastIndexOf(\".Loop\"));\n                var splitted = startOfLatestLoopPC.Split('.');\n                this.NextPC = $\"{String.Join('.', splitted.SkipLast(1))}.{Int32.Parse(splitted.Last())}.C\";\n            }\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            FStarStmts.Add(new FStarStmt(PC, NextPC, StartsAtomicBlock, EndsAtomicBlock, \"UnconditionalJumpStatement\", this.ToString(0, false)));\n            return String.Join(\";\\n\", FStarStmts.ConvertAll(stmt => stmt.GetFStarCodeOfStatement(indentation)));\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            yield break;\n        }\n    }\n\n    public class BreakStatement : Statement\n    {\n\n        public BreakStatement(Token tok)\n        : base(tok)\n        {\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"break;\";\n            return str;\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"break;\";\n            return str;\n        }\n\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            if (PC.LastIndexOf(\".Loop\") == -1) {\n                errors.SemErr(this.FirstTok, $\"break is not used inside a while loop!\");\n            }\n        }\n        public override void SetProgramCounter(string parentPC, int index)\n        {\n            this.PC = $\"{parentPC}.{index}\";\n        }\n        public override void SetNextProgramCounter(string nextPC)\n        {\n            if (PC.LastIndexOf(\".Loop\") != -1) {\n                var startOfLatestLoopPC = this.PC.Substring(0, this.PC.LastIndexOf(\".Loop\"));\n                var splitted = startOfLatestLoopPC.Split('.');\n                this.NextPC = $\"{String.Join('.', splitted.SkipLast(1))}.{Int32.Parse(splitted.Last()) + 1}\";\n            }\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            FStarStmts.Add(new FStarStmt(PC, NextPC, StartsAtomicBlock, EndsAtomicBlock, \"UnconditionalJumpStatement\", this.ToString(0, false)));\n            return String.Join(\";\\n\", FStarStmts.ConvertAll(stmt => stmt.GetFStarCodeOfStatement(indentation)));\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            yield break;\n        }\n    }\n\n    public class ReturnStatement : Statement\n    {\n        public Expr Val;\n\n        public ReturnStatement(Token tok, Expr val)\n        : base(tok)\n        {\n            Val = val;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"return\";\n            str += (Val != null) ? \" \" + Val.ToString(0, labelOn) : \"\";\n            str += ';';\n            return str;\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"return\";\n            str += (Val != null) ? \" \" + Val.ToCProgram(0) : \"\";\n            str += ';';\n            return str;\n        }\n\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            if (Val != null)\n            {\n                Val.Sc = Sc;\n                // TODO: set enforcingtype?\n                Val.TypeResolve(enforcingType, ref errors);\n            }\n        }\n        public override void SetProgramCounter(string parentPC, int index)\n        {\n            this.PC = $\"{parentPC}.{index}\";\n            if (this.Val != null)\n                this.Val.SetProgramCounter(this.PC, 0);\n        }\n        public override void SetNextProgramCounter(string nextPC)\n        {\n            this.NextPC = $\"{this.PC.Split('.')[0]}.End\";\n            if (this.Val != null)\n                this.Val.SetNextProgramCounter(this.NextPC);\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            if (Val != null)\n            {\n                string statement = \"UpdateStatement \";\n                // TODO: What is the semantics of return statement with regards to sequential\n                // if (IsSequential)\n                statement += \"true\";\n                // else\n                // str += \"false\";\n                var func = Sc.EnclosingNode as MethodDecl;\n                statement += $\" ({func.Ret.Name.ToFStarLang(0)}) ({Val.ToFStarLang(0)})\";\n                FStarStmts.Add(new FStarStmt(PC, NextPC, StartsAtomicBlock, EndsAtomicBlock, statement, this.ToString(0, false)));\n                return String.Join(\";\\n\", FStarStmts.ConvertAll(stmt => stmt.GetFStarCodeOfStatement(indentation)));\n            }\n            else {\n                FStarStmts.Add(new FStarStmt(PC, NextPC, StartsAtomicBlock, EndsAtomicBlock, \"UnconditionalJumpStatement\", this.ToString(0, false)));\n                return String.Join(\";\\n\", FStarStmts.ConvertAll(stmt => stmt.GetFStarCodeOfStatement(indentation)));\n            }\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            if (Val != null)\n            {\n                foreach (var node in Val.AllChildren())\n                    yield return node;\n                yield return Val;\n            }\n        }\n    }\n\n    public class YieldStatement : Statement\n    {\n        public YieldStatement(Token tok)\n        : base(tok) { }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"yield;\";\n            return str;\n        }\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n        }\n        public override void SetProgramCounter(string parentPC, int index)\n        {\n            this.PC = $\"{parentPC}.{index}\";\n        }\n        public override void SetNextProgramCounter(string nextPC)\n        {\n            this.NextPC = nextPC;\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            if (!InAtomicBlock) {\n                FStarStmts.Add(new FStarStmt(PC, NextPC, true, true, \"UnconditionalJumpStatement\", this.ToString(0, false)));\n            } else {\n                // split the yield statement into two unconditional jump to handle atomic\n                FStarStmts.Add(new FStarStmt(PC, PC + \".Y\", false, true, \"UnconditionalJumpStatement\", this.ToString(0, false)));\n                FStarStmts.Add(new FStarStmt(PC + \".Y\", NextPC, true, false, \"UnconditionalJumpStatement\", this.ToString(0, false)));\n            }\n            return String.Join(\";\\n\", FStarStmts.ConvertAll(stmt => stmt.GetFStarCodeOfStatement(indentation)));\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            yield break;\n        }\n    }\n\n    public class GotoStatement : Statement\n    {\n        public Ident Id;\n        public Statement stmt; // filled in resolution\n\n        public GotoStatement(Token tok, Ident id)\n        : base(tok)\n        {\n            Contract.Requires(id != null);\n            Id = id;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"goto \" + Id.ToString(0, labelOn) + ';';\n            return str;\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            return ToString(indentation, false);\n        }\n\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            stmt = Sc.GetLabelStatement(Id);\n            if (stmt == null)\n            {\n                errors.SemErr(Id.FirstTok, $\"Label {Id.Name} not found!\");\n            }\n            if (stmt.InAtomicBlock ^ InAtomicBlock)\n            {\n                errors.SemErr(FirstTok, \"Goto cannot cross atomic block!\");\n            }\n        }\n        public override void SetProgramCounter(string parentPC, int index)\n        {\n            this.PC = $\"{parentPC}.{index}\";\n        }\n        public override void SetNextProgramCounter(string nextPC)\n        {\n            this.NextPC = nextPC;\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            FStarStmts.Add(new FStarStmt(PC, stmt.PC, StartsAtomicBlock, EndsAtomicBlock, \"UnconditionalJumpStatement\", this.ToString(0, false)));\n            return String.Join(\";\\n\", FStarStmts.ConvertAll(stmt => stmt.GetFStarCodeOfStatement(indentation)));\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            yield return Id;\n        }\n    }\n\n    public class FenceStatement : Statement\n    {\n        public FenceStatement(Token tok)\n        : base(tok) { }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"fence;\";\n            return str;\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            throw new NotImplementedException();\n        }\n\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        { }\n        public override void SetProgramCounter(string parentPC, int index)\n        {\n            this.PC = $\"{parentPC}.{index}\";\n        }\n        public override void SetNextProgramCounter(string nextPC)\n        {\n            this.NextPC = nextPC;\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            FStarStmts.Add(new FStarStmt(PC, NextPC, StartsAtomicBlock, EndsAtomicBlock, \"FenceStatement\", this.ToString(0, false)));\n            return String.Join(\";\\n\", FStarStmts.ConvertAll(stmt => stmt.GetFStarCodeOfStatement(indentation)));\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            yield break;\n        }\n    }\n\n    public class DeallocStatement : Statement\n    {\n        Expr Addr;\n\n        public DeallocStatement(Token tok, Expr addr)\n        : base(tok)\n        {\n            Contract.Requires(addr != null);\n            Addr = addr;\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"free(\" + Addr.ToString(0, labelOn) + \");\";\n            return str;\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"free(\" + Addr.ToCProgram(0) + \");\";\n            return str;\n        }\n\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        {\n            Addr.Sc = Sc;\n            Addr.TypeResolve(null, ref errors); // TODO: change to pointer type?\n        }\n        public override void SetProgramCounter(string parentPC, int index)\n        {\n            this.PC = $\"{parentPC}.{index}\";\n        }\n        public override void SetNextProgramCounter(string nextPC)\n        {\n            this.NextPC = nextPC;\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            string deallocStatement = $\"DeallocStatement ({Addr.ToFStarLang(0)})\";\n            FStarStmts.Add(new FStarStmt(PC, NextPC, StartsAtomicBlock, EndsAtomicBlock, deallocStatement, ToString(0, false)));\n            return String.Join(\";\\n\", FStarStmts.ConvertAll(stmt => stmt.GetFStarCodeOfStatement(indentation)));\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            foreach (var node in Addr.AllChildren())\n                yield return node;\n            yield return Addr;\n        }\n    }\n\n    // This node is not in grammar, but generated during resolution to better handle corner cases\n    public class UnconditionalJumpStatement : Statement\n    {\n        public UnconditionalJumpStatement(Token tok, string nextPC)\n        : base(tok)\n        {\n            SetNextProgramCounter(nextPC);\n        }\n\n        public override string ToString(int indentation, bool labelOn)\n        {\n            return new string(' ', indentation) + \"UnconditionalJump\";\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            return ToString(indentation, false);\n        }\n\n        public override void TypeResolve(Type enforcingType, ref Errors errors)\n        { }\n        public override void SetProgramCounter(string parentPC, int index)\n        {\n            this.PC = $\"{parentPC}.{index}\";\n        }\n        public override void SetNextProgramCounter(string nextPC)\n        {\n            this.NextPC = nextPC;\n        }\n        public override string ToFStarLang(int indentation)\n        {\n            FStarStmts.Add(new FStarStmt(PC, NextPC, StartsAtomicBlock, EndsAtomicBlock, \"UnconditionalJumpStatement\", this.ToString(0, false)));\n            return String.Join(\";\\n\", FStarStmts.ConvertAll(stmt => stmt.GetFStarCodeOfStatement(indentation)));\n        }\n        public override IEnumerable<AstNode> AllChildren()\n        {\n            yield break;\n        }\n    }\n}\n"
  },
  {
    "path": "experimental/Source/Armada/AST/Type.cs",
    "content": "using System.Collections.Generic;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System;\n\nnamespace Microsoft.Starmada\n{\n    public abstract class Type\n    {\n        public abstract string ToString(int indentation);\n        public abstract string ToCProgram(int indentation);\n        public abstract string ToFStarLang(int indentation, bool includeObjectTD);\n\n        public abstract bool EqualType(Type other);\n        // The direction is this can be converted to other.\n        public abstract bool CompatibleType(Type other);\n    }\n\n    public enum PredefinedTypeEnum\n    {\n        Int8 = 0,\n        Int16,\n        Int32,\n        Int64,\n        UInt8,\n        UInt16,\n        UInt32,\n        UInt64,\n        Int,\n        Nat,\n        Bool,\n        Real,\n        ThreadId,\n        Char,\n        String\n    }\n\n    public class PredefinedType : Type\n    {\n        public PredefinedTypeEnum Kind;\n        public PredefinedType(PredefinedTypeEnum kind)\n        {\n            this.Kind = kind;\n        }\n\n        public bool IsBoundedInt()\n        {\n            switch (Kind)\n            {\n                case PredefinedTypeEnum.Int8:\n                case PredefinedTypeEnum.Int16:\n                case PredefinedTypeEnum.Int32:\n                case PredefinedTypeEnum.Int64:\n                case PredefinedTypeEnum.UInt8:\n                case PredefinedTypeEnum.UInt16:\n                case PredefinedTypeEnum.UInt32:\n                case PredefinedTypeEnum.UInt64:\n                    return true;\n                default: return false;\n            }\n        }\n\n        public override string ToString(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr;\n            switch (Kind)\n            {\n                case PredefinedTypeEnum.Int8: str += \"int8\"; break;\n                case PredefinedTypeEnum.Int16: str += \"int16\"; break;\n                case PredefinedTypeEnum.Int32: str += \"int32\"; break;\n                case PredefinedTypeEnum.Int64: str += \"int64\"; break;\n                case PredefinedTypeEnum.UInt8: str += \"uint8\"; break;\n                case PredefinedTypeEnum.UInt16: str += \"uint16\"; break;\n                case PredefinedTypeEnum.UInt32: str += \"uint32\"; break;\n                case PredefinedTypeEnum.UInt64: str += \"uint64\"; break;\n                case PredefinedTypeEnum.Int: str += \"int\"; break;\n                case PredefinedTypeEnum.Nat: str += \"nat\"; break;\n                case PredefinedTypeEnum.Bool: str += \"bool\"; break;\n                case PredefinedTypeEnum.Real: str += \"real\"; break;\n                case PredefinedTypeEnum.ThreadId: str += \"tid_t\"; break;\n                case PredefinedTypeEnum.Char: str += \"char\"; break;\n                case PredefinedTypeEnum.String: str += \"string\"; break;\n                default: throw new ArgumentException(\"Unknown type\");\n            }\n            return str;\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n                        string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr;\n            switch (Kind)\n            {\n                case PredefinedTypeEnum.Int8: str += \"int8_t\"; break;\n                case PredefinedTypeEnum.Int16: str += \"int16_t\"; break;\n                case PredefinedTypeEnum.Int32: str += \"int32_t\"; break;\n                case PredefinedTypeEnum.Int64: str += \"int64_t\"; break;\n                case PredefinedTypeEnum.UInt8: str += \"uint8_t\"; break;\n                case PredefinedTypeEnum.UInt16: str += \"uint16_t\"; break;\n                case PredefinedTypeEnum.UInt32: str += \"uint32_t\"; break;\n                case PredefinedTypeEnum.UInt64: str += \"uint64_t\"; break;\n                case PredefinedTypeEnum.Int: str += \"int\"; break;\n                case PredefinedTypeEnum.Nat: str += \"nat\"; break;\n                case PredefinedTypeEnum.Bool: str += \"bool\"; break;\n                case PredefinedTypeEnum.Real: str += \"real\"; break;\n                case PredefinedTypeEnum.ThreadId: str += \"tid_t\"; break;\n                case PredefinedTypeEnum.Char: str += \"char\"; break;\n                case PredefinedTypeEnum.String: str += \"string\"; break;\n                default: throw new ArgumentException(\"Unknown type\");\n            }\n            return str;\n        }\n\n        public override string ToFStarLang(int indentation, bool includeObjectTD)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr;\n            switch (Kind)\n            {\n                case PredefinedTypeEnum.Int8:\n                  str += includeObjectTD ? \"ObjectTDPrimitive (PrimitiveTDBoundedInt Armada.BoundedInt.MachineInt8)\" : \"Armada.BoundedInt.MachineInt8\";\n                  break;\n                case PredefinedTypeEnum.Int16:\n                  str += includeObjectTD ? \"ObjectTDPrimitive (PrimitiveTDBoundedInt Armada.BoundedInt.MachineInt16)\" : \"Armada.BoundedInt.MachineInt16\";\n                  break;\n                case PredefinedTypeEnum.Int32:\n                  str += includeObjectTD ? \"ObjectTDPrimitive (PrimitiveTDBoundedInt Armada.BoundedInt.MachineInt32)\" : \"Armada.BoundedInt.MachineInt32\";\n                  break;\n                case PredefinedTypeEnum.Int64:\n                  str += includeObjectTD ? \"ObjectTDPrimitive (PrimitiveTDBoundedInt Armada.BoundedInt.MachineInt64)\" : \"Armada.BoundedInt.MachineInt64\";\n                  break;\n                case PredefinedTypeEnum.UInt8:\n                  str += includeObjectTD ? \"ObjectTDPrimitive (PrimitiveTDBoundedInt Armada.BoundedInt.MachineUint8)\" : \"Armada.BoundedInt.MachineUint8\";\n                  break;\n                case PredefinedTypeEnum.UInt16:\n                  str += includeObjectTD ? \"ObjectTDPrimitive (PrimitiveTDBoundedInt Armada.BoundedInt.MachineUint16)\" : \"Armada.BoundedInt.MachineUint16\";\n                  break;\n                case PredefinedTypeEnum.UInt32:\n                  str += includeObjectTD ? \"ObjectTDPrimitive (PrimitiveTDBoundedInt Armada.BoundedInt.MachineUint32)\" : \"Armada.BoundedInt.MachineUint32\";\n                  break;\n                case PredefinedTypeEnum.UInt64:\n                  str += includeObjectTD ? \"ObjectTDPrimitive (PrimitiveTDBoundedInt Armada.BoundedInt.MachineUint64)\" : \"Armada.BoundedInt.MachineUint64\";\n                  break;\n                case PredefinedTypeEnum.Int:\n                  str += includeObjectTD ? \"ObjectTDAbstract int\" : \"int\";\n                  break;\n                case PredefinedTypeEnum.Nat:\n                  str += includeObjectTD ? \"ObjectTDAbstract nat\" : \"nat\";\n                  break;\n                case PredefinedTypeEnum.Bool:\n                  str += includeObjectTD ? \"ObjectTDPrimitive PrimitiveTDBool\" : \"bool\";\n                  break;\n                case PredefinedTypeEnum.Real:\n                  str += includeObjectTD ? \"ObjectTDAbstract real\" : \"real\";\n                  break;\n                case PredefinedTypeEnum.ThreadId:\n                  str += includeObjectTD ? \"ObjectTDPrimitive PrimitiveTDThreadId\" : \"tid_t\";\n                  break;\n                case PredefinedTypeEnum.Char:\n                  str += includeObjectTD ? \"ObjectTDAbstract char\" : \"char\";\n                  break;\n                case PredefinedTypeEnum.String:\n                  str += includeObjectTD ? \"ObjectTDAbstract string\" : \"string\";\n                  break;\n                default: throw new ArgumentException(\"Unknown type\");\n            }\n            return str;\n        }\n        public override bool EqualType(Type other)\n        {\n            if (other is PredefinedType otherT)\n            {\n                return Kind == otherT.Kind;\n            }\n            return false;\n        }\n        public override bool CompatibleType(Type other)\n        {\n            // TODO (yuchen): ok this is nasty; let's check it carefully\n            if (other is PredefinedType otherT)\n            {\n                return Kind == otherT.Kind || (Kind, otherT.Kind) switch {\n                    (PredefinedTypeEnum.Nat, PredefinedTypeEnum.Int) => true,\n                    (PredefinedTypeEnum a, PredefinedTypeEnum.Int) =>\n                        // Bounded signed int types are compatible with unbounded int\n                        IsBoundedSigned(a) || IsBoundedUnsigned(a),\n                    (PredefinedTypeEnum a, PredefinedTypeEnum.Nat) =>\n                        // Bounded unsigned int types are compatible with unbounded nat\n                        IsBoundedUnsigned(a),\n                    (PredefinedTypeEnum a, PredefinedTypeEnum b) =>\n                        // Only bounded int types may be compatible to each other\n                        CompatibleBoundedInt(a, b),\n                };\n            }\n            return false;\n        }\n        static bool IsBoundedSigned(PredefinedTypeEnum kind) {\n            return PredefinedTypeEnum.Int8 <= kind && kind <= PredefinedTypeEnum.Int64;\n        }\n        static bool IsBoundedUnsigned(PredefinedTypeEnum kind) {\n            return PredefinedTypeEnum.UInt8 <= kind && kind <= PredefinedTypeEnum.UInt64;\n        }\n        static bool CompatibleBoundedInt(PredefinedTypeEnum a, PredefinedTypeEnum b) {\n            return (IsBoundedSigned(a) && IsBoundedSigned(b) && a <= b)\n                || (IsBoundedUnsigned(a) && IsBoundedUnsigned(b) && a <= b);\n        }\n    }\n\n    public class PointerType : Type\n    {\n        public Type EntityType;\n        public PointerType(Type entityType)\n        {\n            this.EntityType = entityType;\n        }\n        public override string ToString(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + \"ptr<\";\n            str = str + EntityType.ToString(0) + \">\";\n            return str;\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + EntityType.ToString(0) + \"*\";\n            return str;\n        }\n        public override string ToFStarLang(int indentation, bool includeObjectTD)\n        {\n            if (!includeObjectTD)\n            {\n                throw new NotImplementedException();\n            }\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str += indentationStr + \"ObjectTDPrimitive PrimitiveTDPointer\";\n            return str;\n        }\n        public override bool EqualType(Type other)\n        {\n            return other switch {\n                PointerType otherT => EntityType.EqualType(otherT.EntityType),\n                _ => false,\n            };\n        }\n        public override bool CompatibleType(Type other)\n        {\n            // TODO (yuchen): Check assumption\n            // Pointer types don't have the C-like compatibility.\n            return other switch {\n                PointerType otherT => EntityType.CompatibleType(otherT.EntityType),\n                _ => false,\n            };\n        }\n    }\n\n    // This type is only used in datatypeDecl TypeResolve\n    public class GenericType : Type\n    {\n        public string Name;\n        public int Index;\n\n        public GenericType(string name, int index)\n        {\n            Name = name;\n            Index = index;\n        }\n\n        public override string ToString(int indentation)\n        {\n            return new string(' ', indentation) + Name;\n        }\n        public override string ToCProgram(int indentation)\n        {\n            return ToString(indentation);\n        }\n        public override string ToFStarLang(int indentation,  bool includeObjectTD)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + (includeObjectTD ? \"ObjectTDAbstract \" : \"\");\n            str += Name;\n            return str;\n        }\n        public override bool EqualType(Type other)\n        {\n            // TODO (yuchen): Check assumption.\n            // Index is a local tag and should imply Name.\n            return other switch {\n                GenericType otherT => Index == otherT.Index,\n                _ => false,\n            };\n        }\n        public override bool CompatibleType(Type other)\n        {\n            // TODO (yuchen): Check assumption.\n            // Abstractors should only be compatible with themselves.\n            return other switch {\n                GenericType otherT => Index == otherT.Index,\n                _ => false,\n            };\n        }\n    }\n\n    public class UserDefinedType : Type\n    {\n        public Ident Name;\n        public List<Type> ArgumentList;\n        public AstNode TypeDeclaration = null;\n        public UserDefinedType(Ident name)\n        {\n            this.Name = name;\n            this.ArgumentList = new List<Type>();\n        }\n        public UserDefinedType(Ident name, List<Type> argumentList)\n        {\n            this.Name = name;\n            this.ArgumentList = argumentList;\n        }\n        public UserDefinedType(Ident name, List<Ident> argumentList)\n        {\n            Contract.Requires(argumentList != null);\n            this.Name = name;\n            this.ArgumentList = argumentList.ConvertAll(id => (Type)new UserDefinedType(id));\n        }\n        public override string ToString(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + Name.ToString(0, false);\n            if (ArgumentList != null && ArgumentList.Count > 0)\n            {\n                str += \"<\";\n                var sep = \"\";\n                foreach (var p in ArgumentList)\n                {\n                    str = str + sep + p.ToString(0);\n                    sep = \", \";\n                }\n                str += \">\";\n            }\n            return str;\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + Name.ToString(0, false);\n            if (ArgumentList != null && ArgumentList.Count > 0)\n            {\n                str += \"(\";\n                var sep = \"\";\n                foreach (var p in ArgumentList)\n                {\n                    str = str + sep + p.ToString(0);\n                    sep = \", \";\n                }\n                str += \")\";\n            }\n            return str;\n        }\n        public override string ToFStarLang(int indentation, bool includeObjectTD)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            if (TypeDeclaration is StructDecl) {\n                str = indentationStr + \"_user_defined_struct__\";\n                str += Name.ToString(0, false).ToLower();\n                return str;\n            }\n            str += indentationStr + (includeObjectTD ? \"ObjectTDAbstract (\" : \"\");\n            str += Name.ToString(0, false);\n            if (ArgumentList.Count > 0)\n            {\n                str += \" \" + String.Join(\" \", ArgumentList.ConvertAll(p => p.ToString(0)));\n            }\n            str += (includeObjectTD ? \")\" : \"\");\n            return str;\n        }\n        public override bool EqualType(Type other)\n        {\n            // TODO (yuchen): Is our type system nominal or structural?\n            // For now, we assume nominal.\n            return other switch {\n                UserDefinedType otherT => Name.Name == otherT.Name.Name\n                    && CompatibleType(other),\n                _ => false,\n            };\n        }\n        public override bool CompatibleType(Type other)\n        {\n            // TODO (yuchen): Same.\n            // For now, we assume nominal.\n            return other switch {\n                UserDefinedType otherT => ArgumentList.Count == otherT.ArgumentList.Count\n                    && ArgumentList\n                        .Zip(otherT.ArgumentList, (a, b) => a.EqualType(b))\n                        .All(x => x),\n                _ => false,\n            };\n        }\n    }\n\n    public abstract class CollectionType : Type\n    {\n        public Type EntityType;\n\n        public CollectionType(Type entityType)\n        {\n            this.EntityType = entityType;\n        }\n\n        public virtual string GetCollectionName()\n        {\n            return \"\";\n        }\n\n        public override string ToString(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + GetCollectionName() + \"<\";\n            str += EntityType.ToString(0);\n            str += \">\";\n            return str;\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            throw new NotSupportedException();\n        }\n        public override string ToFStarLang(int indentation, bool includeObjectTD)\n        {\n            throw new NotImplementedException();\n        }\n    }\n\n    public class SeqType : CollectionType\n    {\n        public SeqType(Type entityType)\n        : base(entityType) { }\n\n        public override string GetCollectionName()\n        {\n            return \"seq\";\n        }\n        public override string ToFStarLang(int indentation, bool includeObjectTD)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str += indentationStr;\n            if (includeObjectTD)\n            {\n                str += $\"ObjectTDAbstract (seq {EntityType.ToFStarLang(0, false)})\"; \n            }\n            else\n            {\n                str = $\"seq {EntityType.ToFStarLang(0, false)}\";\n            }\n            return str;\n        }\n        public override bool EqualType(Type other)\n        {\n            return other switch {\n                SeqType otherT => EntityType.EqualType(otherT.EntityType),\n                _ => false,\n            };\n        }\n        public override bool CompatibleType(Type other)\n        {\n            return other switch {\n                SeqType otherT => EntityType.CompatibleType(otherT.EntityType),\n                _ => false,\n            };\n        }\n    }\n\n    public class SetType : CollectionType\n    {\n        public bool IsInfinite;\n\n        public SetType(Type entityType, bool isInfinite)\n        : base(entityType)\n        {\n            this.IsInfinite = isInfinite;\n        }\n\n        public override string GetCollectionName()\n        {\n            return IsInfinite ? \"iset\" : \"set\";\n        }\n        public override string ToFStarLang(int indentation, bool includeObjectTD)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str += indentationStr;\n            string setStr = \"\";\n            if (IsInfinite)\n            {\n                setStr = $\"FStar.Set.set {EntityType.ToFStarLang(0, false)}\";\n            }\n            else\n            {\n                setStr = $\"FStar.FiniteSet.Base.set {EntityType.ToFStarLang(0, false)}\";\n            }\n            if (includeObjectTD)\n            {\n                setStr = $\"ObjectTDAbstract ({setStr})\"; \n            }\n            str += setStr;\n            return str;\n        }\n        public override bool EqualType(Type other)\n        {\n            return other switch {\n                SetType otherT => IsInfinite == otherT.IsInfinite\n                    && EntityType.EqualType(otherT.EntityType),\n                _ => false,\n            };\n        }\n        public override bool CompatibleType(Type other)\n        {\n            return other switch {\n                SetType otherT => (!IsInfinite || otherT.IsInfinite)\n                    && EntityType.CompatibleType(otherT.EntityType),\n                _ => false,\n            };\n        }\n    }\n\n    public class MapType : CollectionType\n    {\n        // For MapType, the inherited Entity is Value.\n        public bool IsInfinite;\n        public Type KeyType;\n\n        public MapType(Type keyType, Type valueType, bool isInfinite)\n        : base(valueType)\n        {\n            this.IsInfinite = isInfinite;\n            this.KeyType = keyType;\n        }\n\n        public override string GetCollectionName()\n        {\n            return IsInfinite ? \"imap\" : \"map\";\n        }\n\n        public override string ToString(int indentation)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str = str + indentationStr + GetCollectionName() + \"<\";\n            str += KeyType.ToString(0) + \", \" + EntityType.ToString(0);\n            str += \">\";\n            return str;\n        }\n        public override string ToFStarLang(int indentation, bool includeObjectTD)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str += indentationStr;\n            string typePrefix = IsInfinite ? \"FStar.Map.t\" : \"FStar.FiniteMap.Base.map\";\n            string typeStr = $\"{typePrefix} {KeyType.ToFStarLang(0, false)} {EntityType.ToFStarLang(0, false)}\";\n            if (includeObjectTD)\n            {\n                str += $\"ObjectTDAbstract ({typeStr})\"; \n            }\n            else\n            {\n                str += typeStr;\n            }\n            return str;\n        }\n        public override bool EqualType(Type other)\n        {\n            if (other is MapType mapT)\n            {\n                return IsInfinite == mapT.IsInfinite\n                    && KeyType.EqualType(mapT.KeyType)\n                    && EntityType.EqualType(mapT.EntityType);\n            }\n            return false;\n        }\n        public override bool CompatibleType(Type other)\n        {\n            if (other is MapType mapT)\n            {\n                return (!IsInfinite || mapT.IsInfinite)\n                    && KeyType.CompatibleType(mapT.KeyType)\n                    && EntityType.CompatibleType(mapT.EntityType);\n            }\n            return false;\n        }\n    }\n\n    public class TypeSuffix : PointerType\n    {\n        public Ident Size;\n\n        public TypeSuffix(Type baseType, Ident size)\n        : base(baseType)\n        {\n            this.Size = size;\n        }\n\n        public override string ToString(int indentation)\n        {\n            string str = EntityType.ToString(indentation) + \"[\" + Size.ToString(0, false) + \"]\";\n            return str;\n        }\n\n        public override string ToCProgram(int indentation)\n        {\n            string str = \"[\" + Size.ToCProgram(0) + \"]\";\n            return str;\n        }\n        public string ToArrayFStarLang()\n        {\n            return $\"ObjectTDArray ({EntityType.ToFStarLang(0, true)}) ({Size.ToString(0, false)})\";\n        }\n        public override string ToFStarLang(int indentation, bool includeObjectTD)\n        {\n            string str = \"\";\n            string indentationStr = new string(' ', indentation);\n            str += indentationStr;\n            if (!includeObjectTD)\n            {\n                throw new NotImplementedException();\n            }\n            str += ToArrayFStarLang();\n            return str;\n        }\n        public override bool EqualType(Type other)\n        {\n            if (other is TypeSuffix arrT)\n            {\n                return base.EqualType(arrT) && Size.Name == arrT.Size.Name;\n            }\n            return false;\n        }\n        public override bool CompatibleType(Type other)\n        {\n            if (other is TypeSuffix arrT)\n            {\n                return base.CompatibleType(arrT) && Size.Name == arrT.Size.Name;\n            }\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "experimental/Source/Armada/Armada.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\r\n\r\n  <Target Name=\"RunCoco\" BeforeTargets=\"PreBuildEvent\" Outputs=\"$(ProjectDir)Parser.cs;$(ProjectDir)Scanner.cs\" Inputs=\"$(ProjectDir)Starmada.atg;$(ProjectDir)../../third_party/Coco/src/Parser.frame;$(ProjectDir)../../third_party/Coco/src/Scanner.frame\">\r\n    <Exec Command=\"dotnet tool restore\" />\r\n    <Exec Command=\"dotnet --info\" />\r\n    <Exec Command=\"dotnet tool run coco $(ProjectDir)Starmada.atg -namespace Microsoft.Starmada -frames $(ProjectDir)../../third_party/Coco/src\" />\r\n    <!-- Recompute files to build according to https://stackoverflow.com/a/44829863/93197 -->\r\n    <ItemGroup>\r\n      <Compile Include=\"**/*$(DefaultLanguageSourceExtension)\" Exclude=\"$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder);$(BaseIntermediateOutputPath)**;$(BaseOutputPath)**;@(Compile)\" />\r\n    </ItemGroup>\r\n  </Target>\r\n\r\n  <PropertyGroup>\r\n    <OutputType>Exe</OutputType>\r\n    <TargetFramework>net6.0</TargetFramework>\r\n  </PropertyGroup>\r\n\r\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' \">\r\n    <OutputPath>..\\..\\Binary</OutputPath>\r\n    <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' \">\r\n    <OutputPath>..\\..\\Binary</OutputPath>\r\n    <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>\r\n  </PropertyGroup>\r\n  <ItemGroup>\r\n    <PackageReference Include=\"CommandLineParser\" Version=\"2.9.1\" />\r\n  </ItemGroup>\r\n\r\n</Project>\r\n"
  },
  {
    "path": "experimental/Source/Armada/Atomic/AtomicPrinter.cs",
    "content": "using System;\nusing System.IO;\nusing System.Linq;\nusing System.Collections.Generic;\n\nnamespace Microsoft.Starmada\n{\n    class AtomicPrinter\n    {\n        public string ToFStarAtomic(LevelDecl level, int indentation, string moduleName)\n        {\n            Func<int, string> indent = (int i) => new string(' ', indentation + i * 2);\n            string str = \"\";\n\n            str += indent(0) + $\"let atomic_actions: list (list Armada.Action.t) =\\n\";\n            str += indent(1) + \"[\\n\";\n            AtomicSpec atomicSpec = new AtomicSpec(level);\n            str += String.Join(\";\\n\", atomicSpec.Actions.ConvertAll(action => ToFStarAtomic(action, indentation + 4))) + '\\n';\n            str += indent(1) + \"]\\n\\n\";\n            str += indent(0) + \"let prog: (program_t (make_atomic_semantics armada_semantics)) =\\n\";\n            str += indent(1) + \"{\\n\";\n            str += indent(2) + $\"init_f = init_program {moduleName}.prog;\\n\";\n            str += indent(2) + \"actions = atomic_actions;\\n\";\n            str += indent(1) + \"}\\n\";\n            return str;\n        }\n\n        public string ToFStarAtomic(ExecutionPath action, int indentation)\n        {\n            Func<int, string> indent = (int i) => new string(' ', indentation + i * 2);\n            string str = \"\";\n\n            str += indent(0) + \"[\\n\";\n            for (int i = 0; i < action.Stmts.Count; i++)\n            {\n                str += ToFStarAtomic(\n                    action.Stmts[i], indentation + 2,\n                    !(action.FailAtTheEnd && i + 1 == action.Stmts.Count)\n                );\n                str += ((i + 1 == action.Stmts.Count) ? \"\" : \";\") + \"\\n\";\n            }\n            str += indent(0) + \"]\";\n            return str;\n        }\n\n        public string ToFStarAtomic(FStarStmt fstmt, int indentation, bool ok)\n        {\n            Func<int, string> indent = (int i) => new string(' ', indentation + i * 2);\n\n            string str = \"\";\n            string ok_str = ok ? \"true\" : \"false\";\n            str += indent(0) + \"{\\n\";\n            str += indent(1) + $\"ok = {ok_str};\\n\";\n            str += indent(1) + \"program_statement = \\n\";\n            str += fstmt.GetFStarCodeOfStatement(indentation + 4) + '\\n';\n            str += indent(0) + \"}\";\n            return str;\n        }\n\n        public string AtomicToRegular(LevelDecl level, int indentation)\n        {\n            AtomicSpec atomicSpec = new AtomicSpec(level);\n\n            Func<int, string> indent = (int i) => new string(' ', indentation + i * 2);\n            string str = \"\";\n            var moduleName = level.Name.ToString(0, false);\n            var moduleAtomicName = \"Atomic\" + moduleName;\n\n            str += \"let my_atomic_to_regular_map: (list (list nat)) =\\n\";\n            List<List<int>> atomicToRegularMap = atomicSpec.GetAtomicToRegularMap();\n            str += indent(1) + $\"[{String.Join(\"; \", atomicToRegularMap.ConvertAll(indices => $\"[{String.Join(\"; \", indices)}]\"))}]\" + \"\\n\\n\";\n\n            str += $\"let lemma_{moduleAtomicName}_refines_{moduleName} ()\\n\";\n            str += indent(1) + \": Lemma (ensures spec_refines_spec\\n\";\n            str += indent(10) + $\"(semantics_to_spec (make_atomic_semantics armada_semantics) {moduleAtomicName}.prog)\\n\";\n            str += indent(10) + $\"(program_to_spec {moduleName}.prog)\\n\";\n            str += indent(10) + \"eq2) =\\n\";\n            str += indent(1) + \"let aw: atomic_refines_armada_witness_t = {\\n\";\n            str += indent(2) + \"atomic_to_regular_map = my_atomic_to_regular_map;\\n\";\n            str += indent(2) + $\"actions_array = list_to_array (all_actions {moduleName}.prog.program_statements)\\n\";\n            str += indent(1) + \"} in\\n\";\n            str += indent(1) + $\"assert (atomic_refines_armada_witness_valid {moduleAtomicName}.prog {moduleName}.prog aw)\\n\";\n            str += indent(2) + \"by (FStar.Tactics.compute (); FStar.Tactics.trivial ());\\n\";\n            str += indent(1) + $\"atomic_refines_armada_witness_valid_implies_refinement {moduleAtomicName}.prog {moduleName}.prog aw\\n\";\n\n            return str;\n        }\n\n        public string MakePCIndexStarter(int indentation)\n        {\n            Func<int, string> indent = (int i) => new string(' ', indentation + i * 2);\n            string str = \"\";\n            str += indent(0) + \"let make_none_pc_indices: statement_pc_indices_t =\\n\";\n            str += indent(1) + \"{\\n\";\n            str += indent(2) + \"start_pc_index = None;\\n\";\n            str += indent(2) + \"end_pc_index = None;\\n\";\n            str += indent(2) + \"create_thread_initial_pc_index = None;\\n\";\n            str += indent(2) + \"method_call_return_pc_index = None;\\n\";\n            str += indent(1) + \"}\\n\\n\";\n\n            str += indent(0) + \"let make_pc_indices (start_pc_index: nat) (end_pc_index: nat) : statement_pc_indices_t =\\n\";\n            str += indent(1) + \"{\\n\";\n            str += indent(2) + \"start_pc_index = Some start_pc_index;\\n\";\n            str += indent(2) + \"end_pc_index = Some end_pc_index;\\n\";\n            str += indent(2) + \"create_thread_initial_pc_index = None;\\n\";\n            str += indent(2) + \"method_call_return_pc_index = None;\\n\";\n            str += indent(1) + \"}\\n\\n\";\n\n            str += indent(0) + \"let make_terminating_pc_indices (start_pc_index: nat) : statement_pc_indices_t =\\n\";\n            str += indent(1) + \"{\\n\";\n            str += indent(2) + \"start_pc_index = Some start_pc_index;\\n\";\n            str += indent(2) + \"end_pc_index = None;\\n\";\n            str += indent(2) + \"create_thread_initial_pc_index = None;\\n\";\n            str += indent(2) + \"method_call_return_pc_index = None;\\n\";\n            str += indent(1) + \"}\\n\\n\";\n\n            str += indent(0) + \"let make_method_call_pc_indices (start_pc_index: nat) (end_pc_index: nat) (method_call_return_pc_index: nat) : statement_pc_indices_t =\\n\";\n            str += indent(1) + \"{\\n\";\n            str += indent(2) + \"start_pc_index = Some start_pc_index;\\n\";\n            str += indent(2) + \"end_pc_index = Some end_pc_index;\\n\";\n            str += indent(2) + \"create_thread_initial_pc_index = None;\\n\";\n            str += indent(2) + \"method_call_return_pc_index = Some method_call_return_pc_index;\\n\";\n            str += indent(1) + \"}\\n\\n\";\n\n            str += indent(0) + \"let make_create_thread_pc_indices (start_pc_index: nat) (end_pc_index: nat) (create_thread_pc_index: nat) : statement_pc_indices_t =\\n\";\n            str += indent(1) + \"{\\n\";\n            str += indent(2) + \"start_pc_index = Some start_pc_index;\\n\";\n            str += indent(2) + \"end_pc_index = Some end_pc_index;\\n\";\n            str += indent(2) + \"create_thread_initial_pc_index = Some create_thread_pc_index;\\n\";\n            str += indent(2) + \"method_call_return_pc_index = None;\\n\";\n            str += indent(1) + \"}\\n\\n\";\n            return str;\n        }\n\n        public string MakePCIndex(AtomicSpec atomicSpec, FStarStmt fstmt)\n        {\n            string str = \"\";\n            if (fstmt.StartPC == null && fstmt.EndPC == null)\n            {\n                str += $\"make_none_pc_indices\"; \n                return str;\n            }\n            int startPCIndex = atomicSpec.PC2Index[fstmt.StartPC];\n            if (fstmt.EndPC == null) {\n                str += $\"make_terminating_pc_indices {startPCIndex}\";\n                return str;\n            }\n            int endPCIndex = atomicSpec.PC2Index[fstmt.EndPC];\n            if (fstmt.Statement.StartsWith(\"MethodCallStatement\"))\n            {\n                string returnPC = fstmt.Statement.Split(' ')[2];\n                returnPC = returnPC.TrimEnd('\"').TrimStart('\"');\n                int methodCallReturnPCIndex = atomicSpec.PC2Index[returnPC];\n                str += $\"make_method_call_pc_indices {startPCIndex} {endPCIndex} {methodCallReturnPCIndex}\";\n            }\n            else if (fstmt.Statement.StartsWith(\"CreateThreadStatement\"))\n            {\n                string initPC = fstmt.Statement.Split(' ')[2];\n                initPC = initPC.TrimEnd('\"').TrimStart('\"');\n                int createThreadPCIndex = atomicSpec.PC2Index[initPC];\n                str += $\"make_create_thread_pc_indices {startPCIndex} {endPCIndex} {createThreadPCIndex}\";\n            }\n            else\n            {\n                str += $\"make_pc_indices {startPCIndex} {endPCIndex}\";\n            }\n            return str;\n        }\n\n        public string RegularToAtomic(LevelDecl level, int indentation)\n        {\n            AtomicSpec atomicSpec = new AtomicSpec(level);\n\n            Func<int, string> indent = (int i) => new string(' ', indentation + i * 2);\n            string str = \"\";\n            var moduleName = level.Name.ToString(0, false);\n            var moduleAtomicName = \"Atomic\" + moduleName;\n\n            string pcList = $\"[{String.Join(\"; \", atomicSpec.PCs.ConvertAll(pc => $\"\\\"{pc}\\\"\"))}]\";\n            str += $\"let my_lpcs: array_t pc_t = list_to_array {pcList}\\n\\n\";\n\n            str += $\"let my_lprog_main_start_pc_index = {atomicSpec.GetStartIndex()}\\n\\n\";\n\n            str += $\"let my_pc_index_breaking : array_t bool = list_to_array {atomicSpec.GetBreakPCList()}\\n\\n\";\n\n            str += MakePCIndexStarter(0);\n\n            str += $\"let my_pc_indices_array: array_t statement_pc_indices_t = list_to_array\\n\";\n            str += indent(1) + \"[\\n\";\n            foreach (var fstmt in atomicSpec.Fstmts)\n            {\n                string pcIndex = MakePCIndex(atomicSpec, fstmt);\n                str += indent(2) + pcIndex + \";\\n\";\n                str += indent(2) + pcIndex + \";\\n\";\n            }\n            str += indent(1) + \"]\\n\\n\";\n\n            List<string> actionIndicesNoPC = new();\n            for (int i = 0; i < atomicSpec.Actions.Count; i++)\n            {\n                var action = atomicSpec.Actions[i];\n                if (action.Stmts[0].StartPC == null)\n                {\n                    actionIndicesNoPC.Add($\"{i}\");\n                }\n            }\n            str += $\"let my_action_indices_starting_at_no_pc: list nat = [{string.Join(\"; \", actionIndicesNoPC)}]\\n\\n\";\n\n            str += $\"let my_action_indices_starting_at_pc_index: array_t (list nat) = list_to_array\\n\";\n            str += indent(1) + \"[\\n\";\n            foreach (var kv in atomicSpec.PC2Stmt)\n            {\n                var fstmts = kv.Value;\n                List<int> indices = new();\n                foreach (var fstmt in fstmts)\n                {\n                    indices.Add(atomicSpec.GetFstmtIndex(fstmt, true));\n                    indices.Add(atomicSpec.GetFstmtIndex(fstmt, false));\n                }\n                str += indent(2) + $\"[{String.Join(\"; \", indices)}];\\n\";\n                \n            }\n            str += indent(1) + \"]\\n\\n\";\n\n            str += \"let make_successor_info (action_index: nat) (path_index: nat) : armada_successor_info_t =\\n\";\n            str += indent(1) + \"{\\n\";\n            str += indent(2) + \"action_index = action_index;\\n\";\n            str += indent(2) + \"path_index = path_index;\\n\";\n            str += indent(1) + \"}\\n\\n\";\n\n            str += \"let make_breaking_atomic_path_info (path: list nat) (atomic_action_index: nat) : armada_atomic_path_info_t =\\n\";\n            str += indent(1) + \"{\\n\";\n            str += indent(2) + \"path = path;\\n\";\n            str += indent(2) + \"atomic_action_index_or_successors = Inl atomic_action_index;\\n\";\n            str += indent(1) + \"}\\n\\n\";\n\n            str += \"let make_incomplete_atomic_path_info (path: list nat) (successors: list armada_successor_info_t) =\\n\";\n            str += indent(1) + \"{\\n\";\n            str += indent(2) + \"path = path;\\n\";\n            str += indent(2) + \"atomic_action_index_or_successors = Inr successors;\\n\";\n            str += indent(1) + \"}\\n\\n\";\n\n            str += $\"let my_atomic_path_infos: array_t armada_atomic_path_info_t = list_to_array\\n\";\n            str += indent(1) + \"[\\n\";\n            List<string> pathInfos = atomicSpec.GetAtomicPathInfo();\n            foreach (string pathInfo in pathInfos)\n            {\n                str += indent(2) + pathInfo + '\\n';\n            }\n            str += indent(1) + \"]\\n\\n\";\n\n            str += $\"let my_singleton_path_indices: array_t (option nat) = list_to_array\\n\";\n            str += indent(1) + \"[\\n\";\n            List<int> singleton = atomicSpec.GetSingletonPathIndices();\n            foreach (var index in singleton)\n            {\n                str += indent(2) + (index == -1 ? \"None\" : $\"Some {index}\") + \";\\n\";\n            }\n            str += indent(1) + \"]\\n\\n\";\n\n            str += $\"let lemma_{moduleName}_refines_{moduleAtomicName} ()\\n\";\n            str += indent(1) + \": Lemma (ensures spec_refines_spec\\n\";\n            str += indent(10) + $\"(program_to_spec {moduleName}.prog)\\n\";\n            str += indent(10) + $\"(semantics_to_spec (make_atomic_semantics armada_semantics) {moduleAtomicName}.prog)\\n\";\n            str += indent(10) + \"eq2) =\\n\";\n            str += indent(1) + $\"let lprog = {moduleName}.prog in\\n\";\n            str += indent(1) + $\"let hprog = {moduleAtomicName}.prog in\\n\";\n            str += indent(1) + \"let aw: armada_refines_atomic_witness_t = {\\n\";\n            str += indent(2) + \"pc_index_breaking = my_pc_index_breaking;\\n\";\n            str += indent(2) + \"pc_indices_array = my_pc_indices_array;\\n\";\n            str += indent(2) + \"action_indices_starting_at_no_pc = my_action_indices_starting_at_no_pc;\\n\";\n            str += indent(2) + \"action_indices_starting_at_pc_index = my_action_indices_starting_at_pc_index;\\n\";\n            str += indent(2) + \"atomic_path_infos = my_atomic_path_infos;\\n\";\n            str += indent(2) + \"singleton_path_indices = my_singleton_path_indices;\\n\";\n            str += indent(2) + \"lpcs = my_lpcs;\\n\";\n            str += indent(2) + \"lprog_main_start_pc_index = my_lprog_main_start_pc_index;\\n\";\n            str += indent(2) + \"lprog_actions_array = list_to_array (all_actions lprog.program_statements);\\n\";\n            str += indent(2) + \"hprog_actions_array = list_to_array hprog.actions;\\n\";\n            str += indent(1) + \"} in\\n\";\n            str += indent(1) + $\"assert (armada_refines_atomic_witness_valid {moduleName}.prog {moduleAtomicName}.prog aw)\\n\";\n            str += indent(2) + \"by (FStar.Tactics.compute (); FStar.Tactics.trivial ());\\n\";\n            str += indent(1) + $\"armada_refines_atomic_witness_valid_implies_refinement {moduleName}.prog {moduleAtomicName}.prog aw\";\n\n            return str;\n        }\n    }\n}\n"
  },
  {
    "path": "experimental/Source/Armada/Atomic/AtomicSpec.cs",
    "content": "using System;\nusing System.Linq;\nusing System.Collections.Generic;\nusing System.Diagnostics.Contracts;\nusing System.Diagnostics;\n\nnamespace Microsoft.Starmada\n{\n    public class ExecutionPath\n    {\n        public bool FailAtTheEnd;\n        public List<FStarStmt> Stmts;\n\n        public ExecutionPath(bool failAtEnd, List<FStarStmt> stmts)\n        {\n            FailAtTheEnd = failAtEnd;\n            Stmts = stmts;\n        }\n    }\n    public class ExecutionPathScheme\n    {\n        public List<FStarStmt> Stmts;\n        public List<ExecutionPath> Paths;\n        public ExecutionPathScheme(List<FStarStmt> stmts)\n        {\n            Stmts = new List<FStarStmt>(stmts);\n            Debug.Assert(Stmts.Count != 0);\n        }\n        public ExecutionPathScheme(FStarStmt stmt)\n        {\n            Stmts = new List<FStarStmt>();\n            Stmts.Add(stmt);\n        }\n        public List<ExecutionPath> IterateStatements()\n        {\n            if (Paths == null)\n            {\n                Paths = new List<ExecutionPath>();\n                Paths.Add(new ExecutionPath(false, Stmts));\n                for (int i = 1; i <= Stmts.Count; i++)\n                {\n                    List<FStarStmt> fstmts = Stmts.Take(i).ToList();\n                    Paths.Add(new ExecutionPath(true, fstmts));\n                }\n            }\n            return Paths;\n        }\n    }\n\n    public class AtomicSpec\n    {\n        public string MainStartPC;\n        public List<FStarStmt> Fstmts { get; set; } = null;\n        public Dictionary<FStarStmt, int> StmtIndex { get; set; } = null;\n        public List<ExecutionPathScheme> Sequences { get; set; } = null;\n        public List<List<int>> AtomicToRegularMap { get; set; } = null;\n        public List<List<int>> AtomicPathInfo { get; set; } = null;\n        public Dictionary<string, List<FStarStmt>> PC2Stmt { get; set; } = null;\n        public List<string> PCs { get; set; } = null;\n        public Dictionary<string, int> PC2Index { get; set; } = null;\n        public List<ExecutionPath> Actions { get; set; } = null;\n        public HashSet<string> NormalBreakPoints { get; set; } = null;\n        public HashSet<string> LoopBreakPoints { get; set; } = null;\n\n\n        public AtomicSpec(LevelDecl level)\n        {\n            MainStartPC = level.MainStartPC;\n            // Initialize Fstmts, Sequences, NormalBreakPoints\n            if (Fstmts is null)\n            {\n                Fstmts = new();\n                Fstmts.Add(new FStarStmt(null, null, true, true, \"PropagateWriteMessageStatement\"));\n                foreach (MemberDecl member in level.Members)\n                {\n                    if (member is MethodDecl method)\n                    {\n                        Fstmts.AddRange(method.FStarStmts);\n                    }\n                }\n            }\n            if (StmtIndex is null)\n            {\n                StmtIndex = new();\n                for (int i = 0; i < Fstmts.Count; i++)\n                {\n                    StmtIndex[Fstmts[i]] = i * 2;\n                }\n            }\n            if (Sequences is null)\n            {\n                Sequences = new();\n                Sequences.Add(new ExecutionPathScheme(Fstmts[0]));\n                Sequences.AddRange(StatementsToPathSchemes(Fstmts));\n            }\n            if (Actions is null)\n            {\n                Actions = new();\n                foreach (ExecutionPathScheme sequence in Sequences)\n                {\n                    Actions.AddRange(sequence.IterateStatements());\n                }\n            }\n            if (PCs is null)\n            {\n                PCs = new();\n                PC2Index = new();\n                int i = 0;\n                foreach (var kv in PC2Stmt)\n                {\n                    PCs.Add(kv.Key);\n                    PC2Index[kv.Key] = i++;\n                }\n            }\n        }\n\n        public IEnumerable<ExecutionPathScheme> GetExecutionPathSchemes()\n        {\n            return Sequences;\n        }\n\n        public IEnumerable<ExecutionPathScheme> StatementsToPathSchemes(List<FStarStmt> fstmts)\n        {\n            List<ExecutionPathScheme> sequences = new();\n            PC2Stmt = new();\n            List<FStarStmt> path = new List<FStarStmt>();\n            LoopBreakPoints = new();\n            NormalBreakPoints = new();\n            NormalBreakPoints.Add(MainStartPC);\n            HashSet<string> discoveredPCs = new();\n            foreach (FStarStmt fstmt in fstmts)\n            {\n                string PC = fstmt.StartPC;\n                if (PC == null)\n                    continue;\n                if (!PC2Stmt.ContainsKey(PC))\n                {\n                    PC2Stmt[PC] = new List<FStarStmt>();\n                }\n                if (fstmt.EndPC != null && !PC2Stmt.ContainsKey(fstmt.EndPC))\n                {\n                    PC2Stmt[fstmt.EndPC] = new List<FStarStmt>();\n                }\n                PC2Stmt[PC].Add(fstmt);\n            }\n            // First traversal, finding the break points\n            discoveredPCs.Add(MainStartPC);\n            foreach (FStarStmt fstmt in PC2Stmt[MainStartPC])\n            {\n                path.Clear();\n                findBreakPoints(fstmt);\n            }\n            discoveredPCs.Clear();\n            discoveredPCs.Add(MainStartPC);\n            // Second traversal, generate atomic sequences according to additional break points\n            foreach (FStarStmt fstmt in PC2Stmt[MainStartPC])\n            {\n                path.Clear();\n                dfs(fstmt);\n            }\n            return sequences;\n\n            void findBreakPoints(FStarStmt fstmt)\n            {\n                if (fstmt.EndsAtomicBlock)\n                {\n                    if (discoveredPCs.Contains(fstmt.EndPC))\n                        return;\n                    discoveredPCs.Add(fstmt.EndPC);\n                    List<FStarStmt> savedPath = new(path);\n                    foreach (FStarStmt nextStmt in PC2Stmt[fstmt.EndPC])\n                    {\n                        // Deal with MethodCallStatement with stack_overflow true\n                        if (nextStmt.StartsAtomicBlock) {\n                            path.Clear();\n                            findBreakPoints(nextStmt);\n                        }\n                    }\n                    path = savedPath;\n                }\n                path.Add(fstmt);\n                if (path.ConvertAll(fstmt => fstmt.StartPC).Contains(fstmt.EndPC)) // find backedge\n                {\n                    LoopBreakPoints.Add(fstmt.EndPC);\n                }\n                else\n                {\n                    List<FStarStmt> nextStmts = PC2Stmt[fstmt.EndPC];\n                    Contract.Requires(nextStmts.Count > 0);\n                    foreach (FStarStmt nextStmt in nextStmts)\n                    {\n                        findBreakPoints(nextStmt);\n                    }\n                }\n                path.RemoveAt(path.Count - 1);\n                return;\n            }\n\n            void dfs(FStarStmt fstmt)\n            {\n                path.Add(fstmt);\n                if (fstmt.EndsAtomicBlock)\n                {\n                    sequences.Add(new ExecutionPathScheme(path));\n                    if (discoveredPCs.Contains(fstmt.EndPC))\n                        return;\n                    discoveredPCs.Add(fstmt.EndPC);\n                    NormalBreakPoints.Add(fstmt.EndPC);\n                    List<FStarStmt> savedPath = new(path);\n                    foreach (FStarStmt nextStmt in PC2Stmt[fstmt.EndPC])\n                    {\n                        if (nextStmt.StartsAtomicBlock) {\n                            path.Clear();\n                            dfs(nextStmt);\n                        }\n                    }\n                    path = savedPath;\n                }\n                else if (LoopBreakPoints.Contains(fstmt.EndPC))\n                {\n                    if (path.ConvertAll(fstmt => fstmt.StartPC).Contains(fstmt.EndPC)) // loop backedge\n                    {\n                        sequences.Add(new ExecutionPathScheme(path));\n                    }\n                    else\n                    {\n                        List<FStarStmt> savedPath = new List<FStarStmt>(path);\n                        sequences.Add(new ExecutionPathScheme(path));\n                        foreach (FStarStmt nextStmt in PC2Stmt[fstmt.EndPC])\n                        {\n                            path.Clear();\n                            dfs(nextStmt);\n                        }\n                        path = savedPath;\n                    }\n                }\n                else\n                {\n                    List<FStarStmt> nextStmts = PC2Stmt[fstmt.EndPC];\n                    Contract.Requires(nextStmts.Count > 0);\n                    foreach (FStarStmt nextStmt in nextStmts)\n                    {\n                        dfs(nextStmt);\n                    }\n                }\n                path.RemoveAt(path.Count - 1);\n                return;\n            }\n        }\n\n        public int GetFstmtIndex(FStarStmt fstmt, bool ok)\n        {\n            return StmtIndex[fstmt] + (ok ? 0 : 1);\n        }\n        public List<int> GetActionIndices(ExecutionPath action)\n        {\n            List<int> indices = new();\n            foreach (FStarStmt fstmt in action.Stmts)\n            {\n                indices.Add(GetFstmtIndex(fstmt, true));\n            }\n            if (action.FailAtTheEnd)\n            {\n                indices[indices.Count - 1]  += 1;\n            }\n            return indices;\n        }\n\n        public List<List<int>> GetAtomicToRegularMap()\n        {\n            // [[0]; [1]; [2; 4; 6]; [3]; [2; 5]; [2; 4; 7]; [8]; [9]]\n            List<List<int>> atomicToRegularMap = new();\n            foreach (var action in Actions)\n            {\n                atomicToRegularMap.Add(GetActionIndices(action));\n            }\n            return atomicToRegularMap;\n        }\n\n        public int GetMapIndex(List<int> indices)\n        {\n            if (AtomicToRegularMap is null)\n            {\n                AtomicToRegularMap = GetAtomicToRegularMap();\n            }\n            for (int i = 0; i < AtomicToRegularMap.Count; i++)\n            {\n                if (indices.SequenceEqual(AtomicToRegularMap[i]))\n                {\n                    return i;\n                }\n            }\n            return -1;\n        }\n\n        public List<string> GetAtomicPathInfo()\n        {\n            List<string> pathInfos = new();\n            AtomicPathInfo = new();\n            foreach (var sequence in Sequences)\n            {\n                var allfstmts = sequence.Stmts;\n                for (int i = 1; i <= allfstmts.Count; i++)\n                {\n                    List<FStarStmt> fstmts = allfstmts.Take(i).ToList();\n                    var okPath = new ExecutionPath(false, fstmts);\n                    var failPath = new ExecutionPath(true, fstmts);\n\n                    // ok == true\n                    var okIndices = GetActionIndices(okPath);\n                    AtomicPathInfo.Add(okIndices);\n                    if (i == allfstmts.Count)\n                    {\n                        pathInfos.Add($\"make_breaking_atomic_path_info [{String.Join(\"; \", okIndices)}] {GetMapIndex(okIndices)};\");\n                    }\n                    else\n                    {\n                        var nextStmt = allfstmts[i];\n                        int k = pathInfos.Count;\n                        pathInfos.Add($\"make_incomplete_atomic_path_info [{String.Join(\"; \", okIndices)}] [make_successor_info {GetFstmtIndex(nextStmt, true)} {k + 2}; make_successor_info {GetFstmtIndex(nextStmt, false)} {k + 3}];\");\n                    }\n                    // ok == false\n                    var indices = GetActionIndices(failPath);\n                    AtomicPathInfo.Add(indices);\n                    pathInfos.Add($\"make_breaking_atomic_path_info [{String.Join(\"; \", indices)}] {GetMapIndex(indices)};\");\n                }\n            }\n            return pathInfos;\n        }\n\n        public List<int> GetSingletonPathIndices()\n        {\n            List<int> singleton = new();\n            for (int i = 0; i < Fstmts.Count * 2; i++)\n            {\n                bool found = false;\n                for (int j = 0; j < AtomicPathInfo.Count; j++)\n                {\n                    if (AtomicPathInfo[j].Count == 1 && AtomicPathInfo[j][0] == i)\n                    {\n                        found = true;\n                        singleton.Add(j);\n                        break;\n                    }\n                }\n                if (!found)\n                {\n                    singleton.Add(-1);\n                }\n            }\n            return singleton;\n        }\n\n        public int GetStartIndex()\n        {\n            return PC2Index[MainStartPC];\n        }\n\n        public string GetNonYieldingPCList()\n        {\n            return $\"[{String.Join(\"; \", PCs.ConvertAll(pc => (!NormalBreakPoints.Contains(pc)).ToString().ToLower()))}]\";\n        }\n        public string GetBreakPCList()\n        {\n            return $\"[{String.Join(\"; \", PCs.ConvertAll(pc => (NormalBreakPoints.Contains(pc) || LoopBreakPoints.Contains(pc)).ToString().ToLower()))}]\";\n        }\n        public delegate string StmtToString<Stmt>(Stmt stmt, int index, int indentation);\n        public static string BinarySearchGen<Stmt>(List<Stmt> seq, StmtToString<Stmt> fmt, int indentation = 0)\n        {\n            return BinarySearchGen<Stmt>(seq, fmt, indentation, 0, seq.Count);\n        }\n        public static string BinarySearchGen<Stmt>(List<Stmt> seq, StmtToString<Stmt> fmt, int indentation, int a, int b)\n        {\n            string indent = new string(' ', indentation);\n            string str = \"\";\n            Debug.Assert(a <= b);\n            if (a == b) { }\n            else if (a + 1 == b)\n            {\n                str += $\"{fmt(seq[a], a, indentation)}\";\n            }\n            else\n            {\n                var l = BinarySearchGen(seq, fmt, indentation + 2, a, (a + b + 1) / 2);\n                var r = BinarySearchGen(seq, fmt, indentation + 2, (a + b + 1) / 2, b);\n                str += $\"{indent}if n < {(a + b + 1) / 2} then (\\n{l}\\n{indent}) else (\\n{r}\\n{indent})\";\n            }\n            return str;\n        }\n    }\n}"
  },
  {
    "path": "experimental/Source/Armada/IncludeProcessor.cs",
    "content": "\nusing System;\nusing System.IO;\nusing System.Collections;\nusing System.Collections.Generic;\n\nnamespace Microsoft.Starmada {\n    public class IncludeProcessor {\n        string inputFile;\n\n        HashSet<string> seenFiles;\n\n        public IncludeProcessor(string inputFile) {\n            seenFiles = new HashSet<string>();\n            this.inputFile = inputFile;\n        }\n\n        public string processIncludes() {\n            Queue<string> includeFiles = new Queue<string>();\n            includeFiles.Enqueue(inputFile);\n            seenFiles.Add(inputFile);\n            string workingDir = inputFile.Substring(0, inputFile.LastIndexOf(\"/\") + 1);\n\n            string outputFilename = Path.GetTempFileName();\n            StreamWriter sw = File.AppendText(outputFilename);\n\n            while (includeFiles.Count > 0) {\n                string currFile = includeFiles.Dequeue();\n                Scanner scanner = new Scanner(currFile);\n\n                Token tok = scanner.Peek();\n                int lastPos = 0;\n                while (tok.val == \"include\") {\n                    string nextFilename = scanner.Peek().val;\n                    string nextFile = workingDir + nextFilename.Substring(1, nextFilename.Length-2);\n                    if (!seenFiles.Contains(nextFile)) {\n                        includeFiles.Enqueue(nextFile);\n                    }\n                    seenFiles.Add(nextFile);\n                    lastPos = (int)scanner.buffer.Pos;\n                    tok = scanner.Peek();\n                }\n                string fileContent = File.ReadAllText(currFile);\n                sw.Write(scanner.buffer.GetString(lastPos, fileContent.Length));\n            }\n            sw.Close();\n            return outputFilename;\n        }\n    }\n}"
  },
  {
    "path": "experimental/Source/Armada/Program.cs",
    "content": "﻿using System;\nusing System.IO;\nusing System.Linq;\nusing System.Collections.Generic;\nusing Microsoft.Starmada;\nusing CommandLine;\n\nusing CommandLineParser = CommandLine.Parser;\nusing StarmadaParser = Microsoft.Starmada.Parser;\n\nnamespace Starmada\n{\n    class Program\n    {\n        public class Options\n        {\n            [Option('v', \"verbose\", Required = false, HelpText = \"Set output to verbose messages.\")]\n            public bool Verbose { get; set; }\n\n            [Option('c', \"ccode\", Required = false, HelpText = \"Print emitted C output.\")]\n            public bool CCode { get; set; }\n\n            [Option('f', \"fstar\", Required = false, HelpText = \"Print emitted FStar output.\")]\n            public bool FStarCode { get; set; }\n\n            [Option('a', \"atomic\", Required = false, HelpText = \"Print emitted FStar atomic output.\")]\n            public bool AtomicCode { get; set; }\n\n            [Value(0, Required = true, MetaName = \"input_file\", HelpText = \"Input file.\")]\n            public IEnumerable<string> InputFiles { get; set; }\n        }\n\n        static void Main(string[] args)\n        {\n            CommandLineParser.Default.ParseArguments<Options>(args).WithParsed<Options>(o =>\n            {\n                foreach (var inputFile in o.InputFiles)\n                {\n                    IncludeProcessor ip = new IncludeProcessor(inputFile);\n                    string includeFile = ip.processIncludes();\n\n                    Scanner scanner = new Scanner(includeFile);\n                    StarmadaParser p = new StarmadaParser(scanner, inputFile);\n                    p.Parse();\n                    if (p.errors.ErrorCount > 0)\n                    {\n                        Console.WriteLine($\"program has {p.errors.ErrorCount} parse errors\");\n                        Environment.ExitCode = -1;\n                        return;\n                    }\n\n                    if (o.CCode)\n                    {\n                        var cCodeOutputPath = Path.GetDirectoryName(inputFile) + \"/\" + Path.GetFileNameWithoutExtension(inputFile) + \".c\";\n                        System.IO.File.WriteAllText(cCodeOutputPath, p.program.ToCProgram(0));\n                    }\n\n                    p.program.SetProgramCounter(\"\", 0);\n                    Resolver resolver = new Resolver();\n                    resolver.Resolve(p.program);\n                    ProofResolver proofResolver = new();\n                    proofResolver.Resolve(p.program);\n\n                    if (o.Verbose)\n                    {\n                        Console.WriteLine(p.program.ToString(0, true));\n                    }\n\n                    if (p.errors.ErrorCount > 0)\n                    {\n                        Console.WriteLine($\"program has {p.errors.ErrorCount} type resolution errors\");\n                        Environment.ExitCode = -1;\n                        return;\n                    }\n\n                    var Capitalized = (string s) => char.ToUpper(s[0]) + s.Substring(1);\n\n                    var fstarOutputPath = Path.GetDirectoryName(inputFile) + \"/\";\n                    var globalDeclFileName = Capitalized(Path.GetFileNameWithoutExtension(inputFile));\n\n                    var GetOpenModules = (List<string> moduleNames) =>\n                        String.Join(\"\", moduleNames.Select(s => $\"open {s}\\n\"));\n\n                    if (o.FStarCode || o.AtomicCode)\n                    {\n                        System.IO.File.WriteAllText(Path.Combine(fstarOutputPath, globalDeclFileName + \".fst\"), p.program.ToFStarLang(0));\n                        foreach (var level in p.program.Levels)\n                        {\n                            var moduleName = Capitalized(level.Name.ToString(0, false));\n                            var header = Printer.GetFStarHeaderForModule(moduleName);\n                            header += GetOpenModules(new() { globalDeclFileName });\n                            var levelStr = level.ToFStarLang(0) + \"\\n\";\n                            System.IO.File.WriteAllText(fstarOutputPath + moduleName + \".fst\", header + '\\n' + levelStr);\n                        }\n                    }\n\n                    if (o.AtomicCode)\n                    {\n                        var atomicPrinter = new AtomicPrinter();\n                        var proofPrinter = new ProofPrinter();\n                        foreach (var level in p.program.Levels)\n                        {\n                            var levelName = Capitalized(level.Name.ToString(0, false));\n                            var moduleName = \"Atomic\" + levelName;\n                            var header = Printer.GetFStarHeaderForModule(moduleName);\n                            header += Printer.GetFStarAtomicHeader();\n                            header += GetOpenModules(new() { globalDeclFileName, levelName });\n                            var levelStr = atomicPrinter.ToFStarAtomic(level, 0, levelName) + \"\\n\";\n                            System.IO.File.WriteAllText(fstarOutputPath + moduleName + \".fst\", header + '\\n' + levelStr);\n                            foreach (var (name, body) in proofPrinter.GetProofs(level, 0)) {\n                                System.IO.File.WriteAllText(fstarOutputPath + name + \".fst\", body);\n                            }\n                        }\n\n                        LevelDecl L = proofResolver.GetLLevel();\n                        LevelDecl H = proofResolver.GetHLevel();\n                        if (L != null)\n                        {\n                            var moduleName = Capitalized(L.Name.ToString(0, false));\n                            moduleName = \"RegularToAtomicRefinement\" + moduleName;\n                            var header = Printer.GetFStarHeaderForModule(moduleName);\n                            header += Printer.GetFStarAtomicHeader();\n                            var bodyStr = atomicPrinter.RegularToAtomic(L, 0) + \"\\n\";\n                            System.IO.File.WriteAllText(fstarOutputPath + moduleName + \".fst\", header + '\\n' + bodyStr);\n                        }\n                        if (H != null)\n                        {\n                            var moduleName = Capitalized(H.Name.ToString(0, false));\n                            moduleName = \"AtomicToRegularRefinement\" + moduleName;\n                            var header = Printer.GetFStarHeaderForModule(moduleName);\n                            header += Printer.GetFStarAtomicHeader();\n                            var bodyStr = atomicPrinter.AtomicToRegular(H, 0) + \"\\n\";\n                            System.IO.File.WriteAllText(fstarOutputPath + moduleName + \".fst\", header + '\\n' + bodyStr);\n                        }\n\n                        foreach (var proof in proofResolver.ProofRefinements)\n                        {\n                            LevelDecl low = proofResolver.Levels[proof.LLevelName.Name];\n                            LevelDecl high = proofResolver.Levels[proof.HLevelName.Name];\n                            var moduleNameLow = Capitalized(low.Name.ToString(0, false));\n                            var moduleNameHigh = Capitalized(high.Name.ToString(0, false));\n                            foreach (var (name, body) in proofPrinter.GetProofs(proof, low, high, 0)) {\n                                System.IO.File.WriteAllText(fstarOutputPath + name + \".fst\", body);\n                            }\n                        }\n                    }\n                }\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "experimental/Source/Armada/Proof/InvariantPrinter.cs",
    "content": "using System;\nusing System.IO;\nusing System.Linq;\nusing System.Collections.Generic;\n\nnamespace Microsoft.Starmada\n{\n    class InvariantPrinter\n    {\n        public static string GetProof(LevelDecl Level, InvariantDecl Inv, int indentation) {\n            switch (Inv.InvType) {\n                case InvariantType.MAINTAINED_IF_STATEMENT_SATISFIES:\n                    return GetInvMaintainedIfStatementSatistiesProof(Level, Inv.Body, indentation);\n                case InvariantType.MAINTAINED_IF_VARS_UNCHANGED:\n                    return GetInvMaintainedIfVariablesUnchangedProof(Level, Inv.UnchangedVars, Inv.Body, indentation);\n                default:\n                    throw new NotSupportedException();\n            }\n        }\n        public static string GetInvMaintainedIfStatementSatistiesProof(\n            LevelDecl Level, Expr invariant, int indentation)\n        {\n            Func<int, string> indent = (int i) => new string(' ', indentation + i * 2);\n            string str = \"\";\n            var LevelName = Level.Name.ToString(0, false);\n            var LevelAtomicName = \"Atomic\" + LevelName;\n            Scope sc = Level.Sc;\n            var LevelSpec = new AtomicSpec(Level);\n\n            str += indent(0) + $\"let my_inv (s: Armada.State.t) : GTot ubool = {invariant.ToFStarExpr(\"s\")}\\n\\n\";\n\n            str += indent(0) + $\"private let my_action_pred (action: Armada.Action.t) : GTot ubool = True\\n\\n\";\n\n            str += indent(0) + \"#push-options \\\"--z3rlimit 10 --z3cliopt smt.qi.eager_threshold=100\\\"\\n\\n\";\n\n            str += indent(0) + \"private let atomic_lprog_init_establishes_my_inv\\n\";\n            str += indent(1) + $\"(s: Armada.State.t{{(semantics_to_spec (make_atomic_semantics armada_semantics) {LevelAtomicName}.prog).init s}})\\n\";\n            str += indent(1) + \": squash (my_inv s) =\\n\";\n            str += indent(1) + \"()\\n\\n\";\n\n            str += indent(0) + \"private let my_action_pred_preserves_my_inv\\n\";\n            str += indent(1) + \"(actor: tid_t)\\n\";\n            str += indent(1) + \"(starts_atomic_block: bool)\\n\";\n            str += indent(1) + \"(ends_atomic_block: bool)\\n\";\n            str += indent(1) + \"(step: Armada.Step.t)\\n\";\n            str += indent(1) + \"(s: Armada.State.t{\\n\";\n            str += indent(2) + \"Some? (step_computation actor starts_atomic_block ends_atomic_block step s)\\n\";\n            str += indent(2) + \"/\\\\ my_action_pred step.action\\n\";\n            str += indent(2) + \"/\\\\ my_inv s})\\n\";\n            str += indent(1) + \": squash (my_inv (Some?.v (step_computation actor starts_atomic_block ends_atomic_block step s))) =\\n\";\n            str += indent(1) + \"()\\n\\n\";\n\n            str += indent(0) + \"#pop-options\\n\\n\";\n\n            str += indent(0) + \"private let my_special_case_proofs\\n\";\n            str += indent(1) + \": list (option (armada_atomic_special_case_invariant_proof_t my_inv)) =\\n\";\n            str += indent(1) + \"[\\n\";\n            foreach (var action in LevelSpec.Actions)\n            {\n                str += indent(2) + $\"{String.Join(\"; \", action.Stmts.ConvertAll(stmt => \"None\"))};\\n\";\n            }\n            str += indent(1) + \"]\\n\\n\";\n\n            str += indent(0) + $\"let my_inv_witness () : armada_atomic_semantics_invariant_witness_t {LevelAtomicName}.prog my_inv =\\n\";\n            str += indent(1) + \"{\\n\";\n            str += indent(2) + \"action_pred = my_action_pred;\\n\";\n            str += indent(2) + \"special_case_proofs = my_special_case_proofs;\\n\";\n            str += indent(2) + \"init_implies_inv_proof = atomic_lprog_init_establishes_my_inv;\\n\";\n            str += indent(2) + \"action_proof = my_action_pred_preserves_my_inv;\\n\";\n            str += indent(1) + \"}\\n\\n\";\n\n            str += indent(0) + \"let inv_is_stepwise_invariant ()\\n\";\n            str += indent(1) + $\": Lemma (semantics_has_stepwise_inductive_invariant (make_atomic_semantics armada_semantics)\\n\";\n            str += indent(6) + $\"{LevelAtomicName}.prog my_inv) =\\n\";\n            str += indent(1) + \"let aiw = my_inv_witness () in\\n\";\n            str += indent(1) + $\"assert (armada_atomic_semantics_invariant_witness_valid {LevelAtomicName}.prog my_inv aiw)\\n\";\n            str += indent(2) + \"by (FStar.Tactics.compute(); FStar.Tactics.trivial ());\\n\";\n            str += indent(1) + $\"armada_atomic_semantics_invariant_witness_valid_implies_stepwise_invariant {LevelAtomicName}.prog my_inv aiw\\n\\n\";\n            return str;\n        }\n\n        public static string GetInvMaintainedIfVariablesUnchangedProof(\n            LevelDecl Level, List<Ident> Variables, Expr invariant, int indentation)\n        {\n            Func<int, string> indent = (int i) => new string(' ', indentation + i * 2);\n            string str = \"\";\n            var LevelName = Level.Name.ToString(0, false);\n            var LevelAtomicName = \"Atomic\" + LevelName;\n            Scope sc = Level.Sc;\n            var LevelSpec = new AtomicSpec(Level);\n\n            str += indent(0) + \"let vs = [\\n\";\n            var sep = \"\";\n            foreach (var v in Variables)\n            {\n                str += sep + indent(1) + $\"\\\"{v.Name}\\\"\";\n                sep = \";\\n\";\n            }\n            str += \"\\n]\\n\\n\";\n\n            str += indent(0) + $\"private let my_inv (s: Armada.State.t) : GTot ubool =\";\n            str += indent(1) + $\"{invariant.ToFStarExpr(\"s\")}\\n\\n\";\n\n            str += indent(0) + $\"private let my_action_pred (action: Armada.Action.t) : GTot ubool =\\n\";\n            str += indent(2) + \"(not action.ok)\\n\";\n            str += indent(1) + \"\\\\/ ( global_variables_unmodifiable_by_statement vs action.program_statement.statement\\n\";\n            str += indent(2) + \"/\\\\ global_variables_unaddressable_in_statement vs action.program_statement.statement\\n\";\n            str += indent(1) + \")\\n\\n\";\n\n            str += indent(0) + $\"private let inductive_inv (s: Armada.State.t) : GTot ubool =\\n\";\n            str += indent(2) + $\"roots_match s.mem\\n\";\n            str += indent(1) + $\"/\\\\ positions_valid_in_state s\\n\";\n            str += indent(1) + $\"/\\\\ global_variables_unaddressed_in_memory vs s.mem\\n\\n\";\n\n            str += indent(0) + $\"private let inductive_my_inv (s: Armada.State.t) : GTot ubool =\\n\";\n            str += indent(1) + $\"inductive_inv s /\\\\ my_inv s\\n\\n\";\n\n            str += indent(0) + $\"private let step_relation (s s': Armada.State.t): GTot ubool =\\n\";\n            str += indent(1) + $\"states_match_on_global_variables vs s s'\\n\\n\";\n\n            str += indent(0) + $\"private let step_relation_preserves_my_inv (s s': Armada.State.t)\\n\";\n            str += indent(1) + $\": Lemma (requires my_inv s /\\\\ step_relation s s')\\n\";\n            str += indent(5) + $\"(ensures  my_inv s') =\\n\";\n            str += indent(1) + $\"()\\n\\n\";\n\n            str += indent(0) + \"#push-options \\\"--z3rlimit 10 --z3cliopt smt.qi.eager_threshold=100\\\"\\n\\n\";\n\n            str += indent(0) + \"private let atomic_lprog_init_establishes_inductive_my_inv\\n\";\n            str += indent(1) + $\"(s: Armada.State.t{{(semantics_to_spec (make_atomic_semantics armada_semantics) {LevelAtomicName}.prog).init s}})\\n\";\n            str += indent(1) + \": squash (inductive_my_inv s) =\\n\";\n            str += indent(1) + $\"init_implies_global_variables_unaddressed_in_memory vs {LevelName}.prog s\\n\\n\";\n\n            str += indent(0) + \"private let my_action_pred_preserves_inductive_my_inv_proof\\n\";\n            str += indent(1) + \"(actor: tid_t)\\n\";\n            str += indent(1) + \"(starts_atomic_block ends_atomic_block: bool)\\n\";\n            str += indent(1) + \"(step: Armada.Step.t)\\n\";\n            str += indent(1) + \"(s: Armada.State.t)\\n\";\n            str += indent(1) + \": Lemma (requires   Some? (step_computation actor starts_atomic_block ends_atomic_block step s)\\n\";\n            str += indent(10) + \"/\\\\ my_action_pred step.action\\n\";\n            str += indent(10) + \"/\\\\ inductive_my_inv s)\\n\";\n            str += indent(5) + \"(ensures    inductive_my_inv (Some?.v (step_computation actor starts_atomic_block ends_atomic_block step s)))\\n\";\n            str += indent(1) + \"= executing_statement_maintains_roots_match actor step.nd ((s.threads actor).pc) step.action.program_statement.end_pc step.action.program_statement.statement s;\\n\";\n            str += indent(2) + \"executing_statement_maintains_positions_valid_in_state actor step.nd ((s.threads actor).pc) step.action.program_statement.end_pc step.action.program_statement.statement s;\\n\";\n            str += indent(2) + \"if (step.action.ok) then begin\\n\";\n            str += indent(3) + \"global_variables_unaddressable_by_statement_global_vars_unaddressed_in_state vs actor step starts_atomic_block ends_atomic_block s;\\n\";\n            str += indent(3) + \"global_variables_unmodifiable_by_statement_memories_matches_on_global_variables vs actor step starts_atomic_block ends_atomic_block s;\\n\";\n            str += indent(3) + \"step_relation_preserves_my_inv s (Some?.v (step_computation actor starts_atomic_block ends_atomic_block step s))\\n\";\n            str += indent(2) + \"end\\n\\n\";\n\n            str += indent(0) + \"private let my_action_pred_preserves_inductive_my_inv\\n\";\n            str += indent(1) + \"(actor: tid_t)\\n\";\n            str += indent(1) + \"(starts_atomic_block: bool)\\n\";\n            str += indent(1) + \"(ends_atomic_block: bool)\\n\";\n            str += indent(1) + \"(step: Armada.Step.t)\\n\";\n            str += indent(1) + \"(s: Armada.State.t{\\n\";\n            str += indent(2) + \"Some? (step_computation actor starts_atomic_block ends_atomic_block step s)\\n\";\n            str += indent(2) + \"/\\\\ my_action_pred step.action\\n\";\n            str += indent(2) + \"/\\\\ my_inv s})\\n\";\n            str += indent(1) + \": squash (inductive_my_inv (Some?.v (step_computation actor starts_atomic_block ends_atomic_block step s))) =\\n\";\n            str += indent(1) + \"my_action_pred_preserves_inductive_my_inv_proof actor starts_atomic_block ends_atomic_block step s\\n\\n\";\n\n            str += indent(0) + \"#pop-options\\n\\n\";\n\n            str += indent(0) + \"private let my_special_case_proofs\\n\";\n            str += indent(1) + \": list (option (armada_action_special_case_invariant_proof_t my_inv)) =\\n\";\n            str += indent(1) + \"[\\n\";\n            foreach (var action in LevelSpec.Actions)\n            {\n                str += indent(2) + $\"{String.Join(\"; \", action.Stmts.ConvertAll(stmt => \"None\"))};\\n\";\n            }\n            str += indent(1) + \"]\\n\\n\";\n\n            str += indent(0) + $\"let inductive_my_inv_witness () : armada_atomic_semantics_invariant_witness_t {LevelAtomicName}.prog inductive_my_inv =\\n\";\n            str += indent(1) + \"{\\n\";\n            str += indent(2) + \"action_pred = my_action_pred;\\n\";\n            str += indent(2) + \"special_case_proofs = my_special_case_proofs;\\n\";\n            str += indent(2) + \"init_implies_inv_proof = atomic_lprog_init_establishes_inductive_my_inv;\\n\";\n            str += indent(2) + \"action_proof = my_action_pred_preserves_inductive_my_inv;\\n\";\n            str += indent(1) + \"}\\n\\n\";\n\n            str += indent(0) + \"let my_inv_is_stepwise_invariant ()\\n\";\n            str += indent(1) + $\": Lemma (semantics_has_stepwise_inductive_invariant (make_atomic_semantics armada_semantics) {LevelAtomicName}.prog inductive_my_inv) =\\n\";\n            str += indent(1) + \"let aiw = inductive_my_inv_witness () in\\n\";\n            str += indent(1) + $\"assert (armada_atomic_semantics_invariant_witness_valid {LevelAtomicName}.prog inductive_my_inv aiw)\\n\";\n            str += indent(2) + \"by (FStar.Tactics.compute(); FStar.Tactics.trivial ());\\n\";\n            str += indent(1) + $\"armada_atomic_semantics_invariant_witness_valid_implies_stepwise_invariant {LevelAtomicName}.prog inductive_my_inv aiw\\n\\n\";\n            return str;\n        }\n    }\n}\n"
  },
  {
    "path": "experimental/Source/Armada/Proof/Myers.cs",
    "content": "using System.Collections.Generic;\n\nnamespace Microsoft.Starmada\n{\n    public class Diff<S, T> where S : IList<T>\n    {\n        private S a, b;\n        private bool[,] identityMatrix;\n        public class Pos\n        {\n            public int x, y;\n            public Pos(int x, int y)\n            {\n                this.x = x;\n                this.y = y;\n            }\n            public Pos(Pos pos)\n            {\n                this.x = pos.x;\n                this.y = pos.y;\n            }\n            public override string ToString()\n            {\n                return $\"({x.ToString()}, {y.ToString()})\";\n            }\n        }\n        private bool isIdentity(Pos pos)\n        {\n            return identityMatrix[pos.x, pos.y];\n        }\n        private List<(Pos, bool)> next(Pos pos)\n        {\n            List<(Pos, bool)> res = new();\n            if (pos.x < a.Count)\n            {\n                res.Add((new Pos(pos.x + 1, pos.y), false));\n            }\n            if (pos.y < b.Count)\n            {\n                res.Add((new Pos(pos.x, pos.y + 1), false));\n            }\n            if (pos.x < a.Count && pos.y < b.Count && isIdentity(pos))\n            {\n                res.Add((new Pos(pos.x + 1, pos.y + 1), true));\n            }\n            return res;\n        }\n        public class Route\n        {\n            public List<Pos> T { get; set; }\n            public int Length;\n            public Route(int length = int.MaxValue)\n            {\n                this.T = new List<Pos>();\n                this.Length = length;\n            }\n            /// Move forward by 1\n            public Route(Route route)\n            {\n                this.T = new List<Pos>(route.T);\n                this.Length = route.Length + 1;\n            }\n            public Route(Route route, Pos keyPos)\n            {\n                this.T = new List<Pos>(route.T);\n                this.T.Add(new Pos(keyPos));\n                this.Length = route.Length + 1;\n            }\n            /// Returns -1 if not matched\n            public int MapExactForward(int index)\n            {\n                int l = 0;\n                int r = T.Count;\n                while (l < r)\n                {\n                    int k = (l + r) / 2;\n                    if (T[k].x < index)\n                    {\n                        l = k + 1;\n                    } else if (T[k].x > index) {\n                        r = k;\n                    } else {\n                        return T[k].y;\n                    }\n                }\n                return -1;\n            }\n            /// Returns -1 if not matched\n            public int MapExactBackward(int index)\n            {\n                int l = 0;\n                int r = T.Count;\n                while (l < r)\n                {\n                    int k = (l + r) / 2;\n                    if (T[k].y < index)\n                    {\n                        l = k + 1;\n                    } else if (T[k].y > index) {\n                        r = k;\n                    } else {\n                        return T[k].x;\n                    }\n                }\n                return -1;\n            }\n            public override string ToString()\n            {\n                string res = \"\";\n                foreach (var item in this.T)\n                {\n                    res += item;\n                    res += \" -> \";\n                }\n                res += \"end\";\n                return res;\n            }\n        }\n\n        private Route keyRoute;\n\n        private void search()\n        {\n            int lenA = a.Count;\n            int lenB = b.Count;\n            Route[,] rs = new Route[lenA + 1, lenB + 1];\n            for (int i = 0; i <= lenA; i++)\n            {\n                for (int j = 0; j <= lenB; j++)\n                {\n                    rs[i, j] = new Route();\n                }\n            }\n            rs[0, 0] = new Route(0);\n\n            for (int i = 0; i <= lenA; i++)\n            {\n                for (int j = 0; j <= lenB; j++)\n                {\n                    Pos current = new Pos(i, j);\n                    foreach (var (pos, isDiag) in next(current))\n                    {\n                        Route r;\n                        if (isDiag)\n                        {\n                            r = new Route(rs[i, j], current);\n                        }\n                        else\n                        {\n                            r = new Route(rs[i, j]);\n                        }\n                        if (rs[pos.x, pos.y].Length > r.Length)\n                        {\n                            rs[pos.x, pos.y] = r;\n                        }\n                    }\n                }\n            }\n            keyRoute = rs[lenA, lenB];\n        }\n\n        // Init Diff\n        public Diff(S a, S b, EqualityComparer<T> comparator)\n        {\n            this.a = a;\n            this.b = b;\n            int lenA = a.Count;\n            int lenB = b.Count;\n            this.identityMatrix = new bool[lenA, lenB];\n            for (int i = 0; i < lenA; i++)\n            {\n                for (int j = 0; j < lenB; j++)\n                {\n                    this.identityMatrix[i, j] = comparator.Equals(a[i], b[j]);\n                }\n            }\n            this.search();\n        }\n\n        public int MapExactForward(int index)\n        {\n            return keyRoute.MapExactForward(index);\n        }\n        public int MapExactBackward(int index)\n        {\n            return keyRoute.MapExactBackward(index);\n        }\n    }\n}"
  },
  {
    "path": "experimental/Source/Armada/Proof/ProofPrinter.cs",
    "content": "using System;\nusing System.IO;\nusing System.Linq;\nusing System.Collections.Generic;\n\nnamespace Microsoft.Starmada\n{\n    class ProofPrinter\n    {\n        public Dictionary<string, string> GetProofs(LevelDecl L, int indentation)\n        {\n            var Capitalized = (string s) => char.ToUpper(s[0]) + s.Substring(1);\n            var levelName = Capitalized(L.Name.ToString(0, false));\n            Dictionary<string, string> proofs = new();\n\n            foreach (var inv in L.Invariants) {\n                var invName = Capitalized(inv.Name.ToString(0, false));\n                var moduleName = \"Invariant\" + levelName + invName;\n                var invariantHeader = Printer.GetFStarHeaderForModule(moduleName);\n                invariantHeader += Printer.GetFStarInvariantHeader(null);\n                var invariantStr = InvariantPrinter.GetProof(L, inv, indentation) + \"\\n\";\n                proofs[moduleName] = invariantHeader + '\\n' + invariantStr;\n            }\n            return proofs;\n        }\n        // Return a module name => content\n        public Dictionary<string, string> GetProofs(ProofDecl proof, LevelDecl L, LevelDecl H, int indentation)\n        {\n            var Capitalized = (string s) => char.ToUpper(s[0]) + s.Substring(1);\n            var moduleNameLow = Capitalized(L.Name.ToString(0, false));\n            var moduleNameHigh = Capitalized(H.Name.ToString(0, false));\n            var moduleName = \"Proof\" + moduleNameLow + moduleNameHigh;\n\n            StrategyPrinter p;\n            string invariantName = \"\";\n            if (proof.Strategy is WeakeningStrategy)\n            {\n                invariantName = \"Invariant\" + moduleNameLow + moduleNameHigh;\n                p = new WeakeningPrinter();\n            }\n            else if (proof.Strategy is VarIntroStrategy)\n            {\n                invariantName = \"Atomic\" + moduleNameHigh + \"Invariant\";\n                p = new VarIntroPrinter();\n            }\n            else if (proof.Strategy is VarHidingStrategy)\n            {\n                invariantName = \"Atomic\" + moduleNameLow + \"Invariant\";\n                p = new VarHidingPrinter();\n            }\n            else\n            {\n                throw new NotImplementedException();\n            }\n\n            Dictionary<string, string> proofs = new();\n            var header = Printer.GetFStarHeaderForModule(moduleName);\n            header += Printer.GetFStarProofHeader(proof, moduleNameLow, moduleNameHigh);\n            proofs[moduleName] = header + '\\n' + p.GetProof(proof, L, H, indentation);\n\n            var invariantHeader = Printer.GetFStarHeaderForModule(invariantName);\n            invariantHeader += Printer.GetFStarInvariantHeader(proof);\n            var invariantStr = p.GetInvariant(proof, L, H, 0) + \"\\n\";\n            proofs[invariantName] = invariantHeader + '\\n' + invariantStr;\n            return proofs;\n        }\n    }\n\n    interface StrategyPrinter\n    {\n        string GetProof(ProofDecl proof, LevelDecl L, LevelDecl H, int indentation);\n        string GetInvariant(ProofDecl proof, LevelDecl L, LevelDecl H, int indentation);\n    }\n}"
  },
  {
    "path": "experimental/Source/Armada/Proof/ProofSpec.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\n\nnamespace Microsoft.Starmada\n{\n    public class ProofSpec\n    {\n        public AtomicSpec LS;\n        public AtomicSpec HS;\n        \n        public ProofSpec(LevelDecl L, LevelDecl H)\n        {\n            LS = new AtomicSpec(L);\n            HS = new AtomicSpec(H);\n        }\n    }\n\n    public class WeakeningProofSpec : ProofSpec\n    {\n        public List<string> WeakeningTrans;\n        public List<int> WeakeningUpdateIndices;\n\n        public WeakeningProofSpec(LevelDecl L, LevelDecl H)\n        : base(L, H)\n        {\n            WeakeningUpdateIndices = new();\n            WeakeningTrans = GetWeakeningTrans();\n        }\n\n        public List<string> GetWeakeningTrans()\n        {\n            List<string> trans = new();\n            List<ExecutionPathScheme> Lseqs = LS.Sequences;\n            List<ExecutionPathScheme> Hseqs = HS.Sequences;\n            // assert Lseqs.Count == Hseqs.Count\n            int Nseqs = Lseqs.Count;\n            for (int i = 0; i < Nseqs; i++) {\n                List<FStarStmt> LAtomicBlock = Lseqs[i].Stmts;\n                List<FStarStmt> HAtomicBlock = Hseqs[i].Stmts;\n                // assert LAtomicBlock.Count == HAtomicBlock.Count\n                int Nstmts = LAtomicBlock.Count;\n                int firstdiff = -1;\n                for (int j = 0; j < Nstmts; j++) {\n                    if (LAtomicBlock[j] != HAtomicBlock[j]) {\n                        firstdiff = j;\n                        break;\n                    }\n                }\n                string same = \"ArmadaWeakeningTransformerSameStep {0}\";\n                string update = \"ArmadaWeakeningTransformerUpdatedStep my_special_case_action_{0} my_special_case_steps_updater_{0} my_special_case_steps_updater_works_{0}\";\n                if (firstdiff == -1) { // The same atomic sequences\n                    for (int k = 0; k <= Nstmts; k++) {\n                        trans.Add(string.Format(same, trans.Count));\n                    }\n                } else {\n                    WeakeningUpdateIndices.Add(trans.Count);\n                    trans.Add(string.Format(update, trans.Count));\n                    for (int k = 0; k < Nstmts; k++) {\n                        if (k < firstdiff) {\n                            trans.Add(string.Format(same, trans.Count));\n                        } else {\n                            WeakeningUpdateIndices.Add(trans.Count);\n                            trans.Add(string.Format(update, trans.Count));\n                        }\n                    }\n                }\n            }\n            return trans;\n        }\n    }\n\n    public class VarIntroProofSpec: ProofSpec\n    {\n        public List<FStarStmt> VarIntroStmts;\n        public Dictionary<FStarStmt, FStarStmt> FstmtMap; // L statement to H statement\n        public Dictionary<string, string> PCMap; // Map from hpc to lpc\n        public Dictionary<string, List<string>> ReversePCMap; // Map from lpc to hpc\n        public Dictionary<ExecutionPathScheme, ExecutionPathScheme> SequenceMap; // H sequence to L sequence\n        public Dictionary<ExecutionPathScheme, ExecutionPathScheme> ReverseSequenceMap; // L sequence to H sequence\n        public Dictionary<string, ExecutionPathScheme> IntroPCs; // PC in a introduced atomic block\n        public Dictionary<ExecutionPath, ExecutionPath> ActionMap; // L Action to H Action\n\n        public VarIntroProofSpec(LevelDecl L, LevelDecl H)\n        : base(L, H)\n        {\n            VarIntroStmts = GetVarIntroStmts();\n            InitMaps();\n            InitAtomicSequenceMap();\n            InitActionMap();\n        }\n\n        private void InitMaps()\n        {\n            FstmtMap = new();\n            PCMap = new();\n            ReversePCMap = new();\n            int i = 0, j = 0;\n            while (i < LS.Fstmts.Count && j < HS.Fstmts.Count)\n            {\n                FStarStmt lfstmt = LS.Fstmts[i];\n                FStarStmt hfstmt = HS.Fstmts[j];\n                if (VarIntroStmts.Contains(hfstmt))\n                {\n                    j++;\n                    continue;\n                }\n                // TODO: Error checking, whether these two statement matches\n                FstmtMap[lfstmt] = hfstmt;\n                if (hfstmt.StartPC != null && hfstmt.EndPC != null) {\n                    PCMap[hfstmt.StartPC] = lfstmt.StartPC;\n                    PCMap[hfstmt.EndPC] = lfstmt.EndPC;\n                }\n                i++;\n                j++;\n            }\n            foreach (FStarStmt introStmt in VarIntroStmts)\n            {\n                if (!PCMap.ContainsKey(introStmt.EndPC)) {\n                    if (PCMap.ContainsKey(introStmt.StartPC)) {\n                        PCMap[introStmt.EndPC] = PCMap[introStmt.StartPC];\n                    }\n                }\n                if (!PCMap.ContainsKey(introStmt.StartPC)) {\n                    if (PCMap.ContainsKey(introStmt.EndPC)) {\n                        PCMap[introStmt.StartPC] = PCMap[introStmt.EndPC];\n                    }\n                }\n            }\n            foreach (var kv in PCMap)\n            {\n                string lpc = kv.Value;\n                string hpc = kv.Key;\n                if (!ReversePCMap.ContainsKey(lpc)) {\n                    ReversePCMap[lpc] = new();\n                }\n                ReversePCMap[lpc].Add(hpc);\n            }\n        }\n\n        private void InitAtomicSequenceMap()\n        {\n            SequenceMap = new();\n            ReverseSequenceMap = new();\n            Dictionary<(string, string), List<ExecutionPathScheme>> patternMap = new(); // atomic sequence pattern for level L\n            IntroPCs = new();\n            foreach (var sequence in LS.Sequences)\n            {\n                var fstmts = sequence.Stmts;\n                if (fstmts[0].StartPC == null) continue;\n                var pattern = (fstmts[0].StartPC, fstmts[fstmts.Count - 1].EndPC);\n                if (!patternMap.ContainsKey(pattern))\n                    patternMap[pattern] = new();\n                patternMap[pattern].Add(sequence);\n            }\n            foreach (var sequence in HS.Sequences)\n            {\n                var fstmts = sequence.Stmts;\n                if (fstmts[0].StartPC == null) continue;\n                var pattern = (PCMap[fstmts[0].StartPC], PCMap[fstmts[fstmts.Count - 1].EndPC]);\n                if (patternMap.ContainsKey(pattern) && patternMap[pattern].Count > 0)\n                {\n                    var lseq = patternMap[pattern][0];\n                    SequenceMap[sequence] = lseq;\n                    ReverseSequenceMap[lseq] = sequence;\n                    patternMap[pattern].Remove(lseq);\n                }\n                else // Introduced atomic block, add the first PC\n                {\n                    IntroPCs[fstmts[0].StartPC] = sequence;\n                }\n            }\n        }\n\n        private void InitActionMap()\n        {\n            ActionMap = new();\n            // Add the PropagateWriteMessageStatement\n            ActionMap[LS.Actions[0]] = HS.Actions[0];\n            ActionMap[LS.Actions[1]] = HS.Actions[1];\n            foreach (var kv in ReverseSequenceMap)\n            {\n                var lseq = kv.Key;\n                var hseq = kv.Value;\n                foreach (var laction in lseq.Paths)\n                {\n                    // All success to all success\n                    if (!laction.FailAtTheEnd)\n                    {\n                        ActionMap[laction] = hseq.Paths[0];\n                    }\n                    else\n                    {\n                        FStarStmt llast = laction.Stmts[laction.Stmts.Count - 1];\n                        FStarStmt hlast = FstmtMap[llast];\n                        ActionMap[laction] = hseq.Paths[hseq.Stmts.IndexOf(hlast) + 1];\n                    }\n                }\n            }\n            // foreach (var kv in ActionMap)\n            // {\n            //     var laction = kv.Key;\n            //     var haction = kv.Value;\n            //     AtomicPrinter ap = new();\n            //     Console.Write(\"Action Map:\\n\");\n            //     Console.Write(ap.ToFStarAtomic(laction, 0) + '\\n');\n            //     Console.Write(ap.ToFStarAtomic(haction, 0) + '\\n');\n            // }\n        }\n\n        public List<FStarStmt> GetVarIntroStmts()\n        {\n            List<FStarStmt> varIntroStmts = new();\n            HashSet<string> lupdates = new();\n            foreach (var fstmt in LS.Fstmts)\n            {\n                string actualstmt = fstmt.Statement;\n                if (!actualstmt.StartsWith(\"UpdateStatement\"))\n                    continue;\n                lupdates.Add(actualstmt);\n            }\n            foreach (var fstmt in HS.Fstmts)\n            {\n                string actualstmt = fstmt.Statement;\n                if (!actualstmt.StartsWith(\"UpdateStatement\"))\n                    continue;\n                if (!lupdates.Contains(actualstmt))\n                {\n                    varIntroStmts.Add(fstmt);\n                }\n            }\n            return varIntroStmts;\n        }\n\n        public List<FStarStmt> GetNonConstStmts()\n        {\n            List<FStarStmt> nonConstStmts = new();\n            foreach (FStarStmt fstmt in VarIntroStmts)\n            {\n                string actualstmt = fstmt.Statement;\n                int startIdx = actualstmt.IndexOf(\"(ExpressionConstant\");\n                int endIdx = actualstmt.LastIndexOf(')');\n                if (startIdx == -1)\n                {\n                    nonConstStmts.Add(fstmt);\n                    continue;\n                }\n                string rhs = actualstmt.Substring(startIdx, endIdx - startIdx + 1);\n                int left = actualstmt.Count(c => c == '(');\n                int right = actualstmt.Count(c => c == ')');\n                if (left != right)\n                {\n                    nonConstStmts.Add(fstmt);\n                }\n            }\n            return nonConstStmts;\n        }\n    }\n}"
  },
  {
    "path": "experimental/Source/Armada/Proof/VarHidingPrinter.cs",
    "content": "using System;\nusing System.IO;\nusing System.Linq;\nusing System.Collections.Generic;\n\nnamespace Microsoft.Starmada\n{\n    class VarHidingPrinter : StrategyPrinter\n    {\n        public string GetProof(ProofDecl proof, LevelDecl L, LevelDecl H, int indentation)\n        {\n            Func<int, string> indent = (int i) => new string(' ', indentation + i * 2);\n            string str = \"\";\n            var LName = L.Name.ToString(0, false);\n            var LAtomicName = \"Atomic\" + LName;\n            var HName = H.Name.ToString(0, false);\n            var HAtomicName = \"Atomic\" + HName;\n            var HAtomicInvariantName = LAtomicName + \"Invariant\"; // Actually LAtomic Invariant Name\n            AtomicPrinter atomicPrinter = new AtomicPrinter();\n            Scope sc = L.Sc;\n            VarHidingStrategy vs = proof.Strategy as VarHidingStrategy;\n            HashSet<string> hidingVarNameSet = new();\n            foreach (Ident introvar in vs.Variables)\n            {\n                hidingVarNameSet.Add(introvar.Name);\n            }\n            VarIntroProofSpec proofSpec = new VarIntroProofSpec(H, L);\n\n            str += indent(0) + \"let vs: list var_id_t =\\n\";\n            str += indent(1) + \"[\\n\";\n            foreach (Ident introvar in vs.Variables)\n            {\n                str += indent(2) + $\"\\\"{introvar.Name}\\\";\\n\";\n            }\n            str += indent(1) + \"]\\n\\n\";\n\n            str += indent(0) + \"let tds: list object_td_t =\\n\";\n            str += indent(1) + \"[\\n\";\n            foreach (Ident introvar in vs.Variables)\n            {\n                VarDecl vardecl = sc.GetVariableDecl(introvar, false);\n                str += indent(2) + $\"({vardecl.Ty.ToFStarLang(0, true)});\\n\";\n            }\n            str += indent(1) + \"]\\n\\n\";\n\n            str += indent(0) + \"let which_initializers_are_hidings: list bool =\\n\";\n            str += indent(1) + \"[\\n\";\n            foreach (var globalvar in L.Globals)\n            {\n                str += indent(2) + $\"{hidingVarNameSet.Contains(globalvar.Name.Name).ToString().ToLower()};\\n\";\n            }\n            str += indent(1) + \"]\\n\\n\";\n\n            string lpcList = $\"[{String.Join(\"; \", proofSpec.HS.PCs.ConvertAll(pc => $\"\\\"{pc}\\\"\"))}]\";\n            str += indent(0) + $\"let lpcs: array_t pc_t = list_to_array {lpcList}\\n\\n\";\n\n            string hpcList = $\"[{String.Join(\"; \", proofSpec.LS.PCs.ConvertAll(pc => $\"\\\"{pc}\\\"\"))}]\";\n            str += indent(0) + $\"let hpcs: array_t pc_t = list_to_array {hpcList}\\n\\n\";\n\n            List<string> lpc2hpc = new();\n            foreach (string lpc in proofSpec.HS.PCs)\n            {\n                string hpc = proofSpec.PCMap[lpc];\n                lpc2hpc.Add($\"{proofSpec.LS.PC2Index[hpc]}\");\n            }\n            str += indent(0) + $\"let lpc_to_hpc: array_t nat = list_to_array [{String.Join(\"; \", lpc2hpc)}]\\n\\n\";\n\n            string lpcReturnList = $\"[{String.Join(\"; \", proofSpec.HS.PCs.ConvertAll(pc => $\"{pc.EndsWith(\".R\").ToString().ToLower()}\"))}]\";\n            str += indent(0) + $\"let is_return_lpc: array_t bool = list_to_array {lpcReturnList}\\n\\n\";\n\n            str += indent(0) + $\"let is_nonyielding_lpc : array_t bool = list_to_array {proofSpec.HS.GetNonYieldingPCList()}\\n\\n\";\n            str += indent(0) + $\"let is_nonyielding_hpc : array_t bool = list_to_array {proofSpec.LS.GetNonYieldingPCList()}\\n\\n\";\n\n            List<FStarStmt> nonconstStmts = proofSpec.GetNonConstStmts();\n            for (int i = 0; i < nonconstStmts.Count; i++)\n            {\n                str += indent(0) + $\"let statement_subroutine_{i}: program_statement_t =\\n\";\n                str += nonconstStmts[i].GetFStarCodeOfStatement(indentation + 2) + \"\\n\\n\";\n\n                str += indent(0) + \"#push-options \\\"--z3rlimit 20 --z3cliopt smt.qi.eager_threshold=100\\\"\\n\";\n\n                str += indent(0) + $\"let lemma_cant_crash_subroutine_{i}\\n\";\n                str += indent(1) + \"(actor: tid_t)\\n\";\n                str += indent(1) + \"(nd: nondeterminism_t)\\n\";\n                str += indent(1) + \"(s: Armada.State.t{\\n\";\n                str += indent(3) + $\"{HAtomicInvariantName}.inv s\\n\";\n                str += indent(2) + \"/\\\\ all_gvars_have_types s.mem vs tds\\n\";\n                str += indent(2) + \"/\\\\ NotStopped? s.stop_reason\\n\";\n                str += indent(2) + \"/\\\\ ThreadStatusRunning? (s.threads actor).status\\n\";\n                str += indent(2) + $\"/\\\\ statement_subroutine_{i}.start_pc = Some (s.threads actor).pc}})\\n\";\n                str += indent(1) + $\": squash (let ps = statement_subroutine_{i} in\\n\";\n                str += indent(5) + \"not (ComputationUndefined? (statement_computation actor nd (Some?.v ps.start_pc) ps.end_pc ps.statement s))) = \\n\";\n                str += indent(1) + \"()\\n\";\n                str += indent(0) + \"#pop-options\\n\\n\";\n            }\n\n            str += indent(0) + $\"let corresponding_hactions_info: array_t (ltoh_correspondence_t vs tds {HAtomicInvariantName}.inv) = list_to_array\\n\";\n            str += indent(1) + \"[\\n\";\n            Dictionary<ExecutionPath, ExecutionPath> actionMap = new();\n            foreach (var kv in proofSpec.ActionMap)\n            {\n                actionMap[kv.Value] = kv.Key;\n            }\n            foreach (var laction in proofSpec.HS.Actions)\n            {\n                if (actionMap.ContainsKey(laction))\n                {\n                    var haction = actionMap[laction];\n                    int hactionIndex= proofSpec.LS.Actions.IndexOf(haction);\n                    if (laction.Stmts.Count == 1 && laction.Stmts[0].Statement == \"PropagateWriteMessageStatement\")\n                    {\n                        str += indent(2) + $\"CorrespondencePropagate {hactionIndex};\\n\";\n                        continue;\n                    }\n                    List<string> lactionMaps = new();\n                    foreach (FStarStmt lstmt in laction.Stmts)\n                    {\n                        if (proofSpec.VarIntroStmts.Contains(lstmt))\n                        {\n                            lactionMaps.Add(\"true\");\n                        }\n                        else\n                        {\n                            lactionMaps.Add(\"false\");\n                        }\n                    }\n                    str += indent(2) + $\"CorrespondenceNormal {hactionIndex} [{String.Join(\"; \", lactionMaps)}];\\n\";\n                }\n                else if (!laction.FailAtTheEnd)\n                {\n                    str += indent(2) + \"CorrespondenceHidden;\\n\";\n                }\n                else\n                {\n                    string correspond = \"CorrespondenceImpossibleConstantAssignmentFailure\";\n                    foreach (FStarStmt lstmt in laction.Stmts)\n                    {\n                        if (proofSpec.VarIntroStmts.Contains(lstmt))\n                        {\n                            if (nonconstStmts.Contains(lstmt))\n                            {\n                                int nonconstIndex = nonconstStmts.IndexOf(lstmt);\n                                correspond = $\"CorrespondenceImpossibleStatementFailure statement_subroutine_{nonconstIndex} lemma_cant_crash_subroutine_{nonconstIndex}\";\n                            }\n                        }\n                    }\n                    str += indent(2) + correspond + \";\\n\";\n                }\n            }\n            str += indent(1) + \"]\\n\\n\";\n\n            str += $\"let lprog_main_start_pc_index = {proofSpec.HS.GetStartIndex()}\\n\\n\";\n            str += $\"let hprog_main_start_pc_index = {proofSpec.LS.GetStartIndex()}\\n\\n\";\n            \n            str += atomicPrinter.MakePCIndexStarter(0);\n\n            str += indent(0) + \"let lpc_indices_array: array_t (list statement_pc_indices_t) = list_to_array\\n\";\n            str += indent(1) + \"[\\n\";\n            foreach (var laction in proofSpec.HS.Actions)\n            {\n                str += indent(2) + $\"[{String.Join(\"; \", laction.Stmts.ConvertAll(fstmt => atomicPrinter.MakePCIndex(proofSpec.HS, fstmt)))}];\\n\";\n            }\n            str += indent(1) + \"]\\n\\n\";\n\n            str += indent(0) + \"let hpc_indices_array: array_t (list statement_pc_indices_t) = list_to_array\\n\";\n            str += indent(1) + \"[\\n\";\n            foreach (var haction in proofSpec.LS.Actions)\n            {\n                str += indent(2) + $\"[{String.Join(\"; \", haction.Stmts.ConvertAll(fstmt => atomicPrinter.MakePCIndex(proofSpec.LS, fstmt)))}];\\n\";\n            }\n            str += indent(1) + \"]\\n\\n\";\n\n            str += indent(0) + \"let vw: efficient_var_hiding_witness_t = {\\n\";\n            str += indent(1) + $\"lprog = {LName}.prog;\\n\";\n            str += indent(1) + $\"hprog = {HName}.prog;\\n\";\n            str += indent(1) + $\"lprog_actions_array = list_to_array {LAtomicName}.prog.actions;\\n\";\n            str += indent(1) + $\"hprog_actions_array = list_to_array {HAtomicName}.prog.actions;\\n\";\n            str += indent(1) + \"vs = vs;\\n\";\n            str += indent(1) + \"tds = tds;\\n\";\n            str += indent(1) + $\"inv = {HAtomicInvariantName}.inv;\\n\";\n            str += indent(1) + \"which_initializers_are_hidings = which_initializers_are_hidings;\\n\";\n            str += indent(1) + \"lpcs = lpcs;\\n\";\n            str += indent(1) + \"hpcs = hpcs;\\n\";\n            str += indent(1) + \"lpc_to_hpc = lpc_to_hpc;\\n\";\n            str += indent(1) + \"is_return_lpc = is_return_lpc;\\n\";\n            str += indent(1) + \"is_nonyielding_lpc = is_nonyielding_lpc;\\n\";\n            str += indent(1) + \"is_nonyielding_hpc = is_nonyielding_hpc;\\n\";\n            str += indent(1) + \"corresponding_hactions_info = corresponding_hactions_info;\\n\";\n            str += indent(1) + \"lprog_main_start_pc_index = lprog_main_start_pc_index;\\n\";\n            str += indent(1) + \"hprog_main_start_pc_index = hprog_main_start_pc_index;\\n\";\n            str += indent(1) + \"lpc_indices_array = lpc_indices_array;\\n\";\n            str += indent(1) + \"hpc_indices_array = hpc_indices_array;\\n\";\n            str += indent(0) + \"}\\n\\n\";\n\n            str += indent(0) + $\"let lemma_{LAtomicName}Refines{HAtomicName}()\\n\";\n            str += indent(1) + \": Lemma (spec_refines_spec\\n\";\n            str += indent(5) + $\"(semantics_to_spec (make_atomic_semantics armada_semantics) {LAtomicName}.prog)\\n\";\n            str += indent(5) + $\"(semantics_to_spec (make_atomic_semantics armada_semantics) {HAtomicName}.prog)\\n\";\n            str += indent(5) + $\"refinement_requirement) =\\n\";\n            str += indent(1) + $\"let latomic_prog = {LAtomicName}.prog in\\n\";\n            str += indent(1) + $\"let hatomic_prog = {HAtomicName}.prog in\\n\";\n            str += indent(1) + \"let pc_relation = efficient_lh_pc_relation lpc_to_hpc in\\n\";\n            str += indent(1) + \"let pc_return_relation = efficient_lh_pc_return_relation lpc_to_hpc is_return_lpc in\\n\";\n            str += indent(1) + \"assert (efficient_var_hiding_witness_valid latomic_prog hatomic_prog vw)\\n\";\n            str += indent(2) + \"by (FStar.Tactics.compute (); FStar.Tactics.trivial ());\\n\";\n            str += indent(1) + $\"{HAtomicInvariantName}.inv_is_stepwise_invariant ();\\n\";\n            str += indent(1) + \"efficient_var_hiding_witness_valid_implies_refinement latomic_prog hatomic_prog vw\\n\\n\";\n\n            return str;\n        }\n\n        public string GetInvariant(ProofDecl proof, LevelDecl L, LevelDecl H, int indentation)\n        {\n            VarIntroPrinter vp = new();\n            // Exactly the same as varIntro\n            return vp.GetInvariant(proof, H, L, indentation);\n        }\n    }\n}\n"
  },
  {
    "path": "experimental/Source/Armada/Proof/VarIntroPrinter.cs",
    "content": "using System;\nusing System.IO;\nusing System.Linq;\nusing System.Collections.Generic;\n\nnamespace Microsoft.Starmada\n{\n    class VarIntroPrinter : StrategyPrinter\n    {\n        public string GetProof(ProofDecl proof, LevelDecl L, LevelDecl H, int indentation)\n        {\n            Func<int, string> indent = (int i) => new string(' ', indentation + i * 2);\n            string str = \"\";\n            var LName = L.Name.ToString(0, false);\n            var LAtomicName = \"Atomic\" + LName;\n            var HName = H.Name.ToString(0, false);\n            var HAtomicName = \"Atomic\" + HName;\n            var HAtomicInvariantName = HAtomicName + \"Invariant\";\n            AtomicPrinter atomicPrinter = new AtomicPrinter();\n            Scope sc = H.Sc;\n            VarIntroStrategy vs = proof.Strategy as VarIntroStrategy;\n            HashSet<string> introvarNameSet = new();\n            foreach (Ident introvar in vs.Variables)\n            {\n                introvarNameSet.Add(introvar.Name);\n            }\n            VarIntroProofSpec proofSpec = new VarIntroProofSpec(L, H);\n            \n            str += indent(0) + \"let vs: list var_id_t =\\n\";\n            str += indent(1) + \"[\\n\";\n            foreach (Ident introvar in vs.Variables)\n            {\n                str += indent(2) + $\"\\\"{introvar.Name}\\\";\\n\";\n            }\n            str += indent(1) + \"]\\n\\n\";\n\n            str += indent(0) + \"let tds: list object_td_t =\\n\";\n            str += indent(1) + \"[\\n\";\n            foreach (Ident introvar in vs.Variables)\n            {\n                VarDecl vardecl = sc.GetVariableDecl(introvar, false);\n                str += indent(2) + $\"({vardecl.Ty.ToFStarLang(0, true)});\\n\";\n            }\n            str += indent(1) + \"]\\n\\n\";\n\n            str += indent(0) + \"let which_initializers_are_intros: list bool =\\n\";\n            str += indent(1) + \"[\\n\";\n            foreach (var globalvar in H.Globals)\n            {\n                str += indent(2) + $\"{introvarNameSet.Contains(globalvar.Name.Name).ToString().ToLower()};\\n\";\n            }\n            str += indent(1) + \"]\\n\\n\";\n\n            string lpcList = $\"[{String.Join(\"; \", proofSpec.LS.PCs.ConvertAll(pc => $\"\\\"{pc}\\\"\"))}]\";\n            str += indent(0) + $\"let lpcs: array_t pc_t = list_to_array {lpcList}\\n\\n\";\n\n            string hpcList = $\"[{String.Join(\"; \", proofSpec.HS.PCs.ConvertAll(pc => $\"\\\"{pc}\\\"\"))}]\";\n            str += indent(0) + $\"let hpcs: array_t pc_t = list_to_array {hpcList}\\n\\n\";\n\n            List<string> hpc2lpc = new();\n            foreach (string hpc in proofSpec.HS.PCs)\n            {\n                string lpc = proofSpec.PCMap[hpc];\n                hpc2lpc.Add($\"{proofSpec.LS.PC2Index[lpc]}\");\n            }\n            str += indent(0) + $\"let hpc_to_lpc: array_t nat = list_to_array [{String.Join(\"; \", hpc2lpc)}]\\n\\n\";\n            \n            List<string> lpc2hpcs = new();\n            foreach (string lpc in proofSpec.LS.PCs)\n            {\n                List<string> hpcs = proofSpec.ReversePCMap[lpc];\n                List<int> hpcIndices = hpcs.ConvertAll(hpc => proofSpec.HS.PC2Index[hpc]);\n                hpcIndices.Sort();\n                lpc2hpcs.Add($\"[{String.Join(\"; \", hpcIndices.ConvertAll(id => id.ToString()))}]\");\n            }\n            str += indent(0) + $\"let lpc_to_hpcs: array_t (list nat) = list_to_array [{String.Join(\"; \", lpc2hpcs)}]\\n\\n\";\n\n            string hpcReturnList = $\"[{String.Join(\"; \", proofSpec.HS.PCs.ConvertAll(pc => $\"{pc.EndsWith(\".R\").ToString().ToLower()}\"))}]\";\n            str += indent(0) + $\"let is_return_hpc: array_t bool = list_to_array {hpcReturnList}\\n\\n\";\n\n            str += indent(0) + $\"let is_nonyielding_lpc : array_t bool = list_to_array {proofSpec.LS.GetNonYieldingPCList()}\\n\\n\";\n            str += indent(0) + $\"let is_nonyielding_hpc : array_t bool = list_to_array {proofSpec.HS.GetNonYieldingPCList()}\\n\\n\";\n\n            str += indent(0) + $\"let is_breaking_hpc : array_t bool = list_to_array {proofSpec.HS.GetBreakPCList()}\\n\\n\";\n            \n            List<FStarStmt> nonconstStmts = proofSpec.GetNonConstStmts();\n            for (int i = 0; i < nonconstStmts.Count; i++)\n            {\n                str += indent(0) + $\"let statement_subroutine_{i}: program_statement_t =\\n\";\n                str += nonconstStmts[i].GetFStarCodeOfStatement(indentation + 2) + \"\\n\\n\";\n\n                str += indent(0) + \"#push-options \\\"--z3rlimit 20 --z3cliopt smt.qi.eager_threshold=100\\\"\\n\";\n\n                str += indent(0) + $\"let lemma_cant_crash_subroutine_{i}\\n\";\n                str += indent(1) + \"(actor: tid_t)\\n\";\n                str += indent(1) + \"(s: Armada.State.t{\\n\";\n                str += indent(3) + $\"{HAtomicInvariantName}.inv s\\n\";\n                str += indent(2) + \"/\\\\ all_gvars_have_types s.mem vs tds\\n\";\n                str += indent(2) + \"/\\\\ NotStopped? s.stop_reason\\n\";\n                str += indent(2) + \"/\\\\ ThreadStatusRunning? (s.threads actor).status\\n\";\n                str += indent(2) + $\"/\\\\ statement_subroutine_{i}.start_pc = Some (s.threads actor).pc}})\\n\";\n                str += indent(1) + $\": squash (let ps = statement_subroutine_{i} in\\n\";\n                str += indent(5) + \"ComputationProduces? (statement_computation actor [] (Some?.v ps.start_pc) ps.end_pc ps.statement s)) =\\n\";\n                str += indent(1) + \"()\\n\";\n                str += indent(0) + \"#pop-options\\n\\n\";\n\n                str += indent(0) + $\"let introduction_succeeds_witness_subroutine_{i}: introduction_succeeds_witness_t vs tds {HAtomicInvariantName}.inv =\\n\";\n                str += indent(1) + $\"IntroductionSucceedsProof statement_subroutine_{i} lemma_cant_crash_subroutine_{i}\\n\\n\";\n            }\n\n            str += indent(0) + $\"let hpc_info: array_t (efficient_hpc_info_t vs tds {HAtomicInvariantName}.inv) = list_to_array\\n\";\n            str += indent(1) + \"[\\n\";\n            foreach (var hpc in proofSpec.HS.PCs)\n            {\n                string info = \"EfficientHPCInfoNormal\";\n                if (proofSpec.IntroPCs.ContainsKey(hpc))\n                {\n                    var sequence = proofSpec.IntroPCs[hpc];\n                    int successPathIndex = proofSpec.HS.Actions.IndexOf(sequence.Paths[0]);\n                    string endPC = sequence.Stmts[sequence.Stmts.Count - 1].EndPC;\n                    string successReasons = String.Join(\"; \", sequence.Stmts.ConvertAll(stmt => nonconstStmts.Contains(stmt) ? $\"introduction_succeeds_witness_subroutine_{nonconstStmts.IndexOf(stmt)}\" : \"IntroductionSucceedsBecauseItAssignsConstant\"));\n                    int progress = 1;\n                    string nextPC = endPC;\n                    while (proofSpec.IntroPCs.ContainsKey(nextPC))\n                    {\n                        progress += 1;\n                        var nextSeq = proofSpec.IntroPCs[nextPC];\n                        nextPC = nextSeq.Stmts[nextSeq.Stmts.Count - 1].EndPC;\n                    }\n                    // Console.WriteLine(hpc);\n                    // Console.WriteLine(atomicPrinter.ToFStarAtomic(proofSpec.HS.Actions[successPathIndex], 0));\n                    // Console.WriteLine(endPC);\n                    info = $\"EfficientHPCInfoIntroduced {successPathIndex} {proofSpec.HS.PC2Index[endPC]} [{successReasons}] {progress}\";\n                }\n                str += indent(2) + $\"{info};\\n\";\n            }\n            str += indent(1) + \"]\\n\\n\";\n\n            str += indent(0) + $\"let corresponding_hactions_info: array_t (ltoh_correspondence_t vs tds {HAtomicInvariantName}.inv) = list_to_array\\n\";\n            str += indent(1) + \"[\\n\";\n            foreach (var laction in proofSpec.LS.Actions)\n            {\n                var haction = proofSpec.ActionMap[laction];\n                int hactionIndex= proofSpec.HS.Actions.IndexOf(haction);\n                if (laction.Stmts.Count == 1 && laction.Stmts[0].Statement == \"PropagateWriteMessageStatement\")\n                {\n                    str += indent(2) + $\"CorrespondencePropagate {hactionIndex};\\n\";\n                    continue;\n                }\n                List<string> hactionMaps = new();\n                foreach (FStarStmt hstmt in haction.Stmts)\n                {\n                    if (proofSpec.VarIntroStmts.Contains(hstmt))\n                    {\n                        string hactionMap = \"MapperIntroduced \";\n                        if (nonconstStmts.Contains(hstmt))\n                        {\n                            hactionMap += $\"introduction_succeeds_witness_subroutine_{nonconstStmts.IndexOf(hstmt)}\";\n                        }\n                        else\n                        {\n                            hactionMap += \"IntroductionSucceedsBecauseItAssignsConstant\";\n                        }\n                        hactionMaps.Add(hactionMap);\n                    }\n                    else\n                    {\n                        hactionMaps.Add(\"MapperMatching\");\n                    }\n                }\n                str += indent(2) + $\"CorrespondenceNormal {hactionIndex} [{String.Join(\"; \", hactionMaps)}];\\n\";\n            }\n            str += indent(1) + \"]\\n\\n\";\n\n            str += $\"let lprog_main_start_pc_index = {proofSpec.LS.GetStartIndex()}\\n\\n\";\n            str += $\"let hprog_main_start_pc_index = {proofSpec.HS.GetStartIndex()}\\n\\n\";\n\n            str += atomicPrinter.MakePCIndexStarter(0);\n\n            str += indent(0) + \"let lpc_indices_array: array_t (list statement_pc_indices_t) = list_to_array\\n\";\n            str += indent(1) + \"[\\n\";\n            foreach (var laction in proofSpec.LS.Actions)\n            {\n                str += indent(2) + $\"[{String.Join(\"; \", laction.Stmts.ConvertAll(fstmt => atomicPrinter.MakePCIndex(proofSpec.LS, fstmt)))}];\\n\";\n            }\n            str += indent(1) + \"]\\n\\n\";\n\n            str += indent(0) + \"let hpc_indices_array: array_t (list statement_pc_indices_t) = list_to_array\\n\";\n            str += indent(1) + \"[\\n\";\n            foreach (var haction in proofSpec.HS.Actions)\n            {\n                str += indent(2) + $\"[{String.Join(\"; \", haction.Stmts.ConvertAll(fstmt => atomicPrinter.MakePCIndex(proofSpec.HS, fstmt)))}];\\n\";\n            }\n            str += indent(1) + \"]\\n\\n\";\n\n            str += indent(0) + \"let vw: efficient_var_intro_witness_t = {\\n\";\n            str += indent(1) + $\"lprog = {LName}.prog;\\n\";\n            str += indent(1) + $\"hprog = {HName}.prog;\\n\";\n            str += indent(1) + $\"lprog_actions_array = list_to_array {LAtomicName}.prog.actions;\\n\";\n            str += indent(1) + $\"hprog_actions_array = list_to_array {HAtomicName}.prog.actions;\\n\";\n            str += indent(1) + \"vs = vs;\\n\";\n            str += indent(1) + \"tds = tds;\\n\";\n            str += indent(1) + $\"inv = {HAtomicInvariantName}.inv;\\n\";\n            str += indent(1) + \"which_initializers_are_intros = which_initializers_are_intros;\\n\";\n            str += indent(1) + \"lpcs = lpcs;\\n\";\n            str += indent(1) + \"hpcs = hpcs;\\n\";\n            str += indent(1) + \"hpc_to_lpc = hpc_to_lpc;\\n\";\n            str += indent(1) + \"lpc_to_hpcs = lpc_to_hpcs;\\n\";\n            str += indent(1) + \"is_return_hpc = is_return_hpc;\\n\";\n            str += indent(1) + \"is_nonyielding_lpc = is_nonyielding_lpc;\\n\";\n            str += indent(1) + \"is_nonyielding_hpc = is_nonyielding_hpc;\\n\";\n            str += indent(1) + \"is_breaking_hpc = is_breaking_hpc;\\n\";\n            str += indent(1) + \"hpc_info = hpc_info;\\n\";\n            str += indent(1) + \"corresponding_hactions_info = corresponding_hactions_info;\\n\";\n            str += indent(1) + \"lprog_main_start_pc_index = lprog_main_start_pc_index;\\n\";\n            str += indent(1) + \"hprog_main_start_pc_index = hprog_main_start_pc_index;\\n\";\n            str += indent(1) + \"lpc_indices_array = lpc_indices_array;\\n\";\n            str += indent(1) + \"hpc_indices_array = hpc_indices_array;\\n\";\n            str += indent(0) + \"}\\n\\n\";\n\n            str += indent(0) + $\"let lemma_{LAtomicName}Refines{HAtomicName}()\\n\";\n            str += indent(1) + \": Lemma (spec_refines_spec\\n\";\n            str += indent(5) + $\"(semantics_to_spec (make_atomic_semantics armada_semantics) {LAtomicName}.prog)\\n\";\n            str += indent(5) + $\"(semantics_to_spec (make_atomic_semantics armada_semantics) {HAtomicName}.prog)\\n\";\n            str += indent(5) + $\"refinement_requirement) =\\n\";\n            str += indent(1) + $\"let latomic_prog = {LAtomicName}.prog in\\n\";\n            str += indent(1) + $\"let hatomic_prog = {HAtomicName}.prog in\\n\";\n            str += indent(1) + \"assert (efficient_var_intro_witness_valid latomic_prog hatomic_prog vw)\\n\";\n            str += indent(2) + \"by (FStar.Tactics.compute (); FStar.Tactics.trivial ());\\n\";\n            str += indent(1) + $\"{HAtomicInvariantName}.inv_is_stepwise_invariant ();\\n\";\n            str += indent(1) + \"efficient_var_intro_witness_valid_implies_refinement latomic_prog hatomic_prog vw\\n\\n\";\n\n            return str;\n        }\n\n        public string GetInvariant(ProofDecl proof, LevelDecl L, LevelDecl H, int indentation)\n        {\n            Func<int, string> indent = (int i) => new string(' ', indentation + i * 2);\n            string str = \"\";\n            var HName = H.Name.ToString(0, false);\n            var HAtomicName = \"Atomic\" + HName;\n            Scope sc = H.Sc;\n            List<Ident> vars = new();\n            if (proof.Strategy is VarIntroStrategy varIntroStrategy) {\n                vars = varIntroStrategy.Variables;\n            } else if (proof.Strategy is VarHidingStrategy varHidingStrategy) {\n                vars = varHidingStrategy.Variables;\n            } else {\n                throw new NotSupportedException();\n            }\n            var HSpec = new AtomicSpec(H);\n\n            List<VarDecl> introVars = new();\n            List<VarDecl> invariantVars = new();\n            foreach (Ident introvar in vars)\n            {\n                VarDecl vardecl = sc.GetVariableDecl(introvar, false);\n                introVars.Add(vardecl);\n            }\n            foreach (var entity in sc.DefinedEntities)\n            {\n                if (entity is VarDecl vardecl && !introVars.Contains(vardecl))\n                {\n                    invariantVars.Add(vardecl);\n                }\n            }\n\n            str += indent(0) + \"let inv (s: Armada.State.t) : GTot ubool = true\\n\";\n            foreach (var invvar in invariantVars)\n            {\n                str += indent(1) + $\"/\\\\ gvar_has_type s.mem \\\"{invvar.Name.Name}\\\" ({invvar.Ty.ToFStarLang(0, true)})\\n\";\n            }\n            str += '\\n';\n\n            str += indent(0) + \"private let action_pred (action: Armada.Action.t) : GTot ubool = True\\n\\n\";\n\n            str += indent(0) + \"#push-options \\\"--z3rlimit 10 --z3cliopt smt.qi.eager_threshold=100\\\"\\n\\n\";\n\n            str += indent(0) + \"private let atomic_bprog_init_establishes_inv\\n\";\n            str += indent(1) + $\"(s: Armada.State.t{{(semantics_to_spec (make_atomic_semantics armada_semantics) {HAtomicName}.prog).init s}})\\n\";\n            str += indent(1) + \": squash (inv s) =\\n\";\n            str += indent(1) + \"()\\n\\n\";\n\n            str += indent(0) + \"private let action_pred_preserves_inv\\n\";\n            str += indent(1) + \"(actor: tid_t)\\n\";\n            str += indent(1) + \"(starts_atomic_block: bool)\\n\";\n            str += indent(1) + \"(ends_atomic_block: bool)\\n\";\n            str += indent(1) + \"(step: Armada.Step.t)\\n\";\n            str += indent(1) + \"(s: Armada.State.t{\\n\";\n            str += indent(2) + \"Some? (step_computation actor starts_atomic_block ends_atomic_block step s)\\n\";\n            str += indent(2) + \"/\\\\ action_pred step.action\\n\";\n            str += indent(2) + \"/\\\\ inv s})\\n\";\n            str += indent(1) + \": squash (inv (Some?.v (step_computation actor starts_atomic_block ends_atomic_block step s))) =\\n\";\n            str += indent(1) + \"step_computation_maintains_all_gvars_have_types\\n\";\n            str += indent(2) + $\"[{String.Join(\"; \", invariantVars.ConvertAll(vardecl => \"\\\"\" + vardecl.Name.Name + \"\\\"\"))}]\\n\";\n            str += indent(2) + $\"[{String.Join(\"; \", invariantVars.ConvertAll(vardecl => vardecl.Ty.ToFStarLang(0, true)))}]\\n\";\n            str += indent(2) + \"actor starts_atomic_block ends_atomic_block step s\\n\\n\";\n\n            str += indent(0) + \"#pop-options\\n\\n\";\n\n            str += indent(0) + \"private let my_special_case_proofs\\n\";\n            str += indent(1) + \": list (list (option (armada_action_special_case_invariant_proof_t inv))) =\\n\";\n            str += indent(1) + \"[\\n\";\n            foreach (var action in HSpec.Actions)\n            {\n                str += indent(2) + $\"[{String.Join(\"; \", action.Stmts.ConvertAll(stmt => \"None\"))}];\\n\";\n            }\n            str += indent(1) + \"]\\n\\n\";\n\n            str += indent(0) + $\"let inv_witness () : armada_atomic_substep_invariant_witness_t {HAtomicName}.prog inv =\\n\";\n            str += indent(1) + \"{\\n\";\n            str += indent(2) + \"action_pred = action_pred;\\n\";\n            str += indent(2) + \"special_case_proofs = my_special_case_proofs;\\n\";\n            str += indent(2) + \"init_implies_inv_proof = atomic_bprog_init_establishes_inv;\\n\";\n            str += indent(2) + \"action_proof = action_pred_preserves_inv;\\n\";\n            str += indent(1) + \"}\\n\\n\";\n\n            str += indent(0) + \"let inv_is_stepwise_invariant ()\\n\";\n            str += indent(1) + $\": Lemma (is_armada_substep_invariant {HAtomicName}.prog inv) =\\n\";\n            str += indent(1) + \"let aiw = inv_witness () in\\n\";\n            str += indent(1) + $\"assert (armada_atomic_substep_invariant_witness_valid {HAtomicName}.prog inv aiw)\\n\";\n            str += indent(2) + \"by (FStar.Tactics.compute(); FStar.Tactics.trivial ());\\n\";\n            str += indent(1) + $\"armada_atomic_substep_invariant_witness_valid_implies_is_substep_invariant {HAtomicName}.prog inv aiw\\n\\n\";\n            return str;\n        }\n    }\n}\n"
  },
  {
    "path": "experimental/Source/Armada/Proof/WeakeningPrinter.cs",
    "content": "using System;\nusing System.IO;\nusing System.Linq;\nusing System.Collections.Generic;\n\nnamespace Microsoft.Starmada\n{\n    class WeakeningPrinter : StrategyPrinter\n    {\n        public string GetProof(ProofDecl proof, LevelDecl L, LevelDecl H, int indentation)\n        {\n            Func<int, string> indent = (int i) => new string(' ', indentation + i * 2);\n            string str = \"\";\n            var LName = L.Name.ToString(0, false);\n            var LAtomicName = \"Atomic\" + LName;\n            var HName = H.Name.ToString(0, false);\n            var HAtomicName = \"Atomic\" + HName;\n            AtomicPrinter atomicPrinter = new AtomicPrinter();\n            WeakeningProofSpec proofSpec = new WeakeningProofSpec(L, H);\n\n            var updateIndices = proofSpec.WeakeningUpdateIndices;\n            foreach (int index in updateIndices)\n            {\n                str += indent(0) + $\"private let my_special_case_action_{index} : list Armada.Action.t =\\n\";\n                str += atomicPrinter.ToFStarAtomic(proofSpec.LS.Actions[index], 2) + \"\\n\\n\";\n            }\n            foreach (int index in updateIndices)\n            {\n                str += indent(0) + $\"private let my_special_case_steps_updater_{index}\\n\";\n                str += indent(1) + \"(actor: tid_t) (steps: list Armada.Step.t) (s: Armada.State.t)\\n\";\n                str += indent(1) + \": nat * (list Armada.Step.t) =\\n\";\n                var action = proofSpec.HS.Actions[index];\n                List<string> steps = new();\n                for (int i = 0; i < action.Stmts.Count; i++)\n                {\n                    steps.Add($\"step{i}\");\n                    str += indent(1) + $\"let step{i}: Armada.Step.t = \\n\";\n                    str += indent(2) + \"{\\n\";\n                    str += indent(3) + \"nd = [];\\n\";\n                    str += indent(3) + \"action =\\n\";\n                    str += atomicPrinter.ToFStarAtomic(\n                        action.Stmts[i], indentation + 6,\n                        !(action.FailAtTheEnd && i + 1 == action.Stmts.Count)\n                    ) + '\\n';\n                    str += indent(2) + \"}\";\n                    str += ((i + 1 == action.Stmts.Count) ? \"\" : \";\") + \"\\n\";\n                    str += indent(1) + \"in\\n\";\n                }\n                str += indent(1) + $\"({index}, [{string.Join(';', steps)}])\\n\\n\";\n            }\n\n            str += indent(0) + \"#push-options \\\"--z3rlimit 20 --fuel 4\\\"\\n\\n\";\n\n            foreach (int index in updateIndices)\n            {\n                str += indent(0) + $\"private let my_special_case_steps_updater_satisfies_weakening_{index}\\n\";\n                str += indent(1) + \"(actor: tid_t) (starts_atomic_block: bool) (ends_atomic_block: bool) (lsteps: list Armada.Step.t) (haction_index: nat) (hsteps: list Armada.Step.t) (s: Armada.State.t)\\n\";\n                str += indent(1) + $\": Lemma (requires   (FStar.List.Tot.map armada_step_to_action lsteps == my_special_case_action_{index})\\n\";\n                str += indent(8) + \"/\\\\ (my_inv s)\\n\";\n                str += indent(8) + \"/\\\\ (Some? (steps_computation actor starts_atomic_block ends_atomic_block lsteps s))\\n\";\n                str += indent(8) + $\"/\\\\ ((haction_index, hsteps) == my_special_case_steps_updater_{index} actor lsteps s))\\n\";\n                str += indent(5) + \"(ensures  (  (Some? (steps_computation actor starts_atomic_block ends_atomic_block hsteps s))\\n\";\n                str += indent(8) + \"/\\\\ (steps_computation actor starts_atomic_block ends_atomic_block lsteps s ==\\n\";\n                str += indent(10) + \"steps_computation actor starts_atomic_block ends_atomic_block hsteps s)\\n\";\n                str += indent(8) + $\"/\\\\ nth {HAtomicName}.prog.actions haction_index ==\\n\";\n                str += indent(8) + \"Some (map_ghost armada_step_to_action hsteps))) =\\n\";\n                str += indent(1) + \"()\\n\\n\";\n            }\n\n            str += indent(0) + \"#pop-options\\n\\n\";\n\n            foreach (int index in updateIndices)\n            {\n                str += indent(0) + $\"private let my_special_case_steps_updater_works_{index} ()\\n\";\n                str += indent(1) + $\": squash (armada_steps_updater_works (list_to_array {HAtomicName}.prog.actions) my_inv my_special_case_action_{index}\\n\";\n                str += indent(6) + $\"my_special_case_steps_updater_{index}) =\\n\";\n                str += indent(1) + $\"let hatomic_action_array = list_to_array {HAtomicName}.prog.actions in\\n\";\n                str += indent(1) + \"introduce forall (actor: tid_t) (starts_atomic_block: bool) (ends_atomic_block: bool) (lsteps: list Armada.Step.t) (s: Armada.State.t).\\n\";\n                str += indent(3) + $\"map_ghost armada_step_to_action lsteps == my_special_case_action_{index}\\n\";\n                str += indent(2) + \"/\\\\ my_inv s\\n\";\n                str += indent(2) + \"/\\\\ Some? (steps_computation actor starts_atomic_block ends_atomic_block lsteps s)\\n\";\n                str += indent(2) + \"==>\\n\";\n                str += indent(2) + $\"( let hatomic_action_idx, hsteps = my_special_case_steps_updater_{index} actor lsteps s in\\n\";\n                str += indent(3) + \"let haction = map_ghost armada_step_to_action hsteps in\\n\";\n                str += indent(4) + \"hatomic_action_idx < array_len hatomic_action_array\\n\";\n                str += indent(3) + \"/\\\\ array_index hatomic_action_array hatomic_action_idx == haction\\n\";\n                str += indent(3) + \"/\\\\ (steps_computation actor starts_atomic_block ends_atomic_block hsteps s ==\\n\";\n                str += indent(5) + \"steps_computation actor starts_atomic_block ends_atomic_block lsteps s))\\n\";\n                str += indent(1) + \"with introduce _ ==> _\\n\";\n                str += indent(1) + \"with _.\\n\";\n                str += indent(2) + $\"let hatomic_action_idx, hsteps = my_special_case_steps_updater_{index} actor lsteps s in\\n\";\n                str += indent(2) + $\"list_to_array_implies_nth_equivalent hatomic_action_array {HAtomicName}.prog.actions hatomic_action_idx;\\n\";\n                str += indent(2) + $\"my_special_case_steps_updater_satisfies_weakening_{index} actor starts_atomic_block ends_atomic_block\\n\";\n                str += indent(3) + \"lsteps hatomic_action_idx hsteps s\\n\\n\";\n            }\n            \n            str += indent(0) + \"private let my_weakening_transformers\\n\";\n            str += indent(1) + $\": list (armada_weakening_transformer_t (list_to_array {HAtomicName}.prog.actions) my_inv) =\\n\";\n            str += indent(1) + \"[\\n\";\n            var Transformers = proofSpec.WeakeningTrans;\n            for (int i = 0; i < Transformers.Count; i++)\n            {\n                str += indent(2) + Transformers[i] + ((i == Transformers.Count - 1) ? \"\": \";\") + \"\\n\";\n            }\n            str += indent(1) + \"]\\n\\n\";\n\n            str += indent(0) + $\"let lemma_{LAtomicName}_refines_{HAtomicName} ()\\n\";\n            str += indent(1) + $\": Lemma (spec_refines_spec\\n\";\n            str += indent(5) + $\"(semantics_to_spec (make_atomic_semantics armada_semantics) {LAtomicName}.prog)\\n\";\n            str += indent(5) + $\"(semantics_to_spec (make_atomic_semantics armada_semantics) {HAtomicName}.prog)\\n\";\n            str += indent(5) + $\"eq2) =\\n\";\n            str += indent(2) + $\"let ww: armada_weakening_witness_t {LAtomicName}.prog {HAtomicName}.prog = {{\\n\";\n            str += indent(3) + $\"inv = my_inv;\\n\";\n            str += indent(3) + $\"hatomic_action_array = list_to_array {HAtomicName}.prog.actions;\\n\";\n            str += indent(3) + $\"weakening_transformers = my_weakening_transformers;\\n\";\n            str += indent(3) + $\"init_implies_init_proof = (fun _ -> ());\\n\";\n            str += indent(2) + $\"}} in\\n\";\n            str += indent(2) + $\"assert (armada_weakening_witness_valid {LAtomicName}.prog {HAtomicName}.prog ww)\\n\";\n            str += indent(3) + $\"by (compute (); trivial ());\\n\";\n            str += indent(2) + \"my_inv_is_stepwise_invariant ();\\n\";\n            str += indent(2) + $\"armada_weakening_witness_valid_implies_refinement {LAtomicName}.prog {HAtomicName}.prog ww\\n\\n\";\n\n            str += indent(0) + $\"let lemma_{LName}_refines_{HName} ()\\n\";\n            str += indent(1) + $\": Lemma (spec_refines_spec\\n\";\n            str += indent(5) + $\"(program_to_spec {LName}.prog)\\n\";\n            str += indent(5) + $\"(program_to_spec {HName}.prog)\\n\";\n            str += indent(5) + $\"eq2) =\\n\";\n            str += indent(1) + $\"lemma_{LName}_refines_{LAtomicName} ();\\n\";\n            str += indent(1) + $\"lemma_{LAtomicName}_refines_{HAtomicName} ();\\n\";\n            str += indent(1) + $\"lemma_{HAtomicName}_refines_{HName} ();\\n\";\n            str += indent(1) + $\"spec_refinement_transitivity_4\\n\";\n            str += indent(2) + $\"(program_to_spec {LName}.prog)\\n\";\n            str += indent(2) + $\"(semantics_to_spec (make_atomic_semantics armada_semantics) {LAtomicName}.prog)\\n\";\n            str += indent(2) + $\"(semantics_to_spec (make_atomic_semantics armada_semantics) {HAtomicName}.prog)\\n\";\n            str += indent(2) + $\"(program_to_spec {HName}.prog)\\n\";\n            str += indent(2) + $\"eq2\\n\";\n            str += indent(2) + $\"eq2\\n\";\n            str += indent(2) + $\"eq2\\n\";\n            str += indent(2) + $\"eq2\\n\";\n            str += indent(2) + $\"eq2\\n\";\n            return str;\n        }\n\n        public string GetInvariant(ProofDecl proof, LevelDecl L, LevelDecl H, int indentation)\n        {\n            Func<int, string> indent = (int i) => new string(' ', indentation + i * 2);\n            string str = \"\";\n            var LName = L.Name.ToString(0, false);\n            var LAtomicName = \"Atomic\" + LName;\n            var HName = H.Name.ToString(0, false);\n            var HAtomicName = \"Atomic\" + HName;\n            AtomicSpec atomicSpecL = new AtomicSpec(L);\n\n            str += indent(0) + \"let my_inv (s: Armada.State.t) : GTot ubool = true\\n\\n\";\n\n            str += indent(0) + \"private let my_action_pred (action: Armada.Action.t) : GTot ubool = true\\n\\n\";\n\n            str += indent(0) + \"private let my_special_case_proofs\\n\";\n            str += indent(1) + \": list (option (armada_atomic_special_case_invariant_proof_t my_inv)) =\\n\";\n            str += indent(1) + \"[\\n\";\n            for (int i = 0; i < atomicSpecL.Actions.Count; i++)\n            {\n                str += indent(2) + \"None\" + (i + 1 == atomicSpecL.Actions.Count ? \"\" : \";\") + '\\n';\n            }\n            str += indent(1) + \"]\\n\\n\";\n\n            str += indent(0) + \"private let atomic_lprog_init_establishes_my_inv\\n\";\n            str += indent(1) + $\"(s: Armada.State.t{{(semantics_to_spec (make_atomic_semantics armada_semantics) {LAtomicName}.prog).init s}})\\n\";\n            str += indent(1) + \": squash (my_inv s) = ()\\n\\n\";\n\n            str += indent(0) + \"private let my_action_pred_preserves_my_inv\\n\";\n            str += indent(1) + \"(actor: tid_t)\\n\";\n            str += indent(1) + \"(starts_atomic_block: bool)\\n\";\n            str += indent(1) + \"(ends_atomic_block: bool)\\n\";\n            str += indent(1) + \"(step: Armada.Step.t)\\n\";\n            str += indent(1) + \"(s: Armada.State.t{\\n\";\n            str += indent(3) + \"Some? (step_computation actor starts_atomic_block ends_atomic_block step s)\\n\";\n            str += indent(2) + \"/\\\\ my_action_pred step.action\\n\";\n            str += indent(2) + \"/\\\\ my_inv s})\\n\";\n            str += indent(1) + \": squash (my_inv (Some?.v (step_computation actor starts_atomic_block ends_atomic_block step s))) = ()\\n\\n\";\n\n            str += indent(0) + $\"let my_inv_witness () : armada_atomic_semantics_invariant_witness_t {LAtomicName}.prog my_inv =\\n\";\n            str += indent(1) + \"{\\n\";\n            str += indent(2) + \"action_pred = my_action_pred;\\n\";\n            str += indent(2) + \"special_case_proofs = my_special_case_proofs;\\n\";\n            str += indent(2) + \"init_implies_inv_proof = atomic_lprog_init_establishes_my_inv;\\n\";\n            str += indent(2) + \"action_proof = my_action_pred_preserves_my_inv;\\n\";\n            str += indent(1) + \"}\\n\\n\";\n\n            str += indent(0) + \"let my_inv_is_stepwise_invariant ()\\n\";\n            str += indent(1) + \": Lemma (semantics_has_stepwise_inductive_invariant (make_atomic_semantics armada_semantics)\\n\";\n            str += indent(5) + $\"{LAtomicName}.prog my_inv) =\\n\";\n            str += indent(1) + \"let aiw = my_inv_witness () in\\n\";\n            str += indent(1) + $\"assert (armada_atomic_semantics_invariant_witness_valid {LAtomicName}.prog my_inv aiw)\\n\";\n            str += indent(2) + \"by (FStar.Tactics.compute (); FStar.Tactics.trivial ());\\n\";\n            str += indent(1) + $\"armada_atomic_semantics_invariant_witness_valid_implies_stepwise_invariant {LAtomicName}.prog my_inv aiw\\n\";\n            return str;\n        }\n    }\n}\n"
  },
  {
    "path": "experimental/Source/Armada/Proof/WeakeningSpec.cs",
    "content": ""
  },
  {
    "path": "experimental/Source/Armada/Reporting.cs",
    "content": "// Copyright by the contributors to the Dafny Project\n// SPDX-License-Identifier: MIT\n\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics.Contracts;\nusing System.Linq;\nusing System.Text;\n\nnamespace Microsoft.Starmada {\n  public enum ErrorLevel {\n    Info, Warning, Error\n  }\n\n  public enum MessageSource {\n    Parser, Resolver \n  }\n\n  public struct ErrorMessage {\n    public Token token;\n    public string message;\n    public MessageSource source;\n  }\n\n  public abstract class ErrorReporter {\n    public bool ErrorsOnly { get; set; }\n\n    public bool HasErrors => ErrorCount > 0;\n    public int ErrorCount => Count(ErrorLevel.Error);\n\n\n    public abstract bool Message(MessageSource source, ErrorLevel level, Token tok, string msg);\n\n    public void Error(MessageSource source, Token tok, string msg) {\n      Contract.Requires(tok != null);\n      Contract.Requires(msg != null);\n      Message(source, ErrorLevel.Error, tok, msg);\n    }\n\n    public abstract int Count(ErrorLevel level);\n\n    // This method required by the Parser\n    internal void Error(MessageSource source, string filename, int line, int col, string msg) {\n      var tok = new Token();\n      tok.line = line;\n      tok.col = col;\n      Error(source, tok, msg);\n    }\n\n    public void Error(MessageSource source, Token tok, string msg, params object[] args) {\n      Contract.Requires(tok != null);\n      Contract.Requires(msg != null);\n      Contract.Requires(args != null);\n      Error(source, tok, String.Format(msg, args));\n    }\n\n    public void Error(MessageSource source, Statement s, string msg, params object[] args) {\n      Contract.Requires(s != null);\n      Contract.Requires(msg != null);\n      Contract.Requires(args != null);\n      Error(source, s.FirstTok, msg, args);\n    }\n\n    public void Error(MessageSource source, Expr e, string msg, params object[] args) {\n      Contract.Requires(e != null);\n      Contract.Requires(msg != null);\n      Contract.Requires(args != null);\n      Error(source, e.FirstTok, msg, args);\n    }\n\n    public void Warning(MessageSource source, Token tok, string msg) {\n      Contract.Requires(tok != null);\n      Contract.Requires(msg != null);\n      Message(source, ErrorLevel.Warning, tok, msg);\n    }\n\n    public void Warning(MessageSource source, int line, int col, string msg) {\n        Contract.Requires(msg != null);\n        Token tok = new Token();\n        tok.line = line;\n        tok.col = col;\n        Message(source, ErrorLevel.Warning, tok, msg);\n    }\n\n    public void Warning(MessageSource source, Token tok, string msg, params object[] args) {\n      Contract.Requires(tok != null);\n      Contract.Requires(msg != null);\n      Contract.Requires(args != null);\n      Warning(source, tok, String.Format(msg, args));\n    }\n\n    public void Info(MessageSource source, Token tok, string msg) {\n      Contract.Requires(tok != null);\n      Contract.Requires(msg != null);\n      Message(source, ErrorLevel.Info, tok, msg);\n    }\n\n    public void Info(MessageSource source, Token tok, string msg, params object[] args) {\n      Contract.Requires(tok != null);\n      Contract.Requires(msg != null);\n      Contract.Requires(args != null);\n      Info(source, tok, String.Format(msg, args));\n    }\n\n    public static string ErrorToString(ErrorLevel header, Token tok, string msg) {\n      return String.Format(\"{0}: {1}{2}\", TokenToString(tok), header.ToString(), \": \" + msg);\n    }\n\n    public static string TokenToString(Token tok) {\n      return String.Format(\"{0}({1},{2})\", tok.val, tok.line, tok.col - 1);\n    }\n  }\n\n  public abstract class BatchErrorReporter : ErrorReporter {\n    private readonly Dictionary<ErrorLevel, List<ErrorMessage>> allMessages;\n\n    protected BatchErrorReporter() {\n      ErrorsOnly = false;\n      allMessages = new Dictionary<ErrorLevel, List<ErrorMessage>> {\n        [ErrorLevel.Error] = new(),\n        [ErrorLevel.Warning] = new(),\n        [ErrorLevel.Info] = new()\n      };\n    }\n\n    public override bool Message(MessageSource source, ErrorLevel level, Token tok, string msg) {\n      if (ErrorsOnly && level != ErrorLevel.Error) {\n        // discard the message\n        return false;\n      }\n      allMessages[level].Add(new ErrorMessage { token = tok, message = msg });\n      return true;\n    }\n\n    public override int Count(ErrorLevel level) {\n      return allMessages[level].Count;\n    }\n  }\n\n  public class ConsoleErrorReporter : BatchErrorReporter {\n    private ConsoleColor ColorForLevel(ErrorLevel level) {\n      switch (level) {\n        case ErrorLevel.Error:\n          return ConsoleColor.Red;\n        case ErrorLevel.Warning:\n          return ConsoleColor.Yellow;\n        case ErrorLevel.Info:\n          return ConsoleColor.Green;\n        default:\n          throw new Exception();\n      }\n    }\n\n    public override bool Message(MessageSource source, ErrorLevel level, Token tok, string msg) {\n      if (base.Message(source, level, tok, msg) && level != ErrorLevel.Info) {\n        // Extra indent added to make it easier to distinguish multiline error messages for clients that rely on the CLI\n        msg = msg.Replace(Environment.NewLine, Environment.NewLine + \" \");\n\n        ConsoleColor previousColor = Console.ForegroundColor;\n        Console.ForegroundColor = ColorForLevel(level);\n        var errorLine = ErrorToString(level, tok, msg);\n        Console.WriteLine(errorLine);\n\n        Console.ForegroundColor = previousColor;\n        return true;\n      } else {\n        return false;\n      }\n    }\n  }\n\n  public class ErrorReporterSink : ErrorReporter {\n    public ErrorReporterSink() { }\n\n    public override bool Message(MessageSource source, ErrorLevel level, Token tok, string msg) {\n      return false;\n    }\n\n    public override int Count(ErrorLevel level) {\n      return 0;\n    }\n  }\n\n  public class ErrorReporterWrapper : BatchErrorReporter {\n\n    private string msgPrefix;\n    public readonly ErrorReporter WrappedReporter;\n\n    public ErrorReporterWrapper(ErrorReporter reporter, string msgPrefix) {\n      this.msgPrefix = msgPrefix;\n      this.WrappedReporter = reporter;\n    }\n\n    public override bool Message(MessageSource source, ErrorLevel level, Token tok, string msg) {\n      base.Message(source, level, tok, msg);\n      return WrappedReporter.Message(source, level, tok, msgPrefix + msg);\n    }\n  }\n}"
  },
  {
    "path": "experimental/Source/Armada/Resolver.cs",
    "content": "using System.Collections.Generic;\n\nnamespace Microsoft.Starmada\n{\n    public class Resolver\n    {\n        public DatatypeDecl GetStopReasonDatatypeDecl()\n        {\n            DatatypeDecl StopReasonDatatype = new DatatypeDecl(new Token(),\n                new UserDefinedType(new Ident(new Token(), \"stop_reason_t\")));\n            return StopReasonDatatype;\n        }\n        public StructDecl GetArmadaStateStructDecl()\n        {\n            StructDecl ArmadaStateStructure = new StructDecl(new Token(), new Ident(new Token(), \"Armada.State.t\"));\n            ArmadaStateStructure.Decls.Add(\n                new VarDecl(new Token(), new Ident(new Token(), \"initial_tid\"),\n                            new PredefinedType(PredefinedTypeEnum.ThreadId),\n                            null, true, true, true, true));\n            ArmadaStateStructure.Decls.Add(\n                new VarDecl(new Token(), new Ident(new Token(), \"uniqs_used\"),\n                            new SeqType(new PredefinedType(PredefinedTypeEnum.Nat)),\n                            null, true, true, true, true));\n            ArmadaStateStructure.Decls.Add(\n                new VarDecl(new Token(), new Ident(new Token(), \"stop_reason\"),\n                            new UserDefinedType(new Ident(new Token(), \"stop_reason_t\")),\n                            null, true, true, true, true));\n            return ArmadaStateStructure;\n        }\n        public void Resolve(StarmadaProgram program)\n        {\n            program.Sc = new Scope(null);\n            program.Sc.EnclosingNode = program;\n            program.Sc.Push(GetStopReasonDatatypeDecl());\n            program.Sc.Push(GetArmadaStateStructDecl());\n            program.Sc.Push(new VarDecl(new Token(), new Ident(new Token(), \"$state\"), new UserDefinedType(new Ident(new Token(), \"Armada.State.t\")), null, true, true, true));\n            program.TypeResolve(null, ref program.errors);\n        }\n    }\n\n    public class ProofResolver\n    {\n        // Proofs ordered from lower to upper\n        public List<ProofDecl> ProofRefinements;\n        public Dictionary<string, LevelDecl> Levels;\n        // Proofs indexed by lower level name\n        Dictionary<string, ProofDecl> Proofs;\n        Dictionary<string, string> Refinement;\n        HashSet<string> RefinementL;\n        HashSet<string> RefinementH;\n        string L = null;\n        string H = null;\n        public void Resolve(StarmadaProgram program)\n        {\n            ProofRefinements = new();\n            Levels = new();\n            Proofs = new();\n            Refinement = new();\n            RefinementL = new();\n            RefinementH = new();\n            foreach (var level in program.Levels)\n            {\n                Levels[level.Name.Name] = level;\n            }\n            foreach (var proof in program.Proofs)\n            {\n                string l = proof.LLevelName.Name;\n                string h = proof.HLevelName.Name;\n                if (!Levels.ContainsKey(l))\n                {\n                    program.errors.SemErr(new Token(), \"Cannot find level: \" + l);\n                    return;\n                }\n                if (!Levels.ContainsKey(h))\n                {\n                    program.errors.SemErr(new Token(), \"Cannot find level: \" + h);\n                    return;\n                }\n                if (Refinement.ContainsKey(l))\n                {\n                    program.errors.SemErr(new Token(), \"Refinement on the same level for multiple times: \" + l);\n                    return;\n                }\n                Refinement[l] = h;\n                RefinementL.Add(l);\n                RefinementH.Add(h);\n                Proofs[l] = proof;\n            }\n            HashSet<string> Ls = new(RefinementL);\n            Ls.ExceptWith(RefinementH);\n            if (Ls.Count > 1)\n            {\n                program.errors.SemErr(new Token(), \"There are multiple refinement levels that are lowerest levels: \" + string.Join(\", \", Ls));\n                return;\n            }\n            if (Ls.Count == 0)\n            {\n                if (RefinementL.Count > 0)\n                {\n                    program.errors.SemErr(new Token(), \"There are no refinement levels that are lowest levels\");\n                }\n                return;\n            }\n\n            foreach (var lowest in Ls)\n            {\n                L = lowest;\n            }\n            string next = L;\n            while (Refinement.ContainsKey(next))\n            {\n                ProofRefinements.Add(Proofs[next]);\n                next = Refinement[next];\n            }\n            H = next;\n        }\n\n        public LevelDecl GetLLevel()\n        {\n            if (L == null || !Levels.ContainsKey(L))\n                return null;\n            return Levels[L];\n        }\n\n        public LevelDecl GetHLevel()\n        {\n            if (H == null || !Levels.ContainsKey(H))\n                return null;\n            return Levels[H];\n        }\n    }\n}\n"
  },
  {
    "path": "experimental/Source/Armada/Starmada.atg",
    "content": "using System.Collections.Generic;\nusing System.Numerics;\nusing System.IO;\nusing System.Text;\nCOMPILER Starmada\n\npublic StarmadaProgram program;\n\n// Trigger build\npublic Parser(Scanner/*!*/ scanner, string name)\n  : this(scanner)\n{\n  this.reporter = new ConsoleErrorReporter();\n  this.errors = new Errors(name, this.reporter);\n  Token tmpTok = new Token();\n  program = new StarmadaProgram(tmpTok, name, this.errors, this.reporter);\n}\n\nbool IsIdentParen() {\n  scanner.ResetPeek();\n  Token x = scanner.Peek();\n  return la.kind == _ident && x.kind == _openparen;\n}\n\nbool IsDigit() {\n  return (la.kind == _digits);\n}\n\nbool IsOpenAngleBracket() {\n  return la.kind == _openAngleBracket;\n}\n\nbool StarFollowedByCommaSemiOrOpenBrace() {\n  if (la.kind != _star) {\n    return false;\n  }\n  Token x = scanner.Peek();\n  return (x.kind == _comma || x.kind == _semi || x.kind == _lbrace);\n}\n\nbool IsParenStar() {\n  scanner.ResetPeek();\n  Token x = scanner.Peek();\n  return la.kind == _openparen && x.kind == _star;\n}\n\nbool IsEqualSign() {\n  return la.kind == _equalsign;\n}\nbool IsEquivOp() {\n  return la.val == \"<==>\" || la.val == \"\\u21d4\";\n}\nbool IsImpliesOp() {\n  return la.val == \"==>\" || la.val == \"\\u21d2\";\n}\nbool IsExpliesOp() {\n  return la.val == \"<==\" || la.val == \"\\u21d0\";\n}\nbool IsAndOp() {\n  return la.val == \"&&\" || la.val == \"\\u2227\";\n}\nbool IsOrOp() {\n  return la.val == \"||\" || la.val == \"\\u2228\";\n}\nbool IsBitwiseAndOp() {\n  return la.val == \"&\";\n}\nbool IsBitwiseOrOp() {\n  return la.val == \"|\";\n}\nbool IsBitwiseXorOp() {\n  return la.val == \"^\";\n}\nbool IsBitwiseOp() {\n  return IsBitwiseAndOp() || IsBitwiseOrOp() || IsBitwiseXorOp();\n}\nbool IsAs() {\n  return la.kind == _as;\n}\nbool IsRelOp() {\n  return la.val == \"==\"\n      || la.val == \"<\"\n      || la.val == \">\"\n      || la.val == \"<=\"\n      || la.val == \">=\"\n      || la.val == \"!=\"\n      || la.val == \"in\"\n      || la.kind == _notIn\n      || la.val ==\"!!\";\n}\nbool IsShiftOp() {\n  if (la.kind == _openAngleBracket) {\n  } else if (la.kind == _closeAngleBracket) {\n  } else {\n    return false;\n  }\n  scanner.ResetPeek();\n  var x = scanner.Peek();\n  if (x.kind != la.kind) {\n    return false;\n  }\n  return x.pos == la.pos + 1;  // return true only if the tokens are adjacent to each other\n}\nbool IsAddOp() {\n  return la.val == \"+\" || la.val == \"-\";\n}\nbool IsMulOp() {\n  return la.kind == _star || la.val == \"/\" || la.val == \"%\";\n}\nbool IsQSep() {\n  return la.kind == _doublecolon || la.kind == _bullet;\n}\nbool IsMapDisplay() {\n  scanner.ResetPeek();\n  return la.kind == _map && scanner.Peek().kind == _lbracket;\n}\nbool IsIMapDisplay() {\n  scanner.ResetPeek();\n  return la.kind == _imap && scanner.Peek().kind == _lbracket;\n}\nbool IsISetDisplay() {\n  scanner.ResetPeek();\n  return la.kind == _iset && scanner.Peek().kind == _lbrace;\n}\nbool IsNotEndOfCase() {\n  return la.kind != _EOF && la.kind != _rbrace && la.kind != _case;\n}\n\n\n/*--------------------------------------------------------------------------*/\nCHARACTERS\n  letter = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\".\n  digit = \"0123456789\".\n  posDigit = \"123456789\".\n  hexdigit = \"0123456789ABCDEFabcdef\".\n  special = \"'_?\".\n  glyph = \"`~!@#$%^&*()-_=+[{]}|;:',<.>/?\\\\\".\n  cr        = '\\r'.\n  lf        = '\\n'.\n  tab       = '\\t'.\n  space = ' '.\n  nondigit = letter + special.\n  idchar = nondigit + digit.\n  nonidchar = ANY - idchar.\n  /* exclude the characters in 'array' and '\\'' */\n  nondigitMinusBTick = nondigit - 'b' - '\\''.\n  nondigitMinusQuery = nondigit - '?'.\n  idcharMinusV = idchar - 'v'.\n  idcharMinusPosDigitMinusQuery = idchar - posDigit - '?'.\n  idcharMinusTick = idchar - '\\''.\n  /* string literals */\n  charChar = ANY - '\\'' - '\\\\' - cr - lf.\n  stringChar = ANY - '\"' - '\\\\' - cr - lf.\n  verbatimStringChar = ANY - '\"'.\n\n/*------------------------------------------------------------------------*/\nTOKENS\n  ident =  nondigitMinusBTick {idchar}       /* if char 0 is not an 'a' or '\\'', then anything else is fine */\n        |  'b' [ idcharMinusV {idchar} ]\n        |  'b' 'v' [ nondigit {idchar} ]\n        |  'b' 'v' '0' idchar {idchar}\n        |  'b' 'v' posDigit {idchar} nondigit {idchar}\n        |  \"'\" [ idchar ]                        /* if char 0 is a '\\'' and length is 1 or 2, then it is an identifier */\n        |  \"'\" idchar idcharMinusTick            /* if char 0 is '\\'' and length is 3, then it is an identifier provided char 2 is not '\\'' */\n        |  \"'\" idchar idchar idchar { idchar }   /* if char 0 is '\\'' and length exceeds 3, then it is an identifier */\n        .\n  digits = digit {['_'] digit} [ \"u\" | \"U\" | \"ll\" | \"LL\" | \"ull\" | \"ULL\" | \"u8\" | \"U8\" | \"i8\" | \"I8\" | \"u16\" | \"U16\" | \"i16\" | \"I16\"].\n  hexdigits = \"0x\" hexdigit {['_'] hexdigit}.\n  decimaldigits = digit {['_'] digit} '.' digit {['_'] digit}.\n  bvToken = \"bv\" ( '0' | posDigit {digit} ).\n  bool = \"bool\".\n  char = \"char\".\n  int = \"int\".\n  nat = \"nat\".\n  real = \"real\".\n  string = \"string\".\n  set = \"set\".\n  iset = \"iset\".\n  multiset = \"multiset\".\n  seq = \"seq\".\n  map = \"map\".\n  imap = \"imap\".\n  ptr = \"ptr\".\n  charToken =\n      \"'\"\n      ( charChar\n        | \"\\\\\\'\" | \"\\\\\\\"\" | \"\\\\\\\\\" | \"\\\\0\" | \"\\\\n\" | \"\\\\r\" | \"\\\\t\"\n        | \"\\\\u\" hexdigit hexdigit hexdigit hexdigit\n      )\n      \"'\".\n  stringToken =\n      '\"'\n      { stringChar\n        | \"\\\\\\'\" | \"\\\\\\\"\" | \"\\\\\\\\\" | \"\\\\0\" | \"\\\\n\" | \"\\\\r\" | \"\\\\t\"\n        | \"\\\\u\" hexdigit hexdigit hexdigit hexdigit\n      }\n      '\"'\n    | '@' '\"' { verbatimStringChar | \"\\\"\\\"\" } '\"'.\n  colon = ':'.\n  comma = ','.\n  verticalbar = '|'.\n  doublecolon = \"::\".\n  equal = \"=\".\n  equalsign = \":=\".\n  seqEqualSign = \"::=\".\n  boredSmiley = \":|\".\n  bullet = '\\u2022'.\n  dot = '.'.\n  dotdot = \"..\".\n  semi = ';'.\n  darrow = \"=>\".\n  assume = \"assume\".\n  calc = \"calc\".\n  case = \"case\".\n  if = \"if\".\n  then = \"then\".\n  else = \"else\".\n  as = \"as\".\n  by = \"by\".\n  in = \"in\".\n  decreases = \"decreases\".\n  invariant = \"invariant\".\n  datatype = \"datatype\".\n  codatatype = \"codatatype\".\n  var = \"var\".\n  const = \"const\".\n  method = \"method\".\n  malloc = \"malloc\".\n  calloc = \"calloc\".\n  create_thread = \"create_thread\".\n  join = \"join\".\n  compare_and_swap = \"compare_and_swap\".\n  atomic_exchange = \"atomic_exchange\".\n  new = \"new\".\n  awaits = \"awaits\".\n  modifies = \"modifies\".\n  reads = \"reads\".\n  requires = \"requires\".\n  ensures = \"ensures\".\n  ghost = \"ghost\".\n  noaddr = \"noaddr\".\n  sc = \"sc\".\n  reveal = \"reveal\".\n  label = \"label\".\n  lbrace = '{'.\n  rbrace = '}'.\n  lbracket = '['.\n  rbracket = ']'.\n  openparen = '('.\n  closeparen = ')'.\n  openAngleBracket = '<'.\n  closeAngleBracket = '>'.\n  eq = \"==\".\n  neq = \"!=\".\n  neqAlt = '\\u2260'.\n  star = '*'.\n  notIn = \"!in\" CONTEXT (nonidchar).\nCOMMENTS FROM \"/*\" TO \"*/\" NESTED\nCOMMENTS FROM \"//\" TO lf\nIGNORE cr + lf + tab\n\nPRODUCTIONS\n/*------------------------------------------------------------------------*/\n\n// Factor<out Expr expr>\n// = (.\n//     expr = null;\n//     Expr firstOp = null;\n//     Opcode op = Opcode.Nop;\n//   .)\n//   ( (. Ident leaf; .) Ident<out leaf>  (. expr = leaf; .)\n//   | (. Ident leaf; .) Digits<out leaf> (. expr = leaf; .)\n//   | (. op = Opcode.Neg; .)        '-' Factor<out firstOp> (. expr = new Expr(firstOp, null, op, true); .)\n//   | (. op = Opcode.BitwiseNot; .) '!' Factor<out firstOp> (. expr = new Expr(firstOp, null, op, true); .)\n//   | openparen Expr<out firstOp> closeparen (. expr = firstOp; .)\n//   )\n// .\n\nMapLiteralExpressions<.out Dictionary<Expr, Expr> elements.>\n(. Expr key, value; elements = new Dictionary<Expr, Expr>(); .)\n= Expr<out key>\n  equalsign\n  Expr<out value>         (. elements.Add(key, value); .)\n  { comma\n    Expr<out key> equalsign Expr<out value> (. elements.Add(key, value); .)\n  }.\n\nMapDisplayExpr<Token mapToken, bool finite, out Expr expr>\n= (.\n     Contract.Ensures(Contract.ValueAtReturn(out expr) != null);\n     Dictionary<Expr, Expr> elements = new Dictionary<Expr, Expr>();\n  .)\n  lbracket\n  [ MapLiteralExpressions<out elements> ]\n  rbracket\n  (. expr = new MapDisplayExpr(mapToken, finite, elements);\n     expr.LastTok = t;\n  .)\n.\n\nISetDisplayExpr<Token setToken, bool finite, out Expr expr>\n= (.\n     Contract.Ensures(Contract.ValueAtReturn(out expr) != null);\n     List<Expr> elements = new List<Expr>();\n  .)\n  lbrace \n  [ Expressions<out elements> ]\n  rbrace\n  (. expr = new SetDisplayExpr(setToken, finite, elements);\n     expr.LastTok = t;\n  .)\n.\n\nGenericInstantiation<.out List<Type> types.>\n= (.\n    types = new List<Type>();\n    Type ty;\n  .)\n  openAngleBracket\n    Type<out ty>         (. types.Add(ty); .)\n    { comma Type<out ty> (. types.Add(ty); .) \n    }\n  closeAngleBracket\n.\n\nOptGenericInstantiation<.out List<Type> typeList.> =\n  (. typeList = new List<Type>(); .)\n  [ IF(IsOpenAngleBracket()) \n    GenericInstantiation<out typeList>\n  ]\n.\n\n// HashCall<.out List<Type> types, out List<Expr> exprs.>\n// = '#'\n//   [ GenericInstantiation<out types> ]\n//   lbracket Expr<out expr> rbracket (. exprs.add(expr); .)\n//   openparen [ Expressions<out exprs> ] closeparen.\n\nNameSegment<out Expr expr>\n= (. \n    Ident id;\n    // List<Type> types;\n    // List<Expr> exprs;\n  .)\n  Ident<out id> (. expr = id; .)\n  // [ (. types = new List<Type>(); .) GenericInstantiation<out types>\n  // | HashCall<out types, out exprs>\n  // ] // TODO: create a new class for namesegment expr\n.\n\nDisplayExpr<out Expr expr> (. expr = null; Token x; List<Expr> elements = new List<Expr>(); .)\n= ( lbrace   (. x = t; .)\n    [ Expressions<out elements> ] \n    rbrace\n    (. expr = new SetDisplayExpr(x, true, elements);\n       expr.LastTok = t;\n    .)\n  )\n  |\n  ( lbracket (. x = t; .)\n    [ Expressions<out elements> ]\n    rbracket\n    (. expr = new SeqDisplayExpr(x, elements); \n       expr.LastTok = t;\n    .)\n  )\n.\n\nMultiSetExpr<out Expr expr>\n= (. Contract.Ensures(Contract.ValueAtReturn(out expr) != null);\n     Token x = null;\n     List<Expr> elements = new List<Expr>();\n     expr = null;\n  .)\n  multiset                                             (. x = t; .)\n  ( lbrace    [ Expressions<out elements> ] rbrace     (. expr = new MultiSetDisplayExpr(x, elements); expr.LastTok = t; .)\n    |\n    openparen Expr<out expr>                closeparen (. expr = new MultiSetFormingExpr(x, expr); expr.LastTok = t; .)\n  )\n.\n\nSeqConstructionExpr<out Expr expr> \n= (. Contract.Ensures(Contract.ValueAtReturn(out expr) != null);\n     Token x = null;\n     Expr e1, e2; \n     expr = null; \n  .)\n  seq (. x = t; .)\n  openparen Expr<out e1> comma Expr<out e2> closeparen (. expr = new SeqConstructionExpr(x, e1, e2); expr.LastTok = t; .)\n.\n\n// Nat<out BigInteger n>\n// = (. n = BigInteger.Zero;\n//      string S;\n//   .)\n//   ( digits\n//     (. S = Util.RemoveUnderscores(t.val);\n//        try {\n//          n = BigIntegerParser.Parse(S);\n//        } catch (System.FormatException) {\n//          SemErr(\"incorrectly formatted number\");\n//          n = BigInteger.Zero;\n//        }\n//     .)\n//   | hexdigits\n//     (. S = Util.RemoveUnderscores(t.val.Substring(2));\n//        try {\n//          // note: leading 0 required when parsing positive hex numbers\n//          n = BigIntegerParser.Parse(\"0\" + S, System.Globalization.NumberStyles.HexNumber);\n//        } catch (System.FormatException) {\n//          SemErr(\"incorrectly formatted number\");\n//          n = BigInteger.Zero;\n//        }\n//     .)\n//   ).\n\n// Dec<out BaseTypes.BigDec d>\n// = (. d = BaseTypes.BigDec.ZERO; .)\n//   (decimaldigits\n//     (. var S = Util.RemoveUnderscores(t.val);\n//        try {\n//          d = BaseTypes.BigDec.FromString(S);\n//        } catch (System.FormatException) {\n//          SemErr(\"incorrectly formatted number\");\n//          d = BaseTypes.BigDec.ZERO;\n//        }\n//     .)\n//   ).\n\nDigits<out Ident x>\n=\n  digits (. x = new Ident(t, t.val); x.LastTok = t; .)\n  (. if (t.val.ToLower().EndsWith(\"ull\"))\n     {\n       x.Ty = new PredefinedType(PredefinedTypeEnum.UInt64);\n       x.Name = x.Name.Substring(0, x.Name.Length - 3);\n     }\n     else if (t.val.ToLower().EndsWith(\"ll\"))\n     {\n       x.Ty = new PredefinedType(PredefinedTypeEnum.Int64);\n       x.Name = x.Name.Substring(0, x.Name.Length - 2);\n     }\n     else if (t.val.ToLower().EndsWith(\"u\"))\n     {\n       x.Ty = new PredefinedType(PredefinedTypeEnum.UInt32);\n       x.Name = x.Name.Substring(0, x.Name.Length - 1);\n     }\n     else if (t.val.ToLower().EndsWith(\"i8\"))\n     {\n       x.Ty = new PredefinedType(PredefinedTypeEnum.Int8);\n       x.Name = x.Name.Substring(0, x.Name.Length - 2);\n     }\n     else if (t.val.ToLower().EndsWith(\"u8\"))\n     {\n       x.Ty = new PredefinedType(PredefinedTypeEnum.UInt8);\n       x.Name = x.Name.Substring(0, x.Name.Length - 2);\n     }\n     else if (t.val.ToLower().EndsWith(\"i16\"))\n     {\n       x.Ty = new PredefinedType(PredefinedTypeEnum.Int16);\n       x.Name = x.Name.Substring(0, x.Name.Length - 3);\n     }\n     else if (t.val.ToLower().EndsWith(\"u16\"))\n     {\n       x.Ty = new PredefinedType(PredefinedTypeEnum.UInt16);\n       x.Name = x.Name.Substring(0, x.Name.Length - 3);\n     }\n     else\n     {\n       x.Ty = new PredefinedType(PredefinedTypeEnum.Int);\n     }\n  .)\n.\n\nLabelIdent<out Ident id> (. id = null; .)\n=\n  Ident<out id>\n  | Digits<out id>\n.\n\nConstAtomExpression<out Expr expr> (. expr = null; .)\n= (.\n    Expr firstOp;\n    Expr secondOp = null;\n    Token x = null;\n  .)\n  ( \"false\"       (. expr = new LiteralExpr(t, false); expr.LastTok = t; .)\n  | \"true\"        (. expr = new LiteralExpr(t, true); expr.LastTok = t; .)\n  | \"null\"        (. expr = new NullPointerExpr(t); expr.LastTok = t; .)\n  | (. Ident d; .) Digits<out d> (. expr = new ConstantExpr(t, d); expr.LastTok = t; .) // TODO: use LiteralExpr, Digits or Digits and hex and decimal\n  // | Nat<out n>    (. expr = new LiteralExpr(n); .)\n  // | Dec<out d>    (. expr = new LiteralExpr(d); .)\n  | charToken     (. expr = new CharLiteralExpr(t, t.val.Substring(1, t.val.Length - 2)); expr.LastTok = t; .)\n  | stringToken   (. \n                     bool isVerbatim = false;\n                     string s = Util.RemoveParsedStringQuotes(t.val, out isVerbatim);\n                     expr = new StringLiteralExpr(t, s, isVerbatim);\n                     expr.LastTok = t;\n                  .)\n  | \"$me\"         (. expr = new MeExpr(t); expr.LastTok = t; .)\n  | \"$state\"      (. expr = new Ident(t, t.val); expr.LastTok = t; .)\n  | ( \"allocated\"                                       (. x = t; .)\n      openparen Expr<out firstOp> closeparen            (. expr = new UnaryExpr(x, firstOp, Opcode.Allocated, false); expr.LastTok = t; .) )\n  | ( \"allocated_array\"                                 (. x = t; .)\n      openparen Expr<out firstOp> closeparen            (. expr = new UnaryExpr(x, firstOp, Opcode.AllocatedArray, false); expr.LastTok = t; .) )\n  | ( \"global_view\"                                     (. x = t; .)\n      openparen Expr<out firstOp> closeparen            (. expr = new UnaryExpr(x, firstOp, Opcode.GlobalView, false); expr.LastTok = t; .) )\n  | ( verticalbar                                       (. x = t; .)\n      Expr<out firstOp, false> verticalbar              (. expr = new UnaryExpr(x, firstOp, Opcode.Cardinality, false); expr.LastTok = t; .) ) \n  | ( \"if_undefined\"                                    (. x = t; .)\n      openparen Expr<out firstOp> comma Expr<out secondOp> closeparen (. expr = new IfUndefinedExpr(x, firstOp, secondOp); expr.LastTok = t; .) )\n  | ( (. Type ty = null; .)\n      ( \n        int (. x = t; ty = new PredefinedType(PredefinedTypeEnum.Int); .)\n      | real (. x = t; ty = new PredefinedType(PredefinedTypeEnum.Real); .)\n      )\n      openparen Expr<out firstOp, false> closeparen (. expr = new ConversionExpr(x, firstOp, ty); expr.LastTok = t; .)\n    )\n  | openparen (. x = t; .)\n    Expr<out expr, true>\n    closeparen (. expr.FirstTok = x; expr.LastTok = t; .)\n  )\n.\n\n// UnaryExpression<out Expr expr>\n// = Ident<out _> (. expr = null; .).\n\n// TODO: add C# codes\nUnaryExpression<out Expr expr, bool allowBitwiseOps>\n  (.\n    // Expr firstOp;\n    // Expr secondOp = null;\n    expr = null;\n    Opcode op = Opcode.Nop;\n    Token x;\n  .)\n=\n    ( (. op = Opcode.Neg; .)         '-' (. x = t; .)\n      ( IF(IsDigit()) (. Ident d; .) Digits<out d>\n        (. \n          d.Name = '-' + d.Name;\n          d.FirstTok.pos = x.pos;\n          d.FirstTok.charPos = x.charPos;\n          d.FirstTok.col = x.col;\n          d.FirstTok.line = x.line;\n          d.FirstTok.val = '-' + d.FirstTok.val;\n          expr = new ConstantExpr(d.FirstTok, d);\n          expr.LastTok = d.LastTok;\n        .)\n      | UnaryExpression<out expr, allowBitwiseOps> \n      (.\n        expr = new UnaryExpr(x, expr, op, false);\n        expr.LastTok = t;\n      .)\n      )\n    )\n  | ( (. op = Opcode.Not; .)         '!' (. x = t; .) UnaryExpression<out expr, allowBitwiseOps> (. expr = new UnaryExpr(x, expr, op, false); expr.LastTok = t; .) )\n  | ( (. op = Opcode.BitwiseNot; .)  '~' (. x = t; .) UnaryExpression<out expr, allowBitwiseOps> (. expr = new UnaryExpr(x, expr, op, false); expr.LastTok = t; .) )\n  | ( (. op = Opcode.AddressOf; .)   '&' (. x = t; .) UnaryExpression<out expr, allowBitwiseOps> (. expr = new UnaryExpr(x, expr, op, false); expr.LastTok = t; .) )\n  | ( (. op = Opcode.Dereference; .) '*' (. x = t; .) UnaryExpression<out expr, allowBitwiseOps> (. expr = new UnaryExpr(x, expr, op, false); expr.LastTok = t; .) )\n  | ( IF(IsMapDisplay())  map  (. x = t; .) MapDisplayExpr<x, true, out expr>     { Suffix<ref expr> } )\n  | ( IF(IsIMapDisplay()) imap (. x = t; .) MapDisplayExpr<x, false, out expr>    { Suffix<ref expr> } )\n  | ( IF(IsISetDisplay()) iset (. x = t; .) ISetDisplayExpr<x, false, out expr>   { Suffix<ref expr> } )\n  | ( NameSegment<out expr>                                       { Suffix<ref expr> } )\n  | ( DisplayExpr<out expr>                                       { Suffix<ref expr> } )\n  | ( MultiSetExpr<out expr>                                      { Suffix<ref expr> } )\n  | ( SeqConstructionExpr<out expr>                               { Suffix<ref expr> } )\n  | ( ConstAtomExpression<out expr>                               { Suffix<ref expr> } )\n  | ( EndlessExpression<out expr, allowBitwiseOps> )\n.\n\nAsExpression<out Expr expr, bool allowBitwiseOps>\n= UnaryExpression<out expr, allowBitwiseOps>\n  (. Type ty; .)\n  { IF(IsAs())\n    \"as\" Type<out ty> (. expr = new ConversionExpr(expr.FirstTok, expr, ty); expr.LastTok = t; .)\n  }.\n\nBitvectorFactor<out Expr expr, bool allowBitwiseOps>\n= (.\n    Expr secondOp;\n    Opcode op;\n  .)\n  AsExpression<out expr, allowBitwiseOps>\n  [ IF(allowBitwiseOps && IsBitwiseOp()) /* read a BitvectorFactor as far as possible, but not in the context inside a |.| size expression */\n    (\n      (. op = Opcode.BitwiseAnd; .)\n      \"&\"\n      AsExpression<out secondOp, allowBitwiseOps>   (. expr = new BinaryExpr(expr.FirstTok, expr, secondOp, op, false); expr.LastTok = t; .)\n      { IF(IsBitwiseAndOp())\n        \"&\"\n        AsExpression<out secondOp, allowBitwiseOps> (. expr = new BinaryExpr(expr.FirstTok, expr, secondOp, op, false); expr.LastTok = t; .)\n      }\n      [ IF(IsBitwiseOp()) ( \"|\" | \"^\" )  (. SemErr(la, \"Ambiguous use of &, |, ^. Use parentheses to disambiguate.\"); .) ]\n    | (. op = Opcode.BitwiseOr; .)\n      \"|\"\n      AsExpression<out secondOp, allowBitwiseOps>   (. expr = new BinaryExpr(expr.FirstTok, expr, secondOp, op, false); expr.LastTok = t; .)\n      { IF(IsBitwiseOrOp())\n        \"|\"\n        AsExpression<out secondOp, allowBitwiseOps> (. expr = new BinaryExpr(expr.FirstTok, expr, secondOp, op, false); expr.LastTok = t; .)\n      }\n      [ IF(IsBitwiseOp()) ( \"^\" | \"&\" )  (. SemErr(la, \"Ambiguous use of &, |, ^. Use parentheses to disambiguate.\"); .) ]\n    | (. op = Opcode.BitwiseXor; .)\n      \"^\"\n      AsExpression<out secondOp, allowBitwiseOps>   (. expr = new BinaryExpr(expr.FirstTok, expr, secondOp, op, false); expr.LastTok = t; .)\n      { IF(IsBitwiseXorOp())\n        \"^\"\n        AsExpression<out secondOp, allowBitwiseOps> (. expr = new BinaryExpr(expr.FirstTok, expr, secondOp, op, false); expr.LastTok = t; .)\n      }\n      [ IF(IsBitwiseOp()) ( \"&\" | \"|\" )  (. SemErr(la, \"Ambiguous use of &, |, ^. Use parentheses to disambiguate.\"); .) ]\n    )\n  ]\n.\n\nFactor<out Expr expr, bool allowBitwiseOps>\n= (.\n    Expr secondOp = null;\n    Opcode op = Opcode.Nop;\n  .)\n  BitvectorFactor<out expr, allowBitwiseOps>\n  { IF(IsMulOp())\n    ( (. op = Opcode.Mul; .) \"*\"\n    | (. op = Opcode.Div; .) \"/\"\n    | (. op = Opcode.Mod; .) \"%\"\n    ) \n    BitvectorFactor<out secondOp, allowBitwiseOps> (. expr = new BinaryExpr(expr.FirstTok, expr, secondOp, op, false); expr.LastTok = t; .)\n  }.\n\nTerm<out Expr expr, bool allowBitwiseOps>\n= (.\n    Expr secondOp = null;\n    Opcode op = Opcode.Nop;\n  .)\n  Factor<out expr, allowBitwiseOps>\n  { IF(IsAddOp())\n    ( (. op = Opcode.Add; .) \"+\"\n    | (. op = Opcode.Sub; .) \"-\"\n    ) \n    Factor<out secondOp, allowBitwiseOps> (. expr = new BinaryExpr(expr.FirstTok, expr, secondOp, op, false); expr.LastTok = t; .)\n  }.\n\n// TODO: perhaps change to read a Term as far as possible\nShiftTerm<out Expr expr, bool allowBitwiseOps>\n= (.\n    Expr secondOp = null;\n    Opcode op = Opcode.Nop;\n  .)\n  Term<out expr, allowBitwiseOps>\n  { IF(IsShiftOp())\n    ( (. op = Opcode.LeftShift; .) '<' '<'\n    | (. op = Opcode.RightShift; .) '>' '>'\n    ) \n    Term<out secondOp, allowBitwiseOps> (. expr = new BinaryExpr(expr.FirstTok, expr, secondOp, op, false); expr.LastTok = t; .)\n  }.\n\nRelOp<out Opcode op> (. op = Opcode.Add; .)\n= ( eq    (. op = Opcode.Equal; .)\n  | neq   (. op = Opcode.NotEqual; .)\n  | '<'   (. op = Opcode.Lt; .)\n  | '>'   (. op = Opcode.Gt; .)\n  | \"<=\"  (. op = Opcode.Le; .)\n  | \">=\"  (. op = Opcode.Ge; .)\n  | \"in\"  (. op = Opcode.In; .)\n  | notIn (. op = Opcode.NotIn; .)\n  | \"!!\"  (. op = Opcode.Disjoint; .) \n  ).\n\nRelationalExpression<out Expr expr, bool allowBitwiseOps>\n= (.\n    Expr secondOp = null;\n    Opcode op = Opcode.Nop;\n  .)\n  ShiftTerm<out expr, allowBitwiseOps>\n  { IF(IsRelOp())\n    RelOp<out op> \n    ShiftTerm<out secondOp, allowBitwiseOps> (. expr = new BinaryExpr(expr.FirstTok, expr, secondOp, op, false); expr.LastTok = t; .)\n  }\n.\n\nLogicalExpression<out Expr expr, bool allowBitwiseOps> (. expr = null; .)\n= (.\n    Expr secondOp;\n    Opcode op = Opcode.Nop;\n  .)\n  // TODO(Armin): Need to take care of the special case of only one RelationalExpression\n  // Look at Dafny.atg file comments\n  ( ( \"&&\" RelationalExpression<out expr, allowBitwiseOps>\n      { IF(IsAndOp())\n        \"&&\"\n        RelationalExpression<out secondOp, allowBitwiseOps> (. expr = new BinaryExpr(expr.FirstTok, expr, secondOp, Opcode.And, false); expr.LastTok = t; .)\n      }\n      [ IF(IsOrOp()) \"||\" (. SemErr(t, \"Ambiguous use of && and ||. Use parentheses to disambiguate.\"); .) ]\n    )\n  | ( \"||\" RelationalExpression<out expr, allowBitwiseOps>\n      { IF(IsOrOp()) \n        \"||\"\n        RelationalExpression<out secondOp, allowBitwiseOps> (. expr = new BinaryExpr(expr.FirstTok, expr, secondOp, Opcode.Or, false); expr.LastTok = t; .)\n      }\n      [ IF(IsAndOp()) \"&&\" (. SemErr(t, \"Ambiguous use of && and ||. Use parentheses to disambiguate.\"); .) ]\n    )\n  | ( RelationalExpression<out expr, allowBitwiseOps>\n      [ IF(IsAndOp() || IsOrOp())\n        ( (. op = Opcode.And; .) \"&&\"\n          RelationalExpression<out secondOp, allowBitwiseOps>   (. expr = new BinaryExpr(expr.FirstTok, expr, secondOp, op, false); expr.LastTok = t; .)\n          { IF(IsAndOp()) \"&&\"\n            RelationalExpression<out secondOp, allowBitwiseOps> (. expr = new BinaryExpr(expr.FirstTok, expr, secondOp, op, false); expr.LastTok = t; .) \n          } \n        | (. op = Opcode.Or; .) \"||\"\n          RelationalExpression<out secondOp, allowBitwiseOps>   (. expr = new BinaryExpr(expr.FirstTok, expr, secondOp, op, false); expr.LastTok = t; .)\n          { IF(IsOrOp()) \"||\"\n            RelationalExpression<out secondOp, allowBitwiseOps> (. expr = new BinaryExpr(expr.FirstTok, expr, secondOp, op, false); expr.LastTok = t; .)\n          }\n        )\n      ]\n    )\n  ).\n\nImpliesExpression<out Expr expr, bool allowBitwiseOps>\n= (.\n    Expr secondOp;\n    Opcode op = Opcode.Nop;\n  .)\n  LogicalExpression<out expr, allowBitwiseOps>\n  [ IF(IsImpliesOp())  /* read an ImpliesExpression as far as possible */\n    (. op = Opcode.Imply; .) \"==>\"\n    ImpliesExpression<out secondOp, allowBitwiseOps> (. expr = new BinaryExpr(expr.FirstTok, expr, secondOp, op, false); expr.LastTok = t; .)\n  ]\n  .\n\nImpliesExpliesExpression<out Expr expr, bool allowBitwiseOps>\n= (.\n    Expr secondOp;\n    Opcode op = Opcode.Nop;\n  .)\n  LogicalExpression<out expr, allowBitwiseOps>\n  [ IF(IsImpliesOp() || IsExpliesOp()) /* read an ImpliesExpliesExpression as far as possible */\n    (\n      /* Note, the asymmetry in the parsing of implies and explies expressions stems from the fact that\n       * implies is right associative whereas reverse implication is left associative\n       */\n      (. op = Opcode.Imply; .) \"==>\"\n      ImpliesExpression<out secondOp, allowBitwiseOps>   (. expr = new BinaryExpr(expr.FirstTok, expr, secondOp, op, false); expr.LastTok = t; .)\n    | (. op = Opcode.Exply; .) \"<==\"\n      LogicalExpression<out secondOp, allowBitwiseOps>   (. expr = new BinaryExpr(expr.FirstTok, expr, secondOp, op, false); expr.LastTok = t; .)\n      { IF(IsExpliesOp())\n        \"<==\"\n        LogicalExpression<out secondOp, allowBitwiseOps> (. expr = new BinaryExpr(expr.FirstTok, expr, secondOp, op, false); expr.LastTok = t; .)\n      }\n    )\n  ].\n\n/* The \"allowBitwiseOps\" says whether or not to include or bypass bitwise operators\n * at the top level of this expression. It is passed in as \"false\" only inside\n * cardinality brackets, that is, \"|expr|\".\n */\nExpr<out Expr expr, bool allowBitwiseOps = true>\n= (. \n    Expr secondOp;\n    Opcode op = Opcode.Nop;\n  .)\n  ImpliesExpliesExpression<out expr, allowBitwiseOps>\n  { IF(IsEquivOp()) (. op = Opcode.Equiv; .) \n    \"<==>\"\n    Expr<out secondOp> (. expr = new BinaryExpr(expr.FirstTok, expr, secondOp, op, false); expr.LastTok = t; .)\n  }.\n\nIfExpr<out Expr expr, bool allowBitwiseOps>\n= (. Expr cond, thenExpr, elseExpr; Token x; .)\n  if (. x = t; .)\n  Expr<out cond, allowBitwiseOps> then Expr<out thenExpr, allowBitwiseOps> else Expr<out elseExpr, allowBitwiseOps>\n  (. expr = new IfExpr(x, cond, thenExpr, elseExpr); expr.LastTok = t; .)\n.\n\nIdentTypeOptional<out Ident ident>\n= Ident<out ident> [ colon (. Type ty; .) Type<out ty> (. ident.Ty = ty; ident.LastTok = t; .) ].\n\nIdentType<out Ident ident>\n= Ident<out ident> colon (. Type ty; .) Type<out ty> (. ident.Ty = ty; ident.LastTok = t; .).\n\nCasePattern<.out CasePattern pat.>\n= (. List<CasePattern> arguments;\n     Token x;\n     pat = null;\n  .)\n  (\n    IF(IsIdentParen()) (. Ident ident; .) Ident<out ident> (. x = ident.FirstTok; .)\n    openparen                    (. arguments = new List<CasePattern>(); .)\n    [ CasePattern<out pat>       (. arguments.Add(pat); .) \n    { comma CasePattern<out pat> (. arguments.Add(pat); .) } ] \n    closeparen                   (. pat = new CasePattern(x, ident, arguments); .)\n    |\n    (. Ident ident; .) IdentTypeOptional<out ident> (. pat = new CasePattern(ident.FirstTok, ident); pat.LastTok = t; .)\n  ).\n\nCaseExpression<out MatchCaseExpr expr, bool allowBitwiseOps> \n= (. Contract.Ensures(Contract.ValueAtReturn(out expr) != null);\n     Token x;\n     var arguments = new List<CasePattern>();\n     CasePattern pat;\n     Expr body;\n     string name = \"\";\n  .)\n  case (. x = t; .)\n  (\n    (. Ident ident; .) Ident<out ident> (. name = ident.FirstTok.val; .)\n    [ openparen CasePattern<out pat> (. arguments.Add(pat); .)\n    { comma CasePattern<out pat>     (. arguments.Add(pat); .) } closeparen ]\n  )\n  darrow Expr<out body, allowBitwiseOps> (. expr = new MatchCaseExpr(x, name, arguments, body); expr.LastTok = t; .).\n\nMatchExpr<out Expr expr, bool allowBitwiseOps>\n= (. Contract.Ensures(Contract.ValueAtReturn(out expr) != null);\n     Expr matchExpr;\n     Token x;\n     List<MatchCaseExpr> cases = new List<MatchCaseExpr>();\n     bool usesOptionalBraces = false;\n  .)\n  \"match\" (. x = t; .)\n  Expr<out matchExpr, allowBitwiseOps> \n  ( \n    ( IF(la.kind == _lbrace)  /* always favor brace-enclosed match body to a case-less match */\n      lbrace (. usesOptionalBraces = true; .)\n      { (. MatchCaseExpr e; .) CaseExpression<out e, allowBitwiseOps> (. cases.Add(e); .) }\n      rbrace\n    )\n  | { IF(la.kind == _case)  /* let each \"case\" bind to the closest preceding \"match\" */\n      (. MatchCaseExpr e; .) CaseExpression<out e, allowBitwiseOps>   (. cases.Add(e); .)\n    }\n  )\n  (. expr = new MatchExpr(x, matchExpr, cases, usesOptionalBraces); expr.LastTok = t; .)\n  .\n\nQuantifierDomain<.out List<Ident> idents, out Attribute attrs, out Expr range, bool allowBitwiseOps.>\n= (. Ident id;\n     idents = new List<Ident>();\n     range = null;\n     attrs = null;\n  .)\n  IdentType<out id>         (. idents.Add(id); .)\n  { comma IdentType<out id> (. idents.Add(id); .) }\n  { Attribute<out attrs> }\n  [ verticalbar Expr<out range, allowBitwiseOps> ].\n\nQuantifierExpr<out Expr expr, bool allowBitwiseOps>\n= (. Contract.Ensures(Contract.ValueAtReturn(out expr) != null); \n     Token x = null;\n     bool univ = false;\n     List<Ident> idents;\n     Attribute attrs;\n     Expr range;\n     Expr body;\n  .)\n  ( \"forall\" (. x = t; univ = true; .) | \"exists\" (. x = t; .) )\n  QuantifierDomain<out idents, out attrs, out range, allowBitwiseOps> doublecolon\n  Expr<out body, allowBitwiseOps>\n  (. if (univ) {\n       expr = new ForallExpr(x, idents, range, body, attrs);\n     } else {\n       expr = new ExistsExpr(x, idents, range, body, attrs);\n     }\n     expr.LastTok = t;\n  .).\n\nSetComprehensionExpr<out Expr expr, Token setToken, bool finite, bool allowBitwiseOps>\n= (. Contract.Ensures(Contract.ValueAtReturn(out expr) != null);\n     Ident id;\n     List<Ident> idents = new List<Ident>();\n     Expr range;\n     Expr body = null;\n     Attribute attrs = null;\n  .)\n  IdentType<out id>         (. idents.Add(id); .)\n  { comma IdentType<out id> (. idents.Add(id); .) }\n  { Attribute<out attrs> } verticalbar Expr<out range, allowBitwiseOps>\n  [ IF(IsQSep()) doublecolon Expr<out body, allowBitwiseOps> ]\n  (. if (body == null && idents.Count != 1) {\n       SemErr(id.FirstTok, \"a set comprehension with more than one bound variable must have a term expression\");\n       expr = null;\n     } else {\n       expr = new SetComprehension(setToken, finite, idents, range, body, attrs);\n       expr.LastTok = t;\n     }\n  .).\n\nMapComprehensionExpr<out Expr expr, Token mapToken, bool finite, bool allowBitwiseOps>\n= (. Contract.Ensures(Contract.ValueAtReturn(out expr) != null);\n     Ident id;\n     List<Ident> idents = new List<Ident>();\n     Expr range = null;\n     Expr keyExpr;\n     Expr valueExpr = null;\n     Attribute attrs = null;\n  .)\n  IdentType<out id>         (. idents.Add(id); .)\n  { comma IdentType<out id> (. idents.Add(id); .) }\n  { Attribute<out attrs> } [ verticalbar Expr<out range, allowBitwiseOps> ] doublecolon Expr<out keyExpr, allowBitwiseOps>\n  [ IF(IsEqualSign())  /* greedily parse \":=\" */ equalsign Expr<out valueExpr, allowBitwiseOps> ]\n  (. if (valueExpr == null && idents.Count != 1) {\n       SemErr(id.FirstTok, \"a map comprehension with more than one bound variable must have a term expression of the form 'Expr := Expr'\");\n       expr = null;\n     } else {\n       expr = new MapComprehension(mapToken, finite, idents, range, keyExpr, valueExpr, attrs);\n       expr.LastTok = t;\n     }\n  .).\n\n// TODO(ar): add let expr.\n//LetExpr\n//= \n\nLabelExpr<out Expr expr, bool allowBitwiseOps> (. expr = null; .)\n= (. Ident label; Expr e; Token x; .)\n  label (. x = t; .)\n  Ident<out label> colon Expr<out e, allowBitwiseOps> (. expr = new LabelExpr(x, label.FirstTok.val, e); expr.LastTok = t; .)\n.\n\nEndlessExpression<out Expr expr, bool allowBitwiseOps> (. expr = null; .)\n=   IfExpr<out expr, allowBitwiseOps>\n  | MatchExpr<out expr, allowBitwiseOps>\n  | QuantifierExpr<out expr, allowBitwiseOps>\n  | ( (. bool finite = true; Token x; .)\n    (set (. x = t; .) | iset (. x = t; finite = false; .))\n    SetComprehensionExpr<out expr, x, finite, allowBitwiseOps> )\n  | ( (. bool finite = true; Token x; .)\n    (map (. x = t; .) | imap (. x = t; finite = false; .))\n    MapComprehensionExpr<out expr, x, finite, allowBitwiseOps> )\n// TODO(ar): add LetExpr\n//  | LetExpr<out expr>\n  | LabelExpr<out expr, allowBitwiseOps>\n.\n\nAllocCall<out Expr expr>\n= (. Token x; Type ty; Expr count; bool isCalloc = false; .)\n  ( malloc (. isCalloc = false; .) \n  | calloc (. isCalloc = true; .)\n  ) (. x = t; .)\n  openparen Type<out ty> comma Expr<out count> closeparen\n  (. expr = new AllocRhs(x, ty, count, isCalloc); expr.LastTok = t; .).\n\nCreateThreadCall<out Expr expr>\n= (. Token x; Ident ident; List<Expr> elements = new List<Expr>(); .)\n  create_thread (. x = t; .)\n  Ident<out ident> openparen [ Expressions<out elements> ] closeparen\n  (. expr = new CreateThreadRhs(x, ident, elements); expr.LastTok = t; .).\n\nCompareAndSwapCall<out Expr expr>\n= (. Token x; Expr target, oldval, newval; .)\n  compare_and_swap (. x = t; .)\n  openparen Expr<out target> comma Expr<out oldval> comma Expr<out newval> closeparen\n  (. expr = new CompareAndSwapRhs(x, target, oldval, newval); expr.LastTok = t; .).\n\nAtomicExchangeCall<out Expr expr>\n= (. Token x; Expr target, newval; .)\n  atomic_exchange (. x = t; .)\n  openparen Expr<out target> comma Expr<out newval> closeparen\n  (. expr = new AtomicExchangeRhs(x, target, newval); expr.LastTok = t; .).\n\nExpressions<.out List<Expr> elements.>\n= (. Expr expr = null; elements = new List<Expr>(); .)\n  Expr<out expr> (. elements.Add(expr); .)\n  { (. Expr nextexpr = null; .) comma Expr<out nextexpr> (. elements.Add(nextexpr); .) }.\n\nAttribute<.out Attribute attrs.>\n= (. Token x; Ident ident; List<Expr> exprs = new List<Expr>(); .)\n  \"{:\" (. x = t; .)\n  Ident<out ident> [ Expressions<out exprs> ]\n  \"}\"  (. attrs = new Attribute(x, ident, exprs); attrs.LastTok = t; .)\n  .\n\nSetType<out Type ty> = \n  (.\n    bool isInfinite = false;\n    Type entityType;\n  .)\n  ( set\n  | iset (.isInfinite = true; .)\n  ) \n  openAngleBracket Type<out entityType> closeAngleBracket\n  (. ty = new SetType(entityType, isInfinite); .)\n.\n\nSeqType<out Type ty> = \n  (.\n    Type entityType;\n  .)\n  seq\n  openAngleBracket Type<out entityType> closeAngleBracket\n  (. ty = new SeqType(entityType); .)\n.\n\nPtrType<out Type ty> =\n  (. Type entityType; .)\n  ptr openAngleBracket Type<out entityType> closeAngleBracket\n  (. ty = new PointerType(entityType); .)\n.\n\nMapType<out Type ty> = \n  (.\n    bool isInfinite = false;\n    Type keyType;\n    Type valueType;\n  .)\n  ( map\n  | imap (.isInfinite = true; .)\n  ) \n  openAngleBracket Type<out keyType> comma Type<out valueType> closeAngleBracket\n  (. ty = new MapType(keyType, valueType, isInfinite); .)\n.\n\nPredefinedType<out Type ty>\n= (. ty = null; .)\n  ( \"int\"            (. ty = new PredefinedType(PredefinedTypeEnum.Int); .)\n  | \"int8\"           (. ty = new PredefinedType(PredefinedTypeEnum.Int8); .)\n  | \"int16\"          (. ty = new PredefinedType(PredefinedTypeEnum.Int16); .)\n  | \"int32\"          (. ty = new PredefinedType(PredefinedTypeEnum.Int32); .)\n  | \"int64\"          (. ty = new PredefinedType(PredefinedTypeEnum.Int64); .)\n  | \"nat\"            (. ty = new PredefinedType(PredefinedTypeEnum.Nat); .)\n  | \"uint8\"          (. ty = new PredefinedType(PredefinedTypeEnum.UInt8); .)\n  | \"uint16\"         (. ty = new PredefinedType(PredefinedTypeEnum.UInt16); .)\n  | \"uint32\"         (. ty = new PredefinedType(PredefinedTypeEnum.UInt32); .)\n  | \"uint64\"         (. ty = new PredefinedType(PredefinedTypeEnum.UInt64); .)\n  | \"bool\"           (. ty = new PredefinedType(PredefinedTypeEnum.Bool); .)\n  | \"char\"           (. ty = new PredefinedType(PredefinedTypeEnum.Char); .)\n  | \"string\"         (. ty = new PredefinedType(PredefinedTypeEnum.String); .)\n  | \"tid_t\"          (. ty = new PredefinedType(PredefinedTypeEnum.ThreadId); .)\n  ) \n  [ (. Ident d; .) lbracket Digits<out d> rbracket (. ty = new TypeSuffix(ty, d); .) ]\n.\n\nType <out Type ty>\n= (. ty = null; .)\n  ( PredefinedType<out ty>\n  | SetType <out ty>\n  | SeqType <out ty>\n  | PtrType <out ty>\n  | MapType <out ty>\n  | ( (. Ident id; List<Type> typeList; .)\n      Ident<out id> (. ty = null; .)\n      OptGenericInstantiation<out typeList>\n      (. \n         ty = new UserDefinedType(id, typeList); \n      .)\n    )\n  )\n  [ (. Ident d; .) lbracket Digits<out d> rbracket (. ty = new TypeSuffix(ty, d); .) ]\n.\n\nParameter<out Parameter arg>\n= (. Token x; Ident id; Type ty; .)\n  Ident<out id> (. x = t; .)\n  colon\n  Type<out ty>\n  (. arg = new Parameter(x, id, ty); arg.LastTok = t; .)\n.\n\nParameters<.out List<Parameter> args.>\n= (. args = new List<Parameter>(); .)\n  (. Parameter arg; .) Parameter<out arg> (. args.Add(arg); .)\n  { (. Parameter nextarg; .) comma Parameter<out nextarg> (. args.Add(nextarg); .) }.\n\nSuffix<ref Expr expr>\n=\n  (. Ident dotIdent; .)\n  ( dot Ident<out dotIdent> ) (. expr = new BinaryExpr(expr.FirstTok, expr, dotIdent, Opcode.Dot, true); expr.LastTok = t; .)\n  | ( lbracket (. Expr startExpr = null, endExpr = null; Expr valExpr; .)\n      ( \n        ( dotdot [ Expr<out endExpr> ] )     (. expr = new SeqRangeExpr(expr.FirstTok, expr, startExpr, endExpr); .)\n        | \n        ( Expr<out startExpr>                (. bool otherSign = false; .)\n          [ \n            ( dotdot [ Expr<out endExpr> ] ) (. expr = new SeqRangeExpr(expr.FirstTok, expr, startExpr, endExpr); otherSign = true; .)\n          | ( equalsign Expr<out valExpr> )  (. expr = new SeqAssignExpr(expr.FirstTok, expr, startExpr, valExpr); otherSign = true; .)\n          ]\n        )\n        (. if (!otherSign) expr = new SeqSelectExpr(expr.FirstTok, expr, startExpr); .)\n      ) \n      rbracket (. expr.LastTok = t; .)\n    )\n  | (. List<Expr> elements = new List<Expr>(); .) \n    openparen [ Expressions<out elements> ] closeparen (. expr = new ApplySuffix(expr.FirstTok, expr, elements); expr.LastTok = t; .).\n\nIdent<out Ident x>\n=\n  ident (. x = new Ident(t, t.val); x.LastTok = t; .)\n.\n\nLhs<out Expr lhs>\n=\n  (. lhs = null; Expr expr; .)\n  ( \n    (. Ident id; .) Ident <out id> (. lhs = id; .) \n    { \n      Suffix<ref lhs>\n    }\n  | star (. Token x = t; .) Expr<out expr> (. lhs = new UnaryExpr(x, expr, Opcode.Dereference, true); lhs.LastTok = t; .)\n  | openparen Expr<out lhs> closeparen (. lhs.LastTok = t; .)\n    Suffix<ref lhs>\n    { Suffix<ref lhs> }\n  )\n.\n\n\nRhs<out Expr expr>\n=\n  (. expr = null; .)\n//  ( new ( NewArray | TypeAndToken ( NewArray | openparen Expressions closeparen ) )\n  (  \n      IF(StarFollowedByCommaSemiOrOpenBrace())\n      \"*\" (. expr = new WildcardExpr(t); expr.LastTok = t; .)\n    | Expr<out expr>\n    | AllocCall<out expr>\n    | CreateThreadCall<out expr>\n    | CompareAndSwapCall<out expr>\n    | AtomicExchangeCall<out expr>\n  )\n.\n\nAssignStatement<out Statement s>\n=\n  (. \n     Expr lhs;\n     Expr rhs = null; // FIXME: want None\n     bool isSequential = false;\n     Token x = la;\n  .)\n  Lhs <out lhs>\n    [ \n      ( equalsign    (. isSequential = false; .) \n      | seqEqualSign (. isSequential = true; .) )\n      Rhs <out rhs> \n    ] semi\n  (. \n    if (rhs == null) {\n      if (lhs is ApplySuffix) {\n        // This is going to convert to FunctionCallStatement in TypeResolve ...\n        s = new ApplySuffixStatement(lhs as ApplySuffix);\n      }\n      else {\n        throw new NotImplementedException();\n      }\n    }\n    else {\n      s = new AssignStatement(x, lhs, rhs, isSequential); s.LastTok = t;\n    }\n  .) \n  // FIXME: in case of a function call (ApplySuffix) (e.g. foo(x);), this assignment will not\n  // have RHS, that is not correct. The function call itself is an RHS-value and not an LHS-value.\n.\n\nAtomicStatement<out Statement atomicStmt>\n= (. BlockStatement block; Token x; .)\n  (\"atomic\" | \"explicit_yield\") (. x = t; .)\n  BlockStatement<out block>\n  (. atomicStmt = new AtomicStatement(x, block); atomicStmt.LastTok = t; .)\n.\n\nAssertStatement<out Statement assertStmt>\n= (. Token x; Expr cond; .)\n  \"assert\" (. x = t; .)\n  Expr<out cond> semi\n  (. assertStmt = new AssertStatement(x, cond); assertStmt.LastTok = t; .)\n.\n\nAssumeStatement<out Statement assumeStmt>\n= (. Expr cond; Token x; .)\n  ( \"assume\" | \"wait_until\" ) (. x = t; .)\n  Expr<out cond> semi\n  (. assumeStmt = new AssumeStatement(x, cond); assumeStmt.LastTok = t; .)\n.\n\nInvariantSpec\n= (. Expr expr = null; .)\n  invariant Expr<out expr>.\n\nGuard<out Expr e>\n= (. Expr ee;  e = null; .)\n  ( IF(StarFollowedByCommaSemiOrOpenBrace()) \"*\"  (. e = new WildcardExpr(t); e.LastTok = t; .)\n  | IF(IsParenStar())  \"(\" \"*\" \")\"                (. e = new WildcardExpr(t); e.LastTok = t; .)\n  | Expr<out ee, true>                            (. e = ee; .)\n  )\n.\n\nWhileBlock<out WhileBlock whileBlk>\n= (. Expr cond; BlockStatement block; Token x; .)\n  \"while\" (. x = t; .)\n  Guard<out cond> { MethodSpec<out _> | InvariantSpec } BlockStatement<out block>\n  (. whileBlk = new WhileBlock(x, cond, block); whileBlk.LastTok = t; .)\n.\n\nIfStatement<out IfStatement ifstmt>\n= (. Expr cond = null; BlockStatement thenPath; Statement elsePath = null; Token x; .)\n  if (. x = t; .)\n  Guard<out cond> BlockStatement<out thenPath>\n  [ else Statement<out elsePath> ]\n  (. ifstmt = new IfStatement(x, cond, thenPath, elsePath); ifstmt.LastTok = t; .)\n.\n\nBlockStatement<out BlockStatement blockStmt>\n=\n  (. Token x; .)\n  lbrace (. x = t; blockStmt = new BlockStatement(x); .)\n  { \n    (. Statement s; .) \n    Statement<out s> \n    (. blockStmt.Stmts.Add(s); .) \n  } \n  rbrace (. blockStmt.LastTok = t; .)\n.\n\nJoinStatement<out JoinStatement joinStmt>\n=\n  join (. Token x = t; .)\n  (. Expr expr; .) Expr<out expr>\n  semi\n  (. joinStmt = new JoinStatement(x, expr); joinStmt.LastTok = t; .)\n.\n\nIdents<.out List<Ident> identList.>\n=\n  (. \n    identList = new List<Ident>();\n    Ident id;\n  .)\n  Ident<out id>   (. identList.Add(id); .)\n  { comma Ident<out id> (. identList.Add(id); .) }\n.\n\nSomehowStatement<out Statement somehowStmt>\n= (. Contract.Ensures(Contract.ValueAtReturn(out somehowStmt) != null); \n     List<Expr> undefinedUnless = new List<Expr>();\n     List<Ident> mod = null;\n     List<Expr> ens = new List<Expr>();\n     List<Attribute> attrs = new List<Attribute>();\n     List<Expr> elements;\n     Expr expr = null;\n     Token x;\n  .)\n  \"somehow\" (. x = t; .)\n  { (. Attribute attr; .) Attribute<out attr> (. attrs.Add(attr); .) }\n  {\n    ( \"undefined_unless\" Expressions<out elements> (. undefinedUnless.AddRange(elements); .)\n    | \"modifies\" Idents<out mod>\n    | \"ensures\" Expr<out expr>                     (. ens.Add(expr); .)\n    )\n  }\n  semi\n  (. somehowStmt = new SomehowStatement(x, undefinedUnless, mod, ens, attrs); somehowStmt.LastTok = t; .)\n.\n\nCaseStatement<out MatchCaseStmt stmt> \n= (. Token x;\n     var arguments = new List<CasePattern>();\n     CasePattern pat;\n     Statement body;\n     List<Statement> stmts = new List<Statement>();\n     string name = \"\";\n  .)\n  case (. x = t; .)\n  (\n    (. Ident ident; .) Ident<out ident> (. name = ident.FirstTok.val; .)\n    [ openparen CasePattern<out pat> (. arguments.Add(pat); .)\n    { comma CasePattern<out pat>     (. arguments.Add(pat); .) } closeparen ]\n  )\n  darrow SYNC /* this SYNC and the one inside the loop below are used to avoid problems with the IsNotEndOfCase test. The SYNC will\n              * skip until the next symbol that can legally occur here, which is either the beginning of a Stmt or whatever is allowed\n              * to follow the CaseStatement.\n              */\n  { IF(IsNotEndOfCase()) /* This is a little sketchy. It would be nicer to be able to write IF(la is start-symbol of Stmt), but Coco doesn't allow that */\n    Statement<out body> (. stmts.Add(body); .)\n    SYNC\n  } \n  (. stmt = new MatchCaseStmt(x, name, arguments, stmts); stmt.LastTok = t; .)\n.\n\nMatchStatement<out Statement matchStmt>\n= (. Expr matchExpr;\n     Token x;\n     List<MatchCaseStmt> cases = new List<MatchCaseStmt>();\n     bool usesOptionalBraces = false;\n  .)\n  \"match\" (. x = t; .)\n  Expr<out matchExpr, false> \n  ( \n    ( //IF(la.kind == _lbrace)  /* always favor brace-enclosed match body to a case-less match */\n      lbrace (. usesOptionalBraces = true; .)\n      { (. MatchCaseStmt e; .) CaseStatement<out e> (. cases.Add(e); .) }\n      rbrace\n    )\n  | { IF(la.kind == _case)  /* let each \"case\" bind to the closest preceding \"match\" */\n      (. MatchCaseStmt e; .) CaseStatement<out e>   (. cases.Add(e); .)\n    }\n  )\n  (. matchStmt = new MatchStatement(x, matchExpr, cases, usesOptionalBraces); matchStmt.LastTok = t; .)\n.\n\nCreateThreadStatement<out Statement s>\n= (. Expr expr; .)\n  CreateThreadCall<out expr> semi (. s = new ExprStatement(expr.FirstTok, expr); s.LastTok = t; .).\n  \nCompareAndSwapStatement<out Statement s>\n= (. Expr expr; .)\n  CompareAndSwapCall<out expr> semi (. s = new ExprStatement(expr.FirstTok, expr); s.LastTok = t; .).\n\nReturnStatement<out Statement s>\n= (. Token x; Expr val = null; .)\n  \"return\" (. x = t; .)\n  [ Rhs<out val> ] semi (. s = new ReturnStatement(x, val); s.LastTok = t; .).\n\nYieldStatement<out Statement s>\n= (. Token x; .)\n  \"yield\" (. x = t; .) semi (. s = new YieldStatement(x); s.LastTok = t; .).\n\nGotoStatement<out Statement s>\n= (. Token x; Ident ident; .)\n  \"goto\" (. x = t; .)\n  LabelIdent<out ident> semi (. s = new GotoStatement(x, ident); s.LastTok = t; .).\n\nFenceStatement<out Statement s>\n= (. Token x; .)\n  \"fence\" (. x = t; .) semi (. s = new FenceStatement(x); s.LastTok = t; .).\n\nDeallocStatement<out Statement s>\n= (. Token x; Expr expr;.)\n  \"free\" (. x = t; .) openparen Expr<out expr> closeparen semi (. s = new DeallocStatement(x, expr); s.LastTok = t; .).\n\nStatement<out Statement s>\n= (. s = null; .)\n  ( AssignStatement<out s>\n  | AtomicStatement<out s>\n  | AssertStatement<out s>\n  | AssumeStatement<out s>\n  | SomehowStatement<out s>\n  | MatchStatement<out s>\n  | CreateThreadStatement<out s>\n  | CompareAndSwapStatement<out s>\n  | ReturnStatement<out s>\n  | YieldStatement<out s>\n  | GotoStatement<out s>\n  | FenceStatement<out s>\n  | DeallocStatement<out s>\n  | \"continue\"                         (. Token x = t; .)\n    \";\"                                (. s = new ContinueStatement(x); s.LastTok = t; .)\n  | \"break\"                            (. Token x = t; .)\n    \";\"                                (. s = new BreakStatement(x);    s.LastTok = t; .)\n  | (. JoinStatement joinStmt; .)     JoinStatement<out joinStmt>     (. s = joinStmt; .)\n  | (. VarDecl varDecl; .)            VarDecl<out varDecl>            (. s = varDecl; .)\n  | (. WhileBlock whileBlk; .)        WhileBlock<out whileBlk>        (. s = whileBlk; .)\n  | (. IfStatement ifStmt; .)         IfStatement<out ifStmt>         (. s = ifStmt; .)\n  | (. BlockStatement blockStmt; .)   BlockStatement<out blockStmt>   (. s = blockStmt; .)\n  | (. Ident label; .) label Ident<out label> colon Statement<out s>  (. s.Label = label; .)\n  ).\n\nFunctionBody<out Expr expr>\n= \n  lbrace\n  Expr<out expr>\n  rbrace\n.\n\nInvariantDecl<out InvariantDecl invariantDecl>\n= (. Ident ident; Expr expr; Token x; List<Ident> unchangedVars = new List<Ident>(); \n     InvariantType type = InvariantType.MAINTAINED_IF_STATEMENT_SATISFIES; .)\n  \"invariant\" (. x = t; .)\n  Ident<out ident>\n  FunctionBody<out expr>\n  \"by\"\n  ( \"maintained_if_statement_satisfies\" (. type = InvariantType.MAINTAINED_IF_STATEMENT_SATISFIES; .)\n  | \"maintained_if_vars_unchanged\"      (. type = InvariantType.MAINTAINED_IF_VARS_UNCHANGED; .)\n      [ (. Ident id; .) Ident<out id> (. unchangedVars.Add(id); .) ]\n      { (. Ident id; .) comma Ident<out id> (. unchangedVars.Add(id); .) }\n  )\n  (. invariantDecl = new InvariantDecl(x, ident, expr, type, unchangedVars); invariantDecl.LastTok = t; .)\n.\n\nYieldPredicateDecl<out YieldPredicateDecl yieldPredicateDecl>\n= (. Ident ident; Expr expr; Token x; .)\n  \"yield_predicate\" (. x = t; .)\n  Ident<out ident>\n  FunctionBody<out expr>\n  (. yieldPredicateDecl = new YieldPredicateDecl(x, ident, expr); yieldPredicateDecl.LastTok = t; .)\n.\n\nMethodSpec<out MethodSpec spec>\n= (. List<Expr> elements = new List<Expr>(); \n    bool isAwaits = false;\n    bool isEnsures = false;\n    bool isModifies = false;\n    bool isReads = false;\n    bool isRequires = false;\n    bool isUndefinedUnless = false;\n    bool isLogs = false;\n    Token x = null;\n    spec = null;\n    List<Attribute> attrs = new List<Attribute>();\n  .)\n  ( awaits              (. isAwaits = true; x = t; .)\n  | ensures             (. isEnsures = true; x = t; .)\n  | modifies            (. isModifies = true; x = t; .)\n  | reads               (. isReads = true; x = t; .)\n  | requires            (. isRequires = true; x = t; .)\n  | \"undefined_unless\"  (. isUndefinedUnless = true; x = t; .)\n  | \"logs\"              (. isLogs = true; x = t; .)\n  )\n  { (. Attribute attr; .) Attribute<out attr> (. attrs.Add(attr); .) }\n  Expressions<out elements>\n  (.\n    if (isAwaits)               { spec = new MethodSpecAwaits(x, elements); }\n    else if (isEnsures)         { spec = new MethodSpecEnsures(x, elements); }\n    else if (isModifies)        { spec = new MethodSpecModifies(x, elements); }\n    else if (isReads)           { spec = new MethodSpecReads(x, elements); }\n    else if (isRequires)        { spec = new MethodSpecRequires(x, elements); }\n    else if (isUndefinedUnless) { spec = new MethodSpecUndefinedUnless(x, elements); }\n    else if (isLogs)            { spec = new MethodSpecLogs(x, elements); }\n  .)\n  [ semi ]\n  (. spec.Attrs = attrs; spec.LastTok = t; .)\n.\n\nMethodDecl<out MethodDecl method>\n= (. Token x; .)\n  method (. x = t; method = new MethodDecl(x); .)\n  { (. Attribute attr; .)\n    Attribute<out attr>\n    (. method.Attrs.Add(attr); .)\n  } \n  (. Ident ident; .) Ident<out ident> (. method.Name = ident; .)\n  openparen [ (. List<Parameter> args; .) Parameters<out args> (. method.Args = args; .) ] closeparen\n  [ (. Parameter ret; .) \"returns\" openparen Parameter<out ret> closeparen (. method.Ret = ret; .) ]\n  { (. MethodSpec methodSpec; .) \n    MethodSpec<out methodSpec> \n    (. method.Specs.Add(methodSpec); .)\n  }\n  [ \n    lbrace \n    { (. Statement stmt; .) Statement<out stmt> (. method.Stmts.Add(stmt); .) }\n    rbrace\n  ]\n  (. method.LastTok = t; .)\n.\n\nVarDecl<out VarDecl variable>\n=\n  (. \n    Ident name;\n    Type ty = null;\n    Expr val = null;\n    bool isGhost = false;\n    bool isNoaddr = false;\n    bool isConst = false;\n    bool isStronglyConsistent = false;\n    Token x;\n  .)\n  (. x = la; .)\n  { ghost (. isGhost = true; .) | noaddr (. isNoaddr = true; .) | const (. isConst = true; .) | sc (. isStronglyConsistent = true; .) }\n  var\n  Ident<out name> colon Type <out ty> [ equalsign Rhs<out val> ] semi\n  (.\n    variable = new VarDecl(x, name, ty, val, isGhost, isNoaddr, isConst, isStronglyConsistent);\n    variable.LastTok = t;\n  .)\n.\n\nStructDecl<out StructDecl struc>\n=\n  (.\n    Ident name;\n    VarDecl variable;\n    Token x;\n  .)\n  \"struct\" (. x = t; .)\n  Ident<out name> lbrace VarDecl<out variable>\n  (.\n    struc = new StructDecl(x, name);\n    struc.Decls.Add(variable);\n  .)\n  { VarDecl<out variable> (. struc.Decls.Add(variable); .) } rbrace\n  (. struc.LastTok = t; .)\n.\n\nLevelDecl<out LevelDecl level>\n=\n  (. Ident name; Token x; .)\n  \"level\" (. x = t; .)\n  Ident<out name> (. level = new LevelDecl(x, name); .)\n  lbrace\n    { \n      (. VarDecl variable; .)          VarDecl<out variable>             (. level.Globals.Add(variable); .)\n    | (. MethodDecl method; .)         MethodDecl<out method>            (. level.Members.Add(method); .)\n    | (. InvariantDecl invariant; .)   InvariantDecl<out invariant>      (. level.Invariants.Add(invariant); .)\n    | (. YieldPredicateDecl ypDecl; .) YieldPredicateDecl<out ypDecl>    (. level.Members.Add(ypDecl); .)\n    }\n  rbrace (. level.LastTok = t; .)\n.\n\nGenericTypeParameters<.out List<Ident> args.>\n= (. args = new List<Ident>(); \n     Ident id;\n  .)\n  openAngleBracket \n  Ident<out id> (. args.Add(id); .)\n  { comma Ident<out id> (. args.Add(id); .) }\n  closeAngleBracket\n.\n\nDatatypeMemberDecl<out DatatypeMemberDecl memberDecl>\n=\n  (. Ident name; List<Parameter> args = new List<Parameter>(); .)\n  Ident<out name> [ openparen [ Parameters<out args> ] closeparen ]\n  (. memberDecl = new DatatypeMemberDecl(name, args); memberDecl.LastTok = t; .)\n.\n\nDatatypeDecl<out DatatypeDecl datatype>\n=\n  (.\n    Token x;\n    Ident name;\n    UserDefinedType ty;\n    List<Ident> parameterList = new List<Ident>();\n    DatatypeMemberDecl memberDecl;\n  .)\n  \"datatype\" (. x = t; .) \n  Ident<out name>\n  [ GenericTypeParameters<out parameterList> ] equal\n  (. \n    ty = new UserDefinedType(name, parameterList); \n  .)\n  (. datatype = new DatatypeDecl(x, ty); .)\n  DatatypeMemberDecl<out memberDecl> (. memberDecl.parent = datatype; datatype.MemberDeclList.Add(memberDecl); .)\n  { verticalbar DatatypeMemberDecl<out memberDecl> (. datatype.MemberDeclList.Add(memberDecl); .) }\n  (. datatype.LastTok = t; .)\n.\n\nInclude<out string path> =\n  \"include\"\n  stringToken (. path = t.val; .)\n.\n\nTSOElimStrategy<out ProofStrategy strategy> =\n  (. Ident id; Token x; .)\n  \"tso_elim\" (. x = t; .)\n  Ident<out id>\n  (. strategy = new TSOElimStrategy(x, id); strategy.LastTok = t; .)\n.\n\nWeakeningStrategy<out ProofStrategy strategy> =\n  \"weakening\"\n  (. strategy = new WeakeningStrategy(t); strategy.LastTok = t; .)\n.\n\nCombiningStrategy<out ProofStrategy strategy> =\n  (.\n    Ident startLabel;\n    Ident endLabel;\n    Ident newLabel;\n    Token x;\n  .)\n  \"combining\" (. x = t; .)\n  LabelIdent<out startLabel> LabelIdent<out endLabel> LabelIdent<out newLabel>\n  (. strategy = new CombiningStrategy(x, startLabel, endLabel, newLabel); strategy.LastTok = t; .)\n.\n\nCHLInvariant =\n  ( \"chl_invariant\" | \"chl_yield_pred\" ) { Attribute<out _> } ident [ stringToken ].\n\nInductiveInvariant =\n  \"inductive_invariant\" { Attribute<out _> } ident [ stringToken ].\n\nAssumeIntroStrategy<out ProofStrategy strategy> =\n  \"assume_intro\" (. strategy = new AssumeIntroStrategy(t); .)\n  { CHLInvariant | InductiveInvariant } // TODO: add these to the AST node\n  (. strategy.LastTok = t; .)\n.\n\nVarIntroStrategy<out ProofStrategy strategy>\n= (. Ident ident; .)\n  \"var_intro\"\n  (. VarIntroStrategy varIntroStrategy = new VarIntroStrategy(t); .)\n  Ident<out ident> (. varIntroStrategy.Variables.Add(ident); .)\n  {\n    (. Ident id; .) comma Ident<out id> (. varIntroStrategy.Variables.Add(id); .)\n  }\n  (. strategy = varIntroStrategy; strategy.LastTok = t; .)\n.\n\nVarHidingStrategy<out ProofStrategy strategy>\n= (. Ident ident; .)\n  \"var_hiding\"\n  (. VarHidingStrategy varHidingStrategy = new VarHidingStrategy(t); .)\n  Ident<out ident> (. varHidingStrategy.Variables.Add(ident); .)\n  {\n    (. Ident id; .) comma Ident<out id> (. varHidingStrategy.Variables.Add(id); .)\n  }\n  (. strategy = varHidingStrategy; strategy.LastTok = t; .)\n.\n\nProofStrategy<out ProofStrategy strategy> =\n  (. strategy = null; .)\n  ( WeakeningStrategy<out strategy>\n  | TSOElimStrategy<out strategy>\n  | CombiningStrategy<out strategy>\n  | AssumeIntroStrategy<out strategy>\n  | VarIntroStrategy<out strategy>\n  | VarHidingStrategy<out strategy>\n  ).\n\nProofDecl<out ProofDecl proof>\n= (. Ident name, L, H; ProofStrategy strategy; Token x; .)\n  \"proof\" (. x = t; .)\n  Ident<out name> lbrace \"refinement\" Ident<out L> Ident<out H> ProofStrategy<out strategy> rbrace\n  (. proof = new ProofDecl(x, name, L, H, strategy); proof.LastTok = t; .)\n.\n\nStarmada\n= (.\n    LevelDecl level;\n    StructDecl struc;\n    ProofDecl proof;\n    DatatypeDecl datatype;\n .)\n  (. program.FirstTok = la; .)\n  { (. string path; .) Include<out path> (. program.Includes.Add(path); .) }\n  { \n     LevelDecl <out level> (. program.Levels.Add(level); .)\n   | StructDecl <out struc> (. program.StructDecls.Add(struc); .)\n   | ProofDecl <out proof> (. program.Proofs.Add(proof); .)\n   | DatatypeDecl <out datatype> (. program.DatatypeDecls.Add(datatype); .)\n  }\n  (. program.FirstTok = t; .)\n.\n\nEND Starmada.\n"
  },
  {
    "path": "experimental/Source/Armada/Util.cs",
    "content": "using System.Collections.Generic;\nusing System.Diagnostics.Contracts;\n\nnamespace Microsoft.Starmada\n{\n    public class Util\n    {\n        /// <summary>\n        /// For \"S\" returns S and false.\n        /// For @\"S\" return S and true.\n        /// Assumes that s has one of these forms.\n        /// </summary>\n        public static string RemoveParsedStringQuotes(string s, out bool isVerbatimString)\n        {\n            Contract.Requires(s != null);\n            var len = s.Length;\n            if (s[0] == '@') {\n                isVerbatimString = true;\n                return s.Substring(2, len - 3);\n            } else {\n                isVerbatimString = false;\n                return s.Substring(1, len - 2);\n            }\n        }\n\n        public static string ListExprsToString(List<Expr> elements, bool labelOn, string sperator = \", \")\n        {\n            List<string> elementsStr = new List<string>();\n            foreach (Expr expr in elements)\n            {\n                elementsStr.Add(expr.ToString(0, labelOn));\n            }\n            return string.Join(sperator, elementsStr);\n        }\n\n        public static string ListIdentsToString(List<Ident> idents, bool labelOn, string sperator = \", \")\n        {\n            List<string> elementsStr = new List<string>();\n            foreach (Ident ident in idents)\n            {\n                elementsStr.Add(ident.ToString(0, labelOn));\n            }\n            return string.Join(sperator, elementsStr);\n        }\n\n        public static void CheckLowerCase(Ident ident, ref Errors errors)\n        {\n            if (ident.Name.ToLower() != ident.Name)\n            {\n                errors.SynErr(ident.FirstTok.line, ident.FirstTok.col, \"type must be lower case!\");\n            }\n        }\n    }\n}\n\n"
  },
  {
    "path": "experimental/Source/Armada/dotnet-tools.json",
    "content": "{\n  \"version\": 1,\n  \"isRoot\": true,\n  \"tools\": {\n    \"cocor\": {\n      \"version\": \"2014.12.24\",\n      \"commands\": [\n        \"coco\"\n      ]\n    }\n  }\n}\n\n"
  },
  {
    "path": "experimental/Source/Armada.sln",
    "content": "﻿\r\nMicrosoft Visual Studio Solution File, Format Version 12.00\r\n# Visual Studio Version 16\r\nVisualStudioVersion = 16.0.810.17\r\nMinimumVisualStudioVersion = 10.0.40219.1\r\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Armada\", \"Armada\\Armada.csproj\", \"{9F136CC3-A181-43DA-BCDB-3E4E31DC7546}\"\r\nEndProject\r\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Editor\", \"Editor\\Editor.csproj\", \"{274784B6-9A3B-4051-A045-8FCD3D4D1893}\"\r\nEndProject\r\nGlobal\r\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\r\n\t\tDebug|Any CPU = Debug|Any CPU\r\n\t\tRelease|Any CPU = Release|Any CPU\r\n\tEndGlobalSection\r\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\r\n\t\t{9F136CC3-A181-43DA-BCDB-3E4E31DC7546}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{9F136CC3-A181-43DA-BCDB-3E4E31DC7546}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{9F136CC3-A181-43DA-BCDB-3E4E31DC7546}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{9F136CC3-A181-43DA-BCDB-3E4E31DC7546}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{274784B6-9A3B-4051-A045-8FCD3D4D1893}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{274784B6-9A3B-4051-A045-8FCD3D4D1893}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{274784B6-9A3B-4051-A045-8FCD3D4D1893}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{274784B6-9A3B-4051-A045-8FCD3D4D1893}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\tEndGlobalSection\r\n\tGlobalSection(SolutionProperties) = preSolution\r\n\t\tHideSolutionNode = FALSE\r\n\tEndGlobalSection\r\n\tGlobalSection(ExtensibilityGlobals) = postSolution\r\n\t\tSolutionGuid = {5FBEA11D-B071-43FF-95B3-9DC6E4BD22E0}\r\n\tEndGlobalSection\r\n\tGlobalSection(MonoDevelopProperties) = preSolution\r\n\t\toutputpath = ../Binary/\r\n\tEndGlobalSection\r\nEndGlobal\r\n"
  },
  {
    "path": "experimental/Source/Editor/BasicEquality.cs",
    "content": "using System.Collections.Generic;\nusing Microsoft.Starmada;\n\nnamespace Editor\n{\n    public class IdentEq : IEqualityComparer<Ident>\n    {\n        public bool Equals(Ident x, Ident y)\n        {\n            return x.Name == y.Name;\n        }\n\n        public int GetHashCode(Ident obj)\n        {\n            return obj.Name.GetHashCode();\n        }\n    }\n    public class IdentStrEq : IEqualityComparer<IdentStr>\n    {\n        public bool Equals(IdentStr x, IdentStr y)\n        {\n            return x.Str == y.Str;\n        }\n\n        public int GetHashCode(IdentStr obj)\n        {\n            return obj.Str.GetHashCode();\n        }\n    }\n    public class ExprEq : IEqualityComparer<Expr>\n    {\n        public bool Equals(Expr x, Expr y)\n        {\n            return x.ToString(0, false) == y.ToString(0, false);\n        }\n\n        public int GetHashCode(Expr obj)\n        {\n            return obj.GetHashCode();\n        }\n    }\n}\n"
  },
  {
    "path": "experimental/Source/Editor/Driver.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Microsoft.Starmada;\n\nusing StarmadaParser = Microsoft.Starmada.Parser;\n\nnamespace Editor\n{\n    public class Driver\n    {\n        // Project Root\n        public string InputRoot;\n        // Source files\n        public List<string> InputFiles;\n\n        // Caret with selection\n        public StmtRangeLoc CaretRangeLoc;\n\n        // Level range\n        public LevelRange LevelRange;\n\n        // ProjectSummary\n        public ProjectSummary Project;\n\n        public static bool PositionBetweenTokens(Token firstTok, Token lastTok, (int, int) position)\n        {\n            var (line, col) = position;\n            bool afterFirstTok = (firstTok.line == line && firstTok.col < col) || firstTok.line < line;\n            bool beforeLastTok = line < lastTok.line || (line == lastTok.line && col <= lastTok.col + lastTok.val.Length);\n            return afterFirstTok && beforeLastTok;\n        }\n\n        private IEnumerable<string> inputFilesFromTarget(string target)\n        {\n            List<string> inputFiles = new();\n            System.IO.DirectoryInfo info = new(target);\n            foreach (var f in info.GetFiles(\"*.arm\"))\n            {\n                inputFiles.Add(f.FullName);\n            }\n            foreach (var d in info.GetDirectories(\"*.*\"))\n            {\n                if (d.Name != \".build\")\n                {\n                    inputFiles.AddRange(inputFilesFromTarget(d.ToString()));\n                }\n            }\n            return inputFiles;\n        }\n\n        public Driver(string target)\n        {\n            InputRoot = target;\n            InputFiles = new(inputFilesFromTarget(target));\n            CaretRangeLoc = null;\n            LevelRange = null;\n            Project = null;\n        }\n\n        public Driver Run(PositionSelection ps, (IdentStr LLevel, IdentStr HLevel) lvRange)\n        {\n            ProjectSummary proj = new();\n\n            Dictionary<IdentStr, LevelDecl> levels = new(new IdentStrEq());\n            Dictionary<IdentStr, ProofDecl> proofs = new(new IdentStrEq());\n            Dictionary<IdentStr, IdentStr> proofMap = new(new IdentStrEq());\n            HashSet<IdentStr> proofTails = new(new IdentStrEq());\n\n            List<LevelDecl> levelChain = new();\n            List<ProofDecl> proofChain = new();\n\n            CaretLevelMethod caretLevelMethod = null;\n\n            foreach (var inputFile in InputFiles)\n            {\n                Console.WriteLine(\n                    $\"Scanning {InputRoot}{inputFile.Remove(0, System.IO.Path.GetFullPath(InputRoot).Length)}.\"\n                );\n                Scanner scanner = new Scanner(inputFile);\n                StarmadaParser parser = new StarmadaParser(scanner, inputFile);\n                parser.Parse();\n\n                // set StatementLocs\n                if (inputFile.Equals(ps.File))\n                {\n                    caretLevelMethod = new(parser.program, ps.Start);\n                    if (ps.Selection)\n                    {\n                        CaretLevelMethod caretLevelMethodEnd = new(parser.program, ps.End);\n                        if (!caretLevelMethod.Equals(caretLevelMethodEnd))\n                        {\n                            throw new FatalError(\"Invalid Selection across methods\");\n                        }\n                    }\n                }\n                // init levels and proofs\n                foreach (var level in parser.program.Levels)\n                {\n                    levels.Add(new(level.Name), level);\n                    proj.LevelInfoDict.Add(new(level.Name), new LevelInfo(inputFile));\n                }\n                foreach (var proof in parser.program.Proofs)\n                {\n                    proofs.Add(new(proof.LLevelName), proof);\n                    proofMap.Add(new(proof.LLevelName), new(proof.HLevelName));\n                    proofTails.Add(new(proof.HLevelName));\n                }\n            }\n\n            if (caretLevelMethod is null)\n            {\n                throw new FatalError(\"CaretLevelMethod not set\");\n            }\n\n            List<IdentStr> proofHead = new List<IdentStr>();\n            foreach (var (low, _) in proofMap)\n            {\n                if (!proofTails.Contains(low))\n                {\n                    proofHead.Add(low);\n                }\n            }\n            if (proofHead.Count > 1)\n            {\n                throw new FatalError(\"Multiple lowest levels found\");\n            }\n            if (proofHead.Count == 0)\n            {\n                throw new FatalError(\"No lowest level found\");\n            }\n            IdentStr cur = proofHead[0];\n\n            int chainCnt = 0;\n            while (true)\n            {\n                if (!levels.ContainsKey(cur))\n                {\n                    throw new FatalError(\"Level mentioned is not found\");\n                }\n                levelChain.Add(levels[cur]);\n                proj.LevelInfoDict[new(levels[cur].Name)].ChainIdx = chainCnt;\n\n                if (!proofMap.ContainsKey(cur))\n                {\n                    break;\n                }\n\n                if (!proofs.ContainsKey(cur))\n                {\n                    throw new FatalError(\"Proof mentioned is not found\");\n                }\n                proofChain.Add(proofs[cur]);\n\n                // Iterate\n                cur = proofMap[cur];\n                chainCnt += 1;\n            }\n\n            LevelRange = new(\n                lvRange.LLevel is null ? new(levelChain.First().Name) : lvRange.LLevel,\n                lvRange.HLevel is null ? new(levelChain.Last().Name) : lvRange.HLevel\n            );\n\n            // generate LevelStmtSeqChain\n            foreach (var level in levelChain)\n            {\n                proj.LevelSummaryChain.Add(new LevelSummary(level));\n            }\n\n            // generate ProofChain\n            foreach (var proof in proofChain)\n            {\n                proj.ProofSummaryChain.Add(new ProofSummary(proof));\n            }\n\n            Project = proj;\n\n            // Set the CaretRangeLoc\n            caretLevelMethod.SetStmtSeq(Project);\n            StmtLoc start = caretLevelMethod.GetStmtLoc(ps.Start);\n            if (ps.Selection)\n            {\n                StmtLoc end = caretLevelMethod.GetStmtLoc(ps.End);\n                CaretRangeLoc = new(start, end);\n            }\n            else\n            {\n                CaretRangeLoc = new(start);\n            }\n\n            return this;\n        }\n\n        public List<StmtGroupToken> StmtGroupLocToToken(List<StmtGroupLoc> groupLocs)\n        {\n            List<StmtGroupToken> groupToks = new(groupLocs.Select(glo => glo.ToStmtGroupToken(Project)));\n            return groupToks;\n        }\n\n        public void DumpCaretCandidates(string file)\n        {\n            StatementSeq seq = Project\n                .GetLevelSummary(CaretRangeLoc.Level)\n                .MethodCollection[CaretRangeLoc.Method];\n\n            string buffer = \"\";\n            for (int i = CaretRangeLoc.StmtIdx; i <= CaretRangeLoc.StmtEndIdx; i++)\n            {\n                Statement s = seq[i];\n                buffer += s.ToString(0, true) + '\\n';\n            }\n\n            System.IO.File.WriteAllText(file, buffer);\n        }\n    }\n\n    class CaretLevelMethod\n    {\n        IdentStr level;\n        IdentStr method;\n        public CaretLevelMethod(StarmadaProgram program, (int, int) position)\n        {\n            foreach (var lv in program.Levels)\n            {\n                if (Driver.PositionBetweenTokens(lv.FirstTok, lv.LastTok, position))\n                {\n                    foreach (var member in lv.Members)\n                    {\n                        if (Driver.PositionBetweenTokens(member.FirstTok, member.LastTok, position))\n                        {\n                            if (member is MethodDecl)\n                            {\n                                MethodDecl me = (MethodDecl)member;\n                                level = new(lv.Name);\n                                method = new(me.Name);\n                                return;\n                            }\n                            else\n                            {\n                                throw new FatalError(\"Refactor is performed outside method\");\n                            }\n                        }\n                    }\n                    throw new FatalError(\"Refactor is performed in invalid region in a level\");\n                }\n            }\n            throw new FatalError(\"Refactor is performed outside levels\");\n        }\n        public bool Equals(CaretLevelMethod other)\n        {\n            return level.Equals(other.level) && method.Equals(other.method);\n        }\n\n        private StatementSeq stmts;\n        public void SetStmtSeq(ProjectSummary pc)\n        {\n            stmts = pc.LevelSummaryChain[pc.LevelInfoDict[level].ChainIdx].MethodCollection[method];\n        }\n        public StmtLoc GetStmtLoc((int, int) position)\n        {\n            for (int i = 0; i < stmts.Count; i++)\n            {\n                Statement stmt = stmts[i];\n                if (Driver.PositionBetweenTokens(stmt.FirstTok, stmt.LastTok, position))\n                {\n                    return new StmtLoc(level, method, i);\n                }\n            }\n            throw new FatalError(\"Refactor is performed outside the statements\");\n        }\n    }\n}"
  },
  {
    "path": "experimental/Source/Editor/Editor.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.IO;\nusing CommandLine;\n\nusing CommandLineParser = CommandLine.Parser;\nusing Editor;\n\nnamespace Starmada\n{\n    class Editor\n    {\n        [Verb(\"backup\", HelpText = \"Clean `.build` and duplicate the current project.\")]\n        public class BackupOpts\n        {\n            public string Destination { get; set; } = \".build/backup\";\n        }\n\n        // Clean `.build` and duplicate the current project. Effectively `cp -f`.\n        public static int Backup(BackupOpts o)\n        {\n            if (Directory.Exists(o.Destination))\n            {\n                Directory.Delete(o.Destination, true);\n            }\n\n            DirectoryInfo cur = new(Directory.GetCurrentDirectory());\n            DirectoryInfo dest = Directory.CreateDirectory(o.Destination);\n            if (!dest.Exists || !cur.Exists)\n            {\n                throw new DirectoryNotFoundException(\n                    $\"One of the directories involved not valid:\\n\\t{cur.FullName}\\n\\t{dest.FullName}\"\n                );\n            }\n\n            IOUtils.CopyArm(cur, dest);\n\n            return 0;\n        }\n\n        [Verb(\"extract\", HelpText = \"Given a caret position, extract information for the refactor process.\")]\n        public class ExtractOpts\n        {\n            // the caret information\n            [Option('f', \"file\", Required = true, HelpText = \"Select file.\")]\n            public string FileName { get; set; }\n            [Option('p', \"position\", Required = true, HelpText = \"Select position.\")]\n            public string Position { get; set; }\n\n            // level of propagation\n            [Option('l', \"low\", Required = false, HelpText = \"Set lowest propagating level.\")]\n            public IdentStr LLevel { get; set; }\n            [Option('h', \"high\", Required = false, HelpText = \"Set highest propagating level.\")]\n            public IdentStr HLevel { get; set; }\n\n            // caret source code\n            public string CaretCandidates { get; set; } = \".build/candidates\";\n        }\n\n        // Given a caret position, extract information for the refactor process.\n        // Needs most of the user's input.\n        public static int Extract(ExtractOpts o)\n        {\n            // init driver\n            Driver d = new Driver(Directory.GetCurrentDirectory()).Run(\n                new PositionSelection(o.FileName, o.Position),\n                (o.LLevel, o.HLevel)\n            );\n            // init mapper and perform mapping\n            Mapper m = new(d.Project, d.LevelRange);\n            List<StmtGroupLoc> groupLocs = m.IdentifyByStatementSelection(d.CaretRangeLoc);\n            List<StmtGroupToken> groupToks = d.StmtGroupLocToToken(groupLocs);\n\n            d.DumpCaretCandidates(o.CaretCandidates);\n\n            IOUtils.Cache c = new(d.InputFiles, groupToks);\n            c.MemDump();\n\n            return 0;\n        }\n\n        [Verb(\"apply\", HelpText = \"Apply the refactor from candidates.\")]\n        public class ApplyOpts\n        {\n            public string Candidates { get; set; } = \".build/candidates\";\n        }\n\n        // Apply the refactor from candidates.\n        public static int Apply(ApplyOpts o)\n        {\n            string current = Directory.GetCurrentDirectory();\n            IOUtils.Cache c = IOUtils.Cache.MemLoad();\n            // perform refactor\n            RefactorProjectBuffer r = new(c.InputFiles, current, current);\n            List<string> candidates = r.ReadFromFile(o.Candidates, \"deferred\");\n            r.FineGrainedReplacement(c.StmtGroupTokens, candidates);\n            r.Dump(\"file\", \"deferred\");\n            return 0;\n        }\n\n        [Verb(\"restore\", HelpText = \"Clean current project and restore previous state.\")]\n        public class RestoreOpts\n        {\n            public string Source { get; set; } = \".build/backup\";\n        }\n\n        // Restore the old project if something went wrong.\n        // Clean current project and restore previous state.\n        public static int Restore(RestoreOpts o)\n        {\n            DirectoryInfo src = new(o.Source);\n            DirectoryInfo cur = new(Directory.GetCurrentDirectory());\n            if (!src.Exists || !cur.Exists)\n            {\n                throw new DirectoryNotFoundException(\n                    $\"One of the directories involved not valid:\\n\\t{cur.FullName}\\n\\t{src.FullName}\"\n                );\n            }\n\n            IOUtils.DeleteArm(cur);\n            IOUtils.CopyArm(src, cur);\n\n            return 0;\n        }\n\n        [Verb(\"shoot\", HelpText = \"One pass mode with all options.\")]\n        public class Options\n        {\n            // level of propagation\n            [Option('l', \"low\", Required = false, HelpText = \"Set lowest propagating level.\")]\n            public IdentStr LLevel { get; set; }\n            [Option('h', \"high\", Required = false, HelpText = \"Set highest propagating level.\")]\n            public IdentStr HLevel { get; set; }\n\n            // the new input arguments\n            [Option('f', \"file\", Required = true, HelpText = \"Select file.\")]\n            public string FileName { get; set; }\n            [Option('p', \"position\", Required = true, HelpText = \"Select position.\")]\n            public string Position { get; set; }\n\n            // output mode\n            [Option('m', \"mode\", Default = \"file\", Required = false, HelpText = \"Choose output mode [stdout/file].\")]\n            public string OutputMode { get; set; }\n\n            // deferred check\n            [Option('c', \"check\", Default = \"deferred\", Required = false, HelpText = \"Choose parser and type check mode [eager/deferred].\")]\n            public string CheckMode { get; set; }\n\n            // input dir\n            [Value(0, Required = true, MetaName = \"input_dir\", HelpText = \"Input dir of the project\")]\n            public string Input { get; set; }\n            // output dir\n            [Option('o', \"output\", Required = false, HelpText = \"Output dir of the project\")]\n            public string Output { get; set; }\n        }\n\n        static void Main(string[] args)\n        {\n            CommandLineParser.Default\n            .ParseArguments<ExtractOpts, ApplyOpts, BackupOpts, RestoreOpts, Options>(args)\n            .MapResult(\n                (BackupOpts o) => Backup(o),\n                (ExtractOpts o) => Extract(o),\n                (ApplyOpts o) => Apply(o),\n                (RestoreOpts o) => Restore(o),\n                (Options o) =>\n                {\n                    // init driver\n                    Driver d = new Driver(o.Input).Run(\n                        new PositionSelection(o.FileName, o.Position),\n                        (o.LLevel, o.HLevel)\n                    );\n                    // init mapper and perform mapping\n                    Mapper m = new(d.Project, d.LevelRange);\n                    List<StmtGroupLoc> groupLocs = m.IdentifyByStatementSelection(d.CaretRangeLoc);\n                    List<StmtGroupToken> groupToks = d.StmtGroupLocToToken(groupLocs);\n\n                    // perform refactor\n                    RefactorProjectBuffer r = new(d.InputFiles, o.Input, o.Output);\n                    List<string> candidates = r.ReadFromStdin(o.CheckMode);\n                    r.FineGrainedReplacement(groupToks, candidates);\n                    r.Dump(o.OutputMode, o.CheckMode);\n                    return 0;\n                },\n                err => 1\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "experimental/Source/Editor/Editor.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\r\n\r\n  <PropertyGroup>\r\n    <OutputType>Exe</OutputType>\r\n    <TargetFramework>net6.0</TargetFramework>\r\n  </PropertyGroup>\r\n\r\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' \">\r\n    <OutputPath>..\\..\\Binary</OutputPath>\r\n    <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' \">\r\n    <OutputPath>..\\..\\Binary</OutputPath>\r\n    <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>\r\n  </PropertyGroup>\r\n  <ItemGroup>\r\n    <PackageReference Include=\"CommandLineParser\" Version=\"2.9.1\" />\r\n  </ItemGroup>\r\n\r\n  <ItemGroup>\r\n    <ProjectReference Include=\"../Armada/Armada.csproj\" />\r\n  </ItemGroup>\r\n</Project>\r\n"
  },
  {
    "path": "experimental/Source/Editor/IO.cs",
    "content": "using System.Collections.Generic;\nusing System.IO;\nusing System.Text;\nusing System.Text.Json;\nusing System.Text.Json.Serialization;\nusing Editor;\n\nnamespace Starmada\n{\n    class IOUtils\n    {\n        public static void DeleteArm(DirectoryInfo dir)\n        {\n            // Cache directories before we start copying\n            DirectoryInfo[] dirs = dir.GetDirectories();\n\n            // Get the files in the source directory and copy to the destination directory\n            foreach (FileInfo file in dir.GetFiles())\n            {\n                if (file.Extension == \".arm\")\n                {\n                    file.Delete();\n                }\n            }\n\n            // Recursively call this method into subDir\n            foreach (DirectoryInfo subDir in dirs)\n            {\n                // Jump the .build dir\n                if (subDir.Name == \".build\")\n                {\n                    continue;\n                };\n                DeleteArm(subDir);\n            }\n        }\n\n        public static void CopyArm(DirectoryInfo dir, DirectoryInfo dest)\n        {\n            // Cache destination directory string\n            string destDir = dest.FullName;\n\n            // Cache directories before we start copying\n            DirectoryInfo[] dirs = dir.GetDirectories();\n\n            // Create the destination directory\n            Directory.CreateDirectory(destDir);\n\n            // Get the files in the source directory and copy to the destination directory\n            foreach (FileInfo file in dir.GetFiles())\n            {\n                if (file.Extension == \".arm\")\n                {\n                    string targetFilePath = Path.Combine(destDir, file.Name);\n                    file.CopyTo(targetFilePath);\n                }\n            }\n\n            // Recursively call this method into subDir\n            foreach (DirectoryInfo subDir in dirs)\n            {\n                // Jump the .build dir\n                if (subDir.Name == \".build\")\n                {\n                    continue;\n                };\n                string newDestinationDir = Path.Combine(destDir, subDir.Name);\n                CopyArm(subDir, new(newDestinationDir));\n            }\n        }\n\n        public class Cache\n        {\n\n            public List<string> InputFiles { get; }\n            public List<StmtGroupToken> StmtGroupTokens { get; }\n\n            [JsonConstructor]\n            public Cache(List<string> inputFiles, List<StmtGroupToken> stmtGroupTokens)\n            {\n                InputFiles = inputFiles;\n                StmtGroupTokens = stmtGroupTokens;\n            }\n\n            public static string PathBuild()\n            {\n                return \".build\";\n            }\n            public static string PathCache()\n            {\n                Directory.CreateDirectory(PathBuild());\n                return \".build/.cache.json\";\n            }\n\n            public void MemDump()\n            {\n                string jsonCache = JsonSerializer.Serialize(this);\n                File.WriteAllText(PathCache(), jsonCache);\n            }\n\n            public static Cache MemLoad()\n            {\n                string jsonCache = File.ReadAllText(PathCache());\n                Cache c = JsonSerializer.Deserialize<Cache>(jsonCache);\n                return c;\n            }\n        }\n    }\n}"
  },
  {
    "path": "experimental/Source/Editor/Mapper.cs",
    "content": "using System.Collections.Generic;\nusing System.Linq;\nusing Microsoft.Starmada;\n\nnamespace Editor\n{\n    class Mapper\n    {\n        public ProjectSummary Project;\n        public LevelRange Range;\n        private Dictionary<IdentStr, Diff<StatementSeq, Statement>>[] diffs;\n\n        public Mapper(ProjectSummary proj, LevelRange range)\n        {\n            Project = proj;\n            Range = range;\n            diffs = new Dictionary<IdentStr, Diff<StatementSeq, Statement>>[Project.LevelSummaryChain.Count - 1];\n        }\n\n        protected EqualityComparer<Statement> EqualityPicker(ProofSummary proof)\n        {\n            ProofStrategy ps = proof.Strategy;\n            if (ps is TSOElimStrategy) return new TSOElimEq();\n            if (ps is WeakeningStrategy) return new WeakeningEq();\n            // Starweakening - currently not in parser\n            if (ps is CombiningStrategy) return new CombiningEq();\n            if (ps is AssumeIntroStrategy) return new AssumeIntroEq();\n            // Reduction - currently not in parser\n            if (ps is VarIntroStrategy vi_ps) return new VarIntroEq(vi_ps);\n            if (ps is VarHidingStrategy vh_ps) return new VarHidingEq(vh_ps);\n            return new FallbackEq();\n        }\n\n        private Diff<StatementSeq, Statement> getDiff(int lower_idx, IdentStr method)\n        {\n            Dictionary<IdentStr, Diff<StatementSeq, Statement>> diff_lv = diffs[lower_idx];\n            if (diff_lv is null)\n            {\n                diff_lv = new();\n            }\n            if (!diff_lv.TryGetValue(method, out Diff<StatementSeq, Statement> diff_method))\n            {\n                diff_method = null;\n                diff_lv.Add(method, diff_method);\n            }\n            if (diff_method is null)\n            {\n                int i = lower_idx;\n                StatementSeq curSeq = Project.LevelSummaryChain[i].MethodCollection[method];\n                StatementSeq nextSeq = Project.LevelSummaryChain[i + 1].MethodCollection[method];\n                ProofSummary proof = Project.ProofSummaryChain[i];\n                Diff<StatementSeq, Statement> diff = new(\n                    curSeq,\n                    nextSeq,\n                    EqualityPicker(proof)\n                );\n                diff_method = diff;\n            }\n            return diff_method;\n        }\n\n        private List<StmtLoc> IdentifyByStatement(StmtLoc loc)\n        {\n            LevelInfo llv = Project.LevelInfoDict[Range.LLevel];\n            LevelInfo hlv = Project.LevelInfoDict[Range.HLevel];\n            LevelInfo lv = Project.LevelInfoDict[loc.Level];\n            bool valid = llv.ChainIdx <= lv.ChainIdx && lv.ChainIdx <= hlv.ChainIdx;\n            if (!valid)\n            {\n                throw new FatalError(\n                    $\"Incorrect level dependency: requiring {Range.LLevel} <= {loc.Level} <= {Range.HLevel}\"\n                );\n            }\n            // Check if method appears in all levels\n            for (int i = llv.ChainIdx; i <= hlv.ChainIdx; i++)\n            {\n                LevelSummary lvSummary = Project.LevelSummaryChain[i];\n                if (!lvSummary.MethodCollection.ContainsKey(loc.Method))\n                {\n                    throw new FatalError(\n                        $\"Method {loc.Method} not found in {lvSummary.Name}\"\n                    );\n                }\n            }\n\n            List<int> mapping = new List<int>();\n            if (Project.LevelSummaryChain[lv.ChainIdx].MethodCollection[loc.Method].Count <= loc.StmtIdx)\n            {\n                throw new FatalError(\n                    $\"Statement index {loc.StmtIdx} in level {loc.Level} method {loc.Method} out of bound.\"\n                );\n            }\n            mapping.Add(loc.StmtIdx);\n\n            // Lower level propagation\n            for (int i = lv.ChainIdx; i > llv.ChainIdx; i--)\n            {\n                Diff<StatementSeq, Statement> diff = getDiff(i - 1, loc.Method);\n                int prevIdx = diff.MapExactBackward(mapping.Last());\n                // Invalid idx\n                if (prevIdx < 0)\n                {\n                    IdentStr levelName = Project.LevelSummaryChain[i - 1].Name;\n                    throw new FatalError(\n                        $\"Propagation failed in level {levelName} method {loc.Method}.\"\n                    );\n                }\n                mapping.Add(prevIdx);\n            }\n\n            // Reverse indexChain to perform forward propagation\n            mapping.Reverse();\n\n            // Higher level propagation\n            for (int i = lv.ChainIdx; i < hlv.ChainIdx; i++)\n            {\n                Diff<StatementSeq, Statement> diff = getDiff(i, loc.Method);\n                int nextIdx = diff.MapExactForward(mapping.Last());\n                // Invalid idx\n                if (nextIdx < 0)\n                {\n                    IdentStr levelName = Project.LevelSummaryChain[i + 1].Name;\n                    throw new FatalError(\n                        $\"Propagation failed in level {levelName} method {loc.Method}.\"\n                    );\n                }\n                mapping.Add(nextIdx);\n            }\n\n            List<StmtLoc> res = new List<StmtLoc>();\n            for (int i = llv.ChainIdx, j = 0; i <= hlv.ChainIdx; i++, j++)\n            {\n                res.Add(new StmtLoc(Project.LevelSummaryChain[i].Name, loc.Method, mapping[j]));\n            }\n\n            return res;\n        }\n\n        private static List<List<T>> transpose<T>(List<List<T>> source, int arity)\n        {\n            // init\n            List<List<T>> res = new();\n            // transpose\n            for (int i = 0; i < arity; i++)\n            {\n                List<T> l = new();\n                for (int j = 0; j < source.Count; j++)\n                {\n                    l.Add(source[j][i]);\n                }\n                res.Add(l);\n            }\n            return res;\n        }\n\n        public List<StmtGroupLoc> IdentifyByStatementSelection(StmtRangeLoc rangeLoc)\n        {\n            List<List<StmtLoc>> locMat = new();\n            int arity = -1;\n            for (int idx = rangeLoc.StmtIdx; idx <= rangeLoc.StmtEndIdx; idx++)\n            {\n                var locs = IdentifyByStatement(new StmtLoc(rangeLoc.Level, rangeLoc.Method, idx));\n                if (arity == -1)\n                {\n                    arity = locs.Count;\n                }\n                else if (arity != locs.Count)\n                {\n                    throw new FatalError(\"Arity mismatch between levels.\");\n                }\n                locMat.Add(locs);\n            }\n            // transpose\n            List<List<StmtLoc>> locTrans = (List<List<StmtLoc>>)transpose(locMat, arity);\n\n            List<StmtGroupLoc> groups = locTrans.Select(\n                locs => new StmtGroupLoc(locs)\n            ).ToList();\n            return groups;\n        }\n    }\n}\n"
  },
  {
    "path": "experimental/Source/Editor/Paper.md",
    "content": "# Multi-level Editor for Starmada\n\n## Introduction\n\nThe Starmada code involves multiple levels of codes that are associated by proofs. Given the small step nature of the Starmada code, levels are often similar to each other while the difference is where the corresponding proof needs to justify. Reasonable as it sounds, the current scheme requires a cross-level refactor when any change is to be applied to the same piece of logic of the similar code, leaving the programmers with a considerable amount of manual refactoring work.\n\nTo make lifes of our Starmada programmers easier, we introduce the *multi-level editor for Starmada.* Giving semantic analysis based on structured Starmada AST, our editor is capable of preserving the syntactic correctness, as well as the original intention of the programmer, while refactoring. To complete the refactoring task, the editor asks for the range of level propagation, the candidate statement(s) that needs to be editted. Behind the scene, the editor runs a pair-wise level diffing and gets a mapping of every statement from the level it shows up to the level it disappears inside the range. Then the editor classifies the pattern of the statements into either a) clustered: treat the statements as a whole and replace all with the given input code, or b) separated: treat the statement as a list of individuals and perform refactor on statement basis. The output would be either a successful refactor that dumps code with correct syntax (and optionally, type safe) or an error prompt.\n\n## Motivation\n\nTo perform the refactoring, we need to identify pieces of \"similar\" code across all levels being propagated. A typical diff tool can do the job, but not necessarily in an ideal way. Consider the following lines of code for declaring a variable `x` of type `int` and instantiating it with value `1`:\n\n```\nint x := 1;\n int  x   :=1;\nint x ::= 1;\n```\n\nThe first two lines should be undoubtedly considered the same since they are syntactically the same statement, while the third line should under certain condition be treated as \"similar\", such as when it's right before an TSO elimination.\n\nThe traditional approaches fail to accept the programs that are syntactically identical but not identical character-by-character. Even if the whitespaces are removed, they fail to understand the program; there could be situation where the source code looks different yet results in the same AST. A better approach which is adopted in this project is to parse the program first and perform analysis on the AST of the source code.\n\n## The Core Algorithm\n\nThe core algorithm is derived from the [Myers Diff Algorithm]([diff2.pdf (xmailserver.org)](http://www.xmailserver.org/diff2.pdf)), which is a famous diff algorithm that works on sequence, with a given equivalence difinition on the sequence elements. In short, the algorithm finds the shortest editing path between the two sequences. Consider two sequences A = (a~1~, ..., a~m~) and B = (b~1~, ..., b~n~). Each step in the path is either add a~i~, add b~j~, or add both a~i~ and b~j~ when they are equivalent.\n\nTraditionally the Myers Diff Algorithm works on sequences of characters or lines to tell the difference between two given strings. While text-level diffing is commonly used in situations such as git diff, it's not ideal in our use case since we desire a syntax-directed refactor that produces better preservation the structure of the code and, as a result, better conjecture of programmer's intention.\n\nTo apply the algorithm, we have two pieces missing in our puzzle. First, the AST is a tree, but we need two sequences as input; and second, the equivalence relation of statements is not trivial. We'll given solutions in the following two paragraphs.\n\n## AST Flattening\n\nTo apply the algorithm on Starmada AST, we choose to flatten the AST into a sequence by encoding hierarchy structures into delimiter-surrounded blocks. Each statement carries its position information in the source code, which relieves the burden for further locating before replacing them. Since there’s no need of recovering the original structural information (though we can), we consider the flattening as a one-way operation.\n\nThere are three types of block-shaped statement in Starmada: `atomic` block, `if` block and `while` block.  For the beginning and ending of each statement a corresponding delimiter statement is defined. A `flatten` function recursively replaces the block-shaped statements in a list of statements with the statements inside surrounded by the delimiter statements, and outputs a statement sequence where no block-shaped statement remains.\n\n## Strategy as Heuristics\n\nTo establish the equivalence relation between statements, the strategy of the transition from the lower level to the higher level is utilized. There are three types of strategies that have syntax implication: variable introduction, variable hiding and TSO elimination.\n\nFor a pair of statements from the lower and upper level respectively, they should not be equal if the variable is introduced in the lower level or is hidden in the upper level, and they should be equal if the lower one is a TSO-bypassing assignment, given the corresponding strategy.\n\nThe rest of the strategies don't have a trivial explanation, i.e. the statements can't be considered equivalent only by its syntax. For now we consider the AST equivalence as a fallback option; in the future it may be possible to utilize the proof and find a better equivalence relation between statements for the other strategies taken.\n\n## Candidate Statement Sanity Checker\n\nAfter the selection of statements to be refactored and the level propagation range, the programmer inputs the replacement for the statements selected called the *candidate statements*. They should be well-formed Starmada statements with a correct syntax. To enforce this assumption, a sanity checker is provided which parses the candidate statements and test whether they are syntactically correct.\n\n## Refactoring Selections\n\nUsing the method described, we can form a chain of equivalence relation between statements that links from the lowest level all the way up to the highest level. If the target is merely one statement, the refactoring is almost obvious: we can just find all statements on the chain that is considered identical to the one chosen and refactor them. However, if the target is a selection of multiple statements, the intention of the programmer becomes blurry. It could be the case that the programmer wants to treat the selected statements as a whole and replace them with together; or it could be the case that the programmer wants to see them as separate statements and change them one by one.\n\nTo satisfy both needs, a multi-statement refactoring adheres to the following procedure:\n\n1. Go through all the levels on the chain and decide if the selection is clusterred in every level involved. Here *clusterred* means there's no other statement inserted in the selected statements in any level.\n2. If the selection is clusterred, delete the statements on all levels involved and insert the replacement in the same place.\n3. Otherwise, break the statements down to separate statements and do the ordinary refactor statement by statement. The number of candidate statements for replacement shoud match the statements selected, otherwise the refactoring would result in an error.\n\nTo avoid the undesirable refactoring result, the editor tend to fail fast instead of coming up with a solution that is not likely to be correct. If the transition is not absolutely clear and explicit, it's the programmer's responsibility to clarify the intention. It could be the case that the programmer needs multiple refactoring actions instead of just one multi-statement refactoring to disambiguate the transition.\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "experimental/Source/Editor/Position.cs",
    "content": "namespace Editor\n{\n    public class PositionSelection\n    {\n        public string File;\n        public (int, int) Start;\n        public bool Selection;\n        public (int, int) End;\n        public PositionSelection(string path, string s)\n        {\n            System.IO.FileInfo file = new(path);\n            File = file.FullName;\n            if (s.Contains('-'))\n            {\n                var x = s.Split('-');\n                Start = parsePosition(x[0]);\n                End = parsePosition(x[1]);\n                Selection = true;\n            }\n            else\n            {\n                Start = parsePosition(s);\n                Selection = false;\n            }\n        }\n        private (int, int) parsePosition(string s)\n        {\n            var x = s.Split(':');\n            return (int.Parse(x[0]), int.Parse(x[1]));\n        }\n    }\n}"
  },
  {
    "path": "experimental/Source/Editor/Readme.md",
    "content": "# Multilevel Editor for Starmada\n\nThere are two modes for this Starmada Code Refactoring tool: step-by-step mode, similar to the git workflow, used by GUI; and one-pass mode, used in CLI.\n\n## Workflow (step-by-step mode)\n\nFour verbs are provided: `backup`, `extract`, `apply` and `restore`. \n\n### Backup\n\nClean `.build` and duplicate the current project. Effectively `cp -f`.\n\n### Extract\n\nGiven a caret position, extract information for the refactor process. Needs most of the user's input.\n\n### Apply\n\nApply the refactor from candidates.\n\n### Restore\n\nRestore the old project if something went wrong. Clean current project and restore previous state.\n\n## Command Line Interface (one-pass mode)\n\n```\n./Binary/Editor shoot {proj_root} -o {dump} -f {caret_file} -p {caret_position} -m {output_mode} -c {check_mode} < {refactor_candidate_file}\n```\n\nWhere\n\n- `{proj_root}` - The root of a Starmada project, containing all the `.arm` files.\n- `{dump}` - A proposed project root for the output of this refactor.\n- `{caret_*}` - The file and position of the caret; can be either a point or a selection. The position is of format:\n  - `line:column`, e.g. `8:13`\n  - `line:column-line:column`, exclusive, e.g. `7:13-8:12`\n- `{output_mode}`: either `file` or `stdout`. Default `file`, which dumps to the directory; choose `stdout` for debugging.\n- `{check_mode}`: either `deferred` or `eager`. Default `deferred`, which does syntax check (or even type check in the future, when type checker is ready); choose `eager` if you want the user input to be strict and complete.\n- `{refactor_candidate_file}`: a file containing the refactor candidates that the user inputs.\n\nNote that\n\n1. All paths can be relative.\n2. `line` and `column` are 1-indexed numbers.\n3. `{dump}` can be omitted if `{output_mode}` is `{stdout}`.\n4. `{output_mode}` and `{check_mode}` can be omitted.\n\n## Tests\n\nTests are rested in `Tests/editor`. An overview can be done by `tree`:\n\n```\n.\n└── basic\n│  ├── if\n│  │  ├── arg\n│  │  ├── in\n│  │  └── proj\n│  │     └── t.arm\n│  ├── ifcond\n│  │  ├── arg\n│  │  ├── in\n│  │  └── proj\n│  │     └── t.arm\n│  ....\n....\n```\n\nTests are divided by classes `basic`, `range` and `error`, under each lies all the tests. A test is comprised of `arg`, `in` and directories of `proj` and `expect`. The `proj` contains a short Starmada project as a real user project, and the `expect` is the expected output of it. The `error` tests can only be tested by hand, because we currently lack the means to detect a runtime error. If a clean way to do this in Python is known, we can add them to the test suit in no time. \n\n## Core Concepts\n\nBefore diving into detailed code documentation, there are several concepts (or data structures) that we should first investigate. Some of them can be composed together and form a new type.\n\n### Chain\n\nA chain, often represented by a `List`, is a totally ordered set. It requires an index (`Idx`) to destruct. In Starmada both levels and proofs are chains.\n\n### Summary\n\n`Summary`s hold data in a structured manner. There are three types of `Summary`s: `ProjectSummary`, `LevelSummary` and `ProofSummary`, each holding a level of abstraction. `LevelSummary` is managed by a chain, which is a `List` containing all levels in order.\n\n### Sequence (`Seq`)\n\nA sequence is an abstract `List` designed for Myers Diff Algorithm.\n\n### Location (`Loc`)\n\nLocation presents the position of a statement in a certain method of a certain level. `StmtLoc`, for example, contains a level name, a method name, and an index of the statement in the corresponding `StatementSeq`.\n\n### Token\n\nToken presents a piece of consecutive source code text. It's comprised of a beginning position and an ending position. The name token is taken because the content is unseparable.\n\n### Group\n\nA group is a list of content that have the potential to be grouped as a whole. It may or may not end up in a cluster, but it can always be iterated.\n\n## Code Documentation\n\nWith the comments written in the source code and a few core concepts explained above, this is only an outline of dataflow.\n\n### Driver\n\nThe `Driver` is responsible for parsing the input files and deciding the order of the levels using proofs. It outputs `ProjectSummary`, which contains most of the information for the refactor. It also generates `LevelInfo` that maps levels' name to the file it lives and the index in the chain.\n\n### Mapper\n\nThe `Mapper` builds a level-wise mapping from the lowest level in propagation to the highest by calling the function `IdentifyByStatementSelection`. It also picks the right equivalence between statements using function `EqualityPicker`. Deep inside, it uses `Diff`, which implements the Myers Diff Algorithm.\n\n### Diff\n\nThe implementation of the Myers Diff Algorithm. Uses `MapExactForward` and `MapExactBackward` to build up the map. Uses class `Route` to represent an editting path, and picks `key_route`, which is the shortest path of all editting paths.\n\n### RefactorBuffer\n\nAfter all the preparations, the `RefactorBuffer` actually performs the refactoring. It's done in a lazy fashion, where all the potential changes to the file is recorded in `Schema`, and are applied from the bottom of the file all the way up to the top to avoid messing up the position of the changes. The final dump is performed using class `RefactorProjectBuffer`.\n"
  },
  {
    "path": "experimental/Source/Editor/RefactorBuffer.cs",
    "content": "using Editor;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.IO;\nusing System.Text;\nusing Microsoft.Starmada;\n\nusing StarmadaParser = Microsoft.Starmada.Parser;\n\nnamespace Starmada\n{\n    class RefactorBuffer\n    {\n        public string Buffer;\n        public string OutFileName;\n        public SortedDictionary<int, (int, int, string)> Schema;\n        public string GetIndent(int charPos)\n        {\n            string s = Buffer.Remove(charPos);\n            int last = s.LastIndexOf('\\n');\n            return new(' ', charPos - last - 1);\n        }\n        public RefactorBuffer(string buffer, string dumpName)\n        {\n            Buffer = buffer;\n            OutFileName = dumpName;\n            Schema = new();\n        }\n        public void Add((int, int) charPosRange, string candidate)\n        {\n            var (a, b) = charPosRange;\n            Schema.Add(a, (a, b, candidate));\n        }\n        public void Dump()\n        {\n            // always replace the ones in the back\n            foreach (var (_, (a, b, candidate)) in Schema.Reverse())\n            {\n                Buffer = Buffer.Remove(a, b - a).Insert(a, candidate);\n            }\n        }\n    }\n\n    class RefactorProjectBuffer\n    {\n        public Dictionary<string, RefactorBuffer> RefactorBuffers;\n        public string OutputRoot;\n        public RefactorProjectBuffer(List<string> inputs, string input, string output)\n        {\n            RefactorBuffers = new();\n            string inputRoot = input;\n            OutputRoot = output.Length == 0 ? input : output;\n\n            input = Path.GetFullPath(input);\n            output = Path.GetFullPath(output);\n\n            // Remove overlapping check\n            // if (input.StartsWith(output) || output.StartsWith(input))\n            // {\n            //     throw new FatalError($\"Input overlaps with Output ({inputRoot}, {OutputRoot})\");\n            // }\n\n            foreach (var fileName in inputs)\n            {\n                string fileBuffer = File.ReadAllText(fileName);\n\n                string dumpName = fileName.Remove(0, input.Length).Insert(0, output);\n                RefactorBuffers[fileName] = new(fileBuffer, dumpName);\n            }\n        }\n\n        public List<string> ReadFromStdin(string checkMode)\n        {\n            string buffer = \"\";\n            string tmp;\n            while ((tmp = System.Console.ReadLine()) != null && tmp != \"\")\n            {\n                buffer += $\"{tmp}\\n\";\n            }\n            return ReadFromString(buffer, checkMode);\n        }\n\n        public List<string> ReadFromFile(string file, string checkMode)\n        {\n            string buffer = File.ReadAllText(file);\n            return ReadFromString(buffer, checkMode);\n        }\n\n        public List<string> ReadFromString(string buffer, string checkMode)\n        {\n            buffer = buffer.TrimEnd();\n            List<string> res;\n\n            if (checkMode == \"deferred\")\n            {\n                // defer the check\n                res = new(buffer.Split('\\n'));\n            }\n            else\n            {\n                // eager check; only parser\n                string raw = $\"level A {{ method main() {{ {buffer} }} }}\";\n\n                string tmpFileName = \"<internal>\";\n\n                List<StmtToken> candidateTokens;\n                {\n                    Scanner scanner = new(\n                        new MemoryStream(\n                            Encoding.Default.GetBytes(raw)));\n                    StarmadaParser sp = new(scanner, tmpFileName);\n                    sp.Parse();\n                    StarmadaProgram p = sp.program;\n                    List<Statement> s = (p.Levels[0].Members[0] as MethodDecl).Stmts;\n                    candidateTokens = s.Select(\n                        stmt => new StmtToken(tmpFileName, stmt.FirstTok, stmt.LastTok)\n                    ).ToList();\n                }\n\n                res = new(candidateTokens.Select(st => st.GetStringFromBuffer(raw)));\n            }\n\n\n            return res;\n        }\n\n        public void FineGrainedReplacement(List<StmtGroupToken> groupToks, List<string> candidates)\n        {\n            // Check if the stmtGroupTokens are all clustered; or if they all fit the candidate length\n            bool allClustered = true;\n            bool aligned = true;\n            foreach (var groupTok in groupToks)\n            {\n                allClustered = (groupTok.Clustered is not null) && allClustered;\n                aligned = (groupTok.Tokens.Count == candidates.Count) && aligned;\n            }\n            if (allClustered)\n            {\n                foreach (var groupTok in groupToks)\n                {\n                    StmtToken clustered = groupTok.Clustered;\n                    string indent = RefactorBuffers[clustered.File].GetIndent(clustered.GetCharPosRange().Item1);\n                    string candidate = String.Join('\\n',\n                        candidates.Select(c => c.Insert(0, indent))\n                    ).Remove(0, indent.Length);\n                    RefactorBuffers[clustered.File].Add(clustered.GetCharPosRange(), candidate);\n                }\n            }\n            else if (aligned)\n            {\n                foreach (var groupTok in groupToks)\n                {\n                    for (int i = 0; i < groupTok.Tokens.Count; i++)\n                    {\n                        var tok = groupTok.Tokens[i];\n                        RefactorBuffers[tok.File].Add(tok.GetCharPosRange(), candidates[i]);\n                    }\n                }\n            }\n            else\n            {\n                throw new FatalError(\"Neither all clustered nor aligned with the candidates in length\");\n            }\n        }\n\n        public void Dump(string outputMode, string checkMode)\n        {\n            // div\n            string div = String.Concat(Enumerable.Repeat(\"=\", 40));\n\n            foreach (var (fileName, buf) in RefactorBuffers)\n            {\n                buf.Dump();\n                if (outputMode == \"file\")\n                {\n                    // ensures that the directory exists\n                    Directory.CreateDirectory(Path.GetDirectoryName(buf.OutFileName));\n\n                    // write the file\n                    Console.WriteLine($\"Dumping {buf.OutFileName}.\");\n                    File.WriteAllLines(buf.OutFileName, new List<String> { buf.Buffer });\n\n                    // check if deferred\n                    if (checkMode == \"deferred\")\n                    {\n                        string tmpFileName = buf.OutFileName;\n                        Scanner scanner = new Scanner(tmpFileName);\n                        StarmadaParser sp = new StarmadaParser(scanner, tmpFileName);\n                        sp.Parse();\n                        // type check can be done here\n                        // sp.program.TypeResolve();\n                    }\n                }\n                else\n                {\n                    System.Console.WriteLine($\"Output file {buf.OutFileName}:\");\n                    System.Console.WriteLine(div);\n                    System.Console.WriteLine(buf.Buffer);\n                    System.Console.WriteLine(div);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "experimental/Source/Editor/StatementEquality.cs",
    "content": "using System.Collections.Generic;\nusing Microsoft.Starmada;\n\nnamespace Editor\n{\n    public class SyntacticEq : EqualityComparer<Statement>\n    {\n        public SyntacticEq() { }\n        public override bool Equals(Statement x, Statement y)\n        {\n            return x.ToString(0, false) == y.ToString(0, false);\n        }\n        public override int GetHashCode(Statement s)\n        {\n            return s.GetHashCode();\n        }\n    }\n\n    public class FallbackEq : SyntacticEq { }\n\n    public class VarIntroEq : EqualityComparer<Statement>\n    {\n        public List<Ident> Variables;\n        public VarIntroEq(VarIntroStrategy vis)\n        {\n            Variables = vis.Variables;\n        }\n        public override bool Equals(Statement x, Statement y)\n        {\n            if (y is VarDecl && Variables.Contains(((VarDecl)y).Name))\n            {\n                return false;\n            }\n            return new SyntacticEq().Equals(x, y);\n        }\n        public override int GetHashCode(Statement s)\n        {\n            return s.GetHashCode();\n        }\n    }\n\n    public class VarHidingEq : EqualityComparer<Statement>\n    {\n        public List<Ident> Variables;\n        public VarHidingEq(VarHidingStrategy vis)\n        {\n            Variables = vis.Variables;\n        }\n        public override bool Equals(Statement x, Statement y)\n        {\n            if (x is VarDecl && Variables.Contains(((VarDecl)x).Name))\n            {\n                return false;\n            }\n            return new SyntacticEq().Equals(x, y);\n        }\n        public override int GetHashCode(Statement s)\n        {\n            return s.GetHashCode();\n        }\n    }\n\n    public class TSOElimEq : EqualityComparer<Statement>\n    {\n        public TSOElimEq() { }\n        public override bool Equals(Statement x, Statement y)\n        {\n            if (x is AssignStatement && y is AssignStatement)\n            {\n                AssignStatement x_ = x as AssignStatement;\n                AssignStatement y_ = y as AssignStatement;\n                if (!x_.IsSequential && y_.IsSequential)\n                {\n                    if (new ExprEq().Equals(x_.Lhs, y_.Lhs) &&\n                        new ExprEq().Equals(x_.Rhs, y_.Rhs))\n                    {\n                        return true;\n                    }\n                }\n            }\n            return new SyntacticEq().Equals(x, y);\n        }\n\n        public override int GetHashCode(Statement s)\n        {\n            return s.GetHashCode();\n        }\n    }\n\n    public class AssumeIntroEq : SyntacticEq { }\n    // public class ReductionEq : SyntacticEq { }\n    public class WeakeningEq : SyntacticEq { }\n    public class CombiningEq : SyntacticEq { }\n    // public class StarWeakeningEq : SyntacticEq { }\n}\n"
  },
  {
    "path": "experimental/Source/Editor/StatementSeq.cs",
    "content": "using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Microsoft.Starmada;\nusing Type = Microsoft.Starmada.Type;\n\nnamespace Editor\n{\n    public class StatementSeq : IList<Statement>\n    {\n        public abstract class DelimiterStatement : Statement\n        {\n            public DelimiterStatement(Token tok) : base(tok) { }\n            public override void TypeResolve(Type type, ref Errors errors) { throw new NotImplementedException(); }\n            public override void SetProgramCounter(string parentPC, int index) { throw new NotImplementedException(); }\n            public override void SetNextProgramCounter(string nextPC) { throw new NotImplementedException(); }\n            public override string ToFStarLang(int indentation) { throw new NotImplementedException(); }\n        }\n        public class AtomicBegin : DelimiterStatement\n        {\n            public AtomicBegin(AtomicStatement stmt) : base(stmt.FirstTok)\n            {\n                LastTok = stmt.BlockStmt.FirstTok;\n                Label = stmt.Label;\n            }\n            public override string ToString(int indentation, bool labelOn)\n            {\n                string str = \"\";\n                string indentationStr = new string(' ', indentation);\n                if (Label != null && labelOn)\n                {\n                    str = str + indentationStr + base.ToString(0, labelOn) + \"\\n\";\n                }\n                str = str + indentationStr + \"atomic\" + \"\\n\";\n                str = str + indentationStr + \"{\";\n                return str;\n            }\n        }\n        public class AtomicEnd : DelimiterStatement\n        {\n            public AtomicEnd(AtomicStatement stmt) : base(stmt.FirstTok)\n            {\n                FirstTok = stmt.LastTok;\n                LastTok = FirstTok;\n            }\n            public override string ToString(int indentation, bool labelOn)\n            {\n                string str = \"\";\n                string indentationStr = new string(' ', indentation);\n                str = str + indentationStr + \"}\";\n                return str;\n            }\n        }\n        public List<Statement> FlattenAtomic(AtomicStatement atomicStatement)\n        {\n            List<Statement> res = new List<Statement>();\n            res.Add(new AtomicBegin(atomicStatement));\n            res.AddRange(FlattenBlock(atomicStatement.BlockStmt));\n            res.Add(new AtomicEnd(atomicStatement));\n            return res;\n        }\n        public class IfBegin : DelimiterStatement\n        {\n            public Expr Cond;\n            public IfBegin(IfStatement stmt) : base(stmt.FirstTok)\n            {\n                Cond = stmt.Cond;\n                LastTok = stmt.Then.FirstTok;\n                Label = stmt.Label;\n            }\n            public override string ToString(int indentation, bool labelOn)\n            {\n                string str = \"\";\n                string indentationStr = new string(' ', indentation);\n                if (Label != null && labelOn)\n                {\n                    str = str + indentationStr + base.ToString(0, labelOn) + \"\\n\";\n                }\n                str = str + indentationStr + \"if \" + Cond.ToString(0, labelOn) + \"\\n\";\n                str = str + indentationStr + \"{\";\n                return str;\n            }\n        }\n        public class Else : DelimiterStatement\n        {\n            public Else(IfStatement stmt) : base(stmt.FirstTok)\n            {\n                FirstTok = stmt.Then.LastTok;\n                LastTok = stmt.Else.FirstTok;\n            }\n            public override string ToString(int indentation, bool labelOn)\n            {\n                string str = \"\";\n                string indentationStr = new string(' ', indentation);\n                str = str + indentationStr + \"}\" + \"\\n\";\n                str = str + indentationStr + \"else\" + \"\\n\";\n                str = str + indentationStr + \"{\";\n                return str;\n            }\n        }\n        public class IfEnd : DelimiterStatement\n        {\n            public IfEnd(IfStatement stmt) : base(stmt.FirstTok)\n            {\n                FirstTok = stmt.LastTok;\n                LastTok = FirstTok;\n            }\n            public override string ToString(int indentation, bool labelOn)\n            {\n                string str = \"\";\n                string indentationStr = new string(' ', indentation);\n                str = str + indentationStr + \"}\";\n                return str;\n            }\n        }\n        public List<Statement> FlattenIf(IfStatement ifStatement)\n        {\n            List<Statement> res = new List<Statement>();\n            res.Add(new IfBegin(ifStatement));\n            res.AddRange(FlattenBlock(ifStatement.Then));\n            if (ifStatement.Else is not null)\n            {\n                res.Add(new Else(ifStatement));\n                res.AddRange(Flatten(ifStatement.Else));\n            }\n            res.Add(new IfEnd(ifStatement));\n            return res;\n        }\n        public class WhileBegin : DelimiterStatement\n        {\n            public Expr Cond;\n            public WhileBegin(WhileBlock stmt) : base(stmt.FirstTok)\n            {\n                Cond = stmt.Cond;\n                LastTok = stmt.BlockStmt.FirstTok;\n                Label = stmt.Label;\n            }\n            public override string ToString(int indentation, bool labelOn)\n            {\n                string str = \"\";\n                string indentationStr = new string(' ', indentation);\n                if (Label != null && labelOn)\n                {\n                    str = str + indentationStr + base.ToString(0, labelOn) + \"\\n\";\n                }\n                str = str + indentationStr + \"while \" + Cond.ToString(0, labelOn) + \"\\n\";\n                str = str + indentationStr + \"{\";\n                return str;\n            }\n        }\n        public class WhileEnd : DelimiterStatement\n        {\n            public WhileEnd(WhileBlock stmt) : base(stmt.FirstTok)\n            {\n                FirstTok = stmt.BlockStmt.LastTok;\n                LastTok = FirstTok;\n            }\n            public override string ToString(int indentation, bool labelOn)\n            {\n                string str = \"\";\n                string indentationStr = new string(' ', indentation);\n                str = str + indentationStr + \"}\";\n                return str;\n            }\n        }\n        public List<Statement> FlattenWhile(WhileBlock whileBlock)\n        {\n            List<Statement> res = new List<Statement>();\n            res.Add(new WhileBegin(whileBlock));\n            res.AddRange(FlattenBlock(whileBlock.BlockStmt));\n            res.Add(new WhileEnd(whileBlock));\n            return res;\n        }\n        public List<Statement> FlattenBlock(BlockStatement blockStatement)\n        {\n            List<Statement> res = blockStatement.Stmts.SelectMany(stmt => Flatten(stmt)).ToList();\n            return res;\n        }\n        public List<Statement> Flatten(Statement stmt)\n        {\n            List<Statement> res = new List<Statement>();\n            if (stmt is BlockStatement s1)\n            {\n                res.AddRange(FlattenBlock(s1));\n            }\n            else if (stmt is IfStatement s2)\n            {\n                res.AddRange(FlattenIf(s2));\n            }\n            else if (stmt is WhileBlock s3)\n            {\n                res.AddRange(FlattenWhile(s3));\n            }\n            else if (stmt is AtomicStatement s4)\n            {\n                res.AddRange(FlattenAtomic(s4));\n            }\n            else\n            {\n                res.Add(stmt);\n            }\n            return res;\n        }\n\n        public int IndexOf(Statement item)\n        {\n            return ((IList<Statement>)Sequence).IndexOf(item);\n        }\n\n        public void Insert(int index, Statement item)\n        {\n            ((IList<Statement>)Sequence).Insert(index, item);\n        }\n\n        public void RemoveAt(int index)\n        {\n            ((IList<Statement>)Sequence).RemoveAt(index);\n        }\n\n        public void Add(Statement item)\n        {\n            ((ICollection<Statement>)Sequence).Add(item);\n        }\n\n        public void Clear()\n        {\n            ((ICollection<Statement>)Sequence).Clear();\n        }\n\n        public bool Contains(Statement item)\n        {\n            return ((ICollection<Statement>)Sequence).Contains(item);\n        }\n\n        public void CopyTo(Statement[] array, int arrayIndex)\n        {\n            ((ICollection<Statement>)Sequence).CopyTo(array, arrayIndex);\n        }\n\n        public bool Remove(Statement item)\n        {\n            return ((ICollection<Statement>)Sequence).Remove(item);\n        }\n\n        public IEnumerator<Statement> GetEnumerator()\n        {\n            return ((IEnumerable<Statement>)Sequence).GetEnumerator();\n        }\n\n        IEnumerator IEnumerable.GetEnumerator()\n        {\n            return ((IEnumerable)Sequence).GetEnumerator();\n        }\n\n        // SeqStatement\n        public List<Statement> Sequence;\n\n        public int Count => ((ICollection<Statement>)Sequence).Count;\n\n        public bool IsReadOnly => ((ICollection<Statement>)Sequence).IsReadOnly;\n\n        public Statement this[int index] { get => ((IList<Statement>)Sequence)[index]; set => ((IList<Statement>)Sequence)[index] = value; }\n\n        public StatementSeq(List<Statement> seq)\n        {\n            Sequence = seq.SelectMany(stmt => Flatten(stmt)).ToList();\n        }\n    }\n}\n"
  },
  {
    "path": "experimental/Source/Editor/Summary.cs",
    "content": "using System.Collections.Generic;\nusing Microsoft.Starmada;\n\nnamespace Editor\n{\n    public class ProjectSummary\n    {\n        // Stores LevelInfo\n        public Dictionary<IdentStr, LevelInfo> LevelInfoDict { get; set; }\n\n        // Stores the result StatementSeqs\n        public List<LevelSummary> LevelSummaryChain { get; set; }\n\n        // Stores the Proof\n        public List<ProofSummary> ProofSummaryChain { get; set; }\n\n\n        public ProjectSummary()\n        {\n            LevelInfoDict = new(new IdentStrEq());\n            LevelSummaryChain = new();\n            ProofSummaryChain = new();\n        }\n\n        public LevelSummary GetLevelSummary(IdentStr levelName)\n        {\n            return LevelSummaryChain[LevelInfoDict[levelName].ChainIdx];\n        }\n\n        public StmtToken GetStmtToken(StmtLoc loc)\n        {\n            LevelInfo lvInfo = LevelInfoDict[loc.Level];\n            Statement stmt = LevelSummaryChain[lvInfo.ChainIdx].MethodCollection[loc.Method][loc.StmtIdx];\n            return new StmtToken(lvInfo.File, stmt.FirstTok, stmt.LastTok);\n        }\n    }\n\n    public class LevelSummary\n    {\n        public IdentStr Name;\n        public Dictionary<IdentStr, StatementSeq> MethodCollection;\n        public LevelSummary(LevelDecl level)\n        {\n            Name = new(level.Name);\n            MethodCollection = new Dictionary<IdentStr, StatementSeq>(new IdentStrEq());\n            foreach (var member in level.Members)\n            {\n                if (member is MethodDecl method)\n                {\n                    MethodCollection.Add(new(method.Name), new StatementSeq(method.Stmts));\n                }\n            }\n        }\n    }\n\n    public class ProofSummary\n    {\n        public IdentStr Name;\n        public ProofStrategy Strategy;\n        public ProofSummary(ProofDecl proof)\n        {\n            Name = new(proof.Name);\n            Strategy = proof.Strategy;\n        }\n    }\n}"
  },
  {
    "path": "experimental/Source/Editor/Utils.cs",
    "content": "using System.Collections.Generic;\nusing System.Linq;\nusing System.Text.Json.Serialization;\nusing Microsoft.Starmada;\n\nnamespace Editor\n{\n    public class IdentStr\n    {\n        public string Str;\n        public IdentStr(string s)\n        {\n            Str = s;\n        }\n        public IdentStr(Ident id)\n        {\n            Str = id.Name;\n        }\n        public override bool Equals(object obj)\n        {\n            //Check for null and compare run-time types.\n            if ((obj == null) || !this.GetType().Equals(obj.GetType()))\n            {\n                return false;\n            }\n            else\n            {\n                IdentStr p = (IdentStr)obj;\n                return Str == p.Str;\n            }\n        }\n        public override int GetHashCode()\n        {\n            return base.GetHashCode();\n        }\n        public override string ToString()\n        {\n            return Str;\n        }\n    }\n\n    public class LevelInfo\n    {\n        public string File;\n        public int ChainIdx;\n        public LevelInfo(string file)\n        {\n            File = file;\n            ChainIdx = -1;\n        }\n        public string ToString(IdentStr name)\n        {\n            return $\"{name.ToString()}.{ChainIdx} @ {File}\";\n        }\n    }\n\n    public class MethodInfo\n    {\n        public IdentStr Method;\n        public MethodInfo(IdentStr method)\n        {\n            Method = method;\n        }\n    }\n\n    public class StmtLoc\n    {\n        public IdentStr Level;\n        public IdentStr Method;\n        public int StmtIdx;\n        public StmtLoc(IdentStr level, IdentStr method, int stmtIdx)\n        {\n            if (level is null || method is null)\n            {\n                throw new FatalError(\"StmtLoc arguments can't be null.\");\n            }\n            Level = level;\n            Method = method;\n            StmtIdx = stmtIdx;\n        }\n    }\n\n    public class StmtRangeLoc : StmtLoc\n    {\n        // StmtEndIdx == StatementIdx if a point, >= 0 if a valid selection; works as [start, end], so be careful of off by 1.\n        public int StmtEndIdx;\n        public StmtRangeLoc(StmtLoc start) : base(start.Level, start.Method, start.StmtIdx)\n        {\n            StmtEndIdx = start.StmtIdx;\n        }\n        public StmtRangeLoc(StmtLoc start, int endIdx) : base(start.Level, start.Method, start.StmtIdx)\n        {\n            StmtEndIdx = endIdx;\n        }\n        public StmtRangeLoc(StmtLoc start, StmtLoc end) : base(start.Level, start.Method, start.StmtIdx)\n        {\n            if (!start.Level.Equals(end.Level) || !start.Method.Equals(end.Method))\n            {\n                throw new FatalError(\"StmtRangeLoc must locate in the same level in the same method.\");\n            }\n            if (!(start.StmtIdx <= end.StmtIdx))\n            {\n                throw new FatalError(\"StmtRangeLoc must take end located after start.\");\n            }\n            StmtEndIdx = end.StmtIdx;\n        }\n        public StmtLoc GetEndLoc()\n        {\n            return new StmtLoc(Level, Method, StmtEndIdx);\n        }\n    }\n\n    public class StmtGroupLoc\n    {\n        public List<StmtLoc> Locs;\n        public StmtRangeLoc Selection;\n        private void tryCluster()\n        {\n            Selection = null;\n            if (Locs.Count == 0)\n            {\n                return;\n            }\n            StmtLoc head = Locs[0];\n            int end = head.StmtIdx;\n            for (int i = 1; i < Locs.Count; i++)\n            {\n                if (!(Locs[i].StmtIdx == ++end))\n                {\n                    return;\n                }\n            }\n            Selection = new(head, end);\n        }\n        public StmtGroupLoc(IEnumerable<StmtLoc> iter)\n        {\n            Locs = new List<StmtLoc>(iter);\n            tryCluster();\n        }\n        public StmtGroupToken ToStmtGroupToken(ProjectSummary proj)\n        {\n            StmtGroupToken groupTok;\n            groupTok = new(Locs.Select(lo => proj.GetStmtToken(lo)));\n            if (Selection is not null)\n            {\n                StmtToken start = proj.GetStmtToken(Selection);\n                StmtToken end = proj.GetStmtToken(Selection.GetEndLoc());\n                groupTok.Clustered = new(start.File, start.FirstTok, end.LastTok);\n            }\n            return groupTok;\n        }\n    }\n\n    public class StmtToken\n    {\n        public string File { get; set; }\n        public Token FirstTok { get; set; }\n        public Token LastTok { get; set; }\n\n        [JsonConstructor]\n        public StmtToken(string file, Token firstTok, Token lastTok)\n        {\n            File = file;\n            FirstTok = firstTok;\n            LastTok = lastTok;\n        }\n        // exclusive\n        public ((int, int), (int, int)) GetPosRange()\n        {\n            return ((FirstTok.line, FirstTok.col), (LastTok.line, LastTok.col + LastTok.val.Length));\n        }\n        // exclusive\n        public (int, int) GetCharPosRange()\n        {\n            return (FirstTok.charPos, LastTok.charPos + LastTok.val.Length);\n        }\n        public string GetStringFromBuffer(string buf)\n        {\n            var (a, b) = GetCharPosRange();\n            return buf.Substring(a, b - a);\n        }\n\n    }\n\n    public class StmtGroupToken\n    {\n        public List<StmtToken> Tokens { get; set; }\n        public StmtToken Clustered { get; set; }\n        public StmtGroupToken(IEnumerable<StmtToken> iter)\n        {\n            Tokens = new(iter);\n            Clustered = null;\n        }\n        [JsonConstructor]\n        public StmtGroupToken(List<StmtToken> tokens, StmtToken clustered)\n        {\n            Tokens = tokens;\n            Clustered = clustered;\n        }\n    }\n\n    public class LevelRange\n    {\n        public IdentStr LLevel;\n        public IdentStr HLevel;\n        public LevelRange(IdentStr low, IdentStr high)\n        {\n            if (low is null || high is null)\n            {\n                throw new FatalError(\"LevelRange can't be null.\");\n            }\n            LLevel = low;\n            HLevel = high;\n        }\n    }\n}"
  },
  {
    "path": "experimental/Tests/.gitignore",
    "content": "*.fst\n*.out"
  },
  {
    "path": "experimental/Tests/editor/.gitignore",
    "content": ".build/"
  },
  {
    "path": "experimental/Tests/editor/basic/ab/arg",
    "content": "AB.arm -p 7:13-8:15"
  },
  {
    "path": "experimental/Tests/editor/basic/ab/expect/AB.arm",
    "content": "level A {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n\n        y := 20;\n    }\n}\n\nproof AB {\n    refinement A B\n    var_intro z\n}\n\nlevel B {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n\n        y := 20;\n        z := 1;\n    }\n}\n\n"
  },
  {
    "path": "experimental/Tests/editor/basic/ab/in",
    "content": "y := 20;"
  },
  {
    "path": "experimental/Tests/editor/basic/ab/proj/AB.arm",
    "content": "level A {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n\n        x := 5;\n        y := 10;\n    }\n}\n\nproof AB {\n    refinement A B\n    var_intro z\n}\n\nlevel B {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n\n        x := 5;\n        y := 10;\n        z := 1;\n    }\n}\n"
  },
  {
    "path": "experimental/Tests/editor/basic/atomic/arg",
    "content": "t.arm -p 10:16"
  },
  {
    "path": "experimental/Tests/editor/basic/atomic/expect/t.arm",
    "content": "level A {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n\n        x := 5;\n        atomic\n        {\n            y := 20;\n        }\n    }\n}\n\nproof AB {\n    refinement A B\n    var_intro z\n}\n\nlevel B {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n\n        x := 5;\n        atomic\n        {\n            y := 20;\n        }\n        z := 1;\n    }\n}\n\n"
  },
  {
    "path": "experimental/Tests/editor/basic/atomic/in",
    "content": "y := 20;"
  },
  {
    "path": "experimental/Tests/editor/basic/atomic/proj/t.arm",
    "content": "level A {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n\n        x := 5;\n        atomic\n        {\n            y := 10;\n        }\n    }\n}\n\nproof AB {\n    refinement A B\n    var_intro z\n}\n\nlevel B {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n\n        x := 5;\n        atomic\n        {\n            y := 10;\n        }\n        z := 1;\n    }\n}\n"
  },
  {
    "path": "experimental/Tests/editor/basic/if/arg",
    "content": "t.arm -p 10:16"
  },
  {
    "path": "experimental/Tests/editor/basic/if/expect/t.arm",
    "content": "level A {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n\n        x := 5;\n        if x == 5\n        {\n            y := 20;\n        }\n    }\n}\n\nproof AB {\n    refinement A B\n    var_intro z\n}\n\nlevel B {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n\n        x := 5;\n        if x == 5\n        {\n            y := 20;\n        }\n        z := 1;\n    }\n}\n\n"
  },
  {
    "path": "experimental/Tests/editor/basic/if/in",
    "content": "y := 20;"
  },
  {
    "path": "experimental/Tests/editor/basic/if/proj/t.arm",
    "content": "level A {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n\n        x := 5;\n        if x == 5\n        {\n            y := 10;\n        }\n    }\n}\n\nproof AB {\n    refinement A B\n    var_intro z\n}\n\nlevel B {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n\n        x := 5;\n        if x == 5\n        {\n            y := 10;\n        }\n        z := 1;\n    }\n}\n"
  },
  {
    "path": "experimental/Tests/editor/basic/ifcond/arg",
    "content": "t.arm -p 8:14"
  },
  {
    "path": "experimental/Tests/editor/basic/ifcond/expect/t.arm",
    "content": "level A {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n\n        x := 5;\n        if x == 6\n        {\n            y := 10;\n        }\n    }\n}\n\nproof AB {\n    refinement A B\n    var_intro z\n}\n\nlevel B {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n\n        x := 5;\n        if x == 6\n        {\n            y := 10;\n        }\n        z := 1;\n    }\n}\n\n"
  },
  {
    "path": "experimental/Tests/editor/basic/ifcond/in",
    "content": "if x == 6\n{"
  },
  {
    "path": "experimental/Tests/editor/basic/ifcond/proj/t.arm",
    "content": "level A {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n\n        x := 5;\n        if x == 5\n        {\n            y := 10;\n        }\n    }\n}\n\nproof AB {\n    refinement A B\n    var_intro z\n}\n\nlevel B {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n\n        x := 5;\n        if x == 5\n        {\n            y := 10;\n        }\n        z := 1;\n    }\n}\n"
  },
  {
    "path": "experimental/Tests/editor/basic/while/arg",
    "content": "t.arm -p 10:16"
  },
  {
    "path": "experimental/Tests/editor/basic/while/expect/t.arm",
    "content": "level A {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n\n        x := 5;\n        while x == 5\n        {\n            y := 20;\n        }\n    }\n}\n\nproof AB {\n    refinement A B\n    var_intro z\n}\n\nlevel B {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n\n        x := 5;\n        while x == 5\n        {\n            y := 20;\n        }\n        z := 1;\n    }\n}\n\n"
  },
  {
    "path": "experimental/Tests/editor/basic/while/in",
    "content": "y := 20;"
  },
  {
    "path": "experimental/Tests/editor/basic/while/proj/t.arm",
    "content": "level A {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n\n        x := 5;\n        while x == 5\n        {\n            y := 10;\n        }\n    }\n}\n\nproof AB {\n    refinement A B\n    var_intro z\n}\n\nlevel B {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n\n        x := 5;\n        while x == 5\n        {\n            y := 10;\n        }\n        z := 1;\n    }\n}\n"
  },
  {
    "path": "experimental/Tests/editor/range/AST/arg",
    "content": "C.arm -p 12:14-12:18 -l A -h C"
  },
  {
    "path": "experimental/Tests/editor/range/AST/expect/A.arm",
    "content": "level A {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n\n        x := 5;\n        y := 20;\n    }\n}\n\n\n"
  },
  {
    "path": "experimental/Tests/editor/range/AST/expect/AB.arm",
    "content": "include \"A.arm\"\ninclude \"B.arm\"\n\nproof AB {\n    refinement A B\n    var_intro z\n}\n\n"
  },
  {
    "path": "experimental/Tests/editor/range/AST/expect/B.arm",
    "content": "level B {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n\n        x := 5;\n        label l1:\n        y := 20;\n        label l2:\n        z := 1;\n    }\n}\n        \n\n"
  },
  {
    "path": "experimental/Tests/editor/range/AST/expect/BC.arm",
    "content": "include \"B.arm\"\ninclude \"C.arm\"\n\nproof BC {\n    refinement B C\n    combining l1 l2 l3\n}\n\n"
  },
  {
    "path": "experimental/Tests/editor/range/AST/expect/C.arm",
    "content": "level C {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n\n        x := 5;\n        label l3:\n        atomic\n        {\n            y := 20;\n            z := 1;\n        }\n    }\n}\n\n\n"
  },
  {
    "path": "experimental/Tests/editor/range/AST/expect/CD.arm",
    "content": "include \"C.arm\"\ninclude \"D.arm\"\n\nproof CD {\n    refinement C D\n    var_intro w\n}\n\n"
  },
  {
    "path": "experimental/Tests/editor/range/AST/expect/D.arm",
    "content": "level D {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n        var w:uint64 := 0;\n\n        x := 5;\n        label l3:\n        atomic\n        {\n            y := 10;\n            w := 2;\n            z := 1;\n        }\n    }\n}\n        \n\n"
  },
  {
    "path": "experimental/Tests/editor/range/AST/in",
    "content": "y := 20;"
  },
  {
    "path": "experimental/Tests/editor/range/AST/proj/A.arm",
    "content": "level A {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n\n        x := 5;\n        y := 10;\n    }\n}\n\n"
  },
  {
    "path": "experimental/Tests/editor/range/AST/proj/AB.arm",
    "content": "include \"A.arm\"\ninclude \"B.arm\"\n\nproof AB {\n    refinement A B\n    var_intro z\n}\n"
  },
  {
    "path": "experimental/Tests/editor/range/AST/proj/B.arm",
    "content": "level B {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n\n        x := 5;\n        label l1:\n        y := 10;\n        label l2:\n        z := 1;\n    }\n}\n        \n"
  },
  {
    "path": "experimental/Tests/editor/range/AST/proj/BC.arm",
    "content": "include \"B.arm\"\ninclude \"C.arm\"\n\nproof BC {\n    refinement B C\n    combining l1 l2 l3\n}\n"
  },
  {
    "path": "experimental/Tests/editor/range/AST/proj/C.arm",
    "content": "level C {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n\n        x := 5;\n        label l3:\n        atomic\n        {\n            y := 10;\n            z := 1;\n        }\n    }\n}\n\n"
  },
  {
    "path": "experimental/Tests/editor/range/AST/proj/CD.arm",
    "content": "include \"C.arm\"\ninclude \"D.arm\"\n\nproof CD {\n    refinement C D\n    var_intro w\n}\n"
  },
  {
    "path": "experimental/Tests/editor/range/AST/proj/D.arm",
    "content": "level D {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n        var w:uint64 := 0;\n\n        x := 5;\n        label l3:\n        atomic\n        {\n            y := 10;\n            w := 2;\n            z := 1;\n        }\n    }\n}\n        \n"
  },
  {
    "path": "experimental/Tests/editor/range/ASTC/arg",
    "content": "C.arm -p 12:14-13:18 -l B -h D"
  },
  {
    "path": "experimental/Tests/editor/range/ASTC/expect/A.arm",
    "content": "level A {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n\n        x := 5;\n        y := 10;\n    }\n}\n\n\n"
  },
  {
    "path": "experimental/Tests/editor/range/ASTC/expect/AB.arm",
    "content": "include \"A.arm\"\ninclude \"B.arm\"\n\nproof AB {\n    refinement A B\n    var_intro z\n}\n\n"
  },
  {
    "path": "experimental/Tests/editor/range/ASTC/expect/B.arm",
    "content": "level B {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n\n        x := 5;\n        label l1:\n        y := 20;\n        z := 2;\n    }\n}\n        \n\n"
  },
  {
    "path": "experimental/Tests/editor/range/ASTC/expect/BC.arm",
    "content": "include \"B.arm\"\ninclude \"C.arm\"\n\nproof BC {\n    refinement B C\n    combining l1 l2 l3\n}\n\n"
  },
  {
    "path": "experimental/Tests/editor/range/ASTC/expect/C.arm",
    "content": "level C {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n\n        x := 5;\n        label l3:\n        atomic\n        {\n            y := 20;\n            z := 2;\n        }\n    }\n}\n\n\n"
  },
  {
    "path": "experimental/Tests/editor/range/ASTC/expect/CD.arm",
    "content": "include \"C.arm\"\ninclude \"D.arm\"\n\nproof CD {\n    refinement C D\n    var_intro w\n}\n\n"
  },
  {
    "path": "experimental/Tests/editor/range/ASTC/expect/D.arm",
    "content": "level D {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n        var w:uint64 := 0;\n\n        x := 5;\n        label l3:\n        atomic\n        {\n            y := 20;\n            z := 2;\n            w := 2;\n        }\n    }\n}\n        \n\n"
  },
  {
    "path": "experimental/Tests/editor/range/ASTC/in",
    "content": "y := 20;\nz := 2;"
  },
  {
    "path": "experimental/Tests/editor/range/ASTC/proj/A.arm",
    "content": "level A {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n\n        x := 5;\n        y := 10;\n    }\n}\n\n"
  },
  {
    "path": "experimental/Tests/editor/range/ASTC/proj/AB.arm",
    "content": "include \"A.arm\"\ninclude \"B.arm\"\n\nproof AB {\n    refinement A B\n    var_intro z\n}\n"
  },
  {
    "path": "experimental/Tests/editor/range/ASTC/proj/B.arm",
    "content": "level B {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n\n        x := 5;\n        label l1:\n        y := 10;\n        label l2:\n        z := 1;\n    }\n}\n        \n"
  },
  {
    "path": "experimental/Tests/editor/range/ASTC/proj/BC.arm",
    "content": "include \"B.arm\"\ninclude \"C.arm\"\n\nproof BC {\n    refinement B C\n    combining l1 l2 l3\n}\n"
  },
  {
    "path": "experimental/Tests/editor/range/ASTC/proj/C.arm",
    "content": "level C {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n\n        x := 5;\n        label l3:\n        atomic\n        {\n            y := 10;\n            z := 1;\n        }\n    }\n}\n\n"
  },
  {
    "path": "experimental/Tests/editor/range/ASTC/proj/CD.arm",
    "content": "include \"C.arm\"\ninclude \"D.arm\"\n\nproof CD {\n    refinement C D\n    var_intro w\n}\n"
  },
  {
    "path": "experimental/Tests/editor/range/ASTC/proj/D.arm",
    "content": "level D {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n        var w:uint64 := 0;\n\n        x := 5;\n        label l3:\n        atomic\n        {\n            y := 10;\n            z := 1;\n            w := 2;\n        }\n    }\n}\n        \n"
  },
  {
    "path": "experimental/Tests/editor/range/ASTS/arg",
    "content": "C.arm -p 12:14-13:18 -l B -h D"
  },
  {
    "path": "experimental/Tests/editor/range/ASTS/expect/A.arm",
    "content": "level A {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n\n        x := 5;\n        y := 10;\n    }\n}\n\n\n"
  },
  {
    "path": "experimental/Tests/editor/range/ASTS/expect/AB.arm",
    "content": "include \"A.arm\"\ninclude \"B.arm\"\n\nproof AB {\n    refinement A B\n    var_intro z\n}\n\n"
  },
  {
    "path": "experimental/Tests/editor/range/ASTS/expect/B.arm",
    "content": "level B {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n\n        x := 5;\n        label l1:\n        y := 20;\n        z := 2;\n        z ::= 4;\n    }\n}\n        \n\n"
  },
  {
    "path": "experimental/Tests/editor/range/ASTS/expect/BC.arm",
    "content": "include \"B.arm\"\ninclude \"C.arm\"\n\nproof BC {\n    refinement B C\n    combining l1 l2 l3\n}\n\n"
  },
  {
    "path": "experimental/Tests/editor/range/ASTS/expect/C.arm",
    "content": "level C {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n\n        x := 5;\n        label l3:\n        atomic\n        {\n            y := 20;\n            z := 2;\n            z ::= 4;\n        }\n    }\n}\n\n\n"
  },
  {
    "path": "experimental/Tests/editor/range/ASTS/expect/CD.arm",
    "content": "include \"C.arm\"\ninclude \"D.arm\"\n\nproof CD {\n    refinement C D\n    var_intro w\n}\n\n"
  },
  {
    "path": "experimental/Tests/editor/range/ASTS/expect/D.arm",
    "content": "level D {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n        var w:uint64 := 0;\n\n        x := 5;\n        label l3:\n        atomic\n        {\n            y := 20;\n            z := 2;\n            z ::= 4;\n            w := 2;\n        }\n    }\n}\n        \n\n"
  },
  {
    "path": "experimental/Tests/editor/range/ASTS/in",
    "content": "y := 20;\nz := 2;\nz ::= 4;"
  },
  {
    "path": "experimental/Tests/editor/range/ASTS/proj/A.arm",
    "content": "level A {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n\n        x := 5;\n        y := 10;\n    }\n}\n\n"
  },
  {
    "path": "experimental/Tests/editor/range/ASTS/proj/AB.arm",
    "content": "include \"A.arm\"\ninclude \"B.arm\"\n\nproof AB {\n    refinement A B\n    var_intro z\n}\n"
  },
  {
    "path": "experimental/Tests/editor/range/ASTS/proj/B.arm",
    "content": "level B {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n\n        x := 5;\n        label l1:\n        y := 10;\n        label l2:\n        z := 1;\n    }\n}\n        \n"
  },
  {
    "path": "experimental/Tests/editor/range/ASTS/proj/BC.arm",
    "content": "include \"B.arm\"\ninclude \"C.arm\"\n\nproof BC {\n    refinement B C\n    combining l1 l2 l3\n}\n"
  },
  {
    "path": "experimental/Tests/editor/range/ASTS/proj/C.arm",
    "content": "level C {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n\n        x := 5;\n        label l3:\n        atomic\n        {\n            y := 10;\n            z := 1;\n        }\n    }\n}\n\n"
  },
  {
    "path": "experimental/Tests/editor/range/ASTS/proj/CD.arm",
    "content": "include \"C.arm\"\ninclude \"D.arm\"\n\nproof CD {\n    refinement C D\n    var_intro w\n}\n"
  },
  {
    "path": "experimental/Tests/editor/range/ASTS/proj/D.arm",
    "content": "level D {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n        var w:uint64 := 0;\n\n        x := 5;\n        label l3:\n        atomic\n        {\n            y := 10;\n            z := 1;\n            w := 2;\n        }\n    }\n}\n        \n"
  },
  {
    "path": "experimental/Tests/editor/range/counter/arg",
    "content": "E.arm -p 76:17-76:26 -l B -h G"
  },
  {
    "path": "experimental/Tests/editor/range/counter/in",
    "content": "inc1 ::= tid1;\ninc1 ::= inc1;\n"
  },
  {
    "path": "experimental/Tests/editor/range/counter/proj/A.arm",
    "content": "level A {\n    noaddr var x:uint32 := 0;\n    ghost var acquire_map: map<uint64, OptionalThread> := map[];\n\n    method {:extern} print_uint32(i:uint32)\n\n    method {:extern} Mutex_Init() returns (m: uint64)\n        ensures m in acquire_map && acquire_map[m] == OptionalNone()\n        ensures m != 0\n    {\n        atomic {\n            somehow modifies m \n                ensures (m !in acquire_map) && (m != 0);\n            acquire_map := acquire_map[m := OptionalNone()];\n        }\n    }\n\n    // decl acquire lock\n    method {:extern} Acquire(m: uint64)\n        ensures m in acquire_map && acquire_map[m] == OptionalSome($me)\n    {\n        assume acquire_map[m].OptionalNone?;\n        acquire_map[m] := OptionalSome($me);\n    }\n\n    // decl release lock\n    method {:extern} Release(m: uint64)\n        ensures m in acquire_map && acquire_map[m] != OptionalSome($me)\n    {\n        atomic {\n            assume $sb_empty;\n            assert acquire_map[m] == OptionalSome($me);\n            acquire_map[m] := OptionalNone();\n        }\n    }\n \n    method inc(m: uint64)\n    {\n        noaddr var y: uint32;\n        Acquire(m);\n        \n        y := x + 1;\n        x := y;\n\n        Release(m);\n    }\n\n    method main()\n    {\n        noaddr var tid1:uint64 := 0;\n        noaddr var tid2:uint64 := 0;\n        noaddr var m:uint64 := 0;\n\n        m := Mutex_Init();\n\n        tid1 := create_thread inc(m);\n        tid2 := create_thread inc(m);\n\n        join tid1;\n        join tid2;\n        \n        print_uint32(x);\n    }\n}\n        \n"
  },
  {
    "path": "experimental/Tests/editor/range/counter/proj/AB.arm",
    "content": "include \"A.arm\"\ninclude \"B.arm\"\n\nproof AB {\n    refinement A B\n    var_intro mutex, inc1, inc2, done, main_reading\n}\n"
  },
  {
    "path": "experimental/Tests/editor/range/counter/proj/B.arm",
    "content": "include \"SharedStructs.arm\"\n\nlevel B using SharedStructs{\n    noaddr var x:uint32 := 0;\n    ghost var mutex:uint64 := 0;\n    ghost var acquire_map: map<uint64, OptionalThread> := map[];\n    ghost var inc1:uint64 := 0;\n    ghost var inc2:uint64 := 0;\n    ghost var done: set<uint64> := {};\n    ghost var main_reading: uint8 := 0;\n\n    method {:extern} print_uint32(i:uint32)\n\n    method {:extern} Mutex_Init() returns (m: uint64)\n        ensures m in acquire_map && acquire_map[m] == OptionalNone()\n        ensures m != 0\n    {\n        atomic {\n            somehow modifies m\n                ensures (m !in acquire_map) && (m != 0);\n            acquire_map := acquire_map[m := OptionalNone()];\n        }\n    }\n\n    // decl acquire lock\n    method {:extern} Acquire(m: uint64)\n        requires m in acquire_map\n        ensures m in acquire_map && acquire_map[m] == OptionalSome($me)\n        ensures m == old(m)\n    {\n        assume acquire_map[m].OptionalNone?;\n        acquire_map[m] := OptionalSome($me);\n    }\n\n    // decl release lock\n    method {:extern} Release(m: uint64)\n        requires m in acquire_map\n        ensures m in acquire_map && acquire_map[m] != OptionalSome($me)\n        ensures m == old(m)\n    {\n        atomic {\n            assume $sb_empty;\n            assert acquire_map[m] == OptionalSome($me);\n            acquire_map[m] := OptionalNone();\n        }\n    }\n \n    method inc(m: uint64)\n        requires m == mutex\n    {\n        noaddr var y: uint32;\n        Acquire(m);\n        \n        y := x + 1;\n        atomic {\n        x := y;\n        done := done + {$me};\n        }\n\n        Release(m);\n    }\n\n    method main()\n        requires mutex == 0\n    {\n        noaddr var tid1:uint64 := 0;\n        noaddr var tid2:uint64 := 0;\n        noaddr var m:uint64 := 0;\n        \n        m := Mutex_Init();\n        \n        mutex := m;\n\n        atomic {\n            tid1 := create_thread inc(m);\n            inc1 ::= tid1;\n        }\n\n        atomic {\n            tid2 := create_thread inc(m);\n            inc2 := tid2;\n        }\n\n        join tid1;\n        join tid2;\n        \n        main_reading := 1;\n\n        print_uint32(x);\n    }\n\n    invariant only_mutex_is_used\n    {\n        forall m :: m in acquire_map ==> m == mutex || acquire_map[m].OptionalNone?\n    }\n\n    yield_predicate YP1 \n    {\n        (old(inc1) != 0 ==> inc1 == old(inc1)) &&\n        (old(inc2) != 0 ==> inc2 == old(inc2)) &&\n        (old(mutex) != 0 ==> mutex == old(mutex)) &&\n        (forall m :: m in old(acquire_map) ==> m in acquire_map)\n    }\n\n    yield_predicate YP2\n    {\n        (old(mutex) in old(acquire_map) && old(acquire_map[mutex]) == OptionalSome($me) ==> mutex in acquire_map && acquire_map[mutex] == OptionalSome($me)) &&\n        (old(mutex) in old(acquire_map) && old(acquire_map[mutex]) != OptionalSome($me) ==> mutex in acquire_map && acquire_map[mutex] != OptionalSome($me))\n    }\n}\n"
  },
  {
    "path": "experimental/Tests/editor/range/counter/proj/BC.arm",
    "content": "include \"B.arm\"\ninclude \"C.arm\"\n\nproof BC {\n    refinement B C\n    assume_intro\n\n    inductive_invariant no_joinable \"forall jtid :: jtid in s.s.joinable_tids ==> jtid !in threads\"\n\n    inductive_invariant zero_is_not_a_mutex \"0 !in ghosts.acquire_map\"\n\n    chl_invariant no_other_threads @\"\n      && (forall tid :: tid in threads ==> (tid == ghosts.inc1 || tid == ghosts.inc2 || tid == tid_init))\n    \"\n\n    chl_invariant inc1_2_uses_mutex @\"\n      forall tid :: tid in {ghosts.inc1, ghosts.inc2} && tid in threads ==> \n        && (threads[tid].top.Armada_StackFrame_Acquire? ==> threads[tid].top.Acquire.m == ghosts.mutex)\n        && (threads[tid].top.Armada_StackFrame_Release? ==> threads[tid].top.Release.m == ghosts.mutex)\n    \"\n\n    chl_invariant no_threads_when_main_reading @\"\n      forall tid :: tid in threads && tid != tid_init ==> ghosts.main_reading == 0\n    \"\n\n    chl_invariant only_mutex_is_used\n\n    chl_invariant GlobalInvariant @\"\n        (ghosts.mutex in ghosts.acquire_map && ghosts.acquire_map[ghosts.mutex].OptionalSome? ==> ghosts.acquire_map[ghosts.mutex].tid in threads)\n    \"\n\n    inductive_invariant One_Main @\"\n        forall tid :: (tid in threads && (threads[tid].top.Armada_StackFrame_main? || \n                                     threads[tid].top.Armada_StackFrame_print_uint32? ||\n                                     threads[tid].top.Armada_StackFrame_Mutex_Init?))\n                  <==> \n                 (tid in threads && tid == tid_init)\n    \"\n\n    chl_yield_pred inc_threads @\"\n        && (ghosts.inc1 != 0 && ghosts.inc1 !in threads ==> ghosts'.inc1 !in threads')\n        && (ghosts.inc2 != 0 && ghosts.inc2 !in threads ==> ghosts'.inc2 !in threads')\n    \"\n\n    chl_yield_pred main_owns_incs_and_mutex_and_reading @\"\n        && ghosts.mutex == ghosts'.mutex\n        && (tid == tid_init ==> (ghosts.inc1 == ghosts'.inc1 && ghosts.inc2 == ghosts'.inc2 && ghosts.mutex == ghosts'.mutex && ghosts.main_reading == ghosts'.main_reading))\n    \"\n\n    chl_yield_pred YP1\n    //chl_yield_pred {:excludeMethod Acquire, Release, inc} YP2\n    chl_yield_pred {:excludeMethod Acquire, Release, inc} YP2 @\"\n        && (ghosts.mutex in ghosts.acquire_map ==> ghosts'.mutex in ghosts'.acquire_map)\n        && (ghosts.mutex in ghosts.acquire_map && ghosts.acquire_map[ghosts.mutex] == OptionalSome(tid) ==> ghosts'.acquire_map[ghosts'.mutex] == OptionalSome(tid))\n        && (ghosts.mutex in ghosts.acquire_map && ghosts.acquire_map[ghosts.mutex] != OptionalSome(tid) ==> ghosts'.acquire_map[ghosts'.mutex] != OptionalSome(tid))\n    \"\n}\n"
  },
  {
    "path": "experimental/Tests/editor/range/counter/proj/C.arm",
    "content": "include \"SharedStructs.arm\"\n\nlevel C using SharedStructs {\n    noaddr var x:uint32 := 0;\n    ghost var mutex:uint64 := 0;\n    ghost var acquire_map: map<uint64, OptionalThread> := map[];\n    ghost var inc1:uint64 := 0;\n    ghost var inc2:uint64 := 0;\n    ghost var done: set<uint64> := {};\n    ghost var main_reading: uint8 := 0;\n\n    method {:extern} print_uint32(i:uint32)\n\n    method {:extern} Mutex_Init() returns (m: uint64)\n        requires mutex == 0\n        ensures m in acquire_map && acquire_map[m] == OptionalNone()\n        ensures m != 0\n    {\n        atomic {\n            somehow modifies m\n                ensures (m !in acquire_map) && (m != 0);\n            acquire_map := acquire_map[m := OptionalNone()];\n            //acquire_map[m] := OptionalNone();\n        }\n    }\n\n    // decl acquire lock\n    method {:extern} Acquire(m: uint64)\n        requires m in acquire_map && m != 0\n        ensures m in acquire_map && acquire_map[m] == OptionalSome($me)\n        ensures m == old(m)\n    {\n        assume acquire_map[m].OptionalNone?;\n        assume main_reading == 0;\n        acquire_map[m] := OptionalSome($me);\n    }\n\n    // decl release lock\n    method {:extern} Release(m: uint64)\n        requires m in acquire_map && acquire_map[m] == OptionalSome($me)\n        ensures m in acquire_map && acquire_map[m] != OptionalSome($me)\n        ensures m == old(m)\n    {\n        atomic {\n            assume $sb_empty;\n            assert acquire_map[m] == OptionalSome($me);\n            acquire_map[m] := OptionalNone();\n        }\n    }\n \n    method inc(m: uint64)\n        requires m == mutex\n        requires m != 0 && m in acquire_map\n    {\n        noaddr var y: uint32;\n        assume m == mutex;\n        Acquire(m);\n        \n        assume acquire_map[mutex] == OptionalSome($me);\n        y := x + 1;\n\n        assume acquire_map[mutex] == OptionalSome($me);\n        atomic {\n        x := y;\n        done := done + {$me};\n        }\n\n        assume acquire_map[mutex] == OptionalSome($me);\n        assume m == mutex;\n        Release(m);\n    }\n\n    method main()\n        requires mutex == 0\n        requires inc1 == 0\n        requires inc2 == 0\n        requires main_reading == 0\n    {\n        noaddr var tid1:uint64 := 0;\n        noaddr var tid2:uint64 := 0;\n        noaddr var m:uint64 := 0;\n        \n        m := Mutex_Init();\n        \n        assume mutex == 0;\n        mutex := m;\n\n        atomic {\n            tid1 := create_thread inc(m);\n            inc1 ::= tid1;\n        }\n\n        atomic {\n            tid2 := create_thread inc(m);\n            inc2 := tid2;\n        }\n\n        join tid1;\n        join tid2;\n\n        main_reading := 1;\n        \n        assume main_reading == 1;\n        assume mutex in acquire_map;\n        assume acquire_map[mutex].OptionalNone? || acquire_map[mutex] == OptionalSome($me);\n        print_uint32(x);\n    }\n}\n"
  },
  {
    "path": "experimental/Tests/editor/range/counter/proj/CD.arm",
    "content": "include \"C.arm\"\ninclude \"D.arm\"\n\nproof CD {\n    refinement C D\n    tso_elim x @\"\n        && ghosts.mutex in ghosts.acquire_map\n        && tid in threads\n        && (var acquired := ghosts.acquire_map[ghosts.mutex];\n             acquired == OptionalSome(tid) ||\n            (acquired == OptionalNone() && tid == tid_init && ghosts.main_reading == 1))\n    \"\n\n    inductive_invariant zero_is_not_a_mutex \"0 !in ghosts.acquire_map\"\n\n    inductive_invariant One_Main @\"\n        forall tid :: (tid in threads && (threads[tid].top.Armada_StackFrame_main? || \n                  threads[tid].top.Armada_StackFrame_print_uint32? ||\n                  threads[tid].top.Armada_StackFrame_Mutex_Init?))\n                 <==> \n                 (tid in threads && tid == tid_init)\n    \"\n\n    inductive_invariant EmptyBuffer @\"\n      forall tid :: tid in threads && tid == tid_init ==> (|threads[tid].storeBuffer| == 0)\n    \" depends_on One_Main\n}\n"
  },
  {
    "path": "experimental/Tests/editor/range/counter/proj/D.arm",
    "content": "include \"SharedStructs.arm\"\n\nlevel D using SharedStructs {\n    noaddr var x:uint32 := 0;\n    ghost var mutex:uint64 := 0;\n    ghost var acquire_map: map<uint64, OptionalThread> := map[];\n    ghost var inc1:uint64 := 0;\n    ghost var inc2:uint64 := 0;\n    ghost var done: set<uint64> := {};\n    ghost var main_reading: uint8 := 0;\n\n    method {:extern} print_uint32(i:uint32)\n\n    method {:extern} Mutex_Init() returns (m: uint64)\n        requires mutex == 0\n        ensures m in acquire_map && acquire_map[m] == OptionalNone()\n        ensures m != 0\n    {\n        atomic {\n            somehow modifies m\n                ensures (m !in acquire_map) && (m != 0);\n            acquire_map := acquire_map[m := OptionalNone()];\n            //acquire_map[m] := OptionalNone();\n        }\n    }\n\n    // decl acquire lock\n    method {:extern} Acquire(m: uint64)\n        requires m in acquire_map && m != 0\n        ensures m in acquire_map && acquire_map[m] == OptionalSome($me)\n        ensures m == old(m)\n    {\n        assume acquire_map[m].OptionalNone?;\n        acquire_map[m] := OptionalSome($me);\n    }\n\n    // decl release lock\n    method {:extern} Release(m: uint64)\n        requires m in acquire_map && acquire_map[m] == OptionalSome($me)\n        ensures m in acquire_map && acquire_map[m] != OptionalSome($me)\n        ensures m == old(m)\n    {\n        atomic {\n            assume $sb_empty;\n            assert acquire_map[m] == OptionalSome($me);\n            acquire_map[m] := OptionalNone();\n        }\n    }\n \n    method inc(m: uint64)\n        requires m == mutex\n        requires m != 0 && m in acquire_map\n    {\n        noaddr var y: uint32;\n        assume m == mutex;\n        Acquire(m);\n        \n        assume acquire_map[mutex] == OptionalSome($me);\n        y := x + 1;\n\n        assume acquire_map[mutex] == OptionalSome($me);\n        label lb1:\n        atomic {\n        x ::= y;\n        done := done + {$me};\n        }\n\n        assume acquire_map[mutex] == OptionalSome($me);\n        assume m == mutex;\n        Release(m);\n    }\n\n    method main()\n        requires mutex == 0\n        requires inc1 == 0\n        requires inc2 == 0\n    {\n        noaddr var tid1:uint64 := 0;\n        noaddr var tid2:uint64 := 0;\n        noaddr var m:uint64 := 0;\n        \n        m := Mutex_Init();\n\n        assume mutex == 0;\n        mutex := m;\n\n        atomic {\n            tid1 := create_thread inc(m);\n            inc1 ::= tid1;\n        }\n\n        atomic {\n            tid2 := create_thread inc(m);\n            inc2 := tid2;\n        }\n\n        join tid1;\n        join tid2;\n\n        main_reading := 1;\n        \n        assume main_reading == 1;\n        assume mutex in acquire_map;\n        assume acquire_map[mutex].OptionalNone? || acquire_map[mutex] == OptionalSome($me);\n        print_uint32(x);\n    }\n}\n"
  },
  {
    "path": "experimental/Tests/editor/range/counter/proj/DE.arm",
    "content": "include \"D.arm\"\ninclude \"E.arm\"\n\nproof DE {\n    refinement D E\n    reduction phase1 inc_lb1\n    use_address_invariant\n\n    inductive_invariant EmptyBuffer @\"\n      && (forall tid :: tid in threads ==> (threads[tid].storeBuffer == []))\n    \"\n\n    inductive_invariant zero_is_not_a_mutex \"0 !in ghosts.acquire_map\"\n}\n"
  },
  {
    "path": "experimental/Tests/editor/range/counter/proj/E.arm",
    "content": "include \"SharedStructs.arm\"\n\nlevel E using SharedStructs {\n    noaddr var x:uint32 := 0;\n    ghost var mutex:uint64 := 0;\n    ghost var acquire_map: map<uint64, OptionalThread> := map[];\n    ghost var inc1:uint64 := 0;\n    ghost var inc2:uint64 := 0;\n    ghost var done: set<uint64> := {};\n    ghost var main_reading: uint8 := 0;\n\n    method {:extern} print_uint32(i:uint32)\n\n    method {:extern} Mutex_Init() returns (m: uint64)\n    {\n        atomic {\n            somehow modifies m\n                ensures (m !in acquire_map) && (m != 0);\n            acquire_map := acquire_map[m := OptionalNone()];\n            //acquire_map[m] := OptionalNone();\n        }\n    }\n\n    // decl acquire lock\n    method {:extern} Acquire(m: uint64)\n    {\n        assume acquire_map[m].OptionalNone?;\n        acquire_map[m] := OptionalSome($me);\n    }\n\n    // decl release lock\n    method {:extern} Release(m: uint64)\n    {\n        atomic {\n            assume $sb_empty;\n            assert acquire_map[m] == OptionalSome($me);\n            acquire_map[m] := OptionalNone();\n        }\n    }\n \n    method inc(m: uint64)\n        requires m == mutex\n        requires m != 0 && m in acquire_map\n    {\n        noaddr var y: uint32;\n        assume m == mutex;\n        Acquire(m);\n        \n        assume acquire_map[mutex] == OptionalSome($me);\n        atomic {\n            y := x + 1;\n            x ::= y;\n            done := done + {$me};\n        }\n\n        assume acquire_map[mutex] == OptionalSome($me);\n        assume m == mutex;\n        Release(m);\n    }\n\n    method main()\n        requires mutex == 0\n        requires inc1 == 0\n        requires inc2 == 0\n    {\n        noaddr var tid1:uint64 := 0;\n        noaddr var tid2:uint64 := 0;\n        noaddr var m:uint64 := 0;\n        \n        m := Mutex_Init();\n\n        mutex := m;\n\n        atomic {\n            tid1 := create_thread inc(m);\n            inc1 ::= tid1;\n        }\n\n        atomic {\n            tid2 := create_thread inc(m);\n            inc2 := tid2;\n        }\n\n        join tid1;\n        join tid2;\n\n        main_reading := 1;\n        \n        print_uint32(x);\n    }\n}\n"
  },
  {
    "path": "experimental/Tests/editor/range/counter/proj/EF.arm",
    "content": "include \"E.arm\"\ninclude \"F.arm\"\n\nproof EF {\n    refinement E F\n    stack_var_hiding inc y\n}\n"
  },
  {
    "path": "experimental/Tests/editor/range/counter/proj/F.arm",
    "content": "include \"SharedStructs.arm\"\n\nlevel F using SharedStructs {\n    noaddr var x:uint32 := 0;\n    ghost var mutex:uint64 := 0;\n    ghost var acquire_map: map<uint64, OptionalThread> := map[];\n    ghost var inc1:uint64 := 0;\n    ghost var inc2:uint64 := 0;\n    ghost var done: set<uint64> := {};\n    ghost var main_reading: uint8 := 0;\n\n    method {:extern} print_uint32(i:uint32)\n\n    method {:extern} Mutex_Init() returns (m: uint64)\n    {\n        atomic {\n            somehow modifies m\n                ensures (m !in acquire_map) && (m != 0);\n            acquire_map := acquire_map[m := OptionalNone()];\n            //acquire_map[m] := OptionalNone();\n        }\n    }\n\n    // decl acquire lock\n    method {:extern} Acquire(m: uint64)\n    {\n        assume acquire_map[m].OptionalNone?;\n        acquire_map[m] := OptionalSome($me);\n    }\n\n    // decl release lock\n    method {:extern} Release(m: uint64)\n    {\n        atomic {\n            assume $sb_empty;\n            assert acquire_map[m] == OptionalSome($me);\n            acquire_map[m] := OptionalNone();\n        }\n    }\n \n    method inc(m: uint64)\n        requires $me !in done\n    {\n        assume m == mutex;\n        Acquire(m);\n        \n        assume acquire_map[mutex] == OptionalSome($me);\n        atomic {\n            x ::= x + 1;\n            done := done + {$me};\n        }\n\n        assume acquire_map[mutex] == OptionalSome($me);\n        assume m == mutex;\n        Release(m);\n    }\n\n    method main()\n        requires mutex == 0\n        requires inc1 == 0\n        requires inc2 == 0\n    {\n        noaddr var tid1:uint64 := 0;\n        noaddr var tid2:uint64 := 0;\n        noaddr var m:uint64 := 0;\n        \n        m := Mutex_Init();\n\n        mutex := m;\n\n        atomic {\n            tid1 := create_thread inc(m);\n            inc1 ::= tid1;\n        }\n\n        atomic {\n            tid2 := create_thread inc(m);\n            inc2 := tid2;\n        }\n\n        join tid1;\n        join tid2;\n\n        main_reading := 1;\n        \n        print_uint32(x);\n    }\n\n    yield_predicate YP1\n    {\n        $me !in old(done) ==> $me !in done\n    }\n\n    yield_predicate YP2\n    {\n        (old(inc1) != 0 ==> inc1 == old(inc1)) &&\n        (old(inc2) != 0 ==> inc2 == old(inc2)) &&\n        (forall tid :: tid in old(done) ==> tid in done)\n    }\n\n    invariant Inv1\n    {\n        (x as int == |done|) && \n        (done <= {inc1, inc2}) &&\n        (inc1 != 0 ==> inc1 != inc2) &&\n        (0 !in done)\n    }\n}\n"
  },
  {
    "path": "experimental/Tests/editor/range/counter/proj/FG.arm",
    "content": "include \"F.arm\"\ninclude \"G.arm\"\n\nproof FG {\n    refinement F G\n    assume_intro\n    \n    include_file \"extra.dfy\"\n    import_module sets_helpers\n    extra lemma_ExpandedStraightlineBehaviorSatisfiesGlobalInvariant_Inv1_inc_Yielded_1_Then_From_inc_1_To_inc_3\n            \"sets_helpers.Cardinality(s5.s.ghosts.done, {s5.s.ghosts.inc1, s5.s.ghosts.inc2});\"\n    extra lemma_ExpandedStraightlineBehaviorSatisfiesLocalInvariant_main_Yielded_9_Then_From_main_9_To_print_uint32_Start @\"\n      assert s19.s.ghosts.done == {s19.s.ghosts.inc1, s19.s.ghosts.inc2} <==>\n             var hs := ConvertTotalState_LPlusH(s19); hs.ghosts.done == {hs.ghosts.inc1, hs.ghosts.inc2};\n    \"\n\n    inductive_invariant no_joinable \"forall jtid :: jtid in s.s.joinable_tids ==> jtid !in threads\"\n\n    inductive_invariant EmptyBuffer @\"\n      && (forall tid :: tid in threads ==> (threads[tid].storeBuffer == []))\n    \"\n\n    inductive_invariant One_Main @\"\n        forall tid :: (tid in threads && (threads[tid].top.Armada_StackFrame_main? || \n                                     threads[tid].top.Armada_StackFrame_print_uint32? ||\n                                     threads[tid].top.Armada_StackFrame_Mutex_Init?))\n                  <==> \n                 (tid in threads && tid == tid_init)\n    \"\n\n    chl_invariant Inv1\n\n    chl_invariant no_other_threads @\"\n      && (forall tid :: tid in threads ==> (tid == ghosts.inc1 || tid == ghosts.inc2 || tid == tid_init))\n    \"\n\n    chl_invariant GlobalInvariant @\"\n      && (ghosts.inc1 != 0 && ghosts.inc1 !in threads ==> ghosts.inc1 in ghosts.done)\n      && (ghosts.inc2 != 0 && ghosts.inc2 !in threads ==> ghosts.inc2 in ghosts.done)\n    \"\n\n    chl_yield_pred {:excludeMethod inc} YP1\n    chl_yield_pred YP2\n\n    chl_yield_pred inc_threads @\"\n        && (ghosts.inc1 != 0 && ghosts.inc1 !in threads ==> s'.s.ghosts.inc1 !in threads')\n        && (ghosts.inc2 != 0 && ghosts.inc2 !in threads ==> s'.s.ghosts.inc2 !in threads')\n    \"\n\n    chl_yield_pred main_owns_incs @\"\n        && (tid == tid_init ==> (ghosts.inc1 == s'.s.ghosts.inc1 && ghosts.inc2 == s'.s.ghosts.inc2))\n        && (tid == tid_init && ghosts.inc1 in s.s.joinable_tids ==> s'.s.ghosts.inc1 in s'.s.joinable_tids)\n        && (tid == tid_init && ghosts.inc1 in threads ==> (s'.s.ghosts.inc1 in s'.s.joinable_tids || s'.s.ghosts.inc1 in threads'))\n    \"\n}\n"
  },
  {
    "path": "experimental/Tests/editor/range/counter/proj/G.arm",
    "content": "include \"SharedStructs.arm\"\n\nlevel G using SharedStructs {\n    noaddr var x:uint32 := 0;\n    ghost var mutex:uint64 := 0;\n    ghost var acquire_map: map<uint64, OptionalThread> := map[];\n    ghost var inc1:uint64 := 0;\n    ghost var inc2:uint64 := 0;\n    ghost var done: set<uint64> := {};\n    ghost var main_reading: uint8 := 0;\n\n    method {:extern} print_uint32(i:uint32)\n\n    method {:extern} Mutex_Init() returns (m: uint64)\n    {\n        atomic {\n            somehow modifies m\n                ensures (m !in acquire_map) && (m != 0);\n            acquire_map := acquire_map[m := OptionalNone()];\n            //acquire_map[m] := OptionalNone();\n        }\n    }\n\n    // decl acquire lock\n    method {:extern} Acquire(m: uint64)\n    {\n        assume acquire_map[m].OptionalNone?;\n        acquire_map[m] := OptionalSome($me);\n    }\n\n    // decl release lock\n    method {:extern} Release(m: uint64)\n    {\n        atomic {\n            assume $sb_empty;\n            assert acquire_map[m] == OptionalSome($me);\n            acquire_map[m] := OptionalNone();\n        }\n    }\n \n    method inc(m: uint64)\n        requires $me !in done\n    {\n        Acquire(m);\n        \n        atomic {\n            x ::= x + 1;\n            done := done + {$me};\n        }\n\n        Release(m);\n    }\n\n    method main()\n        requires mutex == 0\n        requires inc1 == 0\n        requires inc2 == 0\n    {\n        noaddr var tid1:uint64 := 0;\n        noaddr var tid2:uint64 := 0;\n        noaddr var m:uint64 := 0;\n        \n        m := Mutex_Init();\n\n        mutex := m;\n\n        atomic {\n            tid1 := create_thread inc(m);\n            inc1 ::= tid1;\n        }\n\n        atomic {\n            tid2 := create_thread inc(m);\n            inc2 := tid2;\n        }\n\n        join tid1;\n        join tid2;\n\n        main_reading := 1;\n        \n        assume done == {inc1, inc2};\n        assume x == 2;\n        print_uint32(x);\n    }\n}\n"
  },
  {
    "path": "experimental/Tests/editor/range/counter/proj/GI.arm",
    "content": "include \"G.arm\"\ninclude \"I.arm\"\n\nproof GI {\n    refinement G I\n    weakening\n}\n"
  },
  {
    "path": "experimental/Tests/editor/range/counter/proj/I.arm",
    "content": "include \"SharedStructs.arm\"\n\nlevel I using SharedStructs {\n    noaddr var x:uint32 := 0;\n    ghost var mutex:uint64 := 0;\n    ghost var acquire_map: map<uint64, OptionalThread> := map[];\n    ghost var inc1:uint64 := 0;\n    ghost var inc2:uint64 := 0;\n    ghost var done: set<uint64> := {};\n    ghost var main_reading: uint8 := 0;\n\n    method {:extern} print_uint32(i:uint32)\n\n    method {:extern} Mutex_Init() returns (m: uint64)\n    {\n        atomic {\n            somehow modifies m\n                ensures (m !in acquire_map) && (m != 0);\n            acquire_map := acquire_map[m := OptionalNone()];\n            //acquire_map[m] := OptionalNone();\n        }\n    }\n\n    // decl acquire lock\n    method {:extern} Acquire(m: uint64)\n    {\n        assume acquire_map[m].OptionalNone?;\n        acquire_map[m] := OptionalSome($me);\n    }\n\n    // decl release lock\n    method {:extern} Release(m: uint64)\n    {\n        atomic {\n            assume $sb_empty;\n            assert acquire_map[m] == OptionalSome($me);\n            acquire_map[m] := OptionalNone();\n        }\n    }\n \n    method inc(m: uint64)\n    {\n        Acquire(m);\n        \n        atomic {\n            x ::= x + 1;\n            done := done + {$me};\n        }\n\n        Release(m);\n    }\n\n    method main()\n    {\n        noaddr var tid1:uint64 := 0;\n        noaddr var tid2:uint64 := 0;\n        noaddr var m:uint64 := 0;\n        \n        m := Mutex_Init();\n\n        mutex := m;\n\n        atomic {\n            tid1 := create_thread inc(m);\n            inc1 ::= tid1;\n        }\n\n        atomic {\n            tid2 := create_thread inc(m);\n            inc2 := tid2;\n        }\n\n        join tid1;\n        join tid2;\n\n        main_reading := 1;\n        \n        print_uint32(2);\n    }\n}\n"
  },
  {
    "path": "experimental/Tests/editor/range/counter/proj/IJ.arm",
    "content": "include \"I.arm\"\ninclude \"J.arm\"\n\nproof IJ {\n    refinement I J\n    var_hiding done, inc1, inc2, main_reading\n}\n"
  },
  {
    "path": "experimental/Tests/editor/range/counter/proj/J.arm",
    "content": "include \"SharedStructs.arm\"\n\nlevel J using SharedStructs {\n    noaddr var x:uint32 := 0;\n    ghost var mutex:uint64 := 0;\n    ghost var acquire_map: map<uint64, OptionalThread> := map[];\n\n    method {:extern} print_uint32(i:uint32)\n\n    method {:extern} Mutex_Init() returns (m: uint64)\n    {\n        atomic {\n            somehow modifies m\n                ensures (m !in acquire_map) && (m != 0);\n            acquire_map := acquire_map[m := OptionalNone()];\n            //acquire_map[m] := OptionalNone();\n        }\n    }\n\n    // decl acquire lock\n    method {:extern} Acquire(m: uint64)\n    {\n        assume acquire_map[m].OptionalNone?;\n        acquire_map[m] := OptionalSome($me);\n    }\n\n    // decl release lock\n    method {:extern} Release(m: uint64)\n    {\n        atomic {\n            assume $sb_empty;\n            assert acquire_map[m] == OptionalSome($me);\n            acquire_map[m] := OptionalNone();\n        }\n    }\n \n    method inc(m: uint64)\n    {\n        Acquire(m);\n        \n        atomic {\n            x ::= x + 1;\n        }\n\n        Release(m);\n    }\n\n    method main()\n    {\n        noaddr var tid1:uint64 := 0;\n        noaddr var tid2:uint64 := 0;\n        noaddr var m:uint64 := 0;\n        \n        m := Mutex_Init();\n\n        mutex := m;\n\n        atomic {\n            tid1 := create_thread inc(m);\n        }\n\n        atomic {\n            tid2 := create_thread inc(m);\n        }\n\n        join tid1;\n        join tid2;\n        \n        print_uint32(2);\n    }\n}\n"
  },
  {
    "path": "experimental/Tests/editor/range/counter/proj/SharedStructs.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs\n{\n    datatype OptionalThread = OptionalSome(tid:uint64) | OptionalNone()\n}\n"
  },
  {
    "path": "experimental/Tests/editor/range/counter/proj/Z.arm",
    "content": "include \"SharedStructs.arm\"\n\nlevel Z using SharedStructs {\n    noaddr var x:uint32 := 0;\n\n    method {:extern} print_uint32(i:uint32)\n \n    method inc()\n    {\n    }\n\n    method main()\n    {\n        print_uint32(2);\n    }\n}\n"
  },
  {
    "path": "experimental/Tests/editor/range/counter/proj/extra.dfy",
    "content": "module sets_helpers {\n\nlemma Cardinality<T>(x:set<T>, y:set<T>)\n    ensures x<y ==> |x|<|y|;\n    ensures x<=y ==> |x|<=|y|;\n{\n    if (x!={}) {\n        var e :| e in x;\n        Cardinality(x-{e}, y-{e});\n    }\n}\n\n}\n"
  },
  {
    "path": "experimental/Tests/fail/arr.arm",
    "content": "// This first part is about whether the model for arrays in a struct is sound.  In\n// particular, it looks like x is modeled as a pointer, so that passing in the\n// struct to a function would be passing in a reference\n\nstruct ArrayOfInts {\n  var x: int[8];\n}\n\nlevel A {\n  method m1(b:ArrayOfInts) {\n    b.x[1] := 10;\n  }\n\n  method main() {\n    var a:ArrayOfInts;\n    a.x[1] := 0;\n    m1(a);\n    assert (a.x[1] == 0);\n  }\n}\n"
  },
  {
    "path": "experimental/Tests/fail/fail.arm",
    "content": "struct int_pair {\n  var first:int;\n  var second:int;\n}\n\nlevel Pointer {\n  method parens() {\n    var x:int;\n    // The following two give different errors\n    // x = (1 ^ 2) & 10;\n    x := (1 ^ 2) & 10;\n  }\n\n  method main() {\n    var x:int;\n    x := 1;\n  }\n}\n"
  },
  {
    "path": "experimental/Tests/legacy-armada/.gitignore",
    "content": "**/*.dfy\n**/*.vdfy\n"
  },
  {
    "path": "experimental/Tests/legacy-armada/MyConcreteAProg.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs placeholder {}\n\nlevel A using placeholder\n {\n   ghost var a: int := 1;\n   noaddr var c: uint64 := 3;\n   ghost var e: int := 5;\n\n   method subroutine ()\n   {\n     a := 0;\n   }\n\n   method main ()\n   {\n     a := 10;\n     atomic {\n       c := 20;\n       e := 30;\n     }\n     subroutine();\n   }\n\n  invariant CL30 {\n     c < 30\n  }\n}\n\nlevel B using placeholder\n{\n  ghost var a: int := 1;\n  noaddr var c: uint64 := 3;\n  ghost var e: int := 5;\n\n  method subroutine ()\n  {\n    a := 0;\n  }\n\n  method main ()\n  {\n    a := 10;\n    atomic {\n      c := 20;\n      e := 30;\n    }\n    subroutine();\n  }\n}\n\nproof AB {\n  refinement A B\n  weakening\n  inductive_invariant SBL30 @\"forall tid :: tid in threads ==> forall entry_id :: 0 <= entry_id < |threads[tid].storeBuffer| ==>\n        threads[tid].storeBuffer[entry_id] == L.Armada_StoreBufferEntry(L.Armada_StoreBufferLocation_Unaddressable(L.Armada_GlobalStaticVar_c, []), Armada_PrimitiveValue_uint64(20), L.Armada_PC_main_1)\"\n  inductive_invariant CL30 depends_on SBL30\n}\n"
  },
  {
    "path": "experimental/Tests/libcuckoo/Makefile",
    "content": ".PHONY: all\n\nall: carmada\n\ncarmada: carmada.cpp\n\tclang++ -ggdb -std=c++17 carmada.cpp -o carmada -lLLVM-9 -lclangBasic -lclangAST -lclangSerialization -lclangFrontend -lclangTooling\n"
  },
  {
    "path": "experimental/Tests/libcuckoo/armada.sh",
    "content": "#!/bin/bash\n\narmada=\"mono ../../Binaries/Armada.exe /armadaPath:../..\"\nif [ \"$1\" == \"\" ]; then\n    echo \"Specify file to run\";\n    exit 1;\nfi\n\n#preprocessed_armada_file=`mktemp XXXXXXXX.tmp.arm`\npreprocessed_armada_file=$1_preproc.arm\necho \"Preprocessing...\"\ngcc -P -E - < $1 > $preprocessed_armada_file\necho \"Finished preprocessing.\"\n$armada $preprocessed_armada_file\n"
  },
  {
    "path": "experimental/Tests/libcuckoo/carmada.cpp",
    "content": "// Converts C++ into Armada using clang\n\n#include <iostream>\n#include <fstream>\n#include <optional>\n#include <sstream>\n\n#include \"clang/AST/Stmt.h\"\n#include \"clang/AST/ASTConsumer.h\"\n#include \"clang/AST/RecursiveASTVisitor.h\"\n#include \"clang/Frontend/CompilerInstance.h\"\n#include \"clang/Frontend/FrontendAction.h\"\n#include \"clang/Tooling/Tooling.h\"\n#include \"clang/Basic/SourceManager.h\"\n\nusing namespace clang;\n\nnamespace armada {\n\nclass ast_nd {\npublic:\n  // virtual std::string print(unsigned int depth=0) const = 0;\n  virtual ~ast_nd() {}\n};\n\nclass expr_nd : public ast_nd {\n public:\n  bool is_deref = false;\n  bool is_addrof = false;\n  virtual std::string print() const = 0;\n};\n\nclass array_subscript_nd : public expr_nd {\n public:\n  std::unique_ptr<expr_nd> base;\n  std::unique_ptr<expr_nd> idx;\n\n  virtual std::string print() const {\n    return base->print() + \"[\" + idx->print() + \"]\";\n  }\n};\n\nclass addrof_nd : public expr_nd {\n public:\n  std::unique_ptr<expr_nd> subexpr;\n  bool is_addrof = true;\n\n  virtual std::string print() const {\n    return \"&(\" + subexpr->print() + \")\";\n  }\n};\n\nclass deref_nd : public expr_nd {\n public:\n  std::unique_ptr<expr_nd> subexpr;\n  bool is_deref = true;\n\n  virtual std::string print() const {\n    return \"*(\" + subexpr->print() + \")\";\n  }\n};\n\nclass paren_nd : public expr_nd {\npublic:\n  std::unique_ptr<expr_nd> sub_expr;\n\n  virtual std::string print() const {\n    return \"(\" + sub_expr->print() + \")\";\n  }\n};\n\nclass binary_op_nd : public expr_nd {\npublic:\n  std::unique_ptr<expr_nd> lhs;\n  std::unique_ptr<expr_nd> rhs;\n  std::string op;\n\n  virtual std::string print() const {\n    return lhs->print() + \" \" + op + \" \" + rhs->print();\n  }\n};\n\nclass unary_op_nd : public expr_nd {\npublic:\n  std::unique_ptr<expr_nd> e;\n  std::string op;\n  bool is_prefix;\n\n  virtual std::string print() const {\n    if (is_prefix)\n      return op + e->print();\n    else\n      return e->print() + op;\n  }\n};\n\nclass stmt_nd : public ast_nd {\npublic:\n  virtual std::string print(unsigned int depth=0) const = 0;\n};\n\nclass todo_stmt_nd : public stmt_nd {\npublic:\n  std::string todo;\n\n  virtual std::string print(unsigned int depth=0) const\n  {\n    return std::string(depth*2, ' ') + \"TODO_\" + todo;\n  }\n};\n\nclass stmt_expr_nd : public stmt_nd {\npublic:\n std::unique_ptr<expr_nd> e;\n  virtual std::string print(unsigned int depth=0) const {\n    return std::string(depth*2, ' ') + e->print() + \";\";\n  }\n};\n\nclass call_stmt_nd : public stmt_nd {\n public:\n  std::vector<std::unique_ptr<expr_nd>> args;\n  std::unique_ptr<expr_nd> f;\n  std::string lhs;\n\n  virtual std::string print(unsigned int depth=0) const {\n    std::ostringstream ss;\n    std::string prefix(2*depth, ' ');\n    ss << prefix;\n    if (lhs != std::string(\"\")) {\n      ss << lhs << \" := \";\n    }\n    ss << f->print() + \"(\";\n    for (auto iter = args.begin(); iter != args.end(); iter++) {\n      if (iter != args.begin())\n        ss << \", \";\n      ss << (*iter)->print();\n    }\n    ss << \");\";\n    return ss.str();\n  }\n};\n\nclass return_nd : public stmt_nd {\npublic:\n std::unique_ptr<expr_nd> ret;\n\n  virtual std::string print(unsigned int depth=0) const\n  {\n    if (ret != nullptr)\n      return std::string(depth*2, ' ') + \"return \" + ret->print() + \";\";\n    else\n      return std::string(depth*2, ' ') + \"return;\";\n  }\n};\n\nclass update_nd : public stmt_nd {\npublic:\n  std::unique_ptr<expr_nd> lhs;\n  std::unique_ptr<expr_nd> rhs;\n\n  virtual std::string print(unsigned int depth=0) const\n  {\n    return std::string(depth*2, ' ') + lhs->print() + \" := \" + rhs->print() + \";\";\n  }\n};\n\nclass vardecl_nd : public ast_nd {\n public:\n  vardecl_nd(std::string name_in, std::string type_in)\n     : name(name_in), type(type_in)\n  {}\n\n  virtual std::string print() const {\n    if (is_addressable)\n      return \"var \" + name + \":\" + type + \";\";\n    else\n      return \"noaddr var \" + name + \":\" + type + \";\";\n  }\n\n  std::string name;\n  std::string type;\n  bool is_addressable = false;\n};\n\nclass block_nd : public stmt_nd {\npublic:\n  std::vector<std::unique_ptr<stmt_nd>> stmts;\n  virtual std::string print(unsigned int depth) const {\n    std::ostringstream str;\n    std::string prefix(depth*2, ' ');\n    str << prefix << \"{\\n\";\n\n    for (const auto& stmt : stmts) {\n      if (stmt != nullptr) {\n        str << stmt->print(depth + 1) << \"\\n\";\n      }\n    }\n    str << prefix << \"}\\n\";\n    return str.str();\n  }\n};\n\nclass while_stmt_nd : public stmt_nd {\n public:\n  std::unique_ptr<expr_nd> cond;\n  std::unique_ptr<block_nd> body;\n\n  virtual std::string print(unsigned int depth=0) const {\n    std::ostringstream ss;\n    std::string prefix(depth*2, ' ');\n    ss << prefix << \"while (\" << cond->print() << \")\\n\";\n    ss << body->print(depth);\n    return ss.str();\n  }\n};\n\nclass method_block_nd : public block_nd {\npublic:\n  std::vector<std::unique_ptr<vardecl_nd>> vardecls;\n  std::vector<std::unique_ptr<stmt_nd>> stmts;\n\n  virtual std::string print(unsigned int depth) const {\n    std::ostringstream str;\n    std::string prefix(depth*2, ' ');\n    str << \"{\\n\";\n\n    for (const auto& vardecl : vardecls) {\n      str << prefix << \"  \";\n      if (vardecl != nullptr) {\n        str << vardecl->print() << \"\\n\";\n      }\n    }\n\n    for (const auto& stmt : stmts) {\n      str << prefix;\n      if (stmt != nullptr) {\n        str << stmt->print(depth + 1) << \"\\n\";\n      }\n    }\n    str << \"}\\n\";\n    return str.str();\n  }\n};\n\nclass todo_expr_nd : public expr_nd {\npublic:\n  std::string todo;\n  virtual std::string print() const {\n    return \"TODO_expr__\" + todo;\n  }\n};\n\nclass literal_nd : public expr_nd {\npublic:\n  std::string literal;\n  virtual std::string print() const {\n    return literal;\n  }\n};\n\nclass if_nd : public stmt_nd {\n public:\n  std::unique_ptr<expr_nd> cond;\n  std::unique_ptr<stmt_nd> t;\n  std::unique_ptr<stmt_nd> f;\n\n  virtual std::string print(unsigned int depth=0) const {\n    std::ostringstream ss;\n    std::string prefix = std::string(depth*2, ' ');\n    ss << prefix << \"if (\" << cond->print() << \")\\n\";\n    if (t != nullptr)\n      ss << t->print(depth);\n    if (f != nullptr) {\n      ss << prefix << \"else\\n\";\n      ss << f->print(depth);\n    }\n    return ss.str();\n  }\n};\n\nclass param_nd : public ast_nd {\npublic:\n  std::string name;\n  std::string type;\n\n  virtual std::string print() const {\n    return name + \":\" + type;\n  }\n};\n\nclass params_nd : public ast_nd {\n public:\n  std::vector<std::unique_ptr<param_nd>> param_nds;\n\n  virtual std::string print() const {\n    return \"(TODO_params)\";\n  }\n};\n\nclass method_nd: public ast_nd {\npublic:\n  std::string name;\n  std::unique_ptr<params_nd> params;\n  std::unique_ptr<method_block_nd> block;\n\n  virtual std::string print() const {\n\n    std::ostringstream stream;\n    stream << \"method \" << name;\n    if (params != nullptr) {\n      stream << params->print();\n    } else {\n      stream << \"(TODO_method_params)\";\n    }\n    if (block != nullptr) {\n      stream << \"\\n\" << block->print(0);\n    } else {\n      stream << \"\\n{\\n}\\n\";\n    }\n    return stream.str();\n  }\n};\n}\n\nclass FindNamedClassVisitor\n  : public RecursiveASTVisitor<FindNamedClassVisitor> {\nprivate:\n  std::vector<std::unique_ptr<armada::vardecl_nd>> vardecls;\n  int num_temps = 0;\n  std::vector<std::unique_ptr<armada::stmt_nd>> *block_ctx;\n  std::string class_ctx;\n\n  std::string translate_builtin_type(const BuiltinType *bt) {\n    // return std::string(bt->getNameAsCString());\n    if (bt->isBooleanType()) {\n      return \"bool\";\n    } else if (bt->isCharType()) {\n      return \"uint8\";\n    }\n\n    clang::LangOptions lang_opts;\n    lang_opts.CPlusPlus = true;\n    clang::PrintingPolicy policy(lang_opts);\n    return std::string(bt->getNameAsCString(policy));\n  }\n\n  std::string translate_record_type(const RecordType* rt) {\n    return rt->getDecl()->getNameAsString();\n  }\n\n  std::string translate_elaborated_type(const ElaboratedType* et) {\n    return translate_type(et->getNamedType().getTypePtr());\n  }\n\n  std::string translate_type_concrete(const Type* type) {\n    switch (type->getTypeClass()) {\n      case Type::TypeClass::Typedef:\n        {\n        const TypedefType* tt = static_cast<const TypedefType*>(type);\n        //return tt->getDecl()->getNameAsString();\n        return translate_type(tt->getDecl()->getUnderlyingType().getTypePtr());\n        break;\n        }\n      case Type::TypeClass::Builtin:\n        {\n          return translate_builtin_type(static_cast<const BuiltinType*>(type));\n          break;\n        }\n      case Type::TypeClass::Record:\n        {\n          return translate_record_type(static_cast<const RecordType*>(type));\n          break;\n        }\n      case Type::TypeClass::Elaborated:\n        {\n          return translate_elaborated_type(static_cast<const ElaboratedType*>(type));\n        }\n        // FIXME\n      //case Type::TypeClass::ClassTemplateSpecializationClass:\n        //{\n          //return translate_class_tmpl_spec(static_cast<const TemplateSpecialization*>(type));\n        //}\n      default:\n        break;\n    }\n    return std::string(\"TODO_type_\") + type->getTypeClassName();\n    //if (type->isTypedef()) {\n    //}\n    //std::cout << \"Record type: \" << type->isRecordType() << \"\\n\";\n    //return type->getTypeClassName();\n  }\n\n  std::string translate_type(const Type* type) {\n    switch (type->getTypeClass()) {\n      case Type::TypeClass::Typedef:\n        {\n        const TypedefType* tt = static_cast<const TypedefType*>(type);\n        return tt->getDecl()->getNameAsString();\n        break;\n        }\n      case Type::TypeClass::Builtin:\n        {\n          return translate_builtin_type(static_cast<const BuiltinType*>(type));\n          break;\n        }\n      case Type::TypeClass::Record:\n        {\n          return translate_record_type(static_cast<const RecordType*>(type));\n          break;\n        }\n      case Type::TypeClass::Elaborated:\n        {\n          return translate_elaborated_type(static_cast<const ElaboratedType*>(type));\n        }\n        // FIXME\n      //case Type::TypeClass::ClassTemplateSpecializationClass:\n        //{\n          //return translate_class_tmpl_spec(static_cast<const TemplateSpecialization*>(type));\n        //}\n      default:\n        break;\n    }\n    return std::string(\"TODO_type_\") + type->getTypeClassName();\n    //if (type->isTypedef()) {\n    //}\n    //std::cout << \"Record type: \" << type->isRecordType() << \"\\n\";\n    //return type->getTypeClassName();\n  }\n\n  std::unique_ptr<armada::stmt_nd> translate_decl_statement(const DeclStmt* declStmt) {\n    if (declStmt->isSingleDecl()) {\n      const Decl *decl = declStmt->getSingleDecl();\n\n      if (decl->getDeclKindName() == std::string(\"Var\")) {\n        const VarDecl *varDecl = static_cast<const VarDecl*>(decl);\n        const Type* type = varDecl->getTypeSourceInfo()->getType().getTypePtr();\n        if (type->getTypeClass() == Type::TypeClass::LValueReference) {\n          const Type* pointeeType = static_cast<const LValueReferenceType*>(type)->getPointeeType().getTypePtr();\n          std::string armadaVarName = varDecl->getNameAsString() + \"_ptr\";\n          std::string typeName = std::string(\"ptr<\") + translate_type(pointeeType) + std::string(\">\");\n          // auto ret = std::make_unique<armada::update_nd>();\n          vardecls.push_back(std::make_unique<armada::vardecl_nd>(armadaVarName, typeName));\n          if (varDecl->getInit() == nullptr)\n            return nullptr;\n          if (varDecl->getInit()->getStmtClass() == Stmt::StmtClass::CallExprClass ||\n              varDecl->getInit()->getStmtClass() == Stmt::StmtClass::CXXMemberCallExprClass) {\n            return translate_call_statement_lhs(armadaVarName, static_cast<const CallExpr*>(varDecl->getInit()));\n          } else {\n            auto ret = std::make_unique<armada::update_nd>();\n            auto lhs = std::make_unique<armada::literal_nd>();\n            lhs->literal = armadaVarName;\n            ret->lhs = std::move(lhs);\n            ret->rhs = make_addrof_expr(translate_expr(varDecl->getInit()));\n            return ret;\n          }\n          return nullptr;\n        }\n\n        std::string armadaVarName = varDecl->getNameAsString();\n        vardecls.push_back(std::make_unique<armada::vardecl_nd>(armadaVarName, translate_type(varDecl->getTypeSourceInfo()->getType().getTypePtr())));\n        if (varDecl->getInit() == nullptr)\n          return nullptr;\n        if (varDecl->getInit()->getStmtClass() == Stmt::StmtClass::CallExprClass ||\n            varDecl->getInit()->getStmtClass() == Stmt::StmtClass::CXXMemberCallExprClass) {\n          return translate_call_statement_lhs(armadaVarName, static_cast<const CallExpr*>(varDecl->getInit()));\n        } else {\n          auto ret = std::make_unique<armada::update_nd>();\n          auto lhs = std::make_unique<armada::literal_nd>();\n          lhs->literal = armadaVarName;\n          ret->lhs = std::move(lhs);\n          ret->rhs = translate_expr(varDecl->getInit());\n          return ret;\n        }\n        // std::cout << prefix << \"var \" << varDecl->getNameAsString() << \":\" << varDecl->getTypeSourceInfo()->getType()->getTypeClassName() << \";\\n\";\n      }\n      std::cout << \"VARDECL \" << decl->getDeclKindName() << \"\\n\";\n    }\n    vardecls.push_back(nullptr);\n    return nullptr;\n  }\n\n  void init_call_stmt_rhs(std::unique_ptr<armada::call_stmt_nd> &call_stmt, const CallExpr* callExpr) {\n    translate_expr_for_callee(call_stmt, callExpr->getCallee());\n    add_args_to_call(call_stmt, callExpr);\n  }\n\n  void add_args_to_call(std::unique_ptr<armada::call_stmt_nd> &call_stmt, const CallExpr* callExpr) {\n    unsigned int n = callExpr->getNumArgs();\n    for (unsigned int i = 0; i < n; ++i) {\n      call_stmt->args.push_back(translate_expr(callExpr->getArg(i)));\n    }\n  }\n\n  std::unique_ptr<armada::expr_nd> translate_call_expr(const CallExpr* callExpr) {\n    auto call_stmt = std::make_unique<armada::call_stmt_nd>();\n    init_call_stmt_rhs(call_stmt, callExpr);\n\n    call_stmt->lhs = std::string(\"temp\") + std::to_string(num_temps++);\n    std::string temp_typename = \"TODO_return_type\";\n    /*\n    const FunctionDecl* fdecl = callExpr->getDirectCallee();\n    if (fdecl != nullptr) {\n      temp_typename = \"TODO_fdecl_found\";\n      if (!fdecl->getReturnType().isNull()) {\n        temp_typename = translate_type(fdecl->getReturnType().getTypePtr());\n      }\n    }\n    */\n\n    /*\n    if (!callExpr->getCallReturnType(*Context).isNull()) {\n      std::cout << \"Done!\\n\";\n      temp_typename = \"TODO_null_getTypePtr\";\n      if (callExpr->getCallReturnType(*Context).getTypePtr() != nullptr) {\n        temp_typename = translate_type(callExpr->getCallReturnType(*Context).getTypePtr());\n      }\n    }\n    */\n\n    vardecls.push_back(std::make_unique<armada::vardecl_nd>(call_stmt->lhs, temp_typename));\n\n    auto ret = std::make_unique<armada::literal_nd>();\n    ret->literal = call_stmt->lhs;\n\n    block_ctx->push_back(std::move(call_stmt));\n    \n    return ret;\n  }\n\n  std::unique_ptr<armada::expr_nd> translate_bool_literal(const CXXBoolLiteralExpr* expr)\n  {\n    auto ret = std::make_unique<armada::literal_nd>();\n    if (expr->getValue()) {\n      ret->literal = \"true\";\n    } else {\n      ret->literal = \"false\";\n    }\n    return ret;\n  }\n\n  std::unique_ptr<armada::expr_nd> translate_binary_op(const BinaryOperator* bo) {\n    auto ret = std::make_unique<armada::binary_op_nd>();\n    ret->lhs = translate_expr(bo->getLHS());\n    ret->rhs = translate_expr(bo->getRHS());\n    ret->op = bo->getOpcodeStr().str();\n    return ret;\n  }\n\n  std::unique_ptr<armada::expr_nd> translate_unary_op(const UnaryOperator* uo) {\n    auto ret = std::make_unique<armada::unary_op_nd>();\n    ret->e = translate_expr(uo->getSubExpr());\n    ret->op = uo->getOpcodeStr(uo->getOpcode()).str();\n    ret->is_prefix = !(uo->isPostfix());\n    return ret;\n  }\n\n  std::unique_ptr<armada::call_stmt_nd> translate_call_statement_lhs(std::string lhs, const CallExpr *callExpr) {\n    auto call_stmt = std::make_unique<armada::call_stmt_nd>();\n\n    init_call_stmt_rhs(call_stmt, callExpr);\n    call_stmt->lhs = lhs;\n    return call_stmt;\n  }\n\n  std::unique_ptr<armada::call_stmt_nd> translate_call_statement(const Expr *lhs, const CallExpr *callExpr) {\n    return translate_call_statement_lhs(translate_expr(lhs)->print(), callExpr);\n  }\n\n  std::unique_ptr<armada::stmt_nd> translate_assignment_statement(const BinaryOperator* bo) {\n    auto ret = std::make_unique<armada::update_nd>();\n    if (bo->getRHS()->getStmtClass() == Stmt::StmtClass::CallExprClass) {\n      return translate_call_statement(bo->getLHS(), static_cast<const CallExpr*>(bo->getRHS()));\n    }\n    ret->lhs = translate_expr(bo->getLHS());\n    ret->rhs = translate_expr(bo->getRHS());\n    return ret;\n  }\n\n  std::unique_ptr<armada::expr_nd> make_addrof_expr(std::unique_ptr<armada::expr_nd> e) {\n    if (armada::deref_nd* d = dynamic_cast<armada::deref_nd*>(e.get())) {\n      return std::move(d->subexpr);\n    }\n    auto ret = std::make_unique<armada::addrof_nd>();\n    ret->subexpr = std::move(e);\n    return ret;\n  }\n\n  std::unique_ptr<armada::expr_nd> make_deref_expr(std::unique_ptr<armada::expr_nd> e) {\n    if (armada::addrof_nd* a = dynamic_cast<armada::addrof_nd*>(e.get())) {\n      return std::move(a->subexpr);\n    }\n    auto ret = std::make_unique<armada::deref_nd>();\n    ret->subexpr = std::move(e);\n    return ret;\n  }\n\n  std::unique_ptr<armada::expr_nd> translate_declrefexpr(const DeclRefExpr* declref)\n  {\n    auto ret = std::make_unique<armada::literal_nd>();\n    ret->literal = declref->getDecl()->getNameAsString();\n\n    const Type* type = declref->getDecl()->getType().getTypePtr();\n    if (type->getTypeClass() == Type::TypeClass::LValueReference) {\n      ret->literal = ret->literal + \"_ptr\";\n      return make_deref_expr(std::move(ret));\n    }\n    return ret;\n  }\n\n  std::unique_ptr<armada::expr_nd> translate_implicitcastexpr(const ImplicitCastExpr* expr)\n  {\n    return translate_expr(expr->getSubExpr());\n  }\n\n  template <typename StmtType>\n  void translate_member_expr_for_callee(std::unique_ptr<armada::call_stmt_nd> &c, DeclarationName memberName, const StmtType* member_expr)\n  {\n    if (member_expr->isImplicitAccess()) {\n      auto l = std::make_unique<armada::literal_nd>();\n      l->literal = memberName.getAsString();\n      if (class_ctx.length() > 0) {\n        l->literal = class_ctx + \"_\" + l->literal;\n      }\n      c->f = std::move(l);\n      auto this_nd = std::make_unique<armada::literal_nd>();\n      this_nd->literal = \"this\";\n      c->args.push_back(std::move(this_nd));\n    }\n    else {\n      const Expr* base =  member_expr->getBase();\n\n      auto l = std::make_unique<armada::literal_nd>();\n      l->literal = translate_type_concrete(base->getType().getTypePtr()) + \"_\" + memberName.getAsString();\n      c->f = std::move(l);\n\n      c->args.push_back(make_addrof_expr(translate_expr(base)));\n    }\n  }\n\n  void translate_expr_for_callee(std::unique_ptr<armada::call_stmt_nd> &c, const Expr* expr) {\n    switch (expr->getStmtClass()) {\n      case Stmt::CXXDependentScopeMemberExprClass: {\n        // return translate_dep_member_expr(static_cast<const CXXDependentScopeMemberExpr*>(expr));\n        auto dme = static_cast<const CXXDependentScopeMemberExpr*>(expr);\n        translate_member_expr_for_callee(c, dme->getMember(), dme);\n        return;\n      }\n      case Stmt::UnresolvedMemberExprClass: {\n        // return translate_member_expr(static_cast<const UnresolvedMemberExpr*>(expr));\n        auto ume = static_cast<const UnresolvedMemberExpr*>(expr);\n        translate_member_expr_for_callee(c, ume->getMemberName(), ume);\n        return;\n      }\n      case Stmt::MemberExprClass: {\n        auto me = static_cast<const MemberExpr*>(expr);\n        return translate_member_expr_for_callee(c, me->getMemberDecl()->getDeclName(), me);\n      }\n      default:\n        c->f = translate_expr(expr);\n        return;\n    }\n  }\n\n  template <typename StmtType>\n  std::unique_ptr<armada::expr_nd> translate_member_expr(const StmtType* member_expr, DeclarationName name)\n  {\n    auto ret = std::make_unique<armada::literal_nd>();\n    if (!member_expr->isImplicitAccess()) {\n      ret->literal = translate_expr(member_expr->getBase())->print() + \".\" + name.getAsString();\n    } else {\n      ret->literal = \"(*this).\" + name.getAsString();\n    }\n    return ret;\n  }\n\n  std::string make_temp(const Type* type) {\n    std::string new_name = std::string(\"temp\") + std::to_string(num_temps++);\n    vardecls.push_back(std::make_unique<armada::vardecl_nd>(new_name, translate_type(type)));\n    return new_name;\n  }\n\n  std::unique_ptr<armada::expr_nd> translate_init_list_expr(const InitListExpr* expr) {\n    if (expr->getType().getTypePtr()->getTypeClass() == Type::TypeClass::Record)\n    {\n      return translate_init_list_expr_record(expr, static_cast<const RecordType*>(expr->getType().getTypePtr()));\n    }\n    auto ret = std::make_unique<armada::todo_expr_nd>();\n    ret->todo = \"InitListExpression_nonRecord\";\n    return ret;\n  }\n\n  std::unique_ptr<armada::expr_nd> translate_cxx_unresolved_construct_expr(const CXXUnresolvedConstructExpr* expr) {\n    if (expr->getTypeAsWritten().getTypePtr()->getTypeClass() == Type::TypeClass::Record\n        && expr->isListInitialization())\n    {\n      return translate_cxx_unresolved_construct_expr_record(expr, static_cast<const RecordType*>(expr->getTypeAsWritten().getTypePtr()));\n    }\n    auto ret = std::make_unique<armada::todo_expr_nd>();\n    ret->todo = \"ConstructExpression_nonRecord_List\";\n    return ret;\n  }\n\n  std::unique_ptr<armada::expr_nd> translate_cxx_construct_expr(const CXXConstructExpr* expr) {\n    if (expr->getType().getTypePtr()->getTypeClass() == Type::TypeClass::Record\n        && expr->isListInitialization())\n    {\n      return translate_cxx_construct_expr_record(expr, static_cast<const RecordType*>(expr->getType().getTypePtr()));\n    }\n    auto ret = std::make_unique<armada::todo_expr_nd>();\n    ret->todo = \"ConstructExpression_nonRecord_List\";\n    return ret;\n  }\n\n  std::unique_ptr<armada::expr_nd> translate_init_list_expr_record(const InitListExpr* inits, const RecordType *rt) {\n    const RecordDecl *rd = rt->getDecl();\n    std::string tempRecordName = make_temp(rt);\n    int i = 0;\n    for (auto curr = rd->field_begin(); curr != rd->field_end(); curr++) {\n      std::string currFieldName = curr->getNameAsString();\n\n      auto field_update = std::make_unique<armada::update_nd>();\n      auto lhs = std::make_unique<armada::literal_nd>();\n      lhs->literal = tempRecordName + \".\" + currFieldName;\n      field_update->lhs = std::move(lhs);\n\n      field_update->rhs = translate_expr(inits->getInit(i));\n\n      block_ctx->push_back(std::move(field_update));\n      i++;\n      if (i >= inits->getNumInits()) break;\n    }\n    auto ret = std::make_unique<armada::literal_nd>();\n    ret->literal = tempRecordName;\n    return ret;\n  }\n\n  std::unique_ptr<armada::expr_nd> translate_cxx_construct_expr_record(const CXXConstructExpr* expr, const RecordType *rt) {\n    auto inits = static_cast<const InitListExpr*>(expr->getArg(0));\n    return translate_init_list_expr_record(inits, rt);\n  }\n\n  std::unique_ptr<armada::expr_nd> translate_cxx_unresolved_construct_expr_record(const CXXUnresolvedConstructExpr* expr, const RecordType *rt) {\n    auto inits = static_cast<const InitListExpr*>(expr->getArg(0));\n    return translate_init_list_expr_record(inits, rt);\n  }\n\n  std::unique_ptr<armada::expr_nd> translate_array_subscript(const ArraySubscriptExpr* subscript_expr) {\n    auto ret = std::make_unique<armada::array_subscript_nd>();\n    ret->base = translate_expr(subscript_expr->getIdx());\n    ret->idx = translate_expr(subscript_expr->getBase());\n    return ret;\n  }\n\n  std::unique_ptr<armada::expr_nd> translate_paren_expr(const ParenExpr* paren_expr) {\n    auto ret = std::make_unique<armada::paren_nd>();\n    ret->sub_expr = translate_expr(paren_expr->getSubExpr());\n    return ret;\n  }\n\n  std::unique_ptr<armada::expr_nd> translate_expr(const Expr* expr) {\n    switch (expr->getStmtClass()) {\n      case Stmt::IntegerLiteralClass: {\n        auto ret = std::make_unique<armada::literal_nd>();\n        ret->literal = static_cast<const IntegerLiteral*>(expr)->getValue().toString(10, true);\n        return ret;\n        break;\n      }\n      case Stmt::CXXBoolLiteralExprClass: {\n        return translate_bool_literal(static_cast<const CXXBoolLiteralExpr*>(expr));\n        break;\n      }\n      case Stmt::BinaryOperatorClass: {\n        const BinaryOperator *bo = static_cast<const BinaryOperator*>(expr);\n        if (bo->isAssignmentOp()) {\n          return nullptr;\n        }\n        return translate_binary_op(bo);\n      }\n      case Stmt::UnaryOperatorClass: {\n        const UnaryOperator *uo = static_cast<const UnaryOperator*>(expr);\n        return translate_unary_op(uo);\n      }\n      case Stmt::DeclRefExprClass: {\n        return translate_declrefexpr(static_cast<const DeclRefExpr*>(expr));\n      }\n      case Stmt::ImplicitCastExprClass: {\n        return translate_implicitcastexpr(static_cast<const ImplicitCastExpr*>(expr));\n      }\n      case Stmt::CXXMemberCallExprClass:\n      case Stmt::CallExprClass: {\n        return translate_call_expr(static_cast<const CallExpr*>(expr));\n      }\n      case Stmt::CXXDependentScopeMemberExprClass: {\n        auto e = static_cast<const CXXDependentScopeMemberExpr*>(expr);\n        return translate_member_expr(e, e->getMember());\n      }\n      case Stmt::MemberExprClass: {\n        auto e = static_cast<const MemberExpr*>(expr);\n        return translate_member_expr(e, e->getMemberDecl()->getDeclName());\n      }\n      case Stmt::UnresolvedMemberExprClass: {\n        auto e = static_cast<const UnresolvedMemberExpr*>(expr);\n        return translate_member_expr(e, e->getMemberName());\n      }\n      case Stmt::CXXUnresolvedConstructExprClass: {\n        return translate_cxx_unresolved_construct_expr(static_cast<const CXXUnresolvedConstructExpr*>(expr));\n      }\n      case Stmt::CXXConstructExprClass: {\n        return translate_cxx_construct_expr(static_cast<const CXXConstructExpr*>(expr));\n      }\n      case Stmt::InitListExprClass: {\n        return translate_init_list_expr(static_cast<const InitListExpr*>(expr));\n      }\n      case Stmt::ArraySubscriptExprClass: {\n        return translate_array_subscript(static_cast<const ArraySubscriptExpr*>(expr));\n      }\n      case Stmt::ParenExprClass: {\n        return translate_paren_expr(static_cast<const ParenExpr*>(expr));\n      }\n      case Stmt::ExprWithCleanupsClass: {\n        return translate_expr(static_cast<const ExprWithCleanups*>(expr)->getSubExpr());\n      }\n      default:\n        break;\n    }\n\n    auto ret = std::make_unique<armada::todo_expr_nd>();\n    if (!expr->getType().isNull())  {\n      ret->todo = expr->getStmtClassName() + std::string(\":\") + translate_type(expr->getType().getTypePtr());\n    } else {\n      ret->todo = std::string(expr->getStmtClassName()) + \":unknown type\";\n    }\n    return ret;\n  }\n\n  std::unique_ptr<armada::if_nd> translate_if_statement(const IfStmt* ifStmt) {\n    auto i = std::make_unique<armada::if_nd>();\n    i->cond = translate_expr(ifStmt->getCond());\n    i->t = translate_statement(ifStmt->getThen());\n    i->f = translate_statement(ifStmt->getElse());\n    return std::move(i);\n  }\n\n  std::unique_ptr<armada::return_nd> translate_return_statement(const ReturnStmt* return_stmt) {\n    auto ret = std::make_unique<armada::return_nd>();\n    ret->ret = nullptr;\n    if (return_stmt->getRetValue() != nullptr) {\n      ret->ret = translate_expr(return_stmt->getRetValue());\n    }\n    return ret;\n  }\n\n  std::unique_ptr<armada::while_stmt_nd> translate_while_statement(const WhileStmt *stmt) {\n    auto ret = std::make_unique<armada::while_stmt_nd>();\n    ret->cond = translate_expr(stmt->getCond());\n    const Stmt *body = stmt->getBody();\n    if (body->getStmtClass() == Stmt::CompoundStmtClass) {\n      ret->body = translate_compound_statement(static_cast<const CompoundStmt*>(stmt->getBody()));\n    } else {\n      ret->body = std::make_unique<armada::block_nd>();\n      ret->body->stmts.push_back(translate_statement(stmt->getBody()));\n    }\n    return ret;\n  }\n\n  std::unique_ptr<armada::while_stmt_nd> translate_for_statement(const ForStmt *stmt) {\n    auto ret = std::make_unique<armada::while_stmt_nd>();\n\n    ret->cond = translate_expr(stmt->getCond());\n    block_ctx->push_back(translate_statement(stmt->getInit()));\n\n    const Stmt *body = stmt->getBody();\n    if (body != nullptr) {\n      if (body->getStmtClass() == Stmt::CompoundStmtClass) {\n        ret->body = translate_compound_statement(static_cast<const CompoundStmt*>(stmt->getBody()));\n        if (stmt->getInc() != nullptr)\n          ret->body->stmts.push_back(translate_statement(stmt->getInc()));\n      } else {\n        ret->body = std::make_unique<armada::block_nd>();\n        ret->body->stmts.push_back(translate_statement(stmt->getBody()));\n        if (stmt->getInc() != nullptr)\n          ret->body->stmts.push_back(translate_statement(stmt->getInc()));\n      }\n    } else {\n      ret->body = nullptr;\n    }\n    return ret;\n  }\n\n  std::unique_ptr<armada::stmt_nd> make_stmt_expr(std::unique_ptr<armada::expr_nd> expr) {\n    auto ret = std::make_unique<armada::stmt_expr_nd>();\n    ret->e = std::move(expr);\n    return ret;\n  }\n\n  std::unique_ptr<armada::stmt_nd> translate_no_lhs_call(const CallExpr *callExpr) {\n    auto ret = std::make_unique<armada::call_stmt_nd>();\n    init_call_stmt_rhs(ret, callExpr);\n    ret->lhs = \"\";\n    return ret;\n  }\n\n  std::unique_ptr<armada::stmt_nd> translate_statement(const Stmt* stmt) {\n    if (stmt == nullptr) {\n      return nullptr;\n    }\n    switch (stmt->getStmtClass())\n    {\n      case Stmt::DeclStmtClass: {\n        const DeclStmt *declStmt = static_cast<const DeclStmt*>(stmt);\n        auto s = translate_decl_statement(declStmt);\n        return s;\n        break;\n      }\n      case Stmt::CompoundStmtClass: {\n        return translate_compound_statement(static_cast<const CompoundStmt*>(stmt));\n        break;\n      }\n      case Stmt::IfStmtClass: {\n        return translate_if_statement(static_cast<const IfStmt*>(stmt));\n        break;\n      }\n      case Stmt::ReturnStmtClass: {\n        return translate_return_statement(static_cast<const ReturnStmt*>(stmt));\n        break;\n      }\n      case Stmt::BinaryOperatorClass: {\n        const BinaryOperator *bo = static_cast<const BinaryOperator*>(stmt);\n        if (bo->isAssignmentOp()) {\n          return translate_assignment_statement(bo);\n        }\n      }\n      case Stmt::WhileStmtClass: {\n        return translate_while_statement(static_cast<const WhileStmt*>(stmt));\n      }\n      case Stmt::ForStmtClass: {\n        return translate_for_statement(static_cast<const ForStmt*>(stmt));\n      }\n      case Stmt::CallExprClass: {\n        return translate_no_lhs_call(static_cast<const CallExpr*>(stmt));\n      }\n      case Stmt::CXXMemberCallExprClass: {\n        return translate_no_lhs_call(static_cast<const CallExpr*>(stmt));\n      }\n      case Stmt::UnaryOperatorClass: {\n        return make_stmt_expr(translate_expr(static_cast<const Expr*>(stmt)));\n      }\n      default: {\n        break;\n      }\n    }\n\n    auto ret = std::make_unique<armada::todo_stmt_nd>();\n    ret->todo = stmt->getStmtClassName();\n    return ret;\n  }\n\n  std::unique_ptr<armada::block_nd> translate_compound_statement(const CompoundStmt* compoundStmt) {\n    auto ret = std::make_unique<armada::block_nd>();\n    CompoundStmt::const_body_iterator curr = compoundStmt->body_begin();\n    CompoundStmt::const_body_iterator end = compoundStmt->body_end();\n    while (curr != end) {\n      block_ctx = &(ret->stmts);\n      const Stmt* stmt = *curr;\n      auto s = translate_statement(*curr);\n      if (s != nullptr) {\n        ret->stmts.push_back(std::move(s));\n      }\n      curr++;\n    }\n    return ret;\n  }\n\n  std::unique_ptr<armada::method_nd> translate_method_decl(CXXMethodDecl *decl) {\n    FullSourceLoc FullLocation = Context->getFullLoc(decl->getBeginLoc());\n    if (FullLocation.isValid()) {\n      std::cout << \"\\n\\n// Found declaration of `\" << decl->getQualifiedNameAsString() << \"' at \"\n          << FullLocation.getSpellingLineNumber() << \":\"\n          << FullLocation.getSpellingColumnNumber() << \"\\n\";\n    }\n\n    class_ctx = \"\";\n    num_temps = 0;\n    std::string armadaMethodName = decl->getNameAsString();\n    CXXRecordDecl* parent = decl->getParent();\n    if (parent) {\n      class_ctx = parent->getNameAsString();\n      armadaMethodName = class_ctx + \"_\" + armadaMethodName;\n    }\n\n    vardecls.clear();\n    std::unique_ptr<armada::method_nd> m = std::make_unique<armada::method_nd>();\n    m->name = armadaMethodName;\n    m->params = nullptr;\n\n    clang::Stmt *methodBody = decl->getBody();\n    if (methodBody == nullptr) {\n      m->block = nullptr;\n    } else {\n      m->block = std::make_unique<armada::method_block_nd>();\n      m->block->stmts = std::move(translate_compound_statement(static_cast<CompoundStmt*>(methodBody))->stmts);\n      m->block->vardecls = std::move(vardecls);\n    }\n    return m;\n  }\n\npublic:\n  explicit FindNamedClassVisitor(ASTContext *Context)\n    : Context(Context) {}\n\n  bool VisitCXXMethodDecl(CXXMethodDecl *decl) {\n    auto m = translate_method_decl(decl);\n    std::cout << m->print();\n    return true;\n  }\n\nprivate:\n  ASTContext *Context;\n};\n\nclass FindNamedClassConsumer : public clang::ASTConsumer {\npublic:\n  explicit FindNamedClassConsumer(clang::SourceManager &SM, ASTContext *Context)\n    : sourceManager(SM), Visitor(Context) {}\n\n  virtual void HandleTranslationUnit(clang::ASTContext &Context) {\n    auto Decls = Context.getTranslationUnitDecl()->decls();\n    for (auto &Decl : Decls) {\n      const auto& FileID = sourceManager.getFileID(Decl->getLocation());\n      if (FileID != sourceManager.getMainFileID())\n        continue;\n      Visitor.TraverseDecl(Decl);\n    }\n  }\nprivate:\n  clang::SourceManager &sourceManager;\n  FindNamedClassVisitor Visitor;\n};\n\nclass FindNamedClassAction : public clang::ASTFrontendAction {\npublic:\n  virtual std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(\n    clang::CompilerInstance &Compiler, llvm::StringRef InFile) {\n    return std::unique_ptr<clang::ASTConsumer>(\n        new FindNamedClassConsumer(Compiler.getSourceManager(), &Compiler.getASTContext()));\n  }\n};\n\nint main(int argc, char **argv) {\n  std::ios::sync_with_stdio(true);\n  if (argc > 1) {\n    std::ifstream t(argv[1]);\n    std::string source((std::istreambuf_iterator<char>(t)),\n                     std::istreambuf_iterator<char>());\n    clang::tooling::runToolOnCode(new FindNamedClassAction(), source);\n  }\n}\n"
  },
  {
    "path": "experimental/Tests/libcuckoo/cpp/cuckoohash_config.hh",
    "content": "/** \\file */\n\n#ifndef _CUCKOOHASH_CONFIG_HH\n#define _CUCKOOHASH_CONFIG_HH\n\n#include <cstddef>\n#include <limits>\n\n//! The default maximum number of keys per bucket\nconstexpr size_t SLOT_PER_BUCKET = 4;\n    //#define SLOT_PER_BUCKET 4\n\n//! The default number of elements in an empty hash table\nconstexpr size_t LIBCUCKOO_DEFAULT_SIZE =\n    (1U << 16) * SLOT_PER_BUCKET;\n\n//! The default minimum load factor that the table allows for automatic\n//! expansion. It must be a number between 0.0 and 1.0. The table will throw\n//! libcuckoo_load_factor_too_low if the load factor falls below this value\n//! during an automatic expansion.\nconstexpr double LIBCUCKOO_DEFAULT_MINIMUM_LOAD_FACTOR = 0.05;\n\n//! An alias for the value that sets no limit on the maximum hashpower. If this\n//! value is set as the maximum hashpower limit, there will be no limit. This\n//! is also the default initial value for the maximum hashpower in a table.\nconstexpr size_t LIBCUCKOO_NO_MAXIMUM_HASHPOWER =\n    std::numeric_limits<size_t>::max();\n\n//! set LIBCUCKOO_DEBUG to 1 to enable debug output\n#define LIBCUCKOO_DEBUG 0\n\n#define KEY uint64_t\n#define VALUE uint64_t\n\n\n#endif // _CUCKOOHASH_CONFIG_HH\n"
  },
  {
    "path": "experimental/Tests/libcuckoo/cpp/cuckoohash_map.hh",
    "content": "/** \\file */\n\n#ifndef _CUCKOOHASH_MAP_HH\n#define _CUCKOOHASH_MAP_HH\n\nstruct VALUE {\n};\n\nstruct KEY {\n};\n\n#include <algorithm>\n#include <array>\n#include <atomic>\n#include <bitset>\n#include <cassert>\n#include <cstdint>\n#include <cstdlib>\n#include <functional>\n#include <iostream>\n#include <iterator>\n#include <limits>\n#include <list>\n#include <memory>\n#include <mutex>\n#include <stdexcept>\n#include <thread>\n#include <type_traits>\n#include <utility>\n#include <vector>\n\n#include \"cuckoohash_config.hh\"\n#include \"cuckoohash_util.hh\"\n#include \"libcuckoo_bucket_container.hh\"\n\n// A constexpr version of pow that we can use for various compile-time\n// constants and checks.\nstatic constexpr std::size_t const_pow(std::size_t a, std::size_t b) {\n  return (b == 0) ? 1 : a * const_pow(a, b - 1);\n}\n\n// Type of the partial key\ntypedef uint8_t partial_t;\n\n// The type of the buckets container\ntypedef libcuckoo_bucket_container buckets_t;\n\ntypedef std::hash<KEY> Hash;\ntypedef std::equal_to<KEY> KeyEqual;\ntypedef std::ptrdiff_t difference_type;\ntypedef Hash hasher;\ntypedef KeyEqual key_equal;\n\n// Counter type\ntypedef int64_t counter_type;\n\n// A fast, lightweight spinlock\nLIBCUCKOO_SQUELCH_PADDING_WARNING\nclass LIBCUCKOO_ALIGNAS(64) spinlock {\npublic:\n  spinlock() : elem_counter_(0) { lock_.clear(); }\n\n  spinlock(const spinlock &other) : elem_counter_(other.elem_counter()) {\n    lock_.clear();\n  }\n\n  spinlock &operator=(const spinlock &other) {\n    elem_counter() = other.elem_counter();\n    return *this;\n  }\n\n  void lock() noexcept {\n    while (lock_.test_and_set(std::memory_order_acq_rel))\n      ;\n  }\n\n  void unlock() noexcept { lock_.clear(std::memory_order_release); }\n\n  bool try_lock() noexcept {\n    return !lock_.test_and_set(std::memory_order_acq_rel);\n  }\n\n  counter_type &elem_counter() noexcept { return elem_counter_; }\n\n  counter_type elem_counter() const noexcept { return elem_counter_; }\n\nprivate:\n  std::atomic_flag lock_;\n  counter_type elem_counter_;\n};\n\ntypedef std::vector<spinlock> locks_t;\n\nstruct all_locks_list_node {\n  all_locks_list_node(size_t lock_count) : elt(lock_count), next(nullptr) { }\n\n  locks_t elt;\n  all_locks_list_node *next;\n};\n\nclass all_locks_t {\npublic:\n  all_locks_t(size_t lock_count) {\n    tail_ = new all_locks_list_node(lock_count);\n    head_ = tail_;\n  }\n\n  void append(all_locks_list_node *new_tail) {\n    tail_->next = new_tail;\n    tail_ = new_tail;\n  }\n\n  all_locks_list_node *get_tail() {\n    return tail_;\n  }\n\nprivate:\n  all_locks_list_node *head_;\n  all_locks_list_node *tail_;\n};\n\n// Classes for managing locked buckets. By storing and moving around sets of\n// locked buckets in these classes, we can ensure that they are unlocked\n// properly.\n\nclass LockManager {\npublic:\n  LockManager() : lock(nullptr) { }\n  LockManager(spinlock *i_lock) : lock(i_lock) { }\n\n  LockManager(const LockManager& other) : lock(nullptr) {\n    std::swap(lock, other.lock);\n  }\n\n  LockManager& operator=(const LockManager& other) {\n    std::swap(lock, other.lock);\n    return *this;\n  }\n  \n  ~LockManager() {\n    if (lock != nullptr) {\n      lock->unlock();\n    }\n  }\n\n  void reset() {\n    if (lock != nullptr) {\n      lock->unlock();\n      lock = nullptr;\n    }\n  }\n\n  void swap(const LockManager& other) {\n    std::swap(lock, other.lock);\n  }\n\nprivate:\n  mutable spinlock *lock;\n};\n\nstatic constexpr size_type kMaxNumLocks = 1UL << 16;\n\n// lock_ind converts an index into buckets to an index into locks.\nstatic inline size_type lock_ind(const size_type bucket_ind) {\n  return bucket_ind & (kMaxNumLocks - 1);\n}\n\nclass TwoBuckets {\npublic:\n  TwoBuckets() {}\n  TwoBuckets(locks_t &locks, size_type i1_, size_type i2_)\n      : i1(i1_), i2(i2_), first_manager_(&locks[lock_ind(i1)]),\n        second_manager_((lock_ind(i1) != lock_ind(i2)) ? &locks[lock_ind(i2)]\n                                                       : nullptr) {}\n  TwoBuckets(const TwoBuckets& other)\n    : i1(other.i1), i2(other.i2) {\n    first_manager_.swap(other.first_manager_);\n    second_manager_.swap(other.second_manager_);\n  }\n\n  TwoBuckets& operator=(const TwoBuckets& other) {\n    i1 = other.i1;\n    i2 = other.i2;\n    first_manager_.swap(other.first_manager_);\n    second_manager_.swap(other.second_manager_);\n    return *this;\n  }\n\n  void unlock() {\n    first_manager_.reset();\n    second_manager_.reset();\n  }\n\n  size_type i1, i2;\n\nprivate:\n  LockManager first_manager_, second_manager_;\n};\n\n// The maximum number of items in a cuckoo BFS path. It determines the\n// maximum number of slots we search when cuckooing.\nstatic constexpr uint8_t MAX_BFS_PATH_LEN = 5;\n\n// b_slot holds the information for a BFS path through the table.\nstruct b_slot {\n  // The bucket of the last item in the path.\n  size_type bucket;\n  // a compressed representation of the slots for each of the buckets in\n  // the path. pathcode is sort of like a base-slot_per_bucket number, and\n  // we need to hold at most MAX_BFS_PATH_LEN slots. Thus we need the\n  // maximum pathcode to be at least SLOT_PER_BUCKET^(MAX_BFS_PATH_LEN).\n  uint16_t pathcode;\n  static_assert(const_pow(SLOT_PER_BUCKET, MAX_BFS_PATH_LEN) <\n                    std::numeric_limits<decltype(pathcode)>::max(),\n                \"pathcode may not be large enough to encode a cuckoo \"\n                \"path\");\n  // The 0-indexed position in the cuckoo path this slot occupies. It must\n  // be less than MAX_BFS_PATH_LEN, and also able to hold negative values.\n  int8_t depth;\n  static_assert(MAX_BFS_PATH_LEN - 1 <=\n                    std::numeric_limits<decltype(depth)>::max(),\n                \"The depth type must able to hold a value of\"\n                \" MAX_BFS_PATH_LEN - 1\");\n  static_assert(-1 >= std::numeric_limits<decltype(depth)>::min(),\n                \"The depth type must be able to hold a value of -1\");\n  b_slot() {}\n  b_slot(const size_type b, const uint16_t p, const decltype(depth) d)\n      : bucket(b), pathcode(p), depth(d) {\n    assert(d < MAX_BFS_PATH_LEN);\n  }\n};\n\n// b_queue is the queue used to store b_slots for BFS cuckoo hashing.\nclass b_queue {\npublic:\n  b_queue() noexcept : first_(0), last_(0) {}\n\n  void enqueue(b_slot x) {\n    assert(!full());\n    slots_[last_++] = x;\n  }\n\n  b_slot dequeue() {\n    assert(!empty());\n    assert(first_ < last_);\n    b_slot &x = slots_[first_++];\n    return x;\n  }\n\n  bool empty() const { return first_ == last_; }\n\n  bool full() const { return last_ == MAX_CUCKOO_COUNT; }\n\nprivate:\n  // The size of the BFS queue. It holds just enough elements to fulfill a\n  // MAX_BFS_PATH_LEN search for two starting buckets, with no circular\n  // wrapping-around. For one bucket, this is the geometric sum\n  // sum_{k=0}^{MAX_BFS_PATH_LEN-1} SLOT_PER_BUCKET^k\n  // = (1 - SLOT_PER_BUCKET^MAX_BFS_PATH_LEN) / (1 - SLOT_PER_BUCKET)\n  //\n  // Note that if SLOT_PER_BUCKET == 1, then this simply equals\n  // MAX_BFS_PATH_LEN.\n  static_assert(SLOT_PER_BUCKET > 0,\n                \"SLOT_PER_BUCKET must be greater than 0.\");\n  static constexpr size_type MAX_CUCKOO_COUNT =\n      2 * ((SLOT_PER_BUCKET == 1)\n           ? MAX_BFS_PATH_LEN\n           : (const_pow(SLOT_PER_BUCKET, MAX_BFS_PATH_LEN) - 1) /\n             (SLOT_PER_BUCKET - 1));\n  // An array of b_slots. Since we allocate just enough space to complete a\n  // full search, we should never exceed the end of the array.\n  b_slot slots_[MAX_CUCKOO_COUNT];\n  // The index of the head of the queue in the array\n  size_type first_;\n  // One past the index of the last_ item of the queue in the array.\n  size_type last_;\n};\n\n// Contains a hash and partial for a given key. The partial key is used for\n// partial-key cuckoohashing, and for finding the alternate bucket of that a\n// key hashes to.\nstruct hash_value {\n  size_type hash;\n  partial_t partial;\n};\n\nclass AllLocksManager {\npublic:\n  AllLocksManager(all_locks_list_node *i_first_locked)\n    : first_locked(i_first_locked), active(true) {\n  }\n\n  AllLocksManager(const AllLocksManager& other)\n    : first_locked(other.first_locked), active(true) {\n    other.active = false;\n  }\n\n  AllLocksManager& operator=(const AllLocksManager& other) = delete;\n\n  ~AllLocksManager() {\n    if (active) {\n      for (all_locks_list_node *it = first_locked; it != nullptr; it = it->next) {\n        locks_t &locks = it->elt;\n        for (spinlock &lock : locks) {\n          lock.unlock();\n        }\n      }\n    }\n  }\n  \nprivate:\n  mutable bool active;\n  all_locks_list_node *first_locked;\n};\n\n// Status codes for internal functions\n\nenum cuckoo_status {\n  ok,\n  failure,\n  failure_key_not_found,\n  failure_key_duplicated,\n  failure_table_full,\n  failure_under_expansion,\n};\n\n// A composite type for functions that need to return a table position, and\n// a status code.\nstruct table_position {\n  size_type index;\n  size_type slot;\n  cuckoo_status status;\n};\n\n// CuckooRecord holds one position in a cuckoo path. Since cuckoopath\n// elements only define a sequence of alternate hashings for different hash\n// values, we only need to keep track of the hash values being moved, rather\n// than the keys themselves.\nstruct CuckooRecord {\n  size_type bucket;\n  size_type slot;\n  hash_value hv;\n};\n\n// An array of CuckooRecords\ntypedef std::array<CuckooRecord, MAX_BFS_PATH_LEN> CuckooRecords;\n\n/**\n * A concurrent hash table\n */\nclass cuckoohash_map {\npublic:\n  /** @name Type Declarations */\n  /**@{*/\n\n  /**@}*/\n\n  /** @name Constructors, Destructors, and Assignment */\n  /**@{*/\n\n  /**\n   * Creates a new cuckohash_map instance\n   *\n   * @param n the number of elements to reserve space for initially\n   * @param hf hash function instance to use\n   * @param equal equality function instance to use\n   */\n  cuckoohash_map(size_type n = LIBCUCKOO_DEFAULT_SIZE, const Hash &hf = Hash(),\n                 const KeyEqual &equal = KeyEqual())\n      : hash_fn_(hf), eq_fn_(equal), buckets_(reserve_calc(n)),\n        all_locks_(std::min(bucket_count(), size_type(kMaxNumLocks))),\n        minimum_load_factor_(LIBCUCKOO_DEFAULT_MINIMUM_LOAD_FACTOR),\n        maximum_hashpower_(LIBCUCKOO_NO_MAXIMUM_HASHPOWER) {\n  }\n\n  /**\n   * Eliminate copy assignment operator.\n   */\n\n  cuckoohash_map(const cuckoohash_map &other) = delete;\n  cuckoohash_map &operator=(const cuckoohash_map &other) = delete;\n\n  /**@}*/\n\n  /** @name Table Details\n   *\n   * Methods for getting information about the table. Methods that query\n   * changing properties of the table are not synchronized with concurrent\n   * operations, and may return out-of-date information if the table is being\n   * concurrently modified. They will also continue to work after the container\n   * has been moved.\n   *\n   */\n  /**@{*/\n\n  /**\n   * Returns the function that hashes the keys\n   *\n   * @return the hash function\n   */\n  hasher hash_function() const { return hash_fn_; }\n\n  /**\n   * Returns the function that compares keys for equality\n   *\n   * @return the key comparison function\n   */\n  key_equal key_eq() const { return eq_fn_; }\n\n  /**\n   * Returns the hashpower of the table, which is log<SUB>2</SUB>(@ref\n   * bucket_count()).\n   *\n   * @return the hashpower\n   */\n  size_type hashpower() const { return buckets_.hashpower(); }\n\n  /**\n   * Returns the number of buckets in the table.\n   *\n   * @return the bucket count\n   */\n  size_type bucket_count() const { return buckets_.size(); }\n\n  /**\n   * Returns whether the table is empty or not.\n   *\n   * @return true if the table is empty, false otherwise\n   */\n  bool empty() const { return size() == 0; }\n\n  /**\n   * Returns the number of elements in the table.\n   *\n   * @return number of elements in the table\n   */\n  size_type size() const {\n    counter_type s = 0;\n    for (spinlock &lock : get_current_locks()) {\n      s += lock.elem_counter();\n    }\n    assert(s >= 0);\n    return static_cast<size_type>(s);\n  }\n\n  /** Returns the current capacity of the table, that is, @ref bucket_count()\n   * &times.\n   *\n   * @return capacity of table\n   */\n  size_type capacity() const { return bucket_count() * SLOT_PER_BUCKET; }\n\n  /**\n   * Returns the percentage the table is filled, that is, @ref size() &divide;\n   * @ref capacity().\n   *\n   * @return load factor of the table\n   */\n  double load_factor() const {\n    return static_cast<double>(size()) / static_cast<double>(capacity());\n  }\n\n  /**\n   * Sets the minimum load factor allowed for automatic expansions. If an\n   * expansion is needed when the load factor of the table is lower than this\n   * threshold, ERROR_LOAD_FACTOR_TOO_LOW is returned. It will not be\n   * returned for an explicitly-triggered expansion.\n   *\n   * @param mlf the load factor to set the minimum to\n   * @param error the error code - ERROR_INVALID_ARGUMENT if the given\n   * load factor is less than 0.0 or greater than 1.0\n   */\n  void minimum_load_factor(const double mlf, int &error) {\n    if (mlf < 0.0) {\n      error = ERROR_INVALID_ARGUMENT;\n    } else if (mlf > 1.0) {\n      error = ERROR_INVALID_ARGUMENT;\n    }\n    else {\n      minimum_load_factor_.store(mlf, std::memory_order_release);\n      error = ERROR_NONE;\n    }\n  }\n\n  /**\n   * Returns the minimum load factor of the table\n   *\n   * @return the minimum load factor\n   */\n  double minimum_load_factor() const {\n    return minimum_load_factor_.load(std::memory_order_acquire);\n  }\n\n  /**\n   * Sets the maximum hashpower the table can be. If set to @ref\n   * LIBCUCKOO_NO_MAXIMUM_HASHPOWER, there will be no limit on the hashpower.\n   * Otherwise, the table will not be able to expand beyond the given\n   * hashpower, either by an explicit or an automatic expansion.\n   *\n   * @param mhp the hashpower to set the maximum to\n   * @param error the returned error code - ERROR_INVALID_ARGUMENT\n   * if the current hashpower exceeds the limit\n   */\n  void maximum_hashpower(size_type mhp, int &error) {\n    if (hashpower() > mhp) {\n      error = ERROR_INVALID_ARGUMENT;\n    }\n    else {\n      maximum_hashpower_.store(mhp, std::memory_order_release);\n      error = ERROR_NONE;\n    }\n  }\n\n  /**\n   * Returns the maximum hashpower of the table\n   *\n   * @return the maximum hashpower\n   */\n  size_type maximum_hashpower() const {\n    return maximum_hashpower_.load(std::memory_order_acquire);\n  }\n\n  /**@}*/\n\n  /**\n   * Copies the value associated with @p key into @p val. @c\n   * mapped_type must be @c CopyAssignable.\n   */\n  bool find(const KEY &key, mapped_type &val) const {\n    const hash_value hv = hashed_key(key);\n    const auto b = snapshot_and_lock_two(hv);\n    const table_position pos = cuckoo_find(key, hv.partial, b.i1, b.i2);\n    if (pos.status == ok) {\n      val = buckets_[pos.index].mapped(pos.slot);\n      return true;\n    } else {\n      return false;\n    }\n  }\n\n  /** Searches the table for @p key, and returns the associated value it\n   * finds. @c mapped_type must be @c CopyConstructible.\n   *\n   * @param key the key to search for\n   * @return the value associated with the given key\n   * @param error the returned error code\n   */\n  mapped_type find(const KEY &key, int &error) const {\n    const hash_value hv = hashed_key(key);\n    const auto b = snapshot_and_lock_two(hv);\n    const table_position pos = cuckoo_find(key, hv.partial, b.i1, b.i2);\n    if (pos.status == ok) {\n      error = ERROR_NONE;\n      return buckets_[pos.index].mapped(pos.slot);\n    } else {\n      error = ERROR_OUT_OF_RANGE;\n      return mapped_type();\n    }\n  }\n\n  /**\n   * Returns whether or not @p key is in the table.\n   */\n  bool contains(const KEY &key) const {\n    const hash_value hv = hashed_key(key);\n    const auto b = snapshot_and_lock_two(hv);\n    const table_position pos = cuckoo_find(key, hv.partial, b.i1, b.i2);\n    if (pos.status == ok) {\n      return true;\n    } else {\n      return false;\n    }\n  }\n\n  /**\n   * Updates the value associated with @p key to @p val.\n   * @c mapped_type must be @c MoveAssignable or @c\n   * CopyAssignable.\n   */\n  bool update(const KEY &key, const VALUE &val) {\n    const hash_value hv = hashed_key(key);\n    const auto b = snapshot_and_lock_two(hv);\n    const table_position pos = cuckoo_find(key, hv.partial, b.i1, b.i2);\n    if (pos.status == ok) {\n      buckets_[pos.index].mapped(pos.slot) = val;\n      return true;\n    } else {\n      return false;\n    }\n  }\n\n  /**\n   * Inserts the key-value pair into the table.\n   */\n  bool insert(const KEY &key, const VALUE &val, int &error) {\n    hash_value hv = hashed_key(key);\n    auto b = snapshot_and_lock_two(hv);\n    table_position pos = cuckoo_insert_loop(hv, b, key, error);\n    if (pos.status == ok) {\n      add_to_bucket(pos.index, pos.slot, hv.partial, key, val);\n      return true;\n    } else {\n      return false;\n    }\n  }\n\n  /**\n   * Inserts the key-value pair into the table. If the key is already in the\n   * table, assigns the existing mapped value to @p val.\n   */\n  bool insert_or_assign(const KEY &key, const VALUE &val, int &error) {\n    hash_value hv = hashed_key(key);\n    auto b = snapshot_and_lock_two(hv);\n    table_position pos = cuckoo_insert_loop(hv, b, key, error);\n    if (pos.status == ok) {\n      add_to_bucket(pos.index, pos.slot, hv.partial, key, val);\n      return true;\n    } else if (error == ERROR_NONE) {\n      buckets_[pos.index].mapped(pos.slot) = val;\n      return false;\n    }\n    else {\n      return false;\n    }\n  }\n\n  /**\n   * Erases the key from the table. Equivalent to calling @ref erase_fn with a\n   * functor that just returns true.\n   */\n  bool erase(const KEY &key) {\n    const hash_value hv = hashed_key(key);\n    const auto b = snapshot_and_lock_two(hv);\n    const table_position pos = cuckoo_find(key, hv.partial, b.i1, b.i2);\n    if (pos.status == ok) {\n      del_from_bucket(pos.index, pos.slot);\n      return true;\n    } else {\n      return false;\n    }\n  }\n\n  /**\n   * Resizes the table to the given hashpower. If this hashpower is not larger\n   * than the current hashpower, then it decreases the hashpower to the\n   * maximum of the specified value and the smallest hashpower that can hold\n   * all the elements currently in the table.\n   *\n   * @param n the hashpower to set for the table\n   * @return true if the table changed size, false otherwise\n   */\n  bool rehash(size_type n, int &error) { return cuckoo_rehash(n, error); }\n\n  /**\n   * Reserve enough space in the table for the given number of elements. If\n   * the table can already hold that many elements, the function will shrink\n   * the table to the smallest hashpower that can hold the maximum of the\n   * specified amount and the current table size.\n   *\n   * @param n the number of elements to reserve space for\n   * @return true if the size of the table changed, false otherwise\n   */\n  bool reserve(size_type n, int &error) { return cuckoo_reserve(n, error); }\n\n  /**\n   * Removes all elements in the table, calling their destructors.\n   */\n  void clear() {\n    auto all_locks_manager = snapshot_and_lock_all();\n    cuckoo_clear();\n  }\n\n  /**@}*/\n\nprivate:\n  // Hashing types and functions\n\n  // true if the key is small and simple, which means using partial keys for\n  // lookup would probably slow us down\n  static constexpr bool is_simple =\n      std::is_pod<key_type>::value && sizeof(key_type) <= 8;\n\n  hash_value hashed_key(const KEY &key) const {\n    const size_type hash = hash_function()(key);\n    return {hash, partial_key(hash)};\n  }\n\n  size_type hashed_key_only_hash(const KEY &key) const {\n    return hash_function()(key);\n  }\n\n  // hashsize returns the number of buckets corresponding to a given\n  // hashpower.\n  static inline size_type hashsize(const size_type hp) {\n    return size_type(1) << hp;\n  }\n\n  // hashmask returns the bitmask for the buckets array corresponding to a\n  // given hashpower.\n  static inline size_type hashmask(const size_type hp) {\n    return hashsize(hp) - 1;\n  }\n\n  // The partial key must only depend on the hash value. It cannot change with\n  // the hashpower, because, in order for `cuckoo_fast_double` to work\n  // properly, the alt_index must only grow by one bit at the top each time we\n  // expand the table.\n  static partial_t partial_key(const size_type hash) {\n    const uint64_t hash_64bit = hash;\n    const uint32_t hash_32bit = (static_cast<uint32_t>(hash_64bit) ^\n                                 static_cast<uint32_t>(hash_64bit >> 32));\n    const uint16_t hash_16bit = (static_cast<uint16_t>(hash_32bit) ^\n                                 static_cast<uint16_t>(hash_32bit >> 16));\n    const uint8_t hash_8bit = (static_cast<uint8_t>(hash_16bit) ^\n                               static_cast<uint8_t>(hash_16bit >> 8));\n    return hash_8bit;\n  }\n\n  // index_hash returns the first possible bucket that the given hashed key\n  // could be.\n  static inline size_type index_hash(const size_type hp, const size_type hv) {\n    return hv & hashmask(hp);\n  }\n\n  // alt_index returns the other possible bucket that the given hashed key\n  // could be. It takes the first possible bucket as a parameter. Note that\n  // this function will return the first possible bucket if index is the\n  // second possible bucket, so alt_index(ti, partial, alt_index(ti, partial,\n  // index_hash(ti, hv))) == index_hash(ti, hv).\n  static inline size_type alt_index(const size_type hp, const partial_t partial,\n                                    const size_type index) {\n    // ensure tag is nonzero for the multiply. 0xc6a4a7935bd1e995 is the\n    // hash constant from 64-bit MurmurHash2\n    const size_type nonzero_tag = static_cast<size_type>(partial) + 1;\n    return (index ^ (nonzero_tag * 0xc6a4a7935bd1e995)) & hashmask(hp);\n  }\n\n  // After taking a lock on the table for the given bucket, this function will\n  // check the hashpower to make sure it is the same as what it was before the\n  // lock was taken. If it isn't unlock the bucket and return\n  // ERROR_HASHPOWER_CHANGED instead of ERROR_NONE.\n  inline int check_hashpower(size_type hp, spinlock &lock) const {\n    if (hashpower() != hp) {\n      lock.unlock();\n      LIBCUCKOO_DBG(\"%s\", \"hashpower changed\\n\");\n      return ERROR_HASHPOWER_CHANGED;\n    }\n    else {\n      return ERROR_NONE;\n    }\n  }\n\n  // locks the given bucket index.\n  //\n  // sets error to ERROR_HASHPOWER_CHANGED if it changed after taking the lock.\n  LockManager lock_one(size_type hp, size_type i, int &error) const {\n    locks_t &locks = get_current_locks();\n    spinlock &lock = locks[lock_ind(i)];\n    lock.lock();\n    error = check_hashpower(hp, lock);\n    if (error != ERROR_NONE) {\n      return nullptr;\n    }\n    return LockManager(&lock);\n  }\n\n  // locks the two bucket indexes, always locking the earlier index first to\n  // avoid deadlock. If the two indexes are the same, it just locks one.\n  //\n  // sets error to ERROR_HASHPOWER_CHANGED if it changed after taking the lock.\n\n  TwoBuckets lock_two(size_type hp, size_type i1, size_type i2, int &error) const {\n    size_type l1 = lock_ind(i1);\n    size_type l2 = lock_ind(i2);\n    if (l2 < l1) {\n      std::swap(l1, l2);\n    }\n    locks_t &locks = get_current_locks();\n    locks[l1].lock();\n    error = check_hashpower(hp, locks[l1]);\n    if (error != ERROR_NONE) {\n      return TwoBuckets();\n    }\n    if (l2 != l1) {\n      locks[l2].lock();\n    }\n    return TwoBuckets(locks, i1, i2);\n  }\n\n  // lock_three locks the three bucket indexes in numerical order, returning\n  // the containers as a two (i1 and i2) and a one (i3). The one will not be\n  // active if i3 shares a lock index with i1 or i2.\n  //\n  // sets error to ERROR_HASHPOWER_CHANGED if it changed after taking the lock.\n  std::pair<TwoBuckets, LockManager> lock_three(size_type hp, size_type i1,\n                                                size_type i2, size_type i3,\n                                                int &error)\n                                                const {\n    std::array<size_type, 3> l{{lock_ind(i1), lock_ind(i2), lock_ind(i3)}};\n    // Lock in order.\n    if (l[2] < l[1])\n      std::swap(l[2], l[1]);\n    if (l[2] < l[0])\n      std::swap(l[2], l[0]);\n    if (l[1] < l[0])\n      std::swap(l[1], l[0]);\n    locks_t &locks = get_current_locks();\n    locks[l[0]].lock();\n    error = check_hashpower(hp, locks[l[0]]);\n    if (error != ERROR_NONE) {\n      return std::make_pair(TwoBuckets(), nullptr);\n    }\n    if (l[1] != l[0]) {\n      locks[l[1]].lock();\n    }\n    if (l[2] != l[1]) {\n      locks[l[2]].lock();\n    }\n    return std::make_pair(TwoBuckets(locks, i1, i2),\n                          LockManager((lock_ind(i3) == lock_ind(i1) ||\n                                       lock_ind(i3) == lock_ind(i2))\n                                          ? nullptr\n                                          : &locks[lock_ind(i3)]));\n  }\n\n  // snapshot_and_lock_two loads locks the buckets associated with the given\n  // hash value, making sure the hashpower doesn't change before the locks are\n  // taken. Thus it ensures that the buckets and locks corresponding to the\n  // hash value will stay correct as long as the locks are held. It returns\n  // the bucket indices associated with the hash value and the current\n  // hashpower.\n  TwoBuckets snapshot_and_lock_two(const hash_value &hv) const {\n    while (true) {\n      // Keep the current hashpower and locks we're using to compute the buckets\n      const size_type hp = hashpower();\n      const size_type i1 = index_hash(hp, hv.hash);\n      const size_type i2 = alt_index(hp, hv.partial, i1);\n      int error;\n      TwoBuckets tb = lock_two(hp, i1, i2, error);\n      if (error == ERROR_HASHPOWER_CHANGED) {\n        // The hashpower changed while taking the locks. Try again.\n        continue;\n      }\n      else {\n        return tb;\n      }\n    }\n  }\n\n  // snapshot_and_lock_all takes all the locks, and returns a deleter object\n  // that releases the locks upon destruction. Note that after taking all the\n  // locks, it is okay to resize the buckets_ container, since no other threads\n  // should be accessing the buckets. This should only be called if we are not\n  // in locked_table mode, and after this function is over, we will be in\n  // locked_table mode. When the deleter object goes out of scope, we will be\n  // out of locked_table mode.\n  AllLocksManager snapshot_and_lock_all() {\n    all_locks_list_node *first_locked = all_locks_.get_tail();\n    all_locks_list_node *current_locks = first_locked;\n    while (current_locks != nullptr) {\n      locks_t &locks = current_locks->elt;\n      for (spinlock &lock : locks) {\n        lock.lock();\n      }\n      current_locks = current_locks->next;\n    }\n    // Once we have taken all the locks of the \"current\" container, nobody\n    // else can do locking operations on the table.\n    return AllLocksManager(first_locked);\n  }\n\n  // Searching types and functions\n\n  // cuckoo_find searches the table for the given key, returning the position\n  // of the element found, or a failure status code if the key wasn't found.\n  // It expects the locks to be taken and released outside the function.\n  table_position cuckoo_find(const KEY &key, const partial_t partial,\n                             const size_type i1, const size_type i2) const {\n    int slot = try_read_from_bucket(buckets_[i1], partial, key);\n    if (slot != -1) {\n      return table_position{i1, static_cast<size_type>(slot), ok};\n    }\n    slot = try_read_from_bucket(buckets_[i2], partial, key);\n    if (slot != -1) {\n      return table_position{i2, static_cast<size_type>(slot), ok};\n    }\n    return table_position{0, 0, failure_key_not_found};\n  }\n\n  // try_read_from_bucket will search the bucket for the given key and return\n  // the index of the slot if found, or -1 if not found.\n  int try_read_from_bucket(const bucket &b, const partial_t partial,\n                           const KEY &key) const {\n    // Silence a warning from MSVC about partial being unused if is_simple.\n    (void)partial;\n    for (int i = 0; i < static_cast<int>(SLOT_PER_BUCKET); ++i) {\n      if (!b.occupied(i) || (!is_simple && partial != b.partial(i))) {\n        continue;\n      } else if (key_eq()(b.key(i), key)) {\n        return i;\n      }\n    }\n    return -1;\n  }\n\n  // Insertion types and function\n\n  /**\n   * Runs cuckoo_insert in a loop until it succeeds in insert, so\n   * we pulled out the loop to avoid duplicating logic.\n   *\n   * @param hv the hash value of the key\n   * @param b bucket locks\n   * @param key the key to insert\n   * @return table_position of the location to insert the new element, or the\n   * site of the duplicate element with a status code if there was a duplicate.\n   * In either case, the locks will still be held after the function ends.\n   * @param error the returned error code, e.g., ERROR_LOAD_FACTOR_TOO_LOW\n   * if expansion is necessary but the load factor of the table is below\n   * the threshold\n   */\n  table_position cuckoo_insert_loop(hash_value hv, TwoBuckets &b, const KEY &key, int &error) {\n    error = ERROR_NONE;\n    table_position pos;\n    while (true) {\n      const size_type hp = hashpower();\n      pos = cuckoo_insert(hv, b, key);\n      switch (pos.status) {\n      case ok:\n      case failure_key_duplicated:\n        return pos;\n      case failure_table_full:\n        // Expand the table and try again, re-grabbing the locks\n        cuckoo_fast_double(hp, true /* auto resize */, error);\n        if (error != ERROR_NONE) {\n          return pos;\n        }\n        b = snapshot_and_lock_two(hv);\n        break;\n      case failure_under_expansion:\n        // The table was under expansion while we were cuckooing. Re-grab the\n        // locks and try again.\n        b = snapshot_and_lock_two(hv);\n        break;\n      default:\n        assert(false);\n      }\n    }\n  }\n\n  // cuckoo_insert tries to find an empty slot in either of the buckets to\n  // insert the given key into, performing cuckoo hashing if necessary. It\n  // expects the locks to be taken outside the function. Before inserting, it\n  // checks that the key isn't already in the table. cuckoo hashing presents\n  // multiple concurrency issues, which are explained in the function. The\n  // following return states are possible:\n  //\n  // ok -- Found an empty slot, locks will be held on both buckets after the\n  // function ends, and the position of the empty slot is returned\n  //\n  // failure_key_duplicated -- Found a duplicate key, locks will be held, and\n  // the position of the duplicate key will be returned\n  //\n  // failure_under_expansion -- Failed due to a concurrent expansion\n  // operation. Locks are released. No meaningful position is returned.\n  //\n  // failure_table_full -- Failed to find an empty slot for the table. Locks\n  // are released. No meaningful position is returned.\n  table_position cuckoo_insert(const hash_value hv, TwoBuckets &b, const KEY &key) {\n    int res1, res2;\n    bucket &b1 = buckets_[b.i1];\n    if (!try_find_insert_bucket(b1, res1, hv.partial, key)) {\n      return table_position{b.i1, static_cast<size_type>(res1),\n                            failure_key_duplicated};\n    }\n    bucket &b2 = buckets_[b.i2];\n    if (!try_find_insert_bucket(b2, res2, hv.partial, key)) {\n      return table_position{b.i2, static_cast<size_type>(res2),\n                            failure_key_duplicated};\n    }\n    if (res1 != -1) {\n      return table_position{b.i1, static_cast<size_type>(res1), ok};\n    }\n    if (res2 != -1) {\n      return table_position{b.i2, static_cast<size_type>(res2), ok};\n    }\n\n    // We are unlucky, so let's perform cuckoo hashing.\n    size_type insert_bucket = 0;\n    size_type insert_slot = 0;\n    cuckoo_status st = run_cuckoo(b, insert_bucket, insert_slot);\n    if (st == failure_under_expansion) {\n      // The run_cuckoo operation operated on an old version of the table,\n      // so we have to try again. We signal to the calling insert method\n      // to try again by returning failure_under_expansion.\n      return table_position{0, 0, failure_under_expansion};\n    } else if (st == ok) {\n      assert(!get_current_locks()[lock_ind(b.i1)].try_lock());\n      assert(!get_current_locks()[lock_ind(b.i2)].try_lock());\n      assert(!buckets_[insert_bucket].occupied(insert_slot));\n      assert(insert_bucket == index_hash(hashpower(), hv.hash) ||\n             insert_bucket == alt_index(hashpower(), hv.partial,\n                                        index_hash(hashpower(), hv.hash)));\n      // Since we unlocked the buckets during run_cuckoo, another insert\n      // could have inserted the same key into either b.i1 or\n      // b.i2, so we check for that before doing the insert.\n      table_position pos = cuckoo_find(key, hv.partial, b.i1, b.i2);\n      if (pos.status == ok) {\n        pos.status = failure_key_duplicated;\n        return pos;\n      }\n      return table_position{insert_bucket, insert_slot, ok};\n    }\n    assert(st == failure);\n    LIBCUCKOO_DBG(\"hash table is full (hashpower = %zu, hash_items = %zu,\"\n                  \"load factor = %.2f), need to increase hashpower\\n\",\n                  hashpower(), size(), load_factor());\n    return table_position{0, 0, failure_table_full};\n  }\n\n  // add_to_bucket will insert the given key-value pair into the slot. The key\n  // and value will be move-constructed into the table, so they are not valid\n  // for use afterwards.\n  void add_to_bucket(const size_type bucket_ind, const size_type slot,\n                     const partial_t partial, const KEY &key, const VALUE& val) {\n    buckets_.setKV(bucket_ind, slot, partial, key, val);\n    ++get_current_locks()[lock_ind(bucket_ind)].elem_counter();\n  }\n\n  // try_find_insert_bucket will search the bucket for the given key, and for\n  // an empty slot. If the key is found, we store the slot of the key in\n  // `slot` and return false. If we find an empty slot, we store its position\n  // in `slot` and return true. If no duplicate key is found and no empty slot\n  // is found, we store -1 in `slot` and return true.\n  bool try_find_insert_bucket(const bucket &b, int &slot,\n                              const partial_t partial, const KEY &key) const {\n    // Silence a warning from MSVC about partial being unused if is_simple.\n    (void)partial;\n    slot = -1;\n    for (int i = 0; i < static_cast<int>(SLOT_PER_BUCKET); ++i) {\n      if (b.occupied(i)) {\n        if (!is_simple && partial != b.partial(i)) {\n          continue;\n        }\n        if (key_eq()(b.key(i), key)) {\n          slot = i;\n          return false;\n        }\n      } else {\n        slot = i;\n      }\n    }\n    return true;\n  }\n\n  // run_cuckoo performs cuckoo hashing on the table in an attempt to free up\n  // a slot on either of the insert buckets, which are assumed to be locked\n  // before the start. On success, the bucket and slot that was freed up is\n  // stored in insert_bucket and insert_slot. In order to perform the search\n  // and the swaps, it has to release the locks, which can lead to certain\n  // concurrency issues, the details of which are explained in the function.\n  // If run_cuckoo returns ok (success), then `b` will be active, otherwise it\n  // will not.\n  cuckoo_status run_cuckoo(TwoBuckets &b, size_type &insert_bucket,\n                           size_type &insert_slot) {\n    // We must unlock the buckets here, so that cuckoopath_search and\n    // cuckoopath_move can lock buckets as desired without deadlock.\n    // cuckoopath_move has to move something out of one of the original\n    // buckets as its last operation, and it will lock both buckets and\n    // leave them locked after finishing. This way, we know that if\n    // cuckoopath_move succeeds, then the buckets needed for insertion are\n    // still locked. If cuckoopath_move fails, the buckets are unlocked and\n    // we try again. This unlocking does present two problems. The first is\n    // that another insert on the same key runs and, finding that the key\n    // isn't in the table, inserts the key into the table. Then we insert\n    // the key into the table, causing a duplication. To check for this, we\n    // search the buckets for the key we are trying to insert before doing\n    // so (this is done in cuckoo_insert, and requires that both buckets are\n    // locked). Another problem is that an expansion runs and changes the\n    // hashpower, meaning the buckets may not be valid anymore. In this\n    // case, the cuckoopath functions will have returned\n    // ERROR_HASHPOWER_CHANGED, which we detect and handle here.\n    size_type hp = hashpower();\n    b.unlock();\n    CuckooRecords cuckoo_path;\n    bool done = false;\n    int error;\n    while (!done) {\n      const int depth =\n          cuckoopath_search(hp, cuckoo_path, b.i1, b.i2, error);\n      if (error == ERROR_HASHPOWER_CHANGED) {\n        return failure_under_expansion;\n      }\n      if (depth < 0) {\n        break;\n      }\n\n      if (cuckoopath_move(hp, cuckoo_path, depth, b, error)) {\n        insert_bucket = cuckoo_path[0].bucket;\n        insert_slot = cuckoo_path[0].slot;\n        assert(insert_bucket == b.i1 || insert_bucket == b.i2);\n        assert(!get_current_locks()[lock_ind(b.i1)].try_lock());\n        assert(!get_current_locks()[lock_ind(b.i2)].try_lock());\n        assert(!buckets_[insert_bucket].occupied(insert_slot));\n        done = true;\n        break;\n      }\n      if (error == ERROR_HASHPOWER_CHANGED) {\n        return failure_under_expansion;\n      }\n    }\n    return done ? ok : failure;\n  }\n\n  // cuckoopath_search finds a cuckoo path from one of the starting buckets to\n  // an empty slot in another bucket. It returns the depth of the discovered\n  // cuckoo path on success, and -1 on failure. Since it doesn't take locks on\n  // the buckets it searches, the data can change between this function and\n  // cuckoopath_move. Thus cuckoopath_move checks that the data matches the\n  // cuckoo path before changing it.\n  //\n  // sets error to ERROR_HASHPOWER_CHANGED if it changed during the search.\n  int cuckoopath_search(const size_type hp, CuckooRecords &cuckoo_path,\n                        const size_type i1, const size_type i2, int &error) {\n    error = ERROR_NONE;\n    b_slot x = slot_search(hp, i1, i2, error);\n    if (x.depth == -1) {\n      return -1;\n    }\n    // Fill in the cuckoo path slots from the end to the beginning.\n    for (int i = x.depth; i >= 0; i--) {\n      cuckoo_path[i].slot = x.pathcode % SLOT_PER_BUCKET;\n      x.pathcode /= SLOT_PER_BUCKET;\n    }\n    // Fill in the cuckoo_path buckets and keys from the beginning to the\n    // end, using the final pathcode to figure out which bucket the path\n    // starts on. Since data could have been modified between slot_search\n    // and the computation of the cuckoo path, this could be an invalid\n    // cuckoo_path.\n    CuckooRecord &first = cuckoo_path[0];\n    if (x.pathcode == 0) {\n      first.bucket = i1;\n    } else {\n      assert(x.pathcode == 1);\n      first.bucket = i2;\n    }\n    {\n      const auto lock_manager = lock_one(hp, first.bucket, error);\n      if (error != ERROR_NONE) {\n        return -1;\n      }\n      const bucket &b = buckets_[first.bucket];\n      if (!b.occupied(first.slot)) {\n        // We can terminate here\n        return 0;\n      }\n      first.hv = hashed_key(b.key(first.slot));\n    }\n    for (int i = 1; i <= x.depth; ++i) {\n      CuckooRecord &curr = cuckoo_path[i];\n      const CuckooRecord &prev = cuckoo_path[i - 1];\n      assert(prev.bucket == index_hash(hp, prev.hv.hash) ||\n             prev.bucket ==\n                 alt_index(hp, prev.hv.partial, index_hash(hp, prev.hv.hash)));\n      // We get the bucket that this slot is on by computing the alternate\n      // index of the previous bucket\n      curr.bucket = alt_index(hp, prev.hv.partial, prev.bucket);\n      const auto lock_manager = lock_one(hp, curr.bucket, error);\n      if (error != ERROR_NONE) {\n        return -1;\n      }\n      const bucket &b = buckets_[curr.bucket];\n      if (!b.occupied(curr.slot)) {\n        // We can terminate here\n        return i;\n      }\n      curr.hv = hashed_key(b.key(curr.slot));\n    }\n    return x.depth;\n  }\n\n  // cuckoopath_move moves keys along the given cuckoo path in order to make\n  // an empty slot in one of the buckets in cuckoo_insert. Before the start of\n  // this function, the two insert-locked buckets were unlocked in run_cuckoo.\n  // At the end of the function, if the function returns true (success), then\n  // both insert-locked buckets remain locked. If the function is\n  // unsuccessful, then both insert-locked buckets will be unlocked.\n  //\n  // sets error to ERROR_HASHPOWER_CHANGED if it changed during the move.\n  bool cuckoopath_move(const size_type hp, CuckooRecords &cuckoo_path,\n                       size_type depth, TwoBuckets &b, int &error) {\n    error = ERROR_NONE;\n    if (depth == 0) {\n      // There is a chance that depth == 0, when try_add_to_bucket sees\n      // both buckets as full and cuckoopath_search finds one empty. In\n      // this case, we lock both buckets. If the slot that\n      // cuckoopath_search found empty isn't empty anymore, we unlock them\n      // and return false. Otherwise, the bucket is empty and insertable,\n      // so we hold the locks and return true.\n      const size_type bucket = cuckoo_path[0].bucket;\n      assert(bucket == b.i1 || bucket == b.i2);\n      b = lock_two(hp, b.i1, b.i2, error);\n      if (error != ERROR_NONE) {\n        return false;\n      }\n      if (!buckets_[bucket].occupied(cuckoo_path[0].slot)) {\n        return true;\n      } else {\n        b.unlock();\n        return false;\n      }\n    }\n\n    while (depth > 0) {\n      CuckooRecord &from = cuckoo_path[depth - 1];\n      CuckooRecord &to = cuckoo_path[depth];\n      const size_type fs = from.slot;\n      const size_type ts = to.slot;\n      TwoBuckets twob;\n      LockManager extra_manager;\n      if (depth == 1) {\n        // Even though we are only swapping out of one of the original\n        // buckets, we have to lock both of them along with the slot we\n        // are swapping to, since at the end of this function, they both\n        // must be locked. We store tb inside the extrab container so it\n        // is unlocked at the end of the loop.\n        std::tie(twob, extra_manager) =\n             lock_three(hp, b.i1, b.i2, to.bucket, error);\n      } else {\n        twob = lock_two(hp, from.bucket, to.bucket, error);\n      }\n      if (error != ERROR_NONE) {\n        return false;\n      }\n\n      bucket &fb = buckets_[from.bucket];\n      bucket &tb = buckets_[to.bucket];\n\n      // We plan to kick out fs, but let's check if it is still there;\n      // there's a small chance we've gotten scooped by a later cuckoo. If\n      // that happened, just... try again. Also the slot we are filling in\n      // may have already been filled in by another thread, or the slot we\n      // are moving from may be empty, both of which invalidate the swap.\n      // We only need to check that the hash value is the same, because,\n      // even if the keys are different and have the same hash value, then\n      // the cuckoopath is still valid.\n      if (tb.occupied(ts) || !fb.occupied(fs) ||\n          hashed_key_only_hash(fb.key(fs)) != from.hv.hash) {\n        return false;\n      }\n\n      buckets_.setKV(to.bucket, ts, fb.partial(fs), fb.key(fs),\n                     fb.mapped(fs));\n      buckets_.eraseKV(from.bucket, fs);\n      if (depth == 1) {\n        // Hold onto the locks contained in twob\n        b = twob;\n      }\n      depth--;\n    }\n    return true;\n  }\n\n  // slot_search searches for a cuckoo path using breadth-first search. It\n  // starts with the i1 and i2 buckets, and, until it finds a bucket with an\n  // empty slot, adds each slot of the bucket in the b_slot. If the queue runs\n  // out of space, it fails.\n  //\n  // sets error to ERROR_HASHPOWER_CHANGED if it changed during the search\n  b_slot slot_search(const size_type hp, const size_type i1,\n                     const size_type i2, int &error) {\n    b_queue q;\n    // The initial pathcode informs cuckoopath_search which bucket the path\n    // starts on\n    q.enqueue(b_slot(i1, 0, 0));\n    q.enqueue(b_slot(i2, 1, 0));\n    while (!q.empty()) {\n      b_slot x = q.dequeue();\n      auto lock_manager = lock_one(hp, x.bucket, error);\n      if (error != ERROR_NONE) {\n        return b_slot(0, 0, -1);\n      }\n      bucket &b = buckets_[x.bucket];\n      // Picks a (sort-of) random slot to start from\n      size_type starting_slot = x.pathcode % SLOT_PER_BUCKET;\n      for (size_type i = 0; i < SLOT_PER_BUCKET; ++i) {\n        uint16_t slot = (starting_slot + i) % SLOT_PER_BUCKET;\n        if (!b.occupied(slot)) {\n          // We can terminate the search here\n          x.pathcode = x.pathcode * SLOT_PER_BUCKET + slot;\n          return x;\n        }\n\n        // If x has less than the maximum number of path components,\n        // create a new b_slot item, that represents the bucket we would\n        // have come from if we kicked out the item at this slot.\n        const partial_t partial = b.partial(slot);\n        if (x.depth < MAX_BFS_PATH_LEN - 1) {\n          assert(!q.full());\n          b_slot y(alt_index(hp, partial, x.bucket),\n                   x.pathcode * SLOT_PER_BUCKET + slot, x.depth + 1);\n          q.enqueue(y);\n        }\n      }\n    }\n    // We didn't find a short-enough cuckoo path, so the search terminated.\n    // Return a failure value.\n    return b_slot(0, 0, -1);\n  }\n\n  // cuckoo_fast_double will double the size of the table by taking advantage\n  // of the properties of index_hash and alt_index. If the key's move\n  // constructor is not noexcept, we use cuckoo_expand_simple, since that\n  // provides a strong exception guarantee.\n  cuckoo_status cuckoo_fast_double(size_type current_hp, bool auto_resize,\n                                   int &error) {\n    error = ERROR_NONE;\n    if (!std::is_nothrow_move_constructible<key_type>::value ||\n        !std::is_nothrow_move_constructible<mapped_type>::value) {\n      LIBCUCKOO_DBG(\"%s\", \"cannot run cuckoo_fast_double because key-value\"\n                          \" pair is not nothrow move constructible\");\n      return cuckoo_expand_simple(current_hp + 1, auto_resize, error);\n    }\n    const size_type new_hp = current_hp + 1;\n    auto all_locks_manager = snapshot_and_lock_all();\n    cuckoo_status st = check_resize_validity(current_hp, new_hp, auto_resize, error);\n    if (st != ok) {\n      return st;\n    }\n\n    // We must re-hash the table, moving items in each bucket to a different\n    // one. The hash functions are carefully designed so that when doubling the\n    // number of buckets, each element either stays in its existing bucket or\n    // goes to exactly one new bucket. This means we can re-hash each bucket in\n    // parallel. We create a new empty buckets container and move all the\n    // elements from the old container to the new one.\n    buckets_t new_buckets(new_hp);\n    // For certain types, MSVC may decide that move_buckets() cannot throw and\n    // so the catch block below is dead code. Since that won't always be true,\n    // we just disable the warning here.\n    LIBCUCKOO_SQUELCH_DEADCODE_WARNING_BEGIN;\n    size_type start = 0;\n    size_type end = hashsize(current_hp);\n    static const size_type num_threads =\n        std::max(std::thread::hardware_concurrency(), 1U);\n    size_type work_per_thread = (end - start) / num_threads;\n    std::vector<std::thread> threads;\n    threads.reserve(num_threads);\n    std::vector<int> errors(num_threads, ERROR_NONE);\n    for (size_type i = 0; i < num_threads - 1; ++i) {\n      threads.emplace_back(move_buckets_static, this, std::ref(new_buckets), current_hp, new_hp, start, start + work_per_thread,\n                           std::ref(errors[i]));\n      start += work_per_thread;\n    }\n    threads.emplace_back(move_buckets_static, this, std::ref(new_buckets), current_hp, new_hp, start, end, std::ref(errors.back()));\n    for (size_type i = 0; i < num_threads; ++i) {\n      threads[i].join();\n    }\n    error = ERROR_NONE;\n    for (size_type i = 0; i < num_threads; ++i) {\n      if (errors[i] != ERROR_NONE) {\n        error = errors[i];\n        return failure;\n      }\n    }\n    LIBCUCKOO_SQUELCH_DEADCODE_WARNING_END;\n\n    // Resize the locks array if necessary. This is done before we update the\n    // hashpower so that other threads don't grab the new hashpower and the old\n    // locks\n    maybe_resize_locks(size_type(1) << new_hp);\n    // Swap the old and new buckets. The old bucket data will be destroyed when\n    // the function exits\n    buckets_.swap(new_buckets);\n    return ok;\n  }\n\n  static void cuckoo_expand_simple_thread_routine(cuckoohash_map *old_map,\n                                                  cuckoohash_map *new_map,\n                                                  size_type i, size_type end,\n                                                  int& error)\n  {\n    error = ERROR_NONE;\n    for (; i < end; ++i) {\n      for (size_type j = 0; j < SLOT_PER_BUCKET; ++j) {\n        if (old_map->buckets_[i].occupied(j)) {\n          new_map->insert(old_map->buckets_[i].key(j),\n                          old_map->buckets_[i].mapped(j), error);\n          if (error != ERROR_NONE) {\n            break;\n          }\n        }\n      }\n    }\n  }\n\n  void move_buckets(buckets_t &new_buckets, size_type current_hp,\n                    size_type new_hp, size_type start_ind, size_type end_ind,\n                    int &error) {\n    error = ERROR_NONE;\n    for (size_type old_bucket_ind = start_ind; old_bucket_ind < end_ind;\n         ++old_bucket_ind) {\n      // By doubling the table size, the index_hash and alt_index of\n      // each key got one bit added to the top, at position\n      // current_hp, which means anything we have to move will either\n      // be at the same bucket position, or exactly\n      // hashsize(current_hp) later than the current bucket\n      bucket &old_bucket = buckets_[old_bucket_ind];\n      const size_type new_bucket_ind = old_bucket_ind + hashsize(current_hp);\n      size_type new_bucket_slot = 0;\n\n      // For each occupied slot, either move it into its same position in the\n      // new buckets container, or to the first available spot in the new\n      // bucket in the new buckets container.\n      for (size_type old_bucket_slot = 0; old_bucket_slot < SLOT_PER_BUCKET;\n           ++old_bucket_slot) {\n        if (!old_bucket.occupied(old_bucket_slot)) {\n          continue;\n        }\n        const hash_value hv = hashed_key(old_bucket.key(old_bucket_slot));\n        const size_type old_ihash = index_hash(current_hp, hv.hash);\n        const size_type old_ahash =\n            alt_index(current_hp, hv.partial, old_ihash);\n        const size_type new_ihash = index_hash(new_hp, hv.hash);\n        const size_type new_ahash = alt_index(new_hp, hv.partial, new_ihash);\n        size_type dst_bucket_ind, dst_bucket_slot;\n        if ((old_bucket_ind == old_ihash && new_ihash == new_bucket_ind) ||\n            (old_bucket_ind == old_ahash && new_ahash == new_bucket_ind)) {\n          // We're moving the key to the new bucket\n          dst_bucket_ind = new_bucket_ind;\n          dst_bucket_slot = new_bucket_slot++;\n        } else {\n          // We're moving the key to the old bucket\n          assert((old_bucket_ind == old_ihash && new_ihash == old_ihash) ||\n                 (old_bucket_ind == old_ahash && new_ahash == old_ahash));\n          dst_bucket_ind = old_bucket_ind;\n          dst_bucket_slot = old_bucket_slot;\n        }\n        new_buckets.setKV(dst_bucket_ind, dst_bucket_slot++,\n                          old_bucket.partial(old_bucket_slot),\n                          old_bucket.key(old_bucket_slot),\n                          old_bucket.mapped(old_bucket_slot));\n      }\n    }\n  }\n\n  static void move_buckets_static(cuckoohash_map *m, buckets_t &new_buckets, size_type current_hp,\n                                  size_type new_hp, size_type start_ind, size_type end_ind,\n                                  int &error) {\n      m->move_buckets(new_buckets, current_hp, new_hp, start_ind, end_ind, error);\n  }\n\n  cuckoo_status check_resize_validity(const size_type orig_hp,\n                                      const size_type new_hp,\n                                      bool auto_resize,\n                                      int &error) {\n    error = ERROR_NONE;\n    const size_type mhp = maximum_hashpower();\n    if (mhp != LIBCUCKOO_NO_MAXIMUM_HASHPOWER && new_hp > mhp) {\n      error = ERROR_MAXIMUM_HASH_POWER_EXCEEDED;\n      return failure;\n    }\n    if (auto_resize && load_factor() < minimum_load_factor()) {\n      error = ERROR_LOAD_FACTOR_TOO_LOW;\n      return failure;\n    }\n    if (hashpower() != orig_hp) {\n      // Most likely another expansion ran before this one could grab the\n      // locks\n      LIBCUCKOO_DBG(\"%s\", \"another expansion is on-going\\n\");\n      return failure_under_expansion;\n    }\n    return ok;\n  }\n\n  // When we expand the contanier, we may need to expand the locks array, if\n  // the current locks array is smaller than the maximum size and also smaller\n  // than the number of buckets in the upcoming buckets container. In this\n  // case, we grow the locks array to the smaller of the maximum lock array\n  // size and the bucket count. This is done by allocating an entirely new lock\n  // container, taking all the locks, copying over the counters, and then\n  // finally adding it to the end of `all_locks_`, thereby designating it the\n  // \"current\" locks container. It is the responsibility of the caller to\n  // unlock all locks taken, including the new locks, whenever it is done with\n  // them, so that old threads can resume and potentially re-start.\n  void maybe_resize_locks(size_type new_bucket_count) {\n    locks_t &current_locks = get_current_locks();\n    if (!(current_locks.size() < kMaxNumLocks &&\n          current_locks.size() < new_bucket_count)) {\n      return;\n    }\n\n    all_locks_list_node *new_tail = new all_locks_list_node(std::min(size_type(kMaxNumLocks), new_bucket_count));\n    locks_t &new_locks = new_tail->elt;\n    for (spinlock &lock : new_locks) {\n      lock.lock();\n    }\n    assert(new_locks.size() > current_locks.size());\n    std::copy(current_locks.begin(), current_locks.end(), new_locks.begin());\n    all_locks_.append(new_tail);\n  }\n\n  // cuckoo_expand_simple will resize the table to at least the given\n  // new_hashpower. When we're shrinking the table, if the current table\n  // contains more elements than can be held by new_hashpower, the resulting\n  // hashpower will be greater than `new_hp`. It needs to take all the bucket\n  // locks, since no other operations can change the table during expansion.\n  // sets error to ERROR_MAXIMUM_HASH_POWER_EXCEEDED if we're expanding beyond the\n  // maximum hashpower, and we have an actual limit.\n  cuckoo_status cuckoo_expand_simple(size_type new_hp, bool auto_resize, int &error) {\n    auto all_locks_manager = snapshot_and_lock_all();\n    const size_type hp = hashpower();\n    cuckoo_status st = check_resize_validity(hp, new_hp, auto_resize, error);\n    if (st != ok) {\n      return st;\n    }\n    // Creates a new hash table with hashpower new_hp and adds all\n    // the elements from the old buckets.\n    cuckoohash_map new_map(hashsize(new_hp) * SLOT_PER_BUCKET,\n                           hash_function(), key_eq());\n\n    size_type start = 0;\n    size_type end = hashsize(new_hp);\n    static const size_type num_threads =\n        std::max(std::thread::hardware_concurrency(), 1U);\n    size_type work_per_thread = (end - start) / num_threads;\n    std::vector<std::thread> threads;\n    threads.reserve(num_threads);\n    std::vector<int> errors(num_threads, ERROR_NONE);\n    for (size_type i = 0; i < num_threads - 1; ++i) {\n      threads.emplace_back(cuckoo_expand_simple_thread_routine, this, &new_map, start, start + work_per_thread,\n                           std::ref(errors[i]));\n      start += work_per_thread;\n    }\n    threads.emplace_back(cuckoo_expand_simple_thread_routine, this, &new_map, start, end, std::ref(errors.back()));\n    for (size_type i = 0; i < num_threads; ++i) {\n      threads[i].join();\n    }\n    error = ERROR_NONE;\n    for (size_type i = 0; i < num_threads; ++i) {\n      if (errors[i] != ERROR_NONE) {\n        error = errors[i];\n        return failure;\n      }\n    }\n\n    // Swap the current buckets containers with new_map's. This is okay,\n    // because we have all the locks, so nobody else should be reading from the\n    // buckets array. Then the old buckets array will be deleted when new_map\n    // is deleted. We also resize the locks array if necessary.\n    maybe_resize_locks(new_map.bucket_count());\n    buckets_.swap(new_map.buckets_);\n    return ok;\n  }\n\n  // Deletion functions\n\n  // Removes an item from a bucket, decrementing the associated counter as\n  // well.\n  void del_from_bucket(const size_type bucket_ind, const size_type slot) {\n    buckets_.eraseKV(bucket_ind, slot);\n    --get_current_locks()[lock_ind(bucket_ind)].elem_counter();\n  }\n\n  // Empties the table, calling the destructors of all the elements it removes\n  // from the table. It assumes the locks are taken as necessary.\n  cuckoo_status cuckoo_clear() {\n    buckets_.clear();\n    for (spinlock &lock : get_current_locks()) {\n      lock.elem_counter() = 0;\n    }\n    return ok;\n  }\n\n  // Rehashing functions\n\n  bool cuckoo_rehash(size_type n, int &error) {\n    const size_type hp = hashpower();\n    if (n == hp) {\n      error = ERROR_NONE;\n      return false;\n    }\n    return cuckoo_expand_simple(n, false /* auto resize: no */, error) == ok;\n  }\n\n  bool cuckoo_reserve(size_type n, int &error) {\n    const size_type hp = hashpower();\n    const size_type new_hp = reserve_calc(n);\n    if (new_hp == hp) {\n      error = ERROR_NONE;\n      return false;\n    }\n    return cuckoo_expand_simple(new_hp, false /* auto resize: no */, error) == ok;\n  }\n\n  // Miscellaneous functions\n\n  // reserve_calc takes in a parameter specifying a certain number of slots\n  // for a table and returns the smallest hashpower that will hold n elements.\n  static size_type reserve_calc(const size_type n) {\n    const size_type buckets = (n + SLOT_PER_BUCKET - 1) / SLOT_PER_BUCKET;\n    size_type blog2;\n    for (blog2 = 0; (size_type(1) << blog2) < buckets; ++blog2)\n      ;\n    assert(n <= buckets * SLOT_PER_BUCKET && buckets <= hashsize(blog2));\n    return blog2;\n  }\n\n  locks_t &get_current_locks() const { return all_locks_.get_tail()->elt; }\n\n  // Member variables\n\n  // The hash function\n  hasher hash_fn_;\n\n  // The equality function\n  key_equal eq_fn_;\n\n  // container of buckets. The size or memory location of the buckets cannot be\n  // changed unless all the locks are taken on the table. Thus, it is only safe\n  // to access the buckets_ container when you have at least one lock held.\n  buckets_t buckets_;\n\n  // A linked list of all lock containers. We never discard lock containers,\n  // since there is currently no mechanism for detecting when all threads are\n  // done looking at the memory. The back lock container in this list is\n  // designated the \"current\" one, and is used by all operations taking locks.\n  // This container can be modified if either it is empty (which should only\n  // occur during construction), or if the modifying thread has taken all the\n  // locks on the existing \"current\" container. In the latter case, a\n  // modification must take place before a modification to the hashpower, so\n  // that other threads can detect the change and adjust appropriately. Marked\n  // mutable so that const methods can access and take locks.\n  mutable all_locks_t all_locks_;\n\n  // stores the minimum load factor allowed for automatic expansions. Whenever\n  // an automatic expansion is triggered (during an insertion where cuckoo\n  // hashing fails, for example), we check the load factor against this\n  // double, and return an error if it's lower than this value. It can be\n  // used to signal when the hash function is bad or the input adversarial.\n  std::atomic<double> minimum_load_factor_;\n\n  // stores the maximum hashpower allowed for any expansions. If set to\n  // NO_MAXIMUM_HASHPOWER, this limit will be disregarded.\n  std::atomic<size_type> maximum_hashpower_;\n};\n\n#endif // _CUCKOOHASH_MAP_HH\n"
  },
  {
    "path": "experimental/Tests/libcuckoo/cpp/cuckoohash_util.hh",
    "content": "/** \\file */\n\n#ifndef _CUCKOOHASH_UTIL_HH\n#define _CUCKOOHASH_UTIL_HH\n\n#include \"cuckoohash_config.hh\" // for LIBCUCKOO_DEBUG\n#include <exception>\n#include <thread>\n#include <utility>\n#include <vector>\n\n#if LIBCUCKOO_DEBUG\n//! When \\ref LIBCUCKOO_DEBUG is 0, LIBCUCKOO_DBG will printing out status\n//! messages in various situations\n#define LIBCUCKOO_DBG(fmt, ...)                                                \\\n  fprintf(stderr, \"\\x1b[32m\"                                                   \\\n                  \"[libcuckoo:%s:%d:%lu] \" fmt \"\"                              \\\n                  \"\\x1b[0m\",                                                   \\\n          __FILE__, __LINE__,                                                  \\\n          std::hash<std::thread::id>()(std::this_thread::get_id()),            \\\n          __VA_ARGS__)\n#else\n//! When \\ref LIBCUCKOO_DEBUG is 0, LIBCUCKOO_DBG does nothing\n#define LIBCUCKOO_DBG(fmt, ...)                                                \\\n  do {                                                                         \\\n  } while (0)\n#endif\n\n/**\n * alignas() requires GCC >= 4.9, so we stick with the alignment attribute for\n * GCC.\n */\n#ifdef __GNUC__\n#define LIBCUCKOO_ALIGNAS(x) __attribute__((aligned(x)))\n#else\n#define LIBCUCKOO_ALIGNAS(x) alignas(x)\n#endif\n\n/**\n * At higher warning levels, MSVC produces an annoying warning that alignment\n * may cause wasted space: \"structure was padded due to __declspec(align())\".\n */\n#ifdef _MSC_VER\n#define LIBCUCKOO_SQUELCH_PADDING_WARNING __pragma(warning(suppress : 4324))\n#else\n#define LIBCUCKOO_SQUELCH_PADDING_WARNING\n#endif\n\n/**\n * At higher warning levels, MSVC may issue a deadcode warning which depends on\n * the template arguments given. For certain other template arguments, the code\n * is not really \"dead\".\n */\n#ifdef _MSC_VER\n#define LIBCUCKOO_SQUELCH_DEADCODE_WARNING_BEGIN                               \\\n  do {                                                                         \\\n    __pragma(warning(push));                                                   \\\n    __pragma(warning(disable : 4702))                                          \\\n  } while (0)\n#define LIBCUCKOO_SQUELCH_DEADCODE_WARNING_END __pragma(warning(pop))\n#else\n#define LIBCUCKOO_SQUELCH_DEADCODE_WARNING_BEGIN\n#define LIBCUCKOO_SQUELCH_DEADCODE_WARNING_END\n#endif\n\n#define ERROR_NONE                         0\n#define ERROR_INVALID_ARGUMENT             1\n#define ERROR_OUT_OF_RANGE                 2\n#define ERROR_HASHPOWER_CHANGED            3\n#define ERROR_LOAD_FACTOR_TOO_LOW          4\n#define ERROR_MAXIMUM_HASH_POWER_EXCEEDED  5\n\n#endif // _CUCKOOHASH_UTIL_HH\n"
  },
  {
    "path": "experimental/Tests/libcuckoo/cpp/libcuckoo_bucket_container.hh",
    "content": "#ifndef LIBCUCKOO_BUCKET_CONTAINER_H\n#define LIBCUCKOO_BUCKET_CONTAINER_H\n\n#include <array>\n#include <atomic>\n#include <cassert>\n#include <cstddef>\n#include <iostream>\n#include <memory>\n#include <type_traits>\n#include <utility>\n\n#include \"cuckoohash_util.hh\"\n#include \"cuckoohash_config.hh\"\n\ntypedef uint8_t Partial;\ntypedef KEY key_type;\ntypedef VALUE mapped_type;\ntypedef std::pair<const KEY, VALUE> value_type;\ntypedef Partial partial_t;\ntypedef std::size_t size_type;\ntypedef value_type & reference;\ntypedef const value_type & const_reference;\ntypedef value_type * pointer;\ntypedef const value_type * const_pointer;\ntypedef std::pair<KEY, VALUE> storage_value_type;\n\n/*\n * The bucket type holds SLOT_PER_BUCKET key-value pairs, along with their\n * partial keys and occupancy info. It uses aligned_storage arrays to store\n * the keys and values to allow constructing and destroying key-value pairs\n * in place. The lifetime of bucket data should be managed by the container.\n * It is the user's responsibility to confirm whether the data they are\n * accessing is live or not.\n */\nclass bucket {\npublic:\n  bucket() noexcept : occupied_{} {}\n\n  const value_type &kvpair(size_type ind) const {\n    return *static_cast<const value_type *>(\n        static_cast<const void *>(&values_[ind]));\n  }\n  value_type &kvpair(size_type ind) {\n    return *static_cast<value_type *>(static_cast<void *>(&values_[ind]));\n  }\n\n  const key_type &key(size_type ind) const {\n    return storage_kvpair(ind).first;\n  }\n\n  const mapped_type &mapped(size_type ind) const {\n    return storage_kvpair(ind).second;\n  }\n  mapped_type &mapped(size_type ind) { return storage_kvpair(ind).second; }\n\n  partial_t partial(size_type ind) const { return partials_[ind]; }\n  partial_t &partial(size_type ind) { return partials_[ind]; }\n\n  bool occupied(size_type ind) const { return occupied_[ind]; }\n  bool &occupied(size_type ind) { return occupied_[ind]; }\n\nprivate:\n  friend class libcuckoo_bucket_container;\n\n  const storage_value_type &storage_kvpair(size_type ind) const {\n    return *static_cast<const storage_value_type *>(\n        static_cast<const void *>(&values_[ind]));\n  }\n  storage_value_type &storage_kvpair(size_type ind) {\n    return *static_cast<storage_value_type *>(\n        static_cast<void *>(&values_[ind]));\n  }\n\n  std::array<typename std::aligned_storage<sizeof(storage_value_type),\n                                           alignof(storage_value_type)>::type,\n             SLOT_PER_BUCKET>\n      values_;\n  std::array<partial_t, SLOT_PER_BUCKET> partials_;\n  std::array<bool, SLOT_PER_BUCKET> occupied_;\n};\n\n/**\n * libcuckoo_bucket_container manages storage of key-value pairs for the table.\n * It stores the items inline in uninitialized memory, and keeps track of which\n * slots have live data and which do not. It also stores a partial hash for\n * each live key. It is sized by powers of two.\n */\nclass libcuckoo_bucket_container {\npublic:\n\n  libcuckoo_bucket_container(size_type hp)\n      : hashpower_(hp), buckets_(new bucket[size()]) {\n    // The bucket default constructor is nothrow, so we don't have to\n    // worry about dealing with exceptions when constructing all the\n    // elements.\n    static_assert(std::is_nothrow_constructible<bucket>::value,\n                  \"libcuckoo_bucket_container requires bucket to be nothrow \"\n                  \"constructible\");\n  }\n\n  ~libcuckoo_bucket_container() noexcept { destroy_buckets(); }\n\n  libcuckoo_bucket_container &operator=(const libcuckoo_bucket_container &bc) = delete;\n  libcuckoo_bucket_container(const libcuckoo_bucket_container &bc) = delete;\n\n  void swap(libcuckoo_bucket_container &bc) noexcept {\n    // Regardless of whether we actually swapped the allocators or not, it will\n    // always be okay to do the remainder of the swap. This is because if the\n    // allocators were swapped, then the subsequent operations are okay. If the\n    // allocators weren't swapped but compare equal, then we're okay. If they\n    // weren't swapped and compare unequal, then behavior is undefined, so\n    // we're okay.\n    size_t bc_hashpower = bc.hashpower();\n    bc.hashpower(hashpower());\n    hashpower(bc_hashpower);\n    std::swap(buckets_, bc.buckets_);\n  }\n\n  size_type hashpower() const {\n    return hashpower_.load(std::memory_order_acquire);\n  }\n\n  void hashpower(size_type val) {\n    hashpower_.store(val, std::memory_order_release);\n  }\n\n  size_type size() const { return size_type(1) << hashpower(); }\n\n  bucket &operator[](size_type i) { return buckets_[i]; }\n  const bucket &operator[](size_type i) const { return buckets_[i]; }\n\n  // Constructs live data in a bucket\n  void setKV(size_type ind, size_type slot, partial_t p, const KEY &k, const VALUE& value) {\n    bucket &b = buckets_[ind];\n    assert(!b.occupied(slot));\n    b.partial(slot) = p;\n    storage_value_type &kv = b.storage_kvpair(slot);\n    kv.first = k;\n    kv.second = value;\n    //\ttraits_::construct(allocator_, std::addressof(b.storage_kvpair(slot)), k, value);\n    // This must occur last, to enforce a strong exception guarantee\n    b.occupied(slot) = true;\n  }\n\n  // Destroys live data in a bucket\n  void eraseKV(size_type ind, size_type slot) {\n    bucket &b = buckets_[ind];\n    assert(b.occupied(slot));\n    b.occupied(slot) = false;\n  }\n\n  // Destroys all the live data in the buckets\n  void clear() noexcept {\n    static_assert(\n        std::is_nothrow_destructible<key_type>::value &&\n            std::is_nothrow_destructible<mapped_type>::value,\n        \"libcuckoo_bucket_container requires key and value to be nothrow \"\n        \"destructible\");\n    for (size_type i = 0; i < size(); ++i) {\n      bucket &b = buckets_[i];\n      for (size_type j = 0; j < SLOT_PER_BUCKET; ++j) {\n        if (b.occupied(j)) {\n          eraseKV(i, j);\n        }\n      }\n    }\n  }\n\nprivate:\n  void destroy_buckets() noexcept {\n    if (buckets_ == nullptr) {\n      return;\n    }\n    // The bucket default constructor is nothrow, so we don't have to\n    // worry about dealing with exceptions when constructing all the\n    // elements.\n    static_assert(std::is_nothrow_destructible<bucket>::value,\n                  \"libcuckoo_bucket_container requires bucket to be nothrow \"\n                  \"destructible\");\n    clear();\n    delete buckets_;\n    buckets_ = nullptr;\n  }\n\n  // This needs to be atomic, since it can be read and written by multiple\n  // threads not necessarily synchronized by a lock.\n  std::atomic<size_type> hashpower_;\n  // These buckets are protected by striped locks (external to the\n  // BucketContainer), which must be obtained before accessing a bucket.\n  bucket *buckets_;\n};\n\n#endif // LIBCUCKOO_BUCKET_CONTAINER_H\n"
  },
  {
    "path": "experimental/Tests/libcuckoo/cuckoo.arm",
    "content": "# include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\n#define SLOT_PER_BUCKET 4\n\n#define KeyType int64\n#define ValueType int64\n\n// cuckoohash_util.hh:66\n#define ERROR_NONE                         0\n#define ERROR_INVALID_ARGUMENT             1\n#define ERROR_OUT_OF_RANGE                 2\n#define ERROR_HASHPOWER_CHANGED            3\n#define ERROR_LOAD_FACTOR_TOO_LOW          4\n#define ERROR_MAXIMUM_HASH_POWER_EXCEEDED  5\n\n#define mapped_type ValueType\n#define key_type KeyType\n#define CuckooRecords CuckooRecord[MAX_BFS_PATH_LEN]\n\n// cuckoohash_map.hh:52\n#define partial_t uint8\n#define size_type uint64\n#define counter_type int64\n#define IS_SIMPLE false\n\n// cuckoohash_config.hh:26\n#define LIBCUCKOO_NO_MAXIMUM_HASHPOWER 0xffffffffffffffff\n\n// cuckoohash_map.hh:161\n#define kMaxNumLocks 65536\n\n// cuckoohash_map.hh:202\n#define MAX_BFS_PATH_LEN 5\n\n// cuckoohash_map.hh:265\n// 2 * (const_pow(SLOT_PER_BUCKET, MAX_BFS_PATH_LEN) - 1) / (SLOT_PER_BUCKET - 1)\n// 2 * (const_pow(4, 5) - 1) / (4 - 1)\n#define MAX_CUCKOO_COUNT 682\n\n#define lock_ind(bucket_ind) (bucket_ind & (kMaxNumLocks - 1))\n\n#define vector_bracket(v, idx) (v).data + idx\n#define vector_size(this) (this).len\n\n\n// Found declaration of `LockManager::LockManager' at 128:3\n#define LockManager_LockManager_default(this) \\\n  (this).lock := nullptr;\n\n// Found declaration of `LockManager::LockManager' at 129:3\n#define LockManager_LockManager(this, i_lock)  \\\n  (this).lock := i_lock;\n\n// Found declaration of `LockManager::~LockManager' at 140:3\n#define LockManager_destroy_LockManager(this) \\\n  if (this.lock != nullptr)                \\\n  {                                               \\\n    spinlock_unlock(this.lock);            \\\n  }\n\n// Found declaration of `TwoBuckets::TwoBuckets' at 170:3\n#define TwoBuckets_TwoBuckets_default(this) \\\n    LockManager_LockManager_default((this).first_manager_)   \\\n    LockManager_LockManager_default((this).second_manager_)\n\n// Found declaration of `TwoBuckets::TwoBuckets' at 171:3\n#define TwoBuckets_TwoBuckets(this, locks_ptr, i1_, i2_, tmp0) \\\n    (this).i1 := i1_;                                    \\\n    (this).i2 := i2_;                                    \\\n    tmp0 := vector_bracket(*locks_ptr, lock_ind(i1_));        \\\n    LockManager_LockManager((this).first_manager_, tmp0) \\\n    tmp0 := vector_bracket(*locks_ptr, lock_ind(i2_));        \\\n    LockManager_LockManager((this).second_manager_, if lock_ind(i1_) != lock_ind(i2_) then tmp0 else nullptr)\n\n#define TwoBuckets_destroy_TwoBuckets(this) \\\n    LockManager_destroy_LockManager(this.first_manager_)  \\\n    LockManager_destroy_LockManager(this.second_manager_)\n\n// Found declaration of `b_slot::b_slot' at 227:3\n#define b_slot_b_slot(this, b, p, d) \\\n  this.bucket := b;         \\\n  this.pathcode := p;       \\\n  this.depth := d;\n\n\n// Found declaration of `b_queue::b_queue' at 236:3\n#define b_queue_b_queue(this) \\\n  this.first_ := 0;   \\\n  this.last_ := 0;\n\n// Found declaration of `b_queue::enqueue' at 238:3\n#define b_queue_enqueue(this, x)  \\\n  this.slots_[this.last_] := x;    \\\n  this.last_ := this.last_ + 1;\n\n// Found declaration of `b_queue::dequeue' at 243:3\n#define b_queue_dequeue(this, ret)  \\\n  ret := this.slots_[this.first_];  \\\n  this.first_ := this.first_ + 1;\n\n// Found declaration of `b_queue::empty' at 250:3\n#define b_queue_empty(this) \\\n  this.first_ == this.last_\n\n// Found declaration of `AllLocksManager::AllLocksManager' at 289:3\n#define AllLocksManager_AllLocksManager(this, i_first_locked) \\\n  (this).first_locked := i_first_locked;  \\\n  (this).active := TRUE;\n\n// #define copy_hash_value(lv, rv) \\\n//   lv.hash := rv.hash; \\\n//   lv.partial := rv.partial;\n\n#define copy_LockManager(lv, rv) \\\n  (lv).lock := (rv).lock;\n\n#define copy_TwoBuckets(lv, rv) \\\n  (lv).i1 := (rv).i1; \\\n  (lv).i2 := (rv).i2; \\\n  copy_LockManager((lv).first_manager_, (rv).first_manager_) \\\n  copy_LockManager((lv).second_manager_, (rv).second_manager_)\n\n#define copy_spinlock(lv, rv) \\\n  (lv).lock_ := (rv).lock_; \\\n  (lv).elem_counter_ := (rv).elem_counter_;\n\n#define bool_t uint8\n#define FALSE 0\n#define TRUE 1\n\n#define nullptr null\n\n// cuckoohash_map:318\n#define cuckoo_status uint8\n#define ok 0\n#define failure 1\n#define failure_key_not_found 2\n#define failure_key_duplicated 3\n#define failure_table_full 4\n#define failure_under_expansion 5\n\n// FIXME(double): Need to have double/floats on the heap\n#define double uint64\n\nstructs SharedStructs {\n\n    struct storage_value_type {\n        var first: KeyType;\n        var second: ValueType;\n    }\n\n    struct bucket {\n        // std::array<typename std::aligned_storage<sizeof(storage_value_type),\n                                                // alignof(storage_value_type)>::type,\n                // SLOT_PER_BUCKET>\n            // values_;\n        // std::array<partial_t, SLOT_PER_BUCKET> partials_;\n        // std::array<bool, SLOT_PER_BUCKET> occupied_;\n\n        var values_:storage_value_type[SLOT_PER_BUCKET]\n        var partials_:partial_t[SLOT_PER_BUCKET];\n        var occupied_:bool_t[SLOT_PER_BUCKET];\n    }\n\n    // cuckoohash_map.hh:59\n    struct spinlock {\n      // std::atomic_flag\n        var lock_:bool_t;\n        var elem_counter_:counter_type;\n    }\n\n    // cuckoohash_map.hh:92\n    struct locks_t {\n        var data:ptr<spinlock>;\n        var len:uint64;\n    }\n\n    // cuckoohash_map.hh:94\n    struct all_locks_list_node {\n        var elt:locks_t;\n        var next:ptr<all_locks_list_node>;\n    }\n\n    // cuckoohash_map.hh:101\n    struct all_locks_t {\n        var head_:ptr<all_locks_list_node>;\n        var tail_:ptr<all_locks_list_node>;\n    }\n\n    // cuckoohash_map.hh:126\n    struct LockManager {\n        var lock:ptr<spinlock>;\n    }\n\n    // cuckoohash_map.hh:168\n    struct TwoBuckets {\n        var i1:size_type;\n        var i2:size_type;\n        var first_manager_:LockManager;\n        var second_manager_:LockManager;\n    }\n\n    // cuckoohash_map.hh:205\n    struct b_slot{\n      var bucket: size_type;\n      var pathcode: uint16;\n      var depth: int8;\n    }\n\n    // cuckoohash_map.hh:233\n    struct b_queue {\n      var slots_: b_slot[MAX_CUCKOO_COUNT];\n      var first_: size_type;\n      var last_: size_type;\n    }\n\n    // cuckoohash_map:282\n    struct hash_value {\n        var hash:size_type;\n        var partial:partial_t;\n    }\n\n    // cuckoohash_map:282\n    struct AllLocksManager {\n      var active: bool_t;\n      var first_locked: ptr<all_locks_list_node>;\n    }\n\n    // cuckoohash_map.hh:327\n    struct table_position {\n        var index:size_type;\n        var slot:size_type;\n        var status:cuckoo_status;\n    }\n\n    // cuckoohash_map.hh:339\n    struct CuckooRecord {\n      var bucket: size_type;\n      var slot: size_type;\n      var hv: hash_value;\n    }\n\n    // libcuckoo_bucket_container.hh:89\n    struct bucket_container {\n        var hashpower_:size_type; //atomic\n        var buckets_:ptr<bucket>;\n    }\n\n    // cuckoohash_map.hh:351\n    struct cuckoohash_map {\n        // The hash function\n        // hasher hash_fn_;\n\n        // The equality function\n        // key_equal eq_fn_;\n\n        var buckets_:bucket_container;\n        var all_locks_:all_locks_t;\n        var minimum_load_factor_num: uint64;\n        var minimum_load_factor_dec: uint64; //double\n        var maximum_hashpower_:size_type; //atomic\n    }\n\n}\n\nlevel {:concrete} CuckooHashMap using SharedStructs {\n\n////////////////////////////////////////////////////////////////////////////////\n// external methods\n////////////////////////////////////////////////////////////////////////////////\nmethod {:extern} ext_hash_function(k:KeyType) returns (ret:size_type)\nmethod {:extern} ext_key_eq(k1:KeyType, k2:KeyType) returns (ret:bool_t)\nmethod {:extern} ext_hardware_concurrency() returns (ret: size_type)\n\n\n////////////////////////////////////////////////////////////////////////////////\n// libcuckoo_bucket_container.hh\n////////////////////////////////////////////////////////////////////////////////\n\n\n// // Found declaration of `bucket::bucket' at 38:3\n// method bucket_bucket(TODO_method_params)\n// {\n// }\n// \n// \n// // Found declaration of `bucket::kvpair' at 40:3\n// method bucket_kvpair(TODO_method_params)\n// {\n//   return *TODO_expr__CXXStaticCastExpr:TODO_type_Pointer;\n// }\n// \n// \n// // Found declaration of `bucket::kvpair' at 44:3\n// method bucket_kvpair(TODO_method_params)\n// {\n//   return *TODO_expr__CXXStaticCastExpr:TODO_type_Pointer;\n// }\n// \n\n// Found declaration of `bucket::key' at 48:3\nmethod bucket_key(this_ptr:ptr<bucket>, ind:size_type) returns (ret:ptr<key_type>)\n{\n  noaddr var temp0:ptr<storage_value_type>;\n  temp0 := bucket_storage_kvpair(this_ptr, ind);\n  ret := &((*temp0).first);\n}\n\n\n// Found declaration of `bucket::mapped' at 52:3\nmethod bucket_mapped(this_ptr:ptr<bucket>, ind:size_type) returns (ret:ptr<mapped_type>)\n{\n  noaddr var temp0:ptr<storage_value_type>;\n  temp0 := bucket_storage_kvpair(this_ptr, ind);\n  ret := &((*temp0).second);\n}\n\n\n// Found declaration of `bucket::partial' at 57:3\nmethod bucket_partial_const(this_ptr:ptr<bucket>, ind:size_type) returns (ret:partial_t)\n{\n  ret := (*this_ptr).partials_[ind];\n}\n\n\n// Found declaration of `bucket::partial' at 58:3\nmethod bucket_partial(this_ptr:ptr<bucket>, ind:size_type) returns (ret:ptr<partial_t>)\n{\n  ret := &(*this_ptr).partials_[ind];\n}\n\n\n// Found declaration of `bucket::occupied' at 60:3\nmethod bucket_occupied_const(this_ptr:ptr<bucket>, ind:size_type) returns (ret:bool_t)\n{\n  ret := (*this_ptr).occupied_[ind];\n}\n\n\n// Found declaration of `bucket::occupied' at 61:3\nmethod bucket_occupied(this_ptr:ptr<bucket>, ind:size_type) returns (ret:ptr<bool_t>)\n{\n  ret := &(*this_ptr).occupied_[ind];\n}\n\n\n// Found declaration of `bucket::storage_kvpair' at 66:3\nmethod bucket_storage_kvpair(this_ptr:ptr<bucket>, ind:size_type) returns (ret:ptr<storage_value_type>)\n{\n  ret := &((*this_ptr).values_[ind]);\n}\n\n\n// Found declaration of `libcuckoo_bucket_container::libcuckoo_bucket_container' at 92:3\nmethod bucket_container_bucket_container(this_ptr: ptr<bucket_container>, hp: size_type)\n{\n  noaddr var temp0: size_type;\n  (*this_ptr).hashpower_ := hp;\n  temp0 := libcuckoo_bucket_container_size(this_ptr);\n  (*this_ptr).buckets_ := calloc(bucket, temp0);\n}\n\n// \n// // Found declaration of `libcuckoo_bucket_container::~libcuckoo_bucket_container' at 102:3\n// method libcuckoo_bucket_container_~libcuckoo_bucket_container(TODO_method_params)\n// {\n//   (*this).destroy_buckets();\n// }\n// \n// \n// // Found declaration of `libcuckoo_bucket_container::operator=' at 104:3\n// method libcuckoo_bucket_container_operator=(TODO_method_params)\n// {\n// }\n// \n// \n// // Found declaration of `libcuckoo_bucket_container::libcuckoo_bucket_container' at 105:3\n// method libcuckoo_bucket_container_libcuckoo_bucket_container(TODO_method_params)\n// {\n// }\n// \n// \n// // Found declaration of `libcuckoo_bucket_container::swap' at 107:3\n// method libcuckoo_bucket_container_swap(TODO_method_params)\n// {\n//   noaddr var bc_hashpower:size_t;\n//   noaddr var temp0:TODO_return_type;\n//   bc_hashpower := *(bc_ptr).hashpower();\n//   temp0 := (*this).hashpower();\n//   *(bc_ptr).hashpower(temp0);\n//   (*this).hashpower(bc_hashpower);\n//   swap((*this).buckets_, *(bc_ptr).buckets_);\n// }\n// \n\n// Found declaration of `libcuckoo_bucket_container::hashpower' at 120:3\nmethod libcuckoo_bucket_container_hashpower(this_ptr:ptr<bucket_container>) returns (ret:size_type)\n{\n  ret := (*this_ptr).hashpower_;\n}\n\n// \n// // Found declaration of `libcuckoo_bucket_container::hashpower' at 124:3\n// method libcuckoo_bucket_container_hashpower(TODO_method_params)\n// {\n//   (*this).hashpower_.store(val, memory_order_release);\n// }\n// \n\n// Found declaration of `libcuckoo_bucket_container::size' at 128:3\nmethod libcuckoo_bucket_container_size(this_ptr:ptr<bucket_container>) returns (ret:size_type)\n{\n  noaddr var temp0: size_type;\n  temp0 := libcuckoo_bucket_container_hashpower(this_ptr);\n  ret := 1 << temp0;\n}\n\n// \n// // Found declaration of `libcuckoo_bucket_container::operator[]' at 130:3\n// method libcuckoo_bucket_container_operator[](TODO_method_params)\n// {\n//   return i[(*this).buckets_];\n// }\n// \n// \n// // Found declaration of `libcuckoo_bucket_container::operator[]' at 131:3\n// method libcuckoo_bucket_container_operator[](TODO_method_params)\n// {\n//   return i[(*this).buckets_];\n// }\n\n\n// Found declaration of `libcuckoo_bucket_container::setKV' at 134:3\nmethod libcuckoo_bucket_container_setKV(this_ptr: ptr<bucket_container>, ind: size_type, slot: size_type, p: partial_t, k_ptr: ptr<KeyType>, value_ptr: ptr<ValueType>)\n{\n  noaddr var b_ptr:ptr<bucket>;\n  noaddr var temp0:ptr<partial_t>;\n  noaddr var kv_ptr:ptr<storage_value_type>;\n  noaddr var temp1:ptr<bool_t>;\n  noaddr var k: KeyType := *k_ptr;\n  noaddr var value: ValueType := *value_ptr;\n  b_ptr := (*this_ptr).buckets_ + ind;\n  // assert(!b.occupied(slot));\n  temp0 := bucket_partial(b_ptr, slot);\n  *temp0 := p;\n  kv_ptr := bucket_storage_kvpair(b_ptr, slot);\n  (*kv_ptr).first := k;\n  (*kv_ptr).second := value;\n  temp1 := bucket_occupied(b_ptr, slot);\n  *temp1 := TRUE;\n}\n\n\n// Found declaration of `libcuckoo_bucket_container::eraseKV' at 147:3\nmethod libcuckoo_bucket_container_eraseKV(this_ptr: ptr<bucket_container>, ind: size_type, slot: size_type)\n{\n  noaddr var b_ptr:ptr<bucket>;\n  noaddr var temp0: ptr<bool_t>;\n\n  b_ptr := (*this_ptr).buckets_ + ind;\n//  assert(b.occupied(slot));\n  temp0 := bucket_occupied(b_ptr, slot);\n  *temp0 := FALSE;\n}\n\n\n// Found declaration of `libcuckoo_bucket_container::clear' at 154:3\nmethod libcuckoo_bucket_container_clear(this_ptr: ptr<bucket_container>)\n{\n  noaddr var temp0: size_type;\n  noaddr var i: size_type;\n  noaddr var b_ptr: ptr<bucket>;\n  noaddr var j: size_type;\n  noaddr var temp1: bool_t;\n\n  temp0 := libcuckoo_bucket_container_size(this_ptr);\n  i := 0;\n  while (i < temp0)\n  {\n    b_ptr := (*this_ptr).buckets_ + i;\n    j := 0;\n    while (j < SLOT_PER_BUCKET)\n    {\n      temp1 := bucket_occupied_const(b_ptr, j);\n      if (temp1 != FALSE)\n      {\n        libcuckoo_bucket_container_eraseKV(this_ptr, i, j);\n      }\n      j := j + 1;\n    }\n    i := i + 1;\n  }\n}\n\n\n// Found declaration of `libcuckoo_bucket_container::destroy_buckets' at 171:3\nmethod libcuckoo_bucket_container_destroy_buckets(this_ptr: ptr<bucket_container>)\n{\n  if ((*this_ptr).buckets_ == null)\n  {\n    return;\n  }\n\n  libcuckoo_bucket_container_clear(this_ptr);\n  dealloc (*this_ptr).buckets_;\n  (*this_ptr).buckets_ := null;\n}\n\n\n////////////////////////////////////////////////////////////////////////////////\n// cuckoohash_map.hh\n////////////////////////////////////////////////////////////////////////////////\n\n// Found declaration of `spinlock::spinlock' at 61:3\nmethod spinlock_spinlock(this_ptr:ptr<spinlock>) returns ()\n{\n  (*this_ptr).elem_counter_ := 0;\n  (*this_ptr).lock_ := FALSE;\n}\n\n// \n// // Found declaration of `spinlock::spinlock' at 63:3\n// method spinlock_spinlock(TODO_method_params)\n// {\n//   atomic_flag_clear(&((*this).lock_), TODO_expr__CXXDefaultArgExpr:TODO_type_Enum);\n// }\n// \n// \n// // Found declaration of `spinlock::operator=' at 67:3\n// method spinlock_operator=(TODO_method_params)\n// {\n//   noaddr var temp0:TODO_return_type;\n//   noaddr var temp1:TODO_return_type;\n//   temp0 := spinlock_elem_counter(this);\n//   temp1 := spinlock_elem_counter(other_ptr);\n//   temp0 := temp1;\n//   return *TODO_expr__CXXThisExpr:TODO_type_Pointer;\n// }\n// \n\n// Found declaration of `spinlock::lock' at 72:3\nmethod spinlock_lock(this_ptr:ptr<spinlock>) returns ()\n{\n  noaddr var temp0:bool_t;\n  temp0 := compare_and_swap(((*this_ptr).lock_), FALSE, TRUE);\n  while (temp0 == FALSE)\n  {\n    temp0 := compare_and_swap(((*this_ptr).lock_), FALSE, TRUE);\n  }\n\n}\n\n\n// Found declaration of `spinlock::unlock' at 77:3\nmethod spinlock_unlock(this_ptr:ptr<spinlock>)\n{\n    (*this_ptr).lock_ := FALSE;\n}\n\n// \n// // Found declaration of `spinlock::try_lock' at 79:3\n// method spinlock_try_lock(TODO_method_params)\n// {\n//   noaddr var temp0:TODO_return_type;\n//   temp0 := atomic_flag_test_and_set(&((*this).lock_), memory_order_acq_rel);\n//   return !temp0;\n// }\n\n\n// Found declaration of `spinlock::elem_counter' at 83:3\nmethod spinlock_elem_counter(this_ptr: ptr<spinlock>) returns (ret: ptr<counter_type>)\n{\n  ret := &(*this_ptr).elem_counter_;\n}\n\n\n// // Found declaration of `spinlock::elem_counter' at 85:3\n// method spinlock_elem_counter(TODO_method_params)\n// {\n//   return (*this).elem_counter_;\n// }\n// \n\n// Found declaration of `all_locks_list_node::all_locks_list_node' at 95:3\nmethod all_locks_list_node_all_locks_list_node(this_ptr: ptr<all_locks_list_node>, lock_count: size_type)\n{\n  (*this_ptr).elt.len := lock_count;\n  (*this_ptr).elt.data := calloc(spinlock, lock_count);\n  (*this_ptr).next := null;\n}\n\n// \n// // Found declaration of `all_locks_t::all_locks_t' at 103:3\n// method all_locks_t_all_locks_t(TODO_method_params)\n// {\n//   (*this).tail_ := TODO_expr__CXXNewExpr:TODO_type_Pointer;\n//   (*this).head_ := (*this).tail_;\n// }\n// \n\n// Found declaration of `all_locks_t::append' at 108:3\nmethod all_locks_t_append(this_ptr: ptr<all_locks_t>, new_tail: ptr<all_locks_list_node>)\n{\n  noaddr var tail: ptr<all_locks_list_node>;\n  tail := (*this_ptr).tail_;\n  (*tail).next := new_tail;\n  (*this_ptr).tail_ := new_tail;\n}\n\n\n// Found declaration of `all_locks_t::get_tail' at 113:3\nmethod all_locks_t_get_tail(this_ptr:ptr<all_locks_t>) returns (ret:ptr<all_locks_list_node>)\n{\n  ret := (*this_ptr).tail_;\n}\n\n\n\n\n\n// \n// // Found declaration of `LockManager::LockManager' at 131:3\n// method LockManager_LockManager(TODO_method_params)\n// {\n//   swap((*this).lock, *(other_ptr).lock);\n// }\n// \n// \n// // Found declaration of `LockManager::operator=' at 135:3\n// method LockManager_operator=(TODO_method_params)\n// {\n//   swap((*this).lock, *(other_ptr).lock);\n//   return *TODO_expr__CXXThisExpr:TODO_type_Pointer;\n// }\n// \n\n\n\n// Found declaration of `LockManager::reset' at 146:3\nmethod LockManager_reset(this_ptr: ptr<LockManager>)\n{\n  if ((*this_ptr).lock != null)\n  {\n    spinlock_unlock((*this_ptr).lock);\n    (*this_ptr).lock := null;\n  }\n}\n\n\n// // Found declaration of `LockManager::swap' at 153:3\n// method LockManager_swap(TODO_method_params)\n// {\n//   swap((*this).lock, *(other_ptr).lock);\n// }\n// \n\n// Found declaration of `LockManager::swap' at 164:3\n//function lock_ind(bucket_ind:size_type): size_type\n//{\n//  bucket_ind & (kMaxNumLocks - 1)\n//}\n\n\n\n// \n// // Found declaration of `TwoBuckets::TwoBuckets' at 175:3\n// method TwoBuckets_TwoBuckets(TODO_method_params)\n// {\n//   LockManager_swap(&((*this).first_manager_), *(other_ptr).first_manager_);\n//   LockManager_swap(&((*this).second_manager_), *(other_ptr).second_manager_);\n// }\n// \n// \n// // Found declaration of `TwoBuckets::operator=' at 181:3\n// method TwoBuckets_operator=(TODO_method_params)\n// {\n//   (*this).i1 := *(other_ptr).i1;\n//   (*this).i2 := *(other_ptr).i2;\n//   LockManager_swap(&((*this).first_manager_), *(other_ptr).first_manager_);\n//   LockManager_swap(&((*this).second_manager_), *(other_ptr).second_manager_);\n//   return *TODO_expr__CXXThisExpr:TODO_type_Pointer;\n// }\n// \n\n// Found declaration of `TwoBuckets::unlock' at 189:3\nmethod TwoBuckets_unlock(this_ptr: ptr<TwoBuckets>)\n{\n  LockManager_reset(&((*this_ptr).first_manager_));\n  LockManager_reset(&((*this_ptr).second_manager_));\n}\n\n// \n// // Found declaration of `b_slot::b_slot' at 226:3\n// method b_slot_b_slot(TODO_method_params)\n// {\n// }\n// \n// \n// // Found declaration of `b_queue::full' at 252:3\n// method b_queue_full(TODO_method_params)\n// {\n//   return (*this).last_ == MAX_CUCKOO_COUNT;\n// }\n// \n// \n\n// \n// // Found declaration of `AllLocksManager::AllLocksManager' at 293:3\n// method AllLocksManager_AllLocksManager(TODO_method_params)\n// {\n//   *(other_ptr).active := false;\n// }\n// \n// \n// // Found declaration of `AllLocksManager::operator=' at 298:3\n// method AllLocksManager_operator=(TODO_method_params)\n// {\n// }\n\n\n// Found declaration of `AllLocksManager::~AllLocksManager' at 300:3\nmethod AllLocksManager_destroy_AllLocksManager(this_ptr: ptr<AllLocksManager>)\n{\n  noaddr var it: ptr<all_locks_list_node>;\n  noaddr var locks_ptr: ptr<locks_t>;\n  noaddr var idx: size_type;\n\n  if ((*this_ptr).active != FALSE)\n  {\n    it := (*this_ptr).first_locked;\n    while (it != nullptr)\n    {\n      locks_ptr := &((*it).elt);\n      idx := 0;\n      while (idx < (*locks_ptr).len)\n      {\n        spinlock_unlock(vector_bracket(*locks_ptr, idx));\n        idx := idx + 1;\n      }\n      it := (*it).next;\n    }\n  }\n}\n\n// \n// // Found declaration of `cuckoohash_map::cuckoohash_map' at 368:3\n// method cuckoohash_map_cuckoohash_map(TODO_method_params)\n// {\n// }\n// \n// \n// // Found declaration of `cuckoohash_map::cuckoohash_map' at 380:3\n// method cuckoohash_map_cuckoohash_map(TODO_method_params)\n// {\n// }\n// \n// \n// // Found declaration of `cuckoohash_map::operator=' at 381:3\n// method cuckoohash_map_operator=(TODO_method_params)\n// {\n// }\n// \n// \n// // Found declaration of `cuckoohash_map::hash_function' at 401:3\n// method cuckoohash_map_hash_function(TODO_method_params)\n// {\n//   return TODO_expr__CXXConstructExpr:hasher;\n// }\n// \n// \n// // Found declaration of `cuckoohash_map::key_eq' at 408:3\n// method cuckoohash_map_key_eq(TODO_method_params)\n// {\n//   return TODO_expr__CXXConstructExpr:key_equal;\n// }\n// \n\n// Found declaration of `cuckoohash_map::hashpower' at 416:3\nmethod cuckoohash_map_hashpower(this_ptr:ptr<cuckoohash_map>) returns (ret:size_type)\n{\n  ret := libcuckoo_bucket_container_hashpower(&((*this_ptr).buckets_));\n}\n\n\n// Found declaration of `cuckoohash_map::bucket_count' at 423:3\nmethod cuckoohash_map_bucket_count(this_ptr:ptr<cuckoohash_map>) returns (ret: size_type)\n{\n  ret := libcuckoo_bucket_container_size(&(*this_ptr).buckets_);\n}\n\n\n// // Found declaration of `cuckoohash_map::empty' at 430:3\n// method cuckoohash_map_empty(TODO_method_params)\n// {\n//   noaddr var temp0:TODO_return_type;\n//   temp0 := cuckoohash_map_size(this);\n//   return temp0 == 0;\n// }\n// \n\n// Found declaration of `cuckoohash_map::size' at 437:3\nmethod cuckoohash_map_size(this_ptr:ptr<cuckoohash_map>) returns (ret: size_type)\n{\n  noaddr var counter_ptr: ptr<counter_type>;\n  noaddr var idx: uint64;\n  noaddr var locks: ptr<locks_t>;\n  idx := 0;\n  locks := cuckoohash_map_get_current_locks(this_ptr);\n  while (idx < (*locks).len) {\n    counter_ptr := spinlock_elem_counter((*locks).data + idx);\n    ret := ret + ((*counter_ptr) as size_type);\n  }\n  //assert(s >= 0);\n}\n\n\n// Found declaration of `cuckoohash_map::capacity' at 451:3\nmethod cuckoohash_map_capacity(this_ptr:ptr<cuckoohash_map>) returns (ret: size_type)\n{\n  noaddr var temp0: size_type;\n  temp0 := cuckoohash_map_bucket_count(this_ptr);\n  ret := temp0 * SLOT_PER_BUCKET;\n}\n\n\n// Found declaration of `cuckoohash_map::load_factor' at 459:3\nmethod cuckoohash_map_load_factor(this_ptr:ptr<cuckoohash_map>) returns (ret_num: uint64, ret_dec: uint64)\n{\n  ret_num := cuckoohash_map_size(this_ptr);\n  ret_dec := cuckoohash_map_capacity(this_ptr);\n}\n\n// \n// // Found declaration of `cuckoohash_map::minimum_load_factor' at 473:3\n// method cuckoohash_map_minimum_load_factor(TODO_method_params)\n// {\n//   if (mlf < TODO_expr__FloatingLiteral:double)\n//   {\n//     *(error_ptr) := 1;\n//   }\n//   else\n//   if (mlf > TODO_expr__FloatingLiteral:double)\n//   {\n//     *(error_ptr) := 1;\n//   }\n//   else\n//   {\n//     TODO_type_TemplateSpecialization_store(&((*this).minimum_load_factor_), mlf, memory_order_release);\n//     *(error_ptr) := 0;\n//   }\n// \n// }\n// \n// \n// // Found declaration of `cuckoohash_map::minimum_load_factor' at 490:3\n// method cuckoohash_map_minimum_load_factor(TODO_method_params)\n// {\n//   noaddr var temp0:TODO_return_type;\n//   temp0 := TODO_type_TemplateSpecialization_load(&((*this).minimum_load_factor_), memory_order_acquire);\n//   return temp0;\n// }\n// \n// \n// // Found declaration of `cuckoohash_map::maximum_hashpower' at 504:3\n// method cuckoohash_map_maximum_hashpower(TODO_method_params)\n// {\n//   noaddr var temp0:TODO_return_type;\n//   temp0 := cuckoohash_map_hashpower(this);\n//   if (temp0 > mhp)\n//   {\n//     *(error_ptr) := 1;\n//   }\n//   else\n//   {\n//     __atomic_base_store(&((*this).maximum_hashpower_), mhp, memory_order_release);\n//     *(error_ptr) := 0;\n//   }\n// \n// }\n// \n\n// Found declaration of `cuckoohash_map::maximum_hashpower' at 519:3\nmethod cuckoohash_map_maximum_hashpower(this_ptr:ptr<cuckoohash_map>) returns (ret: size_type)\n{\n  ret := (*this_ptr).maximum_hashpower_;\n}\n\n\n// Found declaration of `cuckoohash_map::find' at 529:3\nmethod cuckoohash_map_find(this_ptr:ptr<cuckoohash_map>, key_ptr:ptr<KeyType>, val_ptr:ptr<ValueType>) returns (ret:bool_t)\n{\n  var hv:hash_value;\n  noaddr var b:TwoBuckets;\n  noaddr var pos:table_position;\n  noaddr var temp_bucket_ptr:ptr<bucket>;\n  noaddr var temp_value_ptr:ptr<mapped_type>;\n  noaddr var temp_v: mapped_type;\n\n  cuckoohash_map_hashed_key(this_ptr, key_ptr, &hv);\n  b := cuckoohash_map_snapshot_and_lock_two(this_ptr, &hv);\n  pos := cuckoohash_map_cuckoo_find(this_ptr, key_ptr, hv.partial, b.i1, b.i2);\n  if (pos.status == ok)\n  {\n    // *(val_ptr) := libcuckoo_bucket_container_get(pos.index).mapped(pos.slot);\n    temp_bucket_ptr := (*this_ptr).buckets_.buckets_ + pos.index;\n    temp_value_ptr := bucket_mapped(temp_bucket_ptr, pos.slot);\n    temp_v := *temp_value_ptr;\n    *val_ptr := temp_v;\n    TwoBuckets_destroy_TwoBuckets(b)\n    ret := TRUE;\n  }\n  else\n  {\n    TwoBuckets_destroy_TwoBuckets(b)\n    ret := FALSE;\n  }\n}\n\n// \n// // Found declaration of `cuckoohash_map::find' at 548:3\n// method cuckoohash_map_find(TODO_method_params)\n// {\n//   noaddr var hv:hash_value;\n//   noaddr var b:TODO_type_Auto;\n//   noaddr var pos:table_position;\n//   noaddr var temp0:TODO_return_type;\n//   hv := TODO_expr__ExprWithCleanups:hash_value;\n//   b := TODO_expr__ExprWithCleanups:TODO_type_Auto;\n//   pos := TODO_expr__ExprWithCleanups:table_position;\n//   if (pos.status == ok)\n//   {\n//     *(error_ptr) := 0;\n//     temp0 := bucket_mapped(&(TODO_expr__CXXOperatorCallExpr:bucket), pos.slot);\n//     return temp0;\n//   }\n//   else\n//   {\n//     *(error_ptr) := 2;\n//     return TODO_expr__CXXScalarValueInitExpr:mapped_type;\n//   }\n// \n// }\n// \n// \n// // Found declaration of `cuckoohash_map::contains' at 564:3\n// method cuckoohash_map_contains(TODO_method_params)\n// {\n//   noaddr var hv:hash_value;\n//   noaddr var b:TODO_type_Auto;\n//   noaddr var pos:table_position;\n//   hv := TODO_expr__ExprWithCleanups:hash_value;\n//   b := TODO_expr__ExprWithCleanups:TODO_type_Auto;\n//   pos := TODO_expr__ExprWithCleanups:table_position;\n//   if (pos.status == ok)\n//   {\n//     return true;\n//   }\n//   else\n//   {\n//     return false;\n//   }\n// \n// }\n// \n// \n// // Found declaration of `cuckoohash_map::update' at 580:3\n// method cuckoohash_map_update(TODO_method_params)\n// {\n//   noaddr var hv:hash_value;\n//   noaddr var b:TODO_type_Auto;\n//   noaddr var pos:table_position;\n//   noaddr var temp0:TODO_return_type;\n//   hv := TODO_expr__ExprWithCleanups:hash_value;\n//   b := TODO_expr__ExprWithCleanups:TODO_type_Auto;\n//   pos := TODO_expr__ExprWithCleanups:table_position;\n//   if (pos.status == ok)\n//   {\n//     temp0 := bucket_mapped(&(TODO_expr__CXXOperatorCallExpr:bucket), pos.slot);\n//     temp0 := *(val_ptr);\n//     return true;\n//   }\n//   else\n//   {\n//     return false;\n//   }\n// \n// }\n// \n\n// Found declaration of `cuckoohash_map::insert' at 595:3\nmethod cuckoohash_map_insert(this_ptr:ptr<cuckoohash_map>, key_ptr:ptr<KeyType>, val_ptr:ptr<ValueType>, error: ptr<uint8>) returns (ret:bool_t)\n{\n  var hv:hash_value;\n  var b:TwoBuckets;\n  noaddr var pos:table_position;\n  noaddr var tmp_b: TwoBuckets;\n  cuckoohash_map_hashed_key(this_ptr, key_ptr, &hv);\n  tmp_b := cuckoohash_map_snapshot_and_lock_two(this_ptr, &hv);\n  copy_TwoBuckets(b, tmp_b)\n  pos := cuckoohash_map_cuckoo_insert_loop(this_ptr, &hv, &b, key_ptr, error);\n  if (pos.status == ok)\n  {\n    cuckoohash_map_add_to_bucket(this_ptr, pos.index, pos.slot, hv.partial, key_ptr, val_ptr);\n    TwoBuckets_destroy_TwoBuckets(b)\n    ret := TRUE;\n  }\n  else\n  {\n    TwoBuckets_destroy_TwoBuckets(b)\n    ret := FALSE;\n  }\n\n}\n\n\n// // Found declaration of `cuckoohash_map::insert_or_assign' at 611:3\n// method cuckoohash_map_insert_or_assign(TODO_method_params)\n// {\n//   noaddr var hv:hash_value;\n//   noaddr var b:TODO_type_Auto;\n//   noaddr var pos:table_position;\n//   noaddr var temp0:TODO_return_type;\n//   hv := TODO_expr__ExprWithCleanups:hash_value;\n//   b := TODO_expr__ExprWithCleanups:TODO_type_Auto;\n//   pos := TODO_expr__ExprWithCleanups:table_position;\n//   if (pos.status == ok)\n//   {\n//     cuckoohash_map_add_to_bucket(this, pos.index, pos.slot, hv.partial, *(key_ptr), *(val_ptr));\n//     return true;\n//   }\n//   else\n//   if (*(error_ptr) == 0)\n//   {\n//     temp0 := bucket_mapped(&(TODO_expr__CXXOperatorCallExpr:bucket), pos.slot);\n//     temp0 := *(val_ptr);\n//     return false;\n//   }\n//   else\n//   {\n//     return false;\n//   }\n// \n// }\n// \n// \n// // Found declaration of `cuckoohash_map::erase' at 631:3\n// method cuckoohash_map_erase(TODO_method_params)\n// {\n//   noaddr var hv:hash_value;\n//   noaddr var b:TODO_type_Auto;\n//   noaddr var pos:table_position;\n//   hv := TODO_expr__ExprWithCleanups:hash_value;\n//   b := TODO_expr__ExprWithCleanups:TODO_type_Auto;\n//   pos := TODO_expr__ExprWithCleanups:table_position;\n//   if (pos.status == ok)\n//   {\n//     cuckoohash_map_del_from_bucket(this, pos.index, pos.slot);\n//     return true;\n//   }\n//   else\n//   {\n//     return false;\n//   }\n// \n// }\n// \n// \n// // Found declaration of `cuckoohash_map::rehash' at 652:3\n// method cuckoohash_map_rehash(TODO_method_params)\n// {\n//   noaddr var temp0:TODO_return_type;\n//   temp0 := cuckoohash_map_cuckoo_rehash(this, n, *(error_ptr));\n//   return temp0;\n// }\n// \n// \n// // Found declaration of `cuckoohash_map::reserve' at 663:3\n// method cuckoohash_map_reserve(TODO_method_params)\n// {\n//   noaddr var temp0:TODO_return_type;\n//   temp0 := cuckoohash_map_cuckoo_reserve(this, n, *(error_ptr));\n//   return temp0;\n// }\n// \n// \n// // Found declaration of `cuckoohash_map::clear' at 668:3\n// method cuckoohash_map_clear(TODO_method_params)\n// {\n//   noaddr var all_locks_manager:TODO_type_Auto;\n//   all_locks_manager := TODO_expr__ExprWithCleanups:TODO_type_Auto;\n//   cuckoohash_map_cuckoo_clear(this);\n// }\n// \n\n// Found declaration of `cuckoohash_map::hashed_key' at 683:3\n// method cuckoohash_map_hashed_key(this_ptr:ptr<cuckoohash_map>, key_ptr:ptr<KeyType>, out: ptr<hash_value>)\n// {\n//   noaddr var hash:size_type;\n//   hash := ext_hash_function(*key_ptr);\n//   (*out).hash := hash;\n//   (*out).partial := cuckoohash_map_partial_key(hash);\n// }\n\nmethod cuckoohash_map_hashed_key_const(this_ptr:ptr<cuckoohash_map>, key_ptr:ptr<KeyType>) returns (out: hash_value)\n{\n  noaddr var hash:size_type;\n  hash := ext_hash_function(*key_ptr);\n  out.hash := hash;\n  out.partial := cuckoohash_map_partial_key(hash);\n}\n\nmethod cuckoohash_map_hashed_key(this_ptr:ptr<cuckoohash_map>, key_ptr:ptr<KeyType>, out_ptr: ptr<hash_value>)\n{\n  noaddr var hash:size_type;\n  hash := ext_hash_function(*key_ptr);\n  (*out_ptr).hash := hash;\n  (*out_ptr).partial := cuckoohash_map_partial_key(hash);\n}\n\n// Found declaration of `cuckoohash_map::hashed_key_only_hash' at 688:3\nmethod cuckoohash_map_hashed_key_only_hash(key_ptr:ptr<KeyType>) returns (ret:size_type)\n{\n  ret := ext_hash_function(*key_ptr);\n}\n\n\n// Found declaration of `cuckoohash_map::hashsize' at 694:3\nmethod cuckoohash_map_hashsize(hp:size_type) returns (ret:size_type)\n{\n  ret := (1 as size_type) << hp;\n}\n\n\n// Found declaration of `cuckoohash_map::hashmask' at 700:3\nmethod cuckoohash_map_hashmask(hp:size_type) returns (ret:size_type)\n{\n  noaddr var temp0:size_type;\n  temp0 := cuckoohash_map_hashsize(hp);\n  ret := temp0 - 1;\n}\n\n\n// Found declaration of `cuckoohash_map::partial_key' at 708:3\nmethod cuckoohash_map_partial_key(hash:size_type) returns (ret:partial_t)\n{\n  noaddr var hash_64bit:uint64;\n  noaddr var hash_32bit:uint32;\n  noaddr var hash_16bit:uint16;\n  noaddr var hash_8bit:uint8;\n  hash_64bit := hash;\n  hash_32bit := ((hash_64bit as uint32) ^ ((hash_64bit >> 32) as uint32));\n  hash_16bit := ((hash_32bit as uint16) ^ ((hash_32bit >> 16) as uint16));\n  hash_8bit := ((hash_16bit as uint8) ^ ((hash_16bit >> 8) as uint8));\n  ret := hash_8bit;\n}\n\n\n// Found declaration of `cuckoohash_map::index_hash' at 721:3\nmethod cuckoohash_map_index_hash(hp:size_type, hv:size_type) returns (ret:size_type)\n{\n  noaddr var temp0:size_type;\n  temp0 := cuckoohash_map_hashmask(hp);\n  ret := hv & temp0;\n}\n\n\n// Found declaration of `cuckoohash_map::alt_index' at 730:3\nmethod cuckoohash_map_alt_index(hp:size_type, partial:partial_t, index:size_type) returns (ret:size_type)\n{\n  noaddr var nonzero_tag:size_type;\n  noaddr var temp0:size_type;\n  nonzero_tag := (partial as size_type) + 1;\n  temp0 := cuckoohash_map_hashmask(hp);\n  ret := (index ^ (nonzero_tag * 0xc6a4a7935bd1e995)) & temp0;\n}\n\n\n// Found declaration of `cuckoohash_map::check_hashpower' at 742:3\nmethod cuckoohash_map_check_hashpower(this_ptr:ptr<cuckoohash_map>, hp:size_type, lock_ptr:ptr<spinlock>) returns (ret:int32)\n{\n  noaddr var temp0:size_type;\n  temp0 := cuckoohash_map_hashpower(this_ptr);\n  if (temp0 != hp)\n  {\n    spinlock_unlock(lock_ptr);\n    ret := ERROR_HASHPOWER_CHANGED;\n  }\n  else\n  {\n    ret := ERROR_NONE;\n  }\n}\n\n\n// Found declaration of `cuckoohash_map::lock_one' at 756:3\nmethod cuckoohash_map_lock_one(this_ptr: ptr<cuckoohash_map>, hp: size_type, i: size_type, error_ptr: ptr<int32>) returns (ret: LockManager)\n{\n  noaddr var locks_ptr: ptr<locks_t>;\n  noaddr var lock_ptr: ptr<spinlock>;\n  noaddr var temp0: int32;\n  locks_ptr := cuckoohash_map_get_current_locks(this_ptr);\n  lock_ptr := vector_bracket(*locks_ptr, lock_ind(i));\n  spinlock_lock(lock_ptr);\n  temp0 := cuckoohash_map_check_hashpower(this_ptr, hp, lock_ptr);\n  *(error_ptr) := temp0;\n  if ((*error_ptr) != ERROR_NONE)\n  {\n    ret.lock := null;\n  }\n\n  ret.lock := lock_ptr;\n}\n\n\n// Found declaration of `cuckoohash_map::lock_two' at 772:3\nmethod cuckoohash_map_lock_two(this_ptr:ptr<cuckoohash_map>, hp:size_type, i1:size_type, i2:size_type, error_ptr:ptr<int32>) returns (ret:TwoBuckets)\n{\n  noaddr var l1:size_type;\n  noaddr var l2:size_type;\n  noaddr var templ:size_type;\n  noaddr var locks_ptr:ptr<locks_t>;\n  noaddr var temp0:int32;\n  noaddr var tmpv: ptr<spinlock>;\n\n  l1 := lock_ind(i1);\n  l2 := lock_ind(i2);\n  if (l2 < l1)\n  {\n    templ := l2;\n    l2 := l1;\n    l1 := templ;\n  }\n\n  locks_ptr := cuckoohash_map_get_current_locks(this_ptr);\n  spinlock_lock(vector_bracket(*locks_ptr, l1));\n  temp0 := cuckoohash_map_check_hashpower(this_ptr, hp, vector_bracket(*locks_ptr, l1));\n  *(error_ptr) := temp0;\n  if ((*error_ptr) != 0)\n  {\n    TwoBuckets_TwoBuckets_default(ret)\n    return;\n  }\n\n  if (l2 != l1)\n  {\n    spinlock_lock(vector_bracket(*locks_ptr, l2));\n  }\n\n  TwoBuckets_TwoBuckets(ret, locks_ptr, i1, i2, tmpv)\n  return;\n}\n\n\n// Found declaration of `cuckoohash_map::lock_three' at 795:3\nmethod cuckoohash_map_lock_three(this_ptr: ptr<cuckoohash_map>, hp: size_type, i1: size_type, i2: size_type, i3: size_type, error_ptr: ptr<int32>) returns (ret1: TwoBuckets, ret2: LockManager)\n{\n  noaddr var l: size_type[3];\n  noaddr var locks_ptr:ptr<locks_t>;\n  noaddr var temp0: int32;\n  noaddr var tmpv: ptr<spinlock>;\n  l[0] := lock_ind(i1);\n  l[1] := lock_ind(i2);\n  l[2] := lock_ind(i3);\n  if (l[2] < l[1]) {\n    i1 := l[2];\n    l[2] := l[1];\n    l[1] := i1;\n  }\n  if (l[2] < l[0]) {\n    i1 := l[2];\n    l[2] := l[0];\n    l[0] := i1;\n  }\n  if (l[1] < l[0]) {\n    i1 := l[1];\n    l[1] := l[0];\n    l[0] := i1;\n  }\n  locks_ptr := cuckoohash_map_get_current_locks(this_ptr);\n  spinlock_lock(vector_bracket(*locks_ptr, l[0]));\n  temp0 := cuckoohash_map_check_hashpower(this_ptr, hp, vector_bracket(*locks_ptr, l[0]));\n  *error_ptr := temp0;\n  if ((*error_ptr) != ERROR_NONE)\n  {\n    TwoBuckets_TwoBuckets_default(ret1)\n    LockManager_LockManager_default(ret2)\n    return;\n  }\n\n  if (l[1] != l[0])\n  {\n    spinlock_lock(vector_bracket(*locks_ptr, l[1]));\n  }\n\n  if (l[2] != l[1])\n  {\n    spinlock_lock(vector_bracket(*locks_ptr, l[2]));\n  }\n\n  TwoBuckets_TwoBuckets(ret1, locks_ptr, i1, i2, tmpv)\n  LockManager_LockManager(ret2, if (lock_ind(i3) == lock_ind(i1) || lock_ind(i3) == lock_ind(i2))\n                                  then nullptr\n                                  else vector_bracket(*locks_ptr, lock_ind(i3)))\n}\n\n// Found declaration of `cuckoohash_map::snapshot_and_lock_two' at 832:3\nmethod cuckoohash_map_snapshot_and_lock_two(this_ptr:ptr<cuckoohash_map>, hv_ptr:ptr<hash_value>) returns (ret:TwoBuckets)\n{\n  noaddr var hp:size_type;\n  noaddr var i1:size_type;\n  noaddr var i2:size_type;\n  var error:int32;\n  noaddr var tb:TwoBuckets;\n  while (true)\n  {\n    hp := cuckoohash_map_hashpower(this_ptr);\n    i1 := cuckoohash_map_index_hash(hp, (*hv_ptr).hash);\n    i2 := cuckoohash_map_alt_index(hp, (*hv_ptr).partial, i1);\n    tb := cuckoohash_map_lock_two(this_ptr, hp, i1, i2, &error);\n    if (error == ERROR_HASHPOWER_CHANGED)\n    {\n      continue;\n    }\n    else\n    {\n      ret := tb;\n      return;\n    }\n  }\n}\n\n\n// Found declaration of `cuckoohash_map::snapshot_and_lock_all' at 857:3\nmethod cuckoohash_map_snapshot_and_lock_all(this_ptr:ptr<cuckoohash_map>) returns (ret: AllLocksManager)\n{\n  noaddr var first_locked: ptr<all_locks_list_node>;\n  noaddr var current_locks: ptr<all_locks_list_node>;\n  noaddr var locks_ptr:ptr<locks_t>;\n  noaddr var i: uint64;\n\n  first_locked := all_locks_t_get_tail(&(*this_ptr).all_locks_);\n  current_locks := first_locked;\n  while (current_locks != null)\n  {\n    locks_ptr := &((*current_locks).elt);\n    i := 0;\n    while (i < vector_size(*locks_ptr)) {\n      spinlock_lock(vector_bracket(*locks_ptr, i));\n    }\n    current_locks := (*current_locks).next;\n  }\n\n  AllLocksManager_AllLocksManager(ret, first_locked)\n}\n\n\n// Found declaration of `cuckoohash_map::cuckoo_find' at 877:3\nmethod cuckoohash_map_cuckoo_find(this_ptr:ptr<cuckoohash_map>, key_ptr:ptr<KeyType>, partial:partial_t, i1:size_type, i2:size_type) returns (ret:table_position)\n{\n  noaddr var slot:int32;\n  slot := cuckoohash_map_try_read_from_bucket(this_ptr, (*this_ptr).buckets_.buckets_ + i1, partial, key_ptr);\n  if (slot != -1)\n  {\n    ret.index := i1;\n    ret.slot := slot as size_type;\n    ret.status := ok;\n    return;\n  }\n\n  slot := cuckoohash_map_try_read_from_bucket(this_ptr, (*this_ptr).buckets_.buckets_ + i2, partial, key_ptr);\n  if (slot != -1)\n  {\n    ret.index := i2;\n    ret.slot := slot as size_type;\n    ret.status := ok;\n    return;\n  }\n\n  ret.index := 0;\n  ret.slot := 0;\n  ret.status := failure_key_not_found;\n  return;\n}\n\n\n// Found declaration of `cuckoohash_map::try_read_from_bucket' at 892:3\nmethod cuckoohash_map_try_read_from_bucket(this_ptr:ptr<cuckoohash_map>, b_ptr:ptr<bucket>, partial:partial_t, key_ptr:ptr<KeyType>)\n    returns (ret:int32)\n{\n  noaddr var i:int32;\n  noaddr var temp0:bool_t;\n  noaddr var temp1:partial_t;\n  noaddr var temp_key_ptr:ptr<KeyType>;\n  noaddr var temp_key:KeyType;\n  i := 0;\n  while (i < SLOT_PER_BUCKET)\n  {\n    temp0 := bucket_occupied_const(b_ptr, i as uint64);\n    temp1 := bucket_partial_const(b_ptr, i as uint64);\n    if (temp0 == FALSE || (!IS_SIMPLE && partial != temp1))\n    {\n      continue;\n    }\n    else\n    {\n      temp_key_ptr := bucket_key(b_ptr, i as uint64);\n      temp_key := *temp_key_ptr;\n      temp0 := ext_key_eq(temp_key, *key_ptr);\n      if (temp0 == TRUE) {\n        ret := i;\n        return;\n      }\n    }\n    i := i + 1;\n  }\n  ret := -1;\n}\n\n\n// Found declaration of `cuckoohash_map::cuckoo_insert_loop' at 922:3\nmethod cuckoohash_map_cuckoo_insert_loop(this_ptr:ptr<cuckoohash_map>, hv_ptr: ptr<hash_value>, b_ptr: ptr<TwoBuckets>, key_ptr: ptr<KeyType>, error_ptr: ptr<uint8>) returns (ret: table_position)\n{\n  noaddr var pos:table_position;\n  noaddr var hp:size_type;\n  noaddr var tmp_b: TwoBuckets;\n  noaddr var tmp: cuckoo_status;\n  *(error_ptr) := 0;\n  while (true)\n  {\n    hp := cuckoohash_map_hashpower(this_ptr);\n    pos := cuckoohash_map_cuckoo_insert(this_ptr, *hv_ptr, b_ptr, key_ptr);\n    if (pos.status == ok || pos.status == failure_key_duplicated)\n    {\n      ret := pos;\n      return;\n    }\n    else if (pos.status == failure_table_full)\n    {\n      tmp := cuckoohash_map_cuckoo_fast_double(this_ptr, hp, TRUE, error_ptr);\n      if ((*error_ptr) != ERROR_NONE) {\n        ret := pos;\n        return;\n      }\n      TwoBuckets_destroy_TwoBuckets((*b_ptr))\n      tmp_b := cuckoohash_map_snapshot_and_lock_two(this_ptr, hv_ptr);\n      copy_TwoBuckets((*b_ptr), tmp_b)\n    }\n    else if (pos.status == failure_under_expansion)\n    {\n      TwoBuckets_destroy_TwoBuckets((*b_ptr))\n      tmp_b := cuckoohash_map_snapshot_and_lock_two(this_ptr, hv_ptr);\n      copy_TwoBuckets((*b_ptr), tmp_b)\n    }\n//    else {\n//      assert FALSE;\n//    }\n  }\n}\n\n\n// Found declaration of `cuckoohash_map::cuckoo_insert' at 969:3\nmethod cuckoohash_map_cuckoo_insert(this_ptr:ptr<cuckoohash_map>, hv: hash_value, b_ptr: ptr<TwoBuckets>, key_ptr: ptr<KeyType>) returns (ret: table_position)\n{\n  noaddr var b1_ptr: ptr<bucket>;\n  noaddr var temp1: bool_t;\n  noaddr var b2_ptr: ptr<bucket>;\n  noaddr var temp2: bool_t;\n  noaddr var insert_bucket_ptr: ptr<size_type>;\n  noaddr var insert_slot_ptr: ptr<size_type>;\n  noaddr var st:cuckoo_status;\n  noaddr var pos:table_position;\n  noaddr var tmp_v: size_type;\n  noaddr var res1_ptr: ptr<int32>;\n  noaddr var res2_ptr: ptr<int32>;\n  tmp_v := (*b_ptr).i1;\n  b1_ptr := (*this_ptr).buckets_.buckets_ + tmp_v;\n  temp1 := cuckoohash_map_try_find_insert_bucket(this_ptr, b1_ptr, res1_ptr, hv.partial, key_ptr);\n  if (temp1 != 0)\n  {\n    ret.index := (*b_ptr).i1;\n    ret.slot := (*res1_ptr) as size_type;\n    ret.status := failure_key_duplicated;\n    return;\n  }\n\n  tmp_v := (*b_ptr).i2;\n  b2_ptr := (*this_ptr).buckets_.buckets_ + tmp_v;\n  temp2 := cuckoohash_map_try_find_insert_bucket(this_ptr, b2_ptr, res2_ptr, hv.partial, key_ptr);\n  if (temp2 != 0)\n  {\n    ret.index := (*b_ptr).i2;\n    ret.slot := (*res2_ptr) as size_type;\n    ret.status := failure_key_duplicated;\n    return;\n  }\n\n  if ((*res1_ptr) != -1)\n  {\n    ret.index := (*b_ptr).i1;\n    ret.slot := *res1_ptr as size_type;\n    ret.status := ok;\n    return;\n  }\n\n  if ((*res2_ptr) != -1)\n  {\n    ret.index := (*b_ptr).i2;\n    ret.slot := *res2_ptr as size_type;\n    ret.status := ok;\n    return;\n  }\n\n  *insert_bucket_ptr := 0;\n  *insert_slot_ptr := 0;\n  st := cuckoohash_map_run_cuckoo(this_ptr, b_ptr, insert_bucket_ptr, insert_slot_ptr);\n  if (st == failure_under_expansion)\n  {\n    ret.index := 0;\n    ret.slot := 0;\n    ret.status := failure_under_expansion;\n    return;\n  }\n  else\n  if (st == ok)\n  {\n//      assert(!get_current_locks()[lock_ind(b.i1)].try_lock());\n//      assert(!get_current_locks()[lock_ind(b.i2)].try_lock());\n//      assert(!buckets_[insert_bucket].occupied(insert_slot));\n//      assert(insert_bucket == index_hash(hashpower(), hv.hash) ||\n//             insert_bucket == alt_index(hashpower(), hv.partial,\n//                                        index_hash(hashpower(), hv.hash)));\n\n    tmp_v := (*b_ptr).i2;\n    pos := cuckoohash_map_cuckoo_find(this_ptr, key_ptr, hv.partial, (*b_ptr).i1, tmp_v);\n    if (pos.status == ok)\n    {\n      ret.index := pos.index;\n      ret.slot := pos.slot;\n      ret.status := failure_key_duplicated;\n      return;\n    }\n\n    ret.index := *insert_bucket_ptr;\n    ret.slot := *insert_slot_ptr;\n    ret.status := ok;\n    return;\n  }\n\n//  assert(st == failure);\n  ret.index := 0;\n  ret.slot := 0;\n  ret.status := failure_table_full;\n}\n\n\n// Found declaration of `cuckoohash_map::add_to_bucket' at 1024:3\nmethod cuckoohash_map_add_to_bucket(this_ptr:ptr<cuckoohash_map>, bucket_ind: size_type, slot: size_type, partial: partial_t, key_ptr:ptr<KeyType>, val_ptr:ptr<ValueType>)\n{\n  noaddr var temp0: ptr<counter_type>;\n  noaddr var locks_ptr: ptr<locks_t>;\n  noaddr var tmp_v: counter_type;\n  \n  libcuckoo_bucket_container_setKV(&((*this_ptr).buckets_), bucket_ind, slot, partial, key_ptr, val_ptr);\n  locks_ptr := cuckoohash_map_get_current_locks(this_ptr);\n  temp0 := spinlock_elem_counter(vector_bracket(*locks_ptr, lock_ind(bucket_ind)));\n  tmp_v := *temp0 + 1;\n  *temp0 := tmp_v;\n}\n\n\n// Found declaration of `cuckoohash_map::try_find_insert_bucket' at 1035:3\nmethod cuckoohash_map_try_find_insert_bucket(this_ptr:ptr<cuckoohash_map>, b_ptr: ptr<bucket>, slot_ptr: ptr<int32>, partial: partial_t, key_ptr: ptr<KeyType>) returns (ret: bool_t)\n{\n  noaddr var i:int32;\n  noaddr var temp0:bool_t;\n  noaddr var temp1:partial_t;\n  noaddr var temp2: ptr<KeyType>;\n  noaddr var temp3: bool_t;\n  noaddr var key: KeyType := *key_ptr;\n\n  *slot_ptr := -1;\n  i := 0;\n  while (i < SLOT_PER_BUCKET)\n  {\n    temp0 := bucket_occupied_const(b_ptr, i as size_type);\n    if (temp0 == TRUE)\n    {\n      temp1 := bucket_partial_const(b_ptr, i as size_type);\n      if (!IS_SIMPLE && partial != temp1)\n      {\n        continue;\n      }\n\n      temp2 := bucket_key(b_ptr, i as size_type);\n      temp3 := ext_key_eq(*temp2, key);\n      if (temp3 == TRUE)\n      {\n        *slot_ptr := i;\n        ret := FALSE;\n        return;\n      }\n    }\n    else\n    {\n      *slot_ptr := i;\n    }\n    i := i + 1;\n  }\n\n  ret := TRUE;\n}\n\n\n// Found declaration of `cuckoohash_map::run_cuckoo' at 1064:3\nmethod cuckoohash_map_run_cuckoo(this_ptr:ptr<cuckoohash_map>, b_ptr: ptr<TwoBuckets>, insert_bucket_ptr: ptr<size_type>, insert_slot_ptr: ptr<size_type>) returns (ret: cuckoo_status)\n{\n  noaddr var hp:size_type;\n  var cuckoo_path: CuckooRecords;\n  noaddr var done:bool_t;\n  var error:int32;\n  noaddr var depth:int8;\n  noaddr var temp0:bool_t;\n  noaddr var tmp1: size_type;\n\n  hp := cuckoohash_map_hashpower(this_ptr);\n  TwoBuckets_unlock(b_ptr);\n  done := FALSE;\n  while (done == failure_under_expansion)\n  {\n    tmp1 := (*b_ptr).i1;\n    depth := cuckoohash_map_cuckoopath_search(this_ptr, hp, &cuckoo_path[0], tmp1, (*b_ptr).i2, &error);\n    if (error == ERROR_HASHPOWER_CHANGED)\n    {\n      ret := failure_under_expansion;\n      return;\n    }\n\n    if (depth < 0)\n    {\n      break;\n    }\n\n    temp0 := cuckoohash_map_cuckoopath_move(this_ptr, hp, &cuckoo_path[0], depth as size_type, b_ptr, &error);\n    if (temp0 == TRUE)\n    {\n      tmp1 := cuckoo_path[0].bucket;\n      *insert_bucket_ptr := tmp1;\n      tmp1 := cuckoo_path[0].slot;\n      *insert_slot_ptr := tmp1;\n//       assert(insert_bucket == b.i1 || insert_bucket == b.i2);\n//       assert(!get_current_locks()[lock_ind(b.i1)].try_lock());\n//       assert(!get_current_locks()[lock_ind(b.i2)].try_lock());\n//       assert(!buckets_[insert_bucket].occupied(insert_slot));\n      done := TRUE;\n      break;\n    }\n\n    if (error == ERROR_HASHPOWER_CHANGED)\n    {\n      ret := failure_under_expansion;\n      return;\n    }\n  }\n\n  ret := if done == TRUE then ok else failure;\n}\n\n\n// Found declaration of `cuckoohash_map::cuckoopath_search' at 1123:3\nmethod cuckoohash_map_cuckoopath_search(this_ptr: ptr<cuckoohash_map>, hp: size_type, cuckoo_path: ptr<CuckooRecord>, i1: size_type, i2: size_type, error_ptr: ptr<int32>) returns (ret: int8)\n{\n  noaddr var x:b_slot;\n  noaddr var i:int8;\n  noaddr var first_ptr:ptr<CuckooRecord>;\n  noaddr var lock_manager:LockManager;\n  noaddr var b_ptr:ptr<bucket>;\n  noaddr var temp0:bool_t;\n  noaddr var curr_ptr:ptr<CuckooRecord>;\n  noaddr var prev_ptr:ptr<CuckooRecord>;\n  noaddr var tmp: ptr<key_type>;\n  noaddr var tmp1: size_type;\n  noaddr var tmp2: partial_t;\n\n  *(error_ptr) := ERROR_NONE;\n  x := cuckoohash_map_slot_search(this_ptr, hp, i1, i2, error_ptr);\n  if (x.depth == -1)\n  {\n    ret := -1;\n    return;\n  }\n\n  i := x.depth;\n  while (i >= 0)\n  {\n    (*(cuckoo_path + i)).slot := (x.pathcode % SLOT_PER_BUCKET) as uint64;\n    x.pathcode := x.pathcode / SLOT_PER_BUCKET;\n    i := i - 1;\n  }\n\n  first_ptr := cuckoo_path;\n  if (x.pathcode == 0)\n  {\n    (*first_ptr).bucket := i1;\n  }\n  else\n  {\n//     assert(x.pathcode == 1);\n    (*first_ptr).bucket := i2;\n  }\n\n  {\n    lock_manager := cuckoohash_map_lock_one(this_ptr, hp, (*first_ptr).bucket, error_ptr);\n    if ((*error_ptr) != ERROR_NONE)\n    {\n      LockManager_destroy_LockManager(lock_manager)\n      ret := -1;\n      return;\n    }\n\n    tmp1 := (*first_ptr).bucket;\n    b_ptr := (*this_ptr).buckets_.buckets_ + tmp1;\n    temp0 := bucket_occupied_const(b_ptr, (*first_ptr).slot);\n    if (temp0 == FALSE)\n    {\n      LockManager_destroy_LockManager(lock_manager)\n      ret := 0;\n      return;\n    }\n\n    tmp := bucket_key(b_ptr, (*first_ptr).slot);\n    cuckoohash_map_hashed_key(this_ptr, tmp, &(*first_ptr).hv);\n\n    LockManager_destroy_LockManager(lock_manager)\n  }\n\n  i := 1;\n  while (i <= x.depth)\n  {\n    curr_ptr := cuckoo_path + i;\n    prev_ptr := cuckoo_path + (i - 1);\n\n//     assert(prev.bucket == index_hash(hp, prev.hv.hash) ||\n//        prev.bucket ==\n//            alt_index(hp, prev.hv.partial, index_hash(hp, prev.hv.hash)));\n\n    tmp2 := (*prev_ptr).hv.partial;\n    tmp1 := (*prev_ptr).bucket;\n    (*curr_ptr).bucket := cuckoohash_map_alt_index(hp, tmp2, tmp1);\n    lock_manager := cuckoohash_map_lock_one(this_ptr, hp, (*curr_ptr).bucket, error_ptr);\n    if ((*error_ptr) != ERROR_NONE)\n    {\n      LockManager_destroy_LockManager(lock_manager)\n      ret := -1;\n      return;\n    }\n\n    tmp1 := (*curr_ptr).bucket;\n    b_ptr := (*this_ptr).buckets_.buckets_ + tmp1;\n    temp0 := bucket_occupied_const(b_ptr, (*curr_ptr).slot);\n    if (temp0 == FALSE)\n    {\n      LockManager_destroy_LockManager(lock_manager)\n      ret := i;\n      return;\n    }\n\n    tmp := bucket_key(b_ptr, (*curr_ptr).slot);\n    cuckoohash_map_hashed_key(this_ptr, tmp, &(*curr_ptr).hv);\n    \n    LockManager_destroy_LockManager(lock_manager)\n    i := i + 1;\n  }\n\n  ret := x.depth;\n}\n\n\n// Found declaration of `cuckoohash_map::cuckoopath_move' at 1190:3\nmethod cuckoohash_map_cuckoopath_move(this_ptr: ptr<cuckoohash_map>, hp: size_type, cuckoo_path: ptr<CuckooRecord>, depth: size_type, b_ptr: ptr<TwoBuckets>, error_ptr: ptr<int32>) returns (ret: bool_t)\n{\n  noaddr var bucket: size_type;\n  noaddr var temp0: bool_t;\n  noaddr var from_ptr: ptr<CuckooRecord>;\n  noaddr var to_ptr: ptr<CuckooRecord>;\n  noaddr var fs: size_type;\n  noaddr var ts: size_type;\n  noaddr var twob: TwoBuckets;\n  noaddr var extra_manager: LockManager;\n  noaddr var fb_ptr: ptr<bucket>;\n  noaddr var tb_ptr: ptr<bucket>;\n  noaddr var temp1: bool_t;\n  noaddr var temp2: bool_t;\n  noaddr var temp3: ptr<key_type>;\n  noaddr var temp4: size_type;\n  noaddr var temp5: partial_t;\n  noaddr var temp6: ptr<key_type>;\n  noaddr var temp7: ptr<mapped_type>;\n  noaddr var temp8: ptr<bucket>;\n\n  noaddr var tmp_i1: size_type;\n  noaddr var tmp_i2: size_type;\n  noaddr var tmp_b: TwoBuckets;\n\n  *error_ptr := ERROR_NONE;\n  if (depth == 0)\n  {\n    bucket := (*cuckoo_path).bucket;\n//      assert(bucket == b.i1 || bucket == b.i2);\n\n    tmp_i1 := (*b_ptr).i1;\n    tmp_b := cuckoohash_map_lock_two(this_ptr, hp, tmp_i1, (*b_ptr).i2, error_ptr);\n    copy_TwoBuckets(*b_ptr, tmp_b)\n\n    if ((*error_ptr) != ERROR_NONE)\n    {\n      ret := FALSE;\n      return;\n    }\n    \n    temp8 := (*this_ptr).buckets_.buckets_ + bucket;\n    temp0 := bucket_occupied_const(temp8, (*cuckoo_path).slot);\n    if (temp0 == FALSE)\n    {\n      ret := TRUE;\n      return;\n    }\n    else\n    {\n      TwoBuckets_unlock(b_ptr);\n      ret := FALSE;\n      return;\n    }\n  }\n\n  while (depth > 0)\n  {\n    from_ptr := cuckoo_path + (depth - 1);\n    to_ptr := cuckoo_path + depth;\n    fs := (*from_ptr).slot;\n    ts := (*to_ptr).slot;\n\n    LockManager_LockManager_default(extra_manager)\n\n    if (depth == 1)\n    {\n      tmp_i1 := (*b_ptr).i1;\n      tmp_i2 := (*b_ptr).i2;\n      twob, extra_manager := cuckoohash_map_lock_three(this_ptr, hp, tmp_i1, tmp_i2, (*to_ptr).bucket, error_ptr);\n    }\n    else\n    {\n      temp4 := (*from_ptr).bucket;\n      twob := cuckoohash_map_lock_two(this_ptr, hp, temp4, (*to_ptr).bucket, error_ptr);\n    }\n\n    if ((*error_ptr) != ERROR_NONE)\n    {\n      ret := FALSE;\n      return;\n    }\n\n    temp4 := (*from_ptr).bucket;\n    fb_ptr := (*this_ptr).buckets_.buckets_ + temp4;\n    temp4 := (*to_ptr).bucket;\n    tb_ptr := (*this_ptr).buckets_.buckets_ + temp4;\n\n    temp1 := bucket_occupied_const(tb_ptr, ts);\n    temp2 := bucket_occupied_const(fb_ptr, fs);\n    temp3 := bucket_key(fb_ptr, fs);\n    temp4 := cuckoohash_map_hashed_key_only_hash(temp3);\n    if (temp1 != FALSE || temp2 == FALSE || temp4 != (*from_ptr).hv.hash)\n    {\n      ret := FALSE;\n      return;\n    }\n\n    temp5 := bucket_partial_const(fb_ptr, fs);\n    temp6 := bucket_key(fb_ptr, fs);\n    temp7 := bucket_mapped(fb_ptr, fs);\n    libcuckoo_bucket_container_setKV(&((*this_ptr).buckets_), (*to_ptr).bucket, ts, temp5, temp6, temp7);\n    libcuckoo_bucket_container_eraseKV(&((*this_ptr).buckets_), (*from_ptr).bucket, fs);\n\n    if (depth == 1)\n    {\n      TwoBuckets_destroy_TwoBuckets((*b_ptr))\n      copy_TwoBuckets((*b_ptr), twob)\n    } else {\n      TwoBuckets_destroy_TwoBuckets(twob)\n    }\n\n    LockManager_destroy_LockManager(extra_manager)\n\n    depth := depth - 1;\n\n  }\n\n  ret := TRUE;\n}\n\n\n// Found declaration of `cuckoohash_map::slot_search' at 1270:3\nmethod cuckoohash_map_slot_search(this_ptr: ptr<cuckoohash_map>, hp: size_type, i1: size_type, i2: size_type, error_ptr: ptr<int32>) returns (ret: b_slot)\n{\n  noaddr var q: b_queue;\n  noaddr var temp0: bool_t;\n  noaddr var x: b_slot;\n  noaddr var lock_manager: LockManager;\n  noaddr var b_ptr: ptr<bucket>;\n  noaddr var starting_slot: size_type;\n  noaddr var i: size_type;\n  noaddr var slot: uint16;\n  noaddr var temp1: bool_t;\n  noaddr var partial: partial_t;\n  noaddr var y:b_slot;\n  noaddr var tmp_b : b_slot;\n  \n  b_queue_b_queue(q)\n  b_slot_b_slot(tmp_b, i1, 0, 0)\n  b_queue_enqueue(q, tmp_b)\n  b_slot_b_slot(tmp_b, i2, 1, 0)\n  b_queue_enqueue(q, tmp_b)\n  temp0 := if b_queue_empty(q) then TRUE else FALSE;\n  while (temp0 == FALSE)\n  {\n    b_queue_dequeue(q, x)\n    lock_manager := cuckoohash_map_lock_one(this_ptr, hp, x.bucket, error_ptr);\n    if ((*error_ptr) != ERROR_NONE)\n    {\n      b_slot_b_slot(tmp_b, 0, 0, -1)\n      ret := tmp_b;\n      return;\n    }\n\n    b_ptr := (*this_ptr).buckets_.buckets_ + x.bucket;\n    starting_slot := (x.pathcode % SLOT_PER_BUCKET) as size_type;\n    i := 0;\n    while (i < SLOT_PER_BUCKET)\n    {\n      slot := ((starting_slot + i) % SLOT_PER_BUCKET) as uint16;\n      temp1 := bucket_occupied_const(b_ptr, slot as uint64);\n      if (temp1 == FALSE)\n      {\n        x.pathcode := x.pathcode * SLOT_PER_BUCKET + slot;\n        ret := x;\n        return;\n      }\n\n      partial := bucket_partial_const(b_ptr, slot as uint64);\n      if (x.depth < MAX_BFS_PATH_LEN - 1)\n      {\n//          assert(!q.full());\n        b_slot_b_slot(y, cuckoohash_map_alt_index(hp, partial, x.bucket), x.pathcode * SLOT_PER_BUCKET + slot, x.depth + 1)\n        b_queue_enqueue(q, y)\n      }\n\n      i := i + 1;\n    }\n    temp0 := if b_queue_empty(q) then TRUE else FALSE;\n  }\n  b_slot_b_slot(tmp_b, 0, 0, -1)\n  ret := tmp_b;\n}\n\n\n// Found declaration of `cuckoohash_map::cuckoo_fast_double' at 1315:3\nmethod cuckoohash_map_cuckoo_fast_double(this_ptr:ptr<cuckoohash_map>, current_hp: size_type, auto_resize: bool_t, error_ptr: ptr<uint8>) returns (ret: cuckoo_status)\n{\n  noaddr var new_hp:size_type;\n  noaddr var all_locks_manager: AllLocksManager;\n  noaddr var st: cuckoo_status;\n  var new_buckets: bucket_container;\n  noaddr var start:size_type;\n  noaddr var end:size_type;\n  noaddr var num_threads: size_type;\n  noaddr var work_per_thread: size_type;\n  noaddr var threads_ptr: ptr<uint64>;\n  noaddr var errors_ptr: ptr<uint8>;\n  noaddr var i:size_type;\n  noaddr var temp0: uint8;\n\n  noaddr var tmp_buckets: bucket_container;\n\n  *error_ptr := ERROR_NONE;\n//    if (!std::is_nothrow_move_constructible<key_type>::value ||\n//        !std::is_nothrow_move_constructible<mapped_type>::value) {\n//      LIBCUCKOO_DBG(\"%s\", \"cannot run cuckoo_fast_double because key-value\"\n//                          \" pair is not nothrow move constructible\");\n//      return cuckoo_expand_simple(current_hp + 1, auto_resize, error);\n//    }\n\n  new_hp := current_hp + 1;\n  all_locks_manager := cuckoohash_map_snapshot_and_lock_all(this_ptr);\n  st := cuckoohash_map_check_resize_validity(this_ptr, current_hp, new_hp, auto_resize, error_ptr);\n  if (st != ok)\n  {\n    ret := st;\n    return;\n  }\n\n  bucket_container_bucket_container(&new_buckets, new_hp);\n  \n  start := 0;\n  end := cuckoohash_map_hashsize(current_hp);\n  num_threads := ext_hardware_concurrency();\n  num_threads := if num_threads < 1 then 1 else num_threads;\n\n  work_per_thread := (end - start) / num_threads;\n  threads_ptr := calloc(uint64, num_threads);\n  errors_ptr := calloc(uint8, num_threads);\n  i := 0;\n  while (i < num_threads - 1)\n  {\n    *(errors_ptr + i) := ERROR_NONE;\n    *(threads_ptr + i) := create_thread cuckoohash_map_move_buckets(this_ptr, &new_buckets, current_hp, new_hp, start, start + work_per_thread, errors_ptr + i);\n    start := start + work_per_thread;\n    i := i + 1;\n  }\n\n  *(errors_ptr + i) := ERROR_NONE;\n  *(threads_ptr + i) := create_thread cuckoohash_map_move_buckets(this_ptr, &new_buckets, current_hp, new_hp, start, end, errors_ptr + i);\n  i := 0;\n  while (i < num_threads)\n  {\n    join *(threads_ptr + i);\n    i := i + 1;\n  }\n\n  *error_ptr := ERROR_NONE;\n  i := 0;\n  while (i < num_threads)\n  {\n    if ((*(errors_ptr + i)) != ERROR_NONE)\n    {\n      temp0 := *(errors_ptr + i);\n      *error_ptr := temp0;\n      ret := failure;\n      return;\n    }\n    i := i + 1;\n  }\n\n  dealloc threads_ptr;\n  dealloc errors_ptr;\n\n  cuckoohash_map_maybe_resize_locks(this_ptr, 1 << new_hp);\n  libcuckoo_bucket_container_destroy_buckets(&(*this_ptr).buckets_);\n\n  tmp_buckets.hashpower_ := new_buckets.hashpower_;\n  tmp_buckets.buckets_ := new_buckets.buckets_;\n\n  (*this_ptr).buckets_.hashpower_ := tmp_buckets.hashpower_;\n  (*this_ptr).buckets_.buckets_ := tmp_buckets.buckets_;\n  ret := ok;\n}\n\n\n// // Found declaration of `cuckoohash_map::cuckoo_expand_simple_thread_routine' at 1378:3\n// method cuckoohash_map_cuckoo_expand_simple_thread_routine(TODO_method_params)\n// {\n//   noaddr var j:size_type;\n//   noaddr var temp0:TODO_return_type;\n//   noaddr var temp1:TODO_return_type;\n//   noaddr var temp2:TODO_return_type;\n//   *(error_ptr) := 0;\n//   while (i < end)\n//   {\n//     j := 0;\n//     while (j < SLOT_PER_BUCKET)\n//     {\n//       temp0 := bucket_occupied(&(TODO_expr__CXXOperatorCallExpr:bucket), j);\n//       if (temp0)\n//       {\n//         temp1 := bucket_key(&(TODO_expr__CXXOperatorCallExpr:bucket), j);\n//         temp2 := bucket_mapped(&(TODO_expr__CXXOperatorCallExpr:bucket), j);\n//         TODO_type_Pointer_insert(&(new_map), temp1, temp2, *(error_ptr));\n//         if (*(error_ptr) != 0)\n//         {\n//           TODO_BreakStmt\n//         }\n// \n//       }\n// \n//       ++j;\n//     }\n// \n//     ++i;\n//   }\n// \n// }\n// \n\n// Found declaration of `cuckoohash_map::move_buckets' at 1397:3\nmethod cuckoohash_map_move_buckets(this_ptr: ptr<cuckoohash_map>, new_buckets_ptr: ptr<bucket_container>, current_hp: size_type, new_hp: size_type, start_ind: size_type, end_ind: size_type, error_ptr: ptr<uint8>)\n{\n  noaddr var old_bucket_ind: size_type;\n  noaddr var old_bucket_ptr: ptr<bucket>;\n  noaddr var new_bucket_ind: size_type;\n  noaddr var temp0: size_type;\n  noaddr var new_bucket_slot:size_type;\n  noaddr var old_bucket_slot:size_type;\n  noaddr var temp1: bool_t;\n  noaddr var t_k: ptr<key_type>;\n  noaddr var hv: hash_value;\n  noaddr var old_ihash: size_type;\n  noaddr var old_ahash: size_type;\n  noaddr var new_ihash:size_type;\n  noaddr var new_ahash:size_type;\n  noaddr var temp2:partial_t;\n  noaddr var temp3:ptr<KeyType>;\n  noaddr var temp4:ptr<ValueType>;\n  noaddr var dst_bucket_ind: size_type;\n  noaddr var dst_bucket_slot: size_type;\n\n  *error_ptr := ERROR_NONE;\n  old_bucket_ind := start_ind;\n  while (old_bucket_ind < end_ind)\n  {\n    old_bucket_ptr := (*this_ptr).buckets_.buckets_ + old_bucket_ind;\n    temp0 := cuckoohash_map_hashsize(current_hp);\n    new_bucket_ind := old_bucket_ind + temp0;\n    new_bucket_slot := 0;\n    old_bucket_slot := 0;\n    while (old_bucket_slot < SLOT_PER_BUCKET)\n    {\n      temp1 := bucket_occupied_const(old_bucket_ptr, old_bucket_slot);\n      if (temp1 == FALSE)\n      {\n        continue;\n      }\n\n      t_k := bucket_key(old_bucket_ptr, old_bucket_slot);\n      hv := cuckoohash_map_hashed_key_const(this_ptr, t_k);\n      old_ihash := cuckoohash_map_index_hash(current_hp, hv.hash);\n      old_ahash := cuckoohash_map_alt_index(current_hp, hv.partial, old_ihash);\n      new_ihash := cuckoohash_map_index_hash(new_hp, hv.hash);\n      new_ahash := cuckoohash_map_alt_index(new_hp, hv.partial, new_ihash);\n      if ((old_bucket_ind == old_ihash && new_ihash == new_bucket_ind) || \n          (old_bucket_ind == old_ahash && new_ahash == new_bucket_ind))\n      {\n        dst_bucket_ind := new_bucket_ind;\n        dst_bucket_slot := new_bucket_slot;\n        new_bucket_slot := new_bucket_slot + 1;\n      }\n      else\n      {\n//         assert((old_bucket_ind == old_ihash && new_ihash == old_ihash) ||\n//                (old_bucket_ind == old_ahash && new_ahash == old_ahash));\n        dst_bucket_ind := old_bucket_ind;\n        dst_bucket_slot := old_bucket_slot;\n      }\n\n      temp2 := bucket_partial_const(old_bucket_ptr, old_bucket_slot);\n      temp3 := bucket_key(old_bucket_ptr, old_bucket_slot);\n      temp4 := bucket_mapped(old_bucket_ptr, old_bucket_slot);\n      libcuckoo_bucket_container_setKV(new_buckets_ptr, dst_bucket_ind, dst_bucket_slot, temp2, temp3, temp4);\n\n      dst_bucket_slot := dst_bucket_slot + 1;\n      old_bucket_slot := old_bucket_slot + 1;\n    }\n    old_bucket_ind := old_bucket_ind + 1;\n  }\n}\n\n// \n// // Found declaration of `cuckoohash_map::move_buckets_static' at 1447:3\n// method cuckoohash_map_move_buckets_static(TODO_method_params)\n// {\n//   TODO_type_Pointer_move_buckets(&(m), *(new_buckets_ptr), current_hp, new_hp, start_ind, end_ind, *(error_ptr));\n// }\n// \n\n// Found declaration of `cuckoohash_map::check_resize_validity' at 1453:3\nmethod cuckoohash_map_check_resize_validity(this_ptr: ptr<cuckoohash_map>, orig_hp: size_type,  new_hp: size_type, auto_resize: bool_t, error_ptr: ptr<uint8>) returns (ret: cuckoo_status)\n{\n  noaddr var mhp: size_type;\n  noaddr var temp_num: uint64;\n  noaddr var temp_dec: uint64;\n  noaddr var lf_num: uint64;\n  noaddr var lf_dec: uint64;\n  noaddr var temp2: size_type;\n\n  *error_ptr := 0;\n  mhp := cuckoohash_map_maximum_hashpower(this_ptr);\n  if (mhp != LIBCUCKOO_NO_MAXIMUM_HASHPOWER && new_hp > mhp)\n  {\n    *error_ptr := ERROR_MAXIMUM_HASH_POWER_EXCEEDED;\n    ret := failure;\n    return;\n  }\n\n  temp_num, temp_dec := cuckoohash_map_load_factor(this_ptr);\n  lf_num := (*this_ptr).minimum_load_factor_num;\n  lf_dec := (*this_ptr).minimum_load_factor_dec;\n  if (auto_resize != FALSE && temp_num * lf_dec < lf_num * temp_dec)\n  {\n    *error_ptr := ERROR_LOAD_FACTOR_TOO_LOW;\n    ret := failure;\n    return;\n  }\n\n  temp2 := cuckoohash_map_hashpower(this_ptr);\n  if (temp2 != orig_hp)\n  {\n    // LIBCUCKOO_DBG(\"%s\", \"another expansion is on-going\\n\");\n    ret := failure_under_expansion;\n    return;\n  }\n\n  ret := ok;\n}\n\n\n// Found declaration of `cuckoohash_map::maybe_resize_locks' at 1486:3\nmethod cuckoohash_map_maybe_resize_locks(this_ptr: ptr<cuckoohash_map>, new_bucket_count: size_type)\n{\n  noaddr var current_locks_ptr:ptr<locks_t>;\n  noaddr var temp0: uint64;\n  noaddr var temp1: uint64;\n  noaddr var new_tail: ptr<all_locks_list_node>;\n  noaddr var new_locks_ptr:ptr<locks_t>;\n  noaddr var i: uint64;\n  noaddr var tmp: ptr<spinlock>;\n  noaddr var t1: bool_t;\n  noaddr var t2: counter_type;\n\n  current_locks_ptr := cuckoohash_map_get_current_locks(this_ptr);\n  temp0 := vector_size(*current_locks_ptr);\n  temp1 := vector_size(*current_locks_ptr);\n  if (!(temp0 < kMaxNumLocks && temp1 < new_bucket_count))\n  {\n    return;\n  }\n\n  new_tail := malloc(all_locks_list_node);\n  all_locks_list_node_all_locks_list_node(new_tail, if kMaxNumLocks < new_bucket_count then kMaxNumLocks else new_bucket_count);\n  new_locks_ptr := &((*new_tail).elt);\n  i := 0;\n  while (i < vector_size(*new_locks_ptr)) {\n    spinlock_lock(vector_bracket(*new_locks_ptr, i));\n  }\n//  assert(new_locks.size() > current_locks.size());\n//  std::copy(current_locks.begin(), current_locks.end(), new_locks.begin());\n  i := 0;\n  while (i < vector_size(*current_locks_ptr)) {\n    tmp := vector_bracket(*current_locks_ptr, i);\n    t1 := (*tmp).lock_;\n    t2 := (*tmp).elem_counter_;\n\n    tmp := vector_bracket(*new_locks_ptr, i);\n    (*tmp).lock_ := t1;\n    (*tmp).elem_counter_ := t2;\n  }\n  all_locks_t_append(&((*this_ptr).all_locks_), new_tail);\n}\n\n// \n// // Found declaration of `cuckoohash_map::cuckoo_expand_simple' at 1510:3\n// method cuckoohash_map_cuckoo_expand_simple(TODO_method_params)\n// {\n//   noaddr var all_locks_manager:TODO_type_Auto;\n//   noaddr var hp:size_type;\n//   noaddr var st:TODO_type_Enum;\n//   noaddr var new_map:cuckoohash_map;\n//   noaddr var start:size_type;\n//   noaddr var end:size_type;\n//   noaddr var num_threads:size_type;\n//   noaddr var work_per_thread:size_type;\n//   noaddr var threads:TODO_type_TemplateSpecialization;\n//   noaddr var errors:TODO_type_TemplateSpecialization;\n//   noaddr var i:size_type;\n//   noaddr var i:size_type;\n//   noaddr var i:size_type;\n//   noaddr var temp0:TODO_return_type;\n//   all_locks_manager := TODO_expr__ExprWithCleanups:TODO_type_Auto;\n//   hp := cuckoohash_map_hashpower(this);\n//   st := cuckoohash_map_check_resize_validity(this, hp, new_hp, auto_resize, *(error_ptr));\n//   if (st != ok)\n//   {\n//     return st;\n//   }\n// \n//   new_map := TODO_expr__ExprWithCleanups:cuckoohash_map;\n//   start := 0;\n//   end := hashsize(new_hp);\n//   num_threads := TODO_expr__ExprWithCleanups:size_type;\n//   work_per_thread := (end - start) / num_threads;\n//   threads := TODO_expr__CXXConstructExpr:TODO_type_TemplateSpecialization;\n//   TODO_type_TemplateSpecialization_reserve(&(threads), num_threads);\n//   errors := TODO_expr__ExprWithCleanups:TODO_type_TemplateSpecialization;\n//   i := 0;\n//   while (i < num_threads - 1)\n//   {\n//     TODO_ExprWithCleanups\n//     TODO_CompoundAssignOperator\n//     ++i;\n//   }\n// \n//   TODO_ExprWithCleanups\n//   i := 0;\n//   while (i < num_threads)\n//   {\n//     value_type_join(&(TODO_expr__CXXOperatorCallExpr:value_type));\n//     ++i;\n//   }\n// \n//   *(error_ptr) := 0;\n//   i := 0;\n//   while (i < num_threads)\n//   {\n//     if (TODO_expr__CXXOperatorCallExpr:value_type != 0)\n//     {\n//       *(error_ptr) := TODO_expr__CXXOperatorCallExpr:value_type;\n//       return failure;\n//     }\n// \n//     ++i;\n//   }\n// \n//   temp0 := cuckoohash_map_bucket_count(&(new_map));\n//   cuckoohash_map_maybe_resize_locks(this, temp0);\n//   libcuckoo_bucket_container_swap(&((*this).buckets_), new_map.buckets_);\n//   return ok;\n// }\n// \n// \n// // Found declaration of `cuckoohash_map::del_from_bucket' at 1560:3\n// method cuckoohash_map_del_from_bucket(TODO_method_params)\n// {\n//   noaddr var temp0:TODO_return_type;\n//   libcuckoo_bucket_container_eraseKV(&((*this).buckets_), bucket_ind, slot);\n//   temp0 := value_type_elem_counter(&(TODO_expr__CXXOperatorCallExpr:value_type));\n//   --temp0;\n// }\n// \n// \n// // Found declaration of `cuckoohash_map::cuckoo_clear' at 1567:3\n// method cuckoohash_map_cuckoo_clear(TODO_method_params)\n// {\n//   libcuckoo_bucket_container_clear(&((*this).buckets_));\n//   TODO_CXXForRangeStmt\n//   return ok;\n// }\n// \n// \n// // Found declaration of `cuckoohash_map::cuckoo_rehash' at 1577:3\n// method cuckoohash_map_cuckoo_rehash(TODO_method_params)\n// {\n//   noaddr var hp:size_type;\n//   noaddr var temp0:TODO_return_type;\n//   hp := cuckoohash_map_hashpower(this);\n//   if (n == hp)\n//   {\n//     *(error_ptr) := 0;\n//     return false;\n//   }\n// \n//   temp0 := cuckoohash_map_cuckoo_expand_simple(this, n, false, *(error_ptr));\n//   return temp0 == ok;\n// }\n// \n// \n// // Found declaration of `cuckoohash_map::cuckoo_reserve' at 1586:3\n// method cuckoohash_map_cuckoo_reserve(TODO_method_params)\n// {\n//   noaddr var hp:size_type;\n//   noaddr var new_hp:size_type;\n//   noaddr var temp0:TODO_return_type;\n//   hp := cuckoohash_map_hashpower(this);\n//   new_hp := reserve_calc(n);\n//   if (new_hp == hp)\n//   {\n//     *(error_ptr) := 0;\n//     return false;\n//   }\n// \n//   temp0 := cuckoohash_map_cuckoo_expand_simple(this, new_hp, false, *(error_ptr));\n//   return temp0 == ok;\n// }\n// \n// \n// // Found declaration of `cuckoohash_map::reserve_calc' at 1600:3\n// method cuckoohash_map_reserve_calc(TODO_method_params)\n// {\n//   noaddr var buckets:size_type;\n//   noaddr var blog2:size_type;\n//   buckets := (n + SLOT_PER_BUCKET - 1) / SLOT_PER_BUCKET;\n//   blog2 := 0;\n//   while ((TODO_expr__CXXFunctionalCastExpr:size_type << blog2) < buckets)\n//   {\n//     TODO_NullStmt\n//     ++blog2;\n//   }\n// \n//   TODO_ParenExpr\n//   return blog2;\n// }\n// \n\n// Found declaration of `cuckoohash_map::get_current_locks' at 1609:3\nmethod cuckoohash_map_get_current_locks(this_ptr:ptr<cuckoohash_map>) returns (ret:ptr<locks_t>)\n{\n  noaddr var temp0:ptr<all_locks_list_node>;\n  temp0 := all_locks_t_get_tail(&((*this_ptr).all_locks_));\n  ret := &(*temp0).elt;\n}\n\n\n    method main ()\n    {\n    }\n// \n}\n\n"
  },
  {
    "path": "experimental/Tests/libcuckoo/cuckoo2.arm",
    "content": "    struct u64frac {\n      var n: uint64;\n      var d: uint64;\n    }\n\n    struct storage_value_type {\n        var first: int64;\n        var second: int64;\n    }\n\n    struct bucket {\n        // std::array<typename std::aligned_storage<sizeof(storage_value_type),\n                                                // alignof(storage_value_type)>::type,\n                // SLOT_PER_BUCKET>\n            // values_;\n        // std::array<partial_t, SLOT_PER_BUCKET> partials_;\n        // std::array<bool, SLOT_PER_BUCKET> occupied_;\n\n        var values_:storage_value_type[8];\n        var partials_:uint8[8];\n        var occupied_:uint8[8];\n    }\n\n    // cuckoohash_map.hh:59\n    struct spinlock {\n      // std::atomic_flag\n        var lock_:uint8;\n        var elem_counter_:uint64;\n    }\n\n    // cuckoohash_map.hh:92\n    struct locks_t {\n        var data:ptr<spinlock>;\n        var len:uint64;\n    }\n\n    // cuckoohash_map.hh:94\n    struct all_locks_list_node {\n        var elt:locks_t;\n        var next:ptr<all_locks_list_node>;\n    }\n\n    // cuckoohash_map.hh:101\n    struct all_locks_t {\n        var head_:ptr<all_locks_list_node>;\n        var tail_:ptr<all_locks_list_node>;\n    }\n\n    // cuckoohash_map.hh:126\n    struct LockManager {\n        var lock:ptr<spinlock>;\n    }\n\n    // cuckoohash_map.hh:168\n    struct TwoBuckets {\n        var i1:uint64;\n        var i2:uint64;\n        var first_manager_:LockManager;\n        var second_manager_:LockManager;\n    }\n\n    // cuckoohash_map.hh:205\n    struct b_slot{\n      var bucket: uint64;\n      var pathcode: uint16;\n      var depth: int8;\n    }\n\n    // cuckoohash_map.hh:233\n    struct b_queue {\n      var slots_: b_slot[682];\n      var first_: uint64;\n      var last_: uint64;\n    }\n\n    // cuckoohash_map:282\n    struct hash_value {\n        var hash:uint64;\n        var partial:uint8;\n    }\n\n    // cuckoohash_map:282\n    struct AllLocksManager {\n      var active: uint8;\n      var first_locked: ptr<all_locks_list_node>;\n    }\n\n    // cuckoohash_map.hh:327\n    struct table_position {\n        var index:uint64;\n        var slot:uint64;\n        var status:uint8;\n    }\n\n    // cuckoohash_map.hh:339\n    struct CuckooRecord {\n      var bucket: uint64;\n      var slot: uint64;\n      var hv: hash_value;\n    }\n\n    // libcuckoo_bucket_container.hh:89\n    struct bucket_container {\n        var hashpower_:uint64; //atomic\n        var buckets_:ptr<bucket>;\n    }\n\n    // cuckoohash_map.hh:351\n    struct cuckoohash_map {\n        // The hash function\n        // hasher hash_fn_;\n\n        // The equality function\n        // key_equal eq_fn_;\n\n        var buckets_:bucket_container;\n        var all_locks_:all_locks_t;\n        var minimum_load_factor_num: uint64;\n        var minimum_load_factor_dec: uint64; //double\n        var maximum_hashpower_:uint64; //atomic\n    }\n\nlevel CuckooHashMap {\n\nmethod {:extern} ext_hash_function(k:int64) returns (ret:uint64)\nmethod {:extern} ext_key_eq(k1:int64, k2:int64) returns (ret:uint8)\nmethod {:extern} ext_hardware_concurrency() returns (ret: uint64)\n\nmethod bucket_key(this_ptr:ptr<bucket>, ind:uint64) returns (ret:ptr<int64>)\n{\n  noaddr var temp0:ptr<storage_value_type>;\n  temp0 := bucket_storage_kvpair(this_ptr, ind);\n  ret := &((*temp0).first);\n}\n\n\n\nmethod bucket_mapped(this_ptr:ptr<bucket>, ind:uint64) returns (ret:ptr<int64>)\n{\n  noaddr var temp0:ptr<storage_value_type>;\n  temp0 := bucket_storage_kvpair(this_ptr, ind);\n  ret := &((*temp0).second);\n}\n\n\n\nmethod bucket_partial_const(this_ptr:ptr<bucket>, ind:uint64) returns (ret:uint8)\n{\n  ret := (*this_ptr).partials_[ind];\n}\n\n\n\nmethod bucket_partial(this_ptr:ptr<bucket>, ind:uint64) returns (ret:ptr<uint8>)\n{\n  ret := &(*this_ptr).partials_[ind];\n}\n\n\n\nmethod bucket_occupied_const(this_ptr:ptr<bucket>, ind:uint64) returns (ret:uint8)\n{\n  ret := (*this_ptr).occupied_[ind];\n}\n\n\n\nmethod bucket_occupied(this_ptr:ptr<bucket>, ind:uint64) returns (ret:ptr<uint8>)\n{\n  ret := &(*this_ptr).occupied_[ind];\n}\n\n\n\nmethod bucket_storage_kvpair(this_ptr:ptr<bucket>, ind:uint64) returns (ret:ptr<storage_value_type>)\n{\n  ret := &((*this_ptr).values_[ind]);\n}\n\n\n\nmethod bucket_container_bucket_container(this_ptr: ptr<bucket_container>, hp: uint64)\n{\n  noaddr var temp0: uint64;\n  (*this_ptr).hashpower_ := hp;\n  temp0 := libcuckoo_bucket_container_size(this_ptr);\n  (*this_ptr).buckets_ := calloc(bucket, temp0);\n}\n\nmethod libcuckoo_bucket_container_hashpower(this_ptr:ptr<bucket_container>) returns (ret:uint64)\n{\n  ret := (*this_ptr).hashpower_;\n}\n\nmethod libcuckoo_bucket_container_size(this_ptr:ptr<bucket_container>) returns (ret:uint64)\n{\n  noaddr var temp0: uint64;\n  temp0 := libcuckoo_bucket_container_hashpower(this_ptr);\n  ret := 1ull << temp0;\n}\n\nmethod libcuckoo_bucket_container_setKV(this_ptr: ptr<bucket_container>, ind: uint64, slot: uint64, p: uint8, k_ptr: ptr<int64>, value_ptr: ptr<int64>)\n{\n  noaddr var b_ptr:ptr<bucket>;\n  noaddr var temp0:ptr<uint8>;\n  noaddr var kv_ptr:ptr<storage_value_type>;\n  noaddr var temp1:ptr<uint8>;\n  noaddr var k: int64 := *k_ptr;\n  noaddr var value: int64 := *value_ptr;\n  b_ptr := (*this_ptr).buckets_ + ind;\n\n  temp0 := bucket_partial(b_ptr, slot);\n  *temp0 := p;\n  kv_ptr := bucket_storage_kvpair(b_ptr, slot);\n  (*kv_ptr).first := k;\n  (*kv_ptr).second := value;\n  temp1 := bucket_occupied(b_ptr, slot);\n  *temp1 := 1;\n}\n\n\n\nmethod libcuckoo_bucket_container_eraseKV(this_ptr: ptr<bucket_container>, ind: uint64, slot: uint64)\n{\n  noaddr var b_ptr:ptr<bucket>;\n  noaddr var temp0: ptr<uint8>;\n\n  b_ptr := (*this_ptr).buckets_ + ind;\n\n  temp0 := bucket_occupied(b_ptr, slot);\n  *temp0 := 0;\n}\n\n\n\nmethod libcuckoo_bucket_container_clear(this_ptr: ptr<bucket_container>)\n{\n  noaddr var temp0: uint64;\n  noaddr var i: uint64;\n  noaddr var b_ptr: ptr<bucket>;\n  noaddr var j: uint64;\n  noaddr var temp1: uint8;\n\n  temp0 := libcuckoo_bucket_container_size(this_ptr);\n  i := 0;\n  while (i < temp0)\n  {\n    b_ptr := (*this_ptr).buckets_ + i;\n    j := 0;\n    while (j < 4)\n    {\n      temp1 := bucket_occupied_const(b_ptr, j);\n      if (temp1 != 0)\n      {\n        libcuckoo_bucket_container_eraseKV(this_ptr, i, j);\n      }\n      j := j + 1;\n    }\n    i := i + 1;\n  }\n}\n\n\n\nmethod libcuckoo_bucket_container_destroy_buckets(this_ptr: ptr<bucket_container>)\n{\n  if ((*this_ptr).buckets_ == null)\n  {\n    return;\n  }\n\n  libcuckoo_bucket_container_clear(this_ptr);\n  free((*this_ptr).buckets_);\n  (*this_ptr).buckets_ := null;\n}\n\n\n\n\n\n\n\nmethod spinlock_spinlock(this_ptr:ptr<spinlock>)\n{\n  (*this_ptr).elem_counter_ := 0;\n  (*this_ptr).lock_ := 0;\n}\n\nmethod spinlock_lock(this_ptr:ptr<spinlock>)\n{\n  noaddr var temp0:bool;\n  temp0 := compare_and_swap(((*this_ptr).lock_), 0, 1);\n  while (temp0 == false)\n  {\n    temp0 := compare_and_swap(((*this_ptr).lock_), 0, 1);\n  }\n\n}\n\n\n\nmethod spinlock_unlock(this_ptr:ptr<spinlock>)\n{\n    (*this_ptr).lock_ := 0;\n}\n\nmethod spinlock_elem_counter(this_ptr: ptr<spinlock>) returns (ret: ptr<uint64>)\n{\n  ret := &(*this_ptr).elem_counter_;\n}\n\nmethod all_locks_list_node_all_locks_list_node(this_ptr: ptr<all_locks_list_node>, lock_count: uint64)\n{\n  (*this_ptr).elt.len := lock_count;\n  (*this_ptr).elt.data := calloc(spinlock, lock_count);\n  (*this_ptr).next := null;\n}\n\nmethod all_locks_t_append(this_ptr: ptr<all_locks_t>, new_tail: ptr<all_locks_list_node>)\n{\n  noaddr var tail: ptr<all_locks_list_node>;\n  tail := (*this_ptr).tail_;\n  (*tail).next := new_tail;\n  (*this_ptr).tail_ := new_tail;\n}\n\n\n\nmethod all_locks_t_get_tail(this_ptr:ptr<all_locks_t>) returns (ret:ptr<all_locks_list_node>)\n{\n  ret := (*this_ptr).tail_;\n}\n\nmethod cuckoohash_map_get_current_locks(this_ptr:ptr<cuckoohash_map>) returns (ret:ptr<locks_t>)\n{\n  noaddr var temp0:ptr<all_locks_list_node>;\n  temp0 := all_locks_t_get_tail(&((*this_ptr).all_locks_));\n  ret := &(*temp0).elt;\n}\n\nmethod LockManager_reset(this_ptr: ptr<LockManager>)\n{\n  if ((*this_ptr).lock != null)\n  {\n    spinlock_unlock((*this_ptr).lock);\n    (*this_ptr).lock := null;\n  }\n}\n\nmethod TwoBuckets_unlock(this_ptr: ptr<TwoBuckets>)\n{\n  LockManager_reset(&((*this_ptr).first_manager_));\n  LockManager_reset(&((*this_ptr).second_manager_));\n}\n\nmethod AllLocksManager_destroy_AllLocksManager(this_ptr: ptr<AllLocksManager>)\n{\n  noaddr var it: ptr<all_locks_list_node>;\n  noaddr var locks_ptr: ptr<locks_t>;\n  noaddr var idx: uint64;\n\n  if ((*this_ptr).active != 0)\n  {\n    it := (*this_ptr).first_locked;\n    while (it != null)\n    {\n      locks_ptr := &((*it).elt);\n      idx := 0;\n      while (idx < (*locks_ptr).len)\n      {\n        spinlock_unlock((*locks_ptr).data + idx);\n        idx := idx + 1;\n      }\n      it := (*it).next;\n    }\n  }\n}\n\nmethod cuckoohash_map_hashpower(this_ptr:ptr<cuckoohash_map>) returns (ret:uint64)\n{\n  ret := libcuckoo_bucket_container_hashpower(&((*this_ptr).buckets_));\n}\n\n\n\nmethod cuckoohash_map_bucket_count(this_ptr:ptr<cuckoohash_map>) returns (ret: uint64)\n{\n  ret := libcuckoo_bucket_container_size(&(*this_ptr).buckets_);\n}\n\nmethod cuckoohash_map_size(this_ptr:ptr<cuckoohash_map>) returns (ret: uint64)\n{\n  noaddr var counter_ptr: ptr<uint64>;\n  noaddr var idx: uint64;\n  noaddr var locks: ptr<locks_t>;\n  idx := 0;\n  locks := cuckoohash_map_get_current_locks(this_ptr);\n  while (idx < (*locks).len) {\n    counter_ptr := spinlock_elem_counter((*locks).data + idx);\n    ret := ret + (*counter_ptr);\n  }\n\n}\n\n\n\nmethod cuckoohash_map_capacity(this_ptr:ptr<cuckoohash_map>) returns (ret: uint64)\n{\n  noaddr var temp0: uint64;\n  temp0 := cuckoohash_map_bucket_count(this_ptr);\n  ret := temp0 * 4;\n}\n\n\n\nmethod cuckoohash_map_load_factor(this_ptr:ptr<cuckoohash_map>) returns (ret: u64frac)\n{\n  ret.n := cuckoohash_map_size(this_ptr);\n  ret.d := cuckoohash_map_capacity(this_ptr);\n}\n\nmethod cuckoohash_map_maximum_hashpower(this_ptr:ptr<cuckoohash_map>) returns (ret: uint64)\n{\n  ret := (*this_ptr).maximum_hashpower_;\n}\n\n\n\nmethod cuckoohash_map_find(this_ptr:ptr<cuckoohash_map>, key_ptr:ptr<int64>, val_ptr:ptr<int64>) returns (ret:uint8)\n{\n  var hv:hash_value;\n  noaddr var b:TwoBuckets;\n  noaddr var pos:table_position;\n  noaddr var temp_bucket_ptr:ptr<bucket>;\n  noaddr var temp_value_ptr:ptr<int64>;\n  noaddr var temp_v: int64;\n\n  cuckoohash_map_hashed_key(this_ptr, key_ptr, &hv);\n  b := cuckoohash_map_snapshot_and_lock_two(this_ptr, &hv);\n  pos := cuckoohash_map_cuckoo_find(this_ptr, key_ptr, hv.partial, b.i1, b.i2);\n  if (pos.status == 0)\n  {\n\n    temp_bucket_ptr := (*this_ptr).buckets_.buckets_ + pos.index;\n    temp_value_ptr := bucket_mapped(temp_bucket_ptr, pos.slot);\n    temp_v := *temp_value_ptr;\n    *val_ptr := temp_v;\n    if (b.first_manager_.lock != null) { spinlock_unlock(b.first_manager_.lock); } if (b.second_manager_.lock != null) { spinlock_unlock(b.second_manager_.lock); }\n    ret := 1;\n  }\n  else\n  {\n    if (b.first_manager_.lock != null) { spinlock_unlock(b.first_manager_.lock); } if (b.second_manager_.lock != null) { spinlock_unlock(b.second_manager_.lock); }\n    ret := 0;\n  }\n}\n\nmethod cuckoohash_map_insert(this_ptr:ptr<cuckoohash_map>, key_ptr:ptr<int64>, val_ptr:ptr<int64>, error: ptr<uint8>) returns (ret:uint8)\n{\n  var hv:hash_value;\n  var b:TwoBuckets;\n  noaddr var pos:table_position;\n  noaddr var tmp_b: TwoBuckets;\n  cuckoohash_map_hashed_key(this_ptr, key_ptr, &hv);\n  tmp_b := cuckoohash_map_snapshot_and_lock_two(this_ptr, &hv);\n  (b).i1 := (tmp_b).i1; (b).i2 := (tmp_b).i2; ((b).first_manager_).lock := ((tmp_b).first_manager_).lock; ((b).second_manager_).lock := ((tmp_b).second_manager_).lock;\n  pos := cuckoohash_map_cuckoo_insert_loop(this_ptr, &hv, &b, key_ptr, error);\n  if (pos.status == 0)\n  {\n    cuckoohash_map_add_to_bucket(this_ptr, pos.index, pos.slot, hv.partial, key_ptr, val_ptr);\n    if (b.first_manager_.lock != null) { spinlock_unlock(b.first_manager_.lock); } if (b.second_manager_.lock != null) { spinlock_unlock(b.second_manager_.lock); }\n    ret := 1;\n  }\n  else\n  {\n    if (b.first_manager_.lock != null) { spinlock_unlock(b.first_manager_.lock); } if (b.second_manager_.lock != null) { spinlock_unlock(b.second_manager_.lock); }\n    ret := 0;\n  }\n\n}\n\nmethod cuckoohash_map_hashed_key_const(this_ptr:ptr<cuckoohash_map>, key_ptr:ptr<int64>) returns (out: hash_value)\n{\n  noaddr var hash:uint64;\n  hash := ext_hash_function(*key_ptr);\n  out.hash := hash;\n  out.partial := cuckoohash_map_partial_key(hash);\n}\n\nmethod cuckoohash_map_hashed_key(this_ptr:ptr<cuckoohash_map>, key_ptr:ptr<int64>, out_ptr: ptr<hash_value>)\n{\n  noaddr var hash:uint64;\n  hash := ext_hash_function(*key_ptr);\n  (*out_ptr).hash := hash;\n  (*out_ptr).partial := cuckoohash_map_partial_key(hash);\n}\n\n\nmethod cuckoohash_map_hashed_key_only_hash(key_ptr:ptr<int64>) returns (ret:uint64)\n{\n  ret := ext_hash_function(*key_ptr);\n}\n\n\n\nmethod cuckoohash_map_hashsize(hp:uint64) returns (ret:uint64)\n{\n  ret := 1ull << hp;\n}\n\n\n\nmethod cuckoohash_map_hashmask(hp:uint64) returns (ret:uint64)\n{\n  noaddr var temp0:uint64;\n  temp0 := cuckoohash_map_hashsize(hp);\n  ret := temp0 - 1;\n}\n\n\n\nmethod cuckoohash_map_partial_key(hash:uint64) returns (ret:uint8)\n{\n  noaddr var hash_64bit:uint64;\n  noaddr var hash_32bit:uint32;\n  noaddr var hash_16bit:uint16;\n  noaddr var hash_8bit:uint8;\n  hash_64bit := hash;\n//  hash_32bit := (hash_64bit as uint32) ^ ((hash_64bit >> 32) as uint32);\n//  hash_16bit := (hash_32bit as uint16) ^ ((hash_32bit >> 16) as uint16);\n//  hash_8bit := (hash_16bit as uint8) ^ ((hash_16bit >> 8) as uint8);\n  ret := hash_8bit;\n}\n\n\n\nmethod cuckoohash_map_index_hash(hp:uint64, hv:uint64) returns (ret:uint64)\n{\n  noaddr var temp0:uint64;\n  temp0 := cuckoohash_map_hashmask(hp);\n  // FIXME: bitwise AND not supported\n  // ret := hv & temp0;\n}\n\n\n\nmethod cuckoohash_map_alt_index(hp:uint64, partial:uint8, index:uint64) returns (ret:uint64)\n{\n  noaddr var nonzero_tag:uint64;\n  noaddr var temp0:uint64;\n  nonzero_tag := (partial as uint64) + 1;\n  temp0 := cuckoohash_map_hashmask(hp);\n  // FIXME:\n  // ret := (index ^ (nonzero_tag * 0xc6a4a7935bd1e995)) & temp0;\n}\n\n\n\nmethod cuckoohash_map_check_hashpower(this_ptr:ptr<cuckoohash_map>, hp:uint64, lock_ptr:ptr<spinlock>) returns (ret:int32)\n{\n  noaddr var temp0:uint64;\n  temp0 := cuckoohash_map_hashpower(this_ptr);\n  if (temp0 != hp)\n  {\n    spinlock_unlock(lock_ptr);\n    ret := 3;\n  }\n  else\n  {\n    ret := 0;\n  }\n}\n\n\n\nmethod cuckoohash_map_lock_one(this_ptr: ptr<cuckoohash_map>, hp: uint64, i: uint64, error_ptr: ptr<int32>) returns (ret: LockManager)\n{\n  noaddr var locks_ptr: ptr<locks_t>;\n  noaddr var lock_ptr: ptr<spinlock>;\n  noaddr var temp0: int32;\n  locks_ptr := cuckoohash_map_get_current_locks(this_ptr);\n  // FIXME:\n  // lock_ptr := (*locks_ptr).data + (i & (65536 - 1));\n  spinlock_lock(lock_ptr);\n  temp0 := cuckoohash_map_check_hashpower(this_ptr, hp, lock_ptr);\n  *(error_ptr) := temp0;\n  if ((*error_ptr) != 0)\n  {\n    ret.lock := null;\n  }\n\n  ret.lock := lock_ptr;\n}\n\n\n\nmethod cuckoohash_map_lock_two(this_ptr:ptr<cuckoohash_map>, hp:uint64, i1:uint64, i2:uint64, error_ptr:ptr<int32>) returns (ret:TwoBuckets)\n{\n  noaddr var l1:uint64;\n  noaddr var l2:uint64;\n  noaddr var templ:uint64;\n  noaddr var locks_ptr:ptr<locks_t>;\n  noaddr var temp0:int32;\n  noaddr var tmpv: ptr<spinlock>;\n\n  // FIXME:\n  // l1 := (i1 & (65536 - 1));\n  // l2 := (i2 & (65536 - 1));\n  if (l2 < l1)\n  {\n    templ := l2;\n    l2 := l1;\n    l1 := templ;\n  }\n\n  locks_ptr := cuckoohash_map_get_current_locks(this_ptr);\n  spinlock_lock((*locks_ptr).data + l1);\n  temp0 := cuckoohash_map_check_hashpower(this_ptr, hp, (*locks_ptr).data + l1);\n  *(error_ptr) := temp0;\n  if ((*error_ptr) != 0)\n  {\n    ((ret).first_manager_).lock := null; ((ret).second_manager_).lock := null;\n    return;\n  }\n\n  if (l2 != l1)\n  {\n    spinlock_lock((*locks_ptr).data + l2);\n  }\n\n  (ret).i1 := i1; (ret).i2 := i2;\n  // FIXME:\n  // tmpv := (*locks_ptr).data + (i1 & (65536 - 1));\n  ((ret).first_manager_).lock := tmpv;\n  // FIXME:\n  // tmpv := (*locks_ptr).data + (i2 & (65536 - 1));\n  // FIXME:\n  // ((ret).second_manager_).lock := if (i1 & (65536 - 1)) != (i2 & (65536 - 1)) then tmpv else null;\n  return;\n}\n\n\n/*\n\nmethod cuckoohash_map_lock_three(this_ptr: ptr<cuckoohash_map>, hp: uint64, i1: uint64, i2: uint64, i3: uint64, error_ptr: ptr<int32>) returns (ret1: TwoBuckets, ret2: LockManager)\n{\n  noaddr var l: uint64[3];\n  noaddr var locks_ptr:ptr<locks_t>;\n  noaddr var temp0: int32;\n  noaddr var tmpv: ptr<spinlock>;\n  l[0] := (i1 & (65536 - 1));\n  l[1] := (i2 & (65536 - 1));\n  l[2] := (i3 & (65536 - 1));\n  if (l[2] < l[1]) {\n    i1 := l[2];\n    l[2] := l[1];\n    l[1] := i1;\n  }\n  if (l[2] < l[0]) {\n    i1 := l[2];\n    l[2] := l[0];\n    l[0] := i1;\n  }\n  if (l[1] < l[0]) {\n    i1 := l[1];\n    l[1] := l[0];\n    l[0] := i1;\n  }\n  locks_ptr := cuckoohash_map_get_current_locks(this_ptr);\n  spinlock_lock((*locks_ptr).data + l[0]);\n  temp0 := cuckoohash_map_check_hashpower(this_ptr, hp, (*locks_ptr).data + l[0]);\n  *error_ptr := temp0;\n  if ((*error_ptr) != 0)\n  {\n    ((ret1).first_manager_).lock := null; ((ret1).second_manager_).lock := null;\n    (ret2).lock := null;\n    return;\n  }\n\n  if (l[1] != l[0])\n  {\n    spinlock_lock((*locks_ptr).data + l[1]);\n  }\n\n  if (l[2] != l[1])\n  {\n    spinlock_lock((*locks_ptr).data + l[2]);\n  }\n\n  (ret1).i1 := i1; (ret1).i2 := i2; tmpv := (*locks_ptr).data + (i1 & (65536 - 1)); ((ret1).first_manager_).lock := tmpv; tmpv := (*locks_ptr).data + (i2 & (65536 - 1)); ((ret1).second_manager_).lock := if (i1 & (65536 - 1)) != (i2 & (65536 - 1)) then tmpv else null;\n  (ret2).lock := if ((i3 & (65536 - 1)) == (i1 & (65536 - 1)) || (i3 & (65536 - 1)) == (i2 & (65536 - 1))) then null else (*locks_ptr).data + (i3 & (65536 - 1));\n\n\n}\n*/\n\nmethod cuckoohash_map_snapshot_and_lock_two(this_ptr:ptr<cuckoohash_map>, hv_ptr:ptr<hash_value>) returns (ret:TwoBuckets)\n{\n  noaddr var hp:uint64;\n  noaddr var i1:uint64;\n  noaddr var i2:uint64;\n  var error:int32;\n  noaddr var tb:TwoBuckets;\n  while (true)\n  {\n    hp := cuckoohash_map_hashpower(this_ptr);\n    i1 := cuckoohash_map_index_hash(hp, (*hv_ptr).hash);\n    i2 := cuckoohash_map_alt_index(hp, (*hv_ptr).partial, i1);\n    tb := cuckoohash_map_lock_two(this_ptr, hp, i1, i2, &error);\n    if (error == 3)\n    {\n      // TODO: empty statement is not allowed. should remove the following\n      // when \"continue\" and \"break\" are added.\n      hp := hp;\n//      continue;\n    }\n    else\n    {\n      ret := tb;\n      return;\n    }\n  }\n}\n\n\n\nmethod cuckoohash_map_snapshot_and_lock_all(this_ptr:ptr<cuckoohash_map>) returns (ret: AllLocksManager)\n{\n  noaddr var first_locked: ptr<all_locks_list_node>;\n  noaddr var current_locks: ptr<all_locks_list_node>;\n  noaddr var locks_ptr:ptr<locks_t>;\n  noaddr var i: uint64;\n\n  first_locked := all_locks_t_get_tail(&(*this_ptr).all_locks_);\n  current_locks := first_locked;\n  while (current_locks != null)\n  {\n    locks_ptr := &((*current_locks).elt);\n    i := 0;\n    while (i < (*locks_ptr).len) {\n      spinlock_lock((*locks_ptr).data + i);\n    }\n    current_locks := (*current_locks).next;\n  }\n\n  (ret).first_locked := first_locked; (ret).active := 1;\n}\n\n\n\nmethod cuckoohash_map_cuckoo_find(this_ptr:ptr<cuckoohash_map>, key_ptr:ptr<int64>, partial:uint8, i1:uint64, i2:uint64) returns (ret:table_position)\n{\n  noaddr var slot:int32;\n  slot := cuckoohash_map_try_read_from_bucket(this_ptr, (*this_ptr).buckets_.buckets_ + i1, partial, key_ptr);\n  if (slot != -1)\n  {\n    ret.index := i1;\n    ret.slot := slot as uint64;\n    ret.status := 0;\n    return;\n  }\n\n  slot := cuckoohash_map_try_read_from_bucket(this_ptr, (*this_ptr).buckets_.buckets_ + i2, partial, key_ptr);\n  if (slot != -1)\n  {\n    ret.index := i2;\n    ret.slot := slot as uint64;\n    ret.status := 0;\n    return;\n  }\n\n  ret.index := 0;\n  ret.slot := 0;\n  ret.status := 2;\n  return;\n}\n\n\n\nmethod cuckoohash_map_try_read_from_bucket(this_ptr:ptr<cuckoohash_map>, b_ptr:ptr<bucket>, partial:uint8, key_ptr:ptr<int64>)\n    returns (ret:int32)\n{\n  noaddr var i:int32;\n  noaddr var temp0:uint8;\n  noaddr var temp1:uint8;\n  noaddr var temp_key_ptr:ptr<int64>;\n  noaddr var temp_key:int64;\n  i := 0;\n  while (i < 4)\n  {\n    temp0 := bucket_occupied_const(b_ptr, i as uint64);\n    temp1 := bucket_partial_const(b_ptr, i as uint64);\n    if (temp0 == 0 || (!false && partial != temp1))\n    {\n      // TODO: empty statement is not allowed. should remove the following\n      // when \"continue\" and \"break\" are added.\n      i := i;\n//      continue;\n    }\n    else\n    {\n      temp_key_ptr := bucket_key(b_ptr, i as uint64);\n      temp_key := *temp_key_ptr;\n      temp0 := ext_key_eq(temp_key, *key_ptr);\n      if (temp0 == 1) {\n        ret := i;\n        return;\n      }\n    }\n    i := i + 1;\n  }\n  ret := -1;\n}\n\n\n\nmethod cuckoohash_map_cuckoo_insert_loop(this_ptr:ptr<cuckoohash_map>, hv_ptr: ptr<hash_value>, b_ptr: ptr<TwoBuckets>, key_ptr: ptr<int64>, error_ptr: ptr<uint8>) returns (ret: table_position)\n{\n  noaddr var pos:table_position;\n  noaddr var hp:uint64;\n  noaddr var tmp_b: TwoBuckets;\n  noaddr var tmp: uint8;\n  *(error_ptr) := 0;\n  while (true)\n  {\n    hp := cuckoohash_map_hashpower(this_ptr);\n    pos := cuckoohash_map_cuckoo_insert(this_ptr, *hv_ptr, b_ptr, key_ptr);\n    if (pos.status == 0 || pos.status == 3)\n    {\n      ret := pos;\n      return;\n    }\n    else if (pos.status == 4)\n    {\n      tmp := cuckoohash_map_cuckoo_fast_double(this_ptr, hp, 1u8, error_ptr);\n      if ((*error_ptr) != 0) {\n        ret := pos;\n        return;\n      }\n      if ((*b_ptr).first_manager_.lock != null) { spinlock_unlock((*b_ptr).first_manager_.lock); } if ((*b_ptr).second_manager_.lock != null) { spinlock_unlock((*b_ptr).second_manager_.lock); }\n      tmp_b := cuckoohash_map_snapshot_and_lock_two(this_ptr, hv_ptr);\n      ((*b_ptr)).i1 := (tmp_b).i1; ((*b_ptr)).i2 := (tmp_b).i2; (((*b_ptr)).first_manager_).lock := ((tmp_b).first_manager_).lock; (((*b_ptr)).second_manager_).lock := ((tmp_b).second_manager_).lock;\n    }\n    else if (pos.status == 5)\n    {\n      if ((*b_ptr).first_manager_.lock != null) { spinlock_unlock((*b_ptr).first_manager_.lock); } if ((*b_ptr).second_manager_.lock != null) { spinlock_unlock((*b_ptr).second_manager_.lock); }\n      tmp_b := cuckoohash_map_snapshot_and_lock_two(this_ptr, hv_ptr);\n      ((*b_ptr)).i1 := (tmp_b).i1; ((*b_ptr)).i2 := (tmp_b).i2; (((*b_ptr)).first_manager_).lock := ((tmp_b).first_manager_).lock; (((*b_ptr)).second_manager_).lock := ((tmp_b).second_manager_).lock;\n    }\n\n\n\n  }\n}\n\n\n\nmethod cuckoohash_map_cuckoo_insert(this_ptr:ptr<cuckoohash_map>, hv: hash_value, b_ptr: ptr<TwoBuckets>, key_ptr: ptr<int64>) returns (ret: table_position)\n{\n  noaddr var b1_ptr: ptr<bucket>;\n  noaddr var temp1: uint8;\n  noaddr var b2_ptr: ptr<bucket>;\n  noaddr var temp2: uint8;\n  noaddr var insert_bucket_ptr: ptr<uint64>;\n  noaddr var insert_slot_ptr: ptr<uint64>;\n  noaddr var st:uint8;\n  noaddr var pos:table_position;\n  noaddr var tmp_v: uint64;\n  noaddr var res1_ptr: ptr<int32>;\n  noaddr var res2_ptr: ptr<int32>;\n  tmp_v := (*b_ptr).i1;\n  b1_ptr := (*this_ptr).buckets_.buckets_ + tmp_v;\n  temp1 := cuckoohash_map_try_find_insert_bucket(this_ptr, b1_ptr, res1_ptr, hv.partial, key_ptr);\n  if (temp1 != 0)\n  {\n    ret.index := (*b_ptr).i1;\n    ret.slot := (*res1_ptr) as uint64;\n    ret.status := 3;\n    return;\n  }\n\n  tmp_v := (*b_ptr).i2;\n  b2_ptr := (*this_ptr).buckets_.buckets_ + tmp_v;\n  temp2 := cuckoohash_map_try_find_insert_bucket(this_ptr, b2_ptr, res2_ptr, hv.partial, key_ptr);\n  if (temp2 != 0)\n  {\n    ret.index := (*b_ptr).i2;\n    ret.slot := (*res2_ptr) as uint64;\n    ret.status := 3;\n    return;\n  }\n\n  if ((*res1_ptr) != -1)\n  {\n    ret.index := (*b_ptr).i1;\n    ret.slot := *res1_ptr as uint64;\n    ret.status := 0;\n    return;\n  }\n\n  if ((*res2_ptr) != -1)\n  {\n    ret.index := (*b_ptr).i2;\n    ret.slot := *res2_ptr as uint64;\n    ret.status := 0;\n    return;\n  }\n\n  *insert_bucket_ptr := 0;\n  *insert_slot_ptr := 0;\n  st := cuckoohash_map_run_cuckoo(this_ptr, b_ptr, insert_bucket_ptr, insert_slot_ptr);\n  if (st == 5)\n  {\n    ret.index := 0;\n    ret.slot := 0;\n    ret.status := 5;\n    return;\n  }\n  else\n  if (st == 0)\n  {\n\n\n\n\n\n\n\n    tmp_v := (*b_ptr).i2;\n    pos := cuckoohash_map_cuckoo_find(this_ptr, key_ptr, hv.partial, (*b_ptr).i1, tmp_v);\n    if (pos.status == 0)\n    {\n      ret.index := pos.index;\n      ret.slot := pos.slot;\n      ret.status := 3;\n      return;\n    }\n\n    ret.index := *insert_bucket_ptr;\n    ret.slot := *insert_slot_ptr;\n    ret.status := 0;\n    return;\n  }\n\n\n  ret.index := 0;\n  ret.slot := 0;\n  ret.status := 4;\n}\n\n\n\nmethod cuckoohash_map_add_to_bucket(this_ptr:ptr<cuckoohash_map>, bucket_ind: uint64, slot: uint64, partial: uint8, key_ptr:ptr<int64>, val_ptr:ptr<int64>)\n{\n  noaddr var temp0: ptr<uint64>;\n  noaddr var locks_ptr: ptr<locks_t>;\n  noaddr var tmp_v: uint64;\n\n  libcuckoo_bucket_container_setKV(&((*this_ptr).buckets_), bucket_ind, slot, partial, key_ptr, val_ptr);\n  locks_ptr := cuckoohash_map_get_current_locks(this_ptr);\n  // FIXME: bitwise AND not supported\n  // temp0 := spinlock_elem_counter((*locks_ptr).data + (bucket_ind & (65536 - 1)));\n  tmp_v := *temp0 + 1;\n  *temp0 := tmp_v;\n}\n\n\n\nmethod cuckoohash_map_try_find_insert_bucket(this_ptr:ptr<cuckoohash_map>, b_ptr: ptr<bucket>, slot_ptr: ptr<int32>, partial: uint8, key_ptr: ptr<int64>) returns (ret: uint8)\n{\n  noaddr var i:int32;\n  noaddr var temp0:uint8;\n  noaddr var temp1:uint8;\n  noaddr var temp2: ptr<int64>;\n  noaddr var temp3: uint8;\n  noaddr var key: int64 := *key_ptr;\n\n  *slot_ptr := -1;\n  i := 0;\n  while (i < 4)\n  {\n    temp0 := bucket_occupied_const(b_ptr, i as uint64);\n    if (temp0 == 1)\n    {\n      temp1 := bucket_partial_const(b_ptr, i as uint64);\n      if (!false && partial != temp1)\n      {\n        // TODO: empty statement is not allowed. should remove the following\n        // when \"continue\" and \"break\" are added.\n        i := i;\n//        continue;\n      }\n\n      temp2 := bucket_key(b_ptr, i as uint64);\n      temp3 := ext_key_eq(*temp2, key);\n      if (temp3 == 1)\n      {\n        *slot_ptr := i;\n        ret := 0;\n        return;\n      }\n    }\n    else\n    {\n      *slot_ptr := i;\n    }\n    i := i + 1;\n  }\n\n  ret := 1;\n}\n\n\n\nmethod cuckoohash_map_run_cuckoo(this_ptr:ptr<cuckoohash_map>, b_ptr: ptr<TwoBuckets>, insert_bucket_ptr: ptr<uint64>, insert_slot_ptr: ptr<uint64>) returns (ret: uint8)\n{\n  noaddr var hp:uint64;\n  var cuckoo_path: CuckooRecord[5];\n  noaddr var done:uint8;\n  var error:int32;\n  noaddr var depth:int8;\n  noaddr var temp0:uint8;\n  noaddr var tmp1: uint64;\n\n  hp := cuckoohash_map_hashpower(this_ptr);\n  TwoBuckets_unlock(b_ptr);\n  done := 0;\n  while (done == 5)\n  {\n    tmp1 := (*b_ptr).i1;\n    depth := cuckoohash_map_cuckoopath_search(this_ptr, hp, &cuckoo_path[0], tmp1, (*b_ptr).i2, &error);\n    if (error == 3)\n    {\n      ret := 5;\n      return;\n    }\n\n    if (depth < 0)\n    {\n      // TODO: empty statement is not allowed. should remove the following\n      // when \"continue\" and \"break\" are added.\n      hp := hp;\n//      break;\n    }\n\n    temp0 := cuckoohash_map_cuckoopath_move(this_ptr, hp, &cuckoo_path[0], depth as uint64, b_ptr, &error);\n    if (temp0 == 1)\n    {\n      tmp1 := cuckoo_path[0].bucket;\n      *insert_bucket_ptr := tmp1;\n      tmp1 := cuckoo_path[0].slot;\n      *insert_slot_ptr := tmp1;\n\n\n\n\n      done := 1;\n//      break;\n    }\n\n    if (error == 3)\n    {\n      ret := 5;\n      return;\n    }\n  }\n\n  ret := if done == 1 then 0 else 1;\n}\n\n\n\nmethod cuckoohash_map_cuckoopath_search(this_ptr: ptr<cuckoohash_map>, hp: uint64, cuckoo_path: ptr<CuckooRecord>, i1: uint64, i2: uint64, error_ptr: ptr<int32>) returns (ret: int8)\n{\n  noaddr var x:b_slot;\n  noaddr var i:int8;\n  noaddr var first_ptr:ptr<CuckooRecord>;\n  noaddr var lock_manager:LockManager;\n  noaddr var b_ptr:ptr<bucket>;\n  noaddr var temp0:uint8;\n  noaddr var curr_ptr:ptr<CuckooRecord>;\n  noaddr var prev_ptr:ptr<CuckooRecord>;\n  noaddr var tmp: ptr<int64>;\n  noaddr var tmp1: uint64;\n  noaddr var tmp2: uint8;\n\n  *(error_ptr) := 0;\n  x := cuckoohash_map_slot_search(this_ptr, hp, i1, i2, error_ptr);\n  if (x.depth == -1)\n  {\n    ret := -1;\n    return;\n  }\n\n  i := x.depth;\n  while (i >= 0)\n  {\n    (*(cuckoo_path + i)).slot := (x.pathcode % 4u16) as uint64;\n    x.pathcode := x.pathcode / 4;\n    i := i - 1;\n  }\n\n  first_ptr := cuckoo_path;\n  if (x.pathcode == 0)\n  {\n    (*first_ptr).bucket := i1;\n  }\n  else\n  {\n\n    (*first_ptr).bucket := i2;\n  }\n\n  {\n    lock_manager := cuckoohash_map_lock_one(this_ptr, hp, (*first_ptr).bucket, error_ptr);\n    if ((*error_ptr) != 0)\n    {\n      if (lock_manager.lock != null) { spinlock_unlock(lock_manager.lock); }\n      ret := -1;\n      return;\n    }\n\n    tmp1 := (*first_ptr).bucket;\n    b_ptr := (*this_ptr).buckets_.buckets_ + tmp1;\n    temp0 := bucket_occupied_const(b_ptr, (*first_ptr).slot);\n    if (temp0 == 0)\n    {\n      if (lock_manager.lock != null) { spinlock_unlock(lock_manager.lock); }\n      ret := 0;\n      return;\n    }\n\n    tmp := bucket_key(b_ptr, (*first_ptr).slot);\n    cuckoohash_map_hashed_key(this_ptr, tmp, &(*first_ptr).hv);\n\n    if (lock_manager.lock != null) { spinlock_unlock(lock_manager.lock); }\n  }\n\n  i := 1;\n  while (i <= x.depth)\n  {\n    curr_ptr := cuckoo_path + i;\n    prev_ptr := cuckoo_path + (i - 1);\n\n\n\n\n\n    tmp2 := (*prev_ptr).hv.partial;\n    tmp1 := (*prev_ptr).bucket;\n    (*curr_ptr).bucket := cuckoohash_map_alt_index(hp, tmp2, tmp1);\n    lock_manager := cuckoohash_map_lock_one(this_ptr, hp, (*curr_ptr).bucket, error_ptr);\n    if ((*error_ptr) != 0)\n    {\n      if (lock_manager.lock != null) { spinlock_unlock(lock_manager.lock); }\n      ret := -1;\n      return;\n    }\n\n    tmp1 := (*curr_ptr).bucket;\n    b_ptr := (*this_ptr).buckets_.buckets_ + tmp1;\n    temp0 := bucket_occupied_const(b_ptr, (*curr_ptr).slot);\n    if (temp0 == 0)\n    {\n      if (lock_manager.lock != null) { spinlock_unlock(lock_manager.lock); }\n      ret := i;\n      return;\n    }\n\n    tmp := bucket_key(b_ptr, (*curr_ptr).slot);\n    cuckoohash_map_hashed_key(this_ptr, tmp, &(*curr_ptr).hv);\n\n    if (lock_manager.lock != null) { spinlock_unlock(lock_manager.lock); }\n    i := i + 1;\n  }\n\n  ret := x.depth;\n}\n\n\n\nmethod cuckoohash_map_cuckoopath_move(this_ptr: ptr<cuckoohash_map>, hp: uint64, cuckoo_path: ptr<CuckooRecord>, depth: uint64, b_ptr: ptr<TwoBuckets>, error_ptr: ptr<int32>) returns (ret: uint8)\n{\n  noaddr var bucket: uint64;\n  noaddr var temp0: uint8;\n  noaddr var from_ptr: ptr<CuckooRecord>;\n  noaddr var to_ptr: ptr<CuckooRecord>;\n  noaddr var fs: uint64;\n  noaddr var ts: uint64;\n  noaddr var twob: TwoBuckets;\n  noaddr var extra_manager: LockManager;\n  noaddr var fb_ptr: ptr<bucket>;\n  noaddr var tb_ptr: ptr<bucket>;\n  noaddr var temp1: uint8;\n  noaddr var temp2: uint8;\n  noaddr var temp3: ptr<int64>;\n  noaddr var temp4: uint64;\n  noaddr var temp5: uint8;\n  noaddr var temp6: ptr<int64>;\n  noaddr var temp7: ptr<int64>;\n  noaddr var temp8: ptr<bucket>;\n\n  noaddr var tmp_i1: uint64;\n  noaddr var tmp_i2: uint64;\n  noaddr var tmp_b: TwoBuckets;\n\n  *error_ptr := 0;\n  if (depth == 0)\n  {\n    bucket := (*cuckoo_path).bucket;\n\n\n    tmp_i1 := (*b_ptr).i1;\n    tmp_b := cuckoohash_map_lock_two(this_ptr, hp, tmp_i1, (*b_ptr).i2, error_ptr);\n    (*b_ptr).i1 := (tmp_b).i1; (*b_ptr).i2 := (tmp_b).i2; ((*b_ptr).first_manager_).lock := ((tmp_b).first_manager_).lock; ((*b_ptr).second_manager_).lock := ((tmp_b).second_manager_).lock;\n\n    if ((*error_ptr) != 0)\n    {\n      ret := 0;\n      return;\n    }\n\n    temp8 := (*this_ptr).buckets_.buckets_ + bucket;\n    temp0 := bucket_occupied_const(temp8, (*cuckoo_path).slot);\n    if (temp0 == 0)\n    {\n      ret := 1;\n      return;\n    }\n    else\n    {\n      TwoBuckets_unlock(b_ptr);\n      ret := 0;\n      return;\n    }\n  }\n\n  while (depth > 0)\n  {\n    from_ptr := cuckoo_path + (depth - 1);\n    to_ptr := cuckoo_path + depth;\n    fs := (*from_ptr).slot;\n    ts := (*to_ptr).slot;\n\n    (extra_manager).lock := null;\n\n    if (depth == 1)\n    {\n      tmp_i1 := (*b_ptr).i1;\n      tmp_i2 := (*b_ptr).i2;\n      //twob, extra_manager := cuckoohash_map_lock_three(this_ptr, hp, tmp_i1, tmp_i2, (*to_ptr).bucket, error_ptr);\n    }\n    else\n    {\n      temp4 := (*from_ptr).bucket;\n      twob := cuckoohash_map_lock_two(this_ptr, hp, temp4, (*to_ptr).bucket, error_ptr);\n    }\n\n    if ((*error_ptr) != 0)\n    {\n      ret := 0;\n      return;\n    }\n\n    temp4 := (*from_ptr).bucket;\n    fb_ptr := (*this_ptr).buckets_.buckets_ + temp4;\n    temp4 := (*to_ptr).bucket;\n    tb_ptr := (*this_ptr).buckets_.buckets_ + temp4;\n\n    temp1 := bucket_occupied_const(tb_ptr, ts);\n    temp2 := bucket_occupied_const(fb_ptr, fs);\n    temp3 := bucket_key(fb_ptr, fs);\n    temp4 := cuckoohash_map_hashed_key_only_hash(temp3);\n    if (temp1 != 0 || temp2 == 0 || temp4 != (*from_ptr).hv.hash)\n    {\n      ret := 0;\n      return;\n    }\n\n    temp5 := bucket_partial_const(fb_ptr, fs);\n    temp6 := bucket_key(fb_ptr, fs);\n    temp7 := bucket_mapped(fb_ptr, fs);\n    libcuckoo_bucket_container_setKV(&((*this_ptr).buckets_), (*to_ptr).bucket, ts, temp5, temp6, temp7);\n    libcuckoo_bucket_container_eraseKV(&((*this_ptr).buckets_), (*from_ptr).bucket, fs);\n\n    if (depth == 1)\n    {\n      if ((*b_ptr).first_manager_.lock != null) { spinlock_unlock((*b_ptr).first_manager_.lock); } if ((*b_ptr).second_manager_.lock != null) { spinlock_unlock((*b_ptr).second_manager_.lock); }\n      ((*b_ptr)).i1 := (twob).i1; ((*b_ptr)).i2 := (twob).i2; (((*b_ptr)).first_manager_).lock := ((twob).first_manager_).lock; (((*b_ptr)).second_manager_).lock := ((twob).second_manager_).lock;\n    } else {\n      if (twob.first_manager_.lock != null) { spinlock_unlock(twob.first_manager_.lock); } if (twob.second_manager_.lock != null) { spinlock_unlock(twob.second_manager_.lock); }\n    }\n\n    if (extra_manager.lock != null) { spinlock_unlock(extra_manager.lock); }\n\n    depth := depth - 1;\n\n  }\n\n  ret := 1;\n}\n\n\n\nmethod cuckoohash_map_slot_search(this_ptr: ptr<cuckoohash_map>, hp: uint64, i1: uint64, i2: uint64, error_ptr: ptr<int32>) returns (ret: b_slot)\n{\n  noaddr var q: b_queue;\n  noaddr var temp0: uint8;\n  noaddr var x: b_slot;\n  noaddr var lock_manager: LockManager;\n  noaddr var b_ptr: ptr<bucket>;\n  noaddr var starting_slot: uint64;\n  noaddr var i: uint64;\n  noaddr var slot: uint16;\n  noaddr var temp1: uint8;\n  noaddr var partial: uint8;\n  noaddr var y:b_slot;\n  noaddr var tmp_b : b_slot;\n\n  q.first_ := 0; q.last_ := 0;\n  tmp_b.bucket := i1; tmp_b.pathcode := 0; tmp_b.depth := 0;\n  q.slots_[q.last_] := tmp_b; q.last_ := q.last_ + 1;\n  tmp_b.bucket := i2; tmp_b.pathcode := 1; tmp_b.depth := 0;\n  q.slots_[q.last_] := tmp_b; q.last_ := q.last_ + 1;\n  temp0 := if q.first_ == q.last_ then 1 else 0;\n  while (temp0 == 0)\n  {\n    x := q.slots_[q.first_]; q.first_ := q.first_ + 1;\n    lock_manager := cuckoohash_map_lock_one(this_ptr, hp, x.bucket, error_ptr);\n    if ((*error_ptr) != 0)\n    {\n      tmp_b.bucket := 0; tmp_b.pathcode := 0; tmp_b.depth := -1;\n      ret := tmp_b;\n      return;\n    }\n\n    b_ptr := (*this_ptr).buckets_.buckets_ + x.bucket;\n    starting_slot := (x.pathcode % 4) as uint64;\n    i := 0;\n    while (i < 4)\n    {\n      slot := ((starting_slot + i) % 4) as uint16;\n      temp1 := bucket_occupied_const(b_ptr, slot as uint64);\n      if (temp1 == 0)\n      {\n        x.pathcode := (x.pathcode << 2u16) + slot;\n        ret := x;\n        return;\n      }\n\n      partial := bucket_partial_const(b_ptr, slot as uint64);\n      if (x.depth < 5 - 1)\n      {\n\n        y.bucket := cuckoohash_map_alt_index(hp, partial, x.bucket); y.pathcode := (x.pathcode << 2u16) + slot; y.depth := x.depth + 1;\n        q.slots_[q.last_] := y; q.last_ := q.last_ + 1;\n      }\n\n      i := i + 1;\n    }\n    temp0 := if q.first_ == q.last_ then 1 else 0;\n  }\n  tmp_b.bucket := 0; tmp_b.pathcode := 0; tmp_b.depth := -1;\n  ret := tmp_b;\n}\n\n\n\nmethod cuckoohash_map_cuckoo_fast_double(this_ptr:ptr<cuckoohash_map>, current_hp: uint64, auto_resize: uint8, error_ptr: ptr<uint8>) returns (ret: uint8)\n{\n  noaddr var new_hp:uint64;\n  noaddr var all_locks_manager: AllLocksManager;\n  noaddr var st: uint8;\n  var new_buckets: bucket_container;\n  noaddr var start:uint64;\n  noaddr var end:uint64;\n  noaddr var num_threads: uint64;\n  noaddr var work_per_thread: uint64;\n  noaddr var threads_ptr: ptr<tid_t>;\n  noaddr var errors_ptr: ptr<uint8>;\n  noaddr var i:uint64;\n  noaddr var temp0: uint8;\n\n  noaddr var tmp_buckets: bucket_container;\n\n  *error_ptr := 0;\n\n\n\n\n\n\n\n  new_hp := current_hp + 1;\n  all_locks_manager := cuckoohash_map_snapshot_and_lock_all(this_ptr);\n  st := cuckoohash_map_check_resize_validity(this_ptr, current_hp, new_hp, auto_resize, error_ptr);\n  if (st != 0)\n  {\n    ret := st;\n    return;\n  }\n\n  bucket_container_bucket_container(&new_buckets, new_hp);\n\n  start := 0;\n  end := cuckoohash_map_hashsize(current_hp);\n  num_threads := ext_hardware_concurrency();\n  num_threads := if num_threads < 1 then 1 else num_threads;\n\n  work_per_thread := (end - start) / num_threads;\n  threads_ptr := calloc(tid_t, num_threads);\n  errors_ptr := calloc(uint8, num_threads);\n  i := 0;\n  while (i < num_threads - 1)\n  {\n    *(errors_ptr + i) := 0;\n    *(threads_ptr + i) := create_thread cuckoohash_map_move_buckets(this_ptr, &new_buckets, current_hp, new_hp, start, start + work_per_thread, errors_ptr + i);\n    start := start + work_per_thread;\n    i := i + 1;\n  }\n\n  *(errors_ptr + i) := 0;\n  *(threads_ptr + i) := create_thread cuckoohash_map_move_buckets(this_ptr, &new_buckets, current_hp, new_hp, start, end, errors_ptr + i);\n  i := 0;\n  while (i < num_threads)\n  {\n    join *(threads_ptr + i);\n    i := i + 1;\n  }\n\n  *error_ptr := 0;\n  i := 0;\n  while (i < num_threads)\n  {\n    if ((*(errors_ptr + i)) != 0)\n    {\n      temp0 := *(errors_ptr + i);\n      *error_ptr := temp0;\n      ret := 1;\n      return;\n    }\n    i := i + 1;\n  }\n\n  free(threads_ptr);\n  free(errors_ptr);\n\n  cuckoohash_map_maybe_resize_locks(this_ptr, 1ull << new_hp);\n  libcuckoo_bucket_container_destroy_buckets(&(*this_ptr).buckets_);\n\n  tmp_buckets.hashpower_ := new_buckets.hashpower_;\n  tmp_buckets.buckets_ := new_buckets.buckets_;\n\n  (*this_ptr).buckets_.hashpower_ := tmp_buckets.hashpower_;\n  (*this_ptr).buckets_.buckets_ := tmp_buckets.buckets_;\n  ret := 0;\n}\n\nmethod cuckoohash_map_move_buckets(this_ptr: ptr<cuckoohash_map>, new_buckets_ptr: ptr<bucket_container>, current_hp: uint64, new_hp: uint64, start_ind: uint64, end_ind: uint64, error_ptr: ptr<uint8>)\n{\n  noaddr var old_bucket_ind: uint64;\n  noaddr var old_bucket_ptr: ptr<bucket>;\n  noaddr var new_bucket_ind: uint64;\n  noaddr var temp0: uint64;\n  noaddr var new_bucket_slot:uint64;\n  noaddr var old_bucket_slot:uint64;\n  noaddr var temp1: uint8;\n  noaddr var t_k: ptr<int64>;\n  noaddr var hv: hash_value;\n  noaddr var old_ihash: uint64;\n  noaddr var old_ahash: uint64;\n  noaddr var new_ihash:uint64;\n  noaddr var new_ahash:uint64;\n  noaddr var temp2:uint8;\n  noaddr var temp3:ptr<int64>;\n  noaddr var temp4:ptr<int64>;\n  noaddr var dst_bucket_ind: uint64;\n  noaddr var dst_bucket_slot: uint64;\n\n  *error_ptr := 0;\n  old_bucket_ind := start_ind;\n  while (old_bucket_ind < end_ind)\n  {\n    old_bucket_ptr := (*this_ptr).buckets_.buckets_ + old_bucket_ind;\n    temp0 := cuckoohash_map_hashsize(current_hp);\n    new_bucket_ind := old_bucket_ind + temp0;\n    new_bucket_slot := 0;\n    old_bucket_slot := 0;\n    while (old_bucket_slot < 4)\n    {\n      temp1 := bucket_occupied_const(old_bucket_ptr, old_bucket_slot);\n      if (temp1 == 0)\n      {\n        // TODO: empty statement is not allowed. should remove the following\n        // when \"continue\" and \"break\" are added.\n        temp1 := temp1;\n//        continue;\n      }\n\n      t_k := bucket_key(old_bucket_ptr, old_bucket_slot);\n      hv := cuckoohash_map_hashed_key_const(this_ptr, t_k);\n      old_ihash := cuckoohash_map_index_hash(current_hp, hv.hash);\n      old_ahash := cuckoohash_map_alt_index(current_hp, hv.partial, old_ihash);\n      new_ihash := cuckoohash_map_index_hash(new_hp, hv.hash);\n      new_ahash := cuckoohash_map_alt_index(new_hp, hv.partial, new_ihash);\n      if ((old_bucket_ind == old_ihash && new_ihash == new_bucket_ind) ||\n          (old_bucket_ind == old_ahash && new_ahash == new_bucket_ind))\n      {\n        dst_bucket_ind := new_bucket_ind;\n        dst_bucket_slot := new_bucket_slot;\n        new_bucket_slot := new_bucket_slot + 1;\n      }\n      else\n      {\n\n\n        dst_bucket_ind := old_bucket_ind;\n        dst_bucket_slot := old_bucket_slot;\n      }\n\n      temp2 := bucket_partial_const(old_bucket_ptr, old_bucket_slot);\n      temp3 := bucket_key(old_bucket_ptr, old_bucket_slot);\n      temp4 := bucket_mapped(old_bucket_ptr, old_bucket_slot);\n      libcuckoo_bucket_container_setKV(new_buckets_ptr, dst_bucket_ind, dst_bucket_slot, temp2, temp3, temp4);\n\n      dst_bucket_slot := dst_bucket_slot + 1;\n      old_bucket_slot := old_bucket_slot + 1;\n    }\n    old_bucket_ind := old_bucket_ind + 1;\n  }\n}\n\nmethod cuckoohash_map_check_resize_validity(this_ptr: ptr<cuckoohash_map>, orig_hp: uint64, new_hp: uint64, auto_resize: uint8, error_ptr: ptr<uint8>) returns (ret: uint8)\n{\n  noaddr var mhp: uint64;\n  noaddr var temp_frac: u64frac;\n  noaddr var lf_num: uint64;\n  noaddr var lf_dec: uint64;\n  noaddr var temp2: uint64;\n\n  *error_ptr := 0;\n  mhp := cuckoohash_map_maximum_hashpower(this_ptr);\n  if (mhp != 18446744073709551615ull && new_hp > mhp)\n  {\n    *error_ptr := 5;\n    ret := 1;\n    return;\n  }\n\n  temp_frac := cuckoohash_map_load_factor(this_ptr);\n  lf_num := (*this_ptr).minimum_load_factor_num;\n  lf_dec := (*this_ptr).minimum_load_factor_dec;\n  if (auto_resize != 0 && temp_frac.n * lf_dec < lf_num * temp_frac.d)\n  {\n    *error_ptr := 4;\n    ret := 1;\n    return;\n  }\n\n  temp2 := cuckoohash_map_hashpower(this_ptr);\n  if (temp2 != orig_hp)\n  {\n\n    ret := 5;\n    return;\n  }\n\n  ret := 0;\n}\n\n\n\nmethod cuckoohash_map_maybe_resize_locks(this_ptr: ptr<cuckoohash_map>, new_bucket_count: uint64)\n{\n  noaddr var current_locks_ptr:ptr<locks_t>;\n  noaddr var temp0: uint64;\n  noaddr var temp1: uint64;\n  noaddr var new_tail: ptr<all_locks_list_node>;\n  noaddr var new_locks_ptr:ptr<locks_t>;\n  noaddr var i: uint64;\n  noaddr var tmp: ptr<spinlock>;\n  noaddr var t1: uint8;\n  noaddr var t2: uint64;\n\n  current_locks_ptr := cuckoohash_map_get_current_locks(this_ptr);\n  temp0 := (*current_locks_ptr).len;\n  temp1 := (*current_locks_ptr).len;\n  if (!(temp0 < 65536 && temp1 < new_bucket_count))\n  {\n    return;\n  }\n\n  new_tail := malloc(all_locks_list_node, 1);\n  all_locks_list_node_all_locks_list_node(new_tail, if 65536ull < new_bucket_count then 65536ull else new_bucket_count);\n  new_locks_ptr := &((*new_tail).elt);\n  i := 0;\n  while (i < (*new_locks_ptr).len) {\n    spinlock_lock((*new_locks_ptr).data + i);\n  }\n\n\n  i := 0;\n  while (i < (*current_locks_ptr).len) {\n    tmp := (*current_locks_ptr).data + i;\n    t1 := (*tmp).lock_;\n    t2 := (*tmp).elem_counter_;\n\n    tmp := (*new_locks_ptr).data + i;\n    (*tmp).lock_ := t1;\n    (*tmp).elem_counter_ := t2;\n  }\n  all_locks_t_append(&((*this_ptr).all_locks_), new_tail);\n}\n\n    method main ()\n    {\n      // Main cannot be empty\n      var i:int := 0;\n      i := i + 1;\n    }\n\n}"
  },
  {
    "path": "experimental/Tests/parser/AST/A.arm",
    "content": "level A {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n\n        x := 5;\n        y := 10;\n    }\n}\n\n"
  },
  {
    "path": "experimental/Tests/parser/AST/A.arm.expect",
    "content": "Tests/parser/AST/A.arm\nlevel A {\n  method main ()\n  {\n    var x:uint64 := 0;\n    var y:uint64 := 0;\n    var z:uint64 := 0;\n    x := 5;\n    y := 10;\n  }\n}\n\n"
  },
  {
    "path": "experimental/Tests/parser/AST/AB.arm",
    "content": "include \"A.arm\"\ninclude \"B.arm\"\n\nproof AB {\n    refinement A B\n    var_intro z\n}\n"
  },
  {
    "path": "experimental/Tests/parser/AST/AB.arm.expect",
    "content": "Tests/parser/AST/AB.arm\nlevel A {\n  method main () {\n    var x:uint64_t := 0;\n    var y:uint64_t := 0;\n    var z:uint64_t := 0;\n    x := 5;\n    y := 10;\n  }\n}\nlevel B {\n  method main () {\n    var x:uint64_t := 0;\n    var y:uint64_t := 0;\n    var z:uint64_t := 0;\n    x := 5;\n    label l1:\n    y := 10;\n    label l2:\n    z := 1;\n  }\n}\nproof AB {\n  refinement A B\n  var_intro z\n}\n\n"
  },
  {
    "path": "experimental/Tests/parser/AST/B.arm",
    "content": "level B {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n\n        x := 5;\n        label l1:\n        y := 10;\n        label l2:\n        z := 1;\n    }\n}\n        \n"
  },
  {
    "path": "experimental/Tests/parser/AST/B.arm.expect",
    "content": "Tests/parser/AST/B.arm\nlevel B {\n  method main ()\n  {\n    var x:uint64 := 0;\n    var y:uint64 := 0;\n    var z:uint64 := 0;\n    x := 5;\n    label l1:\n    y := 10;\n    label l2:\n    z := 1;\n  }\n}\n\n"
  },
  {
    "path": "experimental/Tests/parser/AST/BC.arm",
    "content": "include \"B.arm\"\ninclude \"C.arm\"\n\nproof BC {\n    refinement B C\n    combining l1 l2 l3\n}\n"
  },
  {
    "path": "experimental/Tests/parser/AST/BC.arm.expect",
    "content": "Tests/parser/AST/BC.arm\nlevel B {\n  method main () {\n    var x:uint64_t := 0;\n    var y:uint64_t := 0;\n    var z:uint64_t := 0;\n    x := 5;\n    label l1:\n    y := 10;\n    label l2:\n    z := 1;\n  }\n}\nlevel C {\n  method main () {\n    var x:uint64_t := 0;\n    var y:uint64_t := 0;\n    var z:uint64_t := 0;\n    x := 5;\n    label l3:\n    atomic\n    {\n      y := 10;\n      z := 1;\n    }\n  }\n}\nproof BC {\n  refinement B C\n  combining l1 l2 l3\n}\n\n"
  },
  {
    "path": "experimental/Tests/parser/AST/C.arm",
    "content": "level C {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n\n        x := 5;\n        label l3:\n        atomic\n        {\n            y := 10;\n            z := 1;\n        }\n    }\n}\n\n"
  },
  {
    "path": "experimental/Tests/parser/AST/C.arm.expect",
    "content": "Tests/parser/AST/C.arm\nlevel C {\n  method main ()\n  {\n    var x:uint64 := 0;\n    var y:uint64 := 0;\n    var z:uint64 := 0;\n    x := 5;\n    label l3:\n    atomic\n    {\n      y := 10;\n      z := 1;\n    }\n  }\n}\n\n"
  },
  {
    "path": "experimental/Tests/parser/AST/CD.arm",
    "content": "include \"C.arm\"\ninclude \"D.arm\"\n\nproof CD {\n    refinement C D\n    var_intro w\n}\n"
  },
  {
    "path": "experimental/Tests/parser/AST/CD.arm.expect",
    "content": "Tests/parser/AST/CD.arm\nlevel C {\n  method main () {\n    var x:uint64_t := 0;\n    var y:uint64_t := 0;\n    var z:uint64_t := 0;\n    x := 5;\n    label l3:\n    atomic\n    {\n      y := 10;\n      z := 1;\n    }\n  }\n}\nlevel D {\n  method main () {\n    var x:uint64_t := 0;\n    var y:uint64_t := 0;\n    var z:uint64_t := 0;\n    var w:uint64_t := 0;\n    x := 5;\n    label l3:\n    atomic\n    {\n      y := 10;\n      w := 2;\n      z := 1;\n    }\n  }\n}\nproof CD {\n  refinement C D\n  var_intro w\n}\n\n"
  },
  {
    "path": "experimental/Tests/parser/AST/D.arm",
    "content": "level D {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n        var w:uint64 := 0;\n\n        x := 5;\n        label l3:\n        atomic\n        {\n            y := 10;\n            w := 2;\n            z := 1;\n        }\n    }\n}\n        \n"
  },
  {
    "path": "experimental/Tests/parser/AST/D.arm.expect",
    "content": "Tests/parser/AST/D.arm\nlevel D {\n  method main ()\n  {\n    var x:uint64 := 0;\n    var y:uint64 := 0;\n    var z:uint64 := 0;\n    var w:uint64 := 0;\n    x := 5;\n    label l3:\n    atomic\n    {\n      y := 10;\n      w := 2;\n      z := 1;\n    }\n  }\n}\n\n"
  },
  {
    "path": "experimental/Tests/parser/AST/DE.arm",
    "content": "include \"C.arm\"\ninclude \"D.arm\"\n\nproof CD {\n    refinement C D\n    tso_elim x\n}\n"
  },
  {
    "path": "experimental/Tests/parser/AST/E.arm",
    "content": "level D {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n        var w:uint64 := 0;\n\n        x ::= 5;\n        label l3:\n        atomic\n        {\n            y := 10;\n            w := 2;\n            z := 1;\n        }\n    }\n}\n        \n"
  },
  {
    "path": "experimental/Tests/parser/AST/EndlessExpression.arm",
    "content": "level X {\n    method main() {\n        var x:int;\n        x := if 0 == 1 then 1 else 1 + 2;\n        x := assert x == 1; 1 + 2;\n        x := reveal 1 + 2;\n        // MatchCaseExpr\n        x := match x {\n            case ident (id, id:type, id(casepattern_id)) => 1\n        };\n        // QuantifierExpr\n        x := forall id0:int, id1:int, id2:int {: id expr0, expr1} | expr :: 3;\n        x := exists id:int :: expr;\n        // SetComprehensionExpr\n        x := iset id:int {: id expr0, expr1} | rangeExpr :: bodyExpr;\n        x := set id:int | rangeExpr;\n        // MapDisplayExpr\n        x := map [1:= 2, 3:=4];\n        x := imap [];\n        // MapComprehensionExpr\n        x := map id:int {: id expr0, expr1} | rangeExpr :: bodyExpr := valueExpr;\n        x := imap id:int {: id expr0, expr1} :: bodyExpr;\n        // LabelExpr\n        x := label id: expr;\n    }\n}"
  },
  {
    "path": "experimental/Tests/parser/AST/EndlessExpression.arm.expect",
    "content": "Tests/parser/AST/EndlessExpression.arm\nlevel X {\n  method main ()\n  {\n    var x:int;\n    x := if 0 == 1 then 1 else 1 + 2;\n    x := assert x == 1; 1 + 2;\n    x := reveal 1 + 2;\n    x := match x {case ident (id, id, id(casepattern_id)) => 1};\n    x := forall id0, id1, id2 {: id expr0, expr1} | expr :: 3;\n    x := exists id :: expr;\n    x := iset id {: id expr0, expr1} | rangeExpr :: bodyExpr;\n    x := set id | rangeExpr :: id;\n    x := map [1:=2, 3:=4];\n    x := imap [];\n    x := map id {: id expr0, expr1} | rangeExpr :: bodyExpr := valueExpr;\n    x := imap id {: id expr0, expr1} :: bodyExpr;\n    x := label id: expr;\n  }\n}\n\n"
  },
  {
    "path": "experimental/Tests/parser/AST/Statement.arm",
    "content": "level X {\n    method main() {\n        var x:uint64 := 0;\n        if x == 0\n        {\n            x := 1;\n        }\n        while x == 1\n        {\n            x := x + 2;\n        }\n        assert x == 1;\n        assume x == 1;\n        wait_until x == 1;\n    }\n}"
  },
  {
    "path": "experimental/Tests/parser/AST/Statement.arm.expect",
    "content": "Tests/parser/AST/Statement.arm\nlevel X {\n  method main ()\n  {\n    var x:uint64 := 0;\n    if x == 0\n    {\n      x := 1;\n    }\n    while x == 1\n    {\n      x := x + 2;\n    }\n    assert x == 1;\n    assume x == 1;\n    wait_until x == 1;\n  }\n}\n\n"
  },
  {
    "path": "experimental/Tests/parser/AST/array.arm",
    "content": "level A {\n    method main()\n    {\n        var p:ptr<int>;\n        var arr:int[10];\n        p := calloc(int, 1);\n        *p := 2;\n        arr[2] := 1;\n    }\n}\n"
  },
  {
    "path": "experimental/Tests/parser/AST/array.c",
    "content": "#include <stdint.h>\n#include <pthread.h>\n#include <assert.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdatomic.h>\nvoid _main() {\n  int* p;\n  int arr[10];\n  p = (int*) calloc(sizeof(int), 1);\n  *p = 2;\n  arr[2] = 1;\n}\n\n\nint main() {\n  _main();\n  pthread_exit(NULL);\n}\n"
  },
  {
    "path": "experimental/Tests/parser/AST/state.arm",
    "content": "level A {\n    method main()\n    {\n        assert $state.initial_tid == 0;\n        assert $state.uniqs_used[0] == 0;\n        // assert $state.stop_reason == Armada.State.NotStopped;\n    }\n}\n"
  },
  {
    "path": "experimental/Tests/parser/AST/state.arm.expect",
    "content": "Tests/parser/AST/state.arm\nlevel A {\n  method main ()\n  {\n    assert $state.initial_tid == 0;\n    assert $state.uniqs_used[0] == 0;\n  }\n}\n\n"
  },
  {
    "path": "experimental/Tests/parser/AST/struct.arm",
    "content": "struct st {\n    var a:nat;\n    var b:bool;\n}\n\nlevel A {\n    method main()\n    {\n        var x:st;\n        x.a := 10;\n        x.b := true;\n    }\n}\n"
  },
  {
    "path": "experimental/Tests/parser/AST/struct.arm.expect",
    "content": "Tests/parser/AST/struct.arm\nstruct st {\n  var a:nat;\n  var b:bool;\n}\nlevel A {\n  method main ()\n  {\n    var x:st;\n    x.a := 10;\n    x.b := true;\n  }\n}\n"
  },
  {
    "path": "experimental/Tests/parser/AST/suffix.arm",
    "content": "level A {\n    method f(a:int) returns (z:int)\n    {\n        return a;\n    }\n    method f(a:int, b:int) returns (z:int)\n    {\n        return a + b;\n    }\n    method main()\n    {\n        var arr:seq<int>;\n        var x:int := 0;\n        var y:int := 1;\n\n        f(x);\n        f(0);\n        f(x + y);\n        f(x, x + y);\n        arr[0];\n        arr[x..y];\n        arr[..y];\n        arr[x..];\n        arr[x+y..];\n        arr[x:=x+y];\n        // arr[x:=x+y] := 1;\n    }\n}\n"
  },
  {
    "path": "experimental/Tests/parser/AST/suffix.arm.expect",
    "content": "Tests/parser/AST/suffix.arm\nlevel A {\n  method f (a:int) returns (z:int) {\n    return a;\n  }\n  method f (a:int, b:int) returns (z:int) {\n    return a + b;\n  }\n  method main () {\n    var arr:seq<int>;\n    var x:int := 0;\n    var y:int := 1;\n    f(x);\n    f(0);\n    f(x + y);\n    f(x, x + y);\n    arr[0];\n    arr[x..y];\n    arr[..y];\n    arr[x..];\n    arr[x + y..];\n    arr[x:= x + y];\n  }\n}\n\n"
  },
  {
    "path": "experimental/Tests/parser/TypeResolver/boundedInt.arm",
    "content": "struct Str {\n    var x:int64 := 18446744073709551615;\n    var y:int := 100;\n    var z:int8 := -129;\n    var w:uint64 := -128ull;\n}"
  },
  {
    "path": "experimental/Tests/parser/TypeResolver/boundedInt.arm.expect",
    "content": "Tests/parser/TypeResolver/boundedInt.arm\nstruct Str {\n  var x:int64_t := 18446744073709551615;\n  var y:int := 100;\n  var z:int8_t := -129;\n  var w:uint64_t := -128;\n}\n\n18446744073709551615(2,19): Warning: 18446744073709551615 doesn't fit in int64!\n-129(4,18): Warning: -129 doesn't fit in int8!\n-128ull(5,20): Warning: -128ull doesn't fit in uint64!\n-128ull(5,20): Warning: -128ull is both negative and unsigned! It will be casted to uint64_t\n"
  },
  {
    "path": "experimental/Tests/parser/TypeResolver/collectionType.arm",
    "content": "level A\n{\n    var A:map<int, int>;\n    var B:seq<bool>;\n    var C:set<int>;\n    var D:iset<int>;\n    var E:ptr<int>;\n}"
  },
  {
    "path": "experimental/Tests/parser/TypeResolver/collectionType.arm.expect",
    "content": "level A {\n    var A:map<int, int>;\n    var B:seq<bool>;\n    var C:set<int>;\n    var D:iset<int>;\n    var E:ptr<int>;\n}"
  },
  {
    "path": "experimental/Tests/parser/TypeResolver/ifExpr.arm",
    "content": "level C {\n    method main()\n    {\n        var x:uint64 := 5;\n        var y:uint64 := 10;\n        var z:uint64;\n\n        z := if z < 0 then x else y;\n    }\n}"
  },
  {
    "path": "experimental/Tests/parser/TypeResolver/literalExpr.arm",
    "content": "level A {\n    method main()\n    {\n        var x:bool;\n        var y:char;\n        var z:string;\n\n        x := false;\n        y := 'c';\n        z := \"string\";\n    }\n}"
  },
  {
    "path": "experimental/Tests/parser/TypeResolver/malloc.arm",
    "content": "level A {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n        \n        var p:ptr<int> := malloc(int);\n\n        x := 5;\n        y := 10;\n    }\n}"
  },
  {
    "path": "experimental/Tests/parser/TypeResolver/method.arm",
    "content": "level A {\n    method foo(x:int, y:int) returns (z:int) {\n        x := x + 4;\n        z := y;\n        return x + y;\n    }\n\n    method foo(x:int) returns (z:int) {\n        z := x;\n    }\n\n    method bar(x:int) {\n        x := x + 4;\n    }\n\n    invariant inv1{x}\n\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n        noaddr var tid1:uint64 := 0;\n\n        x := 5;\n        y := 10;\n\n        var p:ptr<int64> := calloc(int64, 3);\n        tid1 := create_thread foo(3, 4);\n        tid1 := create_thread bar(3);\n        z := foo(3, 4) + foo(3) + foo(1, 2, 3);\n\n        assert inv1(true)\n        *p := 4;\n    }\n}"
  },
  {
    "path": "experimental/Tests/parser/TypeResolver/pointer.arm",
    "content": "level A {\n    method foo() {\n        return;\n    }\n\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n        var _p:ptr<uint64> := &x;\n        //var tid:tid_t;\n\n        create_thread foo();\n\n        x := 5;\n        y := 10;\n\n        // TODO: Cannot dereference pointer here?\n        *_p := 4;\n        foo();\n    }\n}"
  },
  {
    "path": "experimental/Tests/parser/TypeResolver/struct.arm",
    "content": "struct Point {\n    var x:int64;\n//    var y:int;\n    var z:int8;\n}\n\ndatatype Option<T> = Some(val:T) | None()\n\nlevel B {\n    var x:int := 10;\n    method main()\n    {\n        var x:set<uint64> := {};\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n        var p:Option<Point>;\n        assert forall y:int | y > 0 :: y == 0;\n\n        //x := foo(y);\n        x := create_thread foo(x);\n        //y := 10;\n//        p.val.z := 666;\n    }\n}"
  },
  {
    "path": "experimental/Tests/parser/compilerTest/arrayDecl.arm",
    "content": "level A {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64[5];\n        z[4] = x;\n        z[3] = y;\n    }\n}"
  },
  {
    "path": "experimental/Tests/parser/compilerTest/createThread.arm",
    "content": "level A {\n    method foo(x:uint64, y:uint64)\n    {\n        x := x + y;\n    }\n\n    method main()\n    {\n        var x:uint64 := 4;\n        var y:uint64 := 3;\n        create_thread foo(x, y);\n    }\n}"
  },
  {
    "path": "experimental/Tests/parser/compilerTest/joinThread.arm",
    "content": "level A {\n    method foo(x:uint64, y:uint64)\n    {\n        x := x + y;\n    }\n\n    method main()\n    {\n        var x:uint64 := 4;\n        var y:uint64 := 3;\n        noaddr var tid1:uint64 := 0;\n\n        tid1 := create_thread foo(x, y);\n        join tid1;\n    }\n}"
  },
  {
    "path": "experimental/Tests/parser/compilerTest/memoryAlloc.arm",
    "content": "level A {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n\n        ptr<uint64> p1 := malloc(uint64);\n        *p1 = 4;\n        ptr<uint64> p2 := calloc(uint64, 3);\n        p2[2] = 4;\n    }\n}\n\n"
  },
  {
    "path": "experimental/Tests/parser/compilerTest/methodDecl.arm",
    "content": "level A {\n    method foo1(x:uint64, y:uint64)\n    {\n        x := x + y;\n    }\n\n    method foo2() \n    {\n        var x:uint64 := 3;\n        x := x - 4;\n    }\n\n    method main()\n    {\n        var x:uint64 := 4;\n        var y:uint64 := 3;\n        noaddr var tid1:uint64 := 0;\n\n        foo1(x, y);\n        foo2();\n    }\n}"
  },
  {
    "path": "experimental/Tests/parser/compilerTest/pointerUsage.arm",
    "content": "level A {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        ptr<uint64> p1 := &x;\n        *p1 = 4;\n        ptr<ptr<uint64> p2 := &p1;\n        **p2 = y;\n    }\n}\n\n"
  },
  {
    "path": "experimental/Tests/parser/compilerTest/primitiveTypes.arm",
    "content": "level A {\n    method main()\n    {\n        var a:uint8 := 0;\n        var b:uint16 := 0;\n        var c:uint32 := 0;\n        var d:uint64 := 0;\n        var e:int8 := 0;\n        var f:int16 := 0;\n        var g:int32 := 0;\n        var h:int64 := 0;\n\n        d := d + 4;\n        f := f - 3;\n\n        var x:int64 := 50;\n        h := h + x;\n        x := x - h;\n    }\n}\n\n"
  },
  {
    "path": "experimental/Tests/parser/compilerTest/structDecl.arm",
    "content": "level A {\n    struct S {\n        var a:int32;\n        var b:int64 := 10;\n    }\n\n    method main()\n    {\n        var a:uint8 := 0;\n        var b:uint16 := 0;\n        var c:S;\n    }\n}\n\n"
  },
  {
    "path": "experimental/Tests/parser/counter/A.arm",
    "content": "level A {\n    noaddr var x:uint32 := 0;\n    ghost var acquire_map: map<uint64, OptionalThread> := map[];\n\n    method {:extern} print_uint32(i:uint32)\n\n    method {:extern} Mutex_Init() returns (m: uint64)\n        ensures m in acquire_map && acquire_map[m] == OptionalNone()\n        ensures m != 0\n    {\n        atomic {\n            somehow modifies m \n                ensures (m !in acquire_map) && (m != 0);\n            acquire_map := acquire_map[m := OptionalNone()];\n        }\n    }\n\n    // decl acquire lock\n    method {:extern} Acquire(m: uint64)\n        ensures m in acquire_map && acquire_map[m] == OptionalSome($me)\n    {\n        assume acquire_map[m].OptionalNone?;\n        acquire_map[m] := OptionalSome($me);\n    }\n\n    // decl release lock\n    method {:extern} Release(m: uint64)\n        ensures m in acquire_map && acquire_map[m] != OptionalSome($me)\n    {\n        atomic {\n            assume $sb_empty;\n            assert acquire_map[m] == OptionalSome($me);\n            acquire_map[m] := OptionalNone();\n        }\n    }\n \n    method inc(m: uint64)\n    {\n        noaddr var y: uint32;\n        Acquire(m);\n        \n        y := x + 1;\n        x := y;\n\n        Release(m);\n    }\n\n    method main()\n    {\n        noaddr var tid1:uint64 := 0;\n        noaddr var tid2:uint64 := 0;\n        noaddr var m:uint64 := 0;\n\n        m := Mutex_Init();\n\n        tid1 := create_thread inc(m);\n        tid2 := create_thread inc(m);\n\n        join tid1;\n        join tid2;\n        \n        print_uint32(x);\n    }\n}\n        \n"
  },
  {
    "path": "experimental/Tests/parser/counter/AB.arm",
    "content": "include \"A.arm\"\ninclude \"B.arm\"\n\nproof AB {\n    refinement A B\n    var_intro mutex, inc1, inc2, done, main_reading\n}\n"
  },
  {
    "path": "experimental/Tests/parser/counter/B.arm",
    "content": "include \"SharedStructs.arm\"\n\nlevel B using SharedStructs{\n    noaddr var x:uint32 := 0;\n    ghost var mutex:uint64 := 0;\n    ghost var acquire_map: map<uint64, OptionalThread> := map[];\n    ghost var inc1:uint64 := 0;\n    ghost var inc2:uint64 := 0;\n    ghost var done: set<uint64> := {};\n    ghost var main_reading: uint8 := 0;\n\n    method {:extern} print_uint32(i:uint32)\n\n    method {:extern} Mutex_Init() returns (m: uint64)\n        ensures m in acquire_map && acquire_map[m] == OptionalNone()\n        ensures m != 0\n    {\n        atomic {\n            somehow modifies m\n                ensures (m !in acquire_map) && (m != 0);\n            acquire_map := acquire_map[m := OptionalNone()];\n        }\n    }\n\n    // decl acquire lock\n    method {:extern} Acquire(m: uint64)\n        requires m in acquire_map\n        ensures m in acquire_map && acquire_map[m] == OptionalSome($me)\n        ensures m == old(m)\n    {\n        assume acquire_map[m].OptionalNone?;\n        acquire_map[m] := OptionalSome($me);\n    }\n\n    // decl release lock\n    method {:extern} Release(m: uint64)\n        requires m in acquire_map\n        ensures m in acquire_map && acquire_map[m] != OptionalSome($me)\n        ensures m == old(m)\n    {\n        atomic {\n            assume $sb_empty;\n            assert acquire_map[m] == OptionalSome($me);\n            acquire_map[m] := OptionalNone();\n        }\n    }\n \n    method inc(m: uint64)\n        requires m == mutex\n    {\n        noaddr var y: uint32;\n        Acquire(m);\n        \n        y := x + 1;\n        atomic {\n        x := y;\n        done := done + {$me};\n        }\n\n        Release(m);\n    }\n\n    method main()\n        requires mutex == 0\n    {\n        noaddr var tid1:uint64 := 0;\n        noaddr var tid2:uint64 := 0;\n        noaddr var m:uint64 := 0;\n        \n        m := Mutex_Init();\n        \n        mutex := m;\n\n        atomic {\n            tid1 := create_thread inc(m);\n            inc1 ::= tid1;\n        }\n\n        atomic {\n            tid2 := create_thread inc(m);\n            inc2 := tid2;\n        }\n\n        join tid1;\n        join tid2;\n        \n        main_reading := 1;\n\n        print_uint32(x);\n    }\n\n    invariant only_mutex_is_used\n    {\n        forall m :: m in acquire_map ==> m == mutex || acquire_map[m].OptionalNone?\n    }\n\n    yield_predicate YP1 \n    {\n        (old(inc1) != 0 ==> inc1 == old(inc1)) &&\n        (old(inc2) != 0 ==> inc2 == old(inc2)) &&\n        (old(mutex) != 0 ==> mutex == old(mutex)) &&\n        (forall m :: m in old(acquire_map) ==> m in acquire_map)\n    }\n\n    yield_predicate YP2\n    {\n        (old(mutex) in old(acquire_map) && old(acquire_map[mutex]) == OptionalSome($me) ==> mutex in acquire_map && acquire_map[mutex] == OptionalSome($me)) &&\n        (old(mutex) in old(acquire_map) && old(acquire_map[mutex]) != OptionalSome($me) ==> mutex in acquire_map && acquire_map[mutex] != OptionalSome($me))\n    }\n}\n"
  },
  {
    "path": "experimental/Tests/parser/counter/BC.arm",
    "content": "include \"B.arm\"\ninclude \"C.arm\"\n\nproof BC {\n    refinement B C\n    assume_intro\n\n    inductive_invariant no_joinable \"forall jtid :: jtid in s.s.joinable_tids ==> jtid !in threads\"\n\n    inductive_invariant zero_is_not_a_mutex \"0 !in ghosts.acquire_map\"\n\n    chl_invariant no_other_threads @\"\n      && (forall tid :: tid in threads ==> (tid == ghosts.inc1 || tid == ghosts.inc2 || tid == tid_init))\n    \"\n\n    chl_invariant inc1_2_uses_mutex @\"\n      forall tid :: tid in {ghosts.inc1, ghosts.inc2} && tid in threads ==> \n        && (threads[tid].top.Armada_StackFrame_Acquire? ==> threads[tid].top.Acquire.m == ghosts.mutex)\n        && (threads[tid].top.Armada_StackFrame_Release? ==> threads[tid].top.Release.m == ghosts.mutex)\n    \"\n\n    chl_invariant no_threads_when_main_reading @\"\n      forall tid :: tid in threads && tid != tid_init ==> ghosts.main_reading == 0\n    \"\n\n    chl_invariant only_mutex_is_used\n\n    chl_invariant GlobalInvariant @\"\n        (ghosts.mutex in ghosts.acquire_map && ghosts.acquire_map[ghosts.mutex].OptionalSome? ==> ghosts.acquire_map[ghosts.mutex].tid in threads)\n    \"\n\n    inductive_invariant One_Main @\"\n        forall tid :: (tid in threads && (threads[tid].top.Armada_StackFrame_main? || \n                                     threads[tid].top.Armada_StackFrame_print_uint32? ||\n                                     threads[tid].top.Armada_StackFrame_Mutex_Init?))\n                  <==> \n                 (tid in threads && tid == tid_init)\n    \"\n\n    chl_yield_pred inc_threads @\"\n        && (ghosts.inc1 != 0 && ghosts.inc1 !in threads ==> ghosts'.inc1 !in threads')\n        && (ghosts.inc2 != 0 && ghosts.inc2 !in threads ==> ghosts'.inc2 !in threads')\n    \"\n\n    chl_yield_pred main_owns_incs_and_mutex_and_reading @\"\n        && ghosts.mutex == ghosts'.mutex\n        && (tid == tid_init ==> (ghosts.inc1 == ghosts'.inc1 && ghosts.inc2 == ghosts'.inc2 && ghosts.mutex == ghosts'.mutex && ghosts.main_reading == ghosts'.main_reading))\n    \"\n\n    chl_yield_pred YP1\n    //chl_yield_pred {:excludeMethod Acquire, Release, inc} YP2\n    chl_yield_pred {:excludeMethod Acquire, Release, inc} YP2 @\"\n        && (ghosts.mutex in ghosts.acquire_map ==> ghosts'.mutex in ghosts'.acquire_map)\n        && (ghosts.mutex in ghosts.acquire_map && ghosts.acquire_map[ghosts.mutex] == OptionalSome(tid) ==> ghosts'.acquire_map[ghosts'.mutex] == OptionalSome(tid))\n        && (ghosts.mutex in ghosts.acquire_map && ghosts.acquire_map[ghosts.mutex] != OptionalSome(tid) ==> ghosts'.acquire_map[ghosts'.mutex] != OptionalSome(tid))\n    \"\n}\n"
  },
  {
    "path": "experimental/Tests/parser/counter/C.arm",
    "content": "include \"SharedStructs.arm\"\n\nlevel C using SharedStructs {\n    noaddr var x:uint32 := 0;\n    ghost var mutex:uint64 := 0;\n    ghost var acquire_map: map<uint64, OptionalThread> := map[];\n    ghost var inc1:uint64 := 0;\n    ghost var inc2:uint64 := 0;\n    ghost var done: set<uint64> := {};\n    ghost var main_reading: uint8 := 0;\n\n    method {:extern} print_uint32(i:uint32)\n\n    method {:extern} Mutex_Init() returns (m: uint64)\n        requires mutex == 0\n        ensures m in acquire_map && acquire_map[m] == OptionalNone()\n        ensures m != 0\n    {\n        atomic {\n            somehow modifies m\n                ensures (m !in acquire_map) && (m != 0);\n            acquire_map := acquire_map[m := OptionalNone()];\n            //acquire_map[m] := OptionalNone();\n        }\n    }\n\n    // decl acquire lock\n    method {:extern} Acquire(m: uint64)\n        requires m in acquire_map && m != 0\n        ensures m in acquire_map && acquire_map[m] == OptionalSome($me)\n        ensures m == old(m)\n    {\n        assume acquire_map[m].OptionalNone?;\n        assume main_reading == 0;\n        acquire_map[m] := OptionalSome($me);\n    }\n\n    // decl release lock\n    method {:extern} Release(m: uint64)\n        requires m in acquire_map && acquire_map[m] == OptionalSome($me)\n        ensures m in acquire_map && acquire_map[m] != OptionalSome($me)\n        ensures m == old(m)\n    {\n        atomic {\n            assume $sb_empty;\n            assert acquire_map[m] == OptionalSome($me);\n            acquire_map[m] := OptionalNone();\n        }\n    }\n \n    method inc(m: uint64)\n        requires m == mutex\n        requires m != 0 && m in acquire_map\n    {\n        noaddr var y: uint32;\n        assume m == mutex;\n        Acquire(m);\n        \n        assume acquire_map[mutex] == OptionalSome($me);\n        y := x + 1;\n\n        assume acquire_map[mutex] == OptionalSome($me);\n        atomic {\n        x := y;\n        done := done + {$me};\n        }\n\n        assume acquire_map[mutex] == OptionalSome($me);\n        assume m == mutex;\n        Release(m);\n    }\n\n    method main()\n        requires mutex == 0\n        requires inc1 == 0\n        requires inc2 == 0\n        requires main_reading == 0\n    {\n        noaddr var tid1:uint64 := 0;\n        noaddr var tid2:uint64 := 0;\n        noaddr var m:uint64 := 0;\n        \n        m := Mutex_Init();\n        \n        assume mutex == 0;\n        mutex := m;\n\n        atomic {\n            tid1 := create_thread inc(m);\n            inc1 ::= tid1;\n        }\n\n        atomic {\n            tid2 := create_thread inc(m);\n            inc2 := tid2;\n        }\n\n        join tid1;\n        join tid2;\n\n        main_reading := 1;\n        \n        assume main_reading == 1;\n        assume mutex in acquire_map;\n        assume acquire_map[mutex].OptionalNone? || acquire_map[mutex] == OptionalSome($me);\n        print_uint32(x);\n    }\n}\n"
  },
  {
    "path": "experimental/Tests/parser/counter/CD.arm",
    "content": "include \"C.arm\"\ninclude \"D.arm\"\n\nproof CD {\n    refinement C D\n    tso_elim x @\"\n        && ghosts.mutex in ghosts.acquire_map\n        && tid in threads\n        && (var acquired := ghosts.acquire_map[ghosts.mutex];\n             acquired == OptionalSome(tid) ||\n            (acquired == OptionalNone() && tid == tid_init && ghosts.main_reading == 1))\n    \"\n\n    inductive_invariant zero_is_not_a_mutex \"0 !in ghosts.acquire_map\"\n\n    inductive_invariant One_Main @\"\n        forall tid :: (tid in threads && (threads[tid].top.Armada_StackFrame_main? || \n                  threads[tid].top.Armada_StackFrame_print_uint32? ||\n                  threads[tid].top.Armada_StackFrame_Mutex_Init?))\n                 <==> \n                 (tid in threads && tid == tid_init)\n    \"\n\n    inductive_invariant EmptyBuffer @\"\n      forall tid :: tid in threads && tid == tid_init ==> (|threads[tid].storeBuffer| == 0)\n    \" depends_on One_Main\n}\n"
  },
  {
    "path": "experimental/Tests/parser/counter/D.arm",
    "content": "include \"SharedStructs.arm\"\n\nlevel D using SharedStructs {\n    noaddr var x:uint32 := 0;\n    ghost var mutex:uint64 := 0;\n    ghost var acquire_map: map<uint64, OptionalThread> := map[];\n    ghost var inc1:uint64 := 0;\n    ghost var inc2:uint64 := 0;\n    ghost var done: set<uint64> := {};\n    ghost var main_reading: uint8 := 0;\n\n    method {:extern} print_uint32(i:uint32)\n\n    method {:extern} Mutex_Init() returns (m: uint64)\n        requires mutex == 0\n        ensures m in acquire_map && acquire_map[m] == OptionalNone()\n        ensures m != 0\n    {\n        atomic {\n            somehow modifies m\n                ensures (m !in acquire_map) && (m != 0);\n            acquire_map := acquire_map[m := OptionalNone()];\n            //acquire_map[m] := OptionalNone();\n        }\n    }\n\n    // decl acquire lock\n    method {:extern} Acquire(m: uint64)\n        requires m in acquire_map && m != 0\n        ensures m in acquire_map && acquire_map[m] == OptionalSome($me)\n        ensures m == old(m)\n    {\n        assume acquire_map[m].OptionalNone?;\n        acquire_map[m] := OptionalSome($me);\n    }\n\n    // decl release lock\n    method {:extern} Release(m: uint64)\n        requires m in acquire_map && acquire_map[m] == OptionalSome($me)\n        ensures m in acquire_map && acquire_map[m] != OptionalSome($me)\n        ensures m == old(m)\n    {\n        atomic {\n            assume $sb_empty;\n            assert acquire_map[m] == OptionalSome($me);\n            acquire_map[m] := OptionalNone();\n        }\n    }\n \n    method inc(m: uint64)\n        requires m == mutex\n        requires m != 0 && m in acquire_map\n    {\n        noaddr var y: uint32;\n        assume m == mutex;\n        Acquire(m);\n        \n        assume acquire_map[mutex] == OptionalSome($me);\n        y := x + 1;\n\n        assume acquire_map[mutex] == OptionalSome($me);\n        label lb1:\n        atomic {\n        x ::= y;\n        done := done + {$me};\n        }\n\n        assume acquire_map[mutex] == OptionalSome($me);\n        assume m == mutex;\n        Release(m);\n    }\n\n    method main()\n        requires mutex == 0\n        requires inc1 == 0\n        requires inc2 == 0\n    {\n        noaddr var tid1:uint64 := 0;\n        noaddr var tid2:uint64 := 0;\n        noaddr var m:uint64 := 0;\n        \n        m := Mutex_Init();\n\n        assume mutex == 0;\n        mutex := m;\n\n        atomic {\n            tid1 := create_thread inc(m);\n            inc1 ::= tid1;\n        }\n\n        atomic {\n            tid2 := create_thread inc(m);\n            inc2 := tid2;\n        }\n\n        join tid1;\n        join tid2;\n\n        main_reading := 1;\n        \n        assume main_reading == 1;\n        assume mutex in acquire_map;\n        assume acquire_map[mutex].OptionalNone? || acquire_map[mutex] == OptionalSome($me);\n        print_uint32(x);\n    }\n}\n"
  },
  {
    "path": "experimental/Tests/parser/counter/DE.arm",
    "content": "include \"D.arm\"\ninclude \"E.arm\"\n\nproof DE {\n    refinement D E\n    reduction phase1 inc_lb1\n    use_address_invariant\n\n    inductive_invariant EmptyBuffer @\"\n      && (forall tid :: tid in threads ==> (threads[tid].storeBuffer == []))\n    \"\n\n    inductive_invariant zero_is_not_a_mutex \"0 !in ghosts.acquire_map\"\n}\n"
  },
  {
    "path": "experimental/Tests/parser/counter/E.arm",
    "content": "include \"SharedStructs.arm\"\n\nlevel E using SharedStructs {\n    noaddr var x:uint32 := 0;\n    ghost var mutex:uint64 := 0;\n    ghost var acquire_map: map<uint64, OptionalThread> := map[];\n    ghost var inc1:uint64 := 0;\n    ghost var inc2:uint64 := 0;\n    ghost var done: set<uint64> := {};\n    ghost var main_reading: uint8 := 0;\n\n    method {:extern} print_uint32(i:uint32)\n\n    method {:extern} Mutex_Init() returns (m: uint64)\n    {\n        atomic {\n            somehow modifies m\n                ensures (m !in acquire_map) && (m != 0);\n            acquire_map := acquire_map[m := OptionalNone()];\n            //acquire_map[m] := OptionalNone();\n        }\n    }\n\n    // decl acquire lock\n    method {:extern} Acquire(m: uint64)\n    {\n        assume acquire_map[m].OptionalNone?;\n        acquire_map[m] := OptionalSome($me);\n    }\n\n    // decl release lock\n    method {:extern} Release(m: uint64)\n    {\n        atomic {\n            assume $sb_empty;\n            assert acquire_map[m] == OptionalSome($me);\n            acquire_map[m] := OptionalNone();\n        }\n    }\n \n    method inc(m: uint64)\n        requires m == mutex\n        requires m != 0 && m in acquire_map\n    {\n        noaddr var y: uint32;\n        assume m == mutex;\n        Acquire(m);\n        \n        assume acquire_map[mutex] == OptionalSome($me);\n        atomic {\n            y := x + 1;\n            x ::= y;\n            done := done + {$me};\n        }\n\n        assume acquire_map[mutex] == OptionalSome($me);\n        assume m == mutex;\n        Release(m);\n    }\n\n    method main()\n        requires mutex == 0\n        requires inc1 == 0\n        requires inc2 == 0\n    {\n        noaddr var tid1:uint64 := 0;\n        noaddr var tid2:uint64 := 0;\n        noaddr var m:uint64 := 0;\n        \n        m := Mutex_Init();\n\n        mutex := m;\n\n        atomic {\n            tid1 := create_thread inc(m);\n            inc1 ::= tid1;\n        }\n\n        atomic {\n            tid2 := create_thread inc(m);\n            inc2 := tid2;\n        }\n\n        join tid1;\n        join tid2;\n\n        main_reading := 1;\n        \n        print_uint32(x);\n    }\n}\n"
  },
  {
    "path": "experimental/Tests/parser/counter/EF.arm",
    "content": "include \"E.arm\"\ninclude \"F.arm\"\n\nproof EF {\n    refinement E F\n    stack_var_hiding inc y\n}\n"
  },
  {
    "path": "experimental/Tests/parser/counter/F.arm",
    "content": "include \"SharedStructs.arm\"\n\nlevel F using SharedStructs {\n    noaddr var x:uint32 := 0;\n    ghost var mutex:uint64 := 0;\n    ghost var acquire_map: map<uint64, OptionalThread> := map[];\n    ghost var inc1:uint64 := 0;\n    ghost var inc2:uint64 := 0;\n    ghost var done: set<uint64> := {};\n    ghost var main_reading: uint8 := 0;\n\n    method {:extern} print_uint32(i:uint32)\n\n    method {:extern} Mutex_Init() returns (m: uint64)\n    {\n        atomic {\n            somehow modifies m\n                ensures (m !in acquire_map) && (m != 0);\n            acquire_map := acquire_map[m := OptionalNone()];\n            //acquire_map[m] := OptionalNone();\n        }\n    }\n\n    // decl acquire lock\n    method {:extern} Acquire(m: uint64)\n    {\n        assume acquire_map[m].OptionalNone?;\n        acquire_map[m] := OptionalSome($me);\n    }\n\n    // decl release lock\n    method {:extern} Release(m: uint64)\n    {\n        atomic {\n            assume $sb_empty;\n            assert acquire_map[m] == OptionalSome($me);\n            acquire_map[m] := OptionalNone();\n        }\n    }\n \n    method inc(m: uint64)\n        requires $me !in done\n    {\n        assume m == mutex;\n        Acquire(m);\n        \n        assume acquire_map[mutex] == OptionalSome($me);\n        atomic {\n            x ::= x + 1;\n            done := done + {$me};\n        }\n\n        assume acquire_map[mutex] == OptionalSome($me);\n        assume m == mutex;\n        Release(m);\n    }\n\n    method main()\n        requires mutex == 0\n        requires inc1 == 0\n        requires inc2 == 0\n    {\n        noaddr var tid1:uint64 := 0;\n        noaddr var tid2:uint64 := 0;\n        noaddr var m:uint64 := 0;\n        \n        m := Mutex_Init();\n\n        mutex := m;\n\n        atomic {\n            tid1 := create_thread inc(m);\n            inc1 ::= tid1;\n        }\n\n        atomic {\n            tid2 := create_thread inc(m);\n            inc2 := tid2;\n        }\n\n        join tid1;\n        join tid2;\n\n        main_reading := 1;\n        \n        print_uint32(x);\n    }\n\n    yield_predicate YP1\n    {\n        $me !in old(done) ==> $me !in done\n    }\n\n    yield_predicate YP2\n    {\n        (old(inc1) != 0 ==> inc1 == old(inc1)) &&\n        (old(inc2) != 0 ==> inc2 == old(inc2)) &&\n        (forall tid :: tid in old(done) ==> tid in done)\n    }\n\n    invariant Inv1\n    {\n        (x as int == |done|) && \n        (done <= {inc1, inc2}) &&\n        (inc1 != 0 ==> inc1 != inc2) &&\n        (0 !in done)\n    }\n}\n"
  },
  {
    "path": "experimental/Tests/parser/counter/FG.arm",
    "content": "include \"F.arm\"\ninclude \"G.arm\"\n\nproof FG {\n    refinement F G\n    assume_intro\n    \n    include_file \"extra.dfy\"\n    import_module sets_helpers\n    extra lemma_ExpandedStraightlineBehaviorSatisfiesGlobalInvariant_Inv1_inc_Yielded_1_Then_From_inc_1_To_inc_3\n            \"sets_helpers.Cardinality(s5.s.ghosts.done, {s5.s.ghosts.inc1, s5.s.ghosts.inc2});\"\n    extra lemma_ExpandedStraightlineBehaviorSatisfiesLocalInvariant_main_Yielded_9_Then_From_main_9_To_print_uint32_Start @\"\n      assert s19.s.ghosts.done == {s19.s.ghosts.inc1, s19.s.ghosts.inc2} <==>\n             var hs := ConvertTotalState_LPlusH(s19); hs.ghosts.done == {hs.ghosts.inc1, hs.ghosts.inc2};\n    \"\n\n    inductive_invariant no_joinable \"forall jtid :: jtid in s.s.joinable_tids ==> jtid !in threads\"\n\n    inductive_invariant EmptyBuffer @\"\n      && (forall tid :: tid in threads ==> (threads[tid].storeBuffer == []))\n    \"\n\n    inductive_invariant One_Main @\"\n        forall tid :: (tid in threads && (threads[tid].top.Armada_StackFrame_main? || \n                                     threads[tid].top.Armada_StackFrame_print_uint32? ||\n                                     threads[tid].top.Armada_StackFrame_Mutex_Init?))\n                  <==> \n                 (tid in threads && tid == tid_init)\n    \"\n\n    chl_invariant Inv1\n\n    chl_invariant no_other_threads @\"\n      && (forall tid :: tid in threads ==> (tid == ghosts.inc1 || tid == ghosts.inc2 || tid == tid_init))\n    \"\n\n    chl_invariant GlobalInvariant @\"\n      && (ghosts.inc1 != 0 && ghosts.inc1 !in threads ==> ghosts.inc1 in ghosts.done)\n      && (ghosts.inc2 != 0 && ghosts.inc2 !in threads ==> ghosts.inc2 in ghosts.done)\n    \"\n\n    chl_yield_pred {:excludeMethod inc} YP1\n    chl_yield_pred YP2\n\n    chl_yield_pred inc_threads @\"\n        && (ghosts.inc1 != 0 && ghosts.inc1 !in threads ==> s'.s.ghosts.inc1 !in threads')\n        && (ghosts.inc2 != 0 && ghosts.inc2 !in threads ==> s'.s.ghosts.inc2 !in threads')\n    \"\n\n    chl_yield_pred main_owns_incs @\"\n        && (tid == tid_init ==> (ghosts.inc1 == s'.s.ghosts.inc1 && ghosts.inc2 == s'.s.ghosts.inc2))\n        && (tid == tid_init && ghosts.inc1 in s.s.joinable_tids ==> s'.s.ghosts.inc1 in s'.s.joinable_tids)\n        && (tid == tid_init && ghosts.inc1 in threads ==> (s'.s.ghosts.inc1 in s'.s.joinable_tids || s'.s.ghosts.inc1 in threads'))\n    \"\n}\n"
  },
  {
    "path": "experimental/Tests/parser/counter/G.arm",
    "content": "include \"SharedStructs.arm\"\n\nlevel G using SharedStructs {\n    noaddr var x:uint32 := 0;\n    ghost var mutex:uint64 := 0;\n    ghost var acquire_map: map<uint64, OptionalThread> := map[];\n    ghost var inc1:uint64 := 0;\n    ghost var inc2:uint64 := 0;\n    ghost var done: set<uint64> := {};\n    ghost var main_reading: uint8 := 0;\n\n    method {:extern} print_uint32(i:uint32)\n\n    method {:extern} Mutex_Init() returns (m: uint64)\n    {\n        atomic {\n            somehow modifies m\n                ensures (m !in acquire_map) && (m != 0);\n            acquire_map := acquire_map[m := OptionalNone()];\n            //acquire_map[m] := OptionalNone();\n        }\n    }\n\n    // decl acquire lock\n    method {:extern} Acquire(m: uint64)\n    {\n        assume acquire_map[m].OptionalNone?;\n        acquire_map[m] := OptionalSome($me);\n    }\n\n    // decl release lock\n    method {:extern} Release(m: uint64)\n    {\n        atomic {\n            assume $sb_empty;\n            assert acquire_map[m] == OptionalSome($me);\n            acquire_map[m] := OptionalNone();\n        }\n    }\n \n    method inc(m: uint64)\n        requires $me !in done\n    {\n        Acquire(m);\n        \n        atomic {\n            x ::= x + 1;\n            done := done + {$me};\n        }\n\n        Release(m);\n    }\n\n    method main()\n        requires mutex == 0\n        requires inc1 == 0\n        requires inc2 == 0\n    {\n        noaddr var tid1:uint64 := 0;\n        noaddr var tid2:uint64 := 0;\n        noaddr var m:uint64 := 0;\n        \n        m := Mutex_Init();\n\n        mutex := m;\n\n        atomic {\n            tid1 := create_thread inc(m);\n            inc1 ::= tid1;\n        }\n\n        atomic {\n            tid2 := create_thread inc(m);\n            inc2 := tid2;\n        }\n\n        join tid1;\n        join tid2;\n\n        main_reading := 1;\n        \n        assume done == {inc1, inc2};\n        assume x == 2;\n        print_uint32(x);\n    }\n}\n"
  },
  {
    "path": "experimental/Tests/parser/counter/GI.arm",
    "content": "include \"G.arm\"\ninclude \"I.arm\"\n\nproof GI {\n    refinement G I\n    weakening\n}\n"
  },
  {
    "path": "experimental/Tests/parser/counter/I.arm",
    "content": "include \"SharedStructs.arm\"\n\nlevel I using SharedStructs {\n    noaddr var x:uint32 := 0;\n    ghost var mutex:uint64 := 0;\n    ghost var acquire_map: map<uint64, OptionalThread> := map[];\n    ghost var inc1:uint64 := 0;\n    ghost var inc2:uint64 := 0;\n    ghost var done: set<uint64> := {};\n    ghost var main_reading: uint8 := 0;\n\n    method {:extern} print_uint32(i:uint32)\n\n    method {:extern} Mutex_Init() returns (m: uint64)\n    {\n        atomic {\n            somehow modifies m\n                ensures (m !in acquire_map) && (m != 0);\n            acquire_map := acquire_map[m := OptionalNone()];\n            //acquire_map[m] := OptionalNone();\n        }\n    }\n\n    // decl acquire lock\n    method {:extern} Acquire(m: uint64)\n    {\n        assume acquire_map[m].OptionalNone?;\n        acquire_map[m] := OptionalSome($me);\n    }\n\n    // decl release lock\n    method {:extern} Release(m: uint64)\n    {\n        atomic {\n            assume $sb_empty;\n            assert acquire_map[m] == OptionalSome($me);\n            acquire_map[m] := OptionalNone();\n        }\n    }\n \n    method inc(m: uint64)\n    {\n        Acquire(m);\n        \n        atomic {\n            x ::= x + 1;\n            done := done + {$me};\n        }\n\n        Release(m);\n    }\n\n    method main()\n    {\n        noaddr var tid1:uint64 := 0;\n        noaddr var tid2:uint64 := 0;\n        noaddr var m:uint64 := 0;\n        \n        m := Mutex_Init();\n\n        mutex := m;\n\n        atomic {\n            tid1 := create_thread inc(m);\n            inc1 ::= tid1;\n        }\n\n        atomic {\n            tid2 := create_thread inc(m);\n            inc2 := tid2;\n        }\n\n        join tid1;\n        join tid2;\n\n        main_reading := 1;\n        \n        print_uint32(2);\n    }\n}\n"
  },
  {
    "path": "experimental/Tests/parser/counter/IJ.arm",
    "content": "include \"I.arm\"\ninclude \"J.arm\"\n\nproof IJ {\n    refinement I J\n    var_hiding done, inc1, inc2, main_reading\n}\n"
  },
  {
    "path": "experimental/Tests/parser/counter/J.arm",
    "content": "include \"SharedStructs.arm\"\n\nlevel J using SharedStructs {\n    noaddr var x:uint32 := 0;\n    ghost var mutex:uint64 := 0;\n    ghost var acquire_map: map<uint64, OptionalThread> := map[];\n\n    method {:extern} print_uint32(i:uint32)\n\n    method {:extern} Mutex_Init() returns (m: uint64)\n    {\n        atomic {\n            somehow modifies m\n                ensures (m !in acquire_map) && (m != 0);\n            acquire_map := acquire_map[m := OptionalNone()];\n            //acquire_map[m] := OptionalNone();\n        }\n    }\n\n    // decl acquire lock\n    method {:extern} Acquire(m: uint64)\n    {\n        assume acquire_map[m].OptionalNone?;\n        acquire_map[m] := OptionalSome($me);\n    }\n\n    // decl release lock\n    method {:extern} Release(m: uint64)\n    {\n        atomic {\n            assume $sb_empty;\n            assert acquire_map[m] == OptionalSome($me);\n            acquire_map[m] := OptionalNone();\n        }\n    }\n \n    method inc(m: uint64)\n    {\n        Acquire(m);\n        \n        atomic {\n            x ::= x + 1;\n        }\n\n        Release(m);\n    }\n\n    method main()\n    {\n        noaddr var tid1:uint64 := 0;\n        noaddr var tid2:uint64 := 0;\n        noaddr var m:uint64 := 0;\n        \n        m := Mutex_Init();\n\n        mutex := m;\n\n        atomic {\n            tid1 := create_thread inc(m);\n        }\n\n        atomic {\n            tid2 := create_thread inc(m);\n        }\n\n        join tid1;\n        join tid2;\n        \n        print_uint32(2);\n    }\n}\n"
  },
  {
    "path": "experimental/Tests/parser/counter/SharedStructs.arm",
    "content": "include \"../../Armada/ArmadaCommonDefinitions.dfy\"\n\nstructs SharedStructs\n{\n    datatype OptionalThread = OptionalSome(tid:uint64) | OptionalNone()\n}\n"
  },
  {
    "path": "experimental/Tests/parser/counter/Z.arm",
    "content": "include \"SharedStructs.arm\"\n\nlevel Z using SharedStructs {\n    noaddr var x:uint32 := 0;\n\n    method {:extern} print_uint32(i:uint32)\n \n    method inc()\n    {\n    }\n\n    method main()\n    {\n        print_uint32(2);\n    }\n}\n"
  },
  {
    "path": "experimental/Tests/parser/counter/extra.dfy",
    "content": "module sets_helpers {\n\nlemma Cardinality<T>(x:set<T>, y:set<T>)\n    ensures x<y ==> |x|<|y|;\n    ensures x<=y ==> |x|<=|y|;\n{\n    if (x!={}) {\n        var e :| e in x;\n        Cardinality(x-{e}, y-{e});\n    }\n}\n\n}\n"
  },
  {
    "path": "experimental/Tests/parser/fstar/alloc/alloc.arm",
    "content": "level L\n{\n  var p: ptr<int32>;\n  method main ()\n  {\n    p := malloc(int32, 2);\n    free(p);\n    p := calloc(int32, 1);\n    free(p);\n  }\n}"
  },
  {
    "path": "experimental/Tests/parser/fstar/arraytest/arraytest.arm",
    "content": "level L\n{\n  var x:int[5] := [0, 1, 2, 3, 4];\n  var arr:int[3];\n  \n  method main ()\n  {\n    var y:int;\n    x[0] := 1;\n    y := x[0];\n  }\n}"
  },
  {
    "path": "experimental/Tests/parser/fstar/assert/assert.arm",
    "content": "level L\n{\n  ghost var a: int := 0;\n  method main ()\n  {\n    assert a == 0;\n  }\n}"
  },
  {
    "path": "experimental/Tests/parser/fstar/assume/assume.arm",
    "content": "level L\n{\n  ghost var a: int := 0;\n  method main ()\n  {\n    assert a == 0;\n  }\n}"
  },
  {
    "path": "experimental/Tests/parser/fstar/atomic/atomic.arm",
    "content": "level A\n{\n  ghost var a: int := 0;\n  ghost var b: int := 1;\n  ghost var c: int := 2;\n  ghost var d: int := 3;\n  ghost var e: int := 0;\n  ghost var f: int := 1;\n  ghost var g: int := 2;\n  ghost var h: int := 3;\n  method main ()\n  {\n    atomic {      // Start  End\n      a := a;     // true   false\n      atomic {\n        b := b;   // false  false\n      }\n      c := c;     // false  true\n    }\n\n    atomic {\n      atomic {\n        d := d;   // true   false\n      }\n      e := e;     // false  true\n    }\n\n    atomic {\n      f := f;     // true   false\n      atomic {\n        g := g;   // false  true\n      }\n    }\n\n    atomic {\n      atomic {\n        h := h;   // true   true\n      }\n    }\n\n    atomic {\n      if true {   // true   false\n        a := a;   // false   false\n        c := c;   // false  true\n      }\n      else {\n        d := d;   // false  true\n      }\n    }\n\n    atomic {\n      if a == 1 { // true false for true case, true true for false case\n        a := 0;   // false true\n      }\n    }\n\n    atomic {\n      while a == 1 { // true false for true case, true true for false case\n        a := 0;   // false true\n      }\n    }\n\n    atomic {\n      a := 1;     // true false\n      b := 1;     // false true\n      yield;\n      c := 1;     // true false\n      d := 1;     // false true\n    }\n\n    atomic {\n      a := 1;     // true true\n      b := 1;     // false true\n      atomic {\n        atomic {\n          yield;\n        }\n        yield;\n        c := 1;     // true false\n      }\n      d := 1;     // false true\n    }\n\n    atomic {\n      a := 1;     // true true\n      yield;\n    }\n    b := 1;       // true true\n\n    atomic {\n      a := 1;         // true false\n      while a == 1 {  // false true for true case, false false for false case\n        yield;\n        c := 1;       // true false\n      }\n      d := 1;         // false true\n    }\n\n    atomic {\n      a := 1;         // true false\n      while a == 1 {  // false true for true case, false false for false case\n        yield;        // true, false extra jump to while\n      }\n      d := 1;         // false true\n    }\n\n    atomic {\n      a := 1;         // true false\n      while a == 1 {  // false false for true case, false false for false case\n        c := 1;       // false true\n        yield;        // true, false extra jump to while\n      }\n      d := 1;         // false true\n    }\n\n    atomic {\n      c := 1;     // true false\n      if a == 1 { // false true for then case, false false for else case\n        yield;\n        d := 1;   // true false\n      }\n      b := 1;     // false true\n    }\n\n    atomic {\n      c := 1;     // true false\n      if a == 1 { // false true for then case, false true for else case\n        yield;    // true true, extra jump\n      }\n    }\n\n    atomic {\n      c := 1;     // true false\n      if a == 1 { // false false for then case, false false for else case\n        a := 1;   // false true\n      }\n      else {\n        b := 1;   // false true\n        yield;    // true true, extra jump\n      }\n    }\n\n  }\n}"
  },
  {
    "path": "experimental/Tests/parser/fstar/atomicExchange/atomicExchange.arm",
    "content": "level L\n{\n  ghost var x: int := 0;\n  ghost var y: int := 0;\n\n  method main ()\n  {\n    x := atomic_exchange(y, 30);\n  }\n}"
  },
  {
    "path": "experimental/Tests/parser/fstar/atomicMethodCall/atomicMethodCall.arm",
    "content": "level L\n{\n  ghost var a: int := 0;\n  ghost var b: int := 1;\n  ghost var c: int := 2;\n  ghost var d: int := 3;\n  ghost var e: int := 0;\n  method foo(a:int, c:int) returns (f:int)\n  {\n    f := b;\n    return f;\n  }\n\n  method {:atomic_method} fooAtomic(a:int, c:int) returns (f:int)\n  {\n    f := b;\n    yield;\n    return f;\n  }\n  method main ()\n  {\n    e := foo(a, b);\n    e := fooAtomic(c, d);\n    atomic {\n      e := fooAtomic(c, d);\n    }\n    e := 2;\n    atomic {\n      e := fooAtomic(c, d);\n      e := 3;\n    }\n  }\n}\n"
  },
  {
    "path": "experimental/Tests/parser/fstar/atomicRecursive/atomicRecursive.arm",
    "content": "level A\n{\n  ghost var a: int := 0;\n  ghost var b: int := 0;\n\n  method {:atomic_method} foo()\n  {\n    if a == 1 {\n      foo();\n    }\n  }\n\n  method main ()\n  {\n    foo();\n  }\n}\n"
  },
  {
    "path": "experimental/Tests/parser/fstar/atomicWhile/atomicWhile.arm",
    "content": "level A\n{\n    ghost var a: int := 0;\n    ghost var b: int := 1;\n\n    method main () {\n        atomic {\n            while a == 0 {\n                a := 1;\n            }\n            b := 1;\n        }\n    }\n}"
  },
  {
    "path": "experimental/Tests/parser/fstar/binaryOperator/binaryOperator.arm",
    "content": "level A\n{\n  ghost var a: bool;\n  ghost var b: int := 1;\n  ghost var bounded_b: int64 := 1;\n  method main ()\n  {\n    var x:int;\n    var bounded_x:int64;\n    var k:bool;\n\n    var s:seq<int> := [0, 1];\n    var set0:set<int>;\n    var set1:iset<int>;\n    var map0:map<int,int>;\n    var map1:imap<int,int>;\n\n    a := b == b;\n    a := b != b;\n    x := b + b;\n    x := b - b;\n    x := b * b;\n    x := b / b;\n    x := b % b;\n    a := a && a;\n    a := a || a;\n    k := a <==> a;\n    k := a ==> a;\n    k := a <== a;\n    x := x << 1;\n    x := x >> 1;\n    bounded_x := bounded_b ^ bounded_b;\n    bounded_x := bounded_b & bounded_b;\n    bounded_x := bounded_b | bounded_b;\n    bounded_x := ~bounded_b;\n\n    k := x in s;\n    k := x in set0;\n    k := x in set1;\n    k := x in map0;\n    k := x in map1;\n    \n    k := x !in s;\n    k := x !in set0;\n    k := x !in set1;\n    k := x !in map0;\n    k := x !in map1;\n  }\n}\n"
  },
  {
    "path": "experimental/Tests/parser/fstar/boundedInt/boundedInt.arm",
    "content": "level L\n{\n  method main ()\n  {\n    var b:uint16;\n    var c:uint16;\n    var d:uint32;\n    b := b + c;\n    b := b - c;\n    b := b / c;\n    b := b + 1;\n    b := 1 + b;\n    d := b * c;\n  }\n}"
  },
  {
    "path": "experimental/Tests/parser/fstar/break/break.arm",
    "content": "level A\n{\n  ghost var b: int := 1;\n\n  method main ()\n  {\n    b := 0;\n    while (true) {\n      if (b != 0) {\n        break;\n      }\n      else {\n        continue;\n      }\n      b := b + 1;\n    }\n    b := 2;\n  }\n}"
  },
  {
    "path": "experimental/Tests/parser/fstar/code/code.arm",
    "content": "level L\n{\n  ghost var a: int := 0;\n  ghost var b: int := 1;\n  ghost var c: int := 2;\n  ghost var d: int := 3;\n  ghost var e: int;\n  ghost var f: int := 1;\n  ghost var g: int := 1;\n  ghost var h: int := 0;\n\n  method main ()\n  {\n    ghost var x: int := 0;\n\n    e := 2;\n    atomic {\n      a := c;\n      d := b;\n      e := e;\n    }\n    f := f / f;\n  }\n}\nlevel H\n{\n  ghost var a: int := 0;\n  ghost var b: int := 1;\n  ghost var c: int := 2;\n  ghost var d: int := 3;\n  ghost var e: int;\n  ghost var f: int := 1;\n  ghost var g: int := 1;\n  ghost var h: int := 0;\n\n  method main ()\n  {\n    ghost var x: int := 0;\n    \n    e := 1 + 1;  // This is the only statement differing from level L\n    atomic {\n      a := c;\n      d := b;\n      e := e;\n    }\n    f := f / f;\n  }\n}\n\n/*\nproof LtoH {\n  refinement L H weakening\n}\n*/\n\n"
  },
  {
    "path": "experimental/Tests/parser/fstar/compareAndSwap/compareAndSwap.arm",
    "content": "level A\n{\n  ghost var a: bool := false;\n  ghost var b: int := 1;\n  ghost var c: int := 2;\n  ghost var d: int := 4;\n\n  method main ()\n  {\n    compare_and_swap(b, c, d);\n    a := compare_and_swap(b, c, d);\n    a ::= compare_and_swap(b, c, d);\n  }\n}"
  },
  {
    "path": "experimental/Tests/parser/fstar/conversionExpr/conversionExpr.arm",
    "content": "level L\n{\n  method main ()\n  {\n    var a:uint8 := 2;\n    var b:uint16;\n    b := a as uint16;\n  }\n}"
  },
  {
    "path": "experimental/Tests/parser/fstar/createThread/createThread.arm",
    "content": "level L\n{\n  ghost var a: int := 0;\n  ghost var b: int := 1;\n  ghost var c: int := 2;\n  ghost var d: int := 3;\n  ghost var e: int;\n  ghost var f: int := 1;\n  ghost var g: int := 1;\n  ghost var h: int := 0;\n  method foo(a:int, c:int)\n  {\n    a := c;\n    d := e;\n  }\n  method main ()\n  {\n    var t1:tid_t;\n    t1 := create_thread foo(a, b);\n    join t1;\n    create_thread foo(a, c);\n  }\n}\nlevel H\n{\n  ghost var a: int := 0;\n  ghost var b: int := 1;\n  ghost var c: int := 2;\n  ghost var d: int := 3;\n  ghost var e: int;\n  ghost var f: int := 1;\n  ghost var g: int := 1;\n  ghost var h: int := 0;\n  method foo(a:int, c:int)\n  {\n    a := c;\n    d := e;\n  }\n  method main ()\n  {\n    var t1:tid_t;\n    t1 := create_thread foo(a, b);\n    join t1;\n    create_thread foo(a, c);\n  }\n}"
  },
  {
    "path": "experimental/Tests/parser/fstar/datatype/datatype.arm",
    "content": "datatype step = Acquire(x:int, y:bool) | Release(x:int) | NoStep\n\n\nlevel L\n{\n  method main ()\n  {\n    var s:step;\n    s := Acquire(1, true);\n    s.x := 1;\n    s.y := false;\n  }\n}\n"
  },
  {
    "path": "experimental/Tests/parser/fstar/fence/fence.arm",
    "content": "level A\n{\n  ghost var a: bool;\n  ghost var b: int := 1;\n\n  method main ()\n  {\n    fence;\n  }\n}"
  },
  {
    "path": "experimental/Tests/parser/fstar/generatedAssign/generatedAssign.arm",
    "content": "level A\n{\n  method main ()\n  {\n    var b:int;\n    var a:int := 1 + 1;\n    var c:int;\n    a := 1;\n  }\n}"
  },
  {
    "path": "experimental/Tests/parser/fstar/goto/goto.arm",
    "content": "level A\n{\n  ghost var b: int := 1;\n\n  method main ()\n  {\n    b := 0;\n    goto lbl1;\n    b := 2;\nlabel lbl1:\n    assert b == 0;\n  }\n}"
  },
  {
    "path": "experimental/Tests/parser/fstar/ifExpr/ifExpr.arm",
    "content": "level A\n{\n  method main ()\n  {\n    var x:int;\n    x := if true then 1 else 0;\n  }\n}"
  },
  {
    "path": "experimental/Tests/parser/fstar/ifStmt/ifStmt.arm",
    "content": "level A\n{\n  ghost var a: bool;\n  ghost var b: int := 1;\n  ghost var c: int := 2;\n  ghost var d: int := 4;\n  ghost var e: int := 5;\n\n  method main ()\n  {\n    var cond: bool := b == b;\n    if b == b {\n        b := c;\n    }\n    else {\n        b := d;\n    }\n    if b == b {\n        b := e;\n    }\n  }\n}"
  },
  {
    "path": "experimental/Tests/parser/fstar/ifundefined/ifundefined.arm",
    "content": "level A\n{\n  method main ()\n  {\n    var x:int := 0;\n    var y:int := if_undefined(1 - x, 1 + x);\n  }\n}"
  },
  {
    "path": "experimental/Tests/parser/fstar/invariantDecl_MaintainedIfStmtSatisfies/invariantDecl.arm",
    "content": "level L\n{\n  ghost var a: int := 0;\n  ghost var b: int := 1;\n  ghost var c: int := 2;\n  ghost var d: int := 3;\n  ghost var e: int;\n  ghost var f: int := 1;\n  ghost var g: int := 1;\n  ghost var h: int := 0;\n  method foo(a:int, c:int)\n  {\n    a := c;\n    d := e;\n  }\n  method main ()\n  {\n    var t1:tid_t;\n    t1 := create_thread foo(a, b);\n    join t1;\n    create_thread foo(a, c);\n  }\n  invariant a_doesnt_change { a == 0 } by maintained_if_statement_satisfies\n}"
  },
  {
    "path": "experimental/Tests/parser/fstar/invariantDecl_MaintainedIfVarsUnchanged/invariantDecl.arm",
    "content": "level L\n{\n  ghost var a: int := 0;\n  ghost var b: int := 1;\n  ghost var c: int := 2;\n  ghost var d: int := 3;\n  ghost var e: int;\n  ghost var f: int := 1;\n  ghost var g: int := 1;\n  ghost var h: int := 0;\n  method foo(a:int, c:int)\n  {\n    a := c;\n    d := e;\n  }\n  method main ()\n  {\n    var t1:tid_t;\n    t1 := create_thread foo(a, b);\n    join t1;\n    create_thread foo(a, c);\n  }\n  invariant a_doesnt_change { a == 0 } by maintained_if_vars_unchanged f, g\n}"
  },
  {
    "path": "experimental/Tests/parser/fstar/literalExpr/literalExpr.arm",
    "content": "level A\n{\n  ghost var a: bool := false;\n  ghost var b: int := 1;\n  ghost var c: char := 'a';\n  ghost var d: string := \"abc\";\n  method main ()\n  {\n    a := true;\n    b := 0;\n    c := 'b';\n    d := \"str\";\n  }\n}\n"
  },
  {
    "path": "experimental/Tests/parser/fstar/mapComprehension/mapComprehension.arm",
    "content": "level A\n{\n  method main ()\n  {\n    var s:seq<int> := [0, 1];\n    var y:int := 3;\n    var z:int := 4;\n    var m0:imap<int,int> := imap x:int | x in s :: x + y := x + z;\n    var m1:map<int,int> := map x:int | x in s :: x := x + 1;\n  }\n}\n"
  },
  {
    "path": "experimental/Tests/parser/fstar/maptest/maptest.arm",
    "content": "level L\n{\n  method main ()\n  {\n    var x:int := 5;\n    var m:imap<string, int> := imap [\"a\" := 1, \"b\" := x];\n    var m1:map<string, int> := map [\"a\" := 1, \"b\" := x];\n    var y:int := m[\"b\"];\n    var y1:int := m1[\"b\"];\n    m := m[\"b\" := 0];\n    m1 := m1[\"b\" := 0];\n  }\n}"
  },
  {
    "path": "experimental/Tests/parser/fstar/matchCase/matchCase.arm",
    "content": "datatype step = Acquire(x:int, y:int) | Release(x:int) | NoStep\nlevel L\n{\n  method foo(s:step) returns (a:int)\n  {\n    a := match s\n    {\n      case Acquire(x, y) => y\n      case Release(x)    => x\n      case NoStep        => 0\n    };\n    return a;\n  }\n  method main ()\n  {\n    var x: int := foo(Acquire(1, 1));\n  }\n}\n"
  },
  {
    "path": "experimental/Tests/parser/fstar/methodCall/methodCall.arm",
    "content": "level L\n{\n  ghost var a: int := 0;\n  ghost var b: int := 1;\n  ghost var c: int := 2;\n  ghost var d: int := 3;\n  ghost var e: int;\n  ghost var f: int := 1;\n  ghost var g: int := 1;\n  ghost var h: int := 0;\n  method foo(a:int, c:int) returns (f:int)\n  {\n    f := b;\n    atomic {\n      a := c;\n      return g;\n      d := e;\n    }\n    return f;\n  }\n  method main ()\n  {\n    e := foo(a, b);\n    e := foo(c, d);\n  }\n}\nlevel H\n{\n  ghost var a: int := 0;\n  ghost var b: int := 1;\n  ghost var c: int := 2;\n  ghost var d: int := 3;\n  ghost var e: int;\n  ghost var f: int := 1;\n  ghost var g: int := 1;\n  ghost var h: int := 0;\n  method foo(a:int, c:int) returns (f:int)\n  {\n    f := b;\n    atomic {\n      a := c;\n      return g;\n      d := e;\n    }\n    return f;\n  }\n  method main ()\n  {\n    e := foo(a, b);\n    e ::= foo(c, d);\n  }\n}"
  },
  {
    "path": "experimental/Tests/parser/fstar/quantifierexpr/quantifierexpr.arm",
    "content": "level A\n{\n  method main ()\n  {\n    var s:seq<int> := [0, 1];\n    var set0:set<int>;\n    var set1:iset<int>;\n    var map0:map<int,int>;\n    var map1:imap<int,int>;\n    var y:int := 1;\n    var flag:bool;\n    flag := forall x:int, z:int | x == z :: x == y;\n    flag := exists x:int | x in s :: x == 1;\n    flag := exists x:int | x in set0 :: x == 1;\n    flag := exists x:int | x in set1 :: x == 1;\n    flag := exists x:int | x in map0 :: x == 1;\n    flag := exists x:int | x in map1 :: x == 1;\n  }\n}"
  },
  {
    "path": "experimental/Tests/parser/fstar/recursiveMatch/recursiveMatch.arm",
    "content": "datatype abc = AB(a:int, b:int) | C(c:int)\ndatatype step = Acquire(x:int, y:abc) | Release(x:int) | NoStep\n\nlevel L\n{\n  method foo(s:step) returns (a:int)\n  {\n    a := match s\n    {\n      case Acquire(x, AB(a, b)) => a\n      case Acquire(x, C(c))     => x\n      case Release(x)           => x\n      case NoStep               => 1\n    };\n    return a;\n  }\n  method main ()\n  {\n    // recursive match is not fully implemented\n    var x: int := 1;\n    var y: int := x + x;\n  }\n}\n"
  },
  {
    "path": "experimental/Tests/parser/fstar/relation/relation.arm",
    "content": "level A\n{\n  var arr:int[3];\n\n  method main ()\n  {\n    var b:bool;\n    var x:int := 1;\n    var y:int := 4;\n    var c:uint16 := 1;\n    var d:uint16 := 2;\n    \n    b := x < y;\n    b := x <= y;\n    b := x > y;\n    b := x >= y;\n\n    b := c < d;\n    b := c <= d;\n    b := c > d;\n    b := c >= d;\n    \n  }\n}\n"
  },
  {
    "path": "experimental/Tests/parser/fstar/seqtest/seqtest.arm",
    "content": "level L\n{\n  method main ()\n  {\n    var x:int := 1;\n    var s0:seq<int> := [];\n    var s1:seq<int> := [0, x];\n    var s2:seq<int> := s1[1..2];\n    x := s1[0];\n    s1 := s1[0 := 1];\n  }\n}"
  },
  {
    "path": "experimental/Tests/parser/fstar/setComprehension/setComprehension.arm",
    "content": "level A\n{\n  method main ()\n  {\n    var s:seq<int> := [0, 1];\n    var y:int := 3;\n    var z:int := 4;\n    var s0:iset<int> := iset x:int | x in s :: 2 + x + y + z;\n    var s1:set<int> := set x:int | x in s :: x * 2;\n  }\n}\n"
  },
  {
    "path": "experimental/Tests/parser/fstar/settest/settest.arm",
    "content": "level L\n{\n  method main ()\n  {\n    var s0:set<int>;\n    var s1:set<int> := {};\n    var s2:set<int> := {1};\n\n    var s3:iset<int>;\n    var s4:iset<int> := iset {};\n    var s5:iset<int> := iset {1};\n    var s6:iset<int> := iset {1, 2};\n\n    var b:bool := false;\n\n    b := s0 !! s1;\n    b := s3 !! s4;\n  }\n}"
  },
  {
    "path": "experimental/Tests/parser/fstar/somehow/somehow.arm",
    "content": "level A\n{\n  ghost var a: int := 0;\n  method main ()\n  {\n    var b: int := 0;\n    somehow {:bwb}\n      modifies a, b \n      undefined_unless a == 0\n      undefined_unless b == 0\n      ensures a == 1\n      ensures b == 2;\n  }\n\n}"
  },
  {
    "path": "experimental/Tests/parser/fstar/somehowLock/somehow.arm",
    "content": "level A\n{\n  ghost var a: int := 0;\n  ghost var b: int := 0;\n  var lock: int := 0;\n  var tid: int := 0;\n\n  method {:extern} lock() returns (a:int)\n    reads a\n    awaits lock == 0\n    modifies lock\n    modifies tid\n    logs a\n    logs b\n    ensures lock == tid\n\n  method {:extern} unlock()\n    reads a\n    reads b\n    requires lock == tid\n    modifies lock\n    ensures lock == 0\n\n  method main ()\n  {\n    b := lock();\n    a := a + 1;\n    unlock();\n  }\n\n}"
  },
  {
    "path": "experimental/Tests/parser/fstar/struct/struct.arm",
    "content": "struct st {\n    var a:nat;\n    var b:bool;\n}\n\nlevel A {\n    method main()\n    {\n        var x:st;\n        x.a := 10;\n        x.b := true;\n    }\n}\n"
  },
  {
    "path": "experimental/Tests/parser/fstar/subroutine/subroutine.arm",
    "content": "level A\n{\n  ghost var a: int := 1;\n  ghost var c: int := 3;\n  ghost var e: int := 5;\n\n  method subroutine ()\n  {\n    a := 0;\n  }\n\n  method main ()\n  {\n    a := 10;\n    atomic {\n      c := 20;\n      e := 30;\n    }\n    subroutine();\n  }\n}\n\nlevel B\n{\n  ghost var a: int := 1;\n  ghost var c: int := 3;\n  ghost var e: int := 5;\n\n  method subroutine ()\n  {\n    a := 0;\n  }\n\n  method main ()\n  {\n    a := 10;\n    atomic {\n      c := 20;\n      e := 30;\n    }\n    subroutine();\n  }\n}\n\n/*\nproof AtoB {\n  refinement A B weakening\n}\n */\n"
  },
  {
    "path": "experimental/Tests/parser/fstar/unaryOperator/unaryOperator.arm",
    "content": "level A\n{\n  ghost var a: int;\n  ghost var b: bool;\n  ghost var pi: ptr<int>;\n  ghost var pb: ptr<bool>;\n  method main ()\n  {\n\n    var s:seq<int> := [0, 1];\n    var set0:set<int>;\n    var map0:map<int,int>;\n\n    if *\n    {\n      a := a;\n    }\n\n    pi := *;\n    *pi := -a;\n    a := -a;\n    b := !b;\n    a := |s|;\n    a := |set0|;\n    a := |map0|;\n  }\n}\n"
  },
  {
    "path": "experimental/Tests/parser/fstar/while/while.arm",
    "content": "level A\n{\n  ghost var a: bool;\n  ghost var b: int := 1;\n  ghost var c: int := 2;\n  ghost var d: int := 4;\n  ghost var e: int := 5;\n\n  method main ()\n  {\n    ghost var cond:bool := b == 1;\n    while cond {\n        b := b + 1;\n    }\n    c := b;\n  }\n}"
  },
  {
    "path": "experimental/Tests/parser/fstar/wildcard/wildcard.arm",
    "content": "level A\n{\n  method main ()\n  {\n    var a:int;\n\n    if *\n    {\n        a := a;\n    }\n\n    while *\n    {\n        a := a;\n    }\n  }\n}\n"
  },
  {
    "path": "experimental/Tests/parser/includeTest/A.arm",
    "content": "level A {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n\n        x := 5;\n        y := 10;\n    }\n}\n        \n"
  },
  {
    "path": "experimental/Tests/parser/includeTest/A.arm.expect",
    "content": "Tests/parser/includeTest/A.arm\nlevel A {\n  method main () {\n    var x:uint64_t := 0;\n    var y:uint64_t := 0;\n    var z:uint64_t := 0;\n    x := 5;\n    y := 10;\n  }\n}\n\n"
  },
  {
    "path": "experimental/Tests/parser/includeTest/B.arm",
    "content": "include \"A.arm\"\nlevel B {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n\n        x := 5;\n        label l1:\n        y := 10;\n        label l2:\n        z := 1;\n    }\n}\n        \n"
  },
  {
    "path": "experimental/Tests/parser/includeTest/B.arm.expect",
    "content": "Tests/parser/includeTest/B.arm\nlevel B {\n  method main () {\n    var x:uint64_t := 0;\n    var y:uint64_t := 0;\n    var z:uint64_t := 0;\n    x := 5;\n    label l1:\n    y := 10;\n    label l2:\n    z := 1;\n  }\n}\nlevel A {\n  method main () {\n    var x:uint64_t := 0;\n    var y:uint64_t := 0;\n    var z:uint64_t := 0;\n    x := 5;\n    y := 10;\n  }\n}\n"
  },
  {
    "path": "experimental/Tests/parser/includeTest/C.arm",
    "content": "include \"A.arm\"\ninclude \"B.arm\"\nlevel C {\n    method main()\n    {\n        var x:uint64 := 0;\n        var y:uint64 := 0;\n        var z:uint64 := 0;\n\n        x := 5;\n        label l3:\n        \n        atomic\n        {\n            y := 10;\n            z := 1;\n        }\n    }\n}\n\n"
  },
  {
    "path": "experimental/Tests/parser/includeTest/C.arm.expect",
    "content": "Tests/parser/includeTest/C.arm\nlevel C {\n  method main () {\n    var x:uint64_t := 0;\n    var y:uint64_t := 0;\n    var z:uint64_t := 0;\n    x := 5;\n    label l3:\n    atomic\n    {\n      y := 10;\n      z := 1;\n    }\n  }\n}\nlevel A {\n  method main () {\n    var x:uint64_t := 0;\n    var y:uint64_t := 0;\n    var z:uint64_t := 0;\n    x := 5;\n    y := 10;\n  }\n}\nlevel B {\n  method main () {\n    var x:uint64_t := 0;\n    var y:uint64_t := 0;\n    var z:uint64_t := 0;\n    x := 5;\n    label l1:\n    y := 10;\n    label l2:\n    z := 1;\n  }\n}\n\n"
  },
  {
    "path": "experimental/Tests/parser/ogCounterExample.arm",
    "content": "struct C1 {\n  var a:int32;\n  var b:int64 := 10;\n}\n\nlevel impl_level {\n  var x := 0;\n\n  var lock := 0;\n  method acquire () \n    awaits lock == 0\n    modifies lock\n    ensures lock == 1\n\n  method release ()\n    requires lock == 1\n    modifies lock\n    ensures lock == 0\n\n  method {:opague} foo(a:int32) {\n    acquire();\n    x := x + a;\n    release();\n  }\n\n  method main() {\n    var t1 := create_thread foo(1);\n    var t2 := create_thread foo(1);\n    t1.join();\n    t2.join();\n    print (x);\n  }\n}\n\nlevel L2 {\n  var x := 0;\n\n  // var lock := 0;\n  // method acquire () \n  //   awaits lock == 0\n  //   modifies lock\n  //   ensures lock == 1\n\n  // method release ()\n  //   requires lock == 1\n  //   modifies lock\n  //   ensures lock == 0\n\n  method {:opague} foo(a:int32) {\n    // acquire();\n    atomic {\n      x := x + a;\n    }\n    // release();\n  }\n\n  method main() {\n    var t1 := create_thread foo(1);\n    var t2 := create_thread foo(1);\n    t1.join();\n    t2.join();\n    print (x);\n  }\n}\n\n\nlevel L3 {\n  var x := 0;\n\n  method {:opague} foo(a:int32)\n  requires a == 1\n  {\n    atomic {\n      x := x + a;\n    }\n  }\n\n  method main() {\n    var t1 := create_thread foo(1);\n    var t2 := create_thread foo(1);\n    t1.join();\n    t2.join();\n    assume x == 2; // This is added\n    print (x);\n  }\n}\n\nproof L1_L2 \n{\n  refinement impl_level L2\n  var_hiding lock\n}\n\nproof L2_L3 {\n  refinement L2 L3\n  assume_intro\n}"
  },
  {
    "path": "experimental/Tests/parser/test.arm",
    "content": "struct C1 {\n  var a:int8;\n  var b:int64 := 10;\n}\n\nstruct C2 {\n  var a:C1;\n  var b:int64 := 10;\n}\n\nlevel L1 {\n  method {:opague} foo(a:int32, b:int8, c:int32) {\n    a := a + 1;\n    c := a + b;\n  }\n}\n\nlevel L2 {\n  method {:opague} foo(a:int32, b, c:int64) {\n    atomic\n    {\n      a := a + 1;\n      c := a + b;\n    }\n  }\n}\n\nproof L1_L2 {\n  refinement L1 L2\n  weakening\n}"
  },
  {
    "path": "experimental/Tests/proof/globalVarsUnmodifiable/globalVarsUnmodifiable.arm",
    "content": "level A\n{\n  ghost var a: int := 1;\n  var c: uint64 := 3;\n  ghost var e: int := 5;\n\n  method subroutine ()\n  {\n    a := 0;\n  }\n\n  method main ()\n  {\n    a := 10;\n    atomic {\n      c := 20;\n      e := 30;\n    }\n    subroutine();\n  }\n}\n"
  },
  {
    "path": "experimental/Tests/proof/varHiding/varHiding.arm",
    "content": "level B\n{\n  ghost var a: int := 1;\n  ghost var b: int := 2;\n  ghost var c: int := 3;\n  ghost var d: int := 4;\n  ghost var e: int := 5;\n\n  method subroutine ()\n  {\n    a := 0;\n    b := a;\n    d := 2;\n  }\n\n  method main ()\n  {\n    atomic {\n      d := 5;\n      a := 10;\n      b := 15;\n    }\n    atomic {\n      c := 20;\n      b := 25;\n      e := 30;\n    }\n    subroutine();\n    atomic {\n      b := 35;\n      d := 40;\n    }\n  }\n}\n\nlevel A\n{\n  ghost var a: int := 1;\n  ghost var c: int := 3;\n  ghost var e: int := 5;\n\n  method subroutine ()\n  {\n    a := 0;\n  }\n\n  method main ()\n  {\n    a := 10;\n    atomic {\n      c := 20;\n      e := 30;\n    }\n    subroutine();\n  }\n}\n\n\nproof BtoA { \n  refinement B A var_hiding b, d \n}\n\n"
  },
  {
    "path": "experimental/Tests/proof/varIntro/varIntro.arm",
    "content": "level A\n{\n  ghost var a: int := 1;\n  ghost var c: int := 3;\n  ghost var e: int := 5;\n\n  method subroutine ()\n  {\n    a := 0;\n  }\n\n  method main ()\n  {\n    a := 10;\n    atomic {\n      c := 20;\n      e := 30;\n    }\n    subroutine();\n  }\n}\n\nlevel B\n{\n  ghost var a: int := 1;\n  ghost var b: int := 2;\n  ghost var c: int := 3;\n  ghost var d: int := 4;\n  ghost var e: int := 5;\n\n  method subroutine ()\n  {\n    a := 0;\n    b := a;\n    d := 2;\n  }\n\n  method main ()\n  {\n    atomic {\n      d := 5;\n      a := 10;\n      b := 15;\n    }\n    atomic {\n      c := 20;\n      b := 25;\n      e := 30;\n    }\n    subroutine();\n    atomic {\n      b := 35;\n      d := 40;\n    }\n  }\n}\n\n\nproof AtoB { \n    refinement A B var_intro b, d \n}\n"
  },
  {
    "path": "experimental/Tests/proof/varIntroWithAtomic/varIntro.arm",
    "content": "level A\n{\n  noaddr var x:int32;\n  noaddr var y:int32;\n\n  method foo() returns (bar: int32)\n  {\n    return 41;\n    return 42;\n  }\n\n  method main()\n  {\n    x := foo();\n    y := 3;\n    y := 41;\n  }\n}\n\nlevel B\n{\n  noaddr var x:int32;\n  noaddr var y:int32;\n  noaddr var z:int32 := 0;\n  ghost noaddr var w:int32 := 42;\n\n  method foo() returns (bar: int32)\n  {\n    return 41;\n    atomic {\n      z := 7;\n      return 42;\n    }\n  }\n\n  method main()\n  {\n    x := foo();\n    atomic {\n      z ::= 42;\n      y := 3;\n      z := 5;\n    }\n    z := 6;\n    w ::= 19;\n    y := 41;\n  }\n}\n\n\nproof AB {\n    refinement A B\n    var_intro z, w\n}\n\n"
  },
  {
    "path": "experimental/docker/Dockerfile",
    "content": "# This Dockerfile should be run from the root FStar directory\n\n# Build the package\nARG ocaml_version=4.12\nARG CI_THREADS=24\n\nFROM ocaml/opam:ubuntu-20.04-ocaml-$ocaml_version AS fstarbuild\n\n# FIXME: the `opam depext` command should be unnecessary with opam 2.1\nRUN opam depext conf-gmp conf-m4\n\nADD --chown=opam:opam ./fstar.opam fstar.opam\n\n# Install opam dependencies only, but not z3\nRUN grep -v z3 < fstar.opam > fstar-no-z3.opam && \\\n    rm fstar.opam && \\\n    opam install --deps-only ./fstar-no-z3.opam && \\\n    rm fstar-no-z3.opam\n\n# Install .NET\nRUN sudo apt-get update && sudo apt-get install --yes --no-install-recommends \\\n  libicu66\n\n# (for .NET, cf. https://aka.ms/dotnet-missing-libicu )\n# CI dependencies: .NET Core\n# Repository install may incur some (transient?) failures (see for instance https://github.com/dotnet/sdk/issues/27082 )\n# So, we use manual install instead, from https://docs.microsoft.com/en-us/dotnet/core/install/linux-scripted-manual#manual-install\nENV DOTNET_ROOT /home/opam/dotnet\nRUN sudo apt-get install --yes --no-install-recommends \\\n    wget scons \\\n    && \\\n    wget https://download.visualstudio.microsoft.com/download/pr/cd0d0a4d-2a6a-4d0d-b42e-dfd3b880e222/008a93f83aba6d1acf75ded3d2cfba24/dotnet-sdk-6.0.400-linux-x64.tar.gz && \\\n    mkdir -p $DOTNET_ROOT && \\\n    tar xf dotnet-sdk-6.0.400-linux-x64.tar.gz -C $DOTNET_ROOT\n\nENV PATH=${PATH}:$DOTNET_ROOT:$DOTNET_ROOT/tools\n\n# Download and extract z3, but do not add it in the PATH\n# We download a z3 that does not depend on libgomp\nADD --chown=opam:opam https://github.com/tahina-pro/z3/releases/download/z3-4.8.5-linux-clang/z3-4.8.5-linux-clang-x86_64.tar.gz z3.tar.gz\nRUN tar xf z3.tar.gz\n\nRUN git clone https://github.com/FStarLang/FStar.git -b v2024.01.13\nWORKDIR FStar/ \nRUN eval $(opam env) && env OTHERFLAGS='--admit_smt_queries true' PATH=$HOME/z3:$PATH make -j $CI_THREADS \nENV PATH=${PATH}:/home/opam/FStar/bin:/home/opam/z3\n\nRUN sudo wget https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb\nRUN sudo dpkg -i packages-microsoft-prod.deb\nRUN sudo apt-get update\nRUN sudo apt-get install -y dotnet-sdk-5.0 aspnetcore-runtime-5.0 dotnet-runtime-5.0\nRUN sudo apt-get install -y dotnet-sdk-6.0 aspnetcore-runtime-6.0 dotnet-runtime-6.0\n\nWORKDIR $HOME\nRUN wget https://github.com/dafny-lang/dafny/releases/download/v3.0.0/dafny-3.0.0-x64-debian-8.11.zip\nRUN unzip dafny-3.0.0-x64-debian-8.11.zip\nRUN git clone https://github.com/microsoft/Armada.git\nWORKDIR $HOME/Armada\nRUN dotnet build Source/Armada.sln\n\nADD --chown=opam . $HOME/starmada\nWORKDIR $HOME/starmada\nRUN dotnet build Source/Armada.sln\n# RUN scons --generate-fstar -j8\n# RUN scons --run-fstar -j8\n\nENV PATH=${PATH}:/home/opam/starmada/Binary\n"
  },
  {
    "path": "experimental/fstar.opam",
    "content": "opam-version: \"2.0\"\nversion: \"2024.01.13~dev\"\nmaintainer: \"taramana@microsoft.com\"\nauthors: \"Nik Swamy <nswamy@microsoft.com>,Jonathan Protzenko <protz@microsoft.com>,Tahina Ramananandro <taramana@microsoft.com>\"\nhomepage: \"http://fstar-lang.org\"\nlicense: \"Apache-2.0\"\ndepends: [\n  \"ocaml\" {>= \"4.10.0\"}\n  \"batteries\"\n  \"zarith\"\n  \"stdint\"\n  \"yojson\"\n  \"dune\" {build & >= \"3.2.0\"}\n  \"memtrace\"\n  \"menhirLib\"\n  \"menhir\" {build & >= \"2.1\"}\n  \"pprint\"\n  \"sedlex\"\n  \"ppxlib\" {>= \"0.27.0\"}\n  \"process\"\n  \"ppx_deriving\" {build}\n  \"ppx_deriving_yojson\" {build}\n  \"z3\" {= \"4.8.5-1\"}\n]\ndepexts: [\"coreutils\"] {os = \"macos\" & os-distribution = \"homebrew\"}\nbuild: [\n  [make \"PREFIX=%{prefix}%\" \"-j\" jobs]\n]\ninstall: [\n  [make \"PREFIX=%{prefix}%\" \"install\"]\n]\ndev-repo: \"git://github.com/FStarLang/FStar\"\nbug-reports: \"https://github.com/FStarLang/FStar/issues\"\nsynopsis: \"Verification system for effectful programs\"\nurl {\n  src: \"https://github.com/FStarLang/FStar/archive/V0.9.7.0-alpha1.zip\"\n  checksum: \"md5=78414a6a5a0ca0c7770a43a36c5f31f7\"\n}\n"
  },
  {
    "path": "experimental/grammar.txt",
    "content": "T = \"uint8\" | ... | \"int64\"\n    | \"ptr<\" T \">\"\n    | T \"[\"  N \"]\"           !! Left recursion\n    | \"struct\" \"{\" { \"var\" ident \":\" T\";\" } \"}\"\n;\n\ne = lit | ident\n    | uop e\n    | e bop e                !! Left recursion\n    | \"&\" e\n    | \"*\" e\n    | e \".\" ident\n    | \"*\"\n    | \"old(\" e \")\"\n;\n\n----------------------------------------------------------------------\nScratch notes\n\ne = lit | ident | e bop e;\n\ne'  =  lit er | ident er\ner  =  bop e  | ϵ\n\n\n\nQ: (1 + 2) * (3 + 4) parsed to an expression with the old Armada.atg?\nA:\nUsing https://github.com/microsoft/Armada/issues/33 to figure out.\nMulOp only referenced in Factor.\nSo, need a factor with (1 + 2) and (3 + 4) as descendants.\nParensExpression shows up in ConstAtomExpression, which shows up in AsExpression,\nwhich shows up in BitVectorFactor, which shows up in Factor.\nWhew! That's a lot of non-terminals.\n\n----------------------------------------------------------------------\nMinimal grammar to experiment with a recursive descent + precedence climbing parser:\n\nstmt = lvalue_list \":=\" rhs_list.\nlhs_list = lvalue {\",\" lhs}\nlhs = ident\nrhs_list = expr {\",\" expr}\n\nexpr = | (expr)\n       | &expr\n       | *expr\n       | expr0\n\nexpr0 =  expr + expr\n       | expr * expr\n       | expr ^ expr\n       | expr && expr\n       | expr || expr\n       | expr[expr]\n       | expr as type\n       | ident\n       | lit\n\nexpr as type is an expression"
  },
  {
    "path": "experimental/lib/.gitignore",
    "content": ".depend\n*.fst.checked\n*.fsti.checked\ntest*.fst\ndep.graph\n"
  },
  {
    "path": "experimental/lib/Armada.Action.fst",
    "content": "module Armada.Action\n\nopen Armada.Base\nopen Armada.Computation\nopen Armada.State\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Threads\nopen Armada.Type\nopen Spec.Logic\nopen Spec.Map\nopen Spec.Ubool\n\nnoeq type program_statement_t = {\n  start_pc: option pc_t;         // if Some `x`, then actor's PC must be at `x` when action begins\n  end_pc: option pc_t;           // if end_pc is Some `y`, then actor's PC is changed to `y` by the action;\n                                 // if end_pc is None and start_pc is None, then actor's PC is unchanged by the action;\n                                 // if end_pc is None and start_pc is Some `x`, then actor is terminated by the action\n  starts_atomic_block: bool;     // whether this action starts with the actor yielded\n  ends_atomic_block: bool;       // whether this action causes the actor to yield when ok=true\n  statement: Armada.Statement.t; // statement to be executed before performing end_pc modification\n}\n\nnoeq type t = {\n  ok: bool;\n  program_statement: program_statement_t;\n}\n\nlet update_thread_pc_in_state (s: Armada.State.t) (tid: tid_t) (opc: option pc_t) : Armada.State.t =\n  match opc with\n  | Some pc ->\n      let thread = s.threads tid in\n      let new_thread = { thread with pc = pc; } in\n      let new_threads = Spec.Map.upd s.threads tid new_thread in\n      { s with threads = new_threads }\n  | None -> s\n\nlet action_computation\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (nd: nondeterminism_t)\n  (action: t)\n  (s: Armada.State.t)\n  : GTot (option Armada.State.t) =\n  // It's illegal to take a step from a stopped state.\n  // Also, if a step isn't crashing, then the action should be yielding if and only if\n  // it's the last step of a transition.  And the action can't crash unless it's the last\n  // step of a transition.\n  let ps = action.program_statement in\n  if   not (NotStopped? s.stop_reason)\n     || (starts_atomic_block <> ps.starts_atomic_block)\n     || (ends_atomic_block <> (not action.ok || ps.ends_atomic_block)) then\n    None\n  else\n    let thread = s.threads actor in\n    // actor must be a running thread\n    // if start_pc isn't None, then it must match the thread's PC\n    if    not (ThreadStatusRunning? thread.status)\n        || (Some? ps.start_pc && Some?.v ps.start_pc <> thread.pc) then\n      None\n    else\n      (match statement_computation actor nd thread.pc ps.end_pc ps.statement s with\n       | ComputationImpossible -> None\n       | ComputationUndefined ->\n           if action.ok then\n             None\n           else\n             Some ({ s with stop_reason = StopReasonUndefinedBehavior })\n       | ComputationProduces s' ->\n           if not action.ok then\n             None\n           else\n             Some (update_thread_pc_in_state s' actor ps.end_pc))\n"
  },
  {
    "path": "experimental/lib/Armada.Base.fst",
    "content": "module Armada.Base\n\ntype tid_t = nat\ntype var_id_t = string\ntype method_id_t = string\ntype pc_t = string\ntype root_id_uniquifier_t = nat\n\ntype root_id_t =\n  | RootIdGlobal: (var_id: var_id_t) -> root_id_t\n  | RootIdStack: (tid: tid_t) -> (method_id: method_id_t) -> (frame_uniq: root_id_uniquifier_t) ->\n                 (var_id: var_id_t) -> root_id_t\n  | RootIdAllocation: (allocation_uniq: root_id_uniquifier_t) -> root_id_t\n  | RootIdFence: root_id_t\n\n"
  },
  {
    "path": "experimental/lib/Armada.BinaryOp.fst",
    "content": "module Armada.BinaryOp\n\nopen Armada.Computation\nopen Armada.Type\nopen Armada.BoundedInt\nopen Armada.Pointer\nopen FStar.BV\nopen Spec.Ubool\n\nnoeq type t = {\n  operand_td1: object_td_t;\n  operand_td2: object_td_t;\n  result_td: object_td_t;\n  eval: (operand1: valid_object_value_t operand_td1) ->\n        (operand2: valid_object_value_t operand_td2) ->\n         GTot (conditional_computation_t (valid_object_value_t result_td));\n}\n\n// infix operator for mathematical integer types\n\nlet add_op : t = \n  let local_eval\n    (operand1: valid_object_value_t (ObjectTDAbstract int))\n    (operand2: valid_object_value_t (ObjectTDAbstract int))\n    : GTot (conditional_computation_t (valid_object_value_t (ObjectTDAbstract int))) = (\n    let op1 = ObjectValueAbstract?.value operand1 in\n    let op2 = ObjectValueAbstract?.value operand2 in\n    let result = op1 + op2 in\n    return (ObjectValueAbstract int result)) in\n  {\n    operand_td1 = ObjectTDAbstract int;\n    operand_td2 = ObjectTDAbstract int;\n    result_td = ObjectTDAbstract int;\n    eval = local_eval;\n  }\n\nlet sub_op : t = \n  let local_eval\n    (operand1: valid_object_value_t (ObjectTDAbstract int))\n    (operand2: valid_object_value_t (ObjectTDAbstract int))\n    : GTot (conditional_computation_t (valid_object_value_t (ObjectTDAbstract int))) = (\n    let op1 = ObjectValueAbstract?.value operand1 in\n    let op2 = ObjectValueAbstract?.value operand2 in\n    let result = op1 - op2 in\n    return (ObjectValueAbstract int result)) in\n  {\n    operand_td1 = ObjectTDAbstract int;\n    operand_td2 = ObjectTDAbstract int;\n    result_td = ObjectTDAbstract int;\n    eval = local_eval;\n  }\n\nlet mul_op : t = \n  let local_eval\n    (operand1: valid_object_value_t (ObjectTDAbstract int))\n    (operand2: valid_object_value_t (ObjectTDAbstract int))\n    : GTot (conditional_computation_t (valid_object_value_t (ObjectTDAbstract int))) = (\n    let op1 = ObjectValueAbstract?.value operand1 in\n    let op2 = ObjectValueAbstract?.value operand2 in\n    let result = op1 `op_Multiply` op2 in\n    return (ObjectValueAbstract int result)) in\n  {\n    operand_td1 = ObjectTDAbstract int;\n    operand_td2 = ObjectTDAbstract int;\n    result_td = ObjectTDAbstract int;\n    eval = local_eval;\n  }\n\nlet div_op : t =\n  let local_eval\n    (operand1: valid_object_value_t (ObjectTDAbstract int))\n    (operand2: valid_object_value_t (ObjectTDAbstract int))\n    : GTot (conditional_computation_t (valid_object_value_t (ObjectTDAbstract int))) = (\n    let numerator = ObjectValueAbstract?.value operand1 in\n    let divisor = ObjectValueAbstract?.value operand2 in\n    if divisor = 0 then\n      ComputationUndefined\n    else\n      let result = numerator / divisor in\n      return (ObjectValueAbstract int result)) in\n  {\n    operand_td1 = ObjectTDAbstract int;\n    operand_td2 = ObjectTDAbstract int;\n    result_td = ObjectTDAbstract int;\n    eval = local_eval;\n  }\n\nlet mod_op : t =\n  let local_eval\n    (operand1: valid_object_value_t (ObjectTDAbstract int))\n    (operand2: valid_object_value_t (ObjectTDAbstract int))\n    : GTot (conditional_computation_t (valid_object_value_t (ObjectTDAbstract int))) = (\n    let numerator = ObjectValueAbstract?.value operand1 in\n    let divisor = ObjectValueAbstract?.value operand2 in\n    if divisor = 0 then\n      ComputationUndefined\n    else\n      let result = numerator % divisor in\n      return (ObjectValueAbstract int result)) in\n  {\n    operand_td1 = ObjectTDAbstract int;\n    operand_td2 = ObjectTDAbstract int;\n    result_td = ObjectTDAbstract int;\n    eval = local_eval;\n  }\n\nlet left_shift_op : t = \n  let local_eval\n    (operand1: valid_object_value_t (ObjectTDAbstract int))\n    (operand2: valid_object_value_t (ObjectTDAbstract nat))\n    : GTot (conditional_computation_t (valid_object_value_t (ObjectTDAbstract int))) = (\n    let op1 = ObjectValueAbstract?.value operand1 in\n    let op2 = ObjectValueAbstract?.value operand2 in\n    let result = FStar.Math.Lib.shift_left op1 op2 in\n    return (ObjectValueAbstract int result)) in\n  {\n    operand_td1 = ObjectTDAbstract int;\n    operand_td2 = ObjectTDAbstract nat;\n    result_td = ObjectTDAbstract int;\n    eval = local_eval;\n  }\n\nlet right_shift_op : t = \n  let local_eval\n    (operand1: valid_object_value_t (ObjectTDAbstract int))\n    (operand2: valid_object_value_t (ObjectTDAbstract nat))\n    : GTot (conditional_computation_t (valid_object_value_t (ObjectTDAbstract int))) = (\n    let op1 = ObjectValueAbstract?.value operand1 in\n    let op2 = ObjectValueAbstract?.value operand2 in\n    let result = FStar.Math.Lib.arithmetic_shift_right op1 op2 in\n    return (ObjectValueAbstract int result)) in\n  {\n    operand_td1 = ObjectTDAbstract int;\n    operand_td2 = ObjectTDAbstract nat;\n    result_td = ObjectTDAbstract int;\n    eval = local_eval;\n  }\n\n// infix operator for bounded integers\n// signed integer overflows are treated as undefined behavior, following C11 standard:\n// http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1548.pdf, pp. 76, section 6.5.5\n\nlet bounded_add_op (bt: bounded_int_type_t) : t =\n  let local_eval\n    (operand1: valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)))\n    (operand2: valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)))\n    : GTot (conditional_computation_t (valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)))) = (\n    let op1 = unbox_primitive_box (ObjectValuePrimitive?.value operand1) in\n    let op2 = unbox_primitive_box (ObjectValuePrimitive?.value operand2) in\n    let result = add bt op1 op2 in\n    if is_signed bt && result <> op1 + op2 then\n       ComputationUndefined\n    else\n      return (ObjectValuePrimitive (PrimitiveBoxBoundedInt bt result))) in\n  {\n    operand_td1 = ObjectTDPrimitive (PrimitiveTDBoundedInt bt);\n    operand_td2 = ObjectTDPrimitive (PrimitiveTDBoundedInt bt);\n    result_td = ObjectTDPrimitive (PrimitiveTDBoundedInt bt);\n    eval = local_eval;\n  }\n\nlet bounded_sub_op (bt: bounded_int_type_t) : t =\n  let local_eval\n    (operand1: valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)))\n    (operand2: valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)))\n    : GTot (conditional_computation_t (valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)))) = (\n    let op1 = unbox_primitive_box (ObjectValuePrimitive?.value operand1) in\n    let op2 = unbox_primitive_box (ObjectValuePrimitive?.value operand2) in\n    let result = sub bt op1 op2 in\n    if is_signed bt && result <> op1 - op2 then\n       ComputationUndefined\n    else\n      return (ObjectValuePrimitive (PrimitiveBoxBoundedInt bt result))) in\n  {\n    operand_td1 = ObjectTDPrimitive (PrimitiveTDBoundedInt bt);\n    operand_td2 = ObjectTDPrimitive (PrimitiveTDBoundedInt bt);\n    result_td = ObjectTDPrimitive (PrimitiveTDBoundedInt bt);\n    eval = local_eval;\n  }\n\nlet bounded_mul_op (bt: bounded_int_type_t) : t =\n  let local_eval\n    (operand1: valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)))\n    (operand2: valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)))\n    : GTot (conditional_computation_t (valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt (double_bt_size bt))))) = (\n    let op1 = unbox_primitive_box (ObjectValuePrimitive?.value operand1) in\n    let op2 = unbox_primitive_box (ObjectValuePrimitive?.value operand2) in\n    let result = mul bt op1 op2 in\n    if is_signed bt && result <> op1 `op_Multiply` op2 then\n       ComputationUndefined\n    else\n      return (ObjectValuePrimitive (PrimitiveBoxBoundedInt (double_bt_size bt) result))) in\n  {\n    operand_td1 = ObjectTDPrimitive (PrimitiveTDBoundedInt bt);\n    operand_td2 = ObjectTDPrimitive (PrimitiveTDBoundedInt bt);\n    result_td = ObjectTDPrimitive (PrimitiveTDBoundedInt (double_bt_size bt));\n    eval = local_eval;\n  }\n\n// is overflow check for div/mod necessary?\n// I guess so: https://stackoverflow.com/questions/30394086/integer-division-overflows/30400252#30400252\n\nlet bounded_div_op (bt: bounded_int_type_t) : t =\n  let local_eval\n    (operand1: valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)))\n    (operand2: valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)))\n    : GTot (conditional_computation_t (valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)))) = (\n    let op1 = unbox_primitive_box (ObjectValuePrimitive?.value operand1) in\n    let op2 = unbox_primitive_box (ObjectValuePrimitive?.value operand2) in\n    if op2 = 0 then\n       ComputationUndefined\n    else\n      let result = div bt op1 op2 in\n      if is_signed bt && result <> op1 / op2 then\n         ComputationUndefined\n      else\n         return (ObjectValuePrimitive (PrimitiveBoxBoundedInt bt result))) in\n  {\n    operand_td1 = ObjectTDPrimitive (PrimitiveTDBoundedInt bt);\n    operand_td2 = ObjectTDPrimitive (PrimitiveTDBoundedInt bt);\n    result_td = ObjectTDPrimitive (PrimitiveTDBoundedInt bt);\n    eval = local_eval;\n  }\n\nlet bounded_mod_op (bt: bounded_int_type_t) : t =\n  let local_eval\n    (operand1: valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)))\n    (operand2: valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)))\n    : GTot (conditional_computation_t (valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)))) = (\n    let op1 = unbox_primitive_box (ObjectValuePrimitive?.value operand1) in\n    let op2 = unbox_primitive_box (ObjectValuePrimitive?.value operand2) in\n    if op2 = 0 then\n       ComputationUndefined\n    else\n      let result = mod bt op1 op2 in\n      if is_signed bt && result <> op1 % op2 then\n         ComputationUndefined\n      else\n         return (ObjectValuePrimitive (PrimitiveBoxBoundedInt bt result))) in\n  {\n    operand_td1 = ObjectTDPrimitive (PrimitiveTDBoundedInt bt);\n    operand_td2 = ObjectTDPrimitive (PrimitiveTDBoundedInt bt);\n    result_td = ObjectTDPrimitive (PrimitiveTDBoundedInt bt);\n    eval = local_eval;\n  }\n\n// logic operators\n\nlet and_op : t =\n  let local_eval\n    (operand1: valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBool)))\n    (operand2: valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBool)))\n    : GTot (conditional_computation_t (valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBool)))) =\n    let op1 = unbox_primitive_box (ObjectValuePrimitive?.value operand1) in\n    let op2 = unbox_primitive_box (ObjectValuePrimitive?.value operand2) in\n      return (ObjectValuePrimitive (PrimitiveBoxBool (op1 && op2))) in\n  {\n    operand_td1 = ObjectTDPrimitive (PrimitiveTDBool);\n    operand_td2 = ObjectTDPrimitive (PrimitiveTDBool);\n    result_td = ObjectTDPrimitive (PrimitiveTDBool);\n    eval = local_eval;\n  }\n\nlet or_op : t =\n  let local_eval\n    (operand1: valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBool)))\n    (operand2: valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBool)))\n    : GTot (conditional_computation_t (valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBool)))) =\n    let op1 = unbox_primitive_box (ObjectValuePrimitive?.value operand1) in\n    let op2 = unbox_primitive_box (ObjectValuePrimitive?.value operand2) in\n      return (ObjectValuePrimitive (PrimitiveBoxBool (op1 || op2))) in\n  {\n    operand_td1 = ObjectTDPrimitive (PrimitiveTDBool);\n    operand_td2 = ObjectTDPrimitive (PrimitiveTDBool);\n    result_td = ObjectTDPrimitive (PrimitiveTDBool);\n    eval = local_eval;\n  }\n\nlet xor_op : t =\n  let local_eval\n    (operand1: valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBool)))\n    (operand2: valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBool)))\n    : GTot (conditional_computation_t (valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBool)))) =\n    let op1 = unbox_primitive_box (ObjectValuePrimitive?.value operand1) in\n    let op2 = unbox_primitive_box (ObjectValuePrimitive?.value operand2) in\n      return (ObjectValuePrimitive (PrimitiveBoxBool ((op1 && not op2) || (not op1 && op2)))) in\n  {\n    operand_td1 = ObjectTDPrimitive (PrimitiveTDBool);\n    operand_td2 = ObjectTDPrimitive (PrimitiveTDBool);\n    result_td = ObjectTDPrimitive (PrimitiveTDBool);\n    eval = local_eval;\n  }\n\nlet equiv_op : t =\n  let local_eval\n    (operand1: valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBool)))\n    (operand2: valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBool)))\n    : GTot (conditional_computation_t (valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBool)))) =\n    let op1 = unbox_primitive_box (ObjectValuePrimitive?.value operand1) in\n    let op2 = unbox_primitive_box (ObjectValuePrimitive?.value operand2) in\n      return (ObjectValuePrimitive (PrimitiveBoxBool ((not op1 && not op2) || (op1 && op2)))) in\n  {\n    operand_td1 = ObjectTDPrimitive (PrimitiveTDBool);\n    operand_td2 = ObjectTDPrimitive (PrimitiveTDBool);\n    result_td = ObjectTDPrimitive (PrimitiveTDBool);\n    eval = local_eval;\n  }\n\nlet imply_op : t =\n  let local_eval\n    (operand1: valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBool)))\n    (operand2: valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBool)))\n    : GTot (conditional_computation_t (valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBool)))) =\n    let op1 = unbox_primitive_box (ObjectValuePrimitive?.value operand1) in\n    let op2 = unbox_primitive_box (ObjectValuePrimitive?.value operand2) in\n      return (ObjectValuePrimitive (PrimitiveBoxBool (not op1 || (op1 && op2)))) in\n  {\n    operand_td1 = ObjectTDPrimitive (PrimitiveTDBool);\n    operand_td2 = ObjectTDPrimitive (PrimitiveTDBool);\n    result_td = ObjectTDPrimitive (PrimitiveTDBool);\n    eval = local_eval;\n  }\n\nlet exply_op : t =\n  let local_eval\n    (operand1: valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBool)))\n    (operand2: valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBool)))\n    : GTot (conditional_computation_t (valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBool)))) =\n    let op1 = unbox_primitive_box (ObjectValuePrimitive?.value operand1) in\n    let op2 = unbox_primitive_box (ObjectValuePrimitive?.value operand2) in\n      return (ObjectValuePrimitive (PrimitiveBoxBool (not op2 || (op1 && op2)))) in\n  {\n    operand_td1 = ObjectTDPrimitive (PrimitiveTDBool);\n    operand_td2 = ObjectTDPrimitive (PrimitiveTDBool);\n    result_td = ObjectTDPrimitive (PrimitiveTDBool);\n    eval = local_eval;\n  }\n\nlet ptr_eq (operand1 operand2: Armada.Pointer.t) :\n    GTot (option bool) =\n  match operand1, operand2 with\n  | PointerNull, PointerNull -> Some true\n  | PointerNull, _ | _, PointerNull -> Some false\n  | PointerRoot id1, PointerRoot id2 -> Some (id1 = id2)\n  | PointerField struct1 field1, PointerField struct2 field2 ->\n    if struct1 = struct2 then Some (field1 = field2) else None\n  | PointerIndex arr1 idx1, PointerIndex arr2 idx2 ->\n    if arr1 = arr2 then Some (idx1 = idx2) else None\n  | _, _ -> None\n\nlet eq_op (op_td: object_td_t) : t =\n  let local_eval\n    (operand1: valid_object_value_t op_td)\n    (operand2: valid_object_value_t op_td)\n    : GTot (conditional_computation_t (valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBool)))) =\n    match op_td with\n    | ObjectTDAbstract _ ->\n      let op1 = ObjectValueAbstract?.value operand1 in\n      let op2 = ObjectValueAbstract?.value operand2 in\n        return (ObjectValuePrimitive (PrimitiveBoxBool (u2b (op1 == op2))))\n    | ObjectTDPrimitive PrimitiveTDPointer ->\n      let op1 = unbox_primitive_box (ObjectValuePrimitive?.value operand1) in\n      let op2 = unbox_primitive_box (ObjectValuePrimitive?.value operand2) in\n      (\n        match ptr_eq op1 op2 with\n        | Some b -> return (ObjectValuePrimitive (PrimitiveBoxBool b))\n        | None -> ComputationUndefined\n      )\n    | ObjectTDPrimitive PrimitiveTDThreadId ->\n      ComputationUndefined\n    | ObjectTDPrimitive _ ->\n      let op1 = unbox_primitive_box (ObjectValuePrimitive?.value operand1) in\n      let op2 = unbox_primitive_box (ObjectValuePrimitive?.value operand2) in\n        return (ObjectValuePrimitive (PrimitiveBoxBool (op1 = op2)))\n    | _ ->\n      ComputationUndefined\n  in\n  {\n    operand_td1 = op_td;\n    operand_td2 = op_td;\n    result_td = ObjectTDPrimitive (PrimitiveTDBool);\n    eval = local_eval;\n  }\n\nlet neq_op (op_td: object_td_t) : t =\n  let local_eval\n    (operand1: valid_object_value_t op_td)\n    (operand2: valid_object_value_t op_td)\n    : GTot (conditional_computation_t (valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBool)))) =\n    match op_td with\n    | ObjectTDAbstract _ ->\n      let op1 = ObjectValueAbstract?.value operand1 in\n      let op2 = ObjectValueAbstract?.value operand2 in\n        return (ObjectValuePrimitive (PrimitiveBoxBool (not (u2b (op1 == op2)))))\n    | ObjectTDPrimitive PrimitiveTDPointer ->\n      let op1 = unbox_primitive_box (ObjectValuePrimitive?.value operand1) in\n      let op2 = unbox_primitive_box (ObjectValuePrimitive?.value operand2) in\n      (\n        match ptr_eq op1 op2 with\n        | Some b -> return (ObjectValuePrimitive (PrimitiveBoxBool (not b)))\n        | None -> ComputationUndefined\n      )\n    | ObjectTDPrimitive PrimitiveTDThreadId ->\n      ComputationUndefined\n    | ObjectTDPrimitive _ ->\n      let op1 = unbox_primitive_box (ObjectValuePrimitive?.value operand1) in\n      let op2 = unbox_primitive_box (ObjectValuePrimitive?.value operand2) in\n        return (ObjectValuePrimitive (PrimitiveBoxBool (op1 <> op2)))\n    | _ ->\n      ComputationUndefined\n  in\n  {\n    operand_td1 = op_td;\n    operand_td2 = op_td;\n    result_td = ObjectTDPrimitive (PrimitiveTDBool);\n    eval = local_eval;\n  }\n\nlet less_than_op : t =\n  let local_eval\n    (operand1: valid_object_value_t (ObjectTDAbstract int))\n    (operand2: valid_object_value_t (ObjectTDAbstract int))\n    : GTot (conditional_computation_t (valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBool)))) = (\n    let op1 = ObjectValueAbstract?.value operand1 in\n    let op2 = ObjectValueAbstract?.value operand2 in\n    let result = op1 < op2 in\n    return (ObjectValuePrimitive (PrimitiveBoxBool result))) in\n  {\n    operand_td1 = ObjectTDAbstract int;\n    operand_td2 = ObjectTDAbstract int;\n    result_td = ObjectTDPrimitive (PrimitiveTDBool);\n    eval = local_eval;\n  }\n\nlet less_than_or_equal_op : t =\n  let local_eval\n    (operand1: valid_object_value_t (ObjectTDAbstract int))\n    (operand2: valid_object_value_t (ObjectTDAbstract int))\n    : GTot (conditional_computation_t (valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBool)))) = (\n    let op1 = ObjectValueAbstract?.value operand1 in\n    let op2 = ObjectValueAbstract?.value operand2 in\n    let result = op1 <= op2 in\n    return (ObjectValuePrimitive (PrimitiveBoxBool result))) in\n  {\n    operand_td1 = ObjectTDAbstract int;\n    operand_td2 = ObjectTDAbstract int;\n    result_td = ObjectTDPrimitive (PrimitiveTDBool);\n    eval = local_eval;\n  }\n\nlet greater_than_op : t =\n  let local_eval\n    (operand1: valid_object_value_t (ObjectTDAbstract int))\n    (operand2: valid_object_value_t (ObjectTDAbstract int))\n    : GTot (conditional_computation_t (valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBool)))) = (\n    let op1 = ObjectValueAbstract?.value operand1 in\n    let op2 = ObjectValueAbstract?.value operand2 in\n    let result = op1 > op2 in\n    return (ObjectValuePrimitive (PrimitiveBoxBool result))) in\n  {\n    operand_td1 = ObjectTDAbstract int;\n    operand_td2 = ObjectTDAbstract int;\n    result_td = ObjectTDPrimitive (PrimitiveTDBool);\n    eval = local_eval;\n  }\n\nlet greater_than_or_equal_op : t =\n  let local_eval\n    (operand1: valid_object_value_t (ObjectTDAbstract int))\n    (operand2: valid_object_value_t (ObjectTDAbstract int))\n    : GTot (conditional_computation_t (valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBool)))) = (\n    let op1 = ObjectValueAbstract?.value operand1 in\n    let op2 = ObjectValueAbstract?.value operand2 in\n    let result = op1 >= op2 in\n    return (ObjectValuePrimitive (PrimitiveBoxBool result))) in\n  {\n    operand_td1 = ObjectTDAbstract int;\n    operand_td2 = ObjectTDAbstract int;\n    result_td = ObjectTDPrimitive (PrimitiveTDBool);\n    eval = local_eval;\n  }\n\nlet bounded_less_than_op (bt: bounded_int_type_t) : t =\n  let local_eval\n    (operand1: valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)))\n    (operand2: valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)))\n    : GTot (conditional_computation_t (valid_object_value_t (ObjectTDPrimitive PrimitiveTDBool))) = (\n    let op1 = unbox_primitive_box (ObjectValuePrimitive?.value operand1) in\n    let op2 = unbox_primitive_box (ObjectValuePrimitive?.value operand2) in\n    let result = op1 < op2 in\n      return (ObjectValuePrimitive (PrimitiveBoxBool result))) in\n  {\n    operand_td1 = ObjectTDPrimitive (PrimitiveTDBoundedInt bt);\n    operand_td2 = ObjectTDPrimitive (PrimitiveTDBoundedInt bt);\n    result_td = ObjectTDPrimitive PrimitiveTDBool;\n    eval = local_eval;\n  }\n\nlet bounded_less_than_or_equal_op (bt: bounded_int_type_t) : t =\n  let local_eval\n    (operand1: valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)))\n    (operand2: valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)))\n    : GTot (conditional_computation_t (valid_object_value_t (ObjectTDPrimitive PrimitiveTDBool))) = (\n    let op1 = unbox_primitive_box (ObjectValuePrimitive?.value operand1) in\n    let op2 = unbox_primitive_box (ObjectValuePrimitive?.value operand2) in\n    let result = op1 <= op2 in\n      return (ObjectValuePrimitive (PrimitiveBoxBool result))) in\n  {\n    operand_td1 = ObjectTDPrimitive (PrimitiveTDBoundedInt bt);\n    operand_td2 = ObjectTDPrimitive (PrimitiveTDBoundedInt bt);\n    result_td = ObjectTDPrimitive PrimitiveTDBool;\n    eval = local_eval;\n  }\n\nlet bounded_greater_than_op (bt: bounded_int_type_t) : t =\n  let local_eval\n    (operand1: valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)))\n    (operand2: valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)))\n    : GTot (conditional_computation_t (valid_object_value_t (ObjectTDPrimitive PrimitiveTDBool))) = (\n    let op1 = unbox_primitive_box (ObjectValuePrimitive?.value operand1) in\n    let op2 = unbox_primitive_box (ObjectValuePrimitive?.value operand2) in\n    let result = op1 > op2 in\n      return (ObjectValuePrimitive (PrimitiveBoxBool result))) in\n  {\n    operand_td1 = ObjectTDPrimitive (PrimitiveTDBoundedInt bt);\n    operand_td2 = ObjectTDPrimitive (PrimitiveTDBoundedInt bt);\n    result_td = ObjectTDPrimitive PrimitiveTDBool;\n    eval = local_eval;\n  }\n\nlet bounded_greater_than_or_equal_op (bt: bounded_int_type_t) : t =\n  let local_eval\n    (operand1: valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)))\n    (operand2: valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)))\n    : GTot (conditional_computation_t (valid_object_value_t (ObjectTDPrimitive PrimitiveTDBool))) = (\n    let op1 = unbox_primitive_box (ObjectValuePrimitive?.value operand1) in\n    let op2 = unbox_primitive_box (ObjectValuePrimitive?.value operand2) in\n    let result = op1 >= op2 in\n      return (ObjectValuePrimitive (PrimitiveBoxBool result))) in\n  {\n    operand_td1 = ObjectTDPrimitive (PrimitiveTDBoundedInt bt);\n    operand_td2 = ObjectTDPrimitive (PrimitiveTDBoundedInt bt);\n    result_td = ObjectTDPrimitive PrimitiveTDBool;\n    eval = local_eval;\n  }\n\nlet pointer_less_than_op : t =\n  let local_eval\n    (operand1 operand2: valid_object_value_t (ObjectTDPrimitive PrimitiveTDPointer))\n    : GTot (conditional_computation_t (valid_object_value_t (ObjectTDPrimitive PrimitiveTDBool))) = (\n    let op1 = unbox_primitive_box (ObjectValuePrimitive?.value operand1) in\n    let op2 = unbox_primitive_box (ObjectValuePrimitive?.value operand2) in\n    match op1, op2 with\n    | PointerIndex arr1 field1, PointerIndex arr2 field2 ->\n      if arr1 = arr2 then return (ObjectValuePrimitive (PrimitiveBoxBool (field1 < field2))) else ComputationUndefined\n    | _ -> ComputationUndefined\n    ) in\n  {\n    operand_td1 = ObjectTDPrimitive PrimitiveTDPointer;\n    operand_td2 = ObjectTDPrimitive PrimitiveTDPointer;\n    result_td = ObjectTDPrimitive PrimitiveTDBool;\n    eval = local_eval;\n  }\n\nlet pointer_less_than_or_equal_op : t =\n  let local_eval\n    (operand1 operand2: valid_object_value_t (ObjectTDPrimitive PrimitiveTDPointer))\n    : GTot (conditional_computation_t (valid_object_value_t (ObjectTDPrimitive PrimitiveTDBool))) = (\n    let op1 = unbox_primitive_box (ObjectValuePrimitive?.value operand1) in\n    let op2 = unbox_primitive_box (ObjectValuePrimitive?.value operand2) in\n    match op1, op2 with\n    | PointerIndex arr1 field1, PointerIndex arr2 field2 ->\n      if arr1 = arr2 then return (ObjectValuePrimitive (PrimitiveBoxBool (field1 < field2))) else ComputationUndefined\n    | _ -> ComputationUndefined\n    ) in\n  {\n    operand_td1 = ObjectTDPrimitive PrimitiveTDPointer;\n    operand_td2 = ObjectTDPrimitive PrimitiveTDPointer;\n    result_td = ObjectTDPrimitive PrimitiveTDBool;\n    eval = local_eval;\n  }\n\nlet pointer_greater_than_op : t =\n  let local_eval\n    (operand1 operand2: valid_object_value_t (ObjectTDPrimitive PrimitiveTDPointer))\n    : GTot (conditional_computation_t (valid_object_value_t (ObjectTDPrimitive PrimitiveTDBool))) = (\n    let op1 = unbox_primitive_box (ObjectValuePrimitive?.value operand1) in\n    let op2 = unbox_primitive_box (ObjectValuePrimitive?.value operand2) in\n    match op1, op2 with\n    | PointerIndex arr1 field1, PointerIndex arr2 field2 ->\n      if arr1 = arr2 then return (ObjectValuePrimitive (PrimitiveBoxBool (field1 > field2))) else ComputationUndefined\n    | _ -> ComputationUndefined\n    ) in\n  {\n    operand_td1 = ObjectTDPrimitive PrimitiveTDPointer;\n    operand_td2 = ObjectTDPrimitive PrimitiveTDPointer;\n    result_td = ObjectTDPrimitive PrimitiveTDBool;\n    eval = local_eval;\n  }\n\nlet pointer_greater_than_or_equal_op : t =\n  let local_eval\n    (operand1 operand2: valid_object_value_t (ObjectTDPrimitive PrimitiveTDPointer))\n    : GTot (conditional_computation_t (valid_object_value_t (ObjectTDPrimitive PrimitiveTDBool))) = (\n    let op1 = unbox_primitive_box (ObjectValuePrimitive?.value operand1) in\n    let op2 = unbox_primitive_box (ObjectValuePrimitive?.value operand2) in\n    match op1, op2 with\n    | PointerIndex arr1 field1, PointerIndex arr2 field2 ->\n      if arr1 = arr2 then return (ObjectValuePrimitive (PrimitiveBoxBool (field1 >= field2))) else ComputationUndefined\n    | _ -> ComputationUndefined\n    ) in\n  {\n    operand_td1 = ObjectTDPrimitive PrimitiveTDPointer;\n    operand_td2 = ObjectTDPrimitive PrimitiveTDPointer;\n    result_td = ObjectTDPrimitive PrimitiveTDBool;\n    eval = local_eval;\n  }\n\n// Bitwise and/or/xor/left shift/right shift\n\nlet bitwise_and_op (bt: bounded_int_type_t) : t =\n  let local_eval\n    (operand1: valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)))\n    (operand2: valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)))\n    : GTot (conditional_computation_t (valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)))) = (\n    if is_signed bt then\n       ComputationUndefined\n    else (\n      let num_bits = num_bits_in_bounded_int_type bt in\n      let op1: bv_t num_bits = int2bv (unbox_primitive_box (ObjectValuePrimitive?.value operand1)) in\n      let op2: bv_t num_bits = int2bv (unbox_primitive_box (ObjectValuePrimitive?.value operand2)) in\n      let result: bt_to_ty bt = bv2int (bvand op1 op2) in\n      return (ObjectValuePrimitive (PrimitiveBoxBoundedInt bt result)))\n    ) in\n  {\n    operand_td1 = ObjectTDPrimitive (PrimitiveTDBoundedInt bt);\n    operand_td2 = ObjectTDPrimitive (PrimitiveTDBoundedInt bt);\n    result_td = ObjectTDPrimitive (PrimitiveTDBoundedInt bt);\n    eval = local_eval;\n  }\n\nlet bitwise_or_op (bt: bounded_int_type_t) : t =\n  let local_eval\n    (operand1: valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)))\n    (operand2: valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)))\n    : GTot (conditional_computation_t (valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)))) = (\n    if is_signed bt then\n       ComputationUndefined\n    else (\n      let num_bits = num_bits_in_bounded_int_type bt in\n      let op1: bv_t num_bits = int2bv (unbox_primitive_box (ObjectValuePrimitive?.value operand1)) in\n      let op2: bv_t num_bits = int2bv (unbox_primitive_box (ObjectValuePrimitive?.value operand2)) in\n      let result: bt_to_ty bt = bv2int (bvor op1 op2) in\n      return (ObjectValuePrimitive (PrimitiveBoxBoundedInt bt result)))\n    ) in\n  {\n    operand_td1 = ObjectTDPrimitive (PrimitiveTDBoundedInt bt);\n    operand_td2 = ObjectTDPrimitive (PrimitiveTDBoundedInt bt);\n    result_td = ObjectTDPrimitive (PrimitiveTDBoundedInt bt);\n    eval = local_eval;\n  }\n\nlet bitwise_xor_op (bt: bounded_int_type_t) : t =\n  let local_eval\n    (operand1: valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)))\n    (operand2: valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)))\n    : GTot (conditional_computation_t (valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)))) = (\n    if is_signed bt then\n       ComputationUndefined\n    else (\n      let num_bits = num_bits_in_bounded_int_type bt in\n      let op1: bv_t num_bits = int2bv (unbox_primitive_box (ObjectValuePrimitive?.value operand1)) in\n      let op2: bv_t num_bits = int2bv (unbox_primitive_box (ObjectValuePrimitive?.value operand2)) in\n      let result: bt_to_ty bt = bv2int (bvxor op1 op2) in\n      return (ObjectValuePrimitive (PrimitiveBoxBoundedInt bt result)))\n    ) in\n  {\n    operand_td1 = ObjectTDPrimitive (PrimitiveTDBoundedInt bt);\n    operand_td2 = ObjectTDPrimitive (PrimitiveTDBoundedInt bt);\n    result_td = ObjectTDPrimitive (PrimitiveTDBoundedInt bt);\n    eval = local_eval;\n  }\n\nlet bitwise_left_shift_op (bt: bounded_int_type_t) : t =\n  let local_eval\n    (operand1: valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)))\n    (operand2: valid_object_value_t (ObjectTDAbstract nat))\n    : GTot (conditional_computation_t (valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)))) = (\n    if is_signed bt then\n       ComputationUndefined\n    else (\n      let num_bits = num_bits_in_bounded_int_type bt in\n      let op1: bv_t num_bits = int2bv (unbox_primitive_box (ObjectValuePrimitive?.value operand1)) in\n      let op2 = ObjectValueAbstract?.value operand2 in\n      let result: bt_to_ty bt = bv2int (bvshl op1 op2) in\n      return (ObjectValuePrimitive (PrimitiveBoxBoundedInt bt result)))\n    ) in\n  {\n    operand_td1 = ObjectTDPrimitive (PrimitiveTDBoundedInt bt);\n    operand_td2 = ObjectTDAbstract nat;\n    result_td = ObjectTDPrimitive (PrimitiveTDBoundedInt bt);\n    eval = local_eval;\n  }\n\nlet bitwise_right_shift_op (bt: bounded_int_type_t) : t =\n  let local_eval\n    (operand1: valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)))\n    (operand2: valid_object_value_t (ObjectTDAbstract nat))\n    : GTot (conditional_computation_t (valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)))) = (\n    if is_signed bt then\n       ComputationUndefined\n    else (\n      let num_bits = num_bits_in_bounded_int_type bt in\n      let op1: bv_t num_bits = int2bv (unbox_primitive_box (ObjectValuePrimitive?.value operand1)) in\n      let op2 = ObjectValueAbstract?.value operand2 in\n      let result: bt_to_ty bt = bv2int (bvshr op1 op2) in\n      return (ObjectValuePrimitive (PrimitiveBoxBoundedInt bt result)))\n    ) in\n  {\n    operand_td1 = ObjectTDPrimitive (PrimitiveTDBoundedInt bt);\n    operand_td2 = ObjectTDAbstract nat;\n    result_td = ObjectTDPrimitive (PrimitiveTDBoundedInt bt);\n    eval = local_eval;\n  }\n\nnoeq type binary_op_t : (operand_td1: object_td_t) -> (operand_td2: object_td_t) -> (result_td: object_td_t) -> Type =\n  | BinaryOpAddInt: binary_op_t (ObjectTDAbstract int) (ObjectTDAbstract int) (ObjectTDAbstract int)\n  | BinaryOpSubInt: binary_op_t (ObjectTDAbstract int) (ObjectTDAbstract int) (ObjectTDAbstract int)\n  | BinaryOpMulInt: binary_op_t (ObjectTDAbstract int) (ObjectTDAbstract int) (ObjectTDAbstract int)\n  | BinaryOpDivInt: binary_op_t (ObjectTDAbstract int) (ObjectTDAbstract int) (ObjectTDAbstract int)\n  | BinaryOpModInt: binary_op_t (ObjectTDAbstract int) (ObjectTDAbstract int) (ObjectTDAbstract int)\n  | BinaryOpLeftShift: binary_op_t (ObjectTDAbstract int) (ObjectTDAbstract nat) (ObjectTDAbstract int)\n  | BinaryOpRightShift: binary_op_t (ObjectTDAbstract int) (ObjectTDAbstract nat) (ObjectTDAbstract int)\n  | BinaryOpBoundedAdd:\n      bt: bounded_int_type_t ->\n      binary_op_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)) (ObjectTDPrimitive (PrimitiveTDBoundedInt bt))\n                  (ObjectTDPrimitive (PrimitiveTDBoundedInt bt))\n  | BinaryOpBoundedSub:\n      bt: bounded_int_type_t ->\n      binary_op_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)) (ObjectTDPrimitive (PrimitiveTDBoundedInt bt))\n                  (ObjectTDPrimitive (PrimitiveTDBoundedInt bt))\n  | BinaryOpBoundedMul:\n      bt: bounded_int_type_t ->\n      binary_op_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)) (ObjectTDPrimitive (PrimitiveTDBoundedInt bt))\n                  (ObjectTDPrimitive (PrimitiveTDBoundedInt (double_bt_size bt)))\n  | BinaryOpBoundedDiv:\n      bt: bounded_int_type_t ->\n      binary_op_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)) (ObjectTDPrimitive (PrimitiveTDBoundedInt bt))\n                  (ObjectTDPrimitive (PrimitiveTDBoundedInt bt))\n  | BinaryOpBoundedMod:\n      bt: bounded_int_type_t ->\n      binary_op_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)) (ObjectTDPrimitive (PrimitiveTDBoundedInt bt))\n                  (ObjectTDPrimitive (PrimitiveTDBoundedInt bt))\n  | BinaryOpAnd: binary_op_t (ObjectTDPrimitive PrimitiveTDBool) (ObjectTDPrimitive PrimitiveTDBool)\n                             (ObjectTDPrimitive PrimitiveTDBool)\n  | BinaryOpOr: binary_op_t (ObjectTDPrimitive PrimitiveTDBool) (ObjectTDPrimitive PrimitiveTDBool)\n                            (ObjectTDPrimitive PrimitiveTDBool)\n  | BinaryOpXor: binary_op_t (ObjectTDPrimitive PrimitiveTDBool) (ObjectTDPrimitive PrimitiveTDBool)\n                             (ObjectTDPrimitive PrimitiveTDBool)\n  | BinaryOpEquiv: binary_op_t (ObjectTDPrimitive PrimitiveTDBool) (ObjectTDPrimitive PrimitiveTDBool)\n                             (ObjectTDPrimitive PrimitiveTDBool)\n  | BinaryOpImply: binary_op_t (ObjectTDPrimitive PrimitiveTDBool) (ObjectTDPrimitive PrimitiveTDBool)\n                             (ObjectTDPrimitive PrimitiveTDBool)\n  | BinaryOpExply: binary_op_t (ObjectTDPrimitive PrimitiveTDBool) (ObjectTDPrimitive PrimitiveTDBool)\n                             (ObjectTDPrimitive PrimitiveTDBool)\n  | BinaryOpEq: op_td: object_td_t -> binary_op_t op_td op_td (ObjectTDPrimitive PrimitiveTDBool)\n  | BinaryOpNeq: op_td: object_td_t -> binary_op_t op_td op_td (ObjectTDPrimitive (PrimitiveTDBool))\n  | BinaryOpLtInt: binary_op_t (ObjectTDAbstract int) (ObjectTDAbstract int) (ObjectTDPrimitive PrimitiveTDBool)\n  | BinaryOpLeInt: binary_op_t (ObjectTDAbstract int) (ObjectTDAbstract int) (ObjectTDPrimitive PrimitiveTDBool)\n  | BinaryOpGtInt: binary_op_t (ObjectTDAbstract int) (ObjectTDAbstract int) (ObjectTDPrimitive PrimitiveTDBool)\n  | BinaryOpGeInt: binary_op_t (ObjectTDAbstract int) (ObjectTDAbstract int) (ObjectTDPrimitive PrimitiveTDBool)\n  | BinaryOpBoundedLt:\n      bt: bounded_int_type_t ->\n      binary_op_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)) (ObjectTDPrimitive (PrimitiveTDBoundedInt bt))\n                  (ObjectTDPrimitive PrimitiveTDBool)\n  | BinaryOpBoundedLe:\n      bt: bounded_int_type_t ->\n      binary_op_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)) (ObjectTDPrimitive (PrimitiveTDBoundedInt bt))\n                  (ObjectTDPrimitive PrimitiveTDBool)\n  | BinaryOpBoundedGt:\n      bt: bounded_int_type_t ->\n      binary_op_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)) (ObjectTDPrimitive (PrimitiveTDBoundedInt bt))\n                  (ObjectTDPrimitive PrimitiveTDBool)\n  | BinaryOpBoundedGe:\n      bt: bounded_int_type_t ->\n      binary_op_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)) (ObjectTDPrimitive (PrimitiveTDBoundedInt bt))\n                  (ObjectTDPrimitive PrimitiveTDBool)\n  | BinaryOpPtrLt: binary_op_t (ObjectTDPrimitive PrimitiveTDPointer) (ObjectTDPrimitive PrimitiveTDPointer)\n                               (ObjectTDPrimitive PrimitiveTDBool)\n  | BinaryOpPtrLe: binary_op_t (ObjectTDPrimitive PrimitiveTDPointer) (ObjectTDPrimitive PrimitiveTDPointer)\n                               (ObjectTDPrimitive PrimitiveTDBool)\n  | BinaryOpPtrGt: binary_op_t (ObjectTDPrimitive PrimitiveTDPointer) (ObjectTDPrimitive PrimitiveTDPointer)\n                               (ObjectTDPrimitive PrimitiveTDBool)\n  | BinaryOpPtrGe: binary_op_t (ObjectTDPrimitive PrimitiveTDPointer) (ObjectTDPrimitive PrimitiveTDPointer)\n                               (ObjectTDPrimitive PrimitiveTDBool)\n  | BinaryOpBitwiseAnd:\n      bt: bounded_int_type_t ->\n      binary_op_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)) (ObjectTDPrimitive (PrimitiveTDBoundedInt bt))\n                  (ObjectTDPrimitive (PrimitiveTDBoundedInt bt))\n  | BinaryOpBitwiseOr:\n      bt: bounded_int_type_t ->\n      binary_op_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)) (ObjectTDPrimitive (PrimitiveTDBoundedInt bt))\n                  (ObjectTDPrimitive (PrimitiveTDBoundedInt bt))\n  | BinaryOpBitwiseXor:\n      bt: bounded_int_type_t ->\n      binary_op_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)) (ObjectTDPrimitive (PrimitiveTDBoundedInt bt))\n                  (ObjectTDPrimitive (PrimitiveTDBoundedInt bt))\n  | BinaryOpBitwiseLeftShift:\n      bt: bounded_int_type_t ->\n      binary_op_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)) (ObjectTDAbstract nat)\n                  (ObjectTDPrimitive (PrimitiveTDBoundedInt bt))\n  | BinaryOpBitwiseRightShift:\n      bt: bounded_int_type_t ->\n      binary_op_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)) (ObjectTDAbstract nat)\n                  (ObjectTDPrimitive (PrimitiveTDBoundedInt bt))\n\nlet get_binary_op\n  (#operand_td1: object_td_t)\n  (#operand_td2: object_td_t)\n  (#result_td: object_td_t)\n  (binary_op: binary_op_t operand_td1 operand_td2 result_td)\n  : GTot (op: t{op.operand_td1 == operand_td1 /\\ op.operand_td2 == operand_td2 /\\ op.result_td == result_td}) =\n  match binary_op with\n  | BinaryOpAddInt -> add_op\n  | BinaryOpSubInt -> sub_op\n  | BinaryOpMulInt -> mul_op\n  | BinaryOpDivInt -> div_op\n  | BinaryOpModInt -> mod_op\n  | BinaryOpLeftShift -> left_shift_op\n  | BinaryOpRightShift -> right_shift_op\n  | BinaryOpBoundedAdd bt -> bounded_add_op bt\n  | BinaryOpBoundedSub bt -> bounded_sub_op bt\n  | BinaryOpBoundedMul bt -> bounded_mul_op bt\n  | BinaryOpBoundedDiv bt -> bounded_div_op bt\n  | BinaryOpBoundedMod bt -> bounded_mod_op bt\n  | BinaryOpAnd -> and_op\n  | BinaryOpOr -> or_op\n  | BinaryOpXor -> xor_op\n  | BinaryOpEquiv -> equiv_op\n  | BinaryOpImply -> imply_op\n  | BinaryOpExply -> exply_op\n  | BinaryOpEq op_td -> eq_op op_td\n  | BinaryOpNeq op_td -> neq_op op_td\n  | BinaryOpLtInt -> less_than_op\n  | BinaryOpLeInt -> less_than_or_equal_op\n  | BinaryOpGtInt -> greater_than_op\n  | BinaryOpGeInt -> greater_than_or_equal_op\n  | BinaryOpBoundedLt bt -> bounded_less_than_op bt\n  | BinaryOpBoundedLe bt -> bounded_less_than_or_equal_op bt\n  | BinaryOpBoundedGt bt -> bounded_greater_than_op bt\n  | BinaryOpBoundedGe bt -> bounded_greater_than_or_equal_op bt\n  | BinaryOpPtrLt -> pointer_less_than_op\n  | BinaryOpPtrLe -> pointer_less_than_or_equal_op\n  | BinaryOpPtrGt -> pointer_greater_than_op\n  | BinaryOpPtrGe -> pointer_greater_than_or_equal_op\n  | BinaryOpBitwiseAnd bt -> bitwise_and_op bt\n  | BinaryOpBitwiseOr bt -> bitwise_or_op bt\n  | BinaryOpBitwiseXor bt -> bitwise_xor_op bt\n  | BinaryOpBitwiseLeftShift bt -> bitwise_left_shift_op bt\n  | BinaryOpBitwiseRightShift bt -> bitwise_right_shift_op bt\n\nlet eval_binary_op\n  (#operand_td1: object_td_t)\n  (#operand_td2: object_td_t)\n  (#result_td: object_td_t)\n  (binary_op: binary_op_t operand_td1 operand_td2 result_td)\n  (operand1: valid_object_value_t operand_td1)\n  (operand2: valid_object_value_t operand_td2)\n  : GTot (conditional_computation_t (valid_object_value_t result_td)) =\n  let op = get_binary_op binary_op in\n  op.eval operand1 operand2\n\n"
  },
  {
    "path": "experimental/lib/Armada.BoundedInt.fst",
    "content": "module Armada.BoundedInt\n\ntype int8 = n: int{-0x80 <= n && n < 0x80}\ntype int16 = n: int{-0x8000 <= n && n < 0x8000}\ntype int32 = n: int{-0x80000000 <= n && n < 0x80000000}\ntype int64 = n: int{-0x8000000000000000 <= n && n < 0x8000000000000000}\ntype uint8 = n: nat{n < 0x100}\ntype uint16 = n: nat{n < 0x10000}\ntype uint32 = n: nat{n < 0x100000000}\ntype uint64 = n: nat{n < 0x10000000000000000}\n\ntype bounded_int_type_t =\n  | MachineInt8\n  | MachineInt16\n  | MachineInt32\n  | MachineInt64\n  | MachineUint8\n  | MachineUint16\n  | MachineUint32\n  | MachineUint64\n\nlet bt_to_ty (bt: bounded_int_type_t) : Type =\n  match bt with\n  | MachineInt8 -> int8\n  | MachineInt16 -> int16\n  | MachineInt32 -> int32\n  | MachineInt64 -> int64\n  | MachineUint8 -> uint8\n  | MachineUint16 -> uint16\n  | MachineUint32 -> uint32\n  | MachineUint64 -> uint64\n\nlet is_signed (bt: bounded_int_type_t) : GTot bool =\n  match bt with\n  | MachineInt8 | MachineInt16 | MachineInt32 | MachineInt64 -> true\n  | _ -> false\n\nprivate let fit_hidden (bt: bounded_int_type_t) (n: int) : (bt_to_ty bt) =\n  match bt with\n  | MachineInt8 -> (n + 0x80) % 0x100 - 0x80\n  | MachineInt16 -> (n + 0x8000) % 0x10000 - 0x8000\n  | MachineInt32 -> (n + 0x80000000) % 0x100000000 - 0x80000000\n  | MachineInt64 -> (n + 0x8000000000000000) % 0x10000000000000000 - 0x8000000000000000\n  | MachineUint8 -> n % 0x100\n  | MachineUint16 -> n % 0x10000\n  | MachineUint32 -> n % 0x100000000\n  | MachineUint64 -> n % 0x10000000000000000\n\n[@\"opaque_to_smt\"]\nlet fit = fit_hidden\n\nlet reveal_fit () : Lemma (fit == fit_hidden) = \n  reveal_opaque (`%fit) fit\n\nlet fit_is_identity_if_already_fits (bt: bounded_int_type_t) (n: bt_to_ty bt)\n  : Lemma (ensures (n = fit bt n))\n          [SMTPat (fit bt n)] =\n  reveal_fit ()\n\nlet add (bt: bounded_int_type_t) (x: bt_to_ty bt) (y: bt_to_ty bt) : (bt_to_ty bt) =\n  fit bt (x + y)\n\nlet sub (bt: bounded_int_type_t) (x: bt_to_ty bt) (y: bt_to_ty bt) : (bt_to_ty bt) =\n  fit bt (x - y)\n\nlet div (bt: bounded_int_type_t) (x: bt_to_ty bt) (y: bt_to_ty bt{y <> 0}) : (bt_to_ty bt) =\n  fit bt (x / y)\n\nlet mod (bt: bounded_int_type_t) (x: bt_to_ty bt) (y: bt_to_ty bt{y <> 0}) : (bt_to_ty bt) =\n  fit bt (x % y)\n\nlet double_bt_size (bt: bounded_int_type_t) : bounded_int_type_t =\n  match bt with\n  | MachineInt8 -> MachineInt16\n  | MachineInt16 -> MachineInt32\n  | MachineInt32 -> MachineInt64\n  | MachineInt64 -> MachineInt64\n  | MachineUint8 -> MachineUint16\n  | MachineUint16 -> MachineUint32\n  | MachineUint32 -> MachineUint64\n  | MachineUint64 -> MachineUint64\n\nlet num_bits_in_bounded_int_type (bt: bounded_int_type_t) : int =\n  match bt with\n  | MachineInt8 -> 8\n  | MachineInt16 -> 16\n  | MachineInt32 -> 32\n  | MachineInt64 -> 64\n  | MachineUint8 -> 8\n  | MachineUint16 -> 16\n  | MachineUint32 -> 32\n  | MachineUint64 -> 64\n\nlet mul (bt: bounded_int_type_t) (x: bt_to_ty bt) (y: bt_to_ty bt) : (bt_to_ty (double_bt_size bt)) =\n  fit (double_bt_size bt) (x `op_Multiply` y)\n"
  },
  {
    "path": "experimental/lib/Armada.Computation.fst",
    "content": "module Armada.Computation\n\nnoeq type conditional_computation_t (ty: Type) =\n  | ComputationImpossible: conditional_computation_t ty\n  | ComputationUndefined: conditional_computation_t ty\n  | ComputationProduces: (result: ty) -> conditional_computation_t ty\n\nunfold let return (#a: Type) (x: a) : GTot (conditional_computation_t a) = ComputationProduces x\n\nunfold let (let?) (#a: Type) (#b: Type) (m: conditional_computation_t a) (f: a -> GTot (conditional_computation_t b))\n  : GTot (conditional_computation_t b) =\n  match m with\n  | ComputationImpossible -> ComputationImpossible\n  | ComputationUndefined -> ComputationUndefined\n  | ComputationProduces x -> f x\n\nlet otherwise (#a: Type) (inhabitance: a) (m: conditional_computation_t a)\n  : GTot a =\n  match m with\n  | ComputationProduces b -> b\n  | _ -> inhabitance\n\n(*\nlet test1 (x: int) (y: int) : GTot (conditional_computation_t int) =\n  if y = 0 then\n    ComputationUndefined\n  else\n    return (x / y)\n    \nlet test2 (x: int) (y: int) (z: int) : GTot (conditional_computation_t int) =\n  let? xy = test1 x y in\n  test1 xy z\n\nlet test3 () : Lemma (True) =\n  assert (test2 1 0 0 == ComputationUndefined);\n  assert (test2 1 3 0 == ComputationUndefined);\n  assert (test2 1 0 3 == ComputationUndefined);\n  assert (test2 12 2 3 == return 2)\n\nlet test4 (x: int) : GTot (conditional_computation_t unit) =\n  if x = 0 then\n    ComputationImpossible\n  else\n    return ()\n\nlet test5 (x: int) (y: int) : GTot (conditional_computation_t int) =\n  let? _ = test4 x in\n  return (x + y)\n\nlet test6 () : Lemma (True) =\n  assert (test5 0 4 == ComputationImpossible)\n*)\n"
  },
  {
    "path": "experimental/lib/Armada.Expression.fst",
    "content": "module Armada.Expression\n\nopen Armada.Base\nopen Armada.BinaryOp\nopen Armada.BoundedInt\nopen Armada.Computation\nopen Armada.Memory\nopen Armada.Pointer\nopen Armada.State\nopen Armada.Thread\nopen Armada.Type\nopen Armada.UnaryOp\nopen FStar.Sequence.Base\nopen Spec.List\nopen Spec.Ubool\nopen Util.List\n\nlet rec build_function_type (return_type: Type0) (operand_types: list Type0) : Type =\n  match operand_types with\n  | [] -> conditional_computation_t return_type\n  | first_type :: remaining_types -> (first_type -> GTot (build_function_type return_type remaining_types))\n\nnoeq type expression_t =\n  | ExpressionConstant: (value: object_value_t) -> expression_t\n  | ExpressionGlobalVariable: (td: object_td_t) -> (var_id: var_id_t) -> expression_t\n  | ExpressionLocalVariable: (td: object_td_t) -> (var_id: var_id_t) -> expression_t\n  | ExpressionUnaryOperator:\n      (operand_td: object_td_t) -> (result_td: object_td_t) ->\n      (operator: unary_op_t operand_td result_td) -> (operand: expression_t) -> expression_t\n  | ExpressionBinaryOperator:\n      (operand_td1: object_td_t) -> (operand_td2: object_td_t) -> (result_td: object_td_t) ->\n      (operator: binary_op_t operand_td1 operand_td2 result_td) ->\n      (operand1: expression_t) -> (operand2: expression_t) -> expression_t\n  | ExpressionIf: (td: object_td_t) -> (cond: expression_t) -> (operand_then: expression_t) ->\n      (operand_else: expression_t) -> expression_t\n  | ExpressionDereference: (td: object_td_t) -> (ptr: expression_t) -> expression_t\n  | ExpressionAddressOf: (obj: expression_t) -> expression_t\n  | ExpressionPointerOffset: (ptr: expression_t) -> (offset: expression_t) -> expression_t\n  | ExpressionFieldOf: (td: object_td_t) -> (obj: expression_t) -> (field_id: nat) -> expression_t\n  | ExpressionAllocated: (ptr: expression_t) -> expression_t\n  | ExpressionApplyFunction:\n      (td: object_td_t) -> (operands: list expression_t) -> (return_type: Type0) -> (operand_types: list Type0) ->\n      (fn: build_function_type return_type operand_types) -> expression_t\n  | ExpressionIfUndefined:\n      (td: object_td_t) -> (potentially_unsafe: expression_t) -> (safe_substitution: expression_t) -> expression_t\n  | ExpressionInitialTid: expression_t\n  | ExpressionUniqsUsed: expression_t\n  | ExpressionStopReason: expression_t\n\nlet expression_to_td (exp: expression_t) : GTot object_td_t =\n  match exp with\n  | ExpressionConstant value -> object_value_to_td value\n  | ExpressionGlobalVariable td _ -> td\n  | ExpressionLocalVariable td _ -> td\n  | ExpressionUnaryOperator _ result_td _ _ -> result_td\n  | ExpressionBinaryOperator _ _ result_td _ _ _ -> result_td\n  | ExpressionIf td _ _ _ -> td\n  | ExpressionDereference td _ -> td\n  | ExpressionAddressOf obj -> ObjectTDPrimitive PrimitiveTDPointer\n  | ExpressionPointerOffset _ _ -> ObjectTDPrimitive PrimitiveTDPointer\n  | ExpressionFieldOf td _ _ -> td\n  | ExpressionAllocated _ -> ObjectTDPrimitive PrimitiveTDBool\n  | ExpressionApplyFunction td _ _ _ _ -> td\n  | ExpressionIfUndefined td _ _ -> td\n  | ExpressionInitialTid -> ObjectTDAbstract tid_t\n  | ExpressionUniqsUsed -> ObjectTDAbstract (list root_id_uniquifier_t)\n  | ExpressionStopReason -> ObjectTDAbstract stop_reason_t\n\nlet rec expressions_to_tds (exps: list expression_t) : GTot (list object_td_t) =\n  match exps with\n  | [] -> []\n  | first_exp :: remaining_exps -> (expression_to_td first_exp) :: (expressions_to_tds remaining_exps)\n\nlet rec types_to_tds (tys: list Type0) : (list object_td_t) =\n  match tys with\n  | [] -> []\n  | first_ty :: remaining_tys -> (ObjectTDAbstract first_ty) :: (types_to_tds remaining_tys)\n\nlet rec expression_valid (exp: expression_t) : GTot bool =\n  match exp with\n  | ExpressionConstant value -> object_value_valid value\n  | ExpressionGlobalVariable td _ -> true\n  | ExpressionLocalVariable td _ -> true\n  | ExpressionUnaryOperator operand_td result_td operator operand ->\n         expression_valid operand\n      && eqb (expression_to_td operand) operand_td\n  | ExpressionBinaryOperator operand_td1 operand_td2 result_td operator operand1 operand2 ->\n         expression_valid operand1\n      && expression_valid operand2\n      && eqb (expression_to_td operand1) operand_td1\n      && eqb (expression_to_td operand2) operand_td2\n  | ExpressionIf td cond operand_then operand_else ->\n         expression_valid cond\n      && expression_valid operand_then\n      && expression_valid operand_else\n      && eqb (expression_to_td cond) (ObjectTDPrimitive PrimitiveTDBool)\n      && eqb (expression_to_td operand_then) td\n      && eqb (expression_to_td operand_else) td\n  | ExpressionDereference td ptr ->\n         expression_valid ptr\n      && eqb (expression_to_td ptr) (ObjectTDPrimitive PrimitiveTDPointer)\n  | ExpressionAddressOf obj -> expression_valid obj\n  | ExpressionPointerOffset ptr offset ->\n         expression_valid ptr\n      && expression_valid offset\n      && eqb (expression_to_td ptr) (ObjectTDPrimitive PrimitiveTDPointer)\n      && eqb (expression_to_td offset) (ObjectTDAbstract int)\n  | ExpressionFieldOf td obj field_id ->\n         expression_valid obj\n      && ObjectTDStruct? (expression_to_td obj)\n      && 0 <= field_id\n      && field_id < length (ObjectTDStruct?.field_tds (expression_to_td obj))\n      && eqb td ((ObjectTDStruct?.field_tds (expression_to_td obj)) `index` field_id)\n  | ExpressionAllocated ptr ->\n         expression_valid ptr\n      && eqb (expression_to_td ptr) (ObjectTDPrimitive PrimitiveTDPointer)\n  | ExpressionApplyFunction td operands return_type operand_types _ ->\n         eqb td (ObjectTDAbstract return_type)\n      && eqb (expressions_to_tds operands) (types_to_tds operand_types)\n  | ExpressionIfUndefined td potentially_unsafe safe_substitution ->\n         eqb td (expression_to_td potentially_unsafe)\n      && eqb td (expression_to_td safe_substitution)\n  | ExpressionInitialTid -> true\n  | ExpressionUniqsUsed -> true\n  | ExpressionStopReason -> true\n\ntype valid_expression_t = value: expression_t{expression_valid value}\n\nlet rec apply_function_to_operands\n  (operands: list object_value_t)\n  (return_type: Type0)\n  (operand_types: list Type0)\n  (fn: build_function_type return_type operand_types)\n  : GTot (conditional_computation_t return_type) =\n  match operands, operand_types with\n  | [], [] -> fn\n  | first_operand :: remaining_operands, first_operand_type :: remaining_operand_types ->\n      (match first_operand with\n       | ObjectValueAbstract ty value ->\n           if eqb first_operand_type ty then\n             let fn_cast: first_operand_type -> GTot (build_function_type return_type remaining_operand_types) = fn in\n             apply_function_to_operands remaining_operands return_type remaining_operand_types (fn_cast value)\n           else\n             ComputationUndefined\n       | _ -> ComputationUndefined)\n  | _ -> ComputationImpossible\n\nlet rec rvalue_computation\n  (exp: expression_t)\n  (actor: tid_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t (valid_object_value_t (expression_to_td exp)))\n  (decreases exp) =\n  if not (expression_valid exp) then\n    ComputationImpossible\n  else\n    match exp with\n    | ExpressionConstant value -> return value\n    | ExpressionGlobalVariable td var_id ->\n        dereference_as_td_computation (PointerRoot (RootIdGlobal var_id)) td actor s.mem\n    | ExpressionLocalVariable td var_id ->\n        let thread = s.threads actor in\n        if not (list_contains var_id thread.top.local_variables) then\n          ComputationImpossible\n        else\n          dereference_as_td_computation\n            (PointerRoot (RootIdStack actor thread.top.method_id thread.top.frame_uniq var_id)) td actor s.mem\n    | ExpressionUnaryOperator operand_td result_td operator operand ->\n        let? operand_value = rvalue_computation operand actor s in\n        eval_unary_op operator operand_value\n    | ExpressionBinaryOperator operand_td1 operand_td2 result_td operator operand1 operand2 ->\n        let? operand_value1 = rvalue_computation operand1 actor s in\n        let? operand_value2 = rvalue_computation operand2 actor s in\n        eval_binary_op operator operand_value1 operand_value2\n    | ExpressionIf td cond operand_then operand_else ->\n        let? cond_value = rvalue_computation cond actor s in\n        let? operand_then_value = rvalue_computation operand_then actor s in\n        let? operand_else_value = rvalue_computation operand_else actor s in\n        let b = PrimitiveBoxBool?.b (ObjectValuePrimitive?.value cond_value) in\n        (ComputationProduces (if b then operand_then_value else operand_else_value))\n    | ExpressionDereference td ptr ->\n        let? ptr_value = rvalue_computation ptr actor s in\n        let p = PrimitiveBoxPointer?.ptr (ObjectValuePrimitive?.value ptr_value) in\n        dereference_as_td_computation p td actor s.mem\n    | ExpressionAddressOf obj ->\n        let? p = lvalue_computation obj actor s in\n        return (ObjectValuePrimitive (PrimitiveBoxPointer p) <: valid_object_value_t (expression_to_td exp))\n    | ExpressionPointerOffset ptr offset ->\n        let? ptr_value = rvalue_computation ptr actor s in\n        let? offset_value = rvalue_computation offset actor s in\n        let p = PrimitiveBoxPointer?.ptr (ObjectValuePrimitive?.value ptr_value) in\n        // It's undefined behavior to offset a pointer that doesn't point into an array,\n        // or to offset outside of the array, except exactly one past the end of the array\n        // (idx == array_len).  This is part of C semantics:  As described in\n        // https://en.cppreference.com/w/cpp/language/operator_arithmetic, \"Any\n        // other situations (that is, attempts to generate a pointer that isn't pointing\n        // at an element of the same array or one past the end) invoke undefined\n        // behavior.\"\n        (match p with\n         | PointerIndex array_ptr idx ->\n             let offset_int = ObjectValueAbstract?.value offset_value in\n             let? array_value = dereference_computation array_ptr s.mem in\n             (match array_value with\n              | ObjectStorageArray _ elements ->\n                  let new_idx: int = (idx <: int) + offset_int in\n                  // It's OK to be equal to `length elements` (one past the end), but not OK to be any higher\n                  if new_idx < 0 || new_idx > length elements then\n                    ComputationUndefined\n                  else\n                    let p' = PointerIndex array_ptr new_idx in\n                    let obj = ObjectValuePrimitive (PrimitiveBoxPointer p') in\n                    return (obj <: valid_object_value_t (expression_to_td exp))\n              | _ -> ComputationUndefined)\n         | _ -> ComputationUndefined)\n    | ExpressionFieldOf td obj field_id ->\n        let? obj_ptr = lvalue_computation obj actor s in\n        dereference_as_td_computation (PointerField obj_ptr field_id) td actor s.mem\n    | ExpressionAllocated ptr ->\n        let? ptr_value = rvalue_computation ptr actor s in\n        let p = PrimitiveBoxPointer?.ptr (ObjectValuePrimitive?.value ptr_value) in\n        return (ObjectValuePrimitive (PrimitiveBoxBool (p <> PointerUninitialized))\n                <: valid_object_value_t (expression_to_td exp))\n    | ExpressionApplyFunction td operands return_type operand_types fn ->\n        let? operand_values = rvalues_computation operands actor s in\n        let? value = apply_function_to_operands operand_values return_type operand_types fn in\n        let v: valid_object_value_t td = ObjectValueAbstract return_type value in\n        return v\n    | ExpressionIfUndefined td potentially_unsafe safe_substitution ->\n        (match rvalue_computation potentially_unsafe actor s with\n         | ComputationImpossible -> ComputationImpossible\n         | ComputationUndefined -> rvalue_computation safe_substitution actor s\n         | ComputationProduces value -> return value)\n    | ExpressionInitialTid ->\n        return (ObjectValueAbstract tid_t s.initial_tid)\n    | ExpressionUniqsUsed ->\n        return (ObjectValueAbstract (list root_id_uniquifier_t) s.uniqs_used)\n    | ExpressionStopReason ->\n        return (ObjectValueAbstract stop_reason_t s.stop_reason)\n\nand lvalue_computation\n  (exp: expression_t)\n  (actor: tid_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.Pointer.t) =\n  if not (expression_valid exp) then\n    ComputationImpossible\n  else\n    match exp with\n    | ExpressionGlobalVariable _ var_id -> return (PointerRoot (RootIdGlobal var_id))\n    | ExpressionLocalVariable _ var_id ->\n        let thread = s.threads actor in\n        if not (list_contains var_id thread.top.local_variables) then\n          ComputationImpossible\n        else\n          return (PointerRoot (RootIdStack actor thread.top.method_id thread.top.frame_uniq var_id))\n    | ExpressionDereference _ ptr ->\n        let? ptr_value = rvalue_computation ptr actor s in\n        return (PrimitiveBoxPointer?.ptr (ObjectValuePrimitive?.value ptr_value))\n    | ExpressionFieldOf td obj field_id ->\n        let? obj_ptr = lvalue_computation obj actor s in\n        return (PointerField obj_ptr field_id)\n    | _ -> ComputationImpossible\n\nand rvalues_computation\n  (exps: list expression_t)\n  (actor: tid_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t (list object_value_t)) =\n  match exps with\n  | [] -> return []\n  | first_exp :: remaining_exps ->\n      let? first_value = rvalue_computation first_exp actor s in\n      let? remaining_values = rvalues_computation remaining_exps actor s in\n      return (first_value :: remaining_values)\n\nlet append_to_thread_write_buffer\n  (threads: Armada.Threads.t)\n  (actor: tid_t)\n  (write_message: write_message_t)\n  : GTot Armada.Threads.t =\n  let thread = threads actor in\n  let write_buffer' = build thread.write_buffer write_message in\n  let thread' = { thread with write_buffer = write_buffer' } in\n  Spec.Map.upd threads actor thread'\n\nlet update_pointed_to_value\n  (p: Armada.Pointer.t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (new_value: object_value_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  match update_pointer p actor writer_pc writer_expression_number bypassing_write_buffer new_value s.mem with\n  | ComputationImpossible -> ComputationImpossible\n  | ComputationUndefined -> ComputationUndefined\n  | ComputationProduces (optional_write_message, mem') ->\n      (match optional_write_message with\n       | Some write_message ->\n           let threads' = append_to_thread_write_buffer s.threads actor write_message in\n           let s' = { s with mem = mem'; threads = threads' } in\n           return s'\n       | None ->\n           let s' = { s with mem = mem' }\n           in return s'\n      )\n\nlet update_expression\n  (exp: expression_t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (new_value: object_value_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  if   not (expression_valid exp)\n     || not (object_value_valid new_value)\n     || neqb (object_value_to_td new_value) (expression_to_td exp) then\n    ComputationImpossible\n  else (\n    let? p = lvalue_computation exp actor s in\n    update_pointed_to_value p actor writer_pc writer_expression_number bypassing_write_buffer new_value s\n  )\n\nlet rec update_expressions\n  (exps: list expression_t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (new_values: list object_value_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  match exps, new_values with\n  | [], [] -> return s\n  | first_exp :: remaining_exps, first_new_value :: remaining_new_values ->\n      let? s' = update_expression first_exp actor writer_pc writer_expression_number\n              bypassing_write_buffer first_new_value s in\n      update_expressions remaining_exps actor writer_pc (writer_expression_number + 1)\n        bypassing_write_buffer remaining_new_values s'\n  | _ -> ComputationImpossible\n\nlet check_expression_up_to_date_for_rmw\n  (exp: expression_t)\n  (actor: tid_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t unit) =\n  if not (expression_valid exp) then\n    ComputationImpossible\n  else (\n    let? p = lvalue_computation exp actor s in\n    let? storage = dereference_computation p s.mem in\n    if object_storage_up_to_date_for_rmw_operation storage actor then\n      return ()\n    else\n      ComputationImpossible\n  )\n\nlet expression_corresponds_to_value\n  (actor: tid_t)\n  (s: Armada.State.t)\n  (exp: expression_t)\n  (value: object_value_t)\n  : GTot bool =\n     expression_valid exp\n  && object_value_valid value\n  && eqb (object_value_to_td value) (expression_to_td exp)\n  && eqb (rvalue_computation exp actor s) (return value)\n\nlet rec rvalues_computation_facts\n  (exps: list expression_t)\n  (actor: tid_t)\n  (s: Armada.State.t)\n  : Lemma (match rvalues_computation exps actor s with\n           | ComputationImpossible ->\n                exists (exp: expression_t).\n                  contains_ubool exp exps /\\ ComputationImpossible? (rvalue_computation exp actor s)\n           | ComputationUndefined ->\n                exists (exp: valid_expression_t).\n                  contains_ubool exp exps /\\ ComputationUndefined? (rvalue_computation exp actor s)\n           | ComputationProduces values ->\n               lists_correspond (expression_corresponds_to_value actor s) exps values) =\n  match exps with\n  | [] -> ()\n  | first_exp :: remaining_exps ->\n      (match rvalue_computation first_exp actor s with\n       | ComputationImpossible -> ()\n       | ComputationUndefined -> ()\n       | ComputationProduces first_value -> rvalues_computation_facts remaining_exps actor s)\n"
  },
  {
    "path": "experimental/lib/Armada.Globals.fst",
    "content": "module Armada.Globals\n\ntype var_index = nat\n\ntype t = Spec.Map.t var_index (option int)\n"
  },
  {
    "path": "experimental/lib/Armada.Init.fst",
    "content": "module Armada.Init\n\nopen Armada.Base\nopen Armada.Computation\nopen Armada.Expression\nopen Armada.Memory\nopen Armada.Pointer\nopen Armada.State\nopen Armada.Thread\nopen Armada.Type\nopen FStar.Sequence.Base\nopen Spec.List\nopen Spec.Map\nopen Spec.Ubool\n\n/////////////////////////\n// Initializer values\n/////////////////////////\n\nnoeq type initializer_value_t =\n  | InitializerArbitrary: (td: object_td_t) -> initializer_value_t\n  | InitializerSpecific: (value: object_value_t) -> initializer_value_t\n\nnoeq type initializer_t = {\n  var_id: var_id_t;\n  iv: initializer_value_t;\n  weakly_consistent: bool;\n}\n\nlet storage_satisfies_initializer_value (storage: valid_object_storage_t) (initializer: initializer_value_t)\n  : GTot bool =\n  match initializer with\n  | InitializerArbitrary td ->\n         object_storage_arbitrarily_initialized_correctly storage\n      && eqb (object_storage_to_td storage) td\n  | InitializerSpecific value ->\n         object_storage_initialized_correctly storage value\n      && eqb (object_storage_to_td storage) (object_value_to_td value)\n\nlet storage_satisfies_initializer_value_type (storage: valid_object_storage_t) (initializer: initializer_value_t)\n  : GTot bool =\n  match initializer with\n  | InitializerArbitrary td ->\n      eqb (object_storage_to_td storage) td\n  | InitializerSpecific value ->\n      eqb (object_storage_to_td storage) (object_value_to_td value)\n\n////////////////////////////\n// Global initialization\n////////////////////////////\n\nlet storage_satisfies_initializer\n  (storage: valid_object_storage_t)\n  (iv: initializer_value_t)\n  (weakly_consistent: bool)\n  : GTot bool =\n     storage_satisfies_initializer_value storage iv\n  && (if weakly_consistent then\n        is_object_storage_weakly_consistent storage\n      else\n        is_object_storage_strongly_consistent storage)\n\nlet memory_satisfies_global_initializer\n  (mem: Armada.Memory.t)\n  (initializer: initializer_t)\n  : GTot ubool =\n  let root = mem (RootIdGlobal initializer.var_id) in\n  match root with\n  | RootGlobal storage ->\n      storage_satisfies_initializer storage initializer.iv initializer.weakly_consistent\n  | _ -> False\n\nlet memory_satisfies_global_initializers\n  (mem: Armada.Memory.t)\n  (initializers: list initializer_t)\n  : GTot ubool =\n  forall init. contains_ubool init initializers ==> memory_satisfies_global_initializer mem init\n\n///////////////////////////////\n// Stack frame initialization\n///////////////////////////////\n\nlet stack_root_satisfies_main_stack_initializer\n  (initializer: initializer_t)\n  (root: root_t)\n  : GTot bool =\n  match root with\n  | RootStackVariable pushed popped storage ->\n         pushed\n      && not popped\n      && storage_satisfies_initializer storage initializer.iv initializer.weakly_consistent\n  | _ -> false\n\nlet memory_satisfies_main_stack_initializer\n  (mem: Armada.Memory.t)\n  (tid: tid_t)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (var_id: var_id_t)\n  (initializer: initializer_t)\n  : GTot bool =\n     var_id = initializer.var_id\n  && (let root_id = RootIdStack tid method_id frame_uniq var_id in\n      let root = mem root_id in\n      stack_root_satisfies_main_stack_initializer initializer root)\n\nlet rec memory_satisfies_main_stack_initializers\n  (mem: Armada.Memory.t)\n  (tid: tid_t)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (var_ids: list var_id_t)\n  (initializers: list initializer_t)\n  : GTot bool =\n  match var_ids, initializers with\n  | [], [] -> true\n  | var_id :: remaining_var_ids, initializer :: remaining_initializers ->\n         memory_satisfies_main_stack_initializer mem tid method_id frame_uniq var_id initializer\n      && memory_satisfies_main_stack_initializers mem tid method_id frame_uniq\n           remaining_var_ids remaining_initializers\n  | _ -> false\n\nlet storage_satisfies_initializer_type (storage: valid_object_storage_t) (initializer: initializer_t) : GTot bool =\n     storage_satisfies_initializer_value_type storage initializer.iv\n  && (if initializer.weakly_consistent then\n        is_object_storage_weakly_consistent storage\n      else\n        is_object_storage_strongly_consistent storage)\n\nlet stack_variable_ready_for_push\n  (root: root_t)\n  (initializer: initializer_t)\n  : GTot bool =\n  match root with\n  | RootStackVariable pushed popped storage ->\n         not pushed\n      && not popped\n      && storage_satisfies_initializer_type storage initializer\n      && object_storage_arbitrarily_initialized_correctly storage\n  | _ -> false\n\nlet push_stack_variable\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (initializer: initializer_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  let root_id = RootIdStack actor method_id frame_uniq initializer.var_id in\n  let root = s.mem root_id in\n  if not (stack_variable_ready_for_push root initializer) then\n    ComputationImpossible\n  else\n    let thread = s.threads actor in\n    let var_id = initializer.var_id in\n    if list_contains var_id thread.top.local_variables then\n      ComputationImpossible\n    else\n      let local_variables' = var_id :: thread.top.local_variables in\n      let top' = { thread.top with local_variables = local_variables' } in\n      let thread' = { thread with top = top' } in\n      let threads' = upd s.threads actor thread' in\n      let root' = RootStackVariable true false (RootStackVariable?.storage root) in\n      let mem' = Spec.Map.upd s.mem root_id root' in\n      let s' = { s with mem = mem'; threads = threads' } in\n      (match initializer.iv with\n       | InitializerArbitrary td -> return s'\n       | InitializerSpecific value ->\n           let td = (object_value_to_td value) in\n           update_expression (ExpressionLocalVariable td var_id) actor writer_pc writer_expression_number\n             false value s')\n\nlet rec push_stack_variables\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (initializers: list initializer_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t)\n    (decreases initializers) =\n  match initializers with\n  | [] -> return s\n  | first_initializer :: remaining_initializers ->\n      let? s' = push_stack_variable actor writer_pc writer_expression_number method_id frame_uniq first_initializer s in\n      push_stack_variables actor writer_pc (writer_expression_number + 1) method_id frame_uniq remaining_initializers s'\n  | _ -> ComputationImpossible\n\nlet rec push_stack_parameters\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (var_ids: list var_id_t)\n  (parameters: list object_value_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t)\n    (decreases parameters) =\n  match parameters, var_ids with\n  | [], [] -> return s\n  | first_parameter :: remaining_parameters, first_var_id :: remaining_var_ids ->\n      let first_initializer =\n        { var_id = first_var_id; iv = InitializerSpecific first_parameter; weakly_consistent = false } in\n      let? s' = push_stack_variable actor writer_pc writer_expression_number method_id frame_uniq first_initializer s in\n      push_stack_parameters actor writer_pc (writer_expression_number + 1) method_id frame_uniq remaining_var_ids\n        remaining_parameters s'\n  | _ -> ComputationImpossible\n\n///////////////////////////////\n// Fence initialization\n///////////////////////////////\n\nlet initial_fence_storage: valid_object_storage_t =\n  ObjectStorageWeaklyConsistentPrimitive PrimitiveTDBool (singleton (PrimitiveBoxBool false)) (Spec.Map.const 0)\n\n////////////////////////////////////////\n// Making uninitalized memory invalid\n////////////////////////////////////////\n\nlet var_id_in_initializer\n  (var_id: var_id_t)\n  (initializer: initializer_t)\n  : GTot bool =\n  initializer.var_id = var_id\n\nlet root_invalid_outside_initializations\n  (mem: Armada.Memory.t)\n  (global_initializers: list initializer_t)\n  (initial_tid: tid_t)\n  (main_method_id: method_id_t)\n  (initial_frame_uniq: root_id_uniquifier_t)\n  (local_stack_variables: list var_id_t)\n  (root_id: root_id_t)\n  : ubool =\n  match mem root_id with\n  | RootGlobal _ ->\n      (match root_id with\n       | RootIdGlobal var_id -> exists init. contains_ubool init global_initializers /\\ var_id_in_initializer var_id init \n       | _ -> False)\n  | RootStackVariable pushed popped storage ->\n      (match root_id with\n       | RootIdStack tid method_id frame_uniq var_id ->\n           pushed ==> (   tid = initial_tid\n                       /\\ method_id = main_method_id\n                       /\\ frame_uniq = initial_frame_uniq\n                       /\\ list_contains var_id local_stack_variables)\n       | _ -> False)\n  | RootAllocated allocated freed storage -> RootIdAllocation? root_id /\\ not allocated\n  | RootFence storage -> RootIdFence? root_id\n  | RootInvalid -> True\n\nlet memory_invalid_outside_initializations\n  (mem: Armada.Memory.t)\n  (global_initializers: list initializer_t)\n  (initial_tid: tid_t)\n  (main_method_id: method_id_t)\n  (initial_frame_uniq: root_id_uniquifier_t)\n  (local_stack_variables: list var_id_t)\n  : GTot ubool =\n  forall root_id. root_invalid_outside_initializations mem global_initializers initial_tid\n               main_method_id initial_frame_uniq local_stack_variables root_id\n"
  },
  {
    "path": "experimental/lib/Armada.Memory.fst",
    "content": "module Armada.Memory\n\nopen Armada.Base\nopen Armada.Computation\nopen Armada.Pointer\nopen Armada.Thread\nopen Armada.Type\nopen FStar.Sequence.Base\nopen Spec.Ubool\nopen Util.Seq\n\nnoeq type object_storage_t =\n  | ObjectStorageWeaklyConsistentPrimitive:\n      (primitive_td: primitive_td_t) ->\n      (values: seq primitive_box_t) ->\n      (local_versions: Spec.Map.t tid_t nat) ->\n      object_storage_t\n  | ObjectStoragePrimitive: (value: primitive_box_t) -> object_storage_t\n  | ObjectStorageStruct: (fields: seq object_storage_t) -> object_storage_t\n  | ObjectStorageArray: (element_td: object_td_t) -> (elements: seq object_storage_t) -> object_storage_t\n  | ObjectStorageAbstract: (ty: Type) -> (value: ty) -> object_storage_t\n\nlet rec object_storage_to_td (storage: object_storage_t) : GTot object_td_t (decreases rank storage) =\n  match storage with\n  | ObjectStorageWeaklyConsistentPrimitive primitive_td _ _ -> ObjectTDPrimitive primitive_td\n  | ObjectStoragePrimitive value -> ObjectTDPrimitive (primitive_box_to_td value)\n  | ObjectStorageStruct fields -> ObjectTDStruct (map_refine object_storage_to_td fields)\n  | ObjectStorageArray element_td elements -> ObjectTDArray element_td (length elements)\n  | ObjectStorageAbstract ty _ -> ObjectTDAbstract ty\n\nlet object_storage_to_td_equivalent_to_map (storage: object_storage_t)\n  : Lemma (ensures (let td = object_storage_to_td storage in\n                    match storage with\n                    | ObjectStorageStruct fields -> td == ObjectTDStruct (map object_storage_to_td fields)\n                    | _ -> True))\n          [SMTPat (object_storage_to_td storage)] =\n  let td = object_storage_to_td storage in\n  match storage with\n  | ObjectStorageStruct fields ->\n      assert (equal (ObjectTDStruct?.field_tds td) (map object_storage_to_td fields))\n  | _ -> ()\n\nlet rec object_storage_valid (storage: object_storage_t) : GTot bool (decreases rank storage) =\n  match storage with\n  | ObjectStorageWeaklyConsistentPrimitive primitive_td values local_versions ->\n         u2b (forall tid.{:pattern local_versions tid} local_versions tid < length values)\n      && u2b (forall value.{:pattern contains values value} contains values value ==> primitive_box_matches_primitive_td value primitive_td)\n  | ObjectStoragePrimitive value -> true\n  | ObjectStorageStruct fields ->\n      u2b (forall field.{:pattern contains fields field} contains fields field ==> object_storage_valid field)\n  | ObjectStorageArray element_td elements ->\n      u2b (forall element.{:pattern contains elements element} contains elements element ==>\n             object_storage_valid element /\\ object_storage_to_td element == element_td)\n  | ObjectStorageAbstract _ _ -> true\n\nlet valid_object_storage_t = (storage: object_storage_t{object_storage_valid storage})\n\nlet rec object_storage_to_value (actor: tid_t) (storage: object_storage_t)\n  : GTot object_value_t (decreases rank storage) =\n  match storage with\n  | ObjectStorageWeaklyConsistentPrimitive _ values local_versions ->\n      let version = local_versions actor in\n      if version < length values then\n        ObjectValuePrimitive (index values version)\n      else\n        ObjectValueAbstract bool false\n  | ObjectStoragePrimitive value -> ObjectValuePrimitive value\n  | ObjectStorageStruct fields -> ObjectValueStruct (map_refine (object_storage_to_value actor) fields)\n  | ObjectStorageArray element_td elements -> ObjectValueArray element_td (map_refine (object_storage_to_value actor) elements)\n  | ObjectStorageAbstract ty value -> ObjectValueAbstract ty value\n\nlet rec object_storage_to_value_preserves_td\n  (actor: tid_t)\n  (storage: valid_object_storage_t)\n  : Lemma (ensures (let value = object_storage_to_value actor storage in\n                      object_value_to_td value == object_storage_to_td storage\n                    /\\ object_value_valid value))\n          (decreases rank storage) =\n  match storage with\n  | ObjectStorageWeaklyConsistentPrimitive primitive_td values local_versions ->\n      let version = local_versions actor in\n      assert (contains values (index values version))\n  | ObjectStoragePrimitive _ -> ()\n  | ObjectStorageStruct fields ->\n      let value = object_storage_to_value actor storage in\n      let td = object_storage_to_td storage in\n      let field_tds = (ObjectTDStruct?.field_tds td) in\n      (match value with\n       | ObjectValueStruct value_fields ->\n           introduce forall (i: nat). i < length fields ==>\n                         object_value_to_td (index value_fields i) == index field_tds i\n                       /\\ object_value_valid (index value_fields i)\n           with introduce _ ==> _\n           with given_antecedent. (\n             assert (contains fields (index fields i));\n             object_storage_to_value_preserves_td actor (index fields i)\n           );\n           (match object_value_to_td (object_storage_to_value actor storage) with\n            | ObjectTDStruct field_tds' -> assert (equal field_tds' field_tds)))\n  | ObjectStorageArray element_td elements ->\n      let value = object_storage_to_value actor storage in\n      (match value with\n       | ObjectValueArray _ value_elements ->\n          introduce forall (i: nat). i < length elements ==>\n                        object_value_to_td (index value_elements i) == element_td\n                      /\\ object_value_valid (index value_elements i)\n          with introduce _ ==> _\n          with given_antecedent. (\n            assert (contains elements (index elements i));\n            assert (index elements i << elements);\n            object_storage_to_value_preserves_td actor (index elements i)\n          )\n      )\n  | ObjectStorageAbstract ty value -> ()\n\nlet object_storage_to_value_preserves_validity\n  (actor: tid_t)\n  (storage: valid_object_storage_t)\n  : Lemma (ensures object_value_valid (object_storage_to_value actor storage))\n          (decreases rank storage) =\n  object_storage_to_value_preserves_td actor storage\n\nlet object_storage_to_value_equivalent_to_map (actor: tid_t) (storage: object_storage_t)\n  : Lemma (ensures (let value = object_storage_to_value actor storage in\n                    match storage with\n                    | ObjectStorageStruct fields ->\n                        value == ObjectValueStruct (map (object_storage_to_value actor) fields)\n                    | ObjectStorageArray element_td elements ->\n                        value == ObjectValueArray element_td (map (object_storage_to_value actor) elements)\n                    | _ -> True))\n          [SMTPat (object_storage_to_value actor storage)] =\n  let value = object_storage_to_value actor storage in\n  match storage with\n  | ObjectStorageStruct fields ->\n      assert (equal (ObjectValueStruct?.fields value) (map (object_storage_to_value actor) fields))\n  | ObjectStorageArray element_td elements ->\n      assert (equal (ObjectValueArray?.elements value) (map (object_storage_to_value actor) elements))\n  | _ -> ()\n\nlet object_storage_up_to_date_for_rmw_operation (storage: object_storage_t) (tid: tid_t) : GTot bool =\n  match storage with\n  | ObjectStorageWeaklyConsistentPrimitive primitive_td values local_versions ->\n      let version_id = local_versions tid in\n      eqb version_id (length values - 1)\n  | _ -> true\n\nlet rec object_value_to_storage (value: object_value_t) : GTot object_storage_t (decreases rank value) =\n  match value with\n  | ObjectValuePrimitive value -> ObjectStoragePrimitive value\n  | ObjectValueStruct fields -> ObjectStorageStruct (map_refine object_value_to_storage fields)\n  | ObjectValueArray element_td elements ->\n      ObjectStorageArray element_td (map_refine object_value_to_storage elements)\n  | ObjectValueAbstract ty v -> ObjectStorageAbstract ty v\n\nlet rec object_value_to_storage_preserves_validity (value: object_value_t)\n  : Lemma (requires object_value_valid value)\n          (ensures    object_storage_valid (object_value_to_storage value)\n                    /\\ (object_storage_to_td (object_value_to_storage value)) == (object_value_to_td value))\n          (decreases rank value) =\n  match value with\n  | ObjectValuePrimitive value -> ()\n  | ObjectValueStruct fields ->\n      let storage = object_value_to_storage value in\n      let td = object_value_to_td value in\n      let field_tds = (ObjectTDStruct?.field_tds td) in\n      (match storage with\n       | ObjectStorageStruct storage_fields ->\n           introduce forall (i: nat). i < length fields ==>\n                         object_storage_to_td (index storage_fields i) == index field_tds i\n                       /\\ object_storage_valid (index storage_fields i)\n           with introduce _ ==> _\n           with given_antecedent. (\n             assert (contains fields (index fields i));\n             object_value_to_storage_preserves_validity (index fields i)\n           );\n           (match object_storage_to_td (object_value_to_storage value) with\n            | ObjectTDStruct field_tds' -> assert (equal field_tds' field_tds)\n           ))\n  | ObjectValueArray element_td elements ->\n      let storage = object_value_to_storage value in\n      (match storage with\n       | ObjectStorageArray _ storage_elements ->\n          introduce forall (i: nat). i < length elements ==>\n                        object_storage_to_td (index storage_elements i) == element_td\n                      /\\ object_storage_valid (index storage_elements i)\n          with introduce _ ==> _\n          with given_antecedent. (\n            assert (contains elements (index elements i));\n            object_value_to_storage_preserves_validity (index elements i)\n          ))\n  | ObjectValueAbstract ty v -> ()\n\nlet rec object_value_has_all_pointers_uninitialized (value: object_value_t)\n  : GTot bool =\n  match value with\n  | ObjectValuePrimitive primitive_value ->\n      (match primitive_value with\n       | PrimitiveBoxPointer ptr -> PointerUninitialized? ptr\n       | _ -> true)\n  | ObjectValueStruct fields ->\n      assert (forall field. contains fields field ==> rank field << rank fields);\n      u2b (forall field. contains fields field ==> object_value_has_all_pointers_uninitialized field)\n  | ObjectValueArray element_td elements ->\n      assert (forall element. contains elements element ==> rank element << rank elements);\n      u2b (forall element. contains elements element ==> object_value_has_all_pointers_uninitialized element)\n  | ObjectValueAbstract ty _ -> true\n\nlet rec object_storage_arbitrarily_initialized_correctly (storage: object_storage_t)\n  : GTot bool (decreases rank storage) =\n  match storage with\n  | ObjectStorageWeaklyConsistentPrimitive _ values local_versions ->\n         length values = 1\n      && u2b (forall tid. local_versions tid = 0)\n      && (match index values 0 with\n          | PrimitiveBoxPointer ptr -> PointerUninitialized? ptr\n          | _ -> true)\n  | ObjectStoragePrimitive primitive_value ->\n      (match primitive_value with\n       | PrimitiveBoxPointer ptr -> PointerUninitialized? ptr\n       | _ -> true)\n  | ObjectStorageStruct fields ->\n      assert (forall field. contains fields field ==> rank field << rank fields);\n      u2b (forall field. contains fields field ==> object_storage_arbitrarily_initialized_correctly field)\n  | ObjectStorageArray element_td elements ->\n      assert (forall element. contains elements element ==> rank element << rank elements);\n      u2b (forall element. contains elements element ==> object_storage_arbitrarily_initialized_correctly element)\n  | ObjectStorageAbstract ty value -> true\n\nlet rec object_storage_initialized_correctly (storage: object_storage_t) (value: object_value_t)\n  : GTot bool (decreases rank storage) =\n  match storage with\n  | ObjectStorageWeaklyConsistentPrimitive _ values local_versions ->\n      (match value with\n       | ObjectValuePrimitive primitive_value ->\n              eqb values (singleton primitive_value)\n           && u2b (forall tid. local_versions tid = 0)\n       | _ -> false)\n  | ObjectStoragePrimitive primitive_value ->\n      eqb value (ObjectValuePrimitive primitive_value)\n  | ObjectStorageStruct fields ->\n      assert (forall field. contains fields field ==> rank field << rank fields);\n      (match value with\n       | ObjectValueStruct field_values ->\n             length fields = length field_values\n           && u2b (forall (i: nat). i < length fields ==>\n                             object_storage_initialized_correctly (index fields i) (index field_values i))\n       | _ -> false)\n  | ObjectStorageArray element_td elements ->\n      assert (forall element. contains elements element ==> rank element << rank elements);\n      (match value with\n       | ObjectValueArray element_td' element_values ->\n             length elements = length element_values\n           && eqb element_td' element_td\n           && u2b (forall (i: nat). i < length elements ==>\n                     object_storage_initialized_correctly (index elements i) (index element_values i))\n       | _ -> false)\n  | ObjectStorageAbstract ty value' -> eqb value (ObjectValueAbstract ty value')\n\nlet rec is_object_storage_weakly_consistent (storage: object_storage_t) : GTot bool =\n  match storage with\n  | ObjectStorageWeaklyConsistentPrimitive _ _ _ -> true\n  | ObjectStoragePrimitive _ -> false\n  | ObjectStorageStruct fields -> u2b (forall field. contains fields field ==> is_object_storage_weakly_consistent field)\n  | ObjectStorageArray _ elements -> u2b (forall element. contains elements element ==>\n                                                    is_object_storage_weakly_consistent element)\n  | ObjectStorageAbstract _ _ -> false\n\nlet rec is_object_storage_strongly_consistent (obj: object_storage_t) : GTot bool =\n  match obj with\n  | ObjectStorageWeaklyConsistentPrimitive _ _ _ -> false\n  | ObjectStoragePrimitive _ -> true\n  | ObjectStorageStruct fields -> u2b (forall field. contains fields field ==>\n                                               is_object_storage_strongly_consistent field)\n  | ObjectStorageArray _ elements -> u2b (forall element. contains elements element ==>\n                                                    is_object_storage_strongly_consistent element)\n  | ObjectStorageAbstract _ _ -> true\n\nnoeq type root_t =\n  | RootGlobal: (storage: valid_object_storage_t) -> root_t\n  | RootStackVariable: (pushed: bool) -> (popped: bool) -> (storage: valid_object_storage_t) -> root_t\n  | RootAllocated: (allocated: bool) -> (freed: bool) -> (storage: valid_object_storage_t) -> root_t\n  | RootFence: (storage: valid_object_storage_t) -> root_t\n  | RootInvalid: root_t\n\ntype t = Spec.Map.t root_id_t root_t\n\nlet root_to_storage_computation (root: root_t) : GTot (conditional_computation_t valid_object_storage_t) =\n  match root with\n  | RootGlobal storage -> return storage\n  | RootStackVariable pushed popped storage ->\n      if not pushed then ComputationImpossible else if popped then ComputationUndefined else return storage\n  | RootAllocated allocated freed storage ->\n      if not allocated then ComputationImpossible else if freed then ComputationUndefined else return storage\n  | RootFence storage -> return storage\n  | RootInvalid -> ComputationImpossible\n\nlet update_root_storage (root: root_t) (new_storage: valid_object_storage_t) : root_t =\n  match root with\n  | RootGlobal storage -> RootGlobal new_storage\n  | RootStackVariable pushed popped storage -> RootStackVariable pushed popped new_storage\n  | RootAllocated allocated freed storage -> RootAllocated allocated freed new_storage\n  | RootFence storage -> RootFence new_storage\n  | RootInvalid -> RootInvalid\n\n/// There are four ways to trigger undefined behavior when\n/// dereferencing a pointer.\n///\n/// 1) Have the pointer be null-based (e.g., if p == NULL, then access\n///    *p or *p.f or *p[3] or *p.f1.f2[7][42])\n///\n/// 2) Have the pointer be based on an uninitalized pointer.\n///\n/// 3) Have the pointer be based on an allocated, freed heap root.\n///    (The state-machine translator won't let you access a\n///    not-yet-allocated part of the heap, so it's not possible to\n///    trigger undefined behavior by accessing a non-yet-allocated\n///    part of the heap.)\n/// \n/// 4) Have the pointer be correctly typed when ignoring array bounds\n///    but incorrectly typed when considering array bounds.  (The\n///    state-machine translator won't let you access non-existent\n///    struct fields, so it's not possible to manifest undefined\n///    behavior by having the pointer be incorrectly typed when\n///    ignoring array bounds.)\n\n/// On the other hand, there are various invalid ways to dereference a\n/// pointer that don't trigger undefined behavior because the\n/// state-machine translation process prevents them from happening.\n/// So the following cases are presumed to be impossible:\n///\n/// 1) Dereferencing a pointer based on a non-null, initialized\n///    pointer to a not-yet-allocated root.  There's no way to assign\n///    the value of such a pointer to any variable or derive it in an\n///    expression.\n/// \n/// 2) Dereferencing a pointer using a struct field ID that's >= the\n///    number of fields in the pointed-to struct.  The state-machine\n///    translator knows the type of every pointer, including what kind\n///    of struct it points to and what fields that struct has.\n///\n/// 3) Dereferencing a non-null pointer that doesn't match the heap's\n///    structure.  After all, the state-machine translator knows the\n///    type of every pointer and doesn't allow casting.\n///\n/// 4) Dereferencing a pointer that matches the heap structure but for\n///    which the heap has a dynamic value of the wrong type.  After\n///    all, the state-machine translator won't generate a program that\n///    ever stores something of one type into a location of a\n///    different type.\n\nlet rec dereference_computation (p: Armada.Pointer.t) (mem: t)\n  : GTot (conditional_computation_t valid_object_storage_t) =\n  match p with\n  | PointerUninitialized -> ComputationUndefined\n  | PointerNull -> ComputationUndefined\n  | PointerRoot root_id ->\n      let root = mem root_id in\n      root_to_storage_computation root\n  | PointerField struct_ptr field_id ->\n      let? parent = dereference_computation struct_ptr mem in\n      (match parent with\n       | ObjectStorageStruct fields ->\n           if field_id >= length fields then\n             ComputationImpossible\n           else\n             let field = index fields field_id in\n             if not (object_storage_valid field) then\n               ComputationImpossible\n             else\n               return (field <: valid_object_storage_t)\n       | _ -> ComputationImpossible)\n  | PointerIndex array_ptr idx ->\n      let? parent = dereference_computation array_ptr mem in\n      (match parent with\n       | ObjectStorageArray _ elements ->\n           if idx < 0 || idx >= length elements then\n             ComputationUndefined\n           else\n             let element = index elements idx in\n             if not (object_storage_valid element) then\n               ComputationImpossible\n             else\n               return (element <: valid_object_storage_t)\n       | _ -> ComputationImpossible)\n\nlet dereference_as_td_computation (p: Armada.Pointer.t) (td: object_td_t) (actor: tid_t) (mem: t)\n  : GTot (conditional_computation_t (valid_object_value_t td)) =\n  let? storage = dereference_computation p mem in\n  object_storage_to_value_preserves_validity actor storage;\n  let value = object_storage_to_value actor storage in\n  if eqb (object_value_to_td value) td then\n    return (object_storage_to_value actor storage <: valid_object_value_t td)\n  else\n    ComputationImpossible\n\nlet can_update_storage_child\n  (storage: valid_object_storage_t)\n  (idx: nat)\n  (new_child: valid_object_storage_t)\n  : GTot bool =\n  match storage with\n  | ObjectStorageStruct fields ->\n        idx < length fields\n     && eqb (object_storage_to_td new_child) (object_storage_to_td (index fields idx))\n  | ObjectStorageArray element_td elements ->\n        idx < length elements\n     && eqb (object_storage_to_td new_child) element_td\n  | _ -> false\n\n#push-options \"--z3cliopt smt.qi.eager_threshold=100\"\n\nlet update_storage_child\n  (storage: valid_object_storage_t)\n  (idx: nat)\n  (new_child: valid_object_storage_t{can_update_storage_child storage idx new_child})\n  : GTot valid_object_storage_t =\n  match storage with\n  | ObjectStorageStruct fields ->\n      let td = object_storage_to_td storage in\n      let field_tds = ObjectTDStruct?.field_tds td in\n      let fields' = update fields idx new_child in\n      let storage' = ObjectStorageStruct fields' in\n      let td' = object_storage_to_td storage' in\n      let field_tds' = ObjectTDStruct?.field_tds td' in\n      assert (equal field_tds field_tds');\n      assert (forall field. contains fields field ==> object_storage_valid field);\n      storage'\n  | ObjectStorageArray element_td elements ->\n      let elements' = update elements idx new_child in\n      let storage' = ObjectStorageArray element_td elements' in\n      assert (forall element. contains elements element ==>\n                object_storage_valid element /\\ object_storage_to_td element == element_td);\n      storage'\n\n#pop-options\n\nlet update_storage\n  (p: Armada.Pointer.t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (storage: valid_object_storage_t)\n  (new_value: object_value_t)\n  : GTot (conditional_computation_t (option write_message_t * valid_object_storage_t))\n    (decreases rank storage) =\n  match storage with\n  | ObjectStorageWeaklyConsistentPrimitive primitive_td values local_versions ->\n      (match new_value with\n       | ObjectValuePrimitive new_box ->\n           if not (primitive_box_matches_primitive_td new_box primitive_td) then\n             ComputationImpossible\n           else\n             let new_version_id = length values in\n             let new_values = build values new_box in\n             if bypassing_write_buffer then\n               let new_local_versions = Spec.Map.const new_version_id in\n               let new_storage = ObjectStorageWeaklyConsistentPrimitive primitive_td new_values\n                                   new_local_versions in\n               return (None, new_storage)\n             else\n               let new_local_versions = Spec.Map.upd local_versions actor new_version_id in\n               let new_storage = ObjectStorageWeaklyConsistentPrimitive primitive_td new_values\n                                   new_local_versions in\n               let write_message = {\n                 location = p;\n                 primitive_td = primitive_td;\n                 version = new_version_id;\n                 writer_pc = writer_pc;\n                 writer_expression_number = writer_expression_number\n               } in\n               if not (object_storage_valid new_storage) then\n                 ComputationImpossible\n               else\n                 return (Some write_message, new_storage)\n       | _ -> ComputationImpossible)\n  | ObjectStoragePrimitive value ->\n      (match new_value with\n       | ObjectValuePrimitive new_box ->\n           if (primitive_box_to_td new_box) <> (primitive_box_to_td value) then\n             ComputationImpossible\n           else\n             let new_storage = ObjectStoragePrimitive new_box in\n             return (None, new_storage)\n       | _ -> ComputationImpossible)\n  | ObjectStorageStruct fields -> ComputationImpossible\n  | ObjectStorageArray element_td elements -> ComputationImpossible\n  | ObjectStorageAbstract ty value ->\n      (match new_value with\n       | ObjectValueAbstract ty' value' ->\n           if neqb ty ty' then\n             ComputationImpossible\n           else\n             let new_storage = ObjectStorageAbstract ty' value' in\n             return (None, new_storage)\n       | _ -> ComputationImpossible)\n\nlet rec update_pointer_directly\n  (p: Armada.Pointer.t)\n  (new_storage: valid_object_storage_t)\n  (mem: t)\n  : GTot (conditional_computation_t t) =\n  match p with\n  | PointerUninitialized -> ComputationUndefined\n  | PointerNull -> ComputationUndefined\n  | PointerRoot root_id ->\n      let root = mem root_id in\n      let? storage = root_to_storage_computation root in\n      if neqb (object_storage_to_td storage) (object_storage_to_td new_storage) then\n        ComputationImpossible\n      else\n        let new_root = update_root_storage root new_storage in\n        let mem' = Spec.Map.upd mem root_id new_root in\n        return mem'\n  | PointerField struct_ptr field_id ->\n      let? parent = dereference_computation struct_ptr mem in\n      (match parent with\n       | ObjectStorageStruct fields ->\n           if   field_id >= length fields\n              || neqb (object_storage_to_td new_storage)\n                     (object_storage_to_td (index fields field_id)) then\n             ComputationImpossible\n           else\n             let new_parent = update_storage_child parent field_id new_storage in\n             update_pointer_directly struct_ptr new_parent mem\n       | _ -> ComputationImpossible)\n  | PointerIndex array_ptr idx ->\n      let? parent = dereference_computation array_ptr mem in\n      (match parent with\n       | ObjectStorageArray element_td elements ->\n           if   idx < 0\n              || idx >= length elements\n              || neqb (object_storage_to_td new_storage) element_td then\n             ComputationImpossible\n           else\n             let new_parent = update_storage_child parent idx new_storage in\n             update_pointer_directly array_ptr new_parent mem\n       | _ -> ComputationImpossible)\n\nlet update_pointer\n  (p: Armada.Pointer.t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (new_value: object_value_t)\n  (mem: t)\n  : GTot (conditional_computation_t (option write_message_t * t)) =\n  match p with\n  | PointerUninitialized -> ComputationUndefined\n  | PointerNull -> ComputationUndefined\n  | PointerRoot root_id ->\n      let root = mem root_id in\n      let? storage = root_to_storage_computation root in\n      (match update_storage p actor writer_pc writer_expression_number bypassing_write_buffer storage\n               new_value with\n       | ComputationImpossible -> ComputationImpossible\n       | ComputationUndefined -> ComputationUndefined\n       | ComputationProduces (write_message, new_root_storage) ->\n           let new_root = update_root_storage root new_root_storage in\n           let new_mem = Spec.Map.upd mem root_id new_root in\n           return (write_message, new_mem))\n  | PointerField struct_ptr field_id ->\n      let? parent = dereference_computation struct_ptr mem in\n      (match parent with\n       | ObjectStorageStruct fields ->\n           if field_id >= length fields then\n             ComputationImpossible\n           else\n             let field = index fields field_id in\n             if   not (object_storage_valid field)\n                || neqb (object_storage_to_td field) (object_value_to_td new_value) then\n               ComputationImpossible\n             else\n               (match update_storage p actor writer_pc writer_expression_number\n                        bypassing_write_buffer field new_value with\n                | ComputationImpossible -> ComputationImpossible\n                | ComputationUndefined -> ComputationUndefined\n                | ComputationProduces (write_message, new_field) ->\n                    if (not (can_update_storage_child parent field_id new_field)) then\n                      ComputationImpossible\n                    else\n                      let new_parent = update_storage_child parent field_id new_field in\n                      let? new_mem = update_pointer_directly struct_ptr new_parent mem in\n                      return (write_message, new_mem))\n       | _ -> ComputationImpossible)\n  | PointerIndex array_ptr idx ->\n      let? parent = dereference_computation array_ptr mem in\n      (match parent with\n       | ObjectStorageArray element_td elements ->\n           if idx < 0 || idx >= length elements then\n             ComputationUndefined\n           else\n             let element = index elements idx in\n             if not (object_storage_valid element) then\n               ComputationImpossible\n             else\n               (match update_storage p actor writer_pc writer_expression_number\n                        bypassing_write_buffer element new_value with\n                | ComputationImpossible -> ComputationImpossible\n                | ComputationUndefined -> ComputationUndefined\n                | ComputationProduces (write_message, new_element) ->\n                    if not (can_update_storage_child parent idx new_element) then\n                      ComputationImpossible\n                    else\n                      let new_parent = update_storage_child parent idx new_element in\n                      let? new_mem = update_pointer_directly array_ptr new_parent mem in\n                      return (write_message, new_mem))\n        | _ -> ComputationImpossible)\n\nlet propagate_write_message\n  (write_message: write_message_t)\n  (receiver_tid: tid_t)\n  (mem: t)\n  : GTot (conditional_computation_t t) =\n  let p = write_message.location in\n  let? storage = dereference_computation p mem in\n  match storage with\n  | ObjectStorageWeaklyConsistentPrimitive primitive_td values local_versions ->\n      if   primitive_td <> write_message.primitive_td\n         || write_message.version >= length values then\n        ComputationImpossible\n      else if local_versions receiver_tid >= write_message.version then\n        // Skip\n        return mem\n      else\n        // Propagate\n        let new_local_versions = Spec.Map.upd local_versions receiver_tid write_message.version in\n        let new_storage = ObjectStorageWeaklyConsistentPrimitive primitive_td values\n                            new_local_versions in\n        if not (object_storage_valid new_storage) then\n          ComputationImpossible\n        else\n          update_pointer_directly p new_storage mem\n  | _ -> ComputationImpossible\n\nlet free_allocated_root (root_id: root_id_t) (mem: t) : GTot (conditional_computation_t t) =\n  let root = mem root_id in\n  match root with\n  | RootGlobal storage -> ComputationUndefined\n  | RootStackVariable pushed popped storage ->\n      if not pushed then ComputationImpossible else ComputationUndefined\n  | RootAllocated allocated freed storage ->\n      if not allocated then\n        ComputationImpossible\n      else if freed then\n        ComputationUndefined\n      else\n        let root' = RootAllocated true true storage in\n        let mem' = Spec.Map.upd mem root_id root' in\n        return mem'\n  | RootFence storage -> ComputationImpossible // there's no way to compile a free of a fence root\n  | RootInvalid -> ComputationImpossible\n\nlet free_pointer (p: Armada.Pointer.t) (mem: t) : GTot (conditional_computation_t t) =\n  match p with\n  | PointerIndex (PointerRoot root_id) idx ->\n      if idx <> 0 then\n        ComputationUndefined\n      else\n        free_allocated_root root_id mem\n  | _ -> ComputationUndefined\n\nlet pop_stack_variable\n  (actor: tid_t)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (var_id: var_id_t)\n  (mem: t)\n  : GTot (conditional_computation_t t) =\n  let root_id = RootIdStack actor method_id frame_uniq var_id in\n  let root = mem root_id in\n  match root with\n  | RootGlobal storage -> ComputationImpossible\n  | RootStackVariable pushed popped storage ->\n      if not pushed || popped then\n        ComputationImpossible\n      else\n        let root' = RootStackVariable true true storage in\n        let mem' = Spec.Map.upd mem root_id root' in\n        return mem'\n  | RootAllocated allocated freed storage -> ComputationImpossible\n  | RootFence storage -> ComputationImpossible\n  | RootInvalid -> ComputationImpossible\n\nlet rec pop_stack_variables\n  (actor: tid_t)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (var_ids: list var_id_t)\n  (mem: t)\n  : GTot (conditional_computation_t t) =\n  match var_ids with\n  | [] -> return mem\n  | first_var_id :: remaining_var_ids ->\n      let? mem' = pop_stack_variable actor method_id frame_uniq first_var_id mem in\n      pop_stack_variables actor method_id frame_uniq remaining_var_ids mem'\n\nlet is_primitive_box_zero_filled (box: primitive_box_t) : bool =\n  match box with\n  | PrimitiveBoxBool b -> not b\n  | PrimitiveBoxBoundedInt _ n -> n = 0\n  | PrimitiveBoxThreadId tid -> tid = 0\n  | PrimitiveBoxPointer ptr -> PointerNull? ptr\n\nlet rec is_storage_zero_filled (storage: object_storage_t) : GTot bool =\n  match storage with\n  | ObjectStorageWeaklyConsistentPrimitive _ values _ ->\n      length values = 1 && is_primitive_box_zero_filled (index values 0)\n  | ObjectStoragePrimitive value ->\n      is_primitive_box_zero_filled value\n  | ObjectStorageStruct fields ->\n      u2b (forall field.{:pattern contains fields field} contains fields field ==> is_storage_zero_filled field)\n  | ObjectStorageArray _ elements ->\n      u2b (forall element.{:pattern contains elements element}\n             contains elements element ==> is_storage_zero_filled element)\n  | ObjectStorageAbstract _ _ ->\n      false\n\nlet rec is_storage_ready_for_allocation (storage: object_storage_t) : GTot bool =\n  match storage with\n  | ObjectStorageWeaklyConsistentPrimitive _ values _ ->\n       length values = 1\n  | ObjectStoragePrimitive _ ->\n      false\n  | ObjectStorageStruct fields ->\n      u2b (forall field.{:pattern contains fields field} contains fields field ==> is_storage_ready_for_allocation field)\n  | ObjectStorageArray _ elements ->\n      u2b (forall element.{:pattern contains elements element}\n             contains elements element ==> is_storage_ready_for_allocation element)\n  | ObjectStorageAbstract _ _ ->\n      false\n"
  },
  {
    "path": "experimental/lib/Armada.Pointer.fst",
    "content": "module Armada.Pointer\n\nopen Armada.Base\n\ntype t =\n  | PointerUninitialized: t\n  | PointerNull: t\n  | PointerRoot: (root_id: root_id_t) -> t\n  | PointerField: (struct_ptr: t) -> (field_id: nat) -> t\n  | PointerIndex: (array_ptr: t) -> (idx: nat) -> t\n\nlet rec pointer_root (p: t) : option root_id_t =\n  match p with\n  | PointerUninitialized -> None\n  | PointerNull -> None\n  | PointerRoot root -> Some root\n  | PointerField struct_ptr _ -> pointer_root struct_ptr\n  | PointerIndex array_ptr _ -> pointer_root array_ptr\n"
  },
  {
    "path": "experimental/lib/Armada.Program.fst",
    "content": "module Armada.Program\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Pointer\nopen Armada.Step\nopen Armada.State\nopen Armada.Thread\nopen Armada.Threads\nopen Armada.Transition\nopen Armada.Type\nopen FStar.Sequence.Base\nopen Spec.Behavior\nopen Spec.List\nopen Spec.Ubool\n\nnoeq type t = {\n  main_method_id: method_id_t;\n  main_start_pc: pc_t;\n  global_initializers: list initializer_t;\n  main_stack_initializers: list initializer_t;\n  program_statements: list program_statement_t;\n}\n\nlet program_contains_statement_of_step (program: Armada.Program.t) (step: Armada.Step.t) : GTot ubool =\n  contains_ubool step.action.program_statement program.program_statements\n\nlet init_program (program: t) (s: Armada.State.t) : GTot ubool =\n     list_len s.uniqs_used = 1 // only one uniquifier has been used, for the main thread's initial stack frame\n  /\\ memory_satisfies_global_initializers s.mem program.global_initializers\n  /\\ s.mem RootIdFence == RootFence initial_fence_storage\n  /\\ s.initial_tid <> 0\n  /\\ (let thread = s.threads s.initial_tid in\n      let initial_frame_uniq = Cons?.hd s.uniqs_used in\n         ThreadStatusRunning? thread.status\n      /\\ thread.pc = program.main_start_pc\n      /\\ eqb thread.stack []\n      /\\ thread.top.method_id = program.main_method_id\n      /\\ thread.top.frame_uniq = initial_frame_uniq\n      /\\ memory_satisfies_main_stack_initializers s.mem s.initial_tid program.main_method_id initial_frame_uniq\n           thread.top.local_variables program.main_stack_initializers\n      /\\ memory_invalid_outside_initializations s.mem program.global_initializers s.initial_tid program.main_method_id\n           initial_frame_uniq thread.top.local_variables)\n  /\\ (forall tid.{:pattern s.threads tid} let thread = s.threads tid in\n               length thread.write_buffer = 0\n             /\\ thread.position_in_other_write_buffers == Spec.Map.const 0\n             /\\ (tid <> s.initial_tid ==> ThreadStatusNotStarted? thread.status))\n\nlet next_program (program: Armada.Program.t) (transition: Armada.Transition.t) (s s': Armada.State.t) : GTot ubool =\n    (forall step. contains_ubool step transition.steps ==> program_contains_statement_of_step program step)\n  /\\ next_transition transition s s'\n\nlet program_to_spec (program: Armada.Program.t) : GTot (spec_t Armada.State.t) =\n  { init = init_program program;\n    next = fun s s' -> exists (transition: Armada.Transition.t). next_program program transition s s' }\n"
  },
  {
    "path": "experimental/lib/Armada.State.fst",
    "content": "module Armada.State\n\nopen Armada.Base\nopen Armada.Memory\nopen Armada.Threads\nopen Armada.Type\nopen FStar.Sequence.Base\nopen Spec.Behavior\nopen Spec.List\nopen Spec.Ubool\n\ntype stop_reason_t =\n  | NotStopped\n  | StopReasonTerminated\n  | StopReasonAssertionFailure\n  | StopReasonUndefinedBehavior\n  | StopReasonStackOverflow\n\ntype trace_entry = object_value_t\n\nnoeq type t = {\n  initial_tid: tid_t;\n  uniqs_used: list root_id_uniquifier_t;\n  mem: Armada.Memory.t;\n  threads: Armada.Threads.t;\n  trace: seq trace_entry;\n  stop_reason: stop_reason_t;\n}\n\nlet refinement_requirement (ls: Armada.State.t) (hs: Armada.State.t) : GTot ubool =\n  if NotStopped? ls.stop_reason then\n    is_prefix ls.trace hs.trace\n  else\n    ls.stop_reason = hs.stop_reason /\\ ls.trace == hs.trace\n"
  },
  {
    "path": "experimental/lib/Armada.Statement.fst",
    "content": "module Armada.Statement\n\nopen Armada.Base\nopen Armada.Computation\nopen Armada.Expression\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Pointer\nopen Armada.State\nopen Armada.Thread\nopen Armada.Threads\nopen Armada.Type\nopen FStar.Sequence.Base\nopen Spec.List\nopen Spec.Map\nopen Spec.Ubool\n\nnoeq type t =\n  | AssumeExpressionStatement: (exp: expression_t) -> t\n  | AssumePredicateStatement: (pred: Armada.State.t -> GTot bool) -> t\n  | AssertTrueStatement: (exp: expression_t) -> t\n  | AssertFalseStatement: (exp: expression_t) -> t\n  | ConditionalJumpStatement: (cond: expression_t) -> t // if or while\n  | UnconditionalJumpStatement: t // skip, jump past else, jump back to loop head, break, continue, goto, if *, while *\n  | UpdateStatement: (bypassing_write_buffer: bool) -> // whether ::= is used\n                     (dst: expression_t) -> (src: expression_t) -> t\n  | NondeterministicUpdateStatement: (bypassing_write_buffer: bool) -> // whether ::= is used\n                                     (dst: expression_t) -> t\n  | PropagateWriteMessageStatement: t\n  | CompareAndSwapStatement: (target: expression_t) ->  // the location to compare to and possibly store into\n                             (old_val: expression_t) -> // the value to compare the current value to\n                             (new_val: expression_t) -> // the value to swap in if the equality comparison succeeds\n                             (bypassing_write_buffer: bool) -> // whether ::= is used for assigning optional_result\n                             (optional_result: option expression_t) -> t // where to write the boolean \"did swap happen?\"\n  | AtomicExchangeStatement: (old_val: expression_t) -> // where the old value of target will be put\n                             (target: expression_t) ->  // where the new value should be assigned to \n                             (new_val: expression_t) -> t // the new value\n                             // e.g., x := atomic_exchange(y, 3) has old_val x, target y, and new_val 3,\n                             // and means to atomically set x := y then y := 3\n  | CreateThreadStatement: (method_id: method_id_t) ->\n                           (initial_pc: pc_t) ->              // initial PC of created thread\n                           (bypassing_write_buffer: bool) ->  // whether ::= is used for assigning the new thread ID\n                           (optional_result: option expression_t) -> // where the resulting thread ID should be\n                                                                    // written (optional)\n                           (parameter_var_ids: list var_id_t) ->  // local variables to store parameters\n                                                                 // (assumed strongly consistent)\n                           (parameter_expressions: list expression_t) -> // expressions to be stored as parameters\n                           (local_variable_initializers: list initializer_t) ->  t\n  | MethodCallStatement: (method_id: method_id_t) ->\n                         (return_pc: pc_t) ->\n                         (parameter_var_ids: list var_id_t) -> // local variables to store parameters\n                                                              // (assumed strongly consistent)\n                         (parameter_expressions: list expression_t) -> // expressions to be stored as parameters\n                         (local_variable_initializers: list initializer_t) ->\n                            // If this is an external method, there should be one local variable initializer for\n                            // each reads clause. The types of these initializers should match the types of those\n                            // reads clauses, in order. So, for instance if it has \"reads p[3], x\" and the types of\n                            // p[3] and x are t1 and t2, then the local variable initializers should be a list\n                            // whose first element is an initializer with type t1 and whose second element is\n                            // an initializer of type t2.\n                         (stack_overflow: bool) -> t\n  | ReturnStatement: (method_id: method_id_t) ->\n                     (bypassing_write_buffer: bool) ->   // whether ::= is used for assigning output variables\n                     (output_dsts: list expression_t) ->\n                     (output_srcs: list expression_t) -> // output sources to be evaluated before popping the stack;\n                                                        // generally, each of these will be an ExpressionLocalVariable\n                                                        // corresponding to an output stack variable\n                     t\n  | TerminateThreadStatement: (method_id: method_id_t) -> t  // top-level method being returned from\n  | TerminateProcessStatement: (method_id: method_id_t) -> t // main method ID being returned from\n  | JoinStatement: (join_tid: expression_t) -> t // in concrete levels, this expression shouldn't read shared state\n  | MallocSuccessfulStatement: (bypassing_write_buffer: bool) -> // whether ::= is used to write the resulting pointer\n                               (result: expression_t) ->         // where the resulting pointer is written\n                               (allocation_td: object_td_t) ->   // type being allocated\n                               (count: expression_t) ->          // count must be a nat\n                               t\n  | MallocReturningNullStatement: (bypassing_write_buffer: bool) -> (result: expression_t) -> (count: expression_t) -> t\n  | CallocSuccessfulStatement: (bypassing_write_buffer: bool) -> (result: expression_t) -> // result must be a pointer\n                               (allocation_td: object_td_t) -> (count: expression_t) ->    // count must be a nat\n                               t\n  | CallocReturningNullStatement: (bypassing_write_buffer: bool) ->\n                                  (result: expression_t) -> // result must be a pointer\n                                  (count: expression_t) ->  // count must be a nat\n                                  t\n  | DeallocStatement: (ptr: expression_t) -> t\n  | SomehowStatement: (undefined_unless_cond: expression_t) -> // undefined_unless conditions combined with &&\n                      (bypassing_write_buffer: bool) ->        // whether updates to modifies clauses\n                                                              //   bypass write buffers\n                      (modifies_clauses: list expression_t) ->\n                      (ensures_cond: expression_t) ->          // ensures conditions combined with &&\n                      t\n  | FenceStatement: t\n  | ExternalMethodStartStatement: (await_cond: expression_t) ->            // awaits conditions combined with &&\n                                  (undefined_unless_cond: expression_t) -> // undefined_unless conditions\n                                                                          //   combined with &&\n                                  (bypassing_write_buffer: bool) ->        // whether havocs of modifies clauses\n                                                                          //   bypass write buffer\n                                  (modifies_clauses: list expression_t) -> // modifies clauses to havoc\n                                  (reads_clauses: list (var_id_t * expression_t)) -> // reads clauses to snapshot\n                                  t\n  | ExternalMethodMiddleStatement: (bypassing_write_buffer: bool) ->        // whether havocs of modifies clauses\n                                                                           //   bypass write buffer\n                                   (modifies_clauses: list expression_t) -> // modifies clauses to havoc\n                                   (reads_clauses: list (var_id_t * expression_t)) -> // reads clauses to snapshot\n                                   t\n  | ExternalMethodEndStatement: (ensures_cond: expression_t) ->             // ensures clauses combined with &&\n                                (logs_clauses: list expression_t) ->        // values to be appended to\n                                                                           //   external-event trace\n                                t\n\nlet assume_expression_statement_computation\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (exp: expression_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  if   Cons? nd\n     || neqb (expression_to_td exp) (ObjectTDAbstract bool) then\n     ComputationImpossible\n  else (\n    let? value = rvalue_computation exp actor s in\n    if ObjectValueAbstract?.value value <> true then\n      ComputationImpossible\n    else\n      return s\n  )\n\nlet assume_predicate_statement_computation\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (pred: Armada.State.t -> GTot bool)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  if   Cons? nd\n     || not (pred s) then\n    ComputationImpossible\n  else\n    return s\n\nlet assert_true_statement_computation\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (exp: expression_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  if   Cons? nd\n     || neqb (expression_to_td exp) (ObjectTDAbstract bool) then\n     ComputationImpossible\n  else (\n    let? value = rvalue_computation exp actor s in\n    if ObjectValueAbstract?.value value <> true then\n      ComputationImpossible\n    else\n      return s\n  )\n\nlet assert_false_statement_computation\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (exp: expression_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  if   Cons? nd\n     || neqb (expression_to_td exp) (ObjectTDAbstract bool) then\n     ComputationImpossible\n  else (\n    let? value = rvalue_computation exp actor s in\n    if ObjectValueAbstract?.value value <> false then\n      ComputationImpossible\n    else\n      let s' = { s with stop_reason = StopReasonAssertionFailure } in\n      return s'\n  )\n\nlet conditional_jump_statement_computation\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (exp: expression_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  if   Cons? nd\n     || neqb (expression_to_td exp) (ObjectTDAbstract bool) then\n    ComputationImpossible\n  else (\n    let? value = rvalue_computation exp actor s in\n    if ObjectValueAbstract?.value value <> true then\n      ComputationImpossible\n    else\n      return s\n  )\n\nlet unconditional_jump_statement_computation\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  if Cons? nd then\n    ComputationImpossible\n  else\n    return s\n\nlet update_statement_computation\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (bypassing_write_buffer: bool)\n  (dst: expression_t)\n  (src: expression_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  if   Cons? nd\n     || neqb (expression_to_td dst) (expression_to_td src) then\n    ComputationImpossible\n  else (\n    let? src_value = rvalue_computation src actor s in\n    update_expression dst actor start_pc 0 bypassing_write_buffer src_value s\n  )\n\nlet nondeterministic_update_statement_computation\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (bypassing_write_buffer: bool)\n  (dst: expression_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (expression_to_td dst) then\n    ComputationImpossible\n  else (\n    let nd_value = Cons?.hd nd in\n    if not (object_value_has_all_pointers_uninitialized nd_value) then\n      ComputationImpossible\n    else\n      update_expression dst actor start_pc 0 bypassing_write_buffer nd_value s\n  )\n\nlet propagate_write_message_statement_computation\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract tid_t) then\n    ComputationImpossible\n  else\n    let receiver_tid: tid_t = ObjectValueAbstract?.value (Cons?.hd nd) in\n    if receiver_tid = actor then // can't propagate to the same thread\n      ComputationImpossible\n    else\n      let propagator_thread = s.threads actor in\n      let receiver_thread = s.threads receiver_tid in\n      let which_message = receiver_thread.position_in_other_write_buffers actor in\n      if which_message >= length propagator_thread.write_buffer then\n        ComputationImpossible\n      else\n        let write_message = index propagator_thread.write_buffer which_message in\n        let position_in_other_write_buffers' =\n          Spec.Map.upd receiver_thread.position_in_other_write_buffers actor (which_message + 1) in\n        let receiver_thread' =\n          { receiver_thread with position_in_other_write_buffers = position_in_other_write_buffers' } in\n        let threads' = Spec.Map.upd s.threads receiver_tid receiver_thread' in\n        match propagate_write_message write_message receiver_tid s.mem with\n        | ComputationImpossible\n        | ComputationUndefined ->\n            // If propagate would trigger undefined behavior (e.g., by propagating to freed memory),\n            // it just leaves memory unchanged.\n            return ({ s with threads = threads'; })\n        | ComputationProduces mem' ->\n            return ({ s with mem = mem'; threads = threads'; })\n\nlet compare_and_swap_statement_computation\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (target: expression_t)\n  (old_val: expression_t)\n  (new_val: expression_t)\n  (bypassing_write_buffer: bool)\n  (optional_result: option expression_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  if   Cons? nd\n     || neqb (expression_to_td target) (expression_to_td old_val)\n     || neqb (expression_to_td target) (expression_to_td new_val)\n     || (match optional_result with\n        | Some result -> neqb (expression_to_td result) (ObjectTDPrimitive PrimitiveTDBool)\n        | None -> false) then\n    ComputationImpossible\n  else (\n    let? _ = check_expression_up_to_date_for_rmw target actor s in\n    let? old_value = rvalue_computation old_val actor s in\n    let? target_value = rvalue_computation target actor s in\n    let? new_value = rvalue_computation new_val actor s in\n    let? target_ptr = lvalue_computation target actor s in\n    let swap = eqb target_value old_value in\n    let? s' = (if swap then update_pointed_to_value target_ptr actor start_pc 0 false new_value s else return s) in\n    match optional_result with\n    | None -> return s'\n    | Some result ->\n        // this line is deceptive, and we might be potentially bitten by it later\n        // but it simplify the control flow\n        let? result_ptr = lvalue_computation result actor s in\n        let swap_value = ObjectValuePrimitive (PrimitiveBoxBool swap) in\n        update_pointed_to_value result_ptr actor start_pc 1 bypassing_write_buffer swap_value s'\n  )\n\nlet atomic_exchange_statement_computation\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (old_val: expression_t)\n  (target: expression_t)\n  (new_val: expression_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  if   Cons? nd\n     || neqb (expression_to_td target) (expression_to_td old_val)\n     || neqb (expression_to_td target) (expression_to_td new_val) then\n     ComputationImpossible\n  else (\n    // pre-update\n    let? _ = check_expression_up_to_date_for_rmw target actor s in\n    let? target_value = rvalue_computation target actor s in\n    let? new_value = rvalue_computation new_val actor s in\n    let? old_ptr = lvalue_computation old_val actor s in\n    let? target_ptr = lvalue_computation target actor s in\n    // post-update\n    let? s' = update_pointed_to_value old_ptr actor start_pc 0 false target_value s in\n    update_pointed_to_value target_ptr actor start_pc 1 false new_value s'\n  )\n\ntype create_thread_nd_t = {\n  new_tid: tid_t;\n  frame_uniq: root_id_uniquifier_t;\n}\n\nlet make_thread_running\n  (method_id: method_id_t)\n  (initial_pc: pc_t)\n  (new_tid: tid_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (s: Armada.State.t)\n  : GTot Armada.State.t =\n  let thread = s.threads new_tid in\n  let thread' =\n    { thread with\n      status = ThreadStatusRunning;\n      pc = initial_pc;\n      top = { method_id = method_id; frame_uniq = frame_uniq; local_variables = [] };\n      stack = []; } in\n  let threads' = upd s.threads new_tid thread' in\n  { s with threads = threads'; uniqs_used = frame_uniq :: s.uniqs_used }\n\nlet create_thread_statement_computation\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (method_id: method_id_t)\n  (initial_pc: pc_t)\n  (bypassing_write_buffer: bool)\n  (optional_result: option expression_t)\n  (parameter_var_ids: list var_id_t)\n  (parameter_expressions: list expression_t)\n  (local_variable_initializers: list initializer_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  // Nondeterminism must have exactly one element, of type create_thread_nd_t\n  // If there is a target, then it must be of type thread ID\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract create_thread_nd_t)\n     || (   Some? optional_result\n        && neqb (expression_to_td (Some?.v optional_result)) (ObjectTDPrimitive PrimitiveTDThreadId))\n     || list_len parameter_var_ids <> list_len parameter_expressions then\n    ComputationImpossible\n  else (\n    let create_thread_nd: create_thread_nd_t = ObjectValueAbstract?.value (Cons?.hd nd) in\n    let new_tid = create_thread_nd.new_tid in\n    if new_tid = 0 then // thread creation failed, so just set the result to 0\n      (match optional_result with\n       | None -> return s\n       | Some result ->\n           let new_tid_value = ObjectValuePrimitive (PrimitiveBoxThreadId new_tid) in\n           update_expression result actor start_pc (list_len parameter_var_ids + list_len local_variable_initializers)\n              bypassing_write_buffer new_tid_value s)\n    else (\n      let frame_uniq = create_thread_nd.frame_uniq in\n      let new_thread = s.threads new_tid in\n      if   new_thread.status <> ThreadStatusNotStarted\n         || length new_thread.write_buffer <> 0\n         || list_contains frame_uniq s.uniqs_used then\n        ComputationImpossible\n      else (\n        // Evaluate parameter expressions\n        let? parameter_values = rvalues_computation parameter_expressions actor s in\n        // Set the new thread's parameters, and give it status \"running\".\n        let s2 = make_thread_running method_id initial_pc new_tid frame_uniq s in\n        // Initialize the input parameters on the stack of the new thread.\n        // All input variables are assumed to be strongly consistent.\n        let? s3 = push_stack_parameters new_tid start_pc 0 method_id frame_uniq parameter_var_ids parameter_values s2 in\n        // Initialize all remaining parameters on the stack of the new thread.\n        let? s4 = push_stack_variables new_tid start_pc (list_len parameter_var_ids) method_id frame_uniq\n                    local_variable_initializers s3 in\n        // Set the target to the new thread's thread ID, if there is a target\n        (match optional_result with\n         | None -> return s4\n         | Some result ->\n             let new_tid_value = ObjectValuePrimitive (PrimitiveBoxThreadId new_tid) in\n             update_expression result actor start_pc (list_len parameter_var_ids + list_len local_variable_initializers)\n               bypassing_write_buffer new_tid_value s4)\n      )\n    )\n  )\n\ntype method_call_nd_t = {\n  frame_uniq: root_id_uniquifier_t;\n}\n\nlet push_stack_frame\n  (actor: tid_t)\n  (method_id: method_id_t)\n  (return_pc: pc_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (s: Armada.State.t)\n  : GTot Armada.State.t =\n  let thread = s.threads actor in\n  let extended_stack_frame' = { return_pc = return_pc; frame = thread.top } in\n  let stack' = extended_stack_frame' :: thread.stack in\n  let top' = { method_id = method_id; frame_uniq = frame_uniq; local_variables = [] } in\n  let thread' = { thread with top = top'; stack = stack' } in\n  let threads' = upd s.threads actor thread' in\n  { s with threads = threads'; uniqs_used = frame_uniq :: s.uniqs_used }\n\nlet method_call_statement_computation\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (method_id: method_id_t)\n  (return_pc: pc_t)\n  (parameter_var_ids: list var_id_t)\n  (parameter_expressions: list expression_t)\n  (local_variable_initializers: list initializer_t)\n  (stack_overflow: bool)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  // Nondeterminism must have exactly one element, of type method_call_nd_t\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract method_call_nd_t) then\n    ComputationImpossible\n  else (\n    let method_call_nd: method_call_nd_t = ObjectValueAbstract?.value (Cons?.hd nd) in\n    let frame_uniq = method_call_nd.frame_uniq in\n    if list_contains frame_uniq s.uniqs_used then\n      ComputationImpossible\n    else (\n      // Evaluate parameter expressions on old stack, in case they reference local variables\n      let? parameter_values = rvalues_computation parameter_expressions actor s in\n      let s2 = push_stack_frame actor method_id return_pc frame_uniq s in\n      // All input variables are assumed to be strongly consistent, so pass weakly_consistent=false\n      let? s3 = push_stack_parameters actor start_pc 0 method_id frame_uniq parameter_var_ids parameter_values s2 in\n      let? s4 = push_stack_variables actor start_pc (list_len parameter_var_ids) method_id frame_uniq\n                  local_variable_initializers s3 in\n      if stack_overflow then\n        return ({ s4 with stop_reason = StopReasonStackOverflow })\n      else\n        return s4\n    )\n  )\n\nlet pop_stack_frame\n  (actor: tid_t)\n  (mem': Armada.Memory.t)\n  (s: Armada.State.t{Cons? (s.threads actor).stack})\n  : GTot Armada.State.t =\n  let thread = s.threads actor in\n  let stack' = Cons?.tl thread.stack in\n  let top' = (Cons?.hd thread.stack).frame in\n  let thread' = { thread with top = top'; stack = stack' } in\n  let threads' = Spec.Map.upd s.threads actor thread' in\n  { s with mem = mem'; threads = threads' }\n\nlet return_statement_computation\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (end_pc: option pc_t)\n  (method_id: method_id_t)\n  (bypassing_write_buffer: bool)\n  (output_dsts: list expression_t)\n  (output_srcs: list expression_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  let thread = s.threads actor in\n  if   Cons? nd\n     || eqb thread.stack []\n     || thread.top.method_id <> method_id\n     || end_pc <> Some (Cons?.hd thread.stack).return_pc then\n    ComputationImpossible\n  else (\n    // First, evaluate output sources, before we pop the stack.\n    let? output_values = rvalues_computation output_srcs actor s in\n    // Second, free the stack variables and pop the stack.\n    let? mem' = pop_stack_variables actor method_id thread.top.frame_uniq thread.top.local_variables s.mem in\n    let s2 = pop_stack_frame actor mem' s in\n    // Third, assign output values to output destinations.\n    update_expressions output_dsts actor start_pc 0 bypassing_write_buffer output_values s2\n  )\n\nlet terminate_thread_statement_computation\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (method_id: method_id_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  let thread = s.threads actor in\n  if   Cons? nd\n     || neqb thread.stack []\n     || thread.top.method_id <> method_id\n     || actor = s.initial_tid then // returning from main in the initial thread terminates the process, not the thread\n    ComputationImpossible\n  else (\n    // Otherwise, mark thread as joinable and free all stack variables\n    let? mem' = pop_stack_variables actor method_id thread.top.frame_uniq thread.top.local_variables s.mem in\n    let thread' = { thread with status = ThreadStatusJoinable } in\n    let threads' = Spec.Map.upd s.threads actor thread' in\n    let s' = { s with mem = mem'; threads = threads' } in\n    return s'\n  )\n\nlet terminate_process_statement_computation\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (method_id: method_id_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  let thread = s.threads actor in\n  if   Cons? nd\n     || neqb thread.stack []\n     || thread.top.method_id <> method_id\n     || actor <> s.initial_tid then // the process is terminated by having the initial thread terminate\n    ComputationImpossible\n  else\n    let s' = { s with stop_reason = StopReasonTerminated } in\n    return s'\n\nlet join_statement_computation\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (join_tid: expression_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  if   Cons? nd\n     || neqb (expression_to_td join_tid) (ObjectTDPrimitive PrimitiveTDThreadId) then\n    ComputationImpossible\n  else (\n    let? tid_value = rvalue_computation join_tid actor s in\n    let other_tid = PrimitiveBoxThreadId?.tid (ObjectValuePrimitive?.value tid_value) in\n    let thread = s.threads other_tid in\n    match thread.status with\n    | ThreadStatusNotStarted -> ComputationImpossible // can't get a handle to a non-started thread\n    | ThreadStatusRunning -> ComputationImpossible    // not possible since join would block\n    | ThreadStatusPostJoin -> ComputationUndefined    // not defined to join a thread twice\n    | ThreadStatusJoinable ->\n        let thread' = { thread with status = ThreadStatusPostJoin } in\n        let threads' = Spec.Map.upd s.threads other_tid thread' in\n        let s' = { s with threads = threads' } in\n        return s'\n  )\n\nlet mark_allocation_root_allocated\n  (uniq: root_id_uniquifier_t)\n  (storage: valid_object_storage_t)\n  (s: Armada.State.t)\n  : GTot Armada.State.t =\n  let root' = RootAllocated true false storage in\n  let mem' = Spec.Map.upd s.mem (RootIdAllocation uniq) root' in\n  { s with mem = mem' }\n\nlet alloc_successful_statement_computation\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (zero_initialized: bool)\n  (bypassing_write_buffer: bool)\n  (result: expression_t)\n  (allocation_td: object_td_t)\n  (count: expression_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  // There should be one non-determinism parameter, the root ID uniquifier.\n  // The result destination should be of type pointer.\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract root_id_uniquifier_t)\n     || neqb (expression_to_td count) (ObjectTDAbstract nat)\n     || neqb (expression_to_td result) (ObjectTDPrimitive PrimitiveTDPointer) then\n    ComputationImpossible\n  else (\n    let? count_value = rvalue_computation count actor s in\n    let sz = ObjectValueAbstract?.value count_value in\n    let array_td = ObjectTDArray allocation_td sz in\n    let uniq = ObjectValueAbstract?.value (Cons?.hd nd) in\n    let root_id = RootIdAllocation uniq in\n    match s.mem root_id with\n    | RootAllocated allocated freed storage ->\n        if   allocated\n           || freed\n           || neqb (object_storage_to_td storage) array_td\n           || not (is_storage_ready_for_allocation storage)\n           || (not zero_initialized && not (object_storage_arbitrarily_initialized_correctly storage))\n           || (zero_initialized && not (is_storage_zero_filled storage)) then\n          ComputationImpossible\n        else\n          // update memory by marking root as allocated\n          let s' = mark_allocation_root_allocated uniq storage s in\n          // store the pointer to the first element of the newly allocated array in result\n          let p = ObjectValuePrimitive (PrimitiveBoxPointer (PointerIndex (PointerRoot root_id) 0)) in\n          update_expression result actor start_pc 0 bypassing_write_buffer p s'\n    | _ -> ComputationImpossible\n  )\n\nlet alloc_returning_null_statement_computation\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (bypassing_write_buffer: bool)\n  (result: expression_t)\n  (count: expression_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  if   Cons? nd\n     || neqb (expression_to_td count) (ObjectTDAbstract nat)\n     || neqb (expression_to_td result) (ObjectTDPrimitive PrimitiveTDPointer) then\n    ComputationImpossible\n  else (\n    let? _ = rvalue_computation count actor s in\n    let p = ObjectValuePrimitive (PrimitiveBoxPointer PointerNull) in\n    update_expression result actor start_pc 0 bypassing_write_buffer p s\n  )\n\nlet dealloc_statement_computation\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (ptr: expression_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  if   Cons? nd\n     || neqb (expression_to_td ptr) (ObjectTDPrimitive PrimitiveTDPointer) then\n    ComputationImpossible\n  else (\n    let? ptr_value = rvalue_computation ptr actor s in\n    let p = PrimitiveBoxPointer?.ptr (ObjectValuePrimitive?.value ptr_value) in\n    let? mem' = free_pointer p s.mem in\n    let s' = { s with mem = mem' } in\n    return s'\n  )\n\nlet somehow_statement_computation\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (undefined_unless_cond: expression_t)\n  (bypassing_write_buffer: bool)\n  (modifies_clauses: list expression_t)\n  (ensures_cond: expression_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  // The non-determinism can be any length, since it's the set of modified objects.\n  if   neqb (expression_to_td undefined_unless_cond) (ObjectTDPrimitive PrimitiveTDBool)\n     || neqb (expression_to_td ensures_cond) (ObjectTDPrimitive PrimitiveTDBool) then\n    ComputationImpossible\n  else (\n    // Exhibit undefined behavior unless the undefined_unless condition holds\n    let? undefined_unless_value = rvalue_computation undefined_unless_cond actor s in\n    let undefined_unless_bool = PrimitiveBoxBool?.b (ObjectValuePrimitive?.value undefined_unless_value) in\n    if not undefined_unless_bool then\n      ComputationUndefined\n    else (\n      // Update each element of the modifies clauses using the nondeterminism to supply modified values\n      let? s' = update_expressions modifies_clauses actor start_pc 0 bypassing_write_buffer nd s in\n      // Assume the ensures clause holds\n      let? ensures_value = rvalue_computation ensures_cond actor s' in\n      let ensures_bool = PrimitiveBoxBool?.b (ObjectValuePrimitive?.value ensures_value) in\n      if not ensures_bool then\n        ComputationImpossible\n      else\n        return s'\n    )\n  )\n\nlet fence_statement_computation\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  if Cons? nd then\n    ComputationImpossible\n  else (\n    let root = s.mem RootIdFence in\n    let? storage = root_to_storage_computation root in\n    if not (object_storage_up_to_date_for_rmw_operation storage actor) then\n      ComputationImpossible\n    else\n      let p = PointerRoot RootIdFence in\n      update_pointed_to_value p actor start_pc 0 false (ObjectValuePrimitive (PrimitiveBoxBool false)) s\n  )\n\nlet rec external_method_take_snapshot_of_reads_clauses_computation\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (reads_clauses: list (var_id_t * expression_t))\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t)\n    (decreases reads_clauses) =\n  match reads_clauses with\n  | [] -> return s\n  | (first_var_id, first_reads_expression) :: remaining_reads_clauses ->\n      let? first_value = rvalue_computation first_reads_expression actor s in\n      let td = expression_to_td first_reads_expression in\n      let local_var = ExpressionLocalVariable td first_var_id in\n      let? s' = update_expression local_var actor writer_pc writer_expression_number bypassing_write_buffer\n                  first_value s in\n      external_method_take_snapshot_of_reads_clauses_computation actor writer_pc (writer_expression_number + 1)\n        bypassing_write_buffer remaining_reads_clauses s'\n\nlet external_method_start_statement_computation\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (await_cond: expression_t)\n  (undefined_unless_cond: expression_t)\n  (bypassing_write_buffer: bool)\n  (modifies_clauses: list expression_t)\n  (reads_clauses: list (var_id_t * expression_t))\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  // The nondeterminism should be a list of all the values to write into the write set\n  if   neqb (expression_to_td await_cond) (ObjectTDPrimitive PrimitiveTDBool)\n     || neqb (expression_to_td undefined_unless_cond) (ObjectTDPrimitive PrimitiveTDBool)\n     || list_len modifies_clauses <> list_len nd then\n    ComputationImpossible\n  else (\n    // First, wait for all the awaits clauses to hold.\n    let? await_value = rvalue_computation await_cond actor s in\n    let await_bool = PrimitiveBoxBool?.b (ObjectValuePrimitive?.value await_value) in\n    if not await_bool then\n      ComputationImpossible\n    else (\n      // Second, manifest undefined behavior if the undefined_unless clauses don't all hold.\n      let? undefined_unless_value = rvalue_computation undefined_unless_cond actor s in\n      let undefined_unless_bool = PrimitiveBoxBool?.b (ObjectValuePrimitive?.value await_value) in\n      if not undefined_unless_bool then\n        ComputationUndefined\n      else (\n        // Third, havoc the write set, using the nondeterminism to supply the new values.\n        let? s2 = update_expressions modifies_clauses actor start_pc 0 bypassing_write_buffer nd s in\n        // Fourth, capture the read set into local stack variables, starting with variable 0.\n        external_method_take_snapshot_of_reads_clauses_computation actor start_pc (list_len modifies_clauses)\n          bypassing_write_buffer reads_clauses s2\n      )\n    )\n  )\n\nlet rec external_method_check_snapshot_computation\n  (actor: tid_t)\n  (reads_clauses: list (var_id_t * expression_t))\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t unit) =\n  match reads_clauses with\n  | [] -> return ()\n  | (first_var_id, first_reads_expression) :: remaining_reads_clauses ->\n      let? first_value = rvalue_computation first_reads_expression actor s in\n      let td = expression_to_td first_reads_expression in\n      let local_var = ExpressionLocalVariable td first_var_id in\n      let? snapshot_value = rvalue_computation local_var actor s in\n      if neqb first_value snapshot_value then\n        ComputationUndefined\n      else\n        external_method_check_snapshot_computation actor remaining_reads_clauses s\n\nlet external_method_middle_statement_computation\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (bypassing_write_buffer: bool)\n  (modifies_clauses: list expression_t)\n  (reads_clauses: list (var_id_t * expression_t))\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  // The nondeterminism should be a list of all the values to write into the write set\n  // First, manifest undefined behavior if the reads clauses don't match the snapshot on the stack,\n  // starting with variable 0.\n  let? _ = external_method_check_snapshot_computation actor reads_clauses s in\n  // Second, havoc the write set, using the nondeterminism `nd` to supply the new values.\n  let? s2 = update_expressions modifies_clauses actor start_pc 0 bypassing_write_buffer nd s in\n  // Third, capture the read set into local stack variables, starting with variable 0.\n  external_method_take_snapshot_of_reads_clauses_computation actor start_pc (list_len modifies_clauses)\n    bypassing_write_buffer reads_clauses s2\n\nlet rec log_expressions_computation\n  (actor: tid_t)\n  (logs_clauses: list expression_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  match logs_clauses with\n  | [] -> return s\n  | first_logs_clause :: remaining_logs_clauses ->\n      let? event = rvalue_computation first_logs_clause actor s in\n      let trace' = s.trace $:: event in\n      let s' = { s with trace = trace' } in\n      log_expressions_computation actor remaining_logs_clauses s'\n\nlet external_method_end_statement_computation\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (ensures_cond: expression_t)\n  (logs_clauses: list expression_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  if   Cons? nd\n     || neqb (expression_to_td ensures_cond) (ObjectTDPrimitive PrimitiveTDBool) then\n    ComputationImpossible\n  else (\n    let? ensures_value = rvalue_computation ensures_cond actor s in\n    let ensures_bool = PrimitiveBoxBool?.b (ObjectValuePrimitive?.value ensures_value) in\n    if not ensures_bool then\n      ComputationImpossible\n    else\n      log_expressions_computation actor logs_clauses s\n  )\n\nlet statement_computation\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (end_pc: option pc_t)\n  (statement: Armada.Statement.t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  match statement with\n  | AssumeExpressionStatement exp ->\n      assume_expression_statement_computation actor nd start_pc exp s\n  | AssumePredicateStatement pred ->\n      assume_predicate_statement_computation actor nd start_pc pred s\n  | AssertTrueStatement exp ->\n      assert_true_statement_computation actor nd start_pc exp s\n  | AssertFalseStatement exp ->\n      assert_false_statement_computation actor nd start_pc exp s\n  | ConditionalJumpStatement cond ->\n      conditional_jump_statement_computation actor nd start_pc cond s\n  | UnconditionalJumpStatement ->\n      unconditional_jump_statement_computation actor nd start_pc s\n  | UpdateStatement bypassing_write_buffer dst src ->\n      update_statement_computation actor nd start_pc bypassing_write_buffer dst src s\n  | NondeterministicUpdateStatement bypassing_write_buffer dst ->\n      nondeterministic_update_statement_computation actor nd start_pc bypassing_write_buffer dst s\n  | PropagateWriteMessageStatement ->\n      propagate_write_message_statement_computation actor nd s\n  | CompareAndSwapStatement target old_val new_val bypassing_write_buffer optional_result ->\n      compare_and_swap_statement_computation actor nd start_pc target old_val new_val bypassing_write_buffer\n        optional_result s\n  | AtomicExchangeStatement old_val target new_val ->\n      atomic_exchange_statement_computation actor nd start_pc old_val target new_val s\n  | CreateThreadStatement method_id initial_pc bypassing_write_buffer optional_result parameter_var_ids\n                          parameter_expressions local_variable_initializers ->\n      create_thread_statement_computation actor nd start_pc method_id initial_pc bypassing_write_buffer optional_result\n        parameter_var_ids parameter_expressions local_variable_initializers s\n  | MethodCallStatement method_id return_pc parameter_var_ids parameter_expressions local_variable_initializers\n                          stack_overflow ->\n      method_call_statement_computation actor nd start_pc method_id return_pc parameter_var_ids parameter_expressions\n        local_variable_initializers stack_overflow s\n  | ReturnStatement method_id bypassing_write_buffer output_dsts output_srcs ->\n      return_statement_computation actor nd start_pc end_pc method_id bypassing_write_buffer output_dsts output_srcs s\n  | TerminateThreadStatement method_id ->\n      terminate_thread_statement_computation actor nd start_pc method_id s\n  | TerminateProcessStatement method_id ->\n      terminate_process_statement_computation actor nd start_pc method_id s\n  | JoinStatement join_tid ->\n      join_statement_computation actor nd start_pc join_tid s\n  | MallocSuccessfulStatement bypassing_write_buffer result allocation_td count ->\n      alloc_successful_statement_computation actor nd start_pc false bypassing_write_buffer result allocation_td count s\n  | MallocReturningNullStatement bypassing_write_buffer result count ->\n      alloc_returning_null_statement_computation actor nd start_pc bypassing_write_buffer result count s\n  | CallocSuccessfulStatement bypassing_write_buffer result allocation_td count ->\n      alloc_successful_statement_computation actor nd start_pc true bypassing_write_buffer result allocation_td count s\n  | CallocReturningNullStatement bypassing_write_buffer result count ->\n      alloc_returning_null_statement_computation actor nd start_pc bypassing_write_buffer result count s\n  | DeallocStatement ptr ->\n      dealloc_statement_computation actor nd start_pc ptr s\n  | SomehowStatement undefined_unless_cond bypassing_write_buffer modifies_clauses ensures_cond ->\n      somehow_statement_computation actor nd start_pc undefined_unless_cond\n        bypassing_write_buffer modifies_clauses ensures_cond s\n  | FenceStatement ->\n      fence_statement_computation actor nd start_pc s\n  | ExternalMethodStartStatement await_cond undefined_unless_cond bypassing_write_buffer\n                                 modifies_clauses reads_clauses ->\n      external_method_start_statement_computation actor nd start_pc await_cond undefined_unless_cond\n        bypassing_write_buffer modifies_clauses reads_clauses s\n  | ExternalMethodMiddleStatement bypassing_write_buffer modifies_clauses reads_clauses ->\n      external_method_middle_statement_computation actor nd start_pc bypassing_write_buffer modifies_clauses\n        reads_clauses s\n  | ExternalMethodEndStatement ensures_cond logs_clauses ->\n      external_method_end_statement_computation actor nd start_pc ensures_cond logs_clauses s\n"
  },
  {
    "path": "experimental/lib/Armada.Step.fst",
    "content": "module Armada.Step\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Type\n\nnoeq type t = {\n  nd: nondeterminism_t;\n  action: Armada.Action.t;\n}\n"
  },
  {
    "path": "experimental/lib/Armada.Thread.fst",
    "content": "module Armada.Thread\n\nopen Armada.Base\nopen Armada.Type\nopen FStar.Sequence.Base\nopen FStar.List.Tot\nopen Spec.Ubool\n\ntype thread_status_t =\n  | ThreadStatusNotStarted: thread_status_t\n  | ThreadStatusRunning: thread_status_t\n  | ThreadStatusJoinable: thread_status_t\n  | ThreadStatusPostJoin: thread_status_t\n\nnoeq type stack_frame_t = {\n  method_id: method_id_t;\n  frame_uniq: root_id_uniquifier_t;\n  local_variables: list var_id_t;\n}\n\nnoeq type extended_stack_frame_t = {\n  return_pc: pc_t;\n  frame: stack_frame_t;\n}\n\nnoeq type write_message_t = {\n  location: Armada.Pointer.t;\n  primitive_td: primitive_td_t;\n  version: nat;\n  writer_pc: pc_t;\n  writer_expression_number: nat;\n}\n\nnoeq type t = {\n  status: thread_status_t;\n  pc: pc_t;\n  top: stack_frame_t;\n  stack: list extended_stack_frame_t;\n  write_buffer: seq write_message_t;\n  position_in_other_write_buffers: Spec.Map.t tid_t nat;\n}\n"
  },
  {
    "path": "experimental/lib/Armada.Threads.fst",
    "content": "module Armada.Threads\n\nopen Armada.Base\nopen Armada.Thread\n\ntype t = Spec.Map.t tid_t Armada.Thread.t\n"
  },
  {
    "path": "experimental/lib/Armada.Transition.fst",
    "content": "module Armada.Transition\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.State\nopen Armada.Statement\nopen Armada.Step\nopen Armada.Threads\nopen Armada.Type\nopen Spec.List\nopen Spec.Ubool\n\nnoeq type t = {\n  actor: tid_t;\n  steps: list Armada.Step.t;\n}\n\nlet step_computation\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (step: Armada.Step.t)\n  (s: Armada.State.t)\n  : GTot (option Armada.State.t) =\n  action_computation actor starts_atomic_block ends_atomic_block step.nd step.action s\n\nlet rec steps_computation\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (steps: list Armada.Step.t)\n  (s: Armada.State.t)\n  : GTot (option Armada.State.t)\n    (decreases steps) =\n  match steps with\n  | [] -> None\n  | [last_step] -> step_computation actor starts_atomic_block ends_atomic_block last_step s\n  | first_step :: remaining_steps ->\n      (match step_computation actor starts_atomic_block false first_step s with\n       | None -> None\n       | Some s' -> steps_computation actor false ends_atomic_block remaining_steps s')\n\nlet next_transition (transition: Armada.Transition.t) (s s': Armada.State.t) : GTot bool =\n  eqb (Some s') (steps_computation transition.actor true true transition.steps s)\n"
  },
  {
    "path": "experimental/lib/Armada.Type.fst",
    "content": "module Armada.Type\n\nopen Armada.Base\nopen Armada.BoundedInt\nopen Spec.Map\nopen Spec.Ubool\nopen FStar.Sequence.Base\nopen Util.Seq\n\n/// \"td\" stands for \"type descriptor\"\n\ntype primitive_td_t =\n  | PrimitiveTDBool: primitive_td_t\n  | PrimitiveTDBoundedInt: (bt: bounded_int_type_t) -> primitive_td_t\n  | PrimitiveTDThreadId: primitive_td_t\n  | PrimitiveTDPointer: primitive_td_t\n\ntype primitive_box_t =\n  | PrimitiveBoxBool: (b: bool) -> primitive_box_t\n  | PrimitiveBoxBoundedInt: (bt: bounded_int_type_t) -> (n: bt_to_ty bt) -> primitive_box_t\n  | PrimitiveBoxThreadId: (tid: tid_t) -> primitive_box_t\n  | PrimitiveBoxPointer: (ptr: Armada.Pointer.t) -> primitive_box_t\n\nlet primitive_td_to_type (td: primitive_td_t) : Type =\n  match td with\n  | PrimitiveTDBool -> bool\n  | PrimitiveTDBoundedInt bt -> bt_to_ty bt\n  | PrimitiveTDThreadId -> tid_t\n  | PrimitiveTDPointer -> Armada.Pointer.t\n\nlet primitive_box_to_td (b: primitive_box_t) : primitive_td_t =\n  match b with\n  | PrimitiveBoxBool _ -> PrimitiveTDBool\n  | PrimitiveBoxBoundedInt bt _ -> PrimitiveTDBoundedInt bt\n  | PrimitiveBoxThreadId _ -> PrimitiveTDThreadId\n  | PrimitiveBoxPointer _ -> PrimitiveTDPointer\n\nlet primitive_box_to_type (b: primitive_box_t) : Type =\n  primitive_td_to_type (primitive_box_to_td b)\n\nlet primitive_box_matches_primitive_td (b: primitive_box_t) (td: primitive_td_t) : bool =\n  primitive_box_to_td b = td\n\nlet unbox_primitive_box (b: primitive_box_t) : (primitive_box_to_type b) =\n  match b with\n  | PrimitiveBoxBool v -> v\n  | PrimitiveBoxBoundedInt _ v -> v\n  | PrimitiveBoxThreadId v -> v\n  | PrimitiveBoxPointer v -> v\n\nnoeq type object_td_t =\n  | ObjectTDPrimitive: (primitive_td: primitive_td_t) -> object_td_t\n  | ObjectTDStruct: (field_tds: seq object_td_t) -> object_td_t\n  | ObjectTDArray: (element_td: object_td_t) -> (sz: nat) -> object_td_t\n  | ObjectTDAbstract: (ty: Type0) -> object_td_t\n\nnoeq type object_value_t =\n  | ObjectValuePrimitive: (value: primitive_box_t) -> object_value_t\n  | ObjectValueStruct: (fields: seq object_value_t) -> object_value_t\n  | ObjectValueArray: (element_td: object_td_t) -> (elements: seq object_value_t) -> object_value_t\n  | ObjectValueAbstract: (ty: Type0) -> (value: ty) -> object_value_t\n\nlet rec object_value_to_td (value: object_value_t) : GTot object_td_t (decreases rank value) =\n  FStar.Sequence.Ambient.all_seq_facts_ambient;\n  match value with\n  | ObjectValuePrimitive primitive_value -> ObjectTDPrimitive (primitive_box_to_td primitive_value)\n  | ObjectValueStruct fields -> ObjectTDStruct (map_refine object_value_to_td fields)\n  | ObjectValueArray element_td elements -> ObjectTDArray element_td (length elements)\n  | ObjectValueAbstract ty _ -> ObjectTDAbstract ty\n\nlet rec object_value_valid (value: object_value_t) : GTot bool (decreases rank value) =\n  match value with\n  | ObjectValuePrimitive value -> true\n  | ObjectValueStruct fields -> u2b (forall field. contains fields field ==> object_value_valid field)\n  | ObjectValueArray element_td elements ->\n      u2b (forall element. contains elements element ==>\n                      object_value_valid element /\\ object_value_to_td element == element_td)\n  | ObjectValueAbstract ty _ -> true\n\ntype valid_object_value_t (td: object_td_t) =\n  value: object_value_t{object_value_valid value /\\ object_value_to_td value == td}\n\ntype nondeterminism_t = list object_value_t\n"
  },
  {
    "path": "experimental/lib/Armada.UnaryOp.fst",
    "content": "module Armada.UnaryOp\n\nopen Armada.Computation\nopen Armada.Type\nopen Spec.Ubool\nopen Armada.BoundedInt\n\nnoeq type t = {\n  operand_td: object_td_t;\n  result_td: object_td_t;\n  eval: (operand: valid_object_value_t operand_td -> GTot (conditional_computation_t (valid_object_value_t result_td)));\n}\n\nlet not_op : t =\n  let local_eval\n    (operand: valid_object_value_t (ObjectTDPrimitive PrimitiveTDBool))\n    : GTot (conditional_computation_t (valid_object_value_t (ObjectTDPrimitive PrimitiveTDBool))) =\n    let op = unbox_primitive_box (ObjectValuePrimitive?.value operand) in\n      return (ObjectValuePrimitive (PrimitiveBoxBool (not op)))\n  in\n  {\n    operand_td = ObjectTDPrimitive PrimitiveTDBool;\n    result_td = ObjectTDPrimitive PrimitiveTDBool;\n    eval = local_eval;\n  }\n\nlet neg_op : t =\n  let local_eval\n    (operand: valid_object_value_t (ObjectTDAbstract int))\n    : GTot (conditional_computation_t (valid_object_value_t (ObjectTDAbstract int))) =\n    let op = ObjectValueAbstract?.value operand in\n      return (ObjectValueAbstract int (- op))\n  in\n  {\n    operand_td = ObjectTDAbstract int;\n    result_td = ObjectTDAbstract int;\n    eval = local_eval;\n  }\n\nlet bounded_neg_op (bt: bounded_int_type_t) : t =\n  let local_eval\n    (operand: valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)))\n    : GTot (conditional_computation_t (valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)))) =\n    let op = unbox_primitive_box (ObjectValuePrimitive?.value operand) in\n    let result = sub bt 0 op in\n    if result = -op then\n      return (ObjectValuePrimitive (PrimitiveBoxBoundedInt bt result))\n    else\n      ComputationUndefined\n  in\n  {\n    operand_td = ObjectTDPrimitive (PrimitiveTDBoundedInt bt);\n    result_td = ObjectTDPrimitive (PrimitiveTDBoundedInt bt);\n    eval = local_eval;\n  }\n\n// casting\nlet cast_op (bt_op bt_res: bounded_int_type_t) : t =\n  let local_eval\n  (operand: valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt_op)))\n  : GTot (conditional_computation_t (valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt_res)))) =\n  let op = unbox_primitive_box (ObjectValuePrimitive?.value operand) in\n  if not (is_signed bt_res) then\n  // casting to unsigned are always well-defined\n    return (ObjectValuePrimitive (PrimitiveBoxBoundedInt bt_res (fit bt_res op)))\n  else if (=) #int op (fit bt_res op) then\n  // if the value fits in the result type then it's well-defined\n    return (ObjectValuePrimitive (PrimitiveBoxBoundedInt bt_res op))\n  else\n  // otherwise it's \"implementation defined\", I will leave it UB for now\n  // we might change this later, if it turns out we need to verify these code\n    ComputationUndefined\n  in\n  {\n    operand_td = ObjectTDPrimitive (PrimitiveTDBoundedInt bt_op);\n    result_td = ObjectTDPrimitive (PrimitiveTDBoundedInt bt_res);\n    eval = local_eval;\n  }\n\nlet bitwise_not_op (bt: bounded_int_type_t) : t =\n  let local_eval\n    (operand: valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)))\n    : GTot (conditional_computation_t (valid_object_value_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)))) =\n    if is_signed bt then\n      ComputationUndefined\n    else (\n      let num_bits = num_bits_in_bounded_int_type bt in\n      let op: FStar.BV.bv_t num_bits = FStar.BV.int2bv (unbox_primitive_box (ObjectValuePrimitive?.value operand)) in\n      let result: bt_to_ty bt = FStar.BV.bv2int (FStar.BV.bvnot op) in\n      return (ObjectValuePrimitive (PrimitiveBoxBoundedInt bt result))\n    )\n  in\n  {\n    operand_td = ObjectTDPrimitive (PrimitiveTDBoundedInt bt);\n    result_td = ObjectTDPrimitive (PrimitiveTDBoundedInt bt);\n    eval = local_eval;\n  }\n\nnoeq type unary_op_t : (operand_td: object_td_t) -> (result_td: object_td_t) -> Type =\n  | UnaryOpNot: unary_op_t (ObjectTDPrimitive PrimitiveTDBool) (ObjectTDPrimitive PrimitiveTDBool)\n  | UnaryOpNeg: unary_op_t (ObjectTDAbstract int) (ObjectTDAbstract int)\n  | UnaryOpBoundedNeg:\n      bt: bounded_int_type_t ->\n      unary_op_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)) (ObjectTDPrimitive (PrimitiveTDBoundedInt bt))\n  | UnaryOpCast:\n      bt_op: bounded_int_type_t ->\n      bt_res: bounded_int_type_t ->\n      unary_op_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt_op)) (ObjectTDPrimitive (PrimitiveTDBoundedInt bt_res))\n  | UnaryOpBitwiseNot:\n      bt: bounded_int_type_t ->\n      unary_op_t (ObjectTDPrimitive (PrimitiveTDBoundedInt bt)) (ObjectTDPrimitive (PrimitiveTDBoundedInt bt))\n\nlet get_unary_op\n  (#operand_td: object_td_t)\n  (#result_td: object_td_t)\n  (unary_op: unary_op_t operand_td result_td)\n  : GTot (op: t{op.operand_td == operand_td /\\ op.result_td == result_td}) =\n  match unary_op with\n  | UnaryOpNot -> not_op\n  | UnaryOpNeg -> neg_op\n  | UnaryOpBoundedNeg bt -> bounded_neg_op bt\n  | UnaryOpCast bt_op bt_res -> cast_op bt_op bt_res\n  | UnaryOpBitwiseNot bt -> bitwise_not_op bt\n\nlet eval_unary_op\n  (#operand_td: object_td_t)\n  (#result_td: object_td_t)\n  (unary_op: unary_op_t operand_td result_td)\n  (operand: valid_object_value_t operand_td)\n  : GTot (conditional_computation_t (valid_object_value_t result_td)) =\n  let op = get_unary_op unary_op in\n  op.eval operand\n"
  },
  {
    "path": "experimental/lib/GlobalVarExampleInvariant.fst",
    "content": "module GlobalVarExampleInvariant\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.BinaryOp\nopen Armada.Computation\nopen Armada.Expression\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Pointer\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Step\nopen Armada.Transition\nopen Armada.Type\nopen FStar.Sequence.Base\nopen Spec.Behavior\nopen Strategies.Atomic\nopen Strategies.Invariant\nopen Strategies.Invariant.Armada.Atomic\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\nopen Spec.List\nopen Spec.Ubool\nopen Util.List\n\nopen Strategies.ArmadaInvariant.PositionsValid\nopen Strategies.ArmadaInvariant.RootsMatch\nopen Strategies.GlobalVars\nopen Strategies.GlobalVars.Init\nopen Strategies.GlobalVarsProof\nopen Strategies.GlobalVars.UnaddressedStatement\n\nlet vs = [\"f\"]\n\nlet my_inv (s: Armada.State.t) : GTot ubool =\n  let root_one: root_t = RootGlobal (ObjectStorageAbstract int 1) in\n    s.mem (RootIdGlobal \"f\") == root_one\n\nprivate let my_action_pred (action: Armada.Action.t) : GTot ubool =\n      (not action.ok)\n    \\/ (  global_variables_unmodifiable_by_statement vs action.program_statement.statement\n       /\\ global_variables_unaddressable_in_statement vs action.program_statement.statement)\n\nprivate let inductive_inv (s: Armada.State.t) : GTot ubool =\n    roots_match s.mem\n  /\\ positions_valid_in_state s\n  /\\ global_variables_unaddressed_in_memory vs s.mem\n\nprivate let inductive_my_inv (s: Armada.State.t) : GTot ubool =\n  inductive_inv s /\\ my_inv s\n\nprivate let step_relation (s s': Armada.State.t): GTot ubool =\n  states_match_on_global_variables vs s s'\n\nprivate let step_relation_preserves_my_inv (s s': Armada.State.t)\n  : Lemma (requires my_inv s /\\ step_relation s s')\n          (ensures  my_inv s') =\n  ()\n\n#push-options \"--z3rlimit 10 --z3cliopt smt.qi.eager_threshold=100\"\n\nprivate let atomic_lprog_init_establishes_inductive_my_inv\n  (s: Armada.State.t{(semantics_to_spec (make_atomic_semantics armada_semantics) MyAtomicLProg.prog).init s})\n  : squash (inductive_my_inv s) =\n  let initializer5: initializer_t =\n    { var_id = \"f\"; iv = InitializerSpecific (ObjectValueAbstract int 1); weakly_consistent = false; } in\n  assert (contains_ubool initializer5 MyLProg.prog.global_initializers)\n    by FStar.Tactics.V2.norm [delta];\n  assert (global_variables_unaddressed_in_initializers vs MyLProg.prog.global_initializers)\n    by (FStar.Tactics.V2.compute (); FStar.Tactics.V2.trivial ());\n  init_implies_global_variables_unaddressed_in_memory vs MyLProg.prog s;\n  assert (global_variables_unaddressed_in_memory vs s.mem)\n\n#pop-options\n\nprivate let my_action_pred_preserves_inductive_my_inv_proof\n  (actor: tid_t)\n  (starts_atomic_block ends_atomic_block: bool)\n  (step: Armada.Step.t)\n  (s: Armada.State.t)\n  : Lemma (requires   Some? (step_computation actor starts_atomic_block ends_atomic_block step s)\n                    /\\ my_action_pred step.action\n                    /\\ inductive_my_inv s)\n          (ensures    inductive_my_inv (Some?.v (step_computation actor starts_atomic_block ends_atomic_block step s)))\n  = executing_statement_maintains_roots_match actor step.nd ((s.threads actor).pc) step.action.program_statement.end_pc step.action.program_statement.statement s;\n    executing_statement_maintains_positions_valid_in_state actor step.nd ((s.threads actor).pc) step.action.program_statement.end_pc step.action.program_statement.statement s;\n    if (step.action.ok) then begin\n      global_variables_unaddressable_by_statement_global_vars_unaddressed_in_state vs actor step starts_atomic_block ends_atomic_block s;\n      global_variables_unmodifiable_by_statement_memories_matches_on_global_variables vs actor step starts_atomic_block ends_atomic_block s;\n      step_relation_preserves_my_inv s (Some?.v (step_computation actor starts_atomic_block ends_atomic_block step s))\n    end\n\nprivate let my_action_pred_preserves_inductive_my_inv\n  (actor: tid_t)\n  (starts_atomic_block ends_atomic_block: bool)\n  (step: Armada.Step.t)\n  (s: Armada.State.t{\n      Some? (step_computation actor starts_atomic_block ends_atomic_block step s)\n    /\\ my_action_pred step.action\n    /\\ inductive_my_inv s\n  })\n  : squash (inductive_my_inv (Some?.v (step_computation actor starts_atomic_block ends_atomic_block step s)))\n  = my_action_pred_preserves_inductive_my_inv_proof actor starts_atomic_block ends_atomic_block step s\n\nprivate let my_divide_by_one_special_case_atomic_action : list Armada.Action.t =\n  [ { ok = true;\n      program_statement = { start_pc = Some \"main.4\";\n                            end_pc = Some \"main.5\";\n                            starts_atomic_block = true;\n                            ends_atomic_block = true;\n                            statement = UpdateStatement false\n                              (ExpressionGlobalVariable (ObjectTDAbstract int) \"f\")\n                              (ExpressionBinaryOperator\n                                (ObjectTDAbstract int) (ObjectTDAbstract int) (ObjectTDAbstract int) BinaryOpDivInt\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"f\")\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"f\")); } } ]\n\n#push-options \"--z3rlimit 10 --z3cliopt smt.qi.eager_threshold=100\"\n\nprivate let my_divide_by_one_special_case_proof\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (atomic_step: list Armada.Step.t)\n  (s: Armada.State.t{\n       map_ghost armada_step_to_action atomic_step == my_divide_by_one_special_case_atomic_action\n     /\\ inductive_my_inv s\n     /\\ Some? (steps_computation actor starts_atomic_block ends_atomic_block atomic_step s)})\n  : squash (inductive_my_inv (Some?.v (steps_computation actor starts_atomic_block ends_atomic_block atomic_step s))) =\n  (* SMT automatically figures out that dividing value #5 by itself preserves the invariant that\n     value #5 is 1. *)\n  ()\n\n#pop-options\n\nprivate let my_special_case_proof: armada_atomic_special_case_invariant_proof_t inductive_my_inv =\n  ArmadaAtomicSpecialCaseInvariantProof my_divide_by_one_special_case_atomic_action my_divide_by_one_special_case_proof\n\nprivate let my_special_case_proofs\n  : list (option (armada_atomic_special_case_invariant_proof_t inductive_my_inv)) =\n  [\n    None;\n    None;\n    None;\n    None;\n    None;\n    None;\n    Some (ArmadaAtomicSpecialCaseInvariantProof my_divide_by_one_special_case_atomic_action\n            my_divide_by_one_special_case_proof);\n    None\n  ]\n\nlet inductive_my_inv_witness () : armada_atomic_semantics_invariant_witness_t MyAtomicLProg.prog inductive_my_inv =\n  {\n    action_pred = my_action_pred;\n    special_case_proofs = my_special_case_proofs;\n    init_implies_inv_proof = atomic_lprog_init_establishes_inductive_my_inv;\n    action_proof = my_action_pred_preserves_inductive_my_inv;\n  }\n\nlet my_inv_is_stepwise_invariant ()\n  : Lemma (semantics_has_stepwise_inductive_invariant (make_atomic_semantics armada_semantics)\n             MyAtomicLProg.prog inductive_my_inv) =\n  let aiw = inductive_my_inv_witness () in\n  assert (armada_atomic_semantics_invariant_witness_valid MyAtomicLProg.prog inductive_my_inv aiw)\n    by (FStar.Tactics.V2.compute (); FStar.Tactics.V2.trivial ());\n  armada_atomic_semantics_invariant_witness_valid_implies_stepwise_invariant MyAtomicLProg.prog inductive_my_inv aiw\n"
  },
  {
    "path": "experimental/lib/Makefile",
    "content": "################################################################################\n# Customize these variables for your project\n################################################################################\n# The root files of your project, from which to begin scanning dependences\nFSTAR_FILES=MyProgramProof.fst MyVarIntroProof.fst MyVarHidingProof.fst GlobalVarExampleInvariant.fst\n\nFSTAR_EXEC?=$(shell which fstar.exe)\nZ3_EXEC?=$(shell which z3)\n\n################################################################################\nFSTAR=$(FSTAR_EXEC) $(OTHERFLAGS) --cache_checked_modules --smt $(Z3_EXEC)\n\nall: verify-all\n\n# a.fst.checked is the binary, checked version of a.fst\n%.checked: %\n\t$(FSTAR) $*\n\ttouch $@\n\nclean:\n\trm -rf *~ *.checked .depend\n\n.depend:\n\t$(FSTAR) --dep full $(FSTAR_FILES) --extract '* -FStar -Prims' > .depend\n\ndepend: .depend\n\ninclude .depend\n\nverify-all: $(addsuffix .checked, $(ALL_FST_FILES))\n"
  },
  {
    "path": "experimental/lib/MyAProg.fst",
    "content": "/// level A\n/// {\n///   ghost var a: int := 1;\n///   ghost var c: int := 3;\n///   ghost var e: int := 5;\n/// \n///   method subroutine ()\n///   {\n///     a := 0;\n///   }\n/// \n///   method main ()\n///   {\n///     a := 10;\n///     atomic {\n///       c := 20;\n///       e := 30;\n///     }\n///     subroutine();\n///   }\n/// }\n\nmodule MyAProg\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Expression\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Type\nopen Armada.Pointer\nopen Armada.Computation\nopen FStar.List.Tot\nopen FStar.Char\nopen FStar.Mul\nopen FStar.Sequence.Base\nopen Spec.Behavior\nopen Spec.Ubool\n\nlet global_initializers: list initializer_t =\n  [\n    { var_id = \"a\"; iv = InitializerSpecific (ObjectValueAbstract int 1); weakly_consistent = false; } ;\n    { var_id = \"c\"; iv = InitializerSpecific (ObjectValueAbstract int 3); weakly_consistent = false; } ;\n    { var_id = \"e\"; iv = InitializerSpecific (ObjectValueAbstract int 5); weakly_consistent = false; }\n  ]\nlet subroutine_stack_initializers: list initializer_t = \n  [\n\n  ]\nlet subroutine_func_statements = \n  [\n    (* a := 0; *)\n    {\n      start_pc = Some \"subroutine.1\";\n      end_pc = Some \"subroutine.End\";\n      starts_atomic_block = true;\n      ends_atomic_block = true;\n      statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"a\") (ExpressionConstant (ObjectValueAbstract int 0));\n    };\n    (* return from subroutine.End to main.3.R *)\n    {\n      start_pc = Some \"subroutine.End\";\n      end_pc = Some \"main.3.R\";\n      starts_atomic_block = true;\n      ends_atomic_block = true;\n      statement = ReturnStatement \"subroutine\" false [] [];\n    }\n  ]\nlet main_stack_initializers: list initializer_t = \n  [\n\n  ]\nlet main_func_statements = \n  [\n    (* a := 10; *)\n    {\n      start_pc = Some \"main.1\";\n      end_pc = Some \"main.2.1\";\n      starts_atomic_block = true;\n      ends_atomic_block = true;\n      statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"a\") (ExpressionConstant (ObjectValueAbstract int 10));\n    };\n    (* c := 20; *)\n    {\n      start_pc = Some \"main.2.1\";\n      end_pc = Some \"main.2.2\";\n      starts_atomic_block = true;\n      ends_atomic_block = false;\n      statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"c\") (ExpressionConstant (ObjectValueAbstract int 20));\n    };\n    (* e := 30; *)\n    {\n      start_pc = Some \"main.2.2\";\n      end_pc = Some \"main.3\";\n      starts_atomic_block = false;\n      ends_atomic_block = true;\n      statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"e\") (ExpressionConstant (ObjectValueAbstract int 30));\n    };\n    (* subroutine() *)\n    {\n      start_pc = Some \"main.3\";\n      end_pc = Some \"subroutine.1\";\n      starts_atomic_block = true;\n      ends_atomic_block = true;\n      statement = MethodCallStatement \"subroutine\" \"main.3.R\" [] [] subroutine_stack_initializers false;\n    };\n    (* subroutine() stack overflow *)\n    {\n      start_pc = Some \"main.3\";\n      end_pc = Some \"subroutine.1\";\n      starts_atomic_block = true;\n      ends_atomic_block = true;\n      statement = MethodCallStatement \"subroutine\" \"main.3.R\" [] [] subroutine_stack_initializers true;\n    };\n    (* return from method *)\n    {\n      start_pc = Some \"main.3.R\";\n      end_pc = Some \"main.End\";\n      starts_atomic_block = true;\n      ends_atomic_block = true;\n      statement = UnconditionalJumpStatement;\n    }\n  ]\nlet propagate_statements =\n  [\n    {\n      start_pc = None;\n      end_pc = None;\n      starts_atomic_block = true;\n      ends_atomic_block = true;\n      statement = PropagateWriteMessageStatement;\n    }\n  ]\nlet program_statements = \n  [\n    subroutine_func_statements;\n    main_func_statements;\n    propagate_statements\n  ]\nlet prog: Armada.Program.t = {\n  main_method_id = \"main\";\n  main_start_pc = \"main.1\";\n  global_initializers = global_initializers;\n  main_stack_initializers = main_stack_initializers;\n  program_statements = flatten program_statements;\n}\n\n"
  },
  {
    "path": "experimental/lib/MyAtomicAProg.fst",
    "content": "module MyAtomicAProg\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Expression\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Type\nopen Armada.Pointer\nopen Armada.Computation\nopen FStar.List.Tot\nopen FStar.Char\nopen FStar.Mul\nopen FStar.Sequence.Base\nopen Spec.Behavior\nopen Spec.Ubool\nopen Strategies.Atomic\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\nopen Strategies.AtomicToRegular.Armada\nopen Strategies.RegularToAtomic.Armada\nopen Strategies.PCIndices\nopen Util.ImmutableArray\nopen Util.Nth\nopen MyAProg\n\nlet atomic_actions: list (list Armada.Action.t) =\n  [\n    // Atomic action #0\n    [\n      {\n        ok = true;\n        program_statement = \n          (* a := 10; *)\n          {\n            start_pc = Some \"main.1\";\n            end_pc = Some \"main.2.1\";\n            starts_atomic_block = true;\n            ends_atomic_block = true;\n            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"a\") (ExpressionConstant (ObjectValueAbstract int 10));\n          }\n      }\n    ];\n    // Atomic action #1\n    [\n      {\n        ok = false;\n        program_statement = \n          (* a := 10; *)\n          {\n            start_pc = Some \"main.1\";\n            end_pc = Some \"main.2.1\";\n            starts_atomic_block = true;\n            ends_atomic_block = true;\n            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"a\") (ExpressionConstant (ObjectValueAbstract int 10));\n          }\n      }\n    ];\n    // Atomic action #2\n    [\n      {\n        ok = true;\n        program_statement = \n          (* c := 20; *)\n          {\n            start_pc = Some \"main.2.1\";\n            end_pc = Some \"main.2.2\";\n            starts_atomic_block = true;\n            ends_atomic_block = false;\n            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"c\") (ExpressionConstant (ObjectValueAbstract int 20));\n          }\n      };\n      {\n        ok = true;\n        program_statement = \n          (* e := 30; *)\n          {\n            start_pc = Some \"main.2.2\";\n            end_pc = Some \"main.3\";\n            starts_atomic_block = false;\n            ends_atomic_block = true;\n            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"e\") (ExpressionConstant (ObjectValueAbstract int 30));\n          }\n      }\n    ];\n    // Atomic action #3\n    [\n      {\n        ok = false;\n        program_statement = \n          (* c := 20; *)\n          {\n            start_pc = Some \"main.2.1\";\n            end_pc = Some \"main.2.2\";\n            starts_atomic_block = true;\n            ends_atomic_block = false;\n            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"c\") (ExpressionConstant (ObjectValueAbstract int 20));\n          }\n      }\n    ];\n    // Atomic action #4\n    [\n      {\n        ok = true;\n        program_statement = \n          (* c := 20; *)\n          {\n            start_pc = Some \"main.2.1\";\n            end_pc = Some \"main.2.2\";\n            starts_atomic_block = true;\n            ends_atomic_block = false;\n            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"c\") (ExpressionConstant (ObjectValueAbstract int 20));\n          }\n      };\n      {\n        ok = false;\n        program_statement = \n          (* e := 30; *)\n          {\n            start_pc = Some \"main.2.2\";\n            end_pc = Some \"main.3\";\n            starts_atomic_block = false;\n            ends_atomic_block = true;\n            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"e\") (ExpressionConstant (ObjectValueAbstract int 30));\n          }\n      }\n    ];\n    // Atomic action #5\n    [\n      {\n        ok = true;\n        program_statement = \n          (* subroutine() *)\n          {\n            start_pc = Some \"main.3\";\n            end_pc = Some \"subroutine.1\";\n            starts_atomic_block = true;\n            ends_atomic_block = true;\n            statement = MethodCallStatement \"subroutine\" \"main.3.R\" [] [] subroutine_stack_initializers false;\n          }\n      }\n    ];\n    // Atomic action #6\n    [\n      {\n        ok = false;\n        program_statement = \n          (* subroutine() *)\n          {\n            start_pc = Some \"main.3\";\n            end_pc = Some \"subroutine.1\";\n            starts_atomic_block = true;\n            ends_atomic_block = true;\n            statement = MethodCallStatement \"subroutine\" \"main.3.R\" [] [] subroutine_stack_initializers false;\n          }\n      }\n    ];\n    // Atomic action #7\n    [\n      {\n        ok = true;\n        program_statement = \n          (* subroutine() stack overflow *)\n          {\n            start_pc = Some \"main.3\";\n            end_pc = Some \"subroutine.1\";\n            starts_atomic_block = true;\n            ends_atomic_block = true;\n            statement = MethodCallStatement \"subroutine\" \"main.3.R\" [] [] subroutine_stack_initializers true;\n          }\n      }\n    ];\n    // Atomic action #8\n    [\n      {\n        ok = false;\n        program_statement = \n          (* subroutine() stack overflow *)\n          {\n            start_pc = Some \"main.3\";\n            end_pc = Some \"subroutine.1\";\n            starts_atomic_block = true;\n            ends_atomic_block = true;\n            statement = MethodCallStatement \"subroutine\" \"main.3.R\" [] [] subroutine_stack_initializers true;\n          }\n      }\n    ];\n    // Atomic action #9\n    [\n      {\n        ok = true;\n        program_statement = \n          (* a := 0; *)\n          {\n            start_pc = Some \"subroutine.1\";\n            end_pc = Some \"subroutine.End\";\n            starts_atomic_block = true;\n            ends_atomic_block = true;\n            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"a\") (ExpressionConstant (ObjectValueAbstract int 0));\n          }\n      }\n    ];\n    // Atomic action #10\n    [\n      {\n        ok = false;\n        program_statement = \n          (* a := 0; *)\n          {\n            start_pc = Some \"subroutine.1\";\n            end_pc = Some \"subroutine.End\";\n            starts_atomic_block = true;\n            ends_atomic_block = true;\n            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"a\") (ExpressionConstant (ObjectValueAbstract int 0));\n          }\n      }\n    ];\n    // Atomic action #11\n    [\n      {\n        ok = true;\n        program_statement = \n          (* return from subroutine.End to main.3.R *)\n          {\n            start_pc = Some \"subroutine.End\";\n            end_pc = Some \"main.3.R\";\n            starts_atomic_block = true;\n            ends_atomic_block = true;\n            statement = ReturnStatement \"subroutine\" false [] [];\n          }\n      }\n    ];\n    // Atomic action #12\n    [\n      {\n        ok = false;\n        program_statement = \n          (* return from subroutine.End to main.3.R *)\n          {\n            start_pc = Some \"subroutine.End\";\n            end_pc = Some \"main.3.R\";\n            starts_atomic_block = true;\n            ends_atomic_block = true;\n            statement = ReturnStatement \"subroutine\" false [] [];\n          }\n      }\n    ];\n    // Atomic action #13\n    [\n      {\n        ok = true;\n        program_statement = \n          (* return from method *)\n          {\n            start_pc = Some \"main.3.R\";\n            end_pc = Some \"main.End\";\n            starts_atomic_block = true;\n            ends_atomic_block = true;\n            statement = UnconditionalJumpStatement;\n          }\n      }\n    ];\n    // Atomic action #14\n    [\n      {\n        ok = false;\n        program_statement = \n          (* return from method *)\n          {\n            start_pc = Some \"main.3.R\";\n            end_pc = Some \"main.End\";\n            starts_atomic_block = true;\n            ends_atomic_block = true;\n            statement = UnconditionalJumpStatement;\n          }\n      }\n    ];\n    // Atomic action #15\n    [\n      {\n        ok = true;\n        program_statement =\n          (* propagate *)\n          {\n            start_pc = None;\n            end_pc = None;\n            starts_atomic_block = true;\n            ends_atomic_block = true;\n            statement = PropagateWriteMessageStatement;\n          }\n      }\n    ];\n    // Atomic action #16\n    [\n      {\n        ok = false;\n        program_statement =\n          (* propagate *)\n          {\n            start_pc = None;\n            end_pc = None;\n            starts_atomic_block = true;\n            ends_atomic_block = true;\n            statement = PropagateWriteMessageStatement;\n          }\n      }\n    ];\n  ]\n\nlet prog: (program_t (make_atomic_semantics armada_semantics)) =\n  {\n    init_f = init_program MyAProg.prog;\n    actions = atomic_actions;\n  }\n\n"
  },
  {
    "path": "experimental/lib/MyAtomicBInvariant.fst",
    "content": "module MyAtomicBInvariant\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.BinaryOp\nopen Armada.Computation\nopen Armada.Expression\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Pointer\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Step\nopen Armada.Transition\nopen Armada.Type\nopen FStar.Sequence.Base\nopen Spec.Behavior\nopen Strategies.Atomic\nopen Strategies.GlobalVars.Types\nopen Strategies.Invariant\nopen Strategies.Invariant.Armada\nopen Strategies.Invariant.Armada.AtomicSubstep\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\nopen Spec.List\nopen Spec.Ubool\nopen Util.List\n\nlet inv (s: Armada.State.t) : GTot ubool =\n    gvar_has_type s.mem \"a\" (ObjectTDAbstract int)\n  /\\ gvar_has_type s.mem \"c\" (ObjectTDAbstract int)\n  /\\ gvar_has_type s.mem \"e\" (ObjectTDAbstract int)\n\nprivate let action_pred (action: Armada.Action.t) : GTot ubool =\n  True\n\n#push-options \"--z3rlimit 10 --z3cliopt smt.qi.eager_threshold=100\"\n\nprivate let atomic_bprog_init_establishes_inv\n  (s: Armada.State.t{(semantics_to_spec (make_atomic_semantics armada_semantics) MyAtomicBProg.prog).init s})\n  : squash (inv s) =\n  ()\n\nprivate let action_pred_preserves_inv\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (step: Armada.Step.t)\n  (s: Armada.State.t{\n      Some? (step_computation actor starts_atomic_block ends_atomic_block step s)\n    /\\ action_pred step.action\n    /\\ inv s})\n  : squash (inv (Some?.v (step_computation actor starts_atomic_block ends_atomic_block step s))) =\n  step_computation_maintains_all_gvars_have_types\n    [\"a\"; \"c\"; \"e\"]\n    [ObjectTDAbstract int; ObjectTDAbstract int; ObjectTDAbstract int]\n    actor starts_atomic_block ends_atomic_block step s\n\n#pop-options\n\nprivate let my_special_case_proofs\n  : list (list (option (armada_action_special_case_invariant_proof_t inv))) =\n  [\n    // Atomic action #0 has 3 actions\n    [None; None; None];\n    // Atomic action #1 has 1 action\n    [None];\n    // Atomic action #2 has 2 actions\n    [None; None];\n    // Atomic action #3 has 3 actions\n    [None; None; None];\n    // Atomic action #4 has 3 actions\n    [None; None; None];\n    // Atomic action #5 has 1 action\n    [None];\n    // Atomic action #6 has 2 actions\n    [None; None];\n    // Atomic action #7 has 3 actions\n    [None; None; None];\n    // Atomic action #8 has 1 action\n    [None];\n    // Atomic action #9 has 1 action\n    [None];\n    // Atomic action #10 has 1 action\n    [None];\n    // Atomic action #11 has 1 action\n    [None];\n    // Atomic action #12 has 1 action\n    [None];\n    // Atomic action #13 has 1 action\n    [None];\n    // Atomic action #14 has 1 action\n    [None];\n    // Atomic action #15 has 1 action\n    [None];\n    // Atomic action #16 has 1 action\n    [None];\n    // Atomic action #17 has 1 action\n    [None];\n    // Atomic action #18 has 1 action\n    [None];\n    // Atomic action #19 has 1 action\n    [None];\n    // Atomic action #20 has 1 action\n    [None];\n    // Atomic action #21 has 1 action\n    [None];\n    // Atomic action #22 has 2 actions\n    [None; None];\n    // Atomic action #23 has 1 action\n    [None];\n    // Atomic action #24 has 2 actions\n    [None; None];\n    // Atomic action #25 has 1 action\n    [None];\n    // Atomic action #26 has 1 action\n    [None];\n  ]\n\nlet inv_witness () : armada_atomic_substep_invariant_witness_t MyAtomicBProg.prog inv =\n  {\n    action_pred = action_pred;\n    special_case_proofs = my_special_case_proofs;\n    init_implies_inv_proof = atomic_bprog_init_establishes_inv;\n    action_proof = action_pred_preserves_inv;\n  }\n\nlet inv_is_stepwise_invariant ()\n  : Lemma (is_armada_substep_invariant MyAtomicBProg.prog inv) =\n  let aiw = inv_witness () in\n  assert (armada_atomic_substep_invariant_witness_valid MyAtomicBProg.prog inv aiw)\n    by (FStar.Tactics.V2.compute(); FStar.Tactics.V2.trivial ());\n  armada_atomic_substep_invariant_witness_valid_implies_is_substep_invariant MyAtomicBProg.prog inv aiw\n"
  },
  {
    "path": "experimental/lib/MyAtomicBProg.fst",
    "content": "module MyAtomicBProg\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Expression\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Type\nopen Armada.Pointer\nopen Armada.Computation\nopen FStar.List.Tot\nopen FStar.Char\nopen FStar.Mul\nopen FStar.Sequence.Base\nopen Spec.Behavior\nopen Spec.Ubool\nopen Strategies.Atomic\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\nopen Strategies.AtomicToRegular.Armada\nopen Strategies.RegularToAtomic.Armada\nopen Strategies.PCIndices\nopen Util.ImmutableArray\nopen Util.Nth\nopen MyBProg\n\nlet atomic_actions: list (list Armada.Action.t) =\n  [\n    // Atomic action #0\n    [\n      {\n        ok = true;\n        program_statement = \n          (* d := 5; *)\n          {\n            start_pc = Some \"main.1.1\";\n            end_pc = Some \"main.1.2\";\n            starts_atomic_block = true;\n            ends_atomic_block = false;\n            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"d\") (ExpressionConstant (ObjectValueAbstract int 5));\n          }\n      };\n      {\n        ok = true;\n        program_statement = \n          (* a := 10; *)\n          {\n            start_pc = Some \"main.1.2\";\n            end_pc = Some \"main.1.3\";\n            starts_atomic_block = false;\n            ends_atomic_block = false;\n            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"a\") (ExpressionConstant (ObjectValueAbstract int 10));\n          }\n      };\n      {\n        ok = true;\n        program_statement = \n          (* b := 15; *)\n          {\n            start_pc = Some \"main.1.3\";\n            end_pc = Some \"main.2.1\";\n            starts_atomic_block = false;\n            ends_atomic_block = true;\n            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"b\") (ExpressionConstant (ObjectValueAbstract int 15));\n          }\n      }\n    ];\n    // Atomic action #1\n    [\n      {\n        ok = false;\n        program_statement = \n          (* d := 5; *)\n          {\n            start_pc = Some \"main.1.1\";\n            end_pc = Some \"main.1.2\";\n            starts_atomic_block = true;\n            ends_atomic_block = false;\n            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"d\") (ExpressionConstant (ObjectValueAbstract int 5));\n          }\n      }\n    ];\n    // Atomic action #2\n    [\n      {\n        ok = true;\n        program_statement = \n          (* d := 5; *)\n          {\n            start_pc = Some \"main.1.1\";\n            end_pc = Some \"main.1.2\";\n            starts_atomic_block = true;\n            ends_atomic_block = false;\n            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"d\") (ExpressionConstant (ObjectValueAbstract int 5));\n          }\n      };\n      {\n        ok = false;\n        program_statement = \n          (* a := 10; *)\n          {\n            start_pc = Some \"main.1.2\";\n            end_pc = Some \"main.1.3\";\n            starts_atomic_block = false;\n            ends_atomic_block = false;\n            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"a\") (ExpressionConstant (ObjectValueAbstract int 10));\n          }\n      }\n    ];\n    // Atomic action #3\n    [\n      {\n        ok = true;\n        program_statement = \n          (* d := 5; *)\n          {\n            start_pc = Some \"main.1.1\";\n            end_pc = Some \"main.1.2\";\n            starts_atomic_block = true;\n            ends_atomic_block = false;\n            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"d\") (ExpressionConstant (ObjectValueAbstract int 5));\n          }\n      };\n      {\n        ok = true;\n        program_statement = \n          (* a := 10; *)\n          {\n            start_pc = Some \"main.1.2\";\n            end_pc = Some \"main.1.3\";\n            starts_atomic_block = false;\n            ends_atomic_block = false;\n            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"a\") (ExpressionConstant (ObjectValueAbstract int 10));\n          }\n      };\n      {\n        ok = false;\n        program_statement = \n          (* b := 15; *)\n          {\n            start_pc = Some \"main.1.3\";\n            end_pc = Some \"main.2.1\";\n            starts_atomic_block = false;\n            ends_atomic_block = true;\n            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"b\") (ExpressionConstant (ObjectValueAbstract int 15));\n          }\n      }\n    ];\n    // Atomic action #4\n    [\n      {\n        ok = true;\n        program_statement = \n          (* c := 20; *)\n          {\n            start_pc = Some \"main.2.1\";\n            end_pc = Some \"main.2.2\";\n            starts_atomic_block = true;\n            ends_atomic_block = false;\n            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"c\") (ExpressionConstant (ObjectValueAbstract int 20));\n          }\n      };\n      {\n        ok = true;\n        program_statement = \n          (* b := 25; *)\n          {\n            start_pc = Some \"main.2.2\";\n            end_pc = Some \"main.2.3\";\n            starts_atomic_block = false;\n            ends_atomic_block = false;\n            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"b\") (ExpressionConstant (ObjectValueAbstract int 25));\n          }\n      };\n      {\n        ok = true;\n        program_statement = \n          (* e := 30; *)\n          {\n            start_pc = Some \"main.2.3\";\n            end_pc = Some \"main.3\";\n            starts_atomic_block = false;\n            ends_atomic_block = true;\n            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"e\") (ExpressionConstant (ObjectValueAbstract int 30));\n          }\n      }\n    ];\n    // Atomic action #5\n    [\n      {\n        ok = false;\n        program_statement = \n          (* c := 20; *)\n          {\n            start_pc = Some \"main.2.1\";\n            end_pc = Some \"main.2.2\";\n            starts_atomic_block = true;\n            ends_atomic_block = false;\n            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"c\") (ExpressionConstant (ObjectValueAbstract int 20));\n          }\n      }\n    ];\n    // Atomic action #6\n    [\n      {\n        ok = true;\n        program_statement = \n          (* c := 20; *)\n          {\n            start_pc = Some \"main.2.1\";\n            end_pc = Some \"main.2.2\";\n            starts_atomic_block = true;\n            ends_atomic_block = false;\n            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"c\") (ExpressionConstant (ObjectValueAbstract int 20));\n          }\n      };\n      {\n        ok = false;\n        program_statement = \n          (* b := 25; *)\n          {\n            start_pc = Some \"main.2.2\";\n            end_pc = Some \"main.2.3\";\n            starts_atomic_block = false;\n            ends_atomic_block = false;\n            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"b\") (ExpressionConstant (ObjectValueAbstract int 25));\n          }\n      }\n    ];\n    // Atomic action #7\n    [\n      {\n        ok = true;\n        program_statement = \n          (* c := 20; *)\n          {\n            start_pc = Some \"main.2.1\";\n            end_pc = Some \"main.2.2\";\n            starts_atomic_block = true;\n            ends_atomic_block = false;\n            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"c\") (ExpressionConstant (ObjectValueAbstract int 20));\n          }\n      };\n      {\n        ok = true;\n        program_statement = \n          (* b := 25; *)\n          {\n            start_pc = Some \"main.2.2\";\n            end_pc = Some \"main.2.3\";\n            starts_atomic_block = false;\n            ends_atomic_block = false;\n            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"b\") (ExpressionConstant (ObjectValueAbstract int 25));\n          }\n      };\n      {\n        ok = false;\n        program_statement = \n          (* e := 30; *)\n          {\n            start_pc = Some \"main.2.3\";\n            end_pc = Some \"main.3\";\n            starts_atomic_block = false;\n            ends_atomic_block = true;\n            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"e\") (ExpressionConstant (ObjectValueAbstract int 30));\n          }\n      }\n    ];\n    // Atomic action #8\n    [\n      {\n        ok = true;\n        program_statement = \n          (* subroutine() *)\n          {\n            start_pc = Some \"main.3\";\n            end_pc = Some \"subroutine.1\";\n            starts_atomic_block = true;\n            ends_atomic_block = true;\n            statement = MethodCallStatement \"subroutine\" \"main.3.R\" [] [] subroutine_stack_initializers false;\n          }\n      }\n    ];\n    // Atomic action #9\n    [\n      {\n        ok = false;\n        program_statement = \n          (* subroutine() *)\n          {\n            start_pc = Some \"main.3\";\n            end_pc = Some \"subroutine.1\";\n            starts_atomic_block = true;\n            ends_atomic_block = true;\n            statement = MethodCallStatement \"subroutine\" \"main.3.R\" [] [] subroutine_stack_initializers false;\n          }\n      }\n    ];\n    // Atomic action #10\n    [\n      {\n        ok = true;\n        program_statement = \n          (* subroutine() stack overflow *)\n          {\n            start_pc = Some \"main.3\";\n            end_pc = Some \"subroutine.1\";\n            starts_atomic_block = true;\n            ends_atomic_block = true;\n            statement = MethodCallStatement \"subroutine\" \"main.3.R\" [] [] subroutine_stack_initializers true;\n          }\n      }\n    ];\n    // Atomic action #11\n    [\n      {\n        ok = false;\n        program_statement = \n          (* subroutine() stack overflow *)\n          {\n            start_pc = Some \"main.3\";\n            end_pc = Some \"subroutine.1\";\n            starts_atomic_block = true;\n            ends_atomic_block = true;\n            statement = MethodCallStatement \"subroutine\" \"main.3.R\" [] [] subroutine_stack_initializers true;\n          }\n      }\n    ];\n    // Atomic action #12\n    [\n      {\n        ok = true;\n        program_statement = \n          (* a := 0; *)\n          {\n            start_pc = Some \"subroutine.1\";\n            end_pc = Some \"subroutine.2\";\n            starts_atomic_block = true;\n            ends_atomic_block = true;\n            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"a\") (ExpressionConstant (ObjectValueAbstract int 0));\n          }\n      }\n    ];\n    // Atomic action #13\n    [\n      {\n        ok = false;\n        program_statement = \n          (* a := 0; *)\n          {\n            start_pc = Some \"subroutine.1\";\n            end_pc = Some \"subroutine.2\";\n            starts_atomic_block = true;\n            ends_atomic_block = true;\n            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"a\") (ExpressionConstant (ObjectValueAbstract int 0));\n          }\n      }\n    ];\n    // Atomic action #14\n    [\n      {\n        ok = true;\n        program_statement = \n          (* b := a; *)\n          {\n            start_pc = Some \"subroutine.2\";\n            end_pc = Some \"subroutine.3\";\n            starts_atomic_block = true;\n            ends_atomic_block = true;\n            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"b\") (ExpressionGlobalVariable (ObjectTDAbstract int) \"a\");\n          }\n      }\n    ];\n    // Atomic action #15\n    [\n      {\n        ok = false;\n        program_statement = \n          (* b := a; *)\n          {\n            start_pc = Some \"subroutine.2\";\n            end_pc = Some \"subroutine.3\";\n            starts_atomic_block = true;\n            ends_atomic_block = true;\n            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"b\") (ExpressionGlobalVariable (ObjectTDAbstract int) \"a\");\n          }\n      }\n    ];\n    // Atomic action #16\n    [\n      {\n        ok = true;\n        program_statement = \n          (* d := 2; *)\n          {\n            start_pc = Some \"subroutine.3\";\n            end_pc = Some \"subroutine.End\";\n            starts_atomic_block = true;\n            ends_atomic_block = true;\n            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"d\") (ExpressionConstant (ObjectValueAbstract int 2));\n          }\n      }\n    ];\n    // Atomic action #17\n    [\n      {\n        ok = false;\n        program_statement = \n          (* d := 2; *)\n          {\n            start_pc = Some \"subroutine.3\";\n            end_pc = Some \"subroutine.End\";\n            starts_atomic_block = true;\n            ends_atomic_block = true;\n            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"d\") (ExpressionConstant (ObjectValueAbstract int 2));\n          }\n      }\n    ];\n    // Atomic action #18\n    [\n      {\n        ok = true;\n        program_statement = \n          (* return from subroutine.End to main.3.R *)\n          {\n            start_pc = Some \"subroutine.End\";\n            end_pc = Some \"main.3.R\";\n            starts_atomic_block = true;\n            ends_atomic_block = true;\n            statement = ReturnStatement \"subroutine\" false [] [];\n          }\n      }\n    ];\n    // Atomic action #19\n    [\n      {\n        ok = false;\n        program_statement = \n          (* return from subroutine.End to main.3.R *)\n          {\n            start_pc = Some \"subroutine.End\";\n            end_pc = Some \"main.3.R\";\n            starts_atomic_block = true;\n            ends_atomic_block = true;\n            statement = ReturnStatement \"subroutine\" false [] [];\n          }\n      }\n    ];\n    // Atomic action #20\n    [\n      {\n        ok = true;\n        program_statement = \n          (* return from method *)\n          {\n            start_pc = Some \"main.3.R\";\n            end_pc = Some \"main.4.1\";\n            starts_atomic_block = true;\n            ends_atomic_block = true;\n            statement = UnconditionalJumpStatement;\n          }\n      }\n    ];\n    // Atomic action #21\n    [\n      {\n        ok = false;\n        program_statement = \n          (* return from method *)\n          {\n            start_pc = Some \"main.3.R\";\n            end_pc = Some \"main.4.1\";\n            starts_atomic_block = true;\n            ends_atomic_block = true;\n            statement = UnconditionalJumpStatement;\n          }\n      }\n    ];\n    // Atomic action #22\n    [\n      {\n        ok = true;\n        program_statement = \n          (* b := 35; *)\n          {\n            start_pc = Some \"main.4.1\";\n            end_pc = Some \"main.4.2\";\n            starts_atomic_block = true;\n            ends_atomic_block = false;\n            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"b\") (ExpressionConstant (ObjectValueAbstract int 35));\n          }\n      };\n      {\n        ok = true;\n        program_statement = \n          (* d := 40; *)\n          {\n            start_pc = Some \"main.4.2\";\n            end_pc = Some \"main.End\";\n            starts_atomic_block = false;\n            ends_atomic_block = true;\n            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"d\") (ExpressionConstant (ObjectValueAbstract int 40));\n          }\n      }\n    ];\n    // Atomic action #23\n    [\n      {\n        ok = false;\n        program_statement = \n          (* b := 35; *)\n          {\n            start_pc = Some \"main.4.1\";\n            end_pc = Some \"main.4.2\";\n            starts_atomic_block = true;\n            ends_atomic_block = false;\n            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"b\") (ExpressionConstant (ObjectValueAbstract int 35));\n          }\n      }\n    ];\n    // Atomic action #24\n    [\n      {\n        ok = true;\n        program_statement = \n          (* b := 35; *)\n          {\n            start_pc = Some \"main.4.1\";\n            end_pc = Some \"main.4.2\";\n            starts_atomic_block = true;\n            ends_atomic_block = false;\n            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"b\") (ExpressionConstant (ObjectValueAbstract int 35));\n          }\n      };\n      {\n        ok = false;\n        program_statement = \n          (* d := 40; *)\n          {\n            start_pc = Some \"main.4.2\";\n            end_pc = Some \"main.End\";\n            starts_atomic_block = false;\n            ends_atomic_block = true;\n            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"d\") (ExpressionConstant (ObjectValueAbstract int 40));\n          }\n      }\n    ];\n    // Atomic action #25\n    [\n      {\n        ok = true;\n        program_statement =\n          (* propagate *)\n          {\n            start_pc = None;\n            end_pc = None;\n            starts_atomic_block = true;\n            ends_atomic_block = true;\n            statement = PropagateWriteMessageStatement;\n          }\n      }\n    ];\n    // Atomic action #26\n    [\n      {\n        ok = false;\n        program_statement =\n          (* propagate *)\n          {\n            start_pc = None;\n            end_pc = None;\n            starts_atomic_block = true;\n            ends_atomic_block = true;\n            statement = PropagateWriteMessageStatement;\n          }\n      }\n    ];\n  ]\n\nlet prog: (program_t (make_atomic_semantics armada_semantics)) =\n  {\n    init_f = init_program MyBProg.prog;\n    actions = atomic_actions;\n  }\n"
  },
  {
    "path": "experimental/lib/MyAtomicHProg.fst",
    "content": "module MyAtomicHProg\n\nopen Armada.Action\nopen Armada.BinaryOp\nopen Armada.Expression\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Type\nopen Spec.Behavior\nopen Spec.List\nopen Spec.Ubool\nopen Strategies.Atomic\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\n\nlet atomic_actions: list (list Armada.Action.t) =\n  [\n    // Statement at PC 0 succeeds\n    [\n      {\n        ok = true;\n        program_statement = { start_pc = Some \"main.0\";\n                              end_pc = Some \"main.1\";\n                              starts_atomic_block = true;\n                              ends_atomic_block = true;\n                              statement = UpdateStatement false\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"e\")\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"g\"); }\n      }\n    ];\n\n    // Statement at PC 0 exhibits undefined behavior\n    [\n      {\n        ok = false;\n        program_statement = { start_pc = Some \"main.0\";\n                              end_pc = Some \"main.1\";\n                              starts_atomic_block = true;\n                              ends_atomic_block = true;\n                              statement = UpdateStatement false\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"e\")\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"g\"); }\n      }\n    ];\n\n    // Statements at PCs 1-3 run successfully\n    [\n      {\n        ok = true;\n        program_statement = { start_pc = Some \"main.1\";\n                              end_pc = Some \"main.2\";\n                              starts_atomic_block = true;\n                              ends_atomic_block = false;\n                              statement = UpdateStatement false\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"a\")\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"c\"); };\n      };\n      {\n        ok = true;\n        program_statement = { start_pc = Some \"main.2\";\n                              end_pc = Some \"main.3\";\n                              starts_atomic_block = false;\n                              ends_atomic_block = false;\n                              statement = UpdateStatement false\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"d\")\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"b\"); }\n      };\n      {\n        ok = true;\n        program_statement = { start_pc = Some \"main.3\";\n                              end_pc = Some \"main.4\";\n                              starts_atomic_block = false;\n                              ends_atomic_block = true;\n                              statement = UpdateStatement false\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"e\")\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"e\"); }\n      }\n    ];\n\n    // Statement at PC 1 exhibits undefined behavior\n    [\n      {\n        ok = false;\n        program_statement = { start_pc = Some \"main.1\";\n                              end_pc = Some \"main.2\";\n                              starts_atomic_block = true;\n                              ends_atomic_block = false;\n                              statement = UpdateStatement false\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"a\")\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"c\"); }\n      }\n    ];\n\n    // Statement at PC 1 runs normally then statement at PC 2 exhibits undefined behavior\n    [\n      {\n        ok = true;\n        program_statement = { start_pc = Some \"main.1\";\n                              end_pc = Some \"main.2\";\n                              starts_atomic_block = true;\n                              ends_atomic_block = false;\n                              statement = UpdateStatement false\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"a\")\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"c\"); }\n      };\n      {\n        ok = false;\n        program_statement = { start_pc = Some \"main.2\";\n                              end_pc = Some \"main.3\";\n                              starts_atomic_block = false;\n                              ends_atomic_block = false;\n                              statement = UpdateStatement false\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"d\")\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"b\"); }\n      }\n    ];\n\n    // Statements at PCs 1-2 run successfully then statement at PC 3 exhibits undefined behavior\n    [\n      {\n        ok = true;\n        program_statement = { start_pc = Some \"main.1\";\n                              end_pc = Some \"main.2\";\n                              starts_atomic_block = true;\n                              ends_atomic_block = false;\n                              statement = UpdateStatement false\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"a\")\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"c\"); }\n      };\n      {\n        ok = true;\n        program_statement = { start_pc = Some \"main.2\";\n                              end_pc = Some \"main.3\";\n                              starts_atomic_block = false;\n                              ends_atomic_block = false;\n                              statement = UpdateStatement false\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"d\")\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"b\"); }\n      };\n      {\n        ok = false;\n        program_statement = { start_pc = Some \"main.3\";\n                              end_pc = Some \"main.4\";\n                              starts_atomic_block = false;\n                              ends_atomic_block = true;\n                              statement = UpdateStatement false\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"e\")\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"e\"); }\n      }\n    ];\n\n    // Statement at PC 4 runs normally\n    [\n      {\n        ok = true;\n        program_statement = { start_pc = Some \"main.4\";\n                              end_pc = Some \"main.5\";\n                              starts_atomic_block = true;\n                              ends_atomic_block = true;\n                              statement = UpdateStatement false\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"f\")\n                                (ExpressionBinaryOperator (ObjectTDAbstract int) (ObjectTDAbstract int) (ObjectTDAbstract int)\n                                  BinaryOpDivInt\n                                  (ExpressionGlobalVariable (ObjectTDAbstract int) \"f\")\n                                  (ExpressionGlobalVariable (ObjectTDAbstract int) \"f\")); }\n      }\n    ];\n\n    // Statement at PC 4 exhibits undefined behavior\n    [\n      {\n        ok = false;\n        program_statement = { start_pc = Some \"main.4\";\n                              end_pc = Some \"main.5\";\n                              starts_atomic_block = true;\n                              ends_atomic_block = true;\n                              statement = UpdateStatement false\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"f\")\n                                (ExpressionBinaryOperator (ObjectTDAbstract int) (ObjectTDAbstract int) (ObjectTDAbstract int)\n                                  BinaryOpDivInt\n                                  (ExpressionGlobalVariable (ObjectTDAbstract int) \"f\")\n                                  (ExpressionGlobalVariable (ObjectTDAbstract int) \"f\")); }\n      }\n    ]\n  ]\n\nlet atomic_semantics : semantics_t =\n  make_atomic_semantics armada_semantics\n\nlet prog: (program_t atomic_semantics) =\n  {\n    init_f = init_program MyHProg.prog;\n    actions = atomic_actions;\n  }\n"
  },
  {
    "path": "experimental/lib/MyAtomicLProg.fst",
    "content": "module MyAtomicLProg\n\nopen Armada.Action\nopen Armada.BinaryOp\nopen Armada.Expression\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Type\nopen Spec.Behavior\nopen Spec.List\nopen Spec.Ubool\nopen Strategies.Atomic\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\n\nlet atomic_actions: list (list Armada.Action.t) =\n  [\n    // Statement at PC 0 succeeds\n    [\n      {\n        ok = true;\n        program_statement = { start_pc = Some \"main.0\";\n                              end_pc = Some \"main.1\";\n                              starts_atomic_block = true;\n                              ends_atomic_block = true;\n                              statement = UpdateStatement false\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"e\")\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"f\"); }\n      }\n    ];\n\n    // Statement at PC 0 exhibits undefined behavior\n    [\n      {\n        ok = false;\n        program_statement = { start_pc = Some \"main.0\";\n                              end_pc = Some \"main.1\";\n                              starts_atomic_block = true;\n                              ends_atomic_block = true;\n                              statement = UpdateStatement false\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"e\")\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"f\"); }\n      }\n    ];\n\n    // Statements at PCs 1-3 run successfully\n    [\n      {\n        ok = true;\n        program_statement = { start_pc = Some \"main.1\";\n                              end_pc = Some \"main.2\";\n                              starts_atomic_block = true;\n                              ends_atomic_block = false;\n                              statement = UpdateStatement false\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"a\")\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"c\"); };\n      };\n      {\n        ok = true;\n        program_statement = { start_pc = Some \"main.2\";\n                              end_pc = Some \"main.3\";\n                              starts_atomic_block = false;\n                              ends_atomic_block = false;\n                              statement = UpdateStatement false\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"d\")\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"b\"); }\n      };\n      {\n        ok = true;\n        program_statement = { start_pc = Some \"main.3\";\n                              end_pc = Some \"main.4\";\n                              starts_atomic_block = false;\n                              ends_atomic_block = true;\n                              statement = UpdateStatement false\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"e\")\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"e\"); }\n      }\n    ];\n\n    // Statement at PC 1 exhibits undefined behavior\n    [\n      {\n        ok = false;\n        program_statement = { start_pc = Some \"main.1\";\n                              end_pc = Some \"main.2\";\n                              starts_atomic_block = true;\n                              ends_atomic_block = false;\n                              statement = UpdateStatement false\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"a\")\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"c\"); }\n      }\n    ];\n\n    // Statement at PC 1 runs normally then statement at PC 2 exhibits undefined behavior\n    [\n      {\n        ok = true;\n        program_statement = { start_pc = Some \"main.1\";\n                              end_pc = Some \"main.2\";\n                              starts_atomic_block = true;\n                              ends_atomic_block = false;\n                              statement = UpdateStatement false\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"a\")\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"c\"); }\n      };\n      {\n        ok = false;\n        program_statement = { start_pc = Some \"main.2\";\n                              end_pc = Some \"main.3\";\n                              starts_atomic_block = false;\n                              ends_atomic_block = false;\n                              statement = UpdateStatement false\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"d\")\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"b\"); }\n      }\n    ];\n\n    // Statements at PCs 1-2 run successfully then statement at PC 3 exhibits undefined behavior\n    [\n      {\n        ok = true;\n        program_statement = { start_pc = Some \"main.1\";\n                              end_pc = Some \"main.2\";\n                              starts_atomic_block = true;\n                              ends_atomic_block = false;\n                              statement = UpdateStatement false\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"a\")\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"c\"); }\n      };\n      {\n        ok = true;\n        program_statement = { start_pc = Some \"main.2\";\n                              end_pc = Some \"main.3\";\n                              starts_atomic_block = false;\n                              ends_atomic_block = false;\n                              statement = UpdateStatement false\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"d\")\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"b\"); }\n      };\n      {\n        ok = false;\n        program_statement = { start_pc = Some \"main.3\";\n                              end_pc = Some \"main.4\";\n                              starts_atomic_block = false;\n                              ends_atomic_block = true;\n                              statement = UpdateStatement false\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"e\")\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"e\"); }\n      }\n    ];\n\n    // Statement at PC 4 runs normally\n    [\n      {\n        ok = true;\n        program_statement = { start_pc = Some \"main.4\";\n                              end_pc = Some \"main.5\";\n                              starts_atomic_block = true;\n                              ends_atomic_block = true;\n                              statement = UpdateStatement false\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"f\")\n                                (ExpressionBinaryOperator\n                                  (ObjectTDAbstract int) (ObjectTDAbstract int) (ObjectTDAbstract int) BinaryOpDivInt\n                                  (ExpressionGlobalVariable (ObjectTDAbstract int) \"f\")\n                                  (ExpressionGlobalVariable (ObjectTDAbstract int) \"f\")); }\n      }\n    ];\n\n    // Statement at PC 4 exhibits undefined behavior\n    [\n      {\n        ok = false;\n        program_statement = { start_pc = Some \"main.4\";\n                              end_pc = Some \"main.5\";\n                              starts_atomic_block = true;\n                              ends_atomic_block = true;\n                              statement = UpdateStatement false\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"f\")\n                                (ExpressionBinaryOperator\n                                  (ObjectTDAbstract int) (ObjectTDAbstract int) (ObjectTDAbstract int) BinaryOpDivInt\n                                  (ExpressionGlobalVariable (ObjectTDAbstract int) \"f\")\n                                  (ExpressionGlobalVariable (ObjectTDAbstract int) \"f\")); }\n      }\n    ]\n  ]\n\nlet prog: (program_t (make_atomic_semantics armada_semantics)) =\n  {\n    init_f = init_program MyLProg.prog;\n    actions = atomic_actions;\n  }\n"
  },
  {
    "path": "experimental/lib/MyAtomicToRegularRefinement.fst",
    "content": "module MyAtomicToRegularRefinement\n\nopen Armada.Action\nopen Armada.BinaryOp\nopen Armada.Expression\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Type\nopen FStar.Tactics.V2\nopen Spec.Behavior\nopen Spec.List\nopen Spec.Ubool\nopen Strategies.Atomic\nopen Strategies.AtomicToRegular.Armada\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\nopen Util.ImmutableArray\nopen Util.Nth\n\nlet my_atomic_to_regular_map: (list (list nat)) =\n  [[0]; [1]; [2; 4; 6]; [3]; [2; 5]; [2; 4; 7]; [8]; [9]]\n\nlet lemma_MyAtomicHProg_refines_MyHProg ()\n  : Lemma (ensures spec_refines_spec\n                     (semantics_to_spec (make_atomic_semantics armada_semantics) MyAtomicHProg.prog)\n                     (program_to_spec MyHProg.prog)\n                     eq2) =\n  let aw: atomic_refines_armada_witness_t = {\n    atomic_to_regular_map = my_atomic_to_regular_map;\n    actions_array = list_to_array (all_actions MyHProg.prog.program_statements)\n  } in\n  assert (atomic_refines_armada_witness_valid MyAtomicHProg.prog MyHProg.prog aw)\n    by (compute(); trivial());\n  atomic_refines_armada_witness_valid_implies_refinement MyAtomicHProg.prog MyHProg.prog aw\n"
  },
  {
    "path": "experimental/lib/MyBProg.fst",
    "content": "/// level B\n/// {\n///   ghost var a: int := 1;\n///   ghost var b: int := 2;\n///   ghost var c: int := 3;\n///   ghost var d: int := 4;\n///   ghost var e: int := 5;\n/// \n///   method subroutine ()\n///   {\n///     a := 0;\n///     b := a;\n///     d := 2;\n///   }\n/// \n///   method main ()\n///   {\n///     atomic {\n///       d := 5;\n///       a := 10;\n///       b := 15;\n///     }\n///     atomic {\n///       c := 20;\n///       b := 25;\n///       e := 30;\n///     }\n///     subroutine();\n///     atomic {\n///       b := 35;\n///       d := 40;\n///     }\n///   }\n/// }\n\nmodule MyBProg\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Expression\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Type\nopen Armada.Pointer\nopen Armada.Computation\nopen FStar.List.Tot\nopen FStar.Char\nopen FStar.Mul\nopen FStar.Sequence.Base\nopen Spec.Behavior\nopen Spec.Ubool\n\nlet global_initializers: list initializer_t =\n  [\n    { var_id = \"a\"; iv = InitializerSpecific (ObjectValueAbstract int 1); weakly_consistent = false; } ;\n    { var_id = \"b\"; iv = InitializerSpecific (ObjectValueAbstract int 2); weakly_consistent = false; } ;\n    { var_id = \"c\"; iv = InitializerSpecific (ObjectValueAbstract int 3); weakly_consistent = false; } ;\n    { var_id = \"d\"; iv = InitializerSpecific (ObjectValueAbstract int 4); weakly_consistent = false; } ;\n    { var_id = \"e\"; iv = InitializerSpecific (ObjectValueAbstract int 5); weakly_consistent = false; }\n  ]\nlet subroutine_stack_initializers: list initializer_t = \n  [\n\n  ]\nlet subroutine_func_statements = \n  [\n    (* a := 0; *)\n    {\n      start_pc = Some \"subroutine.1\";\n      end_pc = Some \"subroutine.2\";\n      starts_atomic_block = true;\n      ends_atomic_block = true;\n      statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"a\") (ExpressionConstant (ObjectValueAbstract int 0));\n    };\n    (* b := a; *)\n    {\n      start_pc = Some \"subroutine.2\";\n      end_pc = Some \"subroutine.3\";\n      starts_atomic_block = true;\n      ends_atomic_block = true;\n      statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"b\") (ExpressionGlobalVariable (ObjectTDAbstract int) \"a\");\n    };\n    (* d := 2; *)\n    {\n      start_pc = Some \"subroutine.3\";\n      end_pc = Some \"subroutine.End\";\n      starts_atomic_block = true;\n      ends_atomic_block = true;\n      statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"d\") (ExpressionConstant (ObjectValueAbstract int 2));\n    };\n    (* return from subroutine.End to main.3.R *)\n    {\n      start_pc = Some \"subroutine.End\";\n      end_pc = Some \"main.3.R\";\n      starts_atomic_block = true;\n      ends_atomic_block = true;\n      statement = ReturnStatement \"subroutine\" false [] [];\n    }\n  ]\nlet main_stack_initializers: list initializer_t = \n  [\n\n  ]\nlet main_func_statements = \n  [\n    (* d := 5; *)\n    {\n      start_pc = Some \"main.1.1\";\n      end_pc = Some \"main.1.2\";\n      starts_atomic_block = true;\n      ends_atomic_block = false;\n      statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"d\") (ExpressionConstant (ObjectValueAbstract int 5));\n    };\n    (* a := 10; *)\n    {\n      start_pc = Some \"main.1.2\";\n      end_pc = Some \"main.1.3\";\n      starts_atomic_block = false;\n      ends_atomic_block = false;\n      statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"a\") (ExpressionConstant (ObjectValueAbstract int 10));\n    };\n    (* b := 15; *)\n    {\n      start_pc = Some \"main.1.3\";\n      end_pc = Some \"main.2.1\";\n      starts_atomic_block = false;\n      ends_atomic_block = true;\n      statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"b\") (ExpressionConstant (ObjectValueAbstract int 15));\n    };\n    (* c := 20; *)\n    {\n      start_pc = Some \"main.2.1\";\n      end_pc = Some \"main.2.2\";\n      starts_atomic_block = true;\n      ends_atomic_block = false;\n      statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"c\") (ExpressionConstant (ObjectValueAbstract int 20));\n    };\n    (* b := 25; *)\n    {\n      start_pc = Some \"main.2.2\";\n      end_pc = Some \"main.2.3\";\n      starts_atomic_block = false;\n      ends_atomic_block = false;\n      statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"b\") (ExpressionConstant (ObjectValueAbstract int 25));\n    };\n    (* e := 30; *)\n    {\n      start_pc = Some \"main.2.3\";\n      end_pc = Some \"main.3\";\n      starts_atomic_block = false;\n      ends_atomic_block = true;\n      statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"e\") (ExpressionConstant (ObjectValueAbstract int 30));\n    };\n    (* subroutine() *)\n    {\n      start_pc = Some \"main.3\";\n      end_pc = Some \"subroutine.1\";\n      starts_atomic_block = true;\n      ends_atomic_block = true;\n      statement = MethodCallStatement \"subroutine\" \"main.3.R\" [] [] subroutine_stack_initializers false;\n    };\n    (* subroutine() stack overflow *)\n    {\n      start_pc = Some \"main.3\";\n      end_pc = Some \"subroutine.1\";\n      starts_atomic_block = true;\n      ends_atomic_block = true;\n      statement = MethodCallStatement \"subroutine\" \"main.3.R\" [] [] subroutine_stack_initializers true;\n    };\n    (* return from method *)\n    {\n      start_pc = Some \"main.3.R\";\n      end_pc = Some \"main.4.1\";\n      starts_atomic_block = true;\n      ends_atomic_block = true;\n      statement = UnconditionalJumpStatement;\n    };\n    (* b := 35; *)\n    {\n      start_pc = Some \"main.4.1\";\n      end_pc = Some \"main.4.2\";\n      starts_atomic_block = true;\n      ends_atomic_block = false;\n      statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"b\") (ExpressionConstant (ObjectValueAbstract int 35));\n    };\n    (* d := 40; *)\n    {\n      start_pc = Some \"main.4.2\";\n      end_pc = Some \"main.End\";\n      starts_atomic_block = false;\n      ends_atomic_block = true;\n      statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"d\") (ExpressionConstant (ObjectValueAbstract int 40));\n    }\n  ]\nlet propagate_statements =\n  [\n    {\n      start_pc = None;\n      end_pc = None;\n      starts_atomic_block = true;\n      ends_atomic_block = true;\n      statement = PropagateWriteMessageStatement;\n    }\n  ]\nlet program_statements = \n  [\n    subroutine_func_statements;\n    main_func_statements;\n    propagate_statements\n  ]\nlet prog: Armada.Program.t = {\n  main_method_id = \"main\";\n  main_start_pc = \"main.1.1\";\n  global_initializers = global_initializers;\n  main_stack_initializers = main_stack_initializers;\n  program_statements = flatten program_statements;\n}\n\n"
  },
  {
    "path": "experimental/lib/MyHProg.arm",
    "content": "level MyHProg\n{\n  ghost var a: int := 0;\n  ghost var b: int := 1;\n  ghost var c: int := 2;\n  ghost var d: int := 3;\n  ghost var e: int;\n  ghost var f: int := 1;\n  ghost var g: int := 1;\n  ghost var h: int := 0;\n\n  method main ()\n  {\n    ghost var x: int := 0;\n\n    e := g;  // This is the only statement differing from level MyLProg\n    atomic {\n      a := c;\n      d := b;\n      e := e;\n    }\n    f := f / f;\n  }\n}\n"
  },
  {
    "path": "experimental/lib/MyHProg.fst",
    "content": "module MyHProg\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.BinaryOp\nopen Armada.Expression\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Type\nopen Spec.Behavior\nopen Spec.Ubool\n\n/// level MyHProg\n/// {\n///   ghost var a: int := 0;\n///   ghost var b: int := 1;\n///   ghost var c: int := 2;\n///   ghost var d: int := 3;\n///   ghost var e: int;\n///   ghost var f: int := 1;\n///   ghost var g: int := 1;\n///   ghost var h: int := 0;\n///\n///   method main ()\n///   {\n///     ghost var x: int := 0;\n///\n///     e := g;  // This is the only statement differing from level MyLProg\n///     atomic {\n///       a := c;\n///       d := b;\n///       e := e;\n///     }\n///     f := f / f;\n///   }\n/// }\n\nlet global_initializers: list initializer_t =\n  [\n    { var_id = \"a\"; iv = InitializerSpecific (ObjectValueAbstract int 0); weakly_consistent = false; } ;\n    { var_id = \"b\"; iv = InitializerSpecific (ObjectValueAbstract int 1); weakly_consistent = false; } ;\n    { var_id = \"c\"; iv = InitializerSpecific (ObjectValueAbstract int 2); weakly_consistent = false; } ;\n    { var_id = \"d\"; iv = InitializerSpecific (ObjectValueAbstract int 3); weakly_consistent = false; } ;\n    { var_id = \"e\"; iv = InitializerArbitrary (ObjectTDAbstract int); weakly_consistent = false; } ;\n    { var_id = \"f\"; iv = InitializerSpecific (ObjectValueAbstract int 1); weakly_consistent = false; } ;\n    { var_id = \"g\"; iv = InitializerSpecific (ObjectValueAbstract int 1); weakly_consistent = false; } ;\n    { var_id = \"h\"; iv = InitializerSpecific (ObjectValueAbstract int 0); weakly_consistent = false; }\n  ]\n\nlet program_statements = [\n  { start_pc = Some \"main.0\"; end_pc = Some \"main.1\"; starts_atomic_block = true; ends_atomic_block = true;\n    statement = UpdateStatement false\n                  (ExpressionGlobalVariable (ObjectTDAbstract int) \"e\")\n                  (ExpressionGlobalVariable (ObjectTDAbstract int) \"g\"); };\n  { start_pc = Some \"main.1\"; end_pc = Some \"main.2\"; starts_atomic_block = true; ends_atomic_block = false;\n    statement = UpdateStatement false\n                  (ExpressionGlobalVariable (ObjectTDAbstract int) \"a\")\n                  (ExpressionGlobalVariable (ObjectTDAbstract int) \"c\"); };\n  { start_pc = Some \"main.2\"; end_pc = Some \"main.3\";  starts_atomic_block = false; ends_atomic_block = false;\n    statement = UpdateStatement false\n                  (ExpressionGlobalVariable (ObjectTDAbstract int) \"d\")\n                  (ExpressionGlobalVariable (ObjectTDAbstract int) \"b\"); };\n  { start_pc = Some \"main.3\"; end_pc = Some \"main.4\"; starts_atomic_block = false; ends_atomic_block = true;\n    statement = UpdateStatement false\n                  (ExpressionGlobalVariable (ObjectTDAbstract int) \"e\")\n                  (ExpressionGlobalVariable (ObjectTDAbstract int) \"e\"); };\n  { start_pc = Some \"main.4\"; end_pc = Some \"main.5\"; starts_atomic_block = true; ends_atomic_block = true;\n    statement = UpdateStatement false\n                  (ExpressionGlobalVariable (ObjectTDAbstract int) \"f\")\n                  (ExpressionBinaryOperator\n                    (ObjectTDAbstract int) (ObjectTDAbstract int) (ObjectTDAbstract int) BinaryOpDivInt\n                    (ExpressionGlobalVariable (ObjectTDAbstract int) \"f\")\n                    (ExpressionGlobalVariable (ObjectTDAbstract int) \"f\")); };\n]\n\nlet prog: Armada.Program.t = {\n  main_method_id = \"main\";\n  main_start_pc = \"main.0\";\n  global_initializers = global_initializers;\n  main_stack_initializers = [ { var_id = \"x\"; iv = InitializerSpecific (ObjectValueAbstract int 0); weakly_consistent = false } ];\n  program_statements = program_statements;\n}\n"
  },
  {
    "path": "experimental/lib/MyLProg.arm",
    "content": "level MyLProg\n{\n  ghost var a: int := 0;\n  ghost var b: int := 1;\n  ghost var c: int := 2;\n  ghost var d: int := 3;\n  ghost var e: int;\n  ghost var f: int := 1;\n  ghost var g: int := 1;\n  ghost var h: int := 0;\n\n  method main ()\n  {\n    ghost var x: int := 0;\n\n    e := f;\n    atomic {\n      a := c;\n      d := b;\n      e := e;\n    }\n    f := f / f;\n  }\n}\n"
  },
  {
    "path": "experimental/lib/MyLProg.fst",
    "content": "module MyLProg\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.BinaryOp\nopen Armada.Expression\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Type\nopen Spec.Behavior\nopen Spec.Ubool\n\n/// level MyLProg\n/// {\n///   ghost var a: int := 0;\n///   ghost var b: int := 1;\n///   ghost var c: int := 2;\n///   ghost var d: int := 3;\n///   ghost var e: int;\n///   ghost var f: int := 1;\n///   ghost var g: int := 1;\n///   ghost var h: int := 0;\n///\n///   method main ()\n///   {\n///     ghost var x: int := 0;\n///\n///     e := f;\n///     atomic {\n///       a := c;\n///       d := b;\n///       e := e;\n///     }\n///     f := f / f;\n///   }\n/// }\n\nlet global_initializers: list initializer_t =\n  [\n    { var_id = \"a\"; iv = InitializerSpecific (ObjectValueAbstract int 0); weakly_consistent = false; } ;\n    { var_id = \"b\"; iv = InitializerSpecific (ObjectValueAbstract int 1); weakly_consistent = false; } ;\n    { var_id = \"c\"; iv = InitializerSpecific (ObjectValueAbstract int 2); weakly_consistent = false; } ;\n    { var_id = \"d\"; iv = InitializerSpecific (ObjectValueAbstract int 3); weakly_consistent = false; } ;\n    { var_id = \"e\"; iv = InitializerArbitrary (ObjectTDAbstract int); weakly_consistent = false; } ;\n    { var_id = \"f\"; iv = InitializerSpecific (ObjectValueAbstract int 1); weakly_consistent = false; } ;\n    { var_id = \"g\"; iv = InitializerSpecific (ObjectValueAbstract int 1); weakly_consistent = false; } ;\n    { var_id = \"h\"; iv = InitializerSpecific (ObjectValueAbstract int 0); weakly_consistent = false; }\n  ]\n\nlet program_statements = [\n  { start_pc = Some \"main.0\"; end_pc = Some \"main.1\"; starts_atomic_block = true; ends_atomic_block = true;\n    statement = UpdateStatement false\n                  (ExpressionGlobalVariable (ObjectTDAbstract int) \"e\")\n                  (ExpressionGlobalVariable (ObjectTDAbstract int) \"f\"); };\n  { start_pc = Some \"main.1\"; end_pc = Some \"main.2\"; starts_atomic_block = true; ends_atomic_block = false;\n    statement = UpdateStatement false\n                  (ExpressionGlobalVariable (ObjectTDAbstract int) \"a\")\n                  (ExpressionGlobalVariable (ObjectTDAbstract int) \"c\"); };\n  { start_pc = Some \"main.2\"; end_pc = Some \"main.3\"; starts_atomic_block = false; ends_atomic_block = false;\n    statement = UpdateStatement false\n                  (ExpressionGlobalVariable (ObjectTDAbstract int) \"d\")\n                  (ExpressionGlobalVariable (ObjectTDAbstract int) \"b\"); };\n  { start_pc = Some \"main.3\"; end_pc = Some \"main.4\"; starts_atomic_block = false; ends_atomic_block = true;\n    statement = UpdateStatement false\n                  (ExpressionGlobalVariable (ObjectTDAbstract int) \"e\")\n                  (ExpressionGlobalVariable (ObjectTDAbstract int) \"e\"); };\n  { start_pc = Some \"main.4\"; end_pc = Some \"main.5\"; starts_atomic_block = true; ends_atomic_block = true;\n    statement = UpdateStatement false\n                  (ExpressionGlobalVariable (ObjectTDAbstract int) \"f\")\n                  (ExpressionBinaryOperator\n                    (ObjectTDAbstract int) (ObjectTDAbstract int) (ObjectTDAbstract int) BinaryOpDivInt\n                    (ExpressionGlobalVariable (ObjectTDAbstract int) \"f\")\n                    (ExpressionGlobalVariable (ObjectTDAbstract int) \"f\")); };\n]\n\nlet prog: Armada.Program.t = {\n  main_method_id = \"main\";\n  main_start_pc = \"main.0\";\n  global_initializers = global_initializers;\n  main_stack_initializers = [ { var_id = \"x\"; iv = InitializerSpecific (ObjectValueAbstract int 0); weakly_consistent = false } ];\n  program_statements = program_statements;\n}\n"
  },
  {
    "path": "experimental/lib/MyList.fst",
    "content": "module MyList\n\nopen FStar.List.Tot\nopen Util.Nth\n\nlet my_list:(list int) = [865; 415; 194; 337; 607; 744; 992; 113; 234; 8; 996; 829; 365; 465; 639; 869; 433; 726; 351; 812; 335; 542; 738; 38; 369; 602; 396; 833; 772; 728; 431; 95; 456; 48; 815; 439; 909; 154; 685; 871; 990; 352; 665; 838; 274; 351; 38; 999; 333; 11; 974; 569; 17; 897; 778; 53; 941; 462; 458; 44; 814; 33; 686; 93; 31; 876; 970; 269; 517; 770; 748; 1; 892; 638; 159; 548; 888; 421; 411; 147; 172; 647; 588; 1; 191; 470; 896; 721; 901; 516; 293; 153; 57; 131; 932; 252; 511; 574; 748; 658; 750; 235; 756; 776; 534; 656; 479; 925; 800; 699; 30; 385; 966; 690; 875; 798; 867; 320; 156; 640; 449; 445; 975; 518; 120; 554; 741; 321; 477; 319; 216; 5; 269; 997; 804; 139; 27; 433; 167; 704; 155; 454; 995; 862; 276; 459; 275; 795; 360; 338; 354; 687; 132; 999; 346; 108; 188; 387; 705; 928; 510; 756; 891; 646; 262; 962; 381; 967; 485; 871; 339; 582; 505; 530; 867; 85; 224; 107; 558; 609; 167; 650; 573; 749; 910; 492; 300; 542; 989; 264; 778; 160; 508; 346; 853; 378; 76; 213; 784; 212; 976; 580; 230; 103; 282; 527; 881; 508; 219; 613; 904; 147; 298; 978; 9; 715; 1; 190; 883; 360; 966; 508; 49; 945; 360; 290; 352; 813; 172; 938; 930; 110; 385; 350; 582; 310; 303; 397; 755; 181; 835; 393; 41; 251; 747; 511; 454; 239; 154; 154; 508; 851; 574; 599; 532; 576; 827; 245; 424; 502; 303; 872; 854; 434; 327; 825; 664; 386; 826; 637; 700; 858; 435; 960; 223; 326; 872; 675; 260; 880; 882; 486; 601; 587; 22; 311; 2; 472; 356; 275; 161; 864; 199; 46; 641; 698; 333; 917; 706; 376; 52; 228; 907; 264; 962; 741; 435; 383; 513; 231; 112; 929; 252; 664; 943; 357; 304; 446; 748; 384; 686; 53; 112; 403; 444; 828; 569; 435; 726; 570; 415; 369; 395; 838; 561; 795; 550; 163; 28; 278; 598; 248; 223; 815; 133; 134; 8; 55; 792; 329; 868; 70; 206; 46; 118; 12; 231; 180; 98; 226; 64; 784; 777; 58; 971; 355; 569; 992; 801; 516; 72; 909; 773; 168; 680; 562; 49; 137; 442; 793; 429; 201; 280; 687; 956; 388; 830; 453; 456; 695; 359; 417; 331; 643; 865; 167; 644; 375; 639; 72; 197; 854; 725; 569; 356; 939; 551; 135; 886; 80; 714; 483; 315; 897; 496; 300; 502; 726; 777; 571; 611; 353; 776; 487; 412; 852; 495; 255; 749; 301; 300; 803; 213; 499; 546; 278; 7; 267; 871; 963; 709; 326; 877; 655; 929; 860; 949; 903; 160; 731; 116; 393; 713; 499; 331; 25; 257; 648; 341; 54; 654; 714; 227; 995; 792; 698; 442; 835; 526; 660; 751; 962; 186; 699; 753; 385; 477; 686; 477; 322; 201; 360; 344; 766; 942; 985; 328; 98; 475; 520; 257; 864; 560; 725; 302; 305; 670; 317; 642; 959; 25; 607; 97; 669; 387; 968; 620; 931; 948; 23; 638; 443; 778; 885; 950; 706; 93; 613; 601; 513; 810; 707; 536; 897; 400; 530; 260; 440; 586; 656; 871; 203; 484; 264; 685; 312; 169; 684; 276; 685; 371; 295; 30; 795; 563; 787; 756; 18; 443; 661; 165; 218; 65; 871; 932; 21; 474; 808; 862; 78; 527; 545; 731; 911; 835; 932; 930; 237; 111; 607; 560; 298; 841; 224; 30; 574; 958; 644; 416; 799; 3; 174; 171; 660; 91; 147; 782; 611; 388; 953; 38; 926; 242; 982; 519; 152; 990; 800; 567; 22; 115; 649; 155; 233; 191; 367; 595; 713; 507; 930; 989; 6; 315; 316; 851; 113; 561; 116; 309; 243; 84; 914; 526; 442; 653; 404; 265; 898; 158; 174; 10; 754; 163; 548; 381; 446; 225; 135; 774; 924; 983; 515; 198; 849; 610; 168; 862; 283; 18; 921; 525; 138; 476; 526; 317; 692; 787; 793; 527; 703; 749; 483; 334; 813; 655; 416; 617; 103; 144; 710; 338; 587; 466; 52; 415; 992; 315; 743; 460; 71; 203; 621; 775; 620; 845; 365; 118; 329; 592; 425; 44; 524; 520; 549; 697; 143; 422; 31; 335; 739; 631; 873; 786; 28; 258; 790; 276; 289; 469; 268; 665; 70; 918; 879; 559; 890; 711; 616; 264; 731; 708; 566; 818; 37; 640; 605; 438; 669; 124; 489; 828; 873; 725; 746; 218; 668; 568; 199; 410; 969; 606; 714; 53; 54; 379; 510; 73; 511; 256; 761; 685; 870; 381; 885; 161; 62; 112; 231; 510; 925; 868; 182; 513; 984; 244; 932; 942; 974; 434; 704; 696; 803; 731; 230; 6; 213; 525; 347; 825; 525; 457; 611; 62; 907; 541; 717; 238; 196; 555; 545; 978; 435; 295; 269; 280; 4; 357; 780; 898; 400; 839; 856; 15; 14; 671; 406; 61; 830; 552; 614; 294; 766; 227; 734; 10; 327; 546; 614; 462; 367; 17; 762; 463; 997; 922; 441; 836; 714; 112; 177; 288; 962; 655; 711; 790; 498; 597; 923; 780; 539; 873; 611; 493; 848; 24; 151; 288; 138; 948; 256; 571; 871; 930; 662; 56; 799; 301; 178; 249; 788; 329; 624; 265; 900; 133; 129; 919; 754; 535; 833; 71; 63; 540; 239; 701; 219; 888; 615; 732; 362; 750; 530; 980; 340; 370; 199; 935; 417; 734; 63; 469; 740; 569; 107; 729; 631; 636; 330; 215; 25; 191; 976; 604; 971; 987; 296; 945; 234; 136; 893; 233; 272; 298; 726; 857; 619; 491; 578; 641; 416; 772; 631; 410; 904; 798; 421; 959; 308; 593; 759; 756; 502; 997; 540; 750; 137; 199; 232; 426; 421; 255; 669; 253; 598; 109; 412; 144; 837; 256; 725; 813; 644; 321; 824; 708; 608; 180; 249; 877; 158; 102; 810; 331; 867; 605; 366; 31; 881; 198; 892; 974; 728; 380; 983; 107; 946; 618; 11; 632; 149; 730; 295; 662; 101; 120; 717; 935; 672; 990; 383; 146; 799; 987; 235; 998; 587; 549; 738; 314; 155]\n\nlet my_fast_index_internal (n:nat{n < 1000}) : int = if n < 500 then (if n < 250 then (if n < 125 then (if n < 62 then (if n < 31 then (if n < 15 then (if n < 7 then (if n < 3 then (if n < 1 then 865 else (if n < 2 then 415 else 194)) else (if n < 5 then (if n < 4 then 337 else 607) else (if n < 6 then 744 else 992))) else (if n < 11 then (if n < 9 then (if n < 8 then 113 else 234) else (if n < 10 then 8 else 996)) else (if n < 13 then (if n < 12 then 829 else 365) else (if n < 14 then 465 else 639)))) else (if n < 23 then (if n < 19 then (if n < 17 then (if n < 16 then 869 else 433) else (if n < 18 then 726 else 351)) else (if n < 21 then (if n < 20 then 812 else 335) else (if n < 22 then 542 else 738))) else (if n < 27 then (if n < 25 then (if n < 24 then 38 else 369) else (if n < 26 then 602 else 396)) else (if n < 29 then (if n < 28 then 833 else 772) else (if n < 30 then 728 else 431))))) else (if n < 46 then (if n < 38 then (if n < 34 then (if n < 32 then 95 else (if n < 33 then 456 else 48)) else (if n < 36 then (if n < 35 then 815 else 439) else (if n < 37 then 909 else 154))) else (if n < 42 then (if n < 40 then (if n < 39 then 685 else 871) else (if n < 41 then 990 else 352)) else (if n < 44 then (if n < 43 then 665 else 838) else (if n < 45 then 274 else 351)))) else (if n < 54 then (if n < 50 then (if n < 48 then (if n < 47 then 38 else 999) else (if n < 49 then 333 else 11)) else (if n < 52 then (if n < 51 then 974 else 569) else (if n < 53 then 17 else 897))) else (if n < 58 then (if n < 56 then (if n < 55 then 778 else 53) else (if n < 57 then 941 else 462)) else (if n < 60 then (if n < 59 then 458 else 44) else (if n < 61 then 814 else 33)))))) else (if n < 93 then (if n < 77 then (if n < 69 then (if n < 65 then (if n < 63 then 686 else (if n < 64 then 93 else 31)) else (if n < 67 then (if n < 66 then 876 else 970) else (if n < 68 then 269 else 517))) else (if n < 73 then (if n < 71 then (if n < 70 then 770 else 748) else (if n < 72 then 1 else 892)) else (if n < 75 then (if n < 74 then 638 else 159) else (if n < 76 then 548 else 888)))) else (if n < 85 then (if n < 81 then (if n < 79 then (if n < 78 then 421 else 411) else (if n < 80 then 147 else 172)) else (if n < 83 then (if n < 82 then 647 else 588) else (if n < 84 then 1 else 191))) else (if n < 89 then (if n < 87 then (if n < 86 then 470 else 896) else (if n < 88 then 721 else 901)) else (if n < 91 then (if n < 90 then 516 else 293) else (if n < 92 then 153 else 57))))) else (if n < 109 then (if n < 101 then (if n < 97 then (if n < 95 then (if n < 94 then 131 else 932) else (if n < 96 then 252 else 511)) else (if n < 99 then (if n < 98 then 574 else 748) else (if n < 100 then 658 else 750))) else (if n < 105 then (if n < 103 then (if n < 102 then 235 else 756) else (if n < 104 then 776 else 534)) else (if n < 107 then (if n < 106 then 656 else 479) else (if n < 108 then 925 else 800)))) else (if n < 117 then (if n < 113 then (if n < 111 then (if n < 110 then 699 else 30) else (if n < 112 then 385 else 966)) else (if n < 115 then (if n < 114 then 690 else 875) else (if n < 116 then 798 else 867))) else (if n < 121 then (if n < 119 then (if n < 118 then 320 else 156) else (if n < 120 then 640 else 449)) else (if n < 123 then (if n < 122 then 445 else 975) else (if n < 124 then 518 else 120))))))) else (if n < 187 then (if n < 156 then (if n < 140 then (if n < 132 then (if n < 128 then (if n < 126 then 554 else (if n < 127 then 741 else 321)) else (if n < 130 then (if n < 129 then 477 else 319) else (if n < 131 then 216 else 5))) else (if n < 136 then (if n < 134 then (if n < 133 then 269 else 997) else (if n < 135 then 804 else 139)) else (if n < 138 then (if n < 137 then 27 else 433) else (if n < 139 then 167 else 704)))) else (if n < 148 then (if n < 144 then (if n < 142 then (if n < 141 then 155 else 454) else (if n < 143 then 995 else 862)) else (if n < 146 then (if n < 145 then 276 else 459) else (if n < 147 then 275 else 795))) else (if n < 152 then (if n < 150 then (if n < 149 then 360 else 338) else (if n < 151 then 354 else 687)) else (if n < 154 then (if n < 153 then 132 else 999) else (if n < 155 then 346 else 108))))) else (if n < 171 then (if n < 163 then (if n < 159 then (if n < 157 then 188 else (if n < 158 then 387 else 705)) else (if n < 161 then (if n < 160 then 928 else 510) else (if n < 162 then 756 else 891))) else (if n < 167 then (if n < 165 then (if n < 164 then 646 else 262) else (if n < 166 then 962 else 381)) else (if n < 169 then (if n < 168 then 967 else 485) else (if n < 170 then 871 else 339)))) else (if n < 179 then (if n < 175 then (if n < 173 then (if n < 172 then 582 else 505) else (if n < 174 then 530 else 867)) else (if n < 177 then (if n < 176 then 85 else 224) else (if n < 178 then 107 else 558))) else (if n < 183 then (if n < 181 then (if n < 180 then 609 else 167) else (if n < 182 then 650 else 573)) else (if n < 185 then (if n < 184 then 749 else 910) else (if n < 186 then 492 else 300)))))) else (if n < 218 then (if n < 202 then (if n < 194 then (if n < 190 then (if n < 188 then 542 else (if n < 189 then 989 else 264)) else (if n < 192 then (if n < 191 then 778 else 160) else (if n < 193 then 508 else 346))) else (if n < 198 then (if n < 196 then (if n < 195 then 853 else 378) else (if n < 197 then 76 else 213)) else (if n < 200 then (if n < 199 then 784 else 212) else (if n < 201 then 976 else 580)))) else (if n < 210 then (if n < 206 then (if n < 204 then (if n < 203 then 230 else 103) else (if n < 205 then 282 else 527)) else (if n < 208 then (if n < 207 then 881 else 508) else (if n < 209 then 219 else 613))) else (if n < 214 then (if n < 212 then (if n < 211 then 904 else 147) else (if n < 213 then 298 else 978)) else (if n < 216 then (if n < 215 then 9 else 715) else (if n < 217 then 1 else 190))))) else (if n < 234 then (if n < 226 then (if n < 222 then (if n < 220 then (if n < 219 then 883 else 360) else (if n < 221 then 966 else 508)) else (if n < 224 then (if n < 223 then 49 else 945) else (if n < 225 then 360 else 290))) else (if n < 230 then (if n < 228 then (if n < 227 then 352 else 813) else (if n < 229 then 172 else 938)) else (if n < 232 then (if n < 231 then 930 else 110) else (if n < 233 then 385 else 350)))) else (if n < 242 then (if n < 238 then (if n < 236 then (if n < 235 then 582 else 310) else (if n < 237 then 303 else 397)) else (if n < 240 then (if n < 239 then 755 else 181) else (if n < 241 then 835 else 393))) else (if n < 246 then (if n < 244 then (if n < 243 then 41 else 251) else (if n < 245 then 747 else 511)) else (if n < 248 then (if n < 247 then 454 else 239) else (if n < 249 then 154 else 154)))))))) else (if n < 375 then (if n < 312 then (if n < 281 then (if n < 265 then (if n < 257 then (if n < 253 then (if n < 251 then 508 else (if n < 252 then 851 else 574)) else (if n < 255 then (if n < 254 then 599 else 532) else (if n < 256 then 576 else 827))) else (if n < 261 then (if n < 259 then (if n < 258 then 245 else 424) else (if n < 260 then 502 else 303)) else (if n < 263 then (if n < 262 then 872 else 854) else (if n < 264 then 434 else 327)))) else (if n < 273 then (if n < 269 then (if n < 267 then (if n < 266 then 825 else 664) else (if n < 268 then 386 else 826)) else (if n < 271 then (if n < 270 then 637 else 700) else (if n < 272 then 858 else 435))) else (if n < 277 then (if n < 275 then (if n < 274 then 960 else 223) else (if n < 276 then 326 else 872)) else (if n < 279 then (if n < 278 then 675 else 260) else (if n < 280 then 880 else 882))))) else (if n < 296 then (if n < 288 then (if n < 284 then (if n < 282 then 486 else (if n < 283 then 601 else 587)) else (if n < 286 then (if n < 285 then 22 else 311) else (if n < 287 then 2 else 472))) else (if n < 292 then (if n < 290 then (if n < 289 then 356 else 275) else (if n < 291 then 161 else 864)) else (if n < 294 then (if n < 293 then 199 else 46) else (if n < 295 then 641 else 698)))) else (if n < 304 then (if n < 300 then (if n < 298 then (if n < 297 then 333 else 917) else (if n < 299 then 706 else 376)) else (if n < 302 then (if n < 301 then 52 else 228) else (if n < 303 then 907 else 264))) else (if n < 308 then (if n < 306 then (if n < 305 then 962 else 741) else (if n < 307 then 435 else 383)) else (if n < 310 then (if n < 309 then 513 else 231) else (if n < 311 then 112 else 929)))))) else (if n < 343 then (if n < 327 then (if n < 319 then (if n < 315 then (if n < 313 then 252 else (if n < 314 then 664 else 943)) else (if n < 317 then (if n < 316 then 357 else 304) else (if n < 318 then 446 else 748))) else (if n < 323 then (if n < 321 then (if n < 320 then 384 else 686) else (if n < 322 then 53 else 112)) else (if n < 325 then (if n < 324 then 403 else 444) else (if n < 326 then 828 else 569)))) else (if n < 335 then (if n < 331 then (if n < 329 then (if n < 328 then 435 else 726) else (if n < 330 then 570 else 415)) else (if n < 333 then (if n < 332 then 369 else 395) else (if n < 334 then 838 else 561))) else (if n < 339 then (if n < 337 then (if n < 336 then 795 else 550) else (if n < 338 then 163 else 28)) else (if n < 341 then (if n < 340 then 278 else 598) else (if n < 342 then 248 else 223))))) else (if n < 359 then (if n < 351 then (if n < 347 then (if n < 345 then (if n < 344 then 815 else 133) else (if n < 346 then 134 else 8)) else (if n < 349 then (if n < 348 then 55 else 792) else (if n < 350 then 329 else 868))) else (if n < 355 then (if n < 353 then (if n < 352 then 70 else 206) else (if n < 354 then 46 else 118)) else (if n < 357 then (if n < 356 then 12 else 231) else (if n < 358 then 180 else 98)))) else (if n < 367 then (if n < 363 then (if n < 361 then (if n < 360 then 226 else 64) else (if n < 362 then 784 else 777)) else (if n < 365 then (if n < 364 then 58 else 971) else (if n < 366 then 355 else 569))) else (if n < 371 then (if n < 369 then (if n < 368 then 992 else 801) else (if n < 370 then 516 else 72)) else (if n < 373 then (if n < 372 then 909 else 773) else (if n < 374 then 168 else 680))))))) else (if n < 437 then (if n < 406 then (if n < 390 then (if n < 382 then (if n < 378 then (if n < 376 then 562 else (if n < 377 then 49 else 137)) else (if n < 380 then (if n < 379 then 442 else 793) else (if n < 381 then 429 else 201))) else (if n < 386 then (if n < 384 then (if n < 383 then 280 else 687) else (if n < 385 then 956 else 388)) else (if n < 388 then (if n < 387 then 830 else 453) else (if n < 389 then 456 else 695)))) else (if n < 398 then (if n < 394 then (if n < 392 then (if n < 391 then 359 else 417) else (if n < 393 then 331 else 643)) else (if n < 396 then (if n < 395 then 865 else 167) else (if n < 397 then 644 else 375))) else (if n < 402 then (if n < 400 then (if n < 399 then 639 else 72) else (if n < 401 then 197 else 854)) else (if n < 404 then (if n < 403 then 725 else 569) else (if n < 405 then 356 else 939))))) else (if n < 421 then (if n < 413 then (if n < 409 then (if n < 407 then 551 else (if n < 408 then 135 else 886)) else (if n < 411 then (if n < 410 then 80 else 714) else (if n < 412 then 483 else 315))) else (if n < 417 then (if n < 415 then (if n < 414 then 897 else 496) else (if n < 416 then 300 else 502)) else (if n < 419 then (if n < 418 then 726 else 777) else (if n < 420 then 571 else 611)))) else (if n < 429 then (if n < 425 then (if n < 423 then (if n < 422 then 353 else 776) else (if n < 424 then 487 else 412)) else (if n < 427 then (if n < 426 then 852 else 495) else (if n < 428 then 255 else 749))) else (if n < 433 then (if n < 431 then (if n < 430 then 301 else 300) else (if n < 432 then 803 else 213)) else (if n < 435 then (if n < 434 then 499 else 546) else (if n < 436 then 278 else 7)))))) else (if n < 468 then (if n < 452 then (if n < 444 then (if n < 440 then (if n < 438 then 267 else (if n < 439 then 871 else 963)) else (if n < 442 then (if n < 441 then 709 else 326) else (if n < 443 then 877 else 655))) else (if n < 448 then (if n < 446 then (if n < 445 then 929 else 860) else (if n < 447 then 949 else 903)) else (if n < 450 then (if n < 449 then 160 else 731) else (if n < 451 then 116 else 393)))) else (if n < 460 then (if n < 456 then (if n < 454 then (if n < 453 then 713 else 499) else (if n < 455 then 331 else 25)) else (if n < 458 then (if n < 457 then 257 else 648) else (if n < 459 then 341 else 54))) else (if n < 464 then (if n < 462 then (if n < 461 then 654 else 714) else (if n < 463 then 227 else 995)) else (if n < 466 then (if n < 465 then 792 else 698) else (if n < 467 then 442 else 835))))) else (if n < 484 then (if n < 476 then (if n < 472 then (if n < 470 then (if n < 469 then 526 else 660) else (if n < 471 then 751 else 962)) else (if n < 474 then (if n < 473 then 186 else 699) else (if n < 475 then 753 else 385))) else (if n < 480 then (if n < 478 then (if n < 477 then 477 else 686) else (if n < 479 then 477 else 322)) else (if n < 482 then (if n < 481 then 201 else 360) else (if n < 483 then 344 else 766)))) else (if n < 492 then (if n < 488 then (if n < 486 then (if n < 485 then 942 else 985) else (if n < 487 then 328 else 98)) else (if n < 490 then (if n < 489 then 475 else 520) else (if n < 491 then 257 else 864))) else (if n < 496 then (if n < 494 then (if n < 493 then 560 else 725) else (if n < 495 then 302 else 305)) else (if n < 498 then (if n < 497 then 670 else 317) else (if n < 499 then 642 else 959))))))))) else (if n < 750 then (if n < 625 then (if n < 562 then (if n < 531 then (if n < 515 then (if n < 507 then (if n < 503 then (if n < 501 then 25 else (if n < 502 then 607 else 97)) else (if n < 505 then (if n < 504 then 669 else 387) else (if n < 506 then 968 else 620))) else (if n < 511 then (if n < 509 then (if n < 508 then 931 else 948) else (if n < 510 then 23 else 638)) else (if n < 513 then (if n < 512 then 443 else 778) else (if n < 514 then 885 else 950)))) else (if n < 523 then (if n < 519 then (if n < 517 then (if n < 516 then 706 else 93) else (if n < 518 then 613 else 601)) else (if n < 521 then (if n < 520 then 513 else 810) else (if n < 522 then 707 else 536))) else (if n < 527 then (if n < 525 then (if n < 524 then 897 else 400) else (if n < 526 then 530 else 260)) else (if n < 529 then (if n < 528 then 440 else 586) else (if n < 530 then 656 else 871))))) else (if n < 546 then (if n < 538 then (if n < 534 then (if n < 532 then 203 else (if n < 533 then 484 else 264)) else (if n < 536 then (if n < 535 then 685 else 312) else (if n < 537 then 169 else 684))) else (if n < 542 then (if n < 540 then (if n < 539 then 276 else 685) else (if n < 541 then 371 else 295)) else (if n < 544 then (if n < 543 then 30 else 795) else (if n < 545 then 563 else 787)))) else (if n < 554 then (if n < 550 then (if n < 548 then (if n < 547 then 756 else 18) else (if n < 549 then 443 else 661)) else (if n < 552 then (if n < 551 then 165 else 218) else (if n < 553 then 65 else 871))) else (if n < 558 then (if n < 556 then (if n < 555 then 932 else 21) else (if n < 557 then 474 else 808)) else (if n < 560 then (if n < 559 then 862 else 78) else (if n < 561 then 527 else 545)))))) else (if n < 593 then (if n < 577 then (if n < 569 then (if n < 565 then (if n < 563 then 731 else (if n < 564 then 911 else 835)) else (if n < 567 then (if n < 566 then 932 else 930) else (if n < 568 then 237 else 111))) else (if n < 573 then (if n < 571 then (if n < 570 then 607 else 560) else (if n < 572 then 298 else 841)) else (if n < 575 then (if n < 574 then 224 else 30) else (if n < 576 then 574 else 958)))) else (if n < 585 then (if n < 581 then (if n < 579 then (if n < 578 then 644 else 416) else (if n < 580 then 799 else 3)) else (if n < 583 then (if n < 582 then 174 else 171) else (if n < 584 then 660 else 91))) else (if n < 589 then (if n < 587 then (if n < 586 then 147 else 782) else (if n < 588 then 611 else 388)) else (if n < 591 then (if n < 590 then 953 else 38) else (if n < 592 then 926 else 242))))) else (if n < 609 then (if n < 601 then (if n < 597 then (if n < 595 then (if n < 594 then 982 else 519) else (if n < 596 then 152 else 990)) else (if n < 599 then (if n < 598 then 800 else 567) else (if n < 600 then 22 else 115))) else (if n < 605 then (if n < 603 then (if n < 602 then 649 else 155) else (if n < 604 then 233 else 191)) else (if n < 607 then (if n < 606 then 367 else 595) else (if n < 608 then 713 else 507)))) else (if n < 617 then (if n < 613 then (if n < 611 then (if n < 610 then 930 else 989) else (if n < 612 then 6 else 315)) else (if n < 615 then (if n < 614 then 316 else 851) else (if n < 616 then 113 else 561))) else (if n < 621 then (if n < 619 then (if n < 618 then 116 else 309) else (if n < 620 then 243 else 84)) else (if n < 623 then (if n < 622 then 914 else 526) else (if n < 624 then 442 else 653))))))) else (if n < 687 then (if n < 656 then (if n < 640 then (if n < 632 then (if n < 628 then (if n < 626 then 404 else (if n < 627 then 265 else 898)) else (if n < 630 then (if n < 629 then 158 else 174) else (if n < 631 then 10 else 754))) else (if n < 636 then (if n < 634 then (if n < 633 then 163 else 548) else (if n < 635 then 381 else 446)) else (if n < 638 then (if n < 637 then 225 else 135) else (if n < 639 then 774 else 924)))) else (if n < 648 then (if n < 644 then (if n < 642 then (if n < 641 then 983 else 515) else (if n < 643 then 198 else 849)) else (if n < 646 then (if n < 645 then 610 else 168) else (if n < 647 then 862 else 283))) else (if n < 652 then (if n < 650 then (if n < 649 then 18 else 921) else (if n < 651 then 525 else 138)) else (if n < 654 then (if n < 653 then 476 else 526) else (if n < 655 then 317 else 692))))) else (if n < 671 then (if n < 663 then (if n < 659 then (if n < 657 then 787 else (if n < 658 then 793 else 527)) else (if n < 661 then (if n < 660 then 703 else 749) else (if n < 662 then 483 else 334))) else (if n < 667 then (if n < 665 then (if n < 664 then 813 else 655) else (if n < 666 then 416 else 617)) else (if n < 669 then (if n < 668 then 103 else 144) else (if n < 670 then 710 else 338)))) else (if n < 679 then (if n < 675 then (if n < 673 then (if n < 672 then 587 else 466) else (if n < 674 then 52 else 415)) else (if n < 677 then (if n < 676 then 992 else 315) else (if n < 678 then 743 else 460))) else (if n < 683 then (if n < 681 then (if n < 680 then 71 else 203) else (if n < 682 then 621 else 775)) else (if n < 685 then (if n < 684 then 620 else 845) else (if n < 686 then 365 else 118)))))) else (if n < 718 then (if n < 702 then (if n < 694 then (if n < 690 then (if n < 688 then 329 else (if n < 689 then 592 else 425)) else (if n < 692 then (if n < 691 then 44 else 524) else (if n < 693 then 520 else 549))) else (if n < 698 then (if n < 696 then (if n < 695 then 697 else 143) else (if n < 697 then 422 else 31)) else (if n < 700 then (if n < 699 then 335 else 739) else (if n < 701 then 631 else 873)))) else (if n < 710 then (if n < 706 then (if n < 704 then (if n < 703 then 786 else 28) else (if n < 705 then 258 else 790)) else (if n < 708 then (if n < 707 then 276 else 289) else (if n < 709 then 469 else 268))) else (if n < 714 then (if n < 712 then (if n < 711 then 665 else 70) else (if n < 713 then 918 else 879)) else (if n < 716 then (if n < 715 then 559 else 890) else (if n < 717 then 711 else 616))))) else (if n < 734 then (if n < 726 then (if n < 722 then (if n < 720 then (if n < 719 then 264 else 731) else (if n < 721 then 708 else 566)) else (if n < 724 then (if n < 723 then 818 else 37) else (if n < 725 then 640 else 605))) else (if n < 730 then (if n < 728 then (if n < 727 then 438 else 669) else (if n < 729 then 124 else 489)) else (if n < 732 then (if n < 731 then 828 else 873) else (if n < 733 then 725 else 746)))) else (if n < 742 then (if n < 738 then (if n < 736 then (if n < 735 then 218 else 668) else (if n < 737 then 568 else 199)) else (if n < 740 then (if n < 739 then 410 else 969) else (if n < 741 then 606 else 714))) else (if n < 746 then (if n < 744 then (if n < 743 then 53 else 54) else (if n < 745 then 379 else 510)) else (if n < 748 then (if n < 747 then 73 else 511) else (if n < 749 then 256 else 761)))))))) else (if n < 875 then (if n < 812 then (if n < 781 then (if n < 765 then (if n < 757 then (if n < 753 then (if n < 751 then 685 else (if n < 752 then 870 else 381)) else (if n < 755 then (if n < 754 then 885 else 161) else (if n < 756 then 62 else 112))) else (if n < 761 then (if n < 759 then (if n < 758 then 231 else 510) else (if n < 760 then 925 else 868)) else (if n < 763 then (if n < 762 then 182 else 513) else (if n < 764 then 984 else 244)))) else (if n < 773 then (if n < 769 then (if n < 767 then (if n < 766 then 932 else 942) else (if n < 768 then 974 else 434)) else (if n < 771 then (if n < 770 then 704 else 696) else (if n < 772 then 803 else 731))) else (if n < 777 then (if n < 775 then (if n < 774 then 230 else 6) else (if n < 776 then 213 else 525)) else (if n < 779 then (if n < 778 then 347 else 825) else (if n < 780 then 525 else 457))))) else (if n < 796 then (if n < 788 then (if n < 784 then (if n < 782 then 611 else (if n < 783 then 62 else 907)) else (if n < 786 then (if n < 785 then 541 else 717) else (if n < 787 then 238 else 196))) else (if n < 792 then (if n < 790 then (if n < 789 then 555 else 545) else (if n < 791 then 978 else 435)) else (if n < 794 then (if n < 793 then 295 else 269) else (if n < 795 then 280 else 4)))) else (if n < 804 then (if n < 800 then (if n < 798 then (if n < 797 then 357 else 780) else (if n < 799 then 898 else 400)) else (if n < 802 then (if n < 801 then 839 else 856) else (if n < 803 then 15 else 14))) else (if n < 808 then (if n < 806 then (if n < 805 then 671 else 406) else (if n < 807 then 61 else 830)) else (if n < 810 then (if n < 809 then 552 else 614) else (if n < 811 then 294 else 766)))))) else (if n < 843 then (if n < 827 then (if n < 819 then (if n < 815 then (if n < 813 then 227 else (if n < 814 then 734 else 10)) else (if n < 817 then (if n < 816 then 327 else 546) else (if n < 818 then 614 else 462))) else (if n < 823 then (if n < 821 then (if n < 820 then 367 else 17) else (if n < 822 then 762 else 463)) else (if n < 825 then (if n < 824 then 997 else 922) else (if n < 826 then 441 else 836)))) else (if n < 835 then (if n < 831 then (if n < 829 then (if n < 828 then 714 else 112) else (if n < 830 then 177 else 288)) else (if n < 833 then (if n < 832 then 962 else 655) else (if n < 834 then 711 else 790))) else (if n < 839 then (if n < 837 then (if n < 836 then 498 else 597) else (if n < 838 then 923 else 780)) else (if n < 841 then (if n < 840 then 539 else 873) else (if n < 842 then 611 else 493))))) else (if n < 859 then (if n < 851 then (if n < 847 then (if n < 845 then (if n < 844 then 848 else 24) else (if n < 846 then 151 else 288)) else (if n < 849 then (if n < 848 then 138 else 948) else (if n < 850 then 256 else 571))) else (if n < 855 then (if n < 853 then (if n < 852 then 871 else 930) else (if n < 854 then 662 else 56)) else (if n < 857 then (if n < 856 then 799 else 301) else (if n < 858 then 178 else 249)))) else (if n < 867 then (if n < 863 then (if n < 861 then (if n < 860 then 788 else 329) else (if n < 862 then 624 else 265)) else (if n < 865 then (if n < 864 then 900 else 133) else (if n < 866 then 129 else 919))) else (if n < 871 then (if n < 869 then (if n < 868 then 754 else 535) else (if n < 870 then 833 else 71)) else (if n < 873 then (if n < 872 then 63 else 540) else (if n < 874 then 239 else 701))))))) else (if n < 937 then (if n < 906 then (if n < 890 then (if n < 882 then (if n < 878 then (if n < 876 then 219 else (if n < 877 then 888 else 615)) else (if n < 880 then (if n < 879 then 732 else 362) else (if n < 881 then 750 else 530))) else (if n < 886 then (if n < 884 then (if n < 883 then 980 else 340) else (if n < 885 then 370 else 199)) else (if n < 888 then (if n < 887 then 935 else 417) else (if n < 889 then 734 else 63)))) else (if n < 898 then (if n < 894 then (if n < 892 then (if n < 891 then 469 else 740) else (if n < 893 then 569 else 107)) else (if n < 896 then (if n < 895 then 729 else 631) else (if n < 897 then 636 else 330))) else (if n < 902 then (if n < 900 then (if n < 899 then 215 else 25) else (if n < 901 then 191 else 976)) else (if n < 904 then (if n < 903 then 604 else 971) else (if n < 905 then 987 else 296))))) else (if n < 921 then (if n < 913 then (if n < 909 then (if n < 907 then 945 else (if n < 908 then 234 else 136)) else (if n < 911 then (if n < 910 then 893 else 233) else (if n < 912 then 272 else 298))) else (if n < 917 then (if n < 915 then (if n < 914 then 726 else 857) else (if n < 916 then 619 else 491)) else (if n < 919 then (if n < 918 then 578 else 641) else (if n < 920 then 416 else 772)))) else (if n < 929 then (if n < 925 then (if n < 923 then (if n < 922 then 631 else 410) else (if n < 924 then 904 else 798)) else (if n < 927 then (if n < 926 then 421 else 959) else (if n < 928 then 308 else 593))) else (if n < 933 then (if n < 931 then (if n < 930 then 759 else 756) else (if n < 932 then 502 else 997)) else (if n < 935 then (if n < 934 then 540 else 750) else (if n < 936 then 137 else 199)))))) else (if n < 968 then (if n < 952 then (if n < 944 then (if n < 940 then (if n < 938 then 232 else (if n < 939 then 426 else 421)) else (if n < 942 then (if n < 941 then 255 else 669) else (if n < 943 then 253 else 598))) else (if n < 948 then (if n < 946 then (if n < 945 then 109 else 412) else (if n < 947 then 144 else 837)) else (if n < 950 then (if n < 949 then 256 else 725) else (if n < 951 then 813 else 644)))) else (if n < 960 then (if n < 956 then (if n < 954 then (if n < 953 then 321 else 824) else (if n < 955 then 708 else 608)) else (if n < 958 then (if n < 957 then 180 else 249) else (if n < 959 then 877 else 158))) else (if n < 964 then (if n < 962 then (if n < 961 then 102 else 810) else (if n < 963 then 331 else 867)) else (if n < 966 then (if n < 965 then 605 else 366) else (if n < 967 then 31 else 881))))) else (if n < 984 then (if n < 976 then (if n < 972 then (if n < 970 then (if n < 969 then 198 else 892) else (if n < 971 then 974 else 728)) else (if n < 974 then (if n < 973 then 380 else 983) else (if n < 975 then 107 else 946))) else (if n < 980 then (if n < 978 then (if n < 977 then 618 else 11) else (if n < 979 then 632 else 149)) else (if n < 982 then (if n < 981 then 730 else 295) else (if n < 983 then 662 else 101)))) else (if n < 992 then (if n < 988 then (if n < 986 then (if n < 985 then 120 else 717) else (if n < 987 then 935 else 672)) else (if n < 990 then (if n < 989 then 990 else 383) else (if n < 991 then 146 else 799))) else (if n < 996 then (if n < 994 then (if n < 993 then 987 else 235) else (if n < 995 then 998 else 587)) else (if n < 998 then (if n < 997 then 549 else 738) else (if n < 999 then 314 else 155)))))))))\n\nlet my_fast_index_internal_is_index ()\n  : Lemma (length my_list = 1000 /\\ equivalent_to_index my_list my_fast_index_internal) =\n  assert (length my_list = 1000 /\\ equivalent_to_index my_list my_fast_index_internal)\n    by FStar.Tactics.V2.norm [zeta; delta; iota; primops]\n\nlet my_fast_index (n:nat{n < 1000}) : (result:int{n < length my_list /\\ index my_list n = result}) =\n  my_fast_index_internal_is_index ();\n  equivalent_to_index_implies_matches_index my_list my_fast_index_internal n;\n  my_fast_index_internal(n)\n"
  },
  {
    "path": "experimental/lib/MyProgramInvariant.fst",
    "content": "module MyProgramInvariant\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.BinaryOp\nopen Armada.Computation\nopen Armada.Expression\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Pointer\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Step\nopen Armada.Transition\nopen Armada.Type\nopen FStar.Sequence.Base\nopen Spec.Behavior\nopen Strategies.Atomic\nopen Strategies.Invariant\nopen Strategies.Invariant.Armada.Atomic\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\nopen Spec.List\nopen Spec.Ubool\nopen Util.List\n\nlet my_inv (s: Armada.State.t) : GTot ubool =\n  let root_one: root_t = RootGlobal (ObjectStorageAbstract int 1) in\n    s.mem (RootIdGlobal \"f\") == root_one\n  /\\ s.mem (RootIdGlobal \"g\") == root_one\n\n#push-options \"--z3rlimit 10 --z3cliopt smt.qi.eager_threshold=100\"\n\nprivate let atomic_lprog_init_establishes_my_inv\n  (s: Armada.State.t{(semantics_to_spec (make_atomic_semantics armada_semantics) MyAtomicLProg.prog).init s})\n  : squash (my_inv s) =\n  let initializer5: initializer_t =\n    { var_id = \"f\"; iv = InitializerSpecific (ObjectValueAbstract int 1); weakly_consistent = false; } in\n  assert (contains_ubool initializer5 MyLProg.prog.global_initializers)\n    by FStar.Tactics.V2.norm [delta];\n  let initializer6: initializer_t =\n    { var_id = \"g\"; iv = InitializerSpecific (ObjectValueAbstract int 1); weakly_consistent = false; } in\n  assert (contains_ubool initializer6 MyLProg.prog.global_initializers)\n    by FStar.Tactics.V2.norm [delta];\n  ()\n\n#pop-options\n\nprivate let my_action_pred (action: Armada.Action.t) : GTot ubool =\n    (not action.ok)\n  \\/ (match action.program_statement.statement with\n     | UpdateStatement bypassing_write_buffer dst src ->\n           bypassing_write_buffer = false\n         /\\ (match dst with\n            | ExpressionGlobalVariable _ v -> v <> \"f\" && v <> \"g\"\n            | _ -> False)\n     | _ -> False)\n\n#push-options \"--z3rlimit 10 --z3cliopt smt.qi.eager_threshold=100\"\n\nprivate let my_action_pred_preserves_my_inv\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (step: Armada.Step.t)\n  (s: Armada.State.t{\n      Some? (step_computation actor starts_atomic_block ends_atomic_block step s)\n    /\\ my_action_pred step.action\n    /\\ my_inv s})\n  : squash (my_inv (Some?.v (step_computation actor starts_atomic_block ends_atomic_block step s))) =\n  ()\n\n#pop-options\n\nprivate let my_divide_by_one_special_case_atomic_action : list Armada.Action.t =\n  [ { ok = true;\n      program_statement = { start_pc = Some \"main.4\";\n                            end_pc = Some \"main.5\";\n                            starts_atomic_block = true;\n                            ends_atomic_block = true;\n                            statement = UpdateStatement false\n                              (ExpressionGlobalVariable (ObjectTDAbstract int) \"f\")\n                              (ExpressionBinaryOperator\n                                (ObjectTDAbstract int) (ObjectTDAbstract int) (ObjectTDAbstract int) BinaryOpDivInt\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"f\")\n                                (ExpressionGlobalVariable (ObjectTDAbstract int) \"f\")); } } ]\n\n#push-options \"--z3rlimit 10 --z3cliopt smt.qi.eager_threshold=100\"\n\nprivate let my_divide_by_one_special_case_proof\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (atomic_step: list Armada.Step.t)\n  (s: Armada.State.t{\n       map_ghost armada_step_to_action atomic_step == my_divide_by_one_special_case_atomic_action\n     /\\ my_inv s\n     /\\ Some? (steps_computation actor starts_atomic_block ends_atomic_block atomic_step s)})\n  : squash (my_inv (Some?.v (steps_computation actor starts_atomic_block ends_atomic_block atomic_step s))) =\n  (* SMT automatically figures out that dividing value #5 by itself preserves the invariant that\n     value #5 is 1. *)\n  ()\n\n#pop-options\n\nprivate let my_special_case_proof: armada_atomic_special_case_invariant_proof_t my_inv =\n  ArmadaAtomicSpecialCaseInvariantProof my_divide_by_one_special_case_atomic_action my_divide_by_one_special_case_proof\n\nprivate let my_special_case_proofs\n  : list (option (armada_atomic_special_case_invariant_proof_t my_inv)) =\n  [\n    None;\n    None;\n    None;\n    None;\n    None;\n    None;\n    Some (ArmadaAtomicSpecialCaseInvariantProof my_divide_by_one_special_case_atomic_action\n            my_divide_by_one_special_case_proof);\n    None\n  ]\n\nlet my_inv_witness () : armada_atomic_semantics_invariant_witness_t MyAtomicLProg.prog my_inv =\n  {\n    action_pred = my_action_pred;\n    special_case_proofs = my_special_case_proofs;\n    init_implies_inv_proof = atomic_lprog_init_establishes_my_inv;\n    action_proof = my_action_pred_preserves_my_inv;\n  }\n\nlet my_inv_is_stepwise_invariant ()\n  : Lemma (semantics_has_stepwise_inductive_invariant (make_atomic_semantics armada_semantics)\n             MyAtomicLProg.prog my_inv) =\n  let aiw = my_inv_witness () in\n  assert (armada_atomic_semantics_invariant_witness_valid MyAtomicLProg.prog my_inv aiw)\n    by (FStar.Tactics.V2.compute (); FStar.Tactics.V2.trivial ());\n  armada_atomic_semantics_invariant_witness_valid_implies_stepwise_invariant MyAtomicLProg.prog my_inv aiw\n"
  },
  {
    "path": "experimental/lib/MyProgramProof.fst",
    "content": "module MyProgramProof\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Expression\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Transition\nopen Armada.Type\nopen FStar.List.Tot.Base\nopen FStar.Tactics.V2\nopen MyAtomicToRegularRefinement\nopen MyProgramInvariant\nopen MyRegularToAtomicRefinement\nopen Spec.Behavior\nopen Spec.List\nopen Spec.Ubool\nopen Strategies.Atomic\nopen Strategies.Invariant\nopen Strategies.Invariant.Armada.Atomic\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\nopen Strategies.Weakening.Armada\nopen Util.Behavior\nopen Util.ImmutableArray\nopen Util.List\n\nprivate let my_special_case_action_0 : list Armada.Action.t =\n  [ { ok = true;\n      program_statement = { start_pc = Some \"main.0\"; end_pc = Some \"main.1\"; starts_atomic_block = true;\n                            ends_atomic_block = true;\n                            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"e\")\n                                          (ExpressionGlobalVariable (ObjectTDAbstract int) \"f\"); } } ]\n\nprivate let my_special_case_action_1 : list Armada.Action.t =\n  [ { ok = false;\n      program_statement = { start_pc = Some \"main.0\"; end_pc = Some \"main.1\"; starts_atomic_block = true;\n                            ends_atomic_block = true;\n                            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"e\")\n                                          (ExpressionGlobalVariable (ObjectTDAbstract int) \"f\"); } } ]\n\nprivate let my_special_case_steps_updater_0\n  (actor: tid_t)\n  (steps: list Armada.Step.t)\n  (s: Armada.State.t)\n  : nat * (list Armada.Step.t) =\n  let step: Armada.Step.t = {\n    nd = [];\n    action = {\n      ok = true;\n      program_statement = { start_pc = Some \"main.0\"; end_pc = Some \"main.1\"; starts_atomic_block = true;\n                            ends_atomic_block = true;\n                            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"e\")\n                                          (ExpressionGlobalVariable (ObjectTDAbstract int) \"g\"); }\n    }\n  } in\n  (0, [step]) // this atomic action is the 0th one in the list of MyAtomicHProg.prog.actions\n\nprivate let my_special_case_steps_updater_1\n  (actor: tid_t)\n  (steps: list Armada.Step.t)\n  (s: Armada.State.t)\n  : nat * (list Armada.Step.t) =\n  let step: Armada.Step.t = {\n    nd = [];\n    action = {\n      ok = false;\n      program_statement = { start_pc = Some \"main.0\"; end_pc = Some \"main.1\"; starts_atomic_block = true;\n                            ends_atomic_block = true;\n                            statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"e\")\n                                          (ExpressionGlobalVariable (ObjectTDAbstract int) \"g\"); }\n    }\n  } in\n  (1, [step]) // this atomic action is the 1st one in the list of MyAtomicHProg.prog.actions\n\n#push-options \"--z3rlimit 10 --fuel 4\"\n\nprivate let my_special_case_steps_updater_satisfies_weakening_0\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (lsteps: list Armada.Step.t)\n  (haction_index: nat)\n  (hsteps: list Armada.Step.t)\n  (s: Armada.State.t)\n  : Lemma (requires   (FStar.List.Tot.map armada_step_to_action lsteps == my_special_case_action_0)\n                    /\\ (my_inv s)\n                    /\\ (Some? (steps_computation actor starts_atomic_block ends_atomic_block lsteps s))\n                    /\\ ((haction_index, hsteps) == my_special_case_steps_updater_0 actor lsteps s))\n          (ensures  (  (Some? (steps_computation actor starts_atomic_block ends_atomic_block hsteps s))\n                     /\\ (steps_computation actor starts_atomic_block ends_atomic_block lsteps s ==\n                        steps_computation actor starts_atomic_block ends_atomic_block hsteps s)\n                     /\\ nth MyAtomicHProg.prog.actions haction_index ==\n                         Some (map_ghost armada_step_to_action hsteps))) =\n  ()\n\nprivate let my_special_case_steps_updater_satisfies_weakening_1\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (lsteps: list Armada.Step.t)\n  (haction_index: nat)\n  (hsteps: list Armada.Step.t)\n  (s: Armada.State.t)\n  : Lemma (requires   (FStar.List.Tot.map armada_step_to_action lsteps == my_special_case_action_1)\n                    /\\ (my_inv s)\n                    /\\ (Some? (steps_computation actor starts_atomic_block ends_atomic_block lsteps s))\n                    /\\ ((haction_index, hsteps) == my_special_case_steps_updater_1 actor lsteps s))\n          (ensures  (  (Some? (steps_computation actor starts_atomic_block ends_atomic_block hsteps s))\n                     /\\ (steps_computation actor starts_atomic_block ends_atomic_block lsteps s ==\n                        steps_computation actor starts_atomic_block ends_atomic_block hsteps s)\n                     /\\ nth MyAtomicHProg.prog.actions haction_index ==\n                         Some (map_ghost armada_step_to_action hsteps))) =\n  ()\n\n#pop-options\n\nprivate let my_special_case_steps_updater_works_0 ()\n  : squash (armada_steps_updater_works (list_to_array MyAtomicHProg.prog.actions) my_inv my_special_case_action_0\n              my_special_case_steps_updater_0) =\n  let hatomic_action_array = list_to_array MyAtomicHProg.prog.actions in\n  introduce forall (actor: tid_t) (starts_atomic_block: bool) (ends_atomic_block: bool) (lsteps: list Armada.Step.t)\n              (s: Armada.State.t).\n      map_ghost armada_step_to_action lsteps == my_special_case_action_0\n    /\\ my_inv s\n    /\\ Some? (steps_computation actor starts_atomic_block ends_atomic_block lsteps s)\n    ==> \n    (let hatomic_action_idx, hsteps = my_special_case_steps_updater_0 actor lsteps s in\n     let haction = map_ghost armada_step_to_action hsteps in\n       hatomic_action_idx < array_len hatomic_action_array\n     /\\ array_index hatomic_action_array hatomic_action_idx == haction\n     /\\ (steps_computation actor starts_atomic_block ends_atomic_block hsteps s ==\n        steps_computation actor starts_atomic_block ends_atomic_block lsteps s))\n  with introduce _ ==> _\n  with _.\n    let hatomic_action_idx, hsteps = my_special_case_steps_updater_0 actor lsteps s in\n    list_to_array_implies_nth_equivalent hatomic_action_array MyAtomicHProg.prog.actions hatomic_action_idx;\n    my_special_case_steps_updater_satisfies_weakening_0 actor starts_atomic_block ends_atomic_block\n      lsteps hatomic_action_idx hsteps s\n\nprivate let my_special_case_steps_updater_works_1 ()\n  : squash (armada_steps_updater_works (list_to_array MyAtomicHProg.prog.actions) my_inv my_special_case_action_1\n              my_special_case_steps_updater_1) =\n  let hatomic_action_array = list_to_array MyAtomicHProg.prog.actions in\n  introduce forall (actor: tid_t) (starts_atomic_block: bool) (ends_atomic_block: bool) (lsteps: list Armada.Step.t)\n              (s: Armada.State.t).\n      map_ghost armada_step_to_action lsteps == my_special_case_action_1\n    /\\ my_inv s\n    /\\ Some? (steps_computation actor starts_atomic_block ends_atomic_block lsteps s)\n    ==> \n    (let hatomic_action_idx, hsteps = my_special_case_steps_updater_1 actor lsteps s in\n     let haction = map_ghost armada_step_to_action hsteps in\n       hatomic_action_idx < array_len hatomic_action_array\n     /\\ array_index hatomic_action_array hatomic_action_idx == haction\n     /\\ (steps_computation actor starts_atomic_block ends_atomic_block hsteps s ==\n        steps_computation actor starts_atomic_block ends_atomic_block lsteps s))\n  with introduce _ ==> _\n  with _.\n    let hatomic_action_idx, hsteps = my_special_case_steps_updater_1 actor lsteps s in\n    list_to_array_implies_nth_equivalent hatomic_action_array MyAtomicHProg.prog.actions hatomic_action_idx;\n    my_special_case_steps_updater_satisfies_weakening_1 actor starts_atomic_block ends_atomic_block\n      lsteps hatomic_action_idx hsteps s\n\nprivate let my_weakening_transformers\n  : list (armada_weakening_transformer_t (list_to_array MyAtomicHProg.prog.actions) my_inv) =\n  [ ArmadaWeakeningTransformerUpdatedStep my_special_case_action_0 my_special_case_steps_updater_0\n                                            my_special_case_steps_updater_works_0;\n    ArmadaWeakeningTransformerUpdatedStep my_special_case_action_1 my_special_case_steps_updater_1\n                                            my_special_case_steps_updater_works_1;\n    ArmadaWeakeningTransformerSameStep 2;\n    ArmadaWeakeningTransformerSameStep 3;\n    ArmadaWeakeningTransformerSameStep 4;\n    ArmadaWeakeningTransformerSameStep 5;\n    ArmadaWeakeningTransformerSameStep 6;\n    ArmadaWeakeningTransformerSameStep 7 ]\n\nlet lemma_MyAtomicLProg_refines_MyAtomicHProg ()\n  : Lemma (spec_refines_spec\n           (semantics_to_spec (make_atomic_semantics armada_semantics) MyAtomicLProg.prog)\n           (semantics_to_spec (make_atomic_semantics armada_semantics) MyAtomicHProg.prog)\n           eq2) =\n  let ww: armada_weakening_witness_t MyAtomicLProg.prog MyAtomicHProg.prog = {\n    inv = my_inv;\n    hatomic_action_array = list_to_array MyAtomicHProg.prog.actions;\n    weakening_transformers = my_weakening_transformers;\n    init_implies_init_proof = (fun _ -> ());\n  } in\n  assert (armada_weakening_witness_valid MyAtomicLProg.prog MyAtomicHProg.prog ww)\n    by (compute (); trivial ());\n  my_inv_is_stepwise_invariant ();\n  armada_weakening_witness_valid_implies_refinement MyAtomicLProg.prog MyAtomicHProg.prog ww\n\nlet lemma_my_lprog_atomic_refines_my_hprog ()\n  : Lemma (spec_refines_spec\n           (program_to_spec MyLProg.prog)\n           (program_to_spec MyHProg.prog)\n           eq2) =\n  lemma_MyLProg_refines_MyAtomicLProg ();\n  lemma_MyAtomicLProg_refines_MyAtomicHProg ();\n  lemma_MyAtomicHProg_refines_MyHProg ();\n  spec_refinement_transitivity_4\n    (program_to_spec MyLProg.prog)\n    (semantics_to_spec (make_atomic_semantics armada_semantics) MyAtomicLProg.prog)\n    (semantics_to_spec (make_atomic_semantics armada_semantics) MyAtomicHProg.prog)\n    (program_to_spec MyHProg.prog)\n    eq2\n    eq2\n    eq2\n    eq2\n    eq2\n"
  },
  {
    "path": "experimental/lib/MyRegularToAtomicRefinement.fst",
    "content": "module MyRegularToAtomicRefinement\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.BinaryOp\nopen Armada.Expression\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Type\nopen FStar.Tactics.V2\nopen MyAtomicLProg\nopen MyLProg\nopen Spec.Behavior\nopen Spec.List\nopen Spec.Logic\nopen Spec.Ubool\nopen Strategies.Atomic\nopen Strategies.PCIndices\nopen Strategies.RegularToAtomic\nopen Strategies.RegularToAtomic.Armada\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\nopen Util.ImmutableArray\nopen Util.Nth\nopen Util.Range\n\n// This is all the PCs in the program.\n\nlet my_lpcs: array_t pc_t = list_to_array [ \"main.0\"; \"main.1\"; \"main.2\"; \"main.3\"; \"main.4\"; \"main.5\" ]\n\n// The start PC is \"main.0\", which is the 0th element of the my_lpcs array.\n\nlet my_lprog_main_start_pc_index = 0\n\n// Every PC is breaking except \"main.2\" and \"main.3\":\n\nlet my_pc_index_breaking : array_t bool = list_to_array [ true; true; false; false; true; true ]\n\n// The ten actions are:\n// 0 - ok = true, start_pc = \"main.0\", end_pc = \"main.1\"\n// 1 - ok = false, start_pc = \"main.0\", end_pc = \"main.1\"\n// 2 - ok = true, start_pc = \"main.1\", end_pc = \"main.2\"\n// 3 - ok = false, start_pc = \"main.1\", end_pc = \"main.2\"\n// 4 - ok = true, start_pc = \"main.2\", end_pc = \"main.3\"\n// 5 - ok = false, start_pc = \"main.2\", end_pc = \"main.3\"\n// 6 - ok = true, start_pc = \"main.3\", end_pc = \"main.4\"\n// 7 - ok = false, start_pc = \"main.3\", end_pc = \"main.4\"\n// 8 - ok = true, start_pc = \"main.4\", end_pc = \"main.5\"\n// 9 - ok = false, start_pc = \"main.4\", end_pc = \"main.5\"\n\nlet make_pc_indices (start_pc_index: nat) (end_pc_index: nat) : statement_pc_indices_t =\n  {\n    start_pc_index = Some start_pc_index;\n    end_pc_index = Some end_pc_index;\n    create_thread_initial_pc_index = None;\n    method_call_return_pc_index = None;\n  }\n\n// This array gives the indices of the PCs mentioned in the ten actions.\n// None of them are create-thread or method-call instructions, so they\n// always use None for the last two fields of each statement_pc_indices_t.\n\nlet my_pc_indices_array: array_t statement_pc_indices_t = list_to_array\n  [\n    make_pc_indices 0 1; // Action 0 goes from \"main.0\" to \"main.1\"\n    make_pc_indices 0 1; // Action 1 goes from \"main.0\" to \"main.1\"\n    make_pc_indices 1 2; // Action 2 goes from \"main.1\" to \"main.2\"\n    make_pc_indices 1 2; // Action 3 goes from \"main.1\" to \"main.2\"\n    make_pc_indices 2 3; // Action 4 goes from \"main.2\" to \"main.3\"\n    make_pc_indices 2 3; // Action 5 goes from \"main.2\" to \"main.3\"\n    make_pc_indices 3 4; // Action 6 goes from \"main.3\" to \"main.4\"\n    make_pc_indices 3 4; // Action 7 goes from \"main.3\" to \"main.4\"\n    make_pc_indices 4 5; // Action 8 goes from \"main.4\" to \"main.5\"\n    make_pc_indices 4 5  // Action 9 goes from \"main.4\" to \"main.5\"\n  ]\n\n// This is the list of action indices with a start_pc of None.  We don't have\n// any in this program because we don't include tau.\n\nlet my_action_indices_starting_at_no_pc: list nat = []\n\n// This is a list of, for each PC, the list of actions that start at that PC.\n\nlet my_action_indices_starting_at_pc_index: array_t (list nat) = list_to_array\n  [\n    [0; 1]; // The actions starting at \"main.0\" are actions 0 and 1\n    [2; 3]; // The actions starting at \"main.1\" are actions 2 and 3\n    [4; 5]; // The actions starting at \"main.2\" are actions 4 and 5\n    [6; 7]; // The actions starting at \"main.3\" are actions 6 and 7\n    [8; 9]; // The actions starting at \"main.4\" are actions 8 and 9\n    []      // The actions starting at \"main.5\" are <empty set>\n  ]\n\nlet make_successor_info (action_index: nat) (path_index: nat) : armada_successor_info_t =\n  {\n    action_index = action_index;\n    path_index = path_index;\n  }\n\nlet make_breaking_atomic_path_info\n  (path: list nat)\n  (atomic_action_index: nat)\n  : armada_atomic_path_info_t =\n  {\n    path = path;\n    atomic_action_index_or_successors = Inl atomic_action_index;\n  }\n\nlet make_incomplete_atomic_path_info\n  (path: list nat)\n  (successors: list armada_successor_info_t) =\n  {\n    path = path;\n    atomic_action_index_or_successors = Inr successors;\n  }\n\n// The following are all the paths, i.e., all the prefixes of atomic actions:\n\nlet my_atomic_path_infos: array_t armada_atomic_path_info_t = list_to_array\n  [\n    // Path 0:  Action 0 by itself is a full atomic action (#0)\n    make_breaking_atomic_path_info [0] 0;\n    // Path 1:  Action 1 by itself is a full atomic action (#1)\n    make_breaking_atomic_path_info [1] 1;\n    // Path 2:  Action 2 by itself doesn't break and can be succeeded by action 4 or 5,\n    //          producing path 6 or 7 respectively\n    make_incomplete_atomic_path_info [2] [make_successor_info 4 6; make_successor_info 5 7];\n    // Path 3:  Action 3 by itself is a full atomic action (#3)\n    make_breaking_atomic_path_info [3] 3;\n    // Path 4:  Action 8 by itself is a full atomic action (#6)\n    make_breaking_atomic_path_info [8] 6;\n    // Path 5:  Action 9 by itself is a full atomic action (#7)\n    make_breaking_atomic_path_info [9] 7;\n    // Path 6:  Actions 2 and 4 in succession don't break and can be succeeded by action 6 or 7,\n    //          producing path 8 or 9 respectively\n    make_incomplete_atomic_path_info [2; 4] [make_successor_info 6 8; make_successor_info 7 9];\n    // Path 7:  Actions 2 and 5 in succession constitute a full atomic action (#4)\n    make_breaking_atomic_path_info [2; 5] 4;\n    // Path 8:  Actions 2, 4, and 6 in succession constitute a full atomic action (#2)\n    make_breaking_atomic_path_info [2; 4; 6] 2;\n    // Path 9:  Actions 2, 4, and 7 in succession constitute a full atomic action (#5)\n    make_breaking_atomic_path_info [2; 4; 7] 5;\n  ]\n\n// This is a list of, for each action, which path consists only of that action.\n\nlet my_singleton_path_indices: array_t (option nat) = list_to_array\n  [\n    Some 0; // Action 0 by itself is path 0\n    Some 1; // Action 1 by itself is path 1\n    Some 2; // Action 2 by itself is path 2\n    Some 3; // Action 3 by itself is path 3\n    None;   // Action 4 by itself isn't among the paths\n    None;   // Action 5 by itself isn't among the paths\n    None;   // Action 6 by itself isn't among the paths\n    None;   // Action 7 by itself isn't among the paths\n    Some 4; // Action 8 by itself is path 4\n    Some 5  // Action 9 by itself is path 5\n  ]\n\nlet lemma_MyLProg_refines_MyAtomicLProg ()\n  : Lemma (ensures spec_refines_spec\n                     (program_to_spec MyLProg.prog)\n                     (semantics_to_spec (make_atomic_semantics armada_semantics) MyAtomicLProg.prog)\n                     eq2) =\n  let lprog = MyLProg.prog in\n  let hprog = MyAtomicLProg.prog in\n  let aw: armada_refines_atomic_witness_t = {\n    pc_index_breaking = my_pc_index_breaking;\n    pc_indices_array = my_pc_indices_array;\n    action_indices_starting_at_no_pc = my_action_indices_starting_at_no_pc;\n    action_indices_starting_at_pc_index = my_action_indices_starting_at_pc_index;\n    atomic_path_infos = my_atomic_path_infos;\n    singleton_path_indices = my_singleton_path_indices;\n    lpcs = my_lpcs;\n    lprog_main_start_pc_index = my_lprog_main_start_pc_index;\n    lprog_actions_array = list_to_array (all_actions lprog.program_statements);\n    hprog_actions_array = list_to_array hprog.actions;\n  } in\n  assert (armada_refines_atomic_witness_valid MyLProg.prog MyAtomicLProg.prog aw)\n    by (compute (); trivial ());\n  armada_refines_atomic_witness_valid_implies_refinement MyLProg.prog MyAtomicLProg.prog aw\n"
  },
  {
    "path": "experimental/lib/MyVarHidingProof.fst",
    "content": "module MyVarHidingProof\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Computation\nopen Armada.Expression\nopen Armada.State\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Transition\nopen Armada.Type\nopen Spec.Behavior\nopen Strategies.ArmadaStatement.ThreadState\nopen Strategies.Atomic\nopen Strategies.GlobalVars\nopen Strategies.GlobalVars.Types\nopen Strategies.Nonyielding\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\nopen Strategies.PCIndices\nopen Strategies.VarHiding.Defs\nopen Strategies.VarHiding.Efficient\nopen Util.ImmutableArray\n\nlet vs: list var_id_t = // hidden variables in no particular order\n  [\n    \"b\";\n    \"d\";\n  ]\n\nlet tds: list object_td_t = // object type descriptors for the hdiden variables in the order corresponding to `vs`\n  [\n    (ObjectTDAbstract int); // \"b\" is an abstract int\n    (ObjectTDAbstract int); // \"d\" is an abstract int\n  ]\n\nlet which_initializers_are_hidings: list bool =\n  [\n    false; // The first initializer in B.global_initializers is a, which is not being hidden\n    true;  // b *is* being hidden\n    false; // c is not being hidden\n    true;  // d is being hidden\n    false; // e is not being hidden\n  ]\n\nlet lpcs: array_t pc_t = list_to_array\n  [\n    \"main.1.1\";       // by index, known as B.PC #0\n    \"main.1.2\";       // by index, known as B.PC #1\n    \"main.1.3\";       // by index, known as B.PC #2\n    \"main.2.1\";       // by index, known as B.PC #3\n    \"main.2.2\";       // by index, known as B.PC #4\n    \"main.2.3\";       // by index, known as B.PC #5\n    \"main.3\";         // by index, known as B.PC #6\n    \"main.3.R\";       // by index, known as B.PC #7\n    \"main.4.1\";       // by index, known as B.PC #8\n    \"main.4.2\";       // by index, known as B.PC #9\n    \"main.End\";       // by index, known as B.PC #10\n    \"subroutine.1\";   // by index, known as B.PC #11\n    \"subroutine.2\";   // by index, known as B.PC #12\n    \"subroutine.3\";   // by index, known as B.PC #13\n    \"subroutine.End\"; // by index, known as B.PC #14\n  ]\n\nlet hpcs: array_t pc_t = list_to_array\n  [\n    \"main.1\";         // by index, known as A.PC #0\n    \"main.2.1\";       // by index, known as A.PC #1\n    \"main.2.2\";       // by index, known as A.PC #2\n    \"main.3\";         // by index, known as A.PC #3\n    \"main.3.R\";       // by index, known as A.PC #4\n    \"main.End\";       // by index, known as A.PC #5\n    \"subroutine.1\";   // by index, known as A.PC #6\n    \"subroutine.End\"; // by index, known as A.PC #7\n  ]\n\nlet lpc_to_hpc: array_t nat = list_to_array\n  [\n    0; // B.main.1.1 (which is B.PC #0) maps to A.main.1 (which is A.PC #0)\n    0; // B.main.1.2 (which is B.PC #1) maps to A.main.1 (which is A.PC #0)\n    1; // B.main.1.3 (which is B.PC #2) maps to A.main.2.1 (which is A.PC #1)\n    1; // B.main.2.1 (which is B.PC #3) maps to A.main.2.1 (which is A.PC #1)\n    2; // B.main.2.2 (which is B.PC #4) maps to A.main.2.2 (which is A.PC #2)\n    2; // B.main.2.3 (which is B.PC #5) maps to A.main.2.2 (which is A.PC #2)\n    3; // B.main.3 (which is B.PC #6) maps to A.main.3 (which is A.PC #3)\n    4; // B.main.3.R (which is B.PC #7) maps to A.main.3.R (which is A.PC #4)\n    5; // B.main.4.1 (which is B.PC #8) maps to A.main.End (which is A.PC #5)\n    5; // B.main.4.2 (which is B.PC #9) maps to A.main.End (which is A.PC #5)\n    5; // B.main.End (which is B.PC #10) maps to A.main.End (which is A.PC #5)\n    6; // B.subroutine.1 (which is B.PC #11) maps to A.subroutine.1 (which is A.PC #6)\n    7; // B.subroutine.2 (which is B.PC #12) maps to A.subroutine.End (which is A.PC #7)\n    7; // B.subroutine.3 (which is B.PC #13) maps to A.subroutine.End (which is A.PC #7)\n    7; // B.subroutine.End (which is B.PC #14) maps to A.subroutine.End (which is A.PC #7)\n  ]\n\nlet is_return_lpc: array_t bool = list_to_array\n  [\n    false; // B.PC #0 isn't a return PC\n    false; // B.PC #1 isn't a return PC\n    false; // ...\n    false;\n    false;\n    false;\n    false;\n    true;  // only B.main.3.R (which is B.PC #7) is a return PC (one that's pushed on the stack to be returned to)\n    false;\n    false;\n    false;\n    false;\n    false;\n    false;\n    false;\n  ]\n\nlet is_nonyielding_lpc: array_t bool = list_to_array\n  [\n    false; // B.main.1.1 is not nonyielding\n    true;  // B.main.1.2 is nonyielding\n    true;  // B.main.1.3 is nonyielding\n    false; // B.main.2.1 is not nonyielding\n    true;  // B.main.2.2 is nonyielding\n    true;  // B.main.2.3 is nonyielding\n    false; // B.main.3 is not nonyielding\n    false; // B.main.3.R is not nonyielding\n    false; // B.main.4.1 is not nonyielding\n    true;  // B.main.4.2 is nonyielding\n    false; // B.main.End is not nonyielding\n    false; // B.subroutine.1 is not nonyielding\n    false; // B.subroutine.2 is not nonyielding\n    false; // B.subroutine.3 is not nonyielding\n    false; // B.subroutine.End is not nonyielding\n  ]\n\nlet is_nonyielding_hpc: array_t bool = list_to_array\n  [\n    false; // A.main.1 is not nonyielding\n    false; // A.main.2.1 is not nonyielding\n    true;  // A.main.2.2 is nonyielding\n    false; // A.main.3 is not nonyielding\n    false; // A.main.3.R is not nonyielding\n    false; // A.main.End is not nonyielding\n    false; // A.subroutine.1 is not nonyielding\n    false; // A.subroutine.End is not nonyielding\n  ]\n\n/// For each hidden statement in the low-level program, if it\n/// doesn't just assign a constant that's a primitive or abstract\n/// value, we have to provide a witness that it can't crash.\n\n// The subroutine_2 statement is `b := a`\n\nlet statement_subroutine_2: program_statement_t =\n  (* b := a; *)\n  {\n    start_pc = Some \"subroutine.2\";\n    end_pc = Some \"subroutine.3\";\n    starts_atomic_block = true;\n    ends_atomic_block = true;\n    statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"b\") (ExpressionGlobalVariable (ObjectTDAbstract int) \"a\");\n  }\n\n// We need to write a proof that the statement `b := a` can't crash,\n// because it doesn't just assign a constant.  It depends on the\n// invariant that the global variable `a` exists and has the same type\n// as `b`.\n\nlet lemma_cant_crash_subroutine_2\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (s: Armada.State.t{\n      MyAtomicBInvariant.inv s\n    /\\ all_gvars_have_types s.mem vs tds\n    /\\ NotStopped? s.stop_reason\n    /\\ ThreadStatusRunning? (s.threads actor).status\n    /\\ statement_subroutine_2.start_pc = Some (s.threads actor).pc})\n  : squash (let ps = statement_subroutine_2 in\n            not (ComputationUndefined? (statement_computation actor nd (Some?.v ps.start_pc) ps.end_pc\n                                          ps.statement s))) =\n  ()\n\n// In corresponding_hactions_info, we describe, for each low-level\n// atomic action, what the corresponding high-level atomic action is.\n// In most cases, it'll be the identical one. But in some, it'll be\n// one that hides one or more hidden assignments. Correspondences are\n// usually CorrespondenceNormal, but for the propagate action we use\n// CorrespondencePropagate and for actions that end with a failure of\n// a hidden assignment statement we use\n// CorrespondenceImpossibleConstantAssignmentFailure or\n// CorrespondenceImpossibleStatementFailure. For each of the\n// CorrespondenceNormal entries, we need to provide a list that\n// indicates which of the actions are hidden.\n\nlet corresponding_hactions_info: array_t (ltoh_correspondence_t vs tds MyAtomicBInvariant.inv) = list_to_array\n  [\n    // Low-level action #B.0 is atomic { d := 5; a := 10; e := 15 } (ok=true)\n    CorrespondenceNormal\n      0 // It corresponds to high-level action #A.0, which is a := 10 (ok=true)\n      [\n        true;    // The action d := 5 is hidden\n        false;   // The action a := 10 is the same as at the low level\n        true;    // The action e := 15 is hidden\n      ];\n    // Low-level action #B.1 is d := 5 (ok=false)\n    CorrespondenceImpossibleConstantAssignmentFailure;\n    // Low-level action #B.2 is atomic { d := 5; (ok=true) a := 10; (ok=false) }\n    CorrespondenceNormal\n      1 // It corresponds to high-level action #A.1, which is a := 10 (ok=false)\n      [\n        true;   // The action d := 5 is hidden\n        false;  // The action a := 10 is the same as at the low level\n      ];\n    // Low-level action #B.3 is atomic { d := 5; a := 10; b := 5 (ok=false) }\n    CorrespondenceImpossibleConstantAssignmentFailure;\n    // Low-level action #B.4 is atomic { c := 20; b := 25; e := 20 } (all ok)\n    CorrespondenceNormal\n      2 // It corresponds to high-level action #A.2, which is c := 20; e := 30 with ok = true, true\n      [\n        false;  // The action c := 20 is not hidden\n        true;   // The action b := 25 is hidden\n        false;  // The action e := 30 is not hidden\n      ];\n    // Low-level action #B.5 is c := 20 (ok = false)\n    CorrespondenceNormal\n      3 // It corresponds to high-level action #A.3, which is c := 20 with ok = false\n      [\n        false;  // The action c := 20 is not hidden\n      ];\n    // Low-level action #B.6 is atomic { c := 20; b := 25 (ok=false) }\n    // It can't occur because a constant assignment to a hidden variable can't fail.\n    CorrespondenceImpossibleConstantAssignmentFailure;\n    // Low-level action #B.7 is atomic { c := 20; b := 25; e := 20 (ok=false) }\n    CorrespondenceNormal\n      4 // It corresponds to high-level action #A.4 is c := 20; e := 30 with ok = true, false\n      [\n        false;  // The action c := 20 is not hidden\n        true;   // The action b := 25 is hidden\n        false;  // The action e := 30 is not hidden\n      ];\n    // Low-level action #B.8 is MethodCall subroutine with ok = true\n    CorrespondenceNormal\n      5 // It corresponds to high-level action #A.5, which is MethodCall subroutine with ok = true\n      [\n        false; // The only action is not hidden\n      ];\n    // Low-level action #B.9 is MethodCall subroutine with ok = false\n    CorrespondenceNormal\n      6 // It corresponds to high-level action #A.6, which is MethodCall subroutine with ok = false\n      [\n        false; // The only action is not hidden\n      ];\n    // Low-level action #B.10 is MethodCall subroutine with stack overflow with ok = true\n    CorrespondenceNormal\n      7 // It corresponds to high-level action #A.7, which is MethodCall subroutine with stack overflow with ok = true\n      [\n        false; // The only action is not hidden\n      ];\n    // Low-level action #B.11 is MethodCall subroutine with stack overflow with ok = false\n    CorrespondenceNormal\n      8 // It corresponds to high-level action #A.8, which is MethodCall subroutine with stack overflow with ok = false\n      [\n        false; // The only action is not hidden\n      ];\n    // Low-level action #B.12 is a := 0 with ok = true\n    CorrespondenceNormal\n      9 // It corresponds to high-level action #A.9, which matches\n      [\n        false; // The only action is not hidden\n      ];\n    // Low-level action #B.13 is a := 0 with ok = false\n    CorrespondenceNormal\n      10 // It corresponds to high-level action #A.10, which matches\n      [\n        false; // The only action is not hidden\n      ];\n    // Low-level action #B.14 is b := a (ok=true)\n    CorrespondenceHidden; // It is entirely hidden\n    // Low-level action #B.15 is b := a (ok=false)\n    CorrespondenceImpossibleStatementFailure // It can't happen because this assignment can't fail\n      statement_subroutine_2\n      lemma_cant_crash_subroutine_2;\n    // Low-level action #B.16 is d := 2 (ok=true)\n    CorrespondenceHidden; // It is entirely hidden\n    // Low-level action #B.17 is d := 2 (ok=false)\n    // It can't occur because a constant assignment to a hidden variable can't fail.\n    CorrespondenceImpossibleConstantAssignmentFailure;\n    // Low-level action #B.18 is Return with ok = true\n    CorrespondenceNormal\n      11 // It corresponds to high-level action #A.11, which matches\n      [\n        false; // The only action is not hidden\n      ];\n    // Low-level action #B.19 is Return with ok = false\n    CorrespondenceNormal\n      12 // It corresponds to high-level action #A.12, which matches\n      [\n        false; // The only action is not hidden\n      ];\n    // Low-level action #B.20 is UnconditionalJump from \"main.3.R\" to \"main.End\" with ok = true\n    CorrespondenceNormal\n      13 // It corresponds to high-level action #A.13, which matches\n      [\n        false; // The only action is not hidden\n      ];\n    // Low-level action #B.21 is UnconditionalJump from \"main.3.R\" to \"main.End\" with ok = false\n    CorrespondenceNormal\n      14 // It corresponds to high-level action #A.14, which matches\n      [\n        false; // The only action is not hidden\n      ];\n    // Low-level action #B.22 is atomic { b := 35; d := 40 } (ok=true)\n    CorrespondenceHidden;\n    // Low-level action #B.23 is b := 35 (ok = false)\n    // It can't occur because a constant assignment to a hidden variable can't fail.\n    CorrespondenceImpossibleConstantAssignmentFailure;\n    // Low-level action #B.24 is atomic { b := 35; d := 40 (ok=false) }\n    // It can't occur because a constant assignment to a hidden variable can't fail.\n    CorrespondenceImpossibleConstantAssignmentFailure;\n    // Low-level action #B.25 is the propagate action list with ok=true\n    CorrespondencePropagate\n      15; // It corresponds to high-level action #A.15, which matches\n    // Low-level action #B.26 is the propagate action list with ok=false\n    CorrespondencePropagate\n      16; // It corresponds to high-level action #A.16, which matches\n  ]\n\n// The start PC for the low-level program is \"main.1.1\", which is B.PC #0\nlet lprog_main_start_pc_index: nat = 0\n\n// The start PC for the high-level program is \"main.1\", which is A.PC #0\nlet hprog_main_start_pc_index: nat = 0\n\nlet make_pc_indices (start_pc_index: nat) (end_pc_index: nat) : statement_pc_indices_t =\n  {\n    start_pc_index = Some start_pc_index;\n    end_pc_index = Some end_pc_index;\n    create_thread_initial_pc_index = None;\n    method_call_return_pc_index = None;\n  }\n\nlet make_empty_pc_indices : statement_pc_indices_t =\n  {\n    start_pc_index = None;\n    end_pc_index = None;\n    create_thread_initial_pc_index = None;\n    method_call_return_pc_index = None;\n  }\n\n// The lpc_indices_array contains, for each atomic action in the low-level program,\n// a list of PC index summaries, one for each action in that atomic action.\n\nlet lpc_indices_array: array_t (list statement_pc_indices_t) = list_to_array\n  [\n    // Atomic action #0\n    [ make_pc_indices 0 1; make_pc_indices 1 2; make_pc_indices 2 3 ];\n    // Atomic action #1\n    [ make_pc_indices 0 1 ];\n    // Atomic action #2\n    [ make_pc_indices 0 1; make_pc_indices 1 2 ];\n    // Atomic action #3\n    [ make_pc_indices 0 1; make_pc_indices 1 2; make_pc_indices 2 3 ];\n    // Atomic action #4\n    [ make_pc_indices 3 4; make_pc_indices 4 5; make_pc_indices 5 6 ];\n    // Atomic action #5\n    [ make_pc_indices 3 4 ];\n    // Atomic action #6\n    [ make_pc_indices 3 4; make_pc_indices 4 5 ];\n    // Atomic action #7\n    [ make_pc_indices 3 4; make_pc_indices 4 5; make_pc_indices 5 6 ];\n    // Atomic action #8\n    [\n      {\n        start_pc_index = Some 6;\n        end_pc_index = Some 11;\n        create_thread_initial_pc_index = None;\n        method_call_return_pc_index = Some 7; // The return PC is \"main.3.R\" (B.PC #7)\n      }\n    ];\n    // Atomic action #9\n    [\n      {\n        start_pc_index = Some 6;\n        end_pc_index = Some 11;\n        create_thread_initial_pc_index = None;\n        method_call_return_pc_index = Some 7; // The return PC is \"main.3.R\" (B.PC #7)\n      }\n    ];\n    // Atomic action #10\n    [\n      {\n        start_pc_index = Some 6;\n        end_pc_index = Some 11;\n        create_thread_initial_pc_index = None;\n        method_call_return_pc_index = Some 7; // The return PC is \"main.3.R\" (B.PC #7)\n      }\n    ];\n    // Atomic action #11\n    [\n      {\n        start_pc_index = Some 6;\n        end_pc_index = Some 11;\n        create_thread_initial_pc_index = None;\n        method_call_return_pc_index = Some 7; // The return PC is \"main.3.R\" (B.PC #7)\n      }\n    ];\n    // Atomic action #12\n    [ make_pc_indices 11 12 ];\n    // Atomic action #13\n    [ make_pc_indices 11 12 ];\n    // Atomic action #14\n    [ make_pc_indices 12 13 ];\n    // Atomic action #15\n    [ make_pc_indices 12 13 ];\n    // Atomic action #16\n    [ make_pc_indices 13 14 ];\n    // Atomic action #17\n    [ make_pc_indices 13 14 ];\n    // Atomic action #18\n    [ make_pc_indices 14 7 ];\n    // Atomic action #19\n    [ make_pc_indices 14 7 ];\n    // Atomic action #20\n    [ make_pc_indices 7 8 ];\n    // Atomic action #21\n    [ make_pc_indices 7 8 ];\n    // Atomic action #22\n    [ make_pc_indices 8 9; make_pc_indices 9 10 ];\n    // Atomic action #23\n    [ make_pc_indices 8 9 ];\n    // Atomic action #24\n    [ make_pc_indices 8 9; make_pc_indices 9 10 ];\n    // Atomic action #25\n    [ make_empty_pc_indices ];\n    // Atomic action #26\n    [ make_empty_pc_indices ];\n  ]\n\n// The hpc_indices_array contains, for each atomic action in the high-level program,\n// a list of PC index summaries, one for each action in that atomic action.\n\nlet hpc_indices_array: array_t (list statement_pc_indices_t) = list_to_array\n  [\n    // Low-level action #A.0 is a := 10 with ok = true. It goes from \"main.1\" (A.PC #0) to \"main.2.1\" (A.PC #1).\n    [ make_pc_indices 0 1 ];\n    // Low-level action #A.1 is a := 10 with ok = false. It goes from \"main.1\" (A.PC #0) to \"main.2.1\" (A.PC #1).\n    [ make_pc_indices 0 1 ];\n    // Low-level action #A.2 is c := 20; e := 30 with ok = true, true\n    [ make_pc_indices 1 2; make_pc_indices 2 3 ];\n    // Low-level action #A.3 is c := 20 with ok = false\n    [ make_pc_indices 1 2 ];\n    // Low-level action #A.4 is c := 20; e := 30 with ok = true, false\n    [ make_pc_indices 1 2; make_pc_indices 2 3 ];\n    // Low-level action #A.5 is MethodCall subroutine with ok = true. It goes from \"main.3\" to \"subroutine.1\".\n    // But, since it does so with a method call, we need to set the method_call_return_pc_index field as well.\n    [\n      {\n        start_pc_index = Some 3;\n        end_pc_index = Some 6;\n        create_thread_initial_pc_index = None;\n        method_call_return_pc_index = Some 4; // The return PC is \"main.3.R\" (A.PC #4)\n      }\n    ];\n    // Low-level action #A.6 is MethodCall subroutine with ok = false. It goes from \"main.3\" to \"subroutine.1\".\n    [\n      {\n        start_pc_index = Some 3;\n        end_pc_index = Some 6;\n        create_thread_initial_pc_index = None;\n        method_call_return_pc_index = Some 4; // The return PC is \"main.3.R\" (A.PC #4)\n      }\n    ];\n    // Low-level action #A.7 is MethodCall subroutine with ok = true. It goes from \"main.3\" to \"subroutine.1\".\n    // But, since it does so with a method call, we need to set the method_call_return_pc_index field as well.\n    [\n      {\n        start_pc_index = Some 3;\n        end_pc_index = Some 6;\n        create_thread_initial_pc_index = None;\n        method_call_return_pc_index = Some 4; // The return PC is \"main.3.R\" (A.PC #4)\n      }\n    ];\n    // Low-level action #A.8 is MethodCall subroutine with ok = false. It goes from \"main.3\" to \"subroutine.1\".\n    [\n      {\n        start_pc_index = Some 3;\n        end_pc_index = Some 6;\n        create_thread_initial_pc_index = None;\n        method_call_return_pc_index = Some 4; // The return PC is \"main.3.R\" (A.PC #4)\n      }\n    ];\n    // Low-level action #A.9 is a := 0 with ok = true\n    [ make_pc_indices 6 7 ];\n    // Low-level action #A.10 is a := 0 with ok = false\n    [ make_pc_indices 6 7 ];\n    // Low-level action #A.11 is Return with ok = true\n    [ make_pc_indices 7 4 ];\n    // Low-level action #A.12 is Return with ok = false\n    [ make_pc_indices 7 4 ];\n    // Low-level action #A.13 is UnconditionalJump from \"main.3.R\" to \"main.End\" with ok = true\n    [ make_pc_indices 4 5 ];\n    // Low-level action #A.14 is UnconditionalJump from \"main.3.R\" to \"main.End\" with ok = false\n    [ make_pc_indices 4 5 ];\n    // Low-level action #A.15 is PropagateWriteMessageStatement with ok = true\n    [ make_empty_pc_indices ];\n    // Low-level action #A.16 is PropagateWriteMessageStatement with ok = false\n    [ make_empty_pc_indices ];\n  ]\n\nlet vw: efficient_var_hiding_witness_t = {\n  lprog = MyBProg.prog;\n  hprog = MyAProg.prog;\n  lprog_actions_array = list_to_array MyAtomicBProg.prog.actions;\n  hprog_actions_array = list_to_array MyAtomicAProg.prog.actions;\n  vs = vs;\n  tds = tds;\n  inv = MyAtomicBInvariant.inv;\n  which_initializers_are_hidings = which_initializers_are_hidings;\n  lpcs = lpcs;\n  hpcs = hpcs;\n  lpc_to_hpc = lpc_to_hpc;\n  is_return_lpc = is_return_lpc;\n  is_nonyielding_lpc = is_nonyielding_lpc;\n  is_nonyielding_hpc = is_nonyielding_hpc;\n  corresponding_hactions_info = corresponding_hactions_info;\n  lprog_main_start_pc_index = lprog_main_start_pc_index;\n  hprog_main_start_pc_index = hprog_main_start_pc_index;\n  lpc_indices_array = lpc_indices_array;\n  hpc_indices_array = hpc_indices_array;\n}\n\nlet lemma_MyAtomicAProgRefinesMyAtomicBProg ()\n  : Lemma (spec_refines_spec\n           (semantics_to_spec (make_atomic_semantics armada_semantics) MyAtomicBProg.prog)\n           (semantics_to_spec (make_atomic_semantics armada_semantics) MyAtomicAProg.prog)\n           refinement_requirement) =\n  let latomic_prog = MyAtomicBProg.prog in\n  let hatomic_prog = MyAtomicAProg.prog in\n  let pc_relation = efficient_lh_pc_relation lpc_to_hpc in\n  let pc_return_relation = efficient_lh_pc_return_relation lpc_to_hpc is_return_lpc in\n  assert (efficient_var_hiding_witness_valid latomic_prog hatomic_prog vw)\n    by (FStar.Tactics.V2.compute (); FStar.Tactics.V2.trivial ());\n  MyAtomicBInvariant.inv_is_stepwise_invariant ();\n  efficient_var_hiding_witness_valid_implies_refinement latomic_prog hatomic_prog vw\n"
  },
  {
    "path": "experimental/lib/MyVarIntroProof.fst",
    "content": "module MyVarIntroProof\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Computation\nopen Armada.Expression\nopen Armada.State\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Transition\nopen Armada.Type\nopen Spec.Behavior\nopen Strategies.ArmadaStatement.ThreadState\nopen Strategies.Atomic\nopen Strategies.GlobalVars.Types\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\nopen Strategies.PCIndices\nopen Strategies.VarIntro.Defs\nopen Strategies.VarIntro.Efficient\nopen Util.ImmutableArray\n\nlet vs: list var_id_t = // introduced variables in no particular order\n  [\n    \"b\";\n    \"d\";\n  ]\n\nlet tds: list object_td_t = // object type descriptors for the introduced variables in the order corresponding to `vs`\n  [\n    (ObjectTDAbstract int); // \"b\" is an abstract int\n    (ObjectTDAbstract int); // \"d\" is an abstract int\n  ]\n\nlet which_initializers_are_intros: list bool =\n  [\n    false; // The first initializer in B.global_initializers is a, which is not being introduced\n    true;  // b *is* being introduced\n    false; // c is not being introduced\n    true;  // d is being introduced\n    false; // e is not being introduced\n  ]\n\nlet lpcs: array_t pc_t = list_to_array\n  [\n    \"main.1\";         // by index, known as A.PC #0\n    \"main.2.1\";       // by index, known as A.PC #1\n    \"main.2.2\";       // by index, known as A.PC #2\n    \"main.3\";         // by index, known as A.PC #3\n    \"main.3.R\";       // by index, known as A.PC #4\n    \"main.End\";       // by index, known as A.PC #5\n    \"subroutine.1\";   // by index, known as A.PC #6\n    \"subroutine.End\"; // by index, known as A.PC #7\n  ]\n\nlet hpcs: array_t pc_t = list_to_array\n  [\n    \"main.1.1\";       // by index, known as B.PC #0\n    \"main.1.2\";       // by index, known as B.PC #1\n    \"main.1.3\";       // by index, known as B.PC #2\n    \"main.2.1\";       // by index, known as B.PC #3\n    \"main.2.2\";       // by index, known as B.PC #4\n    \"main.2.3\";       // by index, known as B.PC #5\n    \"main.3\";         // by index, known as B.PC #6\n    \"main.3.R\";       // by index, known as B.PC #7\n    \"main.4.1\";       // by index, known as B.PC #8\n    \"main.4.2\";       // by index, known as B.PC #9\n    \"main.End\";       // by index, known as B.PC #10\n    \"subroutine.1\";   // by index, known as B.PC #11\n    \"subroutine.2\";   // by index, known as B.PC #12\n    \"subroutine.3\";   // by index, known as B.PC #13\n    \"subroutine.End\"; // by index, known as B.PC #14\n  ]\n\nlet hpc_to_lpc: array_t nat = list_to_array\n  [\n    0; // B.main.1.1 (which is B.PC #0) maps to A.main.1 (which is A.PC #0)\n    0; // B.main.1.2 (which is B.PC #1) maps to A.main.1 (which is A.PC #0)\n    1; // B.main.1.3 (which is B.PC #2) maps to A.main.2.1 (which is A.PC #1)\n    1; // B.main.2.1 (which is B.PC #3) maps to A.main.2.1 (which is A.PC #1)\n    2; // B.main.2.2 (which is B.PC #4) maps to A.main.2.2 (which is A.PC #2)\n    2; // B.main.2.3 (which is B.PC #5) maps to A.main.2.2 (which is A.PC #2)\n    3; // B.main.3 (which is B.PC #6) maps to A.main.3 (which is A.PC #3)\n    4; // B.main.3.R (which is B.PC #7) maps to A.main.3.R (which is A.PC #4)\n    5; // B.main.4.1 (which is B.PC #8) maps to A.main.End (which is A.PC #5)\n    5; // B.main.4.2 (which is B.PC #9) maps to A.main.End (which is A.PC #5)\n    5; // B.main.End (which is B.PC #10) maps to A.main.End (which is A.PC #5)\n    6; // B.subroutine.1 (which is B.PC #11) maps to A.subroutine.1 (which is A.PC #6)\n    7; // B.subroutine.2 (which is B.PC #12) maps to A.subroutine.End (which is A.PC #7)\n    7; // B.subroutine.3 (which is B.PC #13) maps to A.subroutine.End (which is A.PC #7)\n    7; // B.subroutine.End (which is B.PC #14) maps to A.subroutine.End (which is A.PC #7)\n  ]\n\nlet lpc_to_hpcs: array_t (list nat) = list_to_array\n  [\n    [0; 1];     // A.main.1 (which is A.PC #0) maps to B.PCs #0, #1\n    [2; 3];     // A.main.2.1 (which is A.PC #1) maps to B.PCs #2, #3\n    [4; 5];     // A.main.2.2 (which is A.PC #2) maps to B.PCs #4, #5\n    [6];        // A.main.3 (which is A.PC #3) maps to B.PC #6\n    [7];        // A.main.3.R (which is A.PC #4) maps to B.PC #7\n    [8; 9; 10]; // A.main.End (which is A.PC #5) maps to B.PCs #8, #9, #10\n    [11];       // A.subroutine.1 (which is A.PC #6) maps to B.PC #11\n    [12; 13; 14];  // A.subroutine.End (which is A.PC #7) maps to B.PCs #12, #13, #14\n  ]\n\nlet is_return_hpc: array_t bool = list_to_array\n  [\n    false; // B.PC #0 isn't a return PC\n    false; // B.PC #1 isn't a return PC\n    false; // ...\n    false;\n    false;\n    false;\n    false;\n    true;  // only B.main.3.R (which is B.PC #7) is a return PC (one that's pushed on the stack to be returned to)\n    false;\n    false;\n    false;\n    false;\n    false;\n    false;\n    false;\n  ]\n\nlet is_nonyielding_lpc: array_t bool = list_to_array\n  [\n    false; // A.main.1 is not nonyielding\n    false; // A.main.2.1 is not nonyielding\n    true;  // A.main.2.2 is nonyielding\n    false; // A.main.3 is not nonyielding\n    false; // A.main.3.R is not nonyielding\n    false; // A.main.End is not nonyielding\n    false; // A.subroutine.1 is not nonyielding\n    false; // A.subroutine.End is not nonyielding\n  ]\n\nlet is_nonyielding_hpc: array_t bool = list_to_array\n  [\n    false; // B.main.1.1 is not nonyielding\n    true;  // B.main.1.2 is nonyielding\n    true;  // B.main.1.3 is nonyielding\n    false; // B.main.2.1 is not nonyielding\n    true;  // B.main.2.2 is nonyielding\n    true;  // B.main.2.3 is nonyielding\n    false; // B.main.3 is not nonyielding\n    false; // B.main.3.R is not nonyielding\n    false; // B.main.4.1 is not nonyielding\n    true;  // B.main.4.2 is nonyielding\n    false; // B.main.End is not nonyielding\n    false; // B.subroutine.1 is not nonyielding\n    false; // B.subroutine.2 is not nonyielding\n    false; // B.subroutine.3 is not nonyielding\n    false; // B.subroutine.End is not nonyielding\n  ]\n\n// The is_breaking_hpc array describes which high-level PCs are PCs at\n// which atomic actions are broken up. Generally, this is the opposite\n// of nonyielding PCs, since yielding PCs are break points. However,\n// sometimes other PCs are break points (entry points of atomic\n// recursive functions and heads of atomic loops).\n\nlet is_breaking_hpc: array_t bool = list_to_array\n  [\n    true; // B.main.1.1 is a break point\n    false;  // B.main.1.2 is not a break point\n    false;  // B.main.1.3 is not a break point\n    true; // B.main.2.1 is a break point\n    false;  // B.main.2.2 is not a break point\n    false;  // B.main.2.3 is not a break point\n    true; // B.main.3 is a break point\n    true; // B.main.3.R is a break point\n    true; // B.main.4.1 is a break point\n    false;  // B.main.4.2 is not a break point\n    true; // B.main.End is a break point\n    true; // B.subroutine.1 is a break point\n    true; // B.subroutine.2 is a break point\n    true; // B.subroutine.3 is a break point\n    true; // B.subroutine.End is a break point\n  ]\n\n/// For each introduced statement in the high-level program, if it\n/// doesn't just assign a constant that's a primitive or abstract\n/// value, we have to provide a witness that it can't crash.\n\n// The subroutine_2 statement is `b := a`\n\nlet statement_subroutine_2: program_statement_t =\n  (* b := a; *)\n  {\n    start_pc = Some \"subroutine.2\";\n    end_pc = Some \"subroutine.3\";\n    starts_atomic_block = true;\n    ends_atomic_block = true;\n    statement = UpdateStatement false (ExpressionGlobalVariable (ObjectTDAbstract int) \"b\") (ExpressionGlobalVariable (ObjectTDAbstract int) \"a\");\n  }\n\n// We need to write a proof that the statement `b := a` can't crash,\n// because it doesn't just assign a constant.  It depends on the\n// invariant that the global variable `a` exists and has the same type\n// as `b`.\n\nlet lemma_cant_crash_subroutine_2\n  (actor: tid_t)\n  (s: Armada.State.t{\n      MyAtomicBInvariant.inv s\n    /\\ all_gvars_have_types s.mem vs tds\n    /\\ NotStopped? s.stop_reason\n    /\\ ThreadStatusRunning? (s.threads actor).status\n    /\\ statement_subroutine_2.start_pc = Some (s.threads actor).pc})\n  : squash (let ps = statement_subroutine_2 in\n            ComputationProduces? (statement_computation actor [] (Some?.v ps.start_pc) ps.end_pc ps.statement s)) =\n  ()\n\n// This is the witness for the uncrashability of the subroutine_2 statement.\n\nlet introduction_succeeds_witness_subroutine_2: introduction_succeeds_witness_t vs tds MyAtomicBInvariant.inv =\n  IntroductionSucceedsProof statement_subroutine_2 lemma_cant_crash_subroutine_2\n\n// In hpc_info, we describe any atomic blocks (including single\n// statements outside of atomic blocks) that are completely newly\n// introduced.  This doesn't count assignment statements that are\n// introduced into existing atomic blocks.  So, for instance, where A\n// has `a := 10;` and B has `atomic { d := 5; a := 10; e := 15; }`,\n// this doesn't count as an introduced assignment.  That's a\n// correspondence between an A atomic block and a B atomic block,\n// which will be described later.\n\nlet hpc_info: array_t (efficient_hpc_info_t vs tds MyAtomicBInvariant.inv) = list_to_array\n  [\n    EfficientHPCInfoNormal; // B.main.1.1 isn't a PC with an introduced atomic block\n    EfficientHPCInfoNormal; // B.main.1.2 isn't a PC with an introduced atomic block\n    EfficientHPCInfoNormal; // B.main.1.3 isn't a PC with an introduced atomic block\n    EfficientHPCInfoNormal; // B.main.2.1 isn't a PC with an introduced atomic block\n    EfficientHPCInfoNormal; // B.main.2.2 isn't a PC with an introduced atomic block\n    EfficientHPCInfoNormal; // B.main.2.3 isn't a PC with an introduced atomic block\n    EfficientHPCInfoNormal; // B.main.3 isn't a PC with an introduced atomic block\n    EfficientHPCInfoNormal; // B.main.3.R isn't a PC with an introduced atomic block\n    EfficientHPCInfoIntroduced 22 10 [IntroductionSucceedsBecauseItAssignsConstant;\n                                      IntroductionSucceedsBecauseItAssignsConstant] 1;\n      // B.main.4.1 is a PC with an introduced atomic block. It's B's atomic action #22,\n      // which ends at PC B.main.End (B.PC #10). We assign it progress value 1 because\n      // when B is at main.4.1, it has 1 more atomic block to execute (#22) before it\n      // doesn't have to introduce any more atomic blocks.\n    EfficientHPCInfoNormal; // B.main.4.2 isn't a PC with an introduced atomic block\n    EfficientHPCInfoNormal; // B.main.End isn't a PC with an introduced atomic block\n    EfficientHPCInfoNormal; // B.subroutine.1 isn't a PC with an introduced atomic block\n    EfficientHPCInfoIntroduced 14 13 [introduction_succeeds_witness_subroutine_2] 2;\n      // B.subroutine.2 is a PC with an introduced atomic block. It's B's atomic action #14,\n      // which ends at PC B.subroutine.3 (B.PC #13). We assign it progress value 2\n      // because when B is at subroutine.1, it has 2 more atomic block to execute (#14, #16)\n      // before it doesn't have to introduce any more atomic blocks.\n    EfficientHPCInfoIntroduced 16 14 [IntroductionSucceedsBecauseItAssignsConstant] 1;\n      // B.subroutine.3 is a PC with an introduced atomic block. It's B's atomic action #16,\n      // which ends at PC B.subroutine.End (B.PC #14). We assign it progress value 1\n      // because when B is at subroutine.2, it has 1 more atomic block to execute (#16)\n      // before it doesn't have to introduce any more atomic blocks.\n    EfficientHPCInfoNormal; // B.subroutine.End isn't a PC with an introduced atomic block\n  ]\n\n// In corresponding_hactions_info, we describe, for each low-level\n// atomic action, what the corresponding high-level atomic action is.\n// In most cases, it'll be the identical one. But in some, it'll be\n// one that adds one or more introduced assignments. Correspondences\n// are usually CorrespondenceNormal, but for the propagate action we\n// use CorrespondencePropagate. For each of the CorrespondenceNormal\n// entries, we need to provide a \"mapper\" that maps the list of\n// high-level actions to the list of low-level actions.\n\nlet corresponding_hactions_info: array_t (ltoh_correspondence_t vs tds MyAtomicBInvariant.inv) = list_to_array\n  [\n    // Low-level action #A.0 is a := 10 with ok = true.\n    CorrespondenceNormal\n      0 // It corresponds to high-level action #B.0, which is atomic { d := 5; a := 10; e := 15 } (ok=true)\n      [\n        MapperIntroduced IntroductionSucceedsBecauseItAssignsConstant; // The action d := 5 is introduced\n        MapperMatching;                                // The action a := 10 is the same as at the low level\n        MapperIntroduced IntroductionSucceedsBecauseItAssignsConstant; // The action e := 15 is introduced\n      ];\n    // Low-level action #A.1 is a := 10 with ok = false.\n    CorrespondenceNormal\n      2 // It corresponds to high-level action #B.2, which is atomic { d := 5 (ok=true); a := 10 (ok=false) }\n      [\n        MapperIntroduced IntroductionSucceedsBecauseItAssignsConstant; // The action d := 5 is introduced\n        MapperMatching;                                // The action a := 10 is the same as at the low level\n      ];\n    // Low-level action #A.2 is c := 20; e := 30 with ok = true, true\n    CorrespondenceNormal\n      4 // It corresponds to high-level action #B.4, which is atomic { c := 20; b := 25; e := 20 } (all ok)\n      [\n        MapperMatching;                                // The action c := 20 is the same as at the low level\n        MapperIntroduced IntroductionSucceedsBecauseItAssignsConstant; // The action b := 25 is introduced\n        MapperMatching;                                // The action e := 30 is the same as at the low level\n      ];\n    // Low-level action #A.3 is c := 20 with ok = false\n    CorrespondenceNormal\n      5 // It corresponds to high-level action #B.5, which matches\n      [ MapperMatching ];                              // The only action is the same as at the low level\n    // Low-level action #A.4 is c := 20; e := 30 with ok = true, false\n    CorrespondenceNormal\n      7 // It corresponds to high-level action #B.7, which is atomic { c := 20; b := 25; e := 20 (ok=false) }\n      [\n        MapperMatching;                           // The action c := 20 is the same as at the low level\n        MapperIntroduced IntroductionSucceedsBecauseItAssignsConstant; // The action b := 25 is introduced\n        MapperMatching;                           // The action e := 30 is the same as at the low level\n      ];\n    // Low-level action #A.5 is MethodCall subroutine with ok = true\n    CorrespondenceNormal\n      8 // It corresponds to high-level action #B.8, which matches\n      [ MapperMatching ];                              // The only action is the same as at the low level\n    // Low-level action #A.6 is MethodCall subroutine with ok = false\n    CorrespondenceNormal\n      9 // It corresponds to high-level action #B.9, which matches\n      [ MapperMatching ];                              // The only action is the same as at the low level\n    // Low-level action #A.7 is MethodCall subroutine with stack overflow with ok = true\n    CorrespondenceNormal\n      10 // It corresponds to high-level action #B.10, which matches\n      [ MapperMatching ];                              // The only action is the same as at the low level\n    // Low-level action #A.8 is MethodCall subroutine with stack overflow with ok = false\n    CorrespondenceNormal\n      11 // It corresponds to high-level action #B.11, which matches\n      [ MapperMatching ];                              // The only action is the same as at the low level\n    // Low-level action #A.9 is a := 0 with ok = true\n    CorrespondenceNormal\n      12 // It corresponds to high-level action #B.12, which matches\n      [ MapperMatching ];                              // The only action is the same as at the low level\n    // Low-level action #A.10 is a := 0 with ok = false\n    CorrespondenceNormal\n      13 // It corresponds to high-level action #B.13, which matches\n      [ MapperMatching ];                              // The only action is the same as at the low level\n    // Low-level action #A.11 is Return with ok = true\n    CorrespondenceNormal\n      18 // It corresponds to high-level action #B.18, which matches\n      [ MapperMatching ];                              // The only action is the same as at the low level\n    // Low-level action #A.12 is Return with ok = false\n    CorrespondenceNormal\n      19 // It corresponds to high-level action #B.19, which matches\n      [ MapperMatching ];                              // The only action is the same as at the low level\n    // Low-level action #A.13 is UnconditionalJump from \"main.3.R\" to \"main.End\" with ok = true\n    CorrespondenceNormal\n      20 // It corresponds to high-level action #B.20, which matches\n      [ MapperMatching ];                              // The only action is the same as at the low level\n    // Low-level action #A.14 is UnconditionalJump from \"main.3.R\" to \"main.End\" with ok = false\n    CorrespondenceNormal\n      21 // It corresponds to high-level action #B.21, which matches\n      [ MapperMatching ];                              // The only action is the same as at the low level\n    // Low-level action #A.15 is PropagateWriteMessageStatement with ok = true\n    CorrespondencePropagate\n      25; // It corresponds to high-level action #B.25, which matches\n    // Low-level action #A.16 is PropagateWriteMessageStatement with ok = false\n    CorrespondencePropagate\n      26 // It corresponds to high-level action #B.26, which matches\n  ]\n\n// The start PC for the low-level program is \"main.1\", which is A.PC #0\nlet lprog_main_start_pc_index: nat = 0\n\n// The start PC for the high-level program is \"main.1.1\", which is B.PC #0\nlet hprog_main_start_pc_index: nat = 0\n\nlet make_pc_indices (start_pc_index: nat) (end_pc_index: nat) : statement_pc_indices_t =\n  {\n    start_pc_index = Some start_pc_index;\n    end_pc_index = Some end_pc_index;\n    create_thread_initial_pc_index = None;\n    method_call_return_pc_index = None;\n  }\n\nlet make_empty_pc_indices : statement_pc_indices_t =\n  {\n    start_pc_index = None;\n    end_pc_index = None;\n    create_thread_initial_pc_index = None;\n    method_call_return_pc_index = None;\n  }\n\n// The lpc_indices_array contains, for each atomic action in the low-level program,\n// a list of PC index summaries, one for each action in that atomic action.\n\nlet lpc_indices_array: array_t (list statement_pc_indices_t) = list_to_array\n  [\n    // Low-level action #A.0 is a := 10 with ok = true. It goes from \"main.1\" (A.PC #0) to \"main.2.1\" (A.PC #1).\n    [ make_pc_indices 0 1 ];\n    // Low-level action #A.1 is a := 10 with ok = false. It goes from \"main.1\" (A.PC #0) to \"main.2.1\" (A.PC #1).\n    [ make_pc_indices 0 1 ];\n    // Low-level action #A.2 is c := 20; e := 30 with ok = true, true\n    [ make_pc_indices 1 2; make_pc_indices 2 3 ];\n    // Low-level action #A.3 is c := 20 with ok = false\n    [ make_pc_indices 1 2 ];\n    // Low-level action #A.4 is c := 20; e := 30 with ok = true, false\n    [ make_pc_indices 1 2; make_pc_indices 2 3 ];\n    // Low-level action #A.5 is MethodCall subroutine with ok = true. It goes from \"main.3\" to \"subroutine.1\".\n    // But, since it does so with a method call, we need to set the method_call_return_pc_index field as well.\n    [\n      {\n        start_pc_index = Some 3;\n        end_pc_index = Some 6;\n        create_thread_initial_pc_index = None;\n        method_call_return_pc_index = Some 4; // The return PC is \"main.3.R\" (A.PC #4)\n      }\n    ];\n    // Low-level action #A.6 is MethodCall subroutine with ok = false. It goes from \"main.3\" to \"subroutine.1\".\n    [\n      {\n        start_pc_index = Some 3;\n        end_pc_index = Some 6;\n        create_thread_initial_pc_index = None;\n        method_call_return_pc_index = Some 4; // The return PC is \"main.3.R\" (A.PC #4)\n      }\n    ];\n    // Low-level action #A.7 is MethodCall subroutine with ok = true. It goes from \"main.3\" to \"subroutine.1\".\n    // But, since it does so with a method call, we need to set the method_call_return_pc_index field as well.\n    [\n      {\n        start_pc_index = Some 3;\n        end_pc_index = Some 6;\n        create_thread_initial_pc_index = None;\n        method_call_return_pc_index = Some 4; // The return PC is \"main.3.R\" (A.PC #4)\n      }\n    ];\n    // Low-level action #A.8 is MethodCall subroutine with ok = false. It goes from \"main.3\" to \"subroutine.1\".\n    [\n      {\n        start_pc_index = Some 3;\n        end_pc_index = Some 6;\n        create_thread_initial_pc_index = None;\n        method_call_return_pc_index = Some 4; // The return PC is \"main.3.R\" (A.PC #4)\n      }\n    ];\n    // Low-level action #A.9 is a := 0 with ok = true\n    [ make_pc_indices 6 7 ];\n    // Low-level action #A.10 is a := 0 with ok = false\n    [ make_pc_indices 6 7 ];\n    // Low-level action #A.11 is Return with ok = true\n    [ make_pc_indices 7 4 ];\n    // Low-level action #A.12 is Return with ok = false\n    [ make_pc_indices 7 4 ];\n    // Low-level action #A.13 is UnconditionalJump from \"main.3.R\" to \"main.End\" with ok = true\n    [ make_pc_indices 4 5 ];\n    // Low-level action #A.14 is UnconditionalJump from \"main.3.R\" to \"main.End\" with ok = false\n    [ make_pc_indices 4 5 ];\n    // Low-level action #A.15 is PropagateWriteMessageStatement with ok = true\n    [ make_empty_pc_indices ];\n    // Low-level action #A.16 is PropagateWriteMessageStatement with ok = false\n    [ make_empty_pc_indices ];\n  ]\n\n// The hpc_indices_array contains, for each atomic action in the high-level program,\n// a list of PC index summaries, one for each action in that atomic action.\n\nlet hpc_indices_array: array_t (list statement_pc_indices_t) = list_to_array\n  [\n    // Atomic action #0\n    [ make_pc_indices 0 1; make_pc_indices 1 2; make_pc_indices 2 3 ];\n    // Atomic action #1\n    [ make_pc_indices 0 1 ];\n    // Atomic action #2\n    [ make_pc_indices 0 1; make_pc_indices 1 2 ];\n    // Atomic action #3\n    [ make_pc_indices 0 1; make_pc_indices 1 2; make_pc_indices 2 3 ];\n    // Atomic action #4\n    [ make_pc_indices 3 4; make_pc_indices 4 5; make_pc_indices 5 6 ];\n    // Atomic action #5\n    [ make_pc_indices 3 4 ];\n    // Atomic action #6\n    [ make_pc_indices 3 4; make_pc_indices 4 5 ];\n    // Atomic action #7\n    [ make_pc_indices 3 4; make_pc_indices 4 5; make_pc_indices 5 6 ];\n    // Atomic action #8\n    [\n      {\n        start_pc_index = Some 6;\n        end_pc_index = Some 11;\n        create_thread_initial_pc_index = None;\n        method_call_return_pc_index = Some 7; // The return PC is \"main.3.R\" (B.PC #7)\n      }\n    ];\n    // Atomic action #9\n    [\n      {\n        start_pc_index = Some 6;\n        end_pc_index = Some 11;\n        create_thread_initial_pc_index = None;\n        method_call_return_pc_index = Some 7; // The return PC is \"main.3.R\" (B.PC #7)\n      }\n    ];\n    // Atomic action #10\n    [\n      {\n        start_pc_index = Some 6;\n        end_pc_index = Some 11;\n        create_thread_initial_pc_index = None;\n        method_call_return_pc_index = Some 7; // The return PC is \"main.3.R\" (B.PC #7)\n      }\n    ];\n    // Atomic action #11\n    [\n      {\n        start_pc_index = Some 6;\n        end_pc_index = Some 11;\n        create_thread_initial_pc_index = None;\n        method_call_return_pc_index = Some 7; // The return PC is \"main.3.R\" (B.PC #7)\n      }\n    ];\n    // Atomic action #12\n    [ make_pc_indices 11 12 ];\n    // Atomic action #13\n    [ make_pc_indices 11 12 ];\n    // Atomic action #14\n    [ make_pc_indices 12 13 ];\n    // Atomic action #15\n    [ make_pc_indices 12 13 ];\n    // Atomic action #16\n    [ make_pc_indices 13 14 ];\n    // Atomic action #17\n    [ make_pc_indices 13 14 ];\n    // Atomic action #18\n    [ make_pc_indices 14 7 ];\n    // Atomic action #19\n    [ make_pc_indices 14 7 ];\n    // Atomic action #20\n    [ make_pc_indices 7 8 ];\n    // Atomic action #21\n    [ make_pc_indices 7 8 ];\n    // Atomic action #22\n    [ make_pc_indices 8 9; make_pc_indices 9 10 ];\n    // Atomic action #23\n    [ make_pc_indices 8 9 ];\n    // Atomic action #24\n    [ make_pc_indices 8 9; make_pc_indices 9 10 ];\n    // Atomic action #25\n    [ make_empty_pc_indices ];\n    // Atomic action #26\n    [ make_empty_pc_indices ];\n  ]\n\nlet vw: efficient_var_intro_witness_t = {\n  lprog = MyAProg.prog;\n  hprog = MyBProg.prog;\n  lprog_actions_array = list_to_array MyAtomicAProg.prog.actions;\n  hprog_actions_array = list_to_array MyAtomicBProg.prog.actions;\n  vs = vs;\n  tds = tds;\n  inv = MyAtomicBInvariant.inv;\n  which_initializers_are_intros = which_initializers_are_intros;\n  lpcs = lpcs;\n  hpcs = hpcs;\n  hpc_to_lpc = hpc_to_lpc;\n  lpc_to_hpcs = lpc_to_hpcs;\n  is_return_hpc = is_return_hpc;\n  is_nonyielding_lpc = is_nonyielding_lpc;\n  is_nonyielding_hpc = is_nonyielding_hpc;\n  is_breaking_hpc = is_breaking_hpc;\n  hpc_info = hpc_info;\n  corresponding_hactions_info = corresponding_hactions_info;\n  lprog_main_start_pc_index = lprog_main_start_pc_index;\n  hprog_main_start_pc_index = hprog_main_start_pc_index;\n  lpc_indices_array = lpc_indices_array;\n  hpc_indices_array = hpc_indices_array;\n}\n\nlet lemma_MyAtomicAProgRefinesMyAtomicBProg ()\n  : Lemma (spec_refines_spec\n           (semantics_to_spec (make_atomic_semantics armada_semantics) MyAtomicAProg.prog)\n           (semantics_to_spec (make_atomic_semantics armada_semantics) MyAtomicBProg.prog)\n           refinement_requirement) =\n  let latomic_prog = MyAtomicAProg.prog in\n  let hatomic_prog = MyAtomicBProg.prog in\n  assert (efficient_var_intro_witness_valid latomic_prog hatomic_prog vw)\n    by (FStar.Tactics.V2.compute (); FStar.Tactics.V2.trivial ());\n  MyAtomicBInvariant.inv_is_stepwise_invariant ();\n  efficient_var_intro_witness_valid_implies_refinement latomic_prog hatomic_prog vw\n"
  },
  {
    "path": "experimental/lib/Spec.Behavior.fst",
    "content": "module Spec.Behavior\n\nopen Spec.Ubool\n\ntype behavior_t (a: Type) = list a\ntype refinement_relation_t (low_state_t high_state_t: Type) = low_state_t -> high_state_t -> GTot ubool\nnoeq type spec_t (state_t: Type) = { init: state_t -> GTot ubool; next: state_t -> state_t -> GTot ubool }\n\nlet rec behavior_refines_behavior\n  (#low_state_t: Type)\n  (#high_state_t: Type)\n  (lb: behavior_t low_state_t)\n  (hb: behavior_t high_state_t)\n  (rr: refinement_relation_t low_state_t high_state_t)\n  : GTot ubool =\n  match lb with\n  | [] -> Nil? hb\n  | lstate :: ltail ->\n    match hb with\n    | [] -> false\n    | hstate :: htail ->\n      rr lstate hstate /\\\n      (  behavior_refines_behavior ltail htail rr // neither behavior stutters at the beginning\n       \\/ behavior_refines_behavior ltail hb rr  // behavior #1 stutters at the beginning\n       \\/ behavior_refines_behavior lb htail rr) // behavior #2 stutters at the beginning\n\nlet rec behavior_satisfies_next\n  (#state_t: Type)\n  (b: behavior_t state_t)\n  (next: state_t -> state_t -> GTot ubool)\n  : GTot ubool =\n  match b with\n  | [] -> True\n  | [s] -> True\n  | s1 :: s2 :: tl -> next s1 s2 /\\ behavior_satisfies_next (s2 :: tl) next\n\nlet behavior_satisfies_spec\n  (#state_t: Type)\n  (behavior: behavior_t state_t)\n  (spec: spec_t state_t)\n  : GTot ubool =\n  match behavior with\n  | [] -> False\n  | s1 :: _ -> spec.init s1 /\\ behavior_satisfies_next behavior spec.next\n\nlet spec_refines_spec\n  (#low_state_t: Type)\n  (#high_state_t: Type)\n  (lspec: spec_t low_state_t)\n  (hspec: spec_t high_state_t)\n  (rr: refinement_relation_t low_state_t high_state_t)  \n  : ubool =\n  forall (lb: behavior_t low_state_t).\n    behavior_satisfies_spec lb lspec\n    ==> (exists (hb: behavior_t high_state_t). behavior_satisfies_spec hb hspec /\\ behavior_refines_behavior lb hb rr)\n"
  },
  {
    "path": "experimental/lib/Spec.List.fst",
    "content": "module Spec.List\n\nopen FStar.Calc\nopen FStar.List.Tot\nopen Spec.Ubool\n\nlet list_len = length\nlet list_contains = mem\nlet contains_ubool = memP\n\nlet rec list_is_prefix_of_list (#a: Type) (l1: list a) (l2: list a) : GTot bool =\n  match l1 with\n  | [] -> true\n  | hd1 :: tl1 ->\n      match l2 with\n      | [] -> false\n      | hd2 :: tl2 -> eqb hd1 hd2 && list_is_prefix_of_list tl1 tl2\n"
  },
  {
    "path": "experimental/lib/Spec.Logic.fst",
    "content": "module Spec.Logic\n\nlet implies (b1: bool) (b2: bool) : bool =\n  (not b1) || b2\n"
  },
  {
    "path": "experimental/lib/Spec.Map.fst",
    "content": "module Spec.Map\n\nlet op_Hat_Subtraction_Greater = FStar.FunctionalExtensionality.op_Hat_Subtraction_Greater\n\nlet t (k: eqtype) (v: Type) = k ^-> v \nlet upd #k #v (m: t k v) (key: k) (value: v) : t k v = \n  FStar.FunctionalExtensionality.on_domain k (fun key' -> if key = key' then value else m key')\nlet const (#k: eqtype) (#v: Type) (value: v) : t k v = FStar.FunctionalExtensionality.on k (fun (_: k) -> value)\nlet map_eq #k #v (m0 m1: t k v)\n  : Lemma (requires forall key. m0 key == m1 key)\n          (ensures m0 == m1)\n  = FStar.FunctionalExtensionality.extensionality _ _ m0 m1\n"
  },
  {
    "path": "experimental/lib/Spec.Ubool.fst",
    "content": "module Spec.Ubool\n\ntype ubool = Type0 // not-necessarily-decidable boolean\n\nlet u2b (u: ubool) : GTot bool =\n  FStar.IndefiniteDescription.strong_excluded_middle u\n\nlet eqb (#a: Type) (x: a) (y: a) =\n  u2b (x == y)\n\nlet neqb (#a: Type) (x: a) (y: a) =\n  not (eqb x y)\n"
  },
  {
    "path": "experimental/lib/Strategies.ArmadaInvariant.PositionsValid.fst",
    "content": "module Strategies.ArmadaInvariant.PositionsValid\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Computation\nopen Armada.Expression\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Pointer\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Threads\nopen Armada.Transition\nopen Armada.Type\nopen FStar.Sequence.Ambient\nopen FStar.Sequence.Base\nopen FStar.Tactics.V2\nopen Spec.List\nopen Spec.Ubool\nopen Strategies.ArmadaStatement\nopen Util.Tactics\n\nlet init_implies_positions_valid_in_state (program: Armada.Program.t) (s: Armada.State.t)\n  : Lemma (requires init_program program s)\n          (ensures  positions_valid_in_state s) =\n  ()\n\nlet rec push_stack_variables_maintains_positions_valid_in_state\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (initializers: list initializer_t)\n  (s: Armada.State.t)\n  : Lemma (requires positions_valid_in_state s)\n          (ensures  (match push_stack_variables actor writer_pc writer_expression_number method_id\n                             frame_uniq initializers s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> positions_valid_in_state s'))\n          (decreases initializers) =\n  match initializers with\n  | [] -> ()\n  | first_initializer :: remaining_initializers ->\n      (match push_stack_variable actor writer_pc writer_expression_number method_id frame_uniq first_initializer s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces s' ->\n           push_stack_variables_maintains_positions_valid_in_state actor writer_pc (writer_expression_number + 1)\n             method_id frame_uniq remaining_initializers s')\n\nlet rec push_stack_parameters_maintains_positions_valid_in_state\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (var_ids: list var_id_t)\n  (parameters: list object_value_t)\n  (s: Armada.State.t)\n  : Lemma (requires positions_valid_in_state s)\n          (ensures  (match push_stack_parameters actor writer_pc writer_expression_number method_id frame_uniq\n                             var_ids parameters s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> positions_valid_in_state s'))\n          (decreases parameters) =\n  match parameters, var_ids with\n  | [], [] -> ()\n  | first_parameter :: remaining_parameters, first_var_id :: remaining_var_ids ->\n      let first_initializer =\n        { var_id = first_var_id; iv = InitializerSpecific first_parameter; weakly_consistent = false } in\n      (match push_stack_variable actor writer_pc writer_expression_number method_id frame_uniq first_initializer s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces s' ->\n           push_stack_parameters_maintains_positions_valid_in_state actor writer_pc (writer_expression_number + 1)\n             method_id frame_uniq remaining_var_ids remaining_parameters s')\n  | _ -> ()\n\n#push-options \"--z3rlimit 10\"\n\nlet update_pointed_to_value_maintains_positions_valid_in_state\n  (p: Armada.Pointer.t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (new_value: object_value_t)\n  (s: Armada.State.t)\n  : Lemma (requires positions_valid_in_state s)\n          (ensures  (match update_pointed_to_value p actor writer_pc writer_expression_number bypassing_write_buffer\n                             new_value s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> positions_valid_in_state s')) =\n  ()\n\nlet update_expression_maintains_positions_valid_in_state\n  (exp: expression_t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (new_value: object_value_t)\n  (s: Armada.State.t)\n  : Lemma (requires positions_valid_in_state s)\n          (ensures  (match update_expression exp actor writer_pc writer_expression_number bypassing_write_buffer\n                             new_value s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> positions_valid_in_state s')) =\n  ()\n\n#pop-options\n\nlet rec update_expressions_maintains_positions_valid_in_state\n  (exps: list expression_t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (new_values: list object_value_t)\n  (s: Armada.State.t)\n  : Lemma (requires positions_valid_in_state s)\n          (ensures  (match update_expressions exps actor writer_pc writer_expression_number bypassing_write_buffer\n                             new_values s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> positions_valid_in_state s'))\n          (decreases exps) =\n  match exps, new_values with\n  | [], [] -> ()\n  | first_exp :: remaining_exps, first_new_value :: remaining_new_values ->\n      update_expression_maintains_positions_valid_in_state first_exp actor writer_pc writer_expression_number\n        bypassing_write_buffer first_new_value s;\n      (match update_expression first_exp actor writer_pc writer_expression_number\n               bypassing_write_buffer first_new_value s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces s' ->\n           update_expressions_maintains_positions_valid_in_state remaining_exps actor writer_pc\n             (writer_expression_number + 1) bypassing_write_buffer remaining_new_values s')\n  | _ -> ()\n\nlet rec external_method_take_snapshot_of_reads_clauses_computation_maintains_positions_valid_in_state\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (reads_clauses: list (var_id_t * expression_t))\n  (s: Armada.State.t)\n  : Lemma (requires positions_valid_in_state s)\n          (ensures  (match external_method_take_snapshot_of_reads_clauses_computation actor writer_pc\n                             writer_expression_number bypassing_write_buffer reads_clauses s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> positions_valid_in_state s'))\n          (decreases reads_clauses) =\n  match reads_clauses with\n  | [] -> ()\n  | (first_var_id, first_reads_expression) :: remaining_reads_clauses ->\n      (match rvalue_computation first_reads_expression actor s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces first_value ->\n           let td = expression_to_td first_reads_expression in\n           let local_var = ExpressionLocalVariable td first_var_id in\n           update_expression_maintains_positions_valid_in_state local_var actor writer_pc writer_expression_number\n             bypassing_write_buffer first_value s;\n           (match update_expression local_var actor writer_pc writer_expression_number bypassing_write_buffer\n                    first_value s with\n            | ComputationImpossible | ComputationUndefined -> ()\n            | ComputationProduces s' ->\n                external_method_take_snapshot_of_reads_clauses_computation_maintains_positions_valid_in_state\n                  actor writer_pc (writer_expression_number + 1) bypassing_write_buffer remaining_reads_clauses s'))\n  | _ -> ()\n\nlet rec log_expressions_computation_maintains_positions_valid_in_state\n  (actor: tid_t)\n  (logs_clauses: list expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires positions_valid_in_state s)\n          (ensures  (match log_expressions_computation actor logs_clauses s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> positions_valid_in_state s'))\n          (decreases logs_clauses) =\n  match logs_clauses with\n  | [] -> ()\n  | first_logs_clause :: remaining_logs_clauses ->\n      (match rvalue_computation first_logs_clause actor s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces event ->\n           let trace' = s.trace $:: event in\n           let s' = { s with trace = trace' } in\n           log_expressions_computation_maintains_positions_valid_in_state actor remaining_logs_clauses s')\n\n#push-options \"--z3rlimit 10\"\n\nlet assume_expression_statement_computation_maintains_positions_valid_in_state\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (exp: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires positions_valid_in_state s)\n          (ensures  (match assume_expression_statement_computation actor nd start_pc exp s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> positions_valid_in_state s')) =\n  ()\n\nlet assume_predicate_statement_computation_maintains_positions_valid_in_state\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (pred: Armada.State.t -> GTot bool)\n  (s: Armada.State.t)\n  : Lemma (requires positions_valid_in_state s)\n          (ensures  (match assume_predicate_statement_computation actor nd start_pc pred s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> positions_valid_in_state s')) =\n  ()\n\nlet assert_true_statement_computation_maintains_positions_valid_in_state\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (exp: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires positions_valid_in_state s)\n          (ensures  (match assert_true_statement_computation actor nd start_pc exp s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> positions_valid_in_state s')) =\n  ()\n\nlet assert_false_statement_computation_maintains_positions_valid_in_state\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (exp: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires positions_valid_in_state s)\n          (ensures  (match assert_false_statement_computation actor nd start_pc exp s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> positions_valid_in_state s')) =\n  ()\n\nlet conditional_jump_statement_computation_maintains_positions_valid_in_state\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (exp: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires positions_valid_in_state s)\n          (ensures  (match conditional_jump_statement_computation actor nd start_pc exp s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> positions_valid_in_state s')) =\n  ()\n\nlet unconditional_jump_statement_computation_maintains_positions_valid_in_state\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (s: Armada.State.t)\n  : Lemma (requires positions_valid_in_state s)\n          (ensures  (match unconditional_jump_statement_computation actor nd start_pc s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> positions_valid_in_state s')) =\n  ()\n\nlet update_statement_computation_maintains_positions_valid_in_state\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (bypassing_write_buffer: bool)\n  (dst: expression_t)\n  (src: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires positions_valid_in_state s)\n          (ensures  (match update_statement_computation actor nd start_pc bypassing_write_buffer dst src s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> positions_valid_in_state s')) =\n  let cs' = update_statement_computation actor nd start_pc bypassing_write_buffer dst src s in\n  if   Cons? nd\n     || neqb (expression_to_td dst) (expression_to_td src) then\n    ()\n  else (\n    match rvalue_computation src actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces src_value ->\n        update_expression_maintains_positions_valid_in_state dst actor start_pc 0 bypassing_write_buffer src_value s\n  )\n\nlet nondeterministic_update_statement_computation_maintains_positions_valid_in_state\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (bypassing_write_buffer: bool)\n  (dst: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires positions_valid_in_state s)\n          (ensures  (match nondeterministic_update_statement_computation actor nd start_pc bypassing_write_buffer\n                             dst s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> positions_valid_in_state s')) =\n  let cs' = nondeterministic_update_statement_computation actor nd start_pc bypassing_write_buffer dst s in\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (expression_to_td dst) then\n    ()\n  else (\n    let nd_value = Cons?.hd nd in\n    if not (object_value_has_all_pointers_uninitialized nd_value) then\n      ()\n    else\n      update_expression_maintains_positions_valid_in_state dst actor start_pc 0 bypassing_write_buffer nd_value s\n  )\n\nlet propagate_write_message_statement_computation_maintains_positions_valid_in_state\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (s: Armada.State.t)\n  : Lemma (requires positions_valid_in_state s)\n          (ensures  (match propagate_write_message_statement_computation actor nd s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> positions_valid_in_state s')) =\n  ()\n\nlet compare_and_swap_statement_computation_maintains_positions_valid_in_state\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (target: expression_t)\n  (old_val: expression_t)\n  (new_val: expression_t)\n  (bypassing_write_buffer: bool)\n  (optional_result: option expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires positions_valid_in_state s)\n          (ensures  (match compare_and_swap_statement_computation actor nd start_pc target old_val new_val\n                             bypassing_write_buffer optional_result s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> positions_valid_in_state s')) =\n  let cs' = compare_and_swap_statement_computation actor nd start_pc target old_val new_val\n              bypassing_write_buffer optional_result s in\n  if   Cons? nd\n     || neqb (expression_to_td target) (expression_to_td old_val)\n     || neqb (expression_to_td target) (expression_to_td new_val)\n     || (match optional_result with\n        | Some result -> neqb (expression_to_td result) (ObjectTDPrimitive PrimitiveTDBool)\n        | None -> false) then\n    ()\n  else begin\n    match check_expression_up_to_date_for_rmw target actor s, rvalue_computation old_val actor s,\n          rvalue_computation target actor s, rvalue_computation new_val actor s,\n          lvalue_computation target actor s  with\n    | ComputationProduces _, ComputationProduces old_value,\n      ComputationProduces target_value, ComputationProduces new_value,\n      ComputationProduces target_ptr -> begin\n        let swap = eqb target_value old_value in\n        update_pointed_to_value_maintains_positions_valid_in_state target_ptr actor start_pc 0 false new_value s;\n        match optional_result with\n        | None -> ()\n        | Some result ->\n          match lvalue_computation result actor s, (if swap then update_pointed_to_value target_ptr actor start_pc 0 false new_value s else return s) with\n          | ComputationProduces result_ptr, ComputationProduces s' ->\n              let swap_value = ObjectValuePrimitive (PrimitiveBoxBool swap) in\n              update_pointed_to_value_maintains_positions_valid_in_state result_ptr actor start_pc 1 bypassing_write_buffer swap_value s'\n          | _ -> ()\n      end\n    | _ -> ()\n  end\n\nlet atomic_exchange_statement_computation_maintains_positions_valid_in_state\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (old_val: expression_t)\n  (target: expression_t)\n  (new_val: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires positions_valid_in_state s)\n          (ensures  (match atomic_exchange_statement_computation actor nd start_pc old_val target new_val s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> positions_valid_in_state s')) =\n  let cs' = atomic_exchange_statement_computation actor nd start_pc old_val target new_val s in\n  match check_expression_up_to_date_for_rmw target actor s, rvalue_computation target actor s, rvalue_computation new_val actor s, lvalue_computation old_val actor s, lvalue_computation target actor s with\n  | ComputationProduces _, ComputationProduces target_value, ComputationProduces new_value, ComputationProduces old_ptr, ComputationProduces target_ptr ->\n    update_pointed_to_value_maintains_positions_valid_in_state old_ptr actor start_pc 0 false target_value s;\n    begin match update_pointed_to_value old_ptr actor start_pc 0 false target_value s with\n          | ComputationProduces s' ->\n            update_pointed_to_value_maintains_positions_valid_in_state target_ptr actor start_pc 1 false new_value s'\n          | _ -> ()\n    end\n  | _ -> ()\n\nlet make_thread_running_maintains_positions_valid_in_state\n  (method_id: method_id_t)\n  (initial_pc: pc_t)\n  (new_tid: tid_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (s: Armada.State.t)\n  : Lemma (requires positions_valid_in_state s)\n          (ensures  positions_valid_in_state (make_thread_running method_id initial_pc new_tid frame_uniq s)) =\n  ()\n\nlet create_thread_statement_computation_maintains_positions_valid_in_state\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (method_id: method_id_t)\n  (initial_pc: pc_t)\n  (bypassing_write_buffer: bool)\n  (optional_result: option expression_t)\n  (parameter_var_ids: list var_id_t)\n  (parameter_expressions: list expression_t)\n  (local_variable_initializers: list initializer_t)\n  (s: Armada.State.t)\n  : Lemma (requires positions_valid_in_state s)\n          (ensures  (match create_thread_statement_computation actor nd start_pc method_id initial_pc\n                             bypassing_write_buffer optional_result parameter_var_ids parameter_expressions\n                             local_variable_initializers s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> positions_valid_in_state s')) =\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract create_thread_nd_t)\n     || (   Some? optional_result\n        && neqb (expression_to_td (Some?.v optional_result)) (ObjectTDPrimitive PrimitiveTDThreadId))\n     || list_len parameter_var_ids <> list_len parameter_expressions then\n    ()\n  else (\n    let create_thread_nd: create_thread_nd_t = ObjectValueAbstract?.value (Cons?.hd nd) in\n    let new_tid = create_thread_nd.new_tid in\n    if new_tid = 0 then\n      (match optional_result with\n       | None -> ()\n       | Some result ->\n           let new_tid_value = ObjectValuePrimitive (PrimitiveBoxThreadId new_tid) in\n           update_expression_maintains_positions_valid_in_state result actor start_pc\n             (list_len parameter_var_ids + list_len local_variable_initializers) bypassing_write_buffer\n             new_tid_value s)\n    else (\n      let frame_uniq = create_thread_nd.frame_uniq in\n      match rvalues_computation parameter_expressions actor s with\n      | ComputationImpossible | ComputationUndefined -> ()\n      | ComputationProduces parameter_values ->\n          let s2 = make_thread_running method_id initial_pc new_tid frame_uniq s in\n          make_thread_running_maintains_positions_valid_in_state method_id initial_pc new_tid frame_uniq s;\n          push_stack_parameters_maintains_positions_valid_in_state new_tid start_pc 0 method_id\n            frame_uniq parameter_var_ids parameter_values s2;\n          (match push_stack_parameters new_tid start_pc 0 method_id frame_uniq parameter_var_ids\n                   parameter_values s2 with\n           | ComputationImpossible | ComputationUndefined -> ()\n           | ComputationProduces s3 ->\n                push_stack_variables_maintains_positions_valid_in_state new_tid start_pc\n                  (list_len parameter_var_ids) method_id frame_uniq local_variable_initializers s3;\n                (match push_stack_variables new_tid start_pc (list_len parameter_var_ids) method_id frame_uniq\n                         local_variable_initializers s3 with\n                 | ComputationImpossible | ComputationUndefined -> ()\n                 | ComputationProduces s4 ->\n                     (match optional_result with\n                      | None -> ()\n                      | Some result ->\n                         let new_tid_value = ObjectValuePrimitive (PrimitiveBoxThreadId new_tid) in\n                         update_expression_maintains_positions_valid_in_state result actor start_pc\n                           (list_len parameter_var_ids + list_len local_variable_initializers) bypassing_write_buffer\n                           new_tid_value s4)))\n    )\n  )\n\nlet method_call_statement_computation_maintains_positions_valid_in_state\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (method_id: method_id_t)\n  (return_pc: pc_t)\n  (parameter_var_ids: list var_id_t)\n  (parameter_expressions: list expression_t)\n  (local_variable_initializers: list initializer_t)\n  (stack_overflow: bool)\n  (s: Armada.State.t)\n  : Lemma (requires positions_valid_in_state s)\n          (ensures  (match method_call_statement_computation actor nd start_pc method_id return_pc parameter_var_ids\n                             parameter_expressions local_variable_initializers stack_overflow s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> positions_valid_in_state s')) =\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract method_call_nd_t) then\n    ()\n  else (\n    let method_call_nd: method_call_nd_t = ObjectValueAbstract?.value (Cons?.hd nd) in\n    let frame_uniq = method_call_nd.frame_uniq in\n    match rvalues_computation parameter_expressions actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces parameter_values ->\n        let s2 = push_stack_frame actor method_id return_pc frame_uniq s in\n        push_stack_parameters_maintains_positions_valid_in_state actor start_pc 0 method_id frame_uniq\n          parameter_var_ids parameter_values s2;\n        (match push_stack_parameters actor start_pc 0 method_id frame_uniq parameter_var_ids parameter_values s2 with\n         | ComputationImpossible | ComputationUndefined -> ()\n         | ComputationProduces s3 ->\n             push_stack_variables_maintains_positions_valid_in_state actor start_pc\n               (list_len parameter_var_ids) method_id frame_uniq\n               local_variable_initializers s3)\n  )\n\nlet return_statement_computation_maintains_positions_valid_in_state\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (end_pc: option pc_t)\n  (method_id: method_id_t)\n  (bypassing_write_buffer: bool)\n  (output_dsts: list expression_t)\n  (output_srcs: list expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires positions_valid_in_state s)\n          (ensures  (match return_statement_computation actor nd start_pc end_pc method_id bypassing_write_buffer\n                             output_dsts output_srcs s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> positions_valid_in_state s')) =\n  let thread = s.threads actor in\n  if   Cons? nd\n     || eqb thread.stack []\n     || thread.top.method_id <> method_id\n     || end_pc <> Some (Cons?.hd thread.stack).return_pc then\n    ()\n  else (\n    match rvalues_computation output_srcs actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces output_values ->\n        (match pop_stack_variables actor method_id thread.top.frame_uniq thread.top.local_variables s.mem with\n         | ComputationImpossible | ComputationUndefined -> ()\n         | ComputationProduces mem' ->\n             let s2 = pop_stack_frame actor mem' s in\n             update_expressions_maintains_positions_valid_in_state output_dsts actor\n               start_pc 0 bypassing_write_buffer output_values s2)\n  )\n\nlet terminate_thread_statement_computation_maintains_positions_valid_in_state\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (method_id: method_id_t)\n  (s: Armada.State.t)\n  : Lemma (requires positions_valid_in_state s)\n          (ensures  (match terminate_thread_statement_computation actor nd start_pc method_id s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> positions_valid_in_state s')) =\n  ()\n\nlet terminate_process_statement_computation_maintains_positions_valid_in_state\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (method_id: method_id_t)\n  (s: Armada.State.t)\n  : Lemma (requires positions_valid_in_state s)\n          (ensures  (match terminate_process_statement_computation actor nd start_pc method_id s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> positions_valid_in_state s')) =\n  ()\n\nlet join_statement_computation_maintains_positions_valid_in_state\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (join_tid: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires positions_valid_in_state s)\n          (ensures  (match join_statement_computation actor nd start_pc join_tid s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> positions_valid_in_state s')) =\n  ()\n\nlet alloc_successful_statement_computation_maintains_positions_valid_in_state\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (zero_initialized: bool)\n  (bypassing_write_buffer: bool)\n  (result: expression_t)\n  (allocation_td: object_td_t)\n  (count: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires positions_valid_in_state s)\n          (ensures  (match alloc_successful_statement_computation actor nd start_pc zero_initialized\n                             bypassing_write_buffer result allocation_td count s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> positions_valid_in_state s')) =\n  let cs' = alloc_successful_statement_computation actor nd start_pc zero_initialized bypassing_write_buffer result\n              allocation_td count s in\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract root_id_uniquifier_t)\n     || neqb (expression_to_td count) (ObjectTDAbstract nat)\n     || neqb (expression_to_td result) (ObjectTDPrimitive PrimitiveTDPointer) then\n    ()\n  else (\n    match rvalue_computation count actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces count_value ->\n        let sz = ObjectValueAbstract?.value count_value in\n        let array_td = ObjectTDArray allocation_td sz in\n        let uniq = ObjectValueAbstract?.value (Cons?.hd nd) in\n        let root_id = RootIdAllocation uniq in\n        (match s.mem root_id with\n         | RootAllocated allocated freed storage ->\n             if   allocated\n                || freed\n                || neqb (object_storage_to_td storage) array_td\n                || not (is_storage_ready_for_allocation storage)\n                || (not zero_initialized && not (object_storage_arbitrarily_initialized_correctly storage))\n                || (zero_initialized && not (is_storage_zero_filled storage)) then\n               ()\n             else (\n               let s' = mark_allocation_root_allocated uniq storage s in\n               let p = ObjectValuePrimitive (PrimitiveBoxPointer (PointerIndex (PointerRoot root_id) 0)) in\n               update_expression_maintains_positions_valid_in_state result actor start_pc 0 bypassing_write_buffer\n                 p s'\n             )\n         | _ -> ())\n  )\n\nlet alloc_returning_null_statement_computation_maintains_positions_valid_in_state\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (bypassing_write_buffer: bool)\n  (result: expression_t)\n  (count: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires positions_valid_in_state s)\n          (ensures  (match alloc_returning_null_statement_computation actor nd start_pc bypassing_write_buffer\n                             result count s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> positions_valid_in_state s')) =\n  let cs' = alloc_returning_null_statement_computation actor nd start_pc bypassing_write_buffer\n              result count s in\n  if   Cons? nd\n     || neqb (expression_to_td count) (ObjectTDAbstract nat)\n     || neqb (expression_to_td result) (ObjectTDPrimitive PrimitiveTDPointer) then\n    ()\n  else (\n    match rvalue_computation count actor s with\n    | ComputationUndefined | ComputationImpossible -> ()\n    | ComputationProduces _ ->\n        let p = ObjectValuePrimitive (PrimitiveBoxPointer PointerNull) in\n        update_expression_maintains_positions_valid_in_state result actor start_pc 0 bypassing_write_buffer p s\n  )\n\nlet dealloc_statement_computation_maintains_positions_valid_in_state\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (ptr: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires positions_valid_in_state s)\n          (ensures  (match dealloc_statement_computation actor nd start_pc ptr s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> positions_valid_in_state s')) =\n  ()\n\nlet somehow_statement_computation_maintains_positions_valid_in_state\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (undefined_unless_cond: expression_t)\n  (bypassing_write_buffer: bool)\n  (modifies_clauses: list expression_t)\n  (ensures_cond: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires positions_valid_in_state s)\n          (ensures  (match somehow_statement_computation actor nd start_pc undefined_unless_cond\n                             bypassing_write_buffer modifies_clauses ensures_cond s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> positions_valid_in_state s')) =\n  let cs' = somehow_statement_computation actor nd start_pc undefined_unless_cond bypassing_write_buffer\n              modifies_clauses ensures_cond s in\n  if   neqb (expression_to_td undefined_unless_cond) (ObjectTDPrimitive PrimitiveTDBool)\n     || neqb (expression_to_td ensures_cond) (ObjectTDPrimitive PrimitiveTDBool) then\n    ()\n  else (\n    match rvalue_computation undefined_unless_cond actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces undefined_unless_value ->\n        let undefined_unless_bool = PrimitiveBoxBool?.b (ObjectValuePrimitive?.value undefined_unless_value) in\n        if not undefined_unless_bool then\n          ()\n        else\n          update_expressions_maintains_positions_valid_in_state modifies_clauses actor start_pc 0\n            bypassing_write_buffer nd s\n  )\n\nlet fence_statement_computation_maintains_positions_valid_in_state\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (s: Armada.State.t)\n  : Lemma (requires positions_valid_in_state s)\n          (ensures  (match fence_statement_computation actor nd start_pc s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> positions_valid_in_state s')) =\n  ()\n\nlet external_method_start_statement_computation_maintains_positions_valid_in_state\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (await_cond: expression_t)\n  (undefined_unless_cond: expression_t)\n  (bypassing_write_buffer: bool)\n  (modifies_clauses: list expression_t)\n  (reads_clauses: list (var_id_t * expression_t))\n  (s: Armada.State.t)\n  : Lemma (requires positions_valid_in_state s)\n          (ensures  (match external_method_start_statement_computation actor nd start_pc await_cond\n                             undefined_unless_cond bypassing_write_buffer modifies_clauses reads_clauses s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> positions_valid_in_state s')) =\n  let cs' = external_method_start_statement_computation actor nd start_pc await_cond undefined_unless_cond\n              bypassing_write_buffer modifies_clauses reads_clauses s in\n  if   neqb (expression_to_td await_cond) (ObjectTDPrimitive PrimitiveTDBool)\n     || neqb (expression_to_td undefined_unless_cond) (ObjectTDPrimitive PrimitiveTDBool)\n     || list_len modifies_clauses <> list_len nd then\n    ()\n  else (\n    match rvalue_computation await_cond actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces await_value ->\n        let await_bool = PrimitiveBoxBool?.b (ObjectValuePrimitive?.value await_value) in\n        if not await_bool then\n          ()\n        else (\n          match rvalue_computation undefined_unless_cond actor s with\n          | ComputationImpossible | ComputationUndefined -> ()\n          | ComputationProduces undefined_unless_value ->\n              let undefined_unless_bool = PrimitiveBoxBool?.b (ObjectValuePrimitive?.value await_value) in\n              if not undefined_unless_bool then\n                ()\n              else (\n                update_expressions_maintains_positions_valid_in_state modifies_clauses actor start_pc 0\n                  bypassing_write_buffer nd s;\n                match update_expressions modifies_clauses actor start_pc 0 bypassing_write_buffer nd s with\n                | ComputationImpossible | ComputationUndefined -> ()\n                | ComputationProduces s' ->\n                    external_method_take_snapshot_of_reads_clauses_computation_maintains_positions_valid_in_state\n                      actor start_pc (list_len modifies_clauses) bypassing_write_buffer reads_clauses s'\n              )\n        )\n  )\n\nlet external_method_middle_statement_computation_maintains_positions_valid_in_state\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (bypassing_write_buffer: bool)\n  (modifies_clauses: list expression_t)\n  (reads_clauses: list (var_id_t * expression_t))\n  (s: Armada.State.t)\n  : Lemma (requires positions_valid_in_state s)\n          (ensures  (match external_method_middle_statement_computation actor nd start_pc bypassing_write_buffer\n                             modifies_clauses reads_clauses s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> positions_valid_in_state s')) =\n  let cs' = external_method_middle_statement_computation actor nd start_pc bypassing_write_buffer\n              modifies_clauses reads_clauses s in\n  match external_method_check_snapshot_computation actor reads_clauses s with\n  | ComputationImpossible | ComputationUndefined -> ()\n  | ComputationProduces _ ->\n      update_expressions_maintains_positions_valid_in_state modifies_clauses actor start_pc 0\n        bypassing_write_buffer nd s;\n      (match update_expressions modifies_clauses actor start_pc 0 bypassing_write_buffer nd s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces s' ->\n           external_method_take_snapshot_of_reads_clauses_computation_maintains_positions_valid_in_state\n             actor start_pc (list_len modifies_clauses) bypassing_write_buffer reads_clauses s')\n\nlet external_method_end_statement_computation_maintains_positions_valid_in_state\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (ensures_cond: expression_t)\n  (logs_clauses: list expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires positions_valid_in_state s)\n          (ensures  (match external_method_end_statement_computation actor nd start_pc ensures_cond logs_clauses s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> positions_valid_in_state s')) =\n  let cs' = external_method_end_statement_computation actor nd start_pc ensures_cond logs_clauses s in\n  if   Cons? nd\n     || neqb (expression_to_td ensures_cond) (ObjectTDPrimitive PrimitiveTDBool) then\n    ()\n  else (\n    match rvalue_computation ensures_cond actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces ensures_value ->\n        let ensures_bool = PrimitiveBoxBool?.b (ObjectValuePrimitive?.value ensures_value) in\n        log_expressions_computation_maintains_positions_valid_in_state actor logs_clauses s\n  )\n\n#pop-options\n\nlet executing_statement_maintains_positions_valid_in_state\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (end_pc: option pc_t)\n  (statement: Armada.Statement.t)\n  (s: Armada.State.t)\n  : Lemma (requires positions_valid_in_state s)\n          (ensures  (match statement_computation actor nd start_pc end_pc statement s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> positions_valid_in_state s')) =\n  match statement_computation actor nd start_pc end_pc statement s with\n  | ComputationImpossible | ComputationUndefined -> ()\n  | ComputationProduces s' ->\n      (match statement with\n       | AssumeExpressionStatement exp ->\n           assume_expression_statement_computation_maintains_positions_valid_in_state actor nd start_pc exp s\n       | AssumePredicateStatement pred ->\n           assume_predicate_statement_computation_maintains_positions_valid_in_state actor nd start_pc pred s\n       | AssertTrueStatement exp ->\n           assert_true_statement_computation_maintains_positions_valid_in_state actor nd start_pc exp s\n       | AssertFalseStatement exp ->\n           assert_false_statement_computation_maintains_positions_valid_in_state actor nd start_pc exp s\n       | ConditionalJumpStatement cond ->\n           conditional_jump_statement_computation_maintains_positions_valid_in_state actor nd start_pc cond s\n       | UnconditionalJumpStatement ->\n           unconditional_jump_statement_computation_maintains_positions_valid_in_state actor nd start_pc s\n       | UpdateStatement bypassing_write_buffer dst src ->\n           update_statement_computation_maintains_positions_valid_in_state actor nd start_pc bypassing_write_buffer\n             dst src s\n       | NondeterministicUpdateStatement bypassing_write_buffer dst ->\n           nondeterministic_update_statement_computation_maintains_positions_valid_in_state actor nd start_pc\n             bypassing_write_buffer dst s\n       | PropagateWriteMessageStatement ->\n           propagate_write_message_statement_computation_maintains_positions_valid_in_state actor nd s\n       | CompareAndSwapStatement target old_val new_val bypassing_write_buffer optional_result ->\n           compare_and_swap_statement_computation_maintains_positions_valid_in_state actor nd start_pc target\n             old_val new_val bypassing_write_buffer optional_result s\n       | AtomicExchangeStatement old_val target new_val ->\n           atomic_exchange_statement_computation_maintains_positions_valid_in_state actor nd\n             start_pc old_val target new_val s\n       | CreateThreadStatement method_id initial_pc bypassing_write_buffer optional_result parameter_var_ids\n                               parameter_expressions local_variable_initializers ->\n           create_thread_statement_computation_maintains_positions_valid_in_state actor nd start_pc method_id\n             initial_pc bypassing_write_buffer optional_result parameter_var_ids parameter_expressions\n             local_variable_initializers s\n       | MethodCallStatement method_id return_pc parameter_var_ids parameter_expressions local_variable_initializers\n                               stack_overflow ->\n           method_call_statement_computation_maintains_positions_valid_in_state actor nd start_pc method_id return_pc\n             parameter_var_ids parameter_expressions local_variable_initializers stack_overflow s\n       | ReturnStatement method_id bypassing_write_buffer output_dsts output_srcs ->\n           return_statement_computation_maintains_positions_valid_in_state actor nd start_pc end_pc method_id\n             bypassing_write_buffer output_dsts output_srcs s\n       | TerminateThreadStatement method_id ->\n           terminate_thread_statement_computation_maintains_positions_valid_in_state actor nd start_pc method_id s\n       | TerminateProcessStatement method_id ->\n           terminate_process_statement_computation_maintains_positions_valid_in_state actor nd start_pc method_id s\n       | JoinStatement join_tid ->\n           join_statement_computation_maintains_positions_valid_in_state actor nd start_pc join_tid s\n       | MallocSuccessfulStatement bypassing_write_buffer result allocation_td count ->\n           alloc_successful_statement_computation_maintains_positions_valid_in_state actor nd start_pc false\n             bypassing_write_buffer result allocation_td count s\n       | MallocReturningNullStatement bypassing_write_buffer result count ->\n           alloc_returning_null_statement_computation_maintains_positions_valid_in_state actor nd start_pc\n             bypassing_write_buffer result count s\n       | CallocSuccessfulStatement bypassing_write_buffer result allocation_td count ->\n           alloc_successful_statement_computation_maintains_positions_valid_in_state actor nd start_pc true\n             bypassing_write_buffer result allocation_td count s\n       | CallocReturningNullStatement bypassing_write_buffer result count ->\n           alloc_returning_null_statement_computation_maintains_positions_valid_in_state actor nd start_pc\n             bypassing_write_buffer result count s\n       | DeallocStatement ptr ->\n           dealloc_statement_computation_maintains_positions_valid_in_state actor nd start_pc ptr s\n       | SomehowStatement undefined_unless_cond bypassing_write_buffer modifies_clauses ensures_cond ->\n           somehow_statement_computation_maintains_positions_valid_in_state actor nd start_pc undefined_unless_cond\n             bypassing_write_buffer modifies_clauses ensures_cond s\n       | FenceStatement ->\n           fence_statement_computation_maintains_positions_valid_in_state actor nd start_pc s\n       | ExternalMethodStartStatement await_cond undefined_unless_cond bypassing_write_buffer\n                                      modifies_clauses reads_clauses ->\n           external_method_start_statement_computation_maintains_positions_valid_in_state actor nd start_pc await_cond\n             undefined_unless_cond bypassing_write_buffer modifies_clauses reads_clauses s\n       | ExternalMethodMiddleStatement bypassing_write_buffer modifies_clauses reads_clauses ->\n           external_method_middle_statement_computation_maintains_positions_valid_in_state actor nd start_pc\n             bypassing_write_buffer modifies_clauses reads_clauses s\n       | ExternalMethodEndStatement ensures_cond logs_clauses ->\n           external_method_end_statement_computation_maintains_positions_valid_in_state actor nd start_pc ensures_cond\n             logs_clauses s\n      )     \n"
  },
  {
    "path": "experimental/lib/Strategies.ArmadaInvariant.PositionsValid.fsti",
    "content": "module Strategies.ArmadaInvariant.PositionsValid\n\nopen Armada.Base\nopen Armada.Computation\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Threads\nopen Armada.Type\nopen FStar.Sequence.Base\nopen Spec.Ubool\n\nlet position_valid (threads: Armada.Threads.t) (sender_tid: tid_t) (receiver_tid: tid_t) : GTot bool =\n  let sender_thread = threads sender_tid in\n  let receiver_thread = threads receiver_tid in\n  let position = receiver_thread.position_in_other_write_buffers sender_tid in\n  position <= length sender_thread.write_buffer\n\nlet sender_receiver_trigger (sender_tid: tid_t) (receiver_tid: tid_t) : GTot bool =\n  true\n\nlet positions_valid_in_threads (threads: Armada.Threads.t) : GTot ubool =\n  forall sender_tid receiver_tid.{:pattern sender_receiver_trigger sender_tid receiver_tid}\n    sender_receiver_trigger sender_tid receiver_tid\n    ==> position_valid threads sender_tid receiver_tid\n\nlet positions_valid_in_state (s: Armada.State.t) : GTot ubool =\n  positions_valid_in_threads s.threads\n\nval init_implies_positions_valid_in_state (program: Armada.Program.t) (s: Armada.State.t)\n  : Lemma (requires init_program program s)\n          (ensures  positions_valid_in_state s)\n\nval propagate_write_message_statement_computation_maintains_positions_valid_in_state\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (s: Armada.State.t)\n  : Lemma (requires positions_valid_in_state s)\n          (ensures  (match propagate_write_message_statement_computation actor nd s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> positions_valid_in_state s'))\n\nval executing_statement_maintains_positions_valid_in_state\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (end_pc: option pc_t)\n  (statement: Armada.Statement.t)\n  (s: Armada.State.t)\n  : Lemma (requires positions_valid_in_state s)\n          (ensures  (match statement_computation actor nd start_pc end_pc statement s with\n                     | ComputationProduces s' -> positions_valid_in_state s'\n                     | _ -> True))\n"
  },
  {
    "path": "experimental/lib/Strategies.ArmadaInvariant.RootsMatch.fst",
    "content": "module Strategies.ArmadaInvariant.RootsMatch\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Computation\nopen Armada.Expression\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Pointer\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Transition\nopen Armada.Type\nopen FStar.Sequence.Base\nopen FStar.Tactics.V2\nopen Spec.List\nopen Spec.Map\nopen Spec.Ubool\nopen Strategies.ArmadaStatement\nopen Util.Tactics\n\nlet root_matches_root_id (root: root_t) (root_id: root_id_t) : GTot bool =\n  match root with\n  | RootGlobal _ -> RootIdGlobal? root_id\n  | RootStackVariable _ _ _ -> RootIdStack? root_id\n  | RootAllocated _ _ _ -> RootIdAllocation? root_id\n  | RootFence storage ->\n          RootIdFence? root_id\n       && eqb (object_storage_to_td storage) (ObjectTDPrimitive PrimitiveTDBool)\n  | RootInvalid -> true\n\nlet roots_match (mem: Armada.Memory.t) : ubool =\n  forall root_id. root_matches_root_id (mem root_id) root_id\n\nlet init_implies_roots_match (program: Armada.Program.t) (s: Armada.State.t)\n  : Lemma (requires init_program program s)\n          (ensures  roots_match s.mem) =\n  let thread = s.threads s.initial_tid in\n  let initial_frame_uniq = Cons?.hd s.uniqs_used in\n  introduce forall root_id. root_matches_root_id (s.mem root_id) root_id\n  with (\n    let thread = s.threads s.initial_tid in\n    let initial_frame_uniq = Cons?.hd s.uniqs_used in\n    assert (root_invalid_outside_initializations s.mem program.global_initializers s.initial_tid\n              program.main_method_id initial_frame_uniq thread.top.local_variables root_id)\n  )\n\nlet rec update_pointer_directly_maintains_roots_match\n  (p: Armada.Pointer.t)\n  (new_storage: valid_object_storage_t)\n  (mem: Armada.Memory.t)\n  : Lemma (requires roots_match mem)\n          (ensures  (match update_pointer_directly p new_storage mem with\n                     | ComputationProduces mem' -> roots_match mem'\n                     | _ -> True)) =\n  match update_pointer_directly p new_storage mem with\n  | ComputationImpossible | ComputationUndefined -> ()\n  | ComputationProduces mem' ->\n      (match p with\n       | PointerField struct_ptr field_id ->\n           let parent = ComputationProduces?.result (dereference_computation struct_ptr mem) in\n           (match parent with\n            | ObjectStorageStruct fields ->\n                let new_parent = update_storage_child parent field_id new_storage in\n                update_pointer_directly_maintains_roots_match struct_ptr new_parent mem)\n       | PointerIndex array_ptr idx ->\n           let parent = ComputationProduces?.result (dereference_computation array_ptr mem) in\n           (match parent with\n            | ObjectStorageArray element_td elements ->\n                let new_parent = update_storage_child parent idx new_storage in\n                update_pointer_directly_maintains_roots_match array_ptr new_parent mem)\n       | PointerRoot root_id -> ()\n       | _ -> ())\n\n#push-options \"--z3rlimit 10\"\n\nlet update_pointer_maintains_roots_match\n  (p: Armada.Pointer.t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (new_value: object_value_t)\n  (mem: Armada.Memory.t)\n  : Lemma (requires roots_match mem)\n          (ensures  (match update_pointer p actor writer_pc writer_expression_number bypassing_write_buffer\n                             new_value mem with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces (optional_write_message, mem') -> roots_match mem')) =\n  match p with\n  | PointerUninitialized -> ()\n  | PointerNull -> ()\n  | PointerRoot root_id -> ()\n  | PointerField struct_ptr field_id ->\n      (match dereference_computation struct_ptr mem with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces parent ->\n           (match parent with\n            | ObjectStorageStruct fields ->\n                if field_id >= length fields then\n                  ()\n                else\n                  let field = index fields field_id in\n                  if   not (object_storage_valid field)\n                     || neqb (object_storage_to_td field) (object_value_to_td new_value) then\n                    ()\n                  else\n                    (match update_storage p actor writer_pc writer_expression_number\n                             bypassing_write_buffer field new_value with\n                     | ComputationImpossible | ComputationUndefined -> ()\n                     | ComputationProduces (write_message, new_field) ->\n                         if (not (can_update_storage_child parent field_id new_field)) then\n                           ()\n                         else\n                           let new_parent = update_storage_child parent field_id new_field in\n                           update_pointer_directly_maintains_roots_match struct_ptr new_parent mem)\n            | _ -> ()))\n  | PointerIndex array_ptr idx ->\n      (match dereference_computation array_ptr mem with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces parent ->\n           (match parent with\n            | ObjectStorageArray element_td elements ->\n                if idx < 0 || idx >= length elements then\n                  ()\n                else\n                  let element = index elements idx in\n                  if not (object_storage_valid element) then\n                    ()\n                  else\n                    (match update_storage p actor writer_pc writer_expression_number\n                             bypassing_write_buffer element new_value with\n                     | ComputationImpossible | ComputationUndefined -> ()\n                     | ComputationProduces (write_message, new_element) ->\n                         if not (can_update_storage_child parent idx new_element) then\n                           ()\n                         else\n                           let new_parent = update_storage_child parent idx new_element in\n                           update_pointer_directly_maintains_roots_match array_ptr new_parent mem)\n            | _ -> ()))\n\n#pop-options\n\nlet update_pointed_to_value_maintains_roots_match\n  (p: Armada.Pointer.t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (new_value: object_value_t)\n  (s: Armada.State.t)\n  : Lemma (requires roots_match s.mem)\n          (ensures  (match update_pointed_to_value p actor writer_pc writer_expression_number bypassing_write_buffer\n                             new_value s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> roots_match s'.mem)) =\n  update_pointer_maintains_roots_match p actor writer_pc writer_expression_number bypassing_write_buffer\n    new_value s.mem\n\nlet update_expression_maintains_roots_match\n  (exp: expression_t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (new_value: object_value_t)\n  (s: Armada.State.t)\n  : Lemma (requires roots_match s.mem)\n          (ensures  (match update_expression exp actor writer_pc writer_expression_number bypassing_write_buffer\n                             new_value s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> roots_match s'.mem)) =\n  let s' = update_expression exp actor writer_pc writer_expression_number bypassing_write_buffer\n             new_value s in\n  if   not (expression_valid exp)\n     || not (object_value_valid new_value)\n     || neqb (object_value_to_td new_value) (expression_to_td exp) then\n    ()\n  else (\n    match lvalue_computation exp actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces p ->\n        update_pointed_to_value_maintains_roots_match p actor writer_pc writer_expression_number\n          bypassing_write_buffer new_value s\n  )\n\nlet rec update_expressions_maintains_roots_match\n  (exps: list expression_t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (new_values: list object_value_t)\n  (s: Armada.State.t)\n  : Lemma (requires roots_match s.mem)\n          (ensures  (match update_expressions exps actor writer_pc writer_expression_number bypassing_write_buffer\n                             new_values s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> roots_match s'.mem))\n          (decreases exps) =\n  match exps, new_values with\n  | [], [] -> ()\n  | first_exp :: remaining_exps, first_new_value :: remaining_new_values ->\n      update_expression_maintains_roots_match first_exp actor writer_pc writer_expression_number\n        bypassing_write_buffer first_new_value s;\n      (match update_expression first_exp actor writer_pc writer_expression_number\n               bypassing_write_buffer first_new_value s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces s' ->\n           update_expressions_maintains_roots_match remaining_exps actor writer_pc\n             (writer_expression_number + 1) bypassing_write_buffer remaining_new_values s')\n  | _ -> ()\n\nlet push_stack_variable_maintains_roots_match\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (initializer: initializer_t)\n  (s: Armada.State.t)\n  : Lemma (requires roots_match s.mem)\n          (ensures  (match push_stack_variable actor writer_pc writer_expression_number method_id frame_uniq\n                             initializer s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> roots_match s'.mem)) =\n  let root_id = RootIdStack actor method_id frame_uniq initializer.var_id in\n  let root = s.mem root_id in\n  if not (stack_variable_ready_for_push root initializer) then\n    ()\n  else\n    let thread = s.threads actor in\n    let var_id = initializer.var_id in\n    if list_contains var_id thread.top.local_variables then\n      ()\n    else\n      let local_variables' = var_id :: thread.top.local_variables in\n      let top' = { thread.top with local_variables = local_variables' } in\n      let thread' = { thread with top = top' } in\n      let threads' = Spec.Map.upd s.threads actor thread' in\n      let root' = RootStackVariable true false (RootStackVariable?.storage root) in\n      let mem' = upd s.mem root_id root' in\n      let s' = { s with mem = mem'; threads = threads' } in\n      (match initializer.iv with\n       | InitializerArbitrary td -> ()\n       | InitializerSpecific value ->\n           let td = (object_value_to_td value) in\n           update_expression_maintains_roots_match (ExpressionLocalVariable td var_id) actor writer_pc\n             writer_expression_number false value s')\n\nlet rec push_stack_variables_maintains_roots_match\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (initializers: list initializer_t)\n  (s: Armada.State.t)\n  : Lemma (requires roots_match s.mem)\n          (ensures  (match push_stack_variables actor writer_pc writer_expression_number method_id\n                             frame_uniq initializers s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> roots_match s'.mem))\n          (decreases initializers) =\n  match initializers with\n  | [] -> ()\n  | first_initializer :: remaining_initializers ->\n      push_stack_variable_maintains_roots_match actor writer_pc writer_expression_number method_id frame_uniq\n        first_initializer s;\n      (match push_stack_variable actor writer_pc writer_expression_number method_id frame_uniq first_initializer s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces s' ->\n           push_stack_variables_maintains_roots_match actor writer_pc (writer_expression_number + 1)\n             method_id frame_uniq remaining_initializers s')\n\nlet rec push_stack_parameters_maintains_roots_match\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (var_ids: list var_id_t)\n  (parameters: list object_value_t)\n  (s: Armada.State.t)\n  : Lemma (requires roots_match s.mem)\n          (ensures  (match push_stack_parameters actor writer_pc writer_expression_number method_id frame_uniq\n                             var_ids parameters s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> roots_match s'.mem))\n          (decreases parameters) =\n  match parameters, var_ids with\n  | [], [] -> ()\n  | first_parameter :: remaining_parameters, first_var_id :: remaining_var_ids ->\n      let first_initializer =\n        { var_id = first_var_id; iv = InitializerSpecific first_parameter; weakly_consistent = false } in\n      push_stack_variable_maintains_roots_match actor writer_pc writer_expression_number method_id frame_uniq\n        first_initializer s;\n      (match push_stack_variable actor writer_pc writer_expression_number method_id frame_uniq first_initializer s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces s' ->\n           push_stack_parameters_maintains_roots_match actor writer_pc (writer_expression_number + 1)\n             method_id frame_uniq remaining_var_ids remaining_parameters s')\n  | _ -> ()\n\nlet rec pop_stack_variables_maintains_roots_match\n  (actor: tid_t)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (var_ids: list var_id_t)\n  (mem: Armada.Memory.t)\n  : Lemma (requires roots_match mem)\n          (ensures  (match pop_stack_variables actor method_id frame_uniq var_ids mem with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces mem' -> roots_match mem')) =\n  match var_ids with\n  | [] -> ()\n  | first_var_id :: remaining_var_ids ->\n      (match pop_stack_variable actor method_id frame_uniq first_var_id mem with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces mem' ->\n           pop_stack_variables_maintains_roots_match actor method_id frame_uniq remaining_var_ids mem')\n\nlet rec external_method_take_snapshot_of_reads_clauses_computation_maintains_roots_match\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (reads_clauses: list (var_id_t * expression_t))\n  (s: Armada.State.t)\n  : Lemma (requires roots_match s.mem)\n          (ensures  (match external_method_take_snapshot_of_reads_clauses_computation actor writer_pc\n                             writer_expression_number bypassing_write_buffer reads_clauses s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> roots_match s'.mem))\n          (decreases reads_clauses) =\n  match reads_clauses with\n  | [] -> ()\n  | (first_var_id, first_reads_expression) :: remaining_reads_clauses ->\n      (match rvalue_computation first_reads_expression actor s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces first_value ->\n           let td = expression_to_td first_reads_expression in\n           let local_var = ExpressionLocalVariable td first_var_id in\n           update_expression_maintains_roots_match local_var actor writer_pc writer_expression_number\n             bypassing_write_buffer first_value s;\n           (match update_expression local_var actor writer_pc writer_expression_number bypassing_write_buffer\n                    first_value s with\n            | ComputationImpossible | ComputationUndefined -> ()\n            | ComputationProduces s' ->\n                external_method_take_snapshot_of_reads_clauses_computation_maintains_roots_match\n                  actor writer_pc (writer_expression_number + 1) bypassing_write_buffer remaining_reads_clauses s'))\n  | _ -> ()\n\nlet rec log_expressions_computation_maintains_roots_match\n  (actor: tid_t)\n  (logs_clauses: list expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires roots_match s.mem)\n          (ensures  (match log_expressions_computation actor logs_clauses s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> roots_match s'.mem))\n          (decreases logs_clauses) =\n  match logs_clauses with\n  | [] -> ()\n  | first_logs_clause :: remaining_logs_clauses ->\n      (match rvalue_computation first_logs_clause actor s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces event ->\n           let trace' = s.trace $:: event in\n           let s' = { s with trace = trace' } in\n           log_expressions_computation_maintains_roots_match actor remaining_logs_clauses s')\n\nlet propagate_write_message_maintains_roots_match\n  (write_message: write_message_t)\n  (receiver_tid: tid_t)\n  (mem: Armada.Memory.t)\n  : Lemma (requires roots_match mem)\n          (ensures  (match propagate_write_message write_message receiver_tid mem with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces mem' -> roots_match mem')) =\n  let p = write_message.location in\n  match dereference_computation p mem with\n  | ComputationImpossible | ComputationUndefined -> ()\n  | ComputationProduces storage ->\n      (match storage with\n       | ObjectStorageWeaklyConsistentPrimitive primitive_td values local_versions ->\n           if   primitive_td <> write_message.primitive_td\n              || write_message.version >= length values\n              || local_versions receiver_tid >= write_message.version then\n             ()\n           else\n             let new_local_versions = Spec.Map.upd local_versions receiver_tid write_message.version in\n             let new_storage = ObjectStorageWeaklyConsistentPrimitive primitive_td values\n                                 new_local_versions in\n             if not (object_storage_valid new_storage) then\n               ()\n             else\n               update_pointer_directly_maintains_roots_match p new_storage mem\n       | _ -> ())\n\n#push-options \"--z3rlimit 10\"\n\nlet assume_expression_statement_computation_maintains_roots_match\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (exp: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires roots_match s.mem)\n          (ensures  (match assume_expression_statement_computation actor nd start_pc exp s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> roots_match s'.mem)) =\n  ()\n\nlet assume_predicate_statement_computation_maintains_roots_match\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (pred: Armada.State.t -> GTot bool)\n  (s: Armada.State.t)\n  : Lemma (requires roots_match s.mem)\n          (ensures  (match assume_predicate_statement_computation actor nd start_pc pred s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> roots_match s'.mem)) =\n  ()\n\nlet assert_true_statement_computation_maintains_roots_match\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (exp: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires roots_match s.mem)\n          (ensures  (match assert_true_statement_computation actor nd start_pc exp s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> roots_match s'.mem)) =\n  ()\n\nlet assert_false_statement_computation_maintains_roots_match\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (exp: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires roots_match s.mem)\n          (ensures  (match assert_false_statement_computation actor nd start_pc exp s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> roots_match s'.mem)) =\n  ()\n\nlet conditional_jump_statement_computation_maintains_roots_match\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (exp: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires roots_match s.mem)\n          (ensures  (match conditional_jump_statement_computation actor nd start_pc exp s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> roots_match s'.mem)) =\n  ()\n\nlet unconditional_jump_statement_computation_maintains_roots_match\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (s: Armada.State.t)\n  : Lemma (requires roots_match s.mem)\n          (ensures  (match unconditional_jump_statement_computation actor nd start_pc s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> roots_match s'.mem)) =\n  ()\n\nlet update_statement_computation_maintains_roots_match\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (bypassing_write_buffer: bool)\n  (dst: expression_t)\n  (src: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires roots_match s.mem)\n          (ensures  (match update_statement_computation actor nd start_pc bypassing_write_buffer dst src s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> roots_match s'.mem)) =\n  let cs' = update_statement_computation actor nd start_pc bypassing_write_buffer dst src s in\n  if   Cons? nd\n     || neqb (expression_to_td dst) (expression_to_td src) then\n    ()\n  else (\n    match rvalue_computation src actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces src_value ->\n        update_expression_maintains_roots_match dst actor start_pc 0 bypassing_write_buffer src_value s\n  )\n\nlet nondeterministic_update_statement_computation_maintains_roots_match\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (bypassing_write_buffer: bool)\n  (dst: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires roots_match s.mem)\n          (ensures  (match nondeterministic_update_statement_computation actor nd start_pc bypassing_write_buffer\n                             dst s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> roots_match s'.mem)) =\n  let cs' = nondeterministic_update_statement_computation actor nd start_pc bypassing_write_buffer dst s in\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (expression_to_td dst) then\n    ()\n  else (\n    let nd_value = Cons?.hd nd in\n    if not (object_value_has_all_pointers_uninitialized nd_value) then\n      ()\n    else\n      update_expression_maintains_roots_match dst actor start_pc 0 bypassing_write_buffer nd_value s\n  )\n\nlet propagate_write_message_statement_computation_maintains_roots_match\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (s: Armada.State.t)\n  : Lemma (requires roots_match s.mem)\n          (ensures  (match propagate_write_message_statement_computation actor nd s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> roots_match s'.mem)) =\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract tid_t) then\n     ()\n  else\n    let receiver_tid: tid_t = ObjectValueAbstract?.value (Cons?.hd nd) in\n    if receiver_tid = actor then // can't propagate to the same thread\n      ()\n    else\n      let propagator_thread = s.threads actor in\n      let receiver_thread = s.threads receiver_tid in\n      let which_message = receiver_thread.position_in_other_write_buffers actor in\n      if which_message >= length propagator_thread.write_buffer then\n        ()\n      else\n        let write_message = index propagator_thread.write_buffer which_message in\n        propagate_write_message_maintains_roots_match write_message receiver_tid s.mem\n\nlet compare_and_swap_statement_computation_maintains_roots_match\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (target: expression_t)\n  (old_val: expression_t)\n  (new_val: expression_t)\n  (bypassing_write_buffer: bool)\n  (optional_result: option expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires roots_match s.mem)\n          (ensures  (match compare_and_swap_statement_computation actor nd start_pc target old_val new_val\n                             bypassing_write_buffer optional_result s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> roots_match s'.mem)) =\n  let cs' = compare_and_swap_statement_computation actor nd start_pc target old_val new_val\n              bypassing_write_buffer optional_result s in\n  if   Cons? nd\n     || neqb (expression_to_td target) (expression_to_td old_val)\n     || neqb (expression_to_td target) (expression_to_td new_val)\n     || (match optional_result with\n        | Some result -> neqb (expression_to_td result) (ObjectTDPrimitive PrimitiveTDBool)\n        | None -> false) then\n    ()\n  else begin\n    match check_expression_up_to_date_for_rmw target actor s, rvalue_computation old_val actor s,\n          rvalue_computation target actor s, rvalue_computation new_val actor s,\n          lvalue_computation target actor s  with\n    | ComputationProduces _, ComputationProduces old_value,\n      ComputationProduces target_value, ComputationProduces new_value,\n      ComputationProduces target_ptr -> begin\n        let swap = eqb target_value old_value in\n        update_pointed_to_value_maintains_roots_match target_ptr actor start_pc 0 false new_value s;\n        match optional_result with\n        | None -> ()\n        | Some result ->\n          match lvalue_computation result actor s, (if swap then update_pointed_to_value target_ptr actor start_pc 0 false new_value s else return s) with\n          | ComputationProduces result_ptr, ComputationProduces s' ->\n              let swap_value = ObjectValuePrimitive (PrimitiveBoxBool swap) in\n              update_pointed_to_value_maintains_roots_match result_ptr actor start_pc 1 bypassing_write_buffer swap_value s'\n          | _ -> ()\n      end\n    | _ -> ()\n  end\n\nlet atomic_exchange_statement_computation_maintains_roots_match\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (old_val: expression_t)\n  (target: expression_t)\n  (new_val: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires roots_match s.mem)\n          (ensures  (match atomic_exchange_statement_computation actor nd start_pc old_val target new_val s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> roots_match s'.mem)) =\n  let cs' = atomic_exchange_statement_computation actor nd start_pc old_val target new_val s in\n  match check_expression_up_to_date_for_rmw target actor s, rvalue_computation target actor s, rvalue_computation new_val actor s, lvalue_computation old_val actor s, lvalue_computation target actor s with\n  | ComputationProduces _, ComputationProduces target_value, ComputationProduces new_value, ComputationProduces old_ptr, ComputationProduces target_ptr ->\n    update_pointed_to_value_maintains_roots_match old_ptr actor start_pc 0 false target_value s;\n    begin match update_pointed_to_value old_ptr actor start_pc 0 false target_value s with\n          | ComputationProduces s' ->\n            update_pointed_to_value_maintains_roots_match target_ptr actor start_pc 1 false new_value s'\n          | _ -> ()\n    end\n  | _ -> ()\n\nlet create_thread_statement_computation_maintains_roots_match\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (method_id: method_id_t)\n  (initial_pc: pc_t)\n  (bypassing_write_buffer: bool)\n  (optional_result: option expression_t)\n  (parameter_var_ids: list var_id_t)\n  (parameter_expressions: list expression_t)\n  (local_variable_initializers: list initializer_t)\n  (s: Armada.State.t)\n  : Lemma (requires roots_match s.mem)\n          (ensures  (match create_thread_statement_computation actor nd start_pc method_id initial_pc\n                             bypassing_write_buffer optional_result parameter_var_ids parameter_expressions\n                             local_variable_initializers s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> roots_match s'.mem)) =\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract create_thread_nd_t)\n     || (   Some? optional_result\n        && neqb (expression_to_td (Some?.v optional_result)) (ObjectTDPrimitive PrimitiveTDThreadId))\n     || list_len parameter_var_ids <> list_len parameter_expressions then\n    ()\n  else (\n    let create_thread_nd: create_thread_nd_t = ObjectValueAbstract?.value (Cons?.hd nd) in\n    let new_tid = create_thread_nd.new_tid in\n    if new_tid = 0 then\n      (match optional_result with\n       | None -> ()\n       | Some result ->\n          let new_tid_value = ObjectValuePrimitive (PrimitiveBoxThreadId new_tid) in\n          update_expression_maintains_roots_match result actor start_pc\n            (list_len parameter_var_ids + list_len local_variable_initializers) bypassing_write_buffer\n            new_tid_value s)\n    else (\n      let frame_uniq = create_thread_nd.frame_uniq in\n      match rvalues_computation parameter_expressions actor s with\n      | ComputationImpossible | ComputationUndefined -> ()\n      | ComputationProduces parameter_values ->\n          let s2 = make_thread_running method_id initial_pc new_tid frame_uniq s in\n          push_stack_parameters_maintains_roots_match new_tid start_pc 0 method_id\n            frame_uniq parameter_var_ids parameter_values s2;\n          (match push_stack_parameters new_tid start_pc 0 method_id frame_uniq parameter_var_ids\n                   parameter_values s2 with\n           | ComputationImpossible | ComputationUndefined -> ()\n           | ComputationProduces s3 ->\n                push_stack_variables_maintains_roots_match new_tid start_pc\n                  (list_len parameter_var_ids) method_id frame_uniq local_variable_initializers s3;\n                (match push_stack_variables new_tid start_pc (list_len parameter_var_ids) method_id frame_uniq\n                         local_variable_initializers s3 with\n                 | ComputationImpossible | ComputationUndefined -> ()\n                 | ComputationProduces s4 ->\n                     (match optional_result with\n                      | None -> ()\n                      | Some result ->\n                         let new_tid_value = ObjectValuePrimitive (PrimitiveBoxThreadId new_tid) in\n                         update_expression_maintains_roots_match result actor start_pc\n                           (list_len parameter_var_ids + list_len local_variable_initializers) bypassing_write_buffer\n                           new_tid_value s4)))\n    )\n  )\n\nlet method_call_statement_computation_maintains_roots_match\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (method_id: method_id_t)\n  (return_pc: pc_t)\n  (parameter_var_ids: list var_id_t)\n  (parameter_expressions: list expression_t)\n  (local_variable_initializers: list initializer_t)\n  (stack_overflow: bool)\n  (s: Armada.State.t)\n  : Lemma (requires roots_match s.mem)\n          (ensures  (match method_call_statement_computation actor nd start_pc method_id return_pc parameter_var_ids\n                             parameter_expressions local_variable_initializers stack_overflow s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> roots_match s'.mem)) =\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract method_call_nd_t) then\n    ()\n  else (\n    let method_call_nd: method_call_nd_t = ObjectValueAbstract?.value (Cons?.hd nd) in\n    let frame_uniq = method_call_nd.frame_uniq in\n    match rvalues_computation parameter_expressions actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces parameter_values ->\n        let s2 = push_stack_frame actor method_id return_pc frame_uniq s in\n        push_stack_parameters_maintains_roots_match actor start_pc 0 method_id frame_uniq\n          parameter_var_ids parameter_values s2;\n        (match push_stack_parameters actor start_pc 0 method_id frame_uniq parameter_var_ids parameter_values s2 with\n         | ComputationImpossible | ComputationUndefined -> ()\n         | ComputationProduces s3 ->\n             push_stack_variables_maintains_roots_match actor start_pc\n               (list_len parameter_var_ids) method_id frame_uniq\n               local_variable_initializers s3)\n  )\n\nlet return_statement_computation_maintains_roots_match\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (end_pc: option pc_t)\n  (method_id: method_id_t)\n  (bypassing_write_buffer: bool)\n  (output_dsts: list expression_t)\n  (output_srcs: list expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires roots_match s.mem)\n          (ensures  (match return_statement_computation actor nd start_pc end_pc method_id bypassing_write_buffer\n                             output_dsts output_srcs s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> roots_match s'.mem)) =\n  let thread = s.threads actor in\n  if   Cons? nd\n     || eqb thread.stack []\n     || thread.top.method_id <> method_id\n     || end_pc <> Some (Cons?.hd thread.stack).return_pc then\n    ()\n  else (\n    match rvalues_computation output_srcs actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces output_values ->\n        pop_stack_variables_maintains_roots_match actor method_id thread.top.frame_uniq\n          thread.top.local_variables s.mem;\n        (match pop_stack_variables actor method_id thread.top.frame_uniq thread.top.local_variables s.mem with\n         | ComputationImpossible | ComputationUndefined -> ()\n         | ComputationProduces mem' ->\n             let s2 = pop_stack_frame actor mem' s in\n             update_expressions_maintains_roots_match output_dsts actor\n               start_pc 0 bypassing_write_buffer output_values s2)\n  )\n\nlet terminate_thread_statement_computation_maintains_roots_match\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (method_id: method_id_t)\n  (s: Armada.State.t)\n  : Lemma (requires roots_match s.mem)\n          (ensures  (match terminate_thread_statement_computation actor nd start_pc method_id s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> roots_match s'.mem)) =\n  let thread = s.threads actor in\n  if   Cons? nd\n     || neqb thread.stack []\n     || thread.top.method_id <> method_id\n     || actor = s.initial_tid then\n    ()\n  else\n    pop_stack_variables_maintains_roots_match actor method_id thread.top.frame_uniq thread.top.local_variables s.mem\n\nlet terminate_process_statement_computation_maintains_roots_match\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (method_id: method_id_t)\n  (s: Armada.State.t)\n  : Lemma (requires roots_match s.mem)\n          (ensures  (match terminate_process_statement_computation actor nd start_pc method_id s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> roots_match s'.mem)) =\n  ()\n\nlet join_statement_computation_maintains_roots_match\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (join_tid: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires roots_match s.mem)\n          (ensures  (match join_statement_computation actor nd start_pc join_tid s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> roots_match s'.mem)) =\n  ()\n\nlet alloc_successful_statement_computation_maintains_roots_match\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (zero_initialized: bool)\n  (bypassing_write_buffer: bool)\n  (result: expression_t)\n  (allocation_td: object_td_t)\n  (count: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires roots_match s.mem)\n          (ensures  (match alloc_successful_statement_computation actor nd start_pc zero_initialized\n                             bypassing_write_buffer result allocation_td count s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> roots_match s'.mem)) =\n  let cs' = alloc_successful_statement_computation actor nd start_pc zero_initialized bypassing_write_buffer result\n              allocation_td count s in\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract root_id_uniquifier_t)\n     || neqb (expression_to_td count) (ObjectTDAbstract nat)\n     || neqb (expression_to_td result) (ObjectTDPrimitive PrimitiveTDPointer) then\n    ()\n  else (\n    match rvalue_computation count actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces count_value ->\n        let sz = ObjectValueAbstract?.value count_value in\n        let array_td = ObjectTDArray allocation_td sz in\n        let uniq = ObjectValueAbstract?.value (Cons?.hd nd) in\n        let root_id = RootIdAllocation uniq in\n        (match s.mem root_id with\n         | RootAllocated allocated freed storage ->\n             if   allocated\n                || freed\n                || neqb (object_storage_to_td storage) array_td\n                || not (is_storage_ready_for_allocation storage)\n                || (not zero_initialized && not (object_storage_arbitrarily_initialized_correctly storage))\n                || (zero_initialized && not (is_storage_zero_filled storage)) then\n               ()\n             else (\n               let s' = mark_allocation_root_allocated uniq storage s in\n               let p = ObjectValuePrimitive (PrimitiveBoxPointer (PointerIndex (PointerRoot root_id) 0)) in\n               update_expression_maintains_roots_match result actor start_pc 0 bypassing_write_buffer\n                 p s'\n             )\n         | _ -> ())\n  )\n\nlet alloc_returning_null_statement_computation_maintains_roots_match\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (bypassing_write_buffer: bool)\n  (result: expression_t)\n  (count: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires roots_match s.mem)\n          (ensures  (match alloc_returning_null_statement_computation actor nd start_pc bypassing_write_buffer\n                             result count s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> roots_match s'.mem)) =\n  let cs' = alloc_returning_null_statement_computation actor nd start_pc bypassing_write_buffer\n              result count s in\n  if   Cons? nd\n     || neqb (expression_to_td count) (ObjectTDAbstract nat)\n     || neqb (expression_to_td result) (ObjectTDPrimitive PrimitiveTDPointer) then\n    ()\n  else (\n    match rvalue_computation count actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces _ ->\n        let p = ObjectValuePrimitive (PrimitiveBoxPointer PointerNull) in\n        update_expression_maintains_roots_match result actor start_pc 0 bypassing_write_buffer p s\n  )\n\nlet dealloc_statement_computation_maintains_roots_match\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (ptr: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires roots_match s.mem)\n          (ensures  (match dealloc_statement_computation actor nd start_pc ptr s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> roots_match s'.mem)) =\n  let cs' = dealloc_statement_computation actor nd start_pc ptr s in\n  if   Cons? nd\n     || neqb (expression_to_td ptr) (ObjectTDPrimitive PrimitiveTDPointer) then\n    ()\n  else (\n    match rvalue_computation ptr actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces ptr_value ->\n        let p = PrimitiveBoxPointer?.ptr (ObjectValuePrimitive?.value ptr_value) in\n        (match free_pointer p s.mem with\n         | ComputationImpossible | ComputationUndefined -> ()\n         | ComputationProduces mem' -> ())\n  )\n\nlet somehow_statement_computation_maintains_roots_match\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (undefined_unless_cond: expression_t)\n  (bypassing_write_buffer: bool)\n  (modifies_clauses: list expression_t)\n  (ensures_cond: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires roots_match s.mem)\n          (ensures  (match somehow_statement_computation actor nd start_pc undefined_unless_cond\n                             bypassing_write_buffer modifies_clauses ensures_cond s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> roots_match s'.mem)) =\n  let cs' = somehow_statement_computation actor nd start_pc undefined_unless_cond bypassing_write_buffer\n              modifies_clauses ensures_cond s in\n  if   neqb (expression_to_td undefined_unless_cond) (ObjectTDPrimitive PrimitiveTDBool)\n     || neqb (expression_to_td ensures_cond) (ObjectTDPrimitive PrimitiveTDBool) then\n    ()\n  else (\n    match rvalue_computation undefined_unless_cond actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces undefined_unless_value ->\n        let undefined_unless_bool = PrimitiveBoxBool?.b (ObjectValuePrimitive?.value undefined_unless_value) in\n        if not undefined_unless_bool then\n          ()\n        else\n          update_expressions_maintains_roots_match modifies_clauses actor start_pc 0\n            bypassing_write_buffer nd s\n  )\n\nlet fence_statement_computation_maintains_roots_match\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (s: Armada.State.t)\n  : Lemma (requires roots_match s.mem)\n          (ensures  (match fence_statement_computation actor nd start_pc s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> roots_match s'.mem)) =\n  ()\n\nlet external_method_start_statement_computation_maintains_roots_match\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (await_cond: expression_t)\n  (undefined_unless_cond: expression_t)\n  (bypassing_write_buffer: bool)\n  (modifies_clauses: list expression_t)\n  (reads_clauses: list (var_id_t * expression_t))\n  (s: Armada.State.t)\n  : Lemma (requires roots_match s.mem)\n          (ensures  (match external_method_start_statement_computation actor nd start_pc await_cond\n                             undefined_unless_cond bypassing_write_buffer modifies_clauses reads_clauses s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> roots_match s'.mem)) =\n  let cs' = external_method_start_statement_computation actor nd start_pc await_cond undefined_unless_cond\n              bypassing_write_buffer modifies_clauses reads_clauses s in\n  if   neqb (expression_to_td await_cond) (ObjectTDPrimitive PrimitiveTDBool)\n     || neqb (expression_to_td undefined_unless_cond) (ObjectTDPrimitive PrimitiveTDBool)\n     || list_len modifies_clauses <> list_len nd then\n    ()\n  else (\n    match rvalue_computation await_cond actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces await_value ->\n        let await_bool = PrimitiveBoxBool?.b (ObjectValuePrimitive?.value await_value) in\n        if not await_bool then\n          ()\n        else (\n          match rvalue_computation undefined_unless_cond actor s with\n          | ComputationImpossible | ComputationUndefined -> ()\n          | ComputationProduces undefined_unless_value ->\n              let undefined_unless_bool = PrimitiveBoxBool?.b (ObjectValuePrimitive?.value await_value) in\n              if not undefined_unless_bool then\n                ()\n              else (\n                update_expressions_maintains_roots_match modifies_clauses actor start_pc 0\n                  bypassing_write_buffer nd s;\n                match update_expressions modifies_clauses actor start_pc 0 bypassing_write_buffer nd s with\n                | ComputationImpossible | ComputationUndefined -> ()\n                | ComputationProduces s' ->\n                    external_method_take_snapshot_of_reads_clauses_computation_maintains_roots_match\n                      actor start_pc (list_len modifies_clauses) bypassing_write_buffer reads_clauses s'\n              )\n        )\n  )\n\nlet external_method_middle_statement_computation_maintains_roots_match\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (bypassing_write_buffer: bool)\n  (modifies_clauses: list expression_t)\n  (reads_clauses: list (var_id_t * expression_t))\n  (s: Armada.State.t)\n  : Lemma (requires roots_match s.mem)\n          (ensures  (match external_method_middle_statement_computation actor nd start_pc bypassing_write_buffer\n                             modifies_clauses reads_clauses s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> roots_match s'.mem)) =\n  let cs' = external_method_middle_statement_computation actor nd start_pc bypassing_write_buffer\n              modifies_clauses reads_clauses s in\n  match external_method_check_snapshot_computation actor reads_clauses s with\n  | ComputationImpossible | ComputationUndefined -> ()\n  | ComputationProduces _ ->\n      update_expressions_maintains_roots_match modifies_clauses actor start_pc 0\n        bypassing_write_buffer nd s;\n      (match update_expressions modifies_clauses actor start_pc 0 bypassing_write_buffer nd s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces s' ->\n           external_method_take_snapshot_of_reads_clauses_computation_maintains_roots_match\n             actor start_pc (list_len modifies_clauses) bypassing_write_buffer reads_clauses s')\n\nlet external_method_end_statement_computation_maintains_roots_match\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (ensures_cond: expression_t)\n  (logs_clauses: list expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires roots_match s.mem)\n          (ensures  (match external_method_end_statement_computation actor nd start_pc ensures_cond logs_clauses s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> roots_match s'.mem)) =\n  let cs' = external_method_end_statement_computation actor nd start_pc ensures_cond logs_clauses s in\n  if   Cons? nd\n     || neqb (expression_to_td ensures_cond) (ObjectTDPrimitive PrimitiveTDBool) then\n    ()\n  else (\n    match rvalue_computation ensures_cond actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces ensures_value ->\n        let ensures_bool = PrimitiveBoxBool?.b (ObjectValuePrimitive?.value ensures_value) in\n        log_expressions_computation_maintains_roots_match actor logs_clauses s\n  )\n\n#pop-options\n\nlet executing_statement_maintains_roots_match\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (end_pc: option pc_t)\n  (statement: Armada.Statement.t)\n  (s: Armada.State.t)\n  : Lemma (requires roots_match s.mem)\n          (ensures  (match statement_computation actor nd start_pc end_pc statement s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> roots_match s'.mem)) =\n  match statement_computation actor nd start_pc end_pc statement s with\n  | ComputationImpossible | ComputationUndefined -> ()\n  | ComputationProduces s' ->\n      (match statement with\n       | AssumeExpressionStatement exp ->\n           assume_expression_statement_computation_maintains_roots_match actor nd start_pc exp s\n       | AssumePredicateStatement pred ->\n           assume_predicate_statement_computation_maintains_roots_match actor nd start_pc pred s\n       | AssertTrueStatement exp ->\n           assert_true_statement_computation_maintains_roots_match actor nd start_pc exp s\n       | AssertFalseStatement exp ->\n           assert_false_statement_computation_maintains_roots_match actor nd start_pc exp s\n       | ConditionalJumpStatement cond ->\n           conditional_jump_statement_computation_maintains_roots_match actor nd start_pc cond s\n       | UnconditionalJumpStatement ->\n           unconditional_jump_statement_computation_maintains_roots_match actor nd start_pc s\n       | UpdateStatement bypassing_write_buffer dst src ->\n           update_statement_computation_maintains_roots_match actor nd start_pc bypassing_write_buffer\n             dst src s\n       | NondeterministicUpdateStatement bypassing_write_buffer dst ->\n           nondeterministic_update_statement_computation_maintains_roots_match actor nd start_pc\n             bypassing_write_buffer dst s\n       | PropagateWriteMessageStatement ->\n           propagate_write_message_statement_computation_maintains_roots_match actor nd s\n       | CompareAndSwapStatement target old_val new_val bypassing_write_buffer optional_result ->\n           compare_and_swap_statement_computation_maintains_roots_match actor nd start_pc target\n             old_val new_val bypassing_write_buffer optional_result s\n       | AtomicExchangeStatement old_val target new_val ->\n           atomic_exchange_statement_computation_maintains_roots_match actor nd\n             start_pc old_val target new_val s\n       | CreateThreadStatement method_id initial_pc bypassing_write_buffer optional_result parameter_var_ids\n                               parameter_expressions local_variable_initializers ->\n           create_thread_statement_computation_maintains_roots_match actor nd start_pc method_id\n             initial_pc bypassing_write_buffer optional_result parameter_var_ids parameter_expressions\n             local_variable_initializers s\n       | MethodCallStatement method_id return_pc parameter_var_ids parameter_expressions local_variable_initializers\n                               stack_overflow ->\n           method_call_statement_computation_maintains_roots_match actor nd start_pc method_id return_pc\n             parameter_var_ids parameter_expressions local_variable_initializers stack_overflow s\n       | ReturnStatement method_id bypassing_write_buffer output_dsts output_srcs ->\n           return_statement_computation_maintains_roots_match actor nd start_pc end_pc method_id\n             bypassing_write_buffer output_dsts output_srcs s\n       | TerminateThreadStatement method_id ->\n           terminate_thread_statement_computation_maintains_roots_match actor nd start_pc method_id s\n       | TerminateProcessStatement method_id ->\n           terminate_process_statement_computation_maintains_roots_match actor nd start_pc method_id s\n       | JoinStatement join_tid ->\n           join_statement_computation_maintains_roots_match actor nd start_pc join_tid s\n       | MallocSuccessfulStatement bypassing_write_buffer result allocation_td count ->\n           alloc_successful_statement_computation_maintains_roots_match actor nd start_pc false\n             bypassing_write_buffer result allocation_td count s\n       | MallocReturningNullStatement bypassing_write_buffer result count ->\n           alloc_returning_null_statement_computation_maintains_roots_match actor nd start_pc\n             bypassing_write_buffer result count s\n       | CallocSuccessfulStatement bypassing_write_buffer result allocation_td count ->\n           alloc_successful_statement_computation_maintains_roots_match actor nd start_pc true\n             bypassing_write_buffer result allocation_td count s\n       | CallocReturningNullStatement bypassing_write_buffer result count ->\n           alloc_returning_null_statement_computation_maintains_roots_match actor nd start_pc\n             bypassing_write_buffer result count s\n       | DeallocStatement ptr ->\n           dealloc_statement_computation_maintains_roots_match actor nd start_pc ptr s\n       | SomehowStatement undefined_unless_cond bypassing_write_buffer modifies_clauses ensures_cond ->\n           somehow_statement_computation_maintains_roots_match actor nd start_pc undefined_unless_cond\n             bypassing_write_buffer modifies_clauses ensures_cond s\n       | FenceStatement ->\n           fence_statement_computation_maintains_roots_match actor nd start_pc s\n       | ExternalMethodStartStatement await_cond undefined_unless_cond bypassing_write_buffer\n                                      modifies_clauses reads_clauses ->\n           external_method_start_statement_computation_maintains_roots_match actor nd start_pc await_cond\n             undefined_unless_cond bypassing_write_buffer modifies_clauses reads_clauses s\n       | ExternalMethodMiddleStatement bypassing_write_buffer modifies_clauses reads_clauses ->\n           external_method_middle_statement_computation_maintains_roots_match actor nd start_pc\n             bypassing_write_buffer modifies_clauses reads_clauses s\n       | ExternalMethodEndStatement ensures_cond logs_clauses ->\n           external_method_end_statement_computation_maintains_roots_match actor nd start_pc ensures_cond\n             logs_clauses s\n      )     \n"
  },
  {
    "path": "experimental/lib/Strategies.ArmadaInvariant.UnstartedThreads.fst",
    "content": "module Strategies.ArmadaInvariant.UnstartedThreads\n\nopen Armada.Base\nopen Armada.Computation\nopen Armada.Expression\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Pointer\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Threads\nopen Armada.Type\nopen FStar.Sequence.Base\nopen Spec.Ubool\nopen Strategies.ArmadaStatement\n\nlet init_implies_unstarted_threads_have_empty_write_buffers (program: Armada.Program.t) (s: Armada.State.t)\n  : Lemma (requires init_program program s)\n          (ensures  unstarted_threads_have_empty_write_buffers s) =\n  ()\n\n#push-options \"--z3rlimit 10\"\n\nlet push_stack_variable_maintains_unstarted_threads_have_empty_write_buffers\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (initializer: initializer_t)\n  (s: Armada.State.t)\n  : Lemma (requires   ThreadStatusRunning? (s.threads actor).status\n                    /\\ unstarted_threads_have_empty_write_buffers s)\n          (ensures  (match push_stack_variable actor writer_pc writer_expression_number method_id\n                             frame_uniq initializer s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' ->\n                           (forall tid. ThreadStatusRunning? (s.threads tid).status ==>\n                                   ThreadStatusRunning? (s'.threads tid).status)\n                         /\\ unstarted_threads_have_empty_write_buffers s')) =\n  ()\n\n#pop-options\n\nlet rec push_stack_variables_maintains_unstarted_threads_have_empty_write_buffers\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (initializers: list initializer_t)\n  (s: Armada.State.t)\n  : Lemma (requires   ThreadStatusRunning? (s.threads actor).status\n                    /\\ unstarted_threads_have_empty_write_buffers s)\n          (ensures  (match push_stack_variables actor writer_pc writer_expression_number method_id\n                             frame_uniq initializers s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' ->\n                           (forall tid. ThreadStatusRunning? (s.threads tid).status ==>\n                                   ThreadStatusRunning? (s'.threads tid).status)\n                         /\\ unstarted_threads_have_empty_write_buffers s'))\n          (decreases initializers) =\n  match initializers with\n  | [] -> ()\n  | first_initializer :: remaining_initializers ->\n      push_stack_variable_maintains_unstarted_threads_have_empty_write_buffers actor writer_pc\n        writer_expression_number method_id frame_uniq first_initializer s;\n      (match push_stack_variable actor writer_pc writer_expression_number method_id frame_uniq first_initializer s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces s' ->\n           push_stack_variables_maintains_unstarted_threads_have_empty_write_buffers actor writer_pc\n             (writer_expression_number + 1) method_id frame_uniq remaining_initializers s')\n\nlet rec push_stack_parameters_maintains_unstarted_threads_have_empty_write_buffers\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (var_ids: list var_id_t)\n  (parameters: list object_value_t)\n  (s: Armada.State.t)\n  : Lemma (requires   ThreadStatusRunning? (s.threads actor).status\n                    /\\ unstarted_threads_have_empty_write_buffers s)\n          (ensures  (match push_stack_parameters actor writer_pc writer_expression_number method_id frame_uniq\n                             var_ids parameters s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' ->\n                           (forall tid. ThreadStatusRunning? (s.threads tid).status ==>\n                                   ThreadStatusRunning? (s'.threads tid).status)\n                         /\\ unstarted_threads_have_empty_write_buffers s'))\n          (decreases parameters) =\n  match parameters, var_ids with\n  | [], [] -> ()\n  | first_parameter :: remaining_parameters, first_var_id :: remaining_var_ids ->\n      let first_initializer =\n        { var_id = first_var_id; iv = InitializerSpecific first_parameter; weakly_consistent = false } in\n      push_stack_variable_maintains_unstarted_threads_have_empty_write_buffers actor writer_pc\n        writer_expression_number method_id frame_uniq first_initializer s;\n      (match push_stack_variable actor writer_pc writer_expression_number method_id frame_uniq first_initializer s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces s' ->\n           push_stack_parameters_maintains_unstarted_threads_have_empty_write_buffers actor writer_pc\n             (writer_expression_number + 1) method_id frame_uniq remaining_var_ids remaining_parameters s')\n  | _ -> ()\n\nlet update_pointed_to_value_maintains_unstarted_threads_have_empty_write_buffers\n  (p: Armada.Pointer.t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (new_value: object_value_t)\n  (s: Armada.State.t)\n  : Lemma (requires   ThreadStatusRunning? (s.threads actor).status\n                    /\\ unstarted_threads_have_empty_write_buffers s)\n          (ensures  (match update_pointed_to_value p actor writer_pc writer_expression_number bypassing_write_buffer\n                             new_value s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' ->\n                           ThreadStatusRunning? (s'.threads actor).status\n                         /\\ unstarted_threads_have_empty_write_buffers s')) =\n  let cs' = update_pointed_to_value p actor writer_pc writer_expression_number bypassing_write_buffer\n              new_value s in\n  ()\n\nlet update_expression_maintains_unstarted_threads_have_empty_write_buffers\n  (exp: expression_t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (new_value: object_value_t)\n  (s: Armada.State.t)\n  : Lemma (requires   ThreadStatusRunning? (s.threads actor).status\n                    /\\ unstarted_threads_have_empty_write_buffers s)\n          (ensures  (match update_expression exp actor writer_pc writer_expression_number bypassing_write_buffer\n                             new_value s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' ->\n                           ThreadStatusRunning? (s'.threads actor).status\n                         /\\ unstarted_threads_have_empty_write_buffers s')) =\n  let cs' = update_expression exp actor writer_pc writer_expression_number bypassing_write_buffer\n              new_value s in\n  if   not (expression_valid exp)\n     || not (object_value_valid new_value)\n     || neqb (object_value_to_td new_value) (expression_to_td exp) then\n    ()\n  else\n    ()\n\nlet rec update_expressions_maintains_unstarted_threads_have_empty_write_buffers\n  (exps: list expression_t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (new_values: list object_value_t)\n  (s: Armada.State.t)\n  : Lemma (requires   ThreadStatusRunning? (s.threads actor).status\n                    /\\ unstarted_threads_have_empty_write_buffers s)\n          (ensures  (match update_expressions exps actor writer_pc writer_expression_number bypassing_write_buffer\n                             new_values s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' ->\n                           ThreadStatusRunning? (s'.threads actor).status\n                         /\\ unstarted_threads_have_empty_write_buffers s'))\n          (decreases exps) =\n  match exps, new_values with\n  | [], [] -> ()\n  | first_exp :: remaining_exps, first_new_value :: remaining_new_values ->\n      update_expression_maintains_unstarted_threads_have_empty_write_buffers first_exp actor writer_pc\n        writer_expression_number bypassing_write_buffer first_new_value s;\n      (match update_expression first_exp actor writer_pc writer_expression_number\n               bypassing_write_buffer first_new_value s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces s' ->\n           update_expressions_maintains_unstarted_threads_have_empty_write_buffers remaining_exps actor writer_pc\n             (writer_expression_number + 1) bypassing_write_buffer remaining_new_values s')\n  | _ -> ()\n\nlet rec external_method_take_snapshot_maintains_unstarted_threads_have_empty_write_buffers\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (reads_clauses: list (var_id_t * expression_t))\n  (s: Armada.State.t)\n  : Lemma (requires   ThreadStatusRunning? (s.threads actor).status\n                    /\\ unstarted_threads_have_empty_write_buffers s)\n          (ensures  (match external_method_take_snapshot_of_reads_clauses_computation actor writer_pc\n                             writer_expression_number bypassing_write_buffer reads_clauses s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> unstarted_threads_have_empty_write_buffers s'))\n          (decreases reads_clauses) =\n  match reads_clauses with\n  | [] -> ()\n  | (first_var_id, first_reads_expression) :: remaining_reads_clauses ->\n      (match rvalue_computation first_reads_expression actor s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces first_value ->\n           let td = expression_to_td first_reads_expression in\n           let local_var = ExpressionLocalVariable td first_var_id in\n           update_expression_maintains_unstarted_threads_have_empty_write_buffers local_var actor writer_pc\n             writer_expression_number bypassing_write_buffer first_value s;\n           (match update_expression local_var actor writer_pc writer_expression_number bypassing_write_buffer\n                    first_value s with\n            | ComputationImpossible | ComputationUndefined -> ()\n            | ComputationProduces s' ->\n                external_method_take_snapshot_maintains_unstarted_threads_have_empty_write_buffers\n                  actor writer_pc (writer_expression_number + 1) bypassing_write_buffer remaining_reads_clauses s'))\n  | _ -> ()\n\nlet rec log_expressions_computation_maintains_unstarted_threads_have_empty_write_buffers\n  (actor: tid_t)\n  (logs_clauses: list expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires   ThreadStatusRunning? (s.threads actor).status\n                    /\\ unstarted_threads_have_empty_write_buffers s)\n          (ensures  (match log_expressions_computation actor logs_clauses s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> unstarted_threads_have_empty_write_buffers s'))\n          (decreases logs_clauses) =\n  match logs_clauses with\n  | [] -> ()\n  | first_logs_clause :: remaining_logs_clauses ->\n      (match rvalue_computation first_logs_clause actor s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces event ->\n           let trace' = s.trace $:: event in\n           let s' = { s with trace = trace' } in\n           log_expressions_computation_maintains_unstarted_threads_have_empty_write_buffers actor\n             remaining_logs_clauses s')\n\n#push-options \"--z3rlimit 10\"\n\nlet assume_expression_statement_computation_maintains_unstarted_threads_have_empty_write_buffers\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (exp: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires   ThreadStatusRunning? (s.threads actor).status\n                    /\\ unstarted_threads_have_empty_write_buffers s)\n          (ensures  (match assume_expression_statement_computation actor nd start_pc exp s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> unstarted_threads_have_empty_write_buffers s')) =\n  ()\n\nlet assume_predicate_statement_computation_maintains_unstarted_threads_have_empty_write_buffers\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (pred: Armada.State.t -> GTot bool)\n  (s: Armada.State.t)\n  : Lemma (requires   ThreadStatusRunning? (s.threads actor).status\n                    /\\ unstarted_threads_have_empty_write_buffers s)\n          (ensures  (match assume_predicate_statement_computation actor nd start_pc pred s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> unstarted_threads_have_empty_write_buffers s')) =\n  ()\n\nlet assert_true_statement_computation_maintains_unstarted_threads_have_empty_write_buffers\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (exp: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires   ThreadStatusRunning? (s.threads actor).status\n                    /\\ unstarted_threads_have_empty_write_buffers s)\n          (ensures  (match assert_true_statement_computation actor nd start_pc exp s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> unstarted_threads_have_empty_write_buffers s')) =\n  ()\n\nlet assert_false_statement_computation_maintains_unstarted_threads_have_empty_write_buffers\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (exp: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires   ThreadStatusRunning? (s.threads actor).status\n                    /\\ unstarted_threads_have_empty_write_buffers s)\n          (ensures  (match assert_false_statement_computation actor nd start_pc exp s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> unstarted_threads_have_empty_write_buffers s')) =\n  ()\n\nlet conditional_jump_statement_computation_maintains_unstarted_threads_have_empty_write_buffers\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (exp: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires   ThreadStatusRunning? (s.threads actor).status\n                    /\\ unstarted_threads_have_empty_write_buffers s)\n          (ensures  (match conditional_jump_statement_computation actor nd start_pc exp s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> unstarted_threads_have_empty_write_buffers s')) =\n  ()\n\nlet unconditional_jump_statement_computation_maintains_unstarted_threads_have_empty_write_buffers\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (s: Armada.State.t)\n  : Lemma (requires   ThreadStatusRunning? (s.threads actor).status\n                    /\\ unstarted_threads_have_empty_write_buffers s)\n          (ensures  (match unconditional_jump_statement_computation actor nd start_pc s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> unstarted_threads_have_empty_write_buffers s')) =\n  ()\n\nlet update_statement_computation_maintains_unstarted_threads_have_empty_write_buffers\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (bypassing_write_buffer: bool)\n  (dst: expression_t)\n  (src: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires   ThreadStatusRunning? (s.threads actor).status\n                    /\\ unstarted_threads_have_empty_write_buffers s)\n          (ensures  (match update_statement_computation actor nd start_pc bypassing_write_buffer dst src s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> unstarted_threads_have_empty_write_buffers s')) =\n  let cs' = update_statement_computation actor nd start_pc bypassing_write_buffer dst src s in\n  if   Cons? nd\n     || neqb (expression_to_td dst) (expression_to_td src) then\n    ()\n  else (\n    match rvalue_computation src actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces src_value ->\n        update_expression_maintains_unstarted_threads_have_empty_write_buffers dst actor start_pc 0\n          bypassing_write_buffer src_value s\n  )\n\nlet nondeterministic_update_statement_computation_maintains_unstarted_threads_have_empty_write_buffers\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (bypassing_write_buffer: bool)\n  (dst: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires   ThreadStatusRunning? (s.threads actor).status\n                    /\\ unstarted_threads_have_empty_write_buffers s)\n          (ensures  (match nondeterministic_update_statement_computation actor nd start_pc bypassing_write_buffer\n                             dst s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> unstarted_threads_have_empty_write_buffers s')) =\n  let cs' = nondeterministic_update_statement_computation actor nd start_pc bypassing_write_buffer dst s in\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (expression_to_td dst) then\n    ()\n  else (\n    let nd_value = Cons?.hd nd in\n    if not (object_value_has_all_pointers_uninitialized nd_value) then\n      ()\n    else\n      update_expression_maintains_unstarted_threads_have_empty_write_buffers dst actor start_pc 0\n        bypassing_write_buffer nd_value s\n  )\n\nlet propagate_write_message_statement_computation_maintains_unstarted_threads_have_empty_write_buffers\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (s: Armada.State.t)\n  : Lemma (requires   ThreadStatusRunning? (s.threads actor).status\n                    /\\ unstarted_threads_have_empty_write_buffers s)\n          (ensures  (match propagate_write_message_statement_computation actor nd s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> unstarted_threads_have_empty_write_buffers s')) =\n  ()\n\nlet compare_and_swap_statement_computation_maintains_unstarted_threads_have_empty_write_buffers\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (target: expression_t)\n  (old_val: expression_t)\n  (new_val: expression_t)\n  (bypassing_write_buffer: bool)\n  (optional_result: option expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires   ThreadStatusRunning? (s.threads actor).status\n                    /\\ unstarted_threads_have_empty_write_buffers s)\n          (ensures  (match compare_and_swap_statement_computation actor nd start_pc target old_val new_val\n                             bypassing_write_buffer optional_result s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> unstarted_threads_have_empty_write_buffers s')) =\n  let cs' = compare_and_swap_statement_computation actor nd start_pc target old_val new_val\n              bypassing_write_buffer optional_result s in\n  if   Cons? nd\n     || neqb (expression_to_td target) (expression_to_td old_val)\n     || neqb (expression_to_td target) (expression_to_td new_val)\n     || (match optional_result with\n        | Some result -> neqb (expression_to_td result) (ObjectTDPrimitive PrimitiveTDBool)\n        | None -> false) then\n    ()\n  else begin\n    match check_expression_up_to_date_for_rmw target actor s, rvalue_computation old_val actor s,\n          rvalue_computation target actor s, rvalue_computation new_val actor s,\n          lvalue_computation target actor s  with\n    | ComputationProduces _, ComputationProduces old_value,\n      ComputationProduces target_value, ComputationProduces new_value,\n      ComputationProduces target_ptr -> begin\n        let swap = eqb target_value old_value in\n        update_pointed_to_value_maintains_unstarted_threads_have_empty_write_buffers target_ptr actor start_pc 0 false new_value s;\n        match optional_result with\n        | None -> ()\n        | Some result ->\n          match lvalue_computation result actor s, (if swap then update_pointed_to_value target_ptr actor start_pc 0 false new_value s else return s) with\n          | ComputationProduces result_ptr, ComputationProduces s' ->\n              let swap_value = ObjectValuePrimitive (PrimitiveBoxBool swap) in\n              update_pointed_to_value_maintains_unstarted_threads_have_empty_write_buffers result_ptr actor start_pc 1 bypassing_write_buffer swap_value s'\n          | _ -> ()\n      end\n    | _ -> ()\n  end\n\nlet atomic_exchange_statement_computation_maintains_unstarted_threads_have_empty_write_buffers\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (old_val: expression_t)\n  (target: expression_t)\n  (new_val: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires   ThreadStatusRunning? (s.threads actor).status\n                    /\\ unstarted_threads_have_empty_write_buffers s)\n          (ensures  (match atomic_exchange_statement_computation actor nd start_pc old_val target new_val s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> unstarted_threads_have_empty_write_buffers s')) =\n  let cs' = atomic_exchange_statement_computation actor nd start_pc old_val target new_val s in\n  match check_expression_up_to_date_for_rmw target actor s with\n  | ComputationImpossible | ComputationUndefined -> ()\n  | ComputationProduces _ ->\n      (match rvalue_computation target actor s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces target_value ->\n           (match rvalue_computation new_val actor s with\n            | ComputationImpossible | ComputationUndefined -> ()\n            | ComputationProduces new_value ->\n                update_expression_maintains_unstarted_threads_have_empty_write_buffers old_val actor\n                  start_pc 0 false target_value s;\n                (match update_expression old_val actor start_pc 0 false target_value s with\n                 | ComputationImpossible | ComputationUndefined -> ()\n                 | ComputationProduces s' ->\n                     update_expression_maintains_unstarted_threads_have_empty_write_buffers target actor\n                       start_pc 1 false new_value s')))\n\nlet make_thread_running_maintains_unstarted_threads_have_empty_write_buffers\n  (method_id: method_id_t)\n  (initial_pc: pc_t)\n  (new_tid: tid_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (s: Armada.State.t)\n  : Lemma (requires unstarted_threads_have_empty_write_buffers s)\n          (ensures  unstarted_threads_have_empty_write_buffers (make_thread_running method_id initial_pc new_tid\n                      frame_uniq s)) =\n  ()\n\nlet create_thread_statement_computation_maintains_unstarted_threads_have_empty_write_buffers\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (method_id: method_id_t)\n  (initial_pc: pc_t)\n  (bypassing_write_buffer: bool)\n  (optional_result: option expression_t)\n  (parameter_var_ids: list var_id_t)\n  (parameter_expressions: list expression_t)\n  (local_variable_initializers: list initializer_t)\n  (s: Armada.State.t)\n  : Lemma (requires   ThreadStatusRunning? (s.threads actor).status\n                    /\\ unstarted_threads_have_empty_write_buffers s)\n          (ensures  (match create_thread_statement_computation actor nd start_pc method_id initial_pc\n                             bypassing_write_buffer optional_result parameter_var_ids parameter_expressions\n                             local_variable_initializers s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> unstarted_threads_have_empty_write_buffers s')) =\n  let cs' = create_thread_statement_computation actor nd start_pc method_id initial_pc\n              bypassing_write_buffer optional_result parameter_var_ids parameter_expressions\n              local_variable_initializers s in\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract create_thread_nd_t)\n     || (   Some? optional_result\n        && neqb (expression_to_td (Some?.v optional_result)) (ObjectTDPrimitive PrimitiveTDThreadId))\n     || list_len parameter_var_ids <> list_len parameter_expressions then\n    ()\n  else (\n    let create_thread_nd: create_thread_nd_t = ObjectValueAbstract?.value (Cons?.hd nd) in\n    let new_tid = create_thread_nd.new_tid in\n    if new_tid = 0 then\n      (match optional_result with\n       | None -> ()\n       | Some result ->\n          let new_tid_value = ObjectValuePrimitive (PrimitiveBoxThreadId new_tid) in\n          update_expression_maintains_unstarted_threads_have_empty_write_buffers result actor start_pc\n            (list_len parameter_var_ids + list_len local_variable_initializers) bypassing_write_buffer\n            new_tid_value s)\n    else (\n      let frame_uniq = create_thread_nd.frame_uniq in\n      match rvalues_computation parameter_expressions actor s with\n      | ComputationImpossible | ComputationUndefined -> ()\n      | ComputationProduces parameter_values ->\n          let s2 = make_thread_running method_id initial_pc new_tid frame_uniq s in\n          make_thread_running_maintains_unstarted_threads_have_empty_write_buffers method_id initial_pc new_tid\n            frame_uniq s;\n          push_stack_parameters_maintains_unstarted_threads_have_empty_write_buffers new_tid start_pc 0 method_id\n            frame_uniq parameter_var_ids parameter_values s2;\n          (match push_stack_parameters new_tid start_pc 0 method_id frame_uniq parameter_var_ids\n                   parameter_values s2 with\n           | ComputationImpossible | ComputationUndefined -> ()\n           | ComputationProduces s3 ->\n                push_stack_variables_maintains_unstarted_threads_have_empty_write_buffers new_tid start_pc\n                  (list_len parameter_var_ids) method_id frame_uniq local_variable_initializers s3;\n                (match push_stack_variables new_tid start_pc (list_len parameter_var_ids) method_id frame_uniq\n                         local_variable_initializers s3 with\n                 | ComputationImpossible | ComputationUndefined -> ()\n                 | ComputationProduces s4 ->\n                     (match optional_result with\n                      | None -> ()\n                      | Some result ->\n                         let new_tid_value = ObjectValuePrimitive (PrimitiveBoxThreadId new_tid) in\n                         update_expression_maintains_unstarted_threads_have_empty_write_buffers result actor start_pc\n                           (list_len parameter_var_ids + list_len local_variable_initializers) bypassing_write_buffer\n                           new_tid_value s4)))\n    )\n  )\n\nlet method_call_statement_computation_maintains_unstarted_threads_have_empty_write_buffers\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (method_id: method_id_t)\n  (return_pc: pc_t)\n  (parameter_var_ids: list var_id_t)\n  (parameter_expressions: list expression_t)\n  (local_variable_initializers: list initializer_t)\n  (stack_overflow: bool)\n  (s: Armada.State.t)\n  : Lemma (requires   ThreadStatusRunning? (s.threads actor).status\n                    /\\ unstarted_threads_have_empty_write_buffers s)\n          (ensures  (match method_call_statement_computation actor nd start_pc method_id return_pc parameter_var_ids\n                             parameter_expressions local_variable_initializers stack_overflow s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> unstarted_threads_have_empty_write_buffers s')) =\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract method_call_nd_t) then\n    ()\n  else (\n    let method_call_nd: method_call_nd_t = ObjectValueAbstract?.value (Cons?.hd nd) in\n    let frame_uniq = method_call_nd.frame_uniq in\n    match rvalues_computation parameter_expressions actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces parameter_values ->\n        let s2 = push_stack_frame actor method_id return_pc frame_uniq s in\n        push_stack_parameters_maintains_unstarted_threads_have_empty_write_buffers actor start_pc 0\n          method_id frame_uniq parameter_var_ids parameter_values s2;\n        (match push_stack_parameters actor start_pc 0 method_id frame_uniq parameter_var_ids parameter_values s2 with\n         | ComputationImpossible | ComputationUndefined -> ()\n         | ComputationProduces s3 ->\n             push_stack_variables_maintains_unstarted_threads_have_empty_write_buffers actor start_pc\n               (list_len parameter_var_ids) method_id frame_uniq\n               local_variable_initializers s3)\n  )\n\nlet return_statement_computation_maintains_unstarted_threads_have_empty_write_buffers\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (end_pc: option pc_t)\n  (method_id: method_id_t)\n  (bypassing_write_buffer: bool)\n  (output_dsts: list expression_t)\n  (output_srcs: list expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires   ThreadStatusRunning? (s.threads actor).status\n                    /\\ unstarted_threads_have_empty_write_buffers s)\n          (ensures  (match return_statement_computation actor nd start_pc end_pc method_id bypassing_write_buffer\n                             output_dsts output_srcs s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> unstarted_threads_have_empty_write_buffers s')) =\n  let thread = s.threads actor in\n  if   Cons? nd\n     || eqb thread.stack []\n     || thread.top.method_id <> method_id\n     || end_pc <> Some (Cons?.hd thread.stack).return_pc then\n    ()\n  else (\n    match rvalues_computation output_srcs actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces output_values ->\n        (match pop_stack_variables actor method_id thread.top.frame_uniq thread.top.local_variables s.mem with\n         | ComputationImpossible | ComputationUndefined -> ()\n         | ComputationProduces mem' ->\n             let s2 = pop_stack_frame actor mem' s in\n             update_expressions_maintains_unstarted_threads_have_empty_write_buffers output_dsts actor\n               start_pc 0 bypassing_write_buffer output_values s2)\n  )\n\nlet terminate_thread_statement_computation_maintains_unstarted_threads_have_empty_write_buffers\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (method_id: method_id_t)\n  (s: Armada.State.t)\n  : Lemma (requires   ThreadStatusRunning? (s.threads actor).status\n                    /\\ unstarted_threads_have_empty_write_buffers s)\n          (ensures  (match terminate_thread_statement_computation actor nd start_pc method_id s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> unstarted_threads_have_empty_write_buffers s')) =\n  ()\n\nlet terminate_process_statement_computation_maintains_unstarted_threads_have_empty_write_buffers\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (method_id: method_id_t)\n  (s: Armada.State.t)\n  : Lemma (requires   ThreadStatusRunning? (s.threads actor).status\n                    /\\ unstarted_threads_have_empty_write_buffers s)\n          (ensures  (match terminate_process_statement_computation actor nd start_pc method_id s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> unstarted_threads_have_empty_write_buffers s')) =\n  ()\n\nlet join_statement_computation_maintains_unstarted_threads_have_empty_write_buffers\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (join_tid: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires   ThreadStatusRunning? (s.threads actor).status\n                    /\\ unstarted_threads_have_empty_write_buffers s)\n          (ensures  (match join_statement_computation actor nd start_pc join_tid s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> unstarted_threads_have_empty_write_buffers s')) =\n  ()\n\nlet alloc_successful_statement_computation_maintains_unstarted_threads_have_empty_write_buffers\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (zero_initialized: bool)\n  (bypassing_write_buffer: bool)\n  (result: expression_t)\n  (allocation_td: object_td_t)\n  (count: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires   ThreadStatusRunning? (s.threads actor).status\n                    /\\ unstarted_threads_have_empty_write_buffers s)\n          (ensures  (match alloc_successful_statement_computation actor nd start_pc zero_initialized\n                             bypassing_write_buffer result allocation_td count s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> unstarted_threads_have_empty_write_buffers s')) =\n  let cs' = alloc_successful_statement_computation actor nd start_pc zero_initialized bypassing_write_buffer result\n              allocation_td count s in\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract root_id_uniquifier_t)\n     || neqb (expression_to_td count) (ObjectTDAbstract nat)\n     || neqb (expression_to_td result) (ObjectTDPrimitive PrimitiveTDPointer) then\n    ()\n  else (\n    match rvalue_computation count actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces count_value ->\n        let sz = ObjectValueAbstract?.value count_value in\n        let array_td = ObjectTDArray allocation_td sz in\n        let uniq = ObjectValueAbstract?.value (Cons?.hd nd) in\n        let root_id = RootIdAllocation uniq in\n        (match s.mem root_id with\n         | RootAllocated allocated freed storage ->\n             if   allocated\n                || freed\n                || neqb (object_storage_to_td storage) array_td\n                || not (is_storage_ready_for_allocation storage)\n                || (not zero_initialized && not (object_storage_arbitrarily_initialized_correctly storage))\n                || (zero_initialized && not (is_storage_zero_filled storage)) then\n               ()\n             else (\n               let s' = mark_allocation_root_allocated uniq storage s in\n               let p = ObjectValuePrimitive (PrimitiveBoxPointer (PointerIndex (PointerRoot root_id) 0)) in\n               update_expression_maintains_unstarted_threads_have_empty_write_buffers result actor start_pc 0\n                 bypassing_write_buffer p s'\n             )\n         | _ -> ())\n  )\n\nlet alloc_returning_null_statement_computation_maintains_unstarted_threads_have_empty_write_buffers\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (bypassing_write_buffer: bool)\n  (result: expression_t)\n  (count: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires   ThreadStatusRunning? (s.threads actor).status\n                    /\\ unstarted_threads_have_empty_write_buffers s)\n          (ensures  (match alloc_returning_null_statement_computation actor nd start_pc bypassing_write_buffer\n                             result count s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> unstarted_threads_have_empty_write_buffers s')) =\n  let cs' = alloc_returning_null_statement_computation actor nd start_pc bypassing_write_buffer\n              result count s in\n  if   Cons? nd\n     || neqb (expression_to_td count) (ObjectTDAbstract nat)\n     || neqb (expression_to_td result) (ObjectTDPrimitive PrimitiveTDPointer) then\n    ()\n  else (\n    match rvalue_computation count actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces _ ->\n        let p = ObjectValuePrimitive (PrimitiveBoxPointer PointerNull) in\n        update_expression_maintains_unstarted_threads_have_empty_write_buffers result actor start_pc 0\n          bypassing_write_buffer p s\n  )\n\nlet dealloc_statement_computation_maintains_unstarted_threads_have_empty_write_buffers\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (ptr: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires   ThreadStatusRunning? (s.threads actor).status\n                    /\\ unstarted_threads_have_empty_write_buffers s)\n          (ensures  (match dealloc_statement_computation actor nd start_pc ptr s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> unstarted_threads_have_empty_write_buffers s')) =\n  ()\n\nlet somehow_statement_computation_maintains_unstarted_threads_have_empty_write_buffers\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (undefined_unless_cond: expression_t)\n  (bypassing_write_buffer: bool)\n  (modifies_clauses: list expression_t)\n  (ensures_cond: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires   ThreadStatusRunning? (s.threads actor).status\n                    /\\ unstarted_threads_have_empty_write_buffers s)\n          (ensures  (match somehow_statement_computation actor nd start_pc undefined_unless_cond\n                             bypassing_write_buffer modifies_clauses ensures_cond s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> unstarted_threads_have_empty_write_buffers s')) =\n  let cs' = somehow_statement_computation actor nd start_pc undefined_unless_cond bypassing_write_buffer\n              modifies_clauses ensures_cond s in\n  if   neqb (expression_to_td undefined_unless_cond) (ObjectTDPrimitive PrimitiveTDBool)\n     || neqb (expression_to_td ensures_cond) (ObjectTDPrimitive PrimitiveTDBool) then\n    ()\n  else (\n    match rvalue_computation undefined_unless_cond actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces undefined_unless_value ->\n        let undefined_unless_bool = PrimitiveBoxBool?.b (ObjectValuePrimitive?.value undefined_unless_value) in\n        if not undefined_unless_bool then\n          ()\n        else\n          update_expressions_maintains_unstarted_threads_have_empty_write_buffers modifies_clauses actor start_pc 0\n            bypassing_write_buffer nd s\n  )\n\nlet fence_statement_computation_maintains_unstarted_threads_have_empty_write_buffers\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (s: Armada.State.t)\n  : Lemma (requires   ThreadStatusRunning? (s.threads actor).status\n                    /\\ unstarted_threads_have_empty_write_buffers s)\n          (ensures  (match fence_statement_computation actor nd start_pc s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> unstarted_threads_have_empty_write_buffers s')) =\n  ()\n\nlet external_method_start_statement_computation_maintains_unstarted_threads_have_empty_write_buffers\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (await_cond: expression_t)\n  (undefined_unless_cond: expression_t)\n  (bypassing_write_buffer: bool)\n  (modifies_clauses: list expression_t)\n  (reads_clauses: list (var_id_t * expression_t))\n  (s: Armada.State.t)\n  : Lemma (requires   ThreadStatusRunning? (s.threads actor).status\n                    /\\ unstarted_threads_have_empty_write_buffers s)\n          (ensures  (match external_method_start_statement_computation actor nd start_pc await_cond\n                             undefined_unless_cond bypassing_write_buffer modifies_clauses reads_clauses s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> unstarted_threads_have_empty_write_buffers s')) =\n  let cs' = external_method_start_statement_computation actor nd start_pc await_cond undefined_unless_cond\n              bypassing_write_buffer modifies_clauses reads_clauses s in\n  if   neqb (expression_to_td await_cond) (ObjectTDPrimitive PrimitiveTDBool)\n     || neqb (expression_to_td undefined_unless_cond) (ObjectTDPrimitive PrimitiveTDBool)\n     || list_len modifies_clauses <> list_len nd then\n    ()\n  else (\n    match rvalue_computation await_cond actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces await_value ->\n        let await_bool = PrimitiveBoxBool?.b (ObjectValuePrimitive?.value await_value) in\n        if not await_bool then\n          ()\n        else (\n          match rvalue_computation undefined_unless_cond actor s with\n          | ComputationImpossible | ComputationUndefined -> ()\n          | ComputationProduces undefined_unless_value ->\n              let undefined_unless_bool = PrimitiveBoxBool?.b (ObjectValuePrimitive?.value await_value) in\n              if not undefined_unless_bool then\n                ()\n              else (\n                update_expressions_maintains_unstarted_threads_have_empty_write_buffers modifies_clauses\n                  actor start_pc 0 bypassing_write_buffer nd s;\n                match update_expressions modifies_clauses actor start_pc 0 bypassing_write_buffer nd s with\n                | ComputationImpossible | ComputationUndefined -> ()\n                | ComputationProduces s' ->\n                    external_method_take_snapshot_maintains_unstarted_threads_have_empty_write_buffers\n                      actor start_pc (list_len modifies_clauses) bypassing_write_buffer reads_clauses s'\n              )\n        )\n  )\n\nlet external_method_middle_statement_computation_maintains_unstarted_threads_have_empty_write_buffers\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (bypassing_write_buffer: bool)\n  (modifies_clauses: list expression_t)\n  (reads_clauses: list (var_id_t * expression_t))\n  (s: Armada.State.t)\n  : Lemma (requires   ThreadStatusRunning? (s.threads actor).status\n                    /\\ unstarted_threads_have_empty_write_buffers s)\n          (ensures  (match external_method_middle_statement_computation actor nd start_pc bypassing_write_buffer\n                             modifies_clauses reads_clauses s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> unstarted_threads_have_empty_write_buffers s')) =\n  let cs' = external_method_middle_statement_computation actor nd start_pc bypassing_write_buffer\n              modifies_clauses reads_clauses s in\n  match external_method_check_snapshot_computation actor reads_clauses s with\n  | ComputationImpossible | ComputationUndefined -> ()\n  | ComputationProduces _ ->\n      update_expressions_maintains_unstarted_threads_have_empty_write_buffers modifies_clauses actor start_pc 0\n        bypassing_write_buffer nd s;\n      (match update_expressions modifies_clauses actor start_pc 0 bypassing_write_buffer nd s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces s' ->\n           external_method_take_snapshot_maintains_unstarted_threads_have_empty_write_buffers\n             actor start_pc (list_len modifies_clauses) bypassing_write_buffer reads_clauses s')\n\nlet external_method_end_statement_computation_maintains_unstarted_threads_have_empty_write_buffers\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (ensures_cond: expression_t)\n  (logs_clauses: list expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires   ThreadStatusRunning? (s.threads actor).status\n                    /\\ unstarted_threads_have_empty_write_buffers s)\n          (ensures  (match external_method_end_statement_computation actor nd start_pc ensures_cond logs_clauses s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> unstarted_threads_have_empty_write_buffers s')) =\n  let cs' = external_method_end_statement_computation actor nd start_pc ensures_cond logs_clauses s in\n  if   Cons? nd\n     || neqb (expression_to_td ensures_cond) (ObjectTDPrimitive PrimitiveTDBool) then\n    ()\n  else (\n    match rvalue_computation ensures_cond actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces ensures_value ->\n        let ensures_bool = PrimitiveBoxBool?.b (ObjectValuePrimitive?.value ensures_value) in\n        log_expressions_computation_maintains_unstarted_threads_have_empty_write_buffers actor logs_clauses s\n  )\n\n#pop-options\n\nlet executing_statement_maintains_unstarted_threads_have_empty_write_buffers\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (end_pc: option pc_t)\n  (statement: Armada.Statement.t)\n  (s: Armada.State.t)\n  : Lemma (requires   ThreadStatusRunning? (s.threads actor).status\n                    /\\ unstarted_threads_have_empty_write_buffers s)\n          (ensures  (match statement_computation actor nd start_pc end_pc statement s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> unstarted_threads_have_empty_write_buffers s')) =\n  match statement_computation actor nd start_pc end_pc statement s with\n  | ComputationImpossible | ComputationUndefined -> ()\n  | ComputationProduces s' ->\n      (match statement with\n       | AssumeExpressionStatement exp ->\n           assume_expression_statement_computation_maintains_unstarted_threads_have_empty_write_buffers actor nd\n             start_pc exp s\n       | AssumePredicateStatement pred ->\n           assume_predicate_statement_computation_maintains_unstarted_threads_have_empty_write_buffers actor nd\n             start_pc pred s\n       | AssertTrueStatement exp ->\n           assert_true_statement_computation_maintains_unstarted_threads_have_empty_write_buffers actor nd\n             start_pc exp s\n       | AssertFalseStatement exp ->\n           assert_false_statement_computation_maintains_unstarted_threads_have_empty_write_buffers actor nd\n             start_pc exp s\n       | ConditionalJumpStatement cond ->\n           conditional_jump_statement_computation_maintains_unstarted_threads_have_empty_write_buffers actor nd\n             start_pc cond s\n       | UnconditionalJumpStatement ->\n           unconditional_jump_statement_computation_maintains_unstarted_threads_have_empty_write_buffers actor nd\n             start_pc s\n       | UpdateStatement bypassing_write_buffer dst src ->\n           update_statement_computation_maintains_unstarted_threads_have_empty_write_buffers actor nd\n             start_pc bypassing_write_buffer dst src s\n       | NondeterministicUpdateStatement bypassing_write_buffer dst ->\n           nondeterministic_update_statement_computation_maintains_unstarted_threads_have_empty_write_buffers actor nd\n             start_pc bypassing_write_buffer dst s\n       | PropagateWriteMessageStatement ->\n           propagate_write_message_statement_computation_maintains_unstarted_threads_have_empty_write_buffers\n             actor nd s\n       | CompareAndSwapStatement target old_val new_val bypassing_write_buffer optional_result ->\n           compare_and_swap_statement_computation_maintains_unstarted_threads_have_empty_write_buffers\n             actor nd start_pc target old_val new_val bypassing_write_buffer optional_result s\n       | AtomicExchangeStatement old_val target new_val ->\n           atomic_exchange_statement_computation_maintains_unstarted_threads_have_empty_write_buffers actor nd\n             start_pc old_val target new_val s\n       | CreateThreadStatement method_id initial_pc bypassing_write_buffer optional_result parameter_var_ids\n                               parameter_expressions local_variable_initializers ->\n           create_thread_statement_computation_maintains_unstarted_threads_have_empty_write_buffers actor nd\n             start_pc method_id initial_pc bypassing_write_buffer optional_result parameter_var_ids\n             parameter_expressions local_variable_initializers s\n       | MethodCallStatement method_id return_pc parameter_var_ids parameter_expressions local_variable_initializers\n                               stack_overflow ->\n           method_call_statement_computation_maintains_unstarted_threads_have_empty_write_buffers actor nd\n             start_pc method_id return_pc parameter_var_ids parameter_expressions local_variable_initializers\n             stack_overflow s\n       | ReturnStatement method_id bypassing_write_buffer output_dsts output_srcs ->\n           return_statement_computation_maintains_unstarted_threads_have_empty_write_buffers actor nd\n             start_pc end_pc method_id bypassing_write_buffer output_dsts output_srcs s\n       | TerminateThreadStatement method_id ->\n           terminate_thread_statement_computation_maintains_unstarted_threads_have_empty_write_buffers actor nd\n             start_pc method_id s\n       | TerminateProcessStatement method_id ->\n           terminate_process_statement_computation_maintains_unstarted_threads_have_empty_write_buffers actor nd\n             start_pc method_id s\n       | JoinStatement join_tid ->\n           join_statement_computation_maintains_unstarted_threads_have_empty_write_buffers actor nd\n             start_pc join_tid s\n       | MallocSuccessfulStatement bypassing_write_buffer result allocation_td count ->\n           alloc_successful_statement_computation_maintains_unstarted_threads_have_empty_write_buffers actor nd\n             start_pc false bypassing_write_buffer result allocation_td count s\n       | MallocReturningNullStatement bypassing_write_buffer result count ->\n           alloc_returning_null_statement_computation_maintains_unstarted_threads_have_empty_write_buffers actor nd\n             start_pc bypassing_write_buffer result count s\n       | CallocSuccessfulStatement bypassing_write_buffer result allocation_td count ->\n           alloc_successful_statement_computation_maintains_unstarted_threads_have_empty_write_buffers actor nd\n             start_pc true bypassing_write_buffer result allocation_td count s\n       | CallocReturningNullStatement bypassing_write_buffer result count ->\n           alloc_returning_null_statement_computation_maintains_unstarted_threads_have_empty_write_buffers actor nd\n             start_pc bypassing_write_buffer result count s\n       | DeallocStatement ptr ->\n           dealloc_statement_computation_maintains_unstarted_threads_have_empty_write_buffers actor nd start_pc ptr s\n       | SomehowStatement undefined_unless_cond bypassing_write_buffer modifies_clauses ensures_cond ->\n           somehow_statement_computation_maintains_unstarted_threads_have_empty_write_buffers actor nd\n             start_pc undefined_unless_cond bypassing_write_buffer modifies_clauses ensures_cond s\n       | FenceStatement ->\n           fence_statement_computation_maintains_unstarted_threads_have_empty_write_buffers actor nd start_pc s\n       | ExternalMethodStartStatement await_cond undefined_unless_cond bypassing_write_buffer\n                                      modifies_clauses reads_clauses ->\n           external_method_start_statement_computation_maintains_unstarted_threads_have_empty_write_buffers actor nd\n             start_pc await_cond undefined_unless_cond bypassing_write_buffer modifies_clauses reads_clauses s\n       | ExternalMethodMiddleStatement bypassing_write_buffer modifies_clauses reads_clauses ->\n           external_method_middle_statement_computation_maintains_unstarted_threads_have_empty_write_buffers actor nd\n             start_pc bypassing_write_buffer modifies_clauses reads_clauses s\n       | ExternalMethodEndStatement ensures_cond logs_clauses ->\n           external_method_end_statement_computation_maintains_unstarted_threads_have_empty_write_buffers actor nd\n             start_pc ensures_cond logs_clauses s\n      )     \n"
  },
  {
    "path": "experimental/lib/Strategies.ArmadaInvariant.UnstartedThreads.fsti",
    "content": "module Strategies.ArmadaInvariant.UnstartedThreads\n\nopen Armada.Base\nopen Armada.Computation\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Threads\nopen Armada.Type\nopen FStar.Sequence.Base\nopen Spec.List\nopen Spec.Ubool\n\nlet unstarted_threads_have_empty_write_buffers (s: Armada.State.t) : GTot ubool =\n  forall tid. let thread = s.threads tid in\n         ThreadStatusNotStarted? thread.status ==> length thread.write_buffer = 0\n\nval init_implies_unstarted_threads_have_empty_write_buffers (program: Armada.Program.t) (s: Armada.State.t)\n  : Lemma (requires init_program program s)\n          (ensures  unstarted_threads_have_empty_write_buffers s)\n\nval executing_statement_maintains_unstarted_threads_have_empty_write_buffers\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (end_pc: option pc_t)\n  (statement: Armada.Statement.t)\n  (s: Armada.State.t)\n  : Lemma (requires   ThreadStatusRunning? (s.threads actor).status\n                    /\\ unstarted_threads_have_empty_write_buffers s)\n          (ensures  (match statement_computation actor nd start_pc end_pc statement s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> unstarted_threads_have_empty_write_buffers s'))\n"
  },
  {
    "path": "experimental/lib/Strategies.ArmadaStatement.Breaking.fst",
    "content": "module Strategies.ArmadaStatement.Breaking\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.State\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Threads\nopen Armada.Transition\nopen Spec.List\nopen Spec.Ubool\nopen Strategies.ArmadaStatement.Status\nopen Strategies.ArmadaStatement.ThreadState\nopen Strategies.Atomic\nopen Strategies.Breaking\nopen Strategies.Nonyielding\nopen Strategies.PCIndices\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\nopen Util.ImmutableArray\nopen Util.List\n\nlet all_threads_breaking\n  (is_breaking_pc: pc_t -> GTot bool)\n  (s: Armada.State.t)\n  : GTot ubool =\n  NotStopped? s.stop_reason ==>\n    (forall tid. let thread = s.threads tid in\n            ThreadStatusRunning? thread.status ==> is_breaking_pc thread.pc)\n\nlet all_other_threads_breaking\n  (is_breaking_pc: pc_t -> GTot bool)\n  (s: Armada.State.t)\n  (actor: tid_t)\n  : GTot ubool =\n  NotStopped? s.stop_reason ==>\n    (forall tid. let thread = s.threads tid in\n            tid <> actor /\\ ThreadStatusRunning? thread.status ==> is_breaking_pc thread.pc)\n\nlet final_step_computation_establishes_all_threads_breaking\n  (is_breaking_pc: pc_t -> GTot bool)\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (step: Armada.Step.t)\n  (s: Armada.State.t)\n  : Lemma (requires   all_other_threads_breaking is_breaking_pc s actor\n                    /\\ action_only_creates_breaking_threads is_breaking_pc step.action\n                    /\\ action_breaks is_breaking_pc step.action)\n          (ensures (match step_computation actor starts_atomic_block ends_atomic_block step s with\n                    | Some s' -> all_threads_breaking is_breaking_pc s'\n                    | None -> True)) =\n  executing_step_changes_status_depending_on_statement actor starts_atomic_block ends_atomic_block step s;\n  step_effects_on_other_threads actor starts_atomic_block ends_atomic_block step s\n\nlet step_computation_maintains_all_other_threads_breaking\n  (is_breaking_pc: pc_t -> GTot bool)\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (step: Armada.Step.t)\n  (s: Armada.State.t)\n  : Lemma (requires   all_other_threads_breaking is_breaking_pc s actor\n                    /\\ action_only_creates_breaking_threads is_breaking_pc step.action)\n          (ensures (match step_computation actor starts_atomic_block ends_atomic_block step s with\n                    | Some s' -> all_other_threads_breaking is_breaking_pc s' actor\n                    | None -> True)) =\n  executing_step_changes_status_depending_on_statement actor starts_atomic_block ends_atomic_block step s;\n  step_effects_on_other_threads actor starts_atomic_block ends_atomic_block step s\n\nlet rec steps_computation_maintains_all_threads_breaking_if_actions_end_with_all_threads_breaking\n  (is_breaking_pc: pc_t -> GTot bool)\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (steps: list Armada.Step.t)\n  (s: Armada.State.t)\n  : Lemma (requires   all_other_threads_breaking is_breaking_pc s actor\n                    /\\ actions_end_with_all_threads_breaking is_breaking_pc (map_ghost armada_step_to_action steps))\n          (ensures (match steps_computation actor starts_atomic_block ends_atomic_block steps s with\n                    | Some s' -> all_threads_breaking is_breaking_pc s'\n                    | None -> True))\n          (decreases steps) =\n  match steps with\n  | [] -> ()\n  | [final_step] ->\n      final_step_computation_establishes_all_threads_breaking is_breaking_pc actor starts_atomic_block\n        ends_atomic_block final_step s\n  | first_step :: remaining_steps ->\n      step_computation_maintains_all_other_threads_breaking is_breaking_pc actor starts_atomic_block false\n        first_step s;\n      (match step_computation actor starts_atomic_block false first_step s with\n       | None -> ()\n       | Some s' ->\n           steps_computation_maintains_all_threads_breaking_if_actions_end_with_all_threads_breaking\n             is_breaking_pc actor false ends_atomic_block remaining_steps s')\n\nlet steps_computation_maintains_all_threads_breaking\n  (is_breaking_pc: pc_t -> GTot bool)\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (steps: list Armada.Step.t)\n  (s: Armada.State.t)\n  : Lemma (requires   all_threads_breaking is_breaking_pc s\n                    /\\ actions_maintain_all_threads_breaking is_breaking_pc (map_ghost armada_step_to_action steps))\n          (ensures (match steps_computation actor starts_atomic_block ends_atomic_block steps s with\n                    | Some s' -> all_threads_breaking is_breaking_pc s'\n                    | None -> True)) =\n  let actions = map_ghost armada_step_to_action steps in\n  if actions_are_propagate actions then (\n    let step = Cons?.hd steps in\n    executing_step_changes_status_depending_on_statement actor starts_atomic_block ends_atomic_block step s;\n    step_effects_on_other_threads actor starts_atomic_block ends_atomic_block step s;\n    step_computation_requires_start_thread_state actor starts_atomic_block ends_atomic_block step s\n  )\n  else\n    steps_computation_maintains_all_threads_breaking_if_actions_end_with_all_threads_breaking is_breaking_pc\n      actor starts_atomic_block ends_atomic_block steps s\n"
  },
  {
    "path": "experimental/lib/Strategies.ArmadaStatement.Nonyielding.fst",
    "content": "module Strategies.ArmadaStatement.Nonyielding\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.State\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Threads\nopen Armada.Transition\nopen Spec.List\nopen Spec.Ubool\nopen Strategies.ArmadaStatement.Status\nopen Strategies.ArmadaStatement.ThreadState\nopen Strategies.Atomic\nopen Strategies.Nonyielding\nopen Strategies.PCIndices\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\nopen Util.ImmutableArray\nopen Util.List\n\nlet all_threads_yielding\n  (is_nonyielding_pc: pc_t -> GTot bool)\n  (s: Armada.State.t)\n  : GTot ubool =\n  NotStopped? s.stop_reason ==>\n    (forall tid. let thread = s.threads tid in\n            ThreadStatusRunning? thread.status ==> not (is_nonyielding_pc thread.pc))\n\nlet all_other_threads_yielding\n  (is_nonyielding_pc: pc_t -> GTot bool)\n  (s: Armada.State.t)\n  (actor: tid_t)\n  : GTot ubool =\n  NotStopped? s.stop_reason ==>\n    (forall tid. let thread = s.threads tid in\n            tid <> actor /\\ ThreadStatusRunning? thread.status ==> not (is_nonyielding_pc thread.pc))\n\nlet final_step_computation_maintains_all_threads_yielding\n  (is_nonyielding_pc: pc_t -> GTot bool)\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (step: Armada.Step.t)\n  (s: Armada.State.t)\n  : Lemma (requires   all_threads_yielding is_nonyielding_pc s\n                    /\\ (step.action.ok ==> ends_atomic_block)\n                    /\\ action_consistent_with_is_nonyielding_pc is_nonyielding_pc step.action)\n          (ensures (match step_computation actor starts_atomic_block ends_atomic_block step s with\n                    | Some s' -> all_threads_yielding is_nonyielding_pc s'\n                    | None -> True)) =\n  executing_step_changes_status_depending_on_statement actor starts_atomic_block ends_atomic_block step s;\n  step_effects_on_other_threads actor starts_atomic_block ends_atomic_block step s\n\nlet sole_step_computation_maintains_all_threads_yielding\n  (is_nonyielding_pc: pc_t -> GTot bool)\n  (actor: tid_t)\n  (step: Armada.Step.t)\n  (s: Armada.State.t)\n  : Lemma (requires   all_threads_yielding is_nonyielding_pc s\n                    /\\ action_consistent_with_is_nonyielding_pc is_nonyielding_pc step.action)\n          (ensures (match step_computation actor true true step s with\n                    | Some s' -> all_threads_yielding is_nonyielding_pc s'\n                    | None -> True)) =\n  executing_step_changes_status_depending_on_statement actor true true step s;\n  step_effects_on_other_threads actor true true step s\n\nlet step_computation_maintains_all_other_threads_yielding\n  (is_nonyielding_pc: pc_t -> GTot bool)\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (step: Armada.Step.t)\n  (s: Armada.State.t)\n  : Lemma (requires   all_other_threads_yielding is_nonyielding_pc s actor\n                    /\\ action_consistent_with_is_nonyielding_pc is_nonyielding_pc step.action)\n          (ensures (match step_computation actor starts_atomic_block ends_atomic_block step s with\n                    | Some s' -> all_other_threads_yielding is_nonyielding_pc s' actor\n                    | None -> True)) =\n  executing_step_changes_status_depending_on_statement actor starts_atomic_block ends_atomic_block step s;\n  step_effects_on_other_threads actor starts_atomic_block ends_atomic_block step s\n\nlet final_step_computation_establishes_all_threads_yielding\n  (is_nonyielding_pc: pc_t -> GTot bool)\n  (actor: tid_t)\n  (ends_atomic_block: bool)\n  (step: Armada.Step.t)\n  (s: Armada.State.t)\n  : Lemma (requires   all_other_threads_yielding is_nonyielding_pc s actor\n                    /\\ (step.action.ok ==> ends_atomic_block)\n                    /\\ action_consistent_with_is_nonyielding_pc is_nonyielding_pc step.action)\n          (ensures (match step_computation actor false ends_atomic_block step s with\n                    | Some s' -> all_threads_yielding is_nonyielding_pc s'\n                    | None -> True)) =\n  executing_step_changes_status_depending_on_statement actor false ends_atomic_block step s;\n  step_effects_on_other_threads actor false ends_atomic_block step s\n\nlet rec final_steps_computation_establishes_all_threads_yielding\n  (is_nonyielding_pc: pc_t -> GTot bool)\n  (actor: tid_t)\n  (steps: list Armada.Step.t)\n  (s: Armada.State.t)\n  : Lemma (requires   all_other_threads_yielding is_nonyielding_pc s actor\n                    /\\ each_action_consistent_with_is_nonyielding_pc is_nonyielding_pc\n                        (map_ghost armada_step_to_action steps))\n          (ensures (match steps_computation actor false true steps s with\n                    | Some s' -> all_threads_yielding is_nonyielding_pc s'\n                    | None -> True)) =\n  match steps with\n  | [] -> ()\n  | [step] -> final_step_computation_establishes_all_threads_yielding is_nonyielding_pc actor true step s\n  | first_step :: remaining_steps ->\n      step_computation_maintains_all_other_threads_yielding is_nonyielding_pc actor false false first_step s;\n      (match step_computation actor false false first_step s with\n       | Some s' ->\n           final_steps_computation_establishes_all_threads_yielding is_nonyielding_pc actor remaining_steps s'\n       | None -> ())\n\nlet steps_computation_maintains_all_threads_yielding\n  (is_nonyielding_pc: pc_t -> GTot bool)\n  (actor: tid_t)\n  (steps: list Armada.Step.t)\n  (s: Armada.State.t)\n  : Lemma (requires   all_threads_yielding is_nonyielding_pc s\n                    /\\ each_action_consistent_with_is_nonyielding_pc is_nonyielding_pc\n                        (map_ghost armada_step_to_action steps))\n          (ensures (match steps_computation actor true true steps s with\n                    | Some s' -> all_threads_yielding is_nonyielding_pc s'\n                    | None -> True)) =\n  match steps with\n  | [] -> ()\n  | [step] -> sole_step_computation_maintains_all_threads_yielding is_nonyielding_pc actor step s\n  | first_step :: remaining_steps ->\n      step_computation_maintains_all_other_threads_yielding is_nonyielding_pc actor true false first_step s;\n      (match step_computation actor true false first_step s with\n       | Some s' ->\n           final_steps_computation_establishes_all_threads_yielding is_nonyielding_pc actor remaining_steps s'\n       | None -> ())\n\n"
  },
  {
    "path": "experimental/lib/Strategies.ArmadaStatement.Opaque.fst",
    "content": "module Strategies.ArmadaStatement.Opaque\n\nopen Armada.Base\nopen Armada.BinaryOp\nopen Armada.BoundedInt\nopen Armada.Computation\nopen Armada.Expression\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Pointer\nopen Armada.State\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Type\nopen Armada.UnaryOp\nopen FStar.Sequence.Base\nopen FStar.Tactics.V2\nopen Spec.List\nopen Spec.Ubool\nopen Util.List\n\n/// Opaque versions of complex functions called from statement definitions\n\n[@\"opaque_to_smt\"]\nlet rvalue_computation_opaque = rvalue_computation\n\n[@\"opaque_to_smt\"]\nlet rvalues_computation_opaque = rvalues_computation\n\n[@\"opaque_to_smt\"]\nlet update_pointed_to_value_opaque = update_pointed_to_value\n\n[@\"opaque_to_smt\"]\nlet update_expression_opaque = update_expression\n\n[@\"opaque_to_smt\"]\nlet update_expressions_opaque = update_expressions\n\n[@\"opaque_to_smt\"]\nlet propagate_write_message_opaque = propagate_write_message\n\n[@\"opaque_to_smt\"]\nlet check_expression_up_to_date_for_rmw_opaque = check_expression_up_to_date_for_rmw\n\n[@\"opaque_to_smt\"]\nlet push_stack_variables_opaque = push_stack_variables\n\n[@\"opaque_to_smt\"]\nlet push_stack_parameters_opaque = push_stack_parameters\n\n[@\"opaque_to_smt\"]\nlet pop_stack_variables_opaque = pop_stack_variables\n\n[@\"opaque_to_smt\"]\nlet free_pointer_opaque = free_pointer\n\n[@\"opaque_to_smt\"]\nlet external_method_take_snapshot_of_reads_clauses_computation_opaque =\n  external_method_take_snapshot_of_reads_clauses_computation\n\n[@\"opaque_to_smt\"]\nlet external_method_check_snapshot_computation_opaque = external_method_check_snapshot_computation\n\n[@\"opaque_to_smt\"]\nlet log_expressions_computation_opaque = log_expressions_computation\n\n[@\"opaque_to_smt\"]\nlet make_thread_running_opaque = make_thread_running\n\n[@\"opaque_to_smt\"]\nlet push_stack_frame_opaque = push_stack_frame\n\n[@\"opaque_to_smt\"]\nlet pop_stack_frame_opaque = pop_stack_frame\n\n[@\"opaque_to_smt\"]\nlet mark_allocation_root_allocated_opaque = mark_allocation_root_allocated\n\n/// Redacted versions of statement definitions that complex functions called from statement definitions\n\nlet assume_expression_statement_computation_redacted\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (exp: expression_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  if   Cons? nd\n     || neqb (expression_to_td exp) (ObjectTDAbstract bool) then\n     ComputationImpossible\n  else (\n    let? value = rvalue_computation_opaque exp actor s in\n    if ObjectValueAbstract?.value value <> true then\n      ComputationImpossible\n    else\n      return s\n  )\n\nlet assume_predicate_statement_computation_redacted\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (pred: Armada.State.t -> GTot bool)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  if   Cons? nd\n     || not (pred s) then\n    ComputationImpossible\n  else\n    return s\n\nlet assert_true_statement_computation_redacted\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (exp: expression_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  if   Cons? nd\n     || neqb (expression_to_td exp) (ObjectTDAbstract bool) then\n     ComputationImpossible\n  else (\n    let? value = rvalue_computation_opaque exp actor s in\n    if ObjectValueAbstract?.value value <> true then\n      ComputationImpossible\n    else\n      return s\n  )\n\nlet assert_false_statement_computation_redacted\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (exp: expression_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  if   Cons? nd\n     || neqb (expression_to_td exp) (ObjectTDAbstract bool) then\n     ComputationImpossible\n  else (\n    let? value = rvalue_computation_opaque exp actor s in\n    if ObjectValueAbstract?.value value <> false then\n      ComputationImpossible\n    else\n      let s' = { s with stop_reason = StopReasonAssertionFailure } in\n      return s'\n  )\n\nlet conditional_jump_statement_computation_redacted\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (exp: expression_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  if   Cons? nd\n     || neqb (expression_to_td exp) (ObjectTDAbstract bool) then\n    ComputationImpossible\n  else (\n    let? value = rvalue_computation_opaque exp actor s in\n    if ObjectValueAbstract?.value value <> true then\n      ComputationImpossible\n    else\n      return s\n  )\n\nlet unconditional_jump_statement_computation_redacted\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  if Cons? nd then\n    ComputationImpossible\n  else\n    return s\n  \nlet update_statement_computation_redacted\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (bypassing_write_buffer: bool)\n  (dst: expression_t)\n  (src: expression_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  if   Cons? nd\n     || neqb (expression_to_td dst) (expression_to_td src) then\n    ComputationImpossible\n  else (\n    let? src_value = rvalue_computation_opaque src actor s in\n    update_expression_opaque dst actor start_pc 0 bypassing_write_buffer src_value s\n  )\n  \nlet nondeterministic_update_statement_computation_redacted\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (bypassing_write_buffer: bool)\n  (dst: expression_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (expression_to_td dst) then\n    ComputationImpossible\n  else (\n    let nd_value = Cons?.hd nd in\n    if not (object_value_has_all_pointers_uninitialized nd_value) then\n      ComputationImpossible\n    else\n      update_expression_opaque dst actor start_pc 0 bypassing_write_buffer nd_value s\n  )\n\nlet propagate_write_message_statement_computation_redacted\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract tid_t) then\n    ComputationImpossible\n  else\n    let receiver_tid: tid_t = ObjectValueAbstract?.value (Cons?.hd nd) in\n    if receiver_tid = actor then // can't propagate to the same thread\n      ComputationImpossible\n    else\n      let propagator_thread = s.threads actor in\n      let receiver_thread = s.threads receiver_tid in\n      let which_message = receiver_thread.position_in_other_write_buffers actor in\n      if which_message >= length propagator_thread.write_buffer then\n        ComputationImpossible\n      else\n        let write_message = index propagator_thread.write_buffer which_message in\n        let position_in_other_write_buffers' =\n          Spec.Map.upd receiver_thread.position_in_other_write_buffers actor (which_message + 1) in\n        let receiver_thread' =\n          { receiver_thread with position_in_other_write_buffers = position_in_other_write_buffers' } in\n        let threads' = Spec.Map.upd s.threads receiver_tid receiver_thread' in\n        match propagate_write_message_opaque write_message receiver_tid s.mem with\n        | ComputationImpossible\n        | ComputationUndefined ->\n            // If propagate would trigger undefined behavior (e.g., by propagating to freed memory),\n            // it just leaves memory unchanged.\n            return ({ s with threads = threads'; })\n        | ComputationProduces mem' ->\n            return ({ s with mem = mem'; threads = threads'; })\n\nlet compare_and_swap_statement_computation_redacted\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (target: expression_t)\n  (old_val: expression_t)\n  (new_val: expression_t)\n  (bypassing_write_buffer: bool)\n  (optional_result: option expression_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  if   Cons? nd\n     || neqb (expression_to_td target) (expression_to_td old_val)\n     || neqb (expression_to_td target) (expression_to_td new_val)\n     || (match optional_result with\n        | Some result -> neqb (expression_to_td result) (ObjectTDPrimitive PrimitiveTDBool)\n        | None -> false) then\n     ComputationImpossible\n  else (\n    let? _ = check_expression_up_to_date_for_rmw_opaque target actor s in\n    let? old_value = rvalue_computation_opaque old_val actor s in\n    let? target_value = rvalue_computation_opaque target actor s in\n    let? new_value = rvalue_computation_opaque new_val actor s in\n    let? target_ptr = lvalue_computation target actor s in\n    let swap = eqb target_value old_value in\n    let? s' = (if swap then update_pointed_to_value_opaque target_ptr actor start_pc 0 false new_value s else return s)\n    in\n    match optional_result with\n    | None -> return s'\n    | Some result ->\n        // this line is deceptive, and we might be potentially bitten by it later\n        // but it simplify the control flow\n        let? result_ptr = lvalue_computation result actor s in\n        let swap_value = ObjectValuePrimitive (PrimitiveBoxBool swap) in\n        update_pointed_to_value_opaque result_ptr actor start_pc 1 bypassing_write_buffer swap_value s'\n  )\n\nlet atomic_exchange_statement_computation_redacted\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (old_val: expression_t)\n  (target: expression_t)\n  (new_val: expression_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  if   Cons? nd\n     || neqb (expression_to_td target) (expression_to_td old_val)\n     || neqb (expression_to_td target) (expression_to_td new_val) then\n    ComputationImpossible\n  else (\n    // pre-update\n    let? _ = check_expression_up_to_date_for_rmw_opaque target actor s in\n    let? target_value = rvalue_computation_opaque target actor s in\n    let? new_value = rvalue_computation_opaque new_val actor s in\n    let? old_ptr = lvalue_computation old_val actor s in\n    let? target_ptr = lvalue_computation target actor s in\n    // post-update\n    let? s' = update_pointed_to_value_opaque old_ptr actor start_pc 0 false target_value s in\n    update_pointed_to_value_opaque target_ptr actor start_pc 1 false new_value s'\n  )\n\nlet create_thread_statement_computation_redacted\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (method_id: method_id_t)\n  (initial_pc: pc_t)\n  (bypassing_write_buffer: bool)\n  (optional_result: option expression_t)\n  (parameter_var_ids: list var_id_t)\n  (parameter_expressions: list expression_t)\n  (local_variable_initializers: list initializer_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  // Nondeterminism must have exactly one element, of type create_thread_nd_t\n  // If there is a target, then it must be of type thread ID\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract create_thread_nd_t)\n     || (   Some? optional_result\n        && neqb (expression_to_td (Some?.v optional_result)) (ObjectTDPrimitive PrimitiveTDThreadId))\n     || list_len parameter_var_ids <> list_len parameter_expressions then\n    ComputationImpossible\n  else\n    let create_thread_nd: create_thread_nd_t = ObjectValueAbstract?.value (Cons?.hd nd) in\n    let new_tid = create_thread_nd.new_tid in\n    if new_tid = 0 then // thread creation failed, so just set the result to 0\n      (match optional_result with\n       | None -> return s\n       | Some result ->\n           let new_tid_value = ObjectValuePrimitive (PrimitiveBoxThreadId new_tid) in\n           update_expression_opaque result actor start_pc\n              (list_len parameter_var_ids + list_len local_variable_initializers)\n              bypassing_write_buffer new_tid_value s)\n    else (\n      let frame_uniq = create_thread_nd.frame_uniq in\n      let new_thread = s.threads new_tid in\n      if   new_thread.status <> ThreadStatusNotStarted\n         || length new_thread.write_buffer <> 0\n         || list_contains frame_uniq s.uniqs_used then\n        ComputationImpossible\n      else (\n        // Evaluate parameter expressions\n        let? parameter_values = rvalues_computation_opaque parameter_expressions actor s in\n        // Set the new thread's parameters, and give it status \"running\".\n        let s2 = make_thread_running_opaque method_id initial_pc new_tid frame_uniq s in\n        // Initialize the input parameters on the stack of the new thread.\n        // All input variables are assumed to be strongly consistent.\n        let? s3 = push_stack_parameters_opaque new_tid start_pc 0 method_id frame_uniq parameter_var_ids\n                    parameter_values s2 in\n        // Initialize all remaining parameters on the stack of the new thread.\n        let? s4 = push_stack_variables_opaque new_tid start_pc (list_len parameter_var_ids) method_id frame_uniq\n                    local_variable_initializers s3 in\n        // Set the target to the new thread's thread ID, if there is a target\n        (match optional_result with\n         | None -> return s4\n         | Some result ->\n             let new_tid_value = ObjectValuePrimitive (PrimitiveBoxThreadId new_tid) in\n             update_expression_opaque result actor start_pc\n               (list_len parameter_var_ids + list_len local_variable_initializers)\n               bypassing_write_buffer new_tid_value s4)\n    )\n  )\n\nlet method_call_statement_computation_redacted\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (method_id: method_id_t)\n  (return_pc: pc_t)\n  (parameter_var_ids: list var_id_t)\n  (parameter_expressions: list expression_t)\n  (local_variable_initializers: list initializer_t)\n  (stack_overflow: bool)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  // Nondeterminism must have exactly one element, of type method_call_nd_t\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract method_call_nd_t) then\n    ComputationImpossible\n  else\n    let method_call_nd: method_call_nd_t = ObjectValueAbstract?.value (Cons?.hd nd) in\n    let frame_uniq = method_call_nd.frame_uniq in\n    if list_contains frame_uniq s.uniqs_used then\n      ComputationImpossible\n    else (\n      // Evaluate parameter expressions on old stack, in case they reference local variables\n      let? parameter_values = rvalues_computation_opaque parameter_expressions actor s in\n      let s2 = push_stack_frame_opaque actor method_id return_pc frame_uniq s in\n      // All input variables are assumed to be strongly consistent, so pass weakly_consistent=false\n      let? s3 = push_stack_parameters_opaque actor start_pc 0 method_id frame_uniq parameter_var_ids\n                  parameter_values s2 in\n      let? s4 = push_stack_variables_opaque actor start_pc (list_len parameter_var_ids) method_id frame_uniq\n                  local_variable_initializers s3 in\n      if stack_overflow then\n        return ({ s4 with stop_reason = StopReasonStackOverflow })\n      else\n        return s4\n    )\n\nlet return_statement_computation_redacted\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (end_pc: option pc_t)\n  (method_id: method_id_t)\n  (bypassing_write_buffer: bool)\n  (output_dsts: list expression_t)\n  (output_srcs: list expression_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  let thread = s.threads actor in\n  if   Cons? nd\n     || eqb thread.stack []\n     || thread.top.method_id <> method_id\n     || end_pc <> Some (Cons?.hd thread.stack).return_pc then\n    ComputationImpossible\n  else (\n    // First, evaluate output sources, before we pop the stack.\n    let? output_values = rvalues_computation_opaque output_srcs actor s in\n    // Second, free the stack variables and pop the stack.\n    let? mem' = pop_stack_variables_opaque actor method_id thread.top.frame_uniq thread.top.local_variables s.mem in\n    let s2 = pop_stack_frame_opaque actor mem' s in\n    // Third, assign output values to output destinations.\n    update_expressions_opaque output_dsts actor start_pc 0 bypassing_write_buffer output_values s2\n  )\n\nlet terminate_thread_statement_computation_redacted\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (method_id: method_id_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  let thread = s.threads actor in\n  if   Cons? nd\n     || neqb thread.stack []\n     || thread.top.method_id <> method_id\n     || actor = s.initial_tid then // returning from main in the initial thread terminates the process, not the thread\n    ComputationImpossible\n  else (\n    // Otherwise, mark thread as joinable and free all stack variables\n    let? mem' = pop_stack_variables_opaque actor method_id thread.top.frame_uniq thread.top.local_variables s.mem in\n    let thread' = { thread with status = ThreadStatusJoinable } in\n    let threads' = Spec.Map.upd s.threads actor thread' in\n    let s' = { s with mem = mem'; threads = threads' } in\n    return s'\n  )\n\nlet terminate_process_statement_computation_redacted\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (method_id: method_id_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  let thread = s.threads actor in\n  if   Cons? nd\n     || neqb thread.stack []\n     || thread.top.method_id <> method_id\n     || actor <> s.initial_tid then // the process is terminated by having the initial thread terminate\n    ComputationImpossible\n  else\n    let s' = { s with stop_reason = StopReasonTerminated } in\n    return s'\n\nlet join_statement_computation_redacted\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (join_tid: expression_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  if   Cons? nd\n     || neqb (expression_to_td join_tid) (ObjectTDPrimitive PrimitiveTDThreadId) then\n    ComputationImpossible\n  else (\n    let? tid_value = rvalue_computation_opaque join_tid actor s in\n    let other_tid = PrimitiveBoxThreadId?.tid (ObjectValuePrimitive?.value tid_value) in\n    let thread = s.threads other_tid in\n    match thread.status with\n    | ThreadStatusNotStarted -> ComputationImpossible // can't get a handle to a non-started thread\n    | ThreadStatusRunning -> ComputationImpossible    // not possible since join would block\n    | ThreadStatusPostJoin -> ComputationUndefined    // not defined to join a thread twice\n    | ThreadStatusJoinable ->\n        let thread' = { thread with status = ThreadStatusPostJoin } in\n        let threads' = Spec.Map.upd s.threads other_tid thread' in\n        let s' = { s with threads = threads' } in\n        return s'\n  )\n\nlet alloc_successful_statement_computation_redacted\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (zero_initialized: bool)\n  (bypassing_write_buffer: bool)\n  (result: expression_t)\n  (allocation_td: object_td_t)\n  (count: expression_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  // There should be one non-determinism parameter, the root ID uniquifier.\n  // The result destination should be of type pointer.\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract root_id_uniquifier_t)\n     || neqb (expression_to_td count) (ObjectTDAbstract nat)\n     || neqb (expression_to_td result) (ObjectTDPrimitive PrimitiveTDPointer) then\n    ComputationImpossible\n  else (\n    let? count_value = rvalue_computation_opaque count actor s in\n    let sz = ObjectValueAbstract?.value count_value in\n    let array_td = ObjectTDArray allocation_td sz in\n    let uniq = ObjectValueAbstract?.value (Cons?.hd nd) in\n    let root_id = RootIdAllocation uniq in\n    match s.mem root_id with\n    | RootAllocated allocated freed storage ->\n        if   allocated\n           || freed\n           || neqb (object_storage_to_td storage) array_td\n           || not (is_storage_ready_for_allocation storage)\n           || (not zero_initialized && not (object_storage_arbitrarily_initialized_correctly storage))\n           || (zero_initialized && not (is_storage_zero_filled storage)) then\n          ComputationImpossible\n        else\n          // update memory by marking root as allocated\n          let s' = mark_allocation_root_allocated_opaque uniq storage s in\n          // store the pointer to the first element of the newly allocated array in result\n          let p = ObjectValuePrimitive (PrimitiveBoxPointer (PointerIndex (PointerRoot root_id) 0)) in\n          update_expression_opaque result actor start_pc 0 bypassing_write_buffer p s'\n    | _ -> ComputationImpossible\n  )\n\nlet alloc_returning_null_statement_computation_redacted\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (bypassing_write_buffer: bool)\n  (result: expression_t)\n  (count: expression_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  if   Cons? nd\n     || neqb (expression_to_td count) (ObjectTDAbstract nat)\n     || neqb (expression_to_td result) (ObjectTDPrimitive PrimitiveTDPointer) then\n    ComputationImpossible\n  else (\n    let? _ = rvalue_computation_opaque count actor s in\n    let p = ObjectValuePrimitive (PrimitiveBoxPointer PointerNull) in\n    update_expression_opaque result actor start_pc 0 bypassing_write_buffer p s\n  )\n\nlet dealloc_statement_computation_redacted\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (ptr: expression_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  if   Cons? nd\n     || neqb (expression_to_td ptr) (ObjectTDPrimitive PrimitiveTDPointer) then\n    ComputationImpossible\n  else (\n    let? ptr_value = rvalue_computation_opaque ptr actor s in\n    let p = PrimitiveBoxPointer?.ptr (ObjectValuePrimitive?.value ptr_value) in\n    let? mem' = free_pointer_opaque p s.mem in\n    let s' = { s with mem = mem' } in\n    return s'\n  )\n\nlet somehow_statement_computation_redacted\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (undefined_unless_cond: expression_t)\n  (bypassing_write_buffer: bool)\n  (modifies_clauses: list expression_t)\n  (ensures_cond: expression_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  // The non-determinism can be any length, since it's the set of modified objects.\n  if   neqb (expression_to_td undefined_unless_cond) (ObjectTDPrimitive PrimitiveTDBool)\n     || neqb (expression_to_td ensures_cond) (ObjectTDPrimitive PrimitiveTDBool) then\n    ComputationImpossible\n  else (\n    // Exhibit undefined behavior unless the undefined_unless condition holds\n    let? undefined_unless_value = rvalue_computation_opaque undefined_unless_cond actor s in\n    let undefined_unless_bool = PrimitiveBoxBool?.b (ObjectValuePrimitive?.value undefined_unless_value) in\n    if not undefined_unless_bool then\n      ComputationUndefined\n    else (\n      // Update each element of the modifies clauses using the nondeterminism to supply modified values\n      let? s' = update_expressions_opaque modifies_clauses actor start_pc 0 bypassing_write_buffer nd s in\n      // Assume the ensures clause holds\n      let? ensures_value = rvalue_computation_opaque ensures_cond actor s' in\n      let ensures_bool = PrimitiveBoxBool?.b (ObjectValuePrimitive?.value ensures_value) in\n      if not ensures_bool then\n        ComputationImpossible\n      else\n        return s'\n    )\n  )\n\nlet fence_statement_computation_redacted\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  if Cons? nd then\n    ComputationImpossible\n  else (\n    let root = s.mem RootIdFence in\n    let? storage = root_to_storage_computation root in\n    if not (object_storage_up_to_date_for_rmw_operation storage actor) then\n      ComputationImpossible\n    else\n      let p = PointerRoot RootIdFence in\n      update_pointed_to_value_opaque p actor start_pc 0 false (ObjectValuePrimitive (PrimitiveBoxBool false)) s\n  )\n\nlet external_method_take_snapshot_of_reads_clauses_computation_redacted\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (reads_clauses: list (var_id_t * expression_t))\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t)\n    (decreases reads_clauses) =\n  match reads_clauses with\n  | [] -> return s\n  | (first_var_id, first_reads_expression) :: remaining_reads_clauses ->\n      let? first_value = rvalue_computation_opaque first_reads_expression actor s in\n      let td = expression_to_td first_reads_expression in\n      let local_var = ExpressionLocalVariable td first_var_id in\n      let? s' = update_expression_opaque local_var actor writer_pc writer_expression_number bypassing_write_buffer\n                  first_value s in\n      external_method_take_snapshot_of_reads_clauses_computation_opaque actor writer_pc (writer_expression_number + 1)\n        bypassing_write_buffer remaining_reads_clauses s'\n\nlet external_method_start_statement_computation_redacted\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (await_cond: expression_t)\n  (undefined_unless_cond: expression_t)\n  (bypassing_write_buffer: bool)\n  (modifies_clauses: list expression_t)\n  (reads_clauses: list (var_id_t * expression_t))\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  // The nondeterminism should be a list of all the values to write into the write set\n  if   neqb (expression_to_td await_cond) (ObjectTDPrimitive PrimitiveTDBool)\n     || neqb (expression_to_td undefined_unless_cond) (ObjectTDPrimitive PrimitiveTDBool)\n     || list_len modifies_clauses <> list_len nd then\n    ComputationImpossible\n  else (\n    // First, wait for all the awaits clauses to hold.\n    let? await_value = rvalue_computation_opaque await_cond actor s in\n    let await_bool = PrimitiveBoxBool?.b (ObjectValuePrimitive?.value await_value) in\n    if not await_bool then\n      ComputationImpossible\n    else (\n      // Second, manifest undefined behavior if the undefined_unless clauses don't all hold.\n      let? undefined_unless_value = rvalue_computation_opaque undefined_unless_cond actor s in\n      let undefined_unless_bool = PrimitiveBoxBool?.b (ObjectValuePrimitive?.value await_value) in\n      if not undefined_unless_bool then\n        ComputationUndefined\n      else (\n        // Third, havoc the write set, using the nondeterminism to supply the new values.\n        let? s2 = update_expressions_opaque modifies_clauses actor start_pc 0 bypassing_write_buffer nd s in\n        // Fourth, capture the read set into local stack variables, starting with variable 0.\n        external_method_take_snapshot_of_reads_clauses_computation_opaque actor start_pc (list_len modifies_clauses)\n          bypassing_write_buffer reads_clauses s2\n      )\n    )\n  )\n\nlet external_method_middle_statement_computation_redacted\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (bypassing_write_buffer: bool)\n  (modifies_clauses: list expression_t)\n  (reads_clauses: list (var_id_t * expression_t))\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  // The nondeterminism should be a list of all the values to write into the write set\n  // First, manifest undefined behavior if the reads clauses don't match the snapshot on the stack,\n  // starting with variable 0.\n  let? _ = external_method_check_snapshot_computation_opaque actor reads_clauses s in\n  // Second, havoc the write set, using the nondeterminism `nd` to supply the new values.\n  let? s2 = update_expressions_opaque modifies_clauses actor start_pc 0 bypassing_write_buffer nd s in\n  // Third, capture the read set into local stack variables, starting with variable 0.\n  external_method_take_snapshot_of_reads_clauses_computation_opaque actor start_pc (list_len modifies_clauses)\n    bypassing_write_buffer reads_clauses s2\n\nlet external_method_end_statement_computation_redacted\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (ensures_cond: expression_t)\n  (logs_clauses: list expression_t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  if   Cons? nd\n     || neqb (expression_to_td ensures_cond) (ObjectTDPrimitive PrimitiveTDBool) then\n    ComputationImpossible\n  else (\n    let? ensures_value = rvalue_computation_opaque ensures_cond actor s in\n    let ensures_bool = PrimitiveBoxBool?.b (ObjectValuePrimitive?.value ensures_value) in\n    if not ensures_bool then\n      ComputationImpossible\n    else\n      log_expressions_computation_opaque actor logs_clauses s\n  )\n\nlet statement_computation_redacted\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (end_pc: option pc_t)\n  (statement: Armada.Statement.t)\n  (s: Armada.State.t)\n  : GTot (conditional_computation_t Armada.State.t) =\n  match statement with\n  | AssumeExpressionStatement exp ->\n      assume_expression_statement_computation_redacted actor nd start_pc exp s\n  | AssumePredicateStatement pred ->\n      assume_predicate_statement_computation_redacted actor nd start_pc pred s\n  | AssertTrueStatement exp ->\n      assert_true_statement_computation_redacted actor nd start_pc exp s\n  | AssertFalseStatement exp ->\n      assert_false_statement_computation_redacted actor nd start_pc exp s\n  | ConditionalJumpStatement cond ->\n      conditional_jump_statement_computation_redacted actor nd start_pc cond s\n  | UnconditionalJumpStatement ->\n      unconditional_jump_statement_computation_redacted actor nd start_pc s\n  | UpdateStatement bypassing_write_buffer dst src ->\n      update_statement_computation_redacted actor nd start_pc bypassing_write_buffer dst src s\n  | NondeterministicUpdateStatement bypassing_write_buffer dst ->\n      nondeterministic_update_statement_computation_redacted actor nd start_pc bypassing_write_buffer dst s\n  | PropagateWriteMessageStatement ->\n      propagate_write_message_statement_computation_redacted actor nd s\n  | CompareAndSwapStatement target old_val new_val bypassing_write_buffer optional_result ->\n      compare_and_swap_statement_computation_redacted actor nd start_pc target old_val new_val\n        bypassing_write_buffer optional_result s\n  | AtomicExchangeStatement old_val target new_val ->\n      atomic_exchange_statement_computation_redacted actor nd start_pc old_val target new_val s\n  | CreateThreadStatement method_id initial_pc bypassing_write_buffer optional_result parameter_var_ids\n                          parameter_expressions local_variable_initializers ->\n      create_thread_statement_computation_redacted actor nd start_pc method_id initial_pc bypassing_write_buffer\n        optional_result parameter_var_ids parameter_expressions local_variable_initializers s\n  | MethodCallStatement method_id return_pc parameter_var_ids parameter_expressions local_variable_initializers\n                          stack_overflow ->\n      method_call_statement_computation_redacted actor nd start_pc method_id return_pc parameter_var_ids\n        parameter_expressions local_variable_initializers stack_overflow s\n  | ReturnStatement method_id bypassing_write_buffer output_dsts output_srcs ->\n      return_statement_computation_redacted actor nd start_pc end_pc method_id bypassing_write_buffer output_dsts\n        output_srcs s\n  | TerminateThreadStatement method_id ->\n      terminate_thread_statement_computation_redacted actor nd start_pc method_id s\n  | TerminateProcessStatement method_id ->\n      terminate_process_statement_computation_redacted actor nd start_pc method_id s\n  | JoinStatement join_tid ->\n      join_statement_computation_redacted actor nd start_pc join_tid s\n  | MallocSuccessfulStatement bypassing_write_buffer result allocation_td count ->\n      alloc_successful_statement_computation_redacted actor nd start_pc false bypassing_write_buffer result\n        allocation_td count s\n  | MallocReturningNullStatement bypassing_write_buffer result count ->\n      alloc_returning_null_statement_computation_redacted actor nd start_pc bypassing_write_buffer result count s\n  | CallocSuccessfulStatement bypassing_write_buffer result allocation_td count ->\n      alloc_successful_statement_computation_redacted actor nd start_pc true bypassing_write_buffer result\n        allocation_td count s\n  | CallocReturningNullStatement bypassing_write_buffer result count ->\n      alloc_returning_null_statement_computation_redacted actor nd start_pc bypassing_write_buffer result count s\n  | DeallocStatement ptr ->\n      dealloc_statement_computation_redacted actor nd start_pc ptr s\n  | SomehowStatement undefined_unless_cond bypassing_write_buffer modifies_clauses ensures_cond ->\n      somehow_statement_computation_redacted actor nd start_pc undefined_unless_cond\n        bypassing_write_buffer modifies_clauses ensures_cond s\n  | FenceStatement ->\n      fence_statement_computation_redacted actor nd start_pc s\n  | ExternalMethodStartStatement await_cond undefined_unless_cond bypassing_write_buffer\n                                 modifies_clauses reads_clauses ->\n      external_method_start_statement_computation_redacted actor nd start_pc await_cond undefined_unless_cond\n        bypassing_write_buffer modifies_clauses reads_clauses s\n  | ExternalMethodMiddleStatement bypassing_write_buffer modifies_clauses reads_clauses ->\n      external_method_middle_statement_computation_redacted actor nd start_pc bypassing_write_buffer modifies_clauses\n        reads_clauses s\n  | ExternalMethodEndStatement ensures_cond logs_clauses ->\n      external_method_end_statement_computation_redacted actor nd start_pc ensures_cond logs_clauses s\n\n/// Proofs that redacted versions are equivalent to unredacted versions\n\nlet statement_computation_redacted_equivalent ()\n  : Lemma (statement_computation_redacted == statement_computation) =\n  assert (assume_expression_statement_computation_redacted == assume_expression_statement_computation) by trefl();\n  assert (assume_predicate_statement_computation_redacted == assume_predicate_statement_computation) by trefl();\n  assert (assert_true_statement_computation_redacted == assert_true_statement_computation) by trefl();\n  assert (assert_false_statement_computation_redacted == assert_false_statement_computation) by trefl();\n  assert (conditional_jump_statement_computation_redacted == conditional_jump_statement_computation) by trefl();\n  assert (unconditional_jump_statement_computation_redacted == unconditional_jump_statement_computation) by trefl();\n  assert (update_statement_computation_redacted == update_statement_computation) by trefl();\n  assert (nondeterministic_update_statement_computation_redacted == nondeterministic_update_statement_computation)\n    by trefl();\n  assert (propagate_write_message_statement_computation_redacted == propagate_write_message_statement_computation)\n    by trefl();\n  assert (compare_and_swap_statement_computation_redacted == compare_and_swap_statement_computation) by trefl();\n  assert (atomic_exchange_statement_computation_redacted == atomic_exchange_statement_computation) by trefl();\n  assert (create_thread_statement_computation_redacted == create_thread_statement_computation) by trefl();\n  assert (method_call_statement_computation_redacted == method_call_statement_computation) by trefl();\n  assert (return_statement_computation_redacted == return_statement_computation) by trefl();\n  assert (terminate_thread_statement_computation_redacted == terminate_thread_statement_computation) by trefl();\n  assert (terminate_process_statement_computation_redacted == terminate_process_statement_computation) by trefl();\n  assert (join_statement_computation_redacted == join_statement_computation) by trefl();\n  assert (alloc_successful_statement_computation_redacted == alloc_successful_statement_computation) by trefl();\n  assert (alloc_returning_null_statement_computation_redacted == alloc_returning_null_statement_computation)\n    by trefl();\n  assert (dealloc_statement_computation_redacted == dealloc_statement_computation) by trefl();\n  assert (somehow_statement_computation_redacted == somehow_statement_computation) by trefl();\n  assert (fence_statement_computation_redacted == fence_statement_computation) by trefl();\n  assert (external_method_take_snapshot_of_reads_clauses_computation_redacted ==\n          external_method_take_snapshot_of_reads_clauses_computation) by trefl();\n  assert (external_method_start_statement_computation_redacted == external_method_start_statement_computation)\n    by trefl();\n  assert (external_method_middle_statement_computation_redacted == external_method_middle_statement_computation)\n    by trefl();\n  assert (external_method_end_statement_computation_redacted == external_method_end_statement_computation) by trefl();\n  assert (statement_computation_redacted == statement_computation) by trefl()\n"
  },
  {
    "path": "experimental/lib/Strategies.ArmadaStatement.Propagate.fst",
    "content": "module Strategies.ArmadaStatement.Propagate\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Computation\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Program\nopen Armada.State\nopen Armada.Step\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Threads\nopen Armada.Transition\nopen Armada.Type\nopen Spec.List\nopen Spec.Ubool\nopen Util.List\n\nlet propagate_program_statement: program_statement_t =\n  { start_pc = None;\n    end_pc = None;\n    starts_atomic_block = true;\n    ends_atomic_block = true;\n    statement = PropagateWriteMessageStatement }\n\nlet propagate_action: Armada.Action.t =\n  { ok = true; program_statement = propagate_program_statement }\n\nlet propagate_action_list: list Armada.Action.t =\n  [propagate_action]\n\nlet possible_propagate_action_ok\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (s: Armada.State.t)\n  (steps: list Armada.Step.t)\n  : Lemma (requires   Some? (steps_computation actor starts_atomic_block ends_atomic_block steps s)\n                    /\\ Cons? steps\n                    /\\ (Cons?.hd steps).action.program_statement == propagate_program_statement)\n          (ensures  (Cons?.hd steps).action.ok) =\n  ()\n\nlet step_computation_is_propagate_computation\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (s: Armada.State.t)\n  (step: Armada.Step.t)\n  : Lemma (requires  (  step == { nd = nd; action = propagate_action }\n                      /\\ NotStopped? s.stop_reason\n                      /\\ ThreadStatusRunning? (s.threads actor).status\n                      /\\ (ComputationProduces? (propagate_write_message_statement_computation actor nd s))))\n          (ensures  step_computation actor true true step s ==\n                      Some (ComputationProduces?.result (propagate_write_message_statement_computation actor nd s))) =\n  ()\n"
  },
  {
    "path": "experimental/lib/Strategies.ArmadaStatement.Status.fst",
    "content": "module Strategies.ArmadaStatement.Status\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Computation\nopen Armada.Expression\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Pointer\nopen Armada.State\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Transition\nopen Armada.Type\nopen FStar.Sequence.Base\nopen Spec.List\nopen Spec.Logic\nopen Spec.Ubool\nopen Strategies.ArmadaStatement\nopen Strategies.PCRelation\nopen Strategies.Semantics.Armada\n\nlet push_stack_variable_maintains_status\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (initializer: initializer_t)\n  (s: Armada.State.t)\n  : Lemma (ensures  (match push_stack_variable actor writer_pc writer_expression_number method_id\n                             frame_uniq initializer s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> status_unchanged actor s s')) =\n  ()\n\nlet rec push_stack_variables_maintains_status\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (initializers: list initializer_t)\n  (s: Armada.State.t)\n  : Lemma (ensures  (match push_stack_variables actor writer_pc writer_expression_number method_id\n                             frame_uniq initializers s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> status_unchanged actor s s'))\n          (decreases initializers) =\n  match initializers with\n  | [] -> ()\n  | first_initializer :: remaining_initializers ->\n      push_stack_variable_maintains_status actor writer_pc\n        writer_expression_number method_id frame_uniq first_initializer s;\n      (match push_stack_variable actor writer_pc writer_expression_number method_id frame_uniq first_initializer s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces s' ->\n           push_stack_variables_maintains_status actor writer_pc\n             (writer_expression_number + 1) method_id frame_uniq remaining_initializers s')\n\nlet rec push_stack_parameters_maintains_status\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (var_ids: list var_id_t)\n  (parameters: list object_value_t)\n  (s: Armada.State.t)\n  : Lemma (ensures  (match push_stack_parameters actor writer_pc writer_expression_number method_id frame_uniq\n                             var_ids parameters s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> status_unchanged actor s s'))\n          (decreases parameters) =\n  match parameters, var_ids with\n  | [], [] -> ()\n  | first_parameter :: remaining_parameters, first_var_id :: remaining_var_ids ->\n      let first_initializer =\n        { var_id = first_var_id; iv = InitializerSpecific first_parameter; weakly_consistent = false } in\n      push_stack_variable_maintains_status actor writer_pc\n        writer_expression_number method_id frame_uniq first_initializer s;\n      (match push_stack_variable actor writer_pc writer_expression_number method_id frame_uniq first_initializer s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces s' ->\n           push_stack_parameters_maintains_status actor writer_pc\n             (writer_expression_number + 1) method_id frame_uniq remaining_var_ids remaining_parameters s')\n  | _ -> ()\n\nlet update_expression_maintains_status\n  (exp: expression_t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (new_value: object_value_t)\n  (s: Armada.State.t)\n  : Lemma (ensures  (match update_expression exp actor writer_pc writer_expression_number bypassing_write_buffer\n                             new_value s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> status_unchanged actor s s')) =\n  let cs' = update_expression exp actor writer_pc writer_expression_number bypassing_write_buffer\n              new_value s in\n  if   not (expression_valid exp)\n     || not (object_value_valid new_value)\n     || neqb (object_value_to_td new_value) (expression_to_td exp) then\n    ()\n  else\n    ()\n\nlet rec update_expressions_maintains_status\n  (exps: list expression_t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (new_values: list object_value_t)\n  (s: Armada.State.t)\n  : Lemma (ensures  (match update_expressions exps actor writer_pc writer_expression_number bypassing_write_buffer\n                             new_values s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> status_unchanged actor s s'))\n          (decreases exps) =\n  match exps, new_values with\n  | [], [] -> ()\n  | first_exp :: remaining_exps, first_new_value :: remaining_new_values ->\n      update_expression_maintains_status first_exp actor writer_pc\n        writer_expression_number bypassing_write_buffer first_new_value s;\n      (match update_expression first_exp actor writer_pc writer_expression_number\n               bypassing_write_buffer first_new_value s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces s' ->\n           update_expressions_maintains_status remaining_exps actor writer_pc\n             (writer_expression_number + 1) bypassing_write_buffer remaining_new_values s')\n  | _ -> ()\n\nlet rec external_method_take_snapshot_maintains_status\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (reads_clauses: list (var_id_t * expression_t))\n  (s: Armada.State.t)\n  : Lemma (ensures  (match external_method_take_snapshot_of_reads_clauses_computation actor writer_pc\n                             writer_expression_number bypassing_write_buffer reads_clauses s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> status_unchanged actor s s'))\n          (decreases reads_clauses) =\n  match reads_clauses with\n  | [] -> ()\n  | (first_var_id, first_reads_expression) :: remaining_reads_clauses ->\n      (match rvalue_computation first_reads_expression actor s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces first_value ->\n           let td = expression_to_td first_reads_expression in\n           let local_var = ExpressionLocalVariable td first_var_id in\n           update_expression_maintains_status local_var actor writer_pc\n             writer_expression_number bypassing_write_buffer first_value s;\n           (match update_expression local_var actor writer_pc writer_expression_number bypassing_write_buffer\n                    first_value s with\n            | ComputationImpossible | ComputationUndefined -> ()\n            | ComputationProduces s' ->\n                external_method_take_snapshot_maintains_status\n                  actor writer_pc (writer_expression_number + 1) bypassing_write_buffer remaining_reads_clauses s'))\n  | _ -> ()\n\nlet rec log_expressions_computation_maintains_status\n  (actor: tid_t)\n  (logs_clauses: list expression_t)\n  (s: Armada.State.t)\n  : Lemma (ensures  (match log_expressions_computation actor logs_clauses s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> status_unchanged actor s s'))\n          (decreases logs_clauses) =\n  match logs_clauses with\n  | [] -> ()\n  | first_logs_clause :: remaining_logs_clauses ->\n      (match rvalue_computation first_logs_clause actor s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces event ->\n           let trace' = s.trace $:: event in\n           let s' = { s with trace = trace' } in\n           log_expressions_computation_maintains_status actor\n             remaining_logs_clauses s')\n\n#push-options \"--z3rlimit 10\"\n\nlet assume_expression_statement_computation_maintains_status\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (exp: expression_t)\n  (s: Armada.State.t)\n  : Lemma (ensures  (match assume_expression_statement_computation actor nd start_pc exp s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> status_unchanged actor s s')) =\n  ()\n\nlet assume_predicate_statement_computation_maintains_status\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (pred: Armada.State.t -> GTot bool)\n  (s: Armada.State.t)\n  : Lemma (ensures  (match assume_predicate_statement_computation actor nd start_pc pred s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> status_unchanged actor s s')) =\n  ()\n\nlet assert_true_statement_computation_maintains_status\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (exp: expression_t)\n  (s: Armada.State.t)\n  : Lemma (ensures  (match assert_true_statement_computation actor nd start_pc exp s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> status_unchanged actor s s')) =\n  ()\n\nlet assert_false_statement_computation_maintains_status\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (exp: expression_t)\n  (s: Armada.State.t)\n  : Lemma (ensures  (match assert_false_statement_computation actor nd start_pc exp s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' ->\n                           StopReasonAssertionFailure? s'.stop_reason\n                         /\\ (forall other_actor. other_actor <> actor ==>\n                                           s'.threads other_actor == s.threads other_actor))) =\n  ()\n\nlet conditional_jump_statement_computation_maintains_status\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (exp: expression_t)\n  (s: Armada.State.t)\n  : Lemma (ensures  (match conditional_jump_statement_computation actor nd start_pc exp s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> status_unchanged actor s s')) =\n  ()\n\nlet unconditional_jump_statement_computation_maintains_status\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (s: Armada.State.t)\n  : Lemma (ensures  (match unconditional_jump_statement_computation actor nd start_pc s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> status_unchanged actor s s')) =\n  ()\n\nlet update_statement_computation_maintains_status\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (bypassing_write_buffer: bool)\n  (dst: expression_t)\n  (src: expression_t)\n  (s: Armada.State.t)\n  : Lemma (ensures  (match update_statement_computation actor nd start_pc bypassing_write_buffer dst src s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> status_unchanged actor s s')) =\n  let cs' = update_statement_computation actor nd start_pc bypassing_write_buffer dst src s in\n  if   Cons? nd\n     || neqb (expression_to_td dst) (expression_to_td src) then\n    ()\n  else (\n    match rvalue_computation src actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces src_value ->\n        update_expression_maintains_status dst actor start_pc 0 bypassing_write_buffer src_value s\n  )\n\nlet nondeterministic_update_statement_computation_maintains_status\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (bypassing_write_buffer: bool)\n  (dst: expression_t)\n  (s: Armada.State.t)\n  : Lemma (ensures  (match nondeterministic_update_statement_computation actor nd start_pc bypassing_write_buffer\n                             dst s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> status_unchanged actor s s')) =\n  let cs' = nondeterministic_update_statement_computation actor nd start_pc bypassing_write_buffer dst s in\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (expression_to_td dst) then\n    ()\n  else (\n    let nd_value = Cons?.hd nd in\n    if not (object_value_has_all_pointers_uninitialized nd_value) then\n      ()\n    else\n      update_expression_maintains_status dst actor start_pc 0\n        bypassing_write_buffer nd_value s\n  )\n\nlet propagate_write_message_statement_computation_maintains_status\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (s: Armada.State.t)\n  : Lemma (ensures  (match propagate_write_message_statement_computation actor nd s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' ->\n                         let receiver_tid: tid_t = ObjectValueAbstract?.value (Cons?.hd nd) in\n                             s'.stop_reason = s.stop_reason\n                          /\\ (s'.threads actor).status = (s.threads actor).status\n                          /\\ (s'.threads actor).pc = (s.threads actor).pc\n                          /\\ (forall other_actor. other_actor <> actor /\\ other_actor <> receiver_tid ==>\n                                            s'.threads other_actor == s.threads other_actor)\n                          /\\ (s'.threads receiver_tid).status = (s.threads receiver_tid).status\n                          /\\ (s'.threads receiver_tid).pc = (s.threads receiver_tid).pc)) =\n  ()\n\nlet compare_and_swap_statement_computation_maintains_status\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (target: expression_t)\n  (old_val: expression_t)\n  (new_val: expression_t)\n  (bypassing_write_buffer: bool)\n  (optional_result: option expression_t)\n  (s: Armada.State.t)\n  : Lemma (ensures  (match compare_and_swap_statement_computation actor nd start_pc target old_val new_val\n                             bypassing_write_buffer optional_result s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> status_unchanged actor s s')) =\n  let cs' = compare_and_swap_statement_computation actor nd start_pc target old_val new_val\n              bypassing_write_buffer optional_result s in\n  if   Cons? nd\n     || neqb (expression_to_td target) (expression_to_td old_val)\n     || neqb (expression_to_td target) (expression_to_td new_val)\n     || (match optional_result with\n        | Some result -> neqb (expression_to_td result) (ObjectTDPrimitive PrimitiveTDBool)\n        | None -> false) then\n    ()\n  else (\n    match check_expression_up_to_date_for_rmw target actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces _ ->\n        (match rvalue_computation old_val actor s with\n         | ComputationImpossible | ComputationUndefined -> ()\n         | ComputationProduces old_value ->\n             (match rvalue_computation target actor s with\n              | ComputationImpossible | ComputationUndefined -> ()\n              | ComputationProduces target_value ->\n                  (match rvalue_computation new_val actor s with\n                   | ComputationImpossible | ComputationUndefined -> ()\n                   | ComputationProduces new_value ->\n                       let swap = eqb target_value old_value in\n                       update_expression_maintains_status target actor start_pc\n                         0 false new_value s;\n                       (match optional_result with\n                        | None -> ()\n                        | Some result ->\n                            (match if swap then update_expression target actor start_pc 0 false new_value s\n                                   else return s with\n                             | ComputationImpossible | ComputationUndefined -> ()\n                             | ComputationProduces s' ->\n                                 let swap_value = ObjectValuePrimitive (PrimitiveBoxBool swap) in\n                                 update_expression_maintains_status result actor\n                                   start_pc 1 bypassing_write_buffer swap_value s')))))\n  )\n\nlet atomic_exchange_statement_computation_maintains_status\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (old_val: expression_t)\n  (target: expression_t)\n  (new_val: expression_t)\n  (s: Armada.State.t)\n  : Lemma (ensures  (match atomic_exchange_statement_computation actor nd start_pc old_val target new_val s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> status_unchanged actor s s')) =\n  let cs' = atomic_exchange_statement_computation actor nd start_pc old_val target new_val s in\n  match check_expression_up_to_date_for_rmw target actor s with\n  | ComputationImpossible | ComputationUndefined -> ()\n  | ComputationProduces _ ->\n      (match rvalue_computation target actor s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces target_value ->\n           (match rvalue_computation new_val actor s with\n            | ComputationImpossible | ComputationUndefined -> ()\n            | ComputationProduces new_value ->\n                update_expression_maintains_status old_val actor\n                  start_pc 0 false target_value s;\n                (match update_expression old_val actor start_pc 0 false target_value s with\n                 | ComputationImpossible | ComputationUndefined -> ()\n                 | ComputationProduces s' ->\n                     update_expression_maintains_status target actor\n                       start_pc 1 false new_value s')))\n\n#pop-options\n#push-options \"--z3rlimit 20\"\n\nlet create_thread_statement_computation_maintains_status\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (method_id: method_id_t)\n  (initial_pc: pc_t)\n  (bypassing_write_buffer: bool)\n  (optional_result: option expression_t)\n  (parameter_var_ids: list var_id_t)\n  (parameter_expressions: list expression_t)\n  (local_variable_initializers: list initializer_t)\n  (s: Armada.State.t)\n  : Lemma (ensures  (match create_thread_statement_computation actor nd start_pc method_id initial_pc\n                             bypassing_write_buffer optional_result parameter_var_ids parameter_expressions\n                             local_variable_initializers s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' ->\n                         let create_thread_nd: create_thread_nd_t = ObjectValueAbstract?.value (Cons?.hd nd) in\n                         let new_tid = create_thread_nd.new_tid in\n                           s'.stop_reason = s.stop_reason\n                         /\\ (ThreadStatusRunning? (s.threads actor).status ==>\n                              ThreadStatusRunning? (s'.threads actor).status\n                            /\\ (s'.threads actor).pc = (s.threads actor).pc)\n                         /\\ (if new_tid = 0 then\n                             (forall other_actor. other_actor <> actor ==> s'.threads other_actor == s.threads other_actor)\n                            else (\n                                (s'.threads new_tid).pc = initial_pc\n                              /\\ (forall other_actor. other_actor <> actor /\\ other_actor <> new_tid ==>\n                                              s'.threads other_actor == s.threads other_actor)\n                            )))) =\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract create_thread_nd_t)\n     || (   Some? optional_result\n        && neqb (expression_to_td (Some?.v optional_result)) (ObjectTDPrimitive PrimitiveTDThreadId))\n     || list_len parameter_var_ids <> list_len parameter_expressions then\n    ()\n  else (\n    let create_thread_nd: create_thread_nd_t = ObjectValueAbstract?.value (Cons?.hd nd) in\n    let new_tid = create_thread_nd.new_tid in\n    if new_tid = 0 then\n      (match optional_result with\n       | None -> ()\n       | Some result ->\n          let new_tid_value = ObjectValuePrimitive (PrimitiveBoxThreadId new_tid) in\n          update_expression_maintains_status result actor start_pc\n            (list_len parameter_var_ids + list_len local_variable_initializers) bypassing_write_buffer\n            new_tid_value s)\n    else (\n      let frame_uniq = create_thread_nd.frame_uniq in\n      match rvalues_computation parameter_expressions actor s with\n      | ComputationImpossible | ComputationUndefined -> ()\n      | ComputationProduces parameter_values ->\n          let s2 = make_thread_running method_id initial_pc new_tid frame_uniq s in\n          push_stack_parameters_maintains_status new_tid start_pc 0 method_id\n            frame_uniq parameter_var_ids parameter_values s2;\n          (match push_stack_parameters new_tid start_pc 0 method_id frame_uniq parameter_var_ids\n                   parameter_values s2 with\n           | ComputationImpossible | ComputationUndefined -> ()\n           | ComputationProduces s3 ->\n                push_stack_variables_maintains_status new_tid start_pc\n                  (list_len parameter_var_ids) method_id frame_uniq local_variable_initializers s3;\n                (match push_stack_variables new_tid start_pc (list_len parameter_var_ids) method_id frame_uniq\n                         local_variable_initializers s3 with\n                 | ComputationImpossible | ComputationUndefined -> ()\n                 | ComputationProduces s4 ->\n                     (match optional_result with\n                      | None -> ()\n                      | Some result ->\n                         let new_tid_value = ObjectValuePrimitive (PrimitiveBoxThreadId new_tid) in\n                         update_expression_maintains_status result actor start_pc\n                           (list_len parameter_var_ids + list_len local_variable_initializers) bypassing_write_buffer\n                           new_tid_value s4)))\n    )\n  )\n\n#pop-options\n#push-options \"--z3rlimit 10\"\n\nlet method_call_statement_computation_maintains_status\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (method_id: method_id_t)\n  (return_pc: pc_t)\n  (parameter_var_ids: list var_id_t)\n  (parameter_expressions: list expression_t)\n  (local_variable_initializers: list initializer_t)\n  (stack_overflow: bool)\n  (s: Armada.State.t)\n  : Lemma (ensures  (match method_call_statement_computation actor nd start_pc method_id return_pc parameter_var_ids\n                             parameter_expressions local_variable_initializers stack_overflow s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' ->\n                           (s'.threads actor).status = (s.threads actor).status\n                         /\\ (s'.threads actor).pc = (s.threads actor).pc\n                         /\\ (forall other_actor. other_actor <> actor ==> s'.threads other_actor == s.threads other_actor)\n                         /\\ s'.stop_reason = (if stack_overflow then StopReasonStackOverflow else s.stop_reason))) =\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract method_call_nd_t) then\n    ()\n  else (\n    let method_call_nd: method_call_nd_t = ObjectValueAbstract?.value (Cons?.hd nd) in\n    let frame_uniq = method_call_nd.frame_uniq in\n    match rvalues_computation parameter_expressions actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces parameter_values ->\n        let s2 = push_stack_frame actor method_id return_pc frame_uniq s in\n        push_stack_parameters_maintains_status actor start_pc 0\n          method_id frame_uniq parameter_var_ids parameter_values s2;\n        (match push_stack_parameters actor start_pc 0 method_id frame_uniq parameter_var_ids parameter_values s2 with\n         | ComputationImpossible | ComputationUndefined -> ()\n         | ComputationProduces s3 ->\n             push_stack_variables_maintains_status actor start_pc\n               (list_len parameter_var_ids) method_id frame_uniq\n               local_variable_initializers s3)\n  )\n\nlet return_statement_computation_maintains_status\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (end_pc: option pc_t)\n  (method_id: method_id_t)\n  (bypassing_write_buffer: bool)\n  (output_dsts: list expression_t)\n  (output_srcs: list expression_t)\n  (s: Armada.State.t)\n  : Lemma (ensures  (match return_statement_computation actor nd start_pc end_pc method_id bypassing_write_buffer\n                             output_dsts output_srcs s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> status_unchanged actor s s')) =\n  let thread = s.threads actor in\n  if   Cons? nd\n     || eqb thread.stack []\n     || thread.top.method_id <> method_id\n     || end_pc <> Some (Cons?.hd thread.stack).return_pc then\n    ()\n  else (\n    match rvalues_computation output_srcs actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces output_values ->\n        (match pop_stack_variables actor method_id thread.top.frame_uniq thread.top.local_variables s.mem with\n         | ComputationImpossible | ComputationUndefined -> ()\n         | ComputationProduces mem' ->\n             let s2 = pop_stack_frame actor mem' s in\n             update_expressions_maintains_status output_dsts actor\n               start_pc 0 bypassing_write_buffer output_values s2)\n  )\n\nlet terminate_thread_statement_computation_maintains_status\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (method_id: method_id_t)\n  (s: Armada.State.t)\n  : Lemma (ensures  (match terminate_thread_statement_computation actor nd start_pc method_id s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' ->\n                           s'.stop_reason = s.stop_reason\n                         /\\ ThreadStatusJoinable? (s'.threads actor).status\n                         /\\ (forall other_actor. other_actor <> actor ==> s'.threads other_actor == s.threads other_actor))) =\n  ()\n\nlet terminate_process_statement_computation_maintains_status\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (method_id: method_id_t)\n  (s: Armada.State.t)\n  : Lemma (ensures  (match terminate_process_statement_computation actor nd start_pc method_id s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' ->\n                          StopReasonTerminated? s'.stop_reason\n                        /\\ (forall other_actor. other_actor <> actor ==> s'.threads other_actor == s.threads other_actor))) =\n  ()\n\nlet join_statement_computation_maintains_status\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (join_tid: expression_t)\n  (s: Armada.State.t)\n  : Lemma (ensures  (match join_statement_computation actor nd start_pc join_tid s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' ->\n                            s'.stop_reason = s.stop_reason\n                         /\\ (ThreadStatusRunning? (s.threads actor).status ==>\n                              (s'.threads actor).status = (s.threads actor).status\n                            /\\ (s'.threads actor).pc = (s.threads actor).pc))) =\n  ()\n\nlet alloc_successful_statement_computation_maintains_status\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (zero_initialized: bool)\n  (bypassing_write_buffer: bool)\n  (result: expression_t)\n  (allocation_td: object_td_t)\n  (count: expression_t)\n  (s: Armada.State.t)\n  : Lemma (ensures  (match alloc_successful_statement_computation actor nd start_pc zero_initialized\n                             bypassing_write_buffer result allocation_td count s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> status_unchanged actor s s')) =\n  let cs' = alloc_successful_statement_computation actor nd start_pc zero_initialized bypassing_write_buffer result\n              allocation_td count s in\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract root_id_uniquifier_t)\n     || neqb (expression_to_td count) (ObjectTDAbstract nat)\n     || neqb (expression_to_td result) (ObjectTDPrimitive PrimitiveTDPointer) then\n    ()\n  else (\n    match rvalue_computation count actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces count_value ->\n        let sz = ObjectValueAbstract?.value count_value in\n        let array_td = ObjectTDArray allocation_td sz in\n        let uniq = ObjectValueAbstract?.value (Cons?.hd nd) in\n        let root_id = RootIdAllocation uniq in\n        (match s.mem root_id with\n         | RootAllocated allocated freed storage ->\n             if   allocated\n                || freed\n                || neqb (object_storage_to_td storage) array_td\n                || not (is_storage_ready_for_allocation storage)\n                || (not zero_initialized && not (object_storage_arbitrarily_initialized_correctly storage))\n                || (zero_initialized && not (is_storage_zero_filled storage)) then\n               ()\n             else (\n               let s' = mark_allocation_root_allocated uniq storage s in\n               let p = ObjectValuePrimitive (PrimitiveBoxPointer (PointerIndex (PointerRoot root_id) 0)) in\n               update_expression_maintains_status result actor start_pc 0\n                 bypassing_write_buffer p s'\n             )\n         | _ -> ())\n  )\n\nlet alloc_returning_null_statement_computation_maintains_status\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (bypassing_write_buffer: bool)\n  (result: expression_t)\n  (count: expression_t)\n  (s: Armada.State.t)\n  : Lemma (ensures  (match alloc_returning_null_statement_computation actor nd start_pc bypassing_write_buffer\n                             result count s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> status_unchanged actor s s')) =\n  let cs' = alloc_returning_null_statement_computation actor nd start_pc bypassing_write_buffer\n              result count s in\n  if   Cons? nd\n     || neqb (expression_to_td count) (ObjectTDAbstract nat)\n     || neqb (expression_to_td result) (ObjectTDPrimitive PrimitiveTDPointer) then\n    ()\n  else (\n    match rvalue_computation count actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces _ ->\n        let p = ObjectValuePrimitive (PrimitiveBoxPointer PointerNull) in\n        update_expression_maintains_status result actor start_pc 0\n          bypassing_write_buffer p s\n  )\n\nlet dealloc_statement_computation_maintains_status\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (ptr: expression_t)\n  (s: Armada.State.t)\n  : Lemma (ensures  (match dealloc_statement_computation actor nd start_pc ptr s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> status_unchanged actor s s')) =\n  ()\n\nlet somehow_statement_computation_maintains_status\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (undefined_unless_cond: expression_t)\n  (bypassing_write_buffer: bool)\n  (modifies_clauses: list expression_t)\n  (ensures_cond: expression_t)\n  (s: Armada.State.t)\n  : Lemma (ensures  (match somehow_statement_computation actor nd start_pc undefined_unless_cond\n                             bypassing_write_buffer modifies_clauses ensures_cond s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> status_unchanged actor s s')) =\n  let cs' = somehow_statement_computation actor nd start_pc undefined_unless_cond bypassing_write_buffer\n              modifies_clauses ensures_cond s in\n  if   neqb (expression_to_td undefined_unless_cond) (ObjectTDPrimitive PrimitiveTDBool)\n     || neqb (expression_to_td ensures_cond) (ObjectTDPrimitive PrimitiveTDBool) then\n    ()\n  else (\n    match rvalue_computation undefined_unless_cond actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces undefined_unless_value ->\n        let undefined_unless_bool = PrimitiveBoxBool?.b (ObjectValuePrimitive?.value undefined_unless_value) in\n        if not undefined_unless_bool then\n          ()\n        else\n          update_expressions_maintains_status modifies_clauses actor start_pc 0\n            bypassing_write_buffer nd s\n  )\n\nlet fence_statement_computation_maintains_status\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (s: Armada.State.t)\n  : Lemma (ensures  (match fence_statement_computation actor nd start_pc s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> status_unchanged actor s s')) =\n  ()\n\nlet external_method_start_statement_computation_maintains_status\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (await_cond: expression_t)\n  (undefined_unless_cond: expression_t)\n  (bypassing_write_buffer: bool)\n  (modifies_clauses: list expression_t)\n  (reads_clauses: list (var_id_t * expression_t))\n  (s: Armada.State.t)\n  : Lemma (ensures  (match external_method_start_statement_computation actor nd start_pc await_cond\n                             undefined_unless_cond bypassing_write_buffer modifies_clauses reads_clauses s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> status_unchanged actor s s')) =\n  let cs' = external_method_start_statement_computation actor nd start_pc await_cond undefined_unless_cond\n              bypassing_write_buffer modifies_clauses reads_clauses s in\n  if   neqb (expression_to_td await_cond) (ObjectTDPrimitive PrimitiveTDBool)\n     || neqb (expression_to_td undefined_unless_cond) (ObjectTDPrimitive PrimitiveTDBool)\n     || list_len modifies_clauses <> list_len nd then\n    ()\n  else (\n    match rvalue_computation await_cond actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces await_value ->\n        let await_bool = PrimitiveBoxBool?.b (ObjectValuePrimitive?.value await_value) in\n        if not await_bool then\n          ()\n        else (\n          match rvalue_computation undefined_unless_cond actor s with\n          | ComputationImpossible | ComputationUndefined -> ()\n          | ComputationProduces undefined_unless_value ->\n              let undefined_unless_bool = PrimitiveBoxBool?.b (ObjectValuePrimitive?.value await_value) in\n              if not undefined_unless_bool then\n                ()\n              else (\n                update_expressions_maintains_status modifies_clauses\n                  actor start_pc 0 bypassing_write_buffer nd s;\n                match update_expressions modifies_clauses actor start_pc 0 bypassing_write_buffer nd s with\n                | ComputationImpossible | ComputationUndefined -> ()\n                | ComputationProduces s' ->\n                    external_method_take_snapshot_maintains_status\n                      actor start_pc (list_len modifies_clauses) bypassing_write_buffer reads_clauses s'\n              )\n        )\n  )\n\nlet external_method_middle_statement_computation_maintains_status\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (bypassing_write_buffer: bool)\n  (modifies_clauses: list expression_t)\n  (reads_clauses: list (var_id_t * expression_t))\n  (s: Armada.State.t)\n  : Lemma (ensures  (match external_method_middle_statement_computation actor nd start_pc bypassing_write_buffer\n                             modifies_clauses reads_clauses s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> status_unchanged actor s s')) =\n  let cs' = external_method_middle_statement_computation actor nd start_pc bypassing_write_buffer\n              modifies_clauses reads_clauses s in\n  match external_method_check_snapshot_computation actor reads_clauses s with\n  | ComputationImpossible | ComputationUndefined -> ()\n  | ComputationProduces _ ->\n      update_expressions_maintains_status modifies_clauses actor start_pc 0\n        bypassing_write_buffer nd s;\n      (match update_expressions modifies_clauses actor start_pc 0 bypassing_write_buffer nd s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces s' ->\n           external_method_take_snapshot_maintains_status\n             actor start_pc (list_len modifies_clauses) bypassing_write_buffer reads_clauses s')\n\nlet external_method_end_statement_computation_maintains_status\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (ensures_cond: expression_t)\n  (logs_clauses: list expression_t)\n  (s: Armada.State.t)\n  : Lemma (ensures  (match external_method_end_statement_computation actor nd start_pc ensures_cond logs_clauses s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> status_unchanged actor s s')) =\n  let cs' = external_method_end_statement_computation actor nd start_pc ensures_cond logs_clauses s in\n  if   Cons? nd\n     || neqb (expression_to_td ensures_cond) (ObjectTDPrimitive PrimitiveTDBool) then\n    ()\n  else (\n    match rvalue_computation ensures_cond actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces ensures_value ->\n        let ensures_bool = PrimitiveBoxBool?.b (ObjectValuePrimitive?.value ensures_value) in\n        log_expressions_computation_maintains_status actor logs_clauses s\n  )\n\nlet executing_statement_changes_status_depending_on_statement\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (end_pc: option pc_t)\n  (statement: Armada.Statement.t)\n  (s: Armada.State.t)\n  : Lemma (requires   NotStopped? s.stop_reason\n                    /\\ ThreadStatusRunning? (s.threads actor).status)\n          (ensures  (match statement_computation actor nd start_pc end_pc statement s with\n                     | ComputationProduces s' ->\n                         (match statement with\n                          | AssertFalseStatement _ -> StopReasonAssertionFailure? s'.stop_reason\n                          | TerminateProcessStatement _ -> StopReasonTerminated? s'.stop_reason\n                          | TerminateThreadStatement _ ->\n                                NotStopped? s'.stop_reason\n                             && ThreadStatusJoinable? (s'.threads actor).status\n                          | MethodCallStatement _ _ _ _ _ true (* stack overflow *) ->\n                              StopReasonStackOverflow? s'.stop_reason\n                          | _ ->\n                                 NotStopped? s'.stop_reason\n                              && ThreadStatusRunning? (s'.threads actor).status\n                              && (s'.threads actor).pc = (s.threads actor).pc)\n                     | _ -> True)) =\n  match statement with\n  | AssumeExpressionStatement exp ->\n      assume_expression_statement_computation_maintains_status actor nd start_pc exp s\n  | AssumePredicateStatement pred ->\n      assume_predicate_statement_computation_maintains_status actor nd start_pc pred s\n  | AssertTrueStatement exp ->\n      assert_true_statement_computation_maintains_status actor nd start_pc exp s\n  | AssertFalseStatement exp ->\n      assert_false_statement_computation_maintains_status actor nd start_pc exp s\n  | ConditionalJumpStatement cond ->\n      conditional_jump_statement_computation_maintains_status actor nd start_pc cond s\n  | UnconditionalJumpStatement ->\n      unconditional_jump_statement_computation_maintains_status actor nd start_pc s\n  | UpdateStatement bypassing_write_buffer dst src ->\n      update_statement_computation_maintains_status actor nd start_pc bypassing_write_buffer dst src s\n  | NondeterministicUpdateStatement bypassing_write_buffer dst ->\n      nondeterministic_update_statement_computation_maintains_status actor nd start_pc bypassing_write_buffer dst s\n  | PropagateWriteMessageStatement ->\n      propagate_write_message_statement_computation_maintains_status actor nd s\n  | CompareAndSwapStatement target old_val new_val bypassing_write_buffer optional_result ->\n      compare_and_swap_statement_computation_maintains_status actor nd start_pc target old_val new_val\n        bypassing_write_buffer optional_result s\n  | AtomicExchangeStatement old_val target new_val ->\n      atomic_exchange_statement_computation_maintains_status actor nd start_pc old_val target new_val s\n  | CreateThreadStatement method_id initial_pc bypassing_write_buffer optional_result parameter_var_ids\n                          parameter_expressions local_variable_initializers ->\n      create_thread_statement_computation_maintains_status actor nd start_pc method_id initial_pc\n        bypassing_write_buffer optional_result parameter_var_ids parameter_expressions local_variable_initializers s\n  | MethodCallStatement method_id return_pc parameter_var_ids parameter_expressions local_variable_initializers\n                          stack_overflow ->\n      method_call_statement_computation_maintains_status actor nd start_pc method_id return_pc parameter_var_ids\n        parameter_expressions local_variable_initializers stack_overflow s\n  | ReturnStatement method_id bypassing_write_buffer output_dsts output_srcs ->\n      return_statement_computation_maintains_status actor nd start_pc end_pc method_id bypassing_write_buffer\n        output_dsts output_srcs s\n  | TerminateThreadStatement method_id ->\n      terminate_thread_statement_computation_maintains_status actor nd\n        start_pc method_id s\n  | TerminateProcessStatement method_id ->\n      terminate_process_statement_computation_maintains_status actor nd\n        start_pc method_id s\n  | JoinStatement join_tid ->\n      join_statement_computation_maintains_status actor nd start_pc join_tid s\n  | MallocSuccessfulStatement bypassing_write_buffer result allocation_td count ->\n      alloc_successful_statement_computation_maintains_status actor nd start_pc false bypassing_write_buffer result\n        allocation_td count s\n  | MallocReturningNullStatement bypassing_write_buffer result count ->\n      alloc_returning_null_statement_computation_maintains_status actor nd start_pc bypassing_write_buffer\n        result count s\n  | CallocSuccessfulStatement bypassing_write_buffer result allocation_td count ->\n      alloc_successful_statement_computation_maintains_status actor nd start_pc true bypassing_write_buffer result\n        allocation_td count s\n  | CallocReturningNullStatement bypassing_write_buffer result count ->\n      alloc_returning_null_statement_computation_maintains_status actor nd\n        start_pc bypassing_write_buffer result count s\n  | DeallocStatement ptr ->\n      dealloc_statement_computation_maintains_status actor nd start_pc ptr s\n  | SomehowStatement undefined_unless_cond bypassing_write_buffer modifies_clauses ensures_cond ->\n      somehow_statement_computation_maintains_status actor nd\n        start_pc undefined_unless_cond bypassing_write_buffer modifies_clauses ensures_cond s\n  | FenceStatement ->\n      fence_statement_computation_maintains_status actor nd start_pc s\n  | ExternalMethodStartStatement await_cond undefined_unless_cond bypassing_write_buffer\n                                 modifies_clauses reads_clauses ->\n      external_method_start_statement_computation_maintains_status actor nd start_pc await_cond undefined_unless_cond\n        bypassing_write_buffer modifies_clauses reads_clauses s\n  | ExternalMethodMiddleStatement bypassing_write_buffer modifies_clauses reads_clauses ->\n      external_method_middle_statement_computation_maintains_status actor nd start_pc bypassing_write_buffer\n        modifies_clauses reads_clauses s\n  | ExternalMethodEndStatement ensures_cond logs_clauses ->\n      external_method_end_statement_computation_maintains_status actor nd start_pc ensures_cond logs_clauses s\n\nlet most_statement_types_dont_affect_other_threads\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (end_pc: option pc_t)\n  (statement: Armada.Statement.t)\n  (s: Armada.State.t)\n  : Lemma (ensures\n      (match statement_computation actor nd start_pc end_pc statement s with\n       | ComputationProduces s' ->\n           not (  CreateThreadStatement? statement\n                || JoinStatement? statement\n                || PropagateWriteMessageStatement? statement) ==>\n           (forall other_actor. other_actor <> actor ==> s'.threads other_actor == s.threads other_actor)\n       | _ -> True)) =\n  match statement with\n  | AssumeExpressionStatement exp ->\n      assume_expression_statement_computation_maintains_status actor nd start_pc exp s\n  | AssumePredicateStatement pred ->\n      assume_predicate_statement_computation_maintains_status actor nd start_pc pred s\n  | AssertTrueStatement exp ->\n      assert_true_statement_computation_maintains_status actor nd start_pc exp s\n  | AssertFalseStatement exp ->\n      assert_false_statement_computation_maintains_status actor nd start_pc exp s\n  | ConditionalJumpStatement cond ->\n      conditional_jump_statement_computation_maintains_status actor nd start_pc cond s\n  | UnconditionalJumpStatement ->\n      unconditional_jump_statement_computation_maintains_status actor nd start_pc s\n  | UpdateStatement bypassing_write_buffer dst src ->\n      update_statement_computation_maintains_status actor nd start_pc bypassing_write_buffer dst src s\n  | NondeterministicUpdateStatement bypassing_write_buffer dst ->\n      nondeterministic_update_statement_computation_maintains_status actor nd start_pc bypassing_write_buffer dst s\n  | PropagateWriteMessageStatement ->\n      propagate_write_message_statement_computation_maintains_status actor nd s\n  | CompareAndSwapStatement target old_val new_val bypassing_write_buffer optional_result ->\n      compare_and_swap_statement_computation_maintains_status actor nd start_pc target old_val new_val\n        bypassing_write_buffer optional_result s\n  | AtomicExchangeStatement old_val target new_val ->\n      atomic_exchange_statement_computation_maintains_status actor nd start_pc old_val target new_val s\n  | CreateThreadStatement method_id initial_pc bypassing_write_buffer optional_result parameter_var_ids\n                          parameter_expressions local_variable_initializers ->\n      create_thread_statement_computation_maintains_status actor nd start_pc method_id initial_pc\n        bypassing_write_buffer optional_result parameter_var_ids parameter_expressions local_variable_initializers s\n  | MethodCallStatement method_id return_pc parameter_var_ids parameter_expressions local_variable_initializers\n                          stack_overflow ->\n      method_call_statement_computation_maintains_status actor nd start_pc method_id return_pc parameter_var_ids\n        parameter_expressions local_variable_initializers stack_overflow s\n  | ReturnStatement method_id bypassing_write_buffer output_dsts output_srcs ->\n      return_statement_computation_maintains_status actor nd start_pc end_pc method_id bypassing_write_buffer\n        output_dsts output_srcs s\n  | TerminateThreadStatement method_id ->\n      terminate_thread_statement_computation_maintains_status actor nd\n        start_pc method_id s\n  | TerminateProcessStatement method_id ->\n      terminate_process_statement_computation_maintains_status actor nd\n        start_pc method_id s\n  | JoinStatement join_tid ->\n      join_statement_computation_maintains_status actor nd start_pc join_tid s\n  | MallocSuccessfulStatement bypassing_write_buffer result allocation_td count ->\n      alloc_successful_statement_computation_maintains_status actor nd start_pc false bypassing_write_buffer result\n        allocation_td count s\n  | MallocReturningNullStatement bypassing_write_buffer result count ->\n      alloc_returning_null_statement_computation_maintains_status actor nd start_pc bypassing_write_buffer\n        result count s\n  | CallocSuccessfulStatement bypassing_write_buffer result allocation_td count ->\n      alloc_successful_statement_computation_maintains_status actor nd start_pc true bypassing_write_buffer result\n        allocation_td count s\n  | CallocReturningNullStatement bypassing_write_buffer result count ->\n      alloc_returning_null_statement_computation_maintains_status actor nd\n        start_pc bypassing_write_buffer result count s\n  | DeallocStatement ptr ->\n      dealloc_statement_computation_maintains_status actor nd start_pc ptr s\n  | SomehowStatement undefined_unless_cond bypassing_write_buffer modifies_clauses ensures_cond ->\n      somehow_statement_computation_maintains_status actor nd\n        start_pc undefined_unless_cond bypassing_write_buffer modifies_clauses ensures_cond s\n  | FenceStatement ->\n      fence_statement_computation_maintains_status actor nd start_pc s\n  | ExternalMethodStartStatement await_cond undefined_unless_cond bypassing_write_buffer\n                                 modifies_clauses reads_clauses ->\n      external_method_start_statement_computation_maintains_status actor nd start_pc await_cond undefined_unless_cond\n        bypassing_write_buffer modifies_clauses reads_clauses s\n  | ExternalMethodMiddleStatement bypassing_write_buffer modifies_clauses reads_clauses ->\n      external_method_middle_statement_computation_maintains_status actor nd start_pc bypassing_write_buffer\n        modifies_clauses reads_clauses s\n  | ExternalMethodEndStatement ensures_cond logs_clauses ->\n      external_method_end_statement_computation_maintains_status actor nd start_pc ensures_cond logs_clauses s\n\nlet statement_effects_on_other_threads\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (end_pc: option pc_t)\n  (statement: Armada.Statement.t)\n  (s: Armada.State.t)\n  : Lemma (ensures\n      (match statement_computation actor nd start_pc end_pc statement s with\n       | ComputationProduces s' ->\n           (match statement with\n            | CreateThreadStatement _ initial_pc _ _ _ _ _ ->\n                let create_thread_nd: create_thread_nd_t =\n                  ObjectValueAbstract?.value (Cons?.hd nd) in\n                let new_tid = create_thread_nd.new_tid in\n                if new_tid = 0 then\n                  (forall other_actor. other_actor <> actor ==> s'.threads other_actor == s.threads other_actor)\n                else (\n                    (s'.threads new_tid).pc = initial_pc\n                  /\\ (forall other_actor. other_actor <> actor /\\ other_actor <> new_tid ==>\n                                    s'.threads other_actor == s.threads other_actor)\n                )\n            | JoinStatement join_tid ->\n                (match rvalue_computation join_tid actor s with\n                 | ComputationProduces tid_value ->\n                     let other_tid = PrimitiveBoxThreadId?.tid\n                                     (ObjectValuePrimitive?.value tid_value) in\n                       (forall other_actor. other_actor <> actor /\\ other_actor <> other_tid ==>\n                                       s'.threads other_actor == s.threads other_actor)\n                     /\\ (ThreadStatusPostJoin? (s'.threads other_tid).status)\n                 | _ -> False)\n            | PropagateWriteMessageStatement ->\n                let receiver_tid: tid_t = ObjectValueAbstract?.value (Cons?.hd nd) in\n                  (forall other_actor. other_actor <> actor /\\ other_actor <> receiver_tid ==>\n                                  s'.threads other_actor == s.threads other_actor)\n                /\\ (s'.threads receiver_tid).status = (s.threads receiver_tid).status\n                /\\ (s'.threads receiver_tid).pc = (s.threads receiver_tid).pc\n            | _ -> (forall other_actor. other_actor <> actor ==>\n                                  s'.threads other_actor == s.threads other_actor))\n       | _ -> True)) =\n  match statement with\n  | AssumeExpressionStatement exp ->\n      assume_expression_statement_computation_maintains_status actor nd start_pc exp s\n  | AssumePredicateStatement pred ->\n      assume_predicate_statement_computation_maintains_status actor nd start_pc pred s\n  | AssertTrueStatement exp ->\n      assert_true_statement_computation_maintains_status actor nd start_pc exp s\n  | AssertFalseStatement exp ->\n      assert_false_statement_computation_maintains_status actor nd start_pc exp s\n  | ConditionalJumpStatement cond ->\n      conditional_jump_statement_computation_maintains_status actor nd start_pc cond s\n  | UnconditionalJumpStatement ->\n      unconditional_jump_statement_computation_maintains_status actor nd start_pc s\n  | UpdateStatement bypassing_write_buffer dst src ->\n      update_statement_computation_maintains_status actor nd start_pc bypassing_write_buffer dst src s\n  | NondeterministicUpdateStatement bypassing_write_buffer dst ->\n      nondeterministic_update_statement_computation_maintains_status actor nd start_pc bypassing_write_buffer dst s\n  | PropagateWriteMessageStatement ->\n      propagate_write_message_statement_computation_maintains_status actor nd s\n  | CompareAndSwapStatement target old_val new_val bypassing_write_buffer optional_result ->\n      compare_and_swap_statement_computation_maintains_status actor nd start_pc target old_val new_val\n        bypassing_write_buffer optional_result s\n  | AtomicExchangeStatement old_val target new_val ->\n      atomic_exchange_statement_computation_maintains_status actor nd start_pc old_val target new_val s\n  | CreateThreadStatement method_id initial_pc bypassing_write_buffer optional_result parameter_var_ids\n                          parameter_expressions local_variable_initializers ->\n      create_thread_statement_computation_maintains_status actor nd start_pc method_id initial_pc\n        bypassing_write_buffer optional_result parameter_var_ids parameter_expressions local_variable_initializers s\n  | MethodCallStatement method_id return_pc parameter_var_ids parameter_expressions local_variable_initializers\n                          stack_overflow ->\n      method_call_statement_computation_maintains_status actor nd start_pc method_id return_pc parameter_var_ids\n        parameter_expressions local_variable_initializers stack_overflow s\n  | ReturnStatement method_id bypassing_write_buffer output_dsts output_srcs ->\n      return_statement_computation_maintains_status actor nd start_pc end_pc method_id bypassing_write_buffer\n        output_dsts output_srcs s\n  | TerminateThreadStatement method_id ->\n      terminate_thread_statement_computation_maintains_status actor nd\n        start_pc method_id s\n  | TerminateProcessStatement method_id ->\n      terminate_process_statement_computation_maintains_status actor nd\n        start_pc method_id s\n  | JoinStatement join_tid ->\n      join_statement_computation_maintains_status actor nd start_pc join_tid s\n  | MallocSuccessfulStatement bypassing_write_buffer result allocation_td count ->\n      alloc_successful_statement_computation_maintains_status actor nd start_pc false bypassing_write_buffer result\n        allocation_td count s\n  | MallocReturningNullStatement bypassing_write_buffer result count ->\n      alloc_returning_null_statement_computation_maintains_status actor nd start_pc bypassing_write_buffer\n        result count s\n  | CallocSuccessfulStatement bypassing_write_buffer result allocation_td count ->\n      alloc_successful_statement_computation_maintains_status actor nd start_pc true bypassing_write_buffer result\n        allocation_td count s\n  | CallocReturningNullStatement bypassing_write_buffer result count ->\n      alloc_returning_null_statement_computation_maintains_status actor nd\n        start_pc bypassing_write_buffer result count s\n  | DeallocStatement ptr ->\n      dealloc_statement_computation_maintains_status actor nd start_pc ptr s\n  | SomehowStatement undefined_unless_cond bypassing_write_buffer modifies_clauses ensures_cond ->\n      somehow_statement_computation_maintains_status actor nd\n        start_pc undefined_unless_cond bypassing_write_buffer modifies_clauses ensures_cond s\n  | FenceStatement ->\n      fence_statement_computation_maintains_status actor nd start_pc s\n  | ExternalMethodStartStatement await_cond undefined_unless_cond bypassing_write_buffer\n                                 modifies_clauses reads_clauses ->\n      external_method_start_statement_computation_maintains_status actor nd start_pc await_cond undefined_unless_cond\n        bypassing_write_buffer modifies_clauses reads_clauses s\n  | ExternalMethodMiddleStatement bypassing_write_buffer modifies_clauses reads_clauses ->\n      external_method_middle_statement_computation_maintains_status actor nd start_pc bypassing_write_buffer\n        modifies_clauses reads_clauses s\n  | ExternalMethodEndStatement ensures_cond logs_clauses ->\n      external_method_end_statement_computation_maintains_status actor nd start_pc ensures_cond logs_clauses s\n\nlet executing_step_changes_status_depending_on_statement\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (step: Armada.Step.t)\n  (s: Armada.State.t)\n  : Lemma (ensures\n      (match step_computation actor starts_atomic_block ends_atomic_block step s with\n       | Some s' ->\n           if not step.action.ok then\n             eqb s' ({ s with stop_reason = StopReasonUndefinedBehavior })\n           else\n             (match step.action.program_statement.statement with\n              | AssertFalseStatement _ -> StopReasonAssertionFailure? s'.stop_reason\n              | TerminateProcessStatement _ -> StopReasonTerminated? s'.stop_reason\n              | TerminateThreadStatement _ ->\n                     NotStopped? s'.stop_reason\n                  && ThreadStatusJoinable? (s'.threads actor).status\n              | MethodCallStatement _ _ _ _ _ true (* stack overflow *) ->\n                  StopReasonStackOverflow? s'.stop_reason\n              | _ ->    NotStopped? s'.stop_reason\n                    && ThreadStatusRunning? (s'.threads actor).status\n                    && (s'.threads actor).pc =\n                          (match step.action.program_statement.end_pc with\n                           | Some pc -> pc\n                           | None -> (s.threads actor).pc))\n       | None -> True)) =\n  match step_computation actor starts_atomic_block ends_atomic_block step s with\n  | Some s' ->\n      if not step.action.ok then\n        ()\n      else\n        executing_statement_changes_status_depending_on_statement actor step.nd (s.threads actor).pc\n          step.action.program_statement.end_pc step.action.program_statement.statement s\n  | None -> ()\n\nlet step_effects_on_other_threads\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (step: Armada.Step.t)\n  (s: Armada.State.t)\n  : Lemma (ensures\n      (match step_computation actor starts_atomic_block ends_atomic_block step s with\n       | Some s' ->\n           if not step.action.ok then\n             eqb s' ({ s with stop_reason = StopReasonUndefinedBehavior })\n           else\n             (match step.action.program_statement.statement with\n              | CreateThreadStatement _ initial_pc _ _ _ _ _ ->\n                  let create_thread_nd: create_thread_nd_t =\n                    ObjectValueAbstract?.value (Cons?.hd step.nd) in\n                  let new_tid = create_thread_nd.new_tid in\n                  if new_tid = 0 then\n                     (forall other_actor. other_actor <> actor ==> s'.threads other_actor == s.threads other_actor)\n                  else (\n                      (s'.threads new_tid).pc = initial_pc\n                    /\\ (forall other_actor. other_actor <> actor /\\ other_actor <> new_tid ==>\n                                      s'.threads other_actor == s.threads other_actor)\n                  )\n              | JoinStatement join_tid ->\n                  (match rvalue_computation join_tid actor s with\n                   | ComputationProduces tid_value ->\n                       let other_tid = PrimitiveBoxThreadId?.tid\n                                       (ObjectValuePrimitive?.value tid_value) in\n                         (forall other_actor. other_actor <> actor /\\ other_actor <> other_tid ==>\n                                         s'.threads other_actor == s.threads other_actor)\n                       /\\ (ThreadStatusPostJoin? (s'.threads other_tid).status)\n                   | _ -> False)\n              | PropagateWriteMessageStatement ->\n                  let receiver_tid: tid_t = ObjectValueAbstract?.value (Cons?.hd step.nd) in\n                    (forall other_actor. other_actor <> actor /\\ other_actor <> receiver_tid ==>\n                                    s'.threads other_actor == s.threads other_actor)\n                  /\\ (s'.threads receiver_tid).status = (s.threads receiver_tid).status\n                  /\\ (s'.threads receiver_tid).pc = (s.threads receiver_tid).pc\n              | _ -> (forall other_actor. other_actor <> actor ==>\n                                    s'.threads other_actor == s.threads other_actor))\n       | None -> True)) =\n  match step_computation actor starts_atomic_block ends_atomic_block step s with\n  | Some s' ->\n      if not step.action.ok then\n        ()\n      else\n        statement_effects_on_other_threads actor step.nd (s.threads actor).pc\n          step.action.program_statement.end_pc step.action.program_statement.statement s\n  | None -> ()\n"
  },
  {
    "path": "experimental/lib/Strategies.ArmadaStatement.Status.fsti",
    "content": "module Strategies.ArmadaStatement.Status\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Computation\nopen Armada.Expression\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Pointer\nopen Armada.State\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Transition\nopen Armada.Type\nopen FStar.Sequence.Base\nopen Spec.List\nopen Spec.Logic\nopen Spec.Ubool\nopen Strategies.ArmadaStatement\nopen Strategies.PCRelation\nopen Strategies.Semantics.Armada\n\nlet status_unchanged (actor: tid_t) (s: Armada.State.t) (s': Armada.State.t) : Type0 =\n      s'.stop_reason = s.stop_reason\n   /\\ (s'.threads actor).status = (s.threads actor).status\n   /\\ (s'.threads actor).pc = (s.threads actor).pc\n   /\\ (forall other_actor. other_actor <> actor ==> s'.threads other_actor == s.threads other_actor)\n\nval push_stack_variables_maintains_status\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (initializers: list initializer_t)\n  (s: Armada.State.t)\n  : Lemma (ensures  (match push_stack_variables actor writer_pc writer_expression_number method_id\n                             frame_uniq initializers s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> status_unchanged actor s s'))\n\nval push_stack_parameters_maintains_status\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (var_ids: list var_id_t)\n  (parameters: list object_value_t)\n  (s: Armada.State.t)\n  : Lemma (ensures  (match push_stack_parameters actor writer_pc writer_expression_number method_id frame_uniq\n                             var_ids parameters s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> status_unchanged actor s s'))\n\nval executing_statement_changes_status_depending_on_statement\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (end_pc: option pc_t)\n  (statement: Armada.Statement.t)\n  (s: Armada.State.t)\n  : Lemma (requires   NotStopped? s.stop_reason\n                    /\\ ThreadStatusRunning? (s.threads actor).status)\n          (ensures  (match statement_computation actor nd start_pc end_pc statement s with\n                     | ComputationProduces s' ->\n                         (match statement with\n                          | AssertFalseStatement _ -> StopReasonAssertionFailure? s'.stop_reason\n                          | TerminateProcessStatement _ -> StopReasonTerminated? s'.stop_reason\n                          | TerminateThreadStatement _ ->\n                                NotStopped? s'.stop_reason\n                             && ThreadStatusJoinable? (s'.threads actor).status\n                          | MethodCallStatement _ _ _ _ _ true (* stack overflow *) ->\n                              StopReasonStackOverflow? s'.stop_reason\n                          | _ ->\n                                 NotStopped? s'.stop_reason\n                              && ThreadStatusRunning? (s'.threads actor).status\n                              && (s'.threads actor).pc = (s.threads actor).pc)\n                     | _ -> True))\n\nval most_statement_types_dont_affect_other_threads\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (end_pc: option pc_t)\n  (statement: Armada.Statement.t)\n  (s: Armada.State.t)\n  : Lemma (ensures\n      (match statement_computation actor nd start_pc end_pc statement s with\n       | ComputationProduces s' ->\n           not (  CreateThreadStatement? statement\n                || JoinStatement? statement\n                || PropagateWriteMessageStatement? statement) ==>\n           (forall other_actor. other_actor <> actor ==> s'.threads other_actor == s.threads other_actor)\n       | _ -> True))\n\nval statement_effects_on_other_threads\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (end_pc: option pc_t)\n  (statement: Armada.Statement.t)\n  (s: Armada.State.t)\n  : Lemma (ensures\n      (match statement_computation actor nd start_pc end_pc statement s with\n       | ComputationProduces s' ->\n           (match statement with\n            | CreateThreadStatement _ initial_pc _ _ _ _ _ ->\n                let create_thread_nd: create_thread_nd_t =\n                  ObjectValueAbstract?.value (Cons?.hd nd) in\n                let new_tid = create_thread_nd.new_tid in\n                if new_tid = 0 then\n                  (forall other_actor. other_actor <> actor ==> s'.threads other_actor == s.threads other_actor)\n                else (\n                    (s'.threads new_tid).pc = initial_pc\n                  /\\ (forall other_actor. other_actor <> actor /\\ other_actor <> new_tid ==>\n                                    s'.threads other_actor == s.threads other_actor)\n                )\n            | JoinStatement join_tid ->\n                (match rvalue_computation join_tid actor s with\n                 | ComputationProduces tid_value ->\n                     let other_tid = PrimitiveBoxThreadId?.tid\n                                     (ObjectValuePrimitive?.value tid_value) in\n                       (forall other_actor. other_actor <> actor /\\ other_actor <> other_tid ==>\n                                       s'.threads other_actor == s.threads other_actor)\n                     /\\ (ThreadStatusPostJoin? (s'.threads other_tid).status)\n                 | _ -> False)\n            | PropagateWriteMessageStatement ->\n                let receiver_tid: tid_t = ObjectValueAbstract?.value (Cons?.hd nd) in\n                  (forall other_actor. other_actor <> actor /\\ other_actor <> receiver_tid ==>\n                                  s'.threads other_actor == s.threads other_actor)\n                /\\ (s'.threads receiver_tid).status = (s.threads receiver_tid).status\n                /\\ (s'.threads receiver_tid).pc = (s.threads receiver_tid).pc\n            | _ -> (forall other_actor. other_actor <> actor ==>\n                                  s'.threads other_actor == s.threads other_actor))\n       | _ -> True))\n\nval executing_step_changes_status_depending_on_statement\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (step: Armada.Step.t)\n  (s: Armada.State.t)\n  : Lemma (ensures\n      (match step_computation actor starts_atomic_block ends_atomic_block step s with\n       | Some s' ->\n           if not step.action.ok then\n             eqb s' ({ s with stop_reason = StopReasonUndefinedBehavior })\n           else\n             (match step.action.program_statement.statement with\n              | AssertFalseStatement _ -> StopReasonAssertionFailure? s'.stop_reason\n              | TerminateProcessStatement _ -> StopReasonTerminated? s'.stop_reason\n              | TerminateThreadStatement _ ->\n                     NotStopped? s'.stop_reason\n                  && ThreadStatusJoinable? (s'.threads actor).status\n              | MethodCallStatement _ _ _ _ _ true (* stack overflow *) ->\n                  StopReasonStackOverflow? s'.stop_reason\n              | _ ->    NotStopped? s'.stop_reason\n                    && ThreadStatusRunning? (s'.threads actor).status\n                    && (s'.threads actor).pc =\n                          (match step.action.program_statement.end_pc with\n                           | Some pc -> pc\n                           | None -> (s.threads actor).pc))\n       | None -> True))\n\nval step_effects_on_other_threads\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (step: Armada.Step.t)\n  (s: Armada.State.t)\n  : Lemma (ensures\n      (match step_computation actor starts_atomic_block ends_atomic_block step s with\n       | Some s' ->\n           if not step.action.ok then\n             eqb s' ({ s with stop_reason = StopReasonUndefinedBehavior })\n           else\n             (match step.action.program_statement.statement with\n              | CreateThreadStatement _ initial_pc _ _ _ _ _ ->\n                  let create_thread_nd: create_thread_nd_t =\n                    ObjectValueAbstract?.value (Cons?.hd step.nd) in\n                  let new_tid = create_thread_nd.new_tid in\n                  if new_tid = 0 then\n                     (forall other_actor. other_actor <> actor ==> s'.threads other_actor == s.threads other_actor)\n                  else (\n                      (s'.threads new_tid).pc = initial_pc\n                    /\\ (forall other_actor. other_actor <> actor /\\ other_actor <> new_tid ==>\n                                      s'.threads other_actor == s.threads other_actor)\n                  )\n              | JoinStatement join_tid ->\n                  (match rvalue_computation join_tid actor s with\n                   | ComputationProduces tid_value ->\n                       let other_tid = PrimitiveBoxThreadId?.tid\n                                       (ObjectValuePrimitive?.value tid_value) in\n                         (forall other_actor. other_actor <> actor /\\ other_actor <> other_tid ==>\n                                         s'.threads other_actor == s.threads other_actor)\n                       /\\ (ThreadStatusPostJoin? (s'.threads other_tid).status)\n                   | _ -> False)\n              | PropagateWriteMessageStatement ->\n                  let receiver_tid: tid_t = ObjectValueAbstract?.value (Cons?.hd step.nd) in\n                    (forall other_actor. other_actor <> actor /\\ other_actor <> receiver_tid ==>\n                                    s'.threads other_actor == s.threads other_actor)\n                  /\\ (s'.threads receiver_tid).status = (s.threads receiver_tid).status\n                  /\\ (s'.threads receiver_tid).pc = (s.threads receiver_tid).pc\n              | _ -> (forall other_actor. other_actor <> actor ==>\n                                    s'.threads other_actor == s.threads other_actor))\n       | None -> True))\n"
  },
  {
    "path": "experimental/lib/Strategies.ArmadaStatement.ThreadState.fst",
    "content": "module Strategies.ArmadaStatement.ThreadState\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Computation\nopen Armada.Expression\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Pointer\nopen Armada.State\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Transition\nopen Armada.Type\nopen FStar.Tactics.V2\nopen Spec.List\nopen Spec.Logic\nopen Spec.Ubool\nopen Strategies.ArmadaStatement\nopen Strategies.ArmadaStatement.Status\nopen Strategies.PCIndices\nopen Strategies.PCRelation\nopen Strategies.Semantics.Armada\nopen Util.ImmutableArray\nopen Util.List\nopen Util.Relation\nopen Util.Tactics\n\ntype thread_state_t =\n  | ThreadStateRunning: thread_state_t\n  | ThreadStateAtPC: (pc: pc_t) -> thread_state_t\n  | ThreadStateNotRunning: (status: thread_status_t) -> thread_state_t\n  | ThreadStateProcessStopped: (stop_reason: stop_reason_t) -> thread_state_t\n\ntype efficient_thread_state_t =\n  | EfficientThreadStateRunning: efficient_thread_state_t\n  | EfficientThreadStateAtPC: (pc: nat) -> efficient_thread_state_t\n  | EfficientThreadStateNotRunning: (status: thread_status_t) -> efficient_thread_state_t\n  | EfficientThreadStateProcessStopped: (stop_reason: stop_reason_t) -> efficient_thread_state_t\n\nlet thread_state_applies (s: Armada.State.t) (actor: tid_t) (ts: thread_state_t) : GTot bool =\n  match ts with\n  | ThreadStateRunning ->\n         NotStopped? s.stop_reason\n      && ThreadStatusRunning? (s.threads actor).status\n  | ThreadStateAtPC pc ->\n         NotStopped? s.stop_reason\n      && ThreadStatusRunning? (s.threads actor).status\n      && (s.threads actor).pc = pc\n  | ThreadStateNotRunning status ->\n         NotStopped? s.stop_reason\n      && (s.threads actor).status = status\n      && not (ThreadStatusRunning? status)\n  | ThreadStateProcessStopped stop_reason ->\n         s.stop_reason = stop_reason\n      && not (NotStopped? stop_reason)\n\nlet action_enabled_in_thread_state (ts: thread_state_t) (action: Armada.Action.t) : GTot bool =\n  match ts with\n  | ThreadStateRunning -> None? action.program_statement.start_pc\n  | ThreadStateAtPC pc ->\n      (match action.program_statement.start_pc with\n       | Some start_pc -> start_pc = pc\n       | None -> true)\n  | ThreadStateNotRunning _ -> false\n  | ThreadStateProcessStopped _ -> false\n\nlet action_ensures_final_thread_state (ts: thread_state_t) (action: Armada.Action.t) : GTot bool =\n  if not action.ok then\n    ts = ThreadStateProcessStopped StopReasonUndefinedBehavior\n  else\n    match action.program_statement.statement with\n    | AssertFalseStatement _ -> ts = ThreadStateProcessStopped StopReasonAssertionFailure\n    | TerminateProcessStatement _ -> ts = ThreadStateProcessStopped StopReasonTerminated\n    | TerminateThreadStatement _ -> ts = ThreadStateNotRunning ThreadStatusJoinable\n    | MethodCallStatement _ _ _ _ _ true (* stack overflow *) -> ts = ThreadStateProcessStopped StopReasonStackOverflow\n    | _ -> (match action.program_statement.end_pc with\n           | Some pc -> ts = ThreadStateAtPC pc || ts = ThreadStateRunning\n           | None -> ts = ThreadStateRunning)\n\nlet action_to_starting_thread_state (action: Armada.Action.t) : GTot thread_state_t =\n  match action.program_statement.start_pc with\n  | Some pc -> ThreadStateAtPC pc\n  | None -> ThreadStateRunning\n\nlet efficient_action_to_starting_thread_state (pc_indices: statement_pc_indices_t) : GTot efficient_thread_state_t =\n  match pc_indices.start_pc_index with\n  | Some pc -> EfficientThreadStateAtPC pc\n  | None -> EfficientThreadStateRunning\n\nlet program_statement_to_ending_thread_state (ps: program_statement_t) : thread_state_t =\n  match ps.statement with\n  | AssertFalseStatement _ -> ThreadStateProcessStopped StopReasonAssertionFailure\n  | TerminateProcessStatement _ -> ThreadStateProcessStopped StopReasonTerminated\n  | TerminateThreadStatement _ -> ThreadStateNotRunning ThreadStatusJoinable\n  | MethodCallStatement _ _ _ _ _ true (* stack overflow *) -> ThreadStateProcessStopped StopReasonStackOverflow\n  | _ -> (match ps.end_pc with\n         | Some pc -> ThreadStateAtPC pc\n         | None -> ThreadStateRunning)\n\nlet action_to_ending_thread_state (action: Armada.Action.t) : thread_state_t =\n  if not action.ok then\n    ThreadStateProcessStopped StopReasonUndefinedBehavior\n  else\n    program_statement_to_ending_thread_state action.program_statement\n\nlet efficient_program_statement_to_ending_thread_state\n  (ps: program_statement_t)\n  (pc_indices: statement_pc_indices_t)\n  : efficient_thread_state_t =\n  match ps.statement with\n  | AssertFalseStatement _ -> EfficientThreadStateProcessStopped StopReasonAssertionFailure\n  | TerminateProcessStatement _ -> EfficientThreadStateProcessStopped StopReasonTerminated\n  | TerminateThreadStatement _ -> EfficientThreadStateNotRunning ThreadStatusJoinable\n  | MethodCallStatement _ _ _ _ _ true (* stack overflow *) ->\n      EfficientThreadStateProcessStopped StopReasonStackOverflow\n  | _ -> (match pc_indices.end_pc_index with\n         | Some pc -> EfficientThreadStateAtPC pc\n         | None -> EfficientThreadStateRunning)\n\nlet efficient_action_to_ending_thread_state\n  (action: Armada.Action.t)\n  (pc_indices: statement_pc_indices_t)\n  : efficient_thread_state_t =\n  if not action.ok then\n    EfficientThreadStateProcessStopped StopReasonUndefinedBehavior\n  else\n    efficient_program_statement_to_ending_thread_state action.program_statement pc_indices\n\nlet thread_states_match_per_pc_relation\n  (relation: relation_t pc_t pc_t)\n  (ts1: thread_state_t)\n  (ts2: thread_state_t)\n  : GTot bool =\n  match ts1, ts2 with\n  | ThreadStateAtPC pc1, ThreadStateAtPC pc2 -> relation pc1 pc2\n  | ThreadStateNotRunning status1, ThreadStateNotRunning status2 -> status1 = status2\n  | ThreadStateProcessStopped stop_reason1, ThreadStateProcessStopped stop_reason2 -> stop_reason1 = stop_reason2\n  | _, _ -> false\n\nlet efficient_thread_states_match_per_pc_relation\n  (relation: relation_t nat nat)\n  (ts1: efficient_thread_state_t)\n  (ts2: efficient_thread_state_t)\n  : GTot bool =\n  match ts1, ts2 with\n  | EfficientThreadStateAtPC pc1, EfficientThreadStateAtPC pc2 -> relation pc1 pc2\n  | EfficientThreadStateNotRunning status1, EfficientThreadStateNotRunning status2 -> status1 = status2\n  | EfficientThreadStateProcessStopped stop_reason1, EfficientThreadStateProcessStopped stop_reason2 ->\n      stop_reason1 = stop_reason2\n  | _, _ -> false\n\nlet efficient_starting_thread_states_match_per_pc_relation_implies_thread_states_match_per_pc_relation\n  (pcs1: array_t pc_t)\n  (pcs2: array_t pc_t)\n  (idx_relation: relation_t nat nat)\n  (pc_relation: relation_t pc_t pc_t)\n  (action1: Armada.Action.t)\n  (action2: Armada.Action.t)\n  (pc_indices1: statement_pc_indices_t)\n  (pc_indices2: statement_pc_indices_t)\n  : Lemma (requires   program_statement_corresponds_to_statement_pc_indices pcs1 action1.program_statement pc_indices1\n                    /\\ program_statement_corresponds_to_statement_pc_indices pcs2 action2.program_statement pc_indices2\n                    /\\ efficient_thread_states_match_per_pc_relation idx_relation\n                         (efficient_action_to_starting_thread_state pc_indices1)\n                         (efficient_action_to_starting_thread_state pc_indices2)\n                    /\\ (forall (idx1: nat) (idx2: nat). idx1 < array_len pcs1 /\\ idx2 < array_len pcs2 ==>\n                         (let pc1 = array_index pcs1 idx1 in\n                          let pc2 = array_index pcs2 idx2 in\n                          idx_relation idx1 idx2 ==> pc_relation pc1 pc2)))\n         (ensures thread_states_match_per_pc_relation pc_relation (action_to_starting_thread_state action1)\n                    (action_to_starting_thread_state action2)) =\n  ()\n\nlet efficient_ending_thread_states_match_per_pc_relation_implies_thread_states_match_per_pc_relation\n  (pcs1: array_t pc_t)\n  (pcs2: array_t pc_t)\n  (idx_relation: relation_t nat nat)\n  (pc_relation: relation_t pc_t pc_t)\n  (action1: Armada.Action.t)\n  (action2: Armada.Action.t)\n  (pc_indices1: statement_pc_indices_t)\n  (pc_indices2: statement_pc_indices_t)\n  : Lemma (requires   program_statement_corresponds_to_statement_pc_indices pcs1 action1.program_statement pc_indices1\n                    /\\ program_statement_corresponds_to_statement_pc_indices pcs2 action2.program_statement pc_indices2\n                    /\\ efficient_thread_states_match_per_pc_relation idx_relation\n                         (efficient_action_to_ending_thread_state action1 pc_indices1)\n                         (efficient_action_to_ending_thread_state action2 pc_indices2)\n                    /\\ (forall (idx1: nat) (idx2: nat). idx1 < array_len pcs1 /\\ idx2 < array_len pcs2 ==>\n                         (let pc1 = array_index pcs1 idx1 in\n                          let pc2 = array_index pcs2 idx2 in\n                          idx_relation idx1 idx2 ==> pc_relation pc1 pc2)))\n         (ensures thread_states_match_per_pc_relation pc_relation (action_to_ending_thread_state action1)\n                    (action_to_ending_thread_state action2)) =\n  ()\n\nlet step_computation_has_thread_state_effect\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (step: Armada.Step.t)\n  (s: Armada.State.t)\n  : Lemma (ensures (let ts = action_to_ending_thread_state step.action in\n                    match step_computation actor starts_atomic_block ends_atomic_block step s with\n                    | Some s' -> thread_state_applies s' actor ts\n                    | None -> True)) =\n  executing_step_changes_status_depending_on_statement actor starts_atomic_block ends_atomic_block step s\n\nlet step_computation_requires_start_thread_state\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (step: Armada.Step.t)\n  (s: Armada.State.t)\n  : Lemma (ensures (let ts = action_to_starting_thread_state step.action in\n                    match step_computation actor starts_atomic_block ends_atomic_block step s with\n                    | Some s' -> thread_state_applies s actor ts\n                    | None -> True)) =\n  executing_step_changes_status_depending_on_statement actor starts_atomic_block ends_atomic_block step s\n\nlet steps_computation_requires_start_thread_state\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (steps: list Armada.Step.t)\n  (s: Armada.State.t)\n  : Lemma (ensures (match steps_computation actor starts_atomic_block ends_atomic_block steps s with\n                    | Some s' -> thread_state_applies s actor (action_to_starting_thread_state (Cons?.hd steps).action)\n                    | None -> True)) =\n  match steps with\n  | [] -> ()\n  | first_step :: _ ->\n      executing_step_changes_status_depending_on_statement actor starts_atomic_block ends_atomic_block\n        first_step s\n\nlet rec actions_to_ending_thread_state\n  (actions: list Armada.Action.t)\n  : GTot thread_state_t (decreases actions) =\n  match actions with\n  | [] -> ThreadStateRunning\n  | [action] -> action_to_ending_thread_state action\n  | first_action :: remaining_actions -> actions_to_ending_thread_state remaining_actions\n\nlet rec efficient_actions_to_ending_thread_state\n  (actions: list Armada.Action.t)\n  (pc_indices_list: list statement_pc_indices_t)\n  : GTot efficient_thread_state_t (decreases actions) =\n  match actions, pc_indices_list with\n  | [], _ -> EfficientThreadStateRunning\n  | [action], [pc_indices] -> efficient_action_to_ending_thread_state action pc_indices\n  | first_action :: remaining_actions, first_pc_indices :: remaining_pc_indices ->\n      efficient_actions_to_ending_thread_state remaining_actions remaining_pc_indices\n  | _, _ -> EfficientThreadStateRunning\n\nlet rec steps_to_ending_thread_state\n  (steps: list Armada.Step.t)\n  : GTot thread_state_t (decreases steps) =\n  match steps with\n  | [] -> ThreadStateRunning\n  | [step] -> action_to_ending_thread_state step.action\n  | first_step :: remaining_steps -> steps_to_ending_thread_state remaining_steps\n\nlet rec steps_computation_has_thread_state_effect\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (steps: list Armada.Step.t)\n  (s: Armada.State.t)\n  : Lemma (ensures (let ts = steps_to_ending_thread_state steps in\n                    match steps_computation actor starts_atomic_block ends_atomic_block steps s with\n                    | Some s' -> thread_state_applies s' actor ts\n                    | None -> True))\n          (decreases steps) =\n  match steps with\n  | [] -> ()\n  | [step] ->\n      executing_step_changes_status_depending_on_statement actor starts_atomic_block ends_atomic_block step s\n  | first_step :: remaining_steps ->\n      executing_step_changes_status_depending_on_statement actor starts_atomic_block false first_step s;\n      (match step_computation actor starts_atomic_block false first_step s with\n       | Some s' ->\n           steps_computation_has_thread_state_effect actor false ends_atomic_block remaining_steps s'\n       | None -> ())\n\nlet steps_computation_permitting_empty\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (steps: list Armada.Step.t)\n  (s: Armada.State.t)\n  : GTot (option Armada.State.t) =\n  match steps with\n  | [] -> Some s\n  | _ -> steps_computation actor starts_atomic_block ends_atomic_block steps s\n\nlet rec steps_computation_permitting_empty_has_thread_state_effect\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (steps: list Armada.Step.t)\n  (s: Armada.State.t)\n  : Lemma (ensures  (Cons? steps ==>\n                     (let ts = actions_to_ending_thread_state (map_ghost armada_step_to_action steps) in\n                      match steps_computation actor starts_atomic_block ends_atomic_block steps s with\n                      | Some s' -> thread_state_applies s' actor ts\n                      | None -> True)))\n          (decreases steps) =\n  match steps with\n  | [] -> ()\n  | [step] ->\n      executing_step_changes_status_depending_on_statement actor starts_atomic_block ends_atomic_block step s\n  | first_step :: remaining_steps ->\n      executing_step_changes_status_depending_on_statement actor starts_atomic_block false first_step s;\n      (match step_computation actor starts_atomic_block false first_step s with\n       | Some s' ->\n           steps_computation_permitting_empty_has_thread_state_effect actor false ends_atomic_block remaining_steps s'\n       | None -> ())\n"
  },
  {
    "path": "experimental/lib/Strategies.ArmadaStatement.fst",
    "content": "module Strategies.ArmadaStatement\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Computation\nopen Armada.Expression\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Pointer\nopen Armada.State\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Transition\nopen Armada.Type\nopen FStar.Sequence.Base\nopen Spec.List\nopen Spec.Logic\nopen Spec.Ubool\nopen Util.List\n\nlet actor_state_predicate = tid_t -> Armada.State.t -> Armada.State.t -> Type0\n\nlet actor_state_predicate_transitive (pred: actor_state_predicate) =\n  forall actor x1 x2 x3. (pred actor x1 x2 /\\ pred actor x2 x3) ==> (pred actor x1 x3)\n\nlet actor_state_predicate_reflexive (pred: actor_state_predicate) =\n  forall actor x. pred actor x x\n\nlet actor_memory_predicate = tid_t -> Armada.Memory.t -> Armada.Memory.t -> Type0\n\nlet actor_memory_predicate_transitive (pred: actor_memory_predicate) =\n  forall actor x1 x2 x3. (pred actor x1 x2 /\\ pred actor x2 x3) ==> (pred actor x1 x3)\n\nlet actor_memory_predicate_reflexive (pred: actor_memory_predicate) =\n  forall actor x. pred actor x x\n\nlet make_push_stack_variables_lemma_conditional\n  (pred: actor_state_predicate)\n  (initializer_cond: (initializer_t -> GTot bool){\n       (forall actor writer_pc writer_expression_number method_id frame_uniq initializer s.\n          initializer_cond initializer ==>\n          (match push_stack_variable actor writer_pc writer_expression_number method_id frame_uniq\n                   initializer s with\n           | ComputationProduces s' -> pred actor s s'\n           | _ -> True))\n     /\\ actor_state_predicate_reflexive pred\n     /\\ actor_state_predicate_transitive pred})\n  : unit -> Lemma\n      (forall actor writer_pc writer_expression_number method_id frame_uniq initializers s.\n         {:pattern push_stack_variables actor writer_pc writer_expression_number method_id\n                     frame_uniq initializers s}\n         for_all_ghost initializer_cond initializers ==>\n         (match push_stack_variables actor writer_pc writer_expression_number method_id\n                  frame_uniq initializers s with\n          | ComputationProduces s' -> pred actor s s'\n          | _ -> True)) =\n  fun _ ->\n  let rec internal_lem actor writer_pc writer_expression_number method_id frame_uniq initializers s\n    : Lemma (requires for_all_ghost initializer_cond initializers)\n            (ensures (match push_stack_variables actor writer_pc writer_expression_number method_id\n                              frame_uniq initializers s with\n                      | ComputationProduces s' -> pred actor s s'\n                      | _ -> True))\n            (decreases initializers)\n            [SMTPat (push_stack_variables actor writer_pc writer_expression_number method_id\n                       frame_uniq initializers s)] =\n    match initializers with\n    | [] -> ()\n    | first_initializer :: remaining_initializers ->\n        (match push_stack_variable actor writer_pc writer_expression_number method_id frame_uniq\n                 first_initializer s with\n         | ComputationProduces s' ->\n             (match push_stack_variables actor writer_pc (writer_expression_number + 1) method_id\n                      frame_uniq remaining_initializers s' with\n              | ComputationProduces s'' ->\n                  internal_lem actor writer_pc (writer_expression_number + 1) method_id frame_uniq\n                    remaining_initializers s'\n              | _ -> ())\n         | _ -> ())\n  in\n  ()\n\nlet make_push_stack_variables_lemma\n  (pred: actor_state_predicate{\n       (forall actor writer_pc writer_expression_number method_id frame_uniq initializer s.\n           match push_stack_variable actor writer_pc writer_expression_number method_id frame_uniq\n                   initializer s with\n           | ComputationProduces s' -> pred actor s s'\n           | _ -> True)\n     /\\ actor_state_predicate_reflexive pred\n     /\\ actor_state_predicate_transitive pred})\n  : unit -> Lemma\n      (forall actor writer_pc writer_expression_number method_id frame_uniq initializers s.\n         {:pattern push_stack_variables actor writer_pc writer_expression_number method_id\n                     frame_uniq initializers s}\n         match push_stack_variables actor writer_pc writer_expression_number method_id\n                 frame_uniq initializers s with\n         | ComputationProduces s' -> pred actor s s'\n         | _ -> True) =\n  make_push_stack_variables_lemma_conditional pred (fun _ -> true)\n\nlet make_push_stack_variables_premium_conditional\n  (pred: actor_state_predicate)\n  (initializer_cond: initializer_t -> GTot bool{\n       (forall actor writer_pc writer_expression_number method_id frame_uniq initializer s.\n          initializer_cond initializer ==>\n          (match push_stack_variable actor writer_pc writer_expression_number method_id frame_uniq\n                   initializer s with\n           | ComputationProduces s' -> pred actor s s'\n           | _ -> True))\n     /\\ actor_state_predicate_reflexive pred\n     /\\ actor_state_predicate_transitive pred})\n  : GTot (actor: _ -> writer_pc: _ -> writer_expression_number: _ -> method_id: _ -> frame_uniq: _ ->\n          initializers: _ -> s: _ ->\n          GTot (result: conditional_computation_t Armada.State.t{\n                  result == push_stack_variables actor writer_pc writer_expression_number method_id\n                              frame_uniq initializers s\n                /\\ (for_all_ghost initializer_cond initializers ==>\n                   (match result with | ComputationProduces s' -> pred actor s s' | _ -> True))})) =\n  make_push_stack_variables_lemma_conditional pred initializer_cond ();\n  let f actor writer_pc writer_expression_number method_id frame_uniq initializers s\n    : GTot (result: conditional_computation_t Armada.State.t{\n                result == push_stack_variables actor writer_pc writer_expression_number method_id\n                            frame_uniq initializers s\n              /\\ (for_all_ghost initializer_cond initializers ==>\n                 (match result with | ComputationProduces s' -> pred actor s s' | _ -> True))}) =\n    push_stack_variables actor writer_pc writer_expression_number method_id frame_uniq initializers\n      s\n  in\n  f\n\nlet make_push_stack_variables_premium\n  (pred: actor_state_predicate{\n       (forall actor writer_pc writer_expression_number method_id frame_uniq initializers s.\n          match push_stack_variable actor writer_pc writer_expression_number method_id frame_uniq\n                  initializers s with\n          | ComputationProduces s' -> pred actor s s'\n          | _ -> True)\n     /\\ actor_state_predicate_reflexive pred\n     /\\ actor_state_predicate_transitive pred})\n  : GTot (actor: tid_t -> writer_pc: _ -> writer_expression_number: _ -> method_id: _ ->\n          frame_uniq: _ -> initializers: _ -> s: _ ->\n          GTot (result: conditional_computation_t Armada.State.t{\n                  result == push_stack_variables actor writer_pc writer_expression_number method_id\n                              frame_uniq initializers s\n                /\\ (match result with | ComputationProduces s' -> pred actor s s' | _ -> True)})) =\n  make_push_stack_variables_premium_conditional pred (fun _ -> true)\n\nlet make_push_stack_variables_premium_conditional_negative\n  (pred: actor_state_predicate)\n  (initializer_cond: (initializer_t -> GTot bool){\n       (forall actor writer_pc writer_expression_number method_id frame_uniq initializer s.\n          (initializer_cond initializer \\/\n           (match push_stack_variable actor writer_pc writer_expression_number method_id frame_uniq\n                    initializer s with\n            | ComputationProduces s' -> pred actor s s'\n            | _ -> True)))\n     /\\ actor_state_predicate_reflexive pred\n     /\\ actor_state_predicate_transitive pred})\n  : GTot (actor: tid_t -> writer_pc: _ -> writer_expression_number: _ -> method_id: _ ->\n          frame_uniq: _ -> initializers: _ -> s: _ ->\n          GTot (result: conditional_computation_t Armada.State.t{\n                  result == push_stack_variables actor writer_pc writer_expression_number method_id\n                              frame_uniq initializers s\n                /\\ (exists_ghost initializer_cond initializers \\/\n                   (match result with | ComputationProduces s' -> pred actor s s' | _ -> True))})) =\n  make_push_stack_variables_premium_conditional pred\n    (fun initializer -> not (initializer_cond initializer))\n\nlet make_push_stack_parameters_lemma_conditional\n  (pred: actor_state_predicate)\n  (parameter_cond: object_value_t -> GTot bool{\n       (forall actor writer_pc writer_expression_number method_id frame_uniq initializer s.\n            InitializerSpecific? initializer.iv\n          /\\ parameter_cond (InitializerSpecific?.value initializer.iv) ==>\n          (match push_stack_variable actor writer_pc writer_expression_number method_id frame_uniq\n                   initializer s with\n           | ComputationProduces s' -> pred actor s s'\n           | _ -> True))\n     /\\ actor_state_predicate_reflexive pred\n     /\\ actor_state_predicate_transitive pred})\n  : unit -> Lemma\n      (forall actor writer_pc writer_expression_number method_id frame_uniq var_ids parameters s.\n         {:pattern push_stack_parameters actor writer_pc writer_expression_number\n                     method_id frame_uniq var_ids parameters s}\n         for_all_ghost parameter_cond parameters ==>\n         (match push_stack_parameters actor writer_pc writer_expression_number\n                  method_id frame_uniq var_ids parameters s with\n          | ComputationProduces s' -> pred actor s s'\n          | _ -> True)) =\n  fun _ ->\n  let rec internal_lem actor writer_pc writer_expression_number method_id frame_uniq var_ids\n                         parameters s\n    : Lemma (requires for_all_ghost parameter_cond parameters)\n            (ensures (match push_stack_parameters actor writer_pc writer_expression_number\n                              method_id frame_uniq var_ids parameters s with\n                      | ComputationProduces s' -> pred actor s s'\n                      | _ -> True))\n            (decreases parameters)\n            [SMTPat (push_stack_parameters actor writer_pc writer_expression_number\n                       method_id frame_uniq var_ids parameters s)] =\n    match parameters, var_ids with\n    | [], [] -> ()\n    | first_parameter :: remaining_parameters, first_var_id :: remaining_var_ids ->\n        let first_initializer = { var_id = first_var_id; iv = InitializerSpecific first_parameter;\n                                  weakly_consistent = false } in\n        (match push_stack_variable actor writer_pc writer_expression_number method_id\n                             frame_uniq first_initializer s with\n         | ComputationProduces s' ->\n             (match push_stack_parameters actor writer_pc (writer_expression_number + 1) method_id\n                      frame_uniq remaining_var_ids remaining_parameters s' with\n              | ComputationProduces s'' ->\n                  internal_lem actor writer_pc (writer_expression_number + 1) method_id frame_uniq\n                    remaining_var_ids remaining_parameters s'\n              | _ -> ())\n         | _ -> ())\n    | _ -> ()\n  in\n  ()\n\nlet make_pop_stack_variables_lemma\n  (pred: actor_memory_predicate{\n       (forall actor method_id frame_uniq var_id mem.\n          (match pop_stack_variable actor method_id frame_uniq var_id mem with\n           | ComputationProduces mem' -> pred actor mem mem'\n           | _ -> True))\n     /\\ actor_memory_predicate_reflexive pred\n     /\\ actor_memory_predicate_transitive pred})\n  : unit -> Lemma\n      (forall actor method_id frame_uniq var_ids mem.\n         {:pattern pop_stack_variables actor method_id frame_uniq var_ids mem}\n         match pop_stack_variables actor method_id frame_uniq var_ids mem with\n         | ComputationProduces mem' -> pred actor mem mem'\n         | _ -> True) =\n  fun _ ->\n  let rec internal_lem actor method_id frame_uniq var_ids mem\n    : Lemma (ensures (match pop_stack_variables actor method_id frame_uniq var_ids mem with\n                      | ComputationProduces mem' -> pred actor mem mem'\n                      | _ -> True))\n            (decreases var_ids)\n            [SMTPat (pop_stack_variables actor method_id frame_uniq var_ids mem)] =\n    match pop_stack_variables actor method_id frame_uniq var_ids mem with\n    | ComputationProduces mem' ->\n        (match var_ids with\n         | [] -> ()\n         | first_var_id :: remaining_var_ids ->\n             (match pop_stack_variable actor method_id frame_uniq first_var_id mem with\n              | ComputationProduces mem2 ->\n                  internal_lem actor method_id frame_uniq remaining_var_ids mem2\n              | _ -> ()))\n    | _ -> ()\n  in\n  ()\n\nlet make_pop_stack_variables_premium\n  (pred: actor_memory_predicate{\n       (forall actor method_id frame_uniq var_id mem.\n          (match pop_stack_variable actor method_id frame_uniq var_id mem with\n           | ComputationProduces mem' -> pred actor mem mem'\n           | _ -> True))\n     /\\ actor_memory_predicate_reflexive pred\n     /\\ actor_memory_predicate_transitive pred})\n  : GTot (actor: _ -> method_id: _ -> frame_uniq: _ -> var_ids: _ -> mem: _ ->\n          GTot (result: conditional_computation_t Armada.Memory.t{\n                  result == pop_stack_variables actor method_id frame_uniq var_ids mem\n                /\\ (match result with | ComputationProduces mem' -> pred actor mem mem' | _ -> True)})) =\n  let f actor method_id frame_uniq var_ids mem\n    : GTot (result: conditional_computation_t Armada.Memory.t{\n              result == pop_stack_variables actor method_id frame_uniq var_ids mem\n            /\\ (match result with | ComputationProduces mem' -> pred actor mem mem' | _ -> True)}) =\n    make_pop_stack_variables_lemma pred ();\n    pop_stack_variables actor method_id frame_uniq var_ids mem\n  in\n  f\n\nlet make_push_stack_parameters_lemma\n  (pred: actor_state_predicate{\n       (forall actor writer_pc writer_expression_number method_id frame_uniq initializer s.\n          match push_stack_variable actor writer_pc writer_expression_number method_id frame_uniq\n                  initializer s with\n          | ComputationProduces s' -> pred actor s s'\n          | _ -> True)\n     /\\ actor_state_predicate_reflexive pred\n     /\\ actor_state_predicate_transitive pred})\n  : unit -> Lemma (\n      forall actor writer_pc writer_expression_number method_id frame_uniq var_ids parameters s.\n         {:pattern push_stack_parameters actor writer_pc writer_expression_number\n                     method_id frame_uniq var_ids parameters s}\n         match push_stack_parameters actor writer_pc writer_expression_number\n                 method_id frame_uniq var_ids parameters s with\n         | ComputationProduces s' -> pred actor s s'\n         | _ -> True) =\n  make_push_stack_parameters_lemma_conditional pred (fun _ -> true)\n\nlet make_push_stack_parameters_premium_conditional\n  (pred: actor_state_predicate)\n  (parameter_cond: (object_value_t -> GTot bool){\n       (forall actor writer_pc writer_expression_number method_id frame_uniq initializer s.\n            InitializerSpecific? initializer.iv\n          /\\ parameter_cond (InitializerSpecific?.value initializer.iv) ==>\n          (match push_stack_variable actor writer_pc writer_expression_number method_id frame_uniq\n                   initializer s with\n           | ComputationProduces s' -> pred actor s s'\n           | _ -> True))\n     /\\ actor_state_predicate_reflexive pred\n     /\\ actor_state_predicate_transitive pred})\n  : GTot (actor: _ -> writer_pc: _ -> writer_expression_number: _ -> method_id: _ -> frame_uniq: _ ->\n          var_ids: _ -> parameters: _ -> s: _ ->\n          GTot (result: conditional_computation_t Armada.State.t{\n                   result == push_stack_parameters actor writer_pc writer_expression_number\n                               method_id frame_uniq var_ids parameters s\n                 /\\ (for_all_ghost parameter_cond parameters ==>\n                    (match result with | ComputationProduces s' -> pred actor s s' | _ -> True))})) =\n  make_push_stack_parameters_lemma_conditional pred parameter_cond ();\n  let f actor writer_pc writer_expression_number method_id frame_uniq var_ids parameters s\n    : GTot (result: conditional_computation_t Armada.State.t{\n              result == push_stack_parameters actor writer_pc writer_expression_number method_id\n                          frame_uniq var_ids parameters s\n              /\\ (for_all_ghost parameter_cond parameters ==>\n                 (match result with | ComputationProduces s' -> pred actor s s' | _ -> True))}) =\n    push_stack_parameters actor writer_pc writer_expression_number method_id frame_uniq var_ids\n      parameters s\n  in\n  f\n\nlet make_push_stack_parameters_premium\n  (pred: actor_state_predicate{\n       (forall actor writer_pc writer_expression_number method_id frame_uniq var_ids s.\n          match push_stack_variable actor writer_pc writer_expression_number method_id frame_uniq\n                  var_ids s with\n          | ComputationProduces s' -> pred actor s s'\n          | _ -> True)\n     /\\ actor_state_predicate_reflexive pred\n     /\\ actor_state_predicate_transitive pred})\n  : GTot (actor: _ -> writer_pc: _ -> writer_expression_number: _ -> method_id: _ -> frame_uniq: _ ->\n          var_ids: _ -> parameters: _ -> s: _ ->\n          GTot (result: conditional_computation_t Armada.State.t{\n                   result == push_stack_parameters actor writer_pc writer_expression_number\n                               method_id frame_uniq var_ids parameters s\n                 /\\ (match result with | ComputationProduces s' -> pred actor s s' | _ -> True)})) =\n  make_push_stack_parameters_premium_conditional pred (fun _ -> true)\n\nlet make_push_stack_parameters_premium_conditional_negative\n  (pred: actor_state_predicate)\n  (parameter_cond: (object_value_t -> GTot bool){\n       (forall actor writer_pc writer_expression_number method_id frame_uniq initializer s.\n          (InitializerSpecific? initializer.iv /\\\n           parameter_cond (InitializerSpecific?.value initializer.iv)) \\/\n          (match push_stack_variable actor writer_pc writer_expression_number method_id frame_uniq\n                   initializer s with\n           | ComputationProduces s' -> pred actor s s'\n           | _ -> True))\n     /\\ actor_state_predicate_reflexive pred\n     /\\ actor_state_predicate_transitive pred})\n  : GTot (actor: _ -> writer_pc: _ -> writer_expression_number: _ -> method_id: _ -> frame_uniq: _ ->\n          var_ids: _ -> parameters: _ -> s: _ ->\n          GTot (result: conditional_computation_t Armada.State.t{\n                   result == push_stack_parameters actor writer_pc writer_expression_number\n                               method_id frame_uniq var_ids parameters s\n                 /\\ (exists_ghost parameter_cond parameters \\/\n                     (match result with | ComputationProduces s' -> pred actor s s' | _ -> True))})) =\n  make_push_stack_parameters_premium_conditional pred (fun parameter -> not (parameter_cond parameter))\n\nlet make_update_expression_lemma\n  (pred: actor_state_predicate{\n       (forall exp actor writer_pc writer_expression_number bypassing_write_buffer new_value s.\n          match update_expression exp actor writer_pc writer_expression_number\n                  bypassing_write_buffer new_value s with\n          | ComputationProduces s' -> pred actor s s'\n          | _ -> True)})\n  : unit -> Lemma\n      (forall exp actor writer_pc writer_expression_number bypassing_write_buffer new_value s.\n         match update_expression exp actor writer_pc writer_expression_number\n                 bypassing_write_buffer new_value s with\n         | ComputationProduces s' -> pred actor s s'\n         | _ -> True) =\n  fun _ -> ()\n\nlet make_update_expression_premium_conditional\n  (pred: actor_state_predicate)\n  (exp_value_pred: expression_t -> object_value_t -> bool{\n       (forall exp actor writer_pc writer_expression_number bypassing_write_buffer new_value s.\n          exp_value_pred exp new_value ==>\n          (match update_expression exp actor writer_pc writer_expression_number\n                   bypassing_write_buffer new_value s with\n           | ComputationProduces s' -> pred actor s s'\n           | _ -> True))\n     /\\ actor_state_predicate_reflexive pred\n     /\\ actor_state_predicate_transitive pred})\n  : GTot (exp: _ -> actor: _ -> writer_pc: _ -> writer_expression_number: _ ->\n          bypassing_write_buffer: _ -> new_value: _ -> s: _ ->\n          GTot (result: conditional_computation_t Armada.State.t{\n            result == update_expression exp actor writer_pc writer_expression_number\n                        bypassing_write_buffer new_value s\n          /\\ (exp_value_pred exp new_value ==>\n              (match result with\n               | ComputationProduces s' -> pred actor s s'\n               | _ -> True))})) =\n  let f exp actor writer_pc writer_expression_number bypassing_write_buffer new_value s\n    : GTot (result: conditional_computation_t Armada.State.t{\n              result == update_expression exp actor writer_pc writer_expression_number\n                          bypassing_write_buffer new_value s\n              /\\ (exp_value_pred exp new_value ==>\n                 (match result with\n                  | ComputationProduces s' -> pred actor s s'\n                  | _ -> True))}) =\n    update_expression exp actor writer_pc writer_expression_number bypassing_write_buffer\n      new_value s\n  in\n  f\n\nlet make_update_expression_premium\n  (pred: actor_state_predicate{\n       (forall exp actor writer_pc writer_expression_number bypassing_write_buffer new_value s.\n          match update_expression exp actor writer_pc writer_expression_number\n                  bypassing_write_buffer new_value s with\n          | ComputationProduces s' -> pred actor s s'\n          | _ -> True)\n     /\\ actor_state_predicate_reflexive pred\n     /\\ actor_state_predicate_transitive pred})\n  : GTot (exp: _ -> actor: _ -> writer_pc: _ -> writer_expression_number: _ ->\n          bypassing_write_buffer: _ -> new_value: _ -> s: _ ->\n          GTot (result: conditional_computation_t Armada.State.t{\n            result == update_expression exp actor writer_pc writer_expression_number\n                        bypassing_write_buffer new_value s\n          /\\ (match result with | ComputationProduces s' -> pred actor s s' | _ -> True)})) =\n  let f exp actor writer_pc writer_expression_number bypassing_write_buffer new_value s\n    : GTot (result: conditional_computation_t Armada.State.t{\n              result == update_expression exp actor writer_pc writer_expression_number\n                          bypassing_write_buffer new_value s\n              /\\ (match result with | ComputationProduces s' -> pred actor s s' | _ -> True)}) =\n    update_expression exp actor writer_pc writer_expression_number bypassing_write_buffer\n      new_value s\n  in\n  f\n\nlet make_update_expressions_lemma_conditional\n  (pred: actor_state_predicate)\n  (exp_value_pred: expression_t -> object_value_t -> bool{\n       (forall exp actor writer_pc writer_expression_number bypassing_write_buffer new_value s.\n          exp_value_pred exp new_value ==>\n          (match update_expression exp actor writer_pc writer_expression_number\n                   bypassing_write_buffer new_value s with\n           | ComputationProduces s' -> pred actor s s'\n           | _ -> True))\n     /\\ actor_state_predicate_reflexive pred\n     /\\ actor_state_predicate_transitive pred})\n  : unit -> Lemma\n      (forall exps actor writer_pc writer_expression_number bypassing_write_buffer new_values s.\n         lists_correspond exp_value_pred exps new_values ==>\n         (match update_expressions exps actor writer_pc writer_expression_number\n                  bypassing_write_buffer new_values s with\n          | ComputationProduces s' -> pred actor s s'\n          | _ -> True)) =\n  fun _ ->\n  let rec internal_lem exps actor writer_pc writer_expression_number bypassing_write_buffer\n                         new_values s\n    : Lemma (requires lists_correspond exp_value_pred exps new_values)\n            (ensures (match update_expressions exps actor writer_pc writer_expression_number\n                              bypassing_write_buffer new_values s with\n                      | ComputationProduces s' -> pred actor s s'\n                      | _ -> True))\n            (decreases exps)\n            [SMTPat (update_expressions exps actor writer_pc writer_expression_number\n                              bypassing_write_buffer new_values s)] =\n    match exps, new_values with\n    | [], [] -> ()\n    | first_exp :: remaining_exps, first_new_value :: remaining_new_values ->\n        (match update_expression first_exp actor writer_pc writer_expression_number\n                 bypassing_write_buffer first_new_value s with\n         | ComputationProduces s' ->\n             internal_lem remaining_exps actor writer_pc (writer_expression_number + 1)\n                            bypassing_write_buffer remaining_new_values s'\n         | _ -> ())\n    | _ -> ()\n  in\n  ()\n\nlet make_update_expressions_lemma\n  (pred: actor_state_predicate{\n       (forall exp actor writer_pc writer_expression_number bypassing_write_buffer new_value s.\n          match update_expression exp actor writer_pc writer_expression_number\n                  bypassing_write_buffer new_value s with\n          | ComputationProduces s' -> pred actor s s'\n          | _ -> True)\n     /\\ actor_state_predicate_reflexive pred\n     /\\ actor_state_predicate_transitive pred})\n  : unit -> Lemma\n      (forall exps actor writer_pc writer_expression_number bypassing_write_buffer new_values s.\n         match update_expressions exps actor writer_pc writer_expression_number\n                 bypassing_write_buffer new_values s with\n         | ComputationProduces s' -> pred actor s s'\n         | _ -> True) =\n  fun _ ->\n  let rec internal_lem exps actor writer_pc writer_expression_number bypassing_write_buffer\n                         new_values s\n    : Lemma (ensures (match update_expressions exps actor writer_pc writer_expression_number\n                              bypassing_write_buffer new_values s with\n                      | ComputationProduces s' -> pred actor s s'\n                      | _ -> True))\n            (decreases exps)\n            [SMTPat (update_expressions exps actor writer_pc writer_expression_number\n                              bypassing_write_buffer new_values s)] =\n    match exps, new_values with\n    | [], [] -> ()\n    | first_exp :: remaining_exps, first_new_value :: remaining_new_values ->\n        (match update_expression first_exp actor writer_pc writer_expression_number\n                 bypassing_write_buffer first_new_value s with\n         | ComputationProduces s' ->\n             internal_lem remaining_exps actor writer_pc (writer_expression_number + 1)\n                            bypassing_write_buffer remaining_new_values s'\n         | _ -> ())\n    | _ -> ()\n  in\n  ()\n\nlet make_update_expressions_premium_conditional\n  (pred: actor_state_predicate)\n  (exp_value_pred: expression_t -> object_value_t -> bool{\n       (forall exp actor writer_pc writer_expression_number bypassing_write_buffer new_value s.\n          exp_value_pred exp new_value ==>\n          (match update_expression exp actor writer_pc writer_expression_number\n                   bypassing_write_buffer new_value s with\n           | ComputationProduces s' -> pred actor s s'\n           | _ -> True))\n     /\\ actor_state_predicate_reflexive pred\n     /\\ actor_state_predicate_transitive pred})\n  : GTot (exps: _ -> actor: _ -> writer_pc: _ -> writer_expression_number: _ ->\n          bypassing_write_buffer: _ -> new_values: _ -> s: _ ->\n          GTot (result: conditional_computation_t Armada.State.t{\n            result == update_expressions exps actor writer_pc writer_expression_number\n                        bypassing_write_buffer new_values s\n          /\\ (lists_correspond exp_value_pred exps new_values ==>\n             (match result with | ComputationProduces s' -> pred actor s s' | _ -> True))})) =\n  make_update_expressions_lemma_conditional pred exp_value_pred ();\n  let f exps actor writer_pc writer_expression_number bypassing_write_buffer new_values s\n    : GTot (result: conditional_computation_t Armada.State.t{\n              result == update_expressions exps actor writer_pc writer_expression_number\n                          bypassing_write_buffer new_values s\n              /\\ (lists_correspond exp_value_pred exps new_values ==>\n                 (match result with | ComputationProduces s' -> pred actor s s' | _ -> True))}) =\n    update_expressions exps actor writer_pc writer_expression_number bypassing_write_buffer\n      new_values s\n  in\n  f\n\nlet make_update_expressions_premium\n  (pred: actor_state_predicate{\n       (forall exp actor writer_pc writer_expression_number bypassing_write_buffer new_value s.\n          match update_expression exp actor writer_pc writer_expression_number\n                  bypassing_write_buffer new_value s with\n          | ComputationProduces s' -> pred actor s s'\n          | _ -> True)\n     /\\ actor_state_predicate_reflexive pred\n     /\\ actor_state_predicate_transitive pred})\n  : GTot (exps: _ -> actor: _ -> writer_pc: _ -> writer_expression_number: _ ->\n          bypassing_write_buffer: _ -> new_values: _ -> s: _ ->\n          GTot (result: conditional_computation_t Armada.State.t{\n            result == update_expressions exps actor writer_pc writer_expression_number\n                        bypassing_write_buffer new_values s\n          /\\ (match result with | ComputationProduces s' -> pred actor s s' | _ -> True)})) =\n  make_update_expressions_lemma pred ();\n  let f exps actor writer_pc writer_expression_number bypassing_write_buffer new_values s\n    : GTot (result: conditional_computation_t Armada.State.t{\n              result == update_expressions exps actor writer_pc writer_expression_number\n                          bypassing_write_buffer new_values s\n              /\\ (match result with | ComputationProduces s' -> pred actor s s' | _ -> True)}) =\n    update_expressions exps actor writer_pc writer_expression_number bypassing_write_buffer\n      new_values s\n  in\n  f\n\nlet make_external_method_take_snapshot_of_reads_clauses_computation_lemma_conditional\n  (pred: actor_state_predicate)\n  (read_clause_pred: (var_id_t * expression_t) -> bool{\n       (forall var_id actor writer_pc writer_expression_number bypassing_write_buffer exp s.\n          read_clause_pred (var_id, exp) ==>\n          (match rvalue_computation exp actor s with\n           | ComputationProduces value ->\n               let td = expression_to_td exp in\n               let local_var = ExpressionLocalVariable td var_id in\n               (match update_expression local_var actor writer_pc writer_expression_number\n                        bypassing_write_buffer value s with\n                | ComputationProduces s' -> pred actor s s'\n                | _ -> True)\n           | _ -> True))\n     /\\ actor_state_predicate_reflexive pred\n     /\\ actor_state_predicate_transitive pred})\n  : unit -> Lemma\n      (forall actor writer_pc writer_expression_number bypassing_write_buffer reads_clauses s.\n         {:pattern external_method_take_snapshot_of_reads_clauses_computation actor writer_pc\n                     writer_expression_number bypassing_write_buffer reads_clauses s}\n         for_all_ghost read_clause_pred reads_clauses ==>\n         (match external_method_take_snapshot_of_reads_clauses_computation actor writer_pc\n                   writer_expression_number bypassing_write_buffer reads_clauses s with\n          | ComputationProduces s' -> pred actor s s'\n          | _ -> True)) =\n  fun _ ->\n  let rec internal_lem actor writer_pc writer_expression_number bypassing_write_buffer\n                         reads_clauses s\n    : Lemma (requires for_all_ghost read_clause_pred reads_clauses)\n            (ensures (match external_method_take_snapshot_of_reads_clauses_computation actor\n                              writer_pc writer_expression_number bypassing_write_buffer\n                              reads_clauses s with\n                      | ComputationProduces s' -> pred actor s s'\n                      | _ -> True))\n            (decreases reads_clauses)\n            [SMTPat (external_method_take_snapshot_of_reads_clauses_computation actor writer_pc\n                       writer_expression_number bypassing_write_buffer reads_clauses s)] =\n  match reads_clauses with\n  | [] -> ()\n  | (first_var_id, first_reads_expression) :: remaining_reads_clauses ->\n      (match rvalue_computation first_reads_expression actor s with\n       | ComputationProduces first_value ->\n           let td = expression_to_td first_reads_expression in\n           let local_var = ExpressionLocalVariable td first_var_id in\n           (match update_expression local_var actor writer_pc writer_expression_number\n                    bypassing_write_buffer first_value s with\n            | ComputationProduces s' ->\n                internal_lem actor writer_pc (writer_expression_number + 1)\n                  bypassing_write_buffer remaining_reads_clauses s'\n            | _ -> ())\n       | _ -> ())\n  in\n  ()\n\nlet make_external_method_take_snapshot_of_reads_clauses_computation_lemma\n  (pred: actor_state_predicate{\n       (forall var_id actor writer_pc writer_expression_number bypassing_write_buffer exp s.\n          match rvalue_computation exp actor s with\n          | ComputationProduces value ->\n              let td = expression_to_td exp in\n              let local_var = ExpressionLocalVariable td var_id in\n              (match update_expression local_var actor writer_pc writer_expression_number\n                       bypassing_write_buffer value s with\n               | ComputationProduces s' -> pred actor s s'\n               | _ -> True)\n          | _ -> True)\n     /\\ actor_state_predicate_reflexive pred\n     /\\ actor_state_predicate_transitive pred})\n  : unit -> Lemma\n      (forall actor writer_pc writer_expression_number bypassing_write_buffer reads_clauses s.\n         {:pattern external_method_take_snapshot_of_reads_clauses_computation actor writer_pc\n                     writer_expression_number bypassing_write_buffer reads_clauses s}\n         match external_method_take_snapshot_of_reads_clauses_computation actor writer_pc\n                  writer_expression_number bypassing_write_buffer reads_clauses s with\n         | ComputationProduces s' -> pred actor s s'\n         | _ -> True) =\n  make_external_method_take_snapshot_of_reads_clauses_computation_lemma_conditional\n    pred (fun _ -> true)\n\nlet make_external_method_take_snapshot_of_reads_clauses_computation_premium_conditional\n  (pred: actor_state_predicate)\n  (read_clause_pred: (var_id_t * expression_t) -> bool{\n       (forall var_id actor writer_pc writer_expression_number bypassing_write_buffer exp s.\n          read_clause_pred (var_id, exp) ==>\n          (match rvalue_computation exp actor s with\n           | ComputationProduces value ->\n               let td = expression_to_td exp in\n               let local_var = ExpressionLocalVariable td var_id in\n               (match update_expression local_var actor writer_pc writer_expression_number\n                        bypassing_write_buffer value s with\n                | ComputationProduces s' -> pred actor s s'\n                | _ -> True)\n           | _ -> True))\n     /\\ actor_state_predicate_reflexive pred\n     /\\ actor_state_predicate_transitive pred})\n  : GTot (actor: _ -> writer_pc: _ -> writer_expression_number: _ -> bypassing_write_buffer: _ ->\n          reads_clauses: _ -> s: _ ->\n          GTot (result: conditional_computation_t Armada.State.t{\n                    result == external_method_take_snapshot_of_reads_clauses_computation actor\n                                writer_pc writer_expression_number bypassing_write_buffer\n                                reads_clauses s\n                  /\\ (for_all_ghost read_clause_pred reads_clauses ==>\n                     (match result with | ComputationProduces s' -> pred actor s s' | _ -> True))})) =\n  make_external_method_take_snapshot_of_reads_clauses_computation_lemma_conditional pred\n    read_clause_pred ();\n  let f actor writer_pc writer_expression_number bypassing_write_buffer reads_clauses s\n    : GTot (result: conditional_computation_t Armada.State.t{\n                result == external_method_take_snapshot_of_reads_clauses_computation actor\n                            writer_pc writer_expression_number bypassing_write_buffer\n                            reads_clauses s\n              /\\ (for_all_ghost read_clause_pred reads_clauses ==>\n                 (match result with | ComputationProduces s' -> pred actor s s' | _ -> True))}) =\n    external_method_take_snapshot_of_reads_clauses_computation actor writer_pc\n      writer_expression_number bypassing_write_buffer reads_clauses s\n  in\n  f\n\nlet make_external_method_take_snapshot_of_reads_clauses_computation_premium\n  (pred: actor_state_predicate{\n       (forall var_id actor writer_pc writer_expression_number bypassing_write_buffer exp s.\n          match rvalue_computation exp actor s with\n          | ComputationProduces value ->\n              let td = expression_to_td exp in\n              let local_var = ExpressionLocalVariable td var_id in\n              (match update_expression local_var actor writer_pc writer_expression_number\n                       bypassing_write_buffer value s with\n               | ComputationProduces s' -> pred actor s s'\n               | _ -> True)\n          | _ -> True)\n     /\\ actor_state_predicate_reflexive pred\n     /\\ actor_state_predicate_transitive pred})\n  : GTot (actor: _ -> writer_pc: _ -> writer_expression_number: _ -> bypassing_write_buffer: _ ->\n          reads_clauses: _ -> s: _ ->\n          GTot (result: conditional_computation_t Armada.State.t{\n                    result == external_method_take_snapshot_of_reads_clauses_computation actor\n                                writer_pc writer_expression_number bypassing_write_buffer\n                                reads_clauses s\n                  /\\ (match result with | ComputationProduces s' -> pred actor s s' | _ -> True)})) =\n  make_external_method_take_snapshot_of_reads_clauses_computation_premium_conditional\n    pred (fun _ -> true)\n\nlet make_external_method_take_snapshot_of_reads_clauses_computation_premium_conditional_negative\n  (pred: actor_state_predicate)\n  (read_clause_pred: (var_id_t * expression_t) -> bool{\n       (forall var_id actor writer_pc writer_expression_number bypassing_write_buffer exp s.\n          read_clause_pred (var_id, exp) \\/\n            (match rvalue_computation exp actor s with\n             | ComputationProduces value ->\n                 let td = expression_to_td exp in\n                 let local_var = ExpressionLocalVariable td var_id in\n                 (match update_expression local_var actor writer_pc writer_expression_number\n                          bypassing_write_buffer value s with\n                  | ComputationProduces s' -> pred actor s s'\n                  | _ -> True)\n             | _ -> True))\n     /\\ actor_state_predicate_reflexive pred\n     /\\ actor_state_predicate_transitive pred})\n  : GTot (actor: _ -> writer_pc: _ -> writer_expression_number: _ -> bypassing_write_buffer: _ ->\n          reads_clauses: _ -> s: _ ->\n          GTot (result: conditional_computation_t Armada.State.t{\n                    result == external_method_take_snapshot_of_reads_clauses_computation actor\n                                writer_pc writer_expression_number bypassing_write_buffer\n                                reads_clauses s\n                  /\\ (exists_ghost read_clause_pred reads_clauses \\/\n                     (match result with | ComputationProduces s' -> pred actor s s' | _ -> True))})) =\n  make_external_method_take_snapshot_of_reads_clauses_computation_premium_conditional\n    pred (fun ve -> not (read_clause_pred ve))\n\nlet make_log_expressions_computation_lemma_conditional\n  (pred: actor_state_predicate)\n  (logs_clause_cond: expression_t -> GTot bool{\n       (forall actor logs_clause s.\n          logs_clause_cond logs_clause ==>\n          (match rvalue_computation logs_clause actor s with\n           | ComputationProduces event ->\n               let trace' = s.trace $:: event in\n               let s' = { s with trace = trace' } in\n               pred actor s s'\n           | _ -> True))\n     /\\ actor_state_predicate_reflexive pred\n     /\\ actor_state_predicate_transitive pred})\n  : unit -> Lemma\n      (forall actor logs_clauses s.\n         {:pattern log_expressions_computation actor logs_clauses s}\n         for_all_ghost logs_clause_cond logs_clauses ==>\n         (match log_expressions_computation actor logs_clauses s with\n          | ComputationProduces s' -> pred actor s s'\n          | _ -> True)) =\n  fun _ ->\n  let rec internal_lem actor logs_clauses s\n    : Lemma (requires for_all_ghost logs_clause_cond logs_clauses)\n            (ensures (match log_expressions_computation actor logs_clauses s with\n                      | ComputationProduces s' -> pred actor s s'\n                      | _ -> True))\n            (decreases logs_clauses)\n            [SMTPat (log_expressions_computation actor logs_clauses s)] =\n    match logs_clauses with\n    | [] -> ()\n    | first_logs_clause :: remaining_logs_clauses ->\n        (match rvalue_computation first_logs_clause actor s with\n         | ComputationProduces event ->\n             let trace' = s.trace $:: event in\n             let s' = { s with trace = trace' } in\n             internal_lem actor remaining_logs_clauses s'\n         | _ -> ())\n  in\n  ()\n\nlet make_log_expressions_computation_lemma\n  (pred: actor_state_predicate{\n       (forall actor logs_clause s.\n          match rvalue_computation logs_clause actor s with\n          | ComputationProduces event ->\n              let trace' = s.trace $:: event in\n              let s' = { s with trace = trace' } in\n              pred actor s s'\n          | _ -> True)\n     /\\ actor_state_predicate_reflexive pred\n     /\\ actor_state_predicate_transitive pred})\n  : unit -> Lemma\n      (forall actor logs_clauses s.\n         {:pattern log_expressions_computation actor logs_clauses s}\n         match log_expressions_computation actor logs_clauses s with\n         | ComputationProduces s' -> pred actor s s'\n         | _ -> True) =\n  make_log_expressions_computation_lemma_conditional pred (fun _ -> true)\n\nlet make_log_expressions_computation_premium_conditional\n  (pred: actor_state_predicate)\n  (logs_clause_cond: expression_t -> GTot bool{\n       (forall actor logs_clause s.\n          logs_clause_cond logs_clause ==>\n          (match rvalue_computation logs_clause actor s with\n           | ComputationProduces event ->\n               let trace' = s.trace $:: event in\n               let s' = { s with trace = trace' } in\n               pred actor s s'\n           | _ -> True))\n     /\\ actor_state_predicate_reflexive pred\n     /\\ actor_state_predicate_transitive pred})\n  : GTot (actor: _ -> logs_clauses: _ -> s: _ ->\n          GTot (result: conditional_computation_t Armada.State.t{\n                  result == log_expressions_computation actor logs_clauses s\n                /\\ (for_all_ghost logs_clause_cond logs_clauses ==>\n                   (match result with | ComputationProduces s' -> pred actor s s' | _ -> True))})) =\n  make_log_expressions_computation_lemma_conditional pred logs_clause_cond ();\n  let f actor logs_clauses s\n    : GTot (result: conditional_computation_t Armada.State.t{\n                result == log_expressions_computation actor logs_clauses s\n              /\\ (for_all_ghost logs_clause_cond logs_clauses ==>\n                 (match result with | ComputationProduces s' -> pred actor s s' | _ -> True))}) =\n    log_expressions_computation actor logs_clauses s\n  in\n  f\n\nlet make_log_expressions_computation_premium\n  (pred: actor_state_predicate{\n       (forall actor logs_clause s.\n          match rvalue_computation logs_clause actor s with\n          | ComputationProduces event ->\n              let trace' = s.trace $:: event in\n              let s' = { s with trace = trace' } in\n              pred actor s s'\n          | _ -> True)\n     /\\ actor_state_predicate_reflexive pred\n     /\\ actor_state_predicate_transitive pred})\n  : GTot (actor: _ -> logs_clauses: _ -> s: _ ->\n          GTot (result: conditional_computation_t Armada.State.t{\n                  result == log_expressions_computation actor logs_clauses s\n                /\\ (match result with | ComputationProduces s' -> pred actor s s' | _ -> True)})) =\n  make_log_expressions_computation_premium_conditional pred (fun _ -> true)\n\nlet make_log_expressions_computation_premium_conditional_negative\n  (pred: actor_state_predicate)\n  (logs_clause_cond: expression_t -> GTot bool{\n       (forall actor logs_clause s.\n          logs_clause_cond logs_clause \\/\n          (match rvalue_computation logs_clause actor s with\n           | ComputationProduces event ->\n               let trace' = s.trace $:: event in\n               let s' = { s with trace = trace' } in\n               pred actor s s'\n           | _ -> True))\n     /\\ actor_state_predicate_reflexive pred\n     /\\ actor_state_predicate_transitive pred})\n  : GTot (actor: _ -> logs_clauses: _ -> s: _ ->\n          GTot (result: conditional_computation_t Armada.State.t{\n                  result == log_expressions_computation actor logs_clauses s\n                /\\ (exists_ghost logs_clause_cond logs_clauses \\/\n                   (match result with | ComputationProduces s' -> pred actor s s' | _ -> True))})) =\n  make_log_expressions_computation_premium_conditional pred\n    (fun c -> not (logs_clause_cond c))\n\nlet statement_computation_expandables : list string =\n  [\n    \"Armada.Statement.assume_expression_statement_computation\";\n    \"Armada.Statement.assume_predicate_statement_computation\";\n    \"Armada.Statement.assert_true_statement_computation\";\n    \"Armada.Statement.assert_false_statement_computation\";\n    \"Armada.Statement.conditional_jump_statement_computation\";\n    \"Armada.Statement.unconditional_jump_statement_computation\";\n    \"Armada.Statement.update_statement_computation\";\n    \"Armada.Statement.propagate_write_message_statement_computation\";\n    \"Armada.Statement.compare_and_swap_swapping_statement_computation\";\n    \"Armada.Statement.compare_and_swap_nonswapping_statement_computation\";\n    \"Armada.Statement.atomic_exchange_statement_computation\";\n    \"Armada.Statement.make_thread_running\";\n    \"Armada.Statement.create_thread_statement_computation\";\n    \"Armada.Statement.push_stack_frame\";\n    \"Armada.Statement.method_call_statement_computation\";\n    \"Armada.Statement.pop_stack_frame\";\n    \"Armada.Statement.return_statement_computation\";\n    \"Armada.Statement.terminate_thread_statement_computation\";\n    \"Armada.Statement.terminate_process_statement_computation\";\n    \"Armada.Statement.join_statement_computation\";\n    \"Armada.Statement.mark_allocation_root_allocated\";\n    \"Armada.Statement.alloc_successful_statement_computation\";\n    \"Armada.Statement.alloc_returning_null_statement_computation\";\n    \"Armada.Statement.dealloc_statement_computation\";\n    \"Armada.Statement.somehow_statement_computation\";\n    \"Armada.Statement.fence_statement_computation\";\n    \"Armada.Statement.external_method_take_snapshot_of_reads_clauses_computation\";\n    \"Armada.Statement.external_method_start_statement_computation\";\n    \"Armada.Statement.external_method_check_snapshot_computation\";\n    \"Armada.Statement.external_method_middle_statement_computation\";\n    \"Armada.Statement.log_expressions_computation\";\n    \"Armada.Statement.external_method_end_statement_computation\";\n    \"Armada.Statement.statement_computation\";\n    \"Armada.Computation.return\";\n    \"Armada.Computation.bind\"\n  ]\n"
  },
  {
    "path": "experimental/lib/Strategies.Atomic.fst",
    "content": "module Strategies.Atomic\n\nopen Strategies.Semantics\nopen Util.List\n\nlet make_atomic_semantics (sem: semantics_t) : semantics_t = {\n  actor_t = sem.actor_t;\n  state_t = sem.state_t;\n  action_t = list sem.action_t;\n  step_t = list sem.step_t;\n  step_to_action_f = map_ghost sem.step_to_action_f;\n  step_computation_f = steps_computation_generic sem;\n}\n"
  },
  {
    "path": "experimental/lib/Strategies.AtomicToRegular.Armada.fst",
    "content": "module Strategies.AtomicToRegular.Armada\n\nopen Armada.Action\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Step\nopen Armada.Transition\nopen Spec.Behavior\nopen FStar.List.Tot\nopen Spec.Ubool\nopen Strategies.Atomic\nopen Strategies.AtomicToRegular\nopen Util.Behavior\nopen Util.ImmutableArray\nopen Util.List\nopen Util.Nth\n\nnoeq type atomic_refines_armada_relation_t = {\n  lprog: program_t (make_atomic_semantics armada_semantics);\n  hprog: Armada.Program.t;\n  atomic_to_regular_map: list (list nat);\n  actions_array: array_t Armada.Action.t;\n\n  actions_array_correct: unit ->\n    squash (array_matches_list actions_array (all_actions hprog.program_statements));\n  atomic_to_regular_map_valid: unit ->\n    squash (valid_atomic_to_armada_map lprog.actions atomic_to_regular_map actions_array);\n  init_implies_init: s: Armada.State.t{lprog.init_f s} -> squash (init_program hprog s);\n}\n\nlet atomic_refines_armada_relation_implies_valid_atomic_to_regular_map\n  (aa: atomic_refines_armada_relation_t)\n  : Lemma (ensures (valid_atomic_to_regular_map armada_semantics aa.lprog.actions\n                      (all_actions aa.hprog.program_statements) aa.atomic_to_regular_map)) =\n  let regular_actions = all_actions aa.hprog.program_statements in\n  let atomic_actions = aa.lprog.actions in\n  let index_and_action_corr =\n    fun index -> fun action -> (array_nth aa.actions_array index) == (Some action) in\n  let indices_and_actions_corr =\n    fun indices -> fun atomic_action -> lists_correspond_ubool index_and_action_corr indices atomic_action in\n  let index_and_action_corr' = fun index -> fun action -> (nth regular_actions index) == (Some action) in\n  let indices_and_actions_corr' =\n    fun indices -> fun atomic_act -> lists_correspond_ubool index_and_action_corr' indices atomic_act in\n  let lem1 (index: nat) (action: Armada.Action.t) : Lemma\n    (requires index_and_action_corr index action)\n    (ensures  index_and_action_corr' index action) =\n    (aa.actions_array_correct ();\n     array_matches_list_implies_nth_equivalent aa.actions_array regular_actions index) in\n  let lem2 (indices: list nat) (atomic_action: list Armada.Action.t) : Lemma\n    (requires indices_and_actions_corr indices atomic_action)\n    (ensures  indices_and_actions_corr' indices atomic_action) =\n    (lists_correspond_ubool_implies_weaker_correspondence\n       index_and_action_corr index_and_action_corr' indices atomic_action lem1) in\n  aa.atomic_to_regular_map_valid ();\n  assert (valid_atomic_to_armada_map atomic_actions aa.atomic_to_regular_map aa.actions_array ==\n           lists_correspond_ubool indices_and_actions_corr aa.atomic_to_regular_map atomic_actions)\n    by FStar.Tactics.V2.trefl();\n  lists_correspond_ubool_implies_weaker_correspondence\n    indices_and_actions_corr indices_and_actions_corr' aa.atomic_to_regular_map atomic_actions lem2;\n  assert (valid_atomic_to_regular_map armada_semantics atomic_actions regular_actions aa.atomic_to_regular_map ==\n           lists_correspond_ubool indices_and_actions_corr' aa.atomic_to_regular_map atomic_actions)\n    by FStar.Tactics.V2.trefl()\n\nlet atomic_refines_armada_relation_implies_refinement (aa: atomic_refines_armada_relation_t)\n  : Lemma (ensures (spec_refines_spec\n                    (semantics_to_spec (make_atomic_semantics armada_semantics) aa.lprog)\n                    (program_to_spec aa.hprog)\n                    eq2)) =\n  let ar: atomic_refines_regular_relation_t = {\n    sem = armada_semantics;\n    lprog = aa.lprog;\n    hprog = armada_program_to_generic aa.hprog;\n    atomic_to_regular_map = aa.atomic_to_regular_map;\n    atomic_to_regular_map_valid = (fun _ -> atomic_refines_armada_relation_implies_valid_atomic_to_regular_map aa);\n    init_implies_init = aa.init_implies_init;\n  } in\n  atomic_refines_regular_relation_implies_refinement ar;\n  armada_generic_refines_spec aa.hprog;\n  spec_refinement_transitivity\n    (semantics_to_spec (make_atomic_semantics armada_semantics) aa.lprog)\n    (semantics_to_spec armada_semantics (armada_program_to_generic aa.hprog))\n    (program_to_spec aa.hprog)\n    eq2\n    eq2\n    eq2\n\nlet atomic_refines_armada_witness_valid_implies_refinement\n  (lprog: program_t (make_atomic_semantics armada_semantics))\n  (hprog: Armada.Program.t)\n  (aw: atomic_refines_armada_witness_t)\n  (* see .fsti file for spec *) =\n  list_to_array_implies_array_matches_list aw.actions_array (all_actions hprog.program_statements);\n  let ar: atomic_refines_armada_relation_t = {\n    lprog = lprog;\n    hprog = hprog;\n    atomic_to_regular_map = aw.atomic_to_regular_map;\n    actions_array = aw.actions_array;\n    actions_array_correct = (fun _ -> ());\n    atomic_to_regular_map_valid = (fun _ -> ());\n    init_implies_init = (fun _ -> ());\n  } in\n  atomic_refines_armada_relation_implies_refinement ar\n"
  },
  {
    "path": "experimental/lib/Strategies.AtomicToRegular.Armada.fsti",
    "content": "module Strategies.AtomicToRegular.Armada\n\nopen Armada.Action\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Step\nopen Armada.Transition\nopen FStar.ImmutableArray\nopen FStar.List.Tot\nopen Spec.Behavior\nopen Spec.List\nopen Spec.Logic\nopen Spec.Ubool\nopen Strategies.Atomic\nopen Strategies.AtomicToRegular\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\nopen Util.ImmutableArray\nopen Util.List\nopen Util.Nth\n\nlet valid_atomic_to_armada_map\n  (atomic_actions: list (list Armada.Action.t))\n  (atomic_to_regular_map: list (list nat))\n  (actions_array: array_t Armada.Action.t)\n  : GTot ubool =\n  let index_and_action_corr = fun idx -> fun action -> (array_nth actions_array idx) == (Some action) in\n  let indices_and_actions_corr =\n    fun indices -> fun atomic_action -> lists_correspond_ubool index_and_action_corr indices atomic_action in\n  lists_correspond_ubool indices_and_actions_corr atomic_to_regular_map atomic_actions\n\nnoeq type atomic_refines_armada_witness_t = {\n  atomic_to_regular_map: list (list nat);\n  actions_array: array_t Armada.Action.t;\n}\n\nlet atomic_refines_armada_witness_valid\n  (lprog: program_t (make_atomic_semantics armada_semantics))\n  (hprog: Armada.Program.t)\n  (aw: atomic_refines_armada_witness_t)\n  : GTot ubool =\n  valid_atomic_to_armada_map lprog.actions aw.atomic_to_regular_map aw.actions_array\n\nval atomic_refines_armada_witness_valid_implies_refinement\n  (lprog: program_t (make_atomic_semantics armada_semantics))\n  (hprog: Armada.Program.t)\n  (aw: atomic_refines_armada_witness_t)\n  : Lemma (requires   atomic_refines_armada_witness_valid lprog hprog aw\n                    /\\ lprog.init_f == init_program hprog\n                    /\\ aw.actions_array == list_to_array (all_actions hprog.program_statements))\n          (ensures  (spec_refines_spec\n                       (semantics_to_spec (make_atomic_semantics armada_semantics) lprog)\n                       (program_to_spec hprog)\n                       eq2))\n"
  },
  {
    "path": "experimental/lib/Strategies.AtomicToRegular.fst",
    "content": "module Strategies.AtomicToRegular\n\nopen Armada.Action\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Step\nopen Armada.Transition\nopen Spec.Behavior\nopen FStar.List.Tot\nopen Spec.List\nopen Spec.Ubool\nopen Strategies.Atomic\nopen Util.Behavior\nopen Util.List\nopen Util.Nth\n\nlet steps_then_steps_computation\n  (sem: semantics_t)\n  (actor: sem.actor_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (steps1: list sem.step_t)\n  (steps2: list sem.step_t)\n  (s: sem.state_t)\n  : GTot (option sem.state_t) =\n  match steps_computation_generic sem actor starts_atomic_block false steps1 s with\n  | None -> None\n  | Some s' -> steps_computation_generic sem actor false ends_atomic_block steps2 s'\n\nlet rec steps_then_steps_computation_equivalent_to_append_compute\n  (sem: semantics_t)\n  (actor: sem.actor_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (steps1: list sem.step_t)\n  (steps2: list sem.step_t)\n  (s: sem.state_t)\n  : Lemma\n  (requires Cons? steps1 /\\ Cons? steps2)\n  (ensures  steps_then_steps_computation sem actor starts_atomic_block ends_atomic_block steps1 steps2 s ==\n            steps_computation_generic sem actor starts_atomic_block ends_atomic_block (append steps1 steps2) s)\n  (decreases steps1) =\n  match steps1 with\n  | [last_step] -> ()\n  | first_step :: remaining_steps ->\n      (match step_computation_generic sem actor starts_atomic_block false first_step s with\n       | None -> ()\n       | Some s' -> steps_then_steps_computation_equivalent_to_append_compute sem actor\n                     false ends_atomic_block remaining_steps steps2 s')\n\nlet rec list_of_list_of_steps_computation\n  (sem: semantics_t)\n  (actor: sem.actor_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (steps: list (list sem.step_t))\n  (s: sem.state_t)\n  : GTot (option sem.state_t)\n      (decreases steps) =\n  match steps with\n  | [] -> None\n  | [last_step] -> steps_computation_generic sem actor starts_atomic_block ends_atomic_block last_step s\n  | first_step :: remaining_steps ->\n      (match steps_computation_generic sem actor starts_atomic_block false first_step s with\n       | None -> None\n       | Some s' -> list_of_list_of_steps_computation sem actor false ends_atomic_block remaining_steps s')\n\nlet rec successful_generic_atomic_step_computation_equivalent_to_list_of_list_of_steps_computation\n  (sem: semantics_t)\n  (actor: sem.actor_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (steps: list (list sem.step_t))\n  (s: sem.state_t)\n  (s': sem.state_t)\n  : Lemma (requires Some? (steps_computation_generic (make_atomic_semantics sem) actor starts_atomic_block\n                             ends_atomic_block steps s))\n          (ensures  steps_computation_generic (make_atomic_semantics sem) actor starts_atomic_block\n                      ends_atomic_block steps s ==\n                        list_of_list_of_steps_computation sem actor starts_atomic_block ends_atomic_block steps s)\n          (decreases steps) =\n  match steps with\n  | [] -> ()\n  | [last_atomic_step] -> ()\n  | first_step :: remaining_steps ->\n      let s_mid = Some?.v (steps_computation_generic sem actor starts_atomic_block false first_step s) in\n      successful_generic_atomic_step_computation_equivalent_to_list_of_list_of_steps_computation sem actor false\n        ends_atomic_block remaining_steps s_mid s'\n\nlet successful_atomic_step_computation_equivalent_to_list_of_list_of_steps_computation\n  (sem: semantics_t)\n  (transition: transition_t (make_atomic_semantics sem))\n  (s: sem.state_t)\n  (s': sem.state_t)\n  : Lemma (requires next_transition_generic (make_atomic_semantics sem) transition s s')\n          (ensures  steps_computation_generic (make_atomic_semantics sem) transition.actor true true\n                      transition.steps s ==\n                      list_of_list_of_steps_computation sem transition.actor true true transition.steps s)\n          (decreases transition.steps) =\n  successful_generic_atomic_step_computation_equivalent_to_list_of_list_of_steps_computation sem transition.actor\n    true true transition.steps s s'\n\nlet rec flatten_steps_preserves_eval_result\n  (sem: semantics_t)\n  (actor: sem.actor_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (flattened_steps: list sem.step_t)\n  (unflattened_steps: list (list sem.step_t))\n  (s: sem.state_t)\n  : Lemma\n  (requires   flattened_steps == flatten unflattened_steps\n            /\\ (forall steps. contains_ubool steps unflattened_steps ==> Cons? steps)\n            /\\ Some? (list_of_list_of_steps_computation sem actor starts_atomic_block ends_atomic_block\n                       unflattened_steps s))\n  (ensures  (steps_computation_generic sem actor starts_atomic_block ends_atomic_block flattened_steps s) ==\n            (list_of_list_of_steps_computation sem actor starts_atomic_block ends_atomic_block unflattened_steps s))\n  (decreases unflattened_steps) =\n  match unflattened_steps with\n  | [] -> ()\n  | [last_atomic_step] -> append_nil_is_identity last_atomic_step\n  | first_atomic_step :: remaining_unflattened_steps ->\n     let remaining_steps = flatten remaining_unflattened_steps in\n     assert (contains_ubool first_atomic_step unflattened_steps);\n     steps_then_steps_computation_equivalent_to_append_compute sem actor starts_atomic_block ends_atomic_block\n       first_atomic_step remaining_steps s;\n     (match steps_computation_generic sem actor starts_atomic_block false first_atomic_step s with\n      | None -> ()\n      | Some s' -> flatten_steps_preserves_eval_result sem actor false ends_atomic_block remaining_steps\n                    remaining_unflattened_steps s')\n\nlet rec atomic_steps_computation_implies_nonempty_steps\n  (sem: semantics_t)\n  (actor: sem.actor_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (atomic_steps: list (list sem.step_t))\n  (s: sem.state_t)\n  : Lemma (requires Some? (list_of_list_of_steps_computation sem actor starts_atomic_block ends_atomic_block\n                             atomic_steps s))\n          (ensures  forall atomic_step. contains_ubool atomic_step atomic_steps ==> Cons? atomic_step)\n          (decreases atomic_steps) =\n  match atomic_steps with\n  | [last_atomic_step] -> ()\n  | first_atomic_step :: remaining_atomic_steps ->\n      let s' = Some?.v (steps_computation_generic sem actor starts_atomic_block false first_atomic_step s) in\n      atomic_steps_computation_implies_nonempty_steps sem actor false ends_atomic_block remaining_atomic_steps s'\n\nlet flatten_transition_preserves_next_transition\n  (sem: semantics_t)\n  (ltr: transition_t (make_atomic_semantics sem))\n  (htr: transition_t sem)\n  (s: sem.state_t)\n  (s': sem.state_t)\n  : Lemma\n  (requires   htr.steps == flatten ltr.steps\n            /\\ next_transition_generic (make_atomic_semantics sem) ltr s s'\n            /\\ htr.actor == ltr.actor)\n  (ensures  next_transition_generic sem htr s s') =\n  let atomic_sem = make_atomic_semantics sem in\n  let unflattened_steps = ltr.steps in\n  successful_atomic_step_computation_equivalent_to_list_of_list_of_steps_computation sem ltr s s';\n  atomic_steps_computation_implies_nonempty_steps sem ltr.actor true true unflattened_steps s;\n  flatten_steps_preserves_eval_result sem ltr.actor true true htr.steps unflattened_steps s\n\nlet rec indices_correspond_implies_program_containment\n  (sem: semantics_t)\n  (indices: list nat)\n  (atomic_action: list sem.action_t)\n  (regular_actions: list sem.action_t)\n  : Lemma\n  (requires \n    (let index_and_action_corr = (fun index -> fun action -> (nth regular_actions index) == (Some action)) in\n     lists_correspond_ubool index_and_action_corr indices atomic_action))\n  (ensures forall action. contains_ubool action atomic_action ==> contains_ubool action regular_actions) =\n  match atomic_action with\n  | [] -> ()\n  | first_action :: remaining_actions ->\n     nth_implies_contains_ubool regular_actions (hd indices) first_action;\n     indices_correspond_implies_program_containment sem (tl indices) remaining_actions regular_actions\n\nlet expanding_atomic_action_preserves_program_containment\n  (ar: atomic_refines_regular_relation_t)\n  (atomic_step: list ar.sem.step_t)\n  : Lemma\n  (requires contains_ubool (map_ghost ar.sem.step_to_action_f atomic_step) ar.lprog.actions)\n  (ensures  for_all_ubool (program_contains_action_of_step_generic ar.sem ar.hprog) atomic_step) =\n  let sem = ar.sem in\n  let regular_actions = ar.hprog.actions in\n  let atomic_actions = ar.lprog.actions in\n  let atomic_action = map_ghost ar.sem.step_to_action_f atomic_step in\n  let atomic_index = contains_to_index atomic_action atomic_actions in\n  let index_and_action_corr = fun index -> fun action -> (nth regular_actions index) == (Some action) in\n  let indices_and_actions_corr =\n    fun indices -> fun atomic_action -> lists_correspond_ubool index_and_action_corr indices atomic_action in\n  let step_to_action = sem.step_to_action_f in\n  ar.atomic_to_regular_map_valid ();\n  assert (valid_atomic_to_regular_map sem atomic_actions regular_actions ar.atomic_to_regular_map ==\n          lists_correspond_ubool indices_and_actions_corr ar.atomic_to_regular_map atomic_actions)\n    by FStar.Tactics.V2.trefl ();\n  lists_correspond_ubool_implies_index_matches\n    indices_and_actions_corr ar.atomic_to_regular_map atomic_actions atomic_index;\n  let indices = Some?.v (nth ar.atomic_to_regular_map atomic_index) in\n  indices_correspond_implies_program_containment sem indices atomic_action regular_actions;\n  introduce forall step. contains_ubool step atomic_step ==> program_contains_action_of_step_generic ar.sem ar.hprog step\n  with introduce _ ==> _\n  with _. (\n    let p = fun action -> contains_ubool action regular_actions in\n    assert (for_all_ubool p (map_ghost step_to_action atomic_step));\n    map_ghost_contains_ubool step_to_action atomic_step step\n  )\n\nlet flatten_transition_preserves_program_containment\n  (ar: atomic_refines_regular_relation_t)\n  (latomic_steps: list (list ar.sem.step_t))\n  (hsteps: list ar.sem.step_t)\n  : Lemma\n  (requires   hsteps == flatten latomic_steps\n            /\\ for_all_ubool (program_contains_action_of_step_generic (make_atomic_semantics ar.sem) ar.lprog)\n                latomic_steps)\n  (ensures  for_all_ubool (program_contains_action_of_step_generic ar.sem ar.hprog) hsteps) =\n  let property0 = program_contains_action_of_step_generic ar.sem ar.hprog in\n  let property1 = program_contains_action_of_step_generic (make_atomic_semantics ar.sem) ar.lprog in\n  let property2 = (fun atomic_step -> (for_all_ubool property0 atomic_step)) in\n  let property_implication (latomic_step: list ar.sem.step_t)\n    : Lemma (requires property1 latomic_step) (ensures property2 latomic_step) =\n    (expanding_atomic_action_preserves_program_containment ar latomic_step) in\n  for_all_ubool_implication property_implication latomic_steps;\n  flatten_preserves_for_all_ubool property0 latomic_steps\n\nlet atomic_refines_regular_relation_implies_spec_next\n  (ar: atomic_refines_regular_relation_t)\n  (s s': ar.sem.state_t)\n  : Lemma (requires (semantics_to_spec (make_atomic_semantics ar.sem) ar.lprog).next s s')\n          (ensures  (semantics_to_spec ar.sem ar.hprog).next s s') =\n  let sem = ar.sem in\n  let atomic_sem = make_atomic_semantics sem in\n  eliminate exists ltr. next_program_generic atomic_sem ar.lprog ltr s s'\n  returns (semantics_to_spec sem ar.hprog).next s s'\n  with ltr_satisfies_next_program.\n    let lsteps = ltr.steps in\n    let hsteps: list sem.step_t = flatten lsteps in\n    let atomic_actions = ar.lprog.actions in\n    flatten_transition_preserves_program_containment ar ltr.steps hsteps;\n    let htr: transition_t sem = make_transition sem ltr.actor hsteps in\n    let lactions = map_ghost (map_ghost sem.step_to_action_f) lsteps in\n    let property1 = fun atomic_step -> contains_ubool (map_ghost sem.step_to_action_f atomic_step) atomic_actions in\n    assert (for_all_ubool (program_contains_action_of_step_generic atomic_sem ar.lprog) lsteps);\n    assert (program_contains_action_of_step_generic atomic_sem ar.lprog == property1) by FStar.Tactics.V2.trefl();\n    assert (for_all_ubool property1 lsteps);\n    let property2 = fun atomic_action -> contains_ubool atomic_action atomic_actions in\n    for_all_ubool_map\n      (map_ghost sem.step_to_action_f)\n      property2\n      (fun atomic_step -> contains_ubool (map_ghost sem.step_to_action_f atomic_step) atomic_actions)\n      lsteps;\n    assert (for_all_ubool property2 lactions);\n    flatten_transition_preserves_next_transition sem ltr htr s s';\n    introduce exists htr. next_program_generic sem ar.hprog htr s s'\n    with htr and ()\n\nlet rec atomic_refines_regular_relation_implies_behavior_satisfies_hspec_next\n  (ar: atomic_refines_regular_relation_t)\n  (b: behavior_t ar.sem.state_t) :\n  Lemma (requires behavior_satisfies_next b (semantics_to_spec (make_atomic_semantics ar.sem) ar.lprog).next)\n        (ensures  behavior_satisfies_next b (semantics_to_spec ar.sem ar.hprog).next) =\n  match b with\n  | [] -> ()\n  | [state] -> ()\n  | state1 :: state2 :: tl ->\n      atomic_refines_regular_relation_implies_spec_next ar state1 state2;\n      atomic_refines_regular_relation_implies_behavior_satisfies_hspec_next ar (state2 :: tl)\n\nlet atomic_refines_regular_relation_implies_behavior_satisfies_hspec\n  (ar: atomic_refines_regular_relation_t)\n  (b: behavior_t ar.sem.state_t) :\n  Lemma (requires behavior_satisfies_spec b (semantics_to_spec (make_atomic_semantics ar.sem) ar.lprog))\n        (ensures  behavior_satisfies_spec b (semantics_to_spec ar.sem ar.hprog)) =\n  match b with\n  | [] -> ()\n  | state1 :: _ ->\n     ar.init_implies_init state1;\n     atomic_refines_regular_relation_implies_behavior_satisfies_hspec_next ar b\n\nlet atomic_refines_regular_relation_implies_refinement (ar: atomic_refines_regular_relation_t)\n  (* see .fsti file for spec *) =\n  let lspec = semantics_to_spec (make_atomic_semantics ar.sem) ar.lprog in\n  let hspec = semantics_to_spec ar.sem ar.hprog in\n  let lem (b: behavior_t ar.sem.state_t) : Lemma\n    (requires behavior_satisfies_spec b lspec)\n    (ensures  behavior_satisfies_spec b hspec /\\ behavior_refines_behavior b b eq2)\n    [SMTPat (behavior_satisfies_spec b lspec)]\n    = (atomic_refines_regular_relation_implies_behavior_satisfies_hspec ar b;\n       refinement_relation_reflexive_implies_behavior_refines_itself b eq2) in\n  ()\n"
  },
  {
    "path": "experimental/lib/Strategies.AtomicToRegular.fsti",
    "content": "module Strategies.AtomicToRegular\n\nopen Armada.Action\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Step\nopen Armada.Transition\nopen Spec.Behavior\nopen FStar.List.Tot\nopen Spec.Ubool\nopen Strategies.Atomic\nopen Strategies.Semantics\nopen Util.Behavior\nopen Util.List\nopen Util.Nth\n\nlet valid_atomic_to_regular_map\n  (sem: semantics_t)\n  (atomic_actions: list (list sem.action_t))\n  (regular_actions: list sem.action_t)\n  (atomic_to_regular_map: list (list nat))\n  : GTot ubool =\n  let index_and_action_corr = fun index -> fun action -> (nth regular_actions index) == (Some action) in\n  let indices_and_actions_corr =\n    fun indices -> fun atomic_action -> lists_correspond_ubool index_and_action_corr indices atomic_action in\n  lists_correspond_ubool indices_and_actions_corr atomic_to_regular_map atomic_actions\n\nnoeq type atomic_refines_regular_relation_t = {\n  sem: semantics_t;\n  lprog: program_t (make_atomic_semantics sem);\n  hprog: program_t sem;\n  atomic_to_regular_map: list (list nat);\n\n  atomic_to_regular_map_valid: unit ->\n     squash (valid_atomic_to_regular_map sem lprog.actions hprog.actions atomic_to_regular_map);\n  init_implies_init: (s: sem.state_t{lprog.init_f s}) -> squash (hprog.init_f s);\n}\n\nval atomic_refines_regular_relation_implies_refinement (ar: atomic_refines_regular_relation_t)\n  : Lemma (ensures spec_refines_spec\n                     (semantics_to_spec (make_atomic_semantics ar.sem) ar.lprog)\n                     (semantics_to_spec ar.sem ar.hprog)\n                     eq2)\n"
  },
  {
    "path": "experimental/lib/Strategies.Breaking.fst",
    "content": "module Strategies.Breaking\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Statement\nopen Armada.Transition\nopen Spec.List\nopen Strategies.ArmadaStatement.Status\nopen Strategies.ArmadaStatement.ThreadState\nopen Strategies.Atomic\nopen Strategies.PCIndices\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\nopen Util.ImmutableArray\nopen Util.List\n\nlet action_breaks\n  (is_breaking_pc: pc_t -> GTot bool)\n  (action: Armada.Action.t)\n  : GTot bool =\n    (not action.ok)\n  || (match program_statement_to_ending_thread_state action.program_statement with\n     | ThreadStateRunning -> false\n     | ThreadStateAtPC pc -> is_breaking_pc pc\n     | ThreadStateNotRunning status -> true\n     | ThreadStateProcessStopped stop_reason -> true)\n\nlet action_only_creates_breaking_threads\n  (is_breaking_pc: pc_t -> GTot bool)\n  (action: Armada.Action.t)\n  : GTot bool =\n  match action.program_statement.statement with\n  | CreateThreadStatement _ initial_pc _ _ _ _ _ -> is_breaking_pc initial_pc\n  | _ -> true\n\nlet rec actions_end_with_all_threads_breaking\n  (is_breaking_pc: pc_t -> GTot bool)\n  (actions: list Armada.Action.t)\n  : GTot bool =\n  match actions with\n  | [] -> false\n  | [last_action] ->\n         action_only_creates_breaking_threads is_breaking_pc last_action\n      && action_breaks is_breaking_pc last_action\n  | first_action :: remaining_actions ->\n         action_only_creates_breaking_threads is_breaking_pc first_action\n      && actions_end_with_all_threads_breaking is_breaking_pc remaining_actions\n\nlet actions_are_propagate (actions: list Armada.Action.t) : GTot bool =\n  match actions with\n  | [action] ->\n      (let ps = action.program_statement in\n       match ps.statement with\n       | PropagateWriteMessageStatement -> None? ps.start_pc && None? ps.end_pc\n       | _ -> false)\n  | _ -> false\n\nlet actions_maintain_all_threads_breaking\n  (is_breaking_pc: pc_t -> GTot bool)\n  (actions: list Armada.Action.t)\n  : GTot bool =\n    actions_end_with_all_threads_breaking is_breaking_pc actions\n  || actions_are_propagate actions\n\nlet each_action_list_maintains_all_threads_breaking\n  (is_breaking_pc: pc_t -> GTot bool)\n  (actions_list: list (list Armada.Action.t))\n  : GTot bool =\n  for_all_ghost (actions_maintain_all_threads_breaking is_breaking_pc) actions_list\n\nlet efficient_is_breaking_pc\n  (is_breaking_pc: array_t bool)\n  (pc: nat)\n  : GTot bool =\n  match array_nth is_breaking_pc pc with\n  | Some b -> b\n  | None -> false\n\nlet efficient_action_breaks\n  (is_breaking_pc: array_t bool)\n  (action: Armada.Action.t)\n  (pc_indices: statement_pc_indices_t)\n  : GTot bool =\n    (not action.ok)\n  || (match efficient_program_statement_to_ending_thread_state action.program_statement pc_indices with\n     | EfficientThreadStateRunning -> false\n     | EfficientThreadStateAtPC pc -> efficient_is_breaking_pc is_breaking_pc pc\n     | EfficientThreadStateNotRunning status -> true\n     | EfficientThreadStateProcessStopped stop_reason -> true)\n\nlet efficient_action_only_creates_breaking_threads\n  (is_breaking_pc: array_t bool)\n  (pc_indices: statement_pc_indices_t)\n  : GTot bool =\n  match pc_indices.create_thread_initial_pc_index with\n  | Some pc -> efficient_is_breaking_pc is_breaking_pc pc\n  | _ -> true\n\nlet rec efficient_actions_end_with_all_threads_breaking\n  (is_breaking_pc: array_t bool)\n  (actions: list Armada.Action.t)\n  (pc_indices_list: list statement_pc_indices_t)\n  : GTot bool =\n  match actions, pc_indices_list with\n  | [], [] -> false\n  | [last_action], [last_pc_indices] ->\n         efficient_action_only_creates_breaking_threads is_breaking_pc last_pc_indices\n      && efficient_action_breaks is_breaking_pc last_action last_pc_indices\n  | first_action :: remaining_actions, first_pc_indices :: remaining_pc_indices ->\n         efficient_action_only_creates_breaking_threads is_breaking_pc first_pc_indices\n      && efficient_actions_end_with_all_threads_breaking is_breaking_pc remaining_actions remaining_pc_indices\n  | _, _ -> false\n\nlet efficient_actions_maintain_all_threads_breaking\n  (is_breaking_pc: array_t bool)\n  (actions: list Armada.Action.t)\n  (pc_indices_list: list statement_pc_indices_t)\n  : GTot bool =\n    efficient_actions_end_with_all_threads_breaking is_breaking_pc actions pc_indices_list\n  || actions_are_propagate actions\n\nlet efficient_each_action_list_maintains_all_threads_breaking\n  (is_breaking_pc: array_t bool)\n  (actions_array: array_t (list Armada.Action.t))\n  (pc_indices_array: array_t (list statement_pc_indices_t))\n  : GTot bool =\n  arrays_correspond (efficient_actions_maintain_all_threads_breaking is_breaking_pc) actions_array pc_indices_array\n"
  },
  {
    "path": "experimental/lib/Strategies.Common.fst",
    "content": "module Strategies.Common\n\nopen Armada.State\nopen Util.Behavior\nopen Util.List\nopen Util.Seq\n\nlet refinement_requirement_reflexive () : Lemma (refinement_relation_reflexive refinement_requirement) =\n  let lem (s: Armada.State.t) : Lemma (ensures refinement_requirement s s) [SMTPat (refinement_requirement s s)] =\n    () in\n  ()\n"
  },
  {
    "path": "experimental/lib/Strategies.GlobalVars.Init.fst",
    "content": "module Strategies.GlobalVars.Init\n\nopen Armada.Base\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Type\nopen Spec.List\nopen Spec.Ubool\nopen Strategies.GlobalVars\nopen Strategies.GlobalVars.Util\nopen Util.List\n\nlet rec memory_satisfies_main_stack_initializers_implies_satisfies_initializer\n  (mem: Armada.Memory.t)\n  (tid: tid_t)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (var_ids: list var_id_t)\n  (initializers: list initializer_t)\n  (initializer: initializer_t)\n  : Lemma (requires   contains_ubool initializer initializers\n                    /\\ memory_satisfies_main_stack_initializers mem tid method_id frame_uniq var_ids initializers)\n          (ensures  memory_satisfies_main_stack_initializer mem tid method_id frame_uniq initializer.var_id\n                      initializer) =\n  match var_ids, initializers with\n  | first_var_id :: remaining_var_ids, first_initializer :: remaining_initializers ->\n      if eqb first_initializer initializer then\n        ()\n      else\n        memory_satisfies_main_stack_initializers_implies_satisfies_initializer mem tid method_id frame_uniq\n          remaining_var_ids remaining_initializers initializer\n\nlet rec get_initializer_for_initialized_main_stack_variable\n  (mem: Armada.Memory.t)\n  (tid: tid_t)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (var_ids: list var_id_t)\n  (initializers: list initializer_t)\n  (var_id: var_id_t)\n  : Ghost initializer_t\n     (requires   list_contains var_id var_ids\n               /\\ memory_satisfies_main_stack_initializers mem tid method_id frame_uniq var_ids initializers)\n     (ensures  fun initializer ->\n                     contains_ubool initializer initializers\n                   /\\ memory_satisfies_main_stack_initializer mem tid method_id frame_uniq var_id initializer) =\n  match var_ids, initializers with\n  | first_var_id :: remaining_var_ids, first_initializer :: remaining_initializers ->\n      if eqb first_var_id var_id then\n        first_initializer\n      else\n        get_initializer_for_initialized_main_stack_variable mem tid method_id frame_uniq remaining_var_ids\n          remaining_initializers var_id\n\nlet storage_satisfies_initializer_implies_gvars_unaddressed\n  (vs: list var_id_t)\n  (initializer: initializer_t)\n  (storage: valid_object_storage_t)\n  : Lemma (requires   global_variables_unaddressed_in_initializer vs initializer\n                    /\\ storage_satisfies_initializer storage initializer.iv initializer.weakly_consistent)\n          (ensures  global_variables_unaddressed_in_storage vs storage) =\n  match initializer.iv with\n  | InitializerArbitrary td ->\n      object_storage_arbitrarily_initialized_correctly_doesnt_depend_on_gvars vs storage\n  | InitializerSpecific value ->\n      object_storage_initialized_correctly_doesnt_depend_on_gvars vs storage value\n\nlet init_implies_global_variables_unaddressed_in_memory\n  (vs: list var_id_t)\n  (program: Armada.Program.t)\n  (s: Armada.State.t)\n  : Lemma (requires   init_program program s\n                    /\\ global_variables_unaddressed_in_initializers vs program.global_initializers\n                    /\\ global_variables_unaddressed_in_initializers vs program.main_stack_initializers)\n          (ensures  global_variables_unaddressed_in_memory vs s.mem) =\n  introduce forall root_id. global_variables_unaddressed_in_root vs (s.mem root_id)\n  with (\n    let thread = s.threads s.initial_tid in\n    let initial_frame_uniq = Cons?.hd s.uniqs_used in\n    let root = s.mem root_id in\n    assert (root_invalid_outside_initializations s.mem program.global_initializers s.initial_tid\n              program.main_method_id initial_frame_uniq thread.top.local_variables root_id);\n    match root with\n    | RootGlobal storage ->\n        (match root_id with\n         | RootIdGlobal var_id ->\n             assert (exists_ghost (var_id_in_initializer var_id) program.global_initializers);\n             let initializer = exists_ghost_to_witness (var_id_in_initializer var_id) program.global_initializers in\n             for_all_ubool_equivalent_to_forall (memory_satisfies_global_initializer s.mem) program.global_initializers;\n             assert (memory_satisfies_global_initializer s.mem initializer);\n             storage_satisfies_initializer_implies_gvars_unaddressed vs initializer storage)\n    | RootStackVariable pushed popped storage ->\n        if pushed then (\n          match root_id with\n          | RootIdStack tid method_id frame_uniq var_id ->\n              let initializer = get_initializer_for_initialized_main_stack_variable s.mem tid method_id frame_uniq\n                thread.top.local_variables program.main_stack_initializers var_id in\n              storage_satisfies_initializer_implies_gvars_unaddressed vs initializer storage\n        )\n        else\n          ()\n    | RootAllocated allocated freed storage -> ()\n    | _ -> ()\n  )\n"
  },
  {
    "path": "experimental/lib/Strategies.GlobalVars.Permanent.fst",
    "content": "module Strategies.GlobalVars.Permanent\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Computation\nopen Armada.Expression\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Pointer\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Transition\nopen Armada.Type\nopen FStar.Sequence.Base\nopen FStar.Tactics.V2\nopen Spec.List\nopen Spec.Map\nopen Spec.Ubool\nopen Strategies.ArmadaStatement\nopen Util.List\nopen Util.Tactics\n\nlet variable_among_gvars (mem: Armada.Memory.t) (v: var_id_t) : GTot bool =\n  let root_id = RootIdGlobal v in\n  let root = mem root_id in\n  RootGlobal? root\n\nlet all_variables_among_gvars (mem: Armada.Memory.t) (vs: list var_id_t) : GTot bool =\n  for_all_ghost (variable_among_gvars mem) vs\n\nlet rec update_pointer_directly_maintains_variable_among_gvars\n  (v: var_id_t)\n  (p: Armada.Pointer.t)\n  (new_storage: valid_object_storage_t)\n  (mem: Armada.Memory.t)\n  : Lemma (requires variable_among_gvars mem v)\n          (ensures  (match update_pointer_directly p new_storage mem with\n                     | ComputationProduces mem' -> variable_among_gvars mem' v\n                     | _ -> True)) =\n  match update_pointer_directly p new_storage mem with\n  | ComputationImpossible | ComputationUndefined -> ()\n  | ComputationProduces mem' ->\n      (match p with\n       | PointerField struct_ptr field_id ->\n           let parent = ComputationProduces?.result (dereference_computation struct_ptr mem) in\n           (match parent with\n            | ObjectStorageStruct fields ->\n                let new_parent = update_storage_child parent field_id new_storage in\n                update_pointer_directly_maintains_variable_among_gvars v struct_ptr new_parent mem)\n       | PointerIndex array_ptr idx ->\n           let parent = ComputationProduces?.result (dereference_computation array_ptr mem) in\n           (match parent with\n            | ObjectStorageArray element_td elements ->\n                let new_parent = update_storage_child parent idx new_storage in\n                update_pointer_directly_maintains_variable_among_gvars v array_ptr new_parent mem)\n       | PointerRoot root_id -> ()\n       | _ -> ())\n\n#push-options \"--z3rlimit 10\"\n\nlet update_pointer_maintains_variable_among_gvars\n  (v: var_id_t)\n  (p: Armada.Pointer.t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (new_value: object_value_t)\n  (mem: Armada.Memory.t)\n  : Lemma (requires variable_among_gvars mem v)\n          (ensures  (match update_pointer p actor writer_pc writer_expression_number bypassing_write_buffer\n                             new_value mem with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces (optional_write_message, mem') -> variable_among_gvars mem' v)) =\n  match p with\n  | PointerUninitialized -> ()\n  | PointerNull -> ()\n  | PointerRoot root_id -> ()\n  | PointerField struct_ptr field_id ->\n      (match dereference_computation struct_ptr mem with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces parent ->\n           (match parent with\n            | ObjectStorageStruct fields ->\n                if field_id >= length fields then\n                  ()\n                else\n                  let field = index fields field_id in\n                  if   not (object_storage_valid field)\n                     || neqb (object_storage_to_td field) (object_value_to_td new_value) then\n                    ()\n                  else\n                    (match update_storage p actor writer_pc writer_expression_number\n                             bypassing_write_buffer field new_value with\n                     | ComputationImpossible | ComputationUndefined -> ()\n                     | ComputationProduces (write_message, new_field) ->\n                         if (not (can_update_storage_child parent field_id new_field)) then\n                           ()\n                         else\n                           let new_parent = update_storage_child parent field_id new_field in\n                           update_pointer_directly_maintains_variable_among_gvars v struct_ptr new_parent mem)\n            | _ -> ()))\n  | PointerIndex array_ptr idx ->\n      (match dereference_computation array_ptr mem with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces parent ->\n           (match parent with\n            | ObjectStorageArray element_td elements ->\n                if idx < 0 || idx >= length elements then\n                  ()\n                else\n                  let element = index elements idx in\n                  if not (object_storage_valid element) then\n                    ()\n                  else\n                    (match update_storage p actor writer_pc writer_expression_number\n                             bypassing_write_buffer element new_value with\n                     | ComputationImpossible | ComputationUndefined -> ()\n                     | ComputationProduces (write_message, new_element) ->\n                         if not (can_update_storage_child parent idx new_element) then\n                           ()\n                         else\n                           let new_parent = update_storage_child parent idx new_element in\n                           update_pointer_directly_maintains_variable_among_gvars v array_ptr new_parent mem)\n            | _ -> ()))\n\n#pop-options\n\nlet update_pointed_to_value_maintains_variable_among_gvars\n  (v: var_id_t)\n  (p: Armada.Pointer.t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (new_value: object_value_t)\n  (s: Armada.State.t)\n  : Lemma (requires variable_among_gvars s.mem v)\n          (ensures  (match update_pointed_to_value p actor writer_pc writer_expression_number bypassing_write_buffer\n                             new_value s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> variable_among_gvars s'.mem v)) =\n  update_pointer_maintains_variable_among_gvars v p actor writer_pc writer_expression_number bypassing_write_buffer\n    new_value s.mem\n\nlet update_expression_maintains_variable_among_gvars\n  (v: var_id_t)\n  (exp: expression_t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (new_value: object_value_t)\n  (s: Armada.State.t)\n  : Lemma (requires variable_among_gvars s.mem v)\n          (ensures  (match update_expression exp actor writer_pc writer_expression_number bypassing_write_buffer\n                             new_value s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> variable_among_gvars s'.mem v)) =\n  let s' = update_expression exp actor writer_pc writer_expression_number bypassing_write_buffer\n             new_value s in\n  if   not (expression_valid exp)\n     || not (object_value_valid new_value)\n     || neqb (object_value_to_td new_value) (expression_to_td exp) then\n    ()\n  else (\n    match lvalue_computation exp actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces p ->\n        update_pointed_to_value_maintains_variable_among_gvars v p actor writer_pc writer_expression_number\n          bypassing_write_buffer new_value s\n  )\n\nlet rec update_expressions_maintains_variable_among_gvars\n  (v: var_id_t)\n  (exps: list expression_t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (new_values: list object_value_t)\n  (s: Armada.State.t)\n  : Lemma (requires variable_among_gvars s.mem v)\n          (ensures  (match update_expressions exps actor writer_pc writer_expression_number bypassing_write_buffer\n                             new_values s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> variable_among_gvars s'.mem v))\n          (decreases exps) =\n  match exps, new_values with\n  | [], [] -> ()\n  | first_exp :: remaining_exps, first_new_value :: remaining_new_values ->\n      update_expression_maintains_variable_among_gvars v first_exp actor writer_pc writer_expression_number\n        bypassing_write_buffer first_new_value s;\n      (match update_expression first_exp actor writer_pc writer_expression_number\n               bypassing_write_buffer first_new_value s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces s' ->\n           update_expressions_maintains_variable_among_gvars v remaining_exps actor writer_pc\n             (writer_expression_number + 1) bypassing_write_buffer remaining_new_values s')\n  | _ -> ()\n\nlet push_stack_variable_maintains_variable_among_gvars\n  (v: var_id_t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (initializer: initializer_t)\n  (s: Armada.State.t)\n  : Lemma (requires variable_among_gvars s.mem v)\n          (ensures  (match push_stack_variable actor writer_pc writer_expression_number method_id frame_uniq\n                             initializer s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> variable_among_gvars s'.mem v)) =\n  let root_id = RootIdStack actor method_id frame_uniq initializer.var_id in\n  let root = s.mem root_id in\n  if not (stack_variable_ready_for_push root initializer) then\n    ()\n  else\n    let thread = s.threads actor in\n    let var_id = initializer.var_id in\n    if list_contains var_id thread.top.local_variables then\n      ()\n    else\n      let local_variables' = var_id :: thread.top.local_variables in\n      let top' = { thread.top with local_variables = local_variables' } in\n      let thread' = { thread with top = top' } in\n      let threads' = Spec.Map.upd s.threads actor thread' in\n      let root' = RootStackVariable true false (RootStackVariable?.storage root) in\n      let mem' = upd s.mem root_id root' in\n      let s' = { s with mem = mem'; threads = threads' } in\n      (match initializer.iv with\n       | InitializerArbitrary td -> ()\n       | InitializerSpecific value ->\n           let td = (object_value_to_td value) in\n           update_expression_maintains_variable_among_gvars v (ExpressionLocalVariable td var_id) actor writer_pc\n             writer_expression_number false value s')\n\nlet rec push_stack_variables_maintains_variable_among_gvars\n  (v: var_id_t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (initializers: list initializer_t)\n  (s: Armada.State.t)\n  : Lemma (requires variable_among_gvars s.mem v)\n          (ensures  (match push_stack_variables actor writer_pc writer_expression_number method_id\n                             frame_uniq initializers s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> variable_among_gvars s'.mem v))\n          (decreases initializers) =\n  match initializers with\n  | [] -> ()\n  | first_initializer :: remaining_initializers ->\n      push_stack_variable_maintains_variable_among_gvars v actor writer_pc writer_expression_number method_id frame_uniq\n        first_initializer s;\n      (match push_stack_variable actor writer_pc writer_expression_number method_id frame_uniq first_initializer s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces s' ->\n           push_stack_variables_maintains_variable_among_gvars v actor writer_pc (writer_expression_number + 1)\n             method_id frame_uniq remaining_initializers s')\n\nlet rec push_stack_parameters_maintains_variable_among_gvars\n  (v: var_id_t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (var_ids: list var_id_t)\n  (parameters: list object_value_t)\n  (s: Armada.State.t)\n  : Lemma (requires variable_among_gvars s.mem v)\n          (ensures  (match push_stack_parameters actor writer_pc writer_expression_number method_id frame_uniq\n                             var_ids parameters s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> variable_among_gvars s'.mem v))\n          (decreases parameters) =\n  match parameters, var_ids with\n  | [], [] -> ()\n  | first_parameter :: remaining_parameters, first_var_id :: remaining_var_ids ->\n      let first_initializer =\n        { var_id = first_var_id; iv = InitializerSpecific first_parameter; weakly_consistent = false } in\n      push_stack_variable_maintains_variable_among_gvars v actor writer_pc writer_expression_number method_id frame_uniq\n        first_initializer s;\n      (match push_stack_variable actor writer_pc writer_expression_number method_id frame_uniq first_initializer s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces s' ->\n           push_stack_parameters_maintains_variable_among_gvars v actor writer_pc (writer_expression_number + 1)\n             method_id frame_uniq remaining_var_ids remaining_parameters s')\n  | _ -> ()\n\nlet rec pop_stack_variables_maintains_variable_among_gvars\n  (v: var_id_t)\n  (actor: tid_t)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (var_ids: list var_id_t)\n  (mem: Armada.Memory.t)\n  : Lemma (requires variable_among_gvars mem v)\n          (ensures  (match pop_stack_variables actor method_id frame_uniq var_ids mem with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces mem' -> variable_among_gvars mem' v)) =\n  match var_ids with\n  | [] -> ()\n  | first_var_id :: remaining_var_ids ->\n      (match pop_stack_variable actor method_id frame_uniq first_var_id mem with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces mem' ->\n           pop_stack_variables_maintains_variable_among_gvars v actor method_id frame_uniq remaining_var_ids mem')\n\nlet rec external_method_take_snapshot_of_reads_clauses_computation_maintains_variable_among_gvars\n  (v: var_id_t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (reads_clauses: list (var_id_t * expression_t))\n  (s: Armada.State.t)\n  : Lemma (requires variable_among_gvars s.mem v)\n          (ensures  (match external_method_take_snapshot_of_reads_clauses_computation actor writer_pc\n                             writer_expression_number bypassing_write_buffer reads_clauses s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> variable_among_gvars s'.mem v))\n          (decreases reads_clauses) =\n  match reads_clauses with\n  | [] -> ()\n  | (first_var_id, first_reads_expression) :: remaining_reads_clauses ->\n      (match rvalue_computation first_reads_expression actor s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces first_value ->\n           let td = expression_to_td first_reads_expression in\n           let local_var = ExpressionLocalVariable td first_var_id in\n           update_expression_maintains_variable_among_gvars v local_var actor writer_pc writer_expression_number\n             bypassing_write_buffer first_value s;\n           (match update_expression local_var actor writer_pc writer_expression_number bypassing_write_buffer\n                    first_value s with\n            | ComputationImpossible | ComputationUndefined -> ()\n            | ComputationProduces s' ->\n                external_method_take_snapshot_of_reads_clauses_computation_maintains_variable_among_gvars v\n                  actor writer_pc (writer_expression_number + 1) bypassing_write_buffer remaining_reads_clauses s'))\n  | _ -> ()\n\nlet rec log_expressions_computation_maintains_variable_among_gvars\n  (v: var_id_t)\n  (actor: tid_t)\n  (logs_clauses: list expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires variable_among_gvars s.mem v)\n          (ensures  (match log_expressions_computation actor logs_clauses s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> variable_among_gvars s'.mem v))\n          (decreases logs_clauses) =\n  match logs_clauses with\n  | [] -> ()\n  | first_logs_clause :: remaining_logs_clauses ->\n      (match rvalue_computation first_logs_clause actor s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces event ->\n           let trace' = s.trace $:: event in\n           let s' = { s with trace = trace' } in\n           log_expressions_computation_maintains_variable_among_gvars v actor remaining_logs_clauses s')\n\nlet propagate_write_message_maintains_variable_among_gvars\n  (v: var_id_t)\n  (write_message: write_message_t)\n  (receiver_tid: tid_t)\n  (mem: Armada.Memory.t)\n  : Lemma (requires variable_among_gvars mem v)\n          (ensures  (match propagate_write_message write_message receiver_tid mem with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces mem' -> variable_among_gvars mem' v)) =\n  let p = write_message.location in\n  match dereference_computation p mem with\n  | ComputationImpossible | ComputationUndefined -> ()\n  | ComputationProduces storage ->\n      (match storage with\n       | ObjectStorageWeaklyConsistentPrimitive primitive_td values local_versions ->\n           if   primitive_td <> write_message.primitive_td\n              || write_message.version >= length values\n              || local_versions receiver_tid >= write_message.version then\n             ()\n           else\n             let new_local_versions = Spec.Map.upd local_versions receiver_tid write_message.version in\n             let new_storage = ObjectStorageWeaklyConsistentPrimitive primitive_td values\n                                 new_local_versions in\n             if not (object_storage_valid new_storage) then\n               ()\n             else\n               update_pointer_directly_maintains_variable_among_gvars v p new_storage mem\n       | _ -> ())\n\nlet free_pointer_maintains_variable_among_gvars\n  (v: var_id_t)\n  (p: Armada.Pointer.t)\n  (mem: Armada.Memory.t)\n  : Lemma (requires variable_among_gvars mem v)\n          (ensures  (match free_pointer p mem with\n                     | ComputationProduces mem' -> variable_among_gvars mem' v\n                     | _ -> True)) =\n  ()\n\n#push-options \"--z3rlimit 10\"\n\nlet assume_expression_statement_computation_maintains_variable_among_gvars\n  (v: var_id_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (exp: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires variable_among_gvars s.mem v)\n          (ensures  (match assume_expression_statement_computation actor nd start_pc exp s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> variable_among_gvars s'.mem v)) =\n  ()\n\nlet assume_predicate_statement_computation_maintains_variable_among_gvars\n  (v: var_id_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (pred: Armada.State.t -> GTot bool)\n  (s: Armada.State.t)\n  : Lemma (requires variable_among_gvars s.mem v)\n          (ensures  (match assume_predicate_statement_computation actor nd start_pc pred s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> variable_among_gvars s'.mem v)) =\n  ()\n\nlet assert_true_statement_computation_maintains_variable_among_gvars\n  (v: var_id_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (exp: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires variable_among_gvars s.mem v)\n          (ensures  (match assert_true_statement_computation actor nd start_pc exp s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> variable_among_gvars s'.mem v)) =\n  ()\n\nlet assert_false_statement_computation_maintains_variable_among_gvars\n  (v: var_id_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (exp: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires variable_among_gvars s.mem v)\n          (ensures  (match assert_false_statement_computation actor nd start_pc exp s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> variable_among_gvars s'.mem v)) =\n  ()\n\nlet conditional_jump_statement_computation_maintains_variable_among_gvars\n  (v: var_id_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (exp: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires variable_among_gvars s.mem v)\n          (ensures  (match conditional_jump_statement_computation actor nd start_pc exp s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> variable_among_gvars s'.mem v)) =\n  ()\n\nlet unconditional_jump_statement_computation_maintains_variable_among_gvars\n  (v: var_id_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (s: Armada.State.t)\n  : Lemma (requires variable_among_gvars s.mem v)\n          (ensures  (match unconditional_jump_statement_computation actor nd start_pc s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> variable_among_gvars s'.mem v)) =\n  ()\n\nlet update_statement_computation_maintains_variable_among_gvars\n  (v: var_id_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (bypassing_write_buffer: bool)\n  (dst: expression_t)\n  (src: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires variable_among_gvars s.mem v)\n          (ensures  (match update_statement_computation actor nd start_pc bypassing_write_buffer dst src s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> variable_among_gvars s'.mem v)) =\n  let cs' = update_statement_computation actor nd start_pc bypassing_write_buffer dst src s in\n  if   Cons? nd\n     || neqb (expression_to_td dst) (expression_to_td src) then\n    ()\n  else (\n    match rvalue_computation src actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces src_value ->\n        update_expression_maintains_variable_among_gvars v dst actor start_pc 0 bypassing_write_buffer src_value s\n  )\n\nlet nondeterministic_update_statement_computation_maintains_variable_among_gvars\n  (v: var_id_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (bypassing_write_buffer: bool)\n  (dst: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires variable_among_gvars s.mem v)\n          (ensures  (match nondeterministic_update_statement_computation actor nd start_pc bypassing_write_buffer\n                             dst s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> variable_among_gvars s'.mem v)) =\n  let cs' = nondeterministic_update_statement_computation actor nd start_pc bypassing_write_buffer dst s in\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (expression_to_td dst) then\n    ()\n  else (\n    let nd_value = Cons?.hd nd in\n    if not (object_value_has_all_pointers_uninitialized nd_value) then\n      ()\n    else\n      update_expression_maintains_variable_among_gvars v dst actor start_pc 0 bypassing_write_buffer nd_value s\n  )\n\nlet propagate_write_message_statement_computation_maintains_variable_among_gvars\n  (v: var_id_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (s: Armada.State.t)\n  : Lemma (requires variable_among_gvars s.mem v)\n          (ensures  (match propagate_write_message_statement_computation actor nd s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> variable_among_gvars s'.mem v)) =\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract tid_t) then\n     ()\n  else\n    let receiver_tid: tid_t = ObjectValueAbstract?.value (Cons?.hd nd) in\n    if receiver_tid = actor then // can't propagate to the same thread\n      ()\n    else\n      let propagator_thread = s.threads actor in\n      let receiver_thread = s.threads receiver_tid in\n      let which_message = receiver_thread.position_in_other_write_buffers actor in\n      if which_message >= length propagator_thread.write_buffer then\n        ()\n      else\n        let write_message = index propagator_thread.write_buffer which_message in\n        propagate_write_message_maintains_variable_among_gvars v write_message receiver_tid s.mem\n\nlet compare_and_swap_statement_computation_maintains_variable_among_gvars\n  (v: var_id_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (target: expression_t)\n  (old_val: expression_t)\n  (new_val: expression_t)\n  (bypassing_write_buffer: bool)\n  (optional_result: option expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires variable_among_gvars s.mem v)\n          (ensures  (match compare_and_swap_statement_computation actor nd start_pc target old_val new_val\n                             bypassing_write_buffer optional_result s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> variable_among_gvars s'.mem v)) =\n  let cs' = compare_and_swap_statement_computation actor nd start_pc target old_val new_val\n              bypassing_write_buffer optional_result s in\n  if   Cons? nd\n     || neqb (expression_to_td target) (expression_to_td old_val)\n     || neqb (expression_to_td target) (expression_to_td new_val)\n     || (match optional_result with\n        | Some result -> neqb (expression_to_td result) (ObjectTDPrimitive PrimitiveTDBool)\n        | None -> false) then\n    ()\n  else begin\n    match check_expression_up_to_date_for_rmw target actor s, rvalue_computation old_val actor s,\n          rvalue_computation target actor s, rvalue_computation new_val actor s,\n          lvalue_computation target actor s  with\n    | ComputationProduces _, ComputationProduces old_value,\n      ComputationProduces target_value, ComputationProduces new_value,\n      ComputationProduces target_ptr -> begin\n        let swap = eqb target_value old_value in\n        update_pointed_to_value_maintains_variable_among_gvars v target_ptr actor start_pc 0 false new_value s;\n        match optional_result with\n        | None -> ()\n        | Some result ->\n          match lvalue_computation result actor s, (if swap then update_pointed_to_value target_ptr actor start_pc 0 false new_value s else return s) with\n          | ComputationProduces result_ptr, ComputationProduces s' ->\n              let swap_value = ObjectValuePrimitive (PrimitiveBoxBool swap) in\n              update_pointed_to_value_maintains_variable_among_gvars v result_ptr actor start_pc 1 bypassing_write_buffer swap_value s'\n          | _ -> ()\n      end\n    | _ -> ()\n  end\n\nlet atomic_exchange_statement_computation_maintains_variable_among_gvars\n  (v: var_id_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (old_val: expression_t)\n  (target: expression_t)\n  (new_val: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires variable_among_gvars s.mem v)\n          (ensures  (match atomic_exchange_statement_computation actor nd start_pc old_val target new_val s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> variable_among_gvars s'.mem v)) =\n  let cs' = atomic_exchange_statement_computation actor nd start_pc old_val target new_val s in\n  match check_expression_up_to_date_for_rmw target actor s, rvalue_computation target actor s, rvalue_computation new_val actor s, lvalue_computation old_val actor s, lvalue_computation target actor s with\n  | ComputationProduces _, ComputationProduces target_value, ComputationProduces new_value, ComputationProduces old_ptr, ComputationProduces target_ptr ->\n    update_pointed_to_value_maintains_variable_among_gvars v old_ptr actor start_pc 0 false target_value s;\n    begin match update_pointed_to_value old_ptr actor start_pc 0 false target_value s with\n          | ComputationProduces s' ->\n            update_pointed_to_value_maintains_variable_among_gvars v target_ptr actor start_pc 1 false new_value s'\n          | _ -> ()\n    end\n  | _ -> ()\n\nlet create_thread_statement_computation_maintains_variable_among_gvars\n  (v: var_id_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (method_id: method_id_t)\n  (initial_pc: pc_t)\n  (bypassing_write_buffer: bool)\n  (optional_result: option expression_t)\n  (parameter_var_ids: list var_id_t)\n  (parameter_expressions: list expression_t)\n  (local_variable_initializers: list initializer_t)\n  (s: Armada.State.t)\n  : Lemma (requires variable_among_gvars s.mem v)\n          (ensures  (match create_thread_statement_computation actor nd start_pc method_id initial_pc\n                             bypassing_write_buffer optional_result parameter_var_ids parameter_expressions\n                             local_variable_initializers s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> variable_among_gvars s'.mem v)) =\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract create_thread_nd_t)\n     || (   Some? optional_result\n        && neqb (expression_to_td (Some?.v optional_result)) (ObjectTDPrimitive PrimitiveTDThreadId))\n     || list_len parameter_var_ids <> list_len parameter_expressions then\n    ()\n  else (\n    let create_thread_nd: create_thread_nd_t = ObjectValueAbstract?.value (Cons?.hd nd) in\n    let new_tid = create_thread_nd.new_tid in\n    if new_tid = 0 then\n      (match optional_result with\n       | None -> ()\n       | Some result ->\n          let new_tid_value = ObjectValuePrimitive (PrimitiveBoxThreadId new_tid) in\n          update_expression_maintains_variable_among_gvars v result actor start_pc\n            (list_len parameter_var_ids + list_len local_variable_initializers) bypassing_write_buffer\n            new_tid_value s)\n    else (\n      let frame_uniq = create_thread_nd.frame_uniq in\n      match rvalues_computation parameter_expressions actor s with\n      | ComputationImpossible | ComputationUndefined -> ()\n      | ComputationProduces parameter_values ->\n          let s2 = make_thread_running method_id initial_pc new_tid frame_uniq s in\n          push_stack_parameters_maintains_variable_among_gvars v new_tid start_pc 0 method_id\n            frame_uniq parameter_var_ids parameter_values s2;\n          (match push_stack_parameters new_tid start_pc 0 method_id frame_uniq parameter_var_ids\n                   parameter_values s2 with\n           | ComputationImpossible | ComputationUndefined -> ()\n           | ComputationProduces s3 ->\n                push_stack_variables_maintains_variable_among_gvars v new_tid start_pc\n                  (list_len parameter_var_ids) method_id frame_uniq local_variable_initializers s3;\n                (match push_stack_variables new_tid start_pc (list_len parameter_var_ids) method_id frame_uniq\n                         local_variable_initializers s3 with\n                 | ComputationImpossible | ComputationUndefined -> ()\n                 | ComputationProduces s4 ->\n                     (match optional_result with\n                      | None -> ()\n                      | Some result ->\n                         let new_tid_value = ObjectValuePrimitive (PrimitiveBoxThreadId new_tid) in\n                         update_expression_maintains_variable_among_gvars v result actor start_pc\n                           (list_len parameter_var_ids + list_len local_variable_initializers) bypassing_write_buffer\n                           new_tid_value s4)))\n    )\n  )\n\nlet method_call_statement_computation_maintains_variable_among_gvars\n  (v: var_id_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (method_id: method_id_t)\n  (return_pc: pc_t)\n  (parameter_var_ids: list var_id_t)\n  (parameter_expressions: list expression_t)\n  (local_variable_initializers: list initializer_t)\n  (stack_overflow: bool)\n  (s: Armada.State.t)\n  : Lemma (requires variable_among_gvars s.mem v)\n          (ensures  (match method_call_statement_computation actor nd start_pc method_id return_pc parameter_var_ids\n                             parameter_expressions local_variable_initializers stack_overflow s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> variable_among_gvars s'.mem v)) =\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract method_call_nd_t) then\n    ()\n  else (\n    let method_call_nd: method_call_nd_t = ObjectValueAbstract?.value (Cons?.hd nd) in\n    let frame_uniq = method_call_nd.frame_uniq in\n    match rvalues_computation parameter_expressions actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces parameter_values ->\n        let s2 = push_stack_frame actor method_id return_pc frame_uniq s in\n        push_stack_parameters_maintains_variable_among_gvars v actor start_pc 0 method_id frame_uniq\n          parameter_var_ids parameter_values s2;\n        (match push_stack_parameters actor start_pc 0 method_id frame_uniq parameter_var_ids parameter_values s2 with\n         | ComputationImpossible | ComputationUndefined -> ()\n         | ComputationProduces s3 ->\n             push_stack_variables_maintains_variable_among_gvars v actor start_pc\n               (list_len parameter_var_ids) method_id frame_uniq\n               local_variable_initializers s3)\n  )\n\nlet return_statement_computation_maintains_variable_among_gvars\n  (v: var_id_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (end_pc: option pc_t)\n  (method_id: method_id_t)\n  (bypassing_write_buffer: bool)\n  (output_dsts: list expression_t)\n  (output_srcs: list expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires variable_among_gvars s.mem v)\n          (ensures  (match return_statement_computation actor nd start_pc end_pc method_id bypassing_write_buffer\n                             output_dsts output_srcs s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> variable_among_gvars s'.mem v)) =\n  let thread = s.threads actor in\n  if   Cons? nd\n     || eqb thread.stack []\n     || thread.top.method_id <> method_id\n     || end_pc <> Some (Cons?.hd thread.stack).return_pc then\n    ()\n  else (\n    match rvalues_computation output_srcs actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces output_values ->\n        pop_stack_variables_maintains_variable_among_gvars v actor method_id thread.top.frame_uniq\n          thread.top.local_variables s.mem;\n        (match pop_stack_variables actor method_id thread.top.frame_uniq thread.top.local_variables s.mem with\n         | ComputationImpossible | ComputationUndefined -> ()\n         | ComputationProduces mem' ->\n             let s2 = pop_stack_frame actor mem' s in\n             update_expressions_maintains_variable_among_gvars v output_dsts actor\n               start_pc 0 bypassing_write_buffer output_values s2)\n  )\n\nlet terminate_thread_statement_computation_maintains_variable_among_gvars\n  (v: var_id_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (method_id: method_id_t)\n  (s: Armada.State.t)\n  : Lemma (requires variable_among_gvars s.mem v)\n          (ensures  (match terminate_thread_statement_computation actor nd start_pc method_id s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> variable_among_gvars s'.mem v)) =\n  let thread = s.threads actor in\n  if   Cons? nd\n     || neqb thread.stack []\n     || thread.top.method_id <> method_id\n     || actor = s.initial_tid then\n    ()\n  else\n    pop_stack_variables_maintains_variable_among_gvars v actor method_id thread.top.frame_uniq thread.top.local_variables s.mem\n\nlet terminate_process_statement_computation_maintains_variable_among_gvars\n  (v: var_id_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (method_id: method_id_t)\n  (s: Armada.State.t)\n  : Lemma (requires variable_among_gvars s.mem v)\n          (ensures  (match terminate_process_statement_computation actor nd start_pc method_id s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> variable_among_gvars s'.mem v)) =\n  ()\n\nlet join_statement_computation_maintains_variable_among_gvars\n  (v: var_id_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (join_tid: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires variable_among_gvars s.mem v)\n          (ensures  (match join_statement_computation actor nd start_pc join_tid s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> variable_among_gvars s'.mem v)) =\n  ()\n\nlet alloc_successful_statement_computation_maintains_variable_among_gvars\n  (v: var_id_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (zero_initialized: bool)\n  (bypassing_write_buffer: bool)\n  (result: expression_t)\n  (allocation_td: object_td_t)\n  (count: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires variable_among_gvars s.mem v)\n          (ensures  (match alloc_successful_statement_computation actor nd start_pc zero_initialized\n                             bypassing_write_buffer result allocation_td count s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> variable_among_gvars s'.mem v)) =\n  let cs' = alloc_successful_statement_computation actor nd start_pc zero_initialized bypassing_write_buffer result\n              allocation_td count s in\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract root_id_uniquifier_t)\n     || neqb (expression_to_td count) (ObjectTDAbstract nat)\n     || neqb (expression_to_td result) (ObjectTDPrimitive PrimitiveTDPointer) then\n    ()\n  else (\n    match rvalue_computation count actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces count_value ->\n        let sz = ObjectValueAbstract?.value count_value in\n        let array_td = ObjectTDArray allocation_td sz in\n        let uniq = ObjectValueAbstract?.value (Cons?.hd nd) in\n        let root_id = RootIdAllocation uniq in\n        (match s.mem root_id with\n         | RootAllocated allocated freed storage ->\n             if   allocated\n                || freed\n                || neqb (object_storage_to_td storage) array_td\n                || not (is_storage_ready_for_allocation storage)\n                || (not zero_initialized && not (object_storage_arbitrarily_initialized_correctly storage))\n                || (zero_initialized && not (is_storage_zero_filled storage)) then\n               ()\n             else (\n               let s' = mark_allocation_root_allocated uniq storage s in\n               let p = ObjectValuePrimitive (PrimitiveBoxPointer (PointerIndex (PointerRoot root_id) 0)) in\n               update_expression_maintains_variable_among_gvars v result actor start_pc 0 bypassing_write_buffer\n                 p s'\n             )\n         | _ -> ())\n  )\n\nlet alloc_returning_null_statement_computation_maintains_variable_among_gvars\n  (v: var_id_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (bypassing_write_buffer: bool)\n  (result: expression_t)\n  (count: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires variable_among_gvars s.mem v)\n          (ensures  (match alloc_returning_null_statement_computation actor nd start_pc bypassing_write_buffer\n                             result count s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> variable_among_gvars s'.mem v)) =\n  let s' = alloc_returning_null_statement_computation actor nd start_pc bypassing_write_buffer\n              result count s in\n  if   Cons? nd\n     || neqb (expression_to_td count) (ObjectTDAbstract nat)\n     || neqb (expression_to_td result) (ObjectTDPrimitive PrimitiveTDPointer) then\n    ()\n  else (\n    match rvalue_computation count actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces _ ->\n        let p = ObjectValuePrimitive (PrimitiveBoxPointer PointerNull) in\n        update_expression_maintains_variable_among_gvars v result actor start_pc 0 bypassing_write_buffer p s\n  )\n\nlet dealloc_statement_computation_maintains_variable_among_gvars\n  (v: var_id_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (ptr: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires variable_among_gvars s.mem v)\n          (ensures  (match dealloc_statement_computation actor nd start_pc ptr s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> variable_among_gvars s'.mem v)) =\n  if   Cons? nd\n     || neqb (expression_to_td ptr) (ObjectTDPrimitive PrimitiveTDPointer) then\n    ()\n  else (\n    match rvalue_computation ptr actor s with\n    | ComputationImpossible -> ()\n    | ComputationUndefined -> ()\n    | ComputationProduces ptr_value ->\n        let p = PrimitiveBoxPointer?.ptr (ObjectValuePrimitive?.value ptr_value) in\n        free_pointer_maintains_variable_among_gvars v p s.mem\n  )\n\nlet somehow_statement_computation_maintains_variable_among_gvars\n  (v: var_id_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (undefined_unless_cond: expression_t)\n  (bypassing_write_buffer: bool)\n  (modifies_clauses: list expression_t)\n  (ensures_cond: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires variable_among_gvars s.mem v)\n          (ensures  (match somehow_statement_computation actor nd start_pc undefined_unless_cond\n                             bypassing_write_buffer modifies_clauses ensures_cond s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> variable_among_gvars s'.mem v)) =\n  let cs' = somehow_statement_computation actor nd start_pc undefined_unless_cond bypassing_write_buffer\n              modifies_clauses ensures_cond s in\n  if   neqb (expression_to_td undefined_unless_cond) (ObjectTDPrimitive PrimitiveTDBool)\n     || neqb (expression_to_td ensures_cond) (ObjectTDPrimitive PrimitiveTDBool) then\n    ()\n  else (\n    match rvalue_computation undefined_unless_cond actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces undefined_unless_value ->\n        let undefined_unless_bool = PrimitiveBoxBool?.b (ObjectValuePrimitive?.value undefined_unless_value) in\n        if not undefined_unless_bool then\n          ()\n        else\n          update_expressions_maintains_variable_among_gvars v modifies_clauses actor start_pc 0\n            bypassing_write_buffer nd s\n  )\n\nlet fence_statement_computation_maintains_variable_among_gvars\n  (v: var_id_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (s: Armada.State.t)\n  : Lemma (requires variable_among_gvars s.mem v)\n          (ensures  (match fence_statement_computation actor nd start_pc s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> variable_among_gvars s'.mem v)) =\n  ()\n\nlet external_method_start_statement_computation_maintains_variable_among_gvars\n  (v: var_id_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (await_cond: expression_t)\n  (undefined_unless_cond: expression_t)\n  (bypassing_write_buffer: bool)\n  (modifies_clauses: list expression_t)\n  (reads_clauses: list (var_id_t * expression_t))\n  (s: Armada.State.t)\n  : Lemma (requires variable_among_gvars s.mem v)\n          (ensures  (match external_method_start_statement_computation actor nd start_pc await_cond\n                             undefined_unless_cond bypassing_write_buffer modifies_clauses reads_clauses s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> variable_among_gvars s'.mem v)) =\n  let cs' = external_method_start_statement_computation actor nd start_pc await_cond undefined_unless_cond\n              bypassing_write_buffer modifies_clauses reads_clauses s in\n  if   neqb (expression_to_td await_cond) (ObjectTDPrimitive PrimitiveTDBool)\n     || neqb (expression_to_td undefined_unless_cond) (ObjectTDPrimitive PrimitiveTDBool)\n     || list_len modifies_clauses <> list_len nd then\n    ()\n  else (\n    match rvalue_computation await_cond actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces await_value ->\n        let await_bool = PrimitiveBoxBool?.b (ObjectValuePrimitive?.value await_value) in\n        if not await_bool then\n          ()\n        else (\n          match rvalue_computation undefined_unless_cond actor s with\n          | ComputationImpossible | ComputationUndefined -> ()\n          | ComputationProduces undefined_unless_value ->\n              let undefined_unless_bool = PrimitiveBoxBool?.b (ObjectValuePrimitive?.value await_value) in\n              if not undefined_unless_bool then\n                ()\n              else (\n                update_expressions_maintains_variable_among_gvars v modifies_clauses actor start_pc 0\n                  bypassing_write_buffer nd s;\n                match update_expressions modifies_clauses actor start_pc 0 bypassing_write_buffer nd s with\n                | ComputationImpossible | ComputationUndefined -> ()\n                | ComputationProduces s' ->\n                    external_method_take_snapshot_of_reads_clauses_computation_maintains_variable_among_gvars\n                      v actor start_pc (list_len modifies_clauses) bypassing_write_buffer reads_clauses s'\n              )\n        )\n  )\n\nlet external_method_middle_statement_computation_maintains_variable_among_gvars\n  (v: var_id_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (bypassing_write_buffer: bool)\n  (modifies_clauses: list expression_t)\n  (reads_clauses: list (var_id_t * expression_t))\n  (s: Armada.State.t)\n  : Lemma (requires variable_among_gvars s.mem v)\n          (ensures  (match external_method_middle_statement_computation actor nd start_pc bypassing_write_buffer\n                             modifies_clauses reads_clauses s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> variable_among_gvars s'.mem v)) =\n  let cs' = external_method_middle_statement_computation actor nd start_pc bypassing_write_buffer\n              modifies_clauses reads_clauses s in\n  match external_method_check_snapshot_computation actor reads_clauses s with\n  | ComputationImpossible | ComputationUndefined -> ()\n  | ComputationProduces _ ->\n      update_expressions_maintains_variable_among_gvars v modifies_clauses actor start_pc 0\n        bypassing_write_buffer nd s;\n      (match update_expressions modifies_clauses actor start_pc 0 bypassing_write_buffer nd s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces s' ->\n           external_method_take_snapshot_of_reads_clauses_computation_maintains_variable_among_gvars\n             v actor start_pc (list_len modifies_clauses) bypassing_write_buffer reads_clauses s')\n\nlet external_method_end_statement_computation_maintains_variable_among_gvars\n  (v: var_id_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (ensures_cond: expression_t)\n  (logs_clauses: list expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires variable_among_gvars s.mem v)\n          (ensures  (match external_method_end_statement_computation actor nd start_pc ensures_cond logs_clauses s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> variable_among_gvars s'.mem v)) =\n  let cs' = external_method_end_statement_computation actor nd start_pc ensures_cond logs_clauses s in\n  if   Cons? nd\n     || neqb (expression_to_td ensures_cond) (ObjectTDPrimitive PrimitiveTDBool) then\n    ()\n  else (\n    match rvalue_computation ensures_cond actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces ensures_value ->\n        let ensures_bool = PrimitiveBoxBool?.b (ObjectValuePrimitive?.value ensures_value) in\n        log_expressions_computation_maintains_variable_among_gvars v actor logs_clauses s\n  )\n\n#pop-options\n\nlet executing_statement_maintains_variable_among_gvars\n  (v: var_id_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (end_pc: option pc_t)\n  (statement: Armada.Statement.t)\n  (s: Armada.State.t)\n  : Lemma (requires variable_among_gvars s.mem v)\n          (ensures  (match statement_computation actor nd start_pc end_pc statement s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> variable_among_gvars s'.mem v)) =\n  match statement_computation actor nd start_pc end_pc statement s with\n  | ComputationImpossible | ComputationUndefined -> ()\n  | ComputationProduces s' ->\n      (match statement with\n       | AssumeExpressionStatement exp ->\n           assume_expression_statement_computation_maintains_variable_among_gvars v actor nd start_pc exp s\n       | AssumePredicateStatement pred ->\n           assume_predicate_statement_computation_maintains_variable_among_gvars v actor nd start_pc pred s\n       | AssertTrueStatement exp ->\n           assert_true_statement_computation_maintains_variable_among_gvars v actor nd start_pc exp s\n       | AssertFalseStatement exp ->\n           assert_false_statement_computation_maintains_variable_among_gvars v actor nd start_pc exp s\n       | ConditionalJumpStatement cond ->\n           conditional_jump_statement_computation_maintains_variable_among_gvars v actor nd start_pc cond s\n       | UnconditionalJumpStatement ->\n           unconditional_jump_statement_computation_maintains_variable_among_gvars v actor nd start_pc s\n       | UpdateStatement bypassing_write_buffer dst src ->\n           update_statement_computation_maintains_variable_among_gvars v actor nd start_pc bypassing_write_buffer\n             dst src s\n       | NondeterministicUpdateStatement bypassing_write_buffer dst ->\n           nondeterministic_update_statement_computation_maintains_variable_among_gvars v actor nd start_pc\n             bypassing_write_buffer dst s\n       | PropagateWriteMessageStatement ->\n           propagate_write_message_statement_computation_maintains_variable_among_gvars v actor nd s\n       | CompareAndSwapStatement target old_val new_val bypassing_write_buffer optional_result ->\n           compare_and_swap_statement_computation_maintains_variable_among_gvars v actor nd start_pc target\n             old_val new_val bypassing_write_buffer optional_result s\n       | AtomicExchangeStatement old_val target new_val ->\n           atomic_exchange_statement_computation_maintains_variable_among_gvars v actor nd\n             start_pc old_val target new_val s\n       | CreateThreadStatement method_id initial_pc bypassing_write_buffer optional_result parameter_var_ids\n                               parameter_expressions local_variable_initializers ->\n           create_thread_statement_computation_maintains_variable_among_gvars v actor nd start_pc method_id\n             initial_pc bypassing_write_buffer optional_result parameter_var_ids parameter_expressions\n             local_variable_initializers s\n       | MethodCallStatement method_id return_pc parameter_var_ids parameter_expressions local_variable_initializers\n                               stack_overflow ->\n           method_call_statement_computation_maintains_variable_among_gvars v actor nd start_pc method_id return_pc\n             parameter_var_ids parameter_expressions local_variable_initializers stack_overflow s\n       | ReturnStatement method_id bypassing_write_buffer output_dsts output_srcs ->\n           return_statement_computation_maintains_variable_among_gvars v actor nd start_pc end_pc method_id\n             bypassing_write_buffer output_dsts output_srcs s\n       | TerminateThreadStatement method_id ->\n           terminate_thread_statement_computation_maintains_variable_among_gvars v actor nd start_pc method_id s\n       | TerminateProcessStatement method_id ->\n           terminate_process_statement_computation_maintains_variable_among_gvars v actor nd start_pc method_id s\n       | JoinStatement join_tid ->\n           join_statement_computation_maintains_variable_among_gvars v actor nd start_pc join_tid s\n       | MallocSuccessfulStatement bypassing_write_buffer result allocation_td count ->\n           alloc_successful_statement_computation_maintains_variable_among_gvars v actor nd start_pc false\n             bypassing_write_buffer result allocation_td count s\n       | MallocReturningNullStatement bypassing_write_buffer result count ->\n           alloc_returning_null_statement_computation_maintains_variable_among_gvars v actor nd start_pc\n             bypassing_write_buffer result count s\n       | CallocSuccessfulStatement bypassing_write_buffer result allocation_td count ->\n           alloc_successful_statement_computation_maintains_variable_among_gvars v actor nd start_pc true\n             bypassing_write_buffer result allocation_td count s\n       | CallocReturningNullStatement bypassing_write_buffer result count ->\n           alloc_returning_null_statement_computation_maintains_variable_among_gvars v actor nd start_pc\n             bypassing_write_buffer result count s\n       | DeallocStatement ptr ->\n           dealloc_statement_computation_maintains_variable_among_gvars v actor nd start_pc ptr s\n       | SomehowStatement undefined_unless_cond bypassing_write_buffer modifies_clauses ensures_cond ->\n           somehow_statement_computation_maintains_variable_among_gvars v actor nd start_pc undefined_unless_cond\n             bypassing_write_buffer modifies_clauses ensures_cond s\n       | FenceStatement ->\n           fence_statement_computation_maintains_variable_among_gvars v actor nd start_pc s\n       | ExternalMethodStartStatement await_cond undefined_unless_cond bypassing_write_buffer\n                                      modifies_clauses reads_clauses ->\n           external_method_start_statement_computation_maintains_variable_among_gvars v actor nd start_pc await_cond\n             undefined_unless_cond bypassing_write_buffer modifies_clauses reads_clauses s\n       | ExternalMethodMiddleStatement bypassing_write_buffer modifies_clauses reads_clauses ->\n           external_method_middle_statement_computation_maintains_variable_among_gvars v actor nd start_pc\n             bypassing_write_buffer modifies_clauses reads_clauses s\n       | ExternalMethodEndStatement ensures_cond logs_clauses ->\n           external_method_end_statement_computation_maintains_variable_among_gvars v actor nd start_pc ensures_cond\n             logs_clauses s\n      )     \n\nlet step_computation_maintains_variable_among_gvars\n  (v: var_id_t)\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (step: Armada.Step.t)\n  (s: Armada.State.t)\n  : Lemma (requires variable_among_gvars s.mem v)\n          (ensures  (match step_computation actor starts_atomic_block ends_atomic_block step s with\n                     | Some s' -> variable_among_gvars s'.mem v\n                     | None -> True)) =\n  match step_computation actor starts_atomic_block ends_atomic_block step s with\n  | None -> ()\n  | Some s' ->\n      let ps = step.action.program_statement in\n      let thread = s.threads actor in\n      executing_statement_maintains_variable_among_gvars v actor step.nd thread.pc ps.end_pc ps.statement s;\n      (match statement_computation actor step.nd thread.pc ps.end_pc ps.statement s with\n       | ComputationImpossible -> ()\n       | ComputationUndefined -> ()\n       | ComputationProduces s1 -> ())\n\nlet step_computation_maintains_all_variables_among_gvars\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (step: Armada.Step.t)\n  (s: Armada.State.t)\n  : Lemma (requires all_variables_among_gvars s.mem vs)\n          (ensures  (match step_computation actor starts_atomic_block ends_atomic_block step s with\n                     | Some s' -> all_variables_among_gvars s'.mem vs\n                     | None -> True)) =\n  match step_computation actor starts_atomic_block ends_atomic_block step s with\n  | None -> ()\n  | Some s' ->\n      introduce forall v. list_contains v vs /\\ variable_among_gvars s.mem v ==> variable_among_gvars s'.mem v\n      with introduce _ ==> _\n      with _.\n        step_computation_maintains_variable_among_gvars v actor starts_atomic_block ends_atomic_block step s\n"
  },
  {
    "path": "experimental/lib/Strategies.GlobalVars.Pointer.fst",
    "content": "module Strategies.GlobalVars.Pointer\n\nopen Armada.Base\nopen Armada.BinaryOp\nopen Armada.Computation\nopen Armada.Expression\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Pointer\nopen Armada.State\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Type\nopen Armada.UnaryOp\nopen FStar.Sequence.Ambient\nopen FStar.Sequence.Base\nopen Spec.List\nopen Spec.Ubool\nopen Strategies.ArmadaInvariant.PositionsValid\nopen Strategies.ArmadaInvariant.RootsMatch\nopen Strategies.GlobalVars\nopen Strategies.GlobalVars.Unaddressed\nopen Strategies.GlobalVars.Value\nopen Strategies.PCRelation\nopen Util.List\nopen Util.Nth\nopen Util.Seq\nopen Util.Trigger\n\n#push-options \"--z3rlimit 30\"\n\nlet rec dereference_computation_doesnt_depend_on_global_variables\n  (vs: list var_id_t)\n  (p: Armada.Pointer.t)\n  (mem1: Armada.Memory.t)\n  (mem2: Armada.Memory.t)\n  : Lemma (requires   memories_match_except_global_variables vs mem1 mem2\n                    /\\ global_variables_unaddressed_in_pointer vs p\n                    /\\ global_variables_unaddressed_in_memory vs mem1\n                    /\\ global_variables_unaddressed_in_memory vs mem2\n                    /\\ roots_match mem1\n                    /\\ roots_match mem2)\n          (ensures  dereference_computation p mem1 == dereference_computation p mem2\n                    /\\ (match dereference_computation p mem1 with\n                       | ComputationProduces storage -> global_variables_unaddressed_in_storage vs storage\n                       | _ -> True)) =\n  match p with\n  | PointerUninitialized -> ()\n  | PointerNull -> ()\n  | PointerRoot root_id -> ()\n  | PointerField struct_ptr field_id ->\n      dereference_computation_doesnt_depend_on_global_variables vs struct_ptr mem1 mem2\n  | PointerIndex array_ptr idx ->\n      dereference_computation_doesnt_depend_on_global_variables vs array_ptr mem1 mem2\n\nlet dereference_as_td_computation_doesnt_depend_on_global_variables\n  (vs: list var_id_t)\n  (p: Armada.Pointer.t)\n  (td: object_td_t)\n  (actor: tid_t)\n  (mem1: Armada.Memory.t)\n  (mem2: Armada.Memory.t)\n  : Lemma (requires   memories_match_except_global_variables vs mem1 mem2\n                    /\\ global_variables_unaddressed_in_pointer vs p\n                    /\\ global_variables_unaddressed_in_memory vs mem1\n                    /\\ global_variables_unaddressed_in_memory vs mem2\n                    /\\ roots_match mem1\n                    /\\ roots_match mem2)\n          (ensures  dereference_as_td_computation p td actor mem1 == dereference_as_td_computation p td actor mem2\n                    /\\ (match dereference_as_td_computation p td actor mem1 with\n                       | ComputationProduces value -> global_variables_unaddressed_in_object_value vs value\n                       | _ -> True)) =\n  dereference_computation_doesnt_depend_on_global_variables vs p mem1 mem2;\n  match dereference_computation p mem1 with\n  | ComputationProduces storage ->\n      global_variables_unaddressed_in_storage_implies_unaddressed_in_object_value vs actor storage\n  | _ -> ()\n\n#pop-options\n#push-options \"--z3rlimit 80\"\n\nlet rec rvalue_computation_doesnt_depend_on_global_variables\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (exp: expression_t)\n  (actor: tid_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   global_variables_unmentioned_in_expression vs exp\n                    /\\ states_match_except_global_variables vs pc_relation s1 s2\n                    /\\ global_variables_unaddressed_in_memory vs s1.mem\n                    /\\ global_variables_unaddressed_in_memory vs s2.mem\n                    /\\ roots_match s1.mem\n                    /\\ roots_match s2.mem\n                    /\\ ThreadStatusRunning? (s1.threads actor).status)\n          (ensures  rvalue_computation exp actor s1 == rvalue_computation exp actor s2\n                    /\\ (match rvalue_computation exp actor s1 with\n                       | ComputationProduces value -> global_variables_unaddressed_in_object_value vs value\n                       | _ -> True))\n          (decreases exp) =\n  if not (expression_valid exp) then\n    ()\n  else\n    match exp with\n    | ExpressionConstant value -> ()\n    | ExpressionGlobalVariable td var_id ->\n        dereference_as_td_computation_doesnt_depend_on_global_variables vs (PointerRoot (RootIdGlobal var_id)) td actor\n          s1.mem s2.mem\n    | ExpressionLocalVariable td var_id ->\n        let thread = s1.threads actor in\n        if list_contains var_id thread.top.local_variables then\n          dereference_as_td_computation_doesnt_depend_on_global_variables vs\n            (PointerRoot (RootIdStack actor thread.top.method_id thread.top.frame_uniq var_id)) td actor s1.mem s2.mem\n        else\n          ()\n    | ExpressionUnaryOperator _ _ operator operand ->\n        rvalue_computation_doesnt_depend_on_global_variables vs pc_relation operand actor s1 s2\n    | ExpressionBinaryOperator _ _ _ operator operand1 operand2 ->\n        rvalue_computation_doesnt_depend_on_global_variables vs pc_relation operand1 actor s1 s2;\n        rvalue_computation_doesnt_depend_on_global_variables vs pc_relation operand2 actor s1 s2\n    | ExpressionIf _ cond operand_then operand_else ->\n        rvalue_computation_doesnt_depend_on_global_variables vs pc_relation cond actor s1 s2;\n        rvalue_computation_doesnt_depend_on_global_variables vs pc_relation operand_then actor s1 s2;\n        rvalue_computation_doesnt_depend_on_global_variables vs pc_relation operand_else actor s1 s2\n    | ExpressionDereference td ptr ->\n        rvalue_computation_doesnt_depend_on_global_variables vs pc_relation ptr actor s1 s2;\n        (match rvalue_computation ptr actor s1 with\n         | ComputationUndefined | ComputationImpossible -> ()\n         | ComputationProduces ptr_value ->\n             let p = PrimitiveBoxPointer?.ptr (ObjectValuePrimitive?.value ptr_value) in\n             dereference_as_td_computation_doesnt_depend_on_global_variables vs p td actor s1.mem s2.mem)\n    | ExpressionAddressOf obj ->\n        lvalue_computation_doesnt_depend_on_global_variables vs pc_relation obj actor s1 s2\n    | ExpressionPointerOffset ptr offset ->\n        rvalue_computation_doesnt_depend_on_global_variables vs pc_relation ptr actor s1 s2;\n        rvalue_computation_doesnt_depend_on_global_variables vs pc_relation offset actor s1 s2;\n        (match rvalue_computation ptr actor s1 with\n         | ComputationUndefined | ComputationImpossible -> ()\n         | ComputationProduces ptr_value ->\n             (match rvalue_computation offset actor s1 with\n              | ComputationUndefined | ComputationImpossible -> ()\n              | ComputationProduces offset_value ->\n                  let p = PrimitiveBoxPointer?.ptr (ObjectValuePrimitive?.value ptr_value) in\n                  (match p with\n                   | PointerIndex array_ptr idx ->\n                       let offset_int = ObjectValueAbstract?.value offset_value in\n                       dereference_computation_doesnt_depend_on_global_variables vs array_ptr s1.mem s2.mem\n                   | _ -> ())))\n    | ExpressionFieldOf td obj field_id ->\n        lvalue_computation_doesnt_depend_on_global_variables vs pc_relation obj actor s1 s2;\n        (match lvalue_computation obj actor s1 with\n         | ComputationProduces obj_ptr ->\n             dereference_as_td_computation_doesnt_depend_on_global_variables vs (PointerField obj_ptr field_id)\n               td actor s1.mem s2.mem\n         | _ -> ())\n    | ExpressionAllocated ptr ->\n        rvalue_computation_doesnt_depend_on_global_variables vs pc_relation ptr actor s1 s2\n    | ExpressionApplyFunction td operands return_type operand_types fn ->\n        rvalues_computation_doesnt_depend_on_global_variables vs pc_relation operands actor s1 s2\n    | ExpressionIfUndefined td potentially_unsafe safe_substitution ->\n        rvalue_computation_doesnt_depend_on_global_variables vs pc_relation potentially_unsafe actor s1 s2;\n        rvalue_computation_doesnt_depend_on_global_variables vs pc_relation safe_substitution actor s1 s2\n    | ExpressionInitialTid -> ()\n    | ExpressionUniqsUsed -> ()\n    | ExpressionStopReason -> ()\n\nand lvalue_computation_doesnt_depend_on_global_variables\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (exp: expression_t)\n  (actor: tid_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   global_variables_unmentioned_in_expression vs exp\n                    /\\ states_match_except_global_variables vs pc_relation s1 s2\n                    /\\ global_variables_unaddressed_in_memory vs s1.mem\n                    /\\ global_variables_unaddressed_in_memory vs s2.mem\n                    /\\ roots_match s1.mem\n                    /\\ roots_match s2.mem\n                    /\\ ThreadStatusRunning? (s1.threads actor).status)\n          (ensures    lvalue_computation exp actor s1 == lvalue_computation exp actor s2\n                    /\\ (match lvalue_computation exp actor s1 with\n                       | ComputationProduces p -> global_variables_unaddressed_in_pointer vs p\n                       | _ -> True))\n          (decreases exp) =\n  match exp with\n  | ExpressionGlobalVariable _ var_id -> ()\n  | ExpressionLocalVariable _ var_id -> ()\n  | ExpressionDereference _ ptr ->\n      rvalue_computation_doesnt_depend_on_global_variables vs pc_relation ptr actor s1 s2\n  | ExpressionFieldOf td obj field_id ->\n      lvalue_computation_doesnt_depend_on_global_variables vs pc_relation obj actor s1 s2\n  | _ -> ()\n  \nand rvalues_computation_doesnt_depend_on_global_variables\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (exps: list expression_t)\n  (actor: tid_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   global_variables_unmentioned_in_expressions vs exps\n                    /\\ states_match_except_global_variables vs pc_relation s1 s2\n                    /\\ global_variables_unaddressed_in_memory vs s1.mem\n                    /\\ global_variables_unaddressed_in_memory vs s2.mem\n                    /\\ roots_match s1.mem\n                    /\\ roots_match s2.mem\n                    /\\ ThreadStatusRunning? (s1.threads actor).status)\n          (ensures  rvalues_computation exps actor s1 == rvalues_computation exps actor s2\n                    /\\ (match rvalues_computation exps actor s1 with\n                       | ComputationProduces values -> global_variables_unaddressed_in_object_values vs values\n                       | _ -> True))\n          (decreases exps) =\n  match exps with\n  | [] -> ()\n  | exp :: exps' ->\n      rvalue_computation_doesnt_depend_on_global_variables vs pc_relation exp actor s1 s2;\n      rvalues_computation_doesnt_depend_on_global_variables vs pc_relation exps' actor s1 s2\n\n#pop-options\n#push-options \"--z3rlimit 30\"\n\nlet rec update_pointer_directly_with_gvars_unaddressed_maintains_states_match\n  (vs: list var_id_t)\n  (p: Armada.Pointer.t)\n  (new_storage: valid_object_storage_t)\n  (mem1: Armada.Memory.t)\n  (mem2: Armada.Memory.t)\n  : Lemma (requires   global_variables_unaddressed_in_pointer vs p\n                    /\\ global_variables_unaddressed_in_storage vs new_storage\n                    /\\ global_variables_unaddressed_in_memory vs mem1\n                    /\\ global_variables_unaddressed_in_memory vs mem2\n                    /\\ memories_match_except_global_variables vs mem1 mem2\n                    /\\ roots_match mem1\n                    /\\ roots_match mem2)\n          (ensures  (match update_pointer_directly p new_storage mem1, update_pointer_directly p new_storage mem2 with\n                     | ComputationProduces mem1', ComputationProduces mem2' ->\n                           global_variables_unaddressed_in_memory vs mem1'\n                         /\\ global_variables_unaddressed_in_memory vs mem2'\n                         /\\ memories_match_except_global_variables vs mem1' mem2'\n                         /\\ roots_match mem1'\n                         /\\ roots_match mem2'\n                     | ComputationImpossible, ComputationImpossible -> True\n                     | ComputationUndefined, ComputationUndefined -> True\n                     | _ -> False)) =\n  match p with\n  | PointerUninitialized -> ()\n  | PointerNull -> ()\n  | PointerRoot root_id -> ()\n  | PointerField struct_ptr field_id ->\n      dereference_computation_doesnt_depend_on_global_variables vs struct_ptr mem1 mem2;\n      (match dereference_computation struct_ptr mem1 with\n       | ComputationProduces parent ->\n           (match parent with\n            | ObjectStorageStruct fields ->\n                if   field_id >= length fields\n                   || neqb (object_storage_to_td new_storage)\n                          (object_storage_to_td (index fields field_id)) then\n                  ()\n                else (\n                  let new_parent = update_storage_child parent field_id new_storage in\n                  update_pointer_directly_with_gvars_unaddressed_maintains_states_match vs struct_ptr\n                    new_parent mem1 mem2\n                )\n            | _ -> ())\n      | _ -> ())\n  | PointerIndex array_ptr idx ->\n      dereference_computation_doesnt_depend_on_global_variables vs array_ptr mem1 mem2;\n      (match dereference_computation array_ptr mem1 with\n       | ComputationProduces parent ->\n           (match parent with\n            | ObjectStorageArray element_td elements ->\n                if   idx < 0\n                   || idx >= length elements\n                   || neqb (object_storage_to_td new_storage) element_td then\n                  ()\n                else (\n                  let new_parent = update_storage_child parent idx new_storage in\n                  update_pointer_directly_with_gvars_unaddressed_maintains_states_match\n                    vs array_ptr new_parent mem1 mem2\n                )\n            | _ -> ())\n      | _ -> ())\n\nlet rec update_pointer_directly_s1_only_among_gvars_maintains_states_match\n  (vs: list var_id_t)\n  (p: Armada.Pointer.t)\n  (new_storage: valid_object_storage_t)\n  (mem1: Armada.Memory.t)\n  (mem2: Armada.Memory.t)\n  : Lemma (requires   not (global_variables_unaddressed_in_pointer vs p)\n                    /\\ global_variables_unaddressed_in_storage vs new_storage\n                    /\\ global_variables_unaddressed_in_memory vs mem1\n                    /\\ global_variables_unaddressed_in_memory vs mem2\n                    /\\ memories_match_except_global_variables vs mem1 mem2\n                    /\\ roots_match mem1\n                    /\\ roots_match mem2)\n          (ensures  (match update_pointer_directly p new_storage mem1 with\n                     | ComputationProduces mem1' ->\n                           global_variables_unaddressed_in_memory vs mem1'\n                         /\\ memories_match_except_global_variables vs mem1' mem2\n                         /\\ roots_match mem1'\n                     | ComputationImpossible -> True\n                     | ComputationUndefined -> True)) =\n  match p with\n  | PointerUninitialized -> ()\n  | PointerNull -> ()\n  | PointerRoot root_id -> ()\n  | PointerField struct_ptr field_id ->\n      dereference_computation_when_gvars_unaddressed_produces_storage_with_gvars_unaddressed vs struct_ptr mem1;\n      (match dereference_computation struct_ptr mem1 with\n       | ComputationProduces parent ->\n           (match parent with\n            | ObjectStorageStruct fields ->\n                if   field_id >= length fields\n                   || neqb (object_storage_to_td new_storage)\n                          (object_storage_to_td (index fields field_id)) then\n                  ()\n                else (\n                  let new_parent = update_storage_child parent field_id new_storage in\n                  update_pointer_directly_s1_only_among_gvars_maintains_states_match vs struct_ptr\n                    new_parent mem1 mem2\n                )\n            | _ -> ())\n      | _ -> ())\n  | PointerIndex array_ptr idx ->\n      dereference_computation_when_gvars_unaddressed_produces_storage_with_gvars_unaddressed vs array_ptr mem1;\n      (match dereference_computation array_ptr mem1 with\n       | ComputationProduces parent ->\n           (match parent with\n            | ObjectStorageArray element_td elements ->\n                if   idx < 0\n                   || idx >= length elements\n                   || neqb (object_storage_to_td new_storage) element_td then\n                  ()\n                else (\n                  let new_parent = update_storage_child parent idx new_storage in\n                  update_pointer_directly_s1_only_among_gvars_maintains_states_match\n                    vs array_ptr new_parent mem1 mem2\n                )\n            | _ -> ())\n      | _ -> ())\n\nlet rec update_pointer_directly_s2_only_among_gvars_maintains_states_match\n  (vs: list var_id_t)\n  (p: Armada.Pointer.t)\n  (new_storage: valid_object_storage_t)\n  (mem1: Armada.Memory.t)\n  (mem2: Armada.Memory.t)\n  : Lemma (requires   not (global_variables_unaddressed_in_pointer vs p)\n                    /\\ global_variables_unaddressed_in_storage vs new_storage\n                    /\\ global_variables_unaddressed_in_memory vs mem1\n                    /\\ global_variables_unaddressed_in_memory vs mem2\n                    /\\ memories_match_except_global_variables vs mem1 mem2\n                    /\\ roots_match mem1\n                    /\\ roots_match mem2)\n          (ensures  (match update_pointer_directly p new_storage mem2 with\n                     | ComputationProduces mem2' ->\n                           global_variables_unaddressed_in_memory vs mem2'\n                         /\\ memories_match_except_global_variables vs mem1 mem2'\n                         /\\ roots_match mem2'\n                     | ComputationImpossible -> True\n                     | ComputationUndefined -> True)) =\n  match p with\n  | PointerUninitialized -> ()\n  | PointerNull -> ()\n  | PointerRoot root_id -> ()\n  | PointerField struct_ptr field_id ->\n      dereference_computation_when_gvars_unaddressed_produces_storage_with_gvars_unaddressed vs struct_ptr mem2;\n      (match dereference_computation struct_ptr mem2 with\n       | ComputationProduces parent ->\n           (match parent with\n            | ObjectStorageStruct fields ->\n                if   field_id >= length fields\n                   || neqb (object_storage_to_td new_storage)\n                          (object_storage_to_td (index fields field_id)) then\n                  ()\n                else (\n                  let new_parent = update_storage_child parent field_id new_storage in\n                  update_pointer_directly_s2_only_among_gvars_maintains_states_match vs struct_ptr\n                    new_parent mem1 mem2\n                )\n            | _ -> ())\n      | _ -> ())\n  | PointerIndex array_ptr idx ->\n      dereference_computation_when_gvars_unaddressed_produces_storage_with_gvars_unaddressed vs array_ptr mem2;\n      (match dereference_computation array_ptr mem2 with\n       | ComputationProduces parent ->\n           (match parent with\n            | ObjectStorageArray element_td elements ->\n                if   idx < 0\n                   || idx >= length elements\n                   || neqb (object_storage_to_td new_storage) element_td then\n                  ()\n                else (\n                  let new_parent = update_storage_child parent idx new_storage in\n                  update_pointer_directly_s2_only_among_gvars_maintains_states_match\n                    vs array_ptr new_parent mem1 mem2\n                )\n            | _ -> ())\n      | _ -> ())\n\n#pop-options\n#push-options \"--z3rlimit 80\"\n\nlet update_pointer_with_object_lacking_pointer_field_maintains_states_match\n  (vs: list var_id_t)\n  (p: Armada.Pointer.t)\n  (actor: tid_t)\n  (writer_pc1: pc_t)\n  (writer_pc2: pc_t)\n  (writer_expression_number1: nat)\n  (writer_expression_number2: nat)\n  (bypassing_write_buffer: bool)\n  (td: object_td_t)\n  (new_value: valid_object_value_t td)\n  (mem1: Armada.Memory.t)\n  (mem2: Armada.Memory.t)\n  : Lemma (requires   memories_match_except_global_variables vs mem1 mem2\n                    /\\ global_variables_unaddressed_in_memory vs mem1\n                    /\\ global_variables_unaddressed_in_memory vs mem2\n                    /\\ roots_match mem1\n                    /\\ roots_match mem2\n                    /\\ object_td_lacks_pointer_field td\n                    /\\ global_variables_unaddressed_in_pointer vs p)\n          (ensures  (match update_pointer p actor writer_pc1 writer_expression_number1 bypassing_write_buffer\n                             new_value mem1,\n                           update_pointer p actor writer_pc2 writer_expression_number2 bypassing_write_buffer\n                             new_value mem2 with\n                     | ComputationProduces (optional_write_message1, mem1'),\n                       ComputationProduces (optional_write_message2, mem2') ->\n                           memories_match_except_global_variables vs mem1' mem2'\n                         /\\ global_variables_unaddressed_in_memory vs mem1'\n                         /\\ global_variables_unaddressed_in_memory vs mem2'\n                         /\\ roots_match mem1'\n                         /\\ roots_match mem2'\n                         /\\ (match optional_write_message1, optional_write_message2 with\n                            | Some write_message1, Some write_message2 ->\n                                write_messages_match write_message1 write_message2 \n                            | None, None -> True\n                            | _, _ -> False)\n                    | ComputationImpossible, ComputationImpossible -> True\n                    | ComputationUndefined, ComputationUndefined -> True\n                    | _ -> False)) =\n  match p with\n  | PointerUninitialized -> ()\n  | PointerNull -> ()\n  | PointerRoot root_id ->\n      let root = mem1 root_id in\n      (match root_to_storage_computation root with\n       | ComputationProduces storage ->\n           update_storage_lacking_pointer_field_maintains_gvars_unaddressed vs p actor writer_pc1\n             writer_expression_number1 bypassing_write_buffer storage td new_value;\n           update_storage_lacking_pointer_field_maintains_gvars_unaddressed vs p actor writer_pc2\n             writer_expression_number2 bypassing_write_buffer storage td new_value\n       | _ -> ())\n  | PointerField struct_ptr field_id ->\n      dereference_computation_doesnt_depend_on_global_variables vs struct_ptr mem1 mem2;\n      (match dereference_computation struct_ptr mem1 with\n       | ComputationProduces parent ->\n          (match parent with\n           | ObjectStorageStruct fields ->\n               if field_id >= length fields then\n                 ()\n               else\n                 let field = index fields field_id in\n                 if not (object_storage_valid field) || neqb (object_storage_to_td field) td then\n                   ()\n                 else (\n                   update_storage_lacking_pointer_field_maintains_gvars_unaddressed vs p actor writer_pc1\n                     writer_expression_number1 bypassing_write_buffer field td new_value;\n                   update_storage_lacking_pointer_field_maintains_gvars_unaddressed vs p actor writer_pc2\n                     writer_expression_number2 bypassing_write_buffer field td new_value;\n                   (match update_storage p actor writer_pc1 writer_expression_number1\n                            bypassing_write_buffer field new_value,\n                          update_storage p actor writer_pc2 writer_expression_number2\n                            bypassing_write_buffer field new_value with\n                    | ComputationProduces (write_message1, new_field1),\n                      ComputationProduces (write_message2, new_field2) ->\n                        assert (new_field1 == new_field2);\n                        if (not (can_update_storage_child parent field_id new_field1)) then\n                          ()\n                        else (\n                          update_storage_child_with_gvars_unaddressed_maintains_gvars_unaddressed\n                            vs parent field_id new_field1;\n                          let new_parent = update_storage_child parent field_id new_field1 in\n                          update_pointer_directly_with_gvars_unaddressed_maintains_states_match\n                            vs struct_ptr new_parent mem1 mem2\n                        )\n                    | _, _ -> ()\n                   ))\n          | _ -> ())\n       | _ -> ())\n  | PointerIndex array_ptr idx ->\n      dereference_computation_doesnt_depend_on_global_variables vs array_ptr mem1 mem2;\n      (match dereference_computation array_ptr mem1 with\n       | ComputationProduces parent ->\n          (match parent with\n           | ObjectStorageArray element_td elements ->\n               if idx < 0 || idx >= length elements then\n                 ()\n               else\n                 let element = index elements idx in\n                 if not (object_storage_valid element) then\n                   ()\n                 else (\n                   update_storage_lacking_pointer_field_maintains_gvars_unaddressed vs p actor writer_pc1\n                     writer_expression_number1 bypassing_write_buffer element td new_value;\n                   update_storage_lacking_pointer_field_maintains_gvars_unaddressed vs p actor writer_pc2\n                     writer_expression_number2 bypassing_write_buffer element td new_value;\n                   (match update_storage p actor writer_pc1 writer_expression_number1\n                            bypassing_write_buffer element new_value,\n                          update_storage p actor writer_pc2 writer_expression_number2\n                            bypassing_write_buffer element new_value with\n                    | ComputationProduces (write_message1, new_element1),\n                      ComputationProduces (write_message2, new_element2) ->\n                        assert (new_element1 == new_element2);\n                        if not (can_update_storage_child parent idx new_element1) then\n                          ()\n                        else (\n                          update_storage_child_with_gvars_unaddressed_maintains_gvars_unaddressed\n                            vs parent idx new_element1;\n                          let new_parent = update_storage_child parent idx new_element1 in\n                          update_pointer_directly_with_gvars_unaddressed_maintains_states_match\n                            vs array_ptr new_parent mem1 mem2\n                        )\n                    | _, _ -> ()\n                   ))\n          | _ -> ())\n       | _ -> ())\n\nlet update_pointer_with_object_with_gvars_unaddressed_maintains_states_match\n  (vs: list var_id_t)\n  (p: Armada.Pointer.t)\n  (actor: tid_t)\n  (writer_pc1: pc_t)\n  (writer_pc2: pc_t)\n  (writer_expression_number1: nat)\n  (writer_expression_number2: nat)\n  (bypassing_write_buffer: bool)\n  (new_value: object_value_t)\n  (mem1: Armada.Memory.t)\n  (mem2: Armada.Memory.t)\n  : Lemma (requires   memories_match_except_global_variables vs mem1 mem2\n                    /\\ global_variables_unaddressed_in_memory vs mem1\n                    /\\ global_variables_unaddressed_in_memory vs mem2\n                    /\\ roots_match mem1\n                    /\\ roots_match mem2\n                    /\\ global_variables_unaddressed_in_object_value vs new_value\n                    /\\ global_variables_unaddressed_in_pointer vs p)\n          (ensures  (match update_pointer p actor writer_pc1 writer_expression_number1 bypassing_write_buffer\n                             new_value mem1,\n                           update_pointer p actor writer_pc2 writer_expression_number2 bypassing_write_buffer\n                             new_value mem2 with\n                     | ComputationProduces (optional_write_message1, mem1'),\n                       ComputationProduces (optional_write_message2, mem2') ->\n                           memories_match_except_global_variables vs mem1' mem2'\n                         /\\ global_variables_unaddressed_in_memory vs mem1'\n                         /\\ global_variables_unaddressed_in_memory vs mem2'\n                         /\\ roots_match mem1'\n                         /\\ roots_match mem2'\n                         /\\ (match optional_write_message1, optional_write_message2 with\n                            | Some write_message1, Some write_message2 ->\n                                write_messages_match write_message1 write_message2 \n                            | None, None -> True\n                            | _, _ -> False)\n                     | ComputationImpossible, ComputationImpossible -> True\n                     | ComputationUndefined, ComputationUndefined -> True\n                     | _ -> False)) =\n  match p with\n  | PointerUninitialized -> ()\n  | PointerNull -> ()\n  | PointerRoot root_id ->\n      let root = mem1 root_id in\n      (match root_to_storage_computation root with\n       | ComputationProduces storage ->\n           update_storage_with_gvars_unaddressed_maintains_gvars_unaddressed vs p actor writer_pc1\n             writer_expression_number1 bypassing_write_buffer storage new_value;\n           update_storage_with_gvars_unaddressed_maintains_gvars_unaddressed vs p actor writer_pc2\n             writer_expression_number2 bypassing_write_buffer storage new_value\n       | _ -> ())\n  | PointerField struct_ptr field_id ->\n      dereference_computation_doesnt_depend_on_global_variables vs struct_ptr mem1 mem2;\n      (match dereference_computation struct_ptr mem1 with\n       | ComputationProduces parent ->\n          (match parent with\n           | ObjectStorageStruct fields ->\n               if field_id >= length fields then\n                 ()\n               else\n                 let field = index fields field_id in\n                 if   not (object_storage_valid field)\n                    || neqb (object_storage_to_td field) (object_value_to_td new_value) then\n                   ()\n                 else (\n                   update_storage_with_gvars_unaddressed_maintains_gvars_unaddressed vs p actor writer_pc1\n                     writer_expression_number1 bypassing_write_buffer field new_value;\n                   update_storage_with_gvars_unaddressed_maintains_gvars_unaddressed vs p actor writer_pc2\n                     writer_expression_number2 bypassing_write_buffer field new_value;\n                   (match update_storage p actor writer_pc1 writer_expression_number1\n                            bypassing_write_buffer field new_value,\n                          update_storage p actor writer_pc2 writer_expression_number2\n                            bypassing_write_buffer field new_value with\n                    | ComputationProduces (write_message1, new_field1),\n                      ComputationProduces (write_message2, new_field2) ->\n                        assert (new_field1 == new_field2);\n                        if (not (can_update_storage_child parent field_id new_field1)) then\n                          ()\n                        else (\n                          update_storage_child_with_gvars_unaddressed_maintains_gvars_unaddressed\n                            vs parent field_id new_field1;\n                          let new_parent = update_storage_child parent field_id new_field1 in\n                          update_pointer_directly_with_gvars_unaddressed_maintains_states_match\n                            vs struct_ptr new_parent mem1 mem2\n                        )\n                    | _, _ -> ()\n                   ))\n          | _ -> ())\n       | _ -> ())\n  | PointerIndex array_ptr idx ->\n      dereference_computation_doesnt_depend_on_global_variables vs array_ptr mem1 mem2;\n      (match dereference_computation array_ptr mem1 with\n       | ComputationProduces parent ->\n          (match parent with\n           | ObjectStorageArray element_td elements ->\n               if idx < 0 || idx >= length elements then\n                 ()\n               else\n                 let element = index elements idx in\n                 if not (object_storage_valid element) then\n                   ()\n                 else (\n                   update_storage_with_gvars_unaddressed_maintains_gvars_unaddressed vs p actor writer_pc1\n                     writer_expression_number1 bypassing_write_buffer element new_value;\n                   update_storage_with_gvars_unaddressed_maintains_gvars_unaddressed vs p actor writer_pc2\n                     writer_expression_number2 bypassing_write_buffer element new_value;\n                   (match update_storage p actor writer_pc1 writer_expression_number1\n                            bypassing_write_buffer element new_value,\n                          update_storage p actor writer_pc2 writer_expression_number2\n                            bypassing_write_buffer element new_value with\n                    | ComputationProduces (write_message1, new_element1),\n                      ComputationProduces (write_message2, new_element2) ->\n                        assert (new_element1 == new_element2);\n                        if not (can_update_storage_child parent idx new_element1) then\n                          ()\n                        else (\n                          update_storage_child_with_gvars_unaddressed_maintains_gvars_unaddressed\n                            vs parent idx new_element1;\n                          let new_parent = update_storage_child parent idx new_element1 in\n                          update_pointer_directly_with_gvars_unaddressed_maintains_states_match\n                            vs array_ptr new_parent mem1 mem2\n                        )\n                    | _, _ -> ()\n                   ))\n          | _ -> ())\n       | _ -> ())\n\n#pop-options\n\nlet unread_write_buffer_commutes_with_append\n  (threads: Armada.Threads.t{positions_valid_in_threads threads})\n  (sender_tid: tid_t)\n  (receiver_tid: tid_t)\n  (write_message: write_message_t)\n  : Lemma (requires positions_valid_in_threads threads)\n          (ensures  (let threads' = append_to_thread_write_buffer threads sender_tid write_message in\n                       positions_valid_in_threads threads'\n                     /\\ unread_write_buffer threads' sender_tid receiver_tid ==\n                         build (unread_write_buffer threads sender_tid receiver_tid) write_message)) =\n  assert (sender_receiver_trigger sender_tid receiver_tid)\n\nlet rec append_effect_on_remove_global_variables_from_write_buffer_list\n  (vs: list var_id_t)\n  (write_messages: list write_message_t)\n  (write_message: write_message_t)\n  : Lemma (ensures   remove_global_variables_from_write_buffer vs\n                       (FStar.List.Tot.append write_messages [write_message])\n                   == (if global_variables_unaddressed_in_write_message vs write_message then\n                         FStar.List.Tot.append (remove_global_variables_from_write_buffer vs write_messages)\n                           [write_message]\n                       else \n                         remove_global_variables_from_write_buffer vs write_messages)) =\n  match write_messages with\n  | [] -> ()\n  | hd :: tl -> append_effect_on_remove_global_variables_from_write_buffer_list vs tl write_message\n\nlet rec append_message_preserves_write_buffer_lists_match\n  (write_buffer1: list write_message_t)\n  (write_buffer2: list write_message_t)\n  (write_message1: write_message_t)\n  (write_message2: write_message_t)\n  : Lemma (requires   write_buffers_match write_buffer1 write_buffer2\n                    /\\ write_messages_match write_message1 write_message2)\n          (ensures  (let write_buffer1' = FStar.List.Tot.append write_buffer1 [write_message1] in\n                     let write_buffer2' = FStar.List.Tot.append write_buffer2 [write_message2] in\n                     write_buffers_match write_buffer1' write_buffer2')) =\n  match write_buffer1, write_buffer2 with\n  | [], [] -> ()\n  | hd1 :: tl1, hd2 :: tl2 -> append_message_preserves_write_buffer_lists_match tl1 tl2 write_message1 write_message2\n  | _, _ -> false_elim()\n\nlet append_preserves_write_buffer_lists_match_except_global_variables\n  (vs: list var_id_t)\n  (write_buffer1: list write_message_t)\n  (write_buffer2: list write_message_t)\n  (write_message1: write_message_t)\n  (write_message2: write_message_t)\n  : Lemma (requires write_buffers_match (remove_global_variables_from_write_buffer vs write_buffer1)\n                      (remove_global_variables_from_write_buffer vs write_buffer2)\n                    /\\ write_messages_match write_message1 write_message2)\n          (ensures  (let write_buffer1' = FStar.List.Tot.append write_buffer1 [write_message1] in\n                     let write_buffer2' = FStar.List.Tot.append write_buffer2 [write_message2] in\n                     write_buffers_match (remove_global_variables_from_write_buffer vs write_buffer1')\n                       (remove_global_variables_from_write_buffer vs write_buffer2'))) =\n  append_effect_on_remove_global_variables_from_write_buffer_list vs write_buffer1 write_message1;\n  append_effect_on_remove_global_variables_from_write_buffer_list vs write_buffer2 write_message2;\n  append_message_preserves_write_buffer_lists_match (remove_global_variables_from_write_buffer vs write_buffer1)\n    (remove_global_variables_from_write_buffer vs write_buffer2) write_message1 write_message2\n\nlet append_preserves_write_buffers_match_except_global_variables\n  (vs: list var_id_t)\n  (write_buffer1: seq write_message_t)\n  (write_buffer2: seq write_message_t)\n  (write_message1: write_message_t)\n  (write_message2: write_message_t)\n  : Lemma (requires   write_buffers_match_except_global_variables vs write_buffer1 write_buffer2\n                    /\\ write_messages_match write_message1 write_message2)\n          (ensures  (let write_buffer1' = build write_buffer1 write_message1 in\n                     let write_buffer2' = build write_buffer2 write_message2 in\n                     write_buffers_match_except_global_variables vs write_buffer1' write_buffer2'))\n          (decreases length write_buffer1 + length write_buffer2) =\n  build_equivalent_to_append write_buffer1 write_message1;\n  build_equivalent_to_append write_buffer2 write_message2;\n  append_preserves_write_buffer_lists_match_except_global_variables vs (seq_to_list write_buffer1)\n    (seq_to_list write_buffer2) write_message1 write_message2\n\nlet adding_write_message_unaddressing_gvars_maintains_positions_in_write_buffer_matches_for_actor\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (write_message1: write_message_t)\n  (write_message2: write_message_t)\n  (threads1: Armada.Threads.t)\n  (threads2: Armada.Threads.t)\n  (receiver_tid: tid_t)\n  : Lemma (requires   positions_valid_in_threads threads1\n                    /\\ positions_valid_in_threads threads2\n                    /\\ threads_match_except_global_variables vs pc_relation threads1 threads2\n                    /\\ global_variables_unaddressed_in_write_message vs write_message1\n                    /\\ write_messages_match write_message1 write_message2\n                    /\\ positions_valid_in_threads threads1\n                    /\\ positions_valid_in_threads threads2)\n          (ensures  (let threads1' = append_to_thread_write_buffer threads1 actor write_message1 in\n                     let threads2' = append_to_thread_write_buffer threads2 actor write_message2 in\n                       positions_valid_in_threads threads1'\n                     /\\ positions_valid_in_threads threads2'\n                     /\\ write_buffers_match_except_global_variables vs\n                         (unread_write_buffer threads1' actor receiver_tid)\n                         (unread_write_buffer threads2' actor receiver_tid))) =\n  assert (sender_receiver_trigger actor receiver_tid);\n  append_preserves_write_buffers_match_except_global_variables vs\n    (unread_write_buffer threads1 actor receiver_tid)\n    (unread_write_buffer threads2 actor receiver_tid)\n    write_message1\n    write_message2;\n  unread_write_buffer_commutes_with_append threads1 actor receiver_tid write_message1;\n  unread_write_buffer_commutes_with_append threads2 actor receiver_tid write_message2\n\n#push-options \"--z3rlimit 20\"\n\nlet adding_write_message_unaddressing_gvars_maintains_positions_in_write_buffer_matches\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (write_message1: write_message_t)\n  (write_message2: write_message_t)\n  (threads1: Armada.Threads.t)\n  (threads2: Armada.Threads.t)\n  (sender_tid: tid_t)\n  (receiver_tid: tid_t)\n  : Lemma (requires   global_variables_unaddressed_in_write_message vs write_message1\n                    /\\ write_messages_match write_message1 write_message2\n                    /\\ positions_valid_in_threads threads1\n                    /\\ positions_valid_in_threads threads2\n                    /\\ threads_match_except_global_variables vs pc_relation threads1 threads2)\n          (ensures  (let threads1' = append_to_thread_write_buffer threads1 actor write_message1 in\n                     let threads2' = append_to_thread_write_buffer threads2 actor write_message2 in\n                      positions_valid_in_threads threads1'\n                     /\\ positions_valid_in_threads threads2'\n                     /\\ (write_buffers_match_except_global_variables vs\n                         (unread_write_buffer threads1' sender_tid receiver_tid)\n                         (unread_write_buffer threads2' sender_tid receiver_tid)))) =\n  if sender_tid <> actor then\n    assert (sender_receiver_trigger sender_tid receiver_tid)\n  else\n    adding_write_message_unaddressing_gvars_maintains_positions_in_write_buffer_matches_for_actor vs pc_relation\n      actor write_message1 write_message2 threads1 threads2 receiver_tid\n\n#pop-options\n\nlet adding_write_message_unaddressing_gvars_maintains_positions_in_write_buffers_match\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (write_message1: write_message_t)\n  (write_message2: write_message_t)\n  (threads1: Armada.Threads.t)\n  (threads2: Armada.Threads.t)\n  : Lemma (requires   positions_valid_in_threads threads1\n                    /\\ positions_valid_in_threads threads2\n                    /\\ threads_match_except_global_variables vs pc_relation threads1 threads2\n                    /\\ global_variables_unaddressed_in_write_message vs write_message1\n                    /\\ write_messages_match write_message1 write_message2)\n          (ensures  (let threads1' = append_to_thread_write_buffer threads1 actor write_message1 in\n                     let threads2' = append_to_thread_write_buffer threads2 actor write_message2 in\n                       positions_valid_in_threads threads1'\n                     /\\ positions_valid_in_threads threads2'\n                     /\\ positions_in_write_buffers_match_except_global_variables vs threads1' threads2')) =\n  let threads1' = append_to_thread_write_buffer threads1 actor write_message1 in\n  let threads2' = append_to_thread_write_buffer threads2 actor write_message2 in\n  introduce forall sender_tid receiver_tid.\n               write_buffers_match_except_global_variables vs\n                 (unread_write_buffer threads1' sender_tid receiver_tid)\n                 (unread_write_buffer threads2' sender_tid receiver_tid)\n  with adding_write_message_unaddressing_gvars_maintains_positions_in_write_buffer_matches vs pc_relation actor\n         write_message1 write_message2 threads1 threads2 sender_tid receiver_tid\n\nlet adding_write_message_unaddressing_gvars_maintains_positions_in_write_buffers_match_and_positions_valid\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (write_message1: write_message_t)\n  (write_message2: write_message_t)\n  (threads1: Armada.Threads.t)\n  (threads2: Armada.Threads.t)\n  : Lemma (requires   positions_valid_in_threads threads1\n                    /\\ positions_valid_in_threads threads2\n                    /\\ threads_match_except_global_variables vs pc_relation threads1 threads2\n                    /\\ global_variables_unaddressed_in_write_message vs write_message1\n                    /\\ write_messages_match write_message1 write_message2)\n          (ensures  (let threads1' = append_to_thread_write_buffer threads1 actor write_message1 in\n                     let threads2' = append_to_thread_write_buffer threads2 actor write_message2 in\n                       positions_valid_in_threads threads1'\n                     /\\ positions_valid_in_threads threads2'\n                     /\\ positions_in_write_buffers_match_except_global_variables vs threads1' threads2')) =\n  adding_write_message_unaddressing_gvars_maintains_positions_in_write_buffers_match vs pc_relation actor\n    write_message1 write_message2 threads1 threads2\n\n#push-options \"--z3rlimit 50\"\n\nlet update_pointed_to_value_lacking_pointer_field_maintains_states_match\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (p: Armada.Pointer.t)\n  (actor: tid_t)\n  (writer_pc1: pc_t)\n  (writer_pc2: pc_t)\n  (writer_expression_number1: nat)\n  (writer_expression_number2: nat)\n  (bypassing_write_buffer: bool)\n  (td: object_td_t)\n  (new_value: valid_object_value_t td)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   states_match_except_global_variables vs pc_relation s1 s2\n                    /\\ global_variables_unaddressed_in_memory vs s1.mem\n                    /\\ global_variables_unaddressed_in_memory vs s2.mem\n                    /\\ roots_match s1.mem\n                    /\\ roots_match s2.mem\n                    /\\ object_td_lacks_pointer_field td\n                    /\\ global_variables_unaddressed_in_pointer vs p)\n          (ensures  (match update_pointed_to_value p actor writer_pc1 writer_expression_number1 bypassing_write_buffer\n                             new_value s1,\n                           update_pointed_to_value p actor writer_pc2 writer_expression_number2 bypassing_write_buffer\n                             new_value s2 with\n                     | ComputationProduces s1', ComputationProduces s2' ->\n                           states_match_except_global_variables vs pc_relation s1' s2'\n                         /\\ global_variables_unaddressed_in_memory vs s1'.mem\n                         /\\ global_variables_unaddressed_in_memory vs s2'.mem\n                         /\\ roots_match s1'.mem\n                         /\\ roots_match s2'.mem\n                     | ComputationImpossible, ComputationImpossible -> True\n                     | ComputationUndefined, ComputationUndefined -> True\n                     | _ -> False)) =\n  update_pointer_with_object_lacking_pointer_field_maintains_states_match vs p actor writer_pc1 writer_pc2\n    writer_expression_number1 writer_expression_number2 bypassing_write_buffer td new_value s1.mem s2.mem;\n  match update_pointer p actor writer_pc1 writer_expression_number1 bypassing_write_buffer new_value s1.mem,\n        update_pointer p actor writer_pc2 writer_expression_number2 bypassing_write_buffer new_value s2.mem with\n  | ComputationProduces (optional_write_message1, new_mem1), ComputationProduces (optional_write_message2, new_mem2) ->\n      (match optional_write_message1, optional_write_message2 with\n       | Some write_message1, Some write_message2 ->\n           let thread1 = s1.threads actor in\n           let new_write_buffer1 = build thread1.write_buffer write_message1 in\n           let new_thread1 = { thread1 with write_buffer = new_write_buffer1 } in\n           let new_threads1 = Spec.Map.upd s1.threads actor new_thread1 in\n           let s1' = { s1 with mem = new_mem1; threads = new_threads1; } in\n           let s2' = ComputationProduces?.result (update_pointed_to_value p actor writer_pc2 writer_expression_number2\n                                                    bypassing_write_buffer new_value s2) in\n           adding_write_message_unaddressing_gvars_maintains_positions_in_write_buffers_match_and_positions_valid\n             vs pc_relation actor write_message1 write_message2 s1.threads s2.threads;\n           assert (global_variables_unaddressed_in_memory vs s1'.mem);\n           assert (global_variables_unaddressed_in_memory vs s2'.mem);\n           assert (states_match_except_global_variables vs pc_relation s1' s2')\n       | None, None ->\n           let s1' = { s1 with mem = new_mem1; } in\n           let s2' = ComputationProduces?.result (update_pointed_to_value p actor writer_pc2 writer_expression_number2\n                                                    bypassing_write_buffer new_value s2) in\n           assert (global_variables_unaddressed_in_memory vs s1'.mem);\n           assert (global_variables_unaddressed_in_memory vs s2'.mem);\n           assert (states_match_except_global_variables vs pc_relation s1' s2')\n       | _, _ -> false_elim()\n      )\n  | _, _ -> ()\n\nlet update_pointed_to_value_with_gvars_unaddressed_maintains_states_match\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (p: Armada.Pointer.t)\n  (actor: tid_t)\n  (writer_pc1: pc_t)\n  (writer_pc2: pc_t)\n  (writer_expression_number1: nat)\n  (writer_expression_number2: nat)\n  (bypassing_write_buffer: bool)\n  (new_value: object_value_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   states_match_except_global_variables vs pc_relation s1 s2\n                    /\\ global_variables_unaddressed_in_memory vs s1.mem\n                    /\\ global_variables_unaddressed_in_memory vs s2.mem\n                    /\\ roots_match s1.mem\n                    /\\ roots_match s2.mem\n                    /\\ global_variables_unaddressed_in_object_value vs new_value\n                    /\\ global_variables_unaddressed_in_pointer vs p)\n          (ensures  (match update_pointed_to_value p actor writer_pc1 writer_expression_number1 bypassing_write_buffer\n                             new_value s1,\n                           update_pointed_to_value p actor writer_pc2 writer_expression_number2 bypassing_write_buffer\n                             new_value s2 with\n                     | ComputationProduces s1', ComputationProduces s2' ->\n                           states_match_except_global_variables vs pc_relation s1' s2'\n                         /\\ global_variables_unaddressed_in_memory vs s1'.mem\n                         /\\ global_variables_unaddressed_in_memory vs s2'.mem\n                         /\\ roots_match s1'.mem\n                         /\\ roots_match s2'.mem\n                     | ComputationImpossible, ComputationImpossible -> True\n                     | ComputationUndefined, ComputationUndefined -> True\n                     | _ -> False)) =\n  update_pointer_with_object_with_gvars_unaddressed_maintains_states_match vs p actor writer_pc1 writer_pc2\n    writer_expression_number1 writer_expression_number2 bypassing_write_buffer new_value s1.mem s2.mem;\n  match update_pointer p actor writer_pc1 writer_expression_number1 bypassing_write_buffer new_value s1.mem,\n        update_pointer p actor writer_pc2 writer_expression_number2 bypassing_write_buffer new_value s2.mem with\n  | ComputationProduces (optional_write_message1, new_mem1), ComputationProduces (optional_write_message2, new_mem2) ->\n      (match optional_write_message1, optional_write_message2 with\n       | Some write_message1, Some write_message2 ->\n           let thread = s1.threads actor in\n           let new_write_buffer = build thread.write_buffer write_message1 in\n           let new_thread = { thread with write_buffer = new_write_buffer } in\n           let new_threads = Spec.Map.upd s1.threads actor new_thread in\n           let s1' = { s1 with mem = new_mem1; threads = new_threads; } in\n           let s2' = ComputationProduces?.result (update_pointed_to_value p actor writer_pc2 writer_expression_number2\n                                                    bypassing_write_buffer new_value s2) in\n           adding_write_message_unaddressing_gvars_maintains_positions_in_write_buffers_match_and_positions_valid\n             vs pc_relation actor write_message1 write_message2 s1.threads s2.threads;\n           assert (global_variables_unaddressed_in_memory vs s1'.mem);\n           assert (global_variables_unaddressed_in_memory vs s2'.mem);\n           assert (states_match_except_global_variables vs pc_relation s1' s2');\n           assert (roots_match s1'.mem);\n           assert (roots_match s2'.mem)\n       | None, None ->\n           let s1' = { s1 with mem = new_mem1; } in\n           let s2' = ComputationProduces?.result (update_pointed_to_value p actor writer_pc2 writer_expression_number2\n                                                    bypassing_write_buffer new_value s2) in\n           assert (global_variables_unaddressed_in_memory vs s1'.mem);\n           assert (global_variables_unaddressed_in_memory vs s2'.mem);\n           assert (states_match_except_global_variables vs pc_relation s1' s2');\n           assert (roots_match s1'.mem);\n           assert (roots_match s2'.mem)\n       | _, _ -> false_elim ()\n      )\n  | _, _ -> ()\n\n#pop-options\n"
  },
  {
    "path": "experimental/lib/Strategies.GlobalVars.Statement.fst",
    "content": "module Strategies.GlobalVars.Statement\n\nopen Armada.Base\nopen Armada.BinaryOp\nopen Armada.Computation\nopen Armada.Expression\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Pointer\nopen Armada.State\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Type\nopen Armada.UnaryOp\nopen FStar.Sequence.Ambient\nopen FStar.Sequence.Base\nopen Spec.List\nopen Spec.Ubool\nopen Strategies.ArmadaInvariant.PositionsValid\nopen Strategies.ArmadaInvariant.RootsMatch\nopen Strategies.ArmadaInvariant.UnstartedThreads\nopen Strategies.GlobalVars\nopen Strategies.GlobalVars.Pointer\nopen Strategies.GlobalVars.Util\nopen Strategies.PCRelation\nopen Strategies.ArmadaStatement.Status\nopen Util.Seq\n\nlet statement_effect_independent_preconditions\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (start_pc1: pc_t)\n  (start_pc2: pc_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t) =\n     states_match_except_global_variables vs pc_relation s1 s2\n   /\\ global_variables_unaddressed_in_memory vs s1.mem\n   /\\ global_variables_unaddressed_in_memory vs s2.mem\n   /\\ roots_match s1.mem\n   /\\ roots_match s2.mem\n   /\\ unstarted_threads_have_empty_write_buffers s1\n   /\\ unstarted_threads_have_empty_write_buffers s2\n   /\\ pc_relation.relation start_pc1 start_pc2\n   /\\ ThreadStatusRunning? (s1.threads actor).status\n\nlet statement_effect_independent_postconditions\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (cs1': conditional_computation_t Armada.State.t)\n  (cs2': conditional_computation_t Armada.State.t) =\n  match cs1', cs2' with\n  | ComputationProduces s1', ComputationProduces s2' ->\n        states_match_except_global_variables vs pc_relation s1' s2'\n      /\\ global_variables_unaddressed_in_memory vs s1'.mem\n      /\\ global_variables_unaddressed_in_memory vs s2'.mem\n      /\\ roots_match s1'.mem\n      /\\ roots_match s2'.mem\n  | ComputationImpossible, ComputationImpossible -> True\n  | ComputationUndefined, ComputationUndefined -> True\n  | _ -> False\n\n#push-options \"--z3rlimit 20\"\n\nlet statement_effect_independent_in_assume_expression_statement_implications\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc1: pc_t)\n  (start_pc2: pc_t)\n  (exp: expression_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   statement_effect_independent_preconditions vs pc_relation actor start_pc1 start_pc2 s1 s2\n                    /\\ global_variables_unmentioned_in_expression vs exp)\n          (ensures  statement_effect_independent_postconditions vs pc_relation\n                      (assume_expression_statement_computation actor nd start_pc1 exp s1)\n                      (assume_expression_statement_computation actor nd start_pc2 exp s2)) =\n  rvalue_computation_doesnt_depend_on_global_variables vs pc_relation exp actor s1 s2\n\nlet statement_effect_independent_in_assert_true_statement_implications\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc1: pc_t)\n  (start_pc2: pc_t)\n  (exp: expression_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   statement_effect_independent_preconditions vs pc_relation actor start_pc1 start_pc2 s1 s2\n                    /\\ global_variables_unmentioned_in_expression vs exp)\n          (ensures  statement_effect_independent_postconditions vs pc_relation\n                      (assert_true_statement_computation actor nd start_pc1 exp s1)\n                      (assert_true_statement_computation actor nd start_pc2 exp s2)) =\n  rvalue_computation_doesnt_depend_on_global_variables vs pc_relation exp actor s1 s2\n\nlet statement_effect_independent_in_assert_false_statement_implications\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc1: pc_t)\n  (start_pc2: pc_t)\n  (exp: expression_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   statement_effect_independent_preconditions vs pc_relation actor start_pc1 start_pc2 s1 s2\n                    /\\ global_variables_unmentioned_in_expression vs exp)\n          (ensures  statement_effect_independent_postconditions vs pc_relation\n                      (assert_false_statement_computation actor nd start_pc1 exp s1)\n                      (assert_false_statement_computation actor nd start_pc2 exp s2)) =\n  rvalue_computation_doesnt_depend_on_global_variables vs pc_relation exp actor s1 s2\n\nlet statement_effect_independent_in_conditional_jump_statement_implications\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc1: pc_t)\n  (start_pc2: pc_t)\n  (cond: expression_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   statement_effect_independent_preconditions vs pc_relation actor start_pc1 start_pc2 s1 s2\n                    /\\ global_variables_unmentioned_in_expression vs cond)\n          (ensures  statement_effect_independent_postconditions vs pc_relation\n                      (conditional_jump_statement_computation actor nd start_pc1 cond s1)\n                      (conditional_jump_statement_computation actor nd start_pc2 cond s2)) =\n  rvalue_computation_doesnt_depend_on_global_variables vs pc_relation cond actor s1 s2\n\nlet statement_effect_independent_in_unconditional_jump_statement_implications\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc1: pc_t)\n  (start_pc2: pc_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires statement_effect_independent_preconditions vs pc_relation actor start_pc1 start_pc2 s1 s2)\n          (ensures  statement_effect_independent_postconditions vs pc_relation\n                      (unconditional_jump_statement_computation actor nd start_pc1 s1)\n                      (unconditional_jump_statement_computation actor nd start_pc2 s2)) =\n  ()\n\nlet statement_effect_independent_in_update_statement_implications\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc1: pc_t)\n  (start_pc2: pc_t)\n  (bypassing_write_buffer: bool)\n  (dst: expression_t)\n  (src: expression_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   statement_effect_independent_preconditions vs pc_relation actor start_pc1 start_pc2 s1 s2\n                    /\\ global_variables_unmentioned_in_expression vs dst\n                    /\\ global_variables_unmentioned_in_expression vs src)\n          (ensures  statement_effect_independent_postconditions vs pc_relation\n                      (update_statement_computation actor nd start_pc1 bypassing_write_buffer dst src s1)\n                      (update_statement_computation actor nd start_pc2 bypassing_write_buffer dst src s2)) =\n  if   Cons? nd\n     || neqb (expression_to_td dst) (expression_to_td src) then\n    ()\n  else (\n    assert (global_variables_unmentioned_in_expression vs src);\n    rvalue_computation_doesnt_depend_on_global_variables vs pc_relation src actor s1 s2;\n    (match rvalue_computation src actor s1 with\n     | ComputationImpossible | ComputationUndefined -> ()\n     | ComputationProduces src_value ->\n         update_expression_with_gvars_unaddressed_maintains_states_match vs pc_relation\n           dst actor start_pc1 start_pc2 0 0 bypassing_write_buffer src_value s1 s2)\n  )\n\nlet statement_effect_independent_in_nondeterministic_update_statement_implications\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc1: pc_t)\n  (start_pc2: pc_t)\n  (bypassing_write_buffer: bool)\n  (dst: expression_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   statement_effect_independent_preconditions vs pc_relation actor start_pc1 start_pc2 s1 s2\n                    /\\ global_variables_unmentioned_in_expression vs dst)\n          (ensures  statement_effect_independent_postconditions vs pc_relation\n                      (nondeterministic_update_statement_computation actor nd start_pc1 bypassing_write_buffer\n                         dst s1)\n                      (nondeterministic_update_statement_computation actor nd start_pc2 bypassing_write_buffer\n                         dst s2)) =\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (expression_to_td dst) then\n    ()\n  else (\n    let nd_value = Cons?.hd nd in\n    if not (object_value_has_all_pointers_uninitialized nd_value) then\n      ()\n    else (\n      if_object_value_has_all_pointers_uninitialized_then_it_doesnt_depend_on_gvars vs nd_value;\n      update_expression_with_gvars_unaddressed_maintains_states_match vs pc_relation\n           dst actor start_pc1 start_pc2 0 0 bypassing_write_buffer nd_value s1 s2\n    )\n  )\n\nlet statement_effect_independent_in_compare_and_swap_statement_implications\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc1: pc_t)\n  (start_pc2: pc_t)\n  (target: expression_t)\n  (old_val: expression_t)\n  (new_val: expression_t)\n  (bypassing_write_buffer: bool)\n  (optional_result: option expression_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   statement_effect_independent_preconditions vs pc_relation actor start_pc1 start_pc2 s1 s2\n                    /\\ global_variables_unmentioned_in_expression vs target\n                    /\\ global_variables_unmentioned_in_expression vs old_val\n                    /\\ global_variables_unmentioned_in_expression vs new_val\n                    /\\ global_variables_unmentioned_in_optional_expression vs optional_result)\n          (ensures  statement_effect_independent_postconditions vs pc_relation\n                      (compare_and_swap_statement_computation actor nd start_pc1 target old_val new_val\n                         bypassing_write_buffer optional_result s1)\n                      (compare_and_swap_statement_computation actor nd start_pc2 target old_val new_val\n                         bypassing_write_buffer optional_result s2)) =\n  if   Cons? nd\n     || neqb (expression_to_td target) (expression_to_td old_val)\n     || neqb (expression_to_td target) (expression_to_td new_val)\n     || (match optional_result with\n        | Some result -> neqb (expression_to_td result) (ObjectTDPrimitive PrimitiveTDBool)\n        | None -> false) then\n    ()\n  else begin\n    check_expression_up_to_date_for_rmw_doesnt_depend_on_gvars vs pc_relation target actor s1 s2;\n    rvalue_computation_doesnt_depend_on_global_variables vs pc_relation old_val actor s1 s2;\n    rvalue_computation_doesnt_depend_on_global_variables vs pc_relation target actor s1 s2;\n    rvalue_computation_doesnt_depend_on_global_variables vs pc_relation new_val actor s1 s2;\n    lvalue_computation_doesnt_depend_on_global_variables vs pc_relation target actor s1 s2;\n    match check_expression_up_to_date_for_rmw target actor s1, rvalue_computation old_val actor s1,\n          rvalue_computation target actor s1, rvalue_computation new_val actor s1,\n          lvalue_computation target actor s1 with\n    | ComputationProduces _, ComputationProduces old_value,\n      ComputationProduces target_value, ComputationProduces new_value,\n      ComputationProduces target_ptr -> begin\n        let swap = eqb target_value old_value in\n        update_pointed_to_value_with_gvars_unaddressed_maintains_states_match vs pc_relation target_ptr actor start_pc1 start_pc2 0 0 false new_value s1 s2;\n        match optional_result with\n        | None -> ()\n        | Some result ->\n          lvalue_computation_doesnt_depend_on_global_variables vs pc_relation result actor s1 s2;\n          match lvalue_computation result actor s1,\n                (if swap then update_pointed_to_value target_ptr actor start_pc1 0 false new_value s1 else return s1),\n                (if swap then update_pointed_to_value target_ptr actor start_pc2 0 false new_value s2 else return s2) with\n          | ComputationProduces result_ptr, ComputationProduces s1', ComputationProduces s2' ->\n              let swap_value = ObjectValuePrimitive (PrimitiveBoxBool swap) in\n              update_pointed_to_value_with_gvars_unaddressed_maintains_states_match vs pc_relation result_ptr actor start_pc1 start_pc2 1 1 bypassing_write_buffer swap_value s1' s2'\n          | _ -> ()\n      end\n    | _ -> ()\n  end\n\nlet statement_effect_independent_in_atomic_exchange_statement_implications\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc1: pc_t)\n  (start_pc2: pc_t)\n  (old_val: expression_t)\n  (target: expression_t)\n  (new_val: expression_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   statement_effect_independent_preconditions vs pc_relation actor start_pc1 start_pc2 s1 s2\n                    /\\ global_variables_unmentioned_in_expression vs old_val\n                    /\\ global_variables_unmentioned_in_expression vs target\n                    /\\ global_variables_unmentioned_in_expression vs new_val)\n          (ensures  statement_effect_independent_postconditions vs pc_relation\n                      (atomic_exchange_statement_computation actor nd start_pc1 old_val target new_val s1)\n                      (atomic_exchange_statement_computation actor nd start_pc2 old_val target new_val s2)) =\n  // I hate to do this (for potential performance issues), but it works fine this time and it eliminates so many line of proofs...\n  check_expression_up_to_date_for_rmw_doesnt_depend_on_gvars vs pc_relation target actor s1 s2;\n  rvalue_computation_doesnt_depend_on_global_variables vs pc_relation target actor s1 s2;\n  rvalue_computation_doesnt_depend_on_global_variables vs pc_relation new_val actor s1 s2;\n  lvalue_computation_doesnt_depend_on_global_variables vs pc_relation old_val actor s1 s2;\n  assert (lvalue_computation old_val actor s1 == lvalue_computation old_val actor s2);\n  lvalue_computation_doesnt_depend_on_global_variables vs pc_relation target actor s1 s2;\n  assert (lvalue_computation target actor s1 == lvalue_computation target actor s2);\n  match check_expression_up_to_date_for_rmw target actor s1, rvalue_computation target actor s1, rvalue_computation new_val actor s1, lvalue_computation old_val actor s1, lvalue_computation target actor s1 with\n  | ComputationProduces _, ComputationProduces target_value, ComputationProduces new_value, ComputationProduces old_ptr, ComputationProduces target_ptr ->\n    update_pointed_to_value_with_gvars_unaddressed_maintains_states_match vs pc_relation old_ptr actor start_pc1 start_pc2 0 0 false target_value s1 s2;\n    begin match update_pointed_to_value old_ptr actor start_pc1 0 false target_value s1, update_pointed_to_value old_ptr actor start_pc2 0 false target_value s2 with\n          | ComputationProduces s1', ComputationProduces s2' ->\n            update_pointed_to_value_with_gvars_unaddressed_maintains_states_match vs pc_relation target_ptr actor start_pc1 start_pc2 1 1 false new_value s1' s2'\n          | _ -> ()\n    end\n  | _ -> ()\n\nlet statement_effect_independent_in_create_thread_statement_implications\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc1: pc_t)\n  (start_pc2: pc_t)\n  (method_id: method_id_t)\n  (initial_pc1: pc_t)\n  (initial_pc2: pc_t)\n  (bypassing_write_buffer: bool)\n  (optional_result: option expression_t)\n  (parameter_var_ids: list var_id_t)\n  (parameter_expressions: list expression_t)\n  (local_variable_initializers: list initializer_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   statement_effect_independent_preconditions vs pc_relation actor start_pc1 start_pc2 s1 s2\n                    /\\ pc_relation.relation initial_pc1 initial_pc2\n                    /\\ (match optional_result with\n                       | Some result -> global_variables_unmentioned_in_expression vs result\n                       | None -> true)\n                    /\\ global_variables_unmentioned_in_expressions vs parameter_expressions\n                    /\\ global_variables_unaddressed_in_initializers vs local_variable_initializers)\n          (ensures  statement_effect_independent_postconditions vs pc_relation\n                      (create_thread_statement_computation actor nd start_pc1 method_id initial_pc1\n                         bypassing_write_buffer optional_result parameter_var_ids parameter_expressions\n                         local_variable_initializers s1)\n                      (create_thread_statement_computation actor nd start_pc2 method_id initial_pc2\n                         bypassing_write_buffer optional_result parameter_var_ids parameter_expressions\n                         local_variable_initializers s2)) =\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract create_thread_nd_t)\n     || (   Some? optional_result\n        && neqb (expression_to_td (Some?.v optional_result)) (ObjectTDPrimitive PrimitiveTDThreadId))\n     || list_len parameter_var_ids <> list_len parameter_expressions then\n    ()\n  else (\n    let create_thread_nd: create_thread_nd_t = ObjectValueAbstract?.value (Cons?.hd nd) in\n    let new_tid = create_thread_nd.new_tid in\n    if new_tid = 0 then\n      (match optional_result with\n       | None -> ()\n       | Some result ->\n          let new_tid_value = ObjectValuePrimitive (PrimitiveBoxThreadId new_tid) in\n          update_expression_with_gvars_unaddressed_maintains_states_match vs pc_relation result\n            actor start_pc1 start_pc2\n            (list_len parameter_var_ids + list_len local_variable_initializers)\n            (list_len parameter_var_ids + list_len local_variable_initializers)\n            bypassing_write_buffer new_tid_value s1 s2)\n    else (\n      let frame_uniq = create_thread_nd.frame_uniq in\n      let new_thread = s1.threads new_tid in\n      if   new_thread.status <> ThreadStatusNotStarted\n         || length new_thread.write_buffer <> 0\n         || list_contains frame_uniq s1.uniqs_used then\n        ()\n      else (\n        rvalues_computation_doesnt_depend_on_global_variables vs pc_relation parameter_expressions actor s1 s2;\n        match rvalues_computation parameter_expressions actor s1 with\n        | ComputationImpossible | ComputationUndefined -> ()\n        | ComputationProduces parameter_values ->\n            let s21 = make_thread_running method_id initial_pc1 new_tid frame_uniq s1 in\n            let s22 = make_thread_running method_id initial_pc2 new_tid frame_uniq s2 in\n            make_thread_running_doesnt_depend_on_gvars vs pc_relation method_id initial_pc1 initial_pc2\n              new_tid frame_uniq s1 s2;\n            push_stack_parameters_doesnt_depend_on_gvars vs pc_relation new_tid start_pc1 start_pc2 0 0 method_id\n              frame_uniq parameter_var_ids parameter_values s21 s22;\n            (match push_stack_parameters new_tid start_pc1 0 method_id frame_uniq parameter_var_ids\n                     parameter_values s21,\n                   push_stack_parameters new_tid start_pc2 0 method_id frame_uniq parameter_var_ids\n                     parameter_values s22 with\n             | ComputationProduces s31, ComputationProduces s32 ->\n                  push_stack_variables_doesnt_depend_on_gvars vs pc_relation new_tid start_pc1 start_pc2\n                    (list_len parameter_var_ids) (list_len parameter_var_ids) method_id frame_uniq\n                    local_variable_initializers s31 s32;\n                  (match push_stack_variables new_tid start_pc1 (list_len parameter_var_ids) method_id frame_uniq\n                           local_variable_initializers s31,\n                         push_stack_variables new_tid start_pc2 (list_len parameter_var_ids) method_id frame_uniq\n                           local_variable_initializers s32 with\n                   | ComputationProduces s41, ComputationProduces s42 ->\n                       (match optional_result with\n                        | None -> ()\n                        | Some result ->\n                           let new_tid_value = ObjectValuePrimitive (PrimitiveBoxThreadId new_tid) in\n                           push_stack_parameters_maintains_status new_tid start_pc1 0 method_id frame_uniq\n                             parameter_var_ids parameter_values s21;\n                           push_stack_variables_maintains_status new_tid start_pc1 (list_len parameter_var_ids)\n                             method_id frame_uniq local_variable_initializers s31;\n                           assert (new_tid <> actor);\n                           assert (s41.threads actor == s21.threads actor);\n                           update_expression_with_gvars_unaddressed_maintains_states_match vs pc_relation result\n                             actor start_pc1 start_pc2\n                             (list_len parameter_var_ids + list_len local_variable_initializers)\n                             (list_len parameter_var_ids + list_len local_variable_initializers)\n                             bypassing_write_buffer new_tid_value s41 s42)\n                   | _, _ -> ())\n             | _, _ -> ())\n      )\n    )\n  )\n\nlet statement_effect_independent_in_method_call_statement_implications\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc1: pc_t)\n  (start_pc2: pc_t)\n  (method_id: method_id_t)\n  (return_pc1: pc_t)\n  (return_pc2: pc_t)\n  (parameter_var_ids: list var_id_t)\n  (parameter_expressions: list expression_t)\n  (local_variable_initializers: list initializer_t)\n  (stack_overflow: bool)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   statement_effect_independent_preconditions vs pc_relation actor start_pc1 start_pc2 s1 s2\n                    /\\ pc_relation.relation return_pc1 return_pc2\n                    /\\ pc_relation.return_relation return_pc1 return_pc2\n                    /\\ global_variables_unmentioned_in_expressions vs parameter_expressions\n                    /\\ global_variables_unaddressed_in_initializers vs local_variable_initializers)\n          (ensures  statement_effect_independent_postconditions vs pc_relation\n                      (method_call_statement_computation actor nd start_pc1 method_id return_pc1 parameter_var_ids\n                         parameter_expressions local_variable_initializers stack_overflow s1)\n                      (method_call_statement_computation actor nd start_pc2 method_id return_pc2 parameter_var_ids\n                         parameter_expressions local_variable_initializers stack_overflow s2)) =\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract method_call_nd_t) then\n    ()\n  else (\n    let method_call_nd: method_call_nd_t = ObjectValueAbstract?.value (Cons?.hd nd) in\n    let frame_uniq = method_call_nd.frame_uniq in\n    rvalues_computation_doesnt_depend_on_global_variables vs pc_relation parameter_expressions actor s1 s2;\n    match rvalues_computation parameter_expressions actor s1 with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces parameter_values ->\n        let s21 = push_stack_frame actor method_id return_pc1 frame_uniq s1 in\n        let s22 = push_stack_frame actor method_id return_pc2 frame_uniq s2 in\n        push_stack_parameters_doesnt_depend_on_gvars vs pc_relation actor start_pc1 start_pc2 0 0 method_id frame_uniq\n          parameter_var_ids parameter_values s21 s22;\n        (match push_stack_parameters actor start_pc1 0 method_id frame_uniq parameter_var_ids parameter_values s21,\n               push_stack_parameters actor start_pc2 0 method_id frame_uniq parameter_var_ids parameter_values s22 with\n         | ComputationProduces s31, ComputationProduces s32 ->\n             push_stack_variables_doesnt_depend_on_gvars vs pc_relation actor start_pc1 start_pc2\n               (list_len parameter_var_ids) (list_len parameter_var_ids) method_id frame_uniq\n               local_variable_initializers s31 s32\n         | _, _ -> ())\n  )\n\nlet statement_effect_independent_in_return_statement_implications\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc1: pc_t)\n  (start_pc2: pc_t)\n  (end_pc1: option pc_t)\n  (end_pc2: option pc_t)\n  (method_id: method_id_t)\n  (bypassing_write_buffer: bool)\n  (output_dsts: list expression_t)\n  (output_srcs: list expression_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   statement_effect_independent_preconditions vs pc_relation actor start_pc1 start_pc2 s1 s2\n                    /\\ global_variables_unmentioned_in_expressions vs output_dsts\n                    /\\ global_variables_unmentioned_in_expressions vs output_srcs\n                    /\\ (match end_pc1, end_pc2 with\n                       | Some pc1, Some pc2 -> pc_relation.relation pc1 pc2 /\\ pc_relation.return_relation pc1 pc2\n                       | None, None -> True\n                       | _, _ -> False))\n          (ensures  statement_effect_independent_postconditions vs pc_relation\n                      (return_statement_computation actor nd start_pc1 end_pc1 method_id bypassing_write_buffer\n                        output_dsts output_srcs s1)\n                      (return_statement_computation actor nd start_pc2 end_pc2 method_id bypassing_write_buffer\n                        output_dsts output_srcs s2)) =\n  let thread1 = s1.threads actor in\n  let thread2 = s2.threads actor in\n  if   Cons? nd\n     || eqb thread1.stack []\n     || thread1.top.method_id <> method_id\n     || end_pc1 <> Some (Cons?.hd thread1.stack).return_pc then\n    ()\n  else (\n    rvalues_computation_doesnt_depend_on_global_variables vs pc_relation output_srcs actor s1 s2;\n    (match rvalues_computation output_srcs actor s1 with\n     | ComputationImpossible | ComputationUndefined -> ()\n     | ComputationProduces output_values ->\n         pop_stack_variables_doesnt_depend_on_gvars vs actor method_id thread1.top.frame_uniq\n           thread1.top.local_variables s1.mem s2.mem;\n         (match pop_stack_variables actor method_id thread1.top.frame_uniq thread1.top.local_variables s1.mem,\n                pop_stack_variables actor method_id thread2.top.frame_uniq thread2.top.local_variables s2.mem with\n          | ComputationProduces mem1', ComputationProduces mem2' ->\n              let s21 = pop_stack_frame actor mem1' s1 in\n              let s22 = pop_stack_frame actor mem2' s2 in\n              update_expressions_with_gvars_unaddressed_maintains_states_match vs pc_relation output_dsts actor\n                start_pc1 start_pc2 0 0 bypassing_write_buffer output_values s21 s22\n         | _, _ -> ()))\n  )\n\nlet statement_effect_independent_in_terminate_thread_statement_implications\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc1: pc_t)\n  (start_pc2: pc_t)\n  (method_id: method_id_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires statement_effect_independent_preconditions vs pc_relation actor start_pc1 start_pc2 s1 s2)\n          (ensures  statement_effect_independent_postconditions vs pc_relation\n                      (terminate_thread_statement_computation actor nd start_pc1 method_id s1)\n                      (terminate_thread_statement_computation actor nd start_pc2 method_id s2)) =\n  let thread1 = s1.threads actor in\n  if neqb thread1.stack [] then\n    ()\n  else\n    pop_stack_variables_doesnt_depend_on_gvars vs actor method_id thread1.top.frame_uniq\n      thread1.top.local_variables s1.mem s2.mem\n\nlet statement_effect_independent_in_terminate_process_statement_implications\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc1: pc_t)\n  (start_pc2: pc_t)\n  (method_id: method_id_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires statement_effect_independent_preconditions vs pc_relation actor start_pc1 start_pc2 s1 s2)\n          (ensures  statement_effect_independent_postconditions vs pc_relation\n                      (terminate_process_statement_computation actor nd start_pc1 method_id s1)\n                      (terminate_process_statement_computation actor nd start_pc2 method_id s2)) =\n  ()\n\nlet statement_effect_independent_in_join_statement_implications\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc1: pc_t)\n  (start_pc2: pc_t)\n  (join_tid: expression_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   statement_effect_independent_preconditions vs pc_relation actor start_pc1 start_pc2 s1 s2\n                    /\\ global_variables_unmentioned_in_expression vs join_tid)\n          (ensures  statement_effect_independent_postconditions vs pc_relation\n                      (join_statement_computation actor nd start_pc1 join_tid s1)\n                      (join_statement_computation actor nd start_pc2 join_tid s2)) =\n  rvalue_computation_doesnt_depend_on_global_variables vs pc_relation join_tid actor s1 s2\n\n#pop-options\n#push-options \"--z3rlimit 30\"\n\nlet statement_effect_independent_in_alloc_successful_statement_implications\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc1: pc_t)\n  (start_pc2: pc_t)\n  (zero_initialized: bool)\n  (bypassing_write_buffer: bool)\n  (result: expression_t)\n  (allocation_td: object_td_t)\n  (count: expression_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   statement_effect_independent_preconditions vs pc_relation actor start_pc1 start_pc2 s1 s2\n                    /\\ global_variables_unmentioned_in_expression vs result\n                    /\\ global_variables_unmentioned_in_expression vs count)\n          (ensures  statement_effect_independent_postconditions vs pc_relation\n                      (alloc_successful_statement_computation actor nd start_pc1 zero_initialized\n                         bypassing_write_buffer result allocation_td count s1)\n                      (alloc_successful_statement_computation actor nd start_pc2 zero_initialized\n                         bypassing_write_buffer result allocation_td count s2)) =\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract root_id_uniquifier_t)\n     || neqb (expression_to_td count) (ObjectTDAbstract nat)\n     || neqb (expression_to_td result) (ObjectTDPrimitive PrimitiveTDPointer) then\n    ()\n  else (\n    rvalue_computation_doesnt_depend_on_global_variables vs pc_relation count actor s1 s2;\n    match rvalue_computation count actor s1 with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces count_value ->\n        let sz = ObjectValueAbstract?.value count_value in\n        let array_td = ObjectTDArray allocation_td sz in\n        let uniq = ObjectValueAbstract?.value (Cons?.hd nd) in\n        let root_id = RootIdAllocation uniq in\n        (match s1.mem root_id with\n         | RootAllocated allocated freed storage ->\n             if   allocated\n                || freed\n                || neqb (object_storage_to_td storage) array_td\n                || not (is_storage_ready_for_allocation storage)\n                || (not zero_initialized && not (object_storage_arbitrarily_initialized_correctly storage))\n                || (zero_initialized && not (is_storage_zero_filled storage)) then\n               ()\n             else (\n               if zero_initialized then (\n                 assert (is_storage_zero_filled storage);\n                 object_storage_zero_filled_doesnt_depend_on_gvars vs storage;\n                 assert (global_variables_unaddressed_in_storage vs storage)\n               )\n               else (\n                 assert (object_storage_arbitrarily_initialized_correctly storage);\n                 object_storage_arbitrarily_initialized_correctly_doesnt_depend_on_gvars vs storage;\n                 assert (global_variables_unaddressed_in_storage vs storage)\n               );\n               mark_allocation_root_allocated_doesnt_depend_on_gvars vs pc_relation uniq storage s1 s2;\n               let s1' = mark_allocation_root_allocated uniq storage s1 in\n               let s2' = mark_allocation_root_allocated uniq storage s2 in\n               let p = ObjectValuePrimitive (PrimitiveBoxPointer (PointerIndex (PointerRoot root_id) 0)) in\n               update_expression_with_gvars_unaddressed_maintains_states_match vs pc_relation result actor\n                 start_pc1 start_pc2 0 0 bypassing_write_buffer p s1' s2'\n             )\n         | _ -> ())\n  )\n\n#pop-options\n#push-options \"--z3rlimit 20\"\n\nlet statement_effect_independent_in_alloc_returning_null_statement_implications\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc1: pc_t)\n  (start_pc2: pc_t)\n  (bypassing_write_buffer: bool)\n  (result: expression_t)\n  (count: expression_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   statement_effect_independent_preconditions vs pc_relation actor start_pc1 start_pc2 s1 s2\n                    /\\ global_variables_unmentioned_in_expression vs result\n                    /\\ global_variables_unmentioned_in_expression vs count)\n          (ensures  statement_effect_independent_postconditions vs pc_relation\n                      (alloc_returning_null_statement_computation actor nd start_pc1 bypassing_write_buffer\n                         result count s1)\n                      (alloc_returning_null_statement_computation actor nd start_pc2 bypassing_write_buffer\n                         result count s2)) =\n  rvalue_computation_doesnt_depend_on_global_variables vs pc_relation count actor s1 s2;\n  match rvalue_computation count actor s1 with\n  | ComputationImpossible | ComputationUndefined -> ()\n  | ComputationProduces _ ->\n      let p = ObjectValuePrimitive (PrimitiveBoxPointer PointerNull) in\n      update_expression_with_gvars_unaddressed_maintains_states_match vs pc_relation result actor\n        start_pc1 start_pc2 0 0 bypassing_write_buffer p s1 s2\n\nlet statement_effect_independent_in_dealloc_statement_implications\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc1: pc_t)\n  (start_pc2: pc_t)\n  (ptr: expression_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   statement_effect_independent_preconditions vs pc_relation actor start_pc1 start_pc2 s1 s2\n                    /\\ global_variables_unmentioned_in_expression vs ptr)\n          (ensures  statement_effect_independent_postconditions vs pc_relation\n                      (dealloc_statement_computation actor nd start_pc1 ptr s1)\n                      (dealloc_statement_computation actor nd start_pc2 ptr s2)) =\n  if   Cons? nd\n     || neqb (expression_to_td ptr) (ObjectTDPrimitive PrimitiveTDPointer) then\n    ()\n  else (\n    rvalue_computation_doesnt_depend_on_global_variables vs pc_relation ptr actor s1 s2;\n    match rvalue_computation ptr actor s1 with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces ptr_value ->\n        free_pointer_doesnt_depend_on_gvars vs ptr_value s1.mem s2.mem\n  )\n\nlet statement_effect_independent_in_somehow_statement_implications\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc1: pc_t)\n  (start_pc2: pc_t)\n  (undefined_unless_cond: expression_t)\n  (bypassing_write_buffer: bool)\n  (modifies_clauses: list expression_t)\n  (ensures_cond: expression_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   statement_effect_independent_preconditions vs pc_relation actor start_pc1 start_pc2 s1 s2\n                    /\\ global_variables_unmentioned_in_expression vs undefined_unless_cond\n                    /\\ global_variables_unmentioned_in_expressions vs modifies_clauses\n                    /\\ expressions_lack_pointer_field modifies_clauses\n                    /\\ global_variables_unmentioned_in_expression vs ensures_cond\n                    /\\ ThreadStatusRunning? (s1.threads actor).status)\n          (ensures  statement_effect_independent_postconditions vs pc_relation\n                      (somehow_statement_computation actor nd start_pc1 undefined_unless_cond\n                         bypassing_write_buffer modifies_clauses ensures_cond s1)\n                      (somehow_statement_computation actor nd start_pc2 undefined_unless_cond\n                         bypassing_write_buffer modifies_clauses ensures_cond s2)) =\n  if   neqb (expression_to_td undefined_unless_cond) (ObjectTDPrimitive PrimitiveTDBool)\n     || neqb (expression_to_td ensures_cond) (ObjectTDPrimitive PrimitiveTDBool) then\n    ()\n  else (\n    rvalue_computation_doesnt_depend_on_global_variables vs pc_relation undefined_unless_cond actor s1 s2;\n    match rvalue_computation undefined_unless_cond actor s1 with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces undefined_unless_value ->\n        let undefined_unless_bool = PrimitiveBoxBool?.b (ObjectValuePrimitive?.value undefined_unless_value) in\n        if not undefined_unless_bool then\n          ()\n        else (\n          update_expressions_lacking_pointer_field_maintains_states_match vs pc_relation modifies_clauses\n            actor start_pc1 start_pc2 0 0 bypassing_write_buffer nd s1 s2;\n          (match update_expressions modifies_clauses actor start_pc1 0 bypassing_write_buffer nd s1,\n                 update_expressions modifies_clauses actor start_pc2 0 bypassing_write_buffer nd s2 with\n           | ComputationProduces s1', ComputationProduces s2' ->\n               rvalue_computation_doesnt_depend_on_global_variables vs pc_relation ensures_cond actor s1' s2'\n           | _, _ -> ())\n        )\n  )\n\nlet statement_effect_independent_in_fence_statement_implications\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc1: pc_t)\n  (start_pc2: pc_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires statement_effect_independent_preconditions vs pc_relation actor start_pc1 start_pc2 s1 s2)\n          (ensures  statement_effect_independent_postconditions vs pc_relation\n                      (fence_statement_computation actor nd start_pc1 s1)\n                      (fence_statement_computation actor nd start_pc2 s2)) =\n  let root = s1.mem RootIdFence in\n  match root_to_storage_computation root with\n  | ComputationImpossible | ComputationUndefined -> ()\n  | ComputationProduces storage ->\n      if not (object_storage_up_to_date_for_rmw_operation storage actor) then\n        ()\n      else (\n        let p = PointerRoot RootIdFence in\n        assert (global_variables_unaddressed_in_object_value vs (ObjectValuePrimitive (PrimitiveBoxBool false)));\n        assert (global_variables_unaddressed_in_pointer vs p);\n        update_pointed_to_value_with_gvars_unaddressed_maintains_states_match vs pc_relation\n          p actor start_pc1 start_pc2 0 0 false (ObjectValuePrimitive (PrimitiveBoxBool false)) s1 s2\n      )\n\nlet statement_effect_independent_in_external_method_start_statement_implications\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc1: pc_t)\n  (start_pc2: pc_t)\n  (await_cond: expression_t)\n  (undefined_unless_cond: expression_t)\n  (bypassing_write_buffer: bool)\n  (modifies_clauses: list expression_t)\n  (reads_clauses: list (var_id_t * expression_t))\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   statement_effect_independent_preconditions vs pc_relation actor start_pc1 start_pc2 s1 s2\n                    /\\ global_variables_unmentioned_in_expression vs await_cond\n                    /\\ global_variables_unmentioned_in_expression vs undefined_unless_cond\n                    /\\ global_variables_unmentioned_in_expressions vs modifies_clauses\n                    /\\ expressions_lack_pointer_field modifies_clauses\n                    /\\ global_variables_unmentioned_in_reads_clauses vs reads_clauses)\n          (ensures  statement_effect_independent_postconditions vs pc_relation\n                      (external_method_start_statement_computation actor nd start_pc1 await_cond\n                         undefined_unless_cond bypassing_write_buffer modifies_clauses reads_clauses s1)\n                      (external_method_start_statement_computation actor nd start_pc2 await_cond\n                         undefined_unless_cond bypassing_write_buffer modifies_clauses reads_clauses s2)) =\n  if   neqb (expression_to_td await_cond) (ObjectTDPrimitive PrimitiveTDBool)\n     || neqb (expression_to_td undefined_unless_cond) (ObjectTDPrimitive PrimitiveTDBool)\n     || list_len modifies_clauses <> list_len nd then\n    ()\n  else (\n    rvalue_computation_doesnt_depend_on_global_variables vs pc_relation await_cond actor s1 s2;\n    match rvalue_computation await_cond actor s1 with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces await_value ->\n        let await_bool = PrimitiveBoxBool?.b (ObjectValuePrimitive?.value await_value) in\n        if not await_bool then\n          ()\n        else (\n          rvalue_computation_doesnt_depend_on_global_variables vs pc_relation undefined_unless_cond actor s1 s2;\n          match rvalue_computation undefined_unless_cond actor s1 with\n          | ComputationImpossible | ComputationUndefined -> ()\n          | ComputationProduces undefined_unless_value ->\n              let undefined_unless_bool = PrimitiveBoxBool?.b (ObjectValuePrimitive?.value await_value) in\n              if not undefined_unless_bool then\n                ()\n              else (\n                update_expressions_lacking_pointer_field_maintains_states_match vs pc_relation\n                  modifies_clauses actor start_pc1 start_pc2 0 0 bypassing_write_buffer nd s1 s2;\n                match update_expressions modifies_clauses actor start_pc1 0 bypassing_write_buffer nd s1,\n                      update_expressions modifies_clauses actor start_pc2 0 bypassing_write_buffer nd s2 with\n                | ComputationProduces s1', ComputationProduces s2' ->\n                    external_method_take_snapshot_of_reads_clauses_computation_doesnt_depend_on_gvars\n                      vs pc_relation actor start_pc1 start_pc2 (list_len modifies_clauses) (list_len modifies_clauses)\n                      bypassing_write_buffer reads_clauses s1' s2'\n                | _, _ -> ()\n              )\n        )\n  )\n\nlet statement_effect_independent_in_external_method_middle_statement_implications\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc1: pc_t)\n  (start_pc2: pc_t)\n  (bypassing_write_buffer: bool)\n  (modifies_clauses: list expression_t)\n  (reads_clauses: list (var_id_t * expression_t))\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   statement_effect_independent_preconditions vs pc_relation actor start_pc1 start_pc2 s1 s2\n                    /\\ global_variables_unmentioned_in_expressions vs modifies_clauses\n                    /\\ expressions_lack_pointer_field modifies_clauses\n                    /\\ global_variables_unmentioned_in_reads_clauses vs reads_clauses)\n          (ensures  statement_effect_independent_postconditions vs pc_relation\n                      (external_method_middle_statement_computation actor nd start_pc1\n                         bypassing_write_buffer modifies_clauses reads_clauses s1)\n                      (external_method_middle_statement_computation actor nd start_pc2\n                         bypassing_write_buffer modifies_clauses reads_clauses s2)) =\n  external_method_check_snapshot_computation_doesnt_depend_on_gvars vs pc_relation actor reads_clauses s1 s2;\n  (match external_method_check_snapshot_computation actor reads_clauses s1 with\n   | ComputationImpossible | ComputationUndefined -> ()\n   | ComputationProduces _ ->\n       update_expressions_lacking_pointer_field_maintains_states_match vs pc_relation modifies_clauses\n         actor start_pc1 start_pc2 0 0 bypassing_write_buffer nd s1 s2;\n       (match update_expressions modifies_clauses actor start_pc1 0 bypassing_write_buffer nd s1,\n              update_expressions modifies_clauses actor start_pc2 0 bypassing_write_buffer nd s2 with\n        | ComputationProduces s1_next, ComputationProduces s2_next ->\n            external_method_take_snapshot_of_reads_clauses_computation_doesnt_depend_on_gvars vs pc_relation\n              actor start_pc1 start_pc2 (list_len modifies_clauses) (list_len modifies_clauses)\n              bypassing_write_buffer reads_clauses s1_next s2_next\n        | _, _ -> ()))\n\nlet statement_effect_independent_in_external_method_end_statement_implications\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc1: pc_t)\n  (start_pc2: pc_t)\n  (ensures_cond: expression_t)\n  (logs_clauses: list expression_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   statement_effect_independent_preconditions vs pc_relation actor start_pc1 start_pc2 s1 s2\n                    /\\ global_variables_unmentioned_in_expression vs ensures_cond\n                    /\\ global_variables_unmentioned_in_expressions vs logs_clauses)\n          (ensures  statement_effect_independent_postconditions vs pc_relation\n                      (external_method_end_statement_computation actor nd start_pc1 ensures_cond logs_clauses s1)\n                      (external_method_end_statement_computation actor nd start_pc2 ensures_cond logs_clauses s2)) =\n  if   Cons? nd\n     || neqb (expression_to_td ensures_cond) (ObjectTDPrimitive PrimitiveTDBool) then\n    ()\n  else (\n    rvalue_computation_doesnt_depend_on_global_variables vs pc_relation ensures_cond actor s1 s2;\n    match rvalue_computation ensures_cond actor s1 with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces ensures_value ->\n        let ensures_bool = PrimitiveBoxBool?.b (ObjectValuePrimitive?.value ensures_value) in\n        log_expressions_computation_doesnt_depend_on_gvars vs pc_relation actor logs_clauses s1 s2\n  )\n\n#pop-options\n#push-options \"--z3rlimit 30\"\n\nlet statement_effect_independent_implications\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc1: pc_t)\n  (start_pc2: pc_t)\n  (end_pc1: option pc_t)\n  (end_pc2: option pc_t)\n  (statement1: Armada.Statement.t)\n  (statement2: Armada.Statement.t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  (* see .fsti file for spec *) =\n  let cs1' = statement_computation actor nd start_pc1 end_pc1 statement1 s1 in\n  let cs2' = statement_computation actor nd start_pc2 end_pc2 statement2 s2 in\n  assert (statement_effect_independent_preconditions vs pc_relation actor start_pc1 start_pc2 s1 s2);\n  (match statement1 with\n   | AssumeExpressionStatement exp ->\n       statement_effect_independent_in_assume_expression_statement_implications vs pc_relation actor nd\n         start_pc1 start_pc2 exp s1 s2;\n       assert (statement_effect_independent_postconditions vs pc_relation cs1' cs2')\n   | AssumePredicateStatement pred ->\n       false_elim ();\n       assert (statement_effect_independent_postconditions vs pc_relation cs1' cs2')\n   | AssertTrueStatement exp ->\n       statement_effect_independent_in_assert_true_statement_implications vs pc_relation actor nd\n         start_pc1 start_pc2 exp s1 s2;\n       assert (statement_effect_independent_postconditions vs pc_relation cs1' cs2')\n   | AssertFalseStatement exp ->\n       statement_effect_independent_in_assert_false_statement_implications vs pc_relation actor nd\n         start_pc1 start_pc2 exp s1 s2;\n       assert (statement_effect_independent_postconditions vs pc_relation cs1' cs2')\n   | ConditionalJumpStatement cond ->\n       statement_effect_independent_in_conditional_jump_statement_implications vs pc_relation actor nd\n         start_pc1 start_pc2 cond s1 s2;\n       assert (statement_effect_independent_postconditions vs pc_relation cs1' cs2')\n   | UnconditionalJumpStatement ->\n       statement_effect_independent_in_unconditional_jump_statement_implications vs pc_relation actor nd\n         start_pc1 start_pc2   s1 s2;\n       assert (statement_effect_independent_postconditions vs pc_relation cs1' cs2')\n   | UpdateStatement bypassing_write_buffer dst src ->\n       statement_effect_independent_in_update_statement_implications vs pc_relation actor nd\n         start_pc1 start_pc2 bypassing_write_buffer dst src s1 s2;\n       assert (statement_effect_independent_postconditions vs pc_relation cs1' cs2')\n   | NondeterministicUpdateStatement bypassing_write_buffer dst ->\n       statement_effect_independent_in_nondeterministic_update_statement_implications vs pc_relation actor nd\n         start_pc1 start_pc2 bypassing_write_buffer dst s1 s2;\n       assert (statement_effect_independent_postconditions vs pc_relation cs1' cs2')\n   | PropagateWriteMessageStatement ->\n       false_elim ();\n       assert (statement_effect_independent_postconditions vs pc_relation cs1' cs2')\n   | CompareAndSwapStatement target old_val new_val bypassing_write_buffer optional_result ->\n       statement_effect_independent_in_compare_and_swap_statement_implications vs pc_relation actor nd\n         start_pc1 start_pc2 target old_val new_val bypassing_write_buffer optional_result s1 s2;\n       assert (statement_effect_independent_postconditions vs pc_relation cs1' cs2')\n   | AtomicExchangeStatement old_val target new_val ->\n       statement_effect_independent_in_atomic_exchange_statement_implications vs pc_relation actor nd\n         start_pc1 start_pc2 old_val target new_val s1 s2;\n       assert (statement_effect_independent_postconditions vs pc_relation cs1' cs2')\n   | CreateThreadStatement method_id initial_pc bypassing_write_buffer optional_result parameter_var_ids\n                           parameter_expressions local_variable_initializers ->\n       let initial_pc2 = (CreateThreadStatement?.initial_pc statement2) in\n       statement_effect_independent_in_create_thread_statement_implications vs pc_relation actor nd\n         start_pc1 start_pc2 method_id initial_pc initial_pc2 bypassing_write_buffer optional_result\n         parameter_var_ids parameter_expressions local_variable_initializers s1 s2;\n       assert (statement_effect_independent_postconditions vs pc_relation cs1' cs2')\n   | MethodCallStatement method_id return_pc parameter_var_ids parameter_expressions local_variable_initializers\n                           stack_overflow ->\n       let return_pc2 = (MethodCallStatement?.return_pc statement2) in\n       statement_effect_independent_in_method_call_statement_implications vs pc_relation actor nd\n         start_pc1 start_pc2 method_id return_pc return_pc2 parameter_var_ids parameter_expressions\n         local_variable_initializers stack_overflow s1 s2;\n       assert (statement_effect_independent_postconditions vs pc_relation cs1' cs2')\n   | ReturnStatement method_id bypassing_write_buffer output_dsts output_srcs ->\n       statement_effect_independent_in_return_statement_implications vs pc_relation actor nd\n         start_pc1 start_pc2 end_pc1 end_pc2 method_id bypassing_write_buffer output_dsts output_srcs s1 s2;\n       assert (statement_effect_independent_postconditions vs pc_relation cs1' cs2')\n   | TerminateThreadStatement method_id ->\n       statement_effect_independent_in_terminate_thread_statement_implications vs pc_relation actor nd\n         start_pc1 start_pc2 method_id s1 s2;\n       assert (statement_effect_independent_postconditions vs pc_relation cs1' cs2')\n   | TerminateProcessStatement method_id ->\n       statement_effect_independent_in_terminate_process_statement_implications vs pc_relation actor nd\n         start_pc1 start_pc2 method_id s1 s2;\n       assert (statement_effect_independent_postconditions vs pc_relation cs1' cs2')\n   | JoinStatement join_tid ->\n       statement_effect_independent_in_join_statement_implications vs pc_relation actor nd\n         start_pc1 start_pc2 join_tid s1 s2;\n       assert (statement_effect_independent_postconditions vs pc_relation cs1' cs2')\n   | MallocSuccessfulStatement bypassing_write_buffer result allocation_td count ->\n       statement_effect_independent_in_alloc_successful_statement_implications vs pc_relation actor nd\n         start_pc1 start_pc2 false bypassing_write_buffer result allocation_td count s1 s2;\n       assert (statement_effect_independent_postconditions vs pc_relation cs1' cs2')\n   | MallocReturningNullStatement bypassing_write_buffer result count ->\n       statement_effect_independent_in_alloc_returning_null_statement_implications vs pc_relation actor nd\n         start_pc1 start_pc2 bypassing_write_buffer result count s1 s2;\n       assert (statement_effect_independent_postconditions vs pc_relation cs1' cs2')\n   | CallocSuccessfulStatement bypassing_write_buffer result allocation_td count ->\n       statement_effect_independent_in_alloc_successful_statement_implications vs pc_relation actor nd\n         start_pc1 start_pc2 true bypassing_write_buffer result allocation_td count s1 s2;\n       assert (statement_effect_independent_postconditions vs pc_relation cs1' cs2')\n   | CallocReturningNullStatement bypassing_write_buffer result count ->\n       statement_effect_independent_in_alloc_returning_null_statement_implications vs pc_relation actor nd\n         start_pc1 start_pc2 bypassing_write_buffer result count s1 s2;\n       assert (statement_effect_independent_postconditions vs pc_relation cs1' cs2')\n   | DeallocStatement ptr ->\n       statement_effect_independent_in_dealloc_statement_implications vs pc_relation actor nd\n         start_pc1 start_pc2 ptr s1 s2;\n       assert (statement_effect_independent_postconditions vs pc_relation cs1' cs2')\n   | SomehowStatement undefined_unless_cond bypassing_write_buffer modifies_clauses ensures_cond ->\n       statement_effect_independent_in_somehow_statement_implications vs pc_relation actor nd\n         start_pc1 start_pc2 undefined_unless_cond bypassing_write_buffer modifies_clauses ensures_cond s1 s2;\n       assert (statement_effect_independent_postconditions vs pc_relation cs1' cs2')\n   | FenceStatement ->\n       statement_effect_independent_in_fence_statement_implications vs pc_relation actor nd\n         start_pc1 start_pc2 s1 s2;\n       assert (statement_effect_independent_postconditions vs pc_relation cs1' cs2')\n   | ExternalMethodStartStatement await_cond undefined_unless_cond bypassing_write_buffer\n                                  modifies_clauses reads_clauses ->\n       statement_effect_independent_in_external_method_start_statement_implications vs pc_relation actor nd\n         start_pc1 start_pc2 await_cond undefined_unless_cond bypassing_write_buffer\n           modifies_clauses reads_clauses s1 s2;\n       assert (statement_effect_independent_postconditions vs pc_relation cs1' cs2')\n   | ExternalMethodMiddleStatement bypassing_write_buffer modifies_clauses reads_clauses ->\n       statement_effect_independent_in_external_method_middle_statement_implications vs pc_relation actor nd\n         start_pc1 start_pc2 bypassing_write_buffer modifies_clauses reads_clauses s1 s2;\n       assert (statement_effect_independent_postconditions vs pc_relation cs1' cs2')\n   | ExternalMethodEndStatement ensures_cond logs_clauses ->\n       statement_effect_independent_in_external_method_end_statement_implications vs pc_relation actor nd\n         start_pc1 start_pc2 ensures_cond logs_clauses s1 s2;\n       assert (statement_effect_independent_postconditions vs pc_relation cs1' cs2')\n  );\n  assert (statement_effect_independent_postconditions vs pc_relation cs1' cs2')\n"
  },
  {
    "path": "experimental/lib/Strategies.GlobalVars.Statement.fsti",
    "content": "module Strategies.GlobalVars.Statement\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Computation\nopen Armada.State\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Type\nopen Spec.Ubool\nopen Strategies.ArmadaInvariant.RootsMatch\nopen Strategies.ArmadaInvariant.PositionsValid\nopen Strategies.ArmadaInvariant.UnstartedThreads\nopen Strategies.GlobalVars\nopen Strategies.PCIndices\nopen Strategies.PCRelation\nopen Util.ImmutableArray\nopen Util.Relation\n\nlet statements_match_per_pc_relation\n  (relation: relation_t pc_t pc_t)\n  (return_relation: relation_t pc_t pc_t)\n  (statement1: Armada.Statement.t)\n  (statement2: Armada.Statement.t)\n  : GTot ubool =\n  match statement1 with\n  | CreateThreadStatement method_id1 initial_pc1 bypassing_write_buffer1 optional_result1 parameter_var_ids1\n                          parameter_expressions1 local_variable_initializers1 ->\n      (match statement2 with\n       | CreateThreadStatement method_id2 initial_pc2 bypassing_write_buffer2 optional_result2 parameter_var_ids2\n                               parameter_expressions2 local_variable_initializers2 ->\n              method_id1 = method_id2\n           /\\ relation initial_pc1 initial_pc2\n           /\\ bypassing_write_buffer1 = bypassing_write_buffer2\n           /\\ optional_result1 == optional_result2\n           /\\ parameter_var_ids1 = parameter_var_ids2\n           /\\ parameter_expressions1 == parameter_expressions2\n           /\\ local_variable_initializers1 == local_variable_initializers2\n       | _ -> False)\n  | MethodCallStatement method_id1 return_pc1 parameter_var_ids1 parameter_expressions1 local_variable_initializers1\n                          stack_overflow1 ->\n      (match statement2 with\n       | MethodCallStatement method_id2 return_pc2 parameter_var_ids2 parameter_expressions2\n                             local_variable_initializers2 stack_overflow2 ->\n              method_id1 = method_id2\n           /\\ relation return_pc1 return_pc2\n           /\\ return_relation return_pc1 return_pc2\n           /\\ parameter_var_ids1 = parameter_var_ids2\n           /\\ parameter_expressions1 == parameter_expressions2\n           /\\ local_variable_initializers1 == local_variable_initializers2\n           /\\ stack_overflow1 = stack_overflow2\n       | _ -> False)\n  | _ -> statement2 == statement1\n\nlet efficient_statements_match_per_pc_relation\n  (relation: relation_t nat nat)\n  (return_relation: relation_t nat nat)\n  (statement1: Armada.Statement.t)\n  (statement2: Armada.Statement.t)\n  (pc_indices1: statement_pc_indices_t)\n  (pc_indices2: statement_pc_indices_t)\n  : GTot ubool =\n  match statement1 with\n  | CreateThreadStatement method_id1 initial_pc1 bypassing_write_buffer1 optional_result1 parameter_var_ids1\n                          parameter_expressions1 local_variable_initializers1 ->\n      (match statement2 with\n       | CreateThreadStatement method_id2 initial_pc2 bypassing_write_buffer2 optional_result2 parameter_var_ids2\n                               parameter_expressions2 local_variable_initializers2 ->\n              method_id1 = method_id2\n           /\\ bypassing_write_buffer1 = bypassing_write_buffer2\n           /\\ optional_result1 == optional_result2\n           /\\ parameter_var_ids1 = parameter_var_ids2\n           /\\ parameter_expressions1 == parameter_expressions2\n           /\\ local_variable_initializers1 == local_variable_initializers2\n           /\\ (match pc_indices1.create_thread_initial_pc_index, pc_indices2.create_thread_initial_pc_index with\n              | Some idx1, Some idx2 -> relation idx1 idx2\n              | _, _ -> False)\n       | _ -> False)\n  | MethodCallStatement method_id1 return_pc1 parameter_var_ids1 parameter_expressions1 local_variable_initializers1\n                          stack_overflow1 ->\n      (match statement2 with\n       | MethodCallStatement method_id2 return_pc2 parameter_var_ids2 parameter_expressions2\n                             local_variable_initializers2 stack_overflow2 ->\n              method_id1 = method_id2\n           /\\ parameter_var_ids1 = parameter_var_ids2\n           /\\ parameter_expressions1 == parameter_expressions2\n           /\\ local_variable_initializers1 == local_variable_initializers2\n           /\\ stack_overflow1 = stack_overflow2\n           /\\ (match pc_indices1.method_call_return_pc_index, pc_indices2.method_call_return_pc_index with\n              | Some idx1, Some idx2 -> relation idx1 idx2 /\\ return_relation idx1 idx2\n              | _, _ -> False)\n       | _ -> False)\n  | _ -> statement2 == statement1\n\nlet efficient_statements_match_per_pc_relation_implies_statements_match_per_pc_relation\n  (pcs1: array_t pc_t)\n  (pcs2: array_t pc_t)\n  (idx_relation: relation_t nat nat)\n  (idx_return_relation: relation_t nat nat)\n  (pc_relation: relation_t pc_t pc_t)\n  (pc_return_relation: relation_t pc_t pc_t)\n  (ps1: program_statement_t)\n  (ps2: program_statement_t)\n  (pc_indices1: statement_pc_indices_t)\n  (pc_indices2: statement_pc_indices_t)\n  : Lemma (requires   program_statement_corresponds_to_statement_pc_indices pcs1 ps1 pc_indices1\n                    /\\ program_statement_corresponds_to_statement_pc_indices pcs2 ps2 pc_indices2\n                    /\\ efficient_statements_match_per_pc_relation idx_relation idx_return_relation\n                        ps1.statement ps2.statement pc_indices1 pc_indices2\n                    /\\ (forall (idx1: nat) (idx2: nat). idx1 < array_len pcs1 /\\ idx2 < array_len pcs2 ==>\n                         (let pc1 = array_index pcs1 idx1 in\n                          let pc2 = array_index pcs2 idx2 in\n                            (idx_relation idx1 idx2 ==> pc_relation pc1 pc2)\n                          /\\ (idx_return_relation idx1 idx2 ==> pc_return_relation pc1 pc2))))\n          (ensures statements_match_per_pc_relation pc_relation pc_return_relation ps1.statement ps2.statement) =\n  ()\n\nlet program_statement_end_pcs_match_per_pc_relation\n  (relation: relation_t pc_t pc_t)\n  (return_relation: relation_t pc_t pc_t)\n  (ps1: program_statement_t)\n  (ps2: program_statement_t)\n  : GTot ubool =\n  match ps1.end_pc, ps2.end_pc with\n  | Some pc1, Some pc2 -> relation pc1 pc2 /\\ (ReturnStatement? ps1.statement ==> return_relation pc1 pc2)\n  | None, None -> True\n  | _, _ -> False\n\nlet efficient_program_statement_end_pcs_match_per_pc_relation\n  (relation: relation_t nat nat)\n  (return_relation: relation_t nat nat)\n  (ps1: program_statement_t)\n  (ps2: program_statement_t)\n  (pc_indices1: statement_pc_indices_t)\n  (pc_indices2: statement_pc_indices_t)\n  : GTot ubool =\n  match pc_indices1.end_pc_index, pc_indices2.end_pc_index with\n  | Some pc1, Some pc2 -> relation pc1 pc2 /\\ (ReturnStatement? ps1.statement ==> return_relation pc1 pc2)\n  | None, None -> True\n  | _, _ -> False\n\nlet efficient_statement_end_pcs_match_per_pc_relation_implies_program_statement_end_pcs_match_per_pc_relation\n  (pcs1: array_t pc_t)\n  (pcs2: array_t pc_t)\n  (idx_relation: relation_t nat nat)\n  (idx_return_relation: relation_t nat nat)\n  (pc_relation: relation_t pc_t pc_t)\n  (pc_return_relation: relation_t pc_t pc_t)\n  (ps1: program_statement_t)\n  (ps2: program_statement_t)\n  (pc_indices1: statement_pc_indices_t)\n  (pc_indices2: statement_pc_indices_t)\n  : Lemma (requires   program_statement_corresponds_to_statement_pc_indices pcs1 ps1 pc_indices1\n                    /\\ program_statement_corresponds_to_statement_pc_indices pcs2 ps2 pc_indices2\n                    /\\ efficient_program_statement_end_pcs_match_per_pc_relation idx_relation idx_return_relation\n                        ps1 ps2 pc_indices1 pc_indices2\n                    /\\ (forall (idx1: nat) (idx2: nat). idx1 < array_len pcs1 /\\ idx2 < array_len pcs2 ==>\n                         (let pc1 = array_index pcs1 idx1 in\n                          let pc2 = array_index pcs2 idx2 in\n                            (idx_relation idx1 idx2 ==> pc_relation pc1 pc2)\n                          /\\ (idx_return_relation idx1 idx2 ==> pc_return_relation pc1 pc2))))\n          (ensures program_statement_end_pcs_match_per_pc_relation pc_relation pc_return_relation ps1 ps2) =\n  ()\n\nlet program_statements_match_per_pc_relation\n  (relation: relation_t pc_t pc_t)\n  (return_relation: relation_t pc_t pc_t)\n  (ps1: program_statement_t)\n  (ps2: program_statement_t)\n  : GTot ubool =\n     statements_match_per_pc_relation relation return_relation ps1.statement ps2.statement\n   /\\ program_statement_end_pcs_match_per_pc_relation relation return_relation ps1 ps2\n\nlet efficient_program_statements_match_per_pc_relation\n  (relation: relation_t nat nat)\n  (return_relation: relation_t nat nat)\n  (ps1: program_statement_t)\n  (ps2: program_statement_t)\n  (pc_indices1: statement_pc_indices_t)\n  (pc_indices2: statement_pc_indices_t)\n  : GTot ubool =\n     efficient_statements_match_per_pc_relation relation return_relation ps1.statement ps2.statement pc_indices1\n       pc_indices2\n   /\\ efficient_program_statement_end_pcs_match_per_pc_relation relation return_relation ps1 ps2 pc_indices1 pc_indices2\n\nlet efficient_program_statements_match_per_pc_relation_implies_program_statements_match_per_pc_relation\n  (pcs1: array_t pc_t)\n  (pcs2: array_t pc_t)\n  (idx_relation: relation_t nat nat)\n  (idx_return_relation: relation_t nat nat)\n  (pc_relation: relation_t pc_t pc_t)\n  (pc_return_relation: relation_t pc_t pc_t)\n  (ps1: program_statement_t)\n  (ps2: program_statement_t)\n  (pc_indices1: statement_pc_indices_t)\n  (pc_indices2: statement_pc_indices_t)\n  : Lemma (requires   program_statement_corresponds_to_statement_pc_indices pcs1 ps1 pc_indices1\n                    /\\ program_statement_corresponds_to_statement_pc_indices pcs2 ps2 pc_indices2\n                    /\\ efficient_program_statements_match_per_pc_relation idx_relation idx_return_relation\n                        ps1 ps2 pc_indices1 pc_indices2\n                    /\\ (forall (idx1: nat) (idx2: nat). idx1 < array_len pcs1 /\\ idx2 < array_len pcs2 ==>\n                         (let pc1 = array_index pcs1 idx1 in\n                          let pc2 = array_index pcs2 idx2 in\n                            (idx_relation idx1 idx2 ==> pc_relation pc1 pc2)\n                          /\\ (idx_return_relation idx1 idx2 ==> pc_return_relation pc1 pc2))))\n          (ensures program_statements_match_per_pc_relation pc_relation pc_return_relation ps1 ps2) =\n  efficient_statement_end_pcs_match_per_pc_relation_implies_program_statement_end_pcs_match_per_pc_relation\n    pcs1 pcs2 idx_relation idx_return_relation pc_relation pc_return_relation ps1 ps2 pc_indices1 pc_indices2;\n  efficient_statements_match_per_pc_relation_implies_statements_match_per_pc_relation pcs1 pcs2 idx_relation\n    idx_return_relation pc_relation pc_return_relation ps1 ps2 pc_indices1 pc_indices2\n\nlet statement_effect_independent_of_global_variables\n  (vs: list var_id_t)\n  (statement: Armada.Statement.t)\n  : GTot bool =\n  match statement with\n  | AssumeExpressionStatement exp ->\n      global_variables_unmentioned_in_expression vs exp\n  | AssumePredicateStatement pred ->\n      false\n  | AssertTrueStatement exp ->\n      global_variables_unmentioned_in_expression vs exp\n  | AssertFalseStatement exp ->\n      global_variables_unmentioned_in_expression vs exp\n  | ConditionalJumpStatement cond ->\n      global_variables_unmentioned_in_expression vs cond\n  | UnconditionalJumpStatement ->\n      true\n  | UpdateStatement _ dst src ->\n         global_variables_unmentioned_in_expression vs dst\n      && global_variables_unmentioned_in_expression vs src\n  | NondeterministicUpdateStatement _ dst ->\n      global_variables_unmentioned_in_expression vs dst\n  | PropagateWriteMessageStatement ->\n      false\n  | CompareAndSwapStatement target old_val new_val bypassing_write_buffer optional_result ->\n         global_variables_unmentioned_in_expression vs target\n      && global_variables_unmentioned_in_expression vs old_val\n      && global_variables_unmentioned_in_expression vs new_val\n      && global_variables_unmentioned_in_optional_expression vs optional_result\n  | AtomicExchangeStatement old_val target new_val ->\n         global_variables_unmentioned_in_expression vs old_val\n      && global_variables_unmentioned_in_expression vs target\n      && global_variables_unmentioned_in_expression vs new_val\n  | CreateThreadStatement _ _ _ option_result _ parameter_expressions local_variable_initializers ->\n         global_variables_unmentioned_in_optional_expression vs option_result\n      && global_variables_unmentioned_in_expressions vs parameter_expressions\n      && global_variables_unaddressed_in_initializers vs local_variable_initializers\n  | MethodCallStatement _ _ parameter_var_ids parameter_expressions local_variable_initializers stack_overflow ->\n         global_variables_unmentioned_in_expressions vs parameter_expressions\n      && global_variables_unaddressed_in_initializers vs local_variable_initializers\n  | ReturnStatement _ _ output_dsts output_srcs ->\n         global_variables_unmentioned_in_expressions vs output_dsts\n      && global_variables_unmentioned_in_expressions vs output_srcs\n  | TerminateThreadStatement _ ->\n      true\n  | TerminateProcessStatement _ ->\n      true\n  | JoinStatement join_tid ->\n      global_variables_unmentioned_in_expression vs join_tid\n  | MallocSuccessfulStatement _ result _ count ->\n         global_variables_unmentioned_in_expression vs result\n      && global_variables_unmentioned_in_expression vs count\n  | MallocReturningNullStatement _ result count ->\n         global_variables_unmentioned_in_expression vs result\n      && global_variables_unmentioned_in_expression vs count\n  | CallocSuccessfulStatement _ result _ count ->\n         global_variables_unmentioned_in_expression vs result\n      && global_variables_unmentioned_in_expression vs count\n  | CallocReturningNullStatement _ result count ->\n         global_variables_unmentioned_in_expression vs result\n      && global_variables_unmentioned_in_expression vs count\n  | DeallocStatement ptr ->\n      global_variables_unmentioned_in_expression vs ptr\n\n  // For SomehowStatement, we have no idea what's put into the\n  // destinations specified in modifies clauses.  So all we can do is\n  // make sure that none of those destinations has any pointer fields.\n  \n  | SomehowStatement undefined_unless_cond _ modifies_clauses ensures_cond ->\n         global_variables_unmentioned_in_expression vs undefined_unless_cond\n      && global_variables_unmentioned_in_expressions vs modifies_clauses\n      && expressions_lack_pointer_field modifies_clauses\n      && global_variables_unmentioned_in_expression vs ensures_cond\n\n  | FenceStatement ->\n      true\n\n  // For ExternalMethodStartStatement and\n  // ExternalMethodMiddleStatement, we have no idea what's put into\n  // the destinations specified in modifies clauses.  So all we can do\n  // is make sure that none of those destinations has any pointer\n  // fields.\n\n  | ExternalMethodStartStatement await_cond undefined_unless_cond _ modifies_clauses reads_clauses ->\n         global_variables_unmentioned_in_expression vs await_cond\n      && global_variables_unmentioned_in_expression vs undefined_unless_cond\n      && global_variables_unmentioned_in_expressions vs modifies_clauses\n      && expressions_lack_pointer_field modifies_clauses\n      && global_variables_unmentioned_in_reads_clauses vs reads_clauses\n  | ExternalMethodMiddleStatement _ modifies_clauses reads_clauses ->\n         global_variables_unmentioned_in_expressions vs modifies_clauses\n      && expressions_lack_pointer_field modifies_clauses\n      && global_variables_unmentioned_in_reads_clauses vs reads_clauses\n\n  | ExternalMethodEndStatement ensures_cond logs_clauses ->\n         global_variables_unmentioned_in_expression vs ensures_cond\n      && global_variables_unmentioned_in_expressions vs logs_clauses\n\nval statement_effect_independent_implications\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc1: pc_t)\n  (start_pc2: pc_t)\n  (end_pc1: option pc_t)\n  (end_pc2: option pc_t)\n  (statement1: Armada.Statement.t)\n  (statement2: Armada.Statement.t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   states_match_except_global_variables vs pc_relation s1 s2\n                    /\\ global_variables_unaddressed_in_memory vs s1.mem\n                    /\\ global_variables_unaddressed_in_memory vs s2.mem\n                    /\\ roots_match s1.mem\n                    /\\ roots_match s2.mem\n                    /\\ unstarted_threads_have_empty_write_buffers s1\n                    /\\ unstarted_threads_have_empty_write_buffers s2\n                    /\\ statement_effect_independent_of_global_variables vs statement1\n                    /\\ statements_match_per_pc_relation pc_relation.relation pc_relation.return_relation\n                        statement1 statement2\n                    /\\ pc_relation.relation start_pc1 start_pc2\n                    /\\ ThreadStatusRunning? (s1.threads actor).status\n                    /\\ (match end_pc1, end_pc2 with\n                       | Some pc1, Some pc2 ->\n                              pc_relation.relation pc1 pc2\n                           /\\ (ReturnStatement? statement1 ==> pc_relation.return_relation pc1 pc2)\n                       | None, None -> True\n                       | _, _ -> False))\n          (ensures  (match statement_computation actor nd start_pc1 end_pc1 statement1 s1,\n                           statement_computation actor nd start_pc2 end_pc2 statement2 s2 with\n                     | ComputationProduces s1', ComputationProduces s2' ->\n                           states_match_except_global_variables vs pc_relation s1' s2'\n                         /\\ global_variables_unaddressed_in_memory vs s1'.mem\n                         /\\ global_variables_unaddressed_in_memory vs s2'.mem\n                         /\\ roots_match s1'.mem\n                         /\\ roots_match s2'.mem\n                     | ComputationImpossible, ComputationImpossible -> True\n                     | ComputationUndefined, ComputationUndefined -> True\n                     | _ -> False))\n"
  },
  {
    "path": "experimental/lib/Strategies.GlobalVars.Types.fst",
    "content": "module Strategies.GlobalVars.Types\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Computation\nopen Armada.Expression\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Pointer\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Transition\nopen Armada.Type\nopen FStar.Sequence.Base\nopen FStar.Tactics.V2\nopen Spec.List\nopen Spec.Map\nopen Spec.Ubool\nopen Strategies.ArmadaStatement\nopen Util.List\nopen Util.Tactics\n\nlet gvar_has_type (mem: Armada.Memory.t) (v: var_id_t) (td: object_td_t) : GTot ubool =\n  let root_id = RootIdGlobal v in\n  let root = mem root_id in\n  match root with\n  | RootGlobal storage -> object_storage_to_td storage == td\n  | _ -> False\n\nlet all_gvars_have_types (mem: Armada.Memory.t) (vs: list var_id_t) (tds: list object_td_t) : GTot ubool =\n  lists_correspond_ubool (gvar_has_type mem) vs tds\n\nlet rec update_pointer_directly_maintains_gvar_has_type\n  (v: var_id_t)\n  (td: object_td_t)\n  (p: Armada.Pointer.t)\n  (new_storage: valid_object_storage_t)\n  (mem: Armada.Memory.t)\n  : Lemma (requires gvar_has_type mem v td)\n          (ensures  (match update_pointer_directly p new_storage mem with\n                     | ComputationProduces mem' -> gvar_has_type mem' v td\n                     | _ -> True)) =\n  match update_pointer_directly p new_storage mem with\n  | ComputationImpossible | ComputationUndefined -> ()\n  | ComputationProduces mem' ->\n      (match p with\n       | PointerField struct_ptr field_id ->\n           let parent = ComputationProduces?.result (dereference_computation struct_ptr mem) in\n           (match parent with\n            | ObjectStorageStruct fields ->\n                let new_parent = update_storage_child parent field_id new_storage in\n                update_pointer_directly_maintains_gvar_has_type v td struct_ptr new_parent mem)\n       | PointerIndex array_ptr idx ->\n           let parent = ComputationProduces?.result (dereference_computation array_ptr mem) in\n           (match parent with\n            | ObjectStorageArray element_td elements ->\n                let new_parent = update_storage_child parent idx new_storage in\n                update_pointer_directly_maintains_gvar_has_type v td array_ptr new_parent mem)\n       | PointerRoot root_id -> ()\n       | _ -> ())\n\n#push-options \"--z3rlimit 10\"\n\nlet update_pointer_maintains_gvar_has_type\n  (v: var_id_t)\n  (td: object_td_t)\n  (p: Armada.Pointer.t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (new_value: object_value_t)\n  (mem: Armada.Memory.t)\n  : Lemma (requires gvar_has_type mem v td)\n          (ensures  (match update_pointer p actor writer_pc writer_expression_number bypassing_write_buffer\n                             new_value mem with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces (optional_write_message, mem') -> gvar_has_type mem' v td)) =\n  match p with\n  | PointerUninitialized -> ()\n  | PointerNull -> ()\n  | PointerRoot root_id -> ()\n  | PointerField struct_ptr field_id ->\n      (match dereference_computation struct_ptr mem with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces parent ->\n           (match parent with\n            | ObjectStorageStruct fields ->\n                if field_id >= length fields then\n                  ()\n                else\n                  let field = index fields field_id in\n                  if   not (object_storage_valid field)\n                     || neqb (object_storage_to_td field) (object_value_to_td new_value) then\n                    ()\n                  else\n                    (match update_storage p actor writer_pc writer_expression_number\n                             bypassing_write_buffer field new_value with\n                     | ComputationImpossible | ComputationUndefined -> ()\n                     | ComputationProduces (write_message, new_field) ->\n                         if (not (can_update_storage_child parent field_id new_field)) then\n                           ()\n                         else\n                           let new_parent = update_storage_child parent field_id new_field in\n                           update_pointer_directly_maintains_gvar_has_type v td struct_ptr new_parent mem)\n            | _ -> ()))\n  | PointerIndex array_ptr idx ->\n      (match dereference_computation array_ptr mem with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces parent ->\n           (match parent with\n            | ObjectStorageArray element_td elements ->\n                if idx < 0 || idx >= length elements then\n                  ()\n                else\n                  let element = index elements idx in\n                  if not (object_storage_valid element) then\n                    ()\n                  else\n                    (match update_storage p actor writer_pc writer_expression_number\n                             bypassing_write_buffer element new_value with\n                     | ComputationImpossible | ComputationUndefined -> ()\n                     | ComputationProduces (write_message, new_element) ->\n                         if not (can_update_storage_child parent idx new_element) then\n                           ()\n                         else\n                           let new_parent = update_storage_child parent idx new_element in\n                           update_pointer_directly_maintains_gvar_has_type v td array_ptr new_parent mem)\n            | _ -> ()))\n\n#pop-options\n\nlet update_pointed_to_value_maintains_gvar_has_type\n  (v: var_id_t)\n  (td: object_td_t)\n  (p: Armada.Pointer.t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (new_value: object_value_t)\n  (s: Armada.State.t)\n  : Lemma (requires gvar_has_type s.mem v td)\n          (ensures  (match update_pointed_to_value p actor writer_pc writer_expression_number bypassing_write_buffer\n                             new_value s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> gvar_has_type s'.mem v td)) =\n  update_pointer_maintains_gvar_has_type v td p actor writer_pc writer_expression_number bypassing_write_buffer\n    new_value s.mem\n\nlet update_expression_maintains_gvar_has_type\n  (v: var_id_t)\n  (td: object_td_t)\n  (exp: expression_t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (new_value: object_value_t)\n  (s: Armada.State.t)\n  : Lemma (requires gvar_has_type s.mem v td)\n          (ensures  (match update_expression exp actor writer_pc writer_expression_number bypassing_write_buffer\n                             new_value s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> gvar_has_type s'.mem v td)) =\n  let s' = update_expression exp actor writer_pc writer_expression_number bypassing_write_buffer\n             new_value s in\n  if   not (expression_valid exp)\n     || not (object_value_valid new_value)\n     || neqb (object_value_to_td new_value) (expression_to_td exp) then\n    ()\n  else (\n    match lvalue_computation exp actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces p ->\n        update_pointed_to_value_maintains_gvar_has_type v td p actor writer_pc writer_expression_number\n          bypassing_write_buffer new_value s\n  )\n\nlet rec update_expressions_maintains_gvar_has_type\n  (v: var_id_t)\n  (td: object_td_t)\n  (exps: list expression_t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (new_values: list object_value_t)\n  (s: Armada.State.t)\n  : Lemma (requires gvar_has_type s.mem v td)\n          (ensures  (match update_expressions exps actor writer_pc writer_expression_number bypassing_write_buffer\n                             new_values s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> gvar_has_type s'.mem v td))\n          (decreases exps) =\n  match exps, new_values with\n  | [], [] -> ()\n  | first_exp :: remaining_exps, first_new_value :: remaining_new_values ->\n      update_expression_maintains_gvar_has_type v td first_exp actor writer_pc writer_expression_number\n        bypassing_write_buffer first_new_value s;\n      (match update_expression first_exp actor writer_pc writer_expression_number\n               bypassing_write_buffer first_new_value s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces s' ->\n           update_expressions_maintains_gvar_has_type v td remaining_exps actor writer_pc\n             (writer_expression_number + 1) bypassing_write_buffer remaining_new_values s')\n  | _ -> ()\n\nlet push_stack_variable_maintains_gvar_has_type\n  (v: var_id_t)\n  (td: object_td_t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (initializer: initializer_t)\n  (s: Armada.State.t)\n  : Lemma (requires gvar_has_type s.mem v td)\n          (ensures  (match push_stack_variable actor writer_pc writer_expression_number method_id frame_uniq\n                             initializer s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> gvar_has_type s'.mem v td)) =\n  let root_id = RootIdStack actor method_id frame_uniq initializer.var_id in\n  let root = s.mem root_id in\n  if not (stack_variable_ready_for_push root initializer) then\n    ()\n  else\n    let thread = s.threads actor in\n    let var_id = initializer.var_id in\n    if list_contains var_id thread.top.local_variables then\n      ()\n    else\n      let local_variables' = var_id :: thread.top.local_variables in\n      let top' = { thread.top with local_variables = local_variables' } in\n      let thread' = { thread with top = top' } in\n      let threads' = Spec.Map.upd s.threads actor thread' in\n      let root' = RootStackVariable true false (RootStackVariable?.storage root) in\n      let mem' = upd s.mem root_id root' in\n      let s' = { s with mem = mem'; threads = threads' } in\n      (match initializer.iv with\n       | InitializerArbitrary td -> ()\n       | InitializerSpecific value ->\n           let td' = object_value_to_td value in\n           update_expression_maintains_gvar_has_type v td (ExpressionLocalVariable td' var_id) actor writer_pc\n             writer_expression_number false value s')\n\nlet rec push_stack_variables_maintains_gvar_has_type\n  (v: var_id_t)\n  (td: object_td_t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (initializers: list initializer_t)\n  (s: Armada.State.t)\n  : Lemma (requires gvar_has_type s.mem v td)\n          (ensures  (match push_stack_variables actor writer_pc writer_expression_number method_id\n                             frame_uniq initializers s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> gvar_has_type s'.mem v td))\n          (decreases initializers) =\n  match initializers with\n  | [] -> ()\n  | first_initializer :: remaining_initializers ->\n      push_stack_variable_maintains_gvar_has_type v td actor writer_pc writer_expression_number method_id frame_uniq\n        first_initializer s;\n      (match push_stack_variable actor writer_pc writer_expression_number method_id frame_uniq first_initializer s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces s' ->\n           push_stack_variables_maintains_gvar_has_type v td actor writer_pc (writer_expression_number + 1)\n             method_id frame_uniq remaining_initializers s')\n\nlet rec push_stack_parameters_maintains_gvar_has_type\n  (v: var_id_t)\n  (td: object_td_t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (var_ids: list var_id_t)\n  (parameters: list object_value_t)\n  (s: Armada.State.t)\n  : Lemma (requires gvar_has_type s.mem v td)\n          (ensures  (match push_stack_parameters actor writer_pc writer_expression_number method_id frame_uniq\n                             var_ids parameters s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> gvar_has_type s'.mem v td))\n          (decreases parameters) =\n  match parameters, var_ids with\n  | [], [] -> ()\n  | first_parameter :: remaining_parameters, first_var_id :: remaining_var_ids ->\n      let first_initializer =\n        { var_id = first_var_id; iv = InitializerSpecific first_parameter; weakly_consistent = false } in\n      push_stack_variable_maintains_gvar_has_type v td actor writer_pc writer_expression_number method_id frame_uniq\n        first_initializer s;\n      (match push_stack_variable actor writer_pc writer_expression_number method_id frame_uniq first_initializer s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces s' ->\n           push_stack_parameters_maintains_gvar_has_type v td actor writer_pc (writer_expression_number + 1)\n             method_id frame_uniq remaining_var_ids remaining_parameters s')\n  | _ -> ()\n\nlet rec pop_stack_variables_maintains_gvar_has_type\n  (v: var_id_t)\n  (td: object_td_t)\n  (actor: tid_t)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (var_ids: list var_id_t)\n  (mem: Armada.Memory.t)\n  : Lemma (requires gvar_has_type mem v td)\n          (ensures  (match pop_stack_variables actor method_id frame_uniq var_ids mem with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces mem' -> gvar_has_type mem' v td)) =\n  match var_ids with\n  | [] -> ()\n  | first_var_id :: remaining_var_ids ->\n      (match pop_stack_variable actor method_id frame_uniq first_var_id mem with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces mem' ->\n           pop_stack_variables_maintains_gvar_has_type v td actor method_id frame_uniq remaining_var_ids mem')\n\nlet rec external_method_take_snapshot_of_reads_clauses_computation_maintains_gvar_has_type\n  (v: var_id_t)\n  (td: object_td_t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (reads_clauses: list (var_id_t * expression_t))\n  (s: Armada.State.t)\n  : Lemma (requires gvar_has_type s.mem v td)\n          (ensures  (match external_method_take_snapshot_of_reads_clauses_computation actor writer_pc\n                             writer_expression_number bypassing_write_buffer reads_clauses s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> gvar_has_type s'.mem v td))\n          (decreases reads_clauses) =\n  match reads_clauses with\n  | [] -> ()\n  | (first_var_id, first_reads_expression) :: remaining_reads_clauses ->\n      (match rvalue_computation first_reads_expression actor s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces first_value ->\n           let td' = expression_to_td first_reads_expression in\n           let local_var = ExpressionLocalVariable td' first_var_id in\n           update_expression_maintains_gvar_has_type v td local_var actor writer_pc writer_expression_number\n             bypassing_write_buffer first_value s;\n           (match update_expression local_var actor writer_pc writer_expression_number bypassing_write_buffer\n                    first_value s with\n            | ComputationImpossible | ComputationUndefined -> ()\n            | ComputationProduces s' ->\n                external_method_take_snapshot_of_reads_clauses_computation_maintains_gvar_has_type v td\n                  actor writer_pc (writer_expression_number + 1) bypassing_write_buffer remaining_reads_clauses s'))\n  | _ -> ()\n\nlet rec log_expressions_computation_maintains_gvar_has_type\n  (v: var_id_t)\n  (td: object_td_t)\n  (actor: tid_t)\n  (logs_clauses: list expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires gvar_has_type s.mem v td)\n          (ensures  (match log_expressions_computation actor logs_clauses s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> gvar_has_type s'.mem v td))\n          (decreases logs_clauses) =\n  match logs_clauses with\n  | [] -> ()\n  | first_logs_clause :: remaining_logs_clauses ->\n      (match rvalue_computation first_logs_clause actor s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces event ->\n           let trace' = s.trace $:: event in\n           let s' = { s with trace = trace' } in\n           log_expressions_computation_maintains_gvar_has_type v td actor remaining_logs_clauses s')\n\nlet propagate_write_message_maintains_gvar_has_type\n  (v: var_id_t)\n  (td: object_td_t)\n  (write_message: write_message_t)\n  (receiver_tid: tid_t)\n  (mem: Armada.Memory.t)\n  : Lemma (requires gvar_has_type mem v td)\n          (ensures  (match propagate_write_message write_message receiver_tid mem with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces mem' -> gvar_has_type mem' v td)) =\n  let p = write_message.location in\n  match dereference_computation p mem with\n  | ComputationImpossible | ComputationUndefined -> ()\n  | ComputationProduces storage ->\n      (match storage with\n       | ObjectStorageWeaklyConsistentPrimitive primitive_td values local_versions ->\n           if   primitive_td <> write_message.primitive_td\n              || write_message.version >= length values\n              || local_versions receiver_tid >= write_message.version then\n             ()\n           else\n             let new_local_versions = Spec.Map.upd local_versions receiver_tid write_message.version in\n             let new_storage = ObjectStorageWeaklyConsistentPrimitive primitive_td values\n                                 new_local_versions in\n             if not (object_storage_valid new_storage) then\n               ()\n             else\n               update_pointer_directly_maintains_gvar_has_type v td p new_storage mem\n       | _ -> ())\n\nlet free_pointer_maintains_gvar_has_type\n  (v: var_id_t)\n  (td: object_td_t)\n  (p: Armada.Pointer.t)\n  (mem: Armada.Memory.t)\n  : Lemma (requires gvar_has_type mem v td)\n          (ensures  (match free_pointer p mem with\n                     | ComputationProduces mem' -> gvar_has_type mem' v td\n                     | _ -> True)) =\n  ()\n\n#push-options \"--z3rlimit 10\"\n\nlet assume_expression_statement_computation_maintains_gvar_has_type\n  (v: var_id_t)\n  (td: object_td_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (exp: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires gvar_has_type s.mem v td)\n          (ensures  (match assume_expression_statement_computation actor nd start_pc exp s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> gvar_has_type s'.mem v td)) =\n  ()\n\nlet assume_predicate_statement_computation_maintains_gvar_has_type\n  (v: var_id_t)\n  (td: object_td_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (pred: Armada.State.t -> GTot bool)\n  (s: Armada.State.t)\n  : Lemma (requires gvar_has_type s.mem v td)\n          (ensures  (match assume_predicate_statement_computation actor nd start_pc pred s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> gvar_has_type s'.mem v td)) =\n  ()\n\nlet assert_true_statement_computation_maintains_gvar_has_type\n  (v: var_id_t)\n  (td: object_td_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (exp: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires gvar_has_type s.mem v td)\n          (ensures  (match assert_true_statement_computation actor nd start_pc exp s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> gvar_has_type s'.mem v td)) =\n  ()\n\nlet assert_false_statement_computation_maintains_gvar_has_type\n  (v: var_id_t)\n  (td: object_td_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (exp: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires gvar_has_type s.mem v td)\n          (ensures  (match assert_false_statement_computation actor nd start_pc exp s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> gvar_has_type s'.mem v td)) =\n  ()\n\nlet conditional_jump_statement_computation_maintains_gvar_has_type\n  (v: var_id_t)\n  (td: object_td_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (exp: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires gvar_has_type s.mem v td)\n          (ensures  (match conditional_jump_statement_computation actor nd start_pc exp s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> gvar_has_type s'.mem v td)) =\n  ()\n\nlet unconditional_jump_statement_computation_maintains_gvar_has_type\n  (v: var_id_t)\n  (td: object_td_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (s: Armada.State.t)\n  : Lemma (requires gvar_has_type s.mem v td)\n          (ensures  (match unconditional_jump_statement_computation actor nd start_pc s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> gvar_has_type s'.mem v td)) =\n  ()\n\nlet update_statement_computation_maintains_gvar_has_type\n  (v: var_id_t)\n  (td: object_td_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (bypassing_write_buffer: bool)\n  (dst: expression_t)\n  (src: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires gvar_has_type s.mem v td)\n          (ensures  (match update_statement_computation actor nd start_pc bypassing_write_buffer dst src s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> gvar_has_type s'.mem v td)) =\n  let cs' = update_statement_computation actor nd start_pc bypassing_write_buffer dst src s in\n  if   Cons? nd\n     || neqb (expression_to_td dst) (expression_to_td src) then\n    ()\n  else (\n    match rvalue_computation src actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces src_value ->\n        update_expression_maintains_gvar_has_type v td dst actor start_pc 0 bypassing_write_buffer src_value s\n  )\n\nlet nondeterministic_update_statement_computation_maintains_gvar_has_type\n  (v: var_id_t)\n  (td: object_td_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (bypassing_write_buffer: bool)\n  (dst: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires gvar_has_type s.mem v td)\n          (ensures  (match nondeterministic_update_statement_computation actor nd start_pc bypassing_write_buffer\n                             dst s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> gvar_has_type s'.mem v td)) =\n  let cs' = nondeterministic_update_statement_computation actor nd start_pc bypassing_write_buffer dst s in\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (expression_to_td dst) then\n    ()\n  else (\n    let nd_value = Cons?.hd nd in\n    if not (object_value_has_all_pointers_uninitialized nd_value) then\n      ()\n    else\n      update_expression_maintains_gvar_has_type v td dst actor start_pc 0 bypassing_write_buffer nd_value s\n  )\n\nlet propagate_write_message_statement_computation_maintains_gvar_has_type\n  (v: var_id_t)\n  (td: object_td_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (s: Armada.State.t)\n  : Lemma (requires gvar_has_type s.mem v td)\n          (ensures  (match propagate_write_message_statement_computation actor nd s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> gvar_has_type s'.mem v td)) =\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract tid_t) then\n     ()\n  else\n    let receiver_tid: tid_t = ObjectValueAbstract?.value (Cons?.hd nd) in\n    if receiver_tid = actor then // can't propagate to the same thread\n      ()\n    else\n      let propagator_thread = s.threads actor in\n      let receiver_thread = s.threads receiver_tid in\n      let which_message = receiver_thread.position_in_other_write_buffers actor in\n      if which_message >= length propagator_thread.write_buffer then\n        ()\n      else\n        let write_message = index propagator_thread.write_buffer which_message in\n        propagate_write_message_maintains_gvar_has_type v td write_message receiver_tid s.mem\n\nlet compare_and_swap_statement_computation_maintains_gvar_has_type\n  (v: var_id_t)\n  (td: object_td_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (target: expression_t)\n  (old_val: expression_t)\n  (new_val: expression_t)\n  (bypassing_write_buffer: bool)\n  (optional_result: option expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires gvar_has_type s.mem v td)\n          (ensures  (match compare_and_swap_statement_computation actor nd start_pc target old_val new_val\n                             bypassing_write_buffer optional_result s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> gvar_has_type s'.mem v td)) =\n  let cs' = compare_and_swap_statement_computation actor nd start_pc target old_val new_val\n              bypassing_write_buffer optional_result s in\n  if   Cons? nd\n     || neqb (expression_to_td target) (expression_to_td old_val)\n     || neqb (expression_to_td target) (expression_to_td new_val)\n     || (match optional_result with\n        | Some result -> neqb (expression_to_td result) (ObjectTDPrimitive PrimitiveTDBool)\n        | None -> false) then\n    ()\n  else begin\n    match check_expression_up_to_date_for_rmw target actor s, rvalue_computation old_val actor s,\n          rvalue_computation target actor s, rvalue_computation new_val actor s,\n          lvalue_computation target actor s  with\n    | ComputationProduces _, ComputationProduces old_value,\n      ComputationProduces target_value, ComputationProduces new_value,\n      ComputationProduces target_ptr -> begin\n        let swap = eqb target_value old_value in\n        update_pointed_to_value_maintains_gvar_has_type v td target_ptr actor start_pc 0 false new_value s;\n        match optional_result with\n        | None -> ()\n        | Some result ->\n          match lvalue_computation result actor s, (if swap then update_pointed_to_value target_ptr actor start_pc 0 false new_value s else return s) with\n          | ComputationProduces result_ptr, ComputationProduces s' ->\n              let swap_value = ObjectValuePrimitive (PrimitiveBoxBool swap) in\n              update_pointed_to_value_maintains_gvar_has_type v td result_ptr actor start_pc 1 bypassing_write_buffer swap_value s'\n          | _ -> ()\n      end\n    | _ -> ()\n  end\n\nlet atomic_exchange_statement_computation_maintains_gvar_has_type\n  (v: var_id_t)\n  (td: object_td_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (old_val: expression_t)\n  (target: expression_t)\n  (new_val: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires gvar_has_type s.mem v td)\n          (ensures  (match atomic_exchange_statement_computation actor nd start_pc old_val target new_val s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> gvar_has_type s'.mem v td)) =\n  let cs' = atomic_exchange_statement_computation actor nd start_pc old_val target new_val s in\n  match check_expression_up_to_date_for_rmw target actor s, rvalue_computation target actor s, rvalue_computation new_val actor s, lvalue_computation old_val actor s, lvalue_computation target actor s with\n  | ComputationProduces _, ComputationProduces target_value, ComputationProduces new_value, ComputationProduces old_ptr, ComputationProduces target_ptr ->\n    update_pointed_to_value_maintains_gvar_has_type v td old_ptr actor start_pc 0 false target_value s;\n    begin match update_pointed_to_value old_ptr actor start_pc 0 false target_value s with\n          | ComputationProduces s' ->\n            update_pointed_to_value_maintains_gvar_has_type v td target_ptr actor start_pc 1 false new_value s'\n          | _ -> ()\n    end\n  | _ -> ()\n\nlet create_thread_statement_computation_maintains_gvar_has_type\n  (v: var_id_t)\n  (td: object_td_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (method_id: method_id_t)\n  (initial_pc: pc_t)\n  (bypassing_write_buffer: bool)\n  (optional_result: option expression_t)\n  (parameter_var_ids: list var_id_t)\n  (parameter_expressions: list expression_t)\n  (local_variable_initializers: list initializer_t)\n  (s: Armada.State.t)\n  : Lemma (requires gvar_has_type s.mem v td)\n          (ensures  (match create_thread_statement_computation actor nd start_pc method_id initial_pc\n                             bypassing_write_buffer optional_result parameter_var_ids parameter_expressions\n                             local_variable_initializers s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> gvar_has_type s'.mem v td)) =\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract create_thread_nd_t)\n     || (   Some? optional_result\n        && neqb (expression_to_td (Some?.v optional_result)) (ObjectTDPrimitive PrimitiveTDThreadId))\n     || list_len parameter_var_ids <> list_len parameter_expressions then\n    ()\n  else (\n    let create_thread_nd: create_thread_nd_t = ObjectValueAbstract?.value (Cons?.hd nd) in\n    let new_tid = create_thread_nd.new_tid in\n    if new_tid = 0 then\n      (match optional_result with\n       | None -> ()\n       | Some result ->\n          let new_tid_value = ObjectValuePrimitive (PrimitiveBoxThreadId new_tid) in\n          update_expression_maintains_gvar_has_type v td result actor start_pc\n            (list_len parameter_var_ids + list_len local_variable_initializers) bypassing_write_buffer\n            new_tid_value s)\n    else (\n      let frame_uniq = create_thread_nd.frame_uniq in\n      match rvalues_computation parameter_expressions actor s with\n      | ComputationImpossible | ComputationUndefined -> ()\n      | ComputationProduces parameter_values ->\n          let s2 = make_thread_running method_id initial_pc new_tid frame_uniq s in\n          push_stack_parameters_maintains_gvar_has_type v td new_tid start_pc 0 method_id\n            frame_uniq parameter_var_ids parameter_values s2;\n          (match push_stack_parameters new_tid start_pc 0 method_id frame_uniq parameter_var_ids\n                   parameter_values s2 with\n           | ComputationImpossible | ComputationUndefined -> ()\n           | ComputationProduces s3 ->\n                push_stack_variables_maintains_gvar_has_type v td new_tid start_pc\n                  (list_len parameter_var_ids) method_id frame_uniq local_variable_initializers s3;\n                (match push_stack_variables new_tid start_pc (list_len parameter_var_ids) method_id frame_uniq\n                         local_variable_initializers s3 with\n                 | ComputationImpossible | ComputationUndefined -> ()\n                 | ComputationProduces s4 ->\n                     (match optional_result with\n                      | None -> ()\n                      | Some result ->\n                         let new_tid_value = ObjectValuePrimitive (PrimitiveBoxThreadId new_tid) in\n                         update_expression_maintains_gvar_has_type v td result actor start_pc\n                           (list_len parameter_var_ids + list_len local_variable_initializers) bypassing_write_buffer\n                           new_tid_value s4)))\n    )\n  )\n\nlet method_call_statement_computation_maintains_gvar_has_type\n  (v: var_id_t)\n  (td: object_td_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (method_id: method_id_t)\n  (return_pc: pc_t)\n  (parameter_var_ids: list var_id_t)\n  (parameter_expressions: list expression_t)\n  (local_variable_initializers: list initializer_t)\n  (stack_overflow: bool)\n  (s: Armada.State.t)\n  : Lemma (requires gvar_has_type s.mem v td)\n          (ensures  (match method_call_statement_computation actor nd start_pc method_id return_pc parameter_var_ids\n                             parameter_expressions local_variable_initializers stack_overflow s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> gvar_has_type s'.mem v td)) =\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract method_call_nd_t) then\n    ()\n  else (\n    let method_call_nd: method_call_nd_t = ObjectValueAbstract?.value (Cons?.hd nd) in\n    let frame_uniq = method_call_nd.frame_uniq in\n    match rvalues_computation parameter_expressions actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces parameter_values ->\n        let s2 = push_stack_frame actor method_id return_pc frame_uniq s in\n        push_stack_parameters_maintains_gvar_has_type v td actor start_pc 0 method_id frame_uniq\n          parameter_var_ids parameter_values s2;\n        (match push_stack_parameters actor start_pc 0 method_id frame_uniq parameter_var_ids parameter_values s2 with\n         | ComputationImpossible | ComputationUndefined -> ()\n         | ComputationProduces s3 ->\n             push_stack_variables_maintains_gvar_has_type v td actor start_pc\n               (list_len parameter_var_ids) method_id frame_uniq\n               local_variable_initializers s3)\n  )\n\nlet return_statement_computation_maintains_gvar_has_type\n  (v: var_id_t)\n  (td: object_td_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (end_pc: option pc_t)\n  (method_id: method_id_t)\n  (bypassing_write_buffer: bool)\n  (output_dsts: list expression_t)\n  (output_srcs: list expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires gvar_has_type s.mem v td)\n          (ensures  (match return_statement_computation actor nd start_pc end_pc method_id bypassing_write_buffer\n                             output_dsts output_srcs s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> gvar_has_type s'.mem v td)) =\n  let thread = s.threads actor in\n  if   Cons? nd\n     || eqb thread.stack []\n     || thread.top.method_id <> method_id\n     || end_pc <> Some (Cons?.hd thread.stack).return_pc then\n    ()\n  else (\n    match rvalues_computation output_srcs actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces output_values ->\n        pop_stack_variables_maintains_gvar_has_type v td actor method_id thread.top.frame_uniq\n          thread.top.local_variables s.mem;\n        (match pop_stack_variables actor method_id thread.top.frame_uniq thread.top.local_variables s.mem with\n         | ComputationImpossible | ComputationUndefined -> ()\n         | ComputationProduces mem' ->\n             let s2 = pop_stack_frame actor mem' s in\n             update_expressions_maintains_gvar_has_type v td output_dsts actor\n               start_pc 0 bypassing_write_buffer output_values s2)\n  )\n\nlet terminate_thread_statement_computation_maintains_gvar_has_type\n  (v: var_id_t)\n  (td: object_td_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (method_id: method_id_t)\n  (s: Armada.State.t)\n  : Lemma (requires gvar_has_type s.mem v td)\n          (ensures  (match terminate_thread_statement_computation actor nd start_pc method_id s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> gvar_has_type s'.mem v td)) =\n  let thread = s.threads actor in\n  if   Cons? nd\n     || neqb thread.stack []\n     || thread.top.method_id <> method_id\n     || actor = s.initial_tid then\n    ()\n  else\n    pop_stack_variables_maintains_gvar_has_type v td actor method_id thread.top.frame_uniq thread.top.local_variables s.mem\n\nlet terminate_process_statement_computation_maintains_gvar_has_type\n  (v: var_id_t)\n  (td: object_td_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (method_id: method_id_t)\n  (s: Armada.State.t)\n  : Lemma (requires gvar_has_type s.mem v td)\n          (ensures  (match terminate_process_statement_computation actor nd start_pc method_id s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> gvar_has_type s'.mem v td)) =\n  ()\n\nlet join_statement_computation_maintains_gvar_has_type\n  (v: var_id_t)\n  (td: object_td_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (join_tid: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires gvar_has_type s.mem v td)\n          (ensures  (match join_statement_computation actor nd start_pc join_tid s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> gvar_has_type s'.mem v td)) =\n  ()\n\nlet alloc_successful_statement_computation_maintains_gvar_has_type\n  (v: var_id_t)\n  (td: object_td_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (zero_initialized: bool)\n  (bypassing_write_buffer: bool)\n  (result: expression_t)\n  (allocation_td: object_td_t)\n  (count: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires gvar_has_type s.mem v td)\n          (ensures  (match alloc_successful_statement_computation actor nd start_pc zero_initialized\n                             bypassing_write_buffer result allocation_td count s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> gvar_has_type s'.mem v td)) =\n  let cs' = alloc_successful_statement_computation actor nd start_pc zero_initialized bypassing_write_buffer result\n              allocation_td count s in\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract root_id_uniquifier_t)\n     || neqb (expression_to_td count) (ObjectTDAbstract nat)\n     || neqb (expression_to_td result) (ObjectTDPrimitive PrimitiveTDPointer) then\n    ()\n  else (\n    match rvalue_computation count actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces count_value ->\n        let sz = ObjectValueAbstract?.value count_value in\n        let array_td = ObjectTDArray allocation_td sz in\n        let uniq = ObjectValueAbstract?.value (Cons?.hd nd) in\n        let root_id = RootIdAllocation uniq in\n        (match s.mem root_id with\n         | RootAllocated allocated freed storage ->\n             if   allocated\n                || freed\n                || neqb (object_storage_to_td storage) array_td\n                || not (is_storage_ready_for_allocation storage)\n                || (not zero_initialized && not (object_storage_arbitrarily_initialized_correctly storage))\n                || (zero_initialized && not (is_storage_zero_filled storage)) then\n               ()\n             else (\n               let s' = mark_allocation_root_allocated uniq storage s in\n               let p = ObjectValuePrimitive (PrimitiveBoxPointer (PointerIndex (PointerRoot root_id) 0)) in\n               update_expression_maintains_gvar_has_type v td result actor start_pc 0 bypassing_write_buffer\n                 p s'\n             )\n         | _ -> ())\n  )\n\nlet alloc_returning_null_statement_computation_maintains_gvar_has_type\n  (v: var_id_t)\n  (td: object_td_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (bypassing_write_buffer: bool)\n  (result: expression_t)\n  (count: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires gvar_has_type s.mem v td)\n          (ensures  (match alloc_returning_null_statement_computation actor nd start_pc bypassing_write_buffer\n                             result count s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> gvar_has_type s'.mem v td)) =\n  let s' = alloc_returning_null_statement_computation actor nd start_pc bypassing_write_buffer\n              result count s in\n  if   Cons? nd\n     || neqb (expression_to_td count) (ObjectTDAbstract nat)\n     || neqb (expression_to_td result) (ObjectTDPrimitive PrimitiveTDPointer) then\n    ()\n  else (\n    match rvalue_computation count actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces _ ->\n        let p = ObjectValuePrimitive (PrimitiveBoxPointer PointerNull) in\n        update_expression_maintains_gvar_has_type v td result actor start_pc 0 bypassing_write_buffer p s\n  )\n\nlet dealloc_statement_computation_maintains_gvar_has_type\n  (v: var_id_t)\n  (td: object_td_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (ptr: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires gvar_has_type s.mem v td)\n          (ensures  (match dealloc_statement_computation actor nd start_pc ptr s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> gvar_has_type s'.mem v td)) =\n  if   Cons? nd\n     || neqb (expression_to_td ptr) (ObjectTDPrimitive PrimitiveTDPointer) then\n    ()\n  else (\n    match rvalue_computation ptr actor s with\n    | ComputationImpossible -> ()\n    | ComputationUndefined -> ()\n    | ComputationProduces ptr_value ->\n        let p = PrimitiveBoxPointer?.ptr (ObjectValuePrimitive?.value ptr_value) in\n        free_pointer_maintains_gvar_has_type v td p s.mem\n  )\n\nlet somehow_statement_computation_maintains_gvar_has_type\n  (v: var_id_t)\n  (td: object_td_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (undefined_unless_cond: expression_t)\n  (bypassing_write_buffer: bool)\n  (modifies_clauses: list expression_t)\n  (ensures_cond: expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires gvar_has_type s.mem v td)\n          (ensures  (match somehow_statement_computation actor nd start_pc undefined_unless_cond\n                             bypassing_write_buffer modifies_clauses ensures_cond s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> gvar_has_type s'.mem v td)) =\n  let cs' = somehow_statement_computation actor nd start_pc undefined_unless_cond bypassing_write_buffer\n              modifies_clauses ensures_cond s in\n  if   neqb (expression_to_td undefined_unless_cond) (ObjectTDPrimitive PrimitiveTDBool)\n     || neqb (expression_to_td ensures_cond) (ObjectTDPrimitive PrimitiveTDBool) then\n    ()\n  else (\n    match rvalue_computation undefined_unless_cond actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces undefined_unless_value ->\n        let undefined_unless_bool = PrimitiveBoxBool?.b (ObjectValuePrimitive?.value undefined_unless_value) in\n        if not undefined_unless_bool then\n          ()\n        else\n          update_expressions_maintains_gvar_has_type v td modifies_clauses actor start_pc 0\n            bypassing_write_buffer nd s\n  )\n\nlet fence_statement_computation_maintains_gvar_has_type\n  (v: var_id_t)\n  (td: object_td_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (s: Armada.State.t)\n  : Lemma (requires gvar_has_type s.mem v td)\n          (ensures  (match fence_statement_computation actor nd start_pc s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> gvar_has_type s'.mem v td)) =\n  ()\n\nlet external_method_start_statement_computation_maintains_gvar_has_type\n  (v: var_id_t)\n  (td: object_td_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (await_cond: expression_t)\n  (undefined_unless_cond: expression_t)\n  (bypassing_write_buffer: bool)\n  (modifies_clauses: list expression_t)\n  (reads_clauses: list (var_id_t * expression_t))\n  (s: Armada.State.t)\n  : Lemma (requires gvar_has_type s.mem v td)\n          (ensures  (match external_method_start_statement_computation actor nd start_pc await_cond\n                             undefined_unless_cond bypassing_write_buffer modifies_clauses reads_clauses s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> gvar_has_type s'.mem v td)) =\n  let cs' = external_method_start_statement_computation actor nd start_pc await_cond undefined_unless_cond\n              bypassing_write_buffer modifies_clauses reads_clauses s in\n  if   neqb (expression_to_td await_cond) (ObjectTDPrimitive PrimitiveTDBool)\n     || neqb (expression_to_td undefined_unless_cond) (ObjectTDPrimitive PrimitiveTDBool)\n     || list_len modifies_clauses <> list_len nd then\n    ()\n  else (\n    match rvalue_computation await_cond actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces await_value ->\n        let await_bool = PrimitiveBoxBool?.b (ObjectValuePrimitive?.value await_value) in\n        if not await_bool then\n          ()\n        else (\n          match rvalue_computation undefined_unless_cond actor s with\n          | ComputationImpossible | ComputationUndefined -> ()\n          | ComputationProduces undefined_unless_value ->\n              let undefined_unless_bool = PrimitiveBoxBool?.b (ObjectValuePrimitive?.value await_value) in\n              if not undefined_unless_bool then\n                ()\n              else (\n                update_expressions_maintains_gvar_has_type v td modifies_clauses actor start_pc 0\n                  bypassing_write_buffer nd s;\n                match update_expressions modifies_clauses actor start_pc 0 bypassing_write_buffer nd s with\n                | ComputationImpossible | ComputationUndefined -> ()\n                | ComputationProduces s' ->\n                    external_method_take_snapshot_of_reads_clauses_computation_maintains_gvar_has_type\n                      v td actor start_pc (list_len modifies_clauses) bypassing_write_buffer reads_clauses s'\n              )\n        )\n  )\n\nlet external_method_middle_statement_computation_maintains_gvar_has_type\n  (v: var_id_t)\n  (td: object_td_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (bypassing_write_buffer: bool)\n  (modifies_clauses: list expression_t)\n  (reads_clauses: list (var_id_t * expression_t))\n  (s: Armada.State.t)\n  : Lemma (requires gvar_has_type s.mem v td)\n          (ensures  (match external_method_middle_statement_computation actor nd start_pc bypassing_write_buffer\n                             modifies_clauses reads_clauses s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> gvar_has_type s'.mem v td)) =\n  let cs' = external_method_middle_statement_computation actor nd start_pc bypassing_write_buffer\n              modifies_clauses reads_clauses s in\n  match external_method_check_snapshot_computation actor reads_clauses s with\n  | ComputationImpossible | ComputationUndefined -> ()\n  | ComputationProduces _ ->\n      update_expressions_maintains_gvar_has_type v td modifies_clauses actor start_pc 0\n        bypassing_write_buffer nd s;\n      (match update_expressions modifies_clauses actor start_pc 0 bypassing_write_buffer nd s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces s' ->\n           external_method_take_snapshot_of_reads_clauses_computation_maintains_gvar_has_type\n             v td actor start_pc (list_len modifies_clauses) bypassing_write_buffer reads_clauses s')\n\nlet external_method_end_statement_computation_maintains_gvar_has_type\n  (v: var_id_t)\n  (td: object_td_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (ensures_cond: expression_t)\n  (logs_clauses: list expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires gvar_has_type s.mem v td)\n          (ensures  (match external_method_end_statement_computation actor nd start_pc ensures_cond logs_clauses s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> gvar_has_type s'.mem v td)) =\n  let cs' = external_method_end_statement_computation actor nd start_pc ensures_cond logs_clauses s in\n  if   Cons? nd\n     || neqb (expression_to_td ensures_cond) (ObjectTDPrimitive PrimitiveTDBool) then\n    ()\n  else (\n    match rvalue_computation ensures_cond actor s with\n    | ComputationImpossible | ComputationUndefined -> ()\n    | ComputationProduces ensures_value ->\n        let ensures_bool = PrimitiveBoxBool?.b (ObjectValuePrimitive?.value ensures_value) in\n        log_expressions_computation_maintains_gvar_has_type v td actor logs_clauses s\n  )\n\n#pop-options\n\nlet executing_statement_maintains_gvar_has_type\n  (v: var_id_t)\n  (td: object_td_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (end_pc: option pc_t)\n  (statement: Armada.Statement.t)\n  (s: Armada.State.t)\n  : Lemma (requires gvar_has_type s.mem v td)\n          (ensures  (match statement_computation actor nd start_pc end_pc statement s with\n                     | ComputationImpossible | ComputationUndefined -> True\n                     | ComputationProduces s' -> gvar_has_type s'.mem v td)) =\n  match statement_computation actor nd start_pc end_pc statement s with\n  | ComputationImpossible | ComputationUndefined -> ()\n  | ComputationProduces s' ->\n      (match statement with\n       | AssumeExpressionStatement exp ->\n           assume_expression_statement_computation_maintains_gvar_has_type v td actor nd start_pc exp s\n       | AssumePredicateStatement pred ->\n           assume_predicate_statement_computation_maintains_gvar_has_type v td actor nd start_pc pred s\n       | AssertTrueStatement exp ->\n           assert_true_statement_computation_maintains_gvar_has_type v td actor nd start_pc exp s\n       | AssertFalseStatement exp ->\n           assert_false_statement_computation_maintains_gvar_has_type v td actor nd start_pc exp s\n       | ConditionalJumpStatement cond ->\n           conditional_jump_statement_computation_maintains_gvar_has_type v td actor nd start_pc cond s\n       | UnconditionalJumpStatement ->\n           unconditional_jump_statement_computation_maintains_gvar_has_type v td actor nd start_pc s\n       | UpdateStatement bypassing_write_buffer dst src ->\n           update_statement_computation_maintains_gvar_has_type v td actor nd start_pc bypassing_write_buffer\n             dst src s\n       | NondeterministicUpdateStatement bypassing_write_buffer dst ->\n           nondeterministic_update_statement_computation_maintains_gvar_has_type v td actor nd start_pc\n             bypassing_write_buffer dst s\n       | PropagateWriteMessageStatement ->\n           propagate_write_message_statement_computation_maintains_gvar_has_type v td actor nd s\n       | CompareAndSwapStatement target old_val new_val bypassing_write_buffer optional_result ->\n           compare_and_swap_statement_computation_maintains_gvar_has_type v td actor nd start_pc target\n             old_val new_val bypassing_write_buffer optional_result s\n       | AtomicExchangeStatement old_val target new_val ->\n           atomic_exchange_statement_computation_maintains_gvar_has_type v td actor nd\n             start_pc old_val target new_val s\n       | CreateThreadStatement method_id initial_pc bypassing_write_buffer optional_result parameter_var_ids\n                               parameter_expressions local_variable_initializers ->\n           create_thread_statement_computation_maintains_gvar_has_type v td actor nd start_pc method_id\n             initial_pc bypassing_write_buffer optional_result parameter_var_ids parameter_expressions\n             local_variable_initializers s\n       | MethodCallStatement method_id return_pc parameter_var_ids parameter_expressions local_variable_initializers\n                               stack_overflow ->\n           method_call_statement_computation_maintains_gvar_has_type v td actor nd start_pc method_id return_pc\n             parameter_var_ids parameter_expressions local_variable_initializers stack_overflow s\n       | ReturnStatement method_id bypassing_write_buffer output_dsts output_srcs ->\n           return_statement_computation_maintains_gvar_has_type v td actor nd start_pc end_pc method_id\n             bypassing_write_buffer output_dsts output_srcs s\n       | TerminateThreadStatement method_id ->\n           terminate_thread_statement_computation_maintains_gvar_has_type v td actor nd start_pc method_id s\n       | TerminateProcessStatement method_id ->\n           terminate_process_statement_computation_maintains_gvar_has_type v td actor nd start_pc method_id s\n       | JoinStatement join_tid ->\n           join_statement_computation_maintains_gvar_has_type v td actor nd start_pc join_tid s\n       | MallocSuccessfulStatement bypassing_write_buffer result allocation_td count ->\n           alloc_successful_statement_computation_maintains_gvar_has_type v td actor nd start_pc false\n             bypassing_write_buffer result allocation_td count s\n       | MallocReturningNullStatement bypassing_write_buffer result count ->\n           alloc_returning_null_statement_computation_maintains_gvar_has_type v td actor nd start_pc\n             bypassing_write_buffer result count s\n       | CallocSuccessfulStatement bypassing_write_buffer result allocation_td count ->\n           alloc_successful_statement_computation_maintains_gvar_has_type v td actor nd start_pc true\n             bypassing_write_buffer result allocation_td count s\n       | CallocReturningNullStatement bypassing_write_buffer result count ->\n           alloc_returning_null_statement_computation_maintains_gvar_has_type v td actor nd start_pc\n             bypassing_write_buffer result count s\n       | DeallocStatement ptr ->\n           dealloc_statement_computation_maintains_gvar_has_type v td actor nd start_pc ptr s\n       | SomehowStatement undefined_unless_cond bypassing_write_buffer modifies_clauses ensures_cond ->\n           somehow_statement_computation_maintains_gvar_has_type v td actor nd start_pc undefined_unless_cond\n             bypassing_write_buffer modifies_clauses ensures_cond s\n       | FenceStatement ->\n           fence_statement_computation_maintains_gvar_has_type v td actor nd start_pc s\n       | ExternalMethodStartStatement await_cond undefined_unless_cond bypassing_write_buffer\n                                      modifies_clauses reads_clauses ->\n           external_method_start_statement_computation_maintains_gvar_has_type v td actor nd start_pc await_cond\n             undefined_unless_cond bypassing_write_buffer modifies_clauses reads_clauses s\n       | ExternalMethodMiddleStatement bypassing_write_buffer modifies_clauses reads_clauses ->\n           external_method_middle_statement_computation_maintains_gvar_has_type v td actor nd start_pc\n             bypassing_write_buffer modifies_clauses reads_clauses s\n       | ExternalMethodEndStatement ensures_cond logs_clauses ->\n           external_method_end_statement_computation_maintains_gvar_has_type v td actor nd start_pc ensures_cond\n             logs_clauses s\n      )     \n\nlet step_computation_maintains_gvar_has_type\n  (v: var_id_t)\n  (td: object_td_t)\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (step: Armada.Step.t)\n  (s: Armada.State.t)\n  : Lemma (requires gvar_has_type s.mem v td)\n          (ensures  (match step_computation actor starts_atomic_block ends_atomic_block step s with\n                     | Some s' -> gvar_has_type s'.mem v td\n                     | None -> True)) =\n  match step_computation actor starts_atomic_block ends_atomic_block step s with\n  | None -> ()\n  | Some s' ->\n      let ps = step.action.program_statement in\n      let thread = s.threads actor in\n      executing_statement_maintains_gvar_has_type v td actor step.nd thread.pc ps.end_pc ps.statement s;\n      (match statement_computation actor step.nd thread.pc ps.end_pc ps.statement s with\n       | ComputationImpossible -> ()\n       | ComputationUndefined -> ()\n       | ComputationProduces s1 -> ())\n\nlet rec step_computation_maintains_all_gvars_have_types\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (step: Armada.Step.t)\n  (s: Armada.State.t)\n  : Lemma (requires all_gvars_have_types s.mem vs tds)\n          (ensures  (match step_computation actor starts_atomic_block ends_atomic_block step s with\n                     | Some s' -> all_gvars_have_types s'.mem vs tds\n                     | None -> True)) =\n  match vs, tds with\n  | [], [] -> ()\n  | first_v :: remaining_vs, first_td :: remaining_tds ->\n      step_computation_maintains_gvar_has_type first_v first_td actor starts_atomic_block ends_atomic_block\n        step s;\n      step_computation_maintains_all_gvars_have_types remaining_vs remaining_tds actor starts_atomic_block\n        ends_atomic_block step s\n"
  },
  {
    "path": "experimental/lib/Strategies.GlobalVars.Unaddressed.fst",
    "content": "module Strategies.GlobalVars.Unaddressed\n\nopen Armada.Base\nopen Armada.BinaryOp\nopen Armada.Computation\nopen Armada.Expression\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Pointer\nopen Armada.State\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Type\nopen Armada.UnaryOp\nopen FStar.Sequence.Ambient\nopen FStar.Sequence.Base\nopen Spec.List\nopen Spec.Ubool\nopen Strategies.ArmadaInvariant.PositionsValid\nopen Strategies.ArmadaInvariant.RootsMatch\nopen Strategies.GlobalVars\nopen Util.Seq\nopen Util.Trigger\n\nlet rec global_variables_unaddressed_in_storage_implies_unaddressed_in_object_value\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (storage: object_storage_t)\n  : Lemma (requires global_variables_unaddressed_in_storage vs storage)\n          (ensures  global_variables_unaddressed_in_object_value vs (object_storage_to_value actor storage))\n          (decreases rank storage) =\n  match storage with\n  | ObjectStorageWeaklyConsistentPrimitive _ values local_versions -> ()\n  | ObjectStoragePrimitive value -> ()\n  | ObjectStorageStruct fields ->\n      global_variables_unaddressed_in_storages_implies_unaddressed_in_object_values vs actor fields\n  | ObjectStorageArray element_td elements ->\n      global_variables_unaddressed_in_storages_implies_unaddressed_in_object_values vs actor elements\n  | ObjectStorageAbstract ty value -> ()\n\nand global_variables_unaddressed_in_storages_implies_unaddressed_in_object_values\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (storages: seq object_storage_t)\n  : Lemma (requires global_variables_unaddressed_in_storages vs storages)\n          (ensures  global_variables_unaddressed_in_object_value_seq vs\n                      (map_refine (object_storage_to_value actor) storages))\n          (decreases rank storages) =\n  let values = map_refine (object_storage_to_value actor) storages in\n  introduce forall value. contains values value ==> global_variables_unaddressed_in_object_value vs value\n  with\n    introduce _ ==> _\n    with _.\n      eliminate exists storage. contains storages storage /\\ value == object_storage_to_value actor storage\n      returns _\n      with _. global_variables_unaddressed_in_storage_implies_unaddressed_in_object_value vs actor storage\n\n\nlet rec dereference_computation_when_gvars_unaddressed_produces_storage_with_gvars_unaddressed\n  (vs: list var_id_t)\n  (p: Armada.Pointer.t)\n  (mem: Armada.Memory.t)\n  : Lemma (requires   global_variables_unaddressed_in_memory vs mem\n                    /\\ roots_match mem)\n          (ensures  (match dereference_computation p mem with\n                     | ComputationProduces storage -> global_variables_unaddressed_in_storage vs storage\n                     | _ -> True)) =\n  match p with\n  | PointerUninitialized -> ()\n  | PointerNull -> ()\n  | PointerRoot root_id -> ()\n  | PointerField struct_ptr field_id ->\n      dereference_computation_when_gvars_unaddressed_produces_storage_with_gvars_unaddressed vs struct_ptr mem\n  | PointerIndex array_ptr idx ->\n      dereference_computation_when_gvars_unaddressed_produces_storage_with_gvars_unaddressed vs array_ptr mem\n\nlet dereference_as_td_computation_when_gvars_unaddressed_produces_value_with_gvars_unaddressed\n  (vs: list var_id_t)\n  (p: Armada.Pointer.t)\n  (td: object_td_t)\n  (actor: tid_t)\n  (mem: Armada.Memory.t)\n  : Lemma (requires   global_variables_unaddressed_in_memory vs mem\n                    /\\ roots_match mem)\n          (ensures  (match dereference_as_td_computation p td actor mem with\n                     | ComputationProduces value -> global_variables_unaddressed_in_object_value vs value\n                     | _ -> True)) =\n  dereference_computation_when_gvars_unaddressed_produces_storage_with_gvars_unaddressed vs p mem;\n  match dereference_computation p mem with\n  | ComputationProduces storage ->\n      global_variables_unaddressed_in_storage_implies_unaddressed_in_object_value vs actor storage\n  | _ -> ()\n\n#push-options \"--z3rlimit 30\"\n\nlet rec rvalue_computation_when_gvars_unaddressed_produces_value_with_gvars_unaddressed\n  (vs: list var_id_t)\n  (exp: expression_t)\n  (actor: tid_t)\n  (s: Armada.State.t)\n  : Lemma (requires   global_variables_unaddressed_in_rvalue_expression vs exp\n                    /\\ positions_valid_in_state s\n                    /\\ global_variables_unaddressed_in_memory vs s.mem\n                    /\\ roots_match s.mem)\n          (ensures  (match rvalue_computation exp actor s with\n                     | ComputationProduces value -> global_variables_unaddressed_in_object_value vs value\n                     | _ -> True))\n          (decreases exp) =\n  if not (expression_valid exp) then\n    ()\n  else\n    match exp with\n    | ExpressionConstant value -> ()\n    | ExpressionGlobalVariable td var_id ->\n        dereference_as_td_computation_when_gvars_unaddressed_produces_value_with_gvars_unaddressed vs\n          (PointerRoot (RootIdGlobal var_id)) td actor s.mem\n    | ExpressionLocalVariable td var_id ->\n        let thread = s.threads actor in\n        if list_contains var_id thread.top.local_variables then\n          dereference_as_td_computation_when_gvars_unaddressed_produces_value_with_gvars_unaddressed vs\n            (PointerRoot (RootIdStack actor thread.top.method_id thread.top.frame_uniq var_id)) td actor s.mem\n        else\n          ()\n    | ExpressionUnaryOperator _ _ operator operand ->\n        rvalue_computation_when_gvars_unaddressed_produces_value_with_gvars_unaddressed vs operand actor s\n    | ExpressionBinaryOperator _ _ _ operator operand1 operand2 ->\n        rvalue_computation_when_gvars_unaddressed_produces_value_with_gvars_unaddressed vs operand1 actor s;\n        rvalue_computation_when_gvars_unaddressed_produces_value_with_gvars_unaddressed vs operand2 actor s\n    | ExpressionIf _ cond operand_then operand_else ->\n        rvalue_computation_when_gvars_unaddressed_produces_value_with_gvars_unaddressed vs cond actor s;\n        rvalue_computation_when_gvars_unaddressed_produces_value_with_gvars_unaddressed vs operand_then actor s;\n        rvalue_computation_when_gvars_unaddressed_produces_value_with_gvars_unaddressed vs operand_else actor s\n    | ExpressionDereference td ptr ->\n        (match rvalue_computation ptr actor s with\n         | ComputationProduces ptr_value ->\n             let p = PrimitiveBoxPointer?.ptr (ObjectValuePrimitive?.value ptr_value) in\n             dereference_as_td_computation_when_gvars_unaddressed_produces_value_with_gvars_unaddressed vs p td actor\n               s.mem\n         | _ -> ())\n    | ExpressionAddressOf obj ->\n        lvalue_computation_when_gvars_unaddressed_produces_value_with_gvars_unaddressed vs obj actor s\n    | ExpressionPointerOffset ptr offset ->\n        rvalue_computation_when_gvars_unaddressed_produces_value_with_gvars_unaddressed vs ptr actor s\n    | ExpressionFieldOf td obj field_id ->\n        (match lvalue_computation obj actor s with\n         | ComputationProduces obj_ptr ->\n             dereference_as_td_computation_when_gvars_unaddressed_produces_value_with_gvars_unaddressed vs\n               (PointerField obj_ptr field_id) td actor s.mem\n         | _ -> ())\n    | ExpressionAllocated ptr ->\n        rvalue_computation_when_gvars_unaddressed_produces_value_with_gvars_unaddressed vs ptr actor s\n    | ExpressionApplyFunction td operands return_type operand_types fn ->\n        rvalues_computation_when_gvars_unaddressed_produces_value_with_gvars_unaddressed vs operands actor s\n    | ExpressionIfUndefined td potentially_unsafe safe_substitution ->\n        rvalue_computation_when_gvars_unaddressed_produces_value_with_gvars_unaddressed vs\n          potentially_unsafe actor s;\n        rvalue_computation_when_gvars_unaddressed_produces_value_with_gvars_unaddressed vs\n          safe_substitution actor s\n    | ExpressionInitialTid -> ()\n    | ExpressionUniqsUsed -> ()\n    | ExpressionStopReason -> ()\n\nand lvalue_computation_when_gvars_unaddressed_produces_value_with_gvars_unaddressed\n  (vs: list var_id_t)\n  (exp: expression_t)\n  (actor: tid_t)\n  (s: Armada.State.t)\n  : Lemma (requires   global_variables_unaddressed_in_lvalue_expression vs exp\n                    /\\ positions_valid_in_state s\n                    /\\ global_variables_unaddressed_in_memory vs s.mem\n                    /\\ roots_match s.mem)\n          (ensures  (match lvalue_computation exp actor s with\n                     | ComputationProduces p -> global_variables_unaddressed_in_pointer vs p\n                     | _ -> True))\n          (decreases exp) =\n  match exp with\n  | ExpressionGlobalVariable _ var_id -> ()\n  | ExpressionLocalVariable _ var_id -> ()\n  | ExpressionDereference _ ptr ->\n      rvalue_computation_when_gvars_unaddressed_produces_value_with_gvars_unaddressed vs ptr actor s\n  | ExpressionFieldOf td obj field_id ->\n      lvalue_computation_when_gvars_unaddressed_produces_value_with_gvars_unaddressed vs obj actor s\n  | _ -> ()\n  \nand rvalues_computation_when_gvars_unaddressed_produces_value_with_gvars_unaddressed\n  (vs: list var_id_t)\n  (exps: list expression_t)\n  (actor: tid_t)\n  (s: Armada.State.t)\n  : Lemma (requires   global_variables_unaddressed_in_rvalue_expressions vs exps\n                    /\\ positions_valid_in_state s\n                    /\\ global_variables_unaddressed_in_memory vs s.mem\n                    /\\ roots_match s.mem)\n          (ensures  (match rvalues_computation exps actor s with\n                     | ComputationProduces values -> global_variables_unaddressed_in_object_values vs values\n                     | _ -> True))\n          (decreases exps) =\n  match exps with\n  | [] -> ()\n  | exp :: exps' ->\n      rvalue_computation_when_gvars_unaddressed_produces_value_with_gvars_unaddressed vs exp actor s;\n      rvalues_computation_when_gvars_unaddressed_produces_value_with_gvars_unaddressed vs exps' actor s\n\n#pop-options\n#push-options \"--z3rlimit 20\"\n\nlet update_storage_lacking_pointer_field_maintains_gvars_unaddressed\n  (vs: list var_id_t)\n  (p: Armada.Pointer.t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (storage: valid_object_storage_t)\n  (td: object_td_t)\n  (new_value: valid_object_value_t td)\n  : Lemma (requires object_td_lacks_pointer_field td)\n          (ensures  (match update_storage p actor writer_pc writer_expression_number bypassing_write_buffer\n                             storage new_value with\n                     | ComputationProduces (optional_write_message, storage') ->\n                         global_variables_unaddressed_in_storage vs storage'\n                     | _ -> True)) =\n  ()\n\nlet update_storage_with_gvars_unaddressed_maintains_gvars_unaddressed\n  (vs: list var_id_t)\n  (p: Armada.Pointer.t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (storage: valid_object_storage_t)\n  (new_value: object_value_t)\n  : Lemma (requires   global_variables_unaddressed_in_storage vs storage\n                    /\\ global_variables_unaddressed_in_object_value vs new_value)\n          (ensures  (match update_storage p actor writer_pc writer_expression_number bypassing_write_buffer\n                             storage new_value with\n                     | ComputationProduces (optional_write_message, storage') ->\n                         global_variables_unaddressed_in_storage vs storage'\n                     | _ -> True)) =\n  ()\n\nlet rec object_storage_lacks_pointer_field_implies_gvars_unaddressed\n  (vs: list var_id_t)\n  (storage: valid_object_storage_t)\n  : Lemma (requires object_td_lacks_pointer_field (object_storage_to_td storage))\n          (ensures  global_variables_unaddressed_in_storage vs storage) =\n  match storage with\n  | ObjectStorageWeaklyConsistentPrimitive _ values _ -> ()\n  | ObjectStoragePrimitive value -> ()\n  | ObjectStorageStruct fields ->\n      introduce forall field. contains fields field ==> global_variables_unaddressed_in_storage vs field\n      with introduce _ ==> _\n      with _. object_storage_lacks_pointer_field_implies_gvars_unaddressed vs field\n  | ObjectStorageArray _ elements ->\n      introduce forall element. contains elements element ==> global_variables_unaddressed_in_storage vs element\n      with introduce _ ==> _\n      with _. object_storage_lacks_pointer_field_implies_gvars_unaddressed vs element\n  | ObjectStorageAbstract _ _ -> ()\n\nlet update_storage_child_with_gvars_unaddressed_maintains_gvars_unaddressed\n  (vs: list var_id_t)\n  (storage: valid_object_storage_t)\n  (idx: nat)\n  (new_child: valid_object_storage_t{can_update_storage_child storage idx new_child})\n  : Lemma (requires   global_variables_unaddressed_in_storage vs storage\n                    /\\ global_variables_unaddressed_in_storage vs new_child)\n          (ensures  (let storage' = update_storage_child storage idx new_child in\n                     global_variables_unaddressed_in_storage vs storage')) =\n  ()\n\nlet rec update_pointer_directly_with_gvars_unaddressed_maintains_gvars_unaddressed\n  (vs: list var_id_t)\n  (p: Armada.Pointer.t)\n  (new_storage: valid_object_storage_t)\n  (mem: Armada.Memory.t)\n  : Lemma (requires   global_variables_unaddressed_in_storage vs new_storage\n                    /\\ global_variables_unaddressed_in_memory vs mem\n                    /\\ roots_match mem)\n          (ensures  (match update_pointer_directly p new_storage mem with\n                     | ComputationProduces mem' ->\n                           global_variables_unaddressed_in_memory vs mem'\n                         /\\ roots_match mem'\n                     | _ -> True)) =\n  match p with\n  | PointerUninitialized -> ()\n  | PointerNull -> ()\n  | PointerRoot root_id -> ()\n  | PointerField struct_ptr field_id ->\n      dereference_computation_when_gvars_unaddressed_produces_storage_with_gvars_unaddressed vs struct_ptr mem;\n      (match dereference_computation struct_ptr mem with\n       | ComputationProduces parent ->\n           (match parent with\n            | ObjectStorageStruct fields ->\n                if   field_id >= length fields\n                   || neqb (object_storage_to_td new_storage)\n                          (object_storage_to_td (index fields field_id)) then\n                  ()\n                else\n                  let new_parent = update_storage_child parent field_id new_storage in\n                  update_storage_child_with_gvars_unaddressed_maintains_gvars_unaddressed vs\n                    parent field_id new_storage;\n                  update_pointer_directly_with_gvars_unaddressed_maintains_gvars_unaddressed vs\n                    struct_ptr new_parent mem\n            | _ -> ())\n       | _ -> ())\n  | PointerIndex array_ptr idx ->\n      dereference_computation_when_gvars_unaddressed_produces_storage_with_gvars_unaddressed vs array_ptr mem;\n      (match dereference_computation array_ptr mem with\n       | ComputationProduces parent ->\n           (match parent with\n            | ObjectStorageArray element_td elements ->\n                if   idx < 0\n                   || idx >= length elements\n                   || neqb (object_storage_to_td new_storage) element_td then\n                  ()\n                else\n                  let new_parent = update_storage_child parent idx new_storage in\n                  update_storage_child_with_gvars_unaddressed_maintains_gvars_unaddressed vs parent idx new_storage;\n                  update_pointer_directly_with_gvars_unaddressed_maintains_gvars_unaddressed vs array_ptr new_parent mem\n            | _ -> ())\n       | _ -> ())\n\nlet update_pointer_with_object_lacking_pointer_field_maintains_gvars_unaddressed\n  (vs: list var_id_t)\n  (p: Armada.Pointer.t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (td: object_td_t)\n  (new_value: valid_object_value_t td)\n  (mem: Armada.Memory.t)\n  : Lemma (requires   global_variables_unaddressed_in_memory vs mem\n                    /\\ roots_match mem\n                    /\\ object_td_lacks_pointer_field td)\n          (ensures  (match update_pointer p actor writer_pc writer_expression_number bypassing_write_buffer\n                             new_value mem with\n                     | ComputationProduces (optional_write_message, mem') ->\n                           global_variables_unaddressed_in_memory vs mem'\n                         /\\ roots_match mem'\n                    | _ -> True)) =\n  match p with\n  | PointerUninitialized -> ()\n  | PointerNull -> ()\n  | PointerRoot root_id ->\n      let root = mem root_id in\n      (match root_to_storage_computation root with\n       | ComputationProduces storage ->\n           update_storage_lacking_pointer_field_maintains_gvars_unaddressed vs p actor writer_pc\n             writer_expression_number bypassing_write_buffer storage td new_value\n       | _ -> ())\n  | PointerField struct_ptr field_id ->\n      dereference_computation_when_gvars_unaddressed_produces_storage_with_gvars_unaddressed vs struct_ptr mem;\n      (match dereference_computation struct_ptr mem with\n       | ComputationProduces parent ->\n          (match parent with\n           | ObjectStorageStruct fields ->\n               if field_id >= length fields then\n                 ()\n               else\n                 let field = index fields field_id in\n                 if not (object_storage_valid field) || neqb (object_storage_to_td field) td then\n                   ()\n                 else (\n                   update_storage_lacking_pointer_field_maintains_gvars_unaddressed vs p actor writer_pc\n                     writer_expression_number bypassing_write_buffer field td new_value;\n                   (match update_storage p actor writer_pc writer_expression_number\n                            bypassing_write_buffer field new_value with\n                    | ComputationProduces (write_message, new_field) ->\n                        if (not (can_update_storage_child parent field_id new_field)) then\n                          ()\n                        else (\n                          update_storage_child_with_gvars_unaddressed_maintains_gvars_unaddressed\n                            vs parent field_id new_field;\n                          let new_parent = update_storage_child parent field_id new_field in\n                          update_pointer_directly_with_gvars_unaddressed_maintains_gvars_unaddressed\n                            vs struct_ptr new_parent mem\n                        )\n                    | _ -> ()\n                   ))\n          | _ -> ())\n       | _ -> ())\n  | PointerIndex array_ptr idx ->\n      dereference_computation_when_gvars_unaddressed_produces_storage_with_gvars_unaddressed vs array_ptr mem;\n      (match dereference_computation array_ptr mem with\n       | ComputationProduces parent ->\n          (match parent with\n           | ObjectStorageArray element_td elements ->\n               if idx < 0 || idx >= length elements then\n                 ()\n               else\n                 let element = index elements idx in\n                 if not (object_storage_valid element) then\n                   ()\n                 else (\n                   update_storage_lacking_pointer_field_maintains_gvars_unaddressed vs p actor writer_pc\n                     writer_expression_number bypassing_write_buffer element td new_value;\n                   (match update_storage p actor writer_pc writer_expression_number\n                            bypassing_write_buffer element new_value with\n                    | ComputationProduces (write_message, new_element) ->\n                        if not (can_update_storage_child parent idx new_element) then\n                          ()\n                        else (\n                          update_storage_child_with_gvars_unaddressed_maintains_gvars_unaddressed\n                            vs parent idx new_element;\n                          let new_parent = update_storage_child parent idx new_element in\n                          update_pointer_directly_with_gvars_unaddressed_maintains_gvars_unaddressed\n                            vs array_ptr new_parent mem\n                        )\n                    | _ -> ()\n                   ))\n          | _ -> ())\n       | _ -> ())\n\nlet update_pointer_with_object_with_gvars_unaddressed_maintains_gvars_unaddressed\n  (vs: list var_id_t)\n  (p: Armada.Pointer.t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (new_value: object_value_t)\n  (mem: Armada.Memory.t)\n  : Lemma (requires   global_variables_unaddressed_in_memory vs mem\n                    /\\ roots_match mem\n                    /\\ global_variables_unaddressed_in_object_value vs new_value)\n          (ensures  (match update_pointer p actor writer_pc writer_expression_number bypassing_write_buffer\n                             new_value mem with\n                     | ComputationProduces (optional_write_message, mem') ->\n                           global_variables_unaddressed_in_memory vs mem'\n                         /\\ roots_match mem'\n                     | _ -> True)) =\n  match p with\n  | PointerUninitialized -> ()\n  | PointerNull -> ()\n  | PointerRoot root_id ->\n      let root = mem root_id in\n      (match root_to_storage_computation root with\n       | ComputationProduces storage ->\n           update_storage_with_gvars_unaddressed_maintains_gvars_unaddressed vs p actor writer_pc\n             writer_expression_number bypassing_write_buffer storage new_value\n       | _ -> ())\n  | PointerField struct_ptr field_id ->\n      dereference_computation_when_gvars_unaddressed_produces_storage_with_gvars_unaddressed vs struct_ptr mem;\n      (match dereference_computation struct_ptr mem with\n       | ComputationProduces parent ->\n          (match parent with\n           | ObjectStorageStruct fields ->\n               if field_id >= length fields then\n                 ()\n               else\n                 let field = index fields field_id in\n                 if   not (object_storage_valid field)\n                    || neqb (object_storage_to_td field) (object_value_to_td new_value) then\n                   ()\n                 else (\n                   update_storage_with_gvars_unaddressed_maintains_gvars_unaddressed vs p actor writer_pc\n                     writer_expression_number bypassing_write_buffer field new_value;\n                   (match update_storage p actor writer_pc writer_expression_number\n                            bypassing_write_buffer field new_value with\n                    | ComputationProduces (write_message, new_field) ->\n                        if (not (can_update_storage_child parent field_id new_field)) then\n                          ()\n                        else (\n                          update_storage_child_with_gvars_unaddressed_maintains_gvars_unaddressed\n                            vs parent field_id new_field;\n                          let new_parent = update_storage_child parent field_id new_field in\n                          update_pointer_directly_with_gvars_unaddressed_maintains_gvars_unaddressed\n                            vs struct_ptr new_parent mem\n                        )\n                    | _ -> ()\n                   ))\n          | _ -> ())\n       | _ -> ())\n  | PointerIndex array_ptr idx ->\n      dereference_computation_when_gvars_unaddressed_produces_storage_with_gvars_unaddressed vs array_ptr mem;\n      (match dereference_computation array_ptr mem with\n       | ComputationProduces parent ->\n          (match parent with\n           | ObjectStorageArray element_td elements ->\n               if idx < 0 || idx >= length elements then\n                 ()\n               else\n                 let element = index elements idx in\n                 if not (object_storage_valid element) then\n                   ()\n                 else (\n                   update_storage_with_gvars_unaddressed_maintains_gvars_unaddressed vs p actor writer_pc\n                     writer_expression_number bypassing_write_buffer element new_value;\n                   (match update_storage p actor writer_pc writer_expression_number\n                            bypassing_write_buffer element new_value with\n                    | ComputationProduces (write_message, new_element) ->\n                        if not (can_update_storage_child parent idx new_element) then\n                          ()\n                        else (\n                          update_storage_child_with_gvars_unaddressed_maintains_gvars_unaddressed\n                            vs parent idx new_element;\n                          let new_parent = update_storage_child parent idx new_element in\n                          update_pointer_directly_with_gvars_unaddressed_maintains_gvars_unaddressed\n                            vs array_ptr new_parent mem\n                        )\n                    | _ -> ()\n                   ))\n          | _ -> ())\n       | _ -> ())\n\nlet update_pointed_to_value_lacking_pointer_field_maintains_gvars_unaddressed\n  (vs: list var_id_t)\n  (p: Armada.Pointer.t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (td: object_td_t)\n  (new_value: valid_object_value_t td)\n  (s: Armada.State.t)\n  : Lemma (requires   positions_valid_in_state s\n                    /\\ global_variables_unaddressed_in_memory vs s.mem\n                    /\\ roots_match s.mem\n                    /\\ object_td_lacks_pointer_field td)\n          (ensures  (match update_pointed_to_value p actor writer_pc writer_expression_number bypassing_write_buffer\n                             new_value s with\n                     | ComputationProduces s' ->\n                           positions_valid_in_state s'\n                         /\\ global_variables_unaddressed_in_memory vs s'.mem\n                         /\\ roots_match s'.mem\n                     | _ -> True)) =\n  update_pointer_with_object_lacking_pointer_field_maintains_gvars_unaddressed vs p actor writer_pc\n    writer_expression_number bypassing_write_buffer td new_value s.mem;\n  match update_pointer p actor writer_pc writer_expression_number bypassing_write_buffer new_value s.mem with\n  | ComputationProduces (optional_write_message, new_mem) ->\n      (match optional_write_message with\n       | Some write_message ->\n           let thread = s.threads actor in\n           let new_write_buffer = build thread.write_buffer write_message in\n           let new_thread = { thread with write_buffer = new_write_buffer } in\n           let new_threads = Spec.Map.upd s.threads actor new_thread in\n           let s' = { s with mem = new_mem; threads = new_threads; } in\n           assert (global_variables_unaddressed_in_memory vs s'.mem);\n           assert (positions_valid_in_state s')\n       | None ->\n           let s' = { s with mem = new_mem; } in\n           assert (global_variables_unaddressed_in_memory vs s'.mem);\n           assert (positions_valid_in_state s')\n       | _ -> false_elim()\n      )\n  | _ -> ()\n\nlet update_pointed_to_value_with_gvars_unaddressed_maintains_gvars_unaddressed\n  (vs: list var_id_t)\n  (p: Armada.Pointer.t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (new_value: object_value_t)\n  (s: Armada.State.t)\n  : Lemma (requires   positions_valid_in_state s\n                    /\\ global_variables_unaddressed_in_memory vs s.mem\n                    /\\ roots_match s.mem\n                    /\\ global_variables_unaddressed_in_object_value vs new_value)\n          (ensures  (match update_pointed_to_value p actor writer_pc writer_expression_number bypassing_write_buffer\n                             new_value s with\n                     | ComputationProduces s' ->\n                           positions_valid_in_state s'\n                         /\\ global_variables_unaddressed_in_memory vs s'.mem\n                         /\\ roots_match s'.mem\n                     | _ -> True)) =\n  update_pointer_with_object_with_gvars_unaddressed_maintains_gvars_unaddressed vs p actor writer_pc\n    writer_expression_number bypassing_write_buffer new_value s.mem;\n  match update_pointer p actor writer_pc writer_expression_number bypassing_write_buffer new_value s.mem with\n  | ComputationProduces (optional_write_message, new_mem) ->\n      (match optional_write_message with\n       | Some write_message ->\n           let thread = s.threads actor in\n           let new_write_buffer = build thread.write_buffer write_message in\n           let new_thread = { thread with write_buffer = new_write_buffer } in\n           let new_threads = Spec.Map.upd s.threads actor new_thread in\n           let s' = { s with mem = new_mem; threads = new_threads; } in\n           assert (global_variables_unaddressed_in_memory vs s'.mem);\n           assert (positions_valid_in_state s');\n           assert (roots_match s'.mem)\n       | None ->\n           let s' = { s with mem = new_mem; } in\n           assert (global_variables_unaddressed_in_memory vs s'.mem);\n           assert (positions_valid_in_state s');\n           assert (roots_match s'.mem)\n       | _ -> false_elim ()\n      )\n  | _ -> ()\n\nlet update_expression_lacking_pointer_field_maintains_gvars_unaddressed\n  (vs: list var_id_t)\n  (exp: expression_t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (new_value: object_value_t)\n  (s: Armada.State.t)\n  : Lemma (requires   positions_valid_in_state s\n                    /\\ global_variables_unaddressed_in_memory vs s.mem\n                    /\\ roots_match s.mem\n                    /\\ object_td_lacks_pointer_field (expression_to_td exp))\n          (ensures  (match update_expression exp actor writer_pc writer_expression_number\n                             bypassing_write_buffer new_value s with\n                     | ComputationProduces s' ->\n                           positions_valid_in_state s'\n                         /\\ global_variables_unaddressed_in_memory vs s'.mem\n                         /\\ roots_match s'.mem\n                     | _ -> True)) =\n  if   not (expression_valid exp)\n     || not (object_value_valid new_value)\n     || neqb (object_value_to_td new_value) (expression_to_td exp) then\n    ()\n  else (\n    let td = expression_to_td exp in\n    match lvalue_computation exp actor s with\n    | ComputationProduces p ->\n        update_pointed_to_value_lacking_pointer_field_maintains_gvars_unaddressed vs p actor\n          writer_pc writer_expression_number bypassing_write_buffer td new_value s;\n        (match update_pointed_to_value p actor writer_pc writer_expression_number bypassing_write_buffer\n                 new_value s with\n         | ComputationProduces s' -> ()\n         | _ -> ())\n    | _ -> ()\n  )\n\nlet update_expression_with_gvars_unaddressed_maintains_gvars_unaddressed\n  (vs: list var_id_t)\n  (exp: expression_t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (new_value: object_value_t)\n  (s: Armada.State.t)\n  : Lemma (requires   positions_valid_in_state s\n                    /\\ global_variables_unaddressed_in_memory vs s.mem\n                    /\\ roots_match s.mem\n                    /\\ global_variables_unaddressed_in_object_value vs new_value)\n          (ensures  (match update_expression exp actor writer_pc writer_expression_number\n                             bypassing_write_buffer new_value s with\n                     | ComputationProduces s' ->\n                           positions_valid_in_state s'\n                         /\\ global_variables_unaddressed_in_memory vs s'.mem\n                         /\\ roots_match s'.mem\n                     | _ -> True)) =\n  if   not (expression_valid exp)\n     || not (object_value_valid new_value)\n     || neqb (object_value_to_td new_value) (expression_to_td exp) then\n    ()\n  else (\n    let td = expression_to_td exp in\n    match lvalue_computation exp actor s with\n    | ComputationProduces p ->\n        update_pointed_to_value_with_gvars_unaddressed_maintains_gvars_unaddressed vs p actor writer_pc\n          writer_expression_number bypassing_write_buffer new_value s;\n        (match update_pointed_to_value p actor writer_pc writer_expression_number bypassing_write_buffer\n                 new_value s with\n         | ComputationProduces s' -> ()\n         | _ -> ())\n    | _ -> ()\n  )\n\nlet rec update_expressions_with_gvars_unaddressed_maintains_gvars_unaddressed\n  (vs: list var_id_t)\n  (exps: list expression_t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (new_values: list object_value_t)\n  (s: Armada.State.t)\n  : Lemma (requires   positions_valid_in_state s\n                    /\\ global_variables_unaddressed_in_memory vs s.mem\n                    /\\ roots_match s.mem\n                    /\\ global_variables_unaddressed_in_object_values vs new_values)\n          (ensures  (match update_expressions exps actor writer_pc writer_expression_number\n                             bypassing_write_buffer new_values s with\n                     | ComputationProduces s' ->\n                           positions_valid_in_state s'\n                         /\\ global_variables_unaddressed_in_memory vs s'.mem\n                         /\\ roots_match s'.mem\n                     | _ -> True)) =\n  match exps, new_values with\n  | [], [] -> ()\n  | first_exp :: remaining_exps, first_new_value :: remaining_new_values ->\n      update_expression_with_gvars_unaddressed_maintains_gvars_unaddressed vs first_exp actor writer_pc\n        writer_expression_number bypassing_write_buffer first_new_value s;\n      (match update_expression first_exp actor writer_pc writer_expression_number\n               bypassing_write_buffer first_new_value s with\n       | ComputationProduces s_next ->\n           update_expressions_with_gvars_unaddressed_maintains_gvars_unaddressed vs\n             remaining_exps actor writer_pc (writer_expression_number + 1)\n             bypassing_write_buffer remaining_new_values s_next;\n           (match update_expressions exps actor writer_pc writer_expression_number\n                    bypassing_write_buffer new_values s with\n            | ComputationProduces s' -> ()\n            | _ -> ())\n       | _ -> ())\n  | _ -> ()\n\nlet rec update_expressions_lacking_pointer_field_maintains_gvars_unaddressed\n  (vs: list var_id_t)\n  (exps: list expression_t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (new_values: list object_value_t)\n  (s: Armada.State.t)\n  : Lemma (requires   positions_valid_in_state s\n                    /\\ global_variables_unaddressed_in_memory vs s.mem\n                    /\\ roots_match s.mem\n                    /\\ expressions_lack_pointer_field exps)\n          (ensures  (match update_expressions exps actor writer_pc writer_expression_number\n                             bypassing_write_buffer new_values s with\n                     | ComputationProduces s' ->\n                           positions_valid_in_state s'\n                         /\\ global_variables_unaddressed_in_memory vs s'.mem\n                         /\\ roots_match s'.mem\n                     | _ -> True)) =\n  match exps, new_values with\n  | [], [] -> ()\n  | first_exp :: remaining_exps, first_new_value :: remaining_new_values ->\n      update_expression_lacking_pointer_field_maintains_gvars_unaddressed vs first_exp actor writer_pc\n        writer_expression_number bypassing_write_buffer first_new_value s;\n      (match update_expression first_exp actor writer_pc writer_expression_number\n               bypassing_write_buffer first_new_value s with\n       | ComputationProduces s_next ->\n           update_expressions_lacking_pointer_field_maintains_gvars_unaddressed vs remaining_exps actor\n             writer_pc (writer_expression_number + 1) bypassing_write_buffer remaining_new_values s_next;\n           (match update_expressions exps actor writer_pc writer_expression_number\n                    bypassing_write_buffer new_values s with\n            | ComputationProduces s' -> ()\n            | _ -> ())\n       | _ -> ())\n  | _ -> ()\n\nlet propagate_write_message_maintains_gvars_unaddressed\n  (vs: list var_id_t)\n  (write_message: write_message_t)\n  (receiver_tid: tid_t)\n  (mem: Armada.Memory.t)\n  : Lemma (requires   global_variables_unaddressed_in_memory vs mem\n                    /\\ roots_match mem)\n          (ensures  (match propagate_write_message write_message receiver_tid mem with\n                     | ComputationProduces mem' ->\n                           global_variables_unaddressed_in_memory vs mem'\n                         /\\ roots_match mem'\n                     | _ -> True)) =\n  let p = write_message.location in\n  dereference_computation_when_gvars_unaddressed_produces_storage_with_gvars_unaddressed vs p mem;\n  match dereference_computation p mem with\n  | ComputationProduces storage ->\n      (match storage with\n       | ObjectStorageWeaklyConsistentPrimitive primitive_td values local_versions ->\n           if   primitive_td <> write_message.primitive_td\n              || write_message.version >= length values\n              || local_versions receiver_tid >= write_message.version then\n             ()\n           else\n             let new_local_versions = Spec.Map.upd local_versions receiver_tid write_message.version in\n             let new_storage = ObjectStorageWeaklyConsistentPrimitive primitive_td values\n                                 new_local_versions in\n             if not (object_storage_valid new_storage) then\n               ()\n             else\n               update_pointer_directly_with_gvars_unaddressed_maintains_gvars_unaddressed vs p new_storage mem\n       | _ -> ()\n     )\n  | _ -> ()\n"
  },
  {
    "path": "experimental/lib/Strategies.GlobalVars.UnaddressedStatement.fst",
    "content": "module Strategies.GlobalVars.UnaddressedStatement\n\nopen FStar.Sequence.Ambient\nopen FStar.Sequence.Base\n\nopen Util.Seq\nopen Util.Trigger\nopen Spec.List\nopen Spec.Ubool\n\nopen Armada.Base\nopen Armada.BinaryOp\nopen Armada.Computation\nopen Armada.Expression\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Pointer\nopen Armada.State\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Type\nopen Armada.Transition\nopen Armada.UnaryOp\n\nopen Strategies.Invariant\nopen Strategies.ArmadaInvariant.PositionsValid\nopen Strategies.ArmadaInvariant.RootsMatch\nopen Strategies.GlobalVars\nopen Strategies.GlobalVars.Util\nopen Strategies.GlobalVars.Unaddressed\nopen Strategies.ArmadaStatement\n\n#push-options \"--z3rlimit 10\"\n\nlet inductive_invariant (vs: list var_id_t) (s: Armada.State.t) =\n  global_variables_unaddressed_in_memory vs s.mem /\\ positions_valid_in_state s /\\ roots_match s.mem\n\nlet rec object_lacking_pointer_field_global_variables_unaddressed\n  (vs: list var_id_t)\n  (value: object_value_t)\n  : Lemma (requires   object_td_lacks_pointer_field (object_value_to_td value)\n                    /\\ object_value_valid value)\n          (ensures    global_variables_unaddressed_in_object_value vs value)\n          (decreases  rank value)\n  = match value with\n    | ObjectValuePrimitive value ->\n      ()\n    | ObjectValueStruct fields ->\n      objects_lacking_pointer_field_global_variables_unaddressed vs fields\n    | ObjectValueArray element_td elements -> begin\n        objects_lacking_pointer_field_global_variables_unaddressed vs elements;\n        global_variables_unaddressed_in_object_value_seq_equivalent_to_forall vs elements\n      end\n    | ObjectValueAbstract _ _ -> ()\n\nand objects_lacking_pointer_field_global_variables_unaddressed\n  (vs: list var_id_t)\n  (values: seq object_value_t)\n  : Lemma (requires    (forall value. contains values value ==> object_value_valid value)\n                    /\\ (forall value. contains values value ==> object_td_lacks_pointer_field (object_value_to_td value)))\n          (ensures     forall value. contains values value ==> global_variables_unaddressed_in_object_value vs value)\n          (decreases   rank values)\n  = if length values = 0 then\n      ()\n    else begin\n      object_lacking_pointer_field_global_variables_unaddressed vs (index values 0);\n      objects_lacking_pointer_field_global_variables_unaddressed vs (drop values 1)\n    end\n\nlet rvalue_computation_lacking_pointer_field_global_variable_unaddrsessed\n  (vs: list var_id_t)\n  (exp: expression_t)\n  (actor: tid_t)\n  (s: Armada.State.t)\n  : Lemma (requires expression_lacks_pointer_field exp)\n          (ensures  otherwise true begin\n                      let? value = rvalue_computation exp actor s in\n                      return (global_variables_unaddressed_in_object_value vs value)\n                    end)\n  = match rvalue_computation exp actor s with\n    | ComputationProduces value -> begin\n      assert (object_value_valid value /\\ object_value_to_td value == expression_to_td exp);\n      object_lacking_pointer_field_global_variables_unaddressed vs value\n      end\n    | _ -> ()\n\nlet rvalue_computation_when_gvars_unaddressed_at_top_level_produces_value_with_gvars_unaddressed\n  (vs: list var_id_t)\n  (exp: expression_t)\n  (actor: tid_t)\n  (s: Armada.State.t)\n  : Lemma (requires   global_variables_unaddressed_at_top_level_in_rvalue_expression vs exp\n                    /\\ inductive_invariant vs s)\n          (ensures    otherwise true begin\n                        let? value = rvalue_computation exp actor s in\n                        return (global_variables_unaddressed_in_object_value vs value)\n                      end)\n    = if global_variables_unaddressed_in_rvalue_expression vs exp then\n        rvalue_computation_when_gvars_unaddressed_produces_value_with_gvars_unaddressed vs exp actor s\n      else\n        rvalue_computation_lacking_pointer_field_global_variable_unaddrsessed vs exp actor s\n\nlet update_statement_unaddressable_global_vars_unaddressed_in_memory\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (step: Armada.Step.t)\n  (starts_atomic_block ends_atomic_block: bool)\n  (s: Armada.State.t)\n  : Lemma (requires   UpdateStatement? step.action.program_statement.statement\n                    /\\ global_variables_unaddressable_in_statement vs step.action.program_statement.statement\n                    /\\ Some? (step_computation actor starts_atomic_block ends_atomic_block step s)\n                    /\\ inductive_invariant vs s)\n          (ensures  global_variables_unaddressed_in_memory vs (Some?.v (step_computation actor starts_atomic_block ends_atomic_block step s)).mem)\n  = if step.action.ok then begin\n       let stmt = step.action.program_statement.statement in\n       let thread = s.threads actor in\n       let dst = UpdateStatement?.dst stmt in\n       let src = UpdateStatement?.src stmt in\n       let bypassing_write_buffer = UpdateStatement?.bypassing_write_buffer stmt in\n       let new_value = ComputationProduces?.result (rvalue_computation src actor s) in\n       rvalue_computation_when_gvars_unaddressed_at_top_level_produces_value_with_gvars_unaddressed vs src actor s;\n       update_expression_with_gvars_unaddressed_maintains_gvars_unaddressed vs dst actor thread.pc 0 bypassing_write_buffer new_value s\n    end\n\nlet nondeterministic_update_statement_unaddressable_global_vars_unaddressed_in_memory\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (step: Armada.Step.t)\n  (starts_atomic_block ends_atomic_block: bool)\n  (s: Armada.State.t)\n  : Lemma (requires   NondeterministicUpdateStatement? step.action.program_statement.statement\n                    /\\ global_variables_unaddressable_in_statement vs step.action.program_statement.statement\n                    /\\ Some? (step_computation actor starts_atomic_block ends_atomic_block step s)\n                    /\\ inductive_invariant vs s)\n          (ensures  global_variables_unaddressed_in_memory vs (Some?.v (step_computation actor starts_atomic_block ends_atomic_block step s)).mem)\n  = if step.action.ok then begin\n       let stmt = step.action.program_statement.statement in\n       let thread = s.threads actor in\n       let dst = NondeterministicUpdateStatement?.dst stmt in\n       let nd_value = Cons?.hd step.nd in\n       let bypassing_write_buffer = NondeterministicUpdateStatement?.bypassing_write_buffer stmt in\n       update_expression_lacking_pointer_field_maintains_gvars_unaddressed vs dst actor thread.pc 0 bypassing_write_buffer nd_value s\n    end\n\nlet propagate_write_message_statement_unaddressable_global_vars_unaddressed_in_memory\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (step: Armada.Step.t)\n  (starts_atomic_block ends_atomic_block: bool)\n  (s: Armada.State.t)\n  : Lemma (requires   PropagateWriteMessageStatement? step.action.program_statement.statement\n                    /\\ global_variables_unaddressable_in_statement vs step.action.program_statement.statement\n                    /\\ Some? (step_computation actor starts_atomic_block ends_atomic_block step s)\n                    /\\ inductive_invariant vs s)\n          (ensures  global_variables_unaddressed_in_memory vs (Some?.v (step_computation actor starts_atomic_block ends_atomic_block step s)).mem)\n  = if step.action.ok then begin\n       let ps = step.action.program_statement in\n       let stmt = ps.statement in\n       match stmt with\n       | PropagateWriteMessageStatement -> begin\n         let thread = s.threads actor in\n         let start_pc = thread.pc in\n         let receiver_tid: tid_t = ObjectValueAbstract?.value (Cons?.hd step.nd) in\n         let propagator_thread = s.threads actor in\n         let receiver_thread = s.threads receiver_tid in\n         let which_message = receiver_thread.position_in_other_write_buffers actor in\n         let write_message = index propagator_thread.write_buffer which_message in\n         let position_in_other_write_buffers' =\n           Spec.Map.upd receiver_thread.position_in_other_write_buffers actor (which_message + 1) in\n         let receiver_thread' =\n           { receiver_thread with position_in_other_write_buffers = position_in_other_write_buffers' } in\n         let threads' = Spec.Map.upd s.threads receiver_tid receiver_thread' in\n         match propagate_write_message write_message receiver_tid s.mem with\n         | ComputationProduces mem' -> begin\n           let p = write_message.location in\n           let storage = ComputationProduces?.result (dereference_computation p s.mem) in\n           dereference_computation_when_gvars_unaddressed_produces_storage_with_gvars_unaddressed vs p s.mem;\n           match storage with\n           | ObjectStorageWeaklyConsistentPrimitive primitive_td values local_versions ->\n             let new_local_versions = Spec.Map.upd local_versions receiver_tid write_message.version in\n             let new_storage = ObjectStorageWeaklyConsistentPrimitive primitive_td values new_local_versions in\n             assert (global_variables_unaddressed_in_storage vs new_storage);\n             update_pointer_directly_with_gvars_unaddressed_maintains_gvars_unaddressed vs p new_storage s.mem\n           | _ -> ()\n         end\n         | _ -> ()\n       end\n       | _ -> ()\n    end\n\n\nlet compare_and_swap_statement_unaddressable_global_vars_unaddressed_in_memory\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (step: Armada.Step.t)\n  (starts_atomic_block ends_atomic_block: bool)\n  (s: Armada.State.t)\n  : Lemma (requires   CompareAndSwapStatement? step.action.program_statement.statement\n                    /\\ global_variables_unaddressable_in_statement vs step.action.program_statement.statement\n                    /\\ Some? (step_computation actor starts_atomic_block ends_atomic_block step s)\n                    /\\ inductive_invariant vs s)\n          (ensures  global_variables_unaddressed_in_memory vs (Some?.v (step_computation actor starts_atomic_block ends_atomic_block step s)).mem)\n  = if step.action.ok then begin\n      let ps = step.action.program_statement in\n      let thread = s.threads actor in\n      let stmt = ps.statement in\n      let target = CompareAndSwapStatement?.target stmt in\n      let old_val = CompareAndSwapStatement?.old_val stmt in\n      let new_val = CompareAndSwapStatement?.new_val stmt in\n      let optional_result = CompareAndSwapStatement?.optional_result stmt in\n      let bypassing_write_buffer = CompareAndSwapStatement?.bypassing_write_buffer stmt in\n      let target_value = ComputationProduces?.result (rvalue_computation target actor s) in\n      let old_value = ComputationProduces?.result (rvalue_computation old_val actor s) in\n      let new_value = ComputationProduces?.result (rvalue_computation new_val actor s) in\n      let target_ptr = ComputationProduces?.result (lvalue_computation target actor s) in\n      rvalue_computation_when_gvars_unaddressed_at_top_level_produces_value_with_gvars_unaddressed vs new_val actor s;\n      update_pointed_to_value_with_gvars_unaddressed_maintains_gvars_unaddressed\n        vs target_ptr actor thread.pc 0 false new_value s;\n      let swap = eqb target_value old_value in\n      let s' = ComputationProduces?.result (if swap then update_expression target actor thread.pc 0 false new_value s\n                                                    else return s) in\n      match optional_result with\n      | Some result ->\n        let swap_value = ObjectValuePrimitive (PrimitiveBoxBool swap) in\n        let result_ptr = ComputationProduces?.result (lvalue_computation result actor s) in\n        assert (global_variables_unaddressed_in_object_value vs swap_value);\n        update_pointed_to_value_with_gvars_unaddressed_maintains_gvars_unaddressed\n          vs result_ptr actor thread.pc 1 bypassing_write_buffer swap_value s'\n      | _ -> ()\n    end\n\nlet expression_lvalue_computable_gvars_unaddressed_in_rvalue\n  (vs: list var_id_t)\n  (e: expression_t)\n  (actor: tid_t)\n  (s: Armada.State.t)\n  : Lemma (requires begin match lvalue_computation e actor s with\n                          | ComputationImpossible -> false\n                          | _ -> true\n                    end)\n          (ensures  global_variables_unaddressed_in_rvalue_expression vs e)\n  = ()\n\n#push-options \"--z3rlimit 30\"\n\nlet atomic_exchange_statement_unaddressable_global_vars_unaddressed_in_memory\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (step: Armada.Step.t)\n  (starts_atomic_block ends_atomic_block: bool)\n  (s: Armada.State.t)\n  : Lemma (requires   AtomicExchangeStatement? step.action.program_statement.statement\n                    /\\ global_variables_unaddressable_in_statement vs step.action.program_statement.statement\n                    /\\ Some? (step_computation actor starts_atomic_block ends_atomic_block step s)\n                    /\\ inductive_invariant vs s)\n          (ensures  global_variables_unaddressed_in_memory vs (Some?.v (step_computation actor starts_atomic_block ends_atomic_block step s)).mem)\n  = if step.action.ok then begin\n       let ps = step.action.program_statement in\n       let stmt = ps.statement in\n       let thread = s.threads actor in\n       let old_val = AtomicExchangeStatement?.old_val stmt in\n       let old_ptr = ComputationProduces?.result (lvalue_computation old_val actor s) in\n       let new_val = AtomicExchangeStatement?.new_val stmt in\n       let new_value = ComputationProduces?.result (rvalue_computation new_val actor s) in\n       let target = AtomicExchangeStatement?.target stmt in\n       let target_value = ComputationProduces?.result (rvalue_computation target actor s) in\n       let target_ptr = ComputationProduces?.result (lvalue_computation target actor s) in\n       let s' = ComputationProduces?.result (update_pointed_to_value old_ptr actor thread.pc 0 false target_value s) in\n       rvalue_computation_when_gvars_unaddressed_produces_value_with_gvars_unaddressed vs target actor s;\n       expression_lvalue_computable_gvars_unaddressed_in_rvalue vs target actor s;\n       update_pointed_to_value_with_gvars_unaddressed_maintains_gvars_unaddressed vs old_ptr actor thread.pc 0 false target_value s;\n       rvalue_computation_when_gvars_unaddressed_at_top_level_produces_value_with_gvars_unaddressed vs new_val actor s;\n       update_pointed_to_value_with_gvars_unaddressed_maintains_gvars_unaddressed vs target_ptr actor thread.pc 0 false new_value s'\n    end\n\n#pop-options\n\nlet rec rvalues_computation_when_gvars_unaddressed_at_top_level_produce_values_with_gvars_unaddressed\n  (vs: list var_id_t)\n  (exps: list expression_t)\n  (actor: tid_t)\n  (s: Armada.State.t)\n  : Lemma (requires   global_variables_unaddressed_at_top_level_in_rvalue_expressions vs exps\n                    /\\ inductive_invariant vs s)\n          (ensures  (match rvalues_computation exps actor s with\n                     | ComputationProduces values -> global_variables_unaddressed_in_object_values vs values\n                     | _ -> True))\n          (decreases exps) =\n  match exps with\n  | [] -> ()\n  | exp :: exps' ->\n    rvalue_computation_when_gvars_unaddressed_at_top_level_produces_value_with_gvars_unaddressed vs exp actor s;\n    rvalues_computation_when_gvars_unaddressed_at_top_level_produce_values_with_gvars_unaddressed vs exps' actor s\n\nlet push_stack_variable_maintains_inductive_invariant\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (initializer: initializer_t)\n  (s: Armada.State.t)\n  : Lemma (requires   inductive_invariant vs s\n                    /\\ global_variables_unaddressed_in_initializer vs initializer)\n          (ensures    otherwise True begin\n                        let? s' = push_stack_variable\n                                  actor writer_pc writer_expression_number method_id frame_uniq initializer s in\n                        return (inductive_invariant vs s')\n                      end) =\n  let root_id = RootIdStack actor method_id frame_uniq initializer.var_id in\n  let root = s.mem root_id in\n  if not (stack_variable_ready_for_push root initializer) then\n    ()\n  else\n    let thread = s.threads actor in\n    let var_id = initializer.var_id in\n    if list_contains var_id thread.top.local_variables then\n      ()\n    else\n      let local_variables' = var_id :: thread.top.local_variables in\n      let top' = { thread.top with local_variables = local_variables' } in\n      let thread' = { thread with top = top' } in\n      let threads' = Spec.Map.upd s.threads actor thread' in\n      let storage = RootStackVariable?.storage root in\n      assert (object_storage_arbitrarily_initialized_correctly storage);\n      object_storage_arbitrarily_initialized_correctly_doesnt_depend_on_gvars vs storage;\n      let root' = RootStackVariable true false (RootStackVariable?.storage root) in\n      assert (global_variables_unaddressed_in_root vs root');\n      let mem' = Spec.Map.upd s.mem root_id root' in\n      let mem_unaddressed(): Lemma (ensures global_variables_unaddressed_in_memory vs mem') =\n        introduce forall root_id' . global_variables_unaddressed_in_root vs (mem' root_id')\n        with\n          if root_id = root_id' then\n            ()\n          else\n            ()\n      in\n      mem_unaddressed();\n      let s' = { s with mem = mem'; threads = threads' } in\n      (match initializer.iv with\n       | InitializerArbitrary td -> ()\n       | InitializerSpecific value ->\n           push_stack_variable_maintains_roots_match\n             actor writer_pc writer_expression_number method_id frame_uniq initializer s';\n           let td = (object_value_to_td value) in\n           update_expression_with_gvars_unaddressed_maintains_gvars_unaddressed\n             vs (ExpressionLocalVariable td var_id) actor writer_pc\n             writer_expression_number false value s')\n\nlet rec push_stack_variables_maintains_inductive_invariant\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (initializers: list initializer_t)\n  (s: Armada.State.t)\n  : Lemma (requires   inductive_invariant vs s\n                    /\\ global_variables_unaddressed_in_initializers vs initializers)\n          (ensures    otherwise True begin\n                        let? s' = push_stack_variables\n                                  actor writer_pc writer_expression_number method_id frame_uniq initializers s in\n                        return (inductive_invariant vs s')\n                      end)\n          (decreases initializers) =\n  match initializers with\n  | [] -> ()\n  | first_initializer :: remaining_initializers ->\n      (match push_stack_variable actor writer_pc writer_expression_number method_id frame_uniq first_initializer s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces s' ->\n           assert (global_variables_unaddressed_in_initializer vs first_initializer);\n           push_stack_variable_maintains_inductive_invariant\n             vs actor writer_pc writer_expression_number method_id frame_uniq first_initializer s;\n           assert (inductive_invariant vs s');\n           push_stack_variables_maintains_inductive_invariant\n             vs actor writer_pc (writer_expression_number + 1)\n             method_id frame_uniq remaining_initializers s')\n\nlet rec push_stack_parameters_maintains_inductive_invariant\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (var_ids: list var_id_t)\n  (parameters: list object_value_t)\n  (s: Armada.State.t)\n  : Lemma (requires   inductive_invariant vs s\n                    /\\ global_variables_unaddressed_in_object_values vs parameters)\n          (ensures    otherwise True begin\n                        let? s' = push_stack_parameters\n                                  actor writer_pc writer_expression_number method_id frame_uniq var_ids parameters s in\n                      return (inductive_invariant vs s')\n                    end)\n          (decreases parameters) =\n  match parameters, var_ids with\n  | [], [] -> ()\n  | first_parameter :: remaining_parameters, first_var_id :: remaining_var_ids ->\n      let first_initializer =\n        { var_id = first_var_id; iv = InitializerSpecific first_parameter; weakly_consistent = false } in\n      assert (global_variables_unaddressed_in_initializer vs first_initializer);\n      push_stack_variable_maintains_inductive_invariant\n        vs actor writer_pc writer_expression_number method_id frame_uniq first_initializer s;\n      (match push_stack_variable actor writer_pc writer_expression_number method_id frame_uniq first_initializer s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces s' ->\n           push_stack_parameters_maintains_inductive_invariant\n             vs actor writer_pc (writer_expression_number + 1)\n             method_id frame_uniq remaining_var_ids remaining_parameters s')\n  | _ -> ()\n\nlet create_thread_statement_unaddressable_global_vars_unaddressed_in_memory\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (step: Armada.Step.t)\n  (starts_atomic_block ends_atomic_block: bool)\n  (s: Armada.State.t)\n  : Lemma (requires   CreateThreadStatement? step.action.program_statement.statement\n                    /\\ global_variables_unaddressable_in_statement vs step.action.program_statement.statement\n                    /\\ Some? (step_computation actor starts_atomic_block ends_atomic_block step s)\n                    /\\ inductive_invariant vs s)\n          (ensures  global_variables_unaddressed_in_memory vs (Some?.v (step_computation actor starts_atomic_block ends_atomic_block step s)).mem)\n  = if step.action.ok then begin\n       let ps = step.action.program_statement in\n       let stmt = ps.statement in\n       match stmt with\n       | CreateThreadStatement method_id initial_pc bypassing_write_buffer optional_result parameter_var_ids parameter_expressions local_variable_initializers ->\n         let thread = s.threads actor in\n         let start_pc = thread.pc in\n         let create_thread_nd: create_thread_nd_t = ObjectValueAbstract?.value (Cons?.hd step.nd) in\n         let new_tid = create_thread_nd.new_tid in\n         if new_tid = 0 then\n           match optional_result with\n           | None -> ()\n           | Some result ->\n             let new_tid_value = ObjectValuePrimitive (PrimitiveBoxThreadId new_tid) in\n             update_expression_with_gvars_unaddressed_maintains_gvars_unaddressed vs result actor start_pc (list_len parameter_var_ids + list_len local_variable_initializers) bypassing_write_buffer new_tid_value s\n         else begin\n           let new_thread = s.threads new_tid in\n           let frame_uniq = create_thread_nd.frame_uniq in\n           assert (~ (new_thread.status <> ThreadStatusNotStarted\n                  || length new_thread.write_buffer <> 0\n                  || list_contains frame_uniq s.uniqs_used));\n           let parameter_values = ComputationProduces?.result (rvalues_computation parameter_expressions actor s) in\n           rvalues_computation_when_gvars_unaddressed_at_top_level_produce_values_with_gvars_unaddressed vs parameter_expressions actor s;\n           let s2 = make_thread_running method_id initial_pc new_tid frame_uniq s in\n           push_stack_parameters_maintains_inductive_invariant\n             vs new_tid start_pc 0 method_id frame_uniq parameter_var_ids parameter_values s2;\n           let s3 = ComputationProduces?.result\n             (push_stack_parameters new_tid start_pc 0 method_id frame_uniq parameter_var_ids parameter_values s2) in\n           push_stack_variables_maintains_inductive_invariant\n             vs new_tid start_pc (list_len parameter_var_ids) method_id frame_uniq local_variable_initializers s3;\n           let s4 = ComputationProduces?.result\n             (push_stack_variables new_tid start_pc (list_len parameter_var_ids) method_id frame_uniq\n              local_variable_initializers s3) in\n           match optional_result with\n           | None -> ()\n           | Some result ->\n             let new_tid_value = ObjectValuePrimitive (PrimitiveBoxThreadId new_tid) in\n             update_expression_with_gvars_unaddressed_maintains_gvars_unaddressed\n               vs result actor start_pc (list_len parameter_var_ids + list_len local_variable_initializers)\n               bypassing_write_buffer new_tid_value s4\n         end\n       | _ -> ()\n    end\n\nlet method_call_statement_unaddressable_global_vars_unaddressed_in_memory\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (step: Armada.Step.t)\n  (starts_atomic_block ends_atomic_block: bool)\n  (s: Armada.State.t)\n  : Lemma (requires   MethodCallStatement? step.action.program_statement.statement\n                    /\\ global_variables_unaddressable_in_statement vs step.action.program_statement.statement\n                    /\\ Some? (step_computation actor starts_atomic_block ends_atomic_block step s)\n                    /\\ inductive_invariant vs s)\n          (ensures  global_variables_unaddressed_in_memory vs (Some?.v (step_computation actor starts_atomic_block ends_atomic_block step s)).mem)\n  = if step.action.ok then begin\n       let ps = step.action.program_statement in\n         let stmt = ps.statement in\n         match stmt with\n         | MethodCallStatement\n           method_id return_pc parameter_var_ids parameter_expressions local_variable_initializers stack_overflow ->\n           let thread = s.threads actor in\n           let start_pc = thread.pc in\n           let method_call_nd: method_call_nd_t = ObjectValueAbstract?.value (Cons?.hd step.nd) in\n           let frame_uniq = method_call_nd.frame_uniq in\n           assert (~ (list_contains frame_uniq s.uniqs_used));\n           let parameter_values = ComputationProduces?.result (rvalues_computation parameter_expressions actor s) in\n           let s2 = push_stack_frame actor method_id return_pc frame_uniq s in\n           let s3 = ComputationProduces?.result\n             (push_stack_parameters actor start_pc 0 method_id frame_uniq parameter_var_ids parameter_values s2) in\n           rvalues_computation_when_gvars_unaddressed_at_top_level_produce_values_with_gvars_unaddressed vs parameter_expressions actor s;\n           push_stack_parameters_maintains_inductive_invariant\n             vs actor start_pc 0 method_id frame_uniq parameter_var_ids parameter_values s2;\n           let s4 = ComputationProduces?.result\n             (push_stack_variables actor start_pc (list_len parameter_var_ids) method_id frame_uniq \n              local_variable_initializers s3) in\n           push_stack_variables_maintains_inductive_invariant\n             vs actor start_pc (list_len parameter_var_ids) method_id frame_uniq local_variable_initializers s3\n         | _ -> ()\n         end\n\nlet rec pop_stack_variables_maintains_inductive_invariant\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (var_ids: list var_id_t)\n  (s: Armada.State.t)\n  : Lemma (requires inductive_invariant vs s)\n          (ensures otherwise True begin\n                     let? mem' = pop_stack_variables actor method_id frame_uniq var_ids s.mem in\n                     return (inductive_invariant vs ({ s with mem = mem' }))\n                   end)\n  = match var_ids with\n    | [] -> ()\n    | first_var_id :: remaining_var_ids -> begin\n      match pop_stack_variable actor method_id frame_uniq first_var_id s.mem with\n      | ComputationProduces mem' ->\n        assert (inductive_invariant vs ({s with mem = mem'}));\n        pop_stack_variables_maintains_inductive_invariant\n          vs actor method_id frame_uniq remaining_var_ids ({s with mem = mem'})\n      | _ -> ()\n    end\n\nlet return_statement_unaddressable_global_vars_unaddressed_in_memory\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (step: Armada.Step.t)\n  (starts_atomic_block ends_atomic_block: bool)\n  (s: Armada.State.t)\n  : Lemma (requires   ReturnStatement? step.action.program_statement.statement\n                    /\\ global_variables_unaddressable_in_statement vs step.action.program_statement.statement\n                    /\\ Some? (step_computation actor starts_atomic_block ends_atomic_block step s)\n                    /\\ inductive_invariant vs s)\n          (ensures  global_variables_unaddressed_in_memory vs (Some?.v (step_computation actor starts_atomic_block ends_atomic_block step s)).mem)\n  = if step.action.ok then begin\n       let ps = step.action.program_statement in\n       let stmt = ps.statement in\n       match stmt with\n       | ReturnStatement method_id bypassing_write_buffer output_dsts output_srcs ->\n         let thread = s.threads actor in\n         let start_pc = thread.pc in\n         let output_values = ComputationProduces?.result (rvalues_computation output_srcs actor s) in\n         rvalues_computation_when_gvars_unaddressed_at_top_level_produce_values_with_gvars_unaddressed vs output_srcs actor s;\n         let mem' = ComputationProduces?.result\n           (pop_stack_variables actor method_id thread.top.frame_uniq thread.top.local_variables s.mem) in\n         pop_stack_variables_maintains_inductive_invariant\n           vs actor method_id thread.top.frame_uniq thread.top.local_variables s;\n         let s2 = pop_stack_frame actor mem' s in\n         update_expressions_with_gvars_unaddressed_maintains_gvars_unaddressed\n           vs output_dsts actor start_pc 0 bypassing_write_buffer output_values s2\n       | _ -> ()\n    end\n\n\nlet terminate_thread_statement_unaddressable_global_vars_unaddressed_in_memory\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (step: Armada.Step.t)\n  (starts_atomic_block ends_atomic_block: bool)\n  (s: Armada.State.t)\n  : Lemma (requires   TerminateThreadStatement? step.action.program_statement.statement\n                    /\\ global_variables_unaddressable_in_statement vs step.action.program_statement.statement\n                    /\\ Some? (step_computation actor starts_atomic_block ends_atomic_block step s)\n                    /\\ inductive_invariant vs s)\n          (ensures  global_variables_unaddressed_in_memory vs (Some?.v (step_computation actor starts_atomic_block ends_atomic_block step s)).mem)\n  = if step.action.ok then begin\n       let ps = step.action.program_statement in\n       let stmt = ps.statement in\n       match stmt with\n       | TerminateThreadStatement method_id ->\n         let thread = s.threads actor in\n         pop_stack_variables_maintains_inductive_invariant\n           vs actor method_id thread.top.frame_uniq thread.top.local_variables s\n       | _ -> ()\n    end\n\nlet mark_allocation_root_allocated_maintains_inductive_invariant\n  (vs: list var_id_t)\n  (uniq: root_id_uniquifier_t)\n  (storage: valid_object_storage_t)\n  (s: Armada.State.t)\n  : Lemma (requires   inductive_invariant vs s\n                    /\\ global_variables_unaddressed_in_storage vs storage)\n          (ensures inductive_invariant vs (mark_allocation_root_allocated uniq storage s))\n  = ()\n\nlet alloc_successful_statement_unaddressable_global_vars_unaddressed_in_memory\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (step: Armada.Step.t)\n  (starts_atomic_block ends_atomic_block: bool)\n  (s: Armada.State.t)\n  : Lemma (requires   (  MallocSuccessfulStatement? step.action.program_statement.statement\n                      || CallocSuccessfulStatement? step.action.program_statement.statement)\n                    /\\ global_variables_unaddressable_in_statement vs step.action.program_statement.statement\n                    /\\ Some? (step_computation actor starts_atomic_block ends_atomic_block step s)\n                    /\\ inductive_invariant vs s)\n          (ensures  global_variables_unaddressed_in_memory vs (Some?.v (step_computation actor starts_atomic_block ends_atomic_block step s)).mem)\n  = if step.action.ok then begin\n       let ps = step.action.program_statement in\n       let stmt = ps.statement in\n       match stmt with\n       | CallocSuccessfulStatement bypassing_write_buffer result allocation_td count\n       | MallocSuccessfulStatement bypassing_write_buffer result allocation_td count ->\n         let thread = s.threads actor in\n         let start_pc = thread.pc in\n         let count_value = ComputationProduces?.result (rvalue_computation count actor s) in\n         let sz = ObjectValueAbstract?.value count_value in\n         let array_td = ObjectTDArray allocation_td sz in\n         let uniq = ObjectValueAbstract?.value (Cons?.hd step.nd) in\n         let root_id = RootIdAllocation uniq in\n         match s.mem root_id with\n         | RootAllocated allocated freed storage ->\n           let storage_doesnt_depend_on_gvars (): Lemma (ensures global_variables_unaddressed_in_storage vs storage) =\n             if (object_storage_arbitrarily_initialized_correctly storage) then\n               object_storage_arbitrarily_initialized_correctly_doesnt_depend_on_gvars vs storage\n             else\n               object_storage_zero_filled_doesnt_depend_on_gvars vs storage\n           in\n           storage_doesnt_depend_on_gvars ();\n           let s' = mark_allocation_root_allocated uniq storage s in\n           mark_allocation_root_allocated_maintains_inductive_invariant vs uniq storage s;\n           let p = ObjectValuePrimitive (PrimitiveBoxPointer (PointerIndex (PointerRoot root_id) 0)) in\n           update_expression_with_gvars_unaddressed_maintains_gvars_unaddressed\n             vs result actor start_pc 0 bypassing_write_buffer p s'\n         | _ -> ()\n       | _ -> ()\n    end\n\nlet alloc_returning_null_statement_unaddressable_global_vars_unaddressed_in_memory\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (step: Armada.Step.t)\n  (starts_atomic_block ends_atomic_block: bool)\n  (s: Armada.State.t)\n  : Lemma (requires   (  MallocReturningNullStatement? step.action.program_statement.statement\n                      || CallocReturningNullStatement? step.action.program_statement.statement)\n                    /\\ global_variables_unaddressable_in_statement vs step.action.program_statement.statement\n                    /\\ Some? (step_computation actor starts_atomic_block ends_atomic_block step s)\n                    /\\ inductive_invariant vs s)\n          (ensures  global_variables_unaddressed_in_memory vs (Some?.v (step_computation actor starts_atomic_block ends_atomic_block step s)).mem)\n  = if step.action.ok then begin\n       let ps = step.action.program_statement in\n       let stmt = ps.statement in\n       match stmt with\n       | MallocReturningNullStatement bypassing_write_buffer result count\n       | CallocReturningNullStatement bypassing_write_buffer result count ->\n         let thread = s.threads actor in\n         let start_pc = thread.pc in\n         let p = ObjectValuePrimitive (PrimitiveBoxPointer PointerNull) in\n         update_expression_with_gvars_unaddressed_maintains_gvars_unaddressed\n           vs result actor start_pc 0 bypassing_write_buffer p s\n       | _ -> ()\n    end\n\nlet somehow_statement_unaddressable_global_vars_unaddressed_in_memory\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (step: Armada.Step.t)\n  (starts_atomic_block ends_atomic_block: bool)\n  (s: Armada.State.t)\n  : Lemma (requires   SomehowStatement? step.action.program_statement.statement\n                    /\\ global_variables_unaddressable_in_statement vs step.action.program_statement.statement\n                    /\\ Some? (step_computation actor starts_atomic_block ends_atomic_block step s)\n                    /\\ inductive_invariant vs s)\n          (ensures  global_variables_unaddressed_in_memory vs (Some?.v (step_computation actor starts_atomic_block ends_atomic_block step s)).mem)\n  = if step.action.ok then begin\n       let ps = step.action.program_statement in\n       let stmt = ps.statement in\n       match stmt with\n       | SomehowStatement undefined_unless_cond bypassing_write_buffer modifies_clauses ensures_cond ->\n         let thread = s.threads actor in\n         let start_pc = thread.pc in\n         update_expressions_lacking_pointer_field_maintains_gvars_unaddressed\n           vs modifies_clauses actor start_pc 0 bypassing_write_buffer step.nd s\n       | _ -> ()\n    end\n\nlet fence_statement_unaddressable_global_vars_unaddressed_in_memory\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (step: Armada.Step.t)\n  (starts_atomic_block ends_atomic_block: bool)\n  (s: Armada.State.t)\n  : Lemma (requires   FenceStatement? step.action.program_statement.statement\n                    /\\ global_variables_unaddressable_in_statement vs step.action.program_statement.statement\n                    /\\ Some? (step_computation actor starts_atomic_block ends_atomic_block step s)\n                    /\\ inductive_invariant vs s)\n          (ensures  global_variables_unaddressed_in_memory vs (Some?.v (step_computation actor starts_atomic_block ends_atomic_block step s)).mem)\n  = if step.action.ok then begin\n       let ps = step.action.program_statement in\n       let stmt = ps.statement in\n       match stmt with\n       | FenceStatement ->\n         let thread = s.threads actor in\n         let start_pc = thread.pc in\n         let p = PointerRoot RootIdFence in\n         update_pointed_to_value_with_gvars_unaddressed_maintains_gvars_unaddressed\n           vs p actor start_pc 0 false (ObjectValuePrimitive (PrimitiveBoxBool false)) s\n       | _ -> ()\n    end\n\nlet rec external_method_take_snapshot_of_reads_clauses_computation_maintains_inductive_invariant\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (reads_clauses: list (var_id_t * expression_t))\n  (s: Armada.State.t)\n  : Lemma (requires   global_variables_unaddressed_in_reads_clauses vs reads_clauses\n                    /\\ inductive_invariant vs s)\n          (ensures  otherwise True begin\n                      let? s' = external_method_take_snapshot_of_reads_clauses_computation actor writer_pc writer_expression_number bypassing_write_buffer reads_clauses s in\n                      return (inductive_invariant vs s')\n                    end)\n          (decreases reads_clauses)\n  = match reads_clauses with\n  | [] -> ()\n  | (first_var_id, first_reads_expression) :: remaining_reads_clauses -> begin\n    match rvalue_computation first_reads_expression actor s with\n    | ComputationProduces first_value -> begin\n      let td = expression_to_td first_reads_expression in\n      let local_var = ExpressionLocalVariable td first_var_id in\n      match lvalue_computation local_var actor s with\n      | ComputationProduces p -> begin\n        assert (global_variables_unaddressed_in_pointer vs p);\n        match update_pointed_to_value\n              p actor writer_pc writer_expression_number bypassing_write_buffer first_value s with\n        | ComputationProduces s' ->\n          rvalue_computation_when_gvars_unaddressed_produces_value_with_gvars_unaddressed\n            vs first_reads_expression actor s;\n          update_pointed_to_value_with_gvars_unaddressed_maintains_gvars_unaddressed\n            vs p actor writer_pc writer_expression_number bypassing_write_buffer first_value s;\n          external_method_take_snapshot_of_reads_clauses_computation_maintains_inductive_invariant\n            vs actor writer_pc (writer_expression_number + 1) bypassing_write_buffer remaining_reads_clauses s'\n        | _ -> ()\n      end\n      | _ -> ()\n    end\n    | _ -> ()\n  end\n\nlet external_method_start_middle_statement_unaddressable_global_vars_unaddressed_in_memory\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (step: Armada.Step.t)\n  (starts_atomic_block ends_atomic_block: bool)\n  (s: Armada.State.t)\n  : Lemma (requires   (   ExternalMethodStartStatement? step.action.program_statement.statement\n                       || ExternalMethodMiddleStatement? step.action.program_statement.statement)\n                    /\\ global_variables_unaddressable_in_statement vs step.action.program_statement.statement\n                    /\\ Some? (step_computation actor starts_atomic_block ends_atomic_block step s)\n                    /\\ inductive_invariant vs s)\n          (ensures  global_variables_unaddressed_in_memory vs (Some?.v (step_computation actor starts_atomic_block ends_atomic_block step s)).mem)\n  = if step.action.ok then begin\n       let ps = step.action.program_statement in\n       let stmt = ps.statement in\n       match stmt with\n       | ExternalMethodStartStatement\n         _ _ bypassing_write_buffer modifies_clauses reads_clauses\n       | ExternalMethodMiddleStatement\n         bypassing_write_buffer modifies_clauses reads_clauses ->\n         let thread = s.threads actor in\n         let start_pc = thread.pc in\n         let s2 = ComputationProduces?.result\n           (update_expressions modifies_clauses actor start_pc 0 bypassing_write_buffer step.nd s) in\n         update_expressions_lacking_pointer_field_maintains_gvars_unaddressed\n           vs modifies_clauses actor start_pc 0 bypassing_write_buffer step.nd s;\n         external_method_take_snapshot_of_reads_clauses_computation_maintains_inductive_invariant\n           vs actor start_pc (list_len modifies_clauses) bypassing_write_buffer reads_clauses s2\n       | _ -> ()\n       | _ -> ()\n    end\n\nlet rec log_expressions_computation_maintains_inductive_invariant\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (logs_clauses: list expression_t)\n  (s: Armada.State.t)\n  : Lemma (requires inductive_invariant vs s)\n          (ensures  otherwise True begin\n                      let? s' = log_expressions_computation actor logs_clauses s in\n                        return (inductive_invariant vs s')\n                    end)\n  = match logs_clauses with\n  | [] -> ()\n  | first_logs_clause :: remaining_logs_clauses -> begin\n    match rvalue_computation first_logs_clause actor s with\n    | ComputationProduces event ->\n      let trace' = s.trace $:: event in\n      let s' = { s with trace = trace' } in\n      log_expressions_computation_maintains_inductive_invariant vs actor remaining_logs_clauses s'\n    | _ -> ()\n  end\n\nlet external_method_end_statement_unaddressable_global_vars_unaddressed_in_memory\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (step: Armada.Step.t)\n  (starts_atomic_block ends_atomic_block: bool)\n  (s: Armada.State.t)\n  : Lemma (requires   ExternalMethodEndStatement? step.action.program_statement.statement\n                    /\\ global_variables_unaddressable_in_statement vs step.action.program_statement.statement\n                    /\\ Some? (step_computation actor starts_atomic_block ends_atomic_block step s)\n                    /\\ inductive_invariant vs s)\n          (ensures  global_variables_unaddressed_in_memory vs (Some?.v (step_computation actor starts_atomic_block ends_atomic_block step s)).mem)\n  = if step.action.ok then begin\n       let ps = step.action.program_statement in\n       let stmt = ps.statement in\n       match stmt with\n       | ExternalMethodEndStatement _ logs_clauses ->\n         let thread = s.threads actor in\n         log_expressions_computation_maintains_inductive_invariant vs actor logs_clauses s\n       | _ -> ()\n    end\n\n#push-options \"--z3rlimit 30\"\n\nlet global_variables_unaddressable_by_statement_global_vars_unaddressed_in_state\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (step: Armada.Step.t)\n  (starts_atomic_block ends_atomic_block: bool)\n  (s: Armada.State.t)\n  : Lemma (requires   global_variables_unaddressable_in_statement vs step.action.program_statement.statement\n                    /\\ Some? (step_computation actor starts_atomic_block ends_atomic_block step s)\n                    /\\ roots_match s.mem /\\ positions_valid_in_state s\n                    /\\ global_variables_unaddressed_in_memory vs s.mem)\n          (ensures  global_variables_unaddressed_in_memory vs (Some?.v (step_computation actor starts_atomic_block ends_atomic_block step s)).mem)\n  = match step.action.program_statement.statement with\n  | UpdateStatement bypassing_write_buffer dst src ->\n      update_statement_unaddressable_global_vars_unaddressed_in_memory\n        vs actor step starts_atomic_block ends_atomic_block s\n  | NondeterministicUpdateStatement bypassing_write_buffer dst ->\n      nondeterministic_update_statement_unaddressable_global_vars_unaddressed_in_memory\n        vs actor step starts_atomic_block ends_atomic_block s\n  | PropagateWriteMessageStatement ->\n      propagate_write_message_statement_unaddressable_global_vars_unaddressed_in_memory\n        vs actor step starts_atomic_block ends_atomic_block s\n  | CompareAndSwapStatement target old_val new_val bypassing_write_buffer optional_result ->\n      compare_and_swap_statement_unaddressable_global_vars_unaddressed_in_memory\n        vs actor step starts_atomic_block ends_atomic_block s\n  | AtomicExchangeStatement old_val target new_val ->\n      atomic_exchange_statement_unaddressable_global_vars_unaddressed_in_memory\n        vs actor step starts_atomic_block ends_atomic_block s\n  | CreateThreadStatement method_id initial_pc bypassing_write_buffer optional_result parameter_var_ids\n                          parameter_expressions local_variable_initializers ->\n      create_thread_statement_unaddressable_global_vars_unaddressed_in_memory\n        vs actor step starts_atomic_block ends_atomic_block s\n  | MethodCallStatement method_id return_pc parameter_var_ids parameter_expressions local_variable_initializers\n                          stack_overflow ->\n      method_call_statement_unaddressable_global_vars_unaddressed_in_memory\n        vs actor step starts_atomic_block ends_atomic_block s\n  | ReturnStatement method_id bypassing_write_buffer output_dsts output_srcs ->\n      return_statement_unaddressable_global_vars_unaddressed_in_memory\n        vs actor step starts_atomic_block ends_atomic_block s\n  | TerminateThreadStatement method_id ->\n      terminate_thread_statement_unaddressable_global_vars_unaddressed_in_memory\n        vs actor step starts_atomic_block ends_atomic_block s\n  | MallocSuccessfulStatement bypassing_write_buffer result allocation_td count\n  | CallocSuccessfulStatement bypassing_write_buffer result allocation_td count ->\n      alloc_successful_statement_unaddressable_global_vars_unaddressed_in_memory\n        vs actor step starts_atomic_block ends_atomic_block s\n  | MallocReturningNullStatement bypassing_write_buffer result count\n  | CallocReturningNullStatement bypassing_write_buffer result count ->\n      alloc_returning_null_statement_unaddressable_global_vars_unaddressed_in_memory\n        vs actor step starts_atomic_block ends_atomic_block s\n  | SomehowStatement undefined_unless_cond bypassing_write_buffer modifies_clauses ensures_cond ->\n      somehow_statement_unaddressable_global_vars_unaddressed_in_memory\n        vs actor step starts_atomic_block ends_atomic_block s\n  | FenceStatement ->\n      fence_statement_unaddressable_global_vars_unaddressed_in_memory\n        vs actor step starts_atomic_block ends_atomic_block s\n  | ExternalMethodStartStatement _ _ _ _ _\n  | ExternalMethodMiddleStatement _ _ _ ->\n      external_method_start_middle_statement_unaddressable_global_vars_unaddressed_in_memory\n        vs actor step starts_atomic_block ends_atomic_block s\n  | ExternalMethodEndStatement ensures_cond logs_clauses ->\n      external_method_end_statement_unaddressable_global_vars_unaddressed_in_memory\n        vs actor step starts_atomic_block ends_atomic_block s\n  | _ -> ()\n\n#pop-options\n"
  },
  {
    "path": "experimental/lib/Strategies.GlobalVars.Util.fst",
    "content": "module Strategies.GlobalVars.Util\n\nopen Armada.Base\nopen Armada.BinaryOp\nopen Armada.Computation\nopen Armada.Expression\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Pointer\nopen Armada.State\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Type\nopen Armada.UnaryOp\nopen FStar.Sequence.Ambient\nopen FStar.Sequence.Base\nopen Spec.List\nopen Spec.Ubool\nopen Strategies.ArmadaInvariant.PositionsValid\nopen Strategies.ArmadaInvariant.RootsMatch\nopen Strategies.GlobalVars\nopen Strategies.GlobalVars.Pointer\nopen Strategies.GlobalVars.Unaddressed\nopen Strategies.GlobalVars.Value\nopen Strategies.PCRelation\nopen Util.List\nopen Util.Nth\nopen Util.Seq\nopen Util.Trigger\n\nlet memories_match_except_global_variables_reflexive (vs: list var_id_t) (mem: Armada.Memory.t)\n  : Lemma (memories_match_except_global_variables vs mem mem) =\n  ()\n\nlet memories_match_except_global_variables_commutative\n  (vs: list var_id_t)\n  (mem1: Armada.Memory.t)\n  (mem2: Armada.Memory.t)\n  : Lemma (memories_match_except_global_variables vs mem1 mem2 <==>\n             memories_match_except_global_variables vs mem2 mem1) =\n  ()\n\nlet memories_match_except_global_variables_transitive\n  (vs: list var_id_t)\n  (mem1: Armada.Memory.t)\n  (mem2: Armada.Memory.t)\n  (mem3: Armada.Memory.t)\n  : Lemma (requires   memories_match_except_global_variables vs mem1 mem2\n                    /\\ memories_match_except_global_variables vs mem2 mem3)\n          (ensures  memories_match_except_global_variables vs mem1 mem3) =\n  introduce forall root_id. (match root_id with\n                        | RootIdGlobal v -> list_contains v vs \\/ (mem1 root_id == mem3 root_id)\n                        | _ -> mem1 root_id == mem3 root_id)\n  with (\n    match root_id with\n    | RootIdGlobal v ->\n        assert (list_contains v vs \\/ (mem1 root_id == mem2 root_id));\n        assert (list_contains v vs \\/ (mem2 root_id == mem3 root_id))\n    | _ ->\n        assert (mem1 root_id == mem2 root_id);\n        assert (mem2 root_id == mem3 root_id)\n  )\n\nlet equality_pc_relation_implies_state_matches_itself_except_global_variables\n  (vs: list var_id_t)\n  (s: Armada.State.t)\n  : Lemma (requires positions_valid_in_state s)\n          (ensures  states_match_except_global_variables vs equality_pc_relation s s) =\n  introduce forall tid. stacks_match_per_pc_relation equality_pc_relation (s.threads tid).stack (s.threads tid).stack\n  with equality_pc_relation_implies_stack_matches_itself (s.threads tid).stack;\n  assert (threads_match_except_write_buffers_per_pc_relation equality_pc_relation s.threads s.threads);\n  introduce forall sender_tid receiver_tid.\n              sender_receiver_trigger sender_tid receiver_tid ==>\n              write_buffers_match_except_global_variables vs\n                (unread_write_buffer s.threads sender_tid receiver_tid)\n                (unread_write_buffer s.threads sender_tid receiver_tid)\n  with introduce _ ==> _\n  with _.\n    equality_pc_relation_implies_write_buffer_matches_itself\n      (remove_global_variables_from_write_buffer vs\n        (seq_to_list (unread_write_buffer s.threads sender_tid receiver_tid)))\n\n#push-options \"--z3rlimit 60\"\n\nlet update_expression_lacking_pointer_field_maintains_states_match\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (exp: expression_t)\n  (actor: tid_t)\n  (writer_pc1: pc_t)\n  (writer_pc2: pc_t)\n  (writer_expression_number1: nat)\n  (writer_expression_number2: nat)\n  (bypassing_write_buffer: bool)\n  (new_value: object_value_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   states_match_except_global_variables vs pc_relation s1 s2\n                    /\\ global_variables_unaddressed_in_memory vs s1.mem\n                    /\\ global_variables_unaddressed_in_memory vs s2.mem\n                    /\\ roots_match s1.mem\n                    /\\ roots_match s2.mem\n                    /\\ ThreadStatusRunning? (s1.threads actor).status\n                    /\\ global_variables_unmentioned_in_expression vs exp\n                    /\\ object_td_lacks_pointer_field (expression_to_td exp))\n          (ensures  (match update_expression exp actor writer_pc1 writer_expression_number1\n                             bypassing_write_buffer new_value s1,\n                           update_expression exp actor writer_pc2 writer_expression_number2\n                             bypassing_write_buffer new_value s2 with\n                     | ComputationProduces s1', ComputationProduces s2' ->\n                           states_match_except_global_variables vs pc_relation s1' s2'\n                         /\\ global_variables_unaddressed_in_memory vs s1'.mem\n                         /\\ global_variables_unaddressed_in_memory vs s2'.mem\n                         /\\ roots_match s1'.mem\n                         /\\ roots_match s2'.mem\n                     | ComputationImpossible, ComputationImpossible -> True\n                     | ComputationUndefined, ComputationUndefined -> True\n                     | _ -> False)) =\n  if   not (expression_valid exp)\n     || not (object_value_valid new_value)\n     || neqb (object_value_to_td new_value) (expression_to_td exp) then\n    ()\n  else (\n    lvalue_computation_doesnt_depend_on_global_variables vs pc_relation exp actor s1 s2;\n    assert (lvalue_computation exp actor s1 == lvalue_computation exp actor s2);\n    let td = expression_to_td exp in\n    match lvalue_computation exp actor s1 with\n    | ComputationProduces p ->\n        update_pointed_to_value_lacking_pointer_field_maintains_states_match vs pc_relation p actor\n          writer_pc1 writer_pc2 writer_expression_number1 writer_expression_number2 bypassing_write_buffer\n          td new_value s1 s2;\n        (match update_pointed_to_value p actor writer_pc1 writer_expression_number1 bypassing_write_buffer\n                 new_value s1,\n               update_pointed_to_value p actor writer_pc2 writer_expression_number2 bypassing_write_buffer\n                 new_value s2 with\n         | ComputationProduces s1', ComputationProduces s2' -> ()\n         | ComputationImpossible, ComputationImpossible -> ()\n         | ComputationUndefined, ComputationUndefined -> ()\n         | _, _ -> false_elim ())\n    | _ -> ()\n  )\n\n#pop-options\n#push-options \"--z3rlimit 80\"\n\nlet update_expression_with_gvars_unaddressed_maintains_states_match\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (exp: expression_t)\n  (actor: tid_t)\n  (writer_pc1: pc_t)\n  (writer_pc2: pc_t)\n  (writer_expression_number1: nat)\n  (writer_expression_number2: nat)\n  (bypassing_write_buffer: bool)\n  (new_value: object_value_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   states_match_except_global_variables vs pc_relation s1 s2\n                    /\\ global_variables_unaddressed_in_memory vs s1.mem\n                    /\\ global_variables_unaddressed_in_memory vs s2.mem\n                    /\\ roots_match s1.mem\n                    /\\ roots_match s2.mem\n                    /\\ ThreadStatusRunning? (s1.threads actor).status\n                    /\\ global_variables_unmentioned_in_expression vs exp\n                    /\\ global_variables_unaddressed_in_object_value vs new_value)\n          (ensures  (match update_expression exp actor writer_pc1 writer_expression_number1\n                             bypassing_write_buffer new_value s1,\n                           update_expression exp actor writer_pc2 writer_expression_number2\n                             bypassing_write_buffer new_value s2 with\n                     | ComputationProduces s1', ComputationProduces s2' ->\n                           states_match_except_global_variables vs pc_relation s1' s2'\n                         /\\ global_variables_unaddressed_in_memory vs s1'.mem\n                         /\\ global_variables_unaddressed_in_memory vs s2'.mem\n                         /\\ roots_match s1'.mem\n                         /\\ roots_match s2'.mem\n                     | ComputationImpossible, ComputationImpossible -> True\n                     | ComputationUndefined, ComputationUndefined -> True\n                     | _ -> False)) =\n  if   not (expression_valid exp)\n     || not (object_value_valid new_value)\n     || neqb (object_value_to_td new_value) (expression_to_td exp) then\n    ()\n  else (\n    lvalue_computation_doesnt_depend_on_global_variables vs pc_relation exp actor s1 s2;\n    assert (lvalue_computation exp actor s1 == lvalue_computation exp actor s2);\n    let td = expression_to_td exp in\n    match lvalue_computation exp actor s1 with\n    | ComputationProduces p ->\n        update_pointed_to_value_with_gvars_unaddressed_maintains_states_match vs pc_relation\n          p actor writer_pc1 writer_pc2 writer_expression_number1 writer_expression_number2 bypassing_write_buffer\n          new_value s1 s2;\n        (match update_pointed_to_value p actor writer_pc1 writer_expression_number1 bypassing_write_buffer\n                 new_value s1,\n               update_pointed_to_value p actor writer_pc2 writer_expression_number2 bypassing_write_buffer\n                 new_value s2 with\n         | ComputationProduces s1', ComputationProduces s2' -> ()\n         | ComputationImpossible, ComputationImpossible -> ()\n         | ComputationUndefined, ComputationUndefined -> ()\n         | _, _ -> false_elim ())\n    | _ -> ()\n  )\n\n#pop-options\n#push-options \"--z3rlimit 10\"\n\nlet rec update_expressions_with_gvars_unaddressed_maintains_states_match\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (exps: list expression_t)\n  (actor: tid_t)\n  (writer_pc1: pc_t)\n  (writer_pc2: pc_t)\n  (writer_expression_number1: nat)\n  (writer_expression_number2: nat)\n  (bypassing_write_buffer: bool)\n  (new_values: list object_value_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   states_match_except_global_variables vs pc_relation s1 s2\n                    /\\ global_variables_unaddressed_in_memory vs s1.mem\n                    /\\ global_variables_unaddressed_in_memory vs s2.mem\n                    /\\ roots_match s1.mem\n                    /\\ roots_match s2.mem\n                    /\\ ThreadStatusRunning? (s1.threads actor).status\n                    /\\ global_variables_unmentioned_in_expressions vs exps\n                    /\\ global_variables_unaddressed_in_object_values vs new_values)\n          (ensures  (match update_expressions exps actor writer_pc1 writer_expression_number1\n                             bypassing_write_buffer new_values s1,\n                           update_expressions exps actor writer_pc2 writer_expression_number2\n                             bypassing_write_buffer new_values s2 with\n                     | ComputationProduces s1', ComputationProduces s2' ->\n                            states_match_except_global_variables vs pc_relation s1' s2'\n                         /\\ global_variables_unaddressed_in_memory vs s1'.mem\n                         /\\ global_variables_unaddressed_in_memory vs s2'.mem\n                         /\\ roots_match s1'.mem\n                         /\\ roots_match s2'.mem\n                     | ComputationImpossible, ComputationImpossible -> True\n                     | ComputationUndefined, ComputationUndefined -> True\n                     | _ -> False)) =\n  match exps, new_values with\n  | [], [] -> ()\n  | first_exp :: remaining_exps, first_new_value :: remaining_new_values ->\n      update_expression_with_gvars_unaddressed_maintains_states_match vs pc_relation\n        first_exp actor writer_pc1 writer_pc2 writer_expression_number1 writer_expression_number2\n        bypassing_write_buffer first_new_value s1 s2;\n      (match update_expression first_exp actor writer_pc1 writer_expression_number1\n               bypassing_write_buffer first_new_value s1,\n             update_expression first_exp actor writer_pc2 writer_expression_number2\n               bypassing_write_buffer first_new_value s2 with\n       | ComputationProduces s1_next, ComputationProduces s2_next ->\n           update_expressions_with_gvars_unaddressed_maintains_states_match vs pc_relation\n             remaining_exps actor writer_pc1 writer_pc2 (writer_expression_number1 + 1) (writer_expression_number2 + 1)\n             bypassing_write_buffer remaining_new_values s1_next s2_next;\n           (match update_expressions exps actor writer_pc1 writer_expression_number1\n                    bypassing_write_buffer new_values s1,\n                  update_expressions exps actor writer_pc2 writer_expression_number2\n                    bypassing_write_buffer new_values s2 with\n            | ComputationProduces s1', ComputationProduces s2' -> ()\n            | ComputationImpossible, ComputationImpossible -> ()\n            | ComputationUndefined, ComputationUndefined -> ()\n            | _, _ -> ())\n       | ComputationImpossible, ComputationImpossible -> ()\n       | ComputationUndefined, ComputationUndefined -> ()\n       | _, _ -> ())\n  | _, _ -> ()\n\nlet rec update_expressions_lacking_pointer_field_maintains_states_match\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (exps: list expression_t)\n  (actor: tid_t)\n  (writer_pc1: pc_t)\n  (writer_pc2: pc_t)\n  (writer_expression_number1: nat)\n  (writer_expression_number2: nat)\n  (bypassing_write_buffer: bool)\n  (new_values: list object_value_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   states_match_except_global_variables vs pc_relation s1 s2\n                    /\\ global_variables_unaddressed_in_memory vs s1.mem\n                    /\\ global_variables_unaddressed_in_memory vs s2.mem\n                    /\\ roots_match s1.mem\n                    /\\ roots_match s2.mem\n                    /\\ ThreadStatusRunning? (s1.threads actor).status\n                    /\\ global_variables_unmentioned_in_expressions vs exps\n                    /\\ expressions_lack_pointer_field exps)\n          (ensures  (match update_expressions exps actor writer_pc1 writer_expression_number1\n                             bypassing_write_buffer new_values s1,\n                           update_expressions exps actor writer_pc2 writer_expression_number2\n                             bypassing_write_buffer new_values s2 with\n                     | ComputationProduces s1', ComputationProduces s2' ->\n                           states_match_except_global_variables vs pc_relation s1' s2'\n                         /\\ global_variables_unaddressed_in_memory vs s1'.mem\n                         /\\ global_variables_unaddressed_in_memory vs s2'.mem\n                         /\\ roots_match s1'.mem\n                         /\\ roots_match s2'.mem\n                         /\\ ThreadStatusRunning? (s1'.threads actor).status\n                     | ComputationImpossible, ComputationImpossible -> True\n                     | ComputationUndefined, ComputationUndefined -> True\n                     | _ -> False)) =\n  match exps, new_values with\n  | [], [] -> ()\n  | first_exp :: remaining_exps, first_new_value :: remaining_new_values ->\n      update_expression_lacking_pointer_field_maintains_states_match vs pc_relation\n        first_exp actor writer_pc1 writer_pc2 writer_expression_number1 writer_expression_number2\n        bypassing_write_buffer first_new_value s1 s2;\n      (match update_expression first_exp actor writer_pc1 writer_expression_number1\n               bypassing_write_buffer first_new_value s1,\n             update_expression first_exp actor writer_pc2 writer_expression_number2\n               bypassing_write_buffer first_new_value s2 with\n       | ComputationProduces s1_next, ComputationProduces s2_next ->\n           update_expressions_lacking_pointer_field_maintains_states_match vs pc_relation\n             remaining_exps actor writer_pc1 writer_pc2 (writer_expression_number1 + 1) (writer_expression_number2 + 1)\n             bypassing_write_buffer remaining_new_values s1_next s2_next;\n           (match update_expressions exps actor writer_pc1 writer_expression_number1\n                    bypassing_write_buffer new_values s1,\n                  update_expressions exps actor writer_pc2 writer_expression_number2\n                    bypassing_write_buffer new_values s2 with\n            | ComputationProduces s1', ComputationProduces s2' -> ()\n            | ComputationImpossible, ComputationImpossible -> ()\n            | ComputationUndefined, ComputationUndefined -> ()\n            | _, _ -> ())\n       | ComputationImpossible, ComputationImpossible -> ()\n       | ComputationUndefined, ComputationUndefined -> ()\n       | _, _ -> ())\n  | _, _ -> ()\n\nlet propagate_write_message_maintains_states_match\n  (vs: list var_id_t)\n  (write_message1: write_message_t)\n  (write_message2: write_message_t)\n  (receiver_tid: tid_t)\n  (mem1: Armada.Memory.t)\n  (mem2: Armada.Memory.t)\n  : Lemma (requires   memories_match_except_global_variables vs mem1 mem2\n                    /\\ global_variables_unaddressed_in_memory vs mem1\n                    /\\ global_variables_unaddressed_in_memory vs mem2\n                    /\\ roots_match mem1\n                    /\\ roots_match mem2\n                    /\\ global_variables_unaddressed_in_write_message vs write_message1\n                    /\\ global_variables_unaddressed_in_write_message vs write_message2\n                    /\\ write_messages_match write_message1 write_message2)\n          (ensures  (match propagate_write_message write_message1 receiver_tid mem1,\n                           propagate_write_message write_message2 receiver_tid mem2 with\n                     | ComputationProduces mem1', ComputationProduces mem2' ->\n                           memories_match_except_global_variables vs mem1' mem2'\n                         /\\ global_variables_unaddressed_in_memory vs mem1'\n                         /\\ global_variables_unaddressed_in_memory vs mem2'\n                         /\\ roots_match mem1'\n                         /\\ roots_match mem2'\n                     | ComputationImpossible, ComputationImpossible -> True\n                     | ComputationUndefined, ComputationUndefined -> True\n                     | _ -> False)) =\n  let p = write_message1.location in\n  dereference_computation_doesnt_depend_on_global_variables vs p mem1 mem2;\n  match dereference_computation p mem1 with\n  | ComputationProduces storage ->\n      (match storage with\n       | ObjectStorageWeaklyConsistentPrimitive primitive_td values local_versions ->\n           if   primitive_td <> write_message1.primitive_td\n              || write_message1.version >= length values\n              || local_versions receiver_tid >= write_message1.version then\n             ()\n           else\n             let new_local_versions = Spec.Map.upd local_versions receiver_tid write_message1.version in\n             let new_storage = ObjectStorageWeaklyConsistentPrimitive primitive_td values\n                                 new_local_versions in\n             if not (object_storage_valid new_storage) then\n               ()\n             else\n               update_pointer_directly_with_gvars_unaddressed_maintains_states_match vs p\n                 new_storage mem1 mem2\n       | _ -> ()\n     )\n  | _ -> ()\n\nlet propagate_write_message_s1_only_among_gvars_maintains_states_match\n  (vs: list var_id_t)\n  (write_message1: write_message_t)\n  (receiver_tid: tid_t)\n  (mem1: Armada.Memory.t)\n  (mem2: Armada.Memory.t)\n  : Lemma (requires   memories_match_except_global_variables vs mem1 mem2\n                    /\\ global_variables_unaddressed_in_memory vs mem1\n                    /\\ global_variables_unaddressed_in_memory vs mem2\n                    /\\ roots_match mem1\n                    /\\ roots_match mem2\n                    /\\ not (global_variables_unaddressed_in_write_message vs write_message1))\n          (ensures  (match propagate_write_message write_message1 receiver_tid mem1 with\n                     | ComputationProduces mem1' ->\n                           memories_match_except_global_variables vs mem1' mem2\n                         /\\ global_variables_unaddressed_in_memory vs mem1'\n                         /\\ roots_match mem1'\n                     | ComputationImpossible -> True\n                     | ComputationUndefined -> True)) =\n  let p = write_message1.location in\n  dereference_computation_when_gvars_unaddressed_produces_storage_with_gvars_unaddressed vs p mem1;\n  match dereference_computation p mem1 with\n  | ComputationProduces storage ->\n      (match storage with\n       | ObjectStorageWeaklyConsistentPrimitive primitive_td values local_versions ->\n           if   primitive_td <> write_message1.primitive_td\n              || write_message1.version >= length values\n              || local_versions receiver_tid >= write_message1.version then\n             ()\n           else (\n             let new_local_versions = Spec.Map.upd local_versions receiver_tid write_message1.version in\n             let new_storage = ObjectStorageWeaklyConsistentPrimitive primitive_td values\n                                 new_local_versions in\n             assert (global_variables_unaddressed_in_storage vs new_storage);\n             if not (object_storage_valid new_storage) then\n               ()\n             else\n               update_pointer_directly_s1_only_among_gvars_maintains_states_match vs p new_storage mem1 mem2\n           )\n       | _ -> ()\n     )\n  | _ -> ()\n\nlet propagate_write_message_s2_only_among_gvars_maintains_states_match\n  (vs: list var_id_t)\n  (write_message2: write_message_t)\n  (receiver_tid: tid_t)\n  (mem1: Armada.Memory.t)\n  (mem2: Armada.Memory.t)\n  : Lemma (requires   memories_match_except_global_variables vs mem1 mem2\n                    /\\ global_variables_unaddressed_in_memory vs mem1\n                    /\\ global_variables_unaddressed_in_memory vs mem2\n                    /\\ roots_match mem1\n                    /\\ roots_match mem2\n                    /\\ not (global_variables_unaddressed_in_write_message vs write_message2))\n          (ensures  (match propagate_write_message write_message2 receiver_tid mem2 with\n                     | ComputationProduces mem2' ->\n                           memories_match_except_global_variables vs mem1 mem2'\n                         /\\ global_variables_unaddressed_in_memory vs mem2'\n                         /\\ roots_match mem2'\n                     | ComputationImpossible -> True\n                     | ComputationUndefined -> True)) =\n  let p = write_message2.location in\n  dereference_computation_when_gvars_unaddressed_produces_storage_with_gvars_unaddressed vs p mem2;\n  match dereference_computation p mem2 with\n  | ComputationProduces storage ->\n      (match storage with\n       | ObjectStorageWeaklyConsistentPrimitive primitive_td values local_versions ->\n           if   primitive_td <> write_message2.primitive_td\n              || write_message2.version >= length values\n              || local_versions receiver_tid >= write_message2.version then\n             ()\n           else (\n             let new_local_versions = Spec.Map.upd local_versions receiver_tid write_message2.version in\n             let new_storage = ObjectStorageWeaklyConsistentPrimitive primitive_td values\n                                 new_local_versions in\n             assert (global_variables_unaddressed_in_storage vs new_storage);\n             if not (object_storage_valid new_storage) then\n               ()\n             else\n               update_pointer_directly_s2_only_among_gvars_maintains_states_match vs p new_storage mem1 mem2\n           )\n       | _ -> ()\n     )\n  | _ -> ()\n\nlet check_expression_up_to_date_for_rmw_doesnt_depend_on_gvars\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (exp: expression_t)\n  (actor: tid_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   states_match_except_global_variables vs pc_relation s1 s2\n                    /\\ global_variables_unaddressed_in_memory vs s1.mem\n                    /\\ global_variables_unaddressed_in_memory vs s2.mem\n                    /\\ roots_match s1.mem\n                    /\\ roots_match s2.mem\n                    /\\ ThreadStatusRunning? (s1.threads actor).status\n                    /\\ global_variables_unmentioned_in_expression vs exp)\n          (ensures  check_expression_up_to_date_for_rmw exp actor s1 ==\n                    check_expression_up_to_date_for_rmw exp actor s2) =\n  if not (expression_valid exp) then\n    ()\n  else (\n    lvalue_computation_doesnt_depend_on_global_variables vs pc_relation exp actor s1 s2;\n    match lvalue_computation exp actor s1 with\n    | ComputationProduces p -> dereference_computation_doesnt_depend_on_global_variables vs p s1.mem s2.mem\n    | _ -> ()\n  )\n\nlet rec if_object_value_has_all_pointers_uninitialized_then_it_doesnt_depend_on_gvars\n  (vs: list var_id_t)\n  (value: object_value_t)\n  : Lemma (requires object_value_has_all_pointers_uninitialized value)\n          (ensures  global_variables_unaddressed_in_object_value vs value)\n          (decreases rank value) =\n  match value with\n  | ObjectValuePrimitive primitive_value -> ()\n  | ObjectValueStruct fields ->\n      assert (forall field. contains fields field ==> rank field << rank fields);\n      introduce forall field. contains fields field ==> global_variables_unaddressed_in_object_value vs field\n      with introduce _ ==> _\n      with _. if_object_value_has_all_pointers_uninitialized_then_it_doesnt_depend_on_gvars vs field\n  | ObjectValueArray element_td elements ->\n      assert (forall element. contains elements element ==> rank element << rank elements);\n      introduce forall element. contains elements element ==> global_variables_unaddressed_in_object_value vs element\n      with introduce _ ==> _\n      with _. if_object_value_has_all_pointers_uninitialized_then_it_doesnt_depend_on_gvars vs element\n  | ObjectValueAbstract ty value -> ()\n\nlet rec object_storage_arbitrarily_initialized_correctly_doesnt_depend_on_gvars\n  (vs: list var_id_t)\n  (storage: object_storage_t)\n  : Lemma (requires object_storage_arbitrarily_initialized_correctly storage)\n          (ensures  global_variables_unaddressed_in_storage vs storage)\n          (decreases rank storage) =\n  match storage with\n  | ObjectStorageWeaklyConsistentPrimitive _ values local_versions -> ()\n  | ObjectStoragePrimitive primitive_value -> ()\n  | ObjectStorageStruct fields ->\n      assert (forall field. contains fields field ==> rank field << rank fields);\n      introduce forall field. contains fields field ==> global_variables_unaddressed_in_storage vs field\n      with introduce _ ==> _\n      with _. object_storage_arbitrarily_initialized_correctly_doesnt_depend_on_gvars vs field\n  | ObjectStorageArray element_td elements ->\n      assert (forall element. contains elements element ==> rank element << rank elements);\n      introduce forall element. contains elements element ==> global_variables_unaddressed_in_storage vs element\n      with introduce _ ==> _\n      with _. object_storage_arbitrarily_initialized_correctly_doesnt_depend_on_gvars vs element\n  | ObjectStorageAbstract ty value -> ()\n\nlet rec object_storage_zero_filled_doesnt_depend_on_gvars\n  (vs: list var_id_t)\n  (storage: object_storage_t)\n  : Lemma (requires is_storage_zero_filled storage)\n          (ensures  global_variables_unaddressed_in_storage vs storage)\n          (decreases rank storage) =\n  match storage with\n  | ObjectStorageWeaklyConsistentPrimitive _ values local_versions -> ()\n  | ObjectStoragePrimitive primitive_value -> ()\n  | ObjectStorageStruct fields ->\n      assert (forall field. contains fields field ==> rank field << rank fields);\n      introduce forall field. contains fields field ==> global_variables_unaddressed_in_storage vs field\n      with introduce _ ==> _\n      with _. object_storage_zero_filled_doesnt_depend_on_gvars vs field\n  | ObjectStorageArray element_td elements ->\n      assert (forall element. contains elements element ==> rank element << rank elements);\n      introduce forall element. contains elements element ==> global_variables_unaddressed_in_storage vs element\n      with introduce _ ==> _\n      with _. object_storage_zero_filled_doesnt_depend_on_gvars vs element\n  | ObjectStorageAbstract ty value -> ()\n\nlet rec object_storage_initialized_correctly_doesnt_depend_on_gvars\n  (vs: list var_id_t)\n  (storage: object_storage_t)\n  (value: object_value_t)\n  : Lemma (requires   global_variables_unaddressed_in_object_value vs value\n                    /\\ object_storage_initialized_correctly storage value)\n          (ensures  global_variables_unaddressed_in_storage vs storage) =\n  match storage with\n  | ObjectStorageWeaklyConsistentPrimitive _ values local_versions -> ()\n  | ObjectStoragePrimitive value -> ()\n  | ObjectStorageStruct fields ->\n      global_variables_unaddressed_in_storages_equivalent_to_forall vs fields;\n      introduce forall field. contains fields field ==> global_variables_unaddressed_in_storage vs field\n      with introduce _ ==> _\n      with _. (\n        let i = seq_contains_to_index fields field in\n        let field_values = ObjectValueStruct?.fields value in\n        let field_value = index field_values i in\n        assert (rank field << rank fields);\n        object_storage_initialized_correctly_doesnt_depend_on_gvars vs field field_value\n      )\n  | ObjectStorageArray element_td elements ->\n      global_variables_unaddressed_in_storages_equivalent_to_forall vs elements;\n      introduce forall element. contains elements element ==> global_variables_unaddressed_in_storage vs element\n      with introduce _ ==> _\n      with _. (\n        let i = seq_contains_to_index elements element in\n        let element_values = ObjectValueArray?.elements value in\n        let element_value = index element_values i in\n        assert (rank element << rank elements);\n        object_storage_initialized_correctly_doesnt_depend_on_gvars vs element element_value\n      )\n  | ObjectStorageAbstract ty value -> ()\n\n#pop-options\n#push-options \"--z3rlimit 40\"\n\nlet push_stack_variable_doesnt_depend_on_gvars_helper\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (writer_pc1: pc_t)\n  (writer_pc2: pc_t)\n  (writer_expression_number1: nat)\n  (writer_expression_number2: nat)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (initializer: initializer_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  (thread1: Armada.Thread.t)\n  (thread2: Armada.Thread.t)\n  (local_variables1': list var_id_t)\n  (local_variables2': list var_id_t)\n  (top1': stack_frame_t)\n  (top2': stack_frame_t)\n  (thread1': Armada.Thread.t)\n  (thread2': Armada.Thread.t)\n  (threads1': Armada.Threads.t)\n  (threads2': Armada.Threads.t)\n  : Lemma (requires   positions_valid_in_state s1\n                    /\\ positions_valid_in_state s2\n                    /\\ positions_in_write_buffers_match_except_global_variables vs s1.threads s2.threads\n                    /\\ thread1 == s1.threads actor\n                    /\\ thread2 == s2.threads actor\n                    /\\ local_variables1' == initializer.var_id :: thread1.top.local_variables\n                    /\\ local_variables2' == initializer.var_id :: thread2.top.local_variables\n                    /\\ top1' == { thread1.top with local_variables = local_variables1' }\n                    /\\ top2' == { thread2.top with local_variables = local_variables2' }\n                    /\\ thread1' == { thread1 with top = top1' }\n                    /\\ thread2' == { thread2 with top = top2' }\n                    /\\ threads1' == Spec.Map.upd s1.threads actor thread1'\n                    /\\ threads2' == Spec.Map.upd s2.threads actor thread2'\n                    /\\ positions_valid_in_threads threads1'\n                    /\\ positions_valid_in_threads threads2')\n          (ensures  positions_in_write_buffers_match_except_global_variables vs threads1' threads2') =\n  introduce forall sender_tid receiver_tid. write_buffers_match_except_global_variables vs\n                                         (unread_write_buffer threads1' sender_tid receiver_tid)\n                                         (unread_write_buffer threads2' sender_tid receiver_tid)\n  with (\n    assert (sender_receiver_trigger sender_tid receiver_tid);\n    assert (write_buffers_match_except_global_variables vs\n               (unread_write_buffer s1.threads sender_tid receiver_tid)\n               (unread_write_buffer s2.threads sender_tid receiver_tid));\n    assert (unread_write_buffer threads1' sender_tid receiver_tid ==\n              unread_write_buffer s1.threads sender_tid receiver_tid);\n    assert (unread_write_buffer threads2' sender_tid receiver_tid ==\n              unread_write_buffer s2.threads sender_tid receiver_tid)\n  );\n  assert (positions_in_write_buffers_match_except_global_variables vs threads1' threads2')\n\nlet push_stack_variable_doesnt_depend_on_gvars\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (writer_pc1: pc_t)\n  (writer_pc2: pc_t)\n  (writer_expression_number1: nat)\n  (writer_expression_number2: nat)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (initializer: initializer_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   states_match_except_global_variables vs pc_relation s1 s2\n                    /\\ global_variables_unaddressed_in_memory vs s1.mem\n                    /\\ global_variables_unaddressed_in_memory vs s2.mem\n                    /\\ roots_match s1.mem\n                    /\\ roots_match s2.mem\n                    /\\ ThreadStatusRunning? (s1.threads actor).status\n                    /\\ global_variables_unaddressed_in_initializer vs initializer)\n          (ensures  (match push_stack_variable actor writer_pc1 writer_expression_number1 method_id frame_uniq\n                             initializer s1,\n                           push_stack_variable actor writer_pc2 writer_expression_number2 method_id frame_uniq\n                             initializer s2 with\n                     | ComputationProduces s1', ComputationProduces s2' ->\n                           states_match_except_global_variables vs pc_relation s1' s2'\n                         /\\ global_variables_unaddressed_in_memory vs s1'.mem\n                         /\\ global_variables_unaddressed_in_memory vs s2'.mem\n                         /\\ roots_match s1'.mem\n                         /\\ roots_match s2'.mem\n                         /\\ ThreadStatusRunning? (s1'.threads actor).status\n                     | ComputationImpossible, ComputationImpossible -> True\n                     | ComputationUndefined, ComputationUndefined -> True\n                     | _, _ -> False)) =\n  let root_id = RootIdStack actor method_id frame_uniq initializer.var_id in\n  let root = s1.mem root_id in\n  assert (root == s2.mem root_id);\n  if not (stack_variable_ready_for_push root initializer) then\n    ()\n  else (\n    object_storage_arbitrarily_initialized_correctly_doesnt_depend_on_gvars vs (RootStackVariable?.storage root);\n    let thread1 = s1.threads actor in\n    let thread2 = s2.threads actor in\n    let var_id = initializer.var_id in\n    if list_contains var_id thread1.top.local_variables then\n      ()\n    else (\n      let local_variables1' = var_id :: thread1.top.local_variables in\n      let local_variables2' = var_id :: thread2.top.local_variables in\n      let top1' = { thread1.top with local_variables = local_variables1' } in\n      let top2' = { thread2.top with local_variables = local_variables2' } in\n      let thread1' = { thread1 with top = top1' } in\n      let thread2' = { thread2 with top = top2' } in\n      let threads1' = Spec.Map.upd s1.threads actor thread1' in\n      let threads2' = Spec.Map.upd s2.threads actor thread2' in\n      let root' = RootStackVariable true false (RootStackVariable?.storage root) in\n      let mem1' = Spec.Map.upd s1.mem root_id root' in\n      let mem2' = Spec.Map.upd s2.mem root_id root' in\n      let s1' = { s1 with mem = mem1'; threads = threads1' } in\n      let s2' = { s2 with mem = mem2'; threads = threads2' } in\n      push_stack_variable_doesnt_depend_on_gvars_helper vs actor writer_pc1 writer_pc2\n        writer_expression_number1 writer_expression_number2\n        method_id frame_uniq initializer s1 s2 thread1 thread2 local_variables1' local_variables2' top1'\n        top2' thread1' thread2' threads1' threads2';\n      assert (threads_match_except_global_variables vs pc_relation s1'.threads s2'.threads);\n      assert (states_match_except_global_variables vs pc_relation s1' s2');\n      assert (roots_match s1'.mem);\n      assert (roots_match s2'.mem);\n      (match initializer.iv with\n       | InitializerArbitrary td -> ()\n       | InitializerSpecific value ->\n           let td = (object_value_to_td value) in\n           update_expression_with_gvars_unaddressed_maintains_states_match vs pc_relation\n             (ExpressionLocalVariable td var_id) actor writer_pc1 writer_pc2\n             writer_expression_number1 writer_expression_number2 false value s1' s2'\n      )\n    )\n  )\n\nlet rec push_stack_variables_doesnt_depend_on_gvars\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (writer_pc1: pc_t)\n  (writer_pc2: pc_t)\n  (writer_expression_number1: nat)\n  (writer_expression_number2: nat)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (initializers: list initializer_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   states_match_except_global_variables vs pc_relation s1 s2\n                    /\\ global_variables_unaddressed_in_memory vs s1.mem\n                    /\\ global_variables_unaddressed_in_memory vs s2.mem\n                    /\\ roots_match s1.mem\n                    /\\ roots_match s2.mem\n                    /\\ ThreadStatusRunning? (s1.threads actor).status\n                    /\\ global_variables_unaddressed_in_initializers vs initializers)\n          (ensures  (match push_stack_variables actor writer_pc1 writer_expression_number1 method_id frame_uniq\n                             initializers s1,\n                           push_stack_variables actor writer_pc2 writer_expression_number2 method_id frame_uniq\n                             initializers s2 with\n                     | ComputationProduces s1', ComputationProduces s2' ->\n                           states_match_except_global_variables vs pc_relation s1' s2'\n                         /\\ global_variables_unaddressed_in_memory vs s1'.mem\n                         /\\ global_variables_unaddressed_in_memory vs s2'.mem\n                         /\\ roots_match s1'.mem\n                         /\\ roots_match s2'.mem\n                         /\\ ThreadStatusRunning? (s1'.threads actor).status\n                     | ComputationImpossible, ComputationImpossible -> True\n                     | ComputationUndefined, ComputationUndefined -> True\n                     | _ -> False))\n          (decreases initializers) =\n  match initializers with\n  | [] -> ()\n  | first_initializer :: remaining_initializers ->\n      push_stack_variable_doesnt_depend_on_gvars vs pc_relation actor writer_pc1 writer_pc2\n        writer_expression_number1 writer_expression_number2 method_id frame_uniq first_initializer s1 s2;\n      (match push_stack_variable actor writer_pc1 writer_expression_number1 method_id frame_uniq\n               first_initializer s1,\n             push_stack_variable actor writer_pc2 writer_expression_number2 method_id frame_uniq\n               first_initializer s2 with\n       | ComputationProduces s1_next, ComputationProduces s2_next ->\n          push_stack_variables_doesnt_depend_on_gvars vs pc_relation actor writer_pc1 writer_pc2\n            (writer_expression_number1 + 1) (writer_expression_number2 + 1)\n            method_id frame_uniq remaining_initializers s1_next s2_next;\n          (match push_stack_variables actor writer_pc1 writer_expression_number1 method_id frame_uniq\n                   initializers s1,\n                 push_stack_variables actor writer_pc2 writer_expression_number2 method_id frame_uniq\n                   initializers s2 with\n           | ComputationProduces s1', ComputationProduces s2' ->\n               assert (states_match_except_global_variables vs pc_relation s1' s2');\n               assert (global_variables_unaddressed_in_memory vs s1'.mem);\n               assert (global_variables_unaddressed_in_memory vs s2'.mem);\n               assert (roots_match s1'.mem);\n               assert (roots_match s2'.mem)\n           | ComputationImpossible, ComputationImpossible -> ()\n           | ComputationUndefined, ComputationUndefined -> ()\n           | _ -> ())\n       | ComputationImpossible, ComputationImpossible -> ()\n       | ComputationUndefined, ComputationUndefined -> ()\n       | _, _ -> ())\n  | _ -> ()\n\nlet rec push_stack_parameters_doesnt_depend_on_gvars\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (writer_pc1: pc_t)\n  (writer_pc2: pc_t)\n  (writer_expression_number1: nat)\n  (writer_expression_number2: nat)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (var_ids: list var_id_t)\n  (parameters: list object_value_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   states_match_except_global_variables vs pc_relation s1 s2\n                    /\\ global_variables_unaddressed_in_memory vs s1.mem\n                    /\\ global_variables_unaddressed_in_memory vs s2.mem\n                    /\\ roots_match s1.mem\n                    /\\ roots_match s2.mem\n                    /\\ ThreadStatusRunning? (s1.threads actor).status\n                    /\\ global_variables_unaddressed_in_object_values vs parameters)\n          (ensures  (match push_stack_parameters actor writer_pc1 writer_expression_number1 method_id frame_uniq\n                             var_ids parameters s1,\n                           push_stack_parameters actor writer_pc2 writer_expression_number2 method_id frame_uniq\n                             var_ids parameters s2 with\n                     | ComputationProduces s1', ComputationProduces s2' ->\n                           states_match_except_global_variables vs pc_relation s1' s2'\n                         /\\ global_variables_unaddressed_in_memory vs s1'.mem\n                         /\\ global_variables_unaddressed_in_memory vs s2'.mem\n                         /\\ roots_match s1'.mem\n                         /\\ roots_match s2'.mem\n                         /\\ ThreadStatusRunning? (s1'.threads actor).status\n                     | ComputationImpossible, ComputationImpossible -> True\n                     | ComputationUndefined, ComputationUndefined -> True\n                     | _ -> False))\n          (decreases parameters) =\n  match parameters, var_ids with\n  | [], [] -> ()\n  | first_parameter :: remaining_parameters, first_var_id :: remaining_var_ids ->\n      let first_initializer = {\n        var_id = first_var_id;\n        iv = InitializerSpecific first_parameter;\n        weakly_consistent = false\n      } in\n      push_stack_variable_doesnt_depend_on_gvars vs pc_relation actor writer_pc1 writer_pc2\n        writer_expression_number1 writer_expression_number2 method_id frame_uniq first_initializer s1 s2;\n      (match push_stack_variable actor writer_pc1 writer_expression_number1 method_id frame_uniq\n               first_initializer s1,\n             push_stack_variable actor writer_pc2 writer_expression_number2 method_id frame_uniq\n               first_initializer s2 with\n       | ComputationProduces s1_next, ComputationProduces s2_next ->\n           push_stack_parameters_doesnt_depend_on_gvars vs pc_relation actor writer_pc1 writer_pc2\n             (writer_expression_number1 + 1) (writer_expression_number2 + 1)\n             method_id frame_uniq remaining_var_ids remaining_parameters s1_next s2_next;\n           (match push_stack_parameters actor writer_pc1 writer_expression_number1 method_id frame_uniq\n                    var_ids parameters s1,\n                  push_stack_parameters actor writer_pc2 writer_expression_number2 method_id frame_uniq\n                    var_ids parameters s2 with\n            | ComputationProduces s1', ComputationProduces s2' ->\n                assert (states_match_except_global_variables vs pc_relation s1' s2');\n                assert (global_variables_unaddressed_in_memory vs s1'.mem);\n                assert (global_variables_unaddressed_in_memory vs s2'.mem);\n                assert (roots_match s1'.mem);\n                assert (roots_match s2'.mem)\n            | ComputationImpossible, ComputationImpossible -> ()\n            | ComputationUndefined, ComputationUndefined -> ()\n            | _, _ -> ())\n       | ComputationImpossible, ComputationImpossible -> ()\n       | ComputationUndefined, ComputationUndefined -> ()\n       | _, _ -> ())\n  | _ -> ()\n\nlet pop_stack_variable_doesnt_depend_on_gvars\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (var_id: var_id_t)\n  (mem1: Armada.Memory.t)\n  (mem2: Armada.Memory.t)\n  : Lemma (requires   memories_match_except_global_variables vs mem1 mem2\n                    /\\ global_variables_unaddressed_in_memory vs mem1\n                    /\\ global_variables_unaddressed_in_memory vs mem2\n                    /\\ roots_match mem1\n                    /\\ roots_match mem2)\n          (ensures  (match pop_stack_variable actor method_id frame_uniq var_id mem1,\n                           pop_stack_variable actor method_id frame_uniq var_id mem2 with\n                     | ComputationProduces mem1', ComputationProduces mem2' ->\n                           memories_match_except_global_variables vs mem1' mem2'\n                         /\\ global_variables_unaddressed_in_memory vs mem1'\n                         /\\ global_variables_unaddressed_in_memory vs mem2'\n                         /\\ roots_match mem1'\n                         /\\ roots_match mem2'\n                     | ComputationImpossible, ComputationImpossible -> True\n                     | ComputationUndefined, ComputationUndefined -> True\n                     | _ -> False)) =\n  ()\n\nlet rec pop_stack_variables_doesnt_depend_on_gvars\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (var_ids: list var_id_t)\n  (mem1: Armada.Memory.t)\n  (mem2: Armada.Memory.t)\n  : Lemma (requires   memories_match_except_global_variables vs mem1 mem2\n                    /\\ global_variables_unaddressed_in_memory vs mem1\n                    /\\ global_variables_unaddressed_in_memory vs mem2\n                    /\\ roots_match mem1\n                    /\\ roots_match mem2)\n          (ensures  (match pop_stack_variables actor method_id frame_uniq var_ids mem1,\n                           pop_stack_variables actor method_id frame_uniq var_ids mem2 with\n                     | ComputationProduces mem1', ComputationProduces mem2' ->\n                           memories_match_except_global_variables vs mem1' mem2'\n                         /\\ global_variables_unaddressed_in_memory vs mem1'\n                         /\\ global_variables_unaddressed_in_memory vs mem2'\n                         /\\ roots_match mem1'\n                         /\\ roots_match mem2'\n                     | ComputationImpossible, ComputationImpossible -> True\n                     | ComputationUndefined, ComputationUndefined -> True\n                     | _ -> False)) =\n  match var_ids with\n  | [] -> ()\n  | first_var_id :: remaining_var_ids ->\n      pop_stack_variable_doesnt_depend_on_gvars vs actor method_id frame_uniq first_var_id mem1 mem2;\n      (match pop_stack_variable actor method_id frame_uniq first_var_id mem1,\n             pop_stack_variable actor method_id frame_uniq first_var_id mem2 with\n       | ComputationProduces mem1_next, ComputationProduces mem2_next ->\n           pop_stack_variables_doesnt_depend_on_gvars vs actor method_id frame_uniq remaining_var_ids\n             mem1_next mem2_next;\n           (match pop_stack_variables actor method_id frame_uniq remaining_var_ids mem1_next,\n                  pop_stack_variables actor method_id frame_uniq remaining_var_ids mem2_next with\n            | ComputationProduces mem1', ComputationProduces mem2' ->\n                assert (ComputationProduces mem1' == pop_stack_variables actor method_id frame_uniq var_ids mem1);\n                assert (ComputationProduces mem2' == pop_stack_variables actor method_id frame_uniq var_ids mem2);\n                assert (memories_match_except_global_variables vs mem1' mem2');\n                assert (global_variables_unaddressed_in_memory vs mem1');\n                assert (global_variables_unaddressed_in_memory vs mem2');\n                assert (roots_match mem1');\n                assert (roots_match mem2')\n            | ComputationImpossible, ComputationImpossible -> ()\n            | ComputationUndefined, ComputationUndefined -> ()\n            | _ -> ())\n       | ComputationImpossible, ComputationImpossible -> ()\n       | ComputationUndefined, ComputationUndefined -> ()\n       | _ -> ())\n  | _ -> ()\n\nlet free_pointer_doesnt_depend_on_gvars\n  (vs: list var_id_t)\n  (ptr_value: valid_object_value_t (ObjectTDPrimitive PrimitiveTDPointer))\n  (mem1: Armada.Memory.t)\n  (mem2: Armada.Memory.t)\n  : Lemma (requires   memories_match_except_global_variables vs mem1 mem2\n                    /\\ global_variables_unaddressed_in_memory vs mem1\n                    /\\ global_variables_unaddressed_in_memory vs mem2\n                    /\\ roots_match mem1\n                    /\\ roots_match mem2\n                    /\\ global_variables_unaddressed_in_object_value vs ptr_value)\n          (ensures  (let p = PrimitiveBoxPointer?.ptr (ObjectValuePrimitive?.value ptr_value) in\n                     match free_pointer p mem1, free_pointer p mem2 with\n                     | ComputationProduces mem1', ComputationProduces mem2' ->\n                           memories_match_except_global_variables vs mem1' mem2'\n                         /\\ global_variables_unaddressed_in_memory vs mem1'\n                         /\\ global_variables_unaddressed_in_memory vs mem2'\n                         /\\ roots_match mem1'\n                         /\\ roots_match mem2'\n                     | ComputationImpossible, ComputationImpossible -> True\n                     | ComputationUndefined, ComputationUndefined -> True\n                     | _ -> False)) =\n  let p = PrimitiveBoxPointer?.ptr (ObjectValuePrimitive?.value ptr_value) in\n  match p with\n  | PointerIndex (PointerRoot root_id) idx ->\n      if idx <> 0 then\n        ()\n      else\n        (match mem1 root_id with\n         | RootAllocated allocated freed storage ->\n             if not allocated || freed then\n               ()\n             else (\n               let root' = RootAllocated true true storage in\n               let mem1' = Spec.Map.upd mem1 root_id root' in\n               let mem2' = Spec.Map.upd mem2 root_id root' in\n               assert (memories_match_except_global_variables vs mem1' mem2');\n               assert (global_variables_unaddressed_in_memory vs mem1');\n               assert (global_variables_unaddressed_in_memory vs mem2')\n             )\n         | _ -> ())\n  | _ -> ()\n\nlet rec external_method_take_snapshot_of_reads_clauses_computation_doesnt_depend_on_gvars\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (writer_pc1: pc_t)\n  (writer_pc2: pc_t)\n  (writer_expression_number1: nat)\n  (writer_expression_number2: nat)\n  (bypassing_write_buffer: bool)\n  (reads_clauses: list (var_id_t * expression_t))\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   states_match_except_global_variables vs pc_relation s1 s2\n                    /\\ global_variables_unaddressed_in_memory vs s1.mem\n                    /\\ global_variables_unaddressed_in_memory vs s2.mem\n                    /\\ roots_match s1.mem\n                    /\\ roots_match s2.mem\n                    /\\ ThreadStatusRunning? (s1.threads actor).status\n                    /\\ global_variables_unmentioned_in_reads_clauses vs reads_clauses)\n          (ensures  (match external_method_take_snapshot_of_reads_clauses_computation actor writer_pc1\n                             writer_expression_number1 bypassing_write_buffer reads_clauses s1,\n                           external_method_take_snapshot_of_reads_clauses_computation actor writer_pc2\n                             writer_expression_number2 bypassing_write_buffer reads_clauses s2 with\n                     | ComputationProduces s1', ComputationProduces s2' ->\n                           states_match_except_global_variables vs pc_relation s1' s2'\n                         /\\ global_variables_unaddressed_in_memory vs s1'.mem\n                         /\\ global_variables_unaddressed_in_memory vs s2'.mem\n                         /\\ roots_match s1'.mem\n                         /\\ roots_match s2'.mem\n                     | ComputationImpossible, ComputationImpossible -> True\n                     | ComputationUndefined, ComputationUndefined -> True\n                     | _ -> False))\n          (decreases reads_clauses) =\n  match reads_clauses with\n  | [] -> ()\n  | (first_var_id, first_reads_expression) :: remaining_reads_clauses ->\n      rvalue_computation_doesnt_depend_on_global_variables vs pc_relation first_reads_expression actor s1 s2;\n      (match rvalue_computation first_reads_expression actor s1 with\n       | ComputationProduces first_value ->\n           let td = expression_to_td first_reads_expression in\n           let local_var = ExpressionLocalVariable td first_var_id in\n           update_expression_with_gvars_unaddressed_maintains_states_match vs pc_relation local_var actor\n             writer_pc1 writer_pc2 writer_expression_number1 writer_expression_number2\n             bypassing_write_buffer first_value s1 s2;\n           (match update_expression local_var actor writer_pc1 writer_expression_number1 bypassing_write_buffer\n                    first_value s1,\n                  update_expression local_var actor writer_pc2 writer_expression_number2 bypassing_write_buffer\n                    first_value s2 with\n            | ComputationProduces s1_next, ComputationProduces s2_next ->\n                external_method_take_snapshot_of_reads_clauses_computation_doesnt_depend_on_gvars vs pc_relation\n                  actor writer_pc1 writer_pc2 (writer_expression_number1 + 1) (writer_expression_number2 + 1)\n                  bypassing_write_buffer remaining_reads_clauses s1_next s2_next\n            | ComputationImpossible, ComputationImpossible -> ()\n            | ComputationUndefined, ComputationUndefined -> ()\n            | _ -> ())\n       | _ -> ())\n\nlet rec external_method_check_snapshot_computation_doesnt_depend_on_gvars\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (reads_clauses: list (var_id_t * expression_t))\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   states_match_except_global_variables vs pc_relation s1 s2\n                    /\\ global_variables_unaddressed_in_memory vs s1.mem\n                    /\\ global_variables_unaddressed_in_memory vs s2.mem\n                    /\\ roots_match s1.mem\n                    /\\ roots_match s2.mem\n                    /\\ ThreadStatusRunning? (s1.threads actor).status\n                    /\\ global_variables_unmentioned_in_reads_clauses vs reads_clauses)\n          (ensures  external_method_check_snapshot_computation actor reads_clauses s1 ==\n                    external_method_check_snapshot_computation actor reads_clauses s2)\n          (decreases reads_clauses) =\n  match reads_clauses with\n  | [] -> ()\n  | (first_var_id, first_reads_expression) :: remaining_reads_clauses ->\n      rvalue_computation_doesnt_depend_on_global_variables vs pc_relation first_reads_expression actor s1 s2;\n      (match rvalue_computation first_reads_expression actor s1 with\n       | ComputationProduces first_value ->\n           let td = expression_to_td first_reads_expression in\n           let local_var = ExpressionLocalVariable td first_var_id in\n           rvalue_computation_doesnt_depend_on_global_variables vs pc_relation local_var actor s1 s2;\n           (match rvalue_computation local_var actor s1 with\n            | ComputationProduces snapshot_value ->\n                if neqb first_value snapshot_value then\n                  ()\n                else\n                  external_method_check_snapshot_computation_doesnt_depend_on_gvars vs pc_relation\n                    actor remaining_reads_clauses s1 s2\n            | _ -> ())\n       | _ -> ())\n\nlet rec log_expressions_computation_doesnt_depend_on_gvars\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (logs_clauses: list expression_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   states_match_except_global_variables vs pc_relation s1 s2\n                    /\\ global_variables_unaddressed_in_memory vs s1.mem\n                    /\\ global_variables_unaddressed_in_memory vs s2.mem\n                    /\\ roots_match s1.mem\n                    /\\ roots_match s2.mem\n                    /\\ ThreadStatusRunning? (s1.threads actor).status\n                    /\\ global_variables_unmentioned_in_expressions vs logs_clauses)\n          (ensures  (match log_expressions_computation actor logs_clauses s1,\n                           log_expressions_computation actor logs_clauses s2 with\n                     | ComputationProduces s1', ComputationProduces s2' ->\n                           states_match_except_global_variables vs pc_relation s1' s2'\n                         /\\ global_variables_unaddressed_in_memory vs s1'.mem\n                         /\\ global_variables_unaddressed_in_memory vs s2'.mem\n                         /\\ roots_match s1'.mem\n                         /\\ roots_match s2'.mem\n                     | ComputationImpossible, ComputationImpossible -> True\n                     | ComputationUndefined, ComputationUndefined -> True\n                     | _ -> False))\n          (decreases logs_clauses) =\n  match logs_clauses with\n  | [] -> ()\n  | first_logs_clause :: remaining_logs_clauses ->\n      rvalue_computation_doesnt_depend_on_global_variables vs pc_relation first_logs_clause actor s1 s2;\n      (match rvalue_computation first_logs_clause actor s1 with\n       | ComputationProduces event ->\n           let trace1' = s1.trace $:: event in\n           let s1' = { s1 with trace = trace1' } in\n           let trace2' = s2.trace $:: event in\n           let s2' = { s2 with trace = trace2' } in\n           log_expressions_computation_doesnt_depend_on_gvars vs pc_relation actor remaining_logs_clauses s1' s2'\n       | _ -> ())\n\n#pop-options\n#push-options \"--z3rlimit 10\"\n\nlet make_thread_running_doesnt_depend_on_gvars\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (method_id: method_id_t)\n  (initial_pc1: pc_t)\n  (initial_pc2: pc_t)\n  (new_tid: tid_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   states_match_except_global_variables vs pc_relation s1 s2\n                    /\\ global_variables_unaddressed_in_memory vs s1.mem\n                    /\\ global_variables_unaddressed_in_memory vs s2.mem\n                    /\\ roots_match s1.mem\n                    /\\ roots_match s2.mem\n                    /\\ pc_relation.relation initial_pc1 initial_pc2)\n          (ensures  (let s1' = make_thread_running method_id initial_pc1 new_tid frame_uniq s1 in\n                     let s2' = make_thread_running method_id initial_pc2 new_tid frame_uniq s2 in\n                       states_match_except_global_variables vs pc_relation s1' s2'\n                     /\\ global_variables_unaddressed_in_memory vs s1'.mem\n                     /\\ global_variables_unaddressed_in_memory vs s2'.mem\n                     /\\ roots_match s1'.mem\n                     /\\ roots_match s2'.mem)) =\n  assert (stacks_match_per_pc_relation pc_relation [] [])\n\nlet push_stack_frame_doesnt_depend_on_gvars\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (method_id: method_id_t)\n  (return_pc1: pc_t)\n  (return_pc2: pc_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   states_match_except_global_variables vs pc_relation s1 s2\n                    /\\ global_variables_unaddressed_in_memory vs s1.mem\n                    /\\ global_variables_unaddressed_in_memory vs s2.mem\n                    /\\ roots_match s1.mem\n                    /\\ roots_match s2.mem\n                    /\\ ThreadStatusRunning? (s1.threads actor).status\n                    /\\ pc_relation.relation return_pc1 return_pc2\n                    /\\ pc_relation.return_relation return_pc1 return_pc2)\n          (ensures  (let s1' = push_stack_frame actor method_id return_pc1 frame_uniq s1 in\n                     let s2' = push_stack_frame actor method_id return_pc2 frame_uniq s2 in\n                       states_match_except_global_variables vs pc_relation s1' s2'\n                     /\\ global_variables_unaddressed_in_memory vs s1'.mem\n                     /\\ global_variables_unaddressed_in_memory vs s2'.mem\n                     /\\ roots_match s1'.mem\n                     /\\ roots_match s2'.mem)) =\n  let s1' = push_stack_frame actor method_id return_pc1 frame_uniq s1 in\n  let s2' = push_stack_frame actor method_id return_pc2 frame_uniq s2 in\n  assert (stacks_match_per_pc_relation pc_relation (s1'.threads actor).stack (s2'.threads actor).stack)\n\nlet pop_stack_frame_doesnt_depend_on_gvars\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (mem1': Armada.Memory.t)\n  (mem2': Armada.Memory.t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   Cons? (s1.threads actor).stack\n                    /\\ Cons? (s2.threads actor).stack\n                    /\\ states_match_except_global_variables vs pc_relation s1 s2\n                    /\\ memories_match_except_global_variables vs mem1' mem2'\n                    /\\ global_variables_unaddressed_in_memory vs mem1'\n                    /\\ global_variables_unaddressed_in_memory vs mem2'\n                    /\\ roots_match mem1'\n                    /\\ roots_match mem2')\n          (ensures  (let s1' = pop_stack_frame actor mem1' s1 in\n                     let s2' = pop_stack_frame actor mem2' s2 in\n                       states_match_except_global_variables vs pc_relation s1' s2'\n                     /\\ global_variables_unaddressed_in_memory vs s1'.mem\n                     /\\ global_variables_unaddressed_in_memory vs s2'.mem\n                     /\\ roots_match s1'.mem\n                     /\\ roots_match s2'.mem)) =\n  ()\n\nlet mark_allocation_root_allocated_doesnt_depend_on_gvars\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (uniq: root_id_uniquifier_t)\n  (storage: valid_object_storage_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   states_match_except_global_variables vs pc_relation s1 s2\n                    /\\ global_variables_unaddressed_in_memory vs s1.mem\n                    /\\ global_variables_unaddressed_in_memory vs s2.mem\n                    /\\ roots_match s1.mem\n                    /\\ roots_match s2.mem\n                    /\\ global_variables_unaddressed_in_storage vs storage)\n          (ensures  (let s1' = mark_allocation_root_allocated uniq storage s1 in\n                     let s2' = mark_allocation_root_allocated uniq storage s2 in\n                       states_match_except_global_variables vs pc_relation s1' s2'\n                     /\\ global_variables_unaddressed_in_memory vs s1'.mem\n                     /\\ global_variables_unaddressed_in_memory vs s2'.mem\n                     /\\ roots_match s1'.mem\n                     /\\ roots_match s2'.mem)) =\n  let s1' = mark_allocation_root_allocated uniq storage s1 in\n  let s2' = mark_allocation_root_allocated uniq storage s2 in\n  assert (states_match_except_global_variables vs pc_relation s1' s2');\n  assert (roots_match s1'.mem);\n  assert (roots_match s2'.mem)\n"
  },
  {
    "path": "experimental/lib/Strategies.GlobalVars.Value.fst",
    "content": "module Strategies.GlobalVars.Value\n\nopen Armada.Base\nopen Armada.BinaryOp\nopen Armada.Computation\nopen Armada.Expression\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Pointer\nopen Armada.State\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Type\nopen Armada.UnaryOp\nopen FStar.Sequence.Ambient\nopen FStar.Sequence.Base\nopen Spec.List\nopen Spec.Ubool\nopen Strategies.ArmadaInvariant.PositionsValid\nopen Strategies.ArmadaInvariant.RootsMatch\nopen Strategies.GlobalVars\nopen Strategies.GlobalVars.Unaddressed\nopen Strategies.PCRelation\nopen Util.List\nopen Util.Nth\nopen Util.Seq\nopen Util.Trigger\n\n#push-options \"--z3rlimit 30\"\n\nlet rec dereference_computation_doesnt_depend_on_global_variables\n  (vs: list var_id_t)\n  (p: Armada.Pointer.t)\n  (mem1: Armada.Memory.t)\n  (mem2: Armada.Memory.t)\n  : Lemma (requires   memories_match_except_global_variables vs mem1 mem2\n                    /\\ global_variables_unaddressed_in_pointer vs p\n                    /\\ global_variables_unaddressed_in_memory vs mem1\n                    /\\ global_variables_unaddressed_in_memory vs mem2\n                    /\\ roots_match mem1\n                    /\\ roots_match mem2)\n          (ensures  dereference_computation p mem1 == dereference_computation p mem2\n                    /\\ (match dereference_computation p mem1 with\n                       | ComputationProduces storage -> global_variables_unaddressed_in_storage vs storage\n                       | _ -> True)) =\n  match p with\n  | PointerUninitialized -> ()\n  | PointerNull -> ()\n  | PointerRoot root_id -> ()\n  | PointerField struct_ptr field_id ->\n      dereference_computation_doesnt_depend_on_global_variables vs struct_ptr mem1 mem2\n  | PointerIndex array_ptr idx ->\n      dereference_computation_doesnt_depend_on_global_variables vs array_ptr mem1 mem2\n\nlet dereference_as_td_computation_doesnt_depend_on_global_variables\n  (vs: list var_id_t)\n  (p: Armada.Pointer.t)\n  (td: object_td_t)\n  (actor: tid_t)\n  (mem1: Armada.Memory.t)\n  (mem2: Armada.Memory.t)\n  : Lemma (requires   memories_match_except_global_variables vs mem1 mem2\n                    /\\ global_variables_unaddressed_in_pointer vs p\n                    /\\ global_variables_unaddressed_in_memory vs mem1\n                    /\\ global_variables_unaddressed_in_memory vs mem2\n                    /\\ roots_match mem1\n                    /\\ roots_match mem2)\n          (ensures  dereference_as_td_computation p td actor mem1 == dereference_as_td_computation p td actor mem2\n                    /\\ (match dereference_as_td_computation p td actor mem1 with\n                       | ComputationProduces value -> global_variables_unaddressed_in_object_value vs value\n                       | _ -> True)) =\n  dereference_computation_doesnt_depend_on_global_variables vs p mem1 mem2;\n  match dereference_computation p mem1 with\n  | ComputationProduces storage ->\n      global_variables_unaddressed_in_storage_implies_unaddressed_in_object_value vs actor storage\n  | _ -> ()\n\n#pop-options\n#push-options \"--z3rlimit 80\"\n\nlet rec rvalue_computation_doesnt_depend_on_global_variables\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (exp: expression_t)\n  (actor: tid_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   global_variables_unmentioned_in_expression vs exp\n                    /\\ states_match_except_global_variables vs pc_relation s1 s2\n                    /\\ global_variables_unaddressed_in_memory vs s1.mem\n                    /\\ global_variables_unaddressed_in_memory vs s2.mem\n                    /\\ roots_match s1.mem\n                    /\\ roots_match s2.mem\n                    /\\ ThreadStatusRunning? (s1.threads actor).status)\n          (ensures  rvalue_computation exp actor s1 == rvalue_computation exp actor s2\n                    /\\ (match rvalue_computation exp actor s1 with\n                       | ComputationProduces value -> global_variables_unaddressed_in_object_value vs value\n                       | _ -> True))\n          (decreases exp) =\n  if not (expression_valid exp) then\n    ()\n  else\n    match exp with\n    | ExpressionConstant value -> ()\n    | ExpressionGlobalVariable td var_id ->\n        dereference_as_td_computation_doesnt_depend_on_global_variables vs (PointerRoot (RootIdGlobal var_id)) td actor\n          s1.mem s2.mem\n    | ExpressionLocalVariable td var_id ->\n        let thread = s1.threads actor in\n        if list_contains var_id thread.top.local_variables then\n          dereference_as_td_computation_doesnt_depend_on_global_variables vs\n            (PointerRoot (RootIdStack actor thread.top.method_id thread.top.frame_uniq var_id)) td actor s1.mem s2.mem\n        else\n          ()\n    | ExpressionUnaryOperator _ _ operator operand ->\n        rvalue_computation_doesnt_depend_on_global_variables vs pc_relation operand actor s1 s2\n    | ExpressionBinaryOperator _ _ _ operator operand1 operand2 ->\n        rvalue_computation_doesnt_depend_on_global_variables vs pc_relation operand1 actor s1 s2;\n        rvalue_computation_doesnt_depend_on_global_variables vs pc_relation operand2 actor s1 s2\n    | ExpressionIf _ cond operand_then operand_else ->\n        rvalue_computation_doesnt_depend_on_global_variables vs pc_relation cond actor s1 s2;\n        rvalue_computation_doesnt_depend_on_global_variables vs pc_relation operand_then actor s1 s2;\n        rvalue_computation_doesnt_depend_on_global_variables vs pc_relation operand_else actor s1 s2\n    | ExpressionDereference td ptr ->\n        rvalue_computation_doesnt_depend_on_global_variables vs pc_relation ptr actor s1 s2;\n        (match rvalue_computation ptr actor s1 with\n         | ComputationUndefined | ComputationImpossible -> ()\n         | ComputationProduces ptr_value ->\n             let p = PrimitiveBoxPointer?.ptr (ObjectValuePrimitive?.value ptr_value) in\n             dereference_as_td_computation_doesnt_depend_on_global_variables vs p td actor s1.mem s2.mem)\n    | ExpressionAddressOf obj ->\n        lvalue_computation_doesnt_depend_on_global_variables vs pc_relation obj actor s1 s2\n    | ExpressionPointerOffset ptr offset ->\n        rvalue_computation_doesnt_depend_on_global_variables vs pc_relation ptr actor s1 s2;\n        rvalue_computation_doesnt_depend_on_global_variables vs pc_relation offset actor s1 s2;\n        (match rvalue_computation ptr actor s1 with\n         | ComputationUndefined | ComputationImpossible -> ()\n         | ComputationProduces ptr_value ->\n             (match rvalue_computation offset actor s1 with\n              | ComputationUndefined | ComputationImpossible -> ()\n              | ComputationProduces offset_value ->\n                  let p = PrimitiveBoxPointer?.ptr (ObjectValuePrimitive?.value ptr_value) in\n                  (match p with\n                   | PointerIndex array_ptr idx ->\n                       let offset_int = ObjectValueAbstract?.value offset_value in\n                       dereference_computation_doesnt_depend_on_global_variables vs array_ptr s1.mem s2.mem\n                   | _ -> ())))\n    | ExpressionFieldOf td obj field_id ->\n        lvalue_computation_doesnt_depend_on_global_variables vs pc_relation obj actor s1 s2;\n        (match lvalue_computation obj actor s1 with\n         | ComputationProduces obj_ptr ->\n             dereference_as_td_computation_doesnt_depend_on_global_variables vs (PointerField obj_ptr field_id)\n               td actor s1.mem s2.mem\n         | _ -> ())\n    | ExpressionAllocated ptr ->\n        rvalue_computation_doesnt_depend_on_global_variables vs pc_relation ptr actor s1 s2\n    | ExpressionApplyFunction td operands return_type operand_types fn ->\n        rvalues_computation_doesnt_depend_on_global_variables vs pc_relation operands actor s1 s2\n    | ExpressionIfUndefined td potentially_unsafe safe_substitution ->\n        rvalue_computation_doesnt_depend_on_global_variables vs pc_relation potentially_unsafe actor s1 s2;\n        rvalue_computation_doesnt_depend_on_global_variables vs pc_relation safe_substitution actor s1 s2\n    | ExpressionInitialTid -> ()\n    | ExpressionUniqsUsed -> ()\n    | ExpressionStopReason -> ()\n\nand lvalue_computation_doesnt_depend_on_global_variables\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (exp: expression_t)\n  (actor: tid_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   global_variables_unmentioned_in_expression vs exp\n                    /\\ states_match_except_global_variables vs pc_relation s1 s2\n                    /\\ global_variables_unaddressed_in_memory vs s1.mem\n                    /\\ global_variables_unaddressed_in_memory vs s2.mem\n                    /\\ roots_match s1.mem\n                    /\\ roots_match s2.mem\n                    /\\ ThreadStatusRunning? (s1.threads actor).status)\n          (ensures    lvalue_computation exp actor s1 == lvalue_computation exp actor s2\n                    /\\ (match lvalue_computation exp actor s1 with\n                       | ComputationProduces p -> global_variables_unaddressed_in_pointer vs p\n                       | _ -> True))\n          (decreases exp) =\n  match exp with\n  | ExpressionGlobalVariable _ var_id -> ()\n  | ExpressionLocalVariable _ var_id -> ()\n  | ExpressionDereference _ ptr ->\n      rvalue_computation_doesnt_depend_on_global_variables vs pc_relation ptr actor s1 s2\n  | ExpressionFieldOf td obj field_id ->\n      lvalue_computation_doesnt_depend_on_global_variables vs pc_relation obj actor s1 s2\n  | _ -> ()\n  \nand rvalues_computation_doesnt_depend_on_global_variables\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (exps: list expression_t)\n  (actor: tid_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   global_variables_unmentioned_in_expressions vs exps\n                    /\\ states_match_except_global_variables vs pc_relation s1 s2\n                    /\\ global_variables_unaddressed_in_memory vs s1.mem\n                    /\\ global_variables_unaddressed_in_memory vs s2.mem\n                    /\\ roots_match s1.mem\n                    /\\ roots_match s2.mem\n                    /\\ ThreadStatusRunning? (s1.threads actor).status)\n          (ensures  rvalues_computation exps actor s1 == rvalues_computation exps actor s2\n                    /\\ (match rvalues_computation exps actor s1 with\n                       | ComputationProduces values -> global_variables_unaddressed_in_object_values vs values\n                       | _ -> True))\n          (decreases exps) =\n  match exps with\n  | [] -> ()\n  | exp :: exps' ->\n      rvalue_computation_doesnt_depend_on_global_variables vs pc_relation exp actor s1 s2;\n      rvalues_computation_doesnt_depend_on_global_variables vs pc_relation exps' actor s1 s2\n\n#pop-options\n"
  },
  {
    "path": "experimental/lib/Strategies.GlobalVars.VarHiding.fst",
    "content": "module Strategies.GlobalVars.VarHiding\n\nopen Armada.Base\nopen Armada.BinaryOp\nopen Armada.Computation\nopen Armada.Expression\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Pointer\nopen Armada.State\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Type\nopen Armada.UnaryOp\nopen FStar.Sequence.Ambient\nopen FStar.Sequence.Base\nopen Spec.List\nopen Spec.Ubool\nopen Strategies.ArmadaInvariant.PositionsValid\nopen Strategies.ArmadaInvariant.RootsMatch\nopen Strategies.GlobalVars\nopen Strategies.GlobalVars.Pointer\nopen Strategies.GlobalVars.Unaddressed\nopen Strategies.GlobalVars.Util\nopen Strategies.GlobalVars.VarIntro\nopen Strategies.PCRelation\nopen Util.Seq\nopen Util.Trigger\n  \nlet append_among_gvars_s1_only_preserves_write_buffer_lists_match_except_global_variables\n  (vs: list var_id_t)\n  (write_buffer1: list write_message_t)\n  (write_buffer2: list write_message_t)\n  (write_message: write_message_t)\n  : Lemma (requires   write_buffers_match (remove_global_variables_from_write_buffer vs write_buffer1)\n                        (remove_global_variables_from_write_buffer vs write_buffer2)\n                    /\\ pointer_among_global_variables vs write_message.location)\n          (ensures  (let write_buffer1' = FStar.List.Tot.append write_buffer1 [write_message] in\n                     write_buffers_match (remove_global_variables_from_write_buffer vs write_buffer1')\n                       (remove_global_variables_from_write_buffer vs write_buffer2))) =\n  pointer_among_gvars_implies_gvars_addressed vs write_message.location;\n  append_effect_on_remove_global_variables_from_write_buffer_list vs write_buffer1 write_message\n\nlet append_among_gvars_s1_only_preserves_write_buffers_match_except_global_variables\n  (vs: list var_id_t)\n  (write_buffer1: seq write_message_t)\n  (write_buffer2: seq write_message_t)\n  (write_message: write_message_t)\n  : Lemma (requires   write_buffers_match_except_global_variables vs write_buffer1 write_buffer2\n                    /\\ pointer_among_global_variables vs write_message.location)\n          (ensures  (let write_buffer1' = build write_buffer1 write_message in\n                     write_buffers_match_except_global_variables vs write_buffer1' write_buffer2))\n          (decreases length write_buffer1 + length write_buffer2) =\n  build_equivalent_to_append write_buffer1 write_message;\n  append_among_gvars_s1_only_preserves_write_buffer_lists_match_except_global_variables vs (seq_to_list write_buffer1)\n    (seq_to_list write_buffer2) write_message\n\nlet adding_write_message_among_gvars_s1_only_maintains_positions_in_write_buffers_match_and_positions_valid_for_receiver\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (write_message: write_message_t)\n  (threads1: Armada.Threads.t)\n  (threads2: Armada.Threads.t)\n  (receiver_tid: tid_t)\n  : Lemma (requires   positions_valid_in_threads threads1\n                    /\\ positions_valid_in_threads threads2\n                    /\\ threads_match_except_global_variables vs pc_relation threads1 threads2\n                    /\\ pointer_among_global_variables vs write_message.location\n                    /\\ positions_valid_in_threads threads1\n                    /\\ positions_valid_in_threads threads2)\n          (ensures  (let threads1' = append_to_thread_write_buffer threads1 actor write_message in\n                       positions_valid_in_threads threads1'\n                     /\\ write_buffers_match_except_global_variables vs\n                         (unread_write_buffer threads1' actor receiver_tid)\n                         (unread_write_buffer threads2 actor receiver_tid))) =\n  assert (sender_receiver_trigger actor receiver_tid);\n  append_among_gvars_s1_only_preserves_write_buffers_match_except_global_variables vs\n    (unread_write_buffer threads1 actor receiver_tid)\n    (unread_write_buffer threads2 actor receiver_tid)\n    write_message;\n  unread_write_buffer_commutes_with_append threads1 actor receiver_tid write_message\n\nlet adding_write_message_among_gvars_s1_only_maintains_positions_match_and_positions_valid_for_tid_pair\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (write_message: write_message_t)\n  (threads1: Armada.Threads.t)\n  (threads2: Armada.Threads.t)\n  (sender_tid: tid_t)\n  (receiver_tid: tid_t)\n  : Lemma (requires   positions_valid_in_threads threads1\n                    /\\ positions_valid_in_threads threads2\n                    /\\ threads_match_except_global_variables vs pc_relation threads1 threads2\n                    /\\ pointer_among_global_variables vs write_message.location\n                    /\\ positions_valid_in_threads threads1\n                    /\\ positions_valid_in_threads threads2)\n          (ensures  (let threads1' = append_to_thread_write_buffer threads1 actor write_message in\n                       positions_valid_in_threads threads1'\n                     /\\ (write_buffers_match_except_global_variables vs\n                         (unread_write_buffer threads1' sender_tid receiver_tid)\n                         (unread_write_buffer threads2 sender_tid receiver_tid)))) =\n  if sender_tid <> actor then\n    assert (sender_receiver_trigger sender_tid receiver_tid)\n  else\n    adding_write_message_among_gvars_s1_only_maintains_positions_in_write_buffers_match_and_positions_valid_for_receiver\n      vs pc_relation actor write_message threads1 threads2 receiver_tid\n\nlet adding_write_message_among_gvars_s1_only_maintains_positions_in_write_buffers_match_and_positions_valid\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (write_message: write_message_t)\n  (threads1: Armada.Threads.t)\n  (threads2: Armada.Threads.t)\n  : Lemma (requires   positions_valid_in_threads threads1\n                    /\\ positions_valid_in_threads threads2\n                    /\\ threads_match_except_global_variables vs pc_relation threads1 threads2\n                    /\\ pointer_among_global_variables vs write_message.location\n                    /\\ positions_valid_in_threads threads1\n                    /\\ positions_valid_in_threads threads2)\n          (ensures  (let threads1' = append_to_thread_write_buffer threads1 actor write_message in\n                       positions_valid_in_threads threads1'\n                     /\\ positions_in_write_buffers_match_except_global_variables vs threads1' threads2)) =\n  let threads1' = append_to_thread_write_buffer threads1 actor write_message in\n  introduce forall sender_tid receiver_tid.\n               write_buffers_match_except_global_variables vs\n                 (unread_write_buffer threads1' sender_tid receiver_tid)\n                 (unread_write_buffer threads2 sender_tid receiver_tid)\n  with adding_write_message_among_gvars_s1_only_maintains_positions_match_and_positions_valid_for_tid_pair\n         vs pc_relation actor write_message threads1 threads2 sender_tid receiver_tid\n\n#push-options \"--z3rlimit 30\"\n\nlet rec lvalue_computation_among_gvars_doesnt_depend_on_gvars\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (exp: expression_t)\n  (actor: tid_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   lvalue_expression_among_global_variables vs exp\n                    /\\ states_match_except_global_variables vs pc_relation s1 s2\n                    /\\ global_variables_unaddressed_in_memory vs s1.mem\n                    /\\ global_variables_unaddressed_in_memory vs s2.mem\n                    /\\ roots_match s1.mem\n                    /\\ roots_match s2.mem)\n          (ensures  lvalue_computation exp actor s1 == lvalue_computation exp actor s2\n                    /\\ (match lvalue_computation exp actor s1 with\n                       | ComputationProduces p -> pointer_among_global_variables vs p\n                       | _ -> True)) =\n  match exp with\n  | ExpressionGlobalVariable _ var_id -> ()\n  | ExpressionFieldOf td obj field_id ->\n      lvalue_computation_among_gvars_doesnt_depend_on_gvars vs pc_relation obj actor s1 s2\n  | _ -> ()\n\n#pop-options\n#push-options \"--z3rlimit 30\"\n\nlet rec update_pointer_directly_among_gvars_s1_only_maintains_states_match\n  (vs: list var_id_t)\n  (p: Armada.Pointer.t)\n  (new_storage: valid_object_storage_t)\n  (mem1: Armada.Memory.t)\n  (mem2: Armada.Memory.t)\n  : Lemma (requires   pointer_among_global_variables vs p\n                    /\\ global_variables_unaddressed_in_storage vs new_storage\n                    /\\ global_variables_unaddressed_in_memory vs mem1\n                    /\\ global_variables_unaddressed_in_memory vs mem2\n                    /\\ memories_match_except_global_variables vs mem1 mem2\n                    /\\ roots_match mem1\n                    /\\ roots_match mem2\n                    /\\ (ComputationProduces? (update_pointer_directly p new_storage mem1)))\n          (ensures  (match update_pointer_directly p new_storage mem1 with\n                     | ComputationProduces mem1' ->\n                           global_variables_unaddressed_in_memory vs mem1'\n                         /\\ memories_match_except_global_variables vs mem1' mem2\n                         /\\ roots_match mem1')) =\n  match p with\n  | PointerUninitialized -> ()\n  | PointerNull -> ()\n  | PointerRoot root_id -> ()\n  | PointerField struct_ptr field_id ->\n      dereference_computation_when_gvars_unaddressed_produces_storage_with_gvars_unaddressed vs struct_ptr mem1;\n      (match dereference_computation struct_ptr mem1 with\n       | ComputationProduces parent ->\n           (match parent with\n            | ObjectStorageStruct fields ->\n                if   field_id >= length fields\n                   || neqb (object_storage_to_td new_storage)\n                          (object_storage_to_td (index fields field_id)) then\n                  ()\n                else (\n                  let new_parent = update_storage_child parent field_id new_storage in\n                  update_pointer_directly_among_gvars_s1_only_maintains_states_match vs struct_ptr\n                    new_parent mem1 mem2\n                )\n            | _ -> ())\n      | _ -> ())\n  | PointerIndex array_ptr idx ->\n      dereference_computation_when_gvars_unaddressed_produces_storage_with_gvars_unaddressed vs array_ptr mem1;\n      (match dereference_computation array_ptr mem1 with\n       | ComputationProduces parent ->\n           (match parent with\n            | ObjectStorageArray element_td elements ->\n                if   idx < 0\n                   || idx >= length elements\n                   || neqb (object_storage_to_td new_storage) element_td then\n                  ()\n                else (\n                  let new_parent = update_storage_child parent idx new_storage in\n                  update_pointer_directly_among_gvars_s1_only_maintains_states_match vs array_ptr\n                    new_parent mem1 mem2\n                )\n            | _ -> ())\n      | _ -> ())\n\nlet update_pointer_among_gvars_s1_only_maintains_states_match\n  (vs: list var_id_t)\n  (p: Armada.Pointer.t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (new_value: object_value_t)\n  (mem1: Armada.Memory.t)\n  (mem2: Armada.Memory.t)\n  : Lemma (requires   memories_match_except_global_variables vs mem1 mem2\n                    /\\ global_variables_unaddressed_in_memory vs mem1\n                    /\\ global_variables_unaddressed_in_memory vs mem2\n                    /\\ roots_match mem1\n                    /\\ roots_match mem2\n                    /\\ global_variables_unaddressed_in_object_value vs new_value\n                    /\\ pointer_among_global_variables vs p\n                    /\\ (ComputationProduces? (update_pointer p actor writer_pc writer_expression_number\n                                               bypassing_write_buffer new_value mem1)))\n          (ensures  (match update_pointer p actor writer_pc writer_expression_number bypassing_write_buffer\n                             new_value mem1 with\n                     | ComputationProduces (optional_write_message, mem1') ->\n                           memories_match_except_global_variables vs mem1' mem2\n                         /\\ global_variables_unaddressed_in_memory vs mem1'\n                         /\\ roots_match mem1')) =\n  match p with\n  | PointerUninitialized -> ()\n  | PointerNull -> ()\n  | PointerRoot root_id ->\n      let root = mem1 root_id in\n      (match root_to_storage_computation root with\n       | ComputationProduces storage ->\n           update_storage_with_gvars_unaddressed_maintains_gvars_unaddressed vs p actor writer_pc\n             writer_expression_number bypassing_write_buffer storage new_value)\n  | PointerField struct_ptr field_id ->\n      dereference_computation_when_gvars_unaddressed_produces_storage_with_gvars_unaddressed vs struct_ptr mem1;\n      (match dereference_computation struct_ptr mem1 with\n       | ComputationProduces parent ->\n          (match parent with\n           | ObjectStorageStruct fields ->\n               let field = index fields field_id in\n               update_storage_with_gvars_unaddressed_maintains_gvars_unaddressed vs p actor writer_pc\n                 writer_expression_number bypassing_write_buffer field new_value;\n               (match update_storage p actor writer_pc writer_expression_number\n                        bypassing_write_buffer field new_value with\n                | ComputationProduces (write_message, new_field) ->\n                    update_storage_child_with_gvars_unaddressed_maintains_gvars_unaddressed\n                      vs parent field_id new_field;\n                    let new_parent = update_storage_child parent field_id new_field in\n                    update_pointer_directly_among_gvars_s1_only_maintains_states_match\n                      vs struct_ptr new_parent mem1 mem2)))\n  | PointerIndex array_ptr idx ->\n      dereference_computation_when_gvars_unaddressed_produces_storage_with_gvars_unaddressed vs array_ptr mem1;\n      (match dereference_computation array_ptr mem1 with\n       | ComputationProduces parent ->\n          (match parent with\n           | ObjectStorageArray element_td elements ->\n               let element = index elements idx in\n               update_storage_with_gvars_unaddressed_maintains_gvars_unaddressed vs p actor writer_pc\n                 writer_expression_number bypassing_write_buffer element new_value;\n               (match update_storage p actor writer_pc writer_expression_number\n                        bypassing_write_buffer element new_value with\n                | ComputationProduces (write_message, new_element) ->\n                    update_storage_child_with_gvars_unaddressed_maintains_gvars_unaddressed\n                      vs parent idx new_element;\n                    let new_parent = update_storage_child parent idx new_element in\n                    update_pointer_directly_among_gvars_s1_only_maintains_states_match vs array_ptr new_parent\n                      mem1 mem2)))\n\nlet update_pointed_to_value_among_gvars_s1_only_maintains_states_match\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (p: Armada.Pointer.t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (new_value: object_value_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   states_match_except_global_variables vs pc_relation s1 s2\n                    /\\ global_variables_unaddressed_in_memory vs s1.mem\n                    /\\ global_variables_unaddressed_in_memory vs s2.mem\n                    /\\ roots_match s1.mem\n                    /\\ roots_match s2.mem\n                    /\\ global_variables_unaddressed_in_object_value vs new_value\n                    /\\ pointer_among_global_variables vs p\n                    /\\ (ComputationProduces? (update_pointed_to_value p actor writer_pc writer_expression_number\n                                               bypassing_write_buffer new_value s1)))\n          (ensures  (match update_pointed_to_value p actor writer_pc writer_expression_number bypassing_write_buffer\n                             new_value s1 with\n                     | ComputationProduces s1' ->\n                           states_match_except_global_variables vs pc_relation s1' s2\n                         /\\ global_variables_unaddressed_in_memory vs s1'.mem\n                         /\\ roots_match s1'.mem)) =\n  update_pointer_among_gvars_s1_only_maintains_states_match vs p actor writer_pc\n    writer_expression_number bypassing_write_buffer new_value s1.mem s2.mem;\n  match update_pointer p actor writer_pc writer_expression_number bypassing_write_buffer new_value s1.mem with\n  | ComputationProduces (optional_write_message, new_mem) ->\n      (match optional_write_message with\n       | Some write_message ->\n           let thread = s1.threads actor in\n           let new_write_buffer = build thread.write_buffer write_message in\n           let new_thread = { thread with write_buffer = new_write_buffer } in\n           let new_threads = Spec.Map.upd s1.threads actor new_thread in\n           let s1' = { s1 with mem = new_mem; threads = new_threads; } in\n           adding_write_message_among_gvars_s1_only_maintains_positions_in_write_buffers_match_and_positions_valid\n             vs pc_relation actor write_message s1.threads s2.threads;\n           assert (global_variables_unaddressed_in_memory vs s1'.mem);\n           assert (states_match_except_global_variables vs pc_relation s1' s2);\n           assert (roots_match s1'.mem)\n       | None ->\n           let s1' = { s1 with mem = new_mem; } in\n           assert (global_variables_unaddressed_in_memory vs s1'.mem);\n           assert (states_match_except_global_variables vs pc_relation s1' s2);\n           assert (roots_match s1'.mem)\n      )\n\nlet update_expression_with_lvalue_among_gvars_s1_only_maintains_states_match\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (exp: expression_t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (new_value: object_value_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   states_match_except_global_variables vs pc_relation s1 s2\n                    /\\ global_variables_unaddressed_in_memory vs s1.mem\n                    /\\ global_variables_unaddressed_in_memory vs s2.mem\n                    /\\ roots_match s1.mem\n                    /\\ roots_match s2.mem\n                    /\\ lvalue_expression_among_global_variables vs exp\n                    /\\ global_variables_unaddressed_in_object_value vs new_value\n                    /\\ (ComputationProduces? (update_expression exp actor writer_pc writer_expression_number\n                                               bypassing_write_buffer new_value s1)))\n          (ensures  (match update_expression exp actor writer_pc writer_expression_number\n                             bypassing_write_buffer new_value s1 with\n                     | ComputationProduces s1' ->\n                           states_match_except_global_variables vs pc_relation s1' s2\n                         /\\ global_variables_unaddressed_in_memory vs s1'.mem\n                         /\\ roots_match s1'.mem)) =\n  lvalue_computation_among_gvars_doesnt_depend_on_gvars vs pc_relation exp actor s1 s2;\n  let td = expression_to_td exp in\n  match lvalue_computation exp actor s1 with\n  | ComputationProduces p ->\n      update_pointed_to_value_among_gvars_s1_only_maintains_states_match vs pc_relation p actor writer_pc\n        writer_expression_number bypassing_write_buffer new_value s1 s2\n\nlet statement_that_updates_gvars_s1_only_maintains_states_match\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (end_pc: option pc_t)\n  (statement: Armada.Statement.t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  (* see .fsti file for spec *) =\n  match statement_computation actor nd start_pc end_pc statement s1 with\n  | ComputationProduces s1' ->\n      (match statement with\n       | UpdateStatement bypassing_write_buffer dst src ->\n           rvalue_computation_when_gvars_unaddressed_produces_value_with_gvars_unaddressed vs src actor s1;\n           let src_value = ComputationProduces?.result (rvalue_computation src actor s1) in\n           update_expression_with_lvalue_among_gvars_s1_only_maintains_states_match vs pc_relation dst\n             actor start_pc 0 bypassing_write_buffer src_value s1 s2;\n           assert (states_match_except_global_variables vs pc_relation s1' s2)\n       | NondeterministicUpdateStatement bypassing_write_buffer dst ->\n           let nd_value = Cons?.hd nd in\n           if_object_value_has_all_pointers_uninitialized_then_it_doesnt_depend_on_gvars vs nd_value;\n           update_expression_with_lvalue_among_gvars_s1_only_maintains_states_match vs pc_relation dst\n             actor start_pc 0 bypassing_write_buffer nd_value s1 s2;\n           assert (states_match_except_global_variables vs pc_relation s1' s2))\n  | _ -> ()\n\nlet positions_in_write_buffers_match_preserved_by_s1_advance_past_gvar_helper\n  (vs: list var_id_t)\n  (write_buffer1: seq write_message_t)\n  (write_buffer2: seq write_message_t)\n  (write_message1: write_message_t)\n  : Lemma (requires   length write_buffer1 > 0\n                    /\\ write_message1 == index write_buffer1 0\n                    /\\ write_buffers_match_except_global_variables vs write_buffer1 write_buffer2\n                    /\\ not (global_variables_unaddressed_in_write_message vs write_message1))\n          (ensures  write_buffers_match_except_global_variables vs (drop write_buffer1 1) write_buffer2) =\n  let write_messages1 = seq_to_list write_buffer1 in\n  let write_messages2 = seq_to_list write_buffer2 in\n  assert (write_buffers_match (remove_global_variables_from_write_buffer vs write_messages1)\n            (remove_global_variables_from_write_buffer vs write_messages2));\n  match write_messages1 with\n  | hd1 :: tl1 ->\n      assert (hd1 == write_message1);\n      assert (write_buffers_match (remove_global_variables_from_write_buffer vs tl1)\n                (remove_global_variables_from_write_buffer vs write_messages2));\n      seq_to_list_drop_equals_tail write_buffer1;\n      assert (seq_to_list (drop write_buffer1 1) == tl1)\n\nlet positions_in_write_buffers_match_preserved_by_s1_advance_past_gvar\n  (vs: list var_id_t)\n  (threads1: Armada.Threads.t)\n  (threads2: Armada.Threads.t)\n  (sender_tid: tid_t)\n  (receiver_tid: tid_t)\n  (threads1': Armada.Threads.t)\n  : Lemma (requires (let sender_thread1 = threads1 sender_tid in\n                     let receiver_thread1 = threads1 receiver_tid in\n                     let write_buffer1 = sender_thread1.write_buffer in\n                     let position1 = (threads1 receiver_tid).position_in_other_write_buffers sender_tid in\n                       length write_buffer1 > position1\n                     /\\ positions_valid_in_threads threads1\n                     /\\ positions_valid_in_threads threads2\n                     /\\ (let write_message1 = index write_buffer1 position1 in\n                        let position_in_other_write_buffers1' =\n                          Spec.Map.upd receiver_thread1.position_in_other_write_buffers sender_tid\n                            (position1 + 1) in\n                        let receiver_thread1' = { receiver_thread1 with position_in_other_write_buffers =\n                                                    position_in_other_write_buffers1' } in\n                          threads1' == Spec.Map.upd threads1 receiver_tid receiver_thread1'\n                        /\\ not (global_variables_unaddressed_in_write_message vs write_message1)\n                        /\\ positions_in_write_buffers_match_except_global_variables vs threads1 threads2)))\n          (ensures   positions_valid_in_threads threads1'\n                   /\\ positions_in_write_buffers_match_except_global_variables vs threads1' threads2) =\n  introduce forall sender_tid' receiver_tid'.\n     sender_receiver_trigger sender_tid' receiver_tid'\n     ==>    position_valid threads1' sender_tid' receiver_tid'\n         /\\ write_buffers_match_except_global_variables vs\n           (unread_write_buffer threads1' sender_tid' receiver_tid')\n           (unread_write_buffer threads2 sender_tid' receiver_tid')\n  with introduce _ ==> _\n  with _. (\n    assert (sender_receiver_trigger sender_tid' receiver_tid');\n    assert (position_valid threads2 sender_tid' receiver_tid');\n    assert (write_buffers_match_except_global_variables vs\n              (unread_write_buffer threads1 sender_tid' receiver_tid')\n              (unread_write_buffer threads2 sender_tid' receiver_tid'));\n    assert ((threads1' sender_tid').write_buffer == (threads1 sender_tid').write_buffer);\n    if receiver_tid <> receiver_tid' then (\n      assert ((threads1' receiver_tid').position_in_other_write_buffers ==\n              (threads1 receiver_tid').position_in_other_write_buffers)\n    )\n    else if sender_tid <> sender_tid' then (\n      assert ((threads1' receiver_tid').position_in_other_write_buffers sender_tid' ==\n              (threads1 receiver_tid').position_in_other_write_buffers sender_tid')\n    )\n    else (\n      let sender_thread1 = threads1 sender_tid in\n      let receiver_thread1 = threads1 receiver_tid in\n      let write_buffer1 = sender_thread1.write_buffer in\n      let position1 = (threads1 receiver_tid).position_in_other_write_buffers sender_tid in\n      let write_message1 = index write_buffer1 position1 in\n      let unread_write_buffer1 = unread_write_buffer threads1 sender_tid receiver_tid in\n      let unread_write_buffer2 = unread_write_buffer threads2 sender_tid receiver_tid in\n      let unread_write_buffer1' = unread_write_buffer threads1' sender_tid receiver_tid in\n      assert (unread_write_buffer1' == drop unread_write_buffer1 1);\n      assert (index unread_write_buffer1 0 == write_message1);\n      positions_in_write_buffers_match_preserved_by_s1_advance_past_gvar_helper vs unread_write_buffer1\n        unread_write_buffer2 write_message1\n    )\n  )\n\nlet propagate_write_message_statement_computation_s1_only_maintains_states_match\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  (* see .fsti file for spec *) =\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract tid_t) then\n     ()\n  else\n    let receiver_tid: tid_t = ObjectValueAbstract?.value (Cons?.hd nd) in\n    if receiver_tid = actor then // can't propagate to the same thread\n      ()\n    else\n      let propagator_thread1 = s1.threads actor in\n      let receiver_thread1 = s1.threads receiver_tid in\n      let which_message1 = receiver_thread1.position_in_other_write_buffers actor in\n      if which_message1 >= length propagator_thread1.write_buffer then\n        false_elim ()\n      else (\n        assert (which_message1 < length propagator_thread1.write_buffer);\n        let write_message1 = index propagator_thread1.write_buffer which_message1 in\n        let position_in_other_write_buffers1' =\n          Spec.Map.upd receiver_thread1.position_in_other_write_buffers actor (which_message1 + 1) in\n        let receiver_thread1' =\n          { receiver_thread1 with position_in_other_write_buffers = position_in_other_write_buffers1' } in\n        let threads1' = Spec.Map.upd s1.threads receiver_tid receiver_thread1' in\n        propagate_write_message_s1_only_among_gvars_maintains_states_match vs write_message1 receiver_tid\n          s1.mem s2.mem;\n        match propagate_write_message write_message1 receiver_tid s1.mem with\n        | ComputationImpossible\n        | ComputationUndefined ->\n            let s1' = ({ s1 with threads = threads1'; }) in\n            positions_in_write_buffers_match_preserved_by_s1_advance_past_gvar vs s1.threads s2.threads\n              actor receiver_tid s1'.threads;\n            assert (positions_in_write_buffers_match_except_global_variables vs s1'.threads s2.threads)\n        | ComputationProduces mem1' ->\n            let s1' = ({ s1 with mem = mem1'; threads = threads1'; }) in\n            positions_in_write_buffers_match_preserved_by_s1_advance_past_gvar vs s1.threads s2.threads\n              actor receiver_tid s1'.threads;\n            assert (positions_in_write_buffers_match_except_global_variables vs s1'.threads s2.threads)\n      )\n"
  },
  {
    "path": "experimental/lib/Strategies.GlobalVars.VarHiding.fsti",
    "content": "module Strategies.GlobalVars.VarHiding\n\nopen Armada.Base\nopen Armada.Computation\nopen Armada.Expression\nopen Armada.Pointer\nopen Armada.State\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Transition\nopen Armada.Type\nopen FStar.Sequence.Base\nopen Spec.List\nopen Strategies.ArmadaInvariant.PositionsValid\nopen Strategies.ArmadaInvariant.RootsMatch\nopen Strategies.ArmadaInvariant.UnstartedThreads\nopen Strategies.GlobalVars\nopen Strategies.GlobalVars.VarIntro\nopen Strategies.PCRelation\nopen Util.List\n\nval statement_that_updates_gvars_s1_only_maintains_states_match\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (end_pc: option pc_t)\n  (statement: Armada.Statement.t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   states_match_except_global_variables vs pc_relation s1 s2\n                    /\\ global_variables_unaddressed_in_memory vs s1.mem\n                    /\\ global_variables_unaddressed_in_memory vs s2.mem\n                    /\\ roots_match s1.mem\n                    /\\ roots_match s2.mem\n                    /\\ statement_updates_gvars vs statement)\n          (ensures  (match statement_computation actor nd start_pc end_pc statement s1 with\n                     | ComputationProduces s1' ->\n                           states_match_except_global_variables vs pc_relation s1' s2\n                         /\\ global_variables_unaddressed_in_memory vs s1'.mem\n                         /\\ roots_match s1'.mem\n                     | _ -> True))\n\nval propagate_write_message_statement_computation_s1_only_maintains_states_match\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   states_match_except_global_variables vs pc_relation s1 s2\n                    /\\ global_variables_unaddressed_in_memory vs s1.mem\n                    /\\ global_variables_unaddressed_in_memory vs s2.mem\n                    /\\ roots_match s1.mem\n                    /\\ roots_match s2.mem\n                    /\\ unstarted_threads_have_empty_write_buffers s1\n                    /\\ unstarted_threads_have_empty_write_buffers s2\n                    /\\ ThreadStatusRunning? (s1.threads actor).status\n                    /\\ list_len nd = 1\n                    /\\ object_value_to_td (Cons?.hd nd) == ObjectTDAbstract tid_t\n                    /\\ (let receiver_tid = ObjectValueAbstract?.value (Cons?.hd nd) in\n                       let thread1 = s1.threads actor in\n                       let write_buffer1 = thread1.write_buffer in\n                       let position1 = (s1.threads receiver_tid).position_in_other_write_buffers actor in\n                         length write_buffer1 > position1\n                       /\\ (let write_message1 = index write_buffer1 position1 in\n                          not (global_variables_unaddressed_in_write_message vs write_message1))))\n          (ensures  (match propagate_write_message_statement_computation actor nd s1 with\n                     | ComputationProduces s1' ->\n                           states_match_except_global_variables vs pc_relation s1' s2\n                         /\\ global_variables_unaddressed_in_memory vs s1.mem\n                         /\\ roots_match s1.mem\n                         /\\ unstarted_threads_have_empty_write_buffers s1'\n                     | ComputationImpossible -> True\n                     | ComputationUndefined -> True))\n"
  },
  {
    "path": "experimental/lib/Strategies.GlobalVars.VarIntro.fst",
    "content": "module Strategies.GlobalVars.VarIntro\n\nopen Armada.Base\nopen Armada.BinaryOp\nopen Armada.Computation\nopen Armada.Expression\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Pointer\nopen Armada.State\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Type\nopen Armada.UnaryOp\nopen FStar.Sequence.Ambient\nopen FStar.Sequence.Base\nopen Spec.List\nopen Spec.Ubool\nopen Strategies.ArmadaInvariant.PositionsValid\nopen Strategies.ArmadaInvariant.RootsMatch\nopen Strategies.GlobalVars\nopen Strategies.GlobalVars.Pointer\nopen Strategies.GlobalVars.Unaddressed\nopen Strategies.GlobalVars.Util\nopen Strategies.PCRelation\nopen Util.Seq\nopen Util.Trigger\n\nlet rec pointer_among_gvars_implies_gvars_addressed\n  (vs: list var_id_t)\n  (p: Armada.Pointer.t)\n  : Lemma (requires pointer_among_global_variables vs p)\n          (ensures  not (global_variables_unaddressed_in_pointer vs p)) =\n  match p with\n  | PointerUninitialized -> ()\n  | PointerNull -> ()\n  | PointerRoot root_id -> ()\n  | PointerField struct_ptr _ -> pointer_among_gvars_implies_gvars_addressed vs struct_ptr\n  | PointerIndex array_ptr _ -> pointer_among_gvars_implies_gvars_addressed vs array_ptr\n  \nlet append_among_gvars_s2_only_preserves_write_buffer_lists_match_except_global_variables\n  (vs: list var_id_t)\n  (write_buffer1: list write_message_t)\n  (write_buffer2: list write_message_t)\n  (write_message: write_message_t)\n  : Lemma (requires   write_buffers_match (remove_global_variables_from_write_buffer vs write_buffer1)\n                        (remove_global_variables_from_write_buffer vs write_buffer2)\n                    /\\ pointer_among_global_variables vs write_message.location)\n          (ensures  (let write_buffer2' = FStar.List.Tot.append write_buffer2 [write_message] in\n                     write_buffers_match (remove_global_variables_from_write_buffer vs write_buffer1)\n                       (remove_global_variables_from_write_buffer vs write_buffer2'))) =\n  pointer_among_gvars_implies_gvars_addressed vs write_message.location;\n  append_effect_on_remove_global_variables_from_write_buffer_list vs write_buffer2 write_message\n\nlet append_among_gvars_s2_only_preserves_write_buffers_match_except_global_variables\n  (vs: list var_id_t)\n  (write_buffer1: seq write_message_t)\n  (write_buffer2: seq write_message_t)\n  (write_message: write_message_t)\n  : Lemma (requires   write_buffers_match_except_global_variables vs write_buffer1 write_buffer2\n                    /\\ pointer_among_global_variables vs write_message.location)\n          (ensures  (let write_buffer2' = build write_buffer2 write_message in\n                     write_buffers_match_except_global_variables vs write_buffer1 write_buffer2'))\n          (decreases length write_buffer1 + length write_buffer2) =\n  build_equivalent_to_append write_buffer2 write_message;\n  append_among_gvars_s2_only_preserves_write_buffer_lists_match_except_global_variables vs (seq_to_list write_buffer1)\n    (seq_to_list write_buffer2) write_message\n\nlet adding_write_message_among_gvars_s2_only_maintains_positions_in_write_buffers_match_and_positions_valid_for_receiver\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (write_message: write_message_t)\n  (threads1: Armada.Threads.t)\n  (threads2: Armada.Threads.t)\n  (receiver_tid: tid_t)\n  : Lemma (requires   positions_valid_in_threads threads1\n                    /\\ positions_valid_in_threads threads2\n                    /\\ threads_match_except_global_variables vs pc_relation threads1 threads2\n                    /\\ pointer_among_global_variables vs write_message.location\n                    /\\ positions_valid_in_threads threads1\n                    /\\ positions_valid_in_threads threads2)\n          (ensures  (let threads2' = append_to_thread_write_buffer threads2 actor write_message in\n                       positions_valid_in_threads threads2'\n                     /\\ write_buffers_match_except_global_variables vs\n                         (unread_write_buffer threads1 actor receiver_tid)\n                         (unread_write_buffer threads2' actor receiver_tid))) =\n  assert (sender_receiver_trigger actor receiver_tid);\n  append_among_gvars_s2_only_preserves_write_buffers_match_except_global_variables vs\n    (unread_write_buffer threads1 actor receiver_tid)\n    (unread_write_buffer threads2 actor receiver_tid)\n    write_message;\n  unread_write_buffer_commutes_with_append threads2 actor receiver_tid write_message\n\nlet adding_write_message_among_gvars_s2_only_maintains_positions_match_and_positions_valid_for_tid_pair\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (write_message: write_message_t)\n  (threads1: Armada.Threads.t)\n  (threads2: Armada.Threads.t)\n  (sender_tid: tid_t)\n  (receiver_tid: tid_t)\n  : Lemma (requires   positions_valid_in_threads threads1\n                    /\\ positions_valid_in_threads threads2\n                    /\\ threads_match_except_global_variables vs pc_relation threads1 threads2\n                    /\\ pointer_among_global_variables vs write_message.location\n                    /\\ positions_valid_in_threads threads1\n                    /\\ positions_valid_in_threads threads2)\n          (ensures  (let threads2' = append_to_thread_write_buffer threads2 actor write_message in\n                       positions_valid_in_threads threads2'\n                     /\\ (write_buffers_match_except_global_variables vs\n                         (unread_write_buffer threads1 sender_tid receiver_tid)\n                         (unread_write_buffer threads2' sender_tid receiver_tid)))) =\n  if sender_tid <> actor then\n    assert (sender_receiver_trigger sender_tid receiver_tid)\n  else\n    adding_write_message_among_gvars_s2_only_maintains_positions_in_write_buffers_match_and_positions_valid_for_receiver\n      vs pc_relation actor write_message threads1 threads2 receiver_tid\n\nlet adding_write_message_among_gvars_s2_only_maintains_positions_in_write_buffers_match_and_positions_valid\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (write_message: write_message_t)\n  (threads1: Armada.Threads.t)\n  (threads2: Armada.Threads.t)\n  : Lemma (requires   positions_valid_in_threads threads1\n                    /\\ positions_valid_in_threads threads2\n                    /\\ threads_match_except_global_variables vs pc_relation threads1 threads2\n                    /\\ pointer_among_global_variables vs write_message.location\n                    /\\ positions_valid_in_threads threads1\n                    /\\ positions_valid_in_threads threads2)\n          (ensures  (let threads2' = append_to_thread_write_buffer threads2 actor write_message in\n                       positions_valid_in_threads threads2'\n                     /\\ positions_in_write_buffers_match_except_global_variables vs threads1 threads2')) =\n  let threads2' = append_to_thread_write_buffer threads2 actor write_message in\n  introduce forall sender_tid receiver_tid.\n               write_buffers_match_except_global_variables vs\n                 (unread_write_buffer threads1 sender_tid receiver_tid)\n                 (unread_write_buffer threads2' sender_tid receiver_tid)\n  with adding_write_message_among_gvars_s2_only_maintains_positions_match_and_positions_valid_for_tid_pair\n         vs pc_relation actor write_message threads1 threads2 sender_tid receiver_tid\n\n#push-options \"--z3rlimit 30\"\n\nlet rec lvalue_computation_among_gvars_doesnt_depend_on_gvars\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (exp: expression_t)\n  (actor: tid_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   lvalue_expression_among_global_variables vs exp\n                    /\\ states_match_except_global_variables vs pc_relation s1 s2\n                    /\\ global_variables_unaddressed_in_memory vs s1.mem\n                    /\\ global_variables_unaddressed_in_memory vs s2.mem\n                    /\\ roots_match s1.mem\n                    /\\ roots_match s2.mem)\n          (ensures  lvalue_computation exp actor s1 == lvalue_computation exp actor s2\n                    /\\ (match lvalue_computation exp actor s1 with\n                       | ComputationProduces p -> pointer_among_global_variables vs p\n                       | _ -> True)) =\n  match exp with\n  | ExpressionGlobalVariable _ var_id -> ()\n  | ExpressionFieldOf td obj field_id ->\n      lvalue_computation_among_gvars_doesnt_depend_on_gvars vs pc_relation obj actor s1 s2\n  | _ -> ()\n\n#pop-options\n#push-options \"--z3rlimit 30\"\n\nlet rec update_pointer_directly_among_gvars_s2_only_maintains_states_match\n  (vs: list var_id_t)\n  (p: Armada.Pointer.t)\n  (new_storage: valid_object_storage_t)\n  (mem1: Armada.Memory.t)\n  (mem2: Armada.Memory.t)\n  : Lemma (requires   pointer_among_global_variables vs p\n                    /\\ global_variables_unaddressed_in_storage vs new_storage\n                    /\\ global_variables_unaddressed_in_memory vs mem1\n                    /\\ global_variables_unaddressed_in_memory vs mem2\n                    /\\ memories_match_except_global_variables vs mem1 mem2\n                    /\\ roots_match mem1\n                    /\\ roots_match mem2\n                    /\\ (ComputationProduces? (update_pointer_directly p new_storage mem2)))\n          (ensures  (match update_pointer_directly p new_storage mem2 with\n                     | ComputationProduces mem2' ->\n                           global_variables_unaddressed_in_memory vs mem2'\n                         /\\ memories_match_except_global_variables vs mem1 mem2'\n                         /\\ roots_match mem2')) =\n  match p with\n  | PointerUninitialized -> ()\n  | PointerNull -> ()\n  | PointerRoot root_id -> ()\n  | PointerField struct_ptr field_id ->\n      dereference_computation_when_gvars_unaddressed_produces_storage_with_gvars_unaddressed vs struct_ptr mem2;\n      (match dereference_computation struct_ptr mem2 with\n       | ComputationProduces parent ->\n           (match parent with\n            | ObjectStorageStruct fields ->\n                if   field_id >= length fields\n                   || neqb (object_storage_to_td new_storage)\n                          (object_storage_to_td (index fields field_id)) then\n                  ()\n                else (\n                  let new_parent = update_storage_child parent field_id new_storage in\n                  update_pointer_directly_among_gvars_s2_only_maintains_states_match vs struct_ptr\n                    new_parent mem1 mem2\n                )\n            | _ -> ())\n      | _ -> ())\n  | PointerIndex array_ptr idx ->\n      dereference_computation_when_gvars_unaddressed_produces_storage_with_gvars_unaddressed vs array_ptr mem2;\n      (match dereference_computation array_ptr mem2 with\n       | ComputationProduces parent ->\n           (match parent with\n            | ObjectStorageArray element_td elements ->\n                if   idx < 0\n                   || idx >= length elements\n                   || neqb (object_storage_to_td new_storage) element_td then\n                  ()\n                else (\n                  let new_parent = update_storage_child parent idx new_storage in\n                  update_pointer_directly_among_gvars_s2_only_maintains_states_match vs array_ptr\n                    new_parent mem1 mem2\n                )\n            | _ -> ())\n      | _ -> ())\n\nlet update_pointer_among_gvars_s2_only_maintains_states_match\n  (vs: list var_id_t)\n  (p: Armada.Pointer.t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (new_value: object_value_t)\n  (mem1: Armada.Memory.t)\n  (mem2: Armada.Memory.t)\n  : Lemma (requires   memories_match_except_global_variables vs mem1 mem2\n                    /\\ global_variables_unaddressed_in_memory vs mem1\n                    /\\ global_variables_unaddressed_in_memory vs mem2\n                    /\\ roots_match mem1\n                    /\\ roots_match mem2\n                    /\\ global_variables_unaddressed_in_object_value vs new_value\n                    /\\ pointer_among_global_variables vs p\n                    /\\ (ComputationProduces? (update_pointer p actor writer_pc writer_expression_number\n                                               bypassing_write_buffer new_value mem2)))\n          (ensures  (match update_pointer p actor writer_pc writer_expression_number bypassing_write_buffer\n                             new_value mem2 with\n                     | ComputationProduces (optional_write_message, mem2') ->\n                           memories_match_except_global_variables vs mem1 mem2'\n                         /\\ global_variables_unaddressed_in_memory vs mem2'\n                         /\\ roots_match mem2')) =\n  match p with\n  | PointerUninitialized -> ()\n  | PointerNull -> ()\n  | PointerRoot root_id ->\n      let root = mem2 root_id in\n      (match root_to_storage_computation root with\n       | ComputationProduces storage ->\n           update_storage_with_gvars_unaddressed_maintains_gvars_unaddressed vs p actor writer_pc\n             writer_expression_number bypassing_write_buffer storage new_value)\n  | PointerField struct_ptr field_id ->\n      dereference_computation_when_gvars_unaddressed_produces_storage_with_gvars_unaddressed vs struct_ptr mem2;\n      (match dereference_computation struct_ptr mem2 with\n       | ComputationProduces parent ->\n          (match parent with\n           | ObjectStorageStruct fields ->\n               let field = index fields field_id in\n               update_storage_with_gvars_unaddressed_maintains_gvars_unaddressed vs p actor writer_pc\n                 writer_expression_number bypassing_write_buffer field new_value;\n               (match update_storage p actor writer_pc writer_expression_number\n                        bypassing_write_buffer field new_value with\n                | ComputationProduces (write_message, new_field) ->\n                    update_storage_child_with_gvars_unaddressed_maintains_gvars_unaddressed\n                      vs parent field_id new_field;\n                    let new_parent = update_storage_child parent field_id new_field in\n                    update_pointer_directly_among_gvars_s2_only_maintains_states_match\n                      vs struct_ptr new_parent mem1 mem2)))\n  | PointerIndex array_ptr idx ->\n      dereference_computation_when_gvars_unaddressed_produces_storage_with_gvars_unaddressed vs array_ptr mem2;\n      (match dereference_computation array_ptr mem2 with\n       | ComputationProduces parent ->\n          (match parent with\n           | ObjectStorageArray element_td elements ->\n               let element = index elements idx in\n               update_storage_with_gvars_unaddressed_maintains_gvars_unaddressed vs p actor writer_pc\n                 writer_expression_number bypassing_write_buffer element new_value;\n               (match update_storage p actor writer_pc writer_expression_number\n                        bypassing_write_buffer element new_value with\n                | ComputationProduces (write_message, new_element) ->\n                    update_storage_child_with_gvars_unaddressed_maintains_gvars_unaddressed\n                      vs parent idx new_element;\n                    let new_parent = update_storage_child parent idx new_element in\n                    update_pointer_directly_among_gvars_s2_only_maintains_states_match vs array_ptr\n                      new_parent mem1 mem2)))\n\nlet update_pointed_to_value_among_gvars_s2_only_maintains_states_match\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (p: Armada.Pointer.t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (new_value: object_value_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   states_match_except_global_variables vs pc_relation s1 s2\n                    /\\ global_variables_unaddressed_in_memory vs s1.mem\n                    /\\ global_variables_unaddressed_in_memory vs s2.mem\n                    /\\ roots_match s1.mem\n                    /\\ roots_match s2.mem\n                    /\\ global_variables_unaddressed_in_object_value vs new_value\n                    /\\ pointer_among_global_variables vs p\n                    /\\ (ComputationProduces? (update_pointed_to_value p actor writer_pc writer_expression_number\n                                               bypassing_write_buffer new_value s2)))\n          (ensures  (match update_pointed_to_value p actor writer_pc writer_expression_number bypassing_write_buffer\n                             new_value s2 with\n                     | ComputationProduces s2' ->\n                           states_match_except_global_variables vs pc_relation s1 s2'\n                         /\\ global_variables_unaddressed_in_memory vs s2'.mem\n                         /\\ roots_match s2'.mem)) =\n  update_pointer_among_gvars_s2_only_maintains_states_match vs p actor writer_pc\n    writer_expression_number bypassing_write_buffer new_value s1.mem s2.mem;\n  match update_pointer p actor writer_pc writer_expression_number bypassing_write_buffer new_value s2.mem with\n  | ComputationProduces (optional_write_message, new_mem) ->\n      (match optional_write_message with\n       | Some write_message ->\n           let thread = s2.threads actor in\n           let new_write_buffer = build thread.write_buffer write_message in\n           let new_thread = { thread with write_buffer = new_write_buffer } in\n           let new_threads = Spec.Map.upd s2.threads actor new_thread in\n           let s2' = { s2 with mem = new_mem; threads = new_threads; } in\n           adding_write_message_among_gvars_s2_only_maintains_positions_in_write_buffers_match_and_positions_valid\n             vs pc_relation actor write_message s1.threads s2.threads;\n           assert (global_variables_unaddressed_in_memory vs s2'.mem);\n           assert (states_match_except_global_variables vs pc_relation s1 s2');\n           assert (roots_match s2'.mem)\n       | None ->\n           let s2' = { s2 with mem = new_mem; } in\n           assert (global_variables_unaddressed_in_memory vs s2'.mem);\n           assert (states_match_except_global_variables vs pc_relation s1 s2');\n           assert (roots_match s2'.mem)\n      )\n\nlet update_expression_with_lvalue_among_gvars_s2_only_maintains_states_match\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (exp: expression_t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (new_value: object_value_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   states_match_except_global_variables vs pc_relation s1 s2\n                    /\\ global_variables_unaddressed_in_memory vs s1.mem\n                    /\\ global_variables_unaddressed_in_memory vs s2.mem\n                    /\\ roots_match s1.mem\n                    /\\ roots_match s2.mem\n                    /\\ lvalue_expression_among_global_variables vs exp\n                    /\\ global_variables_unaddressed_in_object_value vs new_value\n                    /\\ (ComputationProduces? (update_expression exp actor writer_pc writer_expression_number\n                                               bypassing_write_buffer new_value s2)))\n          (ensures  (match update_expression exp actor writer_pc writer_expression_number\n                             bypassing_write_buffer new_value s2 with\n                     | ComputationProduces s2' ->\n                           states_match_except_global_variables vs pc_relation s1 s2'\n                         /\\ global_variables_unaddressed_in_memory vs s2'.mem\n                         /\\ roots_match s2'.mem)) =\n  lvalue_computation_among_gvars_doesnt_depend_on_gvars vs pc_relation exp actor s1 s2;\n  let td = expression_to_td exp in\n  match lvalue_computation exp actor s2 with\n  | ComputationProduces p ->\n      update_pointed_to_value_among_gvars_s2_only_maintains_states_match vs pc_relation p actor writer_pc\n        writer_expression_number bypassing_write_buffer new_value s1 s2\n\nlet statement_that_updates_gvars_s2_only_maintains_states_match\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (end_pc: option pc_t)\n  (statement: Armada.Statement.t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  (* see .fsti file for spec *) =\n  match statement_computation actor nd start_pc end_pc statement s2 with\n  | ComputationProduces s2' ->\n      (match statement with\n       | UpdateStatement bypassing_write_buffer dst src ->\n           rvalue_computation_when_gvars_unaddressed_produces_value_with_gvars_unaddressed vs src actor s2;\n           let src_value = ComputationProduces?.result (rvalue_computation src actor s2) in\n           update_expression_with_lvalue_among_gvars_s2_only_maintains_states_match vs pc_relation dst\n             actor start_pc 0 bypassing_write_buffer src_value s1 s2;\n           assert (states_match_except_global_variables vs pc_relation s1 s2')\n       | NondeterministicUpdateStatement bypassing_write_buffer dst ->\n           let nd_value = Cons?.hd nd in\n           if_object_value_has_all_pointers_uninitialized_then_it_doesnt_depend_on_gvars vs nd_value;\n           update_expression_with_lvalue_among_gvars_s2_only_maintains_states_match vs pc_relation dst\n             actor start_pc 0 bypassing_write_buffer nd_value s1 s2;\n           assert (states_match_except_global_variables vs pc_relation s1 s2'))\n  | _ -> ()\n\nlet positions_in_write_buffers_match_preserved_by_advance_past_non_gvars_helper\n  (vs: list var_id_t)\n  (write_buffer1: seq write_message_t)\n  (write_buffer2: seq write_message_t)\n  (write_message1: write_message_t)\n  (write_message2: write_message_t)\n  : Lemma (requires   length write_buffer1 > 0\n                    /\\ length write_buffer2 > 0\n                    /\\ write_message1 == index write_buffer1 0\n                    /\\ write_message2 == index write_buffer2 0\n                    /\\ write_buffers_match_except_global_variables vs write_buffer1 write_buffer2\n                    /\\ global_variables_unaddressed_in_write_message vs write_message1\n                    /\\ global_variables_unaddressed_in_write_message vs write_message2\n                    /\\ write_messages_match write_message1 write_message2)\n          (ensures  write_buffers_match_except_global_variables vs (drop write_buffer1 1) (drop write_buffer2 1)) =\n  let write_messages1 = seq_to_list write_buffer1 in\n  let write_messages2 = seq_to_list write_buffer2 in\n  assert (write_buffers_match (remove_global_variables_from_write_buffer vs write_messages1)\n            (remove_global_variables_from_write_buffer vs write_messages2));\n  match write_messages1, write_messages2 with\n  | hd1 :: tl1, hd2 :: tl2 ->\n      assert (hd1 == write_message1);\n      assert (hd2 == write_message2);\n      assert (write_buffers_match (remove_global_variables_from_write_buffer vs tl1)\n                (remove_global_variables_from_write_buffer vs tl2));\n      seq_to_list_drop_equals_tail write_buffer1;\n      seq_to_list_drop_equals_tail write_buffer2;\n      assert (seq_to_list (drop write_buffer1 1) == tl1);\n      assert (seq_to_list (drop write_buffer2 1) == tl2)\n\nlet positions_in_write_buffers_match_preserved_by_advance_past_non_gvars\n  (vs: list var_id_t)\n  (threads1: Armada.Threads.t)\n  (threads2: Armada.Threads.t)\n  (sender_tid: tid_t)\n  (receiver_tid: tid_t)\n  (threads1': Armada.Threads.t)\n  (threads2': Armada.Threads.t)\n  : Lemma (requires (let sender_thread1 = threads1 sender_tid in\n                     let sender_thread2 = threads2 sender_tid in\n                     let receiver_thread1 = threads1 receiver_tid in\n                     let receiver_thread2 = threads2 receiver_tid in\n                     let write_buffer1 = sender_thread1.write_buffer in\n                     let write_buffer2 = sender_thread2.write_buffer in\n                     let position1 = (threads1 receiver_tid).position_in_other_write_buffers sender_tid in\n                     let position2 = (threads2 receiver_tid).position_in_other_write_buffers sender_tid in\n                       length write_buffer1 > position1\n                     /\\ length write_buffer2 > position2\n                     /\\ positions_valid_in_threads threads1\n                     /\\ positions_valid_in_threads threads2\n                     /\\ (let write_message1 = index write_buffer1 position1 in\n                        let write_message2 = index write_buffer2 position2 in\n                        let position_in_other_write_buffers1' =\n                           Spec.Map.upd receiver_thread1.position_in_other_write_buffers sender_tid\n                             (position1 + 1) in\n                        let position_in_other_write_buffers2' =\n                          Spec.Map.upd receiver_thread2.position_in_other_write_buffers sender_tid\n                            (position2 + 1) in\n                        let receiver_thread1' = { receiver_thread1 with position_in_other_write_buffers =\n                                                    position_in_other_write_buffers1' } in\n                        let receiver_thread2' = { receiver_thread2 with position_in_other_write_buffers =\n                                                    position_in_other_write_buffers2' } in\n                          threads1' == Spec.Map.upd threads1 receiver_tid receiver_thread1'\n                        /\\ threads2' == Spec.Map.upd threads2 receiver_tid receiver_thread2'\n                        /\\ global_variables_unaddressed_in_write_message vs write_message1\n                        /\\ global_variables_unaddressed_in_write_message vs write_message2\n                        /\\ write_messages_match write_message1 write_message2\n                        /\\ positions_in_write_buffers_match_except_global_variables vs threads1 threads2)))\n          (ensures   positions_valid_in_threads threads1'\n                   /\\ positions_valid_in_threads threads2'\n                   /\\ positions_in_write_buffers_match_except_global_variables vs threads1' threads2') =\n  introduce forall sender_tid' receiver_tid'.\n     sender_receiver_trigger sender_tid' receiver_tid'\n     ==>    position_valid threads1' sender_tid' receiver_tid'\n         /\\ position_valid threads2' sender_tid' receiver_tid'\n         /\\ write_buffers_match_except_global_variables vs\n           (unread_write_buffer threads1' sender_tid' receiver_tid')\n           (unread_write_buffer threads2' sender_tid' receiver_tid')\n  with introduce _ ==> _\n  with _. (\n    assert (sender_receiver_trigger sender_tid' receiver_tid');\n    assert (position_valid threads1 sender_tid' receiver_tid');\n    assert (position_valid threads2 sender_tid' receiver_tid');\n    assert (write_buffers_match_except_global_variables vs\n              (unread_write_buffer threads1 sender_tid' receiver_tid')\n              (unread_write_buffer threads2 sender_tid' receiver_tid'));\n    assert ((threads1' sender_tid').write_buffer == (threads1 sender_tid').write_buffer);\n    assert ((threads2' sender_tid').write_buffer == (threads2 sender_tid').write_buffer);\n    if receiver_tid <> receiver_tid' then (\n      assert ((threads1' receiver_tid').position_in_other_write_buffers ==\n              (threads1 receiver_tid').position_in_other_write_buffers);\n      assert ((threads2' receiver_tid').position_in_other_write_buffers ==\n              (threads2 receiver_tid').position_in_other_write_buffers)\n    )\n    else if sender_tid <> sender_tid' then (\n      assert ((threads1' receiver_tid').position_in_other_write_buffers sender_tid' ==\n              (threads1 receiver_tid').position_in_other_write_buffers sender_tid');\n      assert ((threads2' receiver_tid').position_in_other_write_buffers sender_tid' ==\n              (threads2 receiver_tid').position_in_other_write_buffers sender_tid')\n    )\n    else (\n      let sender_thread1 = threads1 sender_tid in\n      let sender_thread2 = threads2 sender_tid in\n      let receiver_thread1 = threads1 receiver_tid in\n      let receiver_thread2 = threads2 receiver_tid in\n      let write_buffer1 = sender_thread1.write_buffer in\n      let write_buffer2 = sender_thread2.write_buffer in\n      let position1 = (threads1 receiver_tid).position_in_other_write_buffers sender_tid in\n      let position2 = (threads2 receiver_tid).position_in_other_write_buffers sender_tid in\n      let write_message1 = index write_buffer1 position1 in\n      let write_message2 = index write_buffer2 position2 in\n      let unread_write_buffer1 = unread_write_buffer threads1 sender_tid receiver_tid in\n      let unread_write_buffer2 = unread_write_buffer threads2 sender_tid receiver_tid in\n      let unread_write_buffer1' = unread_write_buffer threads1' sender_tid receiver_tid in\n      let unread_write_buffer2' = unread_write_buffer threads2' sender_tid receiver_tid in\n      assert (unread_write_buffer1' == drop unread_write_buffer1 1);\n      assert (index unread_write_buffer1 0 == write_message1);\n      assert (unread_write_buffer2' == drop unread_write_buffer2 1);\n      assert (index unread_write_buffer2 0 == write_message2);\n      positions_in_write_buffers_match_preserved_by_advance_past_non_gvars_helper vs unread_write_buffer1\n        unread_write_buffer2 write_message1 write_message2\n    )\n  )\n\nlet positions_in_write_buffers_match_preserved_by_s2_advance_past_gvar_helper\n  (vs: list var_id_t)\n  (write_buffer1: seq write_message_t)\n  (write_buffer2: seq write_message_t)\n  (write_message2: write_message_t)\n  : Lemma (requires   length write_buffer2 > 0\n                    /\\ write_message2 == index write_buffer2 0\n                    /\\ write_buffers_match_except_global_variables vs write_buffer1 write_buffer2\n                    /\\ not (global_variables_unaddressed_in_write_message vs write_message2))\n          (ensures  write_buffers_match_except_global_variables vs write_buffer1 (drop write_buffer2 1)) =\n  let write_messages1 = seq_to_list write_buffer1 in\n  let write_messages2 = seq_to_list write_buffer2 in\n  assert (write_buffers_match (remove_global_variables_from_write_buffer vs write_messages1)\n            (remove_global_variables_from_write_buffer vs write_messages2));\n  match write_messages2 with\n  | hd2 :: tl2 ->\n      assert (hd2 == write_message2);\n      assert (write_buffers_match (remove_global_variables_from_write_buffer vs write_messages1)\n                (remove_global_variables_from_write_buffer vs tl2));\n      seq_to_list_drop_equals_tail write_buffer2;\n      assert (seq_to_list (drop write_buffer2 1) == tl2)\n\nlet positions_in_write_buffers_match_preserved_by_s2_advance_past_gvar\n  (vs: list var_id_t)\n  (threads1: Armada.Threads.t)\n  (threads2: Armada.Threads.t)\n  (sender_tid: tid_t)\n  (receiver_tid: tid_t)\n  (threads2': Armada.Threads.t)\n  : Lemma (requires (let sender_thread2 = threads2 sender_tid in\n                     let receiver_thread2 = threads2 receiver_tid in\n                     let write_buffer2 = sender_thread2.write_buffer in\n                     let position2 = (threads2 receiver_tid).position_in_other_write_buffers sender_tid in\n                       length write_buffer2 > position2\n                     /\\ positions_valid_in_threads threads1\n                     /\\ positions_valid_in_threads threads2\n                     /\\ (let write_message2 = index write_buffer2 position2 in\n                        let position_in_other_write_buffers2' =\n                          Spec.Map.upd receiver_thread2.position_in_other_write_buffers sender_tid\n                            (position2 + 1) in\n                        let receiver_thread2' = { receiver_thread2 with position_in_other_write_buffers =\n                                                    position_in_other_write_buffers2' } in\n                          threads2' == Spec.Map.upd threads2 receiver_tid receiver_thread2'\n                        /\\ not (global_variables_unaddressed_in_write_message vs write_message2)\n                        /\\ positions_in_write_buffers_match_except_global_variables vs threads1 threads2)))\n          (ensures   positions_valid_in_threads threads2'\n                   /\\ positions_in_write_buffers_match_except_global_variables vs threads1 threads2') =\n  introduce forall sender_tid' receiver_tid'.\n     sender_receiver_trigger sender_tid' receiver_tid'\n     ==>    position_valid threads2' sender_tid' receiver_tid'\n         /\\ write_buffers_match_except_global_variables vs\n           (unread_write_buffer threads1 sender_tid' receiver_tid')\n           (unread_write_buffer threads2' sender_tid' receiver_tid')\n  with introduce _ ==> _\n  with _. (\n    assert (sender_receiver_trigger sender_tid' receiver_tid');\n    assert (position_valid threads2 sender_tid' receiver_tid');\n    assert (write_buffers_match_except_global_variables vs\n              (unread_write_buffer threads1 sender_tid' receiver_tid')\n              (unread_write_buffer threads2 sender_tid' receiver_tid'));\n    assert ((threads2' sender_tid').write_buffer == (threads2 sender_tid').write_buffer);\n    if receiver_tid <> receiver_tid' then (\n      assert ((threads2' receiver_tid').position_in_other_write_buffers ==\n              (threads2 receiver_tid').position_in_other_write_buffers)\n    )\n    else if sender_tid <> sender_tid' then (\n      assert ((threads2' receiver_tid').position_in_other_write_buffers sender_tid' ==\n              (threads2 receiver_tid').position_in_other_write_buffers sender_tid')\n    )\n    else (\n      let sender_thread2 = threads2 sender_tid in\n      let receiver_thread2 = threads2 receiver_tid in\n      let write_buffer2 = sender_thread2.write_buffer in\n      let position2 = (threads2 receiver_tid).position_in_other_write_buffers sender_tid in\n      let write_message2 = index write_buffer2 position2 in\n      let unread_write_buffer1 = unread_write_buffer threads1 sender_tid receiver_tid in\n      let unread_write_buffer2 = unread_write_buffer threads2 sender_tid receiver_tid in\n      let unread_write_buffer2' = unread_write_buffer threads2' sender_tid receiver_tid in\n      assert (unread_write_buffer2' == drop unread_write_buffer2 1);\n      assert (index unread_write_buffer2 0 == write_message2);\n      positions_in_write_buffers_match_preserved_by_s2_advance_past_gvar_helper vs unread_write_buffer1\n        unread_write_buffer2 write_message2\n    )\n  )\n\nlet statement_that_updates_specific_gvar_using_constant_must_succeed\n  (v: var_id_t)\n  (td: object_td_t)\n  (actor: tid_t)\n  (start_pc: pc_t)\n  (end_pc: option pc_t)\n  (statement: Armada.Statement.t)\n  (s: Armada.State.t)\n  : Lemma (requires   gvar_has_type s.mem v td\n                    /\\ statement_updates_specific_gvar_to_constant v td statement)\n          (ensures  ComputationProduces? (statement_computation actor [] start_pc end_pc statement s)) =\n  match statement with\n  | UpdateStatement bypassing_write_buffer dst src ->\n      assert (expression_to_td dst == expression_to_td src);\n      (match src with\n       | ExpressionConstant value ->\n           assert (object_value_valid value);\n           (match rvalue_computation src actor s with\n            | ComputationImpossible -> false_elim ()\n            | ComputationUndefined -> false_elim ()\n            | ComputationProduces src_value -> ()))\n  | _ -> false_elim ()\n\nlet rec statement_that_updates_gvars_using_constant_must_succeed\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (actor: tid_t)\n  (start_pc: pc_t)\n  (end_pc: option pc_t)\n  (statement: Armada.Statement.t)\n  (s: Armada.State.t)\n  (* see .fsti file for spec *) =\n  match vs, tds with\n  | v :: remaining_vs, td :: remaining_tds ->\n      if u2b (statement_updates_specific_gvar_to_constant v td statement) then\n        statement_that_updates_specific_gvar_using_constant_must_succeed v td actor start_pc end_pc statement s\n      else\n        statement_that_updates_gvars_using_constant_must_succeed remaining_vs remaining_tds\n          actor start_pc end_pc statement s\n  | _, _ -> false_elim ()\n\nlet propagate_write_message_statement_computation_maintains_states_match\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  (* see .fsti file for spec *) =\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract tid_t) then\n     ()\n  else\n    let receiver_tid: tid_t = ObjectValueAbstract?.value (Cons?.hd nd) in\n    if receiver_tid = actor then // can't propagate to the same thread\n      ()\n    else\n      let propagator_thread1 = s1.threads actor in\n      let propagator_thread2 = s2.threads actor in\n      let receiver_thread1 = s1.threads receiver_tid in\n      let receiver_thread2 = s2.threads receiver_tid in\n      let which_message1 = receiver_thread1.position_in_other_write_buffers actor in\n      let which_message2 = receiver_thread2.position_in_other_write_buffers actor in\n      if which_message1 >= length propagator_thread1.write_buffer then\n        false_elim ()\n      else (\n        assert (which_message2 < length propagator_thread2.write_buffer);\n        let write_message1 = index propagator_thread1.write_buffer which_message1 in\n        let write_message2 = index propagator_thread2.write_buffer which_message2 in\n        let position_in_other_write_buffers1' =\n          Spec.Map.upd receiver_thread1.position_in_other_write_buffers actor (which_message1 + 1) in\n        let position_in_other_write_buffers2' =\n          Spec.Map.upd receiver_thread2.position_in_other_write_buffers actor (which_message2 + 1) in\n        let receiver_thread1' =\n          { receiver_thread1 with position_in_other_write_buffers = position_in_other_write_buffers1' } in\n        let receiver_thread2' =\n          { receiver_thread2 with position_in_other_write_buffers = position_in_other_write_buffers2' } in\n        let threads1' = Spec.Map.upd s1.threads receiver_tid receiver_thread1' in\n        let threads2' = Spec.Map.upd s2.threads receiver_tid receiver_thread2' in\n        propagate_write_message_maintains_states_match vs write_message1 write_message2 receiver_tid\n          s1.mem s2.mem;\n        match propagate_write_message write_message1 receiver_tid s1.mem,\n              propagate_write_message write_message2 receiver_tid s2.mem with\n        | ComputationImpossible, ComputationImpossible\n        | ComputationUndefined, ComputationUndefined -> \n            let s1' = ({ s1 with threads = threads1'; }) in\n            let s2' = ({ s2 with threads = threads2'; }) in\n            positions_in_write_buffers_match_preserved_by_advance_past_non_gvars vs s1.threads s2.threads\n              actor receiver_tid s1'.threads s2'.threads;\n            assert (positions_in_write_buffers_match_except_global_variables vs s1'.threads s2'.threads)\n        | ComputationProduces mem1', ComputationProduces mem2' ->\n            let s1' = ({ s1 with mem = mem1'; threads = threads1'; }) in\n            let s2' = ({ s2 with mem = mem2'; threads = threads2'; }) in\n            positions_in_write_buffers_match_preserved_by_advance_past_non_gvars vs s1.threads s2.threads\n              actor receiver_tid s1'.threads s2'.threads;\n            assert (positions_in_write_buffers_match_except_global_variables vs s1'.threads s2'.threads)\n        | _, _ -> ()\n      )\n\nlet propagate_write_message_statement_computation_s2_only_maintains_states_match\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  (* see .fsti file for spec *) =\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract tid_t) then\n     ()\n  else\n    let receiver_tid: tid_t = ObjectValueAbstract?.value (Cons?.hd nd) in\n    if receiver_tid = actor then // can't propagate to the same thread\n      ()\n    else\n      let propagator_thread2 = s2.threads actor in\n      let receiver_thread2 = s2.threads receiver_tid in\n      let which_message2 = receiver_thread2.position_in_other_write_buffers actor in\n      if which_message2 >= length propagator_thread2.write_buffer then\n        false_elim ()\n      else (\n        assert (which_message2 < length propagator_thread2.write_buffer);\n        let write_message2 = index propagator_thread2.write_buffer which_message2 in\n        let position_in_other_write_buffers2' =\n          Spec.Map.upd receiver_thread2.position_in_other_write_buffers actor (which_message2 + 1) in\n        let receiver_thread2' =\n          { receiver_thread2 with position_in_other_write_buffers = position_in_other_write_buffers2' } in\n        let threads2' = Spec.Map.upd s2.threads receiver_tid receiver_thread2' in\n        propagate_write_message_s2_only_among_gvars_maintains_states_match vs write_message2 receiver_tid\n          s1.mem s2.mem;\n        match propagate_write_message write_message2 receiver_tid s2.mem with\n        | ComputationImpossible\n        | ComputationUndefined ->\n            let s2' = ({ s2 with threads = threads2'; }) in\n            positions_in_write_buffers_match_preserved_by_s2_advance_past_gvar vs s1.threads s2.threads\n              actor receiver_tid s2'.threads;\n            assert (positions_in_write_buffers_match_except_global_variables vs s1.threads s2'.threads)\n        | ComputationProduces mem2' ->\n            let s2' = ({ s2 with mem = mem2'; threads = threads2'; }) in\n            positions_in_write_buffers_match_preserved_by_s2_advance_past_gvar vs s1.threads s2.threads\n              actor receiver_tid s2'.threads;\n            assert (positions_in_write_buffers_match_except_global_variables vs s1.threads s2'.threads)\n      )\n"
  },
  {
    "path": "experimental/lib/Strategies.GlobalVars.VarIntro.fsti",
    "content": "module Strategies.GlobalVars.VarIntro\n\nopen Armada.Base\nopen Armada.Computation\nopen Armada.Expression\nopen Armada.Pointer\nopen Armada.State\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Transition\nopen Armada.Type\nopen FStar.Sequence.Base\nopen Spec.List\nopen Spec.Ubool\nopen Strategies.ArmadaInvariant.PositionsValid\nopen Strategies.ArmadaInvariant.RootsMatch\nopen Strategies.ArmadaInvariant.UnstartedThreads\nopen Strategies.GlobalVars\nopen Strategies.GlobalVars.Types\nopen Strategies.PCRelation\nopen Util.List\n\nlet rec pointer_among_global_variables (vs: list var_id_t) (ptr: Armada.Pointer.t) : GTot bool =\n  match ptr with\n  | PointerUninitialized -> false\n  | PointerNull -> false\n  | PointerRoot root_id -> not (global_variables_unmentioned_in_root_id vs root_id)\n  | PointerField struct_ptr _ -> pointer_among_global_variables vs struct_ptr\n  | PointerIndex array_ptr _ -> pointer_among_global_variables vs array_ptr\n\nlet rec lvalue_expression_among_global_variables\n  (vs: list var_id_t)\n  (e: expression_t)\n  : GTot bool =\n  match e with\n  | ExpressionGlobalVariable _ var_id -> list_contains var_id vs\n  | ExpressionFieldOf _ obj _ -> lvalue_expression_among_global_variables vs obj\n  | _ -> false\n\nlet statement_updates_gvars\n  (vs: list var_id_t)\n  (statement: Armada.Statement.t)\n  : GTot bool =\n  match statement with\n  | UpdateStatement bypassing_write_buffer dst src ->\n         lvalue_expression_among_global_variables vs dst\n      && global_variables_unaddressed_in_rvalue_expression vs src\n  | NondeterministicUpdateStatement bypassing_write_buffer dst ->\n      lvalue_expression_among_global_variables vs dst\n  | _ -> false\n\nlet statement_updates_specific_gvar_to_constant\n  (v: var_id_t)\n  (td: object_td_t)\n  (statement: Armada.Statement.t)\n  : GTot ubool =\n  match statement with\n  | UpdateStatement bypassing_write_buffer (ExpressionGlobalVariable td' v') (ExpressionConstant value) ->\n        v' = v\n      /\\ td' == td\n      /\\ object_value_to_td value == td\n      /\\ (ObjectValuePrimitive? value || ObjectValueAbstract? value)\n  | _ -> False\n\nlet rec statement_updates_gvars_using_constant\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (statement: Armada.Statement.t)\n  : GTot ubool =\n  match vs, tds with\n  | v :: remaining_vs, td :: remaining_tds ->\n        statement_updates_specific_gvar_to_constant v td statement\n      \\/ statement_updates_gvars_using_constant remaining_vs remaining_tds statement\n  | _, _ -> False\n\nval pointer_among_gvars_implies_gvars_addressed\n  (vs: list var_id_t)\n  (p: Armada.Pointer.t)\n  : Lemma (requires pointer_among_global_variables vs p)\n          (ensures  not (global_variables_unaddressed_in_pointer vs p))\n\nval statement_that_updates_gvars_s2_only_maintains_states_match\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (start_pc: pc_t)\n  (end_pc: option pc_t)\n  (statement: Armada.Statement.t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   states_match_except_global_variables vs pc_relation s1 s2\n                    /\\ global_variables_unaddressed_in_memory vs s1.mem\n                    /\\ global_variables_unaddressed_in_memory vs s2.mem\n                    /\\ roots_match s1.mem\n                    /\\ roots_match s2.mem\n                    /\\ statement_updates_gvars vs statement)\n          (ensures  (match statement_computation actor nd start_pc end_pc statement s2 with\n                     | ComputationProduces s2' ->\n                           states_match_except_global_variables vs pc_relation s1 s2'\n                         /\\ global_variables_unaddressed_in_memory vs s2'.mem\n                         /\\ roots_match s2'.mem\n                     | _ -> True))\n\nval statement_that_updates_gvars_using_constant_must_succeed\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (actor: tid_t)\n  (start_pc: pc_t)\n  (end_pc: option pc_t)\n  (statement: Armada.Statement.t)\n  (s: Armada.State.t)\n  : Lemma (requires   all_gvars_have_types s.mem vs tds\n                    /\\ statement_updates_gvars_using_constant vs tds statement)\n          (ensures  ComputationProduces? (statement_computation actor [] start_pc end_pc statement s))\n\nval propagate_write_message_statement_computation_maintains_states_match\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   states_match_except_global_variables vs pc_relation s1 s2\n                    /\\ global_variables_unaddressed_in_memory vs s1.mem\n                    /\\ global_variables_unaddressed_in_memory vs s2.mem\n                    /\\ roots_match s1.mem\n                    /\\ roots_match s2.mem\n                    /\\ unstarted_threads_have_empty_write_buffers s1\n                    /\\ unstarted_threads_have_empty_write_buffers s2\n                    /\\ ThreadStatusRunning? (s1.threads actor).status\n                    /\\ list_len nd = 1\n                    /\\ object_value_to_td (Cons?.hd nd) == ObjectTDAbstract tid_t\n                    /\\ (let receiver_tid = ObjectValueAbstract?.value (Cons?.hd nd) in\n                       let thread1 = s1.threads actor in\n                       let thread2 = s2.threads actor in\n                       let write_buffer1 = thread1.write_buffer in\n                       let write_buffer2 = thread2.write_buffer in\n                       let position1 = (s1.threads receiver_tid).position_in_other_write_buffers actor in\n                       let position2 = (s2.threads receiver_tid).position_in_other_write_buffers actor in\n                         length write_buffer1 > position1\n                       /\\ length write_buffer2 > position2\n                       /\\ (let write_message1 = index write_buffer1 position1 in\n                          let write_message2 = index write_buffer2 position2 in\n                            global_variables_unaddressed_in_write_message vs write_message1\n                          /\\ global_variables_unaddressed_in_write_message vs write_message2\n                          /\\ write_messages_match write_message1 write_message2)))\n          (ensures  (match propagate_write_message_statement_computation actor nd s1,\n                           propagate_write_message_statement_computation actor nd s2 with\n                     | ComputationProduces s1', ComputationProduces s2' ->\n                           states_match_except_global_variables vs pc_relation s1' s2'\n                         /\\ global_variables_unaddressed_in_memory vs s1'.mem\n                         /\\ global_variables_unaddressed_in_memory vs s2'.mem\n                         /\\ roots_match s1'.mem\n                         /\\ roots_match s2'.mem\n                         /\\ unstarted_threads_have_empty_write_buffers s1'\n                         /\\ unstarted_threads_have_empty_write_buffers s2'\n                     | ComputationImpossible, ComputationImpossible -> True\n                     | ComputationUndefined, ComputationUndefined -> True\n                     | _ -> False))\n\nval propagate_write_message_statement_computation_s2_only_maintains_states_match\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : Lemma (requires   states_match_except_global_variables vs pc_relation s1 s2\n                    /\\ global_variables_unaddressed_in_memory vs s1.mem\n                    /\\ global_variables_unaddressed_in_memory vs s2.mem\n                    /\\ roots_match s1.mem\n                    /\\ roots_match s2.mem\n                    /\\ unstarted_threads_have_empty_write_buffers s1\n                    /\\ unstarted_threads_have_empty_write_buffers s2\n                    /\\ ThreadStatusRunning? (s2.threads actor).status\n                    /\\ list_len nd = 1\n                    /\\ object_value_to_td (Cons?.hd nd) == ObjectTDAbstract tid_t\n                    /\\ (let receiver_tid = ObjectValueAbstract?.value (Cons?.hd nd) in\n                       let thread2 = s2.threads actor in\n                       let write_buffer2 = thread2.write_buffer in\n                       let position2 = (s2.threads receiver_tid).position_in_other_write_buffers actor in\n                         length write_buffer2 > position2\n                       /\\ (let write_message2 = index write_buffer2 position2 in\n                          not (global_variables_unaddressed_in_write_message vs write_message2))))\n          (ensures  (match propagate_write_message_statement_computation actor nd s2 with\n                     | ComputationProduces s2' ->\n                           states_match_except_global_variables vs pc_relation s1 s2'\n                         /\\ global_variables_unaddressed_in_memory vs s2.mem\n                         /\\ roots_match s2.mem\n                         /\\ unstarted_threads_have_empty_write_buffers s2'\n                     | ComputationImpossible -> True\n                     | ComputationUndefined -> True))\n"
  },
  {
    "path": "experimental/lib/Strategies.GlobalVars.fst",
    "content": "module Strategies.GlobalVars\n\nopen Armada.Base\nopen Armada.Expression\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Pointer\nopen Armada.State\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Type\nopen FStar.Sequence.Base\nopen Spec.List\nopen Spec.Ubool\nopen Strategies.ArmadaInvariant.PositionsValid\nopen Strategies.PCRelation\nopen Util.List\nopen Util.Relation\nopen Util.Seq\n\nlet global_variables_unmentioned_in_root_id (vs: list var_id_t) (root_id: root_id_t) : GTot bool =\n  match root_id with\n  | RootIdGlobal var_id -> not (FStar.List.Tot.contains var_id vs)\n  | _ -> true\n\nlet rec global_variables_unaddressed_in_pointer (vs: list var_id_t) (ptr: Armada.Pointer.t) : GTot bool =\n  match ptr with\n  | PointerUninitialized -> true\n  | PointerNull -> true\n  | PointerRoot root_id -> global_variables_unmentioned_in_root_id vs root_id\n  | PointerField struct_ptr _ -> global_variables_unaddressed_in_pointer vs struct_ptr\n  | PointerIndex array_ptr _ -> global_variables_unaddressed_in_pointer vs array_ptr\n\nlet global_variables_unaddressed_in_box (vs: list var_id_t) (box: primitive_box_t) : GTot bool =\n  match box with\n  | PrimitiveBoxPointer ptr -> global_variables_unaddressed_in_pointer vs ptr\n  | _ -> true\n\nlet global_variables_unaddressed_in_boxes (vs: list var_id_t) (boxes: seq primitive_box_t) : GTot bool =\n  for_all_seq (global_variables_unaddressed_in_box vs) boxes\n\nlet global_variables_unaddressed_in_boxes_equivalent_to_forall (vs: list var_id_t) (boxes: seq primitive_box_t)\n  : Lemma (ensures global_variables_unaddressed_in_boxes vs boxes <==>\n                   (forall box. contains boxes box ==> global_variables_unaddressed_in_box vs box))\n          [SMTPat (global_variables_unaddressed_in_boxes vs boxes)] =\n  for_all_seq_equivalent_to_forall_seq_ubool (global_variables_unaddressed_in_box vs) boxes\n\nlet rec global_variables_unaddressed_in_object_value (vs: list var_id_t) (value: object_value_t)\n  : GTot bool (decreases rank value) =\n  all_seq_facts_lemma ();\n  match value with\n  | ObjectValuePrimitive value -> global_variables_unaddressed_in_box vs value\n  | ObjectValueStruct fields -> global_variables_unaddressed_in_object_value_seq vs fields\n  | ObjectValueArray _ elements -> global_variables_unaddressed_in_object_value_seq vs elements\n  | ObjectValueAbstract _ _ -> true\n\nand global_variables_unaddressed_in_object_value_seq (vs: list var_id_t) (values: seq object_value_t)\n  : GTot bool (decreases rank values) =\n  all_seq_facts_lemma ();\n  if length values = 0 then\n    true\n  else (\n       global_variables_unaddressed_in_object_value vs (index values 0)\n    && global_variables_unaddressed_in_object_value_seq vs (drop values 1)\n  )\n\nlet rec global_variables_unaddressed_in_object_value_seq_equivalent_to_forall\n  (vs: list var_id_t)\n  (values: seq object_value_t)\n  : Lemma (ensures global_variables_unaddressed_in_object_value_seq vs values <==>\n                   (forall value. contains values value ==> global_variables_unaddressed_in_object_value vs value))\n          (decreases rank values)\n          [SMTPat (global_variables_unaddressed_in_object_value_seq vs values)] =\n  all_seq_facts_lemma ();\n  if length values = 0 then\n    ()\n  else\n    global_variables_unaddressed_in_object_value_seq_equivalent_to_forall vs (drop values 1)\n\nlet global_variables_unaddressed_in_object_values (vs: list var_id_t) (values: list object_value_t)\n  : GTot bool =\n  for_all_ghost (global_variables_unaddressed_in_object_value vs) values\n\nlet global_variables_unaddressed_in_object_values_equivalent_to_forall (vs: list var_id_t) (values: list object_value_t)\n  : Lemma (ensures global_variables_unaddressed_in_object_values vs values <==>\n                   (forall value. contains_ubool value values ==> global_variables_unaddressed_in_object_value vs value))\n          [SMTPat (global_variables_unaddressed_in_object_values vs values)] =\n  for_all_ghost_equivalent_to_forall (global_variables_unaddressed_in_object_value vs) values\n\nlet global_variables_unaddressed_in_initializer (vs: list var_id_t) (initializer: initializer_t)\n  : GTot bool =\n  match initializer.iv with\n  | InitializerArbitrary _ -> true\n  | InitializerSpecific value -> global_variables_unaddressed_in_object_value vs value\n\nlet global_variables_unaddressed_in_initializers (vs: list var_id_t) (initializers: list initializer_t)\n  : GTot bool =\n  for_all_ghost (global_variables_unaddressed_in_initializer vs) initializers\n\nlet global_variables_unaddressed_in_initializers_equivalent_to_forall\n  (vs: list var_id_t)\n  (initializers: list initializer_t)\n  : Lemma (ensures global_variables_unaddressed_in_initializers vs initializers <==>\n                   (forall initializer. contains_ubool initializer initializers ==>\n                                   global_variables_unaddressed_in_initializer vs initializer))\n          [SMTPat (global_variables_unaddressed_in_initializers vs initializers)] =\n  for_all_ghost_equivalent_to_forall (global_variables_unaddressed_in_initializer vs) initializers\n\nlet rec global_variables_unaddressed_in_rvalue_expression (vs: list var_id_t) (e: expression_t)\n  : GTot bool =\n  match e with\n  | ExpressionConstant value -> global_variables_unaddressed_in_object_value vs value\n  | ExpressionGlobalVariable _ var_id -> true\n  | ExpressionLocalVariable _ _ -> true\n  | ExpressionUnaryOperator _ _ _ operand -> global_variables_unaddressed_in_rvalue_expression vs operand\n  | ExpressionBinaryOperator _ _ _ _ operand1 operand2 ->\n        global_variables_unaddressed_in_rvalue_expression vs operand1\n      && global_variables_unaddressed_in_rvalue_expression vs operand2\n  | ExpressionIf _ cond operand_then operand_else ->\n         global_variables_unaddressed_in_rvalue_expression vs cond\n      && global_variables_unaddressed_in_rvalue_expression vs operand_then\n      && global_variables_unaddressed_in_rvalue_expression vs operand_else\n  | ExpressionDereference _ _ -> true\n  | ExpressionAddressOf obj -> global_variables_unaddressed_in_lvalue_expression vs obj\n  | ExpressionPointerOffset ptr offset -> global_variables_unaddressed_in_rvalue_expression vs ptr\n  | ExpressionFieldOf _ _ _ -> true\n  | ExpressionAllocated ptr -> global_variables_unaddressed_in_rvalue_expression vs ptr\n  | ExpressionApplyFunction _ operands _ _ _ -> global_variables_unaddressed_in_rvalue_expressions vs operands\n  | ExpressionIfUndefined _ potentially_unsafe safe_substitution ->\n         global_variables_unaddressed_in_rvalue_expression vs potentially_unsafe\n      && global_variables_unaddressed_in_rvalue_expression vs safe_substitution\n  | ExpressionInitialTid -> true\n  | ExpressionUniqsUsed -> true\n  | ExpressionStopReason -> true\n\nand global_variables_unaddressed_in_lvalue_expression (vs: list var_id_t) (e: expression_t) : GTot bool =\n  match e with\n  | ExpressionGlobalVariable _ var_id -> not (FStar.List.Tot.contains var_id vs)\n  | ExpressionDereference _ ptr -> global_variables_unaddressed_in_rvalue_expression vs ptr\n  | ExpressionFieldOf td obj field_id -> global_variables_unaddressed_in_lvalue_expression vs obj\n  | _ -> true\n\nand global_variables_unaddressed_in_rvalue_expressions (vs: list var_id_t) (es: list expression_t)\n  : GTot bool =\n  match es with\n  | [] -> true\n  | e :: es' ->\n         global_variables_unaddressed_in_rvalue_expression vs e\n      && global_variables_unaddressed_in_rvalue_expressions vs es'\n\nand global_variables_unaddressed_in_lvalue_expressions (vs: list var_id_t) (es: list expression_t)\n  : GTot bool =\n  match es with\n  | [] -> true\n  | e :: es' ->\n         global_variables_unaddressed_in_lvalue_expression vs e\n      && global_variables_unaddressed_in_lvalue_expressions vs es'\n\nlet rec global_variables_unaddressed_in_rvalue_expressions_equivalent_to_forall\n  (vs: list var_id_t)\n  (es: list expression_t)\n  : Lemma (ensures global_variables_unaddressed_in_rvalue_expressions vs es <==>\n                   (forall e. contains_ubool e es ==> global_variables_unaddressed_in_rvalue_expression vs e))\n          [SMTPat (global_variables_unaddressed_in_rvalue_expressions vs es)] =\n  match es with\n  | [] -> ()\n  | e :: es' -> global_variables_unaddressed_in_rvalue_expressions_equivalent_to_forall vs es'\n\nlet rec global_variables_unaddressed_in_lvalue_expressions_equivalent_to_forall\n  (vs: list var_id_t)\n  (es: list expression_t)\n  : Lemma (ensures global_variables_unaddressed_in_lvalue_expressions vs es <==>\n                   (forall e. contains_ubool e es ==> global_variables_unaddressed_in_lvalue_expression vs e))\n          [SMTPat (global_variables_unaddressed_in_lvalue_expressions vs es)] =\n  match es with\n  | [] -> ()\n  | e :: es' -> global_variables_unaddressed_in_lvalue_expressions_equivalent_to_forall vs es'\n\nlet global_variables_unaddressed_in_optional_lvalue_expression\n  (vs: list var_id_t)\n  (oe: option expression_t)\n  : GTot bool =\n  match oe with\n  | None -> true\n  | Some e -> global_variables_unaddressed_in_lvalue_expression vs e\n\nlet rec global_variables_unmentioned_in_expression (vs: list var_id_t) (e: expression_t)\n  : GTot bool =\n  match e with\n  | ExpressionConstant value -> global_variables_unaddressed_in_object_value vs value\n  | ExpressionGlobalVariable _ var_id -> not (FStar.List.Tot.contains var_id vs)\n  | ExpressionLocalVariable _ var_id -> true\n  | ExpressionUnaryOperator _ _ _ operand -> global_variables_unmentioned_in_expression vs operand\n  | ExpressionBinaryOperator _ _ _ _ operand1 operand2 ->\n         global_variables_unmentioned_in_expression vs operand1\n      && global_variables_unmentioned_in_expression vs operand2\n  | ExpressionIf _ cond operand_then operand_else ->\n         global_variables_unmentioned_in_expression vs cond\n      && global_variables_unmentioned_in_expression vs operand_then\n      && global_variables_unmentioned_in_expression vs operand_else\n  | ExpressionDereference _ ptr -> global_variables_unmentioned_in_expression vs ptr\n  | ExpressionAddressOf obj -> global_variables_unmentioned_in_expression vs obj\n  | ExpressionPointerOffset ptr offset ->\n         global_variables_unmentioned_in_expression vs ptr\n      && global_variables_unmentioned_in_expression vs offset\n  | ExpressionFieldOf _ obj _ -> global_variables_unmentioned_in_expression vs obj\n  | ExpressionAllocated ptr -> global_variables_unmentioned_in_expression vs ptr\n  | ExpressionApplyFunction _ operands _ _ _ -> global_variables_unmentioned_in_expressions vs operands\n  | ExpressionIfUndefined _ potentially_unsafe safe_substitution ->\n         global_variables_unmentioned_in_expression vs potentially_unsafe\n      && global_variables_unmentioned_in_expression vs safe_substitution\n  | ExpressionInitialTid -> true\n  | ExpressionUniqsUsed -> true\n  | ExpressionStopReason -> true\n\nand global_variables_unmentioned_in_expressions (vs: list var_id_t) (es: list expression_t)\n  : GTot bool =\n  match es with\n  | [] -> true\n  | e :: es' -> global_variables_unmentioned_in_expression vs e && global_variables_unmentioned_in_expressions vs es'\n\nlet rec global_variables_unmentioned_in_expressions_equivalent_to_forall (vs: list var_id_t) (es: list expression_t)\n  : Lemma (ensures global_variables_unmentioned_in_expressions vs es <==>\n                   (forall e. contains_ubool e es ==> global_variables_unmentioned_in_expression vs e))\n          [SMTPat (global_variables_unmentioned_in_expressions vs es)] =\n  match es with\n  | [] -> ()\n  | e :: es' -> global_variables_unmentioned_in_expressions_equivalent_to_forall vs es'\n\nlet global_variables_unmentioned_in_optional_expression (vs: list var_id_t) (oe: option expression_t)\n  : GTot bool =\n  match oe with\n  | None -> true\n  | Some e -> global_variables_unmentioned_in_expression vs e\n\nlet global_variables_unaddressed_in_reads_clause\n  (vs: list var_id_t)\n  (reads_clause: var_id_t * expression_t)\n  : GTot bool =\n  global_variables_unaddressed_in_rvalue_expression vs (snd reads_clause)\n\nlet global_variables_unaddressed_in_reads_clauses\n  (vs: list var_id_t)\n  (reads_clauses: list (var_id_t * expression_t))\n  : GTot bool =\n  for_all_ghost (global_variables_unaddressed_in_reads_clause vs) reads_clauses\n\nlet global_variables_unmentioned_in_reads_clause\n  (vs: list var_id_t)\n  (reads_clause: var_id_t * expression_t)\n  : GTot bool =\n  global_variables_unmentioned_in_expression vs (snd reads_clause)\n\nlet global_variables_unmentioned_in_reads_clauses\n  (vs: list var_id_t)\n  (reads_clauses: list (var_id_t * expression_t))\n  : GTot bool =\n  for_all_ghost (global_variables_unmentioned_in_reads_clause vs) reads_clauses\n\nlet rec object_td_lacks_pointer_field (td: object_td_t) : GTot bool (decreases rank td) =\n  all_seq_facts_lemma ();\n  match td with\n  | ObjectTDPrimitive primitive_td -> not (PrimitiveTDPointer? primitive_td)\n  | ObjectTDStruct field_tds -> object_tds_lack_pointer_field field_tds\n  | ObjectTDArray element_td _ -> object_td_lacks_pointer_field element_td\n  | ObjectTDAbstract _ -> true\n\nand object_tds_lack_pointer_field (tds: seq object_td_t) : GTot bool (decreases rank tds) =\n  all_seq_facts_lemma ();\n    length tds = 0\n  || (   object_td_lacks_pointer_field (index tds 0)\n     && object_tds_lack_pointer_field (drop tds 1))\n\nlet rec object_tds_lack_pointer_field_equivalent_to_forall (tds: seq object_td_t)\n  : Lemma (ensures object_tds_lack_pointer_field tds <==>\n                     (forall td. contains tds td ==> object_td_lacks_pointer_field td))\n          (decreases rank tds)\n          [SMTPat (object_tds_lack_pointer_field tds)] =\n  all_seq_facts_lemma ();\n  if length tds = 0 then\n    ()\n  else\n    object_tds_lack_pointer_field_equivalent_to_forall (drop tds 1)\n\nlet expression_lacks_pointer_field (e: expression_t) : GTot bool =\n  object_td_lacks_pointer_field (expression_to_td e)\n\nlet expressions_lack_pointer_field (es: list expression_t) : GTot bool =\n  for_all_ghost expression_lacks_pointer_field es\n\nlet global_variables_unaddressed_at_top_level_in_rvalue_expression\n  (vs: list var_id_t)\n  (e: expression_t)\n  : GTot bool =\n    global_variables_unaddressed_in_rvalue_expression vs e\n  || expression_lacks_pointer_field e\n\nlet global_variables_unaddressed_at_top_level_in_rvalue_expressions\n  (vs: list var_id_t)\n  (es: list expression_t)\n  : GTot bool =\n  for_all_ghost (global_variables_unaddressed_at_top_level_in_rvalue_expression vs) es\n\nlet global_variables_unaddressed_at_top_level_in_optional_rvalue_expression\n  (vs: list var_id_t)\n  (oe: option expression_t)\n  : GTot bool =\n  match oe with\n  | None -> true\n  | Some e -> global_variables_unaddressed_at_top_level_in_rvalue_expression vs e\n\nlet global_variables_unmodifiable_by_statement\n  (vs: list var_id_t)\n  (statement: Armada.Statement.t)\n  : GTot bool =\n  match statement with\n  | UpdateStatement _ dst _ -> global_variables_unaddressed_in_lvalue_expression vs dst\n  | NondeterministicUpdateStatement _ dst -> global_variables_unaddressed_in_lvalue_expression vs dst\n  | PropagateWriteMessageStatement -> false\n  | CompareAndSwapStatement target _ _ _ optional_result ->\n         global_variables_unaddressed_in_lvalue_expression vs target\n      && global_variables_unaddressed_in_optional_lvalue_expression vs optional_result\n  | AtomicExchangeStatement old_val target _ ->\n         global_variables_unaddressed_in_lvalue_expression vs old_val\n      && global_variables_unaddressed_in_lvalue_expression vs target\n  | CreateThreadStatement _ _ _ optional_result _ parameter_expressions local_variable_initializers ->\n      global_variables_unaddressed_in_optional_lvalue_expression vs optional_result\n      && global_variables_unaddressed_in_rvalue_expressions vs parameter_expressions\n      && global_variables_unaddressed_in_initializers vs local_variable_initializers\n  | ReturnStatement _ _ output_dsts output_srcs ->\n         global_variables_unaddressed_in_lvalue_expressions vs output_dsts\n      && global_variables_unaddressed_in_rvalue_expressions vs output_srcs\n  | MallocSuccessfulStatement _ result _ _ ->\n      global_variables_unaddressed_in_lvalue_expression vs result\n  | MallocReturningNullStatement _ result _ ->\n      global_variables_unaddressed_in_lvalue_expression vs result\n  | CallocSuccessfulStatement _ result _ _ ->\n      global_variables_unaddressed_in_lvalue_expression vs result\n  | CallocReturningNullStatement _ result _ ->\n      global_variables_unaddressed_in_lvalue_expression vs result\n  | SomehowStatement _ _ modifies_clauses _ ->\n         global_variables_unaddressed_in_lvalue_expressions vs modifies_clauses\n      && expressions_lack_pointer_field modifies_clauses\n  | ExternalMethodStartStatement _ _ _ modifies_clauses _ ->\n         global_variables_unaddressed_in_lvalue_expressions vs modifies_clauses\n      && expressions_lack_pointer_field modifies_clauses\n  | ExternalMethodMiddleStatement _ modifies_clauses _ ->\n         global_variables_unaddressed_in_lvalue_expressions vs modifies_clauses\n      && expressions_lack_pointer_field modifies_clauses\n  | _ -> true\n\nlet global_variables_unaddressable_in_statement\n  (vs: list var_id_t)\n  (statement: Armada.Statement.t)\n  : GTot bool =\n  match statement with\n  | UpdateStatement _ dst src ->\n       global_variables_unaddressed_at_top_level_in_rvalue_expression vs src\n  | NondeterministicUpdateStatement _ dst ->\n       expression_lacks_pointer_field dst\n  | CompareAndSwapStatement target _ new_val _ optional_result ->\n         global_variables_unaddressed_at_top_level_in_rvalue_expression vs new_val\n  | AtomicExchangeStatement _ _ new_val ->\n         global_variables_unaddressed_at_top_level_in_rvalue_expression vs new_val\n  | CreateThreadStatement _ _ _ _ parameter_var_ids parameter_expressions\n                          local_variable_initializers ->\n         global_variables_unaddressed_at_top_level_in_rvalue_expressions vs parameter_expressions\n      && global_variables_unaddressed_in_initializers vs local_variable_initializers\n  | MethodCallStatement _ _ parameter_var_ids parameter_expressions local_variable_initializers _ ->\n         global_variables_unaddressed_at_top_level_in_rvalue_expressions vs parameter_expressions\n      && global_variables_unaddressed_in_initializers vs local_variable_initializers\n  | ReturnStatement _ _ output_dsts output_srcs ->\n      global_variables_unaddressed_at_top_level_in_rvalue_expressions vs output_srcs\n\n  // For SomehowStatement, we have no idea what's put into the\n  // destinations specified in modifies clauses.  So all we can do is\n  // make sure that none of those destinations has any pointer fields.\n  \n  | SomehowStatement _ _ modifies_clauses _ ->\n      expressions_lack_pointer_field modifies_clauses\n\n  // For ExternalMethodStartStatement and\n  // ExternalMethodMiddleStatement, we have no idea what's put into\n  // the destinations specified in modifies clauses.  So all we can do\n  // is make sure that none of those destinations has any pointer\n  // fields.\n\n  | ExternalMethodStartStatement _ _ _ modifies_clauses reads_clauses ->\n         expressions_lack_pointer_field modifies_clauses\n      && global_variables_unaddressed_in_reads_clauses vs reads_clauses\n  | ExternalMethodMiddleStatement _ modifies_clauses reads_clauses ->\n        expressions_lack_pointer_field modifies_clauses\n      && global_variables_unaddressed_in_reads_clauses vs reads_clauses\n  | _ -> true\n\nlet rec global_variables_unaddressed_in_storage (vs: list var_id_t) (storage: object_storage_t)\n  : GTot ubool (decreases rank storage) =\n  all_seq_facts_lemma ();\n  match storage with\n  | ObjectStorageWeaklyConsistentPrimitive _ values _ ->\n      global_variables_unaddressed_in_boxes vs values\n  | ObjectStoragePrimitive value -> global_variables_unaddressed_in_box vs value\n  | ObjectStorageStruct fields -> global_variables_unaddressed_in_storages vs fields\n  | ObjectStorageArray _ elements -> global_variables_unaddressed_in_storages vs elements\n  | ObjectStorageAbstract _ _ -> true\n\nand global_variables_unaddressed_in_storages (vs: list var_id_t) (storages: seq object_storage_t)\n  : GTot ubool (decreases rank storages) =\n  all_seq_facts_lemma ();\n    length storages = 0\n  \\/ (  global_variables_unaddressed_in_storage vs (index storages 0)\n     /\\ global_variables_unaddressed_in_storages vs (drop storages 1))\n\nlet rec global_variables_unaddressed_in_storages_equivalent_to_forall\n  (vs: list var_id_t)\n  (storages: seq object_storage_t)\n  : Lemma (ensures global_variables_unaddressed_in_storages vs storages <==>\n                   (forall storage. contains storages storage ==> global_variables_unaddressed_in_storage vs storage))\n          (decreases rank storages)\n          [SMTPat (global_variables_unaddressed_in_storages vs storages)] =\n  all_seq_facts_lemma ();\n  if length storages = 0 then\n    ()\n  else\n     global_variables_unaddressed_in_storages_equivalent_to_forall vs (drop storages 1)\n\nlet global_variables_unaddressed_in_root (vs: list var_id_t) (root: root_t) : GTot ubool =\n  match root with\n  | RootGlobal storage -> global_variables_unaddressed_in_storage vs storage\n  | RootStackVariable pushed popped storage ->\n      (not pushed) \\/ global_variables_unaddressed_in_storage vs storage\n  | RootAllocated allocated freed storage ->\n      (not allocated) \\/ global_variables_unaddressed_in_storage vs storage\n  | _ -> True\n\nlet global_variables_unaddressed_in_memory (vs: list var_id_t) (mem: Armada.Memory.t) : GTot ubool =\n  forall root_id. global_variables_unaddressed_in_root vs (mem root_id)\n\nlet global_variables_unaddressed_in_write_message (vs: list var_id_t) (write_message: write_message_t) : GTot bool =\n  global_variables_unaddressed_in_pointer vs write_message.location\n\nlet global_variables_unaddressed_in_write_messages (vs: list var_id_t) (write_messages: seq write_message_t)\n  : GTot ubool =\n  forall write_message. contains write_messages write_message ==>\n                     global_variables_unaddressed_in_write_message vs write_message\n\nlet global_variables_unaddressed_in_thread (vs: list var_id_t) (thread: Armada.Thread.t) : GTot ubool =\n  global_variables_unaddressed_in_write_messages vs thread.write_buffer\n\nlet global_variables_unaddressed_in_threads (vs: list var_id_t) (threads: Armada.Threads.t) : GTot ubool =\n  forall tid. global_variables_unaddressed_in_thread vs (threads tid)\n\nlet global_variables_unaddressed_in_state (vs: list var_id_t) (s: Armada.State.t) : GTot ubool =\n     global_variables_unaddressed_in_memory vs s.mem\n  /\\ global_variables_unaddressed_in_threads vs s.threads\n\nlet rec remove_global_variables_from_write_buffer\n  (vs: list var_id_t)\n  (write_messages: list write_message_t)\n  : GTot (list write_message_t) =\n  match write_messages with\n  | [] -> []\n  | hd :: tl ->\n      if global_variables_unaddressed_in_write_message vs hd then\n        hd :: (remove_global_variables_from_write_buffer vs tl)\n      else\n        remove_global_variables_from_write_buffer vs tl\n\nlet write_buffers_match_except_global_variables\n  (vs: list var_id_t)\n  (write_messages1: seq write_message_t)\n  (write_messages2: seq write_message_t)\n  : GTot ubool =\n  write_buffers_match (remove_global_variables_from_write_buffer vs (seq_to_list write_messages1))\n    (remove_global_variables_from_write_buffer vs (seq_to_list write_messages2))\n\nlet unread_write_buffer\n  (threads: Armada.Threads.t{positions_valid_in_threads threads})\n  (sender_tid: tid_t)\n  (receiver_tid: tid_t)\n  : GTot (seq write_message_t) =\n  let write_buffer = (threads sender_tid).write_buffer in\n  let position_in_other_write_buffers = (threads receiver_tid).position_in_other_write_buffers in\n  let position = position_in_other_write_buffers sender_tid in\n  assert (sender_receiver_trigger sender_tid receiver_tid);\n  drop write_buffer position\n\nlet positions_in_write_buffers_match_except_global_variables\n  (vs: list var_id_t)\n  (threads1: Armada.Threads.t{positions_valid_in_threads threads1})\n  (threads2: Armada.Threads.t{positions_valid_in_threads threads2})\n  : GTot ubool =\n  forall sender_tid receiver_tid.{:pattern sender_receiver_trigger sender_tid receiver_tid}\n     sender_receiver_trigger sender_tid receiver_tid\n     ==> write_buffers_match_except_global_variables vs\n           (unread_write_buffer threads1 sender_tid receiver_tid)\n           (unread_write_buffer threads2 sender_tid receiver_tid)\n\nlet threads_match_except_global_variables\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (threads1: Armada.Threads.t{positions_valid_in_threads threads1})\n  (threads2: Armada.Threads.t{positions_valid_in_threads threads2})\n  : GTot ubool =\n    threads_match_except_write_buffers_per_pc_relation pc_relation threads1 threads2\n  /\\ positions_in_write_buffers_match_except_global_variables vs threads1 threads2\n\nlet memories_match_except_global_variables (vs: list var_id_t) (mem1: Armada.Memory.t) (mem2: Armada.Memory.t)\n  : GTot ubool =\n  forall root_id.{:pattern mem1 root_id; mem2 root_id}\n            (match root_id with\n             | RootIdGlobal v -> FStar.List.Tot.contains v vs \\/ (mem1 root_id == mem2 root_id)\n             | _ -> mem1 root_id == mem2 root_id)\n\nlet states_match_except_global_variables\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  : GTot ubool =\n    s1.initial_tid = s2.initial_tid\n  /\\ s1.uniqs_used = s2.uniqs_used\n  /\\ memories_match_except_global_variables vs s1.mem s2.mem\n  /\\ positions_valid_in_state s1\n  /\\ positions_valid_in_state s2\n  /\\ threads_match_except_global_variables vs pc_relation s1.threads s2.threads\n  /\\ s1.trace == s2.trace\n  /\\ s1.stop_reason = s2.stop_reason\n\nlet equality_pc_relation_implies_state_matches_itself_except_global_variables\n  (vs: list var_id_t)\n  (s: Armada.State.t)\n  : Lemma (requires positions_valid_in_state s)\n          (ensures  states_match_except_global_variables vs equality_pc_relation s s) =\n  introduce forall tid. stacks_match_per_pc_relation equality_pc_relation (s.threads tid).stack (s.threads tid).stack\n  with equality_pc_relation_implies_stack_matches_itself (s.threads tid).stack;\n  assert (threads_match_except_write_buffers_per_pc_relation equality_pc_relation s.threads s.threads);\n  introduce forall sender_tid receiver_tid.\n              sender_receiver_trigger sender_tid receiver_tid ==>\n              write_buffers_match_except_global_variables vs\n                (unread_write_buffer s.threads sender_tid receiver_tid)\n                (unread_write_buffer s.threads sender_tid receiver_tid)\n  with introduce _ ==> _\n  with _.\n    equality_pc_relation_implies_write_buffer_matches_itself\n      (remove_global_variables_from_write_buffer vs\n        (seq_to_list (unread_write_buffer s.threads sender_tid receiver_tid)))\n"
  },
  {
    "path": "experimental/lib/Strategies.GlobalVarsProof.fst",
    "content": "module Strategies.GlobalVarsProof\n\nopen FStar.Sequence.Ambient\nopen FStar.Sequence.Base\n\nopen Util.Seq\nopen Util.Trigger\nopen Spec.List\nopen Spec.Ubool\n\nopen Armada.Base\nopen Armada.BinaryOp\nopen Armada.Computation\nopen Armada.Expression\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Pointer\nopen Armada.State\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Type\nopen Armada.Transition\nopen Armada.UnaryOp\n\nopen Strategies.Invariant\nopen Strategies.ArmadaInvariant.PositionsValid\nopen Strategies.ArmadaInvariant.RootsMatch\nopen Strategies.GlobalVars\nopen Strategies.GlobalVars.Util\nopen Strategies.GlobalVars.Unaddressed\nopen Strategies.ArmadaStatement\n\nlet ($$) (#a: Type) (#b: Type) (f: a -> b) (x: a): b = f x\nlet ($$$) (#a: Type) (f: a -> GTot (conditional_computation_t a)) (x: a): GTot (conditional_computation_t a) = f x\n\nlet memories_match_on_global_variables\n  (vs: list var_id_t)\n  (mem1 mem2: Armada.Memory.t)\n  : GTot ubool\n  = forall v . list_contains v vs ==>\n      mem1 (RootIdGlobal v) == mem2 (RootIdGlobal v)\n\nlet states_match_on_global_variables\n  (vs: list var_id_t)\n  (s1 s2: Armada.State.t)\n  : GTot ubool\n  = memories_match_on_global_variables vs s1.mem s2.mem\n\n\nlet state_well_formed (vs: list var_id_t) (s: Armada.State.t): GTot ubool =\n  roots_match s.mem /\\ positions_valid_in_state s /\\ global_variables_unaddressed_in_memory vs s.mem\n\nlet rec update_pointer_directly_with_gvars_unaddressed_memories_match_on_global_variables\n  (vs: list var_id_t)\n  (p: Armada.Pointer.t)\n  (new_storage: valid_object_storage_t)\n  (mem: Armada.Memory.t)\n  : Lemma (requires global_variables_unaddressed_in_pointer vs p)\n          (ensures  otherwise True begin\n                      let? mem' = update_pointer_directly p new_storage mem in\n                      return $$$ memories_match_on_global_variables vs mem mem'\n                    end) =\n  match p with\n  | PointerField struct_ptr field_id ->\n      (match dereference_computation struct_ptr mem with\n       | ComputationProduces parent ->\n           (match parent with\n            | ObjectStorageStruct fields ->\n                if   field_id >= length fields\n                   || neqb (object_storage_to_td new_storage)\n                          (object_storage_to_td (index fields field_id)) then\n                  ()\n                  else (\n                  let new_parent = update_storage_child parent field_id new_storage in\n                    update_pointer_directly_with_gvars_unaddressed_memories_match_on_global_variables\n                      vs struct_ptr new_parent mem\n                )\n            | _ -> ())\n      | _ -> ())\n  | PointerIndex array_ptr idx ->\n      (match dereference_computation array_ptr mem with\n       | ComputationProduces parent ->\n           (match parent with\n            | ObjectStorageArray element_td elements ->\n                if   idx < 0\n                   || idx >= length elements\n                   || neqb (object_storage_to_td new_storage) element_td then\n                  ()\n                else (\n                  let new_parent = update_storage_child parent idx new_storage in\n                  update_pointer_directly_with_gvars_unaddressed_memories_match_on_global_variables\n                    vs array_ptr new_parent mem\n                )\n            | _ -> ())\n      | _ -> ())\n  | _ -> ()\n\nlet update_pointer_with_object_with_gvars_unaddressed_memories_match_on_global_variables\n  (vs: list var_id_t)\n  (p: Armada.Pointer.t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (new_value: object_value_t)\n  (mem: Armada.Memory.t)\n  : Lemma (requires global_variables_unaddressed_in_pointer vs p)\n          (ensures  otherwise True begin\n                      let? v = update_pointer p actor writer_pc writer_expression_number bypassing_write_buffer new_value mem in\n                      return $$$ memories_match_on_global_variables vs mem (snd v)\n                    end) =\n  match p with\n  | PointerUninitialized -> ()\n  | PointerNull -> ()\n  | PointerRoot root_id ->\n      let root = mem root_id in\n      (match root_to_storage_computation root with\n       | ComputationProduces storage ->\n           ()\n       | _ -> ())\n  | PointerField struct_ptr field_id ->\n      (match dereference_computation struct_ptr mem with\n       | ComputationProduces parent ->\n          (match parent with\n           | ObjectStorageStruct fields ->\n               if field_id >= length fields then\n                 ()\n               else\n                 let field = index fields field_id in\n                 if not (object_storage_valid field) || neqb (object_storage_to_td field) (object_value_to_td new_value) then\n                   ()\n                 else (\n                   (match update_storage p actor writer_pc writer_expression_number\n                            bypassing_write_buffer field new_value with\n                    | ComputationProduces (write_message, new_field) ->\n                        if (not (can_update_storage_child parent field_id new_field)) then\n                          ()\n                        else (\n                          let new_parent = update_storage_child parent field_id new_field in\n                          update_pointer_directly_with_gvars_unaddressed_memories_match_on_global_variables\n                            vs struct_ptr new_parent mem\n                        )\n                    | _ -> ()\n                   ))\n          | _ -> ())\n       | _ -> ())\n  | PointerIndex array_ptr idx ->\n      (match dereference_computation array_ptr mem with\n       | ComputationProduces parent ->\n          (match parent with\n           | ObjectStorageArray element_td elements ->\n               if idx < 0 || idx >= length elements then\n                 ()\n               else\n                 let element = index elements idx in\n                 if not (object_storage_valid element) then\n                   ()\n                 else (\n                   (match update_storage p actor writer_pc writer_expression_number\n                            bypassing_write_buffer element new_value with\n                    | ComputationProduces (write_message, new_element) ->\n                        if not (can_update_storage_child parent idx new_element) then\n                          ()\n                        else (\n                          let new_parent = update_storage_child parent idx new_element in\n                          update_pointer_directly_with_gvars_unaddressed_memories_match_on_global_variables\n                            vs array_ptr new_parent mem\n                        )\n                    | _ -> ()\n                   ))\n          | _ -> ())\n       | _ -> ())\n\nlet update_pointed_to_value_with_gvars_unaddressed_memories_match_on_global_variables\n  (vs: list var_id_t)\n  (p: Armada.Pointer.t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (new_value: object_value_t)\n  (s: Armada.State.t)\n  : Lemma (requires   global_variables_unaddressed_in_pointer vs p)\n          (ensures  (match update_pointed_to_value p actor writer_pc writer_expression_number bypassing_write_buffer new_value s with\n                      | ComputationProduces s' -> states_match_on_global_variables vs s s'\n                      | _ -> True)) =\n  update_pointer_with_object_with_gvars_unaddressed_memories_match_on_global_variables vs p actor writer_pc\n    writer_expression_number bypassing_write_buffer new_value s.mem;\n  match update_pointer p actor writer_pc writer_expression_number bypassing_write_buffer new_value s.mem with\n  | ComputationProduces (optional_write_message, new_mem) -> begin\n      match optional_write_message with\n      | Some write_message ->\n          let thread = s.threads actor in\n          let new_write_buffer = build thread.write_buffer write_message in\n          let new_thread = { thread with write_buffer = new_write_buffer } in\n          let new_threads = Spec.Map.upd s.threads actor new_thread in\n          let s' = { s with mem = new_mem; threads = new_threads; } in\n          assert (states_match_on_global_variables vs s s')\n      | None ->\n          let s' = { s with mem = new_mem; } in\n          assert (states_match_on_global_variables vs s s')\n      | _ -> false_elim ()\n  end\n  | _ -> ()\n\n#push-options \"--z3rlimit 10\"\n\nlet update_expression_with_gvars_unaddressed_in_lvalue_memories_match_on_global_variables\n  (vs: list var_id_t)\n  (exp: expression_t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (new_value: object_value_t)\n  (s: Armada.State.t)\n  : Lemma (requires   global_variables_unaddressed_in_lvalue_expression vs exp\n                    /\\ state_well_formed vs s)\n          (ensures  otherwise True begin\n                      let? s' = update_expression exp actor writer_pc writer_expression_number bypassing_write_buffer new_value s in\n                      return $$$ states_match_on_global_variables vs s s'\n                    end) =\n  if   not (expression_valid exp)\n          || not (object_value_valid new_value)\n          || neqb (object_value_to_td new_value) (expression_to_td exp) then\n    ()\n  else begin\n    let td = expression_to_td exp in\n    match lvalue_computation exp actor s with\n    | ComputationProduces p ->\n        lvalue_computation_when_gvars_unaddressed_produces_value_with_gvars_unaddressed vs exp actor s;\n        update_pointed_to_value_with_gvars_unaddressed_memories_match_on_global_variables vs p actor writer_pc writer_expression_number bypassing_write_buffer new_value s;\n        (match update_pointed_to_value p actor writer_pc writer_expression_number bypassing_write_buffer\n                 new_value s with\n         | ComputationProduces s' -> ()\n         | _ -> ())\n    | _ -> ()\n  end\n\n#pop-options\n\nlet rec update_expressions_with_gvars_unaddressed_in_both_values_memories_match_on_global_variables\n  (vs: list var_id_t)\n  (exps: list expression_t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (new_values: list object_value_t)\n  (s: Armada.State.t)\n  : Lemma (requires   state_well_formed vs s\n                    /\\ global_variables_unaddressed_in_object_values vs new_values\n                    /\\ global_variables_unaddressed_in_lvalue_expressions vs exps)\n          (ensures otherwise True begin\n                     let? s' = update_expressions exps actor writer_pc writer_expression_number bypassing_write_buffer new_values s in\n                     return $$$ states_match_on_global_variables vs s s'\n                   end)\n  = match exps, new_values with\n    | [], [] -> ()\n    | first_exp :: remaining_exps, first_new_value :: remaining_new_values -> begin\n      update_expression_with_gvars_unaddressed_maintains_gvars_unaddressed vs first_exp actor writer_pc\n        writer_expression_number bypassing_write_buffer first_new_value s;\n      update_expression_with_gvars_unaddressed_in_lvalue_memories_match_on_global_variables vs first_exp actor writer_pc writer_expression_number bypassing_write_buffer first_new_value s;\n      match update_expression first_exp actor writer_pc writer_expression_number\n               bypassing_write_buffer first_new_value s with\n       | ComputationProduces s_next ->\n           update_expressions_with_gvars_unaddressed_in_both_values_memories_match_on_global_variables vs\n             remaining_exps actor writer_pc (writer_expression_number + 1)\n             bypassing_write_buffer remaining_new_values s_next\n       | _ -> ()\n    end\n    | _ -> ()\n\nlet rec update_expressions_with_gvars_unaddressed_in_lvalues_and_lacking_pointer_field_memories_match_on_global_variables\n  (vs: list var_id_t)\n  (exps: list expression_t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (new_values: list object_value_t)\n  (s: Armada.State.t)\n  : Lemma (requires   state_well_formed vs s\n                    /\\ expressions_lack_pointer_field exps\n                    /\\ global_variables_unaddressed_in_lvalue_expressions vs exps)\n          (ensures otherwise True begin\n                     let? s' = update_expressions exps actor writer_pc writer_expression_number bypassing_write_buffer new_values s in\n                     return $$$ states_match_on_global_variables vs s s'\n                   end)\n  = match exps, new_values with\n    | [], [] -> ()\n    | first_exp :: remaining_exps, first_new_value :: remaining_new_values -> begin\n      update_expression_lacking_pointer_field_maintains_gvars_unaddressed vs first_exp actor writer_pc\n        writer_expression_number bypassing_write_buffer first_new_value s;\n      update_expression_with_gvars_unaddressed_in_lvalue_memories_match_on_global_variables vs first_exp actor writer_pc writer_expression_number bypassing_write_buffer first_new_value s;\n      match update_expression first_exp actor writer_pc writer_expression_number\n               bypassing_write_buffer first_new_value s with\n       | ComputationProduces s_next ->\n           update_expressions_with_gvars_unaddressed_in_lvalues_and_lacking_pointer_field_memories_match_on_global_variables vs\n             remaining_exps actor writer_pc (writer_expression_number + 1)\n             bypassing_write_buffer remaining_new_values s_next\n       | _ -> ()\n    end\n    | _ -> ()\n\n#push-options \"--z3rlimit 10\"\n\nlet rec push_stack_parameters_memories_match_on_global_variables\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (var_ids: list var_id_t)\n  (parameters: list object_value_t)\n  (s: Armada.State.t)\n  : Lemma (requires True)\n          (ensures otherwise True begin\n                      let? s' = push_stack_parameters actor writer_pc writer_expression_number method_id frame_uniq var_ids parameters s in\n                      return $$$ states_match_on_global_variables vs s s'\n                    end)\n          (decreases parameters) =\n  match parameters, var_ids with\n  | [], [] -> ()\n  | first_parameter :: remaining_parameters, first_var_id :: remaining_var_ids ->\n      let first_initializer =\n        { var_id = first_var_id; iv = InitializerSpecific first_parameter; weakly_consistent = false } in\n      (match push_stack_variable actor writer_pc writer_expression_number method_id frame_uniq first_initializer s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces s' ->\n           push_stack_parameters_memories_match_on_global_variables vs actor writer_pc (writer_expression_number + 1)\n             method_id frame_uniq remaining_var_ids remaining_parameters s')\n  | _ -> ()\n\n#pop-options\n\nlet rec push_stack_variables_memories_match_on_global_variables\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (initializers: list initializer_t)\n  (s: Armada.State.t)\n  : Lemma (requires True)\n          (ensures  otherwise True begin\n                      let? s' = push_stack_variables actor writer_pc writer_expression_number method_id frame_uniq initializers s in\n                      return $$$ states_match_on_global_variables vs s s'\n                    end)\n          (decreases initializers) =\n  match initializers with\n  | [] -> ()\n  | first_initializer :: remaining_initializers ->\n      (match push_stack_variable actor writer_pc writer_expression_number method_id frame_uniq first_initializer s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces s' ->\n           push_stack_variables_memories_match_on_global_variables vs actor writer_pc (writer_expression_number + 1)\n             method_id frame_uniq remaining_initializers s')\n\nlet rec pop_stack_variables_maintains_state_well_formed\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (var_ids: list var_id_t)\n  (s: Armada.State.t)\n  : Lemma (requires state_well_formed vs s)\n          (ensures otherwise True begin\n                     let? mem' = pop_stack_variables actor method_id frame_uniq var_ids s.mem in\n                     return $$$ state_well_formed vs ({ s with mem = mem' })\n                   end)\n  = match var_ids with\n    | [] -> ()\n    | first_var_id :: remaining_var_ids -> begin\n      match pop_stack_variable actor method_id frame_uniq first_var_id s.mem with\n      | ComputationProduces mem' ->\n        assert (state_well_formed vs ({s with mem = mem'}));\n        pop_stack_variables_maintains_state_well_formed vs actor method_id frame_uniq remaining_var_ids ({s with mem = mem'})\n      | _ -> ()\n    end\n\nlet rec pop_stack_variables_memories_match_on_global_variables\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (var_ids: list var_id_t)\n  (mem: Armada.Memory.t)\n  : Lemma (requires True)\n          (ensures otherwise True begin\n                     let? mem' = pop_stack_variables actor method_id frame_uniq var_ids mem in\n                     return $$$ memories_match_on_global_variables vs mem mem'\n                   end)\n  = match var_ids with\n    | [] -> ()\n    | first_var_id :: remaining_var_ids -> begin\n      match pop_stack_variable actor method_id frame_uniq first_var_id mem with\n      | ComputationProduces mem' ->\n        assert (memories_match_on_global_variables vs mem mem');\n        pop_stack_variables_memories_match_on_global_variables vs actor method_id frame_uniq remaining_var_ids mem'\n      | _ -> ()\n    end\n\n\nlet push_stack_variable_maintains_state_well_formed\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (initializer: initializer_t)\n  (s: Armada.State.t)\n  : Lemma (requires state_well_formed vs s\n                    /\\ global_variables_unaddressed_in_initializer vs initializer)\n          (ensures  otherwise True begin\n                      let? s' = push_stack_variable actor writer_pc writer_expression_number method_id frame_uniq initializer s in\n                      return $$$ state_well_formed vs s'\n                    end) =\n  let root_id = RootIdStack actor method_id frame_uniq initializer.var_id in\n  let root = s.mem root_id in\n  if not (stack_variable_ready_for_push root initializer) then\n    ()\n  else\n    let thread = s.threads actor in\n    let var_id = initializer.var_id in\n    if list_contains var_id thread.top.local_variables then\n      ()\n    else\n      let local_variables' = var_id :: thread.top.local_variables in\n      let top' = { thread.top with local_variables = local_variables' } in\n      let thread' = { thread with top = top' } in\n      let threads' = Spec.Map.upd s.threads actor thread' in\n      let storage = RootStackVariable?.storage root in\n      assert (object_storage_arbitrarily_initialized_correctly storage);\n      object_storage_arbitrarily_initialized_correctly_doesnt_depend_on_gvars vs storage;\n      let root' = RootStackVariable true false (RootStackVariable?.storage root) in\n      assert (global_variables_unaddressed_in_root vs root');\n      let mem' = Spec.Map.upd s.mem root_id root' in\n      let mem_unaddressed(): Lemma (ensures global_variables_unaddressed_in_memory vs mem') =\n        introduce forall root_id' . global_variables_unaddressed_in_root vs (mem' root_id')\n        with\n          if root_id = root_id' then\n            ()\n          else\n            ()\n      in\n      mem_unaddressed();\n      let s' = { s with mem = mem'; threads = threads' } in\n      (match initializer.iv with\n       | InitializerArbitrary td -> ()\n       | InitializerSpecific value ->\n           push_stack_variable_maintains_roots_match actor writer_pc writer_expression_number method_id frame_uniq initializer s';\n           let td = (object_value_to_td value) in\n           update_expression_with_gvars_unaddressed_maintains_gvars_unaddressed vs (ExpressionLocalVariable td var_id) actor writer_pc\n             writer_expression_number false value s')\n\nlet rec push_stack_variables_maintains_state_well_formed\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (initializers: list initializer_t)\n  (s: Armada.State.t)\n  : Lemma (requires    state_well_formed vs s\n                    /\\ global_variables_unaddressed_in_initializers vs initializers)\n          (ensures  otherwise True begin\n                      let? s' = push_stack_variables actor writer_pc writer_expression_number method_id frame_uniq initializers s in\n                      return $$$ state_well_formed vs s'\n                    end)\n          (decreases initializers) =\n  match initializers with\n  | [] -> ()\n  | first_initializer :: remaining_initializers ->\n      (match push_stack_variable actor writer_pc writer_expression_number method_id frame_uniq first_initializer s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces s' ->\n           assert (global_variables_unaddressed_in_initializer vs first_initializer);\n           push_stack_variable_maintains_state_well_formed vs actor writer_pc writer_expression_number method_id frame_uniq first_initializer s;\n           assert (state_well_formed vs s');\n           push_stack_variables_maintains_state_well_formed vs actor writer_pc (writer_expression_number + 1)\n             method_id frame_uniq remaining_initializers s')\n\nlet rec push_stack_parameters_maintains_state_well_formed\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (method_id: method_id_t)\n  (frame_uniq: root_id_uniquifier_t)\n  (var_ids: list var_id_t)\n  (parameters: list object_value_t)\n  (s: Armada.State.t)\n  : Lemma (requires state_well_formed vs s\n                    /\\ global_variables_unaddressed_in_object_values vs parameters)\n          (ensures  otherwise True begin\n                      let? s' = push_stack_parameters actor writer_pc writer_expression_number method_id frame_uniq var_ids parameters s in\n                      return $$$ state_well_formed vs s'\n                    end)\n          (decreases parameters) =\n  match parameters, var_ids with\n  | [], [] -> ()\n  | first_parameter :: remaining_parameters, first_var_id :: remaining_var_ids ->\n      let first_initializer =\n        { var_id = first_var_id; iv = InitializerSpecific first_parameter; weakly_consistent = false } in\n      assert (global_variables_unaddressed_in_initializer vs first_initializer);\n      push_stack_variable_maintains_state_well_formed vs actor writer_pc writer_expression_number method_id frame_uniq first_initializer s;\n      (match push_stack_variable actor writer_pc writer_expression_number method_id frame_uniq first_initializer s with\n       | ComputationImpossible | ComputationUndefined -> ()\n       | ComputationProduces s' ->\n           push_stack_parameters_maintains_state_well_formed vs actor writer_pc (writer_expression_number + 1)\n             method_id frame_uniq remaining_var_ids remaining_parameters s')\n  | _ -> ()\n\nlet mark_allocation_root_allocated_state_well_formed\n  (vs: list var_id_t)\n  (uniq: root_id_uniquifier_t)\n  (storage: valid_object_storage_t)\n  (s: Armada.State.t)\n  : Lemma (requires   state_well_formed vs s\n                    /\\ global_variables_unaddressed_in_storage vs storage)\n          (ensures state_well_formed vs (mark_allocation_root_allocated uniq storage s))\n  = ()\n\nlet rec log_expressions_computation_memories_match_on_global_variables\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (logs_clauses: list expression_t)\n  (s: Armada.State.t)\n  : Lemma (ensures otherwise True begin\n                     let? s' = log_expressions_computation actor logs_clauses s in\n                     return $$$ states_match_on_global_variables vs s s'\n                   end) =\n  match logs_clauses with\n  | [] -> ()\n  | first_logs_clause :: remaining_logs_clauses -> begin\n      match rvalue_computation first_logs_clause actor s with\n      | ComputationProduces event ->\n        let trace' = s.trace $:: event in\n        let s' = { s with trace = trace' } in\n        log_expressions_computation_memories_match_on_global_variables vs actor remaining_logs_clauses s'\n      | _ -> ()\n  end\n\nlet update_statement_memories_match_on_global_variables\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (step: Armada.Step.t)\n  (starts_atomic_block ends_atomic_block: bool)\n  (s: Armada.State.t)\n  : Lemma (requires   UpdateStatement? step.action.program_statement.statement\n                    /\\ global_variables_unmodifiable_by_statement vs step.action.program_statement.statement\n                    /\\ Some? (step_computation actor starts_atomic_block ends_atomic_block step s)\n                    /\\ state_well_formed vs s)\n          (ensures  states_match_on_global_variables vs s (Some?.v $$ step_computation actor starts_atomic_block ends_atomic_block step s))\n  = if step.action.ok then begin\n       let stmt = step.action.program_statement.statement in\n       let thread = s.threads actor in\n       let dst = UpdateStatement?.dst stmt in\n       let bypassing_write_buffer = UpdateStatement?.bypassing_write_buffer stmt in\n       let new_value = ComputationProduces?.result $$ rvalue_computation (UpdateStatement?.src stmt) actor s in\n       update_expression_with_gvars_unaddressed_in_lvalue_memories_match_on_global_variables vs dst actor thread.pc 0 bypassing_write_buffer new_value s\n    end\n\n#push-options \"--z3rlimit 10\"\n\nlet compare_and_swap_statement_memories_match_on_global_variables\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (step: Armada.Step.t)\n  (starts_atomic_block ends_atomic_block: bool)\n  (s: Armada.State.t)\n  : Lemma (requires   CompareAndSwapStatement? step.action.program_statement.statement\n                    /\\ global_variables_unmodifiable_by_statement vs step.action.program_statement.statement\n                    /\\ Some? (step_computation actor starts_atomic_block ends_atomic_block step s)\n                    /\\ state_well_formed vs s)\n          (ensures  states_match_on_global_variables vs s (Some?.v $$ step_computation actor starts_atomic_block ends_atomic_block step s))\n  = if step.action.ok then begin\n    let ps = step.action.program_statement in\n      let thread = s.threads actor in\n      let stmt = ps.statement in\n      let target = CompareAndSwapStatement?.target stmt in\n      let old_val = CompareAndSwapStatement?.old_val stmt in\n      let new_val = CompareAndSwapStatement?.new_val stmt in\n      let optional_result = CompareAndSwapStatement?.optional_result stmt in\n      let bypassing_write_buffer = CompareAndSwapStatement?.bypassing_write_buffer stmt in\n      let target_value = ComputationProduces?.result $$ rvalue_computation target actor s in\n      let old_value = ComputationProduces?.result $$ rvalue_computation old_val actor s in\n      let new_value = ComputationProduces?.result $$ rvalue_computation new_val actor s in\n      let target_ptr = ComputationProduces?.result $$ lvalue_computation target actor s in\n      lvalue_computation_when_gvars_unaddressed_produces_value_with_gvars_unaddressed vs target actor s;\n      update_pointed_to_value_with_gvars_unaddressed_memories_match_on_global_variables vs target_ptr actor thread.pc 0 false new_value s;\n      let swap = eqb target_value old_value in\n      let s' = ComputationProduces?.result $$ (if swap then update_expression target actor thread.pc 0 false new_value s else return s) in\n      match optional_result with\n      | Some result ->\n        let swap_value = ObjectValuePrimitive (PrimitiveBoxBool swap) in\n        let result_ptr = ComputationProduces?.result $$ lvalue_computation result actor s in\n        lvalue_computation_when_gvars_unaddressed_produces_value_with_gvars_unaddressed vs result actor s;\n        update_pointed_to_value_with_gvars_unaddressed_memories_match_on_global_variables vs result_ptr actor thread.pc 1 bypassing_write_buffer swap_value s'\n      | _ -> ()\n    end\n\n#pop-options\n\n#push-options \"--z3rlimit 30\"\n\nlet atomic_exchange_statement_memories_match_on_global_variables\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (step: Armada.Step.t)\n  (starts_atomic_block ends_atomic_block: bool)\n  (s: Armada.State.t)\n  : Lemma (requires   AtomicExchangeStatement? step.action.program_statement.statement\n                    /\\ global_variables_unmodifiable_by_statement vs step.action.program_statement.statement\n                    /\\ Some? (step_computation actor starts_atomic_block ends_atomic_block step s)\n                    /\\ state_well_formed vs s)\n          (ensures  states_match_on_global_variables vs s (Some?.v $$ step_computation actor starts_atomic_block ends_atomic_block step s))\n  = if step.action.ok then begin\n       let ps = step.action.program_statement in\n       let stmt = ps.statement in\n       let thread = s.threads actor in\n       let old_val = AtomicExchangeStatement?.old_val stmt in\n       let old_ptr = ComputationProduces?.result $$ lvalue_computation old_val actor s in\n       let new_val = AtomicExchangeStatement?.new_val stmt in\n       let new_value = ComputationProduces?.result $$ rvalue_computation new_val actor s in\n       let target = AtomicExchangeStatement?.target stmt in\n       let target_value = ComputationProduces?.result $$ rvalue_computation target actor s in\n       let target_ptr = ComputationProduces?.result $$ lvalue_computation target actor s in\n\n       let s' = ComputationProduces?.result $$ update_pointed_to_value old_ptr actor thread.pc 0 false target_value s in\n\n       lvalue_computation_when_gvars_unaddressed_produces_value_with_gvars_unaddressed vs old_val actor s;\n       lvalue_computation_when_gvars_unaddressed_produces_value_with_gvars_unaddressed vs target actor s;\n       update_pointed_to_value_with_gvars_unaddressed_memories_match_on_global_variables vs old_ptr actor thread.pc 0 false target_value s;\n       update_pointed_to_value_with_gvars_unaddressed_memories_match_on_global_variables vs target_ptr actor thread.pc 0 false new_value s'\n    end\n\nlet create_thread_statement_memories_match_on_global_variables\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (step: Armada.Step.t)\n  (starts_atomic_block ends_atomic_block: bool)\n  (s: Armada.State.t)\n  : Lemma (requires   CreateThreadStatement? step.action.program_statement.statement\n                    /\\ global_variables_unmodifiable_by_statement vs step.action.program_statement.statement\n                    /\\ Some? (step_computation actor starts_atomic_block ends_atomic_block step s)\n                    /\\ state_well_formed vs s)\n          (ensures  states_match_on_global_variables vs s (Some?.v $$ step_computation actor starts_atomic_block ends_atomic_block step s))\n  = if step.action.ok then begin\n       let ps = step.action.program_statement in\n       let stmt = ps.statement in\n       match stmt with\n       | CreateThreadStatement method_id initial_pc bypassing_write_buffer optional_result parameter_var_ids parameter_expressions local_variable_initializers ->\n         let thread = s.threads actor in\n         let start_pc = thread.pc in\n         let create_thread_nd: create_thread_nd_t = ObjectValueAbstract?.value (Cons?.hd step.nd) in\n         let new_tid = create_thread_nd.new_tid in\n         if new_tid = 0 then\n           match optional_result with\n           | None -> ()\n           | Some result ->\n             let new_tid_value = ObjectValuePrimitive (PrimitiveBoxThreadId new_tid) in\n             update_expression_with_gvars_unaddressed_in_lvalue_memories_match_on_global_variables vs result actor start_pc (list_len parameter_var_ids + list_len local_variable_initializers) bypassing_write_buffer new_tid_value s\n         else begin\n           let new_thread = s.threads new_tid in\n           let frame_uniq = create_thread_nd.frame_uniq in\n           assert (~ (new_thread.status <> ThreadStatusNotStarted\n                  || length new_thread.write_buffer <> 0\n                  || list_contains frame_uniq s.uniqs_used));\n           let parameter_values = ComputationProduces?.result $$ rvalues_computation parameter_expressions actor s in\n           rvalues_computation_when_gvars_unaddressed_produces_value_with_gvars_unaddressed vs parameter_expressions actor s;\n           let s2 = make_thread_running method_id initial_pc new_tid frame_uniq s in\n           assert (states_match_on_global_variables vs s s2);\n           assert (state_well_formed vs s2);\n           let s3 = ComputationProduces?.result $$ push_stack_parameters new_tid start_pc 0 method_id frame_uniq parameter_var_ids parameter_values s2 in\n           push_stack_parameters_maintains_state_well_formed vs new_tid start_pc 0 method_id frame_uniq parameter_var_ids parameter_values s2;\n           push_stack_parameters_memories_match_on_global_variables vs new_tid start_pc 0 method_id frame_uniq parameter_var_ids parameter_values s2;\n           assert (states_match_on_global_variables vs s s3);\n           assert (state_well_formed vs s3);\n           let s4 = ComputationProduces?.result $$ push_stack_variables new_tid start_pc (list_len parameter_var_ids) method_id frame_uniq local_variable_initializers s3 in\n           push_stack_variables_maintains_state_well_formed vs new_tid start_pc (list_len parameter_var_ids) method_id frame_uniq local_variable_initializers s3;\n           push_stack_variables_memories_match_on_global_variables vs new_tid start_pc (list_len parameter_var_ids) method_id frame_uniq local_variable_initializers s3;\n           assert (states_match_on_global_variables vs s s4);\n           assert (state_well_formed vs s4);\n           match optional_result with\n           | None -> ()\n           | Some result ->\n             let new_tid_value = ObjectValuePrimitive (PrimitiveBoxThreadId new_tid) in\n             assert (global_variables_unaddressed_in_lvalue_expression vs result);\n             update_expression_with_gvars_unaddressed_in_lvalue_memories_match_on_global_variables vs result actor start_pc (list_len parameter_var_ids + list_len local_variable_initializers) bypassing_write_buffer new_tid_value s4\n         end\n       | _ -> ()\n    end\n\nlet method_call_statement_memories_match_on_global_variables\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (step: Armada.Step.t)\n  (starts_atomic_block ends_atomic_block: bool)\n  (s: Armada.State.t)\n  : Lemma (requires   MethodCallStatement? step.action.program_statement.statement\n                    /\\ global_variables_unmodifiable_by_statement vs step.action.program_statement.statement\n                    /\\ Some? (step_computation actor starts_atomic_block ends_atomic_block step s)\n                    /\\ state_well_formed vs s)\n          (ensures  states_match_on_global_variables vs s (Some?.v $$ step_computation actor starts_atomic_block ends_atomic_block step s))\n  = if step.action.ok then begin\n       let ps = step.action.program_statement in\n       let stmt = ps.statement in\n       match stmt with\n       | MethodCallStatement method_id return_pc parameter_var_ids parameter_expressions local_variable_initializers stack_overflow ->\n         let thread = s.threads actor in\n         let start_pc = thread.pc in\n         let method_call_nd: method_call_nd_t = ObjectValueAbstract?.value (Cons?.hd step.nd) in\n         let frame_uniq = method_call_nd.frame_uniq in\n         assert (~ (list_contains frame_uniq s.uniqs_used));\n         let parameter_values = ComputationProduces?.result $$ rvalues_computation parameter_expressions actor s in\n         let s2 = push_stack_frame actor method_id return_pc frame_uniq s in\n         assert (states_match_on_global_variables vs s s2);\n         let s3 = ComputationProduces?.result $$ push_stack_parameters actor start_pc 0 method_id frame_uniq parameter_var_ids parameter_values s2 in\n         push_stack_parameters_memories_match_on_global_variables vs actor start_pc 0 method_id frame_uniq parameter_var_ids parameter_values s2;\n         let s4 = ComputationProduces?.result $$ push_stack_variables actor start_pc (list_len parameter_var_ids) method_id frame_uniq local_variable_initializers s3 in\n         push_stack_variables_memories_match_on_global_variables vs actor start_pc (list_len parameter_var_ids) method_id frame_uniq local_variable_initializers s3;\n         ()\n       | _ -> ()\n    end\n\nlet return_statement_memories_match_on_global_variables\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (step: Armada.Step.t)\n  (starts_atomic_block ends_atomic_block: bool)\n  (s: Armada.State.t)\n  : Lemma (requires   ReturnStatement? step.action.program_statement.statement\n                    /\\ global_variables_unmodifiable_by_statement vs step.action.program_statement.statement\n                    /\\ Some? (step_computation actor starts_atomic_block ends_atomic_block step s)\n                    /\\ state_well_formed vs s)\n          (ensures  states_match_on_global_variables vs s (Some?.v $$ step_computation actor starts_atomic_block ends_atomic_block step s))\n  = if step.action.ok then begin\n       let ps = step.action.program_statement in\n       let stmt = ps.statement in\n       match stmt with\n       | ReturnStatement method_id bypassing_write_buffer output_dsts output_srcs ->\n         let thread = s.threads actor in\n         let start_pc = thread.pc in\n         let output_values = ComputationProduces?.result $$ rvalues_computation output_srcs actor s in\n         rvalues_computation_when_gvars_unaddressed_produces_value_with_gvars_unaddressed vs output_srcs actor s;\n         let mem' = ComputationProduces?.result $$ pop_stack_variables actor method_id thread.top.frame_uniq thread.top.local_variables s.mem in\n         pop_stack_variables_memories_match_on_global_variables vs actor method_id thread.top.frame_uniq thread.top.local_variables s.mem;\n         pop_stack_variables_maintains_state_well_formed vs actor method_id thread.top.frame_uniq thread.top.local_variables s;\n         let s2 = pop_stack_frame actor mem' s in\n         assert (states_match_on_global_variables vs s s2);\n         update_expressions_with_gvars_unaddressed_in_both_values_memories_match_on_global_variables vs output_dsts actor start_pc 0 bypassing_write_buffer output_values s2\n       | _ -> ()\n    end\n\n#pop-options\n\nlet terminate_thread_statement_memories_match_on_global_variables\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (step: Armada.Step.t)\n  (starts_atomic_block ends_atomic_block: bool)\n  (s: Armada.State.t)\n  : Lemma (requires   TerminateThreadStatement? step.action.program_statement.statement\n                    /\\ global_variables_unmodifiable_by_statement vs step.action.program_statement.statement\n                    /\\ Some? (step_computation actor starts_atomic_block ends_atomic_block step s)\n                    /\\ state_well_formed vs s)\n          (ensures  states_match_on_global_variables vs s (Some?.v $$ step_computation actor starts_atomic_block ends_atomic_block step s))\n  = if step.action.ok then begin\n       let ps = step.action.program_statement in\n       let stmt = ps.statement in\n       match stmt with\n       | TerminateThreadStatement method_id ->\n         let thread = s.threads actor in\n         let start_pc = thread.pc in\n         let mem' = ComputationProduces?.result $$ pop_stack_variables actor method_id thread.top.frame_uniq thread.top.local_variables s.mem in\n         pop_stack_variables_memories_match_on_global_variables vs actor method_id thread.top.frame_uniq thread.top.local_variables s.mem;\n         pop_stack_variables_maintains_state_well_formed vs actor method_id thread.top.frame_uniq thread.top.local_variables s;\n         let thread' = { thread with status = ThreadStatusJoinable } in\n         let threads' = Spec.Map.upd s.threads actor thread' in\n         let s' = { s with mem = mem'; threads = threads' } in\n         assert (states_match_on_global_variables vs s s')\n       | _ -> ()\n    end\n\n#push-options \"--z3rlimit 30\"\n\nlet alloc_successful_statement_memories_match_on_global_variables\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (step: Armada.Step.t)\n  (starts_atomic_block ends_atomic_block: bool)\n  (s: Armada.State.t)\n  : Lemma (requires   (MallocSuccessfulStatement? step.action.program_statement.statement || CallocSuccessfulStatement? step.action.program_statement.statement)\n                    /\\ global_variables_unmodifiable_by_statement vs step.action.program_statement.statement\n                    /\\ Some? (step_computation actor starts_atomic_block ends_atomic_block step s)\n                    /\\ state_well_formed vs s)\n          (ensures  states_match_on_global_variables vs s (Some?.v $$ step_computation actor starts_atomic_block ends_atomic_block step s))\n  = if step.action.ok then begin\n       let ps = step.action.program_statement in\n       let stmt = ps.statement in\n       match stmt with\n       | CallocSuccessfulStatement bypassing_write_buffer result allocation_td count\n       | MallocSuccessfulStatement bypassing_write_buffer result allocation_td count ->\n         let thread = s.threads actor in\n         let start_pc = thread.pc in\n         let count_value = ComputationProduces?.result $$ rvalue_computation count actor s in\n         let sz = ObjectValueAbstract?.value count_value in\n         let array_td = ObjectTDArray allocation_td sz in\n         let uniq = ObjectValueAbstract?.value (Cons?.hd step.nd) in\n         let root_id = RootIdAllocation uniq in\n         match s.mem root_id with\n         | RootAllocated allocated freed storage ->\n           let storage_doesnt_depend_on_gvars (): Lemma (ensures global_variables_unaddressed_in_storage vs storage) =\n             if (object_storage_arbitrarily_initialized_correctly storage) then\n               object_storage_arbitrarily_initialized_correctly_doesnt_depend_on_gvars vs storage\n             else\n               object_storage_zero_filled_doesnt_depend_on_gvars vs storage\n           in\n           storage_doesnt_depend_on_gvars ();\n           let s' = mark_allocation_root_allocated uniq storage s in\n           mark_allocation_root_allocated_state_well_formed vs uniq storage s;\n           let p = ObjectValuePrimitive (PrimitiveBoxPointer (PointerIndex (PointerRoot root_id) 0)) in\n           update_expression_with_gvars_unaddressed_in_lvalue_memories_match_on_global_variables vs result actor start_pc 0 bypassing_write_buffer p s'\n         | _ -> ()\n       | _ -> ()\n    end\n\n#pop-options\n\nlet nondeterministic_update_statement_memories_match_on_global_variables\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (step: Armada.Step.t)\n  (starts_atomic_block ends_atomic_block: bool)\n  (s: Armada.State.t)\n  : Lemma (requires   NondeterministicUpdateStatement? step.action.program_statement.statement\n                    /\\ global_variables_unmodifiable_by_statement vs step.action.program_statement.statement\n                    /\\ Some? (step_computation actor starts_atomic_block ends_atomic_block step s)\n                    /\\ state_well_formed vs s)\n          (ensures  states_match_on_global_variables vs s (Some?.v $$ step_computation actor starts_atomic_block ends_atomic_block step s))\n  = if step.action.ok then begin\n       let ps = step.action.program_statement in\n       let stmt = ps.statement in\n       match stmt with\n       | NondeterministicUpdateStatement bypassing_write_buffer dst ->\n         let thread = s.threads actor in\n         let start_pc = thread.pc in\n         let nd_value = Cons?.hd step.nd in\n         update_expression_with_gvars_unaddressed_in_lvalue_memories_match_on_global_variables vs dst actor start_pc 0 bypassing_write_buffer nd_value s\n       | _ -> ()\n    end\n\nlet alloc_returning_null_statement_memories_match_on_global_variables\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (step: Armada.Step.t)\n  (starts_atomic_block ends_atomic_block: bool)\n  (s: Armada.State.t)\n  : Lemma (requires   (MallocReturningNullStatement? step.action.program_statement.statement || CallocReturningNullStatement? step.action.program_statement.statement)\n                    /\\ global_variables_unmodifiable_by_statement vs step.action.program_statement.statement\n                    /\\ Some? (step_computation actor starts_atomic_block ends_atomic_block step s)\n                    /\\ state_well_formed vs s)\n          (ensures  states_match_on_global_variables vs s (Some?.v $$ step_computation actor starts_atomic_block ends_atomic_block step s))\n  = if step.action.ok then begin\n       let ps = step.action.program_statement in\n       let stmt = ps.statement in\n       match stmt with\n       | MallocReturningNullStatement bypassing_write_buffer result count\n       | CallocReturningNullStatement bypassing_write_buffer result count ->\n         let thread = s.threads actor in\n         let start_pc = thread.pc in\n         let p = ObjectValuePrimitive (PrimitiveBoxPointer PointerNull) in\n         update_expression_with_gvars_unaddressed_in_lvalue_memories_match_on_global_variables vs result actor start_pc 0 bypassing_write_buffer p s\n       | _ -> ()\n    end\n\nlet somehow_statement_memories_match_on_global_variables\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (step: Armada.Step.t)\n  (starts_atomic_block ends_atomic_block: bool)\n  (s: Armada.State.t)\n  : Lemma (requires   SomehowStatement? step.action.program_statement.statement\n                    /\\ global_variables_unmodifiable_by_statement vs step.action.program_statement.statement\n                    /\\ Some? (step_computation actor starts_atomic_block ends_atomic_block step s)\n                    /\\ state_well_formed vs s)\n          (ensures  states_match_on_global_variables vs s (Some?.v $$ step_computation actor starts_atomic_block ends_atomic_block step s))\n  = if step.action.ok then begin\n       let ps = step.action.program_statement in\n       let stmt = ps.statement in\n       match stmt with\n       | SomehowStatement undefined_unless_cond bypassing_write_buffer modifies_clauses ensures_cond ->\n         let thread = s.threads actor in\n         let start_pc = thread.pc in\n         update_expressions_with_gvars_unaddressed_in_lvalues_and_lacking_pointer_field_memories_match_on_global_variables vs modifies_clauses actor start_pc 0 bypassing_write_buffer step.nd s\n       | _ -> ()\n    end\n\nlet rec external_method_take_snapshot_of_reads_clauses_computation_memories_match_on_global_variables\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (writer_pc: pc_t)\n  (writer_expression_number: nat)\n  (bypassing_write_buffer: bool)\n  (reads_clauses: list (var_id_t * expression_t))\n  (s: Armada.State.t)\n  : Lemma (requires True)\n          (ensures otherwise True begin\n                     let? s' = external_method_take_snapshot_of_reads_clauses_computation actor writer_pc writer_expression_number bypassing_write_buffer reads_clauses s in\n                     return $$$ states_match_on_global_variables vs s s'\n                   end)\n          (decreases reads_clauses)\n  = match reads_clauses with\n  | [] -> ()\n  | (first_var_id, first_reads_expression) :: remaining_reads_clauses -> begin\n    match rvalue_computation first_reads_expression actor s with\n    | ComputationProduces first_value -> begin\n      let td = expression_to_td first_reads_expression in\n      let local_var = ExpressionLocalVariable td first_var_id in\n      match lvalue_computation local_var actor s with\n      | ComputationProduces p -> begin\n        assert (global_variables_unaddressed_in_pointer vs p);\n        match update_pointed_to_value p actor writer_pc writer_expression_number bypassing_write_buffer first_value s with\n        | ComputationProduces s' ->\n          update_pointed_to_value_with_gvars_unaddressed_memories_match_on_global_variables vs p actor writer_pc writer_expression_number bypassing_write_buffer first_value s;\n          external_method_take_snapshot_of_reads_clauses_computation_memories_match_on_global_variables vs actor writer_pc (writer_expression_number + 1) bypassing_write_buffer remaining_reads_clauses s'\n        | _ -> ()\n      end\n      | _ -> ()\n    end\n    | _ -> ()\n  end\n\nlet external_method_start_statement_memories_match_on_global_variables\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (step: Armada.Step.t)\n  (starts_atomic_block ends_atomic_block: bool)\n  (s: Armada.State.t)\n  : Lemma (requires   ExternalMethodStartStatement? step.action.program_statement.statement\n                    /\\ global_variables_unmodifiable_by_statement vs step.action.program_statement.statement\n                    /\\ Some? (step_computation actor starts_atomic_block ends_atomic_block step s)\n                    /\\ state_well_formed vs s)\n          (ensures  states_match_on_global_variables vs s (Some?.v $$ step_computation actor starts_atomic_block ends_atomic_block step s))\n  = if step.action.ok then begin\n       let ps = step.action.program_statement in\n       let stmt = ps.statement in\n       match stmt with\n       | ExternalMethodStartStatement await_cond undefined_unless_cond bypassing_write_buffer modifies_clauses reads_clauses ->\n         let thread = s.threads actor in\n         let start_pc = thread.pc in\n         let s2 = ComputationProduces?.result $$ update_expressions modifies_clauses actor start_pc 0 bypassing_write_buffer step.nd s in\n         update_expressions_with_gvars_unaddressed_in_lvalues_and_lacking_pointer_field_memories_match_on_global_variables vs modifies_clauses actor start_pc 0 bypassing_write_buffer step.nd s;\n         external_method_take_snapshot_of_reads_clauses_computation_memories_match_on_global_variables vs actor start_pc (list_len modifies_clauses) bypassing_write_buffer reads_clauses s2\n       | _ -> ()\n    end\n\nlet external_method_middle_statement_memories_match_on_global_variables\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (step: Armada.Step.t)\n  (starts_atomic_block ends_atomic_block: bool)\n  (s: Armada.State.t)\n  : Lemma (requires   ExternalMethodMiddleStatement? step.action.program_statement.statement\n                    /\\ global_variables_unmodifiable_by_statement vs step.action.program_statement.statement\n                    /\\ Some? (step_computation actor starts_atomic_block ends_atomic_block step s)\n                    /\\ state_well_formed vs s)\n          (ensures  states_match_on_global_variables vs s (Some?.v $$ step_computation actor starts_atomic_block ends_atomic_block step s))\n  = if step.action.ok then begin\n       let ps = step.action.program_statement in\n       let stmt = ps.statement in\n       match stmt with\n       | ExternalMethodMiddleStatement bypassing_write_buffer modifies_clauses reads_clauses ->\n         let thread = s.threads actor in\n         let start_pc = thread.pc in\n         let s2 = ComputationProduces?.result $$ update_expressions modifies_clauses actor start_pc 0 bypassing_write_buffer step.nd s in\n         update_expressions_with_gvars_unaddressed_in_lvalues_and_lacking_pointer_field_memories_match_on_global_variables vs modifies_clauses actor start_pc 0 bypassing_write_buffer step.nd s;\n         external_method_take_snapshot_of_reads_clauses_computation_memories_match_on_global_variables vs actor start_pc (list_len modifies_clauses) bypassing_write_buffer reads_clauses s2\n       | _ -> ()\n    end\n\nlet external_method_end_statement_memories_match_on_global_variables\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (step: Armada.Step.t)\n  (starts_atomic_block ends_atomic_block: bool)\n  (s: Armada.State.t)\n  : Lemma (requires   ExternalMethodEndStatement? step.action.program_statement.statement\n                    /\\ global_variables_unmodifiable_by_statement vs step.action.program_statement.statement\n                    /\\ Some? (step_computation actor starts_atomic_block ends_atomic_block step s)\n                    /\\ state_well_formed vs s)\n          (ensures  states_match_on_global_variables vs s (Some?.v $$ step_computation actor starts_atomic_block ends_atomic_block step s))\n  = if step.action.ok then begin\n       let ps = step.action.program_statement in\n       let stmt = ps.statement in\n       match stmt with\n       | ExternalMethodEndStatement ensures_cond logs_clauses ->\n         let thread = s.threads actor in\n         let start_pc = thread.pc in\n         log_expressions_computation_memories_match_on_global_variables vs actor logs_clauses s\n       | _ -> ()\n    end\n\n#push-options \"--z3rlimit 30\"\n\nlet global_variables_unmodifiable_by_statement_memories_matches_on_global_variables\n  (vs: list var_id_t)\n  (actor: tid_t)\n  (step: Armada.Step.t)\n  (starts_atomic_block ends_atomic_block: bool)\n  (s: Armada.State.t)\n  : Lemma (requires   global_variables_unmodifiable_by_statement vs step.action.program_statement.statement\n                    /\\ Some? (step_computation actor starts_atomic_block ends_atomic_block step s)\n                    /\\ state_well_formed vs s)\n          (ensures  states_match_on_global_variables vs s (Some?.v $$ step_computation actor starts_atomic_block ends_atomic_block step s))\n  = match step.action.program_statement.statement with\n    | UpdateStatement bypassing_write_buffer dst src ->\n      update_statement_memories_match_on_global_variables vs actor step starts_atomic_block ends_atomic_block s\n    | NondeterministicUpdateStatement bypassing_write_buffer dst ->\n      nondeterministic_update_statement_memories_match_on_global_variables vs actor step starts_atomic_block ends_atomic_block s\n    | CompareAndSwapStatement target old_val new_val bypassing_write_buffer optional_result ->\n      compare_and_swap_statement_memories_match_on_global_variables vs actor step starts_atomic_block ends_atomic_block s\n    | AtomicExchangeStatement old_val target new_val ->\n      atomic_exchange_statement_memories_match_on_global_variables vs actor step starts_atomic_block ends_atomic_block s\n    | CreateThreadStatement method_id initial_pc bypassing_write_buffer optional_result parameter_var_ids\n                            parameter_expressions local_variable_initializers -> create_thread_statement_memories_match_on_global_variables vs actor step starts_atomic_block ends_atomic_block s\n    | MethodCallStatement method_id return_pc parameter_var_ids parameter_expressions local_variable_initializers\n                          stack_overflow ->\n      method_call_statement_memories_match_on_global_variables vs actor step starts_atomic_block ends_atomic_block s\n    | ReturnStatement method_id bypassing_write_buffer output_dsts output_srcs ->\n      return_statement_memories_match_on_global_variables vs actor step starts_atomic_block ends_atomic_block s\n    | TerminateThreadStatement method_id ->\n      terminate_thread_statement_memories_match_on_global_variables vs actor step starts_atomic_block ends_atomic_block s\n    | MallocSuccessfulStatement bypassing_write_buffer result allocation_td count\n    | CallocSuccessfulStatement bypassing_write_buffer result allocation_td count ->\n      alloc_successful_statement_memories_match_on_global_variables vs actor step starts_atomic_block ends_atomic_block s\n    | MallocReturningNullStatement bypassing_write_buffer result count\n    | CallocReturningNullStatement bypassing_write_buffer result count ->\n      alloc_returning_null_statement_memories_match_on_global_variables vs actor step starts_atomic_block ends_atomic_block s\n    | SomehowStatement undefined_unless_cond bypassing_write_buffer modifies_clauses ensures_cond ->\n      somehow_statement_memories_match_on_global_variables vs actor step starts_atomic_block ends_atomic_block s\n    | ExternalMethodStartStatement await_cond undefined_unless_cond bypassing_write_buffer\n                                   modifies_clauses reads_clauses ->\n      external_method_start_statement_memories_match_on_global_variables vs actor step starts_atomic_block ends_atomic_block s\n    | ExternalMethodMiddleStatement bypassing_write_buffer modifies_clauses reads_clauses ->\n      external_method_middle_statement_memories_match_on_global_variables vs actor step starts_atomic_block ends_atomic_block s\n    | ExternalMethodEndStatement ensures_cond logs_clauses ->\n      external_method_end_statement_memories_match_on_global_variables vs actor step starts_atomic_block ends_atomic_block s\n    | _ -> ()\n\n#pop-options\n"
  },
  {
    "path": "experimental/lib/Strategies.Invariant.Armada.Atomic.fst",
    "content": "module Strategies.Invariant.Armada.Atomic\n\nopen FStar.List.Tot\nopen Spec.Behavior\nopen Strategies.Atomic\nopen Strategies.Invariant.Armada\nopen Strategies.Invariant.Atomic\nopen Util.List\n\nnoeq type armada_atomic_semantics_invariant_proof_t = {\n  program: program_t (make_atomic_semantics armada_semantics);\n  inv: invariant_t Armada.State.t;\n  action_pred: Armada.Action.t -> GTot ubool;\n  special_case_proofs: list (option (armada_atomic_special_case_invariant_proof_t inv));\n  init_implies_inv_proof: (s: Armada.State.t{program.init_f s}) -> squash (inv s);\n  action_proof: armada_action_maintains_invariant_proof_t inv action_pred;\n  special_cases_apply_proof: unit ->\n     squash (armada_atomic_special_cases_apply inv action_pred program.actions special_case_proofs);\n}\n\nlet transform_special_case_proof\n  (inv: invariant_t Armada.State.t)\n  (atomic_action: list Armada.Action.t)\n  (special_case_proof:\n     ((actor: tid_t) ->\n      (starts_atomic_block: bool) ->\n      (ends_atomic_block: bool) ->\n      (atomic_step: list Armada.Step.t) ->\n      (s: Armada.State.t{\n          map_ghost armada_step_to_action atomic_step == atomic_action\n        /\\ inv s\n        /\\ Some? (steps_computation actor starts_atomic_block ends_atomic_block atomic_step s)}) ->\n      squash (inv (Some?.v (steps_computation actor starts_atomic_block ends_atomic_block atomic_step s)))))\n  : GTot ((actor: armada_semantics.actor_t) ->\n          (starts_atomic_block: bool) ->\n          (ends_atomic_block: bool) ->\n          (atomic_step: list armada_semantics.step_t) ->\n          (s: armada_semantics.state_t{\n              map_ghost armada_semantics.step_to_action_f atomic_step == atomic_action\n            /\\ inv s\n            /\\ Some? (steps_computation_generic armada_semantics actor starts_atomic_block\n                       ends_atomic_block atomic_step s)}) ->\n          squash (inv (Some?.v (steps_computation_generic armada_semantics actor starts_atomic_block\n                                  ends_atomic_block atomic_step s)))) =\n  fun actor starts_atomic_block ends_atomic_block atomic_step s -> (\n    armada_steps_computation_equivalent actor starts_atomic_block ends_atomic_block atomic_step s;\n    special_case_proof actor starts_atomic_block ends_atomic_block atomic_step s\n  )\n\nlet transform_special_case\n  (inv: invariant_t Armada.State.t)\n  (proof: armada_atomic_special_case_invariant_proof_t inv)\n  : GTot (atomic_special_case_invariant_proof_t armada_semantics inv) =\n  match proof with\n  | ArmadaAtomicSpecialCaseInvariantProof atomic_action special_case_proof ->\n      AtomicSpecialCaseInvariantProof atomic_action (transform_special_case_proof inv atomic_action special_case_proof)\n\nlet transform_optional_special_case\n  (inv: invariant_t Armada.State.t)\n  (optional_proof: option (armada_atomic_special_case_invariant_proof_t inv))\n  : GTot (option (atomic_special_case_invariant_proof_t armada_semantics inv)) =\n  match optional_proof with\n  | None -> None\n  | Some proof -> Some (transform_special_case inv proof)\n\nlet transform_special_cases\n  (inv: invariant_t Armada.State.t)\n  (proofs: list (option (armada_atomic_special_case_invariant_proof_t inv)))\n  : GTot (list (option (atomic_special_case_invariant_proof_t armada_semantics inv))) =\n  map_ghost (transform_optional_special_case inv) proofs\n\nlet armada_atomic_semantics_invariant_proof_implies_is_invariant\n  (asip: armada_atomic_semantics_invariant_proof_t)\n  : Lemma (is_invariant_of_spec asip.inv (semantics_to_spec (make_atomic_semantics armada_semantics) asip.program)) =\n  asip.special_cases_apply_proof ();\n  map_preserves_lists_correspond_ubool\n    (armada_atomic_proof_option_applies asip.inv asip.action_pred)\n    (atomic_proof_option_applies armada_semantics asip.inv asip.action_pred)\n    (transform_optional_special_case asip.inv)\n    asip.program.actions\n    asip.special_case_proofs;\n  let sip: atomic_semantics_invariant_proof_t = {\n    sem = armada_semantics;\n    program = asip.program;\n    inv = asip.inv;\n    action_pred = asip.action_pred;\n    special_case_proofs = transform_special_cases asip.inv asip.special_case_proofs;\n    init_implies_inv_proof = asip.init_implies_inv_proof;\n    action_proof = asip.action_proof;\n    special_cases_apply_proof = asip.special_cases_apply_proof;\n  } in\n  atomic_semantics_invariant_proof_implies_is_invariant sip\n\nlet armada_atomic_semantics_invariant_proof_implies_stepwise_invariant\n  (asip: armada_atomic_semantics_invariant_proof_t)\n  : Lemma (semantics_has_stepwise_inductive_invariant (make_atomic_semantics armada_semantics) asip.program asip.inv) =\n  asip.special_cases_apply_proof ();\n  map_preserves_lists_correspond_ubool\n    (armada_atomic_proof_option_applies asip.inv asip.action_pred)\n    (atomic_proof_option_applies armada_semantics asip.inv asip.action_pred)\n    (transform_optional_special_case asip.inv)\n    asip.program.actions\n    asip.special_case_proofs;\n  let sip: atomic_semantics_invariant_proof_t = {\n    sem = armada_semantics;\n    program = asip.program;\n    inv = asip.inv;\n    action_pred = asip.action_pred;\n    special_case_proofs = transform_special_cases asip.inv asip.special_case_proofs;\n    init_implies_inv_proof = asip.init_implies_inv_proof;\n    action_proof = asip.action_proof;\n    special_cases_apply_proof = asip.special_cases_apply_proof;\n  } in\n  atomic_semantics_invariant_proof_implies_stepwise_invariant sip\n\nlet armada_atomic_semantics_invariant_witness_valid_implies_is_invariant\n  (program: program_t (make_atomic_semantics armada_semantics))\n  (inv: invariant_t Armada.State.t)\n  (aiw: armada_atomic_semantics_invariant_witness_t program inv)\n  (* see .fsti file for spec *) =\n  let aip: armada_atomic_semantics_invariant_proof_t = {\n    program = program;\n    inv = inv;\n    action_pred = aiw.action_pred;\n    special_case_proofs = aiw.special_case_proofs;\n    init_implies_inv_proof = aiw.init_implies_inv_proof;\n    action_proof = aiw.action_proof;\n    special_cases_apply_proof = (fun _ -> ());\n  } in\n  armada_atomic_semantics_invariant_proof_implies_is_invariant aip\n\nlet armada_atomic_semantics_invariant_witness_valid_implies_stepwise_invariant\n  (program: program_t (make_atomic_semantics armada_semantics))\n  (inv: invariant_t Armada.State.t)\n  (aiw: armada_atomic_semantics_invariant_witness_t program inv)\n  (* see .fsti file for spec *) =\n  let aip: armada_atomic_semantics_invariant_proof_t = {\n    program = program;\n    inv = inv;\n    action_pred = aiw.action_pred;\n    special_case_proofs = aiw.special_case_proofs;\n    init_implies_inv_proof = aiw.init_implies_inv_proof;\n    action_proof = aiw.action_proof;\n    special_cases_apply_proof = (fun _ -> ());\n  } in\n  armada_atomic_semantics_invariant_proof_implies_stepwise_invariant aip\n"
  },
  {
    "path": "experimental/lib/Strategies.Invariant.Armada.Atomic.fsti",
    "content": "module Strategies.Invariant.Armada.Atomic\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Step\nopen Armada.Transition\nopen FStar.List.Tot\nopen Spec.Behavior\nopen Spec.List\nopen Spec.Ubool\nopen Strategies.Atomic\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\nopen Strategies.Invariant\nopen Strategies.Invariant.Armada\nopen Strategies.Invariant.Atomic\nopen Util.List\n\nnoeq type armada_atomic_special_case_invariant_proof_t (inv: invariant_t Armada.State.t) =\n  | ArmadaAtomicSpecialCaseInvariantProof :\n     (atomic_action: list Armada.Action.t) ->\n     (special_case_proof:\n       ((actor: tid_t) ->\n        (starts_atomic_block: bool) ->\n        (ends_atomic_block: bool) ->\n        (atomic_step: list Armada.Step.t) ->\n        (s: Armada.State.t{\n             map_ghost armada_step_to_action atomic_step == atomic_action\n           /\\ inv s\n           /\\ Some? (steps_computation actor starts_atomic_block ends_atomic_block atomic_step s)}) ->\n        squash (inv (Some?.v (steps_computation actor starts_atomic_block ends_atomic_block atomic_step s))))) ->\n  armada_atomic_special_case_invariant_proof_t inv\n\nlet armada_atomic_proof_option_applies\n  (inv: invariant_t Armada.State.t)\n  (action_pred: Armada.Action.t -> GTot ubool)\n  (atomic_action: list Armada.Action.t)\n  (proof_option: option (armada_atomic_special_case_invariant_proof_t inv))\n  : GTot ubool =\n  match proof_option with\n  | None -> for_all_ubool action_pred atomic_action\n  | Some prf -> prf.atomic_action == atomic_action\n\nlet armada_atomic_special_cases_apply\n  (inv: invariant_t Armada.State.t)\n  (action_pred: Armada.Action.t -> GTot ubool)\n  (atomic_actions: list (list Armada.Action.t))\n  (special_case_proofs: (list (option (armada_atomic_special_case_invariant_proof_t inv)))) =\n  lists_correspond_ubool (armada_atomic_proof_option_applies inv action_pred) atomic_actions special_case_proofs\n\nnoeq type armada_atomic_semantics_invariant_witness_t\n  (program: program_t (make_atomic_semantics armada_semantics))\n  (inv: invariant_t Armada.State.t) =\n{\n  action_pred: Armada.Action.t -> GTot ubool;\n  special_case_proofs: list (option (armada_atomic_special_case_invariant_proof_t inv));\n  init_implies_inv_proof: (s: Armada.State.t{program.init_f s}) -> squash (inv s);\n  action_proof: armada_action_maintains_invariant_proof_t inv action_pred;\n}\n\nlet armada_atomic_semantics_invariant_witness_valid\n  (program: program_t (make_atomic_semantics armada_semantics))\n  (inv: invariant_t Armada.State.t)\n  (aiw: armada_atomic_semantics_invariant_witness_t program inv)\n  : GTot ubool =\n  armada_atomic_special_cases_apply inv aiw.action_pred program.actions aiw.special_case_proofs\n\nval armada_atomic_semantics_invariant_witness_valid_implies_is_invariant\n  (program: program_t (make_atomic_semantics armada_semantics))\n  (inv: invariant_t Armada.State.t)\n  (aiw: armada_atomic_semantics_invariant_witness_t program inv)\n  : Lemma (requires armada_atomic_semantics_invariant_witness_valid program inv aiw)\n          (ensures  is_invariant_of_spec inv (semantics_to_spec (make_atomic_semantics armada_semantics) program))\n\nval armada_atomic_semantics_invariant_witness_valid_implies_stepwise_invariant\n  (program: program_t (make_atomic_semantics armada_semantics))\n  (inv: invariant_t Armada.State.t)\n  (aiw: armada_atomic_semantics_invariant_witness_t program inv)\n  : Lemma (requires armada_atomic_semantics_invariant_witness_valid program inv aiw)\n          (ensures  semantics_has_stepwise_inductive_invariant (make_atomic_semantics armada_semantics) program inv)\n"
  },
  {
    "path": "experimental/lib/Strategies.Invariant.Armada.AtomicSubstep.fst",
    "content": "module Strategies.Invariant.Armada.AtomicSubstep\n\nopen FStar.List.Tot\nopen Strategies.Atomic\nopen Strategies.Invariant\nopen Strategies.Semantics.Armada\nopen Util.List\n\nlet armada_atomic_substep_invariant_witness_valid_implies_inv_preserved_on_step\n  (program: program_t (make_atomic_semantics armada_semantics))\n  (inv: invariant_t Armada.State.t)\n  (aiw: armada_atomic_substep_invariant_witness_t program inv)\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (step: Armada.Step.t)\n  (s: Armada.State.t)\n  (actions: list Armada.Action.t)\n  (s': Armada.State.t)\n  : Lemma (requires   armada_atomic_substep_invariant_witness_valid program inv aiw\n                    /\\ contains_ubool actions program.actions\n                    /\\ contains_ubool step.action actions\n                    /\\ inv s\n                    /\\ Some s' == step_computation actor starts_atomic_block ends_atomic_block step s)\n          (ensures  inv s') =\n  let proofs = get_correspondent_from_lists_correspond_ubool\n    (lists_correspond_ubool (armada_action_proof_option_applies inv aiw.action_pred))\n    program.actions\n    aiw.special_case_proofs\n    actions in\n  let proof_option = get_correspondent_from_lists_correspond_ubool\n    (armada_action_proof_option_applies inv aiw.action_pred)\n    actions\n    proofs\n    step.action in\n  match proof_option with\n  | None -> \n      assert (aiw.action_pred step.action);\n      aiw.action_proof actor starts_atomic_block ends_atomic_block step s\n  | Some proof ->\n      assert (proof.action == step.action);\n      proof.special_case_proof actor starts_atomic_block ends_atomic_block step s\n\nlet armada_atomic_substep_invariant_witness_valid_implies_is_substep_invariant\n  (program: program_t (make_atomic_semantics armada_semantics))\n  (inv: invariant_t Armada.State.t)\n  (aiw: armada_atomic_substep_invariant_witness_t program inv)\n  (* see .fsti file for spec *) =\n  introduce forall s. program.init_f s ==> inv s\n  with introduce _ ==> _\n  with _. aiw.init_implies_inv_proof (s);\n  introduce forall actor starts_atomic_block ends_atomic_block (step: Armada.Step.t) s actions.\n          contains_ubool actions program.actions\n        /\\ contains_ubool step.action actions\n        /\\ inv s\n        /\\ Some? (step_computation actor starts_atomic_block ends_atomic_block step s)\n        ==> inv (Some?.v (step_computation actor starts_atomic_block ends_atomic_block step s))\n  with introduce _ ==> _\n  with _.\n    armada_atomic_substep_invariant_witness_valid_implies_inv_preserved_on_step program inv aiw\n      actor starts_atomic_block ends_atomic_block step s actions\n      (Some?.v (step_computation actor starts_atomic_block ends_atomic_block step s))\n"
  },
  {
    "path": "experimental/lib/Strategies.Invariant.Armada.AtomicSubstep.fsti",
    "content": "module Strategies.Invariant.Armada.AtomicSubstep\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Step\nopen Armada.Transition\nopen FStar.List.Tot\nopen Spec.Behavior\nopen Spec.List\nopen Spec.Ubool\nopen Strategies.Atomic\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\nopen Strategies.Invariant\nopen Strategies.Invariant.Armada\nopen Util.List\n\nnoeq type armada_atomic_substep_invariant_witness_t\n  (program: program_t (make_atomic_semantics armada_semantics))\n  (inv: invariant_t Armada.State.t) =\n{\n  action_pred: Armada.Action.t -> GTot ubool;\n  special_case_proofs: list (list (option (armada_action_special_case_invariant_proof_t inv)));\n  init_implies_inv_proof: (s: Armada.State.t{program.init_f s}) -> squash (inv s);\n  action_proof: armada_action_maintains_invariant_proof_t inv action_pred;\n}\n\nlet armada_atomic_substep_special_cases_apply\n  (inv: invariant_t Armada.State.t)\n  (action_pred: Armada.Action.t -> GTot ubool)\n  (program_actions: list (list Armada.Action.t))\n  (special_case_proofs: (list (list (option (armada_action_special_case_invariant_proof_t inv))))) =\n  lists_correspond_ubool\n    (lists_correspond_ubool (armada_action_proof_option_applies inv action_pred))\n    program_actions\n    special_case_proofs\n\nlet armada_atomic_substep_invariant_witness_valid\n  (program: program_t (make_atomic_semantics armada_semantics))\n  (inv: invariant_t Armada.State.t)\n  (aiw: armada_atomic_substep_invariant_witness_t program inv)\n  : GTot ubool =\n  armada_atomic_substep_special_cases_apply inv aiw.action_pred program.actions aiw.special_case_proofs\n\nlet is_armada_substep_invariant\n  (program: program_t (make_atomic_semantics armada_semantics))\n  (inv: invariant_t Armada.State.t)\n  : GTot ubool =\n    (forall s. program.init_f s ==> inv s)\n  /\\ (forall actor starts_atomic_block ends_atomic_block (step: Armada.Step.t) s actions.\n        let s' = step_computation actor starts_atomic_block ends_atomic_block step s in\n          contains_ubool actions program.actions\n        /\\ contains_ubool step.action actions\n        /\\ inv s\n        /\\ Some? s'\n        ==> inv (Some?.v s'))\n\nval armada_atomic_substep_invariant_witness_valid_implies_is_substep_invariant\n  (program: program_t (make_atomic_semantics armada_semantics))\n  (inv: invariant_t Armada.State.t)\n  (aiw: armada_atomic_substep_invariant_witness_t program inv)\n  : Lemma (requires armada_atomic_substep_invariant_witness_valid program inv aiw)\n          (ensures  is_armada_substep_invariant program inv)\n"
  },
  {
    "path": "experimental/lib/Strategies.Invariant.Armada.fst",
    "content": "module Strategies.Invariant.Armada\n\nopen FStar.List.Tot\nopen Spec.Behavior\nopen Strategies.Atomic\nopen Strategies.Invariant\nopen Strategies.Semantics.Armada\nopen Util.List\n\nlet is_inductive_armada_invariant_of_program_implies_is_invariant_of_program\n  (inv: invariant_t Armada.State.t)\n  (program: Armada.Program.t)\n  (* see .fsti file for spec *) =\n  is_inductive_invariant_of_spec_implies_is_invariant_of_spec inv (program_to_spec program)\n\nnoeq type armada_invariant_proof_t = {\n  program: Armada.Program.t;\n  inv: invariant_t Armada.State.t;\n  action_pred: Armada.Action.t -> GTot ubool;\n  special_case_proofs: list (option (armada_action_special_case_invariant_proof_t inv));\n  init_implies_inv_proof: (s: Armada.State.t{init_program program s}) -> squash (inv s);\n  action_proof: armada_action_maintains_invariant_proof_t inv action_pred;\n  special_cases_apply_proof: unit ->\n     squash (armada_action_special_cases_apply inv action_pred (all_actions program.program_statements)\n               special_case_proofs);\n}\n\nlet transform_special_case_proof\n  (inv: invariant_t Armada.State.t)\n  (action: Armada.Action.t)\n  (special_case_proof:\n     (actor: tid_t) ->\n     (starts_atomic_block: bool) ->\n     (ends_atomic_block: bool) ->\n     (step: Armada.Step.t) ->\n     (s: Armada.State.t{\n          step.action == action\n        /\\ inv s\n        /\\ Some? (step_computation actor starts_atomic_block ends_atomic_block step s)}) ->\n     squash (inv (Some?.v (step_computation actor starts_atomic_block ends_atomic_block step s))))\n  : GTot ((actor: armada_semantics.actor_t) ->\n          (starts_atomic_block: bool) ->\n          (ends_atomic_block: bool) ->\n          (step: armada_semantics.step_t) ->\n          (s: armada_semantics.state_t{\n              armada_semantics.step_to_action_f step == action\n            /\\ inv s\n            /\\ Some? (step_computation_generic armada_semantics actor starts_atomic_block\n                       ends_atomic_block step s)}) ->\n          squash (inv (Some?.v (step_computation_generic armada_semantics actor starts_atomic_block\n                                  ends_atomic_block step s)))) =\n  special_case_proof\n\nlet transform_special_case\n  (inv: invariant_t Armada.State.t)\n  (proof: armada_action_special_case_invariant_proof_t inv)\n  : GTot (action_special_case_invariant_proof_t armada_semantics inv) =\n  {\n    action = proof.action;\n    special_case_proof = transform_special_case_proof inv proof.action proof.special_case_proof;\n  }\n\nlet transform_optional_special_case\n  (inv: invariant_t Armada.State.t)\n  (optional_proof: option (armada_action_special_case_invariant_proof_t inv))\n  : GTot (option (action_special_case_invariant_proof_t armada_semantics inv)) =\n  match optional_proof with\n  | None -> None\n  | Some proof -> Some (transform_special_case inv proof)\n\nlet transform_optional_special_cases\n  (inv: invariant_t Armada.State.t)\n  (optional_proofs: list (option (armada_action_special_case_invariant_proof_t inv)))\n  : GTot (list (option (action_special_case_invariant_proof_t armada_semantics inv))) =\n  map_ghost (transform_optional_special_case inv) optional_proofs\n\nlet armada_invariant_proof_implies_is_armada_invariant_of_program (aip: armada_invariant_proof_t)\n  : Lemma (is_invariant_of_spec aip.inv (program_to_spec aip.program)) =\n  aip.special_cases_apply_proof ();\n  map_preserves_lists_correspond_ubool\n    (armada_action_proof_option_applies aip.inv aip.action_pred)\n    (action_proof_option_applies armada_semantics aip.inv aip.action_pred)\n    (transform_optional_special_case aip.inv)\n    (all_actions aip.program.program_statements)\n    aip.special_case_proofs;\n  let sip: semantics_invariant_proof_t = {\n    sem = armada_semantics;\n    program = armada_program_to_generic aip.program;\n    inv = aip.inv;\n    action_pred = aip.action_pred;\n    special_case_proofs = transform_optional_special_cases aip.inv aip.special_case_proofs;\n    init_implies_inv_proof = aip.init_implies_inv_proof;\n    action_proof = aip.action_proof;\n    special_cases_apply_proof = (fun _ -> ());\n  } in\n  semantics_invariant_proof_implies_is_invariant_of_spec sip;\n  introduce forall (b: behavior_t Armada.State.t).\n              behavior_satisfies_spec b (program_to_spec aip.program) ==> is_invariant_of_behavior aip.inv b\n  with introduce _ ==> _\n  with _. behavior_satisfies_armada_spec_iff_it_satisfies_generic_spec aip.program b\n\nlet armada_invariant_witness_valid_implies_is_armada_invariant_of_program\n  (program: Armada.Program.t)\n  (inv: invariant_t Armada.State.t)\n  (aiw: armada_invariant_witness_t program inv)\n  (* see .fsti file for spec *) =\n  let aip: armada_invariant_proof_t = {\n    program = program;\n    inv = inv;\n    action_pred = aiw.action_pred;\n    special_case_proofs = aiw.special_case_proofs;\n    init_implies_inv_proof = aiw.init_implies_inv_proof;\n    action_proof = aiw.action_proof;\n    special_cases_apply_proof = (fun _ -> ());\n  } in\n  armada_invariant_proof_implies_is_armada_invariant_of_program aip\n\nlet armada_invariant_proof_implies_stepwise_invariant (aip: armada_invariant_proof_t)\n  : Lemma (armada_program_has_stepwise_inductive_invariant aip.inv aip.program) =\n  aip.special_cases_apply_proof ();\n  map_preserves_lists_correspond_ubool\n    (armada_action_proof_option_applies aip.inv aip.action_pred)\n    (action_proof_option_applies armada_semantics aip.inv aip.action_pred)\n    (transform_optional_special_case aip.inv)\n    (all_actions aip.program.program_statements)\n    aip.special_case_proofs;\n  let sip: semantics_invariant_proof_t = {\n    sem = armada_semantics;\n    program = armada_program_to_generic aip.program;\n    inv = aip.inv;\n    action_pred = aip.action_pred;\n    special_case_proofs = transform_optional_special_cases aip.inv aip.special_case_proofs;\n    init_implies_inv_proof = aip.init_implies_inv_proof;\n    action_proof = aip.action_proof;\n    special_cases_apply_proof = (fun _ -> ());\n  } in\n  semantics_invariant_proof_implies_stepwise_inductive_invariant sip;\n\n  introduce forall (s: Armada.State.t). init_program aip.program s ==> aip.inv s\n  with introduce _ ==> _\n  with _. assert (init_program_generic armada_semantics sip.program s);\n  introduce forall (actor: tid_t) (starts_atomic_block: bool) (ends_atomic_block: bool) (step: Armada.Step.t)\n              (s: Armada.State.t).\n              (  aip.inv s\n               /\\ contains_ubool step.action.program_statement aip.program.program_statements)\n              ==> (match step_computation actor starts_atomic_block ends_atomic_block step s with\n                   | None -> True\n                   | Some s' -> aip.inv s')\n  with introduce _ ==> _\n  with _. (\n    all_actions_has_all_actions step.action aip.program.program_statements;\n    assert (program_contains_action_of_step_generic armada_semantics sip.program step);\n    assert (step_computation actor starts_atomic_block ends_atomic_block step s ==\n            step_computation_generic armada_semantics actor starts_atomic_block ends_atomic_block step s)\n  )\n\nlet armada_invariant_witness_valid_implies_stepwise_invariant\n  (program: Armada.Program.t)\n  (inv: invariant_t Armada.State.t)\n  (aiw: armada_invariant_witness_t program inv)\n  (* see .fsti file for spec *) =\n  let aip: armada_invariant_proof_t = {\n    program = program;\n    inv = inv;\n    action_pred = aiw.action_pred;\n    special_case_proofs = aiw.special_case_proofs;\n    init_implies_inv_proof = aiw.init_implies_inv_proof;\n    action_proof = aiw.action_proof;\n    special_cases_apply_proof = (fun _ -> ());\n  } in\n  armada_invariant_proof_implies_stepwise_invariant aip\n"
  },
  {
    "path": "experimental/lib/Strategies.Invariant.Armada.fsti",
    "content": "module Strategies.Invariant.Armada\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Step\nopen Armada.Transition\nopen FStar.List.Tot\nopen Spec.Behavior\nopen Spec.List\nopen Spec.Ubool\nopen Strategies.Atomic\nopen Strategies.Invariant\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\nopen Util.List\n\nlet is_inductive_armada_invariant_of_program\n  (inv: invariant_t Armada.State.t)\n  (program: Armada.Program.t)\n  : GTot ubool\n  =   (forall (s: Armada.State.t). init_program program s ==> inv s)\n    /\\ (forall (s s': Armada.State.t) (transition: Armada.Transition.t).\n          inv s /\\ next_program program transition s s' ==> inv s')\n\nval is_inductive_armada_invariant_of_program_implies_is_invariant_of_program\n  (inv: invariant_t Armada.State.t)\n  (program: Armada.Program.t)\n  : Lemma\n    (requires is_inductive_armada_invariant_of_program inv program)\n    (ensures  is_invariant_of_spec inv (program_to_spec program))\n\nnoeq type armada_action_special_case_invariant_proof_t (inv: invariant_t Armada.State.t) = {\n  action: Armada.Action.t;\n  special_case_proof:\n    (actor: tid_t) ->\n    (starts_atomic_block: bool) ->\n    (ends_atomic_block: bool) ->\n    (step: Armada.Step.t) ->\n    (s: Armada.State.t{\n        step.action == action\n      /\\ inv s\n      /\\ Some? (step_computation actor starts_atomic_block ends_atomic_block step s)})\n    -> squash (inv (Some?.v (step_computation actor starts_atomic_block ends_atomic_block step s)));\n}\n\ntype armada_action_maintains_invariant_proof_t\n  (inv: invariant_t Armada.State.t)\n  (action_pred: Armada.Action.t -> GTot ubool) =\n  (actor: tid_t) ->\n  (starts_atomic_block: bool) ->\n  (ends_atomic_block: bool) ->\n  (step: Armada.Step.t) ->\n  (s: Armada.State.t{\n      action_pred step.action\n    /\\ inv s\n    /\\ Some? (step_computation actor starts_atomic_block ends_atomic_block step s)}) ->\n  squash (inv (Some?.v (step_computation actor starts_atomic_block ends_atomic_block step s)))\n\nlet armada_action_proof_option_applies\n  (inv: invariant_t Armada.State.t)\n  (action_pred: Armada.Action.t -> GTot ubool)\n  (action: Armada.Action.t)\n  (proof_option: option (armada_action_special_case_invariant_proof_t inv))\n  : GTot ubool =\n  match proof_option with\n  | None -> action_pred action\n  | Some prf -> eqb prf.action action\n\nlet armada_action_special_cases_apply\n  (inv: invariant_t Armada.State.t)\n  (action_pred: Armada.Action.t -> GTot ubool)\n  (program_actions: list Armada.Action.t)\n  (special_case_proofs: (list (option (armada_action_special_case_invariant_proof_t inv)))) =\n  lists_correspond_ubool (armada_action_proof_option_applies inv action_pred) program_actions special_case_proofs\n\n/// Proving invariants of semantics-defined specs\n\nnoeq type armada_invariant_witness_t (program: Armada.Program.t) (inv: invariant_t Armada.State.t) = {\n  action_pred: Armada.Action.t -> GTot ubool;\n  special_case_proofs: list (option (armada_action_special_case_invariant_proof_t inv));\n  init_implies_inv_proof: (s: Armada.State.t{init_program program s}) -> squash (inv s);\n  action_proof: armada_action_maintains_invariant_proof_t inv action_pred;\n}\n\nlet armada_invariant_witness_valid\n  (program: Armada.Program.t)\n  (inv: invariant_t Armada.State.t)\n  (aiw: armada_invariant_witness_t program inv)\n  : GTot ubool =\n  armada_action_special_cases_apply inv aiw.action_pred (all_actions program.program_statements)\n    aiw.special_case_proofs\n\nval armada_invariant_witness_valid_implies_is_armada_invariant_of_program\n  (program: Armada.Program.t)\n  (inv: invariant_t Armada.State.t)\n  (aiw: armada_invariant_witness_t program inv)\n  : Lemma (requires armada_invariant_witness_valid program inv aiw)\n          (ensures  is_invariant_of_spec inv (program_to_spec program))\n\n/// Proving stepwise invariants of atomic programs\n\nlet armada_program_has_stepwise_inductive_invariant\n  (inv: invariant_t Armada.State.t)\n  (program: Armada.Program.t)\n  : GTot ubool =\n    (forall (s: Armada.State.t).{:pattern init_program program s} init_program program s ==> inv s)\n  /\\ (forall (actor: tid_t) (starts_atomic_block: bool) (ends_atomic_block: bool) (step: Armada.Step.t) (s: Armada.State.t).\n       (  inv s\n        /\\ contains_ubool step.action.program_statement program.program_statements)\n       ==> (match step_computation actor starts_atomic_block ends_atomic_block step s with\n           | None -> True\n           | Some s' -> inv s'))\n\nval armada_invariant_witness_valid_implies_stepwise_invariant\n  (program: Armada.Program.t)\n  (inv: invariant_t Armada.State.t)\n  (aiw: armada_invariant_witness_t program inv)\n  : Lemma (requires armada_invariant_witness_valid program inv aiw)\n          (ensures  armada_program_has_stepwise_inductive_invariant inv program)\n"
  },
  {
    "path": "experimental/lib/Strategies.Invariant.Atomic.fst",
    "content": "module Strategies.Invariant.Atomic\n\nopen FStar.List.Tot\nopen Spec.Behavior\nopen Strategies.Atomic\nopen Strategies.Invariant\nopen Util.List\n\n/// Proving invariants of atomic semantics\n\nlet rec next_atomic_step_preserves_inv_case_action_pred\n  (asip: atomic_semantics_invariant_proof_t)\n  (actor: asip.sem.actor_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (atomic_step: list asip.sem.step_t)\n  (s: asip.sem.state_t{\n      for_all_ubool asip.action_pred (map_ghost asip.sem.step_to_action_f atomic_step)\n    /\\ (asip.inv s)\n    /\\ Some? (steps_computation_generic asip.sem actor starts_atomic_block\n               ends_atomic_block atomic_step s)})\n  : GTot (squash (asip.inv (Some?.v (steps_computation_generic asip.sem actor starts_atomic_block\n                                       ends_atomic_block atomic_step s))))\n    (decreases atomic_step) =\n  match atomic_step with\n  | [last_step] -> \n      assert (asip.action_pred (asip.sem.step_to_action_f last_step));\n      asip.action_proof actor starts_atomic_block ends_atomic_block last_step s\n  | first_step :: remaining_steps ->\n      assert (asip.action_pred (asip.sem.step_to_action_f first_step));\n      asip.action_proof actor starts_atomic_block false first_step s;\n      let s' = Some?.v (step_computation_generic asip.sem actor starts_atomic_block false first_step s) in\n      next_atomic_step_preserves_inv_case_action_pred asip actor false ends_atomic_block remaining_steps s'\n\nlet atomic_special_case_proof_corresponds_to_action_special_case_proof\n  (sem: semantics_t)\n  (inv: invariant_t sem.state_t)\n  (atomic_special_case_proof: option (atomic_special_case_invariant_proof_t sem inv))\n  (action_special_case_proof: option (action_special_case_invariant_proof_t (make_atomic_semantics sem) inv))\n  : GTot ubool =\n  match atomic_special_case_proof with\n  | None -> None? action_special_case_proof\n  | Some prf ->    Some? action_special_case_proof\n               && eqb prf.atomic_action (Some?.v action_special_case_proof).action\n\nlet convert_atomic_special_case_proof_to_action_special_case_proof\n  (sem: semantics_t)\n  (inv: invariant_t sem.state_t)\n  (special_case_proof: option (atomic_special_case_invariant_proof_t sem inv))\n  : Ghost (option (action_special_case_invariant_proof_t (make_atomic_semantics sem) inv))\n  (requires True)\n  (ensures fun action_special_case_proof -> atomic_special_case_proof_corresponds_to_action_special_case_proof sem\n                                           inv special_case_proof action_special_case_proof) =\n  match special_case_proof with\n  | None -> None\n  | Some prf ->\n      let atomic_sem = make_atomic_semantics sem in\n      let lem\n        (actor: atomic_sem.actor_t)\n        (starts_atomic_block: bool)\n        (ends_atomic_block: bool)\n        (atomic_step: atomic_sem.step_t)\n        (s: atomic_sem.state_t{\n             atomic_sem.step_to_action_f atomic_step == prf.atomic_action\n           /\\ inv s\n           /\\ Some? (step_computation_generic atomic_sem actor starts_atomic_block\n                      ends_atomic_block atomic_step s)})\n        : squash (inv (Some?.v (step_computation_generic atomic_sem actor starts_atomic_block\n                                  ends_atomic_block atomic_step s))) =\n        (prf.special_case_proof actor starts_atomic_block ends_atomic_block atomic_step s) in\n      Some ({ action = prf.atomic_action; special_case_proof = lem; })\n\nlet rec convert_atomic_special_case_proofs_to_action_special_case_proofs\n  (sem: semantics_t)\n  (inv: invariant_t sem.state_t)\n  (special_case_proofs: list (option (atomic_special_case_invariant_proof_t sem inv)))\n  : Ghost (list (option (action_special_case_invariant_proof_t (make_atomic_semantics sem) inv)))\n  (requires True)\n  (ensures  fun action_special_case_proofs ->\n     lists_correspond_ubool\n     (atomic_special_case_proof_corresponds_to_action_special_case_proof sem inv)\n     special_case_proofs\n     action_special_case_proofs) =\n  match special_case_proofs with\n  | [] -> []\n  | first_proof :: remaining_proofs ->\n      (convert_atomic_special_case_proof_to_action_special_case_proof sem inv first_proof) ::\n      (convert_atomic_special_case_proofs_to_action_special_case_proofs sem inv remaining_proofs)\n\nlet rec atomic_special_cases_apply_implies_action_special_cases_apply\n  (sem: semantics_t)\n  (inv: invariant_t sem.state_t)\n  (action_pred: sem.action_t -> GTot ubool)\n  (proven_actions: list (list sem.action_t))\n  (action_special_case_proofs:\n    list (option (action_special_case_invariant_proof_t (make_atomic_semantics sem) inv)))\n  (atomic_special_case_proofs:\n    list (option (atomic_special_case_invariant_proof_t sem inv)))\n  : Lemma (requires   atomic_special_cases_apply sem inv action_pred proven_actions atomic_special_case_proofs\n                    /\\ lists_correspond_ubool\n                        (atomic_special_case_proof_corresponds_to_action_special_case_proof sem inv)\n                        atomic_special_case_proofs\n                        action_special_case_proofs)\n          (ensures action_special_cases_apply (make_atomic_semantics sem) inv\n                    (for_all_ubool action_pred) proven_actions action_special_case_proofs) =\n  match atomic_special_case_proofs with\n  | [] -> ()\n  | first_atomic_special_case_proof :: remaining_atomic_special_case_proofs ->\n     match action_special_case_proofs with\n     | [] -> assert (false)\n     | first_action_special_case_proof :: remaining_action_special_case_proofs ->\n        atomic_special_cases_apply_implies_action_special_cases_apply\n          sem\n          inv\n          action_pred\n          (tl proven_actions)\n          remaining_action_special_case_proofs\n          remaining_atomic_special_case_proofs\n\nlet atomic_semantics_invariant_proof_implies_is_invariant\n  (asip: atomic_semantics_invariant_proof_t)\n  (* see .fsti file for spec *) =\n  let action_special_case_proofs = convert_atomic_special_case_proofs_to_action_special_case_proofs asip.sem asip.inv\n                                      asip.special_case_proofs in\n  asip.special_cases_apply_proof ();\n  atomic_special_cases_apply_implies_action_special_cases_apply asip.sem asip.inv  asip.action_pred\n    asip.program.actions action_special_case_proofs asip.special_case_proofs;\n  let sip: semantics_invariant_proof_t = {\n    sem = make_atomic_semantics asip.sem;\n    program = asip.program;\n    inv = asip.inv;\n    action_pred = for_all_ubool asip.action_pred;\n    special_case_proofs = action_special_case_proofs;\n    init_implies_inv_proof = asip.init_implies_inv_proof;\n    action_proof = next_atomic_step_preserves_inv_case_action_pred asip;\n    special_cases_apply_proof = (fun _ -> _);\n  } in\n  semantics_invariant_proof_implies_is_invariant_of_spec sip\n\nlet atomic_semantics_invariant_proof_implies_stepwise_invariant\n  (asip: atomic_semantics_invariant_proof_t)\n  (* see .fsti file for spec *) =\n  let action_special_case_proofs = convert_atomic_special_case_proofs_to_action_special_case_proofs asip.sem asip.inv\n                                      asip.special_case_proofs in\n  asip.special_cases_apply_proof ();\n  atomic_special_cases_apply_implies_action_special_cases_apply asip.sem asip.inv asip.action_pred\n    asip.program.actions action_special_case_proofs asip.special_case_proofs;\n  let sip: semantics_invariant_proof_t = {\n    sem = make_atomic_semantics asip.sem;\n    program = asip.program;\n    inv = asip.inv;\n    action_pred = for_all_ubool asip.action_pred;\n    special_case_proofs = action_special_case_proofs;\n    init_implies_inv_proof = asip.init_implies_inv_proof;\n    action_proof = next_atomic_step_preserves_inv_case_action_pred asip;\n    special_cases_apply_proof = (fun _ -> _);\n  } in\n  semantics_invariant_proof_implies_stepwise_inductive_invariant sip\n"
  },
  {
    "path": "experimental/lib/Strategies.Invariant.Atomic.fsti",
    "content": "module Strategies.Invariant.Atomic\n\nopen FStar.List.Tot\nopen Spec.Behavior\nopen Spec.List\nopen Spec.Ubool\nopen Strategies.Atomic\nopen Strategies.Semantics\nopen Strategies.Invariant\nopen Util.List\n\n/// Proving invariants of atomic programs\n\nnoeq type atomic_special_case_invariant_proof_t (sem: semantics_t) (inv: invariant_t sem.state_t) =\n  | AtomicSpecialCaseInvariantProof :\n     (atomic_action: list sem.action_t) ->\n     (special_case_proof:\n       ((actor: sem.actor_t) ->\n        (starts_atomic_block: bool) ->\n        (ends_atomic_block: bool) ->\n        (atomic_step: list sem.step_t) ->\n        (s: sem.state_t{\n            map_ghost sem.step_to_action_f atomic_step == atomic_action\n          /\\ inv s\n          /\\ Some? (steps_computation_generic sem actor starts_atomic_block ends_atomic_block atomic_step s)}) ->\n        squash (inv (Some?.v (steps_computation_generic sem actor starts_atomic_block\n                                ends_atomic_block atomic_step s))))) ->\n  atomic_special_case_invariant_proof_t sem inv\n\nlet atomic_proof_option_applies\n  (sem: semantics_t)\n  (inv: invariant_t sem.state_t)\n  (action_pred: sem.action_t -> GTot ubool)\n  (atomic_action: list sem.action_t)\n  (proof_option: option (atomic_special_case_invariant_proof_t sem inv))\n  : GTot ubool =\n  match proof_option with\n  | None -> for_all_ubool action_pred atomic_action\n  | Some prf -> eqb prf.atomic_action atomic_action\n\nlet atomic_special_cases_apply\n  (sem: semantics_t)\n  (inv: invariant_t sem.state_t)\n  (action_pred: sem.action_t -> GTot ubool)\n  (atomic_actions: list (list sem.action_t))\n  (special_case_proofs: (list (option (atomic_special_case_invariant_proof_t sem inv)))) =\n  lists_correspond_ubool (atomic_proof_option_applies sem inv action_pred) atomic_actions special_case_proofs\n\nnoeq type atomic_semantics_invariant_proof_t = {\n  sem: semantics_t;\n  program: program_t (make_atomic_semantics sem);\n  inv: invariant_t sem.state_t;\n  action_pred: sem.action_t -> GTot ubool;\n  special_case_proofs: list (option (atomic_special_case_invariant_proof_t sem inv));\n  init_implies_inv_proof: (s: sem.state_t{program.init_f s}) -> squash (inv s);\n  action_proof: action_maintains_invariant_proof_t sem inv action_pred;\n  special_cases_apply_proof: unit ->\n     squash (atomic_special_cases_apply sem inv action_pred program.actions special_case_proofs);\n}\n\nval atomic_semantics_invariant_proof_implies_is_invariant (asip: atomic_semantics_invariant_proof_t)\n  : Lemma (is_invariant_of_spec asip.inv (semantics_to_spec (make_atomic_semantics asip.sem) asip.program))\n\nval atomic_semantics_invariant_proof_implies_stepwise_invariant (asip: atomic_semantics_invariant_proof_t)\n  : Lemma (semantics_has_stepwise_inductive_invariant (make_atomic_semantics asip.sem) asip.program asip.inv)\n"
  },
  {
    "path": "experimental/lib/Strategies.Invariant.fst",
    "content": "module Strategies.Invariant\n\nopen FStar.List.Tot\nopen Spec.Behavior\nopen Strategies.Atomic\nopen Util.List\n\n/// Proving invariants\n\nlet rec inductive_invariant_satisfied_initially_and_inductive_implies_invariant\n  (#state: Type)\n  (inv: invariant_t state)\n  (spec: spec_t state)\n  (b: behavior_t state)\n  : Lemma\n    (requires Cons? b ==>\n                inv (Cons?.hd b)\n              /\\ behavior_satisfies_next b spec.next\n              /\\ (forall (s s': state). inv s /\\ (spec.next s s') ==> inv s'))\n    (ensures  is_invariant_of_behavior inv b)\n  = match b with\n    | [] -> ()\n    | s :: tl -> inductive_invariant_satisfied_initially_and_inductive_implies_invariant inv spec tl\n\nlet is_inductive_invariant_of_spec_implies_is_invariant_of_behavior\n  (#state: Type)\n  (inv: invariant_t state)\n  (spec: spec_t state)\n  (b: behavior_t state)\n  : Lemma\n    (requires   is_inductive_invariant_of_spec inv spec\n              /\\ behavior_satisfies_spec b spec)\n    (ensures  is_invariant_of_behavior inv b)\n  = inductive_invariant_satisfied_initially_and_inductive_implies_invariant inv spec b\n\nlet is_inductive_invariant_of_spec_implies_is_invariant_of_spec\n  (#state: Type)\n  (inv: invariant_t state)\n  (spec: spec_t state) =\n  (* see .fsti file for spec *)\n  introduce forall b. behavior_satisfies_spec b spec ==> is_invariant_of_behavior inv b\n  with introduce _ ==> _\n  with given_antecedent. is_inductive_invariant_of_spec_implies_is_invariant_of_behavior inv spec b\n\n/// Proving invariants of semantics\n\nlet step_computation_generic_preserves_inv_case_action_pred\n  (sip: semantics_invariant_proof_t)\n  (actor: sip.sem.actor_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (step: sip.sem.step_t)\n  (s: sip.sem.state_t)\n  : Lemma (requires   (sip.inv s)\n                    /\\ (sip.action_pred (sip.sem.step_to_action_f step))\n                    /\\ (Some? (step_computation_generic sip.sem actor starts_atomic_block\n                                ends_atomic_block step s)))\n          (ensures  sip.inv (Some?.v (step_computation_generic sip.sem actor starts_atomic_block ends_atomic_block\n                                        step s))) =\n  sip.action_proof actor starts_atomic_block ends_atomic_block step s\n\nlet step_computation_generic_preserves_inv_case_special_case\n  (sip: semantics_invariant_proof_t)\n  (actor: sip.sem.actor_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (step: sip.sem.step_t)\n  (s: sip.sem.state_t)\n  (prf: action_special_case_invariant_proof_t sip.sem sip.inv)\n  : Lemma (requires   (sip.inv s)\n                    /\\ prf.action == (sip.sem.step_to_action_f step)\n                    /\\ Some? (step_computation_generic sip.sem actor starts_atomic_block\n                               ends_atomic_block step s))\n          (ensures  sip.inv (Some?.v (step_computation_generic sip.sem actor starts_atomic_block ends_atomic_block\n                                        step s))) =\n  prf.special_case_proof actor starts_atomic_block ends_atomic_block step s\n\nlet get_proof_option\n  (sip: semantics_invariant_proof_t)\n  (action: sip.sem.action_t)\n  : Ghost (option (action_special_case_invariant_proof_t sip.sem sip.inv))\n    (requires contains_ubool action sip.program.actions)\n    (ensures  fun proof_option ->\n      action_proof_option_applies sip.sem sip.inv sip.action_pred action proof_option) =\n  sip.special_cases_apply_proof ();\n  let f = action_proof_option_applies sip.sem sip.inv sip.action_pred in\n  get_correspondent_from_lists_correspond_ubool f sip.program.actions sip.special_case_proofs action\n\nlet step_computation_generic_preserves_inv\n  (sip: semantics_invariant_proof_t)\n  (actor: sip.sem.actor_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (step: sip.sem.step_t)\n  (s: sip.sem.state_t)\n  : Lemma (requires   (sip.inv s)\n                    /\\ (program_contains_action_of_step_generic sip.sem sip.program step)\n                    /\\ (Some? (step_computation_generic sip.sem actor starts_atomic_block\n                                ends_atomic_block step s)))\n          (ensures  sip.inv (Some?.v (step_computation_generic sip.sem actor starts_atomic_block ends_atomic_block\n                                        step s))) =\n  let action = sip.sem.step_to_action_f step in\n  let proof_option = get_proof_option sip action in\n  match proof_option with\n  | None ->\n      assert (action_proof_option_applies sip.sem sip.inv sip.action_pred action None ==\n              sip.action_pred action)\n        by FStar.Tactics.V2.trefl();\n    step_computation_generic_preserves_inv_case_action_pred sip actor starts_atomic_block ends_atomic_block step s\n  | Some prf -> step_computation_generic_preserves_inv_case_special_case sip actor\n                 starts_atomic_block ends_atomic_block step s prf\n\nlet rec eval_steps_generic_preserves_inv\n  (sip: semantics_invariant_proof_t)\n  (actor: sip.sem.actor_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (steps: list sip.sem.step_t)\n  (s: sip.sem.state_t)\n  : Lemma (requires   sip.inv s\n                    /\\ for_all_ubool (program_contains_action_of_step_generic sip.sem sip.program) steps\n                    /\\ Some? (steps_computation_generic sip.sem actor starts_atomic_block\n                               ends_atomic_block steps s))\n          (ensures  sip.inv (Some?.v (steps_computation_generic sip.sem actor starts_atomic_block\n                                        ends_atomic_block steps s)))\n          (decreases steps) =\n  match steps with\n  | [last_step] ->\n     step_computation_generic_preserves_inv sip actor starts_atomic_block ends_atomic_block last_step s\n  | first_step :: remaining_steps ->\n     step_computation_generic_preserves_inv sip actor starts_atomic_block false first_step s;\n     let s' = Some?.v (step_computation_generic sip.sem actor starts_atomic_block false first_step s) in\n     eval_steps_generic_preserves_inv sip actor false ends_atomic_block remaining_steps s'\n\nlet next_transition_generic_preserves_inv\n  (sip: semantics_invariant_proof_t)\n  (transition: transition_t sip.sem)\n  (s: sip.sem.state_t)\n  (s': sip.sem.state_t)\n  : Lemma (requires   next_transition_generic sip.sem transition s s'\n                    /\\ (for_all_ubool (program_contains_action_of_step_generic sip.sem sip.program) transition.steps)\n                    /\\ sip.inv s)\n          (ensures  sip.inv s') =\n  eval_steps_generic_preserves_inv sip transition.actor true true transition.steps s\n\nlet next_program_generic_preserves_inv\n  (sip: semantics_invariant_proof_t)\n  (transition: transition_t sip.sem)\n  (s: sip.sem.state_t)\n  (s': sip.sem.state_t)\n  : Lemma (requires   next_program_generic sip.sem sip.program transition s s'\n                    /\\ sip.inv s)\n          (ensures sip.inv s') =\n  next_transition_generic_preserves_inv sip transition s s'\n\nlet semantics_spec_next_preserves_inv\n  (sip: semantics_invariant_proof_t)\n  (s: sip.sem.state_t)\n  (s': sip.sem.state_t)\n  : Lemma (requires   sip.inv s\n                    /\\ (semantics_to_spec sip.sem sip.program).next s s')\n          (ensures sip.inv s') =\n  eliminate exists transition. next_program_generic sip.sem sip.program transition s s'\n  returns   sip.inv s'\n  with transition_satisfies_next_program.\n    next_program_generic_preserves_inv sip transition s s'\n\nlet semantics_invariant_proof_implies_is_invariant_of_spec (sip: semantics_invariant_proof_t)\n  (* see .fsti file for spec *) =\n  let inv = sip.inv in\n  let spec = semantics_to_spec sip.sem sip.program in\n\n  introduce forall s. spec.init s ==> inv s\n  with introduce spec.init s ==> inv s\n  with given_spec_init. sip.init_implies_inv_proof s;\n\n  introduce forall s s'. inv s /\\ spec.next s s' ==> inv s'\n  with introduce _ ==> _\n  with given_next. (semantics_spec_next_preserves_inv sip s s');\n  \n  is_inductive_invariant_of_spec_implies_is_invariant_of_spec inv spec\n\nlet semantics_invariant_proof_implies_stepwise_inductive_invariant (sip: semantics_invariant_proof_t)\n  (* see .fsti file for spec *) =\n  let inv = sip.inv in\n  let sem = sip.sem in\n  introduce forall s. init_program_generic sem sip.program s ==> inv s\n  with introduce init_program_generic sem sip.program s ==> inv s\n  with given_antecedent. sip.init_implies_inv_proof s;\n\n  introduce forall actor starts_atomic_block ends_atomic_block step s.\n                 inv s\n               /\\ program_contains_action_of_step_generic sem sip.program step\n               /\\ Some? (step_computation_generic sem actor starts_atomic_block ends_atomic_block step s)\n               ==> inv (Some?.v (step_computation_generic sem actor starts_atomic_block ends_atomic_block step s))\n  with introduce _ ==> _\n  with _. step_computation_generic_preserves_inv sip actor starts_atomic_block ends_atomic_block step s\n"
  },
  {
    "path": "experimental/lib/Strategies.Invariant.fsti",
    "content": "module Strategies.Invariant\n\nopen FStar.List.Tot\nopen Spec.Behavior\nopen Spec.List\nopen Spec.Ubool\nopen Strategies.Atomic\nopen Strategies.Semantics\nopen Util.List\n\n/// Proving invariants of arbitrary state machines\n\ntype invariant_t (state_t: Type) = state_t -> GTot ubool\n\nlet is_invariant_of_behavior\n  (#state_t: Type)\n  (inv: invariant_t state_t)\n  (b: behavior_t state_t)\n  : GTot ubool\n  = forall s. contains_ubool s b ==> inv s\n\nlet is_invariant_of_spec\n  (#state_t: Type)\n  (inv: invariant_t state_t)\n  (spec: spec_t state_t)\n  : GTot ubool\n  = forall (b: behavior_t state_t). behavior_satisfies_spec b spec ==> is_invariant_of_behavior inv b\n\nlet is_inductive_invariant_of_spec\n  (#state_t: Type)\n  (inv: invariant_t state_t)\n  (spec: spec_t state_t)\n  : GTot ubool\n  =   (forall (s: state_t). spec.init s ==> inv s)\n    /\\ (forall (s s': state_t). inv s /\\ (spec.next s s') ==> inv s')\n\nval is_inductive_invariant_of_spec_implies_is_invariant_of_spec\n  (#state_t: Type)\n  (inv: invariant_t state_t)\n  (spec: spec_t state_t)\n  : Lemma\n    (requires is_inductive_invariant_of_spec inv spec)\n    (ensures  is_invariant_of_spec inv spec)\n\nnoeq type action_special_case_invariant_proof_t (sem: semantics_t) (inv: invariant_t sem.state_t) = {\n  action: sem.action_t;\n  special_case_proof:\n    (actor: sem.actor_t) ->\n    (starts_atomic_block: bool) ->\n    (ends_atomic_block: bool) ->\n    (step: sem.step_t) ->\n    (s: sem.state_t{\n         sem.step_to_action_f step == action\n       /\\ inv s\n       /\\ Some? (step_computation_generic sem actor starts_atomic_block ends_atomic_block step s)}) ->\n    squash (inv (Some?.v (step_computation_generic sem actor starts_atomic_block ends_atomic_block step s)));\n}\n\ntype action_maintains_invariant_proof_t\n  (sem: semantics_t)\n  (inv: invariant_t sem.state_t)\n  (action_pred: (sem.action_t -> GTot ubool)) =\n  (actor: sem.actor_t) ->\n  (starts_atomic_block: bool) ->\n  (ends_atomic_block: bool) ->\n  (step: sem.step_t) ->\n  (s: sem.state_t{\n       action_pred (sem.step_to_action_f step)\n     /\\ inv s\n     /\\ Some? (step_computation_generic sem actor starts_atomic_block ends_atomic_block step s)}) ->\n  squash (inv (Some?.v (step_computation_generic sem actor starts_atomic_block ends_atomic_block step s)))\n\nlet action_proof_option_applies\n  (sem: semantics_t)\n  (inv: invariant_t sem.state_t)\n  (action_pred: sem.action_t -> GTot ubool)\n  (action: sem.action_t)\n  (proof_option: option (action_special_case_invariant_proof_t sem inv))\n  : GTot ubool =\n  match proof_option with\n  | None -> action_pred action\n  | Some prf -> eqb prf.action action\n\nlet action_special_cases_apply\n  (sem: semantics_t)\n  (inv: invariant_t sem.state_t)\n  (action_pred: sem.action_t -> GTot ubool)\n  (program_actions: list sem.action_t)\n  (special_case_proofs: (list (option (action_special_case_invariant_proof_t sem inv)))) =\n  lists_correspond_ubool (action_proof_option_applies sem inv action_pred) program_actions special_case_proofs\n\n/// Proving invariants of semantics-defined specs\n\nnoeq type semantics_invariant_proof_t = {\n  sem: semantics_t;\n  program: program_t sem;\n  inv: invariant_t sem.state_t;\n  action_pred: sem.action_t -> GTot ubool;\n  special_case_proofs: list (option (action_special_case_invariant_proof_t sem inv));\n  init_implies_inv_proof: (s: sem.state_t{init_program_generic sem program s}) -> squash (inv s);\n  action_proof: action_maintains_invariant_proof_t sem inv action_pred;\n  special_cases_apply_proof: unit ->\n     squash (action_special_cases_apply sem inv action_pred program.actions special_case_proofs);\n}\n\nval semantics_invariant_proof_implies_is_invariant_of_spec (sip: semantics_invariant_proof_t)\n  : Lemma (is_invariant_of_spec sip.inv (semantics_to_spec sip.sem sip.program))\n\n/// Proving stepwise invariants of atomic programs\n\nlet semantics_has_stepwise_inductive_invariant\n  (sem: semantics_t)\n  (program: program_t sem)\n  (inv: invariant_t sem.state_t)\n  : GTot ubool =\n    (forall (s: sem.state_t).{:pattern init_program_generic sem program s} init_program_generic sem program s ==> inv s)\n  /\\ (forall (actor: sem.actor_t) (starts_atomic_block: bool) (ends_atomic_block: bool) (step: sem.step_t) (s: sem.state_t).\n       (  inv s\n        /\\ program_contains_action_of_step_generic sem program step)\n       ==> (match step_computation_generic sem actor starts_atomic_block ends_atomic_block step s with\n           | None -> True\n           | Some s' -> inv s'))\n\nval semantics_invariant_proof_implies_stepwise_inductive_invariant (sip: semantics_invariant_proof_t)\n  : Lemma (semantics_has_stepwise_inductive_invariant sip.sem sip.program sip.inv)\n"
  },
  {
    "path": "experimental/lib/Strategies.Lift.Generic.fst",
    "content": "module Strategies.Lift.Generic\n\nopen FStar.WellFoundedRelation\nopen Spec.Behavior\nopen Spec.List\nopen Spec.Logic\nopen Spec.Ubool\nopen Strategies.Invariant\nopen Strategies.Semantics\nopen Util.List\nopen Util.Logic\n\nnoeq type refinement_choice_t (step_t: Type) (state_t: Type) (aux_t: Type) =\n  | RefinementChoiceSkip: (aux': aux_t) -> refinement_choice_t step_t state_t aux_t\n  | RefinementChoiceIntroduce: (steps: list step_t) -> (state: state_t) -> (aux': aux_t) ->\n                               refinement_choice_t step_t state_t aux_t\n  | RefinementChoiceLift: (steps: list step_t) -> (state: state_t) -> (aux': aux_t) ->\n                          refinement_choice_t step_t state_t aux_t\n\nlet refinement_choice_works\n  (lr: liftability_relation_t)\n  (ls: lr.lsem.state_t)\n  (actor: lr.lsem.actor_t)\n  (starts_atomic_block: bool)\n  (steps: list lr.lsem.step_t)\n  (ls': lr.lsem.state_t)\n  (hs: lr.hsem.state_t)\n  (choice: refinement_choice_t lr.hsem.step_t lr.hsem.state_t lr.aux_t)\n  : GTot ubool =\n  match choice with\n  | RefinementChoiceSkip aux' ->\n         starts_atomic_block\n      /\\ lr.inv ls'\n      /\\ lr.lh_relation aux' ls' hs\n  | RefinementChoiceIntroduce hsteps hs' aux' ->\n         starts_atomic_block\n      /\\ for_all_ubool (program_contains_action_of_step_generic lr.hsem lr.hprog) hsteps\n      /\\ Some hs' == steps_computation_generic lr.hsem actor starts_atomic_block true\n                      hsteps hs\n      /\\ lr.lh_relation aux' ls hs'\n      /\\ (match steps with\n         | [] -> False\n         | lstep :: _ ->\n             lr.progress_wfr.relation (lr.progress_measure hs' lstep actor) (lr.progress_measure hs lstep actor))\n  | RefinementChoiceLift hsteps hs' aux' ->\n        for_all_ubool (program_contains_action_of_step_generic lr.hsem lr.hprog) hsteps\n      /\\ (Some hs') == steps_computation_generic lr.hsem actor starts_atomic_block true\n                        hsteps hs\n      /\\ lr.inv ls'\n      /\\ lr.lh_relation aux' ls' hs'\n\nlet rec get_refinement_choice\n  (lr: liftability_relation_t)\n  (aux: lr.aux_t)\n  (ls: lr.lsem.state_t)\n  (actor: lr.lsem.actor_t)\n  (starts_atomic_block: bool)\n  (lsteps: list lr.lsem.step_t)\n  (ls': lr.lsem.state_t)\n  (hs: lr.hsem.state_t{\n        eqb (Some ls') (steps_computation_generic lr.lsem actor starts_atomic_block true\n                          lsteps ls)\n      /\\ (for_all_ubool (program_contains_action_of_step_generic lr.lsem lr.lprog) lsteps)\n      /\\ lr.inv ls\n      /\\ lr.lh_relation aux ls hs})\n  : GTot (choice: refinement_choice_t lr.hsem.step_t lr.hsem.state_t lr.aux_t{\n            refinement_choice_works lr ls actor starts_atomic_block lsteps ls' hs choice})\n    (decreases (lex_nondep_wfr (default_wfr (list lr.lsem.step_t)) lr.progress_wfr).decreaser\n               (lsteps, lr.progress_measure hs (Cons?.hd lsteps) actor)) =\n  lr.inv_stepwise_invariant_proof ();\n  match lsteps with\n  | [lstep] ->\n      let ls2 = Some?.v (step_computation_generic lr.lsem actor starts_atomic_block true\n                           lstep ls) in\n      assert (lr.inv ls2);\n      (match lr.paths_liftable_proof actor starts_atomic_block true aux ls hs lstep with\n       | StepLifterSkip aux' ->\n           RefinementChoiceSkip aux'\n       | StepLifterIntroduce hstep aux2 ->\n           let hs2 = Some?.v (step_computation_generic lr.hsem actor\n                                starts_atomic_block starts_atomic_block hstep hs) in\n           if starts_atomic_block then\n             RefinementChoiceIntroduce [hstep] hs2 aux2\n           else (\n             let choice' = get_refinement_choice lr aux2 ls actor starts_atomic_block lsteps ls' hs2 in\n             let RefinementChoiceLift hsteps hs' aux' = choice' in\n             RefinementChoiceLift (hstep :: hsteps) hs' aux'\n           )\n        | StepLifterLift hstep aux' ->\n            let hs' = Some?.v (step_computation_generic lr.hsem actor starts_atomic_block true\n                                 hstep hs) in\n            RefinementChoiceLift [hstep] hs' aux')\n  | lstep :: lsteps' ->\n      let ls2 = Some?.v (step_computation_generic lr.lsem actor starts_atomic_block false\n                           lstep ls) in\n      lr.inv_stepwise_invariant_proof ();\n      assert (lr.inv ls2);\n      (match lr.paths_liftable_proof actor starts_atomic_block false aux ls hs lstep with\n       | StepLifterSkip aux2 ->\n           get_refinement_choice lr aux2 ls2 actor false lsteps' ls' hs\n       | StepLifterIntroduce hstep aux2 ->\n           let hs2 = Some?.v (step_computation_generic lr.hsem actor\n                                starts_atomic_block starts_atomic_block hstep hs) in\n           if starts_atomic_block then\n             RefinementChoiceIntroduce [hstep] hs2 aux2\n           else\n             let choice' = get_refinement_choice lr aux2 ls actor starts_atomic_block lsteps ls' hs2 in\n             let RefinementChoiceLift hsteps hs' aux' = choice' in\n             RefinementChoiceLift (hstep :: hsteps) hs' aux'\n       | StepLifterLift hstep aux2 ->\n           let hs2 = Some?.v (step_computation_generic lr.hsem actor starts_atomic_block false\n                                hstep hs) in\n           let choice' = get_refinement_choice lr aux2 ls2 actor false lsteps' ls' hs2 in\n           let RefinementChoiceLift hsteps' hs' aux' = choice' in\n           RefinementChoiceLift (hstep :: hsteps') hs' aux')\n\n#push-options \"--z3rlimit 10\"\n\nlet rec get_hbehavior_satisfying_next\n  (lr: liftability_relation_t)\n  (aux: lr.aux_t)\n  (ltransition: transition_t lr.lsem)\n  (lb: behavior_t lr.lsem.state_t)\n  (hs: lr.hsem.state_t{\n       behavior_satisfies_next lb (semantics_to_spec lr.lsem lr.lprog).next\n    /\\ (for_all_ubool (program_contains_action_of_step_generic lr.lsem lr.lprog) ltransition.steps)\n    /\\ (match lb with\n       | ls ::  ls' :: _ ->\n            lr.inv ls\n          /\\ lr.lh_relation aux ls hs\n          /\\ next_transition_generic lr.lsem ltransition ls ls'\n       | _ -> False)})\n  : GTot (hb: behavior_t lr.hsem.state_t{\n              behavior_satisfies_next hb (semantics_to_spec lr.hsem lr.hprog).next\n            /\\ behavior_refines_behavior lb hb lr.refinement_relation\n            /\\ Cons? hb\n            /\\ Cons?.hd hb == hs})\n    (decreases (lex_nondep_wfr (default_wfr (behavior_t lr.lsem.state_t)) lr.progress_wfr).decreaser\n               (lb, lr.progress_measure hs (Cons?.hd ltransition.steps) ltransition.actor)) =\n  match lb with\n  | ls :: ls' :: lb' ->\n      lr.lh_relation_implies_refinement_proof aux ls hs;\n      let choice = get_refinement_choice lr aux ls ltransition.actor true ltransition.steps ls' hs in\n      (match choice with\n       | RefinementChoiceSkip aux' ->\n           (match lb' with\n            | [] ->\n                lr.lh_relation_implies_refinement_proof aux' ls' hs;\n                [hs]\n            | ls'' :: lb'' ->\n                let ltransition' = simpler_indefinite_description\n                  (fun ltransition' -> next_program_generic lr.lsem lr.lprog ltransition' ls' ls'') in\n                get_hbehavior_satisfying_next lr aux' ltransition' (ls' :: lb') hs)\n       | RefinementChoiceIntroduce hsteps hs' aux' ->\n           lr.lh_relation_implies_refinement_proof aux' ls hs';\n           let hb' = get_hbehavior_satisfying_next lr aux' ltransition lb hs' in\n           let htransition = { actor = ltransition.actor <: lr.hsem.actor_t; steps = hsteps } in\n           assert (next_program_generic lr.hsem lr.hprog htransition hs hs');\n           hs :: hb'\n       | RefinementChoiceLift hsteps hs' aux' ->\n           lr.lh_relation_implies_refinement_proof aux' ls' hs';\n           let htransition = { actor = ltransition.actor <: lr.hsem.actor_t; steps = hsteps } in\n           assert (next_program_generic lr.hsem lr.hprog htransition hs hs');\n           (match lb' with\n            | [] ->\n                [hs; hs']\n            | ls'' :: lb'' ->\n                let ltransition' = simpler_indefinite_description\n                  (fun ltransition' -> next_program_generic lr.lsem lr.lprog ltransition' ls' ls'') in\n                let hb' = get_hbehavior_satisfying_next lr aux' ltransition' (ls' :: lb') hs' in\n                hs :: hb'))\n\n#pop-options\n\nlet get_hbehavior_satisfying_spec\n  (lr: liftability_relation_t)\n  (lb: behavior_t lr.lsem.state_t{behavior_satisfies_spec lb (semantics_to_spec lr.lsem lr.lprog)})\n  : GTot (hb: behavior_t lr.hsem.state_t{\n              behavior_satisfies_spec hb (semantics_to_spec lr.hsem lr.hprog)\n            /\\ behavior_refines_behavior lb hb lr.refinement_relation}) =\n  match lb with\n  | ls :: lb' ->\n      lr.inv_stepwise_invariant_proof ();\n      let hs, aux = lr.init_implies_relation_proof ls in\n      (match lb' with\n       | [] ->\n           lr.lh_relation_implies_refinement_proof aux ls hs;\n           [hs]\n       | ls' :: _ ->\n           let ltransition = simpler_indefinite_description\n             (fun ltransition -> next_program_generic lr.lsem lr.lprog ltransition ls ls') in\n           get_hbehavior_satisfying_next lr aux ltransition lb hs)\n\nlet liftability_relation_implies_refinement (lr: liftability_relation_t)\n  (* see .fsti file for spec *) =\n  let lspec = semantics_to_spec lr.lsem lr.lprog in\n  let hspec = semantics_to_spec lr.hsem lr.hprog in\n  introduce forall lb. behavior_satisfies_spec lb lspec ==>\n              (exists hb. behavior_satisfies_spec hb hspec /\\ behavior_refines_behavior lb hb lr.refinement_relation)\n  with introduce _ ==> _\n  with _.\n    introduce exists hb. behavior_satisfies_spec hb hspec /\\ behavior_refines_behavior lb hb lr.refinement_relation\n    with (get_hbehavior_satisfying_spec lr lb)\n    and ()\n"
  },
  {
    "path": "experimental/lib/Strategies.Lift.Generic.fsti",
    "content": "module Strategies.Lift.Generic\n\nopen FStar.WellFoundedRelation\nopen Spec.Behavior\nopen Spec.List\nopen Spec.Logic\nopen Spec.Ubool\nopen Strategies.Invariant\nopen Strategies.Semantics\n\nnoeq type step_lifter_t (step_t: Type) (aux_t: Type) =\n  | StepLifterSkip: (aux': aux_t) -> step_lifter_t step_t aux_t\n  | StepLifterIntroduce: (hstep: step_t) -> (aux': aux_t) -> step_lifter_t step_t aux_t\n  | StepLifterLift: (hstep: step_t) -> (aux': aux_t) -> step_lifter_t step_t aux_t\n\nlet step_lifter_works\n  (lsem: semantics_t)\n  (hsem: semantics_t{hsem.actor_t == lsem.actor_t})\n  (lprog: program_t lsem)\n  (hprog: program_t hsem)\n  (aux_t: Type)\n  (lh_relation: aux_t -> lsem.state_t -> hsem.state_t -> GTot ubool)\n  (progress_t: Type)\n  (progress_wfr: wfr_t progress_t)\n  (progress_measure: hsem.state_t -> lsem.step_t -> lsem.actor_t -> GTot progress_t)\n  (actor: lsem.actor_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (lstep: lsem.step_t)\n  (ls: lsem.state_t)\n  (hs: hsem.state_t)\n  (lifter: step_lifter_t hsem.step_t aux_t)\n  : GTot ubool =\n  match lifter with\n  | StepLifterSkip aux' ->\n      (match step_computation_generic lsem actor starts_atomic_block ends_atomic_block lstep ls with\n       | Some ls' ->\n             lh_relation aux' ls' hs\n           /\\ (starts_atomic_block = ends_atomic_block)\n       | None -> False)\n  | StepLifterIntroduce hstep aux' ->\n      (* Introduced steps must have ends_atomic_block the same as starts_atomic_block *)\n      (match step_computation_generic hsem actor starts_atomic_block starts_atomic_block hstep hs with\n       | Some hs' ->\n             lh_relation aux' ls hs'\n           /\\ program_contains_action_of_step_generic hsem hprog hstep\n           /\\ progress_wfr.relation (progress_measure hs' lstep actor) (progress_measure hs lstep actor)\n       | None -> False)\n  | StepLifterLift hstep aux' ->\n      (match step_computation_generic lsem actor starts_atomic_block ends_atomic_block lstep ls,\n             step_computation_generic hsem actor starts_atomic_block ends_atomic_block hstep hs with\n       | Some ls', Some hs' ->\n             program_contains_action_of_step_generic hsem hprog hstep\n           /\\ lh_relation aux' ls' hs'\n       | _, _ -> False)\n\nnoeq type liftability_relation_t = {\n  lsem: semantics_t;\n  hsem: (hsem: semantics_t{hsem.actor_t == lsem.actor_t});\n  lprog: program_t lsem;\n  hprog: program_t hsem;\n  aux_t: Type;\n  inv: invariant_t lsem.state_t;\n  lh_relation: aux_t -> lsem.state_t -> hsem.state_t -> GTot ubool;\n  progress_t: Type;\n  progress_wfr: wfr_t progress_t;\n  progress_measure: hsem.state_t -> lsem.step_t -> lsem.actor_t -> GTot progress_t;\n  refinement_relation: lsem.state_t -> hsem.state_t -> GTot ubool;\n\n  paths_liftable_proof:\n    (actor: lsem.actor_t) ->\n    (starts_atomic_block: bool) ->\n    (ends_atomic_block: bool) ->\n    (aux: aux_t) ->\n    (ls: lsem.state_t) ->\n    (hs: hsem.state_t) ->\n    (lstep: lsem.step_t{\n         inv ls\n       /\\ lh_relation aux ls hs\n       /\\ Some? (step_computation_generic lsem actor starts_atomic_block ends_atomic_block lstep ls)\n       /\\ program_contains_action_of_step_generic lsem lprog lstep}) ->\n    GTot (lifter: (step_lifter_t hsem.step_t aux_t){\n      step_lifter_works lsem hsem lprog hprog aux_t lh_relation progress_t progress_wfr\n        progress_measure actor starts_atomic_block ends_atomic_block lstep ls hs lifter});\n\n  inv_stepwise_invariant_proof: unit -> squash (semantics_has_stepwise_inductive_invariant lsem lprog inv);\n\n  init_implies_relation_proof:\n    (ls: lsem.state_t{lprog.init_f ls}) ->\n    GTot (hs_aux: (hsem.state_t * aux_t){\n       let hs, aux = hs_aux in\n       hprog.init_f hs /\\ lh_relation aux ls hs});\n\n  lh_relation_implies_refinement_proof:\n    (aux: aux_t) ->\n    (ls: lsem.state_t) ->\n    (hs: hsem.state_t{inv ls /\\ lh_relation aux ls hs}) ->\n    squash (refinement_relation ls hs);\n}\n\nval liftability_relation_implies_refinement (lr: liftability_relation_t)\n  : Lemma (ensures spec_refines_spec\n                     (semantics_to_spec lr.lsem lr.lprog)\n                     (semantics_to_spec lr.hsem lr.hprog)\n                     lr.refinement_relation)\n"
  },
  {
    "path": "experimental/lib/Strategies.Nonyielding.fst",
    "content": "module Strategies.Nonyielding\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Statement\nopen Armada.Transition\nopen Spec.List\nopen Strategies.ArmadaStatement.Status\nopen Strategies.ArmadaStatement.ThreadState\nopen Strategies.Atomic\nopen Strategies.PCIndices\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\nopen Util.ImmutableArray\nopen Util.List\n\nlet action_consistent_with_is_nonyielding_pc\n  (is_nonyielding_pc: pc_t -> GTot bool)\n  (action: Armada.Action.t)\n  : GTot bool =\n  let ps = action.program_statement in\n  (match ps.start_pc with\n   | None -> ps.starts_atomic_block && ps.ends_atomic_block\n   | Some pc -> ps.starts_atomic_block = not (is_nonyielding_pc pc))\n  &&\n  (match program_statement_to_ending_thread_state ps with\n   | ThreadStateRunning -> ps.ends_atomic_block && None? ps.start_pc\n   | ThreadStateAtPC pc -> ps.ends_atomic_block = not (is_nonyielding_pc pc)\n   | ThreadStateNotRunning status -> ps.ends_atomic_block\n   | ThreadStateProcessStopped stop_reason -> ps.ends_atomic_block)\n  &&\n  (match ps.statement with\n   | CreateThreadStatement _ initial_pc _ _ _ _ _ -> not (is_nonyielding_pc initial_pc)\n   | _ -> true)\n\nlet efficient_is_yielding_pc\n  (is_nonyielding_pc: array_t bool)\n  (pc: nat)\n  : GTot bool =\n  match array_nth is_nonyielding_pc pc with\n  | Some b -> not b\n  | None -> false\n\nlet efficient_is_nonyielding_pc\n  (is_nonyielding_pc: array_t bool)\n  (pc: nat)\n  : GTot bool =\n  match array_nth is_nonyielding_pc pc with\n  | Some b -> b\n  | None -> false\n\nlet efficient_action_consistent_with_is_nonyielding_pc\n  (is_nonyielding_pc: array_t bool)\n  (action: Armada.Action.t)\n  (pc_indices: statement_pc_indices_t)\n  : GTot bool =\n  let ps = action.program_statement in\n  (match pc_indices.start_pc_index with\n   | None -> ps.starts_atomic_block && ps.ends_atomic_block\n   | Some pc -> ps.starts_atomic_block = efficient_is_yielding_pc is_nonyielding_pc pc)\n  &&\n  (match efficient_program_statement_to_ending_thread_state ps pc_indices with\n   | EfficientThreadStateRunning -> ps.ends_atomic_block && None? pc_indices.start_pc_index\n   | EfficientThreadStateAtPC pc -> ps.ends_atomic_block = efficient_is_yielding_pc is_nonyielding_pc pc\n   | EfficientThreadStateNotRunning status -> ps.ends_atomic_block\n   | EfficientThreadStateProcessStopped stop_reason -> ps.ends_atomic_block)\n  &&\n  (match pc_indices.create_thread_initial_pc_index with\n   | Some initial_pc -> efficient_is_yielding_pc is_nonyielding_pc initial_pc\n   | None -> true)\n\nlet each_action_consistent_with_is_nonyielding_pc\n  (is_nonyielding_pc: pc_t -> GTot bool)\n  (actions: list Armada.Action.t)\n  : GTot bool =\n  for_all_ghost (action_consistent_with_is_nonyielding_pc is_nonyielding_pc) actions\n\nlet efficient_each_action_consistent_with_is_nonyielding_pc\n  (is_nonyielding_pc: array_t bool)\n  (actions: list Armada.Action.t)\n  (pc_indices_list: list statement_pc_indices_t)\n  : GTot bool =\n  lists_correspond\n    (fun action pc_indices -> efficient_action_consistent_with_is_nonyielding_pc is_nonyielding_pc action pc_indices)\n    actions pc_indices_list\n\nlet each_action_list_consistent_with_is_nonyielding_pc\n  (is_nonyielding_pc: pc_t -> GTot bool)\n  (actions_list: list (list Armada.Action.t))\n  : GTot bool =\n  for_all_ghost (each_action_consistent_with_is_nonyielding_pc is_nonyielding_pc) actions_list\n\nlet efficient_each_action_list_consistent_with_is_nonyielding_pc\n  (is_nonyielding_pc: array_t bool)\n  (actions_array: array_t (list Armada.Action.t))\n  (pc_indices_array: array_t (list statement_pc_indices_t))\n  : GTot bool =\n  arrays_correspond\n    (fun actions pc_indices_list ->\n      efficient_each_action_consistent_with_is_nonyielding_pc is_nonyielding_pc actions pc_indices_list)\n    actions_array pc_indices_array\n\nlet action_ends_atomic_block_if_necessary\n  (action: Armada.Action.t)\n  : GTot bool =\n  match program_statement_to_ending_thread_state action.program_statement with\n  | ThreadStateRunning -> action.program_statement.ends_atomic_block\n  | ThreadStateAtPC pc -> true\n  | ThreadStateNotRunning _ -> action.program_statement.ends_atomic_block\n  | ThreadStateProcessStopped _ -> action.program_statement.ends_atomic_block\n\nlet each_action_ends_atomic_block_if_necessary\n  (actions: list Armada.Action.t)\n  : GTot bool =\n  for_all_ghost action_ends_atomic_block_if_necessary actions\n\nlet each_action_list_ends_atomic_block_if_necessary\n  (actions_list: list (list Armada.Action.t))\n  : GTot bool =\n  for_all_ghost each_action_ends_atomic_block_if_necessary actions_list\n\nlet rec action_list_doesnt_internally_yield\n  (actions: list Armada.Action.t)\n  : GTot bool (decreases actions) =\n  match actions with\n  | [] -> true\n  | [action] -> true\n  | first_action :: second_action :: remaining_actions ->\n         not first_action.program_statement.ends_atomic_block\n      && not second_action.program_statement.starts_atomic_block\n      && first_action.ok\n      && action_list_doesnt_internally_yield (second_action :: remaining_actions)\n\nlet each_action_list_doesnt_internally_yield\n  (actions_list: list (list Armada.Action.t))\n  : GTot bool =\n  for_all_ghost action_list_doesnt_internally_yield actions_list\n\nlet rec consecutive_actions_end_and_start_with_same_pc\n  (actions: list Armada.Action.t)\n  : GTot bool =\n  match actions with\n  | [] -> true\n  | [action] -> true\n  | first_action :: second_action :: remaining_actions ->\n         first_action.program_statement.end_pc = second_action.program_statement.start_pc\n      && Some? first_action.program_statement.end_pc\n      && consecutive_actions_end_and_start_with_same_pc (second_action :: remaining_actions)\n\nlet each_action_list_has_consecutive_actions_end_and_start_with_same_pc\n  (actions_list: list (list Armada.Action.t))\n  : GTot bool =\n  for_all_ghost consecutive_actions_end_and_start_with_same_pc actions_list\n\nlet actions_start_atomic_block\n  (actions: list Armada.Action.t)\n  : GTot bool =\n  match actions with\n  | [] -> false\n  | action :: _ -> action.program_statement.starts_atomic_block\n\nlet rec actions_end_atomic_block\n  (actions: list Armada.Action.t)\n  : GTot bool =\n  match actions with\n  | [] -> false\n  | [action] -> action.program_statement.ends_atomic_block || not action.ok\n  | first_action :: remaining_actions -> actions_end_atomic_block remaining_actions\n\nlet do_actions_start_and_end_atomic_block\n  (actions: list Armada.Action.t)\n  : GTot (bool * bool) =\n  (actions_start_atomic_block actions, actions_end_atomic_block actions)\n\nlet rec steps_computation_implies_start_and_end_atomic_block\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (steps: list Armada.Step.t)\n  (s: Armada.State.t)\n  : Lemma (requires Some? (steps_computation_generic armada_semantics actor starts_atomic_block ends_atomic_block\n                             steps s))\n          (ensures  (let actions = map_ghost armada_step_to_action steps in\n                       actions_start_atomic_block actions = starts_atomic_block\n                     /\\ actions_end_atomic_block actions = ends_atomic_block))\n          (decreases steps) =\n  match steps with\n  | [] -> ()\n  | [last_step] -> ()\n  | first_step :: remaining_steps ->\n      (match step_computation_generic armada_semantics actor starts_atomic_block false first_step s with\n       | Some s' ->\n          steps_computation_implies_start_and_end_atomic_block actor false ends_atomic_block\n            remaining_steps s')\n"
  },
  {
    "path": "experimental/lib/Strategies.PCIndices.fst",
    "content": "module Strategies.PCIndices\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Statement\nopen Spec.Ubool\nopen Util.ImmutableArray\nopen Util.List\nopen Util.Relation\n\ntype statement_pc_indices_t = {\n  start_pc_index: option nat;\n  end_pc_index: option nat;\n  create_thread_initial_pc_index: option nat;\n  method_call_return_pc_index: option nat;\n}\n\nlet pc_matches_pc_index\n  (pcs: array_t pc_t)\n  (pc: pc_t)\n  (n: nat)\n  : GTot bool =\n  n < array_len pcs && pc = array_index pcs n\n\nlet optional_pc_matches_optional_pc_index\n  (pcs: array_t pc_t)\n  (optional_pc: option pc_t)\n  (optional_index: option nat)\n  : GTot bool =\n  match optional_pc, optional_index with\n  | None, None -> true\n  | Some pc, Some n -> pc_matches_pc_index pcs pc n\n  | _, _ -> false\n\nlet program_statement_corresponds_to_statement_pc_indices\n  (pcs: array_t pc_t)\n  (ps: program_statement_t)\n  (pc_indices: statement_pc_indices_t)\n  : GTot bool =\n     optional_pc_matches_optional_pc_index pcs ps.start_pc pc_indices.start_pc_index\n  && optional_pc_matches_optional_pc_index pcs ps.end_pc pc_indices.end_pc_index\n  && (match ps.statement with\n      | CreateThreadStatement _ initial_pc _ _ _ _ _ ->\n          optional_pc_matches_optional_pc_index pcs (Some initial_pc) pc_indices.create_thread_initial_pc_index\n      | _ -> None? pc_indices.create_thread_initial_pc_index)\n  && (match ps.statement with\n      | MethodCallStatement _ return_pc _ _ _ _ ->\n          optional_pc_matches_optional_pc_index pcs (Some return_pc) pc_indices.method_call_return_pc_index\n      | _ -> None? pc_indices.method_call_return_pc_index)\n\nlet action_corresponds_to_statement_pc_indices\n  (pcs: array_t pc_t)\n  (action: Armada.Action.t)\n  (pc_indices: statement_pc_indices_t)\n  : GTot bool =\n  program_statement_corresponds_to_statement_pc_indices pcs action.program_statement pc_indices\n\nlet actions_correspond_to_statement_pc_indices\n  (pcs: array_t pc_t)\n  (actions: array_t Armada.Action.t)\n  (pc_indices_array: array_t statement_pc_indices_t)\n  : GTot bool =\n  arrays_correspond (action_corresponds_to_statement_pc_indices pcs) actions pc_indices_array\n\nlet action_list_corresponds_to_statement_pc_indices_list\n  (pcs: array_t pc_t)\n  (actions: list Armada.Action.t)\n  (pc_indices_list: list statement_pc_indices_t)\n  : GTot bool =\n  lists_correspond (action_corresponds_to_statement_pc_indices pcs) actions pc_indices_list\n\nlet actions_array_corresponds_to_statement_pc_indices_array\n  (pcs: array_t pc_t)\n  (actions: array_t (list Armada.Action.t))\n  (pc_indices_array: array_t (list statement_pc_indices_t))\n  : GTot bool =\n  arrays_correspond (action_list_corresponds_to_statement_pc_indices_list pcs) actions pc_indices_array\n"
  },
  {
    "path": "experimental/lib/Strategies.PCRelation.fst",
    "content": "module Strategies.PCRelation\n\nopen Armada.Base\nopen Armada.Thread\nopen Armada.Threads\nopen Spec.Ubool\nopen Strategies.ArmadaInvariant.PositionsValid\nopen Util.Relation\n\nnoeq type pc_relation_t = {\n  relation: relation_t pc_t pc_t;\n  return_relation: one_to_one_relation_t pc_t pc_t;\n}\n\nlet equality_pc_relation : pc_relation_t =\n  {\n    relation = (fun pc1 pc2 -> pc1 = pc2);\n    return_relation = (fun pc1 pc2 -> pc1 = pc2);\n  }\n\nlet optional_pcs_match_per_pc_relation\n  (pc_relation: pc_relation_t)\n  (opc1: option pc_t)\n  (opc2: option pc_t)\n  : GTot bool =\n  match opc1, opc2 with\n  | Some pc1, Some pc2 -> pc_relation.relation pc1 pc2\n  | None, None -> true\n  | _, _ -> false\n\nlet extended_stack_frames_match_per_pc_relation\n  (pc_relation: pc_relation_t)\n  (eframe1: extended_stack_frame_t)\n  (eframe2: extended_stack_frame_t)\n  : GTot ubool =\n    pc_relation.relation eframe1.return_pc eframe2.return_pc\n  /\\ pc_relation.return_relation eframe1.return_pc eframe2.return_pc\n  /\\ eframe1.frame == eframe2.frame\n\nlet rec stacks_match_per_pc_relation\n  (pc_relation: pc_relation_t)\n  (stack1: list extended_stack_frame_t)\n  (stack2: list extended_stack_frame_t)\n  : GTot ubool =\n  match stack1, stack2 with\n  | [], [] -> True    \n  | eframe1 :: tail1, eframe2 :: tail2 ->\n        extended_stack_frames_match_per_pc_relation pc_relation eframe1 eframe2\n      /\\ stacks_match_per_pc_relation pc_relation tail1 tail2\n  | _ -> False\n\nlet threads_match_except_write_buffers_per_pc_relation\n  (pc_relation: pc_relation_t)\n  (threads1: Armada.Threads.t{positions_valid_in_threads threads1})\n  (threads2: Armada.Threads.t{positions_valid_in_threads threads2})\n  : GTot ubool =\n  forall tid.{:pattern (threads1 tid).status}\n    let thread1 = threads1 tid in\n    let thread2 = threads2 tid in\n      thread1.status == thread2.status\n    /\\ (ThreadStatusRunning? thread1.status ==>\n            pc_relation.relation thread1.pc thread2.pc\n         /\\ thread1.top == thread2.top\n         /\\ stacks_match_per_pc_relation pc_relation thread1.stack thread2.stack)\n\nlet write_messages_match\n  (write_message1: write_message_t)\n  (write_message2: write_message_t)\n  : GTot bool =\n     write_message1.location = write_message2.location\n  && write_message1.primitive_td = write_message2.primitive_td\n  && write_message1.version = write_message2.version\n  // no need for any relationship for writer_pc and writer_expression_number fields since they don't affect behavior\n\nlet rec write_buffers_match\n  (write_buffer1: list write_message_t)\n  (write_buffer2: list write_message_t)\n  : GTot ubool =\n  match write_buffer1, write_buffer2 with\n  | [], [] -> True\n  | write_message1 :: tail1, write_message2 :: tail2 ->\n        write_messages_match write_message1 write_message2\n      /\\ write_buffers_match tail1 tail2\n  | _, _ -> False\n\nlet rec equality_pc_relation_implies_stack_matches_itself\n  (stack: list extended_stack_frame_t)\n  : Lemma (stacks_match_per_pc_relation equality_pc_relation stack stack) =\n  match stack with\n  | [] -> ()\n  | eframe :: tail -> equality_pc_relation_implies_stack_matches_itself tail\n\nlet rec equality_pc_relation_implies_write_buffer_matches_itself\n  (write_buffer: list write_message_t)\n  : Lemma (ensures write_buffers_match write_buffer write_buffer) =\n  match write_buffer with\n  | [] -> ()\n  | write_message :: tail -> equality_pc_relation_implies_write_buffer_matches_itself tail\n"
  },
  {
    "path": "experimental/lib/Strategies.RegularToAtomic.Armada.Helper.fst",
    "content": "module Strategies.RegularToAtomic.Armada.Helper\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Transition\nopen Armada.Type\nopen FStar.List.Tot\nopen Spec.Behavior\nopen Spec.List\nopen Spec.Logic\nopen Spec.Map\nopen Spec.Ubool\nopen Strategies.ArmadaStatement.Status\nopen Strategies.Atomic\nopen Strategies.RegularToAtomic\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\nopen Util.Behavior\nopen Util.List\nopen Util.Nth\n\nlet is_breaking_optional_pc\n  (pc_breaking: pc_t -> GTot bool)\n  (optional_pc: option pc_t)\n  : GTot bool =\n  match optional_pc with\n  | Some pc -> pc_breaking pc\n  | None -> true\n\nlet pc_breaking_correct_specific\n  (pc_breaking: pc_t -> GTot bool)\n  (ps: program_statement_t)\n  : GTot bool =\n     is_breaking_optional_pc pc_breaking ps.start_pc = ps.starts_atomic_block\n  && is_breaking_optional_pc pc_breaking ps.end_pc = ps.ends_atomic_block\n  && (implies (None? ps.end_pc) (is_breaking_optional_pc pc_breaking ps.start_pc))\n\nlet pc_breaking_correct\n  (lprog: Armada.Program.t)\n  (pc_breaking: pc_t -> GTot bool)\n  : GTot bool =\n  for_all_ghost (pc_breaking_correct_specific pc_breaking) lprog.program_statements\n\nlet created_threads_initially_breaking_specific\n  (pc_breaking: pc_t -> GTot bool)\n  (ps: program_statement_t)\n  : GTot bool =\n  match ps.statement with\n  | CreateThreadStatement _ initial_pc _ _ _ _ _ -> pc_breaking initial_pc\n  | _ -> true\n\nlet created_threads_initially_breaking\n  (lprog: Armada.Program.t)\n  (pc_breaking: pc_t -> GTot bool)\n  : GTot bool =\n  for_all_ghost (created_threads_initially_breaking_specific pc_breaking) lprog.program_statements\n\nlet actions_starting_at_pc_correct_specific\n  (actions_starting_at_pc: option pc_t -> GTot (list Armada.Action.t))\n  (action: Armada.Action.t)\n  : GTot ubool =\n  contains_ubool action (actions_starting_at_pc action.program_statement.start_pc)\n\nlet actions_starting_at_pc_correct\n  (lprog: Armada.Program.t)\n  (actions_starting_at_pc: option pc_t -> GTot (list Armada.Action.t))\n  : GTot ubool =\n  for_all_ubool (actions_starting_at_pc_correct_specific actions_starting_at_pc) (all_actions lprog.program_statements)\n\nlet starting_successors_match_path_infos_specific\n  (starting_successors: list (successor_info_t armada_semantics))\n  (atomic_path_infos: list (atomic_path_info_t armada_semantics))\n  (successor: successor_info_t armada_semantics)\n  : GTot ubool =\n    successor.path_index < length atomic_path_infos\n  /\\ (index atomic_path_infos successor.path_index).path == [successor.action]\n\nlet starting_successors_match_path_infos\n  (starting_successors: list (successor_info_t armada_semantics))\n  (atomic_path_infos: list (atomic_path_info_t armada_semantics))\n  : GTot ubool =\n  for_all_ubool\n    (starting_successors_match_path_infos_specific starting_successors atomic_path_infos)\n    starting_successors\n\nlet path_successor_matches_path_info\n  (atomic_path_infos: list (atomic_path_info_t armada_semantics))\n  (atomic_path_info: atomic_path_info_t armada_semantics)\n  (successor: successor_info_t armada_semantics)\n  : GTot ubool =\n     successor.path_index < length atomic_path_infos\n  /\\ (index atomic_path_infos successor.path_index).path == append atomic_path_info.path [successor.action]\n\nlet path_successors_match_path_infos_specific\n  (atomic_path_infos: list (atomic_path_info_t armada_semantics))\n  (atomic_path_info: atomic_path_info_t armada_semantics)\n  : GTot ubool =\n  for_all_ubool (path_successor_matches_path_info atomic_path_infos atomic_path_info) atomic_path_info.successors\n\nlet path_successors_match_path_infos\n  (atomic_path_infos: list (atomic_path_info_t armada_semantics))\n  : GTot ubool =\n  for_all_ubool (path_successors_match_path_infos_specific atomic_path_infos) atomic_path_infos\n\nlet is_breaking_armada_action (pc_breaking: pc_t -> GTot bool) (action: Armada.Action.t) : GTot bool =\n    not action.ok\n  || is_breaking_optional_pc pc_breaking action.program_statement.end_pc\n  || (match action.program_statement.statement with\n     | AssertFalseStatement _\n     | TerminateProcessStatement _\n     | TerminateThreadStatement _\n     | MethodCallStatement _ _ _ _ _ true -> true\n     | _ -> false)\n\nlet path_breaking_correct_specific\n  (pc_breaking: pc_t -> GTot bool)\n  (atomic_path_info: atomic_path_info_t armada_semantics)\n  : GTot bool =\n     Cons? atomic_path_info.path\n  && atomic_path_info.breaking = is_breaking_armada_action pc_breaking (last atomic_path_info.path)\n\nlet path_breaking_correct\n  (pc_breaking: pc_t -> GTot bool)\n  (atomic_path_infos: list (atomic_path_info_t armada_semantics))\n  : GTot bool =\n  for_all_ghost (path_breaking_correct_specific pc_breaking) atomic_path_infos\n\nlet path_atomic_index_correct\n  (hprog_actions: list (list Armada.Action.t))\n  (atomic_path_info: atomic_path_info_t armada_semantics)\n  : GTot ubool =\n  atomic_path_info.breaking ==>\n      atomic_path_info.atomic_action_index < length hprog_actions\n    /\\ atomic_path_info.path == index hprog_actions atomic_path_info.atomic_action_index\n\nlet path_atomic_indices_correct\n  (hprog_actions: list (list Armada.Action.t))\n  (atomic_path_infos: list (atomic_path_info_t armada_semantics))\n  : GTot ubool =\n  for_all_ubool (path_atomic_index_correct hprog_actions) atomic_path_infos\n\nlet path_action_in_lprog\n  (lprog: Armada.Program.t)\n  (action: Armada.Action.t)\n  : GTot ubool =\n  contains_ubool action.program_statement lprog.program_statements\n\nlet path_actions_in_lprog_specific\n  (lprog: Armada.Program.t)\n  (atomic_path_info: atomic_path_info_t armada_semantics)\n  : GTot ubool =\n  for_all_ubool (path_action_in_lprog lprog) atomic_path_info.path\n\nlet path_actions_in_lprog\n  (lprog: Armada.Program.t)\n  (atomic_path_infos: list (atomic_path_info_t armada_semantics))\n  : GTot ubool =\n  for_all_ubool (path_actions_in_lprog_specific lprog) atomic_path_infos\n\nlet action_matches_successor\n  (action: Armada.Action.t)\n  (successor: successor_info_t armada_semantics)\n  : GTot ubool =\n  action == successor.action\n\nlet successors_include_action\n  (successors: list (successor_info_t armada_semantics))\n  (action: Armada.Action.t)\n  : GTot ubool =\n  exists_ubool (action_matches_successor action) successors\n\nlet starting_successors_reflect_action\n  (pc_breaking: pc_t -> GTot bool)\n  (starting_successors: list (successor_info_t armada_semantics))\n  (action: Armada.Action.t)\n  : GTot ubool =\n  is_breaking_optional_pc pc_breaking action.program_statement.start_pc ==>\n    successors_include_action starting_successors action\n\nlet starting_successors_complete\n  (lprog: Armada.Program.t)\n  (pc_breaking: pc_t -> GTot bool)\n  (starting_successors: list (successor_info_t armada_semantics))\n  : GTot ubool =\n  for_all_ubool (starting_successors_reflect_action pc_breaking starting_successors)\n    (all_actions lprog.program_statements)\n\nlet path_successors_complete_specific\n  (actions_starting_at_pc: option pc_t -> GTot (list Armada.Action.t))\n  (atomic_path_info: atomic_path_info_t armada_semantics)\n  : GTot ubool =\n  not atomic_path_info.breaking ==>\n       length atomic_path_info.path > 0\n    /\\ (let final_action = last atomic_path_info.path in\n       let actions = actions_starting_at_pc (final_action.program_statement.end_pc) in\n       for_all_ubool (successors_include_action atomic_path_info.successors) actions)\n\nlet path_successors_complete\n  (actions_starting_at_pc: option pc_t -> GTot (list Armada.Action.t))\n  (atomic_path_infos: list (atomic_path_info_t armada_semantics))\n  : GTot ubool =\n  for_all_ubool (path_successors_complete_specific actions_starting_at_pc) atomic_path_infos\n\nnoeq type regular_refines_atomic_params_t = {\n  sem: semantics_t;\n  lprog: program_t sem;\n  hprog: program_t (make_atomic_semantics sem);\n  is_breaking_state: sem.state_t -> sem.actor_t -> GTot bool;\n  starting_successors: list (successor_info_t sem);\n  atomic_path_infos: list (atomic_path_info_t sem);\n}\n\nnoeq type armada_refines_atomic_relation_t = {\n  lprog: Armada.Program.t;\n  hprog: program_t (make_atomic_semantics armada_semantics);\n  pc_breaking: pc_t -> GTot bool;\n  actions_starting_at_pc: option pc_t -> GTot (list Armada.Action.t);\n  starting_successors: list (successor_info_t armada_semantics);\n  atomic_path_infos: list (atomic_path_info_t armada_semantics);\n\n  actions_starting_at_pc_correct_proof: unit ->\n    squash (actions_starting_at_pc_correct lprog actions_starting_at_pc);\n\n  starting_successors_match_path_infos_proof: unit ->\n    squash (starting_successors_match_path_infos starting_successors atomic_path_infos);\n\n  path_successors_match_path_infos_proof: unit ->\n    squash (path_successors_match_path_infos atomic_path_infos);\n\n  path_breaking_correct_proof: unit ->\n    squash (path_breaking_correct pc_breaking atomic_path_infos);\n\n  path_atomic_indices_correct_proof: unit ->\n    squash (path_atomic_indices_correct hprog.actions atomic_path_infos);\n\n  path_actions_in_lprog_proof: unit ->\n    squash (path_actions_in_lprog lprog atomic_path_infos);\n\n  starting_successors_complete_proof: unit ->\n    squash (starting_successors_complete lprog pc_breaking starting_successors);\n\n  path_successors_complete_proof: unit ->\n    squash (path_successors_complete actions_starting_at_pc atomic_path_infos);\n\n  created_threads_initially_breaking_proof: unit ->\n    squash (created_threads_initially_breaking lprog pc_breaking);\n\n  pc_breaking_correct_proof: unit ->\n    squash (pc_breaking_correct lprog pc_breaking);\n\n  main_start_pc_breaking_proof: unit ->\n    squash (pc_breaking lprog.main_start_pc);\n\n  inits_identical_proof: unit ->\n    squash (Armada.Program.init_program lprog == hprog.init_f);\n}\n\nlet my_is_breaking_state\n  (pc_breaking: pc_t -> GTot bool)\n  (s: Armada.State.t)\n  (tid: tid_t)\n  : GTot bool =\n  if NotStopped? s.stop_reason then\n    let thread = s.threads tid in\n    if ThreadStatusRunning? thread.status then\n      pc_breaking thread.pc\n    else\n      true\n  else\n    true\n\nlet aa_to_ra_params (aa: armada_refines_atomic_relation_t) : GTot regular_refines_atomic_params_t =\n  {\n    sem = armada_semantics;\n    lprog = armada_program_to_generic aa.lprog;\n    hprog = aa.hprog;\n    is_breaking_state = my_is_breaking_state aa.pc_breaking;\n    starting_successors = aa.starting_successors;\n    atomic_path_infos = aa.atomic_path_infos;\n  }\n\nlet step_not_ending_atomic_block_ends_at_pc\n  (aa: armada_refines_atomic_relation_t)\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (step: Armada.Step.t)\n  (s: Armada.State.t)\n  : Lemma (requires (  contains_ubool step.action.program_statement aa.lprog.program_statements\n                     /\\ Some? (step_computation actor starts_atomic_block false step s)))\n          (ensures  (  Some? step.action.program_statement.end_pc\n                     /\\ (let s' = Some?.v (step_computation actor starts_atomic_block false step s) in\n                        let pc' = Some?.v step.action.program_statement.end_pc in\n                        (s'.threads actor).pc = pc'))) =\n  aa.pc_breaking_correct_proof ()\n\nlet rec steps_not_ending_atomic_block_end_at_pc\n  (aa: armada_refines_atomic_relation_t)\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (steps: list Armada.Step.t)\n  (s: Armada.State.t)\n  : Lemma (requires (  Cons? steps\n                     /\\ (let step = last steps in\n                        contains_ubool step.action.program_statement aa.lprog.program_statements)\n                     /\\ Some? (steps_computation_generic armada_semantics actor starts_atomic_block\n                                false steps s)))\n          (ensures  (let step = last steps in\n                       Some? step.action.program_statement.end_pc\n                     /\\ (let s' = Some?.v (steps_computation_generic armada_semantics actor\n                                            starts_atomic_block false steps s) in\n                        let pc' = Some?.v step.action.program_statement.end_pc in\n                        (s'.threads actor).pc = pc')))\n          (decreases steps) =\n  match steps with\n  | [last_step] -> step_not_ending_atomic_block_ends_at_pc aa actor starts_atomic_block last_step s\n  | first_step :: remaining_steps ->\n      let s_mid = Some?.v (step_computation actor starts_atomic_block false first_step s) in\n      steps_not_ending_atomic_block_end_at_pc aa actor false remaining_steps s_mid\n\nlet lemma_starting_successors_match_path_infos\n  (aa: armada_refines_atomic_relation_t)\n  (rap: regular_refines_atomic_params_t)\n  (successor: successor_info_t armada_semantics{\n       rap == aa_to_ra_params aa\n     /\\ contains_ubool successor rap.starting_successors})\n  : squash (   successor.path_index < length rap.atomic_path_infos\n            /\\ (index rap.atomic_path_infos successor.path_index).path == [successor.action]) =\n  aa.starting_successors_match_path_infos_proof ()\n\n#push-options \"--z3rlimit 10\"\n\nlet lemma_path_successors_match_path_infos\n  (aa: armada_refines_atomic_relation_t)\n  (rap: regular_refines_atomic_params_t)\n  (atomic_path_info: atomic_path_info_t armada_semantics)\n  (successor: successor_info_t armada_semantics{\n       rap == aa_to_ra_params aa\n     /\\ contains_ubool atomic_path_info rap.atomic_path_infos\n     /\\ contains_ubool successor atomic_path_info.successors})\n  : squash (   successor.path_index < length rap.atomic_path_infos\n            /\\ (index rap.atomic_path_infos successor.path_index).path ==\n                 append atomic_path_info.path [successor.action]) =\n  aa.path_successors_match_path_infos_proof ()\n\n#pop-options\n\nlet executing_step_leads_to_breaking\n  (aa: armada_refines_atomic_relation_t)\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (step: Armada.Step.t)\n  (s: Armada.State.t)\n  (s': Armada.State.t)\n  : Lemma (requires Some s' == step_computation_generic armada_semantics actor starts_atomic_block\n                                 ends_atomic_block step s\n                    /\\ contains_ubool step.action.program_statement aa.lprog.program_statements\n                    /\\ (starts_atomic_block ==> my_is_breaking_state aa.pc_breaking s actor))\n          (ensures (let action = armada_semantics.step_to_action_f step in\n                    my_is_breaking_state aa.pc_breaking s' actor = is_breaking_armada_action aa.pc_breaking action)) =\n  let action = armada_semantics.step_to_action_f step in\n  let program_statement = action.program_statement in\n  let statement = program_statement.statement in\n  aa.pc_breaking_correct_proof ();\n  executing_step_changes_status_depending_on_statement actor starts_atomic_block ends_atomic_block step s\n\nlet rec executing_steps_on_path_leads_to_breaking\n  (aa: armada_refines_atomic_relation_t)\n  (path: list Armada.Action.t)\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (steps: list Armada.Step.t)\n  (s: Armada.State.t)\n  (s': Armada.State.t)\n  : Lemma (requires   map_ghost armada_semantics.step_to_action_f steps == path\n                    /\\ Cons? path\n                    /\\ Some s' == steps_computation_generic armada_semantics actor starts_atomic_block\n                                   ends_atomic_block steps s\n                    /\\ for_all_ubool (fun action -> contains_ubool action.program_statement aa.lprog.program_statements)\n                        path\n                    /\\ (starts_atomic_block ==> my_is_breaking_state aa.pc_breaking s actor))\n           (ensures  my_is_breaking_state aa.pc_breaking s' actor =\n                       is_breaking_armada_action aa.pc_breaking (last path)) =\n  match steps with\n  | [last_step] -> executing_step_leads_to_breaking aa actor starts_atomic_block ends_atomic_block last_step s s'\n  | first_step :: remaining_steps ->\n      let s_mid = Some?.v (step_computation_generic armada_semantics actor starts_atomic_block false\n                             first_step s) in\n      executing_steps_on_path_leads_to_breaking aa (Cons?.tl path) actor false ends_atomic_block remaining_steps\n        s_mid s'\n\nlet executing_step_starts_at_pc\n  (aa: armada_refines_atomic_relation_t)\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (step: Armada.Step.t)\n  (s: Armada.State.t)\n  : Lemma (requires   Some? (step_computation_generic armada_semantics actor starts_atomic_block\n                               ends_atomic_block step s)\n                    /\\ contains_ubool step.action.program_statement aa.lprog.program_statements)\n          (ensures (match step.action.program_statement.start_pc with\n                    | None -> starts_atomic_block\n                    | Some pc -> pc = (s.threads actor).pc)) =\n  aa.pc_breaking_correct_proof ()\n\nlet lemma_path_breaking_correct\n  (aa: armada_refines_atomic_relation_t)\n  (rap: regular_refines_atomic_params_t)\n  (atomic_path_info: atomic_path_info_t armada_semantics)\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (steps: list Armada.Step.t)\n  (s: Armada.State.t{\n      rap == aa_to_ra_params aa\n    /\\ contains_ubool atomic_path_info rap.atomic_path_infos\n    /\\ (map_ghost armada_semantics.step_to_action_f steps) == atomic_path_info.path\n    /\\ Some? (steps_computation_generic armada_semantics actor starts_atomic_block\n               ends_atomic_block steps s)\n    /\\ (starts_atomic_block ==> rap.is_breaking_state s actor)})\n  : squash (let s' = Some?.v (steps_computation_generic armada_semantics actor\n                                starts_atomic_block ends_atomic_block steps s) in\n            (atomic_path_info.breaking = rap.is_breaking_state s' actor)) =\n  aa.path_breaking_correct_proof ();\n  let s' = Some?.v (steps_computation_generic armada_semantics actor starts_atomic_block\n                      ends_atomic_block steps s) in\n  aa.path_actions_in_lprog_proof ();\n  executing_steps_on_path_leads_to_breaking aa atomic_path_info.path actor starts_atomic_block ends_atomic_block\n    steps s s'\n\nlet lemma_path_atomic_indices_correct\n  (aa: armada_refines_atomic_relation_t)\n  (rap: regular_refines_atomic_params_t)\n  (atomic_path_info: atomic_path_info_t rap.sem{\n       rap == aa_to_ra_params aa\n     /\\ contains_ubool atomic_path_info rap.atomic_path_infos\n     /\\ atomic_path_info.breaking})\n  : squash (   atomic_path_info.atomic_action_index < length rap.hprog.actions\n            /\\ index rap.hprog.actions atomic_path_info.atomic_action_index == atomic_path_info.path) =\n  aa.path_atomic_indices_correct_proof ()\n\n#push-options \"--z3cliopt smt.qi.eager_threshold=100\"\n\nlet lemma_starting_successors_complete\n  (aa: armada_refines_atomic_relation_t)\n  (rap: regular_refines_atomic_params_t)\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (step: Armada.Step.t)\n  (s: Armada.State.t{\n      rap == aa_to_ra_params aa\n    /\\ contains_ubool step.action rap.lprog.actions\n    /\\ rap.is_breaking_state s actor\n    /\\ Some? (step_computation_generic armada_semantics actor starts_atomic_block\n               ends_atomic_block step s)})\n  : squash (action_among_successors armada_semantics step.action rap.starting_successors) =\n  aa.starting_successors_complete_proof ()\n\nlet lemma_path_successors_complete\n  (aa: armada_refines_atomic_relation_t)\n  (rap: regular_refines_atomic_params_t)\n  (atomic_path_info: atomic_path_info_t armada_semantics)\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (steps: list Armada.Step.t)\n  (step: Armada.Step.t)\n  (s: Armada.State.t{\n      rap == aa_to_ra_params aa\n    /\\ contains_ubool atomic_path_info rap.atomic_path_infos\n    /\\ map_ghost armada_step_to_action steps == atomic_path_info.path\n    /\\ contains_ubool step.action rap.lprog.actions\n    /\\ not atomic_path_info.breaking\n    /\\ (match steps_computation_generic armada_semantics actor starts_atomic_block\n               false steps s with\n       | None -> False\n       | Some s' -> Some? (step_computation_generic armada_semantics actor false\n                            ends_atomic_block step s'))})\n  : squash (action_among_successors armada_semantics step.action atomic_path_info.successors) =\n  let s' = Some?.v (steps_computation_generic armada_semantics actor starts_atomic_block false\n                      steps s) in\n  aa.path_actions_in_lprog_proof ();\n  list_contains_last atomic_path_info.path;\n  map_ghost_maps_last armada_step_to_action steps;\n  steps_not_ending_atomic_block_end_at_pc aa actor starts_atomic_block steps s;\n  all_actions_has_all_actions step.action aa.lprog.program_statements;\n  executing_step_starts_at_pc aa actor false ends_atomic_block step s';\n  aa.path_successors_complete_proof ();\n  aa.actions_starting_at_pc_correct_proof ()\n\n#pop-options\n\nlet lemma_actions_dont_unbreak_other_actors\n  (aa: armada_refines_atomic_relation_t)\n  (rap: regular_refines_atomic_params_t)\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (step: Armada.Step.t)\n  (s: Armada.State.t{\n    let action = step.action in\n      rap == aa_to_ra_params aa\n    /\\ contains_ubool action rap.lprog.actions\n    /\\ Some? (step_computation_generic armada_semantics actor starts_atomic_block\n               ends_atomic_block step s)})\n  : squash (let s' = Some?.v (step_computation_generic armada_semantics actor\n                                starts_atomic_block ends_atomic_block step s) in\n            forall other_actor. rap.is_breaking_state s other_actor /\\ actor <> other_actor ==>\n                             rap.is_breaking_state s' other_actor) =\n  step_effects_on_other_threads actor starts_atomic_block ends_atomic_block step s;\n  if not step.action.ok then\n    ()\n  else (\n    match step.action.program_statement.statement with\n    | CreateThreadStatement _ _ _ _ _ _ _ ->\n        all_actions_has_all_actions step.action aa.lprog.program_statements;\n        aa.created_threads_initially_breaking_proof ()\n    | JoinStatement _ -> ()\n    | PropagateWriteMessageStatement -> ()\n    | _ -> ()\n  )\n\nlet lemma_actions_break_if_last_in_transition\n  (aa: armada_refines_atomic_relation_t)\n  (rap: regular_refines_atomic_params_t)\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (step: Armada.Step.t)\n  (s: Armada.State.t{\n      rap == aa_to_ra_params aa\n    /\\ contains_ubool step.action rap.lprog.actions\n    /\\ Some? (step_computation_generic armada_semantics actor starts_atomic_block true step s)\n    /\\ (starts_atomic_block ==> rap.is_breaking_state s actor)})\n  : squash (let s' = Some?.v (step_computation_generic armada_semantics actor\n                               starts_atomic_block true step s) in\n            rap.is_breaking_state s' actor) =\n  if not step.action.ok then\n    ()\n  else (\n    let s' = Some?.v (step_computation_generic armada_semantics actor starts_atomic_block true step s) in\n    aa.pc_breaking_correct_proof ();\n    all_actions_has_all_actions step.action aa.lprog.program_statements;\n    assert (is_breaking_optional_pc aa.pc_breaking step.action.program_statement.end_pc);\n    executing_step_changes_status_depending_on_statement actor starts_atomic_block true step s;\n    executing_step_starts_at_pc aa actor starts_atomic_block true step s\n  )\n\nlet lemma_init_breaks_all_actors\n  (aa: armada_refines_atomic_relation_t)\n  (rap: regular_refines_atomic_params_t)\n  (s: Armada.State.t{rap == aa_to_ra_params aa /\\ rap.lprog.init_f s})\n  : squash (forall actor. rap.is_breaking_state s actor) =\n  aa.main_start_pc_breaking_proof ()\n\nlet lemma_init_implies_init\n  (aa: armada_refines_atomic_relation_t)\n  (rap: regular_refines_atomic_params_t)\n  (s: Armada.State.t{rap == aa_to_ra_params aa /\\ rap.lprog.init_f s})\n  : squash (rap.hprog.init_f s) =\n  aa.inits_identical_proof ()\n\nlet aa_to_ra (aa: armada_refines_atomic_relation_t)\n  : GTot (ra: regular_refines_atomic_relation_t{\n              ra.sem == armada_semantics\n            /\\ ra.lprog == armada_program_to_generic aa.lprog\n            /\\ ra.hprog == aa.hprog}) =\n  let rap = aa_to_ra_params aa in\n  let ra: regular_refines_atomic_relation_t =\n  {\n     sem = rap.sem;\n     lprog = rap.lprog;\n     hprog = rap.hprog;\n     is_breaking_state = rap.is_breaking_state;\n     starting_successors = rap.starting_successors;\n     atomic_path_infos = rap.atomic_path_infos;\n     starting_successors_match_path_infos_proof = lemma_starting_successors_match_path_infos aa rap;\n     path_successors_match_path_infos_proof = lemma_path_successors_match_path_infos aa rap;\n     path_breaking_correct_proof = lemma_path_breaking_correct aa rap;\n     path_atomic_indices_correct_proof = lemma_path_atomic_indices_correct aa rap;\n     starting_successors_complete_proof = lemma_starting_successors_complete aa rap;\n     path_successors_complete_proof = lemma_path_successors_complete aa rap;\n     actions_dont_unbreak_other_actors_proof = lemma_actions_dont_unbreak_other_actors aa rap;\n     actions_break_if_last_in_transition_proof = lemma_actions_break_if_last_in_transition aa rap;\n     init_breaks_all_actors_proof = lemma_init_breaks_all_actors aa rap;\n     init_implies_init_proof = lemma_init_implies_init aa rap;\n   } in\n   ra\n\nlet armada_refines_atomic_relation_implies_refinement (aa: armada_refines_atomic_relation_t)\n  : Lemma (ensures (spec_refines_spec\n                    (program_to_spec aa.lprog)\n                    (semantics_to_spec (make_atomic_semantics armada_semantics) aa.hprog)\n                    eq2)) =\n  let ra: regular_refines_atomic_relation_t = aa_to_ra aa in\n  regular_refines_atomic_relation_implies_refinement ra;\n  armada_spec_refines_generic aa.lprog;\n  spec_refinement_transitivity\n    (program_to_spec aa.lprog)\n    (semantics_to_spec ra.sem ra.lprog)\n    (semantics_to_spec (make_atomic_semantics ra.sem) ra.hprog)\n    eq2\n    eq2\n    eq2\n"
  },
  {
    "path": "experimental/lib/Strategies.RegularToAtomic.Armada.fst",
    "content": "module Strategies.RegularToAtomic.Armada\n\nopen Armada.Base\nopen Armada.Computation\nopen Armada.Expression\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Pointer\nopen Armada.State\nopen Armada.Step\nopen Armada.Transition\nopen Strategies.ArmadaStatement.Status\nopen Strategies.RegularToAtomic\nopen Strategies.RegularToAtomic.Armada.Helper\nopen Strategies.Semantics.Armada\nopen Util.Behavior\nopen Util.List\nopen Util.Logic\nopen Util.Nth\n\nlet default_action: Armada.Action.t = {\n  ok = true;\n  program_statement = {\n    start_pc = None;\n    end_pc = None;\n    starts_atomic_block = true;\n    ends_atomic_block = true;\n    statement = PropagateWriteMessageStatement;\n  }\n}\n\nlet armada_pc_index_and_pc_breaking\n  (lpcs: array_t pc_t)\n  (pc_index_breaking: array_t bool)\n  (pc: pc_t)\n  (pc_index: nat)\n  : GTot bool =\n     pc_index < array_len lpcs\n  && pc_index < array_len pc_index_breaking\n  && array_index lpcs pc_index = pc\n  && array_index pc_index_breaking pc_index = true\n\nlet armada_pc_index_breaking_to_pc_breaking\n  (lpcs: array_t pc_t)\n  (pc_index_breaking: array_t bool)\n  (pc: pc_t)\n  : GTot bool =\n  u2b (exists (pc_index: nat). armada_pc_index_and_pc_breaking lpcs pc_index_breaking pc pc_index)\n\nlet select_action_from_array\n  (actions_array: array_t Armada.Action.t)\n  (i: nat)\n  : GTot Armada.Action.t =\n  if i < array_len actions_array then array_index actions_array i else default_action\n\nlet armada_successor_info_to_successor_info\n  (lprog_actions_array: array_t Armada.Action.t)\n  (successor: armada_successor_info_t)\n  : GTot (successor_info_t armada_semantics) =\n  {\n    action = select_action_from_array lprog_actions_array successor.action_index;\n    path_index = successor.path_index;\n  }\n\nlet rec singleton_path_indices_offset_to_starting_successors\n  (lprog_actions_array: array_t Armada.Action.t)\n  (singleton_path_indices: array_t (option nat))\n  (offset: nat)\n  : GTot (list (successor_info_t armada_semantics))\n    (decreases array_len singleton_path_indices - offset) =\n  if offset >= array_len singleton_path_indices || offset >= array_len lprog_actions_array then\n    []\n  else\n    let remaining_starting_successors =\n      singleton_path_indices_offset_to_starting_successors lprog_actions_array singleton_path_indices (offset + 1) in\n    match array_index singleton_path_indices offset with\n    | None -> remaining_starting_successors\n    | Some path_index ->\n        let armada_successor: armada_successor_info_t = { action_index = offset; path_index = path_index; } in\n        let starting_successor = armada_successor_info_to_successor_info lprog_actions_array armada_successor in\n        starting_successor :: remaining_starting_successors\n\nlet singleton_path_indices_to_starting_successors\n  (lprog_actions_array: array_t Armada.Action.t)\n  (singleton_path_indices: array_t (option nat))\n  : GTot (list (successor_info_t armada_semantics)) =\n  singleton_path_indices_offset_to_starting_successors lprog_actions_array singleton_path_indices 0\n\nlet armada_actions_starting_at_pc_to_actions_starting_at_pc\n  (lprog_actions_array: array_t Armada.Action.t)\n  (lpcs: array_t pc_t)\n  (action_indices_starting_at_no_pc: list nat)\n  (action_indices_starting_at_pc_index: array_t (list nat))\n  (optional_pc: option pc_t)\n  : GTot (list Armada.Action.t) =\n  match optional_pc with\n  | None -> map_ghost (select_action_from_array lprog_actions_array) action_indices_starting_at_no_pc\n  | Some pc ->\n      (match find_in_array lpcs pc with\n       | None -> []\n       | Some idx ->\n          (match array_nth action_indices_starting_at_pc_index idx with\n           | None -> []\n           | Some action_indices -> map_ghost (select_action_from_array lprog_actions_array) action_indices))\n\nlet armada_atomic_path_info_to_atomic_path_info\n  (lprog_actions_array: array_t Armada.Action.t)\n  (atomic_path_info: armada_atomic_path_info_t)\n  : GTot (atomic_path_info_t armada_semantics) =\n  let path = map_ghost (select_action_from_array lprog_actions_array) atomic_path_info.path in\n  match atomic_path_info.atomic_action_index_or_successors with\n  | Inl atomic_action_index ->\n     {\n       path = path;\n       breaking = true;\n       atomic_action_index = atomic_action_index;\n       successors = [];\n     }\n  | Inr successors ->\n     {\n       path = path;\n       breaking = false;\n       atomic_action_index = 0;\n       successors = map_ghost (armada_successor_info_to_successor_info lprog_actions_array) successors;\n     }\n\n#push-options \"--z3rlimit 30\"\n\nlet actions_starting_at_pc_correct_lemma\n  (lprog: Armada.Program.t)\n  (aw: armada_refines_atomic_witness_t)\n  : Lemma (requires   armada_actions_starting_at_pc_correct aw.action_indices_starting_at_no_pc\n                        aw.action_indices_starting_at_pc_index aw.pc_indices_array\n                    /\\ aw.lprog_actions_array == list_to_array (all_actions lprog.program_statements)\n                    /\\ actions_correspond_to_statement_pc_indices aw.lpcs aw.lprog_actions_array aw.pc_indices_array\n                    /\\ array_elements_unique_ubool aw.lpcs)\n          (ensures  (let actions_starting_at_pc =\n                       armada_actions_starting_at_pc_to_actions_starting_at_pc aw.lprog_actions_array aw.lpcs\n                         aw.action_indices_starting_at_no_pc aw.action_indices_starting_at_pc_index in\n                     actions_starting_at_pc_correct lprog actions_starting_at_pc)) =\n  let actions_starting_at_pc =\n    armada_actions_starting_at_pc_to_actions_starting_at_pc aw.lprog_actions_array aw.lpcs\n      aw.action_indices_starting_at_no_pc aw.action_indices_starting_at_pc_index in\n  introduce forall action. contains_ubool action (all_actions lprog.program_statements) ==>\n                      contains_ubool action (actions_starting_at_pc action.program_statement.start_pc)\n  with introduce _ ==> _\n  with _. (\n    let action_index = contains_ubool_to_index action (all_actions lprog.program_statements) in\n    assert (array_index aw.lprog_actions_array action_index == action);\n    let pc_indices = array_index aw.pc_indices_array action_index in\n    assert (armada_actions_starting_at_pc_correct_specific aw.action_indices_starting_at_no_pc\n              aw.action_indices_starting_at_pc_index action_index pc_indices);\n    assert (action_corresponds_to_statement_pc_indices aw.lpcs action pc_indices);\n    match pc_indices.start_pc_index with\n    | None ->\n        contains_equivalent_to_contains_ubool action_index aw.action_indices_starting_at_no_pc;\n        map_ghost_contains_ubool (select_action_from_array aw.lprog_actions_array)\n          aw.action_indices_starting_at_no_pc action_index\n    | Some pc_index ->\n       let start_pc = Some?.v action.program_statement.start_pc in\n       array_elements_unique_ubool_implication aw.lpcs;\n       assert (find_in_array aw.lpcs start_pc == Some pc_index);\n       contains_equivalent_to_contains_ubool action_index\n         (array_index aw.action_indices_starting_at_pc_index pc_index);\n       map_ghost_contains_ubool (select_action_from_array aw.lprog_actions_array)\n         (array_index aw.action_indices_starting_at_pc_index pc_index) action_index\n  )\n\n#pop-options\n\nlet rec starting_successor_to_singleton_path_index\n  (lprog_actions_array: array_t Armada.Action.t)\n  (singleton_path_indices: array_t (option nat))\n  (offset: nat)\n  (successor: successor_info_t armada_semantics{\n    contains_ubool successor (singleton_path_indices_offset_to_starting_successors\n                               lprog_actions_array singleton_path_indices offset)})\n  : GTot (action_index: nat{   action_index < array_len lprog_actions_array\n                           /\\ action_index < array_len singleton_path_indices\n                           /\\ successor.action == array_index lprog_actions_array action_index\n                           /\\ array_index singleton_path_indices action_index = Some successor.path_index})\n    (decreases array_len singleton_path_indices - offset) =\n  if offset >= array_len singleton_path_indices || offset >= array_len lprog_actions_array then\n    false_elim ()\n  else\n    match array_index singleton_path_indices offset with\n    | None -> starting_successor_to_singleton_path_index lprog_actions_array singleton_path_indices (offset + 1)\n               successor\n    | Some path_index ->\n        let armada_successor: armada_successor_info_t = { action_index = offset; path_index = path_index; } in\n        let starting_successor = armada_successor_info_to_successor_info lprog_actions_array armada_successor in\n        if eqb starting_successor successor then\n          offset\n        else\n          starting_successor_to_singleton_path_index lprog_actions_array singleton_path_indices (offset + 1)\n             successor\n\nlet starting_successors_match_path_infos_lemma\n  (aw: armada_refines_atomic_witness_t)\n  : Lemma (requires   armada_singleton_path_indices_match_path_infos aw.atomic_path_infos\n                        aw.singleton_path_indices)\n          (ensures  (let starting_successors =\n                       singleton_path_indices_to_starting_successors aw.lprog_actions_array\n                         aw.singleton_path_indices in\n                     let atomic_path_infos =\n                       map_ghost (armada_atomic_path_info_to_atomic_path_info aw.lprog_actions_array)\n                         (array_to_list aw.atomic_path_infos) in\n                     starting_successors_match_path_infos starting_successors atomic_path_infos)) =\n  let starting_successors = singleton_path_indices_to_starting_successors aw.lprog_actions_array\n                              aw.singleton_path_indices in\n  let atomic_path_infos = map_ghost (armada_atomic_path_info_to_atomic_path_info aw.lprog_actions_array)\n                            (array_to_list aw.atomic_path_infos) in\n  introduce forall successor. contains_ubool successor starting_successors ==>\n                         starting_successors_match_path_infos_specific starting_successors atomic_path_infos successor\n  with introduce _ ==> _\n  with _. (\n    let action_index = starting_successor_to_singleton_path_index aw.lprog_actions_array aw.singleton_path_indices 0\n                        successor in\n    assert (armada_singleton_path_matches_path_infos_specific aw.atomic_path_infos action_index\n             (Some successor.path_index));\n    map_ghost_maps_index (armada_atomic_path_info_to_atomic_path_info aw.lprog_actions_array)\n      (array_to_list aw.atomic_path_infos) successor.path_index\n  )\n\nlet path_successors_match_path_infos_lemma\n  (aw: armada_refines_atomic_witness_t)\n  : Lemma (requires armada_path_successors_match_path_infos aw.atomic_path_infos)\n          (ensures  (let atomic_path_infos =\n                       map_ghost (armada_atomic_path_info_to_atomic_path_info aw.lprog_actions_array)\n                         (array_to_list aw.atomic_path_infos) in\n                     path_successors_match_path_infos atomic_path_infos)) =\n  let atomic_path_infos = map_ghost (armada_atomic_path_info_to_atomic_path_info aw.lprog_actions_array)\n                           (array_to_list aw.atomic_path_infos) in\n  introduce forall atomic_path_info. contains_ubool atomic_path_info atomic_path_infos ==>\n                                path_successors_match_path_infos_specific atomic_path_infos atomic_path_info\n  with introduce contains_ubool atomic_path_info atomic_path_infos ==>\n                   path_successors_match_path_infos_specific atomic_path_infos atomic_path_info\n  with _. (\n    let path_index = contains_ubool_to_index atomic_path_info atomic_path_infos in\n    map_ghost_maps_index (armada_atomic_path_info_to_atomic_path_info aw.lprog_actions_array)\n      (array_to_list aw.atomic_path_infos) path_index;\n    let armada_atomic_path_info = array_index aw.atomic_path_infos path_index in\n    assert (armada_path_successors_match_path_infos_specific aw.atomic_path_infos armada_atomic_path_info);\n    introduce forall successor. contains_ubool successor atomic_path_info.successors ==>\n                           path_successor_matches_path_info atomic_path_infos atomic_path_info successor\n    with introduce _ ==> _\n    with _. (\n      let armada_successor = reverse_map_element_of_map_ghost\n                               (armada_successor_info_to_successor_info aw.lprog_actions_array)\n                               (Inr?.v armada_atomic_path_info.atomic_action_index_or_successors) successor in\n      assert (armada_path_successor_matches_path_info aw.atomic_path_infos armada_atomic_path_info armada_successor);\n      assert (successor == armada_successor_info_to_successor_info aw.lprog_actions_array armada_successor);\n      map_ghost_maps_index (armada_atomic_path_info_to_atomic_path_info aw.lprog_actions_array)\n        (array_to_list aw.atomic_path_infos) successor.path_index;\n      append_commutes_with_map (select_action_from_array aw.lprog_actions_array) armada_atomic_path_info.path\n        [armada_successor.action_index]\n    )\n  )\n\nlet armada_is_breaking_action_implies_is_breaking_armada_action\n  (aw: armada_refines_atomic_witness_t)\n  (action: Armada.Action.t)\n  (pc_indices: statement_pc_indices_t)\n  : Lemma (requires   action_corresponds_to_statement_pc_indices aw.lpcs action pc_indices\n                    /\\ array_elements_unique_ubool aw.lpcs\n                    /\\ array_len aw.pc_index_breaking = array_len aw.lpcs)\n          (ensures  (let pc_breaking =\n                       armada_pc_index_breaking_to_pc_breaking aw.lpcs aw.pc_index_breaking in\n                     armada_is_breaking_action aw.pc_index_breaking action pc_indices =\n                       is_breaking_armada_action pc_breaking action)) =\n  array_elements_unique_ubool_implication aw.lpcs\n\nlet pc_matches_pc_index_implies_pc_breaking_matches\n  (aw: armada_refines_atomic_witness_t)\n  (pc: pc_t)\n  (pc_index: nat)\n  : Lemma (requires   pc_matches_pc_index aw.lpcs pc pc_index\n                    /\\ armada_pc_breaking_correct aw.lprog_actions_array aw.pc_indices_array aw.pc_index_breaking\n                    /\\ array_len aw.pc_index_breaking = array_len aw.lpcs\n                    /\\ array_elements_unique_ubool aw.lpcs)\n          (ensures  (let pc_breaking = armada_pc_index_breaking_to_pc_breaking aw.lpcs aw.pc_index_breaking in\n                     pc_breaking pc = array_index aw.pc_index_breaking pc_index)) =\n  let pc_breaking = armada_pc_index_breaking_to_pc_breaking aw.lpcs aw.pc_index_breaking in\n  array_elements_unique_ubool_implication aw.lpcs\n\nlet optional_pc_matches_optional_pc_index_implies_is_breaking_optional_pc_matches\n  (aw: armada_refines_atomic_witness_t)\n  (optional_pc: option pc_t)\n  (optional_pc_index: option nat)\n  : Lemma (requires   optional_pc_matches_optional_pc_index aw.lpcs optional_pc optional_pc_index\n                    /\\ armada_pc_breaking_correct aw.lprog_actions_array aw.pc_indices_array aw.pc_index_breaking\n                    /\\ array_len aw.pc_index_breaking = array_len aw.lpcs\n                    /\\ array_elements_unique_ubool aw.lpcs)\n          (ensures  (let pc_breaking = armada_pc_index_breaking_to_pc_breaking aw.lpcs aw.pc_index_breaking in\n                     is_breaking_optional_pc pc_breaking optional_pc =\n                       armada_is_breaking_optional_pc aw.pc_index_breaking optional_pc_index)) =\n  let pc_breaking = armada_pc_index_breaking_to_pc_breaking aw.lpcs aw.pc_index_breaking in\n  array_elements_unique_ubool_implication aw.lpcs;\n  match optional_pc, optional_pc_index with\n  | None, None -> ()\n  | Some pc, Some pc_index ->\n      pc_matches_pc_index_implies_pc_breaking_matches aw pc pc_index\n  | _, _ -> false_elim ()\n\n#push-options \"--z3rlimit 20\"\n\nlet path_breaking_correct_lemma\n  (aw: armada_refines_atomic_witness_t)\n  : Lemma (requires   armada_path_breaking_correct aw.pc_index_breaking aw.lprog_actions_array aw.pc_indices_array\n                        aw.atomic_path_infos\n                    /\\ actions_correspond_to_statement_pc_indices aw.lpcs aw.lprog_actions_array aw.pc_indices_array\n                    /\\ array_elements_unique_ubool aw.lpcs\n                    /\\ array_len aw.pc_index_breaking = array_len aw.lpcs)\n          (ensures  (let pc_breaking = armada_pc_index_breaking_to_pc_breaking aw.lpcs aw.pc_index_breaking in\n                     let atomic_path_infos =\n                       map_ghost (armada_atomic_path_info_to_atomic_path_info aw.lprog_actions_array)\n                         (array_to_list aw.atomic_path_infos) in\n                     path_breaking_correct pc_breaking atomic_path_infos)) =\n  let pc_breaking = armada_pc_index_breaking_to_pc_breaking aw.lpcs aw.pc_index_breaking in\n  let atomic_path_infos =\n    map_ghost (armada_atomic_path_info_to_atomic_path_info aw.lprog_actions_array)\n      (array_to_list aw.atomic_path_infos) in\n  introduce forall atomic_path_info. contains_ubool atomic_path_info atomic_path_infos ==>\n                                path_breaking_correct_specific pc_breaking atomic_path_info\n  with introduce _ ==> _\n  with _. (\n    let path_index = contains_ubool_to_index atomic_path_info atomic_path_infos in\n    map_ghost_maps_index (armada_atomic_path_info_to_atomic_path_info aw.lprog_actions_array)\n      (array_to_list aw.atomic_path_infos) path_index;\n    let armada_atomic_path_info = array_index aw.atomic_path_infos path_index in\n    assert (armada_atomic_path_info_to_atomic_path_info aw.lprog_actions_array armada_atomic_path_info ==\n              atomic_path_info);\n    assert (Cons? atomic_path_info.path);\n    assert (atomic_path_info.path == map_ghost (select_action_from_array aw.lprog_actions_array)\n                                       armada_atomic_path_info.path);\n    assert (atomic_path_info.breaking = Inl? armada_atomic_path_info.atomic_action_index_or_successors);\n    assert (armada_path_breaking_correct_specific aw.pc_index_breaking aw.lprog_actions_array aw.pc_indices_array\n              armada_atomic_path_info);\n    let action_index = last armada_atomic_path_info.path in\n    assert (atomic_path_info.breaking =\n              armada_is_breaking_action aw.pc_index_breaking (array_index aw.lprog_actions_array action_index)\n               (array_index aw.pc_indices_array action_index));\n    let pc_indices = array_index aw.pc_indices_array action_index in\n    let action = array_index aw.lprog_actions_array action_index in\n    map_ghost_maps_last (select_action_from_array aw.lprog_actions_array) armada_atomic_path_info.path;\n    assert (action == last atomic_path_info.path);\n    assert (action_corresponds_to_statement_pc_indices aw.lpcs action pc_indices);\n    assert (atomic_path_info.breaking = armada_is_breaking_action aw.pc_index_breaking action pc_indices);\n    armada_is_breaking_action_implies_is_breaking_armada_action aw action pc_indices;\n    assert (atomic_path_info.breaking = is_breaking_armada_action pc_breaking (last atomic_path_info.path))\n  )\n\nlet path_atomic_indices_correct_lemma\n  (lprog: Armada.Program.t)\n  (hprog: program_t (make_atomic_semantics armada_semantics))\n  (aw: armada_refines_atomic_witness_t)\n  : Lemma (requires   armada_path_atomic_indices_correct aw.lprog_actions_array aw.hprog_actions_array\n                        aw.atomic_path_infos\n                    /\\ aw.lprog_actions_array == list_to_array (all_actions lprog.program_statements)\n                    /\\ aw.hprog_actions_array == list_to_array hprog.actions)\n          (ensures  (let hprog_actions = hprog.actions in\n                     let atomic_path_infos =\n                       map_ghost (armada_atomic_path_info_to_atomic_path_info aw.lprog_actions_array)\n                         (array_to_list aw.atomic_path_infos) in\n                     path_atomic_indices_correct hprog_actions atomic_path_infos)) =\n  let hprog_actions = hprog.actions in\n  let atomic_path_infos =\n    map_ghost (armada_atomic_path_info_to_atomic_path_info aw.lprog_actions_array)\n      (array_to_list aw.atomic_path_infos) in\n  introduce forall atomic_path_info. contains_ubool atomic_path_info atomic_path_infos /\\ atomic_path_info.breaking ==>\n                                  atomic_path_info.atomic_action_index < length hprog_actions\n                                /\\ atomic_path_info.path == (index hprog_actions atomic_path_info.atomic_action_index)\n  with introduce _ ==> _\n  with _. (\n    let path_index = contains_ubool_to_index atomic_path_info atomic_path_infos in\n    map_ghost_maps_index (armada_atomic_path_info_to_atomic_path_info aw.lprog_actions_array)\n      (array_to_list aw.atomic_path_infos) path_index;\n    let armada_atomic_path_info = array_index aw.atomic_path_infos path_index in\n    assert (armada_path_atomic_index_correct aw.lprog_actions_array aw.hprog_actions_array armada_atomic_path_info);\n    let atomic_action_index = Inl?.v armada_atomic_path_info.atomic_action_index_or_successors in\n    let atomic_action = array_index aw.hprog_actions_array atomic_action_index in\n    assert (lists_correspond_ubool (armada_path_entry_correct aw.lprog_actions_array) armada_atomic_path_info.path\n              atomic_action);\n    assert (atomic_action == index hprog_actions atomic_path_info.atomic_action_index);\n    assert (lists_correspond_ubool (armada_path_entry_correct aw.lprog_actions_array) armada_atomic_path_info.path\n              (index hprog_actions atomic_path_info.atomic_action_index));\n    lists_correspond_ubool_implies_map_ghost (armada_path_entry_correct aw.lprog_actions_array)\n      (select_action_from_array aw.lprog_actions_array) armada_atomic_path_info.path\n      (index hprog_actions atomic_path_info.atomic_action_index)\n  )\n\n#pop-options\n\nlet path_actions_in_lprog_lemma\n  (lprog: Armada.Program.t)\n  (aw: armada_refines_atomic_witness_t)\n  : Lemma (requires   armada_path_actions_in_lprog (array_len aw.lprog_actions_array) aw.atomic_path_infos\n                    /\\ aw.lprog_actions_array == list_to_array (all_actions lprog.program_statements))\n          (ensures  (let atomic_path_infos =\n                       map_ghost (armada_atomic_path_info_to_atomic_path_info aw.lprog_actions_array)\n                         (array_to_list aw.atomic_path_infos) in\n                     path_actions_in_lprog lprog atomic_path_infos)) =\n  let atomic_path_infos =\n    map_ghost (armada_atomic_path_info_to_atomic_path_info aw.lprog_actions_array)\n      (array_to_list aw.atomic_path_infos) in\n  introduce forall atomic_path_info. contains_ubool atomic_path_info atomic_path_infos ==>\n                                path_actions_in_lprog_specific lprog atomic_path_info\n  with introduce contains_ubool atomic_path_info atomic_path_infos ==>\n                 path_actions_in_lprog_specific lprog atomic_path_info\n  with _. (\n    let path_index = contains_ubool_to_index atomic_path_info atomic_path_infos in\n    let num_actions = array_len aw.lprog_actions_array in\n    map_ghost_maps_index (armada_atomic_path_info_to_atomic_path_info aw.lprog_actions_array)\n      (array_to_list aw.atomic_path_infos) path_index;\n    let armada_atomic_path_info = array_index aw.atomic_path_infos path_index in\n    assert (armada_path_actions_in_lprog_specific num_actions armada_atomic_path_info);\n    assert (for_all_ghost (fun (action_index: nat) -> action_index < num_actions) armada_atomic_path_info.path);\n    introduce forall action. contains_ubool action atomic_path_info.path ==>\n                        path_action_in_lprog lprog action\n    with introduce _ ==> _\n    with _. (\n      let action_index: nat = reverse_map_element_of_map_ghost (select_action_from_array aw.lprog_actions_array)\n                              armada_atomic_path_info.path action in\n      index_to_contains_ubool (all_actions lprog.program_statements) action_index;\n      all_actions_has_all_actions action lprog.program_statements\n    )\n  )\n\nlet rec singleton_path_index_to_starting_successor\n  (lprog_actions_array: array_t Armada.Action.t)\n  (singleton_path_indices: array_t (option nat))\n  (offset: nat)\n  (action_index: nat{   action_index < array_len lprog_actions_array\n                    /\\ action_index < array_len singleton_path_indices\n                    /\\ action_index >= offset\n                    /\\ Some? (array_index singleton_path_indices action_index)})\n  : GTot (successor: successor_info_t armada_semantics{\n               successor.action == array_index lprog_actions_array action_index\n             /\\ contains_ubool successor (singleton_path_indices_offset_to_starting_successors\n                                           lprog_actions_array singleton_path_indices offset)})\n    (decreases array_len singleton_path_indices - offset) =\n  if action_index > offset then\n    singleton_path_index_to_starting_successor lprog_actions_array singleton_path_indices (offset + 1)\n      action_index\n  else\n    match array_index singleton_path_indices offset with\n    | None -> false_elim ()\n    | Some path_index ->\n        let action = array_index lprog_actions_array action_index in\n        let starting_successor = { action = action; path_index = path_index; } in\n        starting_successor\n\nlet starting_successors_complete_lemma\n  (lprog: Armada.Program.t)\n  (aw: armada_refines_atomic_witness_t)\n  : Lemma (requires   singleton_path_indices_complete aw.pc_index_breaking aw.pc_indices_array\n                        aw.singleton_path_indices\n                    /\\ array_len aw.pc_index_breaking = array_len aw.lpcs\n                    /\\ array_elements_unique_ubool aw.lpcs\n                    /\\ actions_correspond_to_statement_pc_indices aw.lpcs aw.lprog_actions_array aw.pc_indices_array\n                    /\\ aw.lprog_actions_array == list_to_array (all_actions lprog.program_statements))\n          (ensures  (let pc_breaking = armada_pc_index_breaking_to_pc_breaking aw.lpcs aw.pc_index_breaking in\n                     let starting_successors = singleton_path_indices_to_starting_successors aw.lprog_actions_array\n                                                 aw.singleton_path_indices in\n                     starting_successors_complete lprog pc_breaking starting_successors)) =\n  let pc_breaking = armada_pc_index_breaking_to_pc_breaking aw.lpcs aw.pc_index_breaking in\n  let starting_successors = singleton_path_indices_to_starting_successors aw.lprog_actions_array\n                              aw.singleton_path_indices in\n  introduce forall action. contains_ubool action (all_actions lprog.program_statements) ==>\n                      starting_successors_reflect_action pc_breaking starting_successors action\n  with introduce _ ==> _\n  with _. (\n    let action_index = contains_ubool_to_index action (all_actions lprog.program_statements) in\n    assert (array_index aw.lprog_actions_array action_index == action);\n    let pc_indices = array_index aw.pc_indices_array action_index in\n    assert (action_corresponds_to_statement_pc_indices aw.lpcs action pc_indices);\n    let singleton_path_index = array_index aw.singleton_path_indices action_index in\n    assert (singleton_path_indices_reflect_action aw.pc_index_breaking pc_indices singleton_path_index);\n    assert (optional_pc_matches_optional_pc_index aw.lpcs action.program_statement.start_pc\n              pc_indices.start_pc_index);\n    if is_breaking_optional_pc pc_breaking action.program_statement.start_pc then\n      match action.program_statement.start_pc with\n      | Some pc ->\n          assert (armada_pc_index_breaking_to_pc_breaking aw.lpcs aw.pc_index_breaking pc);\n          let pc_index = simpler_indefinite_description (fun (pc_index: nat) ->\n                           armada_pc_index_and_pc_breaking aw.lpcs aw.pc_index_breaking pc pc_index) in\n          assert (pc_breaking pc);\n          array_elements_unique_ubool_implication aw.lpcs;\n          assert (pc_index = Some?.v pc_indices.start_pc_index);\n          assert (armada_is_breaking_optional_pc aw.pc_index_breaking pc_indices.start_pc_index);\n          let singleton_path_index = array_index aw.singleton_path_indices action_index in\n          let successor = singleton_path_index_to_starting_successor aw.lprog_actions_array\n                            aw.singleton_path_indices 0 action_index in\n          assert (contains_ubool successor starting_successors);\n          assert (successors_include_action starting_successors action)\n      | None ->\n          assert (armada_is_breaking_optional_pc aw.pc_index_breaking pc_indices.start_pc_index);\n          let singleton_path_index = array_index aw.singleton_path_indices action_index in\n          let successor = singleton_path_index_to_starting_successor aw.lprog_actions_array\n                            aw.singleton_path_indices 0 action_index in\n          assert (contains_ubool successor starting_successors);\n          assert (successors_include_action starting_successors action)\n    else\n      ()\n  )\n\nlet path_successors_complete_lemma_helper\n  (lprog: Armada.Program.t)\n  (aw: armada_refines_atomic_witness_t)\n  (pc: pc_t)\n  (pc_index: nat)\n  (armada_successors: list armada_successor_info_t)\n  (action: Armada.Action.t)\n  : Lemma (requires   array_elements_unique_ubool aw.lpcs\n                    /\\ pc_matches_pc_index aw.lpcs pc pc_index\n                    /\\ pc_index < array_len aw.action_indices_starting_at_pc_index\n                    /\\ (let actions_starting_at_pc =\n                         armada_actions_starting_at_pc_to_actions_starting_at_pc aw.lprog_actions_array aw.lpcs\n                           aw.action_indices_starting_at_no_pc aw.action_indices_starting_at_pc_index in\n                       let action_indices = array_index aw.action_indices_starting_at_pc_index pc_index in\n                       let actions = actions_starting_at_pc (Some pc) in\n                         for_all_ghost (armada_successors_include_action_index armada_successors)\n                           action_indices\n                       /\\ contains_ubool action actions))\n          (ensures (let successors = map_ghost (armada_successor_info_to_successor_info aw.lprog_actions_array)\n                                       armada_successors in\n                    successors_include_action successors action)) =\n  let successors = map_ghost (armada_successor_info_to_successor_info aw.lprog_actions_array) armada_successors in\n  let actions_starting_at_pc =\n    armada_actions_starting_at_pc_to_actions_starting_at_pc aw.lprog_actions_array aw.lpcs\n      aw.action_indices_starting_at_no_pc aw.action_indices_starting_at_pc_index in\n  let action_indices = array_index aw.action_indices_starting_at_pc_index pc_index in\n  let actions = actions_starting_at_pc (Some pc) in\n  match find_in_array aw.lpcs pc with\n  | None -> false_elim ()\n  | Some idx ->\n      array_elements_unique_ubool_implication aw.lpcs;\n      assert (idx == pc_index);\n      assert (actions == map_ghost (select_action_from_array aw.lprog_actions_array) action_indices);\n      let action_index =\n        reverse_map_element_of_map_ghost (select_action_from_array aw.lprog_actions_array) action_indices action in\n      assert (action == select_action_from_array aw.lprog_actions_array action_index);\n      assert (contains_ubool action_index action_indices);\n      assert (armada_successors_include_action_index armada_successors action_index);\n      let armada_successor =\n        exists_ghost_to_witness (fun successor -> successor.action_index = action_index) armada_successors in\n      let successor = armada_successor_info_to_successor_info aw.lprog_actions_array armada_successor in\n      map_ghost_contains_ubool (armada_successor_info_to_successor_info aw.lprog_actions_array) armada_successors\n        armada_successor;\n      assert (contains_ubool successor successors);\n      assert (action_matches_successor action successor)\n\n#push-options \"--z3rlimit 10\"\n\nlet path_successors_complete_lemma\n  (lprog: Armada.Program.t)\n  (aw: armada_refines_atomic_witness_t)\n  : Lemma (requires   armada_path_successors_complete aw.action_indices_starting_at_pc_index aw.pc_indices_array\n                        aw.atomic_path_infos\n                    /\\ array_elements_unique_ubool aw.lpcs\n                    /\\ actions_correspond_to_statement_pc_indices aw.lpcs aw.lprog_actions_array aw.pc_indices_array)\n          (ensures  (let actions_starting_at_pc =\n                       armada_actions_starting_at_pc_to_actions_starting_at_pc aw.lprog_actions_array aw.lpcs\n                         aw.action_indices_starting_at_no_pc aw.action_indices_starting_at_pc_index in\n                     let atomic_path_infos =\n                       map_ghost (armada_atomic_path_info_to_atomic_path_info aw.lprog_actions_array)\n                         (array_to_list aw.atomic_path_infos) in\n                     path_successors_complete actions_starting_at_pc atomic_path_infos)) =\n  let actions_starting_at_pc =\n    armada_actions_starting_at_pc_to_actions_starting_at_pc aw.lprog_actions_array aw.lpcs\n      aw.action_indices_starting_at_no_pc aw.action_indices_starting_at_pc_index in\n  let atomic_path_infos =\n    map_ghost (armada_atomic_path_info_to_atomic_path_info aw.lprog_actions_array)\n     (array_to_list aw.atomic_path_infos) in\n  introduce forall atomic_path_info. contains_ubool atomic_path_info atomic_path_infos ==>\n                                path_successors_complete_specific actions_starting_at_pc atomic_path_info\n  with introduce contains_ubool atomic_path_info atomic_path_infos ==>\n                 path_successors_complete_specific actions_starting_at_pc atomic_path_info\n  with _. (\n    let path_index = contains_ubool_to_index atomic_path_info atomic_path_infos in\n    map_ghost_maps_index (armada_atomic_path_info_to_atomic_path_info aw.lprog_actions_array)\n      (array_to_list aw.atomic_path_infos) path_index;\n    let armada_atomic_path_info = array_index aw.atomic_path_infos path_index in\n    assert (armada_path_successors_complete_specific aw.action_indices_starting_at_pc_index aw.pc_indices_array\n              armada_atomic_path_info);\n    assert (atomic_path_info == armada_atomic_path_info_to_atomic_path_info aw.lprog_actions_array\n              armada_atomic_path_info);\n    if not atomic_path_info.breaking then (\n       let final_action_index = last armada_atomic_path_info.path in\n       let final_pc_indices = array_index aw.pc_indices_array final_action_index in\n       let end_pc_index = Some?.v final_pc_indices.end_pc_index in\n       let action_indices = array_index aw.action_indices_starting_at_pc_index end_pc_index in\n       let final_action = array_index aw.lprog_actions_array final_action_index in\n       assert (action_corresponds_to_statement_pc_indices aw.lpcs final_action final_pc_indices);\n       map_ghost_maps_last (select_action_from_array aw.lprog_actions_array) armada_atomic_path_info.path;\n       assert (final_action == last atomic_path_info.path);\n       let end_pc = Some?.v final_action.program_statement.end_pc in\n       let actions = actions_starting_at_pc (final_action.program_statement.end_pc) in\n       introduce forall action. contains_ubool action actions ==>\n                           successors_include_action atomic_path_info.successors action\n       with introduce _ ==> _\n       with _. (\n         let successors = Inr?.v armada_atomic_path_info.atomic_action_index_or_successors in\n         path_successors_complete_lemma_helper lprog aw end_pc end_pc_index successors action\n       )\n    )\n    else\n      ()\n  )\n\nlet created_threads_initially_breaking_lemma\n  (lprog: Armada.Program.t)\n  (aw: armada_refines_atomic_witness_t)\n  : Lemma (requires   armada_created_threads_initially_breaking aw.pc_index_breaking aw.pc_indices_array\n                    /\\ aw.lprog_actions_array == list_to_array (all_actions lprog.program_statements)\n                    /\\ array_len aw.pc_index_breaking = array_len aw.lpcs\n                    /\\ actions_correspond_to_statement_pc_indices aw.lpcs aw.lprog_actions_array aw.pc_indices_array)\n          (ensures  (let pc_breaking = armada_pc_index_breaking_to_pc_breaking aw.lpcs aw.pc_index_breaking in\n                     created_threads_initially_breaking lprog pc_breaking)) =\n  let pc_breaking = armada_pc_index_breaking_to_pc_breaking aw.lpcs aw.pc_index_breaking in\n  introduce forall ps. contains_ubool ps lprog.program_statements ==>\n                  created_threads_initially_breaking_specific pc_breaking ps\n  with introduce _ ==> _\n  with _. (\n    match ps.statement with\n    | CreateThreadStatement _ initial_pc _ _ _ _ _ ->\n        let action = { ok = true; program_statement = ps; } in\n        all_actions_has_all_actions action lprog.program_statements;\n        let action_index = contains_ubool_to_index action (all_actions lprog.program_statements) in\n        assert (action == array_index aw.lprog_actions_array action_index);\n        let pc_indices = array_index aw.pc_indices_array action_index in\n        assert (armada_created_threads_initially_breaking_specific aw.pc_index_breaking pc_indices);\n        assert (action_corresponds_to_statement_pc_indices aw.lpcs action pc_indices);\n        assert (pc_breaking initial_pc)\n    | _ -> ()\n  )\n\n#pop-options\n\nlet pc_breaking_correct_lemma\n  (lprog: Armada.Program.t)\n  (aw: armada_refines_atomic_witness_t)\n  : Lemma (requires   armada_pc_breaking_correct aw.lprog_actions_array aw.pc_indices_array aw.pc_index_breaking\n                    /\\ aw.lprog_actions_array == list_to_array (all_actions lprog.program_statements)\n                    /\\ array_len aw.pc_index_breaking = array_len aw.lpcs\n                    /\\ array_elements_unique_ubool aw.lpcs\n                    /\\ actions_correspond_to_statement_pc_indices aw.lpcs aw.lprog_actions_array aw.pc_indices_array)\n          (ensures  (let pc_breaking = armada_pc_index_breaking_to_pc_breaking aw.lpcs aw.pc_index_breaking in\n                     pc_breaking_correct lprog pc_breaking)) =\n  let pc_breaking = armada_pc_index_breaking_to_pc_breaking aw.lpcs aw.pc_index_breaking in\n  introduce forall ps. contains_ubool ps lprog.program_statements ==> pc_breaking_correct_specific pc_breaking ps\n  with introduce _ ==> _\n  with _. (\n    let action = { ok = true; program_statement = ps; } in\n    all_actions_has_all_actions action lprog.program_statements;\n    let action_index = contains_ubool_to_index action (all_actions lprog.program_statements) in\n    assert (action == array_index aw.lprog_actions_array action_index);\n    let pc_indices = array_index aw.pc_indices_array action_index in\n    assert (armada_pc_breaking_correct_specific aw.pc_index_breaking action pc_indices);\n    assert (action_corresponds_to_statement_pc_indices aw.lpcs action pc_indices);\n    optional_pc_matches_optional_pc_index_implies_is_breaking_optional_pc_matches aw ps.start_pc\n      pc_indices.start_pc_index;\n    optional_pc_matches_optional_pc_index_implies_is_breaking_optional_pc_matches aw ps.end_pc\n      pc_indices.end_pc_index\n  )\n\nlet main_start_pc_breaking_lemma\n  (lprog: Armada.Program.t)\n  (aw: armada_refines_atomic_witness_t)\n  : Lemma (requires armada_main_start_pc_breaking lprog.main_start_pc aw.lpcs aw.lprog_main_start_pc_index\n                      aw.pc_index_breaking)\n          (ensures  (let pc_breaking = armada_pc_index_breaking_to_pc_breaking aw.lpcs aw.pc_index_breaking in\n                     pc_breaking lprog.main_start_pc)) =\n  ()\n\nlet armada_refines_atomic_witness_valid_implies_refinement\n  (lprog: Armada.Program.t)\n  (hprog: program_t (make_atomic_semantics armada_semantics))\n  (aw: armada_refines_atomic_witness_t)\n  (* see .fsti file for spec *) =\n  let aa: armada_refines_atomic_relation_t = {\n    lprog = lprog;\n    hprog = hprog;\n    pc_breaking = armada_pc_index_breaking_to_pc_breaking aw.lpcs aw.pc_index_breaking;\n    actions_starting_at_pc = armada_actions_starting_at_pc_to_actions_starting_at_pc\n      aw.lprog_actions_array aw.lpcs aw.action_indices_starting_at_no_pc aw.action_indices_starting_at_pc_index;\n    starting_successors = singleton_path_indices_to_starting_successors aw.lprog_actions_array\n      aw.singleton_path_indices;\n    atomic_path_infos = map_ghost (armada_atomic_path_info_to_atomic_path_info aw.lprog_actions_array)\n      (array_to_list aw.atomic_path_infos);\n    actions_starting_at_pc_correct_proof = (fun _ -> actions_starting_at_pc_correct_lemma lprog aw);\n    starting_successors_match_path_infos_proof = (fun _ -> starting_successors_match_path_infos_lemma aw);\n    path_successors_match_path_infos_proof = (fun _ -> path_successors_match_path_infos_lemma aw);\n    path_breaking_correct_proof = (fun _ -> path_breaking_correct_lemma aw);\n    path_atomic_indices_correct_proof = (fun _ -> path_atomic_indices_correct_lemma lprog hprog aw);\n    path_actions_in_lprog_proof = (fun _ -> path_actions_in_lprog_lemma lprog aw);\n    starting_successors_complete_proof = (fun _ -> starting_successors_complete_lemma lprog aw);\n    path_successors_complete_proof = (fun _ -> path_successors_complete_lemma lprog aw);\n    created_threads_initially_breaking_proof = (fun _ -> created_threads_initially_breaking_lemma lprog aw);\n    pc_breaking_correct_proof = (fun _ -> pc_breaking_correct_lemma lprog aw);\n    main_start_pc_breaking_proof = (fun _ -> main_start_pc_breaking_lemma lprog aw);\n    inits_identical_proof = (fun _ -> ());\n  } in\n  armada_refines_atomic_relation_implies_refinement aa\n"
  },
  {
    "path": "experimental/lib/Strategies.RegularToAtomic.Armada.fsti",
    "content": "module Strategies.RegularToAtomic.Armada\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Program\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Type\nopen FStar.List.Tot\nopen Spec.Behavior\nopen Spec.List\nopen Spec.Logic\nopen Spec.Map\nopen Spec.Ubool\nopen Strategies.Atomic\nopen Strategies.PCIndices\nopen Strategies.RegularToAtomic\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\nopen Util.ImmutableArray\nopen Util.List\nopen Util.Nth\nopen Util.Range\n\ntype armada_successor_info_t = {\n  action_index: nat;\n  path_index: nat;\n}\n\ntype armada_atomic_path_info_t = {\n  path: list nat;\n  atomic_action_index_or_successors: either nat (list armada_successor_info_t);\n}\n\nlet armada_is_breaking_optional_pc\n  (pc_index_breaking: array_t bool)\n  (optional_pc_index: option nat)\n  : GTot bool =\n  match optional_pc_index with\n  | Some pc_index -> if pc_index < array_len pc_index_breaking then array_index pc_index_breaking pc_index else true\n  | None -> true\n\nlet armada_pc_breaking_correct_specific\n  (pc_index_breaking: array_t bool)\n  (action: Armada.Action.t)\n  (pc_indices: statement_pc_indices_t)\n  : GTot bool =\n  let ps = action.program_statement in\n     armada_is_breaking_optional_pc pc_index_breaking pc_indices.start_pc_index = ps.starts_atomic_block\n  && armada_is_breaking_optional_pc pc_index_breaking pc_indices.end_pc_index = ps.ends_atomic_block\n  && (implies (None? ps.end_pc) (armada_is_breaking_optional_pc pc_index_breaking pc_indices.start_pc_index))\n\nlet armada_pc_breaking_correct\n  (actions_array: array_t Armada.Action.t)\n  (pc_indices_array: array_t statement_pc_indices_t)\n  (pc_index_breaking: array_t bool)\n  : GTot bool =\n  arrays_correspond (armada_pc_breaking_correct_specific pc_index_breaking) actions_array pc_indices_array\n\nlet armada_created_threads_initially_breaking_specific\n  (pc_index_breaking: array_t bool)\n  (pc_indices: statement_pc_indices_t)\n  : GTot bool =\n  armada_is_breaking_optional_pc pc_index_breaking pc_indices.create_thread_initial_pc_index\n\nlet armada_created_threads_initially_breaking\n  (pc_index_breaking: array_t bool)\n  (pc_indices_array: array_t statement_pc_indices_t)\n  : GTot bool =\n  for_all_array (armada_created_threads_initially_breaking_specific pc_index_breaking) pc_indices_array\n\nlet armada_actions_starting_at_pc_correct_specific\n  (action_indices_starting_at_no_pc: list nat)\n  (action_indices_starting_at_pc_index: array_t (list nat))\n  (action_index: nat)\n  (pc_indices: statement_pc_indices_t)\n  : GTot bool =\n  match pc_indices.start_pc_index with\n  | None -> list_contains action_index action_indices_starting_at_no_pc\n  | Some pc_index ->\n         pc_index < array_len action_indices_starting_at_pc_index\n      && list_contains action_index (array_index action_indices_starting_at_pc_index pc_index)\n\nlet armada_actions_starting_at_pc_correct\n  (action_indices_starting_at_no_pc: list nat)\n  (action_indices_starting_at_pc_index: array_t (list nat))\n  (pc_indices_array: array_t statement_pc_indices_t)\n  : GTot bool =\n  for_all_array_enumerated\n    (armada_actions_starting_at_pc_correct_specific action_indices_starting_at_no_pc\n      action_indices_starting_at_pc_index)\n    pc_indices_array\n\nlet armada_singleton_path_matches_path_infos_specific\n  (atomic_path_infos: array_t armada_atomic_path_info_t)\n  (action_index: nat)\n  (optional_path_index: option nat)\n  : GTot bool =\n  match optional_path_index with\n  | Some singleton_path_index ->\n         singleton_path_index < array_len atomic_path_infos\n      && (array_index atomic_path_infos singleton_path_index).path = [action_index]\n  | None -> true\n\nlet armada_singleton_path_indices_match_path_infos\n  (atomic_path_infos: array_t armada_atomic_path_info_t)\n  (singleton_path_indices: array_t (option nat))\n  : GTot bool =\n  for_all_array_enumerated\n    (armada_singleton_path_matches_path_infos_specific atomic_path_infos)\n    singleton_path_indices\n\nlet armada_path_successor_matches_path_info\n  (atomic_path_infos: array_t armada_atomic_path_info_t)\n  (atomic_path_info: armada_atomic_path_info_t)\n  (successor: armada_successor_info_t)\n  : GTot bool =\n     successor.path_index < array_len atomic_path_infos\n  && (array_index atomic_path_infos successor.path_index).path\n     = (append atomic_path_info.path [successor.action_index])\n\nlet armada_path_successors_match_path_infos_specific\n  (atomic_path_infos: array_t armada_atomic_path_info_t)\n  (atomic_path_info: armada_atomic_path_info_t)\n  : GTot bool =\n  match atomic_path_info.atomic_action_index_or_successors with\n  | Inl atomic_action_index -> true\n  | Inr successors ->\n    for_all_ghost (armada_path_successor_matches_path_info atomic_path_infos atomic_path_info) successors\n\nlet armada_path_successors_match_path_infos\n  (atomic_path_infos: array_t armada_atomic_path_info_t)\n  : GTot bool =\n  for_all_array (armada_path_successors_match_path_infos_specific atomic_path_infos) atomic_path_infos\n\nlet armada_is_breaking_action\n  (pc_index_breaking: array_t bool)\n  (action: Armada.Action.t)\n  (pc_indices: statement_pc_indices_t)\n  : GTot bool =\n    not action.ok\n  || armada_is_breaking_optional_pc pc_index_breaking pc_indices.end_pc_index\n  || (match action.program_statement.statement with\n     | AssertFalseStatement _\n     | TerminateProcessStatement _\n     | TerminateThreadStatement _\n     | MethodCallStatement _ _ _ _ _ true -> true\n     | _ -> false)\n\nlet armada_path_breaking_correct_specific\n  (pc_index_breaking: array_t bool)\n  (actions_array: array_t Armada.Action.t)\n  (pc_indices_array: array_t statement_pc_indices_t)\n  (atomic_path_info: armada_atomic_path_info_t)\n  : GTot bool =\n     Cons? atomic_path_info.path\n  && (let action_index = last atomic_path_info.path in\n         action_index < array_len actions_array\n      && action_index < array_len pc_indices_array\n      && (Inl? atomic_path_info.atomic_action_index_or_successors) =\n           armada_is_breaking_action pc_index_breaking (array_index actions_array action_index)\n             (array_index pc_indices_array action_index))\n\nlet armada_path_breaking_correct\n  (pc_index_breaking: array_t bool)\n  (actions_array: array_t Armada.Action.t)\n  (pc_indices_array: array_t statement_pc_indices_t)\n  (atomic_path_infos: array_t armada_atomic_path_info_t)\n  : GTot bool =\n  for_all_array (armada_path_breaking_correct_specific pc_index_breaking actions_array pc_indices_array)\n    atomic_path_infos\n\nlet armada_path_entry_correct\n  (actions_array: array_t Armada.Action.t)\n  (action_index: nat)\n  (action: Armada.Action.t)\n  : GTot ubool =\n  array_nth actions_array action_index == Some action\n\nlet armada_path_atomic_index_correct\n  (lprog_actions_array: array_t Armada.Action.t)\n  (hprog_actions_array: array_t (list Armada.Action.t))\n  (atomic_path_info: armada_atomic_path_info_t)\n  : GTot ubool =\n  match atomic_path_info.atomic_action_index_or_successors with\n  | Inl atomic_action_index ->\n         atomic_action_index < array_len hprog_actions_array\n      /\\ lists_correspond_ubool (armada_path_entry_correct lprog_actions_array) atomic_path_info.path\n           (array_index hprog_actions_array atomic_action_index)\n  | Inr successors -> true\n\nlet armada_path_atomic_indices_correct\n  (lprog_actions_array: array_t Armada.Action.t)\n  (hprog_actions_array: array_t (list Armada.Action.t))\n  (atomic_path_infos: array_t armada_atomic_path_info_t)\n  : GTot ubool =\n  for_all_array_ubool (armada_path_atomic_index_correct lprog_actions_array hprog_actions_array) atomic_path_infos\n\nlet armada_path_actions_in_lprog_specific\n  (num_actions: nat)\n  (atomic_path_info: armada_atomic_path_info_t)\n  : GTot bool =\n  for_all_ghost (fun (action_index: nat) -> action_index < num_actions) atomic_path_info.path\n\nlet armada_path_actions_in_lprog\n  (num_actions: nat)\n  (atomic_path_infos: array_t armada_atomic_path_info_t)\n  : GTot bool =\n  for_all_array (armada_path_actions_in_lprog_specific num_actions) atomic_path_infos\n\nlet singleton_path_indices_reflect_action\n  (pc_index_breaking: array_t bool)\n  (pc_indices: statement_pc_indices_t)\n  (singleton_path_index: option nat)\n  : GTot bool =\n  implies\n    (armada_is_breaking_optional_pc pc_index_breaking pc_indices.start_pc_index)\n    (Some? singleton_path_index)\n\nlet singleton_path_indices_complete\n  (pc_index_breaking: array_t bool)\n  (pc_indices_array: array_t statement_pc_indices_t)\n  (singleton_path_indices: array_t (option nat))\n  : GTot bool =\n  arrays_correspond (singleton_path_indices_reflect_action pc_index_breaking) pc_indices_array singleton_path_indices\n\nlet armada_successors_include_action_index\n  (successors: list armada_successor_info_t)\n  (action_index: nat)\n  : GTot bool =\n  exists_ghost (fun successor -> successor.action_index = action_index) successors\n\nlet armada_path_successors_complete_specific\n  (action_indices_starting_at_pc_index: array_t (list nat))\n  (pc_indices_array: array_t statement_pc_indices_t)\n  (atomic_path_info: armada_atomic_path_info_t)\n  : GTot bool =\n  match atomic_path_info.atomic_action_index_or_successors with\n  | Inl atomic_action_index -> true\n  | Inr successors ->\n         length atomic_path_info.path > 0\n      && (let final_action_index = last atomic_path_info.path in\n             final_action_index < array_len pc_indices_array\n          && (match (array_index pc_indices_array final_action_index).end_pc_index with\n              | None -> false\n              | Some end_pc_index ->\n                     end_pc_index < array_len action_indices_starting_at_pc_index\n                  && (let action_indices = array_index action_indices_starting_at_pc_index end_pc_index in\n                      for_all_ghost (armada_successors_include_action_index successors) action_indices)))\n\nlet armada_path_successors_complete\n  (action_indices_starting_at_pc_index: array_t (list nat))\n  (pc_indices_array: array_t statement_pc_indices_t)\n  (atomic_path_infos: array_t armada_atomic_path_info_t)\n  : GTot bool =\n  for_all_array (armada_path_successors_complete_specific action_indices_starting_at_pc_index pc_indices_array)\n    atomic_path_infos\n\nlet armada_main_start_pc_breaking\n  (main_start_pc: pc_t)\n  (lpcs: array_t pc_t)\n  (lprog_main_start_pc_index: nat)\n  (pc_index_breaking: array_t bool)\n  : GTot bool =\n     array_nth lpcs lprog_main_start_pc_index = Some main_start_pc\n  && lprog_main_start_pc_index < array_len pc_index_breaking\n  && array_index pc_index_breaking lprog_main_start_pc_index = true\n\nnoeq type armada_refines_atomic_witness_t = {\n  pc_index_breaking: array_t bool;\n  pc_indices_array: array_t statement_pc_indices_t;\n  action_indices_starting_at_no_pc: list nat;\n  action_indices_starting_at_pc_index: array_t (list nat);\n  atomic_path_infos: array_t armada_atomic_path_info_t;\n  singleton_path_indices: array_t (option nat);\n  lpcs: array_t pc_t;\n  lprog_main_start_pc_index: nat;\n  lprog_actions_array: array_t Armada.Action.t;\n  hprog_actions_array: array_t (list Armada.Action.t);\n}\n\nlet armada_refines_atomic_witness_valid\n  (lprog: Armada.Program.t)\n  (hprog: program_t (make_atomic_semantics armada_semantics))\n  (aw: armada_refines_atomic_witness_t)\n  : GTot ubool =\n     armada_actions_starting_at_pc_correct aw.action_indices_starting_at_no_pc aw.action_indices_starting_at_pc_index\n       aw.pc_indices_array\n  /\\ armada_singleton_path_indices_match_path_infos aw.atomic_path_infos aw.singleton_path_indices\n  /\\ armada_path_successors_match_path_infos aw.atomic_path_infos\n  /\\ array_len aw.pc_index_breaking = array_len aw.lpcs\n  /\\ armada_path_breaking_correct aw.pc_index_breaking aw.lprog_actions_array aw.pc_indices_array aw.atomic_path_infos\n  /\\ armada_path_atomic_indices_correct aw.lprog_actions_array aw.hprog_actions_array aw.atomic_path_infos\n  /\\ armada_path_actions_in_lprog (array_len aw.lprog_actions_array) aw.atomic_path_infos\n  /\\ singleton_path_indices_complete aw.pc_index_breaking aw.pc_indices_array aw.singleton_path_indices\n  /\\ armada_path_successors_complete aw.action_indices_starting_at_pc_index aw.pc_indices_array aw.atomic_path_infos\n  /\\ armada_created_threads_initially_breaking aw.pc_index_breaking aw.pc_indices_array\n  /\\ armada_pc_breaking_correct aw.lprog_actions_array aw.pc_indices_array aw.pc_index_breaking\n  /\\ armada_main_start_pc_breaking lprog.main_start_pc aw.lpcs aw.lprog_main_start_pc_index aw.pc_index_breaking\n  /\\ actions_correspond_to_statement_pc_indices aw.lpcs aw.lprog_actions_array aw.pc_indices_array\n  /\\ array_elements_unique_ubool aw.lpcs\n\nval armada_refines_atomic_witness_valid_implies_refinement\n  (lprog: Armada.Program.t)\n  (hprog: program_t (make_atomic_semantics armada_semantics))\n  (aw: armada_refines_atomic_witness_t)\n  : Lemma (requires   armada_refines_atomic_witness_valid lprog hprog aw\n                    /\\ hprog.init_f == init_program lprog\n                    /\\ aw.lprog_actions_array == list_to_array (all_actions lprog.program_statements)\n                    /\\ aw.hprog_actions_array == list_to_array hprog.actions)\n          (ensures  (spec_refines_spec\n                      (program_to_spec lprog)\n                      (semantics_to_spec (make_atomic_semantics armada_semantics) hprog)\n                      eq2))\n"
  },
  {
    "path": "experimental/lib/Strategies.RegularToAtomic.fst",
    "content": "module Strategies.RegularToAtomic\n\nopen Armada.Action\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Step\nopen Armada.Transition\nopen FStar.List.Tot\nopen Spec.Behavior\nopen Spec.List\nopen Spec.Logic\nopen Spec.Ubool\nopen Strategies.Atomic\nopen Strategies.Semantics\nopen Util.Behavior\nopen Util.List\nopen Util.Logic\nopen Util.Nth\n\nlet all_threads_breaking\n  (ra: regular_refines_atomic_relation_t)\n  (s: ra.sem.state_t)\n  : GTot ubool =\n  forall actor. ra.is_breaking_state s actor\n\nlet all_threads_breaking_except\n  (ra: regular_refines_atomic_relation_t)\n  (s: ra.sem.state_t)\n  (actor: ra.sem.actor_t)\n  : GTot ubool =\n  forall other_actor. actor <> other_actor ==> ra.is_breaking_state s other_actor\n\n#push-options \"--z3rlimit 10\"\n\nlet rec convert_hsteps_and_path_and_lsteps_to_hsteps\n  (ra: regular_refines_atomic_relation_t)\n  (actor: ra.sem.actor_t)\n  (s0: ra.sem.state_t)\n  (hsteps: list (make_atomic_semantics ra.sem).step_t)\n  (s1: ra.sem.state_t)\n  (lpath_steps: list ra.sem.step_t)\n  (atomic_path_info: atomic_path_info_t ra.sem)\n  (s2: ra.sem.state_t)\n  (lsteps: list ra.sem.step_t)\n  (s3: ra.sem.state_t\n    {  (if Nil? hsteps then\n          s1 == s0\n        else\n            Some s1 == steps_computation_generic (make_atomic_semantics ra.sem) actor true false hsteps s0\n          /\\ for_all_ubool (program_contains_action_of_step_generic (make_atomic_semantics ra.sem) ra.hprog) hsteps)\n     /\\ ra.is_breaking_state s1 actor\n     /\\ contains_ubool atomic_path_info ra.atomic_path_infos\n     /\\ not atomic_path_info.breaking\n     /\\ map_ghost ra.sem.step_to_action_f lpath_steps == atomic_path_info.path\n     /\\ Some s2 == steps_computation_generic ra.sem actor (Nil? hsteps) false lpath_steps s1\n     /\\ for_all_ubool (program_contains_action_of_step_generic ra.sem ra.lprog) lsteps\n     /\\ Some s3 == steps_computation_generic ra.sem actor false true lsteps s2})\n  : GTot (hsteps': list (make_atomic_semantics ra.sem).step_t\n    {  Some s3 == steps_computation_generic (make_atomic_semantics ra.sem) actor true true hsteps' s0\n     /\\ for_all_ubool (program_contains_action_of_step_generic (make_atomic_semantics ra.sem) ra.hprog) hsteps'})\n    (decreases lsteps) =\n  match lsteps with\n  | first_step :: remaining_steps ->\n      let first_action = ra.sem.step_to_action_f first_step in\n      let starts_atomic_block = Nil? hsteps in\n      let ends_atomic_block = Nil? remaining_steps in\n      assert (Some? (steps_computation_generic ra.sem actor starts_atomic_block false lpath_steps s1));\n      ra.path_successors_complete_proof atomic_path_info actor starts_atomic_block ends_atomic_block lpath_steps\n        first_step s1;\n      assert (action_among_successors ra.sem first_action atomic_path_info.successors);\n      let successor: (successor_info_t ra.sem) =\n         simpler_indefinite_description\n           (fun (successor: successor_info_t ra.sem) ->\n              contains_ubool successor atomic_path_info.successors /\\ successor.action == first_action) in\n      ra.path_successors_match_path_infos_proof atomic_path_info successor;\n      let next_atomic_path_info = index ra.atomic_path_infos successor.path_index in\n      index_implies_contains_ubool ra.atomic_path_infos successor.path_index next_atomic_path_info;\n      let hstep = append lpath_steps [first_step] in\n      append_one_extends_steps_computation_generic ra.sem actor starts_atomic_block ends_atomic_block\n        lpath_steps first_step s1;\n      let s_mid = Some?.v (steps_computation_generic ra.sem actor starts_atomic_block ends_atomic_block hstep s1) in\n      assert (Some s_mid == step_computation_generic ra.sem actor false ends_atomic_block first_step s2);\n      if ends_atomic_block then\n        ra.actions_break_if_last_in_transition_proof actor false first_step s2\n      else\n        ();\n      append_commutes_with_map ra.sem.step_to_action_f lpath_steps [first_step];\n      ra.path_breaking_correct_proof next_atomic_path_info actor starts_atomic_block ends_atomic_block hstep s1;\n      if next_atomic_path_info.breaking then (\n        let hsteps' = append hsteps [hstep] in\n        assert (next_atomic_path_info.breaking = ra.is_breaking_state s_mid actor);\n        ra.path_atomic_indices_correct_proof next_atomic_path_info;\n        index_implies_contains_ubool ra.hprog.actions next_atomic_path_info.atomic_action_index\n          next_atomic_path_info.path;\n        if Cons? hsteps then\n          append_one_extends_steps_computation_generic (make_atomic_semantics ra.sem) actor true\n            ends_atomic_block hsteps hstep s0\n        else\n          ();\n        append_preserves_for_all_ubool\n          (program_contains_action_of_step_generic (make_atomic_semantics ra.sem) ra.hprog) hsteps [hstep];\n        if Nil? remaining_steps then\n          hsteps'\n        else\n          convert_hsteps_and_lsteps_to_hsteps ra actor s0 hsteps' s_mid remaining_steps s3\n      )\n      else\n        convert_hsteps_and_path_and_lsteps_to_hsteps ra actor s0 hsteps s1 hstep next_atomic_path_info s_mid remaining_steps s3\n\nand convert_hsteps_and_lsteps_to_hsteps\n  (ra: regular_refines_atomic_relation_t)\n  (actor: ra.sem.actor_t)\n  (s0: ra.sem.state_t)\n  (hsteps: list (make_atomic_semantics ra.sem).step_t)\n  (s1: ra.sem.state_t)\n  (lsteps: list ra.sem.step_t)\n  (s2: ra.sem.state_t\n    {  (if Nil? hsteps then\n            s1 == s0\n        else\n            Some s1 == steps_computation_generic (make_atomic_semantics ra.sem) actor true false hsteps s0\n          /\\ for_all_ubool (program_contains_action_of_step_generic (make_atomic_semantics ra.sem) ra.hprog) hsteps)\n     /\\ ra.is_breaking_state s1 actor\n     /\\ for_all_ubool (program_contains_action_of_step_generic ra.sem ra.lprog) lsteps\n     /\\ Some s2 == steps_computation_generic ra.sem actor (Nil? hsteps) true lsteps s1})\n  : GTot (hsteps': list (make_atomic_semantics ra.sem).step_t\n    {  Some s2 == steps_computation_generic (make_atomic_semantics ra.sem) actor true true hsteps' s0\n     /\\ for_all_ubool (program_contains_action_of_step_generic (make_atomic_semantics ra.sem) ra.hprog) hsteps'})\n    (decreases lsteps) =\n  match lsteps with\n  | first_step :: remaining_steps ->\n      let first_action = ra.sem.step_to_action_f first_step in\n      let starts_atomic_block = Nil? hsteps in\n      let ends_atomic_block = Nil? remaining_steps in\n      ra.starting_successors_complete_proof actor starts_atomic_block ends_atomic_block first_step s1;\n      assert (action_among_successors ra.sem first_action ra.starting_successors);\n      let successor: (successor_info_t ra.sem) =\n         simpler_indefinite_description\n           (fun (successor: successor_info_t ra.sem) ->\n              contains_ubool successor ra.starting_successors /\\ successor.action == first_action) in\n      ra.starting_successors_match_path_infos_proof successor;\n      let atomic_path_info = index ra.atomic_path_infos successor.path_index in\n      index_implies_contains_ubool ra.atomic_path_infos successor.path_index atomic_path_info;\n      let s_mid = (Some?.v (steps_computation_generic ra.sem actor starts_atomic_block ends_atomic_block\n                              [first_step] s1)) in\n      if ends_atomic_block then\n        ra.actions_break_if_last_in_transition_proof actor starts_atomic_block first_step s1\n      else\n        ();\n      ra.path_breaking_correct_proof atomic_path_info actor starts_atomic_block ends_atomic_block [first_step] s1;\n      if atomic_path_info.breaking then (\n        let hstep: list ra.sem.step_t = [first_step] in\n        let hsteps' = append hsteps [hstep] in\n        if Cons? hsteps then\n          append_one_extends_steps_computation_generic (make_atomic_semantics ra.sem) actor true\n            ends_atomic_block hsteps hstep s0\n        else\n          ();\n        assert (atomic_path_info.breaking = ra.is_breaking_state s_mid actor);\n        ra.path_atomic_indices_correct_proof atomic_path_info;\n        index_implies_contains_ubool ra.hprog.actions atomic_path_info.atomic_action_index atomic_path_info.path;\n        append_preserves_for_all_ubool (program_contains_action_of_step_generic (make_atomic_semantics ra.sem) ra.hprog)\n          hsteps [hstep];\n        if Nil? remaining_steps then\n          hsteps'\n        else\n          convert_hsteps_and_lsteps_to_hsteps ra actor s0 hsteps' s_mid remaining_steps s2\n      )\n      else\n        convert_hsteps_and_path_and_lsteps_to_hsteps ra actor s0 hsteps s1 [first_step] atomic_path_info s_mid\n          remaining_steps s2\n\n#pop-options\n\nlet convert_lsteps_to_hsteps\n  (ra: regular_refines_atomic_relation_t)\n  (actor: ra.sem.actor_t)\n  (s: ra.sem.state_t{ra.is_breaking_state s actor})\n  (lsteps: list ra.sem.step_t{for_all_ubool (program_contains_action_of_step_generic ra.sem ra.lprog) lsteps})\n  (s': ra.sem.state_t{Some s' == steps_computation_generic ra.sem actor true true lsteps s})\n  : GTot (hsteps: list (make_atomic_semantics ra.sem).step_t\n      {  Some s' == steps_computation_generic (make_atomic_semantics ra.sem) actor true true hsteps s\n       /\\ for_all_ubool (program_contains_action_of_step_generic (make_atomic_semantics ra.sem) ra.hprog) hsteps}) =\n  convert_hsteps_and_lsteps_to_hsteps ra actor s [] s lsteps s'\n\nlet rec last_in_transition_steps_preserve_all_threads_breaking\n  (ra: regular_refines_atomic_relation_t)\n  (actor: ra.sem.actor_t)\n  (starts_atomic_block: bool)\n  (s: ra.sem.state_t)\n  (steps: list ra.sem.step_t)\n  (s': ra.sem.state_t)\n  : Lemma\n    (requires   all_threads_breaking_except ra s actor\n              /\\ for_all_ubool (program_contains_action_of_step_generic ra.sem ra.lprog) steps\n              /\\ Some s' == steps_computation_generic ra.sem actor starts_atomic_block true steps s\n              /\\ (starts_atomic_block ==> ra.is_breaking_state s actor))\n    (ensures  all_threads_breaking ra s')\n    (decreases steps) =\n  match steps with\n  | [last_step] ->\n     ra.actions_break_if_last_in_transition_proof actor starts_atomic_block last_step s;\n     ra.actions_dont_unbreak_other_actors_proof actor starts_atomic_block true last_step s\n  | first_step :: remaining_steps ->\n      ra.actions_dont_unbreak_other_actors_proof actor starts_atomic_block false first_step s;\n      let s_mid = (Some?.v (step_computation_generic ra.sem actor starts_atomic_block false first_step s)) in\n      last_in_transition_steps_preserve_all_threads_breaking ra actor false s_mid remaining_steps s'\n\nlet regular_refines_atomic_relation_implies_spec_next\n  (ra: regular_refines_atomic_relation_t)\n  (s s': ra.sem.state_t)\n  : Lemma (requires all_threads_breaking ra s /\\ (semantics_to_spec ra.sem ra.lprog).next s s')\n          (ensures    all_threads_breaking ra s'\n                    /\\ (semantics_to_spec (make_atomic_semantics ra.sem) ra.hprog).next s s') =\n  let sem = ra.sem in\n  let atomic_sem = make_atomic_semantics sem in\n  eliminate exists ltr. next_program_generic sem ra.lprog ltr s s'\n  returns all_threads_breaking ra s' /\\ (semantics_to_spec atomic_sem ra.hprog).next s s'\n  with ltr_satisfies_next_program.\n    let hsteps = convert_lsteps_to_hsteps ra ltr.actor s ltr.steps s' in\n    let htr = { actor = (ltr.actor <: atomic_sem.actor_t); steps = hsteps } in\n    last_in_transition_steps_preserve_all_threads_breaking ra ltr.actor true s ltr.steps s'\n\nlet rec regular_refines_atomic_relation_implies_behavior_satisfies_hspec_next\n  (ra: regular_refines_atomic_relation_t)\n  (b: behavior_t ra.sem.state_t)\n  : Lemma (requires   Cons? b\n                    /\\ all_threads_breaking ra (Cons?.hd b) \n                    /\\ behavior_satisfies_next b (semantics_to_spec ra.sem ra.lprog).next)\n          (ensures  behavior_satisfies_next b (semantics_to_spec (make_atomic_semantics ra.sem) ra.hprog).next) =\n  match b with\n  | [] -> ()\n  | [state] -> ()\n  | state1 :: state2 :: tl ->\n      regular_refines_atomic_relation_implies_spec_next ra state1 state2;\n      regular_refines_atomic_relation_implies_behavior_satisfies_hspec_next ra (state2 :: tl)\n\nlet regular_refines_atomic_relation_implies_behavior_satisfies_hspec\n  (ra: regular_refines_atomic_relation_t)\n  (b: behavior_t ra.sem.state_t)\n  : Lemma (requires   behavior_satisfies_spec b (semantics_to_spec ra.sem ra.lprog)\n                    /\\ all_threads_breaking ra (Cons?.hd b))\n          (ensures  behavior_satisfies_spec b (semantics_to_spec (make_atomic_semantics ra.sem) ra.hprog)) =\n  ra.init_implies_init_proof (Cons?.hd b);\n  regular_refines_atomic_relation_implies_behavior_satisfies_hspec_next ra b\n\nlet regular_refines_atomic_relation_implies_refinement (ra: regular_refines_atomic_relation_t)\n  (* see .fsti file for spec *) =\n  let lspec = semantics_to_spec ra.sem ra.lprog in\n  let hspec = semantics_to_spec (make_atomic_semantics ra.sem) ra.hprog in\n  let lem (b: behavior_t ra.sem.state_t) : Lemma\n    (requires behavior_satisfies_spec b lspec)\n    (ensures  behavior_satisfies_spec b hspec /\\ behavior_refines_behavior b b eq2)\n    [SMTPat (behavior_satisfies_spec b lspec)]\n    = (ra.init_breaks_all_actors_proof (Cons?.hd b);\n       regular_refines_atomic_relation_implies_behavior_satisfies_hspec ra b;\n       refinement_relation_reflexive_implies_behavior_refines_itself b eq2) in\n  ()\n"
  },
  {
    "path": "experimental/lib/Strategies.RegularToAtomic.fsti",
    "content": "module Strategies.RegularToAtomic\n\nopen Armada.Action\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Step\nopen Armada.Transition\nopen FStar.List.Tot\nopen Spec.Behavior\nopen Spec.List\nopen Spec.Logic\nopen Spec.Ubool\nopen Strategies.Atomic\nopen Strategies.Semantics\nopen Util.List\nopen Util.Nth\n\nnoeq type successor_info_t (sem: semantics_t) = {\n  action: sem.action_t;\n  path_index: nat;\n}\n\nnoeq type atomic_path_info_t (sem: semantics_t) = {\n  path: list sem.action_t;\n  breaking: bool;\n  // For a path that terminates in a break state, the index of the atomic action corresponding to it:\n  atomic_action_index: nat;\n  // For a path that doesn't terminate in a break state, the successor info for all the atomic paths that succeed it.\n  successors: list (successor_info_t sem);\n}\n\nlet action_among_successors\n  (sem: semantics_t)\n  (action: sem.action_t)\n  (successors: list (successor_info_t sem))\n  : GTot ubool =\n  exists successor. contains_ubool successor successors /\\ successor.action == action\n\nnoeq type regular_refines_atomic_relation_t = {\n  sem: semantics_t;\n  lprog: program_t sem;\n  hprog: program_t (make_atomic_semantics sem);\n  is_breaking_state: sem.state_t -> sem.actor_t -> GTot bool;\n  starting_successors: list (successor_info_t sem);\n  atomic_path_infos: list (atomic_path_info_t sem);\n\n  starting_successors_match_path_infos_proof:\n    (successor: successor_info_t sem{contains_ubool successor starting_successors}) ->\n    squash (  successor.path_index < length atomic_path_infos\n            /\\ (index atomic_path_infos successor.path_index).path == [successor.action]);\n\n  path_successors_match_path_infos_proof:\n    (atomic_path_info: atomic_path_info_t sem) ->\n    (successor: successor_info_t sem{\n        contains_ubool atomic_path_info atomic_path_infos\n      /\\ contains_ubool successor atomic_path_info.successors}) ->\n    squash (   successor.path_index < length atomic_path_infos\n            /\\ (index atomic_path_infos successor.path_index).path == append atomic_path_info.path\n                 [successor.action]);\n\n  path_breaking_correct_proof:\n    (atomic_path_info: atomic_path_info_t sem) ->\n    (actor: sem.actor_t) ->\n    (starts_atomic_block: bool) ->\n    (ends_atomic_block: bool) ->\n    (steps: list sem.step_t) ->\n    (s: sem.state_t{\n        contains_ubool atomic_path_info atomic_path_infos\n      /\\ (map_ghost sem.step_to_action_f steps) == atomic_path_info.path\n      /\\ Some? (steps_computation_generic sem actor starts_atomic_block ends_atomic_block steps s)\n      /\\ (starts_atomic_block ==> is_breaking_state s actor)}) ->\n    squash (let s' = Some?.v (steps_computation_generic sem actor starts_atomic_block ends_atomic_block\n                                steps s) in\n            (atomic_path_info.breaking = is_breaking_state s' actor));\n\n  path_atomic_indices_correct_proof:\n    (atomic_path_info: atomic_path_info_t sem{\n         contains_ubool atomic_path_info atomic_path_infos\n       /\\ atomic_path_info.breaking}) ->\n    squash (  atomic_path_info.atomic_action_index < length hprog.actions\n            /\\ index hprog.actions atomic_path_info.atomic_action_index == atomic_path_info.path);\n\n  starting_successors_complete_proof:\n    (actor: sem.actor_t) ->\n    (starts_atomic_block: bool) ->\n    (ends_atomic_block: bool) ->\n    (step: sem.step_t) ->\n    (s: sem.state_t{\n        contains_ubool (sem.step_to_action_f step) lprog.actions\n      /\\ is_breaking_state s actor\n      /\\ Some? (step_computation_generic sem actor starts_atomic_block ends_atomic_block step s)}) ->\n    squash (action_among_successors sem (sem.step_to_action_f step) starting_successors);\n\n  path_successors_complete_proof:\n    (atomic_path_info: atomic_path_info_t sem) ->\n    (actor: sem.actor_t) ->\n    (starts_atomic_block: bool) ->\n    (ends_atomic_block: bool) ->\n    (steps: list sem.step_t) ->\n    (step: sem.step_t) ->\n    (s: sem.state_t{\n        contains_ubool atomic_path_info atomic_path_infos\n      /\\ map_ghost sem.step_to_action_f steps == atomic_path_info.path\n      /\\ contains_ubool (sem.step_to_action_f step) lprog.actions\n      /\\ not atomic_path_info.breaking\n      /\\ (match steps_computation_generic sem actor starts_atomic_block false steps s with\n         | None -> False\n         | Some s' -> Some? (step_computation_generic sem actor false ends_atomic_block step s'))}) ->\n    squash (action_among_successors sem (sem.step_to_action_f step) atomic_path_info.successors);\n\n  actions_dont_unbreak_other_actors_proof:\n    (actor: sem.actor_t) ->\n    (starts_atomic_block: bool) ->\n    (ends_atomic_block: bool) ->\n    (step: sem.step_t) ->\n    (s: sem.state_t{\n      let action = sem.step_to_action_f step in\n         contains_ubool action lprog.actions\n      /\\ Some? (step_computation_generic sem actor starts_atomic_block ends_atomic_block step s)}) ->\n    squash (let s' = Some?.v (step_computation_generic sem actor starts_atomic_block\n                                ends_atomic_block step s) in\n            forall other_actor. is_breaking_state s other_actor /\\ actor <> other_actor ==>\n                             is_breaking_state s' other_actor);\n\n  actions_break_if_last_in_transition_proof:\n    (actor: sem.actor_t) ->\n    (starts_atomic_block: bool) ->\n    (step: sem.step_t) ->\n    (s: sem.state_t{\n        contains_ubool (sem.step_to_action_f step) lprog.actions\n      /\\ Some? (step_computation_generic sem actor starts_atomic_block true step s)\n      /\\ (starts_atomic_block ==> is_breaking_state s actor)}) ->\n    squash (let s' = Some?.v (step_computation_generic sem actor starts_atomic_block true step s) in\n            is_breaking_state s' actor);\n\n  init_breaks_all_actors_proof: (s: sem.state_t{lprog.init_f s}) -> squash (forall actor. is_breaking_state s actor);\n\n  init_implies_init_proof: (s: sem.state_t{lprog.init_f s}) -> squash (hprog.init_f s);\n}\n\nval regular_refines_atomic_relation_implies_refinement (ra: regular_refines_atomic_relation_t)\n  : Lemma (ensures (spec_refines_spec\n                    (semantics_to_spec ra.sem ra.lprog)\n                    (semantics_to_spec (make_atomic_semantics ra.sem) ra.hprog)\n                    eq2))\n"
  },
  {
    "path": "experimental/lib/Strategies.Semantics.Armada.fst",
    "content": "module Strategies.Semantics.Armada\n\nopen Armada.Action\nopen Armada.Step\nopen Armada.Program\nopen Armada.Threads\nopen Armada.Transition\nopen Armada.Type\nopen Spec.Behavior\nopen Spec.List\nopen Strategies.Semantics\nopen Util.Behavior\nopen Util.List\n\nlet rec all_actions_has_all_actions\n  (action: Armada.Action.t)\n  (program_statements: list program_statement_t)\n  : Lemma (contains_ubool action.program_statement program_statements <==>\n             (contains_ubool action (all_actions program_statements))) =\n  match program_statements with\n  | [] -> ()\n  | hd :: tl -> if eqb hd action.program_statement then () else all_actions_has_all_actions action tl\n\nlet armada_state_satisfies_init_equivalent (program: Armada.Program.t) (s: Armada.State.t)\n  : Lemma ((program_to_spec program).init s <==>\n           (semantics_to_spec armada_semantics (armada_program_to_generic program)).init s) =\n  ()\n\nlet rec armada_steps_computation_equivalent\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (steps: list Armada.Step.t)\n  (s: Armada.State.t)\n  : Lemma (ensures  steps_computation actor starts_atomic_block ends_atomic_block steps s ==\n                    steps_computation_generic armada_semantics actor starts_atomic_block ends_atomic_block\n                      steps s)\n          (decreases steps) =\n  match steps with\n  | [] -> ()\n  | [last_step] -> ()\n  | first_step :: remaining_steps ->\n      (match step_computation actor starts_atomic_block false first_step s with\n       | None -> ()\n       | Some s' -> armada_steps_computation_equivalent actor false ends_atomic_block remaining_steps s')\n\nlet armada_transition_to_generic (transition: Armada.Transition.t) : transition_t armada_semantics =\n  { actor = transition.actor; steps = transition.steps; }\n\nlet generic_transition_to_armada (transition: transition_t armada_semantics) : Armada.Transition.t =\n  { actor = transition.actor; steps = transition.steps; }\n\nlet armada_next_transition_equivalent_forward\n  (program: Armada.Program.t)\n  (transition: Armada.Transition.t)\n  (s s': Armada.State.t)\n  : Lemma (requires Armada.Transition.next_transition transition s s')\n          (ensures  next_transition_generic armada_semantics (armada_transition_to_generic transition) s s') =\n  let sem = armada_semantics in\n  armada_steps_computation_equivalent transition.actor true true transition.steps s\n\nlet armada_next_transition_equivalent_backward\n  (transition: transition_t armada_semantics)\n  (s s': Armada.State.t)\n  : Lemma (requires next_transition_generic armada_semantics transition s s')\n          (ensures  Armada.Transition.next_transition (generic_transition_to_armada transition) s s') =\n  armada_steps_computation_equivalent transition.actor true true transition.steps s\n\nlet armada_next_program_equivalent_forward\n  (program: Armada.Program.t)\n  (transition: Armada.Transition.t)\n  (s s': Armada.State.t)\n  : Lemma (requires Armada.Program.next_program program transition s s')\n          (ensures  next_program_generic armada_semantics (armada_program_to_generic program)\n                     (armada_transition_to_generic transition) s s') =\n  let lem (step: Armada.Step.t)\n    : Lemma (requires program_contains_statement_of_step program step)\n            (ensures  program_contains_action_of_step_generic armada_semantics\n                        (armada_program_to_generic program) step) =\n    all_actions_has_all_actions step.action program.program_statements in\n  for_all_ubool_implication lem transition.steps;\n  armada_next_transition_equivalent_forward program transition s s'\n\nlet armada_next_program_equivalent_backward\n  (program: Armada.Program.t)\n  (transition: transition_t armada_semantics)\n  (s s': Armada.State.t)\n  : Lemma (requires next_program_generic armada_semantics (armada_program_to_generic program) transition s s')\n          (ensures  Armada.Program.next_program program (generic_transition_to_armada transition) s s') =\n  let lem (step: Armada.Step.t)\n    : Lemma (requires program_contains_action_of_step_generic armada_semantics\n               (armada_program_to_generic program) step)\n            (ensures  program_contains_statement_of_step program step) =\n    all_actions_has_all_actions step.action program.program_statements in\n  for_all_ubool_implication lem transition.steps;\n  armada_next_transition_equivalent_backward transition s s'\n\nlet armada_next_equivalent (program: Armada.Program.t) (s s': Armada.State.t)\n  : Lemma ((program_to_spec program).next s s' <==>\n           (semantics_to_spec armada_semantics (armada_program_to_generic program)).next s s') =\n  introduce (program_to_spec program).next s s' ==>\n            (semantics_to_spec armada_semantics (armada_program_to_generic program)).next s s'\n  with knowing_program_next. (\n    eliminate exists transition. Armada.Program.next_program program transition s s'\n    returns   _\n    with knowing_transition_satisfies_next_program.\n      armada_next_program_equivalent_forward program transition s s'\n  );\n  introduce (semantics_to_spec armada_semantics (armada_program_to_generic program)).next s s' ==>\n            (program_to_spec program).next s s'\n  with knowing_semantics_next. (\n    eliminate exists transition. next_program_generic armada_semantics\n                              (armada_program_to_generic program) transition s s'\n    returns   _\n    with knowing_transition_satisfies_next_program.\n      armada_next_program_equivalent_backward program transition s s'\n  )\n\nlet rec armada_behavior_satisfies_next_equivalent (program: Armada.Program.t) (b: behavior_t Armada.State.t)\n  : Lemma (behavior_satisfies_next b (program_to_spec program).next <==>\n           behavior_satisfies_next b (semantics_to_spec armada_semantics\n                                       (armada_program_to_generic program)).next) =\n  match b with\n  | [] -> ()\n  | [s] -> ()\n  | s1 :: s2 :: tl ->\n      armada_next_equivalent program s1 s2; armada_behavior_satisfies_next_equivalent program (s2 :: tl)\n\nlet armada_behavior_satisfies_generic_spec (program: Armada.Program.t) (b: behavior_t Armada.State.t)\n  : Lemma (requires behavior_satisfies_spec b (program_to_spec program))\n          (ensures  behavior_satisfies_spec b (semantics_to_spec armada_semantics\n                                                (armada_program_to_generic program))) =\n  armada_behavior_satisfies_next_equivalent program b;\n  armada_state_satisfies_init_equivalent program (Cons?.hd b)\n\nlet armada_generic_behavior_satisfies_spec (program: Armada.Program.t) (b: behavior_t Armada.State.t)\n  : Lemma (requires behavior_satisfies_spec b (semantics_to_spec armada_semantics\n                                                (armada_program_to_generic program)))\n          (ensures  behavior_satisfies_spec b (program_to_spec program)) =\n  armada_behavior_satisfies_next_equivalent program b;\n  armada_state_satisfies_init_equivalent program (Cons?.hd b)\n\nlet armada_spec_refines_generic (program: Armada.Program.t)\n  (* see .fsti file for spec *) =\n  let lspec = program_to_spec program in\n  let hspec = semantics_to_spec armada_semantics (armada_program_to_generic program) in\n  introduce forall (lb: behavior_t Armada.State.t).\n              behavior_satisfies_spec lb lspec ==> \n              (exists hb. behavior_satisfies_spec hb hspec /\\ behavior_refines_behavior lb hb eq2)\n  with\n    introduce _ ==> _\n    with knowing_lb_satisfies_spec. (\n      armada_behavior_satisfies_generic_spec program lb;\n      refinement_relation_reflexive_implies_behavior_refines_itself lb eq2;\n      introduce exists hb. behavior_satisfies_spec hb hspec /\\ behavior_refines_behavior lb hb eq2\n      with lb and ())\n\nlet armada_generic_refines_spec (program: Armada.Program.t)\n  (* see .fsti file for spec *) =\n  let lspec = semantics_to_spec armada_semantics (armada_program_to_generic program) in\n  let hspec = program_to_spec program in\n  introduce forall (lb: behavior_t Armada.State.t).\n              behavior_satisfies_spec lb lspec ==>\n              (exists hb. behavior_satisfies_spec hb hspec /\\ behavior_refines_behavior lb hb eq2)\n  with\n    introduce _ ==> _\n    with knowing_lb_satisfies_spec. (\n      armada_generic_behavior_satisfies_spec program lb;\n      refinement_relation_reflexive_implies_behavior_refines_itself lb eq2;\n      introduce exists hb. behavior_satisfies_spec hb hspec /\\ behavior_refines_behavior lb hb eq2\n      with lb and ())\n\nlet behavior_satisfies_armada_spec_iff_it_satisfies_generic_spec\n  (program: Armada.Program.t)\n  (b: behavior_t Armada.State.t)\n  (* see .fsti file for spec *) =\n  armada_behavior_satisfies_next_equivalent program b;\n  match b with\n  | [] -> ()\n  | s :: _ -> armada_state_satisfies_init_equivalent program s\n"
  },
  {
    "path": "experimental/lib/Strategies.Semantics.Armada.fsti",
    "content": "module Strategies.Semantics.Armada\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Step\nopen Armada.Program\nopen Armada.Threads\nopen Armada.Transition\nopen Armada.Type\nopen Spec.Behavior\nopen Spec.List\nopen Spec.Ubool\nopen Strategies.Semantics\nopen Util.Behavior\n\nlet armada_step_to_action (step: Armada.Step.t) : Armada.Action.t =\n  step.action\n\nlet armada_semantics : semantics_t = {\n  actor_t = tid_t;\n  state_t = Armada.State.t;\n  action_t = Armada.Action.t;\n  step_t = Armada.Step.t;\n  step_to_action_f = armada_step_to_action;\n  step_computation_f = Armada.Transition.step_computation;\n}\n\nlet rec all_actions (program_statements: list program_statement_t) : list Armada.Action.t =\n  match program_statements with\n  | [] -> []\n  | first_program_statement :: remaining_program_statements ->\n      { ok = true; program_statement = first_program_statement } ::\n      { ok = false; program_statement = first_program_statement } ::\n      all_actions remaining_program_statements\n\nval all_actions_has_all_actions\n  (action: Armada.Action.t)\n  (program_statements: list program_statement_t)\n  : Lemma (contains_ubool action.program_statement program_statements <==>\n             (contains_ubool action (all_actions program_statements)))\n\nlet armada_program_to_generic (program: Armada.Program.t) : program_t armada_semantics = {\n  init_f = Armada.Program.init_program program;\n  actions = all_actions program.program_statements;\n}\n\nval armada_steps_computation_equivalent\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (steps: list Armada.Step.t)\n  (s: Armada.State.t)\n  : Lemma (ensures  steps_computation actor starts_atomic_block ends_atomic_block steps s ==\n                    steps_computation_generic armada_semantics actor starts_atomic_block ends_atomic_block\n                      steps s)\n\nval armada_spec_refines_generic (program: Armada.Program.t)\n  : Lemma (spec_refines_spec\n            (program_to_spec program)\n            (semantics_to_spec armada_semantics (armada_program_to_generic program))\n            eq2)\n\nval armada_generic_refines_spec (program: Armada.Program.t)\n  : Lemma (spec_refines_spec\n            (semantics_to_spec armada_semantics (armada_program_to_generic program))\n            (program_to_spec program)\n            eq2)\n\nval behavior_satisfies_armada_spec_iff_it_satisfies_generic_spec\n  (program: Armada.Program.t)\n  (b: behavior_t Armada.State.t)\n  : Lemma (behavior_satisfies_spec b (program_to_spec program) <==>\n           behavior_satisfies_spec b (semantics_to_spec armada_semantics (armada_program_to_generic program)))\n"
  },
  {
    "path": "experimental/lib/Strategies.Semantics.fst",
    "content": "module Strategies.Semantics\n\nopen Armada.Program\nopen Armada.State\nopen Armada.Threads\nopen FStar.List.Tot\nopen Spec.Behavior\nopen Spec.List\nopen Spec.Logic\nopen Spec.Ubool\nopen Util.Behavior\nopen Util.List\n\nnoeq type semantics_t = {\n  // Types\n\n  actor_t: eqtype;\n  state_t: Type;\n  action_t: Type;\n  step_t: Type;\n\n  // Projections\n\n  step_to_action_f: step_t -> GTot action_t;\n\n  // Functions\n\n  step_computation_f: (actor: actor_t) -> (starts_atomic_block: bool) -> (ends_atomic_block: bool) ->\n                        (step: step_t) -> (s: state_t) -> GTot (option state_t);\n}\n\nnoeq type transition_t (sem: semantics_t) = {\n  actor: sem.actor_t;\n  steps: list sem.step_t;\n}\n\nlet make_transition (sem: semantics_t) (actor: sem.actor_t) (steps: list sem.step_t) : transition_t sem =\n  { actor = actor; steps = steps }\n\nnoeq type program_t (sem: semantics_t) = {\n  init_f: sem.state_t -> GTot ubool;\n  actions: list sem.action_t;\n}\n\nlet step_computation_generic\n  (sem: semantics_t)\n  (actor: sem.actor_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (step: sem.step_t)\n  (s: sem.state_t)\n  : GTot (option sem.state_t) =\n  sem.step_computation_f actor starts_atomic_block ends_atomic_block step s\n\nlet rec steps_computation_generic\n  (sem: semantics_t)\n  (actor: sem.actor_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (steps: list sem.step_t)\n  (s: sem.state_t)\n  : GTot (option sem.state_t)\n    (decreases steps) =\n  match steps with\n  | [] -> None\n  | [last_step] -> step_computation_generic sem actor starts_atomic_block ends_atomic_block last_step s\n  | first_step :: remaining_steps ->\n      (match step_computation_generic sem actor starts_atomic_block false first_step s with\n       | None -> None\n       | Some s' -> steps_computation_generic sem actor false ends_atomic_block remaining_steps s')\n\nlet next_transition_generic\n  (sem: semantics_t)\n  (transition: transition_t sem)\n  (s s': sem.state_t)\n  : GTot ubool =\n  Some s' == steps_computation_generic sem transition.actor true true transition.steps s\n\nlet init_program_generic (sem: semantics_t) (program: program_t sem) (s: sem.state_t) : GTot ubool =\n  program.init_f s\n\nlet program_contains_action_of_step_generic\n  (sem: semantics_t)\n  (program: program_t sem)\n  (step: sem.step_t)\n  : GTot ubool =\n  contains_ubool (sem.step_to_action_f step) program.actions\n\nlet next_program_generic\n  (sem: semantics_t)\n  (program: program_t sem)\n  (transition: transition_t sem)\n  (s s': sem.state_t)\n  : GTot ubool =\n    for_all_ubool (program_contains_action_of_step_generic sem program) transition.steps\n  /\\ next_transition_generic sem transition s s'\n\nlet semantics_to_spec (sem: semantics_t) (program: program_t sem) : GTot (spec_t sem.state_t) =\n  { init = init_program_generic sem program;\n    next = fun s s' -> exists transition. next_program_generic sem program transition s s' }\n\n// Useful lemmas\n\nlet rec append_one_extends_steps_computation_generic\n  (sem: semantics_t)\n  (actor: sem.actor_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (first_steps: list sem.step_t)\n  (last_step: sem.step_t)\n  (s: sem.state_t)\n  : Lemma (requires Some? (steps_computation_generic sem actor starts_atomic_block false first_steps s))\n          (ensures  (let s' = Some?.v (steps_computation_generic sem actor starts_atomic_block false first_steps s) in\n                     steps_computation_generic sem actor starts_atomic_block ends_atomic_block\n                       (append first_steps [last_step]) s ==\n                         step_computation_generic sem actor false ends_atomic_block last_step s'))\n          (decreases first_steps) =\n  match first_steps with\n  | [] -> ()\n  | [last_step] -> ()\n  | first_step :: remaining_steps ->\n      let s' = Some?.v (step_computation_generic sem actor starts_atomic_block false first_step s) in\n      append_one_extends_steps_computation_generic sem actor false ends_atomic_block remaining_steps last_step s'\n"
  },
  {
    "path": "experimental/lib/Strategies.VarHiding.Defs.fst",
    "content": "module Strategies.VarHiding.Defs\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Computation\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Threads\nopen Armada.Transition\nopen Armada.Type\nopen Spec.Behavior\nopen Spec.List\nopen Spec.Logic\nopen Spec.Ubool\nopen Strategies.ArmadaStatement.Propagate\nopen Strategies.ArmadaStatement.ThreadState\nopen Strategies.Atomic\nopen Strategies.GlobalVars\nopen Strategies.GlobalVars.Permanent\nopen Strategies.GlobalVars.Statement\nopen Strategies.GlobalVars.Types\nopen Strategies.GlobalVars.VarHiding\nopen Strategies.GlobalVars.VarIntro\nopen Strategies.Invariant\nopen Strategies.Invariant.Armada.AtomicSubstep\nopen Strategies.Nonyielding\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\nopen Util.List\nopen Util.Nth\nopen Util.Relation\n\ntype program_statement_succeeds_proof_t\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (inv: invariant_t Armada.State.t)\n  (ps: program_statement_t) =\n  (actor: tid_t) ->\n  (nd: nondeterminism_t) ->\n  (s: Armada.State.t{\n      inv s\n    /\\ all_gvars_have_types s.mem vs tds\n    /\\ NotStopped? s.stop_reason\n    /\\ ThreadStatusRunning? (s.threads actor).status\n    /\\ ps.start_pc = Some (s.threads actor).pc}) ->\n  squash (not (ComputationUndefined? (statement_computation actor nd (Some?.v ps.start_pc) ps.end_pc ps.statement s)))\n\nnoeq type ltoh_correspondence_t\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (inv: invariant_t Armada.State.t) =\n  | CorrespondenceHidden: ltoh_correspondence_t vs tds inv\n  | CorrespondencePropagate: (hidx: nat) -> ltoh_correspondence_t vs tds inv\n  | CorrespondenceNormal: (hidx: nat) -> (which_actions_hidden: list bool) -> ltoh_correspondence_t vs tds inv\n  | CorrespondenceImpossibleConstantAssignmentFailure: ltoh_correspondence_t vs tds inv\n  | CorrespondenceImpossibleStatementFailure:\n      (ps: program_statement_t) ->\n      (proof: program_statement_succeeds_proof_t vs tds inv ps) ->\n      ltoh_correspondence_t vs tds inv\n\nlet variable_among_gvars (mem: Armada.Memory.t) (v: var_id_t) : GTot bool =\n  let root_id = RootIdGlobal v in\n  let root = mem root_id in\n  RootGlobal? root\n\nlet all_variables_among_gvars (mem: Armada.Memory.t) (vs: list var_id_t) : GTot bool =\n  for_all_ghost (variable_among_gvars mem) vs\n\nlet rec initializers_match_except_global_variables\n  (vs: list var_id_t)\n  (which_are_hidings: list bool)\n  (linits: list initializer_t)\n  (hinits: list initializer_t)\n  : GTot ubool =\n  match which_are_hidings, linits, hinits with\n  | [], [], [] -> True\n  | true :: remaining_which_are_hidings, first_linit :: remaining_linits, _ ->\n        list_contains first_linit.var_id vs\n      /\\ initializers_match_except_global_variables vs remaining_which_are_hidings remaining_linits hinits\n  | false :: remaining_which_are_hidings, first_linit :: remaining_linits, first_hinit :: remaining_hinits ->\n        not (list_contains first_hinit.var_id vs)\n      /\\ first_linit == first_hinit\n      /\\ initializers_match_except_global_variables vs remaining_which_are_hidings remaining_linits remaining_hinits\n  | _, _, _ -> False\n\nlet initializer_value_to_td (init: initializer_value_t) : GTot object_td_t =\n  match init with\n  | InitializerArbitrary td -> td\n  | InitializerSpecific value -> object_value_to_td value\n\nlet initializer_matches_variable_and_td\n  (v: var_id_t)\n  (td: object_td_t)\n  (init: initializer_t)\n  : GTot ubool =\n    init.var_id = v\n  /\\ initializer_value_to_td init.iv == td\n\nlet every_variable_appears_among_initializers\n  (inits: list initializer_t)\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  : GTot ubool =\n  lists_correspond_ubool\n    (fun v td -> exists_ubool (initializer_matches_variable_and_td v td) inits)\n    vs\n    tds\n\nlet program_inits_match_except_global_variables\n  (vs: list var_id_t)\n  (lpc_to_hpc: pc_t -> GTot pc_t)\n  (which_initializers_are_hidings: list bool)\n  (lprog: Armada.Program.t)\n  (hprog: Armada.Program.t)\n  : GTot ubool =\n     lprog.main_method_id = hprog.main_method_id\n  /\\ hprog.main_start_pc = lpc_to_hpc lprog.main_start_pc\n  /\\ initializers_match_except_global_variables vs which_initializers_are_hidings\n       lprog.global_initializers hprog.global_initializers\n  /\\ lprog.main_stack_initializers == hprog.main_stack_initializers\n\nlet lpc_hpc_pc_relation\n  (lpc_to_hpc: pc_t -> GTot pc_t)\n  (lpc: pc_t)\n  (hpc: pc_t)\n  : GTot bool =\n  lpc_to_hpc lpc = hpc\n\nlet lpc_hpc_pc_return_relation\n  (lpc_to_hpc: pc_t -> GTot pc_t)\n  (return_lpcs: list pc_t)\n  (lpc: pc_t)\n  (hpc: pc_t)\n  : GTot bool =\n  list_contains lpc return_lpcs && lpc_to_hpc lpc = hpc\n\nlet rec lactions_all_hidden\n  (vs: list var_id_t)\n  (lpc_to_hpc: pc_t -> GTot pc_t)\n  (lstart_state: thread_state_t)\n  (lend_state: thread_state_t)\n  (lactions: list Armada.Action.t)\n  : GTot ubool\n  (decreases lactions) =\n  match lactions with\n  | [] -> lend_state = lstart_state\n  | first_laction :: remaining_lactions ->\n         action_to_starting_thread_state first_laction = lstart_state\n      /\\ (match lstart_state, action_to_ending_thread_state first_laction with\n         | ThreadStateAtPC lpc1, ThreadStateAtPC lpc2 -> lpc_to_hpc lpc1 = lpc_to_hpc lpc2\n         | _, _ -> False)\n      /\\ statement_updates_gvars vs first_laction.program_statement.statement\n      /\\ lactions_all_hidden vs lpc_to_hpc (action_to_ending_thread_state first_laction) \n           lend_state remaining_lactions\n\nlet laction_corresponds_to_haction\n  (vs: list var_id_t)\n  (lpc_to_hpc: pc_t -> GTot pc_t)\n  (return_lpcs: list pc_t)\n  (laction: Armada.Action.t)\n  (haction: Armada.Action.t)\n  : GTot ubool =\n  let lps, hps = laction.program_statement, haction.program_statement in\n  let relation = lpc_hpc_pc_relation lpc_to_hpc in\n  let return_relation = lpc_hpc_pc_return_relation lpc_to_hpc return_lpcs in\n    statement_effect_independent_of_global_variables vs lps.statement\n  /\\ program_statements_match_per_pc_relation relation return_relation lps hps\n\nlet rec lactions_correspond_to_hactions\n  (vs: list var_id_t)\n  (lpc_to_hpc: pc_t -> GTot pc_t)\n  (return_lpcs: list pc_t)\n  (lstart_state: thread_state_t)\n  (hstart_state: thread_state_t)\n  (lend_state: thread_state_t)\n  (hend_state: thread_state_t)\n  (which_actions_hidden: list bool)\n  (lactions: list Armada.Action.t)\n  (hactions: list Armada.Action.t)\n  : GTot ubool\n  (decreases lactions) =\n  let relation = lpc_hpc_pc_relation lpc_to_hpc in\n  match which_actions_hidden, lactions, hactions with\n  | [], [], [] ->\n        lend_state = lstart_state\n      /\\ hend_state = hstart_state\n  | false :: remaining_which_actions_hidden, first_laction :: remaining_lactions, first_haction :: remaining_hactions ->\n         laction_corresponds_to_haction vs lpc_to_hpc return_lpcs first_laction first_haction\n      /\\ action_to_starting_thread_state first_laction = lstart_state\n      /\\ action_to_starting_thread_state first_haction = hstart_state\n      /\\ ThreadStateAtPC? lstart_state\n      /\\ ThreadStateAtPC? hstart_state\n      /\\ thread_states_match_per_pc_relation relation lstart_state hstart_state\n      /\\ thread_states_match_per_pc_relation relation (action_to_ending_thread_state first_laction)\n           (action_to_ending_thread_state first_haction)\n      /\\ lactions_correspond_to_hactions vs lpc_to_hpc return_lpcs\n           (action_to_ending_thread_state first_laction) (action_to_ending_thread_state first_haction)\n           lend_state hend_state remaining_which_actions_hidden remaining_lactions remaining_hactions\n  | true :: remaining_which_actions_hidden, first_laction :: remaining_lactions, _ ->\n         action_to_starting_thread_state first_laction = lstart_state\n      /\\ ThreadStateAtPC? lstart_state\n      /\\ thread_states_match_per_pc_relation relation lstart_state hstart_state\n      /\\ thread_states_match_per_pc_relation relation (action_to_ending_thread_state first_laction) hstart_state\n      /\\ statement_updates_gvars vs first_laction.program_statement.statement\n      /\\ lactions_correspond_to_hactions vs lpc_to_hpc return_lpcs (action_to_ending_thread_state first_laction) \n           hstart_state lend_state hend_state remaining_which_actions_hidden remaining_lactions hactions\n  | _, _, _ -> False\n\nlet rec lactions_fail_final_statement_updating_gvars_using_constant\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (actions: list Armada.Action.t{Cons? actions})\n  : GTot ubool =\n  match actions with\n  | [action] ->\n        not action.ok\n      /\\ statement_updates_gvars_using_constant vs tds action.program_statement.statement\n  | first_action :: remaining_actions ->\n      lactions_fail_final_statement_updating_gvars_using_constant vs tds remaining_actions\n\nlet rec lactions_fail_specific_final_statement\n  (ps: program_statement_t)\n  (actions: list Armada.Action.t{Cons? actions})\n  : GTot ubool =\n  let start_state = action_to_starting_thread_state (Cons?.hd actions) in\n  match actions with\n  | [action] ->\n        not action.ok\n      /\\ Some? ps.start_pc\n      /\\ start_state = ThreadStateAtPC (Some?.v ps.start_pc)\n      /\\ action.program_statement == ps\n  | first_action :: remaining_actions ->\n        action_to_ending_thread_state first_action = action_to_starting_thread_state (Cons?.hd remaining_actions)\n      /\\ lactions_fail_specific_final_statement ps remaining_actions\n\nlet lactions_correspond_to_hactions_per_correspondence\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (inv: invariant_t Armada.State.t)\n  (lpc_to_hpc: pc_t -> GTot pc_t)\n  (return_lpcs: list pc_t)\n  (hatomic_actions: list (list Armada.Action.t))\n  (lactions: list Armada.Action.t)\n  (correspondence: (ltoh_correspondence_t vs tds inv))\n  : GTot ubool =\n  match correspondence with\n  | CorrespondenceHidden ->\n        Cons? lactions\n      /\\ actions_start_atomic_block lactions = actions_end_atomic_block lactions\n      /\\ (let lstart_state = action_to_starting_thread_state (Cons?.hd lactions) in\n         let lend_state = actions_to_ending_thread_state lactions in\n         lactions_all_hidden vs lpc_to_hpc lstart_state lend_state lactions)\n  | CorrespondencePropagate hidx ->\n        Cons? lactions\n      /\\ (Cons?.hd lactions).program_statement == propagate_program_statement\n      /\\ list_nth hatomic_actions hidx == Some lactions\n  | CorrespondenceNormal hidx which_actions_hidden ->\n      (match list_nth hatomic_actions hidx with\n       | Some hactions ->\n             Cons? lactions\n           /\\ Cons? hactions\n           /\\ do_actions_start_and_end_atomic_block lactions = do_actions_start_and_end_atomic_block hactions\n           /\\ (let lstart_state = action_to_starting_thread_state (Cons?.hd lactions) in\n              let lend_state = actions_to_ending_thread_state lactions in\n              let hstart_state = action_to_starting_thread_state (Cons?.hd hactions) in\n              let hend_state = actions_to_ending_thread_state hactions in\n              lactions_correspond_to_hactions vs lpc_to_hpc return_lpcs lstart_state hstart_state lend_state\n                hend_state which_actions_hidden lactions hactions)\n       | None -> False)\n  | CorrespondenceImpossibleConstantAssignmentFailure ->\n        Cons? lactions\n      /\\ ~(PropagateWriteMessageStatement? (Cons?.hd lactions).program_statement.statement)\n      /\\ lactions_fail_final_statement_updating_gvars_using_constant vs tds lactions\n  | CorrespondenceImpossibleStatementFailure ps proof ->\n        Cons? lactions\n      /\\ ~(PropagateWriteMessageStatement? (Cons?.hd lactions).program_statement.statement)\n      /\\ lactions_fail_specific_final_statement ps lactions\n\nlet return_pcs_unique_inner2\n  (lpc_to_hpc: pc_t -> GTot pc_t)\n  (return_lpcs: list pc_t)\n  (lpc1: pc_t)\n  (lpc2: pc_t)\n  : GTot bool =\n  implies (lpc_to_hpc lpc1 = lpc_to_hpc lpc2) (lpc1 = lpc2)\n\nlet return_pcs_unique_inner1\n  (lpc_to_hpc: pc_t -> GTot pc_t)\n  (return_lpcs: list pc_t)\n  (lpc1: pc_t)\n  : GTot bool =\n  for_all_ghost (return_pcs_unique_inner2 lpc_to_hpc return_lpcs lpc1) return_lpcs\n\nlet return_pcs_unique\n  (lpc_to_hpc: pc_t -> GTot pc_t)\n  (return_lpcs: list pc_t)\n  : GTot bool =\n  for_all_ghost (return_pcs_unique_inner1 lpc_to_hpc return_lpcs) return_lpcs\n\nnoeq type var_hiding_relation_t = {\n  lprog: Armada.Program.t;\n  hprog: Armada.Program.t;\n  latomic_prog: program_t (make_atomic_semantics armada_semantics);\n  hatomic_prog: program_t (make_atomic_semantics armada_semantics);\n  vs: list var_id_t;\n  tds: list object_td_t;\n  inv: invariant_t Armada.State.t;\n  which_initializers_are_hidings: list bool;\n  lpc_to_hpc: pc_t -> GTot pc_t;\n  return_lpcs: list pc_t;\n  is_nonyielding_lpc: pc_t -> GTot bool;\n  is_nonyielding_hpc: pc_t -> GTot bool;\n  corresponding_hactions_info: list (ltoh_correspondence_t vs tds inv);\n\n  inv_is_substep_invariant_proof: unit ->\n    squash (is_armada_substep_invariant latomic_prog inv);\n\n  atomic_inits_match_regular_inits_proof: unit ->\n    squash (latomic_prog.init_f == init_program lprog /\\ hatomic_prog.init_f == init_program hprog);\n\n  program_inits_match_except_global_variables_proof: unit ->\n    squash (program_inits_match_except_global_variables vs lpc_to_hpc which_initializers_are_hidings lprog hprog);\n\n  initial_pcs_correspond_proof: unit -> squash (lpc_to_hpc lprog.main_start_pc = hprog.main_start_pc);\n\n  global_variables_unaddressed_in_initializers_proof: unit ->\n    squash (  global_variables_unaddressed_in_initializers vs lprog.global_initializers\n            /\\ global_variables_unaddressed_in_initializers vs hprog.global_initializers\n            /\\ global_variables_unaddressed_in_initializers vs lprog.main_stack_initializers\n            /\\ global_variables_unaddressed_in_initializers vs hprog.main_stack_initializers);\n\n  all_introduced_global_variables_initialized_proof: unit ->\n    squash (every_variable_appears_among_initializers lprog.global_initializers vs tds);\n\n  return_pcs_unique_proof: unit ->\n    squash (return_pcs_unique lpc_to_hpc return_lpcs);\n\n  lactions_consistent_with_is_nonyielding_pc_proof: unit ->\n    squash (each_action_list_consistent_with_is_nonyielding_pc is_nonyielding_lpc latomic_prog.actions);\n\n  hactions_consistent_with_is_nonyielding_pc_proof: unit ->\n    squash (each_action_list_consistent_with_is_nonyielding_pc is_nonyielding_hpc hatomic_prog.actions);\n\n  each_laction_doesnt_internally_yield_proof: unit ->\n    squash (each_action_list_doesnt_internally_yield latomic_prog.actions);\n\n  each_haction_doesnt_internally_yield_proof: unit ->\n    squash (each_action_list_doesnt_internally_yield hatomic_prog.actions);\n\n  each_haction_ends_atomic_block_if_necessary_proof: unit ->\n    squash (each_action_list_ends_atomic_block_if_necessary hatomic_prog.actions);\n\n  corresponding_hactions_correspond_proof: unit ->\n    squash (lists_correspond_ubool\n              (lactions_correspond_to_hactions_per_correspondence vs tds inv lpc_to_hpc return_lpcs\n                 hatomic_prog.actions)\n              latomic_prog.actions corresponding_hactions_info);\n}\n"
  },
  {
    "path": "experimental/lib/Strategies.VarHiding.Efficient.fst",
    "content": "module Strategies.VarHiding.Efficient\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Threads\nopen Armada.Transition\nopen Armada.Type\nopen Spec.Behavior\nopen Spec.List\nopen Spec.Logic\nopen Spec.Ubool\nopen Strategies.ArmadaStatement.ThreadState\nopen Strategies.Atomic\nopen Strategies.Breaking\nopen Strategies.GlobalVars\nopen Strategies.GlobalVars.Permanent\nopen Strategies.GlobalVars.Statement\nopen Strategies.GlobalVars.VarHiding\nopen Strategies.GlobalVars.VarIntro\nopen Strategies.Invariant\nopen Strategies.Nonyielding\nopen Strategies.PCIndices\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\nopen Strategies.VarHiding.Defs\nopen Strategies.VarHiding.Inefficient\nopen Strategies.VarHiding.Relation\nopen Util.ImmutableArray\nopen Util.List\nopen Util.Nth\nopen Util.Range\nopen Util.Relation\n\nlet default_pc: pc_t = \"\"\n\nlet make_pc_index_to_pc\n  (pcs: array_t pc_t)\n  (idx: nat)\n  : GTot pc_t =\n  match array_nth pcs idx with\n  | None -> default_pc\n  | Some pc -> pc\n\nlet make_pc_indices_to_pcs\n  (pcs: array_t pc_t)\n  (pc_indices: list nat)\n  : GTot (list pc_t) =\n  map_ghost (make_pc_index_to_pc pcs) pc_indices\n\nlet make_lpc_to_hpc\n  (lpcs: array_t pc_t)\n  (hpcs: array_t pc_t)\n  (lpc_to_hpc: array_t nat{array_len lpc_to_hpc = array_len lpcs})\n  (lpc: pc_t)\n  : GTot pc_t =\n  match find_in_array lpcs lpc with\n  | None -> default_pc\n  | Some lpc_index ->\n      let hpc_index = array_index lpc_to_hpc lpc_index in\n      make_pc_index_to_pc hpcs hpc_index\n\nlet rec make_return_pcs_offset\n  (pcs: array_t pc_t)\n  (is_return_pc: array_t bool{array_len is_return_pc = array_len pcs})\n  (offset: nat{offset <= array_len pcs})\n  : GTot (list pc_t) (decreases array_len pcs - offset) =\n  if offset = array_len pcs then\n    []\n  else if array_index is_return_pc offset = true then\n    (array_index pcs offset) :: make_return_pcs_offset pcs is_return_pc (offset + 1)\n  else\n    make_return_pcs_offset pcs is_return_pc (offset + 1)\n\nlet make_return_pcs\n  (pcs: array_t pc_t)\n  (is_return_pc: array_t bool{array_len is_return_pc = array_len pcs})\n  : GTot (list pc_t) =\n  make_return_pcs_offset pcs is_return_pc 0\n\nlet make_is_nonyielding_pc\n  (pcs: array_t pc_t)\n  (is_nonyielding_pc: array_t bool{array_len is_nonyielding_pc = array_len pcs})\n  (pc: pc_t)\n  : GTot bool =\n  match find_in_array pcs pc with\n  | None -> false\n  | Some idx -> array_index is_nonyielding_pc idx\n\nlet convert_efficient_thread_state\n  (pcs: array_t pc_t)\n  (ts: efficient_thread_state_t)\n  : GTot thread_state_t =\n  match ts with\n  | EfficientThreadStateRunning -> ThreadStateRunning\n  | EfficientThreadStateAtPC pc -> ThreadStateAtPC (make_pc_index_to_pc pcs pc)\n  | EfficientThreadStateNotRunning status -> ThreadStateNotRunning status\n  | EfficientThreadStateProcessStopped stop_reason -> ThreadStateProcessStopped stop_reason\n\nlet array_to_list_contains_array_nth_ambient\n  (pcs: array_t pc_t)\n  (idx: nat)\n  : Lemma (requires Some? (array_nth pcs idx))\n          (ensures  list_contains (Some?.v (array_nth pcs idx)) (array_to_list pcs))\n          [SMTPat  (Some? (array_nth pcs idx))] =\n  match array_nth pcs idx with\n  | Some pc ->\n      array_to_list_implies_array_matches_list pcs (array_to_list pcs);        \n      array_matches_list_implies_nth_equivalent pcs (array_to_list pcs) idx;\n      nth_implies_contains (array_to_list pcs) idx pc\n\nlet optional_pc_matches_optional_pc_index_ambient\n  (pcs: array_t pc_t)\n  (optional_pc: option pc_t)\n  (optional_index: option nat)\n  : Lemma (requires optional_pc_matches_optional_pc_index pcs optional_pc optional_index)\n          (ensures  (match optional_pc with\n                     | None -> True\n                     | Some pc -> list_contains pc (array_to_list pcs)))\n          [SMTPat (optional_pc_matches_optional_pc_index pcs optional_pc optional_index)] =\n  match optional_pc, optional_index with\n  | Some pc, Some idx ->\n      array_to_list_implies_array_matches_list pcs (array_to_list pcs);\n      array_matches_list_implies_index_equivalent pcs (array_to_list pcs) idx;\n      index_implies_contains (array_to_list pcs) idx pc\n  | _, _ -> ()\n\nlet find_in_array_inverts_index\n  (pcs: array_t pc_t)\n  (idx: nat)\n  : Lemma (requires   Some? (array_nth pcs idx)\n                    /\\ array_elements_unique pcs)\n          (ensures  find_in_array pcs (array_index pcs idx) = Some idx)\n          [SMTPat   (find_in_array pcs (array_index pcs idx))] =\n  array_elements_unique_implication pcs\n\nlet make_pc_indices_to_pcs_contains_pc_implies_pc_indices_contains_index\n  (pcs: array_t pc_t)\n  (pc_indices: list nat)\n  (pc: pc_t)\n  (idx: nat)\n  : Lemma (requires   list_contains pc (make_pc_indices_to_pcs pcs pc_indices)\n                    /\\ array_nth pcs idx = Some pc\n                    /\\ array_elements_unique pcs\n                    /\\ (forall (idx: nat). list_contains idx pc_indices ==> idx < array_len pcs))\n          (ensures  list_contains idx pc_indices) =\n  let idx' = reverse_map_element_of_map_ghost (make_pc_index_to_pc pcs) pc_indices pc in\n  array_elements_unique_implication pcs;\n  assert (idx' = idx)\n\nlet rec make_return_pcs_offset_contains_return_pc\n  (pcs: array_t pc_t)\n  (is_return_pc: array_t bool{array_len is_return_pc = array_len pcs})\n  (offset: nat{offset <= array_len pcs})\n  (idx: nat{offset <= idx /\\ idx < array_len pcs})\n  : Lemma (requires array_index is_return_pc idx = true)\n          (ensures  list_contains (array_index pcs idx) (make_return_pcs_offset pcs is_return_pc offset))\n          (decreases idx - offset) =\n  if offset = array_len pcs then\n    false_elim ()\n  else if idx = offset && array_index is_return_pc offset = true then\n    ()\n  else\n    make_return_pcs_offset_contains_return_pc pcs is_return_pc (offset + 1) idx\n\nlet make_return_pcs_contains_return_pc\n  (pcs: array_t pc_t)\n  (is_return_pc: array_t bool{array_len is_return_pc = array_len pcs})\n  (idx: nat{idx < array_len is_return_pc})\n  : Lemma (requires array_index is_return_pc idx = true)\n          (ensures  list_contains (array_index pcs idx) (make_return_pcs pcs is_return_pc)) =\n  make_return_pcs_offset_contains_return_pc pcs is_return_pc 0 idx\n\nlet lpc_hpc_relation_facts\n  (lpcs: array_t pc_t)\n  (hpcs: array_t pc_t)\n  (lpc_to_hpc: array_t nat{array_len lpc_to_hpc = array_len lpcs})\n  (is_return_lpc: array_t bool{array_len is_return_lpc = array_len lpcs})\n  : Lemma (requires array_elements_unique lpcs)\n          (ensures  (let index_relation = efficient_lh_pc_relation lpc_to_hpc in\n                     let index_return_relation = efficient_lh_pc_return_relation lpc_to_hpc is_return_lpc in\n                     let inefficient_lpc_to_hpc = make_lpc_to_hpc lpcs hpcs lpc_to_hpc in\n                     let inefficient_return_lpcs = make_return_pcs lpcs is_return_lpc in\n                     let pc_relation = lpc_hpc_pc_relation inefficient_lpc_to_hpc in\n                     let pc_return_relation = lpc_hpc_pc_return_relation inefficient_lpc_to_hpc\n                                                inefficient_return_lpcs in\n                     forall (lidx: nat) (hidx: nat). lidx < array_len lpcs /\\ hidx < array_len hpcs ==>\n                         (let lpc = array_index lpcs lidx in\n                          let hpc = array_index hpcs hidx in\n                            (index_relation lidx hidx ==> pc_relation lpc hpc)\n                          /\\ (index_return_relation lidx hidx ==> pc_return_relation lpc hpc)))) =\n  let index_relation = efficient_lh_pc_relation lpc_to_hpc in\n  let index_return_relation = efficient_lh_pc_return_relation lpc_to_hpc is_return_lpc in\n  let inefficient_lpc_to_hpc = make_lpc_to_hpc lpcs hpcs lpc_to_hpc in\n  let inefficient_return_lpcs = make_return_pcs lpcs is_return_lpc in\n  let pc_relation = lpc_hpc_pc_relation inefficient_lpc_to_hpc in\n  let pc_return_relation = lpc_hpc_pc_return_relation inefficient_lpc_to_hpc inefficient_return_lpcs in\n  let inefficient_lpc_to_hpc = make_lpc_to_hpc lpcs hpcs lpc_to_hpc in\n  let inefficient_return_lpcs = make_return_pcs lpcs is_return_lpc in\n  introduce forall (lidx: nat) (hidx: nat). lidx < array_len lpcs /\\ hidx < array_len hpcs ==>\n                         (let lpc = array_index lpcs lidx in\n                          let hpc = array_index hpcs hidx in\n                            (index_relation lidx hidx ==> pc_relation lpc hpc)\n                          /\\ (index_return_relation lidx hidx ==> pc_return_relation lpc hpc))\n  with introduce _ ==> _\n  with _. (\n    let lpc = array_index lpcs lidx in\n    let hpc = array_index hpcs hidx in\n    introduce index_relation lidx hidx ==> pc_relation lpc hpc\n    with _. (\n      assert (array_nth lpc_to_hpc lidx = Some hidx);\n      assert (find_in_array lpcs lpc = Some lidx);\n      assert (array_index lpc_to_hpc lidx = hidx);\n      assert (make_pc_index_to_pc hpcs hidx = hpc);\n      assert (inefficient_lpc_to_hpc lpc = hpc)\n    );\n    introduce index_return_relation lidx hidx ==> pc_return_relation lpc hpc\n    with _. (\n      assert (array_nth lpc_to_hpc lidx = Some hidx);\n      assert (array_nth is_return_lpc lidx = Some true);\n      assert (find_in_array lpcs lpc = Some lidx);\n      assert (array_index lpc_to_hpc lidx = hidx);\n      assert (make_pc_index_to_pc hpcs hidx = hpc);\n      assert (inefficient_lpc_to_hpc lpc = hpc);\n      make_return_pcs_contains_return_pc lpcs is_return_lpc lidx;\n      assert (list_contains lpc inefficient_return_lpcs)\n    )\n  )\n\nlet program_inits_match_except_global_variables_lemma\n  (vs: list var_id_t)\n  (lpcs: array_t pc_t)\n  (hpcs: array_t pc_t)\n  (lpc_to_hpc: array_t nat{array_len lpc_to_hpc = array_len lpcs})\n  (which_initializers_are_hidings: list bool)\n  (lprog: Armada.Program.t)\n  (hprog: Armada.Program.t)\n  (lprog_main_start_pc_index: nat)\n  (hprog_main_start_pc_index: nat)\n  : Lemma (requires   efficient_program_inits_match_except_global_variables vs lpcs hpcs lpc_to_hpc\n                        which_initializers_are_hidings lprog hprog lprog_main_start_pc_index hprog_main_start_pc_index\n                    /\\ array_elements_unique lpcs)\n          (ensures    program_inits_match_except_global_variables vs (make_lpc_to_hpc lpcs hpcs lpc_to_hpc)\n                        which_initializers_are_hidings lprog hprog\n                    /\\ (make_lpc_to_hpc lpcs hpcs lpc_to_hpc) lprog.main_start_pc = hprog.main_start_pc) =\n  array_elements_unique_implication lpcs\n\nlet rec get_index_of_pc_among_return_pcs_offset\n  (lpcs: array_t pc_t)\n  (is_return_lpc: array_t bool{array_len is_return_lpc = array_len lpcs})\n  (offset: nat{offset <= array_len lpcs})\n  (pc: pc_t)\n  : Ghost nat\n  (requires list_contains pc (make_return_pcs_offset lpcs is_return_lpc offset))\n  (ensures fun idx -> idx < array_len lpcs /\\ array_index lpcs idx = pc /\\ array_index is_return_lpc idx = true)\n  (decreases array_len lpcs - offset) =\n  if offset = array_len lpcs then\n    false_elim ()\n  else if array_index is_return_lpc offset = true then (\n    if array_index lpcs offset = pc then\n      offset\n    else\n      get_index_of_pc_among_return_pcs_offset lpcs is_return_lpc (offset + 1) pc\n  )\n  else\n    get_index_of_pc_among_return_pcs_offset lpcs is_return_lpc (offset + 1) pc\n\nlet get_index_of_pc_among_return_pcs\n  (lpcs: array_t pc_t)\n  (is_return_lpc: array_t bool{array_len is_return_lpc = array_len lpcs})\n  (pc: pc_t)\n  : Ghost nat\n  (requires list_contains pc (make_return_pcs lpcs is_return_lpc))\n  (ensures  fun idx -> idx < array_len lpcs /\\ array_index lpcs idx = pc /\\ array_index is_return_lpc idx = true) =\n  get_index_of_pc_among_return_pcs_offset lpcs is_return_lpc 0 pc\n\nlet apply_efficient_return_lpcs_unique\n  (num_lpcs: nat)\n  (lpc_to_lpc: array_t nat)\n  (is_return_lpc: array_t bool)\n  (lpc1: nat)\n  (lpc2: nat)\n  : Lemma (requires   efficient_return_lpcs_unique num_lpcs lpc_to_lpc is_return_lpc\n                    /\\ lpc1 < num_lpcs\n                    /\\ lpc2 < num_lpcs\n                    /\\ array_nth is_return_lpc lpc1 = Some true\n                    /\\ array_nth is_return_lpc lpc2 = Some true\n                    /\\ array_nth lpc_to_lpc lpc1 = array_nth lpc_to_lpc lpc2)\n          (ensures  lpc1 = lpc2) =\n  assert (efficient_return_lpcs_unique_inner1 num_lpcs lpc_to_lpc is_return_lpc lpc1);\n  assert (efficient_return_lpcs_unique_inner2 lpc_to_lpc is_return_lpc lpc1 lpc2)\n\n#push-options \"--z3rlimit 10\"\n\nlet return_pcs_unique_lemma\n  (lpcs: array_t pc_t)\n  (hpcs: array_t pc_t)\n  (lpc_to_hpc: array_t nat{array_len lpc_to_hpc = array_len lpcs})\n  (is_return_lpc: array_t bool{array_len is_return_lpc = array_len lpcs})\n  : Lemma (requires   efficient_return_lpcs_unique (array_len lpcs) lpc_to_hpc is_return_lpc\n                    /\\ efficient_lpc_to_hpc_contains_valid_indices (array_len hpcs) lpc_to_hpc\n                    /\\ array_elements_unique lpcs\n                    /\\ array_elements_unique hpcs)\n          (ensures  return_pcs_unique (make_lpc_to_hpc lpcs hpcs lpc_to_hpc) (make_return_pcs lpcs is_return_lpc)) =\n  let inefficient_return_lpcs = make_return_pcs lpcs is_return_lpc in\n  let inefficient_lpc_to_hpc = make_lpc_to_hpc lpcs hpcs lpc_to_hpc in\n  introduce forall lpc1. list_contains lpc1 inefficient_return_lpcs ==>\n              return_pcs_unique_inner1 inefficient_lpc_to_hpc inefficient_return_lpcs lpc1\n  with introduce list_contains lpc1 inefficient_return_lpcs ==>\n                   return_pcs_unique_inner1 inefficient_lpc_to_hpc inefficient_return_lpcs lpc1\n  with _. introduce forall lpc2. list_contains lpc2 inefficient_return_lpcs ==>\n                      return_pcs_unique_inner2 inefficient_lpc_to_hpc inefficient_return_lpcs lpc1 lpc2\n  with introduce list_contains lpc2 inefficient_return_lpcs ==>\n                   return_pcs_unique_inner2 inefficient_lpc_to_hpc inefficient_return_lpcs lpc1 lpc2\n  with _. introduce inefficient_lpc_to_hpc lpc1 = inefficient_lpc_to_hpc lpc2 ==> lpc1 = lpc2\n  with _. (\n    let lpc_index1 = get_index_of_pc_among_return_pcs lpcs is_return_lpc lpc1 in\n    let lpc_index2 = get_index_of_pc_among_return_pcs lpcs is_return_lpc lpc2 in\n    assert (lpc_index1 < array_len lpcs);\n    assert (Some? (array_nth lpc_to_hpc lpc_index1));\n    assert (array_nth is_return_lpc lpc_index1 = Some true);\n    assert (lpc_index2 < array_len lpcs);\n    assert (Some? (array_nth lpc_to_hpc lpc_index2));\n    assert (array_nth is_return_lpc lpc_index2 = Some true);\n    array_elements_unique_implication lpcs;\n    assert (find_in_array lpcs lpc1 = Some lpc_index1);\n    assert (find_in_array lpcs lpc2 = Some lpc_index2);\n    let hpc_index1 = array_index lpc_to_hpc lpc_index1 in\n    let hpc_index2 = array_index lpc_to_hpc lpc_index2 in\n    assert (inefficient_lpc_to_hpc lpc1 = make_pc_index_to_pc hpcs hpc_index1);\n    assert (inefficient_lpc_to_hpc lpc2 = make_pc_index_to_pc hpcs hpc_index2);\n    assert (make_pc_index_to_pc hpcs hpc_index1 = make_pc_index_to_pc hpcs hpc_index2);\n    array_elements_unique_implication hpcs;\n    assert (hpc_index1 < array_len hpcs);\n    assert (hpc_index2 < array_len hpcs);\n    assert (hpc_index1 = hpc_index2);\n    assert (array_nth lpc_to_hpc lpc_index1 = array_nth lpc_to_hpc lpc_index2);\n    apply_efficient_return_lpcs_unique (array_len lpcs) lpc_to_hpc is_return_lpc lpc_index1 lpc_index2\n  )\n\nlet each_action_list_consistent_with_is_nonyielding_pc_helper\n  (pcs: array_t pc_t)\n  (is_nonyielding_pc: array_t bool{array_len is_nonyielding_pc = array_len pcs})\n  (action: Armada.Action.t)\n  (pc_indices: statement_pc_indices_t)\n  : Lemma (requires   efficient_action_consistent_with_is_nonyielding_pc is_nonyielding_pc action pc_indices\n                    /\\ action_corresponds_to_statement_pc_indices pcs action pc_indices\n                    /\\ array_elements_unique pcs)\n          (ensures  action_consistent_with_is_nonyielding_pc (make_is_nonyielding_pc pcs is_nonyielding_pc) action) =\n  ()\n\n#pop-options\n\nlet each_action_list_consistent_with_is_nonyielding_pc_lemma\n  (pcs: array_t pc_t)\n  (is_nonyielding_pc: array_t bool{array_len is_nonyielding_pc = array_len pcs})\n  (actions_list: list (list Armada.Action.t))\n  (pc_indices_array: array_t (list statement_pc_indices_t))\n  : Lemma (requires   efficient_each_action_list_consistent_with_is_nonyielding_pc is_nonyielding_pc\n                        (list_to_array actions_list) pc_indices_array\n                    /\\ actions_array_corresponds_to_statement_pc_indices_array pcs (list_to_array actions_list)\n                        pc_indices_array\n                    /\\ array_elements_unique pcs)\n          (ensures each_action_list_consistent_with_is_nonyielding_pc (make_is_nonyielding_pc pcs is_nonyielding_pc)\n                     actions_list) =\n  let inefficient_is_nonyielding_pc = make_is_nonyielding_pc pcs is_nonyielding_pc in\n  introduce forall actions. contains_ubool actions actions_list ==>\n               each_action_consistent_with_is_nonyielding_pc inefficient_is_nonyielding_pc actions\n  with introduce contains_ubool actions actions_list ==>\n                   each_action_consistent_with_is_nonyielding_pc inefficient_is_nonyielding_pc actions\n  with _. introduce forall action. contains_ubool action actions ==>\n                      action_consistent_with_is_nonyielding_pc inefficient_is_nonyielding_pc action\n  with introduce contains_ubool action actions ==>\n                   action_consistent_with_is_nonyielding_pc inefficient_is_nonyielding_pc action\n  with _. (\n    let idx = contains_ubool_to_index actions actions_list in\n    let pc_indices_list = array_index pc_indices_array idx in\n    arrays_correspond_specific_index (action_list_corresponds_to_statement_pc_indices_list pcs)\n      (list_to_array actions_list) pc_indices_array idx;\n    assert (action_list_corresponds_to_statement_pc_indices_list pcs actions pc_indices_list);\n    assert (efficient_each_action_consistent_with_is_nonyielding_pc is_nonyielding_pc actions pc_indices_list);\n    let pc_indices = get_correspondent_from_lists_correspond_doubly\n      (fun action pc_indices -> efficient_action_consistent_with_is_nonyielding_pc is_nonyielding_pc action pc_indices)\n      (action_corresponds_to_statement_pc_indices pcs)\n      actions pc_indices_list action in\n    assert (efficient_action_consistent_with_is_nonyielding_pc is_nonyielding_pc action pc_indices);\n    assert (action_corresponds_to_statement_pc_indices pcs action pc_indices);\n    each_action_list_consistent_with_is_nonyielding_pc_helper pcs is_nonyielding_pc action pc_indices;\n    assert (action_consistent_with_is_nonyielding_pc inefficient_is_nonyielding_pc action)\n  )\n\nlet efficient_laction_corresponds_to_haction_preservation\n  (vs: list var_id_t)\n  (lpcs: array_t pc_t)\n  (hpcs: array_t pc_t)\n  (lpc_to_hpc: array_t nat{array_len lpc_to_hpc = array_len lpcs})\n  (is_return_lpc: array_t bool{array_len is_return_lpc = array_len lpcs})\n  (laction: Armada.Action.t)\n  (haction: Armada.Action.t)\n  (lpc_indices: statement_pc_indices_t)\n  (hpc_indices: statement_pc_indices_t)\n  : Lemma (requires (let pc_relation = efficient_lh_pc_relation lpc_to_hpc in\n                     let pc_return_relation = efficient_lh_pc_return_relation lpc_to_hpc is_return_lpc in\n                       efficient_laction_corresponds_to_haction vs pc_relation pc_return_relation laction haction\n                         lpc_indices hpc_indices\n                     /\\ action_corresponds_to_statement_pc_indices lpcs laction lpc_indices\n                     /\\ action_corresponds_to_statement_pc_indices hpcs haction hpc_indices\n                     /\\ array_elements_unique lpcs))\n          (ensures  (let inefficient_lpc_to_hpc = make_lpc_to_hpc lpcs hpcs lpc_to_hpc in\n                     let inefficient_return_lpcs = make_return_pcs lpcs is_return_lpc in\n                     laction_corresponds_to_haction vs inefficient_lpc_to_hpc inefficient_return_lpcs laction\n                       haction)) =\n  let pc_relation = efficient_lh_pc_relation lpc_to_hpc in\n  let pc_return_relation = efficient_lh_pc_return_relation lpc_to_hpc is_return_lpc in\n  let inefficient_lpc_to_hpc = make_lpc_to_hpc lpcs hpcs lpc_to_hpc in\n  let inefficient_return_lpcs = make_return_pcs lpcs is_return_lpc in\n  let lps, hps = laction.program_statement, haction.program_statement in\n  let relation = lpc_hpc_pc_relation inefficient_lpc_to_hpc in\n  let return_relation = lpc_hpc_pc_return_relation inefficient_lpc_to_hpc inefficient_return_lpcs in\n  assert (efficient_program_statements_match_per_pc_relation pc_relation pc_return_relation lps hps lpc_indices\n            hpc_indices);\n  lpc_hpc_relation_facts lpcs hpcs lpc_to_hpc is_return_lpc;\n  efficient_program_statements_match_per_pc_relation_implies_program_statements_match_per_pc_relation lpcs hpcs\n    pc_relation pc_return_relation relation return_relation lps hps lpc_indices hpc_indices;\n  assert (program_statements_match_per_pc_relation relation return_relation lps hps)\n\nlet efficient_thread_states_match_per_pc_relation_implies_thread_states_match_per_pc_relation\n  (lpcs: array_t pc_t)\n  (hpcs: array_t pc_t)\n  (lpc_to_hpc: array_t nat{array_len lpc_to_hpc = array_len lpcs})\n  (lts: efficient_thread_state_t)\n  (hts: efficient_thread_state_t)\n  : Lemma (requires (let index_relation = efficient_lh_pc_relation lpc_to_hpc in\n                       efficient_thread_states_match_per_pc_relation index_relation lts hts\n                     /\\ array_elements_unique lpcs))\n          (ensures  (let inefficient_lpc_to_hpc = make_lpc_to_hpc lpcs hpcs lpc_to_hpc in\n                     let pc_relation = lpc_hpc_pc_relation inefficient_lpc_to_hpc in\n                     thread_states_match_per_pc_relation pc_relation\n                       (convert_efficient_thread_state lpcs lts)\n                       (convert_efficient_thread_state hpcs hts)))\n          [SMTPat (thread_states_match_per_pc_relation (lpc_hpc_pc_relation (make_lpc_to_hpc lpcs hpcs lpc_to_hpc))\n                    (convert_efficient_thread_state lpcs lts) (convert_efficient_thread_state hpcs hts))] =\n  ()\n\nlet invert_make_pc_indices_to_pcs\n  (pcs: array_t pc_t)\n  (pc_indices: list nat{forall idx. list_contains idx pc_indices ==> idx < array_len pcs})\n  (pc: pc_t{list_contains pc (make_pc_indices_to_pcs pcs pc_indices)})\n  : GTot (idx: nat{list_contains idx pc_indices /\\ array_nth pcs idx = Some pc}) =\n  reverse_map_element_of_map_ghost (make_pc_index_to_pc pcs) pc_indices pc\n\nlet efficient_action_to_starting_thread_state_matches\n  (pcs: array_t pc_t)\n  (action: Armada.Action.t)\n  (pc_indices: statement_pc_indices_t)\n  : Lemma (requires action_corresponds_to_statement_pc_indices pcs action pc_indices)\n          (ensures  action_to_starting_thread_state action = convert_efficient_thread_state pcs\n                      (efficient_action_to_starting_thread_state pc_indices))\n          [SMTPat (action_to_starting_thread_state action);\n           SMTPat (action_corresponds_to_statement_pc_indices pcs action pc_indices)] =\n  ()\n\nlet efficient_action_to_ending_thread_state_matches\n  (pcs: array_t pc_t)\n  (action: Armada.Action.t)\n  (pc_indices: statement_pc_indices_t)\n  : Lemma (requires action_corresponds_to_statement_pc_indices pcs action pc_indices)\n          (ensures  action_to_ending_thread_state action = convert_efficient_thread_state pcs\n                      (efficient_action_to_ending_thread_state action pc_indices))\n          [SMTPat  (action_to_ending_thread_state action);\n           SMTPat  (action_corresponds_to_statement_pc_indices pcs action pc_indices)] =\n  ()\n\nlet rec efficient_actions_to_ending_thread_state_matches\n  (pcs: array_t pc_t)\n  (actions: list Armada.Action.t)\n  (pc_indices_list: list statement_pc_indices_t)\n  : Lemma (requires action_list_corresponds_to_statement_pc_indices_list pcs actions pc_indices_list)\n          (ensures  actions_to_ending_thread_state actions = convert_efficient_thread_state pcs\n                      (efficient_actions_to_ending_thread_state actions pc_indices_list))\n          (decreases actions)\n          [SMTPat  (actions_to_ending_thread_state actions);\n           SMTPat  (action_list_corresponds_to_statement_pc_indices_list pcs actions pc_indices_list)] =\n  match actions, pc_indices_list with\n  | [], _ -> ()\n  | [action], [pc_indices] -> ()\n  | first_action :: remaining_actions, first_pc_indices :: remaining_pc_indices ->\n      efficient_actions_to_ending_thread_state_matches pcs remaining_actions remaining_pc_indices\n  | _, _ -> false_elim ()\n\nlet rec efficient_lactions_all_hidden_preservation\n  (vs: list var_id_t)\n  (lpcs: array_t pc_t)\n  (hpcs: array_t pc_t)\n  (lpc_to_hpc: array_t nat{array_len lpc_to_hpc = array_len lpcs})\n  (lstart_state: efficient_thread_state_t)\n  (lend_state: efficient_thread_state_t)\n  (lactions: list Armada.Action.t)\n  (lpc_indices: list statement_pc_indices_t)\n  : Lemma (requires (  efficient_lactions_all_hidden vs lpc_to_hpc lstart_state lend_state lactions lpc_indices\n                     /\\ action_list_corresponds_to_statement_pc_indices_list lpcs lactions lpc_indices\n                     /\\ array_elements_unique lpcs))\n          (ensures  (let inefficient_lpc_to_hpc = make_lpc_to_hpc lpcs hpcs lpc_to_hpc in\n                     let inefficient_lstart_state = convert_efficient_thread_state lpcs lstart_state in\n                     let inefficient_lend_state = convert_efficient_thread_state lpcs lend_state in\n                     lactions_all_hidden vs inefficient_lpc_to_hpc inefficient_lstart_state inefficient_lend_state\n                       lactions))\n          (decreases lactions) =\n  let pc_relation = efficient_lh_pc_relation lpc_to_hpc in\n  let inefficient_lpc_to_hpc = make_lpc_to_hpc lpcs hpcs lpc_to_hpc in\n  let inefficient_lstart_state = convert_efficient_thread_state lpcs lstart_state in\n  let inefficient_lend_state = convert_efficient_thread_state lpcs lend_state in\n  match lactions, lpc_indices with\n  | [], [] -> ()\n  | first_laction :: remaining_lactions, first_lpc_indices :: remaining_lpc_indices ->\n      efficient_lactions_all_hidden_preservation vs lpcs hpcs lpc_to_hpc\n        (efficient_action_to_ending_thread_state first_laction first_lpc_indices)\n        lend_state remaining_lactions remaining_lpc_indices;\n      assert (match inefficient_lstart_state, action_to_ending_thread_state first_laction with\n              | ThreadStateAtPC lpc1, ThreadStateAtPC lpc2 -> inefficient_lpc_to_hpc lpc1 = inefficient_lpc_to_hpc lpc2\n              | _, _ -> False)\n\nlet rec efficient_lactions_correspond_to_hactions_preservation\n  (vs: list var_id_t)\n  (lpcs: array_t pc_t)\n  (hpcs: array_t pc_t)\n  (lpc_to_hpc: array_t nat{array_len lpc_to_hpc = array_len lpcs})\n  (is_return_lpc: array_t bool{array_len is_return_lpc = array_len lpcs})\n  (lstart_state: efficient_thread_state_t)\n  (hstart_state: efficient_thread_state_t)\n  (lend_state: efficient_thread_state_t)\n  (hend_state: efficient_thread_state_t)\n  (which_actions_hidden: list bool)\n  (lactions: list Armada.Action.t)\n  (hactions: list Armada.Action.t)\n  (lpc_indices: list statement_pc_indices_t)\n  (hpc_indices: list statement_pc_indices_t)\n  : Lemma (requires (let pc_relation = efficient_lh_pc_relation lpc_to_hpc in\n                     let pc_return_relation = efficient_lh_pc_return_relation lpc_to_hpc is_return_lpc in\n                       efficient_lactions_correspond_to_hactions vs pc_relation pc_return_relation\n                         lstart_state hstart_state lend_state hend_state which_actions_hidden lactions hactions\n                         lpc_indices hpc_indices\n                     /\\ action_list_corresponds_to_statement_pc_indices_list lpcs lactions lpc_indices\n                     /\\ action_list_corresponds_to_statement_pc_indices_list hpcs hactions hpc_indices\n                     /\\ array_elements_unique lpcs\n                     /\\ array_elements_unique hpcs))\n          (ensures  (let inefficient_lpc_to_hpc = make_lpc_to_hpc lpcs hpcs lpc_to_hpc in\n                     let inefficient_return_lpcs = make_return_pcs lpcs is_return_lpc in\n                     let inefficient_lstart_state = convert_efficient_thread_state lpcs lstart_state in\n                     let inefficient_lend_state = convert_efficient_thread_state lpcs lend_state in\n                     let inefficient_hstart_state = convert_efficient_thread_state hpcs hstart_state in\n                     let inefficient_hend_state = convert_efficient_thread_state hpcs hend_state in\n                     lactions_correspond_to_hactions vs inefficient_lpc_to_hpc inefficient_return_lpcs\n                       inefficient_lstart_state inefficient_hstart_state inefficient_lend_state\n                       inefficient_hend_state which_actions_hidden lactions hactions))\n          (decreases lactions) =\n  let pc_relation = efficient_lh_pc_relation lpc_to_hpc in\n  let pc_return_relation = efficient_lh_pc_return_relation lpc_to_hpc is_return_lpc in\n  let inefficient_lpc_to_hpc = make_lpc_to_hpc lpcs hpcs lpc_to_hpc in\n  let inefficient_return_lpcs = make_return_pcs lpcs is_return_lpc in\n  let inefficient_lstart_state = convert_efficient_thread_state lpcs lstart_state in\n  let inefficient_lend_state = convert_efficient_thread_state lpcs lend_state in\n  let inefficient_hstart_state = convert_efficient_thread_state hpcs hstart_state in\n  let inefficient_hend_state = convert_efficient_thread_state hpcs hend_state in\n  let relation = fun lpc hpc -> inefficient_lpc_to_hpc lpc = hpc in\n  lpc_hpc_relation_facts lpcs hpcs lpc_to_hpc is_return_lpc;\n  match which_actions_hidden, lactions, hactions, lpc_indices, hpc_indices with\n  | [], [], [], [], [] -> ()\n  | false :: remaining_which_actions_hidden, first_laction :: remaining_lactions, first_haction :: remaining_hactions,\n      first_lpc_indices :: remaining_lpc_indices, first_hpc_indices :: remaining_hpc_indices ->\n      efficient_laction_corresponds_to_haction_preservation vs lpcs hpcs lpc_to_hpc is_return_lpc\n        first_laction first_haction first_lpc_indices first_hpc_indices;\n      efficient_lactions_correspond_to_hactions_preservation vs lpcs hpcs lpc_to_hpc is_return_lpc\n        (efficient_action_to_ending_thread_state first_laction first_lpc_indices)\n        (efficient_action_to_ending_thread_state first_haction first_hpc_indices)\n        lend_state hend_state remaining_which_actions_hidden remaining_lactions remaining_hactions\n        remaining_lpc_indices remaining_hpc_indices\n  | true :: remaining_which_actions_hidden, first_laction :: remaining_lactions, _,\n      first_lpc_indices :: remaining_lpc_indices, _ ->\n      efficient_lactions_correspond_to_hactions_preservation vs lpcs hpcs lpc_to_hpc is_return_lpc\n        (efficient_action_to_ending_thread_state first_laction first_lpc_indices) hstart_state\n        lend_state hend_state remaining_which_actions_hidden remaining_lactions hactions remaining_lpc_indices\n        hpc_indices\n  | _, _, _, _, _ -> false_elim ()\n\n#push-options \"--z3rlimit 30\"\n\nlet efficient_corresponding_hactions_info_correct_inner_preservation\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (inv: invariant_t Armada.State.t)\n  (latomic_actions: list (list Armada.Action.t))\n  (hatomic_actions: list (list Armada.Action.t))\n  (lpcs: array_t pc_t)\n  (hpcs: array_t pc_t)\n  (lpc_to_hpc: array_t nat{array_len lpc_to_hpc = array_len lpcs})\n  (is_nonyielding_lpc: array_t bool{array_len is_nonyielding_lpc = array_len lpcs})\n  (is_return_lpc: array_t bool{array_len is_return_lpc = array_len lpcs})\n  (corresponding_hactions_info: array_t (ltoh_correspondence_t vs tds inv)\n    {array_len corresponding_hactions_info = list_len latomic_actions})\n  (lpc_indices_array: array_t (list statement_pc_indices_t))\n  (hpc_indices_array: array_t (list statement_pc_indices_t))\n  (correspondence: ltoh_correspondence_t vs tds inv)\n  (laction_idx: nat{laction_idx < list_len latomic_actions})\n  : Lemma (requires (let pc_relation = efficient_lh_pc_relation lpc_to_hpc in\n                     let pc_return_relation = efficient_lh_pc_return_relation lpc_to_hpc is_return_lpc in\n                       efficient_corresponding_hactions_info_correct_inner vs tds inv (list_to_array latomic_actions)\n                         (list_to_array hatomic_actions) corresponding_hactions_info lpc_indices_array\n                         hpc_indices_array lpc_to_hpc pc_relation pc_return_relation laction_idx\n                     /\\ efficient_lpc_to_hpc_contains_valid_indices (array_len hpcs) lpc_to_hpc\n                     /\\ array_elements_unique lpcs\n                     /\\ array_elements_unique hpcs\n                     /\\ actions_array_corresponds_to_statement_pc_indices_array lpcs (list_to_array latomic_actions)\n                         lpc_indices_array\n                     /\\ actions_array_corresponds_to_statement_pc_indices_array hpcs (list_to_array hatomic_actions)\n                         hpc_indices_array\n                     /\\ array_nth corresponding_hactions_info laction_idx == Some correspondence))\n          (ensures  (let inefficient_lpc_to_hpc = make_lpc_to_hpc lpcs hpcs lpc_to_hpc in\n                     let inefficient_is_nonyielding_lpc = make_is_nonyielding_pc lpcs is_nonyielding_lpc in\n                     let inefficient_hpcs = array_to_list hpcs in\n                     let inefficient_return_lpcs = make_return_pcs lpcs is_return_lpc in\n                     let lactions = list_index latomic_actions laction_idx in\n                     lactions_correspond_to_hactions_per_correspondence vs tds inv inefficient_lpc_to_hpc\n                       inefficient_return_lpcs hatomic_actions lactions correspondence)) =\n  let inefficient_lpc_to_hpc = make_lpc_to_hpc lpcs hpcs lpc_to_hpc in\n  let inefficient_is_nonyielding_lpc = make_is_nonyielding_pc lpcs is_nonyielding_lpc in\n  let inefficient_hpcs = array_to_list hpcs in\n  let inefficient_return_lpcs = make_return_pcs lpcs is_return_lpc in\n  let latomic_actions_array = list_to_array latomic_actions in\n  let hatomic_actions_array = list_to_array hatomic_actions in\n  let ltoh_info = array_index corresponding_hactions_info laction_idx in\n  list_to_array_implies_index_equivalent latomic_actions_array latomic_actions laction_idx;\n  assert (list_index latomic_actions laction_idx == array_index latomic_actions_array laction_idx);\n  let lactions = array_index latomic_actions_array laction_idx in\n  let pc_relation = efficient_lh_pc_relation lpc_to_hpc in\n  let pc_return_relation = efficient_lh_pc_return_relation lpc_to_hpc is_return_lpc in\n  assert (efficient_corresponding_hactions_info_correct_inner vs tds inv latomic_actions_array\n            hatomic_actions_array corresponding_hactions_info\n            lpc_indices_array hpc_indices_array lpc_to_hpc pc_relation pc_return_relation laction_idx);\n  let lpc_indices = array_index lpc_indices_array laction_idx in\n  assert (action_list_corresponds_to_statement_pc_indices_list lpcs lactions lpc_indices);\n  match array_index corresponding_hactions_info laction_idx with\n  | CorrespondenceHidden ->\n      let lstart_state = efficient_action_to_starting_thread_state (Cons?.hd lpc_indices) in\n      let lend_state = efficient_actions_to_ending_thread_state lactions lpc_indices in\n      assert (actions_start_atomic_block lactions = actions_end_atomic_block lactions);\n      efficient_lactions_all_hidden_preservation vs lpcs hpcs lpc_to_hpc\n        lstart_state lend_state lactions lpc_indices\n  | CorrespondencePropagate hidx ->\n      list_to_array_implies_nth_equivalent hatomic_actions_array hatomic_actions hidx\n  | CorrespondenceNormal hidx which_actions_hidden ->\n      list_to_array_implies_nth_equivalent hatomic_actions_array hatomic_actions hidx;\n      (match array_nth hatomic_actions_array hidx, array_nth hpc_indices_array hidx with\n       | Some hactions, Some hpc_indices ->\n           assert (action_list_corresponds_to_statement_pc_indices_list hpcs hactions hpc_indices);\n           let lstart_state = efficient_action_to_starting_thread_state (Cons?.hd lpc_indices) in\n           let lend_state = efficient_actions_to_ending_thread_state lactions lpc_indices in\n           let hstart_state = efficient_action_to_starting_thread_state (Cons?.hd hpc_indices) in\n           let hend_state = efficient_actions_to_ending_thread_state hactions hpc_indices in\n           efficient_lactions_correspond_to_hactions_preservation vs lpcs hpcs lpc_to_hpc is_return_lpc\n             lstart_state hstart_state lend_state hend_state which_actions_hidden lactions hactions lpc_indices\n             hpc_indices;\n           assert (lactions_correspond_to_hactions_per_correspondence vs tds inv inefficient_lpc_to_hpc\n                     inefficient_return_lpcs hatomic_actions lactions correspondence))\n  | CorrespondenceImpossibleConstantAssignmentFailure ->\n      ()\n  | CorrespondenceImpossibleStatementFailure ps proof ->\n      ()\n\n#pop-options\n#push-options \"--z3rlimit 10\"\n\nlet corresponding_hactions_info_correct_lemma\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (inv: invariant_t Armada.State.t)\n  (latomic_actions: list (list Armada.Action.t))\n  (hatomic_actions: list (list Armada.Action.t))\n  (lpcs: array_t pc_t)\n  (hpcs: array_t pc_t)\n  (lpc_to_hpc: array_t nat{array_len lpc_to_hpc = array_len lpcs})\n  (is_nonyielding_lpc: array_t bool{array_len is_nonyielding_lpc = array_len lpcs})\n  (is_return_lpc: array_t bool{array_len is_return_lpc = array_len lpcs})\n  (corresponding_hactions_info: array_t (ltoh_correspondence_t vs tds inv)\n    {array_len corresponding_hactions_info = list_len latomic_actions})\n  (lpc_indices_array: array_t (list statement_pc_indices_t))\n  (hpc_indices_array: array_t (list statement_pc_indices_t))\n  : Lemma (requires   efficient_corresponding_hactions_info_correct vs tds inv (list_to_array latomic_actions)\n                        (list_to_array hatomic_actions) lpc_to_hpc is_return_lpc\n                        corresponding_hactions_info lpc_indices_array hpc_indices_array\n                    /\\ efficient_lpc_to_hpc_contains_valid_indices (array_len hpcs) lpc_to_hpc\n                    /\\ array_elements_unique lpcs\n                    /\\ array_elements_unique hpcs\n                    /\\ actions_array_corresponds_to_statement_pc_indices_array lpcs (list_to_array latomic_actions)\n                        lpc_indices_array\n                    /\\ actions_array_corresponds_to_statement_pc_indices_array hpcs (list_to_array hatomic_actions)\n                        hpc_indices_array\n                    /\\ array_len corresponding_hactions_info = array_len (list_to_array latomic_actions))\n          (ensures  (let inefficient_lpc_to_hpc = make_lpc_to_hpc lpcs hpcs lpc_to_hpc in\n                     let inefficient_is_nonyielding_lpc = make_is_nonyielding_pc lpcs is_nonyielding_lpc in\n                     let inefficient_hpcs = array_to_list hpcs in\n                     let inefficient_return_lpcs = make_return_pcs lpcs is_return_lpc in\n                     lists_correspond_ubool\n                       (lactions_correspond_to_hactions_per_correspondence vs tds inv inefficient_lpc_to_hpc\n                          inefficient_return_lpcs hatomic_actions)\n                       latomic_actions (array_to_list corresponding_hactions_info))) =\n  let inefficient_lpc_to_hpc = make_lpc_to_hpc lpcs hpcs lpc_to_hpc in\n  let inefficient_is_nonyielding_lpc = make_is_nonyielding_pc lpcs is_nonyielding_lpc in\n  let inefficient_hpcs = array_to_list hpcs in\n  let inefficient_return_lpcs = make_return_pcs lpcs is_return_lpc in\n  let latomic_actions_array = list_to_array latomic_actions in\n  let hatomic_actions_array = list_to_array hatomic_actions in\n  list_to_array_implies_length_equivalent latomic_actions_array latomic_actions;\n  assert (list_len latomic_actions = array_len corresponding_hactions_info);\n  introduce forall laction_idx. laction_idx < list_len latomic_actions ==>\n               lactions_correspond_to_hactions_per_correspondence vs tds inv inefficient_lpc_to_hpc\n                 inefficient_return_lpcs hatomic_actions\n                 (list_index latomic_actions laction_idx)\n                 (array_index corresponding_hactions_info laction_idx)\n  with introduce _ ==> _\n  with _. (\n    let ltoh_info = array_index corresponding_hactions_info laction_idx in\n    list_to_array_implies_index_equivalent latomic_actions_array latomic_actions laction_idx;\n    assert (list_index latomic_actions laction_idx == array_index latomic_actions_array laction_idx);\n    let lactions = array_index latomic_actions_array laction_idx in\n    let pc_relation = efficient_lh_pc_relation lpc_to_hpc in\n    let pc_return_relation = efficient_lh_pc_return_relation lpc_to_hpc is_return_lpc in\n    assert (efficient_corresponding_hactions_info_correct_inner vs tds inv latomic_actions_array\n              hatomic_actions_array corresponding_hactions_info\n              lpc_indices_array hpc_indices_array lpc_to_hpc pc_relation pc_return_relation laction_idx);\n    let lpc_indices = array_index lpc_indices_array laction_idx in\n    let hactions_info = array_index corresponding_hactions_info laction_idx in\n    assert (efficient_lactions_correspond_to_hactions_per_correspondence vs tds inv lpc_to_hpc pc_relation\n              pc_return_relation hatomic_actions_array hpc_indices_array lactions lpc_indices\n              hactions_info);\n    let correspondence = array_index corresponding_hactions_info laction_idx in\n    efficient_corresponding_hactions_info_correct_inner_preservation vs tds inv latomic_actions hatomic_actions\n      lpcs hpcs lpc_to_hpc is_nonyielding_lpc is_return_lpc\n      corresponding_hactions_info lpc_indices_array hpc_indices_array correspondence\n      laction_idx\n  );\n  establish_lists_correspond_ubool_from_index_correspondence\n    (lactions_correspond_to_hactions_per_correspondence vs tds inv inefficient_lpc_to_hpc inefficient_return_lpcs\n       hatomic_actions)\n    latomic_actions (array_to_list corresponding_hactions_info)\n\n#pop-options\n\nlet efficient_var_hiding_witness_valid_implies_refinement\n  (latomic_prog: program_t (make_atomic_semantics armada_semantics))\n  (hatomic_prog: program_t (make_atomic_semantics armada_semantics))\n  (evw: efficient_var_hiding_witness_t)\n  (* see .fsti file for spec *) =\n  let vw: inefficient_var_hiding_witness_t = {\n    lprog = evw.lprog;\n    hprog = evw.hprog;\n    vs = evw.vs;\n    tds = evw.tds;\n    inv = evw.inv;\n    which_initializers_are_hidings = evw.which_initializers_are_hidings;\n    lpc_to_hpc = make_lpc_to_hpc evw.lpcs evw.hpcs evw.lpc_to_hpc;\n    return_lpcs = make_return_pcs evw.lpcs evw.is_return_lpc;\n    is_nonyielding_lpc = make_is_nonyielding_pc evw.lpcs evw.is_nonyielding_lpc;\n    is_nonyielding_hpc = make_is_nonyielding_pc evw.hpcs evw.is_nonyielding_hpc;\n    corresponding_hactions_info = array_to_list evw.corresponding_hactions_info;\n  } in\n  program_inits_match_except_global_variables_lemma evw.vs evw.lpcs evw.hpcs evw.lpc_to_hpc\n    evw.which_initializers_are_hidings evw.lprog evw.hprog evw.lprog_main_start_pc_index evw.hprog_main_start_pc_index;\n  assert (vw.lpc_to_hpc vw.lprog.main_start_pc = vw.hprog.main_start_pc);\n  assert (global_variables_unaddressed_in_initializers vw.vs vw.lprog.global_initializers);\n  assert (global_variables_unaddressed_in_initializers vw.vs vw.hprog.global_initializers);\n  assert (global_variables_unaddressed_in_initializers vw.vs vw.lprog.main_stack_initializers);\n  assert (global_variables_unaddressed_in_initializers vw.vs vw.hprog.main_stack_initializers);\n  assert (every_variable_appears_among_initializers vw.lprog.global_initializers vw.vs vw.tds);\n  return_pcs_unique_lemma evw.lpcs evw.hpcs evw.lpc_to_hpc evw.is_return_lpc;\n  assert (return_pcs_unique vw.lpc_to_hpc vw.return_lpcs);\n  each_action_list_consistent_with_is_nonyielding_pc_lemma evw.lpcs evw.is_nonyielding_lpc latomic_prog.actions\n    evw.lpc_indices_array;\n  assert (each_action_list_consistent_with_is_nonyielding_pc vw.is_nonyielding_lpc latomic_prog.actions);\n  each_action_list_consistent_with_is_nonyielding_pc_lemma evw.hpcs evw.is_nonyielding_hpc hatomic_prog.actions\n    evw.hpc_indices_array;\n  assert (each_action_list_consistent_with_is_nonyielding_pc vw.is_nonyielding_hpc hatomic_prog.actions);\n  assert (each_action_list_doesnt_internally_yield latomic_prog.actions);\n  assert (each_action_list_doesnt_internally_yield hatomic_prog.actions);\n  corresponding_hactions_info_correct_lemma evw.vs evw.tds evw.inv latomic_prog.actions hatomic_prog.actions\n    evw.lpcs evw.hpcs evw.lpc_to_hpc evw.is_nonyielding_lpc\n    evw.is_return_lpc evw.corresponding_hactions_info evw.lpc_indices_array evw.hpc_indices_array;\n  assert (lists_correspond_ubool\n           (lactions_correspond_to_hactions_per_correspondence vw.vs vw.tds vw.inv vw.lpc_to_hpc vw.return_lpcs\n              hatomic_prog.actions)\n           latomic_prog.actions vw.corresponding_hactions_info);\n  assert (inefficient_var_hiding_witness_valid latomic_prog hatomic_prog vw);\n  inefficient_var_hiding_witness_valid_implies_refinement latomic_prog hatomic_prog vw\n"
  },
  {
    "path": "experimental/lib/Strategies.VarHiding.Efficient.fsti",
    "content": "module Strategies.VarHiding.Efficient\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Threads\nopen Armada.Transition\nopen Armada.Type\nopen Spec.Behavior\nopen Spec.List\nopen Spec.Logic\nopen Spec.Ubool\nopen Strategies.ArmadaStatement.Propagate\nopen Strategies.ArmadaStatement.ThreadState\nopen Strategies.Atomic\nopen Strategies.Breaking\nopen Strategies.GlobalVars\nopen Strategies.GlobalVars.Permanent\nopen Strategies.GlobalVars.Statement\nopen Strategies.GlobalVars.VarHiding\nopen Strategies.GlobalVars.VarIntro\nopen Strategies.Invariant\nopen Strategies.Invariant.Armada.AtomicSubstep\nopen Strategies.Nonyielding\nopen Strategies.PCIndices\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\nopen Strategies.VarHiding.Defs\nopen Util.ImmutableArray\nopen Util.List\nopen Util.Nth\nopen Util.Range\nopen Util.Relation\n\nlet efficient_program_inits_match_except_global_variables\n  (vs: list var_id_t)\n  (lpcs: array_t pc_t)\n  (hpcs: array_t pc_t)\n  (lpc_to_hpc: array_t nat)\n  (which_initializers_are_hidings: list bool)\n  (lprog: Armada.Program.t)\n  (hprog: Armada.Program.t)\n  (lprog_main_start_pc: nat)\n  (hprog_main_start_pc: nat)\n  : GTot ubool =\n    lprog.main_method_id = hprog.main_method_id\n  /\\ array_nth lpc_to_hpc lprog_main_start_pc = Some hprog_main_start_pc\n  /\\ array_nth lpcs lprog_main_start_pc = Some lprog.main_start_pc\n  /\\ array_nth hpcs hprog_main_start_pc = Some hprog.main_start_pc\n  /\\ initializers_match_except_global_variables vs which_initializers_are_hidings\n       lprog.global_initializers hprog.global_initializers\n  /\\ lprog.main_stack_initializers == hprog.main_stack_initializers\n\nlet efficient_lpc_to_hpc_contains_valid_indices\n  (num_hpcs: nat)\n  (lpc_to_hpc: array_t nat)\n  : GTot bool =\n  for_all_array (fun (hidx: nat) -> hidx < num_hpcs) lpc_to_hpc\n\nlet efficient_lh_pc_relation (lpc_to_hpc: array_t nat) : GTot (relation_t nat nat) =\n  fun lidx hidx -> array_nth lpc_to_hpc lidx = Some hidx\n\nlet efficient_lh_pc_return_relation (lpc_to_hpc: array_t nat) (is_return_lpc: array_t bool) : GTot (relation_t nat nat) =\n  fun lidx hidx -> array_nth lpc_to_hpc lidx = Some hidx && array_nth is_return_lpc lidx = Some true\n\nlet rec efficient_lactions_all_hidden\n  (vs: list var_id_t)\n  (lpc_to_hpc: array_t nat)\n  (lstart_state: efficient_thread_state_t)\n  (lend_state: efficient_thread_state_t)\n  (lactions: list Armada.Action.t)\n  (lpc_indices: list statement_pc_indices_t)\n  : GTot ubool\n  (decreases lactions) =\n  match lactions, lpc_indices with\n  | [], [] -> lend_state = lstart_state\n  | first_laction :: remaining_lactions, first_lpc_indices :: remaining_lpc_indices ->\n         efficient_action_to_starting_thread_state first_lpc_indices = lstart_state\n      /\\ (match lstart_state, efficient_action_to_ending_thread_state first_laction first_lpc_indices with\n         | EfficientThreadStateAtPC lpc1, EfficientThreadStateAtPC lpc2 ->\n             array_nth lpc_to_hpc lpc1 = array_nth lpc_to_hpc lpc2\n         | _, _ -> False)\n      /\\ statement_updates_gvars vs first_laction.program_statement.statement\n      /\\ efficient_lactions_all_hidden vs lpc_to_hpc\n           (efficient_action_to_ending_thread_state first_laction first_lpc_indices)\n           lend_state remaining_lactions remaining_lpc_indices\n  | _, _ -> False\n\nlet efficient_laction_corresponds_to_haction\n  (vs: list var_id_t)\n  (pc_relation: relation_t nat nat)\n  (pc_return_relation: relation_t nat nat)\n  (laction: Armada.Action.t)\n  (haction: Armada.Action.t)\n  (lpc_indices: statement_pc_indices_t)\n  (hpc_indices: statement_pc_indices_t)\n  : GTot ubool =\n  let lps, hps = laction.program_statement, haction.program_statement in\n    statement_effect_independent_of_global_variables vs lps.statement\n  /\\ efficient_program_statements_match_per_pc_relation pc_relation pc_return_relation lps hps lpc_indices hpc_indices\n\nlet rec efficient_lactions_correspond_to_hactions\n  (vs: list var_id_t)\n  (pc_relation: relation_t nat nat)\n  (pc_return_relation: relation_t nat nat)\n  (lstart_state: efficient_thread_state_t)\n  (hstart_state: efficient_thread_state_t)\n  (lend_state: efficient_thread_state_t)\n  (hend_state: efficient_thread_state_t)\n  (which_actions_hidden: list bool)\n  (lactions: list Armada.Action.t)\n  (hactions: list Armada.Action.t)\n  (lpc_indices: list statement_pc_indices_t)\n  (hpc_indices: list statement_pc_indices_t)\n  : GTot ubool\n  (decreases lactions) =\n  match which_actions_hidden, lactions, hactions, lpc_indices, hpc_indices with\n  | [], [], [], [], [] ->\n        lend_state = lstart_state\n      /\\ hend_state = hstart_state\n  | false :: remaining_which_actions_hidden, first_laction :: remaining_lactions, first_haction :: remaining_hactions,\n      first_lpc_indices :: remaining_lpc_indices, first_hpc_indices :: remaining_hpc_indices ->\n        efficient_laction_corresponds_to_haction vs pc_relation pc_return_relation first_laction first_haction\n          first_lpc_indices first_hpc_indices\n      /\\ efficient_action_to_starting_thread_state first_lpc_indices = lstart_state\n      /\\ efficient_action_to_starting_thread_state first_hpc_indices = hstart_state\n      /\\ EfficientThreadStateAtPC? lstart_state\n      /\\ EfficientThreadStateAtPC? hstart_state\n      /\\ efficient_thread_states_match_per_pc_relation pc_relation lstart_state hstart_state\n      /\\ efficient_thread_states_match_per_pc_relation pc_relation\n          (efficient_action_to_ending_thread_state first_laction first_lpc_indices)\n          (efficient_action_to_ending_thread_state first_haction first_hpc_indices)\n      /\\ efficient_lactions_correspond_to_hactions vs pc_relation pc_return_relation\n          (efficient_action_to_ending_thread_state first_laction first_lpc_indices)\n          (efficient_action_to_ending_thread_state first_haction first_hpc_indices)\n          lend_state hend_state remaining_which_actions_hidden remaining_lactions remaining_hactions\n          remaining_lpc_indices remaining_hpc_indices\n  | true :: remaining_which_actions_hidden, first_laction :: remaining_lactions, _,\n      first_lpc_indices :: remaining_lpc_indices, _ ->\n        efficient_action_to_starting_thread_state first_lpc_indices = lstart_state\n      /\\ EfficientThreadStateAtPC? lstart_state\n      /\\ efficient_thread_states_match_per_pc_relation pc_relation lstart_state hstart_state\n      /\\ efficient_thread_states_match_per_pc_relation pc_relation\n          (efficient_action_to_ending_thread_state first_laction first_lpc_indices) hstart_state\n      /\\ statement_updates_gvars vs first_laction.program_statement.statement\n      /\\ efficient_lactions_correspond_to_hactions vs pc_relation pc_return_relation\n           (efficient_action_to_ending_thread_state first_laction first_lpc_indices) hstart_state lend_state hend_state\n           remaining_which_actions_hidden remaining_lactions hactions remaining_lpc_indices hpc_indices\n  | _, _, _, _, _ -> False\n\nlet efficient_lactions_correspond_to_hactions_per_correspondence\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (inv: invariant_t Armada.State.t)\n  (lpc_to_hpc: array_t nat)\n  (pc_relation: relation_t nat nat)\n  (pc_return_relation: relation_t nat nat)\n  (hatomic_actions_array: array_t (list Armada.Action.t))\n  (hpc_indices_array: array_t (list statement_pc_indices_t))\n  (lactions: list Armada.Action.t)\n  (lpc_indices: list statement_pc_indices_t)\n  (correspondence: ltoh_correspondence_t vs tds inv)\n  : GTot ubool =\n  match correspondence with\n  | CorrespondenceHidden ->\n        Cons? lactions\n      /\\ Cons? lpc_indices\n      /\\ actions_start_atomic_block lactions = actions_end_atomic_block lactions\n      /\\ (let lstart_state = efficient_action_to_starting_thread_state (Cons?.hd lpc_indices) in\n         let lend_state = efficient_actions_to_ending_thread_state lactions lpc_indices in\n         efficient_lactions_all_hidden vs lpc_to_hpc lstart_state lend_state lactions lpc_indices)\n  | CorrespondencePropagate hidx ->\n        Cons? lactions\n      /\\ (Cons?.hd lactions).program_statement == propagate_program_statement\n      /\\ array_nth hatomic_actions_array hidx == Some lactions\n  | CorrespondenceNormal hidx which_actions_hidden ->\n      (match array_nth hatomic_actions_array hidx, array_nth hpc_indices_array hidx with\n       | Some hactions, Some hpc_indices ->\n             Cons? lactions\n           /\\ Cons? lpc_indices\n           /\\ Cons? hactions\n           /\\ Cons? hpc_indices\n           /\\ do_actions_start_and_end_atomic_block lactions = do_actions_start_and_end_atomic_block hactions\n           /\\ (let lstart_state = efficient_action_to_starting_thread_state (Cons?.hd lpc_indices) in\n              let lend_state = efficient_actions_to_ending_thread_state lactions lpc_indices in\n              let hstart_state = efficient_action_to_starting_thread_state (Cons?.hd hpc_indices) in\n              let hend_state = efficient_actions_to_ending_thread_state hactions hpc_indices in\n              efficient_lactions_correspond_to_hactions vs pc_relation pc_return_relation lstart_state hstart_state\n               lend_state hend_state which_actions_hidden lactions hactions lpc_indices hpc_indices)\n       | _, _ -> False)\n  | CorrespondenceImpossibleConstantAssignmentFailure ->\n        Cons? lactions\n      /\\ ~(PropagateWriteMessageStatement? (Cons?.hd lactions).program_statement.statement)\n      /\\ lactions_fail_final_statement_updating_gvars_using_constant vs tds lactions\n  | CorrespondenceImpossibleStatementFailure ps proof ->\n        Cons? lactions\n      /\\ ~(PropagateWriteMessageStatement? (Cons?.hd lactions).program_statement.statement)\n      /\\ lactions_fail_specific_final_statement ps lactions\n\nlet efficient_return_lpcs_unique_inner2\n  (lpc_to_hpc: array_t nat)\n  (is_return_lpc: array_t bool)\n  (lpc1: nat)\n  (lpc2: nat)\n  : GTot bool =\n   implies (   array_nth is_return_lpc lpc2 = Some true\n            && array_nth lpc_to_hpc lpc1 = array_nth lpc_to_hpc lpc2)\n           (lpc1 = lpc2)\n\nlet efficient_return_lpcs_unique_inner1\n  (num_lpcs: nat)\n  (lpc_to_hpc: array_t nat)\n  (is_return_lpc: array_t bool)\n  (lpc1: nat)\n  : GTot bool =\n  implies (array_nth is_return_lpc lpc1 = Some true)\n          (for_all_range num_lpcs (efficient_return_lpcs_unique_inner2 lpc_to_hpc is_return_lpc lpc1))\n\nlet efficient_return_lpcs_unique\n  (num_lpcs: nat)\n  (lpc_to_hpc: array_t nat)\n  (is_return_lpc: array_t bool)\n  : GTot bool =\n  for_all_range num_lpcs (efficient_return_lpcs_unique_inner1 num_lpcs lpc_to_hpc is_return_lpc)\n\nlet efficient_corresponding_hactions_info_correct_inner\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (inv: invariant_t Armada.State.t)\n  (lprog_actions_array: array_t (list Armada.Action.t))\n  (hprog_actions_array: array_t (list Armada.Action.t))\n  (corresponding_hactions_info: array_t (ltoh_correspondence_t vs tds inv))\n  (lpc_indices_array: array_t (list statement_pc_indices_t))\n  (hpc_indices_array: array_t (list statement_pc_indices_t))\n  (lpc_to_hpc: array_t nat)\n  (pc_relation: relation_t nat nat)\n  (pc_return_relation: relation_t nat nat)\n  (idx: nat)\n  : GTot ubool =\n  match array_nth lprog_actions_array idx, array_nth lpc_indices_array idx,\n          array_nth corresponding_hactions_info idx with\n  | Some lactions, Some lpc_indices, Some hactions_info ->\n      efficient_lactions_correspond_to_hactions_per_correspondence vs tds inv lpc_to_hpc pc_relation pc_return_relation\n        hprog_actions_array hpc_indices_array lactions lpc_indices hactions_info\n  | _, _, _ -> False\n\nlet efficient_corresponding_hactions_info_correct\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (inv: invariant_t Armada.State.t)\n  (lprog_actions_array: array_t (list Armada.Action.t))\n  (hprog_actions_array: array_t (list Armada.Action.t))\n  (lpc_to_hpc: array_t nat)\n  (is_return_lpc: array_t bool)\n  (corresponding_hactions_info: array_t (ltoh_correspondence_t vs tds inv))\n  (lpc_indices_array: array_t (list statement_pc_indices_t))\n  (hpc_indices_array: array_t (list statement_pc_indices_t))\n  : GTot ubool =\n  let pc_relation = efficient_lh_pc_relation lpc_to_hpc in\n  let pc_return_relation = efficient_lh_pc_return_relation lpc_to_hpc is_return_lpc in\n  for_all_range_ubool (array_len lprog_actions_array)\n    (efficient_corresponding_hactions_info_correct_inner vs tds inv lprog_actions_array hprog_actions_array\n       corresponding_hactions_info lpc_indices_array hpc_indices_array lpc_to_hpc pc_relation\n       pc_return_relation)\n\nnoeq type efficient_var_hiding_witness_t = {\n  lprog: Armada.Program.t;\n  hprog: Armada.Program.t;\n  lprog_actions_array: array_t (list Armada.Action.t);\n  hprog_actions_array: array_t (list Armada.Action.t);\n  vs: list var_id_t;\n  tds: list object_td_t;\n  inv: invariant_t Armada.State.t;\n  which_initializers_are_hidings: list bool;\n  lpcs: array_t pc_t;\n  hpcs: array_t pc_t;\n  lpc_to_hpc: array_t nat;\n  is_return_lpc: array_t bool;\n  is_nonyielding_lpc: array_t bool;\n  is_nonyielding_hpc: array_t bool;\n  corresponding_hactions_info: array_t (ltoh_correspondence_t vs tds inv);\n  lprog_main_start_pc_index: nat;\n  hprog_main_start_pc_index: nat;\n  lpc_indices_array: array_t (list statement_pc_indices_t);\n  hpc_indices_array: array_t (list statement_pc_indices_t);\n}\n\nlet efficient_var_hiding_witness_valid\n  (latomic_prog: program_t (make_atomic_semantics armada_semantics))\n  (hatomic_prog: program_t (make_atomic_semantics armada_semantics))\n  (vw: efficient_var_hiding_witness_t)\n  : GTot ubool =\n    array_len vw.lpc_to_hpc = array_len vw.lpcs\n  /\\ array_len vw.is_return_lpc = array_len vw.lpcs\n  /\\ array_len vw.is_nonyielding_lpc = array_len vw.lpcs\n  /\\ array_len vw.is_nonyielding_hpc = array_len vw.hpcs\n  /\\ array_len vw.corresponding_hactions_info = array_len vw.lprog_actions_array\n  /\\ array_len vw.lpc_indices_array = array_len vw.lprog_actions_array\n  /\\ array_len vw.hpc_indices_array = array_len vw.hprog_actions_array\n  /\\ array_elements_unique vw.lpcs\n  /\\ array_elements_unique vw.hpcs\n  /\\ efficient_program_inits_match_except_global_variables vw.vs vw.lpcs vw.hpcs vw.lpc_to_hpc\n      vw.which_initializers_are_hidings vw.lprog vw.hprog vw.lprog_main_start_pc_index vw.hprog_main_start_pc_index\n  /\\ global_variables_unaddressed_in_initializers vw.vs vw.lprog.global_initializers\n  /\\ global_variables_unaddressed_in_initializers vw.vs vw.hprog.global_initializers\n  /\\ global_variables_unaddressed_in_initializers vw.vs vw.lprog.main_stack_initializers\n  /\\ global_variables_unaddressed_in_initializers vw.vs vw.hprog.main_stack_initializers\n  /\\ every_variable_appears_among_initializers vw.lprog.global_initializers vw.vs vw.tds\n  /\\ actions_array_corresponds_to_statement_pc_indices_array vw.lpcs vw.lprog_actions_array vw.lpc_indices_array\n  /\\ actions_array_corresponds_to_statement_pc_indices_array vw.hpcs vw.hprog_actions_array vw.hpc_indices_array\n  /\\ efficient_lpc_to_hpc_contains_valid_indices (array_len vw.hpcs) vw.lpc_to_hpc\n  /\\ efficient_return_lpcs_unique (array_len vw.lpcs) vw.lpc_to_hpc vw.is_return_lpc\n  /\\ efficient_each_action_list_consistent_with_is_nonyielding_pc vw.is_nonyielding_lpc vw.lprog_actions_array\n      vw.lpc_indices_array\n  /\\ efficient_each_action_list_consistent_with_is_nonyielding_pc vw.is_nonyielding_hpc vw.hprog_actions_array\n      vw.hpc_indices_array\n  /\\ each_action_list_doesnt_internally_yield latomic_prog.actions\n  /\\ each_action_list_doesnt_internally_yield hatomic_prog.actions\n  /\\ each_action_list_ends_atomic_block_if_necessary hatomic_prog.actions\n  /\\ efficient_corresponding_hactions_info_correct vw.vs vw.tds vw.inv vw.lprog_actions_array vw.hprog_actions_array\n      vw.lpc_to_hpc vw.is_return_lpc vw.corresponding_hactions_info vw.lpc_indices_array vw.hpc_indices_array\n\nval efficient_var_hiding_witness_valid_implies_refinement\n  (latomic_prog: program_t (make_atomic_semantics armada_semantics))\n  (hatomic_prog: program_t (make_atomic_semantics armada_semantics))\n  (evw: efficient_var_hiding_witness_t)\n  : Lemma (requires   efficient_var_hiding_witness_valid latomic_prog hatomic_prog evw\n                    /\\ is_armada_substep_invariant latomic_prog evw.inv\n                    /\\ latomic_prog.init_f == init_program evw.lprog\n                    /\\ hatomic_prog.init_f == init_program evw.hprog\n                    /\\ evw.lprog_actions_array == list_to_array latomic_prog.actions\n                    /\\ evw.hprog_actions_array == list_to_array hatomic_prog.actions)\n          (ensures (spec_refines_spec\n                      (semantics_to_spec (make_atomic_semantics armada_semantics) latomic_prog)\n                      (semantics_to_spec (make_atomic_semantics armada_semantics) hatomic_prog)\n                      refinement_requirement))\n"
  },
  {
    "path": "experimental/lib/Strategies.VarHiding.Helpers.fst",
    "content": "module Strategies.VarHiding.Helpers\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Computation\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Program\nopen Armada.State\nopen Armada.Step\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Threads\nopen Armada.Transition\nopen Armada.Type\nopen FStar.Sequence.Ambient\nopen FStar.Sequence.Base\nopen FStar.WellFoundedRelation\nopen Spec.Behavior\nopen Spec.List\nopen Spec.Logic\nopen Spec.Ubool\nopen Strategies.ArmadaInvariant.RootsMatch\nopen Strategies.ArmadaInvariant.PositionsValid\nopen Strategies.ArmadaInvariant.UnstartedThreads\nopen Strategies.ArmadaStatement.Propagate\nopen Strategies.ArmadaStatement.Status\nopen Strategies.ArmadaStatement.ThreadState\nopen Strategies.Atomic\nopen Strategies.GlobalVars\nopen Strategies.GlobalVars.Init\nopen Strategies.GlobalVars.Permanent\nopen Strategies.GlobalVars.Statement\nopen Strategies.GlobalVars.Types\nopen Strategies.GlobalVars.Unaddressed\nopen Strategies.GlobalVars.Util\nopen Strategies.GlobalVars.VarIntro\nopen Strategies.Lift.Generic\nopen Strategies.Invariant\nopen Strategies.PCRelation\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\nopen Strategies.VarHiding.Defs\nopen Util.List\nopen Util.Nth\nopen Util.Seq\n\n/// Definitions\n\nlet return_pcs_unique_proof_t (lpc_to_hpc: pc_t -> GTot pc_t) (return_lpcs: list pc_t) =\n  unit -> Lemma (return_pcs_unique lpc_to_hpc return_lpcs)\n\nlet var_hiding_pc_relation\n  (lpc_to_hpc: pc_t -> GTot pc_t)\n  (return_lpcs: list pc_t)\n  (return_pcs_unique_proof: return_pcs_unique_proof_t lpc_to_hpc return_lpcs)\n  : pc_relation_t =\n  return_pcs_unique_proof ();\n  let return_relation = (fun lpc hpc -> list_contains lpc return_lpcs && lpc_to_hpc lpc = hpc) in\n  {\n    relation = (fun lpc hpc -> lpc_to_hpc lpc = hpc);\n    return_relation = return_relation;\n  }\n\nlet rec compute_hsteps_from_hactions\n  (hactions: list Armada.Action.t)\n  : Ghost (list Armada.Step.t)\n    (requires True)\n    (ensures fun hsteps -> map_ghost armada_step_to_action hsteps == hactions) =\n  match hactions with\n  | [] -> []\n  | first_haction :: remaining_hactions ->\n      let first_hstep = { nd = []; action = first_haction } in\n      first_hstep :: compute_hsteps_from_hactions remaining_hactions\n\n/// Correspondence between lsteps and hsteps\n\nlet lstep_corresponds_to_hstep\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (lstep: Armada.Step.t)\n  (hstep: Armada.Step.t)\n  : GTot ubool =\n  let lps, hps = lstep.action.program_statement, hstep.action.program_statement in\n    lstep.nd == hstep.nd\n  /\\ statement_effect_independent_of_global_variables vs lps.statement\n  /\\ statements_match_per_pc_relation pc_relation.relation pc_relation.return_relation lps.statement hps.statement\n  /\\ (match lps.end_pc, hps.end_pc with\n     | Some lpc, Some hpc ->\n           pc_relation.relation lpc hpc\n         /\\ (ReturnStatement? lps.statement ==> pc_relation.return_relation lpc hpc)\n     | None, None -> True\n     | _, _ -> False)\n\nlet rec lsteps_correspond_to_hsteps\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (lstart_state: thread_state_t)\n  (hstart_state: thread_state_t)\n  (lend_state: thread_state_t)\n  (hend_state: thread_state_t)\n  (which_actions_hidden: list bool)\n  (lsteps: list Armada.Step.t)\n  (hsteps: list Armada.Step.t)\n  : GTot ubool\n  (decreases lsteps) =\n  match which_actions_hidden, lsteps, hsteps with\n  | [], [], [] -> True\n  | false :: remaining_which_actions_hidden, first_lstep :: remaining_lsteps, first_hstep :: remaining_hsteps ->\n      let first_lstep: Armada.Step.t = first_lstep in\n      let first_hstep: Armada.Step.t = first_hstep in\n         lstep_corresponds_to_hstep vs pc_relation first_lstep first_hstep\n      /\\ action_to_starting_thread_state first_lstep.action = lstart_state\n      /\\ action_to_starting_thread_state first_hstep.action = hstart_state\n      /\\ ThreadStateAtPC? lstart_state\n      /\\ ThreadStateAtPC? hstart_state\n      /\\ thread_states_match_per_pc_relation pc_relation.relation lstart_state hstart_state\n      /\\ thread_states_match_per_pc_relation pc_relation.relation (action_to_ending_thread_state first_lstep.action)\n           (action_to_ending_thread_state first_hstep.action)\n      /\\ lsteps_correspond_to_hsteps vs pc_relation\n           (action_to_ending_thread_state first_lstep.action) (action_to_ending_thread_state first_hstep.action)\n           lend_state hend_state remaining_which_actions_hidden remaining_lsteps remaining_hsteps\n  | true :: remaining_which_actions_hidden, first_lstep :: remaining_lsteps, _ ->\n         action_to_starting_thread_state first_lstep.action = lstart_state\n      /\\ ThreadStateAtPC? lstart_state\n      /\\ thread_states_match_per_pc_relation pc_relation.relation lstart_state hstart_state\n      /\\ thread_states_match_per_pc_relation pc_relation.relation\n           (action_to_ending_thread_state first_lstep.action) hstart_state\n      /\\ statement_updates_gvars vs first_lstep.action.program_statement.statement\n      /\\ lsteps_correspond_to_hsteps vs pc_relation (action_to_ending_thread_state first_lstep.action)\n           hstart_state lend_state hend_state remaining_which_actions_hidden remaining_lsteps hsteps\n  | _, _, _ -> False\n\n#push-options \"--split_queries always\"\nlet rec compute_hsteps_from_lsteps\n  (vs: list var_id_t)\n  (lpc_to_hpc: pc_t -> GTot pc_t)\n  (return_lpcs: list pc_t)\n  (return_pcs_unique_proof: return_pcs_unique_proof_t lpc_to_hpc return_lpcs)\n  (lstart_state: thread_state_t)\n  (hstart_state: thread_state_t)\n  (lend_state: thread_state_t)\n  (hend_state: thread_state_t)\n  (which_actions_hidden: list bool)\n  (lactions: list Armada.Action.t)\n  (hactions: list Armada.Action.t)\n  (lsteps: list Armada.Step.t)\n  : Ghost (list Armada.Step.t)\n    (requires   lactions == map_ghost armada_step_to_action lsteps\n              /\\ lactions_correspond_to_hactions vs lpc_to_hpc return_lpcs lstart_state hstart_state\n                  lend_state hend_state which_actions_hidden lactions hactions)\n    (ensures  fun hsteps -> (let pc_relation = var_hiding_pc_relation lpc_to_hpc return_lpcs return_pcs_unique_proof in\n                            lsteps_correspond_to_hsteps vs pc_relation lstart_state hstart_state\n                              lend_state hend_state which_actions_hidden lsteps hsteps\n                          /\\ hactions == map_ghost armada_step_to_action hsteps))\n    (decreases lactions) =\n  let pc_relation = var_hiding_pc_relation lpc_to_hpc return_lpcs return_pcs_unique_proof in\n  match which_actions_hidden, lactions, hactions, lsteps with\n  | [], [], [], [] -> []\n  | false :: remaining_which_actions_hidden, first_laction :: remaining_lactions, first_haction :: remaining_hactions,\n      first_lstep :: remaining_lsteps ->\n      let first_lstep: Armada.Step.t = first_lstep in\n      let hstep = { nd = first_lstep.nd; action = first_haction } in\n      let lnext_start_state = action_to_ending_thread_state first_laction in\n      let hnext_start_state = action_to_ending_thread_state first_haction in\n      let hsteps' = compute_hsteps_from_lsteps vs lpc_to_hpc return_lpcs return_pcs_unique_proof\n                      lnext_start_state hnext_start_state lend_state hend_state remaining_which_actions_hidden\n                      remaining_lactions remaining_hactions remaining_lsteps in\n      let hsteps = hstep :: hsteps' in\n      assert (lsteps_correspond_to_hsteps vs pc_relation lstart_state hstart_state lend_state hend_state\n                which_actions_hidden lsteps hsteps);\n      hsteps\n  | true :: remaining_which_actions_hidden, first_laction :: remaining_lactions, _, first_lstep :: remaining_lsteps ->\n      let lnext_start_state = action_to_ending_thread_state first_laction in\n      let hsteps = compute_hsteps_from_lsteps vs lpc_to_hpc return_lpcs return_pcs_unique_proof\n                     lnext_start_state hstart_state lend_state hend_state remaining_which_actions_hidden\n                     remaining_lactions hactions remaining_lsteps in\n      assert (lsteps_correspond_to_hsteps vs pc_relation lstart_state hstart_state lend_state hend_state\n                which_actions_hidden lsteps hsteps);\n      hsteps\n  | _, _, _, _ -> false_elim ()\n#pop-options\n\nlet lstep_corresponds_to_hstep_clarifier\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (lstep: Armada.Step.t)\n  (hstep: Armada.Step.t)\n  : Lemma (requires lstep_corresponds_to_hstep vs pc_relation lstep hstep)\n          (ensures  (let lps, hps = lstep.action.program_statement, hstep.action.program_statement in\n                     match lps.end_pc, hps.end_pc with\n                     | Some lpc, Some hpc ->\n                           pc_relation.relation lpc hpc\n                         /\\ (ReturnStatement? lps.statement ==> pc_relation.return_relation lpc hpc)\n                     | None, None -> True\n                     | _, _ -> False)) =\n  ()\n\nlet rec lactions_all_hidden_implies_not_propagate\n  (vs: list var_id_t)\n  (lpc_to_hpc: pc_t -> GTot pc_t)\n  (lstart_state: thread_state_t)\n  (lend_state: thread_state_t)\n  (lactions: list Armada.Action.t)\n  : Lemma (requires   lactions_all_hidden vs lpc_to_hpc lstart_state lend_state lactions\n                    /\\ Cons? lactions)\n          (ensures  ~(PropagateWriteMessageStatement? (Cons?.hd lactions).program_statement.statement))\n          (decreases lactions) =\n  match lactions with\n  | [] -> ()\n  | first_laction :: remaining_lactions ->\n      if Cons? remaining_lactions then\n        lactions_all_hidden_implies_not_propagate vs lpc_to_hpc\n          (action_to_ending_thread_state first_laction) lend_state remaining_lactions\n      else\n        ()\n\nlet rec lactions_correspond_to_hactions_implies_not_propagate\n  (vs: list var_id_t)\n  (lpc_to_hpc: pc_t -> GTot pc_t)\n  (return_lpcs: list pc_t)\n  (lstart_state: thread_state_t)\n  (hstart_state: thread_state_t)\n  (lend_state: thread_state_t)\n  (hend_state: thread_state_t)\n  (which_actions_hidden: list bool)\n  (lactions: list Armada.Action.t)\n  (hactions: list Armada.Action.t)\n  : Lemma (requires lactions_correspond_to_hactions vs lpc_to_hpc return_lpcs lstart_state hstart_state\n                      lend_state hend_state which_actions_hidden lactions hactions\n                    /\\ Cons? lactions)\n          (ensures  ~(PropagateWriteMessageStatement? (Cons?.hd lactions).program_statement.statement))\n          (decreases lactions) =\n  match which_actions_hidden, lactions, hactions with\n  | [], [], [] -> ()\n  | false :: remaining_which_actions_hidden, first_laction :: remaining_lactions, first_haction :: remaining_hactions ->\n      assert (laction_corresponds_to_haction vs lpc_to_hpc return_lpcs first_laction first_haction);\n      assert (~(PropagateWriteMessageStatement? first_laction.program_statement.statement))\n  | true :: remaining_which_actions_hidden, first_laction :: remaining_lactions, _ ->\n      if Cons? remaining_lactions then\n        lactions_correspond_to_hactions_implies_not_propagate vs lpc_to_hpc return_lpcs\n          (action_to_ending_thread_state first_laction) hstart_state lend_state hend_state\n          remaining_which_actions_hidden remaining_lactions hactions\n      else\n        ()\n  | _, _, _ -> ()\n\nlet lsteps_correspond_to_hsteps_implies_first_lstep_matches_lstart_state\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (lstart_state: thread_state_t)\n  (hstart_state: thread_state_t)\n  (lend_state: thread_state_t)\n  (hend_state: thread_state_t)\n  (which_actions_hidden: list bool)\n  (lsteps: list Armada.Step.t)\n  (hsteps: list Armada.Step.t)\n  : Lemma (requires   Cons? lsteps\n                    /\\ lsteps_correspond_to_hsteps vs pc_relation lstart_state hstart_state lend_state hend_state\n                        which_actions_hidden lsteps hsteps)\n          (ensures    lstart_state = action_to_starting_thread_state (Cons?.hd lsteps).action\n                    /\\ ThreadStateAtPC? lstart_state)\n          (decreases lsteps) =\n  ()\n\n/// Propagate\n\nlet rec propagate_maintains_all_gvars_have_types\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (s: Armada.State.t)\n  : Lemma (requires   all_gvars_have_types s.mem vs tds\n                    /\\ (ComputationProduces? (propagate_write_message_statement_computation actor nd s)))\n          (ensures  (let s' = ComputationProduces?.result (propagate_write_message_statement_computation actor nd s) in\n                     all_gvars_have_types s'.mem vs tds)) =\n  match vs, tds with\n  | [], [] -> ()\n  | first_v :: remaining_vs, first_td :: remaining_tds ->\n      propagate_write_message_statement_computation_maintains_gvar_has_type first_v first_td actor nd s;\n      propagate_maintains_all_gvars_have_types remaining_vs remaining_tds actor nd s\n\n/// Maintaining states_match_except_global_variables\n\nlet update_thread_pcs_in_states_maintains_states_match_except_gvars\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  (end_pc1: option pc_t)\n  (end_pc2: option pc_t)\n  : Lemma (requires   states_match_except_global_variables vs pc_relation s1 s2\n                    /\\ optional_pcs_match_per_pc_relation pc_relation end_pc1 end_pc2)\n          (ensures  (let s1' = update_thread_pc_in_state s1 actor end_pc1 in\n                     let s2' = update_thread_pc_in_state s2 actor end_pc2 in\n                     states_match_except_global_variables vs pc_relation s1' s2')) =\n  ()\n\nlet update_thread_pc_in_state_maintains_states_match_except_gvars\n  (vs: list var_id_t)\n  (pc_relation: pc_relation_t)\n  (actor: tid_t)\n  (s1: Armada.State.t)\n  (s2: Armada.State.t)\n  (end_pc1: option pc_t)\n  : Lemma (requires   states_match_except_global_variables vs pc_relation s1 s2\n                    /\\ Some? end_pc1\n                    /\\ pc_relation.relation (Some?.v end_pc1) (s2.threads actor).pc)\n          (ensures  (let s1' = update_thread_pc_in_state s1 actor end_pc1 in\n                     states_match_except_global_variables vs pc_relation s1' s2)) =\n  ()\n"
  },
  {
    "path": "experimental/lib/Strategies.VarHiding.Inefficient.fst",
    "content": "module Strategies.VarHiding.Inefficient\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Threads\nopen Armada.Transition\nopen Armada.Type\nopen Spec.Behavior\nopen Spec.List\nopen Spec.Logic\nopen Spec.Ubool\nopen Strategies.ArmadaStatement.ThreadState\nopen Strategies.Atomic\nopen Strategies.GlobalVars\nopen Strategies.GlobalVars.Permanent\nopen Strategies.GlobalVars.Statement\nopen Strategies.GlobalVars.VarIntro\nopen Strategies.Invariant\nopen Strategies.Nonyielding\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\nopen Strategies.VarHiding.Defs\nopen Strategies.VarHiding.Relation\nopen Util.List\nopen Util.Nth\nopen Util.Relation\n\nlet inefficient_var_hiding_witness_valid_implies_refinement\n  (latomic_prog: program_t (make_atomic_semantics armada_semantics))\n  (hatomic_prog: program_t (make_atomic_semantics armada_semantics))\n  (vw: inefficient_var_hiding_witness_t)\n  (* see .fsti file for spec *) =\n  let vr: var_hiding_relation_t = {\n    lprog = vw.lprog;\n    hprog = vw.hprog;\n    latomic_prog = latomic_prog;\n    hatomic_prog = hatomic_prog;\n    vs = vw.vs;\n    tds = vw.tds;\n    inv = vw.inv;\n    which_initializers_are_hidings = vw.which_initializers_are_hidings;\n    lpc_to_hpc = vw.lpc_to_hpc;\n    return_lpcs = vw.return_lpcs;\n    is_nonyielding_lpc = vw.is_nonyielding_lpc;\n    is_nonyielding_hpc = vw.is_nonyielding_hpc;\n    corresponding_hactions_info = vw.corresponding_hactions_info;\n    inv_is_substep_invariant_proof = (fun _ -> ());\n    atomic_inits_match_regular_inits_proof = (fun _ -> ());\n    program_inits_match_except_global_variables_proof = (fun _ -> ());\n    initial_pcs_correspond_proof = (fun _ -> ());\n    global_variables_unaddressed_in_initializers_proof = (fun _ -> ());\n    all_introduced_global_variables_initialized_proof = (fun _ -> ());\n    return_pcs_unique_proof = (fun _ -> ());\n    lactions_consistent_with_is_nonyielding_pc_proof = (fun _ -> ());\n    hactions_consistent_with_is_nonyielding_pc_proof = (fun _ -> ());\n    each_laction_doesnt_internally_yield_proof = (fun _ -> ());\n    each_haction_doesnt_internally_yield_proof = (fun _ -> ());\n    each_haction_ends_atomic_block_if_necessary_proof = (fun _ -> ());\n    corresponding_hactions_correspond_proof = (fun _ -> ());\n  } in\n  var_hiding_relation_implies_refinement vr\n"
  },
  {
    "path": "experimental/lib/Strategies.VarHiding.Inefficient.fsti",
    "content": "module Strategies.VarHiding.Inefficient\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Threads\nopen Armada.Transition\nopen Armada.Type\nopen Spec.Behavior\nopen Spec.List\nopen Spec.Logic\nopen Spec.Ubool\nopen Strategies.ArmadaStatement.ThreadState\nopen Strategies.Atomic\nopen Strategies.GlobalVars\nopen Strategies.GlobalVars.Permanent\nopen Strategies.GlobalVars.Statement\nopen Strategies.GlobalVars.VarIntro\nopen Strategies.Invariant\nopen Strategies.Invariant.Armada.AtomicSubstep\nopen Strategies.Nonyielding\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\nopen Strategies.VarHiding.Defs\nopen Util.List\nopen Util.Nth\nopen Util.Relation\n\nnoeq type inefficient_var_hiding_witness_t = {\n  lprog: Armada.Program.t;\n  hprog: Armada.Program.t;\n  vs: list var_id_t;\n  tds: list object_td_t;\n  inv: invariant_t Armada.State.t;\n  which_initializers_are_hidings: list bool;\n  lpc_to_hpc: pc_t -> GTot pc_t;\n  return_lpcs: list pc_t;\n  is_nonyielding_lpc: pc_t -> GTot bool;\n  is_nonyielding_hpc: pc_t -> GTot bool;\n  corresponding_hactions_info: list (ltoh_correspondence_t vs tds inv);\n}\n\nlet inefficient_var_hiding_witness_valid\n  (latomic_prog: program_t (make_atomic_semantics armada_semantics))\n  (hatomic_prog: program_t (make_atomic_semantics armada_semantics))\n  (vw: inefficient_var_hiding_witness_t)\n  : GTot ubool =\n    program_inits_match_except_global_variables vw.vs vw.lpc_to_hpc vw.which_initializers_are_hidings vw.lprog vw.hprog\n  /\\ vw.lpc_to_hpc vw.lprog.main_start_pc = vw.hprog.main_start_pc\n  /\\ global_variables_unaddressed_in_initializers vw.vs vw.lprog.global_initializers\n  /\\ global_variables_unaddressed_in_initializers vw.vs vw.hprog.global_initializers\n  /\\ global_variables_unaddressed_in_initializers vw.vs vw.lprog.main_stack_initializers\n  /\\ global_variables_unaddressed_in_initializers vw.vs vw.hprog.main_stack_initializers\n  /\\ every_variable_appears_among_initializers vw.lprog.global_initializers vw.vs vw.tds\n  /\\ return_pcs_unique vw.lpc_to_hpc vw.return_lpcs\n  /\\ each_action_list_consistent_with_is_nonyielding_pc vw.is_nonyielding_lpc latomic_prog.actions\n  /\\ each_action_list_consistent_with_is_nonyielding_pc vw.is_nonyielding_hpc hatomic_prog.actions\n  /\\ each_action_list_doesnt_internally_yield latomic_prog.actions\n  /\\ each_action_list_doesnt_internally_yield hatomic_prog.actions\n  /\\ each_action_list_ends_atomic_block_if_necessary hatomic_prog.actions\n  /\\ lists_correspond_ubool\n       (lactions_correspond_to_hactions_per_correspondence vw.vs vw.tds vw.inv vw.lpc_to_hpc vw.return_lpcs\n          hatomic_prog.actions)\n       latomic_prog.actions vw.corresponding_hactions_info\n\nval inefficient_var_hiding_witness_valid_implies_refinement\n  (latomic_prog: program_t (make_atomic_semantics armada_semantics))\n  (hatomic_prog: program_t (make_atomic_semantics armada_semantics))\n  (vw: inefficient_var_hiding_witness_t)\n  : Lemma (requires   inefficient_var_hiding_witness_valid latomic_prog hatomic_prog vw\n                    /\\ is_armada_substep_invariant latomic_prog vw.inv\n                    /\\ latomic_prog.init_f == init_program vw.lprog\n                    /\\ hatomic_prog.init_f == init_program vw.hprog)\n          (ensures (spec_refines_spec\n                      (semantics_to_spec (make_atomic_semantics armada_semantics) latomic_prog)\n                      (semantics_to_spec (make_atomic_semantics armada_semantics) hatomic_prog)\n                      refinement_requirement))\n"
  },
  {
    "path": "experimental/lib/Strategies.VarHiding.Initialization.fst",
    "content": "module Strategies.VarHiding.Initialization\n\nopen Armada.Base\nopen Armada.Computation\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Program\nopen Armada.State\nopen Armada.Type\nopen Spec.List\nopen Spec.Ubool\nopen Strategies.ArmadaInvariant.RootsMatch\nopen Strategies.ArmadaInvariant.PositionsValid\nopen Strategies.ArmadaInvariant.UnstartedThreads\nopen Strategies.GlobalVars\nopen Strategies.GlobalVars.Init\nopen Strategies.GlobalVars.Permanent\nopen Strategies.GlobalVars.Statement\nopen Strategies.GlobalVars.Unaddressed\nopen Strategies.GlobalVars.Util\nopen Strategies.GlobalVars.VarHiding\nopen Strategies.GlobalVars.VarIntro\nopen Strategies.Lift.Generic\nopen Strategies.Invariant\nopen Strategies.VarHiding.Defs\nopen Util.List\n\nlet rec remove_hidden_initializers_ensures_memories_match_except_gvars\n  (vs: list var_id_t)\n  (which_are_hidings: list bool)\n  (linits: list initializer_t)\n  (hinits: list initializer_t)\n  (lmem: Armada.Memory.t)\n  : Lemma (requires initializers_match_except_global_variables vs which_are_hidings linits hinits)\n          (ensures  (let hmem = remove_hidden_initializers which_are_hidings linits lmem in\n                     memories_match_except_global_variables vs lmem hmem)) =\n  match which_are_hidings, linits, hinits with\n  | [], [], [] -> ()\n  | true :: remaining_which_are_hidings, first_linit :: remaining_linits, _ ->\n      remove_hidden_initializers_ensures_memories_match_except_gvars vs remaining_which_are_hidings remaining_linits\n        hinits lmem\n  | false :: remaining_which_are_hidings, first_linit :: remaining_linits, first_hinit :: remaining_hinits ->\n      remove_hidden_initializers_ensures_memories_match_except_gvars vs remaining_which_are_hidings remaining_linits\n        remaining_hinits lmem\n  | _, _, _ -> ()\n\nlet rec initializers_match_except_global_variables_ensures_inclusion\n  (vs: list var_id_t)\n  (which_are_hidings: list bool)\n  (linits: list initializer_t)\n  (hinits: list initializer_t)\n  (init: initializer_t)\n  : Lemma (requires   contains_ubool init hinits\n                    /\\ initializers_match_except_global_variables vs which_are_hidings linits hinits)\n          (ensures  contains_ubool init linits) =\n  match which_are_hidings, linits, hinits with\n  | [], [], [] -> ()\n  | true :: remaining_which_are_hidings, first_linit :: remaining_linits, _ ->\n      initializers_match_except_global_variables_ensures_inclusion vs remaining_which_are_hidings\n        remaining_linits hinits init\n  | false :: remaining_which_are_hidings, first_linit :: remaining_linits, first_hinit :: remaining_hinits ->\n      if eqb init first_hinit then\n        ()\n      else\n        initializers_match_except_global_variables_ensures_inclusion vs remaining_which_are_hidings\n          remaining_linits remaining_hinits init\n  | _, _, _ -> ()\n\nlet initializers_match_except_global_variables_ensures_satisfies_global_initializers\n  (vs: list var_id_t)\n  (which_are_hidings: list bool)\n  (linits: list initializer_t)\n  (hinits: list initializer_t)\n  (mem: Armada.Memory.t)\n  : Lemma (requires   initializers_match_except_global_variables vs which_are_hidings linits hinits\n                    /\\ memory_satisfies_global_initializers mem linits)\n          (ensures  memory_satisfies_global_initializers mem hinits) =\n  introduce forall init. contains_ubool init hinits ==> memory_satisfies_global_initializer mem init\n  with introduce _ ==> _\n  with _. (\n    initializers_match_except_global_variables_ensures_inclusion vs which_are_hidings linits hinits init\n  )\n\nlet rec initializers_match_except_global_variables_ensures_no_gvars_in_hinits\n  (vs: list var_id_t)\n  (which_are_hidings: list bool)\n  (linits: list initializer_t)\n  (hinits: list initializer_t)\n  : Lemma (requires initializers_match_except_global_variables vs which_are_hidings linits hinits)\n          (ensures  forall init. contains_ubool init hinits ==> not (list_contains init.var_id vs)) =\n  match which_are_hidings, linits, hinits with\n  | [], [], [] -> ()\n  | true :: remaining_which_are_hidings, first_linit :: remaining_linits, _ ->\n      initializers_match_except_global_variables_ensures_no_gvars_in_hinits vs remaining_which_are_hidings\n        remaining_linits hinits\n  | false :: remaining_which_are_hidings, first_linit :: remaining_linits, first_hinit :: remaining_hinits ->\n      initializers_match_except_global_variables_ensures_no_gvars_in_hinits vs remaining_which_are_hidings\n        remaining_linits remaining_hinits\n  | _, _, _ -> ()\n  \nlet rec remove_hidden_initializers_maintains_memory_satisfies_global_initializers\n  (vs: list var_id_t)\n  (which_are_hidings: list bool)\n  (linits: list initializer_t)\n  (hinits: list initializer_t)\n  (all_hinits: list initializer_t)\n  (lmem: Armada.Memory.t)\n  : Lemma (requires   initializers_match_except_global_variables vs which_are_hidings linits hinits\n                    /\\ memory_satisfies_global_initializers lmem all_hinits\n                    /\\ (forall init. contains_ubool init hinits ==> contains_ubool init all_hinits)\n                    /\\ (forall init. contains_ubool init all_hinits ==> not (list_contains init.var_id vs)))\n          (ensures  (let hmem = remove_hidden_initializers which_are_hidings linits lmem in\n                     memory_satisfies_global_initializers hmem all_hinits)) =\n  match which_are_hidings, linits, hinits with\n  | [], [], [] -> ()\n  | true :: remaining_which_are_hidings, first_linit :: remaining_linits, _ ->\n      remove_hidden_initializers_maintains_memory_satisfies_global_initializers vs remaining_which_are_hidings\n        remaining_linits hinits all_hinits lmem\n  | false :: remaining_which_are_hidings, first_linit :: remaining_linits, first_hinit :: remaining_hinits ->\n      remove_hidden_initializers_maintains_memory_satisfies_global_initializers vs remaining_which_are_hidings\n        remaining_linits remaining_hinits all_hinits lmem\n  | _, _, _ -> ()\n\nlet remove_hidden_initializers_ensures_satisfies_global_initializers\n  (vs: list var_id_t)\n  (which_are_hidings: list bool)\n  (linits: list initializer_t)\n  (hinits: list initializer_t)\n  (lmem: Armada.Memory.t)\n  (* see .fsti file for spec *) =\n  initializers_match_except_global_variables_ensures_satisfies_global_initializers vs which_are_hidings\n    linits hinits lmem;\n  initializers_match_except_global_variables_ensures_no_gvars_in_hinits vs which_are_hidings linits hinits;\n  remove_hidden_initializers_maintains_memory_satisfies_global_initializers vs which_are_hidings linits\n    hinits hinits lmem;\n  remove_hidden_initializers_ensures_memories_match_except_gvars vs which_are_hidings linits hinits lmem\n\nlet rec remove_hidden_initializers_maintains_nonglobal_root\n  (which_are_hidings: list bool)\n  (inits: list initializer_t)\n  (lmem: Armada.Memory.t)\n  (root_id: root_id_t)\n  : Lemma (requires not (RootIdGlobal? root_id))\n          (ensures  (let hmem = remove_hidden_initializers which_are_hidings inits lmem in\n                     hmem root_id == lmem root_id)) =\n  match which_are_hidings, inits with\n  | [], _ -> ()\n  | true :: remaining_which_are_hidings, first_hinit :: remaining_inits ->\n      remove_hidden_initializers_maintains_nonglobal_root remaining_which_are_hidings remaining_inits lmem root_id\n  | false :: remaining_which_are_hidings, first_hinit :: remaining_inits ->\n      remove_hidden_initializers_maintains_nonglobal_root remaining_which_are_hidings remaining_inits lmem root_id\n  | _, _ -> ()\n\nlet rec remove_hidden_initializers_ensures_satisfies_main_stack_initializers\n  (vs: list var_id_t)\n  (which_are_hidings: list bool)\n  (linits: list initializer_t)\n  (initial_tid: tid_t)\n  (main_method_id: method_id_t)\n  (initial_frame_uniq: root_id_uniquifier_t)\n  (local_variables: list var_id_t)\n  (main_stack_initializers: list initializer_t)\n  (lmem: Armada.Memory.t)\n  (* see .fsti file for spec *) =\n  match local_variables, main_stack_initializers with\n  | [], [] -> ()\n  | var_id :: remaining_var_ids, initializer :: remaining_initializers ->\n      let root_id = RootIdStack initial_tid main_method_id initial_frame_uniq var_id in\n      remove_hidden_initializers_maintains_nonglobal_root which_are_hidings linits lmem root_id;\n      remove_hidden_initializers_ensures_satisfies_main_stack_initializers vs which_are_hidings linits\n        initial_tid main_method_id initial_frame_uniq remaining_var_ids remaining_initializers lmem\n  | _ -> ()\n\nlet rec matching_hinits_are_present\n  (which_are_hidings: list bool)\n  (linits: list initializer_t)\n  (hinits: list initializer_t)\n  (lmem: Armada.Memory.t)\n  : GTot bool =\n  match which_are_hidings, linits, hinits with\n  | [], [], [] -> true\n  | true :: remaining_which_are_hidings, first_linit :: remaining_linits, _ ->\n      matching_hinits_are_present remaining_which_are_hidings remaining_linits hinits lmem\n  | false :: remaining_which_are_hidings, first_linit :: remaining_linits, first_hinit :: remaining_hinits ->\n      (match lmem (RootIdGlobal first_hinit.var_id) with\n       | RootGlobal _ -> exists_ghost (var_id_in_initializer first_hinit.var_id) hinits\n       | _ -> false)\n  | _, _, _ -> false\n\nlet rec remove_hidden_initializers_maintains_roots_match\n  (which_are_hidings: list bool)\n  (inits: list initializer_t)\n  (mem: Armada.Memory.t)\n  : Lemma (requires roots_match mem)\n          (ensures  roots_match (remove_hidden_initializers which_are_hidings inits mem)) =\n  match which_are_hidings, inits with\n  | [], _ -> ()\n  | true :: remaining_which_are_hidings, first_hinit :: remaining_inits ->\n      remove_hidden_initializers_maintains_roots_match remaining_which_are_hidings remaining_inits mem\n  | false :: remaining_which_are_hidings, first_hinit :: remaining_inits ->\n      remove_hidden_initializers_maintains_roots_match remaining_which_are_hidings remaining_inits mem\n  | _, _ -> ()\n\nlet rec remove_hidden_initializers_doesnt_change_nonglobal\n  (which_are_hidings: list bool)\n  (inits: list initializer_t)\n  (mem: Armada.Memory.t)\n  (root_id: root_id_t)\n  : Lemma (requires not (RootIdGlobal? root_id))\n          (ensures  mem root_id == (remove_hidden_initializers which_are_hidings inits mem) root_id) =\n  match which_are_hidings, inits with\n  | [], _ -> ()\n  | true :: remaining_which_are_hidings, first_hinit :: remaining_inits ->\n      remove_hidden_initializers_doesnt_change_nonglobal remaining_which_are_hidings remaining_inits mem root_id\n  | false :: remaining_which_are_hidings, first_hinit :: remaining_inits ->\n      remove_hidden_initializers_doesnt_change_nonglobal remaining_which_are_hidings remaining_inits mem root_id\n  | _, _ -> ()\n\nlet rec remove_hidden_initializers_maintains_root_invalid_outside_initializations\n  (which_are_hidings: list bool)\n  (inits: list initializer_t)\n  (mem: Armada.Memory.t)\n  (root_id: root_id_t)\n  : Lemma (requires not (RootIdGlobal? root_id))\n          (ensures  mem root_id == (remove_hidden_initializers which_are_hidings inits mem) root_id) =\n  match which_are_hidings, inits with\n  | [], _ -> ()\n  | true :: remaining_which_are_hidings, first_hinit :: remaining_inits ->\n      remove_hidden_initializers_maintains_root_invalid_outside_initializations remaining_which_are_hidings\n        remaining_inits mem root_id\n  | false :: remaining_which_are_hidings, first_hinit :: remaining_inits ->\n      remove_hidden_initializers_maintains_root_invalid_outside_initializations remaining_which_are_hidings\n        remaining_inits mem root_id\n  | _, _ -> ()\n\nlet rec remove_hidden_initializers_doesnt_add_global\n  (which_are_hidings: list bool)\n  (inits: list initializer_t)\n  (mem: Armada.Memory.t)\n  (root_id: root_id_t)\n  : Lemma (requires (let mem' = remove_hidden_initializers which_are_hidings inits mem in\n                     RootGlobal? (mem' root_id)))\n          (ensures  RootGlobal? (mem root_id)) =\n  match which_are_hidings, inits with\n  | [], _ -> ()\n  | true :: remaining_which_are_hidings, first_hinit :: remaining_inits ->\n      remove_hidden_initializers_doesnt_add_global remaining_which_are_hidings\n        remaining_inits mem root_id\n  | false :: remaining_which_are_hidings, first_hinit :: remaining_inits ->\n      remove_hidden_initializers_doesnt_add_global remaining_which_are_hidings\n        remaining_inits mem root_id\n  | _, _ -> ()\n\nlet rec remove_hidden_initializers_removes_extra_inits\n  (vs: list var_id_t)\n  (which_are_hidings: list bool)\n  (linits: list initializer_t)\n  (hinits: list initializer_t)\n  (lmem: Armada.Memory.t)\n  (var_id: var_id_t)\n  : Lemma (requires   exists_ghost (var_id_in_initializer var_id) linits\n                    /\\ ~(exists_ghost (var_id_in_initializer var_id) hinits)\n                    /\\ initializers_match_except_global_variables vs which_are_hidings linits hinits)\n          (ensures  (let hmem = remove_hidden_initializers which_are_hidings linits lmem in\n                     RootInvalid? (hmem (RootIdGlobal var_id)))) =\n  match which_are_hidings, linits, hinits with\n  | [], [], [] -> false_elim ()\n  | true :: remaining_which_are_hidings, first_linit :: remaining_linits, _ ->\n      if first_linit.var_id = var_id then\n        ()\n      else\n        remove_hidden_initializers_removes_extra_inits vs remaining_which_are_hidings remaining_linits\n          hinits lmem var_id\n  | false :: remaining_which_are_hidings, first_linit :: remaining_linits, first_hinit :: remaining_hinits ->\n      remove_hidden_initializers_removes_extra_inits vs remaining_which_are_hidings remaining_linits\n        remaining_hinits lmem var_id\n  | _, _, _ -> false_elim ()\n\nlet remove_hidden_initializers_ensures_memory_invalid_outside_initializations\n  (vs: list var_id_t)\n  (which_are_hidings: list bool)\n  (linits: list initializer_t)\n  (hinits: list initializer_t)\n  (initial_tid: tid_t)\n  (main_method_id: method_id_t)\n  (initial_frame_uniq: root_id_uniquifier_t)\n  (local_variables: list var_id_t)\n  (lmem: Armada.Memory.t)\n  (* see .fsti file for spec *) =\n  let hmem = remove_hidden_initializers which_are_hidings linits lmem in\n  remove_hidden_initializers_maintains_roots_match which_are_hidings linits lmem;\n  introduce forall root_id. root_invalid_outside_initializations hmem hinits initial_tid\n                       main_method_id initial_frame_uniq local_variables root_id\n  with (\n    match hmem root_id with\n    | RootGlobal _ ->\n        (match root_id with\n         | RootIdGlobal var_id ->\n             if exists_ghost (var_id_in_initializer var_id) hinits then\n               ()\n             else (\n               remove_hidden_initializers_doesnt_add_global which_are_hidings linits lmem root_id;\n               assert (exists_ghost (var_id_in_initializer var_id) linits);\n               remove_hidden_initializers_removes_extra_inits vs which_are_hidings linits hinits lmem var_id\n             )\n         | _ -> ())\n    | RootInvalid -> ()\n    | _ -> remove_hidden_initializers_doesnt_change_nonglobal which_are_hidings linits lmem root_id\n  )\n\nlet initialization_ensures_gvar_has_type\n  (v: var_id_t)\n  (td: object_td_t)\n  (inits: list initializer_t)\n  (mem: Armada.Memory.t)\n  : Lemma (requires   memory_satisfies_global_initializers mem inits\n                    /\\ exists_ubool (initializer_matches_variable_and_td v td) inits)\n          (ensures  gvar_has_type mem v td) =\n  ()\n\nlet rec initialization_ensures_all_gvars_have_types_helper\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (inits: list initializer_t)\n  (mem: Armada.Memory.t)\n  : Lemma (requires   memory_satisfies_global_initializers mem inits\n                    /\\ every_variable_appears_among_initializers inits vs tds)\n          (ensures  all_gvars_have_types mem vs tds) =\n  match vs, tds with\n  | [], [] -> ()\n  | first_v :: remaining_vs, first_td :: remaining_tds ->\n      initialization_ensures_gvar_has_type first_v first_td inits mem;\n      initialization_ensures_all_gvars_have_types_helper remaining_vs remaining_tds inits mem\n\nlet initialization_ensures_all_gvars_have_types\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (linits: list initializer_t)\n  (lmem: Armada.Memory.t)\n  (* see .fst file for spec *) =\n  initialization_ensures_all_gvars_have_types_helper vs tds linits lmem\n"
  },
  {
    "path": "experimental/lib/Strategies.VarHiding.Initialization.fsti",
    "content": "module Strategies.VarHiding.Initialization\n\nopen Armada.Base\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Type\nopen Spec.List\nopen Strategies.ArmadaInvariant.RootsMatch\nopen Strategies.GlobalVars\nopen Strategies.GlobalVars.Types\nopen Strategies.VarHiding.Defs\n\nlet remove_hidden_initializer\n  (init: initializer_t)\n  (mem: Armada.Memory.t)\n  : GTot Armada.Memory.t =\n  let root_id = RootIdGlobal init.var_id in\n  Spec.Map.upd mem root_id RootInvalid\n\nlet rec remove_hidden_initializers\n  (which_are_hidings: list bool)\n  (inits: list initializer_t)\n  (mem: Armada.Memory.t)\n  : GTot Armada.Memory.t =\n  match which_are_hidings, inits with\n  | [], _ -> mem\n  | true :: remaining_which_are_hidings, first_init :: remaining_inits ->\n      let mem' = remove_hidden_initializers remaining_which_are_hidings remaining_inits mem in\n      remove_hidden_initializer first_init mem'\n  | false :: remaining_which_are_hidings, first_init :: remaining_inits ->\n      remove_hidden_initializers remaining_which_are_hidings remaining_inits mem\n  | _, _ -> mem\n\nval remove_hidden_initializers_ensures_satisfies_global_initializers\n  (vs: list var_id_t)\n  (which_are_hidings: list bool)\n  (linits: list initializer_t)\n  (hinits: list initializer_t)\n  (lmem: Armada.Memory.t)\n  : Lemma (requires   initializers_match_except_global_variables vs which_are_hidings linits hinits\n                    /\\ memory_satisfies_global_initializers lmem linits)\n          (ensures  (let hmem = remove_hidden_initializers which_are_hidings linits lmem in\n                       memory_satisfies_global_initializers hmem hinits\n                     /\\ memories_match_except_global_variables vs lmem hmem))\n\nval remove_hidden_initializers_ensures_satisfies_main_stack_initializers\n  (vs: list var_id_t)\n  (which_are_hidings: list bool)\n  (linits: list initializer_t)\n  (initial_tid: tid_t)\n  (main_method_id: method_id_t)\n  (initial_frame_uniq: root_id_uniquifier_t)\n  (local_variables: list var_id_t)\n  (main_stack_initializers: list initializer_t)\n  (lmem: Armada.Memory.t)\n  : Lemma (requires memory_satisfies_main_stack_initializers lmem initial_tid main_method_id initial_frame_uniq\n                      local_variables main_stack_initializers)\n          (ensures  (let hmem = remove_hidden_initializers which_are_hidings linits lmem in\n                     memory_satisfies_main_stack_initializers hmem initial_tid main_method_id initial_frame_uniq\n                       local_variables main_stack_initializers))\n\nval remove_hidden_initializers_ensures_memory_invalid_outside_initializations\n  (vs: list var_id_t)\n  (which_are_hidings: list bool)\n  (linits: list initializer_t)\n  (hinits: list initializer_t)\n  (initial_tid: tid_t)\n  (main_method_id: method_id_t)\n  (initial_frame_uniq: root_id_uniquifier_t)\n  (local_variables: list var_id_t)\n  (lmem: Armada.Memory.t)\n  : Lemma (requires   memory_invalid_outside_initializations lmem linits initial_tid main_method_id\n                        initial_frame_uniq local_variables\n                    /\\ initializers_match_except_global_variables vs which_are_hidings linits hinits\n                    /\\ roots_match lmem)\n          (ensures  (let hmem = remove_hidden_initializers which_are_hidings linits lmem in\n                     memory_invalid_outside_initializations hmem hinits initial_tid main_method_id\n                       initial_frame_uniq local_variables))\n\nval initialization_ensures_all_gvars_have_types\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (linits: list initializer_t)\n  (lmem: Armada.Memory.t)\n  : Lemma (requires   memory_satisfies_global_initializers lmem linits\n                    /\\ every_variable_appears_among_initializers linits vs tds)\n          (ensures  all_gvars_have_types lmem vs tds)\n"
  },
  {
    "path": "experimental/lib/Strategies.VarHiding.Invariant.fst",
    "content": "module Strategies.VarHiding.Invariant\n\nopen Armada.Base\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Threads\nopen Armada.Transition\nopen Armada.Type\nopen FStar.Sequence.Base\nopen Spec.List\nopen Spec.Ubool\nopen Strategies.ArmadaInvariant.RootsMatch\nopen Strategies.ArmadaInvariant.PositionsValid\nopen Strategies.ArmadaInvariant.UnstartedThreads\nopen Strategies.ArmadaStatement.Status\nopen Strategies.ArmadaStatement.ThreadState\nopen Strategies.Atomic\nopen Strategies.GlobalVars\nopen Strategies.GlobalVars.Types\nopen Strategies.GlobalVars.VarIntro\nopen Strategies.Invariant\nopen Strategies.PCRelation\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\nopen Strategies.VarHiding.Defs\nopen Strategies.VarHiding.Helpers\nopen Strategies.VarHiding.Initialization\n\nlet var_hiding_invariant\n  (ls: Armada.State.t)\n  : GTot ubool =\n  True\n\nlet var_hiding_lh_relation\n  (vr: var_hiding_relation_t)\n  (u: unit)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  : GTot ubool =\n  let pc_relation = var_hiding_pc_relation vr.lpc_to_hpc vr.return_lpcs vr.return_pcs_unique_proof in\n    states_match_except_global_variables vr.vs pc_relation ls hs\n  /\\ global_variables_unaddressed_in_memory vr.vs ls.mem\n  /\\ global_variables_unaddressed_in_memory vr.vs hs.mem\n  /\\ roots_match ls.mem\n  /\\ roots_match hs.mem\n  /\\ all_gvars_have_types ls.mem vr.vs vr.tds\n  /\\ unstarted_threads_have_empty_write_buffers ls\n  /\\ unstarted_threads_have_empty_write_buffers hs\n  /\\ (NotStopped? ls.stop_reason ==> vr.inv ls)\n\nlet var_hiding_progress_measure\n  (vr: var_hiding_relation_t)\n  (hs: Armada.State.t)\n  (latomic_step: list Armada.Step.t)\n  (actor: tid_t)\n  : GTot nat =\n  let hthread = hs.threads actor in\n  match latomic_step with\n  | [lstep] ->\n      (match lstep.action.program_statement.statement with\n       | PropagateWriteMessageStatement ->\n           let nd = lstep.nd in\n           if   list_len nd <> 1\n              || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract tid_t) then\n             0\n           else\n             let receiver_tid: tid_t = ObjectValueAbstract?.value (Cons?.hd nd) in\n             let position_in_write_buffer = (hs.threads receiver_tid).position_in_other_write_buffers actor in\n             let write_buffer_len = length hthread.write_buffer in\n             if position_in_write_buffer <= write_buffer_len then\n               write_buffer_len - position_in_write_buffer\n             else\n               0\n       | _ -> 0)\n  | _ -> 0\n"
  },
  {
    "path": "experimental/lib/Strategies.VarHiding.Propagate.fst",
    "content": "module Strategies.VarHiding.Propagate\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Computation\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Program\nopen Armada.State\nopen Armada.Step\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Threads\nopen Armada.Transition\nopen Armada.Type\nopen FStar.Sequence.Ambient\nopen FStar.Sequence.Base\nopen FStar.WellFoundedRelation\nopen Spec.Behavior\nopen Spec.List\nopen Spec.Ubool\nopen Strategies.ArmadaInvariant.RootsMatch\nopen Strategies.ArmadaInvariant.PositionsValid\nopen Strategies.ArmadaInvariant.UnstartedThreads\nopen Strategies.ArmadaStatement.Propagate\nopen Strategies.ArmadaStatement.Status\nopen Strategies.ArmadaStatement.ThreadState\nopen Strategies.Atomic\nopen Strategies.GlobalVars\nopen Strategies.GlobalVars.Init\nopen Strategies.GlobalVars.Permanent\nopen Strategies.GlobalVars.Statement\nopen Strategies.GlobalVars.Unaddressed\nopen Strategies.GlobalVars.Util\nopen Strategies.GlobalVars.VarHiding\nopen Strategies.GlobalVars.VarIntro\nopen Strategies.Lift.Generic\nopen Strategies.Invariant\nopen Strategies.PCRelation\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\nopen Strategies.VarHiding.Defs\nopen Strategies.VarHiding.Helpers\nopen Strategies.VarHiding.Initialization\nopen Strategies.VarHiding.Invariant\nopen Util.List\nopen Util.Nth\nopen Util.Seq\n\n#push-options \"--z3rlimit 30\"\n\nlet get_propagate_lifter_case_skip_helper\n  (vr: var_hiding_relation_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  (receiver_tid: tid_t)\n  (step: Armada.Step.t)\n  : Lemma (requires   var_hiding_lh_relation vr () ls hs\n                    /\\ NotStopped? hs.stop_reason\n                    /\\ ThreadStatusRunning? (hs.threads actor).status\n                    /\\ step == { nd = nd; action = propagate_action }\n                    /\\ list_len nd = 1\n                    /\\ object_value_to_td (Cons?.hd nd) == ObjectTDAbstract tid_t\n                    /\\ receiver_tid == ObjectValueAbstract?.value (Cons?.hd nd)\n                    /\\ receiver_tid <> actor\n                    /\\ (match propagate_write_message_statement_computation actor nd ls with\n                       | ComputationProduces ls' -> NotStopped? ls'.stop_reason ==> vr.inv ls'\n                       | _ -> False)\n                    /\\ (let lthread = ls.threads actor in\n                       let lwrite_buffer = lthread.write_buffer in\n                       let lposition = (ls.threads receiver_tid).position_in_other_write_buffers actor in\n                       let lwrite_message = index lwrite_buffer lposition in\n                       let lunread_write_buffer = unread_write_buffer ls.threads actor receiver_tid in\n                         ThreadStatusRunning? lthread.status\n                       /\\ not (global_variables_unaddressed_in_write_message vr.vs lwrite_message)))\n          (ensures  (match propagate_write_message_statement_computation actor nd ls with\n                     | ComputationProduces ls' -> var_hiding_lh_relation vr () ls' hs)) =\n  let lunread_write_buffer = unread_write_buffer ls.threads actor receiver_tid in\n  let hunread_write_buffer = unread_write_buffer hs.threads actor receiver_tid in\n  let pc_relation = var_hiding_pc_relation vr.lpc_to_hpc vr.return_lpcs vr.return_pcs_unique_proof in\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract tid_t) then\n    false_elim ()\n  else\n    let receiver_tid: tid_t = ObjectValueAbstract?.value (Cons?.hd nd) in\n    if receiver_tid = actor then // can't propagate to the same thread\n      false_elim ()\n    else\n      let propagator_thread = ls.threads actor in\n      let receiver_thread = ls.threads receiver_tid in\n      let which_message = receiver_thread.position_in_other_write_buffers actor in\n      if which_message >= length propagator_thread.write_buffer then\n        false_elim ()\n      else (\n        let write_message = index propagator_thread.write_buffer which_message in\n        let position_in_other_write_buffers' =\n          Spec.Map.upd receiver_thread.position_in_other_write_buffers actor (which_message + 1) in\n        let receiver_thread' =\n          { receiver_thread with position_in_other_write_buffers = position_in_other_write_buffers' } in\n        let threads' = Spec.Map.upd ls.threads receiver_tid receiver_thread' in\n        assert (positions_valid_in_threads threads');\n        let lem () : Lemma (positions_in_write_buffers_match_except_global_variables vr.vs threads' hs.threads) =\n        (\n          introduce forall sender_tid' receiver_tid'. sender_receiver_trigger sender_tid' receiver_tid' ==>\n                        write_buffers_match_except_global_variables vr.vs\n                          (unread_write_buffer threads' sender_tid' receiver_tid')\n                          (unread_write_buffer hs.threads sender_tid' receiver_tid')\n          with introduce _ ==> _\n          with _. (\n            assert (position_valid ls.threads sender_tid' receiver_tid');\n            assert (write_buffers_match_except_global_variables vr.vs\n                      (unread_write_buffer ls.threads sender_tid' receiver_tid')\n                      (unread_write_buffer hs.threads sender_tid' receiver_tid'));\n            if receiver_tid <> receiver_tid' then\n              ()\n            else if actor <> sender_tid' then\n              ()\n            else (\n              assert (unread_write_buffer hs.threads sender_tid' receiver_tid' == hunread_write_buffer);\n              assert (unread_write_buffer threads' sender_tid' receiver_tid' == drop lunread_write_buffer 1);\n              seq_to_list_drop_equals_tail lunread_write_buffer\n            )\n          )\n        ) in\n        lem ();\n        assert (positions_in_write_buffers_match_except_global_variables vr.vs threads' hs.threads);\n        match propagate_write_message write_message receiver_tid ls.mem with\n        | ComputationImpossible\n        | ComputationUndefined ->\n            // If propagate would trigger undefined behavior (e.g., by propagating to freed memory),\n            // it just leaves memory unchanged.\n            let ls' = { ls with threads = threads'; } in\n            assert (states_match_except_global_variables vr.vs pc_relation ls' hs);\n            assert (unstarted_threads_have_empty_write_buffers ls');\n            assert (global_variables_unaddressed_in_memory vr.vs ls'.mem);\n            assert (roots_match ls'.mem);\n            assert (var_hiding_lh_relation vr () ls' hs)\n        | ComputationProduces mem' ->\n            let ls' = { ls with mem = mem'; threads = threads'; } in\n            propagate_write_message_statement_computation_s1_only_maintains_states_match vr.vs pc_relation actor nd\n              ls hs;\n            assert (unstarted_threads_have_empty_write_buffers ls');\n            propagate_write_message_maintains_gvars_unaddressed vr.vs write_message receiver_tid ls.mem;\n            assert (global_variables_unaddressed_in_memory vr.vs ls'.mem);\n            assert (roots_match ls'.mem);\n            propagate_maintains_all_gvars_have_types vr.vs vr.tds actor nd ls;\n            assert (var_hiding_lh_relation vr () ls' hs)\n      )\n\n#pop-options\n\nlet get_propagate_lifter_case_skip\n  (vr: var_hiding_relation_t)\n  (actor: tid_t)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  (nd: nondeterminism_t)\n  (receiver_tid: tid_t)\n  (step: Armada.Step.t)\n  (lifter: step_lifter_t (list Armada.Step.t) unit)\n  : Lemma\n    (requires (  var_hiding_lh_relation vr () ls hs\n               /\\ (match propagate_write_message_statement_computation actor nd ls with\n                  | ComputationProduces ls' -> NotStopped? ls'.stop_reason ==> vr.inv ls'\n                  | _ -> False)\n               /\\ NotStopped? ls.stop_reason\n               /\\ list_len nd = 1\n               /\\ object_value_to_td (Cons?.hd nd) == ObjectTDAbstract tid_t\n               /\\ receiver_tid == ObjectValueAbstract?.value (Cons?.hd nd)\n               /\\ lifter == StepLifterSkip ()\n               /\\ step == { nd = nd; action = propagate_action }\n               /\\ (let lthread = ls.threads actor in\n                  let lwrite_buffer = lthread.write_buffer in\n                  let lposition = (ls.threads receiver_tid).position_in_other_write_buffers actor in\n                  let lwrite_message = index lwrite_buffer lposition in\n                    ThreadStatusRunning? lthread.status\n                  /\\ not (global_variables_unaddressed_in_write_message vr.vs lwrite_message))))\n    (ensures  step_lifter_works\n                (make_atomic_semantics armada_semantics)\n                (make_atomic_semantics armada_semantics)\n                vr.latomic_prog vr.hatomic_prog unit (var_hiding_lh_relation vr)\n                nat (default_wfr nat)\n                (var_hiding_progress_measure vr) actor true true [step] ls hs lifter) =\n  let pc_relation = var_hiding_pc_relation vr.lpc_to_hpc vr.return_lpcs vr.return_pcs_unique_proof in\n  let lthread = ls.threads actor in\n  let lwrite_buffer = lthread.write_buffer in\n  let lposition = (ls.threads receiver_tid).position_in_other_write_buffers actor in\n  let lwrite_message = index lwrite_buffer lposition in\n  assert_norm (map_ghost armada_step_to_action [step] == propagate_action_list);\n  get_propagate_lifter_case_skip_helper vr actor nd ls hs receiver_tid step;\n  step_computation_is_propagate_computation actor nd ls step\n\n#push-options \"--z3rlimit 20\"\n\nlet get_propagate_lifter_case_match\n  (vr: var_hiding_relation_t)\n  (actor: tid_t)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  (nd: nondeterminism_t)\n  (receiver_tid: tid_t)\n  (step: Armada.Step.t)\n  (lifter: step_lifter_t (list Armada.Step.t) unit)\n  : Lemma\n    (requires (  var_hiding_lh_relation vr () ls hs\n               /\\ (match propagate_write_message_statement_computation actor nd ls with\n                  | ComputationProduces ls' -> NotStopped? ls'.stop_reason ==> vr.inv ls'\n                  | _ -> False)\n               /\\ NotStopped? ls.stop_reason\n               /\\ list_len nd = 1\n               /\\ object_value_to_td (Cons?.hd nd) == ObjectTDAbstract tid_t\n               /\\ receiver_tid == ObjectValueAbstract?.value (Cons?.hd nd)\n               /\\ (let lthread = ls.threads actor in\n                  let hthread = hs.threads actor in\n                  let lwrite_buffer = lthread.write_buffer in\n                  let hwrite_buffer = hthread.write_buffer in\n                  let lposition = (ls.threads receiver_tid).position_in_other_write_buffers actor in\n                  let hposition = (hs.threads receiver_tid).position_in_other_write_buffers actor in\n                    ThreadStatusRunning? lthread.status\n                  /\\ length hwrite_buffer > hposition\n                  /\\ (let lwrite_message = index lwrite_buffer lposition in\n                     let hwrite_message = index hwrite_buffer hposition in\n                     let lunread_write_buffer = unread_write_buffer ls.threads actor receiver_tid in\n                     let hunread_write_buffer = unread_write_buffer hs.threads actor receiver_tid in\n                     let hstep = [step] in\n                       step == { nd = nd; action = propagate_action }\n                     /\\ program_contains_action_of_step_generic (make_atomic_semantics armada_semantics)\n                         vr.hatomic_prog [step]\n                     /\\ lifter == StepLifterLift hstep ()\n                     /\\ global_variables_unaddressed_in_write_message vr.vs lwrite_message\n                     /\\ global_variables_unaddressed_in_write_message vr.vs hwrite_message\n                     /\\ write_messages_match lwrite_message hwrite_message))))\n    (ensures  step_lifter_works\n                (make_atomic_semantics armada_semantics)\n                (make_atomic_semantics armada_semantics)\n                vr.latomic_prog vr.hatomic_prog unit (var_hiding_lh_relation vr)\n                nat (default_wfr nat)\n                (var_hiding_progress_measure vr) actor true true [step] ls hs lifter) =\n  let pc_relation = var_hiding_pc_relation vr.lpc_to_hpc vr.return_lpcs vr.return_pcs_unique_proof in\n  let lthread = ls.threads actor in\n  let hthread = hs.threads actor in\n  let lwrite_buffer = lthread.write_buffer in\n  let hwrite_buffer = hthread.write_buffer in\n  let lposition = (ls.threads receiver_tid).position_in_other_write_buffers actor in\n  let hposition = (hs.threads receiver_tid).position_in_other_write_buffers actor in\n  let lwrite_message = index lwrite_buffer lposition in\n  let hwrite_message = index hwrite_buffer hposition in\n  let lunread_write_buffer = unread_write_buffer ls.threads actor receiver_tid in\n  let hunread_write_buffer = unread_write_buffer hs.threads actor receiver_tid in\n  assert (map_ghost armada_step_to_action [step] == propagate_action_list);\n  propagate_write_message_statement_computation_maintains_states_match vr.vs pc_relation actor nd ls hs;\n  match propagate_write_message_statement_computation actor nd ls,\n        propagate_write_message_statement_computation actor nd hs with\n  | ComputationProduces ls', ComputationProduces hs' ->\n      assert (states_match_except_global_variables vr.vs pc_relation ls' hs');\n      assert (global_variables_unaddressed_in_memory vr.vs ls'.mem);\n      assert (global_variables_unaddressed_in_memory vr.vs hs'.mem);\n      assert (roots_match ls'.mem);\n      assert (roots_match hs'.mem);\n      propagate_maintains_all_gvars_have_types vr.vs vr.tds actor nd ls;\n      step_computation_is_propagate_computation actor nd ls step;\n      step_computation_is_propagate_computation actor nd hs step;\n      assert (var_hiding_lh_relation vr () ls' hs')\n\n#pop-options\n#push-options \"--z3rlimit 30\"\n\nlet get_propagate_lifter_case_introduce_helper1\n  (vr: var_hiding_relation_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  (receiver_tid: tid_t)\n  (step: Armada.Step.t)\n  : Lemma (requires   var_hiding_lh_relation vr () ls hs\n                    /\\ NotStopped? hs.stop_reason\n                    /\\ ThreadStatusRunning? (hs.threads actor).status\n                    /\\ step == { nd = nd; action = propagate_action }\n                    /\\ list_len nd = 1\n                    /\\ object_value_to_td (Cons?.hd nd) == ObjectTDAbstract tid_t\n                    /\\ receiver_tid == ObjectValueAbstract?.value (Cons?.hd nd)\n                    /\\ receiver_tid <> actor\n                    /\\ (let lthread = ls.threads actor in\n                       let hthread = hs.threads actor in\n                       let lwrite_buffer = lthread.write_buffer in\n                       let hwrite_buffer = hthread.write_buffer in\n                       let hposition = (hs.threads receiver_tid).position_in_other_write_buffers actor in\n                          length hwrite_buffer > hposition\n                       /\\ (let hwrite_message = index hwrite_buffer hposition in\n                          let lunread_write_buffer = unread_write_buffer ls.threads actor receiver_tid in\n                          let hunread_write_buffer = unread_write_buffer hs.threads actor receiver_tid in\n                            step == { nd = nd; action = propagate_action }\n                          /\\ program_contains_action_of_step_generic (make_atomic_semantics armada_semantics)\n                              vr.hatomic_prog [step]\n                          /\\ not (global_variables_unaddressed_in_write_message vr.vs hwrite_message))))\n          (ensures  (match propagate_write_message_statement_computation actor nd hs with\n                     | ComputationProduces hs' -> var_hiding_lh_relation vr () ls hs'\n                     | _ -> False)) =\n  let lunread_write_buffer = unread_write_buffer ls.threads actor receiver_tid in\n  let hunread_write_buffer = unread_write_buffer hs.threads actor receiver_tid in\n  let pc_relation = var_hiding_pc_relation vr.lpc_to_hpc vr.return_lpcs vr.return_pcs_unique_proof in\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract tid_t) then\n    false_elim ()\n  else\n    let receiver_tid: tid_t = ObjectValueAbstract?.value (Cons?.hd nd) in\n    if receiver_tid = actor then // can't propagate to the same thread\n      false_elim ()\n    else\n      let propagator_thread = hs.threads actor in\n      let receiver_thread = hs.threads receiver_tid in\n      let which_message = receiver_thread.position_in_other_write_buffers actor in\n      if which_message >= length propagator_thread.write_buffer then\n        false_elim ()\n      else\n        let write_message = index propagator_thread.write_buffer which_message in\n        let position_in_other_write_buffers' =\n          Spec.Map.upd receiver_thread.position_in_other_write_buffers actor (which_message + 1) in\n        let receiver_thread' =\n          { receiver_thread with position_in_other_write_buffers = position_in_other_write_buffers' } in\n        let threads' = Spec.Map.upd hs.threads receiver_tid receiver_thread' in\n        let lem () : Lemma (  positions_valid_in_threads threads'\n                            /\\ positions_in_write_buffers_match_except_global_variables vr.vs ls.threads threads') =\n        (\n          introduce forall sender_tid' receiver_tid'. sender_receiver_trigger sender_tid' receiver_tid' ==>\n                          position_valid threads' sender_tid' receiver_tid'\n                        /\\ write_buffers_match_except_global_variables vr.vs\n                            (unread_write_buffer ls.threads sender_tid' receiver_tid')\n                            (unread_write_buffer threads' sender_tid' receiver_tid')\n          with introduce _ ==> _\n          with _. (\n            assert (position_valid hs.threads sender_tid' receiver_tid');\n            assert (write_buffers_match_except_global_variables vr.vs\n                      (unread_write_buffer ls.threads sender_tid' receiver_tid')\n                      (unread_write_buffer hs.threads sender_tid' receiver_tid'));\n            if receiver_tid <> receiver_tid' then\n              ()\n            else if actor <> sender_tid' then\n              ()\n            else (\n              assert (unread_write_buffer ls.threads sender_tid' receiver_tid' == lunread_write_buffer);\n              assert (unread_write_buffer threads' sender_tid' receiver_tid' == drop hunread_write_buffer 1);\n              seq_to_list_drop_equals_tail hunread_write_buffer\n            )\n          )\n        ) in\n        lem ();\n        assert (positions_valid_in_threads threads');\n        assert (positions_in_write_buffers_match_except_global_variables vr.vs ls.threads threads');\n        match propagate_write_message write_message receiver_tid hs.mem with\n        | ComputationImpossible\n        | ComputationUndefined ->\n            // If propagate would trigger undefined behavior (e.g., by propagating to freed memory),\n            // it just leaves memory unchanged.\n            let hs' = { hs with threads = threads'; } in\n            assert (states_match_except_global_variables vr.vs pc_relation ls hs');\n            assert (unstarted_threads_have_empty_write_buffers hs');\n            assert (global_variables_unaddressed_in_memory vr.vs hs'.mem);\n            assert (roots_match hs'.mem);\n            assert (var_hiding_lh_relation vr () ls hs')\n        | ComputationProduces mem' ->\n            let hs' = { hs with mem = mem'; threads = threads'; } in\n            propagate_write_message_statement_computation_s2_only_maintains_states_match vr.vs pc_relation actor nd\n              ls hs;\n            assert (unstarted_threads_have_empty_write_buffers hs');\n            propagate_write_message_maintains_gvars_unaddressed vr.vs write_message receiver_tid hs.mem;\n            assert (global_variables_unaddressed_in_memory vr.vs hs'.mem);\n            assert (roots_match hs'.mem);\n            assert (var_hiding_lh_relation vr () ls hs')\n\nlet get_propagate_lifter_case_introduce_helper2\n  (vr: var_hiding_relation_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  (receiver_tid: tid_t)\n  (step: Armada.Step.t)\n  : Lemma (requires   var_hiding_lh_relation vr () ls hs\n                    /\\ NotStopped? hs.stop_reason\n                    /\\ ThreadStatusRunning? (hs.threads actor).status\n                    /\\ step == { nd = nd; action = propagate_action }\n                    /\\ list_len nd = 1\n                    /\\ object_value_to_td (Cons?.hd nd) == ObjectTDAbstract tid_t\n                    /\\ receiver_tid == ObjectValueAbstract?.value (Cons?.hd nd)\n                    /\\ receiver_tid <> actor\n                    /\\ (let lthread = ls.threads actor in\n                       let hthread = hs.threads actor in\n                       let lwrite_buffer = lthread.write_buffer in\n                       let hwrite_buffer = hthread.write_buffer in\n                       let hposition = (hs.threads receiver_tid).position_in_other_write_buffers actor in\n                          length hwrite_buffer > hposition\n                       /\\ (let hwrite_message = index hwrite_buffer hposition in\n                          let lunread_write_buffer = unread_write_buffer ls.threads actor receiver_tid in\n                          let hunread_write_buffer = unread_write_buffer hs.threads actor receiver_tid in\n                            step == { nd = nd; action = propagate_action }\n                          /\\ program_contains_action_of_step_generic (make_atomic_semantics armada_semantics)\n                              vr.hatomic_prog [step]\n                          /\\ not (global_variables_unaddressed_in_write_message vr.vs hwrite_message))))\n          (ensures  (match propagate_write_message_statement_computation actor nd hs with\n                     | ComputationProduces hs' ->\n                           (hs'.threads actor).pc = (hs.threads actor).pc\n                         /\\ var_hiding_progress_measure vr hs' [step] actor <\n                             var_hiding_progress_measure vr hs [step] actor\n                     | _ -> False)) =\n  let pc_relation = var_hiding_pc_relation vr.lpc_to_hpc vr.return_lpcs vr.return_pcs_unique_proof in\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract tid_t) then\n    false_elim ()\n  else\n    let receiver_tid: tid_t = ObjectValueAbstract?.value (Cons?.hd nd) in\n    if receiver_tid = actor then // can't propagate to the same thread\n      false_elim ()\n    else\n      let propagator_thread = hs.threads actor in\n      let receiver_thread = hs.threads receiver_tid in\n      let which_message = receiver_thread.position_in_other_write_buffers actor in\n      if which_message >= length propagator_thread.write_buffer then\n        false_elim ()\n      else\n        let write_message = index propagator_thread.write_buffer which_message in\n        let position_in_other_write_buffers' =\n          Spec.Map.upd receiver_thread.position_in_other_write_buffers actor (which_message + 1) in\n        let receiver_thread' =\n          { receiver_thread with position_in_other_write_buffers = position_in_other_write_buffers' } in\n        let threads' = Spec.Map.upd hs.threads receiver_tid receiver_thread' in\n        assert ((threads' actor).write_buffer == (hs.threads actor).write_buffer);\n        assert (which_message + 1 <= length (threads' actor).write_buffer);\n        assert (position_in_other_write_buffers' actor == which_message + 1);\n        assert (threads' receiver_tid == receiver_thread');\n        assert ((threads' receiver_tid).position_in_other_write_buffers == position_in_other_write_buffers');\n        assert ((threads' receiver_tid).position_in_other_write_buffers actor == which_message + 1);\n        match propagate_write_message write_message receiver_tid hs.mem with\n        | ComputationImpossible\n        | ComputationUndefined ->\n            // If propagate would trigger undefined behavior (e.g., by propagating to freed memory),\n            // it just leaves memory unchanged.\n            let hs' = { hs with threads = threads'; } in\n            assert (var_hiding_progress_measure vr hs [step] actor ==\n                      length propagator_thread.write_buffer - which_message);\n            assert (var_hiding_progress_measure vr hs' [step] actor ==\n                      length (hs'.threads actor).write_buffer - (which_message + 1));\n            assert (var_hiding_progress_measure vr hs' [step] actor <\n                      var_hiding_progress_measure vr hs [step] actor)\n        | ComputationProduces mem' ->\n            let hs' = { hs with mem = mem'; threads = threads'; } in\n            assert (var_hiding_progress_measure vr hs [step] actor ==\n                      length propagator_thread.write_buffer - which_message);\n            assert (var_hiding_progress_measure vr hs' [step] actor ==\n                      length (hs'.threads actor).write_buffer - (which_message + 1));\n            assert (var_hiding_progress_measure vr hs' [step] actor <\n                      var_hiding_progress_measure vr hs [step] actor)\n\nlet get_propagate_lifter_case_introduce\n  (vr: var_hiding_relation_t)\n  (actor: tid_t)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  (nd: nondeterminism_t)\n  (receiver_tid: tid_t)\n  (step: Armada.Step.t)\n  (lifter: step_lifter_t (list Armada.Step.t) unit)\n  : Lemma\n    (requires (  var_hiding_lh_relation vr () ls hs\n               /\\ ComputationProduces? (propagate_write_message_statement_computation actor nd ls)\n               /\\ NotStopped? ls.stop_reason\n               /\\ list_len nd = 1\n               /\\ object_value_to_td (Cons?.hd nd) == ObjectTDAbstract tid_t\n               /\\ receiver_tid == ObjectValueAbstract?.value (Cons?.hd nd)\n               /\\ step == { nd = nd; action = propagate_action }\n               /\\ (let lthread = ls.threads actor in\n                  let hthread = hs.threads actor in\n                  let lwrite_buffer = lthread.write_buffer in\n                  let hwrite_buffer = hthread.write_buffer in\n                  let hposition = (hs.threads receiver_tid).position_in_other_write_buffers actor in\n                    ThreadStatusRunning? lthread.status\n                  /\\ length hwrite_buffer > hposition\n                  /\\ (let hwrite_message = index hwrite_buffer hposition in\n                     let lunread_write_buffer = unread_write_buffer ls.threads actor receiver_tid in\n                     let hunread_write_buffer = unread_write_buffer hs.threads actor receiver_tid in\n                       program_contains_action_of_step_generic (make_atomic_semantics armada_semantics)\n                         vr.hatomic_prog [step]\n                     /\\ lifter == StepLifterIntroduce [step] ()\n                     /\\ not (global_variables_unaddressed_in_write_message vr.vs hwrite_message)))))\n    (ensures  step_lifter_works\n                (make_atomic_semantics armada_semantics)\n                (make_atomic_semantics armada_semantics)\n                vr.latomic_prog vr.hatomic_prog unit (var_hiding_lh_relation vr)\n                nat (default_wfr nat)\n                (var_hiding_progress_measure vr) actor true true [step] ls hs lifter) =\n  let pc_relation = var_hiding_pc_relation vr.lpc_to_hpc vr.return_lpcs vr.return_pcs_unique_proof in\n  let lthread = ls.threads actor in\n  let hthread = hs.threads actor in\n  let lwrite_buffer = lthread.write_buffer in\n  let hwrite_buffer = hthread.write_buffer in\n  let lposition = (ls.threads receiver_tid).position_in_other_write_buffers actor in\n  let hposition = (hs.threads receiver_tid).position_in_other_write_buffers actor in\n  let lwrite_message = index lwrite_buffer lposition in\n  let hwrite_message = index hwrite_buffer hposition in\n  let lunread_write_buffer = unread_write_buffer ls.threads actor receiver_tid in\n  let hunread_write_buffer = unread_write_buffer hs.threads actor receiver_tid in\n  assert_norm (map_ghost armada_step_to_action [step] == propagate_action_list);\n  get_propagate_lifter_case_introduce_helper1 vr actor nd ls hs receiver_tid step;\n  get_propagate_lifter_case_introduce_helper2 vr actor nd ls hs receiver_tid step;\n  step_computation_is_propagate_computation actor nd hs step;\n  let hs' = Some?.v (step_computation_generic (make_atomic_semantics armada_semantics) actor true true [step] hs) in\n  let progress_wfr = default_wfr nat in\n  let progress_measure = var_hiding_progress_measure vr in\n  assert (progress_wfr.relation (progress_measure hs' [step] actor) (progress_measure hs [step] actor))\n\nlet correspondence_for_propagate_implies_propagate_among_hactions\n  (vr: var_hiding_relation_t)\n  (correspondence: (ltoh_correspondence_t vr.vs vr.tds vr.inv))\n  : Lemma (requires lactions_correspond_to_hactions_per_correspondence vr.vs vr.tds vr.inv vr.lpc_to_hpc\n                      vr.return_lpcs vr.hatomic_prog.actions propagate_action_list correspondence)\n          (ensures  contains_ubool propagate_action_list vr.hatomic_prog.actions) =\n  let pc_relation = var_hiding_pc_relation vr.lpc_to_hpc vr.return_lpcs vr.return_pcs_unique_proof in\n  match correspondence with\n  | CorrespondenceHidden ->\n      lactions_all_hidden_implies_not_propagate vr.vs vr.lpc_to_hpc ThreadStateRunning ThreadStateRunning\n         propagate_action_list\n  | CorrespondencePropagate hidx ->\n      nth_implies_contains_ubool vr.hatomic_prog.actions hidx propagate_action_list\n  | CorrespondenceNormal hidx which_actions_hidden ->\n      (match list_nth vr.hatomic_prog.actions hidx with\n       | Some hactions ->\n           lactions_correspond_to_hactions_implies_not_propagate vr.vs vr.lpc_to_hpc vr.return_lpcs\n             ThreadStateRunning ThreadStateRunning ThreadStateRunning ThreadStateRunning\n             which_actions_hidden propagate_action_list hactions\n       | None -> ())\n\nlet get_propagate_lifter_helper\n  (vr: var_hiding_relation_t)\n  (actor: tid_t)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  (nd: nondeterminism_t)\n  : Ghost (step_lifter_t (list Armada.Step.t) unit)\n    (requires   var_hiding_lh_relation vr () ls hs\n              /\\ NotStopped? ls.stop_reason\n              /\\ ThreadStatusRunning? (ls.threads actor).status\n              /\\ contains_ubool propagate_action_list vr.latomic_prog.actions\n              /\\ (match propagate_write_message_statement_computation actor nd ls with\n                 | ComputationProduces ls' -> NotStopped? ls'.stop_reason ==> vr.inv ls'\n                 | _ -> False))\n    (ensures  fun lifter ->\n                let step = { nd = nd; action = propagate_action } in\n                step_lifter_works\n                  (make_atomic_semantics armada_semantics)\n                  (make_atomic_semantics armada_semantics)\n                  vr.latomic_prog vr.hatomic_prog unit (var_hiding_lh_relation vr)\n                  nat (default_wfr nat)\n                  (var_hiding_progress_measure vr) actor true true [step] ls hs lifter) =\n  let lthread = ls.threads actor in\n  let hthread = hs.threads actor in\n  let receiver_tid: tid_t = ObjectValueAbstract?.value (Cons?.hd nd) in\n  assert (positions_in_write_buffers_match_except_global_variables vr.vs ls.threads hs.threads);\n  assert (sender_receiver_trigger actor receiver_tid);\n  let lunread_write_buffer = unread_write_buffer ls.threads actor receiver_tid in\n  let hunread_write_buffer = unread_write_buffer hs.threads actor receiver_tid in\n  let lwrite_buffer = lthread.write_buffer in\n  let hwrite_buffer = hthread.write_buffer in\n  let lposition = (ls.threads receiver_tid).position_in_other_write_buffers actor in\n  let hposition = (hs.threads receiver_tid).position_in_other_write_buffers actor in\n  assert (lunread_write_buffer == drop lwrite_buffer lposition);\n  assert (hunread_write_buffer == drop hwrite_buffer hposition);\n  assert (length lunread_write_buffer > 0);\n  let lwrite_message = index lunread_write_buffer 0 in\n  assert (lwrite_message == index lwrite_buffer lposition);\n  let step = { nd = nd; action = propagate_action } in\n  let lem () : Lemma (program_contains_action_of_step_generic (make_atomic_semantics armada_semantics)\n                        vr.hatomic_prog [step]) =\n  (\n    vr.corresponding_hactions_correspond_proof ();\n    assert (map_ghost armada_step_to_action [step] == propagate_action_list);\n    let correspondence = get_correspondent_from_lists_correspond_ubool\n      (lactions_correspond_to_hactions_per_correspondence vr.vs vr.tds vr.inv vr.lpc_to_hpc\n         vr.return_lpcs vr.hatomic_prog.actions)\n      vr.latomic_prog.actions vr.corresponding_hactions_info propagate_action_list\n    in\n    correspondence_for_propagate_implies_propagate_among_hactions vr correspondence\n  ) in\n  lem ();\n  if global_variables_unaddressed_in_write_message vr.vs lwrite_message then\n    let hwrite_message = index hunread_write_buffer 0 in\n    assert (hwrite_message == index hwrite_buffer hposition);\n    if global_variables_unaddressed_in_write_message vr.vs hwrite_message then (\n      let lifter = StepLifterLift [step] () in\n      get_propagate_lifter_case_match vr actor ls hs nd receiver_tid step lifter;\n      lifter\n    )\n    else (\n      let lifter = StepLifterIntroduce [step] () in\n      get_propagate_lifter_case_introduce vr actor ls hs nd receiver_tid step lifter;\n      lifter\n    )\n  else (\n    let lifter = StepLifterSkip () in\n    get_propagate_lifter_case_skip vr actor ls hs nd receiver_tid step lifter;\n    lifter\n  )\n\nlet get_propagate_lifter\n  (vr: var_hiding_relation_t)\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  (lsteps: list Armada.Step.t)\n  : Ghost (step_lifter_t (list Armada.Step.t) unit)\n    (requires   var_hiding_lh_relation vr () ls hs\n              /\\ Some? (steps_computation_generic armada_semantics actor starts_atomic_block ends_atomic_block\n                         lsteps ls)\n              /\\ contains_ubool (map_ghost armada_step_to_action lsteps) vr.latomic_prog.actions\n              /\\ (Cons?.hd lsteps).action.program_statement.statement == PropagateWriteMessageStatement)\n    (ensures  fun lifter ->\n                step_lifter_works\n                  (make_atomic_semantics armada_semantics)\n                  (make_atomic_semantics armada_semantics)\n                  vr.latomic_prog vr.hatomic_prog unit (var_hiding_lh_relation vr)\n                  nat (default_wfr nat)\n                  (var_hiding_progress_measure vr) actor starts_atomic_block ends_atomic_block lsteps ls hs lifter) =\n  let step = Cons?.hd lsteps in\n  let nd = step.nd in\n  let lactions = map_ghost armada_step_to_action lsteps in\n  vr.corresponding_hactions_correspond_proof ();\n  let correspondence = get_correspondent_from_lists_correspond_ubool\n    (lactions_correspond_to_hactions_per_correspondence vr.vs vr.tds vr.inv vr.lpc_to_hpc vr.return_lpcs\n       vr.hatomic_prog.actions)\n    vr.latomic_prog.actions vr.corresponding_hactions_info lactions\n  in\n  match correspondence with\n  | CorrespondenceHidden -> false_elim ()\n  | CorrespondencePropagate hidx ->\n      possible_propagate_action_ok actor starts_atomic_block ends_atomic_block ls lsteps;\n      (match lsteps with\n       | [step] ->\n            step_computation_is_propagate_computation actor nd ls step;\n            (match propagate_write_message_statement_computation actor nd ls with\n             | ComputationProduces ls' ->\n                 introduce NotStopped? ls'.stop_reason ==> vr.inv ls'\n                 with _. (\n                   vr.inv_is_substep_invariant_proof ();\n                   assert (vr.inv ls);\n                   assert (Some ls' == step_computation actor true true step ls);\n                   assert (contains_ubool step.action propagate_action_list);\n                   assert (contains_ubool propagate_action_list vr.latomic_prog.actions);\n                   assert (vr.inv ls')\n                 )));\n      get_propagate_lifter_helper vr actor ls hs nd\n  | CorrespondenceNormal hidx which_actions_hidden ->\n      (match list_nth vr.hatomic_prog.actions hidx with\n       | Some hactions ->\n           lactions_correspond_to_hactions_implies_not_propagate vr.vs vr.lpc_to_hpc vr.return_lpcs\n             ThreadStateRunning ThreadStateRunning ThreadStateRunning ThreadStateRunning\n             which_actions_hidden lactions hactions;\n           false_elim ()\n       | None -> false_elim ())\n  | CorrespondenceImpossibleConstantAssignmentFailure ->\n      false_elim ()\n  | CorrespondenceImpossibleStatementFailure ps proof ->\n      false_elim ()\n\n#pop-options\n"
  },
  {
    "path": "experimental/lib/Strategies.VarHiding.Relation.fst",
    "content": "module Strategies.VarHiding.Relation\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Computation\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Program\nopen Armada.State\nopen Armada.Step\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Threads\nopen Armada.Transition\nopen Armada.Type\nopen FStar.Sequence.Ambient\nopen FStar.Sequence.Base\nopen FStar.WellFoundedRelation\nopen Spec.Behavior\nopen Spec.List\nopen Spec.Ubool\nopen Strategies.ArmadaInvariant.RootsMatch\nopen Strategies.ArmadaInvariant.PositionsValid\nopen Strategies.ArmadaInvariant.UnstartedThreads\nopen Strategies.ArmadaStatement.Status\nopen Strategies.ArmadaStatement.ThreadState\nopen Strategies.Atomic\nopen Strategies.GlobalVars\nopen Strategies.GlobalVars.Init\nopen Strategies.GlobalVars.Permanent\nopen Strategies.GlobalVars.Statement\nopen Strategies.GlobalVars.Types\nopen Strategies.GlobalVars.Unaddressed\nopen Strategies.GlobalVars.Util\nopen Strategies.GlobalVars.VarHiding\nopen Strategies.GlobalVars.VarIntro\nopen Strategies.Lift.Generic\nopen Strategies.Invariant\nopen Strategies.Nonyielding\nopen Strategies.PCRelation\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\nopen Strategies.VarHiding.Defs\nopen Strategies.VarHiding.Helpers\nopen Strategies.VarHiding.Initialization\nopen Strategies.VarHiding.Invariant\nopen Strategies.VarHiding.Propagate\nopen Util.List\nopen Util.Nth\nopen Util.Seq\n\n#push-options \"--z3rlimit 40\"\n\nlet executing_matching_steps_maintains_invariant\n  (vr: var_hiding_relation_t)\n  (actor: tid_t)\n  (lstart_state: thread_state_t)\n  (hstart_state: thread_state_t)\n  (lend_state: thread_state_t)\n  (hend_state: thread_state_t)\n  (lstarts_atomic_block: bool)\n  (hstarts_atomic_block: bool)\n  (lends_atomic_block: bool)\n  (hends_atomic_block: bool)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  (lstep: Armada.Step.t)\n  (hstep: Armada.Step.t)\n  (containing_latomic_action: list Armada.Action.t)\n  : Lemma (requires \n            (let pc_relation = var_hiding_pc_relation vr.lpc_to_hpc vr.return_lpcs vr.return_pcs_unique_proof in\n               var_hiding_lh_relation vr () ls hs\n             /\\ Some? (step_computation actor lstarts_atomic_block lends_atomic_block lstep ls)\n             /\\ contains_ubool lstep.action containing_latomic_action\n             /\\ contains_ubool containing_latomic_action vr.latomic_prog.actions\n             /\\ lstep_corresponds_to_hstep vr.vs pc_relation lstep hstep\n             /\\ action_to_starting_thread_state lstep.action = lstart_state\n             /\\ action_to_starting_thread_state hstep.action = hstart_state\n             /\\ action_to_ending_thread_state lstep.action = lend_state\n             /\\ action_to_ending_thread_state hstep.action = hend_state\n             /\\ ThreadStateAtPC? lstart_state\n             /\\ ThreadStateAtPC? hstart_state\n             /\\ thread_states_match_per_pc_relation pc_relation.relation lstart_state hstart_state\n             /\\ thread_states_match_per_pc_relation pc_relation.relation lend_state hend_state\n             /\\ lstarts_atomic_block = lstep.action.program_statement.starts_atomic_block\n             /\\ hstarts_atomic_block = hstep.action.program_statement.starts_atomic_block\n             /\\ lends_atomic_block = (lstep.action.program_statement.ends_atomic_block || not lstep.action.ok)\n             /\\ hends_atomic_block = (hstep.action.program_statement.ends_atomic_block || not hstep.action.ok)\n             /\\ thread_state_applies ls actor lstart_state\n             /\\ thread_state_applies hs actor hstart_state))\n    (ensures  (match step_computation actor lstarts_atomic_block lends_atomic_block lstep ls,\n                     step_computation actor hstarts_atomic_block hends_atomic_block hstep hs with\n               | Some ls', Some hs' ->\n                   var_hiding_lh_relation vr () ls' hs'\n               | _, _ -> False)) =\n  let lthread = ls.threads actor in\n  let hthread = hs.threads actor in\n  let laction = lstep.action in\n  let haction = hstep.action in\n  let lps = laction.program_statement in\n  let hps = haction.program_statement in\n  let pc_relation = var_hiding_pc_relation vr.lpc_to_hpc vr.return_lpcs vr.return_pcs_unique_proof in\n  lstep_corresponds_to_hstep_clarifier vr.vs pc_relation lstep hstep;\n  assert (step_computation actor lstarts_atomic_block lends_atomic_block lstep ls ==\n          action_computation actor lstarts_atomic_block lends_atomic_block lstep.nd lstep.action ls);\n  assert (step_computation actor hstarts_atomic_block hends_atomic_block hstep hs ==\n          action_computation actor hstarts_atomic_block hends_atomic_block hstep.nd hstep.action hs);\n  statement_effect_independent_implications vr.vs pc_relation actor lstep.nd lthread.pc hthread.pc\n    lps.end_pc hps.end_pc lps.statement hps.statement ls hs;\n  match statement_computation actor lstep.nd lthread.pc lps.end_pc lps.statement ls,\n        statement_computation actor hstep.nd hthread.pc hps.end_pc hps.statement hs with\n  | ComputationProduces ls', ComputationProduces hs' ->\n      assert (lstep.action.ok);\n      assert (global_variables_unaddressed_in_memory vr.vs ls'.mem);\n      assert (global_variables_unaddressed_in_memory vr.vs hs'.mem);\n      assert (roots_match ls'.mem);\n      assert (roots_match hs'.mem);\n      assert (states_match_except_global_variables vr.vs pc_relation ls' hs');\n      let ls'' = update_thread_pc_in_state ls' actor lps.end_pc in\n      let hs'' = update_thread_pc_in_state hs' actor hps.end_pc in\n      let lem1 () : Lemma (  unstarted_threads_have_empty_write_buffers ls'\n                           /\\ unstarted_threads_have_empty_write_buffers hs') = (\n        executing_statement_maintains_unstarted_threads_have_empty_write_buffers actor lstep.nd\n          lthread.pc lps.end_pc lps.statement ls;\n        executing_statement_maintains_unstarted_threads_have_empty_write_buffers actor hstep.nd\n          hthread.pc hps.end_pc hps.statement hs\n      ) in\n      assert (Some ls'' == step_computation actor lstarts_atomic_block lends_atomic_block lstep ls);\n      assert (Some hs'' == step_computation actor hstarts_atomic_block hends_atomic_block hstep hs);\n      let lem2 () : Lemma (states_match_except_global_variables vr.vs pc_relation ls'' hs'') = (\n        update_thread_pcs_in_states_maintains_states_match_except_gvars vr.vs pc_relation\n          actor ls' hs' lps.end_pc hps.end_pc\n      ) in\n      let lem3 () : Lemma (  global_variables_unaddressed_in_memory vr.vs ls''.mem\n                           /\\ global_variables_unaddressed_in_memory vr.vs hs''.mem\n                           /\\ roots_match ls''.mem\n                           /\\ roots_match hs''.mem) = (\n        assert (ls''.mem == ls'.mem);\n        assert (hs''.mem == hs'.mem)\n      ) in\n      lem1 ();\n      lem2 ();\n      lem3 ();\n      assert (states_match_except_global_variables vr.vs pc_relation ls'' hs'');\n      step_computation_maintains_all_gvars_have_types vr.vs vr.tds actor lstarts_atomic_block\n        lends_atomic_block lstep ls;\n      assert (all_gvars_have_types ls''.mem vr.vs vr.tds);\n      introduce NotStopped? ls''.stop_reason ==> vr.inv ls''\n      with _. vr.inv_is_substep_invariant_proof ()\n  | ComputationUndefined, ComputationUndefined ->\n      assert (not lstep.action.ok)\n\n#pop-options\n#push-options \"--z3rlimit 10\"\n\nlet executing_step_updating_gvars_maintains_invariant\n  (vr: var_hiding_relation_t)\n  (actor: tid_t)\n  (lstarts_atomic_block: bool)\n  (lends_atomic_block: bool)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  (lstep: Armada.Step.t)\n  (containing_latomic_action: list Armada.Action.t)\n  : Lemma (requires \n            (let pc_relation = var_hiding_pc_relation vr.lpc_to_hpc vr.return_lpcs vr.return_pcs_unique_proof in\n               var_hiding_lh_relation vr () ls hs\n             /\\ Some? (step_computation actor lstarts_atomic_block lends_atomic_block lstep ls)\n             /\\ contains_ubool lstep.action containing_latomic_action\n             /\\ contains_ubool containing_latomic_action vr.latomic_prog.actions\n             /\\ statement_updates_gvars vr.vs lstep.action.program_statement.statement\n             /\\ lstep.action.ok\n             /\\ Some? lstep.action.program_statement.end_pc\n             /\\ pc_relation.relation (Some?.v lstep.action.program_statement.end_pc) (hs.threads actor).pc\n             /\\ lstarts_atomic_block = lstep.action.program_statement.starts_atomic_block\n             /\\ lends_atomic_block = lstep.action.program_statement.ends_atomic_block\n             /\\ thread_state_applies ls actor (action_to_starting_thread_state lstep.action)))\n    (ensures  (match step_computation actor lstarts_atomic_block lends_atomic_block lstep ls with\n               | Some ls' -> var_hiding_lh_relation vr () ls' hs\n               | _ -> False)) =\n  let lthread = ls.threads actor in\n  let laction = lstep.action in\n  let lps = laction.program_statement in\n  let pc_relation = var_hiding_pc_relation vr.lpc_to_hpc vr.return_lpcs vr.return_pcs_unique_proof in\n  statement_that_updates_gvars_s1_only_maintains_states_match vr.vs pc_relation actor lstep.nd lthread.pc\n    lps.end_pc lps.statement ls hs;\n  match statement_computation actor lstep.nd lthread.pc lps.end_pc lps.statement ls with\n  | ComputationProduces ls' ->\n      update_thread_pc_in_state_maintains_states_match_except_gvars vr.vs pc_relation actor ls' hs\n        lps.end_pc;\n      let ls'' = update_thread_pc_in_state ls' actor lps.end_pc in\n      assert (states_match_except_global_variables vr.vs pc_relation ls'' hs);\n      assert (global_variables_unaddressed_in_memory vr.vs ls''.mem);\n      executing_statement_maintains_unstarted_threads_have_empty_write_buffers actor lstep.nd\n        lthread.pc lps.end_pc lps.statement ls;\n      assert (unstarted_threads_have_empty_write_buffers ls'');\n      step_computation_maintains_all_gvars_have_types vr.vs vr.tds actor lstarts_atomic_block\n        lends_atomic_block lstep ls;\n      assert (all_gvars_have_types ls''.mem vr.vs vr.tds);\n      introduce NotStopped? ls''.stop_reason ==> vr.inv ls''\n      with _. vr.inv_is_substep_invariant_proof ()\n  | ComputationUndefined ->\n      ()\n\n#pop-options\n#push-options \"--z3rlimit 40\"\n\nlet rec establish_normal_lifter_given_hsteps_at_correct_pc\n  (vr: var_hiding_relation_t)\n  (actor: tid_t)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  (lstart_state: thread_state_t)\n  (hstart_state: thread_state_t)\n  (lend_state: thread_state_t)\n  (hend_state: thread_state_t)\n  (which_actions_hidden: list bool)\n  (lactions: list Armada.Action.t)\n  (hactions: list Armada.Action.t)\n  (lsteps: list Armada.Step.t)\n  (hsteps: list Armada.Step.t)\n  (containing_latomic_action: list Armada.Action.t)\n  : Lemma (requires\n            (let pc_relation = var_hiding_pc_relation vr.lpc_to_hpc vr.return_lpcs vr.return_pcs_unique_proof in\n             let lstarts_atomic_block = actions_start_atomic_block lactions in\n             let lends_atomic_block = actions_end_atomic_block lactions in\n               var_hiding_lh_relation vr () ls hs\n             /\\ (Some? (steps_computation_permitting_empty actor lstarts_atomic_block lends_atomic_block lsteps ls))\n             /\\ (forall laction. contains_ubool laction lactions ==> contains_ubool laction containing_latomic_action)\n             /\\ contains_ubool containing_latomic_action vr.latomic_prog.actions\n             /\\ lactions == map_ghost armada_step_to_action lsteps\n             /\\ hactions == map_ghost armada_step_to_action hsteps\n             /\\ lsteps_correspond_to_hsteps vr.vs pc_relation\n                 lstart_state hstart_state lend_state hend_state which_actions_hidden lsteps hsteps\n             /\\ action_list_doesnt_internally_yield lactions\n             /\\ action_list_doesnt_internally_yield hactions\n             /\\ thread_states_match_per_pc_relation pc_relation.relation lstart_state hstart_state\n             /\\ thread_state_applies ls actor lstart_state\n             /\\ thread_state_applies hs actor hstart_state\n             /\\ each_action_ends_atomic_block_if_necessary hactions))\n    (ensures (let lstarts_atomic_block = actions_start_atomic_block lactions in\n              let lends_atomic_block = actions_end_atomic_block lactions in\n              let hstarts_atomic_block = actions_start_atomic_block hactions in\n              let hends_atomic_block = actions_end_atomic_block hactions in\n              match steps_computation_permitting_empty actor lstarts_atomic_block lends_atomic_block lsteps ls,\n                    steps_computation_permitting_empty actor hstarts_atomic_block hends_atomic_block hsteps hs with\n               | Some ls', Some hs' -> var_hiding_lh_relation vr () ls' hs'\n               | _, _ -> False))\n    (decreases lsteps) =\n  let pc_relation = var_hiding_pc_relation vr.lpc_to_hpc vr.return_lpcs vr.return_pcs_unique_proof in\n  match which_actions_hidden, lactions, hactions, lsteps, hsteps with\n  | [], [], [], [], [] -> ()\n  | false :: remaining_which_actions_hidden, laction :: remaining_lactions, haction :: remaining_hactions,\n      lstep :: remaining_lsteps, hstep :: remaining_hsteps ->\n      let lthread = ls.threads actor in\n      let hthread = hs.threads actor in\n      let lps = laction.program_statement in\n      let hps = haction.program_statement in\n      let lstep: Armada.Step.t = lstep in\n      let hstep: Armada.Step.t = hstep in\n      let lstarts_atomic_block = actions_start_atomic_block lactions in\n      let lends_atomic_block = actions_end_atomic_block lactions in\n      let hstarts_atomic_block = actions_start_atomic_block hactions in\n      let hends_atomic_block = actions_end_atomic_block hactions in\n      let laction_ends_atomic_block = lps.ends_atomic_block || not laction.ok in\n      let haction_ends_atomic_block = hps.ends_atomic_block || not haction.ok in\n      assert (laction_ends_atomic_block = (if (Cons? remaining_lsteps) then false else lends_atomic_block));\n      assert (haction_ends_atomic_block = (if (Cons? remaining_hsteps) then false else hends_atomic_block));\n      executing_matching_steps_maintains_invariant vr actor lstart_state hstart_state\n        (action_to_ending_thread_state lstep.action) (action_to_ending_thread_state hstep.action)\n        lstarts_atomic_block hstarts_atomic_block laction_ends_atomic_block haction_ends_atomic_block\n        ls hs lstep hstep containing_latomic_action;\n      (match step_computation actor lstarts_atomic_block laction_ends_atomic_block lstep ls,\n             step_computation actor hstarts_atomic_block haction_ends_atomic_block hstep hs with\n       | Some ls', Some hs' ->\n           step_computation_has_thread_state_effect actor lstarts_atomic_block laction_ends_atomic_block lstep ls;\n           step_computation_has_thread_state_effect actor hstarts_atomic_block haction_ends_atomic_block hstep hs;\n           step_computation_has_thread_state_effect actor lstarts_atomic_block laction_ends_atomic_block lstep ls;\n           step_computation_has_thread_state_effect actor hstarts_atomic_block haction_ends_atomic_block hstep hs;\n           establish_normal_lifter_given_hsteps_at_correct_pc vr actor ls' hs'\n             (action_to_ending_thread_state lstep.action)\n             (action_to_ending_thread_state hstep.action)\n             lend_state hend_state remaining_which_actions_hidden remaining_lactions remaining_hactions remaining_lsteps\n             remaining_hsteps containing_latomic_action\n       | _, _ -> ())\n  | true :: remaining_which_actions_hidden, laction :: remaining_lactions, _, lstep :: remaining_lsteps, _ ->\n      let lthread = ls.threads actor in\n      let lps = laction.program_statement in\n      let lstep: Armada.Step.t = lstep in\n      let lstarts_atomic_block = actions_start_atomic_block lactions in\n      let lends_atomic_block = actions_end_atomic_block lactions in\n      let laction_ends_atomic_block = lps.ends_atomic_block || not laction.ok in\n      assert (laction_ends_atomic_block = (if (Cons? remaining_lsteps) then false else lends_atomic_block));\n      assert (Some? (step_computation actor lstarts_atomic_block laction_ends_atomic_block lstep ls));\n      executing_step_updating_gvars_maintains_invariant vr actor lstarts_atomic_block laction_ends_atomic_block\n        ls hs lstep containing_latomic_action;\n      (match step_computation actor lstarts_atomic_block laction_ends_atomic_block lstep ls with\n       | Some ls' ->\n           step_computation_has_thread_state_effect actor lstarts_atomic_block\n             laction_ends_atomic_block lstep ls;\n           step_computation_has_thread_state_effect actor lstarts_atomic_block\n             laction_ends_atomic_block lstep ls;\n           establish_normal_lifter_given_hsteps_at_correct_pc vr actor ls' hs\n             (action_to_ending_thread_state lstep.action) hstart_state lend_state hend_state\n             remaining_which_actions_hidden remaining_lactions hactions remaining_lsteps hsteps\n             containing_latomic_action\n       | None -> ())\n  | _, _, _, _, _ -> ()\n\n#pop-options\n\nlet get_normal_lifter_given_hsteps_at_correct_pc\n  (vr: var_hiding_relation_t)\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  (lstart_state: thread_state_t)\n  (hstart_state: thread_state_t)\n  (lend_state: thread_state_t)\n  (hend_state: thread_state_t)\n  (which_actions_hidden: list bool)\n  (lactions: list Armada.Action.t)\n  (hactions: list Armada.Action.t)\n  (lsteps: list Armada.Step.t)\n  (hsteps: list Armada.Step.t)\n  : Ghost (step_lifter_t (list Armada.Step.t) unit)\n    (requires (let pc_relation = var_hiding_pc_relation vr.lpc_to_hpc vr.return_lpcs vr.return_pcs_unique_proof in\n                 var_hiding_lh_relation vr () ls hs\n               /\\ Some? (steps_computation_generic armada_semantics actor\n                          starts_atomic_block ends_atomic_block lsteps ls)\n               /\\ lactions == map_ghost armada_step_to_action lsteps\n               /\\ hactions == map_ghost armada_step_to_action hsteps\n               /\\ contains_ubool lactions vr.latomic_prog.actions\n               /\\ contains_ubool hactions vr.hatomic_prog.actions\n               /\\ lsteps_correspond_to_hsteps vr.vs pc_relation\n                   lstart_state hstart_state lend_state hend_state which_actions_hidden lsteps hsteps\n               /\\ do_actions_start_and_end_atomic_block lactions = do_actions_start_and_end_atomic_block hactions\n               /\\ thread_states_match_per_pc_relation pc_relation.relation lstart_state hstart_state\n               /\\ thread_state_applies ls actor lstart_state\n               /\\ thread_state_applies hs actor hstart_state\n               /\\ Cons? hactions))\n    (ensures  fun lifter -> step_lifter_works\n                           (make_atomic_semantics armada_semantics)\n                           (make_atomic_semantics armada_semantics)\n                           vr.latomic_prog vr.hatomic_prog unit (var_hiding_lh_relation vr)\n                           nat (default_wfr nat)\n                           (var_hiding_progress_measure vr) actor starts_atomic_block ends_atomic_block\n                           lsteps ls hs lifter) =\n  steps_computation_implies_start_and_end_atomic_block actor starts_atomic_block ends_atomic_block lsteps ls;\n  let pc_relation = var_hiding_pc_relation vr.lpc_to_hpc vr.return_lpcs vr.return_pcs_unique_proof in\n  assert (var_hiding_lh_relation vr () ls hs);\n  armada_steps_computation_equivalent actor starts_atomic_block ends_atomic_block lsteps ls;\n  assert (Some? (steps_computation_permitting_empty actor starts_atomic_block ends_atomic_block lsteps ls));\n  vr.each_laction_doesnt_internally_yield_proof ();\n  assert (action_list_doesnt_internally_yield lactions);\n  vr.each_haction_doesnt_internally_yield_proof ();\n  assert (action_list_doesnt_internally_yield hactions);\n  vr.each_haction_ends_atomic_block_if_necessary_proof ();\n  assert (each_action_ends_atomic_block_if_necessary hactions);\n  establish_normal_lifter_given_hsteps_at_correct_pc vr actor ls hs\n    lstart_state hstart_state lend_state hend_state which_actions_hidden lactions hactions lsteps hsteps\n    lactions;\n  armada_steps_computation_equivalent actor starts_atomic_block ends_atomic_block hsteps hs;\n  StepLifterLift hsteps ()\n\n#push-options \"--z3rlimit 10\"\n\nlet rec establish_skip_lifter_given_hsteps_at_correct_pc\n  (vr: var_hiding_relation_t)\n  (actor: tid_t)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  (lstart_state: thread_state_t)\n  (lend_state: thread_state_t)\n  (lactions: list Armada.Action.t)\n  (lsteps: list Armada.Step.t)\n  (containing_latomic_action: list Armada.Action.t)\n  : Lemma (requires\n            (let pc_relation = var_hiding_pc_relation vr.lpc_to_hpc vr.return_lpcs vr.return_pcs_unique_proof in\n             let lstarts_atomic_block = actions_start_atomic_block lactions in\n             let lends_atomic_block = actions_end_atomic_block lactions in\n               var_hiding_lh_relation vr () ls hs\n             /\\ (Some? (steps_computation_permitting_empty actor lstarts_atomic_block\n                         lends_atomic_block lsteps ls))\n             /\\ lactions == map_ghost armada_step_to_action lsteps\n             /\\ lactions_all_hidden vr.vs vr.lpc_to_hpc lstart_state lend_state lactions\n             /\\ (forall laction. contains_ubool laction lactions ==> contains_ubool laction containing_latomic_action)\n             /\\ contains_ubool containing_latomic_action vr.latomic_prog.actions\n             /\\ action_list_doesnt_internally_yield lactions\n             /\\ thread_state_applies ls actor lstart_state))\n    (ensures (let lstarts_atomic_block = actions_start_atomic_block lactions in\n              let lends_atomic_block = actions_end_atomic_block lactions in\n              match steps_computation_permitting_empty actor lstarts_atomic_block lends_atomic_block lsteps ls with\n              | Some ls' -> var_hiding_lh_relation vr () ls' hs\n              | _ -> False))\n    (decreases lsteps) =\n  let pc_relation = var_hiding_pc_relation vr.lpc_to_hpc vr.return_lpcs vr.return_pcs_unique_proof in\n  match lactions, lsteps with\n  | [], [] -> ()\n  | laction :: remaining_lactions, lstep :: remaining_lsteps ->\n      let lthread = ls.threads actor in\n      let lps = laction.program_statement in\n      let lstep: Armada.Step.t = lstep in\n      let lstarts_atomic_block = actions_start_atomic_block lactions in\n      let lends_atomic_block = actions_end_atomic_block lactions in\n      let laction_ends_atomic_block = lps.ends_atomic_block || not laction.ok in\n      assert (laction_ends_atomic_block = (if (Cons? remaining_lsteps) then false else lends_atomic_block));\n      assert (Some? (step_computation actor lstarts_atomic_block laction_ends_atomic_block lstep ls));\n      executing_step_updating_gvars_maintains_invariant vr actor lstarts_atomic_block laction_ends_atomic_block\n        ls hs lstep containing_latomic_action;\n      (match step_computation actor lstarts_atomic_block laction_ends_atomic_block lstep ls with\n       | Some ls' ->\n           step_computation_has_thread_state_effect actor lstarts_atomic_block\n             laction_ends_atomic_block lstep ls;\n           step_computation_has_thread_state_effect actor lstarts_atomic_block\n             laction_ends_atomic_block lstep ls;\n           establish_skip_lifter_given_hsteps_at_correct_pc vr actor ls' hs\n             (action_to_ending_thread_state lstep.action) lend_state\n             remaining_lactions remaining_lsteps containing_latomic_action\n       | None -> ())\n\nlet get_skip_lifter_given_steps_at_correct_pc\n  (vr: var_hiding_relation_t)\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  (lstart_state: thread_state_t)\n  (lend_state: thread_state_t)\n  (lactions: list Armada.Action.t)\n  (lsteps: list Armada.Step.t)\n  : Ghost (step_lifter_t (list Armada.Step.t) unit)\n    (requires (let pc_relation = var_hiding_pc_relation vr.lpc_to_hpc vr.return_lpcs vr.return_pcs_unique_proof in\n                 var_hiding_lh_relation vr () ls hs\n               /\\ Some? (steps_computation_generic armada_semantics actor\n                          starts_atomic_block ends_atomic_block lsteps ls)\n               /\\ lactions == map_ghost armada_step_to_action lsteps\n               /\\ contains_ubool lactions vr.latomic_prog.actions\n               /\\ lactions_all_hidden vr.vs vr.lpc_to_hpc lstart_state lend_state lactions\n               /\\ actions_start_atomic_block lactions = actions_end_atomic_block lactions\n               /\\ thread_state_applies ls actor lstart_state))\n    (ensures  fun lifter -> step_lifter_works\n                           (make_atomic_semantics armada_semantics)\n                           (make_atomic_semantics armada_semantics)\n                           vr.latomic_prog vr.hatomic_prog unit (var_hiding_lh_relation vr)\n                           nat (default_wfr nat)\n                           (var_hiding_progress_measure vr) actor starts_atomic_block ends_atomic_block\n                           lsteps ls hs lifter) =\n  steps_computation_implies_start_and_end_atomic_block actor starts_atomic_block ends_atomic_block lsteps ls;\n  let pc_relation = var_hiding_pc_relation vr.lpc_to_hpc vr.return_lpcs vr.return_pcs_unique_proof in\n  assert (var_hiding_lh_relation vr () ls hs);\n  armada_steps_computation_equivalent actor starts_atomic_block ends_atomic_block lsteps ls;\n  assert (Some? (steps_computation_permitting_empty actor starts_atomic_block ends_atomic_block lsteps ls));\n  vr.each_laction_doesnt_internally_yield_proof ();\n  assert (action_list_doesnt_internally_yield lactions);\n  establish_skip_lifter_given_hsteps_at_correct_pc vr actor ls hs lstart_state lend_state lactions lsteps lactions;\n  StepLifterSkip ()\n\nlet get_skip_lifter\n  (vr: var_hiding_relation_t)\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  (lstart_state: thread_state_t)\n  (lend_state: thread_state_t)\n  (lactions: list Armada.Action.t)\n  (lsteps: list Armada.Step.t)\n  : Ghost (step_lifter_t (list Armada.Step.t) unit)\n    (requires (let pc_relation = var_hiding_pc_relation vr.lpc_to_hpc vr.return_lpcs vr.return_pcs_unique_proof in\n                 var_hiding_lh_relation vr () ls hs\n               /\\ Some? (steps_computation_generic armada_semantics actor\n                          starts_atomic_block ends_atomic_block lsteps ls)\n               /\\ lactions == map_ghost armada_step_to_action lsteps\n               /\\ contains_ubool lactions vr.latomic_prog.actions\n               /\\ lactions_all_hidden vr.vs vr.lpc_to_hpc lstart_state lend_state lactions\n               /\\ actions_start_atomic_block lactions = actions_end_atomic_block lactions))\n    (ensures  fun lifter -> step_lifter_works\n                           (make_atomic_semantics armada_semantics)\n                           (make_atomic_semantics armada_semantics)\n                           vr.latomic_prog vr.hatomic_prog unit (var_hiding_lh_relation vr)\n                           nat (default_wfr nat)\n                           (var_hiding_progress_measure vr) actor starts_atomic_block ends_atomic_block\n                           lsteps ls hs lifter) =\n  armada_steps_computation_equivalent actor starts_atomic_block ends_atomic_block lsteps ls;\n  steps_computation_requires_start_thread_state actor starts_atomic_block ends_atomic_block lsteps ls;\n  let lthread = ls.threads actor in\n  let pc_relation = var_hiding_pc_relation vr.lpc_to_hpc vr.return_lpcs vr.return_pcs_unique_proof in\n  match lstart_state with\n  | ThreadStateAtPC start_lpc ->\n      assert (lstart_state = action_to_starting_thread_state (Cons?.hd lsteps).action);\n      assert (lthread.pc = start_lpc);\n      assert (threads_match_except_global_variables vr.vs pc_relation ls.threads hs.threads);\n      assert (ThreadStatusRunning? lthread.status);\n      get_skip_lifter_given_steps_at_correct_pc vr actor starts_atomic_block ends_atomic_block ls hs\n        lstart_state lend_state lactions lsteps\n  | _ -> false_elim ()\n\nlet get_normal_lifter_given_hsteps\n  (vr: var_hiding_relation_t)\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  (lstart_state: thread_state_t)\n  (hstart_state: thread_state_t)\n  (lend_state: thread_state_t)\n  (hend_state: thread_state_t)\n  (which_actions_hidden: list bool)\n  (lactions: list Armada.Action.t)\n  (hactions: list Armada.Action.t)\n  (lsteps: list Armada.Step.t)\n  (hsteps: list Armada.Step.t)\n  : Ghost (step_lifter_t (list Armada.Step.t) unit)\n    (requires (let pc_relation = var_hiding_pc_relation vr.lpc_to_hpc vr.return_lpcs vr.return_pcs_unique_proof in\n                 var_hiding_lh_relation vr () ls hs\n               /\\ Some? (steps_computation_generic armada_semantics actor\n                          starts_atomic_block ends_atomic_block lsteps ls)\n               /\\ lactions == map_ghost armada_step_to_action lsteps\n               /\\ hactions == map_ghost armada_step_to_action hsteps\n               /\\ contains_ubool lactions vr.latomic_prog.actions\n               /\\ contains_ubool hactions vr.hatomic_prog.actions\n               /\\ lsteps_correspond_to_hsteps vr.vs pc_relation\n                   lstart_state hstart_state lend_state hend_state which_actions_hidden lsteps hsteps\n               /\\ do_actions_start_and_end_atomic_block lactions = do_actions_start_and_end_atomic_block hactions\n               /\\ Cons? hactions))\n    (ensures  fun lifter -> step_lifter_works\n                           (make_atomic_semantics armada_semantics)\n                           (make_atomic_semantics armada_semantics)\n                           vr.latomic_prog vr.hatomic_prog unit (var_hiding_lh_relation vr)\n                           nat (default_wfr nat)\n                           (var_hiding_progress_measure vr) actor starts_atomic_block ends_atomic_block\n                           lsteps ls hs lifter) =\n  armada_steps_computation_equivalent actor starts_atomic_block ends_atomic_block lsteps ls;\n  steps_computation_requires_start_thread_state actor starts_atomic_block ends_atomic_block lsteps ls;\n  let lthread = ls.threads actor in\n  let hthread = hs.threads actor in\n  let pc_relation = var_hiding_pc_relation vr.lpc_to_hpc vr.return_lpcs vr.return_pcs_unique_proof in\n  lsteps_correspond_to_hsteps_implies_first_lstep_matches_lstart_state vr.vs pc_relation lstart_state hstart_state\n    lend_state hend_state which_actions_hidden lsteps hsteps;\n  match lstart_state, hstart_state with\n  | ThreadStateAtPC start_lpc, ThreadStateAtPC start_hpc ->\n      assert (lstart_state = action_to_starting_thread_state (Cons?.hd lsteps).action);\n      assert (lthread.pc = start_lpc);\n      assert (threads_match_except_global_variables vr.vs pc_relation ls.threads hs.threads);\n      assert (ThreadStatusRunning? lthread.status);\n      assert (pc_relation.relation lthread.pc hthread.pc);\n      assert (vr.lpc_to_hpc lthread.pc = hthread.pc);\n      assert (hthread.pc = start_hpc);\n      get_normal_lifter_given_hsteps_at_correct_pc vr actor starts_atomic_block ends_atomic_block ls hs\n        lstart_state hstart_state lend_state hend_state which_actions_hidden lactions hactions lsteps hsteps\n  | _, _ -> false_elim ()\n\nlet rec impossible_constant_assignment_failure_is_impossible\n  (vr: var_hiding_relation_t)\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (s: Armada.State.t)\n  (steps: list Armada.Step.t)\n  (actions: list Armada.Action.t)\n  (containing_latomic_action: list Armada.Action.t)\n  : Lemma (requires   all_gvars_have_types s.mem vr.vs vr.tds\n                    /\\ (NotStopped? s.stop_reason ==> vr.inv s)\n                    /\\ actions == map_ghost armada_step_to_action steps\n                    /\\ Some? (steps_computation_generic armada_semantics actor\n                               starts_atomic_block ends_atomic_block steps s)\n                    /\\ lactions_fail_final_statement_updating_gvars_using_constant vr.vs vr.tds actions\n                    /\\ (forall action. contains_ubool action actions ==> contains_ubool action containing_latomic_action)\n                    /\\ contains_ubool containing_latomic_action vr.latomic_prog.actions)\n          (ensures  False)\n          (decreases actions) =\n  match steps, actions with\n  | [step], [action] ->\n      let ps = action.program_statement in\n      let start_pc = (s.threads actor).pc in\n      statement_that_updates_gvars_using_constant_must_succeed vr.vs vr.tds actor start_pc ps.end_pc ps.statement s\n  | first_step :: remaining_steps, first_action :: remaining_actions ->\n      (match step_computation actor starts_atomic_block false first_step s with\n       | Some s' ->\n           introduce NotStopped? s'.stop_reason ==> vr.inv s'\n           with _. vr.inv_is_substep_invariant_proof ();\n           step_computation_maintains_all_gvars_have_types vr.vs vr.tds actor starts_atomic_block\n             false first_step s;\n           impossible_constant_assignment_failure_is_impossible vr actor false ends_atomic_block s'\n             remaining_steps remaining_actions containing_latomic_action\n       | None -> false_elim ())\n\nlet rec impossible_statement_failure_is_impossible\n  (vr: var_hiding_relation_t)\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (s: Armada.State.t)\n  (steps: list Armada.Step.t)\n  (actions: list Armada.Action.t)\n  (ps: program_statement_t)\n  (proof: program_statement_succeeds_proof_t vr.vs vr.tds vr.inv ps)\n  (containing_latomic_action: list Armada.Action.t)\n  : Lemma (requires   all_gvars_have_types s.mem vr.vs vr.tds\n                    /\\ Cons? actions\n                    /\\ thread_state_applies s actor (action_to_starting_thread_state (Cons?.hd actions))\n                    /\\ vr.inv s\n                    /\\ actions == map_ghost armada_step_to_action steps\n                    /\\ Some? (steps_computation_generic armada_semantics actor\n                               starts_atomic_block ends_atomic_block steps s)\n                    /\\ lactions_fail_specific_final_statement ps actions\n                    /\\ (forall action. contains_ubool action actions ==> contains_ubool action containing_latomic_action)\n                    /\\ contains_ubool containing_latomic_action vr.latomic_prog.actions)\n          (ensures  False)\n          (decreases actions) =\n  match steps, actions with\n  | [step], [action] ->\n      assert (Some? (steps_computation actor starts_atomic_block ends_atomic_block steps s));\n      assert (Some? (step_computation actor starts_atomic_block ends_atomic_block step s));\n      assert (not action.ok);\n      assert (ComputationUndefined? (statement_computation actor step.nd (s.threads actor).pc\n                action.program_statement.end_pc action.program_statement.statement s));\n      proof actor step.nd s\n  | first_step :: remaining_steps, first_action :: remaining_actions ->\n      (match step_computation actor starts_atomic_block false first_step s with\n       | Some s' ->\n           introduce NotStopped? s'.stop_reason ==> vr.inv s'\n           with _. vr.inv_is_substep_invariant_proof ();\n           step_computation_maintains_all_gvars_have_types vr.vs vr.tds actor starts_atomic_block\n             false first_step s;\n           step_computation_has_thread_state_effect actor starts_atomic_block false first_step s;\n           impossible_statement_failure_is_impossible vr actor false ends_atomic_block s'\n             remaining_steps remaining_actions ps proof containing_latomic_action\n       | None -> false_elim ())\n\nlet get_normal_lifter\n  (vr: var_hiding_relation_t)\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  (lsteps: list Armada.Step.t)\n  : Ghost (step_lifter_t (list Armada.Step.t) unit)\n    (requires   var_hiding_lh_relation vr () ls hs\n              /\\ Some? (steps_computation_generic armada_semantics actor\n                         starts_atomic_block ends_atomic_block lsteps ls)\n              /\\ contains_ubool (map_ghost armada_step_to_action lsteps) vr.latomic_prog.actions\n              /\\ ~((Cons?.hd lsteps).action.program_statement.statement == PropagateWriteMessageStatement))\n    (ensures  fun lifter -> step_lifter_works\n                           (make_atomic_semantics armada_semantics)\n                           (make_atomic_semantics armada_semantics)\n                           vr.latomic_prog vr.hatomic_prog unit (var_hiding_lh_relation vr)\n                           nat (default_wfr nat)\n                           (var_hiding_progress_measure vr) actor starts_atomic_block ends_atomic_block\n                           lsteps ls hs lifter) =\n  vr.corresponding_hactions_correspond_proof ();\n  let lactions = map_ghost armada_step_to_action lsteps in\n  let correspondence = get_correspondent_from_lists_correspond_ubool\n    (lactions_correspond_to_hactions_per_correspondence vr.vs vr.tds vr.inv vr.lpc_to_hpc vr.return_lpcs\n       vr.hatomic_prog.actions)\n    vr.latomic_prog.actions\n    vr.corresponding_hactions_info\n    lactions in\n  match correspondence with\n  | CorrespondenceHidden ->\n      let lstart_state = action_to_starting_thread_state (Cons?.hd lactions) in\n      let lend_state = actions_to_ending_thread_state lactions in\n      get_skip_lifter vr actor starts_atomic_block ends_atomic_block ls hs\n        lstart_state lend_state lactions lsteps\n  | CorrespondencePropagate hidx -> false_elim ()\n  | CorrespondenceNormal hidx which_actions_hidden ->\n      (match list_nth vr.hatomic_prog.actions hidx with\n       | Some hactions ->\n           let pc_relation = var_hiding_pc_relation vr.lpc_to_hpc vr.return_lpcs vr.return_pcs_unique_proof in\n           nth_implies_contains_ubool vr.hatomic_prog.actions hidx hactions;\n           let lstart_state = action_to_starting_thread_state (Cons?.hd lactions) in\n           let lend_state = actions_to_ending_thread_state lactions in\n           let hstart_state = action_to_starting_thread_state (Cons?.hd hactions) in\n           let hend_state = actions_to_ending_thread_state hactions in\n           let hsteps = compute_hsteps_from_lsteps vr.vs vr.lpc_to_hpc\n                          vr.return_lpcs vr.return_pcs_unique_proof\n                          lstart_state hstart_state lend_state\n                          hend_state which_actions_hidden lactions hactions lsteps in\n           get_normal_lifter_given_hsteps vr actor starts_atomic_block ends_atomic_block ls hs\n             lstart_state hstart_state lend_state hend_state which_actions_hidden lactions hactions lsteps hsteps\n       | None -> false_elim ())\n  | CorrespondenceImpossibleConstantAssignmentFailure ->\n      impossible_constant_assignment_failure_is_impossible vr actor starts_atomic_block ends_atomic_block ls\n        lsteps lactions lactions;\n      false_elim ()\n  | CorrespondenceImpossibleStatementFailure ps proof ->\n      impossible_statement_failure_is_impossible vr actor starts_atomic_block ends_atomic_block ls\n        lsteps lactions ps proof lactions;\n      false_elim ()\n\n#pop-options\n\nlet get_lifter_for_path\n  (vr: var_hiding_relation_t)\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  (lsteps: list Armada.Step.t)\n  : Ghost (step_lifter_t (list Armada.Step.t) unit)\n    (requires   var_hiding_lh_relation vr () ls hs\n              /\\ Some? (steps_computation_generic armada_semantics actor\n                         starts_atomic_block ends_atomic_block lsteps ls)\n              /\\ contains_ubool (map_ghost armada_step_to_action lsteps) vr.latomic_prog.actions)\n    (ensures  fun lifter -> step_lifter_works\n                           (make_atomic_semantics armada_semantics)\n                           (make_atomic_semantics armada_semantics)\n                           vr.latomic_prog vr.hatomic_prog unit (var_hiding_lh_relation vr)\n                           nat (default_wfr nat)\n                           (var_hiding_progress_measure vr) actor starts_atomic_block ends_atomic_block\n                           lsteps ls hs lifter) =\n  match lsteps with\n  | first_step :: remaining_steps ->\n      (match first_step.action.program_statement.statement with\n       | PropagateWriteMessageStatement ->\n           get_propagate_lifter vr actor starts_atomic_block ends_atomic_block ls hs lsteps\n       | _ -> get_normal_lifter vr actor starts_atomic_block ends_atomic_block ls hs lsteps)\n\nlet paths_liftable_proof\n  (vr: var_hiding_relation_t)\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (aux: unit)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  (lsteps: list Armada.Step.t{\n       var_hiding_invariant ls\n     /\\ var_hiding_lh_relation vr aux ls hs\n     /\\ Some? (step_computation_generic (make_atomic_semantics armada_semantics)\n                actor starts_atomic_block ends_atomic_block lsteps ls)\n     /\\ program_contains_action_of_step_generic (make_atomic_semantics armada_semantics)\n         vr.latomic_prog lsteps})\n  : GTot (lifter: (step_lifter_t (list Armada.Step.t) unit){\n            step_lifter_works\n              (make_atomic_semantics armada_semantics)\n              (make_atomic_semantics armada_semantics)\n              vr.latomic_prog vr.hatomic_prog unit (var_hiding_lh_relation vr)\n              nat (default_wfr nat)\n              (var_hiding_progress_measure vr) actor starts_atomic_block ends_atomic_block\n              lsteps ls hs lifter}) =\n  get_lifter_for_path vr actor starts_atomic_block ends_atomic_block ls hs lsteps\n\nlet inv_stepwise_invariant_proof\n  (vr: var_hiding_relation_t)\n  : Lemma (semantics_has_stepwise_inductive_invariant (make_atomic_semantics armada_semantics)\n             vr.latomic_prog var_hiding_invariant) =\n  ()\n\nlet initialize_hstate\n  (vr: var_hiding_relation_t)\n  (ls: Armada.State.t)\n  : GTot Armada.State.t =\n  let mem' = remove_hidden_initializers vr.which_initializers_are_hidings vr.lprog.global_initializers ls.mem in\n  let thread = ls.threads ls.initial_tid in\n  let thread' = { thread with pc = vr.hprog.main_start_pc } in\n  let threads' = Spec.Map.upd ls.threads ls.initial_tid thread' in\n  { ls with mem = mem'; threads = threads' }\n\nlet initialize_hstate_satisfies_hinit\n  (vr: var_hiding_relation_t)\n  (ls: Armada.State.t)\n  : Lemma (requires init_program vr.lprog ls)\n          (ensures  init_program vr.hprog (initialize_hstate vr ls)) =\n  let hs = initialize_hstate vr ls in\n  vr.program_inits_match_except_global_variables_proof ();\n  remove_hidden_initializers_ensures_satisfies_global_initializers vr.vs vr.which_initializers_are_hidings\n    vr.lprog.global_initializers vr.hprog.global_initializers ls.mem;\n  let thread = hs.threads hs.initial_tid in\n  let initial_frame_uniq = Cons?.hd hs.uniqs_used in\n  remove_hidden_initializers_ensures_satisfies_main_stack_initializers vr.vs vr.which_initializers_are_hidings\n    vr.lprog.global_initializers hs.initial_tid vr.hprog.main_method_id initial_frame_uniq\n    thread.top.local_variables vr.hprog.main_stack_initializers ls.mem;\n  remove_hidden_initializers_ensures_memory_invalid_outside_initializations vr.vs vr.which_initializers_are_hidings\n    vr.lprog.global_initializers vr.hprog.global_initializers hs.initial_tid vr.hprog.main_method_id initial_frame_uniq\n    thread.top.local_variables ls.mem\n\n#push-options \"--z3rlimit 10\"\n\nlet initialize_hstate_satisfies_threads_match_except_global_variables\n  (vr: var_hiding_relation_t)\n  (ls: Armada.State.t)\n  : Lemma (requires init_program vr.lprog ls)\n          (ensures  (let pc_relation = var_hiding_pc_relation vr.lpc_to_hpc vr.return_lpcs\n                                         vr.return_pcs_unique_proof in\n                     let hs = initialize_hstate vr ls in\n                     threads_match_except_global_variables vr.vs pc_relation ls.threads hs.threads)) =\n  vr.initial_pcs_correspond_proof ()\n\n#pop-options\n\nlet initialize_hstate_satisfies_var_hiding_lh_relation\n  (vr: var_hiding_relation_t)\n  (ls: Armada.State.t)\n  : Lemma (requires init_program vr.lprog ls)\n          (ensures var_hiding_lh_relation vr () ls (initialize_hstate vr ls)) =\n  let hs = initialize_hstate vr ls in\n  initialize_hstate_satisfies_hinit vr ls;\n  vr.program_inits_match_except_global_variables_proof ();\n  remove_hidden_initializers_ensures_satisfies_global_initializers vr.vs vr.which_initializers_are_hidings\n    vr.lprog.global_initializers vr.hprog.global_initializers ls.mem;\n  init_implies_positions_valid_in_state vr.hprog hs;\n  init_implies_roots_match vr.hprog hs;\n  init_implies_unstarted_threads_have_empty_write_buffers vr.hprog hs;\n  init_implies_positions_valid_in_state vr.lprog ls;\n  init_implies_roots_match vr.lprog ls;\n  init_implies_unstarted_threads_have_empty_write_buffers vr.lprog ls;\n  let pc_relation = var_hiding_pc_relation vr.lpc_to_hpc vr.return_lpcs vr.return_pcs_unique_proof in\n  initialize_hstate_satisfies_threads_match_except_global_variables vr ls;\n  init_implies_roots_match vr.lprog ls;\n  init_implies_roots_match vr.hprog hs;\n  init_implies_unstarted_threads_have_empty_write_buffers vr.lprog ls;\n  init_implies_unstarted_threads_have_empty_write_buffers vr.hprog hs;\n  vr.global_variables_unaddressed_in_initializers_proof ();\n  init_implies_global_variables_unaddressed_in_memory vr.vs vr.lprog ls;\n  init_implies_global_variables_unaddressed_in_memory vr.vs vr.hprog hs;\n  vr.all_introduced_global_variables_initialized_proof ();\n  initialization_ensures_all_gvars_have_types vr.vs vr.tds vr.lprog.global_initializers ls.mem;\n  assert (all_gvars_have_types ls.mem vr.vs vr.tds);\n  introduce NotStopped? ls.stop_reason ==> vr.inv ls\n  with _. (\n    vr.inv_is_substep_invariant_proof ();\n    vr.atomic_inits_match_regular_inits_proof ();\n    assert (vr.latomic_prog.init_f ls)\n  )\n\nlet init_implies_relation_proof\n  (vr: var_hiding_relation_t)\n  (ls: Armada.State.t{vr.latomic_prog.init_f ls})\n  : GTot (hs_aux: (Armada.State.t * unit){\n            let hs, aux = hs_aux in\n            vr.hatomic_prog.init_f hs /\\ var_hiding_lh_relation vr aux ls hs}) =\n  let hs = initialize_hstate vr ls in\n  let aux = () in\n  vr.atomic_inits_match_regular_inits_proof ();\n  initialize_hstate_satisfies_var_hiding_lh_relation vr ls;\n  initialize_hstate_satisfies_hinit vr ls;\n  (hs, aux)\n\nlet lh_relation_implies_refinement_proof\n  (vr: var_hiding_relation_t)\n  (aux: unit)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t{var_hiding_invariant ls /\\ var_hiding_lh_relation vr aux ls hs})\n  : squash (refinement_requirement ls hs) =\n  ()\n\nlet var_hiding_relation_implies_refinement (vr: var_hiding_relation_t)\n  (* see .fsti file for spec *) =\n  let lr: liftability_relation_t = {\n    lsem = make_atomic_semantics armada_semantics;\n    hsem = make_atomic_semantics armada_semantics;\n    lprog = vr.latomic_prog;\n    hprog = vr.hatomic_prog;\n    aux_t = unit;\n    inv = var_hiding_invariant;\n    lh_relation = var_hiding_lh_relation vr;\n    progress_t = nat;\n    progress_wfr = default_wfr nat;\n    progress_measure = var_hiding_progress_measure vr;\n    refinement_relation = refinement_requirement;\n    paths_liftable_proof = paths_liftable_proof vr;\n    inv_stepwise_invariant_proof = (fun u -> inv_stepwise_invariant_proof vr);\n    init_implies_relation_proof = init_implies_relation_proof vr;\n    lh_relation_implies_refinement_proof = lh_relation_implies_refinement_proof vr;\n  } in\n  liftability_relation_implies_refinement lr\n"
  },
  {
    "path": "experimental/lib/Strategies.VarHiding.Relation.fsti",
    "content": "module Strategies.VarHiding.Relation\n\nopen Armada.State\nopen Armada.Type\nopen Spec.Behavior\nopen Strategies.Atomic\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\nopen Strategies.VarHiding.Defs\n\nval var_hiding_relation_implies_refinement (vr: var_hiding_relation_t)\n  : Lemma (ensures (spec_refines_spec\n                      (semantics_to_spec (make_atomic_semantics armada_semantics) vr.latomic_prog)\n                      (semantics_to_spec (make_atomic_semantics armada_semantics) vr.hatomic_prog)\n                      refinement_requirement))\n"
  },
  {
    "path": "experimental/lib/Strategies.VarIntro.Defs.fst",
    "content": "module Strategies.VarIntro.Defs\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Computation\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Threads\nopen Armada.Transition\nopen Armada.Type\nopen FStar.List.Tot.Base\nopen Spec.Behavior\nopen Spec.List\nopen Spec.Logic\nopen Spec.Ubool\nopen Strategies.ArmadaStatement.Propagate\nopen Strategies.ArmadaStatement.ThreadState\nopen Strategies.Atomic\nopen Strategies.Breaking\nopen Strategies.GlobalVars\nopen Strategies.GlobalVars.Statement\nopen Strategies.GlobalVars.Types\nopen Strategies.GlobalVars.VarIntro\nopen Strategies.Invariant\nopen Strategies.Invariant.Armada.AtomicSubstep\nopen Strategies.Nonyielding\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\nopen Util.List\nopen Util.Nth\nopen Util.Relation\n\ntype program_statement_succeeds_proof_t\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (inv: invariant_t Armada.State.t)\n  (ps: program_statement_t) =\n  (actor: tid_t) ->\n  (s: Armada.State.t{\n      inv s\n    /\\ all_gvars_have_types s.mem vs tds\n    /\\ NotStopped? s.stop_reason\n    /\\ ThreadStatusRunning? (s.threads actor).status\n    /\\ ps.start_pc = Some (s.threads actor).pc}) ->\n  squash (ComputationProduces? (statement_computation actor [] (Some?.v ps.start_pc) ps.end_pc ps.statement s))\n\nnoeq type introduction_succeeds_witness_t\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (inv: invariant_t Armada.State.t) =\n  | IntroductionSucceedsBecauseItAssignsConstant: introduction_succeeds_witness_t vs tds inv\n  | IntroductionSucceedsProof:\n      (ps: program_statement_t) ->\n      (proof: program_statement_succeeds_proof_t vs tds inv ps) -> introduction_succeeds_witness_t vs tds inv\n\nnoeq type haction_mapper_t (vs: list var_id_t) (tds: list object_td_t) (inv: invariant_t Armada.State.t) =\n  | MapperMatching: haction_mapper_t vs tds inv\n  | MapperIntroduced:\n      (introduction_succeeds_witness: introduction_succeeds_witness_t vs tds inv) -> haction_mapper_t vs tds inv\n\nnoeq type ltoh_correspondence_t (vs: list var_id_t) (tds: list object_td_t) (inv: invariant_t Armada.State.t) = \n  | CorrespondencePropagate: (hidx: nat) -> ltoh_correspondence_t vs tds inv\n  | CorrespondenceNormal: (hidx: nat) -> (mapper: list (haction_mapper_t vs tds inv)) -> ltoh_correspondence_t vs tds inv\n\nnoeq type hpc_info_t (vs: list var_id_t) (tds: list object_td_t) (inv: invariant_t Armada.State.t) =\n  | HPCInfoNormal: hpc_info_t vs tds inv\n  | HPCInfoIntroduced:\n      (idx: nat) ->\n      (end_pc: pc_t) ->\n      (introduction_succeeds_witnesses: list (introduction_succeeds_witness_t vs tds inv)) ->\n      (progress: nat) ->\n      hpc_info_t vs tds inv\n\nlet initializer_ok_for_var_intro\n  (init: initializer_t)\n  : GTot bool =\n     not init.weakly_consistent\n  && (match init.iv with\n      | InitializerSpecific value ->\n          (match value with\n           | ObjectValuePrimitive _ -> true\n           | ObjectValueAbstract _ _ -> true\n           | _ -> false)\n      | _ -> false)\n\nlet rec initializers_match_except_global_variables\n  (vs: list var_id_t)\n  (which_are_intros: list bool)\n  (linits: list initializer_t)\n  (hinits: list initializer_t)\n  : GTot ubool =\n  match which_are_intros, linits, hinits with\n  | [], [], [] -> True\n  | true :: remaining_which_are_intros, _, first_hinit :: remaining_hinits ->\n         list_contains first_hinit.var_id vs\n      /\\ initializer_ok_for_var_intro first_hinit\n      /\\ initializers_match_except_global_variables vs remaining_which_are_intros linits remaining_hinits\n  | false :: remaining_which_are_intros, first_linit :: remaining_linits, first_hinit :: remaining_hinits ->\n         not (list_contains first_hinit.var_id vs)\n      /\\ first_linit == first_hinit\n      /\\ initializers_match_except_global_variables vs remaining_which_are_intros remaining_linits remaining_hinits\n  | _, _, _ -> False\n\nlet initializers_match_if_same_variable_id\n  (init1: initializer_t)\n  (init2: initializer_t)\n  : GTot ubool =\n  init1.var_id = init2.var_id ==> init1 == init2\n\nlet initializers_with_same_variable_id_match\n  (inits: list initializer_t)\n  : GTot ubool =\n  for_all_ubool (fun init1 ->\n    for_all_ubool (fun init2 -> initializers_match_if_same_variable_id init1 init2) inits\n  ) inits\n\nlet program_inits_match_except_global_variables\n  (vs: list var_id_t)\n  (hpc_to_lpc: pc_t -> GTot pc_t)\n  (which_initializers_are_intros: list bool)\n  (lprog: Armada.Program.t)\n  (hprog: Armada.Program.t)\n  : GTot ubool =\n    lprog.main_method_id = hprog.main_method_id\n  /\\ lprog.main_start_pc = hpc_to_lpc hprog.main_start_pc\n  /\\ initializers_match_except_global_variables vs which_initializers_are_intros\n       lprog.global_initializers hprog.global_initializers\n  /\\ lprog.main_stack_initializers == hprog.main_stack_initializers\n\nlet start_pc_of_actions (actions: list Armada.Action.t) : GTot (option pc_t) =\n  match actions with\n  | [] -> None\n  | action :: _ -> action.program_statement.start_pc\n\nlet pcs_contain_new_pcs_of_action\n  (pcs: list pc_t)\n  (action: Armada.Action.t)\n  : GTot bool =\n  let ps = action.program_statement in\n  (match ps.end_pc with\n  | Some pc -> list_contains pc pcs\n  | None -> true)\n  &&\n  (match ps.statement with\n   | CreateThreadStatement method_id initial_pc _ _ _ _ _ -> list_contains initial_pc pcs\n   | _ -> true)\n\nlet lpc_hpc_pc_relation\n  (hpc_to_lpc: pc_t -> GTot pc_t)\n  (lpc: pc_t)\n  (hpc: pc_t)\n  : GTot bool =\n  hpc_to_lpc hpc = lpc\n\nlet lpc_hpc_pc_return_relation\n  (hpc_to_lpc: pc_t -> GTot pc_t)\n  (return_hpcs: list pc_t)\n  (lpc: pc_t)\n  (hpc: pc_t)\n  : GTot bool =\n  list_contains hpc return_hpcs && hpc_to_lpc hpc = lpc\n\nlet valid_introduction_succeeds_witness\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (inv: invariant_t Armada.State.t)\n  (ps: program_statement_t)\n  (witness: introduction_succeeds_witness_t vs tds inv)\n  : GTot ubool =\n  match witness with\n  | IntroductionSucceedsBecauseItAssignsConstant -> statement_updates_gvars_using_constant vs tds ps.statement\n  | IntroductionSucceedsProof ps' _ -> ps' == ps\n\nlet laction_corresponds_to_haction\n  (vs: list var_id_t)\n  (hpc_to_lpc: pc_t -> GTot pc_t)\n  (return_hpcs: list pc_t)\n  (laction: Armada.Action.t)\n  (haction: Armada.Action.t)\n  : GTot ubool =\n  let lps, hps = laction.program_statement, haction.program_statement in\n  let relation = lpc_hpc_pc_relation hpc_to_lpc in\n  let return_relation = lpc_hpc_pc_return_relation hpc_to_lpc return_hpcs in\n    statement_effect_independent_of_global_variables vs lps.statement\n  /\\ program_statements_match_per_pc_relation relation return_relation lps hps\n\nlet rec lactions_correspond_to_hactions\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (inv: invariant_t Armada.State.t)\n  (hpc_to_lpc: pc_t -> GTot pc_t)\n  (return_hpcs: list pc_t)\n  (lstart_state: thread_state_t)\n  (hstart_state: thread_state_t)\n  (lend_state: thread_state_t)\n  (hend_state: thread_state_t)\n  (mapper: list (haction_mapper_t vs tds inv))\n  (lactions: list Armada.Action.t)\n  (hactions: list Armada.Action.t)\n  : GTot ubool\n  (decreases hactions) =\n  let relation = lpc_hpc_pc_relation hpc_to_lpc in\n  match mapper, lactions, hactions with\n  | [], [], [] ->\n        lend_state = lstart_state\n      /\\ hend_state = hstart_state\n  | MapperMatching :: remaining_mapper, first_laction :: remaining_lactions, first_haction :: remaining_hactions ->\n         laction_corresponds_to_haction vs hpc_to_lpc return_hpcs first_laction first_haction\n      /\\ action_to_starting_thread_state first_laction = lstart_state\n      /\\ action_to_starting_thread_state first_haction = hstart_state\n      /\\ ThreadStateAtPC? lstart_state\n      /\\ ThreadStateAtPC? hstart_state\n      /\\ thread_states_match_per_pc_relation relation\n           (action_to_ending_thread_state first_laction) (action_to_ending_thread_state first_haction)\n      /\\ lactions_correspond_to_hactions vs tds inv hpc_to_lpc return_hpcs\n           (action_to_ending_thread_state first_laction) (action_to_ending_thread_state first_haction)\n           lend_state hend_state remaining_mapper remaining_lactions remaining_hactions\n  | MapperIntroduced witness :: remaining_mapper, _, first_haction :: remaining_hactions ->\n        first_haction.ok\n      /\\ valid_introduction_succeeds_witness vs tds inv first_haction.program_statement witness\n      /\\ action_to_starting_thread_state first_haction = hstart_state\n      /\\ thread_states_match_per_pc_relation relation lstart_state (action_to_ending_thread_state first_haction)\n      /\\ statement_updates_gvars vs first_haction.program_statement.statement\n      /\\ lactions_correspond_to_hactions vs tds inv hpc_to_lpc return_hpcs lstart_state\n           (action_to_ending_thread_state first_haction) lend_state hend_state\n           remaining_mapper lactions remaining_hactions\n  | _, _, _ -> False\n\nlet laction_haction_correspondence_complete_inner\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (inv: invariant_t Armada.State.t)\n  (is_breaking_hpc: pc_t -> GTot bool)\n  (hpc_info: pc_t -> GTot (hpc_info_t vs tds inv))\n  (start_hpc: pc_t)\n  (hpc: pc_t)\n  : GTot bool =\n    hpc = start_hpc\n  || (not (is_breaking_hpc hpc))\n  || HPCInfoIntroduced? (hpc_info hpc)\n\nlet laction_haction_correspondence_complete\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (inv: invariant_t Armada.State.t)\n  (lpc_to_hpcs: pc_t -> GTot (list pc_t))\n  (is_breaking_hpc: pc_t -> GTot bool)\n  (hpc_info: pc_t -> GTot (hpc_info_t vs tds inv))\n  (lactions: list Armada.Action.t)\n  (hactions: list Armada.Action.t)\n  : GTot bool =\n  let opt_start_lpc = start_pc_of_actions lactions in\n  let opt_start_hpc = start_pc_of_actions hactions in\n  match opt_start_lpc, opt_start_hpc with\n  | None, None -> true\n  | Some start_lpc, Some start_hpc ->\n      for_all_ghost\n        (laction_haction_correspondence_complete_inner vs tds inv is_breaking_hpc hpc_info start_hpc)\n        (lpc_to_hpcs start_lpc)\n  | _, _ -> false\n\nlet rec hactions_introducible\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (inv: invariant_t Armada.State.t)\n  (hpc_to_lpc: pc_t -> GTot pc_t)\n  (hstart_pc: pc_t)\n  (hend_pc: pc_t)\n  (introduction_succeeds_witnesses: list (introduction_succeeds_witness_t vs tds inv))\n  (actions: list Armada.Action.t)\n  : GTot ubool\n  (decreases introduction_succeeds_witnesses) =\n  match introduction_succeeds_witnesses, actions with\n  | [], [] -> hstart_pc = hend_pc\n  | first_witness :: remaining_introduction_succeeds_witnesses, first_action :: remaining_actions ->\n        first_action.ok\n      /\\ action_to_starting_thread_state first_action = ThreadStateAtPC hstart_pc\n      /\\ ThreadStateAtPC? (action_to_ending_thread_state first_action)\n      /\\ hpc_to_lpc hstart_pc = hpc_to_lpc hend_pc\n      /\\ valid_introduction_succeeds_witness vs tds inv first_action.program_statement first_witness\n      /\\ statement_updates_gvars vs first_action.program_statement.statement\n      /\\ hactions_introducible vs tds inv hpc_to_lpc\n           (ThreadStateAtPC?.pc (action_to_ending_thread_state first_action))\n           hend_pc remaining_introduction_succeeds_witnesses remaining_actions\n  | _, _ -> False\n\nlet introduced_atomic_action_makes_progress\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (inv: invariant_t Armada.State.t)\n  (hatomic_actions: list (list Armada.Action.t))\n  (hpc_info: pc_t -> GTot (hpc_info_t vs tds inv))\n  (hpc_to_lpc: pc_t -> GTot pc_t)\n  (is_nonyielding_lpc: pc_t -> GTot bool)\n  (hpc: pc_t)\n  : GTot ubool =\n  match hpc_info hpc with\n  | HPCInfoNormal -> True\n  | HPCInfoIntroduced idx end_pc introduction_succeeds_witnesses progress ->\n      (match nth hatomic_actions idx with\n       | Some hactions ->\n           let lpc = hpc_to_lpc hpc in\n           let lpc_yielding = not (is_nonyielding_lpc lpc) in\n             hactions_introducible vs tds inv hpc_to_lpc hpc end_pc introduction_succeeds_witnesses hactions\n           /\\ actions_start_atomic_block hactions = lpc_yielding\n           /\\ actions_end_atomic_block hactions = lpc_yielding\n           /\\ (match hpc_info end_pc with\n              | HPCInfoNormal -> true\n              | HPCInfoIntroduced _ _ _ progress' -> progress' < progress)\n       | None -> False)\n\nlet lactions_correspond_to_hactions_per_correspondence\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (inv: invariant_t Armada.State.t)\n  (hpc_to_lpc: pc_t -> GTot pc_t)\n  (lpc_to_hpcs: pc_t -> GTot (list pc_t))\n  (return_hpcs: list pc_t)\n  (is_breaking_hpc: pc_t -> GTot bool)\n  (hpc_info: pc_t -> GTot (hpc_info_t vs tds inv))\n  (hatomic_actions: list (list Armada.Action.t))\n  (lactions: list Armada.Action.t)\n  (correspondence: ltoh_correspondence_t vs tds inv)\n  : GTot ubool =\n  match correspondence with\n  | CorrespondencePropagate hidx ->\n        Cons? lactions\n      /\\ (Cons?.hd lactions).program_statement == propagate_program_statement\n      /\\ list_nth hatomic_actions hidx == Some lactions\n  | CorrespondenceNormal hidx mapper ->\n      (match nth hatomic_actions hidx with\n       | Some hactions ->\n             Cons? lactions\n           /\\ Cons? hactions\n           /\\ (let lstart_state = action_to_starting_thread_state (Cons?.hd lactions) in\n              let lend_state = actions_to_ending_thread_state lactions in\n              let hstart_state = action_to_starting_thread_state (Cons?.hd hactions) in\n              let hend_state = actions_to_ending_thread_state hactions in\n                 do_actions_start_and_end_atomic_block lactions = do_actions_start_and_end_atomic_block hactions\n              /\\ lactions_correspond_to_hactions vs tds inv hpc_to_lpc return_hpcs lstart_state\n                   hstart_state lend_state hend_state mapper lactions hactions\n              /\\ laction_haction_correspondence_complete vs tds inv lpc_to_hpcs is_breaking_hpc hpc_info lactions\n                  hactions)\n       | None -> False)\n\nlet initializer_value_to_td (init: initializer_value_t) : GTot object_td_t =\n  match init with\n  | InitializerArbitrary td -> td\n  | InitializerSpecific value -> object_value_to_td value\n\nlet initializer_matches_variable_and_td\n  (v: var_id_t)\n  (td: object_td_t)\n  (init: initializer_t)\n  : GTot ubool =\n    init.var_id = v\n  /\\ initializer_value_to_td init.iv == td\n\nlet every_variable_appears_among_initializers\n  (inits: list initializer_t)\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  : GTot ubool =\n  lists_correspond_ubool\n    (fun v td -> exists_ubool (initializer_matches_variable_and_td v td) inits)\n    vs\n    tds\n\nlet every_hpc_appears_among_lpc_to_hpcs\n  (lpc_to_hpcs: pc_t -> GTot (list pc_t))\n  (hpc_to_lpc: pc_t -> GTot pc_t)\n  (hpcs: list pc_t)\n  : GTot bool =\n  for_all_ghost (fun hpc -> list_contains hpc (lpc_to_hpcs (hpc_to_lpc hpc))) hpcs\n\nlet return_pcs_unique_inner2\n  (hpc_to_lpc: pc_t -> GTot pc_t)\n  (return_hpcs: list pc_t)\n  (hpc1: pc_t)\n  (hpc2: pc_t)\n  : GTot bool =\n  implies (hpc_to_lpc hpc1 = hpc_to_lpc hpc2) (hpc1 = hpc2)\n\nlet return_pcs_unique_inner1\n  (hpc_to_lpc: pc_t -> GTot pc_t)\n  (return_hpcs: list pc_t)\n  (hpc1: pc_t)\n  : GTot bool =\n  for_all_ghost (return_pcs_unique_inner2 hpc_to_lpc return_hpcs hpc1) return_hpcs\n\nlet return_pcs_unique\n  (hpc_to_lpc: pc_t -> GTot pc_t)\n  (return_hpcs: list pc_t)\n  : GTot bool =\n  for_all_ghost (return_pcs_unique_inner1 hpc_to_lpc return_hpcs) return_hpcs\n\nnoeq type var_intro_relation_t = {\n  lprog: Armada.Program.t;\n  hprog: Armada.Program.t;\n  latomic_prog: program_t (make_atomic_semantics armada_semantics);\n  hatomic_prog: program_t (make_atomic_semantics armada_semantics);\n  vs: list var_id_t;\n  tds: list object_td_t;\n  inv: invariant_t Armada.State.t;\n  which_initializers_are_intros: list bool;\n  hpc_to_lpc: pc_t -> GTot pc_t;\n  lpc_to_hpcs: pc_t -> GTot (list pc_t);\n  return_hpcs: list pc_t;\n  is_nonyielding_lpc: pc_t -> GTot bool;\n  is_nonyielding_hpc: pc_t -> GTot bool;\n  is_breaking_hpc: pc_t -> GTot bool;\n  hpcs: list pc_t;\n  hpc_info: pc_t -> GTot (hpc_info_t vs tds inv);\n  corresponding_hactions_info: list (ltoh_correspondence_t vs tds inv);\n\n  inv_is_substep_invariant_proof: unit ->\n    squash (is_armada_substep_invariant hatomic_prog inv);\n\n  atomic_inits_match_regular_inits_proof: unit ->\n    squash (latomic_prog.init_f == init_program lprog /\\ hatomic_prog.init_f == init_program hprog);\n\n  program_inits_match_except_global_variables_proof: unit ->\n    squash (program_inits_match_except_global_variables vs hpc_to_lpc which_initializers_are_intros lprog hprog);\n\n  hinitializers_with_same_variable_id_match_proof: unit ->\n    squash (initializers_with_same_variable_id_match hprog.global_initializers);\n\n  initial_pc_in_pcs_proof: unit ->\n    squash (list_contains hprog.main_start_pc hpcs);\n\n  initial_pc_breaking_proof: unit ->\n    squash (is_breaking_hpc hprog.main_start_pc);\n\n  initial_pcs_correspond_proof: unit -> squash (hpc_to_lpc hprog.main_start_pc = lprog.main_start_pc);\n\n  global_variables_unaddressed_in_initializers_proof: unit ->\n    squash (  global_variables_unaddressed_in_initializers vs lprog.global_initializers\n            /\\ global_variables_unaddressed_in_initializers vs hprog.global_initializers\n            /\\ global_variables_unaddressed_in_initializers vs lprog.main_stack_initializers\n            /\\ global_variables_unaddressed_in_initializers vs hprog.main_stack_initializers);\n\n  all_introduced_global_variables_initialized_proof: unit ->\n    squash (every_variable_appears_among_initializers hprog.global_initializers vs tds);\n\n  hpcs_complete_proof: unit ->\n    squash (for_all_ghost (for_all_ghost (pcs_contain_new_pcs_of_action hpcs)) hatomic_prog.actions);\n\n  lpc_to_hpcs_consistent_with_hpc_to_lpc_proof: unit ->\n    squash (every_hpc_appears_among_lpc_to_hpcs lpc_to_hpcs hpc_to_lpc hpcs);\n\n  return_pcs_unique_proof: unit ->\n    squash (return_pcs_unique hpc_to_lpc return_hpcs);\n\n  lactions_consistent_with_is_nonyielding_pc_proof: unit ->\n    squash (each_action_list_consistent_with_is_nonyielding_pc is_nonyielding_lpc latomic_prog.actions);\n\n  hactions_consistent_with_is_nonyielding_pc_proof: unit ->\n    squash (each_action_list_consistent_with_is_nonyielding_pc is_nonyielding_hpc hatomic_prog.actions);\n\n  hactions_end_in_breaking_pc_proof: unit ->\n    squash (each_action_list_maintains_all_threads_breaking is_breaking_hpc hatomic_prog.actions);\n\n  each_laction_doesnt_internally_yield_proof: unit ->\n    squash (each_action_list_doesnt_internally_yield latomic_prog.actions);\n\n  each_haction_doesnt_internally_yield_proof: unit ->\n    squash (each_action_list_doesnt_internally_yield hatomic_prog.actions);\n\n  introduced_atomic_actions_make_progress_proof: unit ->\n    squash (for_all_ubool (introduced_atomic_action_makes_progress vs tds inv hatomic_prog.actions\n                             hpc_info hpc_to_lpc is_nonyielding_lpc) hpcs);\n\n  corresponding_hactions_correspond_proof: unit ->\n    squash (lists_correspond_ubool\n              (lactions_correspond_to_hactions_per_correspondence vs tds inv\n                 hpc_to_lpc lpc_to_hpcs return_hpcs is_breaking_hpc hpc_info hatomic_prog.actions)\n              latomic_prog.actions corresponding_hactions_info);\n}\n"
  },
  {
    "path": "experimental/lib/Strategies.VarIntro.Efficient.fst",
    "content": "module Strategies.VarIntro.Efficient\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Threads\nopen Armada.Transition\nopen Armada.Type\nopen Spec.Behavior\nopen Spec.List\nopen Spec.Logic\nopen Spec.Ubool\nopen Strategies.ArmadaStatement.ThreadState\nopen Strategies.Atomic\nopen Strategies.Breaking\nopen Strategies.GlobalVars\nopen Strategies.GlobalVars.Permanent\nopen Strategies.GlobalVars.Statement\nopen Strategies.GlobalVars.VarIntro\nopen Strategies.Invariant\nopen Strategies.Nonyielding\nopen Strategies.PCIndices\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\nopen Strategies.VarIntro.Defs\nopen Strategies.VarIntro.Inefficient\nopen Strategies.VarIntro.Relation\nopen Util.ImmutableArray\nopen Util.List\nopen Util.Nth\nopen Util.Range\nopen Util.Relation\n\nlet default_pc: pc_t = \"\"\n\nlet make_pc_index_to_pc\n  (pcs: array_t pc_t)\n  (idx: nat)\n  : GTot pc_t =\n  match array_nth pcs idx with\n  | None -> default_pc\n  | Some pc -> pc\n\nlet make_pc_indices_to_pcs\n  (pcs: array_t pc_t)\n  (pc_indices: list nat)\n  : GTot (list pc_t) =\n  map_ghost (make_pc_index_to_pc pcs) pc_indices\n\nlet make_hpc_to_lpc\n  (hpcs: array_t pc_t)\n  (lpcs: array_t pc_t)\n  (hpc_to_lpc: array_t nat{array_len hpc_to_lpc = array_len hpcs})\n  (hpc: pc_t)\n  : GTot pc_t =\n  match find_in_array hpcs hpc with\n  | None -> default_pc\n  | Some hpc_index ->\n      let lpc_index = array_index hpc_to_lpc hpc_index in\n      make_pc_index_to_pc lpcs lpc_index\n\nlet make_lpc_to_hpcs\n  (hpcs: array_t pc_t)\n  (lpcs: array_t pc_t)\n  (lpc_to_hpcs: array_t (list nat){array_len lpc_to_hpcs = array_len lpcs})\n  (lpc: pc_t)\n  : GTot (list pc_t) =\n  match find_in_array lpcs lpc with\n  | None -> []\n  | Some lpc_index ->\n      let hpc_indices = array_index lpc_to_hpcs lpc_index in\n      make_pc_indices_to_pcs hpcs hpc_indices\n\nlet rec make_return_pcs_offset\n  (pcs: array_t pc_t)\n  (is_return_pc: array_t bool{array_len is_return_pc = array_len pcs})\n  (offset: nat{offset <= array_len pcs})\n  : GTot (list pc_t) (decreases array_len pcs - offset) =\n  if offset = array_len pcs then\n    []\n  else if array_index is_return_pc offset = true then\n    (array_index pcs offset) :: make_return_pcs_offset pcs is_return_pc (offset + 1)\n  else\n    make_return_pcs_offset pcs is_return_pc (offset + 1)\n\nlet make_return_pcs\n  (pcs: array_t pc_t)\n  (is_return_pc: array_t bool{array_len is_return_pc = array_len pcs})\n  : GTot (list pc_t) =\n  make_return_pcs_offset pcs is_return_pc 0\n\nlet make_is_nonyielding_pc\n  (pcs: array_t pc_t)\n  (is_nonyielding_pc: array_t bool{array_len is_nonyielding_pc = array_len pcs})\n  (pc: pc_t)\n  : GTot bool =\n  match find_in_array pcs pc with\n  | None -> false\n  | Some idx -> array_index is_nonyielding_pc idx\n\nlet make_is_breaking_pc\n  (pcs: array_t pc_t)\n  (is_breaking_pc: array_t bool{array_len is_breaking_pc = array_len pcs})\n  (pc: pc_t)\n  : GTot bool =\n  match find_in_array pcs pc with\n  | None -> false\n  | Some idx -> array_index is_breaking_pc idx\n\nlet make_hpc_info\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (inv: invariant_t Armada.State.t)\n  (hpcs: array_t pc_t)\n  (hpc_info: array_t (efficient_hpc_info_t vs tds inv){array_len hpc_info = array_len hpcs})\n  (hpc: pc_t)\n  : GTot (hpc_info_t vs tds inv) =\n  match find_in_array hpcs hpc with\n  | None -> HPCInfoNormal\n  | Some hpc_index ->\n      (match array_index hpc_info hpc_index with\n       | EfficientHPCInfoNormal -> HPCInfoNormal\n       | EfficientHPCInfoIntroduced idx end_pc introduction_succeeds_witnesses progress ->\n           HPCInfoIntroduced idx (make_pc_index_to_pc hpcs end_pc) introduction_succeeds_witnesses progress)\n\nlet convert_efficient_thread_state\n  (pcs: array_t pc_t)\n  (ts: efficient_thread_state_t)\n  : GTot thread_state_t =\n  match ts with\n  | EfficientThreadStateRunning -> ThreadStateRunning\n  | EfficientThreadStateAtPC pc -> ThreadStateAtPC (make_pc_index_to_pc pcs pc)\n  | EfficientThreadStateNotRunning status -> ThreadStateNotRunning status\n  | EfficientThreadStateProcessStopped stop_reason -> ThreadStateProcessStopped stop_reason\n\nlet array_to_list_contains_array_nth_ambient\n  (pcs: array_t pc_t)\n  (idx: nat)\n  : Lemma (requires Some? (array_nth pcs idx))\n          (ensures  list_contains (Some?.v (array_nth pcs idx)) (array_to_list pcs))\n          [SMTPat  (Some? (array_nth pcs idx))] =\n  match array_nth pcs idx with\n  | Some pc ->\n      array_to_list_implies_array_matches_list pcs (array_to_list pcs);        \n      array_matches_list_implies_nth_equivalent pcs (array_to_list pcs) idx;\n      nth_implies_contains (array_to_list pcs) idx pc\n\nlet optional_pc_matches_optional_pc_index_ambient\n  (pcs: array_t pc_t)\n  (optional_pc: option pc_t)\n  (optional_index: option nat)\n  : Lemma (requires optional_pc_matches_optional_pc_index pcs optional_pc optional_index)\n          (ensures  (match optional_pc with\n                     | None -> True\n                     | Some pc -> list_contains pc (array_to_list pcs)))\n          [SMTPat (optional_pc_matches_optional_pc_index pcs optional_pc optional_index)] =\n  match optional_pc, optional_index with\n  | Some pc, Some idx ->\n      array_to_list_implies_array_matches_list pcs (array_to_list pcs);\n      array_matches_list_implies_index_equivalent pcs (array_to_list pcs) idx;\n      index_implies_contains (array_to_list pcs) idx pc\n  | _, _ -> ()\n\nlet find_in_array_inverts_index\n  (pcs: array_t pc_t)\n  (idx: nat)\n  : Lemma (requires   Some? (array_nth pcs idx)\n                    /\\ array_elements_unique pcs)\n          (ensures  find_in_array pcs (array_index pcs idx) = Some idx)\n          [SMTPat   (find_in_array pcs (array_index pcs idx))] =\n  array_elements_unique_implication pcs\n\nlet make_pc_indices_to_pcs_contains_pc_implies_pc_indices_contains_index\n  (pcs: array_t pc_t)\n  (pc_indices: list nat)\n  (pc: pc_t)\n  (idx: nat)\n  : Lemma (requires   list_contains pc (make_pc_indices_to_pcs pcs pc_indices)\n                    /\\ array_nth pcs idx = Some pc\n                    /\\ array_elements_unique pcs\n                    /\\ (forall (idx: nat). list_contains idx pc_indices ==> idx < array_len pcs))\n          (ensures  list_contains idx pc_indices) =\n  let idx' = reverse_map_element_of_map_ghost (make_pc_index_to_pc pcs) pc_indices pc in\n  array_elements_unique_implication pcs;\n  assert (idx' = idx)\n\nlet rec make_return_pcs_offset_contains_return_pc\n  (pcs: array_t pc_t)\n  (is_return_pc: array_t bool{array_len is_return_pc = array_len pcs})\n  (offset: nat{offset <= array_len pcs})\n  (idx: nat{offset <= idx /\\ idx < array_len pcs})\n  : Lemma (requires array_index is_return_pc idx = true)\n          (ensures  list_contains (array_index pcs idx) (make_return_pcs_offset pcs is_return_pc offset))\n          (decreases idx - offset) =\n  if offset = array_len pcs then\n    false_elim ()\n  else if idx = offset && array_index is_return_pc offset = true then\n    ()\n  else\n    make_return_pcs_offset_contains_return_pc pcs is_return_pc (offset + 1) idx\n\nlet make_return_pcs_contains_return_pc\n  (pcs: array_t pc_t)\n  (is_return_pc: array_t bool{array_len is_return_pc = array_len pcs})\n  (idx: nat{idx < array_len is_return_pc})\n  : Lemma (requires array_index is_return_pc idx = true)\n          (ensures  list_contains (array_index pcs idx) (make_return_pcs pcs is_return_pc)) =\n  make_return_pcs_offset_contains_return_pc pcs is_return_pc 0 idx\n\nlet lpc_hpc_relation_facts\n  (lpcs: array_t pc_t)\n  (hpcs: array_t pc_t)\n  (hpc_to_lpc: array_t nat{array_len hpc_to_lpc = array_len hpcs})\n  (is_return_hpc: array_t bool{array_len is_return_hpc = array_len hpcs})\n  : Lemma (requires array_elements_unique hpcs)\n          (ensures  (let index_relation = efficient_hl_pc_relation hpc_to_lpc in\n                     let index_return_relation = efficient_hl_pc_return_relation hpc_to_lpc is_return_hpc in\n                     let inefficient_hpc_to_lpc = make_hpc_to_lpc hpcs lpcs hpc_to_lpc in\n                     let inefficient_return_hpcs = make_return_pcs hpcs is_return_hpc in\n                     let pc_relation = lpc_hpc_pc_relation inefficient_hpc_to_lpc in\n                     let pc_return_relation = lpc_hpc_pc_return_relation inefficient_hpc_to_lpc\n                                                inefficient_return_hpcs in\n                     forall (lidx: nat) (hidx: nat). lidx < array_len lpcs /\\ hidx < array_len hpcs ==>\n                         (let lpc = array_index lpcs lidx in\n                          let hpc = array_index hpcs hidx in\n                            (index_relation lidx hidx ==> pc_relation lpc hpc)\n                          /\\ (index_return_relation lidx hidx ==> pc_return_relation lpc hpc)))) =\n  let index_relation = efficient_hl_pc_relation hpc_to_lpc in\n  let index_return_relation = efficient_hl_pc_return_relation hpc_to_lpc is_return_hpc in\n  let inefficient_hpc_to_lpc = make_hpc_to_lpc hpcs lpcs hpc_to_lpc in\n  let inefficient_return_hpcs = make_return_pcs hpcs is_return_hpc in\n  let pc_relation = lpc_hpc_pc_relation inefficient_hpc_to_lpc in\n  let pc_return_relation = lpc_hpc_pc_return_relation inefficient_hpc_to_lpc inefficient_return_hpcs in\n  let inefficient_hpc_to_lpc = make_hpc_to_lpc hpcs lpcs hpc_to_lpc in\n  let inefficient_return_hpcs = make_return_pcs hpcs is_return_hpc in\n  introduce forall (lidx: nat) (hidx: nat). lidx < array_len lpcs /\\ hidx < array_len hpcs ==>\n                         (let lpc = array_index lpcs lidx in\n                          let hpc = array_index hpcs hidx in\n                            (index_relation lidx hidx ==> pc_relation lpc hpc)\n                          /\\ (index_return_relation lidx hidx ==> pc_return_relation lpc hpc))\n  with introduce _ ==> _\n  with _. (\n    let lpc = array_index lpcs lidx in\n    let hpc = array_index hpcs hidx in\n    introduce index_relation lidx hidx ==> pc_relation lpc hpc\n    with _. (\n      assert (array_nth hpc_to_lpc hidx = Some lidx);\n      assert (find_in_array hpcs hpc = Some hidx);\n      assert (array_index hpc_to_lpc hidx = lidx);\n      assert (make_pc_index_to_pc lpcs lidx = lpc);\n      assert (inefficient_hpc_to_lpc hpc = lpc)\n    );\n    introduce index_return_relation lidx hidx ==> pc_return_relation lpc hpc\n    with _. (\n      assert (array_nth hpc_to_lpc hidx = Some lidx);\n      assert (array_nth is_return_hpc hidx = Some true);\n      assert (find_in_array hpcs hpc = Some hidx);\n      assert (array_index hpc_to_lpc hidx = lidx);\n      assert (make_pc_index_to_pc lpcs lidx = lpc);\n      assert (inefficient_hpc_to_lpc hpc = lpc);\n      make_return_pcs_contains_return_pc hpcs is_return_hpc hidx;\n      assert (list_contains hpc inefficient_return_hpcs)\n    )\n  )\n\nlet program_inits_match_except_global_variables_lemma\n  (vs: list var_id_t)\n  (lpcs: array_t pc_t)\n  (hpcs: array_t pc_t)\n  (hpc_to_lpc: array_t nat{array_len hpc_to_lpc = array_len hpcs})\n  (which_initializers_are_intros: list bool)\n  (lprog: Armada.Program.t)\n  (hprog: Armada.Program.t)\n  (lprog_main_start_pc_index: nat)\n  (hprog_main_start_pc_index: nat)\n  : Lemma (requires   efficient_program_inits_match_except_global_variables vs lpcs hpcs hpc_to_lpc\n                        which_initializers_are_intros lprog hprog lprog_main_start_pc_index hprog_main_start_pc_index\n                    /\\ array_elements_unique hpcs)\n          (ensures    program_inits_match_except_global_variables vs (make_hpc_to_lpc hpcs lpcs hpc_to_lpc)\n                        which_initializers_are_intros lprog hprog\n                    /\\ (make_hpc_to_lpc hpcs lpcs hpc_to_lpc) hprog.main_start_pc = lprog.main_start_pc) =\n  array_elements_unique_implication hpcs\n\nlet hstart_pc_among_hpcs_lemma\n  (hpcs: array_t pc_t)\n  (hprog: Armada.Program.t)\n  (hprog_main_start_pc_index: nat)\n  : Lemma (requires  array_nth hpcs hprog_main_start_pc_index = Some hprog.main_start_pc)\n          (ensures   list_contains hprog.main_start_pc (array_to_list hpcs)) =\n  ()\n\nlet pcs_contain_new_pcs_of_action_lemma\n  (hatomic_prog: program_t (make_atomic_semantics armada_semantics))\n  (hprog_actions_array: array_t (list Armada.Action.t))\n  (hpc_indices_array: array_t (list statement_pc_indices_t))\n  (hpcs: array_t pc_t)\n  : Lemma (requires   hprog_actions_array == list_to_array hatomic_prog.actions\n                    /\\ actions_array_corresponds_to_statement_pc_indices_array hpcs hprog_actions_array\n                        hpc_indices_array)\n          (ensures  for_all_ghost (for_all_ghost (pcs_contain_new_pcs_of_action (array_to_list hpcs)))\n                      hatomic_prog.actions) =\n  let hpc_list = array_to_list hpcs in\n  introduce forall actions. contains_ubool actions hatomic_prog.actions ==>\n               (forall action. contains_ubool action actions ==> pcs_contain_new_pcs_of_action hpc_list action)\n  with introduce contains_ubool actions hatomic_prog.actions ==>\n                   (forall action. contains_ubool action actions ==> pcs_contain_new_pcs_of_action hpc_list action)\n  with _. introduce forall action. contains_ubool action actions ==> pcs_contain_new_pcs_of_action hpc_list action\n  with introduce contains_ubool action actions ==> pcs_contain_new_pcs_of_action hpc_list action\n  with _. (\n    let actions_idx = contains_ubool_to_index actions hatomic_prog.actions in\n    let hactions = array_index hprog_actions_array actions_idx in\n    let hpc_indices_list = array_index hpc_indices_array actions_idx in\n    assert (action_list_corresponds_to_statement_pc_indices_list hpcs hactions hpc_indices_list);\n    let hpc_indices = get_correspondent_from_lists_correspond (action_corresponds_to_statement_pc_indices hpcs)\n      hactions hpc_indices_list action in\n    assert (action_corresponds_to_statement_pc_indices hpcs action hpc_indices)\n  )\n\n#push-options \"--z3rlimit 10\"\n\nlet every_hpc_appears_among_lpc_to_hpcs_lemma\n  (lpcs: array_t pc_t)\n  (hpcs: array_t pc_t)\n  (hpc_to_lpc: array_t nat{array_len hpc_to_lpc = array_len hpcs})\n  (lpc_to_hpcs: array_t (list nat){array_len lpc_to_hpcs = array_len lpcs})\n  : Lemma (requires   efficient_hpc_among_hpc_to_lpc_to_hpcs (array_len hpcs) hpc_to_lpc lpc_to_hpcs\n                    /\\ array_elements_unique lpcs\n                    /\\ array_elements_unique hpcs)\n          (ensures  every_hpc_appears_among_lpc_to_hpcs (make_lpc_to_hpcs hpcs lpcs lpc_to_hpcs)\n                      (make_hpc_to_lpc hpcs lpcs hpc_to_lpc) (array_to_list hpcs)) =\n  let inefficient_hpcs = array_to_list hpcs in\n  let inefficient_hpc_to_lpc = make_hpc_to_lpc hpcs lpcs hpc_to_lpc in\n  let inefficient_lpc_to_hpcs = make_lpc_to_hpcs hpcs lpcs lpc_to_hpcs in\n  introduce forall hpc. list_contains hpc inefficient_hpcs ==>\n                     list_contains hpc (inefficient_lpc_to_hpcs (inefficient_hpc_to_lpc hpc))\n  with introduce list_contains hpc inefficient_hpcs ==>\n                   list_contains hpc (inefficient_lpc_to_hpcs (inefficient_hpc_to_lpc hpc))\n  with _. (\n    let hpc_index = contains_to_index hpc inefficient_hpcs in\n    assert (array_nth hpcs hpc_index = Some hpc);\n    let lpc_index = array_index hpc_to_lpc hpc_index in\n    let lpc = array_index lpcs lpc_index in\n    let hpc_indices = array_index lpc_to_hpcs lpc_index in\n    assert (list_contains hpc_index hpc_indices);\n    assert (find_in_array hpcs hpc = Some hpc_index);\n    assert (inefficient_hpc_to_lpc hpc = lpc);\n    let inefficient_hpcs = inefficient_lpc_to_hpcs lpc in\n    assert (inefficient_hpcs = make_pc_indices_to_pcs hpcs hpc_indices);\n    map_ghost_contains (make_pc_index_to_pc hpcs) hpc_indices hpc_index;\n    assert (list_contains (make_pc_index_to_pc hpcs hpc_index) inefficient_hpcs);\n    assert (make_pc_index_to_pc hpcs hpc_index = hpc)\n  )\n\n#pop-options\n\nlet rec get_index_of_pc_among_return_pcs_offset\n  (hpcs: array_t pc_t)\n  (is_return_hpc: array_t bool{array_len is_return_hpc = array_len hpcs})\n  (offset: nat{offset <= array_len hpcs})\n  (pc: pc_t)\n  : Ghost nat\n  (requires list_contains pc (make_return_pcs_offset hpcs is_return_hpc offset))\n  (ensures fun idx -> idx < array_len hpcs /\\ array_index hpcs idx = pc /\\ array_index is_return_hpc idx = true)\n  (decreases array_len hpcs - offset) =\n  if offset = array_len hpcs then\n    false_elim ()\n  else if array_index is_return_hpc offset = true then (\n    if array_index hpcs offset = pc then\n      offset\n    else\n      get_index_of_pc_among_return_pcs_offset hpcs is_return_hpc (offset + 1) pc\n  )\n  else\n    get_index_of_pc_among_return_pcs_offset hpcs is_return_hpc (offset + 1) pc\n\nlet get_index_of_pc_among_return_pcs\n  (hpcs: array_t pc_t)\n  (is_return_hpc: array_t bool{array_len is_return_hpc = array_len hpcs})\n  (pc: pc_t)\n  : Ghost nat\n  (requires list_contains pc (make_return_pcs hpcs is_return_hpc))\n  (ensures  fun idx -> idx < array_len hpcs /\\ array_index hpcs idx = pc /\\ array_index is_return_hpc idx = true) =\n  get_index_of_pc_among_return_pcs_offset hpcs is_return_hpc 0 pc\n\nlet apply_efficient_return_hpcs_unique\n  (num_hpcs: nat)\n  (hpc_to_lpc: array_t nat)\n  (is_return_hpc: array_t bool)\n  (hpc1: nat)\n  (hpc2: nat)\n  : Lemma (requires   efficient_return_hpcs_unique num_hpcs hpc_to_lpc is_return_hpc\n                    /\\ hpc1 < num_hpcs\n                    /\\ hpc2 < num_hpcs\n                    /\\ array_nth is_return_hpc hpc1 = Some true\n                    /\\ array_nth is_return_hpc hpc2 = Some true\n                    /\\ array_nth hpc_to_lpc hpc1 = array_nth hpc_to_lpc hpc2)\n          (ensures  hpc1 = hpc2) =\n  assert (efficient_return_hpcs_unique_inner1 num_hpcs hpc_to_lpc is_return_hpc hpc1);\n  assert (efficient_return_hpcs_unique_inner2 hpc_to_lpc is_return_hpc hpc1 hpc2)\n\n#push-options \"--z3rlimit 10\"\n\nlet return_pcs_unique_lemma\n  (hpcs: array_t pc_t)\n  (lpcs: array_t pc_t)\n  (hpc_to_lpc: array_t nat{array_len hpc_to_lpc = array_len hpcs})\n  (is_return_hpc: array_t bool{array_len is_return_hpc = array_len hpcs})\n  (lpc_to_hpcs: array_t (list nat){array_len lpc_to_hpcs = array_len lpcs})\n  : Lemma (requires    efficient_return_hpcs_unique (array_len hpcs) hpc_to_lpc is_return_hpc\n                    /\\ efficient_hpc_among_hpc_to_lpc_to_hpcs (array_len hpcs) hpc_to_lpc lpc_to_hpcs\n                    /\\ array_elements_unique lpcs\n                    /\\ array_elements_unique hpcs)\n          (ensures  return_pcs_unique (make_hpc_to_lpc hpcs lpcs hpc_to_lpc) (make_return_pcs hpcs is_return_hpc)) =\n  let inefficient_return_hpcs = make_return_pcs hpcs is_return_hpc in\n  let inefficient_hpc_to_lpc = make_hpc_to_lpc hpcs lpcs hpc_to_lpc in\n  introduce forall hpc1. list_contains hpc1 inefficient_return_hpcs ==>\n              return_pcs_unique_inner1 inefficient_hpc_to_lpc inefficient_return_hpcs hpc1\n  with introduce list_contains hpc1 inefficient_return_hpcs ==>\n                   return_pcs_unique_inner1 inefficient_hpc_to_lpc inefficient_return_hpcs hpc1\n  with _. introduce forall hpc2. list_contains hpc2 inefficient_return_hpcs ==>\n                      return_pcs_unique_inner2 inefficient_hpc_to_lpc inefficient_return_hpcs hpc1 hpc2\n  with introduce list_contains hpc2 inefficient_return_hpcs ==>\n                   return_pcs_unique_inner2 inefficient_hpc_to_lpc inefficient_return_hpcs hpc1 hpc2\n  with _. introduce inefficient_hpc_to_lpc hpc1 = inefficient_hpc_to_lpc hpc2 ==> hpc1 = hpc2\n  with _. (\n    let hpc_index1 = get_index_of_pc_among_return_pcs hpcs is_return_hpc hpc1 in\n    let hpc_index2 = get_index_of_pc_among_return_pcs hpcs is_return_hpc hpc2 in\n    assert (hpc_index1 < array_len hpcs);\n    assert (Some? (array_nth hpc_to_lpc hpc_index1));\n    assert (array_nth is_return_hpc hpc_index1 = Some true);\n    assert (hpc_index2 < array_len hpcs);\n    assert (Some? (array_nth hpc_to_lpc hpc_index2));\n    assert (array_nth is_return_hpc hpc_index2 = Some true);\n    array_elements_unique_implication hpcs;\n    assert (find_in_array hpcs hpc1 = Some hpc_index1);\n    assert (find_in_array hpcs hpc2 = Some hpc_index2);\n    let lpc_index1 = array_index hpc_to_lpc hpc_index1 in\n    let lpc_index2 = array_index hpc_to_lpc hpc_index2 in\n    assert (inefficient_hpc_to_lpc hpc1 = make_pc_index_to_pc lpcs lpc_index1);\n    assert (inefficient_hpc_to_lpc hpc2 = make_pc_index_to_pc lpcs lpc_index2);\n    assert (make_pc_index_to_pc lpcs lpc_index1 = make_pc_index_to_pc lpcs lpc_index2);\n    array_elements_unique_implication lpcs;\n    assert (lpc_index1 < array_len lpcs);\n    assert (lpc_index2 < array_len lpcs);\n    assert (lpc_index1 = lpc_index2);\n    assert (array_nth hpc_to_lpc hpc_index1 = array_nth hpc_to_lpc hpc_index2);\n    apply_efficient_return_hpcs_unique (array_len hpcs) hpc_to_lpc is_return_hpc hpc_index1 hpc_index2\n  )\n\nlet each_action_list_consistent_with_is_nonyielding_pc_helper\n  (pcs: array_t pc_t)\n  (is_nonyielding_pc: array_t bool{array_len is_nonyielding_pc = array_len pcs})\n  (action: Armada.Action.t)\n  (pc_indices: statement_pc_indices_t)\n  : Lemma (requires   efficient_action_consistent_with_is_nonyielding_pc is_nonyielding_pc action pc_indices\n                    /\\ action_corresponds_to_statement_pc_indices pcs action pc_indices\n                    /\\ array_elements_unique pcs)\n          (ensures  action_consistent_with_is_nonyielding_pc (make_is_nonyielding_pc pcs is_nonyielding_pc) action) =\n  ()\n\n#pop-options\n\nlet each_action_list_consistent_with_is_nonyielding_pc_lemma\n  (pcs: array_t pc_t)\n  (is_nonyielding_pc: array_t bool{array_len is_nonyielding_pc = array_len pcs})\n  (actions_list: list (list Armada.Action.t))\n  (pc_indices_array: array_t (list statement_pc_indices_t))\n  : Lemma (requires   efficient_each_action_list_consistent_with_is_nonyielding_pc is_nonyielding_pc\n                        (list_to_array actions_list) pc_indices_array\n                    /\\ actions_array_corresponds_to_statement_pc_indices_array pcs (list_to_array actions_list)\n                        pc_indices_array\n                    /\\ array_elements_unique pcs)\n          (ensures each_action_list_consistent_with_is_nonyielding_pc (make_is_nonyielding_pc pcs is_nonyielding_pc)\n                     actions_list) =\n  let inefficient_is_nonyielding_pc = make_is_nonyielding_pc pcs is_nonyielding_pc in\n  introduce forall actions. contains_ubool actions actions_list ==>\n               each_action_consistent_with_is_nonyielding_pc inefficient_is_nonyielding_pc actions\n  with introduce contains_ubool actions actions_list ==>\n                   each_action_consistent_with_is_nonyielding_pc inefficient_is_nonyielding_pc actions\n  with _. introduce forall action. contains_ubool action actions ==>\n                      action_consistent_with_is_nonyielding_pc inefficient_is_nonyielding_pc action\n  with introduce contains_ubool action actions ==>\n                   action_consistent_with_is_nonyielding_pc inefficient_is_nonyielding_pc action\n  with _. (\n    let idx = contains_ubool_to_index actions actions_list in\n    let pc_indices_list = array_index pc_indices_array idx in\n    arrays_correspond_specific_index (action_list_corresponds_to_statement_pc_indices_list pcs)\n      (list_to_array actions_list) pc_indices_array idx;\n    assert (action_list_corresponds_to_statement_pc_indices_list pcs actions pc_indices_list);\n    assert (efficient_each_action_consistent_with_is_nonyielding_pc is_nonyielding_pc actions pc_indices_list);\n    let pc_indices = get_correspondent_from_lists_correspond_doubly\n      (fun action pc_indices -> efficient_action_consistent_with_is_nonyielding_pc is_nonyielding_pc action pc_indices)\n      (action_corresponds_to_statement_pc_indices pcs)\n      actions pc_indices_list action in\n    assert (efficient_action_consistent_with_is_nonyielding_pc is_nonyielding_pc action pc_indices);\n    assert (action_corresponds_to_statement_pc_indices pcs action pc_indices);\n    each_action_list_consistent_with_is_nonyielding_pc_helper pcs is_nonyielding_pc action pc_indices;\n    assert (action_consistent_with_is_nonyielding_pc inefficient_is_nonyielding_pc action)\n  )\n\nlet efficient_action_breaks_implies_action_breaks\n  (pcs: array_t pc_t)\n  (is_breaking_pc: array_t bool{array_len is_breaking_pc = array_len pcs})\n  (action: Armada.Action.t)\n  (pc_indices: statement_pc_indices_t)\n  : Lemma (requires   efficient_action_breaks is_breaking_pc action pc_indices\n                    /\\ action_corresponds_to_statement_pc_indices pcs action pc_indices\n                    /\\ array_elements_unique pcs)\n          (ensures  action_breaks (make_is_breaking_pc pcs is_breaking_pc) action) =\n  ()\n\nlet efficient_action_only_creates_breaking_threads_implies_action_only_creates_breaking_threads\n  (pcs: array_t pc_t)\n  (is_breaking_pc: array_t bool{array_len is_breaking_pc = array_len pcs})\n  (action: Armada.Action.t)\n  (pc_indices: statement_pc_indices_t)\n  : Lemma (requires   efficient_action_only_creates_breaking_threads is_breaking_pc pc_indices\n                    /\\ action_corresponds_to_statement_pc_indices pcs action pc_indices\n                    /\\ array_elements_unique pcs)\n          (ensures  action_only_creates_breaking_threads (make_is_breaking_pc pcs is_breaking_pc) action) =\n  ()\n\nlet rec efficient_actions_end_with_all_threads_breaking_implies_actions_end_with_all_threads_breaking\n  (pcs: array_t pc_t)\n  (is_breaking_pc: array_t bool{array_len is_breaking_pc = array_len pcs})\n  (actions: list Armada.Action.t)\n  (pc_indices_list: list statement_pc_indices_t)\n  : Lemma (requires   efficient_actions_end_with_all_threads_breaking is_breaking_pc actions pc_indices_list\n                    /\\ action_list_corresponds_to_statement_pc_indices_list pcs actions pc_indices_list\n                    /\\ array_elements_unique pcs)\n          (ensures  actions_end_with_all_threads_breaking (make_is_breaking_pc pcs is_breaking_pc) actions) =\n  match actions, pc_indices_list with\n  | [], [] -> false_elim ()\n  | [last_action], [last_pc_indices] ->\n      efficient_action_only_creates_breaking_threads_implies_action_only_creates_breaking_threads\n        pcs is_breaking_pc last_action last_pc_indices;\n      efficient_action_breaks_implies_action_breaks pcs is_breaking_pc last_action last_pc_indices\n  | first_action :: remaining_actions, first_pc_indices :: remaining_pc_indices ->\n      efficient_action_only_creates_breaking_threads_implies_action_only_creates_breaking_threads\n        pcs is_breaking_pc first_action first_pc_indices;\n      efficient_actions_end_with_all_threads_breaking_implies_actions_end_with_all_threads_breaking\n        pcs is_breaking_pc remaining_actions remaining_pc_indices\n  | _, _ -> false_elim ()\n\nlet efficient_actions_maintain_all_threads_breaking_implies_actions_maintain_all_threads_breaking\n  (pcs: array_t pc_t)\n  (is_breaking_pc: array_t bool{array_len is_breaking_pc = array_len pcs})\n  (actions: list Armada.Action.t)\n  (pc_indices_list: list statement_pc_indices_t)\n  : Lemma (requires   efficient_actions_maintain_all_threads_breaking is_breaking_pc actions pc_indices_list\n                    /\\ action_list_corresponds_to_statement_pc_indices_list pcs actions pc_indices_list\n                    /\\ array_elements_unique pcs)\n          (ensures  actions_maintain_all_threads_breaking (make_is_breaking_pc pcs is_breaking_pc) actions) =\n  if efficient_actions_end_with_all_threads_breaking is_breaking_pc actions pc_indices_list then\n    efficient_actions_end_with_all_threads_breaking_implies_actions_end_with_all_threads_breaking\n      pcs is_breaking_pc actions pc_indices_list\n  else\n    ()\n\nlet each_action_list_maintains_all_threads_breaking_lemma\n  (pcs: array_t pc_t)\n  (is_breaking_pc: array_t bool{array_len is_breaking_pc = array_len pcs})\n  (actions_list: list (list Armada.Action.t))\n  (pc_indices_array: array_t (list statement_pc_indices_t))\n  : Lemma (requires   efficient_each_action_list_maintains_all_threads_breaking is_breaking_pc\n                        (list_to_array actions_list) pc_indices_array\n                    /\\ actions_array_corresponds_to_statement_pc_indices_array pcs (list_to_array actions_list)\n                        pc_indices_array\n                    /\\ array_elements_unique pcs)\n          (ensures each_action_list_maintains_all_threads_breaking (make_is_breaking_pc pcs is_breaking_pc)\n                     actions_list) =\n  let inefficient_is_breaking_pc = make_is_breaking_pc pcs is_breaking_pc in\n  introduce forall actions. contains_ubool actions actions_list ==>\n               actions_maintain_all_threads_breaking inefficient_is_breaking_pc actions\n  with introduce contains_ubool actions actions_list ==>\n                   actions_maintain_all_threads_breaking inefficient_is_breaking_pc actions\n  with _. (\n    let idx = contains_ubool_to_index actions actions_list in\n    let pc_indices_list = array_index pc_indices_array idx in\n    arrays_correspond_specific_index (action_list_corresponds_to_statement_pc_indices_list pcs)\n      (list_to_array actions_list) pc_indices_array idx;\n    assert (action_list_corresponds_to_statement_pc_indices_list pcs actions pc_indices_list);\n    assert (efficient_actions_maintain_all_threads_breaking is_breaking_pc actions pc_indices_list);\n    efficient_actions_maintain_all_threads_breaking_implies_actions_maintain_all_threads_breaking\n      pcs is_breaking_pc actions pc_indices_list\n  )\n\nlet rec efficient_hactions_introducible_implies_hactions_introducible\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (inv: invariant_t Armada.State.t)\n  (lpcs: array_t pc_t)\n  (hpcs: array_t pc_t)\n  (hpc_info: array_t (efficient_hpc_info_t vs tds inv){array_len hpc_info = array_len hpcs})\n  (hpc_to_lpc: array_t nat{array_len hpc_to_lpc = array_len hpcs})\n  (is_nonyielding_lpc: array_t bool{array_len is_nonyielding_lpc = array_len lpcs})\n  (hstart_pc: nat)\n  (hend_pc: nat)\n  (introduction_succeeds_witnesses: list (introduction_succeeds_witness_t vs tds inv))\n  (actions: list Armada.Action.t)\n  (pc_indices: list statement_pc_indices_t)\n  : Lemma (requires   efficient_hactions_introducible vs tds inv hpc_to_lpc hstart_pc hend_pc\n                        introduction_succeeds_witnesses actions pc_indices\n                    /\\ array_elements_unique lpcs\n                    /\\ array_elements_unique hpcs\n                    /\\ action_list_corresponds_to_statement_pc_indices_list hpcs actions pc_indices)\n          (ensures  (let inefficient_hpc_info = make_hpc_info vs tds inv hpcs hpc_info in\n                     let inefficient_hpc_to_lpc = make_hpc_to_lpc hpcs lpcs hpc_to_lpc in\n                     let inefficient_is_nonyielding_lpc = make_is_nonyielding_pc lpcs is_nonyielding_lpc in\n                     let inefficient_hpcs = array_to_list hpcs in\n                     hactions_introducible vs tds inv inefficient_hpc_to_lpc (make_pc_index_to_pc hpcs hstart_pc)\n                       (make_pc_index_to_pc hpcs hend_pc) introduction_succeeds_witnesses actions))\n          (decreases introduction_succeeds_witnesses) =\n  match introduction_succeeds_witnesses, actions, pc_indices with\n  | [], [], [] -> ()\n  | first_witness :: remaining_introduction_succeeds_witnesses, first_action :: remaining_actions,\n      first_pc_indices :: remaining_pc_indices ->\n      assert (find_in_array hpcs (make_pc_index_to_pc hpcs hend_pc) = Some hend_pc);\n      assert (find_in_array hpcs (make_pc_index_to_pc hpcs hstart_pc) = Some hstart_pc);\n      efficient_hactions_introducible_implies_hactions_introducible vs tds inv lpcs hpcs hpc_info hpc_to_lpc\n        is_nonyielding_lpc\n        (EfficientThreadStateAtPC?.pc (efficient_action_to_ending_thread_state first_action first_pc_indices))\n        hend_pc remaining_introduction_succeeds_witnesses remaining_actions remaining_pc_indices\n  | _, _, _ -> ()\n\n#push-options \"--z3rlimit 10\"\n\nlet efficient_introduced_atomic_action_makes_progress_implies_introduced_atomic_action_makes_progress\n  (lpcs: array_t pc_t)\n  (hpcs: array_t pc_t)\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (inv: invariant_t Armada.State.t)\n  (hatomic_actions: list (list Armada.Action.t))\n  (hpc_indices_array: array_t (list statement_pc_indices_t))\n  (hpc_info: array_t (efficient_hpc_info_t vs tds inv){array_len hpc_info = array_len hpcs})\n  (hpc_to_lpc: array_t nat{array_len hpc_to_lpc = array_len hpcs})\n  (is_nonyielding_lpc: array_t bool{array_len is_nonyielding_lpc = array_len lpcs})\n  (hpc: nat{hpc < array_len hpcs})\n  (idx: nat)\n  (end_pc: nat)\n  (introduction_succeeds_witnesses: list (introduction_succeeds_witness_t vs tds inv))\n  (progress: nat)\n  (hactions: list Armada.Action.t)\n  (hpc_indices: list statement_pc_indices_t)\n  (lpc: nat)\n  (lpc_nonyielding: bool)\n  : Lemma (requires   efficient_introduced_atomic_action_makes_progress vs tds inv (list_to_array hatomic_actions)\n                        hpc_indices_array hpc_info hpc_to_lpc is_nonyielding_lpc hpc\n                    /\\ action_list_corresponds_to_statement_pc_indices_list hpcs hactions hpc_indices\n                    /\\ array_elements_unique lpcs\n                    /\\ array_elements_unique hpcs\n                    /\\ array_nth (list_to_array hatomic_actions) idx == Some hactions\n                    /\\ array_nth hpc_indices_array idx == Some hpc_indices\n                    /\\ array_nth hpc_to_lpc hpc = Some lpc\n                    /\\ array_nth is_nonyielding_lpc lpc = Some lpc_nonyielding\n                    /\\ efficient_hactions_introducible vs tds inv hpc_to_lpc hpc end_pc\n                        introduction_succeeds_witnesses hactions hpc_indices\n                    /\\ actions_start_atomic_block hactions = not lpc_nonyielding\n                    /\\ actions_end_atomic_block hactions = not lpc_nonyielding\n                    /\\ (match array_nth hpc_info end_pc with\n                       | Some EfficientHPCInfoNormal -> True\n                       | Some (EfficientHPCInfoIntroduced _ _ _ progress') -> progress' < progress))\n          (ensures (let inefficient_hpc_info = make_hpc_info vs tds inv hpcs hpc_info in\n                    let inefficient_hpc_to_lpc = make_hpc_to_lpc hpcs lpcs hpc_to_lpc in\n                    let inefficient_is_nonyielding_lpc = make_is_nonyielding_pc lpcs is_nonyielding_lpc in\n                    let inefficient_hpcs = array_to_list hpcs in\n                    let inefficient_hpc = array_index hpcs hpc in\n                    let hatomic_actions_array = list_to_array hatomic_actions in\n                    let lpc = inefficient_hpc_to_lpc inefficient_hpc in\n                    let lpc_yielding = not (inefficient_is_nonyielding_lpc lpc) in\n                    let inefficient_end_pc = make_pc_index_to_pc hpcs end_pc in\n                    let hpc_indices = array_index hpc_indices_array idx in\n                    let lpc = array_index hpc_to_lpc hpc in\n                    let lpc_nonyielding = array_index is_nonyielding_lpc lpc in\n                    let inefficient_end_pc = array_index hpcs end_pc in\n                       hactions_introducible vs tds inv inefficient_hpc_to_lpc inefficient_hpc inefficient_end_pc\n                         introduction_succeeds_witnesses hactions\n                    /\\ actions_start_atomic_block hactions = lpc_yielding\n                    /\\ actions_end_atomic_block hactions = lpc_yielding\n                    /\\ (match inefficient_hpc_info inefficient_end_pc with\n                       | HPCInfoNormal -> True\n                       | HPCInfoIntroduced _ _ _ progress' -> progress' < progress))) =\n  let inefficient_hpc_info = make_hpc_info vs tds inv hpcs hpc_info in\n  let inefficient_hpc_to_lpc = make_hpc_to_lpc hpcs lpcs hpc_to_lpc in\n  let inefficient_is_nonyielding_lpc = make_is_nonyielding_pc lpcs is_nonyielding_lpc in\n  let inefficient_hpcs = array_to_list hpcs in\n  let inefficient_hpc = array_index hpcs hpc in\n  let hatomic_actions_array = list_to_array hatomic_actions in\n  let lpc = inefficient_hpc_to_lpc inefficient_hpc in\n  let lpc_yielding = not (inefficient_is_nonyielding_lpc lpc) in\n  let inefficient_end_pc = make_pc_index_to_pc hpcs end_pc in\n  let hpc_indices = array_index hpc_indices_array idx in\n  let lpc = array_index hpc_to_lpc hpc in\n  let lpc_nonyielding = array_index is_nonyielding_lpc lpc in\n  let inefficient_end_pc = array_index hpcs end_pc in\n  assert (efficient_hactions_introducible vs tds inv hpc_to_lpc hpc end_pc introduction_succeeds_witnesses hactions\n            hpc_indices);\n  assert (actions_start_atomic_block hactions = not lpc_nonyielding);\n  assert (actions_end_atomic_block hactions = not lpc_nonyielding);\n  assert (match array_nth hpc_info end_pc with\n          | Some EfficientHPCInfoNormal -> True\n          | Some (EfficientHPCInfoIntroduced _ _ _ progress') -> progress' < progress);\n  assert (find_in_array hpcs inefficient_end_pc = Some end_pc);\n  assert (make_pc_index_to_pc hpcs end_pc = inefficient_end_pc);\n  assert (find_in_array lpcs (inefficient_hpc_to_lpc inefficient_hpc) = Some lpc);\n  efficient_hactions_introducible_implies_hactions_introducible vs tds inv lpcs hpcs hpc_info hpc_to_lpc\n    is_nonyielding_lpc hpc end_pc introduction_succeeds_witnesses hactions hpc_indices\n\nlet introduced_atomic_action_makes_progress_helper\n  (lpcs: array_t pc_t)\n  (hpcs: array_t pc_t)\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (inv: invariant_t Armada.State.t)\n  (hatomic_actions: list (list Armada.Action.t))\n  (hpc_indices_array: array_t (list statement_pc_indices_t))\n  (hpc_info: array_t (efficient_hpc_info_t vs tds inv){array_len hpc_info = array_len hpcs})\n  (hpc_to_lpc: array_t nat{array_len hpc_to_lpc = array_len hpcs})\n  (is_nonyielding_lpc: array_t bool{array_len is_nonyielding_lpc = array_len lpcs})\n  (hpc: nat{hpc < array_len hpcs})\n  : Lemma (requires   efficient_introduced_atomic_action_makes_progress vs tds inv (list_to_array hatomic_actions)\n                        hpc_indices_array hpc_info hpc_to_lpc is_nonyielding_lpc hpc\n                    /\\ actions_array_corresponds_to_statement_pc_indices_array hpcs (list_to_array hatomic_actions)\n                        hpc_indices_array \n                    /\\ array_elements_unique lpcs\n                    /\\ array_elements_unique hpcs)\n          (ensures  introduced_atomic_action_makes_progress vs tds inv hatomic_actions\n                      (make_hpc_info vs tds inv hpcs hpc_info) (make_hpc_to_lpc hpcs lpcs hpc_to_lpc)\n                      (make_is_nonyielding_pc lpcs is_nonyielding_lpc) (array_index hpcs hpc)) =\n  let inefficient_hpc_info = make_hpc_info vs tds inv hpcs hpc_info in\n  let inefficient_hpc_to_lpc = make_hpc_to_lpc hpcs lpcs hpc_to_lpc in\n  let inefficient_is_nonyielding_lpc = make_is_nonyielding_pc lpcs is_nonyielding_lpc in\n  let inefficient_hpcs = array_to_list hpcs in\n  let inefficient_hpc = array_index hpcs hpc in\n  let hatomic_actions_array = list_to_array hatomic_actions in\n  assert (array_index hpcs hpc = inefficient_hpc);\n  assert (find_in_array hpcs inefficient_hpc == Some hpc);\n  match array_index hpc_info hpc with\n  | EfficientHPCInfoNormal -> ()\n  | EfficientHPCInfoIntroduced idx end_pc introduction_succeeds_witnesses progress ->\n      assert (find_in_array hpcs inefficient_hpc = Some hpc);\n      assert (inefficient_hpc_info inefficient_hpc ==\n                HPCInfoIntroduced idx (make_pc_index_to_pc hpcs end_pc) introduction_succeeds_witnesses progress);\n      (match array_nth hatomic_actions_array idx, array_nth hpc_indices_array idx with\n       | Some hactions, Some hpc_indices ->\n           list_to_array_implies_nth_equivalent hatomic_actions_array hatomic_actions idx;\n           assert (list_nth hatomic_actions idx == Some hactions);\n           arrays_correspond_specific_index (action_list_corresponds_to_statement_pc_indices_list hpcs)\n             hatomic_actions_array hpc_indices_array idx;\n           assert (action_list_corresponds_to_statement_pc_indices_list hpcs hactions hpc_indices);\n           (match array_nth hpc_to_lpc hpc with\n            | Some lpc ->\n                (match array_nth is_nonyielding_lpc lpc with\n                 | Some lpc_nonyielding ->\n                     assert (efficient_hactions_introducible vs tds inv hpc_to_lpc hpc end_pc\n                               introduction_succeeds_witnesses hactions hpc_indices);\n                     assert (actions_start_atomic_block hactions = not lpc_nonyielding);\n                     assert (actions_end_atomic_block hactions = not lpc_nonyielding);\n                     assert (match array_nth hpc_info end_pc with\n                             | Some EfficientHPCInfoNormal -> True\n                             | Some (EfficientHPCInfoIntroduced _ _ _ progress') -> progress' < progress);\n                     efficient_introduced_atomic_action_makes_progress_implies_introduced_atomic_action_makes_progress\n                       lpcs hpcs vs tds inv hatomic_actions hpc_indices_array hpc_info hpc_to_lpc is_nonyielding_lpc hpc\n                       idx end_pc introduction_succeeds_witnesses progress hactions hpc_indices lpc lpc_nonyielding)))\n\n#pop-options\n\nlet introduced_atomic_action_makes_progress_lemma\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (inv: invariant_t Armada.State.t)\n  (hatomic_actions: list (list Armada.Action.t))\n  (lpcs: array_t pc_t)\n  (hpcs: array_t pc_t)\n  (hpc_to_lpc: array_t nat{array_len hpc_to_lpc = array_len hpcs})\n  (hpc_info: array_t (efficient_hpc_info_t vs tds inv){array_len hpc_info = array_len hpcs})\n  (is_nonyielding_lpc: array_t bool{array_len is_nonyielding_lpc = array_len lpcs})\n  (lpc_to_hpcs: array_t (list nat){array_len lpc_to_hpcs = array_len lpcs})\n  (is_return_hpc: array_t bool{array_len is_return_hpc = array_len hpcs})\n  (hpc_indices_array: array_t (list statement_pc_indices_t))\n  : Lemma (requires   for_all_range_ubool (array_len hpcs)\n                        (efficient_introduced_atomic_action_makes_progress vs tds inv (list_to_array hatomic_actions)\n                          hpc_indices_array hpc_info hpc_to_lpc is_nonyielding_lpc)\n                    /\\ actions_array_corresponds_to_statement_pc_indices_array hpcs (list_to_array hatomic_actions)\n                        hpc_indices_array\n                    /\\ array_elements_unique lpcs\n                    /\\ array_elements_unique hpcs)\n          (ensures  for_all_ubool\n                      (introduced_atomic_action_makes_progress vs tds inv hatomic_actions\n                        (make_hpc_info vs tds inv hpcs hpc_info) (make_hpc_to_lpc hpcs lpcs hpc_to_lpc)\n                        (make_is_nonyielding_pc lpcs is_nonyielding_lpc))\n                      (array_to_list hpcs)) =\n  let inefficient_hpc_info = make_hpc_info vs tds inv hpcs hpc_info in\n  let inefficient_hpc_to_lpc = make_hpc_to_lpc hpcs lpcs hpc_to_lpc in\n  let inefficient_is_nonyielding_lpc = make_is_nonyielding_pc lpcs is_nonyielding_lpc in\n  let inefficient_hpcs = array_to_list hpcs in\n  introduce forall inefficient_hpc. list_contains inefficient_hpc inefficient_hpcs ==>\n               introduced_atomic_action_makes_progress vs tds inv hatomic_actions inefficient_hpc_info\n                 inefficient_hpc_to_lpc inefficient_is_nonyielding_lpc inefficient_hpc\n  with introduce list_contains inefficient_hpc inefficient_hpcs ==>\n                   introduced_atomic_action_makes_progress vs tds inv hatomic_actions inefficient_hpc_info\n                     inefficient_hpc_to_lpc inefficient_is_nonyielding_lpc inefficient_hpc\n  with _. (\n    let hpc = contains_to_index inefficient_hpc inefficient_hpcs in\n    let hatomic_actions_array = list_to_array hatomic_actions in\n    assert (efficient_introduced_atomic_action_makes_progress vs tds inv hatomic_actions_array\n              hpc_indices_array hpc_info hpc_to_lpc is_nonyielding_lpc hpc);\n    assert (array_index hpcs hpc = inefficient_hpc);\n    assert (find_in_array hpcs inefficient_hpc == Some hpc);\n    introduced_atomic_action_makes_progress_helper lpcs hpcs vs tds inv hatomic_actions hpc_indices_array\n      hpc_info hpc_to_lpc is_nonyielding_lpc hpc\n   )\n\nlet efficient_laction_corresponds_to_haction_preservation\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (lpcs: array_t pc_t)\n  (hpcs: array_t pc_t)\n  (hpc_to_lpc: array_t nat{array_len hpc_to_lpc = array_len hpcs})\n  (is_return_hpc: array_t bool{array_len is_return_hpc = array_len hpcs})\n  (laction: Armada.Action.t)\n  (haction: Armada.Action.t)\n  (lpc_indices: statement_pc_indices_t)\n  (hpc_indices: statement_pc_indices_t)\n  : Lemma (requires (let pc_relation = efficient_hl_pc_relation hpc_to_lpc in\n                     let pc_return_relation = efficient_hl_pc_return_relation hpc_to_lpc is_return_hpc in\n                       efficient_laction_corresponds_to_haction vs pc_relation pc_return_relation laction haction\n                         lpc_indices hpc_indices\n                     /\\ action_corresponds_to_statement_pc_indices lpcs laction lpc_indices\n                     /\\ action_corresponds_to_statement_pc_indices hpcs haction hpc_indices\n                     /\\ array_elements_unique hpcs))\n          (ensures  (let inefficient_hpc_to_lpc = make_hpc_to_lpc hpcs lpcs hpc_to_lpc in\n                     let inefficient_return_hpcs = make_return_pcs hpcs is_return_hpc in\n                     laction_corresponds_to_haction vs inefficient_hpc_to_lpc inefficient_return_hpcs laction\n                       haction)) =\n  let pc_relation = efficient_hl_pc_relation hpc_to_lpc in\n  let pc_return_relation = efficient_hl_pc_return_relation hpc_to_lpc is_return_hpc in\n  let inefficient_hpc_to_lpc = make_hpc_to_lpc hpcs lpcs hpc_to_lpc in\n  let inefficient_return_hpcs = make_return_pcs hpcs is_return_hpc in\n  let lps, hps = laction.program_statement, haction.program_statement in\n  let relation = lpc_hpc_pc_relation inefficient_hpc_to_lpc in\n  let return_relation = lpc_hpc_pc_return_relation inefficient_hpc_to_lpc inefficient_return_hpcs in\n  assert (efficient_program_statements_match_per_pc_relation pc_relation pc_return_relation lps hps lpc_indices\n            hpc_indices);\n  lpc_hpc_relation_facts lpcs hpcs hpc_to_lpc is_return_hpc;\n  efficient_program_statements_match_per_pc_relation_implies_program_statements_match_per_pc_relation lpcs hpcs\n    pc_relation pc_return_relation relation return_relation lps hps lpc_indices hpc_indices;\n  assert (program_statements_match_per_pc_relation relation return_relation lps hps)\n\nlet efficient_thread_states_match_per_pc_relation_implies_thread_states_match_per_pc_relation\n  (lpcs: array_t pc_t)\n  (hpcs: array_t pc_t)\n  (hpc_to_lpc: array_t nat{array_len hpc_to_lpc = array_len hpcs})\n  (lts: efficient_thread_state_t)\n  (hts: efficient_thread_state_t)\n  : Lemma (requires (let index_relation = efficient_hl_pc_relation hpc_to_lpc in\n                       efficient_thread_states_match_per_pc_relation index_relation lts hts\n                     /\\ array_elements_unique hpcs))\n          (ensures  (let inefficient_hpc_to_lpc = make_hpc_to_lpc hpcs lpcs hpc_to_lpc in\n                     let pc_relation = lpc_hpc_pc_relation inefficient_hpc_to_lpc in\n                     thread_states_match_per_pc_relation pc_relation\n                       (convert_efficient_thread_state lpcs lts)\n                       (convert_efficient_thread_state hpcs hts)))\n          [SMTPat (thread_states_match_per_pc_relation (lpc_hpc_pc_relation (make_hpc_to_lpc hpcs lpcs hpc_to_lpc))\n                    (convert_efficient_thread_state lpcs lts) (convert_efficient_thread_state hpcs hts))] =\n  ()\n\nlet efficient_start_pc_of_actions_preservation\n  (pcs: array_t pc_t)\n  (actions: list Armada.Action.t)\n  (pc_indices: list statement_pc_indices_t)\n  : Lemma (requires action_list_corresponds_to_statement_pc_indices_list pcs actions pc_indices)\n          (ensures  (let oidx = efficient_start_pc_of_actions pc_indices in\n                     let opc = start_pc_of_actions actions in\n                     match oidx, opc with\n                     | None, None -> True\n                     | Some idx, Some pc -> Some pc = array_nth pcs idx\n                     | _, _ -> False))\n          [SMTPat (start_pc_of_actions actions);\n           SMTPat (action_list_corresponds_to_statement_pc_indices_list pcs actions pc_indices)] =\n  ()\n\nlet invert_make_pc_indices_to_pcs\n  (pcs: array_t pc_t)\n  (pc_indices: list nat{forall idx. list_contains idx pc_indices ==> idx < array_len pcs})\n  (pc: pc_t{list_contains pc (make_pc_indices_to_pcs pcs pc_indices)})\n  : GTot (idx: nat{list_contains idx pc_indices /\\ array_nth pcs idx = Some pc}) =\n  reverse_map_element_of_map_ghost (make_pc_index_to_pc pcs) pc_indices pc\n\nlet invert_make_lpc_to_hpcs\n  (hpcs: array_t pc_t)\n  (lpcs: array_t pc_t)\n  (lpc_to_hpcs: array_t (list nat){\n       array_len lpc_to_hpcs = array_len lpcs\n     /\\ efficient_lpc_to_hpcs_contain_valid_indices (array_len hpcs) lpc_to_hpcs})\n  (lpc: pc_t)\n  (hpc: pc_t{list_contains hpc (make_lpc_to_hpcs hpcs lpcs lpc_to_hpcs lpc)})\n  : GTot (idx: nat{array_nth hpcs idx = Some hpc}) =\n  match find_in_array lpcs lpc with\n  | None -> false_elim ()\n  | Some lpc_index ->\n     let hpc_indices = array_index lpc_to_hpcs lpc_index in\n     assert (list_contains hpc (make_pc_indices_to_pcs hpcs hpc_indices));\n     invert_make_pc_indices_to_pcs hpcs hpc_indices hpc\n\n#push-options \"--z3rlimit 20\"\n\nlet efficient_laction_haction_correspondence_complete_preservation\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (inv: invariant_t Armada.State.t)\n  (lpcs: array_t pc_t)\n  (hpcs: array_t pc_t)\n  (lpc_to_hpcs: array_t (list nat){array_len lpc_to_hpcs = array_len lpcs})\n  (is_breaking_hpc: array_t bool{array_len is_breaking_hpc = array_len hpcs})\n  (hpc_info: array_t (efficient_hpc_info_t vs tds inv){array_len hpc_info = array_len hpcs})\n  (lactions: list Armada.Action.t)\n  (hactions: list Armada.Action.t)\n  (lpc_indices: list statement_pc_indices_t)\n  (hpc_indices: list statement_pc_indices_t)\n  : Lemma (requires   efficient_laction_haction_correspondence_complete vs tds inv lpc_to_hpcs is_breaking_hpc\n                        hpc_info lpc_indices hpc_indices\n                    /\\ action_list_corresponds_to_statement_pc_indices_list lpcs lactions lpc_indices\n                    /\\ action_list_corresponds_to_statement_pc_indices_list hpcs hactions hpc_indices\n                    /\\ efficient_lpc_to_hpcs_contain_valid_indices (array_len hpcs) lpc_to_hpcs\n                    /\\ array_elements_unique lpcs\n                    /\\ array_elements_unique hpcs)\n          (ensures  (let inefficient_lpc_to_hpcs = make_lpc_to_hpcs hpcs lpcs lpc_to_hpcs in\n                     let inefficient_hpc_info = make_hpc_info vs tds inv hpcs hpc_info in\n                     let inefficient_is_breaking_hpc = make_is_breaking_pc hpcs is_breaking_hpc in\n                     laction_haction_correspondence_complete vs tds inv inefficient_lpc_to_hpcs\n                       inefficient_is_breaking_hpc inefficient_hpc_info lactions hactions)) =\n  let inefficient_lpc_to_hpcs = make_lpc_to_hpcs hpcs lpcs lpc_to_hpcs in\n  let inefficient_hpc_info = make_hpc_info vs tds inv hpcs hpc_info in\n  let inefficient_is_breaking_hpc = make_is_breaking_pc hpcs is_breaking_hpc in\n  let opt_start_lpc = start_pc_of_actions lactions in\n  let opt_start_hpc = start_pc_of_actions hactions in\n  match opt_start_lpc, opt_start_hpc with\n  | None, None -> ()\n  | Some start_lpc, Some start_hpc ->\n      introduce forall hpc. list_contains hpc (inefficient_lpc_to_hpcs start_lpc) ==>\n                       laction_haction_correspondence_complete_inner vs tds inv inefficient_is_breaking_hpc\n                         inefficient_hpc_info start_hpc hpc\n      with introduce _ ==> _\n      with _. (\n        match efficient_start_pc_of_actions lpc_indices, efficient_start_pc_of_actions hpc_indices with\n        | Some start_lpc_index, Some start_hpc_index ->\n            let hpc_index = invert_make_lpc_to_hpcs hpcs lpcs lpc_to_hpcs start_lpc hpc in\n            (match array_nth lpc_to_hpcs start_lpc_index with\n             | Some indices ->\n                 assert (inefficient_lpc_to_hpcs start_lpc == make_pc_indices_to_pcs hpcs indices);\n                 make_pc_indices_to_pcs_contains_pc_implies_pc_indices_contains_index hpcs indices hpc hpc_index)\n      )\n  | _, _ -> ()\n\n#pop-options\n\nlet efficient_action_to_starting_thread_state_matches\n  (pcs: array_t pc_t)\n  (action: Armada.Action.t)\n  (pc_indices: statement_pc_indices_t)\n  : Lemma (requires action_corresponds_to_statement_pc_indices pcs action pc_indices)\n          (ensures  action_to_starting_thread_state action = convert_efficient_thread_state pcs\n                      (efficient_action_to_starting_thread_state pc_indices))\n          [SMTPat (action_to_starting_thread_state action);\n           SMTPat (action_corresponds_to_statement_pc_indices pcs action pc_indices)] =\n  ()\n\nlet efficient_action_to_ending_thread_state_matches\n  (pcs: array_t pc_t)\n  (action: Armada.Action.t)\n  (pc_indices: statement_pc_indices_t)\n  : Lemma (requires action_corresponds_to_statement_pc_indices pcs action pc_indices)\n          (ensures  action_to_ending_thread_state action = convert_efficient_thread_state pcs\n                      (efficient_action_to_ending_thread_state action pc_indices))\n          [SMTPat  (action_to_ending_thread_state action);\n           SMTPat  (action_corresponds_to_statement_pc_indices pcs action pc_indices)] =\n  ()\n\nlet rec efficient_actions_to_ending_thread_state_matches\n  (pcs: array_t pc_t)\n  (actions: list Armada.Action.t)\n  (pc_indices_list: list statement_pc_indices_t)\n  : Lemma (requires action_list_corresponds_to_statement_pc_indices_list pcs actions pc_indices_list)\n          (ensures  actions_to_ending_thread_state actions = convert_efficient_thread_state pcs\n                      (efficient_actions_to_ending_thread_state actions pc_indices_list))\n          (decreases actions)\n          [SMTPat  (actions_to_ending_thread_state actions);\n           SMTPat  (action_list_corresponds_to_statement_pc_indices_list pcs actions pc_indices_list)] =\n  match actions, pc_indices_list with\n  | [], _ -> ()\n  | [action], [pc_indices] -> ()\n  | first_action :: remaining_actions, first_pc_indices :: remaining_pc_indices ->\n      efficient_actions_to_ending_thread_state_matches pcs remaining_actions remaining_pc_indices\n  | _, _ -> false_elim ()\n\nlet rec efficient_lactions_correspond_to_hactions_preservation\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (inv: invariant_t Armada.State.t)\n  (lpcs: array_t pc_t)\n  (hpcs: array_t pc_t)\n  (hpc_to_lpc: array_t nat{array_len hpc_to_lpc = array_len hpcs})\n  (is_return_hpc: array_t bool{array_len is_return_hpc = array_len hpcs})\n  (lstart_state: efficient_thread_state_t)\n  (hstart_state: efficient_thread_state_t)\n  (lend_state: efficient_thread_state_t)\n  (hend_state: efficient_thread_state_t)\n  (mapper: list (haction_mapper_t vs tds inv))\n  (lactions: list Armada.Action.t)\n  (hactions: list Armada.Action.t)\n  (lpc_indices: list statement_pc_indices_t)\n  (hpc_indices: list statement_pc_indices_t)\n  : Lemma (requires (let pc_relation = efficient_hl_pc_relation hpc_to_lpc in\n                     let pc_return_relation = efficient_hl_pc_return_relation hpc_to_lpc is_return_hpc in\n                       efficient_lactions_correspond_to_hactions vs tds inv pc_relation pc_return_relation\n                         lstart_state hstart_state lend_state hend_state mapper lactions hactions\n                         lpc_indices hpc_indices\n                     /\\ action_list_corresponds_to_statement_pc_indices_list lpcs lactions lpc_indices\n                     /\\ action_list_corresponds_to_statement_pc_indices_list hpcs hactions hpc_indices\n                     /\\ array_elements_unique lpcs\n                     /\\ array_elements_unique hpcs))\n          (ensures  (let inefficient_hpc_to_lpc = make_hpc_to_lpc hpcs lpcs hpc_to_lpc in\n                     let inefficient_return_hpcs = make_return_pcs hpcs is_return_hpc in\n                     let inefficient_lstart_state = convert_efficient_thread_state lpcs lstart_state in\n                     let inefficient_lend_state = convert_efficient_thread_state lpcs lend_state in\n                     let inefficient_hstart_state = convert_efficient_thread_state hpcs hstart_state in\n                     let inefficient_hend_state = convert_efficient_thread_state hpcs hend_state in\n                     lactions_correspond_to_hactions vs tds inv inefficient_hpc_to_lpc inefficient_return_hpcs\n                       inefficient_lstart_state inefficient_hstart_state inefficient_lend_state\n                       inefficient_hend_state mapper lactions hactions))\n          (decreases hactions) =\n  let pc_relation = efficient_hl_pc_relation hpc_to_lpc in\n  let pc_return_relation = efficient_hl_pc_return_relation hpc_to_lpc is_return_hpc in\n  let inefficient_hpc_to_lpc = make_hpc_to_lpc hpcs lpcs hpc_to_lpc in\n  let inefficient_return_hpcs = make_return_pcs hpcs is_return_hpc in\n  let inefficient_lstart_state = convert_efficient_thread_state lpcs lstart_state in\n  let inefficient_lend_state = convert_efficient_thread_state lpcs lend_state in\n  let inefficient_hstart_state = convert_efficient_thread_state hpcs hstart_state in\n  let inefficient_hend_state = convert_efficient_thread_state hpcs hend_state in\n  let relation = fun lpc hpc -> inefficient_hpc_to_lpc hpc = lpc in\n  lpc_hpc_relation_facts lpcs hpcs hpc_to_lpc is_return_hpc;\n  match mapper, lactions, hactions, lpc_indices, hpc_indices with\n  | [], [], [], [], [] -> ()\n  | MapperMatching :: remaining_mapper, first_laction :: remaining_lactions, first_haction :: remaining_hactions,\n      first_lpc_indices :: remaining_lpc_indices, first_hpc_indices :: remaining_hpc_indices ->\n      efficient_laction_corresponds_to_haction_preservation vs tds lpcs hpcs hpc_to_lpc is_return_hpc\n        first_laction first_haction first_lpc_indices first_hpc_indices;\n      efficient_lactions_correspond_to_hactions_preservation vs tds inv lpcs hpcs hpc_to_lpc is_return_hpc\n        (efficient_action_to_ending_thread_state first_laction first_lpc_indices)\n        (efficient_action_to_ending_thread_state first_haction first_hpc_indices)\n        lend_state hend_state remaining_mapper remaining_lactions remaining_hactions\n        remaining_lpc_indices remaining_hpc_indices\n  | MapperIntroduced witness :: remaining_mapper, _, first_haction :: remaining_hactions, _,\n      first_hpc_indices :: remaining_hpc_indices ->\n      efficient_lactions_correspond_to_hactions_preservation vs tds inv lpcs hpcs hpc_to_lpc is_return_hpc\n        lstart_state (efficient_action_to_ending_thread_state first_haction first_hpc_indices)\n        lend_state hend_state remaining_mapper lactions remaining_hactions lpc_indices\n        remaining_hpc_indices\n  | _, _, _, _, _ -> false_elim ()\n\n#push-options \"--z3rlimit 20\"\n\nlet efficient_corresponding_hactions_info_correct_inner_preservation\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (inv: invariant_t Armada.State.t)\n  (latomic_actions: list (list Armada.Action.t))\n  (hatomic_actions: list (list Armada.Action.t))\n  (lpcs: array_t pc_t)\n  (hpcs: array_t pc_t)\n  (hpc_to_lpc: array_t nat{array_len hpc_to_lpc = array_len hpcs})\n  (hpc_info: array_t (efficient_hpc_info_t vs tds inv){array_len hpc_info = array_len hpcs})\n  (is_nonyielding_lpc: array_t bool{array_len is_nonyielding_lpc = array_len lpcs})\n  (is_breaking_hpc: array_t bool{array_len is_breaking_hpc = array_len hpcs})\n  (lpc_to_hpcs: array_t (list nat){array_len lpc_to_hpcs = array_len lpcs})\n  (is_return_hpc: array_t bool{array_len is_return_hpc = array_len hpcs})\n  (corresponding_hactions_info: array_t (ltoh_correspondence_t vs tds inv)\n    {array_len corresponding_hactions_info = list_len latomic_actions})\n  (lpc_indices_array: array_t (list statement_pc_indices_t))\n  (hpc_indices_array: array_t (list statement_pc_indices_t))\n  (correspondence: ltoh_correspondence_t vs tds inv)\n  (laction_idx: nat{laction_idx < list_len latomic_actions})\n  : Lemma (requires (let pc_relation = efficient_hl_pc_relation hpc_to_lpc in\n                     let pc_return_relation = efficient_hl_pc_return_relation hpc_to_lpc is_return_hpc in\n                       efficient_corresponding_hactions_info_correct_inner vs tds inv (list_to_array latomic_actions)\n                         (list_to_array hatomic_actions) lpc_to_hpcs is_breaking_hpc hpc_info\n                         corresponding_hactions_info lpc_indices_array hpc_indices_array pc_relation\n                         pc_return_relation laction_idx\n                     /\\ efficient_lpc_to_hpcs_contain_valid_indices (array_len hpcs) lpc_to_hpcs\n                     /\\ array_elements_unique lpcs\n                     /\\ array_elements_unique hpcs\n                     /\\ actions_array_corresponds_to_statement_pc_indices_array lpcs (list_to_array latomic_actions)\n                         lpc_indices_array\n                     /\\ actions_array_corresponds_to_statement_pc_indices_array hpcs (list_to_array hatomic_actions)\n                         hpc_indices_array\n                     /\\ array_nth corresponding_hactions_info laction_idx == Some correspondence))\n          (ensures  (let inefficient_hpc_info = make_hpc_info vs tds inv hpcs hpc_info in\n                     let inefficient_hpc_to_lpc = make_hpc_to_lpc hpcs lpcs hpc_to_lpc in\n                     let inefficient_is_nonyielding_lpc = make_is_nonyielding_pc lpcs is_nonyielding_lpc in\n                     let inefficient_is_breaking_hpc = make_is_breaking_pc hpcs is_breaking_hpc in\n                     let inefficient_hpcs = array_to_list hpcs in\n                     let inefficient_return_hpcs = make_return_pcs hpcs is_return_hpc in\n                     let inefficient_lpc_to_hpcs = make_lpc_to_hpcs hpcs lpcs lpc_to_hpcs in\n                     let lactions = list_index latomic_actions laction_idx in\n                     lactions_correspond_to_hactions_per_correspondence vs tds inv\n                       inefficient_hpc_to_lpc inefficient_lpc_to_hpcs inefficient_return_hpcs\n                       inefficient_is_breaking_hpc inefficient_hpc_info hatomic_actions lactions\n                       correspondence)) =\n  let inefficient_hpc_info = make_hpc_info vs tds inv hpcs hpc_info in\n  let inefficient_hpc_to_lpc = make_hpc_to_lpc hpcs lpcs hpc_to_lpc in\n  let inefficient_is_nonyielding_lpc = make_is_nonyielding_pc lpcs is_nonyielding_lpc in\n  let inefficient_is_breaking_hpc = make_is_breaking_pc hpcs is_breaking_hpc in\n  let inefficient_hpcs = array_to_list hpcs in\n  let inefficient_return_hpcs = make_return_pcs hpcs is_return_hpc in\n  let inefficient_lpc_to_hpcs = make_lpc_to_hpcs hpcs lpcs lpc_to_hpcs in\n  let latomic_actions_array = list_to_array latomic_actions in\n  let hatomic_actions_array = list_to_array hatomic_actions in\n  let ltoh_info = array_index corresponding_hactions_info laction_idx in\n  list_to_array_implies_index_equivalent latomic_actions_array latomic_actions laction_idx;\n  assert (list_index latomic_actions laction_idx == array_index latomic_actions_array laction_idx);\n  let lactions = array_index latomic_actions_array laction_idx in\n  let pc_relation = efficient_hl_pc_relation hpc_to_lpc in\n  let pc_return_relation = efficient_hl_pc_return_relation hpc_to_lpc is_return_hpc in\n  assert (efficient_corresponding_hactions_info_correct_inner vs tds inv latomic_actions_array\n            hatomic_actions_array lpc_to_hpcs is_breaking_hpc hpc_info corresponding_hactions_info\n            lpc_indices_array hpc_indices_array pc_relation pc_return_relation laction_idx);\n  let lpc_indices = array_index lpc_indices_array laction_idx in\n  assert (action_list_corresponds_to_statement_pc_indices_list lpcs lactions lpc_indices);\n  let correspondence = array_index corresponding_hactions_info laction_idx in\n  match correspondence with\n  | CorrespondencePropagate hidx ->\n      list_to_array_implies_nth_equivalent hatomic_actions_array hatomic_actions hidx;\n      let hactions = array_index hatomic_actions_array hidx in\n      assert (Some hactions == list_nth hatomic_actions hidx)\n  | CorrespondenceNormal hidx mapper ->\n      list_to_array_implies_nth_equivalent hatomic_actions_array hatomic_actions hidx;\n      (match array_nth hatomic_actions_array hidx, array_nth hpc_indices_array hidx with\n       | Some hactions, Some hpc_indices ->\n           assert (Some hactions == list_nth hatomic_actions hidx);\n           assert (action_list_corresponds_to_statement_pc_indices_list hpcs hactions hpc_indices);\n           let lstart_state = efficient_action_to_starting_thread_state (Cons?.hd lpc_indices) in\n           let lend_state = efficient_actions_to_ending_thread_state lactions lpc_indices in\n           let hstart_state = efficient_action_to_starting_thread_state (Cons?.hd hpc_indices) in\n           let hend_state = efficient_actions_to_ending_thread_state hactions hpc_indices in\n           assert (do_actions_start_and_end_atomic_block lactions = do_actions_start_and_end_atomic_block hactions);\n           efficient_lactions_correspond_to_hactions_preservation vs tds inv lpcs hpcs hpc_to_lpc is_return_hpc\n             lstart_state hstart_state lend_state hend_state\n             mapper lactions hactions lpc_indices hpc_indices;\n           efficient_laction_haction_correspondence_complete_preservation vs tds inv lpcs hpcs lpc_to_hpcs\n             is_breaking_hpc hpc_info lactions hactions lpc_indices hpc_indices;\n           assert (lactions_correspond_to_hactions_per_correspondence vs tds inv\n                     inefficient_hpc_to_lpc inefficient_lpc_to_hpcs inefficient_return_hpcs\n                     inefficient_is_breaking_hpc inefficient_hpc_info hatomic_actions lactions\n                     correspondence))\n\nlet corresponding_hactions_info_correct_lemma\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (inv: invariant_t Armada.State.t)\n  (latomic_actions: list (list Armada.Action.t))\n  (hatomic_actions: list (list Armada.Action.t))\n  (lpcs: array_t pc_t)\n  (hpcs: array_t pc_t)\n  (hpc_to_lpc: array_t nat{array_len hpc_to_lpc = array_len hpcs})\n  (hpc_info: array_t (efficient_hpc_info_t vs tds inv){array_len hpc_info = array_len hpcs})\n  (is_nonyielding_lpc: array_t bool{array_len is_nonyielding_lpc = array_len lpcs})\n  (is_breaking_hpc: array_t bool{array_len is_breaking_hpc = array_len hpcs})\n  (lpc_to_hpcs: array_t (list nat){array_len lpc_to_hpcs = array_len lpcs})\n  (is_return_hpc: array_t bool{array_len is_return_hpc = array_len hpcs})\n  (corresponding_hactions_info: array_t (ltoh_correspondence_t vs tds inv)\n    {array_len corresponding_hactions_info = list_len latomic_actions})\n  (lpc_indices_array: array_t (list statement_pc_indices_t))\n  (hpc_indices_array: array_t (list statement_pc_indices_t))\n  : Lemma (requires   efficient_corresponding_hactions_info_correct vs tds inv (list_to_array latomic_actions)\n                        (list_to_array hatomic_actions) hpc_to_lpc lpc_to_hpcs is_return_hpc is_breaking_hpc\n                        hpc_info corresponding_hactions_info lpc_indices_array hpc_indices_array\n                    /\\ efficient_lpc_to_hpcs_contain_valid_indices (array_len hpcs) lpc_to_hpcs\n                    /\\ array_elements_unique lpcs\n                    /\\ array_elements_unique hpcs\n                    /\\ actions_array_corresponds_to_statement_pc_indices_array lpcs (list_to_array latomic_actions)\n                        lpc_indices_array\n                    /\\ actions_array_corresponds_to_statement_pc_indices_array hpcs (list_to_array hatomic_actions)\n                        hpc_indices_array\n                    /\\ array_len corresponding_hactions_info = array_len (list_to_array latomic_actions))\n          (ensures  (let inefficient_hpc_info = make_hpc_info vs tds inv hpcs hpc_info in\n                     let inefficient_hpc_to_lpc = make_hpc_to_lpc hpcs lpcs hpc_to_lpc in\n                     let inefficient_is_nonyielding_lpc = make_is_nonyielding_pc lpcs is_nonyielding_lpc in\n                     let inefficient_is_breaking_hpc = make_is_breaking_pc hpcs is_breaking_hpc in\n                     let inefficient_hpcs = array_to_list hpcs in\n                     let inefficient_return_hpcs = make_return_pcs hpcs is_return_hpc in\n                     let inefficient_lpc_to_hpcs = make_lpc_to_hpcs hpcs lpcs lpc_to_hpcs in\n                     lists_correspond_ubool\n                       (lactions_correspond_to_hactions_per_correspondence vs tds inv\n                          inefficient_hpc_to_lpc inefficient_lpc_to_hpcs inefficient_return_hpcs\n                          inefficient_is_breaking_hpc inefficient_hpc_info hatomic_actions)\n                       latomic_actions (array_to_list corresponding_hactions_info))) =\n  let inefficient_hpc_info = make_hpc_info vs tds inv hpcs hpc_info in\n  let inefficient_hpc_to_lpc = make_hpc_to_lpc hpcs lpcs hpc_to_lpc in\n  let inefficient_is_nonyielding_lpc = make_is_nonyielding_pc lpcs is_nonyielding_lpc in\n  let inefficient_is_breaking_hpc = make_is_breaking_pc hpcs is_breaking_hpc in\n  let inefficient_hpcs = array_to_list hpcs in\n  let inefficient_return_hpcs = make_return_pcs hpcs is_return_hpc in\n  let inefficient_lpc_to_hpcs = make_lpc_to_hpcs hpcs lpcs lpc_to_hpcs in\n  let inefficient_corresponding_hactions_info = array_to_list corresponding_hactions_info in\n  let latomic_actions_array = list_to_array latomic_actions in\n  let hatomic_actions_array = list_to_array hatomic_actions in\n  list_to_array_implies_length_equivalent latomic_actions_array latomic_actions;\n  assert (list_len latomic_actions = array_len corresponding_hactions_info);\n  introduce forall laction_idx. laction_idx < list_len latomic_actions ==>\n               lactions_correspond_to_hactions_per_correspondence vs tds inv\n                 inefficient_hpc_to_lpc inefficient_lpc_to_hpcs inefficient_return_hpcs\n                 inefficient_is_breaking_hpc inefficient_hpc_info hatomic_actions\n                 (list_index latomic_actions laction_idx)\n                 (list_index inefficient_corresponding_hactions_info laction_idx)\n  with introduce _ ==> _\n  with _. (\n    let ltoh_info = array_index corresponding_hactions_info laction_idx in\n    list_to_array_implies_index_equivalent latomic_actions_array latomic_actions laction_idx;\n    assert (list_index latomic_actions laction_idx == array_index latomic_actions_array laction_idx);\n    let lactions = array_index latomic_actions_array laction_idx in\n    let pc_relation = efficient_hl_pc_relation hpc_to_lpc in\n    let pc_return_relation = efficient_hl_pc_return_relation hpc_to_lpc is_return_hpc in\n    assert (efficient_corresponding_hactions_info_correct_inner vs tds inv latomic_actions_array\n              hatomic_actions_array lpc_to_hpcs is_breaking_hpc hpc_info corresponding_hactions_info\n              lpc_indices_array hpc_indices_array pc_relation pc_return_relation laction_idx);\n    let lpc_indices = array_index lpc_indices_array laction_idx in\n    let hactions_info = array_index corresponding_hactions_info laction_idx in\n    assert (efficient_lactions_correspond_to_hactions_per_correspondence vs tds inv pc_relation pc_return_relation\n              lpc_to_hpcs is_breaking_hpc hpc_info hatomic_actions_array hpc_indices_array lactions lpc_indices\n              hactions_info);\n    let correspondence = array_index corresponding_hactions_info laction_idx in\n    efficient_corresponding_hactions_info_correct_inner_preservation vs tds inv latomic_actions hatomic_actions\n      lpcs hpcs hpc_to_lpc hpc_info is_nonyielding_lpc is_breaking_hpc lpc_to_hpcs is_return_hpc\n      corresponding_hactions_info lpc_indices_array hpc_indices_array correspondence laction_idx\n  );\n  establish_lists_correspond_ubool_from_index_correspondence\n    (lactions_correspond_to_hactions_per_correspondence vs tds inv\n       inefficient_hpc_to_lpc inefficient_lpc_to_hpcs inefficient_return_hpcs\n       inefficient_is_breaking_hpc inefficient_hpc_info hatomic_actions)\n    latomic_actions inefficient_corresponding_hactions_info\n\n#pop-options\n\nlet efficient_var_intro_witness_valid_implies_refinement\n  (latomic_prog: program_t (make_atomic_semantics armada_semantics))\n  (hatomic_prog: program_t (make_atomic_semantics armada_semantics))\n  (evw: efficient_var_intro_witness_t)\n  (* see .fsti file for spec *) =\n  let vw: var_intro_witness_t = {\n    lprog = evw.lprog;\n    hprog = evw.hprog;\n    vs = evw.vs;\n    tds = evw.tds;\n    inv = evw.inv;\n    which_initializers_are_intros = evw.which_initializers_are_intros;\n    hpc_to_lpc = make_hpc_to_lpc evw.hpcs evw.lpcs evw.hpc_to_lpc;\n    lpc_to_hpcs = make_lpc_to_hpcs evw.hpcs evw.lpcs evw.lpc_to_hpcs;\n    return_hpcs = make_return_pcs evw.hpcs evw.is_return_hpc;\n    is_nonyielding_lpc = make_is_nonyielding_pc evw.lpcs evw.is_nonyielding_lpc;\n    is_nonyielding_hpc = make_is_nonyielding_pc evw.hpcs evw.is_nonyielding_hpc;\n    is_breaking_hpc = make_is_breaking_pc evw.hpcs evw.is_breaking_hpc;\n    hpcs = array_to_list evw.hpcs;\n    hpc_info = make_hpc_info evw.vs evw.tds evw.inv evw.hpcs evw.hpc_info;\n    corresponding_hactions_info = array_to_list evw.corresponding_hactions_info;\n  } in\n  program_inits_match_except_global_variables_lemma evw.vs evw.lpcs evw.hpcs evw.hpc_to_lpc\n    evw.which_initializers_are_intros evw.lprog evw.hprog evw.lprog_main_start_pc_index evw.hprog_main_start_pc_index;\n  assert (vw.is_breaking_hpc vw.hprog.main_start_pc);\n  assert (initializers_with_same_variable_id_match vw.hprog.global_initializers);\n  assert (vw.hpc_to_lpc vw.hprog.main_start_pc = vw.lprog.main_start_pc);\n  hstart_pc_among_hpcs_lemma evw.hpcs evw.hprog evw.hprog_main_start_pc_index;\n  assert (list_contains vw.hprog.main_start_pc vw.hpcs);\n  assert (global_variables_unaddressed_in_initializers vw.vs vw.lprog.global_initializers);\n  assert (global_variables_unaddressed_in_initializers vw.vs vw.hprog.global_initializers);\n  assert (global_variables_unaddressed_in_initializers vw.vs vw.lprog.main_stack_initializers);\n  assert (global_variables_unaddressed_in_initializers vw.vs vw.hprog.main_stack_initializers);\n  assert (every_variable_appears_among_initializers vw.hprog.global_initializers vw.vs vw.tds);\n  pcs_contain_new_pcs_of_action_lemma hatomic_prog evw.hprog_actions_array evw.hpc_indices_array evw.hpcs;\n  assert (for_all_ghost (for_all_ghost (pcs_contain_new_pcs_of_action vw.hpcs)) hatomic_prog.actions);\n  every_hpc_appears_among_lpc_to_hpcs_lemma evw.lpcs evw.hpcs evw.hpc_to_lpc evw.lpc_to_hpcs;\n  assert (every_hpc_appears_among_lpc_to_hpcs vw.lpc_to_hpcs vw.hpc_to_lpc vw.hpcs);\n  return_pcs_unique_lemma evw.hpcs evw.lpcs evw.hpc_to_lpc evw.is_return_hpc evw.lpc_to_hpcs;\n  assert (return_pcs_unique vw.hpc_to_lpc vw.return_hpcs);\n  each_action_list_consistent_with_is_nonyielding_pc_lemma evw.lpcs evw.is_nonyielding_lpc latomic_prog.actions\n    evw.lpc_indices_array;\n  assert (each_action_list_consistent_with_is_nonyielding_pc vw.is_nonyielding_lpc latomic_prog.actions);\n  each_action_list_consistent_with_is_nonyielding_pc_lemma evw.hpcs evw.is_nonyielding_hpc hatomic_prog.actions\n    evw.hpc_indices_array;\n  assert (each_action_list_consistent_with_is_nonyielding_pc vw.is_nonyielding_hpc hatomic_prog.actions);\n  each_action_list_maintains_all_threads_breaking_lemma evw.hpcs evw.is_breaking_hpc hatomic_prog.actions\n    evw.hpc_indices_array;\n  assert (each_action_list_maintains_all_threads_breaking vw.is_breaking_hpc hatomic_prog.actions);\n  assert (each_action_list_doesnt_internally_yield latomic_prog.actions);\n  assert (each_action_list_doesnt_internally_yield hatomic_prog.actions);\n  introduced_atomic_action_makes_progress_lemma evw.vs evw.tds evw.inv hatomic_prog.actions evw.lpcs evw.hpcs\n    evw.hpc_to_lpc evw.hpc_info evw.is_nonyielding_lpc evw.lpc_to_hpcs evw.is_return_hpc evw.hpc_indices_array;\n  assert (for_all_ubool (introduced_atomic_action_makes_progress vw.vs vw.tds vw.inv hatomic_prog.actions\n                          vw.hpc_info vw.hpc_to_lpc vw.is_nonyielding_lpc) vw.hpcs);\n  corresponding_hactions_info_correct_lemma evw.vs evw.tds evw.inv latomic_prog.actions hatomic_prog.actions\n    evw.lpcs evw.hpcs evw.hpc_to_lpc evw.hpc_info evw.is_nonyielding_lpc evw.is_breaking_hpc evw.lpc_to_hpcs\n    evw.is_return_hpc evw.corresponding_hactions_info evw.lpc_indices_array evw.hpc_indices_array;\n  assert (lists_correspond_ubool\n           (lactions_correspond_to_hactions_per_correspondence vw.vs vw.tds vw.inv\n              vw.hpc_to_lpc vw.lpc_to_hpcs vw.return_hpcs vw.is_breaking_hpc vw.hpc_info hatomic_prog.actions)\n           latomic_prog.actions vw.corresponding_hactions_info);\n  assert (var_intro_witness_valid latomic_prog hatomic_prog vw);\n  var_intro_witness_valid_implies_refinement latomic_prog hatomic_prog vw\n"
  },
  {
    "path": "experimental/lib/Strategies.VarIntro.Efficient.fsti",
    "content": "module Strategies.VarIntro.Efficient\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Threads\nopen Armada.Transition\nopen Armada.Type\nopen Spec.Behavior\nopen Spec.List\nopen Spec.Logic\nopen Spec.Ubool\nopen Strategies.ArmadaStatement.Propagate\nopen Strategies.ArmadaStatement.ThreadState\nopen Strategies.Atomic\nopen Strategies.Breaking\nopen Strategies.GlobalVars\nopen Strategies.GlobalVars.Permanent\nopen Strategies.GlobalVars.Statement\nopen Strategies.GlobalVars.VarIntro\nopen Strategies.Invariant\nopen Strategies.Invariant.Armada.AtomicSubstep\nopen Strategies.Nonyielding\nopen Strategies.PCIndices\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\nopen Strategies.VarIntro.Defs\nopen Util.ImmutableArray\nopen Util.List\nopen Util.Nth\nopen Util.Range\nopen Util.Relation\n\nnoeq type efficient_hpc_info_t (vs: list var_id_t) (tds: list object_td_t) (inv: invariant_t Armada.State.t) =\n  | EfficientHPCInfoNormal: efficient_hpc_info_t vs tds inv\n  | EfficientHPCInfoIntroduced:\n      (idx: nat) ->\n      (end_pc: nat) ->\n      (introduction_succeeds_witnesses: list (introduction_succeeds_witness_t vs tds inv)) ->\n      (progress: nat) ->\n      efficient_hpc_info_t vs tds inv\n\nlet efficient_program_inits_match_except_global_variables\n  (vs: list var_id_t)\n  (lpcs: array_t pc_t)\n  (hpcs: array_t pc_t)\n  (hpc_to_lpc: array_t nat)\n  (which_initializers_are_intros: list bool)\n  (lprog: Armada.Program.t)\n  (hprog: Armada.Program.t)\n  (lprog_main_start_pc: nat)\n  (hprog_main_start_pc: nat)\n  : GTot ubool =\n    lprog.main_method_id = hprog.main_method_id\n  /\\ array_nth hpc_to_lpc hprog_main_start_pc = Some lprog_main_start_pc\n  /\\ array_nth lpcs lprog_main_start_pc = Some lprog.main_start_pc\n  /\\ array_nth hpcs hprog_main_start_pc = Some hprog.main_start_pc\n  /\\ initializers_match_except_global_variables vs which_initializers_are_intros\n       lprog.global_initializers hprog.global_initializers\n  /\\ lprog.main_stack_initializers == hprog.main_stack_initializers\n\nlet efficient_lpc_to_hpcs_contain_valid_indices\n  (num_hpcs: nat)\n  (lpc_to_hpcs: array_t (list nat))\n  : GTot bool =\n  for_all_array (for_all_ghost (fun (idx: nat) -> idx < num_hpcs)) lpc_to_hpcs\n\nlet efficient_start_pc_of_actions (pc_indices_list: list statement_pc_indices_t) : GTot (option nat) =\n  match pc_indices_list with\n  | [] -> None\n  | pc_indices :: _ -> pc_indices.start_pc_index\n\nlet efficient_hl_pc_relation (hpc_to_lpc: array_t nat) : GTot (relation_t nat nat) =\n  fun lidx hidx -> array_nth hpc_to_lpc hidx = Some lidx\n\nlet efficient_hl_pc_return_relation (hpc_to_lpc: array_t nat) (is_return_hpc: array_t bool) : GTot (relation_t nat nat) =\n  fun lidx hidx -> array_nth hpc_to_lpc hidx = Some lidx && array_nth is_return_hpc hidx = Some true\n\nlet efficient_laction_corresponds_to_haction\n  (vs: list var_id_t)\n  (pc_relation: relation_t nat nat)\n  (pc_return_relation: relation_t nat nat)\n  (laction: Armada.Action.t)\n  (haction: Armada.Action.t)\n  (lpc_indices: statement_pc_indices_t)\n  (hpc_indices: statement_pc_indices_t)\n  : GTot ubool =\n  let lps, hps = laction.program_statement, haction.program_statement in\n     statement_effect_independent_of_global_variables vs lps.statement\n  /\\ efficient_program_statements_match_per_pc_relation pc_relation pc_return_relation lps hps lpc_indices hpc_indices\n\nlet rec efficient_lactions_correspond_to_hactions\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (inv: invariant_t Armada.State.t)\n  (pc_relation: relation_t nat nat)\n  (pc_return_relation: relation_t nat nat)\n  (lstart_state: efficient_thread_state_t)\n  (hstart_state: efficient_thread_state_t)\n  (lend_state: efficient_thread_state_t)\n  (hend_state: efficient_thread_state_t)\n  (mapper: list (haction_mapper_t vs tds inv))\n  (lactions: list Armada.Action.t)\n  (hactions: list Armada.Action.t)\n  (lpc_indices: list statement_pc_indices_t)\n  (hpc_indices: list statement_pc_indices_t)\n  : GTot ubool\n  (decreases hactions) =\n  match mapper, lactions, hactions, lpc_indices, hpc_indices with\n  | [], [], [], [], [] ->\n        lend_state = lstart_state\n      /\\ hend_state = hstart_state\n  | MapperMatching :: remaining_mapper, first_laction :: remaining_lactions, first_haction :: remaining_hactions,\n      first_lpc_indices :: remaining_lpc_indices, first_hpc_indices :: remaining_hpc_indices ->\n        efficient_laction_corresponds_to_haction vs pc_relation pc_return_relation first_laction first_haction\n          first_lpc_indices first_hpc_indices\n      /\\ efficient_action_to_starting_thread_state first_lpc_indices = lstart_state\n      /\\ efficient_action_to_starting_thread_state first_hpc_indices = hstart_state\n      /\\ EfficientThreadStateAtPC? lstart_state\n      /\\ EfficientThreadStateAtPC? hstart_state\n      /\\ efficient_thread_states_match_per_pc_relation pc_relation\n          (efficient_action_to_ending_thread_state first_laction first_lpc_indices)\n          (efficient_action_to_ending_thread_state first_haction first_hpc_indices)\n      /\\ efficient_lactions_correspond_to_hactions vs tds inv pc_relation pc_return_relation\n          (efficient_action_to_ending_thread_state first_laction first_lpc_indices)\n          (efficient_action_to_ending_thread_state first_haction first_hpc_indices)\n          lend_state hend_state remaining_mapper remaining_lactions remaining_hactions\n          remaining_lpc_indices remaining_hpc_indices\n  | MapperIntroduced witness :: remaining_mapper, _, first_haction :: remaining_hactions, _,\n      first_hpc_indices :: remaining_hpc_indices ->\n        first_haction.ok\n      /\\ efficient_action_to_starting_thread_state first_hpc_indices = hstart_state\n      /\\ efficient_thread_states_match_per_pc_relation pc_relation lstart_state\n          (efficient_action_to_ending_thread_state first_haction first_hpc_indices)\n      /\\ valid_introduction_succeeds_witness vs tds inv first_haction.program_statement witness\n      /\\ statement_updates_gvars vs first_haction.program_statement.statement\n      /\\ efficient_lactions_correspond_to_hactions vs tds inv pc_relation pc_return_relation lstart_state\n           (efficient_action_to_ending_thread_state first_haction first_hpc_indices) lend_state hend_state\n           remaining_mapper lactions remaining_hactions lpc_indices remaining_hpc_indices\n  | _, _, _, _, _ -> False\n\nlet efficient_laction_haction_correspondence_complete_inner\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (inv: invariant_t Armada.State.t)\n  (is_breaking_hpc: array_t bool)\n  (hpc_info: array_t (efficient_hpc_info_t vs tds inv))\n  (start_hpc: nat)\n  (hpc: nat)\n  : GTot bool =\n    hpc = start_hpc\n  || array_nth is_breaking_hpc hpc = Some false\n  || (match array_nth hpc_info hpc with\n     | Some (EfficientHPCInfoIntroduced _ _ _ _) -> true\n     | _ -> false)\n\nlet efficient_laction_haction_correspondence_complete\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (inv: invariant_t Armada.State.t)\n  (lpc_to_hpcs: array_t (list nat))\n  (is_breaking_hpc: array_t bool)\n  (hpc_info: array_t (efficient_hpc_info_t vs tds inv))\n  (lpc_indices: list statement_pc_indices_t)\n  (hpc_indices: list statement_pc_indices_t)\n  : GTot bool =\n  let opt_start_lpc = efficient_start_pc_of_actions lpc_indices in\n  let opt_start_hpc = efficient_start_pc_of_actions hpc_indices in\n  match opt_start_lpc, opt_start_hpc with\n  | None, None -> true\n  | Some start_lpc, Some start_hpc ->\n      (match array_nth lpc_to_hpcs start_lpc with\n       | None -> false\n       | Some hpcs ->\n           for_all_ghost\n             (efficient_laction_haction_correspondence_complete_inner vs tds inv is_breaking_hpc hpc_info start_hpc)\n             hpcs)\n  | _, _ -> false\n\nlet rec efficient_hactions_introducible\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (inv: invariant_t Armada.State.t)\n  (hpc_to_lpc: array_t nat)\n  (hstart_pc: nat)\n  (hend_pc: nat)\n  (introduction_succeeds_witnesses: list (introduction_succeeds_witness_t vs tds inv))\n  (actions: list Armada.Action.t)\n  (pc_indices: list statement_pc_indices_t)\n  : GTot ubool\n  (decreases introduction_succeeds_witnesses) =\n  match introduction_succeeds_witnesses, actions, pc_indices with\n  | [], [], [] -> hstart_pc = hend_pc\n  | first_witness :: remaining_introduction_succeeds_witnesses, first_action :: remaining_actions,\n      first_pc_indices :: remaining_pc_indices ->\n        first_action.ok\n      /\\ efficient_action_to_starting_thread_state first_pc_indices = EfficientThreadStateAtPC hstart_pc\n      /\\ EfficientThreadStateAtPC? (efficient_action_to_ending_thread_state first_action first_pc_indices)\n      /\\ hstart_pc < array_len hpc_to_lpc\n      /\\ array_nth hpc_to_lpc hstart_pc = array_nth hpc_to_lpc hend_pc\n      /\\ valid_introduction_succeeds_witness vs tds inv first_action.program_statement first_witness\n      /\\ statement_updates_gvars vs first_action.program_statement.statement\n      /\\ efficient_hactions_introducible vs tds inv hpc_to_lpc\n           (EfficientThreadStateAtPC?.pc (efficient_action_to_ending_thread_state first_action first_pc_indices))\n           hend_pc remaining_introduction_succeeds_witnesses remaining_actions remaining_pc_indices\n  | _, _, _ -> False\n\nlet efficient_introduced_atomic_action_makes_progress\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (inv: invariant_t Armada.State.t)\n  (hatomic_actions_array: array_t (list Armada.Action.t))\n  (hpc_indices_array: array_t (list statement_pc_indices_t))\n  (hpc_info: array_t (efficient_hpc_info_t vs tds inv))\n  (hpc_to_lpc: array_t nat)\n  (is_nonyielding_lpc: array_t bool)\n  (hpc: nat)\n  : GTot ubool =\n  match array_nth hpc_info hpc with\n  | None -> False\n  | Some EfficientHPCInfoNormal -> True\n  | Some (EfficientHPCInfoIntroduced idx end_pc introduction_succeeds_witnesses progress) ->\n      (match array_nth hatomic_actions_array idx, array_nth hpc_indices_array idx with\n       | Some hactions, Some hpc_indices ->\n           (match array_nth hpc_to_lpc hpc with\n            | None -> False\n            | Some lpc ->\n                (match array_nth is_nonyielding_lpc lpc with\n                 | None -> False\n                 | Some lpc_nonyielding ->\n                       efficient_hactions_introducible vs tds inv hpc_to_lpc hpc end_pc introduction_succeeds_witnesses\n                         hactions hpc_indices\n                     /\\ actions_start_atomic_block hactions = not lpc_nonyielding\n                     /\\ actions_end_atomic_block hactions = not lpc_nonyielding\n                     /\\ (match array_nth hpc_info end_pc with\n                        | None -> False\n                        | Some EfficientHPCInfoNormal -> True\n                        | Some (EfficientHPCInfoIntroduced _ _ _ progress') -> progress' < progress)))\n       | _, _ -> False)\n\nlet efficient_lactions_correspond_to_hactions_per_correspondence\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (inv: invariant_t Armada.State.t)\n  (pc_relation: relation_t nat nat)\n  (pc_return_relation: relation_t nat nat)\n  (lpc_to_hpcs: array_t (list nat))\n  (is_breaking_hpc: array_t bool)\n  (hpc_info: array_t (efficient_hpc_info_t vs tds inv))\n  (hatomic_actions_array: array_t (list Armada.Action.t))\n  (hpc_indices_array: array_t (list statement_pc_indices_t))\n  (lactions: list Armada.Action.t)\n  (lpc_indices: list statement_pc_indices_t)\n  (correspondence: ltoh_correspondence_t vs tds inv)\n  : GTot ubool =\n  match correspondence with\n  | CorrespondencePropagate hidx ->\n        Cons? lactions\n      /\\ (Cons?.hd lactions).program_statement == propagate_program_statement\n      /\\ array_nth hatomic_actions_array hidx == Some lactions\n  | CorrespondenceNormal hidx mapper ->\n      (match array_nth hatomic_actions_array hidx, array_nth hpc_indices_array hidx with\n       | Some hactions, Some hpc_indices ->\n             Cons? lactions\n           /\\ Cons? lpc_indices\n           /\\ Cons? hactions\n           /\\ Cons? hpc_indices\n           /\\ (let lstart_state = efficient_action_to_starting_thread_state (Cons?.hd lpc_indices) in\n              let lend_state = efficient_actions_to_ending_thread_state lactions lpc_indices in\n              let hstart_state = efficient_action_to_starting_thread_state (Cons?.hd hpc_indices) in\n              let hend_state = efficient_actions_to_ending_thread_state hactions hpc_indices in\n                do_actions_start_and_end_atomic_block lactions = do_actions_start_and_end_atomic_block hactions\n              /\\ efficient_lactions_correspond_to_hactions vs tds inv pc_relation pc_return_relation\n                   lstart_state hstart_state lend_state hend_state\n                   mapper lactions hactions lpc_indices hpc_indices\n              /\\ efficient_laction_haction_correspondence_complete vs tds inv lpc_to_hpcs is_breaking_hpc hpc_info\n                  lpc_indices hpc_indices)\n       | _, _ -> False)\n\nlet efficient_hpc_among_hpc_to_lpc_to_hpcs\n  (num_hpcs: nat)\n  (hpc_to_lpc: array_t nat)\n  (lpc_to_hpcs: array_t (list nat))\n  : GTot bool =\n  for_all_range num_hpcs\n    (fun hpc -> (match array_nth hpc_to_lpc hpc with\n              | None -> false\n              | Some lpc ->\n                 (match array_nth lpc_to_hpcs lpc with\n                  | None -> false\n                  | Some hpcs -> list_contains hpc hpcs)))\n\nlet efficient_return_hpcs_unique_inner2\n  (hpc_to_lpc: array_t nat)\n  (is_return_hpc: array_t bool)\n  (hpc1: nat)\n  (hpc2: nat)\n  : GTot bool =\n   implies (   array_nth is_return_hpc hpc2 = Some true\n            && array_nth hpc_to_lpc hpc1 = array_nth hpc_to_lpc hpc2)\n           (hpc1 = hpc2)\n\nlet efficient_return_hpcs_unique_inner1\n  (num_hpcs: nat)\n  (hpc_to_lpc: array_t nat)\n  (is_return_hpc: array_t bool)\n  (hpc1: nat)\n  : GTot bool =\n  implies (array_nth is_return_hpc hpc1 = Some true)\n          (for_all_range num_hpcs (efficient_return_hpcs_unique_inner2 hpc_to_lpc is_return_hpc hpc1))\n\nlet efficient_return_hpcs_unique\n  (num_hpcs: nat)\n  (hpc_to_lpc: array_t nat)\n  (is_return_hpc: array_t bool)\n  : GTot bool =\n  for_all_range num_hpcs (efficient_return_hpcs_unique_inner1 num_hpcs hpc_to_lpc is_return_hpc)\n\nlet efficient_corresponding_hactions_info_correct_inner\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (inv: invariant_t Armada.State.t)\n  (lprog_actions_array: array_t (list Armada.Action.t))\n  (hprog_actions_array: array_t (list Armada.Action.t))\n  (lpc_to_hpcs: array_t (list nat))\n  (is_breaking_hpc: array_t bool)\n  (hpc_info: array_t (efficient_hpc_info_t vs tds inv))\n  (corresponding_hactions_info: array_t (ltoh_correspondence_t vs tds inv))\n  (lpc_indices_array: array_t (list statement_pc_indices_t))\n  (hpc_indices_array: array_t (list statement_pc_indices_t))\n  (pc_relation: relation_t nat nat)\n  (pc_return_relation: relation_t nat nat)\n  (idx: nat)\n  : GTot ubool =\n  match array_nth lprog_actions_array idx, array_nth lpc_indices_array idx,\n          array_nth corresponding_hactions_info idx with\n  | Some lactions, Some lpc_indices, Some hactions_info ->\n      efficient_lactions_correspond_to_hactions_per_correspondence vs tds inv pc_relation pc_return_relation\n        lpc_to_hpcs is_breaking_hpc hpc_info hprog_actions_array hpc_indices_array lactions lpc_indices\n        hactions_info\n  | _, _, _ -> False\n\nlet efficient_corresponding_hactions_info_correct\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  (inv: invariant_t Armada.State.t)\n  (lprog_actions_array: array_t (list Armada.Action.t))\n  (hprog_actions_array: array_t (list Armada.Action.t))\n  (hpc_to_lpc: array_t nat)\n  (lpc_to_hpcs: array_t (list nat))\n  (is_return_hpc: array_t bool)\n  (is_breaking_hpc: array_t bool)\n  (hpc_info: array_t (efficient_hpc_info_t vs tds inv))\n  (corresponding_hactions_info: array_t (ltoh_correspondence_t vs tds inv))\n  (lpc_indices_array: array_t (list statement_pc_indices_t))\n  (hpc_indices_array: array_t (list statement_pc_indices_t))\n  : GTot ubool =\n  let pc_relation = efficient_hl_pc_relation hpc_to_lpc in\n  let pc_return_relation = efficient_hl_pc_return_relation hpc_to_lpc is_return_hpc in\n  for_all_range_ubool (array_len lprog_actions_array)\n    (efficient_corresponding_hactions_info_correct_inner vs tds inv lprog_actions_array hprog_actions_array lpc_to_hpcs\n       is_breaking_hpc hpc_info corresponding_hactions_info lpc_indices_array hpc_indices_array pc_relation\n       pc_return_relation)\n\nnoeq type efficient_var_intro_witness_t = {\n  lprog: Armada.Program.t;\n  hprog: Armada.Program.t;\n  lprog_actions_array: array_t (list Armada.Action.t);\n  hprog_actions_array: array_t (list Armada.Action.t);\n  vs: list var_id_t;\n  tds: list object_td_t;\n  inv: invariant_t Armada.State.t;\n  which_initializers_are_intros: list bool;\n  lpcs: array_t pc_t;\n  hpcs: array_t pc_t;\n  hpc_to_lpc: array_t nat;\n  lpc_to_hpcs: array_t (list nat);\n  is_return_hpc: array_t bool;\n  is_nonyielding_lpc: array_t bool;\n  is_nonyielding_hpc: array_t bool;\n  is_breaking_hpc: array_t bool;\n  hpc_info: array_t (efficient_hpc_info_t vs tds inv);\n  corresponding_hactions_info: array_t (ltoh_correspondence_t vs tds inv);\n  lprog_main_start_pc_index: nat;\n  hprog_main_start_pc_index: nat;\n  lpc_indices_array: array_t (list statement_pc_indices_t);\n  hpc_indices_array: array_t (list statement_pc_indices_t);\n}\n\nlet efficient_var_intro_witness_valid\n  (latomic_prog: program_t (make_atomic_semantics armada_semantics))\n  (hatomic_prog: program_t (make_atomic_semantics armada_semantics))\n  (vw: efficient_var_intro_witness_t)\n  : GTot ubool =\n    array_len vw.hpc_to_lpc = array_len vw.hpcs\n  /\\ array_len vw.lpc_to_hpcs = array_len vw.lpcs\n  /\\ array_len vw.is_return_hpc = array_len vw.hpcs\n  /\\ array_len vw.is_nonyielding_lpc = array_len vw.lpcs\n  /\\ array_len vw.is_nonyielding_hpc = array_len vw.hpcs\n  /\\ array_len vw.is_breaking_hpc = array_len vw.hpcs\n  /\\ array_len vw.hpc_info = array_len vw.hpcs\n  /\\ array_len vw.corresponding_hactions_info = array_len vw.lprog_actions_array\n  /\\ array_len vw.lpc_indices_array = array_len vw.lprog_actions_array\n  /\\ array_len vw.hpc_indices_array = array_len vw.hprog_actions_array\n  /\\ array_elements_unique vw.lpcs\n  /\\ array_elements_unique vw.hpcs\n  /\\ efficient_program_inits_match_except_global_variables vw.vs vw.lpcs vw.hpcs vw.hpc_to_lpc\n      vw.which_initializers_are_intros vw.lprog vw.hprog vw.lprog_main_start_pc_index vw.hprog_main_start_pc_index\n  /\\ array_nth vw.is_breaking_hpc vw.hprog_main_start_pc_index = Some true\n  /\\ initializers_with_same_variable_id_match vw.hprog.global_initializers\n  /\\ global_variables_unaddressed_in_initializers vw.vs vw.lprog.global_initializers\n  /\\ global_variables_unaddressed_in_initializers vw.vs vw.hprog.global_initializers\n  /\\ global_variables_unaddressed_in_initializers vw.vs vw.lprog.main_stack_initializers\n  /\\ global_variables_unaddressed_in_initializers vw.vs vw.hprog.main_stack_initializers\n  /\\ every_variable_appears_among_initializers vw.hprog.global_initializers vw.vs vw.tds\n  /\\ actions_array_corresponds_to_statement_pc_indices_array vw.lpcs vw.lprog_actions_array vw.lpc_indices_array\n  /\\ actions_array_corresponds_to_statement_pc_indices_array vw.hpcs vw.hprog_actions_array vw.hpc_indices_array\n  /\\ efficient_lpc_to_hpcs_contain_valid_indices (array_len vw.hpcs) vw.lpc_to_hpcs\n  /\\ efficient_hpc_among_hpc_to_lpc_to_hpcs (array_len vw.hpcs) vw.hpc_to_lpc vw.lpc_to_hpcs\n  /\\ efficient_return_hpcs_unique (array_len vw.hpcs) vw.hpc_to_lpc vw.is_return_hpc\n  /\\ efficient_each_action_list_consistent_with_is_nonyielding_pc vw.is_nonyielding_lpc vw.lprog_actions_array\n      vw.lpc_indices_array\n  /\\ efficient_each_action_list_consistent_with_is_nonyielding_pc vw.is_nonyielding_hpc vw.hprog_actions_array\n      vw.hpc_indices_array\n  /\\ efficient_each_action_list_maintains_all_threads_breaking vw.is_breaking_hpc vw.hprog_actions_array\n      vw.hpc_indices_array\n  /\\ each_action_list_doesnt_internally_yield latomic_prog.actions\n  /\\ each_action_list_doesnt_internally_yield hatomic_prog.actions\n  /\\ for_all_range_ubool (array_len vw.hpcs)\n      (efficient_introduced_atomic_action_makes_progress vw.vs vw.tds vw.inv vw.hprog_actions_array\n         vw.hpc_indices_array vw.hpc_info vw.hpc_to_lpc vw.is_nonyielding_lpc)\n  /\\ efficient_corresponding_hactions_info_correct vw.vs vw.tds vw.inv vw.lprog_actions_array vw.hprog_actions_array\n      vw.hpc_to_lpc vw.lpc_to_hpcs vw.is_return_hpc vw.is_breaking_hpc vw.hpc_info vw.corresponding_hactions_info\n      vw.lpc_indices_array vw.hpc_indices_array\n\nval efficient_var_intro_witness_valid_implies_refinement\n  (latomic_prog: program_t (make_atomic_semantics armada_semantics))\n  (hatomic_prog: program_t (make_atomic_semantics armada_semantics))\n  (evw: efficient_var_intro_witness_t)\n  : Lemma (requires   efficient_var_intro_witness_valid latomic_prog hatomic_prog evw\n                    /\\ is_armada_substep_invariant hatomic_prog evw.inv\n                    /\\ latomic_prog.init_f == init_program evw.lprog\n                    /\\ hatomic_prog.init_f == init_program evw.hprog\n                    /\\ evw.lprog_actions_array == list_to_array latomic_prog.actions\n                    /\\ evw.hprog_actions_array == list_to_array hatomic_prog.actions)\n          (ensures (spec_refines_spec\n                      (semantics_to_spec (make_atomic_semantics armada_semantics) latomic_prog)\n                      (semantics_to_spec (make_atomic_semantics armada_semantics) hatomic_prog)\n                      refinement_requirement))\n"
  },
  {
    "path": "experimental/lib/Strategies.VarIntro.Helpers.fst",
    "content": "module Strategies.VarIntro.Helpers\r\n\r\nopen Armada.Action\r\nopen Armada.Base\r\nopen Armada.Computation\r\nopen Armada.Init\r\nopen Armada.Memory\r\nopen Armada.Program\r\nopen Armada.State\r\nopen Armada.Step\r\nopen Armada.Statement\r\nopen Armada.Thread\r\nopen Armada.Threads\r\nopen Armada.Transition\r\nopen Armada.Type\r\nopen FStar.Sequence.Ambient\r\nopen FStar.Sequence.Base\r\nopen FStar.WellFoundedRelation\r\nopen Spec.Behavior\r\nopen Spec.List\r\nopen Spec.Logic\r\nopen Spec.Ubool\r\nopen Strategies.ArmadaInvariant.RootsMatch\r\nopen Strategies.ArmadaInvariant.PositionsValid\r\nopen Strategies.ArmadaInvariant.UnstartedThreads\r\nopen Strategies.ArmadaStatement.Status\r\nopen Strategies.ArmadaStatement.ThreadState\r\nopen Strategies.Atomic\r\nopen Strategies.GlobalVars\r\nopen Strategies.GlobalVars.Init\r\nopen Strategies.GlobalVars.Statement\r\nopen Strategies.GlobalVars.Types\r\nopen Strategies.GlobalVars.Unaddressed\r\nopen Strategies.GlobalVars.Util\r\nopen Strategies.GlobalVars.VarIntro\r\nopen Strategies.Lift.Generic\r\nopen Strategies.Invariant\r\nopen Strategies.PCRelation\r\nopen Strategies.Semantics\r\nopen Strategies.Semantics.Armada\r\nopen Strategies.VarIntro.Defs\r\nopen Util.List\r\nopen Util.Nth\r\nopen Util.Seq\r\n\r\n/// Definitions\r\n\r\nlet return_pcs_unique_proof_t (hpc_to_lpc: pc_t -> GTot pc_t) (return_hpcs: list pc_t) =\r\n  unit -> Lemma (return_pcs_unique hpc_to_lpc return_hpcs)\r\n\r\nlet var_intro_pc_relation\r\n  (hpc_to_lpc: pc_t -> GTot pc_t)\r\n  (return_hpcs: list pc_t)\r\n  (return_pcs_unique_proof: return_pcs_unique_proof_t hpc_to_lpc return_hpcs)\r\n  : pc_relation_t =\r\n  return_pcs_unique_proof ();\r\n  let return_relation = (fun lpc hpc -> list_contains hpc return_hpcs && hpc_to_lpc hpc = lpc) in\r\n  {\r\n    relation = (fun lpc hpc -> hpc_to_lpc hpc = lpc);\r\n    return_relation = return_relation;\r\n  }\r\n\r\nlet rec compute_hsteps_from_hactions\r\n  (hactions: list Armada.Action.t)\r\n  : Ghost (list Armada.Step.t)\r\n    (requires True)\r\n    (ensures fun hsteps -> map_ghost armada_step_to_action hsteps == hactions) =\r\n  match hactions with\r\n  | [] -> []\r\n  | first_haction :: remaining_hactions ->\r\n      let first_hstep = { nd = []; action = first_haction } in\r\n      first_hstep :: compute_hsteps_from_hactions remaining_hactions\r\n\r\n/// Preserving all_running_threads_have_pcs_in_list\r\n\r\nlet all_running_threads_have_pcs_in_list\r\n  (pcs: list pc_t)\r\n  (s: Armada.State.t)\r\n  : GTot ubool =\r\n  NotStopped? s.stop_reason ==>\r\n    (forall tid.{:pattern s.threads tid} let thread = s.threads tid in\r\n       ThreadStatusRunning? thread.status ==> list_contains thread.pc pcs)\r\n\r\nlet propagate_maintains_all_running_threads_have_pcs_in_list\r\n  (actor: tid_t)\r\n  (nd: nondeterminism_t)\r\n  (pcs: list pc_t)\r\n  (s: Armada.State.t)\r\n  : Lemma (requires   all_running_threads_have_pcs_in_list pcs s\r\n                    /\\ unstarted_threads_have_empty_write_buffers s\r\n                    /\\ (ComputationProduces? (propagate_write_message_statement_computation actor nd s)))\r\n          (ensures  (let s' = ComputationProduces?.result (propagate_write_message_statement_computation actor nd s) in\r\n                       all_running_threads_have_pcs_in_list pcs s'\r\n                     /\\ unstarted_threads_have_empty_write_buffers s')) =\r\n ()\r\n\r\nlet executing_step_maintains_all_running_threads_have_pcs_in_list\r\n  (pcs: list pc_t)\r\n  (actor: tid_t)\r\n  (starts_atomic_block: bool)\r\n  (ends_atomic_block: bool)\r\n  (step: Armada.Step.t)\r\n  (s: Armada.State.t)\r\n  : Lemma (requires   all_running_threads_have_pcs_in_list pcs s\r\n                    /\\ pcs_contain_new_pcs_of_action pcs step.action\r\n                    /\\ list_contains (s.threads actor).pc pcs)\r\n          (ensures  (match step_computation actor starts_atomic_block ends_atomic_block step s with\r\n                     | Some s' -> all_running_threads_have_pcs_in_list pcs s'\r\n                     | None -> True)) =\r\n  match step_computation actor starts_atomic_block ends_atomic_block step s with\r\n  | Some s' ->\r\n      step_effects_on_other_threads actor starts_atomic_block ends_atomic_block step s;\r\r\n      executing_step_changes_status_depending_on_statement actor starts_atomic_block ends_atomic_block step s\r\n  | None -> ()\r\n\r\n/// Correspondence between lsteps and hsteps\r\n\r\nlet lstep_corresponds_to_hstep\r\n  (vs: list var_id_t)\r\n  (pc_relation: pc_relation_t)\r\n  (lstep: Armada.Step.t)\r\n  (hstep: Armada.Step.t)\r\n  : GTot ubool =\r\n  let lps, hps = lstep.action.program_statement, hstep.action.program_statement in\r\n    lstep.nd == hstep.nd\r\n  /\\ statement_effect_independent_of_global_variables vs lps.statement\r\n  /\\ program_statements_match_per_pc_relation pc_relation.relation pc_relation.return_relation lps hps\r\n\r\nlet rec lsteps_correspond_to_hsteps\r\n  (vs: list var_id_t)\r\n  (tds: list object_td_t)\r\n  (inv: invariant_t Armada.State.t)\r\n  (pc_relation: pc_relation_t)\r\n  (lstart_state: thread_state_t)\r\n  (hstart_state: thread_state_t)\r\n  (lend_state: thread_state_t)\r\n  (hend_state: thread_state_t)\r\n  (mapper: list (haction_mapper_t vs tds inv))\r\n  (lsteps: list Armada.Step.t)\r\n  (hsteps: list Armada.Step.t)\r\n  : GTot ubool\r\n  (decreases hsteps) =\r\n  match mapper, lsteps, hsteps with\r\n  | [], [], [] -> True\r\n  | MapperMatching :: remaining_mapper, first_lstep :: remaining_lsteps, first_hstep :: remaining_hsteps ->\r\n      let first_lstep: Armada.Step.t = first_lstep in\r\n      let first_hstep: Armada.Step.t = first_hstep in\r\n         lstep_corresponds_to_hstep vs pc_relation first_lstep first_hstep\r\n      /\\ action_to_starting_thread_state first_lstep.action = lstart_state\r\n      /\\ action_to_starting_thread_state first_hstep.action = hstart_state\r\n      /\\ ThreadStateAtPC? lstart_state\r\n      /\\ ThreadStateAtPC? hstart_state\r\n      /\\ thread_states_match_per_pc_relation pc_relation.relation\r\n           (action_to_ending_thread_state first_lstep.action) (action_to_ending_thread_state first_hstep.action)\r\n      /\\ lsteps_correspond_to_hsteps vs tds inv pc_relation\r\n           (action_to_ending_thread_state first_lstep.action) (action_to_ending_thread_state first_hstep.action)\r\n           lend_state hend_state remaining_mapper remaining_lsteps remaining_hsteps\r\n  | MapperIntroduced witness :: remaining_mapper, _, first_hstep :: remaining_hsteps ->\r\n        first_hstep.action.ok\r\n      /\\ Nil? first_hstep.nd\r\n      /\\ action_to_starting_thread_state first_hstep.action = hstart_state\r\n      /\\ thread_states_match_per_pc_relation pc_relation.relation lstart_state\r\n           (action_to_ending_thread_state first_hstep.action)\r\n      /\\ valid_introduction_succeeds_witness vs tds inv first_hstep.action.program_statement witness\r\n      /\\ statement_updates_gvars vs first_hstep.action.program_statement.statement\r\n      /\\ lsteps_correspond_to_hsteps vs tds inv pc_relation lstart_state\r\n           (action_to_ending_thread_state first_hstep.action) lend_state hend_state\r\n           remaining_mapper lsteps remaining_hsteps\r\n  | _, _, _ -> False\r\n\r\n#push-options \"--z3rlimit 10\"\r\n\r\nlet rec compute_hsteps_from_lsteps\r\n  (vs: list var_id_t)\r\n  (tds: list object_td_t)\r\n  (inv: invariant_t Armada.State.t)\r\n  (hpc_to_lpc: pc_t -> GTot pc_t)\r\n  (return_hpcs: list pc_t)\r\n  (return_pcs_unique_proof: return_pcs_unique_proof_t hpc_to_lpc return_hpcs)\r\n  (lstart_state: thread_state_t)\r\n  (hstart_state: thread_state_t)\r\n  (lend_state: thread_state_t)\r\n  (hend_state: thread_state_t)\r\n  (mapper: list (haction_mapper_t vs tds inv))\r\n  (lactions: list Armada.Action.t)\r\n  (hactions: list Armada.Action.t)\r\n  (lsteps: list Armada.Step.t)\r\n  : Ghost (list Armada.Step.t)\r\n    (requires   lactions == map_ghost armada_step_to_action lsteps\r\n              /\\ lactions_correspond_to_hactions vs tds inv hpc_to_lpc return_hpcs lstart_state hstart_state\r\n                  lend_state hend_state mapper lactions hactions)\r\n    (ensures  fun hsteps -> (let pc_relation = var_intro_pc_relation hpc_to_lpc return_hpcs return_pcs_unique_proof in\r\n                            lsteps_correspond_to_hsteps vs tds inv pc_relation lstart_state hstart_state\r\n                              lend_state hend_state mapper lsteps hsteps\r\n                          /\\ hactions == map_ghost armada_step_to_action hsteps))\r\n    (decreases hactions) =\r\n  let pc_relation = var_intro_pc_relation hpc_to_lpc return_hpcs return_pcs_unique_proof in\r\n  match mapper, lactions, hactions, lsteps with\r\n  | [], [], [], [] -> []\r\n  | MapperMatching :: remaining_mapper, first_laction :: remaining_lactions, first_haction :: remaining_hactions,\r\n      first_lstep :: remaining_lsteps ->\r\n      let first_lstep: Armada.Step.t = first_lstep in\r\n      let hstep = { nd = first_lstep.nd; action = first_haction } in\r\n      let lnext_start_state = action_to_ending_thread_state first_laction in\r\n      let hnext_start_state = action_to_ending_thread_state first_haction in\r\n      let hsteps' = compute_hsteps_from_lsteps vs tds inv hpc_to_lpc return_hpcs return_pcs_unique_proof\r\n                      lnext_start_state hnext_start_state lend_state hend_state remaining_mapper remaining_lactions\r\n                      remaining_hactions remaining_lsteps in\r\n      let hsteps = hstep :: hsteps' in\r\n      assert (lsteps_correspond_to_hsteps vs tds inv pc_relation lstart_state hstart_state\r\n                lend_state hend_state mapper lsteps hsteps);\r\n      hsteps\r\n  | MapperIntroduced _ :: remaining_mapper, _, first_haction :: remaining_hactions, _ ->\r\n      let hstep = { nd = []; action = { ok = true; program_statement = first_haction.program_statement } } in\r\n      let hnext_start_state = action_to_ending_thread_state first_haction in\r\n      let hsteps' = compute_hsteps_from_lsteps vs tds inv hpc_to_lpc return_hpcs return_pcs_unique_proof\r\n                      lstart_state hnext_start_state lend_state hend_state remaining_mapper lactions\r\n                      remaining_hactions lsteps in\r\n      let hsteps = hstep :: hsteps' in\r\n      assert (lsteps_correspond_to_hsteps vs tds inv pc_relation lstart_state hstart_state\r\n                lend_state hend_state mapper lsteps hsteps);\r\n      hsteps\r\n  | _, _, _, _ -> false_elim ()\r\n\r\n#pop-options\r\n\r\nlet lstep_corresponds_to_hstep_clarifier\r\n  (vs: list var_id_t)\r\n  (pc_relation: pc_relation_t)\r\n  (lstep: Armada.Step.t)\r\n  (hstep: Armada.Step.t)\r\n  : Lemma (requires lstep_corresponds_to_hstep vs pc_relation lstep hstep)\r\n          (ensures  (let lps, hps = lstep.action.program_statement, hstep.action.program_statement in\r\n                     match lps.end_pc, hps.end_pc with\r\n                     | Some lpc, Some hpc ->\r\n                           pc_relation.relation lpc hpc\r\n                         /\\ (ReturnStatement? lps.statement ==> pc_relation.return_relation lpc hpc)\r\n                     | None, None -> True\r\n                     | _, _ -> False)) =\r\n  ()\r\n\r\nlet rec lactions_correspond_to_hactions_implies_not_propagate\r\n  (vs: list var_id_t)\r\n  (tds: list object_td_t)\r\n  (inv: invariant_t Armada.State.t)\r\n  (hpc_to_lpc: pc_t -> GTot pc_t)\r\n  (return_hpcs: list pc_t)\r\n  (lstart_state: thread_state_t)\r\n  (hstart_state: thread_state_t)\r\n  (lend_state: thread_state_t)\r\n  (hend_state: thread_state_t)\r\n  (mapper: list (haction_mapper_t vs tds inv))\r\n  (lactions: list Armada.Action.t)\r\n  (hactions: list Armada.Action.t)\r\n  : Lemma (requires lactions_correspond_to_hactions vs tds inv hpc_to_lpc return_hpcs lstart_state hstart_state\r\n                      lend_state hend_state mapper lactions hactions\r\n                    /\\ Cons? lactions)\r\n          (ensures  ~(PropagateWriteMessageStatement? (Cons?.hd lactions).program_statement.statement))\r\n          (decreases hactions) =\r\n  match mapper, lactions, hactions with\r\n  | [], [], [] -> ()\r\n  | MapperMatching :: remaining_mapper, first_laction :: remaining_lactions, first_haction :: remaining_hactions ->\r\n      assert (laction_corresponds_to_haction vs hpc_to_lpc return_hpcs first_laction first_haction);\r\n      assert (~(PropagateWriteMessageStatement? first_laction.program_statement.statement))\r\n  | MapperIntroduced _ :: remaining_mapper, _, first_haction :: remaining_hactions ->\r\n      lactions_correspond_to_hactions_implies_not_propagate vs tds inv hpc_to_lpc return_hpcs lstart_state\r\n           (action_to_ending_thread_state first_haction) lend_state hend_state\r\n           remaining_mapper lactions remaining_hactions\r\n  | _, _, _ -> ()\r\n\r\n#push-options \"--z3rlimit 10\"\r\n\r\nlet rec lsteps_correspond_to_hsteps_implies_first_lstep_matches_lstart_state\r\n  (vs: list var_id_t)\r\n  (tds: list object_td_t)\r\n  (inv: invariant_t Armada.State.t)\r\n  (pc_relation: pc_relation_t)\r\n  (lstart_state: thread_state_t)\r\n  (hstart_state: thread_state_t)\r\n  (lend_state: thread_state_t)\r\n  (hend_state: thread_state_t)\r\n  (mapper: list (haction_mapper_t vs tds inv))\r\n  (lsteps: list Armada.Step.t)\r\n  (hsteps: list Armada.Step.t)\r\n  : Lemma (requires Cons? lsteps\r\n                    /\\ lsteps_correspond_to_hsteps vs tds inv pc_relation lstart_state hstart_state lend_state\r\n                        hend_state mapper lsteps hsteps)\r\n          (ensures    lstart_state = action_to_starting_thread_state (Cons?.hd lsteps).action\r\n                    /\\ ThreadStateAtPC? lstart_state)\r\n          (decreases hsteps) =\r\n  match mapper, lsteps, hsteps with\r\n  | [], [], [] -> false_elim ()\r\n  | MapperMatching :: remaining_mapper, first_lstep :: remaining_lsteps, first_hstep :: remaining_hsteps ->\r\n      ()\r\n  | MapperIntroduced _ :: remaining_mapper, _, first_hstep :: remaining_hsteps ->\r\n      let first_hstep: Armada.Step.t = first_hstep in\r\n      lsteps_correspond_to_hsteps_implies_first_lstep_matches_lstart_state vs tds inv pc_relation\r\n        lstart_state (action_to_ending_thread_state first_hstep.action) lend_state hend_state\r\n        remaining_mapper lsteps remaining_hsteps\r\n  | _, _, _ -> false_elim ()\r\n\r\n#pop-options\r\n\r\n\r\nlet rec propagate_maintains_all_gvars_have_types\r\n  (vs: list var_id_t)\r\n  (tds: list object_td_t)\r\n  (actor: tid_t)\r\n  (nd: nondeterminism_t)\r\n  (s: Armada.State.t)\r\n  : Lemma (requires   all_gvars_have_types s.mem vs tds\r\n                    /\\ (ComputationProduces? (propagate_write_message_statement_computation actor nd s)))\r\n          (ensures  (let s' = ComputationProduces?.result (propagate_write_message_statement_computation actor nd s) in\r\n                     all_gvars_have_types s'.mem vs tds)) =\r\n  match vs, tds with\r\n  | [], [] -> ()\r\n  | first_v :: remaining_vs, first_td :: remaining_tds ->\r\n      propagate_write_message_statement_computation_maintains_gvar_has_type first_v first_td actor nd s;\r\n      propagate_maintains_all_gvars_have_types remaining_vs remaining_tds actor nd s\r\n\r\n/// Maintaining states_match_except_global_variables\r\n\r\nlet update_thread_pcs_in_states_maintains_states_match_except_gvars\r\n  (vs: list var_id_t)\r\n  (pc_relation: pc_relation_t)\r\n  (actor: tid_t)\r\n  (s1: Armada.State.t)\r\n  (s2: Armada.State.t)\r\n  (end_pc1: option pc_t)\r\n  (end_pc2: option pc_t)\r\n  : Lemma (requires   states_match_except_global_variables vs pc_relation s1 s2\r\n                    /\\ optional_pcs_match_per_pc_relation pc_relation end_pc1 end_pc2)\r\n          (ensures  (let s1' = update_thread_pc_in_state s1 actor end_pc1 in\r\n                     let s2' = update_thread_pc_in_state s2 actor end_pc2 in\r\n                     states_match_except_global_variables vs pc_relation s1' s2')) =\r\n  ()\r\n\r\nlet update_thread_pc_in_state_maintains_states_match_except_gvars\r\n  (vs: list var_id_t)\r\n  (pc_relation: pc_relation_t)\r\n  (actor: tid_t)\r\n  (s1: Armada.State.t)\r\n  (s2: Armada.State.t)\r\n  (end_pc2: option pc_t)\r\n  : Lemma (requires   states_match_except_global_variables vs pc_relation s1 s2\r\n                    /\\ Some? end_pc2\r\n                    /\\ pc_relation.relation (s1.threads actor).pc (Some?.v end_pc2))\r\n          (ensures  (let s2' = update_thread_pc_in_state s2 actor end_pc2 in\r\n                     states_match_except_global_variables vs pc_relation s1 s2')) =\r\n  ()\r\n"
  },
  {
    "path": "experimental/lib/Strategies.VarIntro.Inefficient.fst",
    "content": "module Strategies.VarIntro.Inefficient\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Threads\nopen Armada.Transition\nopen Armada.Type\nopen Spec.Behavior\nopen Spec.List\nopen Spec.Logic\nopen Spec.Ubool\nopen Strategies.ArmadaStatement.ThreadState\nopen Strategies.Atomic\nopen Strategies.GlobalVars\nopen Strategies.GlobalVars.Permanent\nopen Strategies.GlobalVars.Statement\nopen Strategies.GlobalVars.VarIntro\nopen Strategies.Invariant\nopen Strategies.Nonyielding\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\nopen Strategies.VarIntro.Defs\nopen Strategies.VarIntro.Relation\nopen Util.List\nopen Util.Nth\nopen Util.Relation\n\nlet var_intro_witness_valid_implies_refinement\n  (latomic_prog: program_t (make_atomic_semantics armada_semantics))\n  (hatomic_prog: program_t (make_atomic_semantics armada_semantics))\n  (vw: var_intro_witness_t)\n  (* see .fsti file for spec *) =\n  let vr: var_intro_relation_t = {\n    lprog = vw.lprog;\n    hprog = vw.hprog;\n    latomic_prog = latomic_prog;\n    hatomic_prog = hatomic_prog;\n    vs = vw.vs;\n    tds = vw.tds;\n    inv = vw.inv;\n    which_initializers_are_intros = vw.which_initializers_are_intros;\n    hpc_to_lpc = vw.hpc_to_lpc;\n    lpc_to_hpcs = vw.lpc_to_hpcs;\n    return_hpcs = vw.return_hpcs;\n    is_nonyielding_lpc = vw.is_nonyielding_lpc;\n    is_nonyielding_hpc = vw.is_nonyielding_hpc;\n    is_breaking_hpc = vw.is_breaking_hpc;\n    hpcs = vw.hpcs;\n    hpc_info = vw.hpc_info;\n    corresponding_hactions_info = vw.corresponding_hactions_info;\n    inv_is_substep_invariant_proof = (fun _ -> ());\n    atomic_inits_match_regular_inits_proof = (fun _ -> ());\n    program_inits_match_except_global_variables_proof = (fun _ -> ());\n    hinitializers_with_same_variable_id_match_proof = (fun _ -> ());\n    initial_pc_in_pcs_proof = (fun _ -> ());\n    initial_pc_breaking_proof = (fun _ -> ());\n    initial_pcs_correspond_proof = (fun _ -> ());\n    global_variables_unaddressed_in_initializers_proof = (fun _ -> ());\n    all_introduced_global_variables_initialized_proof = (fun _ -> ());\n    hpcs_complete_proof = (fun _ -> ());\n    lpc_to_hpcs_consistent_with_hpc_to_lpc_proof = (fun _ -> ());\n    return_pcs_unique_proof = (fun _ -> ());\n    lactions_consistent_with_is_nonyielding_pc_proof = (fun _ -> ());\n    hactions_consistent_with_is_nonyielding_pc_proof = (fun _ -> ());\n    hactions_end_in_breaking_pc_proof = (fun _ -> ());\n    each_laction_doesnt_internally_yield_proof = (fun _ -> ());\n    each_haction_doesnt_internally_yield_proof = (fun _ -> ());\n    introduced_atomic_actions_make_progress_proof = (fun _ -> ());\n    corresponding_hactions_correspond_proof = (fun _ -> ());\n  } in\n  var_intro_relation_implies_refinement vr\n"
  },
  {
    "path": "experimental/lib/Strategies.VarIntro.Inefficient.fsti",
    "content": "module Strategies.VarIntro.Inefficient\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Threads\nopen Armada.Transition\nopen Armada.Type\nopen Spec.Behavior\nopen Spec.List\nopen Spec.Logic\nopen Spec.Ubool\nopen Strategies.ArmadaStatement.ThreadState\nopen Strategies.Atomic\nopen Strategies.Breaking\nopen Strategies.GlobalVars\nopen Strategies.GlobalVars.Permanent\nopen Strategies.GlobalVars.Statement\nopen Strategies.GlobalVars.VarIntro\nopen Strategies.Invariant\nopen Strategies.Invariant.Armada.AtomicSubstep\nopen Strategies.Nonyielding\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\nopen Strategies.VarIntro.Defs\nopen Util.List\nopen Util.Nth\nopen Util.Relation\n\nnoeq type var_intro_witness_t = {\n  lprog: Armada.Program.t;\n  hprog: Armada.Program.t;\n  vs: list var_id_t;\n  tds: list object_td_t;\n  inv: invariant_t Armada.State.t;\n  which_initializers_are_intros: list bool;\n  hpc_to_lpc: pc_t -> GTot pc_t;\n  lpc_to_hpcs: pc_t -> GTot (list pc_t);\n  return_hpcs: list pc_t;\n  is_nonyielding_lpc: pc_t -> GTot bool;\n  is_nonyielding_hpc: pc_t -> GTot bool;\n  is_breaking_hpc: pc_t -> GTot bool;\n  hpcs: list pc_t;\n  hpc_info: pc_t -> GTot (hpc_info_t vs tds inv);\n  corresponding_hactions_info: list (ltoh_correspondence_t vs tds inv);\n}\n\nlet var_intro_witness_valid\n  (latomic_prog: program_t (make_atomic_semantics armada_semantics))\n  (hatomic_prog: program_t (make_atomic_semantics armada_semantics))\n  (vw: var_intro_witness_t)\n  : GTot ubool =\n    program_inits_match_except_global_variables vw.vs vw.hpc_to_lpc vw.which_initializers_are_intros\n      vw.lprog vw.hprog\n  /\\ vw.is_breaking_hpc vw.hprog.main_start_pc\n  /\\ initializers_with_same_variable_id_match vw.hprog.global_initializers\n  /\\ list_contains vw.hprog.main_start_pc vw.hpcs\n  /\\ vw.hpc_to_lpc vw.hprog.main_start_pc = vw.lprog.main_start_pc\n  /\\ global_variables_unaddressed_in_initializers vw.vs vw.lprog.global_initializers\n  /\\ global_variables_unaddressed_in_initializers vw.vs vw.hprog.global_initializers\n  /\\ global_variables_unaddressed_in_initializers vw.vs vw.lprog.main_stack_initializers\n  /\\ global_variables_unaddressed_in_initializers vw.vs vw.hprog.main_stack_initializers\n  /\\ every_variable_appears_among_initializers vw.hprog.global_initializers vw.vs vw.tds\n  /\\ for_all_ghost (for_all_ghost (pcs_contain_new_pcs_of_action vw.hpcs)) hatomic_prog.actions\n  /\\ every_hpc_appears_among_lpc_to_hpcs vw.lpc_to_hpcs vw.hpc_to_lpc vw.hpcs\n  /\\ return_pcs_unique vw.hpc_to_lpc vw.return_hpcs\n  /\\ each_action_list_consistent_with_is_nonyielding_pc vw.is_nonyielding_lpc latomic_prog.actions\n  /\\ each_action_list_consistent_with_is_nonyielding_pc vw.is_nonyielding_hpc hatomic_prog.actions\n  /\\ each_action_list_maintains_all_threads_breaking vw.is_breaking_hpc hatomic_prog.actions\n  /\\ each_action_list_doesnt_internally_yield latomic_prog.actions\n  /\\ each_action_list_doesnt_internally_yield hatomic_prog.actions\n  /\\ for_all_ubool (introduced_atomic_action_makes_progress vw.vs vw.tds vw.inv hatomic_prog.actions\n                      vw.hpc_info vw.hpc_to_lpc vw.is_nonyielding_lpc) vw.hpcs\n  /\\ lists_correspond_ubool\n       (lactions_correspond_to_hactions_per_correspondence vw.vs vw.tds vw.inv\n          vw.hpc_to_lpc vw.lpc_to_hpcs vw.return_hpcs vw.is_breaking_hpc vw.hpc_info hatomic_prog.actions)\n      latomic_prog.actions vw.corresponding_hactions_info\n\nval var_intro_witness_valid_implies_refinement\n  (latomic_prog: program_t (make_atomic_semantics armada_semantics))\n  (hatomic_prog: program_t (make_atomic_semantics armada_semantics))\n  (vw: var_intro_witness_t)\n  : Lemma (requires   var_intro_witness_valid latomic_prog hatomic_prog vw\n                    /\\ is_armada_substep_invariant hatomic_prog vw.inv\n                    /\\ latomic_prog.init_f == init_program vw.lprog\n                    /\\ hatomic_prog.init_f == init_program vw.hprog)\n          (ensures (spec_refines_spec\n                      (semantics_to_spec (make_atomic_semantics armada_semantics) latomic_prog)\n                      (semantics_to_spec (make_atomic_semantics armada_semantics) hatomic_prog)\n                      refinement_requirement))\n"
  },
  {
    "path": "experimental/lib/Strategies.VarIntro.Initialization.fst",
    "content": "module Strategies.VarIntro.Initialization\n\nopen Armada.Base\nopen Armada.Computation\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Program\nopen Armada.State\nopen Armada.Type\nopen Spec.List\nopen Spec.Ubool\nopen Strategies.ArmadaInvariant.RootsMatch\nopen Strategies.ArmadaInvariant.PositionsValid\nopen Strategies.ArmadaInvariant.UnstartedThreads\nopen Strategies.GlobalVars\nopen Strategies.GlobalVars.Init\nopen Strategies.GlobalVars.Statement\nopen Strategies.GlobalVars.Types\nopen Strategies.GlobalVars.Unaddressed\nopen Strategies.GlobalVars.Util\nopen Strategies.GlobalVars.VarIntro\nopen Strategies.Lift.Generic\nopen Strategies.Invariant\nopen Strategies.VarIntro.Defs\nopen Util.List\n\nlet apply_introduced_initializer_ensures_satisfies_global_initializer\n  (init: initializer_t)\n  (existing_inits: list initializer_t)\n  (mem: Armada.Memory.t)\n  : Lemma (requires    memory_satisfies_global_initializers mem existing_inits\n                    /\\ (forall existing_init. contains_ubool existing_init existing_inits ==>\n                         initializers_match_if_same_variable_id existing_init init)\n                    /\\ initializer_ok_for_var_intro init)\n          (ensures  (let mem' = apply_introduced_initializer init mem in\n                       memory_satisfies_global_initializer mem' init\n                     /\\ memory_satisfies_global_initializers mem' existing_inits)) =\n  ()\n\nlet apply_introduced_initializer_makes_memories_match\n  (vs: list var_id_t)\n  (init: initializer_t)\n  (mem: Armada.Memory.t)\n  : Lemma (requires   list_contains init.var_id vs\n                    /\\ initializer_ok_for_var_intro init)\n          (ensures  memories_match_except_global_variables vs mem (apply_introduced_initializer init mem)) =\n  ()\n\nlet initializers_with_same_variable_id_match_equivalent_to_forall\n  (inits: list initializer_t)\n  (* see .fsti file for spec *) =\n  ()\n\nlet rec apply_introduced_initializers_ensures_satisfies_global_initializers_helper\n  (vs: list var_id_t)\n  (which_are_intros: list bool)\n  (all_linits: list initializer_t)\n  (linits: list initializer_t)\n  (hinits: list initializer_t)\n  (lmem: Armada.Memory.t)\n  : Lemma (requires   initializers_match_except_global_variables vs which_are_intros linits hinits\n                    /\\ initializers_with_same_variable_id_match hinits\n                    /\\ memory_satisfies_global_initializers lmem all_linits\n                    /\\ (forall init. contains_ubool init linits ==> contains_ubool init all_linits)\n                    /\\ (forall linit hinit. contains_ubool linit all_linits /\\ contains_ubool hinit hinits ==>\n                                      initializers_match_if_same_variable_id linit hinit))\n          (ensures  (let hmem = apply_introduced_initializers which_are_intros hinits lmem in\n                       memory_satisfies_global_initializers hmem hinits\n                     /\\ memory_satisfies_global_initializers hmem all_linits\n                     /\\ memories_match_except_global_variables vs lmem hmem)) =\n  let hmem = apply_introduced_initializers which_are_intros hinits lmem in\n  match which_are_intros, linits, hinits with\n  | [], _, _ -> ()\n  | true :: remaining_which_are_intros, _, first_hinit :: remaining_hinits ->\n      let mem' = apply_introduced_initializers remaining_which_are_intros remaining_hinits lmem in\n      apply_introduced_initializers_ensures_satisfies_global_initializers_helper vs remaining_which_are_intros\n        all_linits linits remaining_hinits lmem;\n      apply_introduced_initializer_ensures_satisfies_global_initializer first_hinit remaining_hinits mem';\n      apply_introduced_initializer_ensures_satisfies_global_initializer first_hinit all_linits mem';\n      memories_match_except_global_variables_transitive vs lmem mem' hmem\n  | false :: remaining_which_are_intros, first_linit :: remaining_linits, first_hinit :: remaining_hinits ->\n      apply_introduced_initializers_ensures_satisfies_global_initializers_helper vs remaining_which_are_intros\n        all_linits remaining_linits remaining_hinits lmem\n  | _, _, _ -> ()\n\nlet rec initializers_match_except_global_variables_implies_subset_helper\n  (vs: list var_id_t)\n  (which_are_intros: list bool)\n  (linits: list initializer_t)\n  (hinits: list initializer_t)\n  (linit: initializer_t)\n  : Lemma (requires   initializers_match_except_global_variables vs which_are_intros linits hinits\n                    /\\ contains_ubool linit linits)\n          (ensures  contains_ubool linit hinits) =\n  match which_are_intros, linits, hinits with\n  | [], _, _ -> ()\n  | true :: remaining_which_are_intros, _, first_hinit :: remaining_hinits ->\n      initializers_match_except_global_variables_implies_subset_helper vs remaining_which_are_intros linits\n        remaining_hinits linit\n  | false :: remaining_which_are_intros, first_linit :: remaining_linits, first_hinit :: remaining_hinits ->\n      if eqb first_linit linit then\n        ()\n      else\n        initializers_match_except_global_variables_implies_subset_helper vs remaining_which_are_intros\n          remaining_linits remaining_hinits linit\n  | _, _, _ -> ()\n\nlet initializers_match_except_global_variables_implies_subset\n  (vs: list var_id_t)\n  (which_are_intros: list bool)\n  (linits: list initializer_t)\n  (hinits: list initializer_t)\n  : Lemma (requires initializers_match_except_global_variables vs which_are_intros linits hinits)\n          (ensures  forall linit. contains_ubool linit linits ==> contains_ubool linit hinits) =\n  introduce forall linit. contains_ubool linit linits ==> contains_ubool linit hinits\n  with introduce _ ==> _\n  with _. initializers_match_except_global_variables_implies_subset_helper vs which_are_intros linits hinits linit\n\nlet apply_introduced_initializers_ensures_satisfies_global_initializers\n  (vs: list var_id_t)\n  (which_are_intros: list bool)\n  (linits: list initializer_t)\n  (hinits: list initializer_t)\n  (lmem: Armada.Memory.t)\n  (* see .fsti file for spec *) =\n  initializers_match_except_global_variables_implies_subset vs which_are_intros linits hinits;\n  apply_introduced_initializers_ensures_satisfies_global_initializers_helper vs which_are_intros linits\n    linits hinits lmem\n\nlet rec apply_introduced_initializers_maintains_nonglobal_root\n  (which_are_intros: list bool)\n  (inits: list initializer_t)\n  (lmem: Armada.Memory.t)\n  (root_id: root_id_t)\n  : Lemma (requires not (RootIdGlobal? root_id))\n          (ensures  (let hmem = apply_introduced_initializers which_are_intros inits lmem in\n                     hmem root_id == lmem root_id)) =\n  match which_are_intros, inits with\n  | [], _ -> ()\n  | true :: remaining_which_are_intros, first_hinit :: remaining_inits ->\n      apply_introduced_initializers_maintains_nonglobal_root remaining_which_are_intros remaining_inits lmem root_id\n  | false :: remaining_which_are_intros, first_hinit :: remaining_inits ->\n      apply_introduced_initializers_maintains_nonglobal_root remaining_which_are_intros remaining_inits lmem root_id\n  | _, _ -> ()\n\nlet rec apply_introduced_initializers_ensures_satisfies_main_stack_initializers\n  (vs: list var_id_t)\n  (which_are_intros: list bool)\n  (hinits: list initializer_t)\n  (initial_tid: tid_t)\n  (main_method_id: method_id_t)\n  (initial_frame_uniq: root_id_uniquifier_t)\n  (local_variables: list var_id_t)\n  (main_stack_initializers: list initializer_t)\n  (lmem: Armada.Memory.t)\n  (* see .fsti file for spec *) =\n  match local_variables, main_stack_initializers with\n  | [], [] -> ()\n  | var_id :: remaining_var_ids, initializer :: remaining_initializers ->\n      let root_id = RootIdStack initial_tid main_method_id initial_frame_uniq var_id in\n      apply_introduced_initializers_maintains_nonglobal_root which_are_intros hinits lmem root_id;\n      apply_introduced_initializers_ensures_satisfies_main_stack_initializers vs which_are_intros hinits\n        initial_tid main_method_id initial_frame_uniq remaining_var_ids remaining_initializers lmem\n  | _ -> ()\n\nlet rec matching_linits_are_present\n  (which_are_intros: list bool)\n  (linits: list initializer_t)\n  (hinits: list initializer_t)\n  (lmem: Armada.Memory.t)\n  : GTot bool =\n  match which_are_intros, linits, hinits with\n  | [], [], [] -> true\n  | true :: remaining_which_are_intros, _, first_hinit :: remaining_hinits ->\n      matching_linits_are_present remaining_which_are_intros linits remaining_hinits lmem\n  | false :: remaining_which_are_intros, first_linit :: remaining_linits, first_hinit :: remaining_hinits ->\n      (match lmem (RootIdGlobal first_linit.var_id) with\n       | RootGlobal _ -> exists_ghost (var_id_in_initializer first_linit.var_id) linits\n       | _ -> false)\n  | _, _, _ -> false\n\nlet rec initializers_match_except_global_variables_implies_matching_linits_are_present\n  (vs: list var_id_t)\n  (which_are_intros: list bool)\n  (linits: list initializer_t)\n  (hinits: list initializer_t)\n  (lmem: Armada.Memory.t)\n  : Lemma (requires   memory_satisfies_global_initializers lmem linits\n                    /\\ initializers_match_except_global_variables vs which_are_intros linits hinits)\n          (ensures  matching_linits_are_present which_are_intros linits hinits lmem) =\n  match which_are_intros, linits, hinits with\n  | [], [], [] -> ()\n  | true :: remaining_which_are_intros, _, first_hinit :: remaining_hinits ->\n      initializers_match_except_global_variables_implies_matching_linits_are_present vs remaining_which_are_intros\n        linits remaining_hinits lmem\n  | false :: remaining_which_are_intros, first_linit :: remaining_linits, first_hinit :: remaining_hinits ->\n      initializers_match_except_global_variables_implies_matching_linits_are_present vs remaining_which_are_intros\n        remaining_linits remaining_hinits lmem\n  | _, _, _ -> ()\n\nlet apply_introduced_initializer_updates_memory_invalid_outside_initializations\n  (old_inits: list initializer_t)\n  (new_init: initializer_t)\n  (initial_tid: tid_t)\n  (main_method_id: method_id_t)\n  (initial_frame_uniq: root_id_uniquifier_t)\n  (local_variables: list var_id_t)\n  (mem: Armada.Memory.t)\n  : Lemma (requires   memory_invalid_outside_initializations mem old_inits initial_tid main_method_id\n                        initial_frame_uniq local_variables\n                    /\\ roots_match mem)\n          (ensures  (let mem' = apply_introduced_initializer new_init mem in\n                     let combined_inits = list_append [new_init] old_inits in\n                       roots_match mem'\n                     /\\ memory_invalid_outside_initializations mem combined_inits initial_tid main_method_id\n                         initial_frame_uniq local_variables)) =\n  let mem' = apply_introduced_initializer new_init mem in\n  let combined_inits = list_append [new_init] old_inits in\n  introduce forall root_id. root_invalid_outside_initializations mem' combined_inits initial_tid\n                         main_method_id initial_frame_uniq local_variables root_id\n  with (\n    assert (root_invalid_outside_initializations mem old_inits initial_tid main_method_id initial_frame_uniq\n              local_variables root_id);\n    match root_id with\n    | RootIdGlobal root_var_id ->\n        let f = var_id_in_initializer root_var_id in\n        if root_var_id = new_init.var_id then (\n          introduce exists init. f init /\\ contains_ubool init combined_inits\n          with new_init and contains_ubool_append new_init [new_init] old_inits\n        )\n        else (\n          match mem root_id with\n          | RootGlobal _ ->\n              assert (mem' root_id == mem root_id);\n              assert (exists_ghost f old_inits);\n              eliminate exists init. f init /\\ contains_ubool init old_inits\n              returns exists init. f init /\\ contains_ubool init combined_inits\n              with _. (\n                introduce exists init. f init /\\ contains_ubool init combined_inits\n                with init and contains_ubool_append init [new_init] old_inits\n              )\n          | _ -> ()\n        )\n    | _ -> ()\n  )\n\nlet expand_memory_invalid_outside_initializations\n  (old_inits: list initializer_t)\n  (new_inits: list initializer_t)\n  (initial_tid: tid_t)\n  (main_method_id: method_id_t)\n  (initial_frame_uniq: root_id_uniquifier_t)\n  (local_variables: list var_id_t)\n  (mem: Armada.Memory.t)\n  : Lemma (requires   memory_invalid_outside_initializations mem old_inits initial_tid main_method_id\n                        initial_frame_uniq local_variables\n                    /\\ roots_match mem)\n          (ensures  memory_invalid_outside_initializations mem (list_append new_inits old_inits)\n                      initial_tid main_method_id initial_frame_uniq local_variables) =\n  let combined_inits = list_append new_inits old_inits in\n  introduce forall root_id. root_invalid_outside_initializations mem combined_inits initial_tid\n                         main_method_id initial_frame_uniq local_variables root_id\n  with (\n    assert (root_invalid_outside_initializations mem old_inits initial_tid main_method_id initial_frame_uniq\n              local_variables root_id);\n    match root_id with\n    | RootIdGlobal root_var_id ->\n        let f = var_id_in_initializer root_var_id in\n        (match mem root_id with\n         | RootGlobal _ ->\n             assert (exists_ghost f old_inits);\n             eliminate exists init. f init /\\ contains_ubool init old_inits\n             returns exists init. f init /\\ contains_ubool init combined_inits\n             with _. (\n               introduce exists init. f init /\\ contains_ubool init combined_inits\n               with init and contains_ubool_append init new_inits old_inits\n             )\n         | _ -> ())\n    | _ -> ()\n  )\n\n#push-options \"--z3rlimit 10\"\n\nlet rec apply_introduced_initializers_updates_memory_invalid_outside_initializations\n  (which_are_intros: list bool)\n  (old_inits: list initializer_t)\n  (new_inits: list initializer_t)\n  (initial_tid: tid_t)\n  (main_method_id: method_id_t)\n  (initial_frame_uniq: root_id_uniquifier_t)\n  (local_variables: list var_id_t)\n  (mem: Armada.Memory.t)\n  : Lemma (requires   memory_invalid_outside_initializations mem old_inits initial_tid main_method_id\n                        initial_frame_uniq local_variables\n                    /\\ roots_match mem)\n          (ensures  (let mem' = apply_introduced_initializers which_are_intros new_inits mem in\n                       memory_invalid_outside_initializations mem' (list_append new_inits old_inits)\n                         initial_tid main_method_id initial_frame_uniq local_variables\n                     /\\ roots_match mem')) =\n  match which_are_intros, new_inits with\n  | [], [] -> ()\n  | true :: remaining_which_are_intros, new_init :: remaining_inits ->\n      apply_introduced_initializers_updates_memory_invalid_outside_initializations remaining_which_are_intros\n        old_inits remaining_inits initial_tid main_method_id initial_frame_uniq local_variables mem;\n      let mem' = apply_introduced_initializers remaining_which_are_intros remaining_inits mem in\n      assert (memory_invalid_outside_initializations mem' (list_append remaining_inits old_inits)\n                initial_tid main_method_id initial_frame_uniq local_variables);\n      apply_introduced_initializer_updates_memory_invalid_outside_initializations\n        (list_append remaining_inits old_inits) new_init initial_tid main_method_id initial_frame_uniq\n        local_variables mem';\n      assert (list_append [new_init] (list_append remaining_inits old_inits) ==\n                list_append new_inits old_inits)\n  | false :: remaining_which_are_intros, new_init :: remaining_inits ->\n      apply_introduced_initializers_updates_memory_invalid_outside_initializations remaining_which_are_intros\n        old_inits remaining_inits initial_tid main_method_id initial_frame_uniq local_variables mem;\n      let mem' = apply_introduced_initializers remaining_which_are_intros remaining_inits mem in\n      expand_memory_invalid_outside_initializations (list_append remaining_inits old_inits)\n        [new_init] initial_tid main_method_id initial_frame_uniq local_variables mem';\n      assert (list_append [new_init] (list_append remaining_inits old_inits) ==\n                list_append new_inits old_inits)\n  | _, _ ->\n      expand_memory_invalid_outside_initializations old_inits new_inits initial_tid main_method_id\n        initial_frame_uniq local_variables mem\n\n#pop-options\n\nlet if_in_append_but_not_first_of_either_then_in_append_tails\n  (#a: Type)\n  (x: a)\n  (l1: list a)\n  (l2: list a)\n  : Lemma (requires   contains_ubool x (list_append l1 l2)\n                    /\\ (match l1, l2 with\n                       | hd1 :: tl1, hd2 :: tl2 -> neqb x hd1 /\\ neqb x hd2\n                       | _, _ -> False))\n          (ensures  (match l1, l2 with\n                     | hd1 :: tl1, hd2 :: tl2 -> contains_ubool x (list_append tl1 tl2)\n                     | _ -> False)) =\n  match l1, l2 with\n  | hd1 :: tl1, hd2 :: tl2 ->\n      contains_ubool_append x l1 l2;\n      contains_ubool_append x tl1 tl2\n\nlet rec hinits_subset_of_combined_inits\n  (vs: list var_id_t)\n  (which_are_intros: list bool)\n  (linits: list initializer_t)\n  (hinits: list initializer_t)\n  (init: initializer_t)\n  : Lemma (requires   initializers_match_except_global_variables vs which_are_intros linits hinits\n                    /\\ contains_ubool init (list_append hinits linits))\n          (ensures  contains_ubool init hinits) =\n  match which_are_intros, linits, hinits with\n  | [], [], [] -> ()\n  | true :: remaining_which_are_intros, _, first_hinit :: remaining_hinits ->\n      if eqb first_hinit init then\n        ()\n      else\n        hinits_subset_of_combined_inits vs remaining_which_are_intros linits remaining_hinits init\n  | false :: remaining_which_are_intros, first_linit :: remaining_linits, first_hinit :: remaining_hinits ->\n      if eqb first_hinit init then\n        ()\n      else (\n        if_in_append_but_not_first_of_either_then_in_append_tails init hinits linits;\n        hinits_subset_of_combined_inits vs remaining_which_are_intros remaining_linits remaining_hinits init\n      )\n  | _, _, _ -> ()\n\nlet apply_introduced_initializers_ensures_memory_invalid_outside_initializations\n  (vs: list var_id_t)\n  (which_are_intros: list bool)\n  (linits: list initializer_t)\n  (hinits: list initializer_t)\n  (initial_tid: tid_t)\n  (main_method_id: method_id_t)\n  (initial_frame_uniq: root_id_uniquifier_t)\n  (local_variables: list var_id_t)\n  (lmem: Armada.Memory.t)\n  (* see .fsti file for spec *) =\n  let hmem = apply_introduced_initializers which_are_intros hinits lmem in\n  apply_introduced_initializers_updates_memory_invalid_outside_initializations which_are_intros linits hinits\n    initial_tid main_method_id initial_frame_uniq local_variables lmem;\n  introduce forall root_id. root_invalid_outside_initializations hmem hinits initial_tid\n                         main_method_id initial_frame_uniq local_variables root_id\n  with (\n    let combined_inits = list_append hinits linits in\n    assert (root_invalid_outside_initializations hmem combined_inits initial_tid main_method_id\n              initial_frame_uniq local_variables root_id);\n    match hmem root_id with\n    | RootGlobal _ ->\n        (match root_id with\n         | RootIdGlobal var_id ->\n             let f = var_id_in_initializer var_id in\n             let init = exists_ghost_to_witness f combined_inits in\n             hinits_subset_of_combined_inits vs which_are_intros linits hinits init;\n             assert (contains_ubool init hinits);\n             exists_ghost_equivalent_to_exists f hinits;\n             assert (exists_ghost f hinits)\n         | _ -> ())\n    | _ -> ()\n  )\n\nlet apply_introduced_initializer_ensures_gvar_has_type\n  (init: initializer_t)\n  (mem: Armada.Memory.t)\n  (* see .fsti file for spec *) =\n  ()\n"
  },
  {
    "path": "experimental/lib/Strategies.VarIntro.Initialization.fsti",
    "content": "module Strategies.VarIntro.Initialization\n\nopen Armada.Base\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Type\nopen Spec.List\nopen Strategies.ArmadaInvariant.RootsMatch\nopen Strategies.GlobalVars\nopen Strategies.GlobalVars.Types\nopen Strategies.VarIntro.Defs\n\nlet apply_introduced_initializer\n  (init: initializer_t)\n  (mem: Armada.Memory.t)\n  : GTot Armada.Memory.t =\n  match init.iv with\n  | InitializerSpecific value ->\n      (match value with\n       | ObjectValuePrimitive _\n       | ObjectValueAbstract _ _ ->\n           let root_id = RootIdGlobal init.var_id in\n           let storage = object_value_to_storage value in\n           let root = RootGlobal storage in\n           Spec.Map.upd mem root_id root\n       | _ -> mem)\n  | _ -> mem\n\nlet rec apply_introduced_initializers\n  (which_are_intros: list bool)\n  (inits: list initializer_t)\n  (mem: Armada.Memory.t)\n  : GTot Armada.Memory.t =\n  match which_are_intros, inits with\n  | [], _ -> mem\n  | true :: remaining_which_are_intros, first_hinit :: remaining_inits ->\n      let mem' = apply_introduced_initializers remaining_which_are_intros remaining_inits mem in\n      apply_introduced_initializer first_hinit mem'\n  | false :: remaining_which_are_intros, first_hinit :: remaining_inits ->\n      apply_introduced_initializers remaining_which_are_intros remaining_inits mem\n  | _, _ -> mem\n\nval initializers_with_same_variable_id_match_equivalent_to_forall\n  (inits: list initializer_t)\n  : Lemma (ensures initializers_with_same_variable_id_match inits <==>\n                   (forall init1 init2. contains_ubool init1 inits /\\ contains_ubool init2 inits ==>\n                      initializers_match_if_same_variable_id init1 init2))\n\nval apply_introduced_initializers_ensures_satisfies_global_initializers\n  (vs: list var_id_t)\n  (which_are_intros: list bool)\n  (linits: list initializer_t)\n  (hinits: list initializer_t)\n  (lmem: Armada.Memory.t)\n  : Lemma (requires    initializers_match_except_global_variables vs which_are_intros linits hinits\n                    /\\ initializers_with_same_variable_id_match hinits\n                    /\\ memory_satisfies_global_initializers lmem linits)\n          (ensures  (let hmem = apply_introduced_initializers which_are_intros hinits lmem in\n                       memory_satisfies_global_initializers hmem hinits\n                     /\\ memories_match_except_global_variables vs lmem hmem))\n\nval apply_introduced_initializers_ensures_satisfies_main_stack_initializers\n  (vs: list var_id_t)\n  (which_are_intros: list bool)\n  (hinits: list initializer_t)\n  (initial_tid: tid_t)\n  (main_method_id: method_id_t)\n  (initial_frame_uniq: root_id_uniquifier_t)\n  (local_variables: list var_id_t)\n  (main_stack_initializers: list initializer_t)\n  (lmem: Armada.Memory.t)\n  : Lemma (requires memory_satisfies_main_stack_initializers lmem initial_tid main_method_id initial_frame_uniq\n                      local_variables main_stack_initializers)\n          (ensures  (let hmem = apply_introduced_initializers which_are_intros hinits lmem in\n                     memory_satisfies_main_stack_initializers hmem initial_tid main_method_id initial_frame_uniq\n                        local_variables main_stack_initializers))\n\nval apply_introduced_initializers_ensures_memory_invalid_outside_initializations\n  (vs: list var_id_t)\n  (which_are_intros: list bool)\n  (linits: list initializer_t)\n  (hinits: list initializer_t)\n  (initial_tid: tid_t)\n  (main_method_id: method_id_t)\n  (initial_frame_uniq: root_id_uniquifier_t)\n  (local_variables: list var_id_t)\n  (lmem: Armada.Memory.t)\n  : Lemma (requires   memory_invalid_outside_initializations lmem linits initial_tid main_method_id\n                        initial_frame_uniq local_variables\n                    /\\ initializers_match_except_global_variables vs which_are_intros linits hinits\n                    /\\ roots_match lmem)\n          (ensures  (let hmem = apply_introduced_initializers which_are_intros hinits lmem in\n                     memory_invalid_outside_initializations hmem hinits initial_tid main_method_id\n                       initial_frame_uniq local_variables))\n\nval apply_introduced_initializer_ensures_gvar_has_type\n  (init: initializer_t)\n  (mem: Armada.Memory.t)\n  : Lemma (requires initializer_ok_for_var_intro init)\n          (ensures (let mem' = apply_introduced_initializer init mem in\n                      gvar_has_type mem' init.var_id (initializer_value_to_td init.iv)\n                    /\\ (forall v td. gvar_has_type mem v td /\\ v <> init.var_id ==> gvar_has_type mem' v td)))\n"
  },
  {
    "path": "experimental/lib/Strategies.VarIntro.Invariant.fst",
    "content": "module Strategies.VarIntro.Invariant\n\nopen Armada.Base\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Program\nopen Armada.State\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Threads\nopen Armada.Transition\nopen Armada.Type\nopen FStar.Sequence.Base\nopen Spec.List\nopen Spec.Ubool\nopen Strategies.ArmadaStatement.Breaking\nopen Strategies.ArmadaInvariant.RootsMatch\nopen Strategies.ArmadaInvariant.PositionsValid\nopen Strategies.ArmadaInvariant.UnstartedThreads\nopen Strategies.ArmadaStatement.Status\nopen Strategies.ArmadaStatement.ThreadState\nopen Strategies.Atomic\nopen Strategies.GlobalVars\nopen Strategies.GlobalVars.Types\nopen Strategies.Invariant\nopen Strategies.PCRelation\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\nopen Strategies.VarIntro.Defs\nopen Strategies.VarIntro.Helpers\nopen Strategies.VarIntro.Initialization\n\nlet var_intro_invariant\n  (ls: Armada.State.t)\n  : GTot ubool =\n  True\n\nlet var_intro_lh_relation_between_steps\n  (vr: var_intro_relation_t)\n  (u: unit)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  : GTot ubool =\n  let pc_relation = var_intro_pc_relation vr.hpc_to_lpc vr.return_hpcs vr.return_pcs_unique_proof in\n    states_match_except_global_variables vr.vs pc_relation ls hs\n  /\\ all_running_threads_have_pcs_in_list vr.hpcs hs\n  /\\ global_variables_unaddressed_in_memory vr.vs ls.mem\n  /\\ global_variables_unaddressed_in_memory vr.vs hs.mem\n  /\\ roots_match ls.mem\n  /\\ roots_match hs.mem\n  /\\ all_gvars_have_types hs.mem vr.vs vr.tds\n  /\\ unstarted_threads_have_empty_write_buffers ls\n  /\\ unstarted_threads_have_empty_write_buffers hs\n  /\\ (NotStopped? hs.stop_reason ==> vr.inv hs)\n\nlet var_intro_lh_relation\n  (vr: var_intro_relation_t)\n  (u: unit)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  : GTot ubool =\n    var_intro_lh_relation_between_steps vr u ls hs\n  /\\ all_threads_breaking vr.is_breaking_hpc hs\n  \nlet var_intro_pc_progress_measure\n  (vr: var_intro_relation_t)\n  (hs: Armada.State.t)\n  (actor: tid_t)\n  : GTot nat =\n  let hthread = hs.threads actor in\n  match (vr.hpc_info hthread.pc) with\n  | HPCInfoNormal -> 0\n  | HPCInfoIntroduced _ _ _ progress -> progress + 1\n\nlet var_intro_unread_write_buffer_len_measure\n  (vr: var_intro_relation_t)\n  (hs: Armada.State.t)\n  (latomic_step: list Armada.Step.t)\n  (actor: tid_t)\n  : GTot nat =\n  let hthread = hs.threads actor in\n  match latomic_step with\n  | [lstep] ->\n      (match lstep.action.program_statement.statement with\n       | PropagateWriteMessageStatement ->\n           let nd = lstep.nd in\n           if   list_len nd <> 1\n              || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract tid_t) then\n             0\n           else\n             let receiver_tid: tid_t = ObjectValueAbstract?.value (Cons?.hd nd) in\n             let position_in_write_buffer = (hs.threads receiver_tid).position_in_other_write_buffers actor in\n             let write_buffer_len = length hthread.write_buffer in\n             if position_in_write_buffer <= write_buffer_len then\n               write_buffer_len - position_in_write_buffer\n             else\n               0\n       | _ -> 0)\n  | _ -> 0\n\nlet var_intro_progress_measure\n  (vr: var_intro_relation_t)\n  (hs: Armada.State.t)\n  (latomic_step: list Armada.Step.t)\n  (actor: tid_t)\n  : GTot (nat * nat) =\n  (var_intro_pc_progress_measure vr hs actor, var_intro_unread_write_buffer_len_measure vr hs latomic_step actor)\n"
  },
  {
    "path": "experimental/lib/Strategies.VarIntro.Propagate.fst",
    "content": "module Strategies.VarIntro.Propagate\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Computation\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Program\nopen Armada.State\nopen Armada.Step\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Threads\nopen Armada.Transition\nopen Armada.Type\nopen FStar.Sequence.Ambient\nopen FStar.Sequence.Base\nopen FStar.WellFoundedRelation\nopen Spec.Behavior\nopen Spec.List\nopen Spec.Ubool\nopen Strategies.ArmadaInvariant.RootsMatch\nopen Strategies.ArmadaInvariant.PositionsValid\nopen Strategies.ArmadaStatement.Propagate\nopen Strategies.ArmadaInvariant.UnstartedThreads\nopen Strategies.ArmadaStatement.Status\nopen Strategies.ArmadaStatement.ThreadState\nopen Strategies.Atomic\nopen Strategies.GlobalVars\nopen Strategies.GlobalVars.Init\nopen Strategies.GlobalVars.Statement\nopen Strategies.GlobalVars.Types\nopen Strategies.GlobalVars.Unaddressed\nopen Strategies.GlobalVars.Util\nopen Strategies.GlobalVars.VarHiding\nopen Strategies.GlobalVars.VarIntro\nopen Strategies.Lift.Generic\nopen Strategies.Invariant\nopen Strategies.PCRelation\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\nopen Strategies.VarIntro.Defs\nopen Strategies.VarIntro.Helpers\nopen Strategies.VarIntro.Initialization\nopen Strategies.VarIntro.Invariant\nopen Util.List\nopen Util.Nth\nopen Util.Seq\n\nlet propagate_action: Armada.Action.t =\n  { ok = true; program_statement = propagate_program_statement }\n\n#push-options \"--z3rlimit 20\"\n\nlet get_propagate_lifter_case_skip_helper\n  (vr: var_intro_relation_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  (receiver_tid: tid_t)\n  (step: Armada.Step.t)\n  : Lemma (requires   var_intro_lh_relation vr () ls hs\n                    /\\ NotStopped? hs.stop_reason\n                    /\\ ThreadStatusRunning? (hs.threads actor).status\n                    /\\ step == { nd = nd; action = propagate_action }\n                    /\\ list_len nd = 1\n                    /\\ object_value_to_td (Cons?.hd nd) == ObjectTDAbstract tid_t\n                    /\\ receiver_tid == ObjectValueAbstract?.value (Cons?.hd nd)\n                    /\\ receiver_tid <> actor\n                    /\\ ComputationProduces? (propagate_write_message_statement_computation actor nd ls)\n                    /\\ (let lthread = ls.threads actor in\n                       let lwrite_buffer = lthread.write_buffer in\n                       let lposition = (ls.threads receiver_tid).position_in_other_write_buffers actor in\n                       let lwrite_message = index lwrite_buffer lposition in\n                       let lunread_write_buffer = unread_write_buffer ls.threads actor receiver_tid in\n                         ThreadStatusRunning? lthread.status\n                       /\\ not (global_variables_unaddressed_in_write_message vr.vs lwrite_message)))\n          (ensures  (match propagate_write_message_statement_computation actor nd ls with\n                     | ComputationProduces ls' -> var_intro_lh_relation vr () ls' hs)) =\n  let lunread_write_buffer = unread_write_buffer ls.threads actor receiver_tid in\n  let hunread_write_buffer = unread_write_buffer hs.threads actor receiver_tid in\n  let pc_relation = var_intro_pc_relation vr.hpc_to_lpc vr.return_hpcs vr.return_pcs_unique_proof in\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract tid_t) then\n    false_elim ()\n  else\n    let receiver_tid: tid_t = ObjectValueAbstract?.value (Cons?.hd nd) in\n    if receiver_tid = actor then // can't propagate to the same thread\n      false_elim ()\n    else\n      let propagator_thread = ls.threads actor in\n      let receiver_thread = ls.threads receiver_tid in\n      let which_message = receiver_thread.position_in_other_write_buffers actor in\n      if which_message >= length propagator_thread.write_buffer then\n        false_elim ()\n      else (\n        let write_message = index propagator_thread.write_buffer which_message in\n        let position_in_other_write_buffers' =\n          Spec.Map.upd receiver_thread.position_in_other_write_buffers actor (which_message + 1) in\n        let receiver_thread' =\n          { receiver_thread with position_in_other_write_buffers = position_in_other_write_buffers' } in\n        let threads' = Spec.Map.upd ls.threads receiver_tid receiver_thread' in\n        assert (positions_valid_in_threads threads');\n        let lem () : Lemma (positions_in_write_buffers_match_except_global_variables vr.vs threads' hs.threads) =\n        (\n          introduce forall sender_tid' receiver_tid'. sender_receiver_trigger sender_tid' receiver_tid' ==>\n                        write_buffers_match_except_global_variables vr.vs\n                          (unread_write_buffer threads' sender_tid' receiver_tid')\n                          (unread_write_buffer hs.threads sender_tid' receiver_tid')\n          with introduce _ ==> _\n          with _. (\n            assert (position_valid ls.threads sender_tid' receiver_tid');\n            assert (write_buffers_match_except_global_variables vr.vs\n                      (unread_write_buffer ls.threads sender_tid' receiver_tid')\n                      (unread_write_buffer hs.threads sender_tid' receiver_tid'));\n            if receiver_tid <> receiver_tid' then\n              ()\n            else if actor <> sender_tid' then\n              ()\n            else (\n              assert (unread_write_buffer hs.threads sender_tid' receiver_tid' == hunread_write_buffer);\n              assert (unread_write_buffer threads' sender_tid' receiver_tid' == drop lunread_write_buffer 1);\n              seq_to_list_drop_equals_tail lunread_write_buffer\n            )\n          )\n        ) in\n        lem ();\n        assert (positions_in_write_buffers_match_except_global_variables vr.vs threads' hs.threads);\n        match propagate_write_message write_message receiver_tid ls.mem with\n        | ComputationImpossible\n        | ComputationUndefined ->\n            // If propagate would trigger undefined behavior (e.g., by propagating to freed memory),\n            // it just leaves memory unchanged.\n            let ls' = { ls with threads = threads'; } in\n            assert (states_match_except_global_variables vr.vs pc_relation ls' hs);\n            assert (unstarted_threads_have_empty_write_buffers ls');\n            assert (global_variables_unaddressed_in_memory vr.vs ls'.mem);\n            assert (roots_match ls'.mem);\n            assert (var_intro_lh_relation vr () ls' hs)\n        | ComputationProduces mem' ->\n            let ls' = { ls with mem = mem'; threads = threads'; } in\n            propagate_write_message_statement_computation_s1_only_maintains_states_match vr.vs pc_relation actor nd\n              ls hs;\n            assert (unstarted_threads_have_empty_write_buffers ls');\n            propagate_write_message_maintains_gvars_unaddressed vr.vs write_message receiver_tid ls.mem;\n            assert (global_variables_unaddressed_in_memory vr.vs ls'.mem);\n            assert (roots_match ls'.mem);\n            assert (var_intro_lh_relation vr () ls' hs)\n      )\n\n#pop-options\n\nlet get_propagate_lifter_case_skip\n  (vr: var_intro_relation_t)\n  (actor: tid_t)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  (nd: nondeterminism_t)\n  (receiver_tid: tid_t)\n  (step: Armada.Step.t)\n  (lifter: step_lifter_t (list Armada.Step.t) unit)\n  : Lemma\n    (requires (  var_intro_lh_relation vr () ls hs\n               /\\ ComputationProduces? (propagate_write_message_statement_computation actor nd ls)\n               /\\ NotStopped? ls.stop_reason\n               /\\ list_len nd = 1\n               /\\ object_value_to_td (Cons?.hd nd) == ObjectTDAbstract tid_t\n               /\\ receiver_tid == ObjectValueAbstract?.value (Cons?.hd nd)\n               /\\ lifter == StepLifterSkip ()\n               /\\ step == { nd = nd; action = propagate_action }\n               /\\ (let lthread = ls.threads actor in\n                  let lwrite_buffer = lthread.write_buffer in\n                  let lposition = (ls.threads receiver_tid).position_in_other_write_buffers actor in\n                    lposition < length lwrite_buffer\n                  /\\ (let lwrite_message = index lwrite_buffer lposition in\n                       ThreadStatusRunning? lthread.status\n                     /\\ not (global_variables_unaddressed_in_write_message vr.vs lwrite_message)))))\n    (ensures  step_lifter_works\n                (make_atomic_semantics armada_semantics)\n                (make_atomic_semantics armada_semantics)\n                vr.latomic_prog vr.hatomic_prog unit (var_intro_lh_relation vr)\n                (nat * nat) (lex_nondep_wfr (default_wfr nat) (default_wfr nat))\n                (var_intro_progress_measure vr) actor true true [step] ls hs lifter) =\n  let pc_relation = var_intro_pc_relation vr.hpc_to_lpc vr.return_hpcs vr.return_pcs_unique_proof in\n  let lthread = ls.threads actor in\n  let lwrite_buffer = lthread.write_buffer in\n  let lposition = (ls.threads receiver_tid).position_in_other_write_buffers actor in\n  let lwrite_message = index lwrite_buffer lposition in\n  assert_norm (map_ghost armada_step_to_action [step] == propagate_action_list);\n  get_propagate_lifter_case_skip_helper vr actor nd ls hs receiver_tid step;\n  step_computation_is_propagate_computation actor nd ls step\n\n#push-options \"--z3rlimit 20\"\n\nlet get_propagate_lifter_case_match\n  (vr: var_intro_relation_t)\n  (actor: tid_t)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  (nd: nondeterminism_t)\n  (receiver_tid: tid_t)\n  (step: Armada.Step.t)\n  (lifter: step_lifter_t (list Armada.Step.t) unit)\n  : Lemma\n    (requires (  var_intro_lh_relation vr () ls hs\n               /\\ ComputationProduces? (propagate_write_message_statement_computation actor nd ls)\n               /\\ NotStopped? ls.stop_reason\n               /\\ list_len nd = 1\n               /\\ object_value_to_td (Cons?.hd nd) == ObjectTDAbstract tid_t\n               /\\ receiver_tid == ObjectValueAbstract?.value (Cons?.hd nd)\n               /\\ (let lthread = ls.threads actor in\n                  let hthread = hs.threads actor in\n                  let lwrite_buffer = lthread.write_buffer in\n                  let hwrite_buffer = hthread.write_buffer in\n                  let lposition = (ls.threads receiver_tid).position_in_other_write_buffers actor in\n                  let hposition = (hs.threads receiver_tid).position_in_other_write_buffers actor in\n                    ThreadStatusRunning? lthread.status\n                  /\\ length hwrite_buffer > hposition\n                  /\\ (let lwrite_message = index lwrite_buffer lposition in\n                     let hwrite_message = index hwrite_buffer hposition in\n                     let lunread_write_buffer = unread_write_buffer ls.threads actor receiver_tid in\n                     let hunread_write_buffer = unread_write_buffer hs.threads actor receiver_tid in\n                     let hstep = [step] in\n                       step == { nd = nd; action = propagate_action }\n                     /\\ program_contains_action_of_step_generic (make_atomic_semantics armada_semantics)\n                         vr.hatomic_prog [step]\n                     /\\ lifter == StepLifterLift hstep ()\n                     /\\ global_variables_unaddressed_in_write_message vr.vs lwrite_message\n                     /\\ global_variables_unaddressed_in_write_message vr.vs hwrite_message\n                     /\\ write_messages_match lwrite_message hwrite_message))))\n    (ensures  step_lifter_works\n                (make_atomic_semantics armada_semantics)\n                (make_atomic_semantics armada_semantics)\n                vr.latomic_prog vr.hatomic_prog unit (var_intro_lh_relation vr)\n                (nat * nat) (lex_nondep_wfr (default_wfr nat) (default_wfr nat))\n                (var_intro_progress_measure vr) actor true true [step] ls hs lifter) =\n  let pc_relation = var_intro_pc_relation vr.hpc_to_lpc vr.return_hpcs vr.return_pcs_unique_proof in\n  let lthread = ls.threads actor in\n  let hthread = hs.threads actor in\n  let lwrite_buffer = lthread.write_buffer in\n  let hwrite_buffer = hthread.write_buffer in\n  let lposition = (ls.threads receiver_tid).position_in_other_write_buffers actor in\n  let hposition = (hs.threads receiver_tid).position_in_other_write_buffers actor in\n  let lwrite_message = index lwrite_buffer lposition in\n  let hwrite_message = index hwrite_buffer hposition in\n  let lunread_write_buffer = unread_write_buffer ls.threads actor receiver_tid in\n  let hunread_write_buffer = unread_write_buffer hs.threads actor receiver_tid in\n  assert (map_ghost armada_step_to_action [step] == propagate_action_list);\n  propagate_write_message_statement_computation_maintains_states_match vr.vs pc_relation actor nd ls hs;\n  match propagate_write_message_statement_computation actor nd ls,\n        propagate_write_message_statement_computation actor nd hs with\n  | ComputationProduces ls', ComputationProduces hs' ->\n      assert (states_match_except_global_variables vr.vs pc_relation ls' hs');\n      assert (global_variables_unaddressed_in_memory vr.vs ls'.mem);\n      assert (global_variables_unaddressed_in_memory vr.vs hs'.mem);\n      assert (roots_match ls'.mem);\n      assert (roots_match hs'.mem);\n      propagate_maintains_all_running_threads_have_pcs_in_list actor nd vr.hpcs hs;\n      propagate_maintains_all_gvars_have_types vr.vs vr.tds actor nd hs;\n      step_computation_is_propagate_computation actor nd ls step;\n      step_computation_is_propagate_computation actor nd hs step;\n      introduce NotStopped? hs'.stop_reason ==> vr.inv hs'\n      with _. (\n        vr.inv_is_substep_invariant_proof ();\n        assert (vr.inv hs);\n        assert (contains_ubool step.action propagate_action_list);\n        assert (contains_ubool propagate_action_list vr.hatomic_prog.actions);\n        assert (Some hs' == step_computation actor true true step hs)\n      );\n      assert (var_intro_lh_relation vr () ls' hs')\n\n#pop-options\n#push-options \"--z3rlimit 40\"\n\nlet get_propagate_lifter_case_introduce_helper1\n  (vr: var_intro_relation_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  (receiver_tid: tid_t)\n  (step: Armada.Step.t)\n  : Lemma (requires   var_intro_lh_relation vr () ls hs\n                    /\\ NotStopped? hs.stop_reason\n                    /\\ ThreadStatusRunning? (hs.threads actor).status\n                    /\\ step == { nd = nd; action = propagate_action }\n                    /\\ list_len nd = 1\n                    /\\ object_value_to_td (Cons?.hd nd) == ObjectTDAbstract tid_t\n                    /\\ receiver_tid == ObjectValueAbstract?.value (Cons?.hd nd)\n                    /\\ receiver_tid <> actor\n                    /\\ (let lthread = ls.threads actor in\n                       let hthread = hs.threads actor in\n                       let lwrite_buffer = lthread.write_buffer in\n                       let hwrite_buffer = hthread.write_buffer in\n                       let hposition = (hs.threads receiver_tid).position_in_other_write_buffers actor in\n                          length hwrite_buffer > hposition\n                       /\\ (let hwrite_message = index hwrite_buffer hposition in\n                          let lunread_write_buffer = unread_write_buffer ls.threads actor receiver_tid in\n                          let hunread_write_buffer = unread_write_buffer hs.threads actor receiver_tid in\n                            step == { nd = nd; action = propagate_action }\n                          /\\ program_contains_action_of_step_generic (make_atomic_semantics armada_semantics)\n                              vr.hatomic_prog [step]\n                          /\\ not (global_variables_unaddressed_in_write_message vr.vs hwrite_message))))\n          (ensures  (match propagate_write_message_statement_computation actor nd hs with\n                     | ComputationProduces hs' -> var_intro_lh_relation vr () ls hs'\n                     | _ -> False)) =\n  let lunread_write_buffer = unread_write_buffer ls.threads actor receiver_tid in\n  let hunread_write_buffer = unread_write_buffer hs.threads actor receiver_tid in\n  let pc_relation = var_intro_pc_relation vr.hpc_to_lpc vr.return_hpcs vr.return_pcs_unique_proof in\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract tid_t) then\n    false_elim ()\n  else\n    let receiver_tid: tid_t = ObjectValueAbstract?.value (Cons?.hd nd) in\n    if receiver_tid = actor then // can't propagate to the same thread\n      false_elim ()\n    else\n      let propagator_thread = hs.threads actor in\n      let receiver_thread = hs.threads receiver_tid in\n      let which_message = receiver_thread.position_in_other_write_buffers actor in\n      if which_message >= length propagator_thread.write_buffer then\n        false_elim ()\n      else\n        let write_message = index propagator_thread.write_buffer which_message in\n        let position_in_other_write_buffers' =\n          Spec.Map.upd receiver_thread.position_in_other_write_buffers actor (which_message + 1) in\n        let receiver_thread' =\n          { receiver_thread with position_in_other_write_buffers = position_in_other_write_buffers' } in\n        let threads' = Spec.Map.upd hs.threads receiver_tid receiver_thread' in\n        let lem () : Lemma (  positions_valid_in_threads threads'\n                            /\\ positions_in_write_buffers_match_except_global_variables vr.vs ls.threads threads') =\n        (\n          introduce forall sender_tid' receiver_tid'. sender_receiver_trigger sender_tid' receiver_tid' ==>\n                          position_valid threads' sender_tid' receiver_tid'\n                        /\\ write_buffers_match_except_global_variables vr.vs\n                            (unread_write_buffer ls.threads sender_tid' receiver_tid')\n                            (unread_write_buffer threads' sender_tid' receiver_tid')\n          with introduce _ ==> _\n          with _. (\n            assert (position_valid hs.threads sender_tid' receiver_tid');\n            assert (write_buffers_match_except_global_variables vr.vs\n                      (unread_write_buffer ls.threads sender_tid' receiver_tid')\n                      (unread_write_buffer hs.threads sender_tid' receiver_tid'));\n            if receiver_tid <> receiver_tid' then\n              ()\n            else if actor <> sender_tid' then\n              ()\n            else (\n              assert (unread_write_buffer ls.threads sender_tid' receiver_tid' == lunread_write_buffer);\n              assert (unread_write_buffer threads' sender_tid' receiver_tid' == drop hunread_write_buffer 1);\n              seq_to_list_drop_equals_tail hunread_write_buffer\n            )\n          )\n        ) in\n        lem ();\n        assert (positions_valid_in_threads threads');\n        assert (positions_in_write_buffers_match_except_global_variables vr.vs ls.threads threads');\n        propagate_maintains_all_running_threads_have_pcs_in_list actor nd vr.hpcs hs;\n        propagate_maintains_all_gvars_have_types vr.vs vr.tds actor nd hs;\n        step_computation_is_propagate_computation actor nd hs step;\n        match propagate_write_message write_message receiver_tid hs.mem with\n        | ComputationImpossible\n        | ComputationUndefined ->\n            // If propagate would trigger undefined behavior (e.g., by propagating to freed memory),\n            // it just leaves memory unchanged.\n            let hs' = { hs with threads = threads'; } in\n            assert (states_match_except_global_variables vr.vs pc_relation ls hs');\n            assert (all_running_threads_have_pcs_in_list vr.hpcs hs');\n            assert (unstarted_threads_have_empty_write_buffers hs');\n            assert (global_variables_unaddressed_in_memory vr.vs hs'.mem);\n            assert (roots_match hs'.mem);\n            assert (all_gvars_have_types hs'.mem vr.vs vr.tds);\n            introduce NotStopped? hs'.stop_reason ==> vr.inv hs'\n            with _. (\n              vr.inv_is_substep_invariant_proof ();\n              assert (vr.inv hs);\n              assert (contains_ubool step.action propagate_action_list);\n              assert (contains_ubool propagate_action_list vr.hatomic_prog.actions);\n              assert (Some hs' == step_computation actor true true step hs)\n            );\n            assert (var_intro_lh_relation vr () ls hs')\n        | ComputationProduces mem' ->\n            let hs' = { hs with mem = mem'; threads = threads'; } in\n            propagate_write_message_statement_computation_s2_only_maintains_states_match vr.vs pc_relation actor nd\n              ls hs;\n            assert (all_running_threads_have_pcs_in_list vr.hpcs hs');\n            assert (unstarted_threads_have_empty_write_buffers hs');\n            propagate_write_message_maintains_gvars_unaddressed vr.vs write_message receiver_tid hs.mem;\n            assert (global_variables_unaddressed_in_memory vr.vs hs'.mem);\n            assert (roots_match hs'.mem);\n            assert (all_gvars_have_types hs'.mem vr.vs vr.tds);\n            introduce NotStopped? hs'.stop_reason ==> vr.inv hs'\n            with _. (\n              vr.inv_is_substep_invariant_proof ();\n              assert (vr.inv hs);\n              assert (contains_ubool step.action propagate_action_list);\n              assert (contains_ubool propagate_action_list vr.hatomic_prog.actions);\n              assert (Some hs' == step_computation actor true true step hs)\n            );\n            assert (var_intro_lh_relation vr () ls hs')\n\nlet get_propagate_lifter_case_introduce_helper2\n  (vr: var_intro_relation_t)\n  (actor: tid_t)\n  (nd: nondeterminism_t)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  (receiver_tid: tid_t)\n  (step: Armada.Step.t)\n  : Lemma (requires   var_intro_lh_relation vr () ls hs\n                    /\\ NotStopped? hs.stop_reason\n                    /\\ ThreadStatusRunning? (hs.threads actor).status\n                    /\\ step == { nd = nd; action = propagate_action }\n                    /\\ list_len nd = 1\n                    /\\ object_value_to_td (Cons?.hd nd) == ObjectTDAbstract tid_t\n                    /\\ receiver_tid == ObjectValueAbstract?.value (Cons?.hd nd)\n                    /\\ receiver_tid <> actor\n                    /\\ (let lthread = ls.threads actor in\n                       let hthread = hs.threads actor in\n                       let lwrite_buffer = lthread.write_buffer in\n                       let hwrite_buffer = hthread.write_buffer in\n                       let hposition = (hs.threads receiver_tid).position_in_other_write_buffers actor in\n                          length hwrite_buffer > hposition\n                       /\\ (let hwrite_message = index hwrite_buffer hposition in\n                          let lunread_write_buffer = unread_write_buffer ls.threads actor receiver_tid in\n                          let hunread_write_buffer = unread_write_buffer hs.threads actor receiver_tid in\n                            step == { nd = nd; action = propagate_action }\n                          /\\ program_contains_action_of_step_generic (make_atomic_semantics armada_semantics)\n                              vr.hatomic_prog [step]\n                          /\\ not (global_variables_unaddressed_in_write_message vr.vs hwrite_message))))\n          (ensures  (match propagate_write_message_statement_computation actor nd hs with\n                     | ComputationProduces hs' ->\n                           (hs'.threads actor).pc = (hs.threads actor).pc\n                         /\\ var_intro_unread_write_buffer_len_measure vr hs' [step] actor <\n                             var_intro_unread_write_buffer_len_measure vr hs [step] actor\n                     | _ -> False)) =\n  let pc_relation = var_intro_pc_relation vr.hpc_to_lpc vr.return_hpcs vr.return_pcs_unique_proof in\n  if   list_len nd <> 1\n     || neqb (object_value_to_td (Cons?.hd nd)) (ObjectTDAbstract tid_t) then\n    false_elim ()\n  else\n    let receiver_tid: tid_t = ObjectValueAbstract?.value (Cons?.hd nd) in\n    if receiver_tid = actor then // can't propagate to the same thread\n      false_elim ()\n    else\n      let propagator_thread = hs.threads actor in\n      let receiver_thread = hs.threads receiver_tid in\n      let which_message = receiver_thread.position_in_other_write_buffers actor in\n      if which_message >= length propagator_thread.write_buffer then\n        false_elim ()\n      else\n        let write_message = index propagator_thread.write_buffer which_message in\n        let position_in_other_write_buffers' =\n          Spec.Map.upd receiver_thread.position_in_other_write_buffers actor (which_message + 1) in\n        let receiver_thread' =\n          { receiver_thread with position_in_other_write_buffers = position_in_other_write_buffers' } in\n        let threads' = Spec.Map.upd hs.threads receiver_tid receiver_thread' in\n        assert ((threads' actor).write_buffer == (hs.threads actor).write_buffer);\n        assert (which_message + 1 <= length (threads' actor).write_buffer);\n        assert (position_in_other_write_buffers' actor == which_message + 1);\n        assert (threads' receiver_tid == receiver_thread');\n        assert ((threads' receiver_tid).position_in_other_write_buffers == position_in_other_write_buffers');\n        assert ((threads' receiver_tid).position_in_other_write_buffers actor == which_message + 1);\n        match propagate_write_message write_message receiver_tid hs.mem with\n        | ComputationImpossible\n        | ComputationUndefined ->\n            // If propagate would trigger undefined behavior (e.g., by propagating to freed memory),\n            // it just leaves memory unchanged.\n            let hs' = { hs with threads = threads'; } in\n            assert (var_intro_unread_write_buffer_len_measure vr hs [step] actor ==\n                      length propagator_thread.write_buffer - which_message);\n            assert (var_intro_unread_write_buffer_len_measure vr hs' [step] actor ==\n                      length (hs'.threads actor).write_buffer - (which_message + 1));\n            assert (var_intro_unread_write_buffer_len_measure vr hs' [step] actor <\n                      var_intro_unread_write_buffer_len_measure vr hs [step] actor)\n        | ComputationProduces mem' ->\n            let hs' = { hs with mem = mem'; threads = threads'; } in\n            assert (var_intro_unread_write_buffer_len_measure vr hs [step] actor ==\n                      length propagator_thread.write_buffer - which_message);\n            assert (var_intro_unread_write_buffer_len_measure vr hs' [step] actor ==\n                      length (hs'.threads actor).write_buffer - (which_message + 1));\n            assert (var_intro_unread_write_buffer_len_measure vr hs' [step] actor <\n                      var_intro_unread_write_buffer_len_measure vr hs [step] actor)\n\nlet get_propagate_lifter_case_introduce\n  (vr: var_intro_relation_t)\n  (actor: tid_t)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  (nd: nondeterminism_t)\n  (receiver_tid: tid_t)\n  (step: Armada.Step.t)\n  (lifter: step_lifter_t (list Armada.Step.t) unit)\n  : Lemma\n    (requires (  var_intro_lh_relation vr () ls hs\n               /\\ ComputationProduces? (propagate_write_message_statement_computation actor nd ls)\n               /\\ NotStopped? ls.stop_reason\n               /\\ list_len nd = 1\n               /\\ object_value_to_td (Cons?.hd nd) == ObjectTDAbstract tid_t\n               /\\ receiver_tid == ObjectValueAbstract?.value (Cons?.hd nd)\n               /\\ step == { nd = nd; action = propagate_action }\n               /\\ (let lthread = ls.threads actor in\n                  let hthread = hs.threads actor in\n                  let lwrite_buffer = lthread.write_buffer in\n                  let hwrite_buffer = hthread.write_buffer in\n                  let hposition = (hs.threads receiver_tid).position_in_other_write_buffers actor in\n                    ThreadStatusRunning? lthread.status\n                  /\\ length hwrite_buffer > hposition\n                  /\\ (let hwrite_message = index hwrite_buffer hposition in\n                     let lunread_write_buffer = unread_write_buffer ls.threads actor receiver_tid in\n                     let hunread_write_buffer = unread_write_buffer hs.threads actor receiver_tid in\n                       program_contains_action_of_step_generic (make_atomic_semantics armada_semantics)\n                         vr.hatomic_prog [step]\n                     /\\ lifter == StepLifterIntroduce [step] ()\n                     /\\ not (global_variables_unaddressed_in_write_message vr.vs hwrite_message)))))\n    (ensures  step_lifter_works\n                (make_atomic_semantics armada_semantics)\n                (make_atomic_semantics armada_semantics)\n                vr.latomic_prog vr.hatomic_prog unit (var_intro_lh_relation vr)\n                (nat * nat) (lex_nondep_wfr (default_wfr nat) (default_wfr nat))\n                (var_intro_progress_measure vr) actor true true [step] ls hs lifter) =\n  let pc_relation = var_intro_pc_relation vr.hpc_to_lpc vr.return_hpcs vr.return_pcs_unique_proof in\n  let lthread = ls.threads actor in\n  let hthread = hs.threads actor in\n  let lwrite_buffer = lthread.write_buffer in\n  let hwrite_buffer = hthread.write_buffer in\n  let lposition = (ls.threads receiver_tid).position_in_other_write_buffers actor in\n  let hposition = (hs.threads receiver_tid).position_in_other_write_buffers actor in\n  let lwrite_message = index lwrite_buffer lposition in\n  let hwrite_message = index hwrite_buffer hposition in\n  let lunread_write_buffer = unread_write_buffer ls.threads actor receiver_tid in\n  let hunread_write_buffer = unread_write_buffer hs.threads actor receiver_tid in\n  assert_norm (map_ghost armada_step_to_action [step] == propagate_action_list);\n  get_propagate_lifter_case_introduce_helper1 vr actor nd ls hs receiver_tid step;\n  get_propagate_lifter_case_introduce_helper2 vr actor nd ls hs receiver_tid step;\n  step_computation_is_propagate_computation actor nd hs step;\n  let hs' = Some?.v (step_computation_generic (make_atomic_semantics armada_semantics) actor true true [step] hs) in\n  let progress_wfr = lex_nondep_wfr (default_wfr nat) (default_wfr nat) in\n  let progress_measure = var_intro_progress_measure vr in\n  assert (progress_wfr.relation (progress_measure hs' [step] actor) (progress_measure hs [step] actor))\n\nlet correspondence_for_propagate_implies_propagate_among_hactions\n  (vr: var_intro_relation_t)\n  (correspondence: ltoh_correspondence_t vr.vs vr.tds vr.inv)\n  : Lemma (requires lactions_correspond_to_hactions_per_correspondence vr.vs vr.tds vr.inv vr.hpc_to_lpc vr.lpc_to_hpcs\n                      vr.return_hpcs vr.is_breaking_hpc vr.hpc_info vr.hatomic_prog.actions propagate_action_list\n                      correspondence)\n          (ensures  contains_ubool propagate_action_list vr.hatomic_prog.actions) =\n  let pc_relation = var_intro_pc_relation vr.hpc_to_lpc vr.return_hpcs vr.return_pcs_unique_proof in\n  vr.corresponding_hactions_correspond_proof ();\n  match correspondence with\n  | CorrespondencePropagate hidx ->\n      nth_implies_contains_ubool vr.hatomic_prog.actions hidx propagate_action_list\n  | CorrespondenceNormal hidx mapper ->\n      let hactions = list_index vr.hatomic_prog.actions hidx in\n      lactions_correspond_to_hactions_implies_not_propagate vr.vs vr.tds vr.inv vr.hpc_to_lpc vr.return_hpcs\n        ThreadStateRunning ThreadStateRunning ThreadStateRunning ThreadStateRunning\n        mapper propagate_action_list hactions\n\nlet get_propagate_lifter_helper\n  (vr: var_intro_relation_t)\n  (actor: tid_t)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  (nd: nondeterminism_t)\n  : Ghost (step_lifter_t (list Armada.Step.t) unit)\n    (requires   var_intro_lh_relation vr () ls hs\n              /\\ NotStopped? ls.stop_reason\n              /\\ ThreadStatusRunning? (ls.threads actor).status\n              /\\ contains_ubool propagate_action_list vr.latomic_prog.actions\n              /\\ ComputationProduces? (propagate_write_message_statement_computation actor nd ls))\n    (ensures  fun lifter ->\n                let step = { nd = nd; action = propagate_action } in\n                step_lifter_works\n                  (make_atomic_semantics armada_semantics)\n                  (make_atomic_semantics armada_semantics)\n                  vr.latomic_prog vr.hatomic_prog unit (var_intro_lh_relation vr)\n                  (nat * nat) (lex_nondep_wfr (default_wfr nat) (default_wfr nat))\n                  (var_intro_progress_measure vr) actor true true [step] ls hs lifter) =\n  let lthread = ls.threads actor in\n  let hthread = hs.threads actor in\n  let receiver_tid: tid_t = ObjectValueAbstract?.value (Cons?.hd nd) in\n  assert (positions_in_write_buffers_match_except_global_variables vr.vs ls.threads hs.threads);\n  assert (sender_receiver_trigger actor receiver_tid);\n  let lunread_write_buffer = unread_write_buffer ls.threads actor receiver_tid in\n  let hunread_write_buffer = unread_write_buffer hs.threads actor receiver_tid in\n  let lwrite_buffer = lthread.write_buffer in\n  let hwrite_buffer = hthread.write_buffer in\n  let lposition = (ls.threads receiver_tid).position_in_other_write_buffers actor in\n  let hposition = (hs.threads receiver_tid).position_in_other_write_buffers actor in\n  assert (lunread_write_buffer == drop lwrite_buffer lposition);\n  assert (hunread_write_buffer == drop hwrite_buffer hposition);\n  assert (length lunread_write_buffer > 0);\n  let lwrite_message = index lunread_write_buffer 0 in\n  assert (lwrite_message == index lwrite_buffer lposition);\n  let step = { nd = nd; action = propagate_action } in\n  let lem () : Lemma (program_contains_action_of_step_generic (make_atomic_semantics armada_semantics)\n                        vr.hatomic_prog [step]) =\n  (\n    vr.corresponding_hactions_correspond_proof ();\n    assert (map_ghost armada_step_to_action [step] == propagate_action_list);\n    let correspondence = get_correspondent_from_lists_correspond_ubool\n      (lactions_correspond_to_hactions_per_correspondence vr.vs vr.tds vr.inv vr.hpc_to_lpc vr.lpc_to_hpcs\n         vr.return_hpcs vr.is_breaking_hpc vr.hpc_info vr.hatomic_prog.actions)\n      vr.latomic_prog.actions vr.corresponding_hactions_info propagate_action_list\n    in\n    correspondence_for_propagate_implies_propagate_among_hactions vr correspondence\n  ) in\n  lem ();\n  if global_variables_unaddressed_in_write_message vr.vs lwrite_message then\n    let hwrite_message = index hunread_write_buffer 0 in\n    assert (hwrite_message == index hwrite_buffer hposition);\n    if global_variables_unaddressed_in_write_message vr.vs hwrite_message then (\n      let lifter = StepLifterLift [step] () in\n      get_propagate_lifter_case_match vr actor ls hs nd receiver_tid step lifter;\n      lifter\n    )\n    else (\n      let lifter = StepLifterIntroduce [step] () in\n      get_propagate_lifter_case_introduce vr actor ls hs nd receiver_tid step lifter;\n      lifter\n    )\n  else (\n    let lifter = StepLifterSkip () in\n    get_propagate_lifter_case_skip vr actor ls hs nd receiver_tid step lifter;\n    lifter\n  )\n\nlet get_propagate_lifter\n  (vr: var_intro_relation_t)\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  (lsteps: list Armada.Step.t)\n  : Ghost (step_lifter_t (list Armada.Step.t) unit)\n    (requires   var_intro_lh_relation vr () ls hs\n              /\\ Some? (steps_computation_generic armada_semantics actor starts_atomic_block ends_atomic_block\n                         lsteps ls)\n              /\\ contains_ubool (map_ghost armada_step_to_action lsteps) vr.latomic_prog.actions\n              /\\ (Cons?.hd lsteps).action.program_statement.statement == PropagateWriteMessageStatement)\n    (ensures  fun lifter ->\n                step_lifter_works\n                  (make_atomic_semantics armada_semantics)\n                  (make_atomic_semantics armada_semantics)\n                  vr.latomic_prog vr.hatomic_prog unit (var_intro_lh_relation vr)\n                  (nat * nat) (lex_nondep_wfr (default_wfr nat) (default_wfr nat))\n                  (var_intro_progress_measure vr) actor starts_atomic_block ends_atomic_block lsteps ls hs lifter) =\n  let step = Cons?.hd lsteps in\n  let nd = step.nd in\n  let lactions = map_ghost armada_step_to_action lsteps in\n  vr.corresponding_hactions_correspond_proof ();\n  let correspondence = get_correspondent_from_lists_correspond_ubool\n    (lactions_correspond_to_hactions_per_correspondence vr.vs vr.tds vr.inv vr.hpc_to_lpc vr.lpc_to_hpcs vr.return_hpcs\n       vr.is_breaking_hpc vr.hpc_info vr.hatomic_prog.actions)\n    vr.latomic_prog.actions vr.corresponding_hactions_info lactions\n  in\n  match correspondence with\n  | CorrespondencePropagate hidx ->\n      possible_propagate_action_ok actor starts_atomic_block ends_atomic_block ls lsteps;\n      get_propagate_lifter_helper vr actor ls hs nd\n  | CorrespondenceNormal hidx mapper ->\n      (match list_nth vr.hatomic_prog.actions hidx with\n       | Some hactions ->\n           let lstart_state = action_to_starting_thread_state (Cons?.hd lactions) in\n           let lend_state = actions_to_ending_thread_state lactions in\n           let hstart_state = action_to_starting_thread_state (Cons?.hd hactions) in\n           let hend_state = actions_to_ending_thread_state hactions in\n           lactions_correspond_to_hactions_implies_not_propagate vr.vs vr.tds vr.inv vr.hpc_to_lpc vr.return_hpcs\n             lstart_state hstart_state lend_state hend_state mapper lactions hactions;\n           false_elim ()\n       | None -> false_elim ())\n\n#pop-options\n"
  },
  {
    "path": "experimental/lib/Strategies.VarIntro.Relation.fst",
    "content": "module Strategies.VarIntro.Relation\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Computation\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Program\nopen Armada.State\nopen Armada.Step\nopen Armada.Statement\nopen Armada.Thread\nopen Armada.Threads\nopen Armada.Transition\nopen Armada.Type\nopen FStar.Sequence.Ambient\nopen FStar.Sequence.Base\nopen FStar.WellFoundedRelation\nopen Spec.Behavior\nopen Spec.List\nopen Spec.Ubool\nopen Strategies.ArmadaStatement.Breaking\nopen Strategies.ArmadaInvariant.RootsMatch\nopen Strategies.ArmadaInvariant.PositionsValid\nopen Strategies.ArmadaInvariant.UnstartedThreads\nopen Strategies.ArmadaStatement.Status\nopen Strategies.ArmadaStatement.ThreadState\nopen Strategies.Atomic\nopen Strategies.GlobalVars\nopen Strategies.GlobalVars.Init\nopen Strategies.GlobalVars.Permanent\nopen Strategies.GlobalVars.Statement\nopen Strategies.GlobalVars.Unaddressed\nopen Strategies.GlobalVars.Util\nopen Strategies.GlobalVars.VarIntro\nopen Strategies.Lift.Generic\nopen Strategies.Invariant\nopen Strategies.Nonyielding\nopen Strategies.PCRelation\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\nopen Strategies.VarIntro.Defs\nopen Strategies.VarIntro.Helpers\nopen Strategies.VarIntro.Initialization\nopen Strategies.VarIntro.Invariant\nopen Strategies.VarIntro.Propagate\nopen Util.List\nopen Util.Nth\nopen Util.Seq\n\nlet actions_among_hactions_implies_pcs_contains_new_pcs_of_actions\n  (vr: var_intro_relation_t)\n  (actions: list Armada.Action.t)\n  : Lemma (requires contains_ubool actions vr.hatomic_prog.actions)\n          (ensures  forall action. contains_ubool action actions ==> pcs_contain_new_pcs_of_action vr.hpcs action) =\n  vr.hpcs_complete_proof ()\n\nlet introduction_succeeds_witness_implies_introduction_succeeds\n  (vr: var_intro_relation_t)\n  (actor: tid_t)\n  (step: Armada.Step.t)\n  (s: Armada.State.t)\n  (witness: introduction_succeeds_witness_t vr.vs vr.tds vr.inv)\n  : Lemma (requires   valid_introduction_succeeds_witness vr.vs vr.tds vr.inv step.action.program_statement witness\n                    /\\ step.action.ok\n                    /\\ step.nd == []\n                    /\\ vr.inv s\n                    /\\ all_gvars_have_types s.mem vr.vs vr.tds\n                    /\\ (match step.action.program_statement.start_pc with\n                       | None -> False\n                       | Some pc -> thread_state_applies s actor (ThreadStateAtPC pc)))\n          (ensures  (let ps = step.action.program_statement in\n                     Some? (step_computation actor ps.starts_atomic_block ps.ends_atomic_block step s))) =\n  let ps = step.action.program_statement in\n  match witness with\n  | IntroductionSucceedsBecauseItAssignsConstant ->\n      statement_that_updates_gvars_using_constant_must_succeed vr.vs vr.tds actor (Some?.v ps.start_pc)\n        ps.end_pc ps.statement s\n  | IntroductionSucceedsProof ps' proof ->\n      proof actor s\n\n#push-options \"--z3rlimit 40\"\n\nlet executing_matching_steps_maintains_invariant\n  (vr: var_intro_relation_t)\n  (actor: tid_t)\n  (lstart_state: thread_state_t)\n  (hstart_state: thread_state_t)\n  (lend_state: thread_state_t)\n  (hend_state: thread_state_t)\n  (lstarts_atomic_block: bool)\n  (hstarts_atomic_block: bool)\n  (lends_atomic_block: bool)\n  (hends_atomic_block: bool)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  (lstep: Armada.Step.t)\n  (hstep: Armada.Step.t)\n  (hactions: list Armada.Action.t)\n  : Lemma (requires \n            (let pc_relation = var_intro_pc_relation vr.hpc_to_lpc vr.return_hpcs vr.return_pcs_unique_proof in\n               var_intro_lh_relation_between_steps vr () ls hs\n             /\\ Some? (step_computation actor lstarts_atomic_block lends_atomic_block lstep ls)\n             /\\ lstep_corresponds_to_hstep vr.vs pc_relation lstep hstep\n             /\\ action_to_starting_thread_state lstep.action = lstart_state\n             /\\ action_to_starting_thread_state hstep.action = hstart_state\n             /\\ action_to_ending_thread_state lstep.action = lend_state\n             /\\ action_to_ending_thread_state hstep.action = hend_state\n             /\\ ThreadStateAtPC? lstart_state\n             /\\ ThreadStateAtPC? hstart_state\n             /\\ thread_states_match_per_pc_relation pc_relation.relation lstart_state hstart_state\n             /\\ thread_states_match_per_pc_relation pc_relation.relation lend_state hend_state\n             /\\ lstarts_atomic_block = lstep.action.program_statement.starts_atomic_block\n             /\\ hstarts_atomic_block = hstep.action.program_statement.starts_atomic_block\n             /\\ lends_atomic_block = (lstep.action.program_statement.ends_atomic_block || not lstep.action.ok)\n             /\\ hends_atomic_block = (hstep.action.program_statement.ends_atomic_block || not hstep.action.ok)\n             /\\ pcs_contain_new_pcs_of_action vr.hpcs hstep.action\n             /\\ thread_state_applies ls actor lstart_state\n             /\\ thread_state_applies hs actor hstart_state\n             /\\ contains_ubool hstep.action hactions\n             /\\ contains_ubool hactions vr.hatomic_prog.actions))\n    (ensures  (match step_computation actor lstarts_atomic_block lends_atomic_block lstep ls,\n                     step_computation actor hstarts_atomic_block hends_atomic_block hstep hs with\n               | Some ls', Some hs' ->\n                   var_intro_lh_relation_between_steps vr () ls' hs'\n               | _, _ -> False)) =\n  let lthread = ls.threads actor in\n  let hthread = hs.threads actor in\n  let laction = lstep.action in\n  let haction = hstep.action in\n  let lps = laction.program_statement in\n  let hps = haction.program_statement in\n  let pc_relation = var_intro_pc_relation vr.hpc_to_lpc vr.return_hpcs vr.return_pcs_unique_proof in\n  lstep_corresponds_to_hstep_clarifier vr.vs pc_relation lstep hstep;\n  assert (step_computation actor lstarts_atomic_block lends_atomic_block lstep ls ==\n          action_computation actor lstarts_atomic_block lends_atomic_block lstep.nd lstep.action ls);\n  assert (step_computation actor hstarts_atomic_block hends_atomic_block hstep hs ==\n          action_computation actor hstarts_atomic_block hends_atomic_block hstep.nd hstep.action hs);\n  statement_effect_independent_implications vr.vs pc_relation actor lstep.nd lthread.pc hthread.pc\n    lps.end_pc hps.end_pc lps.statement hps.statement ls hs;\n  match statement_computation actor lstep.nd lthread.pc lps.end_pc lps.statement ls,\n        statement_computation actor hstep.nd hthread.pc hps.end_pc hps.statement hs with\n  | ComputationProduces ls', ComputationProduces hs' ->\n      assert (lstep.action.ok);\n      assert (global_variables_unaddressed_in_memory vr.vs ls'.mem);\n      assert (global_variables_unaddressed_in_memory vr.vs hs'.mem);\n      assert (roots_match ls'.mem);\n      assert (roots_match hs'.mem);\n      assert (states_match_except_global_variables vr.vs pc_relation ls' hs');\n      let ls'' = update_thread_pc_in_state ls' actor lps.end_pc in\n      let hs'' = update_thread_pc_in_state hs' actor hps.end_pc in\n      let lem1 () : Lemma (  unstarted_threads_have_empty_write_buffers ls'\n                           /\\ unstarted_threads_have_empty_write_buffers hs') = (\n        executing_statement_maintains_unstarted_threads_have_empty_write_buffers actor lstep.nd\n          lthread.pc lps.end_pc lps.statement ls;\n        executing_statement_maintains_unstarted_threads_have_empty_write_buffers actor hstep.nd\n          hthread.pc hps.end_pc hps.statement hs\n      ) in\n      assert (Some ls'' == step_computation actor lstarts_atomic_block lends_atomic_block lstep ls);\n      assert (Some hs'' == step_computation actor hstarts_atomic_block hends_atomic_block hstep hs);\n      let lem2 () : Lemma (all_running_threads_have_pcs_in_list vr.hpcs hs'') = (\n        executing_step_maintains_all_running_threads_have_pcs_in_list vr.hpcs actor\n          hstarts_atomic_block hends_atomic_block hstep hs\n      ) in\n      let lem3 () : Lemma (states_match_except_global_variables vr.vs pc_relation ls'' hs'') = (\n        update_thread_pcs_in_states_maintains_states_match_except_gvars vr.vs pc_relation\n          actor ls' hs' lps.end_pc hps.end_pc\n      ) in\n      let lem4 () : Lemma (  global_variables_unaddressed_in_memory vr.vs ls''.mem\n                           /\\ global_variables_unaddressed_in_memory vr.vs hs''.mem\n                           /\\ roots_match ls''.mem\n                           /\\ roots_match hs''.mem) = (\n        assert (ls''.mem == ls'.mem);\n        assert (hs''.mem == hs'.mem)\n      ) in\n      lem1 ();\n      lem2 ();\n      lem3 ();\n      lem4 ();\n      step_computation_maintains_all_gvars_have_types vr.vs vr.tds actor hstarts_atomic_block\n        hends_atomic_block hstep hs;\n      assert (all_gvars_have_types hs''.mem vr.vs vr.tds);\n      assert (states_match_except_global_variables vr.vs pc_relation ls'' hs'');\n      introduce NotStopped? hs''.stop_reason ==> vr.inv hs''\n      with _. vr.inv_is_substep_invariant_proof ()\n  | ComputationUndefined, ComputationUndefined ->\n      assert (not lstep.action.ok)\n\n#pop-options\n#push-options \"--z3rlimit 10\"\n\nlet executing_step_updating_gvars_maintains_invariant\n  (vr: var_intro_relation_t)\n  (actor: tid_t)\n  (hstarts_atomic_block: bool)\n  (hends_atomic_block: bool)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  (hstep: Armada.Step.t)\n  (actions: list Armada.Action.t)\n  : Lemma (requires \n            (let pc_relation = var_intro_pc_relation vr.hpc_to_lpc vr.return_hpcs vr.return_pcs_unique_proof in\n               var_intro_lh_relation_between_steps vr () ls hs\n             /\\ Some? (step_computation actor hstarts_atomic_block hends_atomic_block hstep hs)\n             /\\ statement_updates_gvars vr.vs hstep.action.program_statement.statement\n             /\\ hstep.action.ok\n             /\\ contains_ubool hstep.action actions\n             /\\ contains_ubool actions vr.hatomic_prog.actions\n             /\\ Some? hstep.action.program_statement.end_pc\n             /\\ pc_relation.relation (ls.threads actor).pc (Some?.v hstep.action.program_statement.end_pc)\n             /\\ hstarts_atomic_block = hstep.action.program_statement.starts_atomic_block\n             /\\ hends_atomic_block = hstep.action.program_statement.ends_atomic_block\n             /\\ pcs_contain_new_pcs_of_action vr.hpcs hstep.action\n             /\\ thread_state_applies hs actor (action_to_starting_thread_state hstep.action)))\n    (ensures  (match step_computation actor hstarts_atomic_block hends_atomic_block hstep hs with\n               | Some hs' -> var_intro_lh_relation_between_steps vr () ls hs'\n               | _ -> False)) =\n  let hthread = hs.threads actor in\n  let haction = hstep.action in\n  let hps = haction.program_statement in\n  let pc_relation = var_intro_pc_relation vr.hpc_to_lpc vr.return_hpcs vr.return_pcs_unique_proof in\n  statement_that_updates_gvars_s2_only_maintains_states_match vr.vs pc_relation actor hstep.nd hthread.pc\n    hps.end_pc hps.statement ls hs;\n  match statement_computation actor hstep.nd hthread.pc hps.end_pc hps.statement hs with\n  | ComputationProduces hs' ->\n      update_thread_pc_in_state_maintains_states_match_except_gvars vr.vs pc_relation actor ls hs'\n        hps.end_pc;\n      let hs'' = update_thread_pc_in_state hs' actor hps.end_pc in\n      assert (states_match_except_global_variables vr.vs pc_relation ls hs'');\n      executing_step_maintains_all_running_threads_have_pcs_in_list vr.hpcs actor hstarts_atomic_block\n        hends_atomic_block hstep hs;\n      assert (all_running_threads_have_pcs_in_list vr.hpcs hs'');\n      assert (global_variables_unaddressed_in_memory vr.vs hs''.mem);\n      executing_statement_maintains_unstarted_threads_have_empty_write_buffers actor hstep.nd\n        hthread.pc hps.end_pc hps.statement hs;\n      step_computation_maintains_all_gvars_have_types vr.vs vr.tds actor hstarts_atomic_block\n        hends_atomic_block hstep hs;\n      assert (all_gvars_have_types hs''.mem vr.vs vr.tds);\n      assert (unstarted_threads_have_empty_write_buffers hs'');\n      introduce NotStopped? hs''.stop_reason ==> vr.inv hs''\n      with _. vr.inv_is_substep_invariant_proof ()\n  | ComputationUndefined ->\n      ()\n\n#pop-options\n#push-options \"--z3rlimit 20\"\n\nlet establish_invariant_maintained_given_hsteps_at_correct_pc_case_matching\n  (vr: var_intro_relation_t)\n  (actor: tid_t)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  (lstart_state: thread_state_t)\n  (hstart_state: thread_state_t)\n  (lend_state: thread_state_t)\n  (hend_state: thread_state_t)\n  (mapper: list (haction_mapper_t vr.vs vr.tds vr.inv))\n  (lactions: list Armada.Action.t)\n  (hactions: list Armada.Action.t)\n  (lsteps: list Armada.Step.t)\n  (hsteps: list Armada.Step.t)\n  (all_hactions: list Armada.Action.t)\n  (remaining_mapper: list (haction_mapper_t vr.vs vr.tds vr.inv))\n  (laction: Armada.Action.t)\n  (remaining_lactions: list Armada.Action.t)\n  (haction: Armada.Action.t)\n  (remaining_hactions: list Armada.Action.t)\n  (lstep: Armada.Step.t)\n  (remaining_lsteps: list Armada.Step.t)\n  (hstep: Armada.Step.t)\n  (remaining_hsteps: list Armada.Step.t)\n  : Lemma (requires\n            (let pc_relation = var_intro_pc_relation vr.hpc_to_lpc vr.return_hpcs vr.return_pcs_unique_proof in\n             let lstarts_atomic_block = actions_start_atomic_block lactions in\n             let lends_atomic_block = actions_end_atomic_block lactions in\n               var_intro_lh_relation_between_steps vr () ls hs\n             /\\ (Some? (steps_computation_permitting_empty actor lstarts_atomic_block\n                         lends_atomic_block lsteps ls))\n             /\\ lactions == map_ghost armada_step_to_action lsteps\n             /\\ hactions == map_ghost armada_step_to_action hsteps\n             /\\ (forall haction. contains_ubool haction hactions ==> pcs_contain_new_pcs_of_action vr.hpcs haction)\n             /\\ lsteps_correspond_to_hsteps vr.vs vr.tds vr.inv pc_relation\n                 lstart_state hstart_state lend_state hend_state mapper lsteps hsteps\n             /\\ action_list_doesnt_internally_yield lactions\n             /\\ action_list_doesnt_internally_yield hactions\n             /\\ thread_states_match_per_pc_relation pc_relation.relation lstart_state hstart_state\n             /\\ thread_state_applies ls actor lstart_state\n             /\\ thread_state_applies hs actor hstart_state\n             /\\ each_action_ends_atomic_block_if_necessary hactions\n             /\\ (forall action. contains_ubool action hactions ==> contains_ubool action all_hactions)\n             /\\ contains_ubool all_hactions vr.hatomic_prog.actions\n             /\\ mapper == MapperMatching :: remaining_mapper\n             /\\ lactions == laction :: remaining_lactions\n             /\\ hactions == haction :: remaining_hactions\n             /\\ lsteps == lstep :: remaining_lsteps\n             /\\ hsteps == hstep :: remaining_hsteps))\n    (ensures (let lstarts_atomic_block = actions_start_atomic_block lactions in\n              let hstarts_atomic_block = actions_start_atomic_block hactions in\n              let lps = laction.program_statement in\n              let hps = haction.program_statement in\n              let laction_ends_atomic_block = lps.ends_atomic_block || not laction.ok in\n              let haction_ends_atomic_block = hps.ends_atomic_block || not haction.ok in\n              match step_computation actor lstarts_atomic_block laction_ends_atomic_block lstep ls,\n                    step_computation actor hstarts_atomic_block haction_ends_atomic_block hstep hs with\n              | Some ls', Some hs' -> var_intro_lh_relation_between_steps vr () ls' hs'\n              | _, _ -> False)) =\n  let lthread = ls.threads actor in\n  let hthread = hs.threads actor in\n  let lps = laction.program_statement in\n  let hps = haction.program_statement in\n  let lstep: Armada.Step.t = lstep in\n  let hstep: Armada.Step.t = hstep in\n  let lstarts_atomic_block = actions_start_atomic_block lactions in\n  let lends_atomic_block = actions_end_atomic_block lactions in\n  let hstarts_atomic_block = actions_start_atomic_block hactions in\n  let hends_atomic_block = actions_end_atomic_block hactions in\n  let laction_ends_atomic_block = lps.ends_atomic_block || not laction.ok in\n  let haction_ends_atomic_block = hps.ends_atomic_block || not haction.ok in\n  assert (laction_ends_atomic_block = (if (Cons? remaining_lsteps) then false else lends_atomic_block));\n  assert (haction_ends_atomic_block = (if (Cons? remaining_hsteps) then false else hends_atomic_block));\n  map_ghost_contains_ubool armada_step_to_action hsteps hstep;\n  assert (contains_ubool hstep.action hactions);\n  executing_matching_steps_maintains_invariant vr actor lstart_state hstart_state\n    (action_to_ending_thread_state lstep.action) (action_to_ending_thread_state hstep.action)\n    lstarts_atomic_block hstarts_atomic_block laction_ends_atomic_block haction_ends_atomic_block\n    ls hs lstep hstep all_hactions;\n  (match step_computation actor lstarts_atomic_block laction_ends_atomic_block lstep ls,\n         step_computation actor hstarts_atomic_block haction_ends_atomic_block hstep hs with\n   | Some ls', Some hs' ->\n       introduce NotStopped? hs'.stop_reason ==> vr.inv hs'\n       with _. vr.inv_is_substep_invariant_proof ()\n   | _, _ -> ())\n\nlet establish_invariant_maintained_given_hsteps_at_correct_pc_case_introduced\n  (vr: var_intro_relation_t)\n  (actor: tid_t)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  (lstart_state: thread_state_t)\n  (hstart_state: thread_state_t)\n  (lend_state: thread_state_t)\n  (hend_state: thread_state_t)\n  (mapper: list (haction_mapper_t vr.vs vr.tds vr.inv))\n  (lactions: list Armada.Action.t)\n  (hactions: list Armada.Action.t)\n  (lsteps: list Armada.Step.t)\n  (hsteps: list Armada.Step.t)\n  (all_hactions: list Armada.Action.t)\n  (witness: introduction_succeeds_witness_t vr.vs vr.tds vr.inv)\n  (remaining_mapper: list (haction_mapper_t vr.vs vr.tds vr.inv))\n  (haction: Armada.Action.t)\n  (remaining_hactions: list Armada.Action.t)\n  (hstep: Armada.Step.t)\n  (remaining_hsteps: list Armada.Step.t)\n  : Lemma (requires\n            (let pc_relation = var_intro_pc_relation vr.hpc_to_lpc vr.return_hpcs vr.return_pcs_unique_proof in\n             let lstarts_atomic_block = actions_start_atomic_block lactions in\n             let lends_atomic_block = actions_end_atomic_block lactions in\n               var_intro_lh_relation_between_steps vr () ls hs\n             /\\ (Some? (steps_computation_permitting_empty actor lstarts_atomic_block\n                         lends_atomic_block lsteps ls))\n             /\\ lactions == map_ghost armada_step_to_action lsteps\n             /\\ hactions == map_ghost armada_step_to_action hsteps\n             /\\ (forall haction. contains_ubool haction hactions ==> pcs_contain_new_pcs_of_action vr.hpcs haction)\n             /\\ lsteps_correspond_to_hsteps vr.vs vr.tds vr.inv pc_relation\n                 lstart_state hstart_state lend_state hend_state mapper lsteps hsteps\n             /\\ action_list_doesnt_internally_yield lactions\n             /\\ action_list_doesnt_internally_yield hactions\n             /\\ thread_states_match_per_pc_relation pc_relation.relation lstart_state hstart_state\n             /\\ thread_state_applies ls actor lstart_state\n             /\\ thread_state_applies hs actor hstart_state\n             /\\ each_action_ends_atomic_block_if_necessary hactions\n             /\\ (forall action. contains_ubool action hactions ==> contains_ubool action all_hactions)\n             /\\ contains_ubool all_hactions vr.hatomic_prog.actions\n             /\\ mapper == MapperIntroduced witness :: remaining_mapper\n             /\\ hactions == haction :: remaining_hactions\n             /\\ hsteps == hstep :: remaining_hsteps))\n    (ensures (let lstarts_atomic_block = actions_start_atomic_block lactions in\n              let hstarts_atomic_block = actions_start_atomic_block hactions in\n              let hps = haction.program_statement in\n              let haction_ends_atomic_block = hps.ends_atomic_block || not haction.ok in\n              (match step_computation actor hstarts_atomic_block haction_ends_atomic_block hstep hs with\n               | Some hs' -> var_intro_lh_relation_between_steps vr () ls hs'\n               | _ -> False))) =\n  let hthread = hs.threads actor in\n  let hps = haction.program_statement in\n  let hstep: Armada.Step.t = hstep in\n  let hstarts_atomic_block = actions_start_atomic_block hactions in\n  let hends_atomic_block = actions_end_atomic_block hactions in\n  let haction_ends_atomic_block = hps.ends_atomic_block || not haction.ok in\n  assert (haction_ends_atomic_block = (if (Cons? remaining_hsteps) then false else hends_atomic_block));\n  assert (hstep.nd == []);\n  introduction_succeeds_witness_implies_introduction_succeeds vr actor hstep hs witness;\n  map_ghost_contains_ubool armada_step_to_action hsteps hstep;\n  assert (contains_ubool hstep.action hactions);\n  executing_step_updating_gvars_maintains_invariant vr actor hstarts_atomic_block haction_ends_atomic_block\n    ls hs hstep all_hactions;\n  (match step_computation actor hstarts_atomic_block haction_ends_atomic_block hstep hs with\n   | Some hs' ->\n       step_computation_has_thread_state_effect actor hstarts_atomic_block\n         haction_ends_atomic_block hstep hs;\n       step_computation_has_thread_state_effect actor hstarts_atomic_block\n         haction_ends_atomic_block hstep hs;\n       introduce NotStopped? hs'.stop_reason ==> vr.inv hs'\n       with _. vr.inv_is_substep_invariant_proof ()\n   | None -> ())\n\n// Given a \"normal\" (i.e., not consisting of a propagate step)\n// sequence of low-level steps satisfying\n// steps_computation_permitting_empty, and a sequence of high-level\n// steps satisfying lsteps_correspond_to_hsteps, and given that the\n// high-level thread state corresponds to the starting thread state\n// required for those high-level steps, show that the outcome of\n// executing steps_computation_permitting_empty at the high level\n// produces a state related to the low-level produced state by\n// var_intro_lh_relation_between_steps.\n\nlet rec establish_normal_lifter_given_hsteps_at_correct_pc\n  (vr: var_intro_relation_t)\n  (actor: tid_t)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  (lstart_state: thread_state_t)\n  (hstart_state: thread_state_t)\n  (lend_state: thread_state_t)\n  (hend_state: thread_state_t)\n  (mapper: list (haction_mapper_t vr.vs vr.tds vr.inv))\n  (lactions: list Armada.Action.t)\n  (hactions: list Armada.Action.t)\n  (lsteps: list Armada.Step.t)\n  (hsteps: list Armada.Step.t)\n  (all_hactions: list Armada.Action.t)\n  : Lemma (requires\n            (let pc_relation = var_intro_pc_relation vr.hpc_to_lpc vr.return_hpcs vr.return_pcs_unique_proof in\n             let lstarts_atomic_block = actions_start_atomic_block lactions in\n             let lends_atomic_block = actions_end_atomic_block lactions in\n               var_intro_lh_relation_between_steps vr () ls hs\n             /\\ (Some? (steps_computation_permitting_empty actor lstarts_atomic_block\n                         lends_atomic_block lsteps ls))\n             /\\ lactions == map_ghost armada_step_to_action lsteps\n             /\\ hactions == map_ghost armada_step_to_action hsteps\n             /\\ (forall haction. contains_ubool haction hactions ==> pcs_contain_new_pcs_of_action vr.hpcs haction)\n             /\\ lsteps_correspond_to_hsteps vr.vs vr.tds vr.inv pc_relation\n                 lstart_state hstart_state lend_state hend_state mapper lsteps hsteps\n             /\\ action_list_doesnt_internally_yield lactions\n             /\\ action_list_doesnt_internally_yield hactions\n             /\\ thread_states_match_per_pc_relation pc_relation.relation lstart_state hstart_state\n             /\\ thread_state_applies ls actor lstart_state\n             /\\ thread_state_applies hs actor hstart_state\n             /\\ each_action_ends_atomic_block_if_necessary hactions\n             /\\ (forall action. contains_ubool action hactions ==> contains_ubool action all_hactions)\n             /\\ contains_ubool all_hactions vr.hatomic_prog.actions))\n    (ensures (let lstarts_atomic_block = actions_start_atomic_block lactions in\n              let lends_atomic_block = actions_end_atomic_block lactions in\n              let hstarts_atomic_block = actions_start_atomic_block hactions in\n              let hends_atomic_block = actions_end_atomic_block hactions in\n              match steps_computation_permitting_empty actor lstarts_atomic_block lends_atomic_block lsteps ls,\n                    steps_computation_permitting_empty actor hstarts_atomic_block hends_atomic_block hsteps hs with\n              | Some ls', Some hs' ->\n                  var_intro_lh_relation_between_steps vr () ls' hs'\n              | _, _ -> False))\n    (decreases hsteps) =\n  let pc_relation = var_intro_pc_relation vr.hpc_to_lpc vr.return_hpcs vr.return_pcs_unique_proof in\n  match mapper, lactions, hactions, lsteps, hsteps with\n  | [], [], [], [], [] -> ()\n  | MapperMatching :: remaining_mapper, laction :: remaining_lactions, haction :: remaining_hactions,\n      lstep :: remaining_lsteps, hstep :: remaining_hsteps ->\n      establish_invariant_maintained_given_hsteps_at_correct_pc_case_matching vr actor ls hs lstart_state hstart_state\n        lend_state hend_state mapper lactions hactions lsteps hsteps all_hactions remaining_mapper\n        laction remaining_lactions haction remaining_hactions lstep remaining_lsteps hstep remaining_hsteps;\n      let lps = laction.program_statement in\n      let hps = haction.program_statement in\n      let lstarts_atomic_block = actions_start_atomic_block lactions in\n      let lends_atomic_block = actions_end_atomic_block lactions in\n      let hstarts_atomic_block = actions_start_atomic_block hactions in\n      let hends_atomic_block = actions_end_atomic_block hactions in\n      let laction_ends_atomic_block = lps.ends_atomic_block || not laction.ok in\n      let haction_ends_atomic_block = hps.ends_atomic_block || not haction.ok in\n      (match step_computation actor lstarts_atomic_block laction_ends_atomic_block lstep ls,\n             step_computation actor hstarts_atomic_block haction_ends_atomic_block hstep hs with\n       | Some ls', Some hs' ->\n           step_computation_has_thread_state_effect actor lstarts_atomic_block laction_ends_atomic_block lstep ls;\n           step_computation_has_thread_state_effect actor hstarts_atomic_block haction_ends_atomic_block hstep hs;\n           establish_normal_lifter_given_hsteps_at_correct_pc vr actor ls' hs'\n             (action_to_ending_thread_state lstep.action)\n             (action_to_ending_thread_state hstep.action)\n             lend_state hend_state remaining_mapper remaining_lactions remaining_hactions remaining_lsteps\n             remaining_hsteps all_hactions)\n  | MapperIntroduced witness :: remaining_mapper, _, haction :: remaining_hactions, _, hstep :: remaining_hsteps ->\n      let hps = haction.program_statement in\n      let hstarts_atomic_block = actions_start_atomic_block hactions in\n      let hends_atomic_block = actions_end_atomic_block hactions in\n      let haction_ends_atomic_block = hps.ends_atomic_block || not haction.ok in\n      establish_invariant_maintained_given_hsteps_at_correct_pc_case_introduced vr actor ls hs lstart_state\n        hstart_state lend_state hend_state mapper lactions hactions lsteps hsteps all_hactions witness\n        remaining_mapper haction remaining_hactions hstep remaining_hsteps;\n      (match step_computation actor hstarts_atomic_block haction_ends_atomic_block hstep hs with\n       | Some hs' ->\n           step_computation_has_thread_state_effect actor hstarts_atomic_block\n             haction_ends_atomic_block hstep hs;\n           step_computation_has_thread_state_effect actor hstarts_atomic_block\n             haction_ends_atomic_block hstep hs;\n           establish_normal_lifter_given_hsteps_at_correct_pc vr actor ls hs'\n             lstart_state (action_to_ending_thread_state hstep.action) lend_state hend_state\n             remaining_mapper lactions remaining_hactions lsteps remaining_hsteps all_hactions\n       | None -> ())\n  | _, _, _, _, _ -> ()\n\n#pop-options\n\nlet each_action_consistent_with_is_nonyielding_pc_implies_ends_atomic_block_if_necessary\n  (is_nonyielding_pc: pc_t -> GTot bool)\n  (actions: list Armada.Action.t)\n  : Lemma (requires each_action_consistent_with_is_nonyielding_pc is_nonyielding_pc actions)\n          (ensures  each_action_ends_atomic_block_if_necessary actions) =\n  introduce forall action. contains_ubool action actions ==> action_ends_atomic_block_if_necessary action\n  with introduce _ ==> _\n  with _. assert (action_consistent_with_is_nonyielding_pc is_nonyielding_pc action)\n\n// Given a \"normal\" (i.e., not consisting of a propagate step)\n// sequence of low-level steps satisfying steps_computation_generic,\n// and a sequence of high-level steps satisfying\n// lsteps_correspond_to_hsteps and\n// laction_haction_correspondence_complete, and given that the\n// high-level thread state corresponds to the starting thread state\n// required for those high-level steps, return a lifter object for the\n// normal sequence of steps.\n\nlet get_normal_lifter_given_hsteps_at_correct_pc\n  (vr: var_intro_relation_t)\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  (lstart_state: thread_state_t)\n  (hstart_state: thread_state_t)\n  (lend_state: thread_state_t)\n  (hend_state: thread_state_t)\n  (mapper: list (haction_mapper_t vr.vs vr.tds vr.inv))\n  (lactions: list Armada.Action.t)\n  (hactions: list Armada.Action.t)\n  (lsteps: list Armada.Step.t)\n  (hsteps: list Armada.Step.t)\n  : Ghost (step_lifter_t (list Armada.Step.t) unit)\n    (requires (let pc_relation = var_intro_pc_relation vr.hpc_to_lpc vr.return_hpcs vr.return_pcs_unique_proof in\n                 var_intro_lh_relation vr () ls hs\n               /\\ Some? (steps_computation_generic armada_semantics actor\n                          starts_atomic_block ends_atomic_block lsteps ls)\n               /\\ lactions == map_ghost armada_step_to_action lsteps\n               /\\ hactions == map_ghost armada_step_to_action hsteps\n               /\\ contains_ubool lactions vr.latomic_prog.actions\n               /\\ contains_ubool hactions vr.hatomic_prog.actions\n               /\\ lsteps_correspond_to_hsteps vr.vs vr.tds vr.inv pc_relation\n                   lstart_state hstart_state lend_state hend_state mapper lsteps hsteps\n               /\\ do_actions_start_and_end_atomic_block lactions = do_actions_start_and_end_atomic_block hactions\n               /\\ thread_states_match_per_pc_relation pc_relation.relation lstart_state hstart_state\n               /\\ thread_state_applies ls actor lstart_state\n               /\\ thread_state_applies hs actor hstart_state\n               /\\ laction_haction_correspondence_complete vr.vs vr.tds vr.inv vr.lpc_to_hpcs vr.is_breaking_hpc\n                    vr.hpc_info lactions hactions))\n    (ensures  fun lifter -> step_lifter_works\n                           (make_atomic_semantics armada_semantics)\n                           (make_atomic_semantics armada_semantics)\n                           vr.latomic_prog vr.hatomic_prog unit (var_intro_lh_relation vr)\n                           (nat * nat) (lex_nondep_wfr (default_wfr nat) (default_wfr nat))\n                           (var_intro_progress_measure vr) actor starts_atomic_block ends_atomic_block\n                           lsteps ls hs lifter) =\n  steps_computation_implies_start_and_end_atomic_block actor starts_atomic_block\n    ends_atomic_block lsteps ls;\n  let pc_relation = var_intro_pc_relation vr.hpc_to_lpc vr.return_hpcs vr.return_pcs_unique_proof in\n  assert (var_intro_lh_relation vr () ls hs);\n  armada_steps_computation_equivalent actor starts_atomic_block ends_atomic_block lsteps ls;\n  assert (Some? (steps_computation_permitting_empty actor starts_atomic_block\n                   ends_atomic_block lsteps ls));\n  vr.each_laction_doesnt_internally_yield_proof ();\n  assert (action_list_doesnt_internally_yield lactions);\n  vr.each_haction_doesnt_internally_yield_proof ();\n  assert (action_list_doesnt_internally_yield hactions);\n  vr.hactions_consistent_with_is_nonyielding_pc_proof ();\n  each_action_consistent_with_is_nonyielding_pc_implies_ends_atomic_block_if_necessary vr.is_nonyielding_hpc\n    hactions;\n  assert (each_action_ends_atomic_block_if_necessary hactions);\n  actions_among_hactions_implies_pcs_contains_new_pcs_of_actions vr hactions;\n  establish_normal_lifter_given_hsteps_at_correct_pc vr actor ls hs\n    lstart_state hstart_state lend_state hend_state mapper lactions hactions lsteps hsteps hactions;\n  armada_steps_computation_equivalent actor starts_atomic_block ends_atomic_block hsteps hs;\n  let hstarts_atomic_block = actions_start_atomic_block hactions in\n  let hends_atomic_block = actions_end_atomic_block hactions in\n  vr.hactions_end_in_breaking_pc_proof ();\n  steps_computation_maintains_all_threads_breaking vr.is_breaking_hpc actor hstarts_atomic_block\n    hends_atomic_block hsteps hs;\n  StepLifterLift hsteps ()\n\n#push-options \"--z3rlimit 20\"\n\n// Given a \"normal\" (i.e., not consisting of a propagate step)\n// sequence of low-level steps satisfying steps_computation_generic,\n// and a set of high-level steps known to be introducible, prove that\n// executing those high-level steps produces a valid state that's\n// related to the current low-level state via\n// var_intro_lh_relation_between_steps.\n\nlet rec normal_lifter_works_given_hpc_introducible\n  (vr: var_intro_relation_t)\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  (hsteps: list Armada.Step.t)\n  (hactions: list Armada.Action.t)\n  (hstart_pc: pc_t)\n  (hend_pc: pc_t)\n  (introduction_succeeds_witnesses: list (introduction_succeeds_witness_t vr.vs vr.tds vr.inv))\n  (all_hactions: list Armada.Action.t)\n  : Lemma\n    (requires   var_intro_lh_relation_between_steps vr () ls hs\n              /\\ NotStopped? hs.stop_reason\n              /\\ ThreadStatusRunning? (hs.threads actor).status\n              /\\ (hs.threads actor).pc = hstart_pc\n              /\\ hactions_introducible vr.vs vr.tds vr.inv vr.hpc_to_lpc hstart_pc hend_pc\n                  introduction_succeeds_witnesses hactions\n              /\\ hsteps == compute_hsteps_from_hactions hactions\n              /\\ starts_atomic_block = not (vr.is_nonyielding_hpc hstart_pc)\n              /\\ ends_atomic_block = not (vr.is_nonyielding_lpc (vr.hpc_to_lpc hstart_pc))\n              /\\ each_action_consistent_with_is_nonyielding_pc vr.is_nonyielding_hpc hactions\n              /\\ action_list_doesnt_internally_yield hactions\n              /\\ Cons? hsteps\n              /\\ (forall haction. contains_ubool haction hactions ==> pcs_contain_new_pcs_of_action vr.hpcs haction)\n              /\\ actions_start_atomic_block hactions = starts_atomic_block\n              /\\ actions_end_atomic_block hactions = ends_atomic_block\n              /\\ (forall haction. contains_ubool haction hactions ==> contains_ubool haction all_hactions)\n              /\\ contains_ubool all_hactions vr.hatomic_prog.actions)\n    (ensures  (match steps_computation actor starts_atomic_block ends_atomic_block hsteps hs with\n               | Some hs' ->\n                     var_intro_lh_relation_between_steps vr () ls hs'\n                   /\\ (hs'.threads actor).pc = hend_pc\n               | None -> false))\n    (decreases hsteps) =\n  match hsteps, hactions, introduction_succeeds_witnesses with\n  | [], [], [] -> ()\n  | first_hstep :: remaining_hsteps, first_haction :: remaining_hactions,\n      witness :: remaining_introduction_succeeds_witnesses ->\n      let haction_ends_atomic_block = first_haction.program_statement.ends_atomic_block || not first_haction.ok in\n      introduction_succeeds_witness_implies_introduction_succeeds vr actor first_hstep hs witness;\n      executing_step_updating_gvars_maintains_invariant vr actor starts_atomic_block haction_ends_atomic_block\n        ls hs first_hstep all_hactions;\n      vr.inv_is_substep_invariant_proof ();\n      step_computation_has_thread_state_effect actor starts_atomic_block haction_ends_atomic_block first_hstep hs;\n       (match remaining_hsteps with\n       | [] -> ()\n       | _ -> (\n          match step_computation actor starts_atomic_block haction_ends_atomic_block first_hstep hs with\n          | Some hs2 ->\n              normal_lifter_works_given_hpc_introducible vr actor haction_ends_atomic_block ends_atomic_block\n                 ls hs2 remaining_hsteps remaining_hactions (hs2.threads actor).pc hend_pc\n                 remaining_introduction_succeeds_witnesses all_hactions))\n  | _, _, _ -> ()\n\n// Given a \"normal\" (i.e., not consisting of a propagate step)\n// sequence of low-level steps satisfying steps_computation_generic,\n// and given that the current high-level PC has info indictating it's\n// \"introducible\" (it's possible to introduce an atomic step at the\n// high level that makes progress), return a lifter object for the\n// normal sequence of steps.\n\nlet get_normal_lifter_given_hpc_introducible\n  (vr: var_intro_relation_t)\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  (lsteps: list Armada.Step.t)\n  : Ghost (step_lifter_t (list Armada.Step.t) unit)\n    (requires   var_intro_lh_relation vr () ls hs\n              /\\ NotStopped? hs.stop_reason\n              /\\ ThreadStatusRunning? (hs.threads actor).status\n              /\\ HPCInfoIntroduced? (vr.hpc_info (hs.threads actor).pc)\n              /\\ starts_atomic_block = not (vr.is_nonyielding_lpc (ls.threads actor).pc))\n    (ensures  fun lifter -> step_lifter_works\n                           (make_atomic_semantics armada_semantics)\n                           (make_atomic_semantics armada_semantics)\n                           vr.latomic_prog vr.hatomic_prog unit (var_intro_lh_relation vr)\n                           (nat * nat) (lex_nondep_wfr (default_wfr nat) (default_wfr nat))\n                           (var_intro_progress_measure vr) actor starts_atomic_block ends_atomic_block\n                           lsteps ls hs lifter) =\n  let hthread = hs.threads actor in                         \n  let hpc = hthread.pc in\n  assert (list_contains hpc vr.hpcs);\n  vr.introduced_atomic_actions_make_progress_proof ();\n  assert (introduced_atomic_action_makes_progress vr.vs vr.tds vr.inv vr.hatomic_prog.actions\n            vr.hpc_info vr.hpc_to_lpc vr.is_nonyielding_lpc hpc);\n  match vr.hpc_info hpc with\n  | HPCInfoIntroduced idx end_pc introduction_succeeds_witnesses progress ->\n      (match list_nth vr.hatomic_prog.actions idx with\n       | Some hactions ->\n           assert (hactions_introducible vr.vs vr.tds vr.inv vr.hpc_to_lpc hpc end_pc introduction_succeeds_witnesses\n                     hactions);\n           let hsteps = compute_hsteps_from_hactions hactions in\n           armada_steps_computation_equivalent actor starts_atomic_block\n             starts_atomic_block hsteps hs;\n           vr.hactions_consistent_with_is_nonyielding_pc_proof ();\n           vr.each_haction_doesnt_internally_yield_proof ();\n           nth_implies_contains_ubool vr.hatomic_prog.actions idx hactions;\n           actions_among_hactions_implies_pcs_contains_new_pcs_of_actions vr hactions;\n           normal_lifter_works_given_hpc_introducible vr actor starts_atomic_block starts_atomic_block ls hs\n             hsteps hactions hpc end_pc introduction_succeeds_witnesses hactions;\n           vr.hactions_end_in_breaking_pc_proof ();\n           steps_computation_maintains_all_threads_breaking vr.is_breaking_hpc actor starts_atomic_block\n             starts_atomic_block hsteps hs;\n           (match steps_computation actor starts_atomic_block starts_atomic_block hsteps hs with\n            | Some hs' ->\n                let progress_wfr = lex_nondep_wfr (default_wfr nat) (default_wfr nat) in\n                let progress_measure = var_intro_progress_measure vr in\n                assert (progress_wfr.relation (progress_measure hs' lsteps actor) (progress_measure hs lsteps actor));\n            StepLifterIntroduce hsteps ()))\n\n// Given a \"normal\" (i.e., not consisting of a propagate step)\n// sequence of low-level steps satisfying steps_computation_generic,\n// and a sequence of high-level steps satisfying\n// lsteps_correspond_to_hsteps and\n// laction_haction_correspondence_complete, return a lifter object\n// for the normal sequence of steps.\n\nlet get_normal_lifter_given_hsteps\n  (vr: var_intro_relation_t)\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  (lstart_state: thread_state_t)\n  (hstart_state: thread_state_t)\n  (lend_state: thread_state_t)\n  (hend_state: thread_state_t)\n  (mapper: list (haction_mapper_t vr.vs vr.tds vr.inv))\n  (lactions: list Armada.Action.t)\n  (hactions: list Armada.Action.t)\n  (lsteps: list Armada.Step.t)\n  (hsteps: list Armada.Step.t)\n  : Ghost (step_lifter_t (list Armada.Step.t) unit)\n    (requires (let pc_relation = var_intro_pc_relation vr.hpc_to_lpc vr.return_hpcs vr.return_pcs_unique_proof in\n                 var_intro_lh_relation vr () ls hs\n               /\\ Some? (steps_computation_generic armada_semantics actor\n                          starts_atomic_block ends_atomic_block lsteps ls)\n               /\\ lactions == map_ghost armada_step_to_action lsteps\n               /\\ hactions == map_ghost armada_step_to_action hsteps\n               /\\ contains_ubool lactions vr.latomic_prog.actions\n               /\\ contains_ubool hactions vr.hatomic_prog.actions\n               /\\ lsteps_correspond_to_hsteps vr.vs vr.tds vr.inv pc_relation\n                   lstart_state hstart_state lend_state hend_state mapper lsteps hsteps\n               /\\ do_actions_start_and_end_atomic_block lactions = do_actions_start_and_end_atomic_block hactions\n               /\\ laction_haction_correspondence_complete vr.vs vr.tds vr.inv vr.lpc_to_hpcs\n                   vr.is_breaking_hpc vr.hpc_info lactions hactions))\n    (ensures  fun lifter -> step_lifter_works\n                           (make_atomic_semantics armada_semantics)\n                           (make_atomic_semantics armada_semantics)\n                           vr.latomic_prog vr.hatomic_prog unit (var_intro_lh_relation vr)\n                           (nat * nat) (lex_nondep_wfr (default_wfr nat) (default_wfr nat))\n                           (var_intro_progress_measure vr) actor starts_atomic_block ends_atomic_block\n                           lsteps ls hs lifter) =\n  armada_steps_computation_equivalent actor starts_atomic_block ends_atomic_block lsteps ls;\n  steps_computation_requires_start_thread_state actor starts_atomic_block ends_atomic_block lsteps ls;\n  let lthread = ls.threads actor in\n  let hthread = hs.threads actor in\n  let pc_relation = var_intro_pc_relation vr.hpc_to_lpc vr.return_hpcs vr.return_pcs_unique_proof in\n  lsteps_correspond_to_hsteps_implies_first_lstep_matches_lstart_state vr.vs vr.tds vr.inv\n    pc_relation lstart_state hstart_state lend_state hend_state mapper lsteps hsteps;\n  match lstart_state, hstart_state with\n  | ThreadStateAtPC start_lpc, ThreadStateAtPC start_hpc ->\n      assert (lstart_state = action_to_starting_thread_state (Cons?.hd lsteps).action);\n      assert (lthread.pc = start_lpc);\n      assert (threads_match_except_global_variables vr.vs pc_relation ls.threads hs.threads);\n      assert (ThreadStatusRunning? lthread.status);\n      assert (pc_relation.relation lthread.pc hthread.pc);\n      assert (vr.hpc_to_lpc hthread.pc = lthread.pc);\n      vr.lpc_to_hpcs_consistent_with_hpc_to_lpc_proof ();\n      implication_of_contains_and_for_all\n        (laction_haction_correspondence_complete_inner vr.vs vr.tds vr.inv vr.is_breaking_hpc vr.hpc_info start_hpc)\n        hthread.pc (vr.lpc_to_hpcs start_lpc);\n      assert (laction_haction_correspondence_complete_inner vr.vs vr.tds vr.inv vr.is_breaking_hpc vr.hpc_info\n                start_hpc hthread.pc);\n      if hthread.pc = start_hpc then\n        get_normal_lifter_given_hsteps_at_correct_pc vr actor starts_atomic_block ends_atomic_block ls hs\n          lstart_state hstart_state lend_state hend_state mapper lactions hactions lsteps hsteps\n      else if not (vr.is_breaking_hpc hthread.pc) then (\n        assert (all_threads_breaking vr.is_breaking_hpc hs);\n        false_elim ()\n      )\n      else (\n        vr.lactions_consistent_with_is_nonyielding_pc_proof ();\n        assert (for_all_ghost (each_action_consistent_with_is_nonyielding_pc vr.is_nonyielding_lpc)\n                  vr.latomic_prog.actions);\n        assert (each_action_consistent_with_is_nonyielding_pc vr.is_nonyielding_lpc lactions);\n        assert (action_consistent_with_is_nonyielding_pc vr.is_nonyielding_lpc (Cons?.hd lsteps).action);\n        assert (starts_atomic_block = not (vr.is_nonyielding_lpc lthread.pc));\n        get_normal_lifter_given_hpc_introducible vr actor starts_atomic_block ends_atomic_block ls hs lsteps\n      )\n  | _, _ -> false_elim ()\n\n// Prove that every \"normal\" (i.e., not consisting of a propagate\n// step) sequence of steps satisfying steps_computation_generic is\n// liftable by returning the lifter for a given normal squence of\n// steps.\n\nlet get_normal_lifter\n  (vr: var_intro_relation_t)\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  (lsteps: list Armada.Step.t)\n  : Ghost (step_lifter_t (list Armada.Step.t) unit)\n    (requires   var_intro_lh_relation vr () ls hs\n              /\\ Some? (steps_computation_generic armada_semantics actor\n                         starts_atomic_block ends_atomic_block lsteps ls)\n              /\\ contains_ubool (map_ghost armada_step_to_action lsteps) vr.latomic_prog.actions\n              /\\ ~((Cons?.hd lsteps).action.program_statement.statement == PropagateWriteMessageStatement))\n    (ensures  fun lifter -> step_lifter_works\n                           (make_atomic_semantics armada_semantics)\n                           (make_atomic_semantics armada_semantics)\n                           vr.latomic_prog vr.hatomic_prog unit (var_intro_lh_relation vr)\n                           (nat * nat) (lex_nondep_wfr (default_wfr nat) (default_wfr nat))\n                           (var_intro_progress_measure vr) actor starts_atomic_block ends_atomic_block\n                           lsteps ls hs lifter) =\n  vr.corresponding_hactions_correspond_proof ();\n  let lactions = map_ghost armada_step_to_action lsteps in\n  let correspondence = get_correspondent_from_lists_correspond_ubool\n    (lactions_correspond_to_hactions_per_correspondence vr.vs vr.tds vr.inv vr.hpc_to_lpc vr.lpc_to_hpcs vr.return_hpcs\n       vr.is_breaking_hpc vr.hpc_info vr.hatomic_prog.actions)\n    vr.latomic_prog.actions\n    vr.corresponding_hactions_info\n    lactions in\n  match correspondence with\n  | CorrespondencePropagate hidx -> false_elim ()\n  | CorrespondenceNormal hidx mapper ->\n      (match list_nth vr.hatomic_prog.actions hidx with\n       | Some hactions ->\n           let pc_relation = var_intro_pc_relation vr.hpc_to_lpc vr.return_hpcs vr.return_pcs_unique_proof in\n           nth_implies_contains_ubool vr.hatomic_prog.actions hidx hactions;\n           let lstart_state = action_to_starting_thread_state (Cons?.hd lactions) in\n           let lend_state = actions_to_ending_thread_state lactions in\n           let hstart_state = action_to_starting_thread_state (Cons?.hd hactions) in\n           let hend_state = actions_to_ending_thread_state hactions in\n           let hsteps = compute_hsteps_from_lsteps vr.vs vr.tds vr.inv vr.hpc_to_lpc\n                          vr.return_hpcs vr.return_pcs_unique_proof lstart_state hstart_state lend_state\n                          hend_state mapper lactions hactions lsteps in\n           get_normal_lifter_given_hsteps vr actor starts_atomic_block ends_atomic_block ls hs\n             lstart_state hstart_state lend_state hend_state mapper lactions hactions lsteps hsteps)\n\n#pop-options\n\n// Prove that every sequence of steps satisfying\n// steps_computation_generic is liftable by returning the lifter for a\n// given sequence of steps.\n\nlet get_lifter_for_path\n  (vr: var_intro_relation_t)\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  (lsteps: list Armada.Step.t{\n       var_intro_lh_relation vr () ls hs\n     /\\ Some? (steps_computation_generic armada_semantics actor\n                starts_atomic_block ends_atomic_block lsteps ls)\n     /\\ contains_ubool (map_ghost armada_step_to_action lsteps) vr.latomic_prog.actions})\n  : GTot (lifter: (step_lifter_t (list Armada.Step.t) unit){\n            step_lifter_works\n              (make_atomic_semantics armada_semantics)\n              (make_atomic_semantics armada_semantics)\n              vr.latomic_prog vr.hatomic_prog unit (var_intro_lh_relation vr)\n              (nat * nat) (lex_nondep_wfr (default_wfr nat) (default_wfr nat))\n              (var_intro_progress_measure vr) actor starts_atomic_block ends_atomic_block\n              lsteps ls hs lifter}) =\n  match lsteps with\n  | first_step :: remaining_steps ->\n      (match first_step.action.program_statement.statement with\n       | PropagateWriteMessageStatement ->\n           get_propagate_lifter vr actor starts_atomic_block ends_atomic_block ls hs lsteps\n       | _ -> get_normal_lifter vr actor starts_atomic_block ends_atomic_block ls hs lsteps)\n\n// Prove that every sequence of steps satisfying\n// step_computation_generic is liftable by returning the lifter for a\n// given sequence of steps.\n\nlet paths_liftable_proof\n  (vr: var_intro_relation_t)\n  (actor: tid_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (aux: unit)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t)\n  (lsteps: list Armada.Step.t{\n       var_intro_invariant ls\n     /\\ var_intro_lh_relation vr aux ls hs\n     /\\ Some? (step_computation_generic (make_atomic_semantics armada_semantics)\n                actor starts_atomic_block ends_atomic_block lsteps ls)\n     /\\ program_contains_action_of_step_generic (make_atomic_semantics armada_semantics)\n         vr.latomic_prog lsteps})\n  : GTot (lifter: (step_lifter_t (list Armada.Step.t) unit){\n            step_lifter_works\n              (make_atomic_semantics armada_semantics)\n              (make_atomic_semantics armada_semantics)\n              vr.latomic_prog vr.hatomic_prog unit (var_intro_lh_relation vr)\n              (nat * nat) (lex_nondep_wfr (default_wfr nat) (default_wfr nat))\n              (var_intro_progress_measure vr) actor starts_atomic_block ends_atomic_block\n              lsteps ls hs lifter}) =\n  get_lifter_for_path vr actor starts_atomic_block ends_atomic_block ls hs lsteps\n\nlet inv_stepwise_invariant_proof\n  (vr: var_intro_relation_t)\n  : Lemma (semantics_has_stepwise_inductive_invariant (make_atomic_semantics armada_semantics)\n             vr.latomic_prog var_intro_invariant) =\n  ()\n\nlet initialize_hstate\n  (vr: var_intro_relation_t)\n  (ls: Armada.State.t)\n  : GTot Armada.State.t =\n  let mem' = apply_introduced_initializers vr.which_initializers_are_intros vr.hprog.global_initializers ls.mem in\n  let thread = ls.threads ls.initial_tid in\n  let thread' = { thread with pc = vr.hprog.main_start_pc } in\n  let threads' = Spec.Map.upd ls.threads ls.initial_tid thread' in\n  { ls with mem = mem'; threads = threads' }\n\nlet initialize_hstate_satisfies_hinit\n  (vr: var_intro_relation_t)\n  (ls: Armada.State.t)\n  : Lemma (requires init_program vr.lprog ls)\n          (ensures  init_program vr.hprog (initialize_hstate vr ls)) =\n  let hs = initialize_hstate vr ls in\n  vr.program_inits_match_except_global_variables_proof ();\n  vr.hinitializers_with_same_variable_id_match_proof ();\n  apply_introduced_initializers_ensures_satisfies_global_initializers vr.vs vr.which_initializers_are_intros\n    vr.lprog.global_initializers vr.hprog.global_initializers ls.mem;\n  let thread = hs.threads hs.initial_tid in\n  let initial_frame_uniq = Cons?.hd hs.uniqs_used in\n  apply_introduced_initializers_ensures_satisfies_main_stack_initializers vr.vs vr.which_initializers_are_intros\n    vr.hprog.global_initializers hs.initial_tid vr.hprog.main_method_id initial_frame_uniq\n    thread.top.local_variables vr.hprog.main_stack_initializers ls.mem;\n  apply_introduced_initializers_ensures_memory_invalid_outside_initializations vr.vs vr.which_initializers_are_intros\n    vr.lprog.global_initializers vr.hprog.global_initializers hs.initial_tid vr.hprog.main_method_id initial_frame_uniq\n    thread.top.local_variables ls.mem\n\nlet rec apply_introduced_initializers_ensures_gvar_has_type\n  (vs: list var_id_t)\n  (mem: Armada.Memory.t)\n  (which_initializers_are_intros: list bool)\n  (linits: list initializer_t)\n  (hinits: list initializer_t)\n  (v: var_id_t)\n  (td: object_td_t)\n  (init: initializer_t)\n  : Lemma (requires   initializers_match_except_global_variables vs which_initializers_are_intros linits hinits\n                    /\\ initializers_with_same_variable_id_match hinits\n                    /\\ contains_ubool init hinits\n                    /\\ initializer_matches_variable_and_td v td init\n                    /\\ list_contains v vs)\n          (ensures  (let mem' = apply_introduced_initializers which_initializers_are_intros hinits mem in\n                     gvar_has_type mem' v td)) =\n  match which_initializers_are_intros, linits, hinits with\n  | [], _, _ -> false_elim ()\n  | true :: remaining_which_are_intros, _, first_hinit :: remaining_hinits ->\n      let mem' = apply_introduced_initializers remaining_which_are_intros remaining_hinits mem in\n      if eqb first_hinit init then\n        apply_introduced_initializer_ensures_gvar_has_type first_hinit mem'\n      else (\n        apply_introduced_initializers_ensures_gvar_has_type vs mem remaining_which_are_intros\n          linits remaining_hinits v td init;\n        apply_introduced_initializer_ensures_gvar_has_type first_hinit mem'\n      )\n  | false :: remaining_which_are_intros, first_linit :: remaining_linits, first_hinit :: remaining_hinits ->\n      apply_introduced_initializers_ensures_gvar_has_type vs mem remaining_which_are_intros\n        remaining_linits remaining_hinits v td init\n  | _, _, _ -> false_elim ()\n\n// Prove, by expanding the recursive definition of\n// apply_introduced_initializers, that it ensures all_gvars_have_types\n// for the given list vs. We need the extra condition that every\n// variable in vs is also in vr.vs.\n\nlet rec apply_introduced_initializers_ensures_all_gvars_have_types_helper\n  (vr: var_intro_relation_t)\n  (mem: Armada.Memory.t)\n  (which_initializers_are_intros: list bool)\n  (linits: list initializer_t)\n  (hinits: list initializer_t)\n  (vs: list var_id_t)\n  (tds: list object_td_t)\n  : Lemma (requires   initializers_match_except_global_variables vr.vs which_initializers_are_intros linits hinits\n                    /\\ initializers_with_same_variable_id_match hinits\n                    /\\ every_variable_appears_among_initializers hinits vs tds\n                    /\\ (forall v. list_contains v vs ==> list_contains v vr.vs))\n          (ensures  (let mem' = apply_introduced_initializers which_initializers_are_intros hinits mem in\n                     all_gvars_have_types mem' vs tds)) =\n  match vs, tds with\n  | [], [] -> ()\n  | first_v :: remaining_vs, first_td :: remaining_tds ->\n      let init = exists_ubool_to_witness (initializer_matches_variable_and_td first_v first_td) hinits in\n      apply_introduced_initializers_ensures_gvar_has_type vr.vs mem which_initializers_are_intros linits hinits\n        first_v first_td init;\n      apply_introduced_initializers_ensures_all_gvars_have_types_helper vr mem\n        which_initializers_are_intros linits hinits remaining_vs remaining_tds\n\nlet apply_introduced_initializers_ensures_all_gvars_have_types\n  (vr: var_intro_relation_t)\n  (mem: Armada.Memory.t)\n  (which_initializers_are_intros: list bool)\n  (linits: list initializer_t)\n  (hinits: list initializer_t)\n  : Lemma (requires   initializers_match_except_global_variables vr.vs which_initializers_are_intros linits hinits\n                    /\\ initializers_with_same_variable_id_match hinits\n                    /\\ every_variable_appears_among_initializers hinits vr.vs vr.tds)\n          (ensures  (let mem' = apply_introduced_initializers which_initializers_are_intros hinits mem in\n                     all_gvars_have_types mem' vr.vs vr.tds)) =\n  apply_introduced_initializers_ensures_all_gvars_have_types_helper vr mem which_initializers_are_intros\n    linits hinits vr.vs vr.tds\n\nlet initialize_hstate_ensures_all_variables_among_gvars\n  (vr: var_intro_relation_t)\n  (ls: Armada.State.t)\n  : Lemma (requires init_program vr.lprog ls)\n          (ensures  (let hs = initialize_hstate vr ls in\n                     all_gvars_have_types hs.mem vr.vs vr.tds)) =\n  vr.all_introduced_global_variables_initialized_proof ();\n  vr.program_inits_match_except_global_variables_proof ();\n  vr.hinitializers_with_same_variable_id_match_proof ();\n  apply_introduced_initializers_ensures_all_gvars_have_types vr ls.mem vr.which_initializers_are_intros\n    vr.lprog.global_initializers vr.hprog.global_initializers\n\n#push-options \"--z3rlimit 10\"\n\nlet initialize_hstate_satisfies_threads_match_except_global_variables\n  (vr: var_intro_relation_t)\n  (ls: Armada.State.t)\n  : Lemma (requires init_program vr.lprog ls)\n          (ensures  (let pc_relation = var_intro_pc_relation vr.hpc_to_lpc vr.return_hpcs\n                                         vr.return_pcs_unique_proof in\n                     let hs = initialize_hstate vr ls in\n                     threads_match_except_global_variables vr.vs pc_relation ls.threads hs.threads)) =\n  vr.initial_pcs_correspond_proof ()\n\n#pop-options\n\nlet initialize_hstate_satisfies_var_intro_lh_relation\n  (vr: var_intro_relation_t)\n  (ls: Armada.State.t)\n  : Lemma (requires init_program vr.lprog ls)\n          (ensures  var_intro_lh_relation vr () ls (initialize_hstate vr ls)) =\n  let hs = initialize_hstate vr ls in\n  initialize_hstate_satisfies_hinit vr ls;\n  vr.program_inits_match_except_global_variables_proof ();\n  vr.hinitializers_with_same_variable_id_match_proof ();\n  apply_introduced_initializers_ensures_satisfies_global_initializers vr.vs vr.which_initializers_are_intros\n    vr.lprog.global_initializers vr.hprog.global_initializers ls.mem;\n  init_implies_positions_valid_in_state vr.hprog hs;\n  init_implies_roots_match vr.hprog hs;\n  init_implies_unstarted_threads_have_empty_write_buffers vr.hprog hs;\n  init_implies_positions_valid_in_state vr.lprog ls;\n  init_implies_roots_match vr.lprog ls;\n  init_implies_unstarted_threads_have_empty_write_buffers vr.lprog ls;\n  let pc_relation = var_intro_pc_relation vr.hpc_to_lpc vr.return_hpcs vr.return_pcs_unique_proof in\n  initialize_hstate_satisfies_threads_match_except_global_variables vr ls;\n  vr.initial_pc_in_pcs_proof ();\n  vr.initial_pc_breaking_proof ();\n  init_implies_roots_match vr.lprog ls;\n  init_implies_roots_match vr.hprog hs;\n  init_implies_unstarted_threads_have_empty_write_buffers vr.lprog ls;\n  init_implies_unstarted_threads_have_empty_write_buffers vr.hprog hs;\n  vr.global_variables_unaddressed_in_initializers_proof ();\n  init_implies_global_variables_unaddressed_in_memory vr.vs vr.lprog ls;\n  init_implies_global_variables_unaddressed_in_memory vr.vs vr.hprog hs;\n  initialize_hstate_ensures_all_variables_among_gvars vr ls;\n  introduce NotStopped? hs.stop_reason ==> vr.inv hs\n  with _. (\n    vr.inv_is_substep_invariant_proof ();\n    vr.atomic_inits_match_regular_inits_proof ();\n    assert (vr.hatomic_prog.init_f hs)\n  )\n\nlet init_implies_relation_proof\n  (vr: var_intro_relation_t)\n  (ls: Armada.State.t{vr.latomic_prog.init_f ls})\n  : GTot (hs_aux: (Armada.State.t * unit){\n            let hs, aux = hs_aux in\n            vr.hatomic_prog.init_f hs /\\ var_intro_lh_relation vr aux ls hs}) =\n  let hs = initialize_hstate vr ls in\n  let aux = () in\n  vr.atomic_inits_match_regular_inits_proof ();\n  initialize_hstate_satisfies_var_intro_lh_relation vr ls;\n  initialize_hstate_satisfies_hinit vr ls;\n  (hs, aux)\n\nlet lh_relation_implies_refinement_proof\n  (vr: var_intro_relation_t)\n  (aux: unit)\n  (ls: Armada.State.t)\n  (hs: Armada.State.t{var_intro_invariant ls /\\ var_intro_lh_relation vr aux ls hs})\n  : squash (refinement_requirement ls hs) =\n  ()\n\nlet var_intro_relation_implies_refinement (vr: var_intro_relation_t)\n  (* see .fsti file for spec *) =\n  let lr: liftability_relation_t = {\n    lsem = make_atomic_semantics armada_semantics;\n    hsem = make_atomic_semantics armada_semantics;\n    lprog = vr.latomic_prog;\n    hprog = vr.hatomic_prog;\n    aux_t = unit;\n    inv = var_intro_invariant;\n    lh_relation = var_intro_lh_relation vr;\n    progress_t = nat * nat;\n    progress_wfr = lex_nondep_wfr (default_wfr nat) (default_wfr nat);\n    progress_measure = var_intro_progress_measure vr;\n    refinement_relation = refinement_requirement;\n    paths_liftable_proof = paths_liftable_proof vr;\n    inv_stepwise_invariant_proof = (fun u -> inv_stepwise_invariant_proof vr);\n    init_implies_relation_proof = init_implies_relation_proof vr;\n    lh_relation_implies_refinement_proof = lh_relation_implies_refinement_proof vr;\n  } in\n  liftability_relation_implies_refinement lr\n"
  },
  {
    "path": "experimental/lib/Strategies.VarIntro.Relation.fsti",
    "content": "module Strategies.VarIntro.Relation\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.Init\nopen Armada.Memory\nopen Armada.Program\nopen Armada.State\nopen Armada.Type\nopen Spec.Behavior\nopen Spec.List\nopen Spec.Logic\nopen Spec.Ubool\nopen Strategies.Atomic\nopen Strategies.GlobalVars\nopen Strategies.GlobalVars.Statement\nopen Strategies.GlobalVars.Types\nopen Strategies.GlobalVars.VarIntro\nopen Strategies.Invariant\nopen Strategies.Nonyielding\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\nopen Strategies.VarIntro.Defs\nopen Util.List\nopen Util.Nth\n\nval var_intro_relation_implies_refinement (vr: var_intro_relation_t)\n  : Lemma (ensures (spec_refines_spec\n                      (semantics_to_spec (make_atomic_semantics armada_semantics) vr.latomic_prog)\n                      (semantics_to_spec (make_atomic_semantics armada_semantics) vr.hatomic_prog)\n                      refinement_requirement))\n"
  },
  {
    "path": "experimental/lib/Strategies.Weakening.Armada.fst",
    "content": "module Strategies.Weakening.Armada\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.State\nopen Armada.Step\nopen Armada.Transition\nopen Armada.Type\nopen FStar.List.Tot\nopen FStar.Tactics.V2\nopen Spec.Behavior\nopen Strategies.Atomic\nopen Strategies.Invariant\nopen Strategies.Invariant.Armada.Atomic\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\nopen Strategies.Weakening\nopen Spec.List\nopen Spec.Ubool\nopen Util.List\n\nlet remove_index_from_steps_updater\n  (u:(tid_t -> list Armada.Step.t -> Armada.State.t -> GTot (nat * list Armada.Step.t)))\n  (tid: tid_t)\n  (lsteps: list Armada.Step.t)\n  (ls: Armada.State.t)\n  : GTot (list Armada.Step.t) =\n  let idx, steps = u tid lsteps ls in\n  steps\n\nlet armada_steps_updater_works_implies_step_updater_works\n  (lactions: list Armada.Action.t)\n  (hatomic_actions: list (list Armada.Action.t))\n  (hatomic_action_array: array_t (list Armada.Action.t))\n  (inv: invariant_t Armada.State.t)\n  (steps_updater: (tid_t -> list Armada.Step.t -> Armada.State.t -> GTot (nat * list Armada.Step.t)))\n  (proof: unit -> squash (armada_steps_updater_works hatomic_action_array inv lactions steps_updater))\n  : Lemma (requires hatomic_action_array == list_to_array hatomic_actions)\n          (ensures  step_updater_works (make_atomic_semantics armada_semantics) hatomic_actions inv lactions\n                      (remove_index_from_steps_updater steps_updater)) =\n  let sem = make_atomic_semantics armada_semantics in\n  introduce forall (actor: sem.actor_t) (starts_atomic_block: bool) (ends_atomic_block: bool) (lsteps: sem.step_t)\n              (s: sem.state_t).\n              (  sem.step_to_action_f lsteps == lactions\n               /\\ inv s\n               /\\ Some? (step_computation_generic sem actor starts_atomic_block ends_atomic_block lsteps s)) ==>\n              (let hatomic_action_idx, hsteps = steps_updater actor lsteps s in\n               let hactions = sem.step_to_action_f hsteps in\n                 (contains_ubool hactions hatomic_actions)\n               /\\ (step_computation_generic sem actor starts_atomic_block ends_atomic_block hsteps s ==\n                  step_computation_generic sem actor starts_atomic_block ends_atomic_block lsteps s))\n  with introduce _ ==> _\n  with _. (\n    proof ();\n    armada_steps_computation_equivalent actor starts_atomic_block ends_atomic_block lsteps s;\n    let hatomic_action_idx, hsteps = steps_updater actor lsteps s in\n    armada_steps_computation_equivalent actor starts_atomic_block ends_atomic_block hsteps s;\n    let hactions = sem.step_to_action_f hsteps in\n    index_to_contains_ubool hatomic_actions hatomic_action_idx\n  )\n\nlet armada_weakening_transformer_to_weakening_transformer\n  (hatomic_actions: list (list Armada.Action.t))\n  (hatomic_action_array: array_t (list Armada.Action.t){hatomic_action_array == list_to_array hatomic_actions})\n  (inv: invariant_t Armada.State.t)\n  (awt: armada_weakening_transformer_t hatomic_action_array inv)\n  : GTot (weakening_transformer_t (make_atomic_semantics armada_semantics) hatomic_actions inv) =\n  match awt with\n  | ArmadaWeakeningTransformerSameStep hatomic_action_idx -> WeakeningTransformerSameStep hatomic_action_idx\n  | ArmadaWeakeningTransformerUpdatedStep lactions step_updater proof ->\n      armada_steps_updater_works_implies_step_updater_works lactions hatomic_actions hatomic_action_array inv\n        step_updater proof;\n      WeakeningTransformerUpdatedStep lactions (remove_index_from_steps_updater step_updater) (fun _ -> ())\n\nlet armada_weakening_transformers_to_weakening_transformers\n  (hatomic_actions: list (list Armada.Action.t))\n  (hatomic_action_array: array_t (list Armada.Action.t){hatomic_action_array == list_to_array hatomic_actions})\n  (inv: invariant_t Armada.State.t)\n  (awts: list (armada_weakening_transformer_t hatomic_action_array inv))\n  : GTot (list (weakening_transformer_t (make_atomic_semantics armada_semantics) hatomic_actions inv)) =\n  map_ghost (armada_weakening_transformer_to_weakening_transformer hatomic_actions hatomic_action_array inv) awts\n\nlet armada_weakening_witness_valid_implies_actions_match_weakening_transformers\n  (lprog: program_t (make_atomic_semantics armada_semantics))\n  (hprog: program_t (make_atomic_semantics armada_semantics))\n  (ww: armada_weakening_witness_t lprog hprog)\n  : Lemma (requires    ww.hatomic_action_array == list_to_array hprog.actions\n                    /\\ lists_correspond_ubool action_matches_armada_weakening_transformer lprog.actions\n                        ww.weakening_transformers)\n          (ensures  lists_correspond_ubool action_matches_weakening_transformer lprog.actions\n                      (armada_weakening_transformers_to_weakening_transformers hprog.actions ww.hatomic_action_array\n                         ww.inv ww.weakening_transformers)) =\n  introduce forall lactions weakening_transformer.\n                action_matches_armada_weakening_transformer lactions weakening_transformer ==>\n                  action_matches_weakening_transformer lactions\n                    (armada_weakening_transformer_to_weakening_transformer hprog.actions\n                      ww.hatomic_action_array ww.inv weakening_transformer)\n  with introduce _ ==> _\n  with _. (\n    let weakening_transformer = armada_weakening_transformer_to_weakening_transformer hprog.actions\n                                  ww.hatomic_action_array ww.inv weakening_transformer in\n    match weakening_transformer with\n    | WeakeningTransformerSameStep haction_index ->\n        list_to_array_implies_nth_equivalent ww.hatomic_action_array hprog.actions haction_index\n    | WeakeningTransformerUpdatedStep action _ _ ->\n        assert (lactions == action)\n  );\n  map_preserves_lists_correspond_ubool\n    action_matches_armada_weakening_transformer\n    action_matches_weakening_transformer\n    (armada_weakening_transformer_to_weakening_transformer hprog.actions ww.hatomic_action_array ww.inv)\n    lprog.actions ww.weakening_transformers\n\nlet armada_weakening_witness_valid_implies_refinement\n  (lprog: program_t (make_atomic_semantics armada_semantics))\n  (hprog: program_t (make_atomic_semantics armada_semantics))\n  (ww: armada_weakening_witness_t lprog hprog)\n  (* see .fsti file for spec *) =\n  armada_weakening_witness_valid_implies_actions_match_weakening_transformers lprog hprog ww;\n  let wr: weakening_relation_t = {\n    sem = make_atomic_semantics armada_semantics;\n    lprog = lprog;\n    hprog = hprog;\n    inv = ww.inv;\n    weakening_transformers = armada_weakening_transformers_to_weakening_transformers hprog.actions\n                               ww.hatomic_action_array ww.inv ww.weakening_transformers;\n    sem_has_stepwise_inductive_invariant_proof = (fun _ -> ());\n    actions_match_weakening_transformers_proof = (fun _ -> ());\n    init_implies_init_proof = ww.init_implies_init_proof;\n  } in\n  weakening_relation_implies_refinement wr\n"
  },
  {
    "path": "experimental/lib/Strategies.Weakening.Armada.fsti",
    "content": "module Strategies.Weakening.Armada\n\nopen Armada.Action\nopen Armada.Base\nopen Armada.State\nopen Armada.Step\nopen Armada.Transition\nopen Armada.Type\nopen FStar.List.Tot\nopen Spec.Behavior\nopen Strategies.Atomic\nopen Strategies.Invariant\nopen Strategies.Invariant.Armada.Atomic\nopen Strategies.Semantics\nopen Strategies.Semantics.Armada\nopen Spec.List\nopen Spec.Ubool\nopen Util.ImmutableArray\nopen Util.List\n\nlet armada_steps_updater_works\n  (hatomic_action_array: array_t (list Armada.Action.t))\n  (inv: invariant_t Armada.State.t)\n  (lactions: list Armada.Action.t)\n  (steps_updater: (tid_t -> list Armada.Step.t -> Armada.State.t -> GTot (nat * list Armada.Step.t)))\n  : GTot ubool =\n  forall (actor: tid_t) (starts_atomic_block: bool) (ends_atomic_block: bool) (lsteps: list Armada.Step.t)\n       (s: Armada.State.t).\n    (  map_ghost armada_step_to_action lsteps == lactions\n     /\\ inv s\n     /\\ Some? (steps_computation actor starts_atomic_block ends_atomic_block lsteps s)) ==>\n    (let hatomic_action_idx, hsteps = steps_updater actor lsteps s in\n     let haction = map_ghost armada_step_to_action hsteps in\n       hatomic_action_idx < array_len hatomic_action_array\n     /\\ array_index hatomic_action_array hatomic_action_idx == haction\n     /\\ (steps_computation actor starts_atomic_block ends_atomic_block hsteps s ==\n        steps_computation actor starts_atomic_block ends_atomic_block lsteps s))\n\nnoeq type armada_weakening_transformer_t\n  (hatomic_action_array: array_t (list Armada.Action.t))\n  (inv: invariant_t Armada.State.t) =\n  | ArmadaWeakeningTransformerSameStep: (hatomic_action_idx: nat) ->\n      armada_weakening_transformer_t hatomic_action_array inv\n  | ArmadaWeakeningTransformerUpdatedStep:\n     (lactions: list Armada.Action.t) ->\n     (steps_updater: (tid_t -> list Armada.Step.t -> Armada.State.t -> GTot (nat * list Armada.Step.t))) ->\n     (proof: unit -> squash (armada_steps_updater_works hatomic_action_array inv lactions steps_updater)) ->\n     armada_weakening_transformer_t hatomic_action_array inv\n\nlet action_matches_armada_weakening_transformer\n  (#hatomic_action_array: array_t (list Armada.Action.t))\n  (#inv: invariant_t Armada.State.t)\n  (lactions: list Armada.Action.t)\n  (weakening_transformer: armada_weakening_transformer_t hatomic_action_array inv)\n  : GTot ubool =\n  match weakening_transformer with\n  | ArmadaWeakeningTransformerSameStep hatomic_action_idx ->\n        hatomic_action_idx < array_len hatomic_action_array\n      /\\ array_index hatomic_action_array hatomic_action_idx == lactions\n  | ArmadaWeakeningTransformerUpdatedStep actions _ _ -> lactions == actions\n\nnoeq type armada_weakening_witness_t\n  (lprog: program_t (make_atomic_semantics armada_semantics))\n  (hprog: program_t (make_atomic_semantics armada_semantics)) =\n{\n  inv: invariant_t Armada.State.t;\n  hatomic_action_array: array_t (list Armada.Action.t);\n  weakening_transformers: list (armada_weakening_transformer_t hatomic_action_array inv);\n  init_implies_init_proof: (s: Armada.State.t{lprog.init_f s}) -> squash (hprog.init_f s);\n}\n\nlet armada_weakening_witness_valid\n  (lprog: program_t (make_atomic_semantics armada_semantics))\n  (hprog: program_t (make_atomic_semantics armada_semantics))\n  (ww: armada_weakening_witness_t lprog hprog)\n  : GTot ubool =\n  lists_correspond_ubool action_matches_armada_weakening_transformer lprog.actions ww.weakening_transformers\n\nval armada_weakening_witness_valid_implies_refinement\n  (lprog: program_t (make_atomic_semantics armada_semantics))\n  (hprog: program_t (make_atomic_semantics armada_semantics))\n  (ww: armada_weakening_witness_t lprog hprog)\n  : Lemma (requires   ww.hatomic_action_array == list_to_array hprog.actions\n                    /\\ semantics_has_stepwise_inductive_invariant (make_atomic_semantics armada_semantics) lprog ww.inv\n                    /\\ armada_weakening_witness_valid lprog hprog ww)\n          (ensures  spec_refines_spec\n                      (semantics_to_spec (make_atomic_semantics armada_semantics) lprog)\n                      (semantics_to_spec (make_atomic_semantics armada_semantics) hprog)\n                      eq2)\n"
  },
  {
    "path": "experimental/lib/Strategies.Weakening.fst",
    "content": "module Strategies.Weakening\n\nopen FStar.WellFoundedRelation\nopen Spec.Behavior\nopen Strategies.Semantics\nopen Spec.Ubool\nopen Spec.List\nopen Strategies.Lift.Generic\nopen Util.Behavior\nopen Util.List\nopen Util.Nth\n\nlet lift_step_case_same_step\n  (wr: weakening_relation_t)\n  (actor: wr.sem.actor_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (lstep: wr.sem.step_t)\n  (s: wr.sem.state_t)\n  (laction: wr.sem.action_t)\n  (weakening_transformer: weakening_transformer_t wr.sem wr.hprog.actions wr.inv)\n  : Ghost wr.sem.step_t\n    (requires   wr.inv s\n              /\\ (Some? (step_computation_generic wr.sem actor\n                          starts_atomic_block ends_atomic_block lstep s))\n              /\\ (program_contains_action_of_step_generic wr.sem wr.lprog lstep)\n              /\\ (wr.sem.step_to_action_f lstep == laction)\n              /\\ (action_matches_weakening_transformer laction weakening_transformer)\n              /\\ (WeakeningTransformerSameStep? weakening_transformer))\n    (ensures  fun hstep ->   (Some? (step_computation_generic wr.sem actor\n                                    starts_atomic_block ends_atomic_block lstep s))\n                        /\\ step_computation_generic wr.sem actor starts_atomic_block ends_atomic_block hstep s ==\n                            step_computation_generic wr.sem actor starts_atomic_block ends_atomic_block lstep s\n                        /\\ wr.inv (Some?.v (step_computation_generic wr.sem actor\n                                             starts_atomic_block ends_atomic_block lstep s))\n                        /\\ (program_contains_action_of_step_generic wr.sem wr.hprog hstep)) =\n  wr.sem_has_stepwise_inductive_invariant_proof ();\n  let haction_index = (WeakeningTransformerSameStep?.haction_index weakening_transformer) in\n  let haction = Some?.v (nth wr.hprog.actions haction_index) in\n  nth_implies_contains_ubool wr.hprog.actions haction_index haction;\n  lstep\n  \nlet lift_step_case_updated_step\n  (wr: weakening_relation_t)\n  (actor: wr.sem.actor_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (lstep: wr.sem.step_t)\n  (s: wr.sem.state_t)\n  (laction: wr.sem.action_t)\n  (weakening_transformer: weakening_transformer_t wr.sem wr.hprog.actions wr.inv)\n  : Ghost wr.sem.step_t\n    (requires   wr.inv s\n              /\\ (Some? (step_computation_generic wr.sem actor\n                          starts_atomic_block ends_atomic_block lstep s))\n              /\\ (program_contains_action_of_step_generic wr.sem wr.lprog lstep)\n              /\\ (wr.sem.step_to_action_f lstep == laction)\n              /\\ (action_matches_weakening_transformer laction weakening_transformer)\n              /\\ WeakeningTransformerUpdatedStep? weakening_transformer)\n    (ensures  fun hstep ->   (Some? (step_computation_generic wr.sem actor starts_atomic_block ends_atomic_block hstep s))\n                        /\\ step_computation_generic wr.sem actor starts_atomic_block ends_atomic_block hstep s ==\n                            step_computation_generic wr.sem actor starts_atomic_block ends_atomic_block lstep s\n                        /\\ wr.inv (Some?.v (step_computation_generic wr.sem actor\n                                             starts_atomic_block ends_atomic_block lstep s))\n                        /\\ (program_contains_action_of_step_generic wr.sem wr.hprog hstep)) =\n  wr.sem_has_stepwise_inductive_invariant_proof ();\n  match weakening_transformer with\n  | WeakeningTransformerUpdatedStep _ step_updater proof ->\n      proof ();\n      step_updater actor lstep s\n\nlet lift_step_using_weakening_transformer\n  (wr: weakening_relation_t)\n  (actor: wr.sem.actor_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (lstep: wr.sem.step_t)\n  (s: wr.sem.state_t)\n  (laction: wr.sem.action_t)\n  (weakening_transformer: weakening_transformer_t wr.sem wr.hprog.actions wr.inv)\n  : Ghost wr.sem.step_t\n    (requires   wr.inv s\n              /\\ (Some? (step_computation_generic wr.sem actor\n                          starts_atomic_block ends_atomic_block lstep s))\n              /\\ (program_contains_action_of_step_generic wr.sem wr.lprog lstep)\n              /\\ (wr.sem.step_to_action_f lstep == laction)\n              /\\ (action_matches_weakening_transformer laction weakening_transformer))\n    (ensures  fun hstep ->   (Some? (step_computation_generic wr.sem actor starts_atomic_block ends_atomic_block hstep s))\n                        /\\ step_computation_generic wr.sem actor starts_atomic_block ends_atomic_block hstep s ==\n                            step_computation_generic wr.sem actor starts_atomic_block ends_atomic_block lstep s\n                        /\\ wr.inv (Some?.v (step_computation_generic wr.sem actor\n                                             starts_atomic_block ends_atomic_block lstep s))\n                        /\\ (program_contains_action_of_step_generic wr.sem wr.hprog hstep)) =\n  match weakening_transformer with\n  | WeakeningTransformerSameStep _ ->\n     lift_step_case_same_step wr actor starts_atomic_block ends_atomic_block lstep s laction weakening_transformer\n  | WeakeningTransformerUpdatedStep _ _ _ ->\n     lift_step_case_updated_step wr actor starts_atomic_block ends_atomic_block lstep s laction weakening_transformer\n\nlet lift_step\n  (wr: weakening_relation_t)\n  (actor: wr.sem.actor_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (lstep: wr.sem.step_t)\n  (s: wr.sem.state_t)\n  : Ghost wr.sem.step_t\n    (requires   wr.inv s\n              /\\ (Some? (step_computation_generic wr.sem actor\n                          starts_atomic_block ends_atomic_block lstep s))\n              /\\ (program_contains_action_of_step_generic wr.sem wr.lprog lstep))\n    (ensures  fun hstep ->   (Some? (step_computation_generic wr.sem actor starts_atomic_block ends_atomic_block hstep s))\n                        /\\ step_computation_generic wr.sem actor starts_atomic_block ends_atomic_block hstep s ==\n                            step_computation_generic wr.sem actor starts_atomic_block ends_atomic_block lstep s\n                        /\\ wr.inv (Some?.v (step_computation_generic wr.sem actor\n                                             starts_atomic_block ends_atomic_block lstep s))\n                        /\\ (program_contains_action_of_step_generic wr.sem wr.hprog hstep)) =\n  let laction = wr.sem.step_to_action_f lstep in\n  let laction_index = contains_to_index laction wr.lprog.actions in\n  wr.actions_match_weakening_transformers_proof ();\n  lists_correspond_ubool_implies_index_matches\n    action_matches_weakening_transformer\n    wr.lprog.actions\n    wr.weakening_transformers\n    laction_index;\n  let weakening_transformer = (Some?.v (nth wr.weakening_transformers laction_index)) in\n  lift_step_using_weakening_transformer wr actor starts_atomic_block ends_atomic_block lstep s laction\n    weakening_transformer\n\nlet lh_relation_gen (wr: weakening_relation_t) (aux: unit) (ls: wr.sem.state_t) (hs: wr.sem.state_t) : GTot ubool =\n  ls == hs\n\nlet progress_measure_gen (wr: weakening_relation_t) (hs: wr.sem.state_t) (lstep: wr.sem.step_t) (actor: wr.sem.actor_t)\n  : GTot nat = 0\n\nlet paths_liftable_proof_gen\n  (wr: weakening_relation_t)\n  (actor: wr.sem.actor_t)\n  (starts_atomic_block: bool)\n  (ends_atomic_block: bool)\n  (aux: unit)\n  (ls: wr.sem.state_t)\n  (hs: wr.sem.state_t)\n  (lstep: wr.sem.step_t{\n       wr.inv ls\n     /\\ (lh_relation_gen wr) aux ls hs\n     /\\ Some? (step_computation_generic wr.sem actor starts_atomic_block ends_atomic_block lstep ls)\n     /\\ program_contains_action_of_step_generic wr.sem wr.lprog lstep})\n  : GTot (lifter: (step_lifter_t wr.sem.step_t unit){\n                      step_lifter_works wr.sem wr.sem wr.lprog wr.hprog unit (lh_relation_gen wr)\n                        nat (default_wfr nat) (progress_measure_gen wr)\n                        actor starts_atomic_block ends_atomic_block lstep ls hs lifter}) =\n  StepLifterLift (lift_step wr actor starts_atomic_block ends_atomic_block lstep ls) ()\n\nlet init_implies_relation_proof_gen (wr: weakening_relation_t) (ls: wr.sem.state_t{wr.lprog.init_f ls})\n  : GTot (hs_aux: (wr.sem.state_t * unit){\n            let hs, aux = hs_aux in\n            wr.hprog.init_f hs /\\ lh_relation_gen wr aux ls hs}) =\n  wr.init_implies_init_proof ls;\n  assert (wr.hprog.init_f ls /\\ lh_relation_gen wr () ls ls);\n  (ls, ())\n\nlet lh_relation_implies_refinement_proof_gen\n  (wr: weakening_relation_t)\n  (aux: unit)\n  (ls: wr.sem.state_t)\n  (hs: wr.sem.state_t{wr.inv ls /\\ lh_relation_gen wr aux ls hs})\n  : squash (ls == hs) =\n  ()\n\nlet weakening_relation_to_liftability_relation (wr: weakening_relation_t) : GTot liftability_relation_t =\n  {\n    lsem = wr.sem;\n    hsem = wr.sem;\n    lprog = wr.lprog;\n    hprog = wr.hprog;\n    aux_t = unit;\n    inv = wr.inv;\n    lh_relation = lh_relation_gen wr;\n    progress_t = nat;\n    progress_wfr = default_wfr nat;\n    progress_measure = progress_measure_gen wr;\n    refinement_relation = eq2;\n    paths_liftable_proof = paths_liftable_proof_gen wr;\n    inv_stepwise_invariant_proof = wr.sem_has_stepwise_inductive_invariant_proof;\n    init_implies_relation_proof = init_implies_relation_proof_gen wr;\n    lh_relation_implies_refinement_proof = lh_relation_implies_refinement_proof_gen wr;\n  }\n\nlet weakening_relation_implies_refinement wr =\n  (* see .fsti file for spec *)\n  liftability_relation_implies_refinement (weakening_relation_to_liftability_relation wr)\n"
  },
  {
    "path": "experimental/lib/Strategies.Weakening.fsti",
    "content": "/// This module allows one to prove that two Armada behaviors refine\n/// each other if they satisfy the weakening relation.  To do this,\n/// one calls [weakening_relation_implies_refinement], passing it an\n/// input of type [weakening_relation_t] to demonstrate the weakening\n/// relation.\n///\n/// The signature of [weakening_relation_implies_refinement] is:\n/// \n///   val weakening_relation_implies_refinement (wr: weakening_relation_t)\n///     : Lemma (ensures spec_refines_spec (semantics_to_spec wr.lsem) (semantics_to_spec wr.hsem) eq2)\n/// \n/// The [weakening_relation_t] structure contains the following fields:\n///\n///   [sem] : semantics_t\n/// \n///     The semantics of the low-level and high-level specifications.\n///\n///   [lprog] : program_t sem\n///\n///     The low-level program.\n///\n///   [hprog] : program_t sem\n///\n///     The high-level program.\n///\n///   [inv] : invariant_t lsem.state_t\n///\n///     A purported stepwise invariant of all behaviors of the low-level\n///     semantics.\n///\n///   [weakening_transformers] : list (weakening_transformer_t sem hprog.actions inv)\n///\n///     A list of weakening transformers, one for each action of the low-level program.\n///     That transformer must be either WeakeningTransformerSameStep, meaning that the\n///     identical step exists in the high-level program, or WeakeningTransformerUpdatedStep,\n///     meaning that there's a way to map any low-level step with that action to a high-level\n///     step with identical behavior.\n///\n///   [sem_has_stepwise_inductive_invariant_proof]: unit -> squash (semantics_has_stepwise_inductive_invariant sem lprog inv)\n///\n///     A lemma that proves that inv is a stepwise invariant of the given low-level\n///     semantics.\n/// \n///   [actions_match_weakening_transformers_proof] : unit ->\n///     squash (lists_correspond action_matches_weakening_transformer lprog.actions weakening_transformers)\n///\n///     A lemma that proves that each weakening transformer is a valid transformer for\n///     the corresponding low-level action.\n///\n///   [inits_match] : s: lsem.state_t ->\n///                   squash (requires init_program_generic lsem s) (ensures init_program_generic hsem s))\n///\n///     A lemma that proves that, if the low-level program allows a\n///     state at initialization, the high-level program also allows\n///     that state at initialization.\n\nmodule Strategies.Weakening\n\nopen FStar.List.Tot\nopen Spec.Behavior\nopen Strategies.Invariant\nopen Strategies.Semantics\nopen Spec.List\nopen Spec.Ubool\nopen Util.List\n\nlet step_updater_works\n  (sem: semantics_t)\n  (hprogram_actions: list sem.action_t)\n  (inv: invariant_t sem.state_t)\n  (laction: sem.action_t)\n  (step_updater: (sem.actor_t -> sem.step_t -> sem.state_t -> GTot sem.step_t))\n  : GTot bool =\n   u2b (forall (actor: sem.actor_t) (starts_atomic_block: bool) (ends_atomic_block: bool) (lstep: sem.step_t)\n          (s: sem.state_t).\n     (  sem.step_to_action_f lstep == laction\n      /\\ inv s\n      /\\ Some? (step_computation_generic sem actor starts_atomic_block ends_atomic_block lstep s)) ==>\n     (let hstep = step_updater actor lstep s in\n      let haction = sem.step_to_action_f hstep in\n        (contains_ubool haction hprogram_actions)\n      /\\ (step_computation_generic sem actor starts_atomic_block ends_atomic_block hstep s ==\n         step_computation_generic sem actor starts_atomic_block ends_atomic_block lstep s)))\n\nnoeq type weakening_transformer_t\n  (sem: semantics_t)\n  (hprogram_actions: list sem.action_t)\n  (inv: invariant_t sem.state_t) =\n  | WeakeningTransformerSameStep: (haction_index: nat) -> weakening_transformer_t sem hprogram_actions inv\n  | WeakeningTransformerUpdatedStep:\n     (laction: sem.action_t) ->\n     (step_updater: (sem.actor_t -> sem.step_t -> sem.state_t -> GTot sem.step_t)) ->\n     (proof: unit -> squash (step_updater_works sem hprogram_actions inv laction step_updater)) ->\n     weakening_transformer_t sem hprogram_actions inv\n\nlet action_matches_weakening_transformer\n  (#sem: semantics_t)\n  (#hprogram_actions: list sem.action_t)\n  (#inv: invariant_t sem.state_t)\n  (laction: sem.action_t)\n  (weakening_transformer: weakening_transformer_t sem hprogram_actions inv)\n  : GTot ubool =\n  match weakening_transformer with\n  | WeakeningTransformerSameStep haction_index -> nth hprogram_actions haction_index == Some laction\n  | WeakeningTransformerUpdatedStep action _ _ -> laction == action\n\nnoeq type weakening_relation_t = {\n  sem: semantics_t;\n  lprog: program_t sem;\n  hprog: program_t sem;\n  inv: invariant_t sem.state_t;\n  weakening_transformers: list (weakening_transformer_t sem hprog.actions inv);\n  sem_has_stepwise_inductive_invariant_proof:\n    unit -> squash (semantics_has_stepwise_inductive_invariant sem lprog inv);\n  actions_match_weakening_transformers_proof: unit ->\n    squash (lists_correspond_ubool action_matches_weakening_transformer lprog.actions weakening_transformers);\n  init_implies_init_proof: (s: sem.state_t{lprog.init_f s}) -> squash (hprog.init_f s);\n}\n\nval weakening_relation_implies_refinement (wr: weakening_relation_t)\n  : Lemma (ensures spec_refines_spec (semantics_to_spec wr.sem wr.lprog) (semantics_to_spec wr.sem wr.hprog) eq2)\n"
  },
  {
    "path": "experimental/lib/Util.Behavior.fst",
    "content": "module Util.Behavior\n\nopen FStar.Classical.Sugar\nopen Spec.Behavior\nopen Spec.Ubool\n\nlet refinement_relation_reflexive (#state_t: Type) (rr: refinement_relation_t state_t state_t) : ubool =\n  forall (s: state_t). rr s s\n\nlet rec refinement_relation_reflexive_implies_behavior_refines_itself\n  (#state_t: Type)\n  (b: behavior_t state_t)\n  (rr: refinement_relation_t state_t state_t)\n  : Lemma (requires refinement_relation_reflexive rr)\n          (ensures  behavior_refines_behavior b b rr) =\n  match b with\n  | [] -> ()\n  | lstate :: ltail -> refinement_relation_reflexive_implies_behavior_refines_itself ltail rr\n\nlet refinement_relation_stronger\n  (#low_state: Type)\n  (#high_state: Type)\n  (stronger_rr: refinement_relation_t low_state high_state)\n  (weaker_rr: refinement_relation_t low_state high_state) =\n  (forall (ls: low_state) (hs: high_state).{:pattern stronger_rr ls hs} stronger_rr ls hs ==> weaker_rr ls hs)\n\nlet rec behavior_refinement_maintained_by_weaker_refinement_relation\n  (#low_state: Type)\n  (#high_state: Type)\n  (lb: behavior_t low_state)\n  (hb: behavior_t high_state)\n  (stronger_rr: refinement_relation_t low_state high_state)\n  (weaker_rr: refinement_relation_t low_state high_state)\n  : Lemma\n  (requires (behavior_refines_behavior lb hb stronger_rr) /\\ refinement_relation_stronger stronger_rr weaker_rr)\n  (ensures  (behavior_refines_behavior lb hb weaker_rr)) =\n  match lb with\n  | [] -> assert (Nil? hb)\n  | lstate :: ltail ->\n    match hb with\n    | [] -> assert False\n    | hstate :: htail ->\n       eliminate behavior_refines_behavior ltail htail stronger_rr \\/\n                 (behavior_refines_behavior ltail hb stronger_rr \\/ behavior_refines_behavior lb htail stronger_rr)\n       returns behavior_refines_behavior lb hb weaker_rr\n       with case_ltail_refines_htail.\n         behavior_refinement_maintained_by_weaker_refinement_relation ltail htail stronger_rr weaker_rr\n       and  case_ltail_refines_hb_or_lb_refines_htail.\n         eliminate behavior_refines_behavior ltail hb stronger_rr \\/ behavior_refines_behavior lb htail stronger_rr\n         returns _\n         with case_ltail_refines_hb.\n           behavior_refinement_maintained_by_weaker_refinement_relation ltail hb stronger_rr weaker_rr\n         and  case_lb_refines_htail.\n           behavior_refinement_maintained_by_weaker_refinement_relation lb htail stronger_rr weaker_rr\n\nlet spec_refinement_maintained_by_weaker_refinement_relation\n  (#low_state: Type)\n  (#high_state: Type)\n  (lspec: spec_t low_state)\n  (hspec: spec_t high_state)\n  (stronger_rr: refinement_relation_t low_state high_state)\n  (weaker_rr: refinement_relation_t low_state high_state)\n  : Lemma\n  (requires spec_refines_spec lspec hspec stronger_rr /\\ refinement_relation_stronger stronger_rr weaker_rr)\n  (ensures  spec_refines_spec lspec hspec weaker_rr) =\n  introduce forall lb. behavior_satisfies_spec lb lspec ==>\n                  (exists (hb: behavior_t high_state). behavior_satisfies_spec hb hspec /\\\n                                                  behavior_refines_behavior lb hb weaker_rr)\n  with\n    introduce behavior_satisfies_spec lb lspec ==>\n              (exists (hb: behavior_t high_state). behavior_satisfies_spec hb hspec /\\ behavior_refines_behavior lb hb weaker_rr)\n    with lb_satisfies_spec.\n      eliminate exists hb. behavior_satisfies_spec hb hspec /\\ behavior_refines_behavior lb hb stronger_rr\n      returns _\n      with exists_hb_satisfying_spec_and_refined_by_lb.\n       (behavior_refinement_maintained_by_weaker_refinement_relation lb hb stronger_rr weaker_rr;\n        introduce exists hb. behavior_satisfies_spec hb hspec /\\ behavior_refines_behavior lb hb weaker_rr\n        with hb\n        and ())\n\nlet rec behavior_refines_behavior_without_stuttering\n  (#low_state: Type)\n  (#high_state: Type)\n  (lb: behavior_t low_state)\n  (hb: behavior_t high_state)\n  (rr: refinement_relation_t low_state high_state)\n  : ubool =\n  match lb with\n  | [] -> Nil? hb\n  | lstate :: ltail ->\n    match hb with\n    | [] -> False\n    | hstate :: htail ->\n      rr lstate hstate /\\\n      behavior_refines_behavior_without_stuttering ltail htail rr\n\nlet rec behavior_refines_behavior_without_stuttering_implies_behavior_refines_behavior\n  (#low_state: Type)\n  (#high_state: Type)\n  (lb: behavior_t low_state)\n  (hb: behavior_t high_state)\n  (rr: refinement_relation_t low_state high_state)\n  : Lemma (requires behavior_refines_behavior_without_stuttering lb hb rr)\n          (ensures  behavior_refines_behavior lb hb rr) =\n  match lb with\n  | [] -> ()\n  | lstate :: ltail ->\n     match hb with\n     | [] -> ()\n     | hstate :: htail ->\n        behavior_refines_behavior_without_stuttering_implies_behavior_refines_behavior ltail htail rr\n\nlet rec refinement_relation_reflexive_implies_behavior_refines_itself_without_stuttering\n  (#state_t: Type)\n  (b: behavior_t state_t)\n  (rr: refinement_relation_t state_t state_t)\n  : Lemma (requires refinement_relation_reflexive rr)\n          (ensures  behavior_refines_behavior_without_stuttering b b rr /\\ behavior_refines_behavior b b rr) =\n  match b with\n  | [] -> ()\n  | lstate :: ltail -> refinement_relation_reflexive_implies_behavior_refines_itself_without_stuttering ltail rr\n\nlet rec behavior_refinement_transitivity\n  (#lstate_t: Type)\n  (#mstate_t: Type)\n  (#hstate_t: Type)\n  (lb: behavior_t lstate_t)\n  (mb: behavior_t mstate_t)\n  (hb: behavior_t hstate_t)\n  (rr_lm: refinement_relation_t lstate_t mstate_t)\n  (rr_mh: refinement_relation_t mstate_t hstate_t)\n  (rr_lh: refinement_relation_t lstate_t hstate_t)\n  : Lemma (requires   behavior_refines_behavior lb mb rr_lm\n                    /\\ behavior_refines_behavior mb hb rr_mh\n                    /\\ (forall l m h.{:pattern rr_lm l m; rr_mh m h} rr_lm l m /\\ rr_mh m h ==> rr_lh l h))\n          (ensures  behavior_refines_behavior lb hb rr_lh) =\n  match lb with\n  | [] -> ()\n  | lstate :: ltail ->\n     match mb with\n     | [] -> ()\n     | mstate :: mtail ->\n        match hb with\n        | [] -> ()\n        | hstate :: htail ->\n           eliminate behavior_refines_behavior ltail mtail rr_lm \\/\n                     (behavior_refines_behavior ltail mb rr_lm \\/ behavior_refines_behavior lb mtail rr_lm)\n           returns behavior_refines_behavior lb hb rr_lh\n           with case_ltail_refines_mtail.\n             eliminate behavior_refines_behavior mtail htail rr_mh \\/ \n                        (behavior_refines_behavior mtail hb rr_mh \\/ behavior_refines_behavior mb htail rr_mh)\n             returns _\n             with case_mtail_refines_htail.\n               behavior_refinement_transitivity ltail mtail htail rr_lm rr_mh rr_lh\n             and  case_mtail_refines_hb_or_mb_refines_htail.\n               (eliminate behavior_refines_behavior mtail hb rr_mh \\/ behavior_refines_behavior mb htail rr_mh\n                returns _\n                with case_mtail_refines_hb. behavior_refinement_transitivity ltail mtail hb rr_lm rr_mh rr_lh\n                and  case_mb_refines_htail. behavior_refinement_transitivity lb mb htail rr_lm rr_mh rr_lh)\n           and  case_ltail_refines_mb_or_lb_refines_mtail.\n             eliminate behavior_refines_behavior ltail mb rr_lm \\/ behavior_refines_behavior lb mtail rr_lm\n             returns _\n             with case_ltail_refines_mb.\n               behavior_refinement_transitivity ltail mb hb rr_lm rr_mh rr_lh\n             and  case_lb_refines_mtail.\n               (eliminate behavior_refines_behavior mtail htail rr_mh \\/\n                (behavior_refines_behavior mtail hb rr_mh \\/ behavior_refines_behavior mb htail rr_mh)\n                returns _\n                with case_mtail_refines_htail.\n                  behavior_refinement_transitivity lb mtail htail rr_lm rr_mh rr_lh\n                and  case_mtail_refines_hb_or_mb_refines_htail.\n                  eliminate behavior_refines_behavior mtail hb rr_mh \\/ behavior_refines_behavior mb htail rr_mh\n                  returns _\n                  with case_mail_refines_hb.\n                    behavior_refinement_transitivity lb mtail hb rr_lm rr_mh rr_lh\n                  and  case_mb_refines_htail.\n                    behavior_refinement_transitivity lb mb htail rr_lm rr_mh rr_lh)\n\nlet spec_refinement_transitivity\n  (#lstate_t: Type)\n  (#mstate_t: Type)\n  (#hstate_t: Type)\n  (lspec: spec_t lstate_t)\n  (mspec: spec_t mstate_t)\n  (hspec: spec_t hstate_t)\n  (rr_lm: refinement_relation_t lstate_t mstate_t)\n  (rr_mh: refinement_relation_t mstate_t hstate_t)\n  (rr_lh: refinement_relation_t lstate_t hstate_t)\n  : Lemma (requires   spec_refines_spec lspec mspec rr_lm\n                    /\\ spec_refines_spec mspec hspec rr_mh\n                    /\\ (forall l m h.{:pattern rr_lm l m; rr_mh m h} rr_lm l m /\\ rr_mh m h ==> rr_lh l h))\n          (ensures  spec_refines_spec lspec hspec rr_lh) =\n  introduce forall lb. behavior_satisfies_spec lb lspec ==>\n                  (exists hb. behavior_satisfies_spec hb hspec /\\ behavior_refines_behavior lb hb rr_lh)\n  with\n    introduce behavior_satisfies_spec lb lspec ==>\n                  (exists hb. behavior_satisfies_spec hb hspec /\\ behavior_refines_behavior lb hb rr_lh)\n    with given_that_lb_satisfies_spec.\n      eliminate exists mb. behavior_satisfies_spec mb mspec /\\ behavior_refines_behavior lb mb rr_lm\n      returns _\n      with knowing_mb_satisfies_spec_and_is_refined_by_lb.\n        eliminate exists hb. behavior_satisfies_spec hb hspec /\\ behavior_refines_behavior mb hb rr_mh\n        returns _\n        with knowing_hb_satisfies_spec_and_is_refined_by_mb.\n          behavior_refinement_transitivity lb mb hb rr_lm rr_mh rr_lh\n\nlet spec_refinement_transitivity_4\n  (#state1_t: Type)\n  (#state2_t: Type)\n  (#state3_t: Type)\n  (#state4_t: Type)\n  (spec1: spec_t state1_t)\n  (spec2: spec_t state2_t)\n  (spec3: spec_t state3_t)\n  (spec4: spec_t state4_t)\n  (rr12: refinement_relation_t state1_t state2_t)\n  (rr23: refinement_relation_t state2_t state3_t)\n  (rr34: refinement_relation_t state3_t state4_t)\n  (rr13: refinement_relation_t state1_t state3_t)\n  (rr14: refinement_relation_t state1_t state4_t)\n  : Lemma (requires   spec_refines_spec spec1 spec2 rr12\n                    /\\ spec_refines_spec spec2 spec3 rr23\n                    /\\ spec_refines_spec spec3 spec4 rr34\n                    /\\ (forall s1 s2 s3.{:pattern rr12 s1 s2; rr23 s2 s3} rr12 s1 s2 /\\ rr23 s2 s3 ==> rr13 s1 s3)\n                    /\\ (forall s1 s3 s4.{:pattern rr13 s1 s3; rr34 s3 s4} rr13 s1 s3 /\\ rr34 s3 s4 ==> rr14 s1 s4))\n          (ensures  spec_refines_spec spec1 spec4 rr14) =\n  spec_refinement_transitivity spec1 spec2 spec3 rr12 rr23 rr13;\n  spec_refinement_transitivity spec1 spec3 spec4 rr13 rr34 rr14\n\nlet spec_refinement_transitivity_5\n  (#state1_t: Type)\n  (#state2_t: Type)\n  (#state3_t: Type)\n  (#state4_t: Type)\n  (#state5_t: Type)\n  (spec1: spec_t state1_t)\n  (spec2: spec_t state2_t)\n  (spec3: spec_t state3_t)\n  (spec4: spec_t state4_t)\n  (spec5: spec_t state5_t)\n  (rr12: refinement_relation_t state1_t state2_t)\n  (rr23: refinement_relation_t state2_t state3_t)\n  (rr34: refinement_relation_t state3_t state4_t)\n  (rr45: refinement_relation_t state4_t state5_t)\n  (rr13: refinement_relation_t state1_t state3_t)\n  (rr14: refinement_relation_t state1_t state4_t)\n  (rr15: refinement_relation_t state1_t state5_t)\n  : Lemma (requires   spec_refines_spec spec1 spec2 rr12\n                    /\\ spec_refines_spec spec2 spec3 rr23\n                    /\\ spec_refines_spec spec3 spec4 rr34\n                    /\\ spec_refines_spec spec4 spec5 rr45\n                    /\\ (forall s1 s2 s3.{:pattern rr12 s1 s2; rr23 s2 s3} rr12 s1 s2 /\\ rr23 s2 s3 ==> rr13 s1 s3)\n                    /\\ (forall s1 s3 s4.{:pattern rr13 s1 s3; rr34 s3 s4} rr13 s1 s3 /\\ rr34 s3 s4 ==> rr14 s1 s4)\n                    /\\ (forall s1 s4 s5.{:pattern rr14 s1 s4; rr45 s4 s5} rr14 s1 s4 /\\ rr45 s4 s5 ==> rr15 s1 s5))\n          (ensures  spec_refines_spec spec1 spec5 rr15) =\n  spec_refinement_transitivity spec1 spec2 spec3 rr12 rr23 rr13;\n  spec_refinement_transitivity spec1 spec3 spec4 rr13 rr34 rr14;\n  spec_refinement_transitivity spec1 spec4 spec5 rr14 rr45 rr15\n"
  },
  {
    "path": "experimental/lib/Util.ImmutableArray.fst",
    "content": "module Util.ImmutableArray\n\nopen Spec.List\nopen Util.List\nopen Util.Range\n\nlet rec array_offset_matches_list_implies_length_equivalent\n  (#ty: Type)\n  (a: array_t ty)\n  (len: nat{len = array_len a})\n  (offset: nat)\n  (l: list ty)\n  : Lemma (requires array_offset_matches_list a len offset l)\n          (ensures  array_len a = offset + list_len l)\n          (decreases l) =\n  match l with\n  | [] -> ()\n  | hd :: tl ->\n      array_offset_matches_list_implies_length_equivalent a len (offset + 1) tl\n\nlet array_matches_list_implies_length_equivalent (#ty: Type) (a: array_t ty) (l: list ty)\n  (* see .fsti file for spec *) =\n  array_offset_matches_list_implies_length_equivalent a (array_len a) 0 l\n\nlet rec array_offset_matches_list_implies_nth_equivalent\n  (#ty: Type)\n  (a: array_t ty)\n  (len: nat{len = array_len a})\n  (offset: nat)\n  (l: list ty)\n  (n: nat)\n  : Lemma (requires array_offset_matches_list a len offset l /\\ n >= offset)\n          (ensures  array_nth a n == list_nth l (n - offset))\n          (decreases l) =\n  match l with\n  | [] -> ()\n  | hd :: tl ->\n      if n = offset then\n        ()\n      else\n        array_offset_matches_list_implies_nth_equivalent a len (offset + 1) tl n\n\nlet array_matches_list_implies_nth_equivalent (#ty: Type) (a: array_t ty) (l: list ty) (n: nat)\n  (* see .fsti file for spec *) =\n  array_offset_matches_list_implies_nth_equivalent a (array_len a) 0 l n\n\nlet rec array_offset_matches_list_implies_index_equivalent\n  (#ty: Type)\n  (a: array_t ty)\n  (len: nat{len = array_len a})\n  (offset: nat)\n  (l: list ty)\n  (n: nat{n < len})\n  : Lemma (requires array_offset_matches_list a len offset l /\\ n >= offset /\\ len = offset + list_len l)\n          (ensures  array_index a n == list_index l (n - offset))\n          (decreases l) =\n  match l with\n  | [] -> ()\n  | hd :: tl ->\n      if n = offset then\n        ()\n      else\n        array_offset_matches_list_implies_index_equivalent a len (offset + 1) tl n\n\nlet array_matches_list_implies_index_equivalent\n  (#ty: Type)\n  (a: array_t ty)\n  (l: list ty)\n  (n: nat{n < array_len a})\n  (* see .fsti file for spec *) =\n  array_matches_list_implies_length_equivalent a l;\n  array_offset_matches_list_implies_index_equivalent a (array_len a) 0 l n\n\nlet rec indices_match_implies_array_offset_matches_list\n  (#ty: Type)\n  (a: array_t ty)\n  (len: nat{len = array_len a})\n  (offset: nat)\n  (l: list ty)\n  : Lemma (requires   offset + list_len l = len\n                    /\\ (forall (i: nat{i >= offset /\\ i < array_len a}). array_index a i == list_index l (i - offset)))\n          (ensures  array_offset_matches_list a len offset l)\n          (decreases l) =\n  match l with\n  | [] -> ()\n  | hd :: tl ->\n      indices_match_implies_array_offset_matches_list a len (offset + 1) tl\n\nlet indices_match_implies_array_matches_list\n  (#ty: Type)\n  (a: array_t ty)\n  (l: list ty)\n  : Lemma (requires   list_len l = array_len a\n                    /\\ (forall (i: nat{i < array_len a}). array_index a i == FStar.List.Tot.index l i))\n          (ensures  array_matches_list a l) =\n  indices_match_implies_array_offset_matches_list a (array_len a) 0 l\n\nlet list_to_array_implies_array_matches_list\n  (#ty: Type)\n  (a: array_t ty)\n  (l: list ty)\n  (* see .fsti file for spec *) =\n  to_list_of_list l;\n  length_spec a;\n  introduce forall (i: nat{i < array_len a}). array_index a i == list_index l i\n  with (\n    index_spec a i\n  );\n  indices_match_implies_array_matches_list a l\n\nlet array_to_list_implies_array_matches_list\n  (#ty: Type)\n  (a: array_t ty)\n  (l: list ty)\n  (* see .fsti file for spec *) =\n  length_spec a;\n  assert (list_len l = array_len a);\n  introduce forall (i: nat{i < list_len l}). array_index a i == list_index l i\n  with (\n    index_spec a i\n  );\n  indices_match_implies_array_matches_list a l\n\nlet list_to_array_implies_length_equivalent\n  (#ty: Type)\n  (a: array_t ty)\n  (l: list ty)\n  (* see .fsti file for spec *) =\n  list_to_array_implies_array_matches_list a l;\n  array_matches_list_implies_length_equivalent a l\n\nlet list_to_array_implies_nth_equivalent\n  (#ty: Type)\n  (a: array_t ty)\n  (l: list ty)\n  (n: nat)\n  (* see .fsti file for spec *) =\n  list_to_array_implies_array_matches_list a l;\n  array_matches_list_implies_nth_equivalent a l n\n\nlet list_to_array_implies_index_equivalent\n  (#ty: Type)\n  (a: array_t ty)\n  (l: list ty)\n  (n: nat{n < array_len a})\n  (* see .fsti file for spec *) =\n  list_to_array_implies_array_matches_list a l;\n  array_matches_list_implies_index_equivalent a l n\n\nlet array_elements_unique_implication\n  (#ty: eqtype)\n  (a: array_t ty)\n  (* see .fsti file for spec *) =\n  introduce forall (i: nat) (j: nat). i < array_len a /\\ j < array_len a /\\ i <> j ==> array_index a i <> array_index a j\n  with introduce i < array_len a /\\ j < array_len a /\\ i <> j ==> array_index a i <> array_index a j\n  with _. (\n    if i < j then\n      assert (for_all_range j (fun k -> array_index a j <> array_index a k))\n    else\n      assert (for_all_range i (fun k -> array_index a i <> array_index a k))\n  )\n\nlet array_elements_unique_ubool_implication\n  (#ty: Type)\n  (a: array_t ty)\n  (* see .fsti file for spec *) =\n  introduce forall (i: nat) (j: nat). i < array_len a /\\ j < array_len a /\\ i <> j ==> ~(array_index a i == array_index a j)\n  with introduce _ ==> _\n  with _. (\n    if i < j then\n      assert (for_all_range_ubool j (fun k -> ~(array_index a j == array_index a k)))\n    else\n      assert (for_all_range_ubool i (fun k -> ~(array_index a i == array_index a k)))\n  )\n"
  },
  {
    "path": "experimental/lib/Util.ImmutableArray.fsti",
    "content": "module Util.ImmutableArray\n\nopen FStar.ImmutableArray\nopen Spec.List\nopen Spec.Ubool\nopen Util.List\nopen Util.Nth\nopen Util.Range\n\nlet array_t = FStar.ImmutableArray.t\nlet array_len = FStar.ImmutableArray.length\nlet array_index = FStar.ImmutableArray.index\nlet list_to_array = FStar.ImmutableArray.of_list\nlet array_to_list = FStar.ImmutableArray.to_list\n\nlet array_nth (#ty: Type) (a: array_t ty) (i: nat) : option ty =\n  if i >= array_len a then\n    None\n  else\n    Some (array_index a i)\n\nlet rec array_offset_matches_list\n  (#ty: Type)\n  (a: array_t ty)\n  (len: nat{len = array_len a})\n  (offset: nat)\n  (l: list ty)\n  : GTot bool (decreases l) =\n  match l with\n  | [] -> len = offset\n  | hd :: tl -> len > offset && eqb hd (array_index a offset) && array_offset_matches_list a len (offset + 1) tl\n\nlet array_matches_list (#ty: Type) (a: array_t ty) (l: list ty) : GTot bool =\n  array_offset_matches_list a (array_len a) 0 l\n\nval array_matches_list_implies_length_equivalent (#ty: Type) (a: array_t ty) (l: list ty)\n  : Lemma (requires array_matches_list a l)\n          (ensures  array_len a = list_len l)\n\nval array_matches_list_implies_nth_equivalent (#ty: Type) (a: array_t ty) (l: list ty) (n: nat)\n  : Lemma (requires array_matches_list a l)\n          (ensures  array_nth a n == list_nth l n)\n\nval array_matches_list_implies_index_equivalent\n  (#ty: Type)\n  (a: array_t ty)\n  (l: list ty)\n  (n: nat{n < array_len a})\n  : Lemma (requires array_matches_list a l)\n          (ensures  n < list_len l /\\ array_index a n == list_index l n)\n\nval list_to_array_implies_array_matches_list\n  (#ty: Type)\n  (a: array_t ty)\n  (l: list ty)\n  : Lemma (requires a == list_to_array l)\n          (ensures  array_matches_list a l)\n\nval array_to_list_implies_array_matches_list\n  (#ty: Type)\n  (a: array_t ty)\n  (l: list ty)\n  : Lemma (requires l == array_to_list a)\n          (ensures  array_matches_list a l)\n\nval list_to_array_implies_length_equivalent\n  (#ty: Type)\n  (a: array_t ty)\n  (l: list ty)\n  : Lemma (requires a == list_to_array l)\n          (ensures  array_len a = list_len l)\n\nval list_to_array_implies_nth_equivalent\n  (#ty: Type)\n  (a: array_t ty)\n  (l: list ty)\n  (n: nat)\n  : Lemma (requires a == list_to_array l)\n          (ensures  array_nth a n == list_nth l n)\n\nval list_to_array_implies_index_equivalent\n  (#ty: Type)\n  (a: array_t ty)\n  (l: list ty)\n  (n: nat{n < array_len a})\n  : Lemma (requires a == list_to_array l)\n          (ensures  n < list_len l /\\ array_index a n == list_index l n)\n\nlet for_all_array (#ty: Type) (f: ty -> GTot bool) (a: array_t ty) =\n  for_all_range (array_len a) (fun i -> f (array_index a i))\n\nlet for_all_array_ubool (#ty: Type) (f: ty -> GTot ubool) (a: array_t ty) =\n  for_all_range_ubool (array_len a) (fun i -> f (array_index a i))\n\nlet for_all_array_enumerated (#ty: Type) (f: nat -> ty -> GTot bool) (a: array_t ty) =\n  for_all_range (array_len a) (fun i -> f i (array_index a i))\n\nlet for_all_array_enumerated_ubool (#ty: Type) (f: nat -> ty -> GTot ubool) (a: array_t ty) =\n  for_all_range_ubool (array_len a) (fun i -> f i (array_index a i))\n\nlet arrays_correspond\n  (#ty1: Type)\n  (#ty2: Type)\n  (correspondence: ty1 -> ty2 -> GTot bool)\n  (a1: array_t ty1)\n  (a2: array_t ty2)\n  : GTot bool =\n     array_len a1 = array_len a2\n  && for_all_range (array_len a1) (fun i -> correspondence (array_index a1 i) (array_index a2 i))\n\nlet arrays_correspond_ubool\n  (#ty1: Type)\n  (#ty2: Type)\n  (correspondence: ty1 -> ty2 -> GTot ubool)\n  (a1: array_t ty1)\n  (a2: array_t ty2)\n  : GTot ubool =\n     array_len a1 = array_len a2\n  /\\ for_all_range_ubool (array_len a1) (fun i -> correspondence (array_index a1 i) (array_index a2 i))\n\nlet rec find_in_array_offset\n  (#ty: Type)\n  (a: array_t ty)\n  (offset: nat)\n  (x: ty)\n  : GTot (result: option nat{\n            match result with\n            | None ->   (forall (i: nat).{:pattern array_index a i} offset <= i /\\ i < array_len a ==> ~(array_index a i == x))\n                     /\\ (forall (i: nat).{:pattern array_nth a i} offset <= i ==> ~(array_nth a i == Some x))\n            | Some i -> i < array_len a /\\ array_index a i == x /\\ array_nth a i == Some x})\n    (decreases array_len a - offset) =\n  if offset >= array_len a then\n    None\n  else if eqb (array_index a offset) x then\n    Some offset\n  else\n    find_in_array_offset a (offset + 1) x\n\nlet find_in_array\n  (#ty: Type)\n  (a: array_t ty)\n  (x: ty)\n  : GTot (result: option nat{\n            match result with\n            | None ->   (forall (i: nat).{:pattern array_index a i} i < array_len a ==> ~(array_index a i == x))\n                     /\\ (forall (i: nat).{:pattern array_nth a i} ~(array_nth a i == Some x))\n            | Some i -> i < array_len a /\\ array_index a i == x /\\ array_nth a i == Some x}) =\n  find_in_array_offset a 0 x\n\nlet array_elements_unique\n  (#ty: eqtype)\n  (a: array_t ty)\n  : GTot bool =\n  for_all_range (array_len a) (fun i -> for_all_range i (fun j -> array_index a i <> array_index a j))\n\nlet array_elements_unique_ubool\n  (#ty: Type)\n  (a: array_t ty)\n  : GTot ubool =\n  for_all_range_ubool (array_len a) (fun i -> for_all_range_ubool i (fun j -> ~(array_index a i == array_index a j)))\n\nval array_elements_unique_implication\n  (#ty: eqtype)\n  (a: array_t ty)\n  : Lemma (requires array_elements_unique a)\n          (ensures    (forall (i: nat) (j: nat).{:pattern array_index a i; array_index a j}\n                        i < array_len a /\\ j < array_len a /\\ i <> j ==> array_index a i <> array_index a j)\n                    /\\ (forall (i: nat) (j: nat).{:pattern array_nth a i; array_nth a j}\n                         i <> j /\\ array_nth a i = array_nth a j ==> None? (array_nth a i)))\n\nval array_elements_unique_ubool_implication\n  (#ty: Type)\n  (a: array_t ty)\n  : Lemma (requires array_elements_unique_ubool a)\n          (ensures    (forall (i: nat) (j: nat).{:pattern array_index a i; array_index a j}\n                        i < array_len a /\\ j < array_len a /\\ i <> j ==> ~(array_index a i == array_index a j))\n                    /\\ (forall (i: nat) (j: nat).{:pattern array_nth a i; array_nth a j}\n                         i <> j /\\ array_nth a i == array_nth a j ==> None? (array_nth a i)))\n\nlet arrays_correspond_specific_index\n  (#ty1: Type)\n  (#ty2: Type)\n  (correspondence: ty1 -> ty2 -> GTot bool)\n  (a1: array_t ty1)\n  (a2: array_t ty2{arrays_correspond correspondence a1 a2})\n  (idx: nat{idx < array_len a1})\n  : Lemma (ensures correspondence (array_index a1 idx) (array_index a2 idx)) =\n  ()\n"
  },
  {
    "path": "experimental/lib/Util.List.fst",
    "content": "module Util.List\n\nopen FStar.Calc\nopen FStar.Classical.Sugar\nopen FStar.List.Tot\nopen Spec.List\nopen Spec.Ubool\nopen Util.Logic\n\nlet list_index = FStar.List.Tot.index\nlet list_map = FStar.List.Tot.map\nlet list_append = FStar.List.Tot.append\n\nlet rec for_all_ghost (#a: Type) (f: a -> GTot bool) (l: list a) : GTot bool =\n  match l with\n  | [] -> true\n  | hd :: tl -> f hd && for_all_ghost f tl\n\nlet rec for_all_ubool (#a: Type) (f: a -> GTot ubool) (l: list a) : GTot ubool =\n  match l with\n  | [] -> True\n  | hd :: tl -> f hd /\\ for_all_ubool f tl\n\nlet rec exists_ghost (#a: Type) (f: a -> GTot bool) (l: list a) : GTot bool =\n  match l with\n  | [] -> false\n  | hd :: tl -> f hd || exists_ghost f tl\n\nlet rec exists_ubool (#a: Type) (f: a -> GTot ubool) (l: list a) : GTot ubool =\n  match l with\n  | [] -> False\n  | hd :: tl -> f hd \\/ exists_ubool f tl\n\nlet rec map_ghost (#a: Type) (#b: Type) (f: a -> GTot b) (l: list a) : GTot (list b) =\n  match l with\n  | [] -> []\n  | hd :: tl -> (f hd) :: map_ghost f tl\n\nlet rec for_all_ghost_equivalent_to_forall (#a: Type) (f: a -> GTot bool) (l: list a)\n  : Lemma (for_all_ghost f l <==> (forall x. contains_ubool x l ==> f x))\n           [SMTPat (for_all_ghost f l)] =\n  match l with\n  | [] -> ()\n  | hd :: tl -> for_all_ghost_equivalent_to_forall f tl\n\nlet rec for_all_ghost_equivalent_to_forall_eqtype (#a: eqtype) (f: a -> GTot bool) (l: list a)\n  : Lemma (for_all_ghost f l <==> (forall x. list_contains x l ==> f x))\n           [SMTPat (for_all_ghost f l)] =\n  match l with\n  | [] -> ()\n  | hd :: tl -> for_all_ghost_equivalent_to_forall_eqtype f tl\n\nlet for_all_ghost_specific_case (#a: Type) (f: a -> GTot bool) (l: list a) (x: a)\n  : Lemma (requires for_all_ghost f l /\\ contains_ubool x l)\n          (ensures f x) =\n  for_all_ghost_equivalent_to_forall f l\n\nlet for_all_ghost_specific_case_eqtype (#a: eqtype) (f: a -> GTot bool) (l: list a) (x: a)\n  : Lemma (requires for_all_ghost f l /\\ list_contains x l)\n          (ensures f x) =\n  for_all_ghost_equivalent_to_forall_eqtype f l\n\nlet contains_all (#a: Type) (xs: list a) (ys: list a) : GTot ubool =\n  for_all_ubool (fun (x: a) -> contains_ubool x ys) xs\n\nlet rec list_contains_last (#a: Type) (l: list a)\n  : Lemma (requires Cons? l)\n          (ensures  contains_ubool (last l) l) =\n  match l with\n  | [x] -> ()\n  | hd :: tl -> list_contains_last tl\n\nlet rec contains_equivalent_to_contains_ubool (#a: eqtype) (x: a) (l: list a)\n  : Lemma (ensures  contains x l <==> contains_ubool x l) =\n  match l with\n  | [] -> ()\n  | hd :: tl -> if hd = x then () else contains_equivalent_to_contains_ubool x tl\n\nlet rec for_all_ubool_equivalent_to_forall (#a: Type) (f: a -> GTot ubool) (l: list a)\n  : Lemma (for_all_ubool f l <==> (forall x. contains_ubool x l ==> f x))\n           [SMTPat (for_all_ubool f l)] =\n  match l with\n  | [] -> ()\n  | hd :: tl -> for_all_ubool_equivalent_to_forall f tl\n\nlet rec for_all_ubool_equivalent_to_forall_eqtype (#a: eqtype) (f: a -> GTot ubool) (l: list a)\n  : Lemma (for_all_ubool f l <==> (forall x. list_contains x l ==> f x))\n           [SMTPat (for_all_ubool f l)] =\n  match l with\n  | [] -> ()\n  | hd :: tl -> for_all_ubool_equivalent_to_forall_eqtype f tl\n\nlet for_all_ubool_specific_case (#a: Type) (f: a -> GTot ubool) (l: list a) (x: a)\n  : Lemma (requires for_all_ubool f l /\\ contains_ubool x l)\n          (ensures  f x) =\n  for_all_ubool_equivalent_to_forall f l\n\nlet rec filter_ghost (#a: Type) (f: a -> GTot bool) (l: list a) : GTot (m: list a{forall x. contains_ubool x m ==> f x}) =\n  match l with\n  | [] -> []\n  | hd :: tl -> if f hd then hd :: filter_ghost f tl else filter_ghost f tl\n\nlet rec contains_implies_filter_or_unfiltered (#a: Type) (f: a -> GTot bool) (l: list a) (x: a)\n  : Lemma (requires contains_ubool x l)\n          (ensures  contains_ubool x (filter_ghost f l) \\/ ~ (f x)) =\n  match l with\n  | [] -> ()\n  | hd :: tl -> if eqb x hd then () else contains_implies_filter_or_unfiltered f tl x\n\nlet rec implication_of_contains_and_for_all (#a: eqtype) (f: a -> GTot bool) (x: a) (l: list a)\n  : Lemma (requires list_contains x l /\\ for_all_ghost f l)\n          (ensures  f x) =\n  match l with\n  | [] -> ()\n  | hd :: tl -> if x = hd then () else implication_of_contains_and_for_all f x tl\n\nlet rec implication_of_contains_ubool_and_for_all (#a: Type) (f: a -> GTot bool) (x: a) (l: list a)\n  : Lemma (requires contains_ubool x l /\\ for_all_ghost f l)\n          (ensures  f x) =\n  match l with\n  | [] -> ()\n  | hd :: tl -> if eqb x hd then () else implication_of_contains_ubool_and_for_all f x tl\n\nlet rec for_all_implication\n  (#a: Type)\n  (#property1: a -> GTot bool)\n  (#property2: a -> GTot bool)\n  ($property_implication: (x: a) -> Lemma (requires property1 x) (ensures property2 x))\n  (l: list a)\n  : Lemma\n  (requires for_all_ghost property1 l)\n  (ensures  for_all_ghost property2 l) =\n  match l with\n  | [] -> ()\n  | hd :: tl -> property_implication hd; for_all_implication property_implication tl\n\nlet rec for_all_ubool_implication\n  (#a: Type)\n  (#property1: a -> GTot ubool)\n  (#property2: a -> GTot ubool)\n  ($property_implication: (x: a) -> Lemma (requires property1 x) (ensures property2 x))\n  (l: list a)\n  : Lemma\n  (requires for_all_ubool property1 l)\n  (ensures  for_all_ubool property2 l) =\n  match l with\n  | [] -> ()\n  | hd :: tl -> property_implication hd; for_all_ubool_implication property_implication tl\n\nlet rec for_all_equivalent\n  (#a: Type)\n  (#property1: a -> GTot bool)\n  (#property2: a -> GTot bool)\n  ($property_equivalent: (x: a) -> Lemma (property1 x = property2 x))\n  (l: list a)\n  : Lemma (for_all_ghost property1 l = for_all_ghost property2 l) =\n  match l with\n  | [] -> ()\n  | hd :: tl -> property_equivalent hd; for_all_equivalent property_equivalent tl\n\nlet rec for_all_ubool_equivalent\n  (#a: Type)\n  (#property1: a -> GTot ubool)\n  (#property2: a -> GTot ubool)\n  ($property_equivalent: (x: a) -> Lemma (property1 x == property2 x))\n  (l: list a)\n  : Lemma (for_all_ubool property1 l == for_all_ubool property2 l) =\n  match l with\n  | [] -> ()\n  | hd :: tl -> property_equivalent hd; for_all_ubool_equivalent property_equivalent tl\n\nlet rec lists_correspond\n  (#a: Type)\n  (#b: Type)\n  (correspondence: a -> b -> GTot bool)\n  (l1: list a)\n  (l2: list b)\n  : GTot bool =\n  match l1 with\n  | [] -> Nil? l2\n  | hd1 :: tl1 ->\n      match l2 with\n      | [] -> false\n      | hd2 :: tl2 -> correspondence hd1 hd2 && lists_correspond correspondence tl1 tl2\n\nlet rec lists_correspond_implies_lengths_match\n  (#a: Type)\n  (#b: Type)\n  (correspondence: a -> b -> GTot bool)\n  (l1: list a)\n  (l2: list b)\n  : Lemma\n  (requires lists_correspond #a #b correspondence l1 l2)\n  (ensures  length l1 = length l2) =\n  match l1 with\n  | [] -> ()\n  | hd :: tl -> lists_correspond_implies_lengths_match correspondence tl (Cons?.tl l2)\n\nlet rec lists_correspond_implies_weaker_correspondence\n  (#a: Type)\n  (#b: Type)\n  (stronger_correspondence: a -> b -> GTot bool)\n  (weaker_correspondence: a -> b -> GTot bool)\n  (l1: list a)\n  (l2: list b)\n  (stronger_implies_weaker: (x: a) -> (y: b) ->\n    Lemma (requires stronger_correspondence x y) (ensures weaker_correspondence x y))\n  : Lemma\n  (requires lists_correspond stronger_correspondence l1 l2)\n  (ensures  lists_correspond weaker_correspondence l1 l2) =\n  match l1 with\n  | [] -> ()\n  | hd1 :: tl1 ->\n      match l2 with\n      | [] -> ()\n      | hd2 :: tl2 ->\n          stronger_implies_weaker hd1 hd2;\n          lists_correspond_implies_weaker_correspondence\n            stronger_correspondence weaker_correspondence tl1 tl2 stronger_implies_weaker\n\nlet rec get_correspondent_from_lists_correspond\n  (#a: Type)\n  (#b: Type)\n  (correspondence: a -> b -> GTot bool)\n  (l1: list a)\n  (l2: list b{lists_correspond correspondence l1 l2})\n  (x: a{contains_ubool x l1})\n  : GTot (y:b{correspondence x y /\\ contains_ubool y l2}) =\n  match l1 with\n  | [] -> assert(false)\n  | hd1 :: tl1 ->\n     match l2 with\n     | [] -> assert(false)\n     | hd2 :: tl2 ->\n        if eqb hd1 x then\n          hd2\n        else\n          get_correspondent_from_lists_correspond correspondence tl1 tl2 x\n\nlet rec get_correspondent_from_lists_correspond_doubly\n  (#a: Type)\n  (#b: Type)\n  (correspondence1: a -> b -> GTot bool)\n  (correspondence2: a -> b -> GTot bool)\n  (l1: list a)\n  (l2: list b{lists_correspond correspondence1 l1 l2 /\\ lists_correspond correspondence2 l1 l2})\n  (x: a{contains_ubool x l1})\n  : GTot (y:b{correspondence1 x y /\\ correspondence2 x y /\\ contains_ubool y l2}) =\n  match l1 with\n  | [] -> assert(false)\n  | hd1 :: tl1 ->\n     match l2 with\n     | [] -> assert(false)\n     | hd2 :: tl2 ->\n        if eqb hd1 x then\n          hd2\n        else\n          get_correspondent_from_lists_correspond_doubly correspondence1 correspondence2 tl1 tl2 x\n\nlet rec lists_correspond_ubool\n  (#a: Type)\n  (#b: Type)\n  (correspondence: a -> b -> GTot ubool)\n  (l1: list a)\n  (l2: list b)\n  : GTot ubool =\n  match l1 with\n  | [] -> Nil? l2\n  | hd1 :: tl1 ->\n      match l2 with\n      | [] -> false\n      | hd2 :: tl2 -> correspondence hd1 hd2 /\\ lists_correspond_ubool correspondence tl1 tl2\n\nlet rec lists_correspond_ubool_implies_lengths_match\n  (#a: Type)\n  (#b: Type)\n  (correspondence: a -> b -> GTot ubool)\n  (l1: list a)\n  (l2: list b)\n  : Lemma\n  (requires lists_correspond_ubool #a #b correspondence l1 l2)\n  (ensures  length l1 = length l2) =\n  match l1 with\n  | [] -> ()\n  | hd :: tl -> lists_correspond_ubool_implies_lengths_match correspondence tl (Cons?.tl l2)\n\nlet rec lists_correspond_ubool_implies_weaker_correspondence\n  (#a: Type)\n  (#b: Type)\n  (stronger_correspondence: a -> b -> GTot ubool)\n  (weaker_correspondence: a -> b -> GTot ubool)\n  (l1: list a)\n  (l2: list b)\n  (stronger_implies_weaker: (x: a) -> (y: b) ->\n    Lemma (requires stronger_correspondence x y) (ensures weaker_correspondence x y))\n  : Lemma\n  (requires lists_correspond_ubool stronger_correspondence l1 l2)\n  (ensures  lists_correspond_ubool weaker_correspondence l1 l2) =\n  match l1 with\n  | [] -> ()\n  | hd1 :: tl1 ->\n      match l2 with\n      | [] -> ()\n      | hd2 :: tl2 ->\n          stronger_implies_weaker hd1 hd2;\n          lists_correspond_ubool_implies_weaker_correspondence\n            stronger_correspondence weaker_correspondence tl1 tl2 stronger_implies_weaker\n\nlet rec get_correspondent_from_lists_correspond_ubool\n  (#a: Type)\n  (#b: Type)\n  (correspondence: a -> b -> GTot ubool)\n  (l1: list a)\n  (l2: list b{lists_correspond_ubool correspondence l1 l2})\n  (x: a{contains_ubool x l1})\n  : GTot (y:b{correspondence x y /\\ contains_ubool y l2}) =\n  match l1 with\n  | [] -> assert(false)\n  | hd1 :: tl1 ->\n     match l2 with\n     | [] -> assert(false)\n     | hd2 :: tl2 ->\n        if eqb hd1 x then\n          hd2\n        else\n          get_correspondent_from_lists_correspond_ubool correspondence tl1 tl2 x\n\nlet rec exists_correspondent\n  (#a: Type)\n  (#b: Type)\n  (correspondence: a -> b -> GTot bool)\n  (l1: list a)\n  (l2: list b)\n  : GTot bool =\n  match l1, l2 with\n  | hd1 :: tl1, hd2 :: tl2 -> correspondence hd1 hd2 || exists_correspondent correspondence tl1 tl2\n  | _ -> false\n\nlet rec list_is_map_of_list (#a: Type) (#b: Type) (map_fun: a -> GTot b) (l1: list a) (l2: list b)\n  : GTot bool =\n  match l1 with\n  | [] -> Nil? l2\n  | hd1 :: tl1 ->\n      match l2 with\n      | [] -> false\n      | hd2 :: tl2 -> u2b (hd2 == map_fun hd1) && list_is_map_of_list map_fun tl1 tl2\n\nlet rec if_list_is_map_of_list_then_mapped_element_in_list\n  (#a: Type)\n  (#b: Type)\n  (map_fun: a -> GTot b)\n  (l1: list a)\n  (l2: list b)\n  (x: a)\n  : Lemma (requires contains_ubool x l1 /\\ list_is_map_of_list map_fun l1 l2)\n          (ensures  contains_ubool (map_fun x) l2) =\n  match l1 with\n  | [] -> assert False\n  | hd1 :: tl1 ->\n     match l2 with\n     | [] -> assert False\n     | hd2 :: tl2 ->\n         eliminate x == hd1 \\/ ~(x == hd1)\n         returns  contains_ubool (map_fun x) l2\n         with case_eq_hd1. assert (hd2 == map_fun x)\n         and  case_ne_hd1. if_list_is_map_of_list_then_mapped_element_in_list map_fun tl1 tl2 x\n\nlet rec list_is_prefix_of_list_reflexive (#a: Type) (l1: list a)\n  : Lemma (ensures list_is_prefix_of_list l1 l1) =\n  match l1 with\n  | [] -> ()\n  | hd :: tl -> list_is_prefix_of_list_reflexive tl\n\nlet rec append_preserves_for_all\n  (#a: Type)\n  (property: a -> GTot bool)\n  (l1: list a)\n  (l2: list a)\n  : Lemma\n  (requires for_all_ghost property l1 /\\ for_all_ghost property l2)\n  (ensures  for_all_ghost property (append l1 l2)) =\n  match l1 with\n  | [] -> ()\n  | hd :: tl -> append_preserves_for_all property tl l2\n\nlet rec append_preserves_for_all_ubool\n  (#a: Type)\n  (property: a -> GTot ubool)\n  (l1: list a)\n  (l2: list a)\n  : Lemma\n  (requires for_all_ubool property l1 /\\ for_all_ubool property l2)\n  (ensures  for_all_ubool property (append l1 l2)) =\n  match l1 with\n  | [] -> ()\n  | hd :: tl -> append_preserves_for_all_ubool property tl l2\n\nlet rec flatten_preserves_for_all\n  (#a: Type)\n  (property: a -> GTot bool)\n  (l: list (list a))\n  : Lemma\n  (requires for_all_ghost (fun sublist -> for_all_ghost property sublist) l)\n  (ensures  for_all_ghost property (flatten l)) =\n  match l with\n  | [] -> ()\n  | first_sublist :: remaining_sublists ->\n     flatten_preserves_for_all property remaining_sublists;\n     append_preserves_for_all property first_sublist (flatten remaining_sublists)\n\nlet rec flatten_preserves_for_all_ubool\n  (#a: Type)\n  (property: a -> GTot ubool)\n  (l: list (list a))\n  : Lemma\n  (requires for_all_ubool (fun sublist -> for_all_ubool property sublist) l)\n  (ensures  for_all_ubool property (flatten l)) =\n  match l with\n  | [] -> ()\n  | first_sublist :: remaining_sublists ->\n     flatten_preserves_for_all_ubool property remaining_sublists;\n     append_preserves_for_all_ubool property first_sublist (flatten remaining_sublists)\n\nlet rec append_nil_is_identity (#a: Type) (l: list a) : Lemma (append l Nil == l) =\n  match l with\n  | [] -> ()\n  | hd :: tl -> append_nil_is_identity tl\n\nlet rec append_commutes_with_map (#a: Type) (#b: Type) (f: a -> GTot b) (l1: list a) (l2: list a)\n  : Lemma (append (map_ghost f l1) (map_ghost f l2) == map_ghost f (append l1 l2)) =\n  match l1 with\n  | [] -> ()\n  | hd :: tl -> append_commutes_with_map f tl l2\n\nlet rec contains_ubool_append (#a: Type) (x: a) (l1: list a) (l2: list a)\n  : Lemma (ensures  contains_ubool x l1 \\/ contains_ubool x l2 <==> contains_ubool x (append l1 l2)) =\n  match l1 with\n  | [] -> ()\n  | hd :: tl -> if eqb x hd then () else contains_ubool_append x tl l2\n\nlet rec flatten_commutes_with_map (#a: Type) (#b: Type) (f: a -> GTot b) (l: list (list a))\n  : Lemma (flatten (map_ghost (fun (sublist: list a) -> map_ghost f sublist) l) == map_ghost f (flatten l)) =\n  match l with\n  | [] -> ()\n  | hd :: tl ->\n     flatten_commutes_with_map f tl;\n     append_commutes_with_map f hd (flatten tl)\n\nlet rec for_all_map (#a: Type) (#b: Type) (f: a -> GTot b) (p1: b -> GTot bool) (p2: a -> GTot bool) (l: list a)\n  : Lemma\n  (requires p2 == (fun x -> p1 (f x)))\n  (ensures  for_all_ghost p1 (map_ghost f l) = for_all_ghost p2 l) =\n  match l with\n  | [] -> ()\n  | hd :: tl -> for_all_map f p1 p2 tl\n\nlet rec for_all_ubool_map (#a: Type) (#b: Type) (f: a -> GTot b) (p1: b -> GTot ubool) (p2: a -> GTot ubool) (l: list a)\n  : Lemma\n  (requires p2 == (fun x -> p1 (f x)))\n  (ensures  for_all_ubool p1 (map_ghost f l) == for_all_ubool p2 l) =\n  match l with\n  | [] -> ()\n  | hd :: tl -> for_all_ubool_map f p1 p2 tl\n\nlet rec map_ghost_maps_last (#a: Type) (#b: Type) (f: a -> GTot b) (l: list a)\n  : Lemma (requires Cons? l)\n          (ensures  last (map_ghost f l) == f (last l)) =\n  match l with\n  | [last_element] -> ()\n  | first_element :: remaining_elements -> map_ghost_maps_last f remaining_elements\n\nlet rec lemma_splitAt_fst_length (#a: Type) (n: nat) (l: list a) :\n  Lemma\n    (requires (n <= length l))\n    (ensures  (length (fst (splitAt n l)) = n)) =\n  match n, l with\n  | 0, _ -> ()\n  | _, [] -> ()\n  | _, _ :: l' -> lemma_splitAt_fst_length (n - 1) l'\n\nlet rec for_all_range (n: nat) (f: (i: nat{i < n}) -> GTot bool) : GTot bool =\n  if n = 0 then\n    true\n  else (\n    f (n - 1) && for_all_range (n - 1) f\n  )\n\nlet rec for_all_range_equivalent_to_forall (n: nat) (f: (i: nat{i < n}) -> GTot bool)\n  : Lemma (for_all_range n f <==> (forall (i: nat). i < n ==> f i)) =\n  if n = 0 then\n    ()\n  else\n    for_all_range_equivalent_to_forall (n - 1) f\n\nlet rec exists_ghost_equivalent_to_exists (#a: Type) (f: a -> GTot bool) (l: list a)\n  : Lemma (exists_ghost f l <==> (exists x. f x /\\ contains_ubool x l))\n          [SMTPat (exists_ghost f l)] =\n  match l with\n  | [] -> ()\n  | hd :: tl -> exists_ghost_equivalent_to_exists f tl\n\nlet rec exists_ubool_equivalent_to_exists (#a: Type) (f: a -> GTot ubool) (l: list a)\n  : Lemma (exists_ubool f l <==> (exists x. f x /\\ contains_ubool x l))\n          [SMTPat (exists_ubool f l)] =\n  match l with\n  | [] -> ()\n  | hd :: tl -> exists_ubool_equivalent_to_exists f tl\n\nlet exists_ghost_to_witness (#a: Type) (f: a -> GTot bool) (l: list a{exists_ghost f l})\n  : GTot (x: a{f x /\\ contains_ubool x l}) =\n  exists_ghost_equivalent_to_exists f l;\n  simpler_indefinite_description (fun x -> f x /\\ contains_ubool x l)\n\nlet exists_ubool_to_witness (#a: Type) (f: a -> GTot ubool) (l: list a{exists_ubool f l})\n  : GTot (x: a{f x /\\ contains_ubool x l}) =\n  exists_ubool_equivalent_to_exists f l;\n  simpler_indefinite_description (fun x -> f x /\\ contains_ubool x l)\n\nlet rec contains_ubool_to_index (#a: Type) (x: a) (l: list a{contains_ubool x l})\n  : GTot (i: nat{i < length l /\\ index l i == x}) =\n  match l with\n  | [] -> false_elim ()\n  | hd :: tl -> if eqb x hd then 0 else 1 + contains_ubool_to_index x tl\n\nlet rec index_to_contains_ubool (#a: Type) (l: list a) (n: nat{n < length l})\n  : Lemma (contains_ubool (index l n) l) =\n  match l with\n  | [] -> false_elim ()\n  | hd :: tl -> if n = 0 then () else index_to_contains_ubool tl (n - 1)\n\nlet rec map_preserves_lists_correspond\n  (#a: Type)\n  (#b: Type)\n  (#c: Type)\n  (correspondence1: a -> b -> GTot bool)\n  (correspondence2: a -> c -> GTot bool)\n  (f: b -> GTot c)\n  (l1: list a)\n  (l2: list b)\n  : Lemma (requires   lists_correspond correspondence1 l1 l2\n                    /\\ (forall x y. correspondence1 x y ==> correspondence2 x (f y)))\n          (ensures  lists_correspond correspondence2 l1 (map_ghost f l2)) =\n  match l1, l2 with\n  | [], [] -> ()\n  | hd1 :: tl1, hd2 :: tl2 ->\n     map_preserves_lists_correspond correspondence1 correspondence2 f tl1 tl2\n\nlet rec map_preserves_lists_correspond_ubool\n  (#a: Type)\n  (#b: Type)\n  (#c: Type)\n  (correspondence1: a -> b -> GTot ubool)\n  (correspondence2: a -> c -> GTot ubool)\n  (f: b -> GTot c)\n  (l1: list a)\n  (l2: list b)\n  : Lemma (requires   lists_correspond_ubool correspondence1 l1 l2\n                    /\\ (forall x y. correspondence1 x y ==> correspondence2 x (f y)))\n          (ensures  lists_correspond_ubool correspondence2 l1 (map_ghost f l2)) =\n  match l1, l2 with\n  | [], [] -> ()\n  | hd1 :: tl1, hd2 :: tl2 ->\n     map_preserves_lists_correspond_ubool correspondence1 correspondence2 f tl1 tl2\n\nlet rec map_ghost_contains\n  (#a: eqtype)\n  (#b: eqtype)\n  (f: a -> GTot b)\n  (l: list a)\n  (x: a)\n  : Lemma (requires list_contains x l)\n          (ensures  list_contains (f x) (map_ghost f l)) =\n  match l with\n  | [] -> ()\n  | hd :: tl -> if x = hd then () else map_ghost_contains f tl x\n\nlet rec map_ghost_contains_ubool\n  (#a: Type)\n  (#b: Type)\n  (f: a -> GTot b)\n  (l: list a)\n  (x: a)\n  : Lemma (requires contains_ubool x l)\n          (ensures  contains_ubool (f x) (map_ghost f l)) =\n  match l with\n  | [] -> ()\n  | hd :: tl -> if eqb x hd then () else map_ghost_contains_ubool f tl x\n\nlet rec reverse_map_element_of_map_ghost\n  (#a: Type)\n  (#b: Type)\n  (f: a -> GTot b)\n  (l: list a)\n  (y: b{contains_ubool y (map_ghost f l)})\n  : GTot (x: a{contains_ubool x l /\\ y == f x}) =\n  match l with\n  | [] -> false_elim ()\n  | hd :: tl -> if eqb y (f hd) then hd else reverse_map_element_of_map_ghost f tl y\n\nlet rec map_ghost_preserves_length\n  (#a: Type)\n  (#b: Type)\n  (f: a -> GTot b)\n  (l: list a)\n  : Lemma (ensures length (map_ghost f l) = length l) =\n  match l with\n  | [] -> ()\n  | hd :: tl -> map_ghost_preserves_length f tl\n\nlet rec map_ghost_maps_index\n  (#a: Type)\n  (#b: Type)\n  (f: a -> GTot b)\n  (l: list a)\n  (i: nat)\n  : Lemma (requires i < length l \\/ i < length (map_ghost f l))\n          (ensures    i < length l\n                    /\\ i < length (map_ghost f l)\n                    /\\ index (map_ghost f l) i == f (index l i)) =\n  match l with\n  | [] -> false_elim ()\n  | hd :: tl -> if i = 0 then () else map_ghost_maps_index f tl (i - 1)\n\nlet rec lists_correspond_implies_map_ghost\n  (#a: Type)\n  (#b: Type)\n  (correspondence: a -> b -> GTot bool)\n  (f: a -> GTot b)\n  (l1: list a)\n  (l2: list b)\n  : Lemma (requires   lists_correspond correspondence l1 l2\n                    /\\ (forall x y. correspondence x y ==> y == f x))\n          (ensures  l2 == map_ghost f l1) =\n  match l1, l2 with\n  | [], [] -> ()\n  | hd1 :: tl1, hd2 :: tl2 -> lists_correspond_implies_map_ghost correspondence f tl1 tl2\n  | _, _ -> false_elim ()\n\nlet rec lists_correspond_ubool_implies_map_ghost\n  (#a: Type)\n  (#b: Type)\n  (correspondence: a -> b -> GTot ubool)\n  (f: a -> GTot b)\n  (l1: list a)\n  (l2: list b)\n  : Lemma (requires   lists_correspond_ubool correspondence l1 l2\n                    /\\ (forall x y. correspondence x y ==> y == f x))\n          (ensures  l2 == map_ghost f l1) =\n  match l1, l2 with\n  | [], [] -> ()\n  | hd1 :: tl1, hd2 :: tl2 -> lists_correspond_ubool_implies_map_ghost correspondence f tl1 tl2\n  | _, _ -> false_elim ()\n\nlet empty_lists_correspond\n  (#a: Type)\n  (#b: Type)\n  (correspondence: a -> b -> GTot bool)\n  : Lemma (ensures lists_correspond correspondence [] []) =\n  ()\n"
  },
  {
    "path": "experimental/lib/Util.Logic.fst",
    "content": "module Util.Logic\n\nopen Spec.Logic\nopen Spec.Ubool\n\nlet simpler_indefinite_description (#a: Type) ($p: a -> ubool) : Ghost a\n  (requires exists x. p x)\n  (ensures  fun x -> p x) =\n  let p': a -> prop = fun x -> squash (p x) in\n  FStar.IndefiniteDescription.indefinite_description_ghost a p'\n\nlet indefinite_description_two (#a: Type) (#b: Type) (p: (a -> b -> ubool)) : Ghost (a * b)\n  (requires exists x y. p x y)\n  (ensures  fun xy -> let x, y = xy in p x y) =\n  let p': (a * b) -> prop = fun xy -> squash (let x, y = xy in p x y) in\n  eliminate exists x' y'. p x' y'\n  returns exists xy. p' xy\n  with _. (assert (let x, y = (x', y') in p x y));\n  FStar.IndefiniteDescription.indefinite_description_ghost (a * b) p'\n\nlet indefinite_description_three (#a: Type) (#b: Type) (#c: Type) (p: (a -> b -> c -> ubool)) : Ghost (a * b * c)\n  (requires exists x y z. p x y z)\n  (ensures  fun xyz -> let x, y, z = xyz in p x y z) =\n  let p': (a * b * c) -> prop = fun xyz -> squash (let x, y, z = xyz in p x y z) in\n  eliminate exists x' y' z'. p x' y' z'\n  returns exists xyz. p' xyz\n  with _. (assert (let x, y, z = (x', y', z') in p x y z));\n  FStar.IndefiniteDescription.indefinite_description_ghost (a * b * c) p'\n"
  },
  {
    "path": "experimental/lib/Util.Nth.fst",
    "content": "module Util.Nth\n\nopen FStar.List.Tot\nopen Spec.List\nopen Spec.Ubool\nopen Util.List\n\nlet list_nth = nth\n\nlet rec nth_vs_length (#a: Type) (l: list a) (n: nat)\n  : Lemma (ensures (n < (length l)) <==> Some? (nth l n))\n  = match l with\n    | [] -> ()\n    | hd :: tl -> if n = 0 then () else nth_vs_length tl (n - 1)\n\nlet rec nth_implies_contains (#a: eqtype) (l: list a) (n: nat) (x: a)\n  : Lemma\n  (requires nth l n == Some x)\n  (ensures  list_contains x l)\n  = match l with\n    | [] -> ()\n    | hd :: tl -> if n = 0 then () else nth_implies_contains tl (n - 1) x\n\nlet rec nth_implies_contains_ubool (#a: Type) (l: list a) (n: nat) (x: a)\n  : Lemma\n  (requires nth l n == Some x)\n  (ensures  contains_ubool x l)\n  = match l with\n    | [] -> ()\n    | hd :: tl -> if n = 0 then () else nth_implies_contains_ubool tl (n - 1) x\n\nlet rec index_implies_contains (#a: eqtype) (l: list a) (n: nat{n < length l}) (x: a)\n  : Lemma\n  (requires index l n == x)\n  (ensures  list_contains x l)\n  = match l with\n    | [] -> ()\n    | hd :: tl -> if n = 0 then () else index_implies_contains tl (n - 1) x\n\nlet rec index_implies_contains_ubool (#a: Type) (l: list a) (n: nat{n < length l}) (x: a)\n  : Lemma\n  (requires index l n == x)\n  (ensures  contains_ubool x l)\n  = match l with\n    | [] -> ()\n    | hd :: tl -> if n = 0 then () else index_implies_contains_ubool tl (n - 1) x\n\nlet rec contains_to_index (#a: Type) (x: a) (l: list a)\n  : Ghost nat\n  (requires contains_ubool x l)\n  (ensures  fun n -> n < length l /\\ nth l n == Some x /\\ index l n == x) =\n  if eqb (hd l) x then 0 else 1 + contains_to_index x (tl l)\n\nlet rec lists_correspond_implies_index_matches\n  (#a: Type)\n  (#b: Type)\n  (correspondence_relation: a -> b -> GTot bool)\n  (l1: list a)\n  (l2: list b)\n  (n: nat)\n  : Lemma\n  (requires lists_correspond correspondence_relation l1 l2)\n  (ensures  (match nth l1 n with\n             | None -> None? (nth l2 n)\n             | Some x -> Some? (nth l2 n) /\\ correspondence_relation x (Some?.v (nth l2 n)))) =\n  if n = 0 then\n    ()\n  else\n    match l1 with\n    | [] -> ()\n    | hd :: tl -> lists_correspond_implies_index_matches correspondence_relation tl (Cons?.tl l2) (n - 1)\n\nlet rec lists_correspond_ubool_implies_index_matches\n  (#a: Type)\n  (#b: Type)\n  (correspondence_relation: a -> b -> GTot ubool)\n  (l1: list a)\n  (l2: list b)\n  (n: nat)\n  : Lemma\n  (requires lists_correspond_ubool correspondence_relation l1 l2)\n  (ensures  (match nth l1 n with\n             | None -> None? (nth l2 n)\n             | Some x -> Some? (nth l2 n) /\\ correspondence_relation x (Some?.v (nth l2 n)))) =\n  if n = 0 then\n    ()\n  else\n    match l1 with\n    | [] -> ()\n    | hd :: tl -> lists_correspond_ubool_implies_index_matches correspondence_relation tl (Cons?.tl l2) (n - 1)\n\nlet rec establish_lists_correspond_from_index_correspondence\n  (#a: Type)\n  (#b: Type)\n  (correspondence: a -> b -> GTot bool)\n  (l1: list a)\n  (l2: list b)\n  : Lemma (requires   list_len l1 = list_len l2\n                    /\\ (forall (i: nat). i < list_len l1 ==> correspondence (list_index l1 i) (list_index l2 i)))\n          (ensures  lists_correspond correspondence l1 l2) =\n  match l1 with\n  | [] -> ()\n  | hd1 :: tl1 ->\n     match l2 with\n     | [] -> ()\n     | hd2 :: tl2 ->\n        introduce forall (i: nat). i < list_len tl1 ==> correspondence (list_index tl1 i) (list_index tl2 i)\n        with introduce _ ==> _\n        with _. (\n          assert (list_index tl1 i == list_index l1 (i + 1));\n          assert (list_index tl2 i == list_index l2 (i + 1))\n        );\n        establish_lists_correspond_from_index_correspondence correspondence tl1 tl2\n\nlet rec establish_lists_correspond_ubool_from_index_correspondence\n  (#a: Type)\n  (#b: Type)\n  (correspondence: a -> b -> GTot ubool)\n  (l1: list a)\n  (l2: list b)\n  : Lemma (requires   list_len l1 = list_len l2\n                    /\\ (forall (i: nat). i < list_len l1 ==> correspondence (list_index l1 i) (list_index l2 i)))\n          (ensures  lists_correspond_ubool correspondence l1 l2) =\n  match l1 with\n  | [] -> ()\n  | hd1 :: tl1 ->\n     match l2 with\n     | [] -> ()\n     | hd2 :: tl2 ->\n        introduce forall (i: nat). i < list_len tl1 ==> correspondence (list_index tl1 i) (list_index tl2 i)\n        with introduce _ ==> _\n        with _. (\n          assert (list_index tl1 i == list_index l1 (i + 1));\n          assert (list_index tl2 i == list_index l2 (i + 1))\n        );\n        establish_lists_correspond_ubool_from_index_correspondence correspondence tl1 tl2\n\nlet rec equivalent_to_nth_offset\n  (#a: Type)\n  (offset: nat)\n  (l: list a)\n  (f: nat -> a)\n  : GTot bool\n  (decreases l)\n  = match l with\n    | [] -> true\n    | hd :: tl -> eqb (f offset) hd && (equivalent_to_nth_offset (offset + 1) tl f)\n\nlet equivalent_to_nth (#a: Type) (l: list a) (f: nat -> a) : GTot bool\n  = equivalent_to_nth_offset 0 l f\n\nlet rec equivalent_to_nth_offset_implies_matches_index\n  (#a: Type)\n  (offset: nat)\n  (l: list a)\n  (f: nat -> a)\n  (n: nat) : Lemma\n  (requires equivalent_to_nth_offset offset l f /\\ n < length l)\n  (ensures  nth l n == Some (f (n + offset)))\n  (decreases n)\n  = match l with\n    | [] -> ()\n    | hd :: tl ->\n       if n = 0 then ()\n       else equivalent_to_nth_offset_implies_matches_index (offset + 1) tl f (n - 1)\n\nlet equivalent_to_nth_implies_matches_index\n  (#a: Type) (l: list a) (f: nat -> a) (n: nat) : Lemma\n  (requires equivalent_to_nth l f /\\ n < length l)\n  (ensures  nth l n == Some (f n))\n  = equivalent_to_nth_offset_implies_matches_index 0 l f n\n\nlet rec equivalent_to_index_offset\n  (#a: Type)\n  (offset: nat)\n  (l: list a)\n  (f: (n: nat{n < length l + offset} -> a))\n  : GTot bool\n  (decreases l)\n  = match l with\n    | [] -> true\n    | hd :: tl -> eqb (f offset) hd && (equivalent_to_index_offset (offset + 1) tl f)\n\nlet equivalent_to_index (#a: Type) (l: list a) (f: (n: nat{n < length l}) -> a) : GTot bool\n  = equivalent_to_index_offset 0 l f\n\nlet rec equivalent_to_index_offset_implies_matches_index\n  (#a: Type)\n  (offset: nat)\n  (l: list a)\n  (f: (n: nat{n < length l + offset} -> a))\n  (n: nat) : Lemma\n  (requires equivalent_to_index_offset offset l f /\\ n < length l)\n  (ensures  index l n == f (n + offset))\n  (decreases n)\n  = match l with\n    | [] -> ()\n    | hd :: tl ->\n       if n = 0 then ()\n       else equivalent_to_index_offset_implies_matches_index (offset + 1) tl f (n - 1)\n\nlet equivalent_to_index_implies_matches_index\n  (#a: Type) (l: list a) (f: (n: nat{n < length l}) -> a) (n: nat) : Lemma\n  (requires equivalent_to_index l f /\\ n < length l)\n  (ensures  index l n == f n)\n  = equivalent_to_index_offset_implies_matches_index 0 l f n\n\nlet rec nth_matches_index (#a: Type) (l: list a) (n: nat)\n  : Lemma (requires n < length l)\n          (ensures  nth l n == Some (index l n)) =\n  match l with\n  | [] -> ()\n  | hd :: tl -> if n = 0 then () else nth_matches_index tl (n - 1)\n\nnoeq type fast_list_t (a: Type) = {\n  len: nat;\n  lookup: nat -> a;\n}\n\nlet fast_list_equivalent_to_list (#a:Type) (f: fast_list_t a) (l: list a) : GTot bool =\n     f.len = length l\n  && equivalent_to_nth l f.lookup\n\nlet fast_list_lookup_valid (#a: Type) (f: fast_list_t a) (l: list a) (n: nat)\n  : Lemma (requires fast_list_equivalent_to_list f l /\\ n < f.len)\n          (ensures  index l n == f.lookup n)\n          [SMTPat   (fast_list_equivalent_to_list f l); SMTPat (f.lookup n)] =\n  equivalent_to_nth_implies_matches_index l f.lookup n;\n  nth_matches_index l n\n\nlet fast_nth (#a: Type) (f: fast_list_t a) (n: nat) : option a =\n  if n < f.len then Some (f.lookup n) else None\n\nlet fast_nth_equivalent_to_nth (#a: Type) (f: fast_list_t a) (l: list a) (n: nat)\n  : Lemma (requires fast_list_equivalent_to_list f l)\n          (ensures  fast_nth f n == nth l n) =\n  if n < f.len then\n    equivalent_to_nth_implies_matches_index l f.lookup n\n  else\n    nth_vs_length l n\n\nlet fast_nth_equivalent_to_nth_always (#a: Type) (f: fast_list_t a) (l: list a)\n  : Lemma (requires fast_list_equivalent_to_list f l)\n          (ensures  forall n.{:pattern fast_nth f n} fast_nth f n == nth l n) =\n  introduce forall n. fast_nth f n == nth l n\n  with fast_nth_equivalent_to_nth f l n\n"
  },
  {
    "path": "experimental/lib/Util.Range.fst",
    "content": "module Util.Range\n\nlet rec for_all_range_equivalent_to_forall (n: nat) (f: (i: nat{i < n}) -> GTot bool)\n  (* see .fsti file for spec *) =\n  if n = 0 then\n    ()\n  else\n    for_all_range_equivalent_to_forall (n - 1) f\n\nlet rec for_all_range_ubool_equivalent_to_forall (n: nat) (f: (i: nat{i < n}) -> GTot ubool)\n  (* see .fsti file for spec *) =\n  if n = 0 then\n    ()\n  else\n    for_all_range_ubool_equivalent_to_forall (n - 1) f\n"
  },
  {
    "path": "experimental/lib/Util.Range.fsti",
    "content": "module Util.Range\n\nopen Spec.Ubool\n\nlet rec for_all_range (n: nat) (f: (i: nat{i < n}) -> GTot bool) : GTot bool =\n  if n = 0 then true else (f (n - 1) && for_all_range (n - 1) f)\n\nlet rec for_all_range_ubool (n: nat) (f: (i: nat{i < n}) -> GTot ubool) : GTot ubool =\n  if n = 0 then True else (f (n - 1) /\\ for_all_range_ubool (n - 1) f)\n\nval for_all_range_equivalent_to_forall (n: nat) (f: (i: nat{i < n}) -> GTot bool)\n  : Lemma (ensures for_all_range n f <==> (forall (i: nat). i < n ==> f i))\n          [SMTPat (for_all_range n f)]\n\nval for_all_range_ubool_equivalent_to_forall (n: nat) (f: (i: nat{i < n}) -> GTot ubool)\n  : Lemma (ensures for_all_range_ubool n f <==> (forall (i: nat). i < n ==> f i))\n          [SMTPat (for_all_range_ubool n f)]\n"
  },
  {
    "path": "experimental/lib/Util.Relation.fst",
    "content": "module Util.Relation\n\nopen Spec.Ubool\n\nlet relation_t (a: Type) (b: Type) = a -> b -> GTot bool\n\nlet relation_is_one_to_one (#a: Type) (#b: Type) (relation: relation_t a b) : ubool =\n  forall x1 y1 x2 y2. relation x1 y1 /\\ relation x2 y2 ==> (x1 == x2 <==> y1 == y2)\n\nlet one_to_one_relation_t (a: Type) (b: Type) = relation: (a -> b -> GTot bool){relation_is_one_to_one relation}\n"
  },
  {
    "path": "experimental/lib/Util.Seq.fst",
    "content": "module Util.Seq\n\nopen FStar.Sequence.Ambient\nopen FStar.Sequence.Base\n\nlet rec map (#a: Type) (#b: Type) (f: a -> GTot b) (s: seq a) : GTot (s': seq b{map_correct f s s'}) (decreases rank s) =\n  if length s = 0 then\n    empty\n  else\n    append (singleton (f (index s 0))) (map f (drop s 1))\n\nlet rec map_refine (#a: Type) (#b: Type) (#p: a -> Type0)\n                   ($f: (x:a { p x } -> GTot b)) //the $ allows type inference at the call site to infer p\n                   (s:seq a {forall x. contains s x ==> p x })\n  : GTot (s': seq b{length s = length s' /\\ (forall (i:nat). i < length s ==> p (index s i) /\\ index s' i == f (index s i))})\n    (decreases rank s)\n  = if length s = 0 then\n      empty\n    else\n      let hd = index s 0 in\n      let tl = drop s 1 in\n      assert (rank tl << rank s);\n      append (singleton (f hd)) (map_refine f tl)\n\nlet rec function_to_sequence (#ty: Type) (n: nat) (f: (i: nat{i < n}) -> GTot ty) =\n  (* see .fsti file for spec *)\n  if n = 0 then\n    empty\n  else\n    let s_prev = function_to_sequence (n - 1) f in\n    build s_prev (f (n - 1))\n\nlet rec seq_to_list (#ty: Type) (s: seq ty)\n  : GTot (lst: list ty{  FStar.List.Tot.length lst = length s\n                       /\\ (forall (i: nat). i < length s ==> FStar.List.Tot.index lst i == index s i)})\n    (decreases rank s) =\n  if length s = 0 then\n    []\n  else\n    (index s 0) :: seq_to_list (drop s 1)\n\nlet rec build_equivalent_to_append (#ty: Type) (s: seq ty) (v: ty)\n  : Lemma (ensures seq_to_list (build s v) == FStar.List.Tot.append (seq_to_list s) [v])\n          (decreases rank s) =\n  let lst = seq_to_list s in\n  match lst with\n  | [] -> ()\n  | hd :: tl -> build_equivalent_to_append (drop s 1) v\n\nlet rec exists_seq_implies_specific_helper\n  (#ty: Type)\n  (f: ty -> GTot bool)\n  (s: seq ty)\n  (pos: nat{exists_in_seq_after_pos f s pos})\n  : GTot (x: ty{contains s x /\\ f x})\n    (decreases length s - pos) =\n  if f (index s pos) then\n    index s pos\n  else\n    exists_seq_implies_specific_helper f s (pos + 1)\n\nlet exists_seq_implies_specific (#ty: Type) (f: ty -> GTot bool) (s: seq ty{exists_seq f s})\n  : GTot (x: ty{contains s x /\\ f x}) =\n  exists_seq_implies_specific_helper f s 0\n\nlet rec exists_implies_exists_seq_helper (#ty: Type) (f: ty -> GTot bool) (s: seq ty) (x: ty) (pos: nat)\n  : Lemma (requires   contains s x\n                    /\\ f x\n                    /\\ pos < length s\n                    /\\ (forall (i: nat). i < pos ==> ~(f (index s i))))\n          (ensures  exists_in_seq_after_pos f s pos)\n          (decreases length s - pos) =\n  if f (index s pos) then\n    ()\n  else\n    exists_implies_exists_seq_helper f s x (pos + 1)\n\nlet exists_implies_exists_seq (#ty: Type) (f: ty -> GTot bool) (s: seq ty) (x: ty)\n  : Lemma (requires contains s x /\\ f x)\n          (ensures  exists_seq f s) =\n  exists_implies_exists_seq_helper f s x 0\n\nlet exists_seq_equivalent_to_exists_seq_ubool (#ty: Type) (f: ty -> GTot bool) (s: seq ty)\n  : Lemma (exists_seq f s <==> exists_seq_ubool f s) =\n  introduce exists_seq f s ==> exists_seq_ubool f s\n  with _. (\n    introduce exists x. (contains s x /\\ f x)\n    with (exists_seq_implies_specific f s)\n    and ()\n  );\n  introduce exists_seq_ubool f s ==> exists_seq f s\n  with _. (\n    eliminate exists x. contains s x /\\ f x\n    returns exists_seq f s\n    with _. (exists_implies_exists_seq f s x)\n  )\n\nlet rec for_all_seq_implies_specific_helper (#ty: Type) (f: ty -> GTot bool) (s: seq ty) (x: ty) (pos: nat)\n  : Lemma (requires   for_all_seq_after_pos f s pos\n                    /\\ contains s x\n                    /\\ pos < length s\n                    /\\ (forall (i: nat). i < pos ==> ~(x == (index s i))))\n          (ensures  f x)\n          (decreases length s - pos) =\n  if eqb x (index s pos) then\n    ()\n  else\n    for_all_seq_implies_specific_helper f s x (pos + 1)\n\nlet for_all_seq_implies_specific (#ty: Type) (f: ty -> GTot bool) (s: seq ty) (x: ty)\n  : Lemma (requires for_all_seq f s /\\ contains s x)\n          (ensures  f x)\n          (decreases rank s) =\n  for_all_seq_implies_specific_helper f s x 0\n\nlet rec for_all_seq_equivalent_to_forall_helper (#ty: Type) (f: ty -> GTot bool) (s: seq ty) (pos: nat)\n  : Lemma (requires forall x. contains s x ==> f x)\n          (ensures  for_all_seq_after_pos f s pos)\n          (decreases length s - pos) =\n  if pos < length s then (\n    assert (f (index s pos));\n    for_all_seq_equivalent_to_forall_helper f s (pos + 1)\n  )\n  else\n    ()\n\nlet for_all_seq_equivalent_to_forall_seq_ubool (#ty: Type) (f: ty -> GTot bool) (s: seq ty)\n  : Lemma (ensures for_all_seq f s <==> for_all_seq_ubool f s)\n          (decreases rank s) =\n  introduce for_all_seq f s ==> for_all_seq_ubool f s\n  with _. (\n    introduce forall x. contains s x ==> f x\n    with (\n      introduce _ ==> _\n      with _. for_all_seq_implies_specific f s x\n    )\n  );\n  introduce for_all_seq_ubool f s ==> for_all_seq f s\n  with _.\n    for_all_seq_equivalent_to_forall_helper f s 0\n\nlet seq_contains_to_index (#ty: Type) (s: seq ty) (x: ty)\n  : Ghost nat\n  (requires contains s x)\n  (ensures  fun idx -> idx < length s /\\ index s idx == x) =\n  FStar.IndefiniteDescription.indefinite_description_ghost nat (fun idx -> idx < length s /\\ index s idx == x)\n\nlet rec seq_to_list_drop_equals_tail (#ty: Type) (s: seq ty)\n  : Lemma (requires length s > 0)\n          (ensures  Cons?.tl (seq_to_list s) == seq_to_list (drop s 1))\n          (decreases length s) =\n  if length s = 1 then\n    ()\n  else\n    seq_to_list_drop_equals_tail (drop s 1)\n"
  },
  {
    "path": "experimental/lib/Util.Seq.fsti",
    "content": "module Util.Seq\n\n//open FStar.Sequence.Ambient\nopen FStar.Sequence.Base\nopen Spec.Ubool\n\nlet map_correct (#a: Type) (#b: Type) (f: a -> GTot b) (s: seq a) (s': seq b) : ubool =\n    length s' = length s\n  /\\ (forall (i: nat{i < length s}). index s' i == f (index s i))\n\nval map (#a: Type) (#b: Type) (f: a -> GTot b) (s: seq a) : GTot (s': seq b{map_correct f s s'})\n\nval map_refine (#a: Type) (#b: Type) (#p: a -> Type0)\n               ($f: (x:a { p x } -> GTot b)) //the $ allows type inference at the call site to infer p\n               (s:seq a {forall x. contains s x ==> p x })\n  : GTot (s': seq b{length s = length s' /\\ (forall (i:nat). i < length s ==> p (index s i) /\\ index s' i == f (index s i))})\n\nlet function_to_sequence_correct (#ty: Type) (n: nat) (f: (i: nat{i < n}) -> GTot ty) (s: seq ty) : ubool =\n    length s = n\n  /\\ (forall (i: nat{i < n}). index s i == f i)\n\nval function_to_sequence (#ty: Type) (n: nat) (f: (i: nat{i < n}) -> GTot ty)\n  : GTot (s: seq ty{function_to_sequence_correct n f s})\n\nval seq_to_list (#ty: Type) (s: seq ty)\n  : GTot (lst: list ty{  FStar.List.Tot.length lst = length s\n                       /\\ (forall (i: nat). i < length s ==> FStar.List.Tot.index lst i == index s i)})\n\nval build_equivalent_to_append (#ty: Type) (s: seq ty) (v: ty)\n  : Lemma (ensures seq_to_list (build s v) == FStar.List.Tot.append (seq_to_list s) [v])\n\nlet exists_seq_ubool (#ty: Type) (f: ty -> GTot bool) (s: seq ty) : GTot ubool =\n  exists x. contains s x /\\ f x\n\nlet rec exists_in_seq_after_pos (#ty: Type) (f: ty -> GTot bool) (s: seq ty) (pos: nat)\n  : GTot bool (decreases length s - pos) =\n  if pos < length s then\n    f (index s pos) || exists_in_seq_after_pos f s (pos + 1)\n  else\n    false\n\nlet exists_seq (#ty: Type) (f: ty -> GTot bool) (s: seq ty) : GTot bool =\n  exists_in_seq_after_pos f s 0\n\nval exists_seq_implies_specific (#ty: Type) (f: ty -> GTot bool) (s: seq ty{exists_seq f s})\n  : GTot (x: ty{contains s x /\\ f x})\n\nval exists_seq_equivalent_to_exists_seq_ubool (#ty: Type) (f: ty -> GTot bool) (s: seq ty)\n  : Lemma (ensures exists_seq f s <==> exists_seq_ubool f s)\n\nlet for_all_seq_ubool (#ty: Type) (f: ty -> GTot bool) (s: seq ty) : GTot ubool =\n  forall x. contains s x ==> f x\n\nlet rec for_all_seq_after_pos (#ty: Type) (f: ty -> GTot bool) (s: seq ty) (pos: nat)\n  : GTot bool (decreases length s - pos) =\n  if pos < length s then\n    f (index s pos) && for_all_seq_after_pos f s (pos + 1)\n  else\n    true\n\nlet for_all_seq (#ty: Type) (f: ty -> GTot bool) (s: seq ty) : GTot bool =\n  for_all_seq_after_pos f s 0\n\nval for_all_seq_implies_specific (#ty: Type) (f: ty -> GTot bool) (s: seq ty) (x: ty)\n  : Lemma (requires for_all_seq f s /\\ contains s x)\n          (ensures  f x)\n\nval for_all_seq_equivalent_to_forall_seq_ubool (#ty: Type) (f: ty -> GTot bool) (s: seq ty)\n  : Lemma (ensures for_all_seq f s <==> for_all_seq_ubool f s)\n\nval seq_contains_to_index (#ty: Type) (s: seq ty) (x: ty)\n  : Ghost nat\n  (requires contains s x)\n  (ensures  fun idx -> idx < length s /\\ index s idx == x)\n\nval seq_to_list_drop_equals_tail (#ty: Type) (s: seq ty)\n  : Lemma (requires length s > 0)\n          (ensures  Cons?.tl (seq_to_list s) == seq_to_list (drop s 1))\n\n"
  },
  {
    "path": "experimental/lib/Util.Tactics.fst",
    "content": "module Util.Tactics\n\nopen FStar.Printf\nopen FStar.Tactics.V2\nopen FStar.Reflection.V2.TermEq\n\n/// Replacing a function in the current goal\n///\n/// Using the tactic `replace_fn_in_goal` will replace all instances\n/// of a given function invocation in the goal with an invocation of\n/// another function.  You give it the name of the function to be\n/// replaced (`fn`), the number of arguments to that function\n/// (`argc`), and a lemma that demonstrates that the function is\n/// equivalent to another function (`lem`).  That lemma must take\n/// `argc` arguments and have a postcondition that says that `fn`\n/// applied to that many arguments is `==` to another function.  You\n/// don't have to supply the name of that second function since it's\n/// taken from that postcondition automatically.\n///\n/// NOTE: The lemma must have as a postcondition that f a1 a2 ... ==\n/// f' a1 a2 where f is the replaced function.  If it says that f' a1\n/// a2 ... == f a1 a2 instead (i.e., in the wrong order) then\n/// `replace_fn_in_goal` won't work.\n\nlet rec is_term_an_invocation_of_function (t: term) (fn: term) (argc: nat) : Tac bool =\n  if argc = 0 then\n    term_eq t fn\n  else\n    match t with\n    | Tv_App fn' arg -> is_term_an_invocation_of_function fn' fn (argc - 1)\n    | _ -> false\n\nlet replace_fn_in_goal (fn: term) (argc: nat) (lem: term) : Tac unit =\n  let my_ctrl (t: term) : Tac (bool & ctrl_flag) =\n    (is_term_an_invocation_of_function t fn argc, Continue) in\n  let my_rw () : Tac unit =\n    apply_lemma lem in\n  ctrl_rewrite BottomUp my_ctrl my_rw\n\n/// Synthesizing a lemma invocation for each instance of a function in a term\n///\n/// The tactic `fn_to_lemma_invocations_in_term` creates an optional\n/// term that includes an invocation of lemma `lem` for each time a\n/// given function `fn` appears in a given term `t`.  You must also supply\n/// `argc`, the number of arguments to the function.  The lemma should take\n/// the same arguments as the function, in the same order.\n///\n/// Once you have optional terms from one or more invocations of\n/// `fn_to_lemma_invocations_in_term`, you can use them to synthesize\n/// a proof of a squashed proposition.  To do this, use\n/// `synthesize_proof_term_from_optional_terms`.  This will invoke the\n/// `t_exact` tactic using a term that concatenates all the optional\n/// terms.\n\nprivate let rec combine_optional_terms (ots: list (option term)) : Tac (option term) =\n  match ots with\n  | [] -> None\n  | [ot] -> ot\n  | Some t1 :: remaining_ots ->\n      (match combine_optional_terms remaining_ots with\n       | Some t2 -> Some (`(let _ = (`#t1) in (`#t2)))\n       | None -> Some t1)\n  | None :: remaining_ots -> combine_optional_terms remaining_ots\n\nprivate let rec optional_terms_to_terms (ots: list (option term)) : Tac (list term) =\n  match ots with\n  | [] -> []\n  | Some first_term :: remaining_ots -> first_term :: (optional_terms_to_terms remaining_ots)\n  | None :: remaining_ots -> optional_terms_to_terms remaining_ots\n\nprivate let rec combine_terms (ts: list term) : Tac term =\n  match ts with\n  | [] -> quote ()\n  | [t] -> t\n  | hd :: tl -> let tl' = combine_terms tl in\n              `(let _ = (`#hd) in (`#tl'))\n\nprivate let optional_terms_to_term (ots: list (option term)) : Tac term =\n  combine_terms (optional_terms_to_terms ots)\n\nlet synthesize_proof_term_from_optional_terms (ts: list (option term)) : Tac unit =\n  let t = optional_terms_to_term ts in\n//  print (\"Synthesized proof term: \" ^ (term_to_string t) ^ \" (end synthesized proof term)\");\n  t_exact true true t\n\nlet rec fn_to_lemma_invocation_in_application_term (fn: term) (argc: pos) (lem: term) (t: term) : Tac (option term) =\n  match t with\n  | Tv_App t' arg ->\n     if argc = 1 then\n       if term_eq t' fn then\n         Some (pack (Tv_App lem arg))\n       else\n         None\n     else\n       (match fn_to_lemma_invocation_in_application_term fn (argc - 1) lem t' with\n        | Some lem' -> Some (pack (Tv_App lem' arg))\n        | None -> None)\n  | _ -> None\n\nlet rec fn_to_lemma_invocations_in_term (fn: term) (argc: pos) (lem: term) (t: term) : Tac (option term) =\n  match inspect t with\n  | Tv_Var _ -> None\n  | Tv_BVar _ -> None\n  | Tv_FVar _ -> None\n  | Tv_UInst _ _ -> None\n  | Tv_App hd argv ->\n      let f' = fn_to_lemma_invocation_in_application_term fn argc lem t in\n      let hd' = fn_to_lemma_invocations_in_term fn argc lem hd in\n      let argv' = fn_to_lemma_invocations_in_term fn argc lem (fst argv) in\n      combine_optional_terms [f'; hd'; argv']\n  | Tv_Abs _ _ -> None\n  | Tv_Arrow _ _ -> None\n  | Tv_Type _ -> None\n  | Tv_Refine _ _ -> None\n  | Tv_Const _ -> None\n  | Tv_Uvar _ _ -> None\n  | Tv_Let recf attrs bv def body ->\n      let def_lemmas = fn_to_lemma_invocations_in_term fn argc lem def in\n      let body_lemmas =\n        (match fn_to_lemma_invocations_in_term fn argc lem body with\n         | Some body' -> Some (pack (Tv_Let recf attrs bv def body'))\n         | None -> None) in\n      combine_optional_terms [def_lemmas; body_lemmas]\n  | Tv_Match scrutinee ret brs ->\n      let scrutinee_lemmas = fn_to_lemma_invocations_in_term fn argc lem scrutinee in\n      let any_nontrivial, brs' = fn_to_lemma_invocations_in_branches fn argc lem brs in\n      let match_lemmas = if any_nontrivial then Some (pack (Tv_Match scrutinee ret brs')) else None in\n      combine_optional_terms [scrutinee_lemmas; match_lemmas]\n  | Tv_AscribedT e _ _ _ ->\n      fn_to_lemma_invocations_in_term fn argc lem e\n  | Tv_AscribedC e _ _ _ ->\n      fn_to_lemma_invocations_in_term fn argc lem e\n  | Tv_Unknown -> None\n  | Tv_Unsupp -> None\n\nand fn_to_lemma_invocations_in_branches\n  (fn: term)\n  (argc: pos)\n  (lem: term)\n  (brs: list branch)\n  : Tac (bool * (list branch)) =\n  match brs with\n  | [] -> false, []\n  | (branch_pattern, branch_term) :: remaining_branches ->\n      let remaining_any_nontrivial, remaining_result = fn_to_lemma_invocations_in_branches fn argc lem remaining_branches in\n      match fn_to_lemma_invocations_in_term fn argc lem branch_term with\n      | Some result -> true, (branch_pattern, result) :: remaining_result\n      | None -> remaining_any_nontrivial, (branch_pattern, quote ()) :: remaining_result\n\n(*\n\nassume val f (x: int) (y: int) : Tot int\nassume val f_lemma1 (x: int) (y: int) : Lemma (f x y > x)\nassume val f_lemma2 (x: int) (y: int) : Lemma (f x y > y)\nlet h (x: int) (y: int) (z: int) : Tot int = f (f x y) z\n\nlet f' (x: int) (y: int) : Tot (z: int{z > x /\\ z > y}) =\n  f_lemma1 x y;\n  f_lemma2 x y;\n  f x y\n\nlet f'_equivalence (x: int) (y: int) : Lemma (ensures f x y == f' x y) =\n  ()\n\nlet lem1 (x: int) (y: int) (z: int) (w: int) : Lemma (requires w = h x y z) (ensures w > x /\\ w > y /\\ w > z) =\n  assert (w = h x y z ==> w > x /\\ w > y /\\ w > z) by (\n    norm [nbe; delta; iota];\n    replace_fn_in_goal (`f) 2 (`f'_equivalence)\n  )\n\nlet lem2 (opt_x: option int) (y: int) (z: int) (w: int{match opt_x with | Some x -> w = h x y z | None -> False})\n: squash (match opt_x with | Some x -> w > x /\\ w > y /\\ w > z | None -> True) =\n  _ by (\n    let t1 = quote (match opt_x with | Some x -> w == h x y z | None -> False) in\n    let t2 = norm_term_env (cur_env ()) [nbe; delta; iota] t1 in\n    let ot1 = fn_to_lemma_invocations_in_term (`f) 2 (`f_lemma1) t2 in\n    let ot2 = fn_to_lemma_invocations_in_term (`f) 2 (`f_lemma2) t2 in\n    synthesize_proof_term_from_optional_terms [ot1; ot2]\n  )\n\n*)\n\n/// Converting term views to strings\n///\n/// The function `term_to_view_to_string` converts a term to a term_view and from\n/// that to a string.\n\nlet vconst_to_string  (v: vconst) : Tac string =\n  match v with\n  | C_Unit -> \"C_Unit\"\n  | C_Int i -> \"C_Int(\" ^ (sprintf \"%d\" i) ^ \")\"\n  | C_True -> \"C_True\"\n  | C_False -> \"C_False\"\n  | C_String s -> \"C_String(\" ^ s ^ \")\"\n  | C_Range r -> \"C_Range\"\n  | C_Reify -> \"C_Reify\"\n  | C_Reflect _ -> \"C_Reflect\"\n\nlet rec identifier_to_string (id: list string) : Tac string =\n  match id with\n  | [] -> \"\"\n  | [name] -> name\n  | modname :: id' -> modname ^ (identifier_to_string id')\n\nlet rec term_to_view_to_string (t: term) : Tac string =\n  match inspect t with\n  | Tv_Var v -> \"Tv_Var \" ^ (namedv_to_string v)\n  | Tv_BVar v -> \"Tv_BVar \" ^ (bv_to_string v)\n  | Tv_FVar v -> \"Tv_FVar \" ^ (fv_to_string v)\n  | Tv_UInst v us -> \"Tv_UInst \" ^ (fv_to_string v)\n  | Tv_App hd argv ->\n      \"Tv_App(\" ^ (term_to_view_to_string hd) ^ \" \" ^ (term_to_view_to_string (fst argv)) ^ \")\"\n  | Tv_Abs b body -> \"Tv_Abs(\" ^ (binder_to_string b) ^ \" -> \" ^ (term_to_view_to_string body) ^ \")\"\n  | Tv_Arrow _ _ -> \"Tv_Arrow\"\n  | Tv_Type _ -> \"Tv_Type\"\n  | Tv_Refine bv ref -> \"Tv_Refine\" ^ (term_to_view_to_string ref)\n  | Tv_Const v -> \"Tv_Const(\" ^ (vconst_to_string v) ^ \")\"\n  | Tv_Uvar _ _ -> \"Tv_Uvar\"\n  | Tv_Let recf attrs bv def body ->\n      \"Tv_Let(\" ^ (term_to_view_to_string (binder_to_term bv)) ^\n              \" = \" ^ (term_to_view_to_string def) ^ \" in \" ^ (term_to_view_to_string body) ^ \")\"\n  | Tv_Match scrutinee ret brs ->\n     \"Tv_Match(\" ^ (term_to_view_to_string scrutinee) ^ \" with \" ^ (branches_to_string brs) ^ \")\"\n  | Tv_AscribedT e t tac _ -> \"Tv_AscribedT(\" ^ (term_to_view_to_string e) ^ \")\"\n  | Tv_AscribedC e c tac _ -> \"Tv_AscribedC(\" ^ (term_to_view_to_string e) ^ \")\"\n  | Tv_Unknown -> \"Tv_Unknown\"\n  | Tv_Unsupp -> \"Tv_Unsupp\"\n\nand term_views_to_strings (ts: list term) : Tac string =\n  match ts with\n  | [] -> \"[]\"\n  | hd :: tl -> (term_to_view_to_string hd) ^ \" :: \" ^ (term_views_to_strings tl)\n\nand branches_to_string (bs: list branch) : Tac string =\n  match bs with\n  | [] -> \"\"\n  | (branch_pattern, branch_term) :: tl -> \"| ??? -> \" ^ (term_to_view_to_string branch_term) ^ \" \" ^ (branches_to_string tl)\n\n(*\n\nlet test_term_to_view_to_string (ox: option int) : Lemma (True) =\n  assert (True) by (\n    let t = quote (match ox with | Some x -> True | None -> False) in\n    print (term_to_view_to_string t)\n  )\n\n*)\n"
  },
  {
    "path": "experimental/lib/Util.Trigger.fst",
    "content": "module Util.Trigger\n\nlet trigger (#ty: Type) (v: ty) = True\n\n"
  },
  {
    "path": "experimental/output.c",
    "content": "#include <stdint.h>\n#include <pthread.h>\n#include <assert.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdatomic.h>\nvoid _main() {\n  int* p;\n  int arr[10];\n  p = (int*) calloc(sizeof(int), 1);\n  *p = 2;\n  arr[2] = 1;\n}\n\n\nint main() {\n  _main();\n  pthread_exit(NULL);\n}"
  },
  {
    "path": "experimental/third_party/Coco/LICENSE.txt",
    "content": "Compiler Generator Coco/R,\nCopyright (c) 1990, 2005 Hanspeter Moessenboeck, University of Linz\nextended by M. Loeberbauer & A. Woess, Univ. of Linz\nwith improvements by Pat Terry, Rhodes University\n\nThis program is free software; you can redistribute it and/or modify it \nunder the terms of the GNU General Public License as published by the \nFree Software Foundation; either version 2, or (at your option) any \nlater version.\n\nThis program is distributed in the hope that it will be useful, but \nWITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY \nor FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License \nfor more details.\n\nYou should have received a copy of the GNU General Public License along \nwith this program; if not, write to the Free Software Foundation, Inc., \n59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n\nAs an exception, it is allowed to write an extension of Coco/R that is\nused as a plugin in non-free software.\n\nIf not otherwise stated, any source code generated by Coco/R (other than \nCoco/R itself) does not fall under the GNU General Public License.\n"
  },
  {
    "path": "experimental/third_party/Coco/README.txt",
    "content": "This directory contains:\n\nbin: A copy of Coco.exe from http://www.ssw.uni-linz.ac.at/Research/Projects/Coco/ dated 2014-12-22.\n\nsrc: A copy of the sources of Coco/R from the same place.\n\nNote that the frame files in src/ have been modified to fit Dafny's purposes.\n"
  },
  {
    "path": "experimental/third_party/Coco/src/Parser.frame",
    "content": "/*----------------------------------------------------------------------\nCompiler Generator Coco/R,\nCopyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz\nextended by M. Loeberbauer & A. Woess, Univ. of Linz\nwith improvements by Pat Terry, Rhodes University\n\nThis program is free software; you can redistribute it and/or modify it\nunder the terms of the GNU General Public License as published by the\nFree Software Foundation; either version 2, or (at your option) any\nlater version.\n\nThis program is distributed in the hope that it will be useful, but\nWITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\nor FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\nfor more details.\n\nYou should have received a copy of the GNU General Public License along\nwith this program; if not, write to the Free Software Foundation, Inc.,\n59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n\nAs an exception, it is allowed to write an extension of Coco/R that is\nused as a plugin in non-free software.\n\nIf not otherwise stated, any source code generated by Coco/R (other than\nCoco/R itself) does not fall under the GNU General Public License.\n----------------------------------------------------------------------*/\n-->begin\n/* This file (Parser.cs) is generated from Dafny.atg by the Coco/R\n * parser generator. Do not edit this file directly. Instead, make\n * changes to Dafny.atg and then rebuild using the Makefile found\n * in the same directory as Dafny.atg.\n */\n\nusing System;\nusing System.Diagnostics.Contracts;\n\n-->namespace\n\npublic class Parser {\n-->constants\n  const bool _T = true;\n  const bool _x = false;\n  const int minErrDist = 2;\n\n  public Scanner scanner;\n  public Errors  errors;\n  public ErrorReporter reporter;\n\n  public Token t;    // last recognized token\n  public Token la;   // lookahead token\n  int errDist = minErrDist;\n\n-->declarations\n\n  private Parser(Scanner scanner) {\n    this.scanner = scanner;\n    Token tok = new Token();\n    tok.val = \"\";\n    this.la = tok;\n    this.t = new Token(); // just to satisfy its non-null constraint\n  }\n\n  void SynErr (int n) {\n    if (errDist >= minErrDist) errors.SynErr(la.line, la.col, n);\n    errDist = 0;\n  }\n\n  public void SemErr (Token tok, string msg) {\n    Contract.Requires(msg != null);\n    if (errDist >= minErrDist) errors.SemErr(tok, msg);\n    errDist = 0;\n  }\n\n  void Get () {\n    for (;;) {\n      t = la;\n      la = scanner.Scan();\n      if (la.kind <= maxT) { ++errDist; break; }\n-->pragmas\n      la = t;\n    }\n  }\n\n  void Expect (int n) {\n    if (la.kind==n) Get(); else { SynErr(n); }\n  }\n\n  bool StartOf (int s) {\n    return set[s, la.kind];\n  }\n\n  void ExpectWeak (int n, int follow) {\n    if (la.kind == n) Get();\n    else {\n      SynErr(n);\n      while (!StartOf(follow)) Get();\n    }\n  }\n\n\n  bool WeakSeparator(int n, int syFol, int repFol) {\n    int kind = la.kind;\n    if (kind == n) {Get(); return true;}\n    else if (StartOf(repFol)) {return false;}\n    else {\n      SynErr(n);\n      while (!(set[syFol, kind] || set[repFol, kind] || set[0, kind])) {\n        Get();\n        kind = la.kind;\n      }\n      return StartOf(syFol);\n    }\n  }\n\n\n-->productions\n  \n  public void Parse() {\n    la = new Token();\n    la.val = \"\";\n    Get();\n-->parseRoot\n  }\n\n  static readonly bool[,] set = {\n-->initialization\n  };\n} // end Parser\n\n\npublic class Errors {\n  readonly ErrorReporter Reporting;\n  public int ErrorCount;\n  public string filename;\n\n  public Errors(string filename, ErrorReporter Reporting) {\n    Contract.Requires(Reporting != null);\n    this.filename = filename;\n    this.Reporting = Reporting;\n  }\n\n  public void SynErr(int line, int col, int n) {\n    SynErr(line, col, GetSyntaxErrorString(n));\n  }\n\n  public void SynErr(int line, int col, string msg) {\n    Contract.Requires(msg != null);\n    ErrorCount++;\n    Reporting.Error(MessageSource.Parser, filename, line, col, msg);\n  }\n\n  string GetSyntaxErrorString(int n) {\n    string s;\n    switch (n) {\n-->errors\n      default: s = \"error \" + n; break;\n    }\n    return s;\n  }\n\n  public void SemErr(Token tok, string msg) {\n    Contract.Requires(msg != null);\n    ErrorCount++;\n    Reporting.Error(MessageSource.Parser, filename, tok.line, tok.col, msg);\n  }\n\n  public void Warning(Token tok, string msg) {\n    Contract.Requires(tok != null);\n    Contract.Requires(msg != null);\n    Reporting.Warning(MessageSource.Parser, tok, msg);\n  }\n} // Errors\n\n\npublic class FatalError: Exception {\n  public FatalError(string m): base(m) {}\n}\n\n"
  },
  {
    "path": "experimental/third_party/Coco/src/Scanner.frame",
    "content": "/*----------------------------------------------------------------------\nCompiler Generator Coco/R,\nCopyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz\nextended by M. Loeberbauer & A. Woess, Univ. of Linz\nwith improvements by Pat Terry, Rhodes University\n\nThis program is free software; you can redistribute it and/or modify it \nunder the terms of the GNU General Public License as published by the \nFree Software Foundation; either version 2, or (at your option) any \nlater version.\n\nThis program is distributed in the hope that it will be useful, but \nWITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY \nor FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License \nfor more details.\n\nYou should have received a copy of the GNU General Public License along \nwith this program; if not, write to the Free Software Foundation, Inc., \n59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n\nAs an exception, it is allowed to write an extension of Coco/R that is\nused as a plugin in non-free software.\n\nIf not otherwise stated, any source code generated by Coco/R (other than \nCoco/R itself) does not fall under the GNU General Public License.\n-----------------------------------------------------------------------*/\n-->begin\nusing System;\nusing System.IO;\nusing System.Collections;\n\n-->namespace\n\n[Serializable]\npublic class Token {\n\tpublic int kind    { get; set; } // token kind\n\tpublic int pos     { get; set; } // token position in bytes in the source text (starting at 0)\n\tpublic int charPos { get; set; } // token position in characters in the source text (starting at 0)\n\tpublic int col     { get; set; } // token column (starting at 1)\n\tpublic int line    { get; set; } // token line (starting at 1)\n\tpublic string val  { get; set; } // token value\n\tpublic Token next;               // ML 2005-03-11 Tokens are kept in linked list\n}\n\n//-----------------------------------------------------------------------------------\n// Buffer\n//-----------------------------------------------------------------------------------\npublic class Buffer {\n\t// This Buffer supports the following cases:\n\t// 1) seekable stream (file)\n\t//    a) whole stream in buffer\n\t//    b) part of stream in buffer\n\t// 2) non seekable stream (network, console)\n\n\tpublic const int EOF = char.MaxValue + 1;\n\tconst int MIN_BUFFER_LENGTH = 1024; // 1KB\n\tconst int MAX_BUFFER_LENGTH = MIN_BUFFER_LENGTH * 64; // 64KB\n\tbyte[] buf;         // input buffer\n\tint bufStart;       // position of first byte in buffer relative to input stream\n\tint bufLen;         // length of buffer\n\tint fileLen;        // length of input stream (may change if the stream is no file)\n\tint bufPos;         // current position in buffer\n\tStream stream;      // input stream (seekable)\n\tbool isUserStream;  // was the stream opened by the user?\n\t\n\tpublic Buffer (Stream s, bool isUserStream) {\n\t\tstream = s; this.isUserStream = isUserStream;\n\t\t\n\t\tif (stream.CanSeek) {\n\t\t\tfileLen = (int) stream.Length;\n\t\t\tbufLen = Math.Min(fileLen, MAX_BUFFER_LENGTH);\n\t\t\tbufStart = Int32.MaxValue; // nothing in the buffer so far\n\t\t} else {\n\t\t\tfileLen = bufLen = bufStart = 0;\n\t\t}\n\n\t\tbuf = new byte[(bufLen>0) ? bufLen : MIN_BUFFER_LENGTH];\n\t\tif (fileLen > 0) Pos = 0; // setup buffer to position 0 (start)\n\t\telse bufPos = 0; // index 0 is already after the file, thus Pos = 0 is invalid\n\t\tif (bufLen == fileLen && stream.CanSeek) Close();\n\t}\n\t\n\tprotected Buffer(Buffer b) { // called in UTF8Buffer constructor\n\t\tbuf = b.buf;\n\t\tbufStart = b.bufStart;\n\t\tbufLen = b.bufLen;\n\t\tfileLen = b.fileLen;\n\t\tbufPos = b.bufPos;\n\t\tstream = b.stream;\n\t\t// keep destructor from closing the stream\n\t\tb.stream = null;\n\t\tisUserStream = b.isUserStream;\n\t}\n\n\t~Buffer() { Close(); }\n\t\n\tprotected void Close() {\n\t\tif (!isUserStream && stream != null) {\n\t\t\tstream.Close();\n\t\t\tstream = null;\n\t\t}\n\t}\n\t\n\tpublic virtual int Read () {\n\t\tif (bufPos < bufLen) {\n\t\t\treturn buf[bufPos++];\n\t\t} else if (Pos < fileLen) {\n\t\t\tPos = Pos; // shift buffer start to Pos\n\t\t\treturn buf[bufPos++];\n\t\t} else if (stream != null && !stream.CanSeek && ReadNextStreamChunk() > 0) {\n\t\t\treturn buf[bufPos++];\n\t\t} else {\n\t\t\treturn EOF;\n\t\t}\n\t}\n\n\tpublic int Peek () {\n\t\tint curPos = Pos;\n\t\tint ch = Read();\n\t\tPos = curPos;\n\t\treturn ch;\n\t}\n\t\n\t// beg .. begin, zero-based, inclusive, in byte\n\t// end .. end, zero-based, exclusive, in byte\n\tpublic string GetString (int beg, int end) {\n\t\tint len = 0;\n\t\tchar[] buf = new char[end - beg];\n\t\tint oldPos = Pos;\n\t\tPos = beg;\n\t\twhile (Pos < end) buf[len++] = (char) Read();\n\t\tPos = oldPos;\n\t\treturn new String(buf, 0, len);\n\t}\n\n\tpublic int Pos {\n\t\tget { return bufPos + bufStart; }\n\t\tset {\n\t\t\tif (value >= fileLen && stream != null && !stream.CanSeek) {\n\t\t\t\t// Wanted position is after buffer and the stream\n\t\t\t\t// is not seek-able e.g. network or console,\n\t\t\t\t// thus we have to read the stream manually till\n\t\t\t\t// the wanted position is in sight.\n\t\t\t\twhile (value >= fileLen && ReadNextStreamChunk() > 0);\n\t\t\t}\n\n\t\t\tif (value < 0 || value > fileLen) {\n\t\t\t\tthrow new FatalError(\"buffer out of bounds access, position: \" + value);\n\t\t\t}\n\n\t\t\tif (value >= bufStart && value < bufStart + bufLen) { // already in buffer\n\t\t\t\tbufPos = value - bufStart;\n\t\t\t} else if (stream != null) { // must be swapped in\n\t\t\t\tstream.Seek(value, SeekOrigin.Begin);\n\t\t\t\tbufLen = stream.Read(buf, 0, buf.Length);\n\t\t\t\tbufStart = value; bufPos = 0;\n\t\t\t} else {\n\t\t\t\t// set the position to the end of the file, Pos will return fileLen.\n\t\t\t\tbufPos = fileLen - bufStart;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// Read the next chunk of bytes from the stream, increases the buffer\n\t// if needed and updates the fields fileLen and bufLen.\n\t// Returns the number of bytes read.\n\tprivate int ReadNextStreamChunk() {\n\t\tint free = buf.Length - bufLen;\n\t\tif (free == 0) {\n\t\t\t// in the case of a growing input stream\n\t\t\t// we can neither seek in the stream, nor can we\n\t\t\t// foresee the maximum length, thus we must adapt\n\t\t\t// the buffer size on demand.\n\t\t\tbyte[] newBuf = new byte[bufLen * 2];\n\t\t\tArray.Copy(buf, newBuf, bufLen);\n\t\t\tbuf = newBuf;\n\t\t\tfree = bufLen;\n\t\t}\n\t\tint read = stream.Read(buf, bufLen, free);\n\t\tif (read > 0) {\n\t\t\tfileLen = bufLen = (bufLen + read);\n\t\t\treturn read;\n\t\t}\n\t\t// end of stream reached\n\t\treturn 0;\n\t}\n}\n\n//-----------------------------------------------------------------------------------\n// UTF8Buffer\n//-----------------------------------------------------------------------------------\npublic class UTF8Buffer: Buffer {\n\tpublic UTF8Buffer(Buffer b): base(b) {}\n\n\tpublic override int Read() {\n\t\tint ch;\n\t\tdo {\n\t\t\tch = base.Read();\n\t\t\t// until we find a utf8 start (0xxxxxxx or 11xxxxxx)\n\t\t} while ((ch >= 128) && ((ch & 0xC0) != 0xC0) && (ch != EOF));\n\t\tif (ch < 128 || ch == EOF) {\n\t\t\t// nothing to do, first 127 chars are the same in ascii and utf8\n\t\t\t// 0xxxxxxx or end of file character\n\t\t} else if ((ch & 0xF0) == 0xF0) {\n\t\t\t// 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx\n\t\t\tint c1 = ch & 0x07; ch = base.Read();\n\t\t\tint c2 = ch & 0x3F; ch = base.Read();\n\t\t\tint c3 = ch & 0x3F; ch = base.Read();\n\t\t\tint c4 = ch & 0x3F;\n\t\t\tch = (((((c1 << 6) | c2) << 6) | c3) << 6) | c4;\n\t\t} else if ((ch & 0xE0) == 0xE0) {\n\t\t\t// 1110xxxx 10xxxxxx 10xxxxxx\n\t\t\tint c1 = ch & 0x0F; ch = base.Read();\n\t\t\tint c2 = ch & 0x3F; ch = base.Read();\n\t\t\tint c3 = ch & 0x3F;\n\t\t\tch = (((c1 << 6) | c2) << 6) | c3;\n\t\t} else if ((ch & 0xC0) == 0xC0) {\n\t\t\t// 110xxxxx 10xxxxxx\n\t\t\tint c1 = ch & 0x1F; ch = base.Read();\n\t\t\tint c2 = ch & 0x3F;\n\t\t\tch = (c1 << 6) | c2;\n\t\t}\n\t\treturn ch;\n\t}\n}\n\n//-----------------------------------------------------------------------------------\n// Scanner\n//-----------------------------------------------------------------------------------\npublic class Scanner {\n\tconst char EOL = '\\n';\n\tconst int eofSym = 0; /* pdt */\n-->declarations\n\n\tpublic Buffer buffer; // scanner buffer\n\t\n\tToken t;          // current token\n\tint ch;           // current input character\n\tint pos;          // byte position of current character\n\tint charPos;      // position by unicode characters starting with 0\n\tint col;          // column number of current character\n\tint line;         // line number of current character\n\tint oldEols;      // EOLs that appeared in a comment;\n\tstatic readonly Hashtable start; // maps first token character to start state\n\n\tToken tokens;     // list of tokens already peeked (first token is a dummy)\n\tToken pt;         // current peek token\n\t\n\tchar[] tval = new char[128]; // text of current token\n\tint tlen;         // length of current token\n\t\n\tstatic Scanner() {\n\t\tstart = new Hashtable(128);\n-->initialization\n\t}\n\t\n\tpublic Scanner (string fileName) {\n\t\ttry {\n\t\t\tStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);\n\t\t\tbuffer = new Buffer(stream, false);\n\t\t\tInit();\n\t\t} catch (IOException) {\n\t\t\tthrow new FatalError(\"Cannot open file \" + fileName);\n\t\t}\n\t}\n\t\n\tpublic Scanner (Stream s) {\n\t\tbuffer = new Buffer(s, true);\n\t\tInit();\n\t}\n\t\n\tvoid Init() {\n\t\tpos = -1; line = 1; col = 0; charPos = -1;\n\t\toldEols = 0;\n\t\tNextCh();\n\t\tif (ch == 0xEF) { // check optional byte order mark for UTF-8\n\t\t\tNextCh(); int ch1 = ch;\n\t\t\tNextCh(); int ch2 = ch;\n\t\t\tif (ch1 != 0xBB || ch2 != 0xBF) {\n\t\t\t\tthrow new FatalError(String.Format(\"illegal byte order mark: EF {0,2:X} {1,2:X}\", ch1, ch2));\n\t\t\t}\n\t\t\tbuffer = new UTF8Buffer(buffer); col = 0; charPos = -1;\n\t\t\tNextCh();\n\t\t}\n\t\tpt = tokens = new Token();  // first token is a dummy\n\t}\n\t\n\tvoid NextCh() {\n\t\tif (oldEols > 0) { ch = EOL; oldEols--; } \n\t\telse {\n\t\t\tpos = buffer.Pos;\n\t\t\t// buffer reads unicode chars, if UTF8 has been detected\n\t\t\tch = buffer.Read(); col++; charPos++;\n\t\t\t// replace isolated '\\r' by '\\n' in order to make\n\t\t\t// eol handling uniform across Windows, Unix and Mac\n\t\t\tif (ch == '\\r' && buffer.Peek() != '\\n') ch = EOL;\n\t\t\tif (ch == EOL) { line++; col = 0; }\n\t\t}\n-->casing1\n\t}\n\n\tvoid AddCh() {\n\t\tif (tlen >= tval.Length) {\n\t\t\tchar[] newBuf = new char[2 * tval.Length];\n\t\t\tArray.Copy(tval, 0, newBuf, 0, tval.Length);\n\t\t\ttval = newBuf;\n\t\t}\n\t\tif (ch != Buffer.EOF) {\n-->casing2\n\t\t\tNextCh();\n\t\t}\n\t}\n\n\n-->comments\n\n\tvoid CheckLiteral() {\n-->literals\n\t}\n\n\tToken NextToken() {\n\t\twhile (ch == ' ' ||\n-->scan1\n\t\t) NextCh();\n-->scan2\n\t\tint recKind = noSym;\n\t\tint recEnd = pos;\n\t\tt = new Token();\n\t\tt.pos = pos; t.col = col; t.line = line; t.charPos = charPos;\n\t\tint state;\n\t\tif (start.ContainsKey(ch)) { state = (int) start[ch]; }\n\t\telse { state = 0; }\n\t\ttlen = 0; AddCh();\n\t\t\n\t\tswitch (state) {\n\t\t\tcase -1: { t.kind = eofSym; break; } // NextCh already done\n\t\t\tcase 0: {\n\t\t\t\tif (recKind != noSym) {\n\t\t\t\t\ttlen = recEnd - t.pos;\n\t\t\t\t\tSetScannerBehindT();\n\t\t\t\t}\n\t\t\t\tt.kind = recKind; break;\n\t\t\t} // NextCh already done\n-->scan3\n\t\t}\n\t\tt.val = new String(tval, 0, tlen);\n\t\treturn t;\n\t}\n\t\n\tprivate void SetScannerBehindT() {\n\t\tbuffer.Pos = t.pos;\n\t\tNextCh();\n\t\tline = t.line; col = t.col; charPos = t.charPos;\n\t\tfor (int i = 0; i < tlen; i++) NextCh();\n\t}\n\t\n\t// get the next token (possibly a token already seen during peeking)\n\tpublic Token Scan () {\n\t\tif (tokens.next == null) {\n\t\t\treturn NextToken();\n\t\t} else {\n\t\t\tpt = tokens = tokens.next;\n\t\t\treturn tokens;\n\t\t}\n\t}\n\n\t// peek for the next token, ignore pragmas\n\tpublic Token Peek () {\n\t\tdo {\n\t\t\tif (pt.next == null) {\n\t\t\t\tpt.next = NextToken();\n\t\t\t}\n\t\t\tpt = pt.next;\n\t\t} while (pt.kind > maxT); // skip pragmas\n\t\n\t\treturn pt;\n\t}\n\n\t// make sure that peeking starts at the current scan position\n\tpublic void ResetPeek () { pt = tokens; }\n\n} // end Scanner\n"
  },
  {
    "path": "third_party/Coco/LICENSE.txt",
    "content": "Compiler Generator Coco/R,\nCopyright (c) 1990, 2005 Hanspeter Moessenboeck, University of Linz\nextended by M. Loeberbauer & A. Woess, Univ. of Linz\nwith improvements by Pat Terry, Rhodes University\n\nThis program is free software; you can redistribute it and/or modify it \nunder the terms of the GNU General Public License as published by the \nFree Software Foundation; either version 2, or (at your option) any \nlater version.\n\nThis program is distributed in the hope that it will be useful, but \nWITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY \nor FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License \nfor more details.\n\nYou should have received a copy of the GNU General Public License along \nwith this program; if not, write to the Free Software Foundation, Inc., \n59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n\nAs an exception, it is allowed to write an extension of Coco/R that is\nused as a plugin in non-free software.\n\nIf not otherwise stated, any source code generated by Coco/R (other than \nCoco/R itself) does not fall under the GNU General Public License.\n"
  },
  {
    "path": "third_party/Coco/README.txt",
    "content": "This directory contains:\n\nbin: A copy of Coco.exe from http://www.ssw.uni-linz.ac.at/Research/Projects/Coco/ dated 2014-12-22.\n\nsrc: A copy of the sources of Coco/R from the same place.\n\nNote that the frame files in src/ have been modified to fit Dafny's purposes.\n"
  },
  {
    "path": "third_party/Coco/src/Coco.atg",
    "content": "/*-------------------------------------------------------------------------\nCoco.ATG -- Attributed Grammar\nCompiler Generator Coco/R,\nCopyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz\nextended by M. Loeberbauer & A. Woess, Univ. of Linz\nwith improvements by Pat Terry, Rhodes University\n\nThis program is free software; you can redistribute it and/or modify it \nunder the terms of the GNU General Public License as published by the \nFree Software Foundation; either version 2, or (at your option) any \nlater version.\n\nThis program is distributed in the hope that it will be useful, but \nWITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY \nor FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License \nfor more details.\n\nYou should have received a copy of the GNU General Public License along \nwith this program; if not, write to the Free Software Foundation, Inc., \n59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n\nAs an exception, it is allowed to write an extension of Coco/R that is\nused as a plugin in non-free software.\n\nIf not otherwise stated, any source code generated by Coco/R (other than \nCoco/R itself) does not fall under the GNU General Public License.\n-------------------------------------------------------------------------*/\n/*-------------------------------------------------------------------------\n compile with:\n   Coco Coco.ATG -namespace at.jku.ssw.Coco\n-------------------------------------------------------------------------*/\n$namespace=at.jku.ssw.Coco\n\nusing System.IO;\n\nCOMPILER Coco\n\n\tconst int id = 0;\n\tconst int str = 1;\n\t\n\tpublic TextWriter trace;    // other Coco objects referenced in this ATG\n\tpublic Tab tab;\n\tpublic DFA dfa;\n\tpublic ParserGen pgen;\n\n\tbool   genScanner;\n\tstring tokenString;         // used in declarations of literal tokens\n\tstring noString = \"-none-\"; // used in declarations of literal tokens\n\n/*-------------------------------------------------------------------------*/\n\nCHARACTERS\n\tletter    = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_\".\n\tdigit     = \"0123456789\".\n\tcr        = '\\r'.\n\tlf        = '\\n'.\n\ttab       = '\\t'.\n\tstringCh  = ANY - '\"' - '\\\\' - cr - lf.\n\tcharCh    = ANY - '\\'' - '\\\\' - cr - lf.\n\tprintable = '\\u0020' .. '\\u007e'.\n\thex       = \"0123456789abcdef\".\n\nTOKENS\n\tident     = letter { letter | digit }.\n\tnumber    = digit { digit }.\n\tstring    = '\"' { stringCh | '\\\\' printable } '\"'.\n\tbadString = '\"' { stringCh | '\\\\' printable } (cr | lf).\n\tchar      = '\\'' ( charCh | '\\\\' printable { hex } ) '\\''.\n\nPRAGMAS\n\tddtSym    = '$' { digit | letter }.  (. tab.SetDDT(la.val); .)\n\n\toptionSym = '$' letter { letter } '='\n\t            { digit | letter\n\t            | '-' | '.' | ':'\n\t            }.                       (. tab.SetOption(la.val); .)\n\n\nCOMMENTS FROM \"/*\" TO \"*/\" NESTED\nCOMMENTS FROM \"//\" TO lf\n\nIGNORE cr + lf + tab\n\n/*-------------------------------------------------------------------------*/\n\nPRODUCTIONS\n\nCoco                            (. Symbol sym; Graph g, g1, g2; string gramName; CharSet s; int beg, line; .)\n=\n  [ // using statements\n    ANY                          (. beg = t.pos; line = t.line; .)\n    { ANY }                      (. pgen.usingPos = new Position(beg, la.pos, 0, line); .)\n  ]\n\n  \"COMPILER\"                    (. genScanner = true; \n                                   tab.ignored = new CharSet(); .) \n  ident                         (. gramName = t.val;\n                                   beg = la.pos; line = la.line;\n                                 .)\n  { ANY }                       (. tab.semDeclPos = new Position(beg, la.pos, 0, line); .)\n  [ \"IGNORECASE\"                (. dfa.ignoreCase = true; .) ]   /* pdt */\n  [ \"CHARACTERS\" { SetDecl }]\n  [ \"TOKENS\"  { TokenDecl<Node.t> }]\n  [ \"PRAGMAS\" { TokenDecl<Node.pr> }]\n  { \"COMMENTS\"                  (. bool nested = false; .)\n    \"FROM\" TokenExpr<out g1> \n    \"TO\" TokenExpr<out g2>\n    [ \"NESTED\"                  (. nested = true; .)\n    ]                           (. dfa.NewComment(g1.l, g2.l, nested); .)\n  }\n  { \"IGNORE\" Set<out s>         (. tab.ignored.Or(s); .)\n  }\n\n  SYNC \n  \"PRODUCTIONS\"                 (. if (genScanner) dfa.MakeDeterministic();\n                                   tab.DeleteNodes();\n                                 .)\n  { ident                       (. sym = tab.FindSym(t.val);\n                                   bool undef = sym == null;\n                                   if (undef) sym = tab.NewSym(Node.nt, t.val, t.line);\n                                   else {\n                                     if (sym.typ == Node.nt) {\n                                       if (sym.graph != null) SemErr(\"name declared twice\");\n                                   \t } else SemErr(\"this symbol kind not allowed on left side of production\");\n                                   \t sym.line = t.line;\n                                   }\n                                   bool noAttrs = sym.attrPos == null;\n                                   sym.attrPos = null;\n                                 .)\n    [ AttrDecl<sym> ]           (. if (!undef)\n                                     if (noAttrs != (sym.attrPos == null))\n                                       SemErr(\"attribute mismatch between declaration and use of this symbol\");\n                                 .)\n    [ SemText<out sym.semPos> ] WEAK\n    '='\n    Expression<out g>           (. sym.graph = g.l;\n                                   tab.Finish(g);\n                                 .)\n                                WEAK\n    '.'\n  }\n  \"END\" ident                   (. if (gramName != t.val)\n                                     SemErr(\"name does not match grammar name\");\n                                   tab.gramSy = tab.FindSym(gramName);\n                                   if (tab.gramSy == null)\n                                     SemErr(\"missing production for grammar name\");\n                                   else {\n                                     sym = tab.gramSy;\n                                     if (sym.attrPos != null)\n                                       SemErr(\"grammar symbol must not have attributes\");\n                                   }\n                                   tab.noSym = tab.NewSym(Node.t, \"???\", 0); // noSym gets highest number\n                                   tab.SetupAnys();\n                                   tab.RenumberPragmas();\n                                   if (tab.ddt[2]) tab.PrintNodes();\n                                   if (errors.count == 0) {\n                                     Console.WriteLine(\"checking\");\n                                     tab.CompSymbolSets();\n                                     if (tab.ddt[7]) tab.XRef();\n                                     if (tab.GrammarOk()) {\n                                       Console.Write(\"parser\");\n                                       pgen.WriteParser();\n                                       if (genScanner) {\n                                         Console.Write(\" + scanner\");\n                                         dfa.WriteScanner();\n                                         if (tab.ddt[0]) dfa.PrintStates();\n                                       }\n                                       Console.WriteLine(\" generated\");\n                                       if (tab.ddt[8]) pgen.WriteStatistics();\n                                     }\n                                   }\n                                   if (tab.ddt[6]) tab.PrintSymbolTable();\n                                 .)\n  '.'\n.\n\n/*------------------------------------------------------------------------------------*/\n\nSetDecl                         (. CharSet s; .)\n=\n  ident                         (. string name = t.val;\n                                   CharClass c = tab.FindCharClass(name);\n                                   if (c != null) SemErr(\"name declared twice\");\n                                 .)\n  '=' Set<out s>                (. if (s.Elements() == 0) SemErr(\"character set must not be empty\");\n                                   tab.NewCharClass(name, s);\n                                 .)\n  '.'\n.\n\n/*------------------------------------------------------------------------------------*/\n\nSet<out CharSet s>              (. CharSet s2; .)\n=\n  SimSet<out s>\n  { '+' SimSet<out s2>          (. s.Or(s2); .)\n  | '-' SimSet<out s2>          (. s.Subtract(s2); .)\n  }\n.\n\n/*------------------------------------------------------------------------------------*/\n\nSimSet<out CharSet s>           (. int n1, n2; .)\n=                               (. s = new CharSet(); .)\n( ident                         (. CharClass c = tab.FindCharClass(t.val);\n                                   if (c == null) SemErr(\"undefined name\"); else s.Or(c.set);\n                                 .)\n| string                        (. string name = t.val;\n                                   name = tab.Unescape(name.Substring(1, name.Length-2));\n                                   foreach (char ch in name)\n                                     if (dfa.ignoreCase) s.Set(char.ToLower(ch));\n                                     else s.Set(ch); .)\n| Char<out n1>                  (. s.Set(n1); .)\n  [ \"..\" Char<out n2>           (. for (int i = n1; i <= n2; i++) s.Set(i); .)\n  ]\n| \"ANY\"                         (. s = new CharSet(); s.Fill(); .)\n)\n.\n\n/*--------------------------------------------------------------------------------------*/\n\nChar<out int n>\n=\n  char                          (. string name = t.val; n = 0;\n                                   name = tab.Unescape(name.Substring(1, name.Length-2));\n                                   if (name.Length == 1) n = name[0];\n                                   else SemErr(\"unacceptable character value\");\n                                   if (dfa.ignoreCase && (char)n >= 'A' && (char)n <= 'Z') n += 32;\n                                 .)\n.\n\n/*------------------------------------------------------------------------------------*/\n\nTokenDecl<int typ>              (. string name; int kind; Symbol sym; Graph g; .)\n=\n  Sym<out name, out kind>       (. sym = tab.FindSym(name);\n                                   if (sym != null) SemErr(\"name declared twice\");\n                                   else {\n                                     sym = tab.NewSym(typ, name, t.line);\n                                     sym.tokenKind = Symbol.fixedToken;\n                                   }\n                                   tokenString = null;\n                                 .)\n  SYNC\n  ( '=' TokenExpr<out g> '.'    (. if (kind == str) SemErr(\"a literal must not be declared with a structure\");\n                                   tab.Finish(g);\n                                   if (tokenString == null || tokenString.Equals(noString))\n                                     dfa.ConvertToStates(g.l, sym);\n                                   else { // TokenExpr is a single string\n                                     if (tab.literals[tokenString] != null)\n                                       SemErr(\"token string declared twice\");\n                                     tab.literals[tokenString] = sym;\n                                     dfa.MatchLiteral(tokenString, sym);\n                                   }\n                                 .)\n  |                             (. if (kind == id) genScanner = false;\n                                   else dfa.MatchLiteral(sym.name, sym);\n                                 .)\n  )\n  [ SemText<out sym.semPos>     (. if (typ != Node.pr) SemErr(\"semantic action not allowed here\"); .)\n  ]\n.\n\n/*------------------------------------------------------------------------------------*/\n\nAttrDecl<Symbol sym>\n=\n  '<'                           (. int beg = la.pos; int col = la.col; int line = la.line; .)\n  { ANY\n  | badString                   (. SemErr(\"bad string in attributes\"); .)\n  }\n  '>'                           (. if (t.pos > beg)\n                                     sym.attrPos = new Position(beg, t.pos, col, line); .)\n| \"<.\"                          (. int beg = la.pos; int col = la.col; int line = la.line; .)\n  { ANY\n  | badString                   (. SemErr(\"bad string in attributes\"); .)\n  }\n  \".>\"                          (. if (t.pos > beg)\n                                     sym.attrPos = new Position(beg, t.pos, col, line); .)\n.\n\n/*------------------------------------------------------------------------------------*/\n\nExpression<out Graph g>         (. Graph g2; .)\n= \n  Term<out g>                   (. bool first = true; .)\n  {                             WEAK\n    '|'\n    Term<out g2>                (. if (first) { tab.MakeFirstAlt(g); first = false; }\n                                   tab.MakeAlternative(g, g2);\n                                 .)\n  }\n.\n\n/*------------------------------------------------------------------------------------*/\n\nTerm<out Graph g>               (. Graph g2; Node rslv = null; g = null; .)\n=\n( [                             (. rslv = tab.NewNode(Node.rslv, null, la.line); .)\n    Resolver<out rslv.pos>      (. g = new Graph(rslv); .)\n  ]\n  Factor<out g2>                (. if (rslv != null) tab.MakeSequence(g, g2);\n                                   else g = g2;\n                                 .)\n  { Factor<out g2>              (. tab.MakeSequence(g, g2); .)\n  }\n|                               (. g = new Graph(tab.NewNode(Node.eps, null, 0)); .)\n)                               (. if (g == null) // invalid start of Term\n                                     g = new Graph(tab.NewNode(Node.eps, null, 0));\n                                 .)\n.\n\n/*------------------------------------------------------------------------------------*/\n\nFactor<out Graph g>             (. string name; int kind; Position pos; bool weak = false; \n                                   g = null;\n                                 .)\n=\n( [ \"WEAK\"                      (. weak = true; .)\n  ]\n  Sym<out name, out kind>       (. Symbol sym = tab.FindSym(name);\n                                   if (sym == null && kind == str)\n                                     sym = tab.literals[name] as Symbol;\n                                   bool undef = sym == null;\n                                   if (undef) {\n                                     if (kind == id)\n                                       sym = tab.NewSym(Node.nt, name, 0);  // forward nt\n                                     else if (genScanner) { \n                                       sym = tab.NewSym(Node.t, name, t.line);\n                                       dfa.MatchLiteral(sym.name, sym);\n                                     } else {  // undefined string in production\n                                       SemErr(\"undefined string in production\");\n                                       sym = tab.eofSy;  // dummy\n                                     }\n                                   }\n                                   int typ = sym.typ;\n                                   if (typ != Node.t && typ != Node.nt)\n                                     SemErr(\"this symbol kind is not allowed in a production\");\n                                   if (weak)\n                                     if (typ == Node.t) typ = Node.wt;\n                                     else SemErr(\"only terminals may be weak\");\n                                   Node p = tab.NewNode(typ, sym, t.line);\n                                   g = new Graph(p);\n                                 .)\n  [ Attribs<p>                  (. if (kind != id) SemErr(\"a literal must not have attributes\"); .)\n  ]                             (. if (undef)\n                                     sym.attrPos = p.pos;  // dummy\n                                   else if ((p.pos == null) != (sym.attrPos == null))\n                                     SemErr(\"attribute mismatch between declaration and use of this symbol\");\n                                 .)\n| '(' Expression<out g> ')'\n| '[' Expression<out g> ']'     (. tab.MakeOption(g); .)\n| '{' Expression<out g> '}'     (. tab.MakeIteration(g); .)\n| SemText<out pos>              (. Node p = tab.NewNode(Node.sem, null, 0);\n                                   p.pos = pos;\n                                   g = new Graph(p);\n                                 .)\n| \"ANY\"                         (. Node p = tab.NewNode(Node.any, null, 0);  // p.set is set in tab.SetupAnys\n                                   g = new Graph(p);\n                                 .)\n| \"SYNC\"                        (. Node p = tab.NewNode(Node.sync, null, 0);\n                                   g = new Graph(p);\n                                 .)\n)                               (. if (g == null) // invalid start of Factor\n                                     g = new Graph(tab.NewNode(Node.eps, null, 0));\n                                 .)\n.\n\n/*------------------------------------------------------------------------------------*/\n\nResolver<out Position pos>   \n=\n  \"IF\" \"(\"                       (. int beg = la.pos; int col = la.col; int line = la.line; .)\n  Condition                      (. pos = new Position(beg, t.pos, col, line); .)\n.\n\n/*------------------------------------------------------------------------------------*/\n\nCondition = { \"(\" Condition | ANY } \")\" .\n\n/*------------------------------------------------------------------------------------*/\n\nTokenExpr<out Graph g>          (. Graph g2; .)\n=\n  TokenTerm<out g>              (. bool first = true; .)\n  {                             WEAK\n    '|'\n    TokenTerm<out g2>           (. if (first) { tab.MakeFirstAlt(g); first = false; }\n                                   tab.MakeAlternative(g, g2);\n                                 .)\n  }\n.\n\n/*------------------------------------------------------------------------------------*/\n\nTokenTerm<out Graph g>          (. Graph g2; .)\n=\n  TokenFactor<out g>\n  { TokenFactor<out g2>         (. tab.MakeSequence(g, g2); .)\n  }\n  [ \"CONTEXT\"\n    '(' TokenExpr<out g2>       (. tab.SetContextTrans(g2.l); dfa.hasCtxMoves = true;\n                                   tab.MakeSequence(g, g2); .)\n    ')'\n  ]\n.\n\n/*------------------------------------------------------------------------------------*/\n\nTokenFactor<out Graph g>        (. string name; int kind; .)\n=\n                                (. g = null; .)\n( Sym<out name, out kind>       (. if (kind == id) {\n                                     CharClass c = tab.FindCharClass(name);\n                                     if (c == null) {\n                                       SemErr(\"undefined name\");\n                                       c = tab.NewCharClass(name, new CharSet());\n                                     }\n                                     Node p = tab.NewNode(Node.clas, null, 0); p.val = c.n;\n                                     g = new Graph(p);\n                                     tokenString = noString;\n                                   } else { // str\n                                     g = tab.StrToGraph(name);\n                                     if (tokenString == null) tokenString = name;\n                                     else tokenString = noString;\n                                   }\n                                 .)\n| '(' TokenExpr<out g> ')'\n| '[' TokenExpr<out g> ']'      (. tab.MakeOption(g); tokenString = noString; .)\n| '{' TokenExpr<out g> '}'      (. tab.MakeIteration(g); tokenString = noString; .)\n)                               (. if (g == null) // invalid start of TokenFactor\n                                     g = new Graph(tab.NewNode(Node.eps, null, 0)); .)\n.\n\n/*------------------------------------------------------------------------------------*/\n\nSym<out string name, out int kind>\n=                               (. name = \"???\"; kind = id; .)\n( ident                         (. kind = id; name = t.val; .)\n| (string                       (. name = t.val; .)\n  | char                        (. name = \"\\\"\" + t.val.Substring(1, t.val.Length-2) + \"\\\"\"; .)\n  )                             (. kind = str;\n                                   if (dfa.ignoreCase) name = name.ToLower();\n                                   if (name.IndexOf(' ') >= 0)\n                                     SemErr(\"literal tokens must not contain blanks\"); .)\n)\n.\n\n/*------------------------------------------------------------------------------------*/\n\nAttribs<Node p>\n=\n  '<'                           (. int beg = la.pos; int col = la.col; int line = la.line; .)\n  { ANY \n  | badString                   (. SemErr(\"bad string in attributes\"); .)\n  }\n  '>'                           (. if (t.pos > beg) p.pos = new Position(beg, t.pos, col, line); .)\n| \"<.\"                          (. int beg = la.pos; int col = la.col; int line = la.line; .)\n  { ANY \n  | badString                   (. SemErr(\"bad string in attributes\"); .)\n  }\n  \".>\"                          (. if (t.pos > beg) p.pos = new Position(beg, t.pos, col, line); .)\n.\n\n/*------------------------------------------------------------------------------------*/\n\nSemText<out Position pos>\n=\n  \"(.\"                          (. int beg = la.pos; int col = la.col; int line = la.line; .)\n  { ANY\n  | badString                   (. SemErr(\"bad string in semantic action\"); .)\n  | \"(.\"                        (. SemErr(\"missing end of previous semantic action\"); .)\n  }\n  \".)\"                          (. pos = new Position(beg, t.pos, col, line); .)\n.\n\nEND Coco.\n"
  },
  {
    "path": "third_party/Coco/src/Coco.build",
    "content": "<?xml version=\"1.0\"?>\n<project name=\"Coco/R\" default=\"build\" basedir=\".\">\n\t<property name=\"debug\" value=\"true\" overwrite=\"false\" />\n\n\t<target name=\"usage\">\n\t\t<echo message=\"NAnt Targets:\"/>\n\t\t<echo message=\"    clean: Full clean up.\"/>\n\t\t<echo message=\"    build: Build Coco/R.\"/>\n\t\t<echo message=\"    zip: Create a zip file with the Coco/R sources.\"/>\n\t\t<echo message=\"    self: Create the parser and scanner from the atg.\"/>\n\t</target>\n\n\t<target name=\"init\">\n\t\t<tstamp/>\n\t</target>\n\n\t<target name=\"build\" depends=\"init\">\n\t\t<echo message=\"Building Coco/R...\"/>\n\t\t<csc target=\"exe\" output=\"Coco.exe\" debug=\"${debug}\">\n\t\t\t<sources>\n\t\t\t\t<include name=\"Coco.cs\" />\n\t\t\t\t<include name=\"Scanner.cs\" />\n\t\t\t\t<include name=\"Tab.cs\" />\n\t\t\t\t<include name=\"DFA.cs\" />\n\t\t\t\t<include name=\"ParserGen.cs\" />\n\t\t\t\t<include name=\"Parser.cs\" />\n\t\t\t</sources>\n\t\t</csc>\n\t</target>\n\n\t<target name=\"zip\">\n\t\t<echo message=\"Packing Coco/R...\"/>\n\t\t<zip zipfile=\"CocoSourcesCS.zip\">\n\t\t\t<fileset basedir=\".\">\n\t\t\t\t<include name=\"*.atg\" />\n\t\t\t\t<include name=\"*.frame\" />\n\t\t\t\t<include name=\"*.bat\" />\n\t\t\t\t<include name=\"*.cs\" />\n\t\t\t\t<include name=\"*.build\" />\n\t\t\t</fileset>\n\t\t</zip>\n\t</target>\n\n\t<target name=\"self-mono\">\n\t\t<exec program=\"mono\">\n\t\t\t<arg value=\"Coco.exe\" />\n\t\t\t<arg value=\"-namespace\" />\n\t\t\t<arg value=\"at.jku.ssw.Coco\" />\n\t\t\t<arg value=\"Coco.atg\" />\n\t\t</exec>\n\t</target>\n\n\t<target name=\"self\">\n\t\t<exec program=\"Coco.exe\">\n\t\t\t<arg value=\"-namespace\" />\n\t\t\t<arg value=\"at.jku.ssw.Coco\" />\n\t\t\t<arg value=\"Coco.atg\" />\n\t\t</exec>\n\t</target>\n\n\t<target name=\"clean\">\n\t\t<delete file=\"Coco.exe\" failonerror=\"false\" />\n\t</target>\n\n\t<target name=\"svn-diff\">\n\t\t<exec program=\"svn\">\n\t\t\t<arg value=\"diff\" />\n\t\t\t<arg value=\"--diff-cmd\" />\n\t\t\t<arg value=\"diff\" />\n\t\t\t<arg value=\"-x\" />\n\t\t\t<arg value=\"-uw\" />\n\t\t</exec>\n\t</target>\n\n</project>\n\n"
  },
  {
    "path": "third_party/Coco/src/Coco.cs",
    "content": "/*-------------------------------------------------------------------------\nCompiler Generator Coco/R,\nCopyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz\nextended by M. Loeberbauer & A. Woess, Univ. of Linz\nwith improvements by Pat Terry, Rhodes University\n\nThis program is free software; you can redistribute it and/or modify it \nunder the terms of the GNU General Public License as published by the \nFree Software Foundation; either version 2, or (at your option) any \nlater version.\n\nThis program is distributed in the hope that it will be useful, but \nWITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY \nor FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License \nfor more details.\n\nYou should have received a copy of the GNU General Public License along \nwith this program; if not, write to the Free Software Foundation, Inc., \n59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n\nAs an exception, it is allowed to write an extension of Coco/R that is\nused as a plugin in non-free software.\n\nIf not otherwise stated, any source code generated by Coco/R (other than \nCoco/R itself) does not fall under the GNU General Public License.\n-------------------------------------------------------------------------*/\n/*-------------------------------------------------------------------------\n  Trace output options\n  0 | A: prints the states of the scanner automaton\n  1 | F: prints the First and Follow sets of all nonterminals\n  2 | G: prints the syntax graph of the productions\n  3 | I: traces the computation of the First sets\n  4 | J: prints the sets associated with ANYs and synchronisation sets\n  6 | S: prints the symbol table (terminals, nonterminals, pragmas)\n  7 | X: prints a cross reference list of all syntax symbols\n  8 | P: prints statistics about the Coco run\n  \n  Trace output can be switched on by the pragma\n    $ { digit | letter }\n  in the attributed grammar or as a command-line option\n  -------------------------------------------------------------------------*/\n\nusing System;\nusing System.IO;\n\nnamespace at.jku.ssw.Coco {\n\npublic class Coco {\n\t\t\n\tpublic static int Main (string[] arg) {\n\t\tConsole.WriteLine(\"Coco/R (Apr 19, 2011)\");\n\t\tstring srcName = null, nsName = null, frameDir = null, ddtString = null,\n\t\ttraceFileName = null, outDir = null;\n\t\tbool emitLines = false;\n\t\tint retVal = 1;\n\t\tfor (int i = 0; i < arg.Length; i++) {\n\t\t\tif (arg[i] == \"-namespace\" && i < arg.Length - 1) nsName = arg[++i].Trim();\n\t\t\telse if (arg[i] == \"-frames\" && i < arg.Length - 1) frameDir = arg[++i].Trim();\n\t\t\telse if (arg[i] == \"-trace\" && i < arg.Length - 1) ddtString = arg[++i].Trim();\n\t\t\telse if (arg[i] == \"-o\" && i < arg.Length - 1) outDir = arg[++i].Trim();\n\t\t\telse if (arg[i] == \"-lines\") emitLines = true;\n\t\t\telse srcName = arg[i];\n\t\t}\n\t\tif (arg.Length > 0 && srcName != null) {\n\t\t\ttry {\n\t\t\t\tstring srcDir = Path.GetDirectoryName(srcName);\n\t\t\t\t\n\t\t\t\tScanner scanner = new Scanner(srcName);\n\t\t\t\tParser parser = new Parser(scanner);\n\n\t\t\t\ttraceFileName = Path.Combine(srcDir, \"trace.txt\");\n\t\t\t\tparser.trace = new StreamWriter(new FileStream(traceFileName, FileMode.Create));\n\t\t\t\tparser.tab = new Tab(parser);\n\t\t\t\tparser.dfa = new DFA(parser);\n\t\t\t\tparser.pgen = new ParserGen(parser);\n\n\t\t\t\tparser.tab.srcName = srcName;\n\t\t\t\tparser.tab.srcDir = srcDir;\n\t\t\t\tparser.tab.nsName = nsName;\n\t\t\t\tparser.tab.frameDir = frameDir;\n\t\t\t\tparser.tab.outDir = (outDir != null) ? outDir : srcDir;\n\t\t\t\tparser.tab.emitLines = emitLines;\n\t\t\t\tif (ddtString != null) parser.tab.SetDDT(ddtString);\n\n\t\t\t\tparser.Parse();\n\n\t\t\t\tparser.trace.Close();\n\t\t\t\tFileInfo f = new FileInfo(traceFileName);\n\t\t\t\tif (f.Length == 0) f.Delete();\n\t\t\t\telse Console.WriteLine(\"trace output is in \" + traceFileName);\n\t\t\t\tConsole.WriteLine(\"{0} errors detected\", parser.errors.count);\n\t\t\t\tif (parser.errors.count == 0) { retVal = 0; }\n\t\t\t} catch (IOException) {\n\t\t\t\tConsole.WriteLine(\"-- could not open \" + traceFileName);\n\t\t\t} catch (FatalError e) {\n\t\t\t\tConsole.WriteLine(\"-- \" + e.Message);\n\t\t\t}\n\t\t} else {\n\t\t\tConsole.WriteLine(\"Usage: Coco Grammar.ATG {{Option}}{0}\"\n\t\t\t                  + \"Options:{0}\"\n\t\t\t                  + \"  -namespace <namespaceName>{0}\"\n\t\t\t                  + \"  -frames    <frameFilesDirectory>{0}\"\n\t\t\t                  + \"  -trace     <traceString>{0}\"\n\t\t\t                  + \"  -o         <outputDirectory>{0}\"\n\t\t\t                  + \"  -lines{0}\"\n\t\t\t                  + \"Valid characters in the trace string:{0}\"\n\t\t\t                  + \"  A  trace automaton{0}\"\n\t\t\t                  + \"  F  list first/follow sets{0}\"\n\t\t\t                  + \"  G  print syntax graph{0}\"\n\t\t\t                  + \"  I  trace computation of first sets{0}\"\n\t\t\t                  + \"  J  list ANY and SYNC sets{0}\"\n\t\t\t                  + \"  P  print statistics{0}\"\n\t\t\t                  + \"  S  list symbol table{0}\"\n\t\t\t                  + \"  X  list cross reference table{0}\"\n\t\t\t                  + \"Scanner.frame and Parser.frame files needed in ATG directory{0}\"\n\t\t\t                  + \"or in a directory specified in the -frames option.\",\n\t\t\t                  Environment.NewLine);\n\t\t}\n\t\treturn retVal;\n\t}\n\t\t\n} // end Coco\n\n} // end namespace\n"
  },
  {
    "path": "third_party/Coco/src/Coco.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <Import Project=\"$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props\" Condition=\"Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')\" />\r\n  <PropertyGroup>\r\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\r\n    <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\r\n    <ProjectGuid>{0E177C54-6936-4965-BFD8-17CEEFCCD630}</ProjectGuid>\r\n    <OutputType>Exe</OutputType>\r\n    <RootNamespace>Coco</RootNamespace>\r\n    <AssemblyName>Coco</AssemblyName>\r\n    <TargetFrameworkVersion>net5.0</TargetFrameworkVersion>\r\n    <FileAlignment>512</FileAlignment>\r\n    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' \">\r\n    <PlatformTarget>AnyCPU</PlatformTarget>\r\n    <DebugSymbols>true</DebugSymbols>\r\n    <DebugType>full</DebugType>\r\n    <Optimize>false</Optimize>\r\n    <OutputPath>..\\bin\\</OutputPath>\r\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <WarningLevel>4</WarningLevel>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' \">\r\n    <PlatformTarget>AnyCPU</PlatformTarget>\r\n    <DebugType>pdbonly</DebugType>\r\n    <Optimize>true</Optimize>\r\n    <OutputPath>bin\\Release\\</OutputPath>\r\n    <DefineConstants>TRACE</DefineConstants>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <WarningLevel>4</WarningLevel>\r\n  </PropertyGroup>\r\n  <ItemGroup>\r\n    <Reference Include=\"System\" />\r\n    <Reference Include=\"Microsoft.CSharp\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Compile Include=\"Coco.cs\" />\r\n    <Compile Include=\"DFA.cs\" />\r\n    <Compile Include=\"Parser.cs\" />\r\n    <Compile Include=\"ParserGen.cs\" />\r\n    <Compile Include=\"Scanner.cs\" />\r\n    <Compile Include=\"Tab.cs\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <None Include=\"App.config\" />\r\n  </ItemGroup>\r\n  <Import Project=\"$(MSBuildToolsPath)\\Microsoft.CSharp.targets\" />\r\n</Project>\r\n"
  },
  {
    "path": "third_party/Coco/src/DFA.cs",
    "content": "/*-------------------------------------------------------------------------\nDFA.cs -- Generation of the Scanner Automaton\nCompiler Generator Coco/R,\nCopyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz\nextended by M. Loeberbauer & A. Woess, Univ. of Linz\nwith improvements by Pat Terry, Rhodes University\n\nThis program is free software; you can redistribute it and/or modify it \nunder the terms of the GNU General Public License as published by the \nFree Software Foundation; either version 2, or (at your option) any \nlater version.\n\nThis program is distributed in the hope that it will be useful, but \nWITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY \nor FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License \nfor more details.\n\nYou should have received a copy of the GNU General Public License along \nwith this program; if not, write to the Free Software Foundation, Inc., \n59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n\nAs an exception, it is allowed to write an extension of Coco/R that is\nused as a plugin in non-free software.\n\nIf not otherwise stated, any source code generated by Coco/R (other than \nCoco/R itself) does not fall under the GNU General Public License.\n-------------------------------------------------------------------------*/\nusing System;\nusing System.IO;\nusing System.Text;\nusing System.Collections;\n\nnamespace at.jku.ssw.Coco {\n\n//-----------------------------------------------------------------------------\n//  State\n//-----------------------------------------------------------------------------\n\npublic class State {\t\t\t\t// state of finite automaton\n\tpublic int nr;\t\t\t\t\t\t// state number\n\tpublic Action firstAction;// to first action of this state\n\tpublic Symbol endOf;\t\t\t// recognized token if state is final\n\tpublic bool ctx;\t\t\t\t\t// true if state is reached via contextTrans\n\tpublic State next;\n\t\n\tpublic void AddAction(Action act) {\n\t\tAction lasta = null, a = firstAction;\n\t\twhile (a != null && act.typ >= a.typ) {lasta = a; a = a.next;}\n\t\t// collecting classes at the beginning gives better performance\n\t\tact.next = a;\n\t\tif (a==firstAction) firstAction = act; else lasta.next = act;\n\t}\n\t\n\tpublic void DetachAction(Action act) {\n\t\tAction lasta = null, a = firstAction;\n\t\twhile (a != null && a != act) {lasta = a; a = a.next;}\n\t\tif (a != null)\n\t\t\tif (a == firstAction) firstAction = a.next; else lasta.next = a.next;\n\t}\n\t\n\tpublic void MeltWith(State s) { // copy actions of s to state\n\t\tfor (Action action = s.firstAction; action != null; action = action.next) {\n\t\t\tAction a = new Action(action.typ, action.sym, action.tc);\n\t\t\ta.AddTargets(action);\n\t\t\tAddAction(a);\n\t\t}\n\t}\n\t\n}\n\n//-----------------------------------------------------------------------------\n//  Action\n//-----------------------------------------------------------------------------\n\npublic class Action {\t\t\t// action of finite automaton\n\tpublic int typ;\t\t\t\t\t// type of action symbol: clas, chr\n\tpublic int sym;\t\t\t\t\t// action symbol\n\tpublic int tc;\t\t\t\t\t// transition code: normalTrans, contextTrans\n\tpublic Target target;\t\t// states reached from this action\n\tpublic Action next;\n\t\n\tpublic Action(int typ, int sym, int tc) {\n\t\tthis.typ = typ; this.sym = sym; this.tc = tc;\n\t}\n\t\n\tpublic void AddTarget(Target t) { // add t to the action.targets\n\t\tTarget last = null;\n\t\tTarget p = target;\n\t\twhile (p != null && t.state.nr >= p.state.nr) {\n\t\t\tif (t.state == p.state) return;\n\t\t\tlast = p; p = p.next;\n\t\t}\n\t\tt.next = p;\n\t\tif (p == target) target = t; else last.next = t;\n\t}\n\n\tpublic void AddTargets(Action a) { // add copy of a.targets to action.targets\n\t\tfor (Target p = a.target; p != null; p = p.next) {\n\t\t\tTarget t = new Target(p.state);\n\t\t\tAddTarget(t);\n\t\t}\n\t\tif (a.tc == Node.contextTrans) tc = Node.contextTrans;\n\t}\n\t\n\tpublic CharSet Symbols(Tab tab) {\n\t\tCharSet s;\n\t\tif (typ == Node.clas)\n\t\t\ts = tab.CharClassSet(sym).Clone();\n\t\telse {\n\t\t\ts = new CharSet(); s.Set(sym);\n\t\t}\n\t\treturn s;\n\t}\n\t\n\tpublic void ShiftWith(CharSet s, Tab tab) {\n\t\tif (s.Elements() == 1) {\n\t\t\ttyp = Node.chr; sym = s.First();\n\t\t} else {\n\t\t\tCharClass c = tab.FindCharClass(s);\n\t\t\tif (c == null) c = tab.NewCharClass(\"#\", s); // class with dummy name\n\t\t\ttyp = Node.clas; sym = c.n;\n\t\t}\n\t}\n\t\n}\n\n//-----------------------------------------------------------------------------\n//  Target\n//-----------------------------------------------------------------------------\n\npublic class Target {\t\t\t\t// set of states that are reached by an action\n\tpublic State state;\t\t\t\t// target state\n\tpublic Target next;\n\t\n\tpublic Target (State s) {\n\t\tstate = s;\n\t}\n}\n\n//-----------------------------------------------------------------------------\n//  Melted\n//-----------------------------------------------------------------------------\n\npublic class Melted {\t\t\t\t\t// info about melted states\n\tpublic BitArray set;\t\t\t\t// set of old states\n\tpublic State state;\t\t\t\t\t// new state\n\tpublic Melted next;\n\t\n\tpublic Melted(BitArray set, State state) {\n\t\tthis.set = set; this.state = state;\n\t}\t\n}\n\n//-----------------------------------------------------------------------------\n//  Comment\n//-----------------------------------------------------------------------------\n\npublic class Comment {\t\t\t\t\t// info about comment syntax\n\tpublic string start;\n\tpublic string stop;\n\tpublic bool nested;\n\tpublic Comment next;\n\t\n\tpublic Comment(string start, string stop, bool nested) {\n\t\tthis.start = start; this.stop = stop; this.nested = nested;\n\t}\n\t\n}\n\n//-----------------------------------------------------------------------------\n//  CharSet\n//-----------------------------------------------------------------------------\n\npublic class CharSet {\n\n\tpublic class Range {\n\t\tpublic int from, to;\n\t\tpublic Range next;\n\t\tpublic Range(int from, int to) { this.from = from; this.to = to; }\n\t}\n\n\tpublic Range head;\n\n\tpublic bool this[int i] {\n\t\tget {\n\t\t\tfor (Range p = head; p != null; p = p.next)\n\t\t\t\tif (i < p.from) return false;\n\t\t\t\telse if (i <= p.to) return true; // p.from <= i <= p.to\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tpublic void Set(int i) {\n\t\tRange cur = head, prev = null;\n\t\twhile (cur != null && i >= cur.from-1) {\n\t\t\tif (i <= cur.to + 1) { // (cur.from-1) <= i <= (cur.to+1)\n\t\t\t\tif (i == cur.from - 1) cur.from--;\n\t\t\t\telse if (i == cur.to + 1) {\n\t\t\t\t\tcur.to++;\n\t\t\t\t\tRange next = cur.next;\n\t\t\t\t\tif (next != null && cur.to == next.from - 1) { cur.to = next.to; cur.next = next.next; };\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tprev = cur; cur = cur.next;\n\t\t}\n\t\tRange n = new Range(i, i);\n\t\tn.next = cur;\n\t\tif (prev == null) head = n; else prev.next = n;\n\t}\n\n\tpublic CharSet Clone() {\n\t\tCharSet s = new CharSet();\n\t\tRange prev = null;\n\t\tfor (Range cur = head; cur != null; cur = cur.next) {\n\t\t\tRange r = new Range(cur.from, cur.to);\n\t\t\tif (prev == null) s.head = r; else prev.next = r;\n\t\t\tprev = r;\n\t\t}\n\t\treturn s;\n\t}\n\n\tpublic bool Equals(CharSet s) {\n\t\tRange p = head, q = s.head;\n\t\twhile (p != null && q != null) {\n\t\t\tif (p.from != q.from || p.to != q.to) return false;\n\t\t\tp = p.next; q = q.next;\n\t\t}\n\t\treturn p == q;\n\t}\n\n\tpublic int Elements() {\n\t\tint n = 0;\n\t\tfor (Range p = head; p != null; p = p.next) n += p.to - p.from + 1;\n\t\treturn n;\n\t}\n\n\tpublic int First() {\n\t\tif (head != null) return head.from;\n\t\treturn -1;\n\t}\n\n\tpublic void Or(CharSet s) {\n\t\tfor (Range p = s.head; p != null; p = p.next)\n\t\t\tfor (int i = p.from; i <= p.to; i++) Set(i);\n\t}\n\n\tpublic void And(CharSet s) {\n\t\tCharSet x = new CharSet();\n\t\tfor (Range p = head; p != null; p = p.next)\n\t\t\tfor (int i = p.from; i <= p.to; i++)\n\t\t\t\tif (s[i]) x.Set(i);\n\t\thead = x.head;\n\t}\n\n\tpublic void Subtract(CharSet s) {\n\t\tCharSet x = new CharSet();\n\t\tfor (Range p = head; p != null; p = p.next)\n\t\t\tfor (int i = p.from; i <= p.to; i++)\n\t\t\t\tif (!s[i]) x.Set(i);\n\t\thead = x.head;\n\t}\n\n\tpublic bool Includes(CharSet s) {\n\t\tfor (Range p = s.head; p != null; p = p.next)\n\t\t\tfor (int i = p.from; i <= p.to; i++)\n\t\t\t\tif (!this[i]) return false;\n\t\treturn true;\n\t}\n\n\tpublic bool Intersects(CharSet s) {\n\t\tfor (Range p = s.head; p != null; p = p.next)\n\t\t\tfor (int i = p.from; i <= p.to; i++)\n\t\t\t\tif (this[i]) return true;\n\t\treturn false;\n\t}\n\n\tpublic void Fill() {\n\t\thead = new Range(Char.MinValue, Char.MaxValue);\n\t}\n}\n\n\n//-----------------------------------------------------------------------------\n//  Generator\n//-----------------------------------------------------------------------------\nclass Generator {\n\tprivate const int EOF = -1;\n\n\tprivate FileStream fram;\n\tprivate StreamWriter gen;\n\tprivate readonly Tab tab;\n\tprivate string frameFile;\n\n\tpublic Generator(Tab tab) {\n\t\tthis.tab = tab;\n\t}\n\n\tpublic FileStream OpenFrame(String frame) {\n\t\tif (tab.frameDir != null) frameFile = Path.Combine(tab.frameDir, frame);\n\t\tif (frameFile == null || !File.Exists(frameFile)) frameFile = Path.Combine(tab.srcDir, frame);\n\t\tif (frameFile == null || !File.Exists(frameFile)) throw new FatalError(\"Cannot find : \" + frame);\n\n\t\ttry {\n\t\t\tfram = new FileStream(frameFile, FileMode.Open, FileAccess.Read, FileShare.Read);\n\t\t} catch (FileNotFoundException) {\n\t\t\tthrow new FatalError(\"Cannot open frame file: \" + frameFile);\n\t\t}\n\t\treturn fram;\n\t}\n\n\n\n\tpublic StreamWriter OpenGen(string target) {\n\t\tstring fn = Path.Combine(tab.outDir, target);\n\t\ttry {\n\t\t\tif (File.Exists(fn)) File.Copy(fn, fn + \".old\", true);\n\t\t\tgen = new StreamWriter(new FileStream(fn, FileMode.Create)); /* pdt */\n\t\t} catch (IOException) {\n\t\t\tthrow new FatalError(\"Cannot generate file: \" + fn);\n\t\t}\n\t\treturn gen;\n\t}\n\n\n\tpublic void GenCopyright() {\n\t\tstring copyFr = null;\n\t\tif (tab.frameDir != null) copyFr = Path.Combine(tab.frameDir, \"Copyright.frame\");\n\t\tif (copyFr == null || !File.Exists(copyFr)) copyFr = Path.Combine(tab.srcDir, \"Copyright.frame\");\n\t\tif (copyFr == null || !File.Exists(copyFr)) return;\n\n\t\ttry {\n\t\t\tFileStream scannerFram = fram;\n\t\t\tfram = new FileStream(copyFr, FileMode.Open, FileAccess.Read, FileShare.Read);\n\t\t\tCopyFramePart(null);\n\t\t\tfram = scannerFram;\n\t\t} catch (FileNotFoundException) {\n\t\t\tthrow new FatalError(\"Cannot open Copyright.frame\");\n\t\t}\n\t}\n\n\tpublic void SkipFramePart(String stop) {\n\t\tCopyFramePart(stop, false);\n\t}\n\n\n\tpublic void CopyFramePart(String stop) {\n\t\tCopyFramePart(stop, true);\n\t}\n\n\t// if stop == null, copies until end of file\n\tprivate void CopyFramePart(string stop, bool generateOutput) {\n\t\tchar startCh = (char) 0;\n\t\tint endOfStopString = 0;\n\n\t\tif (stop != null) {\n\t\t\tstartCh = stop[0];\n\t\t\tendOfStopString = stop.Length - 1;\n\t\t}\n\n\t\tint ch = framRead();\n\t\twhile (ch != EOF) {\n\t\t\tif (stop != null && ch == startCh) {\n\t\t\t\tint i = 0;\n\t\t\t\tdo {\n\t\t\t\t\tif (i == endOfStopString) return; // stop[0..i] found\n\t\t\t\t\tch = framRead(); i++;\n\t\t\t\t} while (ch == stop[i]);\n\t\t\t\t// stop[0..i-1] found; continue with last read character\n\t\t\t\tif (generateOutput) gen.Write(stop.Substring(0, i));\n\t\t\t} else {\n\t\t\t\tif (generateOutput) gen.Write((char) ch);\n\t\t\t\tch = framRead();\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (stop != null) throw new FatalError(\"Incomplete or corrupt frame file: \" + frameFile);\n\t}\n\n\tprivate int framRead() {\n\t\ttry {\n\t\t\treturn fram.ReadByte();\n\t\t} catch (Exception) {\n\t\t\tthrow new FatalError(\"Error reading frame file: \" + frameFile);\n\t\t}\n\t}\n}\n\n//-----------------------------------------------------------------------------\n//  DFA\n//-----------------------------------------------------------------------------\n\npublic class DFA {\n\tprivate int maxStates;\n\tprivate int lastStateNr;   // highest state number\n\tprivate State firstState;\n\tprivate State lastState;   // last allocated state\n\tprivate int lastSimState;  // last non melted state\n\tprivate FileStream fram;   // scanner frame input\n\tprivate StreamWriter gen;  // generated scanner file\n\tprivate Symbol curSy;      // current token to be recognized (in FindTrans)\n\tprivate bool dirtyDFA;     // DFA may become nondeterministic in MatchLiteral\n\n\tpublic bool ignoreCase;   // true if input should be treated case-insensitively\n\tpublic bool hasCtxMoves;  // DFA has context transitions\n\t\n\t// other Coco objects\n\tprivate Parser     parser;\n\tprivate Tab        tab;\n\tprivate Errors     errors;\n\tprivate TextWriter trace;\n\n\t//---------- Output primitives\n\tprivate string Ch(int ch) {\n\t\tif (ch < ' ' || ch >= 127 || ch == '\\'' || ch == '\\\\') return Convert.ToString(ch);\n\t\telse return String.Format(\"'{0}'\", (char)ch);\n\t}\n\t\n\tprivate string ChCond(char ch) {\n\t\treturn String.Format(\"ch == {0}\", Ch(ch));\n\t}\n\t\n\tprivate void PutRange(CharSet s) {\n\t\tfor (CharSet.Range r = s.head; r != null; r = r.next) {\n\t\t\tif (r.from == r.to) { gen.Write(\"ch == \" + Ch(r.from)); }\n\t\t\telse if (r.from == 0) { gen.Write(\"ch <= \" + Ch(r.to)); }\n\t\t\telse { gen.Write(\"ch >= \" + Ch(r.from) + \" && ch <= \" + Ch(r.to)); }\n\t\t\tif (r.next != null) gen.Write(\" || \");\n\t\t}\n\t}\n\t\n\t//---------- State handling\n\t\n\tState NewState() {\n\t\tState s = new State(); s.nr = ++lastStateNr;\n\t\tif (firstState == null) firstState = s; else lastState.next = s;\n\t\tlastState = s;\n\t\treturn s;\n\t}\n\t\n\tvoid NewTransition(State from, State to, int typ, int sym, int tc) {\n\t\tTarget t = new Target(to);\n\t\tAction a = new Action(typ, sym, tc); a.target = t;\n\t\tfrom.AddAction(a);\n\t\tif (typ == Node.clas) curSy.tokenKind = Symbol.classToken;\n\t}\n\t\n\tvoid CombineShifts() {\n\t\tState state;\n\t\tAction a, b, c;\n\t\tCharSet seta, setb;\n\t\tfor (state = firstState; state != null; state = state.next) {\n\t\t\tfor (a = state.firstAction; a != null; a = a.next) {\n\t\t\t\tb = a.next;\n\t\t\t\twhile (b != null)\n\t\t\t\t\tif (a.target.state == b.target.state && a.tc == b.tc) {\n\t\t\t\t\t\tseta = a.Symbols(tab); setb = b.Symbols(tab);\n\t\t\t\t\t\tseta.Or(setb);\n\t\t\t\t\t\ta.ShiftWith(seta, tab);\n\t\t\t\t\t\tc = b; b = b.next; state.DetachAction(c);\n\t\t\t\t\t} else b = b.next;\n\t\t\t}\n\t\t}\n\t}\n\t\n\tvoid FindUsedStates(State state, BitArray used) {\n\t\tif (used[state.nr]) return;\n\t\tused[state.nr] = true;\n\t\tfor (Action a = state.firstAction; a != null; a = a.next)\n\t\t\tFindUsedStates(a.target.state, used);\n\t}\n\t\n\tvoid DeleteRedundantStates() {\n\t\tState[] newState = new State[lastStateNr + 1];\n\t\tBitArray used = new BitArray(lastStateNr + 1);\n\t\tFindUsedStates(firstState, used);\n\t\t// combine equal final states\n\t\tfor (State s1 = firstState.next; s1 != null; s1 = s1.next) // firstState cannot be final\n\t\t\tif (used[s1.nr] && s1.endOf != null && s1.firstAction == null && !s1.ctx)\n\t\t\t\tfor (State s2 = s1.next; s2 != null; s2 = s2.next)\n\t\t\t\t\tif (used[s2.nr] && s1.endOf == s2.endOf && s2.firstAction == null & !s2.ctx) {\n\t\t\t\t\t\tused[s2.nr] = false; newState[s2.nr] = s1;\n\t\t\t\t\t}\n\t\tfor (State state = firstState; state != null; state = state.next)\n\t\t\tif (used[state.nr])\n\t\t\t\tfor (Action a = state.firstAction; a != null; a = a.next)\n\t\t\t\t\tif (!used[a.target.state.nr])\n\t\t\t\t\t\ta.target.state = newState[a.target.state.nr];\n\t\t// delete unused states\n\t\tlastState = firstState; lastStateNr = 0; // firstState has number 0\n\t\tfor (State state = firstState.next; state != null; state = state.next)\n\t\t\tif (used[state.nr]) {state.nr = ++lastStateNr; lastState = state;}\n\t\t\telse lastState.next = state.next;\n\t}\n\t\n\tState TheState(Node p) {\n\t\tState state;\n\t\tif (p == null) {state = NewState(); state.endOf = curSy; return state;}\n\t\telse return p.state;\n\t}\n\t\n\tvoid Step(State from, Node p, BitArray stepped) {\n\t\tif (p == null) return;\n\t\tstepped[p.n] = true;\n\t\tswitch (p.typ) {\n\t\t\tcase Node.clas: case Node.chr: {\n\t\t\t\tNewTransition(from, TheState(p.next), p.typ, p.val, p.code);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase Node.alt: {\n\t\t\t\tStep(from, p.sub, stepped); Step(from, p.down, stepped);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase Node.iter: {\n\t\t\t\tif (Tab.DelSubGraph(p.sub)) {\n\t\t\t\t\tparser.SemErr(\"contents of {...} must not be deletable\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (p.next != null && !stepped[p.next.n]) Step(from, p.next, stepped);\n\t\t\t\tStep(from, p.sub, stepped);\n\t\t\t\tif (p.state != from) {\n\t\t\t\t\tStep(p.state, p, new BitArray(tab.nodes.Count));\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase Node.opt: {\n\t\t\t\tif (p.next != null && !stepped[p.next.n]) Step(from, p.next, stepped);\n\t\t\t\tStep(from, p.sub, stepped);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Assigns a state n.state to every node n. There will be a transition from\n\t// n.state to n.next.state triggered by n.val. All nodes in an alternative\n\t// chain are represented by the same state.\n\t// Numbering scheme:\n\t//  - any node after a chr, clas, opt, or alt, must get a new number\n\t//  - if a nested structure starts with an iteration the iter node must get a new number\n\t//  - if an iteration follows an iteration, it must get a new number\n\tvoid NumberNodes(Node p, State state, bool renumIter) {\n\t\tif (p == null) return;\n\t\tif (p.state != null) return; // already visited;\n\t\tif (state == null || (p.typ == Node.iter && renumIter)) state = NewState();\n\t\tp.state = state;\n\t\tif (Tab.DelGraph(p)) state.endOf = curSy;\n\t\tswitch (p.typ) {\n\t\t\tcase Node.clas: case Node.chr: {\n\t\t\t\tNumberNodes(p.next, null, false);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase Node.opt: {\n\t\t\t\tNumberNodes(p.next, null, false);\n\t\t\t\tNumberNodes(p.sub, state, true);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase Node.iter: {\n\t\t\t\tNumberNodes(p.next, state, true);\n\t\t\t\tNumberNodes(p.sub, state, true);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase Node.alt: {\n\t\t\t\tNumberNodes(p.next, null, false);\n\t\t\t\tNumberNodes(p.sub, state, true);\n\t\t\t\tNumberNodes(p.down, state, renumIter);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\t\n\tvoid FindTrans (Node p, bool start, BitArray marked) {\n\t\tif (p == null || marked[p.n]) return;\n\t\tmarked[p.n] = true;\n\t\tif (start) Step(p.state, p, new BitArray(tab.nodes.Count)); // start of group of equally numbered nodes\n\t\tswitch (p.typ) {\n\t\t\tcase Node.clas: case Node.chr: {\n\t\t\t\tFindTrans(p.next, true, marked);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase Node.opt: {\n\t\t\t\tFindTrans(p.next, true, marked); FindTrans(p.sub, false, marked);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase Node.iter: {\n\t\t\t\tFindTrans(p.next, false, marked); FindTrans(p.sub, false, marked);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase Node.alt: {\n\t\t\t\tFindTrans(p.sub, false, marked); FindTrans(p.down, false, marked);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\t\n\tpublic void ConvertToStates(Node p, Symbol sym) {\n\t\tcurSy = sym;\n\t\tif (Tab.DelGraph(p)) {\n\t\t\tparser.SemErr(\"token might be empty\");\n\t\t\treturn;\n\t\t}\n\t\tNumberNodes(p, firstState, true);\n\t\tFindTrans(p, true, new BitArray(tab.nodes.Count));\n\t\tif (p.typ == Node.iter) {\n\t\t\tStep(firstState, p, new BitArray(tab.nodes.Count));\n\t\t}\n\t}\n\t\n\t// match string against current automaton; store it either as a fixedToken or as a litToken\n\tpublic void MatchLiteral(string s, Symbol sym) {\n\t\ts = tab.Unescape(s.Substring(1, s.Length-2));\n\t\tint i, len = s.Length;\n\t\tState state = firstState;\n\t\tAction a = null;\n\t\tfor (i = 0; i < len; i++) { // try to match s against existing DFA\n\t\t\ta = FindAction(state, s[i]);\n\t\t\tif (a == null) break;\n\t\t\tstate = a.target.state;\n\t\t}\n\t\t// if s was not totally consumed or leads to a non-final state => make new DFA from it\n\t\tif (i != len || state.endOf == null) {\n\t\t\tstate = firstState; i = 0; a = null;\n\t\t\tdirtyDFA = true;\n\t\t}\n\t\tfor (; i < len; i++) { // make new DFA for s[i..len-1], ML: i is either 0 or len\n\t\t\tState to = NewState();\n\t\t\tNewTransition(state, to, Node.chr, s[i], Node.normalTrans);\n\t\t\tstate = to;\n\t\t}\n\t\tSymbol matchedSym = state.endOf;\n\t\tif (state.endOf == null) {\n\t\t\tstate.endOf = sym;\n\t\t} else if (matchedSym.tokenKind == Symbol.fixedToken || (a != null && a.tc == Node.contextTrans)) {\n\t\t\t// s matched a token with a fixed definition or a token with an appendix that will be cut off\n\t\t\tparser.SemErr(\"tokens \" + sym.name + \" and \" + matchedSym.name + \" cannot be distinguished\");\n\t\t} else { // matchedSym == classToken || classLitToken\n\t\t\tmatchedSym.tokenKind = Symbol.classLitToken;\n\t\t\tsym.tokenKind = Symbol.litToken;\n\t\t}\n\t}\n\t\n\tvoid SplitActions(State state, Action a, Action b) {\n\t\tAction c; CharSet seta, setb, setc;\n\t\tseta = a.Symbols(tab); setb = b.Symbols(tab);\n\t\tif (seta.Equals(setb)) {\n\t\t\ta.AddTargets(b);\n\t\t\tstate.DetachAction(b);\n\t\t} else if (seta.Includes(setb)) {\n\t\t\tsetc = seta.Clone(); setc.Subtract(setb);\n\t\t\tb.AddTargets(a);\n\t\t\ta.ShiftWith(setc, tab);\n\t\t} else if (setb.Includes(seta)) {\n\t\t\tsetc = setb.Clone(); setc.Subtract(seta);\n\t\t\ta.AddTargets(b);\n\t\t\tb.ShiftWith(setc, tab);\n\t\t} else {\n\t\t\tsetc = seta.Clone(); setc.And(setb);\n\t\t\tseta.Subtract(setc);\n\t\t\tsetb.Subtract(setc);\n\t\t\ta.ShiftWith(seta, tab);\n\t\t\tb.ShiftWith(setb, tab);\n\t\t\tc = new Action(0, 0, Node.normalTrans);  // typ and sym are set in ShiftWith\n\t\t\tc.AddTargets(a);\n\t\t\tc.AddTargets(b);\n\t\t\tc.ShiftWith(setc, tab);\n\t\t\tstate.AddAction(c);\n\t\t}\n\t}\n\t\n\tbool Overlap(Action a, Action b) {\n\t\tCharSet seta, setb;\n\t\tif (a.typ == Node.chr)\n\t\t\tif (b.typ == Node.chr) return a.sym == b.sym;\n\t\t\telse {setb = tab.CharClassSet(b.sym); return setb[a.sym];}\n\t\telse {\n\t\t\tseta = tab.CharClassSet(a.sym);\n\t\t\tif (b.typ == Node.chr) return seta[b.sym];\n\t\t\telse {setb = tab.CharClassSet(b.sym); return seta.Intersects(setb);}\n\t\t}\n\t}\n\t\n\tvoid MakeUnique(State state) {\n\t\tbool changed;\n\t\tdo {\n\t\t\tchanged = false;\n\t\t\tfor (Action a = state.firstAction; a != null; a = a.next)\n\t\t\t\tfor (Action b = a.next; b != null; b = b.next)\n\t\t\t\t\tif (Overlap(a, b)) { SplitActions(state, a, b); changed = true; }\n\t\t} while (changed);\n\t}\n\t\n\tvoid MeltStates(State state) {\n\t\tbool ctx;\n\t\tBitArray targets;\n\t\tSymbol endOf;\n\t\tfor (Action action = state.firstAction; action != null; action = action.next) {\n\t\t\tif (action.target.next != null) {\n\t\t\t\tGetTargetStates(action, out targets, out endOf, out ctx);\n\t\t\t\tMelted melt = StateWithSet(targets);\n\t\t\t\tif (melt == null) {\n\t\t\t\t\tState s = NewState(); s.endOf = endOf; s.ctx = ctx;\n\t\t\t\t\tfor (Target targ = action.target; targ != null; targ = targ.next)\n\t\t\t\t\t\ts.MeltWith(targ.state);\n\t\t\t\t\tMakeUnique(s);\n\t\t\t\t\tmelt = NewMelted(targets, s);\n\t\t\t\t}\n\t\t\t\taction.target.next = null;\n\t\t\t\taction.target.state = melt.state;\n\t\t\t}\n\t\t}\n\t}\n\t\n\tvoid FindCtxStates() {\n\t\tfor (State state = firstState; state != null; state = state.next)\n\t\t\tfor (Action a = state.firstAction; a != null; a = a.next)\n\t\t\t\tif (a.tc == Node.contextTrans) a.target.state.ctx = true;\n\t}\n\t\n\tpublic void MakeDeterministic() {\n\t\tState state;\n\t\tlastSimState = lastState.nr;\n\t\tmaxStates = 2 * lastSimState; // heuristic for set size in Melted.set\n\t\tFindCtxStates();\n\t\tfor (state = firstState; state != null; state = state.next)\n\t\t\tMakeUnique(state);\n\t\tfor (state = firstState; state != null; state = state.next)\n\t\t\tMeltStates(state);\n\t\tDeleteRedundantStates();\n\t\tCombineShifts();\n\t}\n\t\n\tpublic void PrintStates() {\n\t\ttrace.WriteLine();\n\t\ttrace.WriteLine(\"---------- states ----------\");\n\t\tfor (State state = firstState; state != null; state = state.next) {\n\t\t\tbool first = true;\n\t\t\tif (state.endOf == null) trace.Write(\"               \");\n\t\t\telse trace.Write(\"E({0,12})\", tab.Name(state.endOf.name));\n\t\t\ttrace.Write(\"{0,3}:\", state.nr);\n\t\t\tif (state.firstAction == null) trace.WriteLine();\n\t\t\tfor (Action action = state.firstAction; action != null; action = action.next) {\n\t\t\t\tif (first) {trace.Write(\" \"); first = false;} else trace.Write(\"                    \");\n\t\t\t\tif (action.typ == Node.clas) trace.Write(((CharClass)tab.classes[action.sym]).name);\n\t\t\t\telse trace.Write(\"{0, 3}\", Ch(action.sym));\n\t\t\t\tfor (Target targ = action.target; targ != null; targ = targ.next)\n\t\t\t\t\ttrace.Write(\" {0, 3}\", targ.state.nr);\n\t\t\t\tif (action.tc == Node.contextTrans) trace.WriteLine(\" context\"); else trace.WriteLine();\n\t\t\t}\n\t\t}\n\t\ttrace.WriteLine();\n\t\ttrace.WriteLine(\"---------- character classes ----------\");\n\t\ttab.WriteCharClasses();\n\t}\n\t\n//---------------------------- actions --------------------------------\n\n\tpublic Action FindAction(State state, char ch) {\n\t\tfor (Action a = state.firstAction; a != null; a = a.next)\n\t\t\tif (a.typ == Node.chr && ch == a.sym) return a;\n\t\t\telse if (a.typ == Node.clas) {\n\t\t\t\tCharSet s = tab.CharClassSet(a.sym);\n\t\t\t\tif (s[ch]) return a;\n\t\t\t}\n\t\treturn null;\n\t}\n\t\n\tpublic void GetTargetStates(Action a, out BitArray targets, out Symbol endOf, out bool ctx) { \n\t\t// compute the set of target states\n\t\ttargets = new BitArray(maxStates); endOf = null;\n\t\tctx = false;\n\t\tfor (Target t = a.target; t != null; t = t.next) {\n\t\t\tint stateNr = t.state.nr;\n\t\t\tif (stateNr <= lastSimState) targets[stateNr] = true;\n\t\t\telse targets.Or(MeltedSet(stateNr));\n\t\t\tif (t.state.endOf != null)\n\t\t\t\tif (endOf == null || endOf == t.state.endOf)\n\t\t\t\t\tendOf = t.state.endOf;\n\t\t\t\telse\n\t\t\t\t\terrors.SemErr(\"Tokens \" + endOf.name + \" and \" + t.state.endOf.name + \" cannot be distinguished\");\n\t\t\tif (t.state.ctx) {\n\t\t\t\tctx = true;\n\t\t\t\t// The following check seems to be unnecessary. It reported an error\n\t\t\t\t// if a symbol + context was the prefix of another symbol, e.g.\n\t\t\t\t//   s1 = \"a\" \"b\" \"c\".\n\t\t\t\t//   s2 = \"a\" CONTEXT(\"b\").\n\t\t\t\t// But this is ok.\n\t\t\t\t// if (t.state.endOf != null) {\n\t\t\t\t//   Console.WriteLine(\"Ambiguous context clause\");\n\t\t\t\t//\t errors.count++;\n\t\t\t\t// }\n\t\t\t}\n\t\t}\n\t}\n\t\n//------------------------- melted states ------------------------------\n\n\tMelted firstMelted;\t// head of melted state list\n\t\n\tMelted NewMelted(BitArray set, State state) {\n\t\tMelted m = new Melted(set, state);\n\t\tm.next = firstMelted; firstMelted = m;\n\t\treturn m;\n\t}\n\t\n\tBitArray MeltedSet(int nr) {\n\t\tMelted m = firstMelted;\n\t\twhile (m != null) {\n\t\t\tif (m.state.nr == nr) return m.set; else m = m.next;\n\t\t}\n\t\tthrow new FatalError(\"compiler error in Melted.Set\");\n\t}\n\n\tMelted StateWithSet(BitArray s) {\n\t\tfor (Melted m = firstMelted; m != null; m = m.next)\n\t\t\tif (Sets.Equals(s, m.set)) return m;\n\t\treturn null;\n\t}\n\n//------------------------ comments --------------------------------\n\n\tpublic Comment firstComment;\t// list of comments\n\n\tstring CommentStr(Node p) {\n\t\tStringBuilder s = new StringBuilder();\n\t\twhile (p != null) {\n\t\t\tif (p.typ == Node.chr) {\n\t\t\t\ts.Append((char)p.val);\n\t\t\t} else if (p.typ == Node.clas) {\n\t\t\t\tCharSet set = tab.CharClassSet(p.val);\n\t\t\t\tif (set.Elements() != 1) parser.SemErr(\"character set contains more than 1 character\");\n\t\t\t\ts.Append((char)set.First());\n\t\t\t} else parser.SemErr(\"comment delimiters may not be structured\");\n\t\t\tp = p.next;\n\t\t}\n\t\tif (s.Length == 0 || s.Length > 2) {\n\t\t\tparser.SemErr(\"comment delimiters must be 1 or 2 characters long\");\n\t\t\ts = new StringBuilder(\"?\");\n\t\t}\n\t\treturn s.ToString();\n\t}\n\t\n\tpublic void NewComment(Node from, Node to, bool nested) {\n\t\tComment c = new Comment(CommentStr(from), CommentStr(to), nested);\n\t\tc.next = firstComment; firstComment = c;\n\t}\n\n\n//------------------------ scanner generation ----------------------\n\n\tvoid GenComBody(Comment com) {\n\t\tgen.WriteLine(  \"\\t\\t\\tfor(;;) {\");\n\t\tgen.Write    (  \"\\t\\t\\t\\tif ({0}) \", ChCond(com.stop[0])); gen.WriteLine(\"{\");\n\t\tif (com.stop.Length == 1) {\n\t\t\tgen.WriteLine(\"\\t\\t\\t\\t\\tlevel--;\");\n\t\t\tgen.WriteLine(\"\\t\\t\\t\\t\\tif (level == 0) { oldEols = line - line0; NextCh(); return true; }\");\n\t\t\tgen.WriteLine(\"\\t\\t\\t\\t\\tNextCh();\");\n\t\t} else {\n\t\t\tgen.WriteLine(\"\\t\\t\\t\\t\\tNextCh();\");\n\t\t\tgen.WriteLine(\"\\t\\t\\t\\t\\tif ({0}) {{\", ChCond(com.stop[1]));\n\t\t\tgen.WriteLine(\"\\t\\t\\t\\t\\t\\tlevel--;\");\n\t\t\tgen.WriteLine(\"\\t\\t\\t\\t\\t\\tif (level == 0) { oldEols = line - line0; NextCh(); return true; }\");\n\t\t\tgen.WriteLine(\"\\t\\t\\t\\t\\t\\tNextCh();\");\n\t\t\tgen.WriteLine(\"\\t\\t\\t\\t\\t}\");\n\t\t}\n\t\tif (com.nested) {\n\t\t\tgen.Write    (\"\\t\\t\\t\\t}\"); gen.Write(\" else if ({0}) \", ChCond(com.start[0])); gen.WriteLine(\"{\");\n\t\t\tif (com.start.Length == 1)\n\t\t\t\tgen.WriteLine(\"\\t\\t\\t\\t\\tlevel++; NextCh();\");\n\t\t\telse {\n\t\t\t\tgen.WriteLine(\"\\t\\t\\t\\t\\tNextCh();\");\n\t\t\t\tgen.Write    (\"\\t\\t\\t\\t\\tif ({0}) \", ChCond(com.start[1])); gen.WriteLine(\"{\");\n\t\t\t\tgen.WriteLine(\"\\t\\t\\t\\t\\t\\tlevel++; NextCh();\");\n\t\t\t\tgen.WriteLine(\"\\t\\t\\t\\t\\t}\");\n\t\t\t}\n\t\t}\n\t\tgen.WriteLine(    \"\\t\\t\\t\\t} else if (ch == Buffer.EOF) return false;\");\n\t\tgen.WriteLine(    \"\\t\\t\\t\\telse NextCh();\");\n\t\tgen.WriteLine(    \"\\t\\t\\t}\");\n\t}\n\t\n\tvoid GenComment(Comment com, int i) {\n\t\tgen.WriteLine();\n\t\tgen.Write    (\"\\tbool Comment{0}() \", i); gen.WriteLine(\"{\");\n\t\tgen.WriteLine(\"\\t\\tint level = 1, pos0 = pos, line0 = line, col0 = col, charPos0 = charPos;\");\n\t\tif (com.start.Length == 1) {\n\t\t\tgen.WriteLine(\"\\t\\tNextCh();\");\n\t\t\tGenComBody(com);\n\t\t} else {\n\t\t\tgen.WriteLine(\"\\t\\tNextCh();\");\n\t\t\tgen.Write    (\"\\t\\tif ({0}) \", ChCond(com.start[1])); gen.WriteLine(\"{\");\n\t\t\tgen.WriteLine(\"\\t\\t\\tNextCh();\");\n\t\t\tGenComBody(com);\n\t\t\tgen.WriteLine(\"\\t\\t} else {\");\n\t\t\tgen.WriteLine(\"\\t\\t\\tbuffer.Pos = pos0; NextCh(); line = line0; col = col0; charPos = charPos0;\");\n\t\t\tgen.WriteLine(\"\\t\\t}\");\n\t\t\tgen.WriteLine(\"\\t\\treturn false;\");\n\t\t}\n\t\tgen.WriteLine(\"\\t}\");\n\t}\n\t\n\tstring SymName(Symbol sym) {\n\t\tif (Char.IsLetter(sym.name[0])) { // real name value is stored in Tab.literals\n\t\t\tforeach (DictionaryEntry e in tab.literals)\n\t\t\t\tif ((Symbol)e.Value == sym) return (string)e.Key;\n\t\t}\n\t\treturn sym.name;\n\t}\n\t\n\tvoid GenLiterals () {\n\t\tif (ignoreCase) {\n\t\t\tgen.WriteLine(\"\\t\\tswitch (t.val.ToLower()) {\");\n\t\t} else {\n\t\t\tgen.WriteLine(\"\\t\\tswitch (t.val) {\");\n\t\t}\n\t\tforeach (IList ts in new IList[] { tab.terminals, tab.pragmas }) {\n\t\t\tforeach (Symbol sym in ts) {\n\t\t\t\tif (sym.tokenKind == Symbol.litToken) {\n\t\t\t\t\tstring name = SymName(sym);\n\t\t\t\t\tif (ignoreCase) name = name.ToLower();\n\t\t\t\t\t// sym.name stores literals with quotes, e.g. \"\\\"Literal\\\"\"\n\t\t\t\t\tgen.WriteLine(\"\\t\\t\\tcase {0}: t.kind = {1}; break;\", name, sym.n);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tgen.WriteLine(\"\\t\\t\\tdefault: break;\");\n\t\tgen.Write(\"\\t\\t}\");\n\t}\n\t\n\tvoid WriteState(State state) {\n\t\tSymbol endOf = state.endOf;\n\t\tgen.WriteLine(\"\\t\\t\\tcase {0}:\", state.nr);\n\t\tif (endOf != null && state.firstAction != null) {\n\t\t\tgen.WriteLine(\"\\t\\t\\t\\trecEnd = pos; recKind = {0};\", endOf.n);\n\t\t}\n\t\tbool ctxEnd = state.ctx;\n\t\tfor (Action action = state.firstAction; action != null; action = action.next) {\n\t\t\tif (action == state.firstAction) gen.Write(\"\\t\\t\\t\\tif (\");\n\t\t\telse gen.Write(\"\\t\\t\\t\\telse if (\");\n\t\t\tif (action.typ == Node.chr) gen.Write(ChCond((char)action.sym));\n\t\t\telse PutRange(tab.CharClassSet(action.sym));\n\t\t\tgen.Write(\") {\");\n\t\t\tif (action.tc == Node.contextTrans) {\n\t\t\t\tgen.Write(\"apx++; \"); ctxEnd = false;\n\t\t\t} else if (state.ctx)\n\t\t\t\tgen.Write(\"apx = 0; \");\n\t\t\tgen.Write(\"AddCh(); goto case {0};\", action.target.state.nr);\n\t\t\tgen.WriteLine(\"}\");\n\t\t}\n\t\tif (state.firstAction == null)\n\t\t\tgen.Write(\"\\t\\t\\t\\t{\");\n\t\telse\n\t\t\tgen.Write(\"\\t\\t\\t\\telse {\");\n\t\tif (ctxEnd) { // final context state: cut appendix\n\t\t\tgen.WriteLine();\n\t\t\tgen.WriteLine(\"\\t\\t\\t\\t\\ttlen -= apx;\");\n\t\t\tgen.WriteLine(\"\\t\\t\\t\\t\\tSetScannerBehindT();\");\n\t\t\tgen.Write(\"\\t\\t\\t\\t\\t\");\n\t\t}\n\t\tif (endOf == null) {\n\t\t\tgen.WriteLine(\"goto case 0;}\");\n\t\t} else {\n\t\t\tgen.Write(\"t.kind = {0}; \", endOf.n);\n\t\t\tif (endOf.tokenKind == Symbol.classLitToken) {\n\t\t\t\tgen.WriteLine(\"t.val = new String(tval, 0, tlen); CheckLiteral(); return t;}\");\n\t\t\t} else {\n\t\t\t\tgen.WriteLine(\"break;}\");\n\t\t\t}\n\t\t}\n\t}\n\t\n\tvoid WriteStartTab() {\n\t\tfor (Action action = firstState.firstAction; action != null; action = action.next) {\n\t\t\tint targetState = action.target.state.nr;\n\t\t\tif (action.typ == Node.chr) {\n\t\t\t\tgen.WriteLine(\"\\t\\tstart[\" + action.sym + \"] = \" + targetState + \"; \");\n\t\t\t} else {\n\t\t\t\tCharSet s = tab.CharClassSet(action.sym);\n\t\t\t\tfor (CharSet.Range r = s.head; r != null; r = r.next) {\n\t\t\t\t\tgen.WriteLine(\"\\t\\tfor (int i = \" + r.from + \"; i <= \" + r.to + \"; ++i) start[i] = \" + targetState + \";\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tgen.WriteLine(\"\\t\\tstart[Buffer.EOF] = -1;\");\n\t}\n\n\tpublic void WriteScanner() {\n\t\tGenerator g = new Generator(tab);\n\t\tfram = g.OpenFrame(\"Scanner.frame\");\n\t\tgen = g.OpenGen(\"Scanner.cs\");\n\t\tif (dirtyDFA) MakeDeterministic();\n\n\t\tg.GenCopyright();\n\t\tg.SkipFramePart(\"-->begin\");\n\n\t\tg.CopyFramePart(\"-->namespace\");\n\t\tif (tab.nsName != null && tab.nsName.Length > 0) {\n\t\t\tgen.Write(\"namespace \");\n\t\t\tgen.Write(tab.nsName);\n\t\t\tgen.Write(\" {\");\n\t\t}\n\t\tg.CopyFramePart(\"-->declarations\");\n\t\tgen.WriteLine(\"\\tconst int maxT = {0};\", tab.terminals.Count - 1);\n\t\tgen.WriteLine(\"\\tconst int noSym = {0};\", tab.noSym.n);\n\t\tif (ignoreCase)\n\t\t\tgen.Write(\"\\tchar valCh;       // current input character (for token.val)\");\n\t\tg.CopyFramePart(\"-->initialization\");\n\t\tWriteStartTab();\n\t\tg.CopyFramePart(\"-->casing1\");\n\t\tif (ignoreCase) {\n\t\t\tgen.WriteLine(\"\\t\\tif (ch != Buffer.EOF) {\");\n\t\t\tgen.WriteLine(\"\\t\\t\\tvalCh = (char) ch;\");\n\t\t\tgen.WriteLine(\"\\t\\t\\tch = char.ToLower((char) ch);\");\n\t\t\tgen.WriteLine(\"\\t\\t}\");\n\t\t}\n\t\tg.CopyFramePart(\"-->casing2\");\n\t\tgen.Write(\"\\t\\t\\ttval[tlen++] = \");\n\t\tif (ignoreCase) gen.Write(\"valCh;\"); else gen.Write(\"(char) ch;\");\n\t\tg.CopyFramePart(\"-->comments\");\n\t\tComment com = firstComment; \n\t\tint comIdx = 0;\n\t\twhile (com != null) {\n\t\t\tGenComment(com, comIdx);\n\t\t\tcom = com.next; comIdx++;\n\t\t}\n\t\tg.CopyFramePart(\"-->literals\"); GenLiterals();\n\t\tg.CopyFramePart(\"-->scan1\");\n\t\tgen.Write(\"\\t\\t\\t\");\n\t\tif (tab.ignored.Elements() > 0) { PutRange(tab.ignored); } else { gen.Write(\"false\"); }\n\t\tg.CopyFramePart(\"-->scan2\");\n\t\tif (firstComment != null) {\n\t\t\tgen.Write(\"\\t\\tif (\");\n\t\t\tcom = firstComment; comIdx = 0;\n\t\t\twhile (com != null) {\n\t\t\t\tgen.Write(ChCond(com.start[0]));\n\t\t\t\tgen.Write(\" && Comment{0}()\", comIdx);\n\t\t\t\tif (com.next != null) gen.Write(\" ||\");\n\t\t\t\tcom = com.next; comIdx++;\n\t\t\t}\n\t\t\tgen.Write(\") return NextToken();\");\n\t\t}\n\t\tif (hasCtxMoves) { gen.WriteLine(); gen.Write(\"\\t\\tint apx = 0;\"); } /* pdt */\n\t\tg.CopyFramePart(\"-->scan3\");\n\t\tfor (State state = firstState.next; state != null; state = state.next)\n\t\t\tWriteState(state);\n\t\tg.CopyFramePart(null);\n\t\tif (tab.nsName != null && tab.nsName.Length > 0) gen.Write(\"}\");\n\t\tgen.Close();\n\t}\n\t\n\tpublic DFA (Parser parser) {\n\t\tthis.parser = parser;\n\t\ttab = parser.tab;\n\t\terrors = parser.errors;\n\t\ttrace = parser.trace;\n\t\tfirstState = null; lastState = null; lastStateNr = -1;\n\t\tfirstState = NewState();\n\t\tfirstMelted = null; firstComment = null;\n\t\tignoreCase = false;\n\t\tdirtyDFA = false;\n\t\thasCtxMoves = false;\n\t}\n\t\n} // end DFA\n\n} // end namespace\n"
  },
  {
    "path": "third_party/Coco/src/Parser.cs",
    "content": "/*----------------------------------------------------------------------\nCompiler Generator Coco/R,\nCopyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz\nextended by M. Loeberbauer & A. Woess, Univ. of Linz\nwith improvements by Pat Terry, Rhodes University\n\nThis program is free software; you can redistribute it and/or modify it \nunder the terms of the GNU General Public License as published by the \nFree Software Foundation; either version 2, or (at your option) any \nlater version.\n\nThis program is distributed in the hope that it will be useful, but \nWITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY \nor FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License \nfor more details.\n\nYou should have received a copy of the GNU General Public License along \nwith this program; if not, write to the Free Software Foundation, Inc., \n59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n\nAs an exception, it is allowed to write an extension of Coco/R that is\nused as a plugin in non-free software.\n\nIf not otherwise stated, any source code generated by Coco/R (other than \nCoco/R itself) does not fall under the GNU General Public License.\n-----------------------------------------------------------------------*/\nusing System.IO;\n\n\n\nusing System;\n\nnamespace at.jku.ssw.Coco {\n\n\n\npublic class Parser {\n\tpublic const int _EOF = 0;\n\tpublic const int _ident = 1;\n\tpublic const int _number = 2;\n\tpublic const int _string = 3;\n\tpublic const int _badString = 4;\n\tpublic const int _char = 5;\n\tpublic const int maxT = 41;\n\tpublic const int _ddtSym = 42;\n\tpublic const int _optionSym = 43;\n\n\tconst bool _T = true;\n\tconst bool _x = false;\n\tconst int minErrDist = 2;\n\t\n\tpublic Scanner scanner;\n\tpublic Errors  errors;\n\n\tpublic Token t;    // last recognized token\n\tpublic Token la;   // lookahead token\n\tint errDist = minErrDist;\n\nconst int id = 0;\n\tconst int str = 1;\n\t\n\tpublic TextWriter trace;    // other Coco objects referenced in this ATG\n\tpublic Tab tab;\n\tpublic DFA dfa;\n\tpublic ParserGen pgen;\n\n\tbool   genScanner;\n\tstring tokenString;         // used in declarations of literal tokens\n\tstring noString = \"-none-\"; // used in declarations of literal tokens\n\n/*-------------------------------------------------------------------------*/\n\n\n\n\tpublic Parser(Scanner scanner) {\n\t\tthis.scanner = scanner;\n\t\terrors = new Errors();\n\t}\n\n\tvoid SynErr (int n) {\n\t\tif (errDist >= minErrDist) errors.SynErr(la.line, la.col, n);\n\t\terrDist = 0;\n\t}\n\n\tpublic void SemErr (string msg) {\n\t\tif (errDist >= minErrDist) errors.SemErr(t.line, t.col, msg);\n\t\terrDist = 0;\n\t}\n\t\n\tvoid Get () {\n\t\tfor (;;) {\n\t\t\tt = la;\n\t\t\tla = scanner.Scan();\n\t\t\tif (la.kind <= maxT) { ++errDist; break; }\n\t\t\t\tif (la.kind == 42) {\n\t\t\t\ttab.SetDDT(la.val); \n\t\t\t\t}\n\t\t\t\tif (la.kind == 43) {\n\t\t\t\ttab.SetOption(la.val); \n\t\t\t\t}\n\n\t\t\tla = t;\n\t\t}\n\t}\n\t\n\tvoid Expect (int n) {\n\t\tif (la.kind==n) Get(); else { SynErr(n); }\n\t}\n\t\n\tbool StartOf (int s) {\n\t\treturn set[s, la.kind];\n\t}\n\t\n\tvoid ExpectWeak (int n, int follow) {\n\t\tif (la.kind == n) Get();\n\t\telse {\n\t\t\tSynErr(n);\n\t\t\twhile (!StartOf(follow)) Get();\n\t\t}\n\t}\n\n\n\tbool WeakSeparator(int n, int syFol, int repFol) {\n\t\tint kind = la.kind;\n\t\tif (kind == n) {Get(); return true;}\n\t\telse if (StartOf(repFol)) {return false;}\n\t\telse {\n\t\t\tSynErr(n);\n\t\t\twhile (!(set[syFol, kind] || set[repFol, kind] || set[0, kind])) {\n\t\t\t\tGet();\n\t\t\t\tkind = la.kind;\n\t\t\t}\n\t\t\treturn StartOf(syFol);\n\t\t}\n\t}\n\n\t\n\tvoid Coco() {\n\t\tSymbol sym; Graph g, g1, g2; string gramName; CharSet s; int beg, line; \n\t\tif (StartOf(1)) {\n\t\t\tGet();\n\t\t\tbeg = t.pos; line = t.line; \n\t\t\twhile (StartOf(1)) {\n\t\t\t\tGet();\n\t\t\t}\n\t\t\tpgen.usingPos = new Position(beg, la.pos, 0, line); \n\t\t}\n\t\tExpect(6);\n\t\tgenScanner = true; \n\t\ttab.ignored = new CharSet(); \n\t\tExpect(1);\n\t\tgramName = t.val;\n\t\tbeg = la.pos; line = la.line;\n\t\t\n\t\twhile (StartOf(2)) {\n\t\t\tGet();\n\t\t}\n\t\ttab.semDeclPos = new Position(beg, la.pos, 0, line); \n\t\tif (la.kind == 7) {\n\t\t\tGet();\n\t\t\tdfa.ignoreCase = true; \n\t\t}\n\t\tif (la.kind == 8) {\n\t\t\tGet();\n\t\t\twhile (la.kind == 1) {\n\t\t\t\tSetDecl();\n\t\t\t}\n\t\t}\n\t\tif (la.kind == 9) {\n\t\t\tGet();\n\t\t\twhile (la.kind == 1 || la.kind == 3 || la.kind == 5) {\n\t\t\t\tTokenDecl(Node.t);\n\t\t\t}\n\t\t}\n\t\tif (la.kind == 10) {\n\t\t\tGet();\n\t\t\twhile (la.kind == 1 || la.kind == 3 || la.kind == 5) {\n\t\t\t\tTokenDecl(Node.pr);\n\t\t\t}\n\t\t}\n\t\twhile (la.kind == 11) {\n\t\t\tGet();\n\t\t\tbool nested = false; \n\t\t\tExpect(12);\n\t\t\tTokenExpr(out g1);\n\t\t\tExpect(13);\n\t\t\tTokenExpr(out g2);\n\t\t\tif (la.kind == 14) {\n\t\t\t\tGet();\n\t\t\t\tnested = true; \n\t\t\t}\n\t\t\tdfa.NewComment(g1.l, g2.l, nested); \n\t\t}\n\t\twhile (la.kind == 15) {\n\t\t\tGet();\n\t\t\tSet(out s);\n\t\t\ttab.ignored.Or(s); \n\t\t}\n\t\twhile (!(la.kind == 0 || la.kind == 16)) {SynErr(42); Get();}\n\t\tExpect(16);\n\t\tif (genScanner) dfa.MakeDeterministic();\n\t\ttab.DeleteNodes();\n\t\t\n\t\twhile (la.kind == 1) {\n\t\t\tGet();\n\t\t\tsym = tab.FindSym(t.val);\n\t\t\tbool undef = sym == null;\n\t\t\tif (undef) sym = tab.NewSym(Node.nt, t.val, t.line);\n\t\t\telse {\n\t\t\t if (sym.typ == Node.nt) {\n\t\t\t   if (sym.graph != null) SemErr(\"name declared twice\");\n\t\t\t } else SemErr(\"this symbol kind not allowed on left side of production\");\n\t\t\t sym.line = t.line;\n\t\t\t}\n\t\t\tbool noAttrs = sym.attrPos == null;\n\t\t\tsym.attrPos = null;\n\t\t\t\n\t\t\tif (la.kind == 24 || la.kind == 26) {\n\t\t\t\tAttrDecl(sym);\n\t\t\t}\n\t\t\tif (!undef)\n\t\t\t if (noAttrs != (sym.attrPos == null))\n\t\t\t   SemErr(\"attribute mismatch between declaration and use of this symbol\");\n\t\t\t\n\t\t\tif (la.kind == 39) {\n\t\t\t\tSemText(out sym.semPos);\n\t\t\t}\n\t\t\tExpectWeak(17, 3);\n\t\t\tExpression(out g);\n\t\t\tsym.graph = g.l;\n\t\t\ttab.Finish(g);\n\t\t\t\n\t\t\tExpectWeak(18, 4);\n\t\t}\n\t\tExpect(19);\n\t\tExpect(1);\n\t\tif (gramName != t.val)\n\t\t SemErr(\"name does not match grammar name\");\n\t\ttab.gramSy = tab.FindSym(gramName);\n\t\tif (tab.gramSy == null)\n\t\t SemErr(\"missing production for grammar name\");\n\t\telse {\n\t\t sym = tab.gramSy;\n\t\t if (sym.attrPos != null)\n\t\t   SemErr(\"grammar symbol must not have attributes\");\n\t\t}\n\t\ttab.noSym = tab.NewSym(Node.t, \"???\", 0); // noSym gets highest number\n\t\ttab.SetupAnys();\n\t\ttab.RenumberPragmas();\n\t\tif (tab.ddt[2]) tab.PrintNodes();\n\t\tif (errors.count == 0) {\n\t\t Console.WriteLine(\"checking\");\n\t\t tab.CompSymbolSets();\n\t\t if (tab.ddt[7]) tab.XRef();\n\t\t if (tab.GrammarOk()) {\n\t\t   Console.Write(\"parser\");\n\t\t   pgen.WriteParser();\n\t\t   if (genScanner) {\n\t\t     Console.Write(\" + scanner\");\n\t\t     dfa.WriteScanner();\n\t\t     if (tab.ddt[0]) dfa.PrintStates();\n\t\t   }\n\t\t   Console.WriteLine(\" generated\");\n\t\t   if (tab.ddt[8]) pgen.WriteStatistics();\n\t\t }\n\t\t}\n\t\tif (tab.ddt[6]) tab.PrintSymbolTable();\n\t\t\n\t\tExpect(18);\n\t}\n\n\tvoid SetDecl() {\n\t\tCharSet s; \n\t\tExpect(1);\n\t\tstring name = t.val;\n\t\tCharClass c = tab.FindCharClass(name);\n\t\tif (c != null) SemErr(\"name declared twice\");\n\t\t\n\t\tExpect(17);\n\t\tSet(out s);\n\t\tif (s.Elements() == 0) SemErr(\"character set must not be empty\");\n\t\ttab.NewCharClass(name, s);\n\t\t\n\t\tExpect(18);\n\t}\n\n\tvoid TokenDecl(int typ) {\n\t\tstring name; int kind; Symbol sym; Graph g; \n\t\tSym(out name, out kind);\n\t\tsym = tab.FindSym(name);\n\t\tif (sym != null) SemErr(\"name declared twice\");\n\t\telse {\n\t\t sym = tab.NewSym(typ, name, t.line);\n\t\t sym.tokenKind = Symbol.fixedToken;\n\t\t}\n\t\ttokenString = null;\n\t\t\n\t\twhile (!(StartOf(5))) {SynErr(43); Get();}\n\t\tif (la.kind == 17) {\n\t\t\tGet();\n\t\t\tTokenExpr(out g);\n\t\t\tExpect(18);\n\t\t\tif (kind == str) SemErr(\"a literal must not be declared with a structure\");\n\t\t\ttab.Finish(g);\n\t\t\tif (tokenString == null || tokenString.Equals(noString))\n\t\t\t dfa.ConvertToStates(g.l, sym);\n\t\t\telse { // TokenExpr is a single string\n\t\t\t if (tab.literals[tokenString] != null)\n\t\t\t   SemErr(\"token string declared twice\");\n\t\t\t tab.literals[tokenString] = sym;\n\t\t\t dfa.MatchLiteral(tokenString, sym);\n\t\t\t}\n\t\t\t\n\t\t} else if (StartOf(6)) {\n\t\t\tif (kind == id) genScanner = false;\n\t\t\telse dfa.MatchLiteral(sym.name, sym);\n\t\t\t\n\t\t} else SynErr(44);\n\t\tif (la.kind == 39) {\n\t\t\tSemText(out sym.semPos);\n\t\t\tif (typ != Node.pr) SemErr(\"semantic action not allowed here\"); \n\t\t}\n\t}\n\n\tvoid TokenExpr(out Graph g) {\n\t\tGraph g2; \n\t\tTokenTerm(out g);\n\t\tbool first = true; \n\t\twhile (WeakSeparator(28,7,8) ) {\n\t\t\tTokenTerm(out g2);\n\t\t\tif (first) { tab.MakeFirstAlt(g); first = false; }\n\t\t\ttab.MakeAlternative(g, g2);\n\t\t\t\n\t\t}\n\t}\n\n\tvoid Set(out CharSet s) {\n\t\tCharSet s2; \n\t\tSimSet(out s);\n\t\twhile (la.kind == 20 || la.kind == 21) {\n\t\t\tif (la.kind == 20) {\n\t\t\t\tGet();\n\t\t\t\tSimSet(out s2);\n\t\t\t\ts.Or(s2); \n\t\t\t} else {\n\t\t\t\tGet();\n\t\t\t\tSimSet(out s2);\n\t\t\t\ts.Subtract(s2); \n\t\t\t}\n\t\t}\n\t}\n\n\tvoid AttrDecl(Symbol sym) {\n\t\tif (la.kind == 24) {\n\t\t\tGet();\n\t\t\tint beg = la.pos; int col = la.col; int line = la.line; \n\t\t\twhile (StartOf(9)) {\n\t\t\t\tif (StartOf(10)) {\n\t\t\t\t\tGet();\n\t\t\t\t} else {\n\t\t\t\t\tGet();\n\t\t\t\t\tSemErr(\"bad string in attributes\"); \n\t\t\t\t}\n\t\t\t}\n\t\t\tExpect(25);\n\t\t\tif (t.pos > beg)\n\t\t\t sym.attrPos = new Position(beg, t.pos, col, line); \n\t\t} else if (la.kind == 26) {\n\t\t\tGet();\n\t\t\tint beg = la.pos; int col = la.col; int line = la.line; \n\t\t\twhile (StartOf(11)) {\n\t\t\t\tif (StartOf(12)) {\n\t\t\t\t\tGet();\n\t\t\t\t} else {\n\t\t\t\t\tGet();\n\t\t\t\t\tSemErr(\"bad string in attributes\"); \n\t\t\t\t}\n\t\t\t}\n\t\t\tExpect(27);\n\t\t\tif (t.pos > beg)\n\t\t\t sym.attrPos = new Position(beg, t.pos, col, line); \n\t\t} else SynErr(45);\n\t}\n\n\tvoid SemText(out Position pos) {\n\t\tExpect(39);\n\t\tint beg = la.pos; int col = la.col; int line = la.line; \n\t\twhile (StartOf(13)) {\n\t\t\tif (StartOf(14)) {\n\t\t\t\tGet();\n\t\t\t} else if (la.kind == 4) {\n\t\t\t\tGet();\n\t\t\t\tSemErr(\"bad string in semantic action\"); \n\t\t\t} else {\n\t\t\t\tGet();\n\t\t\t\tSemErr(\"missing end of previous semantic action\"); \n\t\t\t}\n\t\t}\n\t\tExpect(40);\n\t\tpos = new Position(beg, t.pos, col, line); \n\t}\n\n\tvoid Expression(out Graph g) {\n\t\tGraph g2; \n\t\tTerm(out g);\n\t\tbool first = true; \n\t\twhile (WeakSeparator(28,15,16) ) {\n\t\t\tTerm(out g2);\n\t\t\tif (first) { tab.MakeFirstAlt(g); first = false; }\n\t\t\ttab.MakeAlternative(g, g2);\n\t\t\t\n\t\t}\n\t}\n\n\tvoid SimSet(out CharSet s) {\n\t\tint n1, n2; \n\t\ts = new CharSet(); \n\t\tif (la.kind == 1) {\n\t\t\tGet();\n\t\t\tCharClass c = tab.FindCharClass(t.val);\n\t\t\tif (c == null) SemErr(\"undefined name\"); else s.Or(c.set);\n\t\t\t\n\t\t} else if (la.kind == 3) {\n\t\t\tGet();\n\t\t\tstring name = t.val;\n\t\t\tname = tab.Unescape(name.Substring(1, name.Length-2));\n\t\t\tforeach (char ch in name)\n\t\t\t if (dfa.ignoreCase) s.Set(char.ToLower(ch));\n\t\t\t else s.Set(ch); \n\t\t} else if (la.kind == 5) {\n\t\t\tChar(out n1);\n\t\t\ts.Set(n1); \n\t\t\tif (la.kind == 22) {\n\t\t\t\tGet();\n\t\t\t\tChar(out n2);\n\t\t\t\tfor (int i = n1; i <= n2; i++) s.Set(i); \n\t\t\t}\n\t\t} else if (la.kind == 23) {\n\t\t\tGet();\n\t\t\ts = new CharSet(); s.Fill(); \n\t\t} else SynErr(46);\n\t}\n\n\tvoid Char(out int n) {\n\t\tExpect(5);\n\t\tstring name = t.val; n = 0;\n\t\tname = tab.Unescape(name.Substring(1, name.Length-2));\n\t\tif (name.Length == 1) n = name[0];\n\t\telse SemErr(\"unacceptable character value\");\n\t\tif (dfa.ignoreCase && (char)n >= 'A' && (char)n <= 'Z') n += 32;\n\t\t\n\t}\n\n\tvoid Sym(out string name, out int kind) {\n\t\tname = \"???\"; kind = id; \n\t\tif (la.kind == 1) {\n\t\t\tGet();\n\t\t\tkind = id; name = t.val; \n\t\t} else if (la.kind == 3 || la.kind == 5) {\n\t\t\tif (la.kind == 3) {\n\t\t\t\tGet();\n\t\t\t\tname = t.val; \n\t\t\t} else {\n\t\t\t\tGet();\n\t\t\t\tname = \"\\\"\" + t.val.Substring(1, t.val.Length-2) + \"\\\"\"; \n\t\t\t}\n\t\t\tkind = str;\n\t\t\tif (dfa.ignoreCase) name = name.ToLower();\n\t\t\tif (name.IndexOf(' ') >= 0)\n\t\t\t SemErr(\"literal tokens must not contain blanks\"); \n\t\t} else SynErr(47);\n\t}\n\n\tvoid Term(out Graph g) {\n\t\tGraph g2; Node rslv = null; g = null; \n\t\tif (StartOf(17)) {\n\t\t\tif (la.kind == 37) {\n\t\t\t\trslv = tab.NewNode(Node.rslv, null, la.line); \n\t\t\t\tResolver(out rslv.pos);\n\t\t\t\tg = new Graph(rslv); \n\t\t\t}\n\t\t\tFactor(out g2);\n\t\t\tif (rslv != null) tab.MakeSequence(g, g2);\n\t\t\telse g = g2;\n\t\t\t\n\t\t\twhile (StartOf(18)) {\n\t\t\t\tFactor(out g2);\n\t\t\t\ttab.MakeSequence(g, g2); \n\t\t\t}\n\t\t} else if (StartOf(19)) {\n\t\t\tg = new Graph(tab.NewNode(Node.eps, null, 0)); \n\t\t} else SynErr(48);\n\t\tif (g == null) // invalid start of Term\n\t\t g = new Graph(tab.NewNode(Node.eps, null, 0));\n\t\t\n\t}\n\n\tvoid Resolver(out Position pos) {\n\t\tExpect(37);\n\t\tExpect(30);\n\t\tint beg = la.pos; int col = la.col; int line = la.line; \n\t\tCondition();\n\t\tpos = new Position(beg, t.pos, col, line); \n\t}\n\n\tvoid Factor(out Graph g) {\n\t\tstring name; int kind; Position pos; bool weak = false; \n\t\tg = null;\n\t\t\n\t\tswitch (la.kind) {\n\t\tcase 1: case 3: case 5: case 29: {\n\t\t\tif (la.kind == 29) {\n\t\t\t\tGet();\n\t\t\t\tweak = true; \n\t\t\t}\n\t\t\tSym(out name, out kind);\n\t\t\tSymbol sym = tab.FindSym(name);\n\t\t\tif (sym == null && kind == str)\n\t\t\t sym = tab.literals[name] as Symbol;\n\t\t\tbool undef = sym == null;\n\t\t\tif (undef) {\n\t\t\t if (kind == id)\n\t\t\t   sym = tab.NewSym(Node.nt, name, 0);  // forward nt\n\t\t\t else if (genScanner) { \n\t\t\t   sym = tab.NewSym(Node.t, name, t.line);\n\t\t\t   dfa.MatchLiteral(sym.name, sym);\n\t\t\t } else {  // undefined string in production\n\t\t\t   SemErr(\"undefined string in production\");\n\t\t\t   sym = tab.eofSy;  // dummy\n\t\t\t }\n\t\t\t}\n\t\t\tint typ = sym.typ;\n\t\t\tif (typ != Node.t && typ != Node.nt)\n\t\t\t SemErr(\"this symbol kind is not allowed in a production\");\n\t\t\tif (weak)\n\t\t\t if (typ == Node.t) typ = Node.wt;\n\t\t\t else SemErr(\"only terminals may be weak\");\n\t\t\tNode p = tab.NewNode(typ, sym, t.line);\n\t\t\tg = new Graph(p);\n\t\t\t\n\t\t\tif (la.kind == 24 || la.kind == 26) {\n\t\t\t\tAttribs(p);\n\t\t\t\tif (kind != id) SemErr(\"a literal must not have attributes\"); \n\t\t\t}\n\t\t\tif (undef)\n\t\t\t sym.attrPos = p.pos;  // dummy\n\t\t\telse if ((p.pos == null) != (sym.attrPos == null))\n\t\t\t SemErr(\"attribute mismatch between declaration and use of this symbol\");\n\t\t\t\n\t\t\tbreak;\n\t\t}\n\t\tcase 30: {\n\t\t\tGet();\n\t\t\tExpression(out g);\n\t\t\tExpect(31);\n\t\t\tbreak;\n\t\t}\n\t\tcase 32: {\n\t\t\tGet();\n\t\t\tExpression(out g);\n\t\t\tExpect(33);\n\t\t\ttab.MakeOption(g); \n\t\t\tbreak;\n\t\t}\n\t\tcase 34: {\n\t\t\tGet();\n\t\t\tExpression(out g);\n\t\t\tExpect(35);\n\t\t\ttab.MakeIteration(g); \n\t\t\tbreak;\n\t\t}\n\t\tcase 39: {\n\t\t\tSemText(out pos);\n\t\t\tNode p = tab.NewNode(Node.sem, null, 0);\n\t\t\tp.pos = pos;\n\t\t\tg = new Graph(p);\n\t\t\t\n\t\t\tbreak;\n\t\t}\n\t\tcase 23: {\n\t\t\tGet();\n\t\t\tNode p = tab.NewNode(Node.any, null, 0);  // p.set is set in tab.SetupAnys\n\t\t\tg = new Graph(p);\n\t\t\t\n\t\t\tbreak;\n\t\t}\n\t\tcase 36: {\n\t\t\tGet();\n\t\t\tNode p = tab.NewNode(Node.sync, null, 0);\n\t\t\tg = new Graph(p);\n\t\t\t\n\t\t\tbreak;\n\t\t}\n\t\tdefault: SynErr(49); break;\n\t\t}\n\t\tif (g == null) // invalid start of Factor\n\t\t g = new Graph(tab.NewNode(Node.eps, null, 0));\n\t\t\n\t}\n\n\tvoid Attribs(Node p) {\n\t\tif (la.kind == 24) {\n\t\t\tGet();\n\t\t\tint beg = la.pos; int col = la.col; int line = la.line; \n\t\t\twhile (StartOf(9)) {\n\t\t\t\tif (StartOf(10)) {\n\t\t\t\t\tGet();\n\t\t\t\t} else {\n\t\t\t\t\tGet();\n\t\t\t\t\tSemErr(\"bad string in attributes\"); \n\t\t\t\t}\n\t\t\t}\n\t\t\tExpect(25);\n\t\t\tif (t.pos > beg) p.pos = new Position(beg, t.pos, col, line); \n\t\t} else if (la.kind == 26) {\n\t\t\tGet();\n\t\t\tint beg = la.pos; int col = la.col; int line = la.line; \n\t\t\twhile (StartOf(11)) {\n\t\t\t\tif (StartOf(12)) {\n\t\t\t\t\tGet();\n\t\t\t\t} else {\n\t\t\t\t\tGet();\n\t\t\t\t\tSemErr(\"bad string in attributes\"); \n\t\t\t\t}\n\t\t\t}\n\t\t\tExpect(27);\n\t\t\tif (t.pos > beg) p.pos = new Position(beg, t.pos, col, line); \n\t\t} else SynErr(50);\n\t}\n\n\tvoid Condition() {\n\t\twhile (StartOf(20)) {\n\t\t\tif (la.kind == 30) {\n\t\t\t\tGet();\n\t\t\t\tCondition();\n\t\t\t} else {\n\t\t\t\tGet();\n\t\t\t}\n\t\t}\n\t\tExpect(31);\n\t}\n\n\tvoid TokenTerm(out Graph g) {\n\t\tGraph g2; \n\t\tTokenFactor(out g);\n\t\twhile (StartOf(7)) {\n\t\t\tTokenFactor(out g2);\n\t\t\ttab.MakeSequence(g, g2); \n\t\t}\n\t\tif (la.kind == 38) {\n\t\t\tGet();\n\t\t\tExpect(30);\n\t\t\tTokenExpr(out g2);\n\t\t\ttab.SetContextTrans(g2.l); dfa.hasCtxMoves = true;\n\t\t\ttab.MakeSequence(g, g2); \n\t\t\tExpect(31);\n\t\t}\n\t}\n\n\tvoid TokenFactor(out Graph g) {\n\t\tstring name; int kind; \n\t\tg = null; \n\t\tif (la.kind == 1 || la.kind == 3 || la.kind == 5) {\n\t\t\tSym(out name, out kind);\n\t\t\tif (kind == id) {\n\t\t\t CharClass c = tab.FindCharClass(name);\n\t\t\t if (c == null) {\n\t\t\t   SemErr(\"undefined name\");\n\t\t\t   c = tab.NewCharClass(name, new CharSet());\n\t\t\t }\n\t\t\t Node p = tab.NewNode(Node.clas, null, 0); p.val = c.n;\n\t\t\t g = new Graph(p);\n\t\t\t tokenString = noString;\n\t\t\t} else { // str\n\t\t\t g = tab.StrToGraph(name);\n\t\t\t if (tokenString == null) tokenString = name;\n\t\t\t else tokenString = noString;\n\t\t\t}\n\t\t\t\n\t\t} else if (la.kind == 30) {\n\t\t\tGet();\n\t\t\tTokenExpr(out g);\n\t\t\tExpect(31);\n\t\t} else if (la.kind == 32) {\n\t\t\tGet();\n\t\t\tTokenExpr(out g);\n\t\t\tExpect(33);\n\t\t\ttab.MakeOption(g); tokenString = noString; \n\t\t} else if (la.kind == 34) {\n\t\t\tGet();\n\t\t\tTokenExpr(out g);\n\t\t\tExpect(35);\n\t\t\ttab.MakeIteration(g); tokenString = noString; \n\t\t} else SynErr(51);\n\t\tif (g == null) // invalid start of TokenFactor\n\t\t g = new Graph(tab.NewNode(Node.eps, null, 0)); \n\t}\n\n\n\n\tpublic void Parse() {\n\t\tla = new Token();\n\t\tla.val = \"\";\t\t\n\t\tGet();\n\t\tCoco();\n\t\tExpect(0);\n\n\t}\n\t\n\tstatic readonly bool[,] set = {\n\t\t{_T,_T,_x,_T, _x,_T,_x,_x, _x,_x,_T,_T, _x,_x,_x,_T, _T,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_T, _x,_x,_x},\n\t\t{_x,_T,_T,_T, _T,_T,_x,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_x},\n\t\t{_x,_T,_T,_T, _T,_T,_T,_x, _x,_x,_x,_x, _T,_T,_T,_x, _x,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_x},\n\t\t{_T,_T,_x,_T, _x,_T,_x,_x, _x,_x,_T,_T, _x,_x,_x,_T, _T,_T,_T,_x, _x,_x,_x,_T, _x,_x,_x,_x, _T,_T,_T,_x, _T,_x,_T,_x, _T,_T,_x,_T, _x,_x,_x},\n\t\t{_T,_T,_x,_T, _x,_T,_x,_x, _x,_x,_T,_T, _x,_x,_x,_T, _T,_T,_x,_T, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_T, _x,_x,_x},\n\t\t{_T,_T,_x,_T, _x,_T,_x,_x, _x,_x,_T,_T, _x,_x,_x,_T, _T,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_T, _x,_x,_x},\n\t\t{_x,_T,_x,_T, _x,_T,_x,_x, _x,_x,_T,_T, _x,_x,_x,_T, _T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_T, _x,_x,_x},\n\t\t{_x,_T,_x,_T, _x,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_x, _T,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x},\n\t\t{_x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_T, _x,_T,_T,_T, _T,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_T, _x,_T,_x,_T, _x,_x,_x,_x, _x,_x,_x},\n\t\t{_x,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_x,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_x},\n\t\t{_x,_T,_T,_T, _x,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_x,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_x},\n\t\t{_x,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_x, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_x},\n\t\t{_x,_T,_T,_T, _x,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_x, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_x},\n\t\t{_x,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _x,_T,_x},\n\t\t{_x,_T,_T,_T, _x,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_x, _x,_T,_x},\n\t\t{_x,_T,_x,_T, _x,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_x, _x,_x,_x,_T, _x,_x,_x,_x, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_x,_T, _x,_x,_x},\n\t\t{_x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_T, _x,_T,_x,_T, _x,_x,_x,_x, _x,_x,_x},\n\t\t{_x,_T,_x,_T, _x,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_T, _x,_x,_x,_x, _x,_T,_T,_x, _T,_x,_T,_x, _T,_T,_x,_T, _x,_x,_x},\n\t\t{_x,_T,_x,_T, _x,_T,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_T, _x,_x,_x,_x, _x,_T,_T,_x, _T,_x,_T,_x, _T,_x,_x,_T, _x,_x,_x},\n\t\t{_x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_T,_x, _x,_x,_x,_x, _x,_x,_x,_x, _T,_x,_x,_T, _x,_T,_x,_T, _x,_x,_x,_x, _x,_x,_x},\n\t\t{_x,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_T,_x, _T,_T,_T,_T, _T,_T,_T,_T, _T,_T,_x}\n\n\t};\n} // end Parser\n\n\npublic class Errors {\n\tpublic int count = 0;                                    // number of errors detected\n\tpublic System.IO.TextWriter errorStream = Console.Out;   // error messages go to this stream\n\tpublic string errMsgFormat = \"-- line {0} col {1}: {2}\"; // 0=line, 1=column, 2=text\n\n\tpublic virtual void SynErr (int line, int col, int n) {\n\t\tstring s;\n\t\tswitch (n) {\n\t\t\tcase 0: s = \"EOF expected\"; break;\n\t\t\tcase 1: s = \"ident expected\"; break;\n\t\t\tcase 2: s = \"number expected\"; break;\n\t\t\tcase 3: s = \"string expected\"; break;\n\t\t\tcase 4: s = \"badString expected\"; break;\n\t\t\tcase 5: s = \"char expected\"; break;\n\t\t\tcase 6: s = \"\\\"COMPILER\\\" expected\"; break;\n\t\t\tcase 7: s = \"\\\"IGNORECASE\\\" expected\"; break;\n\t\t\tcase 8: s = \"\\\"CHARACTERS\\\" expected\"; break;\n\t\t\tcase 9: s = \"\\\"TOKENS\\\" expected\"; break;\n\t\t\tcase 10: s = \"\\\"PRAGMAS\\\" expected\"; break;\n\t\t\tcase 11: s = \"\\\"COMMENTS\\\" expected\"; break;\n\t\t\tcase 12: s = \"\\\"FROM\\\" expected\"; break;\n\t\t\tcase 13: s = \"\\\"TO\\\" expected\"; break;\n\t\t\tcase 14: s = \"\\\"NESTED\\\" expected\"; break;\n\t\t\tcase 15: s = \"\\\"IGNORE\\\" expected\"; break;\n\t\t\tcase 16: s = \"\\\"PRODUCTIONS\\\" expected\"; break;\n\t\t\tcase 17: s = \"\\\"=\\\" expected\"; break;\n\t\t\tcase 18: s = \"\\\".\\\" expected\"; break;\n\t\t\tcase 19: s = \"\\\"END\\\" expected\"; break;\n\t\t\tcase 20: s = \"\\\"+\\\" expected\"; break;\n\t\t\tcase 21: s = \"\\\"-\\\" expected\"; break;\n\t\t\tcase 22: s = \"\\\"..\\\" expected\"; break;\n\t\t\tcase 23: s = \"\\\"ANY\\\" expected\"; break;\n\t\t\tcase 24: s = \"\\\"<\\\" expected\"; break;\n\t\t\tcase 25: s = \"\\\">\\\" expected\"; break;\n\t\t\tcase 26: s = \"\\\"<.\\\" expected\"; break;\n\t\t\tcase 27: s = \"\\\".>\\\" expected\"; break;\n\t\t\tcase 28: s = \"\\\"|\\\" expected\"; break;\n\t\t\tcase 29: s = \"\\\"WEAK\\\" expected\"; break;\n\t\t\tcase 30: s = \"\\\"(\\\" expected\"; break;\n\t\t\tcase 31: s = \"\\\")\\\" expected\"; break;\n\t\t\tcase 32: s = \"\\\"[\\\" expected\"; break;\n\t\t\tcase 33: s = \"\\\"]\\\" expected\"; break;\n\t\t\tcase 34: s = \"\\\"{\\\" expected\"; break;\n\t\t\tcase 35: s = \"\\\"}\\\" expected\"; break;\n\t\t\tcase 36: s = \"\\\"SYNC\\\" expected\"; break;\n\t\t\tcase 37: s = \"\\\"IF\\\" expected\"; break;\n\t\t\tcase 38: s = \"\\\"CONTEXT\\\" expected\"; break;\n\t\t\tcase 39: s = \"\\\"(.\\\" expected\"; break;\n\t\t\tcase 40: s = \"\\\".)\\\" expected\"; break;\n\t\t\tcase 41: s = \"??? expected\"; break;\n\t\t\tcase 42: s = \"this symbol not expected in Coco\"; break;\n\t\t\tcase 43: s = \"this symbol not expected in TokenDecl\"; break;\n\t\t\tcase 44: s = \"invalid TokenDecl\"; break;\n\t\t\tcase 45: s = \"invalid AttrDecl\"; break;\n\t\t\tcase 46: s = \"invalid SimSet\"; break;\n\t\t\tcase 47: s = \"invalid Sym\"; break;\n\t\t\tcase 48: s = \"invalid Term\"; break;\n\t\t\tcase 49: s = \"invalid Factor\"; break;\n\t\t\tcase 50: s = \"invalid Attribs\"; break;\n\t\t\tcase 51: s = \"invalid TokenFactor\"; break;\n\n\t\t\tdefault: s = \"error \" + n; break;\n\t\t}\n\t\terrorStream.WriteLine(errMsgFormat, line, col, s);\n\t\tcount++;\n\t}\n\n\tpublic virtual void SemErr (int line, int col, string s) {\n\t\terrorStream.WriteLine(errMsgFormat, line, col, s);\n\t\tcount++;\n\t}\n\t\n\tpublic virtual void SemErr (string s) {\n\t\terrorStream.WriteLine(s);\n\t\tcount++;\n\t}\n\t\n\tpublic virtual void Warning (int line, int col, string s) {\n\t\terrorStream.WriteLine(errMsgFormat, line, col, s);\n\t}\n\t\n\tpublic virtual void Warning(string s) {\n\t\terrorStream.WriteLine(s);\n\t}\n} // Errors\n\n\npublic class FatalError: Exception {\n\tpublic FatalError(string m): base(m) {}\n}\n}"
  },
  {
    "path": "third_party/Coco/src/Parser.frame",
    "content": "/*----------------------------------------------------------------------\nCompiler Generator Coco/R,\nCopyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz\nextended by M. Loeberbauer & A. Woess, Univ. of Linz\nwith improvements by Pat Terry, Rhodes University\n\nThis program is free software; you can redistribute it and/or modify it\nunder the terms of the GNU General Public License as published by the\nFree Software Foundation; either version 2, or (at your option) any\nlater version.\n\nThis program is distributed in the hope that it will be useful, but\nWITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\nor FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\nfor more details.\n\nYou should have received a copy of the GNU General Public License along\nwith this program; if not, write to the Free Software Foundation, Inc.,\n59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n\nAs an exception, it is allowed to write an extension of Coco/R that is\nused as a plugin in non-free software.\n\nIf not otherwise stated, any source code generated by Coco/R (other than\nCoco/R itself) does not fall under the GNU General Public License.\n----------------------------------------------------------------------*/\n-->begin\n/* This file (Parser.cs) is generated from Dafny.atg by the Coco/R\n * parser generator. Do not edit this file directly. Instead, make\n * changes to Dafny.atg and then rebuild using the Makefile found\n * in the same directory as Dafny.atg.\n */\n\nusing System;\nusing System.Diagnostics.Contracts;\n\n-->namespace\n\npublic class Parser {\n-->constants\n  const bool _T = true;\n  const bool _x = false;\n  const int minErrDist = 2;\n\n  public Scanner scanner;\n  public Errors  errors;\n\n  public IToken t;    // last recognized token\n  public IToken la;   // lookahead token\n  int errDist = minErrDist;\n\n-->declarations\n\n  public Parser(Scanner scanner, Errors errors) {\n    this.scanner = scanner;\n    this.errors = errors;\n    Token tok = new Token();\n    tok.val = \"\";\n    this.la = tok;\n    this.t = new Token(); // just to satisfy its non-null constraint\n  }\n\n  void SynErr (int n) {\n    if (errDist >= minErrDist) errors.SynErr(la.filename, la.line, la.col, n);\n    errDist = 0;\n  }\n\n  public void SemErr (string msg) {\n    Contract.Requires(msg != null);\n    if (errDist >= minErrDist) errors.SemErr(t, msg);\n    errDist = 0;\n  }\n\n  public void SemErr(IToken tok, string msg) {\n    Contract.Requires(tok != null);\n    Contract.Requires(msg != null);\n    errors.SemErr(tok, msg);\n  }\n\n  void Get () {\n    for (;;) {\n      t = theVerifyThisFile ? la : new IncludeToken(theInclude, la);\n      la = scanner.Scan();\n      if (la.kind <= maxT) { ++errDist; break; }\n-->pragmas\n      la = t;\n    }\n  }\n\n  void Expect (int n) {\n    if (la.kind==n) Get(); else { SynErr(n); }\n  }\n\n  bool StartOf (int s) {\n    return set[s, la.kind];\n  }\n\n  void ExpectWeak (int n, int follow) {\n    if (la.kind == n) Get();\n    else {\n      SynErr(n);\n      while (!StartOf(follow)) Get();\n    }\n  }\n\n\n  bool WeakSeparator(int n, int syFol, int repFol) {\n    int kind = la.kind;\n    if (kind == n) {Get(); return true;}\n    else if (StartOf(repFol)) {return false;}\n    else {\n      SynErr(n);\n      while (!(set[syFol, kind] || set[repFol, kind] || set[0, kind])) {\n        Get();\n        kind = la.kind;\n      }\n      return StartOf(syFol);\n    }\n  }\n\n\n-->productions\n\n  public void Parse() {\n    la = new Token();\n    la.val = \"\";\n    Get();\n-->parseRoot\n  }\n\n  static readonly bool[,] set = {\n-->initialization\n  };\n} // end Parser\n\n\npublic class Errors {\n  readonly ErrorReporter Reporting;\n  public int ErrorCount;\n\n  public Errors(ErrorReporter Reporting) {\n    Contract.Requires(Reporting != null);\n    this.Reporting = Reporting;\n  }\n\n  public void SynErr(string filename, int line, int col, int n) {\n    SynErr(filename, line, col, GetSyntaxErrorString(n));\n  }\n\n  public void SynErr(string filename, int line, int col, string msg) {\n    Contract.Requires(msg != null);\n    ErrorCount++;\n    Reporting.Error(MessageSource.Parser, filename, line, col, msg);\n  }\n\n  string GetSyntaxErrorString(int n) {\n    string s;\n    switch (n) {\n-->errors\n      default: s = \"error \" + n; break;\n    }\n    return s;\n  }\n\n  public void SemErr(IToken tok, string msg) {  // semantic errors\n    Contract.Requires(tok != null);\n    Contract.Requires(msg != null);\n    ErrorCount++;\n    Reporting.Error(MessageSource.Parser, tok, msg);\n  }\n\n  public void SemErr(string filename, int line, int col, string msg) {\n    Contract.Requires(msg != null);\n    ErrorCount++;\n    Reporting.Error(MessageSource.Parser, filename, line, col, msg);\n  }\n\n  public void Deprecated(IToken tok, string msg) {\n    Contract.Requires(tok != null);\n    Contract.Requires(msg != null);\n    Reporting.Deprecated(MessageSource.Parser, tok, msg);\n  }\n\n  public void DeprecatedStyle(IToken tok, string msg) {\n    Contract.Requires(tok != null);\n    Contract.Requires(msg != null);\n    Reporting.DeprecatedStyle(MessageSource.Parser, tok, msg);\n  }\n\n  public void Warning(IToken tok, string msg) {\n    Contract.Requires(tok != null);\n    Contract.Requires(msg != null);\n    Reporting.Warning(MessageSource.Parser, tok, msg);\n  }\n} // Errors\n\n\npublic class FatalError: Exception {\n  public FatalError(string m): base(m) {}\n}\n"
  },
  {
    "path": "third_party/Coco/src/ParserGen.cs",
    "content": "/*-------------------------------------------------------------------------\nParserGen.cs -- Generation of the Recursive Descent Parser\nCompiler Generator Coco/R,\nCopyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz\nextended by M. Loeberbauer & A. Woess, Univ. of Linz\nwith improvements by Pat Terry, Rhodes University\n\nThis program is free software; you can redistribute it and/or modify it \nunder the terms of the GNU General Public License as published by the \nFree Software Foundation; either version 2, or (at your option) any \nlater version.\n\nThis program is distributed in the hope that it will be useful, but \nWITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY \nor FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License \nfor more details.\n\nYou should have received a copy of the GNU General Public License along \nwith this program; if not, write to the Free Software Foundation, Inc., \n59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n\nAs an exception, it is allowed to write an extension of Coco/R that is\nused as a plugin in non-free software.\n\nIf not otherwise stated, any source code generated by Coco/R (other than \nCoco/R itself) does not fall under the GNU General Public License.\n-------------------------------------------------------------------------*/\nusing System;\nusing System.IO;\nusing System.Collections;\nusing System.Text;\n\nnamespace at.jku.ssw.Coco {\n\npublic class ParserGen {\n\n\tconst int maxTerm = 3;\t\t// sets of size < maxTerm are enumerated\n\tconst char CR  = '\\r';\n\tconst char LF  = '\\n';\n\tconst int EOF = -1;\n\n\tconst int tErr = 0;\t\t\t// error codes\n\tconst int altErr = 1;\n\tconst int syncErr = 2;\n\t\n\tpublic Position usingPos; // \"using\" definitions from the attributed grammar\n\n\tint errorNr;      // highest parser error number\n\tSymbol curSy;     // symbol whose production is currently generated\n\tFileStream fram;  // parser frame file\n\tStreamWriter gen; // generated parser source file\n\tStringWriter err; // generated parser error messages\n\tArrayList symSet = new ArrayList();\n\t\n\tTab tab;          // other Coco objects\n\tTextWriter trace;\n\tErrors errors;\n\tBuffer buffer;\n\t\n\tvoid Indent (int n) {\n\t\tfor (int i = 1; i <= n; i++) gen.Write('\\t');\n\t}\n\t\n\t\n\tbool Overlaps(BitArray s1, BitArray s2) {\n\t\tint len = s1.Count;\n\t\tfor (int i = 0; i < len; ++i) {\n\t\t\tif (s1[i] && s2[i]) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\t\n\t// use a switch if more than 5 alternatives and none starts with a resolver, and no LL1 warning\n\tbool UseSwitch (Node p) {\n\t\tBitArray s1, s2;\n\t\tif (p.typ != Node.alt) return false;\n\t\tint nAlts = 0;\n\t\ts1 = new BitArray(tab.terminals.Count);\n\t\twhile (p != null) {\n\t\t\ts2 = tab.Expected0(p.sub, curSy);\n\t\t\t// must not optimize with switch statement, if there are ll1 warnings\n\t\t\tif (Overlaps(s1, s2)) { return false; }\n\t\t\ts1.Or(s2);\n\t\t\t++nAlts;\n\t\t\t// must not optimize with switch-statement, if alt uses a resolver expression\n\t\t\tif (p.sub.typ == Node.rslv) return false;\n\t\t\tp = p.down;\n\t\t}\n\t\treturn nAlts > 5;\n\t}\n\n\tvoid CopySourcePart (Position pos, int indent) {\n\t\t// Copy text described by pos from atg to gen\n\t\tint ch, i;\n\t\tif (pos != null) {\n\t\t\tbuffer.Pos = pos.beg; ch = buffer.Read();\n\t\t\tif (tab.emitLines) {\n\t\t\t\tgen.WriteLine();\n\t\t\t\tgen.WriteLine(\"#line {0} \\\"{1}\\\"\", pos.line, tab.srcName);\n\t\t\t}\n\t\t\tIndent(indent);\n\t\t\twhile (buffer.Pos <= pos.end) {\n\t\t\t\twhile (ch == CR || ch == LF) {  // eol is either CR or CRLF or LF\n\t\t\t\t\tgen.WriteLine(); Indent(indent);\n\t\t\t\t\tif (ch == CR) ch = buffer.Read(); // skip CR\n\t\t\t\t\tif (ch == LF) ch = buffer.Read(); // skip LF\n\t\t\t\t\tfor (i = 1; i <= pos.col && (ch == ' ' || ch == '\\t'); i++) { \n\t\t\t\t\t\t// skip blanks at beginning of line\n\t\t\t\t\t\tch = buffer.Read();\n\t\t\t\t\t}\n\t\t\t\t\tif (buffer.Pos > pos.end) goto done;\n\t\t\t\t}\n\t\t\t\tgen.Write((char)ch);\n\t\t\t\tch = buffer.Read();\n\t\t\t}\n\t\t\tdone:\n\t\t\tif (indent > 0) gen.WriteLine();\n\t\t}\n\t}\n\n\tvoid GenErrorMsg (int errTyp, Symbol sym) {\n\t\terrorNr++;\n\t\terr.Write(\"\\t\\t\\tcase \" + errorNr + \": s = \\\"\");\n\t\tswitch (errTyp) {\n\t\t\tcase tErr: \n\t\t\t\tif (sym.name[0] == '\"') err.Write(tab.Escape(sym.name) + \" expected\");\n\t\t\t\telse err.Write(sym.name + \" expected\"); \n\t\t\t\tbreak;\n\t\t\tcase altErr: err.Write(\"invalid \" + sym.name); break;\n\t\t\tcase syncErr: err.Write(\"this symbol not expected in \" + sym.name); break;\n\t\t}\n\t\terr.WriteLine(\"\\\"; break;\");\n\t}\n\t\n\tint NewCondSet (BitArray s) {\n\t\tfor (int i = 1; i < symSet.Count; i++) // skip symSet[0] (reserved for union of SYNC sets)\n\t\t\tif (Sets.Equals(s, (BitArray)symSet[i])) return i;\n\t\tsymSet.Add(s.Clone());\n\t\treturn symSet.Count - 1;\n\t}\n\t\n\tvoid GenCond (BitArray s, Node p) {\n\t\tif (p.typ == Node.rslv) CopySourcePart(p.pos, 0);\n\t\telse {\n\t\t\tint n = Sets.Elements(s);\n\t\t\tif (n == 0) gen.Write(\"false\"); // happens if an ANY set matches no symbol\n\t\t\telse if (n <= maxTerm)\n\t\t\t\tforeach (Symbol sym in tab.terminals) {\n\t\t\t\t\tif (s[sym.n]) {\n\t\t\t\t\t\tgen.Write(\"la.kind == {0}\", sym.n);\n\t\t\t\t\t\t--n;\n\t\t\t\t\t\tif (n > 0) gen.Write(\" || \");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\telse\n\t\t\t\tgen.Write(\"StartOf({0})\", NewCondSet(s));\n\t\t}\n\t}\n\t\t\n\tvoid PutCaseLabels (BitArray s) {\n\t\tforeach (Symbol sym in tab.terminals)\n\t\t\tif (s[sym.n]) gen.Write(\"case {0}: \", sym.n);\n\t}\n\t\n\tvoid GenCode (Node p, int indent, BitArray isChecked) {\n\t\tNode p2;\n\t\tBitArray s1, s2;\n\t\twhile (p != null) {\n\t\t\tswitch (p.typ) {\n\t\t\t\tcase Node.nt: {\n\t\t\t\t\tIndent(indent);\n\t\t\t\t\tgen.Write(p.sym.name + \"(\");\n\t\t\t\t\tCopySourcePart(p.pos, 0);\n\t\t\t\t\tgen.WriteLine(\");\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase Node.t: {\n\t\t\t\t\tIndent(indent);\n\t\t\t\t\t// assert: if isChecked[p.sym.n] is true, then isChecked contains only p.sym.n\n\t\t\t\t\tif (isChecked[p.sym.n]) gen.WriteLine(\"Get();\");\n\t\t\t\t\telse gen.WriteLine(\"Expect({0});\", p.sym.n);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase Node.wt: {\n\t\t\t\t\tIndent(indent);\n\t\t\t\t\ts1 = tab.Expected(p.next, curSy);\n\t\t\t\t\ts1.Or(tab.allSyncSets);\n\t\t\t\t\tgen.WriteLine(\"ExpectWeak({0}, {1});\", p.sym.n, NewCondSet(s1));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase Node.any: {\n\t\t\t\t\tIndent(indent);\n\t\t\t\t\tint acc = Sets.Elements(p.set);\n\t\t\t\t\tif (tab.terminals.Count == (acc + 1) || (acc > 0 && Sets.Equals(p.set, isChecked))) {\n\t\t\t\t\t\t// either this ANY accepts any terminal (the + 1 = end of file), or exactly what's allowed here\n\t\t\t\t\t\tgen.WriteLine(\"Get();\");\n\t\t\t\t\t} else {\n\t\t\t\t\t\tGenErrorMsg(altErr, curSy);\n\t\t\t\t\t\tif (acc > 0) {\n\t\t\t\t\t\t\tgen.Write(\"if (\"); GenCond(p.set, p); gen.WriteLine(\") Get(); else SynErr({0});\", errorNr);\n\t\t\t\t\t\t} else gen.WriteLine(\"SynErr({0}); // ANY node that matches no symbol\", errorNr);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase Node.eps: break; // nothing\n\t\t\t\tcase Node.rslv: break; // nothing\n\t\t\t\tcase Node.sem: {\n\t\t\t\t\tCopySourcePart(p.pos, indent);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase Node.sync: {\n\t\t\t\t\tIndent(indent);\n\t\t\t\t\tGenErrorMsg(syncErr, curSy);\n\t\t\t\t\ts1 = (BitArray)p.set.Clone();\n\t\t\t\t\tgen.Write(\"while (!(\"); GenCond(s1, p); gen.Write(\")) {\");\n\t\t\t\t\tgen.Write(\"SynErr({0}); Get();\", errorNr); gen.WriteLine(\"}\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase Node.alt: {\n\t\t\t\t\ts1 = tab.First(p);\n\t\t\t\t\tbool equal = Sets.Equals(s1, isChecked);\n\t\t\t\t\tbool useSwitch = UseSwitch(p);\n\t\t\t\t\tif (useSwitch) { Indent(indent); gen.WriteLine(\"switch (la.kind) {\"); }\n\t\t\t\t\tp2 = p;\n\t\t\t\t\twhile (p2 != null) {\n\t\t\t\t\t\ts1 = tab.Expected(p2.sub, curSy);\n\t\t\t\t\t\tIndent(indent);\n\t\t\t\t\t\tif (useSwitch) { \n\t\t\t\t\t\t\tPutCaseLabels(s1); gen.WriteLine(\"{\");\n\t\t\t\t\t\t} else if (p2 == p) { \n\t\t\t\t\t\t\tgen.Write(\"if (\"); GenCond(s1, p2.sub); gen.WriteLine(\") {\"); \n\t\t\t\t\t\t} else if (p2.down == null && equal) { gen.WriteLine(\"} else {\");\n\t\t\t\t\t\t} else { \n\t\t\t\t\t\t\tgen.Write(\"} else if (\");  GenCond(s1, p2.sub); gen.WriteLine(\") {\"); \n\t\t\t\t\t\t}\n\t\t\t\t\t\tGenCode(p2.sub, indent + 1, s1);\n\t\t\t\t\t\tif (useSwitch) {\n\t\t\t\t\t\t\tIndent(indent); gen.WriteLine(\"\\tbreak;\");\n\t\t\t\t\t\t\tIndent(indent); gen.WriteLine(\"}\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\tp2 = p2.down;\n\t\t\t\t\t}\n\t\t\t\t\tIndent(indent);\n\t\t\t\t\tif (equal) {\n\t\t\t\t\t\tgen.WriteLine(\"}\");\n\t\t\t\t\t} else {\n\t\t\t\t\t\tGenErrorMsg(altErr, curSy);\n\t\t\t\t\t\tif (useSwitch) {\n\t\t\t\t\t\t\tgen.WriteLine(\"default: SynErr({0}); break;\", errorNr);\n\t\t\t\t\t\t\tIndent(indent); gen.WriteLine(\"}\");\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tgen.Write(\"} \"); gen.WriteLine(\"else SynErr({0});\", errorNr);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase Node.iter: {\n\t\t\t\t\tIndent(indent);\n\t\t\t\t\tp2 = p.sub;\n\t\t\t\t\tgen.Write(\"while (\");\n\t\t\t\t\tif (p2.typ == Node.wt) {\n\t\t\t\t\t\ts1 = tab.Expected(p2.next, curSy);\n\t\t\t\t\t\ts2 = tab.Expected(p.next, curSy);\n\t\t\t\t\t\tgen.Write(\"WeakSeparator({0},{1},{2}) \", p2.sym.n, NewCondSet(s1), NewCondSet(s2));\n\t\t\t\t\t\ts1 = new BitArray(tab.terminals.Count);  // for inner structure\n\t\t\t\t\t\tif (p2.up || p2.next == null) p2 = null; else p2 = p2.next;\n\t\t\t\t\t} else {\n\t\t\t\t\t\ts1 = tab.First(p2);\n\t\t\t\t\t\tGenCond(s1, p2);\n\t\t\t\t\t}\n\t\t\t\t\tgen.WriteLine(\") {\");\n\t\t\t\t\tGenCode(p2, indent + 1, s1);\n\t\t\t\t\tIndent(indent); gen.WriteLine(\"}\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase Node.opt:\n\t\t\t\t\ts1 = tab.First(p.sub);\n\t\t\t\t\tIndent(indent);\n\t\t\t\t\tgen.Write(\"if (\"); GenCond(s1, p.sub); gen.WriteLine(\") {\");\n\t\t\t\t\tGenCode(p.sub, indent + 1, s1);\n\t\t\t\t\tIndent(indent); gen.WriteLine(\"}\");\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (p.typ != Node.eps && p.typ != Node.sem && p.typ != Node.sync) \n\t\t\t\tisChecked.SetAll(false);  // = new BitArray(tab.terminals.Count);\n\t\t\tif (p.up) break;\n\t\t\tp = p.next;\n\t\t}\n\t}\n\t\n\tvoid GenTokens() {\n\t\tforeach (Symbol sym in tab.terminals) {\n\t\t\tif (Char.IsLetter(sym.name[0]))\n\t\t\t\tgen.WriteLine(\"\\tpublic const int _{0} = {1};\", sym.name, sym.n);\n\t\t}\n\t}\n\t\n\tvoid GenPragmas() {\n\t\tforeach (Symbol sym in tab.pragmas) {\n\t\t\tgen.WriteLine(\"\\tpublic const int _{0} = {1};\", sym.name, sym.n);\n\t\t}\n\t}\n\n\tvoid GenCodePragmas() {\n\t\tforeach (Symbol sym in tab.pragmas) {\n\t\t\tgen.WriteLine(\"\\t\\t\\t\\tif (la.kind == {0}) {{\", sym.n);\n\t\t\tCopySourcePart(sym.semPos, 4);\n\t\t\tgen.WriteLine(\"\\t\\t\\t\\t}\");\n\t\t}\n\t}\n\n\tvoid GenProductions() {\n\t\tforeach (Symbol sym in tab.nonterminals) {\n\t\t\tcurSy = sym;\n\t\t\tgen.Write(\"\\tvoid {0}(\", sym.name);\n\t\t\tCopySourcePart(sym.attrPos, 0);\n\t\t\tgen.WriteLine(\") {\");\n\t\t\tCopySourcePart(sym.semPos, 2);\n\t\t\tGenCode(sym.graph, 2, new BitArray(tab.terminals.Count));\n\t\t\tgen.WriteLine(\"\\t}\"); gen.WriteLine();\n\t\t}\n\t}\n\n\tvoid InitSets() {\n\t\tfor (int i = 0; i < symSet.Count; i++) {\n\t\t\tBitArray s = (BitArray)symSet[i];\n\t\t\tgen.Write(\"\\t\\t{\");\n\t\t\tint j = 0;\n\t\t\tforeach (Symbol sym in tab.terminals) {\n\t\t\t\tif (s[sym.n]) gen.Write(\"_T,\"); else gen.Write(\"_x,\");\n\t\t\t\t++j;\n\t\t\t\tif (j%4 == 0) gen.Write(\" \");\n\t\t\t}\n\t\t\tif (i == symSet.Count-1) gen.WriteLine(\"_x}\"); else gen.WriteLine(\"_x},\");\n\t\t}\n\t}\n\n\tpublic void WriteParser () {\n\t\tGenerator g = new Generator(tab);\n\t\tint oldPos = buffer.Pos;  // Pos is modified by CopySourcePart\n\t\tsymSet.Add(tab.allSyncSets);\n\n\t\tfram = g.OpenFrame(\"Parser.frame\");\n\t\tgen = g.OpenGen(\"Parser.cs\");\n\t\terr = new StringWriter();\n\t\tforeach (Symbol sym in tab.terminals) GenErrorMsg(tErr, sym);\n\t\t\n\t\tg.GenCopyright();\n\t\tg.SkipFramePart(\"-->begin\");\n\n\t\tif (usingPos != null) { CopySourcePart(usingPos, 0); gen.WriteLine(); }\n\t\tg.CopyFramePart(\"-->namespace\");\n\t\t/* AW open namespace, if it exists */\n\t\tif (tab.nsName != null && tab.nsName.Length > 0) {\n\t\t\tgen.WriteLine(\"namespace {0} {{\", tab.nsName);\n\t\t\tgen.WriteLine();\n\t\t}\n\t\tg.CopyFramePart(\"-->constants\");\n\t\tGenTokens(); /* ML 2002/09/07 write the token kinds */\n\t\tgen.WriteLine(\"\\tpublic const int maxT = {0};\", tab.terminals.Count-1);\n\t\tGenPragmas(); /* ML 2005/09/23 write the pragma kinds */\n\t\tg.CopyFramePart(\"-->declarations\"); CopySourcePart(tab.semDeclPos, 0);\n\t\tg.CopyFramePart(\"-->pragmas\"); GenCodePragmas();\n\t\tg.CopyFramePart(\"-->productions\"); GenProductions();\n\t\tg.CopyFramePart(\"-->parseRoot\"); gen.WriteLine(\"\\t\\t{0}();\", tab.gramSy.name); if (tab.checkEOF) gen.WriteLine(\"\\t\\tExpect(0);\");\n\t\tg.CopyFramePart(\"-->initialization\"); InitSets();\n\t\tg.CopyFramePart(\"-->errors\"); gen.Write(err.ToString());\n\t\tg.CopyFramePart(null);\n\t\t/* AW 2002-12-20 close namespace, if it exists */\n\t\tif (tab.nsName != null && tab.nsName.Length > 0) gen.Write(\"}\");\n\t\tgen.Close();\n\t\tbuffer.Pos = oldPos;\n\t}\n\t\n\tpublic void WriteStatistics () {\n\t\ttrace.WriteLine();\n\t\ttrace.WriteLine(\"{0} terminals\", tab.terminals.Count);\n\t\ttrace.WriteLine(\"{0} symbols\", tab.terminals.Count + tab.pragmas.Count +\n\t\t                               tab.nonterminals.Count);\n\t\ttrace.WriteLine(\"{0} nodes\", tab.nodes.Count);\n\t\ttrace.WriteLine(\"{0} sets\", symSet.Count);\n\t}\n\n\tpublic ParserGen (Parser parser) {\n\t\ttab = parser.tab;\n\t\terrors = parser.errors;\n\t\ttrace = parser.trace;\n\t\tbuffer = parser.scanner.buffer;\n\t\terrorNr = -1;\n\t\tusingPos = null;\n\t}\n\n} // end ParserGen\n\n} // end namespace\n"
  },
  {
    "path": "third_party/Coco/src/Scanner.cs",
    "content": "/*----------------------------------------------------------------------\nCompiler Generator Coco/R,\nCopyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz\nextended by M. Loeberbauer & A. Woess, Univ. of Linz\nwith improvements by Pat Terry, Rhodes University\n\nThis program is free software; you can redistribute it and/or modify it \nunder the terms of the GNU General Public License as published by the \nFree Software Foundation; either version 2, or (at your option) any \nlater version.\n\nThis program is distributed in the hope that it will be useful, but \nWITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY \nor FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License \nfor more details.\n\nYou should have received a copy of the GNU General Public License along \nwith this program; if not, write to the Free Software Foundation, Inc., \n59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n\nAs an exception, it is allowed to write an extension of Coco/R that is\nused as a plugin in non-free software.\n\nIf not otherwise stated, any source code generated by Coco/R (other than \nCoco/R itself) does not fall under the GNU General Public License.\n-----------------------------------------------------------------------*/\n\nusing System;\nusing System.IO;\nusing System.Collections.Generic;\n\nnamespace at.jku.ssw.Coco {\n\npublic class Token {\n\tpublic int kind;    // token kind\n\tpublic int pos;     // token position in bytes in the source text (starting at 0)\n\tpublic int charPos;  // token position in characters in the source text (starting at 0)\n\tpublic int col;     // token column (starting at 1)\n\tpublic int line;    // token line (starting at 1)\n\tpublic string val;  // token value\n\tpublic Token next;  // ML 2005-03-11 Tokens are kept in linked list\n}\n\n//-----------------------------------------------------------------------------------\n// Buffer\n//-----------------------------------------------------------------------------------\npublic class Buffer {\n\t// This Buffer supports the following cases:\n\t// 1) seekable stream (file)\n\t//    a) whole stream in buffer\n\t//    b) part of stream in buffer\n\t// 2) non seekable stream (network, console)\n\n\tpublic const int EOF = char.MaxValue + 1;\n\tconst int MIN_BUFFER_LENGTH = 1024; // 1KB\n\tconst int MAX_BUFFER_LENGTH = MIN_BUFFER_LENGTH * 64; // 64KB\n\tbyte[] buf;         // input buffer\n\tint bufStart;       // position of first byte in buffer relative to input stream\n\tint bufLen;         // length of buffer\n\tint fileLen;        // length of input stream (may change if the stream is no file)\n\tint bufPos;         // current position in buffer\n\tStream stream;      // input stream (seekable)\n\tbool isUserStream;  // was the stream opened by the user?\n\t\n\tpublic Buffer (Stream s, bool isUserStream) {\n\t\tstream = s; this.isUserStream = isUserStream;\n\t\t\n\t\tif (stream.CanSeek) {\n\t\t\tfileLen = (int) stream.Length;\n\t\t\tbufLen = Math.Min(fileLen, MAX_BUFFER_LENGTH);\n\t\t\tbufStart = Int32.MaxValue; // nothing in the buffer so far\n\t\t} else {\n\t\t\tfileLen = bufLen = bufStart = 0;\n\t\t}\n\n\t\tbuf = new byte[(bufLen>0) ? bufLen : MIN_BUFFER_LENGTH];\n\t\tif (fileLen > 0) Pos = 0; // setup buffer to position 0 (start)\n\t\telse bufPos = 0; // index 0 is already after the file, thus Pos = 0 is invalid\n\t\tif (bufLen == fileLen && stream.CanSeek) Close();\n\t}\n\t\n\tprotected Buffer(Buffer b) { // called in UTF8Buffer constructor\n\t\tbuf = b.buf;\n\t\tbufStart = b.bufStart;\n\t\tbufLen = b.bufLen;\n\t\tfileLen = b.fileLen;\n\t\tbufPos = b.bufPos;\n\t\tstream = b.stream;\n\t\t// keep destructor from closing the stream\n\t\tb.stream = null;\n\t\tisUserStream = b.isUserStream;\n\t}\n\n\t~Buffer() { Close(); }\n\t\n\tprotected void Close() {\n\t\tif (!isUserStream && stream != null) {\n\t\t\tstream.Close();\n\t\t\tstream = null;\n\t\t}\n\t}\n\t\n\tpublic virtual int Read () {\n\t\tif (bufPos < bufLen) {\n\t\t\treturn buf[bufPos++];\n\t\t} else if (Pos < fileLen) {\n\t\t\tPos = Pos; // shift buffer start to Pos\n\t\t\treturn buf[bufPos++];\n\t\t} else if (stream != null && !stream.CanSeek && ReadNextStreamChunk() > 0) {\n\t\t\treturn buf[bufPos++];\n\t\t} else {\n\t\t\treturn EOF;\n\t\t}\n\t}\n\n\tpublic int Peek () {\n\t\tint curPos = Pos;\n\t\tint ch = Read();\n\t\tPos = curPos;\n\t\treturn ch;\n\t}\n\t\n\t// beg .. begin, zero-based, inclusive, in byte\n\t// end .. end, zero-based, exclusive, in byte\n\tpublic string GetString (int beg, int end) {\n\t\tint len = 0;\n\t\tchar[] buf = new char[end - beg];\n\t\tint oldPos = Pos;\n\t\tPos = beg;\n\t\twhile (Pos < end) buf[len++] = (char) Read();\n\t\tPos = oldPos;\n\t\treturn new String(buf, 0, len);\n\t}\n\n\tpublic int Pos {\n\t\tget { return bufPos + bufStart; }\n\t\tset {\n\t\t\tif (value >= fileLen && stream != null && !stream.CanSeek) {\n\t\t\t\t// Wanted position is after buffer and the stream\n\t\t\t\t// is not seek-able e.g. network or console,\n\t\t\t\t// thus we have to read the stream manually till\n\t\t\t\t// the wanted position is in sight.\n\t\t\t\twhile (value >= fileLen && ReadNextStreamChunk() > 0);\n\t\t\t}\n\n\t\t\tif (value < 0 || value > fileLen) {\n\t\t\t\tthrow new FatalError(\"buffer out of bounds access, position: \" + value);\n\t\t\t}\n\n\t\t\tif (value >= bufStart && value < bufStart + bufLen) { // already in buffer\n\t\t\t\tbufPos = value - bufStart;\n\t\t\t} else if (stream != null) { // must be swapped in\n\t\t\t\tstream.Seek(value, SeekOrigin.Begin);\n\t\t\t\tbufLen = stream.Read(buf, 0, buf.Length);\n\t\t\t\tbufStart = value; bufPos = 0;\n\t\t\t} else {\n\t\t\t\t// set the position to the end of the file, Pos will return fileLen.\n\t\t\t\tbufPos = fileLen - bufStart;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// Read the next chunk of bytes from the stream, increases the buffer\n\t// if needed and updates the fields fileLen and bufLen.\n\t// Returns the number of bytes read.\n\tprivate int ReadNextStreamChunk() {\n\t\tint free = buf.Length - bufLen;\n\t\tif (free == 0) {\n\t\t\t// in the case of a growing input stream\n\t\t\t// we can neither seek in the stream, nor can we\n\t\t\t// foresee the maximum length, thus we must adapt\n\t\t\t// the buffer size on demand.\n\t\t\tbyte[] newBuf = new byte[bufLen * 2];\n\t\t\tArray.Copy(buf, newBuf, bufLen);\n\t\t\tbuf = newBuf;\n\t\t\tfree = bufLen;\n\t\t}\n\t\tint read = stream.Read(buf, bufLen, free);\n\t\tif (read > 0) {\n\t\t\tfileLen = bufLen = (bufLen + read);\n\t\t\treturn read;\n\t\t}\n\t\t// end of stream reached\n\t\treturn 0;\n\t}\n}\n\n//-----------------------------------------------------------------------------------\n// UTF8Buffer\n//-----------------------------------------------------------------------------------\npublic class UTF8Buffer: Buffer {\n\tpublic UTF8Buffer(Buffer b): base(b) {}\n\n\tpublic override int Read() {\n\t\tint ch;\n\t\tdo {\n\t\t\tch = base.Read();\n\t\t\t// until we find a utf8 start (0xxxxxxx or 11xxxxxx)\n\t\t} while ((ch >= 128) && ((ch & 0xC0) != 0xC0) && (ch != EOF));\n\t\tif (ch < 128 || ch == EOF) {\n\t\t\t// nothing to do, first 127 chars are the same in ascii and utf8\n\t\t\t// 0xxxxxxx or end of file character\n\t\t} else if ((ch & 0xF0) == 0xF0) {\n\t\t\t// 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx\n\t\t\tint c1 = ch & 0x07; ch = base.Read();\n\t\t\tint c2 = ch & 0x3F; ch = base.Read();\n\t\t\tint c3 = ch & 0x3F; ch = base.Read();\n\t\t\tint c4 = ch & 0x3F;\n\t\t\tch = (((((c1 << 6) | c2) << 6) | c3) << 6) | c4;\n\t\t} else if ((ch & 0xE0) == 0xE0) {\n\t\t\t// 1110xxxx 10xxxxxx 10xxxxxx\n\t\t\tint c1 = ch & 0x0F; ch = base.Read();\n\t\t\tint c2 = ch & 0x3F; ch = base.Read();\n\t\t\tint c3 = ch & 0x3F;\n\t\t\tch = (((c1 << 6) | c2) << 6) | c3;\n\t\t} else if ((ch & 0xC0) == 0xC0) {\n\t\t\t// 110xxxxx 10xxxxxx\n\t\t\tint c1 = ch & 0x1F; ch = base.Read();\n\t\t\tint c2 = ch & 0x3F;\n\t\t\tch = (c1 << 6) | c2;\n\t\t}\n\t\treturn ch;\n\t}\n}\n\n//-----------------------------------------------------------------------------------\n// Scanner\n//-----------------------------------------------------------------------------------\npublic class Scanner {\n\tconst char EOL = '\\n';\n\tconst int eofSym = 0; /* pdt */\n\tconst int maxT = 41;\n\tconst int noSym = 41;\n\n\n\tpublic Buffer buffer; // scanner buffer\n\t\n\tToken t;          // current token\n\tint ch;           // current input character\n\tint pos;          // byte position of current character\n\tint charPos;      // position by unicode characters starting with 0\n\tint col;          // column number of current character\n\tint line;         // line number of current character\n\tint oldEols;      // EOLs that appeared in a comment;\n\tstatic readonly Dictionary<int, int> start; // maps first token character to start state\n\n\tToken tokens;     // list of tokens already peeked (first token is a dummy)\n\tToken pt;         // current peek token\n\t\n\tchar[] tval = new char[128]; // text of current token\n\tint tlen;         // length of current token\n\t\n\tstatic Scanner() {\n\t\tstart = new Dictionary<int, int>(128);\n\t\tfor (int i = 65; i <= 90; ++i) start[i] = 1;\n\t\tfor (int i = 95; i <= 95; ++i) start[i] = 1;\n\t\tfor (int i = 97; i <= 122; ++i) start[i] = 1;\n\t\tfor (int i = 48; i <= 57; ++i) start[i] = 2;\n\t\tstart[34] = 12; \n\t\tstart[39] = 5; \n\t\tstart[36] = 13; \n\t\tstart[61] = 16; \n\t\tstart[46] = 31; \n\t\tstart[43] = 17; \n\t\tstart[45] = 18; \n\t\tstart[60] = 32; \n\t\tstart[62] = 20; \n\t\tstart[124] = 23; \n\t\tstart[40] = 33; \n\t\tstart[41] = 24; \n\t\tstart[91] = 25; \n\t\tstart[93] = 26; \n\t\tstart[123] = 27; \n\t\tstart[125] = 28; \n\t\tstart[Buffer.EOF] = -1;\n\n\t}\n\t\n\tpublic Scanner (string fileName) {\n\t\ttry {\n\t\t\tStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);\n\t\t\tbuffer = new Buffer(stream, false);\n\t\t\tInit();\n\t\t} catch (IOException) {\n\t\t\tthrow new FatalError(\"Cannot open file \" + fileName);\n\t\t}\n\t}\n\t\n\tpublic Scanner (Stream s) {\n\t\tbuffer = new Buffer(s, true);\n\t\tInit();\n\t}\n\t\n\tvoid Init() {\n\t\tpos = -1; line = 1; col = 0; charPos = -1;\n\t\toldEols = 0;\n\t\tNextCh();\n\t\tif (ch == 0xEF) { // check optional byte order mark for UTF-8\n\t\t\tNextCh(); int ch1 = ch;\n\t\t\tNextCh(); int ch2 = ch;\n\t\t\tif (ch1 != 0xBB || ch2 != 0xBF) {\n\t\t\t\tthrow new FatalError(String.Format(\"illegal byte order mark: EF {0,2:X} {1,2:X}\", ch1, ch2));\n\t\t\t}\n\t\t\tbuffer = new UTF8Buffer(buffer); col = 0; charPos = -1;\n\t\t\tNextCh();\n\t\t}\n\t\tpt = tokens = new Token();  // first token is a dummy\n\t}\n\t\n\tvoid NextCh() {\n\t\tif (oldEols > 0) { ch = EOL; oldEols--; } \n\t\telse {\n\t\t\tpos = buffer.Pos;\n\t\t\t// buffer reads unicode chars, if UTF8 has been detected\n\t\t\tch = buffer.Read(); col++; charPos++;\n\t\t\t// replace isolated '\\r' by '\\n' in order to make\n\t\t\t// eol handling uniform across Windows, Unix and Mac\n\t\t\tif (ch == '\\r' && buffer.Peek() != '\\n') ch = EOL;\n\t\t\tif (ch == EOL) { line++; col = 0; }\n\t\t}\n\n\t}\n\n\tvoid AddCh() {\n\t\tif (tlen >= tval.Length) {\n\t\t\tchar[] newBuf = new char[2 * tval.Length];\n\t\t\tArray.Copy(tval, 0, newBuf, 0, tval.Length);\n\t\t\ttval = newBuf;\n\t\t}\n\t\tif (ch != Buffer.EOF) {\n\t\t\ttval[tlen++] = (char) ch;\n\t\t\tNextCh();\n\t\t}\n\t}\n\n\n\n\tbool Comment0() {\n\t\tint level = 1, pos0 = pos, line0 = line, col0 = col, charPos0 = charPos;\n\t\tNextCh();\n\t\tif (ch == '/') {\n\t\t\tNextCh();\n\t\t\tfor(;;) {\n\t\t\t\tif (ch == 10) {\n\t\t\t\t\tlevel--;\n\t\t\t\t\tif (level == 0) { oldEols = line - line0; NextCh(); return true; }\n\t\t\t\t\tNextCh();\n\t\t\t\t} else if (ch == Buffer.EOF) return false;\n\t\t\t\telse NextCh();\n\t\t\t}\n\t\t} else {\n\t\t\tbuffer.Pos = pos0; NextCh(); line = line0; col = col0; charPos = charPos0;\n\t\t}\n\t\treturn false;\n\t}\n\n\tbool Comment1() {\n\t\tint level = 1, pos0 = pos, line0 = line, col0 = col, charPos0 = charPos;\n\t\tNextCh();\n\t\tif (ch == '*') {\n\t\t\tNextCh();\n\t\t\tfor(;;) {\n\t\t\t\tif (ch == '*') {\n\t\t\t\t\tNextCh();\n\t\t\t\t\tif (ch == '/') {\n\t\t\t\t\t\tlevel--;\n\t\t\t\t\t\tif (level == 0) { oldEols = line - line0; NextCh(); return true; }\n\t\t\t\t\t\tNextCh();\n\t\t\t\t\t}\n\t\t\t\t} else if (ch == '/') {\n\t\t\t\t\tNextCh();\n\t\t\t\t\tif (ch == '*') {\n\t\t\t\t\t\tlevel++; NextCh();\n\t\t\t\t\t}\n\t\t\t\t} else if (ch == Buffer.EOF) return false;\n\t\t\t\telse NextCh();\n\t\t\t}\n\t\t} else {\n\t\t\tbuffer.Pos = pos0; NextCh(); line = line0; col = col0; charPos = charPos0;\n\t\t}\n\t\treturn false;\n\t}\n\n\n\tvoid CheckLiteral() {\n\t\tswitch (t.val) {\n\t\t\tcase \"COMPILER\": t.kind = 6; break;\n\t\t\tcase \"IGNORECASE\": t.kind = 7; break;\n\t\t\tcase \"CHARACTERS\": t.kind = 8; break;\n\t\t\tcase \"TOKENS\": t.kind = 9; break;\n\t\t\tcase \"PRAGMAS\": t.kind = 10; break;\n\t\t\tcase \"COMMENTS\": t.kind = 11; break;\n\t\t\tcase \"FROM\": t.kind = 12; break;\n\t\t\tcase \"TO\": t.kind = 13; break;\n\t\t\tcase \"NESTED\": t.kind = 14; break;\n\t\t\tcase \"IGNORE\": t.kind = 15; break;\n\t\t\tcase \"PRODUCTIONS\": t.kind = 16; break;\n\t\t\tcase \"END\": t.kind = 19; break;\n\t\t\tcase \"ANY\": t.kind = 23; break;\n\t\t\tcase \"WEAK\": t.kind = 29; break;\n\t\t\tcase \"SYNC\": t.kind = 36; break;\n\t\t\tcase \"IF\": t.kind = 37; break;\n\t\t\tcase \"CONTEXT\": t.kind = 38; break;\n\t\t\tdefault: break;\n\t\t}\n\t}\n\n\tToken NextToken() {\n\t\twhile (ch == ' ' ||\n\t\t\tch >= 9 && ch <= 10 || ch == 13\n\t\t) NextCh();\n\t\tif (ch == '/' && Comment0() ||ch == '/' && Comment1()) return NextToken();\n\t\tint recKind = noSym;\n\t\tint recEnd = pos;\n\t\tt = new Token();\n\t\tt.pos = pos; t.col = col; t.line = line; t.charPos = charPos;\n\t\tint state;\n\t\tstate = start.ContainsKey(ch) ? start[ch] : 0;\n\t\ttlen = 0; AddCh();\n\t\t\n\t\tswitch (state) {\n\t\t\tcase -1: { t.kind = eofSym; break; } // NextCh already done\n\t\t\tcase 0: {\n\t\t\t\tif (recKind != noSym) {\n\t\t\t\t\ttlen = recEnd - t.pos;\n\t\t\t\t\tSetScannerBehindT();\n\t\t\t\t}\n\t\t\t\tt.kind = recKind; break;\n\t\t\t} // NextCh already done\n\t\t\tcase 1:\n\t\t\t\trecEnd = pos; recKind = 1;\n\t\t\t\tif (ch >= '0' && ch <= '9' || ch >= 'A' && ch <= 'Z' || ch == '_' || ch >= 'a' && ch <= 'z') {AddCh(); goto case 1;}\n\t\t\t\telse {t.kind = 1; t.val = new String(tval, 0, tlen); CheckLiteral(); return t;}\n\t\t\tcase 2:\n\t\t\t\trecEnd = pos; recKind = 2;\n\t\t\t\tif (ch >= '0' && ch <= '9') {AddCh(); goto case 2;}\n\t\t\t\telse {t.kind = 2; break;}\n\t\t\tcase 3:\n\t\t\t\t{t.kind = 3; break;}\n\t\t\tcase 4:\n\t\t\t\t{t.kind = 4; break;}\n\t\t\tcase 5:\n\t\t\t\tif (ch <= 9 || ch >= 11 && ch <= 12 || ch >= 14 && ch <= '&' || ch >= '(' && ch <= '[' || ch >= ']' && ch <= 65535) {AddCh(); goto case 6;}\n\t\t\t\telse if (ch == 92) {AddCh(); goto case 7;}\n\t\t\t\telse {goto case 0;}\n\t\t\tcase 6:\n\t\t\t\tif (ch == 39) {AddCh(); goto case 9;}\n\t\t\t\telse {goto case 0;}\n\t\t\tcase 7:\n\t\t\t\tif (ch >= ' ' && ch <= '~') {AddCh(); goto case 8;}\n\t\t\t\telse {goto case 0;}\n\t\t\tcase 8:\n\t\t\t\tif (ch >= '0' && ch <= '9' || ch >= 'a' && ch <= 'f') {AddCh(); goto case 8;}\n\t\t\t\telse if (ch == 39) {AddCh(); goto case 9;}\n\t\t\t\telse {goto case 0;}\n\t\t\tcase 9:\n\t\t\t\t{t.kind = 5; break;}\n\t\t\tcase 10:\n\t\t\t\trecEnd = pos; recKind = 42;\n\t\t\t\tif (ch >= '0' && ch <= '9' || ch >= 'A' && ch <= 'Z' || ch == '_' || ch >= 'a' && ch <= 'z') {AddCh(); goto case 10;}\n\t\t\t\telse {t.kind = 42; break;}\n\t\t\tcase 11:\n\t\t\t\trecEnd = pos; recKind = 43;\n\t\t\t\tif (ch >= '-' && ch <= '.' || ch >= '0' && ch <= ':' || ch >= 'A' && ch <= 'Z' || ch == '_' || ch >= 'a' && ch <= 'z') {AddCh(); goto case 11;}\n\t\t\t\telse {t.kind = 43; break;}\n\t\t\tcase 12:\n\t\t\t\tif (ch <= 9 || ch >= 11 && ch <= 12 || ch >= 14 && ch <= '!' || ch >= '#' && ch <= '[' || ch >= ']' && ch <= 65535) {AddCh(); goto case 12;}\n\t\t\t\telse if (ch == 10 || ch == 13) {AddCh(); goto case 4;}\n\t\t\t\telse if (ch == '\"') {AddCh(); goto case 3;}\n\t\t\t\telse if (ch == 92) {AddCh(); goto case 14;}\n\t\t\t\telse {goto case 0;}\n\t\t\tcase 13:\n\t\t\t\trecEnd = pos; recKind = 42;\n\t\t\t\tif (ch >= '0' && ch <= '9') {AddCh(); goto case 10;}\n\t\t\t\telse if (ch >= 'A' && ch <= 'Z' || ch == '_' || ch >= 'a' && ch <= 'z') {AddCh(); goto case 15;}\n\t\t\t\telse {t.kind = 42; break;}\n\t\t\tcase 14:\n\t\t\t\tif (ch >= ' ' && ch <= '~') {AddCh(); goto case 12;}\n\t\t\t\telse {goto case 0;}\n\t\t\tcase 15:\n\t\t\t\trecEnd = pos; recKind = 42;\n\t\t\t\tif (ch >= '0' && ch <= '9') {AddCh(); goto case 10;}\n\t\t\t\telse if (ch >= 'A' && ch <= 'Z' || ch == '_' || ch >= 'a' && ch <= 'z') {AddCh(); goto case 15;}\n\t\t\t\telse if (ch == '=') {AddCh(); goto case 11;}\n\t\t\t\telse {t.kind = 42; break;}\n\t\t\tcase 16:\n\t\t\t\t{t.kind = 17; break;}\n\t\t\tcase 17:\n\t\t\t\t{t.kind = 20; break;}\n\t\t\tcase 18:\n\t\t\t\t{t.kind = 21; break;}\n\t\t\tcase 19:\n\t\t\t\t{t.kind = 22; break;}\n\t\t\tcase 20:\n\t\t\t\t{t.kind = 25; break;}\n\t\t\tcase 21:\n\t\t\t\t{t.kind = 26; break;}\n\t\t\tcase 22:\n\t\t\t\t{t.kind = 27; break;}\n\t\t\tcase 23:\n\t\t\t\t{t.kind = 28; break;}\n\t\t\tcase 24:\n\t\t\t\t{t.kind = 31; break;}\n\t\t\tcase 25:\n\t\t\t\t{t.kind = 32; break;}\n\t\t\tcase 26:\n\t\t\t\t{t.kind = 33; break;}\n\t\t\tcase 27:\n\t\t\t\t{t.kind = 34; break;}\n\t\t\tcase 28:\n\t\t\t\t{t.kind = 35; break;}\n\t\t\tcase 29:\n\t\t\t\t{t.kind = 39; break;}\n\t\t\tcase 30:\n\t\t\t\t{t.kind = 40; break;}\n\t\t\tcase 31:\n\t\t\t\trecEnd = pos; recKind = 18;\n\t\t\t\tif (ch == '.') {AddCh(); goto case 19;}\n\t\t\t\telse if (ch == '>') {AddCh(); goto case 22;}\n\t\t\t\telse if (ch == ')') {AddCh(); goto case 30;}\n\t\t\t\telse {t.kind = 18; break;}\n\t\t\tcase 32:\n\t\t\t\trecEnd = pos; recKind = 24;\n\t\t\t\tif (ch == '.') {AddCh(); goto case 21;}\n\t\t\t\telse {t.kind = 24; break;}\n\t\t\tcase 33:\n\t\t\t\trecEnd = pos; recKind = 30;\n\t\t\t\tif (ch == '.') {AddCh(); goto case 29;}\n\t\t\t\telse {t.kind = 30; break;}\n\n\t\t}\n\t\tt.val = new String(tval, 0, tlen);\n\t\treturn t;\n\t}\n\t\n\tprivate void SetScannerBehindT() {\n\t\tbuffer.Pos = t.pos;\n\t\tNextCh();\n\t\tline = t.line; col = t.col; charPos = t.charPos;\n\t\tfor (int i = 0; i < tlen; i++) NextCh();\n\t}\n\t\n\t// get the next token (possibly a token already seen during peeking)\n\tpublic Token Scan () {\n\t\tif (tokens.next == null) {\n\t\t\treturn NextToken();\n\t\t} else {\n\t\t\tpt = tokens = tokens.next;\n\t\t\treturn tokens;\n\t\t}\n\t}\n\n\t// peek for the next token, ignore pragmas\n\tpublic Token Peek () {\n\t\tdo {\n\t\t\tif (pt.next == null) {\n\t\t\t\tpt.next = NextToken();\n\t\t\t}\n\t\t\tpt = pt.next;\n\t\t} while (pt.kind > maxT); // skip pragmas\n\t\n\t\treturn pt;\n\t}\n\n\t// make sure that peeking starts at the current scan position\n\tpublic void ResetPeek () { pt = tokens; }\n\n} // end Scanner\n\n}"
  },
  {
    "path": "third_party/Coco/src/Scanner.frame",
    "content": "/*----------------------------------------------------------------------\nCompiler Generator Coco/R,\nCopyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz\nextended by M. Loeberbauer & A. Woess, Univ. of Linz\nwith improvements by Pat Terry, Rhodes University\n\nThis program is free software; you can redistribute it and/or modify it\nunder the terms of the GNU General Public License as published by the\nFree Software Foundation; either version 2, or (at your option) any\nlater version.\n\nThis program is distributed in the hope that it will be useful, but\nWITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\nor FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\nfor more details.\n\nYou should have received a copy of the GNU General Public License along\nwith this program; if not, write to the Free Software Foundation, Inc.,\n59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n\nAs an exception, it is allowed to write an extension of Coco/R that is\nused as a plugin in non-free software.\n\nIf not otherwise stated, any source code generated by Coco/R (other than\nCoco/R itself) does not fall under the GNU General Public License.\n-----------------------------------------------------------------------*/\n-->begin\n/* This file (Scanner.cs) is generated from Dafny.atg by the Coco/R\n * parser generator. Do not edit this file directly. Instead, make\n * changes to Dafny.atg and then rebuild using the Makefile found\n * in the same directory as Dafny.atg.\n */\n\nusing System;\nusing System.IO;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Text;\nusing System.Diagnostics.Contracts;\nusing Microsoft.Boogie;\n\n\n-->namespace\n\n//-----------------------------------------------------------------------------------\n// Buffer\n//-----------------------------------------------------------------------------------\npublic class Buffer {\n  // This Buffer supports the following cases:\n  // 1) seekable stream (file)\n  //    a) whole stream in buffer\n  //    b) part of stream in buffer\n  // 2) non seekable stream (network, console)\n\n  public const int EOF = 65535 + 1; // char.MaxValue + 1;\n  const int MIN_BUFFER_LENGTH = 1024; // 1KB\n  const int MAX_BUFFER_LENGTH = MIN_BUFFER_LENGTH * 64; // 64KB\n  byte[]/*!*/ buf;         // input buffer\n  int bufStart;       // position of first byte in buffer relative to input stream\n  int bufLen;         // length of buffer\n  int fileLen;        // length of input stream (may change if the stream is no file)\n  int bufPos;         // current position in buffer\n  Stream/*!*/ stream;      // input stream (seekable)\n  bool isUserStream;  // was the stream opened by the user?\n\n  [ContractInvariantMethod]\n  void ObjectInvariant(){\n    Contract.Invariant(buf != null);\n    Contract.Invariant(stream != null);\n  }\n\n//  [NotDelayed]\n  public Buffer (Stream/*!*/ s, bool isUserStream) : base() {\n    Contract.Requires(s != null);\n    stream = s; this.isUserStream = isUserStream;\n\n    int fl, bl;\n    if (s.CanSeek) {\n      fl = (int) s.Length;\n      bl = fl < MAX_BUFFER_LENGTH ? fl : MAX_BUFFER_LENGTH; // Math.Min(fileLen, MAX_BUFFER_LENGTH);\n      bufStart = Int32.MaxValue; // nothing in the buffer so far\n    } else {\n      fl = bl = bufStart = 0;\n    }\n\n    buf = new byte[(bl>0) ? bl : MIN_BUFFER_LENGTH];\n    fileLen = fl;  bufLen = bl;\n\n    if (fileLen > 0) Pos = 0; // setup buffer to position 0 (start)\n    else bufPos = 0; // index 0 is already after the file, thus Pos = 0 is invalid\n    if (bufLen == fileLen && s.CanSeek) Close();\n  }\n\n  protected Buffer(Buffer/*!*/ b) { // called in UTF8Buffer constructor\n    Contract.Requires(b != null);\n    buf = b.buf;\n    bufStart = b.bufStart;\n    bufLen = b.bufLen;\n    fileLen = b.fileLen;\n    bufPos = b.bufPos;\n    stream = b.stream;\n    // keep destructor from closing the stream\n    //b.stream = null;\n    isUserStream = b.isUserStream;\n    // keep destructor from closing the stream\n    b.isUserStream = true;\n  }\n\n  ~Buffer() { Close(); }\n\n  protected void Close() {\n    if (!isUserStream && stream != null) {\n      stream.Close();\n      //stream = null;\n    }\n  }\n\n  public virtual int Read () {\n    if (bufPos < bufLen) {\n      return buf[bufPos++];\n    } else if (Pos < fileLen) {\n      Pos = Pos; // shift buffer start to Pos\n      return buf[bufPos++];\n    } else if (stream != null && !stream.CanSeek && ReadNextStreamChunk() > 0) {\n      return buf[bufPos++];\n    } else {\n      return EOF;\n    }\n  }\n\n  public int Peek () {\n    int curPos = Pos;\n    int ch = Read();\n    Pos = curPos;\n    return ch;\n  }\n\n  public string/*!*/ GetString (int beg, int end) {\n    Contract.Ensures(Contract.Result<string>() != null);\n    int len = 0;\n    char[] buf = new char[end - beg];\n    int oldPos = Pos;\n    Pos = beg;\n    while (Pos < end) buf[len++] = (char) Read();\n    Pos = oldPos;\n    return new String(buf, 0, len);\n  }\n\n  public int Pos {\n    get { return bufPos + bufStart; }\n    set {\n      if (value >= fileLen && stream != null && !stream.CanSeek) {\n        // Wanted position is after buffer and the stream\n        // is not seek-able e.g. network or console,\n        // thus we have to read the stream manually till\n        // the wanted position is in sight.\n        while (value >= fileLen && ReadNextStreamChunk() > 0);\n      }\n\n      if (value < 0 || value > fileLen) {\n        throw new FatalError(\"buffer out of bounds access, position: \" + value);\n      }\n\n      if (value >= bufStart && value < bufStart + bufLen) { // already in buffer\n        bufPos = value - bufStart;\n      } else if (stream != null) { // must be swapped in\n        stream.Seek(value, SeekOrigin.Begin);\n        bufLen = stream.Read(buf, 0, buf.Length);\n        bufStart = value; bufPos = 0;\n      } else {\n        // set the position to the end of the file, Pos will return fileLen.\n        bufPos = fileLen - bufStart;\n      }\n    }\n  }\n\n  // Read the next chunk of bytes from the stream, increases the buffer\n  // if needed and updates the fields fileLen and bufLen.\n  // Returns the number of bytes read.\n  private int ReadNextStreamChunk() {\n    int free = buf.Length - bufLen;\n    if (free == 0) {\n      // in the case of a growing input stream\n      // we can neither seek in the stream, nor can we\n      // foresee the maximum length, thus we must adapt\n      // the buffer size on demand.\n      byte[] newBuf = new byte[bufLen * 2];\n      Array.Copy(buf, newBuf, bufLen);\n      buf = newBuf;\n      free = bufLen;\n    }\n    int read = stream.Read(buf, bufLen, free);\n    if (read > 0) {\n      fileLen = bufLen = (bufLen + read);\n      return read;\n    }\n    // end of stream reached\n    return 0;\n  }\n}\n\n//-----------------------------------------------------------------------------------\n// UTF8Buffer\n//-----------------------------------------------------------------------------------\npublic class UTF8Buffer: Buffer {\n  public UTF8Buffer(Buffer/*!*/ b): base(b) {Contract.Requires(b != null);}\n\n  public override int Read() {\n    int ch;\n    do {\n      ch = base.Read();\n      // until we find a utf8 start (0xxxxxxx or 11xxxxxx)\n    } while ((ch >= 128) && ((ch & 0xC0) != 0xC0) && (ch != EOF));\n    if (ch < 128 || ch == EOF) {\n      // nothing to do, first 127 chars are the same in ascii and utf8\n      // 0xxxxxxx or end of file character\n    } else if ((ch & 0xF0) == 0xF0) {\n      // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx\n      int c1 = ch & 0x07; ch = base.Read();\n      int c2 = ch & 0x3F; ch = base.Read();\n      int c3 = ch & 0x3F; ch = base.Read();\n      int c4 = ch & 0x3F;\n      ch = (((((c1 << 6) | c2) << 6) | c3) << 6) | c4;\n    } else if ((ch & 0xE0) == 0xE0) {\n      // 1110xxxx 10xxxxxx 10xxxxxx\n      int c1 = ch & 0x0F; ch = base.Read();\n      int c2 = ch & 0x3F; ch = base.Read();\n      int c3 = ch & 0x3F;\n      ch = (((c1 << 6) | c2) << 6) | c3;\n    } else if ((ch & 0xC0) == 0xC0) {\n      // 110xxxxx 10xxxxxx\n      int c1 = ch & 0x1F; ch = base.Read();\n      int c2 = ch & 0x3F;\n      ch = (c1 << 6) | c2;\n    }\n    return ch;\n  }\n}\n\n//-----------------------------------------------------------------------------------\n// Scanner\n//-----------------------------------------------------------------------------------\npublic class Scanner {\n  const char EOL = '\\n';\n  const int eofSym = 0; /* pdt */\n-->declarations\n\n  [ContractInvariantMethod]\n  void objectInvariant(){\n    Contract.Invariant(this._buffer != null);\n    Contract.Invariant(t != null);\n    Contract.Invariant(start != null);\n    Contract.Invariant(tokens != null);\n    Contract.Invariant(pt != null);\n    Contract.Invariant(tval != null);\n    Contract.Invariant(Filename != null);\n    Contract.Invariant(FullFilename != null);\n    Contract.Invariant(errorHandler != null);\n  }\n\n  private Buffer/*!*/ _buffer; // scanner buffer\n\n  public Buffer/*!*/ buffer {\n    get {\n      Contract.Ensures(Contract.Result<Buffer>() != null);\n      return this._buffer;\n    }\n    set {\n      Contract.Requires(value != null);\n      this._buffer = value;\n    }\n  }\n\n  Token/*!*/ t;          // current token\n  int ch;           // current input character\n  int pos;          // byte position of current character\n  int charPos;\n  int col;          // column number of current character\n  int line;         // line number of current character\n  int oldEols;      // EOLs that appeared in a comment;\n  static readonly Hashtable/*!*/ start; // maps first token character to start state\n\n  Token/*!*/ tokens;     // list of tokens already peeked (first token is a dummy)\n  Token/*!*/ pt;         // current peek token\n\n  char[]/*!*/ tval = new char[128]; // text of current token\n  int tlen;         // length of current token\n\n  private string/*!*/ Filename;\n  private Errors/*!*/ errorHandler;\n\n  internal string/*!*/ FullFilename { get; private set; }\n\n  static Scanner() {\n    start = new Hashtable(128);\n-->initialization\n  }\n\n//  [NotDelayed]\n  public Scanner (string/*!*/ fullFilename, string/*!*/ fileName, Errors/*!*/ errorHandler, bool useBaseName = false) : base() {\n    Contract.Requires(fileName != null);\n    Contract.Requires(errorHandler != null);\n    this.errorHandler = errorHandler;\n    pt = tokens = new Token();  // first token is a dummy\n    t = new Token(); // dummy because t is a non-null field\n    try {\n      Stream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);\n      this._buffer = new Buffer(stream, false);\n      this.FullFilename = fullFilename;\n      Filename = useBaseName? GetBaseName(fileName): fileName;\n      Init(1);\n    } catch (IOException) {\n      throw new FatalError(\"Cannot open file \" + fileName);\n    }\n  }\n\n//  [NotDelayed]\n  public Scanner (Stream/*!*/ s, Errors/*!*/ errorHandler, string/*!*/ fullFilename, string/*!*/ fileName, int lineNumber = 1, bool useBaseName = false) : base() {\n    Contract.Requires(s != null);\n    Contract.Requires(errorHandler != null);\n    Contract.Requires(fileName != null);\n    pt = tokens = new Token();  // first token is a dummy\n    t = new Token(); // dummy because t is a non-null field\n    this._buffer = new Buffer(s, true);\n    this.errorHandler = errorHandler;\n    this.FullFilename = fullFilename;\n    this.Filename = useBaseName? GetBaseName(fileName) : fileName;\n    Init(lineNumber);\n  }\n\n  string GetBaseName(string fileName) {\n    return System.IO.Path.GetFileName(fileName); // Return basename\n  }\n\n  void Init(int lineNumber) {\n    pos = -1; line = lineNumber; col = 0;\n    oldEols = 0;\n    NextCh();\n    if (ch == 0xEF) { // check optional byte order mark for UTF-8\n      NextCh(); int ch1 = ch;\n      NextCh(); int ch2 = ch;\n      if (ch1 != 0xBB || ch2 != 0xBF) {\n        throw new FatalError(String.Format(\"illegal byte order mark: EF {0,2:X} {1,2:X}\", ch1, ch2));\n      }\n      buffer = new UTF8Buffer(buffer); col = 0;\n      NextCh();\n    }\n    pt = tokens = new Token();  // first token is a dummy\n  }\n\n  string/*!*/ ReadToEOL(){\n  Contract.Ensures(Contract.Result<string>() != null);\n    int p = buffer.Pos;\n    int ch = buffer.Read();\n    // replace isolated '\\r' by '\\n' in order to make\n    // eol handling uniform across Windows, Unix and Mac\n    if (ch == '\\r' && buffer.Peek() != '\\n') ch = EOL;\n    while (ch != EOL && ch != Buffer.EOF){\n    ch = buffer.Read();\n    // replace isolated '\\r' by '\\n' in order to make\n    // eol handling uniform across Windows, Unix and Mac\n    if (ch == '\\r' && buffer.Peek() != '\\n') ch = EOL;\n    }\n    string/*!*/ s = buffer.GetString(p, buffer.Pos);\n    Contract.Assert(s!=null);\n    return s;\n  }\n\n  void NextCh() {\n    if (oldEols > 0) { ch = EOL; oldEols--; }\n    else {\n//      pos = buffer.Pos;\n//      ch = buffer.Read(); col++;\n//      // replace isolated '\\r' by '\\n' in order to make\n//      // eol handling uniform across Windows, Unix and Mac\n//      if (ch == '\\r' && buffer.Peek() != '\\n') ch = EOL;\n//      if (ch == EOL) { line++; col = 0; }\n\n      while (true) {\n        pos = buffer.Pos;\n        ch = buffer.Read(); col++;\n        // replace isolated '\\r' by '\\n' in order to make\n        // eol handling uniform across Windows, Unix and Mac\n        if (ch == '\\r' && buffer.Peek() != '\\n') ch = EOL;\n        if (ch == EOL) {\n          line++; col = 0;\n        } else if (ch == '#' && col == 1) {\n          int prLine = line;\n          int prColumn = 0;\n\n          string/*!*/ hashLine = ReadToEOL();\n          Contract.Assert(hashLine!=null);\n          col = 0;\n          line++;\n\n          hashLine = hashLine.TrimEnd(null);\n          if (hashLine.StartsWith(\"line \") || hashLine == \"line\") {\n          // parse #line pragma:  #line num [filename]\n          string h = hashLine.Substring(4).TrimStart(null);\n          int x = h.IndexOf(' ');\n          if (x == -1) {\n            x = h.Length;  // this will be convenient below when we look for a filename\n          }\n          try {\n            int li = int.Parse(h.Substring(0, x));\n\n            h = h.Substring(x).Trim();\n\n            // act on #line\n            line = li;\n            if (h.Length != 0) {\n            // a filename was specified\n            Filename = h;\n            }\n            continue;  // successfully parsed and acted on the #line pragma\n\n          } catch (FormatException) {\n            // just fall down through to produce an error message\n          }\n          this.errorHandler.SemErr(Filename, prLine, prColumn, \"Malformed (#line num [filename]) pragma: #\" + hashLine);\n          continue;\n          }\n\n          this.errorHandler.SemErr(Filename, prLine, prColumn, \"Unrecognized pragma: #\" + hashLine);\n          continue;\n        }\n        return;\n        }\n\n\n    }\n-->casing1\n  }\n\n  void AddCh() {\n    if (tlen >= tval.Length) {\n      char[] newBuf = new char[2 * tval.Length];\n      Array.Copy(tval, 0, newBuf, 0, tval.Length);\n      tval = newBuf;\n    }\n    if (ch != Buffer.EOF) {\n-->casing2\n      NextCh();\n    }\n  }\n\n\n-->comments\n\n  public void CheckLiteral() {\n-->literals\n  }\n\n  Token/*!*/ NextToken() {\n    Contract.Ensures(Contract.Result<Token>() != null);\n    while (ch == ' ' ||\n-->scan1\n    ) NextCh();\n-->scan2\n    int recKind = noSym;\n    int recEnd = pos;\n    t = new Token();\n    t.pos = pos; t.col = col; t.line = line;\n    t.filename = this.Filename;\n    int state;\n    if (start.ContainsKey(ch)) {\n      Contract.Assert(start[ch] != null);\n      state = (int) start[ch];\n    }\n    else { state = 0; }\n    tlen = 0; AddCh();\n\n    switch (state) {\n      case -1: { t.kind = eofSym; break; } // NextCh already done\n      case 0: {\n        if (recKind != noSym) {\n          tlen = recEnd - t.pos;\n          SetScannerBehindT();\n        }\n        t.kind = recKind; break;\n      } // NextCh already done\n-->scan3\n    }\n    t.val = new String(tval, 0, tlen);\n    return t;\n  }\n\n  private void SetScannerBehindT() {\n    buffer.Pos = t.pos;\n    NextCh();\n    line = t.line; col = t.col;\n    for (int i = 0; i < tlen; i++) NextCh();\n  }\n\n  // get the next token (possibly a token already seen during peeking)\n  public Token/*!*/ Scan () {\n   Contract.Ensures(Contract.Result<Token>() != null);\n    if (tokens.next == null) {\n      return NextToken();\n    } else {\n      pt = tokens = tokens.next;\n      return tokens;\n    }\n  }\n\n  // peek for the next token, ignore pragmas\n  public Token/*!*/ Peek () {\n    Contract.Ensures(Contract.Result<Token>() != null);\n    do {\n      if (pt.next == null) {\n        pt.next = NextToken();\n      }\n      pt = pt.next;\n    } while (pt.kind > maxT); // skip pragmas\n\n    return pt;\n  }\n\n  // make sure that peeking starts at the current scan position\n  public void ResetPeek () { pt = tokens; }\n\n} // end Scanner\n\npublic delegate void ErrorProc(int n, string filename, int line, int col);\n"
  },
  {
    "path": "third_party/Coco/src/Tab.cs",
    "content": "/*-------------------------------------------------------------------------\nTab.cs -- Symbol Table Management\nCompiler Generator Coco/R,\nCopyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz\nextended by M. Loeberbauer & A. Woess, Univ. of Linz\nwith improvements by Pat Terry, Rhodes University\n\nThis program is free software; you can redistribute it and/or modify it \nunder the terms of the GNU General Public License as published by the \nFree Software Foundation; either version 2, or (at your option) any \nlater version.\n\nThis program is distributed in the hope that it will be useful, but \nWITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY \nor FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License \nfor more details.\n\nYou should have received a copy of the GNU General Public License along \nwith this program; if not, write to the Free Software Foundation, Inc., \n59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n\nAs an exception, it is allowed to write an extension of Coco/R that is\nused as a plugin in non-free software.\n\nIf not otherwise stated, any source code generated by Coco/R (other than \nCoco/R itself) does not fall under the GNU General Public License.\n-------------------------------------------------------------------------*/\nusing System;\nusing System.IO;\nusing System.Text;\nusing System.Collections;\n\nnamespace at.jku.ssw.Coco {\n\npublic class Position {  // position of source code stretch (e.g. semantic action, resolver expressions)\n\tpublic readonly int beg;      // start relative to the beginning of the file\n\tpublic readonly int end;      // end of stretch\n\tpublic readonly int col;      // column number of start position\n\tpublic readonly int line;     // line number of start position\n\t\n\tpublic Position(int beg, int end, int col, int line) {\n\t\tthis.beg = beg; this.end = end; this.col = col; this.line = line;\n\t}\n}\n\n\n//=====================================================================\n// Symbol\n//=====================================================================\n\t\npublic class Symbol {\n\t\n\t// token kinds\n\tpublic const int fixedToken    = 0; // e.g. 'a' ('b' | 'c') (structure of literals)\n\tpublic const int classToken    = 1;\t// e.g. digit {digit}   (at least one char class)\n\tpublic const int litToken      = 2; // e.g. \"while\"\n\tpublic const int classLitToken = 3; // e.g. letter {letter} but without literals that have the same structure\n\t\n\tpublic int      n;           // symbol number\n\tpublic int      typ;         // t, nt, pr, unknown, rslv /* ML 29_11_2002 slv added */ /* AW slv --> rslv */\n\tpublic string   name;        // symbol name\n\tpublic Node     graph;       // nt: to first node of syntax graph\n\tpublic int      tokenKind;   // t:  token kind (fixedToken, classToken, ...)\n\tpublic bool     deletable;   // nt: true if nonterminal is deletable\n\tpublic bool     firstReady;  // nt: true if terminal start symbols have already been computed\n\tpublic BitArray first;       // nt: terminal start symbols\n\tpublic BitArray follow;      // nt: terminal followers\n\tpublic BitArray nts;         // nt: nonterminals whose followers have to be added to this sym\n\tpublic int      line;        // source text line number of item in this node\n\tpublic Position attrPos;     // nt: position of attributes in source text (or null)\n\tpublic Position semPos;      // pr: pos of semantic action in source text (or null)\n\t                             // nt: pos of local declarations in source text (or null)\n\n\tpublic Symbol(int typ, string name, int line) {\n\t\tthis.typ = typ; this.name = name; this.line = line;\n\t}\n}\n\n\n//=====================================================================\n// Node\n//=====================================================================\n\npublic class Node {\n\t// constants for node kinds\n\tpublic const int t    =  1;  // terminal symbol\n\tpublic const int pr   =  2;  // pragma\n\tpublic const int nt   =  3;  // nonterminal symbol\n\tpublic const int clas =  4;  // character class\n\tpublic const int chr  =  5;  // character\n\tpublic const int wt   =  6;  // weak terminal symbol\n\tpublic const int any  =  7;  // \n\tpublic const int eps  =  8;  // empty\n\tpublic const int sync =  9;  // synchronization symbol\n\tpublic const int sem  = 10;  // semantic action: (. .)\n\tpublic const int alt  = 11;  // alternative: |\n\tpublic const int iter = 12;  // iteration: { }\n\tpublic const int opt  = 13;  // option: [ ]\n\tpublic const int rslv = 14;  // resolver expr\n\t\n\tpublic const int normalTrans  = 0;\t\t// transition codes\n\tpublic const int contextTrans = 1;\n\t\n\tpublic int      n;\t\t\t// node number\n\tpublic int      typ;\t\t// t, nt, wt, chr, clas, any, eps, sem, sync, alt, iter, opt, rslv\n\tpublic Node     next;\t\t// to successor node\n\tpublic Node     down;\t\t// alt: to next alternative\n\tpublic Node     sub;\t\t// alt, iter, opt: to first node of substructure\n\tpublic bool     up;\t\t\t// true: \"next\" leads to successor in enclosing structure\n\tpublic Symbol   sym;\t\t// nt, t, wt: symbol represented by this node\n\tpublic int      val;\t\t// chr:  ordinal character value\n\t\t\t\t\t\t\t\t\t\t\t\t\t// clas: index of character class\n\tpublic int      code;\t\t// chr, clas: transition code\n\tpublic BitArray set;\t\t// any, sync: the set represented by this node\n\tpublic Position pos;\t\t// nt, t, wt: pos of actual attributes\n\t                            // sem:       pos of semantic action in source text\n\t                            // rslv:       pos of resolver in source text\n\tpublic int      line;\t\t// source text line number of item in this node\n\tpublic State    state;\t// DFA state corresponding to this node\n\t\t\t\t\t\t\t\t\t\t\t\t\t// (only used in DFA.ConvertToStates)\n\n\tpublic Node(int typ, Symbol sym, int line) {\n\t\tthis.typ = typ; this.sym = sym; this.line = line;\n\t}\n}\n\n//=====================================================================\n// Graph \n//=====================================================================\n\npublic class Graph {\t\n\tpublic Node l;\t// left end of graph = head\n\tpublic Node r;\t// right end of graph = list of nodes to be linked to successor graph\n\t\n\tpublic Graph() {\n\t\tl = null; r = null;\n\t}\n\t\n\tpublic Graph(Node left, Node right) {\n\t\tl = left; r = right;\n\t}\n\t\n\tpublic Graph(Node p) {\n\t\tl = p; r = p;\n\t}\n}\n\n//=====================================================================\n// Sets \n//=====================================================================\n\npublic class Sets {\n\t\n\tpublic static int Elements(BitArray s) {\n\t\tint max = s.Count;\n\t\tint n = 0;\n\t\tfor (int i=0; i<max; i++)\n\t\t\tif (s[i]) n++;\n\t\treturn n;\n\t}\n\t\n\tpublic static bool Equals(BitArray a, BitArray b) {\n\t\tint max = a.Count;\n\t\tfor (int i=0; i<max; i++)\n\t\t\tif (a[i] != b[i]) return false;\n\t\treturn true;\n\t}\n\t\n\tpublic static bool Intersect(BitArray a, BitArray b) { // a * b != {}\n\t\tint max = a.Count;\n\t\tfor (int i=0; i<max; i++)\n\t\t\tif (a[i] && b[i]) return true;\n\t\treturn false;\n\t}\n\t\n\tpublic static void Subtract(BitArray a, BitArray b) { // a = a - b\n\t\tBitArray c = (BitArray) b.Clone();\n\t\ta.And(c.Not());\n\t}\n\t\n}\n\n//=====================================================================\n// CharClass\n//=====================================================================\n\npublic class CharClass {\t\n\tpublic int n;       \t// class number\n\tpublic string name;\t\t// class name\n\tpublic CharSet set;\t// set representing the class\n\n\tpublic CharClass(string name, CharSet s) {\n\t\tthis.name = name; this.set = s;\n\t}\n}\n\n\n//=====================================================================\n// Tab\n//=====================================================================\n\npublic class Tab {\n\tpublic Position semDeclPos;       // position of global semantic declarations\n\tpublic CharSet ignored;           // characters ignored by the scanner\n\tpublic bool[] ddt = new bool[10]; // debug and test switches\n\tpublic Symbol gramSy;             // root nonterminal; filled by ATG\n\tpublic Symbol eofSy;              // end of file symbol\n\tpublic Symbol noSym;              // used in case of an error\n\tpublic BitArray allSyncSets;      // union of all synchronisation sets\n\tpublic Hashtable literals;        // symbols that are used as literals\n\t\n\tpublic string srcName;            // name of the atg file (including path)\n\tpublic string srcDir;             // directory path of the atg file\n\tpublic string nsName;             // namespace for generated files\n\tpublic string frameDir;           // directory containing the frame files\n\tpublic string outDir;             // directory for generated files\n\tpublic bool checkEOF = true;      // should coco generate a check for EOF at\n\t                                  //   the end of Parser.Parse():\n\tpublic bool emitLines;            // emit #line pragmas for semantic actions\n\t                                  //   in the generated parser\n\n\tBitArray visited;                 // mark list for graph traversals\n\tSymbol curSy;                     // current symbol in computation of sets\n\t\n\tParser parser;                    // other Coco objects\n\tTextWriter trace;\n\tErrors errors;\n\n\tpublic Tab(Parser parser) {\n\t\tthis.parser = parser;\n\t\ttrace = parser.trace;\n\t\terrors = parser.errors;\n\t\teofSy = NewSym(Node.t, \"EOF\", 0);\n\t\tdummyNode = NewNode(Node.eps, null, 0);\n\t\tliterals = new Hashtable();\n\t}\n\n\t//---------------------------------------------------------------------\n\t//  Symbol list management\n\t//---------------------------------------------------------------------\n\t\n\tpublic ArrayList terminals = new ArrayList();\n\tpublic ArrayList pragmas = new ArrayList();\n\tpublic ArrayList nonterminals = new ArrayList();\n\t\n\tstring[] tKind = {\"fixedToken\", \"classToken\", \"litToken\", \"classLitToken\"};\n\t\n\tpublic Symbol NewSym(int typ, string name, int line) {\n\t\tif (name.Length == 2 && name[0] == '\"') {\n\t\t\tparser.SemErr(\"empty token not allowed\"); name = \"???\";\n\t\t}\n\t\tSymbol sym = new Symbol(typ, name, line);\n\t\tswitch (typ) {\n\t\t\tcase Node.t:  sym.n = terminals.Count; terminals.Add(sym); break;\n\t\t\tcase Node.pr: pragmas.Add(sym); break;\n\t\t\tcase Node.nt: sym.n = nonterminals.Count; nonterminals.Add(sym); break;\n\t\t}\n\t\treturn sym;\n\t}\n\n\tpublic Symbol FindSym(string name) {\n\t\tforeach (Symbol s in terminals)\n\t\t\tif (s.name == name) return s;\n\t\tforeach (Symbol s in nonterminals)\n\t\t\tif (s.name == name) return s;\n\t\treturn null;\n\t}\n\t\n\tint Num(Node p) {\n\t\tif (p == null) return 0; else return p.n;\n\t}\n\t\n\tvoid PrintSym(Symbol sym) {\n\t\ttrace.Write(\"{0,3} {1,-14} {2}\", sym.n, Name(sym.name), nTyp[sym.typ]);\n\t\tif (sym.attrPos==null) trace.Write(\" false \"); else trace.Write(\" true  \");\n\t\tif (sym.typ == Node.nt) {\n\t\t\ttrace.Write(\"{0,5}\", Num(sym.graph));\n\t\t\tif (sym.deletable) trace.Write(\" true  \"); else trace.Write(\" false \");\n\t\t} else\n\t\t\ttrace.Write(\"            \");\n\t\ttrace.WriteLine(\"{0,5} {1}\", sym.line, tKind[sym.tokenKind]);\n\t}\n\n\tpublic void PrintSymbolTable() {\n\t\ttrace.WriteLine(\"Symbol Table:\");\n\t\ttrace.WriteLine(\"------------\"); trace.WriteLine();\n\t\ttrace.WriteLine(\" nr name          typ  hasAt graph  del    line tokenKind\");\n\t\tforeach (Symbol sym in terminals) PrintSym(sym);\n\t\tforeach (Symbol sym in pragmas) PrintSym(sym);\n\t\tforeach (Symbol sym in nonterminals) PrintSym(sym);\n\t\ttrace.WriteLine();\n\t\ttrace.WriteLine(\"Literal Tokens:\");\n\t\ttrace.WriteLine(\"--------------\");\n\t\tforeach (DictionaryEntry e in literals) {\n\t\t\ttrace.WriteLine(\"_\" + ((Symbol)e.Value).name + \" = \" + e.Key + \".\");\n\t\t}\n\t\ttrace.WriteLine();\n\t}\n\t\n\tpublic void PrintSet(BitArray s, int indent) {\n\t\tint col, len;\n\t\tcol = indent;\n\t\tforeach (Symbol sym in terminals) {\n\t\t\tif (s[sym.n]) {\n\t\t\t\tlen = sym.name.Length;\n\t\t\t\tif (col + len >= 80) {\n\t\t\t\t\ttrace.WriteLine();\n\t\t\t\t\tfor (col = 1; col < indent; col++) trace.Write(\" \");\n\t\t\t\t}\n\t\t\t\ttrace.Write(\"{0} \", sym.name);\n\t\t\t\tcol += len + 1;\n\t\t\t}\n\t\t}\n\t\tif (col == indent) trace.Write(\"-- empty set --\");\n\t\ttrace.WriteLine();\n\t}\n\t\n\t//---------------------------------------------------------------------\n\t//  Syntax graph management\n\t//---------------------------------------------------------------------\n\t\n\tpublic ArrayList nodes = new ArrayList();\n\tpublic string[] nTyp =\n\t\t{\"    \", \"t   \", \"pr  \", \"nt  \", \"clas\", \"chr \", \"wt  \", \"any \", \"eps \",\n\t\t \"sync\", \"sem \", \"alt \", \"iter\", \"opt \", \"rslv\"};\n\tNode dummyNode;\n\t\n\tpublic Node NewNode(int typ, Symbol sym, int line) {\n\t\tNode node = new Node(typ, sym, line);\n\t\tnode.n = nodes.Count;\n\t\tnodes.Add(node);\n\t\treturn node;\n\t}\n\t\n\tpublic Node NewNode(int typ, Node sub) {\n\t\tNode node = NewNode(typ, null, 0);\n\t\tnode.sub = sub;\n\t\treturn node;\n\t}\n\t\n\tpublic Node NewNode(int typ, int val, int line) {\n\t\tNode node = NewNode(typ, null, line);\n\t\tnode.val = val;\n\t\treturn node;\n\t}\n\t\n\tpublic void MakeFirstAlt(Graph g) {\n\t\tg.l = NewNode(Node.alt, g.l); g.l.line = g.l.sub.line;\n\t\tg.r.up = true;\n\t\tg.l.next = g.r;\n\t\tg.r = g.l;\n\t}\n\t\n\t// The result will be in g1\n\tpublic void MakeAlternative(Graph g1, Graph g2) {\n\t\tg2.l = NewNode(Node.alt, g2.l); g2.l.line = g2.l.sub.line;\n\t\tg2.l.up = true;\n\t\tg2.r.up = true;\n\t\tNode p = g1.l; while (p.down != null) p = p.down;\n\t\tp.down = g2.l;\n\t\tp = g1.r; while (p.next != null) p = p.next;\n\t\t// append alternative to g1 end list\n\t\tp.next = g2.l;\n\t\t// append g2 end list to g1 end list\n\t\tg2.l.next = g2.r;\n\t}\n\t\n\t// The result will be in g1\n\tpublic void MakeSequence(Graph g1, Graph g2) {\n\t\tNode p = g1.r.next; g1.r.next = g2.l; // link head node\n\t\twhile (p != null) {  // link substructure\n\t\t\tNode q = p.next; p.next = g2.l;\n\t\t\tp = q;\n\t\t}\n\t\tg1.r = g2.r;\n\t}\n\t\n\tpublic void MakeIteration(Graph g) {\n\t\tg.l = NewNode(Node.iter, g.l);\n\t\tg.r.up = true;\n\t\tNode p = g.r;\n\t\tg.r = g.l;\n\t\twhile (p != null) {\n\t\t\tNode q = p.next; p.next = g.l;\n\t\t\tp = q;\n\t\t}\n\t}\n\t\n\tpublic void MakeOption(Graph g) {\n\t\tg.l = NewNode(Node.opt, g.l);\n\t\tg.r.up = true;\n\t\tg.l.next = g.r;\n\t\tg.r = g.l;\n\t}\n\t\n\tpublic void Finish(Graph g) {\n\t\tNode p = g.r;\n\t\twhile (p != null) {\n\t\t\tNode q = p.next; p.next = null;\n\t\t\tp = q;\n\t\t}\n\t}\n\t\n\tpublic void DeleteNodes() {\n\t\tnodes = new ArrayList();\n\t\tdummyNode = NewNode(Node.eps, null, 0);\n\t}\n\t\n\tpublic Graph StrToGraph(string str) {\n\t\tstring s = Unescape(str.Substring(1, str.Length-2));\n\t\tif (s.Length == 0) parser.SemErr(\"empty token not allowed\");\n\t\tGraph g = new Graph();\n\t\tg.r = dummyNode;\n\t\tfor (int i = 0; i < s.Length; i++) {\n\t\t\tNode p = NewNode(Node.chr, (int)s[i], 0);\n\t\t\tg.r.next = p; g.r = p;\n\t\t}\n\t\tg.l = dummyNode.next; dummyNode.next = null;\n\t\treturn g;\n\t}\n\t\n  public void SetContextTrans(Node p) { // set transition code in the graph rooted at p\n    while (p != null) {\n      if (p.typ == Node.chr || p.typ == Node.clas) {\n        p.code = Node.contextTrans;\n      } else if (p.typ == Node.opt || p.typ == Node.iter) {\n        SetContextTrans(p.sub);\n      } else if (p.typ == Node.alt) {\n        SetContextTrans(p.sub); SetContextTrans(p.down);\n      }\n      if (p.up) break;\n      p = p.next;\n    }\n  }\n\t\n\t//------------ graph deletability check -----------------\n\n\tpublic static bool DelGraph(Node p) {\n\t\treturn p == null || DelNode(p) && DelGraph(p.next);\n\t}\n\t\n\tpublic static bool DelSubGraph(Node p) {\n\t\treturn p == null || DelNode(p) && (p.up || DelSubGraph(p.next));\n\t}\n\t\n\tpublic static bool DelNode(Node p) {\n\t\tif (p.typ == Node.nt) return p.sym.deletable;\n\t\telse if (p.typ == Node.alt) return DelSubGraph(p.sub) || p.down != null && DelSubGraph(p.down);\n\t\telse return p.typ == Node.iter || p.typ == Node.opt || p.typ == Node.sem \n\t\t\t|| p.typ == Node.eps || p.typ == Node.rslv || p.typ == Node.sync;\n\t}\n\t\n\t//----------------- graph printing ----------------------\n\t\n\tstring Ptr(Node p, bool up) {\n\t\tstring ptr = (p == null) ? \"0\" : p.n.ToString();\n\t\treturn (up) ? (\"-\" + ptr) : ptr;\n\t}\n\t\n\tstring Pos(Position pos) {\n\t\tif (pos == null) return \"     \"; else return String.Format(\"{0,5}\", pos.beg);\n\t}\n\t\n\tpublic string Name(string name) {\n\t\treturn (name + \"           \").Substring(0, 12);\n\t\t// found no simpler way to get the first 12 characters of the name\n\t\t// padded with blanks on the right\n\t}\n\t\n\tpublic void PrintNodes() {\n\t\ttrace.WriteLine(\"Graph nodes:\");\n\t\ttrace.WriteLine(\"----------------------------------------------------\");\n\t\ttrace.WriteLine(\"   n type name          next  down   sub   pos  line\");\n\t\ttrace.WriteLine(\"                               val  code\");\n\t\ttrace.WriteLine(\"----------------------------------------------------\");\n\t\tforeach (Node p in nodes) {\n\t\t\ttrace.Write(\"{0,4} {1} \", p.n, nTyp[p.typ]);\n\t\t\tif (p.sym != null)\n\t\t\t\ttrace.Write(\"{0,12} \", Name(p.sym.name));\n\t\t\telse if (p.typ == Node.clas) {\n\t\t\t\tCharClass c = (CharClass)classes[p.val];\n\t\t\t\ttrace.Write(\"{0,12} \", Name(c.name));\n\t\t\t} else trace.Write(\"             \");\n\t\t\ttrace.Write(\"{0,5} \", Ptr(p.next, p.up));\n\t\t\tswitch (p.typ) {\n\t\t\t\tcase Node.t: case Node.nt: case Node.wt:\n\t\t\t\t\ttrace.Write(\"             {0,5}\", Pos(p.pos)); break;\n\t\t\t\tcase Node.chr:\n\t\t\t\t\ttrace.Write(\"{0,5} {1,5}       \", p.val, p.code); break;\n\t\t\t\tcase Node.clas:\n\t\t\t\t\ttrace.Write(\"      {0,5}       \", p.code); break;\n\t\t\t\tcase Node.alt: case Node.iter: case Node.opt:\n\t\t\t\t\ttrace.Write(\"{0,5} {1,5}       \", Ptr(p.down, false), Ptr(p.sub, false)); break;\n\t\t\t\tcase Node.sem:\n\t\t\t\t\ttrace.Write(\"             {0,5}\", Pos(p.pos)); break;\n\t\t\t\tcase Node.eps: case Node.any: case Node.sync:\n\t\t\t\t\ttrace.Write(\"                  \"); break;\n\t\t\t}\n\t\t\ttrace.WriteLine(\"{0,5}\", p.line);\n\t\t}\n\t\ttrace.WriteLine();\n\t}\n\t\n\n\t//---------------------------------------------------------------------\n\t//  Character class management\n\t//---------------------------------------------------------------------\n\t\n\tpublic ArrayList classes = new ArrayList();\n\tpublic int dummyName = 'A';\n\n\tpublic CharClass NewCharClass(string name, CharSet s) {\n\t\tif (name == \"#\") name = \"#\" + (char)dummyName++;\n\t\tCharClass c = new CharClass(name, s);\n\t\tc.n = classes.Count;\n\t\tclasses.Add(c);\n\t\treturn c;\n\t}\n\n\tpublic CharClass FindCharClass(string name) {\n\t\tforeach (CharClass c in classes)\n\t\t\tif (c.name == name) return c;\n\t\treturn null;\n\t}\n\t\n\tpublic CharClass FindCharClass(CharSet s) {\n\t\tforeach (CharClass c in classes)\n\t\t\tif (s.Equals(c.set)) return c;\n\t\treturn null;\n\t}\n\t\n\tpublic CharSet CharClassSet(int i) {\n\t\treturn ((CharClass)classes[i]).set;\n\t}\n\t\n\t//----------- character class printing\n\n\tstring Ch(int ch) {\n\t\tif (ch < ' ' || ch >= 127 || ch == '\\'' || ch == '\\\\') return ch.ToString();\n\t\telse return String.Format(\"'{0}'\", (char)ch);\n\t}\n\t\n\tvoid WriteCharSet(CharSet s) {\n\t\tfor (CharSet.Range r = s.head; r != null; r = r.next)\n\t\t\tif (r.from < r.to) { trace.Write(Ch(r.from) + \"..\" + Ch(r.to) + \" \"); }\n\t\t\telse { trace.Write(Ch(r.from) + \" \"); }\n\t}\n\t\n\tpublic void WriteCharClasses () {\n\t\tforeach (CharClass c in classes) {\n\t\t\ttrace.Write(\"{0,-10}: \", c.name);\n\t\t\tWriteCharSet(c.set);\n\t\t\ttrace.WriteLine();\n\t\t}\n\t\ttrace.WriteLine();\n\t}\n\t\n\n\t//---------------------------------------------------------------------\n\t//  Symbol set computations\n\t//---------------------------------------------------------------------\n\n\t/* Computes the first set for the graph rooted at p */\n\tBitArray First0(Node p, BitArray mark) {\n\t\tBitArray fs = new BitArray(terminals.Count);\n\t\twhile (p != null && !mark[p.n]) {\n\t\t\tmark[p.n] = true;\n\t\t\tswitch (p.typ) {\n\t\t\t\tcase Node.nt: {\n\t\t\t\t\tif (p.sym.firstReady) fs.Or(p.sym.first);\n\t\t\t\t\telse fs.Or(First0(p.sym.graph, mark));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase Node.t: case Node.wt: {\n\t\t\t\t\tfs[p.sym.n] = true; break;\n\t\t\t\t}\n\t\t\t\tcase Node.any: {\n\t\t\t\t\tfs.Or(p.set); break;\n\t\t\t\t}\n\t\t\t\tcase Node.alt: {\n\t\t\t\t\tfs.Or(First0(p.sub, mark));\n\t\t\t\t\tfs.Or(First0(p.down, mark));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase Node.iter: case Node.opt: {\n\t\t\t\t\tfs.Or(First0(p.sub, mark));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!DelNode(p)) break;\n\t\t\tp = p.next;\n\t\t}\n\t\treturn fs;\n\t}\n\t\n\tpublic BitArray First(Node p) {\n\t\tBitArray fs = First0(p, new BitArray(nodes.Count));\n\t\tif (ddt[3]) {\n\t\t\ttrace.WriteLine(); \n\t\t\tif (p != null) trace.WriteLine(\"First: node = {0}\", p.n);\n\t\t\telse trace.WriteLine(\"First: node = null\");\n\t\t\tPrintSet(fs, 0);\n\t\t}\n\t\treturn fs;\n\t}\n\n\tvoid CompFirstSets() {\n\t\tforeach (Symbol sym in nonterminals) {\n\t\t\tsym.first = new BitArray(terminals.Count);\n\t\t\tsym.firstReady = false;\n\t\t}\n\t\tforeach (Symbol sym in nonterminals) {\n\t\t\tsym.first = First(sym.graph);\n\t\t\tsym.firstReady = true;\n\t\t}\n\t}\n\t\n\tvoid CompFollow(Node p) {\n\t\twhile (p != null && !visited[p.n]) {\n\t\t\tvisited[p.n] = true;\n\t\t\tif (p.typ == Node.nt) {\n\t\t\t\tBitArray s = First(p.next);\n\t\t\t\tp.sym.follow.Or(s);\n\t\t\t\tif (DelGraph(p.next))\n\t\t\t\t\tp.sym.nts[curSy.n] = true;\n\t\t\t} else if (p.typ == Node.opt || p.typ == Node.iter) {\n\t\t\t\tCompFollow(p.sub);\n\t\t\t} else if (p.typ == Node.alt) {\n\t\t\t\tCompFollow(p.sub); CompFollow(p.down);\n\t\t\t}\n\t\t\tp = p.next;\n\t\t}\n\t}\n\t\n\tvoid Complete(Symbol sym) {\n\t\tif (!visited[sym.n]) {\n\t\t\tvisited[sym.n] = true;\n\t\t\tforeach (Symbol s in nonterminals) {\n\t\t\t\tif (sym.nts[s.n]) {\n\t\t\t\t\tComplete(s);\n\t\t\t\t\tsym.follow.Or(s.follow);\n\t\t\t\t\tif (sym == curSy) sym.nts[s.n] = false;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\tvoid CompFollowSets() {\n\t\tforeach (Symbol sym in nonterminals) {\n\t\t\tsym.follow = new BitArray(terminals.Count);\n\t\t\tsym.nts = new BitArray(nonterminals.Count);\n\t\t}\n\t\tgramSy.follow[eofSy.n] = true;\n\t\tvisited = new BitArray(nodes.Count);\n\t\tforeach (Symbol sym in nonterminals) { // get direct successors of nonterminals\n\t\t\tcurSy = sym;\n\t\t\tCompFollow(sym.graph);\n\t\t}\n\t\tforeach (Symbol sym in nonterminals) { // add indirect successors to followers\n\t\t\tvisited = new BitArray(nonterminals.Count);\n\t\t\tcurSy = sym;\n\t\t\tComplete(sym);\n\t\t}\n\t}\n\t\n\tNode LeadingAny(Node p) {\n\t\tif (p == null) return null;\n\t\tNode a = null;\n\t\tif (p.typ == Node.any) a = p;\n\t\telse if (p.typ == Node.alt) {\n\t\t\ta = LeadingAny(p.sub);\n\t\t\tif (a == null) a = LeadingAny(p.down);\n\t\t}\n\t\telse if (p.typ == Node.opt || p.typ == Node.iter) a = LeadingAny(p.sub);\n\t\tif (a == null && DelNode(p) && !p.up) a = LeadingAny(p.next);\n\t\treturn a;\n\t}\n\t\n\tvoid FindAS(Node p) { // find ANY sets\n\t\tNode a;\n\t\twhile (p != null) {\n\t\t\tif (p.typ == Node.opt || p.typ == Node.iter) {\n\t\t\t\tFindAS(p.sub);\n\t\t\t\ta = LeadingAny(p.sub);\n\t\t\t\tif (a != null) Sets.Subtract(a.set, First(p.next));\n\t\t\t} else if (p.typ == Node.alt) {\n\t\t\t\tBitArray s1 = new BitArray(terminals.Count);\n\t\t\t\tNode q = p;\n\t\t\t\twhile (q != null) {\n\t\t\t\t\tFindAS(q.sub);\n\t\t\t\t\ta = LeadingAny(q.sub);\n\t\t\t\t\tif (a != null)\n\t\t\t\t\t\tSets.Subtract(a.set, First(q.down).Or(s1));\n\t\t\t\t\telse\n\t\t\t\t\t\ts1.Or(First(q.sub));\n\t\t\t\t\tq = q.down;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Remove alternative terminals before ANY, in the following\n\t\t\t// examples a and b must be removed from the ANY set:\n\t\t\t// [a] ANY, or {a|b} ANY, or [a][b] ANY, or (a|) ANY, or\n\t\t\t// A = [a]. A ANY\n\t\t\tif (DelNode(p)) {\n\t\t\t\ta = LeadingAny(p.next);\n\t\t\t\tif (a != null) {\n\t\t\t\t\tNode q = (p.typ == Node.nt) ? p.sym.graph : p.sub;\n\t\t\t\t\tSets.Subtract(a.set, First(q));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (p.up) break;\n\t\t\tp = p.next;\n\t\t}\n\t}\n\t\n\tvoid CompAnySets() {\n\t\tforeach (Symbol sym in nonterminals) FindAS(sym.graph);\n\t}\n\t\n\tpublic BitArray Expected(Node p, Symbol curSy) {\n\t\tBitArray s = First(p);\n\t\tif (DelGraph(p)) s.Or(curSy.follow);\n\t\treturn s;\n\t}\n\n\t// does not look behind resolvers; only called during LL(1) test and in CheckRes\n\tpublic BitArray Expected0(Node p, Symbol curSy) {\n\t\tif (p.typ == Node.rslv) return new BitArray(terminals.Count);\n\t\telse return Expected(p, curSy);\n\t}\n\n\tvoid CompSync(Node p) {\n\t\twhile (p != null && !visited[p.n]) {\n\t\t\tvisited[p.n] = true;\n\t\t\tif (p.typ == Node.sync) {\n\t\t\t\tBitArray s = Expected(p.next, curSy);\n\t\t\t\ts[eofSy.n] = true;\n\t\t\t\tallSyncSets.Or(s);\n\t\t\t\tp.set = s;\n\t\t\t} else if (p.typ == Node.alt) {\n\t\t\t\tCompSync(p.sub); CompSync(p.down);\n\t\t\t} else if (p.typ == Node.opt || p.typ == Node.iter)\n\t\t\t\tCompSync(p.sub);\n\t\t\tp = p.next;\n\t\t}\n\t}\n\t\n\tvoid CompSyncSets() {\n\t\tallSyncSets = new BitArray(terminals.Count);\n\t\tallSyncSets[eofSy.n] = true;\n\t\tvisited = new BitArray(nodes.Count);\n\t\tforeach (Symbol sym in nonterminals) {\n\t\t\tcurSy = sym;\n\t\t\tCompSync(curSy.graph);\n\t\t}\n\t}\n\t\n\tpublic void SetupAnys() {\n\t\tforeach (Node p in nodes)\n\t\t\tif (p.typ == Node.any) {\n\t\t\t\tp.set = new BitArray(terminals.Count, true);\n\t\t\t\tp.set[eofSy.n] = false;\n\t\t\t}\n\t}\n\t\n\tpublic void CompDeletableSymbols() {\n\t\tbool changed;\n\t\tdo {\n\t\t\tchanged = false;\n\t\t\tforeach (Symbol sym in nonterminals)\n\t\t\t\tif (!sym.deletable && sym.graph != null && DelGraph(sym.graph)) {\n\t\t\t\t\tsym.deletable = true; changed = true;\n\t\t\t\t}\n\t\t} while (changed);\n\t\tforeach (Symbol sym in nonterminals)\n\t\t\tif (sym.deletable) errors.Warning(\"  \" + sym.name + \" deletable\");\n\t}\n\t\n\tpublic void RenumberPragmas() {\n\t\tint n = terminals.Count;\n\t\tforeach (Symbol sym in pragmas) sym.n = n++;\n\t}\n\n\tpublic void CompSymbolSets() {\n\t\tCompDeletableSymbols();\n\t\tCompFirstSets();\n\t\tCompAnySets();\n\t\tCompFollowSets();\n\t\tCompSyncSets();\n\t\tif (ddt[1]) {\n\t\t\ttrace.WriteLine();\n\t\t\ttrace.WriteLine(\"First & follow symbols:\");\n\t\t\ttrace.WriteLine(\"----------------------\"); trace.WriteLine();\n\t\t\tforeach (Symbol sym in nonterminals) {\n\t\t\t\ttrace.WriteLine(sym.name);\n\t\t\t\ttrace.Write(\"first:   \"); PrintSet(sym.first, 10);\n\t\t\t\ttrace.Write(\"follow:  \"); PrintSet(sym.follow, 10);\n\t\t\t\ttrace.WriteLine();\n\t\t\t}\n\t\t}\n\t\tif (ddt[4]) {\n\t\t\ttrace.WriteLine();\n\t\t\ttrace.WriteLine(\"ANY and SYNC sets:\");\n\t\t\ttrace.WriteLine(\"-----------------\");\n\t\t\tforeach (Node p in nodes)\n\t\t\t\tif (p.typ == Node.any || p.typ == Node.sync) {\n\t\t\t\t\ttrace.Write(\"{0,4} {1,4}: \", p.n, nTyp[p.typ]);\n\t\t\t\t\tPrintSet(p.set, 11);\n\t\t\t\t}\n\t\t}\n\t}\n\t\n\t//---------------------------------------------------------------------\n\t//  String handling\n\t//---------------------------------------------------------------------\n\t\n\tchar Hex2Char(string s) {\n\t\tint val = 0;\n\t\tfor (int i = 0; i < s.Length; i++) {\n\t\t\tchar ch = s[i];\n\t\t\tif ('0' <= ch && ch <= '9') val = 16 * val + (ch - '0');\n\t\t\telse if ('a' <= ch && ch <= 'f') val = 16 * val + (10 + ch - 'a');\n\t\t\telse if ('A' <= ch && ch <= 'F') val = 16 * val + (10 + ch - 'A');\n\t\t\telse parser.SemErr(\"bad escape sequence in string or character\");\n\t\t}\n\t\tif (val > char.MaxValue) /* pdt */\n\t\t\tparser.SemErr(\"bad escape sequence in string or character\");\n\t\treturn (char)val;\n\t}\n\n\tstring Char2Hex(char ch) {\n\t\tStringWriter w = new StringWriter();\n\t\tw.Write(\"\\\\u{0:x4}\", (int)ch);\n\t\treturn w.ToString();\n\t}\n\n\tpublic string Unescape (string s) {\n\t\t/* replaces escape sequences in s by their Unicode values. */\n\t\tStringBuilder buf = new StringBuilder();\n\t\tint i = 0;\n\t\twhile (i < s.Length) {\n\t\t\tif (s[i] == '\\\\') {\n\t\t\t\tswitch (s[i+1]) {\n\t\t\t\t\tcase '\\\\': buf.Append('\\\\'); i += 2; break;\n\t\t\t\t\tcase '\\'': buf.Append('\\''); i += 2; break;\n\t\t\t\t\tcase '\\\"': buf.Append('\\\"'); i += 2; break;\n\t\t\t\t\tcase 'r': buf.Append('\\r'); i += 2; break;\n\t\t\t\t\tcase 'n': buf.Append('\\n'); i += 2; break;\n\t\t\t\t\tcase 't': buf.Append('\\t'); i += 2; break;\n\t\t\t\t\tcase '0': buf.Append('\\0'); i += 2; break;\n\t\t\t\t\tcase 'a': buf.Append('\\a'); i += 2; break;\n\t\t\t\t\tcase 'b': buf.Append('\\b'); i += 2; break;\n\t\t\t\t\tcase 'f': buf.Append('\\f'); i += 2; break;\n\t\t\t\t\tcase 'v': buf.Append('\\v'); i += 2; break;\n\t\t\t\t\tcase 'u': case 'x':\n\t\t\t\t\t\tif (i + 6 <= s.Length) {\n\t\t\t\t\t\t\tbuf.Append(Hex2Char(s.Substring(i+2, 4))); i += 6; break;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tparser.SemErr(\"bad escape sequence in string or character\"); i = s.Length; break;\n\t\t\t\t\t\t}\n\t\t\t\t\tdefault: parser.SemErr(\"bad escape sequence in string or character\"); i += 2; break;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tbuf.Append(s[i]);\n\t\t\t\ti++;\n\t\t\t}\n\t\t}\n\t\treturn buf.ToString();\n\t}\n\n\tpublic string Escape (string s) {\n\t\tStringBuilder buf = new StringBuilder();\n\t\tforeach (char ch in s) {\n\t\t\tswitch(ch) {\n\t\t\t\tcase '\\\\': buf.Append(\"\\\\\\\\\"); break;\n\t\t\t\tcase '\\'': buf.Append(\"\\\\'\"); break;\n\t\t\t\tcase '\\\"': buf.Append(\"\\\\\\\"\"); break;\n\t\t\t\tcase '\\t': buf.Append(\"\\\\t\"); break;\n\t\t\t\tcase '\\r': buf.Append(\"\\\\r\"); break;\n\t\t\t\tcase '\\n': buf.Append(\"\\\\n\"); break;\n\t\t\t\tdefault:\n\t\t\t\t\tif (ch < ' ' || ch > '\\u007f') buf.Append(Char2Hex(ch));\n\t\t\t\t\telse buf.Append(ch);\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\treturn buf.ToString();\n\t}\n\t\t\t\n\t//---------------------------------------------------------------------\n\t//  Grammar checks\n\t//---------------------------------------------------------------------\n\t\n\tpublic bool GrammarOk() {\n\t\tbool ok = NtsComplete() \n\t\t\t&& AllNtReached() \n\t\t\t&& NoCircularProductions()\n\t\t\t&& AllNtToTerm();\n    if (ok) { CheckResolvers(); CheckLL1(); }\n    return ok;\n\t}\n\n\t//--------------- check for circular productions ----------------------\n\t\n\tclass CNode {\t// node of list for finding circular productions\n\t\tpublic Symbol left, right;\n\t\n\t\tpublic CNode (Symbol l, Symbol r) {\n\t\t\tleft = l; right = r;\n\t\t}\n\t}\n\n\tvoid GetSingles(Node p, ArrayList singles) {\n\t\tif (p == null) return;  // end of graph\n\t\tif (p.typ == Node.nt) {\n\t\t\tif (p.up || DelGraph(p.next)) singles.Add(p.sym);\n\t\t} else if (p.typ == Node.alt || p.typ == Node.iter || p.typ == Node.opt) {\n\t\t\tif (p.up || DelGraph(p.next)) {\n\t\t\t\tGetSingles(p.sub, singles);\n\t\t\t\tif (p.typ == Node.alt) GetSingles(p.down, singles);\n\t\t\t}\n\t\t}\n\t\tif (!p.up && DelNode(p)) GetSingles(p.next, singles);\n\t}\n\t\n\tpublic bool NoCircularProductions() {\n\t\tbool ok, changed, onLeftSide, onRightSide;\n\t\tArrayList list = new ArrayList();\n\t\tforeach (Symbol sym in nonterminals) {\n\t\t\tArrayList singles = new ArrayList();\n\t\t\tGetSingles(sym.graph, singles); // get nonterminals s such that sym-->s\n\t\t\tforeach (Symbol s in singles) list.Add(new CNode(sym, s));\n\t\t}\n\t\tdo {\n\t\t\tchanged = false;\n\t\t\tfor (int i = 0; i < list.Count; i++) {\n\t\t\t\tCNode n = (CNode)list[i];\n\t\t\t\tonLeftSide = false; onRightSide = false;\n\t\t\t\tforeach (CNode m in list) {\n\t\t\t\t\tif (n.left == m.right) onRightSide = true;\n\t\t\t\t\tif (n.right == m.left) onLeftSide = true;\n\t\t\t\t}\n\t\t\t\tif (!onLeftSide || !onRightSide) {\n\t\t\t\t\tlist.Remove(n); i--; changed = true;\n\t\t\t\t}\n\t\t\t}\n\t\t} while(changed);\n\t\tok = true;\n\t\tforeach (CNode n in list) {\n\t\t\tok = false;\n\t\t\terrors.SemErr(\"  \" + n.left.name + \" --> \" + n.right.name);\n\t\t}\n\t\treturn ok;\n\t}\n\t\n\t//--------------- check for LL(1) errors ----------------------\n\t\n\tvoid LL1Error(int cond, Symbol sym) {\n\t\tstring s = \"  LL1 warning in \" + curSy.name + \": \";\n\t\tif (sym != null) s += sym.name + \" is \";\n\t\tswitch (cond) {\n\t\t\tcase 1: s += \"start of several alternatives\"; break;\n\t\t\tcase 2: s += \"start & successor of deletable structure\"; break;\n\t\t\tcase 3: s += \"an ANY node that matches no symbol\"; break;\n\t\t\tcase 4: s += \"contents of [...] or {...} must not be deletable\"; break;\n\t\t}\n\t\terrors.Warning(s);\n\t}\n\t\n\tvoid CheckOverlap(BitArray s1, BitArray s2, int cond) {\n\t\tforeach (Symbol sym in terminals) {\n\t\t\tif (s1[sym.n] && s2[sym.n]) LL1Error(cond, sym);\n\t\t}\n\t}\n\t\n\tvoid CheckAlts(Node p) {\n\t\tBitArray s1, s2;\n\t\twhile (p != null) {\n\t\t\tif (p.typ == Node.alt) {\n\t\t\t\tNode q = p;\n\t\t\t\ts1 = new BitArray(terminals.Count);\n\t\t\t\twhile (q != null) { // for all alternatives\n\t\t\t\t\ts2 = Expected0(q.sub, curSy);\n\t\t\t\t\tCheckOverlap(s1, s2, 1);\n\t\t\t\t\ts1.Or(s2);\n\t\t\t\t\tCheckAlts(q.sub);\n\t\t\t\t\tq = q.down;\n\t\t\t\t}\n\t\t\t} else if (p.typ == Node.opt || p.typ == Node.iter) {\n\t\t\t\tif (DelSubGraph(p.sub)) LL1Error(4, null); // e.g. [[...]]\n\t\t\t\telse {\n\t\t\t\t\ts1 = Expected0(p.sub, curSy);\n\t\t\t\t\ts2 = Expected(p.next, curSy);\n\t\t\t\t\tCheckOverlap(s1, s2, 2);\n\t\t\t\t}\n\t\t\t\tCheckAlts(p.sub);\n\t\t\t} else if (p.typ == Node.any) {\n\t\t\t\tif (Sets.Elements(p.set) == 0) LL1Error(3, null);\n\t\t\t\t// e.g. {ANY} ANY or [ANY] ANY or ( ANY | ANY )\n\t\t\t}\n\t\t\tif (p.up) break;\n\t\t\tp = p.next;\n\t\t}\n\t}\n\n\tpublic void CheckLL1() {\n\t\tforeach (Symbol sym in nonterminals) {\n\t\t\tcurSy = sym;\n\t\t\tCheckAlts(curSy.graph);\n\t\t}\n\t}\n\t\n\t//------------- check if resolvers are legal  --------------------\n\t\n\tvoid ResErr(Node p, string msg) {\n\t\terrors.Warning(p.line, p.pos.col, msg);\n\t}\n\t\n\tvoid CheckRes(Node p, bool rslvAllowed) {\n\t\twhile (p != null) {\n\t\t\tswitch (p.typ) {\n\t\t\t\tcase Node.alt:\n\t\t\t\t\tBitArray expected = new BitArray(terminals.Count);\n\t\t\t\t\tfor (Node q = p; q != null; q = q.down)\n\t\t\t\t\t\texpected.Or(Expected0(q.sub, curSy));\n\t\t\t\t\tBitArray soFar = new BitArray(terminals.Count);\n\t\t\t\t\tfor (Node q = p; q != null; q = q.down) {\n\t\t\t\t\t\tif (q.sub.typ == Node.rslv) {\n\t\t\t\t\t\t  BitArray fs = Expected(q.sub.next, curSy);\n\t\t\t\t\t\t\tif (Sets.Intersect(fs, soFar))\n\t\t\t\t\t\t\t\tResErr(q.sub, \"Warning: Resolver will never be evaluated. \" +\n\t\t\t\t\t\t\t\t\"Place it at previous conflicting alternative.\");\n\t\t\t\t\t\t\tif (!Sets.Intersect(fs, expected))\n\t\t\t\t\t\t\t\tResErr(q.sub, \"Warning: Misplaced resolver: no LL(1) conflict.\");\n\t\t\t\t\t\t} else soFar.Or(Expected(q.sub, curSy));\n\t\t\t\t\t\tCheckRes(q.sub, true);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase Node.iter: case Node.opt:\n\t\t\t\t\tif (p.sub.typ == Node.rslv) {\n\t\t\t\t\t\tBitArray fs = First(p.sub.next);\n\t\t\t\t\t\tBitArray fsNext = Expected(p.next, curSy);\n\t\t\t\t\t\tif (!Sets.Intersect(fs, fsNext)) \n\t\t\t\t\t\t\tResErr(p.sub, \"Warning: Misplaced resolver: no LL(1) conflict.\");\n\t\t\t\t\t}\n\t\t\t\t\tCheckRes(p.sub, true);\n\t\t\t\t\tbreak;\n\t\t\t\tcase Node.rslv:\n\t\t\t\t\tif (!rslvAllowed)\n\t\t\t\t\t\tResErr(p, \"Warning: Misplaced resolver: no alternative.\");\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (p.up) break;\n\t\t\tp = p.next;\n\t\t\trslvAllowed = false;\n\t\t}\n\t}\n\t\n\tpublic void CheckResolvers() {\n\t\tforeach (Symbol sym in nonterminals) {\n\t\t\tcurSy = sym;\n\t\t\tCheckRes(curSy.graph, false);\n\t\t}\n\t}\n\n\t//------------- check if every nts has a production --------------------\n\t\n\tpublic bool NtsComplete() {\n\t\tbool complete = true;\n\t\tforeach (Symbol sym in nonterminals) {\n\t\t\tif (sym.graph == null) {\n\t\t\t\tcomplete = false;\n\t\t\t\terrors.SemErr(\"  No production for \" + sym.name);\n\t\t\t}\n\t\t}\n\t\treturn complete;\n\t}\n\t\n\t//-------------- check if every nts can be reached  -----------------\n\t\n\tvoid MarkReachedNts(Node p) {\n\t\twhile (p != null) {\n\t\t\tif (p.typ == Node.nt && !visited[p.sym.n]) { // new nt reached\n\t\t\t\tvisited[p.sym.n] = true;\n\t\t\t\tMarkReachedNts(p.sym.graph);\n\t\t\t} else if (p.typ == Node.alt || p.typ == Node.iter || p.typ == Node.opt) {\n\t\t\t\tMarkReachedNts(p.sub);\n\t\t\t\tif (p.typ == Node.alt) MarkReachedNts(p.down);\n\t\t\t}\n\t\t\tif (p.up) break;\n\t\t\tp = p.next;\n\t\t}\n\t}\n\t\n\tpublic bool AllNtReached() {\n\t\tbool ok = true;\n\t\tvisited = new BitArray(nonterminals.Count);\n\t\tvisited[gramSy.n] = true;\n\t\tMarkReachedNts(gramSy.graph);\n\t\tforeach (Symbol sym in nonterminals) {\n\t\t\tif (!visited[sym.n]) {\n\t\t\t\tok = false;\n\t\t\t\terrors.Warning(\"  \" + sym.name + \" cannot be reached\");\n\t\t\t}\n\t\t}\n\t\treturn ok;\n\t}\n\t\n\t//--------- check if every nts can be derived to terminals  ------------\n\t\n\tbool IsTerm(Node p, BitArray mark) { // true if graph can be derived to terminals\n\t\twhile (p != null) {\n\t\t\tif (p.typ == Node.nt && !mark[p.sym.n]) return false;\n\t\t\tif (p.typ == Node.alt && !IsTerm(p.sub, mark) \n\t\t\t&& (p.down == null || !IsTerm(p.down, mark))) return false;\n\t\t\tif (p.up) break;\n\t\t\tp = p.next;\n\t\t}\n\t\treturn true;\n\t}\n\t\n\tpublic bool AllNtToTerm() {\n\t\tbool changed, ok = true;\n\t\tBitArray mark = new BitArray(nonterminals.Count);\n\t\t// a nonterminal is marked if it can be derived to terminal symbols\n\t\tdo {\n\t\t\tchanged = false;\n\t\t\tforeach (Symbol sym in nonterminals)\n\t\t\t\tif (!mark[sym.n] && IsTerm(sym.graph, mark)) {\n\t\t\t\t\tmark[sym.n] = true; changed = true;\n\t\t\t\t}\n\t\t} while (changed);\n\t\tforeach (Symbol sym in nonterminals)\n\t\t\tif (!mark[sym.n]) {\n\t\t\t\tok = false;\n\t\t\t\terrors.SemErr(\"  \" + sym.name + \" cannot be derived to terminals\");\n\t\t\t}\n\t\treturn ok;\n\t}\n\t\n\t//---------------------------------------------------------------------\n\t//  Cross reference list\n\t//---------------------------------------------------------------------\n\t\n\tpublic void XRef() {\n\t\tSortedList xref = new SortedList(new SymbolComp());\n\t\t// collect lines where symbols have been defined\n\t\tforeach (Symbol sym in nonterminals) {\n\t\t\tArrayList list = (ArrayList)xref[sym];\n\t\t\tif (list == null) {list = new ArrayList(); xref[sym] = list;}\n\t\t\tlist.Add(- sym.line);\n\t\t}\n\t\t// collect lines where symbols have been referenced\n\t\tforeach (Node n in nodes) {\n\t\t\tif (n.typ == Node.t || n.typ == Node.wt || n.typ == Node.nt) {\n\t\t\t\tArrayList list = (ArrayList)xref[n.sym];\n\t\t\t\tif (list == null) {list = new ArrayList(); xref[n.sym] = list;}\n\t\t\t\tlist.Add(n.line);\n\t\t\t}\n\t\t}\n\t\t// print cross reference list\n\t\ttrace.WriteLine();\n\t\ttrace.WriteLine(\"Cross reference list:\");\n\t\ttrace.WriteLine(\"--------------------\"); trace.WriteLine();\n\t\tforeach (Symbol sym in xref.Keys) {\n\t\t\ttrace.Write(\"  {0,-12}\", Name(sym.name));\n\t\t\tArrayList list = (ArrayList)xref[sym];\n\t\t\tint col = 14;\n\t\t\tforeach (int line in list) {\n\t\t\t\tif (col + 5 > 80) {\n\t\t\t\t\ttrace.WriteLine();\n\t\t\t\t\tfor (col = 1; col <= 14; col++) trace.Write(\" \");\n\t\t\t\t}\n\t\t\t\ttrace.Write(\"{0,5}\", line); col += 5;\n\t\t\t}\n\t\t\ttrace.WriteLine();\n\t\t}\n\t\ttrace.WriteLine(); trace.WriteLine();\n\t}\n\t\n\tpublic void SetDDT(string s) {\n\t\ts = s.ToUpper();\n\t\tforeach (char ch in s) {\n\t\t\tif ('0' <= ch && ch <= '9') ddt[ch - '0'] = true;\n\t\t\telse switch (ch) {\n\t\t\t\tcase 'A' : ddt[0] = true; break; // trace automaton\n\t\t\t\tcase 'F' : ddt[1] = true; break; // list first/follow sets\n\t\t\t\tcase 'G' : ddt[2] = true; break; // print syntax graph\n\t\t\t\tcase 'I' : ddt[3] = true; break; // trace computation of first sets\n\t\t\t\tcase 'J' : ddt[4] = true; break; // print ANY and SYNC sets\n\t\t\t\tcase 'P' : ddt[8] = true; break; // print statistics\n\t\t\t\tcase 'S' : ddt[6] = true; break; // list symbol table\n\t\t\t\tcase 'X' : ddt[7] = true; break; // list cross reference table\n\t\t\t\tdefault : break;\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic void SetOption(string s) {\n\t\tstring[] option = s.Split(new char[] {'='}, 2);\n\t\tstring name = option[0], value = option[1];\n\t\tif (\"$namespace\".Equals(name)) {\n\t\t\tif (nsName == null) nsName = value;\n\t\t} else if (\"$checkEOF\".Equals(name)) {\n\t\t\tcheckEOF = \"true\".Equals(value);\n\t\t}\n\t}\n\n\tclass SymbolComp : IComparer {\n\t\tpublic int Compare(Object x, Object y)  {\n\t\t\treturn ((Symbol) x).name.CompareTo(((Symbol) y).name);\n\t\t}\n\t}\n\n} // end Tab\n\n} // end namespace\n"
  },
  {
    "path": "third_party/Coco/src/build.bat",
    "content": "%windir%\\Microsoft.Net\\Framework\\v2.0.50727\\csc.exe /out:Coco.exe /t:exe Coco.cs Scanner.cs Tab.cs DFA.cs ParserGen.cs Parser.cs"
  },
  {
    "path": "third_party/Coco/src/coc.bat",
    "content": "coco Coco.ATG -namespace at.jku.ssw.Coco"
  },
  {
    "path": "tools/scripts/.gitignore",
    "content": "*.pyc\nprofile-collect\nprofile-report\n"
  },
  {
    "path": "tools/scripts/__init__.py",
    "content": ""
  },
  {
    "path": "tools/scripts/dafny-oneproc.py",
    "content": "#!/usr/bin/python\n\nimport sys\nimport os\nimport subprocess\nimport re\nimport datetime\nos.environ[\"PATH\"] = \"tools/Dafny:\"+os.environ[\"PATH\"]\n\ndef docmd(*cmd):\n    print \"cmd:\", \" \".join(cmd)\n    subprocess.call(cmd)\n    \ndef main():\n    (thisprog,dfyfile,procname) = sys.argv\n    boogieFile = dfyfile.replace(\".dfy\", \".bpl\")\n    escapedProcName = procname.replace(\"_\", \"__\")\n    docmd(\"dafny.exe\", \"/timeLimit:1\", \"/allowGlobals\", \"/noVerify\", \"/print:%s\" % boogieFile, dfyfile)\n\n    boogieFileHandle = open(boogieFile, 'r')\n    mangledProcName = ''\n    for line in boogieFileHandle:\n        m = re.search(r'^procedure\\s*({:[^}]+}\\s*)*(Impl[^\\(]+)', line)\n\tif m:\n            procedureName = m.group(2)\n            if len(procedureName) > len(escapedProcName):\n                suffix = procedureName[len(procedureName) - len(escapedProcName) - 1:]\n                if suffix == '.' + escapedProcName:\n                    mangledProcName = procedureName\n                    break\n    boogieFileHandle.close()\n    if len(mangledProcName) == 0:\n        print 'Could not find procedure ending in .%s in %s' % (escapedProcName, boogieFile)\n        sys.exit(-1)\n\n    start_time = datetime.datetime.now()\n    docmd(\"dafny.exe\", \"/allowGlobals\", \"/allocated:1\", \"/proverWarnings:1\", \"/compile:0\", \"/noCheating:1\", \"/arith:5\", \"/timeLimit:30\", \"/proc:%s\" % mangledProcName, dfyfile)\n    end_time = datetime.datetime.now()\n    docmd(\"rm\", boogieFile)\n    print 'Boogie time was %s sec' % ((end_time - start_time).total_seconds())\n\nmain()\n"
  },
  {
    "path": "tools/scripts/dafny_profiler.py",
    "content": "#!/usr/bin/python\n\nimport sys\nimport os\nimport subprocess\nimport re\n\ndef docmd(*cmd):\n    print \"cmd:\", \" \".join(cmd)\n    subprocess.call(cmd)\n\ndef process_log():\n    fd_in = open(\"z3.log\", \"r\")\n    fd_out = open(\"profile.log\", \"w\")\n    counts = {}\n    for line in fd_in.readlines():\n        m = re.search(r'^\\[mk\\-quant\\]\\s+#\\d*\\s+([^\\s]+)\\s', line)\n        if m:\n            pattern = m.group(1)\n            if pattern in counts:\n                counts[pattern] = counts[pattern] + 1\n            else:\n                counts[pattern] = 1\n    patterns = list(counts.items())\n    patterns = sorted(patterns, key=lambda kv : kv[1], reverse=True)\n    for item in patterns:\n        (key, value) = item\n        fd_out.write(\"%d\\t%s\\n\" % (value, key))\n    fd_in.close()\n    fd_out.close()\n    print \"*** For profile output, see profile.log ***\"\n    \ndef main(args):\n    (thisprog,dfyfile,procname) = args\n    boogieFile = dfyfile.replace(\".dfy\", \".bpl\")\n    escapedProcName = procname.replace(\"_\", \"__\")\n    docmd(\"/e/Apps/Dafny/Binaries/dafny.exe\", \"/timeLimit:1\", \"/noVerify\", \"/arith:5\", \"/compile:0\", \"/print:%s\" % boogieFile, dfyfile)\n\n    boogieFileHandle = open(boogieFile, 'r')\n    mangledProcName = ''\n    mangledCheckFormedName = ''\n    for line in boogieFileHandle:\n        m = re.search(r'^procedure\\s*({:[^}]*}\\s*)*(Impl[^\\(]+)', line)\n\tif m:\n            procedureName = m.group(2)\n            if len(procedureName) > len(escapedProcName) and procedureName[len(procedureName)-len(escapedProcName)-1:] == \".\" + escapedProcName:\n                mangledProcName = procedureName\n                break\n        m = re.search(r'^procedure\\s*({:[^}]*}\\s*)*(CheckWellformed[^\\(]+)', line)\n\tif m:\n            procedureName = m.group(2)\n            if len(procedureName) > len(escapedProcName) and procedureName[len(procedureName)-len(escapedProcName)-1:] == \".\" + escapedProcName:\n                mangledCheckFormedName = procedureName\n    boogieFileHandle.close()\n    if len(mangledProcName) == 0:\n        mangledProcName = mangledCheckFormedName\n        if len(mangledCheckFormedName) == 0:\n            print 'Could not find implementation or check-formedness procedure with substring %s in %s' % (escapedProcName, boogieFile)\n            sys.exit(-1)\n        else:\n            print 'Warning:  Could not find implementation procedure with substring %s, so using check-formedness procedure' % (escapedProcName)\n            \n    z3log = \"z3.log\"\n    if (os.path.exists(z3log)):\n        os.unlink(z3log)\n    docmd(\"/e/Apps/Boogie/Binaries/boogie.exe\", \"/z3opt:nlsat.randomize=false\", \"/z3opt:smt.arith.nl=false\", \"/z3opt:pi.warnings=true\", \"/z3opt:trace=true\", \"/timeLimit:30\", \"/proc:%s\" % mangledProcName, \"/trace\", boogieFile)\n\nif __name__ == '__main__':\n    main(sys.argv)\n    process_log()\n"
  }
]